aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@gmail.com>2013-08-02 08:05:22 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2013-08-02 19:17:46 -0400
commite3263ab389a7bc9398c3d366819d6f39b9cfd677 (patch)
treeaa42182804337d3a491f16a5d581e1102a110858
parentdf0960ab2d95543a7c162b04b2064991666adbad (diff)
x86: provide platform-devices for boot-framebuffers
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> Link: http://lkml.kernel.org/r/1375445127-15480-4-git-send-email-dh.herrmann@gmail.com Tested-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
-rw-r--r--arch/x86/Kconfig26
-rw-r--r--arch/x86/include/asm/sysfb.h41
-rw-r--r--arch/x86/kernel/Makefile2
-rw-r--r--arch/x86/kernel/sysfb.c71
-rw-r--r--arch/x86/kernel/sysfb_simplefb.c95
5 files changed, 235 insertions, 0 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index b32ebf92b0ce..5c56559e0c50 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2270,6 +2270,32 @@ config RAPIDIO
2270 2270
2271source "drivers/rapidio/Kconfig" 2271source "drivers/rapidio/Kconfig"
2272 2272
2273config X86_SYSFB
2274 bool "Mark VGA/VBE/EFI FB as generic system framebuffer"
2275 help
2276 Firmwares often provide initial graphics framebuffers so the BIOS,
2277 bootloader or kernel can show basic video-output during boot for
2278 user-guidance and debugging. Historically, x86 used the VESA BIOS
2279 Extensions and EFI-framebuffers for this, which are mostly limited
2280 to x86.
2281 This option, if enabled, marks VGA/VBE/EFI framebuffers as generic
2282 framebuffers so the new generic system-framebuffer drivers can be
2283 used on x86. If the framebuffer is not compatible with the generic
2284 modes, it is adverticed as fallback platform framebuffer so legacy
2285 drivers like efifb, vesafb and uvesafb can pick it up.
2286 If this option is not selected, all system framebuffers are always
2287 marked as fallback platform framebuffers as usual.
2288
2289 Note: Legacy fbdev drivers, including vesafb, efifb, uvesafb, will
2290 not be able to pick up generic system framebuffers if this option
2291 is selected. You are highly encouraged to enable simplefb as
2292 replacement if you select this option. simplefb can correctly deal
2293 with generic system framebuffers. But you should still keep vesafb
2294 and others enabled as fallback if a system framebuffer is
2295 incompatible with simplefb.
2296
2297 If unsure, say Y.
2298
2273endmenu 2299endmenu
2274 2300
2275 2301
diff --git a/arch/x86/include/asm/sysfb.h b/arch/x86/include/asm/sysfb.h
new file mode 100644
index 000000000000..2395fe03f56b
--- /dev/null
+++ b/arch/x86/include/asm/sysfb.h
@@ -0,0 +1,41 @@
1#ifndef _ARCH_X86_KERNEL_SYSFB_H
2#define _ARCH_X86_KERNEL_SYSFB_H
3
4/*
5 * Generic System Framebuffers on x86
6 * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the Free
10 * Software Foundation; either version 2 of the License, or (at your option)
11 * any later version.
12 */
13
14#include <linux/kernel.h>
15#include <linux/platform_data/simplefb.h>
16#include <linux/screen_info.h>
17
18#ifdef CONFIG_X86_SYSFB
19
20bool parse_mode(const struct screen_info *si,
21 struct simplefb_platform_data *mode);
22int create_simplefb(const struct screen_info *si,
23 const struct simplefb_platform_data *mode);
24
25#else /* CONFIG_X86_SYSFB */
26
27static inline bool parse_mode(const struct screen_info *si,
28 struct simplefb_platform_data *mode)
29{
30 return false;
31}
32
33static inline int create_simplefb(const struct screen_info *si,
34 const struct simplefb_platform_data *mode)
35{
36 return -EINVAL;
37}
38
39#endif /* CONFIG_X86_SYSFB */
40
41#endif /* _ARCH_X86_KERNEL_SYSFB_H */
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 88d99ea77723..90ecdc5d471a 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -103,6 +103,8 @@ obj-$(CONFIG_X86_CHECK_BIOS_CORRUPTION) += check.o
103obj-$(CONFIG_SWIOTLB) += pci-swiotlb.o 103obj-$(CONFIG_SWIOTLB) += pci-swiotlb.o
104obj-$(CONFIG_OF) += devicetree.o 104obj-$(CONFIG_OF) += devicetree.o
105obj-$(CONFIG_UPROBES) += uprobes.o 105obj-$(CONFIG_UPROBES) += uprobes.o
106obj-y += sysfb.o
107obj-$(CONFIG_X86_SYSFB) += sysfb_simplefb.o
106 108
107obj-$(CONFIG_PERF_EVENTS) += perf_regs.o 109obj-$(CONFIG_PERF_EVENTS) += perf_regs.o
108obj-$(CONFIG_TRACING) += tracepoint.o 110obj-$(CONFIG_TRACING) += tracepoint.o
diff --git a/arch/x86/kernel/sysfb.c b/arch/x86/kernel/sysfb.c
new file mode 100644
index 000000000000..7f30e194eb52
--- /dev/null
+++ b/arch/x86/kernel/sysfb.c
@@ -0,0 +1,71 @@
1/*
2 * Generic System Framebuffers on x86
3 * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
8 * any later version.
9 */
10
11/*
12 * Simple-Framebuffer support for x86 systems
13 * Create a platform-device for any available boot framebuffer. The
14 * simple-framebuffer platform device is already available on DT systems, so
15 * this module parses the global "screen_info" object and creates a suitable
16 * platform device compatible with the "simple-framebuffer" DT object. If
17 * the framebuffer is incompatible, we instead create a legacy
18 * "vesa-framebuffer", "efi-framebuffer" or "platform-framebuffer" device and
19 * pass the screen_info as platform_data. This allows legacy drivers
20 * to pick these devices up without messing with simple-framebuffer drivers.
21 * The global "screen_info" is still valid at all times.
22 *
23 * If CONFIG_X86_SYSFB is not selected, we never register "simple-framebuffer"
24 * platform devices, but only use legacy framebuffer devices for
25 * backwards compatibility.
26 *
27 * TODO: We set the dev_id field of all platform-devices to 0. This allows
28 * other x86 OF/DT parsers to create such devices, too. However, they must
29 * start at offset 1 for this to work.
30 */
31
32#include <linux/err.h>
33#include <linux/init.h>
34#include <linux/kernel.h>
35#include <linux/mm.h>
36#include <linux/platform_data/simplefb.h>
37#include <linux/platform_device.h>
38#include <linux/screen_info.h>
39#include <asm/sysfb.h>
40
41static __init int sysfb_init(void)
42{
43 struct screen_info *si = &screen_info;
44 struct simplefb_platform_data mode;
45 struct platform_device *pd;
46 const char *name;
47 bool compatible;
48 int ret;
49
50 /* try to create a simple-framebuffer device */
51 compatible = parse_mode(si, &mode);
52 if (compatible) {
53 ret = create_simplefb(si, &mode);
54 if (!ret)
55 return 0;
56 }
57
58 /* if the FB is incompatible, create a legacy framebuffer device */
59 if (si->orig_video_isVGA == VIDEO_TYPE_EFI)
60 name = "efi-framebuffer";
61 else if (si->orig_video_isVGA == VIDEO_TYPE_VLFB)
62 name = "vesa-framebuffer";
63 else
64 name = "platform-framebuffer";
65
66 pd = platform_device_register_resndata(NULL, name, 0,
67 NULL, 0, si, sizeof(*si));
68 return IS_ERR(pd) ? PTR_ERR(pd) : 0;
69}
70
71device_initcall(sysfb_init);
diff --git a/arch/x86/kernel/sysfb_simplefb.c b/arch/x86/kernel/sysfb_simplefb.c
new file mode 100644
index 000000000000..22513e96b012
--- /dev/null
+++ b/arch/x86/kernel/sysfb_simplefb.c
@@ -0,0 +1,95 @@
1/*
2 * Generic System Framebuffers on x86
3 * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
8 * any later version.
9 */
10
11/*
12 * simple-framebuffer probing
13 * Try to convert "screen_info" into a "simple-framebuffer" compatible mode.
14 * If the mode is incompatible, we return "false" and let the caller create
15 * legacy nodes instead.
16 */
17
18#include <linux/err.h>
19#include <linux/init.h>
20#include <linux/kernel.h>
21#include <linux/mm.h>
22#include <linux/platform_data/simplefb.h>
23#include <linux/platform_device.h>
24#include <linux/screen_info.h>
25#include <asm/sysfb.h>
26
27static const char simplefb_resname[] = "BOOTFB";
28static const struct simplefb_format formats[] = SIMPLEFB_FORMATS;
29
30/* try parsing x86 screen_info into a simple-framebuffer mode struct */
31__init bool parse_mode(const struct screen_info *si,
32 struct simplefb_platform_data *mode)
33{
34 const struct simplefb_format *f;
35 __u8 type;
36 unsigned int i;
37
38 type = si->orig_video_isVGA;
39 if (type != VIDEO_TYPE_VLFB && type != VIDEO_TYPE_EFI)
40 return false;
41
42 for (i = 0; i < ARRAY_SIZE(formats); ++i) {
43 f = &formats[i];
44 if (si->lfb_depth == f->bits_per_pixel &&
45 si->red_size == f->red.length &&
46 si->red_pos == f->red.offset &&
47 si->green_size == f->green.length &&
48 si->green_pos == f->green.offset &&
49 si->blue_size == f->blue.length &&
50 si->blue_pos == f->blue.offset &&
51 si->rsvd_size == f->transp.length &&
52 si->rsvd_pos == f->transp.offset) {
53 mode->format = f->name;
54 mode->width = si->lfb_width;
55 mode->height = si->lfb_height;
56 mode->stride = si->lfb_linelength;
57 return true;
58 }
59 }
60
61 return false;
62}
63
64__init int create_simplefb(const struct screen_info *si,
65 const struct simplefb_platform_data *mode)
66{
67 struct platform_device *pd;
68 struct resource res;
69 unsigned long len;
70
71 /* don't use lfb_size as it may contain the whole VMEM instead of only
72 * the part that is occupied by the framebuffer */
73 len = mode->height * mode->stride;
74 len = PAGE_ALIGN(len);
75 if (len > si->lfb_size << 16) {
76 printk(KERN_WARNING "sysfb: VRAM smaller than advertised\n");
77 return -EINVAL;
78 }
79
80 /* setup IORESOURCE_MEM as framebuffer memory */
81 memset(&res, 0, sizeof(res));
82 res.flags = IORESOURCE_MEM;
83 res.name = simplefb_resname;
84 res.start = si->lfb_base;
85 res.end = si->lfb_base + len - 1;
86 if (res.end <= res.start)
87 return -EINVAL;
88
89 pd = platform_device_register_resndata(NULL, "simple-framebuffer", 0,
90 &res, 1, mode, sizeof(*mode));
91 if (IS_ERR(pd))
92 return PTR_ERR(pd);
93
94 return 0;
95}