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