Julius Werner merged this change.

View Change

Approvals: build bot (Jenkins): Verified Julius Werner: Looks good to me, approved Hung-Te Lin: Looks good to me, approved
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>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/34773
Reviewed-by: Julius Werner <jwerner@chromium.org>
Tested-by: build bot (Jenkins) <no-reply@coreboot.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
3 files changed, 139 insertions(+), 8 deletions(-)

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 392b02d..fffe51f 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>
@@ -256,7 +257,124 @@
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 @@
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 0738876..3f4a47d 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 @@
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 @@
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_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 */

To view, visit change 34773. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: Ie7c824873465ac82a95bcb0ed67b8b9866987008
Gerrit-Change-Number: 34773
Gerrit-PatchSet: 21
Gerrit-Owner: Hung-Te Lin <hungte@chromium.org>
Gerrit-Reviewer: Hung-Te Lin <hungte@chromium.org>
Gerrit-Reviewer: Julius Werner <jwerner@chromium.org>
Gerrit-Reviewer: Nicolas Boichat <drinkcat@chromium.org>
Gerrit-Reviewer: You-Cheng Syu <youcheng@google.com>
Gerrit-Reviewer: Yu-Ping Wu <yupingso@google.com>
Gerrit-Reviewer: build bot (Jenkins) <no-reply@coreboot.org>
Gerrit-Reviewer: jitao shi <jitao.shi@mediatek.com>
Gerrit-Reviewer: yongqiang niu <yongqiang.niu@mediatek.com>
Gerrit-CC: Paul Menzel <paulepanter@users.sourceforge.net>
Gerrit-MessageType: merged