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@xxxxxx> --- 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@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel