@@ -67,6 +67,9 @@ static DEFINE_MUTEX(kernel_fb_helper_lock);
67
67
* helper functions used by many drivers to implement the kernel mode setting
68
68
* interfaces.
69
69
*
70
+ * Drivers that support a dumb buffer with a virtual address and mmap support,
71
+ * should try out the generic fbdev emulation using drm_fbdev_generic_setup().
72
+ *
70
73
* Setup fbdev emulation by calling drm_fb_helper_fbdev_setup() and tear it
71
74
* down by calling drm_fb_helper_fbdev_teardown().
72
75
*
@@ -3118,6 +3121,120 @@ int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
3118
3121
}
3119
3122
EXPORT_SYMBOL (drm_fb_helper_generic_probe );
3120
3123
3124
+ static const struct drm_fb_helper_funcs drm_fb_helper_generic_funcs = {
3125
+ .fb_probe = drm_fb_helper_generic_probe ,
3126
+ };
3127
+
3128
+ static void drm_fbdev_client_unregister (struct drm_client_dev * client )
3129
+ {
3130
+ struct drm_fb_helper * fb_helper = drm_fb_helper_from_client (client );
3131
+
3132
+ if (fb_helper -> fbdev ) {
3133
+ drm_fb_helper_unregister_fbi (fb_helper );
3134
+ /* drm_fbdev_fb_destroy() takes care of cleanup */
3135
+ return ;
3136
+ }
3137
+
3138
+ /* Did drm_fb_helper_fbdev_setup() run? */
3139
+ if (fb_helper -> dev )
3140
+ drm_fb_helper_fini (fb_helper );
3141
+
3142
+ drm_client_release (client );
3143
+ kfree (fb_helper );
3144
+ }
3145
+
3146
+ static int drm_fbdev_client_restore (struct drm_client_dev * client )
3147
+ {
3148
+ struct drm_fb_helper * fb_helper = drm_fb_helper_from_client (client );
3149
+
3150
+ drm_fb_helper_restore_fbdev_mode_unlocked (fb_helper );
3151
+
3152
+ return 0 ;
3153
+ }
3154
+
3155
+ static int drm_fbdev_client_hotplug (struct drm_client_dev * client )
3156
+ {
3157
+ struct drm_fb_helper * fb_helper = drm_fb_helper_from_client (client );
3158
+ struct drm_device * dev = client -> dev ;
3159
+ int ret ;
3160
+
3161
+ /* If drm_fb_helper_fbdev_setup() failed, we only try once */
3162
+ if (!fb_helper -> dev && fb_helper -> funcs )
3163
+ return 0 ;
3164
+
3165
+ if (dev -> fb_helper )
3166
+ return drm_fb_helper_hotplug_event (dev -> fb_helper );
3167
+
3168
+ if (!dev -> mode_config .num_connector )
3169
+ return 0 ;
3170
+
3171
+ ret = drm_fb_helper_fbdev_setup (dev , fb_helper , & drm_fb_helper_generic_funcs ,
3172
+ fb_helper -> preferred_bpp , 0 );
3173
+ if (ret ) {
3174
+ fb_helper -> dev = NULL ;
3175
+ fb_helper -> fbdev = NULL ;
3176
+ return ret ;
3177
+ }
3178
+
3179
+ return 0 ;
3180
+ }
3181
+
3182
+ static const struct drm_client_funcs drm_fbdev_client_funcs = {
3183
+ .owner = THIS_MODULE ,
3184
+ .unregister = drm_fbdev_client_unregister ,
3185
+ .restore = drm_fbdev_client_restore ,
3186
+ .hotplug = drm_fbdev_client_hotplug ,
3187
+ };
3188
+
3189
+ /**
3190
+ * drm_fb_helper_generic_fbdev_setup() - Setup generic fbdev emulation
3191
+ * @dev: DRM device
3192
+ * @preferred_bpp: Preferred bits per pixel for the device.
3193
+ * @dev->mode_config.preferred_depth is used if this is zero.
3194
+ *
3195
+ * This function sets up generic fbdev emulation for drivers that supports
3196
+ * dumb buffers with a virtual address and that can be mmap'ed.
3197
+ *
3198
+ * Restore, hotplug events and teardown are all taken care of. Drivers that do
3199
+ * suspend/resume need to call drm_fb_helper_set_suspend_unlocked() themselves.
3200
+ * Simple drivers might use drm_mode_config_helper_suspend().
3201
+ *
3202
+ * Drivers that set the dirty callback on their framebuffer will get a shadow
3203
+ * fbdev buffer that is blitted onto the real buffer. This is done in order to
3204
+ * make deferred I/O work with all kinds of buffers.
3205
+ *
3206
+ * This function is safe to call even when there are no connectors present.
3207
+ * Setup will be retried on the next hotplug event.
3208
+ *
3209
+ * Returns:
3210
+ * Zero on success or negative error code on failure.
3211
+ */
3212
+ int drm_fbdev_generic_setup (struct drm_device * dev , unsigned int preferred_bpp )
3213
+ {
3214
+ struct drm_fb_helper * fb_helper ;
3215
+ int ret ;
3216
+
3217
+ if (!drm_fbdev_emulation )
3218
+ return 0 ;
3219
+
3220
+ fb_helper = kzalloc (sizeof (* fb_helper ), GFP_KERNEL );
3221
+ if (!fb_helper )
3222
+ return - ENOMEM ;
3223
+
3224
+ ret = drm_client_new (dev , & fb_helper -> client , "fbdev" , & drm_fbdev_client_funcs );
3225
+ if (ret ) {
3226
+ kfree (fb_helper );
3227
+ return ret ;
3228
+ }
3229
+
3230
+ fb_helper -> preferred_bpp = preferred_bpp ;
3231
+
3232
+ drm_fbdev_client_hotplug (& fb_helper -> client );
3233
+
3234
+ return 0 ;
3235
+ }
3236
+ EXPORT_SYMBOL (drm_fbdev_generic_setup );
3237
+
3121
3238
/* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT)
3122
3239
* but the module doesn't depend on any fb console symbols. At least
3123
3240
* attempt to load fbcon to avoid leaving the system without a usable console.
0 commit comments