diff mbox

[RFC,6/6] drm/omap: Enable ycbcr_to_rgb_properties for omapdrm planes REVISIT

Message ID b25fc5b2d0e27d40cacd53d420904b74f49d7515.1492768073.git.jsarha@ti.com (mailing list archive)
State New, archived
Headers show

Commit Message

Jyri Sarha April 21, 2017, 9:51 a.m. UTC
Adds support for YCBCR_TO_RGB_MODE and YCBCR_TO_RGB_CSC properties to
omap_plane.c and dispc.c. The supported CSC presets are:

- YCbCt BT.601 limited range to RGB BT.601 full range
- YCbCt BT.601 full range to RGB BT.601 full range
- YCbCt BT.709 limited range to RGB BT.709 full range

Custom CSC with YCbCr limited and full range preoffsets are
also supported.

Signed-off-by: Jyri Sarha <jsarha@ti.com>
---
 drivers/gpu/drm/omapdrm/dss/dispc.c   | 131 +++++++++++++++++++++++-----------
 drivers/gpu/drm/omapdrm/dss/omapdss.h |  14 ++++
 drivers/gpu/drm/omapdrm/omap_plane.c  |  41 +++++++++++
 3 files changed, 144 insertions(+), 42 deletions(-)
diff mbox

Patch

diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c
index f2a2d08..48dfb9c 100644
--- a/drivers/gpu/drm/omapdrm/dss/dispc.c
+++ b/drivers/gpu/drm/omapdrm/dss/dispc.c
@@ -752,16 +752,6 @@  static void dispc_ovl_set_scale_coef(enum omap_plane_id plane, int fir_hinc,
 	}
 }
 
-struct csc_coef_yuv2rgb {
-	int ry, rcb, rcr, gy, gcb, gcr, by, bcb, bcr;
-	bool full_range;
-};
-
-struct csc_coef_rgb2yuv {
-	int yr, yg, yb, cbr, cbg, cbb, crr, crg, crb;
-	bool full_range;
-};
-
 static void dispc_ovl_write_color_conv_coef(enum omap_plane_id plane,
 		const struct csc_coef_yuv2rgb *ct)
 {
@@ -795,6 +785,54 @@  static void dispc_wb_write_color_conv_coef(const struct csc_coef_rgb2yuv *ct)
 #undef CVAL
 }
 
