diff options
author | Peter Jones <pjones@redhat.com> | 2011-04-06 13:34:58 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2011-04-06 13:58:10 -0400 |
commit | 47dfe51f8f0b9540cbe15072cd352d9f3857d47f (patch) | |
tree | c09deee3af82bbeb4186ae17aaf9070c680b1099 | |
parent | 47c87d930f3db4fc3a30505075e07f5597e2e953 (diff) |
efifb: Support overriding fields FW tells us with the DMI data.
Some machines apparently give us bogus linelength/stride/pitch data, so
we need to support letting the DMI table override the supplied data.
I bet you can't guess whose machines I'm talking about.
Signed-off-by: Peter Jones <pjones@redhat.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r-- | drivers/video/efifb.c | 149 |
1 files changed, 88 insertions, 61 deletions
diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c index a9645b86a623..2359b6403a16 100644 --- a/drivers/video/efifb.c +++ b/drivers/video/efifb.c | |||
@@ -68,41 +68,48 @@ enum { | |||
68 | M_UNKNOWN /* placeholder */ | 68 | M_UNKNOWN /* placeholder */ |
69 | }; | 69 | }; |
70 | 70 | ||
71 | #define OVERRIDE_NONE 0x0 | ||
72 | #define OVERRIDE_BASE 0x1 | ||
73 | #define OVERRIDE_STRIDE 0x2 | ||
74 | #define OVERRIDE_HEIGHT 0x4 | ||
75 | #define OVERRIDE_WIDTH 0x8 | ||
76 | |||
71 | static struct efifb_dmi_info { | 77 | static struct efifb_dmi_info { |
72 | char *optname; | 78 | char *optname; |
73 | unsigned long base; | 79 | unsigned long base; |
74 | int stride; | 80 | int stride; |
75 | int width; | 81 | int width; |
76 | int height; | 82 | int height; |
83 | int flags; | ||
77 | } dmi_list[] __initdata = { | 84 | } dmi_list[] __initdata = { |
78 | [M_I17] = { "i17", 0x80010000, 1472 * 4, 1440, 900 }, | 85 | [M_I17] = { "i17", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE }, |
79 | [M_I20] = { "i20", 0x80010000, 1728 * 4, 1680, 1050 }, /* guess */ | 86 | [M_I20] = { "i20", 0x80010000, 1728 * 4, 1680, 1050, OVERRIDE_NONE }, /* guess */ |
80 | [M_I20_SR] = { "imac7", 0x40010000, 1728 * 4, 1680, 1050 }, | 87 | [M_I20_SR] = { "imac7", 0x40010000, 1728 * 4, 1680, 1050, OVERRIDE_NONE }, |
81 | [M_I24] = { "i24", 0x80010000, 2048 * 4, 1920, 1200 }, /* guess */ | 88 | [M_I24] = { "i24", 0x80010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, /* guess */ |
82 | [M_I24_8_1] = { "imac8", 0xc0060000, 2048 * 4, 1920, 1200 }, | 89 | [M_I24_8_1] = { "imac8", 0xc0060000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, |
83 | [M_I24_10_1] = { "imac10", 0xc0010000, 2048 * 4, 1920, 1080 }, | 90 | [M_I24_10_1] = { "imac10", 0xc0010000, 2048 * 4, 1920, 1080, OVERRIDE_NONE }, |
84 | [M_I27_11_1] = { "imac11", 0xc0010000, 2560 * 4, 2560, 1440 }, | 91 | [M_I27_11_1] = { "imac11", 0xc0010000, 2560 * 4, 2560, 1440, OVERRIDE_NONE }, |
85 | [M_MINI]= { "mini", 0x80000000, 2048 * 4, 1024, 768 }, | 92 | [M_MINI]= { "mini", 0x80000000, 2048 * 4, 1024, 768, OVERRIDE_NONE }, |
86 | [M_MINI_3_1] = { "mini31", 0x40010000, 1024 * 4, 1024, 768 }, | 93 | [M_MINI_3_1] = { "mini31", 0x40010000, 1024 * 4, 1024, 768, OVERRIDE_NONE }, |
87 | [M_MINI_4_1] = { "mini41", 0xc0010000, 2048 * 4, 1920, 1200 }, | 94 | [M_MINI_4_1] = { "mini41", 0xc0010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, |
88 | [M_MB] = { "macbook", 0x80000000, 2048 * 4, 1280, 800 }, | 95 | [M_MB] = { "macbook", 0x80000000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, |
89 | [M_MB_5_1] = { "macbook51", 0x80010000, 2048 * 4, 1280, 800 }, | 96 | [M_MB_5_1] = { "macbook51", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, |
90 | [M_MB_6_1] = { "macbook61", 0x80010000, 2048 * 4, 1280, 800 }, | 97 | [M_MB_6_1] = { "macbook61", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, |
91 | [M_MB_7_1] = { "macbook71", 0x80010000, 2048 * 4, 1280, 800 }, | 98 | [M_MB_7_1] = { "macbook71", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, |
92 | [M_MBA] = { "mba", 0x80000000, 2048 * 4, 1280, 800 }, | 99 | [M_MBA] = { "mba", 0x80000000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, |
93 | [M_MBP] = { "mbp", 0x80010000, 1472 * 4, 1440, 900 }, | 100 | [M_MBP] = { "mbp", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE }, |
94 | [M_MBP_2] = { "mbp2", 0, 0, 0, 0 }, /* placeholder */ | 101 | [M_MBP_2] = { "mbp2", 0, 0, 0, 0, OVERRIDE_NONE }, /* placeholder */ |
95 | [M_MBP_2_2] = { "mbp22", 0x80010000, 1472 * 4, 1440, 900 }, | 102 | [M_MBP_2_2] = { "mbp22", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE }, |
96 | [M_MBP_SR] = { "mbp3", 0x80030000, 2048 * 4, 1440, 900 }, | 103 | [M_MBP_SR] = { "mbp3", 0x80030000, 2048 * 4, 1440, 900, OVERRIDE_NONE }, |
97 | [M_MBP_4] = { "mbp4", 0xc0060000, 2048 * 4, 1920, 1200 }, | 104 | [M_MBP_4] = { "mbp4", 0xc0060000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, |
98 | [M_MBP_5_1] = { "mbp51", 0xc0010000, 2048 * 4, 1440, 900 }, | 105 | [M_MBP_5_1] = { "mbp51", 0xc0010000, 2048 * 4, 1440, 900, OVERRIDE_NONE }, |
99 | [M_MBP_5_2] = { "mbp52", 0xc0010000, 2048 * 4, 1920, 1200 }, | 106 | [M_MBP_5_2] = { "mbp52", 0xc0010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, |
100 | [M_MBP_5_3] = { "mbp53", 0xd0010000, 2048 * 4, 1440, 900 }, | 107 | [M_MBP_5_3] = { "mbp53", 0xd0010000, 2048 * 4, 1440, 900, OVERRIDE_NONE }, |
101 | [M_MBP_6_1] = { "mbp61", 0x90030000, 2048 * 4, 1920, 1200 }, | 108 | [M_MBP_6_1] = { "mbp61", 0x90030000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, |
102 | [M_MBP_6_2] = { "mbp62", 0x90030000, 2048 * 4, 1680, 1050 }, | 109 | [M_MBP_6_2] = { "mbp62", 0x90030000, 2048 * 4, 1680, 1050, OVERRIDE_NONE }, |
103 | [M_MBP_7_1] = { "mbp71", 0xc0010000, 2048 * 4, 1280, 800 }, | 110 | [M_MBP_7_1] = { "mbp71", 0xc0010000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, |
104 | [M_MBP_8_2] = { "mbp82", 0x90010000, 1472 * 4, 1440, 900 }, | 111 | [M_MBP_8_2] = { "mbp82", 0x90010000, 1472 * 4, 1440, 900, OVERRIDE_NONE }, |
105 | [M_UNKNOWN] = { NULL, 0, 0, 0, 0 } | 112 | [M_UNKNOWN] = { NULL, 0, 0, 0, 0, OVERRIDE_NONE } |
106 | }; | 113 | }; |
107 | 114 | ||
108 | static int set_system(const struct dmi_system_id *id); | 115 | static int set_system(const struct dmi_system_id *id); |
@@ -157,16 +164,22 @@ static const struct dmi_system_id dmi_system_table[] __initconst = { | |||
157 | {}, | 164 | {}, |
158 | }; | 165 | }; |
159 | 166 | ||
167 | #define choose_value(dmivalue, fwvalue, field, flags) ({ \ | ||
168 | typeof(fwvalue) _ret_ = fwvalue; \ | ||
169 | if ((flags) & (field)) \ | ||
170 | _ret_ = dmivalue; \ | ||
171 | else if ((fwvalue) == 0) \ | ||
172 | _ret_ = dmivalue; \ | ||
173 | _ret_; \ | ||
174 | }) | ||
175 | |||
160 | static int set_system(const struct dmi_system_id *id) | 176 | static int set_system(const struct dmi_system_id *id) |
161 | { | 177 | { |
162 | struct efifb_dmi_info *info = id->driver_data; | 178 | struct efifb_dmi_info *info = id->driver_data; |
163 | if (info->base == 0) | ||
164 | return 0; | ||
165 | 179 | ||
166 | printk(KERN_INFO "efifb: dmi detected %s - framebuffer at %p " | 180 | if (info->base == 0 && info->height == 0 && info->width == 0 |
167 | "(%dx%d, stride %d)\n", id->ident, | 181 | && info->stride == 0) |
168 | (void *)info->base, info->width, info->height, | 182 | return 0; |
169 | info->stride); | ||
170 | 183 | ||
171 | /* Trust the bootloader over the DMI tables */ | 184 | /* Trust the bootloader over the DMI tables */ |
172 | if (screen_info.lfb_base == 0) { | 185 | if (screen_info.lfb_base == 0) { |
@@ -174,40 +187,47 @@ static int set_system(const struct dmi_system_id *id) | |||
174 | struct pci_dev *dev = NULL; | 187 | struct pci_dev *dev = NULL; |
175 | int found_bar = 0; | 188 | int found_bar = 0; |
176 | #endif | 189 | #endif |
177 | screen_info.lfb_base = info->base; | 190 | if (info->base) { |
191 | screen_info.lfb_base = choose_value(info->base, | ||
192 | screen_info.lfb_base, OVERRIDE_BASE, | ||
193 | info->flags); | ||
178 | 194 | ||
179 | #if defined(CONFIG_PCI) | 195 | #if defined(CONFIG_PCI) |
180 | /* make sure that the address in the table is actually on a | 196 | /* make sure that the address in the table is actually |
181 | * VGA device's PCI BAR */ | 197 | * on a VGA device's PCI BAR */ |
182 | 198 | ||
183 | for_each_pci_dev(dev) { | 199 | for_each_pci_dev(dev) { |
184 | int i; | 200 | int i; |
185 | if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) | 201 | if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) |
186 | continue; | 202 | continue; |
187 | for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { | 203 | for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { |
188 | resource_size_t start, end; | 204 | resource_size_t start, end; |
189 | 205 | ||
190 | start = pci_resource_start(dev, i); | 206 | start = pci_resource_start(dev, i); |
191 | if (start == 0) | 207 | if (start == 0) |
192 | break; | 208 | break; |
193 | end = pci_resource_end(dev, i); | 209 | end = pci_resource_end(dev, i); |
194 | if (screen_info.lfb_base >= start && | 210 | if (screen_info.lfb_base >= start && |
195 | screen_info.lfb_base < end) { | 211 | screen_info.lfb_base < end) { |
196 | found_bar = 1; | 212 | found_bar = 1; |
213 | } | ||
197 | } | 214 | } |
198 | } | 215 | } |
199 | } | 216 | if (!found_bar) |
200 | if (!found_bar) | 217 | screen_info.lfb_base = 0; |
201 | screen_info.lfb_base = 0; | ||
202 | #endif | 218 | #endif |
219 | } | ||
203 | } | 220 | } |
204 | if (screen_info.lfb_base) { | 221 | if (screen_info.lfb_base) { |
205 | if (screen_info.lfb_linelength == 0) | 222 | screen_info.lfb_linelength = choose_value(info->stride, |
206 | screen_info.lfb_linelength = info->stride; | 223 | screen_info.lfb_linelength, OVERRIDE_STRIDE, |
207 | if (screen_info.lfb_width == 0) | 224 | info->flags); |
208 | screen_info.lfb_width = info->width; | 225 | screen_info.lfb_width = choose_value(info->width, |
209 | if (screen_info.lfb_height == 0) | 226 | screen_info.lfb_width, OVERRIDE_WIDTH, |
210 | screen_info.lfb_height = info->height; | 227 | info->flags); |
228 | screen_info.lfb_height = choose_value(info->height, | ||
229 | screen_info.lfb_height, OVERRIDE_HEIGHT, | ||
230 | info->flags); | ||
211 | if (screen_info.orig_video_isVGA == 0) | 231 | if (screen_info.orig_video_isVGA == 0) |
212 | screen_info.orig_video_isVGA = VIDEO_TYPE_EFI; | 232 | screen_info.orig_video_isVGA = VIDEO_TYPE_EFI; |
213 | } else { | 233 | } else { |
@@ -217,6 +237,13 @@ static int set_system(const struct dmi_system_id *id) | |||
217 | screen_info.orig_video_isVGA = 0; | 237 | screen_info.orig_video_isVGA = 0; |
218 | return 0; | 238 | return 0; |
219 | } | 239 | } |
240 | |||
241 | printk(KERN_INFO "efifb: dmi detected %s - framebuffer at %p " | ||
242 | "(%dx%d, stride %d)\n", id->ident, | ||
243 | (void *)screen_info.lfb_base, screen_info.lfb_width, | ||
244 | screen_info.lfb_height, screen_info.lfb_linelength); | ||
245 | |||
246 | |||
220 | return 1; | 247 | return 1; |
221 | } | 248 | } |
222 | 249 | ||