blob: cb9fc599136ff4df2208cfd1ae5378557e2cd0c4 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "vpu.h"
#include "vpu-regs.h"
#include "hhi-regs.h"
#include "vpp-regs.h"
#include <ddk/debug.h>
#include <ddktl/device.h>
namespace astro_display {
namespace {
constexpr uint32_t kVpuMux = 0;
constexpr uint32_t kVpuDiv = 3;
constexpr int16_t RGB709_to_YUV709l_coeff[24] = {
0x0000, 0x0000, 0x0000,
0x00bb, 0x0275, 0x003f,
0x1f99, 0x1ea6, 0x01c2,
0x01c2, 0x1e67, 0x1fd7,
0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000,
0x0040, 0x0200, 0x0200,
0x0000, 0x0000, 0x0000,
};
constexpr int16_t YUV709l_to_RGB709_coeff12[24] = {
-256, -2048, -2048,
4788, 0, 7372,
4788, -876, -2190,
4788, 8686, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
};
} // namespace
// AOBUS Register
#define AOBUS_GEN_PWR_SLEEP0 (0x03a << 2)
// CBUS Reset Register
#define RESET0_LEVEL (0x0420 << 2)
#define RESET1_LEVEL (0x0421 << 2)
#define RESET2_LEVEL (0x0422 << 2)
#define RESET4_LEVEL (0x0424 << 2)
#define RESET7_LEVEL (0x0427 << 2)
#define READ32_VPU_REG(a) vpu_mmio_->Read32(a)
#define WRITE32_VPU_REG(a, v) vpu_mmio_->Write32(v, a)
#define READ32_HHI_REG(a) hhi_mmio_->Read32(a)
#define WRITE32_HHI_REG(a, v) hhi_mmio_->Write32(v, a)
#define READ32_AOBUS_REG(a) aobus_mmio_->Read32(a)
#define WRITE32_AOBUS_REG(a, v) aobus_mmio_->Write32(v, a)
#define READ32_CBUS_REG(a) cbus_mmio_->Read32(a)
#define WRITE32_CBUS_REG(a, v) cbus_mmio_->Write32(v, a)
zx_status_t Vpu::Init(zx_device_t* parent) {
if (initialized_) {
return ZX_OK;
}
zx_status_t status = device_get_protocol(parent, ZX_PROTOCOL_PDEV, &pdev_);
if (status != ZX_OK) {
return status;
}
// Map VPU registers
mmio_buffer_t mmio;
status = pdev_map_mmio_buffer(&pdev_, MMIO_VPU, ZX_CACHE_POLICY_UNCACHED_DEVICE,
&mmio);
if (status != ZX_OK) {
DISP_ERROR("vpu: Could not map VPU mmio\n");
return status;
}
vpu_mmio_ = ddk::MmioBuffer(mmio);
// Map HHI registers
status = pdev_map_mmio_buffer(&pdev_, MMIO_HHI, ZX_CACHE_POLICY_UNCACHED_DEVICE,
&mmio);
if (status != ZX_OK) {
DISP_ERROR("vpu: Could not map HHI mmio\n");
return status;
}
hhi_mmio_ = ddk::MmioBuffer(mmio);
// Map AOBUS registers
status = pdev_map_mmio_buffer(&pdev_, MMIO_AOBUS, ZX_CACHE_POLICY_UNCACHED_DEVICE,
&mmio);
if (status != ZX_OK) {
DISP_ERROR("vpu: Could not map AOBUS mmio\n");
return status;
}
aobus_mmio_ = ddk::MmioBuffer(mmio);
// Map CBUS registers
status = pdev_map_mmio_buffer(&pdev_, MMIO_CBUS, ZX_CACHE_POLICY_UNCACHED_DEVICE,
&mmio);
if (status != ZX_OK) {
DISP_ERROR("vpu: Could not map CBUS mmio\n");
return status;
}
cbus_mmio_ = ddk::MmioBuffer(mmio);
// VPU object is ready to be used
initialized_ = true;
return ZX_OK;
}
void Vpu::VppInit() {
ZX_DEBUG_ASSERT(initialized_);
// init vpu fifo control register
SET_BIT32(VPU, VPP_OFIFO_SIZE, 0xFFF, 0, 12);
WRITE32_REG(VPU, VPP_HOLD_LINES, 0x08080808);
// default probe_sel, for highlight en
SET_BIT32(VPU, VPP_MATRIX_CTRL, 0x7, 12, 3);
// setting up os1 for rgb -> yuv limit
const int16_t* m = RGB709_to_YUV709l_coeff;
// VPP WRAP OSD1 matrix
WRITE32_REG(VPU, VPP_WRAP_OSD1_MATRIX_PRE_OFFSET0_1,
((m[0] & 0xfff) << 16) | (m[1] & 0xfff));
WRITE32_REG(VPU, VPP_WRAP_OSD1_MATRIX_PRE_OFFSET2,
m[2] & 0xfff);
WRITE32_REG(VPU, VPP_WRAP_OSD1_MATRIX_COEF00_01,
((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff));
WRITE32_REG(VPU, VPP_WRAP_OSD1_MATRIX_COEF02_10,
((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff));
WRITE32_REG(VPU, VPP_WRAP_OSD1_MATRIX_COEF11_12,
((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff));
WRITE32_REG(VPU, VPP_WRAP_OSD1_MATRIX_COEF20_21,
((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff));
WRITE32_REG(VPU, VPP_WRAP_OSD1_MATRIX_COEF22,
m[11] & 0x1fff);
WRITE32_REG(VPU, VPP_WRAP_OSD1_MATRIX_OFFSET0_1,
((m[18] & 0xfff) << 16) | (m[19] & 0xfff));
WRITE32_REG(VPU, VPP_WRAP_OSD1_MATRIX_OFFSET2,
m[20] & 0xfff);
SET_BIT32(VPU, VPP_WRAP_OSD1_MATRIX_EN_CTRL, 1, 0, 1);
// VPP WRAP OSD2 matrix
WRITE32_REG(VPU, VPP_WRAP_OSD2_MATRIX_PRE_OFFSET0_1,
((m[0] & 0xfff) << 16) | (m[1] & 0xfff));
WRITE32_REG(VPU, VPP_WRAP_OSD2_MATRIX_PRE_OFFSET2,
m[2] & 0xfff);
WRITE32_REG(VPU, VPP_WRAP_OSD2_MATRIX_COEF00_01,
((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff));
WRITE32_REG(VPU, VPP_WRAP_OSD2_MATRIX_COEF02_10,
((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff));
WRITE32_REG(VPU, VPP_WRAP_OSD2_MATRIX_COEF11_12,
((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff));
WRITE32_REG(VPU, VPP_WRAP_OSD2_MATRIX_COEF20_21,
((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff));
WRITE32_REG(VPU, VPP_WRAP_OSD2_MATRIX_COEF22,
m[11] & 0x1fff);
WRITE32_REG(VPU, VPP_WRAP_OSD2_MATRIX_OFFSET0_1,
((m[18] & 0xfff) << 16) | (m[19] & 0xfff));
WRITE32_REG(VPU, VPP_WRAP_OSD2_MATRIX_OFFSET2,
m[20] & 0xfff);
SET_BIT32(VPU, VPP_WRAP_OSD2_MATRIX_EN_CTRL, 1, 0, 1);
// VPP WRAP OSD3 matrix
WRITE32_REG(VPU, VPP_WRAP_OSD3_MATRIX_PRE_OFFSET0_1,
((m[0] & 0xfff) << 16) | (m[1] & 0xfff));
WRITE32_REG(VPU, VPP_WRAP_OSD3_MATRIX_PRE_OFFSET2,
m[2] & 0xfff);
WRITE32_REG(VPU, VPP_WRAP_OSD3_MATRIX_COEF00_01,
((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff));
WRITE32_REG(VPU, VPP_WRAP_OSD3_MATRIX_COEF02_10,
((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff));
WRITE32_REG(VPU, VPP_WRAP_OSD3_MATRIX_COEF11_12,
((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff));
WRITE32_REG(VPU, VPP_WRAP_OSD3_MATRIX_COEF20_21,
((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff));
WRITE32_REG(VPU, VPP_WRAP_OSD3_MATRIX_COEF22,
m[11] & 0x1fff);
WRITE32_REG(VPU, VPP_WRAP_OSD3_MATRIX_OFFSET0_1,
((m[18] & 0xfff) << 16) | (m[19] & 0xfff));
WRITE32_REG(VPU, VPP_WRAP_OSD3_MATRIX_OFFSET2,
m[20] & 0xfff);
SET_BIT32(VPU, VPP_WRAP_OSD3_MATRIX_EN_CTRL, 1, 0, 1);
WRITE32_REG(VPU, DOLBY_PATH_CTRL, 0xf);
// POST2 matrix: YUV limit -> RGB default is 12bit
m = YUV709l_to_RGB709_coeff12;
// VPP WRAP POST2 matrix
WRITE32_REG(VPU, VPP_POST2_MATRIX_PRE_OFFSET0_1,
(((m[0] >> 2) & 0xfff) << 16) | ((m[1] >> 2) & 0xfff));
WRITE32_REG(VPU, VPP_POST2_MATRIX_PRE_OFFSET2,
(m[2] >> 2) & 0xfff);
WRITE32_REG(VPU, VPP_POST2_MATRIX_COEF00_01,
(((m[3] >> 2) & 0x1fff) << 16) | ((m[4] >> 2) & 0x1fff));
WRITE32_REG(VPU, VPP_POST2_MATRIX_COEF02_10,
(((m[5] >> 2) & 0x1fff) << 16) | ((m[6] >> 2) & 0x1fff));
WRITE32_REG(VPU, VPP_POST2_MATRIX_COEF11_12,
(((m[7] >> 2) & 0x1fff) << 16) | ((m[8] >> 2) & 0x1fff));
WRITE32_REG(VPU, VPP_POST2_MATRIX_COEF20_21,
(((m[9] >> 2) & 0x1fff) << 16) | ((m[10] >> 2) & 0x1fff));
WRITE32_REG(VPU, VPP_POST2_MATRIX_COEF22,
(m[11] >> 2) & 0x1fff);
WRITE32_REG(VPU, VPP_POST2_MATRIX_OFFSET0_1,
(((m[18] >> 2) & 0xfff) << 16) | ((m[19] >> 2) & 0xfff));
WRITE32_REG(VPU, VPP_POST2_MATRIX_OFFSET2,
(m[20] >> 2) & 0xfff);
SET_BIT32(VPU, VPP_POST2_MATRIX_EN_CTRL, 1, 0, 1);
SET_BIT32(VPU, VPP_MATRIX_CTRL, 1, 0, 1);
SET_BIT32(VPU, VPP_MATRIX_CTRL, 0, 8, 3);
// 709L to RGB
WRITE32_REG(VPU, VPP_MATRIX_PRE_OFFSET0_1, 0x0FC00E00);
WRITE32_REG(VPU, VPP_MATRIX_PRE_OFFSET2, 0x00000E00);
// ycbcr limit range, 709 to RGB
// -16 1.164 0 1.793 0
// -128 1.164 -0.213 -0.534 0
// -128 1.164 2.115 0 0
WRITE32_REG(VPU, VPP_MATRIX_COEF00_01, 0x04A80000);
WRITE32_REG(VPU, VPP_MATRIX_COEF02_10, 0x072C04A8);
WRITE32_REG(VPU, VPP_MATRIX_COEF11_12, 0x1F261DDD);
WRITE32_REG(VPU, VPP_MATRIX_COEF20_21, 0x04A80876);
WRITE32_REG(VPU, VPP_MATRIX_COEF22, 0x0);
WRITE32_REG(VPU, VPP_MATRIX_OFFSET0_1, 0x0);
WRITE32_REG(VPU, VPP_MATRIX_OFFSET2, 0x0);
SET_BIT32(VPU, VPP_MATRIX_CLIP, 0, 5, 3);
}
void Vpu::ConfigureClock() {
ZX_DEBUG_ASSERT(initialized_);
// vpu clock
WRITE32_REG(HHI, HHI_VPU_CLK_CNTL, ((kVpuMux << 9) | (kVpuDiv << 0)));
SET_BIT32(HHI, HHI_VPU_CLK_CNTL, 1, 8, 1);
// vpu clkb
// bit 0 is set since kVpuClkFrequency > clkB max frequency (350MHz)
WRITE32_REG(HHI, HHI_VPU_CLKB_CNTL, ((1 << 8) | (1 << 0)));
// vapb clk
// turn on ge2d clock since kVpuClkFrequency > 250MHz
WRITE32_REG(HHI, HHI_VAPBCLK_CNTL, (1 << 30) | (0 << 9) | (1 << 0));
SET_BIT32(HHI, HHI_VAPBCLK_CNTL, 1, 8, 1);
SET_BIT32(HHI, HHI_VID_CLK_CNTL2, 0, 0, 8);
// dmc_arb_config
WRITE32_REG(VPU, VPU_RDARB_MODE_L1C1, 0x0);
WRITE32_REG(VPU, VPU_RDARB_MODE_L1C2, 0x10000);
WRITE32_REG(VPU, VPU_RDARB_MODE_L2C1, 0x900000);
WRITE32_REG(VPU, VPU_WRARB_MODE_L2C1, 0x20000);
}
void Vpu::PowerOn() {
ZX_DEBUG_ASSERT(initialized_);
SET_BIT32(AOBUS, AOBUS_GEN_PWR_SLEEP0, 0, 8, 1); // [8] power on
// power up memories
for (int i = 0; i < 32; i+=2) {
SET_BIT32(HHI, HHI_VPU_MEM_PD_REG0, 0, i, 2);
zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
}
for (int i = 0; i < 32; i+=2) {
SET_BIT32(HHI, HHI_VPU_MEM_PD_REG1, 0, i, 2);
zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
}
SET_BIT32(HHI, HHI_VPU_MEM_PD_REG2, 0, 0, 2);
zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
for (int i = 4; i < 18; i+=2) {
SET_BIT32(HHI, HHI_VPU_MEM_PD_REG2, 0, i, 2);
zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
}
SET_BIT32(HHI, HHI_VPU_MEM_PD_REG2, 0, 30, 2);
zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
for (int i = 8; i < 16; i++) {
SET_BIT32(HHI, HHI_MEM_PD_REG0, 0, i, 1);
zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
}
zx_nanosleep(zx_deadline_after(ZX_USEC(20)));
// Reset VIU + VENC
// Reset VENCI + VENCP + VADC + VENCL
// Reset HDMI-APB + HDMI-SYS + HDMI-TX + HDMI-CEC
CLEAR_MASK32(CBUS, RESET0_LEVEL, ((1<<5) | (1<<10) | (1<<19) | (1<<13)));
CLEAR_MASK32(CBUS, RESET1_LEVEL, (1<<5));
CLEAR_MASK32(CBUS, RESET2_LEVEL, (1<<15));
CLEAR_MASK32(CBUS, RESET4_LEVEL,
((1<<6) | (1<<7) | (1<<13) | (1<<5) | (1<<9) | (1<<4) | (1<<12)));
CLEAR_MASK32(CBUS, RESET7_LEVEL, (1<<7));
// Remove VPU_HDMI ISO
SET_BIT32(AOBUS, AOBUS_GEN_PWR_SLEEP0, 0, 9, 1); // [9] VPU_HDMI
// release Reset
SET_MASK32(CBUS, RESET0_LEVEL, ((1 << 5) | (1<<10) | (1<<19) | (1<<13)));
SET_MASK32(CBUS, RESET1_LEVEL, (1<<5));
SET_MASK32(CBUS, RESET2_LEVEL, (1<<15));
SET_MASK32(CBUS, RESET4_LEVEL,
((1<<6) | (1<<7) | (1<<13) | (1<<5) | (1<<9) | (1<<4) | (1<<12)));
SET_MASK32(CBUS, RESET7_LEVEL, (1<<7));
ConfigureClock();
}
void Vpu::PowerOff() {
ZX_DEBUG_ASSERT(initialized_);
// Power down VPU_HDMI
// Enable Isolation
SET_BIT32(AOBUS, AOBUS_GEN_PWR_SLEEP0, 1, 9, 1); // ISO
zx_nanosleep(zx_deadline_after(ZX_USEC(20)));
// power down memories
for (int i = 0; i < 32; i+=2) {
SET_BIT32(HHI, HHI_VPU_MEM_PD_REG0, 0x3, i, 2);
zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
}
for (int i = 0; i < 32; i+=2) {
SET_BIT32(HHI, HHI_VPU_MEM_PD_REG1, 0x3, i, 2);
zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
}
SET_BIT32(HHI, HHI_VPU_MEM_PD_REG2, 0x3, 0, 2);
zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
for (int i = 4; i < 18; i+=2) {
SET_BIT32(HHI, HHI_VPU_MEM_PD_REG2, 0x3, i, 2);
zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
}
SET_BIT32(HHI, HHI_VPU_MEM_PD_REG2, 0x3, 30, 2);
zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
for (int i = 8; i < 16; i++) {
SET_BIT32(HHI, HHI_MEM_PD_REG0, 0x1, i, 1);
zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
}
zx_nanosleep(zx_deadline_after(ZX_USEC(20)));
// Power down VPU domain
SET_BIT32(AOBUS, AOBUS_GEN_PWR_SLEEP0, 1, 8, 1); // PDN
SET_BIT32(HHI, HHI_VAPBCLK_CNTL, 0, 8, 1);
SET_BIT32(HHI, HHI_VPU_CLK_CNTL, 0, 8, 1);
}
} // namespace astro_display