Setting up burst mode display would require to compute - Horizontal timing edge values to fill burst drq register - Line, sync values to fill burst line register Since there is no direct documentation for these computations the edge and line formulas are taken from BSP code (from linux-sunxi/ drivers/video/sunxi/disp2/disp/de/lowlevel_sun50iw1/de_dsi.c) line_num = panel->lcd_ht*dsi_pixel_bits[panel->lcd_dsi_format]/ (8*panel->lcd_dsi_lane); edge1 = sync_point+(panel->lcd_x+panel->lcd_hbp+20)* dsi_pixel_bits[panel->lcd_dsi_format] /(8*panel->lcd_dsi_lane); edge1 = (edge1>line_num)?line_num:edge1; edge0 = edge1+(panel->lcd_x+40)*tcon_div/8; edge0 = (edge0>line_num)?(edge0-line_num):1; Signed-off-by: Jagan Teki <jagan@xxxxxxxxxxxxxxxxxxxx> --- drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 70 ++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c index 2aeaa19a8d1e..46ad142e66e8 100644 --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c @@ -355,6 +355,41 @@ static void sun6i_dsi_inst_init(struct sun6i_dsi *dsi, SUN6I_DSI_INST_JUMP_CFG_NUM(1)); }; +static u32 sun6i_dsi_get_edge1(struct sun6i_dsi *dsi, + struct drm_display_mode *mode, u32 sync_point) +{ + struct mipi_dsi_device *device = dsi->device; + unsigned int bpp = mipi_dsi_pixel_format_to_bpp(device->format); + u32 hact_sync_bp; + + /* Horizontal timings duration excluding front porch */ + hact_sync_bp = (mode->hdisplay + mode->htotal - mode->hsync_start); + + return (sync_point + ((hact_sync_bp + 20) * bpp / (8 * device->lanes))); +} + +static u32 sun6i_dsi_get_edge0(struct sun6i_dsi *dsi, + struct drm_display_mode *mode, u32 edge1) +{ + struct sun4i_tcon *tcon = dsi->tcon; + unsigned long dclk_rate, dclk_parent_rate, tcon0_div; + + dclk_rate = clk_get_rate(tcon->dclk); + dclk_parent_rate = clk_get_rate(clk_get_parent(tcon->dclk)); + tcon0_div = dclk_parent_rate / dclk_rate; + + return (edge1 + (mode->hdisplay + 40) * tcon0_div / 8); +} + +static u32 sun6i_dsi_get_line_num(struct sun6i_dsi *dsi, + struct drm_display_mode *mode) +{ + struct mipi_dsi_device *device = dsi->device; + unsigned int bpp = mipi_dsi_pixel_format_to_bpp(device->format); + + return (mode->htotal * bpp / (8 * device->lanes)); +} + static int sun6i_dsi_get_drq(struct sun6i_dsi *dsi, struct drm_display_mode *mode) { @@ -404,8 +439,32 @@ static u16 sun6i_dsi_get_video_start_delay(struct sun6i_dsi *dsi, static void sun6i_dsi_setup_burst(struct sun6i_dsi *dsi, struct drm_display_mode *mode) { - regmap_write(dsi->regs, SUN6I_DSI_TCON_DRQ_REG, - sun6i_dsi_get_drq(dsi, mode)); + struct mipi_dsi_device *device = dsi->device; + u32 sync_point = 40; + u32 line_num = sun6i_dsi_get_line_num(dsi, mode); + u32 edge1 = sun6i_dsi_get_edge1(dsi, mode, sync_point); + u32 edge0 = sun6i_dsi_get_edge0(dsi, mode, edge1); + u32 val; + + if (edge1 > line_num) + edge1 = line_num; + + if (edge0 > line_num) + edge0 -= line_num; + else + edge0 = 1; + + regmap_write(dsi->regs, SUN6I_DSI_BURST_DRQ_REG, + SUN6I_DSI_BURST_DRQ_EDGE1(edge1) | + SUN6I_DSI_BURST_DRQ_EDGE0(edge0)); + regmap_write(dsi->regs, SUN6I_DSI_BURST_LINE_REG, + SUN6I_DSI_BURST_LINE_NUM(line_num) | + SUN6I_DSI_BURST_LINE_SYNC_POINT(sync_point)); + + /* enable burst mode */ + regmap_read(dsi->regs, SUN6I_DSI_BASIC_CTL_REG, &val); + val |= SUN6I_DSI_BASIC_CTL_VIDEO_BURST; + regmap_write(dsi->regs, SUN6I_DSI_BASIC_CTL_REG, val); } static void sun6i_dsi_setup_inst_loop(struct sun6i_dsi *dsi, @@ -667,7 +726,12 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder) SUN6I_DSI_BASIC_CTL1_VIDEO_PRECISION | SUN6I_DSI_BASIC_CTL1_VIDEO_MODE); - sun6i_dsi_setup_burst(dsi, mode); + regmap_write(dsi->regs, SUN6I_DSI_TCON_DRQ_REG, + sun6i_dsi_get_drq(dsi, mode)); + + if (device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) + sun6i_dsi_setup_burst(dsi, mode); + sun6i_dsi_setup_inst_loop(dsi, mode); sun6i_dsi_setup_format(dsi, mode); sun6i_dsi_setup_timings(dsi, mode); -- 2.18.0.321.gffc6fa0e3