aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/offb.c
diff options
context:
space:
mode:
authorDmitry Torokhov <dtor@insightbb.com>2006-09-19 01:56:44 -0400
committerDmitry Torokhov <dtor@insightbb.com>2006-09-19 01:56:44 -0400
commit0612ec48762bf8712db1925b2e67246d2237ebab (patch)
tree01b0d69c9c9915015c0f23ad4263646dd5413e99 /drivers/video/offb.c
parent4263cf0fac28122c8381b6f4f9441a43cd93c81f (diff)
parent47a5c6fa0e204a2b63309c648bb2fde36836c826 (diff)
Merge rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'drivers/video/offb.c')
-rw-r--r--drivers/video/offb.c308
1 files changed, 161 insertions, 147 deletions
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index 71ce1fa45cf4..0013311e0564 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -17,7 +17,6 @@
17#include <linux/errno.h> 17#include <linux/errno.h>
18#include <linux/string.h> 18#include <linux/string.h>
19#include <linux/mm.h> 19#include <linux/mm.h>
20#include <linux/tty.h>
21#include <linux/slab.h> 20#include <linux/slab.h>
22#include <linux/vmalloc.h> 21#include <linux/vmalloc.h>
23#include <linux/delay.h> 22#include <linux/delay.h>
@@ -63,8 +62,6 @@ struct offb_par default_par;
63 * Interface used by the world 62 * Interface used by the world
64 */ 63 */
65 64
66int offb_init(void);
67
68static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 65static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
69 u_int transp, struct fb_info *info); 66 u_int transp, struct fb_info *info);
70static int offb_blank(int blank, struct fb_info *info); 67static int offb_blank(int blank, struct fb_info *info);
@@ -73,11 +70,6 @@ static int offb_blank(int blank, struct fb_info *info);
73extern boot_infos_t *boot_infos; 70extern boot_infos_t *boot_infos;
74#endif 71#endif
75 72
76static void offb_init_nodriver(struct device_node *);
77static void offb_init_fb(const char *name, const char *full_name,
78 int width, int height, int depth, int pitch,
79 unsigned long address, struct device_node *dp);
80
81static struct fb_ops offb_ops = { 73static struct fb_ops offb_ops = {
82 .owner = THIS_MODULE, 74 .owner = THIS_MODULE,
83 .fb_setcolreg = offb_setcolreg, 75 .fb_setcolreg = offb_setcolreg,
@@ -230,123 +222,17 @@ static int offb_blank(int blank, struct fb_info *info)
230 return 0; 222 return 0;
231} 223}
232 224
233 /*
234 * Initialisation
235 */
236 225
237int __init offb_init(void) 226static void __iomem *offb_map_reg(struct device_node *np, int index,
227 unsigned long offset, unsigned long size)
238{ 228{
239 struct device_node *dp = NULL, *boot_disp = NULL; 229 struct resource r;
240
241 if (fb_get_options("offb", NULL))
242 return -ENODEV;
243 230
244 for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) { 231 if (of_address_to_resource(np, index, &r))
245 if (get_property(dp, "linux,opened", NULL) && 232 return 0;
246 get_property(dp, "linux,boot-display", NULL)) { 233 if ((r.start + offset + size) > r.end)
247 boot_disp = dp; 234 return 0;
248 offb_init_nodriver(dp); 235 return ioremap(r.start + offset, size);
249 }
250 }
251 for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) {
252 if (get_property(dp, "linux,opened", NULL) &&
253 dp != boot_disp)
254 offb_init_nodriver(dp);
255 }
256
257 return 0;
258}
259
260
261static void __init offb_init_nodriver(struct device_node *dp)
262{
263 unsigned int len;
264 int i, width = 640, height = 480, depth = 8, pitch = 640;
265 unsigned int flags, rsize, addr_prop = 0;
266 unsigned long max_size = 0;
267 u64 rstart, address = OF_BAD_ADDR;
268 u32 *pp, *addrp, *up;
269 u64 asize;
270
271 pp = (u32 *)get_property(dp, "linux,bootx-depth", &len);
272 if (pp == NULL)
273 pp = (u32 *)get_property(dp, "depth", &len);
274 if (pp && len == sizeof(u32))
275 depth = *pp;
276
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))
281 width = *pp;
282
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))
287 height = *pp;
288
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))
293 pitch = *pp;
294 else
295 pitch = width * ((depth + 7) / 8);
296
297 rsize = (unsigned long)pitch * (unsigned long)height;
298
299 /* Ok, now we try to figure out the address of the framebuffer.
300 *
301 * Unfortunately, Open Firmware doesn't provide a standard way to do
302 * so. All we can do is a dodgy heuristic that happens to work in
303 * practice. On most machines, the "address" property contains what
304 * we need, though not on Matrox cards found in IBM machines. What I've
305 * found that appears to give good results is to go through the PCI
306 * ranges and pick one that is both big enough and if possible encloses
307 * the "address" property. If none match, we pick the biggest
308 */
309 up = (u32 *)get_property(dp, "linux,bootx-addr", &len);
310 if (up == NULL)
311 up = (u32 *)get_property(dp, "address", &len);
312 if (up && len == sizeof(u32))
313 addr_prop = *up;
314
315 for (i = 0; (addrp = of_get_address(dp, i, &asize, &flags))
316 != NULL; i++) {
317 int match_addrp = 0;
318
319 if (!(flags & IORESOURCE_MEM))
320 continue;
321 if (asize < rsize)
322 continue;
323 rstart = of_translate_address(dp, addrp);
324 if (rstart == OF_BAD_ADDR)
325 continue;
326 if (addr_prop && (rstart <= addr_prop) &&
327 ((rstart + asize) >= (addr_prop + rsize)))
328 match_addrp = 1;
329 if (match_addrp) {
330 address = addr_prop;
331 break;
332 }
333 if (rsize > max_size) {
334 max_size = rsize;
335 address = OF_BAD_ADDR;
336 }
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) {
344 /* kludge for valkyrie */
345 if (strcmp(dp->name, "valkyrie") == 0)
346 address += 0x1000;
347 offb_init_fb(dp->name, dp->full_name, width, height, depth,
348 pitch, address, dp);
349 }
350} 236}
351 237
352static void __init offb_init_fb(const char *name, const char *full_name, 238static void __init offb_init_fb(const char *name, const char *full_name,
@@ -403,45 +289,39 @@ static void __init offb_init_fb(const char *name, const char *full_name,
403 289
404 par->cmap_type = cmap_unknown; 290 par->cmap_type = cmap_unknown;
405 if (depth == 8) { 291 if (depth == 8) {
406
407 /* Palette hacks disabled for now */ 292 /* Palette hacks disabled for now */
408#if 0
409 if (dp && !strncmp(name, "ATY,Rage128", 11)) { 293 if (dp && !strncmp(name, "ATY,Rage128", 11)) {
410 unsigned long regbase = dp->addrs[2].address; 294 par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff);
411 par->cmap_adr = ioremap(regbase, 0x1FFF); 295 if (par->cmap_adr)
412 par->cmap_type = cmap_r128; 296 par->cmap_type = cmap_r128;
413 } else if (dp && (!strncmp(name, "ATY,RageM3pA", 12) 297 } else if (dp && (!strncmp(name, "ATY,RageM3pA", 12)
414 || !strncmp(name, "ATY,RageM3p12A", 14))) { 298 || !strncmp(name, "ATY,RageM3p12A", 14))) {
415 unsigned long regbase = 299 par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff);
416 dp->parent->addrs[2].address; 300 if (par->cmap_adr)
417 par->cmap_adr = ioremap(regbase, 0x1FFF); 301 par->cmap_type = cmap_M3A;
418 par->cmap_type = cmap_M3A;
419 } else if (dp && !strncmp(name, "ATY,RageM3pB", 12)) { 302 } else if (dp && !strncmp(name, "ATY,RageM3pB", 12)) {
420 unsigned long regbase = 303 par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff);
421 dp->parent->addrs[2].address; 304 if (par->cmap_adr)
422 par->cmap_adr = ioremap(regbase, 0x1FFF); 305 par->cmap_type = cmap_M3B;
423 par->cmap_type = cmap_M3B;
424 } else if (dp && !strncmp(name, "ATY,Rage6", 9)) { 306 } else if (dp && !strncmp(name, "ATY,Rage6", 9)) {
425 unsigned long regbase = dp->addrs[1].address; 307 par->cmap_adr = offb_map_reg(dp, 1, 0, 0x1fff);
426 par->cmap_adr = ioremap(regbase, 0x1FFF); 308 if (par->cmap_adr)
427 par->cmap_type = cmap_radeon; 309 par->cmap_type = cmap_radeon;
428 } else if (!strncmp(name, "ATY,", 4)) { 310 } else if (!strncmp(name, "ATY,", 4)) {
429 unsigned long base = address & 0xff000000UL; 311 unsigned long base = address & 0xff000000UL;
430 par->cmap_adr = 312 par->cmap_adr =
431 ioremap(base + 0x7ff000, 0x1000) + 0xcc0; 313 ioremap(base + 0x7ff000, 0x1000) + 0xcc0;
432 par->cmap_data = par->cmap_adr + 1; 314 par->cmap_data = par->cmap_adr + 1;
433 par->cmap_type = cmap_m64; 315 par->cmap_type = cmap_m64;
434 } else if (device_is_compatible(dp, "pci1014,b7")) { 316 } else if (dp && device_is_compatible(dp, "pci1014,b7")) {
435 unsigned long regbase = dp->addrs[0].address; 317 par->cmap_adr = offb_map_reg(dp, 0, 0x6000, 0x1000);
436 par->cmap_adr = ioremap(regbase + 0x6000, 0x1000); 318 if (par->cmap_adr)
437 par->cmap_type = cmap_gxt2000; 319 par->cmap_type = cmap_gxt2000;
438 } 320 }
439#endif 321 fix->visual = (par->cmap_type != cmap_unknown) ?
440 fix->visual = par->cmap_adr ? FB_VISUAL_PSEUDOCOLOR 322 FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_STATIC_PSEUDOCOLOR;
441 : FB_VISUAL_STATIC_PSEUDOCOLOR;
442 } else 323 } else
443 fix->visual = /* par->cmap_adr ? FB_VISUAL_DIRECTCOLOR 324 fix->visual = FB_VISUAL_TRUECOLOR;
444 : */ FB_VISUAL_TRUECOLOR;
445 325
446 var->xoffset = var->yoffset = 0; 326 var->xoffset = var->yoffset = 0;
447 switch (depth) { 327 switch (depth) {
@@ -521,5 +401,139 @@ static void __init offb_init_fb(const char *name, const char *full_name,
521 info->node, full_name); 401 info->node, full_name);
522} 402}
523 403
404
405static void __init offb_init_nodriver(struct device_node *dp, int no_real_node)
406{
407 unsigned int len;
408 int i, width = 640, height = 480, depth = 8, pitch = 640;
409 unsigned int flags, rsize, addr_prop = 0;
410 unsigned long max_size = 0;
411 u64 rstart, address = OF_BAD_ADDR;
412 u32 *pp, *addrp, *up;
413 u64 asize;
414
415 pp = (u32 *)get_property(dp, "linux,bootx-depth", &len);
416 if (pp == NULL)
417 pp = (u32 *)get_property(dp, "depth", &len);
418 if (pp && len == sizeof(u32))
419 depth = *pp;
420
421 pp = (u32 *)get_property(dp, "linux,bootx-width", &len);
422 if (pp == NULL)
423 pp = (u32 *)get_property(dp, "width", &len);
424 if (pp && len == sizeof(u32))
425 width = *pp;
426
427 pp = (u32 *)get_property(dp, "linux,bootx-height", &len);
428 if (pp == NULL)
429 pp = (u32 *)get_property(dp, "height", &len);
430 if (pp && len == sizeof(u32))
431 height = *pp;
432
433 pp = (u32 *)get_property(dp, "linux,bootx-linebytes", &len);
434 if (pp == NULL)
435 pp = (u32 *)get_property(dp, "linebytes", &len);
436 if (pp && len == sizeof(u32))
437 pitch = *pp;
438 else
439 pitch = width * ((depth + 7) / 8);
440
441 rsize = (unsigned long)pitch * (unsigned long)height;
442
443 /* Ok, now we try to figure out the address of the framebuffer.
444 *
445 * Unfortunately, Open Firmware doesn't provide a standard way to do
446 * so. All we can do is a dodgy heuristic that happens to work in
447 * practice. On most machines, the "address" property contains what
448 * we need, though not on Matrox cards found in IBM machines. What I've
449 * found that appears to give good results is to go through the PCI
450 * ranges and pick one that is both big enough and if possible encloses
451 * the "address" property. If none match, we pick the biggest
452 */
453 up = (u32 *)get_property(dp, "linux,bootx-addr", &len);
454 if (up == NULL)
455 up = (u32 *)get_property(dp, "address", &len);
456 if (up && len == sizeof(u32))
457 addr_prop = *up;
458
459 /* Hack for when BootX is passing us */
460 if (no_real_node)
461 goto skip_addr;
462
463 for (i = 0; (addrp = of_get_address(dp, i, &asize, &flags))
464 != NULL; i++) {
465 int match_addrp = 0;
466
467 if (!(flags & IORESOURCE_MEM))
468 continue;
469 if (asize < rsize)
470 continue;
471 rstart = of_translate_address(dp, addrp);
472 if (rstart == OF_BAD_ADDR)
473 continue;
474 if (addr_prop && (rstart <= addr_prop) &&
475 ((rstart + asize) >= (addr_prop + rsize)))
476 match_addrp = 1;
477 if (match_addrp) {
478 address = addr_prop;
479 break;
480 }
481 if (rsize > max_size) {
482 max_size = rsize;
483 address = OF_BAD_ADDR;
484 }
485
486 if (address == OF_BAD_ADDR)
487 address = rstart;
488 }
489 skip_addr:
490 if (address == OF_BAD_ADDR && addr_prop)
491 address = (u64)addr_prop;
492 if (address != OF_BAD_ADDR) {
493 /* kludge for valkyrie */
494 if (strcmp(dp->name, "valkyrie") == 0)
495 address += 0x1000;
496 offb_init_fb(no_real_node ? "bootx" : dp->name,
497 no_real_node ? "display" : dp->full_name,
498 width, height, depth, pitch, address,
499 no_real_node ? dp : NULL);
500 }
501}
502
503static int __init offb_init(void)
504{
505 struct device_node *dp = NULL, *boot_disp = NULL;
506
507 if (fb_get_options("offb", NULL))
508 return -ENODEV;
509
510 /* Check if we have a MacOS display without a node spec */
511 if (get_property(of_chosen, "linux,bootx-noscreen", NULL) != NULL) {
512 /* The old code tried to work out which node was the MacOS
513 * display based on the address. I'm dropping that since the
514 * lack of a node spec only happens with old BootX versions
515 * (users can update) and with this code, they'll still get
516 * a display (just not the palette hacks).
517 */
518 offb_init_nodriver(of_chosen, 1);
519 }
520
521 for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) {
522 if (get_property(dp, "linux,opened", NULL) &&
523 get_property(dp, "linux,boot-display", NULL)) {
524 boot_disp = dp;
525 offb_init_nodriver(dp, 0);
526 }
527 }
528 for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) {
529 if (get_property(dp, "linux,opened", NULL) &&
530 dp != boot_disp)
531 offb_init_nodriver(dp, 0);
532 }
533
534 return 0;
535}
536
537
524module_init(offb_init); 538module_init(offb_init);
525MODULE_LICENSE("GPL"); 539MODULE_LICENSE("GPL");