dri-devel.lists.freedesktop.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/6] SimpleDRM Driver
@ 2013-09-01 13:36 David Herrmann
  2013-09-01 13:36 ` [PATCH v4 1/6] drm: add SimpleDRM driver David Herrmann
                   ` (6 more replies)
  0 siblings, 7 replies; 15+ messages in thread
From: David Herrmann @ 2013-09-01 13:36 UTC (permalink / raw)
  To: dri-devel

Hi

With the upcoming 3.12 merge-window, I thought people might find themselves with
nothing to do, so here's a new SimpleDRM series. Comments welcome!

This depends on the tip/x86/fb series in the x86-tip tree:
  http://git.kernel.org/cgit/linux/kernel/git/tip/tip.git/log/?h=x86/fb
Which, as far as I understood, will be pushed into 3.12 by the x86 people.

Patches #1 and #2 implement the SimpleDRM driver which can replace vesafb,
efifb, simplefb, vgafb and more. Just enable the CONFIG_X86_SYSFB option and
you're good to go.

Patches #3 to #6 implement drm_kick_out_firmware() to make x86 drivers kick out
firmware-DRM drivers instead of only fbdev via
remove_conflicting_framebuffers().

I tested this based on drm-next plus the x86/fb series merged with i915 and
nouveau and it worked just fine.

Regards
David


David Herrmann (6):
  drm: add SimpleDRM driver
  drm: simpledrm: add fbdev fallback support
  drm: add helpers to kick out firmware drivers
  drm: nouveau: kick out firmware drivers during probe
  drm/i915: use new drm_kick_out_firmware()
  drm/radeon: use new drm_kick_out_firmware()

 MAINTAINERS                                 |   8 +
 drivers/gpu/drm/Kconfig                     |   2 +
 drivers/gpu/drm/Makefile                    |   1 +
 drivers/gpu/drm/drm_pci.c                   |   1 +
 drivers/gpu/drm/drm_platform.c              |   1 +
 drivers/gpu/drm/drm_stub.c                  | 118 +++++++++
 drivers/gpu/drm/drm_usb.c                   |   1 +
 drivers/gpu/drm/i915/i915_dma.c             |   6 +-
 drivers/gpu/drm/nouveau/nouveau_drm.c       |  29 ++-
 drivers/gpu/drm/radeon/radeon_drv.c         |  28 ---
 drivers/gpu/drm/radeon/radeon_kms.c         |  30 +++
 drivers/gpu/drm/simpledrm/Kconfig           |  29 +++
 drivers/gpu/drm/simpledrm/Makefile          |   4 +
 drivers/gpu/drm/simpledrm/simpledrm.h       | 112 +++++++++
 drivers/gpu/drm/simpledrm/simpledrm_drv.c   | 226 +++++++++++++++++
 drivers/gpu/drm/simpledrm/simpledrm_fbdev.c | 153 ++++++++++++
 drivers/gpu/drm/simpledrm/simpledrm_main.c  | 363 ++++++++++++++++++++++++++++
 drivers/gpu/drm/simpledrm/simpledrm_mem.c   | 242 +++++++++++++++++++
 include/drm/drmP.h                          |  26 ++
 19 files changed, 1342 insertions(+), 38 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_drv.c
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_fbdev.c
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_main.c
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_mem.c

-- 
1.8.4

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

* [PATCH v4 1/6] drm: add SimpleDRM driver
  2013-09-01 13:36 [PATCH v4 0/6] SimpleDRM Driver David Herrmann
