diff mbox

[RFC,6/7] drm: Add kms library for shmem backed GEM

Message ID 1499867165-60925-7-git-send-email-noralf@tronnes.org (mailing list archive)
State New, archived
Headers show

Commit Message

Noralf Trønnes July 12, 2017, 1:46 p.m. UTC
This adds kms helpers for the shmem gem library.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/Kconfig               |  11 +++
 drivers/gpu/drm/Makefile              |   1 +
 drivers/gpu/drm/drm_fb_shmem_helper.c | 168 ++++++++++++++++++++++++++++++++++
 include/drm/drm_fb_shmem_helper.h     |  18 ++++
 4 files changed, 198 insertions(+)
 create mode 100644 drivers/gpu/drm/drm_fb_shmem_helper.c
 create mode 100644 include/drm/drm_fb_shmem_helper.h
diff mbox

Patch

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 8e709c2..4c9010d 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -151,6 +151,17 @@  config DRM_GEM_SHMEM_HELPER
 	help
 	  Choose this if you need the GEM SHMEM helper functions
 
+config DRM_KMS_SHMEM_HELPER
+	bool
+	depends on DRM
+	select DRM_GEM_SHMEM_HELPER
+	select DRM_KMS_FB_HELPER
+	select FB_SYS_FILLRECT
+	select FB_SYS_COPYAREA
+	select FB_SYS_IMAGEBLIT
+	help
+	  Choose this if you need the KMS SHMEM helper functions
+
 config DRM_VM
 	bool
 	depends on DRM && MMU
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 598c247..706037c 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -40,6 +40,7 @@  drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
 drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
 drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
 drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o
+drm_kms_helper-$(CONFIG_DRM_KMS_SHMEM_HELPER) += drm_fb_shmem_helper.o
 drm_kms_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o
 
 obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
