Blob Blame History Raw
From: Mihail Atanassov <mihail.atanassov@arm.com>
Date: Tue, 7 Nov 2017 15:30:46 +0000
Subject: drm: mali-dp: Add YUV->RGB conversion support for video layers
Git-commit: 6e810eb508f4b937bc2a718bd4e5cd74cca55500
Patch-mainline: v4.17-rc1
References: FATE#326289 FATE#326079 FATE#326049 FATE#322398 FATE#326166

Internally Mali DP uses an RGB pipeline so video layers that support
YUV input buffers need to convert the input data to RGB. The YUV
buffers can have various encodings and this patch introduces support
for BT.601, BT.709 and BT.2020 encodings, both limited and full ranges.

This patch adds support for specifying the color encoding of the
input buffers for the planes that are backed by the video layers
and programs the YUV2RGB coefficients into hardware based on the
selected encoding.

Signed-off-by: Mihail Atanassov <mihail.atanassov@arm.com>
[updated to use standard properties]
Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>
Acked-by: Petr Tesarik <ptesarik@suse.com>
---
 drivers/gpu/drm/arm/malidp_hw.c     |   14 +++---
 drivers/gpu/drm/arm/malidp_hw.h     |    3 -
 drivers/gpu/drm/arm/malidp_planes.c |   79 ++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/arm/malidp_regs.h   |   11 -----
 4 files changed, 90 insertions(+), 17 deletions(-)

--- a/drivers/gpu/drm/arm/malidp_hw.c
+++ b/drivers/gpu/drm/arm/malidp_hw.c
@@ -75,16 +75,16 @@ static const struct malidp_format_id mal
 };
 
 static const struct malidp_layer malidp500_layers[] = {
-	{ DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE, MALIDP_DE_LV_STRIDE0 },
-	{ DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE, MALIDP_DE_LG_STRIDE },
-	{ DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE, MALIDP_DE_LG_STRIDE },
+	{ DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP500_LV_YUV2RGB },
+	{ DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 },
+	{ DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 },
 };
 
 static const struct malidp_layer malidp550_layers[] = {
-	{ DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE, MALIDP_DE_LV_STRIDE0 },
-	{ DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE, MALIDP_DE_LG_STRIDE },
-	{ DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE, MALIDP_DE_LV_STRIDE0 },
-	{ DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE, MALIDP550_DE_LS_R1_STRIDE },
+	{ DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB },
+	{ DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 },
+	{ DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB },
+	{ DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE, MALIDP550_DE_LS_R1_STRIDE, 0 },
 };
 
 #define SE_N_SCALING_COEFFS	96
--- a/drivers/gpu/drm/arm/malidp_hw.h
+++ b/drivers/gpu/drm/arm/malidp_hw.h
@@ -58,7 +58,8 @@ struct malidp_layer {
 	u16 id;			/* layer ID */
 	u16 base;		/* address offset for the register bank */
 	u16 ptr;		/* address offset for the pointer register */
-	u16 stride_offset;	/* Offset to the first stride register. */
+	u16 stride_offset;	/* offset to the first stride register. */
+	s16 yuv2rgb_offset;	/* offset to the YUV->RGB matrix entries */
 };
 
 enum malidp_scaling_coeff_set {
--- a/drivers/gpu/drm/arm/malidp_planes.c
+++ b/drivers/gpu/drm/arm/malidp_planes.c
@@ -266,6 +266,60 @@ static void malidp_de_set_plane_pitches(
 				mp->layer->stride_offset + i * 4);
 }
 
