mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 18:09:56 +00:00
DRM: rp1: rp1-dsi: Fix escape clock divider and timeouts.
Escape clock divider was fixed at 5, which is correct at 800Mbps/lane but increasingly out of spec for higher rates. Compute it correctly. High speed timeout was fixed at 5*512 == 2560 byte-clocks per lane. Compute it conservatively to be 8/7 times the line period (assuming there will be a transition to LP some time during each scanline?) keeping the old value as a lower bound. Increase LPRX TO to 1024, and BTA TO to 0xb00 (same value as in bridge/synopsys/dw-mipi-dsi). (No change to LP_CMD_TIM. To do: compute this correctly.) Signed-off-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
This commit is contained in:
committed by
Dom Cobley
parent
7630cd526b
commit
f44df36745
@@ -1336,10 +1336,17 @@ static u32 get_colorcode(enum mipi_dsi_pixel_format fmt)
|
|||||||
return 0x005;
|
return 0x005;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Maximum frequency for LP escape clock (20MHz), and some magic numbers */
|
||||||
|
#define RP1DSI_ESC_CLK_KHZ 20000
|
||||||
|
#define RP1DSI_TO_CLK_DIV 5
|
||||||
|
#define RP1DSI_HSTX_TO_MIN 0x200
|
||||||
|
#define RP1DSI_LPRX_TO_VAL 0x400
|
||||||
|
#define RP1DSI_BTA_TO_VAL 0xd00
|
||||||
|
|
||||||
void rp1dsi_dsi_setup(struct rp1_dsi *dsi, struct drm_display_mode const *mode)
|
void rp1dsi_dsi_setup(struct rp1_dsi *dsi, struct drm_display_mode const *mode)
|
||||||
{
|
{
|
||||||
u32 timeout, mask, vid_mode_cfg;
|
u32 timeout, mask, vid_mode_cfg;
|
||||||
u32 freq_khz;
|
int lane_kbps;
|
||||||
unsigned int bpp = mipi_dsi_pixel_format_to_bpp(dsi->display_format);
|
unsigned int bpp = mipi_dsi_pixel_format_to_bpp(dsi->display_format);
|
||||||
|
|
||||||
DSI_WRITE(DSI_PHY_IF_CFG, dsi->lanes - 1);
|
DSI_WRITE(DSI_PHY_IF_CFG, dsi->lanes - 1);
|
||||||
@@ -1349,28 +1356,33 @@ void rp1dsi_dsi_setup(struct rp1_dsi *dsi, struct drm_display_mode const *mode)
|
|||||||
/* a conservative guess (LP escape is slow!) */
|
/* a conservative guess (LP escape is slow!) */
|
||||||
DSI_WRITE(DSI_DPI_LP_CMD_TIM, 0x00100000);
|
DSI_WRITE(DSI_DPI_LP_CMD_TIM, 0x00100000);
|
||||||
|
|
||||||
/* Drop to LP where possible */
|
/* Drop to LP where possible; use LP Escape for all commands */
|
||||||
vid_mode_cfg = 0xbf00;
|
vid_mode_cfg = 0xbf00;
|
||||||
if (!(dsi->display_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE))
|
if (!(dsi->display_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE))
|
||||||
vid_mode_cfg |= 0x01;
|
vid_mode_cfg |= 0x01;
|
||||||
if (dsi->display_flags & MIPI_DSI_MODE_VIDEO_BURST)
|
if (dsi->display_flags & MIPI_DSI_MODE_VIDEO_BURST)
|
||||||
vid_mode_cfg |= 0x02;
|
vid_mode_cfg |= 0x02;
|
||||||
DSI_WRITE(DSI_VID_MODE_CFG, vid_mode_cfg);
|
DSI_WRITE(DSI_VID_MODE_CFG, vid_mode_cfg);
|
||||||
|
|
||||||
/* Use LP Escape Data signalling for all commands */
|
|
||||||
DSI_WRITE(DSI_CMD_MODE_CFG, 0x10F7F00);
|
DSI_WRITE(DSI_CMD_MODE_CFG, 0x10F7F00);
|
||||||
|
|
||||||
/* Select Command Mode */
|
/* Select Command Mode */
|
||||||
DSI_WRITE(DSI_MODE_CFG, 1);
|
DSI_WRITE(DSI_MODE_CFG, 1);
|
||||||
/* XXX magic number */
|
|
||||||
DSI_WRITE(DSI_TO_CNT_CFG, 0x02000200);
|
|
||||||
/* XXX magic number */
|
|
||||||
DSI_WRITE(DSI_BTA_TO_CNT, 0x800);
|
|
||||||
|
|
||||||
|
/* Set timeouts and clock dividers */
|
||||||
|
DSI_WRITE(DSI_TO_CNT_CFG,
|
||||||
|
(max((bpp * mode->htotal) / (7 * RP1DSI_TO_CLK_DIV * dsi->lanes),
|
||||||
|
RP1DSI_HSTX_TO_MIN) << 16) |
|
||||||
|
RP1DSI_LPRX_TO_VAL);
|
||||||
|
DSI_WRITE(DSI_BTA_TO_CNT, RP1DSI_BTA_TO_VAL);
|
||||||
|
lane_kbps = (bpp * mode->clock) / dsi->lanes;
|
||||||
|
DSI_WRITE(DSI_CLKMGR_CFG,
|
||||||
|
(RP1DSI_TO_CLK_DIV << 8) |
|
||||||
|
max(2, lane_kbps / (8 * RP1DSI_ESC_CLK_KHZ) + 1));
|
||||||
|
|
||||||
|
/* Configure video timings */
|
||||||
DSI_WRITE(DSI_VID_PKT_SIZE, mode->hdisplay);
|
DSI_WRITE(DSI_VID_PKT_SIZE, mode->hdisplay);
|
||||||
DSI_WRITE(DSI_VID_NUM_CHUNKS, 0);
|
DSI_WRITE(DSI_VID_NUM_CHUNKS, 0);
|
||||||
DSI_WRITE(DSI_VID_NULL_SIZE, 0);
|
DSI_WRITE(DSI_VID_NULL_SIZE, 0);
|
||||||
|
|
||||||
/* Note, unlike Argon firmware, here we DON'T consider sync to be concurrent with porch */
|
|
||||||
DSI_WRITE(DSI_VID_HSA_TIME,
|
DSI_WRITE(DSI_VID_HSA_TIME,
|
||||||
(bpp * (mode->hsync_end - mode->hsync_start)) / (8 * dsi->lanes));
|
(bpp * (mode->hsync_end - mode->hsync_start)) / (8 * dsi->lanes));
|
||||||
DSI_WRITE(DSI_VID_HBP_TIME,
|
DSI_WRITE(DSI_VID_HBP_TIME,
|
||||||
@@ -1381,9 +1393,8 @@ void rp1dsi_dsi_setup(struct rp1_dsi *dsi, struct drm_display_mode const *mode)
|
|||||||
DSI_WRITE(DSI_VID_VFP_LINES, (mode->vsync_start - mode->vdisplay));
|
DSI_WRITE(DSI_VID_VFP_LINES, (mode->vsync_start - mode->vdisplay));
|
||||||
DSI_WRITE(DSI_VID_VACTIVE_LINES, mode->vdisplay);
|
DSI_WRITE(DSI_VID_VACTIVE_LINES, mode->vdisplay);
|
||||||
|
|
||||||
freq_khz = (bpp * mode->clock) / dsi->lanes;
|
/* Init PHY */
|
||||||
|
dphy_init_khz(dsi, rp1dsi_refclk_freq(dsi) / 1000, lane_kbps);
|
||||||
dphy_init_khz(dsi, rp1dsi_refclk_freq(dsi) / 1000, freq_khz);
|
|
||||||
|
|
||||||
DSI_WRITE(DSI_PHY_TMR_LPCLK_CFG,
|
DSI_WRITE(DSI_PHY_TMR_LPCLK_CFG,
|
||||||
(hsfreq_table[dsi->hsfreq_index].clk_lp2hs << DSI_PHY_TMR_LP2HS_LSB) |
|
(hsfreq_table[dsi->hsfreq_index].clk_lp2hs << DSI_PHY_TMR_LP2HS_LSB) |
|
||||||
@@ -1392,8 +1403,6 @@ void rp1dsi_dsi_setup(struct rp1_dsi *dsi, struct drm_display_mode const *mode)
|
|||||||
(hsfreq_table[dsi->hsfreq_index].data_lp2hs << DSI_PHY_TMR_LP2HS_LSB) |
|
(hsfreq_table[dsi->hsfreq_index].data_lp2hs << DSI_PHY_TMR_LP2HS_LSB) |
|
||||||
(hsfreq_table[dsi->hsfreq_index].data_hs2lp << DSI_PHY_TMR_HS2LP_LSB));
|
(hsfreq_table[dsi->hsfreq_index].data_hs2lp << DSI_PHY_TMR_HS2LP_LSB));
|
||||||
|
|
||||||
DSI_WRITE(DSI_CLKMGR_CFG, 0x00000505);
|
|
||||||
|
|
||||||
/* Wait for PLL lock */
|
/* Wait for PLL lock */
|
||||||
for (timeout = (1 << 14); timeout != 0; --timeout) {
|
for (timeout = (1 << 14); timeout != 0; --timeout) {
|
||||||
usleep_range(10, 50);
|
usleep_range(10, 50);
|
||||||
|
|||||||
Reference in New Issue
Block a user