Commit 283d8911 authored by Alyssa Rosenzweig's avatar Alyssa Rosenzweig

drm/rockchip: Support AFBC on RK3399 big VOP

This patch adds preliminary support for hardware decode of Arm
Framebuffer Compression (AFBC) within the Rockchip display driver,
handled by the RK3399's big VOP. Combined with the open source Panfrost
userspace, this allows the on-board Mali GPU to compress framebuffers
in-flight across the chip from the GPU to the display driver, saving
considerable memory bandwidth.

This patch is based on the downstream ChromeOS patch to implement the
same functionality
https://chromium.googlesource.com/chromiumos/third_party/kernel/+/632d97fa4a1847eb489deee5bce6dcc04dd65fef,
originally by Mark Yao with changes by Kristian H. Kristensen
<hoegsberg@chromium.org>. This patch allows the linked code to build
against a mainline kernel, using the standardized AFBC modifiers rather
than a ChromeOS specific modifier.
Signed-off-by: Mark Yao's avatarMark Yao <mark.yao@rock-chips.com>
Signed-off-by: Alyssa Rosenzweig's avatarAlyssa Rosenzweig <alyssa@rosenzweig.io>
parent ed670557
......@@ -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;
}
......@@ -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);
......
......@@ -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;
......
......@@ -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,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment