diff mbox series

[v3,RESEND,24/24] drm/exynos/gscaler: fix handling YVU420 pixel format

Message ID 20190325071349.22600-25-a.hajda@samsung.com (mailing list archive)
State New, archived
Headers show
Series [v3,RESEND,01/24] arm64: dts: exynos: configure GSCALER related clocks | expand

Commit Message

Andrzej Hajda March 25, 2019, 7:13 a.m. UTC
YVU420 requires swapping addresses of U and V planes.

Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_drm_gsc.c | 52 ++++++++++++++++++-------
 1 file changed, 37 insertions(+), 15 deletions(-)
diff mbox series

Patch

diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
index c7a97d053ab1..f75739e8bc55 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
@@ -535,10 +535,8 @@  static void gsc_src_set_fmt(struct gsc_context *ctx, u32 fmt, bool tiled)
 		cfg |= GSC_IN_YUV422_3P;
 		break;
 	case DRM_FORMAT_YUV420:
-		cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_3P);
-		break;
 	case DRM_FORMAT_YVU420:
-		cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV420_3P);
+		cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_3P);
 		break;
 	case DRM_FORMAT_NV12:
 		cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_2P);
@@ -658,13 +656,32 @@  static void gsc_src_set_buf_seq(struct gsc_context *ctx, u32 buf_id,
 	gsc_write(cfg, GSC_IN_BASE_ADDR_CR_MASK);
 }
 
+/* returns HW plane index based on pixel format */
+static int gsc_hw_plane_index(int index, u32 format)
+{
+	switch (format) {
+	case DRM_FORMAT_YVU420:
+		switch (index) {
+		case 0: return 0;
+		case 1: return 2;
+		case 2: return 1;
+		}
+	default:
+		return index;
+	}
+}
+
 static void gsc_src_set_addr(struct gsc_context *ctx, u32 buf_id,
 			    struct exynos_drm_ipp_buffer *buf)
 {
+	int idx;
+
 	/* address register set */
 	gsc_write(buf->dma_addr[0], GSC_IN_BASE_ADDR_Y(buf_id));
-	gsc_write(buf->dma_addr[1], GSC_IN_BASE_ADDR_CB(buf_id));
-	gsc_write(buf->dma_addr[2], GSC_IN_BASE_ADDR_CR(buf_id));
+	idx = gsc_hw_plane_index(1, buf->format->format);
+	gsc_write(buf->dma_addr[idx], GSC_IN_BASE_ADDR_CB(buf_id));
+	idx = gsc_hw_plane_index(2, buf->format->format);
+	gsc_write(buf->dma_addr[idx], GSC_IN_BASE_ADDR_CR(buf_id));
 
 	gsc_src_set_buf_seq(ctx, buf_id, true);
 }
@@ -722,10 +739,8 @@  static void gsc_dst_set_fmt(struct gsc_context *ctx, u32 fmt, bool tiled)
 		cfg |= GSC_OUT_YUV422_3P;
 		break;
 	case DRM_FORMAT_YUV420:
-		cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_3P);
-		break;
 	case DRM_FORMAT_YVU420:
-		cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV420_3P);
+		cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_3P);
 		break;
 	case DRM_FORMAT_NV12:
 		cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_2P);
@@ -985,10 +1000,13 @@  static void gsc_dst_set_buf_seq(struct gsc_context *ctx, u32 buf_id,
 static void gsc_dst_set_addr(struct gsc_context *ctx,
 			     u32 buf_id, struct exynos_drm_ipp_buffer *buf)
 {
-	/* address register set */
+	int i;
+
 	gsc_write(buf->dma_addr[0], GSC_OUT_BASE_ADDR_Y(buf_id));
-	gsc_write(buf->dma_addr[1], GSC_OUT_BASE_ADDR_CB(buf_id));
-	gsc_write(buf->dma_addr[2], GSC_OUT_BASE_ADDR_CR(buf_id));
+	i = gsc_hw_plane_index(1, buf->format->format);
+	gsc_write(buf->dma_addr[i], GSC_OUT_BASE_ADDR_CB(buf_id));
+	i = gsc_hw_plane_index(2, buf->format->format);
+	gsc_write(buf->dma_addr[i], GSC_OUT_BASE_ADDR_CR(buf_id));
 
 	gsc_dst_set_buf_seq(ctx, buf_id, true);
 }
@@ -1238,10 +1256,14 @@  static void gsc_update_plane(struct exynos_drm_plane *plane)
 	gsc_write(BIT(16) * cropped_w / scaled_w, GSC_MAIN_H_RATIO);
 	gsc_write(BIT(16) * cropped_h / scaled_h, GSC_MAIN_V_RATIO);
 	gsc_write(exynos_drm_fb_dma_addr(fb, 0), GSC_IN_BASE_ADDR_Y(0));
-	if (fb->format->num_planes > 1)
-	        gsc_write(exynos_drm_fb_dma_addr(fb, 1), GSC_IN_BASE_ADDR_CB(0));
-	if (fb->format->num_planes > 2)
-	        gsc_write(exynos_drm_fb_dma_addr(fb, 2), GSC_IN_BASE_ADDR_CR(0));
+	if (fb->format->num_planes > 1) {
+		i = gsc_hw_plane_index(1, fb->format->format);
+		gsc_write(exynos_drm_fb_dma_addr(fb, i), GSC_IN_BASE_ADDR_CB(0));
+	}
+	if (fb->format->num_planes > 2) {
+		i = gsc_hw_plane_index(2, fb->format->format);
+		gsc_write(exynos_drm_fb_dma_addr(fb, i), GSC_IN_BASE_ADDR_CR(0));
+	}
 	gsc_src_set_fmt(ctx, fb->format->format, fb->modifier);
 	gsc_write(scaled_w * scaled_h, GSC_SMART_IF_PIXEL_NUM);
 	gsc_write(GSC_ENABLE_SFR_UPDATE | GSC_ENABLE_ON, GSC_ENABLE);