Skip to content

Commit ddc389f

Browse files
committed
drm/sun4i: backend: Support YUV planes
Now that we have the guarantee that we will have only a single YUV plane, actually support them. The way it works is not really straightforward, since we first need to enable the YUV mode in the plane that we want to setup, and then we have a few registers to setup the YUV buffer and parameters. We also need to setup the color correction to actually have something displayed. Reviewed-by: Chen-Yu Tsai <[email protected]> Signed-off-by: Maxime Ripard <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/66088c1398bd3189123f28a89a7ccc669fe9f296.1519931807.git-series.maxime.ripard@bootlin.com
1 parent 3246355 commit ddc389f

File tree

3 files changed

+119
-0
lines changed

3 files changed

+119
-0
lines changed

drivers/gpu/drm/sun4i/sun4i_backend.c

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,24 @@ static const u32 sunxi_rgb2yuv_coef[12] = {
4242
0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
4343
};
4444

45+
/*
46+
* These coefficients are taken from the A33 BSP from Allwinner.
47+
*
48+
* The formula is for each component, each coefficient being multiplied by
49+
* 1024 and each constant being multiplied by 16:
50+
* G = 1.164 * Y - 0.391 * U - 0.813 * V + 135
51+
* R = 1.164 * Y + 1.596 * V - 222
52+
* B = 1.164 * Y + 2.018 * U + 276
53+
*
54+
* This seems to be a conversion from Y[16:235] UV[16:240] to RGB[0:255],
55+
* following the BT601 spec.
56+
*/
57+
static const u32 sunxi_bt601_yuv2rgb_coef[12] = {
58+
0x000004a7, 0x00001e6f, 0x00001cbf, 0x00000877,
59+
0x000004a7, 0x00000000, 0x00000662, 0x00003211,
60+
0x000004a7, 0x00000812, 0x00000000, 0x00002eb1,
61+
};
62+
4563
static inline bool sun4i_backend_format_is_planar_yuv(uint32_t format)
4664
{
4765
switch (format) {
@@ -198,6 +216,61 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
198216
return 0;
199217
}
200218

219+
static int sun4i_backend_update_yuv_format(struct sun4i_backend *backend,
220+
int layer, struct drm_plane *plane)
221+
{
222+
struct drm_plane_state *state = plane->state;
223+
struct drm_framebuffer *fb = state->fb;
224+
uint32_t format = fb->format->format;
225+
u32 val = SUN4I_BACKEND_IYUVCTL_EN;
226+
int i;
227+
228+
for (i = 0; i < ARRAY_SIZE(sunxi_bt601_yuv2rgb_coef); i++)
229+
regmap_write(backend->engine.regs,
230+
SUN4I_BACKEND_YGCOEF_REG(i),
231+
sunxi_bt601_yuv2rgb_coef[i]);
232+
233+
/*
234+
* We should do that only for a single plane, but the
235+
* framebuffer's atomic_check has our back on this.
236+
*/
237+
regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_ATTCTL_REG0(layer),
238+
SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN,
239+
SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN);
240+
241+
/* TODO: Add support for the multi-planar YUV formats */
242+
if (sun4i_backend_format_is_packed_yuv422(format))
243+
val |= SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV422;
244+
else
245+
DRM_DEBUG_DRIVER("Unsupported YUV format (0x%x)\n", format);
246+
247+
/*
248+
* Allwinner seems to list the pixel sequence from right to left, while
249+
* DRM lists it from left to right.
250+
*/
251+
switch (format) {
252+
case DRM_FORMAT_YUYV:
253+
val |= SUN4I_BACKEND_IYUVCTL_FBPS_VYUY;
254+
break;
255+
case DRM_FORMAT_YVYU:
256+
val |= SUN4I_BACKEND_IYUVCTL_FBPS_UYVY;
257+
break;
258+
case DRM_FORMAT_UYVY:
259+
val |= SUN4I_BACKEND_IYUVCTL_FBPS_YVYU;
260+
break;
261+
case DRM_FORMAT_VYUY:
262+
val |= SUN4I_BACKEND_IYUVCTL_FBPS_YUYV;
263+
break;
264+
default:
265+
DRM_DEBUG_DRIVER("Unsupported YUV pixel sequence (0x%x)\n",
266+
format);
267+
}
268+
269+
regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVCTL_REG, val);
270+
271+
return 0;
272+
}
273+
201274
int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
202275
int layer, struct drm_plane *plane)
203276
{
@@ -207,6 +280,10 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
207280
u32 val;
208281
int ret;
209282

283+
/* Clear the YUV mode */
284+
regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_ATTCTL_REG0(layer),
285+
SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN, 0);
286+
210287
if (plane->state->crtc)
211288
interlaced = plane->state->crtc->state->adjusted_mode.flags
212289
& DRM_MODE_FLAG_INTERLACE;
@@ -218,6 +295,9 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
218295
DRM_DEBUG_DRIVER("Switching display backend interlaced mode %s\n",
219296
interlaced ? "on" : "off");
220297

