forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-01-04 1543e317f1da31b75942316931e8f491a8920811
kernel/drivers/gpu/drm/vc4/vc4_plane.c
....@@ -1,9 +1,6 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Copyright (C) 2015 Broadcom
3
- *
4
- * This program is free software; you can redistribute it and/or modify
5
- * it under the terms of the GNU General Public License version 2 as
6
- * published by the Free Software Foundation.
74 */
85
96 /**
....@@ -20,10 +17,14 @@
2017
2118 #include <drm/drm_atomic.h>
2219 #include <drm/drm_atomic_helper.h>
20
+#include <drm/drm_atomic_uapi.h>
2321 #include <drm/drm_fb_cma_helper.h>
22
+#include <drm/drm_fourcc.h>
23
+#include <drm/drm_gem_framebuffer_helper.h>
2424 #include <drm/drm_plane_helper.h>
2525
2626 #include "uapi/drm/vc4_drm.h"
27
+
2728 #include "vc4_drv.h"
2829 #include "vc4_regs.h"
2930
....@@ -31,45 +32,62 @@
3132 u32 drm; /* DRM_FORMAT_* */
3233 u32 hvs; /* HVS_FORMAT_* */
3334 u32 pixel_order;
35
+ u32 pixel_order_hvs5;
3436 } hvs_formats[] = {
3537 {
36
- .drm = DRM_FORMAT_XRGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
38
+ .drm = DRM_FORMAT_XRGB8888,
39
+ .hvs = HVS_PIXEL_FORMAT_RGBA8888,
3740 .pixel_order = HVS_PIXEL_ORDER_ABGR,
41
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
3842 },
3943 {
40
- .drm = DRM_FORMAT_ARGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
44
+ .drm = DRM_FORMAT_ARGB8888,
45
+ .hvs = HVS_PIXEL_FORMAT_RGBA8888,
4146 .pixel_order = HVS_PIXEL_ORDER_ABGR,
47
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
4248 },
4349 {
44
- .drm = DRM_FORMAT_ABGR8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
50
+ .drm = DRM_FORMAT_ABGR8888,
51
+ .hvs = HVS_PIXEL_FORMAT_RGBA8888,
4552 .pixel_order = HVS_PIXEL_ORDER_ARGB,
53
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,
4654 },
4755 {
48
- .drm = DRM_FORMAT_XBGR8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
56
+ .drm = DRM_FORMAT_XBGR8888,
57
+ .hvs = HVS_PIXEL_FORMAT_RGBA8888,
4958 .pixel_order = HVS_PIXEL_ORDER_ARGB,
59
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,
5060 },
5161 {
52
- .drm = DRM_FORMAT_RGB565, .hvs = HVS_PIXEL_FORMAT_RGB565,
62
+ .drm = DRM_FORMAT_RGB565,
63
+ .hvs = HVS_PIXEL_FORMAT_RGB565,
5364 .pixel_order = HVS_PIXEL_ORDER_XRGB,
5465 },
5566 {
56
- .drm = DRM_FORMAT_BGR565, .hvs = HVS_PIXEL_FORMAT_RGB565,
67
+ .drm = DRM_FORMAT_BGR565,
68
+ .hvs = HVS_PIXEL_FORMAT_RGB565,
5769 .pixel_order = HVS_PIXEL_ORDER_XBGR,
5870 },
5971 {
60
- .drm = DRM_FORMAT_ARGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
72
+ .drm = DRM_FORMAT_ARGB1555,
73
+ .hvs = HVS_PIXEL_FORMAT_RGBA5551,
6174 .pixel_order = HVS_PIXEL_ORDER_ABGR,
75
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
6276 },
6377 {
64
- .drm = DRM_FORMAT_XRGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
78
+ .drm = DRM_FORMAT_XRGB1555,
79
+ .hvs = HVS_PIXEL_FORMAT_RGBA5551,
6580 .pixel_order = HVS_PIXEL_ORDER_ABGR,
81
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
6682 },
6783 {
68
- .drm = DRM_FORMAT_RGB888, .hvs = HVS_PIXEL_FORMAT_RGB888,
84
+ .drm = DRM_FORMAT_RGB888,
85
+ .hvs = HVS_PIXEL_FORMAT_RGB888,
6986 .pixel_order = HVS_PIXEL_ORDER_XRGB,
7087 },
7188 {
72
- .drm = DRM_FORMAT_BGR888, .hvs = HVS_PIXEL_FORMAT_RGB888,
89
+ .drm = DRM_FORMAT_BGR888,
90
+ .hvs = HVS_PIXEL_FORMAT_RGB888,
7391 .pixel_order = HVS_PIXEL_ORDER_XBGR,
7492 },
7593 {
....@@ -128,17 +146,17 @@
128146
129147 static enum vc4_scaling_mode vc4_get_scaling_mode(u32 src, u32 dst)
130148 {
131
- if (dst > src)
132
- return VC4_SCALING_PPF;
133
- else if (dst < src)
134
- return VC4_SCALING_TPZ;
135
- else
149
+ if (dst == src)
136150 return VC4_SCALING_NONE;
151
+ if (3 * dst >= 2 * src)
152
+ return VC4_SCALING_PPF;
153
+ else
154
+ return VC4_SCALING_TPZ;
137155 }
138156
139157 static bool plane_enabled(struct drm_plane_state *state)
140158 {
141
- return state->fb && state->crtc;
159
+ return state->fb && !WARN_ON(!state->crtc);
142160 }
143161
144162 static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane)
....@@ -153,6 +171,7 @@
153171 return NULL;
154172
155173 memset(&vc4_state->lbm, 0, sizeof(vc4_state->lbm));
174
+ vc4_state->dlist_initialized = 0;
156175
157176 __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base);
158177
....@@ -176,7 +195,7 @@
176195 struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
177196 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
178197
179
- if (vc4_state->lbm.allocated) {
198
+ if (drm_mm_node_allocated(&vc4_state->lbm)) {
180199 unsigned long irqflags;
181200
182201 spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags);
....@@ -200,12 +219,10 @@
200219 if (!vc4_state)
201220 return;
202221
203
- plane->state = &vc4_state->base;
204
- plane->state->alpha = DRM_BLEND_ALPHA_OPAQUE;
205
- vc4_state->base.plane = plane;
222
+ __drm_atomic_helper_plane_reset(plane, &vc4_state->base);
206223 }
207224
208
-static void vc4_dlist_write(struct vc4_plane_state *vc4_state, u32 val)
225
+static void vc4_dlist_counter_increment(struct vc4_plane_state *vc4_state)
209226 {
210227 if (vc4_state->dlist_count == vc4_state->dlist_size) {
211228 u32 new_size = max(4u, vc4_state->dlist_count * 2);
....@@ -220,7 +237,15 @@
220237 vc4_state->dlist_size = new_size;
221238 }
222239
223
- vc4_state->dlist[vc4_state->dlist_count++] = val;
240
+ vc4_state->dlist_count++;
241
+}
242
+
243
+static void vc4_dlist_write(struct vc4_plane_state *vc4_state, u32 val)
244
+{
245
+ unsigned int idx = vc4_state->dlist_count;
246
+
247
+ vc4_dlist_counter_increment(vc4_state);
248
+ vc4_state->dlist[idx] = val;
224249 }
225250
226251 /* Returns the scl0/scl1 field based on whether the dimensions need to
....@@ -258,39 +283,96 @@
258283 }
259284 }
260285
286
+static int vc4_plane_margins_adj(struct drm_plane_state *pstate)
287
+{
288
+ struct vc4_plane_state *vc4_pstate = to_vc4_plane_state(pstate);
289
+ unsigned int left, right, top, bottom, adjhdisplay, adjvdisplay;
290
+ struct drm_crtc_state *crtc_state;
291
+
292
+ crtc_state = drm_atomic_get_new_crtc_state(pstate->state,
293
+ pstate->crtc);
294
+
295
+ vc4_crtc_get_margins(crtc_state, &left, &right, &top, &bottom);
296
+ if (!left && !right && !top && !bottom)
297
+ return 0;
298
+
299
+ if (left + right >= crtc_state->mode.hdisplay ||
300
+ top + bottom >= crtc_state->mode.vdisplay)
301
+ return -EINVAL;
302
+
303
+ adjhdisplay = crtc_state->mode.hdisplay - (left + right);
304
+ vc4_pstate->crtc_x = DIV_ROUND_CLOSEST(vc4_pstate->crtc_x *
305
+ adjhdisplay,
306
+ crtc_state->mode.hdisplay);
307
+ vc4_pstate->crtc_x += left;
308
+ if (vc4_pstate->crtc_x > crtc_state->mode.hdisplay - right)
309
+ vc4_pstate->crtc_x = crtc_state->mode.hdisplay - right;
310
+
311
+ adjvdisplay = crtc_state->mode.vdisplay - (top + bottom);
312
+ vc4_pstate->crtc_y = DIV_ROUND_CLOSEST(vc4_pstate->crtc_y *
313
+ adjvdisplay,
314
+ crtc_state->mode.vdisplay);
315
+ vc4_pstate->crtc_y += top;
316
+ if (vc4_pstate->crtc_y > crtc_state->mode.vdisplay - bottom)
317
+ vc4_pstate->crtc_y = crtc_state->mode.vdisplay - bottom;
318
+
319
+ vc4_pstate->crtc_w = DIV_ROUND_CLOSEST(vc4_pstate->crtc_w *
320
+ adjhdisplay,
321
+ crtc_state->mode.hdisplay);
322
+ vc4_pstate->crtc_h = DIV_ROUND_CLOSEST(vc4_pstate->crtc_h *
323
+ adjvdisplay,
324
+ crtc_state->mode.vdisplay);
325
+
326
+ if (!vc4_pstate->crtc_w || !vc4_pstate->crtc_h)
327
+ return -EINVAL;
328
+
329
+ return 0;
330
+}
331
+
261332 static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
262333 {
263
- struct drm_plane *plane = state->plane;
264334 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
265335 struct drm_framebuffer *fb = state->fb;
266336 struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
267
- u32 subpixel_src_mask = (1 << 16) - 1;
268
- u32 format = fb->format->format;
269337 int num_planes = fb->format->num_planes;
270
- u32 h_subsample = 1;
271
- u32 v_subsample = 1;
272
- int i;
338
+ struct drm_crtc_state *crtc_state;
339
+ u32 h_subsample = fb->format->hsub;
340
+ u32 v_subsample = fb->format->vsub;
341
+ int i, ret;
342
+
343
+ crtc_state = drm_atomic_get_existing_crtc_state(state->state,
344
+ state->crtc);
345
+ if (!crtc_state) {
346
+ DRM_DEBUG_KMS("Invalid crtc state\n");
347
+ return -EINVAL;
348
+ }
349
+
350
+ ret = drm_atomic_helper_check_plane_state(state, crtc_state, 1,
351
+ INT_MAX, true, true);
352
+ if (ret)
353
+ return ret;
273354
274355 for (i = 0; i < num_planes; i++)
275356 vc4_state->offsets[i] = bo->paddr + fb->offsets[i];
276357
277
- /* We don't support subpixel source positioning for scaling. */
278
- if ((state->src_x & subpixel_src_mask) ||
279
- (state->src_y & subpixel_src_mask) ||
280
- (state->src_w & subpixel_src_mask) ||
281
- (state->src_h & subpixel_src_mask)) {
282
- return -EINVAL;
283
- }
358
+ /*
359
+ * We don't support subpixel source positioning for scaling,
360
+ * but fractional coordinates can be generated by clipping
361
+ * so just round for now
362
+ */
363
+ vc4_state->src_x = DIV_ROUND_CLOSEST(state->src.x1, 1 << 16);
364
+ vc4_state->src_y = DIV_ROUND_CLOSEST(state->src.y1, 1 << 16);
365
+ vc4_state->src_w[0] = DIV_ROUND_CLOSEST(state->src.x2, 1 << 16) - vc4_state->src_x;
366
+ vc4_state->src_h[0] = DIV_ROUND_CLOSEST(state->src.y2, 1 << 16) - vc4_state->src_y;
284367
285
- vc4_state->src_x = state->src_x >> 16;
286
- vc4_state->src_y = state->src_y >> 16;
287
- vc4_state->src_w[0] = state->src_w >> 16;
288
- vc4_state->src_h[0] = state->src_h >> 16;
368
+ vc4_state->crtc_x = state->dst.x1;
369
+ vc4_state->crtc_y = state->dst.y1;
370
+ vc4_state->crtc_w = state->dst.x2 - state->dst.x1;
371
+ vc4_state->crtc_h = state->dst.y2 - state->dst.y1;
289372
290
- vc4_state->crtc_x = state->crtc_x;
291
- vc4_state->crtc_y = state->crtc_y;
292
- vc4_state->crtc_w = state->crtc_w;
293
- vc4_state->crtc_h = state->crtc_h;
373
+ ret = vc4_plane_margins_adj(state);
374
+ if (ret)
375
+ return ret;
294376
295377 vc4_state->x_scaling[0] = vc4_get_scaling_mode(vc4_state->src_w[0],
296378 vc4_state->crtc_w);
....@@ -303,8 +385,6 @@
303385 if (num_planes > 1) {
304386 vc4_state->is_yuv = true;
305387
306
- h_subsample = drm_format_horz_chroma_subsampling(format);
307
- v_subsample = drm_format_vert_chroma_subsampling(format);
308388 vc4_state->src_w[1] = vc4_state->src_w[0] / h_subsample;
309389 vc4_state->src_h[1] = vc4_state->src_h[0] / v_subsample;
310390
....@@ -327,41 +407,6 @@
327407 vc4_state->is_yuv = false;
328408 vc4_state->x_scaling[1] = VC4_SCALING_NONE;
329409 vc4_state->y_scaling[1] = VC4_SCALING_NONE;
330
- }
331
-
332
- /* No configuring scaling on the cursor plane, since it gets
333
- non-vblank-synced updates, and scaling requires requires
334
- LBM changes which have to be vblank-synced.
335
- */
336
- if (plane->type == DRM_PLANE_TYPE_CURSOR && !vc4_state->is_unity)
337
- return -EINVAL;
338
-
339
- /* Clamp the on-screen start x/y to 0. The hardware doesn't
340
- * support negative y, and negative x wastes bandwidth.
341
- */
342
- if (vc4_state->crtc_x < 0) {
343
- for (i = 0; i < num_planes; i++) {
344
- u32 cpp = fb->format->cpp[i];
345
- u32 subs = ((i == 0) ? 1 : h_subsample);
346
-
347
- vc4_state->offsets[i] += (cpp *
348
- (-vc4_state->crtc_x) / subs);
349
- }
350
- vc4_state->src_w[0] += vc4_state->crtc_x;
351
- vc4_state->src_w[1] += vc4_state->crtc_x / h_subsample;
352
- vc4_state->crtc_x = 0;
353
- }
354
-
355
- if (vc4_state->crtc_y < 0) {
356
- for (i = 0; i < num_planes; i++) {
357
- u32 subs = ((i == 0) ? 1 : v_subsample);
358
-
359
- vc4_state->offsets[i] += (fb->pitches[i] *
360
- (-vc4_state->crtc_y) / subs);
361
- }
362
- vc4_state->src_h[0] += vc4_state->crtc_y;
363
- vc4_state->src_h[1] += vc4_state->crtc_y / v_subsample;
364
- vc4_state->crtc_y = 0;
365410 }
366411
367412 return 0;
....@@ -398,16 +443,29 @@
398443 static u32 vc4_lbm_size(struct drm_plane_state *state)
399444 {
400445 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
401
- /* This is the worst case number. One of the two sizes will
402
- * be used depending on the scaling configuration.
403
- */
404
- u32 pix_per_line = max(vc4_state->src_w[0], (u32)vc4_state->crtc_w);
446
+ struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev);
447
+ u32 pix_per_line;
405448 u32 lbm;
406449
450
+ /* LBM is not needed when there's no vertical scaling. */
451
+ if (vc4_state->y_scaling[0] == VC4_SCALING_NONE &&
452
+ vc4_state->y_scaling[1] == VC4_SCALING_NONE)
453
+ return 0;
454
+
455
+ /*
456
+ * This can be further optimized in the RGB/YUV444 case if the PPF
457
+ * decimation factor is between 0.5 and 1.0 by using crtc_w.
458
+ *
459
+ * It's not an issue though, since in that case since src_w[0] is going
460
+ * to be greater than or equal to crtc_w.
461
+ */
462
+ if (vc4_state->x_scaling[0] == VC4_SCALING_TPZ)
463
+ pix_per_line = vc4_state->crtc_w;
464
+ else
465
+ pix_per_line = vc4_state->src_w[0];
466
+
407467 if (!vc4_state->is_yuv) {
408
- if (vc4_state->is_unity)
409
- return 0;
410
- else if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ)
468
+ if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ)
411469 lbm = pix_per_line * 8;
412470 else {
413471 /* In special cases, this multiplier might be 12. */
....@@ -421,7 +479,11 @@
421479 lbm = pix_per_line * 16;
422480 }
423481
424
- lbm = roundup(lbm, 32);
482
+ /* Align it to 64 or 128 (hvs5) bytes */
483
+ lbm = roundup(lbm, vc4->hvs->hvs5 ? 128 : 64);
484
+
485
+ /* Each "word" of the LBM memory contains 2 or 4 (hvs5) pixels */
486
+ lbm /= vc4->hvs->hvs5 ? 4 : 2;
425487
426488 return lbm;
427489 }
....@@ -458,6 +520,105 @@
458520 }
459521 }
460522
523
+static void vc4_plane_calc_load(struct drm_plane_state *state)
524
+{
525
+ unsigned int hvs_load_shift, vrefresh, i;
526
+ struct drm_framebuffer *fb = state->fb;
527
+ struct vc4_plane_state *vc4_state;
528
+ struct drm_crtc_state *crtc_state;
529
+ unsigned int vscale_factor;
530
+ struct vc4_dev *vc4;
531
+
532
+ vc4 = to_vc4_dev(state->plane->dev);
533
+ if (!vc4->load_tracker_available)
534
+ return;
535
+
536
+ vc4_state = to_vc4_plane_state(state);
537
+ crtc_state = drm_atomic_get_existing_crtc_state(state->state,
538
+ state->crtc);
539
+ vrefresh = drm_mode_vrefresh(&crtc_state->adjusted_mode);
540
+
541
+ /* The HVS is able to process 2 pixels/cycle when scaling the source,
542
+ * 4 pixels/cycle otherwise.
543
+ * Alpha blending step seems to be pipelined and it's always operating
544
+ * at 4 pixels/cycle, so the limiting aspect here seems to be the
545
+ * scaler block.
546
+ * HVS load is expressed in clk-cycles/sec (AKA Hz).
547
+ */
548
+ if (vc4_state->x_scaling[0] != VC4_SCALING_NONE ||
549
+ vc4_state->x_scaling[1] != VC4_SCALING_NONE ||
550
+ vc4_state->y_scaling[0] != VC4_SCALING_NONE ||
551
+ vc4_state->y_scaling[1] != VC4_SCALING_NONE)
552
+ hvs_load_shift = 1;
553
+ else
554
+ hvs_load_shift = 2;
555
+
556
+ vc4_state->membus_load = 0;
557
+ vc4_state->hvs_load = 0;
558
+ for (i = 0; i < fb->format->num_planes; i++) {
559
+ /* Even if the bandwidth/plane required for a single frame is
560
+ *
561
+ * vc4_state->src_w[i] * vc4_state->src_h[i] * cpp * vrefresh
562
+ *
563
+ * when downscaling, we have to read more pixels per line in
564
+ * the time frame reserved for a single line, so the bandwidth
565
+ * demand can be punctually higher. To account for that, we
566
+ * calculate the down-scaling factor and multiply the plane
567
+ * load by this number. We're likely over-estimating the read
568
+ * demand, but that's better than under-estimating it.
569
+ */
570
+ vscale_factor = DIV_ROUND_UP(vc4_state->src_h[i],
571
+ vc4_state->crtc_h);
572
+ vc4_state->membus_load += vc4_state->src_w[i] *
573
+ vc4_state->src_h[i] * vscale_factor *
574
+ fb->format->cpp[i];
575
+ vc4_state->hvs_load += vc4_state->crtc_h * vc4_state->crtc_w;
576
+ }
577
+
578
+ vc4_state->hvs_load *= vrefresh;
579
+ vc4_state->hvs_load >>= hvs_load_shift;
580
+ vc4_state->membus_load *= vrefresh;
581
+}
582
+
583
+static int vc4_plane_allocate_lbm(struct drm_plane_state *state)
584
+{
585
+ struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev);
586
+ struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
587
+ unsigned long irqflags;
588
+ u32 lbm_size;
589
+
590
+ lbm_size = vc4_lbm_size(state);
591
+ if (!lbm_size)
592
+ return 0;
593
+
594
+ if (WARN_ON(!vc4_state->lbm_offset))
595
+ return -EINVAL;
596
+
597
+ /* Allocate the LBM memory that the HVS will use for temporary
598
+ * storage due to our scaling/format conversion.
599
+ */
600
+ if (!drm_mm_node_allocated(&vc4_state->lbm)) {
601
+ int ret;
602
+
603
+ spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags);
604
+ ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm,
605
+ &vc4_state->lbm,
606
+ lbm_size,
607
+ vc4->hvs->hvs5 ? 64 : 32,
608
+ 0, 0);
609
+ spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags);
610
+
611
+ if (ret)
612
+ return ret;
613
+ } else {
614
+ WARN_ON_ONCE(lbm_size != vc4_state->lbm.size);
615
+ }
616
+
617
+ vc4_state->dlist[vc4_state->lbm_offset] = vc4_state->lbm.start;
618
+
619
+ return 0;
620
+}
621
+
461622 /* Writes out a full display list for an active plane to the plane's
462623 * private dlist state.
463624 */
....@@ -470,35 +631,21 @@
470631 u32 ctl0_offset = vc4_state->dlist_count;
471632 const struct hvs_format *format = vc4_get_hvs_format(fb->format->format);
472633 u64 base_format_mod = fourcc_mod_broadcom_mod(fb->modifier);
473
- int num_planes = drm_format_num_planes(format->drm);
634
+ int num_planes = fb->format->num_planes;
635
+ u32 h_subsample = fb->format->hsub;
636
+ u32 v_subsample = fb->format->vsub;
474637 bool mix_plane_alpha;
475638 bool covers_screen;
476639 u32 scl0, scl1, pitch0;
477
- u32 lbm_size, tiling;
478
- unsigned long irqflags;
640
+ u32 tiling, src_y;
479641 u32 hvs_format = format->hvs;
642
+ unsigned int rotation;
480643 int ret, i;
481644
645
+ if (vc4_state->dlist_initialized)
646
+ return 0;
647
+
482648 ret = vc4_plane_setup_clipping_and_scaling(state);
483
- if (ret)
484
- return ret;
485
-
486
- /* Allocate the LBM memory that the HVS will use for temporary
487
- * storage due to our scaling/format conversion.
488
- */
489
- lbm_size = vc4_lbm_size(state);
490
- if (lbm_size) {
491
- if (!vc4_state->lbm.allocated) {
492
- spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags);
493
- ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm,
494
- &vc4_state->lbm,
495
- lbm_size, 32, 0, 0);
496
- spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags);
497
- } else {
498
- WARN_ON_ONCE(lbm_size != vc4_state->lbm.size);
499
- }
500
- }
501
-
502649 if (ret)
503650 return ret;
504651
....@@ -516,26 +663,101 @@
516663 scl1 = vc4_get_scl_field(state, 0);
517664 }
518665
666
+ rotation = drm_rotation_simplify(state->rotation,
667
+ DRM_MODE_ROTATE_0 |
668
+ DRM_MODE_REFLECT_X |
669
+ DRM_MODE_REFLECT_Y);
670
+
671
+ /* We must point to the last line when Y reflection is enabled. */
672
+ src_y = vc4_state->src_y;
673
+ if (rotation & DRM_MODE_REFLECT_Y)
674
+ src_y += vc4_state->src_h[0] - 1;
675
+
519676 switch (base_format_mod) {
520677 case DRM_FORMAT_MOD_LINEAR:
521678 tiling = SCALER_CTL0_TILING_LINEAR;
522679 pitch0 = VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH);
680
+
681
+ /* Adjust the base pointer to the first pixel to be scanned
682
+ * out.
683
+ */
684
+ for (i = 0; i < num_planes; i++) {
685
+ vc4_state->offsets[i] += src_y /
686
+ (i ? v_subsample : 1) *
687
+ fb->pitches[i];
688
+
689
+ vc4_state->offsets[i] += vc4_state->src_x /
690
+ (i ? h_subsample : 1) *
691
+ fb->format->cpp[i];
692
+ }
693
+
523694 break;
524695
525696 case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: {
526
- /* For T-tiled, the FB pitch is "how many bytes from
527
- * one row to the next, such that pitch * tile_h ==
528
- * tile_size * tiles_per_row."
529
- */
530697 u32 tile_size_shift = 12; /* T tiles are 4kb */
698
+ /* Whole-tile offsets, mostly for setting the pitch. */
699
+ u32 tile_w_shift = fb->format->cpp[0] == 2 ? 6 : 5;
531700 u32 tile_h_shift = 5; /* 16 and 32bpp are 32 pixels high */
701
+ u32 tile_w_mask = (1 << tile_w_shift) - 1;
702
+ /* The height mask on 32-bit-per-pixel tiles is 63, i.e. twice
703
+ * the height (in pixels) of a 4k tile.
704
+ */
705
+ u32 tile_h_mask = (2 << tile_h_shift) - 1;
706
+ /* For T-tiled, the FB pitch is "how many bytes from one row to
707
+ * the next, such that
708
+ *
709
+ * pitch * tile_h == tile_size * tiles_per_row
710
+ */
532711 u32 tiles_w = fb->pitches[0] >> (tile_size_shift - tile_h_shift);
712
+ u32 tiles_l = vc4_state->src_x >> tile_w_shift;
713
+ u32 tiles_r = tiles_w - tiles_l;
714
+ u32 tiles_t = src_y >> tile_h_shift;
715
+ /* Intra-tile offsets, which modify the base address (the
716
+ * SCALER_PITCH0_TILE_Y_OFFSET tells HVS how to walk from that
717
+ * base address).
718
+ */
719
+ u32 tile_y = (src_y >> 4) & 1;
720
+ u32 subtile_y = (src_y >> 2) & 3;
721
+ u32 utile_y = src_y & 3;
722
+ u32 x_off = vc4_state->src_x & tile_w_mask;
723
+ u32 y_off = src_y & tile_h_mask;
724
+
725
+ /* When Y reflection is requested we must set the
726
+ * SCALER_PITCH0_TILE_LINE_DIR flag to tell HVS that all lines
727
+ * after the initial one should be fetched in descending order,
728
+ * which makes sense since we start from the last line and go
729
+ * backward.
730
+ * Don't know why we need y_off = max_y_off - y_off, but it's
731
+ * definitely required (I guess it's also related to the "going
732
+ * backward" situation).
733
+ */
734
+ if (rotation & DRM_MODE_REFLECT_Y) {
735
+ y_off = tile_h_mask - y_off;
736
+ pitch0 = SCALER_PITCH0_TILE_LINE_DIR;
737
+ } else {
738
+ pitch0 = 0;
739
+ }
533740
534741 tiling = SCALER_CTL0_TILING_256B_OR_T;
742
+ pitch0 |= (VC4_SET_FIELD(x_off, SCALER_PITCH0_SINK_PIX) |
743
+ VC4_SET_FIELD(y_off, SCALER_PITCH0_TILE_Y_OFFSET) |
744
+ VC4_SET_FIELD(tiles_l, SCALER_PITCH0_TILE_WIDTH_L) |
745
+ VC4_SET_FIELD(tiles_r, SCALER_PITCH0_TILE_WIDTH_R));
746
+ vc4_state->offsets[0] += tiles_t * (tiles_w << tile_size_shift);
747
+ vc4_state->offsets[0] += subtile_y << 8;
748
+ vc4_state->offsets[0] += utile_y << 4;
535749
536
- pitch0 = (VC4_SET_FIELD(0, SCALER_PITCH0_TILE_Y_OFFSET) |
537
- VC4_SET_FIELD(0, SCALER_PITCH0_TILE_WIDTH_L) |
538
- VC4_SET_FIELD(tiles_w, SCALER_PITCH0_TILE_WIDTH_R));
750
+ /* Rows of tiles alternate left-to-right and right-to-left. */
751
+ if (tiles_t & 1) {
752
+ pitch0 |= SCALER_PITCH0_TILE_INITIAL_LINE_DIR;
753
+ vc4_state->offsets[0] += (tiles_w - tiles_l) <<
754
+ tile_size_shift;
755
+ vc4_state->offsets[0] -= (1 + !tile_y) << 10;
756
+ } else {
757
+ vc4_state->offsets[0] += tiles_l << tile_size_shift;
758
+ vc4_state->offsets[0] += tile_y << 10;
759
+ }
760
+
539761 break;
540762 }
541763
....@@ -543,31 +765,22 @@
543765 case DRM_FORMAT_MOD_BROADCOM_SAND128:
544766 case DRM_FORMAT_MOD_BROADCOM_SAND256: {
545767 uint32_t param = fourcc_mod_broadcom_param(fb->modifier);
768
+ u32 tile_w, tile, x_off, pix_per_tile;
546769
547
- /* Column-based NV12 or RGBA.
548
- */
549
- if (fb->format->num_planes > 1) {
550
- if (hvs_format != HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE) {
551
- DRM_DEBUG_KMS("SAND format only valid for NV12/21");
552
- return -EINVAL;
553
- }
554
- hvs_format = HVS_PIXEL_FORMAT_H264;
555
- } else {
556
- if (base_format_mod == DRM_FORMAT_MOD_BROADCOM_SAND256) {
557
- DRM_DEBUG_KMS("SAND256 format only valid for H.264");
558
- return -EINVAL;
559
- }
560
- }
770
+ hvs_format = HVS_PIXEL_FORMAT_H264;
561771
562772 switch (base_format_mod) {
563773 case DRM_FORMAT_MOD_BROADCOM_SAND64:
564774 tiling = SCALER_CTL0_TILING_64B;
775
+ tile_w = 64;
565776 break;
566777 case DRM_FORMAT_MOD_BROADCOM_SAND128:
567778 tiling = SCALER_CTL0_TILING_128B;
779
+ tile_w = 128;
568780 break;
569781 case DRM_FORMAT_MOD_BROADCOM_SAND256:
570782 tiling = SCALER_CTL0_TILING_256B_OR_T;
783
+ tile_w = 256;
571784 break;
572785 default:
573786 break;
....@@ -576,6 +789,23 @@
576789 if (param > SCALER_TILE_HEIGHT_MASK) {
577790 DRM_DEBUG_KMS("SAND height too large (%d)\n", param);
578791 return -EINVAL;
792
+ }
793
+
794
+ pix_per_tile = tile_w / fb->format->cpp[0];
795
+ tile = vc4_state->src_x / pix_per_tile;
796
+ x_off = vc4_state->src_x % pix_per_tile;
797
+
798
+ /* Adjust the base pointer to the first pixel to be scanned
799
+ * out.
800
+ */
801
+ for (i = 0; i < num_planes; i++) {
802
+ vc4_state->offsets[i] += param * tile_w * tile;
803
+ vc4_state->offsets[i] += src_y /
804
+ (i ? v_subsample : 1) *
805
+ tile_w;
806
+ vc4_state->offsets[i] += x_off /
807
+ (i ? h_subsample : 1) *
808
+ fb->format->cpp[i];
579809 }
580810
581811 pitch0 = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT);
....@@ -588,33 +818,6 @@
588818 return -EINVAL;
589819 }
590820
591
- /* Control word */
592
- vc4_dlist_write(vc4_state,
593
- SCALER_CTL0_VALID |
594
- VC4_SET_FIELD(SCALER_CTL0_RGBA_EXPAND_ROUND, SCALER_CTL0_RGBA_EXPAND) |
595
- (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) |
596
- (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
597
- VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) |
598
- (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) |
599
- VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |
600
- VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1));
601
-
602
- /* Position Word 0: Image Positions and Alpha Value */
603
- vc4_state->pos0_offset = vc4_state->dlist_count;
604
- vc4_dlist_write(vc4_state,
605
- VC4_SET_FIELD(state->alpha >> 8, SCALER_POS0_FIXED_ALPHA) |
606
- VC4_SET_FIELD(vc4_state->crtc_x, SCALER_POS0_START_X) |
607
- VC4_SET_FIELD(vc4_state->crtc_y, SCALER_POS0_START_Y));
608
-
609
- /* Position Word 1: Scaled Image Dimensions. */
610
- if (!vc4_state->is_unity) {
611
- vc4_dlist_write(vc4_state,
612
- VC4_SET_FIELD(vc4_state->crtc_w,
613
- SCALER_POS1_SCL_WIDTH) |
614
- VC4_SET_FIELD(vc4_state->crtc_h,
615
- SCALER_POS1_SCL_HEIGHT));
616
- }
617
-
618821 /* Don't waste cycles mixing with plane alpha if the set alpha
619822 * is opaque or there is no per-pixel alpha information.
620823 * In any case we use the alpha property value as the fixed alpha.
....@@ -622,20 +825,120 @@
622825 mix_plane_alpha = state->alpha != DRM_BLEND_ALPHA_OPAQUE &&
623826 fb->format->has_alpha;
624827
625
- /* Position Word 2: Source Image Size, Alpha */
626
- vc4_state->pos2_offset = vc4_state->dlist_count;
627
- vc4_dlist_write(vc4_state,
628
- VC4_SET_FIELD(fb->format->has_alpha ?
629
- SCALER_POS2_ALPHA_MODE_PIPELINE :
630
- SCALER_POS2_ALPHA_MODE_FIXED,
631
- SCALER_POS2_ALPHA_MODE) |
632
- (mix_plane_alpha ? SCALER_POS2_ALPHA_MIX : 0) |
633
- (fb->format->has_alpha ? SCALER_POS2_ALPHA_PREMULT : 0) |
634
- VC4_SET_FIELD(vc4_state->src_w[0], SCALER_POS2_WIDTH) |
635
- VC4_SET_FIELD(vc4_state->src_h[0], SCALER_POS2_HEIGHT));
828
+ if (!vc4->hvs->hvs5) {
829
+ /* Control word */
830
+ vc4_dlist_write(vc4_state,
831
+ SCALER_CTL0_VALID |
832
+ (rotation & DRM_MODE_REFLECT_X ? SCALER_CTL0_HFLIP : 0) |
833
+ (rotation & DRM_MODE_REFLECT_Y ? SCALER_CTL0_VFLIP : 0) |
834
+ VC4_SET_FIELD(SCALER_CTL0_RGBA_EXPAND_ROUND, SCALER_CTL0_RGBA_EXPAND) |
835
+ (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) |
836
+ (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
837
+ VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) |
838
+ (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) |
839
+ VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |
840
+ VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1));
636841
637
- /* Position Word 3: Context. Written by the HVS. */
638
- vc4_dlist_write(vc4_state, 0xc0c0c0c0);
842
+ /* Position Word 0: Image Positions and Alpha Value */
843
+ vc4_state->pos0_offset = vc4_state->dlist_count;
844
+ vc4_dlist_write(vc4_state,
845
+ VC4_SET_FIELD(state->alpha >> 8, SCALER_POS0_FIXED_ALPHA) |
846
+ VC4_SET_FIELD(vc4_state->crtc_x, SCALER_POS0_START_X) |
847
+ VC4_SET_FIELD(vc4_state->crtc_y, SCALER_POS0_START_Y));
848
+
849
+ /* Position Word 1: Scaled Image Dimensions. */
850
+ if (!vc4_state->is_unity) {
851
+ vc4_dlist_write(vc4_state,
852
+ VC4_SET_FIELD(vc4_state->crtc_w,
853
+ SCALER_POS1_SCL_WIDTH) |
854
+ VC4_SET_FIELD(vc4_state->crtc_h,
855
+ SCALER_POS1_SCL_HEIGHT));
856
+ }
857
+
858
+ /* Position Word 2: Source Image Size, Alpha */
859
+ vc4_state->pos2_offset = vc4_state->dlist_count;
860
+ vc4_dlist_write(vc4_state,
861
+ VC4_SET_FIELD(fb->format->has_alpha ?
862
+ SCALER_POS2_ALPHA_MODE_PIPELINE :
863
+ SCALER_POS2_ALPHA_MODE_FIXED,
864
+ SCALER_POS2_ALPHA_MODE) |
865
+ (mix_plane_alpha ? SCALER_POS2_ALPHA_MIX : 0) |
866
+ (fb->format->has_alpha ?
867
+ SCALER_POS2_ALPHA_PREMULT : 0) |
868
+ VC4_SET_FIELD(vc4_state->src_w[0],
869
+ SCALER_POS2_WIDTH) |
870
+ VC4_SET_FIELD(vc4_state->src_h[0],
871
+ SCALER_POS2_HEIGHT));
872
+
873
+ /* Position Word 3: Context. Written by the HVS. */
874
+ vc4_dlist_write(vc4_state, 0xc0c0c0c0);
875
+
876
+ } else {
877
+ u32 hvs_pixel_order = format->pixel_order;
878
+
879
+ if (format->pixel_order_hvs5)
880
+ hvs_pixel_order = format->pixel_order_hvs5;
881
+
882
+ /* Control word */
883
+ vc4_dlist_write(vc4_state,
884
+ SCALER_CTL0_VALID |
885
+ (hvs_pixel_order << SCALER_CTL0_ORDER_SHIFT) |
886
+ (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
887
+ VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) |
888
+ (vc4_state->is_unity ?
889
+ SCALER5_CTL0_UNITY : 0) |
890
+ VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |
891
+ VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1) |
892
+ SCALER5_CTL0_ALPHA_EXPAND |
893
+ SCALER5_CTL0_RGB_EXPAND);
894
+
895
+ /* Position Word 0: Image Positions and Alpha Value */
896
+ vc4_state->pos0_offset = vc4_state->dlist_count;
897
+ vc4_dlist_write(vc4_state,
898
+ (rotation & DRM_MODE_REFLECT_Y ?
899
+ SCALER5_POS0_VFLIP : 0) |
900
+ VC4_SET_FIELD(vc4_state->crtc_x,
901
+ SCALER_POS0_START_X) |
902
+ (rotation & DRM_MODE_REFLECT_X ?
903
+ SCALER5_POS0_HFLIP : 0) |
904
+ VC4_SET_FIELD(vc4_state->crtc_y,
905
+ SCALER5_POS0_START_Y)
906
+ );
907
+
908
+ /* Control Word 2 */
909
+ vc4_dlist_write(vc4_state,
910
+ VC4_SET_FIELD(state->alpha >> 4,
911
+ SCALER5_CTL2_ALPHA) |
912
+ (fb->format->has_alpha ?
913
+ SCALER5_CTL2_ALPHA_PREMULT : 0) |
914
+ (mix_plane_alpha ?
915
+ SCALER5_CTL2_ALPHA_MIX : 0) |
916
+ VC4_SET_FIELD(fb->format->has_alpha ?
917
+ SCALER5_CTL2_ALPHA_MODE_PIPELINE :
918
+ SCALER5_CTL2_ALPHA_MODE_FIXED,
919
+ SCALER5_CTL2_ALPHA_MODE)
920
+ );
921
+
922
+ /* Position Word 1: Scaled Image Dimensions. */
923
+ if (!vc4_state->is_unity) {
924
+ vc4_dlist_write(vc4_state,
925
+ VC4_SET_FIELD(vc4_state->crtc_w,
926
+ SCALER5_POS1_SCL_WIDTH) |
927
+ VC4_SET_FIELD(vc4_state->crtc_h,
928
+ SCALER5_POS1_SCL_HEIGHT));
929
+ }
930
+
931
+ /* Position Word 2: Source Image Size */
932
+ vc4_state->pos2_offset = vc4_state->dlist_count;
933
+ vc4_dlist_write(vc4_state,
934
+ VC4_SET_FIELD(vc4_state->src_w[0],
935
+ SCALER5_POS2_WIDTH) |
936
+ VC4_SET_FIELD(vc4_state->src_h[0],
937
+ SCALER5_POS2_HEIGHT));
938
+
939
+ /* Position Word 3: Context. Written by the HVS. */
940
+ vc4_dlist_write(vc4_state, 0xc0c0c0c0);
941
+ }
639942
640943
641944 /* Pointer Word 0/1/2: RGB / Y / Cb / Cr Pointers
....@@ -671,14 +974,19 @@
671974 vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5);
672975 }
673976
977
+ vc4_state->lbm_offset = 0;
978
+
674979 if (vc4_state->x_scaling[0] != VC4_SCALING_NONE ||
675980 vc4_state->x_scaling[1] != VC4_SCALING_NONE ||
676981 vc4_state->y_scaling[0] != VC4_SCALING_NONE ||
677982 vc4_state->y_scaling[1] != VC4_SCALING_NONE) {
678
- /* LBM Base Address. */
983
+ /* Reserve a slot for the LBM Base Address. The real value will
984
+ * be set when calling vc4_plane_allocate_lbm().
985
+ */
679986 if (vc4_state->y_scaling[0] != VC4_SCALING_NONE ||
680987 vc4_state->y_scaling[1] != VC4_SCALING_NONE) {
681
- vc4_dlist_write(vc4_state, vc4_state->lbm.start);
988
+ vc4_state->lbm_offset = vc4_state->dlist_count;
989
+ vc4_dlist_counter_increment(vc4_state);
682990 }
683991
684992 if (num_planes > 1) {
....@@ -725,6 +1033,15 @@
7251033 vc4_state->needs_bg_fill = fb->format->has_alpha || !covers_screen ||
7261034 state->alpha != DRM_BLEND_ALPHA_OPAQUE;
7271035
1036
+ /* Flag the dlist as initialized to avoid checking it twice in case
1037
+ * the async update check already called vc4_plane_mode_set() and
1038
+ * decided to fallback to sync update because async update was not
1039
+ * possible.
1040
+ */
1041
+ vc4_state->dlist_initialized = 1;
1042
+
1043
+ vc4_plane_calc_load(state);
1044
+
7281045 return 0;
7291046 }
7301047
....@@ -739,13 +1056,18 @@
7391056 struct drm_plane_state *state)
7401057 {
7411058 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
1059
+ int ret;
7421060
7431061 vc4_state->dlist_count = 0;
7441062
745
- if (plane_enabled(state))
746
- return vc4_plane_mode_set(plane, state);
747
- else
1063
+ if (!plane_enabled(state))
7481064 return 0;
1065
+
1066
+ ret = vc4_plane_mode_set(plane, state);
1067
+ if (ret)
1068
+ return ret;
1069
+
1070
+ return vc4_plane_allocate_lbm(state);
7491071 }
7501072
7511073 static void vc4_plane_atomic_update(struct drm_plane *plane,
....@@ -811,29 +1133,59 @@
8111133 static void vc4_plane_atomic_async_update(struct drm_plane *plane,
8121134 struct drm_plane_state *state)
8131135 {
814
- struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);
815
-
816
- if (plane->state->fb != state->fb) {
817
- vc4_plane_async_set_fb(plane, state->fb);
818
- drm_atomic_set_fb_for_plane(plane->state, state->fb);
819
- }
1136
+ struct vc4_plane_state *vc4_state, *new_vc4_state;
8201137
8211138 swap(plane->state->fb, state->fb);
822
- /* Set the cursor's position on the screen. This is the
823
- * expected change from the drm_mode_cursor_universal()
824
- * helper.
825
- */
8261139 plane->state->crtc_x = state->crtc_x;
8271140 plane->state->crtc_y = state->crtc_y;
828
-
829
- /* Allow changing the start position within the cursor BO, if
830
- * that matters.
831
- */
1141
+ plane->state->crtc_w = state->crtc_w;
1142
+ plane->state->crtc_h = state->crtc_h;
8321143 plane->state->src_x = state->src_x;
8331144 plane->state->src_y = state->src_y;
1145
+ plane->state->src_w = state->src_w;
1146
+ plane->state->src_h = state->src_h;
1147
+ plane->state->src_h = state->src_h;
1148
+ plane->state->alpha = state->alpha;
1149
+ plane->state->pixel_blend_mode = state->pixel_blend_mode;
1150
+ plane->state->rotation = state->rotation;
1151
+ plane->state->zpos = state->zpos;
1152
+ plane->state->normalized_zpos = state->normalized_zpos;
1153
+ plane->state->color_encoding = state->color_encoding;
1154
+ plane->state->color_range = state->color_range;
1155
+ plane->state->src = state->src;
1156
+ plane->state->dst = state->dst;
1157
+ plane->state->visible = state->visible;
8341158
835
- /* Update the display list based on the new crtc_x/y. */
836
- vc4_plane_atomic_check(plane, plane->state);
1159
+ new_vc4_state = to_vc4_plane_state(state);
1160
+ vc4_state = to_vc4_plane_state(plane->state);
1161
+
1162
+ vc4_state->crtc_x = new_vc4_state->crtc_x;
1163
+ vc4_state->crtc_y = new_vc4_state->crtc_y;
1164
+ vc4_state->crtc_h = new_vc4_state->crtc_h;
1165
+ vc4_state->crtc_w = new_vc4_state->crtc_w;
1166
+ vc4_state->src_x = new_vc4_state->src_x;
1167
+ vc4_state->src_y = new_vc4_state->src_y;
1168
+ memcpy(vc4_state->src_w, new_vc4_state->src_w,
1169
+ sizeof(vc4_state->src_w));
1170
+ memcpy(vc4_state->src_h, new_vc4_state->src_h,
1171
+ sizeof(vc4_state->src_h));
1172
+ memcpy(vc4_state->x_scaling, new_vc4_state->x_scaling,
1173
+ sizeof(vc4_state->x_scaling));
1174
+ memcpy(vc4_state->y_scaling, new_vc4_state->y_scaling,
1175
+ sizeof(vc4_state->y_scaling));
1176
+ vc4_state->is_unity = new_vc4_state->is_unity;
1177
+ vc4_state->is_yuv = new_vc4_state->is_yuv;
1178
+ memcpy(vc4_state->offsets, new_vc4_state->offsets,
1179
+ sizeof(vc4_state->offsets));
1180
+ vc4_state->needs_bg_fill = new_vc4_state->needs_bg_fill;
1181
+
1182
+ /* Update the current vc4_state pos0, pos2 and ptr0 dlist entries. */
1183
+ vc4_state->dlist[vc4_state->pos0_offset] =
1184
+ new_vc4_state->dlist[vc4_state->pos0_offset];
1185
+ vc4_state->dlist[vc4_state->pos2_offset] =
1186
+ new_vc4_state->dlist[vc4_state->pos2_offset];
1187
+ vc4_state->dlist[vc4_state->ptr0_offset] =
1188
+ new_vc4_state->dlist[vc4_state->ptr0_offset];
8371189
8381190 /* Note that we can't just call vc4_plane_write_dlist()
8391191 * because that would smash the context data that the HVS is
....@@ -850,12 +1202,37 @@
8501202 static int vc4_plane_atomic_async_check(struct drm_plane *plane,
8511203 struct drm_plane_state *state)
8521204 {
853
- /* No configuring new scaling in the fast path. */
854
- if (plane->state->crtc_w != state->crtc_w ||
855
- plane->state->crtc_h != state->crtc_h ||
856
- plane->state->src_w != state->src_w ||
857
- plane->state->src_h != state->src_h)
1205
+ struct vc4_plane_state *old_vc4_state, *new_vc4_state;
1206
+ int ret;
1207
+ u32 i;
1208
+
1209
+ ret = vc4_plane_mode_set(plane, state);
1210
+ if (ret)
1211
+ return ret;
1212
+
1213
+ old_vc4_state = to_vc4_plane_state(plane->state);
1214
+ new_vc4_state = to_vc4_plane_state(state);
1215
+ if (old_vc4_state->dlist_count != new_vc4_state->dlist_count ||
1216
+ old_vc4_state->pos0_offset != new_vc4_state->pos0_offset ||
1217
+ old_vc4_state->pos2_offset != new_vc4_state->pos2_offset ||
1218
+ old_vc4_state->ptr0_offset != new_vc4_state->ptr0_offset ||
1219
+ vc4_lbm_size(plane->state) != vc4_lbm_size(state))
8581220 return -EINVAL;
1221
+
1222
+ /* Only pos0, pos2 and ptr0 DWORDS can be updated in an async update
1223
+ * if anything else has changed, fallback to a sync update.
1224
+ */
1225
+ for (i = 0; i < new_vc4_state->dlist_count; i++) {
1226
+ if (i == new_vc4_state->pos0_offset ||
1227
+ i == new_vc4_state->pos2_offset ||
1228
+ i == new_vc4_state->ptr0_offset ||
1229
+ (new_vc4_state->lbm_offset &&
1230
+ i == new_vc4_state->lbm_offset))
1231
+ continue;
1232
+
1233
+ if (new_vc4_state->dlist[i] != old_vc4_state->dlist[i])
1234
+ return -EINVAL;
1235
+ }
8591236
8601237 return 0;
8611238 }
....@@ -864,7 +1241,6 @@
8641241 struct drm_plane_state *state)
8651242 {
8661243 struct vc4_bo *bo;
867
- struct dma_fence *fence;
8681244 int ret;
8691245
8701246 if (!state->fb)
....@@ -872,8 +1248,7 @@
8721248
8731249 bo = to_vc4_bo(&drm_fb_cma_get_gem_obj(state->fb, 0)->base);
8741250
875
- fence = reservation_object_get_excl_rcu(bo->resv);
876
- drm_atomic_set_fence_for_plane(state, fence);
1251
+ drm_gem_fb_prepare_fb(plane, state);
8771252
8781253 if (plane->state->fb == state->fb)
8791254 return 0;
....@@ -908,7 +1283,6 @@
9081283
9091284 static void vc4_plane_destroy(struct drm_plane *plane)
9101285 {
911
- drm_plane_helper_disable(plane, NULL);
9121286 drm_plane_cleanup(plane);
9131287 }
9141288
....@@ -929,8 +1303,6 @@
9291303 switch (fourcc_mod_broadcom_mod(modifier)) {
9301304 case DRM_FORMAT_MOD_LINEAR:
9311305 case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
932
- case DRM_FORMAT_MOD_BROADCOM_SAND64:
933
- case DRM_FORMAT_MOD_BROADCOM_SAND128:
9341306 return true;
9351307 default:
9361308 return false;
....@@ -946,6 +1318,10 @@
9461318 default:
9471319 return false;
9481320 }
1321
+ case DRM_FORMAT_RGBX1010102:
1322
+ case DRM_FORMAT_BGRX1010102:
1323
+ case DRM_FORMAT_RGBA1010102:
1324
+ case DRM_FORMAT_BGRA1010102:
9491325 case DRM_FORMAT_YUV422:
9501326 case DRM_FORMAT_YVU422:
9511327 case DRM_FORMAT_YUV420:
....@@ -974,7 +1350,6 @@
9741350 struct drm_plane *plane = NULL;
9751351 struct vc4_plane *vc4_plane;
9761352 u32 formats[ARRAY_SIZE(hvs_formats)];
977
- u32 num_formats = 0;
9781353 int ret = 0;
9791354 unsigned i;
9801355 static const uint64_t modifiers[] = {
....@@ -991,25 +1366,66 @@
9911366 if (!vc4_plane)
9921367 return ERR_PTR(-ENOMEM);
9931368
994
- for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) {
995
- /* Don't allow YUV in cursor planes, since that means
996
- * tuning on the scaler, which we don't allow for the
997
- * cursor.
998
- */
999
- if (type != DRM_PLANE_TYPE_CURSOR ||
1000
- hvs_formats[i].hvs < HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE) {
1001
- formats[num_formats++] = hvs_formats[i].drm;
1002
- }
1003
- }
1369
+ for (i = 0; i < ARRAY_SIZE(hvs_formats); i++)
1370
+ formats[i] = hvs_formats[i].drm;
1371
+
10041372 plane = &vc4_plane->base;
10051373 ret = drm_universal_plane_init(dev, plane, 0,
10061374 &vc4_plane_funcs,
1007
- formats, num_formats,
1375
+ formats, ARRAY_SIZE(formats),
10081376 modifiers, type, NULL);
1377
+ if (ret)
1378
+ return ERR_PTR(ret);
10091379
10101380 drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
10111381
10121382 drm_plane_create_alpha_property(plane);
1383
+ drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
1384
+ DRM_MODE_ROTATE_0 |
1385
+ DRM_MODE_ROTATE_180 |
1386
+ DRM_MODE_REFLECT_X |
1387
+ DRM_MODE_REFLECT_Y);
10131388
10141389 return plane;
10151390 }
1391
+
1392
+int vc4_plane_create_additional_planes(struct drm_device *drm)
1393
+{
1394
+ struct drm_plane *cursor_plane;
1395
+ struct drm_crtc *crtc;
1396
+ unsigned int i;
1397
+
1398
+ /* Set up some arbitrary number of planes. We're not limited
1399
+ * by a set number of physical registers, just the space in
1400
+ * the HVS (16k) and how small an plane can be (28 bytes).
1401
+ * However, each plane we set up takes up some memory, and
1402
+ * increases the cost of looping over planes, which atomic
1403
+ * modesetting does quite a bit. As a result, we pick a
1404
+ * modest number of planes to expose, that should hopefully
1405
+ * still cover any sane usecase.
1406
+ */
1407
+ for (i = 0; i < 16; i++) {
1408
+ struct drm_plane *plane =
1409
+ vc4_plane_init(drm, DRM_PLANE_TYPE_OVERLAY);
1410
+
1411
+ if (IS_ERR(plane))
1412
+ continue;
1413
+
1414
+ plane->possible_crtcs =
1415
+ GENMASK(drm->mode_config.num_crtc - 1, 0);
1416
+ }
1417
+
1418
+ drm_for_each_crtc(crtc, drm) {
1419
+ /* Set up the legacy cursor after overlay initialization,
1420
+ * since we overlay planes on the CRTC in the order they were
1421
+ * initialized.
1422
+ */
1423
+ cursor_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_CURSOR);
1424
+ if (!IS_ERR(cursor_plane)) {
1425
+ cursor_plane->possible_crtcs = drm_crtc_mask(crtc);
1426
+ crtc->cursor = cursor_plane;
1427
+ }
1428
+ }
1429
+
1430
+ return 0;
1431
+}