summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJitao Shi <jitao.shi@mediatek.com>2017-02-07 08:51:01 +0800
committerJulius Werner <jwerner@chromium.org>2017-04-25 02:36:55 +0200
commitb927fe19549eaf045e9372f21d1ba19f65fc669f (patch)
treecd8883c534918e037499666eea8eb4d6bcdc3a4c
parent2332adacaf9776f0eb8335c05bc0e65f9c1b2e3e (diff)
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@mediatek.com> Signed-off-by: Daniel Kurtz <djkurtz@chromium.org> Reviewed-on: https://review.coreboot.org/19361 Tested-by: build bot (Jenkins) Reviewed-by: Julius Werner <jwerner@chromium.org>
-rw-r--r--src/mainboard/google/oak/mainboard.c7
-rw-r--r--src/soc/mediatek/mt8173/ddp.c66
-rw-r--r--src/soc/mediatek/mt8173/dsi.c222
-rw-r--r--src/soc/mediatek/mt8173/include/soc/addressmap.h1
-rw-r--r--src/soc/mediatek/mt8173/include/soc/ddp.h27
-rw-r--r--src/soc/mediatek/mt8173/include/soc/dsi.h162
6 files changed, 418 insertions, 67 deletions
diff --git a/src/mainboard/google/oak/mainboard.c b/src/mainboard/google/oak/mainboard.c
index 2e17678cb1..4320f6ec1c 100644
--- a/src/mainboard/google/oak/mainboard.c
+++ b/src/mainboard/google/oak/mainboard.c
@@ -212,6 +212,7 @@ static void display_startup(void)
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 @@ static void display_startup(void)
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 b7a8a6b670..977a9e5fe8 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_od_mout_en, OD_MOUT_EN_RDMA0);
+ write32(&mmsys_cfg->disp_color0_sel_in, COLOR0_SEL_IN_OVL0);
- write32(&mmsys_cfg->disp_ufoe_mout_en, UFOE_MOUT_EN_DSI0);
+ write32(&mmsys_cfg->disp_od_mout_en, OD_MOUT_EN_RDMA0);
- 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 @@ static void od_start(u32 width, u32 height)
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)
@@ -113,6 +126,11 @@ static void color_start(u32 width, u32 height)
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)
{
write32(&disp_ovl[0]->layer[0].con, fmt << 12);
@@ -122,7 +140,8 @@ static void ovl_layer_config(u32 fmt, u32 bpp, u32 width, u32 height)
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 @@ static void main_disp_path_setup(u32 width, u32 height, u32 pixel_clk)
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 3500bf1d01..b445d6c6ea 100644
--- a/src/soc/mediatek/mt8173/dsi.c
+++ b/src/soc/mediatek/mt8173/dsi.c
@@ -20,8 +20,75 @@
#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 @@ static int mtk_dsi_phy_clk_setting(u32 format, u32 lanes,
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 @@ static int mtk_dsi_phy_clk_setting(u32 format, u32 lanes,
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 @@ static int mtk_dsi_phy_clk_setting(u32 format, u32 lanes,
*/
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 @@ static int mtk_dsi_phy_clk_setting(u32 format, u32 lanes,
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 @@ static int mtk_dsi_phy_clk_setting(u32 format, u32 lanes,
*/
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 @@ static void mtk_dsi_phy_timconfig(u32 data_rate)
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 @@ static void mtk_dsi_set_mode(u32 mode_flags)
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 @@ static void mtk_dsi_rxtx_control(u32 lanes)
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 @@ static void mtk_dsi_config_vdo_timing(u32 mode_flags, u32 format,
u32 vfp_byte;
u32 bpp;
u32 packet_fmt;
+ u32 hactive;
if (format == MIPI_DSI_FMT_RGB565)
bpp = 2;
@@ -233,10 +308,10 @@ static void mtk_dsi_config_vdo_timing(u32 mode_flags, u32 format,
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 @@ static void mtk_dsi_config_vdo_timing(u32 mode_flags, u32 format,
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 @@ static void mtk_dsi_config_vdo_timing(u32 mode_flags, u32 format,
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 @@ int mtk_dsi_init(u32 mode_flags, u32 format, u32 lanes,
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 @@ void mtk_dsi_pin_drv_ctrl(void)
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 cab127be75..cc1b39d67c 100644
--- a/src/soc/mediatek/mt8173/include/soc/addressmap.h
+++ b/src/soc/mediatek/mt8173/include/soc/addressmap.h
@@ -64,6 +64,7 @@ enum {
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 9846b1ad40..20e356a909 100644
--- a/src/soc/mediatek/mt8173/include/soc/ddp.h
+++ b/src/soc/mediatek/mt8173/include/soc/ddp.h
@@ -140,6 +140,7 @@ struct mmsys_cfg_regs {
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 @@ enum {
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,8 +400,15 @@ static struct disp_ufoe_regs * const disp_ufoe = (void *)DISP_UFOE_BASE;
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];
u32 cfg_main;
@@ -426,7 +447,7 @@ enum OVL_INPUT_FORMAT {
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 73f4425684..68f45d1144 100644
--- a/src/soc/mediatek/mt8173/include/soc/dsi.h
+++ b/src/soc/mediatek/mt8173/include/soc/dsi.h
@@ -71,21 +71,45 @@ struct dsi_regs {
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 {
@@ -108,6 +132,11 @@ enum {
PACKED_PS_24BIT_RGB888 = (3 << 16)
};
+/* DSI_CMDQ_SIZE */
+enum {
+ CMDQ_SIZE = 0x3f,
+};
+
/* DSI_PHY_LCCON */
enum {
LC_HS_TX_EN = BIT(0),
@@ -148,6 +177,23 @@ enum {
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_top_con, 0x40);
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 @@ struct lvds_tx1_regs {
};
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 @@ enum {
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