aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/offb.c284
1 files changed, 118 insertions, 166 deletions
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index bfeb11bd4712..71ce1fa45cf4 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -97,14 +97,43 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
97 u_int transp, struct fb_info *info) 97 u_int transp, struct fb_info *info)
98{ 98{
99 struct offb_par *par = (struct offb_par *) info->par; 99 struct offb_par *par = (struct offb_par *) info->par;
100 int i, depth;
101 u32 *pal = info->pseudo_palette;
100 102
101 if (!par->cmap_adr || regno > 255) 103 depth = info->var.bits_per_pixel;
104 if (depth == 16)
105 depth = (info->var.green.length == 5) ? 15 : 16;
106
107 if (regno > 255 ||
108 (depth == 16 && regno > 63) ||
109 (depth == 15 && regno > 31))
102 return 1; 110 return 1;
103 111
112 if (regno < 16) {
113 switch (depth) {
114 case 15:
115 pal[regno] = (regno << 10) | (regno << 5) | regno;
116 break;
117 case 16:
118 pal[regno] = (regno << 11) | (regno << 5) | regno;
119 break;
120 case 24:
121 pal[regno] = (regno << 16) | (regno << 8) | regno;
122 break;
123 case 32:
124 i = (regno << 8) | regno;
125 pal[regno] = (i << 16) | i;
126 break;
127 }
128 }
129
104 red >>= 8; 130 red >>= 8;
105 green >>= 8; 131 green >>= 8;
106 blue >>= 8; 132 blue >>= 8;
107 133
134 if (!par->cmap_adr)
135 return 0;
136
108 switch (par->cmap_type) { 137 switch (par->cmap_type) {
109 case cmap_m64: 138 case cmap_m64:
110 writeb(regno, par->cmap_adr); 139 writeb(regno, par->cmap_adr);
@@ -141,20 +170,6 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
141 break; 170 break;
142 } 171 }
143 172
144 if (regno < 16)
145 switch (info->var.bits_per_pixel) {
146 case 16:
147 ((u16 *) (info->pseudo_palette))[regno] =
148 (regno << 10) | (regno << 5) | regno;
149 break;
150 case 32:
151 {
152 int i = (regno << 8) | regno;
153 ((u32 *) (info->pseudo_palette))[regno] =
154 (i << 16) | i;
155 break;
156 }
157 }
158 return 0; 173 return 0;
159} 174}
160 175
@@ -223,81 +238,9 @@ int __init offb_init(void)
223{ 238{
224 struct device_node *dp = NULL, *boot_disp = NULL; 239 struct device_node *dp = NULL, *boot_disp = NULL;
225 240
226#if defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32)
227 struct device_node *macos_display = NULL;
228#endif
229 if (fb_get_options("offb", NULL)) 241 if (fb_get_options("offb", NULL))
230 return -ENODEV; 242 return -ENODEV;
231 243
232#if defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32)
233 /* If we're booted from BootX... */
234 if (boot_infos != 0) {
235 unsigned long addr =
236 (unsigned long) boot_infos->dispDeviceBase;
237 u32 *addrp;
238 u64 daddr, dsize;
239 unsigned int flags;
240
241 /* find the device node corresponding to the macos display */
242 while ((dp = of_find_node_by_type(dp, "display"))) {
243 int i;
244
245 /*
246 * Look for an AAPL,address property first.
247 */
248 unsigned int na;
249 unsigned int *ap =
250 (unsigned int *)get_property(dp, "AAPL,address",
251 &na);
252 if (ap != 0) {
253 for (na /= sizeof(unsigned int); na > 0;
254 --na, ++ap)
255 if (*ap <= addr &&
256 addr < *ap + 0x1000000) {
257 macos_display = dp;
258 goto foundit;
259 }
260 }
261
262 /*
263 * See if the display address is in one of the address
264 * ranges for this display.
265 */
266 i = 0;
267 for (;;) {
268 addrp = of_get_address(dp, i++, &dsize, &flags);
269 if (addrp == NULL)
270 break;
271 if (!(flags & IORESOURCE_MEM))
272 continue;
273 daddr = of_translate_address(dp, addrp);
274 if (daddr == OF_BAD_ADDR)
275 continue;
276 if (daddr <= addr && addr < (daddr + dsize)) {
277 macos_display = dp;
278 goto foundit;
279 }
280 }
281 foundit:
282 if (macos_display) {
283 printk(KERN_INFO "MacOS display is %s\n",
284 dp->full_name);
285 break;
286 }
287 }
288
289 /* initialize it */
290 offb_init_fb(macos_display ? macos_display->
291 name : "MacOS display",
292 macos_display ? macos_display->
293 full_name : "MacOS display",
294 boot_infos->dispDeviceRect[2],
295 boot_infos->dispDeviceRect[3],
296 boot_infos->dispDeviceDepth,
297 boot_infos->dispDeviceRowBytes, addr, NULL);
298 }
299#endif /* defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32) */
300
301 for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) { 244 for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) {
302 if (get_property(dp, "linux,opened", NULL) && 245 if (get_property(dp, "linux,opened", NULL) &&
303 get_property(dp, "linux,boot-display", NULL)) { 246 get_property(dp, "linux,boot-display", NULL)) {
@@ -317,94 +260,93 @@ int __init offb_init(void)
317 260
318static void __init offb_init_nodriver(struct device_node *dp) 261static void __init offb_init_nodriver(struct device_node *dp)
319{ 262{
320 int *pp, i;
321 unsigned int len; 263 unsigned int len;
322 int width = 640, height = 480, depth = 8, pitch; 264 int i, width = 640, height = 480, depth = 8, pitch = 640;
323 unsigned int flags, rsize, *up; 265 unsigned int flags, rsize, addr_prop = 0;
324 u64 address = OF_BAD_ADDR; 266 unsigned long max_size = 0;
325 u32 *addrp; 267 u64 rstart, address = OF_BAD_ADDR;
268 u32 *pp, *addrp, *up;
326 u64 asize; 269 u64 asize;
327 270
328 if ((pp = (int *) get_property(dp, "depth", &len)) != NULL 271 pp = (u32 *)get_property(dp, "linux,bootx-depth", &len);
329 && len == sizeof(int)) 272 if (pp == NULL)
273 pp = (u32 *)get_property(dp, "depth", &len);
274 if (pp && len == sizeof(u32))
330 depth = *pp; 275 depth = *pp;
331 if ((pp = (int *) get_property(dp, "width", &len)) != NULL 276
332 && len == sizeof(int)) 277 pp = (u32 *)get_property(dp, "linux,bootx-width", &len);
278 if (pp == NULL)
279 pp = (u32 *)get_property(dp, "width", &len);
280 if (pp && len == sizeof(u32))
333 width = *pp; 281 width = *pp;
334 if ((pp = (int *) get_property(dp, "height", &len)) != NULL 282
335 && len == sizeof(int)) 283 pp = (u32 *)get_property(dp, "linux,bootx-height", &len);
284 if (pp == NULL)
285 pp = (u32 *)get_property(dp, "height", &len);
286 if (pp && len == sizeof(u32))
336 height = *pp; 287 height = *pp;
337 if ((pp = (int *) get_property(dp, "linebytes", &len)) != NULL 288
338 && len == sizeof(int)) { 289 pp = (u32 *)get_property(dp, "linux,bootx-linebytes", &len);
290 if (pp == NULL)
291 pp = (u32 *)get_property(dp, "linebytes", &len);
292 if (pp && len == sizeof(u32))
339 pitch = *pp; 293 pitch = *pp;
340 if (pitch == 1) 294 else
341 pitch = 0x1000; 295 pitch = width * ((depth + 7) / 8);
342 } else 296
343 pitch = width; 297 rsize = (unsigned long)pitch * (unsigned long)height;
344 298
345 rsize = (unsigned long)pitch * (unsigned long)height * 299 /* Ok, now we try to figure out the address of the framebuffer.
346 (unsigned long)(depth / 8); 300 *
347 301 * Unfortunately, Open Firmware doesn't provide a standard way to do
348 /* Try to match device to a PCI device in order to get a properly 302 * so. All we can do is a dodgy heuristic that happens to work in
349 * translated address rather then trying to decode the open firmware 303 * practice. On most machines, the "address" property contains what
350 * stuff in various incorrect ways 304 * we need, though not on Matrox cards found in IBM machines. What I've
351 */ 305 * found that appears to give good results is to go through the PCI
352#ifdef CONFIG_PCI 306 * ranges and pick one that is both big enough and if possible encloses
353 /* First try to locate the PCI device if any */ 307 * the "address" property. If none match, we pick the biggest
354 { 308 */
355 struct pci_dev *pdev = NULL; 309 up = (u32 *)get_property(dp, "linux,bootx-addr", &len);
356 310 if (up == NULL)
357 for_each_pci_dev(pdev) { 311 up = (u32 *)get_property(dp, "address", &len);
358 if (dp == pci_device_to_OF_node(pdev)) 312 if (up && len == sizeof(u32))
359 break; 313 addr_prop = *up;
360 } 314
361 if (pdev) { 315 for (i = 0; (addrp = of_get_address(dp, i, &asize, &flags))
362 for (i = 0; i < 6 && address == OF_BAD_ADDR; i++) { 316 != NULL; i++) {
363 if ((pci_resource_flags(pdev, i) & 317 int match_addrp = 0;
364 IORESOURCE_MEM) && 318
365 (pci_resource_len(pdev, i) >= rsize)) 319 if (!(flags & IORESOURCE_MEM))
366 address = pci_resource_start(pdev, i); 320 continue;
367 } 321 if (asize < rsize)
368 pci_dev_put(pdev); 322 continue;
369 } 323 rstart = of_translate_address(dp, addrp);
370 } 324 if (rstart == OF_BAD_ADDR)
371#endif /* CONFIG_PCI */ 325 continue;
372 326 if (addr_prop && (rstart <= addr_prop) &&
373 /* This one is dodgy, we may drop it ... */ 327 ((rstart + asize) >= (addr_prop + rsize)))
374 if (address == OF_BAD_ADDR && 328 match_addrp = 1;
375 (up = (unsigned *) get_property(dp, "address", &len)) != NULL && 329 if (match_addrp) {
376 len == sizeof(unsigned int)) 330 address = addr_prop;
377 address = (u64) * up; 331 break;
378
379 if (address == OF_BAD_ADDR) {
380 for (i = 0; (addrp = of_get_address(dp, i, &asize, &flags))
381 != NULL; i++) {
382 if (!(flags & IORESOURCE_MEM))
383 continue;
384 if (asize >= pitch * height * depth / 8)
385 break;
386 }
387 if (addrp == NULL) {
388 printk(KERN_ERR
389 "no framebuffer address found for %s\n",
390 dp->full_name);
391 return;
392 }
393 address = of_translate_address(dp, addrp);
394 if (address == OF_BAD_ADDR) {
395 printk(KERN_ERR
396 "can't translate framebuffer address for %s\n",
397 dp->full_name);
398 return;
399 } 332 }
333 if (rsize > max_size) {
334 max_size = rsize;
335 address = OF_BAD_ADDR;
336 }
400 337
338 if (address == OF_BAD_ADDR)
339 address = rstart;
340 }
341 if (address == OF_BAD_ADDR && addr_prop)
342 address = (u64)addr_prop;
343 if (address != OF_BAD_ADDR) {
401 /* kludge for valkyrie */ 344 /* kludge for valkyrie */
402 if (strcmp(dp->name, "valkyrie") == 0) 345 if (strcmp(dp->name, "valkyrie") == 0)
403 address += 0x1000; 346 address += 0x1000;
347 offb_init_fb(dp->name, dp->full_name, width, height, depth,
348 pitch, address, dp);
404 } 349 }
405 offb_init_fb(dp->name, dp->full_name, width, height, depth,
406 pitch, address, dp);
407
408} 350}
409 351
410static void __init offb_init_fb(const char *name, const char *full_name, 352static void __init offb_init_fb(const char *name, const char *full_name,
@@ -412,7 +354,7 @@ static void __init offb_init_fb(const char *name, const char *full_name,
412 int pitch, unsigned long address, 354 int pitch, unsigned long address,
413 struct device_node *dp) 355 struct device_node *dp)
414{ 356{
415 unsigned long res_size = pitch * height * depth / 8; 357 unsigned long res_size = pitch * height * (depth + 7) / 8;
416 struct offb_par *par = &default_par; 358 struct offb_par *par = &default_par;
417 unsigned long res_start = address; 359 unsigned long res_start = address;
418 struct fb_fix_screeninfo *fix; 360 struct fb_fix_screeninfo *fix;
@@ -426,7 +368,7 @@ static void __init offb_init_fb(const char *name, const char *full_name,
426 printk(KERN_INFO 368 printk(KERN_INFO
427 "Using unsupported %dx%d %s at %lx, depth=%d, pitch=%d\n", 369 "Using unsupported %dx%d %s at %lx, depth=%d, pitch=%d\n",
428 width, height, name, address, depth, pitch); 370 width, height, name, address, depth, pitch);
429 if (depth != 8 && depth != 16 && depth != 32) { 371 if (depth != 8 && depth != 15 && depth != 16 && depth != 32) {
430 printk(KERN_ERR "%s: can't use depth = %d\n", full_name, 372 printk(KERN_ERR "%s: can't use depth = %d\n", full_name,
431 depth); 373 depth);
432 release_mem_region(res_start, res_size); 374 release_mem_region(res_start, res_size);
@@ -502,7 +444,6 @@ static void __init offb_init_fb(const char *name, const char *full_name,
502 : */ FB_VISUAL_TRUECOLOR; 444 : */ FB_VISUAL_TRUECOLOR;
503 445
504 var->xoffset = var->yoffset = 0; 446 var->xoffset = var->yoffset = 0;
505 var->bits_per_pixel = depth;
506 switch (depth) { 447 switch (depth) {
507 case 8: 448 case 8:
508 var->bits_per_pixel = 8; 449 var->bits_per_pixel = 8;
@@ -515,7 +456,7 @@ static void __init offb_init_fb(const char *name, const char *full_name,
515 var->transp.offset = 0; 456 var->transp.offset = 0;
516 var->transp.length = 0; 457 var->transp.length = 0;
517 break; 458 break;
518 case 16: /* RGB 555 */ 459 case 15: /* RGB 555 */
519 var->bits_per_pixel = 16; 460 var->bits_per_pixel = 16;
520 var->red.offset = 10; 461 var->red.offset = 10;
521 var->red.length = 5; 462 var->red.length = 5;
@@ -526,6 +467,17 @@ static void __init offb_init_fb(const char *name, const char *full_name,
526 var->transp.offset = 0; 467 var->transp.offset = 0;
527 var->transp.length = 0; 468 var->transp.length = 0;
528 break; 469 break;
470 case 16: /* RGB 565 */
471 var->bits_per_pixel = 16;
472 var->red.offset = 11;
473 var->red.length = 5;
474 var->green.offset = 5;
475 var->green.length = 6;
476 var->blue.offset = 0;
477 var->blue.length = 5;
478 var->transp.offset = 0;
479 var->transp.length = 0;
480 break;
529 case 32: /* RGB 888 */ 481 case 32: /* RGB 888 */
530 var->bits_per_pixel = 32; 482 var->bits_per_pixel = 32;
531 var->red.offset = 16; 483 var->red.offset = 16;