All of lore.kernel.org
 help / color / mirror / Atom feed
From: Thomas Zimmermann <tzimmermann@suse.de>
To: javierm@redhat.com, maarten.lankhorst@linux.intel.com,
	mripard@kernel.org, airlied@gmail.com, daniel@ffwll.ch,
	andrew@aj.id.au, laurentiu.palcu@oss.nxp.com,
	l.stach@pengutronix.de, shawnguo@kernel.org,
	s.hauer@pengutronix.de, kernel@pengutronix.de,
	festevam@gmail.com, linux-imx@nxp.com, p.zabel@pengutronix.de,
	anitha.chrisanthus@intel.com, edmund.j.dea@intel.com,
	khilman@baylibre.com, jbrunet@baylibre.com,
	martin.blumenstingl@googlemail.com, alain.volmat@foss.st.com,
	yannick.fertre@foss.st.com, raphael.gallais-pou@foss.st.com,
	philippe.cornu@foss.st.com, mcoquelin.stm32@gmail.com,
	alexandre.torgue@foss.st.com, jernej.skrabec@gmail.com,
	samuel@sholland.org, jyri.sarha@iki.fi, tomba@kernel.org,
	linus.walleij@linaro.org, hyun.kwon@xilinx.com,
	laurent.pinchart@ideasonboard.com
Cc: dri-devel@lists.freedesktop.org, linux-aspeed@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org,
	linux-amlogic@lists.infradead.org,
	linux-stm32@st-md-mailman.stormreply.com,
	linux-sunxi@lists.linux.dev,
	Thomas Zimmermann <tzimmermann@suse.de>
Subject: [PATCH 01/22] drm/fbdev-dma: Implement fbdev emulation for GEM DMA helpers
Date: Wed,  1 Mar 2023 16:30:40 +0100	[thread overview]
Message-ID: <20230301153101.4282-2-tzimmermann@suse.de> (raw)
In-Reply-To: <20230301153101.4282-1-tzimmermann@suse.de>

Implement fbdev emulation that is optimized for drivers that use
DMA helpers. The buffers may no tbe moveable, may not require damage
handling and have to be located in system memory. This allows fbdev
emulation to operate directly on the buffer and mmap it to userspace.

Besides those constraints, the emulation works like in the generic
code. As an internal DRM client provides, it receives hotplug, restore
and unregister events. The DRM client is independent from the fbdev
probing, which runs on the first successful hotplug event.

The emulation is part of the DMA helper module and not build unless
DMA helpers and fbdev emulation has been configured.

Tested with vc4.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/Makefile        |   1 +
 drivers/gpu/drm/drm_fbdev_dma.c | 275 ++++++++++++++++++++++++++++++++
 include/drm/drm_fbdev_dma.h     |  15 ++
 3 files changed, 291 insertions(+)
 create mode 100644 drivers/gpu/drm/drm_fbdev_dma.c
 create mode 100644 include/drm/drm_fbdev_dma.h

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index ab4460fcd63f..0d53d0c265f8 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
 obj-$(CONFIG_DRM_BUDDY) += drm_buddy.o
 
 drm_dma_helper-y := drm_gem_dma_helper.o
+drm_dma_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fbdev_dma.o
 drm_dma_helper-$(CONFIG_DRM_KMS_HELPER) += drm_fb_dma_helper.o
 obj-$(CONFIG_DRM_GEM_DMA_HELPER) += drm_dma_helper.o
 
