Re: [RFC v4 22/25] drm/fb-helper: Add generic fbdev emulation

2018-04-16 Thread Daniel Vetter
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:
> +  

[RFC v4 22/25] drm/fb-helper: Add generic fbdev emulation

2018-04-14 Thread Noralf Trønnes
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
+

[RFC v4 22/25] drm/fb-helper: Add generic fbdev emulation

2018-04-12 Thread Noralf Trønnes
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
+