aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2015-12-30 15:25:44 -0500
committerEric Anholt <eric@anholt.net>2016-02-16 14:24:08 -0500
commitfc04023fafecf19ebd09278d8d67dc5ed1f68b46 (patch)
tree25acc41475384d9d364b6278d3cceea0139ac786
parentfe4cd8476928a66e109ab50a430362fcee8a5716 (diff)
drm/vc4: Add support for YUV planes.
This supports 420 and 422 subsampling with 2 or 3 planes, tested with modetest. It doesn't set up chroma subsampling position (which it appears KMS doesn't deal with yet). The LBM memory is overallocated in many cases, but apparently the docs aren't quite correct and I'll probably need to look at the hardware source to really figure it out. Signed-off-by: Eric Anholt <eric@anholt.net>
-rw-r--r--drivers/gpu/drm/vc4/vc4_plane.c256
-rw-r--r--drivers/gpu/drm/vc4/vc4_regs.h56
2 files changed, 253 insertions, 59 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index 013ebff60fb5..7b0c72ae02a0 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -54,15 +54,19 @@ struct vc4_plane_state {
54 /* Clipped coordinates of the plane on the display. */ 54 /* Clipped coordinates of the plane on the display. */
55 int crtc_x, crtc_y, crtc_w, crtc_h; 55 int crtc_x, crtc_y, crtc_w, crtc_h;
56 /* Clipped area being scanned from in the FB. */ 56 /* Clipped area being scanned from in the FB. */
57 u32 src_x, src_y, src_w, src_h; 57 u32 src_x, src_y;
58 58
59 enum vc4_scaling_mode x_scaling, y_scaling; 59 u32 src_w[2], src_h[2];
60
61 /* Scaling selection for the RGB/Y plane and the Cb/Cr planes. */
62 enum vc4_scaling_mode x_scaling[2], y_scaling[2];
60 bool is_unity; 63 bool is_unity;
64 bool is_yuv;
61 65
62 /* Offset to start scanning out from the start of the plane's 66 /* Offset to start scanning out from the start of the plane's
63 * BO. 67 * BO.
64 */ 68 */
65 u32 offset; 69 u32 offsets[3];
66 70
67 /* Our allocation in LBM for temporary storage during scaling. */ 71 /* Our allocation in LBM for temporary storage during scaling. */
68 struct drm_mm_node lbm; 72 struct drm_mm_node lbm;
@@ -79,6 +83,7 @@ static const struct hvs_format {
79 u32 hvs; /* HVS_FORMAT_* */ 83 u32 hvs; /* HVS_FORMAT_* */
80 u32 pixel_order; 84 u32 pixel_order;
81 bool has_alpha; 85 bool has_alpha;
86 bool flip_cbcr;
82} hvs_formats[] = { 87} hvs_formats[] = {
83 { 88 {
84 .drm = DRM_FORMAT_XRGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, 89 .drm = DRM_FORMAT_XRGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
@@ -104,6 +109,32 @@ static const struct hvs_format {
104 .drm = DRM_FORMAT_XRGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551, 109 .drm = DRM_FORMAT_XRGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
105 .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = false, 110 .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = false,
106 }, 111 },
112 {
113 .drm = DRM_FORMAT_YUV422,
114 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
115 },
116 {
117 .drm = DRM_FORMAT_YVU422,
118 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
119 .flip_cbcr = true,
120 },
121 {
122 .drm = DRM_FORMAT_YUV420,
123 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE,
124 },
125 {
126 .drm = DRM_FORMAT_YVU420,
127 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE,
128 .flip_cbcr = true,
129 },
130 {
131 .drm = DRM_FORMAT_NV12,
132 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE,
133 },
134 {
135 .drm = DRM_FORMAT_NV16,
136 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE,
137 },
107}; 138};
108 139
109static const struct hvs_format *vc4_get_hvs_format(u32 drm_format) 140static const struct hvs_format *vc4_get_hvs_format(u32 drm_format)
@@ -219,11 +250,11 @@ static void vc4_dlist_write(struct vc4_plane_state *vc4_state, u32 val)
219 * 250 *
220 * This is a replication of a table from the spec. 251 * This is a replication of a table from the spec.
221 */ 252 */
222static u32 vc4_get_scl_field(struct drm_plane_state *state) 253static u32 vc4_get_scl_field(struct drm_plane_state *state, int plane)
223{ 254{
224 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 255 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
225 256
226 switch (vc4_state->x_scaling << 2 | vc4_state->y_scaling) { 257 switch (vc4_state->x_scaling[plane] << 2 | vc4_state->y_scaling[plane]) {
227 case VC4_SCALING_PPF << 2 | VC4_SCALING_PPF: 258 case VC4_SCALING_PPF << 2 | VC4_SCALING_PPF:
228 return SCALER_CTL0_SCL_H_PPF_V_PPF; 259 return SCALER_CTL0_SCL_H_PPF_V_PPF;
229 case VC4_SCALING_TPZ << 2 | VC4_SCALING_PPF: 260 case VC4_SCALING_TPZ << 2 | VC4_SCALING_PPF:
@@ -254,9 +285,16 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
254 struct drm_plane *plane = state->plane; 285 struct drm_plane *plane = state->plane;
255 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 286 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
256 struct drm_framebuffer *fb = state->fb; 287 struct drm_framebuffer *fb = state->fb;
288 struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
257 u32 subpixel_src_mask = (1 << 16) - 1; 289 u32 subpixel_src_mask = (1 << 16) - 1;
290 u32 format = fb->pixel_format;
291 int num_planes = drm_format_num_planes(format);
292 u32 h_subsample = 1;
293 u32 v_subsample = 1;
294 int i;
258 295
259 vc4_state->offset = fb->offsets[0]; 296 for (i = 0; i < num_planes; i++)
297 vc4_state->offsets[i] = bo->paddr + fb->offsets[i];
260 298
261 /* We don't support subpixel source positioning for scaling. */ 299 /* We don't support subpixel source positioning for scaling. */
262 if ((state->src_x & subpixel_src_mask) || 300 if ((state->src_x & subpixel_src_mask) ||
@@ -268,20 +306,48 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
268 306
269 vc4_state->src_x = state->src_x >> 16; 307 vc4_state->src_x = state->src_x >> 16;
270 vc4_state->src_y = state->src_y >> 16; 308 vc4_state->src_y = state->src_y >> 16;
271 vc4_state->src_w = state->src_w >> 16; 309 vc4_state->src_w[0] = state->src_w >> 16;
272 vc4_state->src_h = state->src_h >> 16; 310 vc4_state->src_h[0] = state->src_h >> 16;
273 311
274 vc4_state->crtc_x = state->crtc_x; 312 vc4_state->crtc_x = state->crtc_x;
275 vc4_state->crtc_y = state->crtc_y; 313 vc4_state->crtc_y = state->crtc_y;
276 vc4_state->crtc_w = state->crtc_w; 314 vc4_state->crtc_w = state->crtc_w;
277 vc4_state->crtc_h = state->crtc_h; 315 vc4_state->crtc_h = state->crtc_h;
278 316
279 vc4_state->x_scaling = vc4_get_scaling_mode(vc4_state->src_w, 317 vc4_state->x_scaling[0] = vc4_get_scaling_mode(vc4_state->src_w[0],
280 vc4_state->crtc_w); 318 vc4_state->crtc_w);
281 vc4_state->y_scaling = vc4_get_scaling_mode(vc4_state->src_h, 319 vc4_state->y_scaling[0] = vc4_get_scaling_mode(vc4_state->src_h[0],
282 vc4_state->crtc_h); 320 vc4_state->crtc_h);
283 vc4_state->is_unity = (vc4_state->x_scaling == VC4_SCALING_NONE && 321
284 vc4_state->y_scaling == VC4_SCALING_NONE); 322 if (num_planes > 1) {
323 vc4_state->is_yuv = true;
324
325 h_subsample = drm_format_horz_chroma_subsampling(format);
326 v_subsample = drm_format_vert_chroma_subsampling(format);
327 vc4_state->src_w[1] = vc4_state->src_w[0] / h_subsample;
328 vc4_state->src_h[1] = vc4_state->src_h[0] / v_subsample;
329
330 vc4_state->x_scaling[1] =
331 vc4_get_scaling_mode(vc4_state->src_w[1],
332 vc4_state->crtc_w);
333 vc4_state->y_scaling[1] =
334 vc4_get_scaling_mode(vc4_state->src_h[1],
335 vc4_state->crtc_h);
336
337 /* YUV conversion requires that scaling be enabled,
338 * even on a plane that's otherwise 1:1. Choose TPZ
339 * for simplicity.
340 */
341 if (vc4_state->x_scaling[0] == VC4_SCALING_NONE)
342 vc4_state->x_scaling[0] = VC4_SCALING_TPZ;
343 if (vc4_state->y_scaling[0] == VC4_SCALING_NONE)
344 vc4_state->y_scaling[0] = VC4_SCALING_TPZ;
345 }
346
347 vc4_state->is_unity = (vc4_state->x_scaling[0] == VC4_SCALING_NONE &&
348 vc4_state->y_scaling[0] == VC4_SCALING_NONE &&
349 vc4_state->x_scaling[1] == VC4_SCALING_NONE &&
350 vc4_state->y_scaling[1] == VC4_SCALING_NONE);
285 351
286 /* No configuring scaling on the cursor plane, since it gets 352 /* No configuring scaling on the cursor plane, since it gets
287 non-vblank-synced updates, and scaling requires requires 353 non-vblank-synced updates, and scaling requires requires
@@ -294,16 +360,27 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
294 * support negative y, and negative x wastes bandwidth. 360 * support negative y, and negative x wastes bandwidth.
295 */ 361 */
296 if (vc4_state->crtc_x < 0) { 362 if (vc4_state->crtc_x < 0) {
297 vc4_state->offset += (drm_format_plane_cpp(fb->pixel_format, 363 for (i = 0; i < num_planes; i++) {
298 0) * 364 u32 cpp = drm_format_plane_cpp(fb->pixel_format, i);
299 -vc4_state->crtc_x); 365 u32 subs = ((i == 0) ? 1 : h_subsample);
300 vc4_state->src_w += vc4_state->crtc_x; 366
367 vc4_state->offsets[i] += (cpp *
368 (-vc4_state->crtc_x) / subs);
369 }
370 vc4_state->src_w[0] += vc4_state->crtc_x;
371 vc4_state->src_w[1] += vc4_state->crtc_x / h_subsample;
301 vc4_state->crtc_x = 0; 372 vc4_state->crtc_x = 0;
302 } 373 }
303 374
304 if (vc4_state->crtc_y < 0) { 375 if (vc4_state->crtc_y < 0) {
305 vc4_state->offset += fb->pitches[0] * -vc4_state->crtc_y; 376 for (i = 0; i < num_planes; i++) {
306 vc4_state->src_h += vc4_state->crtc_y; 377 u32 subs = ((i == 0) ? 1 : v_subsample);
378
379 vc4_state->offsets[i] += (fb->pitches[i] *
380 (-vc4_state->crtc_y) / subs);
381 }
382 vc4_state->src_h[0] += vc4_state->crtc_y;
383 vc4_state->src_h[1] += vc4_state->crtc_y / v_subsample;
307 vc4_state->crtc_y = 0; 384 vc4_state->crtc_y = 0;
308 } 385 }
309 386
@@ -344,15 +421,23 @@ static u32 vc4_lbm_size(struct drm_plane_state *state)
344 /* This is the worst case number. One of the two sizes will 421 /* This is the worst case number. One of the two sizes will
345 * be used depending on the scaling configuration. 422 * be used depending on the scaling configuration.
346 */ 423 */
347 u32 pix_per_line = max(vc4_state->src_w, (u32)vc4_state->crtc_w); 424 u32 pix_per_line = max(vc4_state->src_w[0], (u32)vc4_state->crtc_w);
348 u32 lbm; 425 u32 lbm;
349 426
350 if (vc4_state->is_unity) 427 if (!vc4_state->is_yuv) {
351 return 0; 428 if (vc4_state->is_unity)
352 else if (vc4_state->y_scaling == VC4_SCALING_TPZ) 429 return 0;
353 lbm = pix_per_line * 8; 430 else if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ)
354 else { 431 lbm = pix_per_line * 8;
355 /* In special cases, this multiplier might be 12. */ 432 else {
433 /* In special cases, this multiplier might be 12. */
434 lbm = pix_per_line * 16;
435 }
436 } else {
437 /* There are cases for this going down to a multiplier
438 * of 2, but according to the firmware source, the
439 * table in the docs is somewhat wrong.
440 */
356 lbm = pix_per_line * 16; 441 lbm = pix_per_line * 16;
357 } 442 }
358 443
@@ -361,33 +446,34 @@ static u32 vc4_lbm_size(struct drm_plane_state *state)
361 return lbm; 446 return lbm;
362} 447}
363 448
364static void vc4_write_scaling_parameters(struct drm_plane_state *state) 449static void vc4_write_scaling_parameters(struct drm_plane_state *state,
450 int channel)
365{ 451{
366 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 452 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
367 453
368 /* Ch0 H-PPF Word 0: Scaling Parameters */ 454 /* Ch0 H-PPF Word 0: Scaling Parameters */
369 if (vc4_state->x_scaling == VC4_SCALING_PPF) { 455 if (vc4_state->x_scaling[channel] == VC4_SCALING_PPF) {
370 vc4_write_ppf(vc4_state, 456 vc4_write_ppf(vc4_state,
371 vc4_state->src_w, vc4_state->crtc_w); 457 vc4_state->src_w[channel], vc4_state->crtc_w);
372 } 458 }
373 459
374 /* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */ 460 /* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */
375 if (vc4_state->y_scaling == VC4_SCALING_PPF) { 461 if (vc4_state->y_scaling[channel] == VC4_SCALING_PPF) {
376 vc4_write_ppf(vc4_state, 462 vc4_write_ppf(vc4_state,
377 vc4_state->src_h, vc4_state->crtc_h); 463 vc4_state->src_h[channel], vc4_state->crtc_h);
378 vc4_dlist_write(vc4_state, 0xc0c0c0c0); 464 vc4_dlist_write(vc4_state, 0xc0c0c0c0);
379 } 465 }
380 466
381 /* Ch0 H-TPZ Words 0-1: Scaling Parameters, Recip */ 467 /* Ch0 H-TPZ Words 0-1: Scaling Parameters, Recip */
382 if (vc4_state->x_scaling == VC4_SCALING_TPZ) { 468 if (vc4_state->x_scaling[channel] == VC4_SCALING_TPZ) {
383 vc4_write_tpz(vc4_state, 469 vc4_write_tpz(vc4_state,
384 vc4_state->src_w, vc4_state->crtc_w); 470 vc4_state->src_w[channel], vc4_state->crtc_w);
385 } 471 }
386 472
387 /* Ch0 V-TPZ Words 0-2: Scaling Parameters, Recip, Context */ 473 /* Ch0 V-TPZ Words 0-2: Scaling Parameters, Recip, Context */
388 if (vc4_state->y_scaling == VC4_SCALING_TPZ) { 474 if (vc4_state->y_scaling[channel] == VC4_SCALING_TPZ) {
389 vc4_write_tpz(vc4_state, 475 vc4_write_tpz(vc4_state,
390 vc4_state->src_h, vc4_state->crtc_h); 476 vc4_state->src_h[channel], vc4_state->crtc_h);
391 vc4_dlist_write(vc4_state, 0xc0c0c0c0); 477 vc4_dlist_write(vc4_state, 0xc0c0c0c0);
392 } 478 }
393} 479}
@@ -401,13 +487,13 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
401 struct vc4_dev *vc4 = to_vc4_dev(plane->dev); 487 struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
402 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 488 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
403 struct drm_framebuffer *fb = state->fb; 489 struct drm_framebuffer *fb = state->fb;
404 struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
405 u32 ctl0_offset = vc4_state->dlist_count; 490 u32 ctl0_offset = vc4_state->dlist_count;
406 const struct hvs_format *format = vc4_get_hvs_format(fb->pixel_format); 491 const struct hvs_format *format = vc4_get_hvs_format(fb->pixel_format);
407 u32 scl; 492 int num_planes = drm_format_num_planes(format->drm);
493 u32 scl0, scl1;
408 u32 lbm_size; 494 u32 lbm_size;
409 unsigned long irqflags; 495 unsigned long irqflags;
410 int ret; 496 int ret, i;
411 497
412 ret = vc4_plane_setup_clipping_and_scaling(state); 498 ret = vc4_plane_setup_clipping_and_scaling(state);
413 if (ret) 499 if (ret)
@@ -432,7 +518,19 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
432 if (ret) 518 if (ret)
433 return ret; 519 return ret;
434 520
435 scl = vc4_get_scl_field(state); 521 /* SCL1 is used for Cb/Cr scaling of planar formats. For RGB
522 * and 4:4:4, scl1 should be set to scl0 so both channels of
523 * the scaler do the same thing. For YUV, the Y plane needs
524 * to be put in channel 1 and Cb/Cr in channel 0, so we swap
525 * the scl fields here.
526 */
527 if (num_planes == 1) {
528 scl0 = vc4_get_scl_field(state, 1);
529 scl1 = scl0;
530 } else {
531 scl0 = vc4_get_scl_field(state, 1);
532 scl1 = vc4_get_scl_field(state, 0);
533 }
436 534
437 /* Control word */ 535 /* Control word */
438 vc4_dlist_write(vc4_state, 536 vc4_dlist_write(vc4_state,
@@ -440,8 +538,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
440 (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) | 538 (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) |
441 (format->hvs << SCALER_CTL0_PIXEL_FORMAT_SHIFT) | 539 (format->hvs << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
442 (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) | 540 (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) |
443 VC4_SET_FIELD(scl, SCALER_CTL0_SCL0) | 541 VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |
444 VC4_SET_FIELD(scl, SCALER_CTL0_SCL1)); 542 VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1));
445 543
446 /* Position Word 0: Image Positions and Alpha Value */ 544 /* Position Word 0: Image Positions and Alpha Value */
447 vc4_state->pos0_offset = vc4_state->dlist_count; 545 vc4_state->pos0_offset = vc4_state->dlist_count;
@@ -466,35 +564,68 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
466 SCALER_POS2_ALPHA_MODE_PIPELINE : 564 SCALER_POS2_ALPHA_MODE_PIPELINE :
467 SCALER_POS2_ALPHA_MODE_FIXED, 565 SCALER_POS2_ALPHA_MODE_FIXED,
468 SCALER_POS2_ALPHA_MODE) | 566 SCALER_POS2_ALPHA_MODE) |
469 VC4_SET_FIELD(vc4_state->src_w, SCALER_POS2_WIDTH) | 567 VC4_SET_FIELD(vc4_state->src_w[0], SCALER_POS2_WIDTH) |
470 VC4_SET_FIELD(vc4_state->src_h, SCALER_POS2_HEIGHT)); 568 VC4_SET_FIELD(vc4_state->src_h[0], SCALER_POS2_HEIGHT));
471 569
472 /* Position Word 3: Context. Written by the HVS. */ 570 /* Position Word 3: Context. Written by the HVS. */
473 vc4_dlist_write(vc4_state, 0xc0c0c0c0); 571 vc4_dlist_write(vc4_state, 0xc0c0c0c0);
474 572
475 /* Pointer Word 0: RGB / Y Pointer */ 573
574 /* Pointer Word 0/1/2: RGB / Y / Cb / Cr Pointers
575 *
576 * The pointers may be any byte address.
577 */
476 vc4_state->ptr0_offset = vc4_state->dlist_count; 578 vc4_state->ptr0_offset = vc4_state->dlist_count;
477 vc4_dlist_write(vc4_state, bo->paddr + vc4_state->offset); 579 if (!format->flip_cbcr) {
580 for (i = 0; i < num_planes; i++)
581 vc4_dlist_write(vc4_state, vc4_state->offsets[i]);
582 } else {
583 WARN_ON_ONCE(num_planes != 3);
584 vc4_dlist_write(vc4_state, vc4_state->offsets[0]);
585 vc4_dlist_write(vc4_state, vc4_state->offsets[2]);
586 vc4_dlist_write(vc4_state, vc4_state->offsets[1]);
587 }
478 588
479 /* Pointer Context Word 0: Written by the HVS */ 589 /* Pointer Context Word 0/1/2: Written by the HVS */
480 vc4_dlist_write(vc4_state, 0xc0c0c0c0); 590 for (i = 0; i < num_planes; i++)
591 vc4_dlist_write(vc4_state, 0xc0c0c0c0);
481 592
482 /* Pitch word 0: Pointer 0 Pitch */ 593 /* Pitch word 0/1/2 */
483 vc4_dlist_write(vc4_state, 594 for (i = 0; i < num_planes; i++) {
484 VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH)); 595 vc4_dlist_write(vc4_state,
596 VC4_SET_FIELD(fb->pitches[i], SCALER_SRC_PITCH));
597 }
598
599 /* Colorspace conversion words */
600 if (vc4_state->is_yuv) {
601 vc4_dlist_write(vc4_state, SCALER_CSC0_ITR_R_601_5);
602 vc4_dlist_write(vc4_state, SCALER_CSC1_ITR_R_601_5);
603 vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5);
604 }
485 605
486 if (!vc4_state->is_unity) { 606 if (!vc4_state->is_unity) {
487 /* LBM Base Address. */ 607 /* LBM Base Address. */
488 if (vc4_state->y_scaling != VC4_SCALING_NONE) 608 if (vc4_state->y_scaling[0] != VC4_SCALING_NONE ||
609 vc4_state->y_scaling[1] != VC4_SCALING_NONE) {
489 vc4_dlist_write(vc4_state, vc4_state->lbm.start); 610 vc4_dlist_write(vc4_state, vc4_state->lbm.start);
611 }
490 612
491 vc4_write_scaling_parameters(state); 613 if (num_planes > 1) {
614 /* Emit Cb/Cr as channel 0 and Y as channel
615 * 1. This matches how we set up scl0/scl1
616 * above.
617 */
618 vc4_write_scaling_parameters(state, 1);
619 }
620 vc4_write_scaling_parameters(state, 0);
492 621
493 /* If any PPF setup was done, then all the kernel 622 /* If any PPF setup was done, then all the kernel
494 * pointers get uploaded. 623 * pointers get uploaded.
495 */ 624 */
496 if (vc4_state->x_scaling == VC4_SCALING_PPF || 625 if (vc4_state->x_scaling[0] == VC4_SCALING_PPF ||
497 vc4_state->y_scaling == VC4_SCALING_PPF) { 626 vc4_state->y_scaling[0] == VC4_SCALING_PPF ||
627 vc4_state->x_scaling[1] == VC4_SCALING_PPF ||
628 vc4_state->y_scaling[1] == VC4_SCALING_PPF) {
498 u32 kernel = VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start, 629 u32 kernel = VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start,
499 SCALER_PPF_KERNEL_OFFSET); 630 SCALER_PPF_KERNEL_OFFSET);
500 631
@@ -698,6 +829,7 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
698 struct drm_plane *plane = NULL; 829 struct drm_plane *plane = NULL;
699 struct vc4_plane *vc4_plane; 830 struct vc4_plane *vc4_plane;
700 u32 formats[ARRAY_SIZE(hvs_formats)]; 831 u32 formats[ARRAY_SIZE(hvs_formats)];
832 u32 num_formats = 0;
701 int ret = 0; 833 int ret = 0;
702 unsigned i; 834 unsigned i;
703 835
@@ -708,12 +840,20 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
708 goto fail; 840 goto fail;
709 } 841 }
710 842
711 for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) 843 for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) {
712 formats[i] = hvs_formats[i].drm; 844 /* Don't allow YUV in cursor planes, since that means
845 * tuning on the scaler, which we don't allow for the
846 * cursor.
847 */
848 if (type != DRM_PLANE_TYPE_CURSOR ||
849 hvs_formats[i].hvs < HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE) {
850 formats[num_formats++] = hvs_formats[i].drm;
851 }
852 }
713 plane = &vc4_plane->base; 853 plane = &vc4_plane->base;
714 ret = drm_universal_plane_init(dev, plane, 0xff, 854 ret = drm_universal_plane_init(dev, plane, 0xff,
715 &vc4_plane_funcs, 855 &vc4_plane_funcs,
716 formats, ARRAY_SIZE(formats), 856 formats, num_formats,
717 type, NULL); 857 type, NULL);
718 858
719 drm_plane_helper_add(plane, &vc4_plane_helper_funcs); 859 drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
index 037c7fe67187..25df20ef939c 100644
--- a/drivers/gpu/drm/vc4/vc4_regs.h
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
@@ -503,7 +503,12 @@ enum hvs_pixel_format {
503 HVS_PIXEL_FORMAT_RGB888 = 5, 503 HVS_PIXEL_FORMAT_RGB888 = 5,
504 HVS_PIXEL_FORMAT_RGBA6666 = 6, 504 HVS_PIXEL_FORMAT_RGBA6666 = 6,
505 /* 32bpp */ 505 /* 32bpp */
506 HVS_PIXEL_FORMAT_RGBA8888 = 7 506 HVS_PIXEL_FORMAT_RGBA8888 = 7,
507
508 HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE = 8,
509 HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE = 9,
510 HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE = 10,
511 HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE = 11,
507}; 512};
508 513
509/* Note: the LSB is the rightmost character shown. Only valid for 514/* Note: the LSB is the rightmost character shown. Only valid for
@@ -585,6 +590,55 @@ enum hvs_pixel_format {
585#define SCALER_POS2_WIDTH_MASK VC4_MASK(11, 0) 590#define SCALER_POS2_WIDTH_MASK VC4_MASK(11, 0)
586#define SCALER_POS2_WIDTH_SHIFT 0 591#define SCALER_POS2_WIDTH_SHIFT 0
587 592
593/* Color Space Conversion words. Some values are S2.8 signed
594 * integers, except that the 2 integer bits map as {0x0: 0, 0x1: 1,
595 * 0x2: 2, 0x3: -1}
596 */
597/* bottom 8 bits of S2.8 contribution of Cr to Blue */
598#define SCALER_CSC0_COEF_CR_BLU_MASK VC4_MASK(31, 24)
599#define SCALER_CSC0_COEF_CR_BLU_SHIFT 24
600/* Signed offset to apply to Y before CSC. (Y' = Y + YY_OFS) */
601#define SCALER_CSC0_COEF_YY_OFS_MASK VC4_MASK(23, 16)
602#define SCALER_CSC0_COEF_YY_OFS_SHIFT 16
603/* Signed offset to apply to CB before CSC (Cb' = Cb - 128 + CB_OFS). */
604#define SCALER_CSC0_COEF_CB_OFS_MASK VC4_MASK(15, 8)
605#define SCALER_CSC0_COEF_CB_OFS_SHIFT 8
606/* Signed offset to apply to CB before CSC (Cr' = Cr - 128 + CR_OFS). */
607#define SCALER_CSC0_COEF_CR_OFS_MASK VC4_MASK(7, 0)
608#define SCALER_CSC0_COEF_CR_OFS_SHIFT 0
609#define SCALER_CSC0_ITR_R_601_5 0x00f00000
610#define SCALER_CSC0_ITR_R_709_3 0x00f00000
611#define SCALER_CSC0_JPEG_JFIF 0x00000000
612
613/* S2.8 contribution of Cb to Green */
614#define SCALER_CSC1_COEF_CB_GRN_MASK VC4_MASK(31, 22)
615#define SCALER_CSC1_COEF_CB_GRN_SHIFT 22
616/* S2.8 contribution of Cr to Green */
617#define SCALER_CSC1_COEF_CR_GRN_MASK VC4_MASK(21, 12)
618#define SCALER_CSC1_COEF_CR_GRN_SHIFT 12
619/* S2.8 contribution of Y to all of RGB */
620#define SCALER_CSC1_COEF_YY_ALL_MASK VC4_MASK(11, 2)
621#define SCALER_CSC1_COEF_YY_ALL_SHIFT 2
622/* top 2 bits of S2.8 contribution of Cr to Blue */
623#define SCALER_CSC1_COEF_CR_BLU_MASK VC4_MASK(1, 0)
624#define SCALER_CSC1_COEF_CR_BLU_SHIFT 0
625#define SCALER_CSC1_ITR_R_601_5 0xe73304a8
626#define SCALER_CSC1_ITR_R_709_3 0xf2b784a8
627#define SCALER_CSC1_JPEG_JFIF 0xea34a400
628
629/* S2.8 contribution of Cb to Red */
630#define SCALER_CSC2_COEF_CB_RED_MASK VC4_MASK(29, 20)
631#define SCALER_CSC2_COEF_CB_RED_SHIFT 20
632/* S2.8 contribution of Cr to Red */
633#define SCALER_CSC2_COEF_CR_RED_MASK VC4_MASK(19, 10)
634#define SCALER_CSC2_COEF_CR_RED_SHIFT 10
635/* S2.8 contribution of Cb to Blue */
636#define SCALER_CSC2_COEF_CB_BLU_MASK VC4_MASK(19, 10)
637#define SCALER_CSC2_COEF_CB_BLU_SHIFT 10
638#define SCALER_CSC2_ITR_R_601_5 0x00066204
639#define SCALER_CSC2_ITR_R_709_3 0x00072a1c
640#define SCALER_CSC2_JPEG_JFIF 0x000599c5
641
588#define SCALER_TPZ0_VERT_RECALC BIT(31) 642#define SCALER_TPZ0_VERT_RECALC BIT(31)
589#define SCALER_TPZ0_SCALE_MASK VC4_MASK(28, 8) 643#define SCALER_TPZ0_SCALE_MASK VC4_MASK(28, 8)
590#define SCALER_TPZ0_SCALE_SHIFT 8 644#define SCALER_TPZ0_SCALE_SHIFT 8