All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 0/7] drm: add simpledrm driver
@ 2016-09-02  8:22 David Herrmann
  2016-09-02  8:22 ` [PATCH v5 1/7] x86/sysfb: add support for 64bit EFI lfb_base David Herrmann
                   ` (7 more replies)
  0 siblings, 8 replies; 31+ messages in thread
From: David Herrmann @ 2016-09-02  8:22 UTC (permalink / raw)
  To: dri-devel

Hey

On request of Noralf, I picked up the patches and prepared v5. Works fine with
Xorg, if configured according to:
    https://lists.freedesktop.org/archives/dri-devel/2014-January/052777.html
If anyone knows how to make Xorg pick it up dynamically without such a static
configuration, please let me know.

Thanks
David

David Herrmann (7):
  x86/sysfb: add support for 64bit EFI lfb_base
  x86/sysfb: fix lfb_size calculation
  of/platform: expose of_platform_device_destroy()
  video: add generic framebuffer eviction
  drm: switch to sysfb_evict_conflicts()
  drm: add SimpleDRM driver
  drm/simpledrm: add fbdev fallback support

 MAINTAINERS                                  |   6 +
 arch/x86/kernel/sysfb_simplefb.c             |  39 ++-
 drivers/gpu/drm/Kconfig                      |   3 +
 drivers/gpu/drm/Makefile                     |   1 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c      |  24 +-
 drivers/gpu/drm/bochs/bochs_drv.c            |  19 +-
 drivers/gpu/drm/i915/i915_drv.c              |  73 +---
 drivers/gpu/drm/mgag200/mgag200_drv.c        |  27 +-
 drivers/gpu/drm/mgag200/mgag200_main.c       |   9 -
 drivers/gpu/drm/nouveau/nouveau_drm.c        |  33 +-
 drivers/gpu/drm/radeon/radeon_drv.c          |  24 +-
 drivers/gpu/drm/simpledrm/Kconfig            |  19 ++
 drivers/gpu/drm/simpledrm/Makefile           |   9 +
 drivers/gpu/drm/simpledrm/simpledrm.h        |  91 +++++
 drivers/gpu/drm/simpledrm/simpledrm_damage.c | 194 +++++++++++
 drivers/gpu/drm/simpledrm/simpledrm_drv.c    | 477 +++++++++++++++++++++++++++
 drivers/gpu/drm/simpledrm/simpledrm_fbdev.c  | 143 ++++++++
 drivers/gpu/drm/simpledrm/simpledrm_gem.c    | 109 ++++++
 drivers/gpu/drm/simpledrm/simpledrm_kms.c    | 270 +++++++++++++++
 drivers/gpu/drm/simpledrm/simpledrm_of.c     | 265 +++++++++++++++
 drivers/gpu/drm/sun4i/sun4i_drv.c            |  24 +-
 drivers/gpu/drm/vc4/vc4_drv.c                |  25 +-
 drivers/gpu/drm/virtio/virtgpu_drm_bus.c     |  24 +-
 drivers/of/platform.c                        |  35 +-
 drivers/video/Kconfig                        |   4 +
 drivers/video/Makefile                       |   1 +
 drivers/video/sysfb.c                        | 327 ++++++++++++++++++
 include/linux/of_platform.h                  |   1 +
 include/linux/sysfb.h                        |  34 ++
 29 files changed, 2054 insertions(+), 256 deletions(-)
 create mode 100644 drivers/gpu/drm/simpledrm/Kconfig
 create mode 100644 drivers/gpu/drm/simpledrm/Makefile
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm.h
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_damage.c
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_drv.c
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_fbdev.c
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_gem.c
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_kms.c
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_of.c
 create mode 100644 drivers/video/sysfb.c
 create mode 100644 include/linux/sysfb.h

-- 
2.9.3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v5 1/7] x86/sysfb: add support for 64bit EFI lfb_base
  2016-09-02  8:22 [PATCH v5 0/7] drm: add simpledrm driver David Herrmann
@ 2016-09-02  8:22 ` David Herrmann
  2016-09-02 10:20   ` Tom Gundersen
  2016-09-02  8:22 ` [PATCH v5 2/7] x86/sysfb: fix lfb_size calculation David Herrmann
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 31+ messages in thread
From: David Herrmann @ 2016-09-02  8:22 UTC (permalink / raw)
  To: dri-devel

The screen_info object was extended to support 64bit lfb_base addresses
in:

    commit ae2ee627dc87a70910de91b791b3cd0e9c6facdd
    Author: Matt Fleming <matt.fleming@intel.com>
    Date:   Tue Aug 25 16:32:55 2015 +0100

        efifb: Add support for 64-bit frame buffer addresses

However, the x86 simple-framebuffer setup code never made use of it. Fix
it to properly assemble and verify the lfb_base before advertising
simple-framebuffer devices.

In particular, this means if VIDEO_CAPABILITY_64BIT_BASE is set, the
screen_info->ext_lfb_base field will contain the upper 32bit of the
actual lfb_base. Make sure the address is not 0 (i.e., unset), as well as
does not overflow the physical address type.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 arch/x86/kernel/sysfb_simplefb.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/sysfb_simplefb.c b/arch/x86/kernel/sysfb_simplefb.c
index 764a29f..35b8641 100644
--- a/arch/x86/kernel/sysfb_simplefb.c
+++ b/arch/x86/kernel/sysfb_simplefb.c
@@ -67,6 +67,20 @@ __init int create_simplefb(const struct screen_info *si,
 	struct platform_device *pd;
 	struct resource res;
 	unsigned long len;
+	u64 base;
+
+	/*
+	 * If the 64BIT_BASE capability is set, ext_lfb_base will contain the
+	 * upper half of the base address. Assemble the address, then make sure
+	 * it is valid and we can actually access it.
+	 */
+	base = si->lfb_base;
+	if (si->capabilities & VIDEO_CAPABILITY_64BIT_BASE)
+		base |= (u64)si->ext_lfb_base << 32;
+	if (!base || (u64)(resource_size_t)base != base) {
+		printk(KERN_DEBUG "sysfb: inaccessible VRAM base\n");
+		return -EINVAL;
+	}
 
 	/* don't use lfb_size as it may contain the whole VMEM instead of only
 	 * the part that is occupied by the framebuffer */
@@ -81,8 +95,8 @@ __init int create_simplefb(const struct screen_info *si,
 	memset(&res, 0, sizeof(res));
 	res.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
 	res.name = simplefb_resname;
-	res.start = si->lfb_base;
-	res.end = si->lfb_base + len - 1;
+	res.start = base;
+	res.end = res.start + len - 1;
 	if (res.end <= res.start)
 		return -EINVAL;
 
-- 
2.9.3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v5 2/7] x86/sysfb: fix lfb_size calculation
  2016-09-02  8:22 [PATCH v5 0/7] drm: add simpledrm driver David Herrmann
  2016-09-02  8:22 ` [PATCH v5 1/7] x86/sysfb: add support for 64bit EFI lfb_base David Herrmann
@ 2016-09-02  8:22 ` David Herrmann
  2016-09-02 10:20   ` Tom Gundersen
  2016-09-02  8:22 ` [PATCH v5 3/7] of/platform: expose of_platform_device_destroy() David Herrmann
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 31+ messages in thread
From: David Herrmann @ 2016-09-02  8:22 UTC (permalink / raw)
  To: dri-devel

The screen_info.lfb_size field is shifted by 16 bits *only* in case of
VBE. This has historical reasons since VBE advertised it similarly.
However, in case of EFI framebuffers, the size is no longer shifted. Fix
the x86 simple-framebuffer setup code to use the correct size in the
non-VBE case.

While at it, avoid variable abbreviations and rename 'len' to 'length',
and use the correct types matching the screen_info definition.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 arch/x86/kernel/sysfb_simplefb.c | 25 +++++++++++++++++--------
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/arch/x86/kernel/sysfb_simplefb.c b/arch/x86/kernel/sysfb_simplefb.c
index 35b8641..85195d4 100644
--- a/arch/x86/kernel/sysfb_simplefb.c
+++ b/arch/x86/kernel/sysfb_simplefb.c
@@ -66,8 +66,8 @@ __init int create_simplefb(const struct screen_info *si,
 {
 	struct platform_device *pd;
 	struct resource res;
-	unsigned long len;
-	u64 base;
+	u64 base, size;
+	u32 length;
 
 	/*
 	 * If the 64BIT_BASE capability is set, ext_lfb_base will contain the
@@ -82,11 +82,20 @@ __init int create_simplefb(const struct screen_info *si,
 		return -EINVAL;
 	}
 
-	/* don't use lfb_size as it may contain the whole VMEM instead of only
-	 * the part that is occupied by the framebuffer */
-	len = mode->height * mode->stride;
-	len = PAGE_ALIGN(len);
-	if (len > (u64)si->lfb_size << 16) {
+	/*
+	 * Don't use lfb_size as IORESOURCE size, since it may contain the
+	 * entire VMEM, and thus require huge mappings. Use just the part we
+	 * need, that is, the part where the framebuffer is located. But verify
+	 * that it does not exceed the advertised VMEM.
+	 * Note that in case of VBE, the lfb_size is shifted by 16 bits for
+	 * historical reasons.
+	 */
+	size = si->lfb_size;
+	if (si->orig_video_isVGA == VIDEO_TYPE_VLFB)
+		size <<= 16;
+	length = mode->height * mode->stride;
+	length = PAGE_ALIGN(length);
+	if (length > size) {
 		printk(KERN_WARNING "sysfb: VRAM smaller than advertised\n");
 		return -EINVAL;
 	}
@@ -96,7 +105,7 @@ __init int create_simplefb(const struct screen_info *si,
 	res.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
 	res.name = simplefb_resname;
 	res.start = base;
-	res.end = res.start + len - 1;
+	res.end = res.start + length - 1;
 	if (res.end <= res.start)
 		return -EINVAL;
 
-- 
2.9.3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v5 3/7] of/platform: expose of_platform_device_destroy()
  2016-09-02  8:22 [PATCH v5 0/7] drm: add simpledrm driver David Herrmann
  2016-09-02  8:22 ` [PATCH v5 1/7] x86/sysfb: add support for 64bit EFI lfb_base David Herrmann
  2016-09-02  8:22 ` [PATCH v5 2/7] x86/sysfb: fix lfb_size calculation David Herrmann
@ 2016-09-02  8:22 ` David Herrmann
  2016-09-02 10:21   ` Tom Gundersen
  2016-09-02  8:22 ` [PATCH v5 4/7] video: add generic framebuffer eviction David Herrmann
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 31+ messages in thread
From: David Herrmann @ 2016-09-02  8:22 UTC (permalink / raw)
  To: dri-devel

We already expose of_platform_device_create(), but give the caller no
chance to revert its effect. Make sure we also provide the counterpart
of_platform_device_destroy().

This requires a small refactoring, since so far the internal destructor
is used as iterator to for_each_device(), but we don't want to expose it
with the "void *data" parameter. So provide
of_platform_device_depopulate() as new iterator, which calls into
of_platform_device_destroy().

While at it, drop the unused 'children_left' argument by
of_platform_notify(). It is a left-over that somehow was never removed.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/of/platform.c       | 35 ++++++++++++++++++++++++++---------
 include/linux/of_platform.h |  1 +
 2 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index f39ccd5..f9bb563 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -524,15 +524,18 @@ static int __init of_platform_default_populate_init(void)
 arch_initcall_sync(of_platform_default_populate_init);
 #endif
 
-static int of_platform_device_destroy(struct device *dev, void *data)
+/**
+ * of_platform_device_destroy - unregister an of_device
+ * @dev: device to unregister
+ *
+ * This is the inverse operation of of_platform_device_create(). It unregisters
+ * the passed device, if registered.
+ */
+void of_platform_device_destroy(struct device *dev)
 {
 	/* Do not touch devices not populated from the device tree */
 	if (!dev->of_node || !of_node_check_flag(dev->of_node, OF_POPULATED))
-		return 0;
-
-	/* Recurse for any nodes that were treated as busses */
-	if (of_node_check_flag(dev->of_node, OF_POPULATED_BUS))
-		device_for_each_child(dev, NULL, of_platform_device_destroy);
+		return;
 
 	if (dev->bus == &platform_bus_type)
 		platform_device_unregister(to_platform_device(dev));
@@ -544,6 +547,20 @@ static int of_platform_device_destroy(struct device *dev, void *data)
 	of_dma_deconfigure(dev);
 	of_node_clear_flag(dev->of_node, OF_POPULATED);
 	of_node_clear_flag(dev->of_node, OF_POPULATED_BUS);
+}
+EXPORT_SYMBOL(of_platform_device_destroy);
+
+static int of_platform_device_depopulate(struct device *dev, void *data)
+{
+	/* Do not touch devices not populated from the device tree */
+	if (!dev->of_node || !of_node_check_flag(dev->of_node, OF_POPULATED))
+		return 0;
+
+	/* Recurse for any nodes that were treated as busses */
+	if (of_node_check_flag(dev->of_node, OF_POPULATED_BUS))
+		device_for_each_child(dev, NULL, of_platform_device_depopulate);
+
+	of_platform_device_destroy(dev);
 	return 0;
 }
 
@@ -562,7 +579,8 @@ static int of_platform_device_destroy(struct device *dev, void *data)
 void of_platform_depopulate(struct device *parent)
 {
 	if (parent->of_node && of_node_check_flag(parent->of_node, OF_POPULATED_BUS)) {
-		device_for_each_child(parent, NULL, of_platform_device_destroy);
+		device_for_each_child(parent, NULL,
+				      of_platform_device_depopulate);
 		of_node_clear_flag(parent->of_node, OF_POPULATED_BUS);
 	}
 }
