Skip to content

Commit 7707f72

Browse files
committed
drm/rockchip: Add support for afbc
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
1 parent 7f60c4b commit 7707f72

File tree

5 files changed

+276
-5
lines changed

5 files changed

+276
-5
lines changed

drivers/gpu/drm/rockchip/rockchip_drm_drv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ struct rockchip_crtc_state {
3030
int output_mode;
3131
int output_bpc;
3232
int output_flags;
33+
bool enable_afbc;
3334
};
3435
#define to_rockchip_crtc_state(s) \
3536
container_of(s, struct rockchip_crtc_state, base)

drivers/gpu/drm/rockchip/rockchip_drm_fb.c

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,49 @@ static const struct drm_mode_config_helper_funcs rockchip_mode_config_helpers =
5757
.atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
5858
};
5959

60+
static struct drm_framebuffer *
61+
rockchip_fb_create(struct drm_device *dev, struct drm_file *file,
62+
const struct drm_mode_fb_cmd2 *mode_cmd)
63+
{
64+
struct drm_afbc_framebuffer *afbc_fb;
65+
const struct drm_format_info *info;
66+
int ret;
67+
68+
info = drm_get_format_info(dev, mode_cmd);
69+
if (!info)
70+
return ERR_PTR(-ENOMEM);
71+
72+
afbc_fb = kzalloc(sizeof(*afbc_fb), GFP_KERNEL);
73+
if (!afbc_fb)
74+
return ERR_PTR(-ENOMEM);
75+
76+
ret = drm_gem_fb_init_with_funcs(dev, &afbc_fb->base, file, mode_cmd,
77+
&rockchip_drm_fb_funcs);
78+
if (ret) {
79+
kfree(afbc_fb);
80+
return ERR_PTR(ret);
81+
}
82+
83+
if (drm_is_afbc(mode_cmd->modifier[0])) {
84+
int ret, i;
85+
86+
ret = drm_gem_fb_afbc_init(dev, mode_cmd, afbc_fb);
87+
if (ret) {
88+
struct drm_gem_object **obj = afbc_fb->base.obj;
89+
90+
for (i = 0; i < info->num_planes; ++i)
91+
drm_gem_object_put_unlocked(obj[i]);
92+
93+
kfree(afbc_fb);
94+
return ERR_PTR(ret);
95+
}
96+
}
97+
98+
return &afbc_fb->base;
99+
}
100+
60101
static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
61-
.fb_create = drm_gem_fb_create_with_dirty,
102+
.fb_create = rockchip_fb_create,
62103
.output_poll_changed = drm_fb_helper_output_poll_changed,
63104
.atomic_check = drm_atomic_helper_check,
64105
.atomic_commit = drm_atomic_helper_commit,

drivers/gpu/drm/rockchip/rockchip_drm_vop.c

Lines changed: 135 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,22 @@
9191
#define VOP_WIN_TO_INDEX(vop_win) \
9292
((vop_win) - (vop_win)->vop->win)
9393

94+
#define VOP_AFBC_SET(vop, name, v) \
95+
do { \
96+
if ((vop)->data->afbc) \
97+
vop_reg_set((vop), &(vop)->data->afbc->name, \
98+
0, ~0, v, #name); \
99+
} while (0)
100+
94101
#define to_vop(x) container_of(x, struct vop, crtc)
95102
#define to_vop_win(x) container_of(x, struct vop_win, base)
96103

104+
#define AFBC_FMT_RGB565 0x0
105+
#define AFBC_FMT_U8U8U8U8 0x5
106+
#define AFBC_FMT_U8U8U8 0x4
107+
108+
#define AFBC_TILE_16x16 BIT(4)
109+
97110
/*
98111
* The coefficients of the following matrix are all fixed points.
99112
* 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)
274287
}
275288
}
276289

290+
static int vop_convert_afbc_format(uint32_t format)
291+
{
292+
switch (format) {
293+
case DRM_FORMAT_XRGB8888:
294+
case DRM_FORMAT_ARGB8888:
295+
case DRM_FORMAT_XBGR8888:
296+
case DRM_FORMAT_ABGR8888:
297+
return AFBC_FMT_U8U8U8U8;
298+
case DRM_FORMAT_RGB888:
299+
case DRM_FORMAT_BGR888:
300+
return AFBC_FMT_U8U8U8;
301+
case DRM_FORMAT_RGB565:
302+
case DRM_FORMAT_BGR565:
303+
return AFBC_FMT_RGB565;
304+
/* either of the below should not be reachable */
305+
default:
306+
DRM_WARN_ONCE("unsupported AFBC format[%08x]\n", format);
307+
return -EINVAL;
308+
}
309+
310+
return -EINVAL;
311+
}
312+
277313
static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src,
278314
uint32_t dst, bool is_horizontal,
279315
int vsu_mode, int *vskiplines)
@@ -598,6 +634,17 @@ static int vop_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
598634
vop_win_disable(vop, vop_win);
599635
}
600636
}
637+
638+
if (vop->data->afbc) {
639+
struct rockchip_crtc_state *s;
640+
/*
641+
* Disable AFBC and forget there was a vop window with AFBC
642+
*/
643+
VOP_AFBC_SET(vop, enable, 0);
644+
s = to_rockchip_crtc_state(crtc->state);
645+
s->enable_afbc = false;
646+
}
647+
601648
spin_unlock(&vop->reg_lock);
602649

