In the case of DSI output, the value of SUN4I_TCON0_DCLK_DIV (4) does not represent the actual dotclock divider, PLL_MIPI instead runs at (bpp / lanes )-multiple [1] of the dotclock. [2] Setting 4 as dotclock divder thus leads to reduced frame rate, specifically by 1/3 on 4-lane panels, and by 2/3 on 2-lane panels respectively. As sun4i_dotclock driver stores its calculated divider directly in the register, conditional handling of the DSI output scenario is needed. Instead of reading the divider from SUN4I_TCON0_DCLK_REG, retrieve the value from tcon->dclk_min_div. [1] bits per pixel / number of DSI lanes [2] https://github.com/BPI-SINOVOIP/BPI-M64-bsp-4.4/blob/66bef0f2f30b367eb93b1cbad21ce85e0361f7ae/linux-sunxi/drivers/video/fbdev/sunxi/disp2/disp/de/lowlevel_sun50iw1/disp_al.c#L322 Signed-off-by: Roman Beranek <romanberanek@xxxxxxxxxx> --- drivers/gpu/drm/sun4i/sun4i_dotclock.c | 6 +++++- drivers/gpu/drm/sun4i/sun4i_tcon.c | 5 +++-- drivers/gpu/drm/sun4i/sun4i_tcon.h | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun4i_dotclock.c b/drivers/gpu/drm/sun4i/sun4i_dotclock.c index 417ade3d2565..26fa99aff590 100644 --- a/drivers/gpu/drm/sun4i/sun4i_dotclock.c +++ b/drivers/gpu/drm/sun4i/sun4i_dotclock.c @@ -11,6 +11,7 @@ #include "sun4i_tcon.h" #include "sun4i_dotclock.h" +#include "sun6i_mipi_dsi.h" struct sun4i_dclk { struct clk_hw hw; @@ -56,6 +57,9 @@ static unsigned long sun4i_dclk_recalc_rate(struct clk_hw *hw, struct sun4i_dclk *dclk = hw_to_dclk(hw); u32 val; + if (dclk->tcon->is_dsi) + return parent_rate / dclk->tcon->dclk_min_div; + regmap_read(dclk->regmap, SUN4I_TCON0_DCLK_REG, &val); val >>= SUN4I_TCON0_DCLK_DIV_SHIFT; @@ -116,7 +120,7 @@ static int sun4i_dclk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct sun4i_dclk *dclk = hw_to_dclk(hw); - u8 div = parent_rate / rate; + u8 div = dclk->tcon->is_dsi ? SUN6I_DSI_TCON_DIV : parent_rate / rate; return regmap_update_bits(dclk->regmap, SUN4I_TCON0_DCLK_REG, GENMASK(6, 0), div); diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 523a6d787921..7f5d3c135058 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -367,8 +367,9 @@ static void sun4i_tcon0_mode_set_cpu(struct sun4i_tcon *tcon, u32 block_space, start_delay; u32 tcon_div; - tcon->dclk_min_div = SUN6I_DSI_TCON_DIV; - tcon->dclk_max_div = SUN6I_DSI_TCON_DIV; + tcon->is_dsi = true; + tcon->dclk_min_div = bpp / lanes; + tcon->dclk_max_div = bpp / lanes; sun4i_tcon0_mode_set_common(tcon, mode); diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h index fa23aa23fe4a..d8150ba2f319 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.h +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h @@ -271,6 +271,7 @@ struct sun4i_tcon { struct clk *dclk; u8 dclk_max_div; u8 dclk_min_div; + bool is_dsi; /* Reset control */ struct reset_control *lcd_rst; -- 2.32.0 (Apple Git-132)