@@ -49,22 +49,27 @@ struct vc4_crtc {
49
49
/* Which HVS channel we're using for our CRTC. */
50
50
int channel ;
51
51
52
- /* Pointer to the actual hardware display list memory for the
53
- * crtc.
54
- */
55
- u32 __iomem * dlist ;
56
-
57
- u32 dlist_size ; /* in dwords */
58
-
59
52
struct drm_pending_vblank_event * event ;
60
53
};
61
54
55
+ struct vc4_crtc_state {
56
+ struct drm_crtc_state base ;
57
+ /* Dlist area for this CRTC configuration. */
58
+ struct drm_mm_node mm ;
59
+ };
60
+
62
61
static inline struct vc4_crtc *
63
62
to_vc4_crtc (struct drm_crtc * crtc )
64
63
{
65
64
return (struct vc4_crtc * )crtc ;
66
65
}
67
66
67
+ static inline struct vc4_crtc_state *
68
+ to_vc4_crtc_state (struct drm_crtc_state * crtc_state )
69
+ {
70
+ return (struct vc4_crtc_state * )crtc_state ;
71
+ }
72
+
68
73
struct vc4_crtc_data {
69
74
/* Which channel of the HVS this pixelvalve sources from. */
70
75
int hvs_channel ;
@@ -319,11 +324,13 @@ static void vc4_crtc_enable(struct drm_crtc *crtc)
319
324
static int vc4_crtc_atomic_check (struct drm_crtc * crtc ,
320
325
struct drm_crtc_state * state )
321
326
{
327
+ struct vc4_crtc_state * vc4_state = to_vc4_crtc_state (state );
322
328
struct drm_device * dev = crtc -> dev ;
323
329
struct vc4_dev * vc4 = to_vc4_dev (dev );
324
330
struct drm_plane * plane ;
325
- struct vc4_crtc * vc4_crtc = to_vc4_crtc ( crtc ) ;
331
+ unsigned long flags ;
326
332
u32 dlist_count = 0 ;
333
+ int ret ;
327
334
328
335
/* The pixelvalve can only feed one encoder (and encoders are
329
336
* 1:1 with connectors.)
@@ -346,18 +353,12 @@ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
346
353
347
354
dlist_count ++ ; /* Account for SCALER_CTL0_END. */
348
355
349
- if (!vc4_crtc -> dlist || dlist_count > vc4_crtc -> dlist_size ) {
350
- vc4_crtc -> dlist = ((u32 __iomem * )vc4 -> hvs -> dlist +
351
- HVS_BOOTLOADER_DLIST_END );
352
- vc4_crtc -> dlist_size = ((SCALER_DLIST_SIZE >> 2 ) -
353
- HVS_BOOTLOADER_DLIST_END );
354
-
355
- if (dlist_count > vc4_crtc -> dlist_size ) {
356
- DRM_DEBUG_KMS ("dlist too large for CRTC (%d > %d).\n" ,
357
- dlist_count , vc4_crtc -> dlist_size );
358
- return - EINVAL ;
359
- }
360
- }
356
+ spin_lock_irqsave (& vc4 -> hvs -> mm_lock , flags );
357
+ ret = drm_mm_insert_node (& vc4 -> hvs -> dlist_mm , & vc4_state -> mm ,
358
+ dlist_count , 1 , 0 );
359
+ spin_unlock_irqrestore (& vc4 -> hvs -> mm_lock , flags );
360
+ if (ret )
361
+ return ret ;
361
362
362
363
return 0 ;
363
364
}
@@ -368,47 +369,29 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
368
369
struct drm_device * dev = crtc -> dev ;
369
370
struct vc4_dev * vc4 = to_vc4_dev (dev );
370
371
struct vc4_crtc * vc4_crtc = to_vc4_crtc (crtc );
372
+ struct vc4_crtc_state * vc4_state = to_vc4_crtc_state (crtc -> state );
371
373
struct drm_plane * plane ;
372
374
bool debug_dump_regs = false;
373
- u32 __iomem * dlist_next = vc4_crtc -> dlist ;
375
+ u32 __iomem * dlist_start = vc4 -> hvs -> dlist + vc4_state -> mm .start ;
376
+ u32 __iomem * dlist_next = dlist_start ;
374
377
375
378
if (debug_dump_regs ) {
376
379
DRM_INFO ("CRTC %d HVS before:\n" , drm_crtc_index (crtc ));
377
380
vc4_hvs_dump_state (dev );
378
381
}
379
382
380
- /* Copy all the active planes' dlist contents to the hardware dlist.
381
- *
382
- * XXX: If the new display list was large enough that it
383
- * overlapped a currently-read display list, we need to do
384
- * something like disable scanout before putting in the new
385
- * list. For now, we're safe because we only have the two
386
- * planes.
387
- */
383
+ /* Copy all the active planes' dlist contents to the hardware dlist. */
388
384
drm_atomic_crtc_for_each_plane (plane , crtc ) {
389
385
dlist_next += vc4_plane_write_dlist (plane , dlist_next );
390
386
}
391
387
392
- if (dlist_next == vc4_crtc -> dlist ) {
393
- /* If no planes were enabled, use the SCALER_CTL0_END
394
- * at the start of the display list memory (in the
395
- * bootloader section). We'll rewrite that
396
- * SCALER_CTL0_END, just in case, though.
397
- */
398
- writel (SCALER_CTL0_END , vc4 -> hvs -> dlist );
399
- HVS_WRITE (SCALER_DISPLISTX (vc4_crtc -> channel ), 0 );
400
- } else {
401
- writel (SCALER_CTL0_END , dlist_next );
402
- dlist_next ++ ;
403
-
404
- HVS_WRITE (SCALER_DISPLISTX (vc4_crtc -> channel ),
405
- (u32 __iomem * )vc4_crtc -> dlist -
406
- (u32 __iomem * )vc4 -> hvs -> dlist );
407
-
408
- /* Make the next display list start after ours. */
409
- vc4_crtc -> dlist_size -= (dlist_next - vc4_crtc -> dlist );
410
- vc4_crtc -> dlist = dlist_next ;
411
- }
388
+ writel (SCALER_CTL0_END , dlist_next );
389
+ dlist_next ++ ;
390
+
391
+ WARN_ON_ONCE (dlist_next - dlist_start != vc4_state -> mm .size );
392
+
393
+ HVS_WRITE (SCALER_DISPLISTX (vc4_crtc -> channel ),
394
+ vc4_state -> mm .start );
412
395
413
396
if (debug_dump_regs ) {
414
397
DRM_INFO ("CRTC %d HVS after:\n" , drm_crtc_index (crtc ));
@@ -573,6 +556,36 @@ static int vc4_page_flip(struct drm_crtc *crtc,
573
556
return drm_atomic_helper_page_flip (crtc , fb , event , flags );
574
557
}
575
558
559
+ static struct drm_crtc_state * vc4_crtc_duplicate_state (struct drm_crtc * crtc )
560
+ {
561
+ struct vc4_crtc_state * vc4_state ;
562
+
563
+ vc4_state = kzalloc (sizeof (* vc4_state ), GFP_KERNEL );
564
+ if (!vc4_state )
565
+ return NULL ;
566
+
567
+ __drm_atomic_helper_crtc_duplicate_state (crtc , & vc4_state -> base );
568
+ return & vc4_state -> base ;
569
+ }
570
+
571
+ static void vc4_crtc_destroy_state (struct drm_crtc * crtc ,
572
+ struct drm_crtc_state * state )
573
+ {
574
+ struct vc4_dev * vc4 = to_vc4_dev (crtc -> dev );
575
+ struct vc4_crtc_state * vc4_state = to_vc4_crtc_state (state );
576
+
577
+ if (vc4_state -> mm .allocated ) {
578
+ unsigned long flags ;
579
+
580
+ spin_lock_irqsave (& vc4 -> hvs -> mm_lock , flags );
581
+ drm_mm_remove_node (& vc4_state -> mm );
582
+ spin_unlock_irqrestore (& vc4 -> hvs -> mm_lock , flags );
583
+
584
+ }
585
+
586
+ __drm_atomic_helper_crtc_destroy_state (crtc , state );
587
+ }
588
+
576
589
static const struct drm_crtc_funcs vc4_crtc_funcs = {
577
590
.set_config = drm_atomic_helper_set_config ,
578
591
.destroy = vc4_crtc_destroy ,
@@ -581,8 +594,8 @@ static const struct drm_crtc_funcs vc4_crtc_funcs = {
581
594
.cursor_set = NULL , /* handled by drm_mode_cursor_universal */
582
595
.cursor_move = NULL , /* handled by drm_mode_cursor_universal */
583
596
.reset = drm_atomic_helper_crtc_reset ,
584
- .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state ,
585
- .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state ,
597
+ .atomic_duplicate_state = vc4_crtc_duplicate_state ,
598
+ .atomic_destroy_state = vc4_crtc_destroy_state ,
586
599
};
587
600
588
601
static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
@@ -644,9 +657,9 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data)
644
657
struct vc4_dev * vc4 = to_vc4_dev (drm );
645
658
struct vc4_crtc * vc4_crtc ;
646
659
struct drm_crtc * crtc ;
647
- struct drm_plane * primary_plane , * cursor_plane ;
660
+ struct drm_plane * primary_plane , * cursor_plane , * destroy_plane , * temp ;
648
661
const struct of_device_id * match ;
649
- int ret ;
662
+ int ret , i ;
650
663
651
664
vc4_crtc = devm_kzalloc (dev , sizeof (* vc4_crtc ), GFP_KERNEL );
652
665
if (!vc4_crtc )
@@ -675,38 +688,62 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data)
675
688
goto err ;
676
689
}
677
690
678
- cursor_plane = vc4_plane_init (drm , DRM_PLANE_TYPE_CURSOR );
679
- if (IS_ERR (cursor_plane )) {
680
- dev_err (dev , "failed to construct cursor plane\n" );
681
- ret = PTR_ERR (cursor_plane );
682
- goto err_primary ;
683
- }
684
-
685
- drm_crtc_init_with_planes (drm , crtc , primary_plane , cursor_plane ,
691
+ drm_crtc_init_with_planes (drm , crtc , primary_plane , NULL ,
686
692
& vc4_crtc_funcs , NULL );
687
693
drm_crtc_helper_add (crtc , & vc4_crtc_helper_funcs );
688
694
primary_plane -> crtc = crtc ;
689
- cursor_plane -> crtc = crtc ;
690
695
vc4 -> crtc [drm_crtc_index (crtc )] = vc4_crtc ;
691
696
vc4_crtc -> channel = vc4_crtc -> data -> hvs_channel ;
692
697
698
+ /* Set up some arbitrary number of planes. We're not limited
699
+ * by a set number of physical registers, just the space in
700
+ * the HVS (16k) and how small an plane can be (28 bytes).
701
+ * However, each plane we set up takes up some memory, and
702
+ * increases the cost of looping over planes, which atomic
703
+ * modesetting does quite a bit. As a result, we pick a
704
+ * modest number of planes to expose, that should hopefully
705
+ * still cover any sane usecase.
706
+ */
707
+ for (i = 0 ; i < 8 ; i ++ ) {
708
+ struct drm_plane * plane =
709
+ vc4_plane_init (drm , DRM_PLANE_TYPE_OVERLAY );
710
+
711
+ if (IS_ERR (plane ))
712
+ continue ;
713
+
714
+ plane -> possible_crtcs = 1 << drm_crtc_index (crtc );
715
+ }
716
+
717
+ /* Set up the legacy cursor after overlay initialization,
718
+ * since we overlay planes on the CRTC in the order they were
719
+ * initialized.
720
+ */
721
+ cursor_plane = vc4_plane_init (drm , DRM_PLANE_TYPE_CURSOR );
722
+ if (!IS_ERR (cursor_plane )) {
723
+ cursor_plane -> possible_crtcs = 1 << drm_crtc_index (crtc );
724
+ cursor_plane -> crtc = crtc ;
725
+ crtc -> cursor = cursor_plane ;
726
+ }
727
+
693
728
CRTC_WRITE (PV_INTEN , 0 );
694
729
CRTC_WRITE (PV_INTSTAT , PV_INT_VFP_START );
695
730
ret = devm_request_irq (dev , platform_get_irq (pdev , 0 ),
696
731
vc4_crtc_irq_handler , 0 , "vc4 crtc" , vc4_crtc );
697
732
if (ret )
698
- goto err_cursor ;
733
+ goto err_destroy_planes ;
699
734
700
735
vc4_set_crtc_possible_masks (drm , crtc );
701
736
702
737
platform_set_drvdata (pdev , vc4_crtc );
703
738
704
739
return 0 ;
705
740
706
- err_cursor :
707
- cursor_plane -> funcs -> destroy (cursor_plane );
708
- err_primary :
709
- primary_plane -> funcs -> destroy (primary_plane );
741
+ err_destroy_planes :
742
+ list_for_each_entry_safe (destroy_plane , temp ,
743
+ & drm -> mode_config .plane_list , head ) {
744
+ if (destroy_plane -> possible_crtcs == 1 << drm_crtc_index (crtc ))
745
+ destroy_plane -> funcs -> destroy (destroy_plane );
746
+ }
710
747
err :
711
748
return ret ;
712
749
}
0 commit comments