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_fb_cma_helper.h>
22 #include <drm/drm_fourcc.h>
23 #include <drm/drm_gem_framebuffer_helper.h>
24 #include <drm/drm_plane_helper.h>
26 #include "uapi/drm/vc4_drm.h"
31 static const struct hvs_format
{
32 u32 drm
; /* DRM_FORMAT_* */
33 u32 hvs
; /* HVS_FORMAT_* */
38 .drm
= DRM_FORMAT_XRGB8888
,
39 .hvs
= HVS_PIXEL_FORMAT_RGBA8888
,
40 .pixel_order
= HVS_PIXEL_ORDER_ABGR
,
41 .pixel_order_hvs5
= HVS_PIXEL_ORDER_ARGB
,
44 .drm
= DRM_FORMAT_ARGB8888
,
45 .hvs
= HVS_PIXEL_FORMAT_RGBA8888
,
46 .pixel_order
= HVS_PIXEL_ORDER_ABGR
,
47 .pixel_order_hvs5
= HVS_PIXEL_ORDER_ARGB
,
50 .drm
= DRM_FORMAT_ABGR8888
,
51 .hvs
= HVS_PIXEL_FORMAT_RGBA8888
,
52 .pixel_order
= HVS_PIXEL_ORDER_ARGB
,
53 .pixel_order_hvs5
= HVS_PIXEL_ORDER_ABGR
,
56 .drm
= DRM_FORMAT_XBGR8888
,
57 .hvs
= HVS_PIXEL_FORMAT_RGBA8888
,
58 .pixel_order
= HVS_PIXEL_ORDER_ARGB
,
59 .pixel_order_hvs5
= HVS_PIXEL_ORDER_ABGR
,
62 .drm
= DRM_FORMAT_RGB565
,
63 .hvs
= HVS_PIXEL_FORMAT_RGB565
,
64 .pixel_order
= HVS_PIXEL_ORDER_XRGB
,
67 .drm
= DRM_FORMAT_BGR565
,
68 .hvs
= HVS_PIXEL_FORMAT_RGB565
,
69 .pixel_order
= HVS_PIXEL_ORDER_XBGR
,
72 .drm
= DRM_FORMAT_ARGB1555
,
73 .hvs
= HVS_PIXEL_FORMAT_RGBA5551
,
74 .pixel_order
= HVS_PIXEL_ORDER_ABGR
,
77 .drm
= DRM_FORMAT_XRGB1555
,
78 .hvs
= HVS_PIXEL_FORMAT_RGBA5551
,
79 .pixel_order
= HVS_PIXEL_ORDER_ABGR
,
82 .drm
= DRM_FORMAT_RGB888
,
83 .hvs
= HVS_PIXEL_FORMAT_RGB888
,
84 .pixel_order
= HVS_PIXEL_ORDER_XRGB
,
87 .drm
= DRM_FORMAT_BGR888
,
88 .hvs
= HVS_PIXEL_FORMAT_RGB888
,
89 .pixel_order
= HVS_PIXEL_ORDER_XBGR
,
92 .drm
= DRM_FORMAT_YUV422
,
93 .hvs
= HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE
,
94 .pixel_order
= HVS_PIXEL_ORDER_XYCBCR
,
97 .drm
= DRM_FORMAT_YVU422
,
98 .hvs
= HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE
,
99 .pixel_order
= HVS_PIXEL_ORDER_XYCRCB
,
102 .drm
= DRM_FORMAT_YUV420
,
103 .hvs
= HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE
,
104 .pixel_order
= HVS_PIXEL_ORDER_XYCBCR
,
107 .drm
= DRM_FORMAT_YVU420
,
108 .hvs
= HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE
,
109 .pixel_order
= HVS_PIXEL_ORDER_XYCRCB
,
112 .drm
= DRM_FORMAT_NV12
,
113 .hvs
= HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE
,
114 .pixel_order
= HVS_PIXEL_ORDER_XYCBCR
,
117 .drm
= DRM_FORMAT_NV21
,
118 .hvs
= HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE
,
119 .pixel_order
= HVS_PIXEL_ORDER_XYCRCB
,
122 .drm
= DRM_FORMAT_NV16
,
123 .hvs
= HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE
,
124 .pixel_order
= HVS_PIXEL_ORDER_XYCBCR
,
127 .drm
= DRM_FORMAT_NV61
,
128 .hvs
= HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE
,
129 .pixel_order
= HVS_PIXEL_ORDER_XYCRCB
,
133 static const struct hvs_format
*vc4_get_hvs_format(u32 drm_format
)
137 for (i
= 0; i
< ARRAY_SIZE(hvs_formats
); i
++) {
138 if (hvs_formats
[i
].drm
== drm_format
)
139 return &hvs_formats
[i
];
145 static enum vc4_scaling_mode
vc4_get_scaling_mode(u32 src
, u32 dst
)
148 return VC4_SCALING_NONE
;
149 if (3 * dst
>= 2 * src
)
150 return VC4_SCALING_PPF
;
152 return VC4_SCALING_TPZ
;
155 static bool plane_enabled(struct drm_plane_state
*state
)
157 return state
->fb
&& !WARN_ON(!state
->crtc
);
160 static struct drm_plane_state
*vc4_plane_duplicate_state(struct drm_plane
*plane
)
162 struct vc4_plane_state
*vc4_state
;
164 if (WARN_ON(!plane
->state
))
167 vc4_state
= kmemdup(plane
->state
, sizeof(*vc4_state
), GFP_KERNEL
);
171 memset(&vc4_state
->lbm
, 0, sizeof(vc4_state
->lbm
));
172 vc4_state
->dlist_initialized
= 0;
174 __drm_atomic_helper_plane_duplicate_state(plane
, &vc4_state
->base
);
176 if (vc4_state
->dlist
) {
177 vc4_state
->dlist
= kmemdup(vc4_state
->dlist
,
178 vc4_state
->dlist_count
* 4,
180 if (!vc4_state
->dlist
) {
184 vc4_state
->dlist_size
= vc4_state
->dlist_count
;
187 return &vc4_state
->base
;
190 static void vc4_plane_destroy_state(struct drm_plane
*plane
,
191 struct drm_plane_state
*state
)
193 struct vc4_dev
*vc4
= to_vc4_dev(plane
->dev
);
194 struct vc4_plane_state
*vc4_state
= to_vc4_plane_state(state
);
196 if (drm_mm_node_allocated(&vc4_state
->lbm
)) {
197 unsigned long irqflags
;
199 spin_lock_irqsave(&vc4
->hvs
->mm_lock
, irqflags
);
200 drm_mm_remove_node(&vc4_state
->lbm
);
201 spin_unlock_irqrestore(&vc4
->hvs
->mm_lock
, irqflags
);
204 kfree(vc4_state
->dlist
);
205 __drm_atomic_helper_plane_destroy_state(&vc4_state
->base
);
209 /* Called during init to allocate the plane's atomic state. */
210 static void vc4_plane_reset(struct drm_plane
*plane
)
212 struct vc4_plane_state
*vc4_state
;
214 WARN_ON(plane
->state
);
216 vc4_state
= kzalloc(sizeof(*vc4_state
), GFP_KERNEL
);
220 __drm_atomic_helper_plane_reset(plane
, &vc4_state
->base
);
223 static void vc4_dlist_write(struct vc4_plane_state
*vc4_state
, u32 val
)
225 if (vc4_state
->dlist_count
== vc4_state
->dlist_size
) {
226 u32 new_size
= max(4u, vc4_state
->dlist_count
* 2);
227 u32
*new_dlist
= kmalloc_array(new_size
, 4, GFP_KERNEL
);
231 memcpy(new_dlist
, vc4_state
->dlist
, vc4_state
->dlist_count
* 4);
233 kfree(vc4_state
->dlist
);
234 vc4_state
->dlist
= new_dlist
;
235 vc4_state
->dlist_size
= new_size
;
238 vc4_state
->dlist
[vc4_state
->dlist_count
++] = val
;
241 /* Returns the scl0/scl1 field based on whether the dimensions need to
242 * be up/down/non-scaled.
244 * This is a replication of a table from the spec.
246 static u32
vc4_get_scl_field(struct drm_plane_state
*state
, int plane
)
248 struct vc4_plane_state
*vc4_state
= to_vc4_plane_state(state
);
250 switch (vc4_state
->x_scaling
[plane
] << 2 | vc4_state
->y_scaling
[plane
]) {
251 case VC4_SCALING_PPF
<< 2 | VC4_SCALING_PPF
:
252 return SCALER_CTL0_SCL_H_PPF_V_PPF
;
253 case VC4_SCALING_TPZ
<< 2 | VC4_SCALING_PPF
:
254 return SCALER_CTL0_SCL_H_TPZ_V_PPF
;
255 case VC4_SCALING_PPF
<< 2 | VC4_SCALING_TPZ
:
256 return SCALER_CTL0_SCL_H_PPF_V_TPZ
;
257 case VC4_SCALING_TPZ
<< 2 | VC4_SCALING_TPZ
:
258 return SCALER_CTL0_SCL_H_TPZ_V_TPZ
;
259 case VC4_SCALING_PPF
<< 2 | VC4_SCALING_NONE
:
260 return SCALER_CTL0_SCL_H_PPF_V_NONE
;
261 case VC4_SCALING_NONE
<< 2 | VC4_SCALING_PPF
:
262 return SCALER_CTL0_SCL_H_NONE_V_PPF
;
263 case VC4_SCALING_NONE
<< 2 | VC4_SCALING_TPZ
:
264 return SCALER_CTL0_SCL_H_NONE_V_TPZ
;
265 case VC4_SCALING_TPZ
<< 2 | VC4_SCALING_NONE
:
266 return SCALER_CTL0_SCL_H_TPZ_V_NONE
;
268 case VC4_SCALING_NONE
<< 2 | VC4_SCALING_NONE
:
269 /* The unity case is independently handled by
276 static int vc4_plane_margins_adj(struct drm_plane_state
*pstate
)
278 struct vc4_plane_state
*vc4_pstate
= to_vc4_plane_state(pstate
);
279 unsigned int left
, right
, top
, bottom
, adjhdisplay
, adjvdisplay
;
280 struct drm_crtc_state
*crtc_state
;
282 crtc_state
= drm_atomic_get_new_crtc_state(pstate
->state
,
285 vc4_crtc_get_margins(crtc_state
, &left
, &right
, &top
, &bottom
);
286 if (!left
&& !right
&& !top
&& !bottom
)
289 if (left
+ right
>= crtc_state
->mode
.hdisplay
||
290 top
+ bottom
>= crtc_state
->mode
.vdisplay
)
293 adjhdisplay
= crtc_state
->mode
.hdisplay
- (left
+ right
);
294 vc4_pstate
->crtc_x
= DIV_ROUND_CLOSEST(vc4_pstate
->crtc_x
*
296 crtc_state
->mode
.hdisplay
);
297 vc4_pstate
->crtc_x
+= left
;
298 if (vc4_pstate
->crtc_x
> crtc_state
->mode
.hdisplay
- left
)
299 vc4_pstate
->crtc_x
= crtc_state
->mode
.hdisplay
- left
;
301 adjvdisplay
= crtc_state
->mode
.vdisplay
- (top
+ bottom
);
302 vc4_pstate
->crtc_y
= DIV_ROUND_CLOSEST(vc4_pstate
->crtc_y
*
304 crtc_state
->mode
.vdisplay
);
305 vc4_pstate
->crtc_y
+= top
;
306 if (vc4_pstate
->crtc_y
> crtc_state
->mode
.vdisplay
- top
)
307 vc4_pstate
->crtc_y
= crtc_state
->mode
.vdisplay
- top
;
309 vc4_pstate
->crtc_w
= DIV_ROUND_CLOSEST(vc4_pstate
->crtc_w
*
311 crtc_state
->mode
.hdisplay
);
312 vc4_pstate
->crtc_h
= DIV_ROUND_CLOSEST(vc4_pstate
->crtc_h
*
314 crtc_state
->mode
.vdisplay
);
316 if (!vc4_pstate
->crtc_w
|| !vc4_pstate
->crtc_h
)
322 static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state
*state
)
324 struct vc4_plane_state
*vc4_state
= to_vc4_plane_state(state
);
325 struct drm_framebuffer
*fb
= state
->fb
;
326 struct drm_gem_cma_object
*bo
= drm_fb_cma_get_gem_obj(fb
, 0);
327 u32 subpixel_src_mask
= (1 << 16) - 1;
328 int num_planes
= fb
->format
->num_planes
;
329 struct drm_crtc_state
*crtc_state
;
330 u32 h_subsample
= fb
->format
->hsub
;
331 u32 v_subsample
= fb
->format
->vsub
;
334 crtc_state
= drm_atomic_get_existing_crtc_state(state
->state
,
337 DRM_DEBUG_KMS("Invalid crtc state\n");
341 ret
= drm_atomic_helper_check_plane_state(state
, crtc_state
, 1,
342 INT_MAX
, true, true);
346 for (i
= 0; i
< num_planes
; i
++)
347 vc4_state
->offsets
[i
] = bo
->paddr
+ fb
->offsets
[i
];
349 /* We don't support subpixel source positioning for scaling. */
350 if ((state
->src
.x1
& subpixel_src_mask
) ||
351 (state
->src
.x2
& subpixel_src_mask
) ||
352 (state
->src
.y1
& subpixel_src_mask
) ||
353 (state
->src
.y2
& subpixel_src_mask
)) {
357 vc4_state
->src_x
= state
->src
.x1
>> 16;
358 vc4_state
->src_y
= state
->src
.y1
>> 16;
359 vc4_state
->src_w
[0] = (state
->src
.x2
- state
->src
.x1
) >> 16;
360 vc4_state
->src_h
[0] = (state
->src
.y2
- state
->src
.y1
) >> 16;
362 vc4_state
->crtc_x
= state
->dst
.x1
;
363 vc4_state
->crtc_y
= state
->dst
.y1
;
364 vc4_state
->crtc_w
= state
->dst
.x2
- state
->dst
.x1
;
365 vc4_state
->crtc_h
= state
->dst
.y2
- state
->dst
.y1
;
367 ret
= vc4_plane_margins_adj(state
);
371 vc4_state
->x_scaling
[0] = vc4_get_scaling_mode(vc4_state
->src_w
[0],
373 vc4_state
->y_scaling
[0] = vc4_get_scaling_mode(vc4_state
->src_h
[0],
376 vc4_state
->is_unity
= (vc4_state
->x_scaling
[0] == VC4_SCALING_NONE
&&
377 vc4_state
->y_scaling
[0] == VC4_SCALING_NONE
);
379 if (num_planes
> 1) {
380 vc4_state
->is_yuv
= true;
382 vc4_state
->src_w
[1] = vc4_state
->src_w
[0] / h_subsample
;
383 vc4_state
->src_h
[1] = vc4_state
->src_h
[0] / v_subsample
;
385 vc4_state
->x_scaling
[1] =
386 vc4_get_scaling_mode(vc4_state
->src_w
[1],
388 vc4_state
->y_scaling
[1] =
389 vc4_get_scaling_mode(vc4_state
->src_h
[1],
392 /* YUV conversion requires that horizontal scaling be enabled
393 * on the UV plane even if vc4_get_scaling_mode() returned
394 * VC4_SCALING_NONE (which can happen when the down-scaling
395 * ratio is 0.5). Let's force it to VC4_SCALING_PPF in this
398 if (vc4_state
->x_scaling
[1] == VC4_SCALING_NONE
)
399 vc4_state
->x_scaling
[1] = VC4_SCALING_PPF
;
401 vc4_state
->is_yuv
= false;
402 vc4_state
->x_scaling
[1] = VC4_SCALING_NONE
;
403 vc4_state
->y_scaling
[1] = VC4_SCALING_NONE
;
409 static void vc4_write_tpz(struct vc4_plane_state
*vc4_state
, u32 src
, u32 dst
)
413 scale
= (1 << 16) * src
/ dst
;
415 /* The specs note that while the reciprocal would be defined
416 * as (1<<32)/scale, ~0 is close enough.
420 vc4_dlist_write(vc4_state
,
421 VC4_SET_FIELD(scale
, SCALER_TPZ0_SCALE
) |
422 VC4_SET_FIELD(0, SCALER_TPZ0_IPHASE
));
423 vc4_dlist_write(vc4_state
,
424 VC4_SET_FIELD(recip
, SCALER_TPZ1_RECIP
));
427 static void vc4_write_ppf(struct vc4_plane_state
*vc4_state
, u32 src
, u32 dst
)
429 u32 scale
= (1 << 16) * src
/ dst
;
431 vc4_dlist_write(vc4_state
,
433 VC4_SET_FIELD(scale
, SCALER_PPF_SCALE
) |
434 VC4_SET_FIELD(0, SCALER_PPF_IPHASE
));
437 static u32
vc4_lbm_size(struct drm_plane_state
*state
)
439 struct vc4_plane_state
*vc4_state
= to_vc4_plane_state(state
);
443 /* LBM is not needed when there's no vertical scaling. */
444 if (vc4_state
->y_scaling
[0] == VC4_SCALING_NONE
&&
445 vc4_state
->y_scaling
[1] == VC4_SCALING_NONE
)
449 * This can be further optimized in the RGB/YUV444 case if the PPF
450 * decimation factor is between 0.5 and 1.0 by using crtc_w.
452 * It's not an issue though, since in that case since src_w[0] is going
453 * to be greater than or equal to crtc_w.
455 if (vc4_state
->x_scaling
[0] == VC4_SCALING_TPZ
)
456 pix_per_line
= vc4_state
->crtc_w
;
458 pix_per_line
= vc4_state
->src_w
[0];
460 if (!vc4_state
->is_yuv
) {
461 if (vc4_state
->y_scaling
[0] == VC4_SCALING_TPZ
)
462 lbm
= pix_per_line
* 8;
464 /* In special cases, this multiplier might be 12. */
465 lbm
= pix_per_line
* 16;
468 /* There are cases for this going down to a multiplier
469 * of 2, but according to the firmware source, the
470 * table in the docs is somewhat wrong.
472 lbm
= pix_per_line
* 16;
475 lbm
= roundup(lbm
, 32);
480 static void vc4_write_scaling_parameters(struct drm_plane_state
*state
,
483 struct vc4_plane_state
*vc4_state
= to_vc4_plane_state(state
);
485 /* Ch0 H-PPF Word 0: Scaling Parameters */
486 if (vc4_state
->x_scaling
[channel
] == VC4_SCALING_PPF
) {
487 vc4_write_ppf(vc4_state
,
488 vc4_state
->src_w
[channel
], vc4_state
->crtc_w
);
491 /* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */
492 if (vc4_state
->y_scaling
[channel
] == VC4_SCALING_PPF
) {
493 vc4_write_ppf(vc4_state
,
494 vc4_state
->src_h
[channel
], vc4_state
->crtc_h
);
495 vc4_dlist_write(vc4_state
, 0xc0c0c0c0);
498 /* Ch0 H-TPZ Words 0-1: Scaling Parameters, Recip */
499 if (vc4_state
->x_scaling
[channel
] == VC4_SCALING_TPZ
) {
500 vc4_write_tpz(vc4_state
,
501 vc4_state
->src_w
[channel
], vc4_state
->crtc_w
);
504 /* Ch0 V-TPZ Words 0-2: Scaling Parameters, Recip, Context */
505 if (vc4_state
->y_scaling
[channel
] == VC4_SCALING_TPZ
) {
506 vc4_write_tpz(vc4_state
,
507 vc4_state
->src_h
[channel
], vc4_state
->crtc_h
);
508 vc4_dlist_write(vc4_state
, 0xc0c0c0c0);
512 static void vc4_plane_calc_load(struct drm_plane_state
*state
)
514 unsigned int hvs_load_shift
, vrefresh
, i
;
515 struct drm_framebuffer
*fb
= state
->fb
;
516 struct vc4_plane_state
*vc4_state
;
517 struct drm_crtc_state
*crtc_state
;
518 unsigned int vscale_factor
;
521 vc4
= to_vc4_dev(state
->plane
->dev
);
522 if (!vc4
->load_tracker_available
)
525 vc4_state
= to_vc4_plane_state(state
);
526 crtc_state
= drm_atomic_get_existing_crtc_state(state
->state
,
528 vrefresh
= drm_mode_vrefresh(&crtc_state
->adjusted_mode
);
530 /* The HVS is able to process 2 pixels/cycle when scaling the source,
531 * 4 pixels/cycle otherwise.
532 * Alpha blending step seems to be pipelined and it's always operating
533 * at 4 pixels/cycle, so the limiting aspect here seems to be the
535 * HVS load is expressed in clk-cycles/sec (AKA Hz).
537 if (vc4_state
->x_scaling
[0] != VC4_SCALING_NONE
||
538 vc4_state
->x_scaling
[1] != VC4_SCALING_NONE
||
539 vc4_state
->y_scaling
[0] != VC4_SCALING_NONE
||
540 vc4_state
->y_scaling
[1] != VC4_SCALING_NONE
)
545 vc4_state
->membus_load
= 0;
546 vc4_state
->hvs_load
= 0;
547 for (i
= 0; i
< fb
->format
->num_planes
; i
++) {
548 /* Even if the bandwidth/plane required for a single frame is
550 * vc4_state->src_w[i] * vc4_state->src_h[i] * cpp * vrefresh
552 * when downscaling, we have to read more pixels per line in
553 * the time frame reserved for a single line, so the bandwidth
554 * demand can be punctually higher. To account for that, we
555 * calculate the down-scaling factor and multiply the plane
556 * load by this number. We're likely over-estimating the read
557 * demand, but that's better than under-estimating it.
559 vscale_factor
= DIV_ROUND_UP(vc4_state
->src_h
[i
],
561 vc4_state
->membus_load
+= vc4_state
->src_w
[i
] *
562 vc4_state
->src_h
[i
] * vscale_factor
*
564 vc4_state
->hvs_load
+= vc4_state
->crtc_h
* vc4_state
->crtc_w
;
567 vc4_state
->hvs_load
*= vrefresh
;
568 vc4_state
->hvs_load
>>= hvs_load_shift
;
569 vc4_state
->membus_load
*= vrefresh
;
572 static int vc4_plane_allocate_lbm(struct drm_plane_state
*state
)
574 struct vc4_dev
*vc4
= to_vc4_dev(state
->plane
->dev
);
575 struct vc4_plane_state
*vc4_state
= to_vc4_plane_state(state
);
576 unsigned long irqflags
;
579 lbm_size
= vc4_lbm_size(state
);
583 if (WARN_ON(!vc4_state
->lbm_offset
))
586 /* Allocate the LBM memory that the HVS will use for temporary
587 * storage due to our scaling/format conversion.
589 if (!drm_mm_node_allocated(&vc4_state
->lbm
)) {
592 spin_lock_irqsave(&vc4
->hvs
->mm_lock
, irqflags
);
593 ret
= drm_mm_insert_node_generic(&vc4
->hvs
->lbm_mm
,
596 vc4
->hvs
->hvs5
? 64 : 32,
598 spin_unlock_irqrestore(&vc4
->hvs
->mm_lock
, irqflags
);
603 WARN_ON_ONCE(lbm_size
!= vc4_state
->lbm
.size
);
606 vc4_state
->dlist
[vc4_state
->lbm_offset
] = vc4_state
->lbm
.start
;
611 /* Writes out a full display list for an active plane to the plane's
612 * private dlist state.
614 static int vc4_plane_mode_set(struct drm_plane
*plane
,
615 struct drm_plane_state
*state
)
617 struct vc4_dev
*vc4
= to_vc4_dev(plane
->dev
);
618 struct vc4_plane_state
*vc4_state
= to_vc4_plane_state(state
);
619 struct drm_framebuffer
*fb
= state
->fb
;
620 u32 ctl0_offset
= vc4_state
->dlist_count
;
621 const struct hvs_format
*format
= vc4_get_hvs_format(fb
->format
->format
);
622 u64 base_format_mod
= fourcc_mod_broadcom_mod(fb
->modifier
);
623 int num_planes
= fb
->format
->num_planes
;
624 u32 h_subsample
= fb
->format
->hsub
;
625 u32 v_subsample
= fb
->format
->vsub
;
626 bool mix_plane_alpha
;
628 u32 scl0
, scl1
, pitch0
;
630 u32 hvs_format
= format
->hvs
;
631 unsigned int rotation
;
634 if (vc4_state
->dlist_initialized
)
637 ret
= vc4_plane_setup_clipping_and_scaling(state
);
641 /* SCL1 is used for Cb/Cr scaling of planar formats. For RGB
642 * and 4:4:4, scl1 should be set to scl0 so both channels of
643 * the scaler do the same thing. For YUV, the Y plane needs
644 * to be put in channel 1 and Cb/Cr in channel 0, so we swap
645 * the scl fields here.
647 if (num_planes
== 1) {
648 scl0
= vc4_get_scl_field(state
, 0);
651 scl0
= vc4_get_scl_field(state
, 1);
652 scl1
= vc4_get_scl_field(state
, 0);
655 rotation
= drm_rotation_simplify(state
->rotation
,
660 /* We must point to the last line when Y reflection is enabled. */
661 src_y
= vc4_state
->src_y
;
662 if (rotation
& DRM_MODE_REFLECT_Y
)
663 src_y
+= vc4_state
->src_h
[0] - 1;
665 switch (base_format_mod
) {
666 case DRM_FORMAT_MOD_LINEAR
:
667 tiling
= SCALER_CTL0_TILING_LINEAR
;
668 pitch0
= VC4_SET_FIELD(fb
->pitches
[0], SCALER_SRC_PITCH
);
670 /* Adjust the base pointer to the first pixel to be scanned
673 for (i
= 0; i
< num_planes
; i
++) {
674 vc4_state
->offsets
[i
] += src_y
/
675 (i
? v_subsample
: 1) *
678 vc4_state
->offsets
[i
] += vc4_state
->src_x
/
679 (i
? h_subsample
: 1) *
685 case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED
: {
686 u32 tile_size_shift
= 12; /* T tiles are 4kb */
687 /* Whole-tile offsets, mostly for setting the pitch. */
688 u32 tile_w_shift
= fb
->format
->cpp
[0] == 2 ? 6 : 5;
689 u32 tile_h_shift
= 5; /* 16 and 32bpp are 32 pixels high */
690 u32 tile_w_mask
= (1 << tile_w_shift
) - 1;
691 /* The height mask on 32-bit-per-pixel tiles is 63, i.e. twice
692 * the height (in pixels) of a 4k tile.
694 u32 tile_h_mask
= (2 << tile_h_shift
) - 1;
695 /* For T-tiled, the FB pitch is "how many bytes from one row to
696 * the next, such that
698 * pitch * tile_h == tile_size * tiles_per_row
700 u32 tiles_w
= fb
->pitches
[0] >> (tile_size_shift
- tile_h_shift
);
701 u32 tiles_l
= vc4_state
->src_x
>> tile_w_shift
;
702 u32 tiles_r
= tiles_w
- tiles_l
;
703 u32 tiles_t
= src_y
>> tile_h_shift
;
704 /* Intra-tile offsets, which modify the base address (the
705 * SCALER_PITCH0_TILE_Y_OFFSET tells HVS how to walk from that
708 u32 tile_y
= (src_y
>> 4) & 1;
709 u32 subtile_y
= (src_y
>> 2) & 3;
710 u32 utile_y
= src_y
& 3;
711 u32 x_off
= vc4_state
->src_x
& tile_w_mask
;
712 u32 y_off
= src_y
& tile_h_mask
;
714 /* When Y reflection is requested we must set the
715 * SCALER_PITCH0_TILE_LINE_DIR flag to tell HVS that all lines
716 * after the initial one should be fetched in descending order,
717 * which makes sense since we start from the last line and go
719 * Don't know why we need y_off = max_y_off - y_off, but it's
720 * definitely required (I guess it's also related to the "going
721 * backward" situation).
723 if (rotation
& DRM_MODE_REFLECT_Y
) {
724 y_off
= tile_h_mask
- y_off
;
725 pitch0
= SCALER_PITCH0_TILE_LINE_DIR
;
730 tiling
= SCALER_CTL0_TILING_256B_OR_T
;
731 pitch0
|= (VC4_SET_FIELD(x_off
, SCALER_PITCH0_SINK_PIX
) |
732 VC4_SET_FIELD(y_off
, SCALER_PITCH0_TILE_Y_OFFSET
) |
733 VC4_SET_FIELD(tiles_l
, SCALER_PITCH0_TILE_WIDTH_L
) |
734 VC4_SET_FIELD(tiles_r
, SCALER_PITCH0_TILE_WIDTH_R
));
735 vc4_state
->offsets
[0] += tiles_t
* (tiles_w
<< tile_size_shift
);
736 vc4_state
->offsets
[0] += subtile_y
<< 8;
737 vc4_state
->offsets
[0] += utile_y
<< 4;
739 /* Rows of tiles alternate left-to-right and right-to-left. */
741 pitch0
|= SCALER_PITCH0_TILE_INITIAL_LINE_DIR
;
742 vc4_state
->offsets
[0] += (tiles_w
- tiles_l
) <<
744 vc4_state
->offsets
[0] -= (1 + !tile_y
) << 10;
746 vc4_state
->offsets
[0] += tiles_l
<< tile_size_shift
;
747 vc4_state
->offsets
[0] += tile_y
<< 10;
753 case DRM_FORMAT_MOD_BROADCOM_SAND64
:
754 case DRM_FORMAT_MOD_BROADCOM_SAND128
:
755 case DRM_FORMAT_MOD_BROADCOM_SAND256
: {
756 uint32_t param
= fourcc_mod_broadcom_param(fb
->modifier
);
757 u32 tile_w
, tile
, x_off
, pix_per_tile
;
759 hvs_format
= HVS_PIXEL_FORMAT_H264
;
761 switch (base_format_mod
) {
762 case DRM_FORMAT_MOD_BROADCOM_SAND64
:
763 tiling
= SCALER_CTL0_TILING_64B
;
766 case DRM_FORMAT_MOD_BROADCOM_SAND128
:
767 tiling
= SCALER_CTL0_TILING_128B
;
770 case DRM_FORMAT_MOD_BROADCOM_SAND256
:
771 tiling
= SCALER_CTL0_TILING_256B_OR_T
;
778 if (param
> SCALER_TILE_HEIGHT_MASK
) {
779 DRM_DEBUG_KMS("SAND height too large (%d)\n", param
);
783 pix_per_tile
= tile_w
/ fb
->format
->cpp
[0];
784 tile
= vc4_state
->src_x
/ pix_per_tile
;
785 x_off
= vc4_state
->src_x
% pix_per_tile
;
787 /* Adjust the base pointer to the first pixel to be scanned
790 for (i
= 0; i
< num_planes
; i
++) {
791 vc4_state
->offsets
[i
] += param
* tile_w
* tile
;
792 vc4_state
->offsets
[i
] += src_y
/
793 (i
? v_subsample
: 1) *
795 vc4_state
->offsets
[i
] += x_off
/
796 (i
? h_subsample
: 1) *
800 pitch0
= VC4_SET_FIELD(param
, SCALER_TILE_HEIGHT
);
805 DRM_DEBUG_KMS("Unsupported FB tiling flag 0x%16llx",
806 (long long)fb
->modifier
);
810 /* Don't waste cycles mixing with plane alpha if the set alpha
811 * is opaque or there is no per-pixel alpha information.
812 * In any case we use the alpha property value as the fixed alpha.
814 mix_plane_alpha
= state
->alpha
!= DRM_BLEND_ALPHA_OPAQUE
&&
815 fb
->format
->has_alpha
;
817 if (!vc4
->hvs
->hvs5
) {
819 vc4_dlist_write(vc4_state
,
821 (rotation
& DRM_MODE_REFLECT_X
? SCALER_CTL0_HFLIP
: 0) |
822 (rotation
& DRM_MODE_REFLECT_Y
? SCALER_CTL0_VFLIP
: 0) |
823 VC4_SET_FIELD(SCALER_CTL0_RGBA_EXPAND_ROUND
, SCALER_CTL0_RGBA_EXPAND
) |
824 (format
->pixel_order
<< SCALER_CTL0_ORDER_SHIFT
) |
825 (hvs_format
<< SCALER_CTL0_PIXEL_FORMAT_SHIFT
) |
826 VC4_SET_FIELD(tiling
, SCALER_CTL0_TILING
) |
827 (vc4_state
->is_unity
? SCALER_CTL0_UNITY
: 0) |
828 VC4_SET_FIELD(scl0
, SCALER_CTL0_SCL0
) |
829 VC4_SET_FIELD(scl1
, SCALER_CTL0_SCL1
));
831 /* Position Word 0: Image Positions and Alpha Value */
832 vc4_state
->pos0_offset
= vc4_state
->dlist_count
;
833 vc4_dlist_write(vc4_state
,
834 VC4_SET_FIELD(state
->alpha
>> 8, SCALER_POS0_FIXED_ALPHA
) |
835 VC4_SET_FIELD(vc4_state
->crtc_x
, SCALER_POS0_START_X
) |
836 VC4_SET_FIELD(vc4_state
->crtc_y
, SCALER_POS0_START_Y
));
838 /* Position Word 1: Scaled Image Dimensions. */
839 if (!vc4_state
->is_unity
) {
840 vc4_dlist_write(vc4_state
,
841 VC4_SET_FIELD(vc4_state
->crtc_w
,
842 SCALER_POS1_SCL_WIDTH
) |
843 VC4_SET_FIELD(vc4_state
->crtc_h
,
844 SCALER_POS1_SCL_HEIGHT
));
847 /* Position Word 2: Source Image Size, Alpha */
848 vc4_state
->pos2_offset
= vc4_state
->dlist_count
;
849 vc4_dlist_write(vc4_state
,
850 VC4_SET_FIELD(fb
->format
->has_alpha
?
851 SCALER_POS2_ALPHA_MODE_PIPELINE
:
852 SCALER_POS2_ALPHA_MODE_FIXED
,
853 SCALER_POS2_ALPHA_MODE
) |
854 (mix_plane_alpha
? SCALER_POS2_ALPHA_MIX
: 0) |
855 (fb
->format
->has_alpha
?
856 SCALER_POS2_ALPHA_PREMULT
: 0) |
857 VC4_SET_FIELD(vc4_state
->src_w
[0],
859 VC4_SET_FIELD(vc4_state
->src_h
[0],
860 SCALER_POS2_HEIGHT
));
862 /* Position Word 3: Context. Written by the HVS. */
863 vc4_dlist_write(vc4_state
, 0xc0c0c0c0);
866 u32 hvs_pixel_order
= format
->pixel_order
;
868 if (format
->pixel_order_hvs5
)
869 hvs_pixel_order
= format
->pixel_order_hvs5
;
872 vc4_dlist_write(vc4_state
,
874 (hvs_pixel_order
<< SCALER_CTL0_ORDER_SHIFT
) |
875 (hvs_format
<< SCALER_CTL0_PIXEL_FORMAT_SHIFT
) |
876 VC4_SET_FIELD(tiling
, SCALER_CTL0_TILING
) |
877 (vc4_state
->is_unity
?
878 SCALER5_CTL0_UNITY
: 0) |
879 VC4_SET_FIELD(scl0
, SCALER_CTL0_SCL0
) |
880 VC4_SET_FIELD(scl1
, SCALER_CTL0_SCL1
) |
881 SCALER5_CTL0_ALPHA_EXPAND
|
882 SCALER5_CTL0_RGB_EXPAND
);
884 /* Position Word 0: Image Positions and Alpha Value */
885 vc4_state
->pos0_offset
= vc4_state
->dlist_count
;
886 vc4_dlist_write(vc4_state
,
887 (rotation
& DRM_MODE_REFLECT_Y
?
888 SCALER5_POS0_VFLIP
: 0) |
889 VC4_SET_FIELD(vc4_state
->crtc_x
,
890 SCALER_POS0_START_X
) |
891 (rotation
& DRM_MODE_REFLECT_X
?
892 SCALER5_POS0_HFLIP
: 0) |
893 VC4_SET_FIELD(vc4_state
->crtc_y
,
894 SCALER5_POS0_START_Y
)
898 vc4_dlist_write(vc4_state
,
899 VC4_SET_FIELD(state
->alpha
>> 4,
900 SCALER5_CTL2_ALPHA
) |
901 (fb
->format
->has_alpha
?
902 SCALER5_CTL2_ALPHA_PREMULT
: 0) |
904 SCALER5_CTL2_ALPHA_MIX
: 0) |
905 VC4_SET_FIELD(fb
->format
->has_alpha
?
906 SCALER5_CTL2_ALPHA_MODE_PIPELINE
:
907 SCALER5_CTL2_ALPHA_MODE_FIXED
,
908 SCALER5_CTL2_ALPHA_MODE
)
911 /* Position Word 1: Scaled Image Dimensions. */
912 if (!vc4_state
->is_unity
) {
913 vc4_dlist_write(vc4_state
,
914 VC4_SET_FIELD(vc4_state
->crtc_w
,
915 SCALER_POS1_SCL_WIDTH
) |
916 VC4_SET_FIELD(vc4_state
->crtc_h
,
917 SCALER_POS1_SCL_HEIGHT
));
920 /* Position Word 2: Source Image Size */
921 vc4_state
->pos2_offset
= vc4_state
->dlist_count
;
922 vc4_dlist_write(vc4_state
,
923 VC4_SET_FIELD(vc4_state
->src_w
[0],
924 SCALER5_POS2_WIDTH
) |
925 VC4_SET_FIELD(vc4_state
->src_h
[0],
926 SCALER5_POS2_HEIGHT
));
928 /* Position Word 3: Context. Written by the HVS. */
929 vc4_dlist_write(vc4_state
, 0xc0c0c0c0);
933 /* Pointer Word 0/1/2: RGB / Y / Cb / Cr Pointers
935 * The pointers may be any byte address.
937 vc4_state
->ptr0_offset
= vc4_state
->dlist_count
;
938 for (i
= 0; i
< num_planes
; i
++)
939 vc4_dlist_write(vc4_state
, vc4_state
->offsets
[i
]);
941 /* Pointer Context Word 0/1/2: Written by the HVS */
942 for (i
= 0; i
< num_planes
; i
++)
943 vc4_dlist_write(vc4_state
, 0xc0c0c0c0);
946 vc4_dlist_write(vc4_state
, pitch0
);
949 for (i
= 1; i
< num_planes
; i
++) {
950 if (hvs_format
!= HVS_PIXEL_FORMAT_H264
) {
951 vc4_dlist_write(vc4_state
,
952 VC4_SET_FIELD(fb
->pitches
[i
],
955 vc4_dlist_write(vc4_state
, pitch0
);
959 /* Colorspace conversion words */
960 if (vc4_state
->is_yuv
) {
961 vc4_dlist_write(vc4_state
, SCALER_CSC0_ITR_R_601_5
);
962 vc4_dlist_write(vc4_state
, SCALER_CSC1_ITR_R_601_5
);
963 vc4_dlist_write(vc4_state
, SCALER_CSC2_ITR_R_601_5
);
966 vc4_state
->lbm_offset
= 0;
968 if (vc4_state
->x_scaling
[0] != VC4_SCALING_NONE
||
969 vc4_state
->x_scaling
[1] != VC4_SCALING_NONE
||
970 vc4_state
->y_scaling
[0] != VC4_SCALING_NONE
||
971 vc4_state
->y_scaling
[1] != VC4_SCALING_NONE
) {
972 /* Reserve a slot for the LBM Base Address. The real value will
973 * be set when calling vc4_plane_allocate_lbm().
975 if (vc4_state
->y_scaling
[0] != VC4_SCALING_NONE
||
976 vc4_state
->y_scaling
[1] != VC4_SCALING_NONE
)
977 vc4_state
->lbm_offset
= vc4_state
->dlist_count
++;
979 if (num_planes
> 1) {
980 /* Emit Cb/Cr as channel 0 and Y as channel
981 * 1. This matches how we set up scl0/scl1
984 vc4_write_scaling_parameters(state
, 1);
986 vc4_write_scaling_parameters(state
, 0);
988 /* If any PPF setup was done, then all the kernel
989 * pointers get uploaded.
991 if (vc4_state
->x_scaling
[0] == VC4_SCALING_PPF
||
992 vc4_state
->y_scaling
[0] == VC4_SCALING_PPF
||
993 vc4_state
->x_scaling
[1] == VC4_SCALING_PPF
||
994 vc4_state
->y_scaling
[1] == VC4_SCALING_PPF
) {
995 u32 kernel
= VC4_SET_FIELD(vc4
->hvs
->mitchell_netravali_filter
.start
,
996 SCALER_PPF_KERNEL_OFFSET
);
999 vc4_dlist_write(vc4_state
, kernel
);
1001 vc4_dlist_write(vc4_state
, kernel
);
1003 vc4_dlist_write(vc4_state
, kernel
);
1005 vc4_dlist_write(vc4_state
, kernel
);
1009 vc4_state
->dlist
[ctl0_offset
] |=
1010 VC4_SET_FIELD(vc4_state
->dlist_count
, SCALER_CTL0_SIZE
);
1012 /* crtc_* are already clipped coordinates. */
1013 covers_screen
= vc4_state
->crtc_x
== 0 && vc4_state
->crtc_y
== 0 &&
1014 vc4_state
->crtc_w
== state
->crtc
->mode
.hdisplay
&&
1015 vc4_state
->crtc_h
== state
->crtc
->mode
.vdisplay
;
1016 /* Background fill might be necessary when the plane has per-pixel
1017 * alpha content or a non-opaque plane alpha and could blend from the
1018 * background or does not cover the entire screen.
1020 vc4_state
->needs_bg_fill
= fb
->format
->has_alpha
|| !covers_screen
||
1021 state
->alpha
!= DRM_BLEND_ALPHA_OPAQUE
;
1023 /* Flag the dlist as initialized to avoid checking it twice in case
1024 * the async update check already called vc4_plane_mode_set() and
1025 * decided to fallback to sync update because async update was not
1028 vc4_state
->dlist_initialized
= 1;
1030 vc4_plane_calc_load(state
);
1035 /* If a modeset involves changing the setup of a plane, the atomic
1036 * infrastructure will call this to validate a proposed plane setup.
1037 * However, if a plane isn't getting updated, this (and the
1038 * corresponding vc4_plane_atomic_update) won't get called. Thus, we
1039 * compute the dlist here and have all active plane dlists get updated
1040 * in the CRTC's flush.
1042 static int vc4_plane_atomic_check(struct drm_plane
*plane
,
1043 struct drm_plane_state
*state
)
1045 struct vc4_plane_state
*vc4_state
= to_vc4_plane_state(state
);
1048 vc4_state
->dlist_count
= 0;
1050 if (!plane_enabled(state
))
1053 ret
= vc4_plane_mode_set(plane
, state
);
1057 return vc4_plane_allocate_lbm(state
);
1060 static void vc4_plane_atomic_update(struct drm_plane
*plane
,
1061 struct drm_plane_state
*old_state
)
1063 /* No contents here. Since we don't know where in the CRTC's
1064 * dlist we should be stored, our dlist is uploaded to the
1065 * hardware with vc4_plane_write_dlist() at CRTC atomic_flush
1070 u32
vc4_plane_write_dlist(struct drm_plane
*plane
, u32 __iomem
*dlist
)
1072 struct vc4_plane_state
*vc4_state
= to_vc4_plane_state(plane
->state
);
1075 vc4_state
->hw_dlist
= dlist
;
1077 /* Can't memcpy_toio() because it needs to be 32-bit writes. */
1078 for (i
= 0; i
< vc4_state
->dlist_count
; i
++)
1079 writel(vc4_state
->dlist
[i
], &dlist
[i
]);
1081 return vc4_state
->dlist_count
;
1084 u32
vc4_plane_dlist_size(const struct drm_plane_state
*state
)
1086 const struct vc4_plane_state
*vc4_state
=
1087 container_of(state
, typeof(*vc4_state
), base
);
1089 return vc4_state
->dlist_count
;
1092 /* Updates the plane to immediately (well, once the FIFO needs
1093 * refilling) scan out from at a new framebuffer.
1095 void vc4_plane_async_set_fb(struct drm_plane
*plane
, struct drm_framebuffer
*fb
)
1097 struct vc4_plane_state
*vc4_state
= to_vc4_plane_state(plane
->state
);
1098 struct drm_gem_cma_object
*bo
= drm_fb_cma_get_gem_obj(fb
, 0);
1101 /* We're skipping the address adjustment for negative origin,
1102 * because this is only called on the primary plane.
1104 WARN_ON_ONCE(plane
->state
->crtc_x
< 0 || plane
->state
->crtc_y
< 0);
1105 addr
= bo
->paddr
+ fb
->offsets
[0];
1107 /* Write the new address into the hardware immediately. The
1108 * scanout will start from this address as soon as the FIFO
1109 * needs to refill with pixels.
1111 writel(addr
, &vc4_state
->hw_dlist
[vc4_state
->ptr0_offset
]);
1113 /* Also update the CPU-side dlist copy, so that any later
1114 * atomic updates that don't do a new modeset on our plane
1115 * also use our updated address.
1117 vc4_state
->dlist
[vc4_state
->ptr0_offset
] = addr
;
1120 static void vc4_plane_atomic_async_update(struct drm_plane
*plane
,
1121 struct drm_plane_state
*state
)
1123 struct vc4_plane_state
*vc4_state
, *new_vc4_state
;
1125 swap(plane
->state
->fb
, state
->fb
);
1126 plane
->state
->crtc_x
= state
->crtc_x
;
1127 plane
->state
->crtc_y
= state
->crtc_y
;
1128 plane
->state
->crtc_w
= state
->crtc_w
;
1129 plane
->state
->crtc_h
= state
->crtc_h
;
1130 plane
->state
->src_x
= state
->src_x
;
1131 plane
->state
->src_y
= state
->src_y
;
1132 plane
->state
->src_w
= state
->src_w
;
1133 plane
->state
->src_h
= state
->src_h
;
1134 plane
->state
->src_h
= state
->src_h
;
1135 plane
->state
->alpha
= state
->alpha
;
1136 plane
->state
->pixel_blend_mode
= state
->pixel_blend_mode
;
1137 plane
->state
->rotation
= state
->rotation
;
1138 plane
->state
->zpos
= state
->zpos
;
1139 plane
->state
->normalized_zpos
= state
->normalized_zpos
;
1140 plane
->state
->color_encoding
= state
->color_encoding
;
1141 plane
->state
->color_range
= state
->color_range
;
1142 plane
->state
->src
= state
->src
;
1143 plane
->state
->dst
= state
->dst
;
1144 plane
->state
->visible
= state
->visible
;
1146 new_vc4_state
= to_vc4_plane_state(state
);
1147 vc4_state
= to_vc4_plane_state(plane
->state
);
1149 vc4_state
->crtc_x
= new_vc4_state
->crtc_x
;
1150 vc4_state
->crtc_y
= new_vc4_state
->crtc_y
;
1151 vc4_state
->crtc_h
= new_vc4_state
->crtc_h
;
1152 vc4_state
->crtc_w
= new_vc4_state
->crtc_w
;
1153 vc4_state
->src_x
= new_vc4_state
->src_x
;
1154 vc4_state
->src_y
= new_vc4_state
->src_y
;
1155 memcpy(vc4_state
->src_w
, new_vc4_state
->src_w
,
1156 sizeof(vc4_state
->src_w
));
1157 memcpy(vc4_state
->src_h
, new_vc4_state
->src_h
,
1158 sizeof(vc4_state
->src_h
));
1159 memcpy(vc4_state
->x_scaling
, new_vc4_state
->x_scaling
,
1160 sizeof(vc4_state
->x_scaling
));
1161 memcpy(vc4_state
->y_scaling
, new_vc4_state
->y_scaling
,
1162 sizeof(vc4_state
->y_scaling
));
1163 vc4_state
->is_unity
= new_vc4_state
->is_unity
;
1164 vc4_state
->is_yuv
= new_vc4_state
->is_yuv
;
1165 memcpy(vc4_state
->offsets
, new_vc4_state
->offsets
,
1166 sizeof(vc4_state
->offsets
));
1167 vc4_state
->needs_bg_fill
= new_vc4_state
->needs_bg_fill
;
1169 /* Update the current vc4_state pos0, pos2 and ptr0 dlist entries. */
1170 vc4_state
->dlist
[vc4_state
->pos0_offset
] =
1171 new_vc4_state
->dlist
[vc4_state
->pos0_offset
];
1172 vc4_state
->dlist
[vc4_state
->pos2_offset
] =
1173 new_vc4_state
->dlist
[vc4_state
->pos2_offset
];
1174 vc4_state
->dlist
[vc4_state
->ptr0_offset
] =
1175 new_vc4_state
->dlist
[vc4_state
->ptr0_offset
];
1177 /* Note that we can't just call vc4_plane_write_dlist()
1178 * because that would smash the context data that the HVS is
1181 writel(vc4_state
->dlist
[vc4_state
->pos0_offset
],
1182 &vc4_state
->hw_dlist
[vc4_state
->pos0_offset
]);
1183 writel(vc4_state
->dlist
[vc4_state
->pos2_offset
],
1184 &vc4_state
->hw_dlist
[vc4_state
->pos2_offset
]);
1185 writel(vc4_state
->dlist
[vc4_state
->ptr0_offset
],
1186 &vc4_state
->hw_dlist
[vc4_state
->ptr0_offset
]);
1189 static int vc4_plane_atomic_async_check(struct drm_plane
*plane
,
1190 struct drm_plane_state
*state
)
1192 struct vc4_plane_state
*old_vc4_state
, *new_vc4_state
;
1196 ret
= vc4_plane_mode_set(plane
, state
);
1200 old_vc4_state
= to_vc4_plane_state(plane
->state
);
1201 new_vc4_state
= to_vc4_plane_state(state
);
1202 if (old_vc4_state
->dlist_count
!= new_vc4_state
->dlist_count
||
1203 old_vc4_state
->pos0_offset
!= new_vc4_state
->pos0_offset
||
1204 old_vc4_state
->pos2_offset
!= new_vc4_state
->pos2_offset
||
1205 old_vc4_state
->ptr0_offset
!= new_vc4_state
->ptr0_offset
||
1206 vc4_lbm_size(plane
->state
) != vc4_lbm_size(state
))
1209 /* Only pos0, pos2 and ptr0 DWORDS can be updated in an async update
1210 * if anything else has changed, fallback to a sync update.
1212 for (i
= 0; i
< new_vc4_state
->dlist_count
; i
++) {
1213 if (i
== new_vc4_state
->pos0_offset
||
1214 i
== new_vc4_state
->pos2_offset
||
1215 i
== new_vc4_state
->ptr0_offset
||
1216 (new_vc4_state
->lbm_offset
&&
1217 i
== new_vc4_state
->lbm_offset
))
1220 if (new_vc4_state
->dlist
[i
] != old_vc4_state
->dlist
[i
])
1227 static int vc4_prepare_fb(struct drm_plane
*plane
,
1228 struct drm_plane_state
*state
)
1236 bo
= to_vc4_bo(&drm_fb_cma_get_gem_obj(state
->fb
, 0)->base
);
1238 drm_gem_fb_prepare_fb(plane
, state
);
1240 if (plane
->state
->fb
== state
->fb
)
1243 ret
= vc4_bo_inc_usecnt(bo
);
1250 static void vc4_cleanup_fb(struct drm_plane
*plane
,
1251 struct drm_plane_state
*state
)
1255 if (plane
->state
->fb
== state
->fb
|| !state
->fb
)
1258 bo
= to_vc4_bo(&drm_fb_cma_get_gem_obj(state
->fb
, 0)->base
);
1259 vc4_bo_dec_usecnt(bo
);
1262 static const struct drm_plane_helper_funcs vc4_plane_helper_funcs
= {
1263 .atomic_check
= vc4_plane_atomic_check
,
1264 .atomic_update
= vc4_plane_atomic_update
,
1265 .prepare_fb
= vc4_prepare_fb
,
1266 .cleanup_fb
= vc4_cleanup_fb
,
1267 .atomic_async_check
= vc4_plane_atomic_async_check
,
1268 .atomic_async_update
= vc4_plane_atomic_async_update
,
1271 static void vc4_plane_destroy(struct drm_plane
*plane
)
1273 drm_plane_cleanup(plane
);
1276 static bool vc4_format_mod_supported(struct drm_plane
*plane
,
1280 /* Support T_TILING for RGB formats only. */
1282 case DRM_FORMAT_XRGB8888
:
1283 case DRM_FORMAT_ARGB8888
:
1284 case DRM_FORMAT_ABGR8888
:
1285 case DRM_FORMAT_XBGR8888
:
1286 case DRM_FORMAT_RGB565
:
1287 case DRM_FORMAT_BGR565
:
1288 case DRM_FORMAT_ARGB1555
:
1289 case DRM_FORMAT_XRGB1555
:
1290 switch (fourcc_mod_broadcom_mod(modifier
)) {
1291 case DRM_FORMAT_MOD_LINEAR
:
1292 case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED
:
1297 case DRM_FORMAT_NV12
:
1298 case DRM_FORMAT_NV21
:
1299 switch (fourcc_mod_broadcom_mod(modifier
)) {
1300 case DRM_FORMAT_MOD_LINEAR
:
1301 case DRM_FORMAT_MOD_BROADCOM_SAND64
:
1302 case DRM_FORMAT_MOD_BROADCOM_SAND128
:
1303 case DRM_FORMAT_MOD_BROADCOM_SAND256
:
1308 case DRM_FORMAT_RGBX1010102
:
1309 case DRM_FORMAT_BGRX1010102
:
1310 case DRM_FORMAT_RGBA1010102
:
1311 case DRM_FORMAT_BGRA1010102
:
1312 case DRM_FORMAT_YUV422
:
1313 case DRM_FORMAT_YVU422
:
1314 case DRM_FORMAT_YUV420
:
1315 case DRM_FORMAT_YVU420
:
1316 case DRM_FORMAT_NV16
:
1317 case DRM_FORMAT_NV61
:
1319 return (modifier
== DRM_FORMAT_MOD_LINEAR
);
1323 static const struct drm_plane_funcs vc4_plane_funcs
= {
1324 .update_plane
= drm_atomic_helper_update_plane
,
1325 .disable_plane
= drm_atomic_helper_disable_plane
,
1326 .destroy
= vc4_plane_destroy
,
1327 .set_property
= NULL
,
1328 .reset
= vc4_plane_reset
,
1329 .atomic_duplicate_state
= vc4_plane_duplicate_state
,
1330 .atomic_destroy_state
= vc4_plane_destroy_state
,
1331 .format_mod_supported
= vc4_format_mod_supported
,
1334 struct drm_plane
*vc4_plane_init(struct drm_device
*dev
,
1335 enum drm_plane_type type
)
1337 struct drm_plane
*plane
= NULL
;
1338 struct vc4_plane
*vc4_plane
;
1339 u32 formats
[ARRAY_SIZE(hvs_formats
)];
1342 static const uint64_t modifiers
[] = {
1343 DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED
,
1344 DRM_FORMAT_MOD_BROADCOM_SAND128
,
1345 DRM_FORMAT_MOD_BROADCOM_SAND64
,
1346 DRM_FORMAT_MOD_BROADCOM_SAND256
,
1347 DRM_FORMAT_MOD_LINEAR
,
1348 DRM_FORMAT_MOD_INVALID
1351 vc4_plane
= devm_kzalloc(dev
->dev
, sizeof(*vc4_plane
),
1354 return ERR_PTR(-ENOMEM
);
1356 for (i
= 0; i
< ARRAY_SIZE(hvs_formats
); i
++)
1357 formats
[i
] = hvs_formats
[i
].drm
;
1359 plane
= &vc4_plane
->base
;
1360 ret
= drm_universal_plane_init(dev
, plane
, 0,
1362 formats
, ARRAY_SIZE(formats
),
1363 modifiers
, type
, NULL
);
1365 return ERR_PTR(ret
);
1367 drm_plane_helper_add(plane
, &vc4_plane_helper_funcs
);
1369 drm_plane_create_alpha_property(plane
);
1370 drm_plane_create_rotation_property(plane
, DRM_MODE_ROTATE_0
,
1372 DRM_MODE_ROTATE_180
|
1373 DRM_MODE_REFLECT_X
|
1374 DRM_MODE_REFLECT_Y
);
1379 int vc4_plane_create_additional_planes(struct drm_device
*drm
)
1381 struct drm_plane
*cursor_plane
;
1382 struct drm_crtc
*crtc
;
1385 /* Set up some arbitrary number of planes. We're not limited
1386 * by a set number of physical registers, just the space in
1387 * the HVS (16k) and how small an plane can be (28 bytes).
1388 * However, each plane we set up takes up some memory, and
1389 * increases the cost of looping over planes, which atomic
1390 * modesetting does quite a bit. As a result, we pick a
1391 * modest number of planes to expose, that should hopefully
1392 * still cover any sane usecase.
1394 for (i
= 0; i
< 16; i
++) {
1395 struct drm_plane
*plane
=
1396 vc4_plane_init(drm
, DRM_PLANE_TYPE_OVERLAY
);
1401 plane
->possible_crtcs
=
1402 GENMASK(drm
->mode_config
.num_crtc
- 1, 0);
1405 drm_for_each_crtc(crtc
, drm
) {
1406 /* Set up the legacy cursor after overlay initialization,
1407 * since we overlay planes on the CRTC in the order they were
1410 cursor_plane
= vc4_plane_init(drm
, DRM_PLANE_TYPE_CURSOR
);
1411 if (!IS_ERR(cursor_plane
)) {
1412 cursor_plane
->possible_crtcs
= drm_crtc_mask(crtc
);
1413 crtc
->cursor
= cursor_plane
;