Generic fbdev emulation used to access framebuffers as if they were
located in system memory.

Depending on the whether the framebuffer is in I/O or system memory,
the fbdev emulation now calls the correct functions for accessing each.
This change allows to support generic fbdev emulation on systems that
treat both memory areas differently.

Signed-off-by: Thomas Zimmermann <[email protected]>
---
 drivers/gpu/drm/drm_fb_helper.c | 110 ++++++++++++++++++++++++++++++--
 include/drm/drm_fb_helper.h     |  14 ++++
 2 files changed, 118 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index eff75fad7cab..174e6d97223f 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -771,6 +771,45 @@ void drm_fb_helper_sys_imageblit(struct fb_info *info,
 }
 EXPORT_SYMBOL(drm_fb_helper_sys_imageblit);
 
+/**
+ * drm_fb_helper_cfb_read - wrapper around fb_cfb_read
+ * @info: fb_info struct pointer
+ * @buf: userspace buffer to read from framebuffer memory
+ * @count: number of bytes to read from framebuffer memory
+ * @ppos: read offset within framebuffer memory
+ *
+ * A wrapper around fb_cfb_read implemented by fbdev core
+ */
+ssize_t drm_fb_helper_cfb_read(struct fb_info *info, char __user *buf,
+                              size_t count, loff_t *ppos)
+{
+       return fb_cfb_read(info, buf, count, ppos);
+}
+EXPORT_SYMBOL(drm_fb_helper_cfb_read);
+
+/**
+ * drm_fb_helper_cfb_write - wrapper around fb_cfb_write
+ * @info: fb_info struct pointer
+ * @buf: userspace buffer to write to framebuffer memory
+ * @count: number of bytes to write to framebuffer memory
+ * @ppos: write offset within framebuffer memory
+ *
+ * A wrapper around fb_cfb_write implemented by fbdev core
+ */
+ssize_t drm_fb_helper_cfb_write(struct fb_info *info, const char __user *buf,
+                               size_t count, loff_t *ppos)
+{
+       ssize_t ret;
+
+       ret = fb_cfb_write(info, buf, count, ppos);
+       if (ret > 0)
+               drm_fb_helper_dirty(info, 0, 0, info->var.xres,
+                                   info->var.yres);
+
+       return ret;
+}
+EXPORT_SYMBOL(drm_fb_helper_cfb_write);
+
 /**
  * drm_fb_helper_cfb_fillrect - wrapper around cfb_fillrect
  * @info: fbdev registered by the helper
@@ -2122,6 +2161,59 @@ static int drm_fbdev_fb_mmap(struct fb_info *info, 
struct vm_area_struct *vma)
                return -ENODEV;
 }
 
+static ssize_t drm_fbdev_fb_read(struct fb_info *info, char __user *buf,
+                                size_t count, loff_t *ppos)
+{
+       struct drm_fb_helper *fb_helper = info->par;
+
+       if (fb_helper->screen_buffer_is_iomem)
+               return drm_fb_helper_cfb_read(info, buf, count, ppos);
+       return drm_fb_helper_sys_read(info, buf, count, ppos);
+}
+
+static ssize_t drm_fbdev_fb_write(struct fb_info *info, const char __user *buf,
+                                 size_t count, loff_t *ppos)
+{
+       struct drm_fb_helper *fb_helper = info->par;
+
+       if (fb_helper->screen_buffer_is_iomem)
+               return drm_fb_helper_cfb_write(info, buf, count, ppos);
+       return drm_fb_helper_sys_write(info, buf, count, ppos);
+}
+
+static void drm_fbdev_fb_fillrect(struct fb_info *info,
+                                 const struct fb_fillrect *rect)
+{
+       struct drm_fb_helper *fb_helper = info->par;
+
+       if (fb_helper->screen_buffer_is_iomem)
+               drm_fb_helper_cfb_fillrect(info, rect);
+       else
+               drm_fb_helper_sys_fillrect(info, rect);
+}
+
+static void drm_fbdev_fb_copyarea(struct fb_info *info,
+                                 const struct fb_copyarea *region)
+{
+       struct drm_fb_helper *fb_helper = info->par;
+
+       if (fb_helper->screen_buffer_is_iomem)
+               drm_fb_helper_cfb_copyarea(info, region);
+       else
+               drm_fb_helper_sys_copyarea(info, region);
+}
+
+static void drm_fbdev_fb_imageblit(struct fb_info *info,
+                                  const struct fb_image *image)
+{
+       struct drm_fb_helper *fb_helper = info->par;
+
+       if (fb_helper->screen_buffer_is_iomem)
+               drm_fb_helper_cfb_imageblit(info, image);
+       else
+               drm_fb_helper_sys_imageblit(info, image);
+}
+
 static struct fb_ops drm_fbdev_fb_ops = {
        .owner          = THIS_MODULE,
        DRM_FB_HELPER_DEFAULT_OPS,
@@ -2129,11 +2221,11 @@ static struct fb_ops drm_fbdev_fb_ops = {
        .fb_release     = drm_fbdev_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,
+       .fb_read        = drm_fbdev_fb_read,
+       .fb_write       = drm_fbdev_fb_write,
+       .fb_fillrect    = drm_fbdev_fb_fillrect,
+       .fb_copyarea    = drm_fbdev_fb_copyarea,
+       .fb_imageblit   = drm_fbdev_fb_imageblit,
 };
 
 static struct fb_deferred_io drm_fbdev_defio = {
@@ -2209,10 +2301,15 @@ int drm_fb_helper_generic_probe(struct drm_fb_helper 
*fb_helper,
                fbi->screen_buffer = shadow;
                fbi->fbdefio = &drm_fbdev_defio;
 
+               /* The shadowfb is always in system memory. */
+               fb_helper->screen_buffer_is_iomem = false;
+
                fb_deferred_io_init(fbi);
        } else {
+               bool is_iomem;
+
                /* buffer is mapped for HW framebuffer */
-               vaddr = drm_client_buffer_vmap(fb_helper->buffer, NULL);
+               vaddr = drm_client_buffer_vmap(fb_helper->buffer, &is_iomem);
                if (IS_ERR(vaddr))
                        return PTR_ERR(vaddr);
 
@@ -2223,6 +2320,7 @@ int drm_fb_helper_generic_probe(struct drm_fb_helper 
*fb_helper,
                        fbi->fix.smem_start =
                                page_to_phys(virt_to_page(fbi->screen_buffer));
 #endif
+               fb_helper->screen_buffer_is_iomem = is_iomem;
        }
 
        return 0;
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 2338e9f94a03..afceae8db4af 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -155,6 +155,15 @@ struct drm_fb_helper {
         */
        struct list_head kernel_fb_list;
 
+       /**
+        * @screen_buffer_is_iomem
+        *
+        * True if info->screen_buffer refers to I/O memory, false otherwise.
+        * Depending on this flag, fb_ops should either use sys to cfb
+        * functions.
+        */
+       bool screen_buffer_is_iomem;
+
        /**
         * @delayed_hotplug:
         *
@@ -248,6 +257,11 @@ void drm_fb_helper_sys_copyarea(struct fb_info *info,
 void drm_fb_helper_sys_imageblit(struct fb_info *info,
                                 const struct fb_image *image);
 
+ssize_t drm_fb_helper_cfb_read(struct fb_info *info, char __user *buf,
+                              size_t count, loff_t *ppos);
+ssize_t drm_fb_helper_cfb_write(struct fb_info *info, const char __user *buf,
+                               size_t count, loff_t *ppos);
+
 void drm_fb_helper_cfb_fillrect(struct fb_info *info,
                                const struct fb_fillrect *rect);
 void drm_fb_helper_cfb_copyarea(struct fb_info *info,
-- 
2.23.0

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to