diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index 97438bbbe3892c5b231df6e457b66509e225f7dc..2705b979ff5dd025c6e77fb33e524032c45df577 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -188,6 +188,8 @@ void rockchip_drm_mode_config_init(struct drm_device *dev) dev->mode_config.max_width = 4096; dev->mode_config.max_height = 4096; + dev->mode_config.allow_fb_modifiers = true; + dev->mode_config.funcs = &rockchip_drm_mode_config_funcs; dev->mode_config.helper_private = &rockchip_mode_config_helpers; } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index c7d4c6073ea59b70c56559288def3fb7fd6fe215..e91b3f1882eb07589ac93ed13f6d2a00e2fded27 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -66,6 +66,12 @@ vop_reg_set(vop, &win_yuv2yuv->phy->name, win_yuv2yuv->base, ~0, v, #name); \ } while (0) +#define VOP_AFBDC_SET(vop, name, v) \ + do { \ + if (vop->data->afbdc) \ + vop_reg_set(vop, &vop->data->afbdc->name, 0, ~0, v, #name); \ + } while(0) + #define VOP_INTR_SET_MASK(vop, name, mask, v) \ vop_reg_set(vop, &vop->data->intr->name, 0, mask, v, #name) @@ -131,6 +137,8 @@ struct vop { struct drm_device *drm_dev; bool is_enabled; + struct vop_win *afbdc_win; + struct completion dsp_hold_completion; /* protected by dev->event_lock */ @@ -235,6 +243,11 @@ static inline uint32_t vop_get_intr_type(struct vop *vop, return ret; } +static int vop_win_id(struct vop *vop, struct vop_win *win) +{ + return (win - vop->win) / sizeof(struct vop_win); +} + static inline void vop_cfg_done(struct vop *vop) { VOP_REG_SET(vop, common, cfg_done, 1); @@ -279,6 +292,26 @@ static enum vop_data_format vop_convert_format(uint32_t format) } } +static enum vop_afbc_format 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 VOP_AFBC_RGBA8888; + case DRM_FORMAT_RGB888: + case DRM_FORMAT_BGR888: + return VOP_AFBC_RGB888; + case DRM_FORMAT_RGB565: + case DRM_FORMAT_BGR565: + return VOP_AFBC_RGB565; + default: + DRM_ERROR("unsupported AFBC format[%08x]\n", format); + 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) @@ -626,6 +659,9 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc, mutex_lock(&vop->vop_lock); drm_crtc_vblank_off(crtc); + if (vop->data->afbdc) + VOP_AFBDC_SET(vop, enable, 0); + /* * Vop standby will take effect at end of current frame, * if dsp hold valid irq happen, it means standby complete. @@ -720,6 +756,33 @@ static int vop_plane_atomic_check(struct drm_plane *plane, return -EINVAL; } + /* If AFBC is enabled, some additional restrictions are imposed */ + + if (fb->modifier & DRM_FORMAT_MOD_ARM_AFBC(0)) { + struct vop *vop = to_vop(crtc); + unsigned width = state->src_w >> 16; + unsigned height = state->src_h >> 16; + + if (!vop->data->afbdc) { + DRM_ERROR("VOP does not support AFBDC\n"); + return -EINVAL; + } + + if (state->src.x1 || state->src.y1) { + DRM_ERROR("AFBDC does not support display offsets\n"); + return -EINVAL; + } + + if ((width > 2560) || (height > 1600)) { + DRM_ERROR("AFBC framebuffer too big for decoder\n"); + return -EINVAL; + } + + ret = vop_convert_afbc_format(fb->format->format); + if (ret < 0) + return ret; + } + return 0; } @@ -735,6 +798,9 @@ static void vop_plane_atomic_disable(struct drm_plane *plane, spin_lock(&vop->reg_lock); + if (vop->afbdc_win == vop_win) + vop->afbdc_win = NULL; + VOP_WIN_SET(vop, win, enable, 0); spin_unlock(&vop->reg_lock); @@ -775,6 +841,9 @@ static void vop_plane_atomic_update(struct drm_plane *plane, if (WARN_ON(!vop->is_enabled)) return; + if (vop->afbdc_win == vop_win) + vop->afbdc_win = NULL; + if (!state->visible) { vop_plane_atomic_disable(plane, old_state); return; @@ -809,6 +878,19 @@ static void vop_plane_atomic_update(struct drm_plane *plane, spin_lock(&vop->reg_lock); + if (fb->modifier & DRM_FORMAT_MOD_ARM_AFBC(0)) { + enum vop_afbc_format afbc_format = + vop_convert_afbc_format(fb->format->format); + + VOP_AFBDC_SET(vop, format, afbc_format | (1 << 4)); + VOP_AFBDC_SET(vop, hreg_block_split, 0); + VOP_AFBDC_SET(vop, win_sel, vop_win_id(vop, vop_win)); + VOP_AFBDC_SET(vop, hdr_ptr, dma_addr); + VOP_AFBDC_SET(vop, pic_size, act_info); + + vop->afbdc_win = vop_win; + } + 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); @@ -1153,6 +1235,8 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc, spin_lock(&vop->reg_lock); + VOP_AFBDC_SET(vop, enable, vop->afbdc_win != NULL); + vop_cfg_done(vop); spin_unlock(&vop->reg_lock); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 04ed401d2325e6288225aed9a6bbdba37f2c447d..6b7f8776c46f2815effb161bb303140e48d6cce0 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -34,6 +34,12 @@ enum vop_data_format { VOP_FMT_YUV444SP, }; +enum vop_afbc_format { + VOP_AFBC_RGB565 = 0, + VOP_AFBC_RGB888 = 4, + VOP_AFBC_RGBA8888 = 5, +}; + struct vop_reg { uint32_t mask; uint16_t offset; @@ -66,6 +72,16 @@ struct vop_output { struct vop_reg rgb_en; }; +struct vop_afbdc { + 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_common { struct vop_reg cfg_done; struct vop_reg dsp_blank; @@ -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_afbdc *afbdc; 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 bd76328c0fdb5f378ac5b2e91f7f7867db24fdcc..24daf01651c32085689781470c0ab27196eaeb2e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -795,6 +795,16 @@ static const struct vop_win_yuv2yuv_data rk3399_vop_big_win_yuv2yuv_data[] = { { .base = 0x120, .phy = &rk3399_yuv2yuv_win23_data }, }; +static const struct vop_afbdc rk3399_vop_afbdc = { + .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 = { .version = VOP_VERSION(3, 5), .feature = VOP_FEATURE_OUTPUT_RGB10, @@ -803,6 +813,7 @@ static const struct vop_data rk3399_vop_big = { .modeset = &rk3288_modeset, .output = &rk3399_output, .misc = &rk3368_misc, + .afbdc = &rk3399_vop_afbdc, .win = rk3368_vop_win_data, .win_size = ARRAY_SIZE(rk3368_vop_win_data), .win_yuv2yuv = rk3399_vop_big_win_yuv2yuv_data,