+/* YUV -> RGB, ITU-R BT.601, full range */
+const static struct csc_coef_yuv2rgb coefs_yuv2rgb_bt601_full = {
+	256,   0,  358,		/* ry, rcb, rcr |1.000  0.000  1.402|*/
+	256, -88, -182,		/* gy, gcb, gcr |1.000 -0.344 -0.714|*/
+	256, 452,    0,		/* by, bcb, bcr |1.000  1.772  0.000|*/
+	true,			/* full range */
+};
+
+/* YUV -> RGB, ITU-R BT.601, limited range */
+const static struct csc_coef_yuv2rgb coefs_yuv2rgb_bt601_lim = {
+	298,    0,  409,	/* ry, rcb, rcr |1.164  0.000  1.596|*/
+	298, -100, -208,	/* gy, gcb, gcr |1.164 -0.392 -0.813|*/
+	298,  516,    0,	/* by, bcb, bcr |1.164  2.017  0.000|*/
+	false,			/* limited range */
+};
+
+/* YUV -> RGB, ITU-R BT.709, limited range */
+const static struct csc_coef_yuv2rgb coefs_yuv2rgb_bt709_lim = {
+	298,    0,  459,	/* ry, rcb, rcr |1.164  0.000  1.793|*/
+	298,  -55, -136,	/* gy, gcb, gcr |1.164 -0.213 -0.533|*/
+	298,  541,    0,	/* by, bcb, bcr |1.164  2.112  0.000|*/
+	false,			/* limited range */
+};
+
+/* RGB -> YUV, ITU-R BT.601, limited range */
+const struct csc_coef_rgb2yuv coefs_rgb2yuv_bt601_lim = {
+	 66, 129,  25,		/* yr,   yg,  yb | 0.257  0.504  0.098|*/
+	-38, -74, 112,		/* cbr, cbg, cbb |-0.148 -0.291  0.439|*/
+	112, -94, -18,		/* crr, crg, crb | 0.439 -0.368 -0.071|*/
+	false,			/* limited range */
+};
+
+/* RGB -> YUV, ITU-R BT.601, full range */
+const static struct csc_coef_rgb2yuv coefs_rgb2yuv_bt601_full = {
+	 77,  150,  29,		/* yr,   yg,  yb | 0.299  0.587  0.114|*/
+	-43,  -85, 128,		/* cbr, cbg, cbb |-0.173 -0.339  0.511|*/
+	128, -107, -21,		/* crr, crg, crb | 0.511 -0.428 -0.083|*/
+	true,			/* full range */
+};
+
+/* RGB -> YUV, ITU-R BT.709, limited range */
+const struct csc_coef_rgb2yuv coefs_rgb2yuv_bt701_lim = {
+	 47,  157,   16,	/* yr,   yg,  yb | 0.1826  0.6142  0.0620|*/
+	-26,  -87,  112,	/* cbr, cbg, cbb |-0.1006 -0.3386  0.4392|*/
+	112, -102,  -10,	/* crr, crg, crb | 0.4392 -0.3989 -0.0403|*/
+	false,			/* limited range */
+};
+
 static void dispc_setup_color_conv_coef(void)
 {
 	int i;
@@ -802,38 +840,6 @@  static void dispc_setup_color_conv_coef(void)
 	/* always use full range for now */
 	bool use_full_range = true;
 
-	/* YUV -> RGB, ITU-R BT.601, limited range */
-	const struct csc_coef_yuv2rgb coefs_yuv2rgb_bt601_lim = {
-		298,    0,  409,	/* ry, rcb, rcr */
-		298, -100, -208,	/* gy, gcb, gcr */
-		298,  516,    0,	/* by, bcb, bcr */
-		false,			/* limited range */
-	};
-
-	/* YUV -> RGB, ITU-R BT.601, full range */
-	const struct csc_coef_yuv2rgb coefs_yuv2rgb_bt601_full = {
-		256,   0,  358,		/* ry, rcb, rcr */
-		256, -88, -182,		/* gy, gcb, gcr */
-		256, 452,    0,		/* by, bcb, bcr */
-		true,			/* full range */
-	};
-
-	/* RGB -> YUV, ITU-R BT.601, limited range */
-	const struct csc_coef_rgb2yuv coefs_rgb2yuv_bt601_lim = {
-		 66, 129,  25,		/* yr,   yg,  yb */
-		-38, -74, 112,		/* cbr, cbg, cbb */
-		112, -94, -18,		/* crr, crg, crb */
-		false,			/* limited range */
-	};
-
-	/* RGB -> YUV, ITU-R BT.601, full range */
-	const struct csc_coef_rgb2yuv coefs_rgb2yuv_bt601_full = {
-		 77,  150,  29,		/* yr,   yg,  yb */
-		-43,  -85, 128,		/* cbr, cbg, cbb */
-		128, -107, -21,		/* crr, crg, crb */
-		true,			/* full range */
-	};
-
 	const struct csc_coef_yuv2rgb *yuv2rgb;
 	const struct csc_coef_rgb2yuv *rgb2yuv;
 
@@ -2890,6 +2896,42 @@  static int dispc_ovl_setup_common(enum omap_plane_id plane,
 	return 0;
 }
 
+
+static int dispc_ovl_set_csc(enum omap_plane_id plane,
+			     const struct omap_overlay_info *oi)
+{
+	struct csc_coef_yuv2rgb csc;
+	const struct csc_coef_yuv2rgb *cscp = &csc;
+
+	switch (oi->ycbcr_to_rgb_mode) {
+	case DRM_PLANE_YCBCR_TO_RGB_CSC_LIM_PREOFFSET:
+		csc = oi->ycbcr_to_rgb_csc;
+		csc.full_range = false;
+		break;
+	case DRM_PLANE_YCBCR_TO_RGB_CSC_FULL_PREOFFSET:
+		csc = oi->ycbcr_to_rgb_csc;
+		csc.full_range = true;
+		break;
+	case DRM_PLANE_YCBCR_BT601_LIM_TO_RGB_BT601_FULL:
+		cscp = &coefs_yuv2rgb_bt601_lim;
+		break;
+	case DRM_PLANE_YCBCR_BT601_FULL_TO_RGB_BT601_FULL:
+		cscp = &coefs_yuv2rgb_bt601_full;
+		break;
+	case DRM_PLANE_YCBCR_BT709_LIM_TO_RGB_BT709_FULL:
+		cscp = &coefs_yuv2rgb_bt709_lim;
+		break;
+	default:
+		DSSERR("Unsupported CSC mode %d for plane %d\n",
+		       oi->ycbcr_to_rgb_mode, plane);
+		return -EINVAL;
+	}
+
+	dispc_ovl_write_color_conv_coef(plane, cscp);
+
+	return 0;
+}
+
 static int dispc_ovl_setup(enum omap_plane_id plane,
 		const struct omap_overlay_info *oi,
 		const struct videomode *vm, bool mem_to_mem)
@@ -2912,6 +2954,11 @@  static int dispc_ovl_setup(enum omap_plane_id plane,
 		oi->out_width, oi->out_height, oi->color_mode, oi->rotation,
 		oi->mirror, oi->zorder, oi->pre_mult_alpha, oi->global_alpha,
 		oi->rotation_type, replication, vm, mem_to_mem);
+	if (r)
+		return r;
+
+	if (dss_feat_color_mode_supported(plane, OMAP_DSS_COLOR_UYVY))
+		r = dispc_ovl_set_csc(plane, oi);
 
 	return r;
 }
diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h
index 63c2684..f4aab99 100644
--- a/drivers/gpu/drm/omapdrm/dss/omapdss.h
+++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h
@@ -25,6 +25,7 @@ 
 #include <video/videomode.h>
 #include <linux/platform_data/omapdss.h>
 #include <uapi/drm/drm_mode.h>
+#include <drm/drm_color_mgmt.h>
 
 #define DISPC_IRQ_FRAMEDONE		(1 << 0)
 #define DISPC_IRQ_VSYNC			(1 << 1)
@@ -312,6 +313,16 @@  struct omap_dss_cpr_coefs {
 	s16 br, bg, bb;
 };
 
+struct csc_coef_yuv2rgb {
+	int ry, rcb, rcr, gy, gcb, gcr, by, bcb, bcr;
+	bool full_range;
+};
+
+struct csc_coef_rgb2yuv {
+	int yr, yg, yb, cbr, cbg, cbb, crr, crg, crb;
+	bool full_range;
+};
+
 struct omap_overlay_info {
 	dma_addr_t paddr;
 	dma_addr_t p_uv_addr;  /* for NV12 format */
@@ -330,6 +341,9 @@  struct omap_overlay_info {
 	u8 global_alpha;
 	u8 pre_mult_alpha;
 	u8 zorder;
+
+	enum drm_plane_ycbcr_to_rgb_mode ycbcr_to_rgb_mode;
+	struct csc_coef_yuv2rgb ycbcr_to_rgb_csc;
 };
 
 struct omap_overlay {
diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c
index 9168154..ec38f9c 100644
--- a/drivers/gpu/drm/omapdrm/omap_plane.c
+++ b/drivers/gpu/drm/omapdrm/omap_plane.c
@@ -67,6 +67,27 @@  static void omap_plane_cleanup_fb(struct drm_plane *plane,
 		omap_framebuffer_unpin(old_state->fb);
 }
 
+static int omap_plane_s32_32_to_s2_8(s64 coef)
+{
+	return clamp_val((int)(coef >> 24), -0x1FF - 1, 0x1FF);
+}
+
+static void omap_plane_csc_coefs_from_blob(const void *blob,
+					   struct csc_coef_yuv2rgb *csc)
+{
+	const struct drm_ycbcr_to_rgb_csc *cscbp = blob;
+
+	csc->ry = omap_plane_s32_32_to_s2_8(cscbp->ry);
+	csc->rcb = omap_plane_s32_32_to_s2_8(cscbp->rcb);
+	csc->rcr = omap_plane_s32_32_to_s2_8(cscbp->rcr);
+	csc->gy = omap_plane_s32_32_to_s2_8(cscbp->gy);
+	csc->gcb = omap_plane_s32_32_to_s2_8(cscbp->gcb);
+	csc->gcr = omap_plane_s32_32_to_s2_8(cscbp->gcr);
+	csc->by = omap_plane_s32_32_to_s2_8(cscbp->by);
+	csc->bcb = omap_plane_s32_32_to_s2_8(cscbp->bcb);
+	csc->bcr = omap_plane_s32_32_to_s2_8(cscbp->bcr);
+}
+
 static void omap_plane_atomic_update(struct drm_plane *plane,
 				     struct drm_plane_state *old_state)
 {
@@ -86,6 +107,10 @@  static void omap_plane_atomic_update(struct drm_plane *plane,
 	info.global_alpha = 0xff;
 	info.mirror = 0;
 	info.zorder = omap_state->zorder;
+	info.ycbcr_to_rgb_mode = state->ycbcr_to_rgb_mode;
+	if (state->ycbcr_to_rgb_csc)
+		omap_plane_csc_coefs_from_blob(state->ycbcr_to_rgb_csc->data,
+					       &info.ycbcr_to_rgb_csc);
 
 	memset(&win, 0, sizeof(win));
 	win.rotation = state->rotation;
@@ -324,6 +349,15 @@  static int omap_plane_atomic_get_property(struct drm_plane *plane,
 	.atomic_get_property = omap_plane_atomic_get_property,
 };
 
+/* The enum names are filled by drm_plane_create_ycbcr_to_rgb_properties() */
+static struct drm_prop_enum_list omap_ycbcr_to_rgb_enum_list[] = {
+	{ DRM_PLANE_YCBCR_BT601_LIM_TO_RGB_BT601_FULL, NULL },
+	{ DRM_PLANE_YCBCR_BT601_FULL_TO_RGB_BT601_FULL, NULL },
+	{ DRM_PLANE_YCBCR_BT709_LIM_TO_RGB_BT709_FULL, NULL },
+	{ DRM_PLANE_YCBCR_TO_RGB_CSC_LIM_PREOFFSET, NULL },
+	{ DRM_PLANE_YCBCR_TO_RGB_CSC_FULL_PREOFFSET, NULL },
+};
+
 static const char *plane_id_to_name[] = {
 	[OMAP_DSS_GFX] = "gfx",
 	[OMAP_DSS_VIDEO1] = "vid1",
@@ -378,6 +412,13 @@  struct drm_plane *omap_plane_init(struct drm_device *dev,
 
 	omap_plane_install_properties(plane, &plane->base);
 
+	if ((priv->dispc_ops->ovl_get_color_modes(omap_plane->id) &
+	     OMAP_DSS_COLOR_UYVY) != 0)
+		drm_plane_create_ycbcr_to_rgb_properties(plane,
+				omap_ycbcr_to_rgb_enum_list,
+				ARRAY_SIZE(omap_ycbcr_to_rgb_enum_list),
+				DRM_PLANE_YCBCR_BT601_FULL_TO_RGB_BT601_FULL);
+
 	return plane;
 
 error: