Hung-Te Lin has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/34773 )
Change subject: soc/mediatek: dsi: Support sending MIPI init commands ......................................................................
soc/mediatek: dsi: Support sending MIPI init commands
For systems with real MIPI panels (8173/oak was using PS8640 eDP bridge), we have to send DCS commands to initialize panel.
BUG=b:80501386,b:117254947 TEST=make -j # board = oak and boots
Change-Id: Ie7c824873465ac82a95bcb0ed67b8b9866987008 Signed-off-by: Hung-Te Lin hungte@chromium.org --- M src/mainboard/google/oak/mainboard.c M src/soc/mediatek/common/dsi.c M src/soc/mediatek/common/include/soc/dsi_common.h M src/soc/mediatek/mt8173/include/soc/dsi.h 4 files changed, 150 insertions(+), 8 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/73/34773/1
diff --git a/src/mainboard/google/oak/mainboard.c b/src/mainboard/google/oak/mainboard.c index 0dce17d..bac6fc5 100644 --- a/src/mainboard/google/oak/mainboard.c +++ b/src/mainboard/google/oak/mainboard.c @@ -234,7 +234,7 @@ edid_set_framebuffer_bits_per_pixel(&edid, 32, 0);
mtk_ddp_init(); - ret = mtk_dsi_init(mipi_dsi_flags, MIPI_DSI_FMT_RGB888, 4, &edid); + ret = mtk_dsi_init(mipi_dsi_flags, MIPI_DSI_FMT_RGB888, 4, &edid, NULL); if (ret < 0) { printk(BIOS_ERR, "dsi init fail\n"); return; diff --git a/src/soc/mediatek/common/dsi.c b/src/soc/mediatek/common/dsi.c index 17b127a..a269fe9 100644 --- a/src/soc/mediatek/common/dsi.c +++ b/src/soc/mediatek/common/dsi.c @@ -13,6 +13,7 @@ * GNU General Public License for more details. */
+#include <assert.h> #include <device/mmio.h> #include <console/console.h> #include <device/mmio.h> @@ -223,7 +224,134 @@ write32(&dsi0->dsi_start, 1); }
-int mtk_dsi_init(u32 mode_flags, u32 format, u32 lanes, const struct edid *edid) +static bool mtk_dsi_is_read_command(u32 type) +{ + switch (type) { + case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM: + case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM: + case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM: + case MIPI_DSI_DCS_READ: + return true; + } + return false; +} + +static void mtk_dsi_cmdq(u8 *data, u8 len, u32 type) +{ + struct stopwatch sw; + u8 *tx_buf = data; + u8 cmdq_size; + u32 reg_val, cmdq_mask, i, config, cmdq_off, intsta_0; + + while (read32(&dsi0->dsi_intsta) & (1 << 31)) { + printk(BIOS_ERR, "%s wait dsi no busy\n", __func__); + mdelay(20); + } + + write32(&dsi0->dsi_intsta, 0); + + if (mtk_dsi_is_read_command(type)) + config = BTA; + else + config = (len > 2) ? LONG_PACKET : SHORT_PACKET; + + if (len > 2) { + cmdq_size = 1 + (len + 3) / 4; + cmdq_off = 4; + cmdq_mask = CONFIG | DATA_ID | DATA_0 | DATA_1; + reg_val = (len << 16) | (type << 8) | config; + } else { + cmdq_size = 1; + cmdq_off = 2; + cmdq_mask = CONFIG | DATA_ID; + reg_val = (type << 8) | config; + } + + for (i = 0; i < ARRAY_SIZE(dsi0->dsi_cmdq); i++) + write32(&dsi0->dsi_cmdq[i], 0); + + u8 *cmdq0 = (u8 *)&dsi0->dsi_cmdq[0]; + for (i = 0; i < len; i++) { + clrsetbits_le32(cmdq0 + ((cmdq_off + i) & (0xfffffffc)), + (0xff << (((i + cmdq_off) & 3) * 8)), + tx_buf[i] << (((i + cmdq_off) & 3) * 8)); + } + + clrsetbits_le32(&dsi0->dsi_cmdq[0], cmdq_mask, reg_val); + clrsetbits_le32(&dsi0->dsi_cmdq_size, CMDQ_SIZE, cmdq_size); + mtk_dsi_start(); + + stopwatch_init_usecs_expire(&sw, 400); + do { + intsta_0 = read32(&dsi0->dsi_intsta); + if (intsta_0 & CMD_DONE_INT_FLAG) + break; + udelay(4); + } while (!stopwatch_expired(&sw)); + + if (!(intsta_0 & CMD_DONE_INT_FLAG)) + printk(BIOS_ERR, "dsi send cmd time-out(400uS)\n"); +} + +static void mtk_dsi_send_init_commands(struct lcm_init_table *init_cmd) +{ + assert(init_cmd); + + for (; init_cmd->cmd != LCM_END_CMD; init_cmd++) { + u32 cmd = init_cmd->cmd, len = init_cmd->len; + u32 type; + + switch (cmd) { + case LCM_DELAY_CMD: + mdelay(len); + continue; + + case LCM_DCS_CMD: + switch (len) { + case 0: + return; + case 1: + type = MIPI_DSI_DCS_SHORT_WRITE; + break; + case 2: + type = MIPI_DSI_DCS_SHORT_WRITE_PARAM; + break; + default: + type = MIPI_DSI_DCS_LONG_WRITE; + break; + } + break; + + case LCM_GENERIC_CMD: + switch (len) { + case 0: + type = MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM; + break; + case 1: + type = MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM; + break; + case 2: + type = MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM; + break; + default: + type = MIPI_DSI_GENERIC_LONG_WRITE; + break; + } + break; + + default: + printk(BIOS_ERR, "%s: Unknown cmd: %d, abort\n", + __func__, cmd); + return; + + } + assert(len <= sizeof(init_cmd->data)); + mtk_dsi_cmdq(init_cmd->data, len, type); + } +} + +int mtk_dsi_init(u32 mode_flags, u32 format, u32 lanes, + const struct edid *edid, struct lcm_init_table *init_cmd) { int data_rate; u32 bpp = mtk_dsi_get_bits_per_pixel(format); @@ -239,9 +367,10 @@ mtk_dsi_rxtx_control(mode_flags, lanes); mtk_dsi_clk_hs_mode_disable(); mtk_dsi_config_vdo_timing(mode_flags, format, lanes, edid, &phy_timing); - mtk_dsi_set_mode(mode_flags); mtk_dsi_clk_hs_mode_enable(); - + if (init_cmd) + mtk_dsi_send_init_commands(init_cmd); + mtk_dsi_set_mode(mode_flags); mtk_dsi_start();
return 0; diff --git a/src/soc/mediatek/common/include/soc/dsi_common.h b/src/soc/mediatek/common/include/soc/dsi_common.h index 3e72c58..8597b60 100644 --- a/src/soc/mediatek/common/include/soc/dsi_common.h +++ b/src/soc/mediatek/common/include/soc/dsi_common.h @@ -40,6 +40,18 @@ u8 clk_hs_exit; };
+/* Definitions for cmd in lcm_init_table */ +#define LCM_END_CMD 0 +#define LCM_DELAY_CMD 1 +#define LCM_GENERIC_CMD 2 +#define LCM_DCS_CMD 3 + +struct lcm_init_table { + u32 cmd; + u32 len; + u8 data[7]; +}; + /* Functions that each SOC should provide. */ void mtk_dsi_reset(void); /* mtk_dsi_phy_clk_setting should return the data rate in Mbps. */ @@ -49,7 +61,8 @@ void mtk_dsi_override_phy_timing(struct mtk_phy_timing *timing);
/* Public API provided in common/dsi.c */ -int mtk_dsi_init(u32 mode_flags, u32 format, u32 lanes, - const struct edid *edid); +int mtk_dsi_bpp_from_format(u32 format); +int mtk_dsi_init(u32 mode_flags, u32 format, u32 lanes, const struct edid *edid, + struct lcm_init_table *init_cmd);
#endif // SOC_MEDIATEK_DSI_COMMON_H diff --git a/src/soc/mediatek/mt8173/include/soc/dsi.h b/src/soc/mediatek/mt8173/include/soc/dsi.h index e57bfc5..96d0aad 100644 --- a/src/soc/mediatek/mt8173/include/soc/dsi.h +++ b/src/soc/mediatek/mt8173/include/soc/dsi.h @@ -85,13 +85,13 @@ u8 reserved4[16]; u32 dsi_vm_cmd_con; u8 reserved5[204]; - u32 dsi_cmdq0; + u32 dsi_cmdq[128]; };
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); +check_member(dsi_regs, dsi_cmdq, 0x200); static struct dsi_regs *const dsi0 = (void *)DSI0_BASE; static struct dsi_regs *const dsi1 = (void *)DSI1_BASE;