diff options
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/Kconfig | 26 | ||||
-rw-r--r-- | arch/x86/include/asm/sysfb.h | 98 | ||||
-rw-r--r-- | arch/x86/kernel/Makefile | 3 | ||||
-rw-r--r-- | arch/x86/kernel/sysfb.c | 74 | ||||
-rw-r--r-- | arch/x86/kernel/sysfb_efi.c | 214 | ||||
-rw-r--r-- | arch/x86/kernel/sysfb_simplefb.c | 95 |
6 files changed, 510 insertions, 0 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 | ||
2271 | source "drivers/rapidio/Kconfig" | 2271 | source "drivers/rapidio/Kconfig" |
2272 | 2272 | ||
2273 | config 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 | |||
2273 | endmenu | 2299 | endmenu |
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 | |||
18 | enum { | ||
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 | |||
53 | struct 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 | |||
64 | extern struct efifb_dmi_info efifb_dmi_list[]; | ||
65 | void sysfb_apply_efi_quirks(void); | ||
66 | |||
67 | #else /* CONFIG_EFI */ | ||
68 | |||
69 | static inline void sysfb_apply_efi_quirks(void) | ||
70 | { | ||
71 | } | ||
72 | |||
73 | #endif /* CONFIG_EFI */ | ||
74 | |||
75 | #ifdef CONFIG_X86_SYSFB | ||
76 | |||
77 | bool parse_mode(const struct screen_info *si, | ||
78 | struct simplefb_platform_data *mode); | ||
79 | int create_simplefb(const struct screen_info *si, | ||
80 | const struct simplefb_platform_data *mode); | ||
81 | |||
82 | #else /* CONFIG_X86_SYSFB */ | ||
83 | |||
84 | static inline bool parse_mode(const struct screen_info *si, | ||
85 | struct simplefb_platform_data *mode) | ||
86 | { | ||
87 | return false; | ||
88 | } | ||
89 | |||
90 | static 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 | |||
103 | obj-$(CONFIG_SWIOTLB) += pci-swiotlb.o | 103 | obj-$(CONFIG_SWIOTLB) += pci-swiotlb.o |
104 | obj-$(CONFIG_OF) += devicetree.o | 104 | obj-$(CONFIG_OF) += devicetree.o |
105 | obj-$(CONFIG_UPROBES) += uprobes.o | 105 | obj-$(CONFIG_UPROBES) += uprobes.o |
106 | obj-y += sysfb.o | ||
107 | obj-$(CONFIG_X86_SYSFB) += sysfb_simplefb.o | ||
108 | obj-$(CONFIG_EFI) += sysfb_efi.o | ||
106 | 109 | ||
107 | obj-$(CONFIG_PERF_EVENTS) += perf_regs.o | 110 | obj-$(CONFIG_PERF_EVENTS) += perf_regs.o |
108 | obj-$(CONFIG_TRACING) += tracepoint.o | 111 | obj-$(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 | |||
41 | static __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 */ | ||
74 | 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 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 | |||
30 | enum { | ||
31 | OVERRIDE_NONE = 0x0, | ||
32 | OVERRIDE_BASE = 0x1, | ||
33 | OVERRIDE_STRIDE = 0x2, | ||
34 | OVERRIDE_HEIGHT = 0x4, | ||
35 | OVERRIDE_WIDTH = 0x8, | ||
36 | }; | ||
37 | |||
38 | struct 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 | |||
80 | static 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 | |||
164 | static 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 | |||
27 | static const char simplefb_resname[] = "BOOTFB"; | ||
28 | static 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 | } | ||