Rk3399 vop big can support one afbc decoder, the afbdc decoder
can select which overlay window use it.

afbdc window has some limit:
  1, not support offset on source buffer.
  2, if feed non-afbc buffer to afbc decoder, afbc decoder hardware
     would die, we need take care of using it.

AFBC is a compressed format, means lower bandwidth consume,
it's useful to improve performance.

Signed-off-by: Mark Yao <mark.yao at rock-chips.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h |  6 ++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 89 +++++++++++++++++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 13 +++++
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c |  7 +++
 4 files changed, 115 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index ea39329..1e07fd6 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -44,6 +44,12 @@ struct rockchip_crtc_funcs {

 struct rockchip_crtc_state {
        struct drm_crtc_state base;
+       int afbdc_win_format;
+       int afbdc_win_width;
+       int afbdc_win_height;
+       int afbdc_win_ptr;
+       int afbdc_win_id;
+       int afbdc_en;
        int output_type;
        int output_mode;
 };
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 834456f..6918223 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -99,6 +99,7 @@ struct vop_win {
        struct drm_plane base;
        const struct vop_win_data *data;
        struct vop *vop;
+       int id;

        /* protected by dev->event_lock */
        bool enable;
@@ -514,6 +515,7 @@ static void vop_crtc_disable(struct drm_crtc *crtc)
                VOP_WIN_SET(vop, win, enable, 0);
                spin_unlock(&vop->reg_lock);
        }
+       VOP_CTRL_SET(vop, afbdc_en, 0);

        drm_crtc_vblank_off(crtc);

@@ -1007,9 +1009,81 @@ static void vop_crtc_enable(struct drm_crtc *crtc)
        VOP_CTRL_SET(vop, standby, 0);
 }

+static int vop_afbdc_atomic_check(struct drm_crtc *crtc,
+                                 struct drm_crtc_state *crtc_state)
+{
+       struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
+       struct drm_atomic_state *state = crtc_state->state;
+       struct drm_plane *plane;
+       struct drm_plane_state *pstate;
+       struct vop_plane_state *plane_state;
+       struct vop_win *win;
+       int afbdc_format;
+       int i;
+
+       s->afbdc_en = 0;
+
+       for_each_plane_in_state(state, plane, pstate, i) {
+               struct drm_framebuffer *fb = pstate->fb;
+               struct drm_rect *src;
+
+               win = to_vop_win(plane);
+               plane_state = to_vop_plane_state(pstate);
+
+               if (pstate->crtc != crtc || !fb)
+                       continue;
+
+               if (fb->modifier[0] != DRM_FORMAT_MOD_ARM_AFBC)
+                       continue;
+
+               switch (plane_state->format) {
+               case VOP_FMT_ARGB8888:
+                       afbdc_format = AFBDC_FMT_U8U8U8U8;
+                       break;
+               case VOP_FMT_RGB888:
+                       afbdc_format = AFBDC_FMT_U8U8U8;
+                       break;
+               case VOP_FMT_RGB565:
+                       afbdc_format = AFBDC_FMT_RGB565;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               if (s->afbdc_en) {
+                       DRM_ERROR("vop only support one afbc layer\n");
+                       return -EINVAL;
+               }
+
+               src = &pstate->src;
+               if (src->x1 || src->y1 || fb->offsets[0]) {
+                       DRM_ERROR("win[%d] afbdc not support offset display\n",
+                                 win->id);
+                       DRM_ERROR("xpos=%d, ypos=%d, offset=%d\n",
+                                 src->x1, src->y1, fb->offsets[0]);
+                       return -EINVAL;
+               }
+               s->afbdc_win_format = afbdc_format;
+               s->afbdc_win_width = pstate->fb->width - 1;
+               s->afbdc_win_height = (drm_rect_height(src) >> 16) - 1;
+               s->afbdc_win_id = win->id;
+               s->afbdc_win_ptr = plane_state->yrgb_mst;
+               s->afbdc_en = 1;
+       }
+
+       return 0;
+}
+
+static int vop_crtc_atomic_check(struct drm_crtc *crtc,
+                                struct drm_crtc_state *crtc_state)
+{
+       return vop_afbdc_atomic_check(crtc, crtc_state);
+}
+
 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))
