aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/efifb.c
diff options
context:
space:
mode:
authorPeter Jones <pjones@redhat.com>2011-04-06 13:34:58 -0400
committerPaul Mundt <lethal@linux-sh.org>2011-04-06 13:58:10 -0400
commit47dfe51f8f0b9540cbe15072cd352d9f3857d47f (patch)
treec09deee3af82bbeb4186ae17aaf9070c680b1099 /drivers/video/efifb.c
parent47c87d930f3db4fc3a30505075e07f5597e2e953 (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>
Diffstat (limited to 'drivers/video/efifb.c')
-rw-r--r--drivers/video/efifb.c149
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
71static struct efifb_dmi_info { 77static 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
108static int set_system(const struct dmi_system_id *id); 115static 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
160static int set_system(const struct dmi_system_id *id) 176static 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