aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorMaxime Ripard <maxime.ripard@bootlin.com>2018-03-01 14:18:46 -0500
committerMaxime Ripard <maxime.ripard@bootlin.com>2018-03-19 17:04:57 -0400
commitddc389f5a4abb4c0c91202cd6dc09a28b9e2d82c (patch)
treee93e243cd20af5ae761effed024d77e5cf6dc225 /drivers/gpu/drm
parent32463556a634f3e262581ed348705081706fccd0 (diff)
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 <wens@csie.org> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/66088c1398bd3189123f28a89a7ccc669fe9f296.1519931807.git-series.maxime.ripard@bootlin.com
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_backend.c98
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_backend.h17
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_layer.c4
3 files changed, 119 insertions, 0 deletions
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index 8aaa74d09954..9bad54f3de38 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -42,6 +42,24 @@ static const u32 sunxi_rgb2yuv_coef[12] = {
42 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808 42 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
43}; 43};
44 44
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 */
57static const u32 sunxi_bt601_yuv2rgb_coef[12] = {
58 0x000004a7, 0x00001e6f, 0x00001cbf, 0x00000877,
59 0x000004a7, 0x00000000, 0x00000662, 0x00003211,
60 0x000004a7, 0x00000812, 0x00000000, 0x00002eb1,
61};
62
45static inline bool sun4i_backend_format_is_planar_yuv(uint32_t format) 63static inline bool sun4i_backend_format_is_planar_yuv(uint32_t format)
46{ 64{
47 switch (format) { 65 switch (format) {
@@ -198,6 +216,61 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
198 return 0; 216 return 0;
199} 217}
200 218
219static 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
201int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, 274int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
202 int layer, struct drm_plane *plane) 275 int layer, struct drm_plane *plane)
203{ 276{
@@ -207,6 +280,10 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
207 u32 val; 280 u32 val;
208 int ret; 281 int ret;
209 282
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
210 if (plane->state->crtc) 287 if (plane->state->crtc)
211 interlaced = plane->state->crtc->state->adjusted_mode.flags 288 interlaced = plane->state->crtc->state->adjusted_mode.flags
212 & DRM_MODE_FLAG_INTERLACE; 289 & DRM_MODE_FLAG_INTERLACE;
@@ -218,6 +295,9 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
218 DRM_DEBUG_DRIVER("Switching display backend interlaced mode %s\n", 295 DRM_DEBUG_DRIVER("Switching display backend interlaced mode %s\n",
219 interlaced ? "on" : "off"); 296 interlaced ? "on" : "off");
220 297
298 if (sun4i_backend_format_is_yuv(fb->format->format))
299 return sun4i_backend_update_yuv_format(backend, layer, plane);
300
221 ret = sun4i_backend_drm_format_to_layer(fb->format->format, &val); 301 ret = sun4i_backend_drm_format_to_layer(fb->format->format, &val);
222 if (ret) { 302 if (ret) {
223 DRM_DEBUG_DRIVER("Invalid format\n"); 303 DRM_DEBUG_DRIVER("Invalid format\n");
@@ -255,6 +335,21 @@ int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
255 return 0; 335 return 0;
256} 336}
257 337
338static 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
258int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, 353int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
259 int layer, struct drm_plane *plane) 354 int layer, struct drm_plane *plane)
260{ 355{
@@ -280,6 +375,9 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
280 */ 375 */
281 paddr -= PHYS_OFFSET; 376 paddr -= PHYS_OFFSET;
282 377
378 if (sun4i_backend_format_is_yuv(fb->format->format))
379 return sun4i_backend_update_yuv_buffer(backend, fb, paddr);
380
283 /* Write the 32 lower bits of the address (in bits) */ 381 /* Write the 32 lower bits of the address (in bits) */
284 lo_paddr = paddr << 3; 382 lo_paddr = paddr << 3;
285 DRM_DEBUG_DRIVER("Setting address lower bits to 0x%x\n", lo_paddr); 383 DRM_DEBUG_DRIVER("Setting address lower bits to 0x%x\n", lo_paddr);
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
index 835408281309..316f2179e9e1 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.h
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
@@ -72,6 +72,7 @@
72#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(x) ((x) << 15) 72#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(x) ((x) << 15)
73#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK GENMASK(11, 10) 73#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK GENMASK(11, 10)
74#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(x) ((x) << 10) 74#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(x) ((x) << 10)
75#define SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN BIT(2)
75#define SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN BIT(1) 76#define SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN BIT(1)
76 77
77#define SUN4I_BACKEND_ATTCTL_REG1(l) (0x8a0 + (0x4 * (l))) 78#define SUN4I_BACKEND_ATTCTL_REG1(l) (0x8a0 + (0x4 * (l)))
@@ -110,7 +111,23 @@
110#define SUN4I_BACKEND_SPREN_REG 0x900 111#define SUN4I_BACKEND_SPREN_REG 0x900
111#define SUN4I_BACKEND_SPRFMTCTL_REG 0x908 112#define SUN4I_BACKEND_SPRFMTCTL_REG 0x908
112#define SUN4I_BACKEND_SPRALPHACTL_REG 0x90c 113#define SUN4I_BACKEND_SPRALPHACTL_REG 0x90c
114
113#define SUN4I_BACKEND_IYUVCTL_REG 0x920 115#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
114#define SUN4I_BACKEND_IYUVADD_REG(c) (0x930 + (0x4 * (c))) 131#define SUN4I_BACKEND_IYUVADD_REG(c) (0x930 + (0x4 * (c)))
115 132
116#define SUN4I_BACKEND_IYUVLINEWIDTH_REG(c) (0x940 + (0x4 * (c))) 133#define SUN4I_BACKEND_IYUVLINEWIDTH_REG(c) (0x940 + (0x4 * (c)))
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
index 33ad377569ec..2949a3c912c1 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
@@ -134,7 +134,11 @@ static const uint32_t sun4i_backend_layer_formats[] = {
134 DRM_FORMAT_RGBA4444, 134 DRM_FORMAT_RGBA4444,
135 DRM_FORMAT_RGB888, 135 DRM_FORMAT_RGB888,
136 DRM_FORMAT_RGB565, 136 DRM_FORMAT_RGB565,
137 DRM_FORMAT_UYVY,
138 DRM_FORMAT_VYUY,
137 DRM_FORMAT_XRGB8888, 139 DRM_FORMAT_XRGB8888,
140 DRM_FORMAT_YUYV,
141 DRM_FORMAT_YVYU,
138}; 142};
139 143
140static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm, 144static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,