Re: [Intel-gfx] [RFC v4 22/25] drm/fb-helper: Add generic fbdev emulation
On Sat, Apr 14, 2018 at 01:53:15PM +0200, Noralf Trønnes wrote: > This adds generic fbdev emulation for drivers that supports > dumb buffers which they can export. > > All the driver has to do is call drm_fbdev_generic_setup(). > > Signed-off-by: Noralf Trønnes> --- > drivers/gpu/drm/drm_fb_helper.c | 255 > > include/drm/drm_fb_helper.h | 20 > 2 files changed, 275 insertions(+) > > diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c > index b1124c08b1ed..1954de5b13e0 100644 > --- a/drivers/gpu/drm/drm_fb_helper.c > +++ b/drivers/gpu/drm/drm_fb_helper.c > @@ -30,6 +30,7 @@ > #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt > > #include > +#include > #include > #include > #include > @@ -1995,6 +1996,260 @@ void drm_fb_helper_output_poll_changed(struct > drm_device *dev) > } > EXPORT_SYMBOL(drm_fb_helper_output_poll_changed); > > +static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct > *vma) > +{ > + struct drm_fb_helper *fb_helper = info->par; > + > + return dma_buf_mmap(fb_helper->buffer->dma_buf, vma, 0); > +} > + > +/* > + * fb_ops.fb_destroy is called by the last put_fb_info() call at the end of > + * unregister_framebuffer() or fb_release(). > + */ > +static void drm_fbdev_fb_destroy(struct fb_info *info) > +{ > + struct drm_fb_helper *fb_helper = info->par; > + struct fb_ops *fbops = NULL; > + > + DRM_DEBUG("\n"); > + > + if (fb_helper->fbdev->fbdefio) > + fbops = fb_helper->fbdev->fbops; > + > + drm_fb_helper_fini(fb_helper); > + drm_client_framebuffer_delete(fb_helper->buffer); > + drm_client_free(fb_helper->client); > + kfree(fb_helper); > + kfree(fbops); > +} > + > +static struct fb_ops drm_fbdev_fb_ops = { > + /* > + * No need to set owner, this module is already pinned by the driver. > + * A reference is taken on the driver module in drm_fb_helper_fb_open() > + * to prevent the driver going away with open fd's. > + */ > + DRM_FB_HELPER_DEFAULT_OPS, > + .fb_open= drm_fb_helper_fb_open, > + .fb_release = drm_fb_helper_fb_release, > + .fb_destroy = drm_fbdev_fb_destroy, > + .fb_mmap= drm_fbdev_fb_mmap, > + .fb_read= drm_fb_helper_sys_read, > + .fb_write = drm_fb_helper_sys_write, > + .fb_fillrect= drm_fb_helper_sys_fillrect, > + .fb_copyarea= drm_fb_helper_sys_copyarea, > + .fb_imageblit = drm_fb_helper_sys_imageblit, > +}; > + > +static struct fb_deferred_io drm_fbdev_defio = { > + .delay = HZ / 20, > + .deferred_io= drm_fb_helper_deferred_io, > +}; > + > +/* Hack to test tinydrm before converting to vmalloc buffers */ > +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_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, > +struct drm_fb_helper_surface_size *sizes) > +{ > + struct drm_client_dev *client = fb_helper->client; > + struct drm_display_mode sizes_mode = { > + .hdisplay = sizes->surface_width, > + .vdisplay = sizes->surface_height, > + }; > + struct drm_client_buffer *buffer; > + struct drm_framebuffer *fb; > + struct fb_info *fbi; > + u32 format; > + int ret; > + > + DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n", > + sizes->surface_width, sizes->surface_height, > + sizes->surface_bpp); > + > + format = drm_mode_legacy_fb_format(sizes->surface_bpp, > sizes->surface_depth); > + buffer = drm_client_framebuffer_create(client, _mode, format); > + if (IS_ERR(buffer)) > + return PTR_ERR(buffer); > + > + fb_helper->buffer = buffer; > + fb_helper->fb = buffer->fb; > + fb = buffer->fb; > + > + fbi = drm_fb_helper_alloc_fbi(fb_helper); > + if (IS_ERR(fbi)) { > + ret = PTR_ERR(fbi); > + goto err_free_buffer; > + } > + > + fbi->par = fb_helper; > + fbi->fbops = _fbdev_fb_ops; > + fbi->screen_size = fb->height * fb->pitches[0]; > + fbi->fix.smem_len = fbi->screen_size; > + fbi->screen_buffer = buffer->vaddr; > + strcpy(fbi->fix.id, "DRM emulated"); > + > + drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->format->depth); > + drm_fb_helper_fill_var(fbi, fb_helper, sizes->fb_width, > sizes->fb_height); > + > + /* > + * Drivers that set the dirty callback: > + * - Doesn't use defio: > + * i915, virtio, rockchip > + * - defio with vmalloc buffer blitted on the real one: > + * vmwgfx > + * - defio is disabled because it doesn't work with shmem: > +
[Intel-gfx] [RFC v4 22/25] drm/fb-helper: Add generic fbdev emulation
This adds generic fbdev emulation for drivers that supports dumb buffers which they can export. All the driver has to do is call drm_fbdev_generic_setup(). Signed-off-by: Noralf Trønnes--- drivers/gpu/drm/drm_fb_helper.c | 255 include/drm/drm_fb_helper.h | 20 2 files changed, 275 insertions(+) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index b1124c08b1ed..1954de5b13e0 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -30,6 +30,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include @@ -1995,6 +1996,260 @@ void drm_fb_helper_output_poll_changed(struct drm_device *dev) } EXPORT_SYMBOL(drm_fb_helper_output_poll_changed); +static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + struct drm_fb_helper *fb_helper = info->par; + + return dma_buf_mmap(fb_helper->buffer->dma_buf, vma, 0); +} + +/* + * fb_ops.fb_destroy is called by the last put_fb_info() call at the end of + * unregister_framebuffer() or fb_release(). + */ +static void drm_fbdev_fb_destroy(struct fb_info *info) +{ + struct drm_fb_helper *fb_helper = info->par; + struct fb_ops *fbops = NULL; + + DRM_DEBUG("\n"); + + if (fb_helper->fbdev->fbdefio) + fbops = fb_helper->fbdev->fbops; + + drm_fb_helper_fini(fb_helper); + drm_client_framebuffer_delete(fb_helper->buffer); + drm_client_free(fb_helper->client); + kfree(fb_helper); + kfree(fbops); +} + +static struct fb_ops drm_fbdev_fb_ops = { + /* +* No need to set owner, this module is already pinned by the driver. +* A reference is taken on the driver module in drm_fb_helper_fb_open() +* to prevent the driver going away with open fd's. +*/ + DRM_FB_HELPER_DEFAULT_OPS, + .fb_open= drm_fb_helper_fb_open, + .fb_release = drm_fb_helper_fb_release, + .fb_destroy = drm_fbdev_fb_destroy, + .fb_mmap= drm_fbdev_fb_mmap, + .fb_read= drm_fb_helper_sys_read, + .fb_write = drm_fb_helper_sys_write, + .fb_fillrect= drm_fb_helper_sys_fillrect, + .fb_copyarea= drm_fb_helper_sys_copyarea, + .fb_imageblit = drm_fb_helper_sys_imageblit, +}; + +static struct fb_deferred_io drm_fbdev_defio = { + .delay = HZ / 20, + .deferred_io= drm_fb_helper_deferred_io, +}; + +/* Hack to test tinydrm before converting to vmalloc buffers */ +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_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, + struct drm_fb_helper_surface_size *sizes) +{ + struct drm_client_dev *client = fb_helper->client; + struct drm_display_mode sizes_mode = { + .hdisplay = sizes->surface_width, + .vdisplay = sizes->surface_height, + }; + struct drm_client_buffer *buffer; + struct drm_framebuffer *fb; + struct fb_info *fbi; + u32 format; + int ret; + + DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n", + sizes->surface_width, sizes->surface_height, + sizes->surface_bpp); + + format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth); + buffer = drm_client_framebuffer_create(client, _mode, format); + if (IS_ERR(buffer)) + return PTR_ERR(buffer); + + fb_helper->buffer = buffer; + fb_helper->fb = buffer->fb; + fb = buffer->fb; + + fbi = drm_fb_helper_alloc_fbi(fb_helper); + if (IS_ERR(fbi)) { + ret = PTR_ERR(fbi); + goto err_free_buffer; + } + + fbi->par = fb_helper; + fbi->fbops = _fbdev_fb_ops; + fbi->screen_size = fb->height * fb->pitches[0]; + fbi->fix.smem_len = fbi->screen_size; + fbi->screen_buffer = buffer->vaddr; + strcpy(fbi->fix.id, "DRM emulated"); + + drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->format->depth); + drm_fb_helper_fill_var(fbi, fb_helper, sizes->fb_width, sizes->fb_height); + + /* +* Drivers that set the dirty callback: +* - Doesn't use defio: +* i915, virtio, rockchip +* - defio with vmalloc buffer blitted on the real one: +* vmwgfx +* - defio is disabled because it doesn't work with shmem: +* udl +* - defio with special dirty callback for fbdev, uses vmalloc for fbdev: +* qxl +* - defio with cma buffer, will move to vmalloc buffers: +* tinydrm +
[Intel-gfx] [RFC v4 22/25] drm/fb-helper: Add generic fbdev emulation
This adds generic fbdev emulation for drivers that supports dumb buffers which they can export. All the driver has to do is call drm_fbdev_generic_setup(). Signed-off-by: Noralf Trønnes--- drivers/gpu/drm/drm_fb_helper.c | 255 include/drm/drm_fb_helper.h | 20 2 files changed, 275 insertions(+) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index b1124c08b1ed..1954de5b13e0 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -30,6 +30,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include @@ -1995,6 +1996,260 @@ void drm_fb_helper_output_poll_changed(struct drm_device *dev) } EXPORT_SYMBOL(drm_fb_helper_output_poll_changed); +static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + struct drm_fb_helper *fb_helper = info->par; + + return dma_buf_mmap(fb_helper->buffer->dma_buf, vma, 0); +} + +/* + * fb_ops.fb_destroy is called by the last put_fb_info() call at the end of + * unregister_framebuffer() or fb_release(). + */ +static void drm_fbdev_fb_destroy(struct fb_info *info) +{ + struct drm_fb_helper *fb_helper = info->par; + struct fb_ops *fbops = NULL; + + DRM_DEBUG("\n"); + + if (fb_helper->fbdev->fbdefio) + fbops = fb_helper->fbdev->fbops; + + drm_fb_helper_fini(fb_helper); + drm_client_framebuffer_delete(fb_helper->buffer); + drm_client_free(fb_helper->client); + kfree(fb_helper); + kfree(fbops); +} + +static struct fb_ops drm_fbdev_fb_ops = { + /* +* No need to set owner, this module is already pinned by the driver. +* A reference is taken on the driver module in drm_fb_helper_fb_open() +* to prevent the driver going away with open fd's. +*/ + DRM_FB_HELPER_DEFAULT_OPS, + .fb_open= drm_fb_helper_fb_open, + .fb_release = drm_fb_helper_fb_release, + .fb_destroy = drm_fbdev_fb_destroy, + .fb_mmap= drm_fbdev_fb_mmap, + .fb_read= drm_fb_helper_sys_read, + .fb_write = drm_fb_helper_sys_write, + .fb_fillrect= drm_fb_helper_sys_fillrect, + .fb_copyarea= drm_fb_helper_sys_copyarea, + .fb_imageblit = drm_fb_helper_sys_imageblit, +}; + +static struct fb_deferred_io drm_fbdev_defio = { + .delay = HZ / 20, + .deferred_io= drm_fb_helper_deferred_io, +}; + +/* Hack to test tinydrm before converting to vmalloc buffers */ +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_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, + struct drm_fb_helper_surface_size *sizes) +{ + struct drm_client_dev *client = fb_helper->client; + struct drm_display_mode sizes_mode = { + .hdisplay = sizes->surface_width, + .vdisplay = sizes->surface_height, + }; + struct drm_client_buffer *buffer; + struct drm_framebuffer *fb; + struct fb_info *fbi; + u32 format; + int ret; + + DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n", + sizes->surface_width, sizes->surface_height, + sizes->surface_bpp); + + format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth); + buffer = drm_client_framebuffer_create(client, _mode, format); + if (IS_ERR(buffer)) + return PTR_ERR(buffer); + + fb_helper->buffer = buffer; + fb_helper->fb = buffer->fb; + fb = buffer->fb; + + fbi = drm_fb_helper_alloc_fbi(fb_helper); + if (IS_ERR(fbi)) { + ret = PTR_ERR(fbi); + goto err_free_buffer; + } + + fbi->par = fb_helper; + fbi->fbops = _fbdev_fb_ops; + fbi->screen_size = fb->height * fb->pitches[0]; + fbi->fix.smem_len = fbi->screen_size; + fbi->screen_buffer = buffer->vaddr; + strcpy(fbi->fix.id, "DRM emulated"); + + drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->format->depth); + drm_fb_helper_fill_var(fbi, fb_helper, sizes->fb_width, sizes->fb_height); + + /* +* Drivers that set the dirty callback: +* - Doesn't use defio: +* i915, virtio, rockchip +* - defio with vmalloc buffer blitted on the real one: +* vmwgfx +* - defio is disabled because it doesn't work with shmem: +* udl +* - defio with special dirty callback for fbdev, uses vmalloc for fbdev: +* qxl +* - defio with cma buffer, will move to vmalloc buffers: +* tinydrm +