603650
vop_cfg_done(vop);
@@ -710,6 +757,26 @@ static void vop_plane_destroy(struct drm_plane *plane)
710757
drm_plane_cleanup(plane);
711758
}
712759

760+
static inline bool rockchip_afbc(u64 modifier)
761+
{
762+
return modifier == ROCKCHIP_AFBC_MOD;
763+
}
764+
765+
static bool rockchip_mod_supported(struct drm_plane *plane,
766+
u32 format, u64 modifier)
767+
{
768+
if (modifier == DRM_FORMAT_MOD_LINEAR)
769+
return true;
770+
771+
if (!rockchip_afbc(modifier)) {
772+
DRM_DEBUG_KMS("Unsupported format modifer 0x%llx\n", modifier);
773+
774+
return false;
775+
}
776+
777+
return vop_convert_afbc_format(format) >= 0;
778+
}
779+
713780
static int vop_plane_atomic_check(struct drm_plane *plane,
714781
struct drm_plane_state *state)
715782
{
@@ -758,6 +825,30 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
758825
return -EINVAL;
759826
}
760827

828+
if (rockchip_afbc(fb->modifier)) {
829+
struct vop *vop = to_vop(crtc);
830+
831+
if (!vop->data->afbc) {
832+
DRM_ERROR("vop does not support AFBC\n");
833+
return -EINVAL;
834+
}
835+
836+
ret = vop_convert_afbc_format(fb->format->format);
837+
if (ret < 0)
838+
return ret;
839+
840+
if (state->src.x1 || state->src.y1) {
841+
DRM_ERROR("AFBC does not support offset display, xpos=%d, ypos=%d, offset=%d\n", state->src.x1, state->src.y1, fb->offsets[0]);
842+
return -EINVAL;
843+
}
844+
845+
if (state->rotation && state->rotation != DRM_MODE_ROTATE_0) {
846+
DRM_ERROR("No rotation support in AFBC, rotation=%d\n",
847+
state->rotation);
848+
return -EINVAL;
849+
}
850+
}
851+
761852
return 0;
762853
}
763854

@@ -846,6 +937,16 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
846937

847938
spin_lock(&vop->reg_lock);
848939

940+
if (rockchip_afbc(fb->modifier)) {
941+
int afbc_format = vop_convert_afbc_format(fb->format->format);
942+
943+
VOP_AFBC_SET(vop, format, afbc_format | AFBC_TILE_16x16);
944+
VOP_AFBC_SET(vop, hreg_block_split, 0);
945+
VOP_AFBC_SET(vop, win_sel, VOP_WIN_TO_INDEX(vop_win));
946+
VOP_AFBC_SET(vop, hdr_ptr, dma_addr);
947+
VOP_AFBC_SET(vop, pic_size, act_info);
948+
}
949+
849950
VOP_WIN_SET(vop, win, format, format);
850951
VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4));
851952
VOP_WIN_SET(vop, win, yrgb_mst, dma_addr);
@@ -1001,6 +1102,7 @@ static const struct drm_plane_funcs vop_plane_funcs = {
10011102
.reset = drm_atomic_helper_plane_reset,
10021103
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
10031104
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
1105+
.format_mod_supported = rockchip_mod_supported,
10041106
};
10051107