@@ -1017,6 +1091,19 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc,

        spin_lock(&vop->reg_lock);

+       if (s->afbdc_en) {
+               uint32_t pic_size;
+
+               VOP_CTRL_SET(vop, afbdc_format, s->afbdc_win_format | 1 << 4);
+               VOP_CTRL_SET(vop, afbdc_hreg_block_split, 0);
+               VOP_CTRL_SET(vop, afbdc_sel, s->afbdc_win_id);
+               VOP_CTRL_SET(vop, afbdc_hdr_ptr, s->afbdc_win_ptr);
+               pic_size = (s->afbdc_win_width & 0xffff);
+               pic_size |= s->afbdc_win_height << 16;
+               VOP_CTRL_SET(vop, afbdc_pic_size, pic_size);
+       }
+
+       VOP_CTRL_SET(vop, afbdc_en, s->afbdc_en);
        vop_cfg_done(vop);

        spin_unlock(&vop->reg_lock);
@@ -1042,6 +1129,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,
 };
@@ -1413,6 +1501,7 @@ static void vop_win_init(struct vop *vop)
                struct vop_win *vop_win = &vop->win[i];
                const struct vop_win_data *win_data = &vop_data->win[i];

+               vop_win->id = i;
                vop_win->data = win_data;
                vop_win->vop = vop;
        }
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h 
b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
index ff4f52e..b9b120e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -15,6 +15,10 @@
 #ifndef _ROCKCHIP_DRM_VOP_H
 #define _ROCKCHIP_DRM_VOP_H

+#define AFBDC_FMT_RGB565       0x0
+#define AFBDC_FMT_U8U8U8U8     0x5
+#define AFBDC_FMT_U8U8U8       0x4
+
 enum vop_data_format {
        VOP_FMT_ARGB8888 = 0,
        VOP_FMT_RGB888,
@@ -61,6 +65,15 @@ struct vop_ctrl {
        struct vop_reg hpost_st_end;
        struct vop_reg vpost_st_end;

+       /* AFBDC */
+       struct vop_reg afbdc_en;
+       struct vop_reg afbdc_sel;
+       struct vop_reg afbdc_format;
+       struct vop_reg afbdc_hreg_block_split;
+       struct vop_reg afbdc_pic_size;
+       struct vop_reg afbdc_hdr_ptr;
+       struct vop_reg afbdc_rstn;
+
        struct vop_reg cfg_done;
 };

diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c 
b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
index f1a1688..a09437c 100644
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
@@ -300,6 +300,13 @@ static const struct vop_ctrl rk3399_ctrl_data = {
        .vact_st_end = VOP_REG(RK3399_DSP_VACT_ST_END, 0x1fff1fff, 0),
        .hpost_st_end = VOP_REG(RK3399_POST_DSP_HACT_INFO, 0x1fff1fff, 0),
        .vpost_st_end = VOP_REG(RK3399_POST_DSP_VACT_INFO, 0x1fff1fff, 0),
+       .afbdc_rstn = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 3),
+       .afbdc_en = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 0),
+       .afbdc_sel = VOP_REG(RK3399_AFBCD0_CTRL, 0x3, 1),
+       .afbdc_format = VOP_REG(RK3399_AFBCD0_CTRL, 0x1f, 16),
+       .afbdc_hreg_block_split = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 21),
+       .afbdc_hdr_ptr = VOP_REG(RK3399_AFBCD0_HDR_PTR, 0xffffffff, 0),
+       .afbdc_pic_size = VOP_REG(RK3399_AFBCD0_PIC_SIZE, 0xffffffff, 0),
        .cfg_done = VOP_REG_MASK(RK3399_REG_CFG_DONE, 0x1, 0),
 };

-- 
1.9.1


Reply via email to