All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/14] Platform Framebuffers and SimpleDRM
@ 2013-07-04 12:25 David Herrmann
  2013-07-04 12:25 ` [PATCH v2 01/14] fbdev: simplefb: add init through platform_data David Herrmann
                   ` (15 more replies)
  0 siblings, 16 replies; 23+ messages in thread
From: David Herrmann @ 2013-07-04 12:25 UTC (permalink / raw)
  To: linux-kernel
  Cc: David Airlie, dri-devel, David Herrmann, Geert Uytterhoeven,
	Stephen Warren, Peter Jones, Tomi Valkeinen,
	Jean-Christophe Plagniol-Villard, x86, H. Peter Anvin,
	Ingo Molnar, Thomas Gleixner

Hi

This series changes the way we handle firmware framebuffers on x86 systems. On
other architectures the recently introduced "simple-framebuffer"
platform-devices provide a sane and proper way to handle firmware framebuffers.
So why not use it on x86, too?

This series adds x86 setup code to create proper platform-devices for firmware
framebuffers. For backwards compatibility, efi-fb, vesa-fb and platform-fb
devices are created and vesafb.c, efifb.c bind to the right device. We no
longer have vesafb and efifb load unconditionally on "screen_info".
If a fw-FB is compatible to "simple-framebuffer" devices, we create these
instead. We can then use the generic arch-independent simplefb.c on x86 without
any vesafb/efifb conflicts.

Last but not least, the series introduces SimpleDRM, which is basically simplefb
but as DRM driver with all the usual benefits. SimpleDRM is also the motivation
behind this series, but probably only of interest for the dri-devel
mailing-list.

* Patches 1 & 2 modify simplefb.c to accept framebuffer information via plain
  old platform_data and allow real hw drivers to remove simplefb on conflicts.

* Patches 3 & 4 add x86 setup code to create the right platform-device for any
  found firmware framebuffer.

* Patches 5 - 7 modify simplefb.c, vesafb.c, efifb.c to use these new devices
  and support common x86 formats.

* Patch 8 fixes fbcon to require console binding to avoid crashes during
  framebuffer hotplugging

* Patches 9-14: Introduce SimpleDRM

