30
30
#define pr_fmt (fmt ) KBUILD_MODNAME ": " fmt
31
31
32
32
#include <linux/console.h>
33
+ #include <linux/dma-buf.h>
33
34
#include <linux/kernel.h>
34
35
#include <linux/sysrq.h>
35
36
#include <linux/slab.h>
@@ -738,6 +739,24 @@ static void drm_fb_helper_resume_worker(struct work_struct *work)
738
739
console_unlock ();
739
740
}
740
741
742
+ static void drm_fb_helper_dirty_blit_real (struct drm_fb_helper * fb_helper ,
743
+ struct drm_clip_rect * clip )
744
+ {
745
+ struct drm_framebuffer * fb = fb_helper -> fb ;
746
+ unsigned int cpp = drm_format_plane_cpp (fb -> format -> format , 0 );
747
+ size_t offset = clip -> y1 * fb -> pitches [0 ] + clip -> x1 * cpp ;
748
+ void * src = fb_helper -> fbdev -> screen_buffer + offset ;
749
+ void * dst = fb_helper -> buffer -> vaddr + offset ;
750
+ size_t len = (clip -> x2 - clip -> x1 ) * cpp ;
751
+ unsigned int y ;
752
+
753
+ for (y = clip -> y1 ; y < clip -> y2 ; y ++ ) {
754
+ memcpy (dst , src , len );
755
+ src += fb -> pitches [0 ];
756
+ dst += fb -> pitches [0 ];
757
+ }
758
+ }
759
+
741
760
static void drm_fb_helper_dirty_work (struct work_struct * work )
742
761
{
743
762
struct drm_fb_helper * helper = container_of (work , struct drm_fb_helper ,
@@ -753,8 +772,12 @@ static void drm_fb_helper_dirty_work(struct work_struct *work)
753
772
spin_unlock_irqrestore (& helper -> dirty_lock , flags );
754
773
755
774
/* call dirty callback only when it has been really touched */
756
- if (clip_copy .x1 < clip_copy .x2 && clip_copy .y1 < clip_copy .y2 )
775
+ if (clip_copy .x1 < clip_copy .x2 && clip_copy .y1 < clip_copy .y2 ) {
776
+ /* Generic fbdev uses a shadow buffer */
777
+ if (helper -> buffer )
778
+ drm_fb_helper_dirty_blit_real (helper , & clip_copy );
757
779
helper -> fb -> funcs -> dirty (helper -> fb , NULL , 0 , 0 , & clip_copy , 1 );
780
+ }
758
781
}
759
782
760
783
/**
@@ -2921,6 +2944,180 @@ void drm_fb_helper_output_poll_changed(struct drm_device *dev)
2921
2944
}
2922
2945
EXPORT_SYMBOL (drm_fb_helper_output_poll_changed );
2923
2946
2947
+ /* @user: 1=userspace, 0=fbcon */
2948
+ static int drm_fbdev_fb_open (struct fb_info * info , int user )
2949
+ {
2950
+ struct drm_fb_helper * fb_helper = info -> par ;
2951
+
2952
+ if (!try_module_get (fb_helper -> dev -> driver -> fops -> owner ))
2953
+ return - ENODEV ;
2954
+
2955
+ return 0 ;
2956
+ }
2957
+
2958
+ static int drm_fbdev_fb_release (struct fb_info * info , int user )
2959
+ {
2960
+ struct drm_fb_helper * fb_helper = info -> par ;
2961
+
2962
+ module_put (fb_helper -> dev -> driver -> fops -> owner );
2963
+
2964
+ return 0 ;
2965
+ }
2966
+
2967
+ /*
2968
+ * fb_ops.fb_destroy is called by the last put_fb_info() call at the end of
2969
+ * unregister_framebuffer() or fb_release().
2970
+ */
2971
+ static void drm_fbdev_fb_destroy (struct fb_info * info )
2972
+ {
2973
+ struct drm_fb_helper * fb_helper = info -> par ;
2974
+ struct fb_info * fbi = fb_helper -> fbdev ;
2975
+ struct fb_ops * fbops = NULL ;
2976
+ void * shadow = NULL ;
2977
+
2978
+ if (fbi -> fbdefio ) {
2979
+ fb_deferred_io_cleanup (fbi );
2980
+ shadow = fbi -> screen_buffer ;
2981
+ fbops = fbi -> fbops ;
2982
+ }
2983
+
2984
+ drm_fb_helper_fini (fb_helper );
2985
+
2986
+ if (shadow ) {
2987
+ vfree (shadow );
2988
+ kfree (fbops );
2989
+ }
2990
+
2991
+ drm_client_framebuffer_delete (fb_helper -> buffer );
2992
+ /*
2993
+ * FIXME:
2994
+ * Remove conditional when all CMA drivers have been moved over to using
2995
+ * drm_fbdev_generic_setup().
2996
+ */
2997
+ if (fb_helper -> client .funcs ) {
2998
+ drm_client_release (& fb_helper -> client );
2999
+ kfree (fb_helper );
3000
+ }
3001
+ }
3002
+
3003
+ static int drm_fbdev_fb_mmap (struct fb_info * info , struct vm_area_struct * vma )
3004
+ {
3005
+ struct drm_fb_helper * fb_helper = info -> par ;
3006
+
3007
+ if (fb_helper -> dev -> driver -> gem_prime_mmap )
3008
+ return fb_helper -> dev -> driver -> gem_prime_mmap (fb_helper -> buffer -> gem , vma );
3009
+ else
3010
+ return - ENODEV ;
3011
+ }
3012
+
3013
+ static struct fb_ops drm_fbdev_fb_ops = {
3014
+ .owner = THIS_MODULE ,
3015
+ DRM_FB_HELPER_DEFAULT_OPS ,
3016
+ .fb_open = drm_fbdev_fb_open ,
3017
+ .fb_release = drm_fbdev_fb_release ,
3018
+ .fb_destroy = drm_fbdev_fb_destroy ,
3019
+ .fb_mmap = drm_fbdev_fb_mmap ,
3020
+ .fb_read = drm_fb_helper_sys_read ,
3021
+ .fb_write = drm_fb_helper_sys_write ,
3022
+ .fb_fillrect = drm_fb_helper_sys_fillrect ,
3023
+ .fb_copyarea = drm_fb_helper_sys_copyarea ,
3024
+ .fb_imageblit = drm_fb_helper_sys_imageblit ,
3025
+ };
3026
+
3027
+ static struct fb_deferred_io drm_fbdev_defio = {
3028
+ .delay = HZ / 20 ,
3029
+ .deferred_io = drm_fb_helper_deferred_io ,
3030
+ };
3031
+
3032
+ /**
3033
+ * drm_fb_helper_generic_probe - Generic fbdev emulation probe helper
3034
+ * @fb_helper: fbdev helper structure
3035
+ * @sizes: describes fbdev size and scanout surface size
3036
+ *
3037
+ * This function uses the client API to crate a framebuffer backed by a dumb buffer.
3038
+ *
3039
+ * The _sys_ versions are used for &fb_ops.fb_read, fb_write, fb_fillrect,
3040
+ * fb_copyarea, fb_imageblit.
3041
+ *
3042
+ * Returns:
3043
+ * Zero on success or negative error code on failure.
3044
+ */
3045
+ int drm_fb_helper_generic_probe (struct drm_fb_helper * fb_helper ,
3046
+ struct drm_fb_helper_surface_size * sizes )
3047
+ {
3048
+ struct drm_client_dev * client = & fb_helper -> client ;
3049
+ struct drm_client_buffer * buffer ;
3050
+ struct drm_framebuffer * fb ;
3051
+ struct fb_info * fbi ;
3052
+ u32 format ;
3053
+ int ret ;
3054
+
3055
+ DRM_DEBUG_KMS ("surface width(%d), height(%d) and bpp(%d)\n" ,
3056
+ sizes -> surface_width , sizes -> surface_height ,
3057
+ sizes -> surface_bpp );
3058
+
3059
+ format = drm_mode_legacy_fb_format (sizes -> surface_bpp , sizes -> surface_depth );
3060
+ buffer = drm_client_framebuffer_create (client , sizes -> surface_width ,
3061
+ sizes -> surface_height , format );
3062
+ if (IS_ERR (buffer ))
3063
+ return PTR_ERR (buffer );
3064
+
3065
+ fb_helper -> buffer = buffer ;
3066
+ fb_helper -> fb = buffer -> fb ;
3067
+ fb = buffer -> fb ;
3068
+
3069
+ fbi = drm_fb_helper_alloc_fbi (fb_helper );
3070
+ if (IS_ERR (fbi )) {
3071
+ ret = PTR_ERR (fbi );
3072
+ goto err_free_buffer ;
3073
+ }
3074
+
3075
+ fbi -> par = fb_helper ;
3076
+ fbi -> fbops = & drm_fbdev_fb_ops ;
3077
+ fbi -> screen_size = fb -> height * fb -> pitches [0 ];
3078
+ fbi -> fix .smem_len = fbi -> screen_size ;
3079
+ fbi -> screen_buffer = buffer -> vaddr ;
3080
+ strcpy (fbi -> fix .id , "DRM emulated" );
3081
+
3082
+ drm_fb_helper_fill_fix (fbi , fb -> pitches [0 ], fb -> format -> depth );
3083
+ drm_fb_helper_fill_var (fbi , fb_helper , sizes -> fb_width , sizes -> fb_height );
3084
+
3085
+ if (fb -> funcs -> dirty ) {
3086
+ struct fb_ops * fbops ;
3087
+ void * shadow ;
3088
+
3089
+ /*
3090
+ * fb_deferred_io_cleanup() clears &fbops->fb_mmap so a per
3091
+ * instance version is necessary.
3092
+ */
3093
+ fbops = kzalloc (sizeof (* fbops ), GFP_KERNEL );
3094
+ shadow = vzalloc (fbi -> screen_size );
3095
+ if (!fbops || !shadow ) {
3096
+ kfree (fbops );
3097
+ vfree (shadow );
3098
+ ret = - ENOMEM ;
3099
+ goto err_fb_info_destroy ;
3100
+ }
3101
+
3102
+ * fbops = * fbi -> fbops ;
3103
+ fbi -> fbops = fbops ;
3104
+ fbi -> screen_buffer = shadow ;
3105
+ fbi -> fbdefio = & drm_fbdev_defio ;
3106
+
3107
+ fb_deferred_io_init (fbi );
3108
+ }
3109
+
3110
+ return 0 ;
3111
+
3112
+ err_fb_info_destroy :
3113
+ drm_fb_helper_fini (fb_helper );
3114
+ err_free_buffer :
3115
+ drm_client_framebuffer_delete (buffer );
3116
+
3117
+ return ret ;
3118
+ }
3119
+ EXPORT_SYMBOL (drm_fb_helper_generic_probe );
3120
+
2924
3121
/* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT)
2925
3122
* but the module doesn't depend on any fb console symbols. At least
2926
3123
* attempt to load fbcon to avoid leaving the system without a usable console.
0 commit comments