@@ -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;
}
@@ -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 {
@@ -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:
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(-)