diff options
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_plane.c | 256 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_regs.h | 56 |
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 | ||
109 | static const struct hvs_format *vc4_get_hvs_format(u32 drm_format) | 140 | static 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 | */ |
222 | static u32 vc4_get_scl_field(struct drm_plane_state *state) | 253 | static 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 | ||
364 | static void vc4_write_scaling_parameters(struct drm_plane_state *state) | 449 | static 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 |