@ 2013-09-01 13:36 ` David Herrmann
  2013-09-21 14:18   ` Tom Gundersen
  2013-09-01 13:36 ` [PATCH v4 2/6] drm: simpledrm: add fbdev fallback support David Herrmann
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 15+ messages in thread
From: David Herrmann @ 2013-09-01 13:36 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 one dumb-buffer and attach it to the CRTC. Only if
the buffer is destroyed, a new buffer can be created. The buffer is
directly mapped into user-space, so we have only resources for a single
buffer. Otherwise, shadow buffers plus damage-request would be needed.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Tested-by: Stephen Warren <swarren@nvidia.com>
---
 MAINTAINERS                                |   8 +
 drivers/gpu/drm/Kconfig                    |   2 +
 drivers/gpu/drm/Makefile                   |   1 +
 drivers/gpu/drm/simpledrm/Kconfig          |  18 ++
 drivers/gpu/drm/simpledrm/Makefile         |   3 +
 drivers/gpu/drm/simpledrm/simpledrm.h      |  89 ++++++++
 drivers/gpu/drm/simpledrm/simpledrm_drv.c  | 225 ++++++++++++++++++++
 drivers/gpu/drm/simpledrm/simpledrm_main.c | 328 +++++++++++++++++++++++++++++
 drivers/gpu/drm/simpledrm/simpledrm_mem.c  | 242 +++++++++++++++++++++
 9 files changed, 916 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_drv.c
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_main.c
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_mem.c

diff --git a/MAINTAINERS b/MAINTAINERS
index a26b10e..35c2fab 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7435,6 +7435,14 @@ S:	Odd Fixes
 F:	drivers/media/platform/sh_vou.c
 F:	include/media/sh_vou.h
 
+SIMPLE DRM DRIVER
+M:	David Herrmann <dh.herrmann@gmail.com>
+L:	dri-devel@lists.freedesktop.org
+T:	git git://people.freedesktop.org/~dvdhrm/linux
+S:	Maintained
+F:	drivers/gpu/drm/simpledrm
+F:	include/linux/platform_data/simpledrm.h
+
 SIMPLE FIRMWARE INTERFACE (SFI)
 M:	Len Brown <lenb@kernel.org>
 L:	sfi-devel@simplefirmware.org
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 955555d..33c1765 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -236,3 +236,5 @@ source "drivers/gpu/drm/tilcdc/Kconfig"
 source "drivers/gpu/drm/qxl/Kconfig"
 
 source "drivers/gpu/drm/msm/Kconfig"
+
+source "drivers/gpu/drm/simpledrm/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index f089adf..fe23d6f 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -55,4 +55,5 @@ obj-$(CONFIG_DRM_OMAP)	+= omapdrm/
 obj-$(CONFIG_DRM_TILCDC)	+= tilcdc/
 obj-$(CONFIG_DRM_QXL) += qxl/
 obj-$(CONFIG_DRM_MSM) += msm/
+obj-$(CONFIG_DRM_SIMPLEDRM) += simpledrm/
 obj-y			+= i2c/
diff --git a/drivers/gpu/drm/simpledrm/Kconfig b/drivers/gpu/drm/simpledrm/Kconfig
new file mode 100644
index 0000000..35bcce8
--- /dev/null
+++ b/drivers/gpu/drm/simpledrm/Kconfig
@@ -0,0 +1,18 @@
+config DRM_SIMPLEDRM
+	tristate "Simple firmware framebuffer DRM driver"
+	depends on DRM && (FB_SIMPLE = n)
+	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..ceb97eb
--- /dev/null
+++ b/drivers/gpu/drm/simpledrm/Makefile
@@ -0,0 +1,3 @@
+simpledrm-y := simpledrm_drv.o simpledrm_main.o simpledrm_mem.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..977b344
--- /dev/null
+++ b/drivers/gpu/drm/simpledrm/simpledrm.h
@@ -0,0 +1,89 @@
+/*
+ * SimpleDRM firmware framebuffer driver
+ * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#ifndef SDRM_DRV_H
+#define SDRM_DRV_H
+
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_data/simplefb.h>
+#include <linux/string.h>
+#include <drm/drmP.h>
+
+struct sdrm_device;
+struct sdrm_gem_object;
+struct sdrm_framebuffer;
+
+/* simpledrm devices */
+
+struct sdrm_device {
+	struct drm_device *ddev;
+
+	/* framebuffer information */
+	const struct simplefb_format *fb_sformat;
+	u32 fb_format;
+	u32 fb_width;
+	u32 fb_height;
+	u32 fb_stride;
+	u32 fb_bpp;
+	unsigned long fb_base;
+	unsigned long fb_size;
+	void *fb_map;
+
+	/* mode-setting objects */
+	struct sdrm_gem_object *fb_obj;
+	struct drm_crtc crtc;
+	struct drm_encoder enc;
+	struct drm_connector conn;
+	struct drm_display_mode *mode;
+};
+
+int sdrm_drm_load(struct drm_device *ddev, unsigned long flags);
+int sdrm_drm_unload(struct drm_device *ddev);
+int sdrm_drm_mmap(struct file *filp, struct vm_area_struct *vma);
+int sdrm_pdev_init(struct sdrm_device *sdrm);
+void sdrm_pdev_destroy(struct sdrm_device *sdrm);
+
+/* simpledrm gem objects */
+
+struct sdrm_gem_object {
+	struct drm_gem_object base;
+	unsigned long fb_base;
+	unsigned long fb_size;
+};
+
+#define to_sdrm_bo(x) container_of(x, struct sdrm_gem_object, base)
+
+int sdrm_gem_init_object(struct drm_gem_object *obj);
+void sdrm_gem_free_object(struct drm_gem_object *obj);
+void sdrm_gem_unmap_object(struct sdrm_gem_object *obj);
+
+/* dumb buffers */
+
+int sdrm_dumb_create(struct drm_file *file_priv, struct drm_device *ddev,
+		     struct drm_mode_create_dumb *arg);
+int sdrm_dumb_destroy(struct drm_file *file_priv, struct drm_device *ddev,
+		      uint32_t handle);
+int sdrm_dumb_map_offset(struct drm_file *file_priv, struct drm_device *ddev,
+			 uint32_t handle, uint64_t *offset);
+
+/* simpledrm framebuffers */
+
+struct sdrm_framebuffer {
+	struct drm_framebuffer base;
+	struct sdrm_gem_object *obj;
+};
+
+#define to_sdrm_fb(x) container_of(x, struct sdrm_framebuffer, base)
+
+#endif /* SDRM_DRV_H */
diff --git a/drivers/gpu/drm/simpledrm/simpledrm_drv.c b/drivers/gpu/drm/simpledrm/simpledrm_drv.c
new file mode 100644
index 0000000..8a34051
--- /dev/null
+++ b/drivers/gpu/drm/simpledrm/simpledrm_drv.c
@@ -0,0 +1,225 @@
+/*
+ * SimpleDRM firmware framebuffer driver
+ * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_data/simplefb.h>
+#include <linux/string.h>
+#include <drm/drmP.h>
+#include "simpledrm.h"
+
+static const struct file_operations sdrm_drm_fops = {
+	.owner = THIS_MODULE,
+	.open = drm_open,
+	.mmap = sdrm_drm_mmap,
+	.poll = drm_poll,
+	.read = drm_read,
+	.unlocked_ioctl = drm_ioctl,
+	.release = drm_release,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = drm_compat_ioctl,
+#endif
+	.llseek = noop_llseek,
+};
+
+static struct drm_driver sdrm_drm_driver = {
+	.driver_features = DRIVER_MODESET | DRIVER_GEM,
+	.load = sdrm_drm_load,
+	.unload = sdrm_drm_unload,
+	.fops = &sdrm_drm_fops,
+
+	.gem_init_object = sdrm_gem_init_object,
+	.gem_free_object = sdrm_gem_free_object,
+
+	.dumb_create = sdrm_dumb_create,
+	.dumb_map_offset = sdrm_dumb_map_offset,
+	.dumb_destroy = sdrm_dumb_destroy,
+
+	.name = "simpledrm",
+	.desc = "Simple firmware framebuffer DRM driver",
+	.date = "20130601",
+	.major = 0,
+	.minor = 0,
+	.patchlevel = 1,
+};
+
+static int parse_dt(struct platform_device *pdev,
+		    struct simplefb_platform_data *mode)
+{
+	struct device_node *np = pdev->dev.of_node;
+	const char *format;
+	int ret;
+
+	if (!np)
+		return -ENODEV;
+
+	ret = of_property_read_u32(np, "width", &mode->width);
+	if (ret) {
+		dev_err(&pdev->dev, "Can't parse width property\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(np, "height", &mode->height);
+	if (ret) {
+		dev_err(&pdev->dev, "Can't parse height property\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(np, "stride", &mode->stride);
+	if (ret) {
+		dev_err(&pdev->dev, "Can't parse stride property\n");
+		return ret;
+	}
+
+	ret = of_property_read_string(np, "format", &format);
+	if (ret) {
+		dev_err(&pdev->dev, "Can't parse format property\n");
+		return ret;
+	}
+	mode->format = format;
+
+	return 0;
+}
+
+static struct simplefb_format simplefb_formats[] = SIMPLEFB_FORMATS;
+
+int sdrm_pdev_init(struct sdrm_device *sdrm)
+{
+	struct platform_device *pdev = sdrm->ddev->platformdev;
+	struct simplefb_platform_data *mode = pdev->dev.platform_data;
+	struct simplefb_platform_data pmode;
+	struct resource *mem;
+	unsigned int depth;
+	int ret, i, bpp;
+
+	if (!mode) {
+		mode = &pmode;
+		ret = parse_dt(pdev, mode);
+		if (ret)
+			return ret;
+	}
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem) {
+		dev_err(sdrm->ddev->dev, "No memory resource\n");
+		return -ENODEV;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(simplefb_formats); ++i) {
+		if (strcmp(mode->format, simplefb_formats[i].name))
+			continue;
+
+		sdrm->fb_sformat = &simplefb_formats[i];
+		sdrm->fb_format = simplefb_formats[i].fourcc;
+		sdrm->fb_width = mode->width;
+		sdrm->fb_height = mode->height;
+		sdrm->fb_stride = mode->stride;
+		sdrm->fb_base = mem->start;
+		sdrm->fb_size = resource_size(mem);
+		break;
+	}
+
+	if (i >= ARRAY_SIZE(simplefb_formats)) {
+		dev_err(sdrm->ddev->dev, "Unknown format %s\n", mode->format);
+		return -ENODEV;
+	}
+
+	drm_fb_get_bpp_depth(sdrm->fb_format, &depth, &bpp);
+	if (!bpp) {
+		dev_err(sdrm->ddev->dev, "Unknown format %s\n", mode->format);
+		return -ENODEV;
+	}
+
+	if (sdrm->fb_size < sdrm->fb_stride * sdrm->fb_height) {
+		dev_err(sdrm->ddev->dev, "FB too small\n");
+		return -ENODEV;
+	} else if ((bpp + 7) / 8 * sdrm->fb_width > sdrm->fb_stride) {
+		dev_err(sdrm->ddev->dev, "Invalid stride\n");
+		return -ENODEV;
+	}
+
+	sdrm->fb_bpp = bpp;
+
+	if (!request_mem_region(sdrm->fb_base, sdrm->fb_size,
+				"simple-framebuffer")) {
+		dev_err(sdrm->ddev->dev, "cannot reserve VMEM\n");
+		return -EIO;
+	}
+
+	sdrm->fb_map = ioremap_wc(sdrm->fb_base, sdrm->fb_size);
+	if (!sdrm->fb_map) {
+		dev_err(sdrm->ddev->dev, "cannot remap VMEM\n");
+		ret = -EIO;
+		goto err_region;
+	}
+
+	return 0;
+
+err_region:
+	release_mem_region(sdrm->fb_base, sdrm->fb_size);
+	return ret;
+}
+
+void sdrm_pdev_destroy(struct sdrm_device *sdrm)
+{
+	if (sdrm->fb_map) {
+		iounmap(sdrm->fb_map);
+		release_mem_region(sdrm->fb_base, sdrm->fb_size);
+		sdrm->fb_map = NULL;
+	}
+}
+
+static int sdrm_simplefb_probe(struct platform_device *pdev)
+{
+	return drm_platform_init(&sdrm_drm_driver, pdev);
+}
+
+static int sdrm_simplefb_remove(struct platform_device *pdev)
+{
+	drm_platform_exit(&sdrm_drm_driver, pdev);
+
+	return 0;
+}
+
+static const struct of_device_id simplefb_of_match[] = {
+	{ .compatible = "simple-framebuffer", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, 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 = simplefb_of_match,
+	},
+};
+
+static int __init sdrm_init(void)
+{
+	return platform_driver_register(&sdrm_simplefb_driver);
+}
+
+static void __exit sdrm_exit(void)
+{
+	platform_driver_unregister(&sdrm_simplefb_driver);
+}
+
+module_init(sdrm_init);
+module_exit(sdrm_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>");
+MODULE_DESCRIPTION("Simple firmware framebuffer DRM driver");
diff --git a/drivers/gpu/drm/simpledrm/simpledrm_main.c b/drivers/gpu/drm/simpledrm/simpledrm_main.c
new file mode 100644
index 0000000..ae507e3
--- /dev/null
+++ b/drivers/gpu/drm/simpledrm/simpledrm_main.c
@@ -0,0 +1,328 @@
+/*
+ * SimpleDRM firmware framebuffer driver
+ * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include "simpledrm.h"
+
+/* crtcs */
+
+static int sdrm_crtc_set_config(struct drm_mode_set *set)
+{
+	struct drm_device *ddev;
+	struct sdrm_device *sdrm;
+	struct sdrm_framebuffer *fb;
+
+	if (!set || !set->crtc)
+		return -EINVAL;
+
+	ddev = set->crtc->dev;
+	sdrm = ddev->dev_private;
+
+	if (set->crtc != &sdrm->crtc)
+		return -EINVAL;
+
+	if (!set->mode || !set->fb || !set->num_connectors) {
+		sdrm->conn.encoder = NULL;
+		sdrm->conn.dpms = DRM_MODE_DPMS_OFF;
+		sdrm->enc.crtc = NULL;
+		sdrm->crtc.fb = NULL;
+		sdrm->crtc.enabled = false;
+		return 0;
+	}
+
+	fb = to_sdrm_fb(set->fb);
+
+	if (set->num_connectors != 1 || set->connectors[0] != &sdrm->conn)
+		return -EINVAL;
+	if (set->x || set->y)
+		return -EINVAL;
+	if (set->mode->hdisplay != sdrm->fb_width ||
+	    set->mode->vdisplay != sdrm->fb_height)
+		return -EINVAL;
+
+	sdrm->conn.encoder = &sdrm->enc;
+	sdrm->conn.dpms = DRM_MODE_DPMS_ON;
+	sdrm->enc.crtc = &sdrm->crtc;
+	sdrm->crtc.fb = set->fb;
+	sdrm->crtc.enabled = true;
+	sdrm->crtc.mode = *set->mode;
+	sdrm->crtc.hwmode = *set->mode;
+	sdrm->crtc.x = 0;
+	sdrm->crtc.y = 0;
+
+	drm_calc_timestamping_constants(&sdrm->crtc);
+	return 0;
+}
+
+static const struct drm_crtc_funcs sdrm_crtc_ops = {
+	.set_config = sdrm_crtc_set_config,
+	.destroy = drm_crtc_cleanup,
+};
+
+/* encoders */
+
+static const struct drm_encoder_funcs sdrm_enc_ops = {
+	.destroy = drm_encoder_cleanup,
+};
+
+/* connectors */
+
+static void sdrm_conn_dpms(struct drm_connector *conn, int mode)
+{
+	conn->dpms = mode;
+}
+
+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 int sdrm_conn_fill_modes(struct drm_connector *conn, uint32_t max_x,
+				uint32_t max_y)
+{
+	struct sdrm_device *sdrm = conn->dev->dev_private;
+	struct drm_display_mode *mode;
+	int ret;
+
+	if (conn->force == DRM_FORCE_ON)
+		conn->status = connector_status_connected;
+	else if (conn->force)
+		conn->status = connector_status_disconnected;
+	else
+		conn->status = connector_status_connected;
+
+	list_for_each_entry(mode, &conn->modes, head)
+		mode->status = MODE_UNVERIFIED;
+
+	mode = drm_gtf_mode(sdrm->ddev, sdrm->fb_width, sdrm->fb_height,
+			    60, 0, 0);
+	if (mode) {
+		mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+		drm_mode_probed_add(conn, mode);
+		sdrm->mode = mode;
+		drm_mode_connector_list_update(conn);
+		ret = 1;
+	} else {
+		ret = 0;
+	}
+
+	if (max_x && max_y)
+		drm_mode_validate_size(conn->dev, &conn->modes,
+				       max_x, max_y, 0);
+
+	drm_mode_prune_invalid(conn->dev, &conn->modes, false);
+	if (list_empty(&conn->modes))
+		return 0;
+
+	drm_mode_sort(&conn->modes);
+
+	list_for_each_entry(mode, &conn->modes, head) {
+		mode->vrefresh = drm_mode_vrefresh(mode);
+		drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+	}
+
+	return ret;
+}
+
+static void sdrm_conn_destroy(struct drm_connector *conn)
+{
+	/* Remove the fake-connector from sysfs and then let the DRM core
+	 * clean up all associated resources. */
+	if (device_is_registered(&conn->kdev))
+		drm_sysfs_connector_remove(conn);
+	drm_connector_cleanup(conn);
+}
+
+static const struct drm_connector_funcs sdrm_conn_ops = {
+	.dpms = sdrm_conn_dpms,
+	.detect = sdrm_conn_detect,
+	.fill_modes = sdrm_conn_fill_modes,
+	.destroy = sdrm_conn_destroy,
+};
+
+/* framebuffers */
+
+static int sdrm_fb_create_handle(struct drm_framebuffer *fb,
+				 struct drm_file *dfile,
+				 unsigned int *handle)
+{
+	struct sdrm_framebuffer *sfb = to_sdrm_fb(fb);
+
+	return drm_gem_handle_create(dfile, &sfb->obj->base, handle);
+}
+
+static void sdrm_fb_destroy(struct drm_framebuffer *fb)
+{
+	struct sdrm_framebuffer *sfb = to_sdrm_fb(fb);
+
+	drm_framebuffer_cleanup(fb);
+	drm_gem_object_unreference_unlocked(&sfb->obj->base);
+	kfree(sfb);
+}
+
+static const struct drm_framebuffer_funcs sdrm_fb_ops = {
+	.create_handle = sdrm_fb_create_handle,
+	.destroy = sdrm_fb_destroy,
+};
+
+static struct drm_framebuffer *sdrm_fb_create(struct drm_device *ddev,
+					      struct drm_file *dfile,
+					      struct drm_mode_fb_cmd2 *cmd)
+{
+	struct sdrm_device *sdrm = ddev->dev_private;
+	struct sdrm_framebuffer *fb;
+	struct drm_gem_object *gobj;
+	int ret, i;
+	void *err;
+
+	if (cmd->flags || cmd->pixel_format != sdrm->fb_format)
+		return ERR_PTR(-EINVAL);
+	if (cmd->height != sdrm->fb_height || cmd->width != sdrm->fb_width)
+		return ERR_PTR(-EINVAL);
+	if (cmd->offsets[0] || cmd->pitches[0] != sdrm->fb_stride)
+		return ERR_PTR(-EINVAL);
+
+	gobj = drm_gem_object_lookup(ddev, dfile, cmd->handles[0]);
+	if (!gobj)
+		return ERR_PTR(-EINVAL);
+
+	fb = kzalloc(sizeof(*fb), GFP_KERNEL);
+	if (!fb) {
+		err = ERR_PTR(-ENOMEM);
+		goto err_unref;
+	}
+	fb->obj = to_sdrm_bo(gobj);
+
+	fb->base.pitches[0] = cmd->pitches[0];
+	fb->base.offsets[0] = cmd->offsets[0];
+	for (i = 1; i < 4; i++) {
+		fb->base.pitches[i] = 0;
+		fb->base.offsets[i] = 0;
+	}
+
+	fb->base.width = cmd->width;
+	fb->base.height = cmd->height;
+	fb->base.pixel_format = cmd->pixel_format;
+	drm_fb_get_bpp_depth(cmd->pixel_format, &fb->base.depth,
+			     &fb->base.bits_per_pixel);
+
+	ret = drm_framebuffer_init(ddev, &fb->base, &sdrm_fb_ops);
+	if (ret < 0) {
+		err = ERR_PTR(ret);
+		goto err_free;
+	}
+
+	return &fb->base;
+
+err_free:
+	kfree(fb);
+err_unref:
+	drm_gem_object_unreference_unlocked(gobj);
+	return err;
+}
+
+static const struct drm_mode_config_funcs sdrm_mode_config_ops = {
+	.fb_create = sdrm_fb_create,
+};
+
+/* initialization */
+
+int sdrm_drm_load(struct drm_device *ddev, unsigned long flags)
+{
+	struct sdrm_device *sdrm;
+	int ret;
+
+	sdrm = kzalloc(sizeof(*sdrm), GFP_KERNEL);
+	if (!sdrm)
+		return -ENOMEM;
+
+	sdrm->ddev = ddev;
+	ddev->dev_private = sdrm;
+
+	ddev->devname = kstrdup("simpledrm", GFP_KERNEL);
+	if (!ddev->devname) {
+		ret = -ENOMEM;
+		goto err_free;
+	}
+
+	ret = sdrm_pdev_init(sdrm);
+	if (ret)
+		goto err_name;
+
+	drm_mode_config_init(ddev);
+	ddev->mode_config.min_width = 0;
+	ddev->mode_config.min_height = 0;
+	ddev->mode_config.max_width = 8192;
+	ddev->mode_config.max_height = 8192;
+	ddev->mode_config.funcs = &sdrm_mode_config_ops;
+
+	ret = drm_crtc_init(ddev, &sdrm->crtc, &sdrm_crtc_ops);
+	if (ret)
+		goto err_cleanup;
+
+	sdrm->enc.possible_crtcs = 1;
+	sdrm->enc.possible_clones = 0;
+	ret = drm_encoder_init(ddev, &sdrm->enc, &sdrm_enc_ops,
+			       DRM_MODE_ENCODER_VIRTUAL);
+	if (ret)
+		goto err_cleanup;
+
+	sdrm->conn.display_info.width_mm = 0;
+	sdrm->conn.display_info.height_mm = 0;
+	sdrm->conn.interlace_allowed = false;
+	sdrm->conn.doublescan_allowed = false;
+	sdrm->conn.polled = 0;
+	ret = drm_connector_init(ddev, &sdrm->conn, &sdrm_conn_ops,
+				 DRM_MODE_CONNECTOR_VIRTUAL);
+	if (ret)
+		goto err_cleanup;
+
+	ret = drm_mode_connector_attach_encoder(&sdrm->conn, &sdrm->enc);
+	if (ret)
+		goto err_cleanup;
+
+	ret = drm_sysfs_connector_add(&sdrm->conn);
+	if (ret)
+		goto err_cleanup;
+
+	return 0;
+
+err_cleanup:
+	drm_mode_config_cleanup(ddev);
+	sdrm_pdev_destroy(sdrm);
+err_name:
+	kfree(ddev->devname);
+	ddev->devname = NULL;
+err_free:
+	kfree(sdrm);
+	return ret;
+}
+
+int sdrm_drm_unload(struct drm_device *ddev)
+{
+	struct sdrm_device *sdrm = ddev->dev_private;
+
+	drm_mode_config_cleanup(ddev);
+	sdrm_pdev_destroy(sdrm);
+	kfree(sdrm);
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/simpledrm/simpledrm_mem.c b/drivers/gpu/drm/simpledrm/simpledrm_mem.c
new file mode 100644
index 0000000..1bcd3f1
--- /dev/null
+++ b/drivers/gpu/drm/simpledrm/simpledrm_mem.c
@@ -0,0 +1,242 @@
+/*
+ * SimpleDRM firmware framebuffer driver
+ * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <drm/drmP.h>
+#include "simpledrm.h"
+
+/*
+ * Create GEM Object
+ * Allocates a new GEM object to manage the physical memory at @fb_base with
+ * size @fb_size. Both parameters must be page-aligned and point to the
+ * physical memory of the framebuffer to manage. They must not have a
+ * "struct page" and have to be reserved before.
+ * It is the callers responsibility to create only one object per framebuffer.
+ */
+static struct sdrm_gem_object *sdrm_gem_alloc_object(struct drm_device *ddev,
+						     unsigned long fb_base,
+						     unsigned long fb_size)
+{
+	struct sdrm_gem_object *obj;
+
+	WARN_ON((fb_base & ~PAGE_MASK) != 0);
+	WARN_ON((fb_size & ~PAGE_MASK) != 0);
+
+	/* align to page-size */
+	fb_size = fb_size + (fb_base & ~PAGE_MASK);
+	fb_base = fb_base & PAGE_MASK;
+	fb_size = PAGE_ALIGN(fb_size);
+
+	if (fb_base + fb_size < fb_base)
+		return NULL;
+
+	obj = kzalloc(sizeof(*obj), GFP_KERNEL);
+	if (!obj)
+		return NULL;
+	obj->fb_base = fb_base;
+	obj->fb_size = fb_size;
+
+	drm_gem_private_object_init(ddev, &obj->base, fb_size);
+
+	return obj;
+}
+
+/* drm_gem_object_alloc() is not supported */
+int sdrm_gem_init_object(struct drm_gem_object *gobj)
+{
+	return -EINVAL;
+}
+
+/*
+ * Unmap GEM Object
+ * Destroy any memory-mappings that user-space created on this object. Note
+ * that this will cause SIGBUS errors if user-space continues writing to it.
+ * There is no way to remap the pages in fault-handlers as this is not what
+ * we want. You should destroy the mappings only when destroying the object
+ * so no remapping will be needed.
+ * It's the callers responsibility to prevent any further mappings. This only
+ * destroys all current mappings.
+ */
+void sdrm_gem_unmap_object(struct sdrm_gem_object *obj)
+{
+	struct drm_device *ddev = obj->base.dev;
+
+	drm_vma_node_unmap(&obj->base.vma_node, ddev->dev_mapping);
+}
+
+/*
+ * Free GEM Object
+ * Frees the given GEM object. It does not release the framebuffer memory that
+ * was passed during allocation, but destroys all user-space mappings.
+ */
+void sdrm_gem_free_object(struct drm_gem_object *gobj)
+{
+	struct sdrm_gem_object *obj = to_sdrm_bo(gobj);
+	struct drm_device *ddev = gobj->dev;
+	struct sdrm_device *sdrm = ddev->dev_private;
+
+	if (sdrm->fb_obj == obj)
+		sdrm->fb_obj = NULL;
+
+	sdrm_gem_unmap_object(obj);
+
+	drm_gem_free_mmap_offset(gobj);
+	drm_gem_object_release(gobj);
+	kfree(obj);
+}
+
+/*
+ * Create Dumb Buffer
+ * IOCTL backend for dumb-buffers. We only support one framebuffer per
+ * simple-DRM device so this function fails if there is already a framebuffer
+ * allocated. If not, an initial GEM-object plus framebuffer is created and
+ * forwarded to the caller.
+ *
+ * We could try to kill off the previous framebuffer and create a new one for
+ * the caller. However, user-space often allocates two buffers in a row to
+ * allow double-buffering. If we kill the previous buffer, user-space would
+ * have no chance to notice that only one buffer is available.
+ *
+ * So user-space must make sure they either destroy their buffer when dropping
+ * DRM-Master or leave the CRTC intact and let others share the buffer via
+ * drmModeGetFB().
+ *
+ * The buffer parameters must be the same as from the default-mode of the CRTC.
+ * No other sizes can be supported!
+ */
+int sdrm_dumb_create(struct drm_file *dfile, struct drm_device *ddev,
+		     struct drm_mode_create_dumb *args)
+{
+	struct drm_device *dev = dfile->minor->dev;
+	struct sdrm_device *sdrm = dev->dev_private;
+	struct sdrm_gem_object *obj;
+	int ret;
+
+	/* only allow one framebuffer at a time */
+	if (sdrm->fb_obj)
+		return -ENOMEM;
+
+	if (args->width != sdrm->fb_width ||
+	    args->height != sdrm->fb_height ||
+	    args->bpp != sdrm->fb_bpp ||
+	    args->flags)
+		return -EINVAL;
+
+	args->pitch = sdrm->fb_stride;
+	args->size = sdrm->fb_size;
+	obj = sdrm_gem_alloc_object(ddev, sdrm->fb_base, sdrm->fb_size);
+	if (!obj)
+		return -ENOMEM;
+
+	ret = drm_gem_handle_create(dfile, &obj->base, &args->handle);
+	if (ret) {
+		drm_gem_object_unreference(&obj->base);
+		return ret;
+	}
+
+	/* fb_obj is cleared by sdrm_gem_free_object() */
+	sdrm->fb_obj = obj;
+	drm_gem_object_unreference(&obj->base);
+
+	return 0;
+}
+
+int sdrm_dumb_destroy(struct drm_file *dfile, struct drm_device *ddev,
+		      uint32_t handle)
+{
+	return drm_gem_handle_delete(dfile, handle);
+}
+
+int sdrm_dumb_map_offset(struct drm_file *dfile, struct drm_device *ddev,
+			 uint32_t handle, uint64_t *offset)
+{
+	struct drm_gem_object *gobj;
+	int ret;
+
+	mutex_lock(&ddev->struct_mutex);
+
+	gobj = drm_gem_object_lookup(ddev, dfile, handle);
+	if (!gobj) {
+		ret = -ENOENT;
+		goto out_unlock;
+	}
+
+	ret = drm_gem_create_mmap_offset(gobj);
+	if (ret)
+		goto out_unref;
+
+	*offset = drm_vma_node_offset_addr(&gobj->vma_node);
+
+out_unref:
+	drm_gem_object_unreference(gobj);
+out_unlock:
+	mutex_unlock(&ddev->struct_mutex);
+	return ret;
+}
+
+/*
+ * mmap ioctl
+ * We simply map the physical range of the FB into user-space as requested. We
+ * perform few sanity-checks and then let io_remap_pfn_range() do all the work.
+ * No vma_ops are needed this way as pages are either cleared or present.
+ */
+int sdrm_drm_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct drm_file *priv = filp->private_data;
+	struct drm_device *dev = priv->minor->dev;
+	struct drm_gem_mm *mm = dev->mm_private;
+	struct drm_vma_offset_node *node;
+	struct drm_gem_object *gobj;
+	struct sdrm_gem_object *obj;
+	int ret;
+
+	if (drm_device_is_unplugged(dev))
+		return -ENODEV;
+
+	mutex_lock(&dev->struct_mutex);
+
+	node = drm_vma_offset_exact_lookup(&mm->vma_manager, vma->vm_pgoff,
+					   vma_pages(vma));
+	if (!node) {
+		mutex_unlock(&dev->struct_mutex);
+		return drm_mmap(filp, vma);
+	} else if (!drm_vma_node_is_allowed(node, filp)) {
+		mutex_unlock(&dev->struct_mutex);
+		return -EACCES;
+	}
+
+	/* verify mapping size */
+	if (vma_pages(vma) > drm_vma_node_size(node)) {
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
+	gobj = container_of(node, struct drm_gem_object, vma_node);
+	obj = to_sdrm_bo(gobj);
+
+	vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+	/* FIXME: do we need fb_pgprotect() here? */
+
+	/* This object is _not_ referenced here. Therefore, we _must_ destroy
+	 * the mapping before destroying the bo! We do this in
+	 * sdrm_gem_free_object(). */
+
+	ret = io_remap_pfn_range(vma, vma->vm_start, obj->fb_base >> PAGE_SHIFT,
+				 obj->fb_size, vma->vm_page_prot);
+
+out_unlock:
+	mutex_unlock(&dev->struct_mutex);
+	return ret;
+}
-- 
1.8.4

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

* [PATCH v4 2/6] drm: simpledrm: add fbdev fallback support
  2013-09-01 13:36 [PATCH v4 0/6] SimpleDRM Driver David Herrmann
  2013-09-01 13:36 ` [PATCH v4 1/6] drm: add SimpleDRM driver David Herrmann
