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 <jsa...@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 --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:
-- 
1.9.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to