diff --git a/drivers/gpu/drm/drm_fbdev_dma.c b/drivers/gpu/drm/drm_fbdev_dma.c
new file mode 100644
index 000000000000..cf553ac12a0f
--- /dev/null
+++ b/drivers/gpu/drm/drm_fbdev_dma.c
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: MIT
+
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_gem_dma_helper.h>
+
+#include <drm/drm_fbdev_dma.h>
+
+/*
+ * struct fb_ops
+ */
+
+static int drm_fbdev_dma_fb_open(struct fb_info *info, int user)
+{
+	struct drm_fb_helper *fb_helper = info->par;
+
+	/* No need to take a ref for fbcon because it unbinds on unregister */
+	if (user && !try_module_get(fb_helper->dev->driver->fops->owner))
+		return -ENODEV;
+
+	return 0;
+}
+
+static int drm_fbdev_dma_fb_release(struct fb_info *info, int user)
+{
+	struct drm_fb_helper *fb_helper = info->par;
+
+	if (user)
+		module_put(fb_helper->dev->driver->fops->owner);
+
+	return 0;
+}
+
+static void drm_fbdev_dma_fb_destroy(struct fb_info *info)
+{
+	struct drm_fb_helper *fb_helper = info->par;
+
+	if (!fb_helper->dev)
+		return;
+
+	drm_fb_helper_fini(fb_helper);
+
+	drm_client_buffer_vunmap(fb_helper->buffer);
+	drm_client_framebuffer_delete(fb_helper->buffer);
+	drm_client_release(&fb_helper->client);
+	drm_fb_helper_unprepare(fb_helper);
+	kfree(fb_helper);
+}
+
+static int drm_fbdev_dma_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+	struct drm_fb_helper *fb_helper = info->par;
+	struct drm_device *dev = fb_helper->dev;
+
+	if (drm_WARN_ON_ONCE(dev, !fb_helper->dev->driver->gem_prime_mmap))
+		return -ENODEV;
+
+	return fb_helper->dev->driver->gem_prime_mmap(fb_helper->buffer->gem, vma);
+}
+
+static const struct fb_ops drm_fbdev_dma_fb_ops = {
+	.owner = THIS_MODULE,
+	.fb_open = drm_fbdev_dma_fb_open,
+	.fb_release = drm_fbdev_dma_fb_release,
+	.fb_read = drm_fb_helper_sys_read,
+	.fb_write = drm_fb_helper_sys_write,
+	DRM_FB_HELPER_DEFAULT_OPS,
+	.fb_fillrect = drm_fb_helper_sys_fillrect,
+	.fb_copyarea = drm_fb_helper_sys_copyarea,
+	.fb_imageblit = drm_fb_helper_sys_imageblit,
+	.fb_destroy = drm_fbdev_dma_fb_destroy,
+	.fb_mmap = drm_fbdev_dma_fb_mmap,
+};
+
+/*
+ * struct drm_fb_helper
+ */
+
+static int drm_fbdev_dma_helper_fb_probe(struct drm_fb_helper *fb_helper,
+					 struct drm_fb_helper_surface_size *sizes)
+{
+	struct drm_client_dev *client = &fb_helper->client;
+	struct drm_device *dev = fb_helper->dev;
+	struct drm_client_buffer *buffer;
+	struct drm_gem_dma_object *dma_obj;
+	struct drm_framebuffer *fb;
+	struct fb_info *info;
+	u32 format;
+	struct iosys_map map;
+	int ret;
+
+	drm_dbg_kms(dev, "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, sizes->surface_width,
+					       sizes->surface_height, format);
+	if (IS_ERR(buffer))
+		return PTR_ERR(buffer);
+	dma_obj = to_drm_gem_dma_obj(buffer->gem);
+
+	fb = buffer->fb;
+	if (drm_WARN_ON(dev, fb->funcs->dirty)) {
+		ret = -ENODEV; /* damage handling not supported; use generic emulation */
+		goto err_drm_client_buffer_delete;
+	}
+
+	ret = drm_client_buffer_vmap(buffer, &map);
+	if (ret) {
+		goto err_drm_client_buffer_delete;
+	} else if (drm_WARN_ON(dev, map.is_iomem)) {
+		ret = -ENODEV; /* I/O memory not supported; use generic emulation */
+		goto err_drm_client_buffer_delete;
+	}
+
+	fb_helper->buffer = buffer;
+	fb_helper->fb = buffer->fb;
+
+	info = drm_fb_helper_alloc_info(fb_helper);
+	if (IS_ERR(info)) {
+		ret = PTR_ERR(info);
+		goto err_drm_client_buffer_vunmap;
+	}
+
+	drm_fb_helper_fill_info(info, fb_helper, sizes);
+
+	info->fbops = &drm_fbdev_dma_fb_ops;
+	info->flags = FBINFO_DEFAULT;
+
+	/* screen */
+	info->flags |= FBINFO_VIRTFB; /* system memory */
+	if (dma_obj->map_noncoherent)
+		info->flags |= FBINFO_READS_FAST; /* signal caching */
+	info->screen_size = sizes->surface_height * fb->pitches[0];
+	info->screen_buffer = map.vaddr;
+	info->fix.smem_len = info->screen_size;
+
+#if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
+	/*
+	 * Shamelessly leak the physical address to user-space.
+	 */
+	if (fb_helper->hint_leak_smem_start && !info->fix.smem_start)
+		info->fix.smem_start = page_to_phys(virt_to_page(info->screen_buffer));
+#endif
+
+	return 0;
+
+err_drm_client_buffer_vunmap:
+	fb_helper->fb = NULL;
+	fb_helper->buffer = NULL;
+	drm_client_buffer_vunmap(buffer);
+err_drm_client_buffer_delete:
+	drm_client_framebuffer_delete(buffer);
+	return ret;
+}
+
+static const struct drm_fb_helper_funcs drm_fbdev_dma_helper_funcs = {
+	.fb_probe = drm_fbdev_dma_helper_fb_probe,
+};
+
+/*
+ * struct drm_client_funcs
+ */
+
+static void drm_fbdev_dma_client_unregister(struct drm_client_dev *client)
+{
+	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
+
+	if (fb_helper->info) {
+		drm_fb_helper_unregister_info(fb_helper);
+	} else {
+		drm_client_release(&fb_helper->client);
+		drm_fb_helper_unprepare(fb_helper);
+		kfree(fb_helper);
+	}
+}
+
+static int drm_fbdev_dma_client_restore(struct drm_client_dev *client)
+{
+	drm_fb_helper_lastclose(client->dev);
+
+	return 0;
+}
+
+static int drm_fbdev_dma_client_hotplug(struct drm_client_dev *client)
+{
+	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
+	struct drm_device *dev = client->dev;
+	int ret;
+
+	if (dev->fb_helper)
+		return drm_fb_helper_hotplug_event(dev->fb_helper);
+
+	ret = drm_fb_helper_init(dev, fb_helper);
+	if (ret)
+		goto err_drm_err;
+
+	if (!drm_drv_uses_atomic_modeset(dev))
+		drm_helper_disable_unused_functions(dev);
+
+	ret = drm_fb_helper_initial_config(fb_helper);
+	if (ret)
+		goto err_drm_fb_helper_fini;
+
+	return 0;
+
+err_drm_fb_helper_fini:
+	drm_fb_helper_fini(fb_helper);
+err_drm_err:
+	drm_err(dev, "fbdev-dma: Failed to setup generic emulation (ret=%d)\n", ret);
+	return ret;
+}
+
+static const struct drm_client_funcs drm_fbdev_dma_client_funcs = {
+	.owner		= THIS_MODULE,
+	.unregister	= drm_fbdev_dma_client_unregister,
+	.restore	= drm_fbdev_dma_client_restore,
+	.hotplug	= drm_fbdev_dma_client_hotplug,
+};
+
+/**
+ * drm_fbdev_dma_setup() - Setup fbdev emulation for GEM DMA helpers
+ * @dev: DRM device
+ * @preferred_bpp: Preferred bits per pixel for the device.
+ *                 @dev->mode_config.preferred_depth is used if this is zero.
+ *
+ * This function sets up fbdev emulation for GEM DMA drivers that support
+ * dumb buffers with a virtual address and that can be mmap'ed.
+ * drm_fbdev_dma_setup() shall be called after the DRM driver registered
+ * the new DRM device with drm_dev_register().
+ *
+ * Restore, hotplug events and teardown are all taken care of. Drivers that do
+ * suspend/resume need to call drm_fb_helper_set_suspend_unlocked() themselves.
+ * Simple drivers might use drm_mode_config_helper_suspend().
+ *
+ * This function is safe to call even when there are no connectors present.
+ * Setup will be retried on the next hotplug event.
+ *
+ * The fbdev is destroyed by drm_dev_unregister().
+ */
+void drm_fbdev_dma_setup(struct drm_device *dev, unsigned int preferred_bpp)
+{
+	struct drm_fb_helper *fb_helper;
+	int ret;
+
+	drm_WARN(dev, !dev->registered, "Device has not been registered.\n");
+	drm_WARN(dev, dev->fb_helper, "fb_helper is already set!\n");
+
+	fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL);
+	if (!fb_helper)
+		return;
+	drm_fb_helper_prepare(dev, fb_helper, preferred_bpp, &drm_fbdev_dma_helper_funcs);
+
+	ret = drm_client_init(dev, &fb_helper->client, "fbdev", &drm_fbdev_dma_client_funcs);
+	if (ret) {
+		drm_err(dev, "Failed to register client: %d\n", ret);
+		goto err_drm_client_init;
+	}
+
+	ret = drm_fbdev_dma_client_hotplug(&fb_helper->client);
+	if (ret)
+		drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
+
+	drm_client_register(&fb_helper->client);
+
+	return;
+
+err_drm_client_init:
+	drm_fb_helper_unprepare(fb_helper);
+	kfree(fb_helper);
+}
+EXPORT_SYMBOL(drm_fbdev_dma_setup);
diff --git a/include/drm/drm_fbdev_dma.h b/include/drm/drm_fbdev_dma.h
new file mode 100644
index 000000000000..2da7ee784133
--- /dev/null
+++ b/include/drm/drm_fbdev_dma.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: MIT */
+
+#ifndef DRM_FBDEV_DMA_H
+#define DRM_FBDEV_DMA_H
+
+struct drm_device;
+
+#ifdef CONFIG_DRM_FBDEV_EMULATION
+void drm_fbdev_dma_setup(struct drm_device *dev, unsigned int preferred_bpp);
+#else
+static inline void drm_fbdev_dma_setup(struct drm_device *dev, unsigned int preferred_bpp)
+{ }
+#endif
+
+#endif
-- 
2.39.2


WARNING: multiple messages have this Message-ID (diff)
From: Thomas Zimmermann <tzimmermann@suse.de>
To: javierm@redhat.com, maarten.lankhorst@linux.intel.com,
	mripard@kernel.org, airlied@gmail.com, daniel@ffwll.ch,
	andrew@aj.id.au, laurentiu.palcu@oss.nxp.com,
	l.stach@pengutronix.de, shawnguo@kernel.org,
	s.hauer@pengutronix.de, kernel@pengutronix.de,
	festevam@gmail.com, linux-imx@nxp.com, p.zabel@pengutronix.de,
	anitha.chrisanthus@intel.com, edmund.j.dea@intel.com,
	khilman@baylibre.com, jbrunet@baylibre.com,
	martin.blumenstingl@googlemail.com, alain.volmat@foss.st.com,
	yannick.fertre@foss.st.com, raphael.gallais-pou@foss.st.com,
	philippe.cornu@foss.st.com, mcoquelin.stm32@gmail.com,
	alexandre.torgue@foss.st.com, jernej.skrabec@gmail.com,
	samuel@sholland.org, jyri.sarha@iki.fi, tomba@kernel.org,
	linus.walleij@linaro.org, hyun.kwon@xilinx.com,
	laurent.pinchart@ideasonboard.com
Cc: linux-aspeed@lists.ozlabs.org, dri-devel@lists.freedesktop.org,
	linux-stm32@st-md-mailman.stormreply.com,
	Thomas Zimmermann <tzimmermann@suse.de>,
	linux-amlogic@lists.infradead.org, linux-sunxi@lists.linux.dev,
	linux-arm-kernel@lists.infradead.org
Subject: [PATCH 01/22] drm/fbdev-dma: Implement fbdev emulation for GEM DMA helpers
Date: Wed,  1 Mar 2023 16:30:40 +0100	[thread overview]
Message-ID: <20230301153101.4282-2-tzimmermann@suse.de> (raw)
In-Reply-To: <20230301153101.4282-1-tzimmermann@suse.de>

Implement fbdev emulation that is optimized for drivers that use
DMA helpers. The buffers may no tbe moveable, may not require damage
handling and have to be located in system memory. This allows fbdev
emulation to operate directly on the buffer and mmap it to userspace.

Besides those constraints, the emulation works like in the generic
code. As an internal DRM client provides, it receives hotplug, restore
and unregister events. The DRM client is independent from the fbdev
probing, which runs on the first successful hotplug event.

The emulation is part of the DMA helper module and not build unless
DMA helpers and fbdev emulation has been configured.

Tested with vc4.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/Makefile        |   1 +
 drivers/gpu/drm/drm_fbdev_dma.c | 275 ++++++++++++++++++++++++++++++++
 include/drm/drm_fbdev_dma.h     |  15 ++
 3 files changed, 291 insertions(+)
 create mode 100644 drivers/gpu/drm/drm_fbdev_dma.c
 create mode 100644 include/drm/drm_fbdev_dma.h

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index ab4460fcd63f..0d53d0c265f8 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
 obj-$(CONFIG_DRM_BUDDY) += drm_buddy.o
 
 drm_dma_helper-y := drm_gem_dma_helper.o
