drm/rockchip: vop: support plane zpos property
authorMark Yao <mark.yao@rock-chips.com>
Wed, 27 Apr 2016 08:18:07 +0000 (16:18 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Wed, 4 May 2016 10:24:59 +0000 (18:24 +0800)
Change-Id: Idd0265020a591ce5b34d117442104f625e331119
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 bfd5facfd36b2544b7b5ae9fb32704ff07a8c915..7eb8187c1dd5559885838f1c0046625be09f6b6a 100644 (file)
@@ -63,6 +63,7 @@ struct rockchip_atomic_commit {
 
 struct rockchip_crtc_state {
        struct drm_crtc_state base;
+       int dsp_layer_sel;
        int output_type;
        int output_mode;
 };
index 2785bcf8a8003eafa1214245dbce3b67c20a924e..edb483eda66b6905618f1b23a4391549b92e46b7 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <linux/reset.h>
 #include <linux/delay.h>
+#include <linux/sort.h>
 
 #include "rockchip_drm_drv.h"
 #include "rockchip_drm_gem.h"
 #define to_vop_win(x) container_of(x, struct vop_win, base)
 #define to_vop_plane_state(x) container_of(x, struct vop_plane_state, base)
 
+struct vop_zpos {
+       int win_id;
+       int zpos;
+};
+
 struct vop_plane_state {
        struct drm_plane_state base;
        int format;
+       int zpos;
        struct drm_rect src;
        struct drm_rect dest;
        dma_addr_t yrgb_mst;
@@ -104,6 +111,8 @@ struct vop_win {
        struct vop_win *parent;
        struct drm_plane base;
 
+       int win_id;
+       int area_id;
        uint32_t offset;
        enum drm_plane_type type;
        const struct vop_win_phy *phy;
@@ -118,6 +127,7 @@ struct vop {
        struct drm_crtc crtc;
        struct device *dev;
        struct drm_device *drm_dev;
+       struct drm_property *plane_zpos_prop;
        bool is_enabled;
 
        /* mutex vsync_ work */
@@ -780,6 +790,7 @@ static const struct drm_plane_helper_funcs plane_helper_funcs = {
 
 void vop_atomic_plane_reset(struct drm_plane *plane)
 {
+       struct vop_win *win = to_vop_win(plane);
        struct vop_plane_state *vop_plane_state =
                                        to_vop_plane_state(plane->state);
 
@@ -791,6 +802,7 @@ void vop_atomic_plane_reset(struct drm_plane *plane)
        if (!vop_plane_state)
                return;
 
+       vop_plane_state->zpos = win->win_id;
        plane->state = &vop_plane_state->base;
        plane->state->plane = plane;
 }
@@ -826,6 +838,40 @@ static void vop_atomic_plane_destroy_state(struct drm_plane *plane,
        kfree(vop_state);
 }
 
+static int vop_atomic_plane_set_property(struct drm_plane *plane,
+                                        struct drm_plane_state *state,
+                                        struct drm_property *property,
+                                        uint64_t val)
+{
+       struct vop_win *win = to_vop_win(plane);
+       struct vop_plane_state *plane_state = to_vop_plane_state(state);
+
+       if (property == win->vop->plane_zpos_prop) {
+               plane_state->zpos = val;
+               return 0;
+       }
+
+       DRM_ERROR("failed to set vop plane property\n");
+       return -EINVAL;
+}
+
+static int vop_atomic_plane_get_property(struct drm_plane *plane,
+                                        const struct drm_plane_state *state,
+                                        struct drm_property *property,
+                                        uint64_t *val)
+{
+       struct vop_win *win = to_vop_win(plane);
+       struct vop_plane_state *plane_state = to_vop_plane_state(state);
+
+       if (property == win->vop->plane_zpos_prop) {
+               *val = plane_state->zpos;
+               return 0;
+       }
+
+       DRM_ERROR("failed to get vop plane property\n");
+       return -EINVAL;
+}
+
 static const struct drm_plane_funcs vop_plane_funcs = {
        .update_plane   = drm_atomic_helper_update_plane,
        .disable_plane  = drm_atomic_helper_disable_plane,
@@ -833,6 +879,8 @@ static const struct drm_plane_funcs vop_plane_funcs = {
        .reset = vop_atomic_plane_reset,
        .atomic_duplicate_state = vop_atomic_plane_duplicate_state,
        .atomic_destroy_state = vop_atomic_plane_destroy_state,
+       .atomic_set_property = vop_atomic_plane_set_property,
+       .atomic_get_property = vop_atomic_plane_get_property,
 };
 
 static int vop_crtc_enable_vblank(struct drm_crtc *crtc)
@@ -1006,9 +1054,77 @@ static void vop_crtc_enable(struct drm_crtc *crtc)
        VOP_CTRL_SET(vop, standby, 0);
 }
 
+static int vop_zpos_cmp(const void *a, const void *b)
+{
+       struct vop_zpos *pa = (struct vop_zpos *)a;
+       struct vop_zpos *pb = (struct vop_zpos *)b;
+
+       return pb->zpos - pa->zpos;
+}
+
+static int vop_crtc_atomic_check(struct drm_crtc *crtc,
+                                struct drm_crtc_state *state)
+{
+       struct drm_device *dev = crtc->dev;
+       struct rockchip_crtc_state *s = to_rockchip_crtc_state(state);
+       struct vop *vop = to_vop(crtc);
+       struct drm_plane *plane;
+       struct vop_zpos *pzpos;
+       int dsp_layer_sel = 0;
+       int i, cnt = 0, ret = 0;
+
+       pzpos = kmalloc_array(vop->num_wins, sizeof(*pzpos), GFP_KERNEL);
+       if (!pzpos)
+               return -ENOMEM;
+
+       drm_atomic_crtc_state_for_each_plane(plane, state) {
+               struct drm_plane_state *pstate;
+               struct vop_plane_state *plane_state;
+               struct vop_win *win = to_vop_win(plane);
+
+               if (plane->parent)
+                       continue;
+               if (cnt >= vop->num_wins) {
+                       dev_err(dev->dev, "too many planes!\n");
+                       ret = -EINVAL;
+                       goto err_free_pzpos;
+               }
+               pstate = state->state->plane_states[drm_plane_index(plane)];
+
+               /*
+                * plane might not have changed, in which case take
+                * current state:
+                */
+               if (!pstate)
+                       pstate = plane->state;
+               plane_state = to_vop_plane_state(pstate);
+               pzpos[cnt].zpos = plane_state->zpos;
+               pzpos[cnt].win_id = win->win_id;
+
+               cnt++;
+       }
+
+       sort(pzpos, cnt, sizeof(pzpos[0]), vop_zpos_cmp, NULL);
+
+       for (i = 0; i < cnt; i++) {
+               struct vop_zpos *zpos = &pzpos[i];
+
+               dsp_layer_sel <<= 2;
+               dsp_layer_sel |= zpos->win_id;
+       }
+
+       s->dsp_layer_sel = dsp_layer_sel;
+
+err_free_pzpos:
+       kfree(pzpos);
+       return ret;
+}
+
 static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
                                  struct drm_crtc_state *old_crtc_state)
 {
+       struct rockchip_crtc_state *s =
+                       to_rockchip_crtc_state(crtc->state);
        struct vop *vop = to_vop(crtc);
 
        if (WARN_ON(!vop->is_enabled))
@@ -1016,6 +1132,7 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
 
        spin_lock(&vop->reg_lock);
 
+       VOP_CTRL_SET(vop, dsp_layer_sel, s->dsp_layer_sel);
        vop_cfg_done(vop);
 
        spin_unlock(&vop->reg_lock);
@@ -1038,6 +1155,7 @@ static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = {
        .enable = vop_crtc_enable,
        .disable = vop_crtc_disable,
        .mode_fixup = vop_crtc_mode_fixup,
+       .atomic_check = vop_crtc_atomic_check,
        .atomic_flush = vop_crtc_atomic_flush,
        .atomic_begin = vop_crtc_atomic_begin,
 };
@@ -1178,7 +1296,8 @@ static int vop_plane_init(struct vop *vop, struct vop_win *win,
                return ret;
        }
        drm_plane_helper_add(&win->base, &plane_helper_funcs);
-
+       drm_object_attach_property(&win->base.base,
+                                  vop->plane_zpos_prop, win->win_id);
        return 0;
 }
 
@@ -1389,11 +1508,12 @@ err_unprepare_dclk:
 /*
  * Initialize the vop->win array elements.
  */
-static void vop_win_init(struct vop *vop)
+static int vop_win_init(struct vop *vop)
 {
        const struct vop_data *vop_data = vop->data;
        unsigned int i, j;
        unsigned int num_wins = 0;
+       struct drm_property *prop;
 
        for (i = 0; i < vop_data->win_size; i++) {
                struct vop_win *vop_win = &vop->win[num_wins];
@@ -1405,6 +1525,8 @@ static void vop_win_init(struct vop *vop)
                vop_win->data_formats = win_data->phy->data_formats;
                vop_win->nformats = win_data->phy->nformats;
                vop_win->vop = vop;
+               vop_win->win_id = i;
+               vop_win->area_id = 0;
                num_wins++;
 
                for (j = 0; j < win_data->area_size; j++) {
@@ -1418,9 +1540,20 @@ static void vop_win_init(struct vop *vop)
                        vop_area->data_formats = vop_win->data_formats;
                        vop_area->nformats = vop_win->nformats;
                        vop_area->vop = vop;
+                       vop_area->win_id = i;
+                       vop_area->area_id = j;
                        num_wins++;
                }
        }
+       prop = drm_property_create_range(vop->drm_dev, DRM_MODE_PROP_ATOMIC,
+                                        "ZPOS", 0, vop->data->win_size);
+       if (!prop) {
+               DRM_ERROR("failed to create zpos property\n");
+               return -EINVAL;
+       }
+       vop->plane_zpos_prop = prop;
+
+       return 0;
 }
 
 static int vop_bind(struct device *dev, struct device *master, void *data)
@@ -1456,7 +1589,9 @@ static int vop_bind(struct device *dev, struct device *master, void *data)
        vop->num_wins = num_wins;
        dev_set_drvdata(dev, vop);
 
-       vop_win_init(vop);
+       ret = vop_win_init(vop);
+       if (ret)
+               return ret;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        vop->len = resource_size(res);
index 67939645176240825ba6ba7532ad7b311ab16eb2..4b8f142076876371097a8487b7583bfc9544ae96 100644 (file)
@@ -46,6 +46,7 @@ struct vop_ctrl {
        struct vop_reg hdmi_en;
        struct vop_reg mipi_en;
        struct vop_reg out_mode;
+       struct vop_reg dsp_layer_sel;
        struct vop_reg dither_down;
        struct vop_reg dither_up;
        struct vop_reg pin_pol;
index 1b8ec6637328f197835daeb22f3c85321d337f9f..9944d64b269df3ffde1d3ecb84a56a1ea76f2676 100644 (file)
@@ -153,6 +153,7 @@ static const struct vop_win_phy *rk3288_area_data[] = {
 
 static const struct vop_ctrl rk3288_ctrl_data = {
        .standby = VOP_REG(RK3288_SYS_CTRL, 0x1, 22),
+       .dsp_layer_sel = VOP_REG(RK3288_DSP_CTRL1, 0xff, 8),
        .gate_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 23),
        .mmu_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 20),
        .rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12),
@@ -240,6 +241,7 @@ static const struct vop_ctrl rk3399_ctrl_data = {
        .hdmi_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 13),
        .edp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 14),
        .mipi_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 15),
+       .dsp_layer_sel = VOP_REG(RK3399_DSP_CTRL1, 0xff, 8),
        .dither_down = VOP_REG(RK3399_DSP_CTRL1, 0xf, 1),
        .dither_up = VOP_REG(RK3399_DSP_CTRL1, 0x1, 6),
        .data_blank = VOP_REG(RK3399_DSP_CTRL0, 0x1, 19),
@@ -449,6 +451,7 @@ static const struct vop_ctrl rk3036_ctrl_data = {
        .standby = VOP_REG(RK3036_SYS_CTRL, 0x1, 30),
        .out_mode = VOP_REG(RK3036_DSP_CTRL0, 0xf, 0),
        .pin_pol = VOP_REG(RK3036_DSP_CTRL0, 0xf, 4),
+       .dsp_layer_sel = VOP_REG(RK3036_DSP_CTRL0, 0x1, 8),
        .htotal_pw = VOP_REG(RK3036_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
        .hact_st_end = VOP_REG(RK3036_DSP_HACT_ST_END, 0x1fff1fff, 0),
        .vtotal_pw = VOP_REG(RK3036_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),