Ok. I didn't make 2.4.0 in 2000. Tough. I tried, but we had some
[davej-history.git] / drivers / video / cyberfb.c
blob4510d116550d0874a002f8ffcef79ab0ca5b4be2
1 /*
2 * linux/drivers/video/cyberfb.c -- CyberVision64 frame buffer device
3 * $Id: cyberfb.c,v 1.6 1998/09/11 04:54:58 abair Exp $
5 * Copyright (C) 1998 Alan Bair
7 * This file is based on two CyberVision64 frame buffer device drivers
9 * The second CyberVision64 frame buffer device (cvision.c cvision_core.c):
11 * Copyright (c) 1997 Antonio Santos
13 * Released as a patch to 2.1.35, but never included in the source tree.
14 * This is based on work from the NetBSD CyberVision64 frame buffer driver
15 * and support files (grf_cv.c, grf_cvreg.h, ite_cv.c):
16 * Permission to use the source of this driver was obtained from the
17 * author Michael Teske by Alan Bair.
19 * Copyright (c) 1995 Michael Teske
21 * The first CyberVision64 frame buffer device (cyberfb.c):
23 * Copyright (C) 1996 Martin Apel
24 * Geert Uytterhoeven
26 * Which is based on the Amiga frame buffer device (amifb.c):
28 * Copyright (C) 1995 Geert Uytterhoeven
31 * History:
32 * - 22 Dec 95: Original version by Martin Apel
33 * - 05 Jan 96: Geert: integration into the current source tree
34 * - 01 Aug 98: Alan: Merge in code from cvision.c and cvision_core.c
35 * $Log: cyberfb.c,v $
36 * Revision 1.6 1998/09/11 04:54:58 abair
37 * Update for 2.1.120 change in include file location.
38 * Clean up for public release.
40 * Revision 1.5 1998/09/03 04:27:13 abair
41 * Move cv64_load_video_mode to cyber_set_video so a new video mode is install
42 * with each change of the 'var' data.
44 * Revision 1.4 1998/09/01 00:31:17 abair
45 * Put in a set of default 8,16,24 bpp modes and map cyber8,16 to them.
46 * Update operations with 'par' to handle a more complete set of parameter
47 * values for encode/decode process.
49 * Revision 1.3 1998/08/31 21:31:33 abair
50 * Swap 800x490 for 640x480 video mode and more cleanup.
51 * Abandon idea to resurrect "custom" mode setting via kernel opts,
52 * instead work on making use of fbset program to do this.
54 * Revision 1.2 1998/08/31 06:17:08 abair
55 * Make updates for changes in cyberfb.c released in 2.1.119
56 * and do some cleanup of the code.
58 * Revision 1.1 1998/08/29 18:38:31 abair
59 * Initial revision
61 * Revision 1.3 1998/08/17 06:21:53 abair
62 * Remove more redundant code after merging in cvision_core.c
63 * Set blanking by colormap to pale red to detect this vs trying to
64 * use video blanking. More formating to Linux code style.
66 * Revision 1.2 1998/08/15 17:51:37 abair
67 * Added cvision_core.c code from 2.1.35 patches.
68 * Changed to compile correctly and switch to using initialization
69 * code. Added debugging and dropping of duplicate code.
73 * This file is subject to the terms and conditions of the GNU General Public
74 * License. See the file COPYING in the main directory of this archive
75 * for more details.
79 #include <linux/module.h>
80 #include <linux/kernel.h>
81 #include <linux/errno.h>
82 #include <linux/string.h>
83 #include <linux/mm.h>
84 #include <linux/tty.h>
85 #include <linux/malloc.h>
86 #include <linux/delay.h>
87 #include <linux/zorro.h>
88 #include <linux/fb.h>
89 #include <linux/init.h>
90 #include <asm/uaccess.h>
91 #include <asm/system.h>
92 #include <asm/irq.h>
93 #include <asm/pgtable.h>
94 #include <asm/amigahw.h>
95 #include <asm/io.h>
97 #include "cyberfb.h"
98 #include <video/fbcon.h>
99 #include <video/fbcon-cfb8.h>
100 #include <video/fbcon-cfb16.h>
102 /*#define CYBERFBDEBUG*/
103 #ifdef CYBERFBDEBUG
104 #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
105 static void cv64_dump(void);
106 #else
107 #define DPRINTK(fmt, args...)
108 #endif
110 #define wb_64(regs,reg,dat) (*(((volatile unsigned char *)regs) + reg) = dat)
111 #define rb_64(regs, reg) (*(((volatile unsigned char *)regs) + reg))
113 #define ww_64(regs,reg,dat) (*((volatile unsigned short *)(regs + reg) = dat)
115 struct cyberfb_par {
116 struct fb_var_screeninfo var;
117 __u32 type;
118 __u32 type_aux;
119 __u32 visual;
120 __u32 line_length;
123 static struct cyberfb_par current_par;
125 static int current_par_valid = 0;
126 static int currcon = 0;
128 static struct display disp;
129 static struct fb_info fb_info;
133 * Frame Buffer Name
136 static char cyberfb_name[16] = "Cybervision";
140 * CyberVision Graphics Board
143 static unsigned char Cyber_colour_table [256][3];
144 static unsigned long CyberSize;
145 static volatile unsigned char *CyberBase;
146 static volatile unsigned char *CyberMem;
147 static volatile unsigned char *CyberRegs;
148 static unsigned long CyberMem_phys;
149 static unsigned long CyberRegs_phys;
152 * Predefined Video Modes
155 static struct {
156 const char *name;
157 struct fb_var_screeninfo var;
158 } cyberfb_predefined[] __initdata = {
159 { "640x480-8", { /* Default 8 BPP mode (cyber8) */
160 640, 480, 640, 480, 0, 0, 8, 0,
161 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
162 0, 0, -1, -1, FB_ACCELF_TEXT, 39722, 40, 24, 32, 11, 96, 2,
163 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
164 FB_VMODE_NONINTERLACED
165 }},
166 { "640x480-16", { /* Default 16 BPP mode (cyber16) */
167 640, 480, 640, 480, 0, 0, 16, 0,
168 {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
169 0, 0, -1, -1, FB_ACCELF_TEXT, 39722, 40, 24, 32, 11, 96, 2,
170 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
171 FB_VMODE_NONINTERLACED
172 }},
173 { "640x480-24", { /* Default 24 BPP mode */
174 640, 480, 640, 480, 0, 0, 24, 0,
175 {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0},
176 0, 0, -1, -1, FB_ACCELF_TEXT, 39722, 40, 24, 32, 11, 96, 2,
177 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
178 FB_VMODE_NONINTERLACED
179 }},
180 { "800x490-8", { /* Cybervision 8 bpp */
181 /* NO Acceleration */
182 800, 490, 800, 490, 0, 0, 8, 0,
183 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
184 0, 0, -1, -1, FB_ACCEL_NONE, 33333, 80, 24, 23, 1, 56, 8,
185 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
186 FB_VMODE_NONINTERLACED
188 /* I can't test these with my monitor, but I suspect they will
189 * be OK, since Antonio Santos indicated he had tested them in
190 * his system.
192 { "800x600-8", { /* Cybervision 8 bpp */
193 800, 600, 800, 600, 0, 0, 8, 0,
194 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
195 0, 0, -1, -1, FB_ACCELF_TEXT, 27778, 64, 24, 22, 1, 72, 2,
196 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
197 FB_VMODE_NONINTERLACED
199 { "1024x768-8", { /* Cybervision 8 bpp */
200 1024, 768, 1024, 768, 0, 0, 8, 0,
201 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
202 0, 0, -1, -1, FB_ACCELF_TEXT, 16667, 224, 72, 60, 12, 168, 4,
203 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
204 FB_VMODE_NONINTERLACED
206 { "1152x886-8", { /* Cybervision 8 bpp */
207 1152, 886, 1152, 886, 0, 0, 8, 0,
208 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
209 0, 0, -1, -1, FB_ACCELF_TEXT, 15873, 184, 40, 24, 1, 56, 16,
210 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
211 FB_VMODE_NONINTERLACED
213 { "1280x1024-8", { /* Cybervision 8 bpp */
214 1280, 1024, 1280, 1024, 0, 0, 8, 0,
215 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
216 0, 0, -1, -1, FB_ACCELF_TEXT, 16667, 256, 48, 50, 12, 72, 4,
217 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
218 FB_VMODE_INTERLACED
222 #define NUM_TOTAL_MODES ARRAY_SIZE(cyberfb_predefined)
224 static int Cyberfb_inverse = 0;
227 * Some default modes
230 #define CYBER8_DEFMODE (0)
231 #define CYBER16_DEFMODE (1)
233 static struct fb_var_screeninfo cyberfb_default;
234 static int cyberfb_usermode __initdata = 0;
237 * Interface used by the world
240 int cyberfb_setup(char *options);
242 static int cyberfb_get_fix(struct fb_fix_screeninfo *fix, int con,
243 struct fb_info *info);
244 static int cyberfb_get_var(struct fb_var_screeninfo *var, int con,
245 struct fb_info *info);
246 static int cyberfb_set_var(struct fb_var_screeninfo *var, int con,
247 struct fb_info *info);
248 static int cyberfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
249 struct fb_info *info);
250 static int cyberfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
251 struct fb_info *info);
254 * Interface to the low level console driver
257 int cyberfb_init(void);
258 static int Cyberfb_switch(int con, struct fb_info *info);
259 static int Cyberfb_updatevar(int con, struct fb_info *info);
260 static void Cyberfb_blank(int blank, struct fb_info *info);
263 * Text console acceleration
266 #ifdef FBCON_HAS_CFB8
267 static struct display_switch fbcon_cyber8;
268 #endif
271 * Accelerated Functions used by the low level console driver
274 static void Cyber_WaitQueue(u_short fifo);
275 static void Cyber_WaitBlit(void);
276 static void Cyber_BitBLT(u_short curx, u_short cury, u_short destx,
277 u_short desty, u_short width, u_short height,
278 u_short mode);
279 static void Cyber_RectFill(u_short x, u_short y, u_short width, u_short height,
280 u_short mode, u_short color);
281 #if 0
282 static void Cyber_MoveCursor(u_short x, u_short y);
283 #endif
286 * Hardware Specific Routines
289 static int Cyber_init(void);
290 static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
291 struct cyberfb_par *par);
292 static int Cyber_decode_var(struct fb_var_screeninfo *var,
293 struct cyberfb_par *par);
294 static int Cyber_encode_var(struct fb_var_screeninfo *var,
295 struct cyberfb_par *par);
296 static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
297 u_int *transp, struct fb_info *info);
298 static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
299 u_int transp, struct fb_info *info);
302 * Internal routines
305 static void cyberfb_get_par(struct cyberfb_par *par);
306 static void cyberfb_set_par(struct cyberfb_par *par);
307 static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
308 static void do_install_cmap(int con, struct fb_info *info);
309 static void cyberfb_set_disp(int con, struct fb_info *info);
310 static int get_video_mode(const char *name);
312 /* For cvision_core.c */
313 static unsigned short cv64_compute_clock(unsigned long);
314 static int cv_has_4mb (volatile unsigned char *);
315 static void cv64_board_init (void);
316 static void cv64_load_video_mode (struct fb_var_screeninfo *);
319 /* -------------------- Hardware specific routines ------------------------- */
323 * Initialization
325 * Set the default video mode for this chipset. If a video mode was
326 * specified on the command line, it will override the default mode.
329 static int Cyber_init(void)
331 volatile unsigned char *regs = CyberRegs;
332 volatile unsigned long *CursorBase;
333 int i;
334 DPRINTK("ENTER\n");
336 /* Init local cmap as greyscale levels */
337 for (i = 0; i < 256; i++) {
338 Cyber_colour_table [i][0] = i;
339 Cyber_colour_table [i][1] = i;
340 Cyber_colour_table [i][2] = i;
343 /* Initialize the board and determine fbmem size */
344 cv64_board_init();
345 #ifdef CYBERFBDEBUG
346 DPRINTK("Register state after initing board\n");
347 cv64_dump();
348 #endif
349 /* Clear framebuffer memory */
350 DPRINTK("Clear framebuffer memory\n");
351 memset ((char *)CyberMem, 0, CyberSize);
353 /* Disable hardware cursor */
354 DPRINTK("Disable HW cursor\n");
355 wb_64(regs, S3_CRTC_ADR, S3_REG_LOCK2);
356 wb_64(regs, S3_CRTC_DATA, 0xa0);
357 wb_64(regs, S3_CRTC_ADR, S3_HGC_MODE);
358 wb_64(regs, S3_CRTC_DATA, 0x00);
359 wb_64(regs, S3_CRTC_ADR, S3_HWGC_DX);
360 wb_64(regs, S3_CRTC_DATA, 0x00);
361 wb_64(regs, S3_CRTC_ADR, S3_HWGC_DY);
362 wb_64(regs, S3_CRTC_DATA, 0x00);
364 /* Initialize hardware cursor */
365 DPRINTK("Init HW cursor\n");
366 CursorBase = (u_long *)((char *)(CyberMem) + CyberSize - 0x400);
367 for (i=0; i < 8; i++)
369 *(CursorBase +(i*4)) = 0xffffff00;
370 *(CursorBase+1+(i*4)) = 0xffff0000;
371 *(CursorBase+2+(i*4)) = 0xffff0000;
372 *(CursorBase+3+(i*4)) = 0xffff0000;
374 for (i=8; i < 64; i++)
376 *(CursorBase +(i*4)) = 0xffff0000;
377 *(CursorBase+1+(i*4)) = 0xffff0000;
378 *(CursorBase+2+(i*4)) = 0xffff0000;
379 *(CursorBase+3+(i*4)) = 0xffff0000;
382 Cyber_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, NULL /* unused */);
383 Cyber_setcolreg (254, 0, 0, 0, 0, NULL /* unused */);
385 DPRINTK("EXIT\n");
386 return 0;
391 * This function should fill in the `fix' structure based on the
392 * values in the `par' structure.
395 static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
396 struct cyberfb_par *par)
398 DPRINTK("ENTER\n");
399 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
400 strcpy(fix->id, cyberfb_name);
401 fix->smem_start = CyberMem_phys;
402 fix->smem_len = CyberSize;
403 fix->mmio_start = CyberRegs_phys;
404 fix->mmio_len = 0x10000;
406 fix->type = FB_TYPE_PACKED_PIXELS;
407 fix->type_aux = 0;
408 if (par->var.bits_per_pixel == 15 || par->var.bits_per_pixel == 16 ||
409 par->var.bits_per_pixel == 24 || par->var.bits_per_pixel == 32) {
410 fix->visual = FB_VISUAL_DIRECTCOLOR;
411 } else {
412 fix->visual = FB_VISUAL_PSEUDOCOLOR;
415 fix->xpanstep = 0;
416 fix->ypanstep = 0;
417 fix->ywrapstep = 0;
418 fix->line_length = 0;
419 fix->accel = FB_ACCEL_S3_TRIO64;
421 DPRINTK("EXIT\n");
422 return(0);
427 * Fill the `par' structure based on the values in `var'.
428 * TODO: Verify and adjust values, return -EINVAL if bad.
431 static int Cyber_decode_var(struct fb_var_screeninfo *var,
432 struct cyberfb_par *par)
434 DPRINTK("ENTER\n");
435 par->var.xres = var->xres;
436 par->var.yres = var->yres;
437 par->var.xres_virtual = var->xres_virtual;
438 par->var.yres_virtual = var->yres_virtual;
439 par->var.xoffset = var->xoffset;
440 par->var.yoffset = var->yoffset;
441 par->var.bits_per_pixel = var->bits_per_pixel;
442 par->var.grayscale = var->grayscale;
443 par->var.red = var->red;
444 par->var.green = var->green;
445 par->var.blue = var->blue;
446 par->var.transp = var->transp;
447 par->var.nonstd = var->nonstd;
448 par->var.activate = var->activate;
449 par->var.height = var->height;
450 par->var.width = var->width;
451 if (var->accel_flags & FB_ACCELF_TEXT) {
452 par->var.accel_flags = FB_ACCELF_TEXT;
453 } else {
454 par->var.accel_flags = 0;
456 par->var.pixclock = var->pixclock;
457 par->var.left_margin = var->left_margin;
458 par->var.right_margin = var->right_margin;
459 par->var.upper_margin = var->upper_margin;
460 par->var.lower_margin = var->lower_margin;
461 par->var.hsync_len = var->hsync_len;
462 par->var.vsync_len = var->vsync_len;
463 par->var.sync = var->sync;
464 par->var.vmode = var->vmode;
465 DPRINTK("EXIT\n");
466 return(0);
470 * Fill the `var' structure based on the values in `par' and maybe
471 * other values read out of the hardware.
474 static int Cyber_encode_var(struct fb_var_screeninfo *var,
475 struct cyberfb_par *par)
477 DPRINTK("ENTER\n");
478 var->xres = par->var.xres;
479 var->yres = par->var.yres;
480 var->xres_virtual = par->var.xres_virtual;
481 var->yres_virtual = par->var.yres_virtual;
482 var->xoffset = par->var.xoffset;
483 var->yoffset = par->var.yoffset;
485 var->bits_per_pixel = par->var.bits_per_pixel;
486 var->grayscale = par->var.grayscale;
488 var->red = par->var.red;
489 var->green = par->var.green;
490 var->blue = par->var.blue;
491 var->transp = par->var.transp;
493 var->nonstd = par->var.nonstd;
494 var->activate = par->var.activate;
496 var->height = par->var.height;
497 var->width = par->var.width;
499 var->accel_flags = par->var.accel_flags;
501 var->pixclock = par->var.pixclock;
502 var->left_margin = par->var.left_margin;
503 var->right_margin = par->var.right_margin;
504 var->upper_margin = par->var.upper_margin;
505 var->lower_margin = par->var.lower_margin;
506 var->hsync_len = par->var.hsync_len;
507 var->vsync_len = par->var.vsync_len;
508 var->sync = par->var.sync;
509 var->vmode = par->var.vmode;
511 DPRINTK("EXIT\n");
512 return(0);
517 * Set a single color register. Return != 0 for invalid regno.
520 static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
521 u_int transp, struct fb_info *info)
523 volatile unsigned char *regs = CyberRegs;
525 /*DPRINTK("ENTER\n");*/
526 if (regno > 255) {
527 DPRINTK("EXIT - Register # > 255\n");
528 return (1);
531 wb_64(regs, 0x3c8, (unsigned char) regno);
533 red >>= 10;
534 green >>= 10;
535 blue >>= 10;
537 Cyber_colour_table [regno][0] = red;
538 Cyber_colour_table [regno][1] = green;
539 Cyber_colour_table [regno][2] = blue;
541 wb_64(regs, 0x3c9, red);
542 wb_64(regs, 0x3c9, green);
543 wb_64(regs, 0x3c9, blue);
545 /*DPRINTK("EXIT\n");*/
546 return (0);
551 * Read a single color register and split it into
552 * colors/transparent. Return != 0 for invalid regno.
555 static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
556 u_int *transp, struct fb_info *info)
558 int t;
560 /*DPRINTK("ENTER\n");*/
561 if (regno > 255) {
562 DPRINTK("EXIT - Register # > 255\n");
563 return (1);
565 /* ARB This shifting & oring seems VERY strange */
566 t = Cyber_colour_table [regno][0];
567 *red = (t<<10) | (t<<4) | (t>>2);
568 t = Cyber_colour_table [regno][1];
569 *green = (t<<10) | (t<<4) | (t>>2);
570 t = Cyber_colour_table [regno][2];
571 *blue = (t<<10) | (t<<4) | (t>>2);
572 *transp = 0;
573 /*DPRINTK("EXIT\n");*/
574 return (0);
579 * (Un)Blank the screen
580 * blank: 1 = zero fb cmap
581 * 0 = restore fb cmap from local cmap
584 void Cyberfb_blank(int blank, struct fb_info *info)
586 volatile unsigned char *regs = CyberRegs;
587 int i;
589 DPRINTK("ENTER\n");
590 #if 0
591 /* Blank by turning gfx off */
592 gfx_on_off (1, regs);
593 #else
594 if (blank) {
595 for (i = 0; i < 256; i++) {
596 wb_64(regs, 0x3c8, (unsigned char) i);
597 /* ARB Pale red to detect this blanking method */
598 wb_64(regs, 0x3c9, 48);
599 wb_64(regs, 0x3c9, 0);
600 wb_64(regs, 0x3c9, 0);
602 } else {
603 for (i = 0; i < 256; i++) {
604 wb_64(regs, 0x3c8, (unsigned char) i);
605 wb_64(regs, 0x3c9, Cyber_colour_table[i][0]);
606 wb_64(regs, 0x3c9, Cyber_colour_table[i][1]);
607 wb_64(regs, 0x3c9, Cyber_colour_table[i][2]);
610 #endif
611 DPRINTK("EXIT\n");
615 /**************************************************************
616 * We are waiting for "fifo" FIFO-slots empty
618 static void Cyber_WaitQueue (u_short fifo)
620 unsigned short status;
622 DPRINTK("ENTER\n");
623 do {
624 status = *((u_short volatile *)(CyberRegs + S3_GP_STAT));
625 } while (status & fifo);
626 DPRINTK("EXIT\n");
629 /**************************************************************
630 * We are waiting for Hardware (Graphics Engine) not busy
632 static void Cyber_WaitBlit (void)
634 unsigned short status;
636 DPRINTK("ENTER\n");
637 do {
638 status = *((u_short volatile *)(CyberRegs + S3_GP_STAT));
639 } while (status & S3_HDW_BUSY);
640 DPRINTK("EXIT\n");
643 /**************************************************************
644 * BitBLT - Through the Plane
646 static void Cyber_BitBLT (u_short curx, u_short cury, u_short destx,
647 u_short desty, u_short width, u_short height,
648 u_short mode)
650 volatile unsigned char *regs = CyberRegs;
651 u_short blitcmd = S3_BITBLT;
653 DPRINTK("ENTER\n");
654 /* Set drawing direction */
655 /* -Y, X maj, -X (default) */
656 if (curx > destx) {
657 blitcmd |= 0x0020; /* Drawing direction +X */
658 } else {
659 curx += (width - 1);
660 destx += (width - 1);
663 if (cury > desty) {
664 blitcmd |= 0x0080; /* Drawing direction +Y */
665 } else {
666 cury += (height - 1);
667 desty += (height - 1);
670 Cyber_WaitQueue (0x8000);
672 *((u_short volatile *)(regs + S3_PIXEL_CNTL)) = 0xa000;
673 *((u_short volatile *)(regs + S3_FRGD_MIX)) = (0x0060 | mode);
675 *((u_short volatile *)(regs + S3_CUR_X)) = curx;
676 *((u_short volatile *)(regs + S3_CUR_Y)) = cury;
678 *((u_short volatile *)(regs + S3_DESTX_DIASTP)) = destx;
679 *((u_short volatile *)(regs + S3_DESTY_AXSTP)) = desty;
681 *((u_short volatile *)(regs + S3_MIN_AXIS_PCNT)) = height - 1;
682 *((u_short volatile *)(regs + S3_MAJ_AXIS_PCNT)) = width - 1;
684 *((u_short volatile *)(regs + S3_CMD)) = blitcmd;
685 DPRINTK("EXIT\n");
688 /**************************************************************
689 * Rectangle Fill Solid
691 static void Cyber_RectFill (u_short x, u_short y, u_short width,
692 u_short height, u_short mode, u_short color)
694 volatile unsigned char *regs = CyberRegs;
695 u_short blitcmd = S3_FILLEDRECT;
697 DPRINTK("ENTER\n");
698 Cyber_WaitQueue (0x8000);
700 *((u_short volatile *)(regs + S3_PIXEL_CNTL)) = 0xa000;
701 *((u_short volatile *)(regs + S3_FRGD_MIX)) = (0x0020 | mode);
703 *((u_short volatile *)(regs + S3_MULT_MISC)) = 0xe000;
704 *((u_short volatile *)(regs + S3_FRGD_COLOR)) = color;
706 *((u_short volatile *)(regs + S3_CUR_X)) = x;
707 *((u_short volatile *)(regs + S3_CUR_Y)) = y;
709 *((u_short volatile *)(regs + S3_MIN_AXIS_PCNT)) = height - 1;
710 *((u_short volatile *)(regs + S3_MAJ_AXIS_PCNT)) = width - 1;
712 *((u_short volatile *)(regs + S3_CMD)) = blitcmd;
713 DPRINTK("EXIT\n");
717 #if 0
718 /**************************************************************
719 * Move cursor to x, y
721 static void Cyber_MoveCursor (u_short x, u_short y)
723 volatile unsigned char *regs = CyberRegs;
724 DPRINTK("ENTER\n");
725 *(regs + S3_CRTC_ADR) = 0x39;
726 *(regs + S3_CRTC_DATA) = 0xa0;
728 *(regs + S3_CRTC_ADR) = S3_HWGC_ORGX_H;
729 *(regs + S3_CRTC_DATA) = (char)((x & 0x0700) >> 8);
730 *(regs + S3_CRTC_ADR) = S3_HWGC_ORGX_L;
731 *(regs + S3_CRTC_DATA) = (char)(x & 0x00ff);
733 *(regs + S3_CRTC_ADR) = S3_HWGC_ORGY_H;
734 *(regs + S3_CRTC_DATA) = (char)((y & 0x0700) >> 8);
735 *(regs + S3_CRTC_ADR) = S3_HWGC_ORGY_L;
736 *(regs + S3_CRTC_DATA) = (char)(y & 0x00ff);
737 DPRINTK("EXIT\n");
739 #endif
742 /* -------------------- Generic routines ---------------------------------- */
746 * Fill the hardware's `par' structure.
749 static void cyberfb_get_par(struct cyberfb_par *par)
751 DPRINTK("ENTER\n");
752 if (current_par_valid) {
753 *par = current_par;
754 } else {
755 Cyber_decode_var(&cyberfb_default, par);
757 DPRINTK("EXIT\n");
761 static void cyberfb_set_par(struct cyberfb_par *par)
763 DPRINTK("ENTER\n");
764 current_par = *par;
765 current_par_valid = 1;
766 DPRINTK("EXIT\n");
770 static void cyber_set_video(struct fb_var_screeninfo *var)
773 /* Load the video mode defined by the 'var' data */
774 cv64_load_video_mode (var);
775 #ifdef CYBERFBDEBUG
776 DPRINTK("Register state after loading video mode\n");
777 cv64_dump();
778 #endif
782 static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
784 int err, activate;
785 struct cyberfb_par par;
787 DPRINTK("ENTER\n");
788 if ((err = Cyber_decode_var(var, &par))) {
789 DPRINTK("EXIT - decode_var failed\n");
790 return(err);
792 activate = var->activate;
793 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
794 cyberfb_set_par(&par);
795 Cyber_encode_var(var, &par);
796 var->activate = activate;
798 cyber_set_video(var);
799 DPRINTK("EXIT\n");
800 return 0;
804 static void do_install_cmap(int con, struct fb_info *info)
806 DPRINTK("ENTER\n");
807 if (con != currcon) {
808 DPRINTK("EXIT - Not current console\n");
809 return;
811 if (fb_display[con].cmap.len) {
812 DPRINTK("Use console cmap\n");
813 fb_set_cmap(&fb_display[con].cmap, 1, Cyber_setcolreg, info);
814 } else {
815 DPRINTK("Use default cmap\n");
816 fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
817 1, Cyber_setcolreg, info);
819 DPRINTK("EXIT\n");
823 * Get the Fixed Part of the Display
826 static int cyberfb_get_fix(struct fb_fix_screeninfo *fix, int con,
827 struct fb_info *info)
829 struct cyberfb_par par;
830 int error = 0;
832 DPRINTK("ENTER\n");
833 if (con == -1) {
834 cyberfb_get_par(&par);
835 } else {
836 error = Cyber_decode_var(&fb_display[con].var, &par);
838 DPRINTK("EXIT\n");
839 return(error ? error : Cyber_encode_fix(fix, &par));
844 * Get the User Defined Part of the Display
847 static int cyberfb_get_var(struct fb_var_screeninfo *var, int con,
848 struct fb_info *info)
850 struct cyberfb_par par;
851 int error = 0;
853 DPRINTK("ENTER\n");
854 if (con == -1) {
855 cyberfb_get_par(&par);
856 error = Cyber_encode_var(var, &par);
857 disp.var = *var; /* ++Andre: don't know if this is the right place */
858 } else {
859 *var = fb_display[con].var;
862 DPRINTK("EXIT\n");
863 return(error);
867 static void cyberfb_set_disp(int con, struct fb_info *info)
869 struct fb_fix_screeninfo fix;
870 struct display *display;
872 DPRINTK("ENTER\n");
873 if (con >= 0)
874 display = &fb_display[con];
875 else
876 display = &disp; /* used during initialization */
878 cyberfb_get_fix(&fix, con, info);
879 if (con == -1)
880 con = 0;
881 display->screen_base = (unsigned char *)CyberMem;
882 display->visual = fix.visual;
883 display->type = fix.type;
884 display->type_aux = fix.type_aux;
885 display->ypanstep = fix.ypanstep;
886 display->ywrapstep = fix.ywrapstep;
887 display->can_soft_blank = 1;
888 display->inverse = Cyberfb_inverse;
889 switch (display->var.bits_per_pixel) {
890 #ifdef FBCON_HAS_CFB8
891 case 8:
892 if (display->var.accel_flags & FB_ACCELF_TEXT) {
893 display->dispsw = &fbcon_cyber8;
894 #warning FIXME: We should reinit the graphics engine here
895 } else
896 display->dispsw = &fbcon_cfb8;
897 break;
898 #endif
899 #ifdef FBCON_HAS_CFB16
900 case 16:
901 display->dispsw = &fbcon_cfb16;
902 break;
903 #endif
904 default:
905 display->dispsw = NULL;
906 break;
908 DPRINTK("EXIT\n");
913 * Set the User Defined Part of the Display
916 static int cyberfb_set_var(struct fb_var_screeninfo *var, int con,
917 struct fb_info *info)
919 int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel;
921 DPRINTK("ENTER\n");
922 if ((err = do_fb_set_var(var, con == currcon))) {
923 DPRINTK("EXIT - do_fb_set_var failed\n");
924 return(err);
926 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
927 oldxres = fb_display[con].var.xres;
928 oldyres = fb_display[con].var.yres;
929 oldvxres = fb_display[con].var.xres_virtual;
930 oldvyres = fb_display[con].var.yres_virtual;
931 oldbpp = fb_display[con].var.bits_per_pixel;
932 oldaccel = fb_display[con].var.accel_flags;
933 fb_display[con].var = *var;
934 if (oldxres != var->xres || oldyres != var->yres ||
935 oldvxres != var->xres_virtual ||
936 oldvyres != var->yres_virtual ||
937 oldbpp != var->bits_per_pixel ||
938 oldaccel != var->accel_flags) {
939 cyberfb_set_disp(con, info);
940 (*fb_info.changevar)(con);
941 fb_alloc_cmap(&fb_display[con].cmap, 0, 0);
942 do_install_cmap(con, info);
945 var->activate = 0;
946 DPRINTK("EXIT\n");
947 return(0);
952 * Get the Colormap
955 static int cyberfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
956 struct fb_info *info)
958 DPRINTK("ENTER\n");
959 if (con == currcon) { /* current console? */
960 DPRINTK("EXIT - console is current console\n");
961 return(fb_get_cmap(cmap, kspc, Cyber_getcolreg, info));
962 } else if (fb_display[con].cmap.len) { /* non default colormap? */
963 DPRINTK("Use console cmap\n");
964 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
965 } else {
966 DPRINTK("Use default cmap\n");
967 fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
968 cmap, kspc ? 0 : 2);
970 DPRINTK("EXIT\n");
971 return(0);
976 * Set the Colormap
979 static int cyberfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
980 struct fb_info *info)
982 int err;
984 DPRINTK("ENTER\n");
985 if (!fb_display[con].cmap.len) { /* no colormap allocated? */
986 if ((err = fb_alloc_cmap(&fb_display[con].cmap,
987 1<<fb_display[con].var.bits_per_pixel,
988 0))) {
989 DPRINTK("EXIT - fb_alloc_cmap failed\n");
990 return(err);
993 if (con == currcon) { /* current console? */
994 DPRINTK("EXIT - Current console\n");
995 return(fb_set_cmap(cmap, kspc, Cyber_setcolreg, info));
996 } else {
997 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
999 DPRINTK("EXIT\n");
1000 return(0);
1004 static struct fb_ops cyberfb_ops = {
1005 owner: THIS_MODULE,
1006 fb_get_fix: cyberfb_get_fix,
1007 fb_get_var: cyberfb_get_var,
1008 fb_set_var: cyberfb_set_var,
1009 fb_get_cmap: cyberfb_get_cmap,
1010 fb_set_cmap: cyberfb_set_cmap,
1013 int __init cyberfb_setup(char *options)
1015 char *this_opt;
1016 DPRINTK("ENTER\n");
1018 fb_info.fontname[0] = '\0';
1020 if (!options || !*options) {
1021 DPRINTK("EXIT - no options\n");
1022 return 0;
1025 for (this_opt = strtok(options, ","); this_opt;
1026 this_opt = strtok(NULL, ",")) {
1027 if (!strcmp(this_opt, "inverse")) {
1028 Cyberfb_inverse = 1;
1029 fb_invert_cmaps();
1030 } else if (!strncmp(this_opt, "font:", 5)) {
1031 strcpy(fb_info.fontname, this_opt+5);
1032 } else if (!strcmp (this_opt, "cyber8")) {
1033 cyberfb_default = cyberfb_predefined[CYBER8_DEFMODE].var;
1034 cyberfb_usermode = 1;
1035 } else if (!strcmp (this_opt, "cyber16")) {
1036 cyberfb_default = cyberfb_predefined[CYBER16_DEFMODE].var;
1037 cyberfb_usermode = 1;
1038 } else get_video_mode(this_opt);
1041 DPRINTK("default mode: xres=%d, yres=%d, bpp=%d\n",
1042 cyberfb_default.xres,
1043 cyberfb_default.yres,
1044 cyberfb_default.bits_per_pixel);
1045 DPRINTK("EXIT\n");
1046 return 0;
1050 * Initialization
1053 int __init cyberfb_init(void)
1055 unsigned long board_addr, board_size;
1056 struct cyberfb_par par;
1057 struct zorro_dev *z = NULL;
1058 DPRINTK("ENTER\n");
1060 while ((z = zorro_find_device(ZORRO_PROD_PHASE5_CYBERVISION64, z))) {
1061 board_addr = z->resource.start;
1062 board_size = z->resource.end-z->resource.start+1;
1063 CyberMem_phys = board_addr + 0x01400000;
1064 CyberRegs_phys = CyberMem_phys + 0x00c00000;
1065 if (!request_mem_region(CyberRegs_phys, 0x10000, "S3 Trio64"))
1066 continue;
1067 if (!request_mem_region(CyberMem_phys, 0x400000, "RAM")) {
1068 release_mem_region(CyberRegs_phys, 0x10000);
1069 continue;
1071 DPRINTK("board_addr=%08lx\n", board_addr);
1072 DPRINTK("board_size=%08lx\n", board_size);
1074 CyberBase = ioremap(board_addr, board_size);
1075 CyberRegs = CyberBase + 0x02000000;
1076 CyberMem = CyberBase + 0x01400000;
1077 DPRINTK("CyberBase=%08lx CyberRegs=%08lx CyberMem=%08lx\n",
1078 CyberBase, (long unsigned int)CyberRegs, CyberMem);
1080 #ifdef CYBERFBDEBUG
1081 DPRINTK("Register state just after mapping memory\n");
1082 cv64_dump();
1083 #endif
1085 strcpy(fb_info.modename, cyberfb_name);
1086 fb_info.changevar = NULL;
1087 fb_info.node = -1;
1088 fb_info.fbops = &cyberfb_ops;
1089 fb_info.disp = &disp;
1090 fb_info.switch_con = &Cyberfb_switch;
1091 fb_info.updatevar = &Cyberfb_updatevar;
1092 fb_info.blank = &Cyberfb_blank;
1094 Cyber_init();
1095 /* ++Andre: set cyberfb default mode */
1096 if (!cyberfb_usermode) {
1097 cyberfb_default = cyberfb_predefined[CYBER8_DEFMODE].var;
1098 DPRINTK("Use default cyber8 mode\n");
1100 Cyber_decode_var(&cyberfb_default, &par);
1101 Cyber_encode_var(&cyberfb_default, &par);
1103 do_fb_set_var(&cyberfb_default, 1);
1104 cyberfb_get_var(&fb_display[0].var, -1, &fb_info);
1105 cyberfb_set_disp(-1, &fb_info);
1106 do_install_cmap(0, &fb_info);
1108 if (register_framebuffer(&fb_info) < 0) {
1109 DPRINTK("EXIT - register_framebuffer failed\n");
1110 release_mem_region(CyberMem_phys, 0x400000);
1111 release_mem_region(CyberRegs_phys, 0x10000);
1112 return -EINVAL;
1115 printk("fb%d: %s frame buffer device, using %ldK of video memory\n",
1116 GET_FB_IDX(fb_info.node), fb_info.modename, CyberSize>>10);
1118 /* TODO: This driver cannot be unloaded yet */
1119 MOD_INC_USE_COUNT;
1120 DPRINTK("EXIT\n");
1121 return 0;
1123 return -ENXIO;
1127 static int Cyberfb_switch(int con, struct fb_info *info)
1129 DPRINTK("ENTER\n");
1130 /* Do we have to save the colormap? */
1131 if (fb_display[currcon].cmap.len) {
1132 fb_get_cmap(&fb_display[currcon].cmap, 1, Cyber_getcolreg,
1133 info);
1136 do_fb_set_var(&fb_display[con].var, 1);
1137 currcon = con;
1138 /* Install new colormap */
1139 do_install_cmap(con, info);
1140 DPRINTK("EXIT\n");
1141 return(0);
1146 * Update the `var' structure (called by fbcon.c)
1148 * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
1149 * Since it's called by a kernel driver, no range checking is done.
1152 static int Cyberfb_updatevar(int con, struct fb_info *info)
1154 DPRINTK("Enter - Exit\n");
1155 return(0);
1160 * Get a Video Mode
1163 static int __init get_video_mode(const char *name)
1165 int i;
1167 DPRINTK("ENTER\n");
1168 for (i = 0; i < NUM_TOTAL_MODES; i++) {
1169 if (!strcmp(name, cyberfb_predefined[i].name)) {
1170 cyberfb_default = cyberfb_predefined[i].var;
1171 cyberfb_usermode = 1;
1172 DPRINTK("EXIT - Matched predefined mode\n");
1173 return(i);
1176 return(0);
1181 * Text console acceleration
1184 #ifdef FBCON_HAS_CFB8
1185 static void fbcon_cyber8_bmove(struct display *p, int sy, int sx, int dy,
1186 int dx, int height, int width)
1188 DPRINTK("ENTER\n");
1189 sx *= 8; dx *= 8; width *= 8;
1190 Cyber_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx,
1191 (u_short)(dy*fontheight(p)), (u_short)width,
1192 (u_short)(height*fontheight(p)), (u_short)S3_NEW);
1193 DPRINTK("EXIT\n");
1196 static void fbcon_cyber8_clear(struct vc_data *conp, struct display *p, int sy,
1197 int sx, int height, int width)
1199 unsigned char bg;
1201 DPRINTK("ENTER\n");
1202 sx *= 8; width *= 8;
1203 bg = attr_bgcol_ec(p,conp);
1204 Cyber_RectFill((u_short)sx,
1205 (u_short)(sy*fontheight(p)),
1206 (u_short)width,
1207 (u_short)(height*fontheight(p)),
1208 (u_short)S3_NEW,
1209 (u_short)bg);
1210 DPRINTK("EXIT\n");
1213 static void fbcon_cyber8_putc(struct vc_data *conp, struct display *p, int c,
1214 int yy, int xx)
1216 DPRINTK("ENTER\n");
1217 Cyber_WaitBlit();
1218 fbcon_cfb8_putc(conp, p, c, yy, xx);
1219 DPRINTK("EXIT\n");
1222 static void fbcon_cyber8_putcs(struct vc_data *conp, struct display *p,
1223 const unsigned short *s, int count,
1224 int yy, int xx)
1226 DPRINTK("ENTER\n");
1227 Cyber_WaitBlit();
1228 fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
1229 DPRINTK("EXIT\n");
1232 static void fbcon_cyber8_revc(struct display *p, int xx, int yy)
1234 DPRINTK("ENTER\n");
1235 Cyber_WaitBlit();
1236 fbcon_cfb8_revc(p, xx, yy);
1237 DPRINTK("EXIT\n");
1240 static struct display_switch fbcon_cyber8 = {
1241 setup: fbcon_cfb8_setup,
1242 bmove: fbcon_cyber8_bmove,
1243 clear: fbcon_cyber8_clear,
1244 putc: fbcon_cyber8_putc,
1245 putcs: fbcon_cyber8_putcs,
1246 revc: fbcon_cyber8_revc,
1247 clear_margins: fbcon_cfb8_clear_margins,
1248 fontwidthmask: FONTWIDTH(8)
1250 #endif
1253 #ifdef MODULE
1254 int init_module(void)
1256 return cyberfb_init();
1259 void cleanup_module(void)
1261 /* Not reached because the usecount will never be
1262 decremented to zero */
1263 unregister_framebuffer(&fb_info);
1264 /* TODO: clean up ... */
1266 #endif /* MODULE */
1270 * Low level initialization routines for the CyberVision64 graphics card
1272 * Most of the following code is from cvision_core.c
1276 #define MAXPIXELCLOCK 135000000 /* safety */
1278 #ifdef CV_AGGRESSIVE_TIMING
1279 long cv64_memclk = 55000000;
1280 #else
1281 long cv64_memclk = 50000000;
1282 #endif
1284 /*********************/
1286 static unsigned char clocks[]={
1287 0x13, 0x61, 0x6b, 0x6d, 0x51, 0x69, 0x54, 0x69,
1288 0x4f, 0x68, 0x6b, 0x6b, 0x18, 0x61, 0x7b, 0x6c,
1289 0x51, 0x67, 0x24, 0x62, 0x56, 0x67, 0x77, 0x6a,
1290 0x1d, 0x61, 0x53, 0x66, 0x6b, 0x68, 0x79, 0x69,
1291 0x7c, 0x69, 0x7f, 0x69, 0x22, 0x61, 0x54, 0x65,
1292 0x56, 0x65, 0x58, 0x65, 0x67, 0x66, 0x41, 0x63,
1293 0x27, 0x61, 0x13, 0x41, 0x37, 0x62, 0x6b, 0x4d,
1294 0x23, 0x43, 0x51, 0x49, 0x79, 0x66, 0x54, 0x49,
1295 0x7d, 0x66, 0x34, 0x56, 0x4f, 0x63, 0x1f, 0x42,
1296 0x6b, 0x4b, 0x7e, 0x4d, 0x18, 0x41, 0x2a, 0x43,
1297 0x7b, 0x4c, 0x74, 0x4b, 0x51, 0x47, 0x65, 0x49,
1298 0x24, 0x42, 0x68, 0x49, 0x56, 0x47, 0x75, 0x4a,
1299 0x77, 0x4a, 0x31, 0x43, 0x1d, 0x41, 0x71, 0x49,
1300 0x53, 0x46, 0x29, 0x42, 0x6b, 0x48, 0x1f, 0x41,
1301 0x79, 0x49, 0x6f, 0x48, 0x7c, 0x49, 0x38, 0x43,
1302 0x7f, 0x49, 0x5d, 0x46, 0x22, 0x41, 0x53, 0x45,
1303 0x54, 0x45, 0x55, 0x45, 0x56, 0x45, 0x57, 0x45,
1304 0x58, 0x45, 0x25, 0x41, 0x67, 0x46, 0x5b, 0x45,
1305 0x41, 0x43, 0x78, 0x47, 0x27, 0x41, 0x51, 0x44,
1306 0x13, 0x21, 0x7d, 0x47, 0x37, 0x42, 0x71, 0x46,
1307 0x6b, 0x2d, 0x14, 0x21, 0x23, 0x23, 0x7d, 0x2f,
1308 0x51, 0x29, 0x61, 0x2b, 0x79, 0x46, 0x1d, 0x22,
1309 0x54, 0x29, 0x45, 0x27, 0x7d, 0x46, 0x7f, 0x46,
1310 0x4f, 0x43, 0x2f, 0x41, 0x1f, 0x22, 0x6a, 0x2b,
1311 0x6b, 0x2b, 0x5b, 0x29, 0x7e, 0x2d, 0x65, 0x44,
1312 0x18, 0x21, 0x5e, 0x29, 0x2a, 0x23, 0x45, 0x26,
1313 0x7b, 0x2c, 0x19, 0x21, 0x74, 0x2b, 0x75, 0x2b,
1314 0x51, 0x27, 0x3f, 0x25, 0x65, 0x29, 0x40, 0x25,
1315 0x24, 0x22, 0x41, 0x25, 0x68, 0x29, 0x42, 0x25,
1316 0x56, 0x27, 0x7e, 0x2b, 0x75, 0x2a, 0x1c, 0x21,
1317 0x77, 0x2a, 0x4f, 0x26, 0x31, 0x23, 0x6f, 0x29,
1318 0x1d, 0x21, 0x32, 0x23, 0x71, 0x29, 0x72, 0x29,
1319 0x53, 0x26, 0x69, 0x28, 0x29, 0x22, 0x75, 0x29,
1320 0x6b, 0x28, 0x1f, 0x21, 0x1f, 0x21, 0x6d, 0x28,
1321 0x79, 0x29, 0x2b, 0x22, 0x6f, 0x28, 0x59, 0x26,
1322 0x7c, 0x29, 0x7d, 0x29, 0x38, 0x23, 0x21, 0x21,
1323 0x7f, 0x29, 0x39, 0x23, 0x5d, 0x26, 0x75, 0x28,
1324 0x22, 0x21, 0x77, 0x28, 0x53, 0x25, 0x6c, 0x27,
1325 0x54, 0x25, 0x61, 0x26, 0x55, 0x25, 0x30, 0x22,
1326 0x56, 0x25, 0x63, 0x26, 0x57, 0x25, 0x71, 0x27,
1327 0x58, 0x25, 0x7f, 0x28, 0x25, 0x21, 0x74, 0x27,
1328 0x67, 0x26, 0x40, 0x23, 0x5b, 0x25, 0x26, 0x21,
1329 0x41, 0x23, 0x34, 0x22, 0x78, 0x27, 0x6b, 0x26,
1330 0x27, 0x21, 0x35, 0x22, 0x51, 0x24, 0x7b, 0x27,
1331 0x13, 0x1, 0x13, 0x1, 0x7d, 0x27, 0x4c, 0x9,
1332 0x37, 0x22, 0x5b, 0xb, 0x71, 0x26, 0x5c, 0xb,
1333 0x6b, 0xd, 0x47, 0x23, 0x14, 0x1, 0x4f, 0x9,
1334 0x23, 0x3, 0x75, 0x26, 0x7d, 0xf, 0x1c, 0x2,
1335 0x51, 0x9, 0x59, 0x24, 0x61, 0xb, 0x69, 0x25,
1336 0x79, 0x26, 0x34, 0x5, 0x1d, 0x2, 0x6b, 0x25,
1337 0x54, 0x9, 0x35, 0x5, 0x45, 0x7, 0x6d, 0x25,
1338 0x7d, 0x26, 0x16, 0x1, 0x7f, 0x26, 0x77, 0xd,
1339 0x4f, 0x23, 0x78, 0xd, 0x2f, 0x21, 0x27, 0x3,
1340 0x1f, 0x2, 0x59, 0x9, 0x6a, 0xb, 0x73, 0x25,
1341 0x6b, 0xb, 0x63, 0x24, 0x5b, 0x9, 0x20, 0x2,
1342 0x7e, 0xd, 0x4b, 0x7, 0x65, 0x24, 0x43, 0x22,
1343 0x18, 0x1, 0x6f, 0xb, 0x5e, 0x9, 0x70, 0xb,
1344 0x2a, 0x3, 0x33, 0x4, 0x45, 0x6, 0x60, 0x9,
1345 0x7b, 0xc, 0x19, 0x1, 0x19, 0x1, 0x7d, 0xc,
1346 0x74, 0xb, 0x50, 0x7, 0x75, 0xb, 0x63, 0x9,
1347 0x51, 0x7, 0x23, 0x2, 0x3f, 0x5, 0x1a, 0x1,
1348 0x65, 0x9, 0x2d, 0x3, 0x40, 0x5, 0x0, 0x0,
1351 /* Console colors */
1352 unsigned char cvconscolors[16][3] = { /* background, foreground, hilite */
1353 /* R G B */
1354 {0x30, 0x30, 0x30},
1355 {0x00, 0x00, 0x00},
1356 {0x80, 0x00, 0x00},
1357 {0x00, 0x80, 0x00},
1358 {0x00, 0x00, 0x80},
1359 {0x80, 0x80, 0x00},
1360 {0x00, 0x80, 0x80},
1361 {0x80, 0x00, 0x80},
1362 {0xff, 0xff, 0xff},
1363 {0x40, 0x40, 0x40},
1364 {0xff, 0x00, 0x00},
1365 {0x00, 0xff, 0x00},
1366 {0x00, 0x00, 0xff},
1367 {0xff, 0xff, 0x00},
1368 {0x00, 0xff, 0xff},
1369 {0x00, 0x00, 0xff}
1372 /* -------------------- Hardware specific routines ------------------------- */
1374 /* Read Attribute Controller Register=idx */
1375 inline unsigned char RAttr (volatile unsigned char *regs, short idx)
1377 wb_64 (regs, ACT_ADDRESS_W, idx);
1378 mb();
1379 udelay(100);
1380 return (rb_64(regs, ACT_ADDRESS_R));
1383 /* Read Sequencer Register=idx */
1384 inline unsigned char RSeq (volatile unsigned char *regs, short idx)
1386 wb_64 (regs, SEQ_ADDRESS, idx);
1387 mb();
1388 return (rb_64(regs, SEQ_ADDRESS_R));
1391 /* Read CRT Controller Register=idx */
1392 inline unsigned char RCrt (volatile unsigned char *regs, short idx)
1394 wb_64 (regs, CRT_ADDRESS, idx);
1395 mb();
1396 return (rb_64(regs, CRT_ADDRESS_R));
1399 /* Read Graphics Controller Register=idx */
1400 inline unsigned char RGfx (volatile unsigned char *regs, short idx)
1402 wb_64 (regs, GCT_ADDRESS, idx);
1403 mb();
1404 return (rb_64(regs, GCT_ADDRESS_R));
1408 * Special wakeup/passthrough registers on graphics boards
1411 inline void cv64_write_port (unsigned short bits,
1412 volatile unsigned char *base)
1414 volatile unsigned char *addr;
1415 static unsigned char cvportbits = 0; /* Mirror port bits here */
1416 DPRINTK("ENTER\n");
1418 addr = base + 0x40001;
1419 if (bits & 0x8000) {
1420 cvportbits |= bits & 0xff; /* Set bits */
1421 DPRINTK("Set bits: %04x\n", bits);
1422 } else {
1423 bits = bits & 0xff;
1424 bits = (~bits) & 0xff;
1425 cvportbits &= bits; /* Clear bits */
1426 DPRINTK("Clear bits: %04x\n", bits);
1429 *addr = cvportbits;
1430 DPRINTK("EXIT\n");
1434 * Monitor switch on CyberVision board
1436 * toggle:
1437 * 0 = CyberVision Signal
1438 * 1 = Amiga Signal
1439 * board = board addr
1442 inline void cvscreen (int toggle, volatile unsigned char *board)
1444 DPRINTK("ENTER\n");
1445 if (toggle == 1) {
1446 DPRINTK("Show Amiga video\n");
1447 cv64_write_port (0x10, board);
1448 } else {
1449 DPRINTK("Show CyberVision video\n");
1450 cv64_write_port (0x8010, board);
1452 DPRINTK("EXIT\n");
1455 /* Control screen display */
1456 /* toggle: 0 = on, 1 = off */
1457 /* board = registerbase */
1458 inline void gfx_on_off(int toggle, volatile unsigned char *regs)
1460 int r;
1461 DPRINTK("ENTER\n");
1463 toggle &= 0x1;
1464 toggle = toggle << 5;
1465 DPRINTK("Turn display %s\n", (toggle ? "off" : "on"));
1467 r = (int) RSeq(regs, SEQ_ID_CLOCKING_MODE);
1468 r &= 0xdf; /* Set bit 5 to 0 */
1470 WSeq (regs, SEQ_ID_CLOCKING_MODE, r | toggle);
1471 DPRINTK("EXIT\n");
1475 * Computes M, N, and R values from
1476 * given input frequency. It uses a table of
1477 * precomputed values, to keep CPU time low.
1479 * The return value consist of:
1480 * lower byte: Bits 4-0: N Divider Value
1481 * Bits 5-6: R Value for e.g. SR10 or SR12
1482 * higher byte: Bits 0-6: M divider value for e.g. SR11 or SR13
1484 static unsigned short cv64_compute_clock(unsigned long freq)
1486 static unsigned char *mnr, *save; /* M, N + R vals */
1487 unsigned long work_freq, r;
1488 unsigned short erg;
1489 long diff, d2;
1491 DPRINTK("ENTER\n");
1492 if (freq < 12500000 || freq > MAXPIXELCLOCK) {
1493 printk("CV64 driver: Illegal clock frequency %ld, using 25MHz\n",
1494 freq);
1495 freq = 25000000;
1497 DPRINTK("Freq = %ld\n", freq);
1498 mnr = clocks; /* there the vals are stored */
1499 d2 = 0x7fffffff;
1501 while (*mnr) { /* mnr vals are 0-terminated */
1502 work_freq = (0x37EE * (mnr[0] + 2)) / ((mnr[1] & 0x1F) + 2);
1504 r = (mnr[1] >> 5) & 0x03;
1505 if (r != 0) {
1506 work_freq = work_freq >> r; /* r is the freq divider */
1509 work_freq *= 0x3E8; /* 2nd part of OSC */
1511 diff = abs(freq - work_freq);
1513 if (d2 >= diff) {
1514 d2 = diff;
1515 /* In save are the vals for minimal diff */
1516 save = mnr;
1518 mnr += 2;
1520 erg = *((unsigned short *)save);
1522 DPRINTK("EXIT\n");
1523 return (erg);
1526 static int cv_has_4mb (volatile unsigned char *fb)
1528 volatile unsigned long *tr, *tw;
1529 DPRINTK("ENTER\n");
1531 /* write patterns in memory and test if they can be read */
1532 tw = (volatile unsigned long *) fb;
1533 tr = (volatile unsigned long *) (fb + 0x02000000);
1535 *tw = 0x87654321;
1537 if (*tr != 0x87654321) {
1538 DPRINTK("EXIT - <4MB\n");
1539 return (0);
1542 /* upper memory region */
1543 tw = (volatile unsigned long *) (fb + 0x00200000);
1544 tr = (volatile unsigned long *) (fb + 0x02200000);
1546 *tw = 0x87654321;
1548 if (*tr != 0x87654321) {
1549 DPRINTK("EXIT - <4MB\n");
1550 return (0);
1553 *tw = 0xAAAAAAAA;
1555 if (*tr != 0xAAAAAAAA) {
1556 DPRINTK("EXIT - <4MB\n");
1557 return (0);
1560 *tw = 0x55555555;
1562 if (*tr != 0x55555555) {
1563 DPRINTK("EXIT - <4MB\n");
1564 return (0);
1567 DPRINTK("EXIT\n");
1568 return (1);
1571 static void cv64_board_init (void)
1573 volatile unsigned char *regs = CyberRegs;
1574 int i;
1575 unsigned int clockpar;
1576 unsigned char test;
1578 DPRINTK("ENTER\n");
1581 * Special CyberVision 64 board operations
1583 /* Reset board */
1584 for (i = 0; i < 6; i++) {
1585 cv64_write_port (0xff, CyberBase);
1587 /* Return to operational mode */
1588 cv64_write_port (0x8004, CyberBase);
1591 * Generic (?) S3 chip wakeup
1593 /* Disable I/O & memory decoders, video in setup mode */
1594 wb_64 (regs, SREG_VIDEO_SUBS_ENABLE, 0x10);
1595 /* Video responds to cmds, addrs & data */
1596 wb_64 (regs, SREG_OPTION_SELECT, 0x1);
1597 /* Enable I/O & memory decoders, video in operational mode */
1598 wb_64 (regs, SREG_VIDEO_SUBS_ENABLE, 0x8);
1599 /* VGA color emulation, enable cpu access to display mem */
1600 wb_64 (regs, GREG_MISC_OUTPUT_W, 0x03);
1601 /* Unlock S3 VGA regs */
1602 WCrt (regs, CRT_ID_REGISTER_LOCK_1, 0x48);
1603 /* Unlock system control & extension registers */
1604 WCrt (regs, CRT_ID_REGISTER_LOCK_2, 0xA5);
1605 /* GRF - Enable interrupts */
1606 /* Enable enhanced regs access, Ready cntl 0 wait states */
1607 test = RCrt (regs, CRT_ID_SYSTEM_CONFIG);
1608 test = test | 0x01; /* enable enhanced register access */
1609 test = test & 0xEF; /* clear bit 4, 0 wait state */
1610 WCrt (regs, CRT_ID_SYSTEM_CONFIG, test);
1612 * bit 0=1: Enable enhaced mode functions
1613 * bit 2=0: Enhanced mode 8+ bits/pixel
1614 * bit 4=1: Enable linear addressing
1615 * bit 5=1: Enable MMIO
1617 wb_64 (regs, ECR_ADV_FUNC_CNTL, 0x31);
1619 * bit 0=1: Color emulation
1620 * bit 1=1: Enable CPU access to display memory
1621 * bit 5=1: Select high 64K memory page
1623 /* GRF - 0xE3 */
1624 wb_64 (regs, GREG_MISC_OUTPUT_W, 0x23);
1626 /* Cpu base addr */
1627 WCrt (regs, CRT_ID_EXT_SYS_CNTL_4, 0x0);
1629 /* Reset. This does nothing on Trio, but standard VGA practice */
1630 /* WSeq (CyberRegs, SEQ_ID_RESET, 0x03); */
1631 /* Character clocks 8 dots wide */
1632 WSeq (regs, SEQ_ID_CLOCKING_MODE, 0x01);
1633 /* Enable cpu write to all color planes */
1634 WSeq (regs, SEQ_ID_MAP_MASK, 0x0F);
1635 /* Font table in 1st 8k of plane 2, font A=B disables swtich */
1636 WSeq (regs, SEQ_ID_CHAR_MAP_SELECT, 0x0);
1637 /* Allow mem access to 256kb */
1638 WSeq (regs, SEQ_ID_MEMORY_MODE, 0x2);
1639 /* Unlock S3 extensions to VGA Sequencer regs */
1640 WSeq (regs, SEQ_ID_UNLOCK_EXT, 0x6);
1642 /* Enable 4MB fast page mode */
1643 test = RSeq (regs, SEQ_ID_BUS_REQ_CNTL);
1644 test = test | 1 << 6;
1645 WSeq (regs, SEQ_ID_BUS_REQ_CNTL, test);
1647 /* Faster LUT write: 1 DCLK LUT write cycle, RAMDAC clk doubled */
1648 WSeq (regs, SEQ_ID_RAMDAC_CNTL, 0xC0);
1650 /* Clear immediate clock load bit */
1651 test = RSeq (regs, SEQ_ID_CLKSYN_CNTL_2);
1652 test = test & 0xDF;
1653 /* If > 55MHz, enable 2 cycle memory write */
1654 if (cv64_memclk >= 55000000) {
1655 test |= 0x80;
1657 WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, test);
1659 /* Set MCLK value */
1660 clockpar = cv64_compute_clock (cv64_memclk);
1661 test = (clockpar & 0xFF00) >> 8;
1662 WSeq (regs, SEQ_ID_MCLK_HI, test);
1663 test = clockpar & 0xFF;
1664 WSeq (regs, SEQ_ID_MCLK_LO, test);
1666 /* Chip rev specific: Not in my Trio manual!!! */
1667 if (RCrt (regs, CRT_ID_REVISION) == 0x10)
1668 WSeq (regs, SEQ_ID_MORE_MAGIC, test);
1670 /* We now load an 25 MHz, 31kHz, 640x480 standard VGA Mode. */
1672 /* Set DCLK value */
1673 WSeq (regs, SEQ_ID_DCLK_HI, 0x13);
1674 WSeq (regs, SEQ_ID_DCLK_LO, 0x41);
1676 /* Load DCLK (and MCLK?) immediately */
1677 test = RSeq (regs, SEQ_ID_CLKSYN_CNTL_2);
1678 test = test | 0x22;
1679 WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, test);
1681 /* Enable loading of DCLK */
1682 test = rb_64(regs, GREG_MISC_OUTPUT_R);
1683 test = test | 0x0C;
1684 wb_64 (regs, GREG_MISC_OUTPUT_W, test);
1686 /* Turn off immediate xCLK load */
1687 WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, 0x2);
1689 /* Horizontal character clock counts */
1690 /* 8 LSB of 9 bits = total line - 5 */
1691 WCrt (regs, CRT_ID_HOR_TOTAL, 0x5F);
1692 /* Active display line */
1693 WCrt (regs, CRT_ID_HOR_DISP_ENA_END, 0x4F);
1694 /* Blank assertion start */
1695 WCrt (regs, CRT_ID_START_HOR_BLANK, 0x50);
1696 /* Blank assertion end */
1697 WCrt (regs, CRT_ID_END_HOR_BLANK, 0x82);
1698 /* HSYNC assertion start */
1699 WCrt (regs, CRT_ID_START_HOR_RETR, 0x54);
1700 /* HSYNC assertion end */
1701 WCrt (regs, CRT_ID_END_HOR_RETR, 0x80);
1702 WCrt (regs, CRT_ID_VER_TOTAL, 0xBF);
1703 WCrt (regs, CRT_ID_OVERFLOW, 0x1F);
1704 WCrt (regs, CRT_ID_PRESET_ROW_SCAN, 0x0);
1705 WCrt (regs, CRT_ID_MAX_SCAN_LINE, 0x40);
1706 WCrt (regs, CRT_ID_CURSOR_START, 0x00);
1707 WCrt (regs, CRT_ID_CURSOR_END, 0x00);
1708 WCrt (regs, CRT_ID_START_ADDR_HIGH, 0x00);
1709 WCrt (regs, CRT_ID_START_ADDR_LOW, 0x00);
1710 WCrt (regs, CRT_ID_CURSOR_LOC_HIGH, 0x00);
1711 WCrt (regs, CRT_ID_CURSOR_LOC_LOW, 0x00);
1712 WCrt (regs, CRT_ID_START_VER_RETR, 0x9C);
1713 WCrt (regs, CRT_ID_END_VER_RETR, 0x0E);
1714 WCrt (regs, CRT_ID_VER_DISP_ENA_END, 0x8F);
1715 WCrt (regs, CRT_ID_SCREEN_OFFSET, 0x50);
1716 WCrt (regs, CRT_ID_UNDERLINE_LOC, 0x00);
1717 WCrt (regs, CRT_ID_START_VER_BLANK, 0x96);
1718 WCrt (regs, CRT_ID_END_VER_BLANK, 0xB9);
1719 WCrt (regs, CRT_ID_MODE_CONTROL, 0xE3);
1720 WCrt (regs, CRT_ID_LINE_COMPARE, 0xFF);
1721 WCrt (regs, CRT_ID_BACKWAD_COMP_3, 0x10); /* FIFO enabled */
1722 WCrt (regs, CRT_ID_MISC_1, 0x35);
1723 WCrt (regs, CRT_ID_DISPLAY_FIFO, 0x5A);
1724 WCrt (regs, CRT_ID_EXT_MEM_CNTL_2, 0x70);
1725 WCrt (regs, CRT_ID_LAW_POS_LO, 0x40);
1726 WCrt (regs, CRT_ID_EXT_MEM_CNTL_3, 0xFF);
1728 WGfx (regs, GCT_ID_SET_RESET, 0x0);
1729 WGfx (regs, GCT_ID_ENABLE_SET_RESET, 0x0);
1730 WGfx (regs, GCT_ID_COLOR_COMPARE, 0x0);
1731 WGfx (regs, GCT_ID_DATA_ROTATE, 0x0);
1732 WGfx (regs, GCT_ID_READ_MAP_SELECT, 0x0);
1733 WGfx (regs, GCT_ID_GRAPHICS_MODE, 0x40);
1734 WGfx (regs, GCT_ID_MISC, 0x01);
1735 WGfx (regs, GCT_ID_COLOR_XCARE, 0x0F);
1736 WGfx (regs, GCT_ID_BITMASK, 0xFF);
1738 /* Colors for text mode */
1739 for (i = 0; i < 0xf; i++)
1740 WAttr (regs, i, i);
1742 WAttr (regs, ACT_ID_ATTR_MODE_CNTL, 0x41);
1743 WAttr (regs, ACT_ID_OVERSCAN_COLOR, 0x01);
1744 WAttr (regs, ACT_ID_COLOR_PLANE_ENA, 0x0F);
1745 WAttr (regs, ACT_ID_HOR_PEL_PANNING, 0x0);
1746 WAttr (regs, ACT_ID_COLOR_SELECT, 0x0);
1748 wb_64 (regs, VDAC_MASK, 0xFF);
1750 *((unsigned long *) (regs + ECR_FRGD_COLOR)) = 0xFF;
1751 *((unsigned long *) (regs + ECR_BKGD_COLOR)) = 0;
1753 /* Colors initially set to grayscale */
1755 wb_64 (regs, VDAC_ADDRESS_W, 0);
1756 for (i = 255; i >= 0; i--) {
1757 wb_64(regs, VDAC_DATA, i);
1758 wb_64(regs, VDAC_DATA, i);
1759 wb_64(regs, VDAC_DATA, i);
1762 /* GFx hardware cursor off */
1763 WCrt (regs, CRT_ID_HWGC_MODE, 0x00);
1765 /* Set first to 4MB, so test will work */
1766 WCrt (regs, CRT_ID_LAW_CNTL, 0x13);
1767 /* Find "correct" size of fbmem of Z3 board */
1768 if (cv_has_4mb (CyberMem)) {
1769 CyberSize = 1024 * 1024 * 4;
1770 WCrt (regs, CRT_ID_LAW_CNTL, 0x13);
1771 DPRINTK("4MB board\n");
1772 } else {
1773 CyberSize = 1024 * 1024 * 2;
1774 WCrt (regs, CRT_ID_LAW_CNTL, 0x12);
1775 DPRINTK("2MB board\n");
1778 /* Initialize graphics engine */
1779 Cyber_WaitBlit();
1780 vgaw16 (regs, ECR_FRGD_MIX, 0x27);
1781 vgaw16 (regs, ECR_BKGD_MIX, 0x07);
1782 vgaw16 (regs, ECR_READ_REG_DATA, 0x1000);
1783 udelay(200);
1784 vgaw16 (regs, ECR_READ_REG_DATA, 0x2000);
1785 Cyber_WaitBlit();
1786 vgaw16 (regs, ECR_READ_REG_DATA, 0x3FFF);
1787 Cyber_WaitBlit();
1788 udelay(200);
1789 vgaw16 (regs, ECR_READ_REG_DATA, 0x4FFF);
1790 Cyber_WaitBlit();
1791 vgaw16 (regs, ECR_BITPLANE_WRITE_MASK, ~0);
1792 Cyber_WaitBlit();
1793 vgaw16 (regs, ECR_READ_REG_DATA, 0xE000);
1794 vgaw16 (regs, ECR_CURRENT_Y_POS2, 0x00);
1795 vgaw16 (regs, ECR_CURRENT_X_POS2, 0x00);
1796 vgaw16 (regs, ECR_READ_REG_DATA, 0xA000);
1797 vgaw16 (regs, ECR_DEST_Y__AX_STEP, 0x00);
1798 vgaw16 (regs, ECR_DEST_Y2__AX_STEP2, 0x00);
1799 vgaw16 (regs, ECR_DEST_X__DIA_STEP, 0x00);
1800 vgaw16 (regs, ECR_DEST_X2__DIA_STEP2, 0x00);
1801 vgaw16 (regs, ECR_SHORT_STROKE, 0x00);
1802 vgaw16 (regs, ECR_DRAW_CMD, 0x01);
1804 Cyber_WaitBlit();
1806 vgaw16 (regs, ECR_READ_REG_DATA, 0x4FFF);
1807 vgaw16 (regs, ECR_BKGD_COLOR, 0x01);
1808 vgaw16 (regs, ECR_FRGD_COLOR, 0x00);
1811 /* Enable video display (set bit 5) */
1812 /* ARB - Would also seem to write to AR13.
1813 * May want to use parts of WAttr to set JUST bit 5
1815 WAttr (regs, 0x33, 0);
1817 /* GRF - function code ended here */
1819 /* Turn gfx on again */
1820 gfx_on_off (0, regs);
1822 /* Pass-through */
1823 cvscreen (0, CyberBase);
1825 DPRINTK("EXIT\n");
1828 static void cv64_load_video_mode (struct fb_var_screeninfo *video_mode)
1830 volatile unsigned char *regs = CyberRegs;
1831 int fx, fy;
1832 unsigned short mnr;
1833 unsigned short HT, HDE, HBS, HBE, HSS, HSE, VDE, VBS, VBE, VSS, VSE, VT;
1834 char LACE, DBLSCAN, TEXT, CONSOLE;
1835 int cr50, sr15, sr18, clock_mode, test;
1836 int m, n;
1837 int tfillm, temptym;
1838 int hmul;
1840 /* ---------------- */
1841 int xres, hfront, hsync, hback;
1842 int yres, vfront, vsync, vback;
1843 int bpp;
1844 #if 0
1845 float freq_f;
1846 #endif
1847 long freq;
1848 /* ---------------- */
1850 DPRINTK("ENTER\n");
1851 TEXT = 0; /* if depth == 4 */
1852 CONSOLE = 0; /* mode num == 255 (console) */
1853 fx = fy = 8; /* force 8x8 font */
1855 /* GRF - Disable interrupts */
1857 gfx_on_off (1, regs);
1859 switch (video_mode->bits_per_pixel) {
1860 case 15:
1861 case 16:
1862 hmul = 2;
1863 break;
1865 default:
1866 hmul = 1;
1867 break;
1870 bpp = video_mode->bits_per_pixel;
1871 xres = video_mode->xres;
1872 hfront = video_mode->right_margin;
1873 hsync = video_mode->hsync_len;
1874 hback = video_mode->left_margin;
1876 LACE = 0;
1877 DBLSCAN = 0;
1879 if (video_mode->vmode & FB_VMODE_DOUBLE) {
1880 yres = video_mode->yres * 2;
1881 vfront = video_mode->lower_margin * 2;
1882 vsync = video_mode->vsync_len * 2;
1883 vback = video_mode->upper_margin * 2;
1884 DBLSCAN = 1;
1885 } else if (video_mode->vmode & FB_VMODE_INTERLACED) {
1886 yres = (video_mode->yres + 1) / 2;
1887 vfront = (video_mode->lower_margin + 1) / 2;
1888 vsync = (video_mode->vsync_len + 1) / 2;
1889 vback = (video_mode->upper_margin + 1) / 2;
1890 LACE = 1;
1891 } else {
1892 yres = video_mode->yres;
1893 vfront = video_mode->lower_margin;
1894 vsync = video_mode->vsync_len;
1895 vback = video_mode->upper_margin;
1898 /* ARB Dropping custom setup method from cvision.c */
1899 #if 0
1900 if (cvision_custom_mode) {
1901 HBS = hbs / 8 * hmul;
1902 HBE = hbe / 8 * hmul;
1903 HSS = hss / 8 * hmul;
1904 HSE = hse / 8 * hmul;
1905 HT = ht / 8 * hmul - 5;
1907 VBS = vbs - 1;
1908 VSS = vss;
1909 VSE = vse;
1910 VBE = vbe;
1911 VT = vt - 2;
1912 } else {
1913 #else
1915 #endif
1916 HBS = hmul * (xres / 8);
1917 HBE = hmul * ((xres/8) + (hfront/8) + (hsync/8) + (hback/8) - 2);
1918 HSS = hmul * ((xres/8) + (hfront/8) + 2);
1919 HSE = hmul * ((xres/8) + (hfront/8) + (hsync/8) + 1);
1920 HT = hmul * ((xres/8) + (hfront/8) + (hsync/8) + (hback/8));
1922 VBS = yres;
1923 VBE = yres + vfront + vsync + vback - 2;
1924 VSS = yres + vfront - 1;
1925 VSE = yres + vfront + vsync - 1;
1926 VT = yres + vfront + vsync + vback - 2;
1929 wb_64 (regs, ECR_ADV_FUNC_CNTL, (TEXT ? 0x00 : 0x31));
1931 if (TEXT)
1932 HDE = ((video_mode->xres + fx - 1) / fx) - 1;
1933 else
1934 HDE = (video_mode->xres + 3) * hmul / 8 - 1;
1936 VDE = video_mode->yres - 1;
1938 WCrt (regs, CRT_ID_HWGC_MODE, 0x00);
1939 WCrt (regs, CRT_ID_EXT_DAC_CNTL, 0x00);
1941 WSeq (regs, SEQ_ID_MEMORY_MODE,
1942 (TEXT || (video_mode->bits_per_pixel == 1)) ? 0x06 : 0x0e);
1943 WGfx (regs, GCT_ID_READ_MAP_SELECT, 0x00);
1944 WSeq (regs, SEQ_ID_MAP_MASK,
1945 (video_mode->bits_per_pixel == 1) ? 0x01 : 0xFF);
1946 WSeq (regs, SEQ_ID_CHAR_MAP_SELECT, 0x00);
1948 /* cv64_compute_clock accepts arguments in Hz */
1949 /* pixclock is in ps ... convert to Hz */
1951 #if 0
1952 freq_f = (1.0 / (float) video_mode->pixclock) * 1000000000;
1953 freq = ((long) freq_f) * 1000;
1954 #else
1955 /* freq = (long) ((long long)1000000000000 / (long long) video_mode->pixclock);
1957 freq = (1000000000 / video_mode->pixclock) * 1000;
1958 #endif
1960 mnr = cv64_compute_clock (freq);
1961 WSeq (regs, SEQ_ID_DCLK_HI, ((mnr & 0xFF00) >> 8));
1962 WSeq (regs, SEQ_ID_DCLK_LO, (mnr & 0xFF));
1964 /* Load display parameters into board */
1965 WCrt (regs, CRT_ID_EXT_HOR_OVF,
1966 ((HT & 0x100) ? 0x01 : 0x00) |
1967 ((HDE & 0x100) ? 0x02 : 0x00) |
1968 ((HBS & 0x100) ? 0x04 : 0x00) |
1969 /* ((HBE & 0x40) ? 0x08 : 0x00) | */
1970 ((HSS & 0x100) ? 0x10 : 0x00) |
1971 /* ((HSE & 0x20) ? 0x20 : 0x00) | */
1972 (((HT-5) & 0x100) ? 0x40 : 0x00)
1975 WCrt (regs, CRT_ID_EXT_VER_OVF,
1976 0x40 |
1977 ((VT & 0x400) ? 0x01 : 0x00) |
1978 ((VDE & 0x400) ? 0x02 : 0x00) |
1979 ((VBS & 0x400) ? 0x04 : 0x00) |
1980 ((VSS & 0x400) ? 0x10 : 0x00)
1983 WCrt (regs, CRT_ID_HOR_TOTAL, HT);
1984 WCrt (regs, CRT_ID_DISPLAY_FIFO, HT - 5);
1985 WCrt (regs, CRT_ID_HOR_DISP_ENA_END, ((HDE >= HBS) ? (HBS - 1) : HDE));
1986 WCrt (regs, CRT_ID_START_HOR_BLANK, HBS);
1987 WCrt (regs, CRT_ID_END_HOR_BLANK, ((HBE & 0x1F) | 0x80));
1988 WCrt (regs, CRT_ID_START_HOR_RETR, HSS);
1989 WCrt (regs, CRT_ID_END_HOR_RETR,
1990 (HSE & 0x1F) |
1991 ((HBE & 0x20) ? 0x80 : 0x00)
1993 WCrt (regs, CRT_ID_VER_TOTAL, VT);
1994 WCrt (regs, CRT_ID_OVERFLOW,
1995 0x10 |
1996 ((VT & 0x100) ? 0x01 : 0x00) |
1997 ((VDE & 0x100) ? 0x02 : 0x00) |
1998 ((VSS & 0x100) ? 0x04 : 0x00) |
1999 ((VBS & 0x100) ? 0x08 : 0x00) |
2000 ((VT & 0x200) ? 0x20 : 0x00) |
2001 ((VDE & 0x200) ? 0x40 : 0x00) |
2002 ((VSS & 0x200) ? 0x80 : 0x00)
2004 WCrt (regs, CRT_ID_MAX_SCAN_LINE,
2005 0x40 |
2006 (DBLSCAN ? 0x80 : 0x00) |
2007 ((VBS & 0x200) ? 0x20 : 0x00) |
2008 (TEXT ? ((fy - 1) & 0x1F) : 0x00)
2011 WCrt (regs, CRT_ID_MODE_CONTROL, 0xE3);
2013 /* Text cursor */
2015 if (TEXT) {
2016 #if 1
2017 WCrt (regs, CRT_ID_CURSOR_START, (fy & 0x1f) - 2);
2018 WCrt (regs, CRT_ID_CURSOR_END, (fy & 0x1F) - 1);
2019 #else
2020 WCrt (regs, CRT_ID_CURSOR_START, 0x00);
2021 WCrt (regs, CRT_ID_CURSOR_END, fy & 0x1F);
2022 #endif
2023 WCrt (regs, CRT_ID_UNDERLINE_LOC, (fy - 1) & 0x1F);
2024 WCrt (regs, CRT_ID_CURSOR_LOC_HIGH, 0x00);
2025 WCrt (regs, CRT_ID_CURSOR_LOC_LOW, 0x00);
2028 WCrt (regs, CRT_ID_START_ADDR_HIGH, 0x00);
2029 WCrt (regs, CRT_ID_START_ADDR_LOW, 0x00);
2030 WCrt (regs, CRT_ID_START_VER_RETR, VSS);
2031 WCrt (regs, CRT_ID_END_VER_RETR, (VSE & 0x0F));
2032 WCrt (regs, CRT_ID_VER_DISP_ENA_END, VDE);
2033 WCrt (regs, CRT_ID_START_VER_BLANK, VBS);
2034 WCrt (regs, CRT_ID_END_VER_BLANK, VBE);
2035 WCrt (regs, CRT_ID_LINE_COMPARE, 0xFF);
2036 WCrt (regs, CRT_ID_LACE_RETR_START, HT / 2);
2037 WCrt (regs, CRT_ID_LACE_CONTROL, (LACE ? 0x20 : 0x00));
2038 WGfx (regs, GCT_ID_GRAPHICS_MODE,
2039 ((TEXT || (video_mode->bits_per_pixel == 1)) ? 0x00 : 0x40));
2040 WGfx (regs, GCT_ID_MISC, (TEXT ? 0x04 : 0x01));
2041 WSeq (regs, SEQ_ID_MEMORY_MODE,
2042 ((TEXT || (video_mode->bits_per_pixel == 1)) ? 0x06 : 0x02));
2044 wb_64 (regs, VDAC_MASK, 0xFF);
2046 /* Blank border */
2047 test = RCrt (regs, CRT_ID_BACKWAD_COMP_2);
2048 WCrt (regs, CRT_ID_BACKWAD_COMP_2, (test | 0x20));
2050 sr15 = RSeq (regs, SEQ_ID_CLKSYN_CNTL_2);
2051 sr15 &= 0xEF;
2052 sr18 = RSeq (regs, SEQ_ID_RAMDAC_CNTL);
2053 sr18 &= 0x7F;
2054 clock_mode = 0x00;
2055 cr50 = 0x00;
2057 test = RCrt (regs, CRT_ID_EXT_MISC_CNTL_2);
2058 test &= 0xD;
2060 /* Clear roxxler byte-swapping... */
2061 cv64_write_port (0x0040, CyberBase);
2062 cv64_write_port (0x0020, CyberBase);
2064 switch (video_mode->bits_per_pixel) {
2065 case 1:
2066 case 4: /* text */
2067 HDE = video_mode->xres / 16;
2068 break;
2070 case 8:
2071 if (freq > 80000000) {
2072 clock_mode = 0x10 | 0x02;
2073 sr15 |= 0x10;
2074 sr18 |= 0x80;
2076 HDE = video_mode->xres / 8;
2077 cr50 |= 0x00;
2078 break;
2080 case 15:
2081 cv64_write_port (0x8020, CyberBase);
2082 clock_mode = 0x30;
2083 HDE = video_mode->xres / 4;
2084 cr50 |= 0x10;
2085 break;
2087 case 16:
2088 cv64_write_port (0x8020, CyberBase);
2089 clock_mode = 0x50;
2090 HDE = video_mode->xres / 4;
2091 cr50 |= 0x10;
2092 break;
2094 case 24:
2095 case 32:
2096 cv64_write_port (0x8040, CyberBase);
2097 clock_mode = 0xD0;
2098 HDE = video_mode->xres / 2;
2099 cr50 |= 0x30;
2100 break;
2103 WCrt (regs, CRT_ID_EXT_MISC_CNTL_2, clock_mode | test);
2104 WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, sr15);
2105 WSeq (regs, SEQ_ID_RAMDAC_CNTL, sr18);
2106 WCrt (regs, CRT_ID_SCREEN_OFFSET, HDE);
2108 WCrt (regs, CRT_ID_MISC_1, (TEXT ? 0x05 : 0x35));
2110 test = RCrt (regs, CRT_ID_EXT_SYS_CNTL_2);
2111 test &= ~0x30;
2112 test |= (HDE >> 4) & 0x30;
2113 WCrt (regs, CRT_ID_EXT_SYS_CNTL_2, test);
2115 /* Set up graphics engine */
2116 switch (video_mode->xres) {
2117 case 1024:
2118 cr50 |= 0x00;
2119 break;
2121 case 640:
2122 cr50 |= 0x40;
2123 break;
2125 case 800:
2126 cr50 |= 0x80;
2127 break;
2129 case 1280:
2130 cr50 |= 0xC0;
2131 break;
2133 case 1152:
2134 cr50 |= 0x01;
2135 break;
2137 case 1600:
2138 cr50 |= 0x81;
2139 break;
2141 default: /* XXX */
2142 break;
2145 WCrt (regs, CRT_ID_EXT_SYS_CNTL_1, cr50);
2147 udelay(100);
2148 WAttr (regs, ACT_ID_ATTR_MODE_CNTL, (TEXT ? 0x08 : 0x41));
2149 udelay(100);
2150 WAttr (regs, ACT_ID_COLOR_PLANE_ENA,
2151 (video_mode->bits_per_pixel == 1) ? 0x01 : 0x0F);
2152 udelay(100);
2154 tfillm = (96 * (cv64_memclk / 1000)) / 240000;
2156 switch (video_mode->bits_per_pixel) {
2157 case 32:
2158 case 24:
2159 temptym = (24 * (cv64_memclk / 1000)) / (freq / 1000);
2160 break;
2161 case 15:
2162 case 16:
2163 temptym = (48 * (cv64_memclk / 1000)) / (freq / 1000);
2164 break;
2165 case 4:
2166 temptym = (192 * (cv64_memclk / 1000)) / (freq / 1000);
2167 break;
2168 default:
2169 temptym = (96 * (cv64_memclk / 1000)) / (freq / 1000);
2170 break;
2173 m = (temptym - tfillm - 9) / 2;
2174 if (m < 0)
2175 m = 0;
2176 m = (m & 0x1F) << 3;
2177 if (m < 0x18)
2178 m = 0x18;
2179 n = 0xFF;
2181 WCrt (regs, CRT_ID_EXT_MEM_CNTL_2, m);
2182 WCrt (regs, CRT_ID_EXT_MEM_CNTL_3, n);
2183 udelay(10);
2185 /* Text initialization */
2187 if (TEXT) {
2188 /* Do text initialization here ! */
2191 if (CONSOLE) {
2192 int i;
2193 wb_64 (regs, VDAC_ADDRESS_W, 0);
2194 for (i = 0; i < 4; i++) {
2195 wb_64 (regs, VDAC_DATA, cvconscolors [i][0]);
2196 wb_64 (regs, VDAC_DATA, cvconscolors [i][1]);
2197 wb_64 (regs, VDAC_DATA, cvconscolors [i][2]);
2201 WAttr (regs, 0x33, 0);
2203 /* Turn gfx on again */
2204 gfx_on_off (0, (volatile unsigned char *) regs);
2206 /* Pass-through */
2207 cvscreen (0, CyberBase);
2209 DPRINTK("EXIT\n");
2212 void cvision_bitblt (u_short sx, u_short sy, u_short dx, u_short dy,
2213 u_short w, u_short h)
2215 volatile unsigned char *regs = CyberRegs;
2216 unsigned short drawdir = 0;
2218 DPRINTK("ENTER\n");
2219 if (sx > dx) {
2220 drawdir |= 1 << 5;
2221 } else {
2222 sx += w - 1;
2223 dx += w - 1;
2226 if (sy > dy) {
2227 drawdir |= 1 << 7;
2228 } else {
2229 sy += h - 1;
2230 dy += h - 1;
2233 Cyber_WaitBlit();
2234 vgaw16 (regs, ECR_READ_REG_DATA, 0xA000);
2235 vgaw16 (regs, ECR_BKGD_MIX, 0x7);
2236 vgaw16 (regs, ECR_FRGD_MIX, 0x67);
2237 vgaw16 (regs, ECR_BKGD_COLOR, 0x0);
2238 vgaw16 (regs, ECR_FRGD_COLOR, 0x1);
2239 vgaw16 (regs, ECR_BITPLANE_READ_MASK, 0x1);
2240 vgaw16 (regs, ECR_BITPLANE_WRITE_MASK, 0xFFF);
2241 vgaw16 (regs, ECR_CURRENT_Y_POS, sy);
2242 vgaw16 (regs, ECR_CURRENT_X_POS, sx);
2243 vgaw16 (regs, ECR_DEST_Y__AX_STEP, dy);
2244 vgaw16 (regs, ECR_DEST_X__DIA_STEP, dx);
2245 vgaw16 (regs, ECR_READ_REG_DATA, h - 1);
2246 vgaw16 (regs, ECR_MAJ_AXIS_PIX_CNT, w - 1);
2247 vgaw16 (regs, ECR_DRAW_CMD, 0xC051 | drawdir);
2248 DPRINTK("EXIT\n");
2251 void cvision_clear (u_short dx, u_short dy, u_short w, u_short h, u_short bg)
2253 volatile unsigned char *regs = CyberRegs;
2254 DPRINTK("ENTER\n");
2255 Cyber_WaitBlit();
2256 vgaw16 (regs, ECR_FRGD_MIX, 0x0027);
2257 vgaw16 (regs, ECR_FRGD_COLOR, bg);
2258 vgaw16 (regs, ECR_READ_REG_DATA, 0xA000);
2259 vgaw16 (regs, ECR_CURRENT_Y_POS, dy);
2260 vgaw16 (regs, ECR_CURRENT_X_POS, dx);
2261 vgaw16 (regs, ECR_READ_REG_DATA, h - 1);
2262 vgaw16 (regs, ECR_MAJ_AXIS_PIX_CNT, w - 1);
2263 vgaw16 (regs, ECR_DRAW_CMD, 0x40B1);
2264 DPRINTK("EXIT\n");
2267 #ifdef CYBERFBDEBUG
2269 * Dump internal settings of CyberVision board
2271 static void cv64_dump (void)
2273 volatile unsigned char *regs = CyberRegs;
2274 DPRINTK("ENTER\n");
2275 /* Dump the VGA setup values */
2276 *(regs + S3_CRTC_ADR) = 0x00;
2277 DPRINTK("CR00 = %x\n", *(regs + S3_CRTC_DATA));
2278 *(regs + S3_CRTC_ADR) = 0x01;
2279 DPRINTK("CR01 = %x\n", *(regs + S3_CRTC_DATA));
2280 *(regs + S3_CRTC_ADR) = 0x02;
2281 DPRINTK("CR02 = %x\n", *(regs + S3_CRTC_DATA));
2282 *(regs + S3_CRTC_ADR) = 0x03;
2283 DPRINTK("CR03 = %x\n", *(regs + S3_CRTC_DATA));
2284 *(regs + S3_CRTC_ADR) = 0x04;
2285 DPRINTK("CR04 = %x\n", *(regs + S3_CRTC_DATA));
2286 *(regs + S3_CRTC_ADR) = 0x05;
2287 DPRINTK("CR05 = %x\n", *(regs + S3_CRTC_DATA));
2288 *(regs + S3_CRTC_ADR) = 0x06;
2289 DPRINTK("CR06 = %x\n", *(regs + S3_CRTC_DATA));
2290 *(regs + S3_CRTC_ADR) = 0x07;
2291 DPRINTK("CR07 = %x\n", *(regs + S3_CRTC_DATA));
2292 *(regs + S3_CRTC_ADR) = 0x08;
2293 DPRINTK("CR08 = %x\n", *(regs + S3_CRTC_DATA));
2294 *(regs + S3_CRTC_ADR) = 0x09;
2295 DPRINTK("CR09 = %x\n", *(regs + S3_CRTC_DATA));
2296 *(regs + S3_CRTC_ADR) = 0x10;
2297 DPRINTK("CR10 = %x\n", *(regs + S3_CRTC_DATA));
2298 *(regs + S3_CRTC_ADR) = 0x11;
2299 DPRINTK("CR11 = %x\n", *(regs + S3_CRTC_DATA));
2300 *(regs + S3_CRTC_ADR) = 0x12;
2301 DPRINTK("CR12 = %x\n", *(regs + S3_CRTC_DATA));
2302 *(regs + S3_CRTC_ADR) = 0x13;
2303 DPRINTK("CR13 = %x\n", *(regs + S3_CRTC_DATA));
2304 *(regs + S3_CRTC_ADR) = 0x15;
2305 DPRINTK("CR15 = %x\n", *(regs + S3_CRTC_DATA));
2306 *(regs + S3_CRTC_ADR) = 0x16;
2307 DPRINTK("CR16 = %x\n", *(regs + S3_CRTC_DATA));
2308 *(regs + S3_CRTC_ADR) = 0x36;
2309 DPRINTK("CR36 = %x\n", *(regs + S3_CRTC_DATA));
2310 *(regs + S3_CRTC_ADR) = 0x37;
2311 DPRINTK("CR37 = %x\n", *(regs + S3_CRTC_DATA));
2312 *(regs + S3_CRTC_ADR) = 0x42;
2313 DPRINTK("CR42 = %x\n", *(regs + S3_CRTC_DATA));
2314 *(regs + S3_CRTC_ADR) = 0x43;
2315 DPRINTK("CR43 = %x\n", *(regs + S3_CRTC_DATA));
2316 *(regs + S3_CRTC_ADR) = 0x50;
2317 DPRINTK("CR50 = %x\n", *(regs + S3_CRTC_DATA));
2318 *(regs + S3_CRTC_ADR) = 0x51;
2319 DPRINTK("CR51 = %x\n", *(regs + S3_CRTC_DATA));
2320 *(regs + S3_CRTC_ADR) = 0x53;
2321 DPRINTK("CR53 = %x\n", *(regs + S3_CRTC_DATA));
2322 *(regs + S3_CRTC_ADR) = 0x58;
2323 DPRINTK("CR58 = %x\n", *(regs + S3_CRTC_DATA));
2324 *(regs + S3_CRTC_ADR) = 0x59;
2325 DPRINTK("CR59 = %x\n", *(regs + S3_CRTC_DATA));
2326 *(regs + S3_CRTC_ADR) = 0x5A;
2327 DPRINTK("CR5A = %x\n", *(regs + S3_CRTC_DATA));
2328 *(regs + S3_CRTC_ADR) = 0x5D;
2329 DPRINTK("CR5D = %x\n", *(regs + S3_CRTC_DATA));
2330 *(regs + S3_CRTC_ADR) = 0x5E;
2331 DPRINTK("CR5E = %x\n", *(regs + S3_CRTC_DATA));
2332 DPRINTK("MISC = %x\n", *(regs + GREG_MISC_OUTPUT_R));
2333 *(regs + SEQ_ADDRESS) = 0x01;
2334 DPRINTK("SR01 = %x\n", *(regs + SEQ_ADDRESS_R));
2335 *(regs + SEQ_ADDRESS) = 0x02;
2336 DPRINTK("SR02 = %x\n", *(regs + SEQ_ADDRESS_R));
2337 *(regs + SEQ_ADDRESS) = 0x03;
2338 DPRINTK("SR03 = %x\n", *(regs + SEQ_ADDRESS_R));
2339 *(regs + SEQ_ADDRESS) = 0x09;
2340 DPRINTK("SR09 = %x\n", *(regs + SEQ_ADDRESS_R));
2341 *(regs + SEQ_ADDRESS) = 0x10;
2342 DPRINTK("SR10 = %x\n", *(regs + SEQ_ADDRESS_R));
2343 *(regs + SEQ_ADDRESS) = 0x11;
2344 DPRINTK("SR11 = %x\n", *(regs + SEQ_ADDRESS_R));
2345 *(regs + SEQ_ADDRESS) = 0x12;
2346 DPRINTK("SR12 = %x\n", *(regs + SEQ_ADDRESS_R));
2347 *(regs + SEQ_ADDRESS) = 0x13;
2348 DPRINTK("SR13 = %x\n", *(regs + SEQ_ADDRESS_R));
2349 *(regs + SEQ_ADDRESS) = 0x15;
2350 DPRINTK("SR15 = %x\n", *(regs + SEQ_ADDRESS_R));
2352 return;
2354 #endif