+drm_dma_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fbdev_dma.o
 drm_dma_helper-$(CONFIG_DRM_KMS_HELPER) += drm_fb_dma_helper.o
 obj-$(CONFIG_DRM_GEM_DMA_HELPER) += drm_dma_helper.o
 
diff --git a/drivers/gpu/drm/drm_fbdev_dma.c b/drivers/gpu/drm/drm_fbdev_dma.c
new file mode 100644
index 000000000000..cf553ac12a0f
--- /dev/null
+++ b/drivers/gpu/drm/drm_fbdev_dma.c
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: MIT
+
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_gem_dma_helper.h>
+
+#include <drm/drm_fbdev_dma.h>
+
+/*
+ * struct fb_ops
+ */
+
+static int drm_fbdev_dma_fb_open(struct fb_info *info, int user)
+{
+	struct drm_fb_helper *fb_helper = info->par;
+
+	/* No need to take a ref for fbcon because it unbinds on unregister */
+	if (user && !try_module_get(fb_helper->dev->driver->fops->owner))
+		return -ENODEV;
+
+	return 0;
+}
+
+static int drm_fbdev_dma_fb_release(struct fb_info *info, int user)
+{
+	struct drm_fb_helper *fb_helper = info->par;
+
+	if (user)
+		module_put(fb_helper->dev->driver->fops->owner);
+
+	return 0;
+}
+
+static void drm_fbdev_dma_fb_destroy(struct fb_info *info)
+{
+	struct drm_fb_helper *fb_helper = info->par;
+
+	if (!fb_helper->dev)
+		return;
+
+	drm_fb_helper_fini(fb_helper);
+
+	drm_client_buffer_vunmap(fb_helper->buffer);
+	drm_client_framebuffer_delete(fb_helper->buffer);
+	drm_client_release(&fb_helper->client);
+	drm_fb_helper_unprepare(fb_helper);
+	kfree(fb_helper);
+}
+
+static int drm_fbdev_dma_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+	struct drm_fb_helper *fb_helper = info->par;
+	struct drm_device *dev = fb_helper->dev;
+
+	if (drm_WARN_ON_ONCE(dev, !fb_helper->dev->driver->gem_prime_mmap))
+		return -ENODEV;
+
+	return fb_helper->dev->driver->gem_prime_mmap(fb_helper->buffer->gem, vma);
+}
+
+static const struct fb_ops drm_fbdev_dma_fb_ops = {
+	.owner = THIS_MODULE,
+	.fb_open = drm_fbdev_dma_fb_open,
+	.fb_release = drm_fbdev_dma_fb_release,
+	.fb_read = drm_fb_helper_sys_read,
+	.fb_write = drm_fb_helper_sys_write,
+	DRM_FB_HELPER_DEFAULT_OPS,
+	.fb_fillrect = drm_fb_helper_sys_fillrect,
+	.fb_copyarea = drm_fb_helper_sys_copyarea,
+	.fb_imageblit = drm_fb_helper_sys_imageblit,
+	.fb_destroy = drm_fbdev_dma_fb_destroy,
+	.fb_mmap = drm_fbdev_dma_fb_mmap,
+};
+
+/*
+ * struct drm_fb_helper
+ */
+
+static int drm_fbdev_dma_helper_fb_probe(struct drm_fb_helper *fb_helper,
+					 struct drm_fb_helper_surface_size *sizes)
+{
+	struct drm_client_dev *client = &fb_helper->client;
+	struct drm_device *dev = fb_helper->dev;
+	struct drm_client_buffer *buffer;
+	struct drm_gem_dma_object *dma_obj;
+	struct drm_framebuffer *fb;
+	struct fb_info *info;
+	u32 format;
+	struct iosys_map map;
+	int ret;
+
+	drm_dbg_kms(dev, "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, sizes->surface_width,
+					       sizes->surface_height, format);
+	if (IS_ERR(buffer))
+		return PTR_ERR(buffer);
+	dma_obj = to_drm_gem_dma_obj(buffer->gem);
+
+	fb = buffer->fb;
+	if (drm_WARN_ON(dev, fb->funcs->dirty)) {
+		ret = -ENODEV; /* damage handling not supported; use generic emulation */
+		goto err_drm_client_buffer_delete;
+	}
+
+	ret = drm_client_buffer_vmap(buffer, &map);
+	if (ret) {
+		goto err_drm_client_buffer_delete;
+	} else if (drm_WARN_ON(dev, map.is_iomem)) {
+		ret = -ENODEV; /* I/O memory not supported; use generic emulation */
+		goto err_drm_client_buffer_delete;
+	}
+
+	fb_helper->buffer = buffer;
+	fb_helper->fb = buffer->fb;
+
+	info = drm_fb_helper_alloc_info(fb_helper);
+	if (IS_ERR(info)) {
+		ret = PTR_ERR(info);
+		goto err_drm_client_buffer_vunmap;
+	}
+
+	drm_fb_helper_fill_info(info, fb_helper, sizes);
+
+	info->fbops = &drm_fbdev_dma_fb_ops;
+	info->flags = FBINFO_DEFAULT;
+
+	/* screen */
+	info->flags |= FBINFO_VIRTFB; /* system memory */
+	if (dma_obj->map_noncoherent)
+		info->flags |= FBINFO_READS_FAST; /* signal caching */
+	info->screen_size = sizes->surface_height * fb->pitches[0];
+	info->screen_buffer = map.vaddr;
+	info->fix.smem_len = info->screen_size;
+
+#if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
+	/*
+	 * Shamelessly leak the physical address to user-space.
+	 */
+	if (fb_helper->hint_leak_smem_start && !info->fix.smem_start)
+		info->fix.smem_start = page_to_phys(virt_to_page(info->screen_buffer));
+#endif
+
+	return 0;
+
+err_drm_client_buffer_vunmap:
+	fb_helper->fb = NULL;
+	fb_helper->buffer = NULL;
+	drm_client_buffer_vunmap(buffer);
+err_drm_client_buffer_delete:
+	drm_client_framebuffer_delete(buffer);
+	return ret;
+}
+
+static const struct drm_fb_helper_funcs drm_fbdev_dma_helper_funcs = {
+	.fb_probe = drm_fbdev_dma_helper_fb_probe,
+};
+
+/*
+ * struct drm_client_funcs
+ */
+
+static void drm_fbdev_dma_client_unregister(struct drm_client_dev *client)
+{
+	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
+
+	if (fb_helper->info) {
+		drm_fb_helper_unregister_info(fb_helper);
+	} else {
+		drm_client_release(&fb_helper->client);
+		drm_fb_helper_unprepare(fb_helper);
+		kfree(fb_helper);
+	}
+}
+
+static int drm_fbdev_dma_client_restore(struct drm_client_dev *client)
+{
+	drm_fb_helper_lastclose(client->dev);
+
+	return 0;
+}
+
+static int drm_fbdev_dma_client_hotplug(struct drm_client_dev *client)
+{
+	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
+	struct drm_device *dev = client->dev;
+	int ret;
+
+	if (dev->fb_helper)
+		return drm_fb_helper_hotplug_event(dev->fb_helper);
+
+	ret = drm_fb_helper_init(dev, fb_helper);
+	if (ret)
+		goto err_drm_err;
+
+	if (!drm_drv_uses_atomic_modeset(dev))
+		drm_helper_disable_unused_functions(dev);
+
+	ret = drm_fb_helper_initial_config(fb_helper);
+	if (ret)
+		goto err_drm_fb_helper_fini;
+
+	return 0;
+
+err_drm_fb_helper_fini:
+	drm_fb_helper_fini(fb_helper);
+err_drm_err:
+	drm_err(dev, "fbdev-dma: Failed to setup generic emulation (ret=%d)\n", ret);
+	return ret;
+}
+
+static const struct drm_client_funcs drm_fbdev_dma_client_funcs = {
+	.owner		= THIS_MODULE,
+	.unregister	= drm_fbdev_dma_client_unregister,
+	.restore	= drm_fbdev_dma_client_restore,
+	.hotplug	= drm_fbdev_dma_client_hotplug,
+};
+
+/**
+ * drm_fbdev_dma_setup() - Setup fbdev emulation for GEM DMA helpers
+ * @dev: DRM device
+ * @preferred_bpp: Preferred bits per pixel for the device.
+ *                 @dev->mode_config.preferred_depth is used if this is zero.
+ *
+ * This function sets up fbdev emulation for GEM DMA drivers that support
+ * dumb buffers with a virtual address and that can be mmap'ed.
+ * drm_fbdev_dma_setup() shall be called after the DRM driver registered
+ * the new DRM device with drm_dev_register().
+ *
+ * Restore, hotplug events and teardown are all taken care of. Drivers that do
+ * suspend/resume need to call drm_fb_helper_set_suspend_unlocked() themselves.
+ * Simple drivers might use drm_mode_config_helper_suspend().
+ *
+ * This function is safe to call even when there are no connectors present.
+ * Setup will be retried on the next hotplug event.
+ *
+ * The fbdev is destroyed by drm_dev_unregister().
+ */
+void drm_fbdev_dma_setup(struct drm_device *dev, unsigned int preferred_bpp)
+{
+	struct drm_fb_helper *fb_helper;
+	int ret;
+
+	drm_WARN(dev, !dev->registered, "Device has not been registered.\n");
+	drm_WARN(dev, dev->fb_helper, "fb_helper is already set!\n");
+
+	fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL);
+	if (!fb_helper)
+		return;
+	drm_fb_helper_prepare(dev, fb_helper, preferred_bpp, &drm_fbdev_dma_helper_funcs);
+
+	ret = drm_client_init(dev, &fb_helper->client, "fbdev", &drm_fbdev_dma_client_funcs);
+	if (ret) {
+		drm_err(dev, "Failed to register client: %d\n", ret);
+		goto err_drm_client_init;
+	}
+
+	ret = drm_fbdev_dma_client_hotplug(&fb_helper->client);
+	if (ret)
+		drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
+
+	drm_client_register(&fb_helper->client);
+
+	return;
+
+err_drm_client_init:
+	drm_fb_helper_unprepare(fb_helper);
+	kfree(fb_helper);
+}
+EXPORT_SYMBOL(drm_fbdev_dma_setup);
diff --git a/include/drm/drm_fbdev_dma.h b/include/drm/drm_fbdev_dma.h
new file mode 100644
index 000000000000..2da7ee784133
--- /dev/null
+++ b/include/drm/drm_fbdev_dma.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: MIT */
+
+#ifndef DRM_FBDEV_DMA_H
+#define DRM_FBDEV_DMA_H
+
+struct drm_device;
+
+#ifdef CONFIG_DRM_FBDEV_EMULATION
+void drm_fbdev_dma_setup(struct drm_device *dev, unsigned int preferred_bpp);
+#else
+static inline void drm_fbdev_dma_setup(struct drm_device *dev, unsigned int preferred_bpp)
+{ }
+#endif
+
+#endif
-- 
2.39.2