@ 2013-09-01 13:36 ` David Herrmann
  2013-09-01 13:36 ` [PATCH v4 3/6] drm: add helpers to kick out firmware drivers David Herrmann
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: David Herrmann @ 2013-09-01 13:36 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>
Tested-by: Stephen Warren <swarren@nvidia.com>
---
 drivers/gpu/drm/simpledrm/Kconfig           |  11 ++
 drivers/gpu/drm/simpledrm/Makefile          |   1 +
 drivers/gpu/drm/simpledrm/simpledrm.h       |  22 ++++
 drivers/gpu/drm/simpledrm/simpledrm_fbdev.c | 153 ++++++++++++++++++++++++++++
 drivers/gpu/drm/simpledrm/simpledrm_main.c  |   2 +
 5 files changed, 189 insertions(+)
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_fbdev.c

diff --git a/drivers/gpu/drm/simpledrm/Kconfig b/drivers/gpu/drm/simpledrm/Kconfig
index 35bcce8..eef2a36 100644
--- a/drivers/gpu/drm/simpledrm/Kconfig
+++ b/drivers/gpu/drm/simpledrm/Kconfig
@@ -12,7 +12,18 @@ config DRM_SIMPLEDRM
 	  SimpleDRM supports "simple-framebuffer" DeviceTree objects and
 	  compatible platform framebuffers.
 