298+
if (sun4i_backend_format_is_yuv(fb->format->format))
299+
return sun4i_backend_update_yuv_format(backend, layer, plane);
300+
221301
ret = sun4i_backend_drm_format_to_layer(fb->format->format, &val);
222302
if (ret) {
223303
DRM_DEBUG_DRIVER("Invalid format\n");
@@ -255,6 +335,21 @@ int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
255335
return 0;
256336
}
257337

338+
static int sun4i_backend_update_yuv_buffer(struct sun4i_backend *backend,
339+
struct drm_framebuffer *fb,
340+
dma_addr_t paddr)
341+
{
342+
/* TODO: Add support for the multi-planar YUV formats */
343+
DRM_DEBUG_DRIVER("Setting packed YUV buffer address to %pad\n", &paddr);
344+
regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVADD_REG(0), paddr);
345+
346+
DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
347+
regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVLINEWIDTH_REG(0),
348+
fb->pitches[0] * 8);
349+
350+
return 0;
351+
}
352+
258353
int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
259354
int layer, struct drm_plane *plane)
260355
{
@@ -280,6 +375,9 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
280375
*/
281376
paddr -= PHYS_OFFSET;
282377

378+
if (sun4i_backend_format_is_yuv(fb->format->format))
379+
return sun4i_backend_update_yuv_buffer(backend, fb, paddr);
380+
283381
/* Write the 32 lower bits of the address (in bits) */
284382
lo_paddr = paddr << 3;
285383
DRM_DEBUG_DRIVER("Setting address lower bits to 0x%x\n", lo_paddr);

drivers/gpu/drm/sun4i/sun4i_backend.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(x) ((x) << 15)
7373
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK GENMASK(11, 10)
7474
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(x) ((x) << 10)
75+
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN BIT(2)
7576
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN BIT(1)
7677

7778
#define SUN4I_BACKEND_ATTCTL_REG1(l) (0x8a0 + (0x4 * (l)))
@@ -110,7 +111,23 @@
110111
#define SUN4I_BACKEND_SPREN_REG 0x900
111112
#define SUN4I_BACKEND_SPRFMTCTL_REG 0x908
112113
#define SUN4I_BACKEND_SPRALPHACTL_REG 0x90c
114+
113115
#define SUN4I_BACKEND_IYUVCTL_REG 0x920
116+
#define SUN4I_BACKEND_IYUVCTL_FBFMT_MASK GENMASK(14, 12)
117+
#define SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV444 (4 << 12)
118+
#define SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV422 (3 << 12)
119+
#define SUN4I_BACKEND_IYUVCTL_FBFMT_PLANAR_YUV444 (2 << 12)
120+
#define SUN4I_BACKEND_IYUVCTL_FBFMT_PLANAR_YUV222 (1 << 12)
121+
#define SUN4I_BACKEND_IYUVCTL_FBFMT_PLANAR_YUV111 (0 << 12)
122+
#define SUN4I_BACKEND_IYUVCTL_FBPS_MASK GENMASK(9, 8)
123+
#define SUN4I_BACKEND_IYUVCTL_FBPS_YVYU (3 << 8)
124+
#define SUN4I_BACKEND_IYUVCTL_FBPS_VYUY (2 << 8)
125+
#define SUN4I_BACKEND_IYUVCTL_FBPS_YUYV (1 << 8)
126+
#define SUN4I_BACKEND_IYUVCTL_FBPS_UYVY (0 << 8)
127+
#define SUN4I_BACKEND_IYUVCTL_FBPS_VUYA (1 << 8)
128+
#define SUN4I_BACKEND_IYUVCTL_FBPS_AYUV (0 << 8)
129+
#define SUN4I_BACKEND_IYUVCTL_EN BIT(0)
130+
114131
#define SUN4I_BACKEND_IYUVADD_REG(c) (0x930 + (0x4 * (c)))
115132

116133
#define SUN4I_BACKEND_IYUVLINEWIDTH_REG(c) (0x940 + (0x4 * (c)))

drivers/gpu/drm/sun4i/sun4i_layer.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,11 @@ static const uint32_t sun4i_backend_layer_formats[] = {
134134
DRM_FORMAT_RGBA4444,
135135
DRM_FORMAT_RGB888,
136136
DRM_FORMAT_RGB565,
137+
DRM_FORMAT_UYVY,
138+
DRM_FORMAT_VYUY,
137139
DRM_FORMAT_XRGB8888,
140+
DRM_FORMAT_YUYV,
141+
DRM_FORMAT_YVYU,
138142
};
139143

140144
static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,

0 commit comments

Comments
 (0)