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:
parent
3b217d5c69
commit
75e4314675
|
@ -234,7 +234,7 @@ static void display_startup(void)
|
||||||
edid_set_framebuffer_bits_per_pixel(&edid, 32, 0);
|
edid_set_framebuffer_bits_per_pixel(&edid, 32, 0);
|
||||||
|
|
||||||
mtk_ddp_init();
|
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) {
|
if (ret < 0) {
|
||||||
printk(BIOS_ERR, "dsi init fail\n");
|
printk(BIOS_ERR, "dsi init fail\n");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <device/mmio.h>
|
#include <device/mmio.h>
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <device/mmio.h>
|
#include <device/mmio.h>
|
||||||
|
@ -256,7 +257,124 @@ static void mtk_dsi_start(void)
|
||||||
write32(&dsi0->dsi_start, 1);
|
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;
|
int data_rate;
|
||||||
u32 bits_per_pixel = mtk_dsi_get_bits_per_pixel(format);
|
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_rxtx_control(mode_flags, lanes);
|
||||||
mtk_dsi_clk_hs_mode_disable();
|
mtk_dsi_clk_hs_mode_disable();
|
||||||
mtk_dsi_config_vdo_timing(mode_flags, format, lanes, edid, &phy_timing);
|
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_clk_hs_mode_enable();
|
||||||
|
mtk_dsi_send_init_commands(init_commands);
|
||||||
|
mtk_dsi_set_mode(mode_flags);
|
||||||
mtk_dsi_start();
|
mtk_dsi_start();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -85,14 +85,14 @@ struct dsi_regs {
|
||||||
u8 reserved4[16];
|
u8 reserved4[16];
|
||||||
u32 dsi_vm_cmd_con;
|
u32 dsi_vm_cmd_con;
|
||||||
u8 reserved5[204];
|
u8 reserved5[204];
|
||||||
u32 dsi_cmdq0;
|
u32 dsi_cmdq[128];
|
||||||
};
|
};
|
||||||
static struct dsi_regs *const dsi0 = (void *)DSI0_BASE;
|
static struct dsi_regs *const dsi0 = (void *)DSI0_BASE;
|
||||||
|
|
||||||
check_member(dsi_regs, dsi_phy_lccon, 0x104);
|
check_member(dsi_regs, dsi_phy_lccon, 0x104);
|
||||||
check_member(dsi_regs, dsi_phy_timecon3, 0x11c);
|
check_member(dsi_regs, dsi_phy_timecon3, 0x11c);
|
||||||
check_member(dsi_regs, dsi_vm_cmd_con, 0x130);
|
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 */
|
/* DSI_INTSTA */
|
||||||
enum {
|
enum {
|
||||||
|
@ -324,6 +324,18 @@ struct mtk_phy_timing {
|
||||||
u32 d_phy;
|
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. */
|
/* Functions that each SOC should provide. */
|
||||||
void mtk_dsi_reset(void);
|
void mtk_dsi_reset(void);
|
||||||
void mtk_dsi_configure_mipi_tx(int data_rate, u32 lanes);
|
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);
|
void mtk_dsi_override_phy_timing(struct mtk_phy_timing *timing);
|
||||||
|
|
||||||
/* Public API provided in common/dsi.c */
|
/* Public API provided in common/dsi.c */
|
||||||
int mtk_dsi_init(u32 mode_flags, u32 format, u32 lanes,
|
int mtk_dsi_bpp_from_format(u32 format);
|
||||||
const struct edid *edid);
|
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 */
|
#endif /* SOC_MEDIATEK_DSI_COMMON_H */
|
||||||
|
|
Loading…
Reference in New Issue