@@ -574,7 +592,6 @@ static int of_platform_notify(struct notifier_block *nb,
 {
 	struct of_reconfig_data *rd = arg;
 	struct platform_device *pdev_parent, *pdev;
-	bool children_left;
 
 	switch (of_reconfig_get_state_change(action, rd)) {
 	case OF_RECONFIG_CHANGE_ADD:
@@ -612,7 +629,7 @@ static int of_platform_notify(struct notifier_block *nb,
 			return NOTIFY_OK;	/* no? not meant for us */
 
 		/* unregister takes one ref away */
-		of_platform_device_destroy(&pdev->dev, &children_left);
+		of_platform_device_depopulate(&pdev->dev, NULL);
 
 		/* and put the reference of the find */
 		of_dev_put(pdev);
diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h
index 956a100..a9017d3 100644
--- a/include/linux/of_platform.h
+++ b/include/linux/of_platform.h
@@ -63,6 +63,7 @@ extern struct platform_device *of_find_device_by_node(struct device_node *np);
 extern struct platform_device *of_platform_device_create(struct device_node *np,
 						   const char *bus_id,
 						   struct device *parent);
+extern void of_platform_device_destroy(struct device *dev);
 
 extern int of_platform_bus_probe(struct device_node *root,
 				 const struct of_device_id *matches,
-- 
2.9.3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v5 4/7] video: add generic framebuffer eviction
  2016-09-02  8:22 [PATCH v5 0/7] drm: add simpledrm driver David Herrmann
                   ` (2 preceding siblings ...)
  2016-09-02  8:22 ` [PATCH v5 3/7] of/platform: expose of_platform_device_destroy() David Herrmann
@ 2016-09-02  8:22 ` David Herrmann
  2016-09-02 10:21   ` Tom Gundersen
  2016-09-03 12:06   ` Noralf Trønnes
  2016-09-02  8:22 ` [PATCH v5 5/7] drm: switch to sysfb_evict_conflicts() David Herrmann
                   ` (3 subsequent siblings)
  7 siblings, 2 replies; 31+ messages in thread
From: David Herrmann @ 2016-09-02  8:22 UTC (permalink / raw)
  To: dri-devel

There are several situations where we want hardware handover from an early
boot GFX driver (e.g., vgacon, vesafb, efifb, simplefb) to a full fletched
GFX driver (e.g., most DRM drivers). So far, we relied on
remove_conflicting_framebuffers() to do this for us, however, this had a
bunch of downsides:

  o It only removes conflicting fbdev drivers. It does not drop vgacon,
    early boot console drivers, conflicting DRM drivers, etc.

  o It only unloads the fbdev driver, it does not modify the underlying
    device or resources. In case of "screen_info" drivers (e.g., efifb)
    this is fine, since no resources are pinned. However, if the driver
    binds to a platform-device like "simple-framebuffer", we must make
    sure to unregister that device as well. Otherwise, pinned resources
    like IORESOURCE_MEM stay around, triggering WARN_ONs if the following
    driver requests those resources.

  o It is only available if CONFIG_FB is selected.

This commit adds a new infrastructure that manages system-framebuffers
(short: sysfb). The initial commit provides conflict-resolution for
system-framebuffers. At its core it provides sysfb_evict_conflicts(),
which implements conflict detection and removal for all known types of
GFX driver hand-overs. So far, this includes platform-device removal,
fbdev-firmware-device removal, vgacon removal and VBE detection. To
further simplify the callers, it also provides helpers to figure out what
hand-over to do, based on the device the new drivers binds to:

  o PCI drivers can use sysfb_evict_conflicts_pci(), which will figure out
    the apertures automatically, and does VGA/VBE detection.

  o Generic firmware drivers that might be shadowed at any address in
    memory can use sysfb_evict_conflicts_firmware(), basically removing
    *all* firmware framebuffers in effect.

This only adds the generic sysfb helpers. No users are converted, yet.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/video/Kconfig  |   4 +
 drivers/video/Makefile |   1 +
 drivers/video/sysfb.c  | 327 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/sysfb.h  |  34 +++++
 4 files changed, 366 insertions(+)
 create mode 100644 drivers/video/sysfb.c
 create mode 100644 include/linux/sysfb.h

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 3c20af9..56a8294 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -36,6 +36,10 @@ config VIDEOMODE_HELPERS
 config HDMI
 	bool
 
+config SYSFB
+	bool
+	select DUMMY_CONSOLE if VT
+
 if VT
 	source "drivers/video/console/Kconfig"
 endif
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 9ad3c17..df7bd75 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -1,5 +1,6 @@
 obj-$(CONFIG_VGASTATE)            += vgastate.o
 obj-$(CONFIG_HDMI)                += hdmi.o
+obj-$(CONFIG_SYSFB)		  += sysfb.o
 
 obj-$(CONFIG_VT)		  += console/
 obj-$(CONFIG_LOGO)		  += logo/
diff --git a/drivers/video/sysfb.c b/drivers/video/sysfb.c
new file mode 100644
index 0000000..00585c9
--- /dev/null
+++ b/drivers/video/sysfb.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2013-2016 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ */
+
+#define pr_fmt(fmt) "sysfb: " fmt
+#include <linux/console.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/fb.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/sysfb.h>
+#include <linux/vt.h>
+
+static bool sysfb_evict_match_resource(struct sysfb_evict_ctx *ctx,
+				       struct resource *mem)
+{
+	struct aperture *g;
+	unsigned int i;
+
+	for (i = 0; i < ctx->ap->count; ++i) {
+		g = &ctx->ap->ranges[i];
+
+		if (mem->start == g->base)
+			return true;
+		if (mem->start >= g->base && mem->end < g->base + g->size)
+			return true;
+		if ((ctx->flags & SYSFB_EVICT_VBE) && mem->start == 0xA0000)
+			return true;
+	}
+
+	return false;
+}
+
+static int sysfb_evict_platform_device(struct device *dev, void *userdata)
+{
+	struct sysfb_evict_ctx *ctx = userdata;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct resource *mem;
+
+	if (!pdev->name)
+		return 0;
+
+	if (!strcmp(pdev->name, "simple-framebuffer")) {
+		mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		if (!mem)
+			return 0;
+		if (!sysfb_evict_match_resource(ctx, mem))
+			return 0;
+
+#ifdef CONFIG_OF_ADDRESS
+		if (dev->of_node)
+			of_platform_device_destroy(dev);
+		else
+#endif
+		if (dev_get_platdata(&pdev->dev))
+			platform_device_del(pdev);
+	}
+
+	return 0;
+}
+
+static int sysfb_evict_platform(struct sysfb_evict_ctx *ctx)
+{
+	/*
+	 * Early-boot architecture setup and boot-loarders sometimes create
+	 * preliminary platform devices with a generic framebuffer setup. This
+	 * allows graphics access during boot-up, without a real graphics
+	 * driver loaded. However, once a real graphics driver takes over, we
+	 * have to destroy those platform devices. In the legacy fbdev case, we
+	 * just used to unload the fbdev driver. However, to make sure any kind
+	 * of driver is unloaded, the platform-eviction code here simply
+	 * removes any conflicting platform device directly. This causes any
+	 * bound driver to be detached, and then removes the device entirely so
+	 * it cannot be bound to later on.
+	 *
+	 * Please note that any such platform device must be registered by
+	 * early architecture setup code. If they are registered after regular
+	 * GFX drivers, this will fail horribly.
+	 */
+
+	static DEFINE_MUTEX(lock);
+	int ret;
+
+	/*
+	 * In case of static platform-devices, we must iterate the bus and
+	 * remove them manually. We know that we're the only code that might
+	 * remove them, so a simple static lock serializes all calls here.
+	 */
+	mutex_lock(&lock);
+	ret = bus_for_each_dev(&platform_bus_type, NULL, ctx,
+			       sysfb_evict_platform_device);
+	mutex_unlock(&lock);
+	return ret;
+}
+
+static int sysfb_evict_fbdev(struct sysfb_evict_ctx *ctx)
+{
+	/*
+	 * Usually, evicting platform devices should be enough to also trigger
+	 * fbdev unloading. However, some legacy devices (e.g., uvesafb) have
+	 * no platform devices that can be evicted, so we still fall back to
+	 * the legacy fbdev removal code. Note that this only removes fbdev
+	 * devices marked as FBINFO_MISC_FIRMWARE. Anything else is left
+	 * untouched.
+	 *
+	 * As usual, this only works if the fbdev device is probed early,
+	 * before any real GFX driver wants to take over.
+	 */
+
+	int ret = 0;
+
+#ifdef CONFIG_FB
+	ret = remove_conflicting_framebuffers(ctx->ap, "sysfb",
+					      ctx->flags & SYSFB_EVICT_VBE);
+#endif
+
+	return ret;
+}
+
+static int sysfb_evict_vgacon(struct sysfb_evict_ctx *ctx)
+{
+	/*
+	 * The VGACON console driver pokes at VGA registers randomly. If a GFX
+	 * driver cannot keep the VGA support alive, it better makes sure to
+	 * unload VGACON before probing.
+	 *
+	 * Unloading VGACON requires us to first force dummycon to take over
+	 * from vgacon (but only if vgacon is really in use), followed by a
+	 * deregistration of vgacon. Note that this prevents vgacon from being
+	 * used again after the GFX driver is unloaded. But that is usually
+	 * fine, since VGA state is rarely restored on driver-unload, anyway.
+	 *
+	 * Note that we rely on VGACON to be probed in early boot (actually
+	 * done by ARCH setup code). If it is probed after GFX drivers, this
+	 * will fail horribly. You better make sure VGACON is probed early and
+	 * GFX drivers are probed as normal modules.
+	 */
+
+	int ret = 0;
+
+#ifdef CONFIG_VGA_CONSOLE
+	console_lock();
+	if (con_is_bound(&vga_con))
+		ret = do_take_over_console(&dummy_con, 0,
+					   MAX_NR_CONSOLES - 1, 1);
+	if (ret == 0) {
+		ret = do_unregister_con_driver(&vga_con);
+		if (ret == -ENODEV) /* ignore "already unregistered" */
+			ret = 0;
+	}
+	console_unlock();
+#endif
+
+	return ret;
+}
+
+/**
+ * sysfb_evict_conflicts - remove any conflicting system-framebuffers
+ * @ctx:		eviction context
+ *
+ * This function evicts any conflicting system-framebuffers and their bound
+ * drivers, according to the data given in @ctx.
+ *
+ * Depending on @ctx->flags, the following operations are performed:
+ *
+ *   SYSFB_EVICT_PLATFORM: Firmware framebuffer platform devices (eg.,
+ *                         'simple-framebuffer') that overlap @ctx are removed
+ *                         from the system, causing drivers to be unbound.
+ *                         If SYSFB_EVICT_VBE is given, this also affects
+ *                         devices that own the VGA region.
+ *
+ *   SYSFB_EVICT_FBDEV: Any firmware fbdev drivers that overlap @ctx are
+ *                      unloaded.
+ *                      Furthermore, if SYSFB_EVICT_VBE is given as well, any
+ *                      fbdev driver that maps the VGA region is unloaded.
+ *
+ *   SYSFB_EVICT_VGACON: The vgacon console driver is unbound and unregistered.
+ *
+ * This might call into fbdev driver unregistration, or even device_del() on
+ * some buses. Hence, make sure you call this from your top-level
+ * probe-callbacks, rather than with any gfx-subsystem locks held.
+ *
+ * RETURNS:
+ * 0 on success, negative error code on failure.
+ */
+int sysfb_evict_conflicts(struct sysfb_evict_ctx *ctx)
+{
+	int ret;
+
+	if (WARN_ON(!ctx || !ctx->ap))
+		return -EINVAL;
+
+	pr_info("removing conflicts (sysfb%s%s%s%s)\n",
+		(ctx->flags & SYSFB_EVICT_PLATFORM) ? ", platform" : "",
+		(ctx->flags & SYSFB_EVICT_FBDEV) ? ", fbdev" : "",
+		(ctx->flags & SYSFB_EVICT_VGACON) ? ", vgacon" : "",
+		(ctx->flags & SYSFB_EVICT_VBE) ? ", vbe" : "");
+
+	if (ctx->flags & SYSFB_EVICT_PLATFORM) {
+		ret = sysfb_evict_platform(ctx);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (ctx->flags & SYSFB_EVICT_FBDEV) {
+		ret = sysfb_evict_fbdev(ctx);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (ctx->flags & SYSFB_EVICT_VGACON) {
+		ret = sysfb_evict_vgacon(ctx);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(sysfb_evict_conflicts);
+
+/**
+ * sysfb_evict_conflicts_firmware() - remove all firmware framebuffers
+ *
+ * This is similar to sysfb_evict_conflicts() but uses a fake aperture spanning
+ * the entire address-space. This is suitable for any GFX driver that just
+ * wants to get rid of all available firmware framebuffers.
+ *
+ * RETURNS:
+ * 0 on success, negative error code on failure.
+ */
+int sysfb_evict_conflicts_firmware(void)
+{
+	struct sysfb_evict_ctx ctx = {};
+	int ret;
+
+	ctx.ap = alloc_apertures(1);
+	if (!ctx.ap)
+		return -ENOMEM;
+
+	ctx.ap->ranges[0].base = 0;
+	ctx.ap->ranges[0].size = ~0;
+
+	ctx.flags |= SYSFB_EVICT_FBDEV | SYSFB_EVICT_PLATFORM;
+	ret = sysfb_evict_conflicts(&ctx);
+
+	kfree(ctx.ap);
+	return ret;
+}
+EXPORT_SYMBOL(sysfb_evict_conflicts_firmware);
+
+#ifdef CONFIG_PCI
+/**
+ * sysfb_evict_conflicts_pci() - remove all system framebuffers conflicting
+ *                               with the given pci device
+ * @pdev:		pci device
+ *
+ * This is similar to sysfb_evict_conflicts() but generates the eviction
+ * context based on the given pci device @pdev.
+ *
+ * RETURNS:
+ * 0 on success, negative error code on failure.
+ */
+int sysfb_evict_conflicts_pci(struct pci_dev *pdev)
+{
+	struct sysfb_evict_ctx ctx = {};
+	size_t i, n, offset;
+	int ret;
+
+	/*
+	 * If this device is used as primary VGA device, it is shadowed at the
+	 * VBE base address, so make sure to include it in the apertures.
+	 */
+	if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)
+		ctx.flags |= SYSFB_EVICT_VBE;
+
+	/*
+	 * If a device is a VGA device, make sure to kick out vgacon. We cannot
+	 * rely on the IORESOURCE_ROM_SHADOW, since vgacon can switch between
+	 * vga devices at runtime. So kick out vgacon anyway.
+	 */
+	if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
+		ctx.flags |= SYSFB_EVICT_VGACON;
+
+	/*
+	 * Allocate apertures for all standard PCI resources. Skip them in case
+	 * they are empty.
+	 */
+	ctx.ap = alloc_apertures(PCI_STD_RESOURCE_END - PCI_STD_RESOURCES + 1);
+	if (!ctx.ap)
+		return -ENOMEM;
+
+	offset = PCI_STD_RESOURCES;
+	for (n = 0, i = 0; i < ctx.ap->count; ++i) {
+		if (pci_resource_len(pdev, offset + i) < 1)
+			continue;
+
+		ctx.ap->ranges[n].base = pci_resource_start(pdev, offset + i);
+		ctx.ap->ranges[n].size = pci_resource_len(pdev, offset + i);
+		++n;
+	}
+	ctx.ap->count = n;
+
+	/*
+	 * Evict all matching fbdev devices, VBE devices if they shadow this
+	 * device, vgacon if this is a vga device, and platform devices if they
+	 * match.
+	 */
+	ctx.flags |= SYSFB_EVICT_FBDEV | SYSFB_EVICT_PLATFORM;
+	ret = sysfb_evict_conflicts(&ctx);
+
+	kfree(ctx.ap);
+	return ret;
+}
+EXPORT_SYMBOL(sysfb_evict_conflicts_pci);
+#endif /* CONFIG_PCI */
diff --git a/include/linux/sysfb.h b/include/linux/sysfb.h
new file mode 100644
index 0000000..b67c74a
--- /dev/null
+++ b/include/linux/sysfb.h
@@ -0,0 +1,34 @@
+#ifndef __LINUX_SYSFB_H
+#define __LINUX_SYSFB_H
+
+/*
+ * Copyright (C) 2013-2016 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+
+struct apertures_struct;
+struct pci_dev;
+
+enum {
+	SYSFB_EVICT_PLATFORM			= (1U <<  0),
+	SYSFB_EVICT_FBDEV			= (1U <<  1),
+	SYSFB_EVICT_VGACON			= (1U <<  2),
+	SYSFB_EVICT_VBE				= (1U <<  3),
+};
+
+struct sysfb_evict_ctx {
+	struct apertures_struct *ap;
+	unsigned int flags;
+};
+
+int sysfb_evict_conflicts(struct sysfb_evict_ctx *ctx);
+int sysfb_evict_conflicts_firmware(void);
+int sysfb_evict_conflicts_pci(struct pci_dev *pdev);
+
+#endif /* __LINUX_SYSFB_H */
-- 
2.9.3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v5 5/7] drm: switch to sysfb_evict_conflicts()
  2016-09-02  8:22 [PATCH v5 0/7] drm: add simpledrm driver David Herrmann
                   ` (3 preceding siblings ...)
  2016-09-02  8:22 ` [PATCH v5 4/7] video: add generic framebuffer eviction David Herrmann
@ 2016-09-02  8:22 ` David Herrmann
  2016-09-03 12:13   ` Noralf Trønnes
  2016-09-02  8:22 ` [PATCH v5 6/7] drm: add SimpleDRM driver David Herrmann
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 31+ messages in thread
From: David Herrmann @ 2016-09-02  8:22 UTC (permalink / raw)
  To: dri-devel

Switch over all DRM drivers to use the new sysfb_evict_conflicts()
infrastructure. The only non-trivial conversion is i915, since it does not
make use of the generic PCI resources, but assembles the apertures via
intel ggtt queries.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/gpu/drm/Kconfig                  |  1 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c  | 24 +----------
 drivers/gpu/drm/bochs/bochs_drv.c        | 19 +--------
 drivers/gpu/drm/i915/i915_drv.c          | 73 ++++++--------------------------
 drivers/gpu/drm/mgag200/mgag200_drv.c    | 27 +++---------
 drivers/gpu/drm/mgag200/mgag200_main.c   |  9 ----
 drivers/gpu/drm/nouveau/nouveau_drm.c    | 33 +++------------
 drivers/gpu/drm/radeon/radeon_drv.c      | 24 +----------
 drivers/gpu/drm/sun4i/sun4i_drv.c        | 24 +++--------
 drivers/gpu/drm/vc4/vc4_drv.c            | 25 +++--------
 drivers/gpu/drm/virtio/virtgpu_drm_bus.c | 24 +----------
 11 files changed, 44 insertions(+), 239 deletions(-)

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index fc35731..f27f9b5 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -12,6 +12,7 @@ menuconfig DRM
 	select I2C
 	select I2C_ALGOBIT
 	select DMA_SHARED_BUFFER
+	select SYSFB
 	help
 	  Kernel-level support for the Direct Rendering Infrastructure (DRI)
 	  introduced in XFree86 4.0. If you say Y here, you need to select
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 9aa533c..a1e67da 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -38,6 +38,7 @@
 #include <linux/console.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
+#include <linux/sysfb.h>
 #include <linux/vga_switcheroo.h>
 #include "drm_crtc_helper.h"
 
@@ -326,27 +327,6 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
 
 static struct drm_driver kms_driver;
 
-static int amdgpu_kick_out_firmware_fb(struct pci_dev *pdev)
-{
-	struct apertures_struct *ap;
-	bool primary = false;
-
-	ap = alloc_apertures(1);
-	if (!ap)
-		return -ENOMEM;
-
-	ap->ranges[0].base = pci_resource_start(pdev, 0);
-	ap->ranges[0].size = pci_resource_len(pdev, 0);
-
-#ifdef CONFIG_X86
-	primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
-#endif
-	remove_conflicting_framebuffers(ap, "amdgpudrmfb", primary);
-	kfree(ap);
-
-	return 0;
-}
-
 static int amdgpu_pci_probe(struct pci_dev *pdev,
 			    const struct pci_device_id *ent)
 {
@@ -368,7 +348,7 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
 		return ret;
 
 	/* Get rid of things like offb */
-	ret = amdgpu_kick_out_firmware_fb(pdev);
+	ret = sysfb_evict_conflicts_pci(pdev);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/bochs/bochs_drv.c b/drivers/gpu/drm/bochs/bochs_drv.c
index abace82..99c4ea3 100644
--- a/drivers/gpu/drm/bochs/bochs_drv.c
+++ b/drivers/gpu/drm/bochs/bochs_drv.c
@@ -8,6 +8,7 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/sysfb.h>
 
 #include "bochs.h"
 
@@ -143,28 +144,12 @@ static const struct dev_pm_ops bochs_pm_ops = {
 /* ---------------------------------------------------------------------- */
 /* pci interface                                                          */
 
-static int bochs_kick_out_firmware_fb(struct pci_dev *pdev)
-{
-	struct apertures_struct *ap;
-
-	ap = alloc_apertures(1);
-	if (!ap)
-		return -ENOMEM;
-
-	ap->ranges[0].base = pci_resource_start(pdev, 0);
-	ap->ranges[0].size = pci_resource_len(pdev, 0);
-	remove_conflicting_framebuffers(ap, "bochsdrmfb", false);
-	kfree(ap);
-
-	return 0;
-}
-
 static int bochs_pci_probe(struct pci_dev *pdev,
 			   const struct pci_device_id *ent)
 {
 	int ret;
 
-	ret = bochs_kick_out_firmware_fb(pdev);
+	ret = sysfb_evict_conflicts_pci(pdev);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 95ddd56..4d6a65dd 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -36,6 +36,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/pnp.h>
 #include <linux/slab.h>
+#include <linux/sysfb.h>
 #include <linux/vgaarb.h>
 #include <linux/vga_switcheroo.h>
 #include <linux/vt.h>
@@ -687,70 +688,32 @@ out:
 	return ret;
 }
 
-#if IS_ENABLED(CONFIG_FB)
 static int i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv)
 {
-	struct apertures_struct *ap;
+	struct sysfb_evict_ctx ctx = {};
 	struct pci_dev *pdev = dev_priv->drm.pdev;
 	struct i915_ggtt *ggtt = &dev_priv->ggtt;
-	bool primary;
 	int ret;
 
-	ap = alloc_apertures(1);
-	if (!ap)
-		return -ENOMEM;
-
-	ap->ranges[0].base = ggtt->mappable_base;
-	ap->ranges[0].size = ggtt->mappable_end;
-
-	primary =
-		pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
-
-	ret = remove_conflicting_framebuffers(ap, "inteldrmfb", primary);
-
-	kfree(ap);
-
-	return ret;
-}
-#else
-static int i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv)
-{
-	return 0;
-}
-#endif
+	ctx.flags = SYSFB_EVICT_PLATFORM |
+		    SYSFB_EVICT_FBDEV |
+		    SYSFB_EVICT_VGACON;
 
-#if !defined(CONFIG_VGA_CONSOLE)
-static int i915_kick_out_vgacon(struct drm_i915_private *dev_priv)
-{
-	return 0;
-}
-#elif !defined(CONFIG_DUMMY_CONSOLE)
-static int i915_kick_out_vgacon(struct drm_i915_private *dev_priv)
-{
-	return -ENODEV;
-}
-#else
-static int i915_kick_out_vgacon(struct drm_i915_private *dev_priv)
-{
-	int ret = 0;
+	ctx.ap = alloc_apertures(1);
+	if (!ctx.ap)
+		return -ENOMEM;
 
-	DRM_INFO("Replacing VGA console driver\n");
+	ctx.ap->ranges[0].base = ggtt->mappable_base;
+	ctx.ap->ranges[0].size = ggtt->mappable_end;
 
-	console_lock();
-	if (con_is_bound(&vga_con))
-		ret = do_take_over_console(&dummy_con, 0, MAX_NR_CONSOLES - 1, 1);
-	if (ret == 0) {
-		ret = do_unregister_con_driver(&vga_con);
+	if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)
+		ctx.flags |= SYSFB_EVICT_VBE;
 
-		/* Ignore "already unregistered". */
-		if (ret == -ENODEV)
-			ret = 0;
-	}
-	console_unlock();
+	ret = sysfb_evict_conflicts(&ctx);
 
+	kfree(ctx.ap);
 	return ret;
 }
-#endif
 
 static void intel_init_dpio(struct drm_i915_private *dev_priv)
 {
@@ -1032,20 +995,12 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
 		goto out_ggtt;
 	}
 
-	/* WARNING: Apparently we must kick fbdev drivers before vgacon,
-	 * otherwise the vga fbdev driver falls over. */
 	ret = i915_kick_out_firmware_fb(dev_priv);
 	if (ret) {
 		DRM_ERROR("failed to remove conflicting framebuffer drivers\n");
 		goto out_ggtt;
 	}
 
-	ret = i915_kick_out_vgacon(dev_priv);
-	if (ret) {
-		DRM_ERROR("failed to remove conflicting VGA console\n");
-		goto out_ggtt;
-	}
-
 	pci_set_master(dev->pdev);
 
 	/* overlay on gen2 is broken and can't address above 1G */
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c
index 2b4b125..f30105b 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.c
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.c
@@ -10,6 +10,7 @@
  */
 #include <linux/module.h>
 #include <linux/console.h>
+#include <linux/sysfb.h>
 #include <drm/drmP.h>
 
 #include "mgag200_drv.h"
@@ -41,29 +42,13 @@ static const struct pci_device_id pciidlist[] = {
 
 MODULE_DEVICE_TABLE(pci, pciidlist);
 
-static void mgag200_kick_out_firmware_fb(struct pci_dev *pdev)
-{
-	struct apertures_struct *ap;
-	bool primary = false;
-
-	ap = alloc_apertures(1);
-	if (!ap)
-		return;
-
-	ap->ranges[0].base = pci_resource_start(pdev, 0);
-	ap->ranges[0].size = pci_resource_len(pdev, 0);
-
-#ifdef CONFIG_X86
-	primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
-#endif
-	remove_conflicting_framebuffers(ap, "mgag200drmfb", primary);
-	kfree(ap);
-}
-
-
 static int mga_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-	mgag200_kick_out_firmware_fb(pdev);
+	int ret;
+
+	ret = sysfb_evict_conflicts_pci(pdev);
+	if (ret < 0)
+		return ret;
 
 	return drm_get_pci_dev(pdev, ent, &driver);
 }
diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c
index 13798b3..4723407 100644
--- a/drivers/gpu/drm/mgag200/mgag200_main.c
+++ b/drivers/gpu/drm/mgag200/mgag200_main.c
@@ -124,20 +124,11 @@ static int mga_probe_vram(struct mga_device *mdev, void __iomem *mem)
 static int mga_vram_init(struct mga_device *mdev)
 {
 	void __iomem *mem;
-	struct apertures_struct *aper = alloc_apertures(1);
-	if (!aper)
-		return -ENOMEM;
 
 	/* BAR 0 is VRAM */
 	mdev->mc.vram_base = pci_resource_start(mdev->dev->pdev, 0);
 	mdev->mc.vram_window = pci_resource_len(mdev->dev->pdev, 0);
 
-	aper->ranges[0].base = mdev->mc.vram_base;
-	aper->ranges[0].size = mdev->mc.vram_window;
-
-	remove_conflicting_framebuffers(aper, "mgafb", true);
-	kfree(aper);
-
 	if (!devm_request_mem_region(mdev->dev->dev, mdev->mc.vram_base, mdev->mc.vram_window,
 				"mgadrmfb_vram")) {
 		DRM_ERROR("can't reserve VRAM\n");
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 66c1280..193e833 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -27,6 +27,7 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/pm_runtime.h>
+#include <linux/sysfb.h>
 #include <linux/vga_switcheroo.h>
 
 #include "drmP.h"
@@ -310,8 +311,6 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
 			     const struct pci_device_id *pent)
 {
 	struct nvkm_device *device;
-	struct apertures_struct *aper;
-	bool boot = false;
 	int ret;
 
 	if (vga_switcheroo_client_probe_defer(pdev))
@@ -326,34 +325,12 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
 
 	nvkm_device_del(&device);
 
-	/* Remove conflicting drivers (vesafb, efifb etc). */
-	aper = alloc_apertures(3);
-	if (!aper)
-		return -ENOMEM;
-
-	aper->ranges[0].base = pci_resource_start(pdev, 1);
-	aper->ranges[0].size = pci_resource_len(pdev, 1);
-	aper->count = 1;
-
-	if (pci_resource_len(pdev, 2)) {
-		aper->ranges[aper->count].base = pci_resource_start(pdev, 2);
-		aper->ranges[aper->count].size = pci_resource_len(pdev, 2);
-		aper->count++;
-	}
-
-	if (pci_resource_len(pdev, 3)) {
-		aper->ranges[aper->count].base = pci_resource_start(pdev, 3);
-		aper->ranges[aper->count].size = pci_resource_len(pdev, 3);
-		aper->count++;
+	if (nouveau_modeset != 2) {
+		ret = sysfb_evict_conflicts_pci(pdev);
+		if (ret < 0)
+			return ret;
 	}
 
-#ifdef CONFIG_X86
-	boot = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
-#endif
-	if (nouveau_modeset != 2)
-		remove_conflicting_framebuffers(aper, "nouveaufb", boot);
-	kfree(aper);
-
 	ret = nvkm_device_pci_new(pdev, nouveau_config, nouveau_debug,
 				  true, true, ~0ULL, &device);
 	if (ret)
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index c01a7c6..a0c11bd 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -37,6 +37,7 @@
 #include <linux/console.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
+#include <linux/sysfb.h>
 #include <linux/vga_switcheroo.h>
 #include <drm/drm_gem.h>
 
@@ -309,27 +310,6 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
 
 static struct drm_driver kms_driver;
 
-static int radeon_kick_out_firmware_fb(struct pci_dev *pdev)
-{
-	struct apertures_struct *ap;
-	bool primary = false;
-
-	ap = alloc_apertures(1);
-	if (!ap)
-		return -ENOMEM;
-
-	ap->ranges[0].base = pci_resource_start(pdev, 0);
-	ap->ranges[0].size = pci_resource_len(pdev, 0);
-
-#ifdef CONFIG_X86
-	primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
-#endif
-	remove_conflicting_framebuffers(ap, "radeondrmfb", primary);
-	kfree(ap);
-
-	return 0;
-}
-
 static int radeon_pci_probe(struct pci_dev *pdev,
 			    const struct pci_device_id *ent)
 {
@@ -347,7 +327,7 @@ static int radeon_pci_probe(struct pci_dev *pdev,
 		return -EPROBE_DEFER;
 
 	/* Get rid of things like offb */
-	ret = radeon_kick_out_firmware_fb(pdev);
+	ret = sysfb_evict_conflicts_pci(pdev);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index 7092daa..ac388b5 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -12,6 +12,7 @@
 
 #include <linux/component.h>
 #include <linux/of_graph.h>
+#include <linux/sysfb.h>
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
@@ -97,28 +98,16 @@ static struct drm_driver sun4i_drv_driver = {
 	.disable_vblank		= sun4i_drv_disable_vblank,
 };
 
-static void sun4i_remove_framebuffers(void)
-{
-	struct apertures_struct *ap;
-
-	ap = alloc_apertures(1);
-	if (!ap)
-		return;
-
-	/* The framebuffer can be located anywhere in RAM */
-	ap->ranges[0].base = 0;
-	ap->ranges[0].size = ~0;
-
-	remove_conflicting_framebuffers(ap, "sun4i-drm-fb", false);
-	kfree(ap);
-}
-
 static int sun4i_drv_bind(struct device *dev)
 {
 	struct drm_device *drm;
 	struct sun4i_drv *drv;
 	int ret;
 
+	ret = sysfb_evict_conflicts_firmware();
+	if (ret < 0)
+		return ret;
+
 	drm = drm_dev_alloc(&sun4i_drv_driver, dev);
 	if (!drm)
 		return -ENOMEM;
@@ -156,9 +145,6 @@ static int sun4i_drv_bind(struct device *dev)
 	}
 	drm->irq_enabled = true;
 
-	/* Remove early framebuffers (ie. simplefb) */
-	sun4i_remove_framebuffers();
-
 	/* Create our framebuffer */
 	drv->fbdev = sun4i_framebuffer_init(drm);
 	if (IS_ERR(drv->fbdev)) {
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index 8b42d31..679e65a 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -15,6 +15,7 @@
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/sysfb.h>
 #include "drm_fb_cma_helper.h"
 
 #include "uapi/drm/vc4_drm.h"
@@ -200,24 +201,6 @@ static void vc4_match_add_drivers(struct device *dev,
 	}
 }
 
-static void vc4_kick_out_firmware_fb(void)
-{
-	struct apertures_struct *ap;
-
-	ap = alloc_apertures(1);
-	if (!ap)
-		return;
-
-	/* Since VC4 is a UMA device, the simplefb node may have been
-	 * located anywhere in memory.
-	 */
-	ap->ranges[0].base = 0;
-	ap->ranges[0].size = ~0;
-
-	remove_conflicting_framebuffers(ap, "vc4drmfb", false);
-	kfree(ap);
-}
-
 static int vc4_drm_bind(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
@@ -225,6 +208,10 @@ static int vc4_drm_bind(struct device *dev)
 	struct vc4_dev *vc4;
 	int ret = 0;
 
+	ret = sysfb_evict_conflicts_firmware();
+	if (ret < 0)
+		return ret;
+
 	dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
 	vc4 = devm_kzalloc(dev, sizeof(*vc4), GFP_KERNEL);
@@ -248,8 +235,6 @@ static int vc4_drm_bind(struct device *dev)
 	if (ret)
 		goto gem_destroy;
 
-	vc4_kick_out_firmware_fb();
-
 	ret = drm_dev_register(drm, 0);
 	if (ret < 0)
 		goto unbind_all;
diff --git a/drivers/gpu/drm/virtio/virtgpu_drm_bus.c b/drivers/gpu/drm/virtio/virtgpu_drm_bus.c
index 7f0e93f87..d6a8a94 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drm_bus.c
+++ b/drivers/gpu/drm/virtio/virtgpu_drm_bus.c
@@ -24,29 +24,10 @@
  */
 
 #include <linux/pci.h>
+#include <linux/sysfb.h>
 
 #include "virtgpu_drv.h"
 
-static void virtio_pci_kick_out_firmware_fb(struct pci_dev *pci_dev)
-{
-	struct apertures_struct *ap;
-	bool primary;
-
-	ap = alloc_apertures(1);
-	if (!ap)
-		return;
-
-	ap->ranges[0].base = pci_resource_start(pci_dev, 0);
-	ap->ranges[0].size = pci_resource_len(pci_dev, 0);
-
-	primary = pci_dev->resource[PCI_ROM_RESOURCE].flags
-		& IORESOURCE_ROM_SHADOW;
-
-	remove_conflicting_framebuffers(ap, "virtiodrmfb", primary);
-
-	kfree(ap);
-}
-
 int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev)
 {
 	struct drm_device *dev;
@@ -65,8 +46,7 @@ int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev)
 		DRM_INFO("pci: %s detected\n",
 			 vga ? "virtio-vga" : "virtio-gpu-pci");
 		dev->pdev = pdev;
-		if (vga)
-			virtio_pci_kick_out_firmware_fb(pdev);
+		sysfb_evict_conflicts_pci(pdev);
 	}
 
 	ret = drm_dev_register(dev, 0);
-- 
2.9.3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v5 6/7] drm: add SimpleDRM driver
  2016-09-02  8:22 [PATCH v5 0/7] drm: add simpledrm driver David Herrmann
                   ` (4 preceding siblings ...)
  2016-09-02  8:22 ` [PATCH v5 5/7] drm: switch to sysfb_evict_conflicts() David Herrmann
@ 2016-09-02  8:22 ` David Herrmann
  2016-09-02 12:45   ` Tom Gundersen
                     ` (2 more replies)
  2016-09-02  8:22 ` [PATCH v5 7/7] drm/simpledrm: add fbdev fallback support David Herrmann
  2021-03-10  2:50 ` [PATCH v5 0/7] drm: add simpledrm driver nerdopolis
  7 siblings, 3 replies; 31+ messages in thread
From: David Herrmann @ 2016-09-02  8:22 UTC (permalink / raw)
  To: dri-devel

The SimpleDRM driver binds to simple-framebuffer devices and provides a
DRM/KMS API. It provides only a single CRTC+encoder+connector combination
plus one initial mode.

Userspace can create dumb-buffers which can be blit into the real
framebuffer similar to UDL. No access to the real framebuffer is allowed
(compared to earlier version of this driver) to avoid security issues.
Furthermore, this way we can support arbitrary modes as long as we have a
conversion-helper.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 MAINTAINERS                                  |   6 +
 drivers/gpu/drm/Kconfig                      |   2 +
 drivers/gpu/drm/Makefile                     |   1 +
 drivers/gpu/drm/simpledrm/Kconfig            |  19 ++
 drivers/gpu/drm/simpledrm/Makefile           |   8 +
 drivers/gpu/drm/simpledrm/simpledrm.h        |  83 +++++
 drivers/gpu/drm/simpledrm/simpledrm_damage.c | 194 +++++++++++
 drivers/gpu/drm/simpledrm/simpledrm_drv.c    | 464 +++++++++++++++++++++++++++
 drivers/gpu/drm/simpledrm/simpledrm_gem.c    | 109 +++++++
 drivers/gpu/drm/simpledrm/simpledrm_kms.c    | 263 +++++++++++++++
 drivers/gpu/drm/simpledrm/simpledrm_of.c     | 265 +++++++++++++++
 11 files changed, 1414 insertions(+)
 create mode 100644 drivers/gpu/drm/simpledrm/Kconfig
 create mode 100644 drivers/gpu/drm/simpledrm/Makefile
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm.h
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_damage.c
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_drv.c
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_gem.c
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_kms.c
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_of.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 0bbe4b1..408863d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4140,6 +4140,12 @@ S:	Orphan / Obsolete
 F:	drivers/gpu/drm/savage/
 F:	include/uapi/drm/savage_drm.h
 
+DRM DRIVER FOR SIMPLE FRAMEBUFFER DEVICES
+M:	David Herrmann <dh.herrmann@gmail.com>
+L:	dri-devel@lists.freedesktop.org
+S:	Maintained
+F:	drivers/gpu/drm/simpledrm/
+
 DRM DRIVER FOR SIS VIDEO CARDS
 S:	Orphan / Obsolete
 F:	drivers/gpu/drm/sis/
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index f27f9b5..61cbcd1 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -291,3 +291,5 @@ source "drivers/gpu/drm/arc/Kconfig"
 source "drivers/gpu/drm/hisilicon/Kconfig"
 
 source "drivers/gpu/drm/mediatek/Kconfig"
+
+source "drivers/gpu/drm/simpledrm/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 0238bf8..3e6fe99 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -83,3 +83,4 @@ obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/
 obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/
 obj-$(CONFIG_DRM_ARCPGU)+= arc/
 obj-y			+= hisilicon/
+obj-y			+= simpledrm/
diff --git a/drivers/gpu/drm/simpledrm/Kconfig b/drivers/gpu/drm/simpledrm/Kconfig
new file mode 100644
index 0000000..f45b25d
--- /dev/null
+++ b/drivers/gpu/drm/simpledrm/Kconfig
@@ -0,0 +1,19 @@
+config DRM_SIMPLEDRM
+	tristate "Simple firmware framebuffer DRM driver"
+	depends on DRM
+	select DRM_KMS_HELPER
+	help
+	  SimpleDRM can run on all systems with pre-initialized graphics
+	  hardware. It uses a framebuffer that was initialized during
+	  firmware boot. No page-flipping, modesetting or other advanced
+	  features are available. However, other DRM drivers can be loaded
+	  later and take over from SimpleDRM if they provide real hardware
+	  support.
+
+	  SimpleDRM supports "simple-framebuffer" DeviceTree objects and
+	  compatible platform framebuffers.
+
+	  If unsure, say Y.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called simpledrm.
diff --git a/drivers/gpu/drm/simpledrm/Makefile b/drivers/gpu/drm/simpledrm/Makefile
new file mode 100644
index 0000000..d7b179d
--- /dev/null
+++ b/drivers/gpu/drm/simpledrm/Makefile
@@ -0,0 +1,8 @@
+simpledrm-y := \
+	simpledrm_damage.o \
+	simpledrm_drv.o \
+	simpledrm_gem.o \
+	simpledrm_kms.o \
+	simpledrm_of.o
+
+obj-$(CONFIG_DRM_SIMPLEDRM) := simpledrm.o
diff --git a/drivers/gpu/drm/simpledrm/simpledrm.h b/drivers/gpu/drm/simpledrm/simpledrm.h
new file mode 100644
index 0000000..ed6d725
--- /dev/null
+++ b/drivers/gpu/drm/simpledrm/simpledrm.h
@@ -0,0 +1,83 @@
+#ifndef __SDRM_SIMPLEDRM_H
+#define __SDRM_SIMPLEDRM_H
+
+/*
+ * Copyright (C) 2012-2016 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_simple_kms_helper.h>
+#include <linux/atomic.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+
+struct clk;
+struct regulator;
+struct simplefb_format;
+
+struct sdrm_hw {
+	struct mutex lock;
+	u32 width;
+	u32 height;
+	u32 stride;
+	u32 bpp;
+	u32 format;
+	unsigned long base;
+	unsigned long size;
+	void *map;
+};
+
+struct sdrm_bo {
+	struct drm_gem_object base;
+	struct page **pages;
+	void *vmapping;
+};
+
+struct sdrm_fb {
+	struct drm_framebuffer base;
+	struct sdrm_bo *bo;
+};
+
+struct sdrm_device {
+	atomic_t n_used;
+	struct drm_device *ddev;
+	struct sdrm_hw *hw;
+
+	size_t n_clks;
+	size_t n_regulators;
+	struct clk **clks;
+	struct regulator **regulators;
+
+	struct drm_simple_display_pipe pipe;
+	struct drm_connector conn;
+};
+
+void sdrm_of_bootstrap(void);
+int sdrm_of_bind(struct sdrm_device *sdrm);
+void sdrm_of_unbind(struct sdrm_device *sdrm);
+
+int sdrm_kms_bind(struct sdrm_device *sdrm);
+void sdrm_kms_unbind(struct sdrm_device *sdrm);
+
+void sdrm_dirty(struct sdrm_fb *fb, u32 x, u32 y, u32 width, u32 height);
+
+struct sdrm_bo *sdrm_bo_new(struct drm_device *ddev, size_t size);
+void sdrm_bo_free(struct drm_gem_object *obj);
+int sdrm_bo_vmap(struct sdrm_bo *bo);
+
+int sdrm_dumb_create(struct drm_file *dfile,
+		     struct drm_device *ddev,
+		     struct drm_mode_create_dumb *arg);
+int sdrm_dumb_map_offset(struct drm_file *dfile,
+			 struct drm_device *ddev,
+			 uint32_t handle,
+			 uint64_t *offset);
+
+#endif /* __SDRM_SIMPLEDRM_H */
diff --git a/drivers/gpu/drm/simpledrm/simpledrm_damage.c b/drivers/gpu/drm/simpledrm/simpledrm_damage.c
new file mode 100644
index 0000000..4f7af5d
--- /dev/null
+++ b/drivers/gpu/drm/simpledrm/simpledrm_damage.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2012-2016 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <asm/unaligned.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <linux/kernel.h>
+#include "simpledrm.h"
+
+static inline void sdrm_put(u8 *dst, u32 four_cc, u16 r, u16 g, u16 b)
+{
+	switch (four_cc) {
+	case DRM_FORMAT_RGB565:
+		r >>= 11;
+		g >>= 10;
+		b >>= 11;
+		put_unaligned((u16)((r << 11) | (g << 5) | b), (u16 *)dst);
+		break;
+	case DRM_FORMAT_XRGB1555:
+	case DRM_FORMAT_ARGB1555:
+		r >>= 11;
+		g >>= 11;
+		b >>= 11;
+		put_unaligned((u16)((r << 10) | (g << 5) | b), (u16 *)dst);
+		break;
+	case DRM_FORMAT_RGB888:
+		r >>= 8;
+		g >>= 8;
+		b >>= 8;
+#ifdef __LITTLE_ENDIAN
+		dst[2] = r;
+		dst[1] = g;
+		dst[0] = b;
+#elif defined(__BIG_ENDIAN)
+		dst[0] = r;
+		dst[1] = g;
+		dst[2] = b;
+#endif
+		break;
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ARGB8888:
+		r >>= 8;
+		g >>= 8;
+		b >>= 8;
+		put_unaligned((u32)((r << 16) | (g << 8) | b), (u32 *)dst);
+		break;
+	case DRM_FORMAT_ABGR8888:
+		r >>= 8;
+		g >>= 8;
+		b >>= 8;
+		put_unaligned((u32)((b << 16) | (g << 8) | r), (u32 *)dst);
+		break;
+	case DRM_FORMAT_XRGB2101010:
+	case DRM_FORMAT_ARGB2101010:
+		r >>= 4;
+		g >>= 4;
+		b >>= 4;
+		put_unaligned((u32)((r << 20) | (g << 10) | b), (u32 *)dst);
+		break;
+	}
+}
+
+static void sdrm_blit_from_xrgb8888(const u8 *src,
+				    u32 src_stride,
+				    u32 src_bpp,
+				    u8 *dst,
+				    u32 dst_stride,
+				    u32 dst_bpp,
+				    u32 dst_four_cc,
+				    u32 width,
+				    u32 height)
+{
+	u32 val, i;
+
+	while (height--) {
+		for (i = 0; i < width; ++i) {
+			val = get_unaligned((const u32 *)&src[i * src_bpp]);
+			sdrm_put(&dst[i * dst_bpp], dst_four_cc,
+				 (val & 0x00ff0000U) >> 8,
+				 (val & 0x0000ff00U),
+				 (val & 0x000000ffU) << 8);
+		}
+
+		src += src_stride;
+		dst += dst_stride;
+	}
+}
+
+static void sdrm_blit_from_rgb565(const u8 *src,
+				  u32 src_stride,
+				  u32 src_bpp,
+				  u8 *dst,
+				  u32 dst_stride,
+				  u32 dst_bpp,
+				  u32 dst_four_cc,
+				  u32 width,
+				  u32 height)
+{
+	u32 val, i;
+
+	while (height--) {
+		for (i = 0; i < width; ++i) {
+			val = get_unaligned((const u16 *)&src[i * src_bpp]);
+			sdrm_put(&dst[i * dst_bpp], dst_four_cc,
+				 (val & 0xf800),
+				 (val & 0x07e0) << 5,
+				 (val & 0x001f) << 11);
+		}
+
+		src += src_stride;
+		dst += dst_stride;
+	}
+}
+
+static void sdrm_blit_lines(const u8 *src,
+			    u32 src_stride,
+			    u8 *dst,
+			    u32 dst_stride,
+			    u32 bpp,
+			    u32 width,
+			    u32 height)
+{
+	u32 len;
+
+	len = width * bpp;
+
+	while (height--) {
+		memcpy(dst, src, len);
+		src += src_stride;
+		dst += dst_stride;
+	}
+}
+
+static void sdrm_blit(struct sdrm_hw *hw,
+		      struct sdrm_fb *fb,
+		      u32 x,
+		      u32 y,
+		      u32 width,
+		      u32 height)
+{
+	u32 src_bpp, dst_bpp;
+	u8 *src, *dst;
+
+	src = fb->bo->vmapping;
+	src_bpp = DIV_ROUND_UP(fb->base.bits_per_pixel, 8);
+	src += fb->base.offsets[0] + y * fb->base.pitches[0] + x * src_bpp;
+
+	dst = hw->map;
+	dst_bpp = DIV_ROUND_UP(hw->bpp, 8);
+	dst += y * hw->stride + x * dst_bpp;
+
+	if (fb->base.pixel_format == hw->format) {
+		/* if formats are identical, do a line-by-line copy.. */
+		sdrm_blit_lines(src, fb->base.pitches[0],
+				dst, hw->stride, src_bpp, width, height);
+	} else {
+		/* ..otherwise call slow blit-function */
+		switch (fb->base.pixel_format) {
+		case DRM_FORMAT_ARGB8888:
+		case DRM_FORMAT_XRGB8888:
+			sdrm_blit_from_xrgb8888(src, fb->base.pitches[0],
+						src_bpp, dst, hw->stride,
+						dst_bpp, hw->format,
+						width, height);
+			break;
+		case DRM_FORMAT_RGB565:
+			sdrm_blit_from_rgb565(src, fb->base.pitches[0],
+					      src_bpp, dst, hw->stride,
+					      dst_bpp, hw->format,
+					      width, height);
+			break;
+		}
+	}
+}
+
+void sdrm_dirty(struct sdrm_fb *fb, u32 x, u32 y, u32 width, u32 height)
+{
+	struct sdrm_device *sdrm = fb->base.dev->dev_private;
+
+	if (WARN_ON(!fb->bo->vmapping))
+		return;
+
+	mutex_lock(&sdrm->hw->lock);
+	if (sdrm->hw->map)
+		sdrm_blit(sdrm->hw, fb, x, y, width, height);
+	mutex_unlock(&sdrm->hw->lock);
+}
diff --git a/drivers/gpu/drm/simpledrm/simpledrm_drv.c b/drivers/gpu/drm/simpledrm/simpledrm_drv.c
new file mode 100644
index 0000000..d569120
--- /dev/null
+++ b/drivers/gpu/drm/simpledrm/simpledrm_drv.c
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2012-2016 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <drm/drmP.h>
+#include <linux/atomic.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_data/simplefb.h>
+#include <linux/string.h>
+#include "simpledrm.h"
+
+static struct drm_driver sdrm_drm_driver;
+static DEFINE_MUTEX(sdrm_lock);
+
+static int sdrm_hw_identify(struct platform_device *pdev,
+			    struct simplefb_platform_data *modep,
+			    struct simplefb_format *formatp,
+			    struct resource **memp,
+			    u32 *bppp)
+{
+	static const struct simplefb_format valid_formats[] = SIMPLEFB_FORMATS;
+	struct simplefb_platform_data pm = {}, *mode = pdev->dev.platform_data;
+	struct device_node *np = pdev->dev.of_node;
+	const struct simplefb_format *format = NULL;
+	struct resource *mem;
+	unsigned int depth;
+	int r, bpp;
+	size_t i;
+
+	if (!mode) {
+		if (!np)
+			return -ENODEV;
+
+		mode = &pm;
+
+		r = of_property_read_u32(np, "width", &mode->width);
+		if (r >= 0)
+			r = of_property_read_u32(np, "height", &mode->height);
+		if (r >= 0)
+			r = of_property_read_u32(np, "stride", &mode->stride);
+		if (r >= 0)
+			r = of_property_read_string(np, "format",
+						    &mode->format);
+		if (r < 0)
+			return r;
+	}
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem)
+		return -ENODEV;
+
+	for (i = 0; i < ARRAY_SIZE(valid_formats); ++i) {
+		if (!strcmp(mode->format, valid_formats[i].name)) {
+			format = &valid_formats[i];
+			break;
+		}
+	}
+
+	if (!format)
+		return -ENODEV;
+
+	switch (format->fourcc) {
+	case DRM_FORMAT_RGB565:
+	case DRM_FORMAT_XRGB1555:
+	case DRM_FORMAT_ARGB1555:
+	case DRM_FORMAT_RGB888:
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_ABGR8888:
+	case DRM_FORMAT_XRGB2101010:
+	case DRM_FORMAT_ARGB2101010:
+		/*
+		 * You must adjust sdrm_put() whenever you add a new format
+		 * here, otherwise, blitting operations will not work.
+		 * Furthermore, include/linux/platform_data/simplefb.h needs
+		 * to be adjusted so the platform-device actually allows this
+		 * format.
+		 */
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	drm_fb_get_bpp_depth(format->fourcc, &depth, &bpp);
+	if (!bpp)
+		return -ENODEV;
+	if (resource_size(mem) < mode->stride * mode->height)
+		return -ENODEV;
+	if ((bpp + 7) / 8 * mode->width > mode->stride)
+		return -ENODEV;
+
+	*modep = *mode;
+	*formatp = *format;
+	*memp = mem;
+	*bppp = bpp;
+	return 0;
+}
+
+static struct sdrm_hw *sdrm_hw_new(const struct simplefb_platform_data *mode,
+				   const struct simplefb_format *format,
+				   const struct resource *mem,
+				   u32 bpp)
+{
+	struct sdrm_hw *hw;
+
+	hw = kzalloc(sizeof(*hw), GFP_KERNEL);
+	if (!hw)
+		return ERR_PTR(-ENOMEM);
+
+	mutex_init(&hw->lock);
+	hw->width = mode->width;
+	hw->height = mode->height;
+	hw->stride = mode->stride;
+	hw->bpp = bpp;
+	hw->format = format->fourcc;
+	hw->base = mem->start;
+	hw->size = resource_size(mem);
+
+	return hw;
+}
+
+static struct sdrm_hw *sdrm_hw_free(struct sdrm_hw *hw)
+{
+	if (!hw)
+		return NULL;
+
+	WARN_ON(hw->map);
+	mutex_destroy(&hw->lock);
+	kfree(hw);
+
+	return NULL;
+}
+
+static int sdrm_hw_bind(struct sdrm_hw *hw)
+{
+	mutex_lock(&hw->lock);
+	if (!hw->map)
+		hw->map = ioremap_wc(hw->base, hw->size);
+	mutex_unlock(&hw->lock);
+
+	return hw->map ? 0 : -EIO;
+}
+
+static void sdrm_hw_unbind(struct sdrm_hw *hw)
+{
+	if (!hw)
+		return;
+
+	mutex_lock(&hw->lock);
+	if (hw->map) {
+		iounmap(hw->map);
+		hw->map = NULL;
+	}
+	mutex_unlock(&hw->lock);
+}
+
+static struct sdrm_device *sdrm_device_free(struct sdrm_device *sdrm)
+{
+	if (!sdrm)
+		return NULL;
+
+	WARN_ON(atomic_read(&sdrm->n_used) != INT_MIN);
+	sdrm->hw = sdrm_hw_free(sdrm->hw);
+	drm_dev_unref(sdrm->ddev);
+	kfree(sdrm);
+
+	return NULL;
+}
+
+static struct sdrm_device *sdrm_device_new(struct platform_device *pdev,
+					   struct sdrm_hw *hw)
+{
+	struct sdrm_device *sdrm;
+	int r;
+
+	sdrm = kzalloc(sizeof(*sdrm), GFP_KERNEL);
+	if (!sdrm)
+		return ERR_PTR(-ENOMEM);
+
+	atomic_set(&sdrm->n_used, INT_MIN);
+
+	sdrm->ddev = drm_dev_alloc(&sdrm_drm_driver, &pdev->dev);
+	if (!sdrm->ddev) {
+		r = -ENOMEM;
+		goto error;
+	}
+
+	sdrm->ddev->dev_private = sdrm;
+	sdrm->hw = hw;
+
+	return sdrm;
+
+error:
+	sdrm_device_free(sdrm);
+	return ERR_PTR(r);
+}
+
+static void sdrm_device_unbind(struct sdrm_device *sdrm)
+{
+	if (sdrm) {
+		sdrm_kms_unbind(sdrm);
+		sdrm_hw_unbind(sdrm->hw);
+		sdrm_of_unbind(sdrm);
+	}
+}
+
+static int sdrm_device_bind(struct sdrm_device *sdrm)
+{
+	int r;
+
+	r = sdrm_of_bind(sdrm);
+	if (r < 0)
+		goto error;
+
+	r = sdrm_hw_bind(sdrm->hw);
+	if (r < 0)
+		goto error;
+
+	r = sdrm_kms_bind(sdrm);
+	if (r < 0)
+		goto error;
+
+	return 0;
+
+error:
+	sdrm_device_unbind(sdrm);
+	return r;
+}
+
+static int sdrm_device_acquire(struct sdrm_device *sdrm)
+{
+	return (sdrm && atomic_inc_unless_negative(&sdrm->n_used))
+		? 0 : -ENODEV;
+}
+
+static void sdrm_device_release(struct sdrm_device *sdrm)
+{
+	if (sdrm && atomic_dec_return(&sdrm->n_used) == INT_MIN) {
+		sdrm_device_unbind(sdrm);
+		sdrm_device_free(sdrm);
+	}
+}
+
+static int sdrm_fop_open(struct inode *inode, struct file *file)
+{
+	struct drm_device *ddev;
+	int r;
+
+	mutex_lock(&sdrm_lock);
+	r = drm_open(inode, file);
+	if (r >= 0) {
+		ddev = file->private_data;
+		r = sdrm_device_acquire(ddev->dev_private);
+		if (r < 0)
+			drm_release(inode, file);
+	}
+	mutex_unlock(&sdrm_lock);
+
+	return r;
+}
+
+static int sdrm_fop_release(struct inode *inode, struct file *file)
+{
+	struct drm_file *dfile = file->private_data;
+	struct drm_device *ddev = dfile->minor->dev;
+	struct sdrm_device *sdrm = ddev->dev_private;
+	int res;
+
+	res = drm_release(inode, file);
+	sdrm_device_release(sdrm);
+	return res;
+}
+
+static int sdrm_fop_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct drm_file *dfile = file->private_data;
+	struct drm_device *dev = dfile->minor->dev;
+	struct drm_gem_object *obj = NULL;
+	struct drm_vma_offset_node *node;
+	int r;
+
+	drm_vma_offset_lock_lookup(dev->vma_offset_manager);
+	node = drm_vma_offset_exact_lookup_locked(dev->vma_offset_manager,
+						  vma->vm_pgoff,
+						  vma_pages(vma));
+	if (likely(node)) {
+		obj = container_of(node, struct drm_gem_object, vma_node);
+		if (!kref_get_unless_zero(&obj->refcount))
+			obj = NULL;
+	}
+	drm_vma_offset_unlock_lookup(dev->vma_offset_manager);
+
+	if (!obj)
+		return -EINVAL;
+
+	if (!drm_vma_node_is_allowed(node, dfile)) {
+		drm_gem_object_unreference_unlocked(obj);
+		return -EACCES;
+	}
+
+	if (vma->vm_file)
+		fput(vma->vm_file);
+	vma->vm_file = get_file(obj->filp);
+	vma->vm_pgoff = 0;
+
+	r = obj->filp->f_op->mmap(obj->filp, vma);
+	drm_gem_object_unreference_unlocked(obj);
+	return r;
+}
+
+static int sdrm_simplefb_probe(struct platform_device *pdev)
+{
+	struct simplefb_platform_data hw_mode;
+	struct simplefb_format hw_format;
+	struct sdrm_device *sdrm = NULL;
+	struct sdrm_hw *hw = NULL;
+	struct resource *hw_mem;
+	u32 hw_bpp;
+	int r;
+
+	r = sdrm_hw_identify(pdev, &hw_mode, &hw_format, &hw_mem, &hw_bpp);
+	if (r < 0)
+		goto error;
+
+	hw = sdrm_hw_new(&hw_mode, &hw_format, hw_mem, hw_bpp);
+	if (IS_ERR(hw)) {
+		r = PTR_ERR(hw);
+		hw = NULL;
+		goto error;
+	}
+
+	sdrm = sdrm_device_new(pdev, hw);
+	if (IS_ERR(sdrm)) {
+		r = PTR_ERR(sdrm);
+		sdrm = NULL;
+		goto error;
+	}
+	hw = NULL;
+	platform_set_drvdata(pdev, sdrm);
+
+	r = sdrm_device_bind(sdrm);
+	if (r < 0)
+		goto error;
+
+	/* mark device as enabled and acquire bus ref */
+	WARN_ON(atomic_read(&sdrm->n_used) != INT_MIN);
+	atomic_set(&sdrm->n_used, 1);
+
+	r = drm_dev_register(sdrm->ddev, 0);
+	if (r < 0) {
+		/* mark device as disabled and drop bus ref */
+		WARN_ON(atomic_add_return(INT_MIN, &sdrm->n_used) != INT_MIN);
+		sdrm_device_release(sdrm);
+		return r;
+	}
+
+	dev_info(sdrm->ddev->dev, "initialized %s on minor %d\n",
+		 sdrm->ddev->driver->name, sdrm->ddev->primary->index);
+
+	return 0;
+
+error:
+	sdrm_device_unbind(sdrm);
+	sdrm_device_free(sdrm);
+	sdrm_hw_free(hw);
+	return r;
+}
+
+static int sdrm_simplefb_remove(struct platform_device *pdev)
+{
+	struct sdrm_device *sdrm = platform_get_drvdata(pdev);
+
+	/* mark device as disabled */
+	atomic_add(INT_MIN, &sdrm->n_used);
+	sdrm_hw_unbind(sdrm->hw);
+
+	mutex_lock(&sdrm_lock);
+	drm_dev_unregister(sdrm->ddev);
+	sdrm_device_release(sdrm);
+	mutex_unlock(&sdrm_lock);
+
+	return 0;
+}
+
+static const struct file_operations sdrm_drm_fops = {
+	.owner = THIS_MODULE,
+	.open = sdrm_fop_open,
+	.release = sdrm_fop_release,
+	.mmap = sdrm_fop_mmap,
+	.poll = drm_poll,
+	.read = drm_read,
+	.unlocked_ioctl = drm_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = drm_compat_ioctl,
+#endif
+	.llseek = noop_llseek,
+};
+
+static struct drm_driver sdrm_drm_driver = {
+	.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
+	.fops = &sdrm_drm_fops,
+
+	.gem_free_object = sdrm_bo_free,
+
+	.dumb_create = sdrm_dumb_create,
+	.dumb_map_offset = sdrm_dumb_map_offset,
+	.dumb_destroy = drm_gem_dumb_destroy,
+
+	.name = "simpledrm",
+	.desc = "Simple firmware framebuffer DRM driver",
+	.date = "20160901",
+};
+
+static const struct of_device_id sdrm_simplefb_of_match[] = {
+	{ .compatible = "simple-framebuffer", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, sdrm_simplefb_of_match);
+
+static struct platform_driver sdrm_simplefb_driver = {
+	.probe = sdrm_simplefb_probe,
+	.remove = sdrm_simplefb_remove,
+	.driver = {
+		.name = "simple-framebuffer",
+		.mod_name = KBUILD_MODNAME,
+		.owner = THIS_MODULE,
+		.of_match_table = sdrm_simplefb_of_match,
+	},
+};
+
+static int __init sdrm_init(void)
+{
+	int r;
+
+	r = platform_driver_register(&sdrm_simplefb_driver);
+	if (r < 0)
+		return r;
+
+	sdrm_of_bootstrap();
+	return 0;
+}
+
+static void __exit sdrm_exit(void)
+{
+	platform_driver_unregister(&sdrm_simplefb_driver);
+}
+
+module_init(sdrm_init);
+module_exit(sdrm_exit);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Simple firmware framebuffer DRM driver");
+MODULE_ALIAS("platform:simple-framebuffer");
diff --git a/drivers/gpu/drm/simpledrm/simpledrm_gem.c b/drivers/gpu/drm/simpledrm/simpledrm_gem.c
new file mode 100644
index 0000000..4aaae6e
--- /dev/null
+++ b/drivers/gpu/drm/simpledrm/simpledrm_gem.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2012-2016 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <drm/drmP.h>
+#include <drm/drm_gem.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include "simpledrm.h"
+
+struct sdrm_bo *sdrm_bo_new(struct drm_device *ddev, size_t size)
+{
+	struct sdrm_bo *bo;
+
+	WARN_ON(!size || (size & ~PAGE_MASK) != 0);
+
+	bo = kzalloc(sizeof(*bo), GFP_KERNEL);
+	if (!bo)
+		return NULL;
+
+	if (drm_gem_object_init(ddev, &bo->base, size)) {
+		kfree(bo);
+		return NULL;
+	}
+
+	return bo;
+}
+
+void sdrm_bo_free(struct drm_gem_object *dobj)
+{
+	struct sdrm_bo *bo = container_of(dobj, struct sdrm_bo, base);
+
+	if (bo->vmapping)
+		vunmap(bo->vmapping);
+	if (bo->pages)
+		drm_gem_put_pages(dobj, bo->pages, false, false);
+	drm_gem_object_release(dobj);
+	kfree(bo);
+}
+
+int sdrm_bo_vmap(struct sdrm_bo *bo)
+{
+	int r;
+
+	if (!bo->pages) {
+		bo->pages = drm_gem_get_pages(&bo->base);
+		if (IS_ERR(bo->pages)) {
+			r = PTR_ERR(bo->pages);
+			bo->pages = NULL;
+			return r;
+		}
+	}
+
+	if (!bo->vmapping) {
+		bo->vmapping = vmap(bo->pages, bo->base.size / PAGE_SIZE, 0,
+				    PAGE_KERNEL);
+		if (!bo->vmapping)
+			return -ENOMEM;
+	}
+
+	return 0;
+}
+
+int sdrm_dumb_create(struct drm_file *dfile,
+		     struct drm_device *ddev,
+		     struct drm_mode_create_dumb *args)
+{
+	struct sdrm_bo *bo;
+	int r;
+
+	/* overflow checks are done by DRM core */
+	args->pitch = (args->bpp + 7) / 8 * args->width;
+	args->size = PAGE_ALIGN(args->pitch * args->height);
+
+	bo = sdrm_bo_new(ddev, args->size);
+	if (!bo)
+		return -ENOMEM;
+
+	r = drm_gem_handle_create(dfile, &bo->base, &args->handle);
+	drm_gem_object_unreference_unlocked(&bo->base);
+	return r;
+}
+
+int sdrm_dumb_map_offset(struct drm_file *dfile,
+			 struct drm_device *ddev,
+			 uint32_t handle,
+			 uint64_t *offset)
+{
+	struct drm_gem_object *dobj;
+	int r;
+
+	dobj = drm_gem_object_lookup(dfile, handle);
+	if (!dobj)
+		return -ENOENT;
+
+	r = drm_gem_create_mmap_offset(dobj);
+	if (r >= 0)
+		*offset = drm_vma_node_offset_addr(&dobj->vma_node);
+	drm_gem_object_unreference_unlocked(dobj);
+	return r;
+}
diff --git a/drivers/gpu/drm/simpledrm/simpledrm_kms.c b/drivers/gpu/drm/simpledrm/simpledrm_kms.c
new file mode 100644
index 0000000..00101c9
--- /dev/null
+++ b/drivers/gpu/drm/simpledrm/simpledrm_kms.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2012-2016 Red Hat, Inc.
+ * Copyright (C) 2016 Noralf Trønnes
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_simple_kms_helper.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include "simpledrm.h"
+
+static const uint32_t sdrm_formats[] = {
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_XRGB8888,
+};
+
+static int sdrm_conn_get_modes(struct drm_connector *conn)
+{
+	struct sdrm_device *sdrm = conn->dev->dev_private;
+	struct drm_display_mode *mode;
+
+	mode = drm_cvt_mode(sdrm->ddev, sdrm->hw->width, sdrm->hw->height,
+			    60, false, false, false);
+	if (!mode)
+		return 0;
+
+	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+	drm_mode_set_name(mode);
+	drm_mode_probed_add(conn, mode);
+
+	return 1;
+}
+
+static const struct drm_connector_helper_funcs sdrm_conn_hfuncs = {
+	.get_modes	= sdrm_conn_get_modes,
+	.best_encoder	= drm_atomic_helper_best_encoder,
+};
+
+static enum drm_connector_status sdrm_conn_detect(struct drm_connector *conn,
+						  bool force)
+{
+	/*
+	 * We simulate an always connected monitor. simple-fb doesn't
+	 * provide any way to detect whether the connector is active. Hence,
+	 * signal DRM core that it is always connected.
+	 */
+	return connector_status_connected;
+}
+
+static const struct drm_connector_funcs sdrm_conn_ops = {
+	.dpms			= drm_atomic_helper_connector_dpms,
+	.reset			= drm_atomic_helper_connector_reset,
+	.detect			= sdrm_conn_detect,
+	.fill_modes		= drm_helper_probe_single_connector_modes,
+	.destroy		= drm_connector_cleanup,
+	.atomic_duplicate_state	= drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,
+};
+
+static void sdrm_crtc_send_vblank_event(struct drm_crtc *crtc)
+{
+	if (crtc->state && crtc->state->event) {
+		spin_lock_irq(&crtc->dev->event_lock);
+		drm_crtc_send_vblank_event(crtc, crtc->state->event);
+		spin_unlock_irq(&crtc->dev->event_lock);
+		crtc->state->event = NULL;
+	}
+}
+
+void sdrm_display_pipe_update(struct drm_simple_display_pipe *pipe,
+			      struct drm_plane_state *plane_state)
+{
+	struct drm_framebuffer *dfb = pipe->plane.state->fb;
+	struct sdrm_fb *fb;
+
+	sdrm_crtc_send_vblank_event(&pipe->crtc);
+
+	if (dfb) {
+		fb = container_of(dfb, struct sdrm_fb, base);
+		pipe->plane.fb = dfb;
+		sdrm_dirty(fb, 0, 0, dfb->width, dfb->height);
+	}
+}
+
+static void sdrm_display_pipe_enable(struct drm_simple_display_pipe *pipe,
+				     struct drm_crtc_state *crtc_state)
+{
+	sdrm_crtc_send_vblank_event(&pipe->crtc);
+}
+
+static void sdrm_display_pipe_disable(struct drm_simple_display_pipe *pipe)
+{
+	sdrm_crtc_send_vblank_event(&pipe->crtc);
+}
+
+static const struct drm_simple_display_pipe_funcs sdrm_pipe_funcs = {
+	.update		= sdrm_display_pipe_update,
+	.enable		= sdrm_display_pipe_enable,
+	.disable	= sdrm_display_pipe_disable,
+};
+
+static int sdrm_fb_create_handle(struct drm_framebuffer *dfb,
+				 struct drm_file *dfile,
+				 unsigned int *handle)
+{
+	struct sdrm_fb *fb = container_of(dfb, struct sdrm_fb, base);
+
+	return drm_gem_handle_create(dfile, &fb->bo->base, handle);
+}
+
+static int sdrm_fb_dirty(struct drm_framebuffer *dfb,
+			 struct drm_file *dfile,
+			 unsigned int flags,
+			 unsigned int color,
+			 struct drm_clip_rect *clips,
+			 unsigned int n_clips)
+{
+	struct sdrm_fb *fb = container_of(dfb, struct sdrm_fb, base);
+	struct sdrm_device *sdrm = dfb->dev->dev_private;
+	unsigned int i;
+
+	drm_modeset_lock_all(sdrm->ddev);
+	if (dfb == sdrm->pipe.plane.fb) {
+		if (!clips || !n_clips) {
+			sdrm_dirty(fb, 0, 0, dfb->width, dfb->height);
+		} else {
+			for (i = 0; i < n_clips; i++) {
+				if (clips[i].x1 > clips[i].x2 ||
+				    clips[i].x2 > dfb->width ||
+				    clips[i].y1 > clips[i].y2 ||
+				    clips[i].y2 > dfb->height)
+					continue;
+
+				sdrm_dirty(fb, clips[i].x1, clips[i].y1,
+					   clips[i].x2 - clips[i].x1,
+					   clips[i].y2 - clips[i].y1);
+			}
+		}
+	}
+	drm_modeset_unlock_all(sdrm->ddev);
+
+	return 0;
+}
+
+static void sdrm_fb_destroy(struct drm_framebuffer *dfb)
+{
+	struct sdrm_fb *fb = container_of(dfb, struct sdrm_fb, base);
+
+	drm_framebuffer_cleanup(dfb);
+	drm_gem_object_unreference_unlocked(&fb->bo->base);
+	kfree(fb);
+}
+
+static const struct drm_framebuffer_funcs sdrm_fb_ops = {
+	.create_handle		= sdrm_fb_create_handle,
+	.dirty			= sdrm_fb_dirty,
+	.destroy		= sdrm_fb_destroy,
+};
+
+static struct drm_framebuffer *
+sdrm_fb_create(struct drm_device *ddev,
+	       struct drm_file *dfile,
+	       const struct drm_mode_fb_cmd2 *cmd)
+{
+	struct drm_gem_object *dobj;
+	struct sdrm_fb *fb = NULL;
+	struct sdrm_bo *bo;
+	int r;
+
+	if (cmd->flags)
+		return ERR_PTR(-EINVAL);
+
+	dobj = drm_gem_object_lookup(dfile, cmd->handles[0]);
+	if (!dobj)
+		return ERR_PTR(-EINVAL);
+
+	bo = container_of(dobj, struct sdrm_bo, base);
+
+	r = sdrm_bo_vmap(bo);
+	if (r < 0)
+		goto error;
+
+	fb = kzalloc(sizeof(*fb), GFP_KERNEL);
+	if (!fb) {
+		r = -ENOMEM;
+		goto error;
+	}
+
+	fb->bo = bo;
+	drm_helper_mode_fill_fb_struct(&fb->base, cmd);
+
+	r = drm_framebuffer_init(ddev, &fb->base, &sdrm_fb_ops);
+	if (r < 0)
+		goto error;
+
+	DRM_DEBUG_KMS("[FB:%d] pixel_format: %s\n", fb->base.base.id,
+		      drm_get_format_name(fb->base.pixel_format));
+
+	return &fb->base;
+
+error:
+	kfree(fb);
+	drm_gem_object_unreference_unlocked(dobj);
+	return ERR_PTR(r);
+}
+
+static const struct drm_mode_config_funcs sdrm_mode_config_ops = {
+	.fb_create		= sdrm_fb_create,
+	.atomic_check		= drm_atomic_helper_check,
+	.atomic_commit		= drm_atomic_helper_commit,
+};
+
+int sdrm_kms_bind(struct sdrm_device *sdrm)
+{
+	struct drm_connector *conn = &sdrm->conn;
+	struct drm_device *ddev = sdrm->ddev;
+	int r;
+
+	drm_mode_config_init(ddev);
+	ddev->mode_config.min_width = sdrm->hw->width;
+	ddev->mode_config.max_width = sdrm->hw->width;
+	ddev->mode_config.min_height = sdrm->hw->height;
+	ddev->mode_config.max_height = sdrm->hw->height;
+	ddev->mode_config.preferred_depth = sdrm->hw->bpp;
+	ddev->mode_config.funcs = &sdrm_mode_config_ops;
+	drm_connector_helper_add(conn, &sdrm_conn_hfuncs);
+
+	r = drm_connector_init(ddev, conn, &sdrm_conn_ops,
+			       DRM_MODE_CONNECTOR_VIRTUAL);
+	if (r < 0)
+		goto error;
+
+	r = drm_simple_display_pipe_init(ddev, &sdrm->pipe, &sdrm_pipe_funcs,
+					 sdrm_formats,
+					 ARRAY_SIZE(sdrm_formats), conn);
+	if (r < 0)
+		goto error;
+
+	drm_mode_config_reset(ddev);
+	return 0;
+
+error:
+	drm_mode_config_cleanup(ddev);
+	return r;
+}
+
+void sdrm_kms_unbind(struct sdrm_device *sdrm)
+{
+	if (sdrm->ddev->mode_config.funcs)
+		drm_mode_config_cleanup(sdrm->ddev);
+}
diff --git a/drivers/gpu/drm/simpledrm/simpledrm_of.c b/drivers/gpu/drm/simpledrm/simpledrm_of.c
new file mode 100644
index 0000000..5620000
--- /dev/null
+++ b/drivers/gpu/drm/simpledrm/simpledrm_of.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2012-2016 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <drm/drmP.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include "simpledrm.h"
+
+#ifdef CONFIG_COMMON_CLK
+
+static int sdrm_of_bind_clocks(struct sdrm_device *sdrm,
+			       struct device_node *np)
+{
+	struct clk *clock;
+	size_t i, n;
+	int r;
+
+	n = of_clk_get_parent_count(np);
+	if (n < 1)
+		return 0;
+
+	sdrm->clks = kcalloc(n, sizeof(*sdrm->clks), GFP_KERNEL);
+	if (!sdrm->clks)
+		return -ENOMEM;
+
+	for (i = 0; i < n; ++i) {
+		clock = of_clk_get(np, i);
+		if (!IS_ERR(clock)) {
+			sdrm->clks[sdrm->n_clks++] = clock;
+		} else if (PTR_ERR(clock) == -EPROBE_DEFER) {
+			r = -EPROBE_DEFER;
+			goto error;
+		} else {
+			dev_err(sdrm->ddev->dev, "cannot find clock %zu: %ld\n",
+				i, PTR_ERR(clock));
+		}
+	}
+
+	for (i = 0; i < sdrm->n_clks; ++i) {
+		if (!sdrm->clks[i])
+			continue;
+
+		r = clk_prepare_enable(sdrm->clks[i]);
+		if (r < 0) {
+			dev_err(sdrm->ddev->dev,
+				"cannot find clock %zu: %d\n", i, r);
+			clk_put(sdrm->clks[i]);
+			sdrm->clks[i] = NULL;
+		}
+	}
+
+	return 0;
+
+error:
+	for (i = 0; i < sdrm->n_clks; ++i)
+		clk_put(sdrm->clks[i]);
+	kfree(sdrm->clks);
+	sdrm->clks = NULL;
+	sdrm->n_clks = 0;
+	return r;
+}
+
+static void sdrm_of_unbind_clocks(struct sdrm_device *sdrm)
+{
+	size_t i;
+
+	for (i = 0; i < sdrm->n_clks; ++i) {
+		clk_disable_unprepare(sdrm->clks[i]);
+		clk_put(sdrm->clks[i]);
+	}
+
+	kfree(sdrm->clks);
+	sdrm->clks = NULL;
+	sdrm->n_clks = 0;
+}
+
+#else /* CONFIG_COMMON_CLK */
+
+static int sdrm_of_bind_clocks(struct sdrm_device *sdrm,
+			       struct device_node *np)
+{
+	return 0;
+}
+
+static void sdrm_of_unbind_clocks(struct sdrm_device *sdrm)
+{
+}
+
+#endif /* CONFIG_COMMON_CLK */
+
+#ifdef CONFIG_REGULATOR
+
+static int sdrm_of_bind_regulators(struct sdrm_device *sdrm,
+				   struct device_node *np)
+{
+	struct regulator *regulator;
+	struct property *prop;
+	char *p, *name;
+	size_t i, n;
+	int r;
+
+	n = 0;
+	for_each_property_of_node(np, prop) {
+		p = strstr(prop->name, "-supply");
+		if (p && p != prop->name)
+			++n;
+	}
+
+	if (n < 1)
+		return 0;
+
+	sdrm->regulators = kcalloc(n, sizeof(*sdrm->regulators), GFP_KERNEL);
+	if (!sdrm->regulators)
+		return -ENOMEM;
+
+	for_each_property_of_node(np, prop) {
+		p = strstr(prop->name, "-supply");
+		if (!p || p == prop->name)
+			continue;
+
+		name = kstrndup(prop->name, p - prop->name, GFP_TEMPORARY);
+		if (!name)
+			continue;
+
+		regulator = regulator_get_optional(sdrm->ddev->dev, name);
+		kfree(name);
+
+		if (!IS_ERR(regulator)) {
+			sdrm->regulators[sdrm->n_regulators++] = regulator;
+		} else if (PTR_ERR(regulator) == -EPROBE_DEFER) {
+			r = -EPROBE_DEFER;
+			goto error;
+		} else {
+			dev_warn(sdrm->ddev->dev,
+				 "cannot find regulator %s: %ld\n",
+				 prop->name, PTR_ERR(regulator));
+		}
+	}
+
+	for (i = 0; i < sdrm->n_regulators; ++i) {
+		if (!sdrm->regulators[i])
+			continue;
+
+		r = regulator_enable(sdrm->regulators[i]);
+		if (r < 0) {
+			dev_warn(sdrm->ddev->dev,
+				 "cannot enable regulator %zu: %d\n", i, r);
+			regulator_put(sdrm->regulators[i]);
+			sdrm->regulators[i] = NULL;
+		}
+	}
+
+	return 0;
+
+error:
+	for (i = 0; i < sdrm->n_regulators; ++i)
+		if (sdrm->regulators[i])
+			regulator_put(sdrm->regulators[i]);
+	kfree(sdrm->regulators);
+	sdrm->regulators = NULL;
+	sdrm->n_regulators = 0;
+	return r;
+}
+
+static void sdrm_of_unbind_regulators(struct sdrm_device *sdrm)
+{
+	size_t i;
+
+	for (i = 0; i < sdrm->n_regulators; ++i) {
+		if (sdrm->regulators[i]) {
+			regulator_disable(sdrm->regulators[i]);
+			regulator_put(sdrm->regulators[i]);
+		}
+	}
+
+	kfree(sdrm->regulators);
+	sdrm->regulators = NULL;
+	sdrm->n_regulators = 0;
+}
+
+#else /* CONFIG_REGULATORS */
+
+static int sdrm_of_bind_regulators(struct sdrm_device *sdrm,
+				   struct device_node *np)
+{
+	return 0;
+}
+
+static void sdrm_of_unbind_regulators(struct sdrm_device *sdrm)
+{
+}
+
+#endif /* CONFIG_REGULATORS */
+
+#ifdef CONFIG_OF
+
+void sdrm_of_bootstrap(void)
+{
+#ifdef CONFIG_OF_ADDRESS
+	struct device_node *np;
+
+	for_each_compatible_node(np, NULL, "simple-framebuffer")
+		of_platform_device_create(np, NULL, NULL);
+#endif
+}
+
+int sdrm_of_bind(struct sdrm_device *sdrm)
+{
+	int r;
+
+	if (WARN_ON(sdrm->n_clks > 0 || sdrm->n_regulators > 0))
+		return 0;
+	if (!sdrm->ddev->dev->of_node)
+		return 0;
+
+	r = sdrm_of_bind_clocks(sdrm, sdrm->ddev->dev->of_node);
+	if (r < 0)
+		goto error;
+
+	r = sdrm_of_bind_regulators(sdrm, sdrm->ddev->dev->of_node);
+	if (r < 0)
+		goto error;
+
+	return 0;
+
+error:
+	sdrm_of_unbind(sdrm);
+	return r;
+}
+
+void sdrm_of_unbind(struct sdrm_device *sdrm)
+{
+	sdrm_of_unbind_regulators(sdrm);
+	sdrm_of_unbind_clocks(sdrm);
+}
+
+#else /* CONFIG_OF */
+
+void sdrm_of_bootstrap(void)
+{
+}
+
+int sdrm_of_bind(struct sdrm_device *sdrm)
+{
+	return 0;
+}
+
+void sdrm_of_unbind(struct sdrm_device *sdrm)
+{
+}
+
+#endif /* CONFIG_OF */
-- 
2.9.3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v5 7/7] drm/simpledrm: add fbdev fallback support
  2016-09-02  8:22 [PATCH v5 0/7] drm: add simpledrm driver David Herrmann
                   ` (5 preceding siblings ...)
  2016-09-02  8:22 ` [PATCH v5 6/7] drm: add SimpleDRM driver David Herrmann
@ 2016-09-02  8:22 ` David Herrmann
  2016-09-03 12:04   ` Noralf Trønnes
  2021-03-10  2:50 ` [PATCH v5 0/7] drm: add simpledrm driver nerdopolis
  7 siblings, 1 reply; 31+ messages in thread
From: David Herrmann @ 2016-09-02  8:22 UTC (permalink / raw)
  To: dri-devel

Create a simple fbdev device during SimpleDRM setup so legacy user-space
and fbcon can use it.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/gpu/drm/simpledrm/Makefile          |   1 +
 drivers/gpu/drm/simpledrm/simpledrm.h       |   8 ++
 drivers/gpu/drm/simpledrm/simpledrm_drv.c   |  13 +++
 drivers/gpu/drm/simpledrm/simpledrm_fbdev.c | 143 ++++++++++++++++++++++++++++
 drivers/gpu/drm/simpledrm/simpledrm_kms.c   |  55 ++++++-----
 5 files changed, 196 insertions(+), 24 deletions(-)
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_fbdev.c

diff --git a/drivers/gpu/drm/simpledrm/Makefile b/drivers/gpu/drm/simpledrm/Makefile
index d7b179d..e368d14 100644
--- a/drivers/gpu/drm/simpledrm/Makefile
+++ b/drivers/gpu/drm/simpledrm/Makefile
@@ -1,6 +1,7 @@
 simpledrm-y := \
 	simpledrm_damage.o \
 	simpledrm_drv.o \
+	simpledrm_fbdev.o \
 	simpledrm_gem.o \
 	simpledrm_kms.o \
 	simpledrm_of.o
diff --git a/drivers/gpu/drm/simpledrm/simpledrm.h b/drivers/gpu/drm/simpledrm/simpledrm.h
index ed6d725..d7a2045 100644
--- a/drivers/gpu/drm/simpledrm/simpledrm.h
+++ b/drivers/gpu/drm/simpledrm/simpledrm.h
@@ -19,6 +19,7 @@
 #include <linux/mutex.h>
 
 struct clk;
+struct drm_fb_helper;
 struct regulator;
 struct simplefb_format;
 
@@ -49,6 +50,7 @@ struct sdrm_device {
 	atomic_t n_used;
 	struct drm_device *ddev;
 	struct sdrm_hw *hw;
+	struct drm_fb_helper *fbdev;
 
 	size_t n_clks;
 	size_t n_regulators;
@@ -66,6 +68,9 @@ void sdrm_of_unbind(struct sdrm_device *sdrm);
 int sdrm_kms_bind(struct sdrm_device *sdrm);
 void sdrm_kms_unbind(struct sdrm_device *sdrm);
 
+void sdrm_fbdev_bind(struct sdrm_device *sdrm);
+void sdrm_fbdev_unbind(struct sdrm_device *sdrm);
+
 void sdrm_dirty(struct sdrm_fb *fb, u32 x, u32 y, u32 width, u32 height);
 
 struct sdrm_bo *sdrm_bo_new(struct drm_device *ddev, size_t size);
@@ -80,4 +85,7 @@ int sdrm_dumb_map_offset(struct drm_file *dfile,
 			 uint32_t handle,
 			 uint64_t *offset);
 
+struct sdrm_fb *sdrm_fb_new(struct sdrm_bo *bo,
+			    const struct drm_mode_fb_cmd2 *cmd);
+
 #endif /* __SDRM_SIMPLEDRM_H */
diff --git a/drivers/gpu/drm/simpledrm/simpledrm_drv.c b/drivers/gpu/drm/simpledrm/simpledrm_drv.c
index d569120..6aefe49 100644
--- a/drivers/gpu/drm/simpledrm/simpledrm_drv.c
+++ b/drivers/gpu/drm/simpledrm/simpledrm_drv.c
@@ -9,6 +9,7 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <drm/drmP.h>
+#include <drm/drm_fb_helper.h>
 #include <linux/atomic.h>
 #include <linux/err.h>
 #include <linux/io.h>
@@ -210,6 +211,7 @@ error:
 static void sdrm_device_unbind(struct sdrm_device *sdrm)
 {
 	if (sdrm) {
+		sdrm_fbdev_unbind(sdrm);
 		sdrm_kms_unbind(sdrm);
 		sdrm_hw_unbind(sdrm->hw);
 		sdrm_of_unbind(sdrm);
@@ -232,6 +234,8 @@ static int sdrm_device_bind(struct sdrm_device *sdrm)
 	if (r < 0)
 		goto error;
 
+	sdrm_fbdev_bind(sdrm);
+
 	return 0;
 
 error:
@@ -253,6 +257,14 @@ static void sdrm_device_release(struct sdrm_device *sdrm)
 	}
 }
 
+static void sdrm_device_lastclose(struct drm_device *ddev)
+{
+	struct sdrm_device *sdrm = ddev->dev_private;
+
+	if (sdrm->fbdev)
+		drm_fb_helper_restore_fbdev_mode_unlocked(sdrm->fbdev);
+}
+
 static int sdrm_fop_open(struct inode *inode, struct file *file)
 {
 	struct drm_device *ddev;
@@ -411,6 +423,7 @@ static const struct file_operations sdrm_drm_fops = {
 static struct drm_driver sdrm_drm_driver = {
 	.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
 	.fops = &sdrm_drm_fops,
+	.lastclose = sdrm_device_lastclose,
 
 	.gem_free_object = sdrm_bo_free,
 
diff --git a/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c b/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c
new file mode 100644
index 0000000..17e4e83
--- /dev/null
+++ b/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2012-2016 Red Hat, Inc.
+ * Copyright (C) 2016 Noralf Trønnes
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <linux/err.h>
+#include <linux/fb.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include "simpledrm.h"
+
+static int sdrm_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+	return -ENODEV;
+}
+
+static struct fb_ops sdrm_fbdev_ops = {
+	.owner		= THIS_MODULE,
+	.fb_fillrect	= drm_fb_helper_sys_fillrect,
+	.fb_copyarea	= drm_fb_helper_sys_copyarea,
+	.fb_imageblit	= drm_fb_helper_sys_imageblit,
+	.fb_check_var	= drm_fb_helper_check_var,
+	.fb_set_par	= drm_fb_helper_set_par,
+	.fb_setcmap	= drm_fb_helper_setcmap,
+	.fb_mmap	= sdrm_fbdev_mmap,
+};
+
+static int sdrm_fbdev_probe(struct drm_fb_helper *fbdev,
+			    struct drm_fb_helper_surface_size *sizes)
+{
+	struct sdrm_device *sdrm = fbdev->dev->dev_private;
+	struct drm_mode_fb_cmd2 cmd = {
+		.width = sdrm->hw->width,
+		.height = sdrm->hw->height,
+		.pitches[0] = sdrm->hw->stride,
+		.pixel_format = sdrm->hw->format,
+	};
+	struct fb_info *fbi;
+	struct sdrm_bo *bo;
+	struct sdrm_fb *fb;
+	int r;
+
+	fbi = drm_fb_helper_alloc_fbi(fbdev);
+	if (IS_ERR(fbi))
+		return PTR_ERR(fbi);
+
+	bo = sdrm_bo_new(sdrm->ddev,
+			 PAGE_ALIGN(sdrm->hw->height * sdrm->hw->stride));
+	if (!bo) {
+		r = -ENOMEM;
+		goto error;
+	}
+
+	fb = sdrm_fb_new(bo, &cmd);
+	drm_gem_object_unreference_unlocked(&bo->base);
+	if (IS_ERR(fb)) {
+		r = PTR_ERR(fb);
+		goto error;
+	}
+
+	fbdev->fb = &fb->base;
+	fbi->par = fbdev;
+	fbi->flags = FBINFO_DEFAULT | FBINFO_MISC_FIRMWARE;
+	fbi->fbops = &sdrm_fbdev_ops;
+
+	drm_fb_helper_fill_fix(fbi, fb->base.pitches[0], fb->base.depth);
+	drm_fb_helper_fill_var(fbi, fbdev, fb->base.width, fb->base.height);
+
+	strncpy(fbi->fix.id, "simpledrmfb", sizeof(fbi->fix.id) - 1);
+	fbi->screen_base = bo->vmapping;
+	fbi->fix.smem_len = bo->base.size;
+
+	return 0;
+
+error:
+	drm_fb_helper_release_fbi(fbdev);
+	return r;
+}
+
+static const struct drm_fb_helper_funcs sdrm_fbdev_funcs = {
+	.fb_probe = sdrm_fbdev_probe,
+};
+
+void sdrm_fbdev_bind(struct sdrm_device *sdrm)
+{
+	struct drm_fb_helper *fbdev;
+	int r;
+
+	fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
+	if (!fbdev)
+		return;
+
+	drm_fb_helper_prepare(sdrm->ddev, fbdev, &sdrm_fbdev_funcs);
+
+	r = drm_fb_helper_init(sdrm->ddev, fbdev, 1, 1);
+	if (r < 0)
+		goto error;
+
+	r = drm_fb_helper_single_add_all_connectors(fbdev);
+	if (r < 0)
+		goto error;
+
+	r = drm_fb_helper_initial_config(fbdev,
+				sdrm->ddev->mode_config.preferred_depth);
+	if (r < 0)
+		goto error;
+
+	if (!fbdev->fbdev)
+		goto error;
+
+	sdrm->fbdev = fbdev;
+	return;
+
+error:
+	drm_fb_helper_fini(fbdev);
+	kfree(fbdev);
+}
+
+void sdrm_fbdev_unbind(struct sdrm_device *sdrm)
+{
+	struct drm_fb_helper *fbdev = sdrm->fbdev;
+
+	if (!fbdev)
+		return;
+
+	sdrm->fbdev = NULL;
+	drm_fb_helper_unregister_fbi(fbdev);
+	cancel_work_sync(&fbdev->dirty_work);
+	drm_fb_helper_release_fbi(fbdev);
+	drm_framebuffer_unreference(fbdev->fb);
+	fbdev->fb = NULL;
+	drm_fb_helper_fini(fbdev);
+	kfree(fbdev);
+}
diff --git a/drivers/gpu/drm/simpledrm/simpledrm_kms.c b/drivers/gpu/drm/simpledrm/simpledrm_kms.c
index 00101c9..8f67fe5 100644
--- a/drivers/gpu/drm/simpledrm/simpledrm_kms.c
+++ b/drivers/gpu/drm/simpledrm/simpledrm_kms.c
@@ -169,53 +169,60 @@ static const struct drm_framebuffer_funcs sdrm_fb_ops = {
 	.destroy		= sdrm_fb_destroy,
 };
 
-static struct drm_framebuffer *
-sdrm_fb_create(struct drm_device *ddev,
-	       struct drm_file *dfile,
-	       const struct drm_mode_fb_cmd2 *cmd)
+struct sdrm_fb *sdrm_fb_new(struct sdrm_bo *bo,
+			    const struct drm_mode_fb_cmd2 *cmd)
 {
-	struct drm_gem_object *dobj;
-	struct sdrm_fb *fb = NULL;
-	struct sdrm_bo *bo;
+	struct sdrm_fb *fb;
 	int r;
 
 	if (cmd->flags)
 		return ERR_PTR(-EINVAL);
 
-	dobj = drm_gem_object_lookup(dfile, cmd->handles[0]);
-	if (!dobj)
-		return ERR_PTR(-EINVAL);
-
-	bo = container_of(dobj, struct sdrm_bo, base);
-
 	r = sdrm_bo_vmap(bo);
 	if (r < 0)
-		goto error;
+		return ERR_PTR(r);
 
 	fb = kzalloc(sizeof(*fb), GFP_KERNEL);
-	if (!fb) {
-		r = -ENOMEM;
-		goto error;
-	}
+	if (!fb)
+		return ERR_PTR(r);
 
+	drm_gem_object_reference(&bo->base);
 	fb->bo = bo;
 	drm_helper_mode_fill_fb_struct(&fb->base, cmd);
 
-	r = drm_framebuffer_init(ddev, &fb->base, &sdrm_fb_ops);
+	r = drm_framebuffer_init(bo->base.dev, &fb->base, &sdrm_fb_ops);
 	if (r < 0)
 		goto error;
 
-	DRM_DEBUG_KMS("[FB:%d] pixel_format: %s\n", fb->base.base.id,
-		      drm_get_format_name(fb->base.pixel_format));
-
-	return &fb->base;
+	return fb;
 
 error:
+	drm_gem_object_unreference_unlocked(&bo->base);
 	kfree(fb);
-	drm_gem_object_unreference_unlocked(dobj);
 	return ERR_PTR(r);
 }
 
+static struct drm_framebuffer *
+sdrm_fb_create(struct drm_device *ddev,
+	       struct drm_file *dfile,
+	       const struct drm_mode_fb_cmd2 *cmd)
+{
+	struct drm_gem_object *dobj;
+	struct sdrm_fb *fb;
+
+	dobj = drm_gem_object_lookup(dfile, cmd->handles[0]);
+	if (!dobj)
+		return ERR_PTR(-EINVAL);
+
+	fb = sdrm_fb_new(container_of(dobj, struct sdrm_bo, base), cmd);
+	drm_gem_object_unreference_unlocked(dobj);
+
+	if (IS_ERR(fb))
+		return ERR_CAST(fb);
+
+	return &fb->base;
+}
+
 static const struct drm_mode_config_funcs sdrm_mode_config_ops = {
 	.fb_create		= sdrm_fb_create,
 	.atomic_check		= drm_atomic_helper_check,
-- 
2.9.3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH v5 1/7] x86/sysfb: add support for 64bit EFI lfb_base
  2016-09-02  8:22 ` [PATCH v5 1/7] x86/sysfb: add support for 64bit EFI lfb_base David Herrmann
@ 2016-09-02 10:20   ` Tom Gundersen
  0 siblings, 0 replies; 31+ messages in thread
From: Tom Gundersen @ 2016-09-02 10:20 UTC (permalink / raw)
  To: David Herrmann; +Cc: dri-devel

On Fri, Sep 2, 2016 at 10:22 AM, David Herrmann <dh.herrmann@gmail.com> wrote:
> The screen_info object was extended to support 64bit lfb_base addresses
> in:
>
>     commit ae2ee627dc87a70910de91b791b3cd0e9c6facdd
>     Author: Matt Fleming <matt.fleming@intel.com>
>     Date:   Tue Aug 25 16:32:55 2015 +0100
>
>         efifb: Add support for 64-bit frame buffer addresses
>
> However, the x86 simple-framebuffer setup code never made use of it. Fix
> it to properly assemble and verify the lfb_base before advertising
> simple-framebuffer devices.
>
> In particular, this means if VIDEO_CAPABILITY_64BIT_BASE is set, the
> screen_info->ext_lfb_base field will contain the upper 32bit of the
> actual lfb_base. Make sure the address is not 0 (i.e., unset), as well as
> does not overflow the physical address type.
>
> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>

Reviewed-by: Tom Gundersen <teg@jklm.no>

> ---
>  arch/x86/kernel/sysfb_simplefb.c | 18 ++++++++++++++++--
>  1 file changed, 16 insertions(+), 2 deletions(-)
>
> diff --git a/arch/x86/kernel/sysfb_simplefb.c b/arch/x86/kernel/sysfb_simplefb.c
> index 764a29f..35b8641 100644
> --- a/arch/x86/kernel/sysfb_simplefb.c
> +++ b/arch/x86/kernel/sysfb_simplefb.c
> @@ -67,6 +67,20 @@ __init int create_simplefb(const struct screen_info *si,
>         struct platform_device *pd;
>         struct resource res;
>         unsigned long len;
> +       u64 base;
> +
> +       /*
> +        * If the 64BIT_BASE capability is set, ext_lfb_base will contain the
> +        * upper half of the base address. Assemble the address, then make sure
> +        * it is valid and we can actually access it.
> +        */
> +       base = si->lfb_base;
> +       if (si->capabilities & VIDEO_CAPABILITY_64BIT_BASE)
> +               base |= (u64)si->ext_lfb_base << 32;
> +       if (!base || (u64)(resource_size_t)base != base) {
> +               printk(KERN_DEBUG "sysfb: inaccessible VRAM base\n");
> +               return -EINVAL;
> +       }
>
>         /* don't use lfb_size as it may contain the whole VMEM instead of only
>          * the part that is occupied by the framebuffer */
> @@ -81,8 +95,8 @@ __init int create_simplefb(const struct screen_info *si,
>         memset(&res, 0, sizeof(res));
>         res.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
>         res.name = simplefb_resname;
> -       res.start = si->lfb_base;
> -       res.end = si->lfb_base + len - 1;
> +       res.start = base;
> +       res.end = res.start + len - 1;
>         if (res.end <= res.start)
>                 return -EINVAL;
>
> --
> 2.9.3
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v5 2/7] x86/sysfb: fix lfb_size calculation
  2016-09-02  8:22 ` [PATCH v5 2/7] x86/sysfb: fix lfb_size calculation David Herrmann
@ 2016-09-02 10:20   ` Tom Gundersen
  0 siblings, 0 replies; 31+ messages in thread
From: Tom Gundersen @ 2016-09-02 10:20 UTC (permalink / raw)
  To: David Herrmann; +Cc: dri-devel

On Fri, Sep 2, 2016 at 10:22 AM, David Herrmann <dh.herrmann@gmail.com> wrote:
> The screen_info.lfb_size field is shifted by 16 bits *only* in case of
> VBE. This has historical reasons since VBE advertised it similarly.
> However, in case of EFI framebuffers, the size is no longer shifted. Fix
> the x86 simple-framebuffer setup code to use the correct size in the
> non-VBE case.
>
> While at it, avoid variable abbreviations and rename 'len' to 'length',
> and use the correct types matching the screen_info definition.
>
> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>

Reviewed-by: Tom Gundersen <teg@jklm.no>

> ---
>  arch/x86/kernel/sysfb_simplefb.c | 25 +++++++++++++++++--------
>  1 file changed, 17 insertions(+), 8 deletions(-)
>
> diff --git a/arch/x86/kernel/sysfb_simplefb.c b/arch/x86/kernel/sysfb_simplefb.c
> index 35b8641..85195d4 100644
> --- a/arch/x86/kernel/sysfb_simplefb.c
> +++ b/arch/x86/kernel/sysfb_simplefb.c
> @@ -66,8 +66,8 @@ __init int create_simplefb(const struct screen_info *si,
>  {
>         struct platform_device *pd;
>         struct resource res;
> -       unsigned long len;
> -       u64 base;
> +       u64 base, size;
> +       u32 length;
>
>         /*
>          * If the 64BIT_BASE capability is set, ext_lfb_base will contain the
> @@ -82,11 +82,20 @@ __init int create_simplefb(const struct screen_info *si,
>                 return -EINVAL;
>         }
>
> -       /* don't use lfb_size as it may contain the whole VMEM instead of only
> -        * the part that is occupied by the framebuffer */
> -       len = mode->height * mode->stride;
> -       len = PAGE_ALIGN(len);
> -       if (len > (u64)si->lfb_size << 16) {
> +       /*
> +        * Don't use lfb_size as IORESOURCE size, since it may contain the
> +        * entire VMEM, and thus require huge mappings. Use just the part we
> +        * need, that is, the part where the framebuffer is located. But verify
> +        * that it does not exceed the advertised VMEM.
> +        * Note that in case of VBE, the lfb_size is shifted by 16 bits for
> +        * historical reasons.
> +        */
> +       size = si->lfb_size;
> +       if (si->orig_video_isVGA == VIDEO_TYPE_VLFB)
> +               size <<= 16;
> +       length = mode->height * mode->stride;
> +       length = PAGE_ALIGN(length);
> +       if (length > size) {
>                 printk(KERN_WARNING "sysfb: VRAM smaller than advertised\n");
>                 return -EINVAL;
>         }
> @@ -96,7 +105,7 @@ __init int create_simplefb(const struct screen_info *si,
>         res.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
>         res.name = simplefb_resname;
>         res.start = base;
> -       res.end = res.start + len - 1;
> +       res.end = res.start + length - 1;
>         if (res.end <= res.start)
>                 return -EINVAL;
>
> --
> 2.9.3
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v5 3/7] of/platform: expose of_platform_device_destroy()
  2016-09-02  8:22 ` [PATCH v5 3/7] of/platform: expose of_platform_device_destroy() David Herrmann
@ 2016-09-02 10:21   ` Tom Gundersen
  0 siblings, 0 replies; 31+ messages in thread
From: Tom Gundersen @ 2016-09-02 10:21 UTC (permalink / raw)
  To: David Herrmann; +Cc: dri-devel

On Fri, Sep 2, 2016 at 10:22 AM, David Herrmann <dh.herrmann@gmail.com> wrote:
> We already expose of_platform_device_create(), but give the caller no
> chance to revert its effect. Make sure we also provide the counterpart
> of_platform_device_destroy().
>
> This requires a small refactoring, since so far the internal destructor
> is used as iterator to for_each_device(), but we don't want to expose it
> with the "void *data" parameter. So provide
> of_platform_device_depopulate() as new iterator, which calls into
> of_platform_device_destroy().
>
> While at it, drop the unused 'children_left' argument by
> of_platform_notify(). It is a left-over that somehow was never removed.
>
> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>

Reviewed-by: Tom Gundersen <teg@jklm.no>

> ---
>  drivers/of/platform.c       | 35 ++++++++++++++++++++++++++---------
>  include/linux/of_platform.h |  1 +
>  2 files changed, 27 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/of/platform.c b/drivers/of/platform.c
> index f39ccd5..f9bb563 100644
> --- a/drivers/of/platform.c
> +++ b/drivers/of/platform.c
> @@ -524,15 +524,18 @@ static int __init of_platform_default_populate_init(void)
>  arch_initcall_sync(of_platform_default_populate_init);
>  #endif
>
> -static int of_platform_device_destroy(struct device *dev, void *data)
> +/**
> + * of_platform_device_destroy - unregister an of_device
> + * @dev: device to unregister
> + *
> + * This is the inverse operation of of_platform_device_create(). It unregisters
> + * the passed device, if registered.
> + */
> +void of_platform_device_destroy(struct device *dev)
>  {
>         /* Do not touch devices not populated from the device tree */
>         if (!dev->of_node || !of_node_check_flag(dev->of_node, OF_POPULATED))
> -               return 0;
> -
> -       /* Recurse for any nodes that were treated as busses */
> -       if (of_node_check_flag(dev->of_node, OF_POPULATED_BUS))
> -               device_for_each_child(dev, NULL, of_platform_device_destroy);
> +               return;
>
>         if (dev->bus == &platform_bus_type)
>                 platform_device_unregister(to_platform_device(dev));
> @@ -544,6 +547,20 @@ static int of_platform_device_destroy(struct device *dev, void *data)
>         of_dma_deconfigure(dev);
>         of_node_clear_flag(dev->of_node, OF_POPULATED);
>         of_node_clear_flag(dev->of_node, OF_POPULATED_BUS);
> +}
> +EXPORT_SYMBOL(of_platform_device_destroy);
> +
> +static int of_platform_device_depopulate(struct device *dev, void *data)
> +{
> +       /* Do not touch devices not populated from the device tree */
> +       if (!dev->of_node || !of_node_check_flag(dev->of_node, OF_POPULATED))
> +               return 0;
> +
> +       /* Recurse for any nodes that were treated as busses */
> +       if (of_node_check_flag(dev->of_node, OF_POPULATED_BUS))
> +               device_for_each_child(dev, NULL, of_platform_device_depopulate);
> +
> +       of_platform_device_destroy(dev);
>         return 0;
>  }
>
> @@ -562,7 +579,8 @@ static int of_platform_device_destroy(struct device *dev, void *data)
>  void of_platform_depopulate(struct device *parent)
>  {
>         if (parent->of_node && of_node_check_flag(parent->of_node, OF_POPULATED_BUS)) {
> -               device_for_each_child(parent, NULL, of_platform_device_destroy);
> +               device_for_each_child(parent, NULL,
> +                                     of_platform_device_depopulate);
>                 of_node_clear_flag(parent->of_node, OF_POPULATED_BUS);
>         }
>  }
> @@ -574,7 +592,6 @@ static int of_platform_notify(struct notifier_block *nb,
>  {
>         struct of_reconfig_data *rd = arg;
>         struct platform_device *pdev_parent, *pdev;
> -       bool children_left;
>
>         switch (of_reconfig_get_state_change(action, rd)) {
>         case OF_RECONFIG_CHANGE_ADD:
> @@ -612,7 +629,7 @@ static int of_platform_notify(struct notifier_block *nb,
>                         return NOTIFY_OK;       /* no? not meant for us */
>
>                 /* unregister takes one ref away */
> -               of_platform_device_destroy(&pdev->dev, &children_left);
> +               of_platform_device_depopulate(&pdev->dev, NULL);
>
>                 /* and put the reference of the find */
>                 of_dev_put(pdev);
> diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h
> index 956a100..a9017d3 100644
> --- a/include/linux/of_platform.h
> +++ b/include/linux/of_platform.h
> @@ -63,6 +63,7 @@ extern struct platform_device *of_find_device_by_node(struct device_node *np);
>  extern struct platform_device *of_platform_device_create(struct device_node *np,
>                                                    const char *bus_id,
>                                                    struct device *parent);
> +extern void of_platform_device_destroy(struct device *dev);
>
>  extern int of_platform_bus_probe(struct device_node *root,
>                                  const struct of_device_id *matches,
> --
> 2.9.3
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v5 4/7] video: add generic framebuffer eviction
  2016-09-02  8:22 ` [PATCH v5 4/7] video: add generic framebuffer eviction David Herrmann
@ 2016-09-02 10:21   ` Tom Gundersen
  2016-09-03 12:06   ` Noralf Trønnes
  1 sibling, 0 replies; 31+ messages in thread
From: Tom Gundersen @ 2016-09-02 10:21 UTC (permalink / raw)
  To: David Herrmann; +Cc: dri-devel

On Fri, Sep 2, 2016 at 10:22 AM, David Herrmann <dh.herrmann@gmail.com> wrote:
> There are several situations where we want hardware handover from an early
> boot GFX driver (e.g., vgacon, vesafb, efifb, simplefb) to a full fletched
> GFX driver (e.g., most DRM drivers). So far, we relied on
> remove_conflicting_framebuffers() to do this for us, however, this had a
> bunch of downsides:
>
>   o It only removes conflicting fbdev drivers. It does not drop vgacon,
>     early boot console drivers, conflicting DRM drivers, etc.
>
>   o It only unloads the fbdev driver, it does not modify the underlying
>     device or resources. In case of "screen_info" drivers (e.g., efifb)
>     this is fine, since no resources are pinned. However, if the driver
>     binds to a platform-device like "simple-framebuffer", we must make
>     sure to unregister that device as well. Otherwise, pinned resources
>     like IORESOURCE_MEM stay around, triggering WARN_ONs if the following
>     driver requests those resources.
>
>   o It is only available if CONFIG_FB is selected.
>
> This commit adds a new infrastructure that manages system-framebuffers
> (short: sysfb). The initial commit provides conflict-resolution for
> system-framebuffers. At its core it provides sysfb_evict_conflicts(),
> which implements conflict detection and removal for all known types of
> GFX driver hand-overs. So far, this includes platform-device removal,
> fbdev-firmware-device removal, vgacon removal and VBE detection. To
> further simplify the callers, it also provides helpers to figure out what
> hand-over to do, based on the device the new drivers binds to:
>
>   o PCI drivers can use sysfb_evict_conflicts_pci(), which will figure out
>     the apertures automatically, and does VGA/VBE detection.
>
>   o Generic firmware drivers that might be shadowed at any address in
>     memory can use sysfb_evict_conflicts_firmware(), basically removing
>     *all* firmware framebuffers in effect.
>
> This only adds the generic sysfb helpers. No users are converted, yet.
>
> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>

Reviewed-by: Tom Gundersen <teg@jklm.no>

> ---
>  drivers/video/Kconfig  |   4 +
>  drivers/video/Makefile |   1 +
>  drivers/video/sysfb.c  | 327 +++++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/sysfb.h  |  34 +++++
>  4 files changed, 366 insertions(+)
>  create mode 100644 drivers/video/sysfb.c
>  create mode 100644 include/linux/sysfb.h
>
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index 3c20af9..56a8294 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -36,6 +36,10 @@ config VIDEOMODE_HELPERS
>  config HDMI
>         bool
>
> +config SYSFB
> +       bool
> +       select DUMMY_CONSOLE if VT
> +
>  if VT
>         source "drivers/video/console/Kconfig"
>  endif
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index 9ad3c17..df7bd75 100644
> --- a/drivers/video/Makefile
> +++ b/drivers/video/Makefile
> @@ -1,5 +1,6 @@
>  obj-$(CONFIG_VGASTATE)            += vgastate.o
>  obj-$(CONFIG_HDMI)                += hdmi.o
> +obj-$(CONFIG_SYSFB)              += sysfb.o
>
>  obj-$(CONFIG_VT)                 += console/
>  obj-$(CONFIG_LOGO)               += logo/
> diff --git a/drivers/video/sysfb.c b/drivers/video/sysfb.c
> new file mode 100644
> index 0000000..00585c9
> --- /dev/null
> +++ b/drivers/video/sysfb.c
> @@ -0,0 +1,327 @@
> +/*
> + * Copyright (C) 2013-2016 Red Hat, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License as published by the
> + * Free Software Foundation; either version 2.1 of the License, or (at your
> + * option) any later version.
> + */
> +
> +#define pr_fmt(fmt) "sysfb: " fmt
> +#include <linux/console.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/export.h>
> +#include <linux/fb.h>
> +#include <linux/ioport.h>
> +#include <linux/kernel.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/pci.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/sysfb.h>
> +#include <linux/vt.h>
> +
> +static bool sysfb_evict_match_resource(struct sysfb_evict_ctx *ctx,
> +                                      struct resource *mem)
> +{
> +       struct aperture *g;
> +       unsigned int i;
> +
> +       for (i = 0; i < ctx->ap->count; ++i) {
> +               g = &ctx->ap->ranges[i];
> +
> +               if (mem->start == g->base)
> +                       return true;
> +               if (mem->start >= g->base && mem->end < g->base + g->size)
> +                       return true;
> +               if ((ctx->flags & SYSFB_EVICT_VBE) && mem->start == 0xA0000)
> +                       return true;
> +       }
> +
> +       return false;
> +}
> +
> +static int sysfb_evict_platform_device(struct device *dev, void *userdata)
> +{
> +       struct sysfb_evict_ctx *ctx = userdata;
> +       struct platform_device *pdev = to_platform_device(dev);
> +       struct resource *mem;
> +
> +       if (!pdev->name)
> +               return 0;
> +
> +       if (!strcmp(pdev->name, "simple-framebuffer")) {
> +               mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +               if (!mem)
> +                       return 0;
> +               if (!sysfb_evict_match_resource(ctx, mem))
> +                       return 0;
> +
> +#ifdef CONFIG_OF_ADDRESS
> +               if (dev->of_node)
> +                       of_platform_device_destroy(dev);
> +               else
> +#endif
> +               if (dev_get_platdata(&pdev->dev))
> +                       platform_device_del(pdev);
> +       }
> +
> +       return 0;
> +}
> +
> +static int sysfb_evict_platform(struct sysfb_evict_ctx *ctx)
> +{
> +       /*
> +        * Early-boot architecture setup and boot-loarders sometimes create
> +        * preliminary platform devices with a generic framebuffer setup. This
> +        * allows graphics access during boot-up, without a real graphics
> +        * driver loaded. However, once a real graphics driver takes over, we
> +        * have to destroy those platform devices. In the legacy fbdev case, we
> +        * just used to unload the fbdev driver. However, to make sure any kind
> +        * of driver is unloaded, the platform-eviction code here simply
> +        * removes any conflicting platform device directly. This causes any
> +        * bound driver to be detached, and then removes the device entirely so
> +        * it cannot be bound to later on.
> +        *
> +        * Please note that any such platform device must be registered by
> +        * early architecture setup code. If they are registered after regular
> +        * GFX drivers, this will fail horribly.
> +        */
> +
> +       static DEFINE_MUTEX(lock);
> +       int ret;
> +
> +       /*
> +        * In case of static platform-devices, we must iterate the bus and
> +        * remove them manually. We know that we're the only code that might
> +        * remove them, so a simple static lock serializes all calls here.
> +        */
> +       mutex_lock(&lock);
> +       ret = bus_for_each_dev(&platform_bus_type, NULL, ctx,
> +                              sysfb_evict_platform_device);
> +       mutex_unlock(&lock);
> +       return ret;
> +}
> +
> +static int sysfb_evict_fbdev(struct sysfb_evict_ctx *ctx)
> +{
> +       /*
> +        * Usually, evicting platform devices should be enough to also trigger
> +        * fbdev unloading. However, some legacy devices (e.g., uvesafb) have
> +        * no platform devices that can be evicted, so we still fall back to
> +        * the legacy fbdev removal code. Note that this only removes fbdev
> +        * devices marked as FBINFO_MISC_FIRMWARE. Anything else is left
> +        * untouched.
> +        *
> +        * As usual, this only works if the fbdev device is probed early,
> +        * before any real GFX driver wants to take over.
> +        */
> +
> +       int ret = 0;
> +
> +#ifdef CONFIG_FB
> +       ret = remove_conflicting_framebuffers(ctx->ap, "sysfb",
> +                                             ctx->flags & SYSFB_EVICT_VBE);
> +#endif
> +
> +       return ret;
> +}
> +
> +static int sysfb_evict_vgacon(struct sysfb_evict_ctx *ctx)
> +{
> +       /*
> +        * The VGACON console driver pokes at VGA registers randomly. If a GFX
> +        * driver cannot keep the VGA support alive, it better makes sure to
> +        * unload VGACON before probing.
> +        *
> +        * Unloading VGACON requires us to first force dummycon to take over
> +        * from vgacon (but only if vgacon is really in use), followed by a
> +        * deregistration of vgacon. Note that this prevents vgacon from being
> +        * used again after the GFX driver is unloaded. But that is usually
> +        * fine, since VGA state is rarely restored on driver-unload, anyway.
> +        *
> +        * Note that we rely on VGACON to be probed in early boot (actually
> +        * done by ARCH setup code). If it is probed after GFX drivers, this
> +        * will fail horribly. You better make sure VGACON is probed early and
> +        * GFX drivers are probed as normal modules.
> +        */
> +
> +       int ret = 0;
> +
> +#ifdef CONFIG_VGA_CONSOLE
> +       console_lock();
> +       if (con_is_bound(&vga_con))
> +               ret = do_take_over_console(&dummy_con, 0,
> +                                          MAX_NR_CONSOLES - 1, 1);
> +       if (ret == 0) {
> +               ret = do_unregister_con_driver(&vga_con);
> +               if (ret == -ENODEV) /* ignore "already unregistered" */
> +                       ret = 0;
> +       }
> +       console_unlock();
> +#endif
> +
> +       return ret;
> +}
> +
> +/**
> + * sysfb_evict_conflicts - remove any conflicting system-framebuffers
> + * @ctx:               eviction context
> + *
> + * This function evicts any conflicting system-framebuffers and their bound
> + * drivers, according to the data given in @ctx.
> + *
> + * Depending on @ctx->flags, the following operations are performed:
> + *
> + *   SYSFB_EVICT_PLATFORM: Firmware framebuffer platform devices (eg.,
> + *                         'simple-framebuffer') that overlap @ctx are removed
> + *                         from the system, causing drivers to be unbound.
> + *                         If SYSFB_EVICT_VBE is given, this also affects
> + *                         devices that own the VGA region.
> + *
> + *   SYSFB_EVICT_FBDEV: Any firmware fbdev drivers that overlap @ctx are
> + *                      unloaded.
> + *                      Furthermore, if SYSFB_EVICT_VBE is given as well, any
> + *                      fbdev driver that maps the VGA region is unloaded.
> + *
> + *   SYSFB_EVICT_VGACON: The vgacon console driver is unbound and unregistered.
> + *
> + * This might call into fbdev driver unregistration, or even device_del() on
> + * some buses. Hence, make sure you call this from your top-level
> + * probe-callbacks, rather than with any gfx-subsystem locks held.
> + *
> + * RETURNS:
> + * 0 on success, negative error code on failure.
> + */
> +int sysfb_evict_conflicts(struct sysfb_evict_ctx *ctx)
> +{
> +       int ret;
> +
> +       if (WARN_ON(!ctx || !ctx->ap))
> +               return -EINVAL;
> +
> +       pr_info("removing conflicts (sysfb%s%s%s%s)\n",
> +               (ctx->flags & SYSFB_EVICT_PLATFORM) ? ", platform" : "",
> +               (ctx->flags & SYSFB_EVICT_FBDEV) ? ", fbdev" : "",
> +               (ctx->flags & SYSFB_EVICT_VGACON) ? ", vgacon" : "",
> +               (ctx->flags & SYSFB_EVICT_VBE) ? ", vbe" : "");
> +
> +       if (ctx->flags & SYSFB_EVICT_PLATFORM) {
> +               ret = sysfb_evict_platform(ctx);
> +               if (ret < 0)
> +                       return ret;
> +       }
> +
> +       if (ctx->flags & SYSFB_EVICT_FBDEV) {
> +               ret = sysfb_evict_fbdev(ctx);
> +               if (ret < 0)
> +                       return ret;
> +       }
> +
> +       if (ctx->flags & SYSFB_EVICT_VGACON) {
> +               ret = sysfb_evict_vgacon(ctx);
> +               if (ret < 0)
> +                       return ret;
> +       }
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(sysfb_evict_conflicts);
> +
> +/**
> + * sysfb_evict_conflicts_firmware() - remove all firmware framebuffers
> + *
> + * This is similar to sysfb_evict_conflicts() but uses a fake aperture spanning
> + * the entire address-space. This is suitable for any GFX driver that just
> + * wants to get rid of all available firmware framebuffers.
> + *
> + * RETURNS:
> + * 0 on success, negative error code on failure.
> + */
> +int sysfb_evict_conflicts_firmware(void)
> +{
> +       struct sysfb_evict_ctx ctx = {};
> +       int ret;
> +
> +       ctx.ap = alloc_apertures(1);
> +       if (!ctx.ap)
> +               return -ENOMEM;
> +
> +       ctx.ap->ranges[0].base = 0;
> +       ctx.ap->ranges[0].size = ~0;
> +
> +       ctx.flags |= SYSFB_EVICT_FBDEV | SYSFB_EVICT_PLATFORM;
> +       ret = sysfb_evict_conflicts(&ctx);
> +
> +       kfree(ctx.ap);
> +       return ret;
> +}
> +EXPORT_SYMBOL(sysfb_evict_conflicts_firmware);
> +
> +#ifdef CONFIG_PCI
> +/**
> + * sysfb_evict_conflicts_pci() - remove all system framebuffers conflicting
> + *                               with the given pci device
> + * @pdev:              pci device
> + *
> + * This is similar to sysfb_evict_conflicts() but generates the eviction
> + * context based on the given pci device @pdev.
> + *
> + * RETURNS:
> + * 0 on success, negative error code on failure.
> + */
> +int sysfb_evict_conflicts_pci(struct pci_dev *pdev)
> +{
> +       struct sysfb_evict_ctx ctx = {};
> +       size_t i, n, offset;
> +       int ret;
> +
> +       /*
> +        * If this device is used as primary VGA device, it is shadowed at the
> +        * VBE base address, so make sure to include it in the apertures.
> +        */
> +       if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)
> +               ctx.flags |= SYSFB_EVICT_VBE;
> +
> +       /*
> +        * If a device is a VGA device, make sure to kick out vgacon. We cannot
> +        * rely on the IORESOURCE_ROM_SHADOW, since vgacon can switch between
> +        * vga devices at runtime. So kick out vgacon anyway.
> +        */
> +       if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
> +               ctx.flags |= SYSFB_EVICT_VGACON;
> +
> +       /*
> +        * Allocate apertures for all standard PCI resources. Skip them in case
> +        * they are empty.
> +        */
> +       ctx.ap = alloc_apertures(PCI_STD_RESOURCE_END - PCI_STD_RESOURCES + 1);
> +       if (!ctx.ap)
> +               return -ENOMEM;
> +
> +       offset = PCI_STD_RESOURCES;
> +       for (n = 0, i = 0; i < ctx.ap->count; ++i) {
> +               if (pci_resource_len(pdev, offset + i) < 1)
> +                       continue;
> +
> +               ctx.ap->ranges[n].base = pci_resource_start(pdev, offset + i);
> +               ctx.ap->ranges[n].size = pci_resource_len(pdev, offset + i);
> +               ++n;
> +       }
> +       ctx.ap->count = n;
> +
> +       /*
> +        * Evict all matching fbdev devices, VBE devices if they shadow this
> +        * device, vgacon if this is a vga device, and platform devices if they
> +        * match.
> +        */
> +       ctx.flags |= SYSFB_EVICT_FBDEV | SYSFB_EVICT_PLATFORM;
> +       ret = sysfb_evict_conflicts(&ctx);
> +
> +       kfree(ctx.ap);
> +       return ret;
> +}
> +EXPORT_SYMBOL(sysfb_evict_conflicts_pci);
> +#endif /* CONFIG_PCI */
> diff --git a/include/linux/sysfb.h b/include/linux/sysfb.h
> new file mode 100644
> index 0000000..b67c74a
> --- /dev/null
> +++ b/include/linux/sysfb.h
> @@ -0,0 +1,34 @@
> +#ifndef __LINUX_SYSFB_H
> +#define __LINUX_SYSFB_H
> +
> +/*
> + * Copyright (C) 2013-2016 Red Hat, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License as published by the
> + * Free Software Foundation; either version 2.1 of the License, or (at your
> + * option) any later version.
> + */
> +
> +#include <linux/kernel.h>
> +
> +struct apertures_struct;
> +struct pci_dev;
> +
> +enum {
> +       SYSFB_EVICT_PLATFORM                    = (1U <<  0),
> +       SYSFB_EVICT_FBDEV                       = (1U <<  1),
> +       SYSFB_EVICT_VGACON                      = (1U <<  2),
> +       SYSFB_EVICT_VBE                         = (1U <<  3),
> +};
> +
> +struct sysfb_evict_ctx {
> +       struct apertures_struct *ap;
> +       unsigned int flags;
> +};
> +
> +int sysfb_evict_conflicts(struct sysfb_evict_ctx *ctx);
> +int sysfb_evict_conflicts_firmware(void);
> +int sysfb_evict_conflicts_pci(struct pci_dev *pdev);
> +
> +#endif /* __LINUX_SYSFB_H */
> --
> 2.9.3
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v5 6/7] drm: add SimpleDRM driver
  2016-09-02  8:22 ` [PATCH v5 6/7] drm: add SimpleDRM driver David Herrmann
@ 2016-09-02 12:45   ` Tom Gundersen
  2016-09-03 12:01   ` Noralf Trønnes
  2016-09-05 16:39   ` Noralf Trønnes
  2 siblings, 0 replies; 31+ messages in thread
From: Tom Gundersen @ 2016-09-02 12:45 UTC (permalink / raw)
  To: David Herrmann; +Cc: dri-devel

On Fri, Sep 2, 2016 at 10:22 AM, David Herrmann <dh.herrmann@gmail.com> wrote:
> The SimpleDRM driver binds to simple-framebuffer devices and provides a
> DRM/KMS API. It provides only a single CRTC+encoder+connector combination
> plus one initial mode.
>
> Userspace can create dumb-buffers which can be blit into the real
> framebuffer similar to UDL. No access to the real framebuffer is allowed
> (compared to earlier version of this driver) to avoid security issues.
> Furthermore, this way we can support arbitrary modes as long as we have a
> conversion-helper.
>
> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
> ---
>  MAINTAINERS                                  |   6 +
>  drivers/gpu/drm/Kconfig                      |   2 +
>  drivers/gpu/drm/Makefile                     |   1 +
>  drivers/gpu/drm/simpledrm/Kconfig            |  19 ++
>  drivers/gpu/drm/simpledrm/Makefile           |   8 +
>  drivers/gpu/drm/simpledrm/simpledrm.h        |  83 +++++
>  drivers/gpu/drm/simpledrm/simpledrm_damage.c | 194 +++++++++++
>  drivers/gpu/drm/simpledrm/simpledrm_drv.c    | 464 +++++++++++++++++++++++++++
>  drivers/gpu/drm/simpledrm/simpledrm_gem.c    | 109 +++++++
>  drivers/gpu/drm/simpledrm/simpledrm_kms.c    | 263 +++++++++++++++
>  drivers/gpu/drm/simpledrm/simpledrm_of.c     | 265 +++++++++++++++
>  11 files changed, 1414 insertions(+)
>  create mode 100644 drivers/gpu/drm/simpledrm/Kconfig
>  create mode 100644 drivers/gpu/drm/simpledrm/Makefile
>  create mode 100644 drivers/gpu/drm/simpledrm/simpledrm.h
>  create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_damage.c
>  create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_drv.c
>  create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_gem.c
>  create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_kms.c
>  create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_of.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 0bbe4b1..408863d 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -4140,6 +4140,12 @@ S:       Orphan / Obsolete
>  F:     drivers/gpu/drm/savage/
>  F:     include/uapi/drm/savage_drm.h
>
> +DRM DRIVER FOR SIMPLE FRAMEBUFFER DEVICES
> +M:     David Herrmann <dh.herrmann@gmail.com>
> +L:     dri-devel@lists.freedesktop.org
> +S:     Maintained
> +F:     drivers/gpu/drm/simpledrm/
> +
>  DRM DRIVER FOR SIS VIDEO CARDS
>  S:     Orphan / Obsolete
>  F:     drivers/gpu/drm/sis/
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index f27f9b5..61cbcd1 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -291,3 +291,5 @@ source "drivers/gpu/drm/arc/Kconfig"
>  source "drivers/gpu/drm/hisilicon/Kconfig"
>
>  source "drivers/gpu/drm/mediatek/Kconfig"
> +
> +source "drivers/gpu/drm/simpledrm/Kconfig"
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 0238bf8..3e6fe99 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -83,3 +83,4 @@ obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/
>  obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/
>  obj-$(CONFIG_DRM_ARCPGU)+= arc/
>  obj-y                  += hisilicon/
> +obj-y                  += simpledrm/
> diff --git a/drivers/gpu/drm/simpledrm/Kconfig b/drivers/gpu/drm/simpledrm/Kconfig
> new file mode 100644
> index 0000000..f45b25d
> --- /dev/null
> +++ b/drivers/gpu/drm/simpledrm/Kconfig
> @@ -0,0 +1,19 @@
> +config DRM_SIMPLEDRM
> +       tristate "Simple firmware framebuffer DRM driver"
> +       depends on DRM
> +       select DRM_KMS_HELPER
> +       help
> +         SimpleDRM can run on all systems with pre-initialized graphics
> +         hardware. It uses a framebuffer that was initialized during
> +         firmware boot. No page-flipping, modesetting or other advanced
> +         features are available. However, other DRM drivers can be loaded
> +         later and take over from SimpleDRM if they provide real hardware
> +         support.
> +
> +         SimpleDRM supports "simple-framebuffer" DeviceTree objects and
> +         compatible platform framebuffers.
> +
> +         If unsure, say Y.
> +
> +         To compile this driver as a module, choose M here: the
> +         module will be called simpledrm.
> diff --git a/drivers/gpu/drm/simpledrm/Makefile b/drivers/gpu/drm/simpledrm/Makefile
> new file mode 100644
> index 0000000..d7b179d
> --- /dev/null
> +++ b/drivers/gpu/drm/simpledrm/Makefile
> @@ -0,0 +1,8 @@
> +simpledrm-y := \
> +       simpledrm_damage.o \
> +       simpledrm_drv.o \
> +       simpledrm_gem.o \
> +       simpledrm_kms.o \
> +       simpledrm_of.o
> +
> +obj-$(CONFIG_DRM_SIMPLEDRM) := simpledrm.o
> diff --git a/drivers/gpu/drm/simpledrm/simpledrm.h b/drivers/gpu/drm/simpledrm/simpledrm.h
> new file mode 100644
> index 0000000..ed6d725
> --- /dev/null
> +++ b/drivers/gpu/drm/simpledrm/simpledrm.h
> @@ -0,0 +1,83 @@
> +#ifndef __SDRM_SIMPLEDRM_H
> +#define __SDRM_SIMPLEDRM_H
> +
> +/*
> + * Copyright (C) 2012-2016 Red Hat, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License as published by the
> + * Free Software Foundation; either version 2.1 of the License, or (at your
> + * option) any later version.
> + */
> +
> +#include <drm/drmP.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_gem.h>
> +#include <drm/drm_simple_kms_helper.h>
> +#include <linux/atomic.h>
> +#include <linux/kernel.h>
> +#include <linux/mutex.h>
> +
> +struct clk;
> +struct regulator;
> +struct simplefb_format;
> +
> +struct sdrm_hw {
> +       struct mutex lock;
> +       u32 width;
> +       u32 height;
> +       u32 stride;
> +       u32 bpp;
> +       u32 format;
> +       unsigned long base;
> +       unsigned long size;
> +       void *map;
> +};
> +
> +struct sdrm_bo {
> +       struct drm_gem_object base;
> +       struct page **pages;
> +       void *vmapping;
> +};
> +
> +struct sdrm_fb {
> +       struct drm_framebuffer base;
> +       struct sdrm_bo *bo;
> +};
> +
> +struct sdrm_device {
> +       atomic_t n_used;
> +       struct drm_device *ddev;
> +       struct sdrm_hw *hw;
> +
> +       size_t n_clks;
> +       size_t n_regulators;
> +       struct clk **clks;
> +       struct regulator **regulators;
> +
> +       struct drm_simple_display_pipe pipe;
> +       struct drm_connector conn;
> +};
> +
> +void sdrm_of_bootstrap(void);
> +int sdrm_of_bind(struct sdrm_device *sdrm);
> +void sdrm_of_unbind(struct sdrm_device *sdrm);
> +
> +int sdrm_kms_bind(struct sdrm_device *sdrm);
> +void sdrm_kms_unbind(struct sdrm_device *sdrm);
> +
> +void sdrm_dirty(struct sdrm_fb *fb, u32 x, u32 y, u32 width, u32 height);
> +
> +struct sdrm_bo *sdrm_bo_new(struct drm_device *ddev, size_t size);
> +void sdrm_bo_free(struct drm_gem_object *obj);
> +int sdrm_bo_vmap(struct sdrm_bo *bo);
> +
> +int sdrm_dumb_create(struct drm_file *dfile,
> +                    struct drm_device *ddev,
> +                    struct drm_mode_create_dumb *arg);
> +int sdrm_dumb_map_offset(struct drm_file *dfile,
> +                        struct drm_device *ddev,
> +                        uint32_t handle,
> +                        uint64_t *offset);
> +
> +#endif /* __SDRM_SIMPLEDRM_H */
> diff --git a/drivers/gpu/drm/simpledrm/simpledrm_damage.c b/drivers/gpu/drm/simpledrm/simpledrm_damage.c
> new file mode 100644
> index 0000000..4f7af5d
> --- /dev/null
> +++ b/drivers/gpu/drm/simpledrm/simpledrm_damage.c
> @@ -0,0 +1,194 @@
> +/*
> + * Copyright (C) 2012-2016 Red Hat, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License as published by the
> + * Free Software Foundation; either version 2.1 of the License, or (at your
> + * option) any later version.
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +#include <asm/unaligned.h>
> +#include <drm/drmP.h>
> +#include <drm/drm_crtc.h>
> +#include <linux/kernel.h>
> +#include "simpledrm.h"
> +
> +static inline void sdrm_put(u8 *dst, u32 four_cc, u16 r, u16 g, u16 b)
> +{
> +       switch (four_cc) {
> +       case DRM_FORMAT_RGB565:
> +               r >>= 11;
> +               g >>= 10;
> +               b >>= 11;
> +               put_unaligned((u16)((r << 11) | (g << 5) | b), (u16 *)dst);
> +               break;
> +       case DRM_FORMAT_XRGB1555:
> +       case DRM_FORMAT_ARGB1555:
> +               r >>= 11;
> +               g >>= 11;
> +               b >>= 11;
> +               put_unaligned((u16)((r << 10) | (g << 5) | b), (u16 *)dst);
> +               break;
> +       case DRM_FORMAT_RGB888:
> +               r >>= 8;
> +               g >>= 8;
> +               b >>= 8;
> +#ifdef __LITTLE_ENDIAN
> +               dst[2] = r;
> +               dst[1] = g;
> +               dst[0] = b;
> +#elif defined(__BIG_ENDIAN)
> +               dst[0] = r;
> +               dst[1] = g;
> +               dst[2] = b;
> +#endif
> +               break;
> +       case DRM_FORMAT_XRGB8888:
> +       case DRM_FORMAT_ARGB8888:
> +               r >>= 8;
> +               g >>= 8;
> +               b >>= 8;
> +               put_unaligned((u32)((r << 16) | (g << 8) | b), (u32 *)dst);
> +               break;
> +       case DRM_FORMAT_ABGR8888:
> +               r >>= 8;
> +               g >>= 8;
> +               b >>= 8;
> +               put_unaligned((u32)((b << 16) | (g << 8) | r), (u32 *)dst);
> +               break;
> +       case DRM_FORMAT_XRGB2101010:
> +       case DRM_FORMAT_ARGB2101010:
> +               r >>= 4;
> +               g >>= 4;
> +               b >>= 4;
> +               put_unaligned((u32)((r << 20) | (g << 10) | b), (u32 *)dst);
> +               break;
> +       }
> +}
> +
> +static void sdrm_blit_from_xrgb8888(const u8 *src,
> +                                   u32 src_stride,
> +                                   u32 src_bpp,
> +                                   u8 *dst,
> +                                   u32 dst_stride,
> +                                   u32 dst_bpp,
> +                                   u32 dst_four_cc,
> +                                   u32 width,
> +                                   u32 height)
> +{
> +       u32 val, i;
> +
> +       while (height--) {
> +               for (i = 0; i < width; ++i) {
> +                       val = get_unaligned((const u32 *)&src[i * src_bpp]);
> +                       sdrm_put(&dst[i * dst_bpp], dst_four_cc,
> +                                (val & 0x00ff0000U) >> 8,
> +                                (val & 0x0000ff00U),
> +                                (val & 0x000000ffU) << 8);
> +               }
> +
> +               src += src_stride;
> +               dst += dst_stride;
> +       }
> +}
> +
> +static void sdrm_blit_from_rgb565(const u8 *src,
> +                                 u32 src_stride,
> +                                 u32 src_bpp,
> +                                 u8 *dst,
> +                                 u32 dst_stride,
> +                                 u32 dst_bpp,
> +                                 u32 dst_four_cc,
> +                                 u32 width,
> +                                 u32 height)
> +{
> +       u32 val, i;
> +
> +       while (height--) {
> +               for (i = 0; i < width; ++i) {
> +                       val = get_unaligned((const u16 *)&src[i * src_bpp]);
> +                       sdrm_put(&dst[i * dst_bpp], dst_four_cc,
> +                                (val & 0xf800),
> +                                (val & 0x07e0) << 5,
> +                                (val & 0x001f) << 11);
> +               }
> +
> +               src += src_stride;
> +               dst += dst_stride;
> +       }
> +}
> +
> +static void sdrm_blit_lines(const u8 *src,
> +                           u32 src_stride,
> +                           u8 *dst,
> +                           u32 dst_stride,
> +                           u32 bpp,
> +                           u32 width,
> +                           u32 height)
> +{
> +       u32 len;
> +
> +       len = width * bpp;
> +
> +       while (height--) {
> +               memcpy(dst, src, len);
> +               src += src_stride;
> +               dst += dst_stride;
> +       }
> +}
> +
> +static void sdrm_blit(struct sdrm_hw *hw,
> +                     struct sdrm_fb *fb,
> +                     u32 x,
> +                     u32 y,
> +                     u32 width,
> +                     u32 height)
> +{
> +       u32 src_bpp, dst_bpp;
> +       u8 *src, *dst;
> +
> +       src = fb->bo->vmapping;
> +       src_bpp = DIV_ROUND_UP(fb->base.bits_per_pixel, 8);
> +       src += fb->base.offsets[0] + y * fb->base.pitches[0] + x * src_bpp;
> +
> +       dst = hw->map;
> +       dst_bpp = DIV_ROUND_UP(hw->bpp, 8);
> +       dst += y * hw->stride + x * dst_bpp;
> +
> +       if (fb->base.pixel_format == hw->format) {
> +               /* if formats are identical, do a line-by-line copy.. */
> +               sdrm_blit_lines(src, fb->base.pitches[0],
> +                               dst, hw->stride, src_bpp, width, height);
> +       } else {
> +               /* ..otherwise call slow blit-function */
> +               switch (fb->base.pixel_format) {
> +               case DRM_FORMAT_ARGB8888:
> +               case DRM_FORMAT_XRGB8888:
> +                       sdrm_blit_from_xrgb8888(src, fb->base.pitches[0],
> +                                               src_bpp, dst, hw->stride,
> +                                               dst_bpp, hw->format,
> +                                               width, height);
> +                       break;
> +               case DRM_FORMAT_RGB565:
> +                       sdrm_blit_from_rgb565(src, fb->base.pitches[0],
> +                                             src_bpp, dst, hw->stride,
> +                                             dst_bpp, hw->format,
> +                                             width, height);
> +                       break;
> +               }
> +       }
> +}
> +
> +void sdrm_dirty(struct sdrm_fb *fb, u32 x, u32 y, u32 width, u32 height)
> +{
> +       struct sdrm_device *sdrm = fb->base.dev->dev_private;
> +
> +       if (WARN_ON(!fb->bo->vmapping))
> +               return;
> +
> +       mutex_lock(&sdrm->hw->lock);
> +       if (sdrm->hw->map)
> +               sdrm_blit(sdrm->hw, fb, x, y, width, height);
> +       mutex_unlock(&sdrm->hw->lock);
> +}
> diff --git a/drivers/gpu/drm/simpledrm/simpledrm_drv.c b/drivers/gpu/drm/simpledrm/simpledrm_drv.c
> new file mode 100644
> index 0000000..d569120
> --- /dev/null
> +++ b/drivers/gpu/drm/simpledrm/simpledrm_drv.c
> @@ -0,0 +1,464 @@
> +/*
> + * Copyright (C) 2012-2016 Red Hat, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License as published by the
> + * Free Software Foundation; either version 2.1 of the License, or (at your
> + * option) any later version.
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +#include <drm/drmP.h>
> +#include <linux/atomic.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_data/simplefb.h>
> +#include <linux/string.h>
> +#include "simpledrm.h"
> +
> +static struct drm_driver sdrm_drm_driver;
> +static DEFINE_MUTEX(sdrm_lock);
> +
> +static int sdrm_hw_identify(struct platform_device *pdev,
> +                           struct simplefb_platform_data *modep,
> +                           struct simplefb_format *formatp,
> +                           struct resource **memp,
> +                           u32 *bppp)
> +{
> +       static const struct simplefb_format valid_formats[] = SIMPLEFB_FORMATS;
> +       struct simplefb_platform_data pm = {}, *mode = pdev->dev.platform_data;
> +       struct device_node *np = pdev->dev.of_node;
> +       const struct simplefb_format *format = NULL;
> +       struct resource *mem;
> +       unsigned int depth;
> +       int r, bpp;
> +       size_t i;
> +
> +       if (!mode) {
> +               if (!np)
> +                       return -ENODEV;
> +
> +               mode = &pm;
> +
> +               r = of_property_read_u32(np, "width", &mode->width);
> +               if (r >= 0)
> +                       r = of_property_read_u32(np, "height", &mode->height);
> +               if (r >= 0)
> +                       r = of_property_read_u32(np, "stride", &mode->stride);
> +               if (r >= 0)
> +                       r = of_property_read_string(np, "format",
> +                                                   &mode->format);
> +               if (r < 0)
> +                       return r;
> +       }
> +
> +       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       if (!mem)
> +               return -ENODEV;
> +
> +       for (i = 0; i < ARRAY_SIZE(valid_formats); ++i) {
> +               if (!strcmp(mode->format, valid_formats[i].name)) {
> +                       format = &valid_formats[i];
> +                       break;
> +               }
> +       }
> +
> +       if (!format)
> +               return -ENODEV;
> +
> +       switch (format->fourcc) {
> +       case DRM_FORMAT_RGB565:
> +       case DRM_FORMAT_XRGB1555:
> +       case DRM_FORMAT_ARGB1555:
> +       case DRM_FORMAT_RGB888:
> +       case DRM_FORMAT_XRGB8888:
> +       case DRM_FORMAT_ARGB8888:
> +       case DRM_FORMAT_ABGR8888:
> +       case DRM_FORMAT_XRGB2101010:
> +       case DRM_FORMAT_ARGB2101010:
> +               /*
> +                * You must adjust sdrm_put() whenever you add a new format
> +                * here, otherwise, blitting operations will not work.
> +                * Furthermore, include/linux/platform_data/simplefb.h needs
> +                * to be adjusted so the platform-device actually allows this
> +                * format.
> +                */
> +               break;
> +       default:
> +               return -ENODEV;
> +       }
> +
> +       drm_fb_get_bpp_depth(format->fourcc, &depth, &bpp);
> +       if (!bpp)
> +               return -ENODEV;
> +       if (resource_size(mem) < mode->stride * mode->height)
> +               return -ENODEV;
> +       if ((bpp + 7) / 8 * mode->width > mode->stride)

DIV_ROUND_UP?

> +               return -ENODEV;
> +
> +       *modep = *mode;
> +       *formatp = *format;
> +       *memp = mem;
> +       *bppp = bpp;
> +       return 0;
> +}
> +
> +static struct sdrm_hw *sdrm_hw_new(const struct simplefb_platform_data *mode,
> +                                  const struct simplefb_format *format,
> +                                  const struct resource *mem,
> +                                  u32 bpp)
> +{
> +       struct sdrm_hw *hw;
> +
> +       hw = kzalloc(sizeof(*hw), GFP_KERNEL);
> +       if (!hw)
> +               return ERR_PTR(-ENOMEM);
> +
> +       mutex_init(&hw->lock);
> +       hw->width = mode->width;
> +       hw->height = mode->height;
> +       hw->stride = mode->stride;
> +       hw->bpp = bpp;
> +       hw->format = format->fourcc;
> +       hw->base = mem->start;
> +       hw->size = resource_size(mem);
> +
> +       return hw;
> +}
> +
> +static struct sdrm_hw *sdrm_hw_free(struct sdrm_hw *hw)
> +{
> +       if (!hw)
> +               return NULL;
> +
> +       WARN_ON(hw->map);
> +       mutex_destroy(&hw->lock);
> +       kfree(hw);
> +
> +       return NULL;
> +}
> +
> +static int sdrm_hw_bind(struct sdrm_hw *hw)
> +{
> +       mutex_lock(&hw->lock);
> +       if (!hw->map)
> +               hw->map = ioremap_wc(hw->base, hw->size);
> +       mutex_unlock(&hw->lock);
> +
> +       return hw->map ? 0 : -EIO;
> +}
> +
> +static void sdrm_hw_unbind(struct sdrm_hw *hw)
> +{
> +       if (!hw)
> +               return;
> +
> +       mutex_lock(&hw->lock);
> +       if (hw->map) {
> +               iounmap(hw->map);
> +               hw->map = NULL;
> +       }
> +       mutex_unlock(&hw->lock);
> +}
> +
> +static struct sdrm_device *sdrm_device_free(struct sdrm_device *sdrm)
> +{
> +       if (!sdrm)
> +               return NULL;
> +
> +       WARN_ON(atomic_read(&sdrm->n_used) != INT_MIN);
> +       sdrm->hw = sdrm_hw_free(sdrm->hw);
> +       drm_dev_unref(sdrm->ddev);
> +       kfree(sdrm);
> +
> +       return NULL;
> +}
> +
> +static struct sdrm_device *sdrm_device_new(struct platform_device *pdev,
> +                                          struct sdrm_hw *hw)
> +{
> +       struct sdrm_device *sdrm;
> +       int r;
> +
> +       sdrm = kzalloc(sizeof(*sdrm), GFP_KERNEL);
> +       if (!sdrm)
> +               return ERR_PTR(-ENOMEM);
> +
> +       atomic_set(&sdrm->n_used, INT_MIN);
> +
> +       sdrm->ddev = drm_dev_alloc(&sdrm_drm_driver, &pdev->dev);
> +       if (!sdrm->ddev) {
> +               r = -ENOMEM;
> +               goto error;
> +       }
> +
> +       sdrm->ddev->dev_private = sdrm;
> +       sdrm->hw = hw;
> +
> +       return sdrm;
> +
> +error:
> +       sdrm_device_free(sdrm);
> +       return ERR_PTR(r);
> +}
> +
> +static void sdrm_device_unbind(struct sdrm_device *sdrm)
> +{
> +       if (sdrm) {
> +               sdrm_kms_unbind(sdrm);
> +               sdrm_hw_unbind(sdrm->hw);
> +               sdrm_of_unbind(sdrm);
> +       }
> +}
> +
> +static int sdrm_device_bind(struct sdrm_device *sdrm)
> +{
> +       int r;
> +
> +       r = sdrm_of_bind(sdrm);
> +       if (r < 0)
> +               goto error;
> +
> +       r = sdrm_hw_bind(sdrm->hw);
> +       if (r < 0)
> +               goto error;
> +
> +       r = sdrm_kms_bind(sdrm);
> +       if (r < 0)
> +               goto error;
> +
> +       return 0;
> +
> +error:
> +       sdrm_device_unbind(sdrm);
> +       return r;
> +}
> +
> +static int sdrm_device_acquire(struct sdrm_device *sdrm)
> +{
> +       return (sdrm && atomic_inc_unless_negative(&sdrm->n_used))
> +               ? 0 : -ENODEV;
> +}
> +
> +static void sdrm_device_release(struct sdrm_device *sdrm)
> +{
> +       if (sdrm && atomic_dec_return(&sdrm->n_used) == INT_MIN) {
> +               sdrm_device_unbind(sdrm);
> +               sdrm_device_free(sdrm);
> +       }
> +}
> +
> +static int sdrm_fop_open(struct inode *inode, struct file *file)
> +{
> +       struct drm_device *ddev;
> +       int r;
> +
> +       mutex_lock(&sdrm_lock);
> +       r = drm_open(inode, file);
> +       if (r >= 0) {
> +               ddev = file->private_data;
> +               r = sdrm_device_acquire(ddev->dev_private);
> +               if (r < 0)
> +                       drm_release(inode, file);
> +       }
> +       mutex_unlock(&sdrm_lock);
> +
> +       return r;
> +}
> +
> +static int sdrm_fop_release(struct inode *inode, struct file *file)
> +{
> +       struct drm_file *dfile = file->private_data;
> +       struct drm_device *ddev = dfile->minor->dev;
> +       struct sdrm_device *sdrm = ddev->dev_private;
> +       int res;
> +
> +       res = drm_release(inode, file);
> +       sdrm_device_release(sdrm);
> +       return res;
> +}
> +
> +static int sdrm_fop_mmap(struct file *file, struct vm_area_struct *vma)
> +{
> +       struct drm_file *dfile = file->private_data;
> +       struct drm_device *dev = dfile->minor->dev;
> +       struct drm_gem_object *obj = NULL;
> +       struct drm_vma_offset_node *node;
> +       int r;
> +
> +       drm_vma_offset_lock_lookup(dev->vma_offset_manager);
> +       node = drm_vma_offset_exact_lookup_locked(dev->vma_offset_manager,
> +                                                 vma->vm_pgoff,
> +                                                 vma_pages(vma));
> +       if (likely(node)) {
> +               obj = container_of(node, struct drm_gem_object, vma_node);
> +               if (!kref_get_unless_zero(&obj->refcount))
> +                       obj = NULL;
> +       }
> +       drm_vma_offset_unlock_lookup(dev->vma_offset_manager);
> +
> +       if (!obj)
> +               return -EINVAL;
> +
> +       if (!drm_vma_node_is_allowed(node, dfile)) {
> +               drm_gem_object_unreference_unlocked(obj);
> +               return -EACCES;
> +       }
> +
> +       if (vma->vm_file)
> +               fput(vma->vm_file);
> +       vma->vm_file = get_file(obj->filp);
> +       vma->vm_pgoff = 0;
> +
> +       r = obj->filp->f_op->mmap(obj->filp, vma);
> +       drm_gem_object_unreference_unlocked(obj);
> +       return r;
> +}
> +
> +static int sdrm_simplefb_probe(struct platform_device *pdev)
> +{
> +       struct simplefb_platform_data hw_mode;
> +       struct simplefb_format hw_format;
> +       struct sdrm_device *sdrm = NULL;
> +       struct sdrm_hw *hw = NULL;
> +       struct resource *hw_mem;
> +       u32 hw_bpp;
> +       int r;
> +
> +       r = sdrm_hw_identify(pdev, &hw_mode, &hw_format, &hw_mem, &hw_bpp);
> +       if (r < 0)
> +               goto error;
> +
> +       hw = sdrm_hw_new(&hw_mode, &hw_format, hw_mem, hw_bpp);
> +       if (IS_ERR(hw)) {
> +               r = PTR_ERR(hw);
> +               hw = NULL;
> +               goto error;
> +       }
> +
> +       sdrm = sdrm_device_new(pdev, hw);
> +       if (IS_ERR(sdrm)) {
> +               r = PTR_ERR(sdrm);
> +               sdrm = NULL;
> +               goto error;
> +       }
> +       hw = NULL;
> +       platform_set_drvdata(pdev, sdrm);
> +
> +       r = sdrm_device_bind(sdrm);
> +       if (r < 0)
> +               goto error;
> +
> +       /* mark device as enabled and acquire bus ref */
> +       WARN_ON(atomic_read(&sdrm->n_used) != INT_MIN);
> +       atomic_set(&sdrm->n_used, 1);
> +
> +       r = drm_dev_register(sdrm->ddev, 0);
> +       if (r < 0) {
> +               /* mark device as disabled and drop bus ref */
> +               WARN_ON(atomic_add_return(INT_MIN, &sdrm->n_used) != INT_MIN);
> +               sdrm_device_release(sdrm);
> +               return r;
> +       }
> +
> +       dev_info(sdrm->ddev->dev, "initialized %s on minor %d\n",
> +                sdrm->ddev->driver->name, sdrm->ddev->primary->index);
> +
> +       return 0;
> +
> +error:
> +       sdrm_device_unbind(sdrm);
> +       sdrm_device_free(sdrm);
> +       sdrm_hw_free(hw);
> +       return r;
> +}
> +
> +static int sdrm_simplefb_remove(struct platform_device *pdev)
> +{
> +       struct sdrm_device *sdrm = platform_get_drvdata(pdev);
> +
> +       /* mark device as disabled */
> +       atomic_add(INT_MIN, &sdrm->n_used);
> +       sdrm_hw_unbind(sdrm->hw);
> +
> +       mutex_lock(&sdrm_lock);
> +       drm_dev_unregister(sdrm->ddev);
> +       sdrm_device_release(sdrm);
> +       mutex_unlock(&sdrm_lock);
> +
> +       return 0;
> +}
> +
> +static const struct file_operations sdrm_drm_fops = {
> +       .owner = THIS_MODULE,
> +       .open = sdrm_fop_open,
> +       .release = sdrm_fop_release,
> +       .mmap = sdrm_fop_mmap,
> +       .poll = drm_poll,
> +       .read = drm_read,
> +       .unlocked_ioctl = drm_ioctl,
> +#ifdef CONFIG_COMPAT
> +       .compat_ioctl = drm_compat_ioctl,
> +#endif
> +       .llseek = noop_llseek,
> +};
> +
> +static struct drm_driver sdrm_drm_driver = {
> +       .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
> +       .fops = &sdrm_drm_fops,
> +
> +       .gem_free_object = sdrm_bo_free,
> +
> +       .dumb_create = sdrm_dumb_create,
> +       .dumb_map_offset = sdrm_dumb_map_offset,
> +       .dumb_destroy = drm_gem_dumb_destroy,
> +
> +       .name = "simpledrm",
> +       .desc = "Simple firmware framebuffer DRM driver",
> +       .date = "20160901",
> +};
> +
> +static const struct of_device_id sdrm_simplefb_of_match[] = {
> +       { .compatible = "simple-framebuffer", },
> +       {},
> +};
> +MODULE_DEVICE_TABLE(of, sdrm_simplefb_of_match);
> +
> +static struct platform_driver sdrm_simplefb_driver = {
> +       .probe = sdrm_simplefb_probe,
> +       .remove = sdrm_simplefb_remove,
> +       .driver = {
> +               .name = "simple-framebuffer",
> +               .mod_name = KBUILD_MODNAME,
> +               .owner = THIS_MODULE,
> +               .of_match_table = sdrm_simplefb_of_match,
> +       },
> +};
> +
> +static int __init sdrm_init(void)
> +{
> +       int r;
> +
> +       r = platform_driver_register(&sdrm_simplefb_driver);
> +       if (r < 0)
> +               return r;
> +
> +       sdrm_of_bootstrap();
> +       return 0;
> +}
> +
> +static void __exit sdrm_exit(void)
> +{
> +       platform_driver_unregister(&sdrm_simplefb_driver);
> +}
> +
> +module_init(sdrm_init);
> +module_exit(sdrm_exit);
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Simple firmware framebuffer DRM driver");
> +MODULE_ALIAS("platform:simple-framebuffer");
> diff --git a/drivers/gpu/drm/simpledrm/simpledrm_gem.c b/drivers/gpu/drm/simpledrm/simpledrm_gem.c
> new file mode 100644
> index 0000000..4aaae6e
> --- /dev/null
> +++ b/drivers/gpu/drm/simpledrm/simpledrm_gem.c
> @@ -0,0 +1,109 @@
> +/*
> + * Copyright (C) 2012-2016 Red Hat, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License as published by the
> + * Free Software Foundation; either version 2.1 of the License, or (at your
> + * option) any later version.
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +#include <drm/drmP.h>
> +#include <drm/drm_gem.h>
> +#include <linux/err.h>
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/vmalloc.h>
> +#include "simpledrm.h"
> +
> +struct sdrm_bo *sdrm_bo_new(struct drm_device *ddev, size_t size)
> +{
> +       struct sdrm_bo *bo;
> +
> +       WARN_ON(!size || (size & ~PAGE_MASK) != 0);
> +
> +       bo = kzalloc(sizeof(*bo), GFP_KERNEL);
> +       if (!bo)
> +               return NULL;
> +
> +       if (drm_gem_object_init(ddev, &bo->base, size)) {
> +               kfree(bo);
> +               return NULL;
> +       }
> +
> +       return bo;
> +}
> +
> +void sdrm_bo_free(struct drm_gem_object *dobj)
> +{
> +       struct sdrm_bo *bo = container_of(dobj, struct sdrm_bo, base);
> +
> +       if (bo->vmapping)
> +               vunmap(bo->vmapping);
> +       if (bo->pages)
> +               drm_gem_put_pages(dobj, bo->pages, false, false);
> +       drm_gem_object_release(dobj);
> +       kfree(bo);
> +}
> +
> +int sdrm_bo_vmap(struct sdrm_bo *bo)
> +{
> +       int r;
> +
> +       if (!bo->pages) {
> +               bo->pages = drm_gem_get_pages(&bo->base);
> +               if (IS_ERR(bo->pages)) {
> +                       r = PTR_ERR(bo->pages);
> +                       bo->pages = NULL;
> +                       return r;
> +               }
> +       }
> +
> +       if (!bo->vmapping) {
> +               bo->vmapping = vmap(bo->pages, bo->base.size / PAGE_SIZE, 0,
> +                                   PAGE_KERNEL);
> +               if (!bo->vmapping)
> +                       return -ENOMEM;
> +       }
> +
> +       return 0;
> +}
> +
> +int sdrm_dumb_create(struct drm_file *dfile,
> +                    struct drm_device *ddev,
> +                    struct drm_mode_create_dumb *args)
> +{
> +       struct sdrm_bo *bo;
> +       int r;
> +
> +       /* overflow checks are done by DRM core */
> +       args->pitch = (args->bpp + 7) / 8 * args->width;

DIV_ROUND_UP?

> +       args->size = PAGE_ALIGN(args->pitch * args->height);
> +
> +       bo = sdrm_bo_new(ddev, args->size);
> +       if (!bo)
> +               return -ENOMEM;
> +
> +       r = drm_gem_handle_create(dfile, &bo->base, &args->handle);
> +       drm_gem_object_unreference_unlocked(&bo->base);
> +       return r;
> +}
> +
> +int sdrm_dumb_map_offset(struct drm_file *dfile,
> +                        struct drm_device *ddev,
> +                        uint32_t handle,
> +                        uint64_t *offset)
> +{
> +       struct drm_gem_object *dobj;
> +       int r;
> +
> +       dobj = drm_gem_object_lookup(dfile, handle);
> +       if (!dobj)
> +               return -ENOENT;
> +
> +       r = drm_gem_create_mmap_offset(dobj);
> +       if (r >= 0)
> +               *offset = drm_vma_node_offset_addr(&dobj->vma_node);
> +       drm_gem_object_unreference_unlocked(dobj);
> +       return r;
> +}
> diff --git a/drivers/gpu/drm/simpledrm/simpledrm_kms.c b/drivers/gpu/drm/simpledrm/simpledrm_kms.c
> new file mode 100644
> index 0000000..00101c9
> --- /dev/null
> +++ b/drivers/gpu/drm/simpledrm/simpledrm_kms.c
> @@ -0,0 +1,263 @@
> +/*
> + * Copyright (C) 2012-2016 Red Hat, Inc.
> + * Copyright (C) 2016 Noralf Trønnes
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License as published by the
> + * Free Software Foundation; either version 2.1 of the License, or (at your
> + * option) any later version.
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +#include <drm/drmP.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_gem.h>
> +#include <drm/drm_simple_kms_helper.h>
> +#include <linux/err.h>
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include "simpledrm.h"
> +
> +static const uint32_t sdrm_formats[] = {
> +       DRM_FORMAT_RGB565,
> +       DRM_FORMAT_ARGB8888,
> +       DRM_FORMAT_XRGB8888,
> +};
> +
> +static int sdrm_conn_get_modes(struct drm_connector *conn)
> +{
> +       struct sdrm_device *sdrm = conn->dev->dev_private;
> +       struct drm_display_mode *mode;
> +
> +       mode = drm_cvt_mode(sdrm->ddev, sdrm->hw->width, sdrm->hw->height,
> +                           60, false, false, false);
> +       if (!mode)
> +               return 0;
> +
> +       mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
> +       drm_mode_set_name(mode);
> +       drm_mode_probed_add(conn, mode);
> +
> +       return 1;
> +}
> +
> +static const struct drm_connector_helper_funcs sdrm_conn_hfuncs = {
> +       .get_modes      = sdrm_conn_get_modes,
> +       .best_encoder   = drm_atomic_helper_best_encoder,
> +};
> +
> +static enum drm_connector_status sdrm_conn_detect(struct drm_connector *conn,
> +                                                 bool force)
> +{
> +       /*
> +        * We simulate an always connected monitor. simple-fb doesn't
> +        * provide any way to detect whether the connector is active. Hence,
> +        * signal DRM core that it is always connected.
> +        */
> +       return connector_status_connected;
> +}
> +
> +static const struct drm_connector_funcs sdrm_conn_ops = {
> +       .dpms                   = drm_atomic_helper_connector_dpms,
> +       .reset                  = drm_atomic_helper_connector_reset,
> +       .detect                 = sdrm_conn_detect,
> +       .fill_modes             = drm_helper_probe_single_connector_modes,
> +       .destroy                = drm_connector_cleanup,
> +       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> +       .atomic_destroy_state   = drm_atomic_helper_connector_destroy_state,
> +};
> +
> +static void sdrm_crtc_send_vblank_event(struct drm_crtc *crtc)
> +{
> +       if (crtc->state && crtc->state->event) {
> +               spin_lock_irq(&crtc->dev->event_lock);
> +               drm_crtc_send_vblank_event(crtc, crtc->state->event);
> +               spin_unlock_irq(&crtc->dev->event_lock);
> +               crtc->state->event = NULL;
> +       }
> +}
> +
> +void sdrm_display_pipe_update(struct drm_simple_display_pipe *pipe,
> +                             struct drm_plane_state *plane_state)
> +{
> +       struct drm_framebuffer *dfb = pipe->plane.state->fb;
> +       struct sdrm_fb *fb;
> +
> +       sdrm_crtc_send_vblank_event(&pipe->crtc);
> +
> +       if (dfb) {
> +               fb = container_of(dfb, struct sdrm_fb, base);
> +               pipe->plane.fb = dfb;
> +               sdrm_dirty(fb, 0, 0, dfb->width, dfb->height);
> +       }
> +}
> +
> +static void sdrm_display_pipe_enable(struct drm_simple_display_pipe *pipe,
> +                                    struct drm_crtc_state *crtc_state)
> +{
> +       sdrm_crtc_send_vblank_event(&pipe->crtc);
> +}
> +
> +static void sdrm_display_pipe_disable(struct drm_simple_display_pipe *pipe)
> +{
> +       sdrm_crtc_send_vblank_event(&pipe->crtc);
> +}
> +
> +static const struct drm_simple_display_pipe_funcs sdrm_pipe_funcs = {
> +       .update         = sdrm_display_pipe_update,
> +       .enable         = sdrm_display_pipe_enable,
> +       .disable        = sdrm_display_pipe_disable,
> +};
> +
> +static int sdrm_fb_create_handle(struct drm_framebuffer *dfb,
> +                                struct drm_file *dfile,
> +                                unsigned int *handle)
> +{
> +       struct sdrm_fb *fb = container_of(dfb, struct sdrm_fb, base);
> +
> +       return drm_gem_handle_create(dfile, &fb->bo->base, handle);
> +}
> +
> +static int sdrm_fb_dirty(struct drm_framebuffer *dfb,
> +                        struct drm_file *dfile,
> +                        unsigned int flags,
> +                        unsigned int color,
> +                        struct drm_clip_rect *clips,
> +                        unsigned int n_clips)
> +{
> +       struct sdrm_fb *fb = container_of(dfb, struct sdrm_fb, base);
> +       struct sdrm_device *sdrm = dfb->dev->dev_private;
> +       unsigned int i;
> +
> +       drm_modeset_lock_all(sdrm->ddev);
> +       if (dfb == sdrm->pipe.plane.fb) {
> +               if (!clips || !n_clips) {
> +                       sdrm_dirty(fb, 0, 0, dfb->width, dfb->height);
> +               } else {
> +                       for (i = 0; i < n_clips; i++) {
> +                               if (clips[i].x1 > clips[i].x2 ||
> +                                   clips[i].x2 > dfb->width ||
> +                                   clips[i].y1 > clips[i].y2 ||
> +                                   clips[i].y2 > dfb->height)

As discussed in private, overlapping clip_rects should be cropped to
fit the fb, rather than discarded.

> +                                       continue;
> +
> +                               sdrm_dirty(fb, clips[i].x1, clips[i].y1,
> +                                          clips[i].x2 - clips[i].x1,
> +                                          clips[i].y2 - clips[i].y1);
> +                       }
> +               }
> +       }
> +       drm_modeset_unlock_all(sdrm->ddev);
> +
> +       return 0;
> +}
> +
> +static void sdrm_fb_destroy(struct drm_framebuffer *dfb)
> +{
> +       struct sdrm_fb *fb = container_of(dfb, struct sdrm_fb, base);
> +
> +       drm_framebuffer_cleanup(dfb);
> +       drm_gem_object_unreference_unlocked(&fb->bo->base);
> +       kfree(fb);
> +}
> +
> +static const struct drm_framebuffer_funcs sdrm_fb_ops = {
> +       .create_handle          = sdrm_fb_create_handle,
> +       .dirty                  = sdrm_fb_dirty,
> +       .destroy                = sdrm_fb_destroy,
> +};
> +
> +static struct drm_framebuffer *
> +sdrm_fb_create(struct drm_device *ddev,
> +              struct drm_file *dfile,
> +              const struct drm_mode_fb_cmd2 *cmd)
> +{
> +       struct drm_gem_object *dobj;
> +       struct sdrm_fb *fb = NULL;
> +       struct sdrm_bo *bo;
> +       int r;
> +
> +       if (cmd->flags)
> +               return ERR_PTR(-EINVAL);
> +
> +       dobj = drm_gem_object_lookup(dfile, cmd->handles[0]);
> +       if (!dobj)
> +               return ERR_PTR(-EINVAL);
> +
> +       bo = container_of(dobj, struct sdrm_bo, base);
> +
> +       r = sdrm_bo_vmap(bo);
> +       if (r < 0)
> +               goto error;
> +
> +       fb = kzalloc(sizeof(*fb), GFP_KERNEL);
> +       if (!fb) {
> +               r = -ENOMEM;
> +               goto error;
> +       }
> +
> +       fb->bo = bo;
> +       drm_helper_mode_fill_fb_struct(&fb->base, cmd);
> +
> +       r = drm_framebuffer_init(ddev, &fb->base, &sdrm_fb_ops);
> +       if (r < 0)
> +               goto error;
> +
> +       DRM_DEBUG_KMS("[FB:%d] pixel_format: %s\n", fb->base.base.id,
> +                     drm_get_format_name(fb->base.pixel_format));
> +
> +       return &fb->base;
> +
> +error:
> +       kfree(fb);
> +       drm_gem_object_unreference_unlocked(dobj);
> +       return ERR_PTR(r);
> +}
> +
> +static const struct drm_mode_config_funcs sdrm_mode_config_ops = {
> +       .fb_create              = sdrm_fb_create,
> +       .atomic_check           = drm_atomic_helper_check,
> +       .atomic_commit          = drm_atomic_helper_commit,
> +};
> +
> +int sdrm_kms_bind(struct sdrm_device *sdrm)
> +{
> +       struct drm_connector *conn = &sdrm->conn;
> +       struct drm_device *ddev = sdrm->ddev;
> +       int r;
> +
> +       drm_mode_config_init(ddev);
> +       ddev->mode_config.min_width = sdrm->hw->width;
> +       ddev->mode_config.max_width = sdrm->hw->width;
> +       ddev->mode_config.min_height = sdrm->hw->height;
> +       ddev->mode_config.max_height = sdrm->hw->height;
> +       ddev->mode_config.preferred_depth = sdrm->hw->bpp;
> +       ddev->mode_config.funcs = &sdrm_mode_config_ops;
> +       drm_connector_helper_add(conn, &sdrm_conn_hfuncs);
> +
> +       r = drm_connector_init(ddev, conn, &sdrm_conn_ops,
> +                              DRM_MODE_CONNECTOR_VIRTUAL);
> +       if (r < 0)
> +               goto error;
> +
> +       r = drm_simple_display_pipe_init(ddev, &sdrm->pipe, &sdrm_pipe_funcs,
> +                                        sdrm_formats,
> +                                        ARRAY_SIZE(sdrm_formats), conn);
> +       if (r < 0)
> +               goto error;
> +
> +       drm_mode_config_reset(ddev);
> +       return 0;
> +
> +error:
> +       drm_mode_config_cleanup(ddev);
> +       return r;
> +}
> +
> +void sdrm_kms_unbind(struct sdrm_device *sdrm)
> +{
> +       if (sdrm->ddev->mode_config.funcs)
> +               drm_mode_config_cleanup(sdrm->ddev);
> +}
> diff --git a/drivers/gpu/drm/simpledrm/simpledrm_of.c b/drivers/gpu/drm/simpledrm/simpledrm_of.c
> new file mode 100644
> index 0000000..5620000
> --- /dev/null
> +++ b/drivers/gpu/drm/simpledrm/simpledrm_of.c
> @@ -0,0 +1,265 @@
> +/*
> + * Copyright (C) 2012-2016 Red Hat, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License as published by the
> + * Free Software Foundation; either version 2.1 of the License, or (at your
> + * option) any later version.
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +#include <drm/drmP.h>
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/err.h>
> +#include <linux/kernel.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/slab.h>
> +#include "simpledrm.h"
> +
> +#ifdef CONFIG_COMMON_CLK
> +
> +static int sdrm_of_bind_clocks(struct sdrm_device *sdrm,
> +                              struct device_node *np)
> +{
> +       struct clk *clock;
> +       size_t i, n;
> +       int r;
> +
> +       n = of_clk_get_parent_count(np);
> +       if (n < 1)
> +               return 0;
> +
> +       sdrm->clks = kcalloc(n, sizeof(*sdrm->clks), GFP_KERNEL);
> +       if (!sdrm->clks)
> +               return -ENOMEM;
> +
> +       for (i = 0; i < n; ++i) {
> +               clock = of_clk_get(np, i);
> +               if (!IS_ERR(clock)) {
> +                       sdrm->clks[sdrm->n_clks++] = clock;
> +               } else if (PTR_ERR(clock) == -EPROBE_DEFER) {
> +                       r = -EPROBE_DEFER;
> +                       goto error;
> +               } else {
> +                       dev_err(sdrm->ddev->dev, "cannot find clock %zu: %ld\n",
> +                               i, PTR_ERR(clock));
> +               }
> +       }
> +
> +       for (i = 0; i < sdrm->n_clks; ++i) {
> +               if (!sdrm->clks[i])
> +                       continue;
> +
> +               r = clk_prepare_enable(sdrm->clks[i]);
> +               if (r < 0) {
> +                       dev_err(sdrm->ddev->dev,
> +                               "cannot find clock %zu: %d\n", i, r);

"cannot enable clock" ?

> +                       clk_put(sdrm->clks[i]);
> +                       sdrm->clks[i] = NULL;
> +               }
> +       }
> +
> +       return 0;
> +
> +error:
> +       for (i = 0; i < sdrm->n_clks; ++i)
> +               clk_put(sdrm->clks[i]);
> +       kfree(sdrm->clks);
> +       sdrm->clks = NULL;
> +       sdrm->n_clks = 0;
> +       return r;
> +}
> +
> +static void sdrm_of_unbind_clocks(struct sdrm_device *sdrm)
> +{
> +       size_t i;
> +
> +       for (i = 0; i < sdrm->n_clks; ++i) {
> +               clk_disable_unprepare(sdrm->clks[i]);
> +               clk_put(sdrm->clks[i]);
> +       }
> +
> +       kfree(sdrm->clks);
> +       sdrm->clks = NULL;
> +       sdrm->n_clks = 0;
> +}
> +
> +#else /* CONFIG_COMMON_CLK */
> +
> +static int sdrm_of_bind_clocks(struct sdrm_device *sdrm,
> +                              struct device_node *np)
> +{
> +       return 0;
> +}
> +
> +static void sdrm_of_unbind_clocks(struct sdrm_device *sdrm)
> +{
> +}
> +
> +#endif /* CONFIG_COMMON_CLK */
> +
> +#ifdef CONFIG_REGULATOR
> +
> +static int sdrm_of_bind_regulators(struct sdrm_device *sdrm,
> +                                  struct device_node *np)
> +{
> +       struct regulator *regulator;
> +       struct property *prop;
> +       char *p, *name;
> +       size_t i, n;
> +       int r;
> +
> +       n = 0;
> +       for_each_property_of_node(np, prop) {
> +               p = strstr(prop->name, "-supply");
> +               if (p && p != prop->name)
> +                       ++n;
> +       }
> +
> +       if (n < 1)
> +               return 0;
> +
> +       sdrm->regulators = kcalloc(n, sizeof(*sdrm->regulators), GFP_KERNEL);
> +       if (!sdrm->regulators)
> +               return -ENOMEM;
> +
> +       for_each_property_of_node(np, prop) {
> +               p = strstr(prop->name, "-supply");
> +               if (!p || p == prop->name)
> +                       continue;
> +
> +               name = kstrndup(prop->name, p - prop->name, GFP_TEMPORARY);
> +               if (!name)
> +                       continue;
> +
> +               regulator = regulator_get_optional(sdrm->ddev->dev, name);
> +               kfree(name);
> +
> +               if (!IS_ERR(regulator)) {
> +                       sdrm->regulators[sdrm->n_regulators++] = regulator;
> +               } else if (PTR_ERR(regulator) == -EPROBE_DEFER) {
> +                       r = -EPROBE_DEFER;
> +                       goto error;
> +               } else {
> +                       dev_warn(sdrm->ddev->dev,
> +                                "cannot find regulator %s: %ld\n",
> +                                prop->name, PTR_ERR(regulator));
> +               }
> +       }
> +
> +       for (i = 0; i < sdrm->n_regulators; ++i) {
> +               if (!sdrm->regulators[i])
> +                       continue;
> +
> +               r = regulator_enable(sdrm->regulators[i]);
> +               if (r < 0) {
> +                       dev_warn(sdrm->ddev->dev,
> +                                "cannot enable regulator %zu: %d\n", i, r);
> +                       regulator_put(sdrm->regulators[i]);
> +                       sdrm->regulators[i] = NULL;
> +               }
> +       }
> +
> +       return 0;
> +
> +error:
> +       for (i = 0; i < sdrm->n_regulators; ++i)
> +               if (sdrm->regulators[i])
> +                       regulator_put(sdrm->regulators[i]);
> +       kfree(sdrm->regulators);
> +       sdrm->regulators = NULL;
> +       sdrm->n_regulators = 0;
> +       return r;
> +}
> +
> +static void sdrm_of_unbind_regulators(struct sdrm_device *sdrm)
> +{
> +       size_t i;
> +
> +       for (i = 0; i < sdrm->n_regulators; ++i) {
> +               if (sdrm->regulators[i]) {
> +                       regulator_disable(sdrm->regulators[i]);
> +                       regulator_put(sdrm->regulators[i]);
> +               }
> +       }
> +
> +       kfree(sdrm->regulators);
> +       sdrm->regulators = NULL;
> +       sdrm->n_regulators = 0;
> +}
> +
> +#else /* CONFIG_REGULATORS */
> +
> +static int sdrm_of_bind_regulators(struct sdrm_device *sdrm,
> +                                  struct device_node *np)
> +{
> +       return 0;
> +}
> +
> +static void sdrm_of_unbind_regulators(struct sdrm_device *sdrm)
> +{
> +}
> +
> +#endif /* CONFIG_REGULATORS */
> +
> +#ifdef CONFIG_OF
> +
> +void sdrm_of_bootstrap(void)
> +{
> +#ifdef CONFIG_OF_ADDRESS
> +       struct device_node *np;
> +
> +       for_each_compatible_node(np, NULL, "simple-framebuffer")
> +               of_platform_device_create(np, NULL, NULL);
> +#endif
> +}
> +
> +int sdrm_of_bind(struct sdrm_device *sdrm)
> +{
> +       int r;
> +
> +       if (WARN_ON(sdrm->n_clks > 0 || sdrm->n_regulators > 0))
> +               return 0;
> +       if (!sdrm->ddev->dev->of_node)
> +               return 0;
> +
> +       r = sdrm_of_bind_clocks(sdrm, sdrm->ddev->dev->of_node);
> +       if (r < 0)
> +               goto error;
> +
> +       r = sdrm_of_bind_regulators(sdrm, sdrm->ddev->dev->of_node);
> +       if (r < 0)
> +               goto error;
> +
> +       return 0;
> +
> +error:
> +       sdrm_of_unbind(sdrm);
> +       return r;
> +}
> +
> +void sdrm_of_unbind(struct sdrm_device *sdrm)
> +{
> +       sdrm_of_unbind_regulators(sdrm);
> +       sdrm_of_unbind_clocks(sdrm);
> +}
> +
> +#else /* CONFIG_OF */
> +
> +void sdrm_of_bootstrap(void)
> +{
> +}
> +
> +int sdrm_of_bind(struct sdrm_device *sdrm)
> +{
> +       return 0;
> +}
> +
> +void sdrm_of_unbind(struct sdrm_device *sdrm)
> +{
> +}
> +
> +#endif /* CONFIG_OF */
> --
> 2.9.3
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v5 6/7] drm: add SimpleDRM driver
  2016-09-02  8:22 ` [PATCH v5 6/7] drm: add SimpleDRM driver David Herrmann
  2016-09-02 12:45   ` Tom Gundersen
@ 2016-09-03 12:01   ` Noralf Trønnes
  2016-09-03 12:05     ` David Herrmann
  2016-09-05 16:39   ` Noralf Trønnes
  2 siblings, 1 reply; 31+ messages in thread
From: Noralf Trønnes @ 2016-09-03 12:01 UTC (permalink / raw)
  To: David Herrmann, dri-devel


Den 02.09.2016 10:22, skrev David Herrmann:
> The SimpleDRM driver binds to simple-framebuffer devices and provides a
> DRM/KMS API. It provides only a single CRTC+encoder+connector combination
> plus one initial mode.
>
> Userspace can create dumb-buffers which can be blit into the real
> framebuffer similar to UDL. No access to the real framebuffer is allowed
> (compared to earlier version of this driver) to avoid security issues.
> Furthermore, this way we can support arbitrary modes as long as we have a
> conversion-helper.
>
> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
> ---

[...]

> diff --git a/drivers/gpu/drm/simpledrm/simpledrm_drv.c b/drivers/gpu/drm/simpledrm/simpledrm_drv.c

[...]

> +static int sdrm_fop_mmap(struct file *file, struct vm_area_struct *vma)
> +{
> +	struct drm_file *dfile = file->private_data;
> +	struct drm_device *dev = dfile->minor->dev;
> +	struct drm_gem_object *obj = NULL;
> +	struct drm_vma_offset_node *node;
> +	int r;
> +
> +	drm_vma_offset_lock_lookup(dev->vma_offset_manager);
> +	node = drm_vma_offset_exact_lookup_locked(dev->vma_offset_manager,
> +						  vma->vm_pgoff,
> +						  vma_pages(vma));
> +	if (likely(node)) {
> +		obj = container_of(node, struct drm_gem_object, vma_node);
> +		if (!kref_get_unless_zero(&obj->refcount))
> +			obj = NULL;
> +	}
> +	drm_vma_offset_unlock_lookup(dev->vma_offset_manager);
> +
> +	if (!obj)
> +		return -EINVAL;
> +
> +	if (!drm_vma_node_is_allowed(node, dfile)) {

I get:
drivers/gpu/drm/simpledrm/simpledrm_drv.c:320:2: warning: passing 
argument 2 of ‘drm_vma_node_is_allowed’ from incompatible pointer type 
[enabled by default]

dfile -> file

> +		drm_gem_object_unreference_unlocked(obj);
> +		return -EACCES;
> +	}
> +
> +	if (vma->vm_file)
> +		fput(vma->vm_file);
> +	vma->vm_file = get_file(obj->filp);
> +	vma->vm_pgoff = 0;
> +
> +	r = obj->filp->f_op->mmap(obj->filp, vma);
> +	drm_gem_object_unreference_unlocked(obj);
> +	return r;
> +}

[...]

> diff --git a/drivers/gpu/drm/simpledrm/simpledrm_kms.c b/drivers/gpu/drm/simpledrm/simpledrm_kms.c

[...]

> +static void sdrm_crtc_send_vblank_event(struct drm_crtc *crtc)
> +{
> +	if (crtc->state && crtc->state->event) {
> +		spin_lock_irq(&crtc->dev->event_lock);
> +		drm_crtc_send_vblank_event(crtc, crtc->state->event);
> +		spin_unlock_irq(&crtc->dev->event_lock);
> +		crtc->state->event = NULL;
> +	}
> +}
> +
> +void sdrm_display_pipe_update(struct drm_simple_display_pipe *pipe,
> +			      struct drm_plane_state *plane_state)
> +{
> +	struct drm_framebuffer *dfb = pipe->plane.state->fb;
> +	struct sdrm_fb *fb;
> +
> +	sdrm_crtc_send_vblank_event(&pipe->crtc);
> +
> +	if (dfb) {
> +		fb = container_of(dfb, struct sdrm_fb, base);
> +		pipe->plane.fb = dfb;
> +		sdrm_dirty(fb, 0, 0, dfb->width, dfb->height);
> +	}
> +}
> +
> +static void sdrm_display_pipe_enable(struct drm_simple_display_pipe *pipe,
> +				     struct drm_crtc_state *crtc_state)
> +{
> +	sdrm_crtc_send_vblank_event(&pipe->crtc);
> +}
> +
> +static void sdrm_display_pipe_disable(struct drm_simple_display_pipe *pipe)
> +{
> +	sdrm_crtc_send_vblank_event(&pipe->crtc);
> +}
> +
> +static const struct drm_simple_display_pipe_funcs sdrm_pipe_funcs = {
> +	.update		= sdrm_display_pipe_update,
> +	.enable		= sdrm_display_pipe_enable,
> +	.disable	= sdrm_display_pipe_disable,
> +};

The enable and disable callbacks can be removed.
This commit in drm-misc fixed the flip done timeout:
drm/simple-helpers: Always add planes to the state update


Noralf.

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v5 7/7] drm/simpledrm: add fbdev fallback support
  2016-09-02  8:22 ` [PATCH v5 7/7] drm/simpledrm: add fbdev fallback support David Herrmann
@ 2016-09-03 12:04   ` Noralf Trønnes
  2016-09-03 17:15     ` Noralf Trønnes
  0 siblings, 1 reply; 31+ messages in thread
From: Noralf Trønnes @ 2016-09-03 12:04 UTC (permalink / raw)
  To: David Herrmann, dri-devel


Den 02.09.2016 10:22, skrev David Herrmann:
> Create a simple fbdev device during SimpleDRM setup so legacy user-space
> and fbcon can use it.
>
> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>

[...]

> diff --git a/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c b/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c

[...]

> +void sdrm_fbdev_bind(struct sdrm_device *sdrm)
> +{
> +	struct drm_fb_helper *fbdev;
> +	int r;
> +
> +	fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
> +	if (!fbdev)
> +		return;
> +
> +	drm_fb_helper_prepare(sdrm->ddev, fbdev, &sdrm_fbdev_funcs);
> +
> +	r = drm_fb_helper_init(sdrm->ddev, fbdev, 1, 1);
> +	if (r < 0)
> +		goto error;
> +
> +	r = drm_fb_helper_single_add_all_connectors(fbdev);
> +	if (r < 0)
> +		goto error;
> +
> +	r = drm_fb_helper_initial_config(fbdev,
> +				sdrm->ddev->mode_config.preferred_depth);
> +	if (r < 0)
> +		goto error;
> +
> +	if (!fbdev->fbdev)
> +		goto error;
> +
> +	sdrm->fbdev = fbdev;
> +	return;
> +
> +error:
> +	drm_fb_helper_fini(fbdev);
> +	kfree(fbdev);
> +}
> +
> +void sdrm_fbdev_unbind(struct sdrm_device *sdrm)
> +{
> +	struct drm_fb_helper *fbdev = sdrm->fbdev;
> +
> +	if (!fbdev)
> +		return;
> +
> +	sdrm->fbdev = NULL;
> +	drm_fb_helper_unregister_fbi(fbdev);
> +	cancel_work_sync(&fbdev->dirty_work);
> +	drm_fb_helper_release_fbi(fbdev);
> +	drm_framebuffer_unreference(fbdev->fb);

I get a warning that there are still fb's left during unbind:

[   48.666003] WARNING: CPU: 0 PID: 716 at 
drivers/gpu/drm/drm_crtc.c:3855 drm_mode_config_cleanup+0x180/0x1f4 [drm]

This worked:

-       drm_framebuffer_unreference(fbdev->fb);
+       drm_framebuffer_unregister_private(fbdev->fb);
+       drm_framebuffer_cleanup(fbdev->fb);


Noralf.

> +	fbdev->fb = NULL;
> +	drm_fb_helper_fini(fbdev);
> +	kfree(fbdev);
> +}

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v5 6/7] drm: add SimpleDRM driver
  2016-09-03 12:01   ` Noralf Trønnes
@ 2016-09-03 12:05     ` David Herrmann
  0 siblings, 0 replies; 31+ messages in thread
From: David Herrmann @ 2016-09-03 12:05 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: dri-devel

Hey

On Sat, Sep 3, 2016 at 2:01 PM, Noralf Trønnes <noralf@tronnes.org> wrote:
>
> Den 02.09.2016 10:22, skrev David Herrmann:
>>
>> The SimpleDRM driver binds to simple-framebuffer devices and provides a
>> DRM/KMS API. It provides only a single CRTC+encoder+connector combination
>> plus one initial mode.
>>
>> Userspace can create dumb-buffers which can be blit into the real
>> framebuffer similar to UDL. No access to the real framebuffer is allowed
>> (compared to earlier version of this driver) to avoid security issues.
>> Furthermore, this way we can support arbitrary modes as long as we have a
>> conversion-helper.
>>
>> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
>> ---
>
>
> [...]
>
>> diff --git a/drivers/gpu/drm/simpledrm/simpledrm_drv.c
>> b/drivers/gpu/drm/simpledrm/simpledrm_drv.c
>
>
> [...]
>
>> +static int sdrm_fop_mmap(struct file *file, struct vm_area_struct *vma)
>> +{
>> +       struct drm_file *dfile = file->private_data;
>> +       struct drm_device *dev = dfile->minor->dev;
>> +       struct drm_gem_object *obj = NULL;
>> +       struct drm_vma_offset_node *node;
>> +       int r;
>> +
>> +       drm_vma_offset_lock_lookup(dev->vma_offset_manager);
>> +       node = drm_vma_offset_exact_lookup_locked(dev->vma_offset_manager,
>> +                                                 vma->vm_pgoff,
>> +                                                 vma_pages(vma));
>> +       if (likely(node)) {
>> +               obj = container_of(node, struct drm_gem_object, vma_node);
>> +               if (!kref_get_unless_zero(&obj->refcount))
>> +                       obj = NULL;
>> +       }
>> +       drm_vma_offset_unlock_lookup(dev->vma_offset_manager);
>> +
>> +       if (!obj)
>> +               return -EINVAL;
>> +
>> +       if (!drm_vma_node_is_allowed(node, dfile)) {
>
>
> I get:
> drivers/gpu/drm/simpledrm/simpledrm_drv.c:320:2: warning: passing argument 2
> of ‘drm_vma_node_is_allowed’ from incompatible pointer type [enabled by
> default]
>
> dfile -> file

Yeah, either change that, or apply "[PATCH 0/6] DRM Core Cleanups"
before. I suspect the cleanups to go in before this driver, so didn't
bother changing it.

>> +               drm_gem_object_unreference_unlocked(obj);
>> +               return -EACCES;
>> +       }
>> +
>> +       if (vma->vm_file)
>> +               fput(vma->vm_file);
>> +       vma->vm_file = get_file(obj->filp);
>> +       vma->vm_pgoff = 0;
>> +
>> +       r = obj->filp->f_op->mmap(obj->filp, vma);
>> +       drm_gem_object_unreference_unlocked(obj);
>> +       return r;
>> +}
>
>
> [...]
>
>> diff --git a/drivers/gpu/drm/simpledrm/simpledrm_kms.c
>> b/drivers/gpu/drm/simpledrm/simpledrm_kms.c
>
>
> [...]
>
>
>> +static void sdrm_crtc_send_vblank_event(struct drm_crtc *crtc)
>> +{
>> +       if (crtc->state && crtc->state->event) {
>> +               spin_lock_irq(&crtc->dev->event_lock);
>> +               drm_crtc_send_vblank_event(crtc, crtc->state->event);
>> +               spin_unlock_irq(&crtc->dev->event_lock);
>> +               crtc->state->event = NULL;
>> +       }
>> +}
>> +
>> +void sdrm_display_pipe_update(struct drm_simple_display_pipe *pipe,
>> +                             struct drm_plane_state *plane_state)
>> +{
>> +       struct drm_framebuffer *dfb = pipe->plane.state->fb;
>> +       struct sdrm_fb *fb;
>> +
>> +       sdrm_crtc_send_vblank_event(&pipe->crtc);
>> +
>> +       if (dfb) {
>> +               fb = container_of(dfb, struct sdrm_fb, base);
>> +               pipe->plane.fb = dfb;
>> +               sdrm_dirty(fb, 0, 0, dfb->width, dfb->height);
>> +       }
>> +}
>> +
>> +static void sdrm_display_pipe_enable(struct drm_simple_display_pipe
>> *pipe,
>> +                                    struct drm_crtc_state *crtc_state)
>> +{
>> +       sdrm_crtc_send_vblank_event(&pipe->crtc);
>> +}
>> +
>> +static void sdrm_display_pipe_disable(struct drm_simple_display_pipe
>> *pipe)
>> +{
>> +       sdrm_crtc_send_vblank_event(&pipe->crtc);
>> +}
>> +
>> +static const struct drm_simple_display_pipe_funcs sdrm_pipe_funcs = {
>> +       .update         = sdrm_display_pipe_update,
>> +       .enable         = sdrm_display_pipe_enable,
>> +       .disable        = sdrm_display_pipe_disable,
>> +};
>
>
> The enable and disable callbacks can be removed.
> This commit in drm-misc fixed the flip done timeout:
> drm/simple-helpers: Always add planes to the state update

Right, Daniel told me on IRC already. With this fix applied, I can run
Xorg on top of it just fine.

I dropped the enable/disable callbacks as well now.

Thanks
David
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v5 4/7] video: add generic framebuffer eviction
  2016-09-02  8:22 ` [PATCH v5 4/7] video: add generic framebuffer eviction David Herrmann
  2016-09-02 10:21   ` Tom Gundersen
@ 2016-09-03 12:06   ` Noralf Trønnes
  2016-09-05 11:19     ` David Herrmann
  1 sibling, 1 reply; 31+ messages in thread
From: Noralf Trønnes @ 2016-09-03 12:06 UTC (permalink / raw)
  To: David Herrmann, dri-devel


Den 02.09.2016 10:22, skrev David Herrmann:
> There are several situations where we want hardware handover from an early
> boot GFX driver (e.g., vgacon, vesafb, efifb, simplefb) to a full fletched
> GFX driver (e.g., most DRM drivers). So far, we relied on
> remove_conflicting_framebuffers() to do this for us, however, this had a
> bunch of downsides:
>
>    o It only removes conflicting fbdev drivers. It does not drop vgacon,
>      early boot console drivers, conflicting DRM drivers, etc.
>
>    o It only unloads the fbdev driver, it does not modify the underlying
>      device or resources. In case of "screen_info" drivers (e.g., efifb)
>      this is fine, since no resources are pinned. However, if the driver
>      binds to a platform-device like "simple-framebuffer", we must make
>      sure to unregister that device as well. Otherwise, pinned resources
>      like IORESOURCE_MEM stay around, triggering WARN_ONs if the following
>      driver requests those resources.
>
>    o It is only available if CONFIG_FB is selected.
>
> This commit adds a new infrastructure that manages system-framebuffers
> (short: sysfb). The initial commit provides conflict-resolution for
> system-framebuffers. At its core it provides sysfb_evict_conflicts(),
> which implements conflict detection and removal for all known types of
> GFX driver hand-overs. So far, this includes platform-device removal,
> fbdev-firmware-device removal, vgacon removal and VBE detection. To
> further simplify the callers, it also provides helpers to figure out what
> hand-over to do, based on the device the new drivers binds to:
>
>    o PCI drivers can use sysfb_evict_conflicts_pci(), which will figure out
>      the apertures automatically, and does VGA/VBE detection.
>
>    o Generic firmware drivers that might be shadowed at any address in
>      memory can use sysfb_evict_conflicts_firmware(), basically removing
>      *all* firmware framebuffers in effect.
>
> This only adds the generic sysfb helpers. No users are converted, yet.
>
> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
> ---
>   drivers/video/Kconfig  |   4 +
>   drivers/video/Makefile |   1 +
>   drivers/video/sysfb.c  | 327 +++++++++++++++++++++++++++++++++++++++++++++++++
>   include/linux/sysfb.h  |  34 +++++
>   4 files changed, 366 insertions(+)
>   create mode 100644 drivers/video/sysfb.c
>   create mode 100644 include/linux/sysfb.h
>
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index 3c20af9..56a8294 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -36,6 +36,10 @@ config VIDEOMODE_HELPERS
>   config HDMI
>   	bool
>   
> +config SYSFB
> +	bool
> +	select DUMMY_CONSOLE if VT
> +
>   if VT
>   	source "drivers/video/console/Kconfig"
>   endif
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index 9ad3c17..df7bd75 100644
> --- a/drivers/video/Makefile
> +++ b/drivers/video/Makefile
> @@ -1,5 +1,6 @@
>   obj-$(CONFIG_VGASTATE)            += vgastate.o
>   obj-$(CONFIG_HDMI)                += hdmi.o
> +obj-$(CONFIG_SYSFB)		  += sysfb.o
>   
>   obj-$(CONFIG_VT)		  += console/
>   obj-$(CONFIG_LOGO)		  += logo/
> diff --git a/drivers/video/sysfb.c b/drivers/video/sysfb.c
> new file mode 100644
> index 0000000..00585c9
> --- /dev/null
> +++ b/drivers/video/sysfb.c
> @@ -0,0 +1,327 @@
> +/*
> + * Copyright (C) 2013-2016 Red Hat, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License as published by the
> + * Free Software Foundation; either version 2.1 of the License, or (at your
> + * option) any later version.
> + */
> +
> +#define pr_fmt(fmt) "sysfb: " fmt
> +#include <linux/console.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/export.h>
> +#include <linux/fb.h>
> +#include <linux/ioport.h>
> +#include <linux/kernel.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/pci.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/sysfb.h>
> +#include <linux/vt.h>
> +
> +static bool sysfb_evict_match_resource(struct sysfb_evict_ctx *ctx,
> +				       struct resource *mem)
> +{
> +	struct aperture *g;
> +	unsigned int i;
> +
> +	for (i = 0; i < ctx->ap->count; ++i) {
> +		g = &ctx->ap->ranges[i];
> +
> +		if (mem->start == g->base)
> +			return true;
> +		if (mem->start >= g->base && mem->end < g->base + g->size)
> +			return true;
> +		if ((ctx->flags & SYSFB_EVICT_VBE) && mem->start == 0xA0000)
> +			return true;
> +	}
> +
> +	return false;
> +}
> +
> +static int sysfb_evict_platform_device(struct device *dev, void *userdata)
> +{
> +	struct sysfb_evict_ctx *ctx = userdata;
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct resource *mem;
> +
> +	if (!pdev->name)
> +		return 0;
> +
> +	if (!strcmp(pdev->name, "simple-framebuffer")) {

This doesn't work in my case where the device comes from DT and the name
also contains the address: pdev->name=1e887000.framebuffer

This is one way of solving it:

        if (!pdev->dev.driver || !pdev->dev.driver->name)
                 return 0;

        if (!strcmp(pdev->dev.driver->name, "simple-framebuffer")) {


Noralf.

> +		mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +		if (!mem)
> +			return 0;
> +		if (!sysfb_evict_match_resource(ctx, mem))
> +			return 0;
> +
> +#ifdef CONFIG_OF_ADDRESS
> +		if (dev->of_node)
> +			of_platform_device_destroy(dev);
> +		else
> +#endif
> +		if (dev_get_platdata(&pdev->dev))
> +			platform_device_del(pdev);
> +	}
> +
> +	return 0;
> +}
> +
> +static int sysfb_evict_platform(struct sysfb_evict_ctx *ctx)
> +{
> +	/*
> +	 * Early-boot architecture setup and boot-loarders sometimes create
> +	 * preliminary platform devices with a generic framebuffer setup. This
> +	 * allows graphics access during boot-up, without a real graphics
> +	 * driver loaded. However, once a real graphics driver takes over, we
> +	 * have to destroy those platform devices. In the legacy fbdev case, we
> +	 * just used to unload the fbdev driver. However, to make sure any kind
> +	 * of driver is unloaded, the platform-eviction code here simply
> +	 * removes any conflicting platform device directly. This causes any
> +	 * bound driver to be detached, and then removes the device entirely so
> +	 * it cannot be bound to later on.
> +	 *
> +	 * Please note that any such platform device must be registered by
> +	 * early architecture setup code. If they are registered after regular
> +	 * GFX drivers, this will fail horribly.
> +	 */
> +
> +	static DEFINE_MUTEX(lock);
> +	int ret;
> +
> +	/*
> +	 * In case of static platform-devices, we must iterate the bus and
> +	 * remove them manually. We know that we're the only code that might
> +	 * remove them, so a simple static lock serializes all calls here.
> +	 */
> +	mutex_lock(&lock);
> +	ret = bus_for_each_dev(&platform_bus_type, NULL, ctx,
> +			       sysfb_evict_platform_device);
> +	mutex_unlock(&lock);
> +	return ret;
> +}
> +
> +static int sysfb_evict_fbdev(struct sysfb_evict_ctx *ctx)
> +{
> +	/*
> +	 * Usually, evicting platform devices should be enough to also trigger
> +	 * fbdev unloading. However, some legacy devices (e.g., uvesafb) have
> +	 * no platform devices that can be evicted, so we still fall back to
> +	 * the legacy fbdev removal code. Note that this only removes fbdev
> +	 * devices marked as FBINFO_MISC_FIRMWARE. Anything else is left
> +	 * untouched.
> +	 *
> +	 * As usual, this only works if the fbdev device is probed early,
> +	 * before any real GFX driver wants to take over.
> +	 */
> +
> +	int ret = 0;
> +
> +#ifdef CONFIG_FB
> +	ret = remove_conflicting_framebuffers(ctx->ap, "sysfb",
> +					      ctx->flags & SYSFB_EVICT_VBE);
> +#endif
> +
> +	return ret;
> +}
> +
> +static int sysfb_evict_vgacon(struct sysfb_evict_ctx *ctx)
> +{
> +	/*
> +	 * The VGACON console driver pokes at VGA registers randomly. If a GFX
> +	 * driver cannot keep the VGA support alive, it better makes sure to
> +	 * unload VGACON before probing.
> +	 *
> +	 * Unloading VGACON requires us to first force dummycon to take over
> +	 * from vgacon (but only if vgacon is really in use), followed by a
> +	 * deregistration of vgacon. Note that this prevents vgacon from being
> +	 * used again after the GFX driver is unloaded. But that is usually
> +	 * fine, since VGA state is rarely restored on driver-unload, anyway.
> +	 *
> +	 * Note that we rely on VGACON to be probed in early boot (actually
> +	 * done by ARCH setup code). If it is probed after GFX drivers, this
> +	 * will fail horribly. You better make sure VGACON is probed early and
> +	 * GFX drivers are probed as normal modules.
> +	 */
> +
> +	int ret = 0;
> +
> +#ifdef CONFIG_VGA_CONSOLE
> +	console_lock();
> +	if (con_is_bound(&vga_con))
> +		ret = do_take_over_console(&dummy_con, 0,
> +					   MAX_NR_CONSOLES - 1, 1);
> +	if (ret == 0) {
> +		ret = do_unregister_con_driver(&vga_con);
> +		if (ret == -ENODEV) /* ignore "already unregistered" */
> +			ret = 0;
> +	}
> +	console_unlock();
> +#endif
> +
> +	return ret;
> +}
> +
> +/**
> + * sysfb_evict_conflicts - remove any conflicting system-framebuffers
> + * @ctx:		eviction context
> + *
> + * This function evicts any conflicting system-framebuffers and their bound
> + * drivers, according to the data given in @ctx.
> + *
> + * Depending on @ctx->flags, the following operations are performed:
> + *
> + *   SYSFB_EVICT_PLATFORM: Firmware framebuffer platform devices (eg.,
> + *                         'simple-framebuffer') that overlap @ctx are removed
> + *                         from the system, causing drivers to be unbound.
> + *                         If SYSFB_EVICT_VBE is given, this also affects
> + *                         devices that own the VGA region.
> + *
> + *   SYSFB_EVICT_FBDEV: Any firmware fbdev drivers that overlap @ctx are
> + *                      unloaded.
> + *                      Furthermore, if SYSFB_EVICT_VBE is given as well, any
> + *                      fbdev driver that maps the VGA region is unloaded.
> + *
> + *   SYSFB_EVICT_VGACON: The vgacon console driver is unbound and unregistered.
> + *
> + * This might call into fbdev driver unregistration, or even device_del() on
> + * some buses. Hence, make sure you call this from your top-level
> + * probe-callbacks, rather than with any gfx-subsystem locks held.
> + *
> + * RETURNS:
> + * 0 on success, negative error code on failure.
> + */
> +int sysfb_evict_conflicts(struct sysfb_evict_ctx *ctx)
> +{
> +	int ret;
> +
> +	if (WARN_ON(!ctx || !ctx->ap))
> +		return -EINVAL;
> +
> +	pr_info("removing conflicts (sysfb%s%s%s%s)\n",
> +		(ctx->flags & SYSFB_EVICT_PLATFORM) ? ", platform" : "",
> +		(ctx->flags & SYSFB_EVICT_FBDEV) ? ", fbdev" : "",
> +		(ctx->flags & SYSFB_EVICT_VGACON) ? ", vgacon" : "",
> +		(ctx->flags & SYSFB_EVICT_VBE) ? ", vbe" : "");
> +
> +	if (ctx->flags & SYSFB_EVICT_PLATFORM) {
> +		ret = sysfb_evict_platform(ctx);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	if (ctx->flags & SYSFB_EVICT_FBDEV) {
> +		ret = sysfb_evict_fbdev(ctx);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	if (ctx->flags & SYSFB_EVICT_VGACON) {
> +		ret = sysfb_evict_vgacon(ctx);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(sysfb_evict_conflicts);
> +
> +/**
> + * sysfb_evict_conflicts_firmware() - remove all firmware framebuffers
> + *
> + * This is similar to sysfb_evict_conflicts() but uses a fake aperture spanning
> + * the entire address-space. This is suitable for any GFX driver that just
> + * wants to get rid of all available firmware framebuffers.
> + *
> + * RETURNS:
> + * 0 on success, negative error code on failure.
> + */
> +int sysfb_evict_conflicts_firmware(void)
> +{
> +	struct sysfb_evict_ctx ctx = {};
> +	int ret;
> +
> +	ctx.ap = alloc_apertures(1);
> +	if (!ctx.ap)
> +		return -ENOMEM;
> +
> +	ctx.ap->ranges[0].base = 0;
> +	ctx.ap->ranges[0].size = ~0;
> +
> +	ctx.flags |= SYSFB_EVICT_FBDEV | SYSFB_EVICT_PLATFORM;
> +	ret = sysfb_evict_conflicts(&ctx);
> +
> +	kfree(ctx.ap);
> +	return ret;
> +}
> +EXPORT_SYMBOL(sysfb_evict_conflicts_firmware);
> +
> +#ifdef CONFIG_PCI
> +/**
> + * sysfb_evict_conflicts_pci() - remove all system framebuffers conflicting
> + *                               with the given pci device
> + * @pdev:		pci device
> + *
> + * This is similar to sysfb_evict_conflicts() but generates the eviction
> + * context based on the given pci device @pdev.
> + *
> + * RETURNS:
> + * 0 on success, negative error code on failure.
> + */
> +int sysfb_evict_conflicts_pci(struct pci_dev *pdev)
> +{
> +	struct sysfb_evict_ctx ctx = {};
> +	size_t i, n, offset;
> +	int ret;
> +
> +	/*
> +	 * If this device is used as primary VGA device, it is shadowed at the
> +	 * VBE base address, so make sure to include it in the apertures.
> +	 */
> +	if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)
> +		ctx.flags |= SYSFB_EVICT_VBE;
> +
> +	/*
> +	 * If a device is a VGA device, make sure to kick out vgacon. We cannot
> +	 * rely on the IORESOURCE_ROM_SHADOW, since vgacon can switch between
> +	 * vga devices at runtime. So kick out vgacon anyway.
> +	 */
> +	if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
> +		ctx.flags |= SYSFB_EVICT_VGACON;
> +
> +	/*
> +	 * Allocate apertures for all standard PCI resources. Skip them in case
> +	 * they are empty.
> +	 */
> +	ctx.ap = alloc_apertures(PCI_STD_RESOURCE_END - PCI_STD_RESOURCES + 1);
> +	if (!ctx.ap)
> +		return -ENOMEM;
> +
> +	offset = PCI_STD_RESOURCES;
> +	for (n = 0, i = 0; i < ctx.ap->count; ++i) {
> +		if (pci_resource_len(pdev, offset + i) < 1)
> +			continue;
> +
> +		ctx.ap->ranges[n].base = pci_resource_start(pdev, offset + i);
> +		ctx.ap->ranges[n].size = pci_resource_len(pdev, offset + i);
> +		++n;
> +	}
> +	ctx.ap->count = n;
> +
> +	/*
> +	 * Evict all matching fbdev devices, VBE devices if they shadow this
> +	 * device, vgacon if this is a vga device, and platform devices if they
> +	 * match.
> +	 */
> +	ctx.flags |= SYSFB_EVICT_FBDEV | SYSFB_EVICT_PLATFORM;
> +	ret = sysfb_evict_conflicts(&ctx);
> +
> +	kfree(ctx.ap);
> +	return ret;
> +}
> +EXPORT_SYMBOL(sysfb_evict_conflicts_pci);
> +#endif /* CONFIG_PCI */
> diff --git a/include/linux/sysfb.h b/include/linux/sysfb.h
> new file mode 100644
> index 0000000..b67c74a
> --- /dev/null
> +++ b/include/linux/sysfb.h
> @@ -0,0 +1,34 @@
> +#ifndef __LINUX_SYSFB_H
> +#define __LINUX_SYSFB_H
> +
> +/*
> + * Copyright (C) 2013-2016 Red Hat, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License as published by the
> + * Free Software Foundation; either version 2.1 of the License, or (at your
> + * option) any later version.
> + */
> +
> +#include <linux/kernel.h>
> +
> +struct apertures_struct;
> +struct pci_dev;
> +
> +enum {
> +	SYSFB_EVICT_PLATFORM			= (1U <<  0),
> +	SYSFB_EVICT_FBDEV			= (1U <<  1),
> +	SYSFB_EVICT_VGACON			= (1U <<  2),
> +	SYSFB_EVICT_VBE				= (1U <<  3),
> +};
> +
> +struct sysfb_evict_ctx {
> +	struct apertures_struct *ap;
> +	unsigned int flags;
> +};
> +
> +int sysfb_evict_conflicts(struct sysfb_evict_ctx *ctx);
> +int sysfb_evict_conflicts_firmware(void);
> +int sysfb_evict_conflicts_pci(struct pci_dev *pdev);
> +
> +#endif /* __LINUX_SYSFB_H */

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v5 5/7] drm: switch to sysfb_evict_conflicts()
  2016-09-02  8:22 ` [PATCH v5 5/7] drm: switch to sysfb_evict_conflicts() David Herrmann
@ 2016-09-03 12:13   ` Noralf Trønnes
  0 siblings, 0 replies; 31+ messages in thread
From: Noralf Trønnes @ 2016-09-03 12:13 UTC (permalink / raw)
  To: David Herrmann, dri-devel


Den 02.09.2016 10:22, skrev David Herrmann:
> Switch over all DRM drivers to use the new sysfb_evict_conflicts()
> infrastructure. The only non-trivial conversion is i915, since it does not
> make use of the generic PCI resources, but assembles the apertures via
> intel ggtt queries.
>
> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
> ---

This doesn't apply now with Daniel's wrapper added:
drm_fb_helper_remove_conflicting_framebuffers().

Noralf.

>   drivers/gpu/drm/Kconfig                  |  1 +
>   drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c  | 24 +----------
>   drivers/gpu/drm/bochs/bochs_drv.c        | 19 +--------
>   drivers/gpu/drm/i915/i915_drv.c          | 73 ++++++--------------------------
>   drivers/gpu/drm/mgag200/mgag200_drv.c    | 27 +++---------
>   drivers/gpu/drm/mgag200/mgag200_main.c   |  9 ----
>   drivers/gpu/drm/nouveau/nouveau_drm.c    | 33 +++------------
>   drivers/gpu/drm/radeon/radeon_drv.c      | 24 +----------
>   drivers/gpu/drm/sun4i/sun4i_drv.c        | 24 +++--------
>   drivers/gpu/drm/vc4/vc4_drv.c            | 25 +++--------
>   drivers/gpu/drm/virtio/virtgpu_drm_bus.c | 24 +----------
>   11 files changed, 44 insertions(+), 239 deletions(-)
>
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index fc35731..f27f9b5 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -12,6 +12,7 @@ menuconfig DRM
>   	select I2C
>   	select I2C_ALGOBIT
>   	select DMA_SHARED_BUFFER
> +	select SYSFB
>   	help
>   	  Kernel-level support for the Direct Rendering Infrastructure (DRI)
>   	  introduced in XFree86 4.0. If you say Y here, you need to select
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> index 9aa533c..a1e67da 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> @@ -38,6 +38,7 @@
>   #include <linux/console.h>
>   #include <linux/module.h>
>   #include <linux/pm_runtime.h>
> +#include <linux/sysfb.h>
>   #include <linux/vga_switcheroo.h>
>   #include "drm_crtc_helper.h"
>   
> @@ -326,27 +327,6 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
>   
>   static struct drm_driver kms_driver;
>   
> -static int amdgpu_kick_out_firmware_fb(struct pci_dev *pdev)
> -{
> -	struct apertures_struct *ap;
> -	bool primary = false;
> -
> -	ap = alloc_apertures(1);
> -	if (!ap)
> -		return -ENOMEM;
> -
> -	ap->ranges[0].base = pci_resource_start(pdev, 0);
> -	ap->ranges[0].size = pci_resource_len(pdev, 0);
> -
> -#ifdef CONFIG_X86
> -	primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
> -#endif
> -	remove_conflicting_framebuffers(ap, "amdgpudrmfb", primary);
> -	kfree(ap);
> -
> -	return 0;
> -}
> -
>   static int amdgpu_pci_probe(struct pci_dev *pdev,
>   			    const struct pci_device_id *ent)
>   {
> @@ -368,7 +348,7 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
>   		return ret;
>   
>   	/* Get rid of things like offb */
> -	ret = amdgpu_kick_out_firmware_fb(pdev);
> +	ret = sysfb_evict_conflicts_pci(pdev);
>   	if (ret)
>   		return ret;
>   
> diff --git a/drivers/gpu/drm/bochs/bochs_drv.c b/drivers/gpu/drm/bochs/bochs_drv.c
> index abace82..99c4ea3 100644
> --- a/drivers/gpu/drm/bochs/bochs_drv.c
> +++ b/drivers/gpu/drm/bochs/bochs_drv.c
> @@ -8,6 +8,7 @@
>   #include <linux/mm.h>
>   #include <linux/module.h>
>   #include <linux/slab.h>
> +#include <linux/sysfb.h>
>   
>   #include "bochs.h"
>   
> @@ -143,28 +144,12 @@ static const struct dev_pm_ops bochs_pm_ops = {
>   /* ---------------------------------------------------------------------- */
>   /* pci interface                                                          */
>   
> -static int bochs_kick_out_firmware_fb(struct pci_dev *pdev)
> -{
> -	struct apertures_struct *ap;
> -
> -	ap = alloc_apertures(1);
> -	if (!ap)
> -		return -ENOMEM;
> -
> -	ap->ranges[0].base = pci_resource_start(pdev, 0);
> -	ap->ranges[0].size = pci_resource_len(pdev, 0);
> -	remove_conflicting_framebuffers(ap, "bochsdrmfb", false);
> -	kfree(ap);
> -
> -	return 0;
> -}
> -
>   static int bochs_pci_probe(struct pci_dev *pdev,
>   			   const struct pci_device_id *ent)
>   {
>   	int ret;
>   
> -	ret = bochs_kick_out_firmware_fb(pdev);
> +	ret = sysfb_evict_conflicts_pci(pdev);
>   	if (ret)
>   		return ret;
>   
> diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
> index 95ddd56..4d6a65dd 100644
> --- a/drivers/gpu/drm/i915/i915_drv.c
> +++ b/drivers/gpu/drm/i915/i915_drv.c
> @@ -36,6 +36,7 @@
>   #include <linux/pm_runtime.h>
>   #include <linux/pnp.h>
>   #include <linux/slab.h>
> +#include <linux/sysfb.h>
>   #include <linux/vgaarb.h>
>   #include <linux/vga_switcheroo.h>
>   #include <linux/vt.h>
> @@ -687,70 +688,32 @@ out:
>   	return ret;
>   }
>   
> -#if IS_ENABLED(CONFIG_FB)
>   static int i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv)
>   {
> -	struct apertures_struct *ap;
> +	struct sysfb_evict_ctx ctx = {};
>   	struct pci_dev *pdev = dev_priv->drm.pdev;
>   	struct i915_ggtt *ggtt = &dev_priv->ggtt;
> -	bool primary;
>   	int ret;
>   
> -	ap = alloc_apertures(1);
> -	if (!ap)
> -		return -ENOMEM;
> -
> -	ap->ranges[0].base = ggtt->mappable_base;
> -	ap->ranges[0].size = ggtt->mappable_end;
> -
> -	primary =
> -		pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
> -
> -	ret = remove_conflicting_framebuffers(ap, "inteldrmfb", primary);
> -
> -	kfree(ap);
> -
> -	return ret;
> -}
> -#else
> -static int i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv)
> -{
> -	return 0;
> -}
> -#endif
> +	ctx.flags = SYSFB_EVICT_PLATFORM |
> +		    SYSFB_EVICT_FBDEV |
> +		    SYSFB_EVICT_VGACON;
>   
> -#if !defined(CONFIG_VGA_CONSOLE)
> -static int i915_kick_out_vgacon(struct drm_i915_private *dev_priv)
> -{
> -	return 0;
> -}
> -#elif !defined(CONFIG_DUMMY_CONSOLE)
> -static int i915_kick_out_vgacon(struct drm_i915_private *dev_priv)
> -{
> -	return -ENODEV;
> -}
> -#else
> -static int i915_kick_out_vgacon(struct drm_i915_private *dev_priv)
> -{
> -	int ret = 0;
> +	ctx.ap = alloc_apertures(1);
> +	if (!ctx.ap)
> +		return -ENOMEM;
>   
> -	DRM_INFO("Replacing VGA console driver\n");
> +	ctx.ap->ranges[0].base = ggtt->mappable_base;
> +	ctx.ap->ranges[0].size = ggtt->mappable_end;
>   
> -	console_lock();
> -	if (con_is_bound(&vga_con))
> -		ret = do_take_over_console(&dummy_con, 0, MAX_NR_CONSOLES - 1, 1);
> -	if (ret == 0) {
> -		ret = do_unregister_con_driver(&vga_con);
> +	if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)
> +		ctx.flags |= SYSFB_EVICT_VBE;
>   
> -		/* Ignore "already unregistered". */
> -		if (ret == -ENODEV)
> -			ret = 0;
> -	}
> -	console_unlock();
> +	ret = sysfb_evict_conflicts(&ctx);
>   
> +	kfree(ctx.ap);
>   	return ret;
>   }
> -#endif
>   
>   static void intel_init_dpio(struct drm_i915_private *dev_priv)
>   {
> @@ -1032,20 +995,12 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
>   		goto out_ggtt;
>   	}
>   
> -	/* WARNING: Apparently we must kick fbdev drivers before vgacon,
> -	 * otherwise the vga fbdev driver falls over. */
>   	ret = i915_kick_out_firmware_fb(dev_priv);
>   	if (ret) {
>   		DRM_ERROR("failed to remove conflicting framebuffer drivers\n");
>   		goto out_ggtt;
>   	}
>   
> -	ret = i915_kick_out_vgacon(dev_priv);
> -	if (ret) {
> -		DRM_ERROR("failed to remove conflicting VGA console\n");
> -		goto out_ggtt;
> -	}
> -
>   	pci_set_master(dev->pdev);
>   
>   	/* overlay on gen2 is broken and can't address above 1G */
> diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c
> index 2b4b125..f30105b 100644
> --- a/drivers/gpu/drm/mgag200/mgag200_drv.c
> +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c
> @@ -10,6 +10,7 @@
>    */
>   #include <linux/module.h>
>   #include <linux/console.h>
> +#include <linux/sysfb.h>
>   #include <drm/drmP.h>
>   
>   #include "mgag200_drv.h"
> @@ -41,29 +42,13 @@ static const struct pci_device_id pciidlist[] = {
>   
>   MODULE_DEVICE_TABLE(pci, pciidlist);
>   
> -static void mgag200_kick_out_firmware_fb(struct pci_dev *pdev)
> -{
> -	struct apertures_struct *ap;
> -	bool primary = false;
> -
> -	ap = alloc_apertures(1);
> -	if (!ap)
> -		return;
> -
> -	ap->ranges[0].base = pci_resource_start(pdev, 0);
> -	ap->ranges[0].size = pci_resource_len(pdev, 0);
> -
> -#ifdef CONFIG_X86
> -	primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
> -#endif
> -	remove_conflicting_framebuffers(ap, "mgag200drmfb", primary);
> -	kfree(ap);
> -}
> -
> -
>   static int mga_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
>   {
> -	mgag200_kick_out_firmware_fb(pdev);
> +	int ret;
> +
> +	ret = sysfb_evict_conflicts_pci(pdev);
> +	if (ret < 0)
> +		return ret;
>   
>   	return drm_get_pci_dev(pdev, ent, &driver);
>   }
> diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c
> index 13798b3..4723407 100644
> --- a/drivers/gpu/drm/mgag200/mgag200_main.c
> +++ b/drivers/gpu/drm/mgag200/mgag200_main.c
> @@ -124,20 +124,11 @@ static int mga_probe_vram(struct mga_device *mdev, void __iomem *mem)
>   static int mga_vram_init(struct mga_device *mdev)
>   {
>   	void __iomem *mem;
> -	struct apertures_struct *aper = alloc_apertures(1);
> -	if (!aper)
> -		return -ENOMEM;
>   
>   	/* BAR 0 is VRAM */
>   	mdev->mc.vram_base = pci_resource_start(mdev->dev->pdev, 0);
>   	mdev->mc.vram_window = pci_resource_len(mdev->dev->pdev, 0);
>   
> -	aper->ranges[0].base = mdev->mc.vram_base;
> -	aper->ranges[0].size = mdev->mc.vram_window;
> -
> -	remove_conflicting_framebuffers(aper, "mgafb", true);
> -	kfree(aper);
> -
>   	if (!devm_request_mem_region(mdev->dev->dev, mdev->mc.vram_base, mdev->mc.vram_window,
>   				"mgadrmfb_vram")) {
>   		DRM_ERROR("can't reserve VRAM\n");
> diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
> index 66c1280..193e833 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_drm.c
> +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
> @@ -27,6 +27,7 @@
>   #include <linux/module.h>
>   #include <linux/pci.h>
>   #include <linux/pm_runtime.h>
> +#include <linux/sysfb.h>
>   #include <linux/vga_switcheroo.h>
>   
>   #include "drmP.h"
> @@ -310,8 +311,6 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
>   			     const struct pci_device_id *pent)
>   {
>   	struct nvkm_device *device;
> -	struct apertures_struct *aper;
> -	bool boot = false;
>   	int ret;
>   
>   	if (vga_switcheroo_client_probe_defer(pdev))
> @@ -326,34 +325,12 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
>   
>   	nvkm_device_del(&device);
>   
> -	/* Remove conflicting drivers (vesafb, efifb etc). */
> -	aper = alloc_apertures(3);
> -	if (!aper)
> -		return -ENOMEM;
> -
> -	aper->ranges[0].base = pci_resource_start(pdev, 1);
> -	aper->ranges[0].size = pci_resource_len(pdev, 1);
> -	aper->count = 1;
> -
> -	if (pci_resource_len(pdev, 2)) {
> -		aper->ranges[aper->count].base = pci_resource_start(pdev, 2);
> -		aper->ranges[aper->count].size = pci_resource_len(pdev, 2);
> -		aper->count++;
> -	}
> -
> -	if (pci_resource_len(pdev, 3)) {
> -		aper->ranges[aper->count].base = pci_resource_start(pdev, 3);
> -		aper->ranges[aper->count].size = pci_resource_len(pdev, 3);
> -		aper->count++;
> +	if (nouveau_modeset != 2) {
> +		ret = sysfb_evict_conflicts_pci(pdev);
> +		if (ret < 0)
> +			return ret;
>   	}
>   
> -#ifdef CONFIG_X86
> -	boot = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
> -#endif
> -	if (nouveau_modeset != 2)
> -		remove_conflicting_framebuffers(aper, "nouveaufb", boot);
> -	kfree(aper);
> -
>   	ret = nvkm_device_pci_new(pdev, nouveau_config, nouveau_debug,
>   				  true, true, ~0ULL, &device);
>   	if (ret)
> diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
> index c01a7c6..a0c11bd 100644
> --- a/drivers/gpu/drm/radeon/radeon_drv.c
> +++ b/drivers/gpu/drm/radeon/radeon_drv.c
> @@ -37,6 +37,7 @@
>   #include <linux/console.h>
>   #include <linux/module.h>
>   #include <linux/pm_runtime.h>
> +#include <linux/sysfb.h>
>   #include <linux/vga_switcheroo.h>
>   #include <drm/drm_gem.h>
>   
> @@ -309,27 +310,6 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
>   
>   static struct drm_driver kms_driver;
>   
> -static int radeon_kick_out_firmware_fb(struct pci_dev *pdev)
> -{
> -	struct apertures_struct *ap;
> -	bool primary = false;
> -
> -	ap = alloc_apertures(1);
> -	if (!ap)
> -		return -ENOMEM;
> -
> -	ap->ranges[0].base = pci_resource_start(pdev, 0);
> -	ap->ranges[0].size = pci_resource_len(pdev, 0);
> -
> -#ifdef CONFIG_X86
> -	primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
> -#endif
> -	remove_conflicting_framebuffers(ap, "radeondrmfb", primary);
> -	kfree(ap);
> -
> -	return 0;
> -}
> -
>   static int radeon_pci_probe(struct pci_dev *pdev,
>   			    const struct pci_device_id *ent)
>   {
> @@ -347,7 +327,7 @@ static int radeon_pci_probe(struct pci_dev *pdev,
>   		return -EPROBE_DEFER;
>   
>   	/* Get rid of things like offb */
> -	ret = radeon_kick_out_firmware_fb(pdev);
> +	ret = sysfb_evict_conflicts_pci(pdev);
>   	if (ret)
>   		return ret;
>   
> diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
> index 7092daa..ac388b5 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_drv.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
> @@ -12,6 +12,7 @@
>   
>   #include <linux/component.h>
>   #include <linux/of_graph.h>
> +#include <linux/sysfb.h>
>   
>   #include <drm/drmP.h>
>   #include <drm/drm_crtc_helper.h>
> @@ -97,28 +98,16 @@ static struct drm_driver sun4i_drv_driver = {
>   	.disable_vblank		= sun4i_drv_disable_vblank,
>   };
>   
> -static void sun4i_remove_framebuffers(void)
> -{
> -	struct apertures_struct *ap;
> -
> -	ap = alloc_apertures(1);
> -	if (!ap)
> -		return;
> -
> -	/* The framebuffer can be located anywhere in RAM */
> -	ap->ranges[0].base = 0;
> -	ap->ranges[0].size = ~0;
> -
> -	remove_conflicting_framebuffers(ap, "sun4i-drm-fb", false);
> -	kfree(ap);
> -}
> -
>   static int sun4i_drv_bind(struct device *dev)
>   {
>   	struct drm_device *drm;
>   	struct sun4i_drv *drv;
>   	int ret;
>   
> +	ret = sysfb_evict_conflicts_firmware();
> +	if (ret < 0)
> +		return ret;
> +
>   	drm = drm_dev_alloc(&sun4i_drv_driver, dev);
>   	if (!drm)
>   		return -ENOMEM;
> @@ -156,9 +145,6 @@ static int sun4i_drv_bind(struct device *dev)
>   	}
>   	drm->irq_enabled = true;
>   
> -	/* Remove early framebuffers (ie. simplefb) */
> -	sun4i_remove_framebuffers();
> -
>   	/* Create our framebuffer */
>   	drv->fbdev = sun4i_framebuffer_init(drm);
>   	if (IS_ERR(drv->fbdev)) {
> diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
> index 8b42d31..679e65a 100644
> --- a/drivers/gpu/drm/vc4/vc4_drv.c
> +++ b/drivers/gpu/drm/vc4/vc4_drv.c
> @@ -15,6 +15,7 @@
>   #include <linux/of_platform.h>
>   #include <linux/platform_device.h>
>   #include <linux/pm_runtime.h>
> +#include <linux/sysfb.h>
>   #include "drm_fb_cma_helper.h"
>   
>   #include "uapi/drm/vc4_drm.h"
> @@ -200,24 +201,6 @@ static void vc4_match_add_drivers(struct device *dev,
>   	}
>   }
>   
> -static void vc4_kick_out_firmware_fb(void)
> -{
> -	struct apertures_struct *ap;
> -
> -	ap = alloc_apertures(1);
> -	if (!ap)
> -		return;
> -
> -	/* Since VC4 is a UMA device, the simplefb node may have been
> -	 * located anywhere in memory.
> -	 */
> -	ap->ranges[0].base = 0;
> -	ap->ranges[0].size = ~0;
> -
> -	remove_conflicting_framebuffers(ap, "vc4drmfb", false);
> -	kfree(ap);
> -}
> -
>   static int vc4_drm_bind(struct device *dev)
>   {
>   	struct platform_device *pdev = to_platform_device(dev);
> @@ -225,6 +208,10 @@ static int vc4_drm_bind(struct device *dev)
>   	struct vc4_dev *vc4;
>   	int ret = 0;
>   
> +	ret = sysfb_evict_conflicts_firmware();
> +	if (ret < 0)
> +		return ret;
> +
>   	dev->coherent_dma_mask = DMA_BIT_MASK(32);
>   
>   	vc4 = devm_kzalloc(dev, sizeof(*vc4), GFP_KERNEL);
> @@ -248,8 +235,6 @@ static int vc4_drm_bind(struct device *dev)
>   	if (ret)
>   		goto gem_destroy;
>   
> -	vc4_kick_out_firmware_fb();
> -
>   	ret = drm_dev_register(drm, 0);
>   	if (ret < 0)
>   		goto unbind_all;
> diff --git a/drivers/gpu/drm/virtio/virtgpu_drm_bus.c b/drivers/gpu/drm/virtio/virtgpu_drm_bus.c
> index 7f0e93f87..d6a8a94 100644
> --- a/drivers/gpu/drm/virtio/virtgpu_drm_bus.c
> +++ b/drivers/gpu/drm/virtio/virtgpu_drm_bus.c
> @@ -24,29 +24,10 @@
>    */
>   
>   #include <linux/pci.h>
> +#include <linux/sysfb.h>
>   
>   #include "virtgpu_drv.h"
>   
> -static void virtio_pci_kick_out_firmware_fb(struct pci_dev *pci_dev)
> -{
> -	struct apertures_struct *ap;
> -	bool primary;
> -
> -	ap = alloc_apertures(1);
> -	if (!ap)
> -		return;
> -
> -	ap->ranges[0].base = pci_resource_start(pci_dev, 0);
> -	ap->ranges[0].size = pci_resource_len(pci_dev, 0);
> -
> -	primary = pci_dev->resource[PCI_ROM_RESOURCE].flags
> -		& IORESOURCE_ROM_SHADOW;
> -
> -	remove_conflicting_framebuffers(ap, "virtiodrmfb", primary);
> -
> -	kfree(ap);
> -}
> -
>   int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev)
>   {
>   	struct drm_device *dev;
> @@ -65,8 +46,7 @@ int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev)
>   		DRM_INFO("pci: %s detected\n",
>   			 vga ? "virtio-vga" : "virtio-gpu-pci");
>   		dev->pdev = pdev;
> -		if (vga)
> -			virtio_pci_kick_out_firmware_fb(pdev);
> +		sysfb_evict_conflicts_pci(pdev);
>   	}
>   
>   	ret = drm_dev_register(dev, 0);

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v5 7/7] drm/simpledrm: add fbdev fallback support
  2016-09-03 12:04   ` Noralf Trønnes
@ 2016-09-03 17:15     ` Noralf Trønnes
  2016-09-05 11:21       ` David Herrmann
  0 siblings, 1 reply; 31+ messages in thread
From: Noralf Trønnes @ 2016-09-03 17:15 UTC (permalink / raw)
  To: David Herrmann, dri-devel


Den 03.09.2016 14:04, skrev Noralf Trønnes:
>
> Den 02.09.2016 10:22, skrev David Herrmann:
>> Create a simple fbdev device during SimpleDRM setup so legacy user-space
>> and fbcon can use it.
>>
>> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
>
> [...]
>
>> diff --git a/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c 
>> b/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c
>
> [...]
>
>> +void sdrm_fbdev_bind(struct sdrm_device *sdrm)
>> +{
>> +    struct drm_fb_helper *fbdev;
>> +    int r;
>> +
>> +    fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
>> +    if (!fbdev)
>> +        return;
>> +
>> +    drm_fb_helper_prepare(sdrm->ddev, fbdev, &sdrm_fbdev_funcs);
>> +
>> +    r = drm_fb_helper_init(sdrm->ddev, fbdev, 1, 1);
>> +    if (r < 0)
>> +        goto error;
>> +
>> +    r = drm_fb_helper_single_add_all_connectors(fbdev);
>> +    if (r < 0)
>> +        goto error;
>> +
>> +    r = drm_fb_helper_initial_config(fbdev,
>> +                sdrm->ddev->mode_config.preferred_depth);
>> +    if (r < 0)
>> +        goto error;
>> +
>> +    if (!fbdev->fbdev)
>> +        goto error;
>> +
>> +    sdrm->fbdev = fbdev;
>> +    return;
>> +
>> +error:
>> +    drm_fb_helper_fini(fbdev);
>> +    kfree(fbdev);
>> +}
>> +
>> +void sdrm_fbdev_unbind(struct sdrm_device *sdrm)
>> +{
>> +    struct drm_fb_helper *fbdev = sdrm->fbdev;
>> +
>> +    if (!fbdev)
>> +        return;
>> +
>> +    sdrm->fbdev = NULL;
>> +    drm_fb_helper_unregister_fbi(fbdev);
>> +    cancel_work_sync(&fbdev->dirty_work);
>> +    drm_fb_helper_release_fbi(fbdev);
>> +    drm_framebuffer_unreference(fbdev->fb);
>
> I get a warning that there are still fb's left during unbind:
>
> [   48.666003] WARNING: CPU: 0 PID: 716 at 
> drivers/gpu/drm/drm_crtc.c:3855 drm_mode_config_cleanup+0x180/0x1f4 [drm]
>
> This worked:
>
> -       drm_framebuffer_unreference(fbdev->fb);
> +       drm_framebuffer_unregister_private(fbdev->fb);
> +       drm_framebuffer_cleanup(fbdev->fb);
>

Well not quite, this doesn't free the bo, so maybe this:

-       drm_framebuffer_unreference(fbdev->fb);
+       drm_framebuffer_unregister_private(fbdev->fb);
+       sdrm_fb_destroy(fbdev->fb);

IIRC the reason ref count doesn't drop to zero, had something to do with 
multiple
fb_set_par calls taking reference but not being dropped later.

Noralf.

>
> Noralf.
>
>> +    fbdev->fb = NULL;
>> +    drm_fb_helper_fini(fbdev);
>> +    kfree(fbdev);
>> +}
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
>

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v5 4/7] video: add generic framebuffer eviction
  2016-09-03 12:06   ` Noralf Trønnes
@ 2016-09-05 11:19     ` David Herrmann
  2016-09-05 16:36       ` Noralf Trønnes
  0 siblings, 1 reply; 31+ messages in thread
From: David Herrmann @ 2016-09-05 11:19 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: dri-devel

Hi

On Sat, Sep 3, 2016 at 2:06 PM, Noralf Trønnes <noralf@tronnes.org> wrote:
>
> Den 02.09.2016 10:22, skrev David Herrmann:
>>
>> There are several situations where we want hardware handover from an early
>> boot GFX driver (e.g., vgacon, vesafb, efifb, simplefb) to a full fletched
>> GFX driver (e.g., most DRM drivers). So far, we relied on
>> remove_conflicting_framebuffers() to do this for us, however, this had a
>> bunch of downsides:
>>
>>    o It only removes conflicting fbdev drivers. It does not drop vgacon,
>>      early boot console drivers, conflicting DRM drivers, etc.
>>
>>    o It only unloads the fbdev driver, it does not modify the underlying
>>      device or resources. In case of "screen_info" drivers (e.g., efifb)
>>      this is fine, since no resources are pinned. However, if the driver
>>      binds to a platform-device like "simple-framebuffer", we must make
>>      sure to unregister that device as well. Otherwise, pinned resources
>>      like IORESOURCE_MEM stay around, triggering WARN_ONs if the following
>>      driver requests those resources.
>>
>>    o It is only available if CONFIG_FB is selected.
>>
>> This commit adds a new infrastructure that manages system-framebuffers
>> (short: sysfb). The initial commit provides conflict-resolution for
>> system-framebuffers. At its core it provides sysfb_evict_conflicts(),
>> which implements conflict detection and removal for all known types of
>> GFX driver hand-overs. So far, this includes platform-device removal,
>> fbdev-firmware-device removal, vgacon removal and VBE detection. To
>> further simplify the callers, it also provides helpers to figure out what
>> hand-over to do, based on the device the new drivers binds to:
>>
>>    o PCI drivers can use sysfb_evict_conflicts_pci(), which will figure
>> out
>>      the apertures automatically, and does VGA/VBE detection.
>>
>>    o Generic firmware drivers that might be shadowed at any address in
>>      memory can use sysfb_evict_conflicts_firmware(), basically removing
>>      *all* firmware framebuffers in effect.
>>
>> This only adds the generic sysfb helpers. No users are converted, yet.
>>
>> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
>> ---
>>   drivers/video/Kconfig  |   4 +
>>   drivers/video/Makefile |   1 +
>>   drivers/video/sysfb.c  | 327
>> +++++++++++++++++++++++++++++++++++++++++++++++++
>>   include/linux/sysfb.h  |  34 +++++
>>   4 files changed, 366 insertions(+)
>>   create mode 100644 drivers/video/sysfb.c
>>   create mode 100644 include/linux/sysfb.h
>>
>> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
>> index 3c20af9..56a8294 100644
>> --- a/drivers/video/Kconfig
>> +++ b/drivers/video/Kconfig
>> @@ -36,6 +36,10 @@ config VIDEOMODE_HELPERS
>>   config HDMI
>>         bool
>>   +config SYSFB
>> +       bool
>> +       select DUMMY_CONSOLE if VT
>> +
>>   if VT
>>         source "drivers/video/console/Kconfig"
>>   endif
>> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
>> index 9ad3c17..df7bd75 100644
>> --- a/drivers/video/Makefile
>> +++ b/drivers/video/Makefile
>> @@ -1,5 +1,6 @@
>>   obj-$(CONFIG_VGASTATE)            += vgastate.o
>>   obj-$(CONFIG_HDMI)                += hdmi.o
>> +obj-$(CONFIG_SYSFB)              += sysfb.o
>>     obj-$(CONFIG_VT)              += console/
>>   obj-$(CONFIG_LOGO)              += logo/
>> diff --git a/drivers/video/sysfb.c b/drivers/video/sysfb.c
>> new file mode 100644
>> index 0000000..00585c9
>> --- /dev/null
>> +++ b/drivers/video/sysfb.c
>> @@ -0,0 +1,327 @@
>> +/*
>> + * Copyright (C) 2013-2016 Red Hat, Inc.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> it
>> + * under the terms of the GNU Lesser General Public License as published
>> by the
>> + * Free Software Foundation; either version 2.1 of the License, or (at
>> your
>> + * option) any later version.
>> + */
>> +
>> +#define pr_fmt(fmt) "sysfb: " fmt
>> +#include <linux/console.h>
>> +#include <linux/device.h>
>> +#include <linux/err.h>
>> +#include <linux/export.h>
>> +#include <linux/fb.h>
>> +#include <linux/ioport.h>
>> +#include <linux/kernel.h>
>> +#include <linux/of.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/pci.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/slab.h>
>> +#include <linux/sysfb.h>
>> +#include <linux/vt.h>
>> +
>> +static bool sysfb_evict_match_resource(struct sysfb_evict_ctx *ctx,
>> +                                      struct resource *mem)
>> +{
>> +       struct aperture *g;
>> +       unsigned int i;
>> +
>> +       for (i = 0; i < ctx->ap->count; ++i) {
>> +               g = &ctx->ap->ranges[i];
>> +
>> +               if (mem->start == g->base)
>> +                       return true;
>> +               if (mem->start >= g->base && mem->end < g->base + g->size)
>> +                       return true;
>> +               if ((ctx->flags & SYSFB_EVICT_VBE) && mem->start ==
>> 0xA0000)
>> +                       return true;
>> +       }
>> +
>> +       return false;
>> +}
>> +
>> +static int sysfb_evict_platform_device(struct device *dev, void
>> *userdata)
>> +{
>> +       struct sysfb_evict_ctx *ctx = userdata;
>> +       struct platform_device *pdev = to_platform_device(dev);
>> +       struct resource *mem;
>> +
>> +       if (!pdev->name)
>> +               return 0;
>> +
>> +       if (!strcmp(pdev->name, "simple-framebuffer")) {
>
>
> This doesn't work in my case where the device comes from DT and the name
> also contains the address: pdev->name=1e887000.framebuffer
>
> This is one way of solving it:
>
>        if (!pdev->dev.driver || !pdev->dev.driver->name)
>                 return 0;
>
>        if (!strcmp(pdev->dev.driver->name, "simple-framebuffer")) {

Thanks for the hint, but this would skip devices that are not bound.
How about the attached hunk?

Thanks
David

diff --git a/drivers/video/sysfb.c b/drivers/video/sysfb.c
index 0f039c6..a4ace3f 100644
--- a/drivers/video/sysfb.c
+++ b/drivers/video/sysfb.c
@@ -50,10 +50,8 @@ static int sysfb_evict_platform_device
        struct platform_device *pdev = to_platform_device(dev);
        struct resource *mem;

-       if (!pdev->name)
-               return 0;
-
-       if (!strcmp(pdev->name, "simple-framebuffer")) {
+       if ((pdev->name && !strcmp(pdev->name, "simple-framebuffer")) ||
+           of_device_is_compatible(pdev->dev.of_node, "simple-framebuffer")) {
                mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
                if (!mem)
                        return 0;
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH v5 7/7] drm/simpledrm: add fbdev fallback support
  2016-09-03 17:15     ` Noralf Trønnes
@ 2016-09-05 11:21       ` David Herrmann
  0 siblings, 0 replies; 31+ messages in thread
From: David Herrmann @ 2016-09-05 11:21 UTC (permalink / raw)
  To: Noralf Trønnes, Daniel Vetter; +Cc: dri-devel

Hi

On Sat, Sep 3, 2016 at 7:15 PM, Noralf Trønnes <noralf@tronnes.org> wrote:
>
> Den 03.09.2016 14:04, skrev Noralf Trønnes:
>>
>>
>> Den 02.09.2016 10:22, skrev David Herrmann:
>>>
>>> Create a simple fbdev device during SimpleDRM setup so legacy user-space
>>> and fbcon can use it.
>>>
>>> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
>>
>>
>> [...]
>>
>>> diff --git a/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c
>>> b/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c
>>
>>
>> [...]
>>
>>> +void sdrm_fbdev_bind(struct sdrm_device *sdrm)
>>> +{
>>> +    struct drm_fb_helper *fbdev;
>>> +    int r;
>>> +
>>> +    fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
>>> +    if (!fbdev)
>>> +        return;
>>> +
>>> +    drm_fb_helper_prepare(sdrm->ddev, fbdev, &sdrm_fbdev_funcs);
>>> +
>>> +    r = drm_fb_helper_init(sdrm->ddev, fbdev, 1, 1);
>>> +    if (r < 0)
>>> +        goto error;
>>> +
>>> +    r = drm_fb_helper_single_add_all_connectors(fbdev);
>>> +    if (r < 0)
>>> +        goto error;
>>> +
>>> +    r = drm_fb_helper_initial_config(fbdev,
>>> +                sdrm->ddev->mode_config.preferred_depth);
>>> +    if (r < 0)
>>> +        goto error;
>>> +
>>> +    if (!fbdev->fbdev)
>>> +        goto error;
>>> +
>>> +    sdrm->fbdev = fbdev;
>>> +    return;
>>> +
>>> +error:
>>> +    drm_fb_helper_fini(fbdev);
>>> +    kfree(fbdev);
>>> +}
>>> +
>>> +void sdrm_fbdev_unbind(struct sdrm_device *sdrm)
>>> +{
>>> +    struct drm_fb_helper *fbdev = sdrm->fbdev;
>>> +
>>> +    if (!fbdev)
>>> +        return;
>>> +
>>> +    sdrm->fbdev = NULL;
>>> +    drm_fb_helper_unregister_fbi(fbdev);
>>> +    cancel_work_sync(&fbdev->dirty_work);
>>> +    drm_fb_helper_release_fbi(fbdev);
>>> +    drm_framebuffer_unreference(fbdev->fb);
>>
>>
>> I get a warning that there are still fb's left during unbind:
>>
>> [   48.666003] WARNING: CPU: 0 PID: 716 at drivers/gpu/drm/drm_crtc.c:3855
>> drm_mode_config_cleanup+0x180/0x1f4 [drm]
>>
>> This worked:
>>
>> -       drm_framebuffer_unreference(fbdev->fb);
>> +       drm_framebuffer_unregister_private(fbdev->fb);
>> +       drm_framebuffer_cleanup(fbdev->fb);
>>
>
> Well not quite, this doesn't free the bo, so maybe this:
>
> -       drm_framebuffer_unreference(fbdev->fb);
> +       drm_framebuffer_unregister_private(fbdev->fb);
> +       sdrm_fb_destroy(fbdev->fb);
>
> IIRC the reason ref count doesn't drop to zero, had something to do with
> multiple
> fb_set_par calls taking reference but not being dropped later.

So I don't like this at all. If we leak references, we should fix the
ref-leak or properly document why this is fine to do. Daniel, what is
the exact reason we have unregister_private()? Maybe I should try and
trace the ref-leak.

Thanks
David
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v5 4/7] video: add generic framebuffer eviction
  2016-09-05 11:19     ` David Herrmann
@ 2016-09-05 16:36       ` Noralf Trønnes
  0 siblings, 0 replies; 31+ messages in thread
From: Noralf Trønnes @ 2016-09-05 16:36 UTC (permalink / raw)
  To: David Herrmann; +Cc: dri-devel


Den 05.09.2016 13:19, skrev David Herrmann:
> Hi
>
> On Sat, Sep 3, 2016 at 2:06 PM, Noralf Trønnes <noralf@tronnes.org> wrote:
>> Den 02.09.2016 10:22, skrev David Herrmann:
>>> There are several situations where we want hardware handover from an early
>>> boot GFX driver (e.g., vgacon, vesafb, efifb, simplefb) to a full fletched
>>> GFX driver (e.g., most DRM drivers). So far, we relied on
>>> remove_conflicting_framebuffers() to do this for us, however, this had a
>>> bunch of downsides:
>>>
>>>     o It only removes conflicting fbdev drivers. It does not drop vgacon,
>>>       early boot console drivers, conflicting DRM drivers, etc.
>>>
>>>     o It only unloads the fbdev driver, it does not modify the underlying
>>>       device or resources. In case of "screen_info" drivers (e.g., efifb)
>>>       this is fine, since no resources are pinned. However, if the driver
>>>       binds to a platform-device like "simple-framebuffer", we must make
>>>       sure to unregister that device as well. Otherwise, pinned resources
>>>       like IORESOURCE_MEM stay around, triggering WARN_ONs if the following
>>>       driver requests those resources.
>>>
>>>     o It is only available if CONFIG_FB is selected.
>>>
>>> This commit adds a new infrastructure that manages system-framebuffers
>>> (short: sysfb). The initial commit provides conflict-resolution for
>>> system-framebuffers. At its core it provides sysfb_evict_conflicts(),
>>> which implements conflict detection and removal for all known types of
>>> GFX driver hand-overs. So far, this includes platform-device removal,
>>> fbdev-firmware-device removal, vgacon removal and VBE detection. To
>>> further simplify the callers, it also provides helpers to figure out what
>>> hand-over to do, based on the device the new drivers binds to:
>>>
>>>     o PCI drivers can use sysfb_evict_conflicts_pci(), which will figure
>>> out
>>>       the apertures automatically, and does VGA/VBE detection.
>>>
>>>     o Generic firmware drivers that might be shadowed at any address in
>>>       memory can use sysfb_evict_conflicts_firmware(), basically removing
>>>       *all* firmware framebuffers in effect.
>>>
>>> This only adds the generic sysfb helpers. No users are converted, yet.
>>>
>>> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
>>> ---
>>>    drivers/video/Kconfig  |   4 +
>>>    drivers/video/Makefile |   1 +
>>>    drivers/video/sysfb.c  | 327
>>> +++++++++++++++++++++++++++++++++++++++++++++++++
>>>    include/linux/sysfb.h  |  34 +++++
>>>    4 files changed, 366 insertions(+)
>>>    create mode 100644 drivers/video/sysfb.c
>>>    create mode 100644 include/linux/sysfb.h
>>>
>>> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
>>> index 3c20af9..56a8294 100644
>>> --- a/drivers/video/Kconfig
>>> +++ b/drivers/video/Kconfig
>>> @@ -36,6 +36,10 @@ config VIDEOMODE_HELPERS
>>>    config HDMI
>>>          bool
>>>    +config SYSFB
>>> +       bool
>>> +       select DUMMY_CONSOLE if VT
>>> +
>>>    if VT
>>>          source "drivers/video/console/Kconfig"
>>>    endif
>>> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
>>> index 9ad3c17..df7bd75 100644
>>> --- a/drivers/video/Makefile
>>> +++ b/drivers/video/Makefile
>>> @@ -1,5 +1,6 @@
>>>    obj-$(CONFIG_VGASTATE)            += vgastate.o
>>>    obj-$(CONFIG_HDMI)                += hdmi.o
>>> +obj-$(CONFIG_SYSFB)              += sysfb.o
>>>      obj-$(CONFIG_VT)              += console/
>>>    obj-$(CONFIG_LOGO)              += logo/
>>> diff --git a/drivers/video/sysfb.c b/drivers/video/sysfb.c
>>> new file mode 100644
>>> index 0000000..00585c9
>>> --- /dev/null
>>> +++ b/drivers/video/sysfb.c
>>> @@ -0,0 +1,327 @@
>>> +/*
>>> + * Copyright (C) 2013-2016 Red Hat, Inc.
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> it
>>> + * under the terms of the GNU Lesser General Public License as published
>>> by the
>>> + * Free Software Foundation; either version 2.1 of the License, or (at
>>> your
>>> + * option) any later version.
>>> + */
>>> +
>>> +#define pr_fmt(fmt) "sysfb: " fmt
>>> +#include <linux/console.h>
>>> +#include <linux/device.h>
>>> +#include <linux/err.h>
>>> +#include <linux/export.h>
>>> +#include <linux/fb.h>
>>> +#include <linux/ioport.h>
>>> +#include <linux/kernel.h>
>>> +#include <linux/of.h>
>>> +#include <linux/of_platform.h>
>>> +#include <linux/pci.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/slab.h>
>>> +#include <linux/sysfb.h>
>>> +#include <linux/vt.h>
>>> +
>>> +static bool sysfb_evict_match_resource(struct sysfb_evict_ctx *ctx,
>>> +                                      struct resource *mem)
>>> +{
>>> +       struct aperture *g;
>>> +       unsigned int i;
>>> +
>>> +       for (i = 0; i < ctx->ap->count; ++i) {
>>> +               g = &ctx->ap->ranges[i];
>>> +
>>> +               if (mem->start == g->base)
>>> +                       return true;
>>> +               if (mem->start >= g->base && mem->end < g->base + g->size)
>>> +                       return true;
>>> +               if ((ctx->flags & SYSFB_EVICT_VBE) && mem->start ==
>>> 0xA0000)
>>> +                       return true;
>>> +       }
>>> +
>>> +       return false;
>>> +}
>>> +
>>> +static int sysfb_evict_platform_device(struct device *dev, void
>>> *userdata)
>>> +{
>>> +       struct sysfb_evict_ctx *ctx = userdata;
>>> +       struct platform_device *pdev = to_platform_device(dev);
>>> +       struct resource *mem;
>>> +
>>> +       if (!pdev->name)
>>> +               return 0;
>>> +
>>> +       if (!strcmp(pdev->name, "simple-framebuffer")) {
>>
>> This doesn't work in my case where the device comes from DT and the name
>> also contains the address: pdev->name=1e887000.framebuffer
>>
>> This is one way of solving it:
>>
>>         if (!pdev->dev.driver || !pdev->dev.driver->name)
>>                  return 0;
>>
>>         if (!strcmp(pdev->dev.driver->name, "simple-framebuffer")) {
> Thanks for the hint, but this would skip devices that are not bound.
> How about the attached hunk?
>
> Thanks
> David
>
> diff --git a/drivers/video/sysfb.c b/drivers/video/sysfb.c
> index 0f039c6..a4ace3f 100644
> --- a/drivers/video/sysfb.c
> +++ b/drivers/video/sysfb.c
> @@ -50,10 +50,8 @@ static int sysfb_evict_platform_device
>          struct platform_device *pdev = to_platform_device(dev);
>          struct resource *mem;
>
> -       if (!pdev->name)
> -               return 0;
> -
> -       if (!strcmp(pdev->name, "simple-framebuffer")) {
> +       if ((pdev->name && !strcmp(pdev->name, "simple-framebuffer")) ||
> +           of_device_is_compatible(pdev->dev.of_node, "simple-framebuffer")) {
>                  mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>                  if (!mem)
>                          return 0;
>

This worked fine.

Noralf.


_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v5 6/7] drm: add SimpleDRM driver
  2016-09-02  8:22 ` [PATCH v5 6/7] drm: add SimpleDRM driver David Herrmann
  2016-09-02 12:45   ` Tom Gundersen
  2016-09-03 12:01   ` Noralf Trønnes
@ 2016-09-05 16:39   ` Noralf Trønnes
  2 siblings, 0 replies; 31+ messages in thread
From: Noralf Trønnes @ 2016-09-05 16:39 UTC (permalink / raw)
  To: David Herrmann, dri-devel


Den 02.09.2016 10:22, skrev David Herrmann:
> The SimpleDRM driver binds to simple-framebuffer devices and provides a
> DRM/KMS API. It provides only a single CRTC+encoder+connector combination
> plus one initial mode.
>
> Userspace can create dumb-buffers which can be blit into the real
> framebuffer similar to UDL. No access to the real framebuffer is allowed
> (compared to earlier version of this driver) to avoid security issues.
> Furthermore, this way we can support arbitrary modes as long as we have a
> conversion-helper.
>
> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
> ---

[...]

> diff --git a/drivers/gpu/drm/simpledrm/simpledrm_drv.c b/drivers/gpu/drm/simpledrm/simpledrm_drv.c
> new file mode 100644
> index 0000000..d569120
> --- /dev/null
> +++ b/drivers/gpu/drm/simpledrm/simpledrm_drv.c
> @@ -0,0 +1,464 @@
> +/*
> + * Copyright (C) 2012-2016 Red Hat, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License as published by the
> + * Free Software Foundation; either version 2.1 of the License, or (at your
> + * option) any later version.
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +#include <drm/drmP.h>
> +#include <linux/atomic.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_data/simplefb.h>
> +#include <linux/string.h>
> +#include "simpledrm.h"
> +
> +static struct drm_driver sdrm_drm_driver;
> +static DEFINE_MUTEX(sdrm_lock);
> +
> +static int sdrm_hw_identify(struct platform_device *pdev,
> +			    struct simplefb_platform_data *modep,
> +			    struct simplefb_format *formatp,
> +			    struct resource **memp,
> +			    u32 *bppp)
> +{
> +	static const struct simplefb_format valid_formats[] = SIMPLEFB_FORMATS;
> +	struct simplefb_platform_data pm = {}, *mode = pdev->dev.platform_data;
> +	struct device_node *np = pdev->dev.of_node;
> +	const struct simplefb_format *format = NULL;
> +	struct resource *mem;
> +	unsigned int depth;
> +	int r, bpp;
> +	size_t i;
> +
> +	if (!mode) {
> +		if (!np)
> +			return -ENODEV;
> +
> +		mode = &pm;
> +
> +		r = of_property_read_u32(np, "width", &mode->width);
> +		if (r >= 0)
> +			r = of_property_read_u32(np, "height", &mode->height);
> +		if (r >= 0)
> +			r = of_property_read_u32(np, "stride", &mode->stride);
> +		if (r >= 0)
> +			r = of_property_read_string(np, "format",
> +						    &mode->format);
> +		if (r < 0)
> +			return r;
> +	}
> +
> +	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!mem)
> +		return -ENODEV;
> +
> +	for (i = 0; i < ARRAY_SIZE(valid_formats); ++i) {
> +		if (!strcmp(mode->format, valid_formats[i].name)) {
> +			format = &valid_formats[i];
> +			break;
> +		}
> +	}
> +
> +	if (!format)
> +		return -ENODEV;
> +
> +	switch (format->fourcc) {
> +	case DRM_FORMAT_RGB565:
> +	case DRM_FORMAT_XRGB1555:
> +	case DRM_FORMAT_ARGB1555:
> +	case DRM_FORMAT_RGB888:
> +	case DRM_FORMAT_XRGB8888:
> +	case DRM_FORMAT_ARGB8888:
> +	case DRM_FORMAT_ABGR8888:
> +	case DRM_FORMAT_XRGB2101010:
> +	case DRM_FORMAT_ARGB2101010:
> +		/*
> +		 * You must adjust sdrm_put() whenever you add a new format
> +		 * here, otherwise, blitting operations will not work.
> +		 * Furthermore, include/linux/platform_data/simplefb.h needs
> +		 * to be adjusted so the platform-device actually allows this
> +		 * format.
> +		 */
> +		break;
> +	default:
> +		return -ENODEV;
> +	}
> +
> +	drm_fb_get_bpp_depth(format->fourcc, &depth, &bpp);
> +	if (!bpp)
> +		return -ENODEV;
> +	if (resource_size(mem) < mode->stride * mode->height)
> +		return -ENODEV;
> +	if ((bpp + 7) / 8 * mode->width > mode->stride)
> +		return -ENODEV;
> +
> +	*modep = *mode;
> +	*formatp = *format;
> +	*memp = mem;
> +	*bppp = bpp;
> +	return 0;
> +}
> +
> +static struct sdrm_hw *sdrm_hw_new(const struct simplefb_platform_data *mode,
> +				   const struct simplefb_format *format,
> +				   const struct resource *mem,
> +				   u32 bpp)
> +{
> +	struct sdrm_hw *hw;
> +
> +	hw = kzalloc(sizeof(*hw), GFP_KERNEL);
> +	if (!hw)
> +		return ERR_PTR(-ENOMEM);
> +
> +	mutex_init(&hw->lock);
> +	hw->width = mode->width;
> +	hw->height = mode->height;
> +	hw->stride = mode->stride;
> +	hw->bpp = bpp;
> +	hw->format = format->fourcc;
> +	hw->base = mem->start;
> +	hw->size = resource_size(mem);
> +
> +	return hw;
> +}
> +
> +static struct sdrm_hw *sdrm_hw_free(struct sdrm_hw *hw)
> +{
> +	if (!hw)
> +		return NULL;
> +
> +	WARN_ON(hw->map);
> +	mutex_destroy(&hw->lock);
> +	kfree(hw);
> +
> +	return NULL;
> +}
> +
> +static int sdrm_hw_bind(struct sdrm_hw *hw)
> +{
> +	mutex_lock(&hw->lock);
> +	if (!hw->map)
> +		hw->map = ioremap_wc(hw->base, hw->size);
> +	mutex_unlock(&hw->lock);
> +
> +	return hw->map ? 0 : -EIO;
> +}
> +
> +static void sdrm_hw_unbind(struct sdrm_hw *hw)
> +{
> +	if (!hw)
> +		return;
> +
> +	mutex_lock(&hw->lock);
> +	if (hw->map) {
> +		iounmap(hw->map);
> +		hw->map = NULL;
> +	}
> +	mutex_unlock(&hw->lock);
> +}
> +
> +static struct sdrm_device *sdrm_device_free(struct sdrm_device *sdrm)
> +{
> +	if (!sdrm)
> +		return NULL;
> +
> +	WARN_ON(atomic_read(&sdrm->n_used) != INT_MIN);
> +	sdrm->hw = sdrm_hw_free(sdrm->hw);
> +	drm_dev_unref(sdrm->ddev);
> +	kfree(sdrm);
> +
> +	return NULL;
> +}
> +
> +static struct sdrm_device *sdrm_device_new(struct platform_device *pdev,
> +					   struct sdrm_hw *hw)
> +{
> +	struct sdrm_device *sdrm;
> +	int r;
> +
> +	sdrm = kzalloc(sizeof(*sdrm), GFP_KERNEL);
> +	if (!sdrm)
> +		return ERR_PTR(-ENOMEM);
> +
> +	atomic_set(&sdrm->n_used, INT_MIN);
> +
> +	sdrm->ddev = drm_dev_alloc(&sdrm_drm_driver, &pdev->dev);
> +	if (!sdrm->ddev) {
> +		r = -ENOMEM;
> +		goto error;
> +	}
> +
> +	sdrm->ddev->dev_private = sdrm;
> +	sdrm->hw = hw;
> +
> +	return sdrm;
> +
> +error:
> +	sdrm_device_free(sdrm);
> +	return ERR_PTR(r);
> +}
> +
> +static void sdrm_device_unbind(struct sdrm_device *sdrm)
> +{
> +	if (sdrm) {
> +		sdrm_kms_unbind(sdrm);
> +		sdrm_hw_unbind(sdrm->hw);
> +		sdrm_of_unbind(sdrm);
> +	}
> +}
> +
> +static int sdrm_device_bind(struct sdrm_device *sdrm)
> +{
> +	int r;
> +
> +	r = sdrm_of_bind(sdrm);
> +	if (r < 0)
> +		goto error;
> +
> +	r = sdrm_hw_bind(sdrm->hw);
> +	if (r < 0)
> +		goto error;
> +
> +	r = sdrm_kms_bind(sdrm);
> +	if (r < 0)
> +		goto error;
> +
> +	return 0;
> +
> +error:
> +	sdrm_device_unbind(sdrm);
> +	return r;
> +}
> +
> +static int sdrm_device_acquire(struct sdrm_device *sdrm)
> +{
> +	return (sdrm && atomic_inc_unless_negative(&sdrm->n_used))
> +		? 0 : -ENODEV;
> +}
> +
> +static void sdrm_device_release(struct sdrm_device *sdrm)
> +{
> +	if (sdrm && atomic_dec_return(&sdrm->n_used) == INT_MIN) {
> +		sdrm_device_unbind(sdrm);
> +		sdrm_device_free(sdrm);
> +	}
> +}
> +
> +static int sdrm_fop_open(struct inode *inode, struct file *file)
> +{
> +	struct drm_device *ddev;
> +	int r;
> +
> +	mutex_lock(&sdrm_lock);
> +	r = drm_open(inode, file);
> +	if (r >= 0) {
> +		ddev = file->private_data;
> +		r = sdrm_device_acquire(ddev->dev_private);
> +		if (r < 0)
> +			drm_release(inode, file);
> +	}
> +	mutex_unlock(&sdrm_lock);
> +
> +	return r;
> +}
> +
> +static int sdrm_fop_release(struct inode *inode, struct file *file)
> +{
> +	struct drm_file *dfile = file->private_data;
> +	struct drm_device *ddev = dfile->minor->dev;
> +	struct sdrm_device *sdrm = ddev->dev_private;
> +	int res;
> +
> +	res = drm_release(inode, file);
> +	sdrm_device_release(sdrm);
> +	return res;
> +}
> +
> +static int sdrm_fop_mmap(struct file *file, struct vm_area_struct *vma)
> +{
> +	struct drm_file *dfile = file->private_data;
> +	struct drm_device *dev = dfile->minor->dev;
> +	struct drm_gem_object *obj = NULL;
> +	struct drm_vma_offset_node *node;
> +	int r;
> +
> +	drm_vma_offset_lock_lookup(dev->vma_offset_manager);
> +	node = drm_vma_offset_exact_lookup_locked(dev->vma_offset_manager,
> +						  vma->vm_pgoff,
> +						  vma_pages(vma));
> +	if (likely(node)) {
> +		obj = container_of(node, struct drm_gem_object, vma_node);
> +		if (!kref_get_unless_zero(&obj->refcount))
> +			obj = NULL;
> +	}
> +	drm_vma_offset_unlock_lookup(dev->vma_offset_manager);
> +
> +	if (!obj)
> +		return -EINVAL;
> +
> +	if (!drm_vma_node_is_allowed(node, dfile)) {
> +		drm_gem_object_unreference_unlocked(obj);
> +		return -EACCES;
> +	}
> +
> +	if (vma->vm_file)
> +		fput(vma->vm_file);
> +	vma->vm_file = get_file(obj->filp);
> +	vma->vm_pgoff = 0;
> +
> +	r = obj->filp->f_op->mmap(obj->filp, vma);
> +	drm_gem_object_unreference_unlocked(obj);
> +	return r;
> +}
> +
> +static int sdrm_simplefb_probe(struct platform_device *pdev)
> +{
> +	struct simplefb_platform_data hw_mode;
> +	struct simplefb_format hw_format;
> +	struct sdrm_device *sdrm = NULL;
> +	struct sdrm_hw *hw = NULL;
> +	struct resource *hw_mem;
> +	u32 hw_bpp;
> +	int r;
> +
> +	r = sdrm_hw_identify(pdev, &hw_mode, &hw_format, &hw_mem, &hw_bpp);
> +	if (r < 0)
> +		goto error;
> +
> +	hw = sdrm_hw_new(&hw_mode, &hw_format, hw_mem, hw_bpp);
> +	if (IS_ERR(hw)) {
> +		r = PTR_ERR(hw);
> +		hw = NULL;
> +		goto error;
> +	}
> +
> +	sdrm = sdrm_device_new(pdev, hw);
> +	if (IS_ERR(sdrm)) {
> +		r = PTR_ERR(sdrm);
> +		sdrm = NULL;
> +		goto error;
> +	}
> +	hw = NULL;
> +	platform_set_drvdata(pdev, sdrm);
> +
> +	r = sdrm_device_bind(sdrm);
> +	if (r < 0)
> +		goto error;
> +
> +	/* mark device as enabled and acquire bus ref */
> +	WARN_ON(atomic_read(&sdrm->n_used) != INT_MIN);
> +	atomic_set(&sdrm->n_used, 1);
> +
> +	r = drm_dev_register(sdrm->ddev, 0);
> +	if (r < 0) {
> +		/* mark device as disabled and drop bus ref */
> +		WARN_ON(atomic_add_return(INT_MIN, &sdrm->n_used) != INT_MIN);
> +		sdrm_device_release(sdrm);
> +		return r;
> +	}
> +
> +	dev_info(sdrm->ddev->dev, "initialized %s on minor %d\n",
> +		 sdrm->ddev->driver->name, sdrm->ddev->primary->index);
> +
> +	return 0;
> +
> +error:
> +	sdrm_device_unbind(sdrm);
> +	sdrm_device_free(sdrm);
> +	sdrm_hw_free(hw);
> +	return r;
> +}
> +
> +static int sdrm_simplefb_remove(struct platform_device *pdev)
> +{
> +	struct sdrm_device *sdrm = platform_get_drvdata(pdev);
> +
> +	/* mark device as disabled */
> +	atomic_add(INT_MIN, &sdrm->n_used);
> +	sdrm_hw_unbind(sdrm->hw);
> +
> +	mutex_lock(&sdrm_lock);
> +	drm_dev_unregister(sdrm->ddev);
> +	sdrm_device_release(sdrm);
> +	mutex_unlock(&sdrm_lock);
> +
> +	return 0;
> +}

There is something wrong with the ref counting.
Load, unload is fine:

$ sudo modprobe simpledrm
$ echo 0 | sudo tee /sys/class/vtconsole/vtcon1/bind
$ sudo modprobe -r simpledrm
$ ls -l /dev/fb*
ls: cannot access /dev/fb*: No such file or directory

But if I run modetest in between it's not released:

$ sudo modprobe simpledrm
$ ./libdrm/tests/modetest/modetest -M "simpledrm" -s 23:1824x984
setting mode 1824x984-60Hz@XR24 on connectors 23, crtc 25
$ echo 0 | sudo tee /sys/class/vtconsole/vtcon1/bind
$ sudo modprobe -r simpledrm
$ ls -l /dev/fb*
crw-rw---- 1 root video 29, 0 Sep  5 15:43 /dev/fb0


Noralf.

> +
> +static const struct file_operations sdrm_drm_fops = {
> +	.owner = THIS_MODULE,
> +	.open = sdrm_fop_open,
> +	.release = sdrm_fop_release,
> +	.mmap = sdrm_fop_mmap,
> +	.poll = drm_poll,
> +	.read = drm_read,
> +	.unlocked_ioctl = drm_ioctl,
> +#ifdef CONFIG_COMPAT
> +	.compat_ioctl = drm_compat_ioctl,
> +#endif
> +	.llseek = noop_llseek,
> +};
> +
> +static struct drm_driver sdrm_drm_driver = {
> +	.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
> +	.fops = &sdrm_drm_fops,
> +
> +	.gem_free_object = sdrm_bo_free,
> +
> +	.dumb_create = sdrm_dumb_create,
> +	.dumb_map_offset = sdrm_dumb_map_offset,
> +	.dumb_destroy = drm_gem_dumb_destroy,
> +
> +	.name = "simpledrm",
> +	.desc = "Simple firmware framebuffer DRM driver",
> +	.date = "20160901",
> +};
> +
> +static const struct of_device_id sdrm_simplefb_of_match[] = {
> +	{ .compatible = "simple-framebuffer", },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, sdrm_simplefb_of_match);
> +
> +static struct platform_driver sdrm_simplefb_driver = {
> +	.probe = sdrm_simplefb_probe,
> +	.remove = sdrm_simplefb_remove,
> +	.driver = {
> +		.name = "simple-framebuffer",
> +		.mod_name = KBUILD_MODNAME,
> +		.owner = THIS_MODULE,
> +		.of_match_table = sdrm_simplefb_of_match,
> +	},
> +};
> +
> +static int __init sdrm_init(void)
> +{
> +	int r;
> +
> +	r = platform_driver_register(&sdrm_simplefb_driver);
> +	if (r < 0)
> +		return r;
> +
> +	sdrm_of_bootstrap();
> +	return 0;
> +}
> +
> +static void __exit sdrm_exit(void)
> +{
> +	platform_driver_unregister(&sdrm_simplefb_driver);
> +}
> +
> +module_init(sdrm_init);
> +module_exit(sdrm_exit);
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Simple firmware framebuffer DRM driver");
> +MODULE_ALIAS("platform:simple-framebuffer");
>

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v5 0/7] drm: add simpledrm driver
  2016-09-02  8:22 [PATCH v5 0/7] drm: add simpledrm driver David Herrmann
                   ` (6 preceding siblings ...)
  2016-09-02  8:22 ` [PATCH v5 7/7] drm/simpledrm: add fbdev fallback support David Herrmann
@ 2021-03-10  2:50 ` nerdopolis
  2021-03-10  9:10   ` Thomas Zimmermann
  7 siblings, 1 reply; 31+ messages in thread
From: nerdopolis @ 2021-03-10  2:50 UTC (permalink / raw)
  To: dri-devel

On Friday, September 2, 2016 4:22:38 AM EST David Herrmann wrote:
> Hey
> 
> On request of Noralf, I picked up the patches and prepared v5. Works fine with
> Xorg, if configured according to:
>     https://lists.freedesktop.org/archives/dri-devel/2014-January/052777.html
> If anyone knows how to make Xorg pick it up dynamically without such a static
> configuration, please let me know.
> 
> Thanks
> David
> 
> David Herrmann (7):
>   x86/sysfb: add support for 64bit EFI lfb_base
>   x86/sysfb: fix lfb_size calculation
>   of/platform: expose of_platform_device_destroy()
>   video: add generic framebuffer eviction
>   drm: switch to sysfb_evict_conflicts()
>   drm: add SimpleDRM driver
>   drm/simpledrm: add fbdev fallback support
> 
>  MAINTAINERS                                  |   6 +
>  arch/x86/kernel/sysfb_simplefb.c             |  39 ++-
>  drivers/gpu/drm/Kconfig                      |   3 +
>  drivers/gpu/drm/Makefile                     |   1 +
>  drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c      |  24 +-
>  drivers/gpu/drm/bochs/bochs_drv.c            |  19 +-
>  drivers/gpu/drm/i915/i915_drv.c              |  73 +---
>  drivers/gpu/drm/mgag200/mgag200_drv.c        |  27 +-
>  drivers/gpu/drm/mgag200/mgag200_main.c       |   9 -
>  drivers/gpu/drm/nouveau/nouveau_drm.c        |  33 +-
>  drivers/gpu/drm/radeon/radeon_drv.c          |  24 +-
>  drivers/gpu/drm/simpledrm/Kconfig            |  19 ++
>  drivers/gpu/drm/simpledrm/Makefile           |   9 +
>  drivers/gpu/drm/simpledrm/simpledrm.h        |  91 +++++
>  drivers/gpu/drm/simpledrm/simpledrm_damage.c | 194 +++++++++++
>  drivers/gpu/drm/simpledrm/simpledrm_drv.c    | 477 +++++++++++++++++++++++++++
>  drivers/gpu/drm/simpledrm/simpledrm_fbdev.c  | 143 ++++++++
>  drivers/gpu/drm/simpledrm/simpledrm_gem.c    | 109 ++++++
>  drivers/gpu/drm/simpledrm/simpledrm_kms.c    | 270 +++++++++++++++
>  drivers/gpu/drm/simpledrm/simpledrm_of.c     | 265 +++++++++++++++
>  drivers/gpu/drm/sun4i/sun4i_drv.c            |  24 +-
>  drivers/gpu/drm/vc4/vc4_drv.c                |  25 +-
>  drivers/gpu/drm/virtio/virtgpu_drm_bus.c     |  24 +-
>  drivers/of/platform.c                        |  35 +-
>  drivers/video/Kconfig                        |   4 +
>  drivers/video/Makefile                       |   1 +
>  drivers/video/sysfb.c                        | 327 ++++++++++++++++++
>  include/linux/of_platform.h                  |   1 +
>  include/linux/sysfb.h                        |  34 ++
>  29 files changed, 2054 insertions(+), 256 deletions(-)
>  create mode 100644 drivers/gpu/drm/simpledrm/Kconfig
>  create mode 100644 drivers/gpu/drm/simpledrm/Makefile
>  create mode 100644 drivers/gpu/drm/simpledrm/simpledrm.h
>  create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_damage.c
>  create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_drv.c
>  create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_fbdev.c
>  create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_gem.c
>  create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_kms.c
>  create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_of.c
>  create mode 100644 drivers/video/sysfb.c
>  create mode 100644 include/linux/sysfb.h
> 
> 
Hi

I am kind of curious as I do have interest in seeing this merged as well. 

There is an email in this thread from 2018, but when I tried to import an mbox
file from the whole month for August 2018, for some reason, kmail doesn't see 
the sender and mailing list recipient in that one, so I will reply to this one,
because I was able to import this into my mail client. 
https://www.spinics.net/lists/dri-devel/msg185519.html

I was able to get this to build against Linux 4.8, but not against a newer
version, some headers seem to have been split, and some things are off by 8
and other things. I could NOT find a git repo, but I was able to find the 
newest patches I could find, and import those with git am against 4.8 with
some tweaks. If that is needed, I can link it, but only if you want.

However in QEMU I wasn't able to figure out how to make it create a 
/dev/dri/card0 device, even after blacklisting the other modules for qxl, 
cirrus, etc, and then modprobe-ing simpledrm

In my view something like this is would be useful. There still could be 
hardware devices that don't have modesetting support (like vmvga in 
qemu/virt-manager as an example). And most wayland servers need a 
/dev/dri/card0 device as well as a potential user-mode TTY replacement would
also need /dev/dri/card0

I will admit I unfortunately failed to get it to build against master. I 
couldn't figure out some of the changes, where some new structs were off by
a factor of 8. 


Thanks



_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v5 0/7] drm: add simpledrm driver
  2021-03-10  2:50 ` [PATCH v5 0/7] drm: add simpledrm driver nerdopolis
@ 2021-03-10  9:10   ` Thomas Zimmermann
  2021-03-10 13:52     ` nerdopolis
  2021-03-12  3:49     ` nerdopolis
  0 siblings, 2 replies; 31+ messages in thread
From: Thomas Zimmermann @ 2021-03-10  9:10 UTC (permalink / raw)
  To: nerdopolis, dri-devel


[-- Attachment #1.1.1: Type: text/plain, Size: 2915 bytes --]

Hi

Am 10.03.21 um 03:50 schrieb nerdopolis:
> On Friday, September 2, 2016 4:22:38 AM EST David Herrmann wrote:
>> Hey
>>
>> On request of Noralf, I picked up the patches and prepared v5. Works fine with
>> Xorg, if configured according to:
>>      https://lists.freedesktop.org/archives/dri-devel/2014-January/052777.html
>> If anyone knows how to make Xorg pick it up dynamically without such a static
>> configuration, please let me know.
>>
>>
>>
> Hi
> 
> I am kind of curious as I do have interest in seeing this merged as well.

Please take a look at [1]. It's not the same driver, but something to 
the same effect. I know it's been almost a year, but I do work on this 
and intend to come back with a new version during 2021.

I currently work on fastboot support for the new driver. But it's a 
complicated matter and takes time. If there's interest, we could talk 
about merging what's already there.

Best regards
Thomas

[1] 
https://lore.kernel.org/dri-devel/20200625120011.16168-1-tzimmermann@suse.de/

> 
> There is an email in this thread from 2018, but when I tried to import an mbox
> file from the whole month for August 2018, for some reason, kmail doesn't see
> the sender and mailing list recipient in that one, so I will reply to this one,
> because I was able to import this into my mail client.
> https://www.spinics.net/lists/dri-devel/msg185519.html
> 
> I was able to get this to build against Linux 4.8, but not against a newer
> version, some headers seem to have been split, and some things are off by 8
> and other things. I could NOT find a git repo, but I was able to find the
> newest patches I could find, and import those with git am against 4.8 with
> some tweaks. If that is needed, I can link it, but only if you want.
> 
> However in QEMU I wasn't able to figure out how to make it create a
> /dev/dri/card0 device, even after blacklisting the other modules for qxl,
> cirrus, etc, and then modprobe-ing simpledrm
> 
> In my view something like this is would be useful. There still could be
> hardware devices that don't have modesetting support (like vmvga in
> qemu/virt-manager as an example). And most wayland servers need a
> /dev/dri/card0 device as well as a potential user-mode TTY replacement would
> also need /dev/dri/card0
> 
> I will admit I unfortunately failed to get it to build against master. I
> couldn't figure out some of the changes, where some new structs were off by
> a factor of 8.
> 
> 
> Thanks
> 
> 
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v5 0/7] drm: add simpledrm driver
  2021-03-10  9:10   ` Thomas Zimmermann
@ 2021-03-10 13:52     ` nerdopolis
  2021-03-12  3:49     ` nerdopolis
  1 sibling, 0 replies; 31+ messages in thread
From: nerdopolis @ 2021-03-10 13:52 UTC (permalink / raw)
  To: dri-devel

On Wednesday, March 10, 2021 4:10:35 AM EST Thomas Zimmermann wrote:
> Hi
> 
> Am 10.03.21 um 03:50 schrieb nerdopolis:
> > On Friday, September 2, 2016 4:22:38 AM EST David Herrmann wrote:
> >> Hey
> >>
> >> On request of Noralf, I picked up the patches and prepared v5. Works fine with
> >> Xorg, if configured according to:
> >>      https://lists.freedesktop.org/archives/dri-devel/2014-January/052777.html
> >> If anyone knows how to make Xorg pick it up dynamically without such a static
> >> configuration, please let me know.
> >>
> >>
> >>
> > Hi
> > 
> > I am kind of curious as I do have interest in seeing this merged as well.
> 
> Please take a look at [1]. It's not the same driver, but something to 
> the same effect. I know it's been almost a year, but I do work on this 
> and intend to come back with a new version during 2021.
> 
Thanks, I'll try that out
> I currently work on fastboot support for the new driver. But it's a 
> complicated matter and takes time. If there's interest, we could talk 
> about merging what's already there.
> 
> Best regards
> Thomas
> 
> [1] 
> https://lore.kernel.org/dri-devel/20200625120011.16168-1-tzimmermann@suse.de/
> 
> > 
> > There is an email in this thread from 2018, but when I tried to import an mbox
> > file from the whole month for August 2018, for some reason, kmail doesn't see
> > the sender and mailing list recipient in that one, so I will reply to this one,
> > because I was able to import this into my mail client.
> > https://www.spinics.net/lists/dri-devel/msg185519.html
> > 
> > I was able to get this to build against Linux 4.8, but not against a newer
> > version, some headers seem to have been split, and some things are off by 8
> > and other things. I could NOT find a git repo, but I was able to find the
> > newest patches I could find, and import those with git am against 4.8 with
> > some tweaks. If that is needed, I can link it, but only if you want.
> > 
> > However in QEMU I wasn't able to figure out how to make it create a
> > /dev/dri/card0 device, even after blacklisting the other modules for qxl,
> > cirrus, etc, and then modprobe-ing simpledrm
> > 
> > In my view something like this is would be useful. There still could be
> > hardware devices that don't have modesetting support (like vmvga in
> > qemu/virt-manager as an example). And most wayland servers need a
> > /dev/dri/card0 device as well as a potential user-mode TTY replacement would
> > also need /dev/dri/card0
> > 
> > I will admit I unfortunately failed to get it to build against master. I
> > couldn't figure out some of the changes, where some new structs were off by
> > a factor of 8.
> > 
> > 
> > Thanks
> > 
> > 
> > 
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel
> > 
> 
> 




_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v5 0/7] drm: add simpledrm driver
  2021-03-10  9:10   ` Thomas Zimmermann
  2021-03-10 13:52     ` nerdopolis
@ 2021-03-12  3:49     ` nerdopolis
  2021-03-12  8:03       ` Thomas Zimmermann
  1 sibling, 1 reply; 31+ messages in thread
From: nerdopolis @ 2021-03-12  3:49 UTC (permalink / raw)
  To: dri-devel; +Cc: Thomas Zimmermann

On Wednesday, March 10, 2021 4:10:35 AM EST Thomas Zimmermann wrote:
> Hi
> 
> Am 10.03.21 um 03:50 schrieb nerdopolis:
> > On Friday, September 2, 2016 4:22:38 AM EST David Herrmann wrote:
> >> Hey
> >>
> >> On request of Noralf, I picked up the patches and prepared v5. Works fine with
> >> Xorg, if configured according to:
> >>      https://lists.freedesktop.org/archives/dri-devel/2014-January/052777.html
> >> If anyone knows how to make Xorg pick it up dynamically without such a static
> >> configuration, please let me know.
> >>
> >>
> >>
> > Hi
> > 
> > I am kind of curious as I do have interest in seeing this merged as well.
> 
> Please take a look at [1]. It's not the same driver, but something to 
> the same effect. I know it's been almost a year, but I do work on this 
> and intend to come back with a new version during 2021.
> 
> I currently work on fastboot support for the new driver. But it's a 
> complicated matter and takes time. If there's interest, we could talk 
> about merging what's already there.
> 
> Best regards
> Thomas
> 
> [1] 
> https://lore.kernel.org/dri-devel/20200625120011.16168-1-tzimmermann@suse.de/
> 
> > 
> > There is an email in this thread from 2018, but when I tried to import an mbox
> > file from the whole month for August 2018, for some reason, kmail doesn't see
> > the sender and mailing list recipient in that one, so I will reply to this one,
> > because I was able to import this into my mail client.
> > https://www.spinics.net/lists/dri-devel/msg185519.html
> > 
> > I was able to get this to build against Linux 4.8, but not against a newer
> > version, some headers seem to have been split, and some things are off by 8
> > and other things. I could NOT find a git repo, but I was able to find the
> > newest patches I could find, and import those with git am against 4.8 with
> > some tweaks. If that is needed, I can link it, but only if you want.
> > 
> > However in QEMU I wasn't able to figure out how to make it create a
> > /dev/dri/card0 device, even after blacklisting the other modules for qxl,
> > cirrus, etc, and then modprobe-ing simpledrm
> > 
> > In my view something like this is would be useful. There still could be
> > hardware devices that don't have modesetting support (like vmvga in
> > qemu/virt-manager as an example). And most wayland servers need a
> > /dev/dri/card0 device as well as a potential user-mode TTY replacement would
> > also need /dev/dri/card0
> > 
> > I will admit I unfortunately failed to get it to build against master. I
> > couldn't figure out some of the changes, where some new structs were off by
> > a factor of 8.
> > 
> > 
> > Thanks
> > 
> > 
> > 
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel
> > 
> 
> 
Hi

I tried simplekms against v5.9, and it built, and it runs, and is pretty neat.

I tried using the qxl, cirrus, and vmware card in QEMU. Weston starts on all
of them. And I did ensure that the simplekms driver was being used

That is, it works after adding GRUB_GFXPAYLOAD_LINUX=keep , to avoid having to
set a VGA option. (although not sure the equivalent in syslinux yet)
 

Thanks.


_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v5 0/7] drm: add simpledrm driver
  2021-03-12  3:49     ` nerdopolis
@ 2021-03-12  8:03       ` Thomas Zimmermann
  2021-03-12 13:25         ` nerdopolis
  0 siblings, 1 reply; 31+ messages in thread
From: Thomas Zimmermann @ 2021-03-12  8:03 UTC (permalink / raw)
  To: nerdopolis, dri-devel


[-- Attachment #1.1.1: Type: text/plain, Size: 4167 bytes --]

Hi

Am 12.03.21 um 04:49 schrieb nerdopolis:
> On Wednesday, March 10, 2021 4:10:35 AM EST Thomas Zimmermann wrote:
>> Hi
>>
>> Am 10.03.21 um 03:50 schrieb nerdopolis:
>>> On Friday, September 2, 2016 4:22:38 AM EST David Herrmann wrote:
>>>> Hey
>>>>
>>>> On request of Noralf, I picked up the patches and prepared v5. Works fine with
>>>> Xorg, if configured according to:
>>>>       https://lists.freedesktop.org/archives/dri-devel/2014-January/052777.html
>>>> If anyone knows how to make Xorg pick it up dynamically without such a static
>>>> configuration, please let me know.
>>>>
>>>>
>>>>
>>> Hi
>>>
>>> I am kind of curious as I do have interest in seeing this merged as well.
>>
>> Please take a look at [1]. It's not the same driver, but something to
>> the same effect. I know it's been almost a year, but I do work on this
>> and intend to come back with a new version during 2021.
>>
>> I currently work on fastboot support for the new driver. But it's a
>> complicated matter and takes time. If there's interest, we could talk
>> about merging what's already there.
>>
>> Best regards
>> Thomas
>>
>> [1]
>> https://lore.kernel.org/dri-devel/20200625120011.16168-1-tzimmermann@suse.de/
>>
>>>
>>> There is an email in this thread from 2018, but when I tried to import an mbox
>>> file from the whole month for August 2018, for some reason, kmail doesn't see
>>> the sender and mailing list recipient in that one, so I will reply to this one,
>>> because I was able to import this into my mail client.
>>> https://www.spinics.net/lists/dri-devel/msg185519.html
>>>
>>> I was able to get this to build against Linux 4.8, but not against a newer
>>> version, some headers seem to have been split, and some things are off by 8
>>> and other things. I could NOT find a git repo, but I was able to find the
>>> newest patches I could find, and import those with git am against 4.8 with
>>> some tweaks. If that is needed, I can link it, but only if you want.
>>>
>>> However in QEMU I wasn't able to figure out how to make it create a
>>> /dev/dri/card0 device, even after blacklisting the other modules for qxl,
>>> cirrus, etc, and then modprobe-ing simpledrm
>>>
>>> In my view something like this is would be useful. There still could be
>>> hardware devices that don't have modesetting support (like vmvga in
>>> qemu/virt-manager as an example). And most wayland servers need a
>>> /dev/dri/card0 device as well as a potential user-mode TTY replacement would
>>> also need /dev/dri/card0
>>>
>>> I will admit I unfortunately failed to get it to build against master. I
>>> couldn't figure out some of the changes, where some new structs were off by
>>> a factor of 8.
>>>
>>>
>>> Thanks
>>>
>>>
>>>
>>> _______________________________________________
>>> dri-devel mailing list
>>> dri-devel@lists.freedesktop.org
>>> https://lists.freedesktop.org/mailman/listinfo/dri-devel
>>>
>>
>>
> Hi
> 
> I tried simplekms against v5.9, and it built, and it runs, and is pretty neat.
> 
> I tried using the qxl, cirrus, and vmware card in QEMU. Weston starts on all
> of them. And I did ensure that the simplekms driver was being used

Cool! Thanks a lot. When I submit the next patchset can I add

Tested-by: nerdopolis <bluescreen_avenger@verizon.net>

to the tags?

> 
> That is, it works after adding GRUB_GFXPAYLOAD_LINUX=keep , to avoid having to
> set a VGA option. (although not sure the equivalent in syslinux yet)

Yeah, it's a known 'limitation.' (1) But it's usually something that 
Linux distributions take care of.

The rsp kernel feature needs a set up from the firmware/bootloader/etc. 
Once the driver has been merged, added other generic drivers (EFI, VESA, 
etc) should be a lot easier. Those would maybe not require the firmware 
setup.

Best regards
Thomas

(1) Well, it's the way it's supposed to work.

>   
> 
> Thanks.
> 
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v5 0/7] drm: add simpledrm driver
  2021-03-12  8:03       ` Thomas Zimmermann
@ 2021-03-12 13:25         ` nerdopolis
  0 siblings, 0 replies; 31+ messages in thread
From: nerdopolis @ 2021-03-12 13:25 UTC (permalink / raw)
  To: dri-devel

On Friday, March 12, 2021 3:03:46 AM EST Thomas Zimmermann wrote:
> Hi
> 
> Am 12.03.21 um 04:49 schrieb nerdopolis:
> > On Wednesday, March 10, 2021 4:10:35 AM EST Thomas Zimmermann wrote:
> >> Hi
> >>
> >> Am 10.03.21 um 03:50 schrieb nerdopolis:
> >>> On Friday, September 2, 2016 4:22:38 AM EST David Herrmann wrote:
> >>>> Hey
> >>>>
> >>>> On request of Noralf, I picked up the patches and prepared v5. Works fine with
> >>>> Xorg, if configured according to:
> >>>>       https://lists.freedesktop.org/archives/dri-devel/2014-January/052777.html
> >>>> If anyone knows how to make Xorg pick it up dynamically without such a static
> >>>> configuration, please let me know.
> >>>>
> >>>>
> >>>>
> >>> Hi
> >>>
> >>> I am kind of curious as I do have interest in seeing this merged as well.
> >>
> >> Please take a look at [1]. It's not the same driver, but something to
> >> the same effect. I know it's been almost a year, but I do work on this
> >> and intend to come back with a new version during 2021.
> >>
> >> I currently work on fastboot support for the new driver. But it's a
> >> complicated matter and takes time. If there's interest, we could talk
> >> about merging what's already there.
> >>
> >> Best regards
> >> Thomas
> >>
> >> [1]
> >> https://lore.kernel.org/dri-devel/20200625120011.16168-1-tzimmermann@suse.de/
> >>
> >>>
> >>> There is an email in this thread from 2018, but when I tried to import an mbox
> >>> file from the whole month for August 2018, for some reason, kmail doesn't see
> >>> the sender and mailing list recipient in that one, so I will reply to this one,
> >>> because I was able to import this into my mail client.
> >>> https://www.spinics.net/lists/dri-devel/msg185519.html
> >>>
> >>> I was able to get this to build against Linux 4.8, but not against a newer
> >>> version, some headers seem to have been split, and some things are off by 8
> >>> and other things. I could NOT find a git repo, but I was able to find the
> >>> newest patches I could find, and import those with git am against 4.8 with
> >>> some tweaks. If that is needed, I can link it, but only if you want.
> >>>
> >>> However in QEMU I wasn't able to figure out how to make it create a
> >>> /dev/dri/card0 device, even after blacklisting the other modules for qxl,
> >>> cirrus, etc, and then modprobe-ing simpledrm
> >>>
> >>> In my view something like this is would be useful. There still could be
> >>> hardware devices that don't have modesetting support (like vmvga in
> >>> qemu/virt-manager as an example). And most wayland servers need a
> >>> /dev/dri/card0 device as well as a potential user-mode TTY replacement would
> >>> also need /dev/dri/card0
> >>>
> >>> I will admit I unfortunately failed to get it to build against master. I
> >>> couldn't figure out some of the changes, where some new structs were off by
> >>> a factor of 8.
> >>>
> >>>
> >>> Thanks
> >>>
> >>>
> >>>
> >>> _______________________________________________
> >>> dri-devel mailing list
> >>> dri-devel@lists.freedesktop.org
> >>> https://lists.freedesktop.org/mailman/listinfo/dri-devel
> >>>
> >>
> >>
> > Hi
> > 
> > I tried simplekms against v5.9, and it built, and it runs, and is pretty neat.
> > 
> > I tried using the qxl, cirrus, and vmware card in QEMU. Weston starts on all
> > of them. And I did ensure that the simplekms driver was being used
> 
> Cool! Thanks a lot. When I submit the next patchset can I add
> 
> Tested-by: nerdopolis <bluescreen_avenger@verizon.net>
> 
> to the tags?
> 
Sure!
> > 
> > That is, it works after adding GRUB_GFXPAYLOAD_LINUX=keep , to avoid having to
> > set a VGA option. (although not sure the equivalent in syslinux yet)
> 
> Yeah, it's a known 'limitation.' (1) But it's usually something that 
> Linux distributions take care of.
> 
> The rsp kernel feature needs a set up from the firmware/bootloader/etc. 
> Once the driver has been merged, added other generic drivers (EFI, VESA, 
> etc) should be a lot easier. Those would maybe not require the firmware 
> setup.
> 
> Best regards
> Thomas
> 
> (1) Well, it's the way it's supposed to work.
> 
> >   
> > 
> > Thanks.
> > 
> > 
> 
> 




_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v5 0/7] drm: add simpledrm driver
  2018-07-24 12:27 Mads Lønsethagen
@ 2018-08-07 16:42 ` Daniel Vetter
  0 siblings, 0 replies; 31+ messages in thread
From: Daniel Vetter @ 2018-08-07 16:42 UTC (permalink / raw)
  To: Mads Lønsethagen; +Cc: dri-devel

On Tue, Jul 24, 2018 at 02:27:33PM +0200, Mads Lønsethagen wrote:
> > Hey
> > 
> > On request of Noralf, I picked up the patches and prepared v5. Works
> > fine with
> > Xorg, if configured according to:
> > https://lists.freedesktop.org/archives/dri-devel/2014-January/052777.html
> > If anyone knows how to make Xorg pick it up dynamically without such a
> > static
> > configuration, please let me know.
> > 
> > Thanks
> > David
> > 
> > David Herrmann (7):
> >   x86/sysfb: add support for 64bit EFI lfb_base
> >   x86/sysfb: fix lfb_size calculation
> >   of/platform: expose of_platform_device_destroy()
> >   video: add generic framebuffer eviction
> >   drm: switch to sysfb_evict_conflicts()
> >   drm: add SimpleDRM driver
> >   drm/simpledrm: add fbdev fallback support
> > ...
> 
> Hi!
> 
> I asked Noralf about this patch set recently, and he mentioned that this
> never made it any further than this patch series...
> 
> Are there still any interest in getting this mainlined? Does the code exist
> in any repo anywhere? For my own part, this would be an awesome driver to
> have to resurrect some old hardware I have lying around...

I think no objections against merging this from upstream pov, and David
hopefully still has a git branch somewhere. Even better if you could get a
distro on board to use this instead of efifb of offb.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v5 0/7] drm: add simpledrm driver
@ 2018-07-24 12:27 Mads Lønsethagen
  2018-08-07 16:42 ` Daniel Vetter
  0 siblings, 1 reply; 31+ messages in thread
From: Mads Lønsethagen @ 2018-07-24 12:27 UTC (permalink / raw)
  To: dh.herrmann, dri-devel

> Hey
> 
> On request of Noralf, I picked up the patches and prepared v5. Works 
> fine with
> Xorg, if configured according to:
>     
> https://lists.freedesktop.org/archives/dri-devel/2014-January/052777.html
> If anyone knows how to make Xorg pick it up dynamically without such a 
> static
> configuration, please let me know.
> 
> Thanks
> David
> 
> David Herrmann (7):
>   x86/sysfb: add support for 64bit EFI lfb_base
>   x86/sysfb: fix lfb_size calculation
>   of/platform: expose of_platform_device_destroy()
>   video: add generic framebuffer eviction
>   drm: switch to sysfb_evict_conflicts()
>   drm: add SimpleDRM driver
>   drm/simpledrm: add fbdev fallback support
> ...

Hi!

I asked Noralf about this patch set recently, and he mentioned that this 
never made it any further than this patch series...

Are there still any interest in getting this mainlined? Does the code 
exist in any repo anywhere? For my own part, this would be an awesome 
driver to have to resurrect some old hardware I have lying around...

- Mads
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2021-03-12 13:25 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-02  8:22 [PATCH v5 0/7] drm: add simpledrm driver David Herrmann
2016-09-02  8:22 ` [PATCH v5 1/7] x86/sysfb: add support for 64bit EFI lfb_base David Herrmann
2016-09-02 10:20   ` Tom Gundersen
2016-09-02  8:22 ` [PATCH v5 2/7] x86/sysfb: fix lfb_size calculation David Herrmann
2016-09-02 10:20   ` Tom Gundersen
2016-09-02  8:22 ` [PATCH v5 3/7] of/platform: expose of_platform_device_destroy() David Herrmann
2016-09-02 10:21   ` Tom Gundersen
2016-09-02  8:22 ` [PATCH v5 4/7] video: add generic framebuffer eviction David Herrmann
2016-09-02 10:21   ` Tom Gundersen
2016-09-03 12:06   ` Noralf Trønnes
2016-09-05 11:19     ` David Herrmann
2016-09-05 16:36       ` Noralf Trønnes
2016-09-02  8:22 ` [PATCH v5 5/7] drm: switch to sysfb_evict_conflicts() David Herrmann
2016-09-03 12:13   ` Noralf Trønnes
2016-09-02  8:22 ` [PATCH v5 6/7] drm: add SimpleDRM driver David Herrmann
2016-09-02 12:45   ` Tom Gundersen
2016-09-03 12:01   ` Noralf Trønnes
2016-09-03 12:05     ` David Herrmann
2016-09-05 16:39   ` Noralf Trønnes
2016-09-02  8:22 ` [PATCH v5 7/7] drm/simpledrm: add fbdev fallback support David Herrmann
2016-09-03 12:04   ` Noralf Trønnes
2016-09-03 17:15     ` Noralf Trønnes
2016-09-05 11:21       ` David Herrmann
2021-03-10  2:50 ` [PATCH v5 0/7] drm: add simpledrm driver nerdopolis
2021-03-10  9:10   ` Thomas Zimmermann
2021-03-10 13:52     ` nerdopolis
2021-03-12  3:49     ` nerdopolis
2021-03-12  8:03       ` Thomas Zimmermann
2021-03-12 13:25         ` nerdopolis
2018-07-24 12:27 Mads Lønsethagen
2018-08-07 16:42 ` Daniel Vetter

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.