2 * linux/drivers/video/offb.c -- Open Firmware based frame buffer device
4 * Copyright (C) 1997 Geert Uytterhoeven
6 * This driver is partly based on the PowerMac console driver:
8 * Copyright (C) 1996 Paul Mackerras
10 * This file is subject to the terms and conditions of the GNU General Public
11 * License. See the file COPYING in the main directory of this archive for
15 #include <linux/module.h>
16 #include <linux/kernel.h>
17 #include <linux/errno.h>
18 #include <linux/string.h>
20 #include <linux/vmalloc.h>
21 #include <linux/delay.h>
23 #include <linux/of_address.h>
24 #include <linux/interrupt.h>
26 #include <linux/init.h>
27 #include <linux/ioport.h>
28 #include <linux/pci.h>
32 #include <asm/pci-bridge.h>
36 #include <asm/bootx.h>
41 /* Supported palette hacks */
44 cmap_simple
, /* ATI Mach64 */
45 cmap_r128
, /* ATI Rage128 */
46 cmap_M3A
, /* ATI Rage Mobility M3 Head A */
47 cmap_M3B
, /* ATI Rage Mobility M3 Head B */
48 cmap_radeon
, /* ATI Radeon */
49 cmap_gxt2000
, /* IBM GXT2000 */
50 cmap_avivo
, /* ATI R5xx */
51 cmap_qemu
, /* qemu vga */
55 volatile void __iomem
*cmap_adr
;
56 volatile void __iomem
*cmap_data
;
61 struct offb_par default_par
;
64 extern boot_infos_t
*boot_infos
;
67 /* Definitions used by the Avivo palette hack */
68 #define AVIVO_DC_LUT_RW_SELECT 0x6480
69 #define AVIVO_DC_LUT_RW_MODE 0x6484
70 #define AVIVO_DC_LUT_RW_INDEX 0x6488
71 #define AVIVO_DC_LUT_SEQ_COLOR 0x648c
72 #define AVIVO_DC_LUT_PWL_DATA 0x6490
73 #define AVIVO_DC_LUT_30_COLOR 0x6494
74 #define AVIVO_DC_LUT_READ_PIPE_SELECT 0x6498
75 #define AVIVO_DC_LUT_WRITE_EN_MASK 0x649c
76 #define AVIVO_DC_LUT_AUTOFILL 0x64a0
78 #define AVIVO_DC_LUTA_CONTROL 0x64c0
79 #define AVIVO_DC_LUTA_BLACK_OFFSET_BLUE 0x64c4
80 #define AVIVO_DC_LUTA_BLACK_OFFSET_GREEN 0x64c8
81 #define AVIVO_DC_LUTA_BLACK_OFFSET_RED 0x64cc
82 #define AVIVO_DC_LUTA_WHITE_OFFSET_BLUE 0x64d0
83 #define AVIVO_DC_LUTA_WHITE_OFFSET_GREEN 0x64d4
84 #define AVIVO_DC_LUTA_WHITE_OFFSET_RED 0x64d8
86 #define AVIVO_DC_LUTB_CONTROL 0x6cc0
87 #define AVIVO_DC_LUTB_BLACK_OFFSET_BLUE 0x6cc4
88 #define AVIVO_DC_LUTB_BLACK_OFFSET_GREEN 0x6cc8
89 #define AVIVO_DC_LUTB_BLACK_OFFSET_RED 0x6ccc
90 #define AVIVO_DC_LUTB_WHITE_OFFSET_BLUE 0x6cd0
91 #define AVIVO_DC_LUTB_WHITE_OFFSET_GREEN 0x6cd4
92 #define AVIVO_DC_LUTB_WHITE_OFFSET_RED 0x6cd8
94 #define FB_RIGHT_POS(p, bpp) (fb_be_math(p) ? 0 : (32 - (bpp)))
96 static inline u32
offb_cmap_byteswap(struct fb_info
*info
, u32 value
)
98 u32 bpp
= info
->var
.bits_per_pixel
;
100 return cpu_to_be32(value
) >> FB_RIGHT_POS(info
, bpp
);
104 * Set a single color register. The values supplied are already
105 * rounded down to the hardware's capabilities (according to the
106 * entries in the var structure). Return != 0 for invalid regno.
109 static int offb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
110 u_int transp
, struct fb_info
*info
)
112 struct offb_par
*par
= (struct offb_par
*) info
->par
;
114 if (info
->fix
.visual
== FB_VISUAL_TRUECOLOR
) {
115 u32
*pal
= info
->pseudo_palette
;
116 u32 cr
= red
>> (16 - info
->var
.red
.length
);
117 u32 cg
= green
>> (16 - info
->var
.green
.length
);
118 u32 cb
= blue
>> (16 - info
->var
.blue
.length
);
124 value
= (cr
<< info
->var
.red
.offset
) |
125 (cg
<< info
->var
.green
.offset
) |
126 (cb
<< info
->var
.blue
.offset
);
127 if (info
->var
.transp
.length
> 0) {
128 u32 mask
= (1 << info
->var
.transp
.length
) - 1;
129 mask
<<= info
->var
.transp
.offset
;
132 pal
[regno
] = offb_cmap_byteswap(info
, value
);
146 switch (par
->cmap_type
) {
148 writeb(regno
, par
->cmap_adr
);
149 writeb(red
, par
->cmap_data
);
150 writeb(green
, par
->cmap_data
);
151 writeb(blue
, par
->cmap_data
);
154 /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */
155 out_le32(par
->cmap_adr
+ 0x58,
156 in_le32(par
->cmap_adr
+ 0x58) & ~0x20);
158 /* Set palette index & data */
159 out_8(par
->cmap_adr
+ 0xb0, regno
);
160 out_le32(par
->cmap_adr
+ 0xb4,
161 (red
<< 16 | green
<< 8 | blue
));
164 /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */
165 out_le32(par
->cmap_adr
+ 0x58,
166 in_le32(par
->cmap_adr
+ 0x58) | 0x20);
167 /* Set palette index & data */
168 out_8(par
->cmap_adr
+ 0xb0, regno
);
169 out_le32(par
->cmap_adr
+ 0xb4, (red
<< 16 | green
<< 8 | blue
));
172 /* Set palette index & data (could be smarter) */
173 out_8(par
->cmap_adr
+ 0xb0, regno
);
174 out_le32(par
->cmap_adr
+ 0xb4, (red
<< 16 | green
<< 8 | blue
));
177 out_le32(((unsigned __iomem
*) par
->cmap_adr
) + regno
,
178 (red
<< 16 | green
<< 8 | blue
));
181 /* Write to both LUTs for now */
182 writel(1, par
->cmap_adr
+ AVIVO_DC_LUT_RW_SELECT
);
183 writeb(regno
, par
->cmap_adr
+ AVIVO_DC_LUT_RW_INDEX
);
184 writel(((red
) << 22) | ((green
) << 12) | ((blue
) << 2),
185 par
->cmap_adr
+ AVIVO_DC_LUT_30_COLOR
);
186 writel(0, par
->cmap_adr
+ AVIVO_DC_LUT_RW_SELECT
);
187 writeb(regno
, par
->cmap_adr
+ AVIVO_DC_LUT_RW_INDEX
);
188 writel(((red
) << 22) | ((green
) << 12) | ((blue
) << 2),
189 par
->cmap_adr
+ AVIVO_DC_LUT_30_COLOR
);
200 static int offb_blank(int blank
, struct fb_info
*info
)
202 struct offb_par
*par
= (struct offb_par
*) info
->par
;
212 par
->blanked
= blank
;
215 for (i
= 0; i
< 256; i
++) {
216 switch (par
->cmap_type
) {
218 writeb(i
, par
->cmap_adr
);
219 for (j
= 0; j
< 3; j
++)
220 writeb(0, par
->cmap_data
);
223 /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */
224 out_le32(par
->cmap_adr
+ 0x58,
225 in_le32(par
->cmap_adr
+ 0x58) & ~0x20);
227 /* Set palette index & data */
228 out_8(par
->cmap_adr
+ 0xb0, i
);
229 out_le32(par
->cmap_adr
+ 0xb4, 0);
232 /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */
233 out_le32(par
->cmap_adr
+ 0x58,
234 in_le32(par
->cmap_adr
+ 0x58) | 0x20);
235 /* Set palette index & data */
236 out_8(par
->cmap_adr
+ 0xb0, i
);
237 out_le32(par
->cmap_adr
+ 0xb4, 0);
240 out_8(par
->cmap_adr
+ 0xb0, i
);
241 out_le32(par
->cmap_adr
+ 0xb4, 0);
244 out_le32(((unsigned __iomem
*) par
->cmap_adr
) + i
,
248 writel(1, par
->cmap_adr
+ AVIVO_DC_LUT_RW_SELECT
);
249 writeb(i
, par
->cmap_adr
+ AVIVO_DC_LUT_RW_INDEX
);
250 writel(0, par
->cmap_adr
+ AVIVO_DC_LUT_30_COLOR
);
251 writel(0, par
->cmap_adr
+ AVIVO_DC_LUT_RW_SELECT
);
252 writeb(i
, par
->cmap_adr
+ AVIVO_DC_LUT_RW_INDEX
);
253 writel(0, par
->cmap_adr
+ AVIVO_DC_LUT_30_COLOR
);
257 fb_set_cmap(&info
->cmap
, info
);
261 static int offb_set_par(struct fb_info
*info
)
263 struct offb_par
*par
= (struct offb_par
*) info
->par
;
265 /* On avivo, initialize palette control */
266 if (par
->cmap_type
== cmap_avivo
) {
267 writel(0, par
->cmap_adr
+ AVIVO_DC_LUTA_CONTROL
);
268 writel(0, par
->cmap_adr
+ AVIVO_DC_LUTA_BLACK_OFFSET_BLUE
);
269 writel(0, par
->cmap_adr
+ AVIVO_DC_LUTA_BLACK_OFFSET_GREEN
);
270 writel(0, par
->cmap_adr
+ AVIVO_DC_LUTA_BLACK_OFFSET_RED
);
271 writel(0x0000ffff, par
->cmap_adr
+ AVIVO_DC_LUTA_WHITE_OFFSET_BLUE
);
272 writel(0x0000ffff, par
->cmap_adr
+ AVIVO_DC_LUTA_WHITE_OFFSET_GREEN
);
273 writel(0x0000ffff, par
->cmap_adr
+ AVIVO_DC_LUTA_WHITE_OFFSET_RED
);
274 writel(0, par
->cmap_adr
+ AVIVO_DC_LUTB_CONTROL
);
275 writel(0, par
->cmap_adr
+ AVIVO_DC_LUTB_BLACK_OFFSET_BLUE
);
276 writel(0, par
->cmap_adr
+ AVIVO_DC_LUTB_BLACK_OFFSET_GREEN
);
277 writel(0, par
->cmap_adr
+ AVIVO_DC_LUTB_BLACK_OFFSET_RED
);
278 writel(0x0000ffff, par
->cmap_adr
+ AVIVO_DC_LUTB_WHITE_OFFSET_BLUE
);
279 writel(0x0000ffff, par
->cmap_adr
+ AVIVO_DC_LUTB_WHITE_OFFSET_GREEN
);
280 writel(0x0000ffff, par
->cmap_adr
+ AVIVO_DC_LUTB_WHITE_OFFSET_RED
);
281 writel(1, par
->cmap_adr
+ AVIVO_DC_LUT_RW_SELECT
);
282 writel(0, par
->cmap_adr
+ AVIVO_DC_LUT_RW_MODE
);
283 writel(0x0000003f, par
->cmap_adr
+ AVIVO_DC_LUT_WRITE_EN_MASK
);
284 writel(0, par
->cmap_adr
+ AVIVO_DC_LUT_RW_SELECT
);
285 writel(0, par
->cmap_adr
+ AVIVO_DC_LUT_RW_MODE
);
286 writel(0x0000003f, par
->cmap_adr
+ AVIVO_DC_LUT_WRITE_EN_MASK
);
291 static void offb_destroy(struct fb_info
*info
)
293 if (info
->screen_base
)
294 iounmap(info
->screen_base
);
295 release_mem_region(info
->apertures
->ranges
[0].base
, info
->apertures
->ranges
[0].size
);
296 framebuffer_release(info
);
299 static struct fb_ops offb_ops
= {
300 .owner
= THIS_MODULE
,
301 .fb_destroy
= offb_destroy
,
302 .fb_setcolreg
= offb_setcolreg
,
303 .fb_set_par
= offb_set_par
,
304 .fb_blank
= offb_blank
,
305 .fb_fillrect
= cfb_fillrect
,
306 .fb_copyarea
= cfb_copyarea
,
307 .fb_imageblit
= cfb_imageblit
,
310 static void __iomem
*offb_map_reg(struct device_node
*np
, int index
,
311 unsigned long offset
, unsigned long size
)
317 addrp
= of_get_pci_address(np
, index
, &asize
, &flags
);
319 addrp
= of_get_address(np
, index
, &asize
, &flags
);
322 if ((flags
& (IORESOURCE_IO
| IORESOURCE_MEM
)) == 0)
324 if ((offset
+ size
) > asize
)
326 taddr
= of_translate_address(np
, addrp
);
327 if (taddr
== OF_BAD_ADDR
)
329 return ioremap(taddr
+ offset
, size
);
332 static void offb_init_palette_hacks(struct fb_info
*info
, struct device_node
*dp
,
333 const char *name
, unsigned long address
)
335 struct offb_par
*par
= (struct offb_par
*) info
->par
;
337 if (dp
&& !strncmp(name
, "ATY,Rage128", 11)) {
338 par
->cmap_adr
= offb_map_reg(dp
, 2, 0, 0x1fff);
340 par
->cmap_type
= cmap_r128
;
341 } else if (dp
&& (!strncmp(name
, "ATY,RageM3pA", 12)
342 || !strncmp(name
, "ATY,RageM3p12A", 14))) {
343 par
->cmap_adr
= offb_map_reg(dp
, 2, 0, 0x1fff);
345 par
->cmap_type
= cmap_M3A
;
346 } else if (dp
&& !strncmp(name
, "ATY,RageM3pB", 12)) {
347 par
->cmap_adr
= offb_map_reg(dp
, 2, 0, 0x1fff);
349 par
->cmap_type
= cmap_M3B
;
350 } else if (dp
&& !strncmp(name
, "ATY,Rage6", 9)) {
351 par
->cmap_adr
= offb_map_reg(dp
, 1, 0, 0x1fff);
353 par
->cmap_type
= cmap_radeon
;
354 } else if (!strncmp(name
, "ATY,", 4)) {
355 unsigned long base
= address
& 0xff000000UL
;
357 ioremap(base
+ 0x7ff000, 0x1000) + 0xcc0;
358 par
->cmap_data
= par
->cmap_adr
+ 1;
359 par
->cmap_type
= cmap_simple
;
360 } else if (dp
&& (of_device_is_compatible(dp
, "pci1014,b7") ||
361 of_device_is_compatible(dp
, "pci1014,21c"))) {
362 par
->cmap_adr
= offb_map_reg(dp
, 0, 0x6000, 0x1000);
364 par
->cmap_type
= cmap_gxt2000
;
365 } else if (dp
&& !strncmp(name
, "vga,Display-", 12)) {
366 /* Look for AVIVO initialized by SLOF */
367 struct device_node
*pciparent
= of_get_parent(dp
);
368 const u32
*vid
, *did
;
369 vid
= of_get_property(pciparent
, "vendor-id", NULL
);
370 did
= of_get_property(pciparent
, "device-id", NULL
);
371 /* This will match most R5xx */
372 if (vid
&& did
&& *vid
== 0x1002 &&
373 ((*did
>= 0x7100 && *did
< 0x7800) ||
375 par
->cmap_adr
= offb_map_reg(pciparent
, 2, 0, 0x10000);
377 par
->cmap_type
= cmap_avivo
;
379 of_node_put(pciparent
);
380 } else if (dp
&& of_device_is_compatible(dp
, "qemu,std-vga")) {
382 const __be32 io_of_addr
[3] = { 0x01000000, 0x0, 0x0 };
384 const __be32 io_of_addr
[3] = { 0x00000001, 0x0, 0x0 };
386 u64 io_addr
= of_translate_address(dp
, io_of_addr
);
387 if (io_addr
!= OF_BAD_ADDR
) {
388 par
->cmap_adr
= ioremap(io_addr
+ 0x3c8, 2);
390 par
->cmap_type
= cmap_simple
;
391 par
->cmap_data
= par
->cmap_adr
+ 1;
395 info
->fix
.visual
= (par
->cmap_type
!= cmap_unknown
) ?
396 FB_VISUAL_PSEUDOCOLOR
: FB_VISUAL_STATIC_PSEUDOCOLOR
;
399 static void __init
offb_init_fb(const char *name
, const char *full_name
,
400 int width
, int height
, int depth
,
401 int pitch
, unsigned long address
,
402 int foreign_endian
, struct device_node
*dp
)
404 unsigned long res_size
= pitch
* height
;
405 struct offb_par
*par
= &default_par
;
406 unsigned long res_start
= address
;
407 struct fb_fix_screeninfo
*fix
;
408 struct fb_var_screeninfo
*var
;
409 struct fb_info
*info
;
411 if (!request_mem_region(res_start
, res_size
, "offb"))
415 "Using unsupported %dx%d %s at %lx, depth=%d, pitch=%d\n",
416 width
, height
, name
, address
, depth
, pitch
);
417 if (depth
!= 8 && depth
!= 15 && depth
!= 16 && depth
!= 32) {
418 printk(KERN_ERR
"%s: can't use depth = %d\n", full_name
,
420 release_mem_region(res_start
, res_size
);
424 info
= framebuffer_alloc(sizeof(u32
) * 16, NULL
);
427 release_mem_region(res_start
, res_size
);
435 strcpy(fix
->id
, "OFfb ");
436 strncat(fix
->id
, name
, sizeof(fix
->id
) - sizeof("OFfb "));
437 fix
->id
[sizeof(fix
->id
) - 1] = '\0';
439 var
->xres
= var
->xres_virtual
= width
;
440 var
->yres
= var
->yres_virtual
= height
;
441 fix
->line_length
= pitch
;
443 fix
->smem_start
= address
;
444 fix
->smem_len
= pitch
* height
;
445 fix
->type
= FB_TYPE_PACKED_PIXELS
;
448 par
->cmap_type
= cmap_unknown
;
450 offb_init_palette_hacks(info
, dp
, name
, address
);
452 fix
->visual
= FB_VISUAL_TRUECOLOR
;
454 var
->xoffset
= var
->yoffset
= 0;
457 var
->bits_per_pixel
= 8;
460 var
->green
.offset
= 0;
461 var
->green
.length
= 8;
462 var
->blue
.offset
= 0;
463 var
->blue
.length
= 8;
464 var
->transp
.offset
= 0;
465 var
->transp
.length
= 0;
467 case 15: /* RGB 555 */
468 var
->bits_per_pixel
= 16;
469 var
->red
.offset
= 10;
471 var
->green
.offset
= 5;
472 var
->green
.length
= 5;
473 var
->blue
.offset
= 0;
474 var
->blue
.length
= 5;
475 var
->transp
.offset
= 0;
476 var
->transp
.length
= 0;
478 case 16: /* RGB 565 */
479 var
->bits_per_pixel
= 16;
480 var
->red
.offset
= 11;
482 var
->green
.offset
= 5;
483 var
->green
.length
= 6;
484 var
->blue
.offset
= 0;
485 var
->blue
.length
= 5;
486 var
->transp
.offset
= 0;
487 var
->transp
.length
= 0;
489 case 32: /* RGB 888 */
490 var
->bits_per_pixel
= 32;
491 var
->red
.offset
= 16;
493 var
->green
.offset
= 8;
494 var
->green
.length
= 8;
495 var
->blue
.offset
= 0;
496 var
->blue
.length
= 8;
497 var
->transp
.offset
= 24;
498 var
->transp
.length
= 8;
501 var
->red
.msb_right
= var
->green
.msb_right
= var
->blue
.msb_right
=
502 var
->transp
.msb_right
= 0;
506 var
->height
= var
->width
= -1;
507 var
->pixclock
= 10000;
508 var
->left_margin
= var
->right_margin
= 16;
509 var
->upper_margin
= var
->lower_margin
= 16;
510 var
->hsync_len
= var
->vsync_len
= 8;
512 var
->vmode
= FB_VMODE_NONINTERLACED
;
514 /* set offb aperture size for generic probing */
515 info
->apertures
= alloc_apertures(1);
516 if (!info
->apertures
)
518 info
->apertures
->ranges
[0].base
= address
;
519 info
->apertures
->ranges
[0].size
= fix
->smem_len
;
521 info
->fbops
= &offb_ops
;
522 info
->screen_base
= ioremap(address
, fix
->smem_len
);
523 info
->pseudo_palette
= (void *) (info
+ 1);
524 info
->flags
= FBINFO_DEFAULT
| FBINFO_MISC_FIRMWARE
| foreign_endian
;
526 fb_alloc_cmap(&info
->cmap
, 256, 0);
528 if (register_framebuffer(info
) < 0)
531 fb_info(info
, "Open Firmware frame buffer device on %s\n", full_name
);
535 iounmap(info
->screen_base
);
537 iounmap(par
->cmap_adr
);
538 par
->cmap_adr
= NULL
;
539 framebuffer_release(info
);
540 release_mem_region(res_start
, res_size
);
544 static void __init
offb_init_nodriver(struct device_node
*dp
, int no_real_node
)
547 int i
, width
= 640, height
= 480, depth
= 8, pitch
= 640;
548 unsigned int flags
, rsize
, addr_prop
= 0;
549 unsigned long max_size
= 0;
550 u64 rstart
, address
= OF_BAD_ADDR
;
551 const __be32
*pp
, *addrp
, *up
;
553 int foreign_endian
= 0;
556 if (of_get_property(dp
, "little-endian", NULL
))
557 foreign_endian
= FBINFO_FOREIGN_ENDIAN
;
559 if (of_get_property(dp
, "big-endian", NULL
))
560 foreign_endian
= FBINFO_FOREIGN_ENDIAN
;
563 pp
= of_get_property(dp
, "linux,bootx-depth", &len
);
565 pp
= of_get_property(dp
, "depth", &len
);
566 if (pp
&& len
== sizeof(u32
))
567 depth
= be32_to_cpup(pp
);
569 pp
= of_get_property(dp
, "linux,bootx-width", &len
);
571 pp
= of_get_property(dp
, "width", &len
);
572 if (pp
&& len
== sizeof(u32
))
573 width
= be32_to_cpup(pp
);
575 pp
= of_get_property(dp
, "linux,bootx-height", &len
);
577 pp
= of_get_property(dp
, "height", &len
);
578 if (pp
&& len
== sizeof(u32
))
579 height
= be32_to_cpup(pp
);
581 pp
= of_get_property(dp
, "linux,bootx-linebytes", &len
);
583 pp
= of_get_property(dp
, "linebytes", &len
);
584 if (pp
&& len
== sizeof(u32
) && (*pp
!= 0xffffffffu
))
585 pitch
= be32_to_cpup(pp
);
587 pitch
= width
* ((depth
+ 7) / 8);
589 rsize
= (unsigned long)pitch
* (unsigned long)height
;
591 /* Ok, now we try to figure out the address of the framebuffer.
593 * Unfortunately, Open Firmware doesn't provide a standard way to do
594 * so. All we can do is a dodgy heuristic that happens to work in
595 * practice. On most machines, the "address" property contains what
596 * we need, though not on Matrox cards found in IBM machines. What I've
597 * found that appears to give good results is to go through the PCI
598 * ranges and pick one that is both big enough and if possible encloses
599 * the "address" property. If none match, we pick the biggest
601 up
= of_get_property(dp
, "linux,bootx-addr", &len
);
603 up
= of_get_property(dp
, "address", &len
);
604 if (up
&& len
== sizeof(u32
))
607 /* Hack for when BootX is passing us */
611 for (i
= 0; (addrp
= of_get_address(dp
, i
, &asize
, &flags
))
615 if (!(flags
& IORESOURCE_MEM
))
619 rstart
= of_translate_address(dp
, addrp
);
620 if (rstart
== OF_BAD_ADDR
)
622 if (addr_prop
&& (rstart
<= addr_prop
) &&
623 ((rstart
+ asize
) >= (addr_prop
+ rsize
)))
629 if (rsize
> max_size
) {
631 address
= OF_BAD_ADDR
;
634 if (address
== OF_BAD_ADDR
)
638 if (address
== OF_BAD_ADDR
&& addr_prop
)
639 address
= (u64
)addr_prop
;
640 if (address
!= OF_BAD_ADDR
) {
641 /* kludge for valkyrie */
642 if (strcmp(dp
->name
, "valkyrie") == 0)
644 offb_init_fb(no_real_node
? "bootx" : dp
->name
,
645 no_real_node
? "display" : dp
->full_name
,
646 width
, height
, depth
, pitch
, address
,
647 foreign_endian
, no_real_node
? NULL
: dp
);
651 static int __init
offb_init(void)
653 struct device_node
*dp
= NULL
, *boot_disp
= NULL
;
655 if (fb_get_options("offb", NULL
))
658 /* Check if we have a MacOS display without a node spec */
659 if (of_get_property(of_chosen
, "linux,bootx-noscreen", NULL
) != NULL
) {
660 /* The old code tried to work out which node was the MacOS
661 * display based on the address. I'm dropping that since the
662 * lack of a node spec only happens with old BootX versions
663 * (users can update) and with this code, they'll still get
664 * a display (just not the palette hacks).
666 offb_init_nodriver(of_chosen
, 1);
669 for (dp
= NULL
; (dp
= of_find_node_by_type(dp
, "display"));) {
670 if (of_get_property(dp
, "linux,opened", NULL
) &&
671 of_get_property(dp
, "linux,boot-display", NULL
)) {
673 offb_init_nodriver(dp
, 0);
676 for (dp
= NULL
; (dp
= of_find_node_by_type(dp
, "display"));) {
677 if (of_get_property(dp
, "linux,opened", NULL
) &&
679 offb_init_nodriver(dp
, 0);
686 module_init(offb_init
);
687 MODULE_LICENSE("GPL");