[coreboot-gerrit] Change in coreboot[master]: oak/mediatek/mt8173: Enable Dual DSI output for Rowan
Daniel Kurtz (Code Review)
gerrit at coreboot.org
Wed Apr 19 12:59:01 CEST 2017
Daniel Kurtz has uploaded a new change for review. ( https://review.coreboot.org/19361 )
Change subject: oak/mediatek/mt8173: Enable Dual DSI output for Rowan
......................................................................
oak/mediatek/mt8173: Enable Dual DSI output for Rowan
Rowan uses a dual-DSI (8-lane) BOE panel.
Add dual-DSI support to mt8173/, and wire it up for use on Rowan.
Signed-off-by: Jitao Shi <jitao.shi at mediatek.com>
Signed-off-by: Daniel Kurtz <djkurtz at chromium.org>
BRANCH=none
BUG=b:35774871
TEST=Boot Rowan in developer mode and see output on the panel
Change-Id: Id47dfd7d9e98689b54398fc8d9142336b41dc29f
---
M src/mainboard/google/oak/mainboard.c
M src/soc/mediatek/mt8173/ddp.c
M src/soc/mediatek/mt8173/dsi.c
M src/soc/mediatek/mt8173/include/soc/addressmap.h
M src/soc/mediatek/mt8173/include/soc/ddp.h
M src/soc/mediatek/mt8173/include/soc/dsi.h
6 files changed, 498 insertions(+), 81 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/61/19361/1
diff --git a/src/mainboard/google/oak/mainboard.c b/src/mainboard/google/oak/mainboard.c
index 7cb6a68..1c947d5 100644
--- a/src/mainboard/google/oak/mainboard.c
+++ b/src/mainboard/google/oak/mainboard.c
@@ -182,8 +182,6 @@
static void configure_display(void)
{
- mtcmos_display_power_on();
-
/* board from Rev2 */
gpio_output(PAD_CMMCLK, 1); /* PANEL_3V3_ENABLE */
/* vgp2 set to 3.3V for ps8640 */
@@ -207,11 +205,54 @@
udelay(100);
}
-static void display_startup(void)
+static void configure_backlight_rowan(void)
{
- struct edid edid;
+ gpio_output(PAD_DAIPCMOUT, 0); /* PANEL_LCD_POWER_EN */
+ gpio_output(PAD_DISP_PWM0, 0); /* DISP_PWM0 */
+ gpio_output(PAD_PCM_TX, 0); /* PANEL_POWER_EN */
+}
+
+static void configure_display_rowan(void)
+{
+ gpio_output(PAD_UCTS2, 1); /* VDDIO_EN */
+ /* delay 15 ms for panel vddio to stabilize */
+ mdelay(15);
+
+ gpio_output(PAD_SRCLKENAI2, 1); /* LCD_RESET */
+ udelay(20);
+ gpio_output(PAD_SRCLKENAI2, 0); /* LCD_RESET */
+ udelay(20);
+ gpio_output(PAD_SRCLKENAI2, 1); /* LCD_RESET */
+ mdelay(20);
+
+ /* Rowan panel avdd */
+ gpio_output(PAD_URTS2, 1);
+
+ /* Rowan panel avee */
+ gpio_output(PAD_URTS0, 1);
+
+ /* panel.delay.prepare */
+ mdelay(20);
+}
+
+static const struct edid rowan_boe_edid = {
+ .panel_bits_per_color = 8,
+ .panel_bits_per_pixel = 24,
+ .mode = {
+ .name = "1536x2048 at 60Hz",
+ .pixel_clock = 241646,
+ .lvds_dual_channel = 1,
+ .refresh = 60,
+ .ha = 1536, .hbl = 404, .hso = 200, .hspw = 4, .hborder = 0,
+ .va = 2048, .vbl = 28, .vso = 12, .vspw = 2, .vborder = 0,
+ .phsync = '-', .pvsync = '-',
+ .x_mm = 147, .y_mm = 196,
+ },
+};
+
+static int read_edid_from_ps8640(struct edid *edid)
+{
u8 i2c_bus, i2c_addr;
- int ret;
if (board_id() + CONFIG_BOARD_ID_ADJUSTMENT > 6) {
i2c_bus = 0;
@@ -224,25 +265,49 @@
mtk_i2c_bus_init(i2c_bus);
ps8640_init(i2c_bus, i2c_addr);
- if (ps8640_get_edid(i2c_bus, i2c_addr, &edid)) {
+ if (ps8640_get_edid(i2c_bus, i2c_addr, edid)) {
printk(BIOS_ERR, "Can't get panel's edid\n");
- return;
+ return -1;
}
- edid.x_resolution = edid.mode.ha;
- edid.y_resolution = edid.mode.va;
- edid.bytes_per_line = edid.mode.ha * edid.framebuffer_bits_per_pixel /
- 8;
+ return 0;
+}
- mtk_ddp_init();
- ret = mtk_dsi_init(MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
- MIPI_DSI_FMT_RGB888, 4, &edid);
+static void display_startup(void)
+{
+ struct edid edid;
+ int ret;
+ u32 mipi_dsi_flags;
+ bool dual_dsi_mode;
+
+ if (IS_ENABLED(CONFIG_BOARD_GOOGLE_ROWAN)) {
+ edid = rowan_boe_edid;
+ dual_dsi_mode = true;
+ mipi_dsi_flags = MIPI_DSI_MODE_VIDEO |
+ MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+ MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET |
+ MIPI_DSI_CLOCK_NON_CONTINUOUS;
+ } else {
+ if (read_edid_from_ps8640(&edid) < 0)
+ return;
+
+ dual_dsi_mode = false;
+ mipi_dsi_flags = MIPI_DSI_MODE_VIDEO |
+ MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+ }
+
+ edid_set_framebuffer_bits_per_pixel(&edid, 32, 0);
+
+ mtk_ddp_init(dual_dsi_mode);
+
+ ret = mtk_dsi_init(mipi_dsi_flags, MIPI_DSI_FMT_RGB888, 4,
+ dual_dsi_mode, &edid);
if (ret < 0) {
printk(BIOS_ERR, "dsi init fail\n");
return;
}
- mtk_ddp_mode_set(&edid);
+ mtk_ddp_mode_set(&edid, dual_dsi_mode);
set_vbe_mode_info_valid(&edid, (uintptr_t)0);
}
@@ -264,13 +329,15 @@
mtk_dsi_pin_drv_ctrl();
if (display_init_required()) {
+ mtcmos_display_power_on();
if (IS_ENABLED(CONFIG_BOARD_GOOGLE_ROWAN)) {
- /* display initialization for Rowan */
+ configure_backlight_rowan();
+ configure_display_rowan();
} else {
configure_backlight();
configure_display();
- display_startup();
}
+ display_startup();
} else {
printk(BIOS_INFO, "Skipping display init.\n");
}
diff --git a/src/soc/mediatek/mt8173/ddp.c b/src/soc/mediatek/mt8173/ddp.c
index b7a8a6b..977a9e5 100644
--- a/src/soc/mediatek/mt8173/ddp.c
+++ b/src/soc/mediatek/mt8173/ddp.c
@@ -26,15 +26,22 @@
#define RDMA_FIFO_PSEUDO_SIZE(bytes) (((bytes) / 16) << 16)
#define RDMA_OUTPUT_VALID_FIFO_THRESHOLD(bytes) ((bytes) / 16)
-static void disp_config_main_path_connection(void)
+static void disp_config_main_path_connection(bool dual_dsi_mode)
{
write32(&mmsys_cfg->disp_ovl0_mout_en, OVL0_MOUT_EN_COLOR0);
+ write32(&mmsys_cfg->disp_color0_sel_in, COLOR0_SEL_IN_OVL0);
+
write32(&mmsys_cfg->disp_od_mout_en, OD_MOUT_EN_RDMA0);
- write32(&mmsys_cfg->disp_ufoe_mout_en, UFOE_MOUT_EN_DSI0);
-
- write32(&mmsys_cfg->disp_color0_sel_in, COLOR0_SEL_IN_OVL0);
+ if (dual_dsi_mode) {
+ write32(&mmsys_cfg->disp_ufoe_mout_en, UFOE_MOUT_EN_SPLIT1);
+ write32(&mmsys_cfg->dsi0_sel_in, DSI0_SEL_IN_SPLIT1);
+ write32(&mmsys_cfg->dsi1_sel_in, DSI1_SEL_IN_SPLIT1);
+ } else {
+ write32(&mmsys_cfg->disp_ufoe_mout_en, UFOE_MOUT_EN_DSI0);
+ write32(&mmsys_cfg->dsi0_sel_in, DSI0_SEL_IN_UFOE);
+ }
}
static void disp_config_main_path_mutex(void)
@@ -100,9 +107,15 @@
write32(&disp_od->en, 1);
}
-static void ufoe_start(void)
+static void ufoe_start(u32 width, u32 height, bool dual_dsi_mode)
{
- write32(&disp_ufoe->start, UFO_BYPASS);
+ if (dual_dsi_mode) {
+ write32(&disp_ufoe->frame_width, width);
+ write32(&disp_ufoe->frame_height, height);
+ write32(&disp_ufoe->start, UFO_LR);
+ } else {
+ write32(&disp_ufoe->start, UFO_BYPASS);
+ }
}
static void color_start(u32 width, u32 height)
@@ -111,6 +124,11 @@
write32(&disp_color[0]->height, height);
write32(&disp_color[0]->cfg_main, COLOR_BYPASS_ALL | COLOR_SEQ_SEL);
write32(&disp_color[0]->start, BIT(0));
+}
+
+static void split_start(void)
+{
+ write32(&disp_split->start, 1);
}
static void ovl_layer_config(u32 fmt, u32 bpp, u32 width, u32 height)
@@ -122,7 +140,8 @@
ovl_layer_enable();
}
-static void main_disp_path_setup(u32 width, u32 height, u32 pixel_clk)
+static void main_disp_path_setup(u32 width, u32 height, u32 pixel_clk,
+ bool dual_dsi_mode)
{
/* Setup OVL */
ovl_set_roi(width, height, 0);
@@ -134,44 +153,61 @@
od_start(width, height);
/* Setup UFOE */
- ufoe_start();
+ ufoe_start(width, height, dual_dsi_mode);
+
+ if (dual_dsi_mode)
+ split_start();
/* Setup Color */
color_start(width, height);
/* Setup main path connection */
- disp_config_main_path_connection();
+ disp_config_main_path_connection(dual_dsi_mode);
/* Setup main path mutex */
disp_config_main_path_mutex();
}
-static void disp_clock_on(void)
+static void disp_clock_on(bool dual_dsi_mode)
{
+ u32 dual_dsi_cg_con0;
+ u32 dual_dsi_cg_con1;
+
+ if (dual_dsi_mode) {
+ dual_dsi_cg_con0 = CG_CON0_DISP_SPLIT1;
+ dual_dsi_cg_con1 = CG_CON1_DSI1_ENGINE | CG_CON1_DSI1_DIGITAL;
+ } else {
+ dual_dsi_cg_con0 = 0;
+ dual_dsi_cg_con1 = 0;
+ }
+
clrbits_le32(&mmsys_cfg->mmsys_cg_con0, CG_CON0_SMI_COMMON |
CG_CON0_SMI_LARB0 |
CG_CON0_MUTEX_32K |
CG_CON0_DISP_OVL0 |
CG_CON0_DISP_RDMA0 |
CG_CON0_DISP_COLOR0 |
+ CG_CON0_DISP_UFOE |
+ dual_dsi_cg_con0 |
CG_CON0_DISP_OD);
clrbits_le32(&mmsys_cfg->mmsys_cg_con1, CG_CON1_DSI0_ENGINE |
- CG_CON1_DSI0_DIGITAL);
+ CG_CON1_DSI0_DIGITAL |
+ dual_dsi_cg_con1);
}
-void mtk_ddp_init(void)
+void mtk_ddp_init(bool dual_dsi_mode)
{
- disp_clock_on();
+ disp_clock_on(dual_dsi_mode);
}
-void mtk_ddp_mode_set(const struct edid *edid)
+void mtk_ddp_mode_set(const struct edid *edid, bool dual_dsi_mode)
{
u32 fmt = OVL_INFMT_RGBA8888;
u32 bpp = edid->framebuffer_bits_per_pixel / 8;
main_disp_path_setup(edid->mode.ha, edid->mode.va,
- edid->mode.pixel_clock);
+ edid->mode.pixel_clock, dual_dsi_mode);
rdma_start();
diff --git a/src/soc/mediatek/mt8173/dsi.c b/src/soc/mediatek/mt8173/dsi.c
index 3500bf1..b445d6c 100644
--- a/src/soc/mediatek/mt8173/dsi.c
+++ b/src/soc/mediatek/mt8173/dsi.c
@@ -20,7 +20,74 @@
#include <soc/i2c.h>
#include <soc/gpio.h>
#include <soc/dsi.h>
+#include <soc/ddp.h>
#include <timer.h>
+
+static bool dual_dsi_mode;
+
+static void mipi_write32(void *a, uint32_t v)
+{
+ void *a1 = a + (MIPI_TX1_BASE - MIPI_TX0_BASE);
+ write32(a, v);
+ if (dual_dsi_mode)
+ write32(a1, v);
+}
+
+static void mipi_clrsetbits_le32(void *a, uint32_t m, uint32_t v)
+{
+ void *a1 = a + (MIPI_TX1_BASE - MIPI_TX0_BASE);
+ clrsetbits_le32(a, m, v);
+ if (dual_dsi_mode)
+ clrsetbits_le32(a1, m, v);
+}
+
+static void mipi_clrbits_le32(void *a, uint32_t m)
+{
+ void *a1 = a + (MIPI_TX1_BASE - MIPI_TX0_BASE);
+ clrbits_le32(a, m);
+ if (dual_dsi_mode)
+ clrbits_le32(a1, m);
+}
+
+static void mipi_setbits_le32(void *a, uint32_t m)
+{
+ void *a1 = a + (MIPI_TX1_BASE - MIPI_TX0_BASE);
+ setbits_le32(a, m);
+ if (dual_dsi_mode)
+ setbits_le32(a1, m);
+}
+
+static void dsi_write32(void *a, uint32_t v)
+{
+ void *a1 = a + (DSI1_BASE - DSI0_BASE);
+ write32(a, v);
+ if (dual_dsi_mode)
+ write32(a1, v);
+}
+
+static void dsi_clrsetbits_le32(void *a, uint32_t m, uint32_t v)
+{
+ void *a1 = a + (DSI1_BASE - DSI0_BASE);
+ clrsetbits_le32(a, m, v);
+ if (dual_dsi_mode)
+ clrsetbits_le32(a1, m, v);
+}
+
+static void dsi_clrbits_le32(void *a, uint32_t m)
+{
+ void *a1 = a + (DSI1_BASE - DSI0_BASE);
+ clrbits_le32(a, m);
+ if (dual_dsi_mode)
+ clrbits_le32(a1, m);
+}
+
+static void dsi_setbits_le32(void *a, uint32_t m)
+{
+ void *a1 = a + (DSI1_BASE - DSI0_BASE);
+ setbits_le32(a, m);
+ if (dual_dsi_mode)
+ setbits_le32(a1, m);
+}
static int mtk_dsi_phy_clk_setting(u32 format, u32 lanes,
const struct edid *edid)
@@ -29,7 +96,7 @@
u64 pcw;
u32 reg;
u32 bit_per_pixel;
- int i, data_rate;
+ int i, data_rate, mipi_tx_rate;
reg = read32(&mipi_tx0->dsi_bg_con);
@@ -41,19 +108,19 @@
reg = (reg & (~RG_DSI_V12_SEL)) | (4 << 5);
reg |= RG_DSI_BG_CKEN;
reg |= RG_DSI_BG_CORE_EN;
- write32(&mipi_tx0->dsi_bg_con, reg);
+ mipi_write32(&mipi_tx0->dsi_bg_con, reg);
udelay(30);
- clrsetbits_le32(&mipi_tx0->dsi_top_con, RG_DSI_LNT_IMP_CAL_CODE,
+ mipi_clrsetbits_le32(&mipi_tx0->dsi_top_con, RG_DSI_LNT_IMP_CAL_CODE,
8 << 4 | RG_DSI_LNT_HS_BIAS_EN);
- setbits_le32(&mipi_tx0->dsi_con,
+ mipi_setbits_le32(&mipi_tx0->dsi_con,
RG_DSI0_CKG_LDOOUT_EN | RG_DSI0_LDOCORE_EN);
- clrsetbits_le32(&mipi_tx0->dsi_pll_pwr, RG_DSI_MPPLL_SDM_ISO_EN,
+ mipi_clrsetbits_le32(&mipi_tx0->dsi_pll_pwr, RG_DSI_MPPLL_SDM_ISO_EN,
RG_DSI_MPPLL_SDM_PWR_ON);
- clrbits_le32(&mipi_tx0->dsi_pll_con0, RG_DSI0_MPPLL_PLL_EN);
+ mipi_clrbits_le32(&mipi_tx0->dsi_pll_con0, RG_DSI0_MPPLL_PLL_EN);
switch (format) {
case MIPI_DSI_FMT_RGB565:
@@ -78,6 +145,10 @@
*/
data_rate = edid->mode.pixel_clock * 102 * bit_per_pixel /
(lanes * 1000 * 100);
+ mipi_tx_rate = data_rate;
+ if (dual_dsi_mode)
+ data_rate /= 2;
+
if (data_rate > 500) {
txdiv0 = 0;
txdiv1 = 0;
@@ -100,7 +171,7 @@
return -1;
}
- clrsetbits_le32(&mipi_tx0->dsi_pll_con0,
+ mipi_clrsetbits_le32(&mipi_tx0->dsi_pll_con0,
RG_DSI0_MPPLL_TXDIV1 | RG_DSI0_MPPLL_TXDIV0 |
RG_DSI0_MPPLL_PREDIV, txdiv1 << 5 | txdiv0 << 3);
@@ -114,23 +185,23 @@
*/
pcw = (u64)(data_rate * (1 << txdiv0) * (1 << txdiv1)) << 24;
pcw /= 13;
- write32(&mipi_tx0->dsi_pll_con2, pcw);
+ mipi_write32(&mipi_tx0->dsi_pll_con2, pcw);
- setbits_le32(&mipi_tx0->dsi_pll_con1, RG_DSI0_MPPLL_SDM_FRA_EN);
+ mipi_setbits_le32(&mipi_tx0->dsi_pll_con1, RG_DSI0_MPPLL_SDM_FRA_EN);
- setbits_le32(&mipi_tx0->dsi_clock_lane, LDOOUT_EN);
+ mipi_setbits_le32(&mipi_tx0->dsi_clock_lane, LDOOUT_EN);
for (i = 0; i < lanes; i++)
- setbits_le32(&mipi_tx0->dsi_data_lane[i], LDOOUT_EN);
+ mipi_setbits_le32(&mipi_tx0->dsi_data_lane[i], LDOOUT_EN);
- setbits_le32(&mipi_tx0->dsi_pll_con0, RG_DSI0_MPPLL_PLL_EN);
+ mipi_setbits_le32(&mipi_tx0->dsi_pll_con0, RG_DSI0_MPPLL_PLL_EN);
udelay(40);
- clrbits_le32(&mipi_tx0->dsi_pll_con1, RG_DSI0_MPPLL_SDM_SSC_EN);
- clrbits_le32(&mipi_tx0->dsi_top_con, RG_DSI_PAD_TIE_LOW_EN);
+ mipi_clrbits_le32(&mipi_tx0->dsi_pll_con1, RG_DSI0_MPPLL_SDM_SSC_EN);
+ mipi_clrbits_le32(&mipi_tx0->dsi_top_con, RG_DSI_PAD_TIE_LOW_EN);
- return data_rate;
+ return mipi_tx_rate;
}
static void mtk_dsi_phy_timconfig(u32 data_rate)
@@ -151,26 +222,26 @@
div_round_up(80 + 52 * ui, cycle_time) << 8 |
div_round_up(0x40, cycle_time);
- write32(&dsi0->dsi_phy_timecon0, timcon0);
- write32(&dsi0->dsi_phy_timecon1, timcon1);
- write32(&dsi0->dsi_phy_timecon2, timcon2);
- write32(&dsi0->dsi_phy_timecon3, timcon3);
+ dsi_write32(&dsi0->dsi_phy_timecon0, timcon0);
+ dsi_write32(&dsi0->dsi_phy_timecon1, timcon1);
+ dsi_write32(&dsi0->dsi_phy_timecon2, timcon2);
+ dsi_write32(&dsi0->dsi_phy_timecon3, timcon3);
}
static void mtk_dsi_reset(void)
{
- setbits_le32(&dsi0->dsi_con_ctrl, 3);
- clrbits_le32(&dsi0->dsi_con_ctrl, 1);
+ dsi_setbits_le32(&dsi0->dsi_con_ctrl, 3);
+ dsi_clrbits_le32(&dsi0->dsi_con_ctrl, 1);
}
static void mtk_dsi_clk_hs_mode_enable(void)
{
- setbits_le32(&dsi0->dsi_phy_lccon, LC_HS_TX_EN);
+ dsi_setbits_le32(&dsi0->dsi_phy_lccon, LC_HS_TX_EN);
}
static void mtk_dsi_clk_hs_mode_disable(void)
{
- clrbits_le32(&dsi0->dsi_phy_lccon, LC_HS_TX_EN);
+ dsi_clrbits_le32(&dsi0->dsi_phy_lccon, LC_HS_TX_EN);
}
static void mtk_dsi_set_mode(u32 mode_flags)
@@ -187,10 +258,10 @@
tmp_reg1 = SYNC_PULSE_MODE;
}
- write32(&dsi0->dsi_mode_ctrl, tmp_reg1);
+ dsi_write32(&dsi0->dsi_mode_ctrl, tmp_reg1);
}
-static void mtk_dsi_rxtx_control(u32 lanes)
+static void mtk_dsi_rxtx_control(u32 mode_flags, u32 lanes)
{
u32 tmp_reg = 0;
@@ -210,7 +281,10 @@
break;
}
- write32(&dsi0->dsi_txrx_ctrl, tmp_reg);
+ tmp_reg |= (mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) << 6;
+ tmp_reg |= (mode_flags & MIPI_DSI_MODE_EOT_PACKET) >> 3;
+
+ dsi_write32(&dsi0->dsi_txrx_ctrl, tmp_reg);
}
static void mtk_dsi_config_vdo_timing(u32 mode_flags, u32 format,
@@ -223,6 +297,7 @@
u32 vfp_byte;
u32 bpp;
u32 packet_fmt;
+ u32 hactive;
if (format == MIPI_DSI_FMT_RGB565)
bpp = 2;
@@ -233,10 +308,10 @@
edid->mode.vborder;
vfp_byte = edid->mode.vso - edid->mode.vborder;
- write32(&dsi0->dsi_vsa_nl, edid->mode.vspw);
- write32(&dsi0->dsi_vbp_nl, vbp_byte);
- write32(&dsi0->dsi_vfp_nl, vfp_byte);
- write32(&dsi0->dsi_vact_nl, edid->mode.va);
+ dsi_write32(&dsi0->dsi_vsa_nl, edid->mode.vspw);
+ dsi_write32(&dsi0->dsi_vbp_nl, vbp_byte);
+ dsi_write32(&dsi0->dsi_vfp_nl, vfp_byte);
+ dsi_write32(&dsi0->dsi_vact_nl, edid->mode.va);
if (mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
hbp_byte = (edid->mode.hbl - edid->mode.hso - edid->mode.hspw -
@@ -248,9 +323,9 @@
hsync_active_byte = edid->mode.hspw * bpp - 10;
hfp_byte = (edid->mode.hso - edid->mode.hborder) * bpp - 12;
- write32(&dsi0->dsi_hsa_wc, hsync_active_byte);
- write32(&dsi0->dsi_hbp_wc, hbp_byte);
- write32(&dsi0->dsi_hfp_wc, hfp_byte);
+ dsi_write32(&dsi0->dsi_hsa_wc, hsync_active_byte);
+ dsi_write32(&dsi0->dsi_hbp_wc, hbp_byte);
+ dsi_write32(&dsi0->dsi_hfp_wc, hfp_byte);
switch (format) {
case MIPI_DSI_FMT_RGB888:
@@ -270,31 +345,89 @@
break;
}
- packet_fmt |= edid->mode.ha * bpp & DSI_PS_WC;
- write32(&dsi0->dsi_psctrl, packet_fmt);
+ hactive = edid->mode.ha;
+ if (dual_dsi_mode)
+ hactive /= 2;
+ packet_fmt |= (hactive * bpp) & DSI_PS_WC;
+
+ dsi_write32(&dsi0->dsi_psctrl, packet_fmt);
}
static void mtk_dsi_start(void)
{
- write32(&dsi0->dsi_start, 0);
+ dsi_write32(&dsi0->dsi_start, 0);
+ /* Only start master DSI */
write32(&dsi0->dsi_start, 1);
}
-int mtk_dsi_init(u32 mode_flags, u32 format, u32 lanes,
+static void mtk_dsi_tx_cmd_type0(u8 cmd)
+{
+ struct stopwatch sw;
+ u32 cmdq0;
+ u32 intsta_0, intsta_1;
+
+ cmdq0 = (MIPI_DSI_DCS_SHORT_WRITE << 8) | SHORT_PACKET | (cmd << 16);
+
+ dsi_write32(&dsi0->dsi_cmdq0, cmdq0);
+ dsi_clrsetbits_le32(&dsi0->dsi_cmdq_size, CMDQ_SIZE, 1);
+ dsi_write32(&dsi0->dsi_intsta, 0);
+
+ dsi_write32(&dsi0->dsi_start, 1);
+
+ stopwatch_init_usecs_expire(&sw, 400);
+ do {
+ intsta_0 = read32(&dsi0->dsi_intsta);
+ intsta_1 = read32(&dsi1->dsi_intsta);
+ if ((intsta_0 & CMD_DONE_INT_FLAG) &&
+ (intsta_1 & CMD_DONE_INT_FLAG))
+ break;
+ udelay(4);
+ } while (!stopwatch_expired(&sw));
+
+ if (!(intsta_0 & CMD_DONE_INT_FLAG))
+ printk(BIOS_ERR, "DSI0 DONE INT Timeout\n");
+
+ if (!(intsta_1 & CMD_DONE_INT_FLAG))
+ printk(BIOS_ERR, "DSI1 DONE INT Timeout\n");
+
+ dsi_write32(&dsi0->dsi_start, 0);
+}
+
+int mtk_dsi_init(u32 mode_flags, u32 format, u32 lanes, bool dual,
const struct edid *edid)
{
- int data_rate = mtk_dsi_phy_clk_setting(format, lanes, edid);
+ int data_rate;
+
+ dual_dsi_mode = dual;
+
+ data_rate = mtk_dsi_phy_clk_setting(format, lanes, edid);
if (data_rate < 0)
return -1;
mtk_dsi_reset();
mtk_dsi_phy_timconfig(data_rate);
- mtk_dsi_rxtx_control(lanes);
+ mtk_dsi_rxtx_control(mode_flags, lanes);
mtk_dsi_clk_hs_mode_disable();
mtk_dsi_config_vdo_timing(mode_flags, format, edid);
mtk_dsi_set_mode(mode_flags);
mtk_dsi_clk_hs_mode_enable();
+
+ if (dual_dsi_mode) {
+ dsi_write32(&dsi0->dsi_start, 0);
+ /* Disable dual_dsi when in CMD_MODE */
+ dsi_write32(&dsi0->dsi_con_ctrl, DSI_EN);
+
+ dsi_write32(&dsi0->dsi_mode_ctrl, CMD_MODE);
+
+ mtk_dsi_tx_cmd_type0(MIPI_DCS_EXIT_SLEEP_MODE);
+ mtk_dsi_tx_cmd_type0(MIPI_DCS_SET_DISPLAY_ON);
+
+ dsi_write32(&dsi0->dsi_con_ctrl, DSI_EN | DSI_DUAL);
+
+ dsi_write32(&dsi0->dsi_mode_ctrl, BURST_MODE);
+ }
+
mtk_dsi_start();
return 0;
@@ -303,8 +436,9 @@
void mtk_dsi_pin_drv_ctrl(void)
{
struct stopwatch sw;
+ uint32_t pwr_ack;
- setbits_le32(&lvds_tx1->vopll_ctl3, RG_DA_LVDSTX_PWR_ON);
+ mipi_setbits_le32(&lvds_tx1->vopll_ctl3, RG_DA_LVDSTX_PWR_ON);
stopwatch_init_usecs_expire(&sw, 1000);
@@ -313,7 +447,11 @@
printk(BIOS_ERR, "enable lvdstx_power failed!!!\n");
return;
}
- } while ((read32(&lvds_tx1->vopll_ctl3) & RG_AD_LVDSTX_PWR_ACK) == 0);
+ pwr_ack = read32(&lvds_tx1->vopll_ctl3) & RG_AD_LVDSTX_PWR_ACK;
+ if (dual_dsi_mode)
+ pwr_ack &= read32(&lvds_tx2->vopll_ctl3) &
+ RG_AD_LVDSTX_PWR_ACK;
+ } while (pwr_ack == 0);
- clrbits_le32(&lvds_tx1->vopll_ctl3, RG_DA_LVDS_ISO_EN);
+ mipi_clrbits_le32(&lvds_tx1->vopll_ctl3, RG_DA_LVDS_ISO_EN);
}
diff --git a/src/soc/mediatek/mt8173/include/soc/addressmap.h b/src/soc/mediatek/mt8173/include/soc/addressmap.h
index 00c9a6e..3b67c09 100644
--- a/src/soc/mediatek/mt8173/include/soc/addressmap.h
+++ b/src/soc/mediatek/mt8173/include/soc/addressmap.h
@@ -63,6 +63,7 @@
DISP_RDMA2_BASE = IO_PHYS + 0x4010000,
DISP_COLOR0_BASE = IO_PHYS + 0x4013000,
DISP_COLOR1_BASE = IO_PHYS + 0x4014000,
+ DISP_SPLIT1_BASE = IO_PHYS + 0x4019000,
DISP_UFOE_BASE = IO_PHYS + 0x401A000,
DSI0_BASE = IO_PHYS + 0x401B000,
DSI1_BASE = IO_PHYS + 0x401C000,
diff --git a/src/soc/mediatek/mt8173/include/soc/ddp.h b/src/soc/mediatek/mt8173/include/soc/ddp.h
index 9846b1a..20e356a 100644
--- a/src/soc/mediatek/mt8173/include/soc/ddp.h
+++ b/src/soc/mediatek/mt8173/include/soc/ddp.h
@@ -140,6 +140,7 @@
u32 hdmi_en;
};
+check_member(mmsys_cfg_regs, mmsys_sw1_rst_b, 0x144);
check_member(mmsys_cfg_regs, hdmi_en, 0x904);
static struct mmsys_cfg_regs * const mmsys_cfg = (void *) MMSYS_BASE;
@@ -206,7 +207,20 @@
OVL0_MOUT_EN_COLOR0 = BIT(0),
OD_MOUT_EN_RDMA0 = BIT(0),
UFOE_MOUT_EN_DSI0 = BIT(0),
- COLOR0_SEL_IN_OVL0 = BIT(0),
+ UFOE_MOUT_EN_SPLIT1 = BIT(1),
+};
+
+enum {
+ COLOR0_SEL_IN_OVL0 = 1,
+ DSI0_SEL_IN_UFOE = 0,
+ DSI0_SEL_IN_SPLIT1 = 1,
+ DSI1_SEL_IN_SPLIT1 = 0,
+};
+
+/* MMSYS_SW1_RST_B */
+enum {
+ MMSYS_SW1_RST_DSI0_B = BIT(2),
+ MMSYS_SW1_RST_DSI1_B = BIT(3),
};
struct disp_mutex_regs {
@@ -386,7 +400,14 @@
enum {
UFO_BYPASS = BIT(2),
+ UFO_LR = BIT(3) | BIT(0),
};
+
+struct disp_split_regs {
+ u32 start;
+};
+
+static struct disp_split_regs * const disp_split = (void *)DISP_SPLIT1_BASE;
struct disp_color_regs {
u8 reserved0[1024];
@@ -426,7 +447,7 @@
OVL_INFMT_ABGR8888 = OVL_INFMT_ARGB8888 + OVL_COLOR_BASE,
};
-void mtk_ddp_init(void);
-void mtk_ddp_mode_set(const struct edid *edid);
+void mtk_ddp_init(bool dual_dsi_mode);
+void mtk_ddp_mode_set(const struct edid *edid, bool dual_dsi_mode);
#endif
diff --git a/src/soc/mediatek/mt8173/include/soc/dsi.h b/src/soc/mediatek/mt8173/include/soc/dsi.h
index 73f4425..68f45d1 100644
--- a/src/soc/mediatek/mt8173/include/soc/dsi.h
+++ b/src/soc/mediatek/mt8173/include/soc/dsi.h
@@ -71,21 +71,45 @@
u32 dsi_hbp_wc;
u32 dsi_hfp_wc;
u32 dsi_bllp_wc;
- u8 reserved2[4];
+ u32 dsi_cmdq_size;
u32 dsi_hstx_cklp_wc;
- u8 reserved3[156];
+ u8 reserved2[156];
u32 dsi_phy_lccon;
u32 dsi_phy_ld0con;
- u8 reserved4[4];
+ u8 reserved3[4];
u32 dsi_phy_timecon0;
u32 dsi_phy_timecon1;
u32 dsi_phy_timecon2;
u32 dsi_phy_timecon3;
+ u8 reserved4[16];
+ u32 dsi_vm_cmd_con;
+ u8 reserved5[204];
+ u32 dsi_cmdq0;
};
check_member(dsi_regs, dsi_phy_lccon, 0x104);
check_member(dsi_regs, dsi_phy_timecon3, 0x11c);
+check_member(dsi_regs, dsi_vm_cmd_con, 0x130);
+check_member(dsi_regs, dsi_cmdq0, 0x200);
static struct dsi_regs * const dsi0 = (void *)DSI0_BASE;
+static struct dsi_regs * const dsi1 = (void *)DSI1_BASE;
+
+/* DSI_INTSTA */
+enum {
+ LPRX_RD_RDY_INT_FLAG = BIT(0),
+ CMD_DONE_INT_FLAG = BIT(1),
+ TE_RDY_INT_FLAG = BIT(2),
+ VM_DONE_INT_FLAG = BIT(3),
+ EXT_TE_RDY_INT_FLAG = BIT(4),
+ DSI_BUSY = BIT(31),
+};
+
+/* DSI_CON_CTRL */
+enum {
+ DSI_RESET = BIT(0),
+ DSI_EN = BIT(1),
+ DSI_DUAL = BIT(4),
+};
/* DSI_MODE_CTRL */
enum {
@@ -106,6 +130,11 @@
LOOSELY_PS_18BIT_RGB666 = (1 << 16),
PACKED_PS_18BIT_RGB666 = (2 << 16),
PACKED_PS_24BIT_RGB888 = (3 << 16)
+};
+
+/* DSI_CMDQ_SIZE */
+enum {
+ CMDQ_SIZE = 0x3f,
};
/* DSI_PHY_LCCON */
@@ -148,6 +177,23 @@
CLK_HS_EXIT = (0xf << 16)
};
+/* DSI_VM_CMD_CON */
+enum {
+ VM_CMD_EN = BIT(0),
+ TS_VFP_EN = BIT(5),
+};
+
+/* DSI_CMDQ0 */
+enum {
+ CONFIG = (0xff << 0),
+ SHORT_PACKET = 0,
+ LONG_PACKET = 2,
+ BTA = BIT(2),
+ DATA_ID = (0xff << 8),
+ DATA_0 = (0xff << 16),
+ DATA_1 = (0xff << 24),
+};
+
/* MIPITX_REG */
struct mipi_tx_regs {
u32 dsi_con;
@@ -182,6 +228,7 @@
check_member(mipi_tx_regs, dsi_pll_pwr, 0x68);
static struct mipi_tx_regs * const mipi_tx0 = (void *)MIPI_TX0_BASE;
+static struct mipi_tx_regs * const mipi_tx1 = (void *)MIPI_TX0_BASE;
/* MIPITX_DSI0_CON */
enum {
@@ -276,6 +323,7 @@
};
static struct lvds_tx1_regs * const lvds_tx1 = (void *)(MIPI_TX0_BASE + 0x800);
+static struct lvds_tx1_regs * const lvds_tx2 = (void *)(MIPI_TX1_BASE + 0x800);
/* LVDS_VOPLL_CTRL3 */
enum {
@@ -288,8 +336,114 @@
RG_DA_LVDSTX_PWR_ON = BIT(9)
};
+/* MIPI DSI Processor-to-Peripheral transaction types */
+enum {
+ MIPI_DSI_V_SYNC_START = 0x01,
+ MIPI_DSI_V_SYNC_END = 0x11,
+ MIPI_DSI_H_SYNC_START = 0x21,
+ MIPI_DSI_H_SYNC_END = 0x31,
+
+ MIPI_DSI_COLOR_MODE_OFF = 0x02,
+ MIPI_DSI_COLOR_MODE_ON = 0x12,
+ MIPI_DSI_SHUTDOWN_PERIPHERAL = 0x22,
+ MIPI_DSI_TURN_ON_PERIPHERAL = 0x32,
+
+ MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM = 0x03,
+ MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM = 0x13,
+ MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM = 0x23,
+
+ MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM = 0x04,
+ MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM = 0x14,
+ MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM = 0x24,
+
+ MIPI_DSI_DCS_SHORT_WRITE = 0x05,
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM = 0x15,
+
+ MIPI_DSI_DCS_READ = 0x06,
+
+ MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE = 0x37,
+
+ MIPI_DSI_END_OF_TRANSMISSION = 0x08,
+
+ MIPI_DSI_NULL_PACKET = 0x09,
+ MIPI_DSI_BLANKING_PACKET = 0x19,
+ MIPI_DSI_GENERIC_LONG_WRITE = 0x29,
+ MIPI_DSI_DCS_LONG_WRITE = 0x39,
+
+ MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20 = 0x0c,
+ MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24 = 0x1c,
+ MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16 = 0x2c,
+
+ MIPI_DSI_PACKED_PIXEL_STREAM_30 = 0x0d,
+ MIPI_DSI_PACKED_PIXEL_STREAM_36 = 0x1d,
+ MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12 = 0x3d,
+
+ MIPI_DSI_PACKED_PIXEL_STREAM_16 = 0x0e,
+ MIPI_DSI_PACKED_PIXEL_STREAM_18 = 0x1e,
+ MIPI_DSI_PIXEL_STREAM_3BYTE_18 = 0x2e,
+ MIPI_DSI_PACKED_PIXEL_STREAM_24 = 0x3e,
+};
+
+/* MIPI DSI Peripheral-to-Processor transaction types */
+enum {
+ MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT = 0x02,
+ MIPI_DSI_RX_END_OF_TRANSMISSION = 0x08,
+ MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE = 0x11,
+ MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE = 0x12,
+ MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE = 0x1a,
+ MIPI_DSI_RX_DCS_LONG_READ_RESPONSE = 0x1c,
+ MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE = 0x21,
+ MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE = 0x22,
+};
+
+/* MIPI DCS commands */
+enum {
+ MIPI_DCS_NOP = 0x00,
+ MIPI_DCS_SOFT_RESET = 0x01,
+ MIPI_DCS_GET_DISPLAY_ID = 0x04,
+ MIPI_DCS_GET_RED_CHANNEL = 0x06,
+ MIPI_DCS_GET_GREEN_CHANNEL = 0x07,
+ MIPI_DCS_GET_BLUE_CHANNEL = 0x08,
+ MIPI_DCS_GET_DISPLAY_STATUS = 0x09,
+ MIPI_DCS_GET_POWER_MODE = 0x0A,
+ MIPI_DCS_GET_ADDRESS_MODE = 0x0B,
+ MIPI_DCS_GET_PIXEL_FORMAT = 0x0C,
+ MIPI_DCS_GET_DISPLAY_MODE = 0x0D,
+ MIPI_DCS_GET_SIGNAL_MODE = 0x0E,
+ MIPI_DCS_GET_DIAGNOSTIC_RESULT = 0x0F,
+ MIPI_DCS_ENTER_SLEEP_MODE = 0x10,
+ MIPI_DCS_EXIT_SLEEP_MODE = 0x11,
+ MIPI_DCS_ENTER_PARTIAL_MODE = 0x12,
+ MIPI_DCS_ENTER_NORMAL_MODE = 0x13,
+ MIPI_DCS_EXIT_INVERT_MODE = 0x20,
+ MIPI_DCS_ENTER_INVERT_MODE = 0x21,
+ MIPI_DCS_SET_GAMMA_CURVE = 0x26,
+ MIPI_DCS_SET_DISPLAY_OFF = 0x28,
+ MIPI_DCS_SET_DISPLAY_ON = 0x29,
+ MIPI_DCS_SET_COLUMN_ADDRESS = 0x2A,
+ MIPI_DCS_SET_PAGE_ADDRESS = 0x2B,
+ MIPI_DCS_WRITE_MEMORY_START = 0x2C,
+ MIPI_DCS_WRITE_LUT = 0x2D,
+ MIPI_DCS_READ_MEMORY_START = 0x2E,
+ MIPI_DCS_SET_PARTIAL_AREA = 0x30,
+ MIPI_DCS_SET_SCROLL_AREA = 0x33,
+ MIPI_DCS_SET_TEAR_OFF = 0x34,
+ MIPI_DCS_SET_TEAR_ON = 0x35,
+ MIPI_DCS_SET_ADDRESS_MODE = 0x36,
+ MIPI_DCS_SET_SCROLL_START = 0x37,
+ MIPI_DCS_EXIT_IDLE_MODE = 0x38,
+ MIPI_DCS_ENTER_IDLE_MODE = 0x39,
+ MIPI_DCS_SET_PIXEL_FORMAT = 0x3A,
+ MIPI_DCS_WRITE_MEMORY_CONTINUE = 0x3C,
+ MIPI_DCS_READ_MEMORY_CONTINUE = 0x3E,
+ MIPI_DCS_SET_TEAR_SCANLINE = 0x44,
+ MIPI_DCS_GET_SCANLINE = 0x45,
+ MIPI_DCS_READ_DDB_START = 0xA1,
+ MIPI_DCS_READ_DDB_CONTINUE = 0xA8,
+};
+
int mtk_dsi_init(u32 mode_flags, enum mipi_dsi_pixel_format format, u32 lanes,
- const struct edid *edid);
+ bool dual_dsi_mode, const struct edid *edid);
void mtk_dsi_pin_drv_ctrl(void);
#endif
--
To view, visit https://review.coreboot.org/19361
To unsubscribe, visit https://review.coreboot.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Id47dfd7d9e98689b54398fc8d9142336b41dc29f
Gerrit-PatchSet: 1
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Owner: Daniel Kurtz <djkurtz at google.com>
Gerrit-Reviewer: Daniel Kurtz <djkurtz at chromium.org>
More information about the coreboot-gerrit
mailing list