@@ -42,6 +42,24 @@ static const u32 sunxi_rgb2yuv_coef[12] = {
42
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
+ */
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
+
45
63
static inline bool sun4i_backend_format_is_planar_yuv (uint32_t format )
46
64
{
47
65
switch (format ) {
@@ -198,6 +216,61 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
198
216
return 0 ;
199
217
}
200
218
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
+
201
274
int sun4i_backend_update_layer_formats (struct sun4i_backend * backend ,
202
275
int layer , struct drm_plane * plane )
203
276
{
@@ -207,6 +280,10 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
207
280
u32 val ;
208
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
287
if (plane -> state -> crtc )
211
288
interlaced = plane -> state -> crtc -> state -> adjusted_mode .flags
212
289
& DRM_MODE_FLAG_INTERLACE ;
@@ -218,6 +295,9 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
218
295
DRM_DEBUG_DRIVER ("Switching display backend interlaced mode %s\n" ,
219
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
301
ret = sun4i_backend_drm_format_to_layer (fb -> format -> format , & val );
222
302
if (ret ) {
223
303
DRM_DEBUG_DRIVER ("Invalid format\n" );
@@ -255,6 +335,21 @@ int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
255
335
return 0 ;
256
336
}
257
337
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
+
258
353
int sun4i_backend_update_layer_buffer (struct sun4i_backend * backend ,
259
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
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
381
/* Write the 32 lower bits of the address (in bits) */
284
382
lo_paddr = paddr << 3 ;
285
383
DRM_DEBUG_DRIVER ("Setting address lower bits to 0x%x\n" , lo_paddr );
0 commit comments