WARNING: multiple messages have this Message-ID (diff)
From: Thomas Zimmermann <tzimmermann@suse.de>
To: javierm@redhat.com, maarten.lankhorst@linux.intel.com,
	mripard@kernel.org, airlied@gmail.com, daniel@ffwll.ch,
	andrew@aj.id.au, laurentiu.palcu@oss.nxp.com,
	l.stach@pengutronix.de, shawnguo@kernel.org,
	s.hauer@pengutronix.de, kernel@pengutronix.de,
	festevam@gmail.com, linux-imx@nxp.com, p.zabel@pengutronix.de,
	anitha.chrisanthus@intel.com, edmund.j.dea@intel.com,
	khilman@baylibre.com, jbrunet@baylibre.com,
	martin.blumenstingl@googlemail.com, alain.volmat@foss.st.com,
	yannick.fertre@foss.st.com, raphael.gallais-pou@foss.st.com,
	philippe.cornu@foss.st.com, mcoquelin.stm32@gmail.com,
	alexandre.torgue@foss.st.com, jernej.skrabec@gmail.com,
	samuel@sholland.org, jyri.sarha@iki.fi, tomba@kernel.org,
	linus.walleij@linaro.org, hyun.kwon@xilinx.com,
	laurent.pinchart@ideasonboard.com
Cc: dri-devel@lists.freedesktop.org, linux-aspeed@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org,
	linux-amlogic@lists.infradead.org,
	linux-stm32@st-md-mailman.stormreply.com,
	linux-sunxi@lists.linux.dev,
	Thomas Zimmermann <tzimmermann@suse.de>
Subject: [PATCH 01/22] drm/fbdev-dma: Implement fbdev emulation for GEM DMA helpers
Date: Wed,  1 Mar 2023 16:30:40 +0100	[thread overview]
Message-ID: <20230301153101.4282-2-tzimmermann@suse.de> (raw)
In-Reply-To: <20230301153101.4282-1-tzimmermann@suse.de>

Implement fbdev emulation that is optimized for drivers that use
DMA helpers. The buffers may no tbe moveable, may not require damage
handling and have to be located in system memory. This allows fbdev
emulation to operate directly on the buffer and mmap it to userspace.

Besides those constraints, the emulation works like in the generic
code. As an internal DRM client provides, it receives hotplug, restore
and unregister events. The DRM client is independent from the fbdev
probing, which runs on the first successful hotplug event.

The emulation is part of the DMA helper module and not build unless
DMA helpers and fbdev emulation has been configured.

Tested with vc4.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/Makefile        |   1 +
 drivers/gpu/drm/drm_fbdev_dma.c | 275 ++++++++++++++++++++++++++++++++
 include/drm/drm_fbdev_dma.h     |  15 ++
 3 files changed, 291 insertions(+)
 create mode 100644 drivers/gpu/drm/drm_fbdev_dma.c
 create mode 100644 include/drm/drm_fbdev_dma.h

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index ab4460fcd63f..0d53d0c265f8 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
 obj-$(CONFIG_DRM_BUDDY) += drm_buddy.o
 
 drm_dma_helper-y := drm_gem_dma_helper.o
+drm_dma_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fbdev_dma.o
 drm_dma_helper-$(CONFIG_DRM_KMS_HELPER) += drm_fb_dma_helper.o
 obj-$(CONFIG_DRM_GEM_DMA_HELPER) += drm_dma_helper.o
 
