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>

--
Changelog v5..v6:
- Update to obtain color format from mixer if required.
---
 drivers/gpu/drm/sun4i/sun4i_tcon.c | 28 +++++++++++++++++++++-------
 1 file changed, 21 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c 
b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index 960e83c8291da..4cd3a07daf6e4 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -37,6 +37,7 @@
 #include "sun4i_tcon.h"
 #include "sun6i_mipi_dsi.h"
 #include "sun4i_tcon_dclk.h"
+#include "sun8i_mixer.h"
 #include "sun8i_tcon_top.h"
 #include "sunxi_engine.h"
 
@@ -598,14 +599,27 @@ 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 sun8i_mixer *mixer = engine_to_sun8i_mixer(scrtc->engine);
+
        u8 clk_delay;
        u32 val;
 
        WARN_ON(!tcon->quirks->has_channel_1);
 
+       switch (mixer->color_model.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 +638,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 +656,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.48.1

Reply via email to