From 1fdb9659b5739b7fa654b8c188402bf1155f3961 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Mon, 3 Nov 2025 12:03:01 +0000
Subject: [PATCH] drm/vc4: plane: Swap Cb/Cr pointers for YVU formats

hvs6 appears to have dropped support for the component order
field in 3 plane YUV formats.

Support them by swapping the Cb and Cr planes over when
reading the image pointers.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 drivers/gpu/drm/vc4/vc4_plane.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -37,6 +37,7 @@ static const struct hvs_format {
 	u32 pixel_order_hvs5;
 	bool hvs5_only;
 	bool hvs6_only;
+	bool hvs6_swap_chroma_pointers;
 } hvs_formats[] = {
 	{
 		.drm = DRM_FORMAT_XRGB8888,
@@ -109,6 +110,7 @@ static const struct hvs_format {
 		.hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
 		.pixel_order = HVS_PIXEL_ORDER_XYCRCB,
 		.pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCRCB,
+		.hvs6_swap_chroma_pointers = true,
 	},
 	{
 		.drm = DRM_FORMAT_YUV444,
@@ -121,6 +123,7 @@ static const struct hvs_format {
 		.hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
 		.pixel_order = HVS_PIXEL_ORDER_XYCRCB,
 		.pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCRCB,
+		.hvs6_swap_chroma_pointers = true,
 	},
 	{
 		.drm = DRM_FORMAT_YUV420,
@@ -133,6 +136,7 @@ static const struct hvs_format {
 		.hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE,
 		.pixel_order = HVS_PIXEL_ORDER_XYCRCB,
 		.pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCRCB,
+		.hvs6_swap_chroma_pointers = true,
 	},
 	{
 		.drm = DRM_FORMAT_NV12,
@@ -1873,6 +1877,14 @@ static u32 vc6_plane_get_csc_mode(struct
 	return ret;
 }
 
+static int vc6_get_plane_idx(const struct hvs_format *format, int plane)
+{
+	if (!plane || !format->hvs6_swap_chroma_pointers)
+		return plane;
+
+	return (plane == 1) ? 2 : 1;
+}
+
 static int vc6_plane_mode_set(struct drm_plane *plane,
 			      struct drm_plane_state *state)
 {
@@ -2165,8 +2177,10 @@ static int vc6_plane_mode_set(struct drm
 	 * TODO: This only covers Raster Scan Order planes
 	 */
 	for (i = 0; i < num_planes; i++) {
-		struct drm_gem_dma_object *bo = drm_fb_dma_get_gem_obj(fb, i);
-		dma_addr_t paddr = bo->dma_addr + fb->offsets[i] + offsets[i];
+		int idx = vc6_get_plane_idx(format, i);
+		struct drm_gem_dma_object *bo =
+			drm_fb_dma_get_gem_obj(fb, idx);
+		dma_addr_t paddr = bo->dma_addr + fb->offsets[idx] + offsets[idx];
 
 		/* Pointer Word 0 */
 		vc4_state->ptr0_offset[i] = vc4_state->dlist_count;
