Skip to content

Commit

Permalink
drm/rockchip: Add support for afbc
Browse files Browse the repository at this point in the history
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>
Reviewed-by: Sandy Huang <hjc@rock-chips.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200311145541.29186-7-andrzej.p@collabora.com
  • Loading branch information
Andrzej Pietrasiewicz committed Mar 23, 2020
1 parent 7f60c4b commit 7707f72
Show file tree
Hide file tree
Showing 5 changed files with 276 additions and 5 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/rockchip/rockchip_drm_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
43 changes: 42 additions & 1 deletion drivers/gpu/drm/rockchip/rockchip_drm_fb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
137 changes: 135 additions & 2 deletions drivers/gpu/drm/rockchip/rockchip_drm_vop.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
}

Expand All @@ -1333,13 +1460,17 @@ 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))
return;

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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
17 changes: 17 additions & 0 deletions drivers/gpu/drm/rockchip/rockchip_drm_vop.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 7707f72

Please sign in to comment.