make oldconfig will rebuild these...
[linux-2.4.21-pre4.git] / drivers / video / cyber2000fb.c
1 /*
2  *  linux/drivers/video/cyber2000fb.c
3  *
4  *  Copyright (C) 1998-2000 Russell King
5  *
6  *  MIPS and 50xx clock support
7  *  Copyright (C) 2001 Bradley D. LaRonde <brad@ltc.com>
8  *
9  *  32 bit support, text color and panning fixes for modes != 8 bit
10  *  Copyright (C) 2002 Denis Oliver Kropp <dok@directfb.org>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License version 2 as
14  * published by the Free Software Foundation.
15  *
16  * Intergraphics CyberPro 2000, 2010 and 5000 frame buffer device
17  *
18  * Based on cyberfb.c.
19  *
20  * Note that we now use the new fbcon fix, var and cmap scheme.  We do still
21  * have to check which console is the currently displayed one however, since
22  * especially for the colourmap stuff.  Once fbcon has been fully migrated,
23  * we can kill the last 5 references to cfb->currcon.
24  *
25  * We also use the new hotplug PCI subsystem.  I'm not sure if there are any
26  * such cards, but I'm erring on the side of caution.  We don't want to go
27  * pop just because someone does have one.
28  *
29  * Note that this doesn't work fully in the case of multiple CyberPro cards
30  * with grabbers.  We currently can only attach to the first CyberPro card
31  * found.
32  */
33 #include <linux/config.h>
34 #include <linux/module.h>
35 #include <linux/kernel.h>
36 #include <linux/errno.h>
37 #include <linux/string.h>
38 #include <linux/mm.h>
39 #include <linux/tty.h>
40 #include <linux/slab.h>
41 #include <linux/delay.h>
42 #include <linux/fb.h>
43 #include <linux/pci.h>
44 #include <linux/init.h>
45
46 #include <asm/io.h>
47 #include <asm/irq.h>
48 #include <asm/pgtable.h>
49 #include <asm/system.h>
50 #include <asm/uaccess.h>
51
52 #include <video/fbcon.h>
53 #include <video/fbcon-cfb8.h>
54 #include <video/fbcon-cfb16.h>
55 #include <video/fbcon-cfb24.h>
56 #include <video/fbcon-cfb32.h>
57
58 /*
59  * Define this if you don't want RGB565, but RGB555 for 16bpp displays.
60  */
61 /*#define CFB16_IS_CFB15*/
62
63 #include "cyber2000fb.h"
64
65 struct cfb_info {
66         struct fb_info          fb;
67         struct display_switch   *dispsw;
68         struct pci_dev          *dev;
69         unsigned char           *region;
70         unsigned char           *regs;
71         signed int              currcon;
72         int                     func_use_count;
73         u_long                  ref_ps;
74
75         /*
76          * Clock divisors
77          */
78         u_int                   divisors[4];
79
80         struct {
81                 u8 red, green, blue;
82         } palette[NR_PALETTE];
83
84         u_char                  mem_ctl1;
85         u_char                  mem_ctl2;
86         u_char                  mclk_mult;
87         u_char                  mclk_div;
88 };
89
90 static char default_font_storage[40];
91 static char *default_font = "Acorn8x8";
92 MODULE_PARM(default_font, "s");
93 MODULE_PARM_DESC(default_font, "Default font name");
94
95 /*
96  * Our access methods.
97  */
98 #define cyber2000fb_writel(val,reg,cfb) writel(val, (cfb)->regs + (reg))
99 #define cyber2000fb_writew(val,reg,cfb) writew(val, (cfb)->regs + (reg))
100 #define cyber2000fb_writeb(val,reg,cfb) writeb(val, (cfb)->regs + (reg))
101
102 #define cyber2000fb_readb(reg,cfb)      readb((cfb)->regs + (reg))
103
104 static inline void
105 cyber2000_crtcw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
106 {
107         cyber2000fb_writew((reg & 255) | val << 8, 0x3d4, cfb);
108 }
109
110 static inline void
111 cyber2000_grphw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
112 {
113         cyber2000fb_writew((reg & 255) | val << 8, 0x3ce, cfb);
114 }
115
116 static inline unsigned int
117 cyber2000_grphr(unsigned int reg, struct cfb_info *cfb)
118 {
119         cyber2000fb_writeb(reg, 0x3ce, cfb);
120         return cyber2000fb_readb(0x3cf, cfb);
121 }
122
123 static inline void
124 cyber2000_attrw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
125 {
126         cyber2000fb_readb(0x3da, cfb);
127         cyber2000fb_writeb(reg, 0x3c0, cfb);
128         cyber2000fb_readb(0x3c1, cfb);
129         cyber2000fb_writeb(val, 0x3c0, cfb);
130 }
131
132 static inline void
133 cyber2000_seqw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
134 {
135         cyber2000fb_writew((reg & 255) | val << 8, 0x3c4, cfb);
136 }
137
138 /* -------------------- Hardware specific routines ------------------------- */
139
140 /*
141  * Hardware Cyber2000 Acceleration
142  */
143 static void cyber2000_accel_wait(struct cfb_info *cfb)
144 {
145         int count = 100000;
146
147         while (cyber2000fb_readb(CO_REG_CONTROL, cfb) & 0x80) {
148                 if (!count--) {
149                         debug_printf("accel_wait timed out\n");
150                         cyber2000fb_writeb(0, CO_REG_CONTROL, cfb);
151                         return;
152                 }
153                 udelay(1);
154         }
155 }
156
157 static void cyber2000_accel_setup(struct display *p)
158 {
159         struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
160
161         cfb->dispsw->setup(p);
162 }
163
164 static void
165 cyber2000_accel_bmove(struct display *p, int sy, int sx, int dy, int dx,
166                       int height, int width)
167 {
168         struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
169         struct fb_var_screeninfo *var = &p->fb_info->var;
170         u_long src, dst;
171         u_int fh, fw;
172         int cmd = CO_CMD_L_PATTERN_FGCOL;
173
174         fw    = fontwidth(p);
175         sx    *= fw;
176         dx    *= fw;
177         width *= fw;
178         width -= 1;
179
180         if (sx < dx) {
181                 sx += width;
182                 dx += width;
183                 cmd |= CO_CMD_L_INC_LEFT;
184         }
185
186         fh     = fontheight(p);
187         sy     *= fh;
188         dy     *= fh;
189         height *= fh;
190         height -= 1;
191
192         if (sy < dy) {
193                 sy += height;
194                 dy += height;
195                 cmd |= CO_CMD_L_INC_UP;
196         }
197
198         src    = sx + sy * var->xres_virtual;
199         dst    = dx + dy * var->xres_virtual;
200
201         cyber2000_accel_wait(cfb);
202         cyber2000fb_writeb(0x00,  CO_REG_CONTROL, cfb);
203         cyber2000fb_writeb(0x03,  CO_REG_FORE_MIX, cfb);
204         cyber2000fb_writew(width, CO_REG_WIDTH, cfb);
205
206         if (var->bits_per_pixel != 24) {
207                 cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
208                 cyber2000fb_writel(src, CO_REG_SRC_PTR, cfb);
209         } else {
210                 cyber2000fb_writel(dst * 3, CO_REG_DEST_PTR, cfb);
211                 cyber2000fb_writeb(dst,     CO_REG_X_PHASE, cfb);
212                 cyber2000fb_writel(src * 3, CO_REG_SRC_PTR, cfb);
213         }
214
215         cyber2000fb_writew(height, CO_REG_HEIGHT, cfb);
216         cyber2000fb_writew(cmd,    CO_REG_CMD_L, cfb);
217         cyber2000fb_writew(0x2800, CO_REG_CMD_H, cfb);
218 }
219
220 static void
221 cyber2000_accel_clear(struct vc_data *conp, struct display *p, int sy, int sx,
222                       int height, int width)
223 {
224         struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
225         struct fb_var_screeninfo *var = &p->fb_info->var;
226         u_long dst;
227         u_int fw, fh;
228         u32 bgx = attr_bgcol_ec(p, conp);
229
230         fw = fontwidth(p);
231         fh = fontheight(p);
232
233         dst    = sx * fw + sy * var->xres_virtual * fh;
234         width  = width * fw - 1;
235         height = height * fh - 1;
236
237         cyber2000_accel_wait(cfb);
238         cyber2000fb_writeb(0x00,   CO_REG_CONTROL,  cfb);
239         cyber2000fb_writeb(0x03,   CO_REG_FORE_MIX, cfb);
240         cyber2000fb_writew(width,  CO_REG_WIDTH,    cfb);
241         cyber2000fb_writew(height, CO_REG_HEIGHT,   cfb);
242
243         switch (var->bits_per_pixel) {
244         case 15:
245         case 16:
246                 bgx = ((u16 *)p->dispsw_data)[bgx];
247         case 8:
248                 cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
249                 break;
250
251         case 24:
252                 cyber2000fb_writel(dst * 3, CO_REG_DEST_PTR, cfb);
253                 cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb);
254                 bgx = ((u32 *)p->dispsw_data)[bgx];
255                 break;
256
257         case 32:
258                 bgx = ((u32 *)p->dispsw_data)[bgx];
259                 cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
260                 break;
261         }
262
263         cyber2000fb_writel(bgx, CO_REG_FOREGROUND, cfb);
264         cyber2000fb_writew(CO_CMD_L_PATTERN_FGCOL, CO_REG_CMD_L, cfb);
265         cyber2000fb_writew(0x0800, CO_REG_CMD_H, cfb);
266 }
267
268 static void
269 cyber2000_accel_putc(struct vc_data *conp, struct display *p, int c,
270                      int yy, int xx)
271 {
272         struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
273
274         cyber2000_accel_wait(cfb);
275         cfb->dispsw->putc(conp, p, c, yy, xx);
276 }
277
278 static void
279 cyber2000_accel_putcs(struct vc_data *conp, struct display *p,
280                       const unsigned short *s, int count, int yy, int xx)
281 {
282         struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
283
284         cyber2000_accel_wait(cfb);
285         cfb->dispsw->putcs(conp, p, s, count, yy, xx);
286 }
287
288 static void cyber2000_accel_revc(struct display *p, int xx, int yy)
289 {
290         struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
291
292         cyber2000_accel_wait(cfb);
293         cfb->dispsw->revc(p, xx, yy);
294 }
295
296 static void
297 cyber2000_accel_clear_margins(struct vc_data *conp, struct display *p,
298                               int bottom_only)
299 {
300         struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
301
302         cfb->dispsw->clear_margins(conp, p, bottom_only);
303 }
304
305 static struct display_switch fbcon_cyber_accel = {
306         setup:          cyber2000_accel_setup,
307         bmove:          cyber2000_accel_bmove,
308         clear:          cyber2000_accel_clear,
309         putc:           cyber2000_accel_putc,
310         putcs:          cyber2000_accel_putcs,
311         revc:           cyber2000_accel_revc,
312         clear_margins:  cyber2000_accel_clear_margins,
313         fontwidthmask:  FONTWIDTH(8)|FONTWIDTH(16)
314 };
315
316 /*
317  *    Set a single color register. Return != 0 for invalid regno.
318  */
319 static int
320 cyber2000_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
321                     u_int transp, struct fb_info *info)
322 {
323         struct cfb_info *cfb = (struct cfb_info *)info;
324
325         u_int alpha = transp ^ 0xFFFF;
326
327         if (regno >= NR_PALETTE)
328                 return 1;
329
330         red   >>= 8;
331         green >>= 8;
332         blue  >>= 8;
333         alpha >>= 8;
334
335         cfb->palette[regno].red   = red;
336         cfb->palette[regno].green = green;
337         cfb->palette[regno].blue  = blue;
338
339         switch (cfb->fb.var.bits_per_pixel) {
340 #ifdef FBCON_HAS_CFB8
341         case 8:
342                 cyber2000fb_writeb(regno, 0x3c8, cfb);
343                 cyber2000fb_writeb(red,   0x3c9, cfb);
344                 cyber2000fb_writeb(green, 0x3c9, cfb);
345                 cyber2000fb_writeb(blue,  0x3c9, cfb);
346                 break;
347 #endif
348
349 #ifdef FBCON_HAS_CFB16
350         case 16:
351 #ifndef CFB16_IS_CFB15
352                 if (regno < 64) {
353                         /* write green */
354                         cyber2000fb_writeb(regno << 2, 0x3c8, cfb);
355                         cyber2000fb_writeb(cfb->palette[regno >> 1].red, 0x3c9, cfb);
356                         cyber2000fb_writeb(green, 0x3c9, cfb);
357                         cyber2000fb_writeb(cfb->palette[regno >> 1].blue, 0x3c9, cfb);
358                 }
359
360                 if (regno < 32) {
361                         /* write red,blue */
362                         cyber2000fb_writeb(regno << 3, 0x3c8, cfb);
363                         cyber2000fb_writeb(red, 0x3c9, cfb);
364                         cyber2000fb_writeb(cfb->palette[regno << 1].green, 0x3c9, cfb);
365                         cyber2000fb_writeb(blue, 0x3c9, cfb);
366                 }
367
368                 if (regno < 16)
369                         ((u16 *)cfb->fb.pseudo_palette)[regno] =
370                                 ((red   << 8) & 0xf800) |
371                                 ((green << 3) & 0x07e0) |
372                                 ((blue  >> 3));
373                 break;
374 #endif
375
376         case 15:
377                 if (regno < 32) {
378                         cyber2000fb_writeb(regno << 3, 0x3c8, cfb);
379                         cyber2000fb_writeb(red, 0x3c9, cfb);
380                         cyber2000fb_writeb(green, 0x3c9, cfb);
381                         cyber2000fb_writeb(blue, 0x3c9, cfb);
382                 }
383                 if (regno < 16)
384                         ((u16 *)cfb->fb.pseudo_palette)[regno] =
385                                 ((red   << 7) & 0x7c00) |
386                                 ((green << 2) & 0x03e0) |
387                                 ((blue  >> 3));
388                 break;
389
390 #endif
391
392 #ifdef FBCON_HAS_CFB24
393         case 24:
394                 cyber2000fb_writeb(regno, 0x3c8, cfb);
395                 cyber2000fb_writeb(red,   0x3c9, cfb);
396                 cyber2000fb_writeb(green, 0x3c9, cfb);
397                 cyber2000fb_writeb(blue,  0x3c9, cfb);
398
399                 if (regno < 16)
400                         ((u32 *)cfb->fb.pseudo_palette)[regno] =
401                                 (red << 16) | (green << 8) | blue;
402                 break;
403 #endif
404
405 #ifdef FBCON_HAS_CFB32
406         case 32:
407                 cyber2000fb_writeb(regno, 0x3c8, cfb);
408                 cyber2000fb_writeb(red,   0x3c9, cfb);
409                 cyber2000fb_writeb(green, 0x3c9, cfb);
410                 cyber2000fb_writeb(blue,  0x3c9, cfb);
411
412                 if (regno < 16)
413                         ((u32 *)cfb->fb.pseudo_palette)[regno] =
414                                 (alpha << 24) | (red << 16) | (green << 8) | blue;
415                 break;
416 #endif
417
418         default:
419                 return 1;
420         }
421
422         return 0;
423 }
424
425 struct par_info {
426         /*
427          * Hardware
428          */
429         u_char  clock_mult;
430         u_char  clock_div;
431         u_char  visualid;
432         u_char  pixformat;
433         u_char  crtc_ofl;
434         u_char  crtc[19];
435         u_int   width;
436         u_int   pitch;
437         u_int   fetch;
438
439         /*
440          * Other
441          */
442         u_char  palette_ctrl;
443         u_int   vmode;
444 };
445
446 static const u_char crtc_idx[] = {
447         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
448         0x08, 0x09,
449         0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18
450 };
451
452 static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw)
453 {
454         u_int i;
455
456         /*
457          * Blank palette
458          */
459         for (i = 0; i < NR_PALETTE; i++) {
460                 cyber2000fb_writeb(i, 0x3c8, cfb);
461                 cyber2000fb_writeb(0, 0x3c9, cfb);
462                 cyber2000fb_writeb(0, 0x3c9, cfb);
463                 cyber2000fb_writeb(0, 0x3c9, cfb);
464         }
465
466         cyber2000fb_writeb(0xef, 0x3c2, cfb);
467         cyber2000_crtcw(0x11, 0x0b, cfb);
468         cyber2000_attrw(0x11, 0x00, cfb);
469
470         cyber2000_seqw(0x00, 0x01, cfb);
471         cyber2000_seqw(0x01, 0x01, cfb);
472         cyber2000_seqw(0x02, 0x0f, cfb);
473         cyber2000_seqw(0x03, 0x00, cfb);
474         cyber2000_seqw(0x04, 0x0e, cfb);
475         cyber2000_seqw(0x00, 0x03, cfb);
476
477         for (i = 0; i < sizeof(crtc_idx); i++)
478                 cyber2000_crtcw(crtc_idx[i], hw->crtc[i], cfb);
479
480         for (i = 0x0a; i < 0x10; i++)
481                 cyber2000_crtcw(i, 0, cfb);
482
483         cyber2000_grphw(0x11, hw->crtc_ofl, cfb);
484         cyber2000_grphw(0x00, 0x00, cfb);
485         cyber2000_grphw(0x01, 0x00, cfb);
486         cyber2000_grphw(0x02, 0x00, cfb);
487         cyber2000_grphw(0x03, 0x00, cfb);
488         cyber2000_grphw(0x04, 0x00, cfb);
489         cyber2000_grphw(0x05, 0x60, cfb);
490         cyber2000_grphw(0x06, 0x05, cfb);
491         cyber2000_grphw(0x07, 0x0f, cfb);
492         cyber2000_grphw(0x08, 0xff, cfb);
493
494         /* Attribute controller registers */
495         for (i = 0; i < 16; i++)
496                 cyber2000_attrw(i, i, cfb);
497
498         cyber2000_attrw(0x10, 0x01, cfb);
499         cyber2000_attrw(0x11, 0x00, cfb);
500         cyber2000_attrw(0x12, 0x0f, cfb);
501         cyber2000_attrw(0x13, 0x00, cfb);
502         cyber2000_attrw(0x14, 0x00, cfb);
503
504         /* woody: set the interlaced bit... */
505         /* FIXME: what about doublescan? */
506         cyber2000fb_writeb(0x11, 0x3ce, cfb);
507         i = cyber2000fb_readb(0x3cf, cfb);
508         if (hw->vmode == FB_VMODE_INTERLACED)
509                 i |= 0x20;
510         else
511                 i &= ~0x20;
512         cyber2000fb_writeb(i, 0x3cf, cfb);
513
514         /* PLL registers */
515         cyber2000_grphw(DCLK_MULT, hw->clock_mult, cfb);
516         cyber2000_grphw(DCLK_DIV,  hw->clock_div, cfb);
517         cyber2000_grphw(MCLK_MULT, cfb->mclk_mult, cfb);
518         cyber2000_grphw(MCLK_DIV,  cfb->mclk_div, cfb);
519         cyber2000_grphw(0x90, 0x01, cfb);
520         cyber2000_grphw(0xb9, 0x80, cfb);
521         cyber2000_grphw(0xb9, 0x00, cfb);
522
523         cyber2000fb_writeb(0x56, 0x3ce, cfb);
524         i = cyber2000fb_readb(0x3cf, cfb);
525         cyber2000fb_writeb(i | 4, 0x3cf, cfb);
526         cyber2000fb_writeb(hw->palette_ctrl, 0x3c6, cfb);
527         cyber2000fb_writeb(i,    0x3cf, cfb);
528
529         cyber2000fb_writeb(0x20, 0x3c0, cfb);
530         cyber2000fb_writeb(0xff, 0x3c6, cfb);
531
532         cyber2000_grphw(0x14, hw->fetch, cfb);
533         cyber2000_grphw(0x15, ((hw->fetch >> 8) & 0x03) |
534                               ((hw->pitch >> 4) & 0x30), cfb);
535         cyber2000_grphw(0x77, hw->visualid, cfb);
536
537         /* make sure we stay in linear mode */
538         cyber2000_grphw(0x33, 0x0d, cfb);
539
540         /*
541          * Set up accelerator registers
542          */
543         cyber2000fb_writew(hw->width,     CO_REG_SRC_WIDTH,  cfb);
544         cyber2000fb_writew(hw->width,     CO_REG_DEST_WIDTH, cfb);
545         cyber2000fb_writeb(hw->pixformat, CO_REG_PIX_FORMAT, cfb);
546 }
547
548 static inline int
549 cyber2000fb_update_start(struct cfb_info *cfb, struct fb_var_screeninfo *var)
550 {
551         u_int base;
552
553         base = var->yoffset * var->xres_virtual + var->xoffset;
554
555         /* have to be careful, because bits_per_pixel might be 15
556            in this version of the driver -- dok@directfb.org 2002/06/13 */
557         base *= (var->bits_per_pixel + 7) >> 3;
558
559         base >>= 2;
560
561         if (base >= 1 << 20)
562                 return -EINVAL;
563
564         cyber2000_grphw(0x10, base >> 16 | 0x10, cfb);
565         cyber2000_crtcw(0x0c, base >> 8, cfb);
566         cyber2000_crtcw(0x0d, base, cfb);
567
568         return 0;
569 }
570
571 /*
572  * Set the Colormap
573  */
574 static int
575 cyber2000fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
576                      struct fb_info *info)
577 {
578         struct cfb_info *cfb = (struct cfb_info *)info;
579         struct fb_cmap *dcmap = &fb_display[con].cmap;
580         int err = 0;
581
582         /* no colormap allocated? */
583         if (!dcmap->len) {
584                 int size;
585
586                 if (cfb->fb.var.bits_per_pixel == 16)
587                         size = 32;
588                 else
589                         size = 256;
590
591                 err = fb_alloc_cmap(dcmap, size, 0);
592         }
593
594         /*
595          * we should be able to remove this test once fbcon has been
596          * "improved" --rmk
597          */
598         if (!err && con == cfb->currcon) {
599                 err = fb_set_cmap(cmap, kspc, cyber2000_setcolreg, &cfb->fb);
600                 dcmap = &cfb->fb.cmap;
601         }
602
603         if (!err)
604                 fb_copy_cmap(cmap, dcmap, kspc ? 0 : 1);
605
606         return err;
607 }
608
609 static int
610 cyber2000fb_decode_crtc(struct par_info *hw, struct cfb_info *cfb,
611                         struct fb_var_screeninfo *var)
612 {
613         u_int Htotal, Hblankend, Hsyncend;
614         u_int Vtotal, Vdispend, Vblankstart, Vblankend, Vsyncstart, Vsyncend;
615 #define BIT(v,b1,m,b2) (((v >> b1) & m) << b2)
616
617         hw->crtc[13] = hw->pitch;
618         hw->crtc[17] = 0xe3;
619         hw->crtc[14] = 0;
620         hw->crtc[8]  = 0;
621
622         Htotal      = var->xres + var->right_margin +
623                       var->hsync_len + var->left_margin;
624
625         if (Htotal > 2080)
626                 return -EINVAL;
627
628         hw->crtc[0] = (Htotal >> 3) - 5;
629         hw->crtc[1] = (var->xres >> 3) - 1;
630         hw->crtc[2] = var->xres >> 3;
631         hw->crtc[4] = (var->xres + var->right_margin) >> 3;
632
633         Hblankend   = (Htotal - 4*8) >> 3;
634
635         hw->crtc[3] = BIT(Hblankend,  0, 0x1f,  0) |
636                       BIT(1,          0, 0x01,  7);
637
638         Hsyncend    = (var->xres + var->right_margin + var->hsync_len) >> 3;
639
640         hw->crtc[5] = BIT(Hsyncend,   0, 0x1f,  0) |
641                       BIT(Hblankend,  5, 0x01,  7);
642
643         Vdispend    = var->yres - 1;
644         Vsyncstart  = var->yres + var->lower_margin;
645         Vsyncend    = var->yres + var->lower_margin + var->vsync_len;
646         Vtotal      = var->yres + var->lower_margin + var->vsync_len +
647                       var->upper_margin - 2;
648
649         if (Vtotal > 2047)
650                 return -EINVAL;
651
652         Vblankstart = var->yres + 6;
653         Vblankend   = Vtotal - 10;
654
655         hw->crtc[6]  = Vtotal;
656         hw->crtc[7]  = BIT(Vtotal,     8, 0x01,  0) |
657                         BIT(Vdispend,   8, 0x01,  1) |
658                         BIT(Vsyncstart, 8, 0x01,  2) |
659                         BIT(Vblankstart,8, 0x01,  3) |
660                         BIT(1,          0, 0x01,  4) |
661                         BIT(Vtotal,     9, 0x01,  5) |
662                         BIT(Vdispend,   9, 0x01,  6) |
663                         BIT(Vsyncstart, 9, 0x01,  7);
664         hw->crtc[9]  = BIT(0,          0, 0x1f,  0) |
665                         BIT(Vblankstart,9, 0x01,  5) |
666                         BIT(1,          0, 0x01,  6);
667         hw->crtc[10] = Vsyncstart;
668         hw->crtc[11] = BIT(Vsyncend,   0, 0x0f,  0) |
669                        BIT(1,          0, 0x01,  7);
670         hw->crtc[12] = Vdispend;
671         hw->crtc[15] = Vblankstart;
672         hw->crtc[16] = Vblankend;
673         hw->crtc[18] = 0xff;
674
675         /* overflow - graphics reg 0x11 */
676         /* 0=VTOTAL:10 1=VDEND:10 2=VRSTART:10 3=VBSTART:10
677          * 4=LINECOMP:10 5-IVIDEO 6=FIXCNT
678          */
679         hw->crtc_ofl =
680                 BIT(Vtotal,     10, 0x01,  0) |
681                 BIT(Vdispend,   10, 0x01,  1) |
682                 BIT(Vsyncstart, 10, 0x01,  2) |
683                 BIT(Vblankstart,10, 0x01,  3) |
684                 1 << 4;
685
686         return 0;
687 }
688
689 /*
690  * The following was discovered by a good monitor, bit twiddling, theorising
691  * and but mostly luck.  Strangely, it looks like everyone elses' PLL!
692  *
693  * Clock registers:
694  *   fclock = fpll / div2
695  *   fpll   = fref * mult / div1
696  * where:
697  *   fref = 14.318MHz (69842ps)
698  *   mult = reg0xb0.7:0
699  *   div1 = (reg0xb1.5:0 + 1)
700  *   div2 =  2^(reg0xb1.7:6)
701  *   fpll should be between 115 and 260 MHz
702  *  (8696ps and 3846ps)
703  */
704 static int
705 cyber2000fb_decode_clock(struct par_info *hw, struct cfb_info *cfb,
706                          struct fb_var_screeninfo *var)
707 {
708         u_long pll_ps = var->pixclock;
709         const u_long ref_ps = cfb->ref_ps;
710         u_int div2, t_div1, best_div1, best_mult;
711         int best_diff;
712         int vco;
713
714         /*
715          * Step 1:
716          *   find div2 such that 115MHz < fpll < 260MHz
717          *   and 0 <= div2 < 4
718          */
719         for (div2 = 0; div2 < 4; div2++) {
720                 u_long new_pll;
721
722                 new_pll = pll_ps / cfb->divisors[div2];
723                 if (8696 > new_pll && new_pll > 3846) {
724                         pll_ps = new_pll;
725                         break;
726                 }
727         }
728
729         if (div2 == 4)
730                 return -EINVAL;
731
732         /*
733          * Step 2:
734          *  Given pll_ps and ref_ps, find:
735          *    pll_ps * 0.995 < pll_ps_calc < pll_ps * 1.005
736          *  where { 1 < best_div1 < 32, 1 < best_mult < 256 }
737          *    pll_ps_calc = best_div1 / (ref_ps * best_mult)
738          */
739         best_diff = 0x7fffffff;
740         best_mult = 32;
741         best_div1 = 255;
742         for (t_div1 = 32; t_div1 > 1; t_div1 -= 1) {
743                 u_int rr, t_mult, t_pll_ps;
744                 int diff;
745
746                 /*
747                  * Find the multiplier for this divisor
748                  */
749                 rr = ref_ps * t_div1;
750                 t_mult = (rr + pll_ps / 2) / pll_ps;
751
752                 /*
753                  * Is the multiplier within the correct range?
754                  */
755                 if (t_mult > 256 || t_mult < 2)
756                         continue;
757
758                 /*
759                  * Calculate the actual clock period from this multiplier
760                  * and divisor, and estimate the error.
761                  */
762                 t_pll_ps = (rr + t_mult / 2) / t_mult;
763                 diff = pll_ps - t_pll_ps;
764                 if (diff < 0)
765                         diff = -diff;
766
767                 if (diff < best_diff) {
768                         best_diff = diff;
769                         best_mult = t_mult;
770                         best_div1 = t_div1;
771                 }
772
773                 /*
774                  * If we hit an exact value, there is no point in continuing.
775                  */
776                 if (diff == 0)
777                         break;
778         }
779
780         /*
781          * Step 3:
782          *  combine values
783          */
784         hw->clock_mult = best_mult - 1;
785         hw->clock_div  = div2 << 6 | (best_div1 - 1);
786
787         vco = ref_ps * best_div1 / best_mult;
788         if ((ref_ps == 40690) && (vco < 5556))
789                 /* Set VFSEL when VCO > 180MHz (5.556 ps). */
790                 hw->clock_div |= DCLK_DIV_VFSEL;
791
792         return 0;
793 }
794
795 /*
796  * Decode the info required for the hardware.
797  * This involves the PLL parameters for the dot clock,
798  * CRTC registers, and accelerator settings.
799  */
800 static int
801 cyber2000fb_decode_var(struct fb_var_screeninfo *var, struct cfb_info *cfb,
802                        struct par_info *hw)
803 {
804         int err;
805
806         hw->width = var->xres_virtual;
807         hw->palette_ctrl = 0x06;
808         hw->vmode = var->vmode;
809
810         switch (var->bits_per_pixel) {
811 #ifdef FBCON_HAS_CFB8
812         case 8: /* PSEUDOCOLOUR, 256 */
813                 hw->pixformat           = PIXFORMAT_8BPP;
814                 hw->visualid            = VISUALID_256;
815                 hw->pitch               = hw->width >> 3;
816                 break;
817 #endif
818 #ifdef FBCON_HAS_CFB16
819         case 16:/* DIRECTCOLOUR, 64k */
820 #ifndef CFB16_IS_CFB15
821                 hw->pixformat           = PIXFORMAT_16BPP;
822                 hw->visualid            = VISUALID_64K;
823                 hw->pitch               = hw->width >> 2;
824                 hw->palette_ctrl        |= 0x10;
825                 break;
826 #endif
827         case 15:/* DIRECTCOLOUR, 32k */
828                 hw->pixformat           = PIXFORMAT_16BPP;
829                 hw->visualid            = VISUALID_32K;
830                 hw->pitch               = hw->width >> 2;
831                 hw->palette_ctrl        |= 0x10;
832                 break;
833
834 #endif
835 #ifdef FBCON_HAS_CFB24
836         case 24:/* TRUECOLOUR, 16m */
837                 hw->pixformat           = PIXFORMAT_24BPP;
838                 hw->visualid            = VISUALID_16M;
839                 hw->width               *= 3;
840                 hw->pitch               = hw->width >> 3;
841                 hw->palette_ctrl        |= 0x10;
842                 break;
843 #endif
844 #ifdef FBCON_HAS_CFB32
845         case 32:/* TRUECOLOUR, 16m */
846                 hw->pixformat           = PIXFORMAT_32BPP;
847                 hw->visualid            = VISUALID_16M_32;
848                 hw->pitch               = hw->width >> 1;
849                 hw->palette_ctrl        |= 0x10;
850                 break;
851 #endif
852         default:
853                 return -EINVAL;
854         }
855
856         err = cyber2000fb_decode_clock(hw, cfb, var);
857         if (err)
858                 return err;
859
860         err = cyber2000fb_decode_crtc(hw, cfb, var);
861         if (err)
862                 return err;
863
864         hw->width -= 1;
865         hw->fetch = hw->pitch;
866         if (!(cfb->mem_ctl2 & MEM_CTL2_64BIT))
867                 hw->fetch <<= 1;
868         hw->fetch += 1;
869
870         return 0;
871 }
872
873 /*
874  *    Set the User Defined Part of the Display
875  */
876 static int
877 cyber2000fb_set_var(struct fb_var_screeninfo *var, int con,
878                     struct fb_info *info)
879 {
880         struct cfb_info *cfb = (struct cfb_info *)info;
881         struct display *display;
882         struct par_info hw;
883         int err, chgvar = 0;
884
885         /*
886          * CONUPDATE and SMOOTH_XPAN are equal.  However,
887          * SMOOTH_XPAN is only used internally by fbcon.
888          */
889         if (var->vmode & FB_VMODE_CONUPDATE) {
890                 var->vmode |= FB_VMODE_YWRAP;
891                 var->xoffset = cfb->fb.var.xoffset;
892                 var->yoffset = cfb->fb.var.yoffset;
893         }
894
895         err = cyber2000fb_decode_var(var, (struct cfb_info *)info, &hw);
896         if (err)
897                 return err;
898
899         if (var->activate & FB_ACTIVATE_TEST)
900                 return 0;
901
902         if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
903                 return -EINVAL;
904
905         if (cfb->fb.var.xres != var->xres)
906                 chgvar = 1;
907         if (cfb->fb.var.yres != var->yres)
908                 chgvar = 1;
909         if (cfb->fb.var.xres_virtual != var->xres_virtual)
910                 chgvar = 1;
911         if (cfb->fb.var.yres_virtual != var->yres_virtual)
912                 chgvar = 1;
913         if (cfb->fb.var.bits_per_pixel != var->bits_per_pixel)
914                 chgvar = 1;
915
916         if (con < 0) {
917                 display = cfb->fb.disp;
918                 chgvar = 0;
919         } else {
920                 display = fb_display + con;
921         }
922
923         var->red.msb_right      = 0;
924         var->green.msb_right    = 0;
925         var->blue.msb_right     = 0;
926
927         switch (var->bits_per_pixel) {
928 #ifdef FBCON_HAS_CFB8
929         case 8: /* PSEUDOCOLOUR, 256 */
930                 var->red.offset         = 0;
931                 var->red.length         = 8;
932                 var->green.offset       = 0;
933                 var->green.length       = 8;
934                 var->blue.offset        = 0;
935                 var->blue.length        = 8;
936
937                 cfb->fb.fix.visual      = FB_VISUAL_PSEUDOCOLOR;
938                 cfb->dispsw             = &fbcon_cfb8;
939                 display->dispsw_data    = NULL;
940                 display->next_line      = var->xres_virtual;
941                 break;
942 #endif
943 #ifdef FBCON_HAS_CFB16
944         case 16:/* DIRECTCOLOUR, 64k */
945 #ifndef CFB16_IS_CFB15
946                 var->red.offset         = 11;
947                 var->red.length         = 5;
948                 var->green.offset       = 5;
949                 var->green.length       = 6;
950                 var->blue.offset        = 0;
951                 var->blue.length        = 5;
952
953                 cfb->fb.fix.visual      = FB_VISUAL_DIRECTCOLOR;
954                 cfb->dispsw             = &fbcon_cfb16;
955                 display->dispsw_data    = cfb->fb.pseudo_palette;
956                 display->next_line      = var->xres_virtual * 2;
957                 break;
958 #endif
959         case 15:/* DIRECTCOLOUR, 32k */
960                 var->bits_per_pixel     = 15;
961                 var->red.offset         = 10;
962                 var->red.length         = 5;
963                 var->green.offset       = 5;
964                 var->green.length       = 5;
965                 var->blue.offset        = 0;
966                 var->blue.length        = 5;
967
968                 cfb->fb.fix.visual      = FB_VISUAL_DIRECTCOLOR;
969                 cfb->dispsw             = &fbcon_cfb16;
970                 display->dispsw_data    = cfb->fb.pseudo_palette;
971                 display->next_line      = var->xres_virtual * 2;
972                 break;
973 #endif
974 #ifdef FBCON_HAS_CFB24
975         case 24:/* TRUECOLOUR, 16m */
976                 var->red.offset         = 16;
977                 var->red.length         = 8;
978                 var->green.offset       = 8;
979                 var->green.length       = 8;
980                 var->blue.offset        = 0;
981                 var->blue.length        = 8;
982
983                 cfb->fb.fix.visual      = FB_VISUAL_TRUECOLOR;
984                 cfb->dispsw             = &fbcon_cfb24;
985                 display->dispsw_data    = cfb->fb.pseudo_palette;
986                 display->next_line      = var->xres_virtual * 3;
987                 break;
988 #endif
989 #ifdef FBCON_HAS_CFB32
990         case 32:/* TRUECOLOUR, 16m */
991                 var->transp.offset      = 24;
992                 var->transp.length      = 8;
993                 var->red.offset         = 16;
994                 var->red.length         = 8;
995                 var->green.offset       = 8;
996                 var->green.length       = 8;
997                 var->blue.offset        = 0;
998                 var->blue.length        = 8;
999
1000                 cfb->fb.fix.visual      = FB_VISUAL_TRUECOLOR;
1001                 cfb->dispsw             = &fbcon_cfb32;
1002                 display->dispsw_data    = cfb->fb.pseudo_palette;
1003                 display->next_line      = var->xres_virtual * 4;
1004                 break;
1005 #endif
1006         default:/* in theory this should never happen */
1007                 printk(KERN_WARNING "%s: no support for %dbpp\n",
1008                        cfb->fb.fix.id, var->bits_per_pixel);
1009                 cfb->dispsw = &fbcon_dummy;
1010                 break;
1011         }
1012
1013         if (var->accel_flags & FB_ACCELF_TEXT && cfb->dispsw != &fbcon_dummy)
1014                 display->dispsw = &fbcon_cyber_accel;
1015         else
1016                 display->dispsw = cfb->dispsw;
1017
1018         cfb->fb.fix.line_length = display->next_line;
1019
1020         display->screen_base    = cfb->fb.screen_base;
1021         display->line_length    = cfb->fb.fix.line_length;
1022         display->visual         = cfb->fb.fix.visual;
1023         display->type           = cfb->fb.fix.type;
1024         display->type_aux       = cfb->fb.fix.type_aux;
1025         display->ypanstep       = cfb->fb.fix.ypanstep;
1026         display->ywrapstep      = cfb->fb.fix.ywrapstep;
1027         display->can_soft_blank = 1;
1028         display->inverse        = 0;
1029
1030         cfb->fb.var = *var;
1031         cfb->fb.var.activate &= ~FB_ACTIVATE_ALL;
1032
1033         /*
1034          * Update the old var.  The fbcon drivers still use this.
1035          * Once they are using cfb->fb.var, this can be dropped.
1036          *                                      --rmk
1037          */
1038         display->var = cfb->fb.var;
1039
1040         /*
1041          * If we are setting all the virtual consoles, also set the
1042          * defaults used to create new consoles.
1043          */
1044         if (var->activate & FB_ACTIVATE_ALL)
1045                 cfb->fb.disp->var = cfb->fb.var;
1046
1047         if (chgvar && info && cfb->fb.changevar)
1048                 cfb->fb.changevar(con);
1049
1050         cyber2000fb_update_start(cfb, var);
1051         cyber2000fb_set_timing(cfb, &hw);
1052         fb_set_cmap(&cfb->fb.cmap, 1, cyber2000_setcolreg, &cfb->fb);
1053
1054         return 0;
1055 }
1056
1057
1058 /*
1059  *    Pan or Wrap the Display
1060  */
1061 static int
1062 cyber2000fb_pan_display(struct fb_var_screeninfo *var, int con,
1063                         struct fb_info *info)
1064 {
1065         struct cfb_info *cfb = (struct cfb_info *)info;
1066         u_int y_bottom;
1067
1068         y_bottom = var->yoffset;
1069
1070         if (!(var->vmode & FB_VMODE_YWRAP))
1071                 y_bottom += var->yres;
1072
1073         if (var->xoffset > (var->xres_virtual - var->xres))
1074                 return -EINVAL;
1075         if (y_bottom > cfb->fb.var.yres_virtual)
1076                 return -EINVAL;
1077
1078         if (cyber2000fb_update_start(cfb, var))
1079                 return -EINVAL;
1080
1081         cfb->fb.var.xoffset = var->xoffset;
1082         cfb->fb.var.yoffset = var->yoffset;
1083         if (var->vmode & FB_VMODE_YWRAP) {
1084                 cfb->fb.var.vmode |= FB_VMODE_YWRAP;
1085         } else {
1086                 cfb->fb.var.vmode &= ~FB_VMODE_YWRAP;
1087         }
1088
1089         return 0;
1090 }
1091
1092
1093 /*
1094  *    Update the `var' structure (called by fbcon.c)
1095  *
1096  *    This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
1097  *    Since it's called by a kernel driver, no range checking is done.
1098  */
1099 static int cyber2000fb_updatevar(int con, struct fb_info *info)
1100 {
1101         struct cfb_info *cfb = (struct cfb_info *)info;
1102
1103         return cyber2000fb_update_start(cfb, &fb_display[con].var);
1104 }
1105
1106 static int cyber2000fb_switch(int con, struct fb_info *info)
1107 {
1108         struct cfb_info *cfb = (struct cfb_info *)info;
1109         struct display *disp;
1110         struct fb_cmap *cmap;
1111
1112         if (cfb->currcon >= 0) {
1113                 disp = fb_display + cfb->currcon;
1114
1115                 /*
1116                  * Save the old colormap and video mode.
1117                  */
1118                 disp->var = cfb->fb.var;
1119                 if (disp->cmap.len)
1120                         fb_copy_cmap(&cfb->fb.cmap, &disp->cmap, 0);
1121         }
1122
1123         cfb->currcon = con;
1124         disp = fb_display + con;
1125
1126         /*
1127          * Install the new colormap and change the video mode.  By default,
1128          * fbcon sets all the colormaps and video modes to the default
1129          * values at bootup.
1130          *
1131          * Really, we want to set the colourmap size depending on the
1132          * depth of the new video mode.  For now, we leave it at its
1133          * default 256 entry.
1134          */
1135         if (disp->cmap.len)
1136                 cmap = &disp->cmap;
1137         else
1138                 cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);
1139
1140         fb_copy_cmap(cmap, &cfb->fb.cmap, 0);
1141
1142         cfb->fb.var = disp->var;
1143         cfb->fb.var.activate = FB_ACTIVATE_NOW;
1144
1145         cyber2000fb_set_var(&cfb->fb.var, con, &cfb->fb);
1146
1147         return 0;
1148 }
1149
1150 /*
1151  *    (Un)Blank the display.
1152  */
1153 static void cyber2000fb_blank(int blank, struct fb_info *info)
1154 {
1155         struct cfb_info *cfb = (struct cfb_info *)info;
1156         int i;
1157
1158         /*
1159          *  Blank the screen if blank_mode != 0, else unblank. If
1160          *  blank == NULL then the caller blanks by setting the CLUT
1161          *  (Color Look Up Table) to all black. Return 0 if blanking
1162          *  succeeded, != 0 if un-/blanking failed due to e.g. a
1163          *  video mode which doesn't support it. Implements VESA
1164          *  suspend and powerdown modes on hardware that supports
1165          *  disabling hsync/vsync:
1166          *    blank_mode == 2: suspend vsync
1167          *    blank_mode == 3: suspend hsync
1168          *    blank_mode == 4: powerdown
1169          *
1170          *  wms...Enable VESA DMPS compatible powerdown mode
1171          *  run "setterm -powersave powerdown" to take advantage
1172          */
1173      
1174         switch (blank) {
1175         case 4: /* powerdown - both sync lines down */
1176                 cyber2000_grphw(0x16, 0x05, cfb);
1177                 break;  
1178         case 3: /* hsync off */
1179                 cyber2000_grphw(0x16, 0x01, cfb);
1180                 break;  
1181         case 2: /* vsync off */
1182                 cyber2000_grphw(0x16, 0x04, cfb);
1183                 break;  
1184         case 1: /* soft blank */
1185                 cyber2000_grphw(0x16, 0x00, cfb);
1186                 for (i = 0; i < NR_PALETTE; i++) {
1187                         cyber2000fb_writeb(i, 0x3c8, cfb);
1188                         cyber2000fb_writeb(0, 0x3c9, cfb);
1189                         cyber2000fb_writeb(0, 0x3c9, cfb);
1190                         cyber2000fb_writeb(0, 0x3c9, cfb);
1191                 }
1192                 break;
1193         default: /* unblank */
1194                 cyber2000_grphw(0x16, 0x00, cfb);
1195                 for (i = 0; i < NR_PALETTE; i++) {
1196                         cyber2000fb_writeb(i, 0x3c8, cfb);
1197                         cyber2000fb_writeb(cfb->palette[i].red, 0x3c9, cfb);
1198                         cyber2000fb_writeb(cfb->palette[i].green, 0x3c9, cfb);
1199                         cyber2000fb_writeb(cfb->palette[i].blue, 0x3c9, cfb);
1200                 }
1201                 break;
1202         }
1203 }
1204
1205 /*
1206  * Get the currently displayed virtual consoles colormap.
1207  */
1208 static int
1209 gen_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
1210 {
1211         fb_copy_cmap(&info->cmap, cmap, kspc ? 0 : 2);
1212         return 0;
1213 }
1214
1215 /*
1216  * Get the currently displayed virtual consoles fixed part of the display.
1217  */
1218 static int
1219 gen_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1220 {
1221         *fix = info->fix;
1222         return 0;
1223 }
1224
1225 /*
1226  * Get the current user defined part of the display.
1227  */
1228 static int
1229 gen_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
1230 {
1231         *var = info->var;
1232         return 0;
1233 }
1234
1235 static struct fb_ops cyber2000fb_ops = {
1236         owner:          THIS_MODULE,
1237         fb_set_var:     cyber2000fb_set_var,
1238         fb_set_cmap:    cyber2000fb_set_cmap,
1239         fb_pan_display: cyber2000fb_pan_display,
1240         fb_get_fix:     gen_get_fix,
1241         fb_get_var:     gen_get_var,
1242         fb_get_cmap:    gen_get_cmap,
1243 };
1244
1245 /*
1246  * Enable access to the extended registers
1247  */
1248 static void cyber2000fb_enable_extregs(struct cfb_info *cfb)
1249 {
1250         cfb->func_use_count += 1;
1251
1252         if (cfb->func_use_count == 1) {
1253                 int old;
1254
1255                 old = cyber2000_grphr(FUNC_CTL, cfb);
1256                 cyber2000_grphw(FUNC_CTL, old | FUNC_CTL_EXTREGENBL, cfb);
1257         }
1258 }
1259
1260 /*
1261  * Disable access to the extended registers
1262  */
1263 static void cyber2000fb_disable_extregs(struct cfb_info *cfb)
1264 {
1265         if (cfb->func_use_count == 1) {
1266                 int old;
1267
1268                 old = cyber2000_grphr(FUNC_CTL, cfb);
1269                 cyber2000_grphw(FUNC_CTL, old & ~FUNC_CTL_EXTREGENBL, cfb);
1270         }
1271
1272         cfb->func_use_count -= 1;
1273 }
1274
1275 /*
1276  * This is the only "static" reference to the internal data structures
1277  * of this driver.  It is here solely at the moment to support the other
1278  * CyberPro modules external to this driver.
1279  */
1280 static struct cfb_info          *int_cfb_info;
1281
1282 /*
1283  * Attach a capture/tv driver to the core CyberX0X0 driver.
1284  */
1285 int cyber2000fb_attach(struct cyberpro_info *info, int idx)
1286 {
1287         if (int_cfb_info != NULL) {
1288                 info->dev             = int_cfb_info->dev;
1289                 info->regs            = int_cfb_info->regs;
1290                 info->fb              = int_cfb_info->fb.screen_base;
1291                 info->fb_size         = int_cfb_info->fb.fix.smem_len;
1292                 info->enable_extregs  = cyber2000fb_enable_extregs;
1293                 info->disable_extregs = cyber2000fb_disable_extregs;
1294                 info->info            = int_cfb_info;
1295
1296                 strncpy(info->dev_name, int_cfb_info->fb.fix.id, sizeof(info->dev_name));
1297
1298                 MOD_INC_USE_COUNT;
1299         }
1300
1301         return int_cfb_info != NULL;
1302 }
1303
1304 /*
1305  * Detach a capture/tv driver from the core CyberX0X0 driver.
1306  */
1307 void cyber2000fb_detach(int idx)
1308 {
1309         MOD_DEC_USE_COUNT;
1310 }
1311
1312 EXPORT_SYMBOL(cyber2000fb_attach);
1313 EXPORT_SYMBOL(cyber2000fb_detach);
1314
1315 /*
1316  * These parameters give
1317  * 640x480, hsync 31.5kHz, vsync 60Hz
1318  */
1319 static struct fb_videomode __devinitdata cyber2000fb_default_mode = {
1320         refresh:        60,
1321         xres:           640,
1322         yres:           480,
1323         pixclock:       39722,
1324         left_margin:    56,
1325         right_margin:   16,
1326         upper_margin:   34,
1327         lower_margin:   9,
1328         hsync_len:      88,
1329         vsync_len:      2,
1330         sync:           FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
1331         vmode:          FB_VMODE_NONINTERLACED
1332 };
1333
1334 static char igs_regs[] __devinitdata = {
1335                                         0x12, 0x00,     0x13, 0x00,
1336                                         0x16, 0x00,
1337                         0x31, 0x00,     0x32, 0x00,
1338         0x50, 0x00,     0x51, 0x00,     0x52, 0x00,     0x53, 0x00,
1339         0x54, 0x00,     0x55, 0x00,     0x56, 0x00,     0x57, 0x01,
1340         0x58, 0x00,     0x59, 0x00,     0x5a, 0x00,
1341         0x70, 0x0b,                                     0x73, 0x30,
1342         0x74, 0x0b,     0x75, 0x17,     0x76, 0x00,     0x7a, 0xc8
1343 };
1344
1345 /*
1346  * We need to wake up the CyberPro, and make sure its in linear memory
1347  * mode.  Unfortunately, this is specific to the platform and card that
1348  * we are running on.
1349  *
1350  * On x86 and ARM, should we be initialising the CyberPro first via the
1351  * IO registers, and then the MMIO registers to catch all cases?  Can we
1352  * end up in the situation where the chip is in MMIO mode, but not awake
1353  * on an x86 system?
1354  *
1355  * Note that on the NetWinder, the firmware automatically detects the
1356  * type, width and size, and leaves this in extended registers 0x71 and
1357  * 0x72 for us.
1358  */
1359 static inline void cyberpro_init_hw(struct cfb_info *cfb, int at_boot)
1360 {
1361         int i;
1362
1363         /*
1364          * Wake up the CyberPro.
1365          */
1366 #ifdef __sparc__
1367 #ifdef __sparc_v9__
1368 #error "You loose, consult DaveM."
1369 #else
1370         /*
1371          * SPARC does not have an "outb" instruction, so we generate
1372          * I/O cycles storing into a reserved memory space at
1373          * physical address 0x3000000
1374          */
1375         {
1376                 unsigned char *iop;
1377
1378                 iop = ioremap(0x3000000, 0x5000);
1379                 if (iop == NULL) {
1380                         prom_printf("iga5000: cannot map I/O\n");
1381                         return -ENOMEM;
1382                 }
1383
1384                 writeb(0x18, iop + 0x46e8);
1385                 writeb(0x01, iop + 0x102);
1386                 writeb(0x08, iop + 0x46e8);
1387                 writeb(0x33, iop + 0x3ce);
1388                 writeb(0x01, iop + 0x3cf);
1389
1390                 iounmap((void *)iop);
1391         }
1392 #endif
1393
1394         if (at_boot) {
1395                 /*
1396                  * Use mclk from BIOS.  Only read this if we're
1397                  * initialising this card for the first time.
1398                  * FIXME: what about hotplug?
1399                  */
1400                 cfb->mclk_mult = cyber2000_grphr(MCLK_MULT, cfb);
1401                 cfb->mclk_div  = cyber2000_grphr(MCLK_DIV, cfb);
1402         }
1403 #endif
1404 #if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
1405         /*
1406          * x86 and MIPS are simple, we just do regular
1407          * outb's instead of cyber2000fb_writeb.
1408          */
1409         outb(0x18, 0x46e8);
1410         outb(0x01, 0x102);
1411         outb(0x08, 0x46e8);
1412         outb(0x33, 0x3ce);
1413         outb(0x01, 0x3cf);
1414
1415         if (at_boot) {
1416                 /*
1417                  * Use mclk from BIOS.  Only read this if we're
1418                  * initialising this card for the first time.
1419                  * FIXME: what about hotplug?
1420                  */
1421                 cfb->mclk_mult = cyber2000_grphr(MCLK_MULT, cfb);
1422                 cfb->mclk_div  = cyber2000_grphr(MCLK_DIV, cfb);
1423         }
1424 #endif
1425 #ifdef __arm__
1426         cyber2000fb_writeb(0x18, 0x46e8, cfb);
1427         cyber2000fb_writeb(0x01, 0x102, cfb);
1428         cyber2000fb_writeb(0x08, 0x46e8, cfb);
1429         cyber2000fb_writeb(0x33, 0x3ce, cfb);
1430         cyber2000fb_writeb(0x01, 0x3cf, cfb);
1431
1432         /*
1433          * MCLK on the NetWinder and the Shark is fixed at 75MHz
1434          */
1435         cfb->mclk_mult = 0xdb;
1436         cfb->mclk_div  = 0x54;
1437 #endif
1438
1439         /*
1440          * Initialise the CyberPro
1441          */
1442         for (i = 0; i < sizeof(igs_regs); i += 2)
1443                 cyber2000_grphw(igs_regs[i], igs_regs[i+1], cfb);
1444
1445         if (at_boot) {
1446                 /*
1447                  * get the video RAM size and width from the VGA register.
1448                  * This should have been already initialised by the BIOS,
1449                  * but if it's garbage, claim default 1MB VRAM (woody)
1450                  */
1451                 cfb->mem_ctl1 = cyber2000_grphr(MEM_CTL1, cfb);
1452                 cfb->mem_ctl2 = cyber2000_grphr(MEM_CTL2, cfb);
1453         } else {
1454                 /*
1455                  * Reprogram the MEM_CTL1 and MEM_CTL2 registers
1456                  */
1457                 cyber2000_grphw(MEM_CTL1, cfb->mem_ctl1, cfb);
1458                 cyber2000_grphw(MEM_CTL2, cfb->mem_ctl2, cfb);
1459         }
1460
1461         /*
1462          * Ensure thatwe are using the correct PLL.
1463          * (CyberPro 5000's may be programmed to use
1464          * an additional set of PLLs.
1465          */
1466         cyber2000fb_writeb(0xba, 0x3ce, cfb);
1467         cyber2000fb_writeb(cyber2000fb_readb(0x3cf, cfb) & 0x80, 0x3cf, cfb);
1468 }
1469
1470 static struct cfb_info * __devinit
1471 cyberpro_alloc_fb_info(struct pci_dev *dev, const struct pci_device_id *id, char *name)
1472 {
1473         struct cfb_info *cfb;
1474
1475         cfb = kmalloc(sizeof(struct cfb_info) + sizeof(struct display) +
1476                        sizeof(u32) * 16, GFP_KERNEL);
1477
1478         if (!cfb)
1479                 return NULL;
1480
1481         memset(cfb, 0, sizeof(struct cfb_info) + sizeof(struct display));
1482
1483         cfb->currcon            = -1;
1484         cfb->dev                = dev;
1485
1486         if (id->driver_data == FB_ACCEL_IGS_CYBER5000)
1487                 cfb->ref_ps     = 40690; // 24.576 MHz
1488         else
1489                 cfb->ref_ps     = 69842; // 14.31818 MHz (69841?)
1490
1491         cfb->divisors[0]        = 1;
1492         cfb->divisors[1]        = 2;
1493         cfb->divisors[2]        = 4;
1494
1495         if (id->driver_data == FB_ACCEL_IGS_CYBER2000)
1496                 cfb->divisors[3] = 8;
1497         else
1498                 cfb->divisors[3] = 6;
1499
1500         strcpy(cfb->fb.fix.id, name);
1501
1502         cfb->fb.fix.type        = FB_TYPE_PACKED_PIXELS;
1503         cfb->fb.fix.type_aux    = 0;
1504         cfb->fb.fix.xpanstep    = 0;
1505         cfb->fb.fix.ypanstep    = 1;
1506         cfb->fb.fix.ywrapstep   = 0;
1507         cfb->fb.fix.accel       = id->driver_data;
1508
1509         cfb->fb.var.nonstd      = 0;
1510         cfb->fb.var.activate    = FB_ACTIVATE_NOW;
1511         cfb->fb.var.height      = -1;
1512         cfb->fb.var.width       = -1;
1513         cfb->fb.var.accel_flags = FB_ACCELF_TEXT;
1514
1515         strcpy(cfb->fb.modename, cfb->fb.fix.id);
1516         strcpy(cfb->fb.fontname, default_font);
1517
1518         cfb->fb.fbops           = &cyber2000fb_ops;
1519         cfb->fb.changevar       = NULL;
1520         cfb->fb.switch_con      = cyber2000fb_switch;
1521         cfb->fb.updatevar       = cyber2000fb_updatevar;
1522         cfb->fb.blank           = cyber2000fb_blank;
1523         cfb->fb.flags           = FBINFO_FLAG_DEFAULT;
1524         cfb->fb.disp            = (struct display *)(cfb + 1);
1525         cfb->fb.pseudo_palette  = (void *)(cfb->fb.disp + 1);
1526
1527         fb_alloc_cmap(&cfb->fb.cmap, NR_PALETTE, 0);
1528
1529         return cfb;
1530 }
1531
1532 static void __devinit
1533 cyberpro_free_fb_info(struct cfb_info *cfb)
1534 {
1535         if (cfb) {
1536                 /*
1537                  * Free the colourmap
1538                  */
1539                 fb_alloc_cmap(&cfb->fb.cmap, 0, 0);
1540
1541                 kfree(cfb);
1542         }
1543 }
1544
1545 /*
1546  * Parse Cyber2000fb options.  Usage:
1547  *  video=cyber2000:font:fontname
1548  */
1549 int
1550 cyber2000fb_setup(char *options)
1551 {
1552         char *opt;
1553
1554         if (!options || !*options)
1555                 return 0;
1556
1557         while ((opt = strsep(&options, ",")) != NULL) {
1558                 if (!*opt)
1559                         continue;
1560
1561                 if (strncmp(opt, "font:", 5) == 0) {
1562                         strncpy(default_font_storage, opt + 5, sizeof(default_font_storage));
1563                         default_font = default_font_storage;
1564                         continue;
1565                 }
1566
1567                 printk(KERN_ERR "CyberPro20x0: unknown parameter: %s\n", opt);
1568         }
1569         return 0;
1570 }
1571
1572 static int __devinit
1573 cyberpro_probe(struct pci_dev *dev, const struct pci_device_id *id)
1574 {
1575         struct cfb_info *cfb;
1576         u_int h_sync, v_sync;
1577         u_long smem_size;
1578         char name[16];
1579         int err;
1580
1581         sprintf(name, "CyberPro%4X", id->device);
1582
1583         err = pci_enable_device(dev);
1584         if (err)
1585                 return err;
1586
1587         err = pci_request_regions(dev, name);
1588         if (err)
1589                 return err;
1590
1591         err = -ENOMEM;
1592         cfb = cyberpro_alloc_fb_info(dev, id, name);
1593         if (!cfb)
1594                 goto failed_release;
1595
1596         cfb->region = ioremap(pci_resource_start(dev, 0),
1597                               pci_resource_len(dev, 0));
1598         if (!cfb->region)
1599                 goto failed_ioremap;
1600
1601         cfb->regs = cfb->region + MMIO_OFFSET;
1602
1603         cyberpro_init_hw(cfb, 1);
1604
1605         switch (cfb->mem_ctl2 & MEM_CTL2_SIZE_MASK) {
1606         case MEM_CTL2_SIZE_4MB: smem_size = 0x00400000; break;
1607         case MEM_CTL2_SIZE_2MB: smem_size = 0x00200000; break;
1608         default:                smem_size = 0x00100000; break;
1609         }
1610
1611         /*
1612          * Hmm, we _need_ a portable way of finding the address for
1613          * the remap stuff, both for mmio and for smem.
1614          */
1615         cfb->fb.fix.mmio_start = pci_resource_start(dev, 0) + MMIO_OFFSET;
1616         cfb->fb.fix.smem_start = pci_resource_start(dev, 0);
1617         cfb->fb.fix.mmio_len   = MMIO_SIZE;
1618         cfb->fb.fix.smem_len   = smem_size;
1619         cfb->fb.screen_base    = cfb->region;
1620
1621         if (!fb_find_mode(&cfb->fb.var, &cfb->fb, NULL, NULL, 0,
1622                           &cyber2000fb_default_mode, 8)) {
1623                 printk("%s: no valid mode found\n", cfb->fb.fix.id);
1624                 goto failed;
1625         }
1626
1627         cfb->fb.var.yres_virtual = cfb->fb.fix.smem_len * 8 /
1628                         (cfb->fb.var.bits_per_pixel * cfb->fb.var.xres_virtual);
1629
1630         if (cfb->fb.var.yres_virtual < cfb->fb.var.yres)
1631                 cfb->fb.var.yres_virtual = cfb->fb.var.yres;
1632
1633         cyber2000fb_set_var(&cfb->fb.var, -1, &cfb->fb);
1634
1635         /*
1636          * Calculate the hsync and vsync frequencies.  Note that
1637          * we split the 1e12 constant up so that we can preserve
1638          * the precision and fit the results into 32-bit registers.
1639          *  (1953125000 * 512 = 1e12)
1640          */
1641         h_sync = 1953125000 / cfb->fb.var.pixclock;
1642         h_sync = h_sync * 512 / (cfb->fb.var.xres + cfb->fb.var.left_margin +
1643                  cfb->fb.var.right_margin + cfb->fb.var.hsync_len);
1644         v_sync = h_sync / (cfb->fb.var.yres + cfb->fb.var.upper_margin +
1645                  cfb->fb.var.lower_margin + cfb->fb.var.vsync_len);
1646
1647         printk(KERN_INFO "%s: %dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
1648                 cfb->fb.fix.id, cfb->fb.fix.smem_len >> 10,
1649                 cfb->fb.var.xres, cfb->fb.var.yres,
1650                 h_sync / 1000, h_sync % 1000, v_sync);
1651
1652         err = register_framebuffer(&cfb->fb);
1653         if (err < 0)
1654                 goto failed;
1655
1656         /*
1657          * Our driver data
1658          */
1659         pci_set_drvdata(dev, cfb);
1660         if (int_cfb_info == NULL)
1661                 int_cfb_info = cfb;
1662
1663         return 0;
1664
1665 failed:
1666         iounmap(cfb->region);
1667 failed_ioremap:
1668         cyberpro_free_fb_info(cfb);
1669 failed_release:
1670         pci_release_regions(dev);
1671
1672         return err;
1673 }
1674
1675 static void __devexit cyberpro_remove(struct pci_dev *dev)
1676 {
1677         struct cfb_info *cfb = pci_get_drvdata(dev);
1678
1679         if (cfb) {
1680                 /*
1681                  * If unregister_framebuffer fails, then
1682                  * we will be leaving hooks that could cause
1683                  * oopsen laying around.
1684                  */
1685                 if (unregister_framebuffer(&cfb->fb))
1686                         printk(KERN_WARNING "%s: danger Will Robinson, "
1687                                 "danger danger!  Oopsen imminent!\n",
1688                                 cfb->fb.fix.id);
1689                 iounmap(cfb->region);
1690                 cyberpro_free_fb_info(cfb);
1691
1692                 /*
1693                  * Ensure that the driver data is no longer
1694                  * valid.
1695                  */
1696                 pci_set_drvdata(dev, NULL);
1697                 if (cfb == int_cfb_info)
1698                         int_cfb_info = NULL;
1699
1700                 pci_release_regions(dev);
1701         }
1702 }
1703
1704 static int cyberpro_suspend(struct pci_dev *dev, u32 state)
1705 {
1706         return 0;
1707 }
1708
1709 /*
1710  * Re-initialise the CyberPro hardware
1711  */
1712 static int cyberpro_resume(struct pci_dev *dev)
1713 {
1714         struct cfb_info *cfb = pci_get_drvdata(dev);
1715
1716         if (cfb) {
1717                 cyberpro_init_hw(cfb, 0);
1718
1719                 /*
1720                  * Restore the old video mode and the palette.
1721                  * We also need to tell fbcon to redraw the console.
1722                  */
1723                 cfb->fb.var.activate = FB_ACTIVATE_NOW;
1724                 cyber2000fb_set_var(&cfb->fb.var, -1, &cfb->fb);
1725         }
1726
1727         return 0;
1728 }
1729
1730 static struct pci_device_id cyberpro_pci_table[] __devinitdata = {
1731         { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000,
1732                 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_IGS_CYBER2000 },
1733         { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010,
1734                 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_IGS_CYBER2010 },
1735         { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5000,
1736                 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_IGS_CYBER5000 },
1737         { 0, }
1738 };
1739
1740 static struct pci_driver cyberpro_driver = {
1741         name:           "CyberPro",
1742         probe:          cyberpro_probe,
1743         remove:         __devexit_p(cyberpro_remove),
1744         suspend:        cyberpro_suspend,
1745         resume:         cyberpro_resume,
1746         id_table:       cyberpro_pci_table
1747 };
1748
1749 /*
1750  * I don't think we can use the "module_init" stuff here because
1751  * the fbcon stuff may not be initialised yet.  Hence the #ifdef
1752  * around module_init.
1753  */
1754 int __init cyber2000fb_init(void)
1755 {
1756         return pci_module_init(&cyberpro_driver);
1757 }
1758
1759 static void __exit cyberpro_exit(void)
1760 {
1761         pci_unregister_driver(&cyberpro_driver);
1762 }
1763
1764 #ifdef MODULE
1765 module_init(cyber2000fb_init);
1766 #endif
1767 module_exit(cyberpro_exit);
1768
1769 MODULE_AUTHOR("Russell King");
1770 MODULE_DESCRIPTION("CyberPro 2000, 2010 and 5000 framebuffer driver");
1771 MODULE_DEVICE_TABLE(pci,cyberpro_pci_table);
1772 MODULE_LICENSE("GPL");