diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index f833e9b681d6..c716f3f7d6ee 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -560,6 +560,19 @@ struct vop2_video_port_regs { struct vop_reg hdr_dst_color_ctrl; struct vop_reg hdr_src_alpha_ctrl; struct vop_reg hdr_dst_alpha_ctrl; + + /* BCSH */ + struct vop_reg bcsh_brightness; + struct vop_reg bcsh_contrast; + struct vop_reg bcsh_sat_con; + struct vop_reg bcsh_sin_hue; + struct vop_reg bcsh_cos_hue; + struct vop_reg bcsh_r2y_csc_mode; + struct vop_reg bcsh_r2y_en; + struct vop_reg bcsh_y2r_csc_mode; + struct vop_reg bcsh_y2r_en; + struct vop_reg bcsh_out_mode; + struct vop_reg bcsh_en; }; struct vop_win_data { diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index e56f77276420..070fe496879b 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -342,6 +342,11 @@ struct vop2_video_port { * @nr_wins: active wins attached to the video port; */ uint8_t nr_wins; + + /** + * @active_tv_state: TV connector related states + */ + struct drm_tv_connector_state active_tv_state; }; struct vop2 { @@ -1028,8 +1033,11 @@ static int vop2_convert_csc_mode(int csc_mode) { switch (csc_mode) { case V4L2_COLORSPACE_SMPTE170M: + case V4L2_COLORSPACE_470_SYSTEM_M: + case V4L2_COLORSPACE_470_SYSTEM_BG: return CSC_BT601L; case V4L2_COLORSPACE_REC709: + case V4L2_COLORSPACE_SMPTE240M: case V4L2_COLORSPACE_DEFAULT: return CSC_BT709L; case V4L2_COLORSPACE_JPEG: @@ -3279,6 +3287,91 @@ static void vop2_post_config(struct drm_crtc *crtc) static void vop2_tv_config_update(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { + struct rockchip_crtc_state *vcstate = + to_rockchip_crtc_state(crtc->state); + struct rockchip_crtc_state *old_vcstate = + to_rockchip_crtc_state(old_crtc_state); + struct vop2_video_port *vp = to_vop2_video_port(crtc); + struct vop2 *vop2 = vp->vop2; + const struct vop2_data *vop2_data = vop2->data; + const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id]; + int brightness, contrast, saturation, hue, sin_hue, cos_hue; + + if (!vcstate->tv_state) + return; + + /* post BCSH CSC */ + vcstate->post_r2y_en = 0; + vcstate->post_y2r_en = 0; + vcstate->bcsh_en = 0; + if (vcstate->tv_state->brightness != 50 || + vcstate->tv_state->contrast != 50 || + vcstate->tv_state->saturation != 50 || vcstate->tv_state->hue != 50) + vcstate->bcsh_en = 1; + /* + * The BCSH only need to config once except one of the following + * condition changed: + * 1. tv_state: include brightness,contrast,saturation and hue; + * 2. yuv_overlay: it is related to BCSH r2y module; + * 4. bcsh_en: control the BCSH module enable or disable state; + * 5. bus_format: it is related to BCSH y2r module; + */ + if (!memcmp(vcstate->tv_state, &vp->active_tv_state, sizeof(*vcstate->tv_state)) && + vcstate->yuv_overlay == old_vcstate->yuv_overlay && + vcstate->bcsh_en == old_vcstate->bcsh_en && + vcstate->bus_format == old_vcstate->bus_format) + return; + + memcpy(&vp->active_tv_state, vcstate->tv_state, sizeof(*vcstate->tv_state)); + if (vcstate->bcsh_en) { + if (!vcstate->yuv_overlay) + vcstate->post_r2y_en = 1; + if (!is_yuv_output(vcstate->bus_format)) + vcstate->post_y2r_en = 1; + } else { + if (!vcstate->yuv_overlay && is_yuv_output(vcstate->bus_format)) + vcstate->post_r2y_en = 1; + if (vcstate->yuv_overlay && !is_yuv_output(vcstate->bus_format)) + vcstate->post_y2r_en = 1; + } + + vcstate->post_csc_mode = vop2_convert_csc_mode(vcstate->color_space); + VOP_MODULE_SET(vop2, vp, bcsh_r2y_en, vcstate->post_r2y_en); + VOP_MODULE_SET(vop2, vp, bcsh_y2r_en, vcstate->post_y2r_en); + VOP_MODULE_SET(vop2, vp, bcsh_r2y_csc_mode, vcstate->post_csc_mode); + VOP_MODULE_SET(vop2, vp, bcsh_y2r_csc_mode, vcstate->post_csc_mode); + if (!vcstate->bcsh_en) { + VOP_MODULE_SET(vop2, vp, bcsh_en, vcstate->bcsh_en); + return; + } + + if (vp_data->feature & VOP_FEATURE_OUTPUT_10BIT) + brightness = interpolate(0, -128, 100, 127, + vcstate->tv_state->brightness); + else + brightness = interpolate(0, -32, 100, 31, + vcstate->tv_state->brightness); + contrast = interpolate(0, 0, 100, 511, vcstate->tv_state->contrast); + saturation = interpolate(0, 0, 100, 511, vcstate->tv_state->saturation); + hue = interpolate(0, -30, 100, 30, vcstate->tv_state->hue); + + /* + * a:[-30~0]: + * sin_hue = 0x100 - sin(a)*256; + * cos_hue = cos(a)*256; + * a:[0~30] + * sin_hue = sin(a)*256; + * cos_hue = cos(a)*256; + */ + sin_hue = fixp_sin32(hue) >> 23; + cos_hue = fixp_cos32(hue) >> 23; + VOP_MODULE_SET(vop2, vp, bcsh_brightness, brightness); + VOP_MODULE_SET(vop2, vp, bcsh_contrast, contrast); + VOP_MODULE_SET(vop2, vp, bcsh_sat_con, saturation * contrast / 0x100); + VOP_MODULE_SET(vop2, vp, bcsh_sin_hue, sin_hue); + VOP_MODULE_SET(vop2, vp, bcsh_cos_hue, cos_hue); + VOP_MODULE_SET(vop2, vp, bcsh_out_mode, BCSH_OUT_MODE_NORMAL_VIDEO); + VOP_MODULE_SET(vop2, vp, bcsh_en, vcstate->bcsh_en); } static void vop2_cfg_update(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 5517125c9598..3b41682cdbd0 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -403,6 +403,18 @@ static const struct vop2_video_port_regs rk3568_vop_vp0_regs = { .hdr_dst_color_ctrl = VOP_REG(RK3568_HDR0_DST_COLOR_CTRL, 0xffffffff, 0), .hdr_src_alpha_ctrl = VOP_REG(RK3568_HDR0_SRC_ALPHA_CTRL, 0xffffffff, 0), .hdr_dst_alpha_ctrl = VOP_REG(RK3568_HDR0_DST_ALPHA_CTRL, 0xffffffff, 0), + + .bcsh_brightness = VOP_REG(RK3568_VP0_BCSH_BCS, 0xff, 0), + .bcsh_contrast = VOP_REG(RK3568_VP0_BCSH_BCS, 0x1ff, 8), + .bcsh_sat_con = VOP_REG(RK3568_VP0_BCSH_BCS, 0x3ff, 20), + .bcsh_out_mode = VOP_REG(RK3568_VP0_BCSH_BCS, 0x3, 30), + .bcsh_sin_hue = VOP_REG(RK3568_VP0_BCSH_H, 0x1ff, 0), + .bcsh_cos_hue = VOP_REG(RK3568_VP0_BCSH_H, 0x1ff, 16), + .bcsh_r2y_csc_mode = VOP_REG(RK3568_VP0_BCSH_CTRL, 0x3, 6), + .bcsh_r2y_en = VOP_REG(RK3568_VP0_BCSH_CTRL, 0x1, 4), + .bcsh_y2r_csc_mode = VOP_REG(RK3568_VP0_BCSH_CTRL, 0x3, 2), + .bcsh_y2r_en = VOP_REG(RK3568_VP0_BCSH_CTRL, 0x1, 0), + .bcsh_en = VOP_REG(RK3568_VP0_BCSH_COLOR_BAR, 0x1, 31), }; static const struct vop2_video_port_regs rk3568_vop_vp1_regs = { @@ -436,6 +448,18 @@ static const struct vop2_video_port_regs rk3568_vop_vp1_regs = { .dither_down_mode = VOP_REG(RK3568_VP1_DSP_CTRL, 0x1, 20), .mipi_dual_en = VOP_REG(RK3568_VP1_MIPI_CTRL, 0x1, 20), .mipi_dual_channel_swap = VOP_REG(RK3568_VP1_MIPI_CTRL, 0x1, 21), + + .bcsh_brightness = VOP_REG(RK3568_VP1_BCSH_BCS, 0xff, 0), + .bcsh_contrast = VOP_REG(RK3568_VP1_BCSH_BCS, 0x1ff, 8), + .bcsh_sat_con = VOP_REG(RK3568_VP1_BCSH_BCS, 0x3ff, 20), + .bcsh_out_mode = VOP_REG(RK3568_VP1_BCSH_BCS, 0x3, 30), + .bcsh_sin_hue = VOP_REG(RK3568_VP1_BCSH_H, 0x1ff, 0), + .bcsh_cos_hue = VOP_REG(RK3568_VP1_BCSH_H, 0x1ff, 16), + .bcsh_r2y_csc_mode = VOP_REG(RK3568_VP1_BCSH_CTRL, 0x3, 6), + .bcsh_r2y_en = VOP_REG(RK3568_VP1_BCSH_CTRL, 0x1, 4), + .bcsh_y2r_csc_mode = VOP_REG(RK3568_VP1_BCSH_CTRL, 0x3, 2), + .bcsh_y2r_en = VOP_REG(RK3568_VP1_BCSH_CTRL, 0x1, 0), + .bcsh_en = VOP_REG(RK3568_VP1_BCSH_COLOR_BAR, 0x1, 31), }; static const struct vop2_video_port_regs rk3568_vop_vp2_regs = { @@ -469,6 +493,18 @@ static const struct vop2_video_port_regs rk3568_vop_vp2_regs = { .dither_down_mode = VOP_REG(RK3568_VP2_DSP_CTRL, 0x1, 20), .mipi_dual_en = VOP_REG(RK3568_VP2_MIPI_CTRL, 0x1, 20), .mipi_dual_channel_swap = VOP_REG(RK3568_VP2_MIPI_CTRL, 0x1, 21), + + .bcsh_brightness = VOP_REG(RK3568_VP2_BCSH_BCS, 0xff, 0), + .bcsh_contrast = VOP_REG(RK3568_VP2_BCSH_BCS, 0x1ff, 8), + .bcsh_sat_con = VOP_REG(RK3568_VP2_BCSH_BCS, 0x3ff, 20), + .bcsh_out_mode = VOP_REG(RK3568_VP2_BCSH_BCS, 0x3, 30), + .bcsh_sin_hue = VOP_REG(RK3568_VP2_BCSH_H, 0x1ff, 0), + .bcsh_cos_hue = VOP_REG(RK3568_VP2_BCSH_H, 0x1ff, 16), + .bcsh_r2y_csc_mode = VOP_REG(RK3568_VP2_BCSH_CTRL, 0x3, 6), + .bcsh_r2y_en = VOP_REG(RK3568_VP2_BCSH_CTRL, 0x1, 4), + .bcsh_y2r_csc_mode = VOP_REG(RK3568_VP2_BCSH_CTRL, 0x3, 2), + .bcsh_y2r_en = VOP_REG(RK3568_VP2_BCSH_CTRL, 0x1, 0), + .bcsh_en = VOP_REG(RK3568_VP2_BCSH_COLOR_BAR, 0x1, 31), }; static const struct vop2_video_port_data rk3568_vop_video_ports[] = { diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h index 2ac65f3e99b5..08171ef21de6 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h @@ -1091,6 +1091,10 @@ #define RK3568_VP0_DSP_VACT_ST_END 0xC54 #define RK3568_VP0_DSP_VS_ST_END_F1 0xC58 #define RK3568_VP0_DSP_VACT_ST_END_F1 0xC5C +#define RK3568_VP0_BCSH_CTRL 0xC60 +#define RK3568_VP0_BCSH_BCS 0xC64 +#define RK3568_VP0_BCSH_H 0xC68 +#define RK3568_VP0_BCSH_COLOR_BAR 0xC6C #define RK3568_VP1_DSP_CTRL 0xD00 #define RK3568_VP1_MIPI_CTRL 0xD04 @@ -1110,6 +1114,10 @@ #define RK3568_VP1_DSP_VACT_ST_END 0xD54 #define RK3568_VP1_DSP_VS_ST_END_F1 0xD58 #define RK3568_VP1_DSP_VACT_ST_END_F1 0xD5C +#define RK3568_VP1_BCSH_CTRL 0xD60 +#define RK3568_VP1_BCSH_BCS 0xD64 +#define RK3568_VP1_BCSH_H 0xD68 +#define RK3568_VP1_BCSH_COLOR_BAR 0xD6C #define RK3568_VP2_DSP_CTRL 0xE00 #define RK3568_VP2_MIPI_CTRL 0xE04 @@ -1129,6 +1137,10 @@ #define RK3568_VP2_DSP_VACT_ST_END 0xE54 #define RK3568_VP2_DSP_VS_ST_END_F1 0xE58 #define RK3568_VP2_DSP_VACT_ST_END_F1 0xE5C +#define RK3568_VP2_BCSH_CTRL 0xE60 +#define RK3568_VP2_BCSH_BCS 0xE64 +#define RK3568_VP2_BCSH_H 0xE68 +#define RK3568_VP2_BCSH_COLOR_BAR 0xE6C /* Overlay registers definition */ #define RK3568_OVL_CTRL 0x600