diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 635b1ff23366..6ae3c0472532 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -213,6 +213,7 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder, s->output_type = DRM_MODE_CONNECTOR_eDP; if (info->num_bus_formats) s->bus_format = info->bus_formats[0]; + s->tv_state = &conn_state->tv; return 0; } diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index 99439a2fb571..27172a8cc939 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -743,6 +743,7 @@ static int cdn_dp_encoder_atomic_check(struct drm_encoder *encoder, s->output_mode = ROCKCHIP_OUT_MODE_AAAA; s->output_type = DRM_MODE_CONNECTOR_DisplayPort; + s->tv_state = &conn_state->tv; return 0; } diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index 0951a88c9325..10c94c529c5a 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -1220,6 +1220,7 @@ dw_mipi_dsi_encoder_atomic_check(struct drm_encoder *encoder, s->output_type = DRM_MODE_CONNECTOR_DSI; if (info->num_bus_formats) s->bus_format = info->bus_formats[0]; + s->tv_state = &conn_state->tv; if (dsi->slave) s->output_flags = ROCKCHIP_OUTPUT_DSI_DUAL_CHANNEL; diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index e3e976c859df..651e6fe5dbec 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -543,6 +543,7 @@ dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder, s->bus_format = MEDIA_BUS_FMT_RGB888_1X24; } s->output_type = DRM_MODE_CONNECTOR_HDMIA; + s->tv_state = &conn_state->tv; return 0; } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 28df7e479ea1..bcafbc7b8e3c 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -1122,6 +1122,26 @@ static void rockchip_gem_pool_destroy(struct drm_device *drm) gen_pool_destroy(private->secure_buffer_pool); } +static void rockchip_attach_connector_property(struct drm_device *drm) +{ + struct drm_connector *connector; + struct drm_mode_config *conf = &drm->mode_config; + + mutex_lock(&drm->mode_config.mutex); + + drm_for_each_connector(connector, drm) { +#define ROCKCHIP_PROP_ATTACH(prop, v) \ + drm_object_attach_property(&connector->base, prop, v) + + ROCKCHIP_PROP_ATTACH(conf->tv_brightness_property, 100); + ROCKCHIP_PROP_ATTACH(conf->tv_contrast_property, 100); + ROCKCHIP_PROP_ATTACH(conf->tv_saturation_property, 100); + ROCKCHIP_PROP_ATTACH(conf->tv_hue_property, 100); + } + + mutex_unlock(&drm->mode_config.mutex); +} + static int rockchip_drm_bind(struct device *dev) { struct drm_device *drm_dev; @@ -1192,6 +1212,8 @@ static int rockchip_drm_bind(struct device *dev) if (ret) goto err_mode_config_cleanup; + rockchip_attach_connector_property(drm_dev); + ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc); if (ret) goto err_unbind_all; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index b40c8f6d5a39..f73d0f445311 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -76,6 +76,7 @@ struct rockchip_dclk_pll { struct rockchip_crtc_state { struct drm_crtc_state base; struct drm_property_blob *cabc_lut; + struct drm_tv_connector_state *tv_state; int left_margin; int right_margin; int top_margin; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 1e3ae60d27da..fa3c6b8db92e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -2192,6 +2193,67 @@ static void vop_update_cabc(struct drm_crtc *crtc, } } +static void vop_tv_config_update(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) +{ + struct rockchip_crtc_state *s = + to_rockchip_crtc_state(crtc->state); + struct rockchip_crtc_state *old_s = + to_rockchip_crtc_state(old_crtc_state); + int brightness, contrast, saturation, hue, sin_hue, cos_hue; + struct vop *vop = to_vop(crtc); + const struct vop_data *vop_data = vop->data; + + if (!s->tv_state) + return; + + if (old_s->tv_state && + !memcmp(s->tv_state, old_s->tv_state, sizeof(*s->tv_state))) + return; + + if (s->tv_state->brightness == 50 && + s->tv_state->contrast == 50 && + s->tv_state->saturation == 50 && + s->tv_state->hue == 50) { + VOP_CTRL_SET(vop, bcsh_en, 0); + return; + } + + if (vop_data->feature & VOP_FEATURE_OUTPUT_10BIT) + brightness = interpolate(0, -128, 100, 127, + s->tv_state->brightness); + else + brightness = interpolate(0, -32, 100, 31, + s->tv_state->brightness); + contrast = interpolate(0, 0, 100, 511, s->tv_state->contrast); + saturation = interpolate(0, 0, 100, 511, s->tv_state->saturation); + hue = interpolate(0, -30, 100, 30, s->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_CTRL_SET(vop, bcsh_brightness, brightness); + VOP_CTRL_SET(vop, bcsh_contrast, contrast); + VOP_CTRL_SET(vop, bcsh_sat_con, saturation * contrast / 0x100); + VOP_CTRL_SET(vop, bcsh_sin_hue, sin_hue); + VOP_CTRL_SET(vop, bcsh_cos_hue, cos_hue); + VOP_CTRL_SET(vop, bcsh_en, 1); + if (!is_yuv_output(s->bus_format)) { + VOP_CTRL_SET(vop, bcsh_r2y_en, 1); + VOP_CTRL_SET(vop, bcsh_y2r_en, 1); + } else { + VOP_CTRL_SET(vop, bcsh_r2y_en, 0); + VOP_CTRL_SET(vop, bcsh_y2r_en, 0); + } +} + static void vop_cfg_update(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { @@ -2201,6 +2263,8 @@ static void vop_cfg_update(struct drm_crtc *crtc, spin_lock(&vop->reg_lock); + vop_tv_config_update(crtc, old_crtc_state); + if (s->afbdc_en) { uint32_t pic_size; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 7fcc95a03829..5f3a5710e81b 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -179,6 +179,20 @@ struct vop_ctrl { struct vop_reg cabc_global_dn; struct vop_reg cabc_calc_pixel_num; + /* 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_color_bar; + struct vop_reg bcsh_out_mode; + struct vop_reg bcsh_en; + struct vop_reg cfg_done; }; @@ -544,5 +558,10 @@ static inline int us_to_vertical_line(struct drm_display_mode *mode, int us) return us * mode->clock / mode->htotal / 1000; } +static inline int interpolate(int x1, int y1, int x2, int y2, int x) +{ + return y1 + (y2 - y1) * (x - x1) / (x2 - x1); +} + extern const struct component_ops vop_component_ops; #endif /* _ROCKCHIP_DRM_VOP_H */ diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c index 14855cc2db97..54dec40f0adc 100644 --- a/drivers/gpu/drm/rockchip/rockchip_lvds.c +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c @@ -621,6 +621,7 @@ rockchip_lvds_encoder_atomic_check(struct drm_encoder *encoder, s->output_type = DRM_MODE_CONNECTOR_LVDS; if (info->num_bus_formats) s->bus_format = info->bus_formats[0]; + s->tv_state = &conn_state->tv; return 0; } diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 7bc5cb42e3d9..81aa1a6d9f4a 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -247,6 +247,19 @@ static const struct vop_ctrl rk3288_ctrl_data = { .cabc_global_dn_limit_en = VOP_REG_VER(RK3399_CABC_CTRL3, 0x1, 8, 3, 5, -1), + .bcsh_brightness = VOP_REG(RK3288_BCSH_BCS, 0xff, 0), + .bcsh_contrast = VOP_REG(RK3288_BCSH_BCS, 0x1ff, 8), + .bcsh_sat_con = VOP_REG(RK3288_BCSH_BCS, 0x3ff, 20), + .bcsh_out_mode = VOP_REG(RK3288_BCSH_BCS, 0x3, 0), + .bcsh_sin_hue = VOP_REG(RK3288_BCSH_H, 0x1ff, 0), + .bcsh_cos_hue = VOP_REG(RK3288_BCSH_H, 0x1ff, 16), + .bcsh_r2y_csc_mode = VOP_REG_VER(RK3368_BCSH_CTRL, 0x1, 6, 3, 2, -1), + .bcsh_r2y_en = VOP_REG_VER(RK3368_BCSH_CTRL, 0x1, 4, 3, 2, -1), + .bcsh_y2r_csc_mode = VOP_REG_VER(RK3368_BCSH_CTRL, 0x3, 2, 3, 2, -1), + .bcsh_y2r_en = VOP_REG_VER(RK3368_BCSH_CTRL, 0x1, 0, 3, 2, -1), + .bcsh_color_bar = VOP_REG(RK3288_BCSH_COLOR_BAR, 0xffffff, 8), + .bcsh_en = VOP_REG(RK3288_BCSH_COLOR_BAR, 0x1, 0), + .xmirror = VOP_REG(RK3288_DSP_CTRL0, 0x1, 22), .ymirror = VOP_REG(RK3288_DSP_CTRL0, 0x1, 23), diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h index 285ff6e5733b..26a80fef5598 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h @@ -121,6 +121,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 */