+static const s16
+malidp_yuv2rgb_coeffs[][DRM_COLOR_RANGE_MAX][MALIDP_COLORADJ_NUM_COEFFS] = {
+	[DRM_COLOR_YCBCR_BT601][DRM_COLOR_YCBCR_LIMITED_RANGE] = {
+		1192,    0, 1634,
+		1192, -401, -832,
+		1192, 2066,    0,
+		  64,  512,  512
+	},
+	[DRM_COLOR_YCBCR_BT601][DRM_COLOR_YCBCR_FULL_RANGE] = {
+		1024,    0, 1436,
+		1024, -352, -731,
+		1024, 1815,    0,
+		   0,  512,  512
+	},
+	[DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_LIMITED_RANGE] = {
+		1192,    0, 1836,
+		1192, -218, -546,
+		1192, 2163,    0,
+		  64,  512,  512
+	},
+	[DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_FULL_RANGE] = {
+		1024,    0, 1613,
+		1024, -192, -479,
+		1024, 1900,    0,
+		   0,  512,  512
+	},
+	[DRM_COLOR_YCBCR_BT2020][DRM_COLOR_YCBCR_LIMITED_RANGE] = {
+		1024,    0, 1476,
+		1024, -165, -572,
+		1024, 1884,    0,
+		   0,  512,  512
+	},
+	[DRM_COLOR_YCBCR_BT2020][DRM_COLOR_YCBCR_FULL_RANGE] = {
+		1024,    0, 1510,
+		1024, -168, -585,
+		1024, 1927,    0,
+		   0,  512,  512
+	}
+};
+
+static void malidp_de_set_color_encoding(struct malidp_plane *plane,
+					 enum drm_color_encoding enc,
+					 enum drm_color_range range)
+{
+	unsigned int i;
+
+	for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; i++) {
+		/* coefficients are signed, two's complement values */
+		malidp_hw_write(plane->hwdev, malidp_yuv2rgb_coeffs[enc][range][i],
+				plane->layer->base + plane->layer->yuv2rgb_offset +
+				i * 4);
+	}
+}
+
 static void malidp_de_plane_update(struct drm_plane *plane,
 				   struct drm_plane_state *old_state)
 {
@@ -297,6 +351,11 @@ static void malidp_de_plane_update(struc
 	malidp_de_set_plane_pitches(mp, ms->n_planes,
 				    plane->state->fb->pitches);
 
+	if ((plane->state->color_encoding != old_state->color_encoding) ||
+	    (plane->state->color_range != old_state->color_range))
+		malidp_de_set_color_encoding(mp, plane->state->color_encoding,
+					     plane->state->color_range);
+
 	malidp_hw_write(mp->hwdev, LAYER_H_VAL(src_w) | LAYER_V_VAL(src_h),
 			mp->layer->base + MALIDP_LAYER_SIZE);
 
@@ -438,6 +497,26 @@ int malidp_de_planes_init(struct drm_dev
 		drm_plane_create_rotation_property(&plane->base, DRM_MODE_ROTATE_0, flags);
 		malidp_hw_write(malidp->dev, MALIDP_ALPHA_LUT,
 				plane->layer->base + MALIDP_LAYER_COMPOSE);
+
+		/* Attach the YUV->RGB property only to video layers */
+		if (id & (DE_VIDEO1 | DE_VIDEO2)) {
+			/* default encoding for YUV->RGB is BT601 NARROW */
+			enum drm_color_encoding enc = DRM_COLOR_YCBCR_BT601;
+			enum drm_color_range range = DRM_COLOR_YCBCR_LIMITED_RANGE;
+
+			ret = drm_plane_create_color_properties(&plane->base,
+					BIT(DRM_COLOR_YCBCR_BT601) | \
+					BIT(DRM_COLOR_YCBCR_BT709) | \
+					BIT(DRM_COLOR_YCBCR_BT2020),
+					BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | \
+					BIT(DRM_COLOR_YCBCR_FULL_RANGE),
+					enc, range);
+			if (!ret)
+				/* program the HW registers */
+				malidp_de_set_color_encoding(plane, enc, range);
+			else
+				DRM_WARN("Failed to create video layer %d color properties\n", id);
+		}
 	}
 
 	kfree(formats);
--- a/drivers/gpu/drm/arm/malidp_regs.h
+++ b/drivers/gpu/drm/arm/malidp_regs.h
@@ -170,10 +170,7 @@
 #define MALIDP500_CONFIG_3D		0x00038
 #define MALIDP500_BGND_COLOR		0x0003c
 #define MALIDP500_OUTPUT_DEPTH		0x00044
-#define MALIDP500_YUV_RGB_COEF		0x00048
-#define MALIDP500_COLOR_ADJ_COEF	0x00078
-#define MALIDP500_COEF_TABLE_ADDR	0x000a8
-#define MALIDP500_COEF_TABLE_DATA	0x000ac
+#define MALIDP500_COEFFS_BASE		0x00078
 
 /*
  * The YUV2RGB coefficients on the DP500 are not in the video layer's register
@@ -181,11 +178,6 @@
  * the negative offset.
  */
 #define MALIDP500_LV_YUV2RGB		((s16)(-0xB8))
-/*
- * To match DP550/650, the start of the coeffs registers is
- * at COLORADJ_COEFF0 instead of at YUV_RGB_COEF1.
- */
-#define MALIDP500_COEFFS_BASE		0x00078
 #define MALIDP500_DE_LV_BASE		0x00100
 #define MALIDP500_DE_LV_PTR_BASE	0x00124
 #define MALIDP500_DE_LG1_BASE		0x00200
@@ -213,6 +205,7 @@
 #define MALIDP550_DE_BGND_COLOR		0x00044
 #define MALIDP550_DE_OUTPUT_DEPTH	0x0004c
 #define MALIDP550_COEFFS_BASE		0x00050
+#define MALIDP550_LV_YUV2RGB		0x00084
 #define MALIDP550_DE_LV1_BASE		0x00100
 #define MALIDP550_DE_LV1_PTR_BASE	0x00124
 #define MALIDP550_DE_LV2_BASE		0x00200