+	  If fbdev support is enabled, this driver will also provide an fbdev
+	  compatibility layer.
+
 	  If unsure, say Y.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called simpledrm.
+
+config DRM_SIMPLEDRM_FBDEV
+	bool
+	depends on DRM_SIMPLEDRM && FB
+	default y
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
diff --git a/drivers/gpu/drm/simpledrm/Makefile b/drivers/gpu/drm/simpledrm/Makefile
index ceb97eb..2144787 100644
--- a/drivers/gpu/drm/simpledrm/Makefile
+++ b/drivers/gpu/drm/simpledrm/Makefile
@@ -1,3 +1,4 @@
 simpledrm-y := simpledrm_drv.o simpledrm_main.o simpledrm_mem.o
+simpledrm-$(CONFIG_DRM_SIMPLEDRM_FBDEV) += simpledrm_fbdev.o
 
 obj-$(CONFIG_DRM_SIMPLEDRM) := simpledrm.o
diff --git a/drivers/gpu/drm/simpledrm/simpledrm.h b/drivers/gpu/drm/simpledrm/simpledrm.h
index 977b344..b854981 100644
--- a/drivers/gpu/drm/simpledrm/simpledrm.h
+++ b/drivers/gpu/drm/simpledrm/simpledrm.h
@@ -46,6 +46,9 @@ struct sdrm_device {
 	struct drm_encoder enc;
 	struct drm_connector conn;
 	struct drm_display_mode *mode;
+
+	/* fbdev */
+	struct fb_info *fbdev;
 };
 
 int sdrm_drm_load(struct drm_device *ddev, unsigned long flags);
@@ -86,4 +89,23 @@ struct sdrm_framebuffer {
 
 #define to_sdrm_fb(x) container_of(x, struct sdrm_framebuffer, base)
 
+/* simpledrm fbdev helpers */
+
+#ifdef CONFIG_DRM_SIMPLEDRM_FBDEV
+
+void sdrm_fbdev_init(struct sdrm_device *sdrm);
+void sdrm_fbdev_cleanup(struct sdrm_device *sdrm);
+
+#else /* CONFIG_DRM_SIMPLEDRM_FBDEV */
+
+static inline void sdrm_fbdev_init(struct sdrm_device *sdrm)
+{
+}
+
+static inline void sdrm_fbdev_cleanup(struct sdrm_device *sdrm)
+{
+}
+
+#endif /* CONFIG_DRM_SIMPLEDRM_FBDEV */
+
 #endif /* SDRM_DRV_H */
diff --git a/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c b/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c
new file mode 100644
index 0000000..7e2e4a2
--- /dev/null
+++ b/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c
@@ -0,0 +1,153 @@
+/*
+ * SimpleDRM firmware framebuffer driver
+ * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+/*
+ * fbdev compatibility layer
+ * We provide a basic fbdev device for the same framebuffer that is used for
+ * the pseudo CRTC.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include "simpledrm.h"
+
+struct sdrm_fbdev {
+	u32 palette[16];
+};
+
+static int sdrm_fbdev_setcolreg(u_int regno, u_int red, u_int green,
+				u_int blue, u_int transp, struct fb_info *info)
+{
+	u32 *pal = info->pseudo_palette;
+	u32 cr = red >> (16 - info->var.red.length);
+	u32 cg = green >> (16 - info->var.green.length);
+	u32 cb = blue >> (16 - info->var.blue.length);
+	u32 value;
+
+	if (regno >= 16)
+		return -EINVAL;
+
+	value = (cr << info->var.red.offset) |
+		(cg << info->var.green.offset) |
+		(cb << info->var.blue.offset);
+
+	if (info->var.transp.length > 0) {
+		u32 mask = (1 << info->var.transp.length) - 1;
+		mask <<= info->var.transp.offset;
+		value |= mask;
+	}
+
+	pal[regno] = value;
+
+	return 0;
+}
+
+static struct fb_ops sdrm_fbdev_ops = {
+	.owner		= THIS_MODULE,
+	.fb_setcolreg	= sdrm_fbdev_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+};
+
+void sdrm_fbdev_init(struct sdrm_device *sdrm)
+{
+	struct sdrm_fbdev *fb;
+	struct fb_info *info;
+	int ret;
+
+	if (fb_get_options("simpledrmfb", NULL))
+		return;
+
+	info = framebuffer_alloc(sizeof(struct sdrm_fbdev), sdrm->ddev->dev);
+	if (!info)
+		goto err_out;
+
+	fb = info->par;
+	info->flags = FBINFO_DEFAULT | FBINFO_MISC_FIRMWARE;
+	info->pseudo_palette = fb->palette;
+	info->fbops = &sdrm_fbdev_ops;
+	info->screen_base = sdrm->fb_map;
+
+	strncpy(info->fix.id, "simpledrmfb", 15);
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.visual = FB_VISUAL_TRUECOLOR;
+	info->fix.accel = FB_ACCEL_NONE;
+	info->fix.smem_start = (unsigned long)sdrm->fb_base;
+	info->fix.smem_len = sdrm->fb_size;
+	info->fix.line_length = sdrm->fb_stride;
+
+	info->var.activate = FB_ACTIVATE_NOW;
+	info->var.vmode = FB_VMODE_NONINTERLACED;
+	info->var.bits_per_pixel = sdrm->fb_bpp;
+	info->var.height = -1;
+	info->var.width = -1;
+	info->var.xres = sdrm->fb_width;
+	info->var.yres = sdrm->fb_height;
+	info->var.xres_virtual = info->var.xres;
+	info->var.yres_virtual = info->var.yres;
+	info->var.red = sdrm->fb_sformat->red;
+	info->var.green = sdrm->fb_sformat->green;
+	info->var.blue = sdrm->fb_sformat->blue;
+	info->var.transp = sdrm->fb_sformat->transp;
+
+	/* some dummy values for timing to make fbset happy */
+	info->var.pixclock = 10000000 / info->var.xres * 1000 / info->var.yres;
+	info->var.left_margin = (info->var.xres / 8) & 0xf8;
+	info->var.right_margin = 32;
+	info->var.upper_margin = 16;
+	info->var.lower_margin = 4;
+	info->var.hsync_len = (info->var.xres / 8) & 0xf8;
+	info->var.vsync_len = 4;
+
+	info->apertures = alloc_apertures(1);
+	if (!info->apertures)
+		goto err_free;
+
+	info->apertures->ranges[0].base = (unsigned long)sdrm->fb_base;
+	info->apertures->ranges[0].size = sdrm->fb_size;
+
+	sdrm->fbdev = info;
+	ret = register_framebuffer(info);
+	if (ret < 0)
+		goto err_free;
+
+	dev_info(sdrm->ddev->dev, "fbdev frontend %s as fb%d\n",
+		 info->fix.id, info->node);
+
+	return;
+
+err_free:
+	framebuffer_release(info);
+	sdrm->fbdev = NULL;
+err_out:
+	dev_warn(sdrm->ddev->dev, "cannot create fbdev frontend\n");
+}
+
+void sdrm_fbdev_cleanup(struct sdrm_device *sdrm)
+{
+	struct fb_info *info;
+
+	if (!sdrm->fbdev)
+		return;
+
+	dev_info(sdrm->ddev->dev, "fbdev cleanup\n");
+	info = sdrm->fbdev;
+	sdrm->fbdev = NULL;
+
+	if (unregister_framebuffer(info))
+		dev_warn(sdrm->ddev->dev, "unregister_framebuffer() failed, leaking fbdev device\n");
+	else
+		framebuffer_release(info);
+}
diff --git a/drivers/gpu/drm/simpledrm/simpledrm_main.c b/drivers/gpu/drm/simpledrm/simpledrm_main.c
index ae507e3..497542d 100644
--- a/drivers/gpu/drm/simpledrm/simpledrm_main.c
+++ b/drivers/gpu/drm/simpledrm/simpledrm_main.c
@@ -303,6 +303,7 @@ int sdrm_drm_load(struct drm_device *ddev, unsigned long flags)
 	if (ret)
 		goto err_cleanup;
 
