From 75e4314675cecf6faf7c02920a86f3157e6ba5c1 Mon Sep 17 00:00:00 2001 From: Hung-Te Lin Date: Wed, 7 Aug 2019 10:31:27 +0800 Subject: 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 Reviewed-on: https://review.coreboot.org/c/coreboot/+/34773 Reviewed-by: Julius Werner Tested-by: build bot (Jenkins) --- src/soc/mediatek/common/dsi.c | 124 ++++++++++++++++++++++- src/soc/mediatek/common/include/soc/dsi_common.h | 21 +++- 2 files changed, 138 insertions(+), 7 deletions(-) (limited to 'src/soc') diff --git a/src/soc/mediatek/common/dsi.c b/src/soc/mediatek/common/dsi.c index 392b02d24d..fffe51f708 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 #include #include #include @@ -256,7 +257,124 @@ static void mtk_dsi_start(void) 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(const u8 *data, u8 len, u32 type) +{ + const u8 *tx_buf = data; + u32 config; + int i, j; + + if (!wait_ms(20, !(read32(&dsi0->dsi_intsta) & DSI_BUSY))) { + printk(BIOS_ERR, "%s: cannot get DSI ready for sending commands" + " after 20ms and the panel may not work properly.\n", + __func__); + return; + } + 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) { + uint32_t val = (type << 8) | config; + for (i = 0; i < len; i++) + val |= tx_buf[i] << (i + 2) * 8; + write32(&dsi0->dsi_cmdq[0], val); + write32(&dsi0->dsi_cmdq_size, 1); + } else { + /* TODO(hungte) Replace by buffer_to_fifo32_prefix */ + write32(&dsi0->dsi_cmdq[0], (len << 16) | (type << 8) | config); + for (i = 0; i < len; i += 4) { + uint32_t val = 0; + for (j = 0; j < MIN(len - i, 4); j++) + val |= tx_buf[i + j] << j * 8; + write32(&dsi0->dsi_cmdq[i / 4 + 1], val); + } + write32(&dsi0->dsi_cmdq_size, 1 + DIV_ROUND_UP(len, 4)); + } + + mtk_dsi_start(); + + if (!wait_us(400, read32(&dsi0->dsi_intsta) & CMD_DONE_INT_FLAG)) { + printk(BIOS_ERR, "%s: failed sending DSI command, " + "panel may not work.\n", __func__); + return; + } +} + +static void mtk_dsi_send_init_commands(const struct lcm_init_command *init) +{ + if (!init) + return; + + for (; init->cmd != LCM_END_CMD; init++) { + u32 cmd = init->cmd, len = init->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 panel initialization.\n", __func__, cmd); + return; + + } + assert(len <= sizeof(init->data)); + mtk_dsi_cmdq(init->data, len, type); + } +} + +int mtk_dsi_init(u32 mode_flags, u32 format, u32 lanes, const struct edid *edid, + const struct lcm_init_command *init_commands) { int data_rate; u32 bits_per_pixel = mtk_dsi_get_bits_per_pixel(format); @@ -272,9 +390,9 @@ int mtk_dsi_init(u32 mode_flags, u32 format, u32 lanes, const struct edid *edid) 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(); - + mtk_dsi_send_init_commands(init_commands); + 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 0738876aea..3f4a47d1b8 100644 --- a/src/soc/mediatek/common/include/soc/dsi_common.h +++ b/src/soc/mediatek/common/include/soc/dsi_common.h @@ -85,14 +85,14 @@ struct dsi_regs { u8 reserved4[16]; u32 dsi_vm_cmd_con; u8 reserved5[204]; - u32 dsi_cmdq0; + u32 dsi_cmdq[128]; }; static struct dsi_regs *const dsi0 = (void *)DSI0_BASE; 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); /* DSI_INTSTA */ enum { @@ -324,6 +324,18 @@ struct mtk_phy_timing { u32 d_phy; }; +/* Definitions for cmd in lcm_init_command */ +#define LCM_END_CMD 0 +#define LCM_DELAY_CMD 1 +#define LCM_GENERIC_CMD 2 +#define LCM_DCS_CMD 3 + +struct lcm_init_command { + u16 cmd; + u16 len; + u8 data[8]; +}; + /* Functions that each SOC should provide. */ void mtk_dsi_reset(void); void mtk_dsi_configure_mipi_tx(int data_rate, u32 lanes); @@ -332,7 +344,8 @@ void mtk_dsi_configure_mipi_tx(int data_rate, u32 lanes); 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, + const struct lcm_init_command *init_commands); #endif /* SOC_MEDIATEK_DSI_COMMON_H */ -- cgit v1.2.3