blob: 43bb3e44ae0c5636dfb7e2a1e89cbad0282c8081 [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 "aml-dsi-host.h"
#include <ddk/debug.h>
#include <fbl/alloc_checker.h>
namespace astro_display {
#define READ32_MIPI_DSI_REG(a) mipi_dsi_mmio_->Read32(a)
#define WRITE32_MIPI_DSI_REG(a, v) mipi_dsi_mmio_->Write32(v, a)
#define READ32_HHI_REG(a) hhi_mmio_->Read32(a)
#define WRITE32_HHI_REG(a, v) hhi_mmio_->Write32(v, a)
zx_status_t AmlDsiHost::HostModeInit(const display_setting_t& disp_setting) {
// Setup relevant TOP_CNTL register -- Undocumented --
SET_BIT32(MIPI_DSI, MIPI_DSI_TOP_CNTL, SUPPORTED_DPI_FORMAT, TOP_CNTL_DPI_CLR_MODE_START,
TOP_CNTL_DPI_CLR_MODE_BITS);
SET_BIT32(MIPI_DSI, MIPI_DSI_TOP_CNTL, SUPPORTED_VENC_DATA_WIDTH, TOP_CNTL_IN_CLR_MODE_START,
TOP_CNTL_IN_CLR_MODE_BITS);
SET_BIT32(MIPI_DSI, MIPI_DSI_TOP_CNTL, 0, TOP_CNTL_CHROMA_SUBSAMPLE_START,
TOP_CNTL_CHROMA_SUBSAMPLE_BITS);
// setup dsi config
dsi_config_t dsi_cfg;
dsi_cfg.display_setting = disp_setting;
dsi_cfg.video_mode_type = VIDEO_MODE_BURST;
dsi_cfg.color_coding = COLOR_CODE_PACKED_24BIT_888;
designware_config_t dw_cfg;
dw_cfg.lp_escape_time = phy_->GetLowPowerEscaseTime();
dw_cfg.lp_cmd_pkt_size = LPCMD_PKT_SIZE;
dw_cfg.phy_timer_clkhs_to_lp = PHY_TMR_LPCLK_CLKHS_TO_LP;
dw_cfg.phy_timer_clklp_to_hs = PHY_TMR_LPCLK_CLKLP_TO_HS;
dw_cfg.phy_timer_hs_to_lp = PHY_TMR_HS_TO_LP;
dw_cfg.phy_timer_lp_to_hs = PHY_TMR_LP_TO_HS;
dw_cfg.auto_clklane = 1;
dsi_cfg.vendor_config_buffer = &dw_cfg;
dsiimpl_.Config(&dsi_cfg);
return ZX_OK;
}
void AmlDsiHost::PhyEnable() {
WRITE32_REG(HHI, HHI_MIPI_CNTL0,
MIPI_CNTL0_CMN_REF_GEN_CTRL(0x29) | MIPI_CNTL0_VREF_SEL(VREF_SEL_VR) |
MIPI_CNTL0_LREF_SEL(LREF_SEL_L_ROUT) | MIPI_CNTL0_LBG_EN |
MIPI_CNTL0_VR_TRIM_CNTL(0x7) | MIPI_CNTL0_VR_GEN_FROM_LGB_EN);
WRITE32_REG(HHI, HHI_MIPI_CNTL1, MIPI_CNTL1_DSI_VBG_EN | MIPI_CNTL1_CTL);
WRITE32_REG(HHI, HHI_MIPI_CNTL2, MIPI_CNTL2_DEFAULT_VAL); // 4 lane
}
void AmlDsiHost::PhyDisable() {
WRITE32_REG(HHI, HHI_MIPI_CNTL0, 0);
WRITE32_REG(HHI, HHI_MIPI_CNTL1, 0);
WRITE32_REG(HHI, HHI_MIPI_CNTL2, 0);
}
void AmlDsiHost::HostOff(const display_setting_t& disp_setting) {
ZX_DEBUG_ASSERT(initialized_);
// turn host off only if it's been fully turned on
if (!host_on_) {
return;
}
// Place dsi in command mode first
dsiimpl_.SetMode(DSI_MODE_COMMAND);
// Turn off LCD
lcd_->Disable();
// disable PHY
PhyDisable();
// finally shutdown host
phy_->Shutdown();
host_on_ = false;
}
zx_status_t AmlDsiHost::HostOn(const display_setting_t& disp_setting) {
ZX_DEBUG_ASSERT(initialized_);
if (host_on_) {
return ZX_OK;
}
// Enable MIPI PHY
PhyEnable();
// Create MIPI PHY object
fbl::AllocChecker ac;
phy_ = fbl::make_unique_checked<astro_display::AmlMipiPhy>(&ac);
if (!ac.check()) {
DISP_ERROR("Could not create AmlMipiPhy object\n");
return ZX_ERR_NO_MEMORY;
}
zx_status_t status = phy_->Init(pdev_dev_, dsi_dev_, disp_setting.lane_num);
if (status != ZX_OK) {
DISP_ERROR("MIPI PHY Init failed!\n");
return status;
}
// Load Phy configuration
status = phy_->PhyCfgLoad(bitrate_);
if (status != ZX_OK) {
DISP_ERROR("Error during phy config calculations! %d\n", status);
return status;
}
// Enable dwc mipi_dsi_host's clock
SET_BIT32(MIPI_DSI, MIPI_DSI_TOP_CNTL, 0x3, 4, 2);
// mipi_dsi_host's reset
SET_BIT32(MIPI_DSI, MIPI_DSI_TOP_SW_RESET, 0xf, 0, 4);
// Release mipi_dsi_host's reset
SET_BIT32(MIPI_DSI, MIPI_DSI_TOP_SW_RESET, 0x0, 0, 4);
// Enable dwc mipi_dsi_host's clock
SET_BIT32(MIPI_DSI, MIPI_DSI_TOP_CLK_CNTL, 0x3, 0, 2);
WRITE32_REG(MIPI_DSI, MIPI_DSI_TOP_MEM_PD, 0);
zx_nanosleep(zx_deadline_after(ZX_MSEC(10)));
// Initialize host in command mode first
dsiimpl_.SetMode(DSI_MODE_COMMAND);
if ((status = HostModeInit(disp_setting)) != ZX_OK) {
DISP_ERROR("Error during dsi host init! %d\n", status);
return status;
}
// Initialize mipi dsi D-phy
if ((status = phy_->Startup()) != ZX_OK) {
DISP_ERROR("Error during MIPI D-PHY Initialization! %d\n", status);
return status;
}
// Load LCD Init values while in command mode
lcd_ = fbl::make_unique_checked<astro_display::Lcd>(&ac, panel_type_);
if (!ac.check()) {
DISP_ERROR("Failed to create LCD object\n");
return ZX_ERR_NO_MEMORY;
}
status = lcd_->Init(dsi_dev_, lcd_gpio_dev_);
if (status != ZX_OK) {
DISP_ERROR("Error during LCD Initialization! %d\n", status);
return status;
}
status = lcd_->Enable();
if (status != ZX_OK) {
DISP_ERROR("Could not enable LCD! %d\n", status);
return status;
}
// switch to video mode
dsiimpl_.SetMode(DSI_MODE_VIDEO);
// Host is On and Active at this point
host_on_ = true;
return ZX_OK;
}
zx_status_t AmlDsiHost::Init() {
if (initialized_) {
return ZX_OK;
}
zx_status_t status = device_get_protocol(pdev_dev_, ZX_PROTOCOL_PDEV, &pdev_);
if (status != ZX_OK) {
DISP_ERROR("AmlDsiHost: Could not get ZX_PROTOCOL_PDEV protocol\n");
return status;
}
dsiimpl_ = dsi_dev_;
// Map MIPI DSI and HHI registers
mmio_buffer_t mmio;
status = pdev_map_mmio_buffer(&pdev_, MMIO_MPI_DSI, ZX_CACHE_POLICY_UNCACHED_DEVICE, &mmio);
if (status != ZX_OK) {
DISP_ERROR("Could not map MIPI DSI mmio\n");
return status;
}
mipi_dsi_mmio_ = ddk::MmioBuffer(mmio);
status = pdev_map_mmio_buffer(&pdev_, MMIO_HHI, ZX_CACHE_POLICY_UNCACHED_DEVICE, &mmio);
if (status != ZX_OK) {
DISP_ERROR("Could not map HHI mmio\n");
return status;
}
hhi_mmio_ = ddk::MmioBuffer(mmio);
initialized_ = true;
return ZX_OK;
}
void AmlDsiHost::Dump() {
ZX_DEBUG_ASSERT(initialized_);
DISP_INFO("MIPI_DSI_TOP_SW_RESET = 0x%x\n", READ32_REG(MIPI_DSI, MIPI_DSI_TOP_SW_RESET));
DISP_INFO("MIPI_DSI_TOP_CLK_CNTL = 0x%x\n", READ32_REG(MIPI_DSI, MIPI_DSI_TOP_CLK_CNTL));
DISP_INFO("MIPI_DSI_TOP_CNTL = 0x%x\n", READ32_REG(MIPI_DSI, MIPI_DSI_TOP_CNTL));
DISP_INFO("MIPI_DSI_TOP_SUSPEND_CNTL = 0x%x\n", READ32_REG(MIPI_DSI, MIPI_DSI_TOP_SUSPEND_CNTL));
DISP_INFO("MIPI_DSI_TOP_SUSPEND_LINE = 0x%x\n", READ32_REG(MIPI_DSI, MIPI_DSI_TOP_SUSPEND_LINE));
DISP_INFO("MIPI_DSI_TOP_SUSPEND_PIX = 0x%x\n", READ32_REG(MIPI_DSI, MIPI_DSI_TOP_SUSPEND_PIX));
DISP_INFO("MIPI_DSI_TOP_MEAS_CNTL = 0x%x\n", READ32_REG(MIPI_DSI, MIPI_DSI_TOP_MEAS_CNTL));
DISP_INFO("MIPI_DSI_TOP_STAT = 0x%x\n", READ32_REG(MIPI_DSI, MIPI_DSI_TOP_STAT));
DISP_INFO("MIPI_DSI_TOP_MEAS_STAT_TE0 = 0x%x\n",
READ32_REG(MIPI_DSI, MIPI_DSI_TOP_MEAS_STAT_TE0));
DISP_INFO("MIPI_DSI_TOP_MEAS_STAT_TE1 = 0x%x\n",
READ32_REG(MIPI_DSI, MIPI_DSI_TOP_MEAS_STAT_TE1));
DISP_INFO("MIPI_DSI_TOP_MEAS_STAT_VS0 = 0x%x\n",
READ32_REG(MIPI_DSI, MIPI_DSI_TOP_MEAS_STAT_VS0));
DISP_INFO("MIPI_DSI_TOP_MEAS_STAT_VS1 = 0x%x\n",
READ32_REG(MIPI_DSI, MIPI_DSI_TOP_MEAS_STAT_VS1));
DISP_INFO("MIPI_DSI_TOP_INTR_CNTL_STAT = 0x%x\n",
READ32_REG(MIPI_DSI, MIPI_DSI_TOP_INTR_CNTL_STAT));
DISP_INFO("MIPI_DSI_TOP_MEM_PD = 0x%x\n", READ32_REG(MIPI_DSI, MIPI_DSI_TOP_MEM_PD));
}
} // namespace astro_display