aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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,