+	sdrm_fbdev_init(sdrm);
 	return 0;
 
 err_cleanup:
@@ -320,6 +321,7 @@ int sdrm_drm_unload(struct drm_device *ddev)
 {
 	struct sdrm_device *sdrm = ddev->dev_private;
 
+	sdrm_fbdev_cleanup(sdrm);
 	drm_mode_config_cleanup(ddev);
 	sdrm_pdev_destroy(sdrm);
 	kfree(sdrm);
-- 
1.8.4

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

* [PATCH v4 3/6] drm: add helpers to kick out firmware drivers
  2013-09-01 13:36 [PATCH v4 0/6] SimpleDRM Driver David Herrmann
  2013-09-01 13:36 ` [PATCH v4 1/6] drm: add SimpleDRM driver David Herrmann
  2013-09-01 13:36 ` [PATCH v4 2/6] drm: simpledrm: add fbdev fallback support David Herrmann
@ 2013-09-01 13:36 ` David Herrmann
  2013-09-01 13:36 ` [PATCH v4 4/6] drm: nouveau: kick out firmware drivers during probe David Herrmann
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: David Herrmann @ 2013-09-01 13:36 UTC (permalink / raw)
  To: dri-devel

If we load a real hardware DRM driver, we want all firmware drivers to be
unloaded. Historically, this was done via
remove_conflicting_framebuffers(), but for DRM drivers (like SimpleDRM) we
need a new way.

This patch introduces DRIVER_FIRMWARE and DRM apertures to provide a quite
similar way to kick out firmware DRM drivers. Additionally, unlike the
fbdev equivalent, DRM firmware drivers can now query the system whether a
real hardware driver is already loaded and prevent loading themselves.

Whenever a real hardware DRM driver is loaded which claims to provide the
boot fw FB, we invalidate the firmware framebuffer. Otherwise, simpledrm
could be loaded again, after a real hw-driver was unloaded (which is
very unlikely to work, except if hw-drivers reset fw FBs during unload).
Note that fbdev doesn't provide such protection against late driver
probing.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Tested-by: Stephen Warren <swarren@nvidia.com>
---
 drivers/gpu/drm/drm_pci.c                  |   1 +
 drivers/gpu/drm/drm_platform.c             |   1 +
 drivers/gpu/drm/drm_stub.c                 | 118 +++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_usb.c                  |   1 +
 drivers/gpu/drm/simpledrm/simpledrm.h      |   1 +
 drivers/gpu/drm/simpledrm/simpledrm_drv.c  |   3 +-
 drivers/gpu/drm/simpledrm/simpledrm_main.c |  33 ++++++++
 include/drm/drmP.h                         |  26 +++++++
 8 files changed, 183 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c
index 1f96cee..f3de4d6 100644
--- a/drivers/gpu/drm/drm_pci.c
+++ b/drivers/gpu/drm/drm_pci.c
@@ -378,6 +378,7 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
 	}
 
 	list_add_tail(&dev->driver_item, &driver->device_list);
+	list_add_tail(&dev->global_item, &drm_devlist);
 
 	DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n",
 		 driver->name, driver->major, driver->minor, driver->patchlevel,
diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c
index f7a18c6..a287429 100644
--- a/drivers/gpu/drm/drm_platform.c
+++ b/drivers/gpu/drm/drm_platform.c
@@ -94,6 +94,7 @@ static int drm_get_platform_dev(struct platform_device *platdev,
 	}
 
 	list_add_tail(&dev->driver_item, &driver->device_list);
+	list_add_tail(&dev->global_item, &drm_devlist);
 
 	mutex_unlock(&drm_global_mutex);
 
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c
index e7eb027..363e47b 100644
--- a/drivers/gpu/drm/drm_stub.c
+++ b/drivers/gpu/drm/drm_stub.c
@@ -49,6 +49,10 @@ EXPORT_SYMBOL(drm_vblank_offdelay);
 unsigned int drm_timestamp_precision = 20;  /* Default to 20 usecs. */
 EXPORT_SYMBOL(drm_timestamp_precision);
 
