aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-09-04 12:12:17 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-09-04 12:12:17 -0400
commit228abe73ad67665d71eacd6a8a347dd76b0115ae (patch)
treedfa4e0d394aab9b54ed1662eb611ea8e1904ac58
parent1f9c52e16b5f67131440ddd51bd0cff27e45ea10 (diff)
parent765d5b9c2b72f5b99722cdfcf4bf8f88c556cf92 (diff)
Merge branch 'x86-fb-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 fb changes from Ingo Molnar: "This tree includes preparatory patches for SimpleDRM driver support, by David Herrmann. They clean up x86 framebuffer support by creating simplefb devices wherever possible. More background can be found at http://lwn.net/Articles/558104/" * 'x86-fb-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: fbdev: fbcon: select VT_HW_CONSOLE_BINDING fbdev: efifb: bind to efi-framebuffer fbdev: vesafb: bind to platform-framebuffer device fbdev: simplefb: add common x86 RGB formats x86: sysfb: move EFI quirks from efifb to sysfb x86: provide platform-devices for boot-framebuffers fbdev: simplefb: mark as fw and allocate apertures fbdev: simplefb: add init through platform_data
-rw-r--r--arch/x86/Kconfig26
-rw-r--r--arch/x86/include/asm/sysfb.h98
-rw-r--r--arch/x86/kernel/Makefile3
-rw-r--r--arch/x86/kernel/sysfb.c74
-rw-r--r--arch/x86/kernel/sysfb_efi.c214
-rw-r--r--arch/x86/kernel/sysfb_simplefb.c95
-rw-r--r--drivers/video/Kconfig5
-rw-r--r--drivers/video/console/Kconfig3
-rw-r--r--drivers/video/efifb.c302
-rw-r--r--drivers/video/simplefb.c58
-rw-r--r--drivers/video/vesafb.c55
-rw-r--r--include/linux/platform_data/simplefb.h63
12 files changed, 666 insertions, 330 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index f16fc34e6608..ff47e230d355 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..2aeb3e25579c
--- /dev/null
+++ b/arch/x86/include/asm/sysfb.h
@@ -0,0 +1,98 @@
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
18enum {
19 M_I17, /* 17-Inch iMac */
20 M_I20, /* 20-Inch iMac */
21 M_I20_SR, /* 20-Inch iMac (Santa Rosa) */
22 M_I24, /* 24-Inch iMac */
23 M_I24_8_1, /* 24-Inch iMac, 8,1th gen */
24 M_I24_10_1, /* 24-Inch iMac, 10,1th gen */
25 M_I27_11_1, /* 27-Inch iMac, 11,1th gen */
26 M_MINI, /* Mac Mini */
27 M_MINI_3_1, /* Mac Mini, 3,1th gen */
28 M_MINI_4_1, /* Mac Mini, 4,1th gen */
29 M_MB, /* MacBook */
30 M_MB_2, /* MacBook, 2nd rev. */
31 M_MB_3, /* MacBook, 3rd rev. */
32 M_MB_5_1, /* MacBook, 5th rev. */
33 M_MB_6_1, /* MacBook, 6th rev. */
34 M_MB_7_1, /* MacBook, 7th rev. */
35 M_MB_SR, /* MacBook, 2nd gen, (Santa Rosa) */
36 M_MBA, /* MacBook Air */
37 M_MBA_3, /* Macbook Air, 3rd rev */
38 M_MBP, /* MacBook Pro */
39 M_MBP_2, /* MacBook Pro 2nd gen */
40 M_MBP_2_2, /* MacBook Pro 2,2nd gen */
41 M_MBP_SR, /* MacBook Pro (Santa Rosa) */
42 M_MBP_4, /* MacBook Pro, 4th gen */
43 M_MBP_5_1, /* MacBook Pro, 5,1th gen */
44 M_MBP_5_2, /* MacBook Pro, 5,2th gen */
45 M_MBP_5_3, /* MacBook Pro, 5,3rd gen */
46 M_MBP_6_1, /* MacBook Pro, 6,1th gen */
47 M_MBP_6_2, /* MacBook Pro, 6,2th gen */
48 M_MBP_7_1, /* MacBook Pro, 7,1th gen */
49 M_MBP_8_2, /* MacBook Pro, 8,2nd gen */
50 M_UNKNOWN /* placeholder */
51};
52
53struct efifb_dmi_info {
54 char *optname;
55 unsigned long base;
56 int stride;
57 int width;
58 int height;
59 int flags;
60};
61
62#ifdef CONFIG_EFI
63
64extern struct efifb_dmi_info efifb_dmi_list[];
65void sysfb_apply_efi_quirks(void);
66
67#else /* CONFIG_EFI */
68
69static inline void sysfb_apply_efi_quirks(void)
70{
71}
72
73#endif /* CONFIG_EFI */
74
75#ifdef CONFIG_X86_SYSFB
76
77bool parse_mode(const struct screen_info *si,
78 struct simplefb_platform_data *mode);
79int create_simplefb(const struct screen_info *si,
80 const struct simplefb_platform_data *mode);
81
82#else /* CONFIG_X86_SYSFB */
83
84static inline bool parse_mode(const struct screen_info *si,
85 struct simplefb_platform_data *mode)
86{
87 return false;
88}
89
90static inline int create_simplefb(const struct screen_info *si,
91 const struct simplefb_platform_data *mode)
92{
93 return -EINVAL;
94}
95
96#endif /* CONFIG_X86_SYSFB */
97
98#endif /* _ARCH_X86_KERNEL_SYSFB_H */
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 88d99ea77723..a5408b965c9d 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -103,6 +103,9 @@ 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
108obj-$(CONFIG_EFI) += sysfb_efi.o
106 109
107obj-$(CONFIG_PERF_EVENTS) += perf_regs.o 110obj-$(CONFIG_PERF_EVENTS) += perf_regs.o
108obj-$(CONFIG_TRACING) += tracepoint.o 111obj-$(CONFIG_TRACING) += tracepoint.o
diff --git a/arch/x86/kernel/sysfb.c b/arch/x86/kernel/sysfb.c
new file mode 100644
index 000000000000..193ec2ce46c7
--- /dev/null
+++ b/arch/x86/kernel/sysfb.c
@@ -0,0 +1,74 @@
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 sysfb_apply_efi_quirks();
51
52 /* try to create a simple-framebuffer device */
53 compatible = parse_mode(si, &mode);
54 if (compatible) {
55 ret = create_simplefb(si, &mode);
56 if (!ret)
57 return 0;
58 }
59
60 /* if the FB is incompatible, create a legacy framebuffer device */
61 if (si->orig_video_isVGA == VIDEO_TYPE_EFI)
62 name = "efi-framebuffer";
63 else if (si->orig_video_isVGA == VIDEO_TYPE_VLFB)
64 name = "vesa-framebuffer";
65 else
66 name = "platform-framebuffer";
67
68 pd = platform_device_register_resndata(NULL, name, 0,
69 NULL, 0, si, sizeof(*si));
70 return IS_ERR(pd) ? PTR_ERR(pd) : 0;
71}
72
73/* must execute after PCI subsystem for EFI quirks */
74device_initcall(sysfb_init);
diff --git a/arch/x86/kernel/sysfb_efi.c b/arch/x86/kernel/sysfb_efi.c
new file mode 100644
index 000000000000..b285d4e8c68e
--- /dev/null
+++ b/arch/x86/kernel/sysfb_efi.c
@@ -0,0 +1,214 @@
1/*
2 * Generic System Framebuffers on x86
3 * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
4 *
5 * EFI Quirks Copyright (c) 2006 Edgar Hucek <gimli@dark-green.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 */
12
13/*
14 * EFI Quirks
15 * Several EFI systems do not correctly advertise their boot framebuffers.
16 * Hence, we use this static table of known broken machines and fix up the
17 * information so framebuffer drivers can load corectly.
18 */
19
20#include <linux/dmi.h>
21#include <linux/err.h>
22#include <linux/init.h>
23#include <linux/kernel.h>
24#include <linux/mm.h>
25#include <linux/pci.h>
26#include <linux/screen_info.h>
27#include <video/vga.h>
28#include <asm/sysfb.h>
29
30enum {
31 OVERRIDE_NONE = 0x0,
32 OVERRIDE_BASE = 0x1,
33 OVERRIDE_STRIDE = 0x2,
34 OVERRIDE_HEIGHT = 0x4,
35 OVERRIDE_WIDTH = 0x8,
36};
37
38struct efifb_dmi_info efifb_dmi_list[] = {
39 [M_I17] = { "i17", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE },
40 [M_I20] = { "i20", 0x80010000, 1728 * 4, 1680, 1050, OVERRIDE_NONE }, /* guess */
41 [M_I20_SR] = { "imac7", 0x40010000, 1728 * 4, 1680, 1050, OVERRIDE_NONE },
42 [M_I24] = { "i24", 0x80010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, /* guess */
43 [M_I24_8_1] = { "imac8", 0xc0060000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
44 [M_I24_10_1] = { "imac10", 0xc0010000, 2048 * 4, 1920, 1080, OVERRIDE_NONE },
45 [M_I27_11_1] = { "imac11", 0xc0010000, 2560 * 4, 2560, 1440, OVERRIDE_NONE },
46 [M_MINI]= { "mini", 0x80000000, 2048 * 4, 1024, 768, OVERRIDE_NONE },
47 [M_MINI_3_1] = { "mini31", 0x40010000, 1024 * 4, 1024, 768, OVERRIDE_NONE },
48 [M_MINI_4_1] = { "mini41", 0xc0010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
49 [M_MB] = { "macbook", 0x80000000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
50 [M_MB_5_1] = { "macbook51", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
51 [M_MB_6_1] = { "macbook61", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
52 [M_MB_7_1] = { "macbook71", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
53 [M_MBA] = { "mba", 0x80000000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
54 /* 11" Macbook Air 3,1 passes the wrong stride */
55 [M_MBA_3] = { "mba3", 0, 2048 * 4, 0, 0, OVERRIDE_STRIDE },
56 [M_MBP] = { "mbp", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE },
57 [M_MBP_2] = { "mbp2", 0, 0, 0, 0, OVERRIDE_NONE }, /* placeholder */
58 [M_MBP_2_2] = { "mbp22", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE },
59 [M_MBP_SR] = { "mbp3", 0x80030000, 2048 * 4, 1440, 900, OVERRIDE_NONE },
60 [M_MBP_4] = { "mbp4", 0xc0060000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
61 [M_MBP_5_1] = { "mbp51", 0xc0010000, 2048 * 4, 1440, 900, OVERRIDE_NONE },
62 [M_MBP_5_2] = { "mbp52", 0xc0010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
63 [M_MBP_5_3] = { "mbp53", 0xd0010000, 2048 * 4, 1440, 900, OVERRIDE_NONE },
64 [M_MBP_6_1] = { "mbp61", 0x90030000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
65 [M_MBP_6_2] = { "mbp62", 0x90030000, 2048 * 4, 1680, 1050, OVERRIDE_NONE },
66 [M_MBP_7_1] = { "mbp71", 0xc0010000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
67 [M_MBP_8_2] = { "mbp82", 0x90010000, 1472 * 4, 1440, 900, OVERRIDE_NONE },
68 [M_UNKNOWN] = { NULL, 0, 0, 0, 0, OVERRIDE_NONE }
69};
70
71#define choose_value(dmivalue, fwvalue, field, flags) ({ \
72 typeof(fwvalue) _ret_ = fwvalue; \
73 if ((flags) & (field)) \
74 _ret_ = dmivalue; \
75 else if ((fwvalue) == 0) \
76 _ret_ = dmivalue; \
77 _ret_; \
78 })
79
80static int __init efifb_set_system(const struct dmi_system_id *id)
81{
82 struct efifb_dmi_info *info = id->driver_data;
83
84 if (info->base == 0 && info->height == 0 && info->width == 0 &&
85 info->stride == 0)
86 return 0;
87
88 /* Trust the bootloader over the DMI tables */
89 if (screen_info.lfb_base == 0) {
90#if defined(CONFIG_PCI)
91 struct pci_dev *dev = NULL;
92 int found_bar = 0;
93#endif
94 if (info->base) {
95 screen_info.lfb_base = choose_value(info->base,
96 screen_info.lfb_base, OVERRIDE_BASE,
97 info->flags);
98
99#if defined(CONFIG_PCI)
100 /* make sure that the address in the table is actually
101 * on a VGA device's PCI BAR */
102
103 for_each_pci_dev(dev) {
104 int i;
105 if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
106 continue;
107 for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
108 resource_size_t start, end;
109
110 start = pci_resource_start(dev, i);
111 if (start == 0)
112 break;
113 end = pci_resource_end(dev, i);
114 if (screen_info.lfb_base >= start &&
115 screen_info.lfb_base < end) {
116 found_bar = 1;
117 }
118 }
119 }
120 if (!found_bar)
121 screen_info.lfb_base = 0;
122#endif
123 }
124 }
125 if (screen_info.lfb_base) {
126 screen_info.lfb_linelength = choose_value(info->stride,
127 screen_info.lfb_linelength, OVERRIDE_STRIDE,
128 info->flags);
129 screen_info.lfb_width = choose_value(info->width,
130 screen_info.lfb_width, OVERRIDE_WIDTH,
131 info->flags);
132 screen_info.lfb_height = choose_value(info->height,
133 screen_info.lfb_height, OVERRIDE_HEIGHT,
134 info->flags);
135 if (screen_info.orig_video_isVGA == 0)
136 screen_info.orig_video_isVGA = VIDEO_TYPE_EFI;
137 } else {
138 screen_info.lfb_linelength = 0;
139 screen_info.lfb_width = 0;
140 screen_info.lfb_height = 0;
141 screen_info.orig_video_isVGA = 0;
142 return 0;
143 }
144
145 printk(KERN_INFO "efifb: dmi detected %s - framebuffer at 0x%08x "
146 "(%dx%d, stride %d)\n", id->ident,
147 screen_info.lfb_base, screen_info.lfb_width,
148 screen_info.lfb_height, screen_info.lfb_linelength);
149
150 return 1;
151}
152
153#define EFIFB_DMI_SYSTEM_ID(vendor, name, enumid) \
154 { \
155 efifb_set_system, \
156 name, \
157 { \
158 DMI_MATCH(DMI_BIOS_VENDOR, vendor), \
159 DMI_MATCH(DMI_PRODUCT_NAME, name) \
160 }, \
161 &efifb_dmi_list[enumid] \
162 }
163
164static const struct dmi_system_id efifb_dmi_system_table[] __initconst = {
165 EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac4,1", M_I17),
166 /* At least one of these two will be right; maybe both? */
167 EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac5,1", M_I20),
168 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac5,1", M_I20),
169 /* At least one of these two will be right; maybe both? */
170 EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac6,1", M_I24),
171 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac6,1", M_I24),
172 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac7,1", M_I20_SR),
173 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac8,1", M_I24_8_1),
174 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac10,1", M_I24_10_1),
175 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac11,1", M_I27_11_1),
176 EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "Macmini1,1", M_MINI),
177 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "Macmini3,1", M_MINI_3_1),
178 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "Macmini4,1", M_MINI_4_1),
179 EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook1,1", M_MB),
180 /* At least one of these two will be right; maybe both? */
181 EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook2,1", M_MB),
182 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook2,1", M_MB),
183 /* At least one of these two will be right; maybe both? */
184 EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook3,1", M_MB),
185 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook3,1", M_MB),
186 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook4,1", M_MB),
187 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook5,1", M_MB_5_1),
188 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook6,1", M_MB_6_1),
189 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook7,1", M_MB_7_1),
190 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir1,1", M_MBA),
191 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir3,1", M_MBA_3),
192 EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro1,1", M_MBP),
193 EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,1", M_MBP_2),
194 EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,2", M_MBP_2_2),
195 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro2,1", M_MBP_2),
196 EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro3,1", M_MBP_SR),
197 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro3,1", M_MBP_SR),
198 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro4,1", M_MBP_4),
199 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,1", M_MBP_5_1),
200 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,2", M_MBP_5_2),
201 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,3", M_MBP_5_3),
202 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro6,1", M_MBP_6_1),
203 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro6,2", M_MBP_6_2),
204 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro7,1", M_MBP_7_1),
205 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro8,2", M_MBP_8_2),
206 {},
207};
208
209__init void sysfb_apply_efi_quirks(void)
210{
211 if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI ||
212 !(screen_info.capabilities & VIDEO_CAPABILITY_SKIP_QUIRKS))
213 dmi_check_system(efifb_dmi_system_table);
214}
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}
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 4cf1e1dd5621..34c3d960634d 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2457,7 +2457,7 @@ config FB_HYPERV
2457 2457
2458config FB_SIMPLE 2458config FB_SIMPLE
2459 bool "Simple framebuffer support" 2459 bool "Simple framebuffer support"
2460 depends on (FB = y) && OF 2460 depends on (FB = y)
2461 select FB_CFB_FILLRECT 2461 select FB_CFB_FILLRECT
2462 select FB_CFB_COPYAREA 2462 select FB_CFB_COPYAREA
2463 select FB_CFB_IMAGEBLIT 2463 select FB_CFB_IMAGEBLIT
@@ -2469,8 +2469,7 @@ config FB_SIMPLE
2469 pre-allocated frame buffer surface. 2469 pre-allocated frame buffer surface.
2470 2470
2471 Configuration re: surface address, size, and format must be provided 2471 Configuration re: surface address, size, and format must be provided
2472 through device tree, or potentially plain old platform data in the 2472 through device tree, or plain old platform data.
2473 future.
2474 2473
2475source "drivers/video/omap/Kconfig" 2474source "drivers/video/omap/Kconfig"
2476source "drivers/video/omap2/Kconfig" 2475source "drivers/video/omap2/Kconfig"
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index 8c30603e0a86..846caab75a46 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -92,7 +92,8 @@ config DUMMY_CONSOLE_ROWS
92 92
93config FRAMEBUFFER_CONSOLE 93config FRAMEBUFFER_CONSOLE
94 tristate "Framebuffer Console support" 94 tristate "Framebuffer Console support"
95 depends on FB 95 depends on FB && !UML
96 select VT_HW_CONSOLE_BINDING
96 select CRC32 97 select CRC32
97 select FONT_SUPPORT 98 select FONT_SUPPORT
98 help 99 help
diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c
index 50fe668c6172..2a8286ef2645 100644
--- a/drivers/video/efifb.c
+++ b/drivers/video/efifb.c
@@ -15,6 +15,7 @@
15#include <linux/dmi.h> 15#include <linux/dmi.h>
16#include <linux/pci.h> 16#include <linux/pci.h>
17#include <video/vga.h> 17#include <video/vga.h>
18#include <asm/sysfb.h>
18 19
19static bool request_mem_succeeded = false; 20static bool request_mem_succeeded = false;
20 21
@@ -38,223 +39,6 @@ static struct fb_fix_screeninfo efifb_fix = {
38 .visual = FB_VISUAL_TRUECOLOR, 39 .visual = FB_VISUAL_TRUECOLOR,
39}; 40};
40 41
41enum {
42 M_I17, /* 17-Inch iMac */
43 M_I20, /* 20-Inch iMac */
44 M_I20_SR, /* 20-Inch iMac (Santa Rosa) */
45 M_I24, /* 24-Inch iMac */
46 M_I24_8_1, /* 24-Inch iMac, 8,1th gen */
47 M_I24_10_1, /* 24-Inch iMac, 10,1th gen */
48 M_I27_11_1, /* 27-Inch iMac, 11,1th gen */
49 M_MINI, /* Mac Mini */
50 M_MINI_3_1, /* Mac Mini, 3,1th gen */
51 M_MINI_4_1, /* Mac Mini, 4,1th gen */
52 M_MB, /* MacBook */
53 M_MB_2, /* MacBook, 2nd rev. */
54 M_MB_3, /* MacBook, 3rd rev. */
55 M_MB_5_1, /* MacBook, 5th rev. */
56 M_MB_6_1, /* MacBook, 6th rev. */
57 M_MB_7_1, /* MacBook, 7th rev. */
58 M_MB_SR, /* MacBook, 2nd gen, (Santa Rosa) */
59 M_MBA, /* MacBook Air */
60 M_MBA_3, /* Macbook Air, 3rd rev */
61 M_MBP, /* MacBook Pro */
62 M_MBP_2, /* MacBook Pro 2nd gen */
63 M_MBP_2_2, /* MacBook Pro 2,2nd gen */
64 M_MBP_SR, /* MacBook Pro (Santa Rosa) */
65 M_MBP_4, /* MacBook Pro, 4th gen */
66 M_MBP_5_1, /* MacBook Pro, 5,1th gen */
67 M_MBP_5_2, /* MacBook Pro, 5,2th gen */
68 M_MBP_5_3, /* MacBook Pro, 5,3rd gen */
69 M_MBP_6_1, /* MacBook Pro, 6,1th gen */
70 M_MBP_6_2, /* MacBook Pro, 6,2th gen */
71 M_MBP_7_1, /* MacBook Pro, 7,1th gen */
72 M_MBP_8_2, /* MacBook Pro, 8,2nd gen */
73 M_UNKNOWN /* placeholder */
74};
75
76#define OVERRIDE_NONE 0x0
77#define OVERRIDE_BASE 0x1
78#define OVERRIDE_STRIDE 0x2
79#define OVERRIDE_HEIGHT 0x4
80#define OVERRIDE_WIDTH 0x8
81
82static struct efifb_dmi_info {
83 char *optname;
84 unsigned long base;
85 int stride;
86 int width;
87 int height;
88 int flags;
89} dmi_list[] __initdata = {
90 [M_I17] = { "i17", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE },
91 [M_I20] = { "i20", 0x80010000, 1728 * 4, 1680, 1050, OVERRIDE_NONE }, /* guess */
92 [M_I20_SR] = { "imac7", 0x40010000, 1728 * 4, 1680, 1050, OVERRIDE_NONE },
93 [M_I24] = { "i24", 0x80010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, /* guess */
94 [M_I24_8_1] = { "imac8", 0xc0060000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
95 [M_I24_10_1] = { "imac10", 0xc0010000, 2048 * 4, 1920, 1080, OVERRIDE_NONE },
96 [M_I27_11_1] = { "imac11", 0xc0010000, 2560 * 4, 2560, 1440, OVERRIDE_NONE },
97 [M_MINI]= { "mini", 0x80000000, 2048 * 4, 1024, 768, OVERRIDE_NONE },
98 [M_MINI_3_1] = { "mini31", 0x40010000, 1024 * 4, 1024, 768, OVERRIDE_NONE },
99 [M_MINI_4_1] = { "mini41", 0xc0010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
100 [M_MB] = { "macbook", 0x80000000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
101 [M_MB_5_1] = { "macbook51", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
102 [M_MB_6_1] = { "macbook61", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
103 [M_MB_7_1] = { "macbook71", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
104 [M_MBA] = { "mba", 0x80000000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
105 /* 11" Macbook Air 3,1 passes the wrong stride */
106 [M_MBA_3] = { "mba3", 0, 2048 * 4, 0, 0, OVERRIDE_STRIDE },
107 [M_MBP] = { "mbp", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE },
108 [M_MBP_2] = { "mbp2", 0, 0, 0, 0, OVERRIDE_NONE }, /* placeholder */
109 [M_MBP_2_2] = { "mbp22", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE },
110 [M_MBP_SR] = { "mbp3", 0x80030000, 2048 * 4, 1440, 900, OVERRIDE_NONE },
111 [M_MBP_4] = { "mbp4", 0xc0060000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
112 [M_MBP_5_1] = { "mbp51", 0xc0010000, 2048 * 4, 1440, 900, OVERRIDE_NONE },
113 [M_MBP_5_2] = { "mbp52", 0xc0010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
114 [M_MBP_5_3] = { "mbp53", 0xd0010000, 2048 * 4, 1440, 900, OVERRIDE_NONE },
115 [M_MBP_6_1] = { "mbp61", 0x90030000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
116 [M_MBP_6_2] = { "mbp62", 0x90030000, 2048 * 4, 1680, 1050, OVERRIDE_NONE },
117 [M_MBP_7_1] = { "mbp71", 0xc0010000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
118 [M_MBP_8_2] = { "mbp82", 0x90010000, 1472 * 4, 1440, 900, OVERRIDE_NONE },
119 [M_UNKNOWN] = { NULL, 0, 0, 0, 0, OVERRIDE_NONE }
120};
121
122static int set_system(const struct dmi_system_id *id);
123
124#define EFIFB_DMI_SYSTEM_ID(vendor, name, enumid) \
125 { set_system, name, { \
126 DMI_MATCH(DMI_BIOS_VENDOR, vendor), \
127 DMI_MATCH(DMI_PRODUCT_NAME, name) }, \
128 &dmi_list[enumid] }
129
130static const struct dmi_system_id dmi_system_table[] __initconst = {
131 EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac4,1", M_I17),
132 /* At least one of these two will be right; maybe both? */
133 EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac5,1", M_I20),
134 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac5,1", M_I20),
135 /* At least one of these two will be right; maybe both? */
136 EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac6,1", M_I24),
137 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac6,1", M_I24),
138 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac7,1", M_I20_SR),
139 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac8,1", M_I24_8_1),
140 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac10,1", M_I24_10_1),
141 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac11,1", M_I27_11_1),
142 EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "Macmini1,1", M_MINI),
143 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "Macmini3,1", M_MINI_3_1),
144 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "Macmini4,1", M_MINI_4_1),
145 EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook1,1", M_MB),
146 /* At least one of these two will be right; maybe both? */
147 EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook2,1", M_MB),
148 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook2,1", M_MB),
149 /* At least one of these two will be right; maybe both? */
150 EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook3,1", M_MB),
151 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook3,1", M_MB),
152 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook4,1", M_MB),
153 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook5,1", M_MB_5_1),
154 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook6,1", M_MB_6_1),
155 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook7,1", M_MB_7_1),
156 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir1,1", M_MBA),
157 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir3,1", M_MBA_3),
158 EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro1,1", M_MBP),
159 EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,1", M_MBP_2),
160 EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,2", M_MBP_2_2),
161 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro2,1", M_MBP_2),
162 EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro3,1", M_MBP_SR),
163 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro3,1", M_MBP_SR),
164 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro4,1", M_MBP_4),
165 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,1", M_MBP_5_1),
166 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,2", M_MBP_5_2),
167 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,3", M_MBP_5_3),
168 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro6,1", M_MBP_6_1),
169 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro6,2", M_MBP_6_2),
170 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro7,1", M_MBP_7_1),
171 EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro8,2", M_MBP_8_2),
172 {},
173};
174
175#define choose_value(dmivalue, fwvalue, field, flags) ({ \
176 typeof(fwvalue) _ret_ = fwvalue; \
177 if ((flags) & (field)) \
178 _ret_ = dmivalue; \
179 else if ((fwvalue) == 0) \
180 _ret_ = dmivalue; \
181 _ret_; \
182 })
183
184static int set_system(const struct dmi_system_id *id)
185{
186 struct efifb_dmi_info *info = id->driver_data;
187
188 if (info->base == 0 && info->height == 0 && info->width == 0
189 && info->stride == 0)
190 return 0;
191
192 /* Trust the bootloader over the DMI tables */
193 if (screen_info.lfb_base == 0) {
194#if defined(CONFIG_PCI)
195 struct pci_dev *dev = NULL;
196 int found_bar = 0;
197#endif
198 if (info->base) {
199 screen_info.lfb_base = choose_value(info->base,
200 screen_info.lfb_base, OVERRIDE_BASE,
201 info->flags);
202
203#if defined(CONFIG_PCI)
204 /* make sure that the address in the table is actually
205 * on a VGA device's PCI BAR */
206
207 for_each_pci_dev(dev) {
208 int i;
209 if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
210 continue;
211 for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
212 resource_size_t start, end;
213
214 start = pci_resource_start(dev, i);
215 if (start == 0)
216 break;
217 end = pci_resource_end(dev, i);
218 if (screen_info.lfb_base >= start &&
219 screen_info.lfb_base < end) {
220 found_bar = 1;
221 }
222 }
223 }
224 if (!found_bar)
225 screen_info.lfb_base = 0;
226#endif
227 }
228 }
229 if (screen_info.lfb_base) {
230 screen_info.lfb_linelength = choose_value(info->stride,
231 screen_info.lfb_linelength, OVERRIDE_STRIDE,
232 info->flags);
233 screen_info.lfb_width = choose_value(info->width,
234 screen_info.lfb_width, OVERRIDE_WIDTH,
235 info->flags);
236 screen_info.lfb_height = choose_value(info->height,
237 screen_info.lfb_height, OVERRIDE_HEIGHT,
238 info->flags);
239 if (screen_info.orig_video_isVGA == 0)
240 screen_info.orig_video_isVGA = VIDEO_TYPE_EFI;
241 } else {
242 screen_info.lfb_linelength = 0;
243 screen_info.lfb_width = 0;
244 screen_info.lfb_height = 0;
245 screen_info.orig_video_isVGA = 0;
246 return 0;
247 }
248
249 printk(KERN_INFO "efifb: dmi detected %s - framebuffer at 0x%08x "
250 "(%dx%d, stride %d)\n", id->ident,
251 screen_info.lfb_base, screen_info.lfb_width,
252 screen_info.lfb_height, screen_info.lfb_linelength);
253
254
255 return 1;
256}
257
258static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green, 42static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
259 unsigned blue, unsigned transp, 43 unsigned blue, unsigned transp,
260 struct fb_info *info) 44 struct fb_info *info)
@@ -312,7 +96,7 @@ void vga_set_default_device(struct pci_dev *pdev)
312 default_vga = pdev; 96 default_vga = pdev;
313} 97}
314 98
315static int __init efifb_setup(char *options) 99static int efifb_setup(char *options)
316{ 100{
317 char *this_opt; 101 char *this_opt;
318 int i; 102 int i;
@@ -323,12 +107,12 @@ static int __init efifb_setup(char *options)
323 if (!*this_opt) continue; 107 if (!*this_opt) continue;
324 108
325 for (i = 0; i < M_UNKNOWN; i++) { 109 for (i = 0; i < M_UNKNOWN; i++) {
326 if (!strcmp(this_opt, dmi_list[i].optname) && 110 if (!strcmp(this_opt, efifb_dmi_list[i].optname) &&
327 dmi_list[i].base != 0) { 111 efifb_dmi_list[i].base != 0) {
328 screen_info.lfb_base = dmi_list[i].base; 112 screen_info.lfb_base = efifb_dmi_list[i].base;
329 screen_info.lfb_linelength = dmi_list[i].stride; 113 screen_info.lfb_linelength = efifb_dmi_list[i].stride;
330 screen_info.lfb_width = dmi_list[i].width; 114 screen_info.lfb_width = efifb_dmi_list[i].width;
331 screen_info.lfb_height = dmi_list[i].height; 115 screen_info.lfb_height = efifb_dmi_list[i].height;
332 } 116 }
333 } 117 }
334 if (!strncmp(this_opt, "base:", 5)) 118 if (!strncmp(this_opt, "base:", 5))
@@ -369,13 +153,28 @@ static int __init efifb_setup(char *options)
369 return 0; 153 return 0;
370} 154}
371 155
372static int __init efifb_probe(struct platform_device *dev) 156static int efifb_probe(struct platform_device *dev)
373{ 157{
374 struct fb_info *info; 158 struct fb_info *info;
375 int err; 159 int err;
376 unsigned int size_vmode; 160 unsigned int size_vmode;
377 unsigned int size_remap; 161 unsigned int size_remap;
378 unsigned int size_total; 162 unsigned int size_total;
163 char *option = NULL;
164
165 if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
166 return -ENODEV;
167
168 if (fb_get_options("efifb", &option))
169 return -ENODEV;
170 efifb_setup(option);
171
172 /* We don't get linelength from UGA Draw Protocol, only from
173 * EFI Graphics Protocol. So if it's not in DMI, and it's not
174 * passed in from the user, we really can't use the framebuffer.
175 */
176 if (!screen_info.lfb_linelength)
177 return -ENODEV;
379 178
380 if (!screen_info.lfb_depth) 179 if (!screen_info.lfb_depth)
381 screen_info.lfb_depth = 32; 180 screen_info.lfb_depth = 32;
@@ -539,55 +338,12 @@ err_release_mem:
539} 338}
540 339
541static struct platform_driver efifb_driver = { 340static struct platform_driver efifb_driver = {
542 .driver = { 341 .driver = {
543 .name = "efifb", 342 .name = "efi-framebuffer",
343 .owner = THIS_MODULE,
544 }, 344 },
345 .probe = efifb_probe,
545}; 346};
546 347
547static struct platform_device efifb_device = { 348module_platform_driver(efifb_driver);
548 .name = "efifb",
549};
550
551static int __init efifb_init(void)
552{
553 int ret;
554 char *option = NULL;
555
556 if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI ||
557 !(screen_info.capabilities & VIDEO_CAPABILITY_SKIP_QUIRKS))
558 dmi_check_system(dmi_system_table);
559
560 if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
561 return -ENODEV;
562
563 if (fb_get_options("efifb", &option))
564 return -ENODEV;
565 efifb_setup(option);
566
567 /* We don't get linelength from UGA Draw Protocol, only from
568 * EFI Graphics Protocol. So if it's not in DMI, and it's not
569 * passed in from the user, we really can't use the framebuffer.
570 */
571 if (!screen_info.lfb_linelength)
572 return -ENODEV;
573
574 ret = platform_device_register(&efifb_device);
575 if (ret)
576 return ret;
577
578 /*
579 * This is not just an optimization. We will interfere
580 * with a real driver if we get reprobed, so don't allow
581 * it.
582 */
583 ret = platform_driver_probe(&efifb_driver, efifb_probe);
584 if (ret) {
585 platform_device_unregister(&efifb_device);
586 return ret;
587 }
588
589 return ret;
590}
591module_init(efifb_init);
592
593MODULE_LICENSE("GPL"); 349MODULE_LICENSE("GPL");
diff --git a/drivers/video/simplefb.c b/drivers/video/simplefb.c
index e2e9e3e61b72..8d7810613058 100644
--- a/drivers/video/simplefb.c
+++ b/drivers/video/simplefb.c
@@ -24,6 +24,7 @@
24#include <linux/fb.h> 24#include <linux/fb.h>
25#include <linux/io.h> 25#include <linux/io.h>
26#include <linux/module.h> 26#include <linux/module.h>
27#include <linux/platform_data/simplefb.h>
27#include <linux/platform_device.h> 28#include <linux/platform_device.h>
28 29
29static struct fb_fix_screeninfo simplefb_fix = { 30static struct fb_fix_screeninfo simplefb_fix = {
@@ -73,18 +74,7 @@ static struct fb_ops simplefb_ops = {
73 .fb_imageblit = cfb_imageblit, 74 .fb_imageblit = cfb_imageblit,
74}; 75};
75 76
76struct simplefb_format { 77static struct simplefb_format simplefb_formats[] = SIMPLEFB_FORMATS;
77 const char *name;
78 u32 bits_per_pixel;
79 struct fb_bitfield red;
80 struct fb_bitfield green;
81 struct fb_bitfield blue;
82 struct fb_bitfield transp;
83};
84
85static struct simplefb_format simplefb_formats[] = {
86 { "r5g6b5", 16, {11, 5}, {5, 6}, {0, 5}, {0, 0} },
87};
88 78
89struct simplefb_params { 79struct simplefb_params {
90 u32 width; 80 u32 width;
@@ -139,6 +129,33 @@ static int simplefb_parse_dt(struct platform_device *pdev,
139 return 0; 129 return 0;
140} 130}
141 131
132static int simplefb_parse_pd(struct platform_device *pdev,
133 struct simplefb_params *params)
134{
135 struct simplefb_platform_data *pd = pdev->dev.platform_data;
136 int i;
137
138 params->width = pd->width;
139 params->height = pd->height;
140 params->stride = pd->stride;
141
142 params->format = NULL;
143 for (i = 0; i < ARRAY_SIZE(simplefb_formats); i++) {
144 if (strcmp(pd->format, simplefb_formats[i].name))
145 continue;
146
147 params->format = &simplefb_formats[i];
148 break;
149 }
150
151 if (!params->format) {
152 dev_err(&pdev->dev, "Invalid format value\n");
153 return -EINVAL;
154 }
155
156 return 0;
157}
158
142static int simplefb_probe(struct platform_device *pdev) 159static int simplefb_probe(struct platform_device *pdev)
143{ 160{
144 int ret; 161 int ret;
@@ -149,7 +166,12 @@ static int simplefb_probe(struct platform_device *pdev)
149 if (fb_get_options("simplefb", NULL)) 166 if (fb_get_options("simplefb", NULL))
150 return -ENODEV; 167 return -ENODEV;
151 168
152 ret = simplefb_parse_dt(pdev, &params); 169 ret = -ENODEV;
170 if (pdev->dev.platform_data)
171 ret = simplefb_parse_pd(pdev, &params);
172 else if (pdev->dev.of_node)
173 ret = simplefb_parse_dt(pdev, &params);
174
153 if (ret) 175 if (ret)
154 return ret; 176 return ret;
155 177
@@ -180,8 +202,16 @@ static int simplefb_probe(struct platform_device *pdev)
180 info->var.blue = params.format->blue; 202 info->var.blue = params.format->blue;
181 info->var.transp = params.format->transp; 203 info->var.transp = params.format->transp;
182 204
205 info->apertures = alloc_apertures(1);
206 if (!info->apertures) {
207 framebuffer_release(info);
208 return -ENOMEM;
209 }
210 info->apertures->ranges[0].base = info->fix.smem_start;
211 info->apertures->ranges[0].size = info->fix.smem_len;
212
183 info->fbops = &simplefb_ops; 213 info->fbops = &simplefb_ops;
184 info->flags = FBINFO_DEFAULT; 214 info->flags = FBINFO_DEFAULT | FBINFO_MISC_FIRMWARE;
185 info->screen_base = devm_ioremap(&pdev->dev, info->fix.smem_start, 215 info->screen_base = devm_ioremap(&pdev->dev, info->fix.smem_start,
186 info->fix.smem_len); 216 info->fix.smem_len);
187 if (!info->screen_base) { 217 if (!info->screen_base) {
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index 501b3406c6d5..bd83233ec227 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -29,7 +29,7 @@
29 29
30/* --------------------------------------------------------------------- */ 30/* --------------------------------------------------------------------- */
31 31
32static struct fb_var_screeninfo vesafb_defined __initdata = { 32static struct fb_var_screeninfo vesafb_defined = {
33 .activate = FB_ACTIVATE_NOW, 33 .activate = FB_ACTIVATE_NOW,
34 .height = -1, 34 .height = -1,
35 .width = -1, 35 .width = -1,
@@ -40,7 +40,7 @@ static struct fb_var_screeninfo vesafb_defined __initdata = {
40 .vmode = FB_VMODE_NONINTERLACED, 40 .vmode = FB_VMODE_NONINTERLACED,
41}; 41};
42 42
43static struct fb_fix_screeninfo vesafb_fix __initdata = { 43static struct fb_fix_screeninfo vesafb_fix = {
44 .id = "VESA VGA", 44 .id = "VESA VGA",
45 .type = FB_TYPE_PACKED_PIXELS, 45 .type = FB_TYPE_PACKED_PIXELS,
46 .accel = FB_ACCEL_NONE, 46 .accel = FB_ACCEL_NONE,
@@ -48,8 +48,8 @@ static struct fb_fix_screeninfo vesafb_fix __initdata = {
48 48
49static int inverse __read_mostly; 49static int inverse __read_mostly;
50static int mtrr __read_mostly; /* disable mtrr */ 50static int mtrr __read_mostly; /* disable mtrr */
51static int vram_remap __initdata; /* Set amount of memory to be used */ 51static int vram_remap; /* Set amount of memory to be used */
52static int vram_total __initdata; /* Set total amount of memory */ 52static int vram_total; /* Set total amount of memory */
53static int pmi_setpal __read_mostly = 1; /* pmi for palette changes ??? */ 53static int pmi_setpal __read_mostly = 1; /* pmi for palette changes ??? */
54static int ypan __read_mostly; /* 0..nothing, 1..ypan, 2..ywrap */ 54static int ypan __read_mostly; /* 0..nothing, 1..ypan, 2..ywrap */
55static void (*pmi_start)(void) __read_mostly; 55static void (*pmi_start)(void) __read_mostly;
@@ -192,7 +192,7 @@ static struct fb_ops vesafb_ops = {
192 .fb_imageblit = cfb_imageblit, 192 .fb_imageblit = cfb_imageblit,
193}; 193};
194 194
195static int __init vesafb_setup(char *options) 195static int vesafb_setup(char *options)
196{ 196{
197 char *this_opt; 197 char *this_opt;
198 198
@@ -226,13 +226,18 @@ static int __init vesafb_setup(char *options)
226 return 0; 226 return 0;
227} 227}
228 228
229static int __init vesafb_probe(struct platform_device *dev) 229static int vesafb_probe(struct platform_device *dev)
230{ 230{
231 struct fb_info *info; 231 struct fb_info *info;
232 int i, err; 232 int i, err;
233 unsigned int size_vmode; 233 unsigned int size_vmode;
234 unsigned int size_remap; 234 unsigned int size_remap;
235 unsigned int size_total; 235 unsigned int size_total;
236 char *option = NULL;
237
238 /* ignore error return of fb_get_options */
239 fb_get_options("vesafb", &option);
240 vesafb_setup(option);
236 241
237 if (screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) 242 if (screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB)
238 return -ENODEV; 243 return -ENODEV;
@@ -496,40 +501,12 @@ err:
496} 501}
497 502
498static struct platform_driver vesafb_driver = { 503static struct platform_driver vesafb_driver = {
499 .driver = { 504 .driver = {
500 .name = "vesafb", 505 .name = "vesa-framebuffer",
506 .owner = THIS_MODULE,
501 }, 507 },
508 .probe = vesafb_probe,
502}; 509};
503 510
504static struct platform_device *vesafb_device; 511module_platform_driver(vesafb_driver);
505
506static int __init vesafb_init(void)
507{
508 int ret;
509 char *option = NULL;
510
511 /* ignore error return of fb_get_options */
512 fb_get_options("vesafb", &option);
513 vesafb_setup(option);
514
515 vesafb_device = platform_device_alloc("vesafb", 0);
516 if (!vesafb_device)
517 return -ENOMEM;
518
519 ret = platform_device_add(vesafb_device);
520 if (!ret) {
521 ret = platform_driver_probe(&vesafb_driver, vesafb_probe);
522 if (ret)
523 platform_device_del(vesafb_device);
524 }
525
526 if (ret) {
527 platform_device_put(vesafb_device);
528 vesafb_device = NULL;
529 }
530
531 return ret;
532}
533module_init(vesafb_init);
534
535MODULE_LICENSE("GPL"); 512MODULE_LICENSE("GPL");
diff --git a/include/linux/platform_data/simplefb.h b/include/linux/platform_data/simplefb.h
new file mode 100644
index 000000000000..53774b0cd8e9
--- /dev/null
+++ b/include/linux/platform_data/simplefb.h
@@ -0,0 +1,63 @@
1/*
2 * simplefb.h - Simple Framebuffer Device
3 *
4 * Copyright (C) 2013 David Herrmann <dh.herrmann@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#ifndef __PLATFORM_DATA_SIMPLEFB_H__
13#define __PLATFORM_DATA_SIMPLEFB_H__
14
15#include <drm/drm_fourcc.h>
16#include <linux/fb.h>
17#include <linux/kernel.h>
18
19/* format array, use it to initialize a "struct simplefb_format" array */
20#define SIMPLEFB_FORMATS \
21{ \
22 { "r5g6b5", 16, {11, 5}, {5, 6}, {0, 5}, {0, 0}, DRM_FORMAT_RGB565 }, \
23 { "x1r5g5b5", 16, {10, 5}, {5, 5}, {0, 5}, {0, 0}, DRM_FORMAT_XRGB1555 }, \
24 { "a1r5g5b5", 16, {10, 5}, {5, 5}, {0, 5}, {15, 1}, DRM_FORMAT_ARGB1555 }, \
25 { "r8g8b8", 24, {16, 8}, {8, 8}, {0, 8}, {0, 0}, DRM_FORMAT_RGB888 }, \
26 { "x8r8g8b8", 32, {16, 8}, {8, 8}, {0, 8}, {0, 0}, DRM_FORMAT_XRGB8888 }, \
27 { "a8r8g8b8", 32, {16, 8}, {8, 8}, {0, 8}, {24, 8}, DRM_FORMAT_ARGB8888 }, \
28 { "x2r10g10b10", 32, {20, 10}, {10, 10}, {0, 10}, {0, 0}, DRM_FORMAT_XRGB2101010 }, \
29 { "a2r10g10b10", 32, {20, 10}, {10, 10}, {0, 10}, {30, 2}, DRM_FORMAT_ARGB2101010 }, \
30}
31
32/*
33 * Data-Format for Simple-Framebuffers
34 * @name: unique 0-terminated name that can be used to identify the mode
35 * @red,green,blue: Offsets and sizes of the single RGB parts
36 * @transp: Offset and size of the alpha bits. length=0 means no alpha
37 * @fourcc: 32bit DRM four-CC code (see drm_fourcc.h)
38 */
39struct simplefb_format {
40 const char *name;
41 u32 bits_per_pixel;
42 struct fb_bitfield red;
43 struct fb_bitfield green;
44 struct fb_bitfield blue;
45 struct fb_bitfield transp;
46 u32 fourcc;
47};
48
49/*
50 * Simple-Framebuffer description
51 * If the arch-boot code creates simple-framebuffers without DT support, it
52 * can pass the width, height, stride and format via this platform-data object.
53 * The framebuffer location must be given as IORESOURCE_MEM resource.
54 * @format must be a format as described in "struct simplefb_format" above.
55 */
56struct simplefb_platform_data {
57 u32 width;
58 u32 height;
59 u32 stride;
60 const char *format;
61};
62
63#endif /* __PLATFORM_DATA_SIMPLEFB_H__ */