From: Jernej Skrabec <jernej.skra...@gmail.com>

Account for U/V channel subsampling by reducing the dot clock and
resolution with a divider in the DE3 timing controller if a YUV format
is selected.

Signed-off-by: Jernej Skrabec <jernej.skra...@gmail.com>
Signed-off-by: Ryan Walklin <r...@testtoast.com>
---
 drivers/gpu/drm/sun4i/sun4i_tcon.c | 26 +++++++++++++++++++-------
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c 
b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index a1a2c845ade0c..e39926e9f0b5d 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -598,14 +598,26 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon 
*tcon,
 static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
                                 const struct drm_display_mode *mode)
 {
-       unsigned int bp, hsync, vsync, vtotal;
+       unsigned int bp, hsync, vsync, vtotal, div;
+       struct sun4i_crtc *scrtc = tcon->crtc;
+       struct sunxi_engine *engine = scrtc->engine;
        u8 clk_delay;
        u32 val;
 
        WARN_ON(!tcon->quirks->has_channel_1);
 
+       switch (engine->format) {
+       case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+       case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+               div = 2;
+               break;
+       default:
+               div = 1;
+               break;
+       }
+
        /* Configure the dot clock */
-       clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000);
+       clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000 / div);
 
        /* Adjust clock delay */
        clk_delay = sun4i_tcon_get_clk_delay(mode, 1);
@@ -624,17 +636,17 @@ static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
 
        /* Set the input resolution */
        regmap_write(tcon->regs, SUN4I_TCON1_BASIC0_REG,
-                    SUN4I_TCON1_BASIC0_X(mode->crtc_hdisplay) |
+                    SUN4I_TCON1_BASIC0_X(mode->crtc_hdisplay / div) |
                     SUN4I_TCON1_BASIC0_Y(mode->crtc_vdisplay));
 
        /* Set the upscaling resolution */
        regmap_write(tcon->regs, SUN4I_TCON1_BASIC1_REG,
-                    SUN4I_TCON1_BASIC1_X(mode->crtc_hdisplay) |
+                    SUN4I_TCON1_BASIC1_X(mode->crtc_hdisplay / div) |
                     SUN4I_TCON1_BASIC1_Y(mode->crtc_vdisplay));
 
        /* Set the output resolution */
        regmap_write(tcon->regs, SUN4I_TCON1_BASIC2_REG,
-                    SUN4I_TCON1_BASIC2_X(mode->crtc_hdisplay) |
+                    SUN4I_TCON1_BASIC2_X(mode->crtc_hdisplay / div) |
                     SUN4I_TCON1_BASIC2_Y(mode->crtc_vdisplay));
 
        /* Set horizontal display timings */
@@ -642,8 +654,8 @@ static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
        DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
                         mode->htotal, bp);
        regmap_write(tcon->regs, SUN4I_TCON1_BASIC3_REG,
-                    SUN4I_TCON1_BASIC3_H_TOTAL(mode->crtc_htotal) |
-                    SUN4I_TCON1_BASIC3_H_BACKPORCH(bp));
+                    SUN4I_TCON1_BASIC3_H_TOTAL(mode->crtc_htotal / div) |
+                    SUN4I_TCON1_BASIC3_H_BACKPORCH(bp / div));
 
        bp = mode->crtc_vtotal - mode->crtc_vsync_start;
        DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
-- 
2.45.2

Reply via email to