Skip to content

Commit 9060d7f

Browse files
committed
drm/fb-helper: Finish the generic fbdev emulation
This adds a drm_fbdev_generic_setup() function that sets up generic fbdev emulation with client callbacks for restore, hotplug and unregister. Signed-off-by: Noralf Trønnes <[email protected]> Reviewed-by: Daniel Vetter <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent e896c13 commit 9060d7f

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed

drivers/gpu/drm/drm_fb_helper.c

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ static DEFINE_MUTEX(kernel_fb_helper_lock);
6767
* helper functions used by many drivers to implement the kernel mode setting
6868
* interfaces.
6969
*
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+
*
7073
* Setup fbdev emulation by calling drm_fb_helper_fbdev_setup() and tear it
7174
* down by calling drm_fb_helper_fbdev_teardown().
7275
*
@@ -3118,6 +3121,120 @@ int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
31183121
}
31193122
EXPORT_SYMBOL(drm_fb_helper_generic_probe);
31203123

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+
31213238
/* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT)
31223239
* but the module doesn't depend on any fb console symbols. At least
31233240
* attempt to load fbcon to avoid leaving the system without a usable console.

include/drm/drm_fb_helper.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ void drm_fb_helper_output_poll_changed(struct drm_device *dev);
354354

355355
int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
356356
struct drm_fb_helper_surface_size *sizes);
357+
int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp);
357358
#else
358359
static inline void drm_fb_helper_prepare(struct drm_device *dev,
359360
struct drm_fb_helper *helper,
@@ -595,6 +596,12 @@ drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
595596
return 0;
596597
}
597598

599+
static inline int
600+
drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
601+
{
602+
return 0;
603+
}
604+
598605
#endif
599606

600607
static inline int

0 commit comments

Comments
 (0)