diff mbox series

[7/8] drm/fb-helper: Select between fb_{sys, cfb}_read() and _write()

Message ID 20191106093121.21762-8-tzimmermann@suse.de (mailing list archive)
State New, archived
Headers show
Series Support I/O memory in generic fbdev emulation | expand

Commit Message

Thomas Zimmermann Nov. 6, 2019, 9:31 a.m. UTC
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 <tzimmermann@suse.de>
---
 drivers/gpu/drm/drm_fb_helper.c | 110 ++++++++++++++++++++++++++++++--
 include/drm/drm_fb_helper.h     |  14 ++++
 2 files changed, 118 insertions(+), 6 deletions(-)
diff mbox series

Patch

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,