[PATCH 7/8] drm/fb-helper: Select between fb_{sys, cfb}_read() and _write()
Thomas Zimmermann
tzimmermann at suse.de
Wed Nov 6 09:31:20 UTC 2019
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 at 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 --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
More information about the dri-devel
mailing list