[coreboot-gerrit] Change in coreboot[master]: mediatek/mt8173: Add support for Dual DSI output

Julius Werner (Code Review) gerrit at coreboot.org
Tue Apr 25 02:36:56 CEST 2017


Julius Werner has submitted this change and it was merged. ( https://review.coreboot.org/19361 )

Change subject: mediatek/mt8173: Add support for Dual DSI output
......................................................................


mediatek/mt8173: Add support for Dual DSI output

The MT817x display output pipeline can be configured to drive an 8-lane
MIPI/DSI panel using "dual DSI" mode.  For the "dual DSI" video data path,
the UFO block is configured to reorder the data stream into left and right
halves which are then sent by the SPLIT1 block to the DSI0 and DSI1
respectively.  The DSI0 and DSI1 outputs are then synchronously clocked at
half the nominal data rate by their respective MIPI_TX0/MIPI_TX1 phys.

Also, update the call sites in oak mainboard to avoid build breakage.

BRANCH=none
BUG=b:35774871
TEST=Boot Rowan in developer mode and see output on the panel

Change-Id: Id47dfd7d9e98689b54398fc8d9142336b41dc29f
Signed-off-by: Jitao Shi <jitao.shi at mediatek.com>
Signed-off-by: Daniel Kurtz <djkurtz at chromium.org>
Reviewed-on: https://review.coreboot.org/19361
Tested-by: build bot (Jenkins)
Reviewed-by: Julius Werner <jwerner at chromium.org>
---
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, 418 insertions(+), 67 deletions(-)

Approvals:
  Julius Werner: Looks good to me, approved
  build bot (Jenkins): Verified



diff --git a/src/mainboard/google/oak/mainboard.c b/src/mainboard/google/oak/mainboard.c
index 2e17678..4320f6e 100644
--- a/src/mainboard/google/oak/mainboard.c
+++ b/src/mainboard/google/oak/mainboard.c
@@ -212,6 +212,7 @@
 	struct edid edid;
 	u8 i2c_bus, i2c_addr;
 	int ret;
+	bool dual_dsi_mode = false;
 
 	if (board_id() + CONFIG_BOARD_ID_ADJUSTMENT > 6) {
 		i2c_bus = 0;
@@ -231,15 +232,15 @@
 
 	edid_set_framebuffer_bits_per_pixel(&edid, 32, 0);
 
-	mtk_ddp_init();
+	mtk_ddp_init(dual_dsi_mode);
 	ret = mtk_dsi_init(MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
-			   MIPI_DSI_FMT_RGB888, 4, &edid);
+			   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);
 }
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 cab127b..cc1b39d 100644
--- a/src/soc/mediatek/mt8173/include/soc/addressmap.h
+++ b/src/soc/mediatek/mt8173/include/soc/addressmap.h
@@ -64,6 +64,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: merged
Gerrit-Change-Id: Id47dfd7d9e98689b54398fc8d9142336b41dc29f
Gerrit-PatchSet: 4
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Owner: Daniel Kurtz <djkurtz at google.com>
Gerrit-Reviewer: Aaron Durbin <adurbin at chromium.org>
Gerrit-Reviewer: Daniel Kurtz <djkurtz at chromium.org>
Gerrit-Reviewer: Daniel Kurtz <djkurtz at google.com>
Gerrit-Reviewer: Julius Werner <jwerner at chromium.org>
Gerrit-Reviewer: Paul Menzel <paulepanter at users.sourceforge.net>
Gerrit-Reviewer: build bot (Jenkins)



More information about the coreboot-gerrit mailing list