aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/vc4/vc4_plane.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/vc4/vc4_plane.c')
-rw-r--r--drivers/gpu/drm/vc4/vc4_plane.c256
1 files changed, 198 insertions, 58 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);