diff --git a/drivers/gpu/drm/drm_fbdev_dma.c b/drivers/gpu/drm/drm_fbdev_dma.c
new file mode 100644
index 000000000000..cf553ac12a0f
--- /dev/null
+++ b/drivers/gpu/drm/drm_fbdev_dma.c
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: MIT
+
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_gem_dma_helper.h>
+
+#include <drm/drm_fbdev_dma.h>
+
+/*
+ * struct fb_ops
+ */
+
+static int drm_fbdev_dma_fb_open(struct fb_info *info, int user)
+{
+	struct drm_fb_helper *fb_helper = info->par;
+
+	/* No need to take a ref for fbcon because it unbinds on unregister */
+	if (user && !try_module_get(fb_helper->dev->driver->fops->owner))
+		return -ENODEV;
+
+	return 0;
+}
+
+static int drm_fbdev_dma_fb_release(struct fb_info *info, int user)
+{
+	struct drm_fb_helper *fb_helper = info->par;
+
+	if (user)
+		module_put(fb_helper->dev->driver->fops->owner);
+
+	return 0;
+}
+
+static void drm_fbdev_dma_fb_destroy(struct fb_info *info)
+{
+	struct drm_fb_helper *fb_helper = info->par;
+
+	if (!fb_helper->dev)
+		return;
+
+	drm_fb_helper_fini(fb_helper);
+
+	drm_client_buffer_vunmap(fb_helper->buffer);
+	drm_client_framebuffer_delete(fb_helper->buffer);
+	drm_client_release(&fb_helper->client);
+	drm_fb_helper_unprepare(fb_helper);
+	kfree(fb_helper);
+}
+
+static int drm_fbdev_dma_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+	struct drm_fb_helper *fb_helper = info->par;
+	struct drm_device *dev = fb_helper->dev;
+
+	if (drm_WARN_ON_ONCE(dev, !fb_helper->dev->driver->gem_prime_mmap))
+		return -ENODEV;
+
+	return fb_helper->dev->driver->gem_prime_mmap(fb_helper->buffer->gem, vma);
+}
+
+static const struct fb_ops drm_fbdev_dma_fb_ops = {
+	.owner = THIS_MODULE,
+	.fb_open = drm_fbdev_dma_fb_open,
+	.fb_release = drm_fbdev_dma_fb_release,
+	.fb_read = drm_fb_helper_sys_read,
+	.fb_write = drm_fb_helper_sys_write,
+	DRM_FB_HELPER_DEFAULT_OPS,
+	.fb_fillrect = drm_fb_helper_sys_fillrect,
+	.fb_copyarea = drm_fb_helper_sys_copyarea,
+	.fb_imageblit = drm_fb_helper_sys_imageblit,
+	.fb_destroy = drm_fbdev_dma_fb_destroy,
+	.fb_mmap = drm_fbdev_dma_fb_mmap,
+};
+
+/*
+ * struct drm_fb_helper
+ */
+
+static int drm_fbdev_dma_helper_fb_probe(struct drm_fb_helper *fb_helper,
+					 struct drm_fb_helper_surface_size *sizes)
+{
+	struct drm_client_dev *client = &fb_helper->client;
+	struct drm_device *dev = fb_helper->dev;
+	struct drm_client_buffer *buffer;
+	struct drm_gem_dma_object *dma_obj;
+	struct drm_framebuffer *fb;
+	struct fb_info *info;
+	u32 format;
+	struct iosys_map map;
+	int ret;
+
+	drm_dbg_kms(dev, "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, sizes->surface_width,
+					       sizes->surface_height, format);
+	if (IS_ERR(buffer))
+		return PTR_ERR(buffer);
+	dma_obj = to_drm_gem_dma_obj(buffer->gem);
+
+	fb = buffer->fb;
+	if (drm_WARN_ON(dev, fb->funcs->dirty)) {
+		ret = -ENODEV; /* damage handling not supported; use generic emulation */
+		goto err_drm_client_buffer_delete;
+	}
+
+	ret = drm_client_buffer_vmap(buffer, &map);
+	if (ret) {
+		goto err_drm_client_buffer_delete;
+	} else if (drm_WARN_ON(dev, map.is_iomem)) {
+		ret = -ENODEV; /* I/O memory not supported; use generic emulation */
+		goto err_drm_client_buffer_delete;
+	}
+
+	fb_helper->buffer = buffer;
+	fb_helper->fb = buffer->fb;
+
+	info = drm_fb_helper_alloc_info(fb_helper);
+	if (IS_ERR(info)) {
+		ret = PTR_ERR(info);
+		goto err_drm_client_buffer_vunmap;
+	}
+
+	drm_fb_helper_fill_info(info, fb_helper, sizes);
+
+	info->fbops = &drm_fbdev_dma_fb_ops;
+	info->flags = FBINFO_DEFAULT;
+
+	/* screen */
+	info->flags |= FBINFO_VIRTFB; /* system memory */
+	if (dma_obj->map_noncoherent)
+		info->flags |= FBINFO_READS_FAST; /* signal caching */
+	info->screen_size = sizes->surface_height * fb->pitches[0];
+	info->screen_buffer = map.vaddr;
+	info->fix.smem_len = info->screen_size;
+
+#if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
+	/*
+	 * Shamelessly leak the physical address to user-space.
+	 */
+	if (fb_helper->hint_leak_smem_start && !info->fix.smem_start)
+		info->fix.smem_start = page_to_phys(virt_to_page(info->screen_buffer));
+#endif
+
+	return 0;
+
+err_drm_client_buffer_vunmap:
+	fb_helper->fb = NULL;
+	fb_helper->buffer = NULL;
+	drm_client_buffer_vunmap(buffer);
+err_drm_client_buffer_delete:
+	drm_client_framebuffer_delete(buffer);
+	return ret;
+}
+
+static const struct drm_fb_helper_funcs drm_fbdev_dma_helper_funcs = {
+	.fb_probe = drm_fbdev_dma_helper_fb_probe,
+};
+
+/*
+ * struct drm_client_funcs
+ */
+
+static void drm_fbdev_dma_client_unregister(struct drm_client_dev *client)
+{
+	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
+
+	if (fb_helper->info) {
+		drm_fb_helper_unregister_info(fb_helper);
+	} else {
+		drm_client_release(&fb_helper->client);
+		drm_fb_helper_unprepare(fb_helper);
+		kfree(fb_helper);
+	}
+}
+
+static int drm_fbdev_dma_client_restore(struct drm_client_dev *client)
+{
+	drm_fb_helper_lastclose(client->dev);
+
+	return 0;
+}
+
+static int drm_fbdev_dma_client_hotplug(struct drm_client_dev *client)
+{
+	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
+	struct drm_device *dev = client->dev;
+	int ret;
+
+	if (dev->fb_helper)
+		return drm_fb_helper_hotplug_event(dev->fb_helper);
+
+	ret = drm_fb_helper_init(dev, fb_helper);
+	if (ret)
+		goto err_drm_err;
+
+	if (!drm_drv_uses_atomic_modeset(dev))
+		drm_helper_disable_unused_functions(dev);
+
+	ret = drm_fb_helper_initial_config(fb_helper);
+	if (ret)
+		goto err_drm_fb_helper_fini;
+
+	return 0;
+
+err_drm_fb_helper_fini:
+	drm_fb_helper_fini(fb_helper);
+err_drm_err:
+	drm_err(dev, "fbdev-dma: Failed to setup generic emulation (ret=%d)\n", ret);
+	return ret;
+}
+
+static const struct drm_client_funcs drm_fbdev_dma_client_funcs = {
+	.owner		= THIS_MODULE,
+	.unregister	= drm_fbdev_dma_client_unregister,
+	.restore	= drm_fbdev_dma_client_restore,
+	.hotplug	= drm_fbdev_dma_client_hotplug,
+};
+
+/**
+ * drm_fbdev_dma_setup() - Setup fbdev emulation for GEM DMA helpers
+ * @dev: DRM device
+ * @preferred_bpp: Preferred bits per pixel for the device.
+ *                 @dev->mode_config.preferred_depth is used if this is zero.
+ *
+ * This function sets up fbdev emulation for GEM DMA drivers that support
+ * dumb buffers with a virtual address and that can be mmap'ed.
+ * drm_fbdev_dma_setup() shall be called after the DRM driver registered
+ * the new DRM device with drm_dev_register().
+ *
+ * Restore, hotplug events and teardown are all taken care of. Drivers that do
+ * suspend/resume need to call drm_fb_helper_set_suspend_unlocked() themselves.
+ * Simple drivers might use drm_mode_config_helper_suspend().
+ *
+ * This function is safe to call even when there are no connectors present.
+ * Setup will be retried on the next hotplug event.
+ *
+ * The fbdev is destroyed by drm_dev_unregister().
+ */
+void drm_fbdev_dma_setup(struct drm_device *dev, unsigned int preferred_bpp)
+{
+	struct drm_fb_helper *fb_helper;
+	int ret;
+
+	drm_WARN(dev, !dev->registered, "Device has not been registered.\n");
+	drm_WARN(dev, dev->fb_helper, "fb_helper is already set!\n");
+
+	fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL);
+	if (!fb_helper)
+		return;
+	drm_fb_helper_prepare(dev, fb_helper, preferred_bpp, &drm_fbdev_dma_helper_funcs);
+
+	ret = drm_client_init(dev, &fb_helper->client, "fbdev", &drm_fbdev_dma_client_funcs);
+	if (ret) {
+		drm_err(dev, "Failed to register client: %d\n", ret);
+		goto err_drm_client_init;
+	}
+
+	ret = drm_fbdev_dma_client_hotplug(&fb_helper->client);
+	if (ret)
+		drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
+
+	drm_client_register(&fb_helper->client);
+
+	return;
+
+err_drm_client_init:
+	drm_fb_helper_unprepare(fb_helper);
+	kfree(fb_helper);
+}
+EXPORT_SYMBOL(drm_fbdev_dma_setup);
diff --git a/include/drm/drm_fbdev_dma.h b/include/drm/drm_fbdev_dma.h
new file mode 100644
index 000000000000..2da7ee784133
--- /dev/null
+++ b/include/drm/drm_fbdev_dma.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: MIT */
+
+#ifndef DRM_FBDEV_DMA_H
+#define DRM_FBDEV_DMA_H
+
+struct drm_device;
+
+#ifdef CONFIG_DRM_FBDEV_EMULATION
+void drm_fbdev_dma_setup(struct drm_device *dev, unsigned int preferred_bpp);
+#else
+static inline void drm_fbdev_dma_setup(struct drm_device *dev, unsigned int preferred_bpp)
+{ }
+#endif
+
+#endif
-- 
2.39.2


_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

