[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