Changes in v2:
 - We now provide efi-framebuffer, vesa-framebuffer or platform-framebuffer
   legacy devices instead of just platform-framebuffer devs. This allows to
   load vesafb, efifb, .. simultaneously instead of only one driver.
 - vesafb and efifb now use the new platform devices
 - simplefb can now be unloaded via remove_conflicting_framebuffers()
 - efifb EFI quirks now moved to x86 setup
 - refactored x86 setup code to avoid #ifdefs
 - Many small fixes (thanks to Stephen and Andy)
 - Adjusted i915 and radeon to use new drm_kick_out_firmware()
 - fbcon now works with SimpleDRM (fixed the palette handling and def-flags)
 - fbdev unloading fixed (Patch #8)

Open issues:
 - How does static platform-device creation conflict with OF support on x86?
   If we want to support "simple-framebuffer" devices via OF, we currently
   require screen_info...isVGA to be 0 so sysfb.c does nothing. Is that
   guaranteed?
 - Should we try to move the offb.c DT parser to sysfb.c, too, so we can
   convert these devices to simple-framebuffers?
 - How can we integrate vga16fb.c into this? Bind to "platform-framebuffer"?
 - Is there any other generic driver that we might want to check? I haven't
   found more (except uvesafb, which always was separate, anyway).
 - What FB formats are common on x86 that we should add to SIMPLEFB_FORMATS?
   (other than ARGB/XRGB32)
 - Should we move default_vga detection from efifb.c to sysfb_efi.c, too? We
   could make the DMI table __init then.

I tested this (including DRM handover) with vesafb, efifb and simpledrm. It all
worked well without problems. More testing is highly welcome! Also feel free
to pickup individual fixes which don't directly depend on the series (eg. #1,
 #2, #7, #8).

Comments welcome!
Cheers
David

David Herrmann (14):
  fbdev: simplefb: add init through platform_data
  fbdev: simplefb: mark as fw and allocate apertures
  x86: provide platform-devices for boot-framebuffers
  x86: sysfb: move EFI quirks from efifb to sysfb
  fbdev: simplefb: add 32bit RGB formats
  fbdev: vesafb: bind to platform-framebuffer device
  fbdev: efifb: bind to efi-framebuffer
  fbdev: fbcon: select VT_HW_CONSOLE_BINDING
  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 +
 arch/x86/Kconfig                            |  26 ++
 arch/x86/include/asm/sysfb.h                |  98 ++++++++
 arch/x86/kernel/Makefile                    |   3 +
 arch/x86/kernel/sysfb.c                     |  74 ++++++
 arch/x86/kernel/sysfb_efi.c                 | 214 ++++++++++++++++
 arch/x86/kernel/sysfb_simplefb.c            |  95 ++++++++
 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          |   6 +
 drivers/gpu/drm/simpledrm/simpledrm.h       | 112 +++++++++
 drivers/gpu/drm/simpledrm/simpledrm_drv.c   | 227 +++++++++++++++++
 drivers/gpu/drm/simpledrm/simpledrm_fbdev.c | 153 ++++++++++++
 drivers/gpu/drm/simpledrm/simpledrm_main.c  | 363 ++++++++++++++++++++++++++++
 drivers/gpu/drm/simpledrm/simpledrm_mem.c   | 252 +++++++++++++++++++
 drivers/video/Kconfig                       |   5 +-
 drivers/video/console/Kconfig               |   3 +-
 drivers/video/efifb.c                       | 302 +++--------------------
 drivers/video/simplefb.c                    |  58 +++--
 drivers/video/vesafb.c                      |  55 ++---
 include/drm/drmP.h                          |  26 ++
 include/linux/platform_data/simplefb.h      |  58 +++++
 31 files changed, 2016 insertions(+), 368 deletions(-)
 create mode 100644 arch/x86/include/asm/sysfb.h
 create mode 100644 arch/x86/kernel/sysfb.c
 create mode 100644 arch/x86/kernel/sysfb_efi.c
 create mode 100644 arch/x86/kernel/sysfb_simplefb.c
 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
 create mode 100644 include/linux/platform_data/simplefb.h

-- 
1.8.3.2


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

* [PATCH v2 01/14] fbdev: simplefb: add init through platform_data
  2013-07-04 12:25 [PATCH v2 00/14] Platform Framebuffers and SimpleDRM David Herrmann
@ 2013-07-04 12:25 ` David Herrmann
  2013-07-09 21:17   ` Stephen Warren
  2013-07-04 12:25 ` [PATCH v2 02/14] fbdev: simplefb: mark as fw and allocate apertures David Herrmann
                   ` (14 subsequent siblings)
  15 siblings, 1 reply; 23+ messages in thread
From: David Herrmann @ 2013-07-04 12:25 UTC (permalink / raw)
  To: linux-kernel; +Cc: David Airlie, dri-devel, David Herrmann, Stephen Warren

If we create proper platform-devices in x86 boot-code, we can use simplefb
for VBE or EFI framebuffers, too. However, there is normally no OF support
so we introduce a platform_data object so x86 boot-code can pass the
parameters via plain old platform-data.

This also removes the OF dependency as it is not needed. The headers
provide proper dummies for the case OF is disabled.

Furthermore, we move the FORMAT-definitions to the common platform header
so initialization code can use it to transform "struct screen_info" to
the right format-name.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/video/Kconfig                  |  5 ++-
 drivers/video/simplefb.c               | 48 +++++++++++++++++++++--------
 include/linux/platform_data/simplefb.h | 56 ++++++++++++++++++++++++++++++++++
 3 files changed, 93 insertions(+), 16 deletions(-)
 create mode 100644 include/linux/platform_data/simplefb.h

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 2e937bd..22586ee 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2455,7 +2455,7 @@ config FB_HYPERV
 
 config FB_SIMPLE
 	bool "Simple framebuffer support"
-	depends on (FB = y) && OF
+	depends on (FB = y)
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
@@ -2467,8 +2467,7 @@ config FB_SIMPLE
 	  pre-allocated frame buffer surface.
 
 	  Configuration re: surface address, size, and format must be provided
-	  through device tree, or potentially plain old platform data in the
-	  future.
+	  through device tree, or plain old platform data.
 
 source "drivers/video/omap/Kconfig"
 source "drivers/video/omap2/Kconfig"
diff --git a/drivers/video/simplefb.c b/drivers/video/simplefb.c
index e2e9e3e..5886989 100644
--- a/drivers/video/simplefb.c
+++ b/drivers/video/simplefb.c
@@ -24,6 +24,7 @@
 #include <linux/fb.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/platform_data/simplefb.h>
 #include <linux/platform_device.h>
 
 static struct fb_fix_screeninfo simplefb_fix = {
@@ -73,18 +74,7 @@ static struct fb_ops simplefb_ops = {
 	.fb_imageblit	= cfb_imageblit,
 };
 
-struct simplefb_format {
-	const char *name;
-	u32 bits_per_pixel;
-	struct fb_bitfield red;
-	struct fb_bitfield green;
-	struct fb_bitfield blue;
-	struct fb_bitfield transp;
-};
-
-static struct simplefb_format simplefb_formats[] = {
-	{ "r5g6b5", 16, {11, 5}, {5, 6}, {0, 5}, {0, 0} },
-};
+static struct simplefb_format simplefb_formats[] = SIMPLEFB_FORMATS;
 
 struct simplefb_params {
 	u32 width;
@@ -139,6 +129,33 @@ static int simplefb_parse_dt(struct platform_device *pdev,
 	return 0;
 }
 
+static int simplefb_parse_pd(struct platform_device *pdev,
+			     struct simplefb_params *params)
+{
+	struct simplefb_platform_data *pd = pdev->dev.platform_data;
+	int i;
+
+	params->width = pd->width;
+	params->height = pd->height;
+	params->stride = pd->stride;
+
+	params->format = NULL;
+	for (i = 0; i < ARRAY_SIZE(simplefb_formats); i++) {
+		if (strcmp(pd->format, simplefb_formats[i].name))
+			continue;
+
+		params->format = &simplefb_formats[i];
+		break;
+	}
+
+	if (!params->format) {
+		dev_err(&pdev->dev, "Invalid format value\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int simplefb_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -149,7 +166,12 @@ static int simplefb_probe(struct platform_device *pdev)
 	if (fb_get_options("simplefb", NULL))
 		return -ENODEV;
 
-	ret = simplefb_parse_dt(pdev, &params);
+	ret = -ENODEV;
+	if (pdev->dev.platform_data)
+		ret = simplefb_parse_pd(pdev, &params);
+	else if (pdev->dev.of_node)
+		ret = simplefb_parse_dt(pdev, &params);
+
 	if (ret)
 		return ret;
 
diff --git a/include/linux/platform_data/simplefb.h b/include/linux/platform_data/simplefb.h
new file mode 100644
index 0000000..5fa2c5e
--- /dev/null
+++ b/include/linux/platform_data/simplefb.h
@@ -0,0 +1,56 @@
+/*
+ * simplefb.h - Simple Framebuffer Device
+ *
+ * Copyright (C) 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 __PLATFORM_DATA_SIMPLEFB_H__
+#define __PLATFORM_DATA_SIMPLEFB_H__
+
+#include <drm/drm_fourcc.h>
+#include <linux/fb.h>
+#include <linux/kernel.h>
+
+/* format array, use it to initialize a "struct simplefb_format" array */
+#define SIMPLEFB_FORMATS \
+{ \
+	{ "r5g6b5", 16, {11, 5}, {5, 6}, {0, 5}, {0, 0}, DRM_FORMAT_RGB565 }, \
+}
+
+/*
+ * Data-Format for Simple-Framebuffers
+ * @name: unique 0-terminated name that can be used to identify the mode
+ * @red,green,blue: Offsets and sizes of the single RGB parts
+ * @transp: Offset and size of the alpha bits. length=0 means no alpha
+ * @fourcc: 32bit DRM four-CC code (see drm_fourcc.h)
+ */
+struct simplefb_format {
+	const char *name;
+	u32 bits_per_pixel;
+	struct fb_bitfield red;
+	struct fb_bitfield green;
+	struct fb_bitfield blue;
+	struct fb_bitfield transp;
+	u32 fourcc;
+};
+
+/*
+ * Simple-Framebuffer description
+ * If the arch-boot code creates simple-framebuffers without DT support, it
+ * can pass the width, height, stride and format via this platform-data object.
+ * The framebuffer location must be given as IORESOURCE_MEM resource.
+ * @format must be a format as described in "struct simplefb_format" above.
+ */
+struct simplefb_platform_data {
+	u32 width;
+	u32 height;
+	u32 stride;
+	const char *format;
+};
+
+#endif /* __PLATFORM_DATA_SIMPLEFB_H__ */
-- 
1.8.3.2


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

* [PATCH v2 02/14] fbdev: simplefb: mark as fw and allocate apertures
  2013-07-04 12:25 [PATCH v2 00/14] Platform Framebuffers and SimpleDRM David Herrmann
  2013-07-04 12:25 ` [PATCH v2 01/14] fbdev: simplefb: add init through platform_data David Herrmann
@ 2013-07-04 12:25 ` David Herrmann
  2013-07-04 12:25   ` David Herrmann
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: David Herrmann @ 2013-07-04 12:25 UTC (permalink / raw)
  To: linux-kernel; +Cc: David Airlie, dri-devel, David Herrmann, Stephen Warren

fbdev-core uses FBINFO_MISC_FIRMWARE to mark drivers that use firmware
framebuffers. Furthermore, we now allocate apertures for the fbinfo
device.
Both information is used by remove_conflicting_framebuffers() to remove a
fbdev device whenever a real driver is loaded. This is used heavily on x86
for VGA/vesa/EFI framebuffers, but is also of great use for all other
systems.

Especially with x86 support for simplefb, this information is needed to
unload simplefb before a real hw-driver (like i915, radeon, nouveau) is
loaded.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/video/simplefb.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/video/simplefb.c b/drivers/video/simplefb.c
index 5886989..8d78106 100644
--- a/drivers/video/simplefb.c
+++ b/drivers/video/simplefb.c
@@ -202,8 +202,16 @@ static int simplefb_probe(struct platform_device *pdev)
 	info->var.blue = params.format->blue;
 	info->var.transp = params.format->transp;
 
+	info->apertures = alloc_apertures(1);
+	if (!info->apertures) {
+		framebuffer_release(info);
+		return -ENOMEM;
+	}
+	info->apertures->ranges[0].base = info->fix.smem_start;
+	info->apertures->ranges[0].size = info->fix.smem_len;
+
 	info->fbops = &simplefb_ops;
-	info->flags = FBINFO_DEFAULT;
+	info->flags = FBINFO_DEFAULT | FBINFO_MISC_FIRMWARE;
 	info->screen_base = devm_ioremap(&pdev->dev, info->fix.smem_start,
 					 info->fix.smem_len);
 	if (!info->screen_base) {
-- 
1.8.3.2


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

* [PATCH v2 03/14] x86: provide platform-devices for boot-framebuffers
  2013-07-04 12:25 [PATCH v2 00/14] Platform Framebuffers and SimpleDRM David Herrmann
@ 2013-07-04 12:25   ` David Herrmann
  2013-07-04 12:25 ` [PATCH v2 02/14] fbdev: simplefb: mark as fw and allocate apertures David Herrmann
                     ` (14 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: David Herrmann @ 2013-07-04 12:25 UTC (permalink / raw)
  To: linux-kernel
  Cc: David Airlie, dri-devel, David Herrmann, x86, H. Peter Anvin,
	Ingo Molnar, Thomas Gleixner

The current situation regarding boot-framebuffers (VGA, VESA/VBE, EFI) on
x86 causes troubles when loading multiple fbdev drivers. The global
"struct screen_info" does not provide any state-tracking about which
drivers use the FBs. request_mem_region() theoretically works, but
unfortunately vesafb/efifb ignore it due to quirks for broken boards.

Avoid this by creating a platform framebuffer devices with a pointer
to the "struct screen_info" as platform-data. Drivers can now create
platform-drivers and the driver-core will refuse multiple drivers being
active simultaneously.

We keep the screen_info available for backwards-compatibility. Drivers
can be converted in follow-up patches.

Different devices are created for VGA/VESA/EFI FBs to allow multiple
drivers to be loaded on distro kernels. We create:
 - "vesa-framebuffer" for VBE/VESA graphics FBs
 - "efi-framebuffer" for EFI FBs
 - "platform-framebuffer" for everything else
This allows to load vesafb, efifb and others simultaneously and each
picks up only the supported FB types.

Apart from platform-framebuffer devices, this also introduces a
compatibility option for "simple-framebuffer" drivers which recently got
introduced for OF based systems. If CONFIG_X86_SYSFB is selected, we
try to match the screen_info against a simple-framebuffer supported
format. If we succeed, we create a "simple-framebuffer" device instead
of a platform-framebuffer.
This allows to reuse the simplefb.c driver across architectures and also
to introduce a SimpleDRM driver. There is no need to have vesafb.c,
efifb.c, simplefb.c and more just to have architecture specific quirks
in their setup-routines.

Instead, we now move the architecture specific quirks into x86-setup and
provide a generic simple-framebuffer. For backwards-compatibility (if
strange formats are used), we still allow vesafb/efifb to be loaded
simultaneously and pick up all remaining devices.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 arch/x86/Kconfig                 | 26 +++++++++++
 arch/x86/include/asm/sysfb.h     | 41 +++++++++++++++++
 arch/x86/kernel/Makefile         |  2 +
 arch/x86/kernel/sysfb.c          | 71 ++++++++++++++++++++++++++++++
 arch/x86/kernel/sysfb_simplefb.c | 95 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 235 insertions(+)
 create mode 100644 arch/x86/include/asm/sysfb.h
 create mode 100644 arch/x86/kernel/sysfb.c
 create mode 100644 arch/x86/kernel/sysfb_simplefb.c

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index fe120da..54a93a5 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2255,6 +2255,32 @@ config RAPIDIO
 
 source "drivers/rapidio/Kconfig"
 
+config X86_SYSFB
+	bool "Mark VGA/VBE/EFI FB as generic system framebuffer"
+	help
+	  Firmwares often provide initial graphics framebuffers so the BIOS,
+	  bootloader or kernel can show basic video-output during boot for
+	  user-guidance and debugging. Historically, x86 used the VESA BIOS
+	  Extensions and EFI-framebuffers for this, which are mostly limited
+	  to x86.
+	  This option, if enabled, marks VGA/VBE/EFI framebuffers as generic
+	  framebuffers so the new generic system-framebuffer drivers can be
+	  used on x86. If the framebuffer is not compatible with the generic
+	  modes, it is adverticed as fallback platform framebuffer so legacy
+	  drivers like efifb, vesafb and uvesafb can pick it up.
+	  If this option is not selected, all system framebuffers are always
+	  marked as fallback platform framebuffers as usual.
+
+	  Note: Legacy fbdev drivers, including vesafb, efifb, uvesafb, will
+	  not be able to pick up generic system framebuffers if this option
+	  is selected. You are highly encouraged to enable simplefb as
+	  replacement if you select this option. simplefb can correctly deal
+	  with generic system framebuffers. But you should still keep vesafb
+	  and others enabled as fallback if a system framebuffer is
+	  incompatible with simplefb.
+
+	  If unsure, say Y.
+
 endmenu
 
 
diff --git a/arch/x86/include/asm/sysfb.h b/arch/x86/include/asm/sysfb.h
new file mode 100644
index 0000000..2395fe0
--- /dev/null
+++ b/arch/x86/include/asm/sysfb.h
@@ -0,0 +1,41 @@
+#ifndef _ARCH_X86_KERNEL_SYSFB_H
+#define _ARCH_X86_KERNEL_SYSFB_H
+
+/*
+ * Generic System Framebuffers on x86
+ * 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/kernel.h>
+#include <linux/platform_data/simplefb.h>
+#include <linux/screen_info.h>
+
+#ifdef CONFIG_X86_SYSFB
+
+bool parse_mode(const struct screen_info *si,
+		struct simplefb_platform_data *mode);
+int create_simplefb(const struct screen_info *si,
+		    const struct simplefb_platform_data *mode);
+
+#else /* CONFIG_X86_SYSFB */
+
+static inline bool parse_mode(const struct screen_info *si,
+			      struct simplefb_platform_data *mode)
+{
+	return false;
+}
+
+static inline int create_simplefb(const struct screen_info *si,
+				  const struct simplefb_platform_data *mode)
+{
+	return -EINVAL;
+}
+
+#endif /* CONFIG_X86_SYSFB */
+
+#endif /* _ARCH_X86_KERNEL_SYSFB_H */
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 7bd3bd3..c5e7677 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -100,6 +100,8 @@ obj-$(CONFIG_X86_CHECK_BIOS_CORRUPTION) += check.o
 obj-$(CONFIG_SWIOTLB)			+= pci-swiotlb.o
 obj-$(CONFIG_OF)			+= devicetree.o
 obj-$(CONFIG_UPROBES)			+= uprobes.o
+obj-y					+= sysfb.o
+obj-$(CONFIG_X86_SYSFB)			+= sysfb_simplefb.o
 
 obj-$(CONFIG_PERF_EVENTS)		+= perf_regs.o
 
diff --git a/arch/x86/kernel/sysfb.c b/arch/x86/kernel/sysfb.c
new file mode 100644
index 0000000..7f30e19
--- /dev/null
+++ b/arch/x86/kernel/sysfb.c
@@ -0,0 +1,71 @@
+/*
+ * Generic System Framebuffers on x86
+ * 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.
+ */
+
+/*
+ * Simple-Framebuffer support for x86 systems
+ * Create a platform-device for any available boot framebuffer. The
+ * simple-framebuffer platform device is already available on DT systems, so
+ * this module parses the global "screen_info" object and creates a suitable
+ * platform device compatible with the "simple-framebuffer" DT object. If
+ * the framebuffer is incompatible, we instead create a legacy
+ * "vesa-framebuffer", "efi-framebuffer" or "platform-framebuffer" device and
+ * pass the screen_info as platform_data. This allows legacy drivers
+ * to pick these devices up without messing with simple-framebuffer drivers.
+ * The global "screen_info" is still valid at all times.
+ *
+ * If CONFIG_X86_SYSFB is not selected, we never register "simple-framebuffer"
+ * platform devices, but only use legacy framebuffer devices for
+ * backwards compatibility.
+ *
+ * TODO: We set the dev_id field of all platform-devices to 0. This allows
+ * other x86 OF/DT parsers to create such devices, too. However, they must
+ * start at offset 1 for this to work.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/platform_data/simplefb.h>
+#include <linux/platform_device.h>
+#include <linux/screen_info.h>
+#include <asm/sysfb.h>
+
+static __init int sysfb_init(void)
+{
+	struct screen_info *si = &screen_info;
+	struct simplefb_platform_data mode;
+	struct platform_device *pd;
+	const char *name;
+	bool compatible;
+	int ret;
+
+	/* try to create a simple-framebuffer device */
+	compatible = parse_mode(si, &mode);
+	if (compatible) {
+		ret = create_simplefb(si, &mode);
+		if (!ret)
+			return 0;
+	}
+
+	/* if the FB is incompatible, create a legacy framebuffer device */
+	if (si->orig_video_isVGA == VIDEO_TYPE_EFI)
+		name = "efi-framebuffer";
+	else if (si->orig_video_isVGA == VIDEO_TYPE_VLFB)
+		name = "vesa-framebuffer";
+	else
+		name = "platform-framebuffer";
+
+	pd = platform_device_register_resndata(NULL, name, 0,
+					       NULL, 0, si, sizeof(*si));
+	return IS_ERR(pd) ? PTR_ERR(pd) : 0;
+}
+
+device_initcall(sysfb_init);
diff --git a/arch/x86/kernel/sysfb_simplefb.c b/arch/x86/kernel/sysfb_simplefb.c
new file mode 100644
index 0000000..22513e9
--- /dev/null
+++ b/arch/x86/kernel/sysfb_simplefb.c
@@ -0,0 +1,95 @@
+/*
+ * Generic System Framebuffers on x86
+ * 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.
+ */
+
+/*
+ * simple-framebuffer probing
+ * Try to convert "screen_info" into a "simple-framebuffer" compatible mode.
+ * If the mode is incompatible, we return "false" and let the caller create
+ * legacy nodes instead.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/platform_data/simplefb.h>
+#include <linux/platform_device.h>
+#include <linux/screen_info.h>
+#include <asm/sysfb.h>
+
+static const char simplefb_resname[] = "BOOTFB";
+static const struct simplefb_format formats[] = SIMPLEFB_FORMATS;
+
+/* try parsing x86 screen_info into a simple-framebuffer mode struct */
+__init bool parse_mode(const struct screen_info *si,
+		       struct simplefb_platform_data *mode)
+{
+	const struct simplefb_format *f;
+	__u8 type;
+	unsigned int i;
+
+	type = si->orig_video_isVGA;
+	if (type != VIDEO_TYPE_VLFB && type != VIDEO_TYPE_EFI)
+		return false;
+
+	for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+		f = &formats[i];
+		if (si->lfb_depth == f->bits_per_pixel &&
+		    si->red_size == f->red.length &&
+		    si->red_pos == f->red.offset &&
+		    si->green_size == f->green.length &&
+		    si->green_pos == f->green.offset &&
+		    si->blue_size == f->blue.length &&
+		    si->blue_pos == f->blue.offset &&
+		    si->rsvd_size == f->transp.length &&
+		    si->rsvd_pos == f->transp.offset) {
+			mode->format = f->name;
+			mode->width = si->lfb_width;
+			mode->height = si->lfb_height;
+			mode->stride = si->lfb_linelength;
+			return true;
+		}
+	}
+
+	return false;
+}
+
+__init int create_simplefb(const struct screen_info *si,
+			   const struct simplefb_platform_data *mode)
+{
+	struct platform_device *pd;
+	struct resource res;
+	unsigned long len;
+
+	/* 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 > si->lfb_size << 16) {
+		printk(KERN_WARNING "sysfb: VRAM smaller than advertised\n");
+		return -EINVAL;
+	}
+
+	/* setup IORESOURCE_MEM as framebuffer memory */
+	memset(&res, 0, sizeof(res));
+	res.flags = IORESOURCE_MEM;
+	res.name = simplefb_resname;
+	res.start = si->lfb_base;
+	res.end = si->lfb_base + len - 1;
+	if (res.end <= res.start)
+		return -EINVAL;
+
+	pd = platform_device_register_resndata(NULL, "simple-framebuffer", 0,
+					       &res, 1, mode, sizeof(*mode));
+	if (IS_ERR(pd))
+		return PTR_ERR(pd);
+
+	return 0;
+}
-- 
1.8.3.2


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

* [PATCH v2 03/14] x86: provide platform-devices for boot-framebuffers
@ 2013-07-04 12:25   ` David Herrmann
  0 siblings, 0 replies; 23+ messages in thread
From: David Herrmann @ 2013-07-04 12:25 UTC (permalink / raw)
  To: linux-kernel; +Cc: x86, dri-devel, Ingo Molnar, H. Peter Anvin, Thomas Gleixner

The current situation regarding boot-framebuffers (VGA, VESA/VBE, EFI) on
x86 causes troubles when loading multiple fbdev drivers. The global
"struct screen_info" does not provide any state-tracking about which
drivers use the FBs. request_mem_region() theoretically works, but
unfortunately vesafb/efifb ignore it due to quirks for broken boards.

Avoid this by creating a platform framebuffer devices with a pointer
to the "struct screen_info" as platform-data. Drivers can now create
platform-drivers and the driver-core will refuse multiple drivers being
active simultaneously.

We keep the screen_info available for backwards-compatibility. Drivers
can be converted in follow-up patches.

Different devices are created for VGA/VESA/EFI FBs to allow multiple
drivers to be loaded on distro kernels. We create:
 - "vesa-framebuffer" for VBE/VESA graphics FBs
 - "efi-framebuffer" for EFI FBs
 - "platform-framebuffer" for everything else
This allows to load vesafb, efifb and others simultaneously and each
picks up only the supported FB types.

Apart from platform-framebuffer devices, this also introduces a
compatibility option for "simple-framebuffer" drivers which recently got
introduced for OF based systems. If CONFIG_X86_SYSFB is selected, we
try to match the screen_info against a simple-framebuffer supported
format. If we succeed, we create a "simple-framebuffer" device instead
of a platform-framebuffer.
This allows to reuse the simplefb.c driver across architectures and also
to introduce a SimpleDRM driver. There is no need to have vesafb.c,
efifb.c, simplefb.c and more just to have architecture specific quirks
in their setup-routines.

Instead, we now move the architecture specific quirks into x86-setup and
provide a generic simple-framebuffer. For backwards-compatibility (if
strange formats are used), we still allow vesafb/efifb to be loaded
simultaneously and pick up all remaining devices.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 arch/x86/Kconfig                 | 26 +++++++++++
 arch/x86/include/asm/sysfb.h     | 41 +++++++++++++++++
 arch/x86/kernel/Makefile         |  2 +
 arch/x86/kernel/sysfb.c          | 71 ++++++++++++++++++++++++++++++
 arch/x86/kernel/sysfb_simplefb.c | 95 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 235 insertions(+)
 create mode 100644 arch/x86/include/asm/sysfb.h
 create mode 100644 arch/x86/kernel/sysfb.c
 create mode 100644 arch/x86/kernel/sysfb_simplefb.c

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index fe120da..54a93a5 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2255,6 +2255,32 @@ config RAPIDIO
 
 source "drivers/rapidio/Kconfig"
 
+config X86_SYSFB
+	bool "Mark VGA/VBE/EFI FB as generic system framebuffer"
+	help
+	  Firmwares often provide initial graphics framebuffers so the BIOS,
+	  bootloader or kernel can show basic video-output during boot for
+	  user-guidance and debugging. Historically, x86 used the VESA BIOS
+	  Extensions and EFI-framebuffers for this, which are mostly limited
+	  to x86.
+	  This option, if enabled, marks VGA/VBE/EFI framebuffers as generic
+	  framebuffers so the new generic system-framebuffer drivers can be
+	  used on x86. If the framebuffer is not compatible with the generic
+	  modes, it is adverticed as fallback platform framebuffer so legacy
+	  drivers like efifb, vesafb and uvesafb can pick it up.
+	  If this option is not selected, all system framebuffers are always
+	  marked as fallback platform framebuffers as usual.
+
+	  Note: Legacy fbdev drivers, including vesafb, efifb, uvesafb, will
+	  not be able to pick up generic system framebuffers if this option
+	  is selected. You are highly encouraged to enable simplefb as
+	  replacement if you select this option. simplefb can correctly deal
+	  with generic system framebuffers. But you should still keep vesafb
+	  and others enabled as fallback if a system framebuffer is
+	  incompatible with simplefb.
+
+	  If unsure, say Y.
+
 endmenu
 
 
diff --git a/arch/x86/include/asm/sysfb.h b/arch/x86/include/asm/sysfb.h
new file mode 100644
index 0000000..2395fe0
--- /dev/null
+++ b/arch/x86/include/asm/sysfb.h
@@ -0,0 +1,41 @@
+#ifndef _ARCH_X86_KERNEL_SYSFB_H
+#define _ARCH_X86_KERNEL_SYSFB_H
+
+/*
+ * Generic System Framebuffers on x86
+ * 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/kernel.h>
+#include <linux/platform_data/simplefb.h>
+#include <linux/screen_info.h>
+
+#ifdef CONFIG_X86_SYSFB
+
+bool parse_mode(const struct screen_info *si,
+		struct simplefb_platform_data *mode);
+int create_simplefb(const struct screen_info *si,
+		    const struct simplefb_platform_data *mode);
+
+#else /* CONFIG_X86_SYSFB */
+
+static inline bool parse_mode(const struct screen_info *si,
+			      struct simplefb_platform_data *mode)
+{
+	return false;
+}
+
+static inline int create_simplefb(const struct screen_info *si,
+				  const struct simplefb_platform_data *mode)
+{
+	return -EINVAL;
+}
+
+#endif /* CONFIG_X86_SYSFB */
+
+#endif /* _ARCH_X86_KERNEL_SYSFB_H */
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 7bd3bd3..c5e7677 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -100,6 +100,8 @@ obj-$(CONFIG_X86_CHECK_BIOS_CORRUPTION) += check.o
 obj-$(CONFIG_SWIOTLB)			+= pci-swiotlb.o
 obj-$(CONFIG_OF)			+= devicetree.o
 obj-$(CONFIG_UPROBES)			+= uprobes.o
+obj-y					+= sysfb.o
+obj-$(CONFIG_X86_SYSFB)			+= sysfb_simplefb.o
 
 obj-$(CONFIG_PERF_EVENTS)		+= perf_regs.o
 
diff --git a/arch/x86/kernel/sysfb.c b/arch/x86/kernel/sysfb.c
new file mode 100644
index 0000000..7f30e19
--- /dev/null
+++ b/arch/x86/kernel/sysfb.c
@@ -0,0 +1,71 @@
+/*
+ * Generic System Framebuffers on x86
+ * 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.
+ */
+
+/*
+ * Simple-Framebuffer support for x86 systems
+ * Create a platform-device for any available boot framebuffer. The
+ * simple-framebuffer platform device is already available on DT systems, so
+ * this module parses the global "screen_info" object and creates a suitable
+ * platform device compatible with the "simple-framebuffer" DT object. If
+ * the framebuffer is incompatible, we instead create a legacy
+ * "vesa-framebuffer", "efi-framebuffer" or "platform-framebuffer" device and
+ * pass the screen_info as platform_data. This allows legacy drivers
+ * to pick these devices up without messing with simple-framebuffer drivers.
+ * The global "screen_info" is still valid at all times.
+ *
+ * If CONFIG_X86_SYSFB is not selected, we never register "simple-framebuffer"
+ * platform devices, but only use legacy framebuffer devices for
+ * backwards compatibility.
+ *
+ * TODO: We set the dev_id field of all platform-devices to 0. This allows
+ * other x86 OF/DT parsers to create such devices, too. However, they must
+ * start at offset 1 for this to work.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/platform_data/simplefb.h>
+#include <linux/platform_device.h>
+#include <linux/screen_info.h>
+#include <asm/sysfb.h>
+
+static __init int sysfb_init(void)
+{
+	struct screen_info *si = &screen_info;
+	struct simplefb_platform_data mode;
+	struct platform_device *pd;
+	const char *name;
+	bool compatible;
+	int ret;
+
+	/* try to create a simple-framebuffer device */
+	compatible = parse_mode(si, &mode);
+	if (compatible) {
+		ret = create_simplefb(si, &mode);
+		if (!ret)
+			return 0;
+	}
+
+	/* if the FB is incompatible, create a legacy framebuffer device */
+	if (si->orig_video_isVGA == VIDEO_TYPE_EFI)
+		name = "efi-framebuffer";
+	else if (si->orig_video_isVGA == VIDEO_TYPE_VLFB)
+		name = "vesa-framebuffer";
+	else
+		name = "platform-framebuffer";
+
+	pd = platform_device_register_resndata(NULL, name, 0,
+					       NULL, 0, si, sizeof(*si));
+	return IS_ERR(pd) ? PTR_ERR(pd) : 0;
+}
+
+device_initcall(sysfb_init);
diff --git a/arch/x86/kernel/sysfb_simplefb.c b/arch/x86/kernel/sysfb_simplefb.c
new file mode 100644
index 0000000..22513e9
--- /dev/null
+++ b/arch/x86/kernel/sysfb_simplefb.c
@@ -0,0 +1,95 @@
+/*
+ * Generic System Framebuffers on x86
+ * 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.
+ */
+
+/*
+ * simple-framebuffer probing
+ * Try to convert "screen_info" into a "simple-framebuffer" compatible mode.
+ * If the mode is incompatible, we return "false" and let the caller create
+ * legacy nodes instead.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/platform_data/simplefb.h>
+#include <linux/platform_device.h>
+#include <linux/screen_info.h>
+#include <asm/sysfb.h>
+
+static const char simplefb_resname[] = "BOOTFB";
+static const struct simplefb_format formats[] = SIMPLEFB_FORMATS;
+
+/* try parsing x86 screen_info into a simple-framebuffer mode struct */
+__init bool parse_mode(const struct screen_info *si,
+		       struct simplefb_platform_data *mode)
+{
+	const struct simplefb_format *f;
+	__u8 type;
+	unsigned int i;
+
+	type = si->orig_video_isVGA;
+	if (type != VIDEO_TYPE_VLFB && type != VIDEO_TYPE_EFI)
+		return false;
+
+	for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+		f = &formats[i];
+		if (si->lfb_depth == f->bits_per_pixel &&
+		    si->red_size == f->red.length &&
+		    si->red_pos == f->red.offset &&
+		    si->green_size == f->green.length &&
+		    si->green_pos == f->green.offset &&
+		    si->blue_size == f->blue.length &&
+		    si->blue_pos == f->blue.offset &&
+		    si->rsvd_size == f->transp.length &&
+		    si->rsvd_pos == f->transp.offset) {
+			mode->format = f->name;
+			mode->width = si->lfb_width;
+			mode->height = si->lfb_height;
+			mode->stride = si->lfb_linelength;
+			return true;
+		}
+	}
+
+	return false;
+}
+
+__init int create_simplefb(const struct screen_info *si,
+			   const struct simplefb_platform_data *mode)
+{
+	struct platform_device *pd;
+	struct resource res;
+	unsigned long len;
+
+	/* 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 > si->lfb_size << 16) {
+		printk(KERN_WARNING "sysfb: VRAM smaller than advertised\n");
+		return -EINVAL;
+	}
+
+	/* setup IORESOURCE_MEM as framebuffer memory */
+	memset(&res, 0, sizeof(res));
+	res.flags = IORESOURCE_MEM;
+	res.name = simplefb_resname;
+	res.start = si->lfb_base;
+	res.end = si->lfb_base + len - 1;
+	if (res.end <= res.start)
+		return -EINVAL;
+
+	pd = platform_device_register_resndata(NULL, "simple-framebuffer", 0,
+					       &res, 1, mode, sizeof(*mode));
+	if (IS_ERR(pd))
+		return PTR_ERR(pd);
+
+	return 0;
+}
-- 
1.8.3.2

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

* [PATCH v2 04/14] x86: sysfb: move EFI quirks from efifb to sysfb
  2013-07-04 12:25 [PATCH v2 00/14] Platform Framebuffers and SimpleDRM David Herrmann
                   ` (2 preceding siblings ...)
  2013-07-04 12:25   ` David Herrmann
@ 2013-07-04 12:25 ` David Herrmann
  2013-07-04 12:25 ` [PATCH v2 05/14] fbdev: simplefb: add 32bit RGB formats David Herrmann
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: David Herrmann @ 2013-07-04 12:25 UTC (permalink / raw)
  To: linux-kernel
  Cc: David Airlie, dri-devel, David Herrmann, Peter Jones, x86,
	H. Peter Anvin, Ingo Molnar, Thomas Gleixner

The EFI FB quirks from efifb.c are useful for simple-framebuffer devices
as well. Apply them by default so we can convert efifb.c to use
efi-framebuffer platform devices.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 arch/x86/include/asm/sysfb.h |  57 +++++++++++
 arch/x86/kernel/Makefile     |   1 +
 arch/x86/kernel/sysfb.c      |   3 +
 arch/x86/kernel/sysfb_efi.c  | 214 +++++++++++++++++++++++++++++++++++++++
 drivers/video/efifb.c        | 234 ++-----------------------------------------
 5 files changed, 282 insertions(+), 227 deletions(-)
 create mode 100644 arch/x86/kernel/sysfb_efi.c

diff --git a/arch/x86/include/asm/sysfb.h b/arch/x86/include/asm/sysfb.h
index 2395fe0..2aeb3e2 100644
--- a/arch/x86/include/asm/sysfb.h
+++ b/arch/x86/include/asm/sysfb.h
@@ -15,6 +15,63 @@
 #include <linux/platform_data/simplefb.h>
 #include <linux/screen_info.h>
 
+enum {
+	M_I17,		/* 17-Inch iMac */
+	M_I20,		/* 20-Inch iMac */
+	M_I20_SR,	/* 20-Inch iMac (Santa Rosa) */
+	M_I24,		/* 24-Inch iMac */
+	M_I24_8_1,	/* 24-Inch iMac, 8,1th gen */
+	M_I24_10_1,	/* 24-Inch iMac, 10,1th gen */
+	M_I27_11_1,	/* 27-Inch iMac, 11,1th gen */
+	M_MINI,		/* Mac Mini */
+	M_MINI_3_1,	/* Mac Mini, 3,1th gen */
+	M_MINI_4_1,	/* Mac Mini, 4,1th gen */
+	M_MB,		/* MacBook */
+	M_MB_2,		/* MacBook, 2nd rev. */
+	M_MB_3,		/* MacBook, 3rd rev. */
+	M_MB_5_1,	/* MacBook, 5th rev. */
+	M_MB_6_1,	/* MacBook, 6th rev. */
+	M_MB_7_1,	/* MacBook, 7th rev. */
+	M_MB_SR,	/* MacBook, 2nd gen, (Santa Rosa) */
+	M_MBA,		/* MacBook Air */
+	M_MBA_3,	/* Macbook Air, 3rd rev */
+	M_MBP,		/* MacBook Pro */
+	M_MBP_2,	/* MacBook Pro 2nd gen */
+	M_MBP_2_2,	/* MacBook Pro 2,2nd gen */
+	M_MBP_SR,	/* MacBook Pro (Santa Rosa) */
+	M_MBP_4,	/* MacBook Pro, 4th gen */
+	M_MBP_5_1,	/* MacBook Pro, 5,1th gen */
+	M_MBP_5_2,	/* MacBook Pro, 5,2th gen */
+	M_MBP_5_3,	/* MacBook Pro, 5,3rd gen */
+	M_MBP_6_1,	/* MacBook Pro, 6,1th gen */
+	M_MBP_6_2,	/* MacBook Pro, 6,2th gen */
+	M_MBP_7_1,	/* MacBook Pro, 7,1th gen */
+	M_MBP_8_2,	/* MacBook Pro, 8,2nd gen */
+	M_UNKNOWN	/* placeholder */
+};
+
+struct efifb_dmi_info {
+	char *optname;
+	unsigned long base;
+	int stride;
+	int width;
+	int height;
+	int flags;
+};
+
+#ifdef CONFIG_EFI
+
+extern struct efifb_dmi_info efifb_dmi_list[];
+void sysfb_apply_efi_quirks(void);
+
+#else /* CONFIG_EFI */
+
+static inline void sysfb_apply_efi_quirks(void)
+{
+}
+
+#endif /* CONFIG_EFI */
+
 #ifdef CONFIG_X86_SYSFB
 
 bool parse_mode(const struct screen_info *si,
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index c5e7677..66c87da 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -102,6 +102,7 @@ obj-$(CONFIG_OF)			+= devicetree.o
 obj-$(CONFIG_UPROBES)			+= uprobes.o
 obj-y					+= sysfb.o
 obj-$(CONFIG_X86_SYSFB)			+= sysfb_simplefb.o
+obj-$(CONFIG_EFI)			+= sysfb_efi.o
 
 obj-$(CONFIG_PERF_EVENTS)		+= perf_regs.o
 
diff --git a/arch/x86/kernel/sysfb.c b/arch/x86/kernel/sysfb.c
index 7f30e19..193ec2c 100644
--- a/arch/x86/kernel/sysfb.c
+++ b/arch/x86/kernel/sysfb.c
@@ -47,6 +47,8 @@ static __init int sysfb_init(void)
 	bool compatible;
 	int ret;
 
+	sysfb_apply_efi_quirks();
+
 	/* try to create a simple-framebuffer device */
 	compatible = parse_mode(si, &mode);
 	if (compatible) {
@@ -68,4 +70,5 @@ static __init int sysfb_init(void)
 	return IS_ERR(pd) ? PTR_ERR(pd) : 0;
 }
 
+/* must execute after PCI subsystem for EFI quirks */
 device_initcall(sysfb_init);
diff --git a/arch/x86/kernel/sysfb_efi.c b/arch/x86/kernel/sysfb_efi.c
new file mode 100644
index 0000000..b285d4e
--- /dev/null
+++ b/arch/x86/kernel/sysfb_efi.c
@@ -0,0 +1,214 @@
+/*
+ * Generic System Framebuffers on x86
+ * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
+ *
+ * EFI Quirks Copyright (c) 2006 Edgar Hucek <gimli@dark-green.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.
+ */
+
+/*
+ * EFI Quirks
+ * Several EFI systems do not correctly advertise their boot framebuffers.
+ * Hence, we use this static table of known broken machines and fix up the
+ * information so framebuffer drivers can load corectly.
+ */
+
+#include <linux/dmi.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/screen_info.h>
+#include <video/vga.h>
+#include <asm/sysfb.h>
+
+enum {
+	OVERRIDE_NONE = 0x0,
+	OVERRIDE_BASE = 0x1,
+	OVERRIDE_STRIDE = 0x2,
+	OVERRIDE_HEIGHT = 0x4,
+	OVERRIDE_WIDTH = 0x8,
+};
+
+struct efifb_dmi_info efifb_dmi_list[] = {
+	[M_I17] = { "i17", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE },
+	[M_I20] = { "i20", 0x80010000, 1728 * 4, 1680, 1050, OVERRIDE_NONE }, /* guess */
+	[M_I20_SR] = { "imac7", 0x40010000, 1728 * 4, 1680, 1050, OVERRIDE_NONE },
+	[M_I24] = { "i24", 0x80010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, /* guess */
+	[M_I24_8_1] = { "imac8", 0xc0060000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
+	[M_I24_10_1] = { "imac10", 0xc0010000, 2048 * 4, 1920, 1080, OVERRIDE_NONE },
+	[M_I27_11_1] = { "imac11", 0xc0010000, 2560 * 4, 2560, 1440, OVERRIDE_NONE },
+	[M_MINI]= { "mini", 0x80000000, 2048 * 4, 1024, 768, OVERRIDE_NONE },
+	[M_MINI_3_1] = { "mini31", 0x40010000, 1024 * 4, 1024, 768, OVERRIDE_NONE },
+	[M_MINI_4_1] = { "mini41", 0xc0010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
+	[M_MB] = { "macbook", 0x80000000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
+	[M_MB_5_1] = { "macbook51", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
+	[M_MB_6_1] = { "macbook61", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
+	[M_MB_7_1] = { "macbook71", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
+	[M_MBA] = { "mba", 0x80000000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
+	/* 11" Macbook Air 3,1 passes the wrong stride */
+	[M_MBA_3] = { "mba3", 0, 2048 * 4, 0, 0, OVERRIDE_STRIDE },
+	[M_MBP] = { "mbp", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE },
+	[M_MBP_2] = { "mbp2", 0, 0, 0, 0, OVERRIDE_NONE }, /* placeholder */
+	[M_MBP_2_2] = { "mbp22", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE },
+	[M_MBP_SR] = { "mbp3", 0x80030000, 2048 * 4, 1440, 900, OVERRIDE_NONE },
+	[M_MBP_4] = { "mbp4", 0xc0060000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
+	[M_MBP_5_1] = { "mbp51", 0xc0010000, 2048 * 4, 1440, 900, OVERRIDE_NONE },
+	[M_MBP_5_2] = { "mbp52", 0xc0010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
+	[M_MBP_5_3] = { "mbp53", 0xd0010000, 2048 * 4, 1440, 900, OVERRIDE_NONE },
+	[M_MBP_6_1] = { "mbp61", 0x90030000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
+	[M_MBP_6_2] = { "mbp62", 0x90030000, 2048 * 4, 1680, 1050, OVERRIDE_NONE },
+	[M_MBP_7_1] = { "mbp71", 0xc0010000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
+	[M_MBP_8_2] = { "mbp82", 0x90010000, 1472 * 4, 1440, 900, OVERRIDE_NONE },
+	[M_UNKNOWN] = { NULL, 0, 0, 0, 0, OVERRIDE_NONE }
+};
+
+#define choose_value(dmivalue, fwvalue, field, flags) ({	\
+		typeof(fwvalue) _ret_ = fwvalue;		\
+		if ((flags) & (field))				\
+			_ret_ = dmivalue;			\
+		else if ((fwvalue) == 0)			\
+			_ret_ = dmivalue;			\
+		_ret_;						\
+	})
+
+static int __init efifb_set_system(const struct dmi_system_id *id)
+{
+	struct efifb_dmi_info *info = id->driver_data;
+
+	if (info->base == 0 && info->height == 0 && info->width == 0 &&
+	    info->stride == 0)
+		return 0;
+
+	/* Trust the bootloader over the DMI tables */
+	if (screen_info.lfb_base == 0) {
+#if defined(CONFIG_PCI)
+		struct pci_dev *dev = NULL;
+		int found_bar = 0;
+#endif
+		if (info->base) {
+			screen_info.lfb_base = choose_value(info->base,
+				screen_info.lfb_base, OVERRIDE_BASE,
+				info->flags);
+
+#if defined(CONFIG_PCI)
+			/* make sure that the address in the table is actually
+			 * on a VGA device's PCI BAR */
+
+			for_each_pci_dev(dev) {
+				int i;
+				if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
+					continue;
+				for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+					resource_size_t start, end;
+
+					start = pci_resource_start(dev, i);
+					if (start == 0)
+						break;
+					end = pci_resource_end(dev, i);
+					if (screen_info.lfb_base >= start &&
+					    screen_info.lfb_base < end) {
+						found_bar = 1;
+					}
+				}
+			}
+			if (!found_bar)
+				screen_info.lfb_base = 0;
+#endif
+		}
+	}
+	if (screen_info.lfb_base) {
+		screen_info.lfb_linelength = choose_value(info->stride,
+			screen_info.lfb_linelength, OVERRIDE_STRIDE,
+			info->flags);
+		screen_info.lfb_width = choose_value(info->width,
+			screen_info.lfb_width, OVERRIDE_WIDTH,
+			info->flags);
+		screen_info.lfb_height = choose_value(info->height,
+			screen_info.lfb_height, OVERRIDE_HEIGHT,
+			info->flags);
+		if (screen_info.orig_video_isVGA == 0)
+			screen_info.orig_video_isVGA = VIDEO_TYPE_EFI;
+	} else {
+		screen_info.lfb_linelength = 0;
+		screen_info.lfb_width = 0;
+		screen_info.lfb_height = 0;
+		screen_info.orig_video_isVGA = 0;
+		return 0;
+	}
+
+	printk(KERN_INFO "efifb: dmi detected %s - framebuffer at 0x%08x "
+			 "(%dx%d, stride %d)\n", id->ident,
+			 screen_info.lfb_base, screen_info.lfb_width,
+			 screen_info.lfb_height, screen_info.lfb_linelength);
+
+	return 1;
+}
+
+#define EFIFB_DMI_SYSTEM_ID(vendor, name, enumid)		\
+	{							\
+		efifb_set_system,				\
+		name,						\
+		{						\
+			DMI_MATCH(DMI_BIOS_VENDOR, vendor),	\
+			DMI_MATCH(DMI_PRODUCT_NAME, name)	\
+		},						\
+		&efifb_dmi_list[enumid]				\
+	}
+
+static const struct dmi_system_id efifb_dmi_system_table[] __initconst = {
+	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac4,1", M_I17),
+	/* At least one of these two will be right; maybe both? */
+	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac5,1", M_I20),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac5,1", M_I20),
+	/* At least one of these two will be right; maybe both? */
+	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac6,1", M_I24),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac6,1", M_I24),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac7,1", M_I20_SR),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac8,1", M_I24_8_1),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac10,1", M_I24_10_1),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac11,1", M_I27_11_1),
+	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "Macmini1,1", M_MINI),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "Macmini3,1", M_MINI_3_1),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "Macmini4,1", M_MINI_4_1),
+	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook1,1", M_MB),
+	/* At least one of these two will be right; maybe both? */
+	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook2,1", M_MB),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook2,1", M_MB),
+	/* At least one of these two will be right; maybe both? */
+	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook3,1", M_MB),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook3,1", M_MB),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook4,1", M_MB),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook5,1", M_MB_5_1),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook6,1", M_MB_6_1),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook7,1", M_MB_7_1),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir1,1", M_MBA),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir3,1", M_MBA_3),
+	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro1,1", M_MBP),
+	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,1", M_MBP_2),
+	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,2", M_MBP_2_2),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro2,1", M_MBP_2),
+	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro3,1", M_MBP_SR),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro3,1", M_MBP_SR),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro4,1", M_MBP_4),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,1", M_MBP_5_1),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,2", M_MBP_5_2),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,3", M_MBP_5_3),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro6,1", M_MBP_6_1),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro6,2", M_MBP_6_2),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro7,1", M_MBP_7_1),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro8,2", M_MBP_8_2),
+	{},
+};
+
+__init void sysfb_apply_efi_quirks(void)
+{
+	if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI ||
+	    !(screen_info.capabilities & VIDEO_CAPABILITY_SKIP_QUIRKS))
+		dmi_check_system(efifb_dmi_system_table);
+}
diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c
index 50fe668..e493bcb 100644
--- a/drivers/video/efifb.c
+++ b/drivers/video/efifb.c
@@ -15,6 +15,7 @@
 #include <linux/dmi.h>
 #include <linux/pci.h>
 #include <video/vga.h>
+#include <asm/sysfb.h>
 
 static bool request_mem_succeeded = false;
 
@@ -38,223 +39,6 @@ static struct fb_fix_screeninfo efifb_fix = {
 	.visual			= FB_VISUAL_TRUECOLOR,
 };
 
-enum {
-	M_I17,		/* 17-Inch iMac */
-	M_I20,		/* 20-Inch iMac */
-	M_I20_SR,	/* 20-Inch iMac (Santa Rosa) */
-	M_I24,		/* 24-Inch iMac */
-	M_I24_8_1,	/* 24-Inch iMac, 8,1th gen */
-	M_I24_10_1,	/* 24-Inch iMac, 10,1th gen */
-	M_I27_11_1,	/* 27-Inch iMac, 11,1th gen */
-	M_MINI,		/* Mac Mini */
-	M_MINI_3_1,	/* Mac Mini, 3,1th gen */
-	M_MINI_4_1,	/* Mac Mini, 4,1th gen */
-	M_MB,		/* MacBook */
-	M_MB_2,		/* MacBook, 2nd rev. */
-	M_MB_3,		/* MacBook, 3rd rev. */
-	M_MB_5_1,	/* MacBook, 5th rev. */
-	M_MB_6_1,	/* MacBook, 6th rev. */
-	M_MB_7_1,	/* MacBook, 7th rev. */
-	M_MB_SR,	/* MacBook, 2nd gen, (Santa Rosa) */
-	M_MBA,		/* MacBook Air */
-	M_MBA_3,	/* Macbook Air, 3rd rev */
-	M_MBP,		/* MacBook Pro */
-	M_MBP_2,	/* MacBook Pro 2nd gen */
-	M_MBP_2_2,	/* MacBook Pro 2,2nd gen */
-	M_MBP_SR,	/* MacBook Pro (Santa Rosa) */
-	M_MBP_4,	/* MacBook Pro, 4th gen */
-	M_MBP_5_1,    /* MacBook Pro, 5,1th gen */
-	M_MBP_5_2,	/* MacBook Pro, 5,2th gen */
-	M_MBP_5_3,	/* MacBook Pro, 5,3rd gen */
-	M_MBP_6_1,	/* MacBook Pro, 6,1th gen */
-	M_MBP_6_2,	/* MacBook Pro, 6,2th gen */
-	M_MBP_7_1,	/* MacBook Pro, 7,1th gen */
-	M_MBP_8_2,	/* MacBook Pro, 8,2nd gen */
-	M_UNKNOWN	/* placeholder */
-};
-
-#define OVERRIDE_NONE	0x0
-#define OVERRIDE_BASE	0x1
-#define OVERRIDE_STRIDE	0x2
-#define OVERRIDE_HEIGHT	0x4
-#define OVERRIDE_WIDTH	0x8
-
-static struct efifb_dmi_info {
-	char *optname;
-	unsigned long base;
-	int stride;
-	int width;
-	int height;
-	int flags;
-} dmi_list[] __initdata = {
-	[M_I17] = { "i17", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE },
-	[M_I20] = { "i20", 0x80010000, 1728 * 4, 1680, 1050, OVERRIDE_NONE }, /* guess */
-	[M_I20_SR] = { "imac7", 0x40010000, 1728 * 4, 1680, 1050, OVERRIDE_NONE },
-	[M_I24] = { "i24", 0x80010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, /* guess */
-	[M_I24_8_1] = { "imac8", 0xc0060000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
-	[M_I24_10_1] = { "imac10", 0xc0010000, 2048 * 4, 1920, 1080, OVERRIDE_NONE },
-	[M_I27_11_1] = { "imac11", 0xc0010000, 2560 * 4, 2560, 1440, OVERRIDE_NONE },
-	[M_MINI]= { "mini", 0x80000000, 2048 * 4, 1024, 768, OVERRIDE_NONE },
-	[M_MINI_3_1] = { "mini31", 0x40010000, 1024 * 4, 1024, 768, OVERRIDE_NONE },
-	[M_MINI_4_1] = { "mini41", 0xc0010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
-	[M_MB] = { "macbook", 0x80000000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
-	[M_MB_5_1] = { "macbook51", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
-	[M_MB_6_1] = { "macbook61", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
-	[M_MB_7_1] = { "macbook71", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
-	[M_MBA] = { "mba", 0x80000000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
-	/* 11" Macbook Air 3,1 passes the wrong stride */
-	[M_MBA_3] = { "mba3", 0, 2048 * 4, 0, 0, OVERRIDE_STRIDE },
-	[M_MBP] = { "mbp", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE },
-	[M_MBP_2] = { "mbp2", 0, 0, 0, 0, OVERRIDE_NONE }, /* placeholder */
-	[M_MBP_2_2] = { "mbp22", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE },
-	[M_MBP_SR] = { "mbp3", 0x80030000, 2048 * 4, 1440, 900, OVERRIDE_NONE },
-	[M_MBP_4] = { "mbp4", 0xc0060000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
-	[M_MBP_5_1] = { "mbp51", 0xc0010000, 2048 * 4, 1440, 900, OVERRIDE_NONE },
-	[M_MBP_5_2] = { "mbp52", 0xc0010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
-	[M_MBP_5_3] = { "mbp53", 0xd0010000, 2048 * 4, 1440, 900, OVERRIDE_NONE },
-	[M_MBP_6_1] = { "mbp61", 0x90030000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
-	[M_MBP_6_2] = { "mbp62", 0x90030000, 2048 * 4, 1680, 1050, OVERRIDE_NONE },
-	[M_MBP_7_1] = { "mbp71", 0xc0010000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
-	[M_MBP_8_2] = { "mbp82", 0x90010000, 1472 * 4, 1440, 900, OVERRIDE_NONE },
-	[M_UNKNOWN] = { NULL, 0, 0, 0, 0, OVERRIDE_NONE }
-};
-
-static int set_system(const struct dmi_system_id *id);
-
-#define EFIFB_DMI_SYSTEM_ID(vendor, name, enumid)		\
-	{ set_system, name, {					\
-		DMI_MATCH(DMI_BIOS_VENDOR, vendor),		\
-		DMI_MATCH(DMI_PRODUCT_NAME, name) },		\
-	  &dmi_list[enumid] }
-
-static const struct dmi_system_id dmi_system_table[] __initconst = {
-	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac4,1", M_I17),
-	/* At least one of these two will be right; maybe both? */
-	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac5,1", M_I20),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac5,1", M_I20),
-	/* At least one of these two will be right; maybe both? */
-	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac6,1", M_I24),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac6,1", M_I24),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac7,1", M_I20_SR),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac8,1", M_I24_8_1),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac10,1", M_I24_10_1),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac11,1", M_I27_11_1),
-	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "Macmini1,1", M_MINI),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "Macmini3,1", M_MINI_3_1),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "Macmini4,1", M_MINI_4_1),
-	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook1,1", M_MB),
-	/* At least one of these two will be right; maybe both? */
-	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook2,1", M_MB),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook2,1", M_MB),
-	/* At least one of these two will be right; maybe both? */
-	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook3,1", M_MB),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook3,1", M_MB),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook4,1", M_MB),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook5,1", M_MB_5_1),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook6,1", M_MB_6_1),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook7,1", M_MB_7_1),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir1,1", M_MBA),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir3,1", M_MBA_3),
-	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro1,1", M_MBP),
-	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,1", M_MBP_2),
-	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,2", M_MBP_2_2),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro2,1", M_MBP_2),
-	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro3,1", M_MBP_SR),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro3,1", M_MBP_SR),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro4,1", M_MBP_4),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,1", M_MBP_5_1),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,2", M_MBP_5_2),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,3", M_MBP_5_3),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro6,1", M_MBP_6_1),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro6,2", M_MBP_6_2),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro7,1", M_MBP_7_1),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro8,2", M_MBP_8_2),
-	{},
-};
-
-#define choose_value(dmivalue, fwvalue, field, flags) ({	\
-		typeof(fwvalue) _ret_ = fwvalue;		\
-		if ((flags) & (field))				\
-			_ret_ = dmivalue;			\
-		else if ((fwvalue) == 0)			\
-			_ret_ = dmivalue;			\
-		_ret_;						\
-	})
-
-static int set_system(const struct dmi_system_id *id)
-{
-	struct efifb_dmi_info *info = id->driver_data;
-
-	if (info->base == 0 && info->height == 0 && info->width == 0
-			&& info->stride == 0)
-		return 0;
-
-	/* Trust the bootloader over the DMI tables */
-	if (screen_info.lfb_base == 0) {
-#if defined(CONFIG_PCI)
-		struct pci_dev *dev = NULL;
-		int found_bar = 0;
-#endif
-		if (info->base) {
-			screen_info.lfb_base = choose_value(info->base,
-				screen_info.lfb_base, OVERRIDE_BASE,
-				info->flags);
-
-#if defined(CONFIG_PCI)
-			/* make sure that the address in the table is actually
-			 * on a VGA device's PCI BAR */
-
-			for_each_pci_dev(dev) {
-				int i;
-				if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
-					continue;
-				for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
-					resource_size_t start, end;
-
-					start = pci_resource_start(dev, i);
-					if (start == 0)
-						break;
-					end = pci_resource_end(dev, i);
-					if (screen_info.lfb_base >= start &&
-					    screen_info.lfb_base < end) {
-						found_bar = 1;
-					}
-				}
-			}
-			if (!found_bar)
-				screen_info.lfb_base = 0;
-#endif
-		}
-	}
-	if (screen_info.lfb_base) {
-		screen_info.lfb_linelength = choose_value(info->stride,
-			screen_info.lfb_linelength, OVERRIDE_STRIDE,
-			info->flags);
-		screen_info.lfb_width = choose_value(info->width,
-			screen_info.lfb_width, OVERRIDE_WIDTH,
-			info->flags);
-		screen_info.lfb_height = choose_value(info->height,
-			screen_info.lfb_height, OVERRIDE_HEIGHT,
-			info->flags);
-		if (screen_info.orig_video_isVGA == 0)
-			screen_info.orig_video_isVGA = VIDEO_TYPE_EFI;
-	} else {
-		screen_info.lfb_linelength = 0;
-		screen_info.lfb_width = 0;
-		screen_info.lfb_height = 0;
-		screen_info.orig_video_isVGA = 0;
-		return 0;
-	}
-
-	printk(KERN_INFO "efifb: dmi detected %s - framebuffer at 0x%08x "
-			 "(%dx%d, stride %d)\n", id->ident,
-			 screen_info.lfb_base, screen_info.lfb_width,
-			 screen_info.lfb_height, screen_info.lfb_linelength);
-
-
-	return 1;
-}
-
 static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
 			   unsigned blue, unsigned transp,
 			   struct fb_info *info)
@@ -323,12 +107,12 @@ static int __init efifb_setup(char *options)
 			if (!*this_opt) continue;
 
 			for (i = 0; i < M_UNKNOWN; i++) {
-				if (!strcmp(this_opt, dmi_list[i].optname) &&
-				    dmi_list[i].base != 0) {
-					screen_info.lfb_base = dmi_list[i].base;
-					screen_info.lfb_linelength = dmi_list[i].stride;
-					screen_info.lfb_width = dmi_list[i].width;
-					screen_info.lfb_height = dmi_list[i].height;
+				if (!strcmp(this_opt, efifb_dmi_list[i].optname) &&
+				    efifb_dmi_list[i].base != 0) {
+					screen_info.lfb_base = efifb_dmi_list[i].base;
+					screen_info.lfb_linelength = efifb_dmi_list[i].stride;
+					screen_info.lfb_width = efifb_dmi_list[i].width;
+					screen_info.lfb_height = efifb_dmi_list[i].height;
 				}
 			}
 			if (!strncmp(this_opt, "base:", 5))
@@ -553,10 +337,6 @@ static int __init efifb_init(void)
 	int ret;
 	char *option = NULL;
 
-	if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI ||
-	    !(screen_info.capabilities & VIDEO_CAPABILITY_SKIP_QUIRKS))
-		dmi_check_system(dmi_system_table);
-
 	if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
 		return -ENODEV;
 
-- 
1.8.3.2


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

* [PATCH v2 05/14] fbdev: simplefb: add 32bit RGB formats
  2013-07-04 12:25 [PATCH v2 00/14] Platform Framebuffers and SimpleDRM David Herrmann
                   ` (3 preceding siblings ...)
  2013-07-04 12:25 ` [PATCH v2 04/14] x86: sysfb: move EFI quirks from efifb to sysfb David Herrmann
@ 2013-07-04 12:25 ` David Herrmann
  2013-07-04 12:25 ` [PATCH v2 06/14] fbdev: vesafb: bind to platform-framebuffer device David Herrmann
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: David Herrmann @ 2013-07-04 12:25 UTC (permalink / raw)
  To: linux-kernel; +Cc: David Airlie, dri-devel, David Herrmann

32bit XRGB and ARGB are used by modern x86 systems for EFI and VESA
framebuffers. Add both variants so simplefb can be used on such systems.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 include/linux/platform_data/simplefb.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/linux/platform_data/simplefb.h b/include/linux/platform_data/simplefb.h
index 5fa2c5e..e1630be 100644
--- a/include/linux/platform_data/simplefb.h
+++ b/include/linux/platform_data/simplefb.h
@@ -20,6 +20,8 @@
 #define SIMPLEFB_FORMATS \
 { \
 	{ "r5g6b5", 16, {11, 5}, {5, 6}, {0, 5}, {0, 0}, DRM_FORMAT_RGB565 }, \
+	{ "a8r8g8b8", 32, {16, 8}, {8, 8}, {0, 8}, {24, 8}, DRM_FORMAT_ARGB8888 }, \
+	{ "x8r8g8b8", 32, {16, 8}, {8, 8}, {0, 8}, {0, 0}, DRM_FORMAT_XRGB8888 }, \
 }
 
 /*
-- 
1.8.3.2


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

* [PATCH v2 06/14] fbdev: vesafb: bind to platform-framebuffer device
  2013-07-04 12:25 [PATCH v2 00/14] Platform Framebuffers and SimpleDRM David Herrmann
                   ` (4 preceding siblings ...)
  2013-07-04 12:25 ` [PATCH v2 05/14] fbdev: simplefb: add 32bit RGB formats David Herrmann
@ 2013-07-04 12:25 ` David Herrmann
  2013-07-04 12:25 ` [PATCH v2 07/14] fbdev: efifb: bind to efi-framebuffer David Herrmann
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: David Herrmann @ 2013-07-04 12:25 UTC (permalink / raw)
  To: linux-kernel; +Cc: David Airlie, dri-devel, David Herrmann

x86 creates platform-framebuffer platform devices for every system
framebuffer. Use these instead of creating a dummy device.

This requires us to remove the __init annotations as hotplugging may occur
during runtime.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/video/vesafb.c | 55 +++++++++++++++-----------------------------------
 1 file changed, 16 insertions(+), 39 deletions(-)

diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index 501b340..bd83233 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -29,7 +29,7 @@
 
 /* --------------------------------------------------------------------- */
 
-static struct fb_var_screeninfo vesafb_defined __initdata = {
+static struct fb_var_screeninfo vesafb_defined = {
 	.activate	= FB_ACTIVATE_NOW,
 	.height		= -1,
 	.width		= -1,
@@ -40,7 +40,7 @@ static struct fb_var_screeninfo vesafb_defined __initdata = {
 	.vmode		= FB_VMODE_NONINTERLACED,
 };
 
-static struct fb_fix_screeninfo vesafb_fix __initdata = {
+static struct fb_fix_screeninfo vesafb_fix = {
 	.id	= "VESA VGA",
 	.type	= FB_TYPE_PACKED_PIXELS,
 	.accel	= FB_ACCEL_NONE,
@@ -48,8 +48,8 @@ static struct fb_fix_screeninfo vesafb_fix __initdata = {
 
 static int   inverse    __read_mostly;
 static int   mtrr       __read_mostly;		/* disable mtrr */
-static int   vram_remap __initdata;		/* Set amount of memory to be used */
-static int   vram_total __initdata;		/* Set total amount of memory */
+static int   vram_remap;			/* Set amount of memory to be used */
+static int   vram_total;			/* Set total amount of memory */
 static int   pmi_setpal __read_mostly = 1;	/* pmi for palette changes ??? */
 static int   ypan       __read_mostly;		/* 0..nothing, 1..ypan, 2..ywrap */
 static void  (*pmi_start)(void) __read_mostly;
@@ -192,7 +192,7 @@ static struct fb_ops vesafb_ops = {
 	.fb_imageblit	= cfb_imageblit,
 };
 
-static int __init vesafb_setup(char *options)
+static int vesafb_setup(char *options)
 {
 	char *this_opt;
 	
@@ -226,13 +226,18 @@ static int __init vesafb_setup(char *options)
 	return 0;
 }
 
-static int __init vesafb_probe(struct platform_device *dev)
+static int vesafb_probe(struct platform_device *dev)
 {
 	struct fb_info *info;
 	int i, err;
 	unsigned int size_vmode;
 	unsigned int size_remap;
 	unsigned int size_total;
+	char *option = NULL;
+
+	/* ignore error return of fb_get_options */
+	fb_get_options("vesafb", &option);
+	vesafb_setup(option);
 
 	if (screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB)
 		return -ENODEV;
@@ -496,40 +501,12 @@ err:
 }
 
 static struct platform_driver vesafb_driver = {
-	.driver	= {
-		.name	= "vesafb",
+	.driver = {
+		.name = "vesa-framebuffer",
+		.owner = THIS_MODULE,
 	},
+	.probe = vesafb_probe,
 };
 
-static struct platform_device *vesafb_device;
-
-static int __init vesafb_init(void)
-{
-	int ret;
-	char *option = NULL;
-
-	/* ignore error return of fb_get_options */
-	fb_get_options("vesafb", &option);
-	vesafb_setup(option);
-
-	vesafb_device = platform_device_alloc("vesafb", 0);
-	if (!vesafb_device)
-		return -ENOMEM;
-
-	ret = platform_device_add(vesafb_device);
-	if (!ret) {
-		ret = platform_driver_probe(&vesafb_driver, vesafb_probe);
-		if (ret)
-			platform_device_del(vesafb_device);
-	}
-
-	if (ret) {
-		platform_device_put(vesafb_device);
-		vesafb_device = NULL;
-	}
-
-	return ret;
-}
-module_init(vesafb_init);
-
+module_platform_driver(vesafb_driver);
 MODULE_LICENSE("GPL");
-- 
1.8.3.2


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

* [PATCH v2 07/14] fbdev: efifb: bind to efi-framebuffer
  2013-07-04 12:25 [PATCH v2 00/14] Platform Framebuffers and SimpleDRM David Herrmann
                   ` (5 preceding siblings ...)
  2013-07-04 12:25 ` [PATCH v2 06/14] fbdev: vesafb: bind to platform-framebuffer device David Herrmann
@ 2013-07-04 12:25 ` David Herrmann
  2013-07-04 12:25 ` [PATCH v2 08/14] fbdev: fbcon: select VT_HW_CONSOLE_BINDING David Herrmann
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: David Herrmann @ 2013-07-04 12:25 UTC (permalink / raw)
  To: linux-kernel; +Cc: David Airlie, dri-devel, David Herrmann, Peter Jones

Instead of creating a dummy device, we now bind to the efi-fb device
which is provided by x86 initialization code.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/video/efifb.c | 68 +++++++++++++++++----------------------------------
 1 file changed, 22 insertions(+), 46 deletions(-)

diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c
index e493bcb..2a8286e 100644
--- a/drivers/video/efifb.c
+++ b/drivers/video/efifb.c
@@ -96,7 +96,7 @@ void vga_set_default_device(struct pci_dev *pdev)
 	default_vga = pdev;
 }
 
-static int __init efifb_setup(char *options)
+static int efifb_setup(char *options)
 {
 	char *this_opt;
 	int i;
@@ -153,13 +153,28 @@ static int __init efifb_setup(char *options)
 	return 0;
 }
 
-static int __init efifb_probe(struct platform_device *dev)
+static int efifb_probe(struct platform_device *dev)
 {
 	struct fb_info *info;
 	int err;
 	unsigned int size_vmode;
 	unsigned int size_remap;
 	unsigned int size_total;
+	char *option = NULL;
+
+	if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
+		return -ENODEV;
+
+	if (fb_get_options("efifb", &option))
+		return -ENODEV;
+	efifb_setup(option);
+
+	/* We don't get linelength from UGA Draw Protocol, only from
+	 * EFI Graphics Protocol.  So if it's not in DMI, and it's not
+	 * passed in from the user, we really can't use the framebuffer.
+	 */
+	if (!screen_info.lfb_linelength)
+		return -ENODEV;
 
 	if (!screen_info.lfb_depth)
 		screen_info.lfb_depth = 32;
@@ -323,51 +338,12 @@ err_release_mem:
 }
 
 static struct platform_driver efifb_driver = {
-	.driver	= {
-		.name	= "efifb",
+	.driver = {
+		.name = "efi-framebuffer",
+		.owner = THIS_MODULE,
 	},
+	.probe = efifb_probe,
 };
 
-static struct platform_device efifb_device = {
-	.name	= "efifb",
-};
-
-static int __init efifb_init(void)
-{
-	int ret;
-	char *option = NULL;
-
-	if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
-		return -ENODEV;
-
-	if (fb_get_options("efifb", &option))
-		return -ENODEV;
-	efifb_setup(option);
-
-	/* We don't get linelength from UGA Draw Protocol, only from
-	 * EFI Graphics Protocol.  So if it's not in DMI, and it's not
-	 * passed in from the user, we really can't use the framebuffer.
-	 */
-	if (!screen_info.lfb_linelength)
-		return -ENODEV;
-
-	ret = platform_device_register(&efifb_device);
-	if (ret)
-		return ret;
-
-	/*
-	 * This is not just an optimization.  We will interfere
-	 * with a real driver if we get reprobed, so don't allow
-	 * it.
-	 */
-	ret = platform_driver_probe(&efifb_driver, efifb_probe);
-	if (ret) {
-		platform_device_unregister(&efifb_device);
-		return ret;
-	}
-
-	return ret;
-}
-module_init(efifb_init);
-
+module_platform_driver(efifb_driver);
 MODULE_LICENSE("GPL");
-- 
1.8.3.2


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

* [PATCH v2 08/14] fbdev: fbcon: select VT_HW_CONSOLE_BINDING
  2013-07-04 12:25 [PATCH v2 00/14] Platform Framebuffers and SimpleDRM David Herrmann
                   ` (6 preceding siblings ...)
  2013-07-04 12:25 ` [PATCH v2 07/14] fbdev: efifb: bind to efi-framebuffer David Herrmann
@ 2013-07-04 12:25 ` David Herrmann
  2013-07-04 12:25 ` [PATCH v2 09/14] drm: add SimpleDRM driver David Herrmann
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: David Herrmann @ 2013-07-04 12:25 UTC (permalink / raw)
  To: linux-kernel
  Cc: David Airlie, dri-devel, David Herrmann, Tomi Valkeinen,
	Jean-Christophe Plagniol-Villard

fbdev provides framebuffer hotplugging, hence, we need to allow fbcon to
unbind from framebuffers. Unfortunately, fbcon_fb_unbind() cannot unbind
from the last framebuffer, unless console-unbinding is supported.

Fixing fbcon_unbind() to return 0 caused some horrible NULL-derefs in the
VT layer and I couldn't figure out why. Hence, lets just require
console-unbinding so fbdev hotplugging works with fbcon.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/video/console/Kconfig | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index bc922c4..538d700 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -89,7 +89,8 @@ config DUMMY_CONSOLE_ROWS
 
 config FRAMEBUFFER_CONSOLE
 	tristate "Framebuffer Console support"
-	depends on FB
+	depends on FB && !UML
+	select VT_HW_CONSOLE_BINDING
 	select CRC32
 	help
 	  Low-level framebuffer-based console driver.
-- 
1.8.3.2


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

* [PATCH v2 09/14] drm: add SimpleDRM driver
  2013-07-04 12:25 [PATCH v2 00/14] Platform Framebuffers and SimpleDRM David Herrmann
                   ` (7 preceding siblings ...)
  2013-07-04 12:25 ` [PATCH v2 08/14] fbdev: fbcon: select VT_HW_CONSOLE_BINDING David Herrmann
@ 2013-07-04 12:25 ` David Herrmann
  2013-07-04 12:25 ` [PATCH v2 10/14] drm: simpledrm: add fbdev fallback support David Herrmann
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: David Herrmann @ 2013-07-04 12:25 UTC (permalink / raw)
  To: linux-kernel; +Cc: David Airlie, dri-devel, 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 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>
---
 MAINTAINERS                                |   8 +
 drivers/gpu/drm/Kconfig                    |   2 +
 drivers/gpu/drm/Makefile                   |   1 +
 drivers/gpu/drm/simpledrm/Kconfig          |  18 ++
 drivers/gpu/drm/simpledrm/Makefile         |   5 +
 drivers/gpu/drm/simpledrm/simpledrm.h      |  89 ++++++++
 drivers/gpu/drm/simpledrm/simpledrm_drv.c  | 226 ++++++++++++++++++++
 drivers/gpu/drm/simpledrm/simpledrm_main.c | 328 +++++++++++++++++++++++++++++
 drivers/gpu/drm/simpledrm/simpledrm_mem.c  | 252 ++++++++++++++++++++++
 9 files changed, 929 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 ad7e322..b9aa4e4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7305,6 +7305,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 b16c50e..b3ccef6 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -220,3 +220,5 @@ source "drivers/gpu/drm/omapdrm/Kconfig"
 source "drivers/gpu/drm/tilcdc/Kconfig"
 
 source "drivers/gpu/drm/qxl/Kconfig"
+
+source "drivers/gpu/drm/simpledrm/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 1c9f2439..59c424d 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -52,4 +52,5 @@ obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
 obj-$(CONFIG_DRM_OMAP)	+= omapdrm/
 obj-$(CONFIG_DRM_TILCDC)	+= tilcdc/
 obj-$(CONFIG_DRM_QXL) += qxl/
+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..4f82844
--- /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
+	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..2d474a5
--- /dev/null
+++ b/drivers/gpu/drm/simpledrm/Makefile
@@ -0,0 +1,5 @@
+ccflags-y := -Iinclude/drm
+
+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..b774d5c
--- /dev/null
+++ b/drivers/gpu/drm/simpledrm/simpledrm_drv.c
@@ -0,0 +1,226 @@
+/*
+ * 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,
+	.fasync = drm_fasync,
+#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..ba89be4
--- /dev/null
+++ b/drivers/gpu/drm/simpledrm/simpledrm_mem.c
@@ -0,0 +1,252 @@
+/*
+ * 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;
+
+	if (drm_gem_private_object_init(ddev, &obj->base, fb_size)) {
+		kfree(obj);
+		return NULL;
+	}
+
+	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;
+	loff_t off;
+
+	off = obj->base.map_list.hash.key << PAGE_SHIFT;
+	unmap_mapping_range(ddev->dev_mapping, off, obj->fb_size, 1);
+}
+
+/*
+ * 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);
+
+	if (gobj->map_list.map)
+		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;
+	}
+
+	if (!gobj->map_list.map) {
+		ret = drm_gem_create_mmap_offset(gobj);
+		if (ret)
+			goto out_unref;
+	}
+
+	*offset = gobj->map_list.hash.key << PAGE_SHIFT;
+
+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_local_map *map;
+	struct drm_hash_item *item;
+	struct drm_gem_object *gobj;
+	struct sdrm_gem_object *obj;
+	unsigned long len;
+	int ret;
+
+	mutex_lock(&dev->struct_mutex);
+
+	if (drm_ht_find_item(&mm->offset_hash, vma->vm_pgoff, &item)) {
+		mutex_unlock(&dev->struct_mutex);
+		return drm_mmap(filp, vma);
+	}
+
+	map = drm_hash_entry(item, struct drm_map_list, hash)->map;
+	if (!map ||
+	    ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) {
+		ret =  -EPERM;
+		goto out_unlock;
+	}
+
+	gobj = map->handle;
+	obj = to_sdrm_bo(gobj);
+
+	vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
+	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? */
+
+	/* verify mapping size */
+	len = vma->vm_end - vma->vm_start;
+	if (len > obj->fb_size) {
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
+	/* This object is _not_ referenced here. Therefore, we _must_ destroy
+	 * the mapping before destroying the bo! */
+
+	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.3.2


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

* [PATCH v2 10/14] drm: simpledrm: add fbdev fallback support
  2013-07-04 12:25 [PATCH v2 00/14] Platform Framebuffers and SimpleDRM David Herrmann
                   ` (8 preceding siblings ...)
  2013-07-04 12:25 ` [PATCH v2 09/14] drm: add SimpleDRM driver David Herrmann
@ 2013-07-04 12:25 ` David Herrmann
  2013-07-04 12:25 ` [PATCH v2 11/14] drm: add helpers to kick out firmware drivers David Herrmann
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: David Herrmann @ 2013-07-04 12:25 UTC (permalink / raw)
  To: linux-kernel; +Cc: David Airlie, dri-devel, 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>
---
 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 4f82844..1ba585e 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 2d474a5..554d617 100644
--- a/drivers/gpu/drm/simpledrm/Makefile
+++ b/drivers/gpu/drm/simpledrm/Makefile
@@ -1,5 +1,6 @@
 ccflags-y := -Iinclude/drm
 
 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.3.2


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

* [PATCH v2 11/14] drm: add helpers to kick out firmware drivers
  2013-07-04 12:25 [PATCH v2 00/14] Platform Framebuffers and SimpleDRM David Herrmann
                   ` (9 preceding siblings ...)
  2013-07-04 12:25 ` [PATCH v2 10/14] drm: simpledrm: add fbdev fallback support David Herrmann
@ 2013-07-04 12:25 ` David Herrmann
  2013-07-04 12:25 ` [PATCH v2 12/14] drm: nouveau: kick out firmware drivers during probe David Herrmann
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: David Herrmann @ 2013-07-04 12:25 UTC (permalink / raw)
  To: linux-kernel; +Cc: David Airlie, dri-devel, David Herrmann

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>
---
 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 14194b6..4dcb2a4 100644
--- a/drivers/gpu/drm/drm_pci.c
+++ b/drivers/gpu/drm/drm_pci.c
@@ -366,6 +366,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 b8a282e..94923c8 100644
--- a/drivers/gpu/drm/drm_platform.c
+++ b/drivers/gpu/drm/drm_platform.c
@@ -88,6 +88,7 @@ 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 16f3ec5..9b7557e 100644
--- a/drivers/gpu/drm/drm_stub.c
+++ b/drivers/gpu/drm/drm_stub.c
@@ -46,6 +46,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.
@@ -484,7 +488,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);
 }
@@ -507,3 +513,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 34a156f..5ad8dba 100644
--- a/drivers/gpu/drm/drm_usb.c
+++ b/drivers/gpu/drm/drm_usb.c
@@ -50,6 +50,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 b774d5c..08f2286 100644
--- a/drivers/gpu/drm/simpledrm/simpledrm_drv.c
+++ b/drivers/gpu/drm/simpledrm/simpledrm_drv.c
@@ -34,9 +34,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 63d17ee..a19e710 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -47,6 +47,7 @@
 #include <linux/fs.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
+#include <linux/fb.h>
 #include <linux/file.h>
 #include <linux/platform_device.h>
 #include <linux/pci.h>
@@ -156,6 +157,7 @@ int drm_err(const char *func, const char *format, ...);
 #define DRIVER_GEM         0x1000
 #define DRIVER_MODESET     0x2000
 #define DRIVER_PRIME       0x4000
+#define DRIVER_FIRMWARE    0x8000
 
 #define DRIVER_BUS_PCI 0x1
 #define DRIVER_BUS_PLATFORM 0x2
@@ -954,6 +956,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;
 
@@ -1077,6 +1096,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
@@ -1532,6 +1554,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_vblank_offdelay;
-- 
1.8.3.2


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

* [PATCH v2 12/14] drm: nouveau: kick out firmware drivers during probe
  2013-07-04 12:25 [PATCH v2 00/14] Platform Framebuffers and SimpleDRM David Herrmann
                   ` (10 preceding siblings ...)
  2013-07-04 12:25 ` [PATCH v2 11/14] drm: add helpers to kick out firmware drivers David Herrmann
@ 2013-07-04 12:25 ` David Herrmann
  2013-07-04 12:25 ` [PATCH v2 13/14] drm/i915: use new drm_kick_out_firmware() David Herrmann
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: David Herrmann @ 2013-07-04 12:25 UTC (permalink / raw)
  To: linux-kernel; +Cc: David Airlie, dri-devel, David Herrmann

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

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 383f4e6..418867f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -233,13 +233,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);
@@ -265,8 +263,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);
@@ -294,9 +302,13 @@ 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;
 	lockdep_set_class(&drm->client.mutex, &drm_client_lock_class_key);
 
 	dev->dev_private = drm;
@@ -392,6 +404,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.3.2


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

* [PATCH v2 13/14] drm/i915: use new drm_kick_out_firmware()
  2013-07-04 12:25 [PATCH v2 00/14] Platform Framebuffers and SimpleDRM David Herrmann
                   ` (11 preceding siblings ...)
  2013-07-04 12:25 ` [PATCH v2 12/14] drm: nouveau: kick out firmware drivers during probe David Herrmann
@ 2013-07-04 12:25 ` David Herrmann
  2013-07-04 12:25 ` [PATCH v2 14/14] drm/radeon: " David Herrmann
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: David Herrmann @ 2013-07-04 12:25 UTC (permalink / raw)
  To: linux-kernel; +Cc: David Airlie, dri-devel, David Herrmann

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

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 3b315ba..d525b49 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1436,9 +1436,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.3.2


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

* [PATCH v2 14/14] drm/radeon: use new drm_kick_out_firmware()
  2013-07-04 12:25 [PATCH v2 00/14] Platform Framebuffers and SimpleDRM David Herrmann
                   ` (12 preceding siblings ...)
  2013-07-04 12:25 ` [PATCH v2 13/14] drm/i915: use new drm_kick_out_firmware() David Herrmann
@ 2013-07-04 12:25 ` David Herrmann
  2013-07-04 17:48 ` [PATCH v2 00/14] Platform Framebuffers and SimpleDRM H. Peter Anvin
  2013-07-09 21:02 ` Stephen Warren
  15 siblings, 0 replies; 23+ messages in thread
From: David Herrmann @ 2013-07-04 12:25 UTC (permalink / raw)
  To: linux-kernel; +Cc: David Airlie, dri-devel, David Herrmann

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

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 094e7e5..8ed3ab3 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -308,37 +308,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 4f2d4f4..f199b3c 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.3.2


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

* Re: [PATCH v2 00/14] Platform Framebuffers and SimpleDRM
  2013-07-04 12:25 [PATCH v2 00/14] Platform Framebuffers and SimpleDRM David Herrmann
                   ` (13 preceding siblings ...)
  2013-07-04 12:25 ` [PATCH v2 14/14] drm/radeon: " David Herrmann
@ 2013-07-04 17:48 ` H. Peter Anvin
  2013-07-05 13:09     ` David Herrmann
  2013-07-09 21:02 ` Stephen Warren
  15 siblings, 1 reply; 23+ messages in thread
From: H. Peter Anvin @ 2013-07-04 17:48 UTC (permalink / raw)
  To: David Herrmann
  Cc: linux-kernel, David Airlie, dri-devel, Geert Uytterhoeven,
	Stephen Warren, Peter Jones, Tomi Valkeinen,
	Jean-Christophe Plagniol-Villard, x86, Ingo Molnar,
	Thomas Gleixner

On 07/04/2013 05:25 AM, David Herrmann wrote:
>   - What FB formats are common on x86 that we should add to SIMPLEFB_FORMATS?
>     (other than ARGB/XRGB32)

The common pixel formats on x86 are:

- Palettized 4-bit planar (bigendian, i.e. MSB to the left)
- Palettized 8-bit packed (one byte per pixel)
- 16-bit RGB555 (16-bit littleendian words with R=14:10, G=9:5, B=4:0)
- 16-bit RGB565 (16-bit littleendian words with R=15:11, G=10:5, B=4:0)
- 24-bit RGB888 in littleendian order (first byte in memory is B,
   second is G, third is R)
- 32-bit ARGB8888 (first byte in memory is B, second G, third R, fourth
   unused in the framebuffer proper)
- 32-bit RGB10:10:10 (I *believe* 32-bit littleendian words with
   R=29:20, G=19:10, B=9:0)

	-hpa


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

* Re: [PATCH v2 00/14] Platform Framebuffers and SimpleDRM
  2013-07-04 17:48 ` [PATCH v2 00/14] Platform Framebuffers and SimpleDRM H. Peter Anvin
@ 2013-07-05 13:09     ` David Herrmann
  0 siblings, 0 replies; 23+ messages in thread
From: David Herrmann @ 2013-07-05 13:09 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: linux-kernel, David Airlie, dri-devel, Geert Uytterhoeven,
	Stephen Warren, Peter Jones, Tomi Valkeinen,
	Jean-Christophe Plagniol-Villard, x86, Ingo Molnar,
	Thomas Gleixner

Hi

On Thu, Jul 4, 2013 at 7:48 PM, H. Peter Anvin <hpa@zytor.com> wrote:
> On 07/04/2013 05:25 AM, David Herrmann wrote:
>>
>>   - What FB formats are common on x86 that we should add to
>> SIMPLEFB_FORMATS?
>>     (other than ARGB/XRGB32)
>
>
> The common pixel formats on x86 are:
>
> - Palettized 4-bit planar (bigendian, i.e. MSB to the left)
> - Palettized 8-bit packed (one byte per pixel)

Unlikely to be supported with DRM. But if users want it, we can always
add a shadow-buffer and advertise it as RGB332 or alike. Otherwise,
they have to use fbdev as usual, which sounds reasonable to me.

> - 16-bit RGB555 (16-bit littleendian words with R=14:10, G=9:5, B=4:0)

DRM_FORMAT_XRGB1555

> - 16-bit RGB565 (16-bit littleendian words with R=15:11, G=10:5, B=4:0)

DRM_FORMAT_RGB565

> - 24-bit RGB888 in littleendian order (first byte in memory is B,
>   second is G, third is R)

DRM_FORMAT_RGB888

> - 32-bit ARGB8888 (first byte in memory is B, second G, third R, fourth
>   unused in the framebuffer proper)

DRM_FORMAT_ARGB8888

> - 32-bit RGB10:10:10 (I *believe* 32-bit littleendian words with
>   R=29:20, G=19:10, B=9:0)

DRM_FORMAT_XRGB2101010

Thanks for the hints, I will add these to patch #5.
David

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

* Re: [PATCH v2 00/14] Platform Framebuffers and SimpleDRM
@ 2013-07-05 13:09     ` David Herrmann
  0 siblings, 0 replies; 23+ messages in thread
From: David Herrmann @ 2013-07-05 13:09 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Stephen Warren, Tomi Valkeinen, x86, linux-kernel, dri-devel,
	Peter Jones, Geert Uytterhoeven, Thomas Gleixner,
	Jean-Christophe Plagniol-Villard, Ingo Molnar

Hi

On Thu, Jul 4, 2013 at 7:48 PM, H. Peter Anvin <hpa@zytor.com> wrote:
> On 07/04/2013 05:25 AM, David Herrmann wrote:
>>
>>   - What FB formats are common on x86 that we should add to
>> SIMPLEFB_FORMATS?
>>     (other than ARGB/XRGB32)
>
>
> The common pixel formats on x86 are:
>
> - Palettized 4-bit planar (bigendian, i.e. MSB to the left)
> - Palettized 8-bit packed (one byte per pixel)

Unlikely to be supported with DRM. But if users want it, we can always
add a shadow-buffer and advertise it as RGB332 or alike. Otherwise,
they have to use fbdev as usual, which sounds reasonable to me.

> - 16-bit RGB555 (16-bit littleendian words with R=14:10, G=9:5, B=4:0)

DRM_FORMAT_XRGB1555

> - 16-bit RGB565 (16-bit littleendian words with R=15:11, G=10:5, B=4:0)

DRM_FORMAT_RGB565

> - 24-bit RGB888 in littleendian order (first byte in memory is B,
>   second is G, third is R)

DRM_FORMAT_RGB888

> - 32-bit ARGB8888 (first byte in memory is B, second G, third R, fourth
>   unused in the framebuffer proper)

DRM_FORMAT_ARGB8888

> - 32-bit RGB10:10:10 (I *believe* 32-bit littleendian words with
>   R=29:20, G=19:10, B=9:0)

DRM_FORMAT_XRGB2101010

Thanks for the hints, I will add these to patch #5.
David

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

* Re: [PATCH v2 00/14] Platform Framebuffers and SimpleDRM
  2013-07-04 12:25 [PATCH v2 00/14] Platform Framebuffers and SimpleDRM David Herrmann
                   ` (14 preceding siblings ...)
  2013-07-04 17:48 ` [PATCH v2 00/14] Platform Framebuffers and SimpleDRM H. Peter Anvin
@ 2013-07-09 21:02 ` Stephen Warren
  2013-07-10 17:28   ` David Herrmann
  15 siblings, 1 reply; 23+ messages in thread
From: Stephen Warren @ 2013-07-09 21:02 UTC (permalink / raw)
  To: David Herrmann
  Cc: linux-kernel, David Airlie, dri-devel, Geert Uytterhoeven,
	Peter Jones, Tomi Valkeinen, Jean-Christophe Plagniol-Villard,
	x86, H. Peter Anvin, Ingo Molnar, Thomas Gleixner

On 07/04/2013 06:25 AM, David Herrmann wrote:
> Hi
> 
> This series changes the way we handle firmware framebuffers on x86 systems. On
> other architectures the recently introduced "simple-framebuffer"
> platform-devices provide a sane and proper way to handle firmware framebuffers.
> So why not use it on x86, too?

Tested-by: Stephen Warren <swarren@nvidia.com>

(This time I didn't see any issue with the FB content being blank; I
must have forgotten a console= command-line parameter or something the
last time around)

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

* Re: [PATCH v2 01/14] fbdev: simplefb: add init through platform_data
  2013-07-04 12:25 ` [PATCH v2 01/14] fbdev: simplefb: add init through platform_data David Herrmann
@ 2013-07-09 21:17   ` Stephen Warren
  0 siblings, 0 replies; 23+ messages in thread
From: Stephen Warren @ 2013-07-09 21:17 UTC (permalink / raw)
  To: David Herrmann; +Cc: linux-kernel, David Airlie, dri-devel

On 07/04/2013 06:25 AM, David Herrmann wrote:
> If we create proper platform-devices in x86 boot-code, we can use simplefb
> for VBE or EFI framebuffers, too. However, there is normally no OF support
> so we introduce a platform_data object so x86 boot-code can pass the
> parameters via plain old platform-data.
> 
> This also removes the OF dependency as it is not needed. The headers
> provide proper dummies for the case OF is disabled.
> 
> Furthermore, we move the FORMAT-definitions to the common platform header
> so initialization code can use it to transform "struct screen_info" to
> the right format-name.

Patches 1 and 5,
Reviewed-by: Stephen Warren <swarren@nvidia.com>

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

* Re: [PATCH v2 00/14] Platform Framebuffers and SimpleDRM
  2013-07-09 21:02 ` Stephen Warren
@ 2013-07-10 17:28   ` David Herrmann
  0 siblings, 0 replies; 23+ messages in thread
From: David Herrmann @ 2013-07-10 17:28 UTC (permalink / raw)
  To: Stephen Warren
  Cc: linux-kernel, David Airlie, dri-devel, Geert Uytterhoeven,
	Peter Jones, Tomi Valkeinen, Jean-Christophe Plagniol-Villard,
	x86, H. Peter Anvin, Ingo Molnar, Thomas Gleixner

Hi

On Tue, Jul 9, 2013 at 11:02 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 07/04/2013 06:25 AM, David Herrmann wrote:
>> Hi
>>
>> This series changes the way we handle firmware framebuffers on x86 systems. On
>> other architectures the recently introduced "simple-framebuffer"
>> platform-devices provide a sane and proper way to handle firmware framebuffers.
>> So why not use it on x86, too?
>
> Tested-by: Stephen Warren <swarren@nvidia.com>
>
> (This time I didn't see any issue with the FB content being blank; I
> must have forgotten a console= command-line parameter or something the
> last time around)

I think I had some error in the pseudo_palette handling (which I now
copied from simplefb.c), but I am not sure why it didn't work in v1.
Thanks a lot for testing!

Regards
David

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

* Re: [PATCH v2 03/14] x86: provide platform-devices for boot-framebuffers
  2013-07-04 12:25   ` David Herrmann
  (?)
@ 2013-07-17 17:40   ` David Herrmann
  -1 siblings, 0 replies; 23+ messages in thread
From: David Herrmann @ 2013-07-17 17:40 UTC (permalink / raw)
  To: linux-kernel
  Cc: David Airlie, dri-devel, David Herrmann, x86, H. Peter Anvin,
	Ingo Molnar, Thomas Gleixner

Hi

Any comments on this?

On Thu, Jul 4, 2013 at 2:25 PM, David Herrmann <dh.herrmann@gmail.com> wrote:
> The current situation regarding boot-framebuffers (VGA, VESA/VBE, EFI) on
> x86 causes troubles when loading multiple fbdev drivers. The global
> "struct screen_info" does not provide any state-tracking about which
> drivers use the FBs. request_mem_region() theoretically works, but
> unfortunately vesafb/efifb ignore it due to quirks for broken boards.
>
> Avoid this by creating a platform framebuffer devices with a pointer
> to the "struct screen_info" as platform-data. Drivers can now create
> platform-drivers and the driver-core will refuse multiple drivers being
> active simultaneously.
>
> We keep the screen_info available for backwards-compatibility. Drivers
> can be converted in follow-up patches.
>
> Different devices are created for VGA/VESA/EFI FBs to allow multiple
> drivers to be loaded on distro kernels. We create:
>  - "vesa-framebuffer" for VBE/VESA graphics FBs
>  - "efi-framebuffer" for EFI FBs
>  - "platform-framebuffer" for everything else
> This allows to load vesafb, efifb and others simultaneously and each
> picks up only the supported FB types.
>
> Apart from platform-framebuffer devices, this also introduces a
> compatibility option for "simple-framebuffer" drivers which recently got
> introduced for OF based systems. If CONFIG_X86_SYSFB is selected, we
> try to match the screen_info against a simple-framebuffer supported
> format. If we succeed, we create a "simple-framebuffer" device instead
> of a platform-framebuffer.
> This allows to reuse the simplefb.c driver across architectures and also
> to introduce a SimpleDRM driver. There is no need to have vesafb.c,
> efifb.c, simplefb.c and more just to have architecture specific quirks
> in their setup-routines.
>
> Instead, we now move the architecture specific quirks into x86-setup and
> provide a generic simple-framebuffer. For backwards-compatibility (if
> strange formats are used), we still allow vesafb/efifb to be loaded
> simultaneously and pick up all remaining devices.
>
> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
> ---
>  arch/x86/Kconfig                 | 26 +++++++++++
>  arch/x86/include/asm/sysfb.h     | 41 +++++++++++++++++
>  arch/x86/kernel/Makefile         |  2 +
>  arch/x86/kernel/sysfb.c          | 71 ++++++++++++++++++++++++++++++
>  arch/x86/kernel/sysfb_simplefb.c | 95 ++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 235 insertions(+)
>  create mode 100644 arch/x86/include/asm/sysfb.h
>  create mode 100644 arch/x86/kernel/sysfb.c
>  create mode 100644 arch/x86/kernel/sysfb_simplefb.c
>
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index fe120da..54a93a5 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -2255,6 +2255,32 @@ config RAPIDIO
>
>  source "drivers/rapidio/Kconfig"
>
> +config X86_SYSFB
> +       bool "Mark VGA/VBE/EFI FB as generic system framebuffer"
> +       help
> +         Firmwares often provide initial graphics framebuffers so the BIOS,
> +         bootloader or kernel can show basic video-output during boot for
> +         user-guidance and debugging. Historically, x86 used the VESA BIOS
> +         Extensions and EFI-framebuffers for this, which are mostly limited
> +         to x86.
> +         This option, if enabled, marks VGA/VBE/EFI framebuffers as generic
> +         framebuffers so the new generic system-framebuffer drivers can be
> +         used on x86. If the framebuffer is not compatible with the generic
> +         modes, it is adverticed as fallback platform framebuffer so legacy
> +         drivers like efifb, vesafb and uvesafb can pick it up.
> +         If this option is not selected, all system framebuffers are always
> +         marked as fallback platform framebuffers as usual.
> +
> +         Note: Legacy fbdev drivers, including vesafb, efifb, uvesafb, will
> +         not be able to pick up generic system framebuffers if this option
> +         is selected. You are highly encouraged to enable simplefb as
> +         replacement if you select this option. simplefb can correctly deal
> +         with generic system framebuffers. But you should still keep vesafb
> +         and others enabled as fallback if a system framebuffer is
> +         incompatible with simplefb.
> +
> +         If unsure, say Y.
> +
>  endmenu
>
>
> diff --git a/arch/x86/include/asm/sysfb.h b/arch/x86/include/asm/sysfb.h
> new file mode 100644
> index 0000000..2395fe0
> --- /dev/null
> +++ b/arch/x86/include/asm/sysfb.h
> @@ -0,0 +1,41 @@
> +#ifndef _ARCH_X86_KERNEL_SYSFB_H
> +#define _ARCH_X86_KERNEL_SYSFB_H
> +
> +/*
> + * Generic System Framebuffers on x86
> + * 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/kernel.h>
> +#include <linux/platform_data/simplefb.h>
> +#include <linux/screen_info.h>
> +
> +#ifdef CONFIG_X86_SYSFB
> +
> +bool parse_mode(const struct screen_info *si,
> +               struct simplefb_platform_data *mode);
> +int create_simplefb(const struct screen_info *si,
> +                   const struct simplefb_platform_data *mode);
> +
> +#else /* CONFIG_X86_SYSFB */
> +
> +static inline bool parse_mode(const struct screen_info *si,
> +                             struct simplefb_platform_data *mode)
> +{
> +       return false;
> +}
> +
> +static inline int create_simplefb(const struct screen_info *si,
> +                                 const struct simplefb_platform_data *mode)
> +{
> +       return -EINVAL;
> +}
> +
> +#endif /* CONFIG_X86_SYSFB */
> +
> +#endif /* _ARCH_X86_KERNEL_SYSFB_H */
> diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
> index 7bd3bd3..c5e7677 100644
> --- a/arch/x86/kernel/Makefile
> +++ b/arch/x86/kernel/Makefile
> @@ -100,6 +100,8 @@ obj-$(CONFIG_X86_CHECK_BIOS_CORRUPTION) += check.o
>  obj-$(CONFIG_SWIOTLB)                  += pci-swiotlb.o
>  obj-$(CONFIG_OF)                       += devicetree.o
>  obj-$(CONFIG_UPROBES)                  += uprobes.o
> +obj-y                                  += sysfb.o
> +obj-$(CONFIG_X86_SYSFB)                        += sysfb_simplefb.o
>
>  obj-$(CONFIG_PERF_EVENTS)              += perf_regs.o
>
> diff --git a/arch/x86/kernel/sysfb.c b/arch/x86/kernel/sysfb.c
> new file mode 100644
> index 0000000..7f30e19
> --- /dev/null
> +++ b/arch/x86/kernel/sysfb.c
> @@ -0,0 +1,71 @@
> +/*
> + * Generic System Framebuffers on x86
> + * 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.
> + */
> +
> +/*
> + * Simple-Framebuffer support for x86 systems
> + * Create a platform-device for any available boot framebuffer. The
> + * simple-framebuffer platform device is already available on DT systems, so
> + * this module parses the global "screen_info" object and creates a suitable
> + * platform device compatible with the "simple-framebuffer" DT object. If
> + * the framebuffer is incompatible, we instead create a legacy
> + * "vesa-framebuffer", "efi-framebuffer" or "platform-framebuffer" device and
> + * pass the screen_info as platform_data. This allows legacy drivers
> + * to pick these devices up without messing with simple-framebuffer drivers.
> + * The global "screen_info" is still valid at all times.
> + *
> + * If CONFIG_X86_SYSFB is not selected, we never register "simple-framebuffer"
> + * platform devices, but only use legacy framebuffer devices for
> + * backwards compatibility.
> + *
> + * TODO: We set the dev_id field of all platform-devices to 0. This allows
> + * other x86 OF/DT parsers to create such devices, too. However, they must
> + * start at offset 1 for this to work.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/mm.h>
> +#include <linux/platform_data/simplefb.h>
> +#include <linux/platform_device.h>
> +#include <linux/screen_info.h>
> +#include <asm/sysfb.h>
> +
> +static __init int sysfb_init(void)
> +{
> +       struct screen_info *si = &screen_info;
> +       struct simplefb_platform_data mode;
> +       struct platform_device *pd;
> +       const char *name;
> +       bool compatible;
> +       int ret;
> +
> +       /* try to create a simple-framebuffer device */
> +       compatible = parse_mode(si, &mode);
> +       if (compatible) {
> +               ret = create_simplefb(si, &mode);
> +               if (!ret)
> +                       return 0;
> +       }
> +
> +       /* if the FB is incompatible, create a legacy framebuffer device */
> +       if (si->orig_video_isVGA == VIDEO_TYPE_EFI)
> +               name = "efi-framebuffer";
> +       else if (si->orig_video_isVGA == VIDEO_TYPE_VLFB)
> +               name = "vesa-framebuffer";
> +       else
> +               name = "platform-framebuffer";
> +
> +       pd = platform_device_register_resndata(NULL, name, 0,
> +                                              NULL, 0, si, sizeof(*si));
> +       return IS_ERR(pd) ? PTR_ERR(pd) : 0;
> +}
> +
> +device_initcall(sysfb_init);
> diff --git a/arch/x86/kernel/sysfb_simplefb.c b/arch/x86/kernel/sysfb_simplefb.c
> new file mode 100644
> index 0000000..22513e9
> --- /dev/null
> +++ b/arch/x86/kernel/sysfb_simplefb.c
> @@ -0,0 +1,95 @@
> +/*
> + * Generic System Framebuffers on x86
> + * 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.
> + */
> +
> +/*
> + * simple-framebuffer probing
> + * Try to convert "screen_info" into a "simple-framebuffer" compatible mode.
> + * If the mode is incompatible, we return "false" and let the caller create
> + * legacy nodes instead.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/mm.h>
> +#include <linux/platform_data/simplefb.h>
> +#include <linux/platform_device.h>
> +#include <linux/screen_info.h>
> +#include <asm/sysfb.h>
> +
> +static const char simplefb_resname[] = "BOOTFB";
> +static const struct simplefb_format formats[] = SIMPLEFB_FORMATS;
> +
> +/* try parsing x86 screen_info into a simple-framebuffer mode struct */
> +__init bool parse_mode(const struct screen_info *si,
> +                      struct simplefb_platform_data *mode)
> +{
> +       const struct simplefb_format *f;
> +       __u8 type;
> +       unsigned int i;
> +
> +       type = si->orig_video_isVGA;
> +       if (type != VIDEO_TYPE_VLFB && type != VIDEO_TYPE_EFI)
> +               return false;
> +
> +       for (i = 0; i < ARRAY_SIZE(formats); ++i) {
> +               f = &formats[i];
> +               if (si->lfb_depth == f->bits_per_pixel &&
> +                   si->red_size == f->red.length &&
> +                   si->red_pos == f->red.offset &&
> +                   si->green_size == f->green.length &&
> +                   si->green_pos == f->green.offset &&
> +                   si->blue_size == f->blue.length &&
> +                   si->blue_pos == f->blue.offset &&
> +                   si->rsvd_size == f->transp.length &&
> +                   si->rsvd_pos == f->transp.offset) {
> +                       mode->format = f->name;
> +                       mode->width = si->lfb_width;
> +                       mode->height = si->lfb_height;
> +                       mode->stride = si->lfb_linelength;
> +                       return true;
> +               }
> +       }
> +
> +       return false;
> +}
> +
> +__init int create_simplefb(const struct screen_info *si,
> +                          const struct simplefb_platform_data *mode)
> +{
> +       struct platform_device *pd;
> +       struct resource res;
> +       unsigned long len;
> +
> +       /* 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 > si->lfb_size << 16) {
> +               printk(KERN_WARNING "sysfb: VRAM smaller than advertised\n");
> +               return -EINVAL;
> +       }
> +
> +       /* setup IORESOURCE_MEM as framebuffer memory */
> +       memset(&res, 0, sizeof(res));
> +       res.flags = IORESOURCE_MEM;
> +       res.name = simplefb_resname;
> +       res.start = si->lfb_base;
> +       res.end = si->lfb_base + len - 1;
> +       if (res.end <= res.start)
> +               return -EINVAL;
> +
> +       pd = platform_device_register_resndata(NULL, "simple-framebuffer", 0,
> +                                              &res, 1, mode, sizeof(*mode));
> +       if (IS_ERR(pd))
> +               return PTR_ERR(pd);
> +
> +       return 0;
> +}
> --
> 1.8.3.2
>

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

end of thread, other threads:[~2013-07-17 17:40 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-07-04 12:25 [PATCH v2 00/14] Platform Framebuffers and SimpleDRM David Herrmann
2013-07-04 12:25 ` [PATCH v2 01/14] fbdev: simplefb: add init through platform_data David Herrmann
2013-07-09 21:17   ` Stephen Warren
2013-07-04 12:25 ` [PATCH v2 02/14] fbdev: simplefb: mark as fw and allocate apertures David Herrmann
2013-07-04 12:25 ` [PATCH v2 03/14] x86: provide platform-devices for boot-framebuffers David Herrmann
2013-07-04 12:25   ` David Herrmann
2013-07-17 17:40   ` David Herrmann
2013-07-04 12:25 ` [PATCH v2 04/14] x86: sysfb: move EFI quirks from efifb to sysfb David Herrmann
2013-07-04 12:25 ` [PATCH v2 05/14] fbdev: simplefb: add 32bit RGB formats David Herrmann
2013-07-04 12:25 ` [PATCH v2 06/14] fbdev: vesafb: bind to platform-framebuffer device David Herrmann
2013-07-04 12:25 ` [PATCH v2 07/14] fbdev: efifb: bind to efi-framebuffer David Herrmann
2013-07-04 12:25 ` [PATCH v2 08/14] fbdev: fbcon: select VT_HW_CONSOLE_BINDING David Herrmann
2013-07-04 12:25 ` [PATCH v2 09/14] drm: add SimpleDRM driver David Herrmann
2013-07-04 12:25 ` [PATCH v2 10/14] drm: simpledrm: add fbdev fallback support David Herrmann
2013-07-04 12:25 ` [PATCH v2 11/14] drm: add helpers to kick out firmware drivers David Herrmann
2013-07-04 12:25 ` [PATCH v2 12/14] drm: nouveau: kick out firmware drivers during probe David Herrmann
2013-07-04 12:25 ` [PATCH v2 13/14] drm/i915: use new drm_kick_out_firmware() David Herrmann
2013-07-04 12:25 ` [PATCH v2 14/14] drm/radeon: " David Herrmann
2013-07-04 17:48 ` [PATCH v2 00/14] Platform Framebuffers and SimpleDRM H. Peter Anvin
2013-07-05 13:09   ` David Herrmann
2013-07-05 13:09     ` David Herrmann
2013-07-09 21:02 ` Stephen Warren
2013-07-10 17:28   ` David Herrmann

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.