@@ -141,6 +141,19 @@ const struct ssd130x_deviceinfo ssd130x_variants[] = {
141141};
142142EXPORT_SYMBOL_NS_GPL (ssd130x_variants , DRM_SSD130X );
143143
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+
144157static inline struct ssd130x_device * drm_to_ssd130x (struct drm_device * drm )
145158{
146159 return container_of (drm , struct ssd130x_device , drm );
@@ -434,12 +447,14 @@ static int ssd130x_init(struct ssd130x_device *ssd130x)
434447 SSD130X_SET_ADDRESS_MODE_HORIZONTAL );
435448}
436449
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 )
438453{
439454 unsigned int x = rect -> x1 ;
440455 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 ;
443458 unsigned int width = drm_rect_width (rect );
444459 unsigned int height = drm_rect_height (rect );
445460 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 *
535550 return ret ;
536551}
537552
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 )
539555{
540556 struct drm_rect fullscreen = {
541557 .x1 = 0 ,
@@ -544,21 +560,21 @@ static void ssd130x_clear_screen(struct ssd130x_device *ssd130x)
544560 .y2 = ssd130x -> height ,
545561 };
546562
547- ssd130x_update_rect (ssd130x , & fullscreen );
563+ ssd130x_update_rect (ssd130x , ssd130x_state , & fullscreen );
548564}
549565
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 ,
551568 struct drm_rect * rect )
552569{
570+ struct drm_framebuffer * fb = state -> fb ;
553571 struct ssd130x_device * ssd130x = drm_to_ssd130x (fb -> dev );
554572 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 ;
555575 struct iosys_map dst ;
556576 unsigned int dst_pitch ;
557577 int ret = 0 ;
558- u8 * buf = ssd130x -> buffer ;
559-
560- if (!buf )
561- return 0 ;
562578
563579 /* Align y to display page boundaries */
564580 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
575591
576592 drm_gem_fb_end_cpu_access (fb , DMA_FROM_DEVICE );
577593
578- ssd130x_update_rect (ssd130x , rect );
594+ ssd130x_update_rect (ssd130x , ssd130x_state , rect );
579595
580596 return ret ;
581597}
582598
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+
583637static void ssd130x_primary_plane_helper_atomic_update (struct drm_plane * plane ,
584638 struct drm_atomic_state * state )
585639{
@@ -602,7 +656,7 @@ static void ssd130x_primary_plane_helper_atomic_update(struct drm_plane *plane,
602656 if (!drm_rect_intersect (& dst_clip , & damage ))
603657 continue ;
604658
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 );
606660 }
607661
608662 drm_dev_exit (idx );
@@ -613,26 +667,79 @@ static void ssd130x_primary_plane_helper_atomic_disable(struct drm_plane *plane,
613667{
614668 struct drm_device * drm = plane -> dev ;
615669 struct ssd130x_device * ssd130x = drm_to_ssd130x (drm );
670+ struct ssd130x_plane_state * ssd130x_state = to_ssd130x_plane_state (plane -> state );
616671 int idx ;
617672
618673 if (!drm_dev_enter (drm , & idx ))
619674 return ;
620675
621- ssd130x_clear_screen (ssd130x );
676+ ssd130x_clear_screen (ssd130x , ssd130x_state );
622677
623678 drm_dev_exit (idx );
624679}
625680
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+
626730static const struct drm_plane_helper_funcs ssd130x_primary_plane_helper_funcs = {
627731 DRM_GEM_SHADOW_PLANE_HELPER_FUNCS ,
628- .atomic_check = drm_plane_helper_atomic_check ,
732+ .atomic_check = ssd130x_primary_plane_helper_atomic_check ,
629733 .atomic_update = ssd130x_primary_plane_helper_atomic_update ,
630734 .atomic_disable = ssd130x_primary_plane_helper_atomic_disable ,
631735};
632736
633737static const struct drm_plane_funcs ssd130x_primary_plane_funcs = {
634738 .update_plane = drm_atomic_helper_update_plane ,
635739 .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 ,
636743 .destroy = drm_plane_cleanup ,
637744 DRM_GEM_SHADOW_PLANE_FUNCS ,
638745};
@@ -677,10 +784,6 @@ static void ssd130x_encoder_helper_atomic_enable(struct drm_encoder *encoder,
677784{
678785 struct drm_device * drm = encoder -> dev ;
679786 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 ;
684787 int ret ;
685788
686789 ret = ssd130x_power_on (ssd130x );
@@ -691,22 +794,6 @@ static void ssd130x_encoder_helper_atomic_enable(struct drm_encoder *encoder,
691794 if (ret )
692795 goto power_off ;
693796
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-
710797 ssd130x_write_cmd (ssd130x , 1 , SSD130X_DISPLAY_ON );
711798
712799 backlight_enable (ssd130x -> bl_dev );
@@ -728,9 +815,6 @@ static void ssd130x_encoder_helper_atomic_disable(struct drm_encoder *encoder,
728815
729816 ssd130x_write_cmd (ssd130x , 1 , SSD130X_DISPLAY_OFF );
730817
731- kfree (ssd130x -> data_array );
732- kfree (ssd130x -> buffer );
733-
734818 ssd130x_power_off (ssd130x );
735819}
736820
0 commit comments