10061108
static int vop_crtc_enable_vblank(struct drm_crtc *crtc)
@@ -1310,6 +1412,10 @@ static int vop_crtc_atomic_check(struct drm_crtc *crtc,
13101412
struct drm_crtc_state *crtc_state)
13111413
{
13121414
struct vop *vop = to_vop(crtc);
1415+
struct drm_plane *plane;
1416+
struct drm_plane_state *plane_state;
1417+
struct rockchip_crtc_state *s;
1418+
int afbc_planes = 0;
13131419

13141420
if (vop->lut_regs && crtc_state->color_mgmt_changed &&
13151421
crtc_state->gamma_lut) {
@@ -1323,6 +1429,27 @@ static int vop_crtc_atomic_check(struct drm_crtc *crtc,
13231429
}
13241430
}
13251431

1432+
drm_atomic_crtc_state_for_each_plane(plane, crtc_state) {
1433+
plane_state =
1434+
drm_atomic_get_plane_state(crtc_state->state, plane);
1435+
if (IS_ERR(plane_state)) {
1436+
DRM_DEBUG_KMS("Cannot get plane state for plane %s\n",
1437+
plane->name);
1438+
return PTR_ERR(plane_state);
1439+
}
1440+
1441+
if (drm_is_afbc(plane_state->fb->modifier))
1442+
++afbc_planes;
1443+
}
1444+
1445+
if (afbc_planes > 1) {
1446+
DRM_DEBUG_KMS("Invalid number of AFBC planes; got %d, expected at most 1\n", afbc_planes);
1447+
return -EINVAL;
1448+
}
1449+
1450+
s = to_rockchip_crtc_state(crtc_state);
1451+
s->enable_afbc = afbc_planes > 0;
1452+
13261453
return 0;
13271454
}
13281455

@@ -1333,13 +1460,17 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
13331460
struct drm_plane_state *old_plane_state, *new_plane_state;
13341461
struct vop *vop = to_vop(crtc);
13351462
struct drm_plane *plane;
1463+
struct rockchip_crtc_state *s;
13361464
int i;
13371465

13381466
if (WARN_ON(!vop->is_enabled))
13391467
return;
13401468

13411469
spin_lock(&vop->reg_lock);
13421470

1471+
/* Enable AFBC if there is some AFBC window, disable otherwise. */
1472+
s = to_rockchip_crtc_state(crtc->state);
1473+
VOP_AFBC_SET(vop, enable, s->enable_afbc);
13431474
vop_cfg_done(vop);
13441475

13451476
spin_unlock(&vop->reg_lock);
@@ -1634,7 +1765,8 @@ static int vop_create_crtc(struct vop *vop)
16341765
0, &vop_plane_funcs,
16351766
win_data->phy->data_formats,
16361767
win_data->phy->nformats,
1637-
NULL, win_data->type, NULL);
1768+
win_data->phy->format_modifiers,
1769+
win_data->type, NULL);
16381770
if (ret) {
16391771
DRM_DEV_ERROR(vop->dev, "failed to init plane %d\n",
16401772
ret);
@@ -1678,7 +1810,8 @@ static int vop_create_crtc(struct vop *vop)
16781810
&vop_plane_funcs,
16791811
win_data->phy->data_formats,
16801812
win_data->phy->nformats,
1681-
NULL, win_data->type, NULL);
1813+
win_data->phy->format_modifiers,
1814+
win_data->type, NULL);
16821815
if (ret) {
16831816
DRM_DEV_ERROR(vop->dev, "failed to init overlay %d\n",
16841817
ret);

drivers/gpu/drm/rockchip/rockchip_drm_vop.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@
1717

1818
#define NUM_YUV2YUV_COEFFICIENTS 12
1919

20+
#define ROCKCHIP_AFBC_MOD \
21+
DRM_FORMAT_MOD_ARM_AFBC( \
22+
AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | AFBC_FORMAT_MOD_SPARSE \
23+
)
24+
2025
enum vop_data_format {
2126
VOP_FMT_ARGB8888 = 0,
2227
VOP_FMT_RGB888,
@@ -34,6 +39,16 @@ struct vop_reg {
3439
bool relaxed;
3540
};
3641

42+
struct vop_afbc {
43+
struct vop_reg enable;
44+
struct vop_reg win_sel;
45+
struct vop_reg format;
46+
struct vop_reg hreg_block_split;
47+
struct vop_reg pic_size;
48+
struct vop_reg hdr_ptr;
49+
struct vop_reg rstn;
50+
};
51+
3752
struct vop_modeset {
3853
struct vop_reg htotal_pw;
3954
struct vop_reg hact_st_end;
@@ -134,6 +149,7 @@ struct vop_win_phy {
134149
const struct vop_scl_regs *scl;
135150
const uint32_t *data_formats;
136151
uint32_t nformats;
152+
const uint64_t *format_modifiers;
137153

138154
struct vop_reg enable;
139155
struct vop_reg gate;
@@ -173,6 +189,7 @@ struct vop_data {
173189
const struct vop_misc *misc;
174190
const struct vop_modeset *modeset;
175191
const struct vop_output *output;
192+
const struct vop_afbc *afbc;
176193
const struct vop_win_yuv2yuv_data *win_yuv2yuv;
177194
const struct vop_win_data *win;
178195
unsigned int win_size;

0 commit comments

Comments
 (0)