1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2015 Broadcom
7 * DOC: VC4 plane module
9 * Each DRM plane is a layer of pixels being scanned out by the HVS.
11 * At atomic modeset check time, we compute the HVS display element
12 * state that would be necessary for displaying the plane (giving us a
13 * chance to figure out if a plane configuration is invalid), then at
14 * atomic flush time the CRTC will ask us to write our element state
15 * into the region of the HVS that it has allocated for us.
18 #include <drm/drm_atomic.h>
19 #include <drm/drm_atomic_helper.h>
20 #include <drm/drm_atomic_uapi.h>
21 #include <drm/drm_blend.h>
22 #include <drm/drm_drv.h>
23 #include <drm/drm_fb_dma_helper.h>
24 #include <drm/drm_fourcc.h>
25 #include <drm/drm_framebuffer.h>
26 #include <drm/drm_gem_atomic_helper.h>
28 #include "uapi/drm/vc4_drm.h"
33 static const struct hvs_format {
34 u32 drm; /* DRM_FORMAT_* */
35 u32 hvs; /* HVS_FORMAT_* */
41 .drm = DRM_FORMAT_XRGB8888,
42 .hvs = HVS_PIXEL_FORMAT_RGBA8888,
43 .pixel_order = HVS_PIXEL_ORDER_ABGR,
44 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
47 .drm = DRM_FORMAT_ARGB8888,
48 .hvs = HVS_PIXEL_FORMAT_RGBA8888,
49 .pixel_order = HVS_PIXEL_ORDER_ABGR,
50 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
53 .drm = DRM_FORMAT_ABGR8888,
54 .hvs = HVS_PIXEL_FORMAT_RGBA8888,
55 .pixel_order = HVS_PIXEL_ORDER_ARGB,
56 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,
59 .drm = DRM_FORMAT_XBGR8888,
60 .hvs = HVS_PIXEL_FORMAT_RGBA8888,
61 .pixel_order = HVS_PIXEL_ORDER_ARGB,
62 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,
65 .drm = DRM_FORMAT_RGB565,
66 .hvs = HVS_PIXEL_FORMAT_RGB565,
67 .pixel_order = HVS_PIXEL_ORDER_XRGB,
68 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XRGB,
71 .drm = DRM_FORMAT_BGR565,
72 .hvs = HVS_PIXEL_FORMAT_RGB565,
73 .pixel_order = HVS_PIXEL_ORDER_XBGR,
74 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XBGR,
77 .drm = DRM_FORMAT_ARGB1555,
78 .hvs = HVS_PIXEL_FORMAT_RGBA5551,
79 .pixel_order = HVS_PIXEL_ORDER_ABGR,
80 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
83 .drm = DRM_FORMAT_XRGB1555,
84 .hvs = HVS_PIXEL_FORMAT_RGBA5551,
85 .pixel_order = HVS_PIXEL_ORDER_ABGR,
86 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
89 .drm = DRM_FORMAT_RGB888,
90 .hvs = HVS_PIXEL_FORMAT_RGB888,
91 .pixel_order = HVS_PIXEL_ORDER_XRGB,
92 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XRGB,
95 .drm = DRM_FORMAT_BGR888,
96 .hvs = HVS_PIXEL_FORMAT_RGB888,
97 .pixel_order = HVS_PIXEL_ORDER_XBGR,
98 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XBGR,
101 .drm = DRM_FORMAT_YUV422,
102 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
103 .pixel_order = HVS_PIXEL_ORDER_XYCBCR,
104 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCBCR,
107 .drm = DRM_FORMAT_YVU422,
108 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
109 .pixel_order = HVS_PIXEL_ORDER_XYCRCB,
110 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCRCB,
113 .drm = DRM_FORMAT_YUV444,
114 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
115 .pixel_order = HVS_PIXEL_ORDER_XYCBCR,
116 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCBCR,
119 .drm = DRM_FORMAT_YVU444,
120 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
121 .pixel_order = HVS_PIXEL_ORDER_XYCRCB,
122 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCRCB,
125 .drm = DRM_FORMAT_YUV420,
126 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE,
127 .pixel_order = HVS_PIXEL_ORDER_XYCBCR,
128 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCBCR,
131 .drm = DRM_FORMAT_YVU420,
132 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE,
133 .pixel_order = HVS_PIXEL_ORDER_XYCRCB,
134 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCRCB,
137 .drm = DRM_FORMAT_NV12,
138 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE,
139 .pixel_order = HVS_PIXEL_ORDER_XYCBCR,
140 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCBCR,
143 .drm = DRM_FORMAT_NV21,
144 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE,
145 .pixel_order = HVS_PIXEL_ORDER_XYCRCB,
146 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCRCB,
149 .drm = DRM_FORMAT_NV16,
150 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE,
151 .pixel_order = HVS_PIXEL_ORDER_XYCBCR,
152 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCBCR,
155 .drm = DRM_FORMAT_NV61,
156 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE,
157 .pixel_order = HVS_PIXEL_ORDER_XYCRCB,
158 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCRCB,
161 .drm = DRM_FORMAT_P030,
162 .hvs = HVS_PIXEL_FORMAT_YCBCR_10BIT,
163 .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCBCR,
167 .drm = DRM_FORMAT_XRGB2101010,
168 .hvs = HVS_PIXEL_FORMAT_RGBA1010102,
169 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
173 .drm = DRM_FORMAT_ARGB2101010,
174 .hvs = HVS_PIXEL_FORMAT_RGBA1010102,
175 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
179 .drm = DRM_FORMAT_ABGR2101010,
180 .hvs = HVS_PIXEL_FORMAT_RGBA1010102,
181 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,
185 .drm = DRM_FORMAT_XBGR2101010,
186 .hvs = HVS_PIXEL_FORMAT_RGBA1010102,
187 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,
191 .drm = DRM_FORMAT_RGB332,
192 .hvs = HVS_PIXEL_FORMAT_RGB332,
193 .pixel_order = HVS_PIXEL_ORDER_ARGB,
194 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
197 .drm = DRM_FORMAT_BGR233,
198 .hvs = HVS_PIXEL_FORMAT_RGB332,
199 .pixel_order = HVS_PIXEL_ORDER_ABGR,
200 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,
203 .drm = DRM_FORMAT_XRGB4444,
204 .hvs = HVS_PIXEL_FORMAT_RGBA4444,
205 .pixel_order = HVS_PIXEL_ORDER_ABGR,
206 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
209 .drm = DRM_FORMAT_ARGB4444,
210 .hvs = HVS_PIXEL_FORMAT_RGBA4444,
211 .pixel_order = HVS_PIXEL_ORDER_ABGR,
212 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
215 .drm = DRM_FORMAT_XBGR4444,
216 .hvs = HVS_PIXEL_FORMAT_RGBA4444,
217 .pixel_order = HVS_PIXEL_ORDER_ARGB,
218 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,
221 .drm = DRM_FORMAT_ABGR4444,
222 .hvs = HVS_PIXEL_FORMAT_RGBA4444,
223 .pixel_order = HVS_PIXEL_ORDER_ARGB,
224 .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,
227 .drm = DRM_FORMAT_BGRX4444,
228 .hvs = HVS_PIXEL_FORMAT_RGBA4444,
229 .pixel_order = HVS_PIXEL_ORDER_RGBA,
230 .pixel_order_hvs5 = HVS_PIXEL_ORDER_BGRA,
233 .drm = DRM_FORMAT_BGRA4444,
234 .hvs = HVS_PIXEL_FORMAT_RGBA4444,
235 .pixel_order = HVS_PIXEL_ORDER_RGBA,
236 .pixel_order_hvs5 = HVS_PIXEL_ORDER_BGRA,
239 .drm = DRM_FORMAT_RGBX4444,
240 .hvs = HVS_PIXEL_FORMAT_RGBA4444,
241 .pixel_order = HVS_PIXEL_ORDER_BGRA,
242 .pixel_order_hvs5 = HVS_PIXEL_ORDER_RGBA,
245 .drm = DRM_FORMAT_RGBA4444,
246 .hvs = HVS_PIXEL_FORMAT_RGBA4444,
247 .pixel_order = HVS_PIXEL_ORDER_BGRA,
248 .pixel_order_hvs5 = HVS_PIXEL_ORDER_RGBA,
252 static const struct hvs_format *vc4_get_hvs_format(u32 drm_format)
256 for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) {
257 if (hvs_formats[i].drm == drm_format)
258 return &hvs_formats[i];
264 static enum vc4_scaling_mode vc4_get_scaling_mode(u32 src, u32 dst)
266 if (dst == src >> 16)
267 return VC4_SCALING_NONE;
268 if (3 * dst >= 2 * (src >> 16))
269 return VC4_SCALING_PPF;
271 return VC4_SCALING_TPZ;
274 static bool plane_enabled(struct drm_plane_state *state)
276 return state->fb && !WARN_ON(!state->crtc);
279 static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane)
281 struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
282 struct vc4_hvs *hvs = vc4->hvs;
283 struct vc4_plane_state *vc4_state;
286 if (WARN_ON(!plane->state))
289 vc4_state = kmemdup(plane->state, sizeof(*vc4_state), GFP_KERNEL);
293 memset(&vc4_state->lbm, 0, sizeof(vc4_state->lbm));
295 for (i = 0; i < DRM_FORMAT_MAX_PLANES; i++) {
296 if (vc4_state->upm_handle[i])
297 refcount_inc(&hvs->upm_refcounts[vc4_state->upm_handle[i]].refcount);
300 vc4_state->dlist_initialized = 0;
302 __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base);
304 if (vc4_state->dlist) {
305 vc4_state->dlist = kmemdup(vc4_state->dlist,
306 vc4_state->dlist_count * 4,
308 if (!vc4_state->dlist) {
312 vc4_state->dlist_size = vc4_state->dlist_count;
315 return &vc4_state->base;
318 static void vc4_plane_release_upm_ida(struct vc4_hvs *hvs, unsigned int upm_handle)
320 struct vc4_upm_refcounts *refcount = &hvs->upm_refcounts[upm_handle];
321 unsigned long irqflags;
323 spin_lock_irqsave(&hvs->mm_lock, irqflags);
324 drm_mm_remove_node(&refcount->upm);
325 spin_unlock_irqrestore(&hvs->mm_lock, irqflags);
326 refcount->upm.start = 0;
327 refcount->upm.size = 0;
330 ida_free(&hvs->upm_handles, upm_handle);
333 static void vc4_plane_destroy_state(struct drm_plane *plane,
334 struct drm_plane_state *state)
336 struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
337 struct vc4_hvs *hvs = vc4->hvs;
338 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
341 if (drm_mm_node_allocated(&vc4_state->lbm)) {
342 unsigned long irqflags;
344 spin_lock_irqsave(&hvs->mm_lock, irqflags);
345 drm_mm_remove_node(&vc4_state->lbm);
346 spin_unlock_irqrestore(&hvs->mm_lock, irqflags);
349 for (i = 0; i < DRM_FORMAT_MAX_PLANES; i++) {
350 struct vc4_upm_refcounts *refcount;
352 if (!vc4_state->upm_handle[i])
355 refcount = &hvs->upm_refcounts[vc4_state->upm_handle[i]];
357 if (refcount_dec_and_test(&refcount->refcount))
358 vc4_plane_release_upm_ida(hvs, vc4_state->upm_handle[i]);
361 kfree(vc4_state->dlist);
362 __drm_atomic_helper_plane_destroy_state(&vc4_state->base);
366 /* Called during init to allocate the plane's atomic state. */
367 static void vc4_plane_reset(struct drm_plane *plane)
369 struct vc4_plane_state *vc4_state;
372 __drm_atomic_helper_plane_destroy_state(plane->state);
376 vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
380 __drm_atomic_helper_plane_reset(plane, &vc4_state->base);
383 static void vc4_dlist_counter_increment(struct vc4_plane_state *vc4_state)
385 if (vc4_state->dlist_count == vc4_state->dlist_size) {
386 u32 new_size = max(4u, vc4_state->dlist_count * 2);
387 u32 *new_dlist = kmalloc_array(new_size, 4, GFP_KERNEL);
391 memcpy(new_dlist, vc4_state->dlist, vc4_state->dlist_count * 4);
393 kfree(vc4_state->dlist);
394 vc4_state->dlist = new_dlist;
395 vc4_state->dlist_size = new_size;
398 vc4_state->dlist_count++;
401 static void vc4_dlist_write(struct vc4_plane_state *vc4_state, u32 val)
403 unsigned int idx = vc4_state->dlist_count;
405 vc4_dlist_counter_increment(vc4_state);
406 vc4_state->dlist[idx] = val;
409 /* Returns the scl0/scl1 field based on whether the dimensions need to
410 * be up/down/non-scaled.
412 * This is a replication of a table from the spec.
414 static u32 vc4_get_scl_field(struct drm_plane_state *state, int plane)
416 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
418 switch (vc4_state->x_scaling[plane] << 2 | vc4_state->y_scaling[plane]) {
419 case VC4_SCALING_PPF << 2 | VC4_SCALING_PPF:
420 return SCALER_CTL0_SCL_H_PPF_V_PPF;
421 case VC4_SCALING_TPZ << 2 | VC4_SCALING_PPF:
422 return SCALER_CTL0_SCL_H_TPZ_V_PPF;
423 case VC4_SCALING_PPF << 2 | VC4_SCALING_TPZ:
424 return SCALER_CTL0_SCL_H_PPF_V_TPZ;
425 case VC4_SCALING_TPZ << 2 | VC4_SCALING_TPZ:
426 return SCALER_CTL0_SCL_H_TPZ_V_TPZ;
427 case VC4_SCALING_PPF << 2 | VC4_SCALING_NONE:
428 return SCALER_CTL0_SCL_H_PPF_V_NONE;
429 case VC4_SCALING_NONE << 2 | VC4_SCALING_PPF:
430 return SCALER_CTL0_SCL_H_NONE_V_PPF;
431 case VC4_SCALING_NONE << 2 | VC4_SCALING_TPZ:
432 return SCALER_CTL0_SCL_H_NONE_V_TPZ;
433 case VC4_SCALING_TPZ << 2 | VC4_SCALING_NONE:
434 return SCALER_CTL0_SCL_H_TPZ_V_NONE;
436 case VC4_SCALING_NONE << 2 | VC4_SCALING_NONE:
437 /* The unity case is independently handled by
444 static int vc4_plane_margins_adj(struct drm_plane_state *pstate)
446 struct vc4_plane_state *vc4_pstate = to_vc4_plane_state(pstate);
447 unsigned int left, right, top, bottom, adjhdisplay, adjvdisplay;
448 struct drm_crtc_state *crtc_state;
450 crtc_state = drm_atomic_get_new_crtc_state(pstate->state,
453 vc4_crtc_get_margins(crtc_state, &left, &right, &top, &bottom);
454 if (!left && !right && !top && !bottom)
457 if (left + right >= crtc_state->mode.hdisplay ||
458 top + bottom >= crtc_state->mode.vdisplay)
461 adjhdisplay = crtc_state->mode.hdisplay - (left + right);
462 vc4_pstate->crtc_x = DIV_ROUND_CLOSEST(vc4_pstate->crtc_x *
464 crtc_state->mode.hdisplay);
465 vc4_pstate->crtc_x += left;
466 if (vc4_pstate->crtc_x > crtc_state->mode.hdisplay - right)
467 vc4_pstate->crtc_x = crtc_state->mode.hdisplay - right;
469 adjvdisplay = crtc_state->mode.vdisplay - (top + bottom);
470 vc4_pstate->crtc_y = DIV_ROUND_CLOSEST(vc4_pstate->crtc_y *
472 crtc_state->mode.vdisplay);
473 vc4_pstate->crtc_y += top;
474 if (vc4_pstate->crtc_y > crtc_state->mode.vdisplay - bottom)
475 vc4_pstate->crtc_y = crtc_state->mode.vdisplay - bottom;
477 vc4_pstate->crtc_w = DIV_ROUND_CLOSEST(vc4_pstate->crtc_w *
479 crtc_state->mode.hdisplay);
480 vc4_pstate->crtc_h = DIV_ROUND_CLOSEST(vc4_pstate->crtc_h *
482 crtc_state->mode.vdisplay);
484 if (!vc4_pstate->crtc_w || !vc4_pstate->crtc_h)
490 static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
492 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
493 struct drm_framebuffer *fb = state->fb;
494 int num_planes = fb->format->num_planes;
495 struct drm_crtc_state *crtc_state;
496 u32 h_subsample = fb->format->hsub;
497 u32 v_subsample = fb->format->vsub;
500 crtc_state = drm_atomic_get_existing_crtc_state(state->state,
503 DRM_DEBUG_KMS("Invalid crtc state\n");
507 ret = drm_atomic_helper_check_plane_state(state, crtc_state, 1,
508 INT_MAX, true, true);
512 vc4_state->src_x = state->src.x1;
513 vc4_state->src_y = state->src.y1;
514 vc4_state->src_w[0] = state->src.x2 - vc4_state->src_x;
515 vc4_state->src_h[0] = state->src.y2 - vc4_state->src_y;
517 vc4_state->crtc_x = state->dst.x1;
518 vc4_state->crtc_y = state->dst.y1;
519 vc4_state->crtc_w = state->dst.x2 - state->dst.x1;
520 vc4_state->crtc_h = state->dst.y2 - state->dst.y1;
522 ret = vc4_plane_margins_adj(state);
526 vc4_state->x_scaling[0] = vc4_get_scaling_mode(vc4_state->src_w[0],
528 vc4_state->y_scaling[0] = vc4_get_scaling_mode(vc4_state->src_h[0],
531 vc4_state->is_unity = (vc4_state->x_scaling[0] == VC4_SCALING_NONE &&
532 vc4_state->y_scaling[0] == VC4_SCALING_NONE);
534 if (num_planes > 1) {
535 vc4_state->is_yuv = true;
537 vc4_state->src_w[1] = vc4_state->src_w[0] / h_subsample;
538 vc4_state->src_h[1] = vc4_state->src_h[0] / v_subsample;
540 vc4_state->x_scaling[1] =
541 vc4_get_scaling_mode(vc4_state->src_w[1],
543 vc4_state->y_scaling[1] =
544 vc4_get_scaling_mode(vc4_state->src_h[1],
547 /* YUV conversion requires that horizontal scaling be enabled
548 * on the UV plane even if vc4_get_scaling_mode() returned
549 * VC4_SCALING_NONE (which can happen when the down-scaling
550 * ratio is 0.5). Let's force it to VC4_SCALING_PPF in this
553 if (vc4_state->x_scaling[1] == VC4_SCALING_NONE)
554 vc4_state->x_scaling[1] = VC4_SCALING_PPF;
556 /* Similarly UV needs vertical scaling to be enabled.
557 * Without this a 1:1 scaled YUV422 plane isn't rendered.
559 if (vc4_state->y_scaling[1] == VC4_SCALING_NONE)
560 vc4_state->y_scaling[1] = VC4_SCALING_PPF;
562 vc4_state->is_yuv = false;
563 vc4_state->x_scaling[1] = VC4_SCALING_NONE;
564 vc4_state->y_scaling[1] = VC4_SCALING_NONE;
570 static void vc4_write_tpz(struct vc4_plane_state *vc4_state, u32 src, u32 dst)
572 struct vc4_dev *vc4 = to_vc4_dev(vc4_state->base.plane->dev);
575 WARN_ON_ONCE(vc4->gen > VC4_GEN_6_D);
579 /* The specs note that while the reciprocal would be defined
580 * as (1<<32)/scale, ~0 is close enough.
584 vc4_dlist_write(vc4_state,
586 * The BCM2712 is lacking BIT(31) compared to
587 * the previous generations, but we don't use
590 VC4_SET_FIELD(scale, SCALER_TPZ0_SCALE) |
591 VC4_SET_FIELD(0, SCALER_TPZ0_IPHASE));
592 vc4_dlist_write(vc4_state,
593 VC4_SET_FIELD(recip, SCALER_TPZ1_RECIP));
596 /* phase magnitude bits */
599 static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst,
602 struct vc4_dev *vc4 = to_vc4_dev(vc4_state->base.plane->dev);
603 u32 scale = src / dst;
607 WARN_ON_ONCE(vc4->gen > VC4_GEN_6_D);
610 * Start the phase at 1/2 pixel from the 1st pixel at src_x.
615 * The phase is relative to scale_src->x, so shift it for
616 * display list's x value
618 offset = (xy & 0x1ffff) >> (16 - PHASE_BITS) >> 1;
619 offset += -(1 << PHASE_BITS >> 2);
622 * The phase is relative to scale_src->x, so shift it for
623 * display list's x value
625 offset = (xy & 0xffff) >> (16 - PHASE_BITS);
626 offset += -(1 << PHASE_BITS >> 1);
629 * This is a kludge to make sure the scaling factors are
630 * consistent with YUV's luma scaling. We lose 1-bit precision
637 * There may be a also small error introduced by precision of scale.
638 * Add half of that as a compromise
640 offset2 = src - dst * scale;
641 offset2 >>= 16 - PHASE_BITS;
642 phase = offset + (offset2 >> 1);
644 /* Ensure +ve values don't touch the sign bit, then truncate negative values */
645 if (phase >= 1 << PHASE_BITS)
646 phase = (1 << PHASE_BITS) - 1;
648 phase &= SCALER_PPF_IPHASE_MASK;
650 vc4_dlist_write(vc4_state,
652 VC4_SET_FIELD(scale, SCALER_PPF_SCALE) |
654 * The register layout documentation is slightly
655 * different to setup the phase in the BCM2712,
656 * but they seem equivalent.
658 VC4_SET_FIELD(phase, SCALER_PPF_IPHASE));
661 static u32 __vc4_lbm_size(struct drm_plane_state *state)
663 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
664 struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev);
668 /* LBM is not needed when there's no vertical scaling. */
669 if (vc4_state->y_scaling[0] == VC4_SCALING_NONE &&
670 vc4_state->y_scaling[1] == VC4_SCALING_NONE)
674 * This can be further optimized in the RGB/YUV444 case if the PPF
675 * decimation factor is between 0.5 and 1.0 by using crtc_w.
677 * It's not an issue though, since in that case since src_w[0] is going
678 * to be greater than or equal to crtc_w.
680 if (vc4_state->x_scaling[0] == VC4_SCALING_TPZ)
681 pix_per_line = vc4_state->crtc_w;
683 pix_per_line = vc4_state->src_w[0] >> 16;
685 if (!vc4_state->is_yuv) {
686 if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ)
687 lbm = pix_per_line * 8;
689 /* In special cases, this multiplier might be 12. */
690 lbm = pix_per_line * 16;
693 /* There are cases for this going down to a multiplier
694 * of 2, but according to the firmware source, the
695 * table in the docs is somewhat wrong.
697 lbm = pix_per_line * 16;
700 /* Align it to 64 or 128 (hvs5) bytes */
701 lbm = roundup(lbm, vc4->gen == VC4_GEN_5 ? 128 : 64);
703 /* Each "word" of the LBM memory contains 2 or 4 (hvs5) pixels */
704 lbm /= vc4->gen == VC4_GEN_5 ? 4 : 2;
709 static unsigned int vc4_lbm_words_per_component(const struct drm_plane_state *state,
710 unsigned int channel)
712 const struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
714 switch (vc4_state->y_scaling[channel]) {
715 case VC4_SCALING_PPF:
718 case VC4_SCALING_TPZ:
726 static unsigned int vc4_lbm_components(const struct drm_plane_state *state,
727 unsigned int channel)
729 const struct drm_format_info *info = state->fb->format;
730 const struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
732 if (vc4_state->y_scaling[channel] == VC4_SCALING_NONE)
736 return channel ? 2 : 1;
744 static unsigned int vc4_lbm_channel_size(const struct drm_plane_state *state,
745 unsigned int channel)
747 const struct drm_format_info *info = state->fb->format;
748 const struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
749 unsigned int channels_scaled = 0;
750 unsigned int components, words, wpc;
751 unsigned int width, lines;
754 /* LBM is meant to use the smaller of source or dest width, but there
755 * is a issue with UV scaling that the size required for the second
756 * channel is based on the source width only.
758 if (info->hsub > 1 && channel == 1)
759 width = state->src_w >> 16;
761 width = min(state->src_w >> 16, state->crtc_w);
762 width = round_up(width / info->hsub, 4);
764 wpc = vc4_lbm_words_per_component(state, channel);
768 components = vc4_lbm_components(state, channel);
772 if (state->alpha != DRM_BLEND_ALPHA_OPAQUE && info->has_alpha)
775 words = width * wpc * components;
777 lines = DIV_ROUND_UP(words, 128 / info->hsub);
779 for (i = 0; i < 2; i++)
780 if (vc4_state->y_scaling[channel] != VC4_SCALING_NONE)
783 if (channels_scaled == 1)
789 static unsigned int __vc6_lbm_size(const struct drm_plane_state *state)
791 const struct drm_format_info *info = state->fb->format;
794 return max(vc4_lbm_channel_size(state, 0),
795 vc4_lbm_channel_size(state, 1));
797 return vc4_lbm_channel_size(state, 0);
800 static u32 vc4_lbm_size(struct drm_plane_state *state)
802 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
803 struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev);
805 /* LBM is not needed when there's no vertical scaling. */
806 if (vc4_state->y_scaling[0] == VC4_SCALING_NONE &&
807 vc4_state->y_scaling[1] == VC4_SCALING_NONE)
810 if (vc4->gen >= VC4_GEN_6_C)
811 return __vc6_lbm_size(state);
813 return __vc4_lbm_size(state);
816 static size_t vc6_upm_size(const struct drm_plane_state *state,
819 const struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
820 unsigned int stride = state->fb->pitches[plane];
823 * TODO: This only works for raster formats, and is sub-optimal
824 * for buffers with a stride aligned on 32 bytes.
826 unsigned int words_per_line = (stride + 62) / 32;
827 unsigned int fetch_region_size = words_per_line * 32;
828 unsigned int buffer_lines = 2 << vc4_state->upm_buffer_lines;
829 unsigned int buffer_size = fetch_region_size * buffer_lines;
831 return ALIGN(buffer_size, HVS_UBM_WORD_SIZE);
834 static void vc4_write_scaling_parameters(struct drm_plane_state *state,
837 struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev);
838 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
840 WARN_ON_ONCE(vc4->gen > VC4_GEN_6_D);
842 /* Ch0 H-PPF Word 0: Scaling Parameters */
843 if (vc4_state->x_scaling[channel] == VC4_SCALING_PPF) {
844 vc4_write_ppf(vc4_state, vc4_state->src_w[channel],
845 vc4_state->crtc_w, vc4_state->src_x, channel);
848 /* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */
849 if (vc4_state->y_scaling[channel] == VC4_SCALING_PPF) {
850 vc4_write_ppf(vc4_state, vc4_state->src_h[channel],
851 vc4_state->crtc_h, vc4_state->src_y, channel);
852 vc4_dlist_write(vc4_state, 0xc0c0c0c0);
855 /* Ch0 H-TPZ Words 0-1: Scaling Parameters, Recip */
856 if (vc4_state->x_scaling[channel] == VC4_SCALING_TPZ) {
857 vc4_write_tpz(vc4_state, vc4_state->src_w[channel],
861 /* Ch0 V-TPZ Words 0-2: Scaling Parameters, Recip, Context */
862 if (vc4_state->y_scaling[channel] == VC4_SCALING_TPZ) {
863 vc4_write_tpz(vc4_state, vc4_state->src_h[channel],
865 vc4_dlist_write(vc4_state, 0xc0c0c0c0);
869 static void vc4_plane_calc_load(struct drm_plane_state *state)
871 unsigned int hvs_load_shift, vrefresh, i;
872 struct drm_framebuffer *fb = state->fb;
873 struct vc4_plane_state *vc4_state;
874 struct drm_crtc_state *crtc_state;
875 unsigned int vscale_factor;
877 vc4_state = to_vc4_plane_state(state);
878 crtc_state = drm_atomic_get_existing_crtc_state(state->state,
880 vrefresh = drm_mode_vrefresh(&crtc_state->adjusted_mode);
882 /* The HVS is able to process 2 pixels/cycle when scaling the source,
883 * 4 pixels/cycle otherwise.
884 * Alpha blending step seems to be pipelined and it's always operating
885 * at 4 pixels/cycle, so the limiting aspect here seems to be the
887 * HVS load is expressed in clk-cycles/sec (AKA Hz).
889 if (vc4_state->x_scaling[0] != VC4_SCALING_NONE ||
890 vc4_state->x_scaling[1] != VC4_SCALING_NONE ||
891 vc4_state->y_scaling[0] != VC4_SCALING_NONE ||
892 vc4_state->y_scaling[1] != VC4_SCALING_NONE)
897 vc4_state->membus_load = 0;
898 vc4_state->hvs_load = 0;
899 for (i = 0; i < fb->format->num_planes; i++) {
900 /* Even if the bandwidth/plane required for a single frame is
902 * (vc4_state->src_w[i] >> 16) * (vc4_state->src_h[i] >> 16) *
905 * when downscaling, we have to read more pixels per line in
906 * the time frame reserved for a single line, so the bandwidth
907 * demand can be punctually higher. To account for that, we
908 * calculate the down-scaling factor and multiply the plane
909 * load by this number. We're likely over-estimating the read
910 * demand, but that's better than under-estimating it.
912 vscale_factor = DIV_ROUND_UP(vc4_state->src_h[i] >> 16,
914 vc4_state->membus_load += (vc4_state->src_w[i] >> 16) *
915 (vc4_state->src_h[i] >> 16) *
916 vscale_factor * fb->format->cpp[i];
917 vc4_state->hvs_load += vc4_state->crtc_h * vc4_state->crtc_w;
920 vc4_state->hvs_load *= vrefresh;
921 vc4_state->hvs_load >>= hvs_load_shift;
922 vc4_state->membus_load *= vrefresh;
925 static int vc4_plane_allocate_lbm(struct drm_plane_state *state)
927 struct drm_device *drm = state->plane->dev;
928 struct vc4_dev *vc4 = to_vc4_dev(drm);
929 struct drm_plane *plane = state->plane;
930 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
931 unsigned long irqflags;
934 lbm_size = vc4_lbm_size(state);
939 * NOTE: BCM2712 doesn't need to be aligned, since the size
940 * returned by vc4_lbm_size() is in words already.
942 if (vc4->gen == VC4_GEN_5)
943 lbm_size = ALIGN(lbm_size, 64);
944 else if (vc4->gen == VC4_GEN_4)
945 lbm_size = ALIGN(lbm_size, 32);
947 drm_dbg_driver(drm, "[PLANE:%d:%s] LBM Allocation Size: %u\n",
948 plane->base.id, plane->name, lbm_size);
950 if (WARN_ON(!vc4_state->lbm_offset))
953 /* Allocate the LBM memory that the HVS will use for temporary
954 * storage due to our scaling/format conversion.
956 if (!drm_mm_node_allocated(&vc4_state->lbm)) {
959 spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags);
960 ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm,
964 spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags);
967 drm_err(drm, "Failed to allocate LBM entry: %d\n", ret);
971 WARN_ON_ONCE(lbm_size != vc4_state->lbm.size);
974 vc4_state->dlist[vc4_state->lbm_offset] = vc4_state->lbm.start;
979 static int vc6_plane_allocate_upm(struct drm_plane_state *state)
981 const struct drm_format_info *info = state->fb->format;
982 struct drm_device *drm = state->plane->dev;
983 struct vc4_dev *vc4 = to_vc4_dev(drm);
984 struct vc4_hvs *hvs = vc4->hvs;
985 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
989 WARN_ON_ONCE(vc4->gen < VC4_GEN_6_C);
991 vc4_state->upm_buffer_lines = SCALER6_PTR0_UPM_BUFF_SIZE_2_LINES;
993 for (i = 0; i < info->num_planes; i++) {
994 struct vc4_upm_refcounts *refcount;
996 unsigned long irqflags;
999 upm_size = vc6_upm_size(state, i);
1002 upm_handle = vc4_state->upm_handle[i];
1005 hvs->upm_refcounts[upm_handle].size == upm_size) {
1006 /* Allocation is the same size as the previous user of
1007 * the plane. Keep the allocation.
1009 vc4_state->upm_handle[i] = upm_handle;
1012 refcount_dec_and_test(&hvs->upm_refcounts[upm_handle].refcount)) {
1013 vc4_plane_release_upm_ida(hvs, upm_handle);
1014 vc4_state->upm_handle[i] = 0;
1017 upm_handle = ida_alloc_range(&hvs->upm_handles, 1,
1018 VC4_NUM_UPM_HANDLES,
1020 if (upm_handle < 0) {
1021 drm_dbg(drm, "Out of upm_handles\n");
1024 vc4_state->upm_handle[i] = upm_handle;
1026 refcount = &hvs->upm_refcounts[upm_handle];
1027 refcount_set(&refcount->refcount, 1);
1028 refcount->size = upm_size;
1030 spin_lock_irqsave(&hvs->mm_lock, irqflags);
1031 ret = drm_mm_insert_node_generic(&hvs->upm_mm,
1033 upm_size, HVS_UBM_WORD_SIZE,
1035 spin_unlock_irqrestore(&hvs->mm_lock, irqflags);
1037 drm_err(drm, "Failed to allocate UPM entry: %d\n", ret);
1038 refcount_set(&refcount->refcount, 0);
1039 ida_free(&hvs->upm_handles, upm_handle);
1040 vc4_state->upm_handle[i] = 0;
1045 refcount = &hvs->upm_refcounts[upm_handle];
1046 vc4_state->dlist[vc4_state->ptr0_offset[i]] |=
1047 VC4_SET_FIELD(refcount->upm.start / HVS_UBM_WORD_SIZE,
1048 SCALER6_PTR0_UPM_BASE) |
1049 VC4_SET_FIELD(vc4_state->upm_handle[i] - 1,
1050 SCALER6_PTR0_UPM_HANDLE) |
1051 VC4_SET_FIELD(vc4_state->upm_buffer_lines,
1052 SCALER6_PTR0_UPM_BUFF_SIZE);
1058 static void vc6_plane_free_upm(struct drm_plane_state *state)
1060 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
1061 struct drm_device *drm = state->plane->dev;
1062 struct vc4_dev *vc4 = to_vc4_dev(drm);
1063 struct vc4_hvs *hvs = vc4->hvs;
1066 WARN_ON_ONCE(vc4->gen < VC4_GEN_6_C);
1068 for (i = 0; i < DRM_FORMAT_MAX_PLANES; i++) {
1069 unsigned int upm_handle;
1071 upm_handle = vc4_state->upm_handle[i];
1075 if (refcount_dec_and_test(&hvs->upm_refcounts[upm_handle].refcount))
1076 vc4_plane_release_upm_ida(hvs, upm_handle);
1077 vc4_state->upm_handle[i] = 0;
1082 * The colorspace conversion matrices are held in 3 entries in the dlist.
1083 * Create an array of them, with entries for each full and limited mode, and
1084 * each supported colorspace.
1086 static const u32 colorspace_coeffs[2][DRM_COLOR_ENCODING_MAX][3] = {
1091 SCALER_CSC0_ITR_R_601_5,
1092 SCALER_CSC1_ITR_R_601_5,
1093 SCALER_CSC2_ITR_R_601_5,
1096 SCALER_CSC0_ITR_R_709_3,
1097 SCALER_CSC1_ITR_R_709_3,
1098 SCALER_CSC2_ITR_R_709_3,
1101 SCALER_CSC0_ITR_R_2020,
1102 SCALER_CSC1_ITR_R_2020,
1103 SCALER_CSC2_ITR_R_2020,
1109 SCALER_CSC0_JPEG_JFIF,
1110 SCALER_CSC1_JPEG_JFIF,
1111 SCALER_CSC2_JPEG_JFIF,
1114 SCALER_CSC0_ITR_R_709_3_FR,
1115 SCALER_CSC1_ITR_R_709_3_FR,
1116 SCALER_CSC2_ITR_R_709_3_FR,
1119 SCALER_CSC0_ITR_R_2020_FR,
1120 SCALER_CSC1_ITR_R_2020_FR,
1121 SCALER_CSC2_ITR_R_2020_FR,
1126 static u32 vc4_hvs4_get_alpha_blend_mode(struct drm_plane_state *state)
1128 struct drm_device *dev = state->state->dev;
1129 struct vc4_dev *vc4 = to_vc4_dev(dev);
1131 WARN_ON_ONCE(vc4->gen != VC4_GEN_4);
1133 if (!state->fb->format->has_alpha)
1134 return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_FIXED,
1135 SCALER_POS2_ALPHA_MODE);
1137 switch (state->pixel_blend_mode) {
1138 case DRM_MODE_BLEND_PIXEL_NONE:
1139 return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_FIXED,
1140 SCALER_POS2_ALPHA_MODE);
1142 case DRM_MODE_BLEND_PREMULTI:
1143 return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_PIPELINE,
1144 SCALER_POS2_ALPHA_MODE) |
1145 SCALER_POS2_ALPHA_PREMULT;
1146 case DRM_MODE_BLEND_COVERAGE:
1147 return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_PIPELINE,
1148 SCALER_POS2_ALPHA_MODE);
1152 static u32 vc4_hvs5_get_alpha_blend_mode(struct drm_plane_state *state)
1154 struct drm_device *dev = state->state->dev;
1155 struct vc4_dev *vc4 = to_vc4_dev(dev);
1157 WARN_ON_ONCE(vc4->gen != VC4_GEN_5 && vc4->gen != VC4_GEN_6_C &&
1158 vc4->gen != VC4_GEN_6_D);
1164 if (!state->fb->format->has_alpha)
1165 return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_FIXED,
1166 SCALER5_CTL2_ALPHA_MODE);
1168 switch (state->pixel_blend_mode) {
1169 case DRM_MODE_BLEND_PIXEL_NONE:
1170 return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_FIXED,
1171 SCALER5_CTL2_ALPHA_MODE);
1173 case DRM_MODE_BLEND_PREMULTI:
1174 return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_PIPELINE,
1175 SCALER5_CTL2_ALPHA_MODE) |
1176 SCALER5_CTL2_ALPHA_PREMULT;
1177 case DRM_MODE_BLEND_COVERAGE:
1178 return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_PIPELINE,
1179 SCALER5_CTL2_ALPHA_MODE);
1182 /* 2712-D configures fixed alpha mode in CTL0 */
1183 return state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI ?
1184 SCALER5_CTL2_ALPHA_PREMULT : 0;
1188 static u32 vc4_hvs6_get_alpha_mask_mode(struct drm_plane_state *state)
1190 struct drm_device *dev = state->state->dev;
1191 struct vc4_dev *vc4 = to_vc4_dev(dev);
1193 WARN_ON_ONCE(vc4->gen != VC4_GEN_6_C && vc4->gen != VC4_GEN_6_D);
1195 if (vc4->gen == VC4_GEN_6_D &&
1196 (!state->fb->format->has_alpha ||
1197 state->pixel_blend_mode == DRM_MODE_BLEND_PIXEL_NONE))
1198 return VC4_SET_FIELD(SCALER6D_CTL0_ALPHA_MASK_FIXED,
1199 SCALER6_CTL0_ALPHA_MASK);
1201 return VC4_SET_FIELD(SCALER6_CTL0_ALPHA_MASK_NONE, SCALER6_CTL0_ALPHA_MASK);
1204 /* Writes out a full display list for an active plane to the plane's
1205 * private dlist state.
1207 static int vc4_plane_mode_set(struct drm_plane *plane,
1208 struct drm_plane_state *state)
1210 struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
1211 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
1212 struct drm_framebuffer *fb = state->fb;
1213 u32 ctl0_offset = vc4_state->dlist_count;
1214 const struct hvs_format *format = vc4_get_hvs_format(fb->format->format);
1215 u64 base_format_mod = fourcc_mod_broadcom_mod(fb->modifier);
1216 int num_planes = fb->format->num_planes;
1217 u32 h_subsample = fb->format->hsub;
1218 u32 v_subsample = fb->format->vsub;
1219 bool mix_plane_alpha;
1221 u32 scl0, scl1, pitch0;
1222 u32 tiling, src_x, src_y;
1224 u32 hvs_format = format->hvs;
1225 unsigned int rotation;
1226 u32 offsets[3] = { 0 };
1229 if (vc4_state->dlist_initialized)
1232 ret = vc4_plane_setup_clipping_and_scaling(state);
1236 if (!vc4_state->src_w[0] || !vc4_state->src_h[0] ||
1237 !vc4_state->crtc_w || !vc4_state->crtc_h) {
1238 /* 0 source size probably means the plane is offscreen */
1239 vc4_state->dlist_initialized = 1;
1243 width = vc4_state->src_w[0] >> 16;
1244 height = vc4_state->src_h[0] >> 16;
1246 /* SCL1 is used for Cb/Cr scaling of planar formats. For RGB
1247 * and 4:4:4, scl1 should be set to scl0 so both channels of
1248 * the scaler do the same thing. For YUV, the Y plane needs
1249 * to be put in channel 1 and Cb/Cr in channel 0, so we swap
1250 * the scl fields here.
1252 if (num_planes == 1) {
1253 scl0 = vc4_get_scl_field(state, 0);
1256 scl0 = vc4_get_scl_field(state, 1);
1257 scl1 = vc4_get_scl_field(state, 0);
1260 rotation = drm_rotation_simplify(state->rotation,
1262 DRM_MODE_REFLECT_X |
1263 DRM_MODE_REFLECT_Y);
1265 /* We must point to the last line when Y reflection is enabled. */
1266 src_y = vc4_state->src_y >> 16;
1267 if (rotation & DRM_MODE_REFLECT_Y)
1268 src_y += height - 1;
1270 src_x = vc4_state->src_x >> 16;
1272 switch (base_format_mod) {
1273 case DRM_FORMAT_MOD_LINEAR:
1274 tiling = SCALER_CTL0_TILING_LINEAR;
1275 pitch0 = VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH);
1277 /* Adjust the base pointer to the first pixel to be scanned
1280 for (i = 0; i < num_planes; i++) {
1281 offsets[i] += src_y / (i ? v_subsample : 1) * fb->pitches[i];
1282 offsets[i] += src_x / (i ? h_subsample : 1) * fb->format->cpp[i];
1287 case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: {
1288 u32 tile_size_shift = 12; /* T tiles are 4kb */
1289 /* Whole-tile offsets, mostly for setting the pitch. */
1290 u32 tile_w_shift = fb->format->cpp[0] == 2 ? 6 : 5;
1291 u32 tile_h_shift = 5; /* 16 and 32bpp are 32 pixels high */
1292 u32 tile_w_mask = (1 << tile_w_shift) - 1;
1293 /* The height mask on 32-bit-per-pixel tiles is 63, i.e. twice
1294 * the height (in pixels) of a 4k tile.
1296 u32 tile_h_mask = (2 << tile_h_shift) - 1;
1297 /* For T-tiled, the FB pitch is "how many bytes from one row to
1298 * the next, such that
1300 * pitch * tile_h == tile_size * tiles_per_row
1302 u32 tiles_w = fb->pitches[0] >> (tile_size_shift - tile_h_shift);
1303 u32 tiles_l = src_x >> tile_w_shift;
1304 u32 tiles_r = tiles_w - tiles_l;
1305 u32 tiles_t = src_y >> tile_h_shift;
1306 /* Intra-tile offsets, which modify the base address (the
1307 * SCALER_PITCH0_TILE_Y_OFFSET tells HVS how to walk from that
1310 u32 tile_y = (src_y >> 4) & 1;
1311 u32 subtile_y = (src_y >> 2) & 3;
1312 u32 utile_y = src_y & 3;
1313 u32 x_off = src_x & tile_w_mask;
1314 u32 y_off = src_y & tile_h_mask;
1316 /* When Y reflection is requested we must set the
1317 * SCALER_PITCH0_TILE_LINE_DIR flag to tell HVS that all lines
1318 * after the initial one should be fetched in descending order,
1319 * which makes sense since we start from the last line and go
1321 * Don't know why we need y_off = max_y_off - y_off, but it's
1322 * definitely required (I guess it's also related to the "going
1323 * backward" situation).
1325 if (rotation & DRM_MODE_REFLECT_Y) {
1326 y_off = tile_h_mask - y_off;
1327 pitch0 = SCALER_PITCH0_TILE_LINE_DIR;
1332 tiling = SCALER_CTL0_TILING_256B_OR_T;
1333 pitch0 |= (VC4_SET_FIELD(x_off, SCALER_PITCH0_SINK_PIX) |
1334 VC4_SET_FIELD(y_off, SCALER_PITCH0_TILE_Y_OFFSET) |
1335 VC4_SET_FIELD(tiles_l, SCALER_PITCH0_TILE_WIDTH_L) |
1336 VC4_SET_FIELD(tiles_r, SCALER_PITCH0_TILE_WIDTH_R));
1337 offsets[0] += tiles_t * (tiles_w << tile_size_shift);
1338 offsets[0] += subtile_y << 8;
1339 offsets[0] += utile_y << 4;
1341 /* Rows of tiles alternate left-to-right and right-to-left. */
1343 pitch0 |= SCALER_PITCH0_TILE_INITIAL_LINE_DIR;
1344 offsets[0] += (tiles_w - tiles_l) << tile_size_shift;
1345 offsets[0] -= (1 + !tile_y) << 10;
1347 offsets[0] += tiles_l << tile_size_shift;
1348 offsets[0] += tile_y << 10;
1354 case DRM_FORMAT_MOD_BROADCOM_SAND64:
1355 case DRM_FORMAT_MOD_BROADCOM_SAND128:
1356 case DRM_FORMAT_MOD_BROADCOM_SAND256: {
1357 uint32_t param = fourcc_mod_broadcom_param(fb->modifier);
1359 if (param > SCALER_TILE_HEIGHT_MASK) {
1360 DRM_DEBUG_KMS("SAND height too large (%d)\n",
1365 if (fb->format->format == DRM_FORMAT_P030) {
1366 hvs_format = HVS_PIXEL_FORMAT_YCBCR_10BIT;
1367 tiling = SCALER_CTL0_TILING_128B;
1369 hvs_format = HVS_PIXEL_FORMAT_H264;
1371 switch (base_format_mod) {
1372 case DRM_FORMAT_MOD_BROADCOM_SAND64:
1373 tiling = SCALER_CTL0_TILING_64B;
1375 case DRM_FORMAT_MOD_BROADCOM_SAND128:
1376 tiling = SCALER_CTL0_TILING_128B;
1378 case DRM_FORMAT_MOD_BROADCOM_SAND256:
1379 tiling = SCALER_CTL0_TILING_256B_OR_T;
1386 /* Adjust the base pointer to the first pixel to be scanned
1389 * For P030, y_ptr [31:4] is the 128bit word for the start pixel
1390 * y_ptr [3:0] is the pixel (0-11) contained within that 128bit
1391 * word that should be taken as the first pixel.
1392 * Ditto uv_ptr [31:4] vs [3:0], however [3:0] contains the
1393 * element within the 128bit word, eg for pixel 3 the value
1396 for (i = 0; i < num_planes; i++) {
1397 u32 tile_w, tile, x_off, pix_per_tile;
1399 if (fb->format->format == DRM_FORMAT_P030) {
1401 * Spec says: bits [31:4] of the given address
1402 * should point to the 128-bit word containing
1403 * the desired starting pixel, and bits[3:0]
1404 * should be between 0 and 11, indicating which
1405 * of the 12-pixels in that 128-bit word is the
1406 * first pixel to be used
1408 u32 remaining_pixels = src_x % 96;
1409 u32 aligned = remaining_pixels / 12;
1410 u32 last_bits = remaining_pixels % 12;
1412 x_off = aligned * 16 + last_bits;
1416 switch (base_format_mod) {
1417 case DRM_FORMAT_MOD_BROADCOM_SAND64:
1420 case DRM_FORMAT_MOD_BROADCOM_SAND128:
1423 case DRM_FORMAT_MOD_BROADCOM_SAND256:
1429 pix_per_tile = tile_w / fb->format->cpp[0];
1430 x_off = (src_x % pix_per_tile) /
1431 (i ? h_subsample : 1) *
1435 tile = src_x / pix_per_tile;
1437 offsets[i] += param * tile_w * tile;
1438 offsets[i] += src_y / (i ? v_subsample : 1) * tile_w;
1439 offsets[i] += x_off & ~(i ? 1 : 0);
1442 pitch0 = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT);
1447 DRM_DEBUG_KMS("Unsupported FB tiling flag 0x%16llx",
1448 (long long)fb->modifier);
1452 /* fetch an extra pixel if we don't actually line up with the left edge. */
1453 if ((vc4_state->src_x & 0xffff) && vc4_state->src_x < (state->fb->width << 16))
1456 /* same for the right side */
1457 if (((vc4_state->src_x + vc4_state->src_w[0]) & 0xffff) &&
1458 vc4_state->src_x + vc4_state->src_w[0] < (state->fb->width << 16))
1461 /* now for the top */
1462 if ((vc4_state->src_y & 0xffff) && vc4_state->src_y < (state->fb->height << 16))
1465 /* and the bottom */
1466 if (((vc4_state->src_y + vc4_state->src_h[0]) & 0xffff) &&
1467 vc4_state->src_y + vc4_state->src_h[0] < (state->fb->height << 16))
1470 /* For YUV444 the hardware wants double the width, otherwise it doesn't
1471 * fetch full width of chroma
1473 if (format->drm == DRM_FORMAT_YUV444 || format->drm == DRM_FORMAT_YVU444)
1476 /* Don't waste cycles mixing with plane alpha if the set alpha
1477 * is opaque or there is no per-pixel alpha information.
1478 * In any case we use the alpha property value as the fixed alpha.
1480 mix_plane_alpha = state->alpha != DRM_BLEND_ALPHA_OPAQUE &&
1481 fb->format->has_alpha;
1483 if (vc4->gen == VC4_GEN_4) {
1485 vc4_dlist_write(vc4_state,
1487 (rotation & DRM_MODE_REFLECT_X ? SCALER_CTL0_HFLIP : 0) |
1488 (rotation & DRM_MODE_REFLECT_Y ? SCALER_CTL0_VFLIP : 0) |
1489 VC4_SET_FIELD(SCALER_CTL0_RGBA_EXPAND_ROUND, SCALER_CTL0_RGBA_EXPAND) |
1490 (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) |
1491 (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
1492 VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) |
1493 (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) |
1494 VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |
1495 VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1));
1497 /* Position Word 0: Image Positions and Alpha Value */
1498 vc4_state->pos0_offset = vc4_state->dlist_count;
1499 vc4_dlist_write(vc4_state,
1500 VC4_SET_FIELD(state->alpha >> 8, SCALER_POS0_FIXED_ALPHA) |
1501 VC4_SET_FIELD(vc4_state->crtc_x, SCALER_POS0_START_X) |
1502 VC4_SET_FIELD(vc4_state->crtc_y, SCALER_POS0_START_Y));
1504 /* Position Word 1: Scaled Image Dimensions. */
1505 if (!vc4_state->is_unity) {
1506 vc4_dlist_write(vc4_state,
1507 VC4_SET_FIELD(vc4_state->crtc_w,
1508 SCALER_POS1_SCL_WIDTH) |
1509 VC4_SET_FIELD(vc4_state->crtc_h,
1510 SCALER_POS1_SCL_HEIGHT));
1513 /* Position Word 2: Source Image Size, Alpha */
1514 vc4_state->pos2_offset = vc4_state->dlist_count;
1515 vc4_dlist_write(vc4_state,
1516 (mix_plane_alpha ? SCALER_POS2_ALPHA_MIX : 0) |
1517 vc4_hvs4_get_alpha_blend_mode(state) |
1518 VC4_SET_FIELD(width, SCALER_POS2_WIDTH) |
1519 VC4_SET_FIELD(height, SCALER_POS2_HEIGHT));
1521 /* Position Word 3: Context. Written by the HVS. */
1522 vc4_dlist_write(vc4_state, 0xc0c0c0c0);
1526 vc4_dlist_write(vc4_state,
1528 (format->pixel_order_hvs5 << SCALER_CTL0_ORDER_SHIFT) |
1529 (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
1530 VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) |
1531 (vc4_state->is_unity ?
1532 SCALER5_CTL0_UNITY : 0) |
1533 VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |
1534 VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1) |
1535 SCALER5_CTL0_ALPHA_EXPAND |
1536 SCALER5_CTL0_RGB_EXPAND);
1538 /* Position Word 0: Image Positions and Alpha Value */
1539 vc4_state->pos0_offset = vc4_state->dlist_count;
1540 vc4_dlist_write(vc4_state,
1541 (rotation & DRM_MODE_REFLECT_Y ?
1542 SCALER5_POS0_VFLIP : 0) |
1543 VC4_SET_FIELD(vc4_state->crtc_x,
1544 SCALER_POS0_START_X) |
1545 (rotation & DRM_MODE_REFLECT_X ?
1546 SCALER5_POS0_HFLIP : 0) |
1547 VC4_SET_FIELD(vc4_state->crtc_y,
1548 SCALER5_POS0_START_Y)
1551 /* Control Word 2 */
1552 vc4_dlist_write(vc4_state,
1553 VC4_SET_FIELD(state->alpha >> 4,
1554 SCALER5_CTL2_ALPHA) |
1555 vc4_hvs5_get_alpha_blend_mode(state) |
1557 SCALER5_CTL2_ALPHA_MIX : 0)
1560 /* Position Word 1: Scaled Image Dimensions. */
1561 if (!vc4_state->is_unity) {
1562 vc4_dlist_write(vc4_state,
1563 VC4_SET_FIELD(vc4_state->crtc_w,
1564 SCALER5_POS1_SCL_WIDTH) |
1565 VC4_SET_FIELD(vc4_state->crtc_h,
1566 SCALER5_POS1_SCL_HEIGHT));
1569 /* Position Word 2: Source Image Size */
1570 vc4_state->pos2_offset = vc4_state->dlist_count;
1571 vc4_dlist_write(vc4_state,
1572 VC4_SET_FIELD(width, SCALER5_POS2_WIDTH) |
1573 VC4_SET_FIELD(height, SCALER5_POS2_HEIGHT));
1575 /* Position Word 3: Context. Written by the HVS. */
1576 vc4_dlist_write(vc4_state, 0xc0c0c0c0);
1580 /* Pointer Word 0/1/2: RGB / Y / Cb / Cr Pointers
1582 * The pointers may be any byte address.
1584 vc4_state->ptr0_offset[0] = vc4_state->dlist_count;
1586 for (i = 0; i < num_planes; i++) {
1587 struct drm_gem_dma_object *bo = drm_fb_dma_get_gem_obj(fb, i);
1589 vc4_dlist_write(vc4_state, bo->dma_addr + fb->offsets[i] + offsets[i]);
1592 /* Pointer Context Word 0/1/2: Written by the HVS */
1593 for (i = 0; i < num_planes; i++)
1594 vc4_dlist_write(vc4_state, 0xc0c0c0c0);
1597 vc4_dlist_write(vc4_state, pitch0);
1599 /* Pitch word 1/2 */
1600 for (i = 1; i < num_planes; i++) {
1601 if (hvs_format != HVS_PIXEL_FORMAT_H264 &&
1602 hvs_format != HVS_PIXEL_FORMAT_YCBCR_10BIT) {
1603 vc4_dlist_write(vc4_state,
1604 VC4_SET_FIELD(fb->pitches[i],
1607 vc4_dlist_write(vc4_state, pitch0);
1611 /* Colorspace conversion words */
1612 if (vc4_state->is_yuv) {
1613 enum drm_color_encoding color_encoding = state->color_encoding;
1614 enum drm_color_range color_range = state->color_range;
1617 if (color_encoding >= DRM_COLOR_ENCODING_MAX)
1618 color_encoding = DRM_COLOR_YCBCR_BT601;
1619 if (color_range >= DRM_COLOR_RANGE_MAX)
1620 color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
1622 ccm = colorspace_coeffs[color_range][color_encoding];
1624 vc4_dlist_write(vc4_state, ccm[0]);
1625 vc4_dlist_write(vc4_state, ccm[1]);
1626 vc4_dlist_write(vc4_state, ccm[2]);
1629 vc4_state->lbm_offset = 0;
1631 if (vc4_state->x_scaling[0] != VC4_SCALING_NONE ||
1632 vc4_state->x_scaling[1] != VC4_SCALING_NONE ||
1633 vc4_state->y_scaling[0] != VC4_SCALING_NONE ||
1634 vc4_state->y_scaling[1] != VC4_SCALING_NONE) {
1635 /* Reserve a slot for the LBM Base Address. The real value will
1636 * be set when calling vc4_plane_allocate_lbm().
1638 if (vc4_state->y_scaling[0] != VC4_SCALING_NONE ||
1639 vc4_state->y_scaling[1] != VC4_SCALING_NONE) {
1640 vc4_state->lbm_offset = vc4_state->dlist_count;
1641 vc4_dlist_counter_increment(vc4_state);
1644 if (num_planes > 1) {
1645 /* Emit Cb/Cr as channel 0 and Y as channel
1646 * 1. This matches how we set up scl0/scl1
1649 vc4_write_scaling_parameters(state, 1);
1651 vc4_write_scaling_parameters(state, 0);
1653 /* If any PPF setup was done, then all the kernel
1654 * pointers get uploaded.
1656 if (vc4_state->x_scaling[0] == VC4_SCALING_PPF ||
1657 vc4_state->y_scaling[0] == VC4_SCALING_PPF ||
1658 vc4_state->x_scaling[1] == VC4_SCALING_PPF ||
1659 vc4_state->y_scaling[1] == VC4_SCALING_PPF) {
1660 u32 kernel = VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start,
1661 SCALER_PPF_KERNEL_OFFSET);
1664 vc4_dlist_write(vc4_state, kernel);
1666 vc4_dlist_write(vc4_state, kernel);
1668 vc4_dlist_write(vc4_state, kernel);
1670 vc4_dlist_write(vc4_state, kernel);
1674 vc4_state->dlist[ctl0_offset] |=
1675 VC4_SET_FIELD(vc4_state->dlist_count, SCALER_CTL0_SIZE);
1677 /* crtc_* are already clipped coordinates. */
1678 covers_screen = vc4_state->crtc_x == 0 && vc4_state->crtc_y == 0 &&
1679 vc4_state->crtc_w == state->crtc->mode.hdisplay &&
1680 vc4_state->crtc_h == state->crtc->mode.vdisplay;
1681 /* Background fill might be necessary when the plane has per-pixel
1682 * alpha content or a non-opaque plane alpha and could blend from the
1683 * background or does not cover the entire screen.
1685 vc4_state->needs_bg_fill = fb->format->has_alpha || !covers_screen ||
1686 state->alpha != DRM_BLEND_ALPHA_OPAQUE;
1688 /* Flag the dlist as initialized to avoid checking it twice in case
1689 * the async update check already called vc4_plane_mode_set() and
1690 * decided to fallback to sync update because async update was not
1693 vc4_state->dlist_initialized = 1;
1695 vc4_plane_calc_load(state);
1700 static u32 vc6_plane_get_csc_mode(struct vc4_plane_state *vc4_state)
1702 struct drm_plane_state *state = &vc4_state->base;
1703 struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev);
1706 if (vc4_state->is_yuv) {
1707 enum drm_color_encoding color_encoding = state->color_encoding;
1708 enum drm_color_range color_range = state->color_range;
1710 /* CSC pre-loaded with:
1711 * 0 = BT601 limited range
1712 * 1 = BT709 limited range
1713 * 2 = BT2020 limited range
1714 * 3 = BT601 full range
1715 * 4 = BT709 full range
1716 * 5 = BT2020 full range
1718 if (color_encoding > DRM_COLOR_YCBCR_BT2020)
1719 color_encoding = DRM_COLOR_YCBCR_BT601;
1720 if (color_range > DRM_COLOR_YCBCR_FULL_RANGE)
1721 color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
1723 if (vc4->gen == VC4_GEN_6_C) {
1724 ret |= SCALER6C_CTL2_CSC_ENABLE;
1725 ret |= VC4_SET_FIELD(color_encoding + (color_range * 3),
1726 SCALER6C_CTL2_BRCM_CFC_CONTROL);
1728 ret |= SCALER6D_CTL2_CSC_ENABLE;
1729 ret |= VC4_SET_FIELD(color_encoding + (color_range * 3),
1730 SCALER6D_CTL2_BRCM_CFC_CONTROL);
1737 static int vc6_plane_mode_set(struct drm_plane *plane,
1738 struct drm_plane_state *state)
1740 struct drm_device *drm = plane->dev;
1741 struct vc4_dev *vc4 = to_vc4_dev(drm);
1742 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
1743 struct drm_framebuffer *fb = state->fb;
1744 const struct hvs_format *format = vc4_get_hvs_format(fb->format->format);
1745 u64 base_format_mod = fourcc_mod_broadcom_mod(fb->modifier);
1746 int num_planes = fb->format->num_planes;
1747 u32 h_subsample = fb->format->hsub;
1748 u32 v_subsample = fb->format->vsub;
1749 bool mix_plane_alpha;
1751 u32 scl0, scl1, pitch0;
1752 u32 tiling, src_x, src_y;
1754 u32 hvs_format = format->hvs;
1755 u32 offsets[3] = { 0 };
1756 unsigned int rotation;
1759 if (vc4_state->dlist_initialized)
1762 ret = vc4_plane_setup_clipping_and_scaling(state);
1766 if (!vc4_state->src_w[0] || !vc4_state->src_h[0] ||
1767 !vc4_state->crtc_w || !vc4_state->crtc_h) {
1768 /* 0 source size probably means the plane is offscreen.
1769 * 0 destination size is a redundant plane.
1771 vc4_state->dlist_initialized = 1;
1775 width = vc4_state->src_w[0] >> 16;
1776 height = vc4_state->src_h[0] >> 16;
1778 /* SCL1 is used for Cb/Cr scaling of planar formats. For RGB
1779 * and 4:4:4, scl1 should be set to scl0 so both channels of
1780 * the scaler do the same thing. For YUV, the Y plane needs
1781 * to be put in channel 1 and Cb/Cr in channel 0, so we swap
1782 * the scl fields here.
1784 if (num_planes == 1) {
1785 scl0 = vc4_get_scl_field(state, 0);
1788 scl0 = vc4_get_scl_field(state, 1);
1789 scl1 = vc4_get_scl_field(state, 0);
1792 rotation = drm_rotation_simplify(state->rotation,
1794 DRM_MODE_REFLECT_X |
1795 DRM_MODE_REFLECT_Y);
1797 /* We must point to the last line when Y reflection is enabled. */
1798 src_y = vc4_state->src_y >> 16;
1799 if (rotation & DRM_MODE_REFLECT_Y)
1800 src_y += height - 1;
1802 src_x = vc4_state->src_x >> 16;
1804 switch (base_format_mod) {
1805 case DRM_FORMAT_MOD_LINEAR:
1806 tiling = SCALER6_CTL0_ADDR_MODE_LINEAR;
1808 /* Adjust the base pointer to the first pixel to be scanned
1811 for (i = 0; i < num_planes; i++) {
1812 offsets[i] += src_y / (i ? v_subsample : 1) * fb->pitches[i];
1813 offsets[i] += src_x / (i ? h_subsample : 1) * fb->format->cpp[i];
1818 case DRM_FORMAT_MOD_BROADCOM_SAND128:
1819 case DRM_FORMAT_MOD_BROADCOM_SAND256: {
1820 uint32_t param = fourcc_mod_broadcom_param(fb->modifier);
1821 u32 components_per_word;
1822 u32 starting_offset;
1825 if (param > SCALER_TILE_HEIGHT_MASK) {
1826 DRM_DEBUG_KMS("SAND height too large (%d)\n",
1831 if (fb->format->format == DRM_FORMAT_P030) {
1832 hvs_format = HVS_PIXEL_FORMAT_YCBCR_10BIT;
1833 tiling = SCALER6_CTL0_ADDR_MODE_128B;
1835 hvs_format = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE;
1837 switch (base_format_mod) {
1838 case DRM_FORMAT_MOD_BROADCOM_SAND128:
1839 tiling = SCALER6_CTL0_ADDR_MODE_128B;
1841 case DRM_FORMAT_MOD_BROADCOM_SAND256:
1842 tiling = SCALER6_CTL0_ADDR_MODE_256B;
1849 /* Adjust the base pointer to the first pixel to be scanned
1852 * For P030, y_ptr [31:4] is the 128bit word for the start pixel
1853 * y_ptr [3:0] is the pixel (0-11) contained within that 128bit
1854 * word that should be taken as the first pixel.
1855 * Ditto uv_ptr [31:4] vs [3:0], however [3:0] contains the
1856 * element within the 128bit word, eg for pixel 3 the value
1859 for (i = 0; i < num_planes; i++) {
1860 u32 tile_w, tile, x_off, pix_per_tile;
1862 if (fb->format->format == DRM_FORMAT_P030) {
1864 * Spec says: bits [31:4] of the given address
1865 * should point to the 128-bit word containing
1866 * the desired starting pixel, and bits[3:0]
1867 * should be between 0 and 11, indicating which
1868 * of the 12-pixels in that 128-bit word is the
1869 * first pixel to be used
1871 u32 remaining_pixels = src_x % 96;
1872 u32 aligned = remaining_pixels / 12;
1873 u32 last_bits = remaining_pixels % 12;
1875 x_off = aligned * 16 + last_bits;
1879 switch (base_format_mod) {
1880 case DRM_FORMAT_MOD_BROADCOM_SAND128:
1883 case DRM_FORMAT_MOD_BROADCOM_SAND256:
1889 pix_per_tile = tile_w / fb->format->cpp[0];
1890 x_off = (src_x % pix_per_tile) /
1891 (i ? h_subsample : 1) *
1895 tile = src_x / pix_per_tile;
1897 offsets[i] += param * tile_w * tile;
1898 offsets[i] += src_y / (i ? v_subsample : 1) * tile_w;
1899 offsets[i] += x_off & ~(i ? 1 : 0);
1902 components_per_word = fb->format->format == DRM_FORMAT_P030 ? 24 : 32;
1903 starting_offset = src_x % components_per_word;
1904 fetch_count = (width + starting_offset + components_per_word - 1) /
1905 components_per_word;
1907 pitch0 = VC4_SET_FIELD(param, SCALER6_PTR2_PITCH) |
1908 VC4_SET_FIELD(fetch_count - 1, SCALER6_PTR2_FETCH_COUNT);
1913 DRM_DEBUG_KMS("Unsupported FB tiling flag 0x%16llx",
1914 (long long)fb->modifier);
1918 /* fetch an extra pixel if we don't actually line up with the left edge. */
1919 if ((vc4_state->src_x & 0xffff) && vc4_state->src_x < (state->fb->width << 16))
1922 /* same for the right side */
1923 if (((vc4_state->src_x + vc4_state->src_w[0]) & 0xffff) &&
1924 vc4_state->src_x + vc4_state->src_w[0] < (state->fb->width << 16))
1927 /* now for the top */
1928 if ((vc4_state->src_y & 0xffff) && vc4_state->src_y < (state->fb->height << 16))
1931 /* and the bottom */
1932 if (((vc4_state->src_y + vc4_state->src_h[0]) & 0xffff) &&
1933 vc4_state->src_y + vc4_state->src_h[0] < (state->fb->height << 16))
1936 /* for YUV444 hardware wants double the width, otherwise it doesn't
1937 * fetch full width of chroma
1939 if (format->drm == DRM_FORMAT_YUV444 || format->drm == DRM_FORMAT_YVU444)
1942 /* Don't waste cycles mixing with plane alpha if the set alpha
1943 * is opaque or there is no per-pixel alpha information.
1944 * In any case we use the alpha property value as the fixed alpha.
1946 mix_plane_alpha = state->alpha != DRM_BLEND_ALPHA_OPAQUE &&
1947 fb->format->has_alpha;
1949 /* Control Word 0: Scaling Configuration & Element Validity*/
1950 vc4_dlist_write(vc4_state,
1951 SCALER6_CTL0_VALID |
1952 VC4_SET_FIELD(tiling, SCALER6_CTL0_ADDR_MODE) |
1953 vc4_hvs6_get_alpha_mask_mode(state) |
1954 (vc4_state->is_unity ? SCALER6_CTL0_UNITY : 0) |
1955 VC4_SET_FIELD(format->pixel_order_hvs5, SCALER6_CTL0_ORDERRGBA) |
1956 VC4_SET_FIELD(scl1, SCALER6_CTL0_SCL1_MODE) |
1957 VC4_SET_FIELD(scl0, SCALER6_CTL0_SCL0_MODE) |
1958 VC4_SET_FIELD(hvs_format, SCALER6_CTL0_PIXEL_FORMAT));
1960 /* Position Word 0: Image Position */
1961 vc4_state->pos0_offset = vc4_state->dlist_count;
1962 vc4_dlist_write(vc4_state,
1963 VC4_SET_FIELD(vc4_state->crtc_y, SCALER6_POS0_START_Y) |
1964 (rotation & DRM_MODE_REFLECT_X ? SCALER6_POS0_HFLIP : 0) |
1965 VC4_SET_FIELD(vc4_state->crtc_x, SCALER6_POS0_START_X));
1967 /* Control Word 2: Alpha Value & CSC */
1968 vc4_dlist_write(vc4_state,
1969 vc6_plane_get_csc_mode(vc4_state) |
1970 vc4_hvs5_get_alpha_blend_mode(state) |
1971 (mix_plane_alpha ? SCALER6_CTL2_ALPHA_MIX : 0) |
1972 VC4_SET_FIELD(state->alpha >> 4, SCALER5_CTL2_ALPHA));
1974 /* Position Word 1: Scaled Image Dimensions */
1975 if (!vc4_state->is_unity)
1976 vc4_dlist_write(vc4_state,
1977 VC4_SET_FIELD(vc4_state->crtc_h - 1,
1978 SCALER6_POS1_SCL_LINES) |
1979 VC4_SET_FIELD(vc4_state->crtc_w - 1,
1980 SCALER6_POS1_SCL_WIDTH));
1982 /* Position Word 2: Source Image Size */
1983 vc4_state->pos2_offset = vc4_state->dlist_count;
1984 vc4_dlist_write(vc4_state,
1985 VC4_SET_FIELD(height - 1,
1986 SCALER6_POS2_SRC_LINES) |
1987 VC4_SET_FIELD(width - 1,
1988 SCALER6_POS2_SRC_WIDTH));
1990 /* Position Word 3: Context */
1991 vc4_dlist_write(vc4_state, 0xc0c0c0c0);
1994 * TODO: This only covers Raster Scan Order planes
1996 for (i = 0; i < num_planes; i++) {
1997 struct drm_gem_dma_object *bo = drm_fb_dma_get_gem_obj(fb, i);
1998 dma_addr_t paddr = bo->dma_addr + fb->offsets[i] + offsets[i];
2000 /* Pointer Word 0 */
2001 vc4_state->ptr0_offset[i] = vc4_state->dlist_count;
2002 vc4_dlist_write(vc4_state,
2003 (rotation & DRM_MODE_REFLECT_Y ? SCALER6_PTR0_VFLIP : 0) |
2005 * The UPM buffer will be allocated in
2006 * vc6_plane_allocate_upm().
2008 VC4_SET_FIELD(upper_32_bits(paddr) & 0xff,
2009 SCALER6_PTR0_UPPER_ADDR));
2011 /* Pointer Word 1 */
2012 vc4_dlist_write(vc4_state, lower_32_bits(paddr));
2014 /* Pointer Word 2 */
2015 if (base_format_mod != DRM_FORMAT_MOD_BROADCOM_SAND128 &&
2016 base_format_mod != DRM_FORMAT_MOD_BROADCOM_SAND256) {
2017 vc4_dlist_write(vc4_state,
2018 VC4_SET_FIELD(fb->pitches[i],
2019 SCALER6_PTR2_PITCH));
2021 vc4_dlist_write(vc4_state, pitch0);
2027 * TODO: We're not using the palette mode
2032 * TODO: It's only relevant if we set the trans_rgb bit in the
2033 * control word 0, and we don't at the moment.
2036 vc4_state->lbm_offset = 0;
2038 if (!vc4_state->is_unity || fb->format->is_yuv) {
2040 * Reserve a slot for the LBM Base Address. The real value will
2041 * be set when calling vc4_plane_allocate_lbm().
2043 if (vc4_state->y_scaling[0] != VC4_SCALING_NONE ||
2044 vc4_state->y_scaling[1] != VC4_SCALING_NONE) {
2045 vc4_state->lbm_offset = vc4_state->dlist_count;
2046 vc4_dlist_counter_increment(vc4_state);
2049 if (vc4_state->x_scaling[0] != VC4_SCALING_NONE ||
2050 vc4_state->x_scaling[1] != VC4_SCALING_NONE ||
2051 vc4_state->y_scaling[0] != VC4_SCALING_NONE ||
2052 vc4_state->y_scaling[1] != VC4_SCALING_NONE) {
2055 * Emit Cb/Cr as channel 0 and Y as channel
2056 * 1. This matches how we set up scl0/scl1
2059 vc4_write_scaling_parameters(state, 1);
2061 vc4_write_scaling_parameters(state, 0);
2065 * If any PPF setup was done, then all the kernel
2066 * pointers get uploaded.
2068 if (vc4_state->x_scaling[0] == VC4_SCALING_PPF ||
2069 vc4_state->y_scaling[0] == VC4_SCALING_PPF ||
2070 vc4_state->x_scaling[1] == VC4_SCALING_PPF ||
2071 vc4_state->y_scaling[1] == VC4_SCALING_PPF) {
2073 VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start,
2074 SCALER_PPF_KERNEL_OFFSET);
2077 vc4_dlist_write(vc4_state, kernel);
2079 vc4_dlist_write(vc4_state, kernel);
2081 vc4_dlist_write(vc4_state, kernel);
2083 vc4_dlist_write(vc4_state, kernel);
2087 vc4_dlist_write(vc4_state, SCALER6_CTL0_END);
2089 vc4_state->dlist[0] |=
2090 VC4_SET_FIELD(vc4_state->dlist_count, SCALER6_CTL0_NEXT);
2092 /* crtc_* are already clipped coordinates. */
2093 covers_screen = vc4_state->crtc_x == 0 && vc4_state->crtc_y == 0 &&
2094 vc4_state->crtc_w == state->crtc->mode.hdisplay &&
2095 vc4_state->crtc_h == state->crtc->mode.vdisplay;
2098 * Background fill might be necessary when the plane has per-pixel
2099 * alpha content or a non-opaque plane alpha and could blend from the
2100 * background or does not cover the entire screen.
2102 vc4_state->needs_bg_fill = fb->format->has_alpha || !covers_screen ||
2103 state->alpha != DRM_BLEND_ALPHA_OPAQUE;
2106 * Flag the dlist as initialized to avoid checking it twice in case
2107 * the async update check already called vc4_plane_mode_set() and
2108 * decided to fallback to sync update because async update was not
2111 vc4_state->dlist_initialized = 1;
2113 vc4_plane_calc_load(state);
2115 drm_dbg_driver(drm, "[PLANE:%d:%s] Computed DLIST size: %u\n",
2116 plane->base.id, plane->name, vc4_state->dlist_count);
2121 /* If a modeset involves changing the setup of a plane, the atomic
2122 * infrastructure will call this to validate a proposed plane setup.
2123 * However, if a plane isn't getting updated, this (and the
2124 * corresponding vc4_plane_atomic_update) won't get called. Thus, we
2125 * compute the dlist here and have all active plane dlists get updated
2126 * in the CRTC's flush.
2128 static int vc4_plane_atomic_check(struct drm_plane *plane,
2129 struct drm_atomic_state *state)
2131 struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
2132 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
2134 struct vc4_plane_state *vc4_state = to_vc4_plane_state(new_plane_state);
2137 vc4_state->dlist_count = 0;
2139 if (!plane_enabled(new_plane_state)) {
2140 struct drm_plane_state *old_plane_state =
2141 drm_atomic_get_old_plane_state(state, plane);
2143 if (vc4->gen >= VC4_GEN_6_C && old_plane_state &&
2144 plane_enabled(old_plane_state)) {
2145 vc6_plane_free_upm(new_plane_state);
2150 if (vc4->gen >= VC4_GEN_6_C)
2151 ret = vc6_plane_mode_set(plane, new_plane_state);
2153 ret = vc4_plane_mode_set(plane, new_plane_state);
2157 if (!vc4_state->src_w[0] || !vc4_state->src_h[0] ||
2158 !vc4_state->crtc_w || !vc4_state->crtc_h)
2161 ret = vc4_plane_allocate_lbm(new_plane_state);
2165 if (vc4->gen >= VC4_GEN_6_C) {
2166 ret = vc6_plane_allocate_upm(new_plane_state);
2174 static void vc4_plane_atomic_update(struct drm_plane *plane,
2175 struct drm_atomic_state *state)
2177 /* No contents here. Since we don't know where in the CRTC's
2178 * dlist we should be stored, our dlist is uploaded to the
2179 * hardware with vc4_plane_write_dlist() at CRTC atomic_flush
2184 u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist)
2186 struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);
2190 if (!drm_dev_enter(plane->dev, &idx))
2193 vc4_state->hw_dlist = dlist;
2195 /* Can't memcpy_toio() because it needs to be 32-bit writes. */
2196 for (i = 0; i < vc4_state->dlist_count; i++)
2197 writel(vc4_state->dlist[i], &dlist[i]);
2202 return vc4_state->dlist_count;
2205 u32 vc4_plane_dlist_size(const struct drm_plane_state *state)
2207 const struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
2209 return vc4_state->dlist_count;
2212 /* Updates the plane to immediately (well, once the FIFO needs
2213 * refilling) scan out from at a new framebuffer.
2215 void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb)
2217 struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);
2218 struct drm_gem_dma_object *bo = drm_fb_dma_get_gem_obj(fb, 0);
2219 struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
2220 dma_addr_t dma_addr = bo->dma_addr + fb->offsets[0];
2223 if (!drm_dev_enter(plane->dev, &idx))
2226 /* We're skipping the address adjustment for negative origin,
2227 * because this is only called on the primary plane.
2229 WARN_ON_ONCE(plane->state->crtc_x < 0 || plane->state->crtc_y < 0);
2231 if (vc4->gen == VC4_GEN_6_C) {
2234 value = vc4_state->dlist[vc4_state->ptr0_offset[0]] &
2235 ~SCALER6_PTR0_UPPER_ADDR_MASK;
2236 value |= VC4_SET_FIELD(upper_32_bits(dma_addr) & 0xff,
2237 SCALER6_PTR0_UPPER_ADDR);
2239 writel(value, &vc4_state->hw_dlist[vc4_state->ptr0_offset[0]]);
2240 vc4_state->dlist[vc4_state->ptr0_offset[0]] = value;
2242 value = lower_32_bits(dma_addr);
2243 writel(value, &vc4_state->hw_dlist[vc4_state->ptr0_offset[0] + 1]);
2244 vc4_state->dlist[vc4_state->ptr0_offset[0] + 1] = value;
2248 addr = (u32)dma_addr;
2250 /* Write the new address into the hardware immediately. The
2251 * scanout will start from this address as soon as the FIFO
2252 * needs to refill with pixels.
2254 writel(addr, &vc4_state->hw_dlist[vc4_state->ptr0_offset[0]]);
2256 /* Also update the CPU-side dlist copy, so that any later
2257 * atomic updates that don't do a new modeset on our plane
2258 * also use our updated address.
2260 vc4_state->dlist[vc4_state->ptr0_offset[0]] = addr;
2266 static void vc4_plane_atomic_async_update(struct drm_plane *plane,
2267 struct drm_atomic_state *state)
2269 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
2271 struct vc4_plane_state *vc4_state, *new_vc4_state;
2274 if (!drm_dev_enter(plane->dev, &idx))
2277 swap(plane->state->fb, new_plane_state->fb);
2278 plane->state->crtc_x = new_plane_state->crtc_x;
2279 plane->state->crtc_y = new_plane_state->crtc_y;
2280 plane->state->crtc_w = new_plane_state->crtc_w;
2281 plane->state->crtc_h = new_plane_state->crtc_h;
2282 plane->state->src_x = new_plane_state->src_x;
2283 plane->state->src_y = new_plane_state->src_y;
2284 plane->state->src_w = new_plane_state->src_w;
2285 plane->state->src_h = new_plane_state->src_h;
2286 plane->state->alpha = new_plane_state->alpha;
2287 plane->state->pixel_blend_mode = new_plane_state->pixel_blend_mode;
2288 plane->state->rotation = new_plane_state->rotation;
2289 plane->state->zpos = new_plane_state->zpos;
2290 plane->state->normalized_zpos = new_plane_state->normalized_zpos;
2291 plane->state->color_encoding = new_plane_state->color_encoding;
2292 plane->state->color_range = new_plane_state->color_range;
2293 plane->state->src = new_plane_state->src;
2294 plane->state->dst = new_plane_state->dst;
2295 plane->state->visible = new_plane_state->visible;
2297 new_vc4_state = to_vc4_plane_state(new_plane_state);
2298 vc4_state = to_vc4_plane_state(plane->state);
2300 vc4_state->crtc_x = new_vc4_state->crtc_x;
2301 vc4_state->crtc_y = new_vc4_state->crtc_y;
2302 vc4_state->crtc_h = new_vc4_state->crtc_h;
2303 vc4_state->crtc_w = new_vc4_state->crtc_w;
2304 vc4_state->src_x = new_vc4_state->src_x;
2305 vc4_state->src_y = new_vc4_state->src_y;
2306 memcpy(vc4_state->src_w, new_vc4_state->src_w,
2307 sizeof(vc4_state->src_w));
2308 memcpy(vc4_state->src_h, new_vc4_state->src_h,
2309 sizeof(vc4_state->src_h));
2310 memcpy(vc4_state->x_scaling, new_vc4_state->x_scaling,
2311 sizeof(vc4_state->x_scaling));
2312 memcpy(vc4_state->y_scaling, new_vc4_state->y_scaling,
2313 sizeof(vc4_state->y_scaling));
2314 vc4_state->is_unity = new_vc4_state->is_unity;
2315 vc4_state->is_yuv = new_vc4_state->is_yuv;
2316 vc4_state->needs_bg_fill = new_vc4_state->needs_bg_fill;
2318 /* Update the current vc4_state pos0, pos2 and ptr0 dlist entries. */
2319 vc4_state->dlist[vc4_state->pos0_offset] =
2320 new_vc4_state->dlist[vc4_state->pos0_offset];
2321 vc4_state->dlist[vc4_state->pos2_offset] =
2322 new_vc4_state->dlist[vc4_state->pos2_offset];
2323 vc4_state->dlist[vc4_state->ptr0_offset[0]] =
2324 new_vc4_state->dlist[vc4_state->ptr0_offset[0]];
2326 /* Note that we can't just call vc4_plane_write_dlist()
2327 * because that would smash the context data that the HVS is
2330 writel(vc4_state->dlist[vc4_state->pos0_offset],
2331 &vc4_state->hw_dlist[vc4_state->pos0_offset]);
2332 writel(vc4_state->dlist[vc4_state->pos2_offset],
2333 &vc4_state->hw_dlist[vc4_state->pos2_offset]);
2334 writel(vc4_state->dlist[vc4_state->ptr0_offset[0]],
2335 &vc4_state->hw_dlist[vc4_state->ptr0_offset[0]]);
2340 static int vc4_plane_atomic_async_check(struct drm_plane *plane,
2341 struct drm_atomic_state *state)
2343 struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
2344 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
2346 struct vc4_plane_state *old_vc4_state, *new_vc4_state;
2350 if (vc4->gen <= VC4_GEN_5)
2351 ret = vc4_plane_mode_set(plane, new_plane_state);
2353 ret = vc6_plane_mode_set(plane, new_plane_state);
2357 old_vc4_state = to_vc4_plane_state(plane->state);
2358 new_vc4_state = to_vc4_plane_state(new_plane_state);
2360 if (!new_vc4_state->hw_dlist)
2363 if (old_vc4_state->dlist_count != new_vc4_state->dlist_count ||
2364 old_vc4_state->pos0_offset != new_vc4_state->pos0_offset ||
2365 old_vc4_state->pos2_offset != new_vc4_state->pos2_offset ||
2366 old_vc4_state->ptr0_offset[0] != new_vc4_state->ptr0_offset[0] ||
2367 vc4_lbm_size(plane->state) != vc4_lbm_size(new_plane_state))
2370 /* Only pos0, pos2 and ptr0 DWORDS can be updated in an async update
2371 * if anything else has changed, fallback to a sync update.
2373 for (i = 0; i < new_vc4_state->dlist_count; i++) {
2374 if (i == new_vc4_state->pos0_offset ||
2375 i == new_vc4_state->pos2_offset ||
2376 i == new_vc4_state->ptr0_offset[0] ||
2377 (new_vc4_state->lbm_offset &&
2378 i == new_vc4_state->lbm_offset))
2381 if (new_vc4_state->dlist[i] != old_vc4_state->dlist[i])
2388 static int vc4_prepare_fb(struct drm_plane *plane,
2389 struct drm_plane_state *state)
2397 bo = to_vc4_bo(&drm_fb_dma_get_gem_obj(state->fb, 0)->base);
2399 ret = drm_gem_plane_helper_prepare_fb(plane, state);
2403 return vc4_bo_inc_usecnt(bo);
2406 static void vc4_cleanup_fb(struct drm_plane *plane,
2407 struct drm_plane_state *state)
2414 bo = to_vc4_bo(&drm_fb_dma_get_gem_obj(state->fb, 0)->base);
2415 vc4_bo_dec_usecnt(bo);
2418 static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
2419 .atomic_check = vc4_plane_atomic_check,
2420 .atomic_update = vc4_plane_atomic_update,
2421 .prepare_fb = vc4_prepare_fb,
2422 .cleanup_fb = vc4_cleanup_fb,
2423 .atomic_async_check = vc4_plane_atomic_async_check,
2424 .atomic_async_update = vc4_plane_atomic_async_update,
2427 static const struct drm_plane_helper_funcs vc5_plane_helper_funcs = {
2428 .atomic_check = vc4_plane_atomic_check,
2429 .atomic_update = vc4_plane_atomic_update,
2430 .atomic_async_check = vc4_plane_atomic_async_check,
2431 .atomic_async_update = vc4_plane_atomic_async_update,
2434 static bool vc4_format_mod_supported(struct drm_plane *plane,
2438 /* Support T_TILING for RGB formats only. */
2440 case DRM_FORMAT_XRGB8888:
2441 case DRM_FORMAT_ARGB8888:
2442 case DRM_FORMAT_ABGR8888:
2443 case DRM_FORMAT_XBGR8888:
2444 case DRM_FORMAT_RGB565:
2445 case DRM_FORMAT_BGR565:
2446 case DRM_FORMAT_ARGB1555:
2447 case DRM_FORMAT_XRGB1555:
2448 switch (fourcc_mod_broadcom_mod(modifier)) {
2449 case DRM_FORMAT_MOD_LINEAR:
2450 case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
2455 case DRM_FORMAT_NV12:
2456 case DRM_FORMAT_NV21:
2457 switch (fourcc_mod_broadcom_mod(modifier)) {
2458 case DRM_FORMAT_MOD_LINEAR:
2459 case DRM_FORMAT_MOD_BROADCOM_SAND64:
2460 case DRM_FORMAT_MOD_BROADCOM_SAND128:
2461 case DRM_FORMAT_MOD_BROADCOM_SAND256:
2466 case DRM_FORMAT_P030:
2467 switch (fourcc_mod_broadcom_mod(modifier)) {
2468 case DRM_FORMAT_MOD_BROADCOM_SAND128:
2473 case DRM_FORMAT_RGBX1010102:
2474 case DRM_FORMAT_BGRX1010102:
2475 case DRM_FORMAT_RGBA1010102:
2476 case DRM_FORMAT_BGRA1010102:
2477 case DRM_FORMAT_XRGB4444:
2478 case DRM_FORMAT_ARGB4444:
2479 case DRM_FORMAT_XBGR4444:
2480 case DRM_FORMAT_ABGR4444:
2481 case DRM_FORMAT_RGBX4444:
2482 case DRM_FORMAT_RGBA4444:
2483 case DRM_FORMAT_BGRX4444:
2484 case DRM_FORMAT_BGRA4444:
2485 case DRM_FORMAT_RGB332:
2486 case DRM_FORMAT_BGR233:
2487 case DRM_FORMAT_YUV422:
2488 case DRM_FORMAT_YVU422:
2489 case DRM_FORMAT_YUV420:
2490 case DRM_FORMAT_YVU420:
2491 case DRM_FORMAT_NV16:
2492 case DRM_FORMAT_NV61:
2494 return (modifier == DRM_FORMAT_MOD_LINEAR);
2498 static const struct drm_plane_funcs vc4_plane_funcs = {
2499 .update_plane = drm_atomic_helper_update_plane,
2500 .disable_plane = drm_atomic_helper_disable_plane,
2501 .reset = vc4_plane_reset,
2502 .atomic_duplicate_state = vc4_plane_duplicate_state,
2503 .atomic_destroy_state = vc4_plane_destroy_state,
2504 .format_mod_supported = vc4_format_mod_supported,
2507 struct drm_plane *vc4_plane_init(struct drm_device *dev,
2508 enum drm_plane_type type,
2509 uint32_t possible_crtcs)
2511 struct vc4_dev *vc4 = to_vc4_dev(dev);
2512 struct drm_plane *plane;
2513 struct vc4_plane *vc4_plane;
2514 u32 formats[ARRAY_SIZE(hvs_formats)];
2515 int num_formats = 0;
2517 static const uint64_t modifiers[] = {
2518 DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
2519 DRM_FORMAT_MOD_BROADCOM_SAND128,
2520 DRM_FORMAT_MOD_BROADCOM_SAND64,
2521 DRM_FORMAT_MOD_BROADCOM_SAND256,
2522 DRM_FORMAT_MOD_LINEAR,
2523 DRM_FORMAT_MOD_INVALID
2526 for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) {
2527 if (!hvs_formats[i].hvs5_only || vc4->gen >= VC4_GEN_5) {
2528 formats[num_formats] = hvs_formats[i].drm;
2533 vc4_plane = drmm_universal_plane_alloc(dev, struct vc4_plane, base,
2536 formats, num_formats,
2537 modifiers, type, NULL);
2538 if (IS_ERR(vc4_plane))
2539 return ERR_CAST(vc4_plane);
2540 plane = &vc4_plane->base;
2542 if (vc4->gen >= VC4_GEN_5)
2543 drm_plane_helper_add(plane, &vc5_plane_helper_funcs);
2545 drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
2547 drm_plane_create_alpha_property(plane);
2548 drm_plane_create_blend_mode_property(plane,
2549 BIT(DRM_MODE_BLEND_PIXEL_NONE) |
2550 BIT(DRM_MODE_BLEND_PREMULTI) |
2551 BIT(DRM_MODE_BLEND_COVERAGE));
2552 drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
2554 DRM_MODE_ROTATE_180 |
2555 DRM_MODE_REFLECT_X |
2556 DRM_MODE_REFLECT_Y);
2558 drm_plane_create_color_properties(plane,
2559 BIT(DRM_COLOR_YCBCR_BT601) |
2560 BIT(DRM_COLOR_YCBCR_BT709) |
2561 BIT(DRM_COLOR_YCBCR_BT2020),
2562 BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
2563 BIT(DRM_COLOR_YCBCR_FULL_RANGE),
2564 DRM_COLOR_YCBCR_BT709,
2565 DRM_COLOR_YCBCR_LIMITED_RANGE);
2567 if (type == DRM_PLANE_TYPE_PRIMARY)
2568 drm_plane_create_zpos_immutable_property(plane, 0);
2573 #define VC4_NUM_OVERLAY_PLANES 16
2575 int vc4_plane_create_additional_planes(struct drm_device *drm)
2577 struct drm_plane *cursor_plane;
2578 struct drm_crtc *crtc;
2581 /* Set up some arbitrary number of planes. We're not limited
2582 * by a set number of physical registers, just the space in
2583 * the HVS (16k) and how small an plane can be (28 bytes).
2584 * However, each plane we set up takes up some memory, and
2585 * increases the cost of looping over planes, which atomic
2586 * modesetting does quite a bit. As a result, we pick a
2587 * modest number of planes to expose, that should hopefully
2588 * still cover any sane usecase.
2590 for (i = 0; i < VC4_NUM_OVERLAY_PLANES; i++) {
2591 struct drm_plane *plane =
2592 vc4_plane_init(drm, DRM_PLANE_TYPE_OVERLAY,
2593 GENMASK(drm->mode_config.num_crtc - 1, 0));
2598 /* Create zpos property. Max of all the overlays + 1 primary +
2599 * 1 cursor plane on a crtc.
2601 drm_plane_create_zpos_property(plane, i + 1, 1,
2602 VC4_NUM_OVERLAY_PLANES + 1);
2605 drm_for_each_crtc(crtc, drm) {
2606 /* Set up the legacy cursor after overlay initialization,
2607 * since the zpos fallback is that planes are rendered by plane
2608 * ID order, and that then puts the cursor on top.
2610 cursor_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_CURSOR,
2611 drm_crtc_mask(crtc));
2612 if (!IS_ERR(cursor_plane)) {
2613 crtc->cursor = cursor_plane;
2615 drm_plane_create_zpos_property(cursor_plane,
2616 VC4_NUM_OVERLAY_PLANES + 1,
2618 VC4_NUM_OVERLAY_PLANES + 1);