drm/rockchip: vop: support overscan setting
authorMark Yao <mark.yao@rock-chips.com>
Wed, 11 Jan 2017 02:14:26 +0000 (10:14 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Thu, 12 Jan 2017 06:21:00 +0000 (14:21 +0800)
Change-Id: I2213c7da45fd625d154a9bf11c79ec5608b06a0e
Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
drivers/gpu/drm/rockchip/rockchip_drm_drv.h
drivers/gpu/drm/rockchip/rockchip_drm_vop.c
drivers/gpu/drm/rockchip/rockchip_drm_vop.h
drivers/gpu/drm/rockchip/rockchip_vop_reg.c

index 2f80d7d88dfb8fed5fe57f9cf96c9cc55af6f146..8ddc21eadc3930a289b0c2d540a0e66c916641bf 100644 (file)
@@ -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;
index 9bd8a9573fd45f8a4f09dc1b5ed3da938571aa58..ad1eb9ab00e26448207329dd6f06becee64ac45d 100644 (file)
@@ -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:
index 7314333233f200defce1b060700a496bde471b73..de9685093aca917217f9d1be71f8d90fbe515943 100644 (file)
@@ -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;
index 77f59d041c19cb2088d728e17ae84a0397da3763..e64fbed9b49433b01209e4bf784e4648c8262926 100644 (file)
@@ -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),