+static bool drm_fw_invalid;	/* true if fw FBs have been destroyed */
+LIST_HEAD(drm_devlist);		/* device list; protected by global lock */
+EXPORT_SYMBOL(drm_devlist);
+
 /*
  * Default to use monotonic timestamps for wait-for-vblank and page-flip
  * complete events.
@@ -459,7 +463,9 @@ void drm_put_dev(struct drm_device *dev)
 
 	drm_put_minor(&dev->primary);
 
+	list_del(&dev->global_item);
 	list_del(&dev->driver_item);
+	kfree(dev->apertures);
 	kfree(dev->devname);
 	kfree(dev);
 }
@@ -484,3 +490,115 @@ void drm_unplug_dev(struct drm_device *dev)
 	mutex_unlock(&drm_global_mutex);
 }
 EXPORT_SYMBOL(drm_unplug_dev);
+
+void drm_unplug_dev_locked(struct drm_device *dev)
+{
+	/* for a USB device */
+	if (drm_core_check_feature(dev, DRIVER_MODESET))
+		drm_unplug_minor(dev->control);
+	drm_unplug_minor(dev->primary);
+
+	drm_device_set_unplugged(dev);
+
+	/* TODO: schedule drm_put_dev if open_count == 0 */
+}
+EXPORT_SYMBOL(drm_unplug_dev_locked);
+
+#define VGA_FB_PHYS 0xa0000
+
+static bool apertures_overlap(struct drm_device *dev,
+			      struct apertures_struct *ap,
+			      bool boot)
+{
+	unsigned int i, j;
+	struct aperture *a, *b;
+
+	if (!dev->apertures)
+		return false;
+
+	for (i = 0; i < dev->apertures->count; ++i) {
+		a = &dev->apertures->ranges[i];
+
+		if (boot && a->base == VGA_FB_PHYS)
+			return true;
+
+		for (j = 0; ap && j < ap->count; ++j) {
+			b = &ap->ranges[j];
+			if (a->base <= b->base && a->base + a->size > b->base)
+				return true;
+			if (b->base <= a->base && b->base + b->size > a->base)
+				return true;
+		}
+	}
+
+	return false;
+}
+
+/**
+ * Kick out firmware
+ *
+ * Virtually unplug any firmware graphics devices which overlap the given
+ * region. This must be called with the global-drm-mutex locked.
+ * This calls the kick_out_firmware() callback on any firmware DRM driver and
+ * after that remove_conflicting_framebuffers() to remove legacy fbdev
+ * framebuffers.
+ */
+void drm_kick_out_firmware(struct apertures_struct *ap, bool boot)
+{
+	struct drm_device *dev;
+
+	if (boot)
+		drm_fw_invalid = true;
+
+	list_for_each_entry(dev, &drm_devlist, global_item) {
+		if (!drm_core_check_feature(dev, DRIVER_FIRMWARE))
+			continue;
+		if (apertures_overlap(dev, ap, boot)) {
+			DRM_INFO("kicking out firmware %s\n",
+				 dev->devname);
+			dev->driver->kick_out_firmware(dev);
+		}
+	}
+
+#ifdef CONFIG_FB
+	remove_conflicting_framebuffers(ap, "DRM", boot);
+#endif
+}
+EXPORT_SYMBOL(drm_kick_out_firmware);
+
+/**
+ * Verify that no driver uses firmware FBs
+ *
+ * Whenever you register a firmware framebuffer driver, you should store the
+ * apertures in @ap and test whether any other registered driver already
+ * claimed this area. Hence, if this function returns true, you should _not_
+ * register your driver!
+ */
+bool drm_is_firmware_used(struct apertures_struct *ap)
+{
+	struct drm_device *dev;
+	unsigned int i;
+	bool boot = false;
+
+	/* If a real DRM driver was loaded once, we cannot assume that the
+	 * firmware framebuffers are still valid. */
+	if (drm_fw_invalid)
+		return true;
+
+	for (i = 0; ap && i < ap->count; ++i) {
+		if (ap->ranges[i].base == VGA_FB_PHYS) {
+			boot = true;
+			break;
+		}
+	}
+
+	list_for_each_entry(dev, &drm_devlist, global_item) {
+		if (dev->apert_boot && boot)
+			return true;
+		if (apertures_overlap(dev, ap, false))
+			return true;
+	}
+
+	return false;
+}
+EXPORT_SYMBOL(drm_is_firmware_used);
diff --git a/drivers/gpu/drm/drm_usb.c b/drivers/gpu/drm/drm_usb.c
index 8766472..b672cf2 100644
--- a/drivers/gpu/drm/drm_usb.c
+++ b/drivers/gpu/drm/drm_usb.c
@@ -56,6 +56,7 @@ int drm_get_usb_dev(struct usb_interface *interface,
 		goto err_g3;
 
 	list_add_tail(&dev->driver_item, &driver->device_list);
+	list_add_tail(&dev->global_item, &drm_devlist);
 
 	mutex_unlock(&drm_global_mutex);
 
diff --git a/drivers/gpu/drm/simpledrm/simpledrm.h b/drivers/gpu/drm/simpledrm/simpledrm.h
index b854981..c093ad5 100644
--- a/drivers/gpu/drm/simpledrm/simpledrm.h
+++ b/drivers/gpu/drm/simpledrm/simpledrm.h
@@ -53,6 +53,7 @@ struct sdrm_device {
 
 int sdrm_drm_load(struct drm_device *ddev, unsigned long flags);
 int sdrm_drm_unload(struct drm_device *ddev);
+void sdrm_drm_kick_out_firmware(struct drm_device *ddev);
 int sdrm_drm_mmap(struct file *filp, struct vm_area_struct *vma);
 int sdrm_pdev_init(struct sdrm_device *sdrm);
 void sdrm_pdev_destroy(struct sdrm_device *sdrm);
diff --git a/drivers/gpu/drm/simpledrm/simpledrm_drv.c b/drivers/gpu/drm/simpledrm/simpledrm_drv.c
index 8a34051..aea702c 100644
--- a/drivers/gpu/drm/simpledrm/simpledrm_drv.c
+++ b/drivers/gpu/drm/simpledrm/simpledrm_drv.c
@@ -33,9 +33,10 @@ static const struct file_operations sdrm_drm_fops = {
 };
 
 static struct drm_driver sdrm_drm_driver = {
-	.driver_features = DRIVER_MODESET | DRIVER_GEM,
+	.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_FIRMWARE,
 	.load = sdrm_drm_load,
 	.unload = sdrm_drm_unload,
+	.kick_out_firmware = sdrm_drm_kick_out_firmware,
 	.fops = &sdrm_drm_fops,
 
 	.gem_init_object = sdrm_gem_init_object,
diff --git a/drivers/gpu/drm/simpledrm/simpledrm_main.c b/drivers/gpu/drm/simpledrm/simpledrm_main.c
index 497542d..38571c2 100644
--- a/drivers/gpu/drm/simpledrm/simpledrm_main.c
+++ b/drivers/gpu/drm/simpledrm/simpledrm_main.c
@@ -267,6 +267,21 @@ int sdrm_drm_load(struct drm_device *ddev, unsigned long flags)
 	if (ret)
 		goto err_name;
 
+	ddev->apertures = alloc_apertures(1);
+	if (!ddev->apertures) {
+		ret = -ENOMEM;
+		goto err_pdev;
+	}
+
+	ddev->apertures->ranges[0].base = sdrm->fb_base;
+	ddev->apertures->ranges[0].size = sdrm->fb_size;
+
+	if (drm_is_firmware_used(ddev->apertures)) {
+		dev_info(ddev->dev, "firmware framebuffer is already in use\n");
+		ret = -EBUSY;
+		goto err_apert;
+	}
+
 	drm_mode_config_init(ddev);
 	ddev->mode_config.min_width = 0;
 	ddev->mode_config.min_height = 0;
@@ -308,6 +323,9 @@ int sdrm_drm_load(struct drm_device *ddev, unsigned long flags)
 
 err_cleanup:
 	drm_mode_config_cleanup(ddev);
+err_apert:
+	kfree(ddev->apertures);
+err_pdev:
 	sdrm_pdev_destroy(sdrm);
 err_name:
 	kfree(ddev->devname);
@@ -328,3 +346,18 @@ int sdrm_drm_unload(struct drm_device *ddev)
 
 	return 0;
 }
+
+void sdrm_drm_kick_out_firmware(struct drm_device *ddev)
+{
+	struct sdrm_device *sdrm = ddev->dev_private;
+
+	mutex_lock(&ddev->struct_mutex);
+
+	sdrm_fbdev_cleanup(sdrm);
+	drm_unplug_dev_locked(ddev);
+	if (sdrm->fb_obj)
+		sdrm_gem_unmap_object(sdrm->fb_obj);
+	sdrm_pdev_destroy(sdrm);
+
+	mutex_unlock(&ddev->struct_mutex);
+}
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 2907341..d197033 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -46,6 +46,7 @@
 #include <linux/miscdevice.h>
 #include <linux/fs.h>
 #include <linux/init.h>
+#include <linux/fb.h>
 #include <linux/file.h>
 #include <linux/platform_device.h>
 #include <linux/pci.h>
@@ -146,6 +147,7 @@ int drm_err(const char *func, const char *format, ...);
 #define DRIVER_MODESET     0x2000
 #define DRIVER_PRIME       0x4000
 #define DRIVER_RENDER      0x8000
+#define DRIVER_FIRMWARE    0x10000
 
 #define DRIVER_BUS_PCI 0x1
 #define DRIVER_BUS_PLATFORM 0x2
@@ -966,6 +968,23 @@ struct drm_driver {
 			    struct drm_device *dev,
 			    uint32_t handle);
 
+	/**
+	 * kick_out_firmware - kick out firmware driver
+	 * @dev: DRM device
+	 *
+	 * Iff this driver has DRIVER_FIRMWARE set, this function is called
+	 * when a real hw-driver is loaded and claims the framebuffer memory
+	 * that is mapped by the firmware driver. This is called with the
+	 * global drm mutex held.
+	 * Drivers should unmap any memory-mappings, disable the device and
+	 * schedule a driver removal.
+	 *
+	 * Note that a driver setting DRIVER_FIRMWARE is supposed to also set
+	 * the "apertures" information on @dev. It is used to match the memory
+	 * regions that are used by firmware drivers.
+	 */
+	void (*kick_out_firmware) (struct drm_device *dev);
+
 	/* Driver private ops for this object */
 	const struct vm_operations_struct *gem_vm_ops;
 
@@ -1087,6 +1106,7 @@ struct drm_pending_vblank_event {
  */
 struct drm_device {
 	struct list_head driver_item;	/**< list of devices per driver */
+	struct list_head global_item;	/**< global list of devices */
 	char *devname;			/**< For /proc/interrupts */
 	int if_version;			/**< Highest interface version set */
 
@@ -1218,6 +1238,8 @@ struct drm_device {
 	int switch_power_state;
 
 	atomic_t unplugged; /* device has been unplugged or gone away */
+	struct apertures_struct *apertures;	/**< fbmem apertures */
+	bool apert_boot;			/**< true if mapped as boot fb */
 };
 
 #define DRM_SWITCH_POWER_ON 0
@@ -1457,6 +1479,10 @@ extern void drm_master_put(struct drm_master **master);
 extern void drm_put_dev(struct drm_device *dev);
 extern int drm_put_minor(struct drm_minor **minor);
 extern void drm_unplug_dev(struct drm_device *dev);
+extern void drm_unplug_dev_locked(struct drm_device *dev);
+extern void drm_kick_out_firmware(struct apertures_struct *ap, bool boot);
+extern bool drm_is_firmware_used(struct apertures_struct *ap);
+extern struct list_head drm_devlist;
 extern unsigned int drm_debug;
 extern unsigned int drm_rnodes;
 
-- 
1.8.4

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

* [PATCH v4 4/6] drm: nouveau: kick out firmware drivers during probe
  2013-09-01 13:36 [PATCH v4 0/6] SimpleDRM Driver David Herrmann
                   ` (2 preceding siblings ...)
  2013-09-01 13:36 ` [PATCH v4 3/6] drm: add helpers to kick out firmware drivers David Herrmann
@ 2013-09-01 13:36 ` David Herrmann
  2013-09-01 13:36 ` [PATCH v4 5/6] drm/i915: use new drm_kick_out_firmware() David Herrmann
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: David Herrmann @ 2013-09-01 13:36 UTC (permalink / raw)
  To: dri-devel; +Cc: Ben Skeggs

Use the new DRM infrastructure to kick out firmware drivers before probing
the real driver.

Cc: Maarten Lankhorst <maarten.lankhorst@canonical.com>
Cc: Ben Skeggs <bskeggs@redhat.com>
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/gpu/drm/nouveau/nouveau_drm.c | 29 ++++++++++++++++++++++-------
 1 file changed, 22 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 62c6118..452cc21 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -252,13 +252,11 @@ nouveau_accel_init(struct nouveau_drm *drm)
 	nouveau_bo_move_init(drm);
 }
 
-static int nouveau_drm_probe(struct pci_dev *pdev,
-			     const struct pci_device_id *pent)
+static int nouveau_kick_out_firmware(struct drm_device *dev)
 {
-	struct nouveau_device *device;
 	struct apertures_struct *aper;
 	bool boot = false;
-	int ret;
+	struct pci_dev *pdev = dev->pdev;
 
 	/* remove conflicting drivers (vesafb, efifb etc) */
 	aper = alloc_apertures(3);
@@ -284,8 +282,18 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
 #ifdef CONFIG_X86
 	boot = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
 #endif
-	remove_conflicting_framebuffers(aper, "nouveaufb", boot);
-	kfree(aper);
+
+	drm_kick_out_firmware(aper, boot);
+	dev->apertures = aper;
+	dev->apert_boot = boot;
+	return 0;
+}
+
+static int nouveau_drm_probe(struct pci_dev *pdev,
+			     const struct pci_device_id *pent)
+{
+	struct nouveau_device *device;
+	int ret;
 
 	ret = nouveau_device_create(pdev, nouveau_name(pdev), pci_name(pdev),
 				    nouveau_config, nouveau_debug, &device);
@@ -336,10 +344,14 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
 	struct nouveau_drm *drm;
 	int ret;
 
-	ret = nouveau_cli_create(pdev, "DRM", sizeof(*drm), (void**)&drm);
+	ret = nouveau_kick_out_firmware(dev);
 	if (ret)
 		return ret;
 
+	ret = nouveau_cli_create(pdev, "DRM", sizeof(*drm), (void**)&drm);
+	if (ret)
+		goto fail_apert;
+
 	dev->dev_private = drm;
 	drm->dev = dev;
 
@@ -444,6 +456,9 @@ fail_ttm:
 	nouveau_vga_fini(drm);
 fail_device:
 	nouveau_cli_destroy(&drm->client);
+fail_apert:
+	kfree(dev->apertures);
+	dev->apertures = NULL;
 	return ret;
 }
 
-- 
1.8.4

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

* [PATCH v4 5/6] drm/i915: use new drm_kick_out_firmware()
  2013-09-01 13:36 [PATCH v4 0/6] SimpleDRM Driver David Herrmann
                   ` (3 preceding siblings ...)
  2013-09-01 13:36 ` [PATCH v4 4/6] drm: nouveau: kick out firmware drivers during probe David Herrmann
@ 2013-09-01 13:36 ` David Herrmann
  2013-09-02  7:43   ` Daniel Vetter
  2013-09-01 13:36 ` [PATCH v4 6/6] drm/radeon: " David Herrmann
  2013-09-04 17:34 ` [PATCH v4 0/6] SimpleDRM Driver David Herrmann
  6 siblings, 1 reply; 15+ messages in thread
From: David Herrmann @ 2013-09-01 13:36 UTC (permalink / raw)
  To: dri-devel; +Cc: Daniel Vetter

Use the new DRM infrastructure to kick out firmware DRM drivers before
loading i915.

Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/gpu/drm/i915/i915_dma.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 3e4e607..9d375a6 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1414,9 +1414,9 @@ static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv)
 	primary =
 		pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
 
-	remove_conflicting_framebuffers(ap, "inteldrmfb", primary);
-
-	kfree(ap);
+	drm_kick_out_firmware(ap, primary);
+	dev_priv->dev->apertures = ap;
+	dev_priv->dev->apert_boot = primary;
 }
 
 static void i915_dump_device_info(struct drm_i915_private *dev_priv)
-- 
1.8.4

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

* [PATCH v4 6/6] drm/radeon: use new drm_kick_out_firmware()
  2013-09-01 13:36 [PATCH v4 0/6] SimpleDRM Driver David Herrmann
                   ` (4 preceding siblings ...)
  2013-09-01 13:36 ` [PATCH v4 5/6] drm/i915: use new drm_kick_out_firmware() David Herrmann
@ 2013-09-01 13:36 ` David Herrmann
  2013-09-04 17:34 ` [PATCH v4 0/6] SimpleDRM Driver David Herrmann
  6 siblings, 0 replies; 15+ messages in thread
From: David Herrmann @ 2013-09-01 13:36 UTC (permalink / raw)
  To: dri-devel; +Cc: Alex Deucher

Kick out firmware DRM and fbdev drivers via the new
drm_kick_out_firmware() before loading radeon.

Cc: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/gpu/drm/radeon/radeon_drv.c | 28 ----------------------------
 drivers/gpu/drm/radeon/radeon_kms.c | 30 ++++++++++++++++++++++++++++++
 2 files changed, 30 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 1f93dd5..13f1e15 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -311,37 +311,9 @@ static struct drm_driver driver_old = {
 
 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)
 {
-	int ret;
-
-	/* Get rid of things like offb */
-	ret = radeon_kick_out_firmware_fb(pdev);
-	if (ret)
-		return ret;
-
 	return drm_get_pci_dev(pdev, ent, &kms_driver);
 }
 
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index b46a561..d8f2a38 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -62,6 +62,30 @@ done_free:
 	return 0;
 }
 
