[PATCH] fbdev: sstfb: Driver cleanups
[linux-2.6] / drivers / video / controlfb.c
1 /*
2  *  controlfb.c -- frame buffer device for the PowerMac 'control' display
3  *
4  *  Created 12 July 1998 by Dan Jacobowitz <dan@debian.org>
5  *  Copyright (C) 1998 Dan Jacobowitz
6  *  Copyright (C) 2001 Takashi Oe
7  *
8  *  Mmap code by Michel Lanners <mlan@cpu.lu>
9  *
10  *  Frame buffer structure from:
11  *    drivers/video/chipsfb.c -- frame buffer device for
12  *    Chips & Technologies 65550 chip.
13  *
14  *    Copyright (C) 1998 Paul Mackerras
15  *
16  *    This file is derived from the Powermac "chips" driver:
17  *    Copyright (C) 1997 Fabio Riccardi.
18  *    And from the frame buffer device for Open Firmware-initialized devices:
19  *    Copyright (C) 1997 Geert Uytterhoeven.
20  *
21  *  Hardware information from:
22  *    control.c: Console support for PowerMac "control" display adaptor.
23  *    Copyright (C) 1996 Paul Mackerras
24  *
25  *  Updated to 2.5 framebuffer API by Ben Herrenschmidt
26  *  <benh@kernel.crashing.org>, Paul Mackerras <paulus@samba.org>,
27  *  and James Simmons <jsimmons@infradead.org>.
28  *
29  *  This file is subject to the terms and conditions of the GNU General Public
30  *  License. See the file COPYING in the main directory of this archive for
31  *  more details.
32  */
33
34 #include <linux/config.h>
35 #include <linux/module.h>
36 #include <linux/kernel.h>
37 #include <linux/errno.h>
38 #include <linux/string.h>
39 #include <linux/mm.h>
40 #include <linux/tty.h>
41 #include <linux/slab.h>
42 #include <linux/vmalloc.h>
43 #include <linux/delay.h>
44 #include <linux/interrupt.h>
45 #include <linux/fb.h>
46 #include <linux/init.h>
47 #include <linux/pci.h>
48 #include <linux/nvram.h>
49 #include <linux/adb.h>
50 #include <linux/cuda.h>
51 #include <asm/io.h>
52 #include <asm/prom.h>
53 #include <asm/pgtable.h>
54 #include <asm/btext.h>
55
56 #include "macmodes.h"
57 #include "controlfb.h"
58
59 struct fb_par_control {
60         int     vmode, cmode;
61         int     xres, yres;
62         int     vxres, vyres;
63         int     xoffset, yoffset;
64         int     pitch;
65         struct control_regvals  regvals;
66         unsigned long sync;
67         unsigned char ctrl;
68 };
69
70 #define DIRTY(z) ((x)->z != (y)->z)
71 #define DIRTY_CMAP(z) (memcmp(&((x)->z), &((y)->z), sizeof((y)->z)))
72 static inline int PAR_EQUAL(struct fb_par_control *x, struct fb_par_control *y)
73 {
74         int i, results;
75
76         results = 1;
77         for (i = 0; i < 3; i++)
78                 results &= !DIRTY(regvals.clock_params[i]);
79         if (!results)
80                 return 0;
81         for (i = 0; i < 16; i++)
82                 results &= !DIRTY(regvals.regs[i]);
83         if (!results)
84                 return 0;
85         return (!DIRTY(cmode) && !DIRTY(xres) && !DIRTY(yres)
86                 && !DIRTY(vxres) && !DIRTY(vyres));
87 }
88 static inline int VAR_MATCH(struct fb_var_screeninfo *x, struct fb_var_screeninfo *y)
89 {
90         return (!DIRTY(bits_per_pixel) && !DIRTY(xres)
91                 && !DIRTY(yres) && !DIRTY(xres_virtual)
92                 && !DIRTY(yres_virtual)
93                 && !DIRTY_CMAP(red) && !DIRTY_CMAP(green) && !DIRTY_CMAP(blue));
94 }
95
96 struct fb_info_control {
97         struct fb_info          info;
98         struct fb_par_control   par;
99         u32                     pseudo_palette[17];
100                 
101         struct cmap_regs        __iomem *cmap_regs;
102         unsigned long           cmap_regs_phys;
103         
104         struct control_regs     __iomem *control_regs;
105         unsigned long           control_regs_phys;
106         unsigned long           control_regs_size;
107         
108         __u8                    __iomem *frame_buffer;
109         unsigned long           frame_buffer_phys;
110         unsigned long           fb_orig_base;
111         unsigned long           fb_orig_size;
112
113         int                     control_use_bank2;
114         unsigned long           total_vram;
115         unsigned char           vram_attr;
116 };
117
118 /* control register access macro */
119 #define CNTRL_REG(INFO,REG) (&(((INFO)->control_regs->REG).r))
120
121
122 /******************** Prototypes for exported functions ********************/
123 /*
124  * struct fb_ops
125  */
126 static int controlfb_pan_display(struct fb_var_screeninfo *var,
127         struct fb_info *info);
128 static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
129         u_int transp, struct fb_info *info);
130 static int controlfb_blank(int blank_mode, struct fb_info *info);
131 static int controlfb_mmap(struct fb_info *info, struct file *file,
132         struct vm_area_struct *vma);
133 static int controlfb_set_par (struct fb_info *info);
134 static int controlfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info);
135
136 /******************** Prototypes for internal functions **********************/
137
138 static void set_control_clock(unsigned char *params);
139 static int init_control(struct fb_info_control *p);
140 static void control_set_hardware(struct fb_info_control *p,
141         struct fb_par_control *par);
142 static int control_of_init(struct device_node *dp);
143 static void find_vram_size(struct fb_info_control *p);
144 static int read_control_sense(struct fb_info_control *p);
145 static int calc_clock_params(unsigned long clk, unsigned char *param);
146 static int control_var_to_par(struct fb_var_screeninfo *var,
147         struct fb_par_control *par, const struct fb_info *fb_info);
148 static inline void control_par_to_var(struct fb_par_control *par,
149         struct fb_var_screeninfo *var);
150 static void control_init_info(struct fb_info *info, struct fb_info_control *p);
151 static void control_cleanup(void);
152
153
154 /************************** Internal variables *******************************/
155
156 static struct fb_info_control *control_fb;
157
158 static int default_vmode __initdata = VMODE_NVRAM;
159 static int default_cmode __initdata = CMODE_NVRAM;
160
161
162 static struct fb_ops controlfb_ops = {
163         .owner          = THIS_MODULE,
164         .fb_check_var   = controlfb_check_var,
165         .fb_set_par     = controlfb_set_par,
166         .fb_setcolreg   = controlfb_setcolreg,
167         .fb_pan_display = controlfb_pan_display,
168         .fb_blank       = controlfb_blank,
169         .fb_mmap        = controlfb_mmap,
170         .fb_fillrect    = cfb_fillrect,
171         .fb_copyarea    = cfb_copyarea,
172         .fb_imageblit   = cfb_imageblit,
173 };
174
175
176 /********************  The functions for controlfb_ops ********************/
177
178 #ifdef MODULE
179 MODULE_LICENSE("GPL");
180
181 int init_module(void)
182 {
183         struct device_node *dp;
184
185         dp = find_devices("control");
186         if (dp != 0 && !control_of_init(dp))
187                 return 0;
188
189         return -ENXIO;
190 }
191
192 void cleanup_module(void)
193 {
194         control_cleanup();
195 }
196 #endif
197
198 /*
199  * Checks a var structure
200  */
201 static int controlfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info)
202 {
203         struct fb_par_control par;
204         int err;
205
206         err = control_var_to_par(var, &par, info);
207         if (err)
208                 return err;     
209         control_par_to_var(&par, var);
210
211         return 0;
212 }
213
214 /*
215  * Applies current var to display
216  */
217 static int controlfb_set_par (struct fb_info *info)
218 {
219         struct fb_info_control *p = (struct fb_info_control *) info;
220         struct fb_par_control par;
221         int err;
222
223         if((err = control_var_to_par(&info->var, &par, info))) {
224                 printk (KERN_ERR "controlfb_set_par: error calling"
225                                  " control_var_to_par: %d.\n", err);
226                 return err;
227         }
228         
229         control_set_hardware(p, &par);
230
231         info->fix.visual = (p->par.cmode == CMODE_8) ?
232                 FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
233         info->fix.line_length = p->par.pitch;
234         info->fix.xpanstep = 32 >> p->par.cmode;
235         info->fix.ypanstep = 1;
236
237         return 0;
238 }
239
240 /*
241  * Set screen start address according to var offset values
242  */
243 static inline void set_screen_start(int xoffset, int yoffset,
244         struct fb_info_control *p)
245 {
246         struct fb_par_control *par = &p->par;
247
248         par->xoffset = xoffset;
249         par->yoffset = yoffset;
250         out_le32(CNTRL_REG(p,start_addr),
251                  par->yoffset * par->pitch + (par->xoffset << par->cmode));
252 }
253
254
255 static int controlfb_pan_display(struct fb_var_screeninfo *var,
256                                  struct fb_info *info)
257 {
258         unsigned int xoffset, hstep;
259         struct fb_info_control *p = (struct fb_info_control *)info;
260         struct fb_par_control *par = &p->par;
261
262         /*
263          * make sure start addr will be 32-byte aligned
264          */
265         hstep = 0x1f >> par->cmode;
266         xoffset = (var->xoffset + hstep) & ~hstep;
267
268         if (xoffset+par->xres > par->vxres ||
269             var->yoffset+par->yres > par->vyres)
270                 return -EINVAL;
271
272         set_screen_start(xoffset, var->yoffset, p);
273
274         return 0;
275 }
276
277
278 /*
279  * Private mmap since we want to have a different caching on the framebuffer
280  * for controlfb.
281  * Note there's no locking in here; it's done in fb_mmap() in fbmem.c.
282  */
283 static int controlfb_mmap(struct fb_info *info, struct file *file,
284                        struct vm_area_struct *vma)
285 {
286        unsigned long off, start;
287        u32 len;
288
289        off = vma->vm_pgoff << PAGE_SHIFT;
290
291        /* frame buffer memory */
292        start = info->fix.smem_start;
293        len = PAGE_ALIGN((start & ~PAGE_MASK)+info->fix.smem_len);
294        if (off >= len) {
295                /* memory mapped io */
296                off -= len;
297                if (info->var.accel_flags)
298                        return -EINVAL;
299                start = info->fix.mmio_start;
300                len = PAGE_ALIGN((start & ~PAGE_MASK)+info->fix.mmio_len);
301                pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED;
302        } else {
303                /* framebuffer */
304                pgprot_val(vma->vm_page_prot) |= _PAGE_WRITETHRU;
305        }
306        start &= PAGE_MASK;
307        if ((vma->vm_end - vma->vm_start + off) > len)
308                 return -EINVAL;
309        off += start;
310        vma->vm_pgoff = off >> PAGE_SHIFT;
311        if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
312            vma->vm_end - vma->vm_start, vma->vm_page_prot))
313                return -EAGAIN;
314
315        return 0;
316 }
317
318 static int controlfb_blank(int blank_mode, struct fb_info *info)
319 {
320         struct fb_info_control *p = (struct fb_info_control *) info;
321         unsigned ctrl;
322
323         ctrl = ld_le32(CNTRL_REG(p,ctrl));
324         if (blank_mode > 0)
325                 switch (blank_mode) {
326                 case FB_BLANK_VSYNC_SUSPEND:
327                         ctrl &= ~3;
328                         break;
329                 case FB_BLANK_HSYNC_SUSPEND:
330                         ctrl &= ~0x30;
331                         break;
332                 case FB_BLANK_POWERDOWN:
333                         ctrl &= ~0x33;
334                         /* fall through */
335                 case FB_BLANK_NORMAL:
336                         ctrl |= 0x400;
337                         break;
338                 default:
339                         break;
340                 }
341         else {
342                 ctrl &= ~0x400;
343                 ctrl |= 0x33;
344         }
345         out_le32(CNTRL_REG(p,ctrl), ctrl);
346
347         return 0;
348 }
349
350 static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
351                              u_int transp, struct fb_info *info)
352 {
353         struct fb_info_control *p = (struct fb_info_control *) info;
354         __u8 r, g, b;
355
356         if (regno > 255)
357                 return 1;
358
359         r = red >> 8;
360         g = green >> 8;
361         b = blue >> 8;
362
363         out_8(&p->cmap_regs->addr, regno);      /* tell clut what addr to fill  */
364         out_8(&p->cmap_regs->lut, r);           /* send one color channel at    */
365         out_8(&p->cmap_regs->lut, g);           /* a time...                    */
366         out_8(&p->cmap_regs->lut, b);
367
368         if (regno < 16) {
369                 int i;
370                 switch (p->par.cmode) {
371                 case CMODE_16:
372                         p->pseudo_palette[regno] =
373                             (regno << 10) | (regno << 5) | regno;
374                         break;
375                 case CMODE_32:
376                         i = (regno << 8) | regno;
377                         p->pseudo_palette[regno] = (i << 16) | i;
378                         break;
379                 }
380         }
381
382         return 0;
383 }
384
385
386 /********************  End of controlfb_ops implementation  ******************/
387
388
389
390 static void set_control_clock(unsigned char *params)
391 {
392 #ifdef CONFIG_ADB_CUDA
393         struct adb_request req;
394         int i;
395
396         for (i = 0; i < 3; ++i) {
397                 cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
398                              0x50, i + 1, params[i]);
399                 while (!req.complete)
400                         cuda_poll();
401         }
402 #endif  
403 }
404
405
406 /*
407  * finish off the driver initialization and register
408  */
409 static int __init init_control(struct fb_info_control *p)
410 {
411         int full, sense, vmode, cmode, vyres;
412         struct fb_var_screeninfo var;
413         int rc;
414         
415         printk(KERN_INFO "controlfb: ");
416
417         full = p->total_vram == 0x400000;
418
419         /* Try to pick a video mode out of NVRAM if we have one. */
420         if (default_cmode == CMODE_NVRAM){
421                 cmode = nvram_read_byte(NV_CMODE);
422                 if(cmode < CMODE_8 || cmode > CMODE_32)
423                         cmode = CMODE_8;
424         } else
425                 cmode=default_cmode;
426
427         if (default_vmode == VMODE_NVRAM) {
428                 vmode = nvram_read_byte(NV_VMODE);
429                 if (vmode < 1 || vmode > VMODE_MAX ||
430                     control_mac_modes[vmode - 1].m[full] < cmode) {
431                         sense = read_control_sense(p);
432                         printk("Monitor sense value = 0x%x, ", sense);
433                         vmode = mac_map_monitor_sense(sense);
434                         if (control_mac_modes[vmode - 1].m[full] < cmode)
435                                 vmode = VMODE_640_480_60;
436                 }
437         } else {
438                 vmode=default_vmode;
439                 if (control_mac_modes[vmode - 1].m[full] < cmode) {
440                         if (cmode > CMODE_8)
441                                 cmode--;
442                         else
443                                 vmode = VMODE_640_480_60;
444                 }
445         }
446
447         /* Initialize info structure */
448         control_init_info(&p->info, p);
449
450         /* Setup default var */
451         if (mac_vmode_to_var(vmode, cmode, &var) < 0) {
452                 /* This shouldn't happen! */
453                 printk("mac_vmode_to_var(%d, %d,) failed\n", vmode, cmode);
454 try_again:
455                 vmode = VMODE_640_480_60;
456                 cmode = CMODE_8;
457                 if (mac_vmode_to_var(vmode, cmode, &var) < 0) {
458                         printk(KERN_ERR "controlfb: mac_vmode_to_var() failed\n");
459                         return -ENXIO;
460                 }
461                 printk(KERN_INFO "controlfb: ");
462         }
463         printk("using video mode %d and color mode %d.\n", vmode, cmode);
464
465         vyres = (p->total_vram - CTRLFB_OFF) / (var.xres << cmode);
466         if (vyres > var.yres)
467                 var.yres_virtual = vyres;
468
469         /* Apply default var */
470         var.activate = FB_ACTIVATE_NOW;
471         rc = fb_set_var(&p->info, &var);
472         if (rc && (vmode != VMODE_640_480_60 || cmode != CMODE_8))
473                 goto try_again;
474
475         /* Register with fbdev layer */
476         if (register_framebuffer(&p->info) < 0)
477                 return -ENXIO;
478         
479         printk(KERN_INFO "fb%d: control display adapter\n", p->info.node);      
480
481         return 0;
482 }
483
484 #define RADACAL_WRITE(a,d) \
485         out_8(&p->cmap_regs->addr, (a)); \
486         out_8(&p->cmap_regs->dat,   (d))
487
488 /* Now how about actually saying, Make it so! */
489 /* Some things in here probably don't need to be done each time. */
490 static void control_set_hardware(struct fb_info_control *p, struct fb_par_control *par)
491 {
492         struct control_regvals  *r;
493         volatile struct preg    __iomem *rp;
494         int                     i, cmode;
495
496         if (PAR_EQUAL(&p->par, par)) {
497                 /*
498                  * check if only xoffset or yoffset differs.
499                  * this prevents flickers in typical VT switch case.
500                  */
501                 if (p->par.xoffset != par->xoffset ||
502                     p->par.yoffset != par->yoffset)
503                         set_screen_start(par->xoffset, par->yoffset, p);
504                         
505                 return;
506         }
507         
508         p->par = *par;
509         cmode = p->par.cmode;
510         r = &par->regvals;
511         
512         /* Turn off display */
513         out_le32(CNTRL_REG(p,ctrl), 0x400 | par->ctrl);
514         
515         set_control_clock(r->clock_params);
516         
517         RADACAL_WRITE(0x20, r->radacal_ctrl);
518         RADACAL_WRITE(0x21, p->control_use_bank2 ? 0 : 1);
519         RADACAL_WRITE(0x10, 0);
520         RADACAL_WRITE(0x11, 0);
521
522         rp = &p->control_regs->vswin;
523         for (i = 0; i < 16; ++i, ++rp)
524                 out_le32(&rp->r, r->regs[i]);
525         
526         out_le32(CNTRL_REG(p,pitch), par->pitch);
527         out_le32(CNTRL_REG(p,mode), r->mode);
528         out_le32(CNTRL_REG(p,vram_attr), p->vram_attr);
529         out_le32(CNTRL_REG(p,start_addr), par->yoffset * par->pitch
530                  + (par->xoffset << cmode));
531         out_le32(CNTRL_REG(p,rfrcnt), 0x1e5);
532         out_le32(CNTRL_REG(p,intr_ena), 0);
533
534         /* Turn on display */
535         out_le32(CNTRL_REG(p,ctrl), par->ctrl);
536
537 #ifdef CONFIG_BOOTX_TEXT
538         btext_update_display(p->frame_buffer_phys + CTRLFB_OFF,
539                              p->par.xres, p->par.yres,
540                              (cmode == CMODE_32? 32: cmode == CMODE_16? 16: 8),
541                              p->par.pitch);
542 #endif /* CONFIG_BOOTX_TEXT */
543 }
544
545
546 /*
547  * Parse user speficied options (`video=controlfb:')
548  */
549 static void __init control_setup(char *options)
550 {
551         char *this_opt;
552
553         if (!options || !*options)
554                 return;
555
556         while ((this_opt = strsep(&options, ",")) != NULL) {
557                 if (!strncmp(this_opt, "vmode:", 6)) {
558                         int vmode = simple_strtoul(this_opt+6, NULL, 0);
559                         if (vmode > 0 && vmode <= VMODE_MAX &&
560                             control_mac_modes[vmode - 1].m[1] >= 0)
561                                 default_vmode = vmode;
562                 } else if (!strncmp(this_opt, "cmode:", 6)) {
563                         int depth = simple_strtoul(this_opt+6, NULL, 0);
564                         switch (depth) {
565                          case CMODE_8:
566                          case CMODE_16:
567                          case CMODE_32:
568                                 default_cmode = depth;
569                                 break;
570                          case 8:
571                                 default_cmode = CMODE_8;
572                                 break;
573                          case 15:
574                          case 16:
575                                 default_cmode = CMODE_16;
576                                 break;
577                          case 24:
578                          case 32:
579                                 default_cmode = CMODE_32;
580                                 break;
581                         }
582                 }
583         }
584 }
585
586 static int __init control_init(void)
587 {
588         struct device_node *dp;
589         char *option = NULL;
590
591         if (fb_get_options("controlfb", &option))
592                 return -ENODEV;
593         control_setup(option);
594
595         dp = find_devices("control");
596         if (dp != 0 && !control_of_init(dp))
597                 return 0;
598
599         return -ENXIO;
600 }
601
602 module_init(control_init);
603
604 /* Work out which banks of VRAM we have installed. */
605 /* danj: I guess the card just ignores writes to nonexistant VRAM... */
606
607 static void __init find_vram_size(struct fb_info_control *p)
608 {
609         int bank1, bank2;
610
611         /*
612          * Set VRAM in 2MB (bank 1) mode
613          * VRAM Bank 2 will be accessible through offset 0x600000 if present
614          * and VRAM Bank 1 will not respond at that offset even if present
615          */
616         out_le32(CNTRL_REG(p,vram_attr), 0x31);
617
618         out_8(&p->frame_buffer[0x600000], 0xb3);
619         out_8(&p->frame_buffer[0x600001], 0x71);
620         asm volatile("eieio; dcbf 0,%0" : : "r" (&p->frame_buffer[0x600000])
621                                         : "memory" );
622         mb();
623         asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x600000])
624                                         : "memory" );
625         mb();
626
627         bank2 = (in_8(&p->frame_buffer[0x600000]) == 0xb3)
628                 && (in_8(&p->frame_buffer[0x600001]) == 0x71);
629
630         /*
631          * Set VRAM in 2MB (bank 2) mode
632          * VRAM Bank 1 will be accessible through offset 0x000000 if present
633          * and VRAM Bank 2 will not respond at that offset even if present
634          */
635         out_le32(CNTRL_REG(p,vram_attr), 0x39);
636
637         out_8(&p->frame_buffer[0], 0x5a);
638         out_8(&p->frame_buffer[1], 0xc7);
639         asm volatile("eieio; dcbf 0,%0" : : "r" (&p->frame_buffer[0])
640                                         : "memory" );
641         mb();
642         asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0])
643                                         : "memory" );
644         mb();
645
646         bank1 = (in_8(&p->frame_buffer[0]) == 0x5a)
647                 && (in_8(&p->frame_buffer[1]) == 0xc7);
648
649         if (bank2) {
650                 if (!bank1) {
651                         /*
652                          * vram bank 2 only
653                          */
654                         p->control_use_bank2 = 1;
655                         p->vram_attr = 0x39;
656                         p->frame_buffer += 0x600000;
657                         p->frame_buffer_phys += 0x600000;
658                 } else {
659                         /*
660                          * 4 MB vram
661                          */
662                         p->vram_attr = 0x51;
663                 }
664         } else {
665                 /*
666                  * vram bank 1 only
667                  */
668                 p->vram_attr = 0x31;
669         }
670
671         p->total_vram = (bank1 + bank2) * 0x200000;
672
673         printk(KERN_INFO "controlfb: VRAM Total = %dMB "
674                         "(%dMB @ bank 1, %dMB @ bank 2)\n",
675                         (bank1 + bank2) << 1, bank1 << 1, bank2 << 1);
676 }
677
678
679 /*
680  * find "control" and initialize
681  */
682 static int __init control_of_init(struct device_node *dp)
683 {
684         struct fb_info_control  *p;
685         struct resource         fb_res, reg_res;
686
687         if (control_fb) {
688                 printk(KERN_ERR "controlfb: only one control is supported\n");
689                 return -ENXIO;
690         }
691
692         if (of_pci_address_to_resource(dp, 2, &fb_res) ||
693             of_pci_address_to_resource(dp, 1, &reg_res)) {
694                 printk(KERN_ERR "can't get 2 addresses for control\n");
695                 return -ENXIO;
696         }
697         p = kmalloc(sizeof(*p), GFP_KERNEL);
698         if (p == 0)
699                 return -ENXIO;
700         control_fb = p; /* save it for cleanups */
701         memset(p, 0, sizeof(*p));
702
703         /* Map in frame buffer and registers */
704         p->fb_orig_base = fb_res.start;
705         p->fb_orig_size = fb_res.end - fb_res.start + 1;
706         /* use the big-endian aperture (??) */
707         p->frame_buffer_phys = fb_res.start + 0x800000;
708         p->control_regs_phys = reg_res.start;
709         p->control_regs_size = reg_res.end - reg_res.start + 1;
710
711         if (!p->fb_orig_base ||
712             !request_mem_region(p->fb_orig_base,p->fb_orig_size,"controlfb")) {
713                 p->fb_orig_base = 0;
714                 goto error_out;
715         }
716         /* map at most 8MB for the frame buffer */
717         p->frame_buffer = __ioremap(p->frame_buffer_phys, 0x800000,
718                                     _PAGE_WRITETHRU);
719
720         if (!p->control_regs_phys ||
721             !request_mem_region(p->control_regs_phys, p->control_regs_size,
722             "controlfb regs")) {
723                 p->control_regs_phys = 0;
724                 goto error_out;
725         }
726         p->control_regs = ioremap(p->control_regs_phys, p->control_regs_size);
727
728         p->cmap_regs_phys = 0xf301b000;  /* XXX not in prom? */
729         if (!request_mem_region(p->cmap_regs_phys, 0x1000, "controlfb cmap")) {
730                 p->cmap_regs_phys = 0;
731                 goto error_out;
732         }
733         p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000);
734
735         if (!p->cmap_regs || !p->control_regs || !p->frame_buffer)
736                 goto error_out;
737
738         find_vram_size(p);
739         if (!p->total_vram)
740                 goto error_out;
741
742         if (init_control(p) < 0)
743                 goto error_out;
744
745         return 0;
746
747 error_out:
748         control_cleanup();
749         return -ENXIO;
750 }
751
752 /*
753  * Get the monitor sense value.
754  * Note that this can be called before calibrate_delay,
755  * so we can't use udelay.
756  */
757 static int read_control_sense(struct fb_info_control *p)
758 {
759         int sense;
760
761         out_le32(CNTRL_REG(p,mon_sense), 7);    /* drive all lines high */
762         __delay(200);
763         out_le32(CNTRL_REG(p,mon_sense), 077);  /* turn off drivers */
764         __delay(2000);
765         sense = (in_le32(CNTRL_REG(p,mon_sense)) & 0x1c0) << 2;
766
767         /* drive each sense line low in turn and collect the other 2 */
768         out_le32(CNTRL_REG(p,mon_sense), 033);  /* drive A low */
769         __delay(2000);
770         sense |= (in_le32(CNTRL_REG(p,mon_sense)) & 0xc0) >> 2;
771         out_le32(CNTRL_REG(p,mon_sense), 055);  /* drive B low */
772         __delay(2000);
773         sense |= ((in_le32(CNTRL_REG(p,mon_sense)) & 0x100) >> 5)
774                 | ((in_le32(CNTRL_REG(p,mon_sense)) & 0x40) >> 4);
775         out_le32(CNTRL_REG(p,mon_sense), 066);  /* drive C low */
776         __delay(2000);
777         sense |= (in_le32(CNTRL_REG(p,mon_sense)) & 0x180) >> 7;
778
779         out_le32(CNTRL_REG(p,mon_sense), 077);  /* turn off drivers */
780         
781         return sense;
782 }
783
784 /**********************  Various translation functions  **********************/
785
786 #define CONTROL_PIXCLOCK_BASE   256016
787 #define CONTROL_PIXCLOCK_MIN    5000    /* ~ 200 MHz dot clock */
788
789 /*
790  * calculate the clock paramaters to be sent to CUDA according to given
791  * pixclock in pico second.
792  */
793 static int calc_clock_params(unsigned long clk, unsigned char *param)
794 {
795         unsigned long p0, p1, p2, k, l, m, n, min;
796
797         if (clk > (CONTROL_PIXCLOCK_BASE << 3))
798                 return 1;
799
800         p2 = ((clk << 4) < CONTROL_PIXCLOCK_BASE)? 3: 2;
801         l = clk << p2;
802         p0 = 0;
803         p1 = 0;
804         for (k = 1, min = l; k < 32; k++) {
805                 unsigned long rem;
806
807                 m = CONTROL_PIXCLOCK_BASE * k;
808                 n = m / l;
809                 rem = m % l;
810                 if (n && (n < 128) && rem < min) {
811                         p0 = k;
812                         p1 = n;
813                         min = rem;
814                 }
815         }
816         if (!p0 || !p1)
817                 return 1;
818
819         param[0] = p0;
820         param[1] = p1;
821         param[2] = p2;
822
823         return 0;
824 }
825
826
827 /*
828  * This routine takes a user-supplied var, and picks the best vmode/cmode
829  * from it.
830  */
831
832 static int control_var_to_par(struct fb_var_screeninfo *var,
833         struct fb_par_control *par, const struct fb_info *fb_info)
834 {
835         int cmode, piped_diff, hstep;
836         unsigned hperiod, hssync, hsblank, hesync, heblank, piped, heq, hlfln,
837                  hserr, vperiod, vssync, vesync, veblank, vsblank, vswin, vewin;
838         unsigned long pixclock;
839         struct fb_info_control *p = (struct fb_info_control *) fb_info;
840         struct control_regvals *r = &par->regvals;
841
842         switch (var->bits_per_pixel) {
843         case 8:
844                 par->cmode = CMODE_8;
845                 if (p->total_vram > 0x200000) {
846                         r->mode = 3;
847                         r->radacal_ctrl = 0x20;
848                         piped_diff = 13;
849                 } else {
850                         r->mode = 2;
851                         r->radacal_ctrl = 0x10;
852                         piped_diff = 9;
853                 }
854                 break;
855         case 15:
856         case 16:
857                 par->cmode = CMODE_16;
858                 if (p->total_vram > 0x200000) {
859                         r->mode = 2;
860                         r->radacal_ctrl = 0x24;
861                         piped_diff = 5;
862                 } else {
863                         r->mode = 1;
864                         r->radacal_ctrl = 0x14;
865                         piped_diff = 3;
866                 }
867                 break;
868         case 32:
869                 par->cmode = CMODE_32;
870                 if (p->total_vram > 0x200000) {
871                         r->mode = 1;
872                         r->radacal_ctrl = 0x28;
873                 } else {
874                         r->mode = 0;
875                         r->radacal_ctrl = 0x18;
876                 }
877                 piped_diff = 1;
878                 break;
879         default:
880                 return -EINVAL;
881         }
882
883         /*
884          * adjust xres and vxres so that the corresponding memory widths are
885          * 32-byte aligned
886          */
887         hstep = 31 >> par->cmode;
888         par->xres = (var->xres + hstep) & ~hstep;
889         par->vxres = (var->xres_virtual + hstep) & ~hstep;
890         par->xoffset = (var->xoffset + hstep) & ~hstep;
891         if (par->vxres < par->xres)
892                 par->vxres = par->xres;
893         par->pitch = par->vxres << par->cmode;
894
895         par->yres = var->yres;
896         par->vyres = var->yres_virtual;
897         par->yoffset = var->yoffset;
898         if (par->vyres < par->yres)
899                 par->vyres = par->yres;
900
901         par->sync = var->sync;
902
903         if (par->pitch * par->vyres + CTRLFB_OFF > p->total_vram)
904                 return -EINVAL;
905
906         if (par->xoffset + par->xres > par->vxres)
907                 par->xoffset = par->vxres - par->xres;
908         if (par->yoffset + par->yres > par->vyres)
909                 par->yoffset = par->vyres - par->yres;
910
911         pixclock = (var->pixclock < CONTROL_PIXCLOCK_MIN)? CONTROL_PIXCLOCK_MIN:
912                    var->pixclock;
913         if (calc_clock_params(pixclock, r->clock_params))
914                 return -EINVAL;
915
916         hperiod = ((var->left_margin + par->xres + var->right_margin
917                     + var->hsync_len) >> 1) - 2;
918         hssync = hperiod + 1;
919         hsblank = hssync - (var->right_margin >> 1);
920         hesync = (var->hsync_len >> 1) - 1;
921         heblank = (var->left_margin >> 1) + hesync;
922         piped = heblank - piped_diff;
923         heq = var->hsync_len >> 2;
924         hlfln = (hperiod+2) >> 1;
925         hserr = hssync-hesync;
926         vperiod = (var->vsync_len + var->lower_margin + par->yres
927                    + var->upper_margin) << 1;
928         vssync = vperiod - 2;
929         vesync = (var->vsync_len << 1) - vperiod + vssync;
930         veblank = (var->upper_margin << 1) + vesync;
931         vsblank = vssync - (var->lower_margin << 1);
932         vswin = (vsblank+vssync) >> 1;
933         vewin = (vesync+veblank) >> 1;
934
935         r->regs[0] = vswin;
936         r->regs[1] = vsblank;
937         r->regs[2] = veblank;
938         r->regs[3] = vewin;
939         r->regs[4] = vesync;
940         r->regs[5] = vssync;
941         r->regs[6] = vperiod;
942         r->regs[7] = piped;
943         r->regs[8] = hperiod;
944         r->regs[9] = hsblank;
945         r->regs[10] = heblank;
946         r->regs[11] = hesync;
947         r->regs[12] = hssync;
948         r->regs[13] = heq;
949         r->regs[14] = hlfln;
950         r->regs[15] = hserr;
951
952         if (par->xres >= 1280 && par->cmode >= CMODE_16)
953                 par->ctrl = 0x7f;
954         else
955                 par->ctrl = 0x3b;
956
957         if (mac_var_to_vmode(var, &par->vmode, &cmode))
958                 par->vmode = 0;
959
960         return 0;
961 }
962
963
964 /*
965  * Convert hardware data in par to an fb_var_screeninfo
966  */
967
968 static void control_par_to_var(struct fb_par_control *par, struct fb_var_screeninfo *var)
969 {
970         struct control_regints *rv;
971         
972         rv = (struct control_regints *) par->regvals.regs;
973         
974         memset(var, 0, sizeof(*var));
975         var->xres = par->xres;
976         var->yres = par->yres;
977         var->xres_virtual = par->vxres;
978         var->yres_virtual = par->vyres;
979         var->xoffset = par->xoffset;
980         var->yoffset = par->yoffset;
981         
982         switch(par->cmode) {
983         default:
984         case CMODE_8:
985                 var->bits_per_pixel = 8;
986                 var->red.length = 8;
987                 var->green.length = 8;
988                 var->blue.length = 8;
989                 break;
990         case CMODE_16:  /* RGB 555 */
991                 var->bits_per_pixel = 16;
992                 var->red.offset = 10;
993                 var->red.length = 5;
994                 var->green.offset = 5;
995                 var->green.length = 5;
996                 var->blue.length = 5;
997                 break;
998         case CMODE_32:  /* RGB 888 */
999                 var->bits_per_pixel = 32;
1000                 var->red.offset = 16;
1001                 var->red.length = 8;
1002                 var->green.offset = 8;
1003                 var->green.length = 8;
1004                 var->blue.length = 8;
1005                 var->transp.offset = 24;
1006                 var->transp.length = 8;
1007                 break;
1008         }
1009         var->height = -1;
1010         var->width = -1;
1011         var->vmode = FB_VMODE_NONINTERLACED;
1012
1013         var->left_margin = (rv->heblank - rv->hesync) << 1;
1014         var->right_margin = (rv->hssync - rv->hsblank) << 1;
1015         var->hsync_len = (rv->hperiod + 2 - rv->hssync + rv->hesync) << 1;
1016
1017         var->upper_margin = (rv->veblank - rv->vesync) >> 1;
1018         var->lower_margin = (rv->vssync - rv->vsblank) >> 1;
1019         var->vsync_len = (rv->vperiod - rv->vssync + rv->vesync) >> 1;
1020
1021         var->sync = par->sync;
1022
1023         /*
1024          * 10^12 * clock_params[0] / (3906400 * clock_params[1]
1025          *                            * 2^clock_params[2])
1026          * (10^12 * clock_params[0] / (3906400 * clock_params[1]))
1027          * >> clock_params[2]
1028          */
1029         /* (255990.17 * clock_params[0] / clock_params[1]) >> clock_params[2] */
1030         var->pixclock = CONTROL_PIXCLOCK_BASE * par->regvals.clock_params[0];
1031         var->pixclock /= par->regvals.clock_params[1];
1032         var->pixclock >>= par->regvals.clock_params[2];
1033 }
1034
1035 /*
1036  * Set misc info vars for this driver
1037  */
1038 static void __init control_init_info(struct fb_info *info, struct fb_info_control *p)
1039 {
1040         /* Fill fb_info */
1041         info->par = &p->par;
1042         info->fbops = &controlfb_ops;
1043         info->pseudo_palette = p->pseudo_palette;
1044         info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
1045         info->screen_base = p->frame_buffer + CTRLFB_OFF;
1046
1047         fb_alloc_cmap(&info->cmap, 256, 0);
1048
1049         /* Fill fix common fields */
1050         strcpy(info->fix.id, "control");
1051         info->fix.mmio_start = p->control_regs_phys;
1052         info->fix.mmio_len = sizeof(struct control_regs);
1053         info->fix.type = FB_TYPE_PACKED_PIXELS;
1054         info->fix.smem_start = p->frame_buffer_phys + CTRLFB_OFF;
1055         info->fix.smem_len = p->total_vram - CTRLFB_OFF;
1056         info->fix.ywrapstep = 0;
1057         info->fix.type_aux = 0;
1058         info->fix.accel = FB_ACCEL_NONE;
1059 }
1060
1061
1062 static void control_cleanup(void)
1063 {
1064         struct fb_info_control  *p = control_fb;
1065
1066         if (!p)
1067                 return;
1068
1069         if (p->cmap_regs)
1070                 iounmap(p->cmap_regs);
1071         if (p->control_regs)
1072                 iounmap(p->control_regs);
1073         if (p->frame_buffer) {
1074                 if (p->control_use_bank2)
1075                         p->frame_buffer -= 0x600000;
1076                 iounmap(p->frame_buffer);
1077         }
1078         if (p->cmap_regs_phys)
1079                 release_mem_region(p->cmap_regs_phys, 0x1000);
1080         if (p->control_regs_phys)
1081                 release_mem_region(p->control_regs_phys, p->control_regs_size);
1082         if (p->fb_orig_base)
1083                 release_mem_region(p->fb_orig_base, p->fb_orig_size);
1084         kfree(p);
1085 }
1086
1087