diff --git a/drivers/gpu/drm/drm_fb_shmem_helper.c b/drivers/gpu/drm/drm_fb_shmem_helper.c
new file mode 100644
index 0000000..ddcf24f
--- /dev/null
+++ b/drivers/gpu/drm/drm_fb_shmem_helper.c
@@ -0,0 +1,168 @@ 
+/*
+ * drm kms/fb shmem (shared memory) helper functions
+ *
+ * Copyright (C) 2017 Noralf Trønnes
+ *
+ * Based on drm_fb_cma_helper.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_gem_shmem_helper.h>
+#include <drm/drm_fb_gem_helper.h>
+#include <drm/drm_fb_shmem_helper.h>
+
+#ifdef CONFIG_DEBUG_FS
+static void drm_fb_shmem_describe(struct drm_framebuffer *fb, struct seq_file *m)
+{
+	struct drm_fb_gem *fb_gem = to_fb_gem(fb);
+	struct drm_gem_shmem_object *obj;
+	int i;
+
+	seq_printf(m, "[FB:%d] %dx%d@%4.4s\n", fb->base.id, fb->width, fb->height,
+			(char *)&fb->format->format);
+
+	for (i = 0; i < fb->format->num_planes; i++) {
+		obj = to_drm_gem_shmem_obj(fb_gem->obj[i]);
+		seq_printf(m, "   %d: offset=%d pitch=%d, obj: ",
+				i, fb->offsets[i], fb->pitches[i]);
+		drm_gem_shmem_describe(obj, m);
+	}
+}
+
+/**
+ * drm_fb_shmem_debugfs_show() - Helper to list shmem framebuffer objects
+ *                               in debugfs.
+ * @m: output file
+ * @arg: private data for the callback
+ */
+int drm_fb_shmem_debugfs_show(struct seq_file *m, void *arg)
+{
+	struct drm_info_node *node = (struct drm_info_node *)m->private;
+	struct drm_device *dev = node->minor->dev;
+	struct drm_framebuffer *fb;
+
+	mutex_lock(&dev->mode_config.fb_lock);
+	drm_for_each_fb(fb, dev)
+		drm_fb_shmem_describe(fb, m);
+	mutex_unlock(&dev->mode_config.fb_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(drm_fb_shmem_debugfs_show);
+#endif
+
+static int drm_fb_shmem_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
+{
+	struct drm_fb_helper *helper = fbi->par;
+	struct drm_fb_gem *fb_gem = to_fb_gem(helper->fb);
+
+	return drm_gem_shmem_prime_mmap(fb_gem->obj[0], vma);
+}
+
+static int drm_fb_helper_fb_open(struct fb_info *fbi, int user)
+{
+	struct drm_fb_helper *helper = fbi->par;
+
+	if (!try_module_get(helper->dev->driver->fops->owner))
+		return -ENODEV;
+
+	return 0;
+}
+
+static int drm_fb_helper_fb_release(struct fb_info *fbi, int user)
+{
+	struct drm_fb_helper *helper = fbi->par;
+
+	module_put(helper->dev->driver->fops->owner);
+
+	return 0;
+}
+
+static struct fb_ops drm_fb_helper_fb_ops = {
+	.owner		= THIS_MODULE,
+	DRM_FB_HELPER_DEFAULT_OPS,
+	.fb_open	= drm_fb_helper_fb_open,
+	.fb_release	= drm_fb_helper_fb_release,
+	.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_mmap	= drm_fb_shmem_mmap,
+};
+
+/**
+ * drm_fb_shmem_fbdev_probe -
+ * @helper: fbdev emulation structure
+ * @sizes: fbdev description
+ * @fb_funcs: Framebuffer helper functions
+ *
+ * Drivers can use this in their &drm_fb_helper_funcs->fb_probe function.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ */
+int drm_fb_shmem_fbdev_probe(struct drm_fb_helper *helper,
+			     struct drm_fb_helper_surface_size *sizes,
+			     const struct drm_framebuffer_funcs *fb_funcs)
+{
+	struct drm_device *dev = helper->dev;
+	struct drm_mode_fb_cmd2 mode_cmd;
+	struct drm_gem_shmem_object *obj;
+	struct drm_gem_object *gem;
+	struct drm_fb_gem *fb_gem;
+	void *shadow = NULL;
+	size_t size;
+	int ret;
+
+	size = drm_fb_helper_mode_cmd(&mode_cmd, sizes);
+
+	obj = drm_gem_shmem_create(dev, size);
+	if (IS_ERR(obj))
+		return PTR_ERR(obj);
+
+	gem = &obj->base;
+	fb_gem = drm_fb_gem_alloc(dev, &mode_cmd, &gem, 1, fb_funcs);
+	if (IS_ERR(fb_gem)) {
+		dev_err(dev->dev, "Failed to allocate DRM framebuffer.\n");
+		drm_gem_object_put_unlocked(&obj->base);
+		return PTR_ERR(fb_gem);
+	}
+
+	ret = drm_gem_shmem_vmap(obj);
+	if (ret)
+		goto error;
+
+	if (fb_funcs->dirty) {
+		shadow = vzalloc(size);
+		if (!shadow) {
+			ret = -ENOMEM;
+			goto error;
+		}
+		helper->defio_vaddr = obj->vaddr;
+	}
+
+	ret = drm_fb_helper_simple_fb_probe(helper, sizes, &fb_gem->base,
+					    &drm_fb_helper_fb_ops,
+					    shadow ? shadow : obj->vaddr, 0,
+					    size);
+	if (ret < 0)
+		goto error;
+
+	return 0;
+
+error:
+	vfree(shadow);
+	drm_framebuffer_remove(&fb_gem->base);
+
+	return ret;
+}
+EXPORT_SYMBOL(drm_fb_shmem_fbdev_probe);
diff --git a/include/drm/drm_fb_shmem_helper.h b/include/drm/drm_fb_shmem_helper.h
new file mode 100644
index 0000000..5c57131
--- /dev/null
+++ b/include/drm/drm_fb_shmem_helper.h
@@ -0,0 +1,18 @@ 
+#ifndef __DRM_FB_SHMEM_HELPER_H__
+#define __DRM_FB_SHMEM_HELPER_H__
+
+struct drm_fb_helper_surface_size;
+struct drm_framebuffer_funcs;
+struct drm_fb_helper;
+
+int drm_fb_shmem_fbdev_probe(struct drm_fb_helper *helper,
+			     struct drm_fb_helper_surface_size *sizes,
+			     const struct drm_framebuffer_funcs *fb_funcs);
+
+#ifdef CONFIG_DEBUG_FS
+struct seq_file;
+
+int drm_fb_shmem_debugfs_show(struct seq_file *m, void *arg);
+#endif
+
+#endif