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>
This commit is contained in:
Hung-Te Lin 2019-08-07 10:31:27 +08:00 committed by Julius Werner
parent 3b217d5c69
commit 75e4314675
3 changed files with 139 additions and 8 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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 */