2 * linux/drivers/video/cyber2000fb.c
4 * Integraphics Cyber2000 frame buffer device
8 #include <linux/module.h>
9 #include <linux/kernel.h>
10 #include <linux/errno.h>
11 #include <linux/string.h>
13 #include <linux/tty.h>
14 #include <linux/malloc.h>
15 #include <linux/delay.h>
17 #include <linux/pci.h>
18 #include <linux/init.h>
22 #include <asm/pgtable.h>
23 #include <asm/system.h>
24 #include <asm/uaccess.h>
26 #include <video/fbcon.h>
27 #include <video/fbcon-cfb8.h>
28 #include <video/fbcon-cfb16.h>
29 #include <video/fbcon-cfb24.h>
34 #define DEFAULT_XRES 640
35 #define DEFAULT_YRES 480
38 static volatile unsigned char *CyberRegs
;
40 #include "cyber2000fb.h"
42 static struct display global_disp
;
43 static struct fb_info fb_info
;
44 static struct cyber2000fb_par current_par
;
45 static struct display_switch
*dispsw
;
46 static struct fb_var_screeninfo __initdata init_var
= {};
49 static void debug_printf(char *fmt
, ...)
55 vsprintf(buffer
, fmt
, ap
);
61 #define debug_printf(x...) do { } while (0)
65 * Predefined Video Modes
67 static const struct res cyber2000_res
[] = {
71 0x5f, 0x4f, 0x50, 0x80, 0x52, 0x9d, 0x0b, 0x3e,
73 0xe9, 0x8b, 0xdf, 0x50, 0x00, 0xe6, 0x04, 0xc3
76 { 0xd2, 0xce, 0xdb, 0x54 }
82 0x7f, 0x63, 0x64, 0x00, 0x66, 0x10, 0x6f, 0xf0,
84 0x5b, 0x8f, 0x57, 0x64, 0x00, 0x59, 0x6e, 0xe3
87 { 0x52, 0x85, 0xdb, 0x54 }
93 0x9f, 0x7f, 0x80, 0x80, 0x8b, 0x94, 0x1e, 0xfd,
95 0x03, 0x86, 0xff, 0x80, 0x0f, 0x00, 0x1e, 0xe3
98 { 0xd0, 0x52, 0xdb, 0x54 }
112 0xce, 0x9f, 0xa0, 0x8f, 0xa2, 0x1f, 0x28, 0x52,
114 0x08, 0x8f, 0xff, 0xa0, 0x00, 0x03, 0x27, 0xe3
117 { 0xb4, 0x4b, 0xdb, 0x54 }
123 0xff, 0xc7, 0xc9, 0x9f, 0xcf, 0xa0, 0xfe, 0x10,
125 0xcf, 0x89, 0xaf, 0xc8, 0x00, 0xbc, 0xf1, 0xe3
128 { 0xbd, 0x10, 0xdb, 0x54 }
132 #define NUM_TOTAL_MODES arraysize(cyber2000_res)
134 static const char igs_regs
[] = {
135 0x10, 0x10, 0x12, 0x00, 0x13, 0x00,
136 0x30, 0x21, 0x31, 0x00, 0x32, 0x00, 0x33, 0x01,
137 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00,
138 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x01,
139 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00,
140 0x70, 0x0b, 0x71, 0x10, 0x72, 0x45, 0x73, 0x30,
141 0x74, 0x1b, 0x75, 0x1e, 0x76, 0x00, 0x7a, 0xc8
144 static const char crtc_idx
[] = {
145 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
147 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
150 static void cyber2000_init_hw(const struct res
*res
)
154 debug_printf("init vga hw for %dx%d\n", res
->xres
, res
->yres
);
156 cyber2000_outb(0xef, 0x3c2);
157 cyber2000_crtcw(0x11, 0x0b);
158 cyber2000_attrw(0x11, 0x00);
160 cyber2000_seqw(0x00, 0x01);
161 cyber2000_seqw(0x01, 0x01);
162 cyber2000_seqw(0x02, 0x0f);
163 cyber2000_seqw(0x03, 0x00);
164 cyber2000_seqw(0x04, 0x0e);
165 cyber2000_seqw(0x00, 0x03);
167 for (i
= 0; i
< sizeof(crtc_idx
); i
++)
168 cyber2000_crtcw(crtc_idx
[i
], res
->crtc_regs
[i
]);
170 for (i
= 0x0a; i
< 0x10; i
++)
171 cyber2000_crtcw(i
, 0);
173 cyber2000_crtcw(0x18, 0xff);
175 cyber2000_grphw(0x00, 0x00);
176 cyber2000_grphw(0x01, 0x00);
177 cyber2000_grphw(0x02, 0x00);
178 cyber2000_grphw(0x03, 0x00);
179 cyber2000_grphw(0x04, 0x00);
180 cyber2000_grphw(0x05, 0x60);
181 cyber2000_grphw(0x06, 0x05);
182 cyber2000_grphw(0x07, 0x0f);
183 cyber2000_grphw(0x08, 0xff);
185 for (i
= 0; i
< 16; i
++)
186 cyber2000_attrw(i
, i
);
188 cyber2000_attrw(0x10, 0x01);
189 cyber2000_attrw(0x11, 0x00);
190 cyber2000_attrw(0x12, 0x0f);
191 cyber2000_attrw(0x13, 0x00);
192 cyber2000_attrw(0x14, 0x00);
194 for (i
= 0; i
< sizeof(igs_regs
); i
+= 2)
195 cyber2000_grphw(igs_regs
[i
], igs_regs
[i
+1]);
197 cyber2000_grphw(0x11, res
->crtc_ofl
);
199 for (i
= 0; i
< 4; i
+= 1)
200 cyber2000_grphw(0xb0 + i
, res
->clk_regs
[i
]);
202 cyber2000_grphw(0x90, 0x01);
203 cyber2000_grphw(0xb9, 0x80);
204 cyber2000_grphw(0xb9, 0x00);
206 cyber2000_outb(0x56, 0x3ce);
207 i
= cyber2000_inb(0x3cf);
208 cyber2000_outb(i
| 4, 0x3cf);
209 cyber2000_outb(0x04, 0x3c6);
210 cyber2000_outb(i
, 0x3cf);
212 cyber2000_outb(0x20, 0x3c0);
213 cyber2000_outb(0xff, 0x3c6);
215 for (i
= 0; i
< 256; i
++) {
216 cyber2000_outb(i
, 0x3c8);
217 cyber2000_outb(0, 0x3c9);
218 cyber2000_outb(0, 0x3c9);
219 cyber2000_outb(0, 0x3c9);
224 static struct fb_ops cyber2000fb_ops
;
226 /* -------------------- Hardware specific routines ------------------------- */
229 * Hardware Cyber2000 Acceleration
231 static void cyber2000_accel_wait(void)
235 while (cyber2000_inb(0xbf011) & 0x80) {
237 debug_printf("accel_wait timed out\n");
238 cyber2000_outb(0, 0xbf011);
246 cyber2000_accel_setup(struct display
*p
)
252 cyber2000_accel_bmove(struct display
*p
, int sy
, int sx
, int dy
, int dx
,
253 int height
, int width
)
255 unsigned long src
, dst
, chwidth
= p
->var
.xres_virtual
* fontheight(p
);
272 src
= sx
+ sy
* chwidth
;
273 dst
= dx
+ dy
* chwidth
;
274 width
= width
* fontwidth(p
) - 1;
275 height
= height
* fontheight(p
) - 1;
277 cyber2000_accel_wait();
278 cyber2000_outb(0x00, 0xbf011);
279 cyber2000_outb(0x03, 0xbf048);
280 cyber2000_outw(width
, 0xbf060);
282 if (p
->var
.bits_per_pixel
!= 24) {
283 cyber2000_outl(dst
, 0xbf178);
284 cyber2000_outl(src
, 0xbf170);
286 cyber2000_outl(dst
* 3, 0xbf178);
287 cyber2000_outb(dst
, 0xbf078);
288 cyber2000_outl(src
* 3, 0xbf170);
291 cyber2000_outw(height
, 0xbf062);
292 cyber2000_outw(v
, 0xbf07c);
293 cyber2000_outw(0x2800, 0xbf07e);
297 cyber2000_accel_clear(struct vc_data
*conp
, struct display
*p
, int sy
, int sx
,
298 int height
, int width
)
301 u32 bgx
= attr_bgcol_ec(p
, conp
);
303 dst
= sx
* fontwidth(p
) + sy
* p
->var
.xres_virtual
* fontheight(p
);
304 width
= width
* fontwidth(p
) - 1;
305 height
= height
* fontheight(p
) - 1;
307 cyber2000_accel_wait();
308 cyber2000_outb(0x00, 0xbf011);
309 cyber2000_outb(0x03, 0xbf048);
310 cyber2000_outw(width
, 0xbf060);
311 cyber2000_outw(height
, 0xbf062);
313 switch (p
->var
.bits_per_pixel
) {
316 bgx
= ((u16
*)p
->dispsw_data
)[bgx
];
318 cyber2000_outl(dst
, 0xbf178);
322 cyber2000_outl(dst
* 3, 0xbf178);
323 cyber2000_outb(dst
, 0xbf078);
324 bgx
= ((u32
*)p
->dispsw_data
)[bgx
];
328 cyber2000_outl(bgx
, 0xbf058);
329 cyber2000_outw(0x8000, 0xbf07c);
330 cyber2000_outw(0x0800, 0xbf07e);
334 cyber2000_accel_putc(struct vc_data
*conp
, struct display
*p
, int c
, int yy
, int xx
)
336 cyber2000_accel_wait();
337 dispsw
->putc(conp
, p
, c
, yy
, xx
);
341 cyber2000_accel_putcs(struct vc_data
*conp
, struct display
*p
,
342 const unsigned short *s
, int count
, int yy
, int xx
)
344 cyber2000_accel_wait();
345 dispsw
->putcs(conp
, p
, s
, count
, yy
, xx
);
349 cyber2000_accel_revc(struct display
*p
, int xx
, int yy
)
351 cyber2000_accel_wait();
352 dispsw
->revc(p
, xx
, yy
);
356 cyber2000_accel_clear_margins(struct vc_data
*conp
, struct display
*p
, int bottom_only
)
358 dispsw
->clear_margins(conp
, p
, bottom_only
);
361 static struct display_switch fbcon_cyber_accel
= {
362 cyber2000_accel_setup
,
363 cyber2000_accel_bmove
,
364 cyber2000_accel_clear
,
365 cyber2000_accel_putc
,
366 cyber2000_accel_putcs
,
367 cyber2000_accel_revc
,
370 cyber2000_accel_clear_margins
,
371 FONTWIDTH(8)|FONTWIDTH(16)
378 cyber2000_getcolreg(u_int regno
, u_int
* red
, u_int
* green
, u_int
* blue
,
379 u_int
* transp
, struct fb_info
*fb_info
)
386 t
= current_par
.palette
[regno
].red
;
387 *red
= t
<< 10 | t
<< 4 | t
>> 2;
389 t
= current_par
.palette
[regno
].green
;
390 *green
= t
<< 10 | t
<< 4 | t
>> 2;
392 t
= current_par
.palette
[regno
].blue
;
393 *blue
= t
<< 10 | t
<< 4 | t
>> 2;
401 * Set a single color register. Return != 0 for invalid regno.
404 cyber2000_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
405 u_int transp
, struct fb_info
*fb_info
)
414 current_par
.palette
[regno
].red
= red
;
415 current_par
.palette
[regno
].green
= green
;
416 current_par
.palette
[regno
].blue
= blue
;
418 switch (fb_display
[current_par
.currcon
].var
.bits_per_pixel
) {
419 #ifdef FBCON_HAS_CFB8
421 cyber2000_outb(regno
, 0x3c8);
422 cyber2000_outb(red
, 0x3c9);
423 cyber2000_outb(green
, 0x3c9);
424 cyber2000_outb(blue
, 0x3c9);
428 #ifdef FBCON_HAS_CFB16
431 cyber2000_outb(regno
<< 3, 0x3c8);
432 cyber2000_outb(red
, 0x3c9);
433 cyber2000_outb(green
, 0x3c9);
434 cyber2000_outb(blue
, 0x3c9);
437 current_par
.c_table
.cfb16
[regno
] = regno
| regno
<< 5 | regno
<< 10;
443 cyber2000_outb(regno
<< 2, 0x3c8);
444 cyber2000_outb(current_par
.palette
[regno
>> 1].red
, 0x3c9);
445 cyber2000_outb(green
, 0x3c9);
446 cyber2000_outb(current_par
.palette
[regno
>> 1].blue
, 0x3c9);
451 cyber2000_outb(regno
<< 3, 0x3c8);
452 cyber2000_outb(red
, 0x3c9);
453 cyber2000_outb(current_par
.palette
[regno
<< 1].green
, 0x3c9);
454 cyber2000_outb(blue
, 0x3c9);
458 current_par
.c_table
.cfb16
[regno
] = regno
| regno
<< 5 | regno
<< 11;
462 #ifdef FBCON_HAS_CFB24
464 cyber2000_outb(regno
, 0x3c8);
465 cyber2000_outb(red
, 0x3c9);
466 cyber2000_outb(green
, 0x3c9);
467 cyber2000_outb(blue
, 0x3c9);
470 current_par
.c_table
.cfb24
[regno
] = regno
| regno
<< 8 | regno
<< 16;
481 static void cyber2000fb_calculate_timing(unsigned char *v
, struct fb_var_screeninfo
*var
)
483 int Htotal
, Hdispend
, Hblankstart
, Hblankend
, Hsyncstart
, Hsyncend
;
484 int Vtotal
, Vdispend
, Vblankstart
, Vblankend
, Vsyncstart
, Vsyncend
;
485 #define BIT(v,b1,m,b2) (((v >> b1) & m) << b2)
487 Hdispend
= var
->xres
;
488 Hsyncstart
= var
->xres
+ var
->right_margin
;
489 Hsyncend
= var
->xres
+ var
->right_margin
+ var
->hsync_len
;
490 Htotal
= var
->xres
+ var
->right_margin
+ var
->hsync_len
+ var
->left_margin
;
492 Hblankstart
= var
->xres
;
493 Hblankend
= Htotal
- 4*8;
495 Vdispend
= var
->yres
;
496 Vsyncstart
= var
->yres
+ var
->lower_margin
;
497 Vsyncend
= var
->yres
+ var
->lower_margin
+ var
->vsync_len
;
498 Vtotal
= var
->yres
+ var
->lower_margin
+ var
->vsync_len
+ var
->upper_margin
;
500 Vblankstart
= var
->yres
+ 7;
501 Vblankend
= Vtotal
- 11;
520 v
[3] = BIT(Hblankend
, 0, 0x1f, 0) |
523 v
[5] = BIT(Hsyncend
, 0, 0x1f, 0) |
524 BIT(Hblankend
, 5, 0x01, 7);
527 v
[7] = BIT(Vtotal
, 8, 0x01, 0) |
528 BIT(Vdispend
, 8, 0x01, 1) |
529 BIT(Vsyncstart
, 8, 0x01, 2) |
530 BIT(Vblankstart
,8, 0x01, 3) |
532 BIT(Vtotal
, 9, 0x01, 5) |
533 BIT(Vdispend
, 9, 0x01, 6) |
534 BIT(Vsyncstart
, 9, 0x01, 7);
536 v
[9] = BIT(0, 0, 0x1f, 0) |
537 BIT(Vblankstart
,9, 0x01, 5) |
540 v
[11] = BIT(Vsyncend
, 0, 0x0f, 0) |
548 /* overflow - graphics reg 0x11 */
549 v
[18] = BIT(Vtotal
, 10, 0x01, 0) | /* guess */
550 BIT(Vdispend
, 10, 0x01, 1) |
551 BIT(Vsyncstart
, 10, 0x01, 2) | /* guess */
552 BIT(Vblankstart
,10, 0x01, 3) | /* guess */
553 BIT(Hblankend
, 6, 0x01, 4); /* guess */
556 static void cyber2000fb_set_timing(struct fb_var_screeninfo
*var
)
558 unsigned int width
= var
->xres_virtual
;
559 unsigned int scr_pitch
, fetchrow
, i
;
560 char b
, graph_r77
, crtc
[32];
562 switch (var
->bits_per_pixel
) {
563 case 8: /* PSEUDOCOLOUR, 256 */
569 case 15:/* DIRECTCOLOUR, 32k */
572 scr_pitch
= width
* 2;
575 case 16:/* DIRECTCOLOUR, 64k */
578 scr_pitch
= width
* 2;
581 case 24:/* TRUECOLOUR, 16m */
594 fetchrow
= scr_pitch
+ 1;
596 cyber2000fb_calculate_timing(crtc
, var
);
598 for (i
= 0; i
< NUM_TOTAL_MODES
; i
++)
599 if (var
->xres
== cyber2000_res
[i
].xres
&&
600 var
->yres
== cyber2000_res
[i
].yres
)
603 if (i
< NUM_TOTAL_MODES
)
604 cyber2000_init_hw(cyber2000_res
+ i
);
606 crtc
[13] = scr_pitch
;
609 * reprogram the CRTC with the values we calculated
610 * above. This should be cleaned up once we're
611 * confident that we're generating the correct
612 * values. Disable this if you're having problems,
613 * and report the values obtained from the kernel
617 cyber2000_crtcw(0x11, 0x0b);
618 for (i
= 0; i
< sizeof(crtc_idx
); i
++)
619 cyber2000_crtcw(crtc_idx
[i
], crtc
[i
]);
621 cyber2000_crtcw(0x13, crtc
[13]);
624 cyber2000_grphw(0x14, fetchrow
);
625 /* FIXME: is this the right way round? */
626 cyber2000_grphw(0x15, ((fetchrow
>> 4) & 0xf0) | ((scr_pitch
>> 8) & 0x0f));
627 cyber2000_grphw(0x77, graph_r77
);
628 cyber2000_grphw(0x33, 0x1c);
630 cyber2000_outw(width
, 0xbf018);
631 cyber2000_outw(width
, 0xbf218);
632 cyber2000_outb(b
, 0xbf01c);
637 for (j
= 0; j
< 19; j
++) printk("%2d ", j
); printk("\n"KERN_DEBUG
);
638 for (j
= 0; j
< 19; j
++) printk("%02X ", crtc
[j
]); printk("\n"KERN_DEBUG
);
639 for (j
= 0; j
< 18; j
++) printk("%02X ", cyber2000_res
[i
].crtc_regs
[j
]);
640 printk("%02X\n", cyber2000_res
[i
].crtc_ofl
);
646 cyber2000fb_update_start(struct fb_var_screeninfo
*var
)
651 base
= var
->yoffset
* var
->xres_virtual
+ var
->xoffset
;
653 cyber2000_crtcw(0x0c, base
);
654 cyber2000_crtcw(0x0d, base
>> 8);
655 /* FIXME: need the upper bits of the start offset */
656 /* cyber2000_crtcw(0x??, base >> 16);*/
661 * Open/Release the frame buffer device
663 static int cyber2000fb_open(struct fb_info
*info
, int user
)
669 static int cyber2000fb_release(struct fb_info
*info
, int user
)
679 cyber2000fb_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
680 struct fb_info
*info
)
684 if (con
== current_par
.currcon
) /* current console? */
685 err
= fb_get_cmap(cmap
, kspc
, cyber2000_getcolreg
, info
);
686 else if (fb_display
[con
].cmap
.len
) /* non default colormap? */
687 fb_copy_cmap(&fb_display
[con
].cmap
, cmap
, kspc
? 0 : 2);
689 fb_copy_cmap(fb_default_cmap(1 << fb_display
[con
].var
.bits_per_pixel
),
699 cyber2000fb_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
700 struct fb_info
*info
)
702 struct display
*disp
= &fb_display
[con
];
705 if (!disp
->cmap
.len
) { /* no colormap allocated? */
708 if (disp
->var
.bits_per_pixel
== 16)
713 err
= fb_alloc_cmap(&disp
->cmap
, size
, 0);
716 if (con
== current_par
.currcon
) /* current console? */
717 err
= fb_set_cmap(cmap
, kspc
, cyber2000_setcolreg
,
720 fb_copy_cmap(cmap
, &disp
->cmap
, kspc
? 0 : 1);
727 cyber2000fb_decode_var(struct fb_var_screeninfo
*var
, int con
, int *visual
)
729 switch (var
->bits_per_pixel
) {
730 #ifdef FBCON_HAS_CFB8
732 *visual
= FB_VISUAL_PSEUDOCOLOR
;
735 #ifdef FBCON_HAS_CFB16
738 *visual
= FB_VISUAL_DIRECTCOLOR
;
741 #ifdef FBCON_HAS_CFB24
743 *visual
= FB_VISUAL_TRUECOLOR
;
754 * Get the Fixed Part of the Display
757 cyber2000fb_get_fix(struct fb_fix_screeninfo
*fix
, int con
,
758 struct fb_info
*fb_info
)
760 struct display
*display
;
762 memset(fix
, 0, sizeof(struct fb_fix_screeninfo
));
763 strcpy(fix
->id
, "Cyber2000");
766 display
= fb_display
+ con
;
768 display
= &global_disp
;
770 fix
->smem_start
= current_par
.screen_base_p
;
771 fix
->smem_len
= current_par
.screen_size
;
772 fix
->mmio_start
= current_par
.regs_base_p
;
773 fix
->mmio_len
= 0x000c0000;
774 fix
->type
= display
->type
;
775 fix
->type_aux
= display
->type_aux
;
777 fix
->ypanstep
= display
->ypanstep
;
778 fix
->ywrapstep
= display
->ywrapstep
;
779 fix
->visual
= display
->visual
;
780 fix
->line_length
= display
->line_length
;
781 fix
->accel
= 22; /*FB_ACCEL_IGS_CYBER2000*/
788 * Get the User Defined Part of the Display
791 cyber2000fb_get_var(struct fb_var_screeninfo
*var
, int con
,
792 struct fb_info
*fb_info
)
795 *var
= global_disp
.var
;
797 *var
= fb_display
[con
].var
;
803 * Set the User Defined Part of the Display
806 cyber2000fb_set_var(struct fb_var_screeninfo
*var
, int con
, struct fb_info
*info
)
808 struct display
*display
;
809 int err
, chgvar
= 0, visual
;
812 display
= fb_display
+ con
;
814 display
= &global_disp
;
816 err
= cyber2000fb_decode_var(var
, con
, &visual
);
820 switch (var
->activate
& FB_ACTIVATE_MASK
) {
821 case FB_ACTIVATE_TEST
:
824 case FB_ACTIVATE_NXTOPEN
:
825 case FB_ACTIVATE_NOW
:
833 if (display
->var
.xres
!= var
->xres
)
835 if (display
->var
.yres
!= var
->yres
)
837 if (display
->var
.xres_virtual
!= var
->xres_virtual
)
839 if (display
->var
.yres_virtual
!= var
->yres_virtual
)
841 if (display
->var
.accel_flags
!= var
->accel_flags
)
843 if (memcmp(&display
->var
.red
, &var
->red
, sizeof(var
->red
)))
845 if (memcmp(&display
->var
.green
, &var
->green
, sizeof(var
->green
)))
847 if (memcmp(&display
->var
.blue
, &var
->blue
, sizeof(var
->green
)))
852 display
->var
.activate
&= ~FB_ACTIVATE_ALL
;
854 if (var
->activate
& FB_ACTIVATE_ALL
)
855 global_disp
.var
= display
->var
;
857 display
->screen_base
= (char *)current_par
.screen_base
;
858 display
->visual
= visual
;
859 display
->type
= FB_TYPE_PACKED_PIXELS
;
860 display
->type_aux
= 0;
861 display
->ypanstep
= 0;
862 display
->ywrapstep
= 0;
863 display
->can_soft_blank
= 1;
864 display
->inverse
= 0;
866 switch (display
->var
.bits_per_pixel
) {
867 #ifdef FBCON_HAS_CFB8
869 dispsw
= &fbcon_cfb8
;
870 display
->dispsw_data
= NULL
;
871 display
->next_line
= var
->xres_virtual
;
874 #ifdef FBCON_HAS_CFB16
877 dispsw
= &fbcon_cfb16
;
878 display
->dispsw_data
= current_par
.c_table
.cfb16
;
879 display
->next_line
= var
->xres_virtual
* 2;
882 #ifdef FBCON_HAS_CFB24
884 dispsw
= &fbcon_cfb24
;
885 display
->dispsw_data
= current_par
.c_table
.cfb24
;
886 display
->next_line
= var
->xres_virtual
* 3;
890 printk(KERN_WARNING
"cyber2000: no support for %dbpp\n",
891 display
->var
.bits_per_pixel
);
892 dispsw
= &fbcon_dummy
;
896 display
->line_length
= display
->next_line
;
898 if (display
->var
.accel_flags
& FB_ACCELF_TEXT
&&
899 dispsw
!= &fbcon_dummy
)
900 display
->dispsw
= &fbcon_cyber_accel
;
902 display
->dispsw
= dispsw
;
904 if (chgvar
&& info
&& info
->changevar
)
905 info
->changevar(con
);
907 if (con
== current_par
.currcon
) {
908 struct fb_cmap
*cmap
;
910 cyber2000fb_update_start(var
);
911 cyber2000fb_set_timing(var
);
913 if (display
->cmap
.len
)
914 cmap
= &display
->cmap
;
916 cmap
= fb_default_cmap(current_par
.palette_size
);
918 fb_set_cmap(cmap
, 1, cyber2000_setcolreg
, info
);
925 * Pan or Wrap the Display
927 static int cyber2000fb_pan_display(struct fb_var_screeninfo
*var
, int con
,
928 struct fb_info
*info
)
932 y_bottom
= var
->yoffset
;
934 if (!(var
->vmode
& FB_VMODE_YWRAP
))
935 y_bottom
+= var
->yres
;
937 if (var
->xoffset
> (var
->xres_virtual
- var
->xres
))
939 if (y_bottom
> fb_display
[con
].var
.yres_virtual
)
941 /*disabled until we can update the start address properly */
944 cyber2000fb_update_start(var
);
946 fb_display
[con
].var
.xoffset
= var
->xoffset
;
947 fb_display
[con
].var
.yoffset
= var
->yoffset
;
948 if (var
->vmode
& FB_VMODE_YWRAP
)
949 fb_display
[con
].var
.vmode
|= FB_VMODE_YWRAP
;
951 fb_display
[con
].var
.vmode
&= ~FB_VMODE_YWRAP
;
957 static int cyber2000fb_ioctl(struct inode
*inode
, struct file
*file
,
958 u_int cmd
, u_long arg
, int con
, struct fb_info
*info
)
965 * Update the `var' structure (called by fbcon.c)
967 * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
968 * Since it's called by a kernel driver, no range checking is done.
971 cyber2000fb_updatevar(int con
, struct fb_info
*info
)
973 if (con
== current_par
.currcon
)
974 cyber2000fb_update_start(&fb_display
[con
].var
);
979 cyber2000fb_switch(int con
, struct fb_info
*info
)
981 struct fb_cmap
*cmap
;
983 if (current_par
.currcon
>= 0) {
984 cmap
= &fb_display
[current_par
.currcon
].cmap
;
987 fb_get_cmap(cmap
, 1, cyber2000_getcolreg
, info
);
990 current_par
.currcon
= con
;
992 fb_display
[con
].var
.activate
= FB_ACTIVATE_NOW
;
994 cyber2000fb_set_var(&fb_display
[con
].var
, con
, info
);
1000 * (Un)Blank the display.
1002 static void cyber2000fb_blank(int blank
, struct fb_info
*fb_info
)
1007 for (i
= 0; i
< 256; i
++) {
1008 cyber2000_outb(i
, 0x3c8);
1009 cyber2000_outb(0, 0x3c9);
1010 cyber2000_outb(0, 0x3c9);
1011 cyber2000_outb(0, 0x3c9);
1014 for (i
= 0; i
< 256; i
++) {
1015 cyber2000_outb(i
, 0x3c8);
1016 cyber2000_outb(current_par
.palette
[i
].red
, 0x3c9);
1017 cyber2000_outb(current_par
.palette
[i
].green
, 0x3c9);
1018 cyber2000_outb(current_par
.palette
[i
].blue
, 0x3c9);
1023 int __init
cyber2000fb_setup(char *options
)
1028 static struct fb_ops cyber2000fb_ops
=
1031 cyber2000fb_release
,
1032 cyber2000fb_get_fix
,
1033 cyber2000fb_get_var
,
1034 cyber2000fb_set_var
,
1035 cyber2000fb_get_cmap
,
1036 cyber2000fb_set_cmap
,
1037 cyber2000fb_pan_display
,
1042 cyber2000fb_init_fbinfo(void)
1044 static int first
= 1;
1050 strcpy(fb_info
.modename
, "Cyber2000");
1051 strcpy(fb_info
.fontname
, "Acorn8x8");
1054 fb_info
.fbops
= &cyber2000fb_ops
;
1055 fb_info
.disp
= &global_disp
;
1056 fb_info
.changevar
= NULL
;
1057 fb_info
.switch_con
= cyber2000fb_switch
;
1058 fb_info
.updatevar
= cyber2000fb_updatevar
;
1059 fb_info
.blank
= cyber2000fb_blank
;
1060 fb_info
.flags
= FBINFO_FLAG_DEFAULT
;
1063 * setup initial parameters
1065 memset(&init_var
, 0, sizeof(init_var
));
1066 init_var
.xres_virtual
=
1067 init_var
.xres
= DEFAULT_XRES
;
1068 init_var
.yres_virtual
=
1069 init_var
.yres
= DEFAULT_YRES
;
1070 init_var
.bits_per_pixel
= DEFAULT_BPP
;
1073 * These parameters give
1074 * 640x480, hsync 31.5kHz, vsync 60Hz
1076 init_var
.left_margin
= 56;
1077 init_var
.right_margin
= 16;
1078 init_var
.upper_margin
= 34;
1079 init_var
.lower_margin
= 9;
1080 init_var
.hsync_len
= 88;
1081 init_var
.vsync_len
= 2;
1082 init_var
.pixclock
= 39722;
1084 init_var
.red
.msb_right
= 0;
1085 init_var
.green
.msb_right
= 0;
1086 init_var
.blue
.msb_right
= 0;
1088 switch(init_var
.bits_per_pixel
) {
1090 init_var
.bits_per_pixel
= 8;
1091 case 8: /* PSEUDOCOLOUR */
1092 init_var
.bits_per_pixel
= 8;
1093 init_var
.red
.offset
= 0;
1094 init_var
.red
.length
= 8;
1095 init_var
.green
.offset
= 0;
1096 init_var
.green
.length
= 8;
1097 init_var
.blue
.offset
= 0;
1098 init_var
.blue
.length
= 8;
1101 case 15: /* RGB555 */
1102 init_var
.bits_per_pixel
= 15;
1103 init_var
.red
.offset
= 10;
1104 init_var
.red
.length
= 5;
1105 init_var
.green
.offset
= 5;
1106 init_var
.green
.length
= 5;
1107 init_var
.blue
.offset
= 0;
1108 init_var
.blue
.length
= 5;
1111 case 16: /* RGB565 */
1112 init_var
.bits_per_pixel
= 16;
1113 init_var
.red
.offset
= 11;
1114 init_var
.red
.length
= 5;
1115 init_var
.green
.offset
= 5;
1116 init_var
.green
.length
= 6;
1117 init_var
.blue
.offset
= 0;
1118 init_var
.blue
.length
= 5;
1121 case 24: /* RGB888 */
1122 init_var
.bits_per_pixel
= 24;
1123 init_var
.red
.offset
= 16;
1124 init_var
.red
.length
= 8;
1125 init_var
.green
.offset
= 8;
1126 init_var
.green
.length
= 8;
1127 init_var
.blue
.offset
= 0;
1128 init_var
.blue
.length
= 8;
1132 init_var
.nonstd
= 0;
1133 init_var
.activate
= FB_ACTIVATE_NOW
;
1134 init_var
.height
= -1;
1135 init_var
.width
= -1;
1136 init_var
.accel_flags
= FB_ACCELF_TEXT
;
1137 init_var
.sync
= FB_SYNC_COMP_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
;
1138 init_var
.vmode
= FB_VMODE_NONINTERLACED
;
1144 int __init
cyber2000fb_init(void)
1146 struct pci_dev
*dev
;
1147 u_int h_sync
, v_sync
;
1148 u_long base_p
, base_v
;
1150 dev
= pci_find_device(PCI_VENDOR_ID_INTERG
, 0x2000, NULL
);
1154 /* this should be done by PCI generic code */
1155 base_p
= 0x80000000 + dev
->resource
[0].start
;
1158 * This should be ioremap'd, thus:
1160 * base_v = ioremap(dev->resource[0].start, dev->resource[0].end - dev->resource[0].start + 1);
1162 base_v
= (u_long
)bus_to_virt(dev
->resource
[0].start
);
1165 CyberRegs
= base_v
+ 0x00800000;
1167 cyber2000_outb(0x18, 0x46e8);
1168 cyber2000_outb(0x01, 0x102);
1169 cyber2000_outb(0x08, 0x46e8);
1171 cyber2000fb_init_fbinfo();
1173 current_par
.currcon
= -1;
1174 current_par
.screen_base_p
= base_p
;
1175 current_par
.screen_base
= base_v
;
1176 current_par
.screen_size
= 0x00200000;
1177 current_par
.regs_base_p
= base_p
+ 0x00800000;
1179 cyber2000fb_set_var(&init_var
, -1, &fb_info
);
1181 h_sync
= 1953125000 / init_var
.pixclock
;
1182 h_sync
= h_sync
* 512 / (init_var
.xres
+ init_var
.left_margin
+
1183 init_var
.right_margin
+ init_var
.hsync_len
);
1184 v_sync
= h_sync
/ (init_var
.yres
+ init_var
.upper_margin
+
1185 init_var
.lower_margin
+ init_var
.vsync_len
);
1187 printk("Cyber2000: %ldkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
1188 current_par
.screen_size
>> 10,
1189 init_var
.xres
, init_var
.yres
,
1190 h_sync
/ 1000, h_sync
% 1000, v_sync
);
1192 if (register_framebuffer(&fb_info
) < 0)
1195 MOD_INC_USE_COUNT
; /* TODO: This driver cannot be unloaded yet */
1202 int __init
init_module(void)
1204 return cyber2000fb_init();
1207 void cleanup_module(void)
1209 /* Not reached because the usecount will never be
1210 decremented to zero */
1211 unregister_framebuffer(&fb_info
);
1212 /* TODO: clean up ... */