WARNING: multiple messages have this Message-ID (diff)
From: Thomas Zimmermann <tzimmermann@suse.de>
To: javierm@redhat.com, maarten.lankhorst@linux.intel.com,
	mripard@kernel.org, airlied@gmail.com, daniel@ffwll.ch,
	andrew@aj.id.au, laurentiu.palcu@oss.nxp.com,
	l.stach@pengutronix.de, shawnguo@kernel.org,
	s.hauer@pengutronix.de, kernel@pengutronix.de,
	festevam@gmail.com, linux-imx@nxp.com, p.zabel@pengutronix.de,
	anitha.chrisanthus@intel.com, edmund.j.dea@intel.com,
	khilman@baylibre.com, jbrunet@baylibre.com,
	martin.blumenstingl@googlemail.com, alain.volmat@foss.st.com,
	yannick.fertre@foss.st.com, raphael.gallais-pou@foss.st.com,
	philippe.cornu@foss.st.com, mcoquelin.stm32@gmail.com,
	alexandre.torgue@foss.st.com, jernej.skrabec@gmail.com,
	samuel@sholland.org, jyri.sarha@iki.fi, tomba@kernel.org,
	linus.walleij@linaro.org, hyun.kwon@xilinx.com,
	laurent.pinchart@ideasonboard.com
Cc: dri-devel@lists.freedesktop.org, linux-aspeed@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org,
	linux-amlogic@lists.infradead.org,
	linux-stm32@st-md-mailman.stormreply.com,
	linux-sunxi@lists.linux.dev,
	Thomas Zimmermann <tzimmermann@suse.de>
Subject: [PATCH 01/22] drm/fbdev-dma: Implement fbdev emulation for GEM DMA helpers
Date: Wed,  1 Mar 2023 16:30:40 +0100	[thread overview]
Message-ID: <20230301153101.4282-2-tzimmermann@suse.de> (raw)
In-Reply-To: <20230301153101.4282-1-tzimmermann@suse.de>

Implement fbdev emulation that is optimized for drivers that use
DMA helpers. The buffers may no tbe moveable, may not require damage
handling and have to be located in system memory. This allows fbdev
emulation to operate directly on the buffer and mmap it to userspace.

Besides those constraints, the emulation works like in the generic
code. As an internal DRM client provides, it receives hotplug, restore
and unregister events. The DRM client is independent from the fbdev
probing, which runs on the first successful hotplug event.

The emulation is part of the DMA helper module and not build unless
DMA helpers and fbdev emulation has been configured.

Tested with vc4.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/Makefile        |   1 +
 drivers/gpu/drm/drm_fbdev_dma.c | 275 ++++++++++++++++++++++++++++++++
 include/drm/drm_fbdev_dma.h     |  15 ++
 3 files changed, 291 insertions(+)
 create mode 100644 drivers/gpu/drm/drm_fbdev_dma.c
 create mode 100644 include/drm/drm_fbdev_dma.h

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index ab4460fcd63f..0d53d0c265f8 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
 obj-$(CONFIG_DRM_BUDDY) += drm_buddy.o
 
 drm_dma_helper-y := drm_gem_dma_helper.o
+drm_dma_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fbdev_dma.o
 drm_dma_helper-$(CONFIG_DRM_KMS_HELPER) += drm_fb_dma_helper.o
 obj-$(CONFIG_DRM_GEM_DMA_HELPER) += drm_dma_helper.o
 
diff --git a/drivers/gpu/drm/drm_fbdev_dma.c b/drivers/gpu/drm/drm_fbdev_dma.c
new file mode 100644
index 000000000000..cf553ac12a0f
--- /dev/null
+++ b/drivers/gpu/drm/drm_fbdev_dma.c
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: MIT
+
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_gem_dma_helper.h>
+
+#include <drm/drm_fbdev_dma.h>
+
+/*
+ * struct fb_ops
+ */
+
+static int drm_fbdev_dma_fb_open(struct fb_info *info, int user)
+{
+	struct drm_fb_helper *fb_helper = info->par;
+
+	/* No need to take a ref for fbcon because it unbinds on unregister */
+	if (user && !try_module_get(fb_helper->dev->driver->fops->owner))
+		return -ENODEV;
+
+	return 0;
+}
+
+static int drm_fbdev_dma_fb_release(struct fb_info *info, int user)
+{
+	struct drm_fb_helper *fb_helper = info->par;
+
+	if (user)
+		module_put(fb_helper->dev->driver->fops->owner);
+
+	return 0;
+}
+
+static void drm_fbdev_dma_fb_destroy(struct fb_info *info)
+{
+	struct drm_fb_helper *fb_helper = info->par;
+
+	if (!fb_helper->dev)
+		return;
+
+	drm_fb_helper_fini(fb_helper);
+
+	drm_client_buffer_vunmap(fb_helper->buffer);
+	drm_client_framebuffer_delete(fb_helper->buffer);
+	drm_client_release(&fb_helper->client);
+	drm_fb_helper_unprepare(fb_helper);
+	kfree(fb_helper);
+}
+
+static int drm_fbdev_dma_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+	struct drm_fb_helper *fb_helper = info->par;
+	struct drm_device *dev = fb_helper->dev;
+
+	if (drm_WARN_ON_ONCE(dev, !fb_helper->dev->driver->gem_prime_mmap))
+		return -ENODEV;
+
+	return fb_helper->dev->driver->gem_prime_mmap(fb_helper->buffer->gem, vma);
+}
+
+static const struct fb_ops drm_fbdev_dma_fb_ops = {
+	.owner = THIS_MODULE,
+	.fb_open = drm_fbdev_dma_fb_open,
+	.fb_release = drm_fbdev_dma_fb_release,
+	.fb_read = drm_fb_helper_sys_read,
+	.fb_write = drm_fb_helper_sys_write,
+	DRM_FB_HELPER_DEFAULT_OPS,
+	.fb_fillrect = drm_fb_helper_sys_fillrect,
+	.fb_copyarea = drm_fb_helper_sys_copyarea,
+	.fb_imageblit = drm_fb_helper_sys_imageblit,
+	.fb_destroy = drm_fbdev_dma_fb_destroy,
+	.fb_mmap = drm_fbdev_dma_fb_mmap,
+};
+
+/*
+ * struct drm_fb_helper
+ */
+
+static int drm_fbdev_dma_helper_fb_probe(struct drm_fb_helper *fb_helper,
+					 struct drm_fb_helper_surface_size *sizes)
+{
+	struct drm_client_dev *client = &fb_helper->client;
+	struct drm_device *dev = fb_helper->dev;
+	struct drm_client_buffer *buffer;
+	struct drm_gem_dma_object *dma_obj;
+	struct drm_framebuffer *fb;
+	struct fb_info *info;
+	u32 format;
+	struct iosys_map map;
+	int ret;
+
+	drm_dbg_kms(dev, "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, sizes->surface_width,
+					       sizes->surface_height, format);
+	if (IS_ERR(buffer))
+		return PTR_ERR(buffer);
+	dma_obj = to_drm_gem_dma_obj(buffer->gem);
+
+	fb = buffer->fb;
+	if (drm_WARN_ON(dev, fb->funcs->dirty)) {
+		ret = -ENODEV; /* damage handling not supported; use generic emulation */
+		goto err_drm_client_buffer_delete;
+	}
+
+	ret = drm_client_buffer_vmap(buffer, &map);
+	if (ret) {
+		goto err_drm_client_buffer_delete;
+	} else if (drm_WARN_ON(dev, map.is_iomem)) {
+		ret = -ENODEV; /* I/O memory not supported; use generic emulation */
+		goto err_drm_client_buffer_delete;
+	}
+
+	fb_helper->buffer = buffer;
+	fb_helper->fb = buffer->fb;
+
+	info = drm_fb_helper_alloc_info(fb_helper);
+	if (IS_ERR(info)) {
+		ret = PTR_ERR(info);
+		goto err_drm_client_buffer_vunmap;
+	}
+
+	drm_fb_helper_fill_info(info, fb_helper, sizes);
+
+	info->fbops = &drm_fbdev_dma_fb_ops;
+	info->flags = FBINFO_DEFAULT;
+
+	/* screen */
+	info->flags |= FBINFO_VIRTFB; /* system memory */
+	if (dma_obj->map_noncoherent)
+		info->flags |= FBINFO_READS_FAST; /* signal caching */
+	info->screen_size = sizes->surface_height * fb->pitches[0];
+	info->screen_buffer = map.vaddr;
+	info->fix.smem_len = info->screen_size;
+
+#if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
+	/*
+	 * Shamelessly leak the physical address to user-space.
+	 */
+	if (fb_helper->hint_leak_smem_start && !info->fix.smem_start)
+		info->fix.smem_start = page_to_phys(virt_to_page(info->screen_buffer));
+#endif
+
+	return 0;
+
+err_drm_client_buffer_vunmap:
+	fb_helper->fb = NULL;
+	fb_helper->buffer = NULL;
+	drm_client_buffer_vunmap(buffer);
+err_drm_client_buffer_delete:
+	drm_client_framebuffer_delete(buffer);
+	return ret;
+}
+
+static const struct drm_fb_helper_funcs drm_fbdev_dma_helper_funcs = {
+	.fb_probe = drm_fbdev_dma_helper_fb_probe,
+};
+
+/*
+ * struct drm_client_funcs
+ */
+
+static void drm_fbdev_dma_client_unregister(struct drm_client_dev *client)
+{
+	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
+
+	if (fb_helper->info) {
+		drm_fb_helper_unregister_info(fb_helper);
+	} else {
+		drm_client_release(&fb_helper->client);
+		drm_fb_helper_unprepare(fb_helper);
+		kfree(fb_helper);
+	}
+}
+
+static int drm_fbdev_dma_client_restore(struct drm_client_dev *client)
+{
+	drm_fb_helper_lastclose(client->dev);
+
+	return 0;
+}
+
+static int drm_fbdev_dma_client_hotplug(struct drm_client_dev *client)
+{
+	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
+	struct drm_device *dev = client->dev;
+	int ret;
+
+	if (dev->fb_helper)
+		return drm_fb_helper_hotplug_event(dev->fb_helper);
+
+	ret = drm_fb_helper_init(dev, fb_helper);
+	if (ret)
+		goto err_drm_err;
+
+	if (!drm_drv_uses_atomic_modeset(dev))
+		drm_helper_disable_unused_functions(dev);
+
+	ret = drm_fb_helper_initial_config(fb_helper);
+	if (ret)
+		goto err_drm_fb_helper_fini;
+
+	return 0;
+
+err_drm_fb_helper_fini:
+	drm_fb_helper_fini(fb_helper);
+err_drm_err:
+	drm_err(dev, "fbdev-dma: Failed to setup generic emulation (ret=%d)\n", ret);
+	return ret;
+}
+
+static const struct drm_client_funcs drm_fbdev_dma_client_funcs = {
+	.owner		= THIS_MODULE,
+	.unregister	= drm_fbdev_dma_client_unregister,
+	.restore	= drm_fbdev_dma_client_restore,
+	.hotplug	= drm_fbdev_dma_client_hotplug,
+};
+
+/**
+ * drm_fbdev_dma_setup() - Setup fbdev emulation for GEM DMA helpers
+ * @dev: DRM device
+ * @preferred_bpp: Preferred bits per pixel for the device.
+ *                 @dev->mode_config.preferred_depth is used if this is zero.
+ *
+ * This function sets up fbdev emulation for GEM DMA drivers that support
+ * dumb buffers with a virtual address and that can be mmap'ed.
+ * drm_fbdev_dma_setup() shall be called after the DRM driver registered
+ * the new DRM device with drm_dev_register().
+ *
+ * Restore, hotplug events and teardown are all taken care of. Drivers that do
+ * suspend/resume need to call drm_fb_helper_set_suspend_unlocked() themselves.
+ * Simple drivers might use drm_mode_config_helper_suspend().
+ *
+ * This function is safe to call even when there are no connectors present.
+ * Setup will be retried on the next hotplug event.
+ *
+ * The fbdev is destroyed by drm_dev_unregister().
+ */
+void drm_fbdev_dma_setup(struct drm_device *dev, unsigned int preferred_bpp)
+{
+	struct drm_fb_helper *fb_helper;
+	int ret;
+
+	drm_WARN(dev, !dev->registered, "Device has not been registered.\n");
+	drm_WARN(dev, dev->fb_helper, "fb_helper is already set!\n");
+
+	fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL);
+	if (!fb_helper)
+		return;
+	drm_fb_helper_prepare(dev, fb_helper, preferred_bpp, &drm_fbdev_dma_helper_funcs);
+
+	ret = drm_client_init(dev, &fb_helper->client, "fbdev", &drm_fbdev_dma_client_funcs);
+	if (ret) {
+		drm_err(dev, "Failed to register client: %d\n", ret);
+		goto err_drm_client_init;
+	}
+
+	ret = drm_fbdev_dma_client_hotplug(&fb_helper->client);
+	if (ret)
+		drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
+
+	drm_client_register(&fb_helper->client);
+
+	return;
+
+err_drm_client_init:
+	drm_fb_helper_unprepare(fb_helper);
+	kfree(fb_helper);
+}
+EXPORT_SYMBOL(drm_fbdev_dma_setup);
diff --git a/include/drm/drm_fbdev_dma.h b/include/drm/drm_fbdev_dma.h
new file mode 100644
index 000000000000..2da7ee784133
--- /dev/null
+++ b/include/drm/drm_fbdev_dma.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: MIT */
+
+#ifndef DRM_FBDEV_DMA_H
+#define DRM_FBDEV_DMA_H
+
+struct drm_device;
+
+#ifdef CONFIG_DRM_FBDEV_EMULATION
+void drm_fbdev_dma_setup(struct drm_device *dev, unsigned int preferred_bpp);
+#else
+static inline void drm_fbdev_dma_setup(struct drm_device *dev, unsigned int preferred_bpp)
+{ }
+#endif
+
+#endif
-- 
2.39.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  reply	other threads:[~2023-03-01 15:31 UTC|newest]

