[PATCH v6 12/27] drm: sun4i: de3: add YUV support to the TCON

Ryan Walklin
2025-02-16T08:57:12Z

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.skrabec@gmail.com>
Signed-off-by: Ryan Walklin <ryan@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