2 * Linux/drivers/video/cyber2000fb.c
4 * Copyright (C) 1998-2000 Russell King
6 * Integraphics CyberPro 2000, 2010 and 5000 frame buffer device
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
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>
29 #include <linux/tty.h>
30 #include <linux/malloc.h>
31 #include <linux/delay.h>
33 #include <linux/pci.h>
34 #include <linux/init.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
58 #define PCI_PHYS_OFFSET 0x00000000
61 static char *CyberRegs
;
63 #include "cyber2000fb.h"
67 struct display_switch
*dispsw
;
80 } palette
[NR_PALETTE
];
88 /* -------------------- Hardware specific routines ------------------------- */
91 * Hardware Cyber2000 Acceleration
93 static void cyber2000_accel_wait(void)
97 while (cyber2000_inb(CO_REG_CONTROL
) & 0x80) {
99 debug_printf("accel_wait timed out\n");
100 cyber2000_outb(0, CO_REG_CONTROL
);
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
);
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
;
121 int cmd
= CO_CMD_L_PATTERN_FGCOL
;
132 cmd
|= CO_CMD_L_INC_LEFT
;
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
);
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
);
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
;
176 u32 bgx
= attr_bgcol_ec(p
, conp
);
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
) {
194 bgx
= ((u16
*)p
->dispsw_data
)[bgx
];
196 cyber2000_outl(dst
, CO_REG_DEST_PTR
);
200 cyber2000_outl(dst
* 3, CO_REG_DEST_PTR
);
201 cyber2000_outb(dst
, CO_REG_X_PHASE
);
202 bgx
= ((u32
*)p
->dispsw_data
)[bgx
];
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
);
212 cyber2000_accel_putc(struct vc_data
*conp
, struct display
*p
, int c
,
215 struct cfb_info
*cfb
= (struct cfb_info
*)p
->fb_info
;
217 cyber2000_accel_wait();
218 cfb
->dispsw
->putc(conp
, p
, c
, yy
, xx
);
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
);
240 cyber2000_accel_clear_margins(struct vc_data
*conp
, struct display
*p
,
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.
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
)
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
282 cyber2000_outb(regno
, 0x3c8);
283 cyber2000_outb(red
, 0x3c9);
284 cyber2000_outb(green
, 0x3c9);
285 cyber2000_outb(blue
, 0x3c9);
289 #ifdef FBCON_HAS_CFB16
291 #ifndef CFB16_IS_CFB15
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);
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);
309 ((u16
*)cfb
->fb
.pseudo_palette
)[regno
] =
310 regno
| regno
<< 5 | regno
<< 11;
316 cyber2000_outb(regno
<< 3, 0x3c8);
317 cyber2000_outb(red
, 0x3c9);
318 cyber2000_outb(green
, 0x3c9);
319 cyber2000_outb(blue
, 0x3c9);
322 ((u16
*)cfb
->fb
.pseudo_palette
)[regno
] =
323 regno
| regno
<< 5 | regno
<< 10;
328 #ifdef FBCON_HAS_CFB24
330 cyber2000_outb(regno
, 0x3c8);
331 cyber2000_outb(red
, 0x3c9);
332 cyber2000_outb(green
, 0x3c9);
333 cyber2000_outb(blue
, 0x3c9);
336 ((u32
*)cfb
->fb
.pseudo_palette
)[regno
] =
337 regno
| regno
<< 8 | regno
<< 16;
368 static const u_char crtc_idx
[] = {
369 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
371 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18
374 static void cyber2000fb_set_timing(struct cfb_info
*cfb
, struct par_info
*hw
)
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);
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
);
461 cyber2000fb_update_start(struct cfb_info
*cfb
, struct fb_var_screeninfo
*var
)
465 base
= var
->yoffset
* var
->xres_virtual
+ var
->xoffset
;
472 cyber2000_grphw(0x10, base
>> 16 | 0x10);
473 cyber2000_crtcw(0x0c, base
>> 8);
474 cyber2000_crtcw(0x0d, base
);
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
;
490 /* no colormap allocated? */
494 if (cfb
->fb
.var
.bits_per_pixel
== 16)
499 err
= fb_alloc_cmap(dcmap
, size
, 0);
503 * we should be able to remove this test once fbcon has been
506 if (!err
&& con
== cfb
->currcon
) {
507 err
= fb_set_cmap(cmap
, kspc
, cyber2000_setcolreg
, &cfb
->fb
);
508 dcmap
= &cfb
->fb
.cmap
;
512 fb_copy_cmap(cmap
, dcmap
, kspc
? 0 : 1);
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
;
530 Htotal
= var
->xres
+ var
->right_margin
+
531 var
->hsync_len
+ var
->left_margin
;
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) |
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;
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) |
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) |
575 hw
->crtc
[10] = Vsyncstart
;
576 hw
->crtc
[11] = BIT(Vsyncend
, 0, 0x0f, 0) |
578 hw
->crtc
[12] = Vdispend
;
579 hw
->crtc
[15] = Vblankstart
;
580 hw
->crtc
[16] = Vblankend
;
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
588 BIT(Vtotal
, 10, 0x01, 0) |
589 BIT(Vdispend
, 10, 0x01, 1) |
590 BIT(Vsyncstart
, 10, 0x01, 2) |
591 BIT(Vblankstart
,10, 0x01, 3) |
598 * The following was discovered by a good monitor, bit twiddling, theorising
599 * and but mostly luck. Strangely, it looks like everyone elses' PLL!
602 * fclock = fpll / div2
603 * fpll = fref * mult / div1
605 * fref = 14.318MHz (69842ps)
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)
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
;
623 * find div2 such that 115MHz < fpll < 260MHz
626 for (div2
= 0; div2
< 4; div2
++) {
629 new_pll
= pll_ps
/ cfb
->divisors
[div2
];
630 if (8696 > new_pll
&& new_pll
> 3846) {
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;
649 for (t_div1
= 32; t_div1
> 1; t_div1
-= 1) {
650 u_int rr
, t_mult
, t_pll_ps
;
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)
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
;
674 if (diff
< best_diff
) {
681 * If we hit an exact value, there is no point in continuing.
691 hw
->clock_mult
= best_mult
- 1;
692 hw
->clock_div
= div2
<< 6 | (best_div1
- 1);
698 * Decode the info required for the hardware.
699 * This involves the PLL parameters for the dot clock,
700 * CRTC registers, and accelerator settings.
703 cyber2000fb_decode_var(struct fb_var_screeninfo
*var
, struct cfb_info
*cfb
,
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;
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;
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;
736 #ifdef FBCON_HAS_CFB24
737 case 24:/* TRUECOLOUR, 16m */
738 hw
->pixformat
= PIXFORMAT_24BPP
;
739 hw
->visualid
= VISUALID_16M
;
741 hw
->pitch
= hw
->width
>> 3;
742 hw
->palette_ctrl
= 0x14;
749 err
= cyber2000fb_decode_clock(hw
, cfb
, var
);
753 err
= cyber2000fb_decode_crtc(hw
, cfb
, var
);
758 hw
->fetch
= hw
->pitch
;
759 if (!(cfb
->mem_ctl2
& MEM_CTL2_64BIT
))
767 * Set the User Defined Part of the Display
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
;
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
);
792 if (var
->activate
& FB_ACTIVATE_TEST
)
795 if ((var
->activate
& FB_ACTIVATE_MASK
) != FB_ACTIVATE_NOW
)
798 if (cfb
->fb
.var
.xres
!= var
->xres
)
800 if (cfb
->fb
.var
.yres
!= var
->yres
)
802 if (cfb
->fb
.var
.xres_virtual
!= var
->xres_virtual
)
804 if (cfb
->fb
.var
.yres_virtual
!= var
->yres_virtual
)
806 if (cfb
->fb
.var
.bits_per_pixel
!= var
->bits_per_pixel
)
810 display
= cfb
->fb
.disp
;
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 */
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
;
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;
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;
853 case 15:/* DIRECTCOLOUR, 32k */
854 var
->bits_per_pixel
= 15;
855 var
->red
.offset
= 10;
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;
868 #ifdef FBCON_HAS_CFB24
869 case 24:/* TRUECOLOUR, 16m */
870 var
->red
.offset
= 16;
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;
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
;
890 if (var
->accel_flags
& FB_ACCELF_TEXT
&& cfb
->dispsw
!= &fbcon_dummy
)
891 display
->dispsw
= &fbcon_cyber_accel
;
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;
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.
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
);
936 * Pan or Wrap the Display
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
;
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
))
952 if (y_bottom
> cfb
->fb
.var
.yres_virtual
)
955 if (cyber2000fb_update_start(cfb
, var
))
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
;
963 cfb
->fb
.var
.vmode
&= ~FB_VMODE_YWRAP
;
971 cyber2000fb_ioctl(struct inode
*inode
, struct file
*file
, u_int cmd
,
972 u_long arg
, int con
, struct fb_info
*info
)
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
;
1005 fb_copy_cmap(&cfb
->fb
.cmap
, &disp
->cmap
, 0);
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
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.
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
);
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
;
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
1060 case 4: /* powerdown - both sync lines down */
1061 cyber2000_grphw(0x16, 0x05);
1063 case 3: /* hsync off */
1064 cyber2000_grphw(0x16, 0x01);
1066 case 2: /* vsync off */
1067 cyber2000_grphw(0x16, 0x04);
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);
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);
1091 * Get the currently displayed virtual consoles colormap.
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);
1101 * Get the currently displayed virtual consoles fixed part of the display.
1104 gen_get_fix(struct fb_fix_screeninfo
*fix
, int con
, struct fb_info
*info
)
1111 * Get the current user defined part of the display.
1114 gen_get_var(struct fb_var_screeninfo
*var
, int con
, struct fb_info
*info
)
1120 static struct fb_ops cyber2000fb_ops
= {
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) {
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) {
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
));
1187 return int_cfb_info
!= NULL
;
1191 * Detach a capture/tv driver from the core CyberX0X0 driver.
1193 void cyber2000fb_detach(int idx
)
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
= {
1216 sync
: FB_SYNC_COMP_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
,
1217 vmode
: FB_VMODE_NONINTERLACED
1220 int __init
cyber2000fb_setup(char *options
)
1225 static char igs_regs
[] __devinitdata
= {
1226 0x12, 0x00, 0x13, 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
1246 * Note that on the NetWinder, the firmware automatically detects the
1247 * type, width and size, and leaves this in extended registers 0x71 and
1250 static inline void cyberpro_init_hw(struct cfb_info
*cfb
, int at_boot
)
1255 * Wake up the CyberPro.
1259 #error "You loose, consult DaveM."
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
1269 iop
= ioremap(0x3000000, 0x5000);
1271 prom_printf("iga5000: cannot map I/O\n");
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
);
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
);
1297 * x86 is simple, we just do regular outb's instead of
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
);
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;
1331 * Initialise the CyberPro
1333 for (i
= 0; i
< sizeof(igs_regs
); i
+= 2)
1334 cyber2000_grphw(igs_regs
[i
], igs_regs
[i
+1]);
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
);
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
);
1372 memset(cfb
, 0, sizeof(struct cfb_info
) + sizeof(struct display
));
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;
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);
1418 static void __devinit
1419 cyberpro_free_fb_info(struct cfb_info
*cfb
)
1423 * Free the colourmap
1425 fb_alloc_cmap(&cfb
->fb
.cmap
, 0, 0);
1432 * Map in the registers
1434 static int __devinit
1435 cyberpro_map_mmio(struct cfb_info
*cfb
, struct pci_dev
*dev
)
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
);
1449 CyberRegs
= ioremap(mmio_base
, MMIO_SIZE
);
1451 printk("%s: unable to map memory mapped IO\n",
1461 static void __devinit
cyberpro_unmap_mmio(struct cfb_info
*cfb
)
1463 if (cfb
&& CyberRegs
) {
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
)
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",
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",
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
;
1520 err
= pci_enable_device(dev
);
1525 cfb
= cyberpro_alloc_fb_info(dev
, id
);
1529 err
= cyberpro_map_mmio(cfb
, dev
);
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
);
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
);
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
);
1583 dev
->driver_data
= cfb
;
1584 if (int_cfb_info
== NULL
)
1590 cyberpro_unmap_smem(cfb
);
1591 cyberpro_unmap_mmio(cfb
);
1592 cyberpro_free_fb_info(cfb
);
1597 static void __devexit
cyberpro_remove(struct pci_dev
*dev
)
1599 struct cfb_info
*cfb
= (struct cfb_info
*)dev
->driver_data
;
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",
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
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
;
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
},
1658 MODULE_DEVICE_TABLE(pci
, cyberpro_pci_table
);
1660 static struct pci_driver cyberpro_driver
= {
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
);
1685 module_init(cyber2000fb_init
);
1687 module_exit(cyberpro_exit
);