diff --git a/drivers/video/drm/rockchip-dw-mipi-dsi.c b/drivers/video/drm/rockchip-dw-mipi-dsi.c index 7c0073147f..406257ee3a 100644 --- a/drivers/video/drm/rockchip-dw-mipi-dsi.c +++ b/drivers/video/drm/rockchip-dw-mipi-dsi.c @@ -961,6 +961,7 @@ static int rockchip_dw_mipi_dsi_init(struct display_state *state) dsi->node = mipi_node; conn_state->private = dsi; conn_state->output_mode = ROCKCHIP_OUT_MODE_P888; + conn_state->color_space = V4L2_COLORSPACE_DEFAULT; panel = dev_read_subnode(conn_state->dev, "panel"); if (!ofnode_valid(panel)) { diff --git a/drivers/video/drm/rockchip_analogix_dp.c b/drivers/video/drm/rockchip_analogix_dp.c index da7b1a0495..b86863ec3f 100644 --- a/drivers/video/drm/rockchip_analogix_dp.c +++ b/drivers/video/drm/rockchip_analogix_dp.c @@ -883,6 +883,7 @@ static int rockchip_analogix_dp_init(struct display_state *state) conn_state->private = dp; conn_state->type = DRM_MODE_CONNECTOR_eDP; conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA; + conn_state->color_space = V4L2_COLORSPACE_DEFAULT; #if 0 if (pdata->chip_type == RK3399_EDP) { diff --git a/drivers/video/drm/rockchip_display.h b/drivers/video/drm/rockchip_display.h index 0ddab1c355..6219c35aac 100644 --- a/drivers/video/drm/rockchip_display.h +++ b/drivers/video/drm/rockchip_display.h @@ -35,6 +35,9 @@ enum display_mode { #define ROCKCHIP_OUT_MODE_P888 0 #define ROCKCHIP_OUT_MODE_P666 1 #define ROCKCHIP_OUT_MODE_P565 2 +#define ROCKCHIP_OUT_MODE_S888 8 +#define ROCKCHIP_OUT_MODE_S888_DUMMY 12 +#define ROCKCHIP_OUT_MODE_YUV420 14 /* for use special outface */ #define ROCKCHIP_OUT_MODE_AAAA 15 @@ -86,6 +89,7 @@ struct connector_state { int output_mode; int type; int output_type; + int color_space; struct { u32 *lut; diff --git a/drivers/video/drm/rockchip_lvds.c b/drivers/video/drm/rockchip_lvds.c index 86617e8524..21c5c05a16 100644 --- a/drivers/video/drm/rockchip_lvds.c +++ b/drivers/video/drm/rockchip_lvds.c @@ -642,6 +642,7 @@ static int rockchip_lvds_init(struct display_state *state) conn_state->output_mode = ROCKCHIP_OUT_MODE_P666; else conn_state->output_mode = ROCKCHIP_OUT_MODE_P888; + conn_state->color_space = V4L2_COLORSPACE_DEFAULT; return 0; } diff --git a/drivers/video/drm/rockchip_vop.c b/drivers/video/drm/rockchip_vop.c index 8ad5c0c005..cfdf184640 100644 --- a/drivers/video/drm/rockchip_vop.c +++ b/drivers/video/drm/rockchip_vop.c @@ -30,6 +30,56 @@ static inline int us_to_vertical_line(struct drm_display_mode *mode, int us) return us * mode->clock / mode->htotal / 1000; } +static int to_vop_csc_mode(int csc_mode) +{ + switch (csc_mode) { + case V4L2_COLORSPACE_SMPTE170M: + return CSC_BT601L; + case V4L2_COLORSPACE_REC709: + case V4L2_COLORSPACE_DEFAULT: + return CSC_BT709L; + case V4L2_COLORSPACE_JPEG: + return CSC_BT601F; + case V4L2_COLORSPACE_BT2020: + return CSC_BT2020; + default: + return CSC_BT709L; + } +} + +static bool is_yuv_output(uint32_t bus_format) +{ + switch (bus_format) { + case MEDIA_BUS_FMT_YUV8_1X24: + case MEDIA_BUS_FMT_YUV10_1X30: + case MEDIA_BUS_FMT_UYYVYY8_0_5X24: + case MEDIA_BUS_FMT_UYYVYY10_0_5X30: + return true; + default: + return false; + } +} + +static bool is_uv_swap(uint32_t bus_format, uint32_t output_mode) +{ + /* + * FIXME: + * + * There is no media type for YUV444 output, + * so when out_mode is AAAA or P888, assume output is YUV444 on + * yuv format. + * + * From H/W testing, YUV444 mode need a rb swap. + */ + if ((bus_format == MEDIA_BUS_FMT_YUV8_1X24 || + bus_format == MEDIA_BUS_FMT_YUV10_1X30) && + (output_mode == ROCKCHIP_OUT_MODE_AAAA || + output_mode == ROCKCHIP_OUT_MODE_P888)) + return true; + else + return false; +} + static int rockchip_vop_init_gamma(struct vop *vop, struct display_state *state) { struct crtc_state *crtc_state = &state->crtc_state; @@ -103,6 +153,8 @@ static int rockchip_vop_init(struct display_state *state) struct clk dclk, aclk; u32 val; int ret; + bool yuv_overlay = false, post_r2y_en = false, post_y2r_en = false; + u16 post_csc_mode; vop = malloc(sizeof(*vop)); if (!vop) @@ -188,6 +240,14 @@ static int rockchip_vop_init(struct display_state *state) case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: val = DITHER_DOWN_EN(1) | DITHER_DOWN_MODE(RGB888_TO_RGB666); break; + case MEDIA_BUS_FMT_YUV8_1X24: + case MEDIA_BUS_FMT_UYYVYY8_0_5X24: + val = DITHER_DOWN_EN(0) | PRE_DITHER_DOWN_EN(1); + break; + case MEDIA_BUS_FMT_YUV10_1X30: + case MEDIA_BUS_FMT_UYYVYY10_0_5X30: + val = DITHER_DOWN_EN(0) | PRE_DITHER_DOWN_EN(0); + break; case MEDIA_BUS_FMT_RGB888_1X24: default: val = DITHER_DOWN_EN(0) | PRE_DITHER_DOWN_EN(0); @@ -200,7 +260,53 @@ static int rockchip_vop_init(struct display_state *state) val |= DITHER_DOWN_MODE_SEL(DITHER_DOWN_ALLEGRO); VOP_CTRL_SET(vop, dither_down, val); + VOP_CTRL_SET(vop, dclk_ddr, + conn_state->output_mode == ROCKCHIP_OUT_MODE_YUV420 ? 1 : 0); + VOP_CTRL_SET(vop, hdmi_dclk_out_en, + conn_state->output_mode == ROCKCHIP_OUT_MODE_YUV420 ? 1 : 0); + + if (is_uv_swap(conn_state->bus_format, conn_state->output_mode)) + VOP_CTRL_SET(vop, dsp_data_swap, DSP_RB_SWAP); + else + VOP_CTRL_SET(vop, dsp_data_swap, 0); + VOP_CTRL_SET(vop, out_mode, conn_state->output_mode); + + if (VOP_CTRL_SUPPORT(vop, overlay_mode)) { + yuv_overlay = is_yuv_output(conn_state->bus_format); + VOP_CTRL_SET(vop, overlay_mode, yuv_overlay); + } + /* + * todo: r2y for win csc + */ + VOP_CTRL_SET(vop, dsp_out_yuv, is_yuv_output(conn_state->bus_format)); + + if (yuv_overlay) { + if (!is_yuv_output(conn_state->bus_format)) + post_y2r_en = true; + } else { + if (is_yuv_output(conn_state->bus_format)) + post_r2y_en = true; + } + + post_csc_mode = to_vop_csc_mode(conn_state->color_space); + VOP_CTRL_SET(vop, bcsh_r2y_en, post_r2y_en); + VOP_CTRL_SET(vop, bcsh_y2r_en, post_y2r_en); + VOP_CTRL_SET(vop, bcsh_r2y_csc_mode, post_csc_mode); + VOP_CTRL_SET(vop, bcsh_y2r_csc_mode, post_csc_mode); + + /* + * Background color is 10bit depth if vop version >= 3.5 + */ + if (!is_yuv_output(conn_state->bus_format)) + val = 0; + else if (VOP_MAJOR(vop->version) == 3 && + VOP_MINOR(vop->version) >= 5) + val = 0x20010200; + else + val = 0x801080; + VOP_CTRL_SET(vop, dsp_background, val); + VOP_CTRL_SET(vop, htotal_pw, (htotal << 16) | hsync_len); val = hact_st << 16; val |= hact_end; diff --git a/drivers/video/drm/rockchip_vop.h b/drivers/video/drm/rockchip_vop.h index 8b2d3ffc4e..f0f7a211b5 100644 --- a/drivers/video/drm/rockchip_vop.h +++ b/drivers/video/drm/rockchip_vop.h @@ -128,6 +128,18 @@ enum dither_down_mode_sel { DITHER_DOWN_FRC = 0x1 }; +enum vop_csc_format { + CSC_BT601L, + CSC_BT709L, + CSC_BT601F, + CSC_BT2020, +}; + +#define DSP_BG_SWAP 0x1 +#define DSP_RB_SWAP 0x2 +#define DSP_RG_SWAP 0x4 +#define DSP_DELTA_SWAP 0x8 + #define PRE_DITHER_DOWN_EN(x) ((x) << 0) #define DITHER_DOWN_EN(x) ((x) << 1) #define DITHER_DOWN_MODE(x) ((x) << 2) @@ -238,6 +250,7 @@ struct vop_ctrl { struct vop_reg core_dclk_div; struct vop_reg dclk_ddr; struct vop_reg p2i_en; + struct vop_reg hdmi_dclk_out_en; struct vop_reg rgb_en; struct vop_reg lvds_en; struct vop_reg edp_en; diff --git a/drivers/video/drm/rockchip_vop_reg.c b/drivers/video/drm/rockchip_vop_reg.c index c3a054485d..9a184612ea 100644 --- a/drivers/video/drm/rockchip_vop_reg.c +++ b/drivers/video/drm/rockchip_vop_reg.c @@ -219,6 +219,9 @@ static const struct vop_ctrl rk3328_ctrl_data = { .hpost_st_end = VOP_REG(RK3328_POST_DSP_HACT_INFO, 0x1fff1fff, 0), .vpost_st_end = VOP_REG(RK3328_POST_DSP_VACT_INFO, 0x1fff1fff, 0), .vpost_st_end_f1 = VOP_REG(RK3328_POST_DSP_VACT_INFO_F1, 0x1fff1fff, 0), + .post_scl_factor = VOP_REG(RK3328_POST_SCL_FACTOR_YRGB, 0xffffffff, 0), + .post_scl_ctrl = VOP_REG(RK3328_POST_SCL_CTRL, 0x3, 0), + .dsp_out_yuv = VOP_REG(RK3328_POST_SCL_CTRL, 0x1, 2), .dsp_interlace = VOP_REG(RK3328_DSP_CTRL0, 0x1, 10), .dsp_layer_sel = VOP_REG(RK3328_DSP_CTRL1, 0xff, 8), .post_lb_mode = VOP_REG(RK3328_SYS_CTRL, 0x1, 18), @@ -249,6 +252,19 @@ static const struct vop_ctrl rk3328_ctrl_data = { .dsp_background = VOP_REG(RK3328_DSP_BG, 0xffffffff, 0), + .bcsh_brightness = VOP_REG(RK3328_BCSH_BCS, 0xff, 0), + .bcsh_contrast = VOP_REG(RK3328_BCSH_BCS, 0x1ff, 8), + .bcsh_sat_con = VOP_REG(RK3328_BCSH_BCS, 0x3ff, 20), + .bcsh_out_mode = VOP_REG(RK3328_BCSH_BCS, 0x3, 30), + .bcsh_sin_hue = VOP_REG(RK3328_BCSH_H, 0x1ff, 0), + .bcsh_cos_hue = VOP_REG(RK3328_BCSH_H, 0x1ff, 16), + .bcsh_r2y_csc_mode = VOP_REG(RK3328_BCSH_CTRL, 0x3, 6), + .bcsh_r2y_en = VOP_REG(RK3328_BCSH_CTRL, 0x1, 4), + .bcsh_y2r_csc_mode = VOP_REG(RK3328_BCSH_CTRL, 0x3, 2), + .bcsh_y2r_en = VOP_REG(RK3328_BCSH_CTRL, 0x1, 0), + .bcsh_color_bar = VOP_REG(RK3328_BCSH_COLOR_BAR, 0xffffff, 8), + .bcsh_en = VOP_REG(RK3328_BCSH_COLOR_BAR, 0x1, 0), + .cfg_done = VOP_REG(RK3328_REG_CFG_DONE, 0x1, 0), }; diff --git a/drivers/video/drm/rockchip_vop_reg.h b/drivers/video/drm/rockchip_vop_reg.h index 70d76bb59f..675616240e 100644 --- a/drivers/video/drm/rockchip_vop_reg.h +++ b/drivers/video/drm/rockchip_vop_reg.h @@ -112,6 +112,10 @@ #define RK3288_DSP_VACT_ST_END 0x0194 #define RK3288_DSP_VS_ST_END_F1 0x0198 #define RK3288_DSP_VACT_ST_END_F1 0x019c + +#define RK3288_BCSH_COLOR_BAR 0x01b0 +#define RK3288_BCSH_BCS 0x01b4 +#define RK3288_BCSH_H 0x01b8 /* register definition end */ /* rk3368 register definition */ diff --git a/include/drm_modes.h b/include/drm_modes.h index bc8d569f63..e77f3a6bbc 100644 --- a/include/drm_modes.h +++ b/include/drm_modes.h @@ -56,6 +56,64 @@ #define DRM_EDID_PT_STEREO (1 << 5) #define DRM_EDID_PT_INTERLACED (1 << 7) +/* see also http://vektor.theorem.ca/graphics/ycbcr/ */ +enum v4l2_colorspace { + /* + * Default colorspace, i.e. let the driver figure it out. + * Can only be used with video capture. + */ + V4L2_COLORSPACE_DEFAULT = 0, + + /* SMPTE 170M: used for broadcast NTSC/PAL SDTV */ + V4L2_COLORSPACE_SMPTE170M = 1, + + /* Obsolete pre-1998 SMPTE 240M HDTV standard, superseded by Rec 709 */ + V4L2_COLORSPACE_SMPTE240M = 2, + + /* Rec.709: used for HDTV */ + V4L2_COLORSPACE_REC709 = 3, + + /* + * Deprecated, do not use. No driver will ever return this. This was + * based on a misunderstanding of the bt878 datasheet. + */ + V4L2_COLORSPACE_BT878 = 4, + + /* + * NTSC 1953 colorspace. This only makes sense when dealing with + * really, really old NTSC recordings. Superseded by SMPTE 170M. + */ + V4L2_COLORSPACE_470_SYSTEM_M = 5, + + /* + * EBU Tech 3213 PAL/SECAM colorspace. This only makes sense when + * dealing with really old PAL/SECAM recordings. Superseded by + * SMPTE 170M. + */ + V4L2_COLORSPACE_470_SYSTEM_BG = 6, + + /* + * Effectively shorthand for V4L2_COLORSPACE_SRGB, V4L2_YCBCR_ENC_601 + * and V4L2_QUANTIZATION_FULL_RANGE. To be used for (Motion-)JPEG. + */ + V4L2_COLORSPACE_JPEG = 7, + + /* For RGB colorspaces such as produces by most webcams. */ + V4L2_COLORSPACE_SRGB = 8, + + /* AdobeRGB colorspace */ + V4L2_COLORSPACE_ADOBERGB = 9, + + /* BT.2020 colorspace, used for UHDTV. */ + V4L2_COLORSPACE_BT2020 = 10, + + /* Raw colorspace: for RAW unprocessed images */ + V4L2_COLORSPACE_RAW = 11, + + /* DCI-P3 colorspace, used by cinema projectors */ + V4L2_COLORSPACE_DCI_P3 = 12, +}; + struct drm_display_mode { /* Proposed mode values */ int clock; /* in kHz */