Import 2.4.0-test5pre5
[davej-history.git] / drivers / video / cyber2000fb.c
blob7f9cac9a1b656ec396596319a83c23f1dfc9671b
1 /*
2 * Linux/drivers/video/cyber2000fb.c
4 * Copyright (C) 1998-2000 Russell King
6 * Integraphics CyberPro 2000, 2010 and 5000 frame buffer device
8 * Based on cyberfb.c.
10 * Note that we now use the new fbcon fix, var and cmap scheme. We do still
11 * have to check which console is the currently displayed one however, since
12 * especially for the colourmap stuff. Once fbcon has been fully migrated,
13 * we can kill the last 5 references to cfb->currcon.
15 * We also use the new hotplug PCI subsystem. I'm not sure if there are any
16 * such cards, but I'm erring on the side of caution. We don't want to go
17 * pop just because someone does have one.
19 * Note that this doesn't work fully in the case of multiple CyberPro cards
20 * with grabbers. We currently can only attach to the first CyberPro card
21 * found.
23 #include <linux/config.h>
24 #include <linux/module.h>
25 #include <linux/kernel.h>
26 #include <linux/errno.h>
27 #include <linux/string.h>
28 #include <linux/mm.h>
29 #include <linux/tty.h>
30 #include <linux/malloc.h>
31 #include <linux/delay.h>
32 #include <linux/fb.h>
33 #include <linux/pci.h>
34 #include <linux/init.h>
36 #include <asm/io.h>
37 #include <asm/irq.h>
38 #include <asm/pgtable.h>
39 #include <asm/system.h>
40 #include <asm/uaccess.h>
42 #include <video/fbcon.h>
43 #include <video/fbcon-cfb8.h>
44 #include <video/fbcon-cfb16.h>
45 #include <video/fbcon-cfb24.h>
48 * Define this if you don't want RGB565, but RGB555 for 16bpp displays.
50 /*#define CFB16_IS_CFB15*/
53 * This is the offset of the PCI space in physical memory
55 #ifdef CONFIG_FOOTBRIDGE
56 #define PCI_PHYS_OFFSET 0x80000000
57 #else
58 #define PCI_PHYS_OFFSET 0x00000000
59 #endif
61 static char *CyberRegs;
63 #include "cyber2000fb.h"
65 struct cfb_info {
66 struct fb_info fb;
67 struct display_switch *dispsw;
68 struct pci_dev *dev;
69 signed int currcon;
70 int func_use_count;
71 u_long ref_ps;
74 * Clock divisors
76 u_int divisors[4];
78 struct {
79 u8 red, green, blue;
80 } palette[NR_PALETTE];
82 u_char mem_ctl1;
83 u_char mem_ctl2;
84 u_char mclk_mult;
85 u_char mclk_div;
88 /* -------------------- Hardware specific routines ------------------------- */
91 * Hardware Cyber2000 Acceleration
93 static void cyber2000_accel_wait(void)
95 int count = 100000;
97 while (cyber2000_inb(CO_REG_CONTROL) & 0x80) {
98 if (!count--) {
99 debug_printf("accel_wait timed out\n");
100 cyber2000_outb(0, CO_REG_CONTROL);
101 return;
103 udelay(1);
107 static void cyber2000_accel_setup(struct display *p)
109 struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
111 cfb->dispsw->setup(p);
114 static void
115 cyber2000_accel_bmove(struct display *p, int sy, int sx, int dy, int dx,
116 int height, int width)
118 struct fb_var_screeninfo *var = &p->fb_info->var;
119 u_long src, dst;
120 u_int fh, fw;
121 int cmd = CO_CMD_L_PATTERN_FGCOL;
123 fw = fontwidth(p);
124 sx *= fw;
125 dx *= fw;
126 width *= fw;
127 width -= 1;
129 if (sx < dx) {
130 sx += width;
131 dx += width;
132 cmd |= CO_CMD_L_INC_LEFT;
135 fh = fontheight(p);
136 sy *= fh;
137 dy *= fh;
138 height *= fh;
139 height -= 1;
141 if (sy < dy) {
142 sy += height;
143 dy += height;
144 cmd |= CO_CMD_L_INC_UP;
147 src = sx + sy * var->xres_virtual;
148 dst = dx + dy * var->xres_virtual;
150 cyber2000_accel_wait();
151 cyber2000_outb(0x00, CO_REG_CONTROL);
152 cyber2000_outb(0x03, CO_REG_FORE_MIX);
153 cyber2000_outw(width, CO_REG_WIDTH);
155 if (var->bits_per_pixel != 24) {
156 cyber2000_outl(dst, CO_REG_DEST_PTR);
157 cyber2000_outl(src, CO_REG_SRC_PTR);
158 } else {
159 cyber2000_outl(dst * 3, CO_REG_DEST_PTR);
160 cyber2000_outb(dst, CO_REG_X_PHASE);
161 cyber2000_outl(src * 3, CO_REG_SRC_PTR);
164 cyber2000_outw(height, CO_REG_HEIGHT);
165 cyber2000_outw(cmd, CO_REG_CMD_L);
166 cyber2000_outw(0x2800, CO_REG_CMD_H);
169 static void
170 cyber2000_accel_clear(struct vc_data *conp, struct display *p, int sy, int sx,
171 int height, int width)
173 struct fb_var_screeninfo *var = &p->fb_info->var;
174 u_long dst;
175 u_int fw, fh;
176 u32 bgx = attr_bgcol_ec(p, conp);
178 fw = fontwidth(p);
179 fh = fontheight(p);
181 dst = sx * fw + sy * var->xres_virtual * fh;
182 width = width * fw - 1;
183 height = height * fh - 1;
185 cyber2000_accel_wait();
186 cyber2000_outb(0x00, CO_REG_CONTROL);
187 cyber2000_outb(0x03, CO_REG_FORE_MIX);
188 cyber2000_outw(width, CO_REG_WIDTH);
189 cyber2000_outw(height, CO_REG_HEIGHT);
191 switch (var->bits_per_pixel) {
192 case 15:
193 case 16:
194 bgx = ((u16 *)p->dispsw_data)[bgx];
195 case 8:
196 cyber2000_outl(dst, CO_REG_DEST_PTR);
197 break;
199 case 24:
200 cyber2000_outl(dst * 3, CO_REG_DEST_PTR);
201 cyber2000_outb(dst, CO_REG_X_PHASE);
202 bgx = ((u32 *)p->dispsw_data)[bgx];
203 break;
206 cyber2000_outl(bgx, CO_REG_FOREGROUND);
207 cyber2000_outw(CO_CMD_L_PATTERN_FGCOL, CO_REG_CMD_L);
208 cyber2000_outw(0x0800, CO_REG_CMD_H);
211 static void
212 cyber2000_accel_putc(struct vc_data *conp, struct display *p, int c,
213 int yy, int xx)
215 struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
217 cyber2000_accel_wait();
218 cfb->dispsw->putc(conp, p, c, yy, xx);
221 static void
222 cyber2000_accel_putcs(struct vc_data *conp, struct display *p,
223 const unsigned short *s, int count, int yy, int xx)
225 struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
227 cyber2000_accel_wait();
228 cfb->dispsw->putcs(conp, p, s, count, yy, xx);
231 static void cyber2000_accel_revc(struct display *p, int xx, int yy)
233 struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
235 cyber2000_accel_wait();
236 cfb->dispsw->revc(p, xx, yy);
239 static void
240 cyber2000_accel_clear_margins(struct vc_data *conp, struct display *p,
241 int bottom_only)
243 struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
245 cfb->dispsw->clear_margins(conp, p, bottom_only);
248 static struct display_switch fbcon_cyber_accel = {
249 setup: cyber2000_accel_setup,
250 bmove: cyber2000_accel_bmove,
251 clear: cyber2000_accel_clear,
252 putc: cyber2000_accel_putc,
253 putcs: cyber2000_accel_putcs,
254 revc: cyber2000_accel_revc,
255 clear_margins: cyber2000_accel_clear_margins,
256 fontwidthmask: FONTWIDTH(8)|FONTWIDTH(16)
260 * Set a single color register. Return != 0 for invalid regno.
262 static int
263 cyber2000_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
264 u_int transp, struct fb_info *info)
266 struct cfb_info *cfb = (struct cfb_info *)info;
268 if (regno >= NR_PALETTE)
269 return 1;
271 red >>= 10;
272 green >>= 10;
273 blue >>= 10;
275 cfb->palette[regno].red = red;
276 cfb->palette[regno].green = green;
277 cfb->palette[regno].blue = blue;
279 switch (cfb->fb.var.bits_per_pixel) {
280 #ifdef FBCON_HAS_CFB8
281 case 8:
282 cyber2000_outb(regno, 0x3c8);
283 cyber2000_outb(red, 0x3c9);
284 cyber2000_outb(green, 0x3c9);
285 cyber2000_outb(blue, 0x3c9);
286 break;
287 #endif
289 #ifdef FBCON_HAS_CFB16
290 case 16:
291 #ifndef CFB16_IS_CFB15
292 if (regno < 64) {
293 /* write green */
294 cyber2000_outb(regno << 2, 0x3c8);
295 cyber2000_outb(cfb->palette[regno >> 1].red, 0x3c9);
296 cyber2000_outb(green, 0x3c9);
297 cyber2000_outb(cfb->palette[regno >> 1].blue, 0x3c9);
300 if (regno < 32) {
301 /* write red,blue */
302 cyber2000_outb(regno << 3, 0x3c8);
303 cyber2000_outb(red, 0x3c9);
304 cyber2000_outb(cfb->palette[regno << 1].green, 0x3c9);
305 cyber2000_outb(blue, 0x3c9);
308 if (regno < 16)
309 ((u16 *)cfb->fb.pseudo_palette)[regno] =
310 regno | regno << 5 | regno << 11;
311 break;
312 #endif
314 case 15:
315 if (regno < 32) {
316 cyber2000_outb(regno << 3, 0x3c8);
317 cyber2000_outb(red, 0x3c9);
318 cyber2000_outb(green, 0x3c9);
319 cyber2000_outb(blue, 0x3c9);
321 if (regno < 16)
322 ((u16 *)cfb->fb.pseudo_palette)[regno] =
323 regno | regno << 5 | regno << 10;
324 break;
326 #endif
328 #ifdef FBCON_HAS_CFB24
329 case 24:
330 cyber2000_outb(regno, 0x3c8);
331 cyber2000_outb(red, 0x3c9);
332 cyber2000_outb(green, 0x3c9);
333 cyber2000_outb(blue, 0x3c9);
335 if (regno < 16)
336 ((u32 *)cfb->fb.pseudo_palette)[regno] =
337 regno | regno << 8 | regno << 16;
338 break;
339 #endif
341 default:
342 return 1;
345 return 0;
348 struct par_info {
350 * Hardware
352 u_char clock_mult;
353 u_char clock_div;
354 u_char visualid;
355 u_char pixformat;
356 u_char crtc_ofl;
357 u_char crtc[19];
358 u_int width;
359 u_int pitch;
360 u_int fetch;
363 * Other
365 u_char palette_ctrl;
368 static const u_char crtc_idx[] = {
369 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
370 0x08, 0x09,
371 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18
374 static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw)
376 u_int i;
379 * Blank palette
381 for (i = 0; i < NR_PALETTE; i++) {
382 cyber2000_outb(i, 0x3c8);
383 cyber2000_outb(0, 0x3c9);
384 cyber2000_outb(0, 0x3c9);
385 cyber2000_outb(0, 0x3c9);
388 cyber2000_outb(0xef, 0x3c2);
389 cyber2000_crtcw(0x11, 0x0b);
390 cyber2000_attrw(0x11, 0x00);
392 cyber2000_seqw(0x00, 0x01);
393 cyber2000_seqw(0x01, 0x01);
394 cyber2000_seqw(0x02, 0x0f);
395 cyber2000_seqw(0x03, 0x00);
396 cyber2000_seqw(0x04, 0x0e);
397 cyber2000_seqw(0x00, 0x03);
399 for (i = 0; i < sizeof(crtc_idx); i++)
400 cyber2000_crtcw(crtc_idx[i], hw->crtc[i]);
402 for (i = 0x0a; i < 0x10; i++)
403 cyber2000_crtcw(i, 0);
405 cyber2000_grphw(0x11, hw->crtc_ofl);
406 cyber2000_grphw(0x00, 0x00);
407 cyber2000_grphw(0x01, 0x00);
408 cyber2000_grphw(0x02, 0x00);
409 cyber2000_grphw(0x03, 0x00);
410 cyber2000_grphw(0x04, 0x00);
411 cyber2000_grphw(0x05, 0x60);
412 cyber2000_grphw(0x06, 0x05);
413 cyber2000_grphw(0x07, 0x0f);
414 cyber2000_grphw(0x08, 0xff);
416 /* Attribute controller registers */
417 for (i = 0; i < 16; i++)
418 cyber2000_attrw(i, i);
420 cyber2000_attrw(0x10, 0x01);
421 cyber2000_attrw(0x11, 0x00);
422 cyber2000_attrw(0x12, 0x0f);
423 cyber2000_attrw(0x13, 0x00);
424 cyber2000_attrw(0x14, 0x00);
426 /* PLL registers */
427 cyber2000_grphw(DCLK_MULT, hw->clock_mult);
428 cyber2000_grphw(DCLK_DIV, hw->clock_div);
429 cyber2000_grphw(MCLK_MULT, cfb->mclk_mult);
430 cyber2000_grphw(MCLK_DIV, cfb->mclk_div);
431 cyber2000_grphw(0x90, 0x01);
432 cyber2000_grphw(0xb9, 0x80);
433 cyber2000_grphw(0xb9, 0x00);
435 cyber2000_outb(0x56, 0x3ce);
436 i = cyber2000_inb(0x3cf);
437 cyber2000_outb(i | 4, 0x3cf);
438 cyber2000_outb(hw->palette_ctrl, 0x3c6);
439 cyber2000_outb(i, 0x3cf);
441 cyber2000_outb(0x20, 0x3c0);
442 cyber2000_outb(0xff, 0x3c6);
444 cyber2000_grphw(0x14, hw->fetch);
445 cyber2000_grphw(0x15, ((hw->fetch >> 8) & 0x03) |
446 ((hw->pitch >> 4) & 0x30));
447 cyber2000_grphw(0x77, hw->visualid);
449 /* make sure we stay in linear mode */
450 cyber2000_grphw(0x33, 0x0d);
453 * Set up accelerator registers
455 cyber2000_outw(hw->width, CO_REG_SRC_WIDTH);
456 cyber2000_outw(hw->width, CO_REG_DEST_WIDTH);
457 cyber2000_outb(hw->pixformat, CO_REG_PIX_FORMAT);
460 static inline int
461 cyber2000fb_update_start(struct cfb_info *cfb, struct fb_var_screeninfo *var)
463 u_int base;
465 base = var->yoffset * var->xres_virtual + var->xoffset;
467 base >>= 2;
469 if (base >= 1 << 20)
470 return -EINVAL;
472 cyber2000_grphw(0x10, base >> 16 | 0x10);
473 cyber2000_crtcw(0x0c, base >> 8);
474 cyber2000_crtcw(0x0d, base);
476 return 0;
480 * Set the Colormap
482 static int
483 cyber2000fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
484 struct fb_info *info)
486 struct cfb_info *cfb = (struct cfb_info *)info;
487 struct fb_cmap *dcmap = &fb_display[con].cmap;
488 int err = 0;
490 /* no colormap allocated? */
491 if (!dcmap->len) {
492 int size;
494 if (cfb->fb.var.bits_per_pixel == 16)
495 size = 32;
496 else
497 size = 256;
499 err = fb_alloc_cmap(dcmap, size, 0);
503 * we should be able to remove this test once fbcon has been
504 * "improved" --rmk
506 if (!err && con == cfb->currcon) {
507 err = fb_set_cmap(cmap, kspc, cyber2000_setcolreg, &cfb->fb);
508 dcmap = &cfb->fb.cmap;
511 if (!err)
512 fb_copy_cmap(cmap, dcmap, kspc ? 0 : 1);
514 return err;
517 static int
518 cyber2000fb_decode_crtc(struct par_info *hw, struct cfb_info *cfb,
519 struct fb_var_screeninfo *var)
521 u_int Htotal, Hblankend, Hsyncend;
522 u_int Vtotal, Vdispend, Vblankstart, Vblankend, Vsyncstart, Vsyncend;
523 #define BIT(v,b1,m,b2) (((v >> b1) & m) << b2)
525 hw->crtc[13] = hw->pitch;
526 hw->crtc[17] = 0xe3;
527 hw->crtc[14] = 0;
528 hw->crtc[8] = 0;
530 Htotal = var->xres + var->right_margin +
531 var->hsync_len + var->left_margin;
533 if (Htotal > 2080)
534 return -EINVAL;
536 hw->crtc[0] = (Htotal >> 3) - 5;
537 hw->crtc[1] = (var->xres >> 3) - 1;
538 hw->crtc[2] = var->xres >> 3;
539 hw->crtc[4] = (var->xres + var->right_margin) >> 3;
541 Hblankend = (Htotal - 4*8) >> 3;
543 hw->crtc[3] = BIT(Hblankend, 0, 0x1f, 0) |
544 BIT(1, 0, 0x01, 7);
546 Hsyncend = (var->xres + var->right_margin + var->hsync_len) >> 3;
548 hw->crtc[5] = BIT(Hsyncend, 0, 0x1f, 0) |
549 BIT(Hblankend, 5, 0x01, 7);
551 Vdispend = var->yres - 1;
552 Vsyncstart = var->yres + var->lower_margin;
553 Vsyncend = var->yres + var->lower_margin + var->vsync_len;
554 Vtotal = var->yres + var->lower_margin + var->vsync_len +
555 var->upper_margin - 2;
557 if (Vtotal > 2047)
558 return -EINVAL;
560 Vblankstart = var->yres + 6;
561 Vblankend = Vtotal - 10;
563 hw->crtc[6] = Vtotal;
564 hw->crtc[7] = BIT(Vtotal, 8, 0x01, 0) |
565 BIT(Vdispend, 8, 0x01, 1) |
566 BIT(Vsyncstart, 8, 0x01, 2) |
567 BIT(Vblankstart,8, 0x01, 3) |
568 BIT(1, 0, 0x01, 4) |
569 BIT(Vtotal, 9, 0x01, 5) |
570 BIT(Vdispend, 9, 0x01, 6) |
571 BIT(Vsyncstart, 9, 0x01, 7);
572 hw->crtc[9] = BIT(0, 0, 0x1f, 0) |
573 BIT(Vblankstart,9, 0x01, 5) |
574 BIT(1, 0, 0x01, 6);
575 hw->crtc[10] = Vsyncstart;
576 hw->crtc[11] = BIT(Vsyncend, 0, 0x0f, 0) |
577 BIT(1, 0, 0x01, 7);
578 hw->crtc[12] = Vdispend;
579 hw->crtc[15] = Vblankstart;
580 hw->crtc[16] = Vblankend;
581 hw->crtc[18] = 0xff;
583 /* overflow - graphics reg 0x11 */
584 /* 0=VTOTAL:10 1=VDEND:10 2=VRSTART:10 3=VBSTART:10
585 * 4=LINECOMP:10 5-IVIDEO 6=FIXCNT
587 hw->crtc_ofl =
588 BIT(Vtotal, 10, 0x01, 0) |
589 BIT(Vdispend, 10, 0x01, 1) |
590 BIT(Vsyncstart, 10, 0x01, 2) |
591 BIT(Vblankstart,10, 0x01, 3) |
592 1 << 4;
594 return 0;
598 * The following was discovered by a good monitor, bit twiddling, theorising
599 * and but mostly luck. Strangely, it looks like everyone elses' PLL!
601 * Clock registers:
602 * fclock = fpll / div2
603 * fpll = fref * mult / div1
604 * where:
605 * fref = 14.318MHz (69842ps)
606 * mult = reg0xb0.7:0
607 * div1 = (reg0xb1.5:0 + 1)
608 * div2 = 2^(reg0xb1.7:6)
609 * fpll should be between 115 and 260 MHz
610 * (8696ps and 3846ps)
612 static int
613 cyber2000fb_decode_clock(struct par_info *hw, struct cfb_info *cfb,
614 struct fb_var_screeninfo *var)
616 u_long pll_ps = var->pixclock;
617 const u_long ref_ps = cfb->ref_ps;
618 u_int div2, t_div1, best_div1, best_mult;
619 int best_diff;
622 * Step 1:
623 * find div2 such that 115MHz < fpll < 260MHz
624 * and 0 <= div2 < 4
626 for (div2 = 0; div2 < 4; div2++) {
627 u_long new_pll;
629 new_pll = pll_ps / cfb->divisors[div2];
630 if (8696 > new_pll && new_pll > 3846) {
631 pll_ps = new_pll;
632 break;
636 if (div2 == 4)
637 return -EINVAL;
640 * Step 2:
641 * Given pll_ps and ref_ps, find:
642 * pll_ps * 0.995 < pll_ps_calc < pll_ps * 1.005
643 * where { 1 < best_div1 < 32, 1 < best_mult < 256 }
644 * pll_ps_calc = best_div1 / (ref_ps * best_mult)
646 best_diff = 0x7fffffff;
647 best_mult = 32;
648 best_div1 = 255;
649 for (t_div1 = 32; t_div1 > 1; t_div1 -= 1) {
650 u_int rr, t_mult, t_pll_ps;
651 int diff;
654 * Find the multiplier for this divisor
656 rr = ref_ps * t_div1;
657 t_mult = (rr + pll_ps / 2) / pll_ps;
660 * Is the multiplier within the correct range?
662 if (t_mult > 256 || t_mult < 2)
663 continue;
666 * Calculate the actual clock period from this multiplier
667 * and divisor, and estimate the error.
669 t_pll_ps = (rr + t_mult / 2) / t_mult;
670 diff = pll_ps - t_pll_ps;
671 if (diff < 0)
672 diff = -diff;
674 if (diff < best_diff) {
675 best_diff = diff;
676 best_mult = t_mult;
677 best_div1 = t_div1;
681 * If we hit an exact value, there is no point in continuing.
683 if (diff == 0)
684 break;
688 * Step 3:
689 * combine values
691 hw->clock_mult = best_mult - 1;
692 hw->clock_div = div2 << 6 | (best_div1 - 1);
694 return 0;
698 * Decode the info required for the hardware.
699 * This involves the PLL parameters for the dot clock,
700 * CRTC registers, and accelerator settings.
702 static int
703 cyber2000fb_decode_var(struct fb_var_screeninfo *var, struct cfb_info *cfb,
704 struct par_info *hw)
706 int err;
708 hw->width = var->xres_virtual;
710 switch (var->bits_per_pixel) {
711 #ifdef FBCON_HAS_CFB8
712 case 8: /* PSEUDOCOLOUR, 256 */
713 hw->pixformat = PIXFORMAT_8BPP;
714 hw->visualid = VISUALID_256;
715 hw->pitch = hw->width >> 3;
716 hw->palette_ctrl = 0x04;
717 break;
718 #endif
719 #ifdef FBCON_HAS_CFB16
720 case 16:/* DIRECTCOLOUR, 64k */
721 #ifndef CFB16_IS_CFB15
722 hw->pixformat = PIXFORMAT_16BPP;
723 hw->visualid = VISUALID_64K;
724 hw->pitch = hw->width >> 2;
725 hw->palette_ctrl = 0x14;
726 break;
727 #endif
728 case 15:/* DIRECTCOLOUR, 32k */
729 hw->pixformat = PIXFORMAT_16BPP;
730 hw->visualid = VISUALID_32K;
731 hw->pitch = hw->width >> 2;
732 hw->palette_ctrl = 0x14;
733 break;
735 #endif
736 #ifdef FBCON_HAS_CFB24
737 case 24:/* TRUECOLOUR, 16m */
738 hw->pixformat = PIXFORMAT_24BPP;
739 hw->visualid = VISUALID_16M;
740 hw->width *= 3;
741 hw->pitch = hw->width >> 3;
742 hw->palette_ctrl = 0x14;
743 break;
744 #endif
745 default:
746 return -EINVAL;
749 err = cyber2000fb_decode_clock(hw, cfb, var);
750 if (err)
751 return err;
753 err = cyber2000fb_decode_crtc(hw, cfb, var);
754 if (err)
755 return err;
757 hw->width -= 1;
758 hw->fetch = hw->pitch;
759 if (!(cfb->mem_ctl2 & MEM_CTL2_64BIT))
760 hw->fetch <<= 1;
761 hw->fetch += 1;
763 return 0;
767 * Set the User Defined Part of the Display
769 static int
770 cyber2000fb_set_var(struct fb_var_screeninfo *var, int con,
771 struct fb_info *info)
773 struct cfb_info *cfb = (struct cfb_info *)info;
774 struct display *display;
775 struct par_info hw;
776 int err, chgvar = 0;
779 * CONUPDATE and SMOOTH_XPAN are equal. However,
780 * SMOOTH_XPAN is only used internally by fbcon.
782 if (var->vmode & FB_VMODE_CONUPDATE) {
783 var->vmode |= FB_VMODE_YWRAP;
784 var->xoffset = cfb->fb.var.xoffset;
785 var->yoffset = cfb->fb.var.yoffset;
788 err = cyber2000fb_decode_var(var, (struct cfb_info *)info, &hw);
789 if (err)
790 return err;
792 if (var->activate & FB_ACTIVATE_TEST)
793 return 0;
795 if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
796 return -EINVAL;
798 if (cfb->fb.var.xres != var->xres)
799 chgvar = 1;
800 if (cfb->fb.var.yres != var->yres)
801 chgvar = 1;
802 if (cfb->fb.var.xres_virtual != var->xres_virtual)
803 chgvar = 1;
804 if (cfb->fb.var.yres_virtual != var->yres_virtual)
805 chgvar = 1;
806 if (cfb->fb.var.bits_per_pixel != var->bits_per_pixel)
807 chgvar = 1;
809 if (con < 0) {
810 display = cfb->fb.disp;
811 chgvar = 0;
812 } else {
813 display = fb_display + con;
816 var->red.msb_right = 0;
817 var->green.msb_right = 0;
818 var->blue.msb_right = 0;
820 switch (var->bits_per_pixel) {
821 #ifdef FBCON_HAS_CFB8
822 case 8: /* PSEUDOCOLOUR, 256 */
823 var->red.offset = 0;
824 var->red.length = 8;
825 var->green.offset = 0;
826 var->green.length = 8;
827 var->blue.offset = 0;
828 var->blue.length = 8;
830 cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
831 cfb->dispsw = &fbcon_cfb8;
832 display->dispsw_data = NULL;
833 display->next_line = var->xres_virtual;
834 break;
835 #endif
836 #ifdef FBCON_HAS_CFB16
837 case 16:/* DIRECTCOLOUR, 64k */
838 #ifndef CFB16_IS_CFB15
839 var->bits_per_pixel = 15;
840 var->red.offset = 11;
841 var->red.length = 5;
842 var->green.offset = 5;
843 var->green.length = 6;
844 var->blue.offset = 0;
845 var->blue.length = 5;
847 cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR;
848 cfb->dispsw = &fbcon_cfb16;
849 display->dispsw_data = cfb->fb.pseudo_palette;
850 display->next_line = var->xres_virtual * 2;
851 break;
852 #endif
853 case 15:/* DIRECTCOLOUR, 32k */
854 var->bits_per_pixel = 15;
855 var->red.offset = 10;
856 var->red.length = 5;
857 var->green.offset = 5;
858 var->green.length = 5;
859 var->blue.offset = 0;
860 var->blue.length = 5;
862 cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR;
863 cfb->dispsw = &fbcon_cfb16;
864 display->dispsw_data = cfb->fb.pseudo_palette;
865 display->next_line = var->xres_virtual * 2;
866 break;
867 #endif
868 #ifdef FBCON_HAS_CFB24
869 case 24:/* TRUECOLOUR, 16m */
870 var->red.offset = 16;
871 var->red.length = 8;
872 var->green.offset = 8;
873 var->green.length = 8;
874 var->blue.offset = 0;
875 var->blue.length = 8;
877 cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
878 cfb->dispsw = &fbcon_cfb24;
879 display->dispsw_data = cfb->fb.pseudo_palette;
880 display->next_line = var->xres_virtual * 3;
881 break;
882 #endif
883 default:/* in theory this should never happen */
884 printk(KERN_WARNING "%s: no support for %dbpp\n",
885 cfb->fb.fix.id, var->bits_per_pixel);
886 cfb->dispsw = &fbcon_dummy;
887 break;
890 if (var->accel_flags & FB_ACCELF_TEXT && cfb->dispsw != &fbcon_dummy)
891 display->dispsw = &fbcon_cyber_accel;
892 else
893 display->dispsw = cfb->dispsw;
895 cfb->fb.fix.line_length = display->next_line;
897 display->screen_base = cfb->fb.screen_base;
898 display->line_length = cfb->fb.fix.line_length;
899 display->visual = cfb->fb.fix.visual;
900 display->type = cfb->fb.fix.type;
901 display->type_aux = cfb->fb.fix.type_aux;
902 display->ypanstep = cfb->fb.fix.ypanstep;
903 display->ywrapstep = cfb->fb.fix.ywrapstep;
904 display->can_soft_blank = 1;
905 display->inverse = 0;
907 cfb->fb.var = *var;
908 cfb->fb.var.activate &= ~FB_ACTIVATE_ALL;
911 * Update the old var. The fbcon drivers still use this.
912 * Once they are using cfb->fb.var, this can be dropped.
913 * --rmk
915 display->var = cfb->fb.var;
918 * If we are setting all the virtual consoles, also set the
919 * defaults used to create new consoles.
921 if (var->activate & FB_ACTIVATE_ALL)
922 cfb->fb.disp->var = cfb->fb.var;
924 if (chgvar && info && cfb->fb.changevar)
925 cfb->fb.changevar(con);
927 cyber2000fb_update_start(cfb, var);
928 cyber2000fb_set_timing(cfb, &hw);
929 fb_set_cmap(&cfb->fb.cmap, 1, cyber2000_setcolreg, &cfb->fb);
931 return 0;
936 * Pan or Wrap the Display
938 static int
939 cyber2000fb_pan_display(struct fb_var_screeninfo *var, int con,
940 struct fb_info *info)
942 struct cfb_info *cfb = (struct cfb_info *)info;
943 u_int y_bottom;
945 y_bottom = var->yoffset;
947 if (!(var->vmode & FB_VMODE_YWRAP))
948 y_bottom += var->yres;
950 if (var->xoffset > (var->xres_virtual - var->xres))
951 return -EINVAL;
952 if (y_bottom > cfb->fb.var.yres_virtual)
953 return -EINVAL;
955 if (cyber2000fb_update_start(cfb, var))
956 return -EINVAL;
958 cfb->fb.var.xoffset = var->xoffset;
959 cfb->fb.var.yoffset = var->yoffset;
960 if (var->vmode & FB_VMODE_YWRAP) {
961 cfb->fb.var.vmode |= FB_VMODE_YWRAP;
962 } else {
963 cfb->fb.var.vmode &= ~FB_VMODE_YWRAP;
966 return 0;
970 static int
971 cyber2000fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
972 u_long arg, int con, struct fb_info *info)
974 return -EINVAL;
979 * Update the `var' structure (called by fbcon.c)
981 * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
982 * Since it's called by a kernel driver, no range checking is done.
984 static int cyber2000fb_updatevar(int con, struct fb_info *info)
986 struct cfb_info *cfb = (struct cfb_info *)info;
988 return cyber2000fb_update_start(cfb, &fb_display[con].var);
991 static int cyber2000fb_switch(int con, struct fb_info *info)
993 struct cfb_info *cfb = (struct cfb_info *)info;
994 struct display *disp;
995 struct fb_cmap *cmap;
997 if (cfb->currcon >= 0) {
998 disp = fb_display + cfb->currcon;
1001 * Save the old colormap and video mode.
1003 disp->var = cfb->fb.var;
1004 if (disp->cmap.len)
1005 fb_copy_cmap(&cfb->fb.cmap, &disp->cmap, 0);
1008 cfb->currcon = con;
1009 disp = fb_display + con;
1012 * Install the new colormap and change the video mode. By default,
1013 * fbcon sets all the colormaps and video modes to the default
1014 * values at bootup.
1016 * Really, we want to set the colourmap size depending on the
1017 * depth of the new video mode. For now, we leave it at its
1018 * default 256 entry.
1020 if (disp->cmap.len)
1021 cmap = &disp->cmap;
1022 else
1023 cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);
1025 fb_copy_cmap(cmap, &cfb->fb.cmap, 0);
1027 cfb->fb.var = disp->var;
1028 cfb->fb.var.activate = FB_ACTIVATE_NOW;
1030 cyber2000fb_set_var(&cfb->fb.var, con, &cfb->fb);
1032 return 0;
1036 * (Un)Blank the display.
1038 static void cyber2000fb_blank(int blank, struct fb_info *info)
1040 struct cfb_info *cfb = (struct cfb_info *)info;
1041 int i;
1044 * Blank the screen if blank_mode != 0, else unblank. If
1045 * blank == NULL then the caller blanks by setting the CLUT
1046 * (Color Look Up Table) to all black. Return 0 if blanking
1047 * succeeded, != 0 if un-/blanking failed due to e.g. a
1048 * video mode which doesn't support it. Implements VESA
1049 * suspend and powerdown modes on hardware that supports
1050 * disabling hsync/vsync:
1051 * blank_mode == 2: suspend vsync
1052 * blank_mode == 3: suspend hsync
1053 * blank_mode == 4: powerdown
1055 * wms...Enable VESA DMPS compatible powerdown mode
1056 * run "setterm -powersave powerdown" to take advantage
1059 switch (blank) {
1060 case 4: /* powerdown - both sync lines down */
1061 cyber2000_grphw(0x16, 0x05);
1062 break;
1063 case 3: /* hsync off */
1064 cyber2000_grphw(0x16, 0x01);
1065 break;
1066 case 2: /* vsync off */
1067 cyber2000_grphw(0x16, 0x04);
1068 break;
1069 case 1: /* just software blanking of screen */
1070 cyber2000_grphw(0x16, 0x00);
1071 for (i = 0; i < 256; i++) {
1072 cyber2000_outb(i, 0x3c8);
1073 cyber2000_outb(0, 0x3c9);
1074 cyber2000_outb(0, 0x3c9);
1075 cyber2000_outb(0, 0x3c9);
1077 break;
1078 default: /* case 0, or anything else: unblank */
1079 cyber2000_grphw(0x16, 0x00);
1080 for (i = 0; i < 256; i++) {
1081 cyber2000_outb(i, 0x3c8);
1082 cyber2000_outb(cfb->palette[i].red, 0x3c9);
1083 cyber2000_outb(cfb->palette[i].green, 0x3c9);
1084 cyber2000_outb(cfb->palette[i].blue, 0x3c9);
1086 break;
1091 * Get the currently displayed virtual consoles colormap.
1093 static int
1094 gen_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
1096 fb_copy_cmap(&info->cmap, cmap, kspc ? 0 : 2);
1097 return 0;
1101 * Get the currently displayed virtual consoles fixed part of the display.
1103 static int
1104 gen_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1106 *fix = info->fix;
1107 return 0;
1111 * Get the current user defined part of the display.
1113 static int
1114 gen_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
1116 *var = info->var;
1117 return 0;
1120 static struct fb_ops cyber2000fb_ops = {
1121 owner: THIS_MODULE,
1122 fb_set_var: cyber2000fb_set_var,
1123 fb_set_cmap: cyber2000fb_set_cmap,
1124 fb_pan_display: cyber2000fb_pan_display,
1125 fb_ioctl: cyber2000fb_ioctl,
1126 fb_get_fix: gen_get_fix,
1127 fb_get_var: gen_get_var,
1128 fb_get_cmap: gen_get_cmap,
1132 * Enable access to the extended registers
1134 static void cyber2000fb_enable_extregs(struct cfb_info *cfb)
1136 cfb->func_use_count += 1;
1138 if (cfb->func_use_count == 1) {
1139 int old;
1141 old = cyber2000_grphr(FUNC_CTL);
1142 cyber2000_grphw(FUNC_CTL, old | FUNC_CTL_EXTREGENBL);
1147 * Disable access to the extended registers
1149 static void cyber2000fb_disable_extregs(struct cfb_info *cfb)
1151 if (cfb->func_use_count == 1) {
1152 int old;
1154 old = cyber2000_grphr(FUNC_CTL);
1155 cyber2000_grphw(FUNC_CTL, old & ~FUNC_CTL_EXTREGENBL);
1158 cfb->func_use_count -= 1;
1162 * This is the only "static" reference to the internal data structures
1163 * of this driver. It is here solely at the moment to support the other
1164 * CyberPro modules external to this driver.
1166 static struct cfb_info *int_cfb_info;
1169 * Attach a capture/tv driver to the core CyberX0X0 driver.
1171 int cyber2000fb_attach(struct cyberpro_info *info, int idx)
1173 if (int_cfb_info != NULL) {
1174 info->dev = int_cfb_info->dev;
1175 info->regs = CyberRegs;
1176 info->fb = int_cfb_info->fb.screen_base;
1177 info->fb_size = int_cfb_info->fb.fix.smem_len;
1178 info->enable_extregs = cyber2000fb_enable_extregs;
1179 info->disable_extregs = cyber2000fb_disable_extregs;
1180 info->info = int_cfb_info;
1182 strncpy(info->dev_name, int_cfb_info->fb.fix.id, sizeof(info->dev_name));
1184 MOD_INC_USE_COUNT;
1187 return int_cfb_info != NULL;
1191 * Detach a capture/tv driver from the core CyberX0X0 driver.
1193 void cyber2000fb_detach(int idx)
1195 MOD_DEC_USE_COUNT;
1198 EXPORT_SYMBOL(cyber2000fb_attach);
1199 EXPORT_SYMBOL(cyber2000fb_detach);
1202 * These parameters give
1203 * 640x480, hsync 31.5kHz, vsync 60Hz
1205 static struct fb_videomode __devinitdata cyber2000fb_default_mode = {
1206 refresh: 60,
1207 xres: 640,
1208 yres: 480,
1209 pixclock: 39722,
1210 left_margin: 56,
1211 right_margin: 16,
1212 upper_margin: 34,
1213 lower_margin: 9,
1214 hsync_len: 88,
1215 vsync_len: 2,
1216 sync: FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
1217 vmode: FB_VMODE_NONINTERLACED
1220 int __init cyber2000fb_setup(char *options)
1222 return 0;
1225 static char igs_regs[] __devinitdata = {
1226 0x12, 0x00, 0x13, 0x00,
1227 0x16, 0x00,
1228 0x31, 0x00, 0x32, 0x00,
1229 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00,
1230 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x01,
1231 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00,
1232 0x70, 0x0b, 0x73, 0x30,
1233 0x74, 0x0b, 0x75, 0x17, 0x76, 0x00, 0x7a, 0xc8
1237 * We need to wake up the CyberPro, and make sure its in linear memory
1238 * mode. Unfortunately, this is specific to the platform and card that
1239 * we are running on.
1241 * On x86 and ARM, should we be initialising the CyberPro first via the
1242 * IO registers, and then the MMIO registers to catch all cases? Can we
1243 * end up in the situation where the chip is in MMIO mode, but not awake
1244 * on an x86 system?
1246 * Note that on the NetWinder, the firmware automatically detects the
1247 * type, width and size, and leaves this in extended registers 0x71 and
1248 * 0x72 for us.
1250 static inline void cyberpro_init_hw(struct cfb_info *cfb, int at_boot)
1252 int i;
1255 * Wake up the CyberPro.
1257 #ifdef __sparc__
1258 #ifdef __sparc_v9__
1259 #error "You loose, consult DaveM."
1260 #else
1262 * SPARC does not have an "outb" instruction, so we generate
1263 * I/O cycles storing into a reserved memory space at
1264 * physical address 0x3000000
1267 unsigned char *iop;
1269 iop = ioremap(0x3000000, 0x5000);
1270 if (iop == NULL) {
1271 prom_printf("iga5000: cannot map I/O\n");
1272 return -ENOMEM;
1275 writeb(0x18, iop + 0x46e8);
1276 writeb(0x01, iop + 0x102);
1277 writeb(0x08, iop + 0x46e8);
1278 writeb(0x33, iop + 0x3ce);
1279 writeb(0x01, iop + 0x3cf);
1281 iounmap((void *)iop);
1283 #endif
1285 if (at_boot) {
1287 * Use mclk from BIOS. Only read this if we're
1288 * initialising this card for the first time.
1289 * FIXME: what about hotplug?
1291 cfb->mclk_mult = cyber2000_grphr(MCLK_MULT);
1292 cfb->mclk_div = cyber2000_grphr(MCLK_DIV);
1294 #endif
1295 #ifdef __i386__
1297 * x86 is simple, we just do regular outb's instead of
1298 * cyber2000_outb.
1300 outb(0x18, 0x46e8);
1301 outb(0x01, 0x102);
1302 outb(0x08, 0x46e8);
1303 outb(0x33, 0x3ce);
1304 outb(0x01, 0x3cf);
1306 if (at_boot) {
1308 * Use mclk from BIOS. Only read this if we're
1309 * initialising this card for the first time.
1310 * FIXME: what about hotplug?
1312 cfb->mclk_mult = cyber2000_grphr(MCLK_MULT);
1313 cfb->mclk_div = cyber2000_grphr(MCLK_DIV);
1315 #endif
1316 #ifdef __arm__
1317 cyber2000_outb(0x18, 0x46e8);
1318 cyber2000_outb(0x01, 0x102);
1319 cyber2000_outb(0x08, 0x46e8);
1320 cyber2000_outb(0x33, 0x3ce);
1321 cyber2000_outb(0x01, 0x3cf);
1324 * MCLK on the NetWinder is fixed at 75MHz
1326 cfb->mclk_mult = 0xdb;
1327 cfb->mclk_div = 0x54;
1328 #endif
1331 * Initialise the CyberPro
1333 for (i = 0; i < sizeof(igs_regs); i += 2)
1334 cyber2000_grphw(igs_regs[i], igs_regs[i+1]);
1336 if (at_boot) {
1338 * get the video RAM size and width from the VGA register.
1339 * This should have been already initialised by the BIOS,
1340 * but if it's garbage, claim default 1MB VRAM (woody)
1342 cfb->mem_ctl1 = cyber2000_grphr(MEM_CTL1);
1343 cfb->mem_ctl2 = cyber2000_grphr(MEM_CTL2);
1344 } else {
1346 * Reprogram the MEM_CTL1 and MEM_CTL2 registers
1348 cyber2000_grphw(MEM_CTL1, cfb->mem_ctl1);
1349 cyber2000_grphw(MEM_CTL2, cfb->mem_ctl2);
1353 * Ensure thatwe are using the correct PLL.
1354 * (CyberPro 5000's may be programmed to use
1355 * an additional set of PLLs.
1357 cyber2000_outb(0xba, 0x3ce);
1358 cyber2000_outb(cyber2000_inb(0x3cf) & 0x80, 0x3cf);
1361 static struct cfb_info * __devinit
1362 cyberpro_alloc_fb_info(struct pci_dev *dev, const struct pci_device_id *id)
1364 struct cfb_info *cfb;
1366 cfb = kmalloc(sizeof(struct cfb_info) + sizeof(struct display) +
1367 sizeof(u32) * 16, GFP_KERNEL);
1369 if (!cfb)
1370 return NULL;
1372 memset(cfb, 0, sizeof(struct cfb_info) + sizeof(struct display));
1374 cfb->currcon = -1;
1375 cfb->dev = dev;
1376 cfb->ref_ps = 69842;
1377 cfb->divisors[0] = 1;
1378 cfb->divisors[1] = 2;
1379 cfb->divisors[2] = 4;
1381 if (id->driver_data == FB_ACCEL_IGS_CYBER2010)
1382 cfb->divisors[3] = 6;
1383 else
1384 cfb->divisors[3] = 8;
1386 sprintf(cfb->fb.fix.id, "CyberPro%4X", id->device);
1388 cfb->fb.fix.type = FB_TYPE_PACKED_PIXELS;
1389 cfb->fb.fix.type_aux = 0;
1390 cfb->fb.fix.xpanstep = 0;
1391 cfb->fb.fix.ypanstep = 1;
1392 cfb->fb.fix.ywrapstep = 0;
1393 cfb->fb.fix.accel = id->driver_data;
1395 cfb->fb.var.nonstd = 0;
1396 cfb->fb.var.activate = FB_ACTIVATE_NOW;
1397 cfb->fb.var.height = -1;
1398 cfb->fb.var.width = -1;
1399 cfb->fb.var.accel_flags = FB_ACCELF_TEXT;
1401 strcpy(cfb->fb.modename, cfb->fb.fix.id);
1402 strcpy(cfb->fb.fontname, "Acorn8x8");
1404 cfb->fb.fbops = &cyber2000fb_ops;
1405 cfb->fb.changevar = NULL;
1406 cfb->fb.switch_con = cyber2000fb_switch;
1407 cfb->fb.updatevar = cyber2000fb_updatevar;
1408 cfb->fb.blank = cyber2000fb_blank;
1409 cfb->fb.flags = FBINFO_FLAG_DEFAULT;
1410 cfb->fb.disp = (struct display *)(cfb + 1);
1411 cfb->fb.pseudo_palette = (void *)(cfb->fb.disp + 1);
1413 fb_alloc_cmap(&cfb->fb.cmap, NR_PALETTE, 0);
1415 return cfb;
1418 static void __devinit
1419 cyberpro_free_fb_info(struct cfb_info *cfb)
1421 if (cfb) {
1423 * Free the colourmap
1425 fb_alloc_cmap(&cfb->fb.cmap, 0, 0);
1427 kfree(cfb);
1432 * Map in the registers
1434 static int __devinit
1435 cyberpro_map_mmio(struct cfb_info *cfb, struct pci_dev *dev)
1437 u_long mmio_base;
1439 mmio_base = pci_resource_start(dev, 0) + MMIO_OFFSET;
1441 cfb->fb.fix.mmio_start = mmio_base + PCI_PHYS_OFFSET;
1442 cfb->fb.fix.mmio_len = MMIO_SIZE;
1444 if (!request_mem_region(mmio_base, MMIO_SIZE, "memory mapped I/O")) {
1445 printk("%s: memory mapped IO in use\n", cfb->fb.fix.id);
1446 return -EBUSY;
1449 CyberRegs = ioremap(mmio_base, MMIO_SIZE);
1450 if (!CyberRegs) {
1451 printk("%s: unable to map memory mapped IO\n",
1452 cfb->fb.fix.id);
1453 return -ENOMEM;
1455 return 0;
1459 * Unmap registers
1461 static void __devinit cyberpro_unmap_mmio(struct cfb_info *cfb)
1463 if (cfb && CyberRegs) {
1464 iounmap(CyberRegs);
1465 CyberRegs = NULL;
1467 release_mem_region(cfb->fb.fix.mmio_start - PCI_PHYS_OFFSET,
1468 cfb->fb.fix.mmio_len);
1473 * Map in screen memory
1475 static int __devinit
1476 cyberpro_map_smem(struct cfb_info *cfb, struct pci_dev *dev, u_long smem_len)
1478 u_long smem_base;
1480 smem_base = pci_resource_start(dev, 0);
1482 cfb->fb.fix.smem_start = smem_base + PCI_PHYS_OFFSET;
1483 cfb->fb.fix.smem_len = smem_len;
1485 if (!request_mem_region(smem_base, smem_len, "frame buffer")) {
1486 printk("%s: frame buffer in use\n",
1487 cfb->fb.fix.id);
1488 return -EBUSY;
1491 cfb->fb.screen_base = ioremap(smem_base, smem_len);
1492 if (!cfb->fb.screen_base) {
1493 printk("%s: unable to map screen memory\n",
1494 cfb->fb.fix.id);
1495 return -ENOMEM;
1498 return 0;
1501 static void __devinit cyberpro_unmap_smem(struct cfb_info *cfb)
1503 if (cfb && cfb->fb.screen_base) {
1504 iounmap(cfb->fb.screen_base);
1505 cfb->fb.screen_base = NULL;
1507 release_mem_region(cfb->fb.fix.smem_start - PCI_PHYS_OFFSET,
1508 cfb->fb.fix.smem_len);
1512 static int __devinit
1513 cyberpro_probe(struct pci_dev *dev, const struct pci_device_id *id)
1515 struct cfb_info *cfb;
1516 u_int h_sync, v_sync;
1517 u_long smem_size;
1518 int err;
1520 err = pci_enable_device(dev);
1521 if (err)
1522 return err;
1524 err = -ENOMEM;
1525 cfb = cyberpro_alloc_fb_info(dev, id);
1526 if (!cfb)
1527 goto failed;
1529 err = cyberpro_map_mmio(cfb, dev);
1530 if (err)
1531 goto failed;
1533 cyberpro_init_hw(cfb, 1);
1535 switch (cfb->mem_ctl2 & MEM_CTL2_SIZE_MASK) {
1536 case MEM_CTL2_SIZE_4MB: smem_size = 0x00400000; break;
1537 case MEM_CTL2_SIZE_2MB: smem_size = 0x00200000; break;
1538 default: smem_size = 0x00100000; break;
1541 err = cyberpro_map_smem(cfb, dev, smem_size);
1542 if (err)
1543 goto failed;
1545 if (!fb_find_mode(&cfb->fb.var, &cfb->fb, NULL, NULL, 0,
1546 &cyber2000fb_default_mode, 8)) {
1547 printk("%s: no valid mode found\n", cfb->fb.fix.id);
1548 goto failed;
1551 cfb->fb.var.yres_virtual = cfb->fb.fix.smem_len * 8 /
1552 (cfb->fb.var.bits_per_pixel * cfb->fb.var.xres_virtual);
1554 if (cfb->fb.var.yres_virtual < cfb->fb.var.yres)
1555 cfb->fb.var.yres_virtual = cfb->fb.var.yres;
1557 cyber2000fb_set_var(&cfb->fb.var, -1, &cfb->fb);
1560 * Calculate the hsync and vsync frequencies. Note that
1561 * we split the 1e12 constant up so that we can preserve
1562 * the precision and fit the results into 32-bit registers.
1563 * (1953125000 * 512 = 1e12)
1565 h_sync = 1953125000 / cfb->fb.var.pixclock;
1566 h_sync = h_sync * 512 / (cfb->fb.var.xres + cfb->fb.var.left_margin +
1567 cfb->fb.var.right_margin + cfb->fb.var.hsync_len);
1568 v_sync = h_sync / (cfb->fb.var.yres + cfb->fb.var.upper_margin +
1569 cfb->fb.var.lower_margin + cfb->fb.var.vsync_len);
1571 printk(KERN_INFO "%s: %dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
1572 cfb->fb.fix.id, cfb->fb.fix.smem_len >> 10,
1573 cfb->fb.var.xres, cfb->fb.var.yres,
1574 h_sync / 1000, h_sync % 1000, v_sync);
1576 err = register_framebuffer(&cfb->fb);
1577 if (err < 0)
1578 goto failed;
1581 * Our driver data
1583 dev->driver_data = cfb;
1584 if (int_cfb_info == NULL)
1585 int_cfb_info = cfb;
1587 return 0;
1589 failed:
1590 cyberpro_unmap_smem(cfb);
1591 cyberpro_unmap_mmio(cfb);
1592 cyberpro_free_fb_info(cfb);
1594 return err;
1597 static void __devexit cyberpro_remove(struct pci_dev *dev)
1599 struct cfb_info *cfb = (struct cfb_info *)dev->driver_data;
1601 if (cfb) {
1603 * If unregister_framebuffer fails, then
1604 * we will be leaving hooks that could cause
1605 * oopsen laying around.
1607 if (unregister_framebuffer(&cfb->fb))
1608 printk(KERN_WARNING "%s: danger Will Robinson, "
1609 "danger danger! Oopsen imminent!\n",
1610 cfb->fb.fix.id);
1611 cyberpro_unmap_smem(cfb);
1612 cyberpro_unmap_mmio(cfb);
1613 cyberpro_free_fb_info(cfb);
1616 * Ensure that the driver data is no longer
1617 * valid.
1619 dev->driver_data = NULL;
1620 if (cfb == int_cfb_info)
1621 int_cfb_info = NULL;
1625 static void cyberpro_suspend(struct pci_dev *dev)
1630 * Re-initialise the CyberPro hardware
1632 static void cyberpro_resume(struct pci_dev *dev)
1634 struct cfb_info *cfb = (struct cfb_info *)dev->driver_data;
1636 if (cfb) {
1637 cyberpro_init_hw(cfb, 0);
1640 * Restore the old video mode and the palette.
1641 * We also need to tell fbcon to redraw the console.
1643 cfb->fb.var.activate = FB_ACTIVATE_NOW;
1644 cyber2000fb_set_var(&cfb->fb.var, -1, &cfb->fb);
1648 static struct pci_device_id cyberpro_pci_table[] __devinitdata = {
1649 { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000,
1650 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_IGS_CYBER2000 },
1651 { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010,
1652 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_IGS_CYBER2010 },
1653 { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5000,
1654 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_IGS_CYBER5000 },
1655 { 0, }
1658 MODULE_DEVICE_TABLE(pci, cyberpro_pci_table);
1660 static struct pci_driver cyberpro_driver = {
1661 name: "CyberPro",
1662 probe: cyberpro_probe,
1663 remove: cyberpro_remove,
1664 suspend: cyberpro_suspend,
1665 resume: cyberpro_resume,
1666 id_table: cyberpro_pci_table
1670 * I don't think we can use the "module_init" stuff here because
1671 * the fbcon stuff may not be initialised yet. Hence the #ifdef
1672 * around module_init.
1674 int __init cyber2000fb_init(void)
1676 return pci_module_init(&cyberpro_driver);
1679 static void __exit cyberpro_exit(void)
1681 pci_unregister_driver(&cyberpro_driver);
1684 #ifdef MODULE
1685 module_init(cyber2000fb_init);
1686 #endif
1687 module_exit(cyberpro_exit);