Ok. I didn't make 2.4.0 in 2000. Tough. I tried, but we had some
[davej-history.git] / drivers / video / controlfb.c
blobfe64ab9a143c1ebc55e251242d3c1cd5f074ca2b
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 <linux/adb.h>
47 #include <linux/cuda.h>
48 #include <asm/io.h>
49 #include <asm/prom.h>
50 #include <asm/pgtable.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_get_fix(struct fb_fix_screeninfo *fix, int con,
114 struct fb_info *info);
115 static int control_get_var(struct fb_var_screeninfo *var, int con,
116 struct fb_info *info);
117 static int control_set_var(struct fb_var_screeninfo *var, int con,
118 struct fb_info *info);
119 static int control_pan_display(struct fb_var_screeninfo *var, int con,
120 struct fb_info *info);
121 static int control_get_cmap(struct fb_cmap *cmap, int kspc, int con,
122 struct fb_info *info);
123 static int control_set_cmap(struct fb_cmap *cmap, int kspc, int con,
124 struct fb_info *info);
125 static int control_mmap(struct fb_info *info, struct file *file,
126 struct vm_area_struct *vma);
129 static int controlfb_getcolreg(u_int regno, u_int *red, u_int *green,
130 u_int *blue, u_int *transp, struct fb_info *info);
131 static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
132 u_int transp, struct fb_info *info);
134 /******************** Prototypes for internal functions ********************/
135 static void control_par_to_fix(struct fb_par_control *par, struct fb_fix_screeninfo *fix,
136 struct fb_info_control *p);
137 static void do_install_cmap(int con, struct fb_info *info);
138 static void control_set_dispsw(struct display *disp, int cmode, struct fb_info_control *p);
140 /************************* Internal variables *****************************/
141 static int currcon = 0;
142 static int par_set = 0;
143 static char fontname[40] __initdata = { 0 };
144 static int default_vmode = VMODE_NVRAM;
145 static int default_cmode = CMODE_NVRAM;
148 * Exported functions
150 int control_init(void);
151 void control_setup(char *);
153 static void control_of_init(struct device_node *dp);
154 static int read_control_sense(struct fb_info_control *p);
155 static inline int control_vram_reqd(int video_mode, int color_mode);
156 static void set_control_clock(unsigned char *params);
157 static void control_set_hardware(struct fb_info_control *p, struct fb_par_control *par);
158 static inline void control_par_to_var(struct fb_par_control *par, struct fb_var_screeninfo *var);
159 static int control_var_to_par(struct fb_var_screeninfo *var,
160 struct fb_par_control *par, const struct fb_info *fb_info);
162 static void control_init_info(struct fb_info *info, struct fb_info_control *p);
163 static void control_par_to_display(struct fb_par_control *par,
164 struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_control *p);
166 static int controlfb_updatevar(int con, struct fb_info *info);
168 static struct fb_ops controlfb_ops = {
169 owner: THIS_MODULE,
170 fb_get_fix: control_get_fix,
171 fb_get_var: control_get_var,
172 fb_set_var: control_set_var,
173 fb_get_cmap: control_get_cmap,
174 fb_set_cmap: control_set_cmap,
175 fb_pan_display: control_pan_display,
176 fb_mmap: control_mmap,
181 /******************** The functions for controlfb_ops ********************/
183 #ifdef MODULE
184 int init_module(void)
186 struct device_node *dp;
188 printk("Loading...\n");
189 dp = find_devices("control");
190 if (dp != 0)
191 control_of_init(dp);
192 else
193 printk("Failed.\n");
194 printk("Done.\n");
197 void cleanup_module(void)
199 /* FIXME: clean up and release regions */
201 #endif
203 /*********** Providing our information to the user ************/
205 static int control_get_fix(struct fb_fix_screeninfo *fix, int con,
206 struct fb_info *info)
208 struct fb_info_control *p = (struct fb_info_control *) info;
210 if(!par_set)
211 printk(KERN_ERR "control_get_fix called with unset par!\n");
212 if(con == -1) {
213 control_par_to_fix(&p->par, fix, p);
214 } else {
215 struct fb_par_control par;
217 control_var_to_par(&fb_display[con].var, &par, info);
218 control_par_to_fix(&par, fix, p);
220 return 0;
223 static int control_get_var(struct fb_var_screeninfo *var, 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_var called with unset par!\n");
230 if(con == -1) {
231 control_par_to_var(&p->par, var);
232 } else {
233 *var = fb_display[con].var;
235 return 0;
238 /* Sets everything according to var */
239 /* No longer safe for use in console switching */
240 static int control_set_var(struct fb_var_screeninfo *var, int con,
241 struct fb_info *info)
243 struct fb_info_control *p = (struct fb_info_control *) info;
244 struct display *disp;
245 struct fb_par_control par;
246 int depthchange, err;
247 int activate = var->activate;
249 disp = (con >= 0) ? &fb_display[con] : info->disp;
251 if((err = control_var_to_par(var, &par, info))) {
252 printk (KERN_ERR "control_set_var: error calling control_var_to_par: %d.\n", err);
253 return err;
256 control_par_to_var(&par, var);
258 if ((activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
259 return 0;
261 /* I know, we want to use fb_display[con], but grab certain info from p->var instead. */
262 /* [above no longer true] */
263 depthchange = (disp->var.bits_per_pixel != var->bits_per_pixel);
264 if(!VAR_MATCH(&disp->var, var)) {
265 struct fb_fix_screeninfo fix;
266 control_par_to_fix(&par, &fix, p);
267 control_par_to_display(&par, disp, &fix, p);
268 if(info->changevar)
269 (*info->changevar)(con);
270 } else
271 disp->var = *var;
272 /*p->disp = *disp;*/
275 if(con == currcon || con == -1) {
276 control_set_hardware(p, &par);
278 if(depthchange) {
279 if((err = fb_alloc_cmap(&disp->cmap, 0, 0)))
280 return err;
281 do_install_cmap(con, info);
283 return 0;
286 static int control_pan_display(struct fb_var_screeninfo *var, int con,
287 struct fb_info *info)
289 struct fb_info_control *p = (struct fb_info_control *)info;
290 struct fb_par_control *par = &p->par;
292 if (var->xoffset != 0 || var->yoffset+var->yres > var->yres_virtual)
293 return -EINVAL;
294 fb_display[con].var.yoffset = par->yoffset = var->yoffset;
295 if(con == currcon)
296 out_le32(&p->control_regs->start_addr.r,
297 par->yoffset * (par->vxres << par->cmode));
298 return 0;
301 static int control_get_cmap(struct fb_cmap *cmap, int kspc, int con,
302 struct fb_info *info)
304 if (con == currcon) /* current console? */
305 return fb_get_cmap(cmap, kspc, controlfb_getcolreg, info);
306 if (fb_display[con].cmap.len) /* non default colormap? */
307 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0: 2);
308 else {
309 int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
310 fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
312 return 0;
315 static int control_set_cmap(struct fb_cmap *cmap, int kspc, int con,
316 struct fb_info *info)
318 struct display *disp = &fb_display[con];
319 int err;
321 if (disp->cmap.len == 0) {
322 int size = disp->var.bits_per_pixel == 16 ? 32 : 256;
323 err = fb_alloc_cmap(&disp->cmap, size, 0);
324 if (err)
325 return err;
327 if (con == currcon)
328 return fb_set_cmap(cmap, kspc, controlfb_setcolreg, info);
329 fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
330 return 0;
333 /* Private mmap since we want to have a different caching on the framebuffer
334 * for controlfb.
335 * Note there's no locking in here; it's done in fb_mmap() in fbmem.c.
337 static int control_mmap(struct fb_info *info, struct file *file,
338 struct vm_area_struct *vma)
340 struct fb_ops *fb = info->fbops;
341 struct fb_fix_screeninfo fix;
342 struct fb_var_screeninfo var;
343 unsigned long off, start;
344 u32 len;
346 fb->fb_get_fix(&fix, PROC_CONSOLE(info), info);
347 off = vma->vm_pgoff << PAGE_SHIFT;
349 /* frame buffer memory */
350 start = fix.smem_start;
351 len = PAGE_ALIGN((start & ~PAGE_MASK)+fix.smem_len);
352 if (off >= len) {
353 /* memory mapped io */
354 off -= len;
355 fb->fb_get_var(&var, PROC_CONSOLE(info), info);
356 if (var.accel_flags)
357 return -EINVAL;
358 start = fix.mmio_start;
359 len = PAGE_ALIGN((start & ~PAGE_MASK)+fix.mmio_len);
360 pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED;
361 } else {
362 /* framebuffer */
363 pgprot_val(vma->vm_page_prot) |= _PAGE_WRITETHRU;
365 start &= PAGE_MASK;
366 vma->vm_pgoff = off >> PAGE_SHIFT;
367 if (io_remap_page_range(vma->vm_start, off,
368 vma->vm_end - vma->vm_start, vma->vm_page_prot))
369 return -EAGAIN;
371 return 0;
375 /******************** End of controlfb_ops implementation ********************/
376 /* (new one that is) */
379 static int controlfb_switch(int con, struct fb_info *info)
381 struct fb_info_control *p = (struct fb_info_control *)info;
382 struct fb_par_control par;
383 int oldcon = currcon;
385 if (fb_display[currcon].cmap.len)
386 fb_get_cmap(&fb_display[currcon].cmap, 1, controlfb_getcolreg,
387 info);
388 currcon = con;
390 control_var_to_par(&fb_display[con].var, &par, info);
391 control_set_hardware(p, &par);
392 control_set_dispsw(&fb_display[con], par.cmode, p);
394 if(fb_display[oldcon].var.yoffset != fb_display[con].var.yoffset)
395 controlfb_updatevar(con, info);
397 do_install_cmap(con, info);
398 return 1;
401 static int controlfb_updatevar(int con, struct fb_info *info)
403 struct fb_info_control *p = (struct fb_info_control *)info;
405 if(con != currcon)
406 return 0;
407 /* imsttfb blanks the unused bottom of the screen here...hmm. */
408 out_le32(&p->control_regs->start_addr.r,
409 fb_display[con].var.yoffset * fb_display[con].line_length);
411 return 0;
414 static void controlfb_blank(int blank_mode, struct fb_info *info)
417 * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
418 * then the caller blanks by setting the CLUT (Color Look Up Table) to all
419 * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
420 * to e.g. a video mode which doesn't support it. Implements VESA suspend
421 * and powerdown modes on hardware that supports disabling hsync/vsync:
422 * blank_mode == 2: suspend vsync
423 * blank_mode == 3: suspend hsync
424 * blank_mode == 4: powerdown
426 /* A blank_mode of 1+VESA_NO_BLANKING or 1+VESA_POWERDOWN act alike... */
427 struct fb_info_control *p = (struct fb_info_control *) info;
428 int ctrl;
430 if(blank_mode == 1+VESA_NO_BLANKING)
431 blank_mode = 1+VESA_POWERDOWN;
432 ctrl = ld_le32(&p->control_regs->ctrl.r) | 0x33;
433 if (blank_mode)
434 --blank_mode;
435 if (blank_mode & VESA_VSYNC_SUSPEND)
436 ctrl &= ~3;
437 if (blank_mode & VESA_HSYNC_SUSPEND)
438 ctrl &= ~0x30;
439 out_le32(&p->control_regs->ctrl.r, ctrl);
441 /* TODO: Figure out how the heck to powerdown this thing! */
443 return;
446 static int controlfb_getcolreg(u_int regno, u_int *red, u_int *green,
447 u_int *blue, u_int *transp, struct fb_info *info)
449 struct fb_info_control *p = (struct fb_info_control *) info;
451 if (regno > 255)
452 return 1;
453 *red = (p->palette[regno].red<<8) | p->palette[regno].red;
454 *green = (p->palette[regno].green<<8) | p->palette[regno].green;
455 *blue = (p->palette[regno].blue<<8) | p->palette[regno].blue;
456 *transp = 0;
457 return 0;
460 static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
461 u_int transp, struct fb_info *info)
463 struct fb_info_control *p = (struct fb_info_control *) info;
464 u_int i;
465 __u8 r, g, b;
467 if (regno > 255)
468 return 1;
470 r = red >> 8;
471 g = green >> 8;
472 b = blue >> 8;
474 p->palette[regno].red = r;
475 p->palette[regno].green = g;
476 p->palette[regno].blue = b;
478 out_8(&p->cmap_regs->addr, regno); /* tell clut what addr to fill */
479 out_8(&p->cmap_regs->lut, r); /* send one color channel at */
480 out_8(&p->cmap_regs->lut, g); /* a time... */
481 out_8(&p->cmap_regs->lut, b);
483 if (regno < 16)
484 switch (p->par.cmode) {
485 #ifdef FBCON_HAS_CFB16
486 case CMODE_16:
487 p->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | regno;
488 break;
489 #endif
490 #ifdef FBCON_HAS_CFB32
491 case CMODE_32:
492 i = (regno << 8) | regno;
493 p->fbcon_cmap.cfb32[regno] = (i << 16) | i;
494 break;
495 #endif
497 return 0;
500 static void do_install_cmap(int con, struct fb_info *info)
502 if (con != currcon)
503 return;
504 if (fb_display[con].cmap.len)
505 fb_set_cmap(&fb_display[con].cmap, 1, controlfb_setcolreg,
506 info);
507 else {
508 int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
509 fb_set_cmap(fb_default_cmap(size), 1, controlfb_setcolreg,
510 info);
514 static inline int control_vram_reqd(int video_mode, int color_mode)
516 return (control_reg_init[video_mode-1]->vres
517 * control_reg_init[video_mode-1]->hres << color_mode)
518 + control_reg_init[video_mode-1]->offset[color_mode];
521 static void set_control_clock(unsigned char *params)
523 struct adb_request req;
524 int i;
526 #ifdef CONFIG_ADB_CUDA
527 for (i = 0; i < 3; ++i) {
528 cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
529 0x50, i + 1, params[i]);
530 while (!req.complete)
531 cuda_poll();
533 #endif
537 static void __init init_control(struct fb_info_control *p)
539 struct fb_par_control parstruct;
540 struct fb_par_control *par = &parstruct;
541 struct fb_var_screeninfo var;
543 p->sense = read_control_sense(p);
544 printk(KERN_INFO "Monitor sense value = 0x%x, ", p->sense);
545 /* Try to pick a video mode out of NVRAM if we have one. */
546 if (default_vmode == VMODE_NVRAM) {
547 par->vmode = nvram_read_byte(NV_VMODE);
548 if(par->vmode <= 0 || par->vmode > VMODE_MAX || !control_reg_init[par->vmode - 1])
549 par->vmode = VMODE_CHOOSE;
550 if(par->vmode == VMODE_CHOOSE)
551 par->vmode = mac_map_monitor_sense(p->sense);
552 if(!control_reg_init[par->vmode - 1])
553 par->vmode = VMODE_640_480_60;
554 } else
555 par->vmode=default_vmode;
557 if (default_cmode == CMODE_NVRAM){
558 par->cmode = nvram_read_byte(NV_CMODE);
559 if(par->cmode < CMODE_8 || par->cmode > CMODE_32)
560 par->cmode = CMODE_8;}
561 else
562 par->cmode=default_cmode;
564 * Reduce the pixel size if we don't have enough VRAM.
566 while(par->cmode > CMODE_8 && control_vram_reqd(par->vmode, par->cmode) > p->total_vram)
567 par->cmode--;
569 printk("using video mode %d and color mode %d.\n", par->vmode, par->cmode);
571 par->vxres = par->xres = control_reg_init[par->vmode - 1]->hres;
572 par->yres = control_reg_init[par->vmode - 1]->vres;
573 par->vyres = p->total_vram / (par->vxres << par->cmode);
574 par->xoffset = par->yoffset = 0;
576 control_init_info(&p->info, p);
578 par_set = 1; /* Debug */
580 control_par_to_var(par, &var);
581 var.activate = FB_ACTIVATE_NOW;
582 control_set_var(&var, -1, &p->info);
584 p->info.flags = FBINFO_FLAG_DEFAULT;
585 if (register_framebuffer(&p->info) < 0) {
586 kfree(p);
587 return;
590 printk(KERN_INFO "fb%d: control display adapter\n", GET_FB_IDX(p->info.node));
593 #define STORE_D2(a,d) \
594 out_8(&p->cmap_regs->addr, (a)); \
595 out_8(&p->cmap_regs->d2, (d))
597 /* Now how about actually saying, Make it so! */
598 /* Some things in here probably don't need to be done each time. */
599 static void control_set_hardware(struct fb_info_control *p, struct fb_par_control *par)
601 struct control_regvals *init;
602 volatile struct preg *rp;
603 int flags, ctrl, i;
604 int vmode, cmode;
606 if(PAR_EQUAL(&p->par, par))
607 return;
609 p->par = *par;
611 vmode = p->par.vmode;
612 cmode = p->par.cmode;
614 init = control_reg_init[vmode - 1];
616 if (control_vram_reqd(vmode, cmode) > 0x200000)
617 flags = 0x51;
618 else if (p->control_use_bank2)
619 flags = 0x39;
620 else
621 flags = 0x31;
622 if (vmode >= VMODE_1280_960_75 && cmode >= CMODE_16)
623 ctrl = 0x7f;
624 else
625 ctrl = 0x3b;
627 /* Initialize display timing registers */
628 out_le32(&p->control_regs->ctrl.r, 0x43b);
630 set_control_clock(init->clock_params);
632 STORE_D2(0x20, init->radacal_ctrl[cmode]);
633 STORE_D2(0x21, p->control_use_bank2 ? 0 : 1);
634 STORE_D2(0x10, 0);
635 STORE_D2(0x11, 0);
637 rp = &p->control_regs->vswin;
638 for (i = 0; i < 16; ++i, ++rp)
639 out_le32(&rp->r, init->regs[i]);
641 out_le32(&p->control_regs->pitch.r, par->vxres << cmode);
642 out_le32(&p->control_regs->mode.r, init->mode[cmode]);
643 out_le32(&p->control_regs->flags.r, flags);
644 out_le32(&p->control_regs->start_addr.r,
645 par->yoffset * (par->vxres << cmode));
646 out_le32(&p->control_regs->reg18.r, 0x1e5);
647 out_le32(&p->control_regs->reg19.r, 0);
649 for (i = 0; i < 16; ++i) {
650 controlfb_setcolreg(color_table[i], default_red[i]<<8,
651 default_grn[i]<<8, default_blu[i]<<8,
652 0, (struct fb_info *)p);
654 /* Does the above need to be here each time? -- danj */
656 /* Turn on display */
657 out_le32(&p->control_regs->ctrl.r, ctrl);
659 #ifdef CONFIG_FB_COMPAT_XPMAC
660 /* And let the world know the truth. */
661 if (!console_fb_info || console_fb_info == &p->info) {
662 display_info.height = p->par.yres;
663 display_info.width = p->par.xres;
664 display_info.depth = (cmode == CMODE_32) ? 32 :
665 ((cmode == CMODE_16) ? 16 : 8);
666 display_info.pitch = p->par.vxres << p->par.cmode;
667 display_info.mode = vmode;
668 strncpy(display_info.name, "control",
669 sizeof(display_info.name));
670 display_info.fb_address = p->frame_buffer_phys
671 + control_reg_init[vmode-1]->offset[cmode];
672 display_info.cmap_adr_address = p->cmap_regs_phys;
673 display_info.cmap_data_address = p->cmap_regs_phys + 0x30;
674 display_info.disp_reg_address = p->control_regs_phys;
675 console_fb_info = &p->info;
677 #endif /* CONFIG_FB_COMPAT_XPMAC */
680 int __init control_init(void)
682 struct device_node *dp;
684 dp = find_devices("control");
685 if (dp != 0)
686 control_of_init(dp);
687 return 0;
690 static void __init control_of_init(struct device_node *dp)
692 struct fb_info_control *p;
693 unsigned long addr, size;
694 int i, bank1, bank2;
696 if(dp->n_addrs != 2) {
697 printk(KERN_ERR "expecting 2 address for control (got %d)", dp->n_addrs);
698 return;
700 p = kmalloc(sizeof(*p), GFP_ATOMIC);
701 if (p == 0)
702 return;
703 memset(p, 0, sizeof(*p));
705 /* Map in frame buffer and registers */
706 for (i = 0; i < dp->n_addrs; ++i) {
707 addr = dp->addrs[i].address;
708 size = dp->addrs[i].size;
709 /* Let's assume we can request either all or nothing */
710 if (!request_mem_region(addr, size, "controlfb")) {
711 kfree(p);
712 return;
714 if (size >= 0x800000) {
715 /* use the big-endian aperture (??) */
716 addr += 0x800000;
717 /* map at most 8MB for the frame buffer */
718 p->frame_buffer_phys = addr;
719 p->frame_buffer = __ioremap(addr, 0x800000, _PAGE_WRITETHRU);
720 } else {
721 p->control_regs_phys = addr;
722 p->control_regs = ioremap(addr, size);
725 p->cmap_regs_phys = 0xf301b000; /* XXX not in prom? */
726 request_mem_region(p->cmap_regs_phys, 0x1000, "controlfb cmap");
727 p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000);
729 /* Work out which banks of VRAM we have installed. */
730 /* According to Andrew Fyfe <bandr@best.com>, the VRAM behaves like so: */
731 /* afyfe: observations from an 8500:
732 * - with 2M vram in bank 1, it appears at offsets 0, 2M and 4M
733 * - with 2M vram in bank 2, it appears only at offset 6M
734 * - with 4M vram, it appears only as a 4M block at offset 0.
737 /* We know there is something at 2M if there is something at 0M. */
738 out_8(&p->frame_buffer[0x200000], 0xa5);
739 out_8(&p->frame_buffer[0x200001], 0x38);
740 asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x200000]) : "memory" );
742 out_8(&p->frame_buffer[0], 0x5a);
743 out_8(&p->frame_buffer[1], 0xc7);
744 asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0]) : "memory" );
746 bank1 = (in_8(&p->frame_buffer[0x000000]) == 0x5a)
747 && (in_8(&p->frame_buffer[0x000001]) == 0xc7);
748 bank2 = (in_8(&p->frame_buffer[0x200000]) == 0xa5)
749 && (in_8(&p->frame_buffer[0x200001]) == 0x38);
751 if(bank2 && !bank1)
752 printk(KERN_INFO "controlfb: Found memory at 2MB but not at 0! Please contact dan@debian.org\n");
754 if(!bank1) {
755 out_8(&p->frame_buffer[0x600000], 0xa5);
756 out_8(&p->frame_buffer[0x600001], 0x38);
757 asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x600000]) : "memory" );
758 bank2 = (in_8(&p->frame_buffer[0x600000]) == 0xa5)
759 && (in_8(&p->frame_buffer[0x600001]) == 0x38);
760 /* If we don't have bank 1 installed, we hope we have bank 2 :-) */
761 p->control_use_bank2 = 1;
762 p->frame_buffer += 0x600000;
763 p->frame_buffer_phys += 0x600000;
766 p->total_vram = (bank1 + bank2) * 0x200000;
768 printk(KERN_INFO "controlfb: Memory bank 1 %s, bank 2 %s, total VRAM %dMB\n",
769 bank1 ? "present" : "absent", bank2 ? "present" : "absent",
770 2 * (bank1 + bank2));
772 init_control(p);
776 * Get the monitor sense value.
777 * Note that this can be called before calibrate_delay,
778 * so we can't use udelay.
780 static int read_control_sense(struct fb_info_control *p)
782 int sense;
784 out_le32(&p->control_regs->mon_sense.r, 7); /* drive all lines high */
785 __delay(200);
786 out_le32(&p->control_regs->mon_sense.r, 077); /* turn off drivers */
787 __delay(2000);
788 sense = (in_le32(&p->control_regs->mon_sense.r) & 0x1c0) << 2;
790 /* drive each sense line low in turn and collect the other 2 */
791 out_le32(&p->control_regs->mon_sense.r, 033); /* drive A low */
792 __delay(2000);
793 sense |= (in_le32(&p->control_regs->mon_sense.r) & 0xc0) >> 2;
794 out_le32(&p->control_regs->mon_sense.r, 055); /* drive B low */
795 __delay(2000);
796 sense |= ((in_le32(&p->control_regs->mon_sense.r) & 0x100) >> 5)
797 | ((in_le32(&p->control_regs->mon_sense.r) & 0x40) >> 4);
798 out_le32(&p->control_regs->mon_sense.r, 066); /* drive C low */
799 __delay(2000);
800 sense |= (in_le32(&p->control_regs->mon_sense.r) & 0x180) >> 7;
802 out_le32(&p->control_regs->mon_sense.r, 077); /* turn off drivers */
804 return sense;
807 /*********************** Various translation functions ***********************/
808 #if 1
809 /* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */
810 static int control_var_to_par(struct fb_var_screeninfo *var,
811 struct fb_par_control *par, const struct fb_info *fb_info)
813 int xres = var->xres;
814 int yres = var->yres;
815 int bpp = var->bits_per_pixel;
816 struct fb_info_control *p = (struct fb_info_control *) fb_info;
819 * Get the video params out of 'var'. If a value doesn't fit, round it up,
820 * if it's too big, return -EINVAL.
822 * Suggestion: Round up in the following order: bits_per_pixel, xres,
823 * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
824 * bitfields, horizontal timing, vertical timing.
826 /* swiped by jonh from atyfb.c */
827 if (xres <= 640 && yres <= 480)
828 par->vmode = VMODE_640_480_67; /* 640x480, 67Hz */
829 else if (xres <= 640 && yres <= 870)
830 par->vmode = VMODE_640_870_75P; /* 640x870, 75Hz (portrait) */
831 else if (xres <= 800 && yres <= 600)
832 par->vmode = VMODE_800_600_75; /* 800x600, 75Hz */
833 else if (xres <= 832 && yres <= 624)
834 par->vmode = VMODE_832_624_75; /* 832x624, 75Hz */
835 else if (xres <= 1024 && yres <= 768)
836 par->vmode = VMODE_1024_768_75; /* 1024x768, 75Hz */
837 else if (xres <= 1152 && yres <= 870)
838 par->vmode = VMODE_1152_870_75; /* 1152x870, 75Hz */
839 else if (xres <= 1280 && yres <= 960)
840 par->vmode = VMODE_1280_960_75; /* 1280x960, 75Hz */
841 else if (xres <= 1280 && yres <= 1024)
842 par->vmode = VMODE_1280_1024_75; /* 1280x1024, 75Hz */
843 else {
844 printk(KERN_ERR "Bad x/y res in var_to_par\n");
845 return -EINVAL;
848 xres = control_reg_init[par->vmode-1]->hres;
849 yres = control_reg_init[par->vmode-1]->vres;
851 par->xres = xres;
852 par->yres = yres;
854 if (var->xres_virtual <= xres)
855 par->vxres = xres;
856 else if(var->xres_virtual > xres) {
857 par->vxres = xres;
858 } else /* NotReached at present */
859 par->vxres = (var->xres_virtual+7) & ~7;
861 if (var->yres_virtual <= yres)
862 par->vyres = yres;
863 else
864 par->vyres = var->yres_virtual;
866 if (var->xoffset > 0 || var->yoffset+yres > par->vyres) {
867 printk(KERN_ERR "Bad offsets in var_to_par\n");
868 return -EINVAL;
871 par->xoffset = (var->xoffset+7) & ~7;
872 par->yoffset = var->yoffset;
875 if (bpp <= 8)
876 par->cmode = CMODE_8;
877 else if (bpp <= 16)
878 par->cmode = CMODE_16;
879 else if (bpp <= 32)
880 par->cmode = CMODE_32;
881 else {
882 printk(KERN_ERR "Bad bpp in var_to_par\n");
883 return -EINVAL;
886 if (control_vram_reqd(par->vmode, par->cmode) > p->total_vram) {
887 printk(KERN_ERR "Too much VRAM required for vmode %d cmode %d.\n", par->vmode, par->cmode);
888 return -EINVAL;
891 /* Check if we know about the wanted video mode */
892 if (control_reg_init[par->vmode - 1] == NULL) {
893 printk(KERN_ERR "init is null in control_var_to_par().\n");
894 /* I'm not sure if control has any specific requirements -- */
895 /* if we have a regvals struct, we're good to go? */
896 return -EINVAL;
899 return 0;
901 #else
902 /* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */
903 static int control_var_to_par(struct fb_var_screeninfo *var,
904 struct fb_par_control *par, const struct fb_info *fb_info)
906 struct fb_info_control *p = (struct fb_info_control *) fb_info;
908 if(mac_var_to_vmode(var, &par->vmode, &par->cmode) != 0)
909 return -EINVAL;
910 par->xres = par->vxres = vmode_attrs[par->vmode - 1].hres;
911 par->yres = par->vyres = vmode_attrs[par->vmode - 1].vres;
912 par->xoffset = par->yoffset = 0;
914 if (control_vram_reqd(par->vmode, par->cmode) > p->total_vram)
915 return -EINVAL;
917 /* Check if we know about the wanted video mode */
918 if(!control_reg_init[par->vmode-1]) {
919 /* I'm not sure if control has any specific requirements -- */
920 /* if we have a regvals struct, we're good to go? */
921 return -EINVAL;
923 return 0;
925 #endif
927 /*********** Convert hardware data in par to an fb_var_screeninfo ***********/
929 static void control_par_to_var(struct fb_par_control *par, struct fb_var_screeninfo *var)
931 struct control_regints *rv;
933 rv = (struct control_regints *) control_reg_init[par->vmode - 1]->regs;
935 memset(var, 0, sizeof(*var));
936 var->xres = control_reg_init[par->vmode - 1]->hres;
937 var->yres = control_reg_init[par->vmode - 1]->vres;
938 var->xres_virtual = par->vxres;
939 var->yres_virtual = par->vyres;
940 var->xoffset = par->xoffset;
941 var->yoffset = par->yoffset;
942 var->grayscale = 0;
944 if(par->cmode != CMODE_8 && par->cmode != CMODE_16 && par->cmode != CMODE_32) {
945 printk(KERN_ERR "Bad color mode in control_par_to_var()!\n");
946 par->cmode = CMODE_8;
948 switch(par->cmode) {
949 case CMODE_8:
950 var->bits_per_pixel = 8;
951 var->red.offset = 0;
952 var->red.length = 8;
953 var->green.offset = 0;
954 var->green.length = 8;
955 var->blue.offset = 0;
956 var->blue.length = 8;
957 var->transp.offset = 0;
958 var->transp.length = 0;
959 break;
960 case CMODE_16: /* RGB 555 */
961 var->bits_per_pixel = 16;
962 var->red.offset = 10;
963 var->red.length = 5;
964 var->green.offset = 5;
965 var->green.length = 5;
966 var->blue.offset = 0;
967 var->blue.length = 5;
968 var->transp.offset = 0;
969 var->transp.length = 0;
970 break;
971 case CMODE_32: /* RGB 888 */
972 var->bits_per_pixel = 32;
973 var->red.offset = 16;
974 var->red.length = 8;
975 var->green.offset = 8;
976 var->green.length = 8;
977 var->blue.offset = 0;
978 var->blue.length = 8;
979 var->transp.offset = 24;
980 var->transp.length = 8;
981 break;
983 var->red.msb_right = 0;
984 var->green.msb_right = 0;
985 var->blue.msb_right = 0;
986 var->transp.msb_right = 0;
987 var->nonstd = 0;
988 var->activate = 0;
989 var->height = -1;
990 var->width = -1;
991 var->vmode = FB_VMODE_NONINTERLACED;
993 var->left_margin = (rv->heblank - rv->hesync)
994 << ((par->vmode > 18) ? 2 : 1);
995 var->right_margin = (rv->hssync - rv->hsblank)
996 << ((par->vmode > 18) ? 2 : 1);
997 var->hsync_len = (rv->hperiod + 2 - rv->hssync + rv->hesync)
998 << ((par->vmode > 18) ? 2 : 1);
1000 var->upper_margin = (rv->veblank - rv->vesync) >> 1;
1001 var->lower_margin = (rv->vssync - rv->vsblank) >> 1;
1002 var->vsync_len = (rv->vperiod - rv->vssync + rv->vesync) >> 1;
1004 /* Acording to macmodes.c... */
1005 if((par->vmode >= 9 && par->vmode <= 12) ||
1006 (par->vmode >= 16 && par->vmode <= 18) ||
1007 (par->vmode == 20))
1009 var->sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT;
1010 } else {
1011 var->sync = 0; /* I suppose */
1014 /* The reason these are both here: with my revised margin calculations, */
1015 /* these SHOULD both give the same answer for each mode. Some day I */
1016 /* will sit down and check the rest. Works perfectly for vmode 13. */
1018 #if 0
1019 /* jonh's pixclocks...*/
1020 /* no long long support in the kernel :-( */
1021 /* this splittig trick will work if xres > 232 */
1022 var->pixclock = 1000000000/
1023 (var->left_margin+var->xres+var->right_margin+var->hsync_len);
1024 var->pixclock *= 1000;
1025 var->pixclock /= vmode_attrs[par->vmode-1].vfreq*
1026 (var->upper_margin+var->yres+var->lower_margin+var->vsync_len);
1027 #else
1028 /* danj's */
1029 /* 10^12 * clock_params[0] / (3906400 * clock_params[1] * 2^clock_params[2]) */
1030 /* (10^12 * clock_params[0] / (3906400 * clock_params[1])) >> clock_params[2] */
1031 /* (255990.17 * clock_params[0] / clock_params[1]) >> clock_params[2] */
1032 var->pixclock = 255990 * control_reg_init[par->vmode-1]->clock_params[0];
1033 var->pixclock /= control_reg_init[par->vmode-1]->clock_params[1];
1034 var->pixclock >>= control_reg_init[par->vmode-1]->clock_params[2];
1035 #endif
1038 static void control_par_to_fix(struct fb_par_control *par, struct fb_fix_screeninfo *fix,
1039 struct fb_info_control *p)
1041 memset(fix, 0, sizeof(*fix));
1042 strcpy(fix->id, "control");
1043 fix->mmio_start = p->control_regs_phys;
1044 fix->mmio_len = sizeof(struct control_regs);
1045 fix->type = FB_TYPE_PACKED_PIXELS;
1047 fix->ypanstep = 1;
1049 fix->type_aux = 0;
1050 fix->ywrapstep = 0;
1051 fix->ypanstep = 0;
1052 fix->xpanstep = 0;
1055 fix->smem_start = (p->frame_buffer_phys
1056 + control_reg_init[par->vmode-1]->offset[par->cmode]);
1057 fix->smem_len = p->total_vram - control_reg_init[par->vmode-1]->offset[par->cmode];
1058 fix->visual = (par->cmode == CMODE_8) ?
1059 FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
1060 fix->line_length = par->vxres << par->cmode;
1063 /* We never initialize any display except for p->disp.
1064 And p->disp is already memset to 0. So no memset here.
1065 [Found by Takashi Oe]
1067 static void control_par_to_display(struct fb_par_control *par,
1068 struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_control *p)
1070 /* memset(disp, 0, sizeof(*disp)); */
1071 disp->type = fix->type;
1072 disp->can_soft_blank = 1;
1073 disp->scrollmode = SCROLL_YNOMOVE | SCROLL_YNOPARTIAL;
1074 disp->ypanstep = fix->ypanstep;
1075 disp->ywrapstep = fix->ywrapstep;
1076 #if 0
1077 disp->type_aux = fix->type_aux;
1078 disp->cmap.red = NULL; /* ??? danj */
1079 disp->cmap.green = NULL;
1080 disp->cmap.blue = NULL;
1081 disp->cmap.transp = NULL;
1082 /* Yeah, I realize I just set 0 = 0. */
1083 #endif
1085 control_par_to_var(par, &disp->var);
1086 disp->screen_base = (char *) p->frame_buffer
1087 + control_reg_init[par->vmode-1]->offset[par->cmode];
1088 disp->visual = fix->visual;
1089 disp->line_length = fix->line_length;
1090 control_set_dispsw(disp, par->cmode, p);
1093 static void control_cfb16_revc(struct display *p, int xx, int yy)
1095 u8 *dest;
1096 int bytes = p->next_line, rows;
1098 dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p)*2;
1099 for (rows = fontheight(p); rows--; dest += bytes) {
1100 switch (fontwidth(p)) {
1101 case 16:
1102 ((u32 *)dest)[6] ^= 0x3def3def; ((u32 *)dest)[7] ^= 0x3def3def;
1103 /* FALL THROUGH */
1104 case 12:
1105 ((u32 *)dest)[4] ^= 0x3def3def; ((u32 *)dest)[5] ^= 0x3def3def;
1106 /* FALL THROUGH */
1107 case 8:
1108 ((u32 *)dest)[2] ^= 0x3def3def; ((u32 *)dest)[3] ^= 0x3def3def;
1109 /* FALL THROUGH */
1110 case 4:
1111 ((u32 *)dest)[0] ^= 0x3def3def; ((u32 *)dest)[1] ^= 0x3def3def;
1116 static void control_cfb32_revc(struct display *p, int xx, int yy)
1118 u8 *dest;
1119 int bytes = p->next_line, rows;
1121 dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 4;
1122 for (rows = fontheight(p); rows--; dest += bytes) {
1123 switch (fontwidth(p)) {
1124 case 16:
1125 ((u32 *)dest)[12] ^= 0x0f0f0f0f; ((u32 *)dest)[13] ^= 0x0f0f0f0f;
1126 ((u32 *)dest)[14] ^= 0x0f0f0f0f; ((u32 *)dest)[15] ^= 0x0f0f0f0f;
1127 /* FALL THROUGH */
1128 case 12:
1129 ((u32 *)dest)[8] ^= 0x0f0f0f0f; ((u32 *)dest)[9] ^= 0x0f0f0f0f;
1130 ((u32 *)dest)[10] ^= 0x0f0f0f0f; ((u32 *)dest)[11] ^= 0x0f0f0f0f;
1131 /* FALL THROUGH */
1132 case 8:
1133 ((u32 *)dest)[4] ^= 0x0f0f0f0f; ((u32 *)dest)[5] ^= 0x0f0f0f0f;
1134 ((u32 *)dest)[6] ^= 0x0f0f0f0f; ((u32 *)dest)[7] ^= 0x0f0f0f0f;
1135 /* FALL THROUGH */
1136 case 4:
1137 ((u32 *)dest)[0] ^= 0x0f0f0f0f; ((u32 *)dest)[1] ^= 0x0f0f0f0f;
1138 ((u32 *)dest)[2] ^= 0x0f0f0f0f; ((u32 *)dest)[3] ^= 0x0f0f0f0f;
1139 /* FALL THROUGH */
1144 static struct display_switch control_cfb16 = {
1145 setup: fbcon_cfb16_setup,
1146 bmove: fbcon_cfb16_bmove,
1147 clear: fbcon_cfb16_clear,
1148 putc: fbcon_cfb16_putc,
1149 putcs: fbcon_cfb16_putcs,
1150 revc: control_cfb16_revc,
1151 clear_margins: fbcon_cfb16_clear_margins,
1152 fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1155 static struct display_switch control_cfb32 = {
1156 setup: fbcon_cfb32_setup,
1157 bmove: fbcon_cfb32_bmove,
1158 clear: fbcon_cfb32_clear,
1159 putc: fbcon_cfb32_putc,
1160 putcs: fbcon_cfb32_putcs,
1161 revc: control_cfb32_revc,
1162 clear_margins: fbcon_cfb32_clear_margins,
1163 fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1167 static void control_set_dispsw(struct display *disp, int cmode, struct fb_info_control *p)
1169 switch (cmode) {
1170 #ifdef FBCON_HAS_CFB8
1171 case CMODE_8:
1172 disp->dispsw = &fbcon_cfb8;
1173 break;
1174 #endif
1175 #ifdef FBCON_HAS_CFB16
1176 case CMODE_16:
1177 disp->dispsw = &control_cfb16;
1178 disp->dispsw_data = p->fbcon_cmap.cfb16;
1179 break;
1180 #endif
1181 #ifdef FBCON_HAS_CFB32
1182 case CMODE_32:
1183 disp->dispsw = &control_cfb32;
1184 disp->dispsw_data = p->fbcon_cmap.cfb32;
1185 break;
1186 #endif
1187 default:
1188 disp->dispsw = &fbcon_dummy;
1189 break;
1193 static void __init control_init_info(struct fb_info *info, struct fb_info_control *p)
1195 strcpy(info->modename, "control");
1196 info->node = -1; /* ??? danj */
1197 info->fbops = &controlfb_ops;
1198 info->disp = &p->display;
1199 strcpy(info->fontname, fontname);
1200 info->changevar = NULL;
1201 info->switch_con = &controlfb_switch;
1202 info->updatevar = &controlfb_updatevar;
1203 info->blank = &controlfb_blank;
1206 /* Parse user speficied options (`video=controlfb:') */
1207 void __init control_setup(char *options)
1209 char *this_opt;
1211 if (!options || !*options)
1212 return;
1214 for (this_opt = strtok(options, ","); this_opt;
1215 this_opt = strtok(NULL, ",")) {
1216 if (!strncmp(this_opt, "font:", 5)) {
1217 char *p;
1218 int i;
1220 p = this_opt +5;
1221 for (i = 0; i < sizeof(fontname) - 1; i++)
1222 if (!*p || *p == ' ' || *p == ',')
1223 break;
1224 memcpy(fontname, this_opt + 5, i);
1225 fontname[i] = 0;
1227 if (!strncmp(this_opt, "vmode:", 6)) {
1228 int vmode = simple_strtoul(this_opt+6, NULL, 0);
1229 if (vmode > 0 && vmode <= VMODE_MAX)
1230 default_vmode = vmode;
1231 } else if (!strncmp(this_opt, "cmode:", 6)) {
1232 int depth = simple_strtoul(this_opt+6, NULL, 0);
1233 switch (depth) {
1234 case CMODE_8:
1235 case CMODE_16:
1236 case CMODE_32:
1237 default_cmode = depth;
1238 break;
1239 case 8:
1240 default_cmode = CMODE_8;
1241 break;
1242 case 15:
1243 case 16:
1244 default_cmode = CMODE_16;
1245 break;
1246 case 24:
1247 case 32:
1248 default_cmode = CMODE_32;
1249 break;
1255 #if 0
1256 static int controlfb_pan_display(struct fb_var_screeninfo *var,
1257 struct controlfb_par *par,
1258 const struct fb_info *fb_info)
1261 * Pan (or wrap, depending on the `vmode' field) the display using the
1262 * `xoffset' and `yoffset' fields of the `var' structure.
1263 * If the values don't fit, return -EINVAL.
1266 FUNCID;
1268 return 0;
1271 #endif