summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mainboard/google/oak/mainboard.c2
-rw-r--r--src/soc/mediatek/common/dsi.c124
-rw-r--r--src/soc/mediatek/common/include/soc/dsi_common.h21
3 files changed, 139 insertions, 8 deletions
diff --git a/src/mainboard/google/oak/mainboard.c b/src/mainboard/google/oak/mainboard.c
index 0dce17d40d..bac6fc50c7 100644
--- a/src/mainboard/google/oak/mainboard.c
+++ b/src/mainboard/google/oak/mainboard.c
@@ -234,7 +234,7 @@ static void display_startup(void)
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 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 <assert.h>
#include <device/mmio.h>
#include <console/console.h>
#include <device/mmio.h>
@@ -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 */