Thread overview: 219+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-03-01 15:30 [PATCH 00/22] drm/dma-helper: Add dedicated fbdev emulation Thomas Zimmermann
2023-03-01 15:30 ` Thomas Zimmermann
2023-03-01 15:30 ` Thomas Zimmermann
2023-03-01 15:30 ` Thomas Zimmermann
2023-03-01 15:30 ` Thomas Zimmermann [this message]
2023-03-01 15:30   ` [PATCH 01/22] drm/fbdev-dma: Implement fbdev emulation for GEM DMA helpers Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-09 11:04   ` Javier Martinez Canillas
2023-03-09 11:04     ` Javier Martinez Canillas
2023-03-09 11:04     ` Javier Martinez Canillas
2023-03-09 11:04     ` Javier Martinez Canillas
2023-03-09 11:14     ` Javier Martinez Canillas
2023-03-09 11:14       ` Javier Martinez Canillas
2023-03-09 11:14       ` Javier Martinez Canillas
2023-03-09 11:14       ` Javier Martinez Canillas
2023-03-10 13:54     ` Thomas Zimmermann
2023-03-10 13:54       ` Thomas Zimmermann
2023-03-10 13:54       ` Thomas Zimmermann
2023-03-10 13:54       ` Thomas Zimmermann
2023-03-01 15:30 ` [PATCH 02/22] arm/hdlcd: Use GEM DMA fbdev emulation Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-09 11:17   ` Javier Martinez Canillas
2023-03-09 11:17     ` Javier Martinez Canillas
2023-03-09 11:17     ` Javier Martinez Canillas
2023-03-09 11:17     ` Javier Martinez Canillas
2023-03-01 15:30 ` [PATCH 03/22] arm/malidp: " Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-09 11:18   ` Javier Martinez Canillas
2023-03-09 11:18     ` Javier Martinez Canillas
2023-03-09 11:18     ` Javier Martinez Canillas
2023-03-09 11:18     ` Javier Martinez Canillas
2023-03-01 15:30 ` [PATCH 04/22] drm/aspeed: " Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-09 11:20   ` Javier Martinez Canillas
2023-03-09 11:20     ` Javier Martinez Canillas
2023-03-09 11:20     ` Javier Martinez Canillas
2023-03-09 11:20     ` Javier Martinez Canillas
2023-03-01 15:30 ` [PATCH 05/22] drm/atmel-hlcdc: " Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-02 19:47   ` Sam Ravnborg
2023-03-02 19:47     ` Sam Ravnborg
2023-03-02 19:47     ` Sam Ravnborg
2023-03-02 19:47     ` Sam Ravnborg
2023-03-09 11:20   ` Javier Martinez Canillas
2023-03-09 11:20     ` Javier Martinez Canillas
2023-03-09 11:20     ` Javier Martinez Canillas
2023-03-09 11:20     ` Javier Martinez Canillas
2023-03-01 15:30 ` [PATCH 06/22] drm/fsl-dcu: " Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-09 11:20   ` Javier Martinez Canillas
2023-03-09 11:20     ` Javier Martinez Canillas
2023-03-09 11:20     ` Javier Martinez Canillas
2023-03-09 11:20     ` Javier Martinez Canillas
2023-03-01 15:30 ` [PATCH 07/22] drm/imx/dcss: " Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-09 11:20   ` Javier Martinez Canillas
2023-03-09 11:20     ` Javier Martinez Canillas
2023-03-09 11:20     ` Javier Martinez Canillas
2023-03-09 11:20     ` Javier Martinez Canillas
2023-03-01 15:30 ` [PATCH 08/22] drm/imx: " Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-09 11:21   ` Javier Martinez Canillas
2023-03-09 11:21     ` Javier Martinez Canillas
2023-03-09 11:21     ` Javier Martinez Canillas
2023-03-09 11:21     ` Javier Martinez Canillas
2023-03-09 11:22   ` Javier Martinez Canillas
2023-03-09 11:22     ` Javier Martinez Canillas
2023-03-09 11:22     ` Javier Martinez Canillas
2023-03-09 11:22     ` Javier Martinez Canillas
2023-03-01 15:30 ` [PATCH 09/22] drm/kmb: " Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-06 17:18   ` Chrisanthus, Anitha
2023-03-06 17:18     ` Chrisanthus, Anitha
2023-03-06 17:18     ` Chrisanthus, Anitha
2023-03-06 17:18     ` Chrisanthus, Anitha
2023-03-09 11:21   ` Javier Martinez Canillas
2023-03-09 11:21     ` Javier Martinez Canillas
2023-03-09 11:21     ` Javier Martinez Canillas
2023-03-09 11:21     ` Javier Martinez Canillas
2023-03-01 15:30 ` [PATCH 10/22] drm/logicvc: " Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-09 11:23   ` Javier Martinez Canillas
2023-03-09 11:23     ` Javier Martinez Canillas
2023-03-09 11:23     ` Javier Martinez Canillas
2023-03-09 11:23     ` Javier Martinez Canillas
2023-03-01 15:30 ` [PATCH 11/22] drm/meson: " Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-04 21:53   ` Martin Blumenstingl
2023-03-04 21:53     ` Martin Blumenstingl
2023-03-04 21:53     ` Martin Blumenstingl
2023-03-04 21:53     ` Martin Blumenstingl
2023-03-09 11:22   ` Javier Martinez Canillas
2023-03-09 11:22     ` Javier Martinez Canillas
2023-03-09 11:22     ` Javier Martinez Canillas
2023-03-09 11:22     ` Javier Martinez Canillas
2023-03-01 15:30 ` [PATCH 12/22] drm/mxsfb/lcdif: " Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-09 11:24   ` Javier Martinez Canillas
2023-03-09 11:24     ` Javier Martinez Canillas
2023-03-09 11:24     ` Javier Martinez Canillas
2023-03-09 11:24     ` Javier Martinez Canillas
2023-03-01 15:30 ` [PATCH 13/22] drm/mxsfb: " Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-09 11:25   ` Javier Martinez Canillas
2023-03-09 11:25     ` Javier Martinez Canillas
2023-03-09 11:25     ` Javier Martinez Canillas
2023-03-09 11:25     ` Javier Martinez Canillas
2023-03-01 15:30 ` [PATCH 14/22] drm/sti: " Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-09 11:26   ` Javier Martinez Canillas
2023-03-09 11:26     ` Javier Martinez Canillas
2023-03-09 11:26     ` Javier Martinez Canillas
2023-03-09 11:26     ` Javier Martinez Canillas
2023-03-01 15:30 ` [PATCH 15/22] drm/stm: " Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-09 11:26   ` Javier Martinez Canillas
2023-03-09 11:26     ` Javier Martinez Canillas
2023-03-09 11:26     ` Javier Martinez Canillas
2023-03-09 11:26     ` Javier Martinez Canillas
2023-03-01 15:30 ` [PATCH 16/22] drm/sun4i: " Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-09 11:26   ` Javier Martinez Canillas
2023-03-09 11:26     ` Javier Martinez Canillas
2023-03-09 11:26     ` Javier Martinez Canillas
2023-03-09 11:26     ` Javier Martinez Canillas
2023-03-01 15:30 ` [PATCH 17/22] drm/tidss: " Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-09 11:27   ` Javier Martinez Canillas
2023-03-09 11:27     ` Javier Martinez Canillas
2023-03-09 11:27     ` Javier Martinez Canillas
2023-03-09 11:27     ` Javier Martinez Canillas
2023-03-01 15:30 ` [PATCH 18/22] drm/tilcdc: " Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-09 11:27   ` Javier Martinez Canillas
2023-03-09 11:27     ` Javier Martinez Canillas
2023-03-09 11:27     ` Javier Martinez Canillas
2023-03-09 11:27     ` Javier Martinez Canillas
2023-03-01 15:30 ` [PATCH 19/22] drm/arcpgu: " Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-09 11:28   ` Javier Martinez Canillas
2023-03-09 11:28     ` Javier Martinez Canillas
2023-03-09 11:28     ` Javier Martinez Canillas
2023-03-09 11:28     ` Javier Martinez Canillas
2023-03-01 15:30 ` [PATCH 20/22] drm/tve200: " Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-01 15:30   ` Thomas Zimmermann
2023-03-06 22:19   ` Linus Walleij
2023-03-06 22:19     ` Linus Walleij
2023-03-06 22:19     ` Linus Walleij
2023-03-06 22:19     ` Linus Walleij
2023-03-09 11:28   ` Javier Martinez Canillas
2023-03-09 11:28     ` Javier Martinez Canillas
2023-03-09 11:28     ` Javier Martinez Canillas
2023-03-09 11:28     ` Javier Martinez Canillas
2023-03-01 15:31 ` [PATCH 21/22] drm/vc4: " Thomas Zimmermann
2023-03-01 15:31   ` Thomas Zimmermann
2023-03-01 15:31   ` Thomas Zimmermann
2023-03-01 15:31   ` Thomas Zimmermann
2023-03-09 11:28   ` Javier Martinez Canillas
2023-03-09 11:28     ` Javier Martinez Canillas
2023-03-09 11:28     ` Javier Martinez Canillas
2023-03-01 15:31 ` [PATCH 22/22] drm/xlnx: " Thomas Zimmermann
2023-03-01 15:31   ` Thomas Zimmermann
2023-03-01 15:31   ` Thomas Zimmermann
2023-03-01 15:31   ` Thomas Zimmermann
2023-03-09 11:29   ` Javier Martinez Canillas
2023-03-09 11:29     ` Javier Martinez Canillas
2023-03-09 11:29     ` Javier Martinez Canillas
2023-03-09 11:29     ` Javier Martinez Canillas
2023-03-06 22:19 ` [PATCH 00/22] drm/dma-helper: Add dedicated " Linus Walleij
2023-03-06 22:19   ` Linus Walleij
2023-03-06 22:19   ` Linus Walleij
2023-03-06 22:19   ` Linus Walleij
2023-03-07  8:55   ` Thomas Zimmermann
2023-03-07  8:55     ` Thomas Zimmermann
2023-03-07  8:55     ` Thomas Zimmermann
2023-03-07  8:55     ` Thomas Zimmermann
2023-03-09  8:17     ` Linus Walleij
2023-03-09  8:17       ` Linus Walleij
2023-03-09  8:17       ` Linus Walleij
2023-03-09  8:17       ` Linus Walleij

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230301153101.4282-2-tzimmermann@suse.de \
    --to=tzimmermann@suse.de \
    --cc=airlied@gmail.com \
    --cc=alain.volmat@foss.st.com \
    --cc=alexandre.torgue@foss.st.com \
    --cc=andrew@aj.id.au \
    --cc=anitha.chrisanthus@intel.com \
    --cc=daniel@ffwll.ch \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=edmund.j.dea@intel.com \
    --cc=festevam@gmail.com \
    --cc=hyun.kwon@xilinx.com \
    --cc=javierm@redhat.com \
    --cc=jbrunet@baylibre.com \
    --cc=jernej.skrabec@gmail.com \
    --cc=jyri.sarha@iki.fi \
    --cc=kernel@pengutronix.de \
    --cc=khilman@baylibre.com \
    --cc=l.stach@pengutronix.de \
    --cc=laurent.pinchart@ideasonboard.com \
    --cc=laurentiu.palcu@oss.nxp.com \
    --cc=linus.walleij@linaro.org \
    --cc=linux-amlogic@lists.infradead.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-aspeed@lists.ozlabs.org \
    --cc=linux-imx@nxp.com \
    --cc=linux-stm32@st-md-mailman.stormreply.com \
    --cc=linux-sunxi@lists.linux.dev \
    --cc=maarten.lankhorst@linux.intel.com \
    --cc=martin.blumenstingl@googlemail.com \
    --cc=mcoquelin.stm32@gmail.com \
    --cc=mripard@kernel.org \
    --cc=p.zabel@pengutronix.de \
    --cc=philippe.cornu@foss.st.com \
    --cc=raphael.gallais-pou@foss.st.com \
    --cc=s.hauer@pengutronix.de \
    --cc=samuel@sholland.org \
    --cc=shawnguo@kernel.org \
    --cc=tomba@kernel.org \
    --cc=yannick.fertre@foss.st.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.