Message ID | 20200311145541.29186-7-andrzej.p@collabora.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Add AFBC support for Rockchip | expand |
On Wed, 11 Mar 2020 at 14:56, Andrzej Pietrasiewicz <andrzej.p@collabora.com> wrote: > > This patch adds support for afbc handling. afbc is a compressed format > which reduces the necessary memory bandwidth. > > Co-developed-by: Mark Yao <mark.yao@rock-chips.com> > Signed-off-by: Mark Yao <mark.yao@rock-chips.com> > Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com> > --- > drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 1 + > drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 43 +++++- > drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 137 +++++++++++++++++++- > drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 17 +++ > drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 83 +++++++++++- > 5 files changed, 276 insertions(+), 5 deletions(-) > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h > index c5b06048124e..e33c2dcd0d4b 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h > @@ -30,6 +30,7 @@ struct rockchip_crtc_state { > int output_mode; > int output_bpc; > int output_flags; > + bool enable_afbc; > }; > #define to_rockchip_crtc_state(s) \ > container_of(s, struct rockchip_crtc_state, base) > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c > index 221e72e71432..9b13c784b347 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c > @@ -57,8 +57,49 @@ static const struct drm_mode_config_helper_funcs rockchip_mode_config_helpers = > .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, > }; > > +static struct drm_framebuffer * > +rockchip_fb_create(struct drm_device *dev, struct drm_file *file, > + const struct drm_mode_fb_cmd2 *mode_cmd) > +{ > + struct drm_afbc_framebuffer *afbc_fb; > + const struct drm_format_info *info; > + int ret; > + > + info = drm_get_format_info(dev, mode_cmd); > + if (!info) > + return ERR_PTR(-ENOMEM); > + > + afbc_fb = kzalloc(sizeof(*afbc_fb), GFP_KERNEL); > + if (!afbc_fb) > + return ERR_PTR(-ENOMEM); > + > + ret = drm_gem_fb_init_with_funcs(dev, &afbc_fb->base, file, mode_cmd, > + &rockchip_drm_fb_funcs); > + if (ret) { > + kfree(afbc_fb); > + return ERR_PTR(ret); > + } > + > + if (drm_is_afbc(mode_cmd->modifier[0])) { > + int ret, i; > + > + ret = drm_gem_fb_afbc_init(dev, mode_cmd, afbc_fb); > + if (ret) { > + struct drm_gem_object **obj = afbc_fb->base.obj; > + > + for (i = 0; i < info->num_planes; ++i) > + drm_gem_object_put_unlocked(obj[i]); > + > + kfree(afbc_fb); > + return ERR_PTR(ret); > + } > + } > + > + return &afbc_fb->base; > +} > + > static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = { > - .fb_create = drm_gem_fb_create_with_dirty, > + .fb_create = rockchip_fb_create, > .output_poll_changed = drm_fb_helper_output_poll_changed, > .atomic_check = drm_atomic_helper_check, > .atomic_commit = drm_atomic_helper_commit, > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > index cecb2cc781f5..b87d22eb6ae1 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > @@ -91,9 +91,22 @@ > #define VOP_WIN_TO_INDEX(vop_win) \ > ((vop_win) - (vop_win)->vop->win) > > +#define VOP_AFBC_SET(vop, name, v) \ > + do { \ > + if ((vop)->data->afbc) \ > + vop_reg_set((vop), &(vop)->data->afbc->name, \ > + 0, ~0, v, #name); \ > + } while (0) > + > #define to_vop(x) container_of(x, struct vop, crtc) > #define to_vop_win(x) container_of(x, struct vop_win, base) > > +#define AFBC_FMT_RGB565 0x0 > +#define AFBC_FMT_U8U8U8U8 0x5 > +#define AFBC_FMT_U8U8U8 0x4 > + > +#define AFBC_TILE_16x16 BIT(4) > + > /* > * The coefficients of the following matrix are all fixed points. > * The format is S2.10 for the 3x3 part of the matrix, and S9.12 for the offsets. > @@ -274,6 +287,29 @@ static enum vop_data_format vop_convert_format(uint32_t format) > } > } > > +static int vop_convert_afbc_format(uint32_t format) > +{ > + switch (format) { > + case DRM_FORMAT_XRGB8888: > + case DRM_FORMAT_ARGB8888: > + case DRM_FORMAT_XBGR8888: > + case DRM_FORMAT_ABGR8888: > + return AFBC_FMT_U8U8U8U8; > + case DRM_FORMAT_RGB888: > + case DRM_FORMAT_BGR888: > + return AFBC_FMT_U8U8U8; > + case DRM_FORMAT_RGB565: > + case DRM_FORMAT_BGR565: > + return AFBC_FMT_RGB565; > + /* either of the below should not be reachable */ > + default: > + DRM_WARN_ONCE("unsupported AFBC format[%08x]\n", format); > + return -EINVAL; > + } > + > + return -EINVAL; > +} > + > static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src, > uint32_t dst, bool is_horizontal, > int vsu_mode, int *vskiplines) > @@ -598,6 +634,17 @@ static int vop_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) > vop_win_disable(vop, vop_win); > } > } > + > + if (vop->data->afbc) { > + struct rockchip_crtc_state *s; > + /* > + * Disable AFBC and forget there was a vop window with AFBC > + */ > + VOP_AFBC_SET(vop, enable, 0); > + s = to_rockchip_crtc_state(crtc->state); > + s->enable_afbc = false; > + } > + > spin_unlock(&vop->reg_lock); > > vop_cfg_done(vop); > @@ -710,6 +757,26 @@ static void vop_plane_destroy(struct drm_plane *plane) > drm_plane_cleanup(plane); > } > > +static inline bool rockchip_afbc(u64 modifier) > +{ > + return modifier == ROCKCHIP_AFBC_MOD; > +} > + > +static bool rockchip_mod_supported(struct drm_plane *plane, > + u32 format, u64 modifier) > +{ > + if (modifier == DRM_FORMAT_MOD_LINEAR) > + return true; > + > + if (!rockchip_afbc(modifier)) { > + DRM_DEBUG_KMS("Unsupported format modifer 0x%llx\n", modifier); > + > + return false; > + } > + > + return vop_convert_afbc_format(format) >= 0; > +} > + > static int vop_plane_atomic_check(struct drm_plane *plane, > struct drm_plane_state *state) > { > @@ -758,6 +825,30 @@ static int vop_plane_atomic_check(struct drm_plane *plane, > return -EINVAL; > } > > + if (rockchip_afbc(fb->modifier)) { > + struct vop *vop = to_vop(crtc); > + > + if (!vop->data->afbc) { > + DRM_ERROR("vop does not support AFBC\n"); > + return -EINVAL; > + } > + > + ret = vop_convert_afbc_format(fb->format->format); > + if (ret < 0) > + return ret; > + > + if (state->src.x1 || state->src.y1) { > + DRM_ERROR("AFBC does not support offset display, xpos=%d, ypos=%d, offset=%d\n", state->src.x1, state->src.y1, fb->offsets[0]); > + return -EINVAL; > + } > + > + if (state->rotation && state->rotation != DRM_MODE_ROTATE_0) { > + DRM_ERROR("No rotation support in AFBC, rotation=%d\n", > + state->rotation); > + return -EINVAL; > + } > + } > + > return 0; > } > > @@ -846,6 +937,16 @@ static void vop_plane_atomic_update(struct drm_plane *plane, > > spin_lock(&vop->reg_lock); > > + if (rockchip_afbc(fb->modifier)) { > + int afbc_format = vop_convert_afbc_format(fb->format->format); > + > + VOP_AFBC_SET(vop, format, afbc_format | AFBC_TILE_16x16); > + VOP_AFBC_SET(vop, hreg_block_split, 0); > + VOP_AFBC_SET(vop, win_sel, VOP_WIN_TO_INDEX(vop_win)); > + VOP_AFBC_SET(vop, hdr_ptr, dma_addr); > + VOP_AFBC_SET(vop, pic_size, act_info); > + } > + > VOP_WIN_SET(vop, win, format, format); > VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4)); > VOP_WIN_SET(vop, win, yrgb_mst, dma_addr); > @@ -1001,6 +1102,7 @@ static const struct drm_plane_funcs vop_plane_funcs = { > .reset = drm_atomic_helper_plane_reset, > .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, > .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, > + .format_mod_supported = rockchip_mod_supported, > }; > > static int vop_crtc_enable_vblank(struct drm_crtc *crtc) > @@ -1310,6 +1412,10 @@ static int vop_crtc_atomic_check(struct drm_crtc *crtc, > struct drm_crtc_state *crtc_state) > { > struct vop *vop = to_vop(crtc); > + struct drm_plane *plane; > + struct drm_plane_state *plane_state; > + struct rockchip_crtc_state *s; > + int afbc_planes = 0; > > if (vop->lut_regs && crtc_state->color_mgmt_changed && > crtc_state->gamma_lut) { > @@ -1323,6 +1429,27 @@ static int vop_crtc_atomic_check(struct drm_crtc *crtc, > } > } > > + drm_atomic_crtc_state_for_each_plane(plane, crtc_state) { > + plane_state = > + drm_atomic_get_plane_state(crtc_state->state, plane); > + if (IS_ERR(plane_state)) { > + DRM_DEBUG_KMS("Cannot get plane state for plane %s\n", > + plane->name); > + return PTR_ERR(plane_state); > + } > + > + if (drm_is_afbc(plane_state->fb->modifier)) > + ++afbc_planes; > + } > + > + if (afbc_planes > 1) { > + DRM_DEBUG_KMS("Invalid number of AFBC planes; got %d, expected at most 1\n", afbc_planes); > + return -EINVAL; > + } > + > + s = to_rockchip_crtc_state(crtc_state); > + s->enable_afbc = afbc_planes > 0; > + > return 0; > } > > @@ -1333,6 +1460,7 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc, > struct drm_plane_state *old_plane_state, *new_plane_state; > struct vop *vop = to_vop(crtc); > struct drm_plane *plane; > + struct rockchip_crtc_state *s; > int i; > > if (WARN_ON(!vop->is_enabled)) > @@ -1340,6 +1468,9 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc, > > spin_lock(&vop->reg_lock); > > + /* Enable AFBC if there is some AFBC window, disable otherwise. */ > + s = to_rockchip_crtc_state(crtc->state); > + VOP_AFBC_SET(vop, enable, s->enable_afbc); > vop_cfg_done(vop); > > spin_unlock(&vop->reg_lock); > @@ -1634,7 +1765,8 @@ static int vop_create_crtc(struct vop *vop) > 0, &vop_plane_funcs, > win_data->phy->data_formats, > win_data->phy->nformats, > - NULL, win_data->type, NULL); > + win_data->phy->format_modifiers, > + win_data->type, NULL); > if (ret) { > DRM_DEV_ERROR(vop->dev, "failed to init plane %d\n", > ret); > @@ -1678,7 +1810,8 @@ static int vop_create_crtc(struct vop *vop) > &vop_plane_funcs, > win_data->phy->data_formats, > win_data->phy->nformats, > - NULL, win_data->type, NULL); > + win_data->phy->format_modifiers, > + win_data->type, NULL); > if (ret) { > DRM_DEV_ERROR(vop->dev, "failed to init overlay %d\n", > ret); > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h > index cc672620d6e0..d03bdb531ef2 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h > @@ -17,6 +17,11 @@ > > #define NUM_YUV2YUV_COEFFICIENTS 12 > > +#define ROCKCHIP_AFBC_MOD \ > + DRM_FORMAT_MOD_ARM_AFBC( \ > + AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | AFBC_FORMAT_MOD_SPARSE \ > + ) > + > enum vop_data_format { > VOP_FMT_ARGB8888 = 0, > VOP_FMT_RGB888, > @@ -34,6 +39,16 @@ struct vop_reg { > bool relaxed; > }; > > +struct vop_afbc { > + struct vop_reg enable; > + struct vop_reg win_sel; > + struct vop_reg format; > + struct vop_reg hreg_block_split; > + struct vop_reg pic_size; > + struct vop_reg hdr_ptr; > + struct vop_reg rstn; > +}; > + > struct vop_modeset { > struct vop_reg htotal_pw; > struct vop_reg hact_st_end; > @@ -134,6 +149,7 @@ struct vop_win_phy { > const struct vop_scl_regs *scl; > const uint32_t *data_formats; > uint32_t nformats; > + const uint64_t *format_modifiers; > > struct vop_reg enable; > struct vop_reg gate; > @@ -173,6 +189,7 @@ struct vop_data { > const struct vop_misc *misc; > const struct vop_modeset *modeset; > const struct vop_output *output; > + const struct vop_afbc *afbc; > const struct vop_win_yuv2yuv_data *win_yuv2yuv; > const struct vop_win_data *win; > unsigned int win_size; > diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c > index 7a9d979c8d5d..2413deded22c 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c > +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c > @@ -50,6 +50,17 @@ static const uint32_t formats_win_full[] = { > DRM_FORMAT_NV24, > }; > > +static const uint64_t format_modifiers_win_full[] = { > + DRM_FORMAT_MOD_LINEAR, > + DRM_FORMAT_MOD_INVALID, > +}; > + > +static const uint64_t format_modifiers_win_full_afbc[] = { > + ROCKCHIP_AFBC_MOD, > + DRM_FORMAT_MOD_LINEAR, > + DRM_FORMAT_MOD_INVALID, > +}; > + > static const uint32_t formats_win_lite[] = { > DRM_FORMAT_XRGB8888, > DRM_FORMAT_ARGB8888, > @@ -61,6 +72,11 @@ static const uint32_t formats_win_lite[] = { > DRM_FORMAT_BGR565, > }; > > +static const uint64_t format_modifiers_win_lite[] = { > + DRM_FORMAT_MOD_LINEAR, > + DRM_FORMAT_MOD_INVALID, > +}; > + > static const struct vop_scl_regs rk3036_win_scl = { > .scale_yrgb_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), > .scale_yrgb_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 16), > @@ -72,6 +88,7 @@ static const struct vop_win_phy rk3036_win0_data = { > .scl = &rk3036_win_scl, > .data_formats = formats_win_full, > .nformats = ARRAY_SIZE(formats_win_full), > + .format_modifiers = format_modifiers_win_full, > .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 0), > .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 3), > .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 15), > @@ -87,6 +104,7 @@ static const struct vop_win_phy rk3036_win0_data = { > static const struct vop_win_phy rk3036_win1_data = { > .data_formats = formats_win_lite, > .nformats = ARRAY_SIZE(formats_win_lite), > + .format_modifiers = format_modifiers_win_lite, > .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1), > .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6), > .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19), > @@ -153,6 +171,7 @@ static const struct vop_data rk3036_vop = { > static const struct vop_win_phy rk3126_win1_data = { > .data_formats = formats_win_lite, > .nformats = ARRAY_SIZE(formats_win_lite), > + .format_modifiers = format_modifiers_win_lite, > .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1), > .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6), > .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19), > @@ -234,6 +253,7 @@ static const struct vop_win_phy px30_win0_data = { > .scl = &px30_win_scl, > .data_formats = formats_win_full, > .nformats = ARRAY_SIZE(formats_win_full), > + .format_modifiers = format_modifiers_win_full, > .enable = VOP_REG(PX30_WIN0_CTRL0, 0x1, 0), > .format = VOP_REG(PX30_WIN0_CTRL0, 0x7, 1), > .rb_swap = VOP_REG(PX30_WIN0_CTRL0, 0x1, 12), > @@ -249,6 +269,7 @@ static const struct vop_win_phy px30_win0_data = { > static const struct vop_win_phy px30_win1_data = { > .data_formats = formats_win_lite, > .nformats = ARRAY_SIZE(formats_win_lite), > + .format_modifiers = format_modifiers_win_lite, > .enable = VOP_REG(PX30_WIN1_CTRL0, 0x1, 0), > .format = VOP_REG(PX30_WIN1_CTRL0, 0x7, 4), > .rb_swap = VOP_REG(PX30_WIN1_CTRL0, 0x1, 12), > @@ -261,6 +282,7 @@ static const struct vop_win_phy px30_win1_data = { > static const struct vop_win_phy px30_win2_data = { > .data_formats = formats_win_lite, > .nformats = ARRAY_SIZE(formats_win_lite), > + .format_modifiers = format_modifiers_win_lite, > .gate = VOP_REG(PX30_WIN2_CTRL0, 0x1, 4), > .enable = VOP_REG(PX30_WIN2_CTRL0, 0x1, 0), > .format = VOP_REG(PX30_WIN2_CTRL0, 0x3, 5), > @@ -316,6 +338,7 @@ static const struct vop_win_phy rk3066_win0_data = { > .scl = &rk3066_win_scl, > .data_formats = formats_win_full, > .nformats = ARRAY_SIZE(formats_win_full), > + .format_modifiers = format_modifiers_win_full, > .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 0), > .format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 4), > .rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 19), > @@ -332,6 +355,7 @@ static const struct vop_win_phy rk3066_win1_data = { > .scl = &rk3066_win_scl, > .data_formats = formats_win_full, > .nformats = ARRAY_SIZE(formats_win_full), > + .format_modifiers = format_modifiers_win_full, > .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 1), > .format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 7), > .rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 23), > @@ -347,6 +371,7 @@ static const struct vop_win_phy rk3066_win1_data = { > static const struct vop_win_phy rk3066_win2_data = { > .data_formats = formats_win_lite, > .nformats = ARRAY_SIZE(formats_win_lite), > + .format_modifiers = format_modifiers_win_lite, > .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 2), > .format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 10), > .rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 27), > @@ -426,6 +451,7 @@ static const struct vop_win_phy rk3188_win0_data = { > .scl = &rk3188_win_scl, > .data_formats = formats_win_full, > .nformats = ARRAY_SIZE(formats_win_full), > + .format_modifiers = format_modifiers_win_full, > .enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 0), > .format = VOP_REG(RK3188_SYS_CTRL, 0x7, 3), > .rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 15), > @@ -440,6 +466,7 @@ static const struct vop_win_phy rk3188_win0_data = { > static const struct vop_win_phy rk3188_win1_data = { > .data_formats = formats_win_lite, > .nformats = ARRAY_SIZE(formats_win_lite), > + .format_modifiers = format_modifiers_win_lite, > .enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 1), > .format = VOP_REG(RK3188_SYS_CTRL, 0x7, 6), > .rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 19), > @@ -545,6 +572,7 @@ static const struct vop_win_phy rk3288_win01_data = { > .scl = &rk3288_win_full_scl, > .data_formats = formats_win_full, > .nformats = ARRAY_SIZE(formats_win_full), > + .format_modifiers = format_modifiers_win_full, > .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), > .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), > .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), > @@ -563,6 +591,7 @@ static const struct vop_win_phy rk3288_win01_data = { > static const struct vop_win_phy rk3288_win23_data = { > .data_formats = formats_win_lite, > .nformats = ARRAY_SIZE(formats_win_lite), > + .format_modifiers = format_modifiers_win_lite, > .enable = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 4), > .gate = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 0), > .format = VOP_REG(RK3288_WIN2_CTRL0, 0x7, 1), > @@ -677,6 +706,7 @@ static const struct vop_win_phy rk3368_win01_data = { > .scl = &rk3288_win_full_scl, > .data_formats = formats_win_full, > .nformats = ARRAY_SIZE(formats_win_full), > + .format_modifiers = format_modifiers_win_full, > .enable = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 0), > .format = VOP_REG(RK3368_WIN0_CTRL0, 0x7, 1), > .rb_swap = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 12), > @@ -697,6 +727,7 @@ static const struct vop_win_phy rk3368_win01_data = { > static const struct vop_win_phy rk3368_win23_data = { > .data_formats = formats_win_lite, > .nformats = ARRAY_SIZE(formats_win_lite), > + .format_modifiers = format_modifiers_win_lite, > .gate = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 0), > .enable = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 4), > .format = VOP_REG(RK3368_WIN2_CTRL0, 0x3, 5), > @@ -817,6 +848,53 @@ static const struct vop_win_yuv2yuv_data rk3399_vop_big_win_yuv2yuv_data[] = { > .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 9) }, > { .base = 0xC0, .phy = &rk3399_yuv2yuv_win23_data }, > { .base = 0x120, .phy = &rk3399_yuv2yuv_win23_data }, > + > +}; > + > +static const struct vop_win_phy rk3399_win01_data = { > + .scl = &rk3288_win_full_scl, > + .data_formats = formats_win_full, > + .nformats = ARRAY_SIZE(formats_win_full), > + .format_modifiers = format_modifiers_win_full_afbc, > + .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), > + .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), > + .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), > + .y_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 22), > + .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0), > + .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0), > + .dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0), > + .yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0), > + .uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0), > + .yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0), > + .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16), > + .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0), > + .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0), > +}; > + > +/* > + * rk3399 vop big windows register layout is same as rk3288, but we > + * have a separate rk3399 win data array here so that we can advertise > + * AFBC on the primary plane. > + */ > +static const struct vop_win_data rk3399_vop_win_data[] = { > + { .base = 0x00, .phy = &rk3399_win01_data, > + .type = DRM_PLANE_TYPE_PRIMARY }, > + { .base = 0x40, .phy = &rk3288_win01_data, > + .type = DRM_PLANE_TYPE_OVERLAY }, > + { .base = 0x00, .phy = &rk3288_win23_data, > + .type = DRM_PLANE_TYPE_OVERLAY }, > + { .base = 0x50, .phy = &rk3288_win23_data, > + .type = DRM_PLANE_TYPE_CURSOR }, > +}; > + > +static const struct vop_afbc rk3399_vop_afbc = { > + .rstn = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 3), > + .enable = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 0), > + .win_sel = VOP_REG(RK3399_AFBCD0_CTRL, 0x3, 1), > + .format = VOP_REG(RK3399_AFBCD0_CTRL, 0x1f, 16), > + .hreg_block_split = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 21), > + .hdr_ptr = VOP_REG(RK3399_AFBCD0_HDR_PTR, 0xffffffff, 0), > + .pic_size = VOP_REG(RK3399_AFBCD0_PIC_SIZE, 0xffffffff, 0), > }; > > static const struct vop_data rk3399_vop_big = { > @@ -826,9 +904,10 @@ static const struct vop_data rk3399_vop_big = { > .common = &rk3288_common, > .modeset = &rk3288_modeset, > .output = &rk3399_output, > + .afbc = &rk3399_vop_afbc, > .misc = &rk3368_misc, > - .win = rk3368_vop_win_data, > - .win_size = ARRAY_SIZE(rk3368_vop_win_data), > + .win = rk3399_vop_win_data, > + .win_size = ARRAY_SIZE(rk3399_vop_win_data), > .win_yuv2yuv = rk3399_vop_big_win_yuv2yuv_data, > }; > > -- > 2.17.1 Heiko, Sandy, being the maintainers of the Rockchip driver, can you review/ack this patch? I believe the intention is to merge the series via drm-misc. Andrzej already has commit access. -Emil
Hi Emil, 在 2020/3/16 下午10:10, Emil Velikov 写道: > On Wed, 11 Mar 2020 at 14:56, Andrzej Pietrasiewicz > <andrzej.p@collabora.com> wrote: >> This patch adds support for afbc handling. afbc is a compressed format >> which reduces the necessary memory bandwidth. >> >> Co-developed-by: Mark Yao <mark.yao@rock-chips.com> >> Signed-off-by: Mark Yao <mark.yao@rock-chips.com> >> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com> >> --- >> drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 1 + >> drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 43 +++++- >> drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 137 +++++++++++++++++++- >> drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 17 +++ >> drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 83 +++++++++++- >> 5 files changed, 276 insertions(+), 5 deletions(-) >> >> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h >> index c5b06048124e..e33c2dcd0d4b 100644 >> --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h >> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h >> @@ -30,6 +30,7 @@ struct rockchip_crtc_state { >> int output_mode; >> int output_bpc; >> int output_flags; >> + bool enable_afbc; >> }; >> #define to_rockchip_crtc_state(s) \ >> container_of(s, struct rockchip_crtc_state, base) >> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c >> index 221e72e71432..9b13c784b347 100644 >> --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c >> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c >> @@ -57,8 +57,49 @@ static const struct drm_mode_config_helper_funcs rockchip_mode_config_helpers = >> .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, >> }; >> >> +static struct drm_framebuffer * >> +rockchip_fb_create(struct drm_device *dev, struct drm_file *file, >> + const struct drm_mode_fb_cmd2 *mode_cmd) >> +{ >> + struct drm_afbc_framebuffer *afbc_fb; >> + const struct drm_format_info *info; >> + int ret; >> + >> + info = drm_get_format_info(dev, mode_cmd); >> + if (!info) >> + return ERR_PTR(-ENOMEM); >> + >> + afbc_fb = kzalloc(sizeof(*afbc_fb), GFP_KERNEL); >> + if (!afbc_fb) >> + return ERR_PTR(-ENOMEM); >> + >> + ret = drm_gem_fb_init_with_funcs(dev, &afbc_fb->base, file, mode_cmd, >> + &rockchip_drm_fb_funcs); >> + if (ret) { >> + kfree(afbc_fb); >> + return ERR_PTR(ret); >> + } >> + >> + if (drm_is_afbc(mode_cmd->modifier[0])) { >> + int ret, i; >> + >> + ret = drm_gem_fb_afbc_init(dev, mode_cmd, afbc_fb); >> + if (ret) { >> + struct drm_gem_object **obj = afbc_fb->base.obj; >> + >> + for (i = 0; i < info->num_planes; ++i) >> + drm_gem_object_put_unlocked(obj[i]); >> + >> + kfree(afbc_fb); >> + return ERR_PTR(ret); >> + } >> + } >> + >> + return &afbc_fb->base; >> +} >> + >> static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = { >> - .fb_create = drm_gem_fb_create_with_dirty, >> + .fb_create = rockchip_fb_create, >> .output_poll_changed = drm_fb_helper_output_poll_changed, >> .atomic_check = drm_atomic_helper_check, >> .atomic_commit = drm_atomic_helper_commit, >> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c >> index cecb2cc781f5..b87d22eb6ae1 100644 >> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c >> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c >> @@ -91,9 +91,22 @@ >> #define VOP_WIN_TO_INDEX(vop_win) \ >> ((vop_win) - (vop_win)->vop->win) >> >> +#define VOP_AFBC_SET(vop, name, v) \ >> + do { \ >> + if ((vop)->data->afbc) \ >> + vop_reg_set((vop), &(vop)->data->afbc->name, \ >> + 0, ~0, v, #name); \ >> + } while (0) >> + >> #define to_vop(x) container_of(x, struct vop, crtc) >> #define to_vop_win(x) container_of(x, struct vop_win, base) >> >> +#define AFBC_FMT_RGB565 0x0 >> +#define AFBC_FMT_U8U8U8U8 0x5 >> +#define AFBC_FMT_U8U8U8 0x4 >> + >> +#define AFBC_TILE_16x16 BIT(4) >> + >> /* >> * The coefficients of the following matrix are all fixed points. >> * The format is S2.10 for the 3x3 part of the matrix, and S9.12 for the offsets. >> @@ -274,6 +287,29 @@ static enum vop_data_format vop_convert_format(uint32_t format) >> } >> } >> >> +static int vop_convert_afbc_format(uint32_t format) >> +{ >> + switch (format) { >> + case DRM_FORMAT_XRGB8888: >> + case DRM_FORMAT_ARGB8888: >> + case DRM_FORMAT_XBGR8888: >> + case DRM_FORMAT_ABGR8888: >> + return AFBC_FMT_U8U8U8U8; >> + case DRM_FORMAT_RGB888: >> + case DRM_FORMAT_BGR888: >> + return AFBC_FMT_U8U8U8; >> + case DRM_FORMAT_RGB565: >> + case DRM_FORMAT_BGR565: >> + return AFBC_FMT_RGB565; >> + /* either of the below should not be reachable */ >> + default: >> + DRM_WARN_ONCE("unsupported AFBC format[%08x]\n", format); >> + return -EINVAL; >> + } >> + >> + return -EINVAL; >> +} >> + >> static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src, >> uint32_t dst, bool is_horizontal, >> int vsu_mode, int *vskiplines) >> @@ -598,6 +634,17 @@ static int vop_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) >> vop_win_disable(vop, vop_win); >> } >> } >> + >> + if (vop->data->afbc) { >> + struct rockchip_crtc_state *s; >> + /* >> + * Disable AFBC and forget there was a vop window with AFBC >> + */ >> + VOP_AFBC_SET(vop, enable, 0); >> + s = to_rockchip_crtc_state(crtc->state); >> + s->enable_afbc = false; >> + } >> + >> spin_unlock(&vop->reg_lock); >> >> vop_cfg_done(vop); >> @@ -710,6 +757,26 @@ static void vop_plane_destroy(struct drm_plane *plane) >> drm_plane_cleanup(plane); >> } >> >> +static inline bool rockchip_afbc(u64 modifier) >> +{ >> + return modifier == ROCKCHIP_AFBC_MOD; >> +} >> + >> +static bool rockchip_mod_supported(struct drm_plane *plane, >> + u32 format, u64 modifier) >> +{ >> + if (modifier == DRM_FORMAT_MOD_LINEAR) >> + return true; >> + >> + if (!rockchip_afbc(modifier)) { >> + DRM_DEBUG_KMS("Unsupported format modifer 0x%llx\n", modifier); >> + >> + return false; >> + } >> + >> + return vop_convert_afbc_format(format) >= 0; >> +} >> + >> static int vop_plane_atomic_check(struct drm_plane *plane, >> struct drm_plane_state *state) >> { >> @@ -758,6 +825,30 @@ static int vop_plane_atomic_check(struct drm_plane *plane, >> return -EINVAL; >> } >> >> + if (rockchip_afbc(fb->modifier)) { >> + struct vop *vop = to_vop(crtc); >> + >> + if (!vop->data->afbc) { >> + DRM_ERROR("vop does not support AFBC\n"); >> + return -EINVAL; >> + } >> + >> + ret = vop_convert_afbc_format(fb->format->format); >> + if (ret < 0) >> + return ret; >> + >> + if (state->src.x1 || state->src.y1) { >> + DRM_ERROR("AFBC does not support offset display, xpos=%d, ypos=%d, offset=%d\n", state->src.x1, state->src.y1, fb->offsets[0]); >> + return -EINVAL; >> + } >> + >> + if (state->rotation && state->rotation != DRM_MODE_ROTATE_0) { >> + DRM_ERROR("No rotation support in AFBC, rotation=%d\n", >> + state->rotation); >> + return -EINVAL; >> + } >> + } >> + >> return 0; >> } >> >> @@ -846,6 +937,16 @@ static void vop_plane_atomic_update(struct drm_plane *plane, >> >> spin_lock(&vop->reg_lock); >> >> + if (rockchip_afbc(fb->modifier)) { >> + int afbc_format = vop_convert_afbc_format(fb->format->format); >> + >> + VOP_AFBC_SET(vop, format, afbc_format | AFBC_TILE_16x16); >> + VOP_AFBC_SET(vop, hreg_block_split, 0); >> + VOP_AFBC_SET(vop, win_sel, VOP_WIN_TO_INDEX(vop_win)); >> + VOP_AFBC_SET(vop, hdr_ptr, dma_addr); >> + VOP_AFBC_SET(vop, pic_size, act_info); >> + } >> + >> VOP_WIN_SET(vop, win, format, format); >> VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4)); >> VOP_WIN_SET(vop, win, yrgb_mst, dma_addr); >> @@ -1001,6 +1102,7 @@ static const struct drm_plane_funcs vop_plane_funcs = { >> .reset = drm_atomic_helper_plane_reset, >> .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, >> .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, >> + .format_mod_supported = rockchip_mod_supported, >> }; >> >> static int vop_crtc_enable_vblank(struct drm_crtc *crtc) >> @@ -1310,6 +1412,10 @@ static int vop_crtc_atomic_check(struct drm_crtc *crtc, >> struct drm_crtc_state *crtc_state) >> { >> struct vop *vop = to_vop(crtc); >> + struct drm_plane *plane; >> + struct drm_plane_state *plane_state; >> + struct rockchip_crtc_state *s; >> + int afbc_planes = 0; >> >> if (vop->lut_regs && crtc_state->color_mgmt_changed && >> crtc_state->gamma_lut) { >> @@ -1323,6 +1429,27 @@ static int vop_crtc_atomic_check(struct drm_crtc *crtc, >> } >> } >> >> + drm_atomic_crtc_state_for_each_plane(plane, crtc_state) { >> + plane_state = >> + drm_atomic_get_plane_state(crtc_state->state, plane); >> + if (IS_ERR(plane_state)) { >> + DRM_DEBUG_KMS("Cannot get plane state for plane %s\n", >> + plane->name); >> + return PTR_ERR(plane_state); >> + } >> + >> + if (drm_is_afbc(plane_state->fb->modifier)) >> + ++afbc_planes; >> + } >> + >> + if (afbc_planes > 1) { >> + DRM_DEBUG_KMS("Invalid number of AFBC planes; got %d, expected at most 1\n", afbc_planes); >> + return -EINVAL; >> + } >> + >> + s = to_rockchip_crtc_state(crtc_state); >> + s->enable_afbc = afbc_planes > 0; >> + >> return 0; >> } >> >> @@ -1333,6 +1460,7 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc, >> struct drm_plane_state *old_plane_state, *new_plane_state; >> struct vop *vop = to_vop(crtc); >> struct drm_plane *plane; >> + struct rockchip_crtc_state *s; >> int i; >> >> if (WARN_ON(!vop->is_enabled)) >> @@ -1340,6 +1468,9 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc, >> >> spin_lock(&vop->reg_lock); >> >> + /* Enable AFBC if there is some AFBC window, disable otherwise. */ >> + s = to_rockchip_crtc_state(crtc->state); >> + VOP_AFBC_SET(vop, enable, s->enable_afbc); >> vop_cfg_done(vop); >> >> spin_unlock(&vop->reg_lock); >> @@ -1634,7 +1765,8 @@ static int vop_create_crtc(struct vop *vop) >> 0, &vop_plane_funcs, >> win_data->phy->data_formats, >> win_data->phy->nformats, >> - NULL, win_data->type, NULL); >> + win_data->phy->format_modifiers, >> + win_data->type, NULL); >> if (ret) { >> DRM_DEV_ERROR(vop->dev, "failed to init plane %d\n", >> ret); >> @@ -1678,7 +1810,8 @@ static int vop_create_crtc(struct vop *vop) >> &vop_plane_funcs, >> win_data->phy->data_formats, >> win_data->phy->nformats, >> - NULL, win_data->type, NULL); >> + win_data->phy->format_modifiers, >> + win_data->type, NULL); >> if (ret) { >> DRM_DEV_ERROR(vop->dev, "failed to init overlay %d\n", >> ret); >> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h >> index cc672620d6e0..d03bdb531ef2 100644 >> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h >> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h >> @@ -17,6 +17,11 @@ >> >> #define NUM_YUV2YUV_COEFFICIENTS 12 >> >> +#define ROCKCHIP_AFBC_MOD \ >> + DRM_FORMAT_MOD_ARM_AFBC( \ >> + AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | AFBC_FORMAT_MOD_SPARSE \ >> + ) >> + >> enum vop_data_format { >> VOP_FMT_ARGB8888 = 0, >> VOP_FMT_RGB888, >> @@ -34,6 +39,16 @@ struct vop_reg { >> bool relaxed; >> }; >> >> +struct vop_afbc { >> + struct vop_reg enable; >> + struct vop_reg win_sel; >> + struct vop_reg format; >> + struct vop_reg hreg_block_split; >> + struct vop_reg pic_size; >> + struct vop_reg hdr_ptr; >> + struct vop_reg rstn; >> +}; >> + >> struct vop_modeset { >> struct vop_reg htotal_pw; >> struct vop_reg hact_st_end; >> @@ -134,6 +149,7 @@ struct vop_win_phy { >> const struct vop_scl_regs *scl; >> const uint32_t *data_formats; >> uint32_t nformats; >> + const uint64_t *format_modifiers; >> >> struct vop_reg enable; >> struct vop_reg gate; >> @@ -173,6 +189,7 @@ struct vop_data { >> const struct vop_misc *misc; >> const struct vop_modeset *modeset; >> const struct vop_output *output; >> + const struct vop_afbc *afbc; >> const struct vop_win_yuv2yuv_data *win_yuv2yuv; >> const struct vop_win_data *win; >> unsigned int win_size; >> diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c >> index 7a9d979c8d5d..2413deded22c 100644 >> --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c >> +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c >> @@ -50,6 +50,17 @@ static const uint32_t formats_win_full[] = { >> DRM_FORMAT_NV24, >> }; >> >> +static const uint64_t format_modifiers_win_full[] = { >> + DRM_FORMAT_MOD_LINEAR, >> + DRM_FORMAT_MOD_INVALID, >> +}; >> + >> +static const uint64_t format_modifiers_win_full_afbc[] = { >> + ROCKCHIP_AFBC_MOD, >> + DRM_FORMAT_MOD_LINEAR, >> + DRM_FORMAT_MOD_INVALID, >> +}; >> + >> static const uint32_t formats_win_lite[] = { >> DRM_FORMAT_XRGB8888, >> DRM_FORMAT_ARGB8888, >> @@ -61,6 +72,11 @@ static const uint32_t formats_win_lite[] = { >> DRM_FORMAT_BGR565, >> }; >> >> +static const uint64_t format_modifiers_win_lite[] = { >> + DRM_FORMAT_MOD_LINEAR, >> + DRM_FORMAT_MOD_INVALID, >> +}; >> + >> static const struct vop_scl_regs rk3036_win_scl = { >> .scale_yrgb_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), >> .scale_yrgb_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 16), >> @@ -72,6 +88,7 @@ static const struct vop_win_phy rk3036_win0_data = { >> .scl = &rk3036_win_scl, >> .data_formats = formats_win_full, >> .nformats = ARRAY_SIZE(formats_win_full), >> + .format_modifiers = format_modifiers_win_full, >> .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 0), >> .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 3), >> .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 15), >> @@ -87,6 +104,7 @@ static const struct vop_win_phy rk3036_win0_data = { >> static const struct vop_win_phy rk3036_win1_data = { >> .data_formats = formats_win_lite, >> .nformats = ARRAY_SIZE(formats_win_lite), >> + .format_modifiers = format_modifiers_win_lite, >> .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1), >> .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6), >> .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19), >> @@ -153,6 +171,7 @@ static const struct vop_data rk3036_vop = { >> static const struct vop_win_phy rk3126_win1_data = { >> .data_formats = formats_win_lite, >> .nformats = ARRAY_SIZE(formats_win_lite), >> + .format_modifiers = format_modifiers_win_lite, >> .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1), >> .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6), >> .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19), >> @@ -234,6 +253,7 @@ static const struct vop_win_phy px30_win0_data = { >> .scl = &px30_win_scl, >> .data_formats = formats_win_full, >> .nformats = ARRAY_SIZE(formats_win_full), >> + .format_modifiers = format_modifiers_win_full, >> .enable = VOP_REG(PX30_WIN0_CTRL0, 0x1, 0), >> .format = VOP_REG(PX30_WIN0_CTRL0, 0x7, 1), >> .rb_swap = VOP_REG(PX30_WIN0_CTRL0, 0x1, 12), >> @@ -249,6 +269,7 @@ static const struct vop_win_phy px30_win0_data = { >> static const struct vop_win_phy px30_win1_data = { >> .data_formats = formats_win_lite, >> .nformats = ARRAY_SIZE(formats_win_lite), >> + .format_modifiers = format_modifiers_win_lite, >> .enable = VOP_REG(PX30_WIN1_CTRL0, 0x1, 0), >> .format = VOP_REG(PX30_WIN1_CTRL0, 0x7, 4), >> .rb_swap = VOP_REG(PX30_WIN1_CTRL0, 0x1, 12), >> @@ -261,6 +282,7 @@ static const struct vop_win_phy px30_win1_data = { >> static const struct vop_win_phy px30_win2_data = { >> .data_formats = formats_win_lite, >> .nformats = ARRAY_SIZE(formats_win_lite), >> + .format_modifiers = format_modifiers_win_lite, >> .gate = VOP_REG(PX30_WIN2_CTRL0, 0x1, 4), >> .enable = VOP_REG(PX30_WIN2_CTRL0, 0x1, 0), >> .format = VOP_REG(PX30_WIN2_CTRL0, 0x3, 5), >> @@ -316,6 +338,7 @@ static const struct vop_win_phy rk3066_win0_data = { >> .scl = &rk3066_win_scl, >> .data_formats = formats_win_full, >> .nformats = ARRAY_SIZE(formats_win_full), >> + .format_modifiers = format_modifiers_win_full, >> .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 0), >> .format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 4), >> .rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 19), >> @@ -332,6 +355,7 @@ static const struct vop_win_phy rk3066_win1_data = { >> .scl = &rk3066_win_scl, >> .data_formats = formats_win_full, >> .nformats = ARRAY_SIZE(formats_win_full), >> + .format_modifiers = format_modifiers_win_full, >> .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 1), >> .format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 7), >> .rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 23), >> @@ -347,6 +371,7 @@ static const struct vop_win_phy rk3066_win1_data = { >> static const struct vop_win_phy rk3066_win2_data = { >> .data_formats = formats_win_lite, >> .nformats = ARRAY_SIZE(formats_win_lite), >> + .format_modifiers = format_modifiers_win_lite, >> .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 2), >> .format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 10), >> .rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 27), >> @@ -426,6 +451,7 @@ static const struct vop_win_phy rk3188_win0_data = { >> .scl = &rk3188_win_scl, >> .data_formats = formats_win_full, >> .nformats = ARRAY_SIZE(formats_win_full), >> + .format_modifiers = format_modifiers_win_full, >> .enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 0), >> .format = VOP_REG(RK3188_SYS_CTRL, 0x7, 3), >> .rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 15), >> @@ -440,6 +466,7 @@ static const struct vop_win_phy rk3188_win0_data = { >> static const struct vop_win_phy rk3188_win1_data = { >> .data_formats = formats_win_lite, >> .nformats = ARRAY_SIZE(formats_win_lite), >> + .format_modifiers = format_modifiers_win_lite, >> .enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 1), >> .format = VOP_REG(RK3188_SYS_CTRL, 0x7, 6), >> .rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 19), >> @@ -545,6 +572,7 @@ static const struct vop_win_phy rk3288_win01_data = { >> .scl = &rk3288_win_full_scl, >> .data_formats = formats_win_full, >> .nformats = ARRAY_SIZE(formats_win_full), >> + .format_modifiers = format_modifiers_win_full, >> .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), >> .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), >> .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), >> @@ -563,6 +591,7 @@ static const struct vop_win_phy rk3288_win01_data = { >> static const struct vop_win_phy rk3288_win23_data = { >> .data_formats = formats_win_lite, >> .nformats = ARRAY_SIZE(formats_win_lite), >> + .format_modifiers = format_modifiers_win_lite, >> .enable = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 4), >> .gate = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 0), >> .format = VOP_REG(RK3288_WIN2_CTRL0, 0x7, 1), >> @@ -677,6 +706,7 @@ static const struct vop_win_phy rk3368_win01_data = { >> .scl = &rk3288_win_full_scl, >> .data_formats = formats_win_full, >> .nformats = ARRAY_SIZE(formats_win_full), >> + .format_modifiers = format_modifiers_win_full, >> .enable = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 0), >> .format = VOP_REG(RK3368_WIN0_CTRL0, 0x7, 1), >> .rb_swap = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 12), >> @@ -697,6 +727,7 @@ static const struct vop_win_phy rk3368_win01_data = { >> static const struct vop_win_phy rk3368_win23_data = { >> .data_formats = formats_win_lite, >> .nformats = ARRAY_SIZE(formats_win_lite), >> + .format_modifiers = format_modifiers_win_lite, >> .gate = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 0), >> .enable = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 4), >> .format = VOP_REG(RK3368_WIN2_CTRL0, 0x3, 5), >> @@ -817,6 +848,53 @@ static const struct vop_win_yuv2yuv_data rk3399_vop_big_win_yuv2yuv_data[] = { >> .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 9) }, >> { .base = 0xC0, .phy = &rk3399_yuv2yuv_win23_data }, >> { .base = 0x120, .phy = &rk3399_yuv2yuv_win23_data }, >> + >> +}; >> + >> +static const struct vop_win_phy rk3399_win01_data = { >> + .scl = &rk3288_win_full_scl, >> + .data_formats = formats_win_full, >> + .nformats = ARRAY_SIZE(formats_win_full), >> + .format_modifiers = format_modifiers_win_full_afbc, >> + .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), >> + .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), >> + .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), >> + .y_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 22), >> + .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0), >> + .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0), >> + .dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0), >> + .yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0), >> + .uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0), >> + .yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0), >> + .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16), >> + .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0), >> + .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0), >> +}; >> + >> +/* >> + * rk3399 vop big windows register layout is same as rk3288, but we >> + * have a separate rk3399 win data array here so that we can advertise >> + * AFBC on the primary plane. >> + */ >> +static const struct vop_win_data rk3399_vop_win_data[] = { >> + { .base = 0x00, .phy = &rk3399_win01_data, >> + .type = DRM_PLANE_TYPE_PRIMARY }, >> + { .base = 0x40, .phy = &rk3288_win01_data, >> + .type = DRM_PLANE_TYPE_OVERLAY }, >> + { .base = 0x00, .phy = &rk3288_win23_data, >> + .type = DRM_PLANE_TYPE_OVERLAY }, >> + { .base = 0x50, .phy = &rk3288_win23_data, >> + .type = DRM_PLANE_TYPE_CURSOR }, >> +}; >> + >> +static const struct vop_afbc rk3399_vop_afbc = { >> + .rstn = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 3), >> + .enable = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 0), >> + .win_sel = VOP_REG(RK3399_AFBCD0_CTRL, 0x3, 1), >> + .format = VOP_REG(RK3399_AFBCD0_CTRL, 0x1f, 16), >> + .hreg_block_split = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 21), >> + .hdr_ptr = VOP_REG(RK3399_AFBCD0_HDR_PTR, 0xffffffff, 0), >> + .pic_size = VOP_REG(RK3399_AFBCD0_PIC_SIZE, 0xffffffff, 0), >> }; >> >> static const struct vop_data rk3399_vop_big = { >> @@ -826,9 +904,10 @@ static const struct vop_data rk3399_vop_big = { >> .common = &rk3288_common, >> .modeset = &rk3288_modeset, >> .output = &rk3399_output, >> + .afbc = &rk3399_vop_afbc, >> .misc = &rk3368_misc, >> - .win = rk3368_vop_win_data, >> - .win_size = ARRAY_SIZE(rk3368_vop_win_data), >> + .win = rk3399_vop_win_data, >> + .win_size = ARRAY_SIZE(rk3399_vop_win_data), >> .win_yuv2yuv = rk3399_vop_big_win_yuv2yuv_data, >> }; >> >> -- >> 2.17.1 > Heiko, Sandy, being the maintainers of the Rockchip driver, can you > review/ack this patch? > > I believe the intention is to merge the series via drm-misc. Andrzej > already has commit access. > > -Emil > > Thanks for you patch, maybe we need to consider the compatibility with px30 platform afbc features,the main difference is: 1. px30 support x offset and y offset display, and the state->src.x1 / state->src.y1 should be alibegned as 16pixel/line; 2.px30 only win1 can support afbdc format;
Hi Sandy, W dniu 19.03.2020 o 03:57, Sandy Huang pisze: > Hi Emil, > <snip> >>> -- >>> 2.17.1 >> Heiko, Sandy, being the maintainers of the Rockchip driver, can you >> review/ack this patch? >> >> I believe the intention is to merge the series via drm-misc. Andrzej >> already has commit access. >> >> -Emil >> >> > Thanks for you patch, maybe we need to consider the compatibility with px30 > platform afbc features,the main difference is: > > 1. px30 support x offset and y offset display, and the state->src.x1 / > state->src.y1 should be alibegned as 16pixel/line; > > 2.px30 only win1 can support afbdc format; > > Actually I sent the patch, Emil kindly forwarded it to you. Unfortunately I don't have px30 hardware, so I can't test. Can we merge the patch as is (if you are ok with the way it is now) and then I will help reviewing the patch adding px30 support on top of it? Regards, Andrzej
Hi Andrzej , 在 2020/3/19 下午5:54, Andrzej Pietrasiewicz 写道: > Hi Sandy, > > > W dniu 19.03.2020 o 03:57, Sandy Huang pisze: >> Hi Emil, >> > > <snip> > >>>> -- >>>> 2.17.1 >>> Heiko, Sandy, being the maintainers of the Rockchip driver, can you >>> review/ack this patch? >>> >>> I believe the intention is to merge the series via drm-misc. Andrzej >>> already has commit access. >>> >>> -Emil >>> >>> >> Thanks for you patch, maybe we need to consider the compatibility >> with px30 platform afbc features,the main difference is: >> >> 1. px30 support x offset and y offset display, and the state->src.x1 >> / state->src.y1 should be alibegned as 16pixel/line; >> >> 2.px30 only win1 can support afbdc format; >> >> > > Actually I sent the patch, Emil kindly forwarded it to you. > > Unfortunately I don't have px30 hardware, so I can't test. Can we > merge the patch as is (if you are ok with the way it is now) and then > I will help reviewing the patch adding px30 support on top of it? > > Regards, > > Andrzej OK, Let's add px30 AFBC support later. Reviewed-by: Sandy Huang <hjc@rock-chips.com> > > >
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index c5b06048124e..e33c2dcd0d4b 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -30,6 +30,7 @@ struct rockchip_crtc_state { int output_mode; int output_bpc; int output_flags; + bool enable_afbc; }; #define to_rockchip_crtc_state(s) \ container_of(s, struct rockchip_crtc_state, base) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index 221e72e71432..9b13c784b347 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -57,8 +57,49 @@ static const struct drm_mode_config_helper_funcs rockchip_mode_config_helpers = .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, }; +static struct drm_framebuffer * +rockchip_fb_create(struct drm_device *dev, struct drm_file *file, + const struct drm_mode_fb_cmd2 *mode_cmd) +{ + struct drm_afbc_framebuffer *afbc_fb; + const struct drm_format_info *info; + int ret; + + info = drm_get_format_info(dev, mode_cmd); + if (!info) + return ERR_PTR(-ENOMEM); + + afbc_fb = kzalloc(sizeof(*afbc_fb), GFP_KERNEL); + if (!afbc_fb) + return ERR_PTR(-ENOMEM); + + ret = drm_gem_fb_init_with_funcs(dev, &afbc_fb->base, file, mode_cmd, + &rockchip_drm_fb_funcs); + if (ret) { + kfree(afbc_fb); + return ERR_PTR(ret); + } + + if (drm_is_afbc(mode_cmd->modifier[0])) { + int ret, i; + + ret = drm_gem_fb_afbc_init(dev, mode_cmd, afbc_fb); + if (ret) { + struct drm_gem_object **obj = afbc_fb->base.obj; + + for (i = 0; i < info->num_planes; ++i) + drm_gem_object_put_unlocked(obj[i]); + + kfree(afbc_fb); + return ERR_PTR(ret); + } + } + + return &afbc_fb->base; +} + static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = { - .fb_create = drm_gem_fb_create_with_dirty, + .fb_create = rockchip_fb_create, .output_poll_changed = drm_fb_helper_output_poll_changed, .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index cecb2cc781f5..b87d22eb6ae1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -91,9 +91,22 @@ #define VOP_WIN_TO_INDEX(vop_win) \ ((vop_win) - (vop_win)->vop->win) +#define VOP_AFBC_SET(vop, name, v) \ + do { \ + if ((vop)->data->afbc) \ + vop_reg_set((vop), &(vop)->data->afbc->name, \ + 0, ~0, v, #name); \ + } while (0) + #define to_vop(x) container_of(x, struct vop, crtc) #define to_vop_win(x) container_of(x, struct vop_win, base) +#define AFBC_FMT_RGB565 0x0 +#define AFBC_FMT_U8U8U8U8 0x5 +#define AFBC_FMT_U8U8U8 0x4 + +#define AFBC_TILE_16x16 BIT(4) + /* * The coefficients of the following matrix are all fixed points. * The format is S2.10 for the 3x3 part of the matrix, and S9.12 for the offsets. @@ -274,6 +287,29 @@ static enum vop_data_format vop_convert_format(uint32_t format) } } +static int vop_convert_afbc_format(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + return AFBC_FMT_U8U8U8U8; + case DRM_FORMAT_RGB888: + case DRM_FORMAT_BGR888: + return AFBC_FMT_U8U8U8; + case DRM_FORMAT_RGB565: + case DRM_FORMAT_BGR565: + return AFBC_FMT_RGB565; + /* either of the below should not be reachable */ + default: + DRM_WARN_ONCE("unsupported AFBC format[%08x]\n", format); + return -EINVAL; + } + + return -EINVAL; +} + static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src, uint32_t dst, bool is_horizontal, int vsu_mode, int *vskiplines) @@ -598,6 +634,17 @@ static int vop_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) vop_win_disable(vop, vop_win); } } + + if (vop->data->afbc) { + struct rockchip_crtc_state *s; + /* + * Disable AFBC and forget there was a vop window with AFBC + */ + VOP_AFBC_SET(vop, enable, 0); + s = to_rockchip_crtc_state(crtc->state); + s->enable_afbc = false; + } + spin_unlock(&vop->reg_lock); vop_cfg_done(vop); @@ -710,6 +757,26 @@ static void vop_plane_destroy(struct drm_plane *plane) drm_plane_cleanup(plane); } +static inline bool rockchip_afbc(u64 modifier) +{ + return modifier == ROCKCHIP_AFBC_MOD; +} + +static bool rockchip_mod_supported(struct drm_plane *plane, + u32 format, u64 modifier) +{ + if (modifier == DRM_FORMAT_MOD_LINEAR) + return true; + + if (!rockchip_afbc(modifier)) { + DRM_DEBUG_KMS("Unsupported format modifer 0x%llx\n", modifier); + + return false; + } + + return vop_convert_afbc_format(format) >= 0; +} + static int vop_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { @@ -758,6 +825,30 @@ static int vop_plane_atomic_check(struct drm_plane *plane, return -EINVAL; } + if (rockchip_afbc(fb->modifier)) { + struct vop *vop = to_vop(crtc); + + if (!vop->data->afbc) { + DRM_ERROR("vop does not support AFBC\n"); + return -EINVAL; + } + + ret = vop_convert_afbc_format(fb->format->format); + if (ret < 0) + return ret; + + if (state->src.x1 || state->src.y1) { + DRM_ERROR("AFBC does not support offset display, xpos=%d, ypos=%d, offset=%d\n", state->src.x1, state->src.y1, fb->offsets[0]); + return -EINVAL; + } + + if (state->rotation && state->rotation != DRM_MODE_ROTATE_0) { + DRM_ERROR("No rotation support in AFBC, rotation=%d\n", + state->rotation); + return -EINVAL; + } + } + return 0; } @@ -846,6 +937,16 @@ static void vop_plane_atomic_update(struct drm_plane *plane, spin_lock(&vop->reg_lock); + if (rockchip_afbc(fb->modifier)) { + int afbc_format = vop_convert_afbc_format(fb->format->format); + + VOP_AFBC_SET(vop, format, afbc_format | AFBC_TILE_16x16); + VOP_AFBC_SET(vop, hreg_block_split, 0); + VOP_AFBC_SET(vop, win_sel, VOP_WIN_TO_INDEX(vop_win)); + VOP_AFBC_SET(vop, hdr_ptr, dma_addr); + VOP_AFBC_SET(vop, pic_size, act_info); + } + VOP_WIN_SET(vop, win, format, format); VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4)); VOP_WIN_SET(vop, win, yrgb_mst, dma_addr); @@ -1001,6 +1102,7 @@ static const struct drm_plane_funcs vop_plane_funcs = { .reset = drm_atomic_helper_plane_reset, .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, + .format_mod_supported = rockchip_mod_supported, }; static int vop_crtc_enable_vblank(struct drm_crtc *crtc) @@ -1310,6 +1412,10 @@ static int vop_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state) { struct vop *vop = to_vop(crtc); + struct drm_plane *plane; + struct drm_plane_state *plane_state; + struct rockchip_crtc_state *s; + int afbc_planes = 0; if (vop->lut_regs && crtc_state->color_mgmt_changed && crtc_state->gamma_lut) { @@ -1323,6 +1429,27 @@ static int vop_crtc_atomic_check(struct drm_crtc *crtc, } } + drm_atomic_crtc_state_for_each_plane(plane, crtc_state) { + plane_state = + drm_atomic_get_plane_state(crtc_state->state, plane); + if (IS_ERR(plane_state)) { + DRM_DEBUG_KMS("Cannot get plane state for plane %s\n", + plane->name); + return PTR_ERR(plane_state); + } + + if (drm_is_afbc(plane_state->fb->modifier)) + ++afbc_planes; + } + + if (afbc_planes > 1) { + DRM_DEBUG_KMS("Invalid number of AFBC planes; got %d, expected at most 1\n", afbc_planes); + return -EINVAL; + } + + s = to_rockchip_crtc_state(crtc_state); + s->enable_afbc = afbc_planes > 0; + return 0; } @@ -1333,6 +1460,7 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_plane_state *old_plane_state, *new_plane_state; struct vop *vop = to_vop(crtc); struct drm_plane *plane; + struct rockchip_crtc_state *s; int i; if (WARN_ON(!vop->is_enabled)) @@ -1340,6 +1468,9 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc, spin_lock(&vop->reg_lock); + /* Enable AFBC if there is some AFBC window, disable otherwise. */ + s = to_rockchip_crtc_state(crtc->state); + VOP_AFBC_SET(vop, enable, s->enable_afbc); vop_cfg_done(vop); spin_unlock(&vop->reg_lock); @@ -1634,7 +1765,8 @@ static int vop_create_crtc(struct vop *vop) 0, &vop_plane_funcs, win_data->phy->data_formats, win_data->phy->nformats, - NULL, win_data->type, NULL); + win_data->phy->format_modifiers, + win_data->type, NULL); if (ret) { DRM_DEV_ERROR(vop->dev, "failed to init plane %d\n", ret); @@ -1678,7 +1810,8 @@ static int vop_create_crtc(struct vop *vop) &vop_plane_funcs, win_data->phy->data_formats, win_data->phy->nformats, - NULL, win_data->type, NULL); + win_data->phy->format_modifiers, + win_data->type, NULL); if (ret) { DRM_DEV_ERROR(vop->dev, "failed to init overlay %d\n", ret); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index cc672620d6e0..d03bdb531ef2 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -17,6 +17,11 @@ #define NUM_YUV2YUV_COEFFICIENTS 12 +#define ROCKCHIP_AFBC_MOD \ + DRM_FORMAT_MOD_ARM_AFBC( \ + AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | AFBC_FORMAT_MOD_SPARSE \ + ) + enum vop_data_format { VOP_FMT_ARGB8888 = 0, VOP_FMT_RGB888, @@ -34,6 +39,16 @@ struct vop_reg { bool relaxed; }; +struct vop_afbc { + struct vop_reg enable; + struct vop_reg win_sel; + struct vop_reg format; + struct vop_reg hreg_block_split; + struct vop_reg pic_size; + struct vop_reg hdr_ptr; + struct vop_reg rstn; +}; + struct vop_modeset { struct vop_reg htotal_pw; struct vop_reg hact_st_end; @@ -134,6 +149,7 @@ struct vop_win_phy { const struct vop_scl_regs *scl; const uint32_t *data_formats; uint32_t nformats; + const uint64_t *format_modifiers; struct vop_reg enable; struct vop_reg gate; @@ -173,6 +189,7 @@ struct vop_data { const struct vop_misc *misc; const struct vop_modeset *modeset; const struct vop_output *output; + const struct vop_afbc *afbc; const struct vop_win_yuv2yuv_data *win_yuv2yuv; const struct vop_win_data *win; unsigned int win_size; diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 7a9d979c8d5d..2413deded22c 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -50,6 +50,17 @@ static const uint32_t formats_win_full[] = { DRM_FORMAT_NV24, }; +static const uint64_t format_modifiers_win_full[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID, +}; + +static const uint64_t format_modifiers_win_full_afbc[] = { + ROCKCHIP_AFBC_MOD, + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID, +}; + static const uint32_t formats_win_lite[] = { DRM_FORMAT_XRGB8888, DRM_FORMAT_ARGB8888, @@ -61,6 +72,11 @@ static const uint32_t formats_win_lite[] = { DRM_FORMAT_BGR565, }; +static const uint64_t format_modifiers_win_lite[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID, +}; + static const struct vop_scl_regs rk3036_win_scl = { .scale_yrgb_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), .scale_yrgb_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 16), @@ -72,6 +88,7 @@ static const struct vop_win_phy rk3036_win0_data = { .scl = &rk3036_win_scl, .data_formats = formats_win_full, .nformats = ARRAY_SIZE(formats_win_full), + .format_modifiers = format_modifiers_win_full, .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 0), .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 3), .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 15), @@ -87,6 +104,7 @@ static const struct vop_win_phy rk3036_win0_data = { static const struct vop_win_phy rk3036_win1_data = { .data_formats = formats_win_lite, .nformats = ARRAY_SIZE(formats_win_lite), + .format_modifiers = format_modifiers_win_lite, .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1), .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6), .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19), @@ -153,6 +171,7 @@ static const struct vop_data rk3036_vop = { static const struct vop_win_phy rk3126_win1_data = { .data_formats = formats_win_lite, .nformats = ARRAY_SIZE(formats_win_lite), + .format_modifiers = format_modifiers_win_lite, .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1), .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6), .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19), @@ -234,6 +253,7 @@ static const struct vop_win_phy px30_win0_data = { .scl = &px30_win_scl, .data_formats = formats_win_full, .nformats = ARRAY_SIZE(formats_win_full), + .format_modifiers = format_modifiers_win_full, .enable = VOP_REG(PX30_WIN0_CTRL0, 0x1, 0), .format = VOP_REG(PX30_WIN0_CTRL0, 0x7, 1), .rb_swap = VOP_REG(PX30_WIN0_CTRL0, 0x1, 12), @@ -249,6 +269,7 @@ static const struct vop_win_phy px30_win0_data = { static const struct vop_win_phy px30_win1_data = { .data_formats = formats_win_lite, .nformats = ARRAY_SIZE(formats_win_lite), + .format_modifiers = format_modifiers_win_lite, .enable = VOP_REG(PX30_WIN1_CTRL0, 0x1, 0), .format = VOP_REG(PX30_WIN1_CTRL0, 0x7, 4), .rb_swap = VOP_REG(PX30_WIN1_CTRL0, 0x1, 12), @@ -261,6 +282,7 @@ static const struct vop_win_phy px30_win1_data = { static const struct vop_win_phy px30_win2_data = { .data_formats = formats_win_lite, .nformats = ARRAY_SIZE(formats_win_lite), + .format_modifiers = format_modifiers_win_lite, .gate = VOP_REG(PX30_WIN2_CTRL0, 0x1, 4), .enable = VOP_REG(PX30_WIN2_CTRL0, 0x1, 0), .format = VOP_REG(PX30_WIN2_CTRL0, 0x3, 5), @@ -316,6 +338,7 @@ static const struct vop_win_phy rk3066_win0_data = { .scl = &rk3066_win_scl, .data_formats = formats_win_full, .nformats = ARRAY_SIZE(formats_win_full), + .format_modifiers = format_modifiers_win_full, .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 0), .format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 4), .rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 19), @@ -332,6 +355,7 @@ static const struct vop_win_phy rk3066_win1_data = { .scl = &rk3066_win_scl, .data_formats = formats_win_full, .nformats = ARRAY_SIZE(formats_win_full), + .format_modifiers = format_modifiers_win_full, .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 1), .format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 7), .rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 23), @@ -347,6 +371,7 @@ static const struct vop_win_phy rk3066_win1_data = { static const struct vop_win_phy rk3066_win2_data = { .data_formats = formats_win_lite, .nformats = ARRAY_SIZE(formats_win_lite), + .format_modifiers = format_modifiers_win_lite, .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 2), .format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 10), .rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 27), @@ -426,6 +451,7 @@ static const struct vop_win_phy rk3188_win0_data = { .scl = &rk3188_win_scl, .data_formats = formats_win_full, .nformats = ARRAY_SIZE(formats_win_full), + .format_modifiers = format_modifiers_win_full, .enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 0), .format = VOP_REG(RK3188_SYS_CTRL, 0x7, 3), .rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 15), @@ -440,6 +466,7 @@ static const struct vop_win_phy rk3188_win0_data = { static const struct vop_win_phy rk3188_win1_data = { .data_formats = formats_win_lite, .nformats = ARRAY_SIZE(formats_win_lite), + .format_modifiers = format_modifiers_win_lite, .enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 1), .format = VOP_REG(RK3188_SYS_CTRL, 0x7, 6), .rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 19), @@ -545,6 +572,7 @@ static const struct vop_win_phy rk3288_win01_data = { .scl = &rk3288_win_full_scl, .data_formats = formats_win_full, .nformats = ARRAY_SIZE(formats_win_full), + .format_modifiers = format_modifiers_win_full, .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), @@ -563,6 +591,7 @@ static const struct vop_win_phy rk3288_win01_data = { static const struct vop_win_phy rk3288_win23_data = { .data_formats = formats_win_lite, .nformats = ARRAY_SIZE(formats_win_lite), + .format_modifiers = format_modifiers_win_lite, .enable = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 4), .gate = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 0), .format = VOP_REG(RK3288_WIN2_CTRL0, 0x7, 1), @@ -677,6 +706,7 @@ static const struct vop_win_phy rk3368_win01_data = { .scl = &rk3288_win_full_scl, .data_formats = formats_win_full, .nformats = ARRAY_SIZE(formats_win_full), + .format_modifiers = format_modifiers_win_full, .enable = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 0), .format = VOP_REG(RK3368_WIN0_CTRL0, 0x7, 1), .rb_swap = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 12), @@ -697,6 +727,7 @@ static const struct vop_win_phy rk3368_win01_data = { static const struct vop_win_phy rk3368_win23_data = { .data_formats = formats_win_lite, .nformats = ARRAY_SIZE(formats_win_lite), + .format_modifiers = format_modifiers_win_lite, .gate = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 0), .enable = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 4), .format = VOP_REG(RK3368_WIN2_CTRL0, 0x3, 5), @@ -817,6 +848,53 @@ static const struct vop_win_yuv2yuv_data rk3399_vop_big_win_yuv2yuv_data[] = { .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 9) }, { .base = 0xC0, .phy = &rk3399_yuv2yuv_win23_data }, { .base = 0x120, .phy = &rk3399_yuv2yuv_win23_data }, + +}; + +static const struct vop_win_phy rk3399_win01_data = { + .scl = &rk3288_win_full_scl, + .data_formats = formats_win_full, + .nformats = ARRAY_SIZE(formats_win_full), + .format_modifiers = format_modifiers_win_full_afbc, + .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), + .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), + .y_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 22), + .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0), + .uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0), + .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16), + .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0), + .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0), +}; + +/* + * rk3399 vop big windows register layout is same as rk3288, but we + * have a separate rk3399 win data array here so that we can advertise + * AFBC on the primary plane. + */ +static const struct vop_win_data rk3399_vop_win_data[] = { + { .base = 0x00, .phy = &rk3399_win01_data, + .type = DRM_PLANE_TYPE_PRIMARY }, + { .base = 0x40, .phy = &rk3288_win01_data, + .type = DRM_PLANE_TYPE_OVERLAY }, + { .base = 0x00, .phy = &rk3288_win23_data, + .type = DRM_PLANE_TYPE_OVERLAY }, + { .base = 0x50, .phy = &rk3288_win23_data, + .type = DRM_PLANE_TYPE_CURSOR }, +}; + +static const struct vop_afbc rk3399_vop_afbc = { + .rstn = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 3), + .enable = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 0), + .win_sel = VOP_REG(RK3399_AFBCD0_CTRL, 0x3, 1), + .format = VOP_REG(RK3399_AFBCD0_CTRL, 0x1f, 16), + .hreg_block_split = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 21), + .hdr_ptr = VOP_REG(RK3399_AFBCD0_HDR_PTR, 0xffffffff, 0), + .pic_size = VOP_REG(RK3399_AFBCD0_PIC_SIZE, 0xffffffff, 0), }; static const struct vop_data rk3399_vop_big = { @@ -826,9 +904,10 @@ static const struct vop_data rk3399_vop_big = { .common = &rk3288_common, .modeset = &rk3288_modeset, .output = &rk3399_output, + .afbc = &rk3399_vop_afbc, .misc = &rk3368_misc, - .win = rk3368_vop_win_data, - .win_size = ARRAY_SIZE(rk3368_vop_win_data), + .win = rk3399_vop_win_data, + .win_size = ARRAY_SIZE(rk3399_vop_win_data), .win_yuv2yuv = rk3399_vop_big_win_yuv2yuv_data, };