From 5ce649ed79fe6208e927b0c7d3b62fe1d8a9fe2c Mon Sep 17 00:00:00 2001 From: Mark Yao Date: Wed, 11 Jan 2017 10:14:26 +0800 Subject: [PATCH] drm/rockchip: vop: support overscan setting Change-Id: I2213c7da45fd625d154a9bf11c79ec5608b06a0e Signed-off-by: Mark Yao --- drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 4 + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 145 +++++++++++++++++++- drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 2 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 3 + 4 files changed, 147 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 2f80d7d88dfb..8ddc21eadc39 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -67,6 +67,10 @@ struct rockchip_atomic_commit { struct rockchip_crtc_state { struct drm_crtc_state base; + int left_margin; + int right_margin; + int top_margin; + int bottom_margin; int afbdc_win_format; int afbdc_win_width; int afbdc_win_height; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 9bd8a9573fd4..ad1eb9ab00e2 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -1717,6 +1717,44 @@ err_free_pzpos: return ret; } +static void vop_post_config(struct drm_crtc *crtc) +{ + struct vop *vop = to_vop(crtc); + struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state); + struct drm_display_mode *mode = &crtc->state->adjusted_mode; + u16 vtotal = mode->crtc_vtotal; + u16 hdisplay = mode->crtc_hdisplay; + u16 hact_st = mode->crtc_htotal - mode->crtc_hsync_start; + u16 vdisplay = mode->crtc_vdisplay; + u16 vact_st = mode->crtc_vtotal - mode->crtc_vsync_start; + u16 hsize = hdisplay * (s->left_margin + s->right_margin) / 200; + u16 vsize = vdisplay * (s->top_margin + s->bottom_margin) / 200; + u16 hact_end, vact_end; + u32 val; + + hact_st += hdisplay * (100 - s->left_margin) / 200; + hact_end = hact_st + hsize; + val = hact_st << 16; + val |= hact_end; + VOP_CTRL_SET(vop, hpost_st_end, val); + vact_st += vdisplay * (100 - s->top_margin) / 200; + vact_end = vact_st + vsize; + val = vact_st << 16; + val |= vact_end; + VOP_CTRL_SET(vop, vpost_st_end, val); + val = scl_cal_scale2(vdisplay, vsize) << 16; + val |= scl_cal_scale2(hdisplay, hsize); + VOP_CTRL_SET(vop, post_scl_factor, val); + VOP_CTRL_SET(vop, post_scl_ctrl, 0x3); + if (mode->flags & DRM_MODE_FLAG_INTERLACE) { + u16 vact_st_f1 = vtotal + vact_st + 1; + u16 vact_end_f1 = vact_st_f1 + vsize; + + val = vact_st_f1 << 16 | vact_end_f1; + VOP_CTRL_SET(vop, vpost_st_end_f1, val); + } +} + static void vop_cfg_update(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { @@ -1740,6 +1778,7 @@ static void vop_cfg_update(struct drm_crtc *crtc, VOP_CTRL_SET(vop, afbdc_en, s->afbdc_en); VOP_CTRL_SET(vop, dsp_layer_sel, s->dsp_layer_sel); + vop_post_config(crtc); spin_unlock(&vop->reg_lock); } @@ -1824,20 +1863,30 @@ static void vop_crtc_destroy(struct drm_crtc *crtc) static void vop_crtc_reset(struct drm_crtc *crtc) { - if (crtc->state) + struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state); + + if (crtc->state) { __drm_atomic_helper_crtc_destroy_state(crtc, crtc->state); - kfree(crtc->state); + kfree(s); + } - crtc->state = kzalloc(sizeof(struct rockchip_crtc_state), GFP_KERNEL); - if (crtc->state) - crtc->state->crtc = crtc; + s = kzalloc(sizeof(*s), GFP_KERNEL); + if (!s) + return; + crtc->state = &s->base; + crtc->state->crtc = crtc; + s->left_margin = 100; + s->right_margin = 100; + s->top_margin = 100; + s->bottom_margin = 100; } static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc) { - struct rockchip_crtc_state *rockchip_state; + struct rockchip_crtc_state *rockchip_state, *old_state; - rockchip_state = kzalloc(sizeof(*rockchip_state), GFP_KERNEL); + old_state = to_rockchip_crtc_state(crtc->state); + rockchip_state = kmemdup(old_state, sizeof(*old_state), GFP_KERNEL); if (!rockchip_state) return NULL; @@ -1854,11 +1903,79 @@ static void vop_crtc_destroy_state(struct drm_crtc *crtc, kfree(s); } +static int vop_crtc_atomic_get_property(struct drm_crtc *crtc, + const struct drm_crtc_state *state, + struct drm_property *property, + uint64_t *val) +{ + struct drm_device *drm_dev = crtc->dev; + struct drm_mode_config *mode_config = &drm_dev->mode_config; + struct rockchip_crtc_state *s = to_rockchip_crtc_state(state); + + if (property == mode_config->tv_left_margin_property) { + *val = s->left_margin; + return 0; + } + + if (property == mode_config->tv_right_margin_property) { + *val = s->right_margin; + return 0; + } + + if (property == mode_config->tv_top_margin_property) { + *val = s->top_margin; + return 0; + } + + if (property == mode_config->tv_bottom_margin_property) { + *val = s->bottom_margin; + return 0; + } + + DRM_ERROR("failed to get vop crtc property\n"); + return -EINVAL; +} + +static int vop_crtc_atomic_set_property(struct drm_crtc *crtc, + struct drm_crtc_state *state, + struct drm_property *property, + uint64_t val) +{ + struct drm_device *drm_dev = crtc->dev; + struct drm_mode_config *mode_config = &drm_dev->mode_config; + struct rockchip_crtc_state *s = to_rockchip_crtc_state(state); + + if (property == mode_config->tv_left_margin_property) { + s->left_margin = val; + return 0; + } + + if (property == mode_config->tv_right_margin_property) { + s->right_margin = val; + return 0; + } + + if (property == mode_config->tv_top_margin_property) { + s->top_margin = val; + return 0; + } + + if (property == mode_config->tv_bottom_margin_property) { + s->bottom_margin = val; + return 0; + } + + DRM_ERROR("failed to set vop crtc property\n"); + return -EINVAL; +} + static const struct drm_crtc_funcs vop_crtc_funcs = { .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, .destroy = vop_crtc_destroy, .reset = vop_crtc_reset, + .atomic_get_property = vop_crtc_atomic_get_property, + .atomic_set_property = vop_crtc_atomic_set_property, .atomic_duplicate_state = vop_crtc_duplicate_state, .atomic_destroy_state = vop_crtc_destroy_state, }; @@ -2061,6 +2178,18 @@ static int vop_create_crtc(struct vop *vop) crtc->port = port; rockchip_register_crtc_funcs(crtc, &private_crtc_funcs); + ret = drm_mode_create_tv_properties(drm_dev, 0, NULL); + if (ret) + goto err_unregister_crtc_funcs; +#define VOP_ATTACH_MODE_CONFIG_PROP(prop, v) \ + drm_object_attach_property(&crtc->base, drm_dev->mode_config.prop, v) + + VOP_ATTACH_MODE_CONFIG_PROP(tv_left_margin_property, 100); + VOP_ATTACH_MODE_CONFIG_PROP(tv_right_margin_property, 100); + VOP_ATTACH_MODE_CONFIG_PROP(tv_top_margin_property, 100); + VOP_ATTACH_MODE_CONFIG_PROP(tv_bottom_margin_property, 100); +#undef VOP_ATTACH_MODE_CONFIG_PROP + if (VOP_CTRL_SUPPORT(vop, afbdc_en)) feature |= BIT(ROCKCHIP_DRM_CRTC_FEATURE_AFBDC); drm_object_attach_property(&crtc->base, vop->feature_prop, @@ -2068,6 +2197,8 @@ static int vop_create_crtc(struct vop *vop) return 0; +err_unregister_crtc_funcs: + rockchip_unregister_crtc_funcs(crtc); err_cleanup_crtc: drm_crtc_cleanup(crtc); err_cleanup_planes: diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 7314333233f2..de9685093aca 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -83,6 +83,8 @@ struct vop_ctrl { struct vop_reg hpost_st_end; struct vop_reg vpost_st_end; struct vop_reg vpost_st_end_f1; + struct vop_reg post_scl_factor; + struct vop_reg post_scl_ctrl; struct vop_reg dsp_interlace; struct vop_reg global_regdone_en; struct vop_reg auto_gate_en; diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 77f59d041c19..e64fbed9b494 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -178,6 +178,9 @@ static const struct vop_ctrl rk3288_ctrl_data = { .hpost_st_end = VOP_REG(RK3288_POST_DSP_HACT_INFO, 0x1fff1fff, 0), .vpost_st_end = VOP_REG(RK3288_POST_DSP_VACT_INFO, 0x1fff1fff, 0), .vpost_st_end_f1 = VOP_REG(RK3288_POST_DSP_VACT_INFO_F1, 0x1fff1fff, 0), + .post_scl_factor = VOP_REG(RK3288_POST_SCL_FACTOR_YRGB, 0xffffffff, 0), + .post_scl_ctrl = VOP_REG(RK3288_POST_SCL_CTRL, 0x3, 0), + .dsp_interlace = VOP_REG(RK3288_DSP_CTRL0, 0x1, 10), .auto_gate_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 23), .dsp_layer_sel = VOP_REG(RK3288_DSP_CTRL1, 0xff, 8), -- 2.34.1