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/aperture.h>
16 #include <linux/module.h>
17 #include <linux/kernel.h>
18 #include <linux/errno.h>
19 #include <linux/string.h>
21 #include <linux/vmalloc.h>
22 #include <linux/delay.h>
24 #include <linux/of_address.h>
25 #include <linux/interrupt.h>
27 #include <linux/init.h>
28 #include <linux/ioport.h>
29 #include <linux/pci.h>
30 #include <linux/platform_device.h>
34 #include <asm/bootx.h>
39 /* Supported palette hacks */
42 cmap_simple
, /* ATI Mach64 */
43 cmap_r128
, /* ATI Rage128 */
44 cmap_M3A
, /* ATI Rage Mobility M3 Head A */
45 cmap_M3B
, /* ATI Rage Mobility M3 Head B */
46 cmap_radeon
, /* ATI Radeon */
47 cmap_gxt2000
, /* IBM GXT2000 */
48 cmap_avivo
, /* ATI R5xx */
49 cmap_qemu
, /* qemu vga */
53 volatile void __iomem
*cmap_adr
;
54 volatile void __iomem
*cmap_data
;
57 u32 pseudo_palette
[16];
63 extern boot_infos_t
*boot_infos
;
66 /* Definitions used by the Avivo palette hack */
67 #define AVIVO_DC_LUT_RW_SELECT 0x6480
68 #define AVIVO_DC_LUT_RW_MODE 0x6484
69 #define AVIVO_DC_LUT_RW_INDEX 0x6488
70 #define AVIVO_DC_LUT_SEQ_COLOR 0x648c
71 #define AVIVO_DC_LUT_PWL_DATA 0x6490
72 #define AVIVO_DC_LUT_30_COLOR 0x6494
73 #define AVIVO_DC_LUT_READ_PIPE_SELECT 0x6498
74 #define AVIVO_DC_LUT_WRITE_EN_MASK 0x649c
75 #define AVIVO_DC_LUT_AUTOFILL 0x64a0
77 #define AVIVO_DC_LUTA_CONTROL 0x64c0
78 #define AVIVO_DC_LUTA_BLACK_OFFSET_BLUE 0x64c4
79 #define AVIVO_DC_LUTA_BLACK_OFFSET_GREEN 0x64c8
80 #define AVIVO_DC_LUTA_BLACK_OFFSET_RED 0x64cc
81 #define AVIVO_DC_LUTA_WHITE_OFFSET_BLUE 0x64d0
82 #define AVIVO_DC_LUTA_WHITE_OFFSET_GREEN 0x64d4
83 #define AVIVO_DC_LUTA_WHITE_OFFSET_RED 0x64d8
85 #define AVIVO_DC_LUTB_CONTROL 0x6cc0
86 #define AVIVO_DC_LUTB_BLACK_OFFSET_BLUE 0x6cc4
87 #define AVIVO_DC_LUTB_BLACK_OFFSET_GREEN 0x6cc8
88 #define AVIVO_DC_LUTB_BLACK_OFFSET_RED 0x6ccc
89 #define AVIVO_DC_LUTB_WHITE_OFFSET_BLUE 0x6cd0
90 #define AVIVO_DC_LUTB_WHITE_OFFSET_GREEN 0x6cd4
91 #define AVIVO_DC_LUTB_WHITE_OFFSET_RED 0x6cd8
94 * Set a single color register. The values supplied are already
95 * rounded down to the hardware's capabilities (according to the
96 * entries in the var structure). Return != 0 for invalid regno.
99 static int offb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
100 u_int transp
, struct fb_info
*info
)
102 struct offb_par
*par
= (struct offb_par
*) info
->par
;
104 if (info
->fix
.visual
== FB_VISUAL_TRUECOLOR
) {
105 u32
*pal
= info
->pseudo_palette
;
106 u32 cr
= red
>> (16 - info
->var
.red
.length
);
107 u32 cg
= green
>> (16 - info
->var
.green
.length
);
108 u32 cb
= blue
>> (16 - info
->var
.blue
.length
);
114 value
= (cr
<< info
->var
.red
.offset
) |
115 (cg
<< info
->var
.green
.offset
) |
116 (cb
<< info
->var
.blue
.offset
);
117 if (info
->var
.transp
.length
> 0) {
118 u32 mask
= (1 << info
->var
.transp
.length
) - 1;
119 mask
<<= info
->var
.transp
.offset
;
136 switch (par
->cmap_type
) {
138 writeb(regno
, par
->cmap_adr
);
139 writeb(red
, par
->cmap_data
);
140 writeb(green
, par
->cmap_data
);
141 writeb(blue
, par
->cmap_data
);
144 /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */
145 out_le32(par
->cmap_adr
+ 0x58,
146 in_le32(par
->cmap_adr
+ 0x58) & ~0x20);
149 /* Set palette index & data */
150 out_8(par
->cmap_adr
+ 0xb0, regno
);
151 out_le32(par
->cmap_adr
+ 0xb4,
152 (red
<< 16 | green
<< 8 | blue
));
155 /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */
156 out_le32(par
->cmap_adr
+ 0x58,
157 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, (red
<< 16 | green
<< 8 | blue
));
163 /* Set palette index & data (could be smarter) */
164 out_8(par
->cmap_adr
+ 0xb0, regno
);
165 out_le32(par
->cmap_adr
+ 0xb4, (red
<< 16 | green
<< 8 | blue
));
168 out_le32(((unsigned __iomem
*) par
->cmap_adr
) + regno
,
169 (red
<< 16 | green
<< 8 | blue
));
172 /* Write to both LUTs for now */
173 writel(1, par
->cmap_adr
+ AVIVO_DC_LUT_RW_SELECT
);
174 writeb(regno
, par
->cmap_adr
+ AVIVO_DC_LUT_RW_INDEX
);
175 writel(((red
) << 22) | ((green
) << 12) | ((blue
) << 2),
176 par
->cmap_adr
+ AVIVO_DC_LUT_30_COLOR
);
177 writel(0, par
->cmap_adr
+ AVIVO_DC_LUT_RW_SELECT
);
178 writeb(regno
, par
->cmap_adr
+ AVIVO_DC_LUT_RW_INDEX
);
179 writel(((red
) << 22) | ((green
) << 12) | ((blue
) << 2),
180 par
->cmap_adr
+ AVIVO_DC_LUT_30_COLOR
);
191 static int offb_blank(int blank
, struct fb_info
*info
)
193 struct offb_par
*par
= (struct offb_par
*) info
->par
;
203 par
->blanked
= blank
;
206 for (i
= 0; i
< 256; i
++) {
207 switch (par
->cmap_type
) {
209 writeb(i
, par
->cmap_adr
);
210 for (j
= 0; j
< 3; j
++)
211 writeb(0, par
->cmap_data
);
214 /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */
215 out_le32(par
->cmap_adr
+ 0x58,
216 in_le32(par
->cmap_adr
+ 0x58) & ~0x20);
219 /* Set palette index & data */
220 out_8(par
->cmap_adr
+ 0xb0, i
);
221 out_le32(par
->cmap_adr
+ 0xb4, 0);
224 /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */
225 out_le32(par
->cmap_adr
+ 0x58,
226 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 out_8(par
->cmap_adr
+ 0xb0, i
);
233 out_le32(par
->cmap_adr
+ 0xb4, 0);
236 out_le32(((unsigned __iomem
*) par
->cmap_adr
) + i
,
240 writel(1, par
->cmap_adr
+ AVIVO_DC_LUT_RW_SELECT
);
241 writeb(i
, par
->cmap_adr
+ AVIVO_DC_LUT_RW_INDEX
);
242 writel(0, par
->cmap_adr
+ AVIVO_DC_LUT_30_COLOR
);
243 writel(0, par
->cmap_adr
+ AVIVO_DC_LUT_RW_SELECT
);
244 writeb(i
, par
->cmap_adr
+ AVIVO_DC_LUT_RW_INDEX
);
245 writel(0, par
->cmap_adr
+ AVIVO_DC_LUT_30_COLOR
);
249 fb_set_cmap(&info
->cmap
, info
);
253 static int offb_set_par(struct fb_info
*info
)
255 struct offb_par
*par
= (struct offb_par
*) info
->par
;
257 /* On avivo, initialize palette control */
258 if (par
->cmap_type
== cmap_avivo
) {
259 writel(0, par
->cmap_adr
+ AVIVO_DC_LUTA_CONTROL
);
260 writel(0, par
->cmap_adr
+ AVIVO_DC_LUTA_BLACK_OFFSET_BLUE
);
261 writel(0, par
->cmap_adr
+ AVIVO_DC_LUTA_BLACK_OFFSET_GREEN
);
262 writel(0, par
->cmap_adr
+ AVIVO_DC_LUTA_BLACK_OFFSET_RED
);
263 writel(0x0000ffff, par
->cmap_adr
+ AVIVO_DC_LUTA_WHITE_OFFSET_BLUE
);
264 writel(0x0000ffff, par
->cmap_adr
+ AVIVO_DC_LUTA_WHITE_OFFSET_GREEN
);
265 writel(0x0000ffff, par
->cmap_adr
+ AVIVO_DC_LUTA_WHITE_OFFSET_RED
);
266 writel(0, par
->cmap_adr
+ AVIVO_DC_LUTB_CONTROL
);
267 writel(0, par
->cmap_adr
+ AVIVO_DC_LUTB_BLACK_OFFSET_BLUE
);
268 writel(0, par
->cmap_adr
+ AVIVO_DC_LUTB_BLACK_OFFSET_GREEN
);
269 writel(0, par
->cmap_adr
+ AVIVO_DC_LUTB_BLACK_OFFSET_RED
);
270 writel(0x0000ffff, par
->cmap_adr
+ AVIVO_DC_LUTB_WHITE_OFFSET_BLUE
);
271 writel(0x0000ffff, par
->cmap_adr
+ AVIVO_DC_LUTB_WHITE_OFFSET_GREEN
);
272 writel(0x0000ffff, par
->cmap_adr
+ AVIVO_DC_LUTB_WHITE_OFFSET_RED
);
273 writel(1, par
->cmap_adr
+ AVIVO_DC_LUT_RW_SELECT
);
274 writel(0, par
->cmap_adr
+ AVIVO_DC_LUT_RW_MODE
);
275 writel(0x0000003f, par
->cmap_adr
+ AVIVO_DC_LUT_WRITE_EN_MASK
);
276 writel(0, par
->cmap_adr
+ AVIVO_DC_LUT_RW_SELECT
);
277 writel(0, par
->cmap_adr
+ AVIVO_DC_LUT_RW_MODE
);
278 writel(0x0000003f, par
->cmap_adr
+ AVIVO_DC_LUT_WRITE_EN_MASK
);
283 static void offb_destroy(struct fb_info
*info
)
285 struct offb_par
*par
= info
->par
;
287 if (info
->screen_base
)
288 iounmap(info
->screen_base
);
289 release_mem_region(par
->base
, par
->size
);
290 fb_dealloc_cmap(&info
->cmap
);
291 framebuffer_release(info
);
294 static const struct fb_ops offb_ops
= {
295 .owner
= THIS_MODULE
,
296 FB_DEFAULT_IOMEM_OPS
,
297 .fb_destroy
= offb_destroy
,
298 .fb_setcolreg
= offb_setcolreg
,
299 .fb_set_par
= offb_set_par
,
300 .fb_blank
= offb_blank
,
303 static void __iomem
*offb_map_reg(struct device_node
*np
, int index
,
304 unsigned long offset
, unsigned long size
)
310 addrp
= of_get_pci_address(np
, index
, &asize
, &flags
);
312 addrp
= of_get_address(np
, index
, &asize
, &flags
);
315 if ((flags
& (IORESOURCE_IO
| IORESOURCE_MEM
)) == 0)
317 if ((offset
+ size
) > asize
)
319 taddr
= of_translate_address(np
, addrp
);
320 if (taddr
== OF_BAD_ADDR
)
322 return ioremap(taddr
+ offset
, size
);
325 static void offb_init_palette_hacks(struct fb_info
*info
, struct device_node
*dp
,
326 unsigned long address
)
328 struct offb_par
*par
= (struct offb_par
*) info
->par
;
330 if (of_node_name_prefix(dp
, "ATY,Rage128")) {
331 par
->cmap_adr
= offb_map_reg(dp
, 2, 0, 0x1fff);
333 par
->cmap_type
= cmap_r128
;
334 } else if (of_node_name_prefix(dp
, "ATY,RageM3pA") ||
335 of_node_name_prefix(dp
, "ATY,RageM3p12A")) {
336 par
->cmap_adr
= offb_map_reg(dp
, 2, 0, 0x1fff);
338 par
->cmap_type
= cmap_M3A
;
339 } else if (of_node_name_prefix(dp
, "ATY,RageM3pB")) {
340 par
->cmap_adr
= offb_map_reg(dp
, 2, 0, 0x1fff);
342 par
->cmap_type
= cmap_M3B
;
343 } else if (of_node_name_prefix(dp
, "ATY,Rage6")) {
344 par
->cmap_adr
= offb_map_reg(dp
, 1, 0, 0x1fff);
346 par
->cmap_type
= cmap_radeon
;
347 } else if (of_node_name_prefix(dp
, "ATY,")) {
348 unsigned long base
= address
& 0xff000000UL
;
350 ioremap(base
+ 0x7ff000, 0x1000) + 0xcc0;
351 par
->cmap_data
= par
->cmap_adr
+ 1;
352 par
->cmap_type
= cmap_simple
;
353 } else if (dp
&& (of_device_is_compatible(dp
, "pci1014,b7") ||
354 of_device_is_compatible(dp
, "pci1014,21c"))) {
355 par
->cmap_adr
= offb_map_reg(dp
, 0, 0x6000, 0x1000);
357 par
->cmap_type
= cmap_gxt2000
;
358 } else if (of_node_name_prefix(dp
, "vga,Display-")) {
359 /* Look for AVIVO initialized by SLOF */
360 struct device_node
*pciparent
__free(device_node
) = of_get_parent(dp
);
361 const u32
*vid
, *did
;
362 vid
= of_get_property(pciparent
, "vendor-id", NULL
);
363 did
= of_get_property(pciparent
, "device-id", NULL
);
364 /* This will match most R5xx */
365 if (vid
&& did
&& *vid
== 0x1002 &&
366 ((*did
>= 0x7100 && *did
< 0x7800) ||
368 par
->cmap_adr
= offb_map_reg(pciparent
, 2, 0, 0x10000);
370 par
->cmap_type
= cmap_avivo
;
372 } else if (dp
&& of_device_is_compatible(dp
, "qemu,std-vga")) {
374 const __be32 io_of_addr
[3] = { 0x01000000, 0x0, 0x0 };
376 const __be32 io_of_addr
[3] = { 0x00000001, 0x0, 0x0 };
378 u64 io_addr
= of_translate_address(dp
, io_of_addr
);
379 if (io_addr
!= OF_BAD_ADDR
) {
380 par
->cmap_adr
= ioremap(io_addr
+ 0x3c8, 2);
382 par
->cmap_type
= cmap_simple
;
383 par
->cmap_data
= par
->cmap_adr
+ 1;
387 info
->fix
.visual
= (par
->cmap_type
!= cmap_unknown
) ?
388 FB_VISUAL_PSEUDOCOLOR
: FB_VISUAL_STATIC_PSEUDOCOLOR
;
391 static void offb_init_fb(struct platform_device
*parent
, const char *name
,
392 int width
, int height
, int depth
,
393 int pitch
, unsigned long address
,
394 int foreign_endian
, struct device_node
*dp
)
396 unsigned long res_size
= pitch
* height
;
397 unsigned long res_start
= address
;
398 struct fb_fix_screeninfo
*fix
;
399 struct fb_var_screeninfo
*var
;
400 struct fb_info
*info
;
401 struct offb_par
*par
;
403 if (!request_mem_region(res_start
, res_size
, "offb"))
407 "Using unsupported %dx%d %s at %lx, depth=%d, pitch=%d\n",
408 width
, height
, name
, address
, depth
, pitch
);
409 if (depth
!= 8 && depth
!= 15 && depth
!= 16 && depth
!= 32) {
410 printk(KERN_ERR
"%pOF: can't use depth = %d\n", dp
, depth
);
411 release_mem_region(res_start
, res_size
);
415 info
= framebuffer_alloc(sizeof(*par
), &parent
->dev
);
417 release_mem_region(res_start
, res_size
);
420 platform_set_drvdata(parent
, info
);
426 snprintf(fix
->id
, sizeof(fix
->id
), "OFfb %s", name
);
428 snprintf(fix
->id
, sizeof(fix
->id
), "OFfb %pOFn", dp
);
431 var
->xres
= var
->xres_virtual
= width
;
432 var
->yres
= var
->yres_virtual
= height
;
433 fix
->line_length
= pitch
;
435 fix
->smem_start
= address
;
436 fix
->smem_len
= pitch
* height
;
437 fix
->type
= FB_TYPE_PACKED_PIXELS
;
440 par
->cmap_type
= cmap_unknown
;
442 offb_init_palette_hacks(info
, dp
, address
);
444 fix
->visual
= FB_VISUAL_TRUECOLOR
;
446 var
->xoffset
= var
->yoffset
= 0;
449 var
->bits_per_pixel
= 8;
452 var
->green
.offset
= 0;
453 var
->green
.length
= 8;
454 var
->blue
.offset
= 0;
455 var
->blue
.length
= 8;
456 var
->transp
.offset
= 0;
457 var
->transp
.length
= 0;
459 case 15: /* RGB 555 */
460 var
->bits_per_pixel
= 16;
461 var
->red
.offset
= 10;
463 var
->green
.offset
= 5;
464 var
->green
.length
= 5;
465 var
->blue
.offset
= 0;
466 var
->blue
.length
= 5;
467 var
->transp
.offset
= 0;
468 var
->transp
.length
= 0;
470 case 16: /* RGB 565 */
471 var
->bits_per_pixel
= 16;
472 var
->red
.offset
= 11;
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;
481 case 32: /* RGB 888 */
482 var
->bits_per_pixel
= 32;
483 var
->red
.offset
= 16;
485 var
->green
.offset
= 8;
486 var
->green
.length
= 8;
487 var
->blue
.offset
= 0;
488 var
->blue
.length
= 8;
489 var
->transp
.offset
= 24;
490 var
->transp
.length
= 8;
493 var
->red
.msb_right
= var
->green
.msb_right
= var
->blue
.msb_right
=
494 var
->transp
.msb_right
= 0;
498 var
->height
= var
->width
= -1;
499 var
->pixclock
= 10000;
500 var
->left_margin
= var
->right_margin
= 16;
501 var
->upper_margin
= var
->lower_margin
= 16;
502 var
->hsync_len
= var
->vsync_len
= 8;
504 var
->vmode
= FB_VMODE_NONINTERLACED
;
507 par
->size
= fix
->smem_len
;
509 info
->fbops
= &offb_ops
;
510 info
->screen_base
= ioremap(address
, fix
->smem_len
);
511 info
->pseudo_palette
= par
->pseudo_palette
;
512 info
->flags
= foreign_endian
;
514 fb_alloc_cmap(&info
->cmap
, 256, 0);
516 if (devm_aperture_acquire_for_platform_device(parent
, par
->base
, par
->size
) < 0)
518 if (register_framebuffer(info
) < 0)
521 fb_info(info
, "Open Firmware frame buffer device on %pOF\n", dp
);
525 fb_dealloc_cmap(&info
->cmap
);
526 iounmap(info
->screen_base
);
527 iounmap(par
->cmap_adr
);
528 par
->cmap_adr
= NULL
;
529 framebuffer_release(info
);
530 release_mem_region(res_start
, res_size
);
534 static void offb_init_nodriver(struct platform_device
*parent
, struct device_node
*dp
,
538 int i
, width
= 640, height
= 480, depth
= 8, pitch
= 640;
539 unsigned int flags
, rsize
, addr_prop
= 0;
540 unsigned long max_size
= 0;
541 u64 rstart
, address
= OF_BAD_ADDR
;
542 const __be32
*pp
, *addrp
, *up
;
544 int foreign_endian
= 0;
547 if (of_property_read_bool(dp
, "little-endian"))
548 foreign_endian
= FBINFO_FOREIGN_ENDIAN
;
550 if (of_property_read_bool(dp
, "big-endian"))
551 foreign_endian
= FBINFO_FOREIGN_ENDIAN
;
554 pp
= of_get_property(dp
, "linux,bootx-depth", &len
);
556 pp
= of_get_property(dp
, "depth", &len
);
557 if (pp
&& len
== sizeof(u32
))
558 depth
= be32_to_cpup(pp
);
560 pp
= of_get_property(dp
, "linux,bootx-width", &len
);
562 pp
= of_get_property(dp
, "width", &len
);
563 if (pp
&& len
== sizeof(u32
))
564 width
= be32_to_cpup(pp
);
566 pp
= of_get_property(dp
, "linux,bootx-height", &len
);
568 pp
= of_get_property(dp
, "height", &len
);
569 if (pp
&& len
== sizeof(u32
))
570 height
= be32_to_cpup(pp
);
572 pp
= of_get_property(dp
, "linux,bootx-linebytes", &len
);
574 pp
= of_get_property(dp
, "linebytes", &len
);
575 if (pp
&& len
== sizeof(u32
) && (*pp
!= 0xffffffffu
))
576 pitch
= be32_to_cpup(pp
);
578 pitch
= width
* ((depth
+ 7) / 8);
580 rsize
= (unsigned long)pitch
* (unsigned long)height
;
582 /* Ok, now we try to figure out the address of the framebuffer.
584 * Unfortunately, Open Firmware doesn't provide a standard way to do
585 * so. All we can do is a dodgy heuristic that happens to work in
586 * practice. On most machines, the "address" property contains what
587 * we need, though not on Matrox cards found in IBM machines. What I've
588 * found that appears to give good results is to go through the PCI
589 * ranges and pick one that is both big enough and if possible encloses
590 * the "address" property. If none match, we pick the biggest
592 up
= of_get_property(dp
, "linux,bootx-addr", &len
);
594 up
= of_get_property(dp
, "address", &len
);
595 if (up
&& len
== sizeof(u32
))
598 /* Hack for when BootX is passing us */
602 for (i
= 0; (addrp
= of_get_address(dp
, i
, &asize
, &flags
))
606 if (!(flags
& IORESOURCE_MEM
))
610 rstart
= of_translate_address(dp
, addrp
);
611 if (rstart
== OF_BAD_ADDR
)
613 if (addr_prop
&& (rstart
<= addr_prop
) &&
614 ((rstart
+ asize
) >= (addr_prop
+ rsize
)))
620 if (rsize
> max_size
) {
622 address
= OF_BAD_ADDR
;
625 if (address
== OF_BAD_ADDR
)
629 if (address
== OF_BAD_ADDR
&& addr_prop
)
630 address
= (u64
)addr_prop
;
631 if (address
!= OF_BAD_ADDR
) {
633 const __be32
*vidp
, *didp
;
635 struct pci_dev
*pdev
;
637 vidp
= of_get_property(dp
, "vendor-id", NULL
);
638 didp
= of_get_property(dp
, "device-id", NULL
);
640 vid
= be32_to_cpup(vidp
);
641 did
= be32_to_cpup(didp
);
642 pdev
= pci_get_device(vid
, did
, NULL
);
643 if (!pdev
|| pci_enable_device(pdev
))
647 /* kludge for valkyrie */
648 if (of_node_name_eq(dp
, "valkyrie"))
650 offb_init_fb(parent
, no_real_node
? "bootx" : NULL
,
651 width
, height
, depth
, pitch
, address
,
652 foreign_endian
, no_real_node
? NULL
: dp
);
656 static void offb_remove(struct platform_device
*pdev
)
658 struct fb_info
*info
= platform_get_drvdata(pdev
);
661 unregister_framebuffer(info
);
664 static int offb_probe_bootx_noscreen(struct platform_device
*pdev
)
666 offb_init_nodriver(pdev
, of_chosen
, 1);
671 static struct platform_driver offb_driver_bootx_noscreen
= {
673 .name
= "bootx-noscreen",
675 .probe
= offb_probe_bootx_noscreen
,
676 .remove
= offb_remove
,
679 static int offb_probe_display(struct platform_device
*pdev
)
681 offb_init_nodriver(pdev
, pdev
->dev
.of_node
, 0);
686 static const struct of_device_id offb_of_match_display
[] = {
687 { .compatible
= "display", },
690 MODULE_DEVICE_TABLE(of
, offb_of_match_display
);
692 static struct platform_driver offb_driver_display
= {
694 .name
= "of-display",
695 .of_match_table
= offb_of_match_display
,
697 .probe
= offb_probe_display
,
698 .remove
= offb_remove
,
701 static int __init
offb_init(void)
703 if (fb_get_options("offb", NULL
))
706 platform_driver_register(&offb_driver_bootx_noscreen
);
707 platform_driver_register(&offb_driver_display
);
711 module_init(offb_init
);
713 static void __exit
offb_exit(void)
715 platform_driver_unregister(&offb_driver_display
);
716 platform_driver_unregister(&offb_driver_bootx_noscreen
);
718 module_exit(offb_exit
);
720 MODULE_DESCRIPTION("Open Firmware frame buffer device driver");
721 MODULE_LICENSE("GPL");