soc/mediatek: dsi: reduce the hbp and hfp for phy timing
The extra data transfer in DSI, namely, lpx, hs_prepare, hs_zero, hs_exit and the sof/eof of DSI packets, will enlarge the line time, which causes the real frame on dsi bus to be lower than the one calculated by video timing. Therefore, hfp_byte is reduced by d_phy to compensate the increase in time by the extra data transfer. However, if hfp_byte is not large enough, the hsync period will be increased on DSI data, leading to display scrolling in firmware screen. To avoid this situation, this patch changes the DSI Tx driver to reduce both hfp_byte and hbp_byte, with the amount proportional to hfp and hbp, respectively. Refer to kernel's change in CL:1915442. Also rename 'phy_timing' to 'timing' to sync with kernel upstream. Since the phy timing initialization sequence has been corrected, the m value adjustment in the analogix driver can be removed. BUG=b:144824303 BRANCH=kukui TEST=emerge-jacuzzi coreboot TEST=Boots and sees firmware screen on krane and juniper TEST=No scrolling issue on juniper AUO and InnoLux panels Change-Id: I10a4d8a4fb41c309fa1917cf1cdf19dabed98227 Signed-off-by: Yu-Ping Wu <yupingso@google.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/38400 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Hung-Te Lin <hungte@chromium.org>
This commit is contained in:
parent
443fbd7049
commit
f68cc81513
|
@ -273,7 +273,7 @@ static int anx7625_calculate_m_n(u32 pixelclock,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
*m = (unsigned long long)pixelclock * 599 / 600;
|
*m = pixelclock;
|
||||||
*n = XTAL_FRQ / post_divider;
|
*n = XTAL_FRQ / post_divider;
|
||||||
*pd = post_divider;
|
*pd = post_divider;
|
||||||
|
|
||||||
|
|
|
@ -74,47 +74,43 @@ __weak void mtk_dsi_override_phy_timing(struct mtk_phy_timing *timing)
|
||||||
/* Do nothing. */
|
/* Do nothing. */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mtk_dsi_phy_timing(u32 data_rate, struct mtk_phy_timing *phy_timing)
|
static void mtk_dsi_phy_timing(u32 data_rate, struct mtk_phy_timing *timing)
|
||||||
{
|
{
|
||||||
u32 cycle_time, ui;
|
u32 timcon0, timcon1, timcon2, timcon3;
|
||||||
u32 data_rate_mhz = DIV_ROUND_UP(data_rate, MHz);
|
u32 data_rate_mhz = DIV_ROUND_UP(data_rate, MHz);
|
||||||
|
|
||||||
ui = 1000 / data_rate_mhz + 0x01;
|
memset(timing, 0, sizeof(*timing));
|
||||||
cycle_time = 8000 / data_rate_mhz + 0x01;
|
|
||||||
|
|
||||||
memset(phy_timing, 0, sizeof(*phy_timing));
|
timing->lpx = (60 * data_rate_mhz / (8 * 1000)) + 1;
|
||||||
|
timing->da_hs_prepare = (80 * data_rate_mhz + 4 * 1000) / 8000;
|
||||||
|
timing->da_hs_zero = (170 * data_rate_mhz + 10 * 1000) / 8000 + 1 -
|
||||||
|
timing->da_hs_prepare;
|
||||||
|
timing->da_hs_trail = timing->da_hs_prepare + 1;
|
||||||
|
|
||||||
phy_timing->lpx = DIV_ROUND_UP(60, cycle_time);
|
timing->ta_go = 4 * timing->lpx - 2;
|
||||||
phy_timing->da_hs_prepare = DIV_ROUND_UP((50 + 5 * ui), cycle_time);
|
timing->ta_sure = timing->lpx + 2;
|
||||||
phy_timing->da_hs_zero = DIV_ROUND_UP((110 + 6 * ui), cycle_time);
|
timing->ta_get = 4 * timing->lpx;
|
||||||
phy_timing->da_hs_trail = DIV_ROUND_UP(((4 * ui) + 77), cycle_time);
|
timing->da_hs_exit = 2 * timing->lpx + 1;
|
||||||
|
|
||||||
phy_timing->ta_go = 4U * phy_timing->lpx;
|
timing->da_hs_sync = 1;
|
||||||
phy_timing->ta_sure = 3U * phy_timing->lpx / 2U;
|
|
||||||
phy_timing->ta_get = 5U * phy_timing->lpx;
|
|
||||||
phy_timing->da_hs_exit = 2U * phy_timing->lpx;
|
|
||||||
|
|
||||||
phy_timing->da_hs_sync = 1;
|
timing->clk_hs_prepare = 70 * data_rate_mhz / (8 * 1000);
|
||||||
phy_timing->clk_hs_zero = DIV_ROUND_UP(0x150U, cycle_time);
|
timing->clk_hs_post = timing->clk_hs_prepare + 8;
|
||||||
phy_timing->clk_hs_trail = DIV_ROUND_UP(0x64U, cycle_time) + 0xaU;
|
timing->clk_hs_trail = timing->clk_hs_prepare;
|
||||||
|
timing->clk_hs_zero = timing->clk_hs_trail * 4;
|
||||||
phy_timing->clk_hs_prepare = DIV_ROUND_UP(0x40U, cycle_time);
|
timing->clk_hs_exit = 2 * timing->clk_hs_trail;
|
||||||
phy_timing->clk_hs_post = DIV_ROUND_UP(80U + 52U * ui, cycle_time);
|
|
||||||
phy_timing->clk_hs_exit = 2U * phy_timing->lpx;
|
|
||||||
|
|
||||||
/* Allow board-specific tuning. */
|
/* Allow board-specific tuning. */
|
||||||
mtk_dsi_override_phy_timing(phy_timing);
|
mtk_dsi_override_phy_timing(timing);
|
||||||
|
|
||||||
u32 timcon0, timcon1, timcon2, timcon3;
|
timcon0 = timing->lpx | timing->da_hs_prepare << 8 |
|
||||||
|
timing->da_hs_zero << 16 | timing->da_hs_trail << 24;
|
||||||
timcon0 = phy_timing->lpx | phy_timing->da_hs_prepare << 8 |
|
timcon1 = timing->ta_go | timing->ta_sure << 8 |
|
||||||
phy_timing->da_hs_zero << 16 | phy_timing->da_hs_trail << 24;
|
timing->ta_get << 16 | timing->da_hs_exit << 24;
|
||||||
timcon1 = phy_timing->ta_go | phy_timing->ta_sure << 8 |
|
timcon2 = timing->da_hs_sync << 8 | timing->clk_hs_zero << 16 |
|
||||||
phy_timing->ta_get << 16 | phy_timing->da_hs_exit << 24;
|
timing->clk_hs_trail << 24;
|
||||||
timcon2 = phy_timing->da_hs_sync << 8 | phy_timing->clk_hs_zero << 16 |
|
timcon3 = timing->clk_hs_prepare | timing->clk_hs_post << 8 |
|
||||||
phy_timing->clk_hs_trail << 24;
|
timing->clk_hs_exit << 16;
|
||||||
timcon3 = phy_timing->clk_hs_prepare | phy_timing->clk_hs_post << 8 |
|
|
||||||
phy_timing->clk_hs_exit << 16;
|
|
||||||
|
|
||||||
write32(&dsi0->dsi_phy_timecon0, timcon0);
|
write32(&dsi0->dsi_phy_timecon0, timcon0);
|
||||||
write32(&dsi0->dsi_phy_timecon1, timcon1);
|
write32(&dsi0->dsi_phy_timecon1, timcon1);
|
||||||
|
@ -180,6 +176,8 @@ static void mtk_dsi_config_vdo_timing(u32 mode_flags, u32 format, u32 lanes,
|
||||||
const struct mtk_phy_timing *phy_timing)
|
const struct mtk_phy_timing *phy_timing)
|
||||||
{
|
{
|
||||||
u32 hsync_active_byte;
|
u32 hsync_active_byte;
|
||||||
|
u32 hbp;
|
||||||
|
u32 hfp;
|
||||||
u32 hbp_byte;
|
u32 hbp_byte;
|
||||||
u32 hfp_byte;
|
u32 hfp_byte;
|
||||||
u32 vbp_byte;
|
u32 vbp_byte;
|
||||||
|
@ -199,17 +197,20 @@ static void mtk_dsi_config_vdo_timing(u32 mode_flags, u32 format, u32 lanes,
|
||||||
write32(&dsi0->dsi_vfp_nl, vfp_byte);
|
write32(&dsi0->dsi_vfp_nl, vfp_byte);
|
||||||
write32(&dsi0->dsi_vact_nl, edid->mode.va);
|
write32(&dsi0->dsi_vact_nl, edid->mode.va);
|
||||||
|
|
||||||
unsigned int hspw = 0;
|
|
||||||
if (mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
|
|
||||||
hspw = edid->mode.hspw;
|
|
||||||
|
|
||||||
hbp_byte = (edid->mode.hbl - edid->mode.hso - hspw - edid->mode.hborder)
|
|
||||||
* bytes_per_pixel - 10;
|
|
||||||
hsync_active_byte = edid->mode.hspw * bytes_per_pixel - 10;
|
hsync_active_byte = edid->mode.hspw * bytes_per_pixel - 10;
|
||||||
hfp_byte = (edid->mode.hso - edid->mode.hborder) * bytes_per_pixel;
|
|
||||||
|
hbp = edid->mode.hbl - edid->mode.hso - edid->mode.hspw -
|
||||||
|
edid->mode.hborder;
|
||||||
|
hfp = edid->mode.hso - edid->mode.hborder;
|
||||||
|
|
||||||
|
if (mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
|
||||||
|
hbp_byte = hbp * bytes_per_pixel - 10;
|
||||||
|
else
|
||||||
|
hbp_byte = (hbp + edid->mode.hspw) * bytes_per_pixel - 10;
|
||||||
|
hfp_byte = hfp * bytes_per_pixel;
|
||||||
|
|
||||||
data_phy_cycles = phy_timing->lpx + phy_timing->da_hs_prepare +
|
data_phy_cycles = phy_timing->lpx + phy_timing->da_hs_prepare +
|
||||||
phy_timing->da_hs_zero + phy_timing->da_hs_exit + 2;
|
phy_timing->da_hs_zero + phy_timing->da_hs_exit + 3;
|
||||||
|
|
||||||
u32 delta = 12;
|
u32 delta = 12;
|
||||||
if (mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
|
if (mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
|
||||||
|
@ -218,11 +219,14 @@ static void mtk_dsi_config_vdo_timing(u32 mode_flags, u32 format, u32 lanes,
|
||||||
u32 d_phy = phy_timing->d_phy;
|
u32 d_phy = phy_timing->d_phy;
|
||||||
if (d_phy == 0)
|
if (d_phy == 0)
|
||||||
d_phy = data_phy_cycles * lanes + delta;
|
d_phy = data_phy_cycles * lanes + delta;
|
||||||
if (hfp_byte > d_phy)
|
|
||||||
hfp_byte -= d_phy;
|
if ((hfp + hbp) * bytes_per_pixel > d_phy) {
|
||||||
else
|
hfp_byte -= d_phy * hfp / (hfp + hbp);
|
||||||
printk(BIOS_ERR, "HFP is not greater than d-phy, FPS < 60Hz "
|
hbp_byte -= d_phy * hbp / (hfp + hbp);
|
||||||
"and the panel may not work properly.\n");
|
} else {
|
||||||
|
printk(BIOS_ERR, "HFP plus HBP is not greater than d_phy, "
|
||||||
|
"the panel may not work properly.\n");
|
||||||
|
}
|
||||||
|
|
||||||
write32(&dsi0->dsi_hsa_wc, hsync_active_byte);
|
write32(&dsi0->dsi_hsa_wc, hsync_active_byte);
|
||||||
write32(&dsi0->dsi_hbp_wc, hbp_byte);
|
write32(&dsi0->dsi_hbp_wc, hbp_byte);
|
||||||
|
|
Loading…
Reference in New Issue