2 * linux/drivers/video/cyber2000fb.c
4 * Copyright (C) 1998-2000 Russell King
6 * MIPS and 50xx clock support
7 * Copyright (C) 2001 Bradley D. LaRonde <brad@ltc.com>
9 * 32 bit support, text color and panning fixes for modes != 8 bit
10 * Copyright (C) 2002 Denis Oliver Kropp <dok@directfb.org>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
16 * Intergraphics CyberPro 2000, 2010 and 5000 frame buffer device
20 * Note that we now use the new fbcon fix, var and cmap scheme. We do still
21 * have to check which console is the currently displayed one however, since
22 * especially for the colourmap stuff. Once fbcon has been fully migrated,
23 * we can kill the last 5 references to cfb->currcon.
25 * We also use the new hotplug PCI subsystem. I'm not sure if there are any
26 * such cards, but I'm erring on the side of caution. We don't want to go
27 * pop just because someone does have one.
29 * Note that this doesn't work fully in the case of multiple CyberPro cards
30 * with grabbers. We currently can only attach to the first CyberPro card
33 #include <linux/config.h>
34 #include <linux/module.h>
35 #include <linux/kernel.h>
36 #include <linux/errno.h>
37 #include <linux/string.h>
39 #include <linux/tty.h>
40 #include <linux/slab.h>
41 #include <linux/delay.h>
43 #include <linux/pci.h>
44 #include <linux/init.h>
48 #include <asm/pgtable.h>
49 #include <asm/system.h>
50 #include <asm/uaccess.h>
52 #include <video/fbcon.h>
53 #include <video/fbcon-cfb8.h>
54 #include <video/fbcon-cfb16.h>
55 #include <video/fbcon-cfb24.h>
56 #include <video/fbcon-cfb32.h>
59 * Define this if you don't want RGB565, but RGB555 for 16bpp displays.
61 /*#define CFB16_IS_CFB15*/
63 #include "cyber2000fb.h"
67 struct display_switch *dispsw;
69 unsigned char *region;
82 } palette[NR_PALETTE];
90 static char default_font_storage[40];
91 static char *default_font = "Acorn8x8";
92 MODULE_PARM(default_font, "s");
93 MODULE_PARM_DESC(default_font, "Default font name");
98 #define cyber2000fb_writel(val,reg,cfb) writel(val, (cfb)->regs + (reg))
99 #define cyber2000fb_writew(val,reg,cfb) writew(val, (cfb)->regs + (reg))
100 #define cyber2000fb_writeb(val,reg,cfb) writeb(val, (cfb)->regs + (reg))
102 #define cyber2000fb_readb(reg,cfb) readb((cfb)->regs + (reg))
105 cyber2000_crtcw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
107 cyber2000fb_writew((reg & 255) | val << 8, 0x3d4, cfb);
111 cyber2000_grphw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
113 cyber2000fb_writew((reg & 255) | val << 8, 0x3ce, cfb);
116 static inline unsigned int
117 cyber2000_grphr(unsigned int reg, struct cfb_info *cfb)
119 cyber2000fb_writeb(reg, 0x3ce, cfb);
120 return cyber2000fb_readb(0x3cf, cfb);
124 cyber2000_attrw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
126 cyber2000fb_readb(0x3da, cfb);
127 cyber2000fb_writeb(reg, 0x3c0, cfb);
128 cyber2000fb_readb(0x3c1, cfb);
129 cyber2000fb_writeb(val, 0x3c0, cfb);
133 cyber2000_seqw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
135 cyber2000fb_writew((reg & 255) | val << 8, 0x3c4, cfb);
138 /* -------------------- Hardware specific routines ------------------------- */
141 * Hardware Cyber2000 Acceleration
143 static void cyber2000_accel_wait(struct cfb_info *cfb)
147 while (cyber2000fb_readb(CO_REG_CONTROL, cfb) & 0x80) {
149 debug_printf("accel_wait timed out\n");
150 cyber2000fb_writeb(0, CO_REG_CONTROL, cfb);
157 static void cyber2000_accel_setup(struct display *p)
159 struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
161 cfb->dispsw->setup(p);
165 cyber2000_accel_bmove(struct display *p, int sy, int sx, int dy, int dx,
166 int height, int width)
168 struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
169 struct fb_var_screeninfo *var = &p->fb_info->var;
172 int cmd = CO_CMD_L_PATTERN_FGCOL;
183 cmd |= CO_CMD_L_INC_LEFT;
195 cmd |= CO_CMD_L_INC_UP;
198 src = sx + sy * var->xres_virtual;
199 dst = dx + dy * var->xres_virtual;
201 cyber2000_accel_wait(cfb);
202 cyber2000fb_writeb(0x00, CO_REG_CONTROL, cfb);
203 cyber2000fb_writeb(0x03, CO_REG_FORE_MIX, cfb);
204 cyber2000fb_writew(width, CO_REG_WIDTH, cfb);
206 if (var->bits_per_pixel != 24) {
207 cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
208 cyber2000fb_writel(src, CO_REG_SRC_PTR, cfb);
210 cyber2000fb_writel(dst * 3, CO_REG_DEST_PTR, cfb);
211 cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb);
212 cyber2000fb_writel(src * 3, CO_REG_SRC_PTR, cfb);
215 cyber2000fb_writew(height, CO_REG_HEIGHT, cfb);
216 cyber2000fb_writew(cmd, CO_REG_CMD_L, cfb);
217 cyber2000fb_writew(0x2800, CO_REG_CMD_H, cfb);
221 cyber2000_accel_clear(struct vc_data *conp, struct display *p, int sy, int sx,
222 int height, int width)
224 struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
225 struct fb_var_screeninfo *var = &p->fb_info->var;
228 u32 bgx = attr_bgcol_ec(p, conp);
233 dst = sx * fw + sy * var->xres_virtual * fh;
234 width = width * fw - 1;
235 height = height * fh - 1;
237 cyber2000_accel_wait(cfb);
238 cyber2000fb_writeb(0x00, CO_REG_CONTROL, cfb);
239 cyber2000fb_writeb(0x03, CO_REG_FORE_MIX, cfb);
240 cyber2000fb_writew(width, CO_REG_WIDTH, cfb);
241 cyber2000fb_writew(height, CO_REG_HEIGHT, cfb);
243 switch (var->bits_per_pixel) {
246 bgx = ((u16 *)p->dispsw_data)[bgx];
248 cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
252 cyber2000fb_writel(dst * 3, CO_REG_DEST_PTR, cfb);
253 cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb);
254 bgx = ((u32 *)p->dispsw_data)[bgx];
258 bgx = ((u32 *)p->dispsw_data)[bgx];
259 cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
263 cyber2000fb_writel(bgx, CO_REG_FOREGROUND, cfb);
264 cyber2000fb_writew(CO_CMD_L_PATTERN_FGCOL, CO_REG_CMD_L, cfb);
265 cyber2000fb_writew(0x0800, CO_REG_CMD_H, cfb);
269 cyber2000_accel_putc(struct vc_data *conp, struct display *p, int c,
272 struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
274 cyber2000_accel_wait(cfb);
275 cfb->dispsw->putc(conp, p, c, yy, xx);
279 cyber2000_accel_putcs(struct vc_data *conp, struct display *p,
280 const unsigned short *s, int count, int yy, int xx)
282 struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
284 cyber2000_accel_wait(cfb);
285 cfb->dispsw->putcs(conp, p, s, count, yy, xx);
288 static void cyber2000_accel_revc(struct display *p, int xx, int yy)
290 struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
292 cyber2000_accel_wait(cfb);
293 cfb->dispsw->revc(p, xx, yy);
297 cyber2000_accel_clear_margins(struct vc_data *conp, struct display *p,
300 struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
302 cfb->dispsw->clear_margins(conp, p, bottom_only);
305 static struct display_switch fbcon_cyber_accel = {
306 setup: cyber2000_accel_setup,
307 bmove: cyber2000_accel_bmove,
308 clear: cyber2000_accel_clear,
309 putc: cyber2000_accel_putc,
310 putcs: cyber2000_accel_putcs,
311 revc: cyber2000_accel_revc,
312 clear_margins: cyber2000_accel_clear_margins,
313 fontwidthmask: FONTWIDTH(8)|FONTWIDTH(16)
317 * Set a single color register. Return != 0 for invalid regno.
320 cyber2000_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
321 u_int transp, struct fb_info *info)
323 struct cfb_info *cfb = (struct cfb_info *)info;
325 u_int alpha = transp ^ 0xFFFF;
327 if (regno >= NR_PALETTE)
335 cfb->palette[regno].red = red;
336 cfb->palette[regno].green = green;
337 cfb->palette[regno].blue = blue;
339 switch (cfb->fb.var.bits_per_pixel) {
340 #ifdef FBCON_HAS_CFB8
342 cyber2000fb_writeb(regno, 0x3c8, cfb);
343 cyber2000fb_writeb(red, 0x3c9, cfb);
344 cyber2000fb_writeb(green, 0x3c9, cfb);
345 cyber2000fb_writeb(blue, 0x3c9, cfb);
349 #ifdef FBCON_HAS_CFB16
351 #ifndef CFB16_IS_CFB15
354 cyber2000fb_writeb(regno << 2, 0x3c8, cfb);
355 cyber2000fb_writeb(cfb->palette[regno >> 1].red, 0x3c9, cfb);
356 cyber2000fb_writeb(green, 0x3c9, cfb);
357 cyber2000fb_writeb(cfb->palette[regno >> 1].blue, 0x3c9, cfb);
362 cyber2000fb_writeb(regno << 3, 0x3c8, cfb);
363 cyber2000fb_writeb(red, 0x3c9, cfb);
364 cyber2000fb_writeb(cfb->palette[regno << 1].green, 0x3c9, cfb);
365 cyber2000fb_writeb(blue, 0x3c9, cfb);
369 ((u16 *)cfb->fb.pseudo_palette)[regno] =
370 ((red << 8) & 0xf800) |
371 ((green << 3) & 0x07e0) |
378 cyber2000fb_writeb(regno << 3, 0x3c8, cfb);
379 cyber2000fb_writeb(red, 0x3c9, cfb);
380 cyber2000fb_writeb(green, 0x3c9, cfb);
381 cyber2000fb_writeb(blue, 0x3c9, cfb);
384 ((u16 *)cfb->fb.pseudo_palette)[regno] =
385 ((red << 7) & 0x7c00) |
386 ((green << 2) & 0x03e0) |
392 #ifdef FBCON_HAS_CFB24
394 cyber2000fb_writeb(regno, 0x3c8, cfb);
395 cyber2000fb_writeb(red, 0x3c9, cfb);
396 cyber2000fb_writeb(green, 0x3c9, cfb);
397 cyber2000fb_writeb(blue, 0x3c9, cfb);
400 ((u32 *)cfb->fb.pseudo_palette)[regno] =
401 (red << 16) | (green << 8) | blue;
405 #ifdef FBCON_HAS_CFB32
407 cyber2000fb_writeb(regno, 0x3c8, cfb);
408 cyber2000fb_writeb(red, 0x3c9, cfb);
409 cyber2000fb_writeb(green, 0x3c9, cfb);
410 cyber2000fb_writeb(blue, 0x3c9, cfb);
413 ((u32 *)cfb->fb.pseudo_palette)[regno] =
414 (alpha << 24) | (red << 16) | (green << 8) | blue;
446 static const u_char crtc_idx[] = {
447 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
449 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18
452 static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw)
459 for (i = 0; i < NR_PALETTE; i++) {
460 cyber2000fb_writeb(i, 0x3c8, cfb);
461 cyber2000fb_writeb(0, 0x3c9, cfb);
462 cyber2000fb_writeb(0, 0x3c9, cfb);
463 cyber2000fb_writeb(0, 0x3c9, cfb);
466 cyber2000fb_writeb(0xef, 0x3c2, cfb);
467 cyber2000_crtcw(0x11, 0x0b, cfb);
468 cyber2000_attrw(0x11, 0x00, cfb);
470 cyber2000_seqw(0x00, 0x01, cfb);
471 cyber2000_seqw(0x01, 0x01, cfb);
472 cyber2000_seqw(0x02, 0x0f, cfb);
473 cyber2000_seqw(0x03, 0x00, cfb);
474 cyber2000_seqw(0x04, 0x0e, cfb);
475 cyber2000_seqw(0x00, 0x03, cfb);
477 for (i = 0; i < sizeof(crtc_idx); i++)
478 cyber2000_crtcw(crtc_idx[i], hw->crtc[i], cfb);
480 for (i = 0x0a; i < 0x10; i++)
481 cyber2000_crtcw(i, 0, cfb);
483 cyber2000_grphw(0x11, hw->crtc_ofl, cfb);
484 cyber2000_grphw(0x00, 0x00, cfb);
485 cyber2000_grphw(0x01, 0x00, cfb);
486 cyber2000_grphw(0x02, 0x00, cfb);
487 cyber2000_grphw(0x03, 0x00, cfb);
488 cyber2000_grphw(0x04, 0x00, cfb);
489 cyber2000_grphw(0x05, 0x60, cfb);
490 cyber2000_grphw(0x06, 0x05, cfb);
491 cyber2000_grphw(0x07, 0x0f, cfb);
492 cyber2000_grphw(0x08, 0xff, cfb);
494 /* Attribute controller registers */
495 for (i = 0; i < 16; i++)
496 cyber2000_attrw(i, i, cfb);
498 cyber2000_attrw(0x10, 0x01, cfb);
499 cyber2000_attrw(0x11, 0x00, cfb);
500 cyber2000_attrw(0x12, 0x0f, cfb);
501 cyber2000_attrw(0x13, 0x00, cfb);
502 cyber2000_attrw(0x14, 0x00, cfb);
504 /* woody: set the interlaced bit... */
505 /* FIXME: what about doublescan? */
506 cyber2000fb_writeb(0x11, 0x3ce, cfb);
507 i = cyber2000fb_readb(0x3cf, cfb);
508 if (hw->vmode == FB_VMODE_INTERLACED)
512 cyber2000fb_writeb(i, 0x3cf, cfb);
515 cyber2000_grphw(DCLK_MULT, hw->clock_mult, cfb);
516 cyber2000_grphw(DCLK_DIV, hw->clock_div, cfb);
517 cyber2000_grphw(MCLK_MULT, cfb->mclk_mult, cfb);
518 cyber2000_grphw(MCLK_DIV, cfb->mclk_div, cfb);
519 cyber2000_grphw(0x90, 0x01, cfb);
520 cyber2000_grphw(0xb9, 0x80, cfb);
521 cyber2000_grphw(0xb9, 0x00, cfb);
523 cyber2000fb_writeb(0x56, 0x3ce, cfb);
524 i = cyber2000fb_readb(0x3cf, cfb);
525 cyber2000fb_writeb(i | 4, 0x3cf, cfb);
526 cyber2000fb_writeb(hw->palette_ctrl, 0x3c6, cfb);
527 cyber2000fb_writeb(i, 0x3cf, cfb);
529 cyber2000fb_writeb(0x20, 0x3c0, cfb);
530 cyber2000fb_writeb(0xff, 0x3c6, cfb);
532 cyber2000_grphw(0x14, hw->fetch, cfb);
533 cyber2000_grphw(0x15, ((hw->fetch >> 8) & 0x03) |
534 ((hw->pitch >> 4) & 0x30), cfb);
535 cyber2000_grphw(0x77, hw->visualid, cfb);
537 /* make sure we stay in linear mode */
538 cyber2000_grphw(0x33, 0x0d, cfb);
541 * Set up accelerator registers
543 cyber2000fb_writew(hw->width, CO_REG_SRC_WIDTH, cfb);
544 cyber2000fb_writew(hw->width, CO_REG_DEST_WIDTH, cfb);
545 cyber2000fb_writeb(hw->pixformat, CO_REG_PIX_FORMAT, cfb);
549 cyber2000fb_update_start(struct cfb_info *cfb, struct fb_var_screeninfo *var)
553 base = var->yoffset * var->xres_virtual + var->xoffset;
555 /* have to be careful, because bits_per_pixel might be 15
556 in this version of the driver -- dok@directfb.org 2002/06/13 */
557 base *= (var->bits_per_pixel + 7) >> 3;
564 cyber2000_grphw(0x10, base >> 16 | 0x10, cfb);
565 cyber2000_crtcw(0x0c, base >> 8, cfb);
566 cyber2000_crtcw(0x0d, base, cfb);
575 cyber2000fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
576 struct fb_info *info)
578 struct cfb_info *cfb = (struct cfb_info *)info;
579 struct fb_cmap *dcmap = &fb_display[con].cmap;
582 /* no colormap allocated? */
586 if (cfb->fb.var.bits_per_pixel == 16)
591 err = fb_alloc_cmap(dcmap, size, 0);
595 * we should be able to remove this test once fbcon has been
598 if (!err && con == cfb->currcon) {
599 err = fb_set_cmap(cmap, kspc, cyber2000_setcolreg, &cfb->fb);
600 dcmap = &cfb->fb.cmap;
604 fb_copy_cmap(cmap, dcmap, kspc ? 0 : 1);
610 cyber2000fb_decode_crtc(struct par_info *hw, struct cfb_info *cfb,
611 struct fb_var_screeninfo *var)
613 u_int Htotal, Hblankend, Hsyncend;
614 u_int Vtotal, Vdispend, Vblankstart, Vblankend, Vsyncstart, Vsyncend;
615 #define BIT(v,b1,m,b2) (((v >> b1) & m) << b2)
617 hw->crtc[13] = hw->pitch;
622 Htotal = var->xres + var->right_margin +
623 var->hsync_len + var->left_margin;
628 hw->crtc[0] = (Htotal >> 3) - 5;
629 hw->crtc[1] = (var->xres >> 3) - 1;
630 hw->crtc[2] = var->xres >> 3;
631 hw->crtc[4] = (var->xres + var->right_margin) >> 3;
633 Hblankend = (Htotal - 4*8) >> 3;
635 hw->crtc[3] = BIT(Hblankend, 0, 0x1f, 0) |
638 Hsyncend = (var->xres + var->right_margin + var->hsync_len) >> 3;
640 hw->crtc[5] = BIT(Hsyncend, 0, 0x1f, 0) |
641 BIT(Hblankend, 5, 0x01, 7);
643 Vdispend = var->yres - 1;
644 Vsyncstart = var->yres + var->lower_margin;
645 Vsyncend = var->yres + var->lower_margin + var->vsync_len;
646 Vtotal = var->yres + var->lower_margin + var->vsync_len +
647 var->upper_margin - 2;
652 Vblankstart = var->yres + 6;
653 Vblankend = Vtotal - 10;
655 hw->crtc[6] = Vtotal;
656 hw->crtc[7] = BIT(Vtotal, 8, 0x01, 0) |
657 BIT(Vdispend, 8, 0x01, 1) |
658 BIT(Vsyncstart, 8, 0x01, 2) |
659 BIT(Vblankstart,8, 0x01, 3) |
661 BIT(Vtotal, 9, 0x01, 5) |
662 BIT(Vdispend, 9, 0x01, 6) |
663 BIT(Vsyncstart, 9, 0x01, 7);
664 hw->crtc[9] = BIT(0, 0, 0x1f, 0) |
665 BIT(Vblankstart,9, 0x01, 5) |
667 hw->crtc[10] = Vsyncstart;
668 hw->crtc[11] = BIT(Vsyncend, 0, 0x0f, 0) |
670 hw->crtc[12] = Vdispend;
671 hw->crtc[15] = Vblankstart;
672 hw->crtc[16] = Vblankend;
675 /* overflow - graphics reg 0x11 */
676 /* 0=VTOTAL:10 1=VDEND:10 2=VRSTART:10 3=VBSTART:10
677 * 4=LINECOMP:10 5-IVIDEO 6=FIXCNT
680 BIT(Vtotal, 10, 0x01, 0) |
681 BIT(Vdispend, 10, 0x01, 1) |
682 BIT(Vsyncstart, 10, 0x01, 2) |
683 BIT(Vblankstart,10, 0x01, 3) |
690 * The following was discovered by a good monitor, bit twiddling, theorising
691 * and but mostly luck. Strangely, it looks like everyone elses' PLL!
694 * fclock = fpll / div2
695 * fpll = fref * mult / div1
697 * fref = 14.318MHz (69842ps)
699 * div1 = (reg0xb1.5:0 + 1)
700 * div2 = 2^(reg0xb1.7:6)
701 * fpll should be between 115 and 260 MHz
702 * (8696ps and 3846ps)
705 cyber2000fb_decode_clock(struct par_info *hw, struct cfb_info *cfb,
706 struct fb_var_screeninfo *var)
708 u_long pll_ps = var->pixclock;
709 const u_long ref_ps = cfb->ref_ps;
710 u_int div2, t_div1, best_div1, best_mult;
716 * find div2 such that 115MHz < fpll < 260MHz
719 for (div2 = 0; div2 < 4; div2++) {
722 new_pll = pll_ps / cfb->divisors[div2];
723 if (8696 > new_pll && new_pll > 3846) {
734 * Given pll_ps and ref_ps, find:
735 * pll_ps * 0.995 < pll_ps_calc < pll_ps * 1.005
736 * where { 1 < best_div1 < 32, 1 < best_mult < 256 }
737 * pll_ps_calc = best_div1 / (ref_ps * best_mult)
739 best_diff = 0x7fffffff;
742 for (t_div1 = 32; t_div1 > 1; t_div1 -= 1) {
743 u_int rr, t_mult, t_pll_ps;
747 * Find the multiplier for this divisor
749 rr = ref_ps * t_div1;
750 t_mult = (rr + pll_ps / 2) / pll_ps;
753 * Is the multiplier within the correct range?
755 if (t_mult > 256 || t_mult < 2)
759 * Calculate the actual clock period from this multiplier
760 * and divisor, and estimate the error.
762 t_pll_ps = (rr + t_mult / 2) / t_mult;
763 diff = pll_ps - t_pll_ps;
767 if (diff < best_diff) {
774 * If we hit an exact value, there is no point in continuing.
784 hw->clock_mult = best_mult - 1;
785 hw->clock_div = div2 << 6 | (best_div1 - 1);
787 vco = ref_ps * best_div1 / best_mult;
788 if ((ref_ps == 40690) && (vco < 5556))
789 /* Set VFSEL when VCO > 180MHz (5.556 ps). */
790 hw->clock_div |= DCLK_DIV_VFSEL;
796 * Decode the info required for the hardware.
797 * This involves the PLL parameters for the dot clock,
798 * CRTC registers, and accelerator settings.
801 cyber2000fb_decode_var(struct fb_var_screeninfo *var, struct cfb_info *cfb,
806 hw->width = var->xres_virtual;
807 hw->palette_ctrl = 0x06;
808 hw->vmode = var->vmode;
810 switch (var->bits_per_pixel) {
811 #ifdef FBCON_HAS_CFB8
812 case 8: /* PSEUDOCOLOUR, 256 */
813 hw->pixformat = PIXFORMAT_8BPP;
814 hw->visualid = VISUALID_256;
815 hw->pitch = hw->width >> 3;
818 #ifdef FBCON_HAS_CFB16
819 case 16:/* DIRECTCOLOUR, 64k */
820 #ifndef CFB16_IS_CFB15
821 hw->pixformat = PIXFORMAT_16BPP;
822 hw->visualid = VISUALID_64K;
823 hw->pitch = hw->width >> 2;
824 hw->palette_ctrl |= 0x10;
827 case 15:/* DIRECTCOLOUR, 32k */
828 hw->pixformat = PIXFORMAT_16BPP;
829 hw->visualid = VISUALID_32K;
830 hw->pitch = hw->width >> 2;
831 hw->palette_ctrl |= 0x10;
835 #ifdef FBCON_HAS_CFB24
836 case 24:/* TRUECOLOUR, 16m */
837 hw->pixformat = PIXFORMAT_24BPP;
838 hw->visualid = VISUALID_16M;
840 hw->pitch = hw->width >> 3;
841 hw->palette_ctrl |= 0x10;
844 #ifdef FBCON_HAS_CFB32
845 case 32:/* TRUECOLOUR, 16m */
846 hw->pixformat = PIXFORMAT_32BPP;
847 hw->visualid = VISUALID_16M_32;
848 hw->pitch = hw->width >> 1;
849 hw->palette_ctrl |= 0x10;
856 err = cyber2000fb_decode_clock(hw, cfb, var);
860 err = cyber2000fb_decode_crtc(hw, cfb, var);
865 hw->fetch = hw->pitch;
866 if (!(cfb->mem_ctl2 & MEM_CTL2_64BIT))
874 * Set the User Defined Part of the Display
877 cyber2000fb_set_var(struct fb_var_screeninfo *var, int con,
878 struct fb_info *info)
880 struct cfb_info *cfb = (struct cfb_info *)info;
881 struct display *display;
886 * CONUPDATE and SMOOTH_XPAN are equal. However,
887 * SMOOTH_XPAN is only used internally by fbcon.
889 if (var->vmode & FB_VMODE_CONUPDATE) {
890 var->vmode |= FB_VMODE_YWRAP;
891 var->xoffset = cfb->fb.var.xoffset;
892 var->yoffset = cfb->fb.var.yoffset;
895 err = cyber2000fb_decode_var(var, (struct cfb_info *)info, &hw);
899 if (var->activate & FB_ACTIVATE_TEST)
902 if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
905 if (cfb->fb.var.xres != var->xres)
907 if (cfb->fb.var.yres != var->yres)
909 if (cfb->fb.var.xres_virtual != var->xres_virtual)
911 if (cfb->fb.var.yres_virtual != var->yres_virtual)
913 if (cfb->fb.var.bits_per_pixel != var->bits_per_pixel)
917 display = cfb->fb.disp;
920 display = fb_display + con;
923 var->red.msb_right = 0;
924 var->green.msb_right = 0;
925 var->blue.msb_right = 0;
927 switch (var->bits_per_pixel) {
928 #ifdef FBCON_HAS_CFB8
929 case 8: /* PSEUDOCOLOUR, 256 */
932 var->green.offset = 0;
933 var->green.length = 8;
934 var->blue.offset = 0;
935 var->blue.length = 8;
937 cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
938 cfb->dispsw = &fbcon_cfb8;
939 display->dispsw_data = NULL;
940 display->next_line = var->xres_virtual;
943 #ifdef FBCON_HAS_CFB16
944 case 16:/* DIRECTCOLOUR, 64k */
945 #ifndef CFB16_IS_CFB15
946 var->red.offset = 11;
948 var->green.offset = 5;
949 var->green.length = 6;
950 var->blue.offset = 0;
951 var->blue.length = 5;
953 cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR;
954 cfb->dispsw = &fbcon_cfb16;
955 display->dispsw_data = cfb->fb.pseudo_palette;
956 display->next_line = var->xres_virtual * 2;
959 case 15:/* DIRECTCOLOUR, 32k */
960 var->bits_per_pixel = 15;
961 var->red.offset = 10;
963 var->green.offset = 5;
964 var->green.length = 5;
965 var->blue.offset = 0;
966 var->blue.length = 5;
968 cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR;
969 cfb->dispsw = &fbcon_cfb16;
970 display->dispsw_data = cfb->fb.pseudo_palette;
971 display->next_line = var->xres_virtual * 2;
974 #ifdef FBCON_HAS_CFB24
975 case 24:/* TRUECOLOUR, 16m */
976 var->red.offset = 16;
978 var->green.offset = 8;
979 var->green.length = 8;
980 var->blue.offset = 0;
981 var->blue.length = 8;
983 cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
984 cfb->dispsw = &fbcon_cfb24;
985 display->dispsw_data = cfb->fb.pseudo_palette;
986 display->next_line = var->xres_virtual * 3;
989 #ifdef FBCON_HAS_CFB32
990 case 32:/* TRUECOLOUR, 16m */
991 var->transp.offset = 24;
992 var->transp.length = 8;
993 var->red.offset = 16;
995 var->green.offset = 8;
996 var->green.length = 8;
997 var->blue.offset = 0;
998 var->blue.length = 8;
1000 cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
1001 cfb->dispsw = &fbcon_cfb32;
1002 display->dispsw_data = cfb->fb.pseudo_palette;
1003 display->next_line = var->xres_virtual * 4;
1006 default:/* in theory this should never happen */
1007 printk(KERN_WARNING "%s: no support for %dbpp\n",
1008 cfb->fb.fix.id, var->bits_per_pixel);
1009 cfb->dispsw = &fbcon_dummy;
1013 if (var->accel_flags & FB_ACCELF_TEXT && cfb->dispsw != &fbcon_dummy)
1014 display->dispsw = &fbcon_cyber_accel;
1016 display->dispsw = cfb->dispsw;
1018 cfb->fb.fix.line_length = display->next_line;
1020 display->screen_base = cfb->fb.screen_base;
1021 display->line_length = cfb->fb.fix.line_length;
1022 display->visual = cfb->fb.fix.visual;
1023 display->type = cfb->fb.fix.type;
1024 display->type_aux = cfb->fb.fix.type_aux;
1025 display->ypanstep = cfb->fb.fix.ypanstep;
1026 display->ywrapstep = cfb->fb.fix.ywrapstep;
1027 display->can_soft_blank = 1;
1028 display->inverse = 0;
1031 cfb->fb.var.activate &= ~FB_ACTIVATE_ALL;
1034 * Update the old var. The fbcon drivers still use this.
1035 * Once they are using cfb->fb.var, this can be dropped.
1038 display->var = cfb->fb.var;
1041 * If we are setting all the virtual consoles, also set the
1042 * defaults used to create new consoles.
1044 if (var->activate & FB_ACTIVATE_ALL)
1045 cfb->fb.disp->var = cfb->fb.var;
1047 if (chgvar && info && cfb->fb.changevar)
1048 cfb->fb.changevar(con);
1050 cyber2000fb_update_start(cfb, var);
1051 cyber2000fb_set_timing(cfb, &hw);
1052 fb_set_cmap(&cfb->fb.cmap, 1, cyber2000_setcolreg, &cfb->fb);
1059 * Pan or Wrap the Display
1062 cyber2000fb_pan_display(struct fb_var_screeninfo *var, int con,
1063 struct fb_info *info)
1065 struct cfb_info *cfb = (struct cfb_info *)info;
1068 y_bottom = var->yoffset;
1070 if (!(var->vmode & FB_VMODE_YWRAP))
1071 y_bottom += var->yres;
1073 if (var->xoffset > (var->xres_virtual - var->xres))
1075 if (y_bottom > cfb->fb.var.yres_virtual)
1078 if (cyber2000fb_update_start(cfb, var))
1081 cfb->fb.var.xoffset = var->xoffset;
1082 cfb->fb.var.yoffset = var->yoffset;
1083 if (var->vmode & FB_VMODE_YWRAP) {
1084 cfb->fb.var.vmode |= FB_VMODE_YWRAP;
1086 cfb->fb.var.vmode &= ~FB_VMODE_YWRAP;
1094 * Update the `var' structure (called by fbcon.c)
1096 * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
1097 * Since it's called by a kernel driver, no range checking is done.
1099 static int cyber2000fb_updatevar(int con, struct fb_info *info)
1101 struct cfb_info *cfb = (struct cfb_info *)info;
1103 return cyber2000fb_update_start(cfb, &fb_display[con].var);
1106 static int cyber2000fb_switch(int con, struct fb_info *info)
1108 struct cfb_info *cfb = (struct cfb_info *)info;
1109 struct display *disp;
1110 struct fb_cmap *cmap;
1112 if (cfb->currcon >= 0) {
1113 disp = fb_display + cfb->currcon;
1116 * Save the old colormap and video mode.
1118 disp->var = cfb->fb.var;
1120 fb_copy_cmap(&cfb->fb.cmap, &disp->cmap, 0);
1124 disp = fb_display + con;
1127 * Install the new colormap and change the video mode. By default,
1128 * fbcon sets all the colormaps and video modes to the default
1131 * Really, we want to set the colourmap size depending on the
1132 * depth of the new video mode. For now, we leave it at its
1133 * default 256 entry.
1138 cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);
1140 fb_copy_cmap(cmap, &cfb->fb.cmap, 0);
1142 cfb->fb.var = disp->var;
1143 cfb->fb.var.activate = FB_ACTIVATE_NOW;
1145 cyber2000fb_set_var(&cfb->fb.var, con, &cfb->fb);
1151 * (Un)Blank the display.
1153 static void cyber2000fb_blank(int blank, struct fb_info *info)
1155 struct cfb_info *cfb = (struct cfb_info *)info;
1159 * Blank the screen if blank_mode != 0, else unblank. If
1160 * blank == NULL then the caller blanks by setting the CLUT
1161 * (Color Look Up Table) to all black. Return 0 if blanking
1162 * succeeded, != 0 if un-/blanking failed due to e.g. a
1163 * video mode which doesn't support it. Implements VESA
1164 * suspend and powerdown modes on hardware that supports
1165 * disabling hsync/vsync:
1166 * blank_mode == 2: suspend vsync
1167 * blank_mode == 3: suspend hsync
1168 * blank_mode == 4: powerdown
1170 * wms...Enable VESA DMPS compatible powerdown mode
1171 * run "setterm -powersave powerdown" to take advantage
1175 case 4: /* powerdown - both sync lines down */
1176 cyber2000_grphw(0x16, 0x05, cfb);
1178 case 3: /* hsync off */
1179 cyber2000_grphw(0x16, 0x01, cfb);
1181 case 2: /* vsync off */
1182 cyber2000_grphw(0x16, 0x04, cfb);
1184 case 1: /* soft blank */
1185 cyber2000_grphw(0x16, 0x00, cfb);
1186 for (i = 0; i < NR_PALETTE; i++) {
1187 cyber2000fb_writeb(i, 0x3c8, cfb);
1188 cyber2000fb_writeb(0, 0x3c9, cfb);
1189 cyber2000fb_writeb(0, 0x3c9, cfb);
1190 cyber2000fb_writeb(0, 0x3c9, cfb);
1193 default: /* unblank */
1194 cyber2000_grphw(0x16, 0x00, cfb);
1195 for (i = 0; i < NR_PALETTE; i++) {
1196 cyber2000fb_writeb(i, 0x3c8, cfb);
1197 cyber2000fb_writeb(cfb->palette[i].red, 0x3c9, cfb);
1198 cyber2000fb_writeb(cfb->palette[i].green, 0x3c9, cfb);
1199 cyber2000fb_writeb(cfb->palette[i].blue, 0x3c9, cfb);
1206 * Get the currently displayed virtual consoles colormap.
1209 gen_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
1211 fb_copy_cmap(&info->cmap, cmap, kspc ? 0 : 2);
1216 * Get the currently displayed virtual consoles fixed part of the display.
1219 gen_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1226 * Get the current user defined part of the display.
1229 gen_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
1235 static struct fb_ops cyber2000fb_ops = {
1237 fb_set_var: cyber2000fb_set_var,
1238 fb_set_cmap: cyber2000fb_set_cmap,
1239 fb_pan_display: cyber2000fb_pan_display,
1240 fb_get_fix: gen_get_fix,
1241 fb_get_var: gen_get_var,
1242 fb_get_cmap: gen_get_cmap,
1246 * Enable access to the extended registers
1248 static void cyber2000fb_enable_extregs(struct cfb_info *cfb)
1250 cfb->func_use_count += 1;
1252 if (cfb->func_use_count == 1) {
1255 old = cyber2000_grphr(FUNC_CTL, cfb);
1256 cyber2000_grphw(FUNC_CTL, old | FUNC_CTL_EXTREGENBL, cfb);
1261 * Disable access to the extended registers
1263 static void cyber2000fb_disable_extregs(struct cfb_info *cfb)
1265 if (cfb->func_use_count == 1) {
1268 old = cyber2000_grphr(FUNC_CTL, cfb);
1269 cyber2000_grphw(FUNC_CTL, old & ~FUNC_CTL_EXTREGENBL, cfb);
1272 cfb->func_use_count -= 1;
1276 * This is the only "static" reference to the internal data structures
1277 * of this driver. It is here solely at the moment to support the other
1278 * CyberPro modules external to this driver.
1280 static struct cfb_info *int_cfb_info;
1283 * Attach a capture/tv driver to the core CyberX0X0 driver.
1285 int cyber2000fb_attach(struct cyberpro_info *info, int idx)
1287 if (int_cfb_info != NULL) {
1288 info->dev = int_cfb_info->dev;
1289 info->regs = int_cfb_info->regs;
1290 info->fb = int_cfb_info->fb.screen_base;
1291 info->fb_size = int_cfb_info->fb.fix.smem_len;
1292 info->enable_extregs = cyber2000fb_enable_extregs;
1293 info->disable_extregs = cyber2000fb_disable_extregs;
1294 info->info = int_cfb_info;
1296 strncpy(info->dev_name, int_cfb_info->fb.fix.id, sizeof(info->dev_name));
1301 return int_cfb_info != NULL;
1305 * Detach a capture/tv driver from the core CyberX0X0 driver.
1307 void cyber2000fb_detach(int idx)
1312 EXPORT_SYMBOL(cyber2000fb_attach);
1313 EXPORT_SYMBOL(cyber2000fb_detach);
1316 * These parameters give
1317 * 640x480, hsync 31.5kHz, vsync 60Hz
1319 static struct fb_videomode __devinitdata cyber2000fb_default_mode = {
1330 sync: FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
1331 vmode: FB_VMODE_NONINTERLACED
1334 static char igs_regs[] __devinitdata = {
1335 0x12, 0x00, 0x13, 0x00,
1337 0x31, 0x00, 0x32, 0x00,
1338 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00,
1339 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x01,
1340 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00,
1341 0x70, 0x0b, 0x73, 0x30,
1342 0x74, 0x0b, 0x75, 0x17, 0x76, 0x00, 0x7a, 0xc8
1346 * We need to wake up the CyberPro, and make sure its in linear memory
1347 * mode. Unfortunately, this is specific to the platform and card that
1348 * we are running on.
1350 * On x86 and ARM, should we be initialising the CyberPro first via the
1351 * IO registers, and then the MMIO registers to catch all cases? Can we
1352 * end up in the situation where the chip is in MMIO mode, but not awake
1355 * Note that on the NetWinder, the firmware automatically detects the
1356 * type, width and size, and leaves this in extended registers 0x71 and
1359 static inline void cyberpro_init_hw(struct cfb_info *cfb, int at_boot)
1364 * Wake up the CyberPro.
1368 #error "You loose, consult DaveM."
1371 * SPARC does not have an "outb" instruction, so we generate
1372 * I/O cycles storing into a reserved memory space at
1373 * physical address 0x3000000
1378 iop = ioremap(0x3000000, 0x5000);
1380 prom_printf("iga5000: cannot map I/O\n");
1384 writeb(0x18, iop + 0x46e8);
1385 writeb(0x01, iop + 0x102);
1386 writeb(0x08, iop + 0x46e8);
1387 writeb(0x33, iop + 0x3ce);
1388 writeb(0x01, iop + 0x3cf);
1390 iounmap((void *)iop);
1396 * Use mclk from BIOS. Only read this if we're
1397 * initialising this card for the first time.
1398 * FIXME: what about hotplug?
1400 cfb->mclk_mult = cyber2000_grphr(MCLK_MULT, cfb);
1401 cfb->mclk_div = cyber2000_grphr(MCLK_DIV, cfb);
1404 #if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
1406 * x86 and MIPS are simple, we just do regular
1407 * outb's instead of cyber2000fb_writeb.
1417 * Use mclk from BIOS. Only read this if we're
1418 * initialising this card for the first time.
1419 * FIXME: what about hotplug?
1421 cfb->mclk_mult = cyber2000_grphr(MCLK_MULT, cfb);
1422 cfb->mclk_div = cyber2000_grphr(MCLK_DIV, cfb);
1426 cyber2000fb_writeb(0x18, 0x46e8, cfb);
1427 cyber2000fb_writeb(0x01, 0x102, cfb);
1428 cyber2000fb_writeb(0x08, 0x46e8, cfb);
1429 cyber2000fb_writeb(0x33, 0x3ce, cfb);
1430 cyber2000fb_writeb(0x01, 0x3cf, cfb);
1433 * MCLK on the NetWinder and the Shark is fixed at 75MHz
1435 cfb->mclk_mult = 0xdb;
1436 cfb->mclk_div = 0x54;
1440 * Initialise the CyberPro
1442 for (i = 0; i < sizeof(igs_regs); i += 2)
1443 cyber2000_grphw(igs_regs[i], igs_regs[i+1], cfb);
1447 * get the video RAM size and width from the VGA register.
1448 * This should have been already initialised by the BIOS,
1449 * but if it's garbage, claim default 1MB VRAM (woody)
1451 cfb->mem_ctl1 = cyber2000_grphr(MEM_CTL1, cfb);
1452 cfb->mem_ctl2 = cyber2000_grphr(MEM_CTL2, cfb);
1455 * Reprogram the MEM_CTL1 and MEM_CTL2 registers
1457 cyber2000_grphw(MEM_CTL1, cfb->mem_ctl1, cfb);
1458 cyber2000_grphw(MEM_CTL2, cfb->mem_ctl2, cfb);
1462 * Ensure thatwe are using the correct PLL.
1463 * (CyberPro 5000's may be programmed to use
1464 * an additional set of PLLs.
1466 cyber2000fb_writeb(0xba, 0x3ce, cfb);
1467 cyber2000fb_writeb(cyber2000fb_readb(0x3cf, cfb) & 0x80, 0x3cf, cfb);
1470 static struct cfb_info * __devinit
1471 cyberpro_alloc_fb_info(struct pci_dev *dev, const struct pci_device_id *id, char *name)
1473 struct cfb_info *cfb;
1475 cfb = kmalloc(sizeof(struct cfb_info) + sizeof(struct display) +
1476 sizeof(u32) * 16, GFP_KERNEL);
1481 memset(cfb, 0, sizeof(struct cfb_info) + sizeof(struct display));
1486 if (id->driver_data == FB_ACCEL_IGS_CYBER5000)
1487 cfb->ref_ps = 40690; // 24.576 MHz
1489 cfb->ref_ps = 69842; // 14.31818 MHz (69841?)
1491 cfb->divisors[0] = 1;
1492 cfb->divisors[1] = 2;
1493 cfb->divisors[2] = 4;
1495 if (id->driver_data == FB_ACCEL_IGS_CYBER2000)
1496 cfb->divisors[3] = 8;
1498 cfb->divisors[3] = 6;
1500 strcpy(cfb->fb.fix.id, name);
1502 cfb->fb.fix.type = FB_TYPE_PACKED_PIXELS;
1503 cfb->fb.fix.type_aux = 0;
1504 cfb->fb.fix.xpanstep = 0;
1505 cfb->fb.fix.ypanstep = 1;
1506 cfb->fb.fix.ywrapstep = 0;
1507 cfb->fb.fix.accel = id->driver_data;
1509 cfb->fb.var.nonstd = 0;
1510 cfb->fb.var.activate = FB_ACTIVATE_NOW;
1511 cfb->fb.var.height = -1;
1512 cfb->fb.var.width = -1;
1513 cfb->fb.var.accel_flags = FB_ACCELF_TEXT;
1515 strcpy(cfb->fb.modename, cfb->fb.fix.id);
1516 strcpy(cfb->fb.fontname, default_font);
1518 cfb->fb.fbops = &cyber2000fb_ops;
1519 cfb->fb.changevar = NULL;
1520 cfb->fb.switch_con = cyber2000fb_switch;
1521 cfb->fb.updatevar = cyber2000fb_updatevar;
1522 cfb->fb.blank = cyber2000fb_blank;
1523 cfb->fb.flags = FBINFO_FLAG_DEFAULT;
1524 cfb->fb.disp = (struct display *)(cfb + 1);
1525 cfb->fb.pseudo_palette = (void *)(cfb->fb.disp + 1);
1527 fb_alloc_cmap(&cfb->fb.cmap, NR_PALETTE, 0);
1532 static void __devinit
1533 cyberpro_free_fb_info(struct cfb_info *cfb)
1537 * Free the colourmap
1539 fb_alloc_cmap(&cfb->fb.cmap, 0, 0);
1546 * Parse Cyber2000fb options. Usage:
1547 * video=cyber2000:font:fontname
1550 cyber2000fb_setup(char *options)
1554 if (!options || !*options)
1557 while ((opt = strsep(&options, ",")) != NULL) {
1561 if (strncmp(opt, "font:", 5) == 0) {
1562 strncpy(default_font_storage, opt + 5, sizeof(default_font_storage));
1563 default_font = default_font_storage;
1567 printk(KERN_ERR "CyberPro20x0: unknown parameter: %s\n", opt);
1572 static int __devinit
1573 cyberpro_probe(struct pci_dev *dev, const struct pci_device_id *id)
1575 struct cfb_info *cfb;
1576 u_int h_sync, v_sync;
1581 sprintf(name, "CyberPro%4X", id->device);
1583 err = pci_enable_device(dev);
1587 err = pci_request_regions(dev, name);
1592 cfb = cyberpro_alloc_fb_info(dev, id, name);
1594 goto failed_release;
1596 cfb->region = ioremap(pci_resource_start(dev, 0),
1597 pci_resource_len(dev, 0));
1599 goto failed_ioremap;
1601 cfb->regs = cfb->region + MMIO_OFFSET;
1603 cyberpro_init_hw(cfb, 1);
1605 switch (cfb->mem_ctl2 & MEM_CTL2_SIZE_MASK) {
1606 case MEM_CTL2_SIZE_4MB: smem_size = 0x00400000; break;
1607 case MEM_CTL2_SIZE_2MB: smem_size = 0x00200000; break;
1608 default: smem_size = 0x00100000; break;
1612 * Hmm, we _need_ a portable way of finding the address for
1613 * the remap stuff, both for mmio and for smem.
1615 cfb->fb.fix.mmio_start = pci_resource_start(dev, 0) + MMIO_OFFSET;
1616 cfb->fb.fix.smem_start = pci_resource_start(dev, 0);
1617 cfb->fb.fix.mmio_len = MMIO_SIZE;
1618 cfb->fb.fix.smem_len = smem_size;
1619 cfb->fb.screen_base = cfb->region;
1621 if (!fb_find_mode(&cfb->fb.var, &cfb->fb, NULL, NULL, 0,
1622 &cyber2000fb_default_mode, 8)) {
1623 printk("%s: no valid mode found\n", cfb->fb.fix.id);
1627 cfb->fb.var.yres_virtual = cfb->fb.fix.smem_len * 8 /
1628 (cfb->fb.var.bits_per_pixel * cfb->fb.var.xres_virtual);
1630 if (cfb->fb.var.yres_virtual < cfb->fb.var.yres)
1631 cfb->fb.var.yres_virtual = cfb->fb.var.yres;
1633 cyber2000fb_set_var(&cfb->fb.var, -1, &cfb->fb);
1636 * Calculate the hsync and vsync frequencies. Note that
1637 * we split the 1e12 constant up so that we can preserve
1638 * the precision and fit the results into 32-bit registers.
1639 * (1953125000 * 512 = 1e12)
1641 h_sync = 1953125000 / cfb->fb.var.pixclock;
1642 h_sync = h_sync * 512 / (cfb->fb.var.xres + cfb->fb.var.left_margin +
1643 cfb->fb.var.right_margin + cfb->fb.var.hsync_len);
1644 v_sync = h_sync / (cfb->fb.var.yres + cfb->fb.var.upper_margin +
1645 cfb->fb.var.lower_margin + cfb->fb.var.vsync_len);
1647 printk(KERN_INFO "%s: %dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
1648 cfb->fb.fix.id, cfb->fb.fix.smem_len >> 10,
1649 cfb->fb.var.xres, cfb->fb.var.yres,
1650 h_sync / 1000, h_sync % 1000, v_sync);
1652 err = register_framebuffer(&cfb->fb);
1659 pci_set_drvdata(dev, cfb);
1660 if (int_cfb_info == NULL)
1666 iounmap(cfb->region);
1668 cyberpro_free_fb_info(cfb);
1670 pci_release_regions(dev);
1675 static void __devexit cyberpro_remove(struct pci_dev *dev)
1677 struct cfb_info *cfb = pci_get_drvdata(dev);
1681 * If unregister_framebuffer fails, then
1682 * we will be leaving hooks that could cause
1683 * oopsen laying around.
1685 if (unregister_framebuffer(&cfb->fb))
1686 printk(KERN_WARNING "%s: danger Will Robinson, "
1687 "danger danger! Oopsen imminent!\n",
1689 iounmap(cfb->region);
1690 cyberpro_free_fb_info(cfb);
1693 * Ensure that the driver data is no longer
1696 pci_set_drvdata(dev, NULL);
1697 if (cfb == int_cfb_info)
1698 int_cfb_info = NULL;
1700 pci_release_regions(dev);
1704 static int cyberpro_suspend(struct pci_dev *dev, u32 state)
1710 * Re-initialise the CyberPro hardware
1712 static int cyberpro_resume(struct pci_dev *dev)
1714 struct cfb_info *cfb = pci_get_drvdata(dev);
1717 cyberpro_init_hw(cfb, 0);
1720 * Restore the old video mode and the palette.
1721 * We also need to tell fbcon to redraw the console.
1723 cfb->fb.var.activate = FB_ACTIVATE_NOW;
1724 cyber2000fb_set_var(&cfb->fb.var, -1, &cfb->fb);
1730 static struct pci_device_id cyberpro_pci_table[] __devinitdata = {
1731 { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000,
1732 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_IGS_CYBER2000 },
1733 { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010,
1734 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_IGS_CYBER2010 },
1735 { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5000,
1736 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_IGS_CYBER5000 },
1740 static struct pci_driver cyberpro_driver = {
1742 probe: cyberpro_probe,
1743 remove: __devexit_p(cyberpro_remove),
1744 suspend: cyberpro_suspend,
1745 resume: cyberpro_resume,
1746 id_table: cyberpro_pci_table
1750 * I don't think we can use the "module_init" stuff here because
1751 * the fbcon stuff may not be initialised yet. Hence the #ifdef
1752 * around module_init.
1754 int __init cyber2000fb_init(void)
1756 return pci_module_init(&cyberpro_driver);
1759 static void __exit cyberpro_exit(void)
1761 pci_unregister_driver(&cyberpro_driver);
1765 module_init(cyber2000fb_init);
1767 module_exit(cyberpro_exit);
1769 MODULE_AUTHOR("Russell King");
1770 MODULE_DESCRIPTION("CyberPro 2000, 2010 and 5000 framebuffer driver");
1771 MODULE_DEVICE_TABLE(pci,cyberpro_pci_table);
1772 MODULE_LICENSE("GPL");