Message ID | 1460135110-24121-3-git-send-email-noralf@tronnes.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Fri, Apr 08, 2016 at 07:05:04PM +0200, Noralf Trønnes wrote: > This adds fbdev deferred io support if CONFIG_FB_DEFERRED_IO is enabled. > The driver has to provide a (struct drm_framebuffer_funcs *)->dirty() > callback to get notification of fbdev framebuffer changes. > If the dirty() hook is set, then fb_deferred_io is set up automatically > by the helper. > > Two functions have been added so that the driver can provide a dirty() > function: > - drm_fbdev_cma_init_with_funcs() > This makes it possible for the driver to provided a custom > (struct drm_fb_helper_funcs *)->fb_probe() function. > - drm_fbdev_cma_create_with_funcs() > This is used by the .fb_probe hook to set a driver provided > (struct drm_framebuffer_funcs *)->dirty() function. > > Example driver code: > > static int driver_fbdev_fb_dirty(struct drm_framebuffer *fb, > struct drm_file *file_priv, > unsigned flags, unsigned color, > struct drm_clip_rect *clips, > unsigned num_clips) > { > struct drm_gem_cma_object *cma = drm_fb_cma_get_gem_obj(fb, 0); > > return 0; > } > > static struct drm_framebuffer_funcs driver_fbdev_fb_funcs = { > .destroy = drm_fb_cma_destroy, > .create_handle = drm_fb_cma_create_handle, > .dirty = driver_fbdev_fb_dirty, > }; > > static int driver_fbdev_create(struct drm_fb_helper *helper, > struct drm_fb_helper_surface_size *sizes) > { > return drm_fbdev_cma_create_with_funcs(helper, sizes, > &driver_fbdev_fb_funcs); > } > > static const struct drm_fb_helper_funcs driver_fb_helper_funcs = { > .fb_probe = driver_fbdev_create, > }; > > Driver probe: > fbdev = drm_fbdev_cma_init_with_funcs(dev, 16, > dev->mode_config.num_crtc, > dev->mode_config.num_connector, > &driver_fb_helper_funcs); > The above should be part of the cma kerneldoc help text I think. If you use drm-intel-nightly you can even properly quote source snippets and stuff: http://blog.ffwll.ch/2016/01/better-markup-for-kernel-gpu-docbook.html > Signed-off-by: Noralf Trønnes <noralf@tronnes.org> For this patch we also need an ack from Laurent Pinchart. Please cc him on the next round. -Daniel > --- > drivers/gpu/drm/drm_fb_cma_helper.c | 149 +++++++++++++++++++++++++++++++++--- > include/drm/drm_fb_cma_helper.h | 14 ++++ > 2 files changed, 151 insertions(+), 12 deletions(-) > > diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c > index c895b6f..b347ddd 100644 > --- a/drivers/gpu/drm/drm_fb_cma_helper.c > +++ b/drivers/gpu/drm/drm_fb_cma_helper.c > @@ -25,6 +25,8 @@ > #include <drm/drm_fb_cma_helper.h> > #include <linux/module.h> > > +#define DEFAULT_FBDEFIO_DELAY_MS 50 > + > struct drm_fb_cma { > struct drm_framebuffer fb; > struct drm_gem_cma_object *obj[4]; > @@ -45,7 +47,7 @@ static inline struct drm_fb_cma *to_fb_cma(struct drm_framebuffer *fb) > return container_of(fb, struct drm_fb_cma, fb); > } > > -static void drm_fb_cma_destroy(struct drm_framebuffer *fb) > +void drm_fb_cma_destroy(struct drm_framebuffer *fb) > { > struct drm_fb_cma *fb_cma = to_fb_cma(fb); > int i; > @@ -58,8 +60,9 @@ static void drm_fb_cma_destroy(struct drm_framebuffer *fb) > drm_framebuffer_cleanup(fb); > kfree(fb_cma); > } > +EXPORT_SYMBOL(drm_fb_cma_destroy); > > -static int drm_fb_cma_create_handle(struct drm_framebuffer *fb, > +int drm_fb_cma_create_handle(struct drm_framebuffer *fb, > struct drm_file *file_priv, unsigned int *handle) > { > struct drm_fb_cma *fb_cma = to_fb_cma(fb); > @@ -67,6 +70,7 @@ static int drm_fb_cma_create_handle(struct drm_framebuffer *fb, > return drm_gem_handle_create(file_priv, > &fb_cma->obj[0]->base, handle); > } > +EXPORT_SYMBOL(drm_fb_cma_create_handle); > > static struct drm_framebuffer_funcs drm_fb_cma_funcs = { > .destroy = drm_fb_cma_destroy, > @@ -75,7 +79,7 @@ static struct drm_framebuffer_funcs drm_fb_cma_funcs = { > > static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev, > const const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_cma_object **obj, > - unsigned int num_planes) > + unsigned int num_planes, struct drm_framebuffer_funcs *funcs) > { > struct drm_fb_cma *fb_cma; > int ret; > @@ -90,7 +94,7 @@ static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev, > for (i = 0; i < num_planes; i++) > fb_cma->obj[i] = obj[i]; > > - ret = drm_framebuffer_init(dev, &fb_cma->fb, &drm_fb_cma_funcs); > + ret = drm_framebuffer_init(dev, &fb_cma->fb, funcs); > if (ret) { > dev_err(dev->dev, "Failed to initialize framebuffer: %d\n", ret); > kfree(fb_cma); > @@ -144,7 +148,7 @@ struct drm_framebuffer *drm_fb_cma_create(struct drm_device *dev, > objs[i] = to_drm_gem_cma_obj(obj); > } > > - fb_cma = drm_fb_cma_alloc(dev, mode_cmd, objs, i); > + fb_cma = drm_fb_cma_alloc(dev, mode_cmd, objs, i, &drm_fb_cma_funcs); > if (IS_ERR(fb_cma)) { > ret = PTR_ERR(fb_cma); > goto err_gem_object_unreference; > @@ -232,8 +236,93 @@ static struct fb_ops drm_fbdev_cma_ops = { > .fb_setcmap = drm_fb_helper_setcmap, > }; > > -static int drm_fbdev_cma_create(struct drm_fb_helper *helper, > - struct drm_fb_helper_surface_size *sizes) > +#ifdef CONFIG_FB_DEFERRED_IO > +/* > + * HACK > + * fb_deferred_io_mmap() is not exported so I use this hack until it's clear > + * that this patch will be used. > + */ > +static int (*fb_deferred_io_mmap)(struct fb_info *info, > + struct vm_area_struct *vma); > +/* > + * I sent a question about my need to set vm_page_prot to the fbdev ML, but > + * I haven't heard back. So exporting fb_deferred_io_mmap() is probably > + * the best solution. > + */ > +static int drm_fbdev_cma_deferred_io_mmap(struct fb_info *info, > + struct vm_area_struct *vma) > +{ > + fb_deferred_io_mmap(info, vma); > + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); > + > + return 0; > +} > + > +static int drm_fbdev_cma_defio_init(struct fb_info *fbi, > + struct drm_gem_cma_object *cma_obj) > +{ > + struct fb_deferred_io *fbdefio; > + struct fb_ops *fbops; > + > + /* > + * Per device structures are needed because: > + * fbops: fb_deferred_io_cleanup() clears fbops.fb_mmap > + * fbdefio: individual delays > + */ > + fbdefio = kzalloc(sizeof(*fbdefio), GFP_KERNEL); > + fbops = kzalloc(sizeof(*fbops), GFP_KERNEL); > + if (!fbdefio || !fbops) { > + kfree(fbdefio); > + return -ENOMEM; > + } > + > + /* can't be offset from vaddr since dirty() uses cma_obj */ > + fbi->screen_buffer = cma_obj->vaddr; > + /* fb_deferred_io_fault() needs a physical address */ > + fbi->fix.smem_start = page_to_phys(virt_to_page(fbi->screen_buffer)); > + > + *fbops = *fbi->fbops; > + fbi->fbops = fbops; > + > + fbdefio->delay = msecs_to_jiffies(DEFAULT_FBDEFIO_DELAY_MS); > + fbdefio->deferred_io = drm_fb_helper_deferred_io; > + fbi->fbdefio = fbdefio; > + fb_deferred_io_init(fbi); > + > + if (!fb_deferred_io_mmap) > + fb_deferred_io_mmap = fbi->fbops->fb_mmap; > + fbi->fbops->fb_mmap = drm_fbdev_cma_deferred_io_mmap; > + > + return 0; > +} > + > +static void drm_fbdev_cma_defio_fini(struct fb_info *fbi) > +{ > + if (!fbi->fbdefio) > + return; > + > + fb_deferred_io_cleanup(fbi); > + kfree(fbi->fbdefio); > + kfree(fbi->fbops); > +} > +#else > +static inline int drm_fbdev_cma_defio_init(struct fb_info *fbi) > +{ > + return 0; > +} > + > +static inline void drm_fbdev_cma_defio_fini(struct fb_info *fbi) > +{ > +} > +#endif /* CONFIG_FB_DEFERRED_IO */ > + > +/* > + * For use in a (struct drm_fb_helper_funcs *)->fb_probe callback function that > + * needs custom struct drm_framebuffer_funcs, like dirty() for deferred_io use. > + */ > +int drm_fbdev_cma_create_with_funcs(struct drm_fb_helper *helper, > + struct drm_fb_helper_surface_size *sizes, > + struct drm_framebuffer_funcs *funcs) > { > struct drm_fbdev_cma *fbdev_cma = to_fbdev_cma(helper); > struct drm_mode_fb_cmd2 mode_cmd = { 0 }; > @@ -269,7 +358,7 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper, > goto err_gem_free_object; > } > > - fbdev_cma->fb = drm_fb_cma_alloc(dev, &mode_cmd, &obj, 1); > + fbdev_cma->fb = drm_fb_cma_alloc(dev, &mode_cmd, &obj, 1, funcs); > if (IS_ERR(fbdev_cma->fb)) { > dev_err(dev->dev, "Failed to allocate DRM framebuffer.\n"); > ret = PTR_ERR(fbdev_cma->fb); > @@ -295,31 +384,48 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper, > fbi->screen_size = size; > fbi->fix.smem_len = size; > > + if (funcs->dirty) { > + ret = drm_fbdev_cma_defio_init(fbi, obj); > + if (ret) > + goto err_cma_destroy; > + } > + > return 0; > > +err_cma_destroy: > + drm_framebuffer_unregister_private(&fbdev_cma->fb->fb); > + drm_fb_cma_destroy(&fbdev_cma->fb->fb); > err_fb_info_destroy: > drm_fb_helper_release_fbi(helper); > err_gem_free_object: > dev->driver->gem_free_object(&obj->base); > return ret; > } > +EXPORT_SYMBOL(drm_fbdev_cma_create_with_funcs); > + > +static int drm_fbdev_cma_create(struct drm_fb_helper *helper, > + struct drm_fb_helper_surface_size *sizes) > +{ > + return drm_fbdev_cma_create_with_funcs(helper, sizes, &drm_fb_cma_funcs); > +} > > static const struct drm_fb_helper_funcs drm_fb_cma_helper_funcs = { > .fb_probe = drm_fbdev_cma_create, > }; > > /** > - * drm_fbdev_cma_init() - Allocate and initializes a drm_fbdev_cma struct > + * drm_fbdev_cma_init_with_funcs() - Allocate and initializes a drm_fbdev_cma struct > * @dev: DRM device > * @preferred_bpp: Preferred bits per pixel for the device > * @num_crtc: Number of CRTCs > * @max_conn_count: Maximum number of connectors > + * @funcs: fb helper functions, in particular fb_probe() > * > * Returns a newly allocated drm_fbdev_cma struct or a ERR_PTR. > */ > -struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev, > +struct drm_fbdev_cma *drm_fbdev_cma_init_with_funcs(struct drm_device *dev, > unsigned int preferred_bpp, unsigned int num_crtc, > - unsigned int max_conn_count) > + unsigned int max_conn_count, const struct drm_fb_helper_funcs *funcs) > { > struct drm_fbdev_cma *fbdev_cma; > struct drm_fb_helper *helper; > @@ -333,7 +439,7 @@ struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev, > > helper = &fbdev_cma->fb_helper; > > - drm_fb_helper_prepare(dev, helper, &drm_fb_cma_helper_funcs); > + drm_fb_helper_prepare(dev, helper, funcs); > > ret = drm_fb_helper_init(dev, helper, num_crtc, max_conn_count); > if (ret < 0) { > @@ -363,6 +469,24 @@ err_free: > > return ERR_PTR(ret); > } > +EXPORT_SYMBOL_GPL(drm_fbdev_cma_init_with_funcs); > + > +/** > + * drm_fbdev_cma_init() - Allocate and initializes a drm_fbdev_cma struct > + * @dev: DRM device > + * @preferred_bpp: Preferred bits per pixel for the device > + * @num_crtc: Number of CRTCs > + * @max_conn_count: Maximum number of connectors > + * > + * Returns a newly allocated drm_fbdev_cma struct or a ERR_PTR. > + */ > +struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev, > + unsigned int preferred_bpp, unsigned int num_crtc, > + unsigned int max_conn_count) > +{ > + return drm_fbdev_cma_init_with_funcs(dev, preferred_bpp, num_crtc, > + max_conn_count, &drm_fb_cma_helper_funcs); > +} > EXPORT_SYMBOL_GPL(drm_fbdev_cma_init); > > /** > @@ -372,6 +496,7 @@ EXPORT_SYMBOL_GPL(drm_fbdev_cma_init); > void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma) > { > drm_fb_helper_unregister_fbi(&fbdev_cma->fb_helper); > + drm_fbdev_cma_defio_fini(fbdev_cma->fb_helper.fbdev); > drm_fb_helper_release_fbi(&fbdev_cma->fb_helper); > > if (fbdev_cma->fb) { > diff --git a/include/drm/drm_fb_cma_helper.h b/include/drm/drm_fb_cma_helper.h > index be62bd3..6554b6f 100644 > --- a/include/drm/drm_fb_cma_helper.h > +++ b/include/drm/drm_fb_cma_helper.h > @@ -4,11 +4,18 @@ > struct drm_fbdev_cma; > struct drm_gem_cma_object; > > +struct drm_fb_helper_surface_size; > +struct drm_framebuffer_funcs; > +struct drm_fb_helper_funcs; > struct drm_framebuffer; > +struct drm_fb_helper; > struct drm_device; > struct drm_file; > struct drm_mode_fb_cmd2; > > +struct drm_fbdev_cma *drm_fbdev_cma_init_with_funcs(struct drm_device *dev, > + unsigned int preferred_bpp, unsigned int num_crtc, > + unsigned int max_conn_count, const struct drm_fb_helper_funcs *funcs); > struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev, > unsigned int preferred_bpp, unsigned int num_crtc, > unsigned int max_conn_count); > @@ -16,6 +23,13 @@ void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma); > > void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma *fbdev_cma); > void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma *fbdev_cma); > +int drm_fbdev_cma_create_with_funcs(struct drm_fb_helper *helper, > + struct drm_fb_helper_surface_size *sizes, > + struct drm_framebuffer_funcs *funcs); > + > +void drm_fb_cma_destroy(struct drm_framebuffer *fb); > +int drm_fb_cma_create_handle(struct drm_framebuffer *fb, > + struct drm_file *file_priv, unsigned int *handle); > > struct drm_framebuffer *drm_fb_cma_create(struct drm_device *dev, > struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd); > -- > 2.2.2 > > _______________________________________________ > dri-devel mailing list > dri-devel@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/dri-devel
diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index c895b6f..b347ddd 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -25,6 +25,8 @@ #include <drm/drm_fb_cma_helper.h> #include <linux/module.h> +#define DEFAULT_FBDEFIO_DELAY_MS 50 + struct drm_fb_cma { struct drm_framebuffer fb; struct drm_gem_cma_object *obj[4]; @@ -45,7 +47,7 @@ static inline struct drm_fb_cma *to_fb_cma(struct drm_framebuffer *fb) return container_of(fb, struct drm_fb_cma, fb); } -static void drm_fb_cma_destroy(struct drm_framebuffer *fb) +void drm_fb_cma_destroy(struct drm_framebuffer *fb) { struct drm_fb_cma *fb_cma = to_fb_cma(fb); int i; @@ -58,8 +60,9 @@ static void drm_fb_cma_destroy(struct drm_framebuffer *fb) drm_framebuffer_cleanup(fb); kfree(fb_cma); } +EXPORT_SYMBOL(drm_fb_cma_destroy); -static int drm_fb_cma_create_handle(struct drm_framebuffer *fb, +int drm_fb_cma_create_handle(struct drm_framebuffer *fb, struct drm_file *file_priv, unsigned int *handle) { struct drm_fb_cma *fb_cma = to_fb_cma(fb); @@ -67,6 +70,7 @@ static int drm_fb_cma_create_handle(struct drm_framebuffer *fb, return drm_gem_handle_create(file_priv, &fb_cma->obj[0]->base, handle); } +EXPORT_SYMBOL(drm_fb_cma_create_handle); static struct drm_framebuffer_funcs drm_fb_cma_funcs = { .destroy = drm_fb_cma_destroy, @@ -75,7 +79,7 @@ static struct drm_framebuffer_funcs drm_fb_cma_funcs = { static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev, const const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_cma_object **obj, - unsigned int num_planes) + unsigned int num_planes, struct drm_framebuffer_funcs *funcs) { struct drm_fb_cma *fb_cma; int ret; @@ -90,7 +94,7 @@ static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev, for (i = 0; i < num_planes; i++) fb_cma->obj[i] = obj[i]; - ret = drm_framebuffer_init(dev, &fb_cma->fb, &drm_fb_cma_funcs); + ret = drm_framebuffer_init(dev, &fb_cma->fb, funcs); if (ret) { dev_err(dev->dev, "Failed to initialize framebuffer: %d\n", ret); kfree(fb_cma); @@ -144,7 +148,7 @@ struct drm_framebuffer *drm_fb_cma_create(struct drm_device *dev, objs[i] = to_drm_gem_cma_obj(obj); } - fb_cma = drm_fb_cma_alloc(dev, mode_cmd, objs, i); + fb_cma = drm_fb_cma_alloc(dev, mode_cmd, objs, i, &drm_fb_cma_funcs); if (IS_ERR(fb_cma)) { ret = PTR_ERR(fb_cma); goto err_gem_object_unreference; @@ -232,8 +236,93 @@ static struct fb_ops drm_fbdev_cma_ops = { .fb_setcmap = drm_fb_helper_setcmap, }; -static int drm_fbdev_cma_create(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes) +#ifdef CONFIG_FB_DEFERRED_IO +/* + * HACK + * fb_deferred_io_mmap() is not exported so I use this hack until it's clear + * that this patch will be used. + */ +static int (*fb_deferred_io_mmap)(struct fb_info *info, + struct vm_area_struct *vma); +/* + * I sent a question about my need to set vm_page_prot to the fbdev ML, but + * I haven't heard back. So exporting fb_deferred_io_mmap() is probably + * the best solution. + */ +static int drm_fbdev_cma_deferred_io_mmap(struct fb_info *info, + struct vm_area_struct *vma) +{ + fb_deferred_io_mmap(info, vma); + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + + return 0; +} + +static int drm_fbdev_cma_defio_init(struct fb_info *fbi, + struct drm_gem_cma_object *cma_obj) +{ + struct fb_deferred_io *fbdefio; + struct fb_ops *fbops; + + /* + * Per device structures are needed because: + * fbops: fb_deferred_io_cleanup() clears fbops.fb_mmap + * fbdefio: individual delays + */ + fbdefio = kzalloc(sizeof(*fbdefio), GFP_KERNEL); + fbops = kzalloc(sizeof(*fbops), GFP_KERNEL); + if (!fbdefio || !fbops) { + kfree(fbdefio); + return -ENOMEM; + } + + /* can't be offset from vaddr since dirty() uses cma_obj */ + fbi->screen_buffer = cma_obj->vaddr; + /* fb_deferred_io_fault() needs a physical address */ + fbi->fix.smem_start = page_to_phys(virt_to_page(fbi->screen_buffer)); + + *fbops = *fbi->fbops; + fbi->fbops = fbops; + + fbdefio->delay = msecs_to_jiffies(DEFAULT_FBDEFIO_DELAY_MS); + fbdefio->deferred_io = drm_fb_helper_deferred_io; + fbi->fbdefio = fbdefio; + fb_deferred_io_init(fbi); + + if (!fb_deferred_io_mmap) + fb_deferred_io_mmap = fbi->fbops->fb_mmap; + fbi->fbops->fb_mmap = drm_fbdev_cma_deferred_io_mmap; + + return 0; +} + +static void drm_fbdev_cma_defio_fini(struct fb_info *fbi) +{ + if (!fbi->fbdefio) + return; + + fb_deferred_io_cleanup(fbi); + kfree(fbi->fbdefio); + kfree(fbi->fbops); +} +#else +static inline int drm_fbdev_cma_defio_init(struct fb_info *fbi) +{ + return 0; +} + +static inline void drm_fbdev_cma_defio_fini(struct fb_info *fbi) +{ +} +#endif /* CONFIG_FB_DEFERRED_IO */ + +/* + * For use in a (struct drm_fb_helper_funcs *)->fb_probe callback function that + * needs custom struct drm_framebuffer_funcs, like dirty() for deferred_io use. + */ +int drm_fbdev_cma_create_with_funcs(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes, + struct drm_framebuffer_funcs *funcs) { struct drm_fbdev_cma *fbdev_cma = to_fbdev_cma(helper); struct drm_mode_fb_cmd2 mode_cmd = { 0 }; @@ -269,7 +358,7 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper, goto err_gem_free_object; } - fbdev_cma->fb = drm_fb_cma_alloc(dev, &mode_cmd, &obj, 1); + fbdev_cma->fb = drm_fb_cma_alloc(dev, &mode_cmd, &obj, 1, funcs); if (IS_ERR(fbdev_cma->fb)) { dev_err(dev->dev, "Failed to allocate DRM framebuffer.\n"); ret = PTR_ERR(fbdev_cma->fb); @@ -295,31 +384,48 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper, fbi->screen_size = size; fbi->fix.smem_len = size; + if (funcs->dirty) { + ret = drm_fbdev_cma_defio_init(fbi, obj); + if (ret) + goto err_cma_destroy; + } + return 0; +err_cma_destroy: + drm_framebuffer_unregister_private(&fbdev_cma->fb->fb); + drm_fb_cma_destroy(&fbdev_cma->fb->fb); err_fb_info_destroy: drm_fb_helper_release_fbi(helper); err_gem_free_object: dev->driver->gem_free_object(&obj->base); return ret; } +EXPORT_SYMBOL(drm_fbdev_cma_create_with_funcs); + +static int drm_fbdev_cma_create(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes) +{ + return drm_fbdev_cma_create_with_funcs(helper, sizes, &drm_fb_cma_funcs); +} static const struct drm_fb_helper_funcs drm_fb_cma_helper_funcs = { .fb_probe = drm_fbdev_cma_create, }; /** - * drm_fbdev_cma_init() - Allocate and initializes a drm_fbdev_cma struct + * drm_fbdev_cma_init_with_funcs() - Allocate and initializes a drm_fbdev_cma struct * @dev: DRM device * @preferred_bpp: Preferred bits per pixel for the device * @num_crtc: Number of CRTCs * @max_conn_count: Maximum number of connectors + * @funcs: fb helper functions, in particular fb_probe() * * Returns a newly allocated drm_fbdev_cma struct or a ERR_PTR. */ -struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev, +struct drm_fbdev_cma *drm_fbdev_cma_init_with_funcs(struct drm_device *dev, unsigned int preferred_bpp, unsigned int num_crtc, - unsigned int max_conn_count) + unsigned int max_conn_count, const struct drm_fb_helper_funcs *funcs) { struct drm_fbdev_cma *fbdev_cma; struct drm_fb_helper *helper; @@ -333,7 +439,7 @@ struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev, helper = &fbdev_cma->fb_helper; - drm_fb_helper_prepare(dev, helper, &drm_fb_cma_helper_funcs); + drm_fb_helper_prepare(dev, helper, funcs); ret = drm_fb_helper_init(dev, helper, num_crtc, max_conn_count); if (ret < 0) { @@ -363,6 +469,24 @@ err_free: return ERR_PTR(ret); } +EXPORT_SYMBOL_GPL(drm_fbdev_cma_init_with_funcs); + +/** + * drm_fbdev_cma_init() - Allocate and initializes a drm_fbdev_cma struct + * @dev: DRM device + * @preferred_bpp: Preferred bits per pixel for the device + * @num_crtc: Number of CRTCs + * @max_conn_count: Maximum number of connectors + * + * Returns a newly allocated drm_fbdev_cma struct or a ERR_PTR. + */ +struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev, + unsigned int preferred_bpp, unsigned int num_crtc, + unsigned int max_conn_count) +{ + return drm_fbdev_cma_init_with_funcs(dev, preferred_bpp, num_crtc, + max_conn_count, &drm_fb_cma_helper_funcs); +} EXPORT_SYMBOL_GPL(drm_fbdev_cma_init); /** @@ -372,6 +496,7 @@ EXPORT_SYMBOL_GPL(drm_fbdev_cma_init); void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma) { drm_fb_helper_unregister_fbi(&fbdev_cma->fb_helper); + drm_fbdev_cma_defio_fini(fbdev_cma->fb_helper.fbdev); drm_fb_helper_release_fbi(&fbdev_cma->fb_helper); if (fbdev_cma->fb) { diff --git a/include/drm/drm_fb_cma_helper.h b/include/drm/drm_fb_cma_helper.h index be62bd3..6554b6f 100644 --- a/include/drm/drm_fb_cma_helper.h +++ b/include/drm/drm_fb_cma_helper.h @@ -4,11 +4,18 @@ struct drm_fbdev_cma; struct drm_gem_cma_object; +struct drm_fb_helper_surface_size; +struct drm_framebuffer_funcs; +struct drm_fb_helper_funcs; struct drm_framebuffer; +struct drm_fb_helper; struct drm_device; struct drm_file; struct drm_mode_fb_cmd2; +struct drm_fbdev_cma *drm_fbdev_cma_init_with_funcs(struct drm_device *dev, + unsigned int preferred_bpp, unsigned int num_crtc, + unsigned int max_conn_count, const struct drm_fb_helper_funcs *funcs); struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev, unsigned int preferred_bpp, unsigned int num_crtc, unsigned int max_conn_count); @@ -16,6 +23,13 @@ void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma); void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma *fbdev_cma); void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma *fbdev_cma); +int drm_fbdev_cma_create_with_funcs(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes, + struct drm_framebuffer_funcs *funcs); + +void drm_fb_cma_destroy(struct drm_framebuffer *fb); +int drm_fb_cma_create_handle(struct drm_framebuffer *fb, + struct drm_file *file_priv, unsigned int *handle); struct drm_framebuffer *drm_fb_cma_create(struct drm_device *dev, struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd);
This adds fbdev deferred io support if CONFIG_FB_DEFERRED_IO is enabled. The driver has to provide a (struct drm_framebuffer_funcs *)->dirty() callback to get notification of fbdev framebuffer changes. If the dirty() hook is set, then fb_deferred_io is set up automatically by the helper. Two functions have been added so that the driver can provide a dirty() function: - drm_fbdev_cma_init_with_funcs() This makes it possible for the driver to provided a custom (struct drm_fb_helper_funcs *)->fb_probe() function. - drm_fbdev_cma_create_with_funcs() This is used by the .fb_probe hook to set a driver provided (struct drm_framebuffer_funcs *)->dirty() function. Example driver code: static int driver_fbdev_fb_dirty(struct drm_framebuffer *fb, struct drm_file *file_priv, unsigned flags, unsigned color, struct drm_clip_rect *clips, unsigned num_clips) { struct drm_gem_cma_object *cma = drm_fb_cma_get_gem_obj(fb, 0); return 0; } static struct drm_framebuffer_funcs driver_fbdev_fb_funcs = { .destroy = drm_fb_cma_destroy, .create_handle = drm_fb_cma_create_handle, .dirty = driver_fbdev_fb_dirty, }; static int driver_fbdev_create(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { return drm_fbdev_cma_create_with_funcs(helper, sizes, &driver_fbdev_fb_funcs); } static const struct drm_fb_helper_funcs driver_fb_helper_funcs = { .fb_probe = driver_fbdev_create, }; Driver probe: fbdev = drm_fbdev_cma_init_with_funcs(dev, 16, dev->mode_config.num_crtc, dev->mode_config.num_connector, &driver_fb_helper_funcs); Signed-off-by: Noralf Trønnes <noralf@tronnes.org> --- drivers/gpu/drm/drm_fb_cma_helper.c | 149 +++++++++++++++++++++++++++++++++--- include/drm/drm_fb_cma_helper.h | 14 ++++ 2 files changed, 151 insertions(+), 12 deletions(-)