+static int radeon_kick_out_firmware(struct drm_device *dev)
+{
+	struct pci_dev *pdev = 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
+
+	drm_kick_out_firmware(ap, primary);
+	dev->apertures = ap;
+	dev->apert_boot = primary;
+
+	return 0;
+}
+
 /**
  * radeon_driver_load_kms - Main load function for KMS.
  *
@@ -86,6 +110,12 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags)
 	}
 	dev->dev_private = (void *)rdev;
 
+	r = radeon_kick_out_firmware(dev);
+	if (r) {
+		kfree(rdev);
+		return r;
+	}
+
 	/* update BUS flag */
 	if (drm_pci_device_is_agp(dev)) {
 		flags |= RADEON_IS_AGP;
-- 
1.8.4

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

* Re: [PATCH v4 5/6] drm/i915: use new drm_kick_out_firmware()
  2013-09-01 13:36 ` [PATCH v4 5/6] drm/i915: use new drm_kick_out_firmware() David Herrmann
@ 2013-09-02  7:43   ` Daniel Vetter
  2013-09-02 12:02     ` David Herrmann
  0 siblings, 1 reply; 15+ messages in thread
From: Daniel Vetter @ 2013-09-02  7:43 UTC (permalink / raw)
  To: David Herrmann; +Cc: Daniel Vetter, dri-devel

On Sun, Sep 01, 2013 at 03:36:51PM +0200, David Herrmann wrote:
> Use the new DRM infrastructure to kick out firmware DRM drivers before
> loading i915.
> 
> Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
> ---
>  drivers/gpu/drm/i915/i915_dma.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
> index 3e4e607..9d375a6 100644
> --- a/drivers/gpu/drm/i915/i915_dma.c
> +++ b/drivers/gpu/drm/i915/i915_dma.c
> @@ -1414,9 +1414,9 @@ static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv)
>  	primary =
>  		pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
>  
> -	remove_conflicting_framebuffers(ap, "inteldrmfb", primary);
> -
> -	kfree(ap);
> +	drm_kick_out_firmware(ap, primary);
> +	dev_priv->dev->apertures = ap;
> +	dev_priv->dev->apert_boot = primary;

What about passing dev to drm_kick_out_firmware and shovelling these two
assignments in there? I've check your nouveau/radeon patches and I think
this would work ...
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

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

* Re: [PATCH v4 5/6] drm/i915: use new drm_kick_out_firmware()
  2013-09-02  7:43   ` Daniel Vetter
@ 2013-09-02 12:02     ` David Herrmann
  2013-09-02 14:26       ` Daniel Vetter
  0 siblings, 1 reply; 15+ messages in thread
From: David Herrmann @ 2013-09-02 12:02 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Daniel Vetter, dri-devel@lists.freedesktop.org

Hi

On Mon, Sep 2, 2013 at 9:43 AM, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Sun, Sep 01, 2013 at 03:36:51PM +0200, David Herrmann wrote:
>> Use the new DRM infrastructure to kick out firmware DRM drivers before
>> loading i915.
>>
>> Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
>> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
>> ---
>>  drivers/gpu/drm/i915/i915_dma.c | 6 +++---
>>  1 file changed, 3 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
>> index 3e4e607..9d375a6 100644
>> --- a/drivers/gpu/drm/i915/i915_dma.c
>> +++ b/drivers/gpu/drm/i915/i915_dma.c
>> @@ -1414,9 +1414,9 @@ static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv)
>>       primary =
>>               pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
>>
>> -     remove_conflicting_framebuffers(ap, "inteldrmfb", primary);
>> -
>> -     kfree(ap);
>> +     drm_kick_out_firmware(ap, primary);
>> +     dev_priv->dev->apertures = ap;
>> +     dev_priv->dev->apert_boot = primary;
>
> What about passing dev to drm_kick_out_firmware and shovelling these two
> assignments in there? I've check your nouveau/radeon patches and I think
> this would work ...

Yepp, that sounds reasonable. And I guess the kfree() of apertures can
also be done in drm_put_dev(). Maybe we can even to the whole stuff in
drm_pci.c, I will have a look.

Thanks
David

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

* Re: [PATCH v4 5/6] drm/i915: use new drm_kick_out_firmware()
  2013-09-02 12:02     ` David Herrmann
@ 2013-09-02 14:26       ` Daniel Vetter
  0 siblings, 0 replies; 15+ messages in thread
From: Daniel Vetter @ 2013-09-02 14:26 UTC (permalink / raw)
  To: David Herrmann; +Cc: Daniel Vetter, dri-devel@lists.freedesktop.org

On Mon, Sep 02, 2013 at 02:02:06PM +0200, David Herrmann wrote:
> Hi
> 
> On Mon, Sep 2, 2013 at 9:43 AM, Daniel Vetter <daniel@ffwll.ch> wrote:
> > On Sun, Sep 01, 2013 at 03:36:51PM +0200, David Herrmann wrote:
> >> Use the new DRM infrastructure to kick out firmware DRM drivers before
> >> loading i915.
> >>
> >> Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> >> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
> >> ---
> >>  drivers/gpu/drm/i915/i915_dma.c | 6 +++---
> >>  1 file changed, 3 insertions(+), 3 deletions(-)
> >>
> >> diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
> >> index 3e4e607..9d375a6 100644
> >> --- a/drivers/gpu/drm/i915/i915_dma.c
> >> +++ b/drivers/gpu/drm/i915/i915_dma.c
> >> @@ -1414,9 +1414,9 @@ static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv)
> >>       primary =
> >>               pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
> >>
> >> -     remove_conflicting_framebuffers(ap, "inteldrmfb", primary);
> >> -
> >> -     kfree(ap);
> >> +     drm_kick_out_firmware(ap, primary);
> >> +     dev_priv->dev->apertures = ap;
> >> +     dev_priv->dev->apert_boot = primary;
> >
> > What about passing dev to drm_kick_out_firmware and shovelling these two
> > assignments in there? I've check your nouveau/radeon patches and I think
> > this would work ...
> 
> Yepp, that sounds reasonable. And I guess the kfree() of apertures can
> also be done in drm_put_dev(). Maybe we can even to the whole stuff in
> drm_pci.c, I will have a look.

I like the helper approach used here since it allows drivers to pick an
appropriate spot. Moving it into drm_pci.c could be a bit ugly. Aside: I'm
pondering ideas to weed out the midlayer smell from the drm device init
sequence. I've played around with a few things and it looks like we're
really close to doing the Right Thing ;-)

Cheers, Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

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

* Re: [PATCH v4 0/6] SimpleDRM Driver
  2013-09-01 13:36 [PATCH v4 0/6] SimpleDRM Driver David Herrmann
                   ` (5 preceding siblings ...)
  2013-09-01 13:36 ` [PATCH v4 6/6] drm/radeon: " David Herrmann
@ 2013-09-04 17:34 ` David Herrmann
  2013-09-08 11:33   ` Tom Gundersen
  6 siblings, 1 reply; 15+ messages in thread
From: David Herrmann @ 2013-09-04 17:34 UTC (permalink / raw)
  To: dri-devel@lists.freedesktop.org

Hi

On Sun, Sep 1, 2013 at 3:36 PM, David Herrmann <dh.herrmann@gmail.com> wrote:
> Hi
>
> With the upcoming 3.12 merge-window, I thought people might find themselves with
> nothing to do, so here's a new SimpleDRM series. Comments welcome!
>
> This depends on the tip/x86/fb series in the x86-tip tree:
>   http://git.kernel.org/cgit/linux/kernel/git/tip/tip.git/log/?h=x86/fb
> Which, as far as I understood, will be pushed into 3.12 by the x86 people.

FYI, this is now merged in Linus' tree. See:
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=228abe73ad67665d71eacd6a8a347dd76b0115ae

So hopefully we can get SimpleDRM ready for 3.13.

Cheers
David

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

