Import 2.3.18pre1
[davej-history.git] / drivers / video / platinumfb.c
blobcf7fe3418e8016104a5d12fa4bd3553afa297b1d
1 /*
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
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
17 * more details.
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>
25 #include <linux/mm.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>
31 #include <linux/fb.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>
38 #endif
39 #include <asm/io.h>
40 #include <asm/prom.h>
41 #include <asm/pgtable.h>
42 #include <asm/adb.h>
44 #include <video/fbcon.h>
45 #include <video/fbcon-cfb8.h>
46 #include <video/fbcon-cfb16.h>
47 #include <video/fbcon-cfb32.h>
48 #include <video/macmodes.h>
50 #include "platinumfb.h"
52 static char fontname[40] __initdata = { 0 };
54 static int currcon = 0;
56 static int default_vmode = VMODE_NVRAM;
57 static int default_cmode = CMODE_NVRAM;
59 struct fb_par_platinum {
60 int vmode, cmode;
61 int xres, yres;
62 int vxres, vyres;
63 int xoffset, yoffset;
66 struct fb_info_platinum {
67 struct fb_info fb_info;
68 struct display disp;
69 struct fb_par_platinum default_par;
70 struct fb_par_platinum current_par;
72 struct {
73 __u8 red, green, blue;
74 } palette[256];
76 volatile struct cmap_regs *cmap_regs;
77 unsigned long cmap_regs_phys;
79 volatile struct platinum_regs *platinum_regs;
80 unsigned long platinum_regs_phys;
82 __u8 *frame_buffer;
83 volatile __u8 *base_frame_buffer;
84 unsigned long frame_buffer_phys;
86 unsigned long total_vram;
87 int clktype;
88 int dactype;
90 union {
91 #ifdef FBCON_HAS_CFB16
92 u16 cfb16[16];
93 #endif
94 #ifdef FBCON_HAS_CFB32
95 u32 cfb32[16];
96 #endif
97 } fbcon_cmap;
101 * Frame buffer device API
104 static int platinum_open(struct fb_info *info, int user);
105 static int platinum_release(struct fb_info *info, int user);
106 static int platinum_get_fix(struct fb_fix_screeninfo *fix, int con,
107 struct fb_info *fb);
108 static int platinum_get_var(struct fb_var_screeninfo *var, int con,
109 struct fb_info *fb);
110 static int platinum_set_var(struct fb_var_screeninfo *var, int con,
111 struct fb_info *fb);
112 static int platinum_pan_display(struct fb_var_screeninfo *var, int con,
113 struct fb_info *fb);
114 static int platinum_get_cmap(struct fb_cmap *cmap, int kspc, int con,
115 struct fb_info *info);
116 static int platinum_set_cmap(struct fb_cmap *cmap, int kspc, int con,
117 struct fb_info *info);
118 static int platinum_ioctl(struct inode *inode, struct file *file, u_int cmd,
119 u_long arg, int con, struct fb_info *info);
123 * Interface to the low level console driver
126 static int platinum_switch(int con, struct fb_info *fb);
127 static int platinum_updatevar(int con, struct fb_info *fb);
128 static void platinum_blank(int blank, struct fb_info *fb);
132 * internal functions
135 static inline int platinum_vram_reqd(int video_mode, int color_mode);
136 static int read_platinum_sense(struct fb_info_platinum *info);
137 static void set_platinum_clock(struct fb_info_platinum *info);
138 static void platinum_set_par(const struct fb_par_platinum *par, struct fb_info_platinum *info);
139 static int platinum_par_to_var(struct fb_var_screeninfo *var,
140 const struct fb_par_platinum *par,
141 const struct fb_info_platinum *info);
142 static int platinum_var_to_par(const struct fb_var_screeninfo *var,
143 struct fb_par_platinum *par,
144 const struct fb_info_platinum *info);
145 static int platinum_encode_fix(struct fb_fix_screeninfo *fix,
146 const struct fb_par_platinum *par,
147 const struct fb_info_platinum *info);
148 static int platinum_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
149 u_int *transp, struct fb_info *fb);
150 static int platinum_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
151 u_int transp, struct fb_info *fb);
152 static void do_install_cmap(int con, struct fb_info *info);
156 * Interface used by the world
159 int platinum_init(void);
160 #ifdef CONFIG_FB_OF
161 void platinum_of_init(struct device_node *dp);
162 #endif
163 int platinum_setup(char*);
166 static struct fb_ops platinumfb_ops = {
167 platinum_open,
168 platinum_release,
169 platinum_get_fix,
170 platinum_get_var,
171 platinum_set_var,
172 platinum_get_cmap,
173 platinum_set_cmap,
174 platinum_pan_display,
175 platinum_ioctl
179 __openfirmware
182 static int platinum_open(struct fb_info *info, int user)
184 MOD_INC_USE_COUNT;
185 return 0;
188 static int platinum_release(struct fb_info *info, int user)
190 MOD_DEC_USE_COUNT;
191 return 0;
194 static int platinum_get_fix(struct fb_fix_screeninfo *fix, int con,
195 struct fb_info *fb)
197 const struct fb_info_platinum *info = (struct fb_info_platinum *)fb;
198 struct fb_par_platinum par;
200 if (con == -1)
201 par = info->default_par;
202 else
203 platinum_var_to_par(&fb_display[con].var, &par, info);
205 platinum_encode_fix(fix, &par, info);
206 return 0;
209 static int platinum_get_var(struct fb_var_screeninfo *var, int con,
210 struct fb_info *fb)
212 const struct fb_info_platinum *info = (struct fb_info_platinum *)fb;
214 if (con == -1)
215 platinum_par_to_var(var, &info->default_par, info);
216 else
217 *var = fb_display[con].var;
219 return 0;
222 static int platinum_set_var(struct fb_var_screeninfo *var, int con,
223 struct fb_info *fb)
225 struct fb_info_platinum *info = (struct fb_info_platinum *) fb;
226 struct fb_par_platinum par;
227 struct display *display;
228 int oldxres, oldyres, oldvxres, oldvyres, oldbpp, err;
229 int activate = var->activate;
231 display = (con >= 0) ? &fb_display[con] : fb->disp;
233 if((err = platinum_var_to_par(var, &par, info))) {
234 printk(KERN_ERR "platinum_set_var: error calling platinum_var_to_par: %d.\n", err);
235 return err;
238 platinum_par_to_var(var, &par, info);
240 if ((activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) {
241 printk(KERN_INFO "platinum_set_var: Not activating.\n");
242 return 0;
245 oldxres = display->var.xres;
246 oldyres = display->var.yres;
247 oldvxres = display->var.xres_virtual;
248 oldvyres = display->var.yres_virtual;
249 oldbpp = display->var.bits_per_pixel;
250 display->var = *var;
252 if (oldxres != var->xres || oldyres != var->yres ||
253 oldvxres != var->xres_virtual || oldyres != var->yres_virtual ||
254 oldbpp != var->bits_per_pixel) {
255 struct fb_fix_screeninfo fix;
257 platinum_encode_fix(&fix, &par, info);
258 display->screen_base = (char *) info->frame_buffer + 0x1000;
259 display->visual = fix.visual;
260 display->type = fix.type;
261 display->type_aux = fix.type_aux;
262 display->ypanstep = fix.ypanstep;
263 display->ywrapstep = fix.ywrapstep;
264 display->line_length = fix.line_length;
265 display->can_soft_blank = 1;
266 display->inverse = 0;
268 switch(par.cmode) {
269 #ifdef FBCON_HAS_CFB8
270 case CMODE_8:
271 display->dispsw = &fbcon_cfb8;
272 break;
273 #endif
274 #ifdef FBCON_HAS_CFB16
275 case CMODE_16:
276 display->dispsw = &fbcon_cfb16;
277 display->dispsw_data = info->fbcon_cmap.cfb16;
278 break;
279 #endif
280 #ifdef FBCON_HAS_CFB32
281 case CMODE_32:
282 display->dispsw = &fbcon_cfb32;
283 display->dispsw_data = info->fbcon_cmap.cfb32;
284 break;
285 #endif
286 default:
287 display->dispsw = &fbcon_dummy;
288 break;
291 display->scrollmode = SCROLL_YREDRAW;
292 if (info->fb_info.changevar)
293 (*info->fb_info.changevar)(con);
296 if (con == currcon)
297 platinum_set_par(&par, info);
299 if (oldbpp != var->bits_per_pixel) {
300 if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
301 return err;
302 do_install_cmap(con, &info->fb_info);
305 return 0;
308 static int platinum_pan_display(struct fb_var_screeninfo *var, int con,
309 struct fb_info *info)
312 * Pan (or wrap, depending on the `vmode' field) the display using the
313 * `xoffset' and `yoffset' fields of the `var' structure.
314 * If the values don't fit, return -EINVAL.
317 if (var->xoffset != 0 || var->yoffset != 0)
318 return -EINVAL;
319 return 0;
322 static int platinum_get_cmap(struct fb_cmap *cmap, int kspc, int con,
323 struct fb_info *info)
325 if (con == currcon) /* current console? */
326 return fb_get_cmap(cmap, kspc, platinum_getcolreg, info);
327 if (fb_display[con].cmap.len) /* non default colormap? */
328 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
329 else {
330 int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
331 fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
333 return 0;
336 static int platinum_set_cmap(struct fb_cmap *cmap, int kspc, int con,
337 struct fb_info *info)
339 int err;
341 if (!fb_display[con].cmap.len) {
342 int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
343 err = fb_alloc_cmap(&fb_display[con].cmap, size, 0);
344 if (err)
345 return err;
348 if (con == currcon)
349 return fb_set_cmap(cmap, kspc, platinum_setcolreg, info);
350 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
351 return 0;
354 static int platinum_ioctl(struct inode *inode, struct file *file, u_int cmd,
355 u_long arg, int con, struct fb_info *info)
357 printk(KERN_ERR "platinum_ioctl not yet implemented\n");
358 return -EINVAL;
361 static int platinum_switch(int con, struct fb_info *fb)
363 struct fb_info_platinum *info = (struct fb_info_platinum *) fb;
364 struct fb_par_platinum par;
366 if (fb_display[currcon].cmap.len)
367 fb_get_cmap(&fb_display[currcon].cmap, 1, platinum_getcolreg,
368 fb);
369 currcon = con;
371 platinum_var_to_par(&fb_display[currcon].var, &par, info);
372 platinum_set_par(&par, info);
373 do_install_cmap(con, fb);
375 return 1;
378 static int platinum_updatevar(int con, struct fb_info *fb)
380 printk(KERN_ERR "platinum_updatevar is doing nothing yet.\n");
381 return 0;
384 static void platinum_blank(int blank, struct fb_info *fb)
387 * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
388 * then the caller blanks by setting the CLUT (Color Look Up Table) to all
389 * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
390 * to e.g. a video mode which doesn't support it. Implements VESA suspend
391 * and powerdown modes on hardware that supports disabling hsync/vsync:
392 * blank_mode == 2: suspend vsync
393 * blank_mode == 3: suspend hsync
394 * blank_mode == 4: powerdown
396 /* [danj] I think there's something fishy about those constants... */
398 struct fb_info_platinum *info = (struct fb_info_platinum *) fb;
399 int ctrl;
401 ctrl = ld_le32(&info->platinum_regs->ctrl.r) | 0x33;
402 if (blank)
403 --blank_mode;
404 if (blank & VESA_VSYNC_SUSPEND)
405 ctrl &= ~3;
406 if (blank & VESA_HSYNC_SUSPEND)
407 ctrl &= ~0x30;
408 out_le32(&info->platinum_regs->ctrl.r, ctrl);
410 /* TODO: Figure out how the heck to powerdown this thing! */
411 return;
414 static int platinum_getcolreg(u_int regno, u_int *red, u_int *green,
415 u_int *blue, u_int *transp, struct fb_info *fb)
417 struct fb_info_platinum *info = (struct fb_info_platinum *) fb;
419 if (regno > 255)
420 return 1;
422 *red = (info->palette[regno].red<<8) | info->palette[regno].red;
423 *green = (info->palette[regno].green<<8) | info->palette[regno].green;
424 *blue = (info->palette[regno].blue<<8) | info->palette[regno].blue;
425 *transp = 0;
426 return 0;
429 static int platinum_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
430 u_int transp, struct fb_info *fb)
432 struct fb_info_platinum *info = (struct fb_info_platinum *) fb;
433 volatile struct cmap_regs *cmap_regs = info->cmap_regs;
434 int scale;
436 if (regno > 255)
437 return 1;
439 red >>= 8;
440 green >>= 8;
441 blue >>= 8;
443 info->palette[regno].red = red;
444 info->palette[regno].green = green;
445 info->palette[regno].blue = blue;
447 scale = (info->current_par.cmode == CMODE_16) ? 3 : 0;
449 out_8(&cmap_regs->addr, regno); /* tell clut what addr to fill */
450 out_8(&cmap_regs->lut, red<<scale); /* send one color channel at */
451 out_8(&cmap_regs->lut, green<<scale); /* a time... */
452 out_8(&cmap_regs->lut, blue<<scale);
454 if(regno < 16) {
455 #ifdef FBCON_HAS_CFB16
456 info->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | (regno << 0);
457 #endif
458 #ifdef FBCON_HAS_CFB32
459 info->fbcon_cmap.cfb32[regno] = (regno << 24) | (regno << 16) | (regno << 8) | regno;
460 #endif
462 return 0;
465 static void do_install_cmap(int con, struct fb_info *info)
467 if (con != currcon)
468 return;
469 if (fb_display[con].cmap.len)
470 fb_set_cmap(&fb_display[con].cmap, 1, platinum_setcolreg,
471 info);
472 else {
473 int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
474 fb_set_cmap(fb_default_cmap(size), 1, platinum_setcolreg,
475 info);
479 static inline int platinum_vram_reqd(int video_mode, int color_mode)
481 return vmode_attrs[video_mode-1].vres *
482 (vmode_attrs[video_mode-1].hres * (1<<color_mode) + 0x20) +0x1000;
485 #define STORE_D2(a, d) { \
486 out_8(&cmap_regs->addr, (a+32)); \
487 out_8(&cmap_regs->d2, (d)); \
490 static void set_platinum_clock(struct fb_info_platinum *info)
492 volatile struct cmap_regs *cmap_regs = info->cmap_regs;
493 struct platinum_regvals *init;
495 init = platinum_reg_init[info->current_par.vmode-1];
497 STORE_D2(6, 0xc6);
498 out_8(&cmap_regs->addr,3+32);
500 if (in_8(&cmap_regs->d2) == 2) {
501 STORE_D2(7, init->clock_params[info->clktype][0]);
502 STORE_D2(8, init->clock_params[info->clktype][1]);
503 STORE_D2(3, 3);
504 } else {
505 STORE_D2(4, init->clock_params[info->clktype][0]);
506 STORE_D2(5, init->clock_params[info->clktype][1]);
507 STORE_D2(3, 2);
510 __delay(5000);
511 STORE_D2(9, 0xa6);
515 /* Now how about actually saying, Make it so! */
516 /* Some things in here probably don't need to be done each time. */
517 static void platinum_set_par(const struct fb_par_platinum *par, struct fb_info_platinum *info)
519 volatile struct platinum_regs *platinum_regs = info->platinum_regs;
520 volatile struct cmap_regs *cmap_regs = info->cmap_regs;
521 struct platinum_regvals *init;
522 int i;
523 int vmode, cmode;
525 info->current_par = *par;
527 vmode = par->vmode;
528 cmode = par->cmode;
530 init = platinum_reg_init[vmode - 1];
532 /* Initialize display timing registers */
533 out_be32(&platinum_regs->reg[24].r, 7); /* turn display off */
535 for (i = 0; i < 26; ++i)
536 out_be32(&platinum_regs->reg[i+32].r, init->regs[i]);
538 out_be32(&platinum_regs->reg[26+32].r, (info->total_vram == 0x100000 ?
539 init->offset[cmode] + 4 - cmode :
540 init->offset[cmode]));
541 out_be32(&platinum_regs->reg[16].r, (unsigned) info->frame_buffer_phys + 0x1000 - 0x10);
542 out_be32(&platinum_regs->reg[18].r, init->pitch[cmode]);
543 out_be32(&platinum_regs->reg[19].r, (info->total_vram == 0x100000 ?
544 init->mode[cmode+1] :
545 init->mode[cmode]));
546 out_be32(&platinum_regs->reg[20].r, (info->total_vram == 0x100000 ? 0x11 : 0x1011));
547 out_be32(&platinum_regs->reg[21].r, 0x100);
548 out_be32(&platinum_regs->reg[22].r, 1);
549 out_be32(&platinum_regs->reg[23].r, 1);
550 out_be32(&platinum_regs->reg[26].r, 0xc00);
551 out_be32(&platinum_regs->reg[27].r, 0x235);
552 /* out_be32(&platinum_regs->reg[27].r, 0x2aa); */
554 STORE_D2(0, (info->total_vram == 0x100000 ?
555 init->dacula_ctrl[cmode] & 0xf :
556 init->dacula_ctrl[cmode]));
557 STORE_D2(1, 4);
558 STORE_D2(2, 0);
560 set_platinum_clock(info);
562 out_be32(&platinum_regs->reg[24].r, 0); /* turn display on */
564 #ifdef CONFIG_FB_COMPAT_XPMAC
565 if (console_fb_info == &info->fb_info) {
566 display_info.height = par->yres;
567 display_info.width = par->xres;
568 display_info.depth = ( (cmode == CMODE_32) ? 32 :
569 ((cmode == CMODE_16) ? 16 : 8));
570 display_info.pitch = vmode_attrs[vmode-1].hres * (1<<cmode) + 0x20;
571 display_info.mode = vmode;
572 strncpy(display_info.name, "platinum",
573 sizeof(display_info.name));
574 display_info.fb_address = info->frame_buffer_phys + 0x1000;
575 display_info.cmap_adr_address = info->cmap_regs_phys;
576 display_info.cmap_data_address = info->cmap_regs_phys + 0x30;
577 display_info.disp_reg_address = info->platinum_regs_phys;
580 #endif /* CONFIG_FB_COMPAT_XPMAC */
584 static int __init init_platinum(struct fb_info_platinum *info)
586 struct fb_var_screeninfo var;
587 struct display *disp;
588 int sense;
589 int j,k;
591 sense = read_platinum_sense(info);
592 printk(KERN_INFO "Monitor sense value = 0x%x, ", sense);
594 if (default_vmode == VMODE_NVRAM) {
595 default_vmode = nvram_read_byte(NV_VMODE);
596 if (default_vmode <= 0 || default_vmode > VMODE_MAX ||
597 !platinum_reg_init[default_vmode-1])
598 default_vmode = VMODE_CHOOSE;
600 if (default_vmode == VMODE_CHOOSE) {
601 default_vmode = mac_map_monitor_sense(sense);
603 if (default_vmode <= 0 || default_vmode > VMODE_MAX)
604 default_vmode = VMODE_640_480_60;
605 if (default_cmode == CMODE_NVRAM)
606 default_cmode = nvram_read_byte(NV_CMODE);
607 if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
608 default_cmode = CMODE_8;
610 * Reduce the pixel size if we don't have enough VRAM.
612 while(default_cmode > CMODE_8 && platinum_vram_reqd(default_vmode, default_cmode) > info->total_vram)
613 default_cmode--;
615 printk("using video mode %d and color mode %d.\n", default_vmode, default_cmode);
617 mac_vmode_to_var(default_vmode, default_cmode, &var);
619 if (platinum_var_to_par(&var, &info->default_par, info)) {
620 printk(KERN_ERR "platinumfb: can't set default video mode\n");
621 return 0;
624 disp = &info->disp;
626 strcpy(info->fb_info.modename, "platinum");
627 info->fb_info.node = -1;
628 info->fb_info.fbops = &platinumfb_ops;
629 info->fb_info.disp = disp;
630 strcpy(info->fb_info.fontname, fontname);
631 info->fb_info.changevar = NULL;
632 info->fb_info.switch_con = &platinum_switch;
633 info->fb_info.updatevar = &platinum_updatevar;
634 info->fb_info.blank = &platinum_blank;
635 info->fb_info.flags = FBINFO_FLAG_DEFAULT;
637 for (j = 0; j < 16; j++) {
638 k = color_table[j];
639 info->palette[j].red = default_red[k];
640 info->palette[j].green = default_grn[k];
641 info->palette[j].blue = default_blu[k];
643 platinum_set_var(&var, -1, &info->fb_info);
645 if (register_framebuffer(&info->fb_info) < 0)
646 return 0;
648 printk(KERN_INFO "fb%d: platinum frame buffer device\n",
649 GET_FB_IDX(info->fb_info.node));
651 return 1;
654 int __init platinum_init(void)
656 #ifndef CONFIG_FB_OF
657 struct device_node *dp;
659 dp = find_devices("platinum");
660 if (dp != 0)
661 platinum_of_init(dp);
662 #endif /* CONFIG_FB_OF */
663 return 0;
666 #ifdef __powerpc__
667 #define invalidate_cache(addr) \
668 asm volatile("eieio; dcbi 0,%1" \
669 : "=m" (*(addr)) : "r" (addr) : "memory");
670 #else
671 #define invalidate_cache(addr)
672 #endif
674 void __init platinum_of_init(struct device_node *dp)
676 struct fb_info_platinum *info;
677 unsigned long addr, size;
678 int i, bank0, bank1, bank2, bank3;
680 if(dp->n_addrs != 2) {
681 printk(KERN_ERR "expecting 2 address for platinum (got %d)", dp->n_addrs);
682 return;
685 info = kmalloc(sizeof(*info), GFP_ATOMIC);
686 if (info == 0)
687 return;
688 memset(info, 0, sizeof(*info));
690 /* Map in frame buffer and registers */
691 for (i = 0; i < dp->n_addrs; ++i) {
692 addr = dp->addrs[i].address;
693 size = dp->addrs[i].size;
694 if (size >= 0x400000) {
695 /* frame buffer - map only 4MB */
696 info->frame_buffer_phys = addr;
697 info->frame_buffer = __ioremap(addr, 0x400000, _PAGE_WRITETHRU);
698 info->base_frame_buffer = info->frame_buffer;
699 } else {
700 /* registers */
701 info->platinum_regs_phys = addr;
702 info->platinum_regs = ioremap(addr, size);
706 info->cmap_regs_phys = 0xf301b000; /* XXX not in prom? */
707 info->cmap_regs = ioremap(info->cmap_regs_phys, 0x1000);
709 /* Grok total video ram */
710 out_be32(&info->platinum_regs->reg[16].r, (unsigned)info->frame_buffer_phys);
711 out_be32(&info->platinum_regs->reg[20].r, 0x1011); /* select max vram */
712 out_be32(&info->platinum_regs->reg[24].r, 0); /* switch in vram */
714 info->base_frame_buffer[0x100000] = 0x34;
715 info->base_frame_buffer[0x100008] = 0x0;
716 invalidate_cache(&info->base_frame_buffer[0x100000]);
717 info->base_frame_buffer[0x200000] = 0x56;
718 info->base_frame_buffer[0x200008] = 0x0;
719 invalidate_cache(&info->base_frame_buffer[0x200000]);
720 info->base_frame_buffer[0x300000] = 0x78;
721 info->base_frame_buffer[0x300008] = 0x0;
722 invalidate_cache(&info->base_frame_buffer[0x300000]);
723 bank0 = 1; /* builtin 1MB vram, always there */
724 bank1 = info->base_frame_buffer[0x100000] == 0x34;
725 bank2 = info->base_frame_buffer[0x200000] == 0x56;
726 bank3 = info->base_frame_buffer[0x300000] == 0x78;
727 info->total_vram = (bank0 + bank1 + bank2 + bank3) * 0x100000;
728 printk(KERN_INFO "Total VRAM = %dMB %d%d%d%d\n", (int) (info->total_vram / 1024 / 1024), bank3, bank2, bank1, bank0);
731 * Try to determine whether we have an old or a new DACula.
733 out_8(&info->cmap_regs->addr, 0x40);
734 info->dactype = in_8(&info->cmap_regs->d2);
735 switch (info->dactype) {
736 case 0x3c:
737 info->clktype = 1;
738 break;
739 case 0x84:
740 info->clktype = 0;
741 break;
742 default:
743 info->clktype = 0;
744 printk(KERN_INFO "Unknown DACula type: %x\n", info->dactype);
745 break;
748 if (!init_platinum(info)) {
749 kfree(info);
750 return;
753 #ifdef CONFIG_FB_COMPAT_XPMAC
754 if (!console_fb_info)
755 console_fb_info = &info->fb_info;
756 #endif
760 * Get the monitor sense value.
761 * Note that this can be called before calibrate_delay,
762 * so we can't use udelay.
764 static int read_platinum_sense(struct fb_info_platinum *info)
766 volatile struct platinum_regs *platinum_regs = info->platinum_regs;
767 int sense;
769 out_be32(&platinum_regs->reg[23].r, 7); /* turn off drivers */
770 __delay(2000);
771 sense = (~in_be32(&platinum_regs->reg[23].r) & 7) << 8;
773 /* drive each sense line low in turn and collect the other 2 */
774 out_be32(&platinum_regs->reg[23].r, 3); /* drive A low */
775 __delay(2000);
776 sense |= (~in_be32(&platinum_regs->reg[23].r) & 3) << 4;
777 out_be32(&platinum_regs->reg[23].r, 5); /* drive B low */
778 __delay(2000);
779 sense |= (~in_be32(&platinum_regs->reg[23].r) & 4) << 1;
780 sense |= (~in_be32(&platinum_regs->reg[23].r) & 1) << 2;
781 out_be32(&platinum_regs->reg[23].r, 6); /* drive C low */
782 __delay(2000);
783 sense |= (~in_be32(&platinum_regs->reg[23].r) & 6) >> 1;
785 out_be32(&platinum_regs->reg[23].r, 7); /* turn off drivers */
787 return sense;
790 /* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */
791 static int platinum_var_to_par(const struct fb_var_screeninfo *var,
792 struct fb_par_platinum *par,
793 const struct fb_info_platinum *info)
795 if(mac_var_to_vmode(var, &par->vmode, &par->cmode) != 0) {
796 printk(KERN_ERR "platinum_var_to_par: mac_var_to_vmode unsuccessful.\n");
797 printk(KERN_ERR "platinum_var_to_par: var->xres = %d\n", var->xres);
798 printk(KERN_ERR "platinum_var_to_par: var->yres = %d\n", var->yres);
799 printk(KERN_ERR "platinum_var_to_par: var->xres_virtual = %d\n", var->xres_virtual);
800 printk(KERN_ERR "platinum_var_to_par: var->yres_virtual = %d\n", var->yres_virtual);
801 printk(KERN_ERR "platinum_var_to_par: var->bits_per_pixel = %d\n", var->bits_per_pixel);
802 printk(KERN_ERR "platinum_var_to_par: var->pixclock = %d\n", var->pixclock);
803 printk(KERN_ERR "platinum_var_to_par: var->vmode = %d\n", var->vmode);
804 return -EINVAL;
807 if(!platinum_reg_init[par->vmode-1]) {
808 printk(KERN_ERR "platinum_var_to_par, vmode %d not valid.\n", par->vmode);
809 return -EINVAL;
812 if (platinum_vram_reqd(par->vmode, par->cmode) > info->total_vram) {
813 printk(KERN_ERR "platinum_var_to_par, not enough ram for vmode %d, cmode %d.\n", par->vmode, par->cmode);
814 return -EINVAL;
817 par->xres = vmode_attrs[par->vmode-1].hres;
818 par->yres = vmode_attrs[par->vmode-1].vres;
819 par->xoffset = 0;
820 par->yoffset = 0;
821 par->vxres = par->xres;
822 par->vyres = par->yres;
824 return 0;
827 static int platinum_par_to_var(struct fb_var_screeninfo *var,
828 const struct fb_par_platinum *par,
829 const struct fb_info_platinum *info)
831 return mac_vmode_to_var(par->vmode, par->cmode, var);
834 static int platinum_encode_fix(struct fb_fix_screeninfo *fix,
835 const struct fb_par_platinum *par,
836 const struct fb_info_platinum *info)
838 memset(fix, 0, sizeof(*fix));
839 strcpy(fix->id, "platinum");
840 fix->smem_start = (info->frame_buffer_phys + 0x1000);
841 fix->smem_len = (u32) info->total_vram - 0x1000;
842 fix->mmio_start = (info->platinum_regs_phys);
843 fix->mmio_len = 0x1000;
844 fix->type = FB_TYPE_PACKED_PIXELS;
845 fix->type_aux = 0;
846 fix->ywrapstep = 0;
847 fix->xpanstep = 0;
848 fix->ypanstep = 0;
849 fix->visual = (par->cmode == CMODE_8) ?
850 FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
851 fix->line_length = vmode_attrs[par->vmode-1].hres * (1<<par->cmode) + 0x20;
853 return 0;
858 * Parse user speficied options (`video=platinumfb:')
860 int __init platinum_setup(char *options)
862 char *this_opt;
864 if (!options || !*options)
865 return 0;
867 for (this_opt = strtok(options, ","); this_opt;
868 this_opt = strtok(NULL, ",")) {
869 if (!strncmp(this_opt, "font:", 5)) {
870 char *p;
871 int i;
873 p = this_opt + 5;
874 for (i = 0; i < sizeof(fontname) - 1; i++)
875 if (!*p || *p == ' ' || *p == ',')
876 break;
877 memcpy(fontname, this_opt + 5, i);
878 fontname[i] = 0;
880 if (!strncmp(this_opt, "vmode:", 6)) {
881 int vmode = simple_strtoul(this_opt+6, NULL, 0);
882 if (vmode > 0 && vmode <= VMODE_MAX)
883 default_vmode = vmode;
884 } else if (!strncmp(this_opt, "cmode:", 6)) {
885 int depth = simple_strtoul(this_opt+6, NULL, 0);
886 switch (depth) {
887 case 8:
888 default_cmode = CMODE_8;
889 break;
890 case 15:
891 case 16:
892 default_cmode = CMODE_16;
893 break;
894 case 24:
895 case 32:
896 default_cmode = CMODE_32;
897 break;
901 return 0;