@@ -141,6 +141,19 @@ const struct ssd130x_deviceinfo ssd130x_variants[] = {
141
141
};
142
142
EXPORT_SYMBOL_NS_GPL (ssd130x_variants , DRM_SSD130X );
143
143
144
+ struct ssd130x_plane_state {
145
+ struct drm_plane_state base ;
146
+ /* Intermediate buffer to convert pixels from XRGB8888 to HW format */
147
+ u8 * buffer ;
148
+ /* Buffer to store pixels in HW format and written to the panel */
149
+ u8 * data_array ;
150
+ };
151
+
152
+ static inline struct ssd130x_plane_state * to_ssd130x_plane_state (struct drm_plane_state * state )
153
+ {
154
+ return container_of (state , struct ssd130x_plane_state , base );
155
+ }
156
+
144
157
static inline struct ssd130x_device * drm_to_ssd130x (struct drm_device * drm )
145
158
{
146
159
return container_of (drm , struct ssd130x_device , drm );
@@ -434,12 +447,14 @@ static int ssd130x_init(struct ssd130x_device *ssd130x)
434
447
SSD130X_SET_ADDRESS_MODE_HORIZONTAL );
435
448
}
436
449
437
- static int ssd130x_update_rect (struct ssd130x_device * ssd130x , struct drm_rect * rect )
450
+ static int ssd130x_update_rect (struct ssd130x_device * ssd130x ,
451
+ struct ssd130x_plane_state * ssd130x_state ,
452
+ struct drm_rect * rect )
438
453
{
439
454
unsigned int x = rect -> x1 ;
440
455
unsigned int y = rect -> y1 ;
441
- u8 * buf = ssd130x -> buffer ;
442
- u8 * data_array = ssd130x -> data_array ;
456
+ u8 * buf = ssd130x_state -> buffer ;
457
+ u8 * data_array = ssd130x_state -> data_array ;
443
458
unsigned int width = drm_rect_width (rect );
444
459
unsigned int height = drm_rect_height (rect );
445
460
unsigned int line_length = DIV_ROUND_UP (width , 8 );
@@ -535,7 +550,8 @@ static int ssd130x_update_rect(struct ssd130x_device *ssd130x, struct drm_rect *
535
550
return ret ;
536
551
}
537
552
538
- static void ssd130x_clear_screen (struct ssd130x_device * ssd130x )
553
+ static void ssd130x_clear_screen (struct ssd130x_device * ssd130x ,
554
+ struct ssd130x_plane_state * ssd130x_state )
539
555
{
540
556
struct drm_rect fullscreen = {
541
557
.x1 = 0 ,
@@ -544,21 +560,21 @@ static void ssd130x_clear_screen(struct ssd130x_device *ssd130x)
544
560
.y2 = ssd130x -> height ,
545
561
};
546
562
547
- ssd130x_update_rect (ssd130x , & fullscreen );
563
+ ssd130x_update_rect (ssd130x , ssd130x_state , & fullscreen );
548
564
}
549
565
550
- static int ssd130x_fb_blit_rect (struct drm_framebuffer * fb , const struct iosys_map * vmap ,
566
+ static int ssd130x_fb_blit_rect (struct drm_plane_state * state ,
567
+ const struct iosys_map * vmap ,
551
568
struct drm_rect * rect )
552
569
{
570
+ struct drm_framebuffer * fb = state -> fb ;
553
571
struct ssd130x_device * ssd130x = drm_to_ssd130x (fb -> dev );
554
572
unsigned int page_height = ssd130x -> device_info -> page_height ;
573
+ struct ssd130x_plane_state * ssd130x_state = to_ssd130x_plane_state (state );
574
+ u8 * buf = ssd130x_state -> buffer ;
555
575
struct iosys_map dst ;
556
576
unsigned int dst_pitch ;
557
577
int ret = 0 ;
558
- u8 * buf = ssd130x -> buffer ;
559
-
560
- if (!buf )
561
- return 0 ;
562
578
563
579
/* Align y to display page boundaries */
564
580
rect -> y1 = round_down (rect -> y1 , page_height );
@@ -575,11 +591,49 @@ static int ssd130x_fb_blit_rect(struct drm_framebuffer *fb, const struct iosys_m
575
591
576
592
drm_gem_fb_end_cpu_access (fb , DMA_FROM_DEVICE );
577
593
578
- ssd130x_update_rect (ssd130x , rect );
594
+ ssd130x_update_rect (ssd130x , ssd130x_state , rect );
579
595
580
596
return ret ;
581
597
}
582
598
599
+ static int ssd130x_primary_plane_helper_atomic_check (struct drm_plane * plane ,
600
+ struct drm_atomic_state * state )
601
+ {
602
+ struct drm_device * drm = plane -> dev ;
603
+ struct ssd130x_device * ssd130x = drm_to_ssd130x (drm );
604
+ struct drm_plane_state * plane_state = drm_atomic_get_new_plane_state (state , plane );
605
+ struct ssd130x_plane_state * ssd130x_state = to_ssd130x_plane_state (plane_state );
606
+ unsigned int page_height = ssd130x -> device_info -> page_height ;
607
+ unsigned int pages = DIV_ROUND_UP (ssd130x -> height , page_height );
608
+ const struct drm_format_info * fi ;
609
+ unsigned int pitch ;
610
+ int ret ;
611
+
612
+ ret = drm_plane_helper_atomic_check (plane , state );
613
+ if (ret )
614
+ return ret ;
615
+
616
+ fi = drm_format_info (DRM_FORMAT_R1 );
617
+ if (!fi )
618
+ return - EINVAL ;
619
+
620
+ pitch = drm_format_info_min_pitch (fi , 0 , ssd130x -> width );
621
+
622
+ ssd130x_state -> buffer = kcalloc (pitch , ssd130x -> height , GFP_KERNEL );
623
+ if (!ssd130x_state -> buffer )
624
+ return - ENOMEM ;
625
+
626
+ ssd130x_state -> data_array = kcalloc (ssd130x -> width , pages , GFP_KERNEL );
627
+ if (!ssd130x_state -> data_array ) {
628
+ kfree (ssd130x_state -> buffer );
629
+ /* Set to prevent a double free in .atomic_destroy_state() */
630
+ ssd130x_state -> buffer = NULL ;
631
+ return - ENOMEM ;
632
+ }
633
+
634
+ return 0 ;
635
+ }
636
+
583
637
static void ssd130x_primary_plane_helper_atomic_update (struct drm_plane * plane ,
584
638
struct drm_atomic_state * state )
585
639
{
@@ -602,7 +656,7 @@ static void ssd130x_primary_plane_helper_atomic_update(struct drm_plane *plane,
602
656
if (!drm_rect_intersect (& dst_clip , & damage ))
603
657
continue ;
604
658
605
- ssd130x_fb_blit_rect (plane_state -> fb , & shadow_plane_state -> data [0 ], & dst_clip );
659
+ ssd130x_fb_blit_rect (plane_state , & shadow_plane_state -> data [0 ], & dst_clip );
606
660
}
607
661
608
662
drm_dev_exit (idx );
@@ -613,26 +667,79 @@ static void ssd130x_primary_plane_helper_atomic_disable(struct drm_plane *plane,
613
667
{
614
668
struct drm_device * drm = plane -> dev ;
615
669
struct ssd130x_device * ssd130x = drm_to_ssd130x (drm );
670
+ struct ssd130x_plane_state * ssd130x_state = to_ssd130x_plane_state (plane -> state );
616
671
int idx ;
617
672
618
673
if (!drm_dev_enter (drm , & idx ))
619
674
return ;
620
675
621
- ssd130x_clear_screen (ssd130x );
676
+ ssd130x_clear_screen (ssd130x , ssd130x_state );
622
677
623
678
drm_dev_exit (idx );
624
679
}
625
680
681
+ /* Called during init to allocate the plane's atomic state. */
682
+ static void ssd130x_primary_plane_reset (struct drm_plane * plane )
683
+ {
684
+ struct ssd130x_plane_state * ssd130x_state ;
685
+
686
+ WARN_ON (plane -> state );
687
+
688
+ ssd130x_state = kzalloc (sizeof (* ssd130x_state ), GFP_KERNEL );
689
+ if (!ssd130x_state )
690
+ return ;
691
+
692
+ __drm_atomic_helper_plane_reset (plane , & ssd130x_state -> base );
693
+ }
694
+
695
+ static struct drm_plane_state * ssd130x_primary_plane_duplicate_state (struct drm_plane * plane )
696
+ {
697
+ struct ssd130x_plane_state * old_ssd130x_state ;
698
+ struct ssd130x_plane_state * ssd130x_state ;
699
+
700
+ if (WARN_ON (!plane -> state ))
701
+ return NULL ;
702
+
703
+ old_ssd130x_state = to_ssd130x_plane_state (plane -> state );
704
+ ssd130x_state = kmemdup (old_ssd130x_state , sizeof (* ssd130x_state ), GFP_KERNEL );
705
+ if (!ssd130x_state )
706
+ return NULL ;
707
+
708
+ /* The buffers are not duplicated and are allocated in .atomic_check */
709
+ ssd130x_state -> buffer = NULL ;
710
+ ssd130x_state -> data_array = NULL ;
711
+
712
+ __drm_atomic_helper_plane_duplicate_state (plane , & ssd130x_state -> base );
713
+
714
+ return & ssd130x_state -> base ;
715
+ }
716
+
717
+ static void ssd130x_primary_plane_destroy_state (struct drm_plane * plane ,
718
+ struct drm_plane_state * state )
719
+ {
720
+ struct ssd130x_plane_state * ssd130x_state = to_ssd130x_plane_state (state );
721
+
722
+ kfree (ssd130x_state -> data_array );
723
+ kfree (ssd130x_state -> buffer );
724
+
725
+ __drm_atomic_helper_plane_destroy_state (& ssd130x_state -> base );
726
+
727
+ kfree (ssd130x_state );
728
+ }
729
+
626
730
static const struct drm_plane_helper_funcs ssd130x_primary_plane_helper_funcs = {
627
731
DRM_GEM_SHADOW_PLANE_HELPER_FUNCS ,
628
- .atomic_check = drm_plane_helper_atomic_check ,
732
+ .atomic_check = ssd130x_primary_plane_helper_atomic_check ,
629
733
.atomic_update = ssd130x_primary_plane_helper_atomic_update ,
630
734
.atomic_disable = ssd130x_primary_plane_helper_atomic_disable ,
631
735
};
632
736
633
737
static const struct drm_plane_funcs ssd130x_primary_plane_funcs = {
634
738
.update_plane = drm_atomic_helper_update_plane ,
635
739
.disable_plane = drm_atomic_helper_disable_plane ,
740
+ .reset = ssd130x_primary_plane_reset ,
741
+ .atomic_duplicate_state = ssd130x_primary_plane_duplicate_state ,
742
+ .atomic_destroy_state = ssd130x_primary_plane_destroy_state ,
636
743
.destroy = drm_plane_cleanup ,
637
744
DRM_GEM_SHADOW_PLANE_FUNCS ,
638
745
};
@@ -677,10 +784,6 @@ static void ssd130x_encoder_helper_atomic_enable(struct drm_encoder *encoder,
677
784
{
678
785
struct drm_device * drm = encoder -> dev ;
679
786
struct ssd130x_device * ssd130x = drm_to_ssd130x (drm );
680
- unsigned int page_height = ssd130x -> device_info -> page_height ;
681
- unsigned int pages = DIV_ROUND_UP (ssd130x -> height , page_height );
682
- const struct drm_format_info * fi ;
683
- unsigned int pitch ;
684
787
int ret ;
685
788
686
789
ret = ssd130x_power_on (ssd130x );
@@ -691,22 +794,6 @@ static void ssd130x_encoder_helper_atomic_enable(struct drm_encoder *encoder,
691
794
if (ret )
692
795
goto power_off ;
693
796
694
- fi = drm_format_info (DRM_FORMAT_R1 );
695
- if (!fi )
696
- goto power_off ;
697
-
698
- pitch = drm_format_info_min_pitch (fi , 0 , ssd130x -> width );
699
-
700
- ssd130x -> buffer = kcalloc (pitch , ssd130x -> height , GFP_KERNEL );
701
- if (!ssd130x -> buffer )
702
- goto power_off ;
703
-
704
- ssd130x -> data_array = kcalloc (ssd130x -> width , pages , GFP_KERNEL );
705
- if (!ssd130x -> data_array ) {
706
- kfree (ssd130x -> buffer );
707
- goto power_off ;
708
- }
709
-
710
797
ssd130x_write_cmd (ssd130x , 1 , SSD130X_DISPLAY_ON );
711
798
712
799
backlight_enable (ssd130x -> bl_dev );
@@ -728,9 +815,6 @@ static void ssd130x_encoder_helper_atomic_disable(struct drm_encoder *encoder,
728
815
729
816
ssd130x_write_cmd (ssd130x , 1 , SSD130X_DISPLAY_OFF );
730
817
731
- kfree (ssd130x -> data_array );
732
- kfree (ssd130x -> buffer );
733
-
734
818
ssd130x_power_off (ssd130x );
735
819
}
736
820
0 commit comments