* added 0.99 linux version
[mascara-docs.git] / i386 / linux / linux-2.3.21 / drivers / video / cyber2000fb.c
blobcedb41c2a599d277fb8fcbaac667b6c745ac2d79
1 /*
2 * linux/drivers/video/cyber2000fb.c
4 * Integraphics Cyber2000 frame buffer device
6 * Based on cyberfb.c
7 */
8 #include <linux/module.h>
9 #include <linux/kernel.h>
10 #include <linux/errno.h>
11 #include <linux/string.h>
12 #include <linux/mm.h>
13 #include <linux/tty.h>
14 #include <linux/malloc.h>
15 #include <linux/delay.h>
16 #include <linux/fb.h>
17 #include <linux/pci.h>
18 #include <linux/init.h>
20 #include <asm/io.h>
21 #include <asm/irq.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>
32 * Some defaults
34 #define DEFAULT_XRES 640
35 #define DEFAULT_YRES 480
36 #define DEFAULT_BPP 8
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 = {};
48 #ifdef DEBUG
49 static void debug_printf(char *fmt, ...)
51 char buffer[128];
52 va_list ap;
54 va_start(ap, fmt);
55 vsprintf(buffer, fmt, ap);
56 va_end(ap);
58 printascii(buffer);
60 #else
61 #define debug_printf(x...) do { } while (0)
62 #endif
65 * Predefined Video Modes
67 static const struct res cyber2000_res[] = {
69 640, 480,
71 0x5f, 0x4f, 0x50, 0x80, 0x52, 0x9d, 0x0b, 0x3e,
72 0x00, 0x40,
73 0xe9, 0x8b, 0xdf, 0x50, 0x00, 0xe6, 0x04, 0xc3
75 0x00,
76 { 0xd2, 0xce, 0xdb, 0x54 }
80 800, 600,
82 0x7f, 0x63, 0x64, 0x00, 0x66, 0x10, 0x6f, 0xf0,
83 0x00, 0x60,
84 0x5b, 0x8f, 0x57, 0x64, 0x00, 0x59, 0x6e, 0xe3
86 0x00,
87 { 0x52, 0x85, 0xdb, 0x54 }
91 1024, 768,
93 0x9f, 0x7f, 0x80, 0x80, 0x8b, 0x94, 0x1e, 0xfd,
94 0x00, 0x60,
95 0x03, 0x86, 0xff, 0x80, 0x0f, 0x00, 0x1e, 0xe3
97 0x00,
98 { 0xd0, 0x52, 0xdb, 0x54 }
100 #if 0
102 1152, 886,
108 #endif
110 1280, 1024,
112 0xce, 0x9f, 0xa0, 0x8f, 0xa2, 0x1f, 0x28, 0x52,
113 0x00, 0x40,
114 0x08, 0x8f, 0xff, 0xa0, 0x00, 0x03, 0x27, 0xe3
116 0x1d,
117 { 0xb4, 0x4b, 0xdb, 0x54 }
121 1600, 1200,
123 0xff, 0xc7, 0xc9, 0x9f, 0xcf, 0xa0, 0xfe, 0x10,
124 0x00, 0x40,
125 0xcf, 0x89, 0xaf, 0xc8, 0x00, 0xbc, 0xf1, 0xe3
127 0x1f,
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,
146 0x08, 0x09,
147 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
150 static void cyber2000_init_hw(const struct res *res)
152 int i;
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)
233 int count = 10000;
235 while (cyber2000_inb(0xbf011) & 0x80) {
236 if (!count--) {
237 debug_printf("accel_wait timed out\n");
238 cyber2000_outb(0, 0xbf011);
239 return;
241 udelay(10);
245 static void
246 cyber2000_accel_setup(struct display *p)
248 dispsw->setup(p);
251 static void
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);
256 int v = 0x8000;
258 if (sx < dx) {
259 sx += width - 1;
260 dx += width - 1;
261 v |= 4;
264 if (sy < dy) {
265 sy += height - 1;
266 dy += height - 1;
267 v |= 2;
270 sx *= fontwidth(p);
271 dx *= fontwidth(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);
285 } else {
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);
296 static void
297 cyber2000_accel_clear(struct vc_data *conp, struct display *p, int sy, int sx,
298 int height, int width)
300 unsigned long dst;
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) {
314 case 15:
315 case 16:
316 bgx = ((u16 *)p->dispsw_data)[bgx];
317 case 8:
318 cyber2000_outl(dst, 0xbf178);
319 break;
321 case 24:
322 cyber2000_outl(dst * 3, 0xbf178);
323 cyber2000_outb(dst, 0xbf078);
324 bgx = ((u32 *)p->dispsw_data)[bgx];
325 break;
328 cyber2000_outl(bgx, 0xbf058);
329 cyber2000_outw(0x8000, 0xbf07c);
330 cyber2000_outw(0x0800, 0xbf07e);
333 static void
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);
340 static void
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);
348 static void
349 cyber2000_accel_revc(struct display *p, int xx, int yy)
351 cyber2000_accel_wait();
352 dispsw->revc(p, xx, yy);
355 static void
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,
368 NULL,
369 NULL,
370 cyber2000_accel_clear_margins,
371 FONTWIDTH(8)|FONTWIDTH(16)
375 * Palette
377 static int
378 cyber2000_getcolreg(u_int regno, u_int * red, u_int * green, u_int * blue,
379 u_int * transp, struct fb_info *fb_info)
381 int t;
383 if (regno >= 256)
384 return 1;
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;
395 *transp = 0;
397 return 0;
401 * Set a single color register. Return != 0 for invalid regno.
403 static int
404 cyber2000_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
405 u_int transp, struct fb_info *fb_info)
407 if (regno > 255)
408 return 1;
410 red >>= 10;
411 green >>= 10;
412 blue >>= 10;
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
420 case 8:
421 cyber2000_outb(regno, 0x3c8);
422 cyber2000_outb(red, 0x3c9);
423 cyber2000_outb(green, 0x3c9);
424 cyber2000_outb(blue, 0x3c9);
425 break;
426 #endif
428 #ifdef FBCON_HAS_CFB16
429 case 15:
430 if (regno < 32) {
431 cyber2000_outb(regno << 3, 0x3c8);
432 cyber2000_outb(red, 0x3c9);
433 cyber2000_outb(green, 0x3c9);
434 cyber2000_outb(blue, 0x3c9);
436 if (regno < 16)
437 current_par.c_table.cfb16[regno] = regno | regno << 5 | regno << 10;
438 break;
440 case 16:
441 if (regno < 64) {
442 /* write green */
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);
449 if (regno < 32) {
450 /* write red,blue */
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);
457 if (regno < 16)
458 current_par.c_table.cfb16[regno] = regno | regno << 5 | regno << 11;
459 break;
460 #endif
462 #ifdef FBCON_HAS_CFB24
463 case 24:
464 cyber2000_outb(regno, 0x3c8);
465 cyber2000_outb(red, 0x3c9);
466 cyber2000_outb(green, 0x3c9);
467 cyber2000_outb(blue, 0x3c9);
469 if (regno < 16)
470 current_par.c_table.cfb24[regno] = regno | regno << 8 | regno << 16;
471 break;
472 #endif
474 default:
475 return 1;
478 return 0;
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;
503 Hdispend >>= 3;
504 Hsyncstart >>= 3;
505 Hsyncend >>= 3;
506 Htotal >>= 3;
507 Hblankstart >>= 3;
508 Hblankend >>= 3;
510 Htotal -= 5;
511 Hdispend -= 1;
512 Vtotal -= 2;
513 Vdispend -= 1;
514 Vblankstart -= 1;
515 Vblankend -= 1;
517 v[0] = Htotal;
518 v[1] = Hdispend;
519 v[2] = Hblankstart;
520 v[3] = BIT(Hblankend, 0, 0x1f, 0) |
521 BIT(1, 0, 0x01, 7);
522 v[4] = Hsyncstart;
523 v[5] = BIT(Hsyncend, 0, 0x1f, 0) |
524 BIT(Hblankend, 5, 0x01, 7);
526 v[6] = Vtotal;
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) |
531 BIT(1, 0, 0x01, 4) |
532 BIT(Vtotal, 9, 0x01, 5) |
533 BIT(Vdispend, 9, 0x01, 6) |
534 BIT(Vsyncstart, 9, 0x01, 7);
535 v[8] = 0;
536 v[9] = BIT(0, 0, 0x1f, 0) |
537 BIT(Vblankstart,9, 0x01, 5) |
538 BIT(1, 0, 0x01, 6);
539 v[10] = Vsyncstart;
540 v[11] = BIT(Vsyncend, 0, 0x0f, 0) |
541 BIT(1, 0, 0x01, 7);
542 v[12] = Vdispend;
543 v[14] = 0;
544 v[15] = Vblankstart;
545 v[16] = Vblankend;
546 v[17] = 0xe3;
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 */
564 b = 0;
565 graph_r77 = 1;
566 scr_pitch = width;
567 break;
569 case 15:/* DIRECTCOLOUR, 32k */
570 b = 1;
571 graph_r77 = 6;
572 scr_pitch = width * 2;
573 break;
575 case 16:/* DIRECTCOLOUR, 64k */
576 b = 1;
577 graph_r77 = 2;
578 scr_pitch = width * 2;
579 break;
581 case 24:/* TRUECOLOUR, 16m */
582 b = 2;
583 graph_r77 = 4;
584 width *= 3;
585 scr_pitch = width;
586 break;
588 default:
589 return;
592 width -= 1;
593 scr_pitch >>= 3;
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)
601 break;
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
614 * messages.
616 #if 1
617 cyber2000_crtcw(0x11, 0x0b);
618 for (i = 0; i < sizeof(crtc_idx); i++)
619 cyber2000_crtcw(crtc_idx[i], crtc[i]);
620 #else
621 cyber2000_crtcw(0x13, crtc[13]);
622 #endif
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);
634 #if 0
635 { int j; i = 0;
636 printk(KERN_DEBUG);
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);
642 #endif
645 static inline void
646 cyber2000fb_update_start(struct fb_var_screeninfo *var)
648 #if 0
649 unsigned int base;
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);*/
657 #endif
661 * Open/Release the frame buffer device
663 static int cyber2000fb_open(struct fb_info *info, int user)
665 MOD_INC_USE_COUNT;
666 return 0;
669 static int cyber2000fb_release(struct fb_info *info, int user)
671 MOD_DEC_USE_COUNT;
672 return 0;
676 * Get the Colormap
678 static int
679 cyber2000fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
680 struct fb_info *info)
682 int err = 0;
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);
688 else
689 fb_copy_cmap(fb_default_cmap(1 << fb_display[con].var.bits_per_pixel),
690 cmap, kspc ? 0 : 2);
691 return err;
696 * Set the Colormap
698 static int
699 cyber2000fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
700 struct fb_info *info)
702 struct display *disp = &fb_display[con];
703 int err = 0;
705 if (!disp->cmap.len) { /* no colormap allocated? */
706 int size;
708 if (disp->var.bits_per_pixel == 16)
709 size = 32;
710 else
711 size = 256;
713 err = fb_alloc_cmap(&disp->cmap, size, 0);
715 if (!err) {
716 if (con == current_par.currcon) /* current console? */
717 err = fb_set_cmap(cmap, kspc, cyber2000_setcolreg,
718 info);
719 else
720 fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
723 return err;
726 static int
727 cyber2000fb_decode_var(struct fb_var_screeninfo *var, int con, int *visual)
729 switch (var->bits_per_pixel) {
730 #ifdef FBCON_HAS_CFB8
731 case 8:
732 *visual = FB_VISUAL_PSEUDOCOLOR;
733 break;
734 #endif
735 #ifdef FBCON_HAS_CFB16
736 case 15:
737 case 16:
738 *visual = FB_VISUAL_DIRECTCOLOR;
739 break;
740 #endif
741 #ifdef FBCON_HAS_CFB24
742 case 24:
743 *visual = FB_VISUAL_TRUECOLOR;
744 break;
745 #endif
746 default:
747 return -EINVAL;
750 return 0;
754 * Get the Fixed Part of the Display
756 static int
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");
765 if (con >= 0)
766 display = fb_display + con;
767 else
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;
776 fix->xpanstep = 0;
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*/
783 return 0;
788 * Get the User Defined Part of the Display
790 static int
791 cyber2000fb_get_var(struct fb_var_screeninfo *var, int con,
792 struct fb_info *fb_info)
794 if (con == -1)
795 *var = global_disp.var;
796 else
797 *var = fb_display[con].var;
799 return 0;
803 * Set the User Defined Part of the Display
805 static int
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;
811 if (con >= 0)
812 display = fb_display + con;
813 else
814 display = &global_disp;
816 err = cyber2000fb_decode_var(var, con, &visual);
817 if (err)
818 return err;
820 switch (var->activate & FB_ACTIVATE_MASK) {
821 case FB_ACTIVATE_TEST:
822 return 0;
824 case FB_ACTIVATE_NXTOPEN:
825 case FB_ACTIVATE_NOW:
826 break;
828 default:
829 return -EINVAL;
832 if (con >= 0) {
833 if (display->var.xres != var->xres)
834 chgvar = 1;
835 if (display->var.yres != var->yres)
836 chgvar = 1;
837 if (display->var.xres_virtual != var->xres_virtual)
838 chgvar = 1;
839 if (display->var.yres_virtual != var->yres_virtual)
840 chgvar = 1;
841 if (display->var.accel_flags != var->accel_flags)
842 chgvar = 1;
843 if (memcmp(&display->var.red, &var->red, sizeof(var->red)))
844 chgvar = 1;
845 if (memcmp(&display->var.green, &var->green, sizeof(var->green)))
846 chgvar = 1;
847 if (memcmp(&display->var.blue, &var->blue, sizeof(var->green)))
848 chgvar = 1;
851 display->var = *var;
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
868 case 8:
869 dispsw = &fbcon_cfb8;
870 display->dispsw_data = NULL;
871 display->next_line = var->xres_virtual;
872 break;
873 #endif
874 #ifdef FBCON_HAS_CFB16
875 case 15:
876 case 16:
877 dispsw = &fbcon_cfb16;
878 display->dispsw_data = current_par.c_table.cfb16;
879 display->next_line = var->xres_virtual * 2;
880 break;
881 #endif
882 #ifdef FBCON_HAS_CFB24
883 case 24:
884 dispsw = &fbcon_cfb24;
885 display->dispsw_data = current_par.c_table.cfb24;
886 display->next_line = var->xres_virtual * 3;
887 break;
888 #endif
889 default:
890 printk(KERN_WARNING "cyber2000: no support for %dbpp\n",
891 display->var.bits_per_pixel);
892 dispsw = &fbcon_dummy;
893 break;
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;
901 else
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;
915 else
916 cmap = fb_default_cmap(current_par.palette_size);
918 fb_set_cmap(cmap, 1, cyber2000_setcolreg, info);
920 return 0;
925 * Pan or Wrap the Display
927 static int cyber2000fb_pan_display(struct fb_var_screeninfo *var, int con,
928 struct fb_info *info)
930 u_int y_bottom;
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))
938 return -EINVAL;
939 if (y_bottom > fb_display[con].var.yres_virtual)
940 return -EINVAL;
941 /*disabled until we can update the start address properly */
942 return -EINVAL;
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;
950 else
951 fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
953 return 0;
957 static int cyber2000fb_ioctl(struct inode *inode, struct file *file,
958 u_int cmd, u_long arg, int con, struct fb_info *info)
960 return -EINVAL;
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.
970 static int
971 cyber2000fb_updatevar(int con, struct fb_info *info)
973 if (con == current_par.currcon)
974 cyber2000fb_update_start(&fb_display[con].var);
975 return 0;
978 static int
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;
986 if (cmap->len)
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);
996 return 0;
1000 * (Un)Blank the display.
1002 static void cyber2000fb_blank(int blank, struct fb_info *fb_info)
1004 int i;
1006 if (blank) {
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);
1013 } else {
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)
1025 return 0;
1028 static struct fb_ops cyber2000fb_ops =
1030 cyber2000fb_open,
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,
1038 cyber2000fb_ioctl
1041 static void __init
1042 cyber2000fb_init_fbinfo(void)
1044 static int first = 1;
1046 if (!first)
1047 return;
1048 first = 0;
1050 strcpy(fb_info.modename, "Cyber2000");
1051 strcpy(fb_info.fontname, "Acorn8x8");
1053 fb_info.node = -1;
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) {
1089 default:
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;
1099 break;
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;
1109 break;
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;
1119 break;
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;
1129 break;
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;
1142 * Initialization
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);
1151 if (!dev)
1152 return -ENXIO;
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);
1164 /*FIXME*/
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)
1193 return -EINVAL;
1195 MOD_INC_USE_COUNT; /* TODO: This driver cannot be unloaded yet */
1196 return 0;
1201 #ifdef MODULE
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 ... */
1215 #endif /* MODULE */