2 * platinumfb.c -- frame buffer device for the PowerMac 'platinum' display
4 * Copyright (C) 1998 Franz Sirl
6 * Frame buffer structure from:
7 * drivers/video/controlfb.c -- frame buffer device for
8 * Apple 'control' display chip.
9 * Copyright (C) 1998 Dan Jacobowitz
11 * Hardware information from:
12 * platinum.c: Console support for PowerMac "platinum" display adaptor.
13 * Copyright (C) 1996 Paul Mackerras and Mark Abene
15 * This file is subject to the terms and conditions of the GNU General Public
16 * License. See the file COPYING in the main directory of this archive for
20 #include <linux/config.h>
21 #include <linux/module.h>
22 #include <linux/kernel.h>
23 #include <linux/errno.h>
24 #include <linux/string.h>
26 #include <linux/tty.h>
27 #include <linux/malloc.h>
28 #include <linux/vmalloc.h>
29 #include <linux/delay.h>
30 #include <linux/interrupt.h>
32 #include <linux/selection.h>
33 #include <linux/init.h>
34 #include <linux/pci.h>
35 #include <linux/nvram.h>
36 #ifdef CONFIG_FB_COMPAT_XPMAC
37 #include <asm/vc_ioctl.h>
41 #include <asm/pgtable.h>
43 #include <video/fbcon.h>
44 #include <video/fbcon-cfb8.h>
45 #include <video/fbcon-cfb16.h>
46 #include <video/fbcon-cfb32.h>
47 #include <video/macmodes.h>
49 #include "platinumfb.h"
51 static char fontname
[40] __initdata
= { 0 };
53 static int currcon
= 0;
55 static int default_vmode
= VMODE_NVRAM
;
56 static int default_cmode
= CMODE_NVRAM
;
58 struct fb_par_platinum
{
65 struct fb_info_platinum
{
66 struct fb_info fb_info
;
68 struct fb_par_platinum default_par
;
69 struct fb_par_platinum current_par
;
72 __u8 red
, green
, blue
;
75 volatile struct cmap_regs
*cmap_regs
;
76 unsigned long cmap_regs_phys
;
78 volatile struct platinum_regs
*platinum_regs
;
79 unsigned long platinum_regs_phys
;
82 volatile __u8
*base_frame_buffer
;
83 unsigned long frame_buffer_phys
;
85 unsigned long total_vram
;
90 #ifdef FBCON_HAS_CFB16
93 #ifdef FBCON_HAS_CFB32
100 * Frame buffer device API
103 static int platinum_get_fix(struct fb_fix_screeninfo
*fix
, int con
,
105 static int platinum_get_var(struct fb_var_screeninfo
*var
, int con
,
107 static int platinum_set_var(struct fb_var_screeninfo
*var
, int con
,
109 static int platinum_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
110 struct fb_info
*info
);
111 static int platinum_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
112 struct fb_info
*info
);
116 * Interface to the low level console driver
119 static int platinum_switch(int con
, struct fb_info
*fb
);
120 static int platinum_updatevar(int con
, struct fb_info
*fb
);
121 static void platinum_blank(int blank
, struct fb_info
*fb
);
128 static void platinum_of_init(struct device_node
*dp
);
129 static inline int platinum_vram_reqd(int video_mode
, int color_mode
);
130 static int read_platinum_sense(struct fb_info_platinum
*info
);
131 static void set_platinum_clock(struct fb_info_platinum
*info
);
132 static void platinum_set_par(const struct fb_par_platinum
*par
, struct fb_info_platinum
*info
);
133 static int platinum_par_to_var(struct fb_var_screeninfo
*var
,
134 const struct fb_par_platinum
*par
,
135 const struct fb_info_platinum
*info
);
136 static int platinum_var_to_par(const struct fb_var_screeninfo
*var
,
137 struct fb_par_platinum
*par
,
138 const struct fb_info_platinum
*info
);
139 static int platinum_encode_fix(struct fb_fix_screeninfo
*fix
,
140 const struct fb_par_platinum
*par
,
141 const struct fb_info_platinum
*info
);
142 static void platinum_set_dispsw(struct display
*disp
,
143 struct fb_info_platinum
*info
, int cmode
,
145 static int platinum_getcolreg(u_int regno
, u_int
*red
, u_int
*green
, u_int
*blue
,
146 u_int
*transp
, struct fb_info
*fb
);
147 static int platinum_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
148 u_int transp
, struct fb_info
*fb
);
149 static void do_install_cmap(int con
, struct fb_info
*info
);
153 * Interface used by the world
156 int platinum_init(void);
157 int platinum_setup(char*);
159 static struct fb_ops platinumfb_ops
= {
161 fb_get_fix
: platinum_get_fix
,
162 fb_get_var
: platinum_get_var
,
163 fb_set_var
: platinum_set_var
,
164 fb_get_cmap
: platinum_get_cmap
,
165 fb_set_cmap
: platinum_set_cmap
,
168 static int platinum_get_fix(struct fb_fix_screeninfo
*fix
, int con
,
171 const struct fb_info_platinum
*info
= (struct fb_info_platinum
*)fb
;
172 struct fb_par_platinum par
;
175 par
= info
->default_par
;
177 platinum_var_to_par(&fb_display
[con
].var
, &par
, info
);
179 platinum_encode_fix(fix
, &par
, info
);
183 static int platinum_get_var(struct fb_var_screeninfo
*var
, int con
,
186 const struct fb_info_platinum
*info
= (struct fb_info_platinum
*)fb
;
189 platinum_par_to_var(var
, &info
->default_par
, info
);
191 *var
= fb_display
[con
].var
;
196 static void platinum_set_dispsw(struct display
*disp
,
197 struct fb_info_platinum
*info
, int cmode
,
201 #ifdef FBCON_HAS_CFB8
203 disp
->dispsw
= &fbcon_cfb8
;
206 #ifdef FBCON_HAS_CFB16
208 disp
->dispsw
= &fbcon_cfb16
;
209 disp
->dispsw_data
= info
->fbcon_cmap
.cfb16
;
212 #ifdef FBCON_HAS_CFB32
214 disp
->dispsw
= &fbcon_cfb32
;
215 disp
->dispsw_data
= info
->fbcon_cmap
.cfb32
;
219 disp
->dispsw
= &fbcon_dummy
;
224 static int platinum_set_var(struct fb_var_screeninfo
*var
, int con
,
227 struct fb_info_platinum
*info
= (struct fb_info_platinum
*) fb
;
228 struct fb_par_platinum par
;
229 struct display
*display
;
230 int oldxres
, oldyres
, oldvxres
, oldvyres
, oldbpp
, err
;
231 int activate
= var
->activate
;
232 struct platinum_regvals
*init
;
234 display
= (con
>= 0) ? &fb_display
[con
] : fb
->disp
;
236 if((err
= platinum_var_to_par(var
, &par
, info
))) {
237 printk(KERN_ERR
"platinum_set_var: error calling platinum_var_to_par: %d.\n", err
);
241 platinum_par_to_var(var
, &par
, info
);
243 if ((activate
& FB_ACTIVATE_MASK
) != FB_ACTIVATE_NOW
) {
244 printk(KERN_INFO
"platinum_set_var: Not activating.\n");
248 init
= platinum_reg_init
[par
.vmode
-1];
250 oldxres
= display
->var
.xres
;
251 oldyres
= display
->var
.yres
;
252 oldvxres
= display
->var
.xres_virtual
;
253 oldvyres
= display
->var
.yres_virtual
;
254 oldbpp
= display
->var
.bits_per_pixel
;
257 if (oldxres
!= var
->xres
|| oldyres
!= var
->yres
||
258 oldvxres
!= var
->xres_virtual
|| oldyres
!= var
->yres_virtual
||
259 oldbpp
!= var
->bits_per_pixel
) {
260 struct fb_fix_screeninfo fix
;
262 platinum_encode_fix(&fix
, &par
, info
);
263 display
->screen_base
= (char *) info
->frame_buffer
+ init
->fb_offset
+ 0x20;
264 display
->visual
= fix
.visual
;
265 display
->type
= fix
.type
;
266 display
->type_aux
= fix
.type_aux
;
267 display
->ypanstep
= fix
.ypanstep
;
268 display
->ywrapstep
= fix
.ywrapstep
;
269 display
->line_length
= fix
.line_length
;
270 display
->can_soft_blank
= 1;
271 display
->inverse
= 0;
272 platinum_set_dispsw(display
, info
, par
.cmode
, 0);
273 display
->scrollmode
= SCROLL_YREDRAW
;
274 if (info
->fb_info
.changevar
)
275 (*info
->fb_info
.changevar
)(con
);
278 if (!info
->fb_info
.display_fg
||
279 info
->fb_info
.display_fg
->vc_num
== con
)
280 platinum_set_par(&par
, info
);
282 if (oldbpp
!= var
->bits_per_pixel
) {
283 if ((err
= fb_alloc_cmap(&display
->cmap
, 0, 0)))
285 do_install_cmap(con
, &info
->fb_info
);
291 static int platinum_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
292 struct fb_info
*info
)
294 if (!info
->display_fg
||
295 info
->display_fg
->vc_num
== con
) /* current console? */
296 return fb_get_cmap(cmap
, kspc
, platinum_getcolreg
, info
);
297 if (fb_display
[con
].cmap
.len
) /* non default colormap? */
298 fb_copy_cmap(&fb_display
[con
].cmap
, cmap
, kspc
? 0 : 2);
300 int size
= fb_display
[con
].var
.bits_per_pixel
== 16 ? 32 : 256;
301 fb_copy_cmap(fb_default_cmap(size
), cmap
, kspc
? 0 : 2);
306 static int platinum_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
307 struct fb_info
*info
)
310 struct display
*disp
;
313 disp
= &fb_display
[con
];
316 if (!disp
->cmap
.len
) { /* no colormap allocated? */
317 int size
= disp
->var
.bits_per_pixel
== 16 ? 32 : 256;
318 if ((err
= fb_alloc_cmap(&disp
->cmap
, size
, 0)))
322 if (!info
->display_fg
||
323 info
->display_fg
->vc_num
== con
) /* current console? */
324 return fb_set_cmap(cmap
, kspc
, platinum_setcolreg
, info
);
326 fb_copy_cmap(cmap
, &disp
->cmap
, kspc
? 0 : 1);
330 static int platinum_switch(int con
, struct fb_info
*fb
)
332 struct fb_info_platinum
*info
= (struct fb_info_platinum
*) fb
;
333 struct fb_par_platinum par
;
335 if (fb_display
[currcon
].cmap
.len
)
336 fb_get_cmap(&fb_display
[currcon
].cmap
, 1, platinum_getcolreg
,
340 platinum_var_to_par(&fb_display
[con
].var
, &par
, info
);
341 platinum_set_par(&par
, info
);
342 platinum_set_dispsw(&fb_display
[con
], info
, par
.cmode
, 0);
343 do_install_cmap(con
, fb
);
348 static int platinum_updatevar(int con
, struct fb_info
*fb
)
350 printk(KERN_ERR
"platinum_updatevar is doing nothing yet.\n");
354 static void platinum_blank(int blank
, struct fb_info
*fb
)
357 * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
358 * then the caller blanks by setting the CLUT (Color Look Up Table) to all
359 * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
360 * to e.g. a video mode which doesn't support it. Implements VESA suspend
361 * and powerdown modes on hardware that supports disabling hsync/vsync:
362 * blank_mode == 2: suspend vsync
363 * blank_mode == 3: suspend hsync
364 * blank_mode == 4: powerdown
366 /* [danj] I think there's something fishy about those constants... */
368 struct fb_info_platinum *info = (struct fb_info_platinum *) fb;
371 ctrl = ld_le32(&info->platinum_regs->ctrl.r) | 0x33;
374 if (blank & VESA_VSYNC_SUSPEND)
376 if (blank & VESA_HSYNC_SUSPEND)
378 out_le32(&info->platinum_regs->ctrl.r, ctrl);
380 /* TODO: Figure out how the heck to powerdown this thing! */
384 static int platinum_getcolreg(u_int regno
, u_int
*red
, u_int
*green
,
385 u_int
*blue
, u_int
*transp
, struct fb_info
*fb
)
387 struct fb_info_platinum
*info
= (struct fb_info_platinum
*) fb
;
392 *red
= (info
->palette
[regno
].red
<<8) | info
->palette
[regno
].red
;
393 *green
= (info
->palette
[regno
].green
<<8) | info
->palette
[regno
].green
;
394 *blue
= (info
->palette
[regno
].blue
<<8) | info
->palette
[regno
].blue
;
399 static int platinum_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
400 u_int transp
, struct fb_info
*fb
)
402 struct fb_info_platinum
*info
= (struct fb_info_platinum
*) fb
;
403 volatile struct cmap_regs
*cmap_regs
= info
->cmap_regs
;
412 info
->palette
[regno
].red
= red
;
413 info
->palette
[regno
].green
= green
;
414 info
->palette
[regno
].blue
= blue
;
416 out_8(&cmap_regs
->addr
, regno
); /* tell clut what addr to fill */
417 out_8(&cmap_regs
->lut
, red
); /* send one color channel at */
418 out_8(&cmap_regs
->lut
, green
); /* a time... */
419 out_8(&cmap_regs
->lut
, blue
);
422 #ifdef FBCON_HAS_CFB16
423 info
->fbcon_cmap
.cfb16
[regno
] = (regno
<< 10) | (regno
<< 5) | (regno
<< 0);
425 #ifdef FBCON_HAS_CFB32
426 info
->fbcon_cmap
.cfb32
[regno
] = (regno
<< 24) | (regno
<< 16) | (regno
<< 8) | regno
;
432 static void do_install_cmap(int con
, struct fb_info
*info
)
436 if (fb_display
[con
].cmap
.len
)
437 fb_set_cmap(&fb_display
[con
].cmap
, 1, platinum_setcolreg
,
440 int size
= fb_display
[con
].var
.bits_per_pixel
== 16 ? 32 : 256;
441 fb_set_cmap(fb_default_cmap(size
), 1, platinum_setcolreg
,
446 static inline int platinum_vram_reqd(int video_mode
, int color_mode
)
448 return vmode_attrs
[video_mode
-1].vres
*
449 (vmode_attrs
[video_mode
-1].hres
* (1<<color_mode
) + 0x20) +0x1000;
452 #define STORE_D2(a, d) { \
453 out_8(&cmap_regs->addr, (a+32)); \
454 out_8(&cmap_regs->d2, (d)); \
457 static void set_platinum_clock(struct fb_info_platinum
*info
)
459 volatile struct cmap_regs
*cmap_regs
= info
->cmap_regs
;
460 struct platinum_regvals
*init
;
462 init
= platinum_reg_init
[info
->current_par
.vmode
-1];
465 out_8(&cmap_regs
->addr
,3+32);
467 if (in_8(&cmap_regs
->d2
) == 2) {
468 STORE_D2(7, init
->clock_params
[info
->clktype
][0]);
469 STORE_D2(8, init
->clock_params
[info
->clktype
][1]);
472 STORE_D2(4, init
->clock_params
[info
->clktype
][0]);
473 STORE_D2(5, init
->clock_params
[info
->clktype
][1]);
482 /* Now how about actually saying, Make it so! */
483 /* Some things in here probably don't need to be done each time. */
484 static void platinum_set_par(const struct fb_par_platinum
*par
, struct fb_info_platinum
*info
)
486 volatile struct platinum_regs
*platinum_regs
= info
->platinum_regs
;
487 volatile struct cmap_regs
*cmap_regs
= info
->cmap_regs
;
488 struct platinum_regvals
*init
;
492 info
->current_par
= *par
;
497 init
= platinum_reg_init
[vmode
- 1];
499 /* Initialize display timing registers */
500 out_be32(&platinum_regs
->reg
[24].r
, 7); /* turn display off */
502 for (i
= 0; i
< 26; ++i
)
503 out_be32(&platinum_regs
->reg
[i
+32].r
, init
->regs
[i
]);
505 out_be32(&platinum_regs
->reg
[26+32].r
, (info
->total_vram
== 0x100000 ?
506 init
->offset
[cmode
] + 4 - cmode
:
507 init
->offset
[cmode
]));
508 out_be32(&platinum_regs
->reg
[16].r
, (unsigned) info
->frame_buffer_phys
+init
->fb_offset
+0x10);
509 out_be32(&platinum_regs
->reg
[18].r
, init
->pitch
[cmode
]);
510 out_be32(&platinum_regs
->reg
[19].r
, (info
->total_vram
== 0x100000 ?
511 init
->mode
[cmode
+1] :
513 out_be32(&platinum_regs
->reg
[20].r
, (info
->total_vram
== 0x100000 ? 0x11 : 0x1011));
514 out_be32(&platinum_regs
->reg
[21].r
, 0x100);
515 out_be32(&platinum_regs
->reg
[22].r
, 1);
516 out_be32(&platinum_regs
->reg
[23].r
, 1);
517 out_be32(&platinum_regs
->reg
[26].r
, 0xc00);
518 out_be32(&platinum_regs
->reg
[27].r
, 0x235);
519 /* out_be32(&platinum_regs->reg[27].r, 0x2aa); */
521 STORE_D2(0, (info
->total_vram
== 0x100000 ?
522 init
->dacula_ctrl
[cmode
] & 0xf :
523 init
->dacula_ctrl
[cmode
]));
527 set_platinum_clock(info
);
529 out_be32(&platinum_regs
->reg
[24].r
, 0); /* turn display on */
531 #ifdef CONFIG_FB_COMPAT_XPMAC
532 if (console_fb_info
== &info
->fb_info
) {
533 display_info
.height
= par
->yres
;
534 display_info
.width
= par
->xres
;
535 display_info
.depth
= ( (cmode
== CMODE_32
) ? 32 :
536 ((cmode
== CMODE_16
) ? 16 : 8));
537 display_info
.pitch
= vmode_attrs
[vmode
-1].hres
* (1<<cmode
) + 0x20;
538 display_info
.mode
= vmode
;
539 strncpy(display_info
.name
, "platinum",
540 sizeof(display_info
.name
));
541 display_info
.fb_address
= info
->frame_buffer_phys
+ init
->fb_offset
+ 0x20;
542 display_info
.cmap_adr_address
= info
->cmap_regs_phys
;
543 display_info
.cmap_data_address
= info
->cmap_regs_phys
+ 0x30;
544 display_info
.disp_reg_address
= info
->platinum_regs_phys
;
547 #endif /* CONFIG_FB_COMPAT_XPMAC */
551 static int __init
init_platinum(struct fb_info_platinum
*info
)
553 struct fb_var_screeninfo var
;
554 struct display
*disp
;
558 sense
= read_platinum_sense(info
);
559 printk(KERN_INFO
"Monitor sense value = 0x%x, ", sense
);
561 if (default_vmode
== VMODE_NVRAM
) {
562 default_vmode
= nvram_read_byte(NV_VMODE
);
563 if (default_vmode
<= 0 || default_vmode
> VMODE_MAX
||
564 !platinum_reg_init
[default_vmode
-1])
565 default_vmode
= VMODE_CHOOSE
;
567 if (default_vmode
== VMODE_CHOOSE
) {
568 default_vmode
= mac_map_monitor_sense(sense
);
570 if (default_vmode
<= 0 || default_vmode
> VMODE_MAX
)
571 default_vmode
= VMODE_640_480_60
;
572 if (default_cmode
== CMODE_NVRAM
)
573 default_cmode
= nvram_read_byte(NV_CMODE
);
574 if (default_cmode
< CMODE_8
|| default_cmode
> CMODE_32
)
575 default_cmode
= CMODE_8
;
577 * Reduce the pixel size if we don't have enough VRAM.
579 while(default_cmode
> CMODE_8
&& platinum_vram_reqd(default_vmode
, default_cmode
) > info
->total_vram
)
582 printk("using video mode %d and color mode %d.\n", default_vmode
, default_cmode
);
584 mac_vmode_to_var(default_vmode
, default_cmode
, &var
);
586 if (platinum_var_to_par(&var
, &info
->default_par
, info
)) {
587 printk(KERN_ERR
"platinumfb: can't set default video mode\n");
593 strcpy(info
->fb_info
.modename
, "platinum");
594 info
->fb_info
.node
= -1;
595 info
->fb_info
.fbops
= &platinumfb_ops
;
596 info
->fb_info
.disp
= disp
;
597 strcpy(info
->fb_info
.fontname
, fontname
);
598 info
->fb_info
.changevar
= NULL
;
599 info
->fb_info
.switch_con
= &platinum_switch
;
600 info
->fb_info
.updatevar
= &platinum_updatevar
;
601 info
->fb_info
.blank
= &platinum_blank
;
602 info
->fb_info
.flags
= FBINFO_FLAG_DEFAULT
;
604 for (j
= 0; j
< 16; j
++) {
606 info
->palette
[j
].red
= default_red
[k
];
607 info
->palette
[j
].green
= default_grn
[k
];
608 info
->palette
[j
].blue
= default_blu
[k
];
610 platinum_set_var(&var
, -1, &info
->fb_info
);
612 if (register_framebuffer(&info
->fb_info
) < 0)
615 printk(KERN_INFO
"fb%d: platinum frame buffer device\n",
616 GET_FB_IDX(info
->fb_info
.node
));
621 int __init
platinum_init(void)
623 struct device_node
*dp
;
625 dp
= find_devices("platinum");
627 platinum_of_init(dp
);
632 #define invalidate_cache(addr) \
633 asm volatile("eieio; dcbf 0,%1" \
634 : "=m" (*(addr)) : "r" (addr) : "memory");
636 #define invalidate_cache(addr)
639 static void __init
platinum_of_init(struct device_node
*dp
)
641 struct fb_info_platinum
*info
;
642 unsigned long addr
, size
;
643 volatile __u8
*fbuffer
;
644 int i
, bank0
, bank1
, bank2
, bank3
;
646 if(dp
->n_addrs
!= 2) {
647 printk(KERN_ERR
"expecting 2 address for platinum (got %d)", dp
->n_addrs
);
651 info
= kmalloc(sizeof(*info
), GFP_ATOMIC
);
654 memset(info
, 0, sizeof(*info
));
656 /* Map in frame buffer and registers */
657 for (i
= 0; i
< dp
->n_addrs
; ++i
) {
658 addr
= dp
->addrs
[i
].address
;
659 size
= dp
->addrs
[i
].size
;
660 /* Let's assume we can request either all or nothing */
661 if (!request_mem_region(addr
, size
, "platinumfb")) {
665 if (size
>= 0x400000) {
666 /* frame buffer - map only 4MB */
667 info
->frame_buffer_phys
= addr
;
668 info
->frame_buffer
= __ioremap(addr
, 0x400000, _PAGE_WRITETHRU
);
669 info
->base_frame_buffer
= info
->frame_buffer
;
672 info
->platinum_regs_phys
= addr
;
673 info
->platinum_regs
= ioremap(addr
, size
);
677 info
->cmap_regs_phys
= 0xf301b000; /* XXX not in prom? */
678 request_mem_region(info
->cmap_regs_phys
, 0x1000, "platinumfb cmap");
679 info
->cmap_regs
= ioremap(info
->cmap_regs_phys
, 0x1000);
681 /* Grok total video ram */
682 out_be32(&info
->platinum_regs
->reg
[16].r
, (unsigned)info
->frame_buffer_phys
);
683 out_be32(&info
->platinum_regs
->reg
[20].r
, 0x1011); /* select max vram */
684 out_be32(&info
->platinum_regs
->reg
[24].r
, 0); /* switch in vram */
686 fbuffer
= info
->base_frame_buffer
;
687 fbuffer
[0x100000] = 0x34;
688 fbuffer
[0x100008] = 0x0;
689 invalidate_cache(&fbuffer
[0x100000]);
690 fbuffer
[0x200000] = 0x56;
691 fbuffer
[0x200008] = 0x0;
692 invalidate_cache(&fbuffer
[0x200000]);
693 fbuffer
[0x300000] = 0x78;
694 fbuffer
[0x300008] = 0x0;
695 invalidate_cache(&fbuffer
[0x300000]);
696 bank0
= 1; /* builtin 1MB vram, always there */
697 bank1
= fbuffer
[0x100000] == 0x34;
698 bank2
= fbuffer
[0x200000] == 0x56;
699 bank3
= fbuffer
[0x300000] == 0x78;
700 info
->total_vram
= (bank0
+ bank1
+ bank2
+ bank3
) * 0x100000;
701 printk(KERN_INFO
"Total VRAM = %dMB %d%d%d%d\n", (int) (info
->total_vram
/ 1024 / 1024), bank3
, bank2
, bank1
, bank0
);
704 * Try to determine whether we have an old or a new DACula.
706 out_8(&info
->cmap_regs
->addr
, 0x40);
707 info
->dactype
= in_8(&info
->cmap_regs
->d2
);
708 switch (info
->dactype
) {
717 printk(KERN_INFO
"Unknown DACula type: %x\n", info
->dactype
);
721 if (!init_platinum(info
)) {
726 #ifdef CONFIG_FB_COMPAT_XPMAC
727 if (!console_fb_info
)
728 console_fb_info
= &info
->fb_info
;
733 * Get the monitor sense value.
734 * Note that this can be called before calibrate_delay,
735 * so we can't use udelay.
737 static int read_platinum_sense(struct fb_info_platinum
*info
)
739 volatile struct platinum_regs
*platinum_regs
= info
->platinum_regs
;
742 out_be32(&platinum_regs
->reg
[23].r
, 7); /* turn off drivers */
744 sense
= (~in_be32(&platinum_regs
->reg
[23].r
) & 7) << 8;
746 /* drive each sense line low in turn and collect the other 2 */
747 out_be32(&platinum_regs
->reg
[23].r
, 3); /* drive A low */
749 sense
|= (~in_be32(&platinum_regs
->reg
[23].r
) & 3) << 4;
750 out_be32(&platinum_regs
->reg
[23].r
, 5); /* drive B low */
752 sense
|= (~in_be32(&platinum_regs
->reg
[23].r
) & 4) << 1;
753 sense
|= (~in_be32(&platinum_regs
->reg
[23].r
) & 1) << 2;
754 out_be32(&platinum_regs
->reg
[23].r
, 6); /* drive C low */
756 sense
|= (~in_be32(&platinum_regs
->reg
[23].r
) & 6) >> 1;
758 out_be32(&platinum_regs
->reg
[23].r
, 7); /* turn off drivers */
763 /* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */
764 static int platinum_var_to_par(const struct fb_var_screeninfo
*var
,
765 struct fb_par_platinum
*par
,
766 const struct fb_info_platinum
*info
)
768 if(mac_var_to_vmode(var
, &par
->vmode
, &par
->cmode
) != 0) {
769 printk(KERN_ERR
"platinum_var_to_par: mac_var_to_vmode unsuccessful.\n");
770 printk(KERN_ERR
"platinum_var_to_par: var->xres = %d\n", var
->xres
);
771 printk(KERN_ERR
"platinum_var_to_par: var->yres = %d\n", var
->yres
);
772 printk(KERN_ERR
"platinum_var_to_par: var->xres_virtual = %d\n", var
->xres_virtual
);
773 printk(KERN_ERR
"platinum_var_to_par: var->yres_virtual = %d\n", var
->yres_virtual
);
774 printk(KERN_ERR
"platinum_var_to_par: var->bits_per_pixel = %d\n", var
->bits_per_pixel
);
775 printk(KERN_ERR
"platinum_var_to_par: var->pixclock = %d\n", var
->pixclock
);
776 printk(KERN_ERR
"platinum_var_to_par: var->vmode = %d\n", var
->vmode
);
780 if(!platinum_reg_init
[par
->vmode
-1]) {
781 printk(KERN_ERR
"platinum_var_to_par, vmode %d not valid.\n", par
->vmode
);
785 if (platinum_vram_reqd(par
->vmode
, par
->cmode
) > info
->total_vram
) {
786 printk(KERN_ERR
"platinum_var_to_par, not enough ram for vmode %d, cmode %d.\n", par
->vmode
, par
->cmode
);
790 par
->xres
= vmode_attrs
[par
->vmode
-1].hres
;
791 par
->yres
= vmode_attrs
[par
->vmode
-1].vres
;
794 par
->vxres
= par
->xres
;
795 par
->vyres
= par
->yres
;
800 static int platinum_par_to_var(struct fb_var_screeninfo
*var
,
801 const struct fb_par_platinum
*par
,
802 const struct fb_info_platinum
*info
)
804 return mac_vmode_to_var(par
->vmode
, par
->cmode
, var
);
807 static int platinum_encode_fix(struct fb_fix_screeninfo
*fix
,
808 const struct fb_par_platinum
*par
,
809 const struct fb_info_platinum
*info
)
811 struct platinum_regvals
*init
;
813 init
= platinum_reg_init
[par
->vmode
-1];
815 memset(fix
, 0, sizeof(*fix
));
816 strcpy(fix
->id
, "platinum");
817 fix
->smem_start
= (info
->frame_buffer_phys
) + init
->fb_offset
+ 0x20;
818 fix
->smem_len
= (u32
) info
->total_vram
;
819 fix
->mmio_start
= (info
->platinum_regs_phys
);
820 fix
->mmio_len
= 0x1000;
821 fix
->type
= FB_TYPE_PACKED_PIXELS
;
826 fix
->visual
= (par
->cmode
== CMODE_8
) ?
827 FB_VISUAL_PSEUDOCOLOR
: FB_VISUAL_DIRECTCOLOR
;
828 fix
->line_length
= vmode_attrs
[par
->vmode
-1].hres
* (1<<par
->cmode
) + 0x20;
835 * Parse user speficied options (`video=platinumfb:')
837 int __init
platinum_setup(char *options
)
841 if (!options
|| !*options
)
844 for (this_opt
= strtok(options
, ","); this_opt
;
845 this_opt
= strtok(NULL
, ",")) {
846 if (!strncmp(this_opt
, "font:", 5)) {
851 for (i
= 0; i
< sizeof(fontname
) - 1; i
++)
852 if (!*p
|| *p
== ' ' || *p
== ',')
854 memcpy(fontname
, this_opt
+ 5, i
);
857 if (!strncmp(this_opt
, "vmode:", 6)) {
858 int vmode
= simple_strtoul(this_opt
+6, NULL
, 0);
859 if (vmode
> 0 && vmode
<= VMODE_MAX
)
860 default_vmode
= vmode
;
861 } else if (!strncmp(this_opt
, "cmode:", 6)) {
862 int depth
= simple_strtoul(this_opt
+6, NULL
, 0);
866 default_cmode
= CMODE_8
;
870 default_cmode
= CMODE_16
;
874 default_cmode
= CMODE_32
;