Import 2.3.18pre1
[davej-history.git] / drivers / video / controlfb.c
blob6893afbefc122e77cc1b29ce51f184887b9217cd
1 /*
2 * controlfb.c -- frame buffer device for the PowerMac 'control' display
4 * Created 12 July 1998 by Dan Jacobowitz <dan@debian.org>
5 * Copyright (C) 1998 Dan Jacobowitz
7 * Frame buffer structure from:
8 * drivers/video/chipsfb.c -- frame buffer device for
9 * Chips & Technologies 65550 chip.
11 * Copyright (C) 1998 Paul Mackerras
13 * This file is derived from the Powermac "chips" driver:
14 * Copyright (C) 1997 Fabio Riccardi.
15 * And from the frame buffer device for Open Firmware-initialized devices:
16 * Copyright (C) 1997 Geert Uytterhoeven.
18 * Hardware information from:
19 * control.c: Console support for PowerMac "control" display adaptor.
20 * Copyright (C) 1996 Paul Mackerras
22 * This file is subject to the terms and conditions of the GNU General Public
23 * License. See the file COPYING in the main directory of this archive for
24 * more details.
27 #include <linux/config.h>
28 #include <linux/module.h>
29 #include <linux/kernel.h>
30 #include <linux/errno.h>
31 #include <linux/string.h>
32 #include <linux/mm.h>
33 #include <linux/tty.h>
34 #include <linux/malloc.h>
35 #include <linux/vmalloc.h>
36 #include <linux/delay.h>
37 #include <linux/interrupt.h>
38 #include <linux/fb.h>
39 #include <linux/selection.h>
40 #include <linux/init.h>
41 #include <linux/pci.h>
42 #include <linux/nvram.h>
43 #ifdef CONFIG_FB_COMPAT_XPMAC
44 #include <asm/vc_ioctl.h>
45 #endif
46 #include <asm/io.h>
47 #include <asm/prom.h>
48 #include <asm/pgtable.h>
49 #include <asm/adb.h>
50 #include <asm/cuda.h>
52 #include <video/fbcon.h>
53 #include <video/fbcon-cfb8.h>
54 #include <video/fbcon-cfb16.h>
55 #include <video/fbcon-cfb32.h>
56 #include <video/macmodes.h>
58 #include "controlfb.h"
60 struct fb_par_control {
61 int vmode, cmode;
62 int xres, yres;
63 int vxres, vyres;
64 int xoffset, yoffset;
67 #define DIRTY(z) ((x)->z != (y)->z)
68 static inline int PAR_EQUAL(struct fb_par_control *x, struct fb_par_control *y)
70 return (!DIRTY(vmode) && !DIRTY(cmode) && !DIRTY(xres)
71 && !DIRTY(yres) && !DIRTY(vxres) && !DIRTY(vyres)
72 && !DIRTY(xoffset) && !DIRTY(yoffset));
74 static inline int VAR_MATCH(struct fb_var_screeninfo *x, struct fb_var_screeninfo *y)
76 return (!DIRTY(bits_per_pixel) && !DIRTY(xres)
77 && !DIRTY(yres) && !DIRTY(xres_virtual)
78 && !DIRTY(yres_virtual));
81 struct fb_info_control {
82 struct fb_info info;
83 /* struct fb_fix_screeninfo fix;
84 struct fb_var_screeninfo var;*/
85 struct display display;
86 struct fb_par_control par;
87 struct {
88 __u8 red, green, blue;
89 } palette[256];
91 struct cmap_regs *cmap_regs;
92 unsigned long cmap_regs_phys;
94 struct control_regs *control_regs;
95 unsigned long control_regs_phys;
97 __u8 *frame_buffer;
98 unsigned long frame_buffer_phys;
100 int sense, control_use_bank2;
101 unsigned long total_vram;
102 union {
103 #ifdef FBCON_HAS_CFB16
104 u16 cfb16[16];
105 #endif
106 #ifdef FBCON_HAS_CFB32
107 u32 cfb32[16];
108 #endif
109 } fbcon_cmap;
112 /******************** Prototypes for exported functions ********************/
113 static int control_open(struct fb_info *info, int user);
114 static int control_release(struct fb_info *info, int user);
115 static int control_get_fix(struct fb_fix_screeninfo *fix, int con,
116 struct fb_info *info);
117 static int control_get_var(struct fb_var_screeninfo *var, int con,
118 struct fb_info *info);
119 static int control_set_var(struct fb_var_screeninfo *var, int con,
120 struct fb_info *info);
121 static int control_pan_display(struct fb_var_screeninfo *var, int con,
122 struct fb_info *info);
123 static int control_get_cmap(struct fb_cmap *cmap, int kspc, int con,
124 struct fb_info *info);
125 static int control_set_cmap(struct fb_cmap *cmap, int kspc, int con,
126 struct fb_info *info);
127 static int control_ioctl(struct inode *inode, struct file *file, u_int cmd,
128 u_long arg, int con, struct fb_info *info);
131 static int controlfb_getcolreg(u_int regno, u_int *red, u_int *green,
132 u_int *blue, u_int *transp, struct fb_info *info);
133 static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
134 u_int transp, struct fb_info *info);
136 /******************** Prototypes for internal functions ********************/
137 static void control_par_to_fix(struct fb_par_control *par, struct fb_fix_screeninfo *fix,
138 struct fb_info_control *p);
139 static void do_install_cmap(int con, struct fb_info *info);
140 static void control_set_dispsw(struct display *disp, int cmode, struct fb_info_control *p);
142 /************************* Internal variables *****************************/
143 static int currcon = 0;
144 static int par_set = 0;
145 static char fontname[40] __initdata = { 0 };
146 static int default_vmode = VMODE_NVRAM;
147 static int default_cmode = CMODE_NVRAM;
150 * Exported functions
152 int control_init(void);
153 #ifdef CONFIG_FB_OF
154 void control_of_init(struct device_node *dp);
155 #endif
156 void control_setup(char *);
158 static int read_control_sense(struct fb_info_control *p);
159 static inline int control_vram_reqd(int video_mode, int color_mode);
160 static void set_control_clock(unsigned char *params);
161 static void control_set_hardware(struct fb_info_control *p, struct fb_par_control *par);
162 static inline void control_par_to_var(struct fb_par_control *par, struct fb_var_screeninfo *var);
163 static int control_var_to_par(struct fb_var_screeninfo *var,
164 struct fb_par_control *par, const struct fb_info *fb_info);
166 static void control_init_info(struct fb_info *info, struct fb_info_control *p);
167 static void control_par_to_display(struct fb_par_control *par,
168 struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_control *p);
170 static int controlfb_updatevar(int con, struct fb_info *info);
172 static struct fb_ops controlfb_ops = {
173 control_open,
174 control_release,
175 control_get_fix,
176 control_get_var,
177 control_set_var,
178 control_get_cmap,
179 control_set_cmap,
180 control_pan_display,
181 control_ioctl
186 /******************** The functions for controlfb_ops ********************/
188 /********** Dummies for loading control as a module **********/
190 int control_open(struct fb_info *info, int user)
192 MOD_INC_USE_COUNT;
193 return 0;
196 static int control_release(struct fb_info *info, int user)
198 MOD_DEC_USE_COUNT;
199 return 0;
202 #ifdef MODULE
203 int init_module(void)
205 struct device_node *dp;
207 printk("Loading...\n");
208 dp = find_devices("control");
209 if (dp != 0)
210 control_of_init(dp);
211 else
212 printk("Failed.\n");
213 printk("Done.\n");
216 void cleanup_module(void)
219 #endif
221 /*********** Providing our information to the user ************/
223 static int control_get_fix(struct fb_fix_screeninfo *fix, int con,
224 struct fb_info *info)
226 struct fb_info_control *p = (struct fb_info_control *) info;
228 if(!par_set)
229 printk(KERN_ERR "control_get_fix called with unset par!\n");
230 if(con == -1) {
231 control_par_to_fix(&p->par, fix, p);
232 } else {
233 struct fb_par_control par;
235 control_var_to_par(&fb_display[con].var, &par, info);
236 control_par_to_fix(&par, fix, p);
238 return 0;
241 static int control_get_var(struct fb_var_screeninfo *var, int con,
242 struct fb_info *info)
244 struct fb_info_control *p = (struct fb_info_control *) info;
246 if(!par_set)
247 printk(KERN_ERR "control_get_var called with unset par!\n");
248 if(con == -1) {
249 control_par_to_var(&p->par, var);
250 } else {
251 *var = fb_display[con].var;
253 return 0;
256 /* Sets everything according to var */
257 /* No longer safe for use in console switching */
258 static int control_set_var(struct fb_var_screeninfo *var, int con,
259 struct fb_info *info)
261 struct fb_info_control *p = (struct fb_info_control *) info;
262 struct display *disp;
263 struct fb_par_control par;
264 int depthchange, err;
265 int activate = var->activate;
267 disp = (con >= 0) ? &fb_display[con] : info->disp;
269 if((err = control_var_to_par(var, &par, info))) {
270 printk (KERN_ERR "control_set_var: error calling control_var_to_par: %d.\n", err);
271 return err;
274 control_par_to_var(&par, var);
276 if ((activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
277 return 0;
279 /* I know, we want to use fb_display[con], but grab certain info from p->var instead. */
280 /* [above no longer true] */
281 depthchange = (disp->var.bits_per_pixel != var->bits_per_pixel);
282 if(!VAR_MATCH(&disp->var, var)) {
283 struct fb_fix_screeninfo fix;
284 control_par_to_fix(&par, &fix, p);
285 control_par_to_display(&par, disp, &fix, p);
286 if(info->changevar)
287 (*info->changevar)(con);
288 } else
289 disp->var = *var;
290 /*p->disp = *disp;*/
293 if(con == currcon || con == -1) {
294 control_set_hardware(p, &par);
296 if(depthchange) {
297 if((err = fb_alloc_cmap(&disp->cmap, 0, 0)))
298 return err;
299 do_install_cmap(con, info);
301 return 0;
304 static int control_pan_display(struct fb_var_screeninfo *var, int con,
305 struct fb_info *info)
307 struct fb_info_control *p = (struct fb_info_control *)info;
308 struct fb_par_control *par = &p->par;
310 if (var->xoffset != 0 || var->yoffset+var->yres > var->yres_virtual)
311 return -EINVAL;
312 fb_display[con].var.yoffset = par->yoffset = var->yoffset;
313 if(con == currcon)
314 out_le32(&p->control_regs->start_addr.r,
315 par->yoffset * (par->vxres << par->cmode));
316 return 0;
319 static int control_get_cmap(struct fb_cmap *cmap, int kspc, int con,
320 struct fb_info *info)
322 if (con == currcon) /* current console? */
323 return fb_get_cmap(cmap, kspc, controlfb_getcolreg, info);
324 if (fb_display[con].cmap.len) /* non default colormap? */
325 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0: 2);
326 else {
327 int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
328 fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
330 return 0;
333 static int control_set_cmap(struct fb_cmap *cmap, int kspc, int con,
334 struct fb_info *info)
336 struct display *disp = &fb_display[con];
337 int err;
339 if (disp->cmap.len == 0) {
340 int size = disp->var.bits_per_pixel == 16 ? 32 : 256;
341 err = fb_alloc_cmap(&disp->cmap, size, 0);
342 if (err)
343 return err;
345 if (con == currcon)
346 return fb_set_cmap(cmap, kspc, controlfb_setcolreg, info);
347 fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
348 return 0;
351 static int control_ioctl(struct inode *inode, struct file *file, u_int cmd,
352 u_long arg, int con, struct fb_info *info)
354 return -EINVAL;
357 /******************** End of controlfb_ops implementation ********************/
358 /* (new one that is) */
361 static int controlfb_switch(int con, struct fb_info *info)
363 struct fb_info_control *p = (struct fb_info_control *)info;
364 struct fb_par_control par;
365 int oldcon = currcon;
367 if (fb_display[currcon].cmap.len)
368 fb_get_cmap(&fb_display[currcon].cmap, 1, controlfb_getcolreg,
369 info);
370 currcon = con;
372 control_var_to_par(&fb_display[con].var, &par, info);
373 control_set_hardware(p, &par);
374 control_set_dispsw(&fb_display[con], par.cmode, p);
376 if(fb_display[oldcon].var.yoffset != fb_display[con].var.yoffset)
377 controlfb_updatevar(con, info);
379 do_install_cmap(con, info);
380 return 1;
383 static int controlfb_updatevar(int con, struct fb_info *info)
385 struct fb_info_control *p = (struct fb_info_control *)info;
387 if(con != currcon)
388 return 0;
389 /* imsttfb blanks the unused bottom of the screen here...hmm. */
390 out_le32(&p->control_regs->start_addr.r,
391 fb_display[con].var.yoffset * fb_display[con].line_length);
393 return 0;
396 static void controlfb_blank(int blank_mode, struct fb_info *info)
399 * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
400 * then the caller blanks by setting the CLUT (Color Look Up Table) to all
401 * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
402 * to e.g. a video mode which doesn't support it. Implements VESA suspend
403 * and powerdown modes on hardware that supports disabling hsync/vsync:
404 * blank_mode == 2: suspend vsync
405 * blank_mode == 3: suspend hsync
406 * blank_mode == 4: powerdown
408 /* A blank_mode of 1+VESA_NO_BLANKING or 1+VESA_POWERDOWN act alike... */
409 struct fb_info_control *p = (struct fb_info_control *) info;
410 int ctrl;
412 if(blank_mode == 1+VESA_NO_BLANKING)
413 blank_mode = 1+VESA_POWERDOWN;
414 ctrl = ld_le32(&p->control_regs->ctrl.r) | 0x33;
415 if (blank_mode)
416 --blank_mode;
417 if (blank_mode & VESA_VSYNC_SUSPEND)
418 ctrl &= ~3;
419 if (blank_mode & VESA_HSYNC_SUSPEND)
420 ctrl &= ~0x30;
421 out_le32(&p->control_regs->ctrl.r, ctrl);
423 /* TODO: Figure out how the heck to powerdown this thing! */
425 return;
428 static int controlfb_getcolreg(u_int regno, u_int *red, u_int *green,
429 u_int *blue, u_int *transp, struct fb_info *info)
431 struct fb_info_control *p = (struct fb_info_control *) info;
433 if (regno > 255)
434 return 1;
435 *red = (p->palette[regno].red<<8) | p->palette[regno].red;
436 *green = (p->palette[regno].green<<8) | p->palette[regno].green;
437 *blue = (p->palette[regno].blue<<8) | p->palette[regno].blue;
438 *transp = 0;
439 return 0;
442 static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
443 u_int transp, struct fb_info *info)
445 struct fb_info_control *p = (struct fb_info_control *) info;
446 u_int i;
447 __u8 r, g, b;
449 if (regno > 255)
450 return 1;
452 r = red >> 8;
453 g = green >> 8;
454 b = blue >> 8;
456 p->palette[regno].red = r;
457 p->palette[regno].green = g;
458 p->palette[regno].blue = b;
460 out_8(&p->cmap_regs->addr, regno); /* tell clut what addr to fill */
461 out_8(&p->cmap_regs->lut, r); /* send one color channel at */
462 out_8(&p->cmap_regs->lut, g); /* a time... */
463 out_8(&p->cmap_regs->lut, b);
465 if (regno < 16)
466 switch (p->par.cmode) {
467 #ifdef FBCON_HAS_CFB16
468 case CMODE_16:
469 p->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | regno;
470 break;
471 #endif
472 #ifdef FBCON_HAS_CFB32
473 case CMODE_32:
474 i = (regno << 8) | regno;
475 p->fbcon_cmap.cfb32[regno] = (i << 16) | i;
476 break;
477 #endif
479 return 0;
482 static void do_install_cmap(int con, struct fb_info *info)
484 if (con != currcon)
485 return;
486 if (fb_display[con].cmap.len)
487 fb_set_cmap(&fb_display[con].cmap, 1, controlfb_setcolreg,
488 info);
489 else {
490 int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
491 fb_set_cmap(fb_default_cmap(size), 1, controlfb_setcolreg,
492 info);
496 #ifdef CONFIG_FB_COMPAT_XPMAC
497 extern struct vc_mode display_info;
498 extern struct fb_info *console_fb_info;
499 #endif /* CONFIG_FB_COMPAT_XPMAC */
501 static inline int control_vram_reqd(int video_mode, int color_mode)
503 return (control_reg_init[video_mode-1]->vres
504 * control_reg_init[video_mode-1]->hres << color_mode)
505 + control_reg_init[video_mode-1]->offset[color_mode];
508 static void set_control_clock(unsigned char *params)
510 struct adb_request req;
511 int i;
513 for (i = 0; i < 3; ++i) {
514 cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
515 0x50, i + 1, params[i]);
516 while (!req.complete)
517 cuda_poll();
522 static void __init init_control(struct fb_info_control *p)
524 struct fb_par_control parstruct;
525 struct fb_par_control *par = &parstruct;
526 struct fb_var_screeninfo var;
528 p->sense = read_control_sense(p);
529 printk(KERN_INFO "Monitor sense value = 0x%x, ", p->sense);
530 /* Try to pick a video mode out of NVRAM if we have one. */
531 par->vmode = nvram_read_byte(NV_VMODE);
532 if(par->vmode <= 0 || par->vmode > VMODE_MAX || !control_reg_init[par->vmode - 1])
533 par->vmode = VMODE_CHOOSE;
534 if(par->vmode == VMODE_CHOOSE)
535 par->vmode = mac_map_monitor_sense(p->sense);
536 if(!control_reg_init[par->vmode - 1])
537 par->vmode = VMODE_640_480_60;
539 par->cmode = nvram_read_byte(NV_CMODE);
540 if(par->cmode < CMODE_8 || par->cmode > CMODE_32)
541 par->cmode = CMODE_8;
543 * Reduce the pixel size if we don't have enough VRAM.
545 while(par->cmode > CMODE_8 && control_vram_reqd(par->vmode, par->cmode) > p->total_vram)
546 par->cmode--;
548 printk("using video mode %d and color mode %d.\n", par->vmode, par->cmode);
550 par->vxres = par->xres = control_reg_init[par->vmode - 1]->hres;
551 par->yres = control_reg_init[par->vmode - 1]->vres;
552 par->vyres = p->total_vram / (par->vxres << par->cmode);
553 par->xoffset = par->yoffset = 0;
555 control_init_info(&p->info, p);
557 par_set = 1; /* Debug */
559 control_par_to_var(par, &var);
560 var.activate = FB_ACTIVATE_NOW;
561 control_set_var(&var, -1, &p->info);
563 p->info.flags = FBINFO_FLAG_DEFAULT;
564 if (register_framebuffer(&p->info) < 0) {
565 kfree(p);
566 return;
569 printk(KERN_INFO "fb%d: control display adapter\n", GET_FB_IDX(p->info.node));
572 #define STORE_D2(a,d) \
573 out_8(&p->cmap_regs->addr, (a)); \
574 out_8(&p->cmap_regs->d2, (d))
576 /* Now how about actually saying, Make it so! */
577 /* Some things in here probably don't need to be done each time. */
578 static void control_set_hardware(struct fb_info_control *p, struct fb_par_control *par)
580 struct control_regvals *init;
581 volatile struct preg *rp;
582 int flags, ctrl, i;
583 int vmode, cmode;
585 if(PAR_EQUAL(&p->par, par))
586 return;
588 p->par = *par;
590 vmode = p->par.vmode;
591 cmode = p->par.cmode;
593 init = control_reg_init[vmode - 1];
595 if (control_vram_reqd(vmode, cmode) > 0x200000)
596 flags = 0x51;
597 else if (p->control_use_bank2)
598 flags = 0x39;
599 else
600 flags = 0x31;
601 if (vmode >= VMODE_1280_960_75 && cmode >= CMODE_16)
602 ctrl = 0x7f;
603 else
604 ctrl = 0x3b;
606 /* Initialize display timing registers */
607 out_le32(&p->control_regs->ctrl.r, 0x43b);
609 set_control_clock(init->clock_params);
611 STORE_D2(0x20, init->radacal_ctrl[cmode]);
612 STORE_D2(0x21, p->control_use_bank2 ? 0 : 1);
613 STORE_D2(0x10, 0);
614 STORE_D2(0x11, 0);
616 rp = &p->control_regs->vswin;
617 for (i = 0; i < 16; ++i, ++rp)
618 out_le32(&rp->r, init->regs[i]);
620 out_le32(&p->control_regs->pitch.r, par->vxres << cmode);
621 out_le32(&p->control_regs->mode.r, init->mode[cmode]);
622 out_le32(&p->control_regs->flags.r, flags);
623 out_le32(&p->control_regs->start_addr.r,
624 par->yoffset * (par->vxres << cmode));
625 out_le32(&p->control_regs->reg18.r, 0x1e5);
626 out_le32(&p->control_regs->reg19.r, 0);
628 for (i = 0; i < 16; ++i) {
629 controlfb_setcolreg(color_table[i], default_red[i]<<8,
630 default_grn[i]<<8, default_blu[i]<<8,
631 0, (struct fb_info *)p);
633 /* Does the above need to be here each time? -- danj */
635 /* Turn on display */
636 out_le32(&p->control_regs->ctrl.r, ctrl);
638 #ifdef CONFIG_FB_COMPAT_XPMAC
639 /* And let the world know the truth. */
640 if (!console_fb_info || console_fb_info == &p->info) {
641 display_info.height = p->par.yres;
642 display_info.width = p->par.xres;
643 display_info.depth = (cmode == CMODE_32) ? 32 :
644 ((cmode == CMODE_16) ? 16 : 8);
645 display_info.pitch = p->par.vxres << p->par.cmode;
646 display_info.mode = vmode;
647 strncpy(display_info.name, "control",
648 sizeof(display_info.name));
649 display_info.fb_address = p->frame_buffer_phys
650 + control_reg_init[vmode-1]->offset[cmode];
651 display_info.cmap_adr_address = p->cmap_regs_phys;
652 display_info.cmap_data_address = p->cmap_regs_phys + 0x30;
653 display_info.disp_reg_address = p->control_regs_phys;
654 console_fb_info = &p->info;
656 #endif /* CONFIG_FB_COMPAT_XPMAC */
659 int __init control_init(void)
661 #ifndef CONFIG_FB_OF
662 struct device_node *dp;
664 dp = find_devices("control");
665 if (dp != 0)
666 control_of_init(dp);
667 #endif /* CONFIG_FB_OF */
668 return 0;
671 void __init control_of_init(struct device_node *dp)
673 struct fb_info_control *p;
674 unsigned long addr, size;
675 int i, bank1, bank2;
677 if(dp->n_addrs != 2) {
678 printk(KERN_ERR "expecting 2 address for control (got %d)", dp->n_addrs);
679 return;
681 p = kmalloc(sizeof(*p), GFP_ATOMIC);
682 if (p == 0)
683 return;
684 memset(p, 0, sizeof(*p));
686 /* Map in frame buffer and registers */
687 for (i = 0; i < dp->n_addrs; ++i) {
688 addr = dp->addrs[i].address;
689 size = dp->addrs[i].size;
690 if (size >= 0x800000) {
691 /* use the big-endian aperture (??) */
692 addr += 0x800000;
693 /* map at most 8MB for the frame buffer */
694 p->frame_buffer_phys = addr;
695 p->frame_buffer = __ioremap(addr, 0x800000, _PAGE_WRITETHRU);
696 } else {
697 p->control_regs_phys = addr;
698 p->control_regs = ioremap(addr, size);
701 p->cmap_regs_phys = 0xf301b000; /* XXX not in prom? */
702 p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000);
704 /* Work out which banks of VRAM we have installed. */
705 /* danj: I guess the card just ignores writes to nonexistant VRAM... */
706 out_8(&p->frame_buffer[0], 0x5a);
707 out_8(&p->frame_buffer[1], 0xc7);
708 asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0]) : "memory" );
709 bank1 = (in_8(&p->frame_buffer[0]) == 0x5a) && (in_8(&p->frame_buffer[1]) == 0xc7);
711 out_8(&p->frame_buffer[0x600000], 0xa5);
712 out_8(&p->frame_buffer[0x600001], 0x38);
713 asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x600000]) : "memory" );
714 bank2 = (in_8(&p->frame_buffer[0x600000]) == 0xa5)
715 && (in_8(&p->frame_buffer[0x600001]) == 0x38);
717 p->total_vram = (bank1 + bank2) * 0x200000;
718 /* If we don't have bank 1 installed, we hope we have bank 2 :-) */
719 p->control_use_bank2 = !bank1;
720 if (p->control_use_bank2) {
721 p->frame_buffer += 0x600000;
722 p->frame_buffer_phys += 0x600000;
725 init_control(p);
729 * Get the monitor sense value.
730 * Note that this can be called before calibrate_delay,
731 * so we can't use udelay.
733 static int read_control_sense(struct fb_info_control *p)
735 int sense;
737 out_le32(&p->control_regs->mon_sense.r, 7); /* drive all lines high */
738 __delay(200);
739 out_le32(&p->control_regs->mon_sense.r, 077); /* turn off drivers */
740 __delay(2000);
741 sense = (in_le32(&p->control_regs->mon_sense.r) & 0x1c0) << 2;
743 /* drive each sense line low in turn and collect the other 2 */
744 out_le32(&p->control_regs->mon_sense.r, 033); /* drive A low */
745 __delay(2000);
746 sense |= (in_le32(&p->control_regs->mon_sense.r) & 0xc0) >> 2;
747 out_le32(&p->control_regs->mon_sense.r, 055); /* drive B low */
748 __delay(2000);
749 sense |= ((in_le32(&p->control_regs->mon_sense.r) & 0x100) >> 5)
750 | ((in_le32(&p->control_regs->mon_sense.r) & 0x40) >> 4);
751 out_le32(&p->control_regs->mon_sense.r, 066); /* drive C low */
752 __delay(2000);
753 sense |= (in_le32(&p->control_regs->mon_sense.r) & 0x180) >> 7;
755 out_le32(&p->control_regs->mon_sense.r, 077); /* turn off drivers */
757 return sense;
760 /*********************** Various translation functions ***********************/
761 #if 1
762 /* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */
763 static int control_var_to_par(struct fb_var_screeninfo *var,
764 struct fb_par_control *par, const struct fb_info *fb_info)
766 int xres = var->xres;
767 int yres = var->yres;
768 int bpp = var->bits_per_pixel;
769 struct fb_info_control *p = (struct fb_info_control *) fb_info;
772 * Get the video params out of 'var'. If a value doesn't fit, round it up,
773 * if it's too big, return -EINVAL.
775 * Suggestion: Round up in the following order: bits_per_pixel, xres,
776 * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
777 * bitfields, horizontal timing, vertical timing.
779 /* swiped by jonh from atyfb.c */
780 if (xres <= 512 && yres <= 384)
781 par->vmode = VMODE_512_384_60; /* 512x384, 60Hz */
782 else if (xres <= 640 && yres <= 480)
783 par->vmode = VMODE_640_480_67; /* 640x480, 67Hz */
784 else if (xres <= 640 && yres <= 870)
785 par->vmode = VMODE_640_870_75P; /* 640x870, 75Hz (portrait) */
786 else if (xres <= 768 && yres <= 576)
787 par->vmode = VMODE_768_576_50I; /* 768x576, 50Hz (PAL full frame) */
788 else if (xres <= 800 && yres <= 600)
789 par->vmode = VMODE_800_600_75; /* 800x600, 75Hz */
790 else if (xres <= 832 && yres <= 624)
791 par->vmode = VMODE_832_624_75; /* 832x624, 75Hz */
792 else if (xres <= 1024 && yres <= 768)
793 par->vmode = VMODE_1024_768_75; /* 1024x768, 75Hz */
794 else if (xres <= 1152 && yres <= 870)
795 par->vmode = VMODE_1152_870_75; /* 1152x870, 75Hz */
796 else if (xres <= 1280 && yres <= 960)
797 par->vmode = VMODE_1280_960_75; /* 1280x960, 75Hz */
798 else if (xres <= 1280 && yres <= 1024)
799 par->vmode = VMODE_1280_1024_75; /* 1280x1024, 75Hz */
800 else {
801 printk(KERN_ERR "Bad x/y res in var_to_par\n");
802 return -EINVAL;
805 xres = control_reg_init[par->vmode-1]->hres;
806 yres = control_reg_init[par->vmode-1]->vres;
808 par->xres = xres;
809 par->yres = yres;
811 if (var->xres_virtual <= xres)
812 par->vxres = xres;
813 else if(var->xres_virtual > xres) {
814 par->vxres = xres;
815 } else /* NotReached at present */
816 par->vxres = (var->xres_virtual+7) & ~7;
818 if (var->yres_virtual <= yres)
819 par->vyres = yres;
820 else
821 par->vyres = var->yres_virtual;
823 if (var->xoffset > 0 || var->yoffset+yres > par->vyres) {
824 printk(KERN_ERR "Bad offsets in var_to_par\n");
825 return -EINVAL;
828 par->xoffset = (var->xoffset+7) & ~7;
829 par->yoffset = var->yoffset;
832 if (bpp <= 8)
833 par->cmode = CMODE_8;
834 else if (bpp <= 16)
835 par->cmode = CMODE_16;
836 else if (bpp <= 32)
837 par->cmode = CMODE_32;
838 else {
839 printk(KERN_ERR "Bad bpp in var_to_par\n");
840 return -EINVAL;
843 if (control_vram_reqd(par->vmode, par->cmode) > p->total_vram) {
844 printk(KERN_ERR "Too much VRAM required for vmode %d cmode %d.\n", par->vmode, par->cmode);
845 return -EINVAL;
848 /* Check if we know about the wanted video mode */
849 if (control_reg_init[par->vmode - 1] == NULL) {
850 printk(KERN_ERR "init is null in control_var_to_par().\n");
851 /* I'm not sure if control has any specific requirements -- */
852 /* if we have a regvals struct, we're good to go? */
853 return -EINVAL;
856 return 0;
858 #else
859 /* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */
860 static int control_var_to_par(struct fb_var_screeninfo *var,
861 struct fb_par_control *par, const struct fb_info *fb_info)
863 struct fb_info_control *p = (struct fb_info_control *) fb_info;
865 if(mac_var_to_vmode(var, &par->vmode, &par->cmode) != 0)
866 return -EINVAL;
867 par->xres = par->vxres = vmode_attrs[par->vmode - 1].hres;
868 par->yres = par->vyres = vmode_attrs[par->vmode - 1].vres;
869 par->xoffset = par->yoffset = 0;
871 if (control_vram_reqd(par->vmode, par->cmode) > p->total_vram)
872 return -EINVAL;
874 /* Check if we know about the wanted video mode */
875 if(!control_reg_init[par->vmode-1]) {
876 /* I'm not sure if control has any specific requirements -- */
877 /* if we have a regvals struct, we're good to go? */
878 return -EINVAL;
880 return 0;
882 #endif
884 /*********** Convert hardware data in par to an fb_var_screeninfo ***********/
886 static void control_par_to_var(struct fb_par_control *par, struct fb_var_screeninfo *var)
888 struct control_regints *rv;
890 rv = (struct control_regints *) control_reg_init[par->vmode - 1]->regs;
892 memset(var, 0, sizeof(*var));
893 var->xres = control_reg_init[par->vmode - 1]->hres;
894 var->yres = control_reg_init[par->vmode - 1]->vres;
895 var->xres_virtual = par->vxres;
896 var->yres_virtual = par->vyres;
897 var->xoffset = par->xoffset;
898 var->yoffset = par->yoffset;
899 var->grayscale = 0;
901 if(par->cmode != CMODE_8 && par->cmode != CMODE_16 && par->cmode != CMODE_32) {
902 printk(KERN_ERR "Bad color mode in control_par_to_var()!\n");
903 par->cmode = CMODE_8;
905 switch(par->cmode) {
906 case CMODE_8:
907 var->bits_per_pixel = 8;
908 var->red.offset = 0;
909 var->red.length = 8;
910 var->green.offset = 0;
911 var->green.length = 8;
912 var->blue.offset = 0;
913 var->blue.length = 8;
914 var->transp.offset = 0;
915 var->transp.length = 0;
916 break;
917 case CMODE_16: /* RGB 555 */
918 var->bits_per_pixel = 16;
919 var->red.offset = 10;
920 var->red.length = 5;
921 var->green.offset = 5;
922 var->green.length = 5;
923 var->blue.offset = 0;
924 var->blue.length = 5;
925 var->transp.offset = 0;
926 var->transp.length = 0;
927 break;
928 case CMODE_32: /* RGB 888 */
929 var->bits_per_pixel = 32;
930 var->red.offset = 16;
931 var->red.length = 8;
932 var->green.offset = 8;
933 var->green.length = 8;
934 var->blue.offset = 0;
935 var->blue.length = 8;
936 var->transp.offset = 24;
937 var->transp.length = 8;
938 break;
940 var->red.msb_right = 0;
941 var->green.msb_right = 0;
942 var->blue.msb_right = 0;
943 var->transp.msb_right = 0;
944 var->nonstd = 0;
945 var->activate = 0;
946 var->height = -1;
947 var->width = -1;
948 var->vmode = FB_VMODE_NONINTERLACED;
950 var->left_margin = (rv->heblank - rv->hesync)
951 << ((par->vmode > 18) ? 2 : 1);
952 var->right_margin = (rv->hssync - rv->hsblank)
953 << ((par->vmode > 18) ? 2 : 1);
954 var->hsync_len = (rv->hperiod + 2 - rv->hssync + rv->hesync)
955 << ((par->vmode > 18) ? 2 : 1);
957 var->upper_margin = (rv->veblank - rv->vesync) >> 1;
958 var->lower_margin = (rv->vssync - rv->vsblank) >> 1;
959 var->vsync_len = (rv->vperiod - rv->vssync + rv->vesync) >> 1;
961 /* Acording to macmodes.c... */
962 if((par->vmode >= 9 && par->vmode <= 12) ||
963 (par->vmode >= 16 && par->vmode <= 18) ||
964 (par->vmode == 20))
966 var->sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT;
967 } else {
968 var->sync = 0; /* I suppose */
971 /* The reason these are both here: with my revised margin calculations, */
972 /* these SHOULD both give the same answer for each mode. Some day I */
973 /* will sit down and check the rest. Works perfectly for vmode 13. */
975 #if 0
976 /* jonh's pixclocks...*/
977 /* no long long support in the kernel :-( */
978 /* this splittig trick will work if xres > 232 */
979 var->pixclock = 1000000000/
980 (var->left_margin+var->xres+var->right_margin+var->hsync_len);
981 var->pixclock *= 1000;
982 var->pixclock /= vmode_attrs[par->vmode-1].vfreq*
983 (var->upper_margin+var->yres+var->lower_margin+var->vsync_len);
984 #else
985 /* danj's */
986 /* 10^12 * clock_params[0] / (3906400 * clock_params[1] * 2^clock_params[2]) */
987 /* (10^12 * clock_params[0] / (3906400 * clock_params[1])) >> clock_params[2] */
988 /* (255990.17 * clock_params[0] / clock_params[1]) >> clock_params[2] */
989 var->pixclock = 255990 * control_reg_init[par->vmode-1]->clock_params[0];
990 var->pixclock /= control_reg_init[par->vmode-1]->clock_params[1];
991 var->pixclock >>= control_reg_init[par->vmode-1]->clock_params[2];
992 #endif
995 static void control_par_to_fix(struct fb_par_control *par, struct fb_fix_screeninfo *fix,
996 struct fb_info_control *p)
998 memset(fix, 0, sizeof(*fix));
999 strcpy(fix->id, "control");
1000 fix->mmio_start = p->control_regs_phys;
1001 fix->mmio_len = sizeof(struct control_regs);
1002 fix->type = FB_TYPE_PACKED_PIXELS;
1004 fix->ypanstep = 1;
1006 fix->type_aux = 0;
1007 fix->ywrapstep = 0;
1008 fix->ypanstep = 0;
1009 fix->xpanstep = 0;
1012 fix->smem_start = (p->frame_buffer_phys
1013 + control_reg_init[par->vmode-1]->offset[par->cmode]);
1014 fix->smem_len = p->total_vram - control_reg_init[par->vmode-1]->offset[par->cmode];
1015 fix->visual = (par->cmode == CMODE_8) ?
1016 FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
1017 fix->line_length = par->vxres << par->cmode;
1020 /* We never initialize any display except for p->disp.
1021 And p->disp is already memset to 0. So no memset here.
1022 [Found by Takashi Oe]
1024 static void control_par_to_display(struct fb_par_control *par,
1025 struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_control *p)
1027 /* memset(disp, 0, sizeof(*disp)); */
1028 disp->type = fix->type;
1029 disp->can_soft_blank = 1;
1030 disp->scrollmode = SCROLL_YNOMOVE | SCROLL_YNOPARTIAL;
1031 disp->ypanstep = fix->ypanstep;
1032 disp->ywrapstep = fix->ywrapstep;
1033 #if 0
1034 disp->type_aux = fix->type_aux;
1035 disp->cmap.red = NULL; /* ??? danj */
1036 disp->cmap.green = NULL;
1037 disp->cmap.blue = NULL;
1038 disp->cmap.transp = NULL;
1039 /* Yeah, I realize I just set 0 = 0. */
1040 #endif
1042 control_par_to_var(par, &disp->var);
1043 disp->screen_base = (char *) p->frame_buffer
1044 + control_reg_init[par->vmode-1]->offset[par->cmode];
1045 disp->visual = fix->visual;
1046 disp->line_length = fix->line_length;
1047 control_set_dispsw(disp, par->cmode, p);
1050 static void control_cfb16_revc(struct display *p, int xx, int yy)
1052 u8 *dest;
1053 int bytes = p->next_line, rows;
1055 dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p)*2;
1056 for (rows = fontheight(p); rows--; dest += bytes) {
1057 switch (fontwidth(p)) {
1058 case 16:
1059 ((u32 *)dest)[6] ^= 0x3def3def; ((u32 *)dest)[7] ^= 0x3def3def;
1060 /* FALL THROUGH */
1061 case 12:
1062 ((u32 *)dest)[4] ^= 0x3def3def; ((u32 *)dest)[5] ^= 0x3def3def;
1063 /* FALL THROUGH */
1064 case 8:
1065 ((u32 *)dest)[2] ^= 0x3def3def; ((u32 *)dest)[3] ^= 0x3def3def;
1066 /* FALL THROUGH */
1067 case 4:
1068 ((u32 *)dest)[0] ^= 0x3def3def; ((u32 *)dest)[1] ^= 0x3def3def;
1073 static void control_cfb32_revc(struct display *p, int xx, int yy)
1075 u8 *dest;
1076 int bytes = p->next_line, rows;
1078 dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 4;
1079 for (rows = fontheight(p); rows--; dest += bytes) {
1080 switch (fontwidth(p)) {
1081 case 16:
1082 ((u32 *)dest)[12] ^= 0x0f0f0f0f; ((u32 *)dest)[13] ^= 0x0f0f0f0f;
1083 ((u32 *)dest)[14] ^= 0x0f0f0f0f; ((u32 *)dest)[15] ^= 0x0f0f0f0f;
1084 /* FALL THROUGH */
1085 case 12:
1086 ((u32 *)dest)[8] ^= 0x0f0f0f0f; ((u32 *)dest)[9] ^= 0x0f0f0f0f;
1087 ((u32 *)dest)[10] ^= 0x0f0f0f0f; ((u32 *)dest)[11] ^= 0x0f0f0f0f;
1088 /* FALL THROUGH */
1089 case 8:
1090 ((u32 *)dest)[4] ^= 0x0f0f0f0f; ((u32 *)dest)[5] ^= 0x0f0f0f0f;
1091 ((u32 *)dest)[6] ^= 0x0f0f0f0f; ((u32 *)dest)[7] ^= 0x0f0f0f0f;
1092 /* FALL THROUGH */
1093 case 4:
1094 ((u32 *)dest)[0] ^= 0x0f0f0f0f; ((u32 *)dest)[1] ^= 0x0f0f0f0f;
1095 ((u32 *)dest)[2] ^= 0x0f0f0f0f; ((u32 *)dest)[3] ^= 0x0f0f0f0f;
1096 /* FALL THROUGH */
1101 static struct display_switch control_cfb16 = {
1102 fbcon_cfb16_setup, fbcon_cfb16_bmove, fbcon_cfb16_clear, fbcon_cfb16_putc,
1103 fbcon_cfb16_putcs, control_cfb16_revc, NULL, NULL, fbcon_cfb16_clear_margins,
1104 FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1107 static struct display_switch control_cfb32 = {
1108 fbcon_cfb32_setup, fbcon_cfb32_bmove, fbcon_cfb32_clear, fbcon_cfb32_putc,
1109 fbcon_cfb32_putcs, control_cfb32_revc, NULL, NULL, fbcon_cfb32_clear_margins,
1110 FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1114 static void control_set_dispsw(struct display *disp, int cmode, struct fb_info_control *p)
1116 switch (cmode) {
1117 #ifdef FBCON_HAS_CFB8
1118 case CMODE_8:
1119 disp->dispsw = &fbcon_cfb8;
1120 break;
1121 #endif
1122 #ifdef FBCON_HAS_CFB16
1123 case CMODE_16:
1124 disp->dispsw = &control_cfb16;
1125 disp->dispsw_data = p->fbcon_cmap.cfb16;
1126 break;
1127 #endif
1128 #ifdef FBCON_HAS_CFB32
1129 case CMODE_32:
1130 disp->dispsw = &control_cfb32;
1131 disp->dispsw_data = p->fbcon_cmap.cfb32;
1132 break;
1133 #endif
1134 default:
1135 disp->dispsw = &fbcon_dummy;
1136 break;
1140 static void control_init_info(struct fb_info *info, struct fb_info_control *p)
1142 strcpy(info->modename, "control");
1143 info->node = -1; /* ??? danj */
1144 info->fbops = &controlfb_ops;
1145 info->disp = &p->display;
1146 strcpy(info->fontname, fontname);
1147 info->changevar = NULL;
1148 info->switch_con = &controlfb_switch;
1149 info->updatevar = &controlfb_updatevar;
1150 info->blank = &controlfb_blank;
1153 /* Parse user speficied options (`video=controlfb:') */
1154 void __init control_setup(char *options)
1156 char *this_opt;
1158 if (!options || !*options)
1159 return;
1161 for (this_opt = strtok(options, ","); this_opt;
1162 this_opt = strtok(NULL, ",")) {
1163 if (!strncmp(this_opt, "font:", 5)) {
1164 char *p;
1165 int i;
1167 p = this_opt +5;
1168 for (i = 0; i < sizeof(fontname) - 1; i++)
1169 if (!*p || *p == ' ' || *p == ',')
1170 break;
1171 memcpy(fontname, this_opt + 5, i);
1172 fontname[i] = 0;
1174 if (!strncmp(this_opt, "vmode:", 6)) {
1175 int vmode = simple_strtoul(this_opt+6, NULL, 0);
1176 if (vmode > 0 && vmode <= VMODE_MAX)
1177 default_vmode = vmode;
1178 } else if (!strncmp(this_opt, "cmode:", 6)) {
1179 int depth = simple_strtoul(this_opt+6, NULL, 0);
1180 switch (depth) {
1181 case CMODE_8:
1182 case CMODE_16:
1183 case CMODE_32:
1184 default_cmode = depth;
1185 break;
1186 case 8:
1187 default_cmode = CMODE_8;
1188 break;
1189 case 15:
1190 case 16:
1191 default_cmode = CMODE_16;
1192 break;
1193 case 24:
1194 case 32:
1195 default_cmode = CMODE_32;
1196 break;
1202 #if 0
1203 static int controlfb_pan_display(struct fb_var_screeninfo *var,
1204 struct controlfb_par *par,
1205 const struct fb_info *fb_info)
1208 * Pan (or wrap, depending on the `vmode' field) the display using the
1209 * `xoffset' and `yoffset' fields of the `var' structure.
1210 * If the values don't fit, return -EINVAL.
1213 FUNCID;
1215 return 0;
1218 #endif