* Re: [PATCH v4 0/6] SimpleDRM Driver
  2013-09-04 17:34 ` [PATCH v4 0/6] SimpleDRM Driver David Herrmann
@ 2013-09-08 11:33   ` Tom Gundersen
  2013-09-08 13:13     ` David Herrmann
  0 siblings, 1 reply; 15+ messages in thread
From: Tom Gundersen @ 2013-09-08 11:33 UTC (permalink / raw)
  To: David Herrmann; +Cc: dri-devel@lists.freedesktop.org

Hi David,

On Wed, Sep 4, 2013 at 7:34 PM, David Herrmann <dh.herrmann@gmail.com> wrote:
> Hi
>
> On Sun, Sep 1, 2013 at 3:36 PM, David Herrmann <dh.herrmann@gmail.com> wrote:
>> Hi
>>
>> With the upcoming 3.12 merge-window, I thought people might find themselves with
>> nothing to do, so here's a new SimpleDRM series. Comments welcome!
>>
>> This depends on the tip/x86/fb series in the x86-tip tree:
>>   http://git.kernel.org/cgit/linux/kernel/git/tip/tip.git/log/?h=x86/fb
>> Which, as far as I understood, will be pushed into 3.12 by the x86 people.
>
> FYI, this is now merged in Linus' tree. See:
> https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=228abe73ad67665d71eacd6a8a347dd76b0115ae
>
> So hopefully we can get SimpleDRM ready for 3.13.

Now that simplefb works for me, I finally got around to testing this.
Just a couple of comments:

 * I guess you need to add the modalias "platform:simple-framebuffer"
in addition to the "of:..." one to get module auto loading working.

 * the driver currently doesn't work with your IORESOURCE_BUSY fix to
sysfb (as might be expected(?)):
        simple-framebuffer simple-framebuffer.0: cannot reserve VMEM
        simple-framebuffer: probe of simple-framebuffer.0 failed with error -5

* except for that, fbcon on top of the fbdev fallback support works
fine for me. I didn't yet try the drm driver itself, what clients (if
any) are supposed to work with this, kmscon, weston?

Cheers,

Tom

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

* Re: [PATCH v4 0/6] SimpleDRM Driver
  2013-09-08 11:33   ` Tom Gundersen
@ 2013-09-08 13:13     ` David Herrmann
  0 siblings, 0 replies; 15+ messages in thread
From: David Herrmann @ 2013-09-08 13:13 UTC (permalink / raw)
  To: Tom Gundersen; +Cc: dri-devel@lists.freedesktop.org

Hi

On Sun, Sep 8, 2013 at 1:33 PM, Tom Gundersen <teg@jklm.no> wrote:
> Hi David,
>
> On Wed, Sep 4, 2013 at 7:34 PM, David Herrmann <dh.herrmann@gmail.com> wrote:
>> Hi
>>
>> On Sun, Sep 1, 2013 at 3:36 PM, David Herrmann <dh.herrmann@gmail.com> wrote:
>>> Hi
>>>
>>> With the upcoming 3.12 merge-window, I thought people might find themselves with
>>> nothing to do, so here's a new SimpleDRM series. Comments welcome!
>>>
>>> This depends on the tip/x86/fb series in the x86-tip tree:
>>>   http://git.kernel.org/cgit/linux/kernel/git/tip/tip.git/log/?h=x86/fb
>>> Which, as far as I understood, will be pushed into 3.12 by the x86 people.
>>
>> FYI, this is now merged in Linus' tree. See:
>> https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=228abe73ad67665d71eacd6a8a347dd76b0115ae
>>
>> So hopefully we can get SimpleDRM ready for 3.13.
>
> Now that simplefb works for me, I finally got around to testing this.
> Just a couple of comments:
>
>  * I guess you need to add the modalias "platform:simple-framebuffer"
> in addition to the "of:..." one to get module auto loading working.

Yes, sounds good.

>  * the driver currently doesn't work with your IORESOURCE_BUSY fix to
> sysfb (as might be expected(?)):
>         simple-framebuffer simple-framebuffer.0: cannot reserve VMEM
>         simple-framebuffer: probe of simple-framebuffer.0 failed with error -5

Yes, if the simple-framebuffer region is already marked BUSY,
simpleDRM must not (and doesn't have to) call __request_region() (or
request_mem_region()). I have to remove that call if the BUSY fix gets
applied.

> * except for that, fbcon on top of the fbdev fallback support works
> fine for me. I didn't yet try the drm driver itself, what clients (if
> any) are supposed to work with this, kmscon, weston?

Obviously, simpledrm doesn't support double-buffering, page-flipping
or other advanced techniques. So I currently doubt you can use any
real application on it as they all at least require 2 buffers. I
haven't decided whether to emulate these in the kernel driver or to
rely on user-space to deal with this reduced driver. It's quite likely
I will go with both. That means, a compatibility option that makes
simpledrm emulate any required techniques (multiple FBs,
page-flipping) but also user-space patches to maybe some day be able
to disable the kernel emulation.

Thanks a lot for testing all this. I will try to get the fixes into
rc2. The speed-improvements might have to wait for 3.13, though.

Cheers
David

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

* Re: [PATCH v4 1/6] drm: add SimpleDRM driver
  2013-09-01 13:36 ` [PATCH v4 1/6] drm: add SimpleDRM driver David Herrmann
@ 2013-09-21 14:18   ` Tom Gundersen
  2013-10-02 15:09     ` David Herrmann
  0 siblings, 1 reply; 15+ messages in thread
From: Tom Gundersen @ 2013-09-21 14:18 UTC (permalink / raw)
  To: David Herrmann; +Cc: dri-devel@lists.freedesktop.org

Hi David,

On Sun, Sep 1, 2013 at 3:36 PM, 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 one dumb-buffer and attach it to the CRTC. Only if
> the buffer is destroyed, a new buffer can be created. The buffer is
> directly mapped into user-space, so we have only resources for a single
> buffer. Otherwise, shadow buffers plus damage-request would be needed.
>
> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
> Tested-by: Stephen Warren <swarren@nvidia.com>
> ---

[...]

> +static int sdrm_conn_fill_modes(struct drm_connector *conn, uint32_t max_x,
> +                               uint32_t max_y)
> +{
> +       struct sdrm_device *sdrm = conn->dev->dev_private;
> +       struct drm_display_mode *mode;
> +       int ret;
> +
> +       if (conn->force == DRM_FORCE_ON)
> +               conn->status = connector_status_connected;
> +       else if (conn->force)
> +               conn->status = connector_status_disconnected;
> +       else
> +               conn->status = connector_status_connected;
> +
> +       list_for_each_entry(mode, &conn->modes, head)
> +               mode->status = MODE_UNVERIFIED;
> +
> +       mode = drm_gtf_mode(sdrm->ddev, sdrm->fb_width, sdrm->fb_height,
> +                           60, 0, 0);
> +       if (mode) {
> +               mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
> +               drm_mode_probed_add(conn, mode);
> +               sdrm->mode = mode;

Should you also be setting sdrm->fb_{width,height} to
mode->{v,h}display here? Otherwise, due to the rounding in
drm_gtf_mode(), these values won't necessarily match (which I suppose
they must?).

Cheers,

Tom

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

* Re: [PATCH v4 1/6] drm: add SimpleDRM driver
  2013-09-21 14:18   ` Tom Gundersen
@ 2013-10-02 15:09     ` David Herrmann
  0 siblings, 0 replies; 15+ messages in thread
From: David Herrmann @ 2013-10-02 15:09 UTC (permalink / raw)
  To: Tom Gundersen; +Cc: dri-devel@lists.freedesktop.org

Hi Tom

On Sat, Sep 21, 2013 at 4:18 PM, Tom Gundersen <teg@jklm.no> wrote:
> Hi David,
>
> On Sun, Sep 1, 2013 at 3:36 PM, 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 one dumb-buffer and attach it to the CRTC. Only if
>> the buffer is destroyed, a new buffer can be created. The buffer is
>> directly mapped into user-space, so we have only resources for a single
>> buffer. Otherwise, shadow buffers plus damage-request would be needed.
>>
>> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
>> Tested-by: Stephen Warren <swarren@nvidia.com>
>> ---
>
> [...]
>
>> +static int sdrm_conn_fill_modes(struct drm_connector *conn, uint32_t max_x,
>> +                               uint32_t max_y)
>> +{
>> +       struct sdrm_device *sdrm = conn->dev->dev_private;
>> +       struct drm_display_mode *mode;
>> +       int ret;
>> +
>> +       if (conn->force == DRM_FORCE_ON)
>> +               conn->status = connector_status_connected;
>> +       else if (conn->force)
>> +               conn->status = connector_status_disconnected;
>> +       else
>> +               conn->status = connector_status_connected;
>> +
>> +       list_for_each_entry(mode, &conn->modes, head)
>> +               mode->status = MODE_UNVERIFIED;
>> +
>> +       mode = drm_gtf_mode(sdrm->ddev, sdrm->fb_width, sdrm->fb_height,
>> +                           60, 0, 0);
>> +       if (mode) {
>> +               mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
>> +               drm_mode_probed_add(conn, mode);
>> +               sdrm->mode = mode;
>
> Should you also be setting sdrm->fb_{width,height} to
> mode->{v,h}display here? Otherwise, due to the rounding in
> drm_gtf_mode(), these values won't necessarily match (which I suppose
> they must?).

What the ****. I wasn't aware drm_gtf_mode() modifies the v/hdisplay
values. Hm.. I will probably have to use something else then.

Thanks
David

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

end of thread, other threads:[~2013-10-02 15:09 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-09-01 13:36 [PATCH v4 0/6] SimpleDRM Driver David Herrmann
2013-09-01 13:36 ` [PATCH v4 1/6] drm: add SimpleDRM driver David Herrmann
2013-09-21 14:18   ` Tom Gundersen
2013-10-02 15:09     ` David Herrmann
2013-09-01 13:36 ` [PATCH v4 2/6] drm: simpledrm: add fbdev fallback support David Herrmann
2013-09-01 13:36 ` [PATCH v4 3/6] drm: add helpers to kick out firmware drivers David Herrmann
2013-09-01 13:36 ` [PATCH v4 4/6] drm: nouveau: kick out firmware drivers during probe David Herrmann
2013-09-01 13:36 ` [PATCH v4 5/6] drm/i915: use new drm_kick_out_firmware() David Herrmann
2013-09-02  7:43   ` Daniel Vetter
2013-09-02 12:02     ` David Herrmann
2013-09-02 14:26       ` Daniel Vetter
2013-09-01 13:36 ` [PATCH v4 6/6] drm/radeon: " David Herrmann
2013-09-04 17:34 ` [PATCH v4 0/6] SimpleDRM Driver David Herrmann
2013-09-08 11:33   ` Tom Gundersen
2013-09-08 13:13     ` David Herrmann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).