Import 2.3.18pre1
[davej-history.git] / drivers / video / cyberfb.c
blob7e4aea83f3db5c94b629ed98db3dabb3b0c7d5a6
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 arraysize(x) (sizeof(x)/sizeof(*(x)))
112 #define wb_64(regs,reg,dat) (*(((volatile unsigned char *)regs) + reg) = dat)
113 #define rb_64(regs, reg) (*(((volatile unsigned char *)regs) + reg))
115 #define ww_64(regs,reg,dat) (*((volatile unsigned short *)(regs + reg) = dat)
117 struct cyberfb_par {
118 struct fb_var_screeninfo var;
119 __u32 type;
120 __u32 type_aux;
121 __u32 visual;
122 __u32 line_length;
125 static struct cyberfb_par current_par;
127 static int current_par_valid = 0;
128 static int currcon = 0;
130 static struct display disp;
131 static struct fb_info fb_info;
135 * Frame Buffer Name
138 static char cyberfb_name[16] = "Cybervision";
142 * CyberVision Graphics Board
145 static unsigned char Cyber_colour_table [256][3];
146 static unsigned long CyberSize;
147 static volatile unsigned char *CyberBase;
148 static volatile unsigned char *CyberMem;
149 static volatile unsigned char *CyberRegs;
150 static unsigned long CyberMem_phys;
151 static unsigned long CyberRegs_phys;
154 * Predefined Video Modes
157 static struct {
158 const char *name;
159 struct fb_var_screeninfo var;
160 } cyberfb_predefined[] __initdata = {
161 { "640x480-8", { /* Default 8 BPP mode (cyber8) */
162 640, 480, 640, 480, 0, 0, 8, 0,
163 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
164 0, 0, -1, -1, FB_ACCELF_TEXT, 39722, 40, 24, 32, 11, 96, 2,
165 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
166 FB_VMODE_NONINTERLACED
167 }},
168 { "640x480-16", { /* Default 16 BPP mode (cyber16) */
169 640, 480, 640, 480, 0, 0, 16, 0,
170 {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
171 0, 0, -1, -1, FB_ACCELF_TEXT, 39722, 40, 24, 32, 11, 96, 2,
172 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
173 FB_VMODE_NONINTERLACED
174 }},
175 { "640x480-24", { /* Default 24 BPP mode */
176 640, 480, 640, 480, 0, 0, 24, 0,
177 {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0},
178 0, 0, -1, -1, FB_ACCELF_TEXT, 39722, 40, 24, 32, 11, 96, 2,
179 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
180 FB_VMODE_NONINTERLACED
181 }},
182 { "800x490-8", { /* Cybervision 8 bpp */
183 /* NO Acceleration */
184 800, 490, 800, 490, 0, 0, 8, 0,
185 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
186 0, 0, -1, -1, FB_ACCEL_NONE, 33333, 80, 24, 23, 1, 56, 8,
187 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
188 FB_VMODE_NONINTERLACED
190 /* I can't test these with my monitor, but I suspect they will
191 * be OK, since Antonio Santos indicated he had tested them in
192 * his system.
194 { "800x600-8", { /* Cybervision 8 bpp */
195 800, 600, 800, 600, 0, 0, 8, 0,
196 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
197 0, 0, -1, -1, FB_ACCELF_TEXT, 27778, 64, 24, 22, 1, 72, 2,
198 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
199 FB_VMODE_NONINTERLACED
201 { "1024x768-8", { /* Cybervision 8 bpp */
202 1024, 768, 1024, 768, 0, 0, 8, 0,
203 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
204 0, 0, -1, -1, FB_ACCELF_TEXT, 16667, 224, 72, 60, 12, 168, 4,
205 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
206 FB_VMODE_NONINTERLACED
208 { "1152x886-8", { /* Cybervision 8 bpp */
209 1152, 886, 1152, 886, 0, 0, 8, 0,
210 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
211 0, 0, -1, -1, FB_ACCELF_TEXT, 15873, 184, 40, 24, 1, 56, 16,
212 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
213 FB_VMODE_NONINTERLACED
215 { "1280x1024-8", { /* Cybervision 8 bpp */
216 1280, 1024, 1280, 1024, 0, 0, 8, 0,
217 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
218 0, 0, -1, -1, FB_ACCELF_TEXT, 16667, 256, 48, 50, 12, 72, 4,
219 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
220 FB_VMODE_INTERLACED
224 #define NUM_TOTAL_MODES arraysize(cyberfb_predefined)
226 static int Cyberfb_inverse = 0;
229 * Some default modes
232 #define CYBER8_DEFMODE (0)
233 #define CYBER16_DEFMODE (1)
235 static struct fb_var_screeninfo cyberfb_default;
236 static int cyberfb_usermode __initdata = 0;
239 * Interface used by the world
242 int cyberfb_setup(char *options);
244 static int cyberfb_open(struct fb_info *info, int user);
245 static int cyberfb_release(struct fb_info *info, int user);
246 static int cyberfb_get_fix(struct fb_fix_screeninfo *fix, int con,
247 struct fb_info *info);
248 static int cyberfb_get_var(struct fb_var_screeninfo *var, int con,
249 struct fb_info *info);
250 static int cyberfb_set_var(struct fb_var_screeninfo *var, int con,
251 struct fb_info *info);
252 static int cyberfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
253 struct fb_info *info);
254 static int cyberfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
255 struct fb_info *info);
256 static int cyberfb_pan_display(struct fb_var_screeninfo *var, int con,
257 struct fb_info *info);
258 static int cyberfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
259 u_long arg, int con, struct fb_info *info);
262 * Interface to the low level console driver
265 int cyberfb_init(void);
266 static int Cyberfb_switch(int con, struct fb_info *info);
267 static int Cyberfb_updatevar(int con, struct fb_info *info);
268 static void Cyberfb_blank(int blank, struct fb_info *info);
271 * Text console acceleration
274 #ifdef FBCON_HAS_CFB8
275 static struct display_switch fbcon_cyber8;
276 #endif
279 * Accelerated Functions used by the low level console driver
282 static void Cyber_WaitQueue(u_short fifo);
283 static void Cyber_WaitBlit(void);
284 static void Cyber_BitBLT(u_short curx, u_short cury, u_short destx,
285 u_short desty, u_short width, u_short height,
286 u_short mode);
287 static void Cyber_RectFill(u_short x, u_short y, u_short width, u_short height,
288 u_short mode, u_short color);
289 #if 0
290 static void Cyber_MoveCursor(u_short x, u_short y);
291 #endif
294 * Hardware Specific Routines
297 static int Cyber_init(void);
298 static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
299 struct cyberfb_par *par);
300 static int Cyber_decode_var(struct fb_var_screeninfo *var,
301 struct cyberfb_par *par);
302 static int Cyber_encode_var(struct fb_var_screeninfo *var,
303 struct cyberfb_par *par);
304 static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
305 u_int *transp, struct fb_info *info);
306 static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
307 u_int transp, struct fb_info *info);
310 * Internal routines
313 static void cyberfb_get_par(struct cyberfb_par *par);
314 static void cyberfb_set_par(struct cyberfb_par *par);
315 static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
316 static void do_install_cmap(int con, struct fb_info *info);
317 static void cyberfb_set_disp(int con, struct fb_info *info);
318 static int get_video_mode(const char *name);
320 /* For cvision_core.c */
321 static unsigned short cv64_compute_clock(unsigned long);
322 static int cv_has_4mb (volatile unsigned char *);
323 static void cv64_board_init (void);
324 static void cv64_load_video_mode (struct fb_var_screeninfo *);
327 /* -------------------- Hardware specific routines ------------------------- */
331 * Initialization
333 * Set the default video mode for this chipset. If a video mode was
334 * specified on the command line, it will override the default mode.
337 static int Cyber_init(void)
339 volatile unsigned char *regs = CyberRegs;
340 volatile unsigned long *CursorBase;
341 int i;
342 DPRINTK("ENTER\n");
344 /* Init local cmap as greyscale levels */
345 for (i = 0; i < 256; i++) {
346 Cyber_colour_table [i][0] = i;
347 Cyber_colour_table [i][1] = i;
348 Cyber_colour_table [i][2] = i;
351 /* Initialize the board and determine fbmem size */
352 cv64_board_init();
353 #ifdef CYBERFBDEBUG
354 DPRINTK("Register state after initing board\n");
355 cv64_dump();
356 #endif
357 /* Clear framebuffer memory */
358 DPRINTK("Clear framebuffer memory\n");
359 memset ((char *)CyberMem, 0, CyberSize);
361 /* Disable hardware cursor */
362 DPRINTK("Disable HW cursor\n");
363 wb_64(regs, S3_CRTC_ADR, S3_REG_LOCK2);
364 wb_64(regs, S3_CRTC_DATA, 0xa0);
365 wb_64(regs, S3_CRTC_ADR, S3_HGC_MODE);
366 wb_64(regs, S3_CRTC_DATA, 0x00);
367 wb_64(regs, S3_CRTC_ADR, S3_HWGC_DX);
368 wb_64(regs, S3_CRTC_DATA, 0x00);
369 wb_64(regs, S3_CRTC_ADR, S3_HWGC_DY);
370 wb_64(regs, S3_CRTC_DATA, 0x00);
372 /* Initialize hardware cursor */
373 DPRINTK("Init HW cursor\n");
374 CursorBase = (u_long *)((char *)(CyberMem) + CyberSize - 0x400);
375 for (i=0; i < 8; i++)
377 *(CursorBase +(i*4)) = 0xffffff00;
378 *(CursorBase+1+(i*4)) = 0xffff0000;
379 *(CursorBase+2+(i*4)) = 0xffff0000;
380 *(CursorBase+3+(i*4)) = 0xffff0000;
382 for (i=8; i < 64; i++)
384 *(CursorBase +(i*4)) = 0xffff0000;
385 *(CursorBase+1+(i*4)) = 0xffff0000;
386 *(CursorBase+2+(i*4)) = 0xffff0000;
387 *(CursorBase+3+(i*4)) = 0xffff0000;
390 Cyber_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, NULL /* unused */);
391 Cyber_setcolreg (254, 0, 0, 0, 0, NULL /* unused */);
393 DPRINTK("EXIT\n");
394 return 0;
399 * This function should fill in the `fix' structure based on the
400 * values in the `par' structure.
403 static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
404 struct cyberfb_par *par)
406 DPRINTK("ENTER\n");
407 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
408 strcpy(fix->id, cyberfb_name);
409 fix->smem_start = CyberMem_phys;
410 fix->smem_len = CyberSize;
411 fix->mmio_start = CyberRegs_phys;
412 fix->mmio_len = 0x10000;
414 fix->type = FB_TYPE_PACKED_PIXELS;
415 fix->type_aux = 0;
416 if (par->var.bits_per_pixel == 15 || par->var.bits_per_pixel == 16 ||
417 par->var.bits_per_pixel == 24 || par->var.bits_per_pixel == 32) {
418 fix->visual = FB_VISUAL_DIRECTCOLOR;
419 } else {
420 fix->visual = FB_VISUAL_PSEUDOCOLOR;
423 fix->xpanstep = 0;
424 fix->ypanstep = 0;
425 fix->ywrapstep = 0;
426 fix->line_length = 0;
427 fix->accel = FB_ACCEL_S3_TRIO64;
429 DPRINTK("EXIT\n");
430 return(0);
435 * Fill the `par' structure based on the values in `var'.
436 * TODO: Verify and adjust values, return -EINVAL if bad.
439 static int Cyber_decode_var(struct fb_var_screeninfo *var,
440 struct cyberfb_par *par)
442 DPRINTK("ENTER\n");
443 par->var.xres = var->xres;
444 par->var.yres = var->yres;
445 par->var.xres_virtual = var->xres_virtual;
446 par->var.yres_virtual = var->yres_virtual;
447 par->var.xoffset = var->xoffset;
448 par->var.yoffset = var->yoffset;
449 par->var.bits_per_pixel = var->bits_per_pixel;
450 par->var.grayscale = var->grayscale;
451 par->var.red = var->red;
452 par->var.green = var->green;
453 par->var.blue = var->blue;
454 par->var.transp = var->transp;
455 par->var.nonstd = var->nonstd;
456 par->var.activate = var->activate;
457 par->var.height = var->height;
458 par->var.width = var->width;
459 if (var->accel_flags & FB_ACCELF_TEXT) {
460 par->var.accel_flags = FB_ACCELF_TEXT;
461 } else {
462 par->var.accel_flags = 0;
464 par->var.pixclock = var->pixclock;
465 par->var.left_margin = var->left_margin;
466 par->var.right_margin = var->right_margin;
467 par->var.upper_margin = var->upper_margin;
468 par->var.lower_margin = var->lower_margin;
469 par->var.hsync_len = var->hsync_len;
470 par->var.vsync_len = var->vsync_len;
471 par->var.sync = var->sync;
472 par->var.vmode = var->vmode;
473 DPRINTK("EXIT\n");
474 return(0);
478 * Fill the `var' structure based on the values in `par' and maybe
479 * other values read out of the hardware.
482 static int Cyber_encode_var(struct fb_var_screeninfo *var,
483 struct cyberfb_par *par)
485 DPRINTK("ENTER\n");
486 var->xres = par->var.xres;
487 var->yres = par->var.yres;
488 var->xres_virtual = par->var.xres_virtual;
489 var->yres_virtual = par->var.yres_virtual;
490 var->xoffset = par->var.xoffset;
491 var->yoffset = par->var.yoffset;
493 var->bits_per_pixel = par->var.bits_per_pixel;
494 var->grayscale = par->var.grayscale;
496 var->red = par->var.red;
497 var->green = par->var.green;
498 var->blue = par->var.blue;
499 var->transp = par->var.transp;
501 var->nonstd = par->var.nonstd;
502 var->activate = par->var.activate;
504 var->height = par->var.height;
505 var->width = par->var.width;
507 var->accel_flags = par->var.accel_flags;
509 var->pixclock = par->var.pixclock;
510 var->left_margin = par->var.left_margin;
511 var->right_margin = par->var.right_margin;
512 var->upper_margin = par->var.upper_margin;
513 var->lower_margin = par->var.lower_margin;
514 var->hsync_len = par->var.hsync_len;
515 var->vsync_len = par->var.vsync_len;
516 var->sync = par->var.sync;
517 var->vmode = par->var.vmode;
519 DPRINTK("EXIT\n");
520 return(0);
525 * Set a single color register. Return != 0 for invalid regno.
528 static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
529 u_int transp, struct fb_info *info)
531 volatile unsigned char *regs = CyberRegs;
533 /*DPRINTK("ENTER\n");*/
534 if (regno > 255) {
535 DPRINTK("EXIT - Register # > 255\n");
536 return (1);
539 wb_64(regs, 0x3c8, (unsigned char) regno);
541 red >>= 10;
542 green >>= 10;
543 blue >>= 10;
545 Cyber_colour_table [regno][0] = red;
546 Cyber_colour_table [regno][1] = green;
547 Cyber_colour_table [regno][2] = blue;
549 wb_64(regs, 0x3c9, red);
550 wb_64(regs, 0x3c9, green);
551 wb_64(regs, 0x3c9, blue);
553 /*DPRINTK("EXIT\n");*/
554 return (0);
559 * Read a single color register and split it into
560 * colors/transparent. Return != 0 for invalid regno.
563 static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
564 u_int *transp, struct fb_info *info)
566 int t;
568 /*DPRINTK("ENTER\n");*/
569 if (regno > 255) {
570 DPRINTK("EXIT - Register # > 255\n");
571 return (1);
573 /* ARB This shifting & oring seems VERY strange */
574 t = Cyber_colour_table [regno][0];
575 *red = (t<<10) | (t<<4) | (t>>2);
576 t = Cyber_colour_table [regno][1];
577 *green = (t<<10) | (t<<4) | (t>>2);
578 t = Cyber_colour_table [regno][2];
579 *blue = (t<<10) | (t<<4) | (t>>2);
580 *transp = 0;
581 /*DPRINTK("EXIT\n");*/
582 return (0);
587 * (Un)Blank the screen
588 * blank: 1 = zero fb cmap
589 * 0 = restore fb cmap from local cmap
592 void Cyberfb_blank(int blank, struct fb_info *info)
594 volatile unsigned char *regs = CyberRegs;
595 int i;
597 DPRINTK("ENTER\n");
598 #if 0
599 /* Blank by turning gfx off */
600 gfx_on_off (1, regs);
601 #else
602 if (blank) {
603 for (i = 0; i < 256; i++) {
604 wb_64(regs, 0x3c8, (unsigned char) i);
605 /* ARB Pale red to detect this blanking method */
606 wb_64(regs, 0x3c9, 48);
607 wb_64(regs, 0x3c9, 0);
608 wb_64(regs, 0x3c9, 0);
610 } else {
611 for (i = 0; i < 256; i++) {
612 wb_64(regs, 0x3c8, (unsigned char) i);
613 wb_64(regs, 0x3c9, Cyber_colour_table[i][0]);
614 wb_64(regs, 0x3c9, Cyber_colour_table[i][1]);
615 wb_64(regs, 0x3c9, Cyber_colour_table[i][2]);
618 #endif
619 DPRINTK("EXIT\n");
623 /**************************************************************
624 * We are waiting for "fifo" FIFO-slots empty
626 static void Cyber_WaitQueue (u_short fifo)
628 unsigned short status;
630 DPRINTK("ENTER\n");
631 do {
632 status = *((u_short volatile *)(CyberRegs + S3_GP_STAT));
633 } while (status & fifo);
634 DPRINTK("EXIT\n");
637 /**************************************************************
638 * We are waiting for Hardware (Graphics Engine) not busy
640 static void Cyber_WaitBlit (void)
642 unsigned short status;
644 DPRINTK("ENTER\n");
645 do {
646 status = *((u_short volatile *)(CyberRegs + S3_GP_STAT));
647 } while (status & S3_HDW_BUSY);
648 DPRINTK("EXIT\n");
651 /**************************************************************
652 * BitBLT - Through the Plane
654 static void Cyber_BitBLT (u_short curx, u_short cury, u_short destx,
655 u_short desty, u_short width, u_short height,
656 u_short mode)
658 volatile unsigned char *regs = CyberRegs;
659 u_short blitcmd = S3_BITBLT;
661 DPRINTK("ENTER\n");
662 /* Set drawing direction */
663 /* -Y, X maj, -X (default) */
664 if (curx > destx) {
665 blitcmd |= 0x0020; /* Drawing direction +X */
666 } else {
667 curx += (width - 1);
668 destx += (width - 1);
671 if (cury > desty) {
672 blitcmd |= 0x0080; /* Drawing direction +Y */
673 } else {
674 cury += (height - 1);
675 desty += (height - 1);
678 Cyber_WaitQueue (0x8000);
680 *((u_short volatile *)(regs + S3_PIXEL_CNTL)) = 0xa000;
681 *((u_short volatile *)(regs + S3_FRGD_MIX)) = (0x0060 | mode);
683 *((u_short volatile *)(regs + S3_CUR_X)) = curx;
684 *((u_short volatile *)(regs + S3_CUR_Y)) = cury;
686 *((u_short volatile *)(regs + S3_DESTX_DIASTP)) = destx;
687 *((u_short volatile *)(regs + S3_DESTY_AXSTP)) = desty;
689 *((u_short volatile *)(regs + S3_MIN_AXIS_PCNT)) = height - 1;
690 *((u_short volatile *)(regs + S3_MAJ_AXIS_PCNT)) = width - 1;
692 *((u_short volatile *)(regs + S3_CMD)) = blitcmd;
693 DPRINTK("EXIT\n");
696 /**************************************************************
697 * Rectangle Fill Solid
699 static void Cyber_RectFill (u_short x, u_short y, u_short width,
700 u_short height, u_short mode, u_short color)
702 volatile unsigned char *regs = CyberRegs;
703 u_short blitcmd = S3_FILLEDRECT;
705 DPRINTK("ENTER\n");
706 Cyber_WaitQueue (0x8000);
708 *((u_short volatile *)(regs + S3_PIXEL_CNTL)) = 0xa000;
709 *((u_short volatile *)(regs + S3_FRGD_MIX)) = (0x0020 | mode);
711 *((u_short volatile *)(regs + S3_MULT_MISC)) = 0xe000;
712 *((u_short volatile *)(regs + S3_FRGD_COLOR)) = color;
714 *((u_short volatile *)(regs + S3_CUR_X)) = x;
715 *((u_short volatile *)(regs + S3_CUR_Y)) = y;
717 *((u_short volatile *)(regs + S3_MIN_AXIS_PCNT)) = height - 1;
718 *((u_short volatile *)(regs + S3_MAJ_AXIS_PCNT)) = width - 1;
720 *((u_short volatile *)(regs + S3_CMD)) = blitcmd;
721 DPRINTK("EXIT\n");
725 #if 0
726 /**************************************************************
727 * Move cursor to x, y
729 static void Cyber_MoveCursor (u_short x, u_short y)
731 volatile unsigned char *regs = CyberRegs;
732 DPRINTK("ENTER\n");
733 *(regs + S3_CRTC_ADR) = 0x39;
734 *(regs + S3_CRTC_DATA) = 0xa0;
736 *(regs + S3_CRTC_ADR) = S3_HWGC_ORGX_H;
737 *(regs + S3_CRTC_DATA) = (char)((x & 0x0700) >> 8);
738 *(regs + S3_CRTC_ADR) = S3_HWGC_ORGX_L;
739 *(regs + S3_CRTC_DATA) = (char)(x & 0x00ff);
741 *(regs + S3_CRTC_ADR) = S3_HWGC_ORGY_H;
742 *(regs + S3_CRTC_DATA) = (char)((y & 0x0700) >> 8);
743 *(regs + S3_CRTC_ADR) = S3_HWGC_ORGY_L;
744 *(regs + S3_CRTC_DATA) = (char)(y & 0x00ff);
745 DPRINTK("EXIT\n");
747 #endif
750 /* -------------------- Generic routines ---------------------------------- */
754 * Fill the hardware's `par' structure.
757 static void cyberfb_get_par(struct cyberfb_par *par)
759 DPRINTK("ENTER\n");
760 if (current_par_valid) {
761 *par = current_par;
762 } else {
763 Cyber_decode_var(&cyberfb_default, par);
765 DPRINTK("EXIT\n");
769 static void cyberfb_set_par(struct cyberfb_par *par)
771 DPRINTK("ENTER\n");
772 current_par = *par;
773 current_par_valid = 1;
774 DPRINTK("EXIT\n");
778 static void cyber_set_video(struct fb_var_screeninfo *var)
781 /* Load the video mode defined by the 'var' data */
782 cv64_load_video_mode (var);
783 #ifdef CYBERFBDEBUG
784 DPRINTK("Register state after loading video mode\n");
785 cv64_dump();
786 #endif
790 static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
792 int err, activate;
793 struct cyberfb_par par;
795 DPRINTK("ENTER\n");
796 if ((err = Cyber_decode_var(var, &par))) {
797 DPRINTK("EXIT - decode_var failed\n");
798 return(err);
800 activate = var->activate;
801 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
802 cyberfb_set_par(&par);
803 Cyber_encode_var(var, &par);
804 var->activate = activate;
806 cyber_set_video(var);
807 DPRINTK("EXIT\n");
808 return 0;
812 static void do_install_cmap(int con, struct fb_info *info)
814 DPRINTK("ENTER\n");
815 if (con != currcon) {
816 DPRINTK("EXIT - Not current console\n");
817 return;
819 if (fb_display[con].cmap.len) {
820 DPRINTK("Use console cmap\n");
821 fb_set_cmap(&fb_display[con].cmap, 1, Cyber_setcolreg, info);
822 } else {
823 DPRINTK("Use default cmap\n");
824 fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
825 1, Cyber_setcolreg, info);
827 DPRINTK("EXIT\n");
832 * Open/Release the frame buffer device
835 static int cyberfb_open(struct fb_info *info, int user)
838 * Nothing, only a usage count for the moment
841 MOD_INC_USE_COUNT;
842 return(0);
845 static int cyberfb_release(struct fb_info *info, int user)
847 MOD_DEC_USE_COUNT;
848 return(0);
853 * Get the Fixed Part of the Display
856 static int cyberfb_get_fix(struct fb_fix_screeninfo *fix, int con,
857 struct fb_info *info)
859 struct cyberfb_par par;
860 int error = 0;
862 DPRINTK("ENTER\n");
863 if (con == -1) {
864 cyberfb_get_par(&par);
865 } else {
866 error = Cyber_decode_var(&fb_display[con].var, &par);
868 DPRINTK("EXIT\n");
869 return(error ? error : Cyber_encode_fix(fix, &par));
874 * Get the User Defined Part of the Display
877 static int cyberfb_get_var(struct fb_var_screeninfo *var, int con,
878 struct fb_info *info)
880 struct cyberfb_par par;
881 int error = 0;
883 DPRINTK("ENTER\n");
884 if (con == -1) {
885 cyberfb_get_par(&par);
886 error = Cyber_encode_var(var, &par);
887 disp.var = *var; /* ++Andre: don't know if this is the right place */
888 } else {
889 *var = fb_display[con].var;
892 DPRINTK("EXIT\n");
893 return(error);
897 static void cyberfb_set_disp(int con, struct fb_info *info)
899 struct fb_fix_screeninfo fix;
900 struct display *display;
902 DPRINTK("ENTER\n");
903 if (con >= 0)
904 display = &fb_display[con];
905 else
906 display = &disp; /* used during initialization */
908 cyberfb_get_fix(&fix, con, info);
909 if (con == -1)
910 con = 0;
911 display->screen_base = (unsigned char *)CyberMem;
912 display->visual = fix.visual;
913 display->type = fix.type;
914 display->type_aux = fix.type_aux;
915 display->ypanstep = fix.ypanstep;
916 display->ywrapstep = fix.ywrapstep;
917 display->can_soft_blank = 1;
918 display->inverse = Cyberfb_inverse;
919 switch (display->var.bits_per_pixel) {
920 #ifdef FBCON_HAS_CFB8
921 case 8:
922 if (display->var.accel_flags & FB_ACCELF_TEXT) {
923 display->dispsw = &fbcon_cyber8;
924 #warning FIXME: We should reinit the graphics engine here
925 } else
926 display->dispsw = &fbcon_cfb8;
927 break;
928 #endif
929 #ifdef FBCON_HAS_CFB16
930 case 16:
931 display->dispsw = &fbcon_cfb16;
932 break;
933 #endif
934 default:
935 display->dispsw = NULL;
936 break;
938 DPRINTK("EXIT\n");
943 * Set the User Defined Part of the Display
946 static int cyberfb_set_var(struct fb_var_screeninfo *var, int con,
947 struct fb_info *info)
949 int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel;
951 DPRINTK("ENTER\n");
952 if ((err = do_fb_set_var(var, con == currcon))) {
953 DPRINTK("EXIT - do_fb_set_var failed\n");
954 return(err);
956 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
957 oldxres = fb_display[con].var.xres;
958 oldyres = fb_display[con].var.yres;
959 oldvxres = fb_display[con].var.xres_virtual;
960 oldvyres = fb_display[con].var.yres_virtual;
961 oldbpp = fb_display[con].var.bits_per_pixel;
962 oldaccel = fb_display[con].var.accel_flags;
963 fb_display[con].var = *var;
964 if (oldxres != var->xres || oldyres != var->yres ||
965 oldvxres != var->xres_virtual ||
966 oldvyres != var->yres_virtual ||
967 oldbpp != var->bits_per_pixel ||
968 oldaccel != var->accel_flags) {
969 cyberfb_set_disp(con, info);
970 (*fb_info.changevar)(con);
971 fb_alloc_cmap(&fb_display[con].cmap, 0, 0);
972 do_install_cmap(con, info);
975 var->activate = 0;
976 DPRINTK("EXIT\n");
977 return(0);
982 * Get the Colormap
985 static int cyberfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
986 struct fb_info *info)
988 DPRINTK("ENTER\n");
989 if (con == currcon) { /* current console? */
990 DPRINTK("EXIT - console is current console\n");
991 return(fb_get_cmap(cmap, kspc, Cyber_getcolreg, info));
992 } else if (fb_display[con].cmap.len) { /* non default colormap? */
993 DPRINTK("Use console cmap\n");
994 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
995 } else {
996 DPRINTK("Use default cmap\n");
997 fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
998 cmap, kspc ? 0 : 2);
1000 DPRINTK("EXIT\n");
1001 return(0);
1006 * Set the Colormap
1009 static int cyberfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
1010 struct fb_info *info)
1012 int err;
1014 DPRINTK("ENTER\n");
1015 if (!fb_display[con].cmap.len) { /* no colormap allocated? */
1016 if ((err = fb_alloc_cmap(&fb_display[con].cmap,
1017 1<<fb_display[con].var.bits_per_pixel,
1018 0))) {
1019 DPRINTK("EXIT - fb_alloc_cmap failed\n");
1020 return(err);
1023 if (con == currcon) { /* current console? */
1024 DPRINTK("EXIT - Current console\n");
1025 return(fb_set_cmap(cmap, kspc, Cyber_setcolreg, info));
1026 } else {
1027 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
1029 DPRINTK("EXIT\n");
1030 return(0);
1035 * Pan or Wrap the Display
1037 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
1040 static int cyberfb_pan_display(struct fb_var_screeninfo *var, int con,
1041 struct fb_info *info)
1043 return -EINVAL;
1048 * Cybervision Frame Buffer Specific ioctls
1051 static int cyberfb_ioctl(struct inode *inode, struct file *file,
1052 u_int cmd, u_long arg, int con, struct fb_info *info)
1054 return -EINVAL;
1058 static struct fb_ops cyberfb_ops = {
1059 cyberfb_open, cyberfb_release, cyberfb_get_fix, cyberfb_get_var,
1060 cyberfb_set_var, cyberfb_get_cmap, cyberfb_set_cmap,
1061 cyberfb_pan_display, cyberfb_ioctl
1065 int __init cyberfb_setup(char *options)
1067 char *this_opt;
1068 DPRINTK("ENTER\n");
1070 fb_info.fontname[0] = '\0';
1072 if (!options || !*options) {
1073 DPRINTK("EXIT - no options\n");
1074 return 0;
1077 for (this_opt = strtok(options, ","); this_opt;
1078 this_opt = strtok(NULL, ",")) {
1079 if (!strcmp(this_opt, "inverse")) {
1080 Cyberfb_inverse = 1;
1081 fb_invert_cmaps();
1082 } else if (!strncmp(this_opt, "font:", 5)) {
1083 strcpy(fb_info.fontname, this_opt+5);
1084 } else if (!strcmp (this_opt, "cyber8")) {
1085 cyberfb_default = cyberfb_predefined[CYBER8_DEFMODE].var;
1086 cyberfb_usermode = 1;
1087 } else if (!strcmp (this_opt, "cyber16")) {
1088 cyberfb_default = cyberfb_predefined[CYBER16_DEFMODE].var;
1089 cyberfb_usermode = 1;
1090 } else get_video_mode(this_opt);
1093 DPRINTK("default mode: xres=%d, yres=%d, bpp=%d\n",
1094 cyberfb_default.xres,
1095 cyberfb_default.yres,
1096 cyberfb_default.bits_per_pixel);
1097 DPRINTK("EXIT\n");
1098 return 0;
1102 * Initialization
1105 int __init cyberfb_init(void)
1107 struct cyberfb_par par;
1108 unsigned long board_addr;
1109 unsigned long board_size;
1110 const struct ConfigDev *cd;
1111 unsigned int CyberKey = 0;
1112 DPRINTK("ENTER\n");
1114 if (!(CyberKey = zorro_find(ZORRO_PROD_PHASE5_CYBERVISION64, 0, 0))) {
1115 DPRINTK("EXIT - zorro_find failed\n");
1116 return -ENXIO;
1119 cd = zorro_get_board (CyberKey);
1120 zorro_config_board (CyberKey, 0);
1121 board_addr = (unsigned long)cd->cd_BoardAddr;
1122 board_size = (unsigned long)cd->cd_BoardSize;
1123 DPRINTK("board_addr=%08lx\n", board_addr);
1124 DPRINTK("board_size=%08lx\n", board_size);
1126 CyberBase = ioremap(board_addr, board_size);
1127 CyberRegs = CyberBase + 0x02000000;
1128 CyberMem = CyberBase + 0x01400000;
1129 DPRINTK("CyberBase=%08lx CyberRegs=%08lx CyberMem=%08lx\n",
1130 CyberBase, (long unsigned int)CyberRegs, CyberMem);
1132 CyberMem_phys = board_addr + 0x01400000;
1133 CyberRegs_phys = CyberMem_phys + 0x00c00000;
1134 DPRINTK("CyberMem=%08lx CyberRegs=%08lx\n", CyberMem,
1135 (long unsigned int)CyberRegs);
1137 #ifdef CYBERFBDEBUG
1138 DPRINTK("Register state just after mapping memory\n");
1139 cv64_dump();
1140 #endif
1142 strcpy(fb_info.modename, cyberfb_name);
1143 fb_info.changevar = NULL;
1144 fb_info.node = -1;
1145 fb_info.fbops = &cyberfb_ops;
1146 fb_info.disp = &disp;
1147 fb_info.switch_con = &Cyberfb_switch;
1148 fb_info.updatevar = &Cyberfb_updatevar;
1149 fb_info.blank = &Cyberfb_blank;
1151 Cyber_init();
1152 /* ++Andre: set cyberfb default mode */
1153 if (!cyberfb_usermode) {
1154 cyberfb_default = cyberfb_predefined[CYBER8_DEFMODE].var;
1155 DPRINTK("Use default cyber8 mode\n");
1157 Cyber_decode_var(&cyberfb_default, &par);
1158 Cyber_encode_var(&cyberfb_default, &par);
1160 do_fb_set_var(&cyberfb_default, 1);
1161 cyberfb_get_var(&fb_display[0].var, -1, &fb_info);
1162 cyberfb_set_disp(-1, &fb_info);
1163 do_install_cmap(0, &fb_info);
1165 if (register_framebuffer(&fb_info) < 0) {
1166 DPRINTK("EXIT - register_framebuffer failed\n");
1167 return -EINVAL;
1170 printk("fb%d: %s frame buffer device, using %ldK of video memory\n",
1171 GET_FB_IDX(fb_info.node), fb_info.modename, CyberSize>>10);
1173 /* TODO: This driver cannot be unloaded yet */
1174 MOD_INC_USE_COUNT;
1175 DPRINTK("EXIT\n");
1176 return 0;
1180 static int Cyberfb_switch(int con, struct fb_info *info)
1182 DPRINTK("ENTER\n");
1183 /* Do we have to save the colormap? */
1184 if (fb_display[currcon].cmap.len) {
1185 fb_get_cmap(&fb_display[currcon].cmap, 1, Cyber_getcolreg,
1186 info);
1189 do_fb_set_var(&fb_display[con].var, 1);
1190 currcon = con;
1191 /* Install new colormap */
1192 do_install_cmap(con, info);
1193 DPRINTK("EXIT\n");
1194 return(0);
1199 * Update the `var' structure (called by fbcon.c)
1201 * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
1202 * Since it's called by a kernel driver, no range checking is done.
1205 static int Cyberfb_updatevar(int con, struct fb_info *info)
1207 DPRINTK("Enter - Exit\n");
1208 return(0);
1213 * Get a Video Mode
1216 static int __init get_video_mode(const char *name)
1218 int i;
1220 DPRINTK("ENTER\n");
1221 for (i = 0; i < NUM_TOTAL_MODES; i++) {
1222 if (!strcmp(name, cyberfb_predefined[i].name)) {
1223 cyberfb_default = cyberfb_predefined[i].var;
1224 cyberfb_usermode = 1;
1225 DPRINTK("EXIT - Matched predefined mode\n");
1226 return(i);
1229 return(0);
1234 * Text console acceleration
1237 #ifdef FBCON_HAS_CFB8
1238 static void fbcon_cyber8_bmove(struct display *p, int sy, int sx, int dy,
1239 int dx, int height, int width)
1241 DPRINTK("ENTER\n");
1242 sx *= 8; dx *= 8; width *= 8;
1243 Cyber_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx,
1244 (u_short)(dy*fontheight(p)), (u_short)width,
1245 (u_short)(height*fontheight(p)), (u_short)S3_NEW);
1246 DPRINTK("EXIT\n");
1249 static void fbcon_cyber8_clear(struct vc_data *conp, struct display *p, int sy,
1250 int sx, int height, int width)
1252 unsigned char bg;
1254 DPRINTK("ENTER\n");
1255 sx *= 8; width *= 8;
1256 bg = attr_bgcol_ec(p,conp);
1257 Cyber_RectFill((u_short)sx,
1258 (u_short)(sy*fontheight(p)),
1259 (u_short)width,
1260 (u_short)(height*fontheight(p)),
1261 (u_short)S3_NEW,
1262 (u_short)bg);
1263 DPRINTK("EXIT\n");
1266 static void fbcon_cyber8_putc(struct vc_data *conp, struct display *p, int c,
1267 int yy, int xx)
1269 DPRINTK("ENTER\n");
1270 Cyber_WaitBlit();
1271 fbcon_cfb8_putc(conp, p, c, yy, xx);
1272 DPRINTK("EXIT\n");
1275 static void fbcon_cyber8_putcs(struct vc_data *conp, struct display *p,
1276 const unsigned short *s, int count,
1277 int yy, int xx)
1279 DPRINTK("ENTER\n");
1280 Cyber_WaitBlit();
1281 fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
1282 DPRINTK("EXIT\n");
1285 static void fbcon_cyber8_revc(struct display *p, int xx, int yy)
1287 DPRINTK("ENTER\n");
1288 Cyber_WaitBlit();
1289 fbcon_cfb8_revc(p, xx, yy);
1290 DPRINTK("EXIT\n");
1293 static struct display_switch fbcon_cyber8 = {
1294 fbcon_cfb8_setup, fbcon_cyber8_bmove, fbcon_cyber8_clear, fbcon_cyber8_putc,
1295 fbcon_cyber8_putcs, fbcon_cyber8_revc, NULL, NULL, fbcon_cfb8_clear_margins,
1296 FONTWIDTH(8)
1298 #endif
1301 #ifdef MODULE
1302 int init_module(void)
1304 return cyberfb_init();
1307 void cleanup_module(void)
1309 /* Not reached because the usecount will never be
1310 decremented to zero */
1311 unregister_framebuffer(&fb_info);
1312 /* TODO: clean up ... */
1314 #endif /* MODULE */
1318 * Low level initialization routines for the CyberVision64 graphics card
1320 * Most of the following code is from cvision_core.c
1324 #define MAXPIXELCLOCK 135000000 /* safety */
1326 #ifdef CV_AGGRESSIVE_TIMING
1327 long cv64_memclk = 55000000;
1328 #else
1329 long cv64_memclk = 50000000;
1330 #endif
1332 /*********************/
1334 static unsigned char clocks[]={
1335 0x13, 0x61, 0x6b, 0x6d, 0x51, 0x69, 0x54, 0x69,
1336 0x4f, 0x68, 0x6b, 0x6b, 0x18, 0x61, 0x7b, 0x6c,
1337 0x51, 0x67, 0x24, 0x62, 0x56, 0x67, 0x77, 0x6a,
1338 0x1d, 0x61, 0x53, 0x66, 0x6b, 0x68, 0x79, 0x69,
1339 0x7c, 0x69, 0x7f, 0x69, 0x22, 0x61, 0x54, 0x65,
1340 0x56, 0x65, 0x58, 0x65, 0x67, 0x66, 0x41, 0x63,
1341 0x27, 0x61, 0x13, 0x41, 0x37, 0x62, 0x6b, 0x4d,
1342 0x23, 0x43, 0x51, 0x49, 0x79, 0x66, 0x54, 0x49,
1343 0x7d, 0x66, 0x34, 0x56, 0x4f, 0x63, 0x1f, 0x42,
1344 0x6b, 0x4b, 0x7e, 0x4d, 0x18, 0x41, 0x2a, 0x43,
1345 0x7b, 0x4c, 0x74, 0x4b, 0x51, 0x47, 0x65, 0x49,
1346 0x24, 0x42, 0x68, 0x49, 0x56, 0x47, 0x75, 0x4a,
1347 0x77, 0x4a, 0x31, 0x43, 0x1d, 0x41, 0x71, 0x49,
1348 0x53, 0x46, 0x29, 0x42, 0x6b, 0x48, 0x1f, 0x41,
1349 0x79, 0x49, 0x6f, 0x48, 0x7c, 0x49, 0x38, 0x43,
1350 0x7f, 0x49, 0x5d, 0x46, 0x22, 0x41, 0x53, 0x45,
1351 0x54, 0x45, 0x55, 0x45, 0x56, 0x45, 0x57, 0x45,
1352 0x58, 0x45, 0x25, 0x41, 0x67, 0x46, 0x5b, 0x45,
1353 0x41, 0x43, 0x78, 0x47, 0x27, 0x41, 0x51, 0x44,
1354 0x13, 0x21, 0x7d, 0x47, 0x37, 0x42, 0x71, 0x46,
1355 0x6b, 0x2d, 0x14, 0x21, 0x23, 0x23, 0x7d, 0x2f,
1356 0x51, 0x29, 0x61, 0x2b, 0x79, 0x46, 0x1d, 0x22,
1357 0x54, 0x29, 0x45, 0x27, 0x7d, 0x46, 0x7f, 0x46,
1358 0x4f, 0x43, 0x2f, 0x41, 0x1f, 0x22, 0x6a, 0x2b,
1359 0x6b, 0x2b, 0x5b, 0x29, 0x7e, 0x2d, 0x65, 0x44,
1360 0x18, 0x21, 0x5e, 0x29, 0x2a, 0x23, 0x45, 0x26,
1361 0x7b, 0x2c, 0x19, 0x21, 0x74, 0x2b, 0x75, 0x2b,
1362 0x51, 0x27, 0x3f, 0x25, 0x65, 0x29, 0x40, 0x25,
1363 0x24, 0x22, 0x41, 0x25, 0x68, 0x29, 0x42, 0x25,
1364 0x56, 0x27, 0x7e, 0x2b, 0x75, 0x2a, 0x1c, 0x21,
1365 0x77, 0x2a, 0x4f, 0x26, 0x31, 0x23, 0x6f, 0x29,
1366 0x1d, 0x21, 0x32, 0x23, 0x71, 0x29, 0x72, 0x29,
1367 0x53, 0x26, 0x69, 0x28, 0x29, 0x22, 0x75, 0x29,
1368 0x6b, 0x28, 0x1f, 0x21, 0x1f, 0x21, 0x6d, 0x28,
1369 0x79, 0x29, 0x2b, 0x22, 0x6f, 0x28, 0x59, 0x26,
1370 0x7c, 0x29, 0x7d, 0x29, 0x38, 0x23, 0x21, 0x21,
1371 0x7f, 0x29, 0x39, 0x23, 0x5d, 0x26, 0x75, 0x28,
1372 0x22, 0x21, 0x77, 0x28, 0x53, 0x25, 0x6c, 0x27,
1373 0x54, 0x25, 0x61, 0x26, 0x55, 0x25, 0x30, 0x22,
1374 0x56, 0x25, 0x63, 0x26, 0x57, 0x25, 0x71, 0x27,
1375 0x58, 0x25, 0x7f, 0x28, 0x25, 0x21, 0x74, 0x27,
1376 0x67, 0x26, 0x40, 0x23, 0x5b, 0x25, 0x26, 0x21,
1377 0x41, 0x23, 0x34, 0x22, 0x78, 0x27, 0x6b, 0x26,
1378 0x27, 0x21, 0x35, 0x22, 0x51, 0x24, 0x7b, 0x27,
1379 0x13, 0x1, 0x13, 0x1, 0x7d, 0x27, 0x4c, 0x9,
1380 0x37, 0x22, 0x5b, 0xb, 0x71, 0x26, 0x5c, 0xb,
1381 0x6b, 0xd, 0x47, 0x23, 0x14, 0x1, 0x4f, 0x9,
1382 0x23, 0x3, 0x75, 0x26, 0x7d, 0xf, 0x1c, 0x2,
1383 0x51, 0x9, 0x59, 0x24, 0x61, 0xb, 0x69, 0x25,
1384 0x79, 0x26, 0x34, 0x5, 0x1d, 0x2, 0x6b, 0x25,
1385 0x54, 0x9, 0x35, 0x5, 0x45, 0x7, 0x6d, 0x25,
1386 0x7d, 0x26, 0x16, 0x1, 0x7f, 0x26, 0x77, 0xd,
1387 0x4f, 0x23, 0x78, 0xd, 0x2f, 0x21, 0x27, 0x3,
1388 0x1f, 0x2, 0x59, 0x9, 0x6a, 0xb, 0x73, 0x25,
1389 0x6b, 0xb, 0x63, 0x24, 0x5b, 0x9, 0x20, 0x2,
1390 0x7e, 0xd, 0x4b, 0x7, 0x65, 0x24, 0x43, 0x22,
1391 0x18, 0x1, 0x6f, 0xb, 0x5e, 0x9, 0x70, 0xb,
1392 0x2a, 0x3, 0x33, 0x4, 0x45, 0x6, 0x60, 0x9,
1393 0x7b, 0xc, 0x19, 0x1, 0x19, 0x1, 0x7d, 0xc,
1394 0x74, 0xb, 0x50, 0x7, 0x75, 0xb, 0x63, 0x9,
1395 0x51, 0x7, 0x23, 0x2, 0x3f, 0x5, 0x1a, 0x1,
1396 0x65, 0x9, 0x2d, 0x3, 0x40, 0x5, 0x0, 0x0,
1399 /* Console colors */
1400 unsigned char cvconscolors[16][3] = { /* background, foreground, hilite */
1401 /* R G B */
1402 {0x30, 0x30, 0x30},
1403 {0x00, 0x00, 0x00},
1404 {0x80, 0x00, 0x00},
1405 {0x00, 0x80, 0x00},
1406 {0x00, 0x00, 0x80},
1407 {0x80, 0x80, 0x00},
1408 {0x00, 0x80, 0x80},
1409 {0x80, 0x00, 0x80},
1410 {0xff, 0xff, 0xff},
1411 {0x40, 0x40, 0x40},
1412 {0xff, 0x00, 0x00},
1413 {0x00, 0xff, 0x00},
1414 {0x00, 0x00, 0xff},
1415 {0xff, 0xff, 0x00},
1416 {0x00, 0xff, 0xff},
1417 {0x00, 0x00, 0xff}
1420 /* -------------------- Hardware specific routines ------------------------- */
1422 /* Read Attribute Controller Register=idx */
1423 inline unsigned char RAttr (volatile unsigned char *regs, short idx)
1425 wb_64 (regs, ACT_ADDRESS_W, idx);
1426 mb();
1427 udelay(100);
1428 return (rb_64(regs, ACT_ADDRESS_R));
1431 /* Read Sequencer Register=idx */
1432 inline unsigned char RSeq (volatile unsigned char *regs, short idx)
1434 wb_64 (regs, SEQ_ADDRESS, idx);
1435 mb();
1436 return (rb_64(regs, SEQ_ADDRESS_R));
1439 /* Read CRT Controller Register=idx */
1440 inline unsigned char RCrt (volatile unsigned char *regs, short idx)
1442 wb_64 (regs, CRT_ADDRESS, idx);
1443 mb();
1444 return (rb_64(regs, CRT_ADDRESS_R));
1447 /* Read Graphics Controller Register=idx */
1448 inline unsigned char RGfx (volatile unsigned char *regs, short idx)
1450 wb_64 (regs, GCT_ADDRESS, idx);
1451 mb();
1452 return (rb_64(regs, GCT_ADDRESS_R));
1456 * Special wakeup/passthrough registers on graphics boards
1459 inline void cv64_write_port (unsigned short bits,
1460 volatile unsigned char *base)
1462 volatile unsigned char *addr;
1463 static unsigned char cvportbits = 0; /* Mirror port bits here */
1464 DPRINTK("ENTER\n");
1466 addr = base + 0x40001;
1467 if (bits & 0x8000) {
1468 cvportbits |= bits & 0xff; /* Set bits */
1469 DPRINTK("Set bits: %04x\n", bits);
1470 } else {
1471 bits = bits & 0xff;
1472 bits = (~bits) & 0xff;
1473 cvportbits &= bits; /* Clear bits */
1474 DPRINTK("Clear bits: %04x\n", bits);
1477 *addr = cvportbits;
1478 DPRINTK("EXIT\n");
1482 * Monitor switch on CyberVision board
1484 * toggle:
1485 * 0 = CyberVision Signal
1486 * 1 = Amiga Signal
1487 * board = board addr
1490 inline void cvscreen (int toggle, volatile unsigned char *board)
1492 DPRINTK("ENTER\n");
1493 if (toggle == 1) {
1494 DPRINTK("Show Amiga video\n");
1495 cv64_write_port (0x10, board);
1496 } else {
1497 DPRINTK("Show CyberVision video\n");
1498 cv64_write_port (0x8010, board);
1500 DPRINTK("EXIT\n");
1503 /* Control screen display */
1504 /* toggle: 0 = on, 1 = off */
1505 /* board = registerbase */
1506 inline void gfx_on_off(int toggle, volatile unsigned char *regs)
1508 int r;
1509 DPRINTK("ENTER\n");
1511 toggle &= 0x1;
1512 toggle = toggle << 5;
1513 DPRINTK("Turn display %s\n", (toggle ? "off" : "on"));
1515 r = (int) RSeq(regs, SEQ_ID_CLOCKING_MODE);
1516 r &= 0xdf; /* Set bit 5 to 0 */
1518 WSeq (regs, SEQ_ID_CLOCKING_MODE, r | toggle);
1519 DPRINTK("EXIT\n");
1523 * Computes M, N, and R values from
1524 * given input frequency. It uses a table of
1525 * precomputed values, to keep CPU time low.
1527 * The return value consist of:
1528 * lower byte: Bits 4-0: N Divider Value
1529 * Bits 5-6: R Value for e.g. SR10 or SR12
1530 * higher byte: Bits 0-6: M divider value for e.g. SR11 or SR13
1532 static unsigned short cv64_compute_clock(unsigned long freq)
1534 static unsigned char *mnr, *save; /* M, N + R vals */
1535 unsigned long work_freq, r;
1536 unsigned short erg;
1537 long diff, d2;
1539 DPRINTK("ENTER\n");
1540 if (freq < 12500000 || freq > MAXPIXELCLOCK) {
1541 printk("CV64 driver: Illegal clock frequency %ld, using 25MHz\n",
1542 freq);
1543 freq = 25000000;
1545 DPRINTK("Freq = %ld\n", freq);
1546 mnr = clocks; /* there the vals are stored */
1547 d2 = 0x7fffffff;
1549 while (*mnr) { /* mnr vals are 0-terminated */
1550 work_freq = (0x37EE * (mnr[0] + 2)) / ((mnr[1] & 0x1F) + 2);
1552 r = (mnr[1] >> 5) & 0x03;
1553 if (r != 0) {
1554 work_freq = work_freq >> r; /* r is the freq divider */
1557 work_freq *= 0x3E8; /* 2nd part of OSC */
1559 diff = abs(freq - work_freq);
1561 if (d2 >= diff) {
1562 d2 = diff;
1563 /* In save are the vals for minimal diff */
1564 save = mnr;
1566 mnr += 2;
1568 erg = *((unsigned short *)save);
1570 DPRINTK("EXIT\n");
1571 return (erg);
1574 static int cv_has_4mb (volatile unsigned char *fb)
1576 volatile unsigned long *tr, *tw;
1577 DPRINTK("ENTER\n");
1579 /* write patterns in memory and test if they can be read */
1580 tw = (volatile unsigned long *) fb;
1581 tr = (volatile unsigned long *) (fb + 0x02000000);
1583 *tw = 0x87654321;
1585 if (*tr != 0x87654321) {
1586 DPRINTK("EXIT - <4MB\n");
1587 return (0);
1590 /* upper memory region */
1591 tw = (volatile unsigned long *) (fb + 0x00200000);
1592 tr = (volatile unsigned long *) (fb + 0x02200000);
1594 *tw = 0x87654321;
1596 if (*tr != 0x87654321) {
1597 DPRINTK("EXIT - <4MB\n");
1598 return (0);
1601 *tw = 0xAAAAAAAA;
1603 if (*tr != 0xAAAAAAAA) {
1604 DPRINTK("EXIT - <4MB\n");
1605 return (0);
1608 *tw = 0x55555555;
1610 if (*tr != 0x55555555) {
1611 DPRINTK("EXIT - <4MB\n");
1612 return (0);
1615 DPRINTK("EXIT\n");
1616 return (1);
1619 static void cv64_board_init (void)
1621 volatile unsigned char *regs = CyberRegs;
1622 int i;
1623 unsigned int clockpar;
1624 unsigned char test;
1626 DPRINTK("ENTER\n");
1629 * Special CyberVision 64 board operations
1631 /* Reset board */
1632 for (i = 0; i < 6; i++) {
1633 cv64_write_port (0xff, CyberBase);
1635 /* Return to operational mode */
1636 cv64_write_port (0x8004, CyberBase);
1639 * Generic (?) S3 chip wakeup
1641 /* Disable I/O & memory decoders, video in setup mode */
1642 wb_64 (regs, SREG_VIDEO_SUBS_ENABLE, 0x10);
1643 /* Video responds to cmds, addrs & data */
1644 wb_64 (regs, SREG_OPTION_SELECT, 0x1);
1645 /* Enable I/O & memory decoders, video in operational mode */
1646 wb_64 (regs, SREG_VIDEO_SUBS_ENABLE, 0x8);
1647 /* VGA color emulation, enable cpu access to display mem */
1648 wb_64 (regs, GREG_MISC_OUTPUT_W, 0x03);
1649 /* Unlock S3 VGA regs */
1650 WCrt (regs, CRT_ID_REGISTER_LOCK_1, 0x48);
1651 /* Unlock system control & extension registers */
1652 WCrt (regs, CRT_ID_REGISTER_LOCK_2, 0xA5);
1653 /* GRF - Enable interrupts */
1654 /* Enable enhanced regs access, Ready cntl 0 wait states */
1655 test = RCrt (regs, CRT_ID_SYSTEM_CONFIG);
1656 test = test | 0x01; /* enable enhanced register access */
1657 test = test & 0xEF; /* clear bit 4, 0 wait state */
1658 WCrt (regs, CRT_ID_SYSTEM_CONFIG, test);
1660 * bit 0=1: Enable enhaced mode functions
1661 * bit 2=0: Enhanced mode 8+ bits/pixel
1662 * bit 4=1: Enable linear addressing
1663 * bit 5=1: Enable MMIO
1665 wb_64 (regs, ECR_ADV_FUNC_CNTL, 0x31);
1667 * bit 0=1: Color emulation
1668 * bit 1=1: Enable CPU access to display memory
1669 * bit 5=1: Select high 64K memory page
1671 /* GRF - 0xE3 */
1672 wb_64 (regs, GREG_MISC_OUTPUT_W, 0x23);
1674 /* Cpu base addr */
1675 WCrt (regs, CRT_ID_EXT_SYS_CNTL_4, 0x0);
1677 /* Reset. This does nothing on Trio, but standard VGA practice */
1678 /* WSeq (CyberRegs, SEQ_ID_RESET, 0x03); */
1679 /* Character clocks 8 dots wide */
1680 WSeq (regs, SEQ_ID_CLOCKING_MODE, 0x01);
1681 /* Enable cpu write to all color planes */
1682 WSeq (regs, SEQ_ID_MAP_MASK, 0x0F);
1683 /* Font table in 1st 8k of plane 2, font A=B disables swtich */
1684 WSeq (regs, SEQ_ID_CHAR_MAP_SELECT, 0x0);
1685 /* Allow mem access to 256kb */
1686 WSeq (regs, SEQ_ID_MEMORY_MODE, 0x2);
1687 /* Unlock S3 extensions to VGA Sequencer regs */
1688 WSeq (regs, SEQ_ID_UNLOCK_EXT, 0x6);
1690 /* Enable 4MB fast page mode */
1691 test = RSeq (regs, SEQ_ID_BUS_REQ_CNTL);
1692 test = test | 1 << 6;
1693 WSeq (regs, SEQ_ID_BUS_REQ_CNTL, test);
1695 /* Faster LUT write: 1 DCLK LUT write cycle, RAMDAC clk doubled */
1696 WSeq (regs, SEQ_ID_RAMDAC_CNTL, 0xC0);
1698 /* Clear immediate clock load bit */
1699 test = RSeq (regs, SEQ_ID_CLKSYN_CNTL_2);
1700 test = test & 0xDF;
1701 /* If > 55MHz, enable 2 cycle memory write */
1702 if (cv64_memclk >= 55000000) {
1703 test |= 0x80;
1705 WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, test);
1707 /* Set MCLK value */
1708 clockpar = cv64_compute_clock (cv64_memclk);
1709 test = (clockpar & 0xFF00) >> 8;
1710 WSeq (regs, SEQ_ID_MCLK_HI, test);
1711 test = clockpar & 0xFF;
1712 WSeq (regs, SEQ_ID_MCLK_LO, test);
1714 /* Chip rev specific: Not in my Trio manual!!! */
1715 if (RCrt (regs, CRT_ID_REVISION) == 0x10)
1716 WSeq (regs, SEQ_ID_MORE_MAGIC, test);
1718 /* We now load an 25 MHz, 31kHz, 640x480 standard VGA Mode. */
1720 /* Set DCLK value */
1721 WSeq (regs, SEQ_ID_DCLK_HI, 0x13);
1722 WSeq (regs, SEQ_ID_DCLK_LO, 0x41);
1724 /* Load DCLK (and MCLK?) immediately */
1725 test = RSeq (regs, SEQ_ID_CLKSYN_CNTL_2);
1726 test = test | 0x22;
1727 WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, test);
1729 /* Enable loading of DCLK */
1730 test = rb_64(regs, GREG_MISC_OUTPUT_R);
1731 test = test | 0x0C;
1732 wb_64 (regs, GREG_MISC_OUTPUT_W, test);
1734 /* Turn off immediate xCLK load */
1735 WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, 0x2);
1737 /* Horizontal character clock counts */
1738 /* 8 LSB of 9 bits = total line - 5 */
1739 WCrt (regs, CRT_ID_HOR_TOTAL, 0x5F);
1740 /* Active display line */
1741 WCrt (regs, CRT_ID_HOR_DISP_ENA_END, 0x4F);
1742 /* Blank assertion start */
1743 WCrt (regs, CRT_ID_START_HOR_BLANK, 0x50);
1744 /* Blank assertion end */
1745 WCrt (regs, CRT_ID_END_HOR_BLANK, 0x82);
1746 /* HSYNC assertion start */
1747 WCrt (regs, CRT_ID_START_HOR_RETR, 0x54);
1748 /* HSYNC assertion end */
1749 WCrt (regs, CRT_ID_END_HOR_RETR, 0x80);
1750 WCrt (regs, CRT_ID_VER_TOTAL, 0xBF);
1751 WCrt (regs, CRT_ID_OVERFLOW, 0x1F);
1752 WCrt (regs, CRT_ID_PRESET_ROW_SCAN, 0x0);
1753 WCrt (regs, CRT_ID_MAX_SCAN_LINE, 0x40);
1754 WCrt (regs, CRT_ID_CURSOR_START, 0x00);
1755 WCrt (regs, CRT_ID_CURSOR_END, 0x00);
1756 WCrt (regs, CRT_ID_START_ADDR_HIGH, 0x00);
1757 WCrt (regs, CRT_ID_START_ADDR_LOW, 0x00);
1758 WCrt (regs, CRT_ID_CURSOR_LOC_HIGH, 0x00);
1759 WCrt (regs, CRT_ID_CURSOR_LOC_LOW, 0x00);
1760 WCrt (regs, CRT_ID_START_VER_RETR, 0x9C);
1761 WCrt (regs, CRT_ID_END_VER_RETR, 0x0E);
1762 WCrt (regs, CRT_ID_VER_DISP_ENA_END, 0x8F);
1763 WCrt (regs, CRT_ID_SCREEN_OFFSET, 0x50);
1764 WCrt (regs, CRT_ID_UNDERLINE_LOC, 0x00);
1765 WCrt (regs, CRT_ID_START_VER_BLANK, 0x96);
1766 WCrt (regs, CRT_ID_END_VER_BLANK, 0xB9);
1767 WCrt (regs, CRT_ID_MODE_CONTROL, 0xE3);
1768 WCrt (regs, CRT_ID_LINE_COMPARE, 0xFF);
1769 WCrt (regs, CRT_ID_BACKWAD_COMP_3, 0x10); /* FIFO enabled */
1770 WCrt (regs, CRT_ID_MISC_1, 0x35);
1771 WCrt (regs, CRT_ID_DISPLAY_FIFO, 0x5A);
1772 WCrt (regs, CRT_ID_EXT_MEM_CNTL_2, 0x70);
1773 WCrt (regs, CRT_ID_LAW_POS_LO, 0x40);
1774 WCrt (regs, CRT_ID_EXT_MEM_CNTL_3, 0xFF);
1776 WGfx (regs, GCT_ID_SET_RESET, 0x0);
1777 WGfx (regs, GCT_ID_ENABLE_SET_RESET, 0x0);
1778 WGfx (regs, GCT_ID_COLOR_COMPARE, 0x0);
1779 WGfx (regs, GCT_ID_DATA_ROTATE, 0x0);
1780 WGfx (regs, GCT_ID_READ_MAP_SELECT, 0x0);
1781 WGfx (regs, GCT_ID_GRAPHICS_MODE, 0x40);
1782 WGfx (regs, GCT_ID_MISC, 0x01);
1783 WGfx (regs, GCT_ID_COLOR_XCARE, 0x0F);
1784 WGfx (regs, GCT_ID_BITMASK, 0xFF);
1786 /* Colors for text mode */
1787 for (i = 0; i < 0xf; i++)
1788 WAttr (regs, i, i);
1790 WAttr (regs, ACT_ID_ATTR_MODE_CNTL, 0x41);
1791 WAttr (regs, ACT_ID_OVERSCAN_COLOR, 0x01);
1792 WAttr (regs, ACT_ID_COLOR_PLANE_ENA, 0x0F);
1793 WAttr (regs, ACT_ID_HOR_PEL_PANNING, 0x0);
1794 WAttr (regs, ACT_ID_COLOR_SELECT, 0x0);
1796 wb_64 (regs, VDAC_MASK, 0xFF);
1798 *((unsigned long *) (regs + ECR_FRGD_COLOR)) = 0xFF;
1799 *((unsigned long *) (regs + ECR_BKGD_COLOR)) = 0;
1801 /* Colors initially set to grayscale */
1803 wb_64 (regs, VDAC_ADDRESS_W, 0);
1804 for (i = 255; i >= 0; i--) {
1805 wb_64(regs, VDAC_DATA, i);
1806 wb_64(regs, VDAC_DATA, i);
1807 wb_64(regs, VDAC_DATA, i);
1810 /* GFx hardware cursor off */
1811 WCrt (regs, CRT_ID_HWGC_MODE, 0x00);
1813 /* Set first to 4MB, so test will work */
1814 WCrt (regs, CRT_ID_LAW_CNTL, 0x13);
1815 /* Find "correct" size of fbmem of Z3 board */
1816 if (cv_has_4mb (CyberMem)) {
1817 CyberSize = 1024 * 1024 * 4;
1818 WCrt (regs, CRT_ID_LAW_CNTL, 0x13);
1819 DPRINTK("4MB board\n");
1820 } else {
1821 CyberSize = 1024 * 1024 * 2;
1822 WCrt (regs, CRT_ID_LAW_CNTL, 0x12);
1823 DPRINTK("2MB board\n");
1826 /* Initialize graphics engine */
1827 Cyber_WaitBlit();
1828 vgaw16 (regs, ECR_FRGD_MIX, 0x27);
1829 vgaw16 (regs, ECR_BKGD_MIX, 0x07);
1830 vgaw16 (regs, ECR_READ_REG_DATA, 0x1000);
1831 udelay(200);
1832 vgaw16 (regs, ECR_READ_REG_DATA, 0x2000);
1833 Cyber_WaitBlit();
1834 vgaw16 (regs, ECR_READ_REG_DATA, 0x3FFF);
1835 Cyber_WaitBlit();
1836 udelay(200);
1837 vgaw16 (regs, ECR_READ_REG_DATA, 0x4FFF);
1838 Cyber_WaitBlit();
1839 vgaw16 (regs, ECR_BITPLANE_WRITE_MASK, ~0);
1840 Cyber_WaitBlit();
1841 vgaw16 (regs, ECR_READ_REG_DATA, 0xE000);
1842 vgaw16 (regs, ECR_CURRENT_Y_POS2, 0x00);
1843 vgaw16 (regs, ECR_CURRENT_X_POS2, 0x00);
1844 vgaw16 (regs, ECR_READ_REG_DATA, 0xA000);
1845 vgaw16 (regs, ECR_DEST_Y__AX_STEP, 0x00);
1846 vgaw16 (regs, ECR_DEST_Y2__AX_STEP2, 0x00);
1847 vgaw16 (regs, ECR_DEST_X__DIA_STEP, 0x00);
1848 vgaw16 (regs, ECR_DEST_X2__DIA_STEP2, 0x00);
1849 vgaw16 (regs, ECR_SHORT_STROKE, 0x00);
1850 vgaw16 (regs, ECR_DRAW_CMD, 0x01);
1852 Cyber_WaitBlit();
1854 vgaw16 (regs, ECR_READ_REG_DATA, 0x4FFF);
1855 vgaw16 (regs, ECR_BKGD_COLOR, 0x01);
1856 vgaw16 (regs, ECR_FRGD_COLOR, 0x00);
1859 /* Enable video display (set bit 5) */
1860 /* ARB - Would also seem to write to AR13.
1861 * May want to use parts of WAttr to set JUST bit 5
1863 WAttr (regs, 0x33, 0);
1865 /* GRF - function code ended here */
1867 /* Turn gfx on again */
1868 gfx_on_off (0, regs);
1870 /* Pass-through */
1871 cvscreen (0, CyberBase);
1873 DPRINTK("EXIT\n");
1876 static void cv64_load_video_mode (struct fb_var_screeninfo *video_mode)
1878 volatile unsigned char *regs = CyberRegs;
1879 int fx, fy;
1880 unsigned short mnr;
1881 unsigned short HT, HDE, HBS, HBE, HSS, HSE, VDE, VBS, VBE, VSS, VSE, VT;
1882 char LACE, DBLSCAN, TEXT, CONSOLE;
1883 int cr50, sr15, sr18, clock_mode, test;
1884 int m, n;
1885 int tfillm, temptym;
1886 int hmul;
1888 /* ---------------- */
1889 int xres, hfront, hsync, hback;
1890 int yres, vfront, vsync, vback;
1891 int bpp;
1892 #if 0
1893 float freq_f;
1894 #endif
1895 long freq;
1896 /* ---------------- */
1898 DPRINTK("ENTER\n");
1899 TEXT = 0; /* if depth == 4 */
1900 CONSOLE = 0; /* mode num == 255 (console) */
1901 fx = fy = 8; /* force 8x8 font */
1903 /* GRF - Disable interrupts */
1905 gfx_on_off (1, regs);
1907 switch (video_mode->bits_per_pixel) {
1908 case 15:
1909 case 16:
1910 hmul = 2;
1911 break;
1913 default:
1914 hmul = 1;
1915 break;
1918 bpp = video_mode->bits_per_pixel;
1919 xres = video_mode->xres;
1920 hfront = video_mode->right_margin;
1921 hsync = video_mode->hsync_len;
1922 hback = video_mode->left_margin;
1924 LACE = 0;
1925 DBLSCAN = 0;
1927 if (video_mode->vmode & FB_VMODE_DOUBLE) {
1928 yres = video_mode->yres * 2;
1929 vfront = video_mode->lower_margin * 2;
1930 vsync = video_mode->vsync_len * 2;
1931 vback = video_mode->upper_margin * 2;
1932 DBLSCAN = 1;
1933 } else if (video_mode->vmode & FB_VMODE_INTERLACED) {
1934 yres = (video_mode->yres + 1) / 2;
1935 vfront = (video_mode->lower_margin + 1) / 2;
1936 vsync = (video_mode->vsync_len + 1) / 2;
1937 vback = (video_mode->upper_margin + 1) / 2;
1938 LACE = 1;
1939 } else {
1940 yres = video_mode->yres;
1941 vfront = video_mode->lower_margin;
1942 vsync = video_mode->vsync_len;
1943 vback = video_mode->upper_margin;
1946 /* ARB Dropping custom setup method from cvision.c */
1947 #if 0
1948 if (cvision_custom_mode) {
1949 HBS = hbs / 8 * hmul;
1950 HBE = hbe / 8 * hmul;
1951 HSS = hss / 8 * hmul;
1952 HSE = hse / 8 * hmul;
1953 HT = ht / 8 * hmul - 5;
1955 VBS = vbs - 1;
1956 VSS = vss;
1957 VSE = vse;
1958 VBE = vbe;
1959 VT = vt - 2;
1960 } else {
1961 #else
1963 #endif
1964 HBS = hmul * (xres / 8);
1965 HBE = hmul * ((xres/8) + (hfront/8) + (hsync/8) + (hback/8) - 2);
1966 HSS = hmul * ((xres/8) + (hfront/8) + 2);
1967 HSE = hmul * ((xres/8) + (hfront/8) + (hsync/8) + 1);
1968 HT = hmul * ((xres/8) + (hfront/8) + (hsync/8) + (hback/8));
1970 VBS = yres;
1971 VBE = yres + vfront + vsync + vback - 2;
1972 VSS = yres + vfront - 1;
1973 VSE = yres + vfront + vsync - 1;
1974 VT = yres + vfront + vsync + vback - 2;
1977 wb_64 (regs, ECR_ADV_FUNC_CNTL, (TEXT ? 0x00 : 0x31));
1979 if (TEXT)
1980 HDE = ((video_mode->xres + fx - 1) / fx) - 1;
1981 else
1982 HDE = (video_mode->xres + 3) * hmul / 8 - 1;
1984 VDE = video_mode->yres - 1;
1986 WCrt (regs, CRT_ID_HWGC_MODE, 0x00);
1987 WCrt (regs, CRT_ID_EXT_DAC_CNTL, 0x00);
1989 WSeq (regs, SEQ_ID_MEMORY_MODE,
1990 (TEXT || (video_mode->bits_per_pixel == 1)) ? 0x06 : 0x0e);
1991 WGfx (regs, GCT_ID_READ_MAP_SELECT, 0x00);
1992 WSeq (regs, SEQ_ID_MAP_MASK,
1993 (video_mode->bits_per_pixel == 1) ? 0x01 : 0xFF);
1994 WSeq (regs, SEQ_ID_CHAR_MAP_SELECT, 0x00);
1996 /* cv64_compute_clock accepts arguments in Hz */
1997 /* pixclock is in ps ... convert to Hz */
1999 #if 0
2000 freq_f = (1.0 / (float) video_mode->pixclock) * 1000000000;
2001 freq = ((long) freq_f) * 1000;
2002 #else
2003 /* freq = (long) ((long long)1000000000000 / (long long) video_mode->pixclock);
2005 freq = (1000000000 / video_mode->pixclock) * 1000;
2006 #endif
2008 mnr = cv64_compute_clock (freq);
2009 WSeq (regs, SEQ_ID_DCLK_HI, ((mnr & 0xFF00) >> 8));
2010 WSeq (regs, SEQ_ID_DCLK_LO, (mnr & 0xFF));
2012 /* Load display parameters into board */
2013 WCrt (regs, CRT_ID_EXT_HOR_OVF,
2014 ((HT & 0x100) ? 0x01 : 0x00) |
2015 ((HDE & 0x100) ? 0x02 : 0x00) |
2016 ((HBS & 0x100) ? 0x04 : 0x00) |
2017 /* ((HBE & 0x40) ? 0x08 : 0x00) | */
2018 ((HSS & 0x100) ? 0x10 : 0x00) |
2019 /* ((HSE & 0x20) ? 0x20 : 0x00) | */
2020 (((HT-5) & 0x100) ? 0x40 : 0x00)
2023 WCrt (regs, CRT_ID_EXT_VER_OVF,
2024 0x40 |
2025 ((VT & 0x400) ? 0x01 : 0x00) |
2026 ((VDE & 0x400) ? 0x02 : 0x00) |
2027 ((VBS & 0x400) ? 0x04 : 0x00) |
2028 ((VSS & 0x400) ? 0x10 : 0x00)
2031 WCrt (regs, CRT_ID_HOR_TOTAL, HT);
2032 WCrt (regs, CRT_ID_DISPLAY_FIFO, HT - 5);
2033 WCrt (regs, CRT_ID_HOR_DISP_ENA_END, ((HDE >= HBS) ? (HBS - 1) : HDE));
2034 WCrt (regs, CRT_ID_START_HOR_BLANK, HBS);
2035 WCrt (regs, CRT_ID_END_HOR_BLANK, ((HBE & 0x1F) | 0x80));
2036 WCrt (regs, CRT_ID_START_HOR_RETR, HSS);
2037 WCrt (regs, CRT_ID_END_HOR_RETR,
2038 (HSE & 0x1F) |
2039 ((HBE & 0x20) ? 0x80 : 0x00)
2041 WCrt (regs, CRT_ID_VER_TOTAL, VT);
2042 WCrt (regs, CRT_ID_OVERFLOW,
2043 0x10 |
2044 ((VT & 0x100) ? 0x01 : 0x00) |
2045 ((VDE & 0x100) ? 0x02 : 0x00) |
2046 ((VSS & 0x100) ? 0x04 : 0x00) |
2047 ((VBS & 0x100) ? 0x08 : 0x00) |
2048 ((VT & 0x200) ? 0x20 : 0x00) |
2049 ((VDE & 0x200) ? 0x40 : 0x00) |
2050 ((VSS & 0x200) ? 0x80 : 0x00)
2052 WCrt (regs, CRT_ID_MAX_SCAN_LINE,
2053 0x40 |
2054 (DBLSCAN ? 0x80 : 0x00) |
2055 ((VBS & 0x200) ? 0x20 : 0x00) |
2056 (TEXT ? ((fy - 1) & 0x1F) : 0x00)
2059 WCrt (regs, CRT_ID_MODE_CONTROL, 0xE3);
2061 /* Text cursor */
2063 if (TEXT) {
2064 #if 1
2065 WCrt (regs, CRT_ID_CURSOR_START, (fy & 0x1f) - 2);
2066 WCrt (regs, CRT_ID_CURSOR_END, (fy & 0x1F) - 1);
2067 #else
2068 WCrt (regs, CRT_ID_CURSOR_START, 0x00);
2069 WCrt (regs, CRT_ID_CURSOR_END, fy & 0x1F);
2070 #endif
2071 WCrt (regs, CRT_ID_UNDERLINE_LOC, (fy - 1) & 0x1F);
2072 WCrt (regs, CRT_ID_CURSOR_LOC_HIGH, 0x00);
2073 WCrt (regs, CRT_ID_CURSOR_LOC_LOW, 0x00);
2076 WCrt (regs, CRT_ID_START_ADDR_HIGH, 0x00);
2077 WCrt (regs, CRT_ID_START_ADDR_LOW, 0x00);
2078 WCrt (regs, CRT_ID_START_VER_RETR, VSS);
2079 WCrt (regs, CRT_ID_END_VER_RETR, (VSE & 0x0F));
2080 WCrt (regs, CRT_ID_VER_DISP_ENA_END, VDE);
2081 WCrt (regs, CRT_ID_START_VER_BLANK, VBS);
2082 WCrt (regs, CRT_ID_END_VER_BLANK, VBE);
2083 WCrt (regs, CRT_ID_LINE_COMPARE, 0xFF);
2084 WCrt (regs, CRT_ID_LACE_RETR_START, HT / 2);
2085 WCrt (regs, CRT_ID_LACE_CONTROL, (LACE ? 0x20 : 0x00));
2086 WGfx (regs, GCT_ID_GRAPHICS_MODE,
2087 ((TEXT || (video_mode->bits_per_pixel == 1)) ? 0x00 : 0x40));
2088 WGfx (regs, GCT_ID_MISC, (TEXT ? 0x04 : 0x01));
2089 WSeq (regs, SEQ_ID_MEMORY_MODE,
2090 ((TEXT || (video_mode->bits_per_pixel == 1)) ? 0x06 : 0x02));
2092 wb_64 (regs, VDAC_MASK, 0xFF);
2094 /* Blank border */
2095 test = RCrt (regs, CRT_ID_BACKWAD_COMP_2);
2096 WCrt (regs, CRT_ID_BACKWAD_COMP_2, (test | 0x20));
2098 sr15 = RSeq (regs, SEQ_ID_CLKSYN_CNTL_2);
2099 sr15 &= 0xEF;
2100 sr18 = RSeq (regs, SEQ_ID_RAMDAC_CNTL);
2101 sr18 &= 0x7F;
2102 clock_mode = 0x00;
2103 cr50 = 0x00;
2105 test = RCrt (regs, CRT_ID_EXT_MISC_CNTL_2);
2106 test &= 0xD;
2108 /* Clear roxxler byte-swapping... */
2109 cv64_write_port (0x0040, CyberBase);
2110 cv64_write_port (0x0020, CyberBase);
2112 switch (video_mode->bits_per_pixel) {
2113 case 1:
2114 case 4: /* text */
2115 HDE = video_mode->xres / 16;
2116 break;
2118 case 8:
2119 if (freq > 80000000) {
2120 clock_mode = 0x10 | 0x02;
2121 sr15 |= 0x10;
2122 sr18 |= 0x80;
2124 HDE = video_mode->xres / 8;
2125 cr50 |= 0x00;
2126 break;
2128 case 15:
2129 cv64_write_port (0x8020, CyberBase);
2130 clock_mode = 0x30;
2131 HDE = video_mode->xres / 4;
2132 cr50 |= 0x10;
2133 break;
2135 case 16:
2136 cv64_write_port (0x8020, CyberBase);
2137 clock_mode = 0x50;
2138 HDE = video_mode->xres / 4;
2139 cr50 |= 0x10;
2140 break;
2142 case 24:
2143 case 32:
2144 cv64_write_port (0x8040, CyberBase);
2145 clock_mode = 0xD0;
2146 HDE = video_mode->xres / 2;
2147 cr50 |= 0x30;
2148 break;
2151 WCrt (regs, CRT_ID_EXT_MISC_CNTL_2, clock_mode | test);
2152 WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, sr15);
2153 WSeq (regs, SEQ_ID_RAMDAC_CNTL, sr18);
2154 WCrt (regs, CRT_ID_SCREEN_OFFSET, HDE);
2156 WCrt (regs, CRT_ID_MISC_1, (TEXT ? 0x05 : 0x35));
2158 test = RCrt (regs, CRT_ID_EXT_SYS_CNTL_2);
2159 test &= ~0x30;
2160 test |= (HDE >> 4) & 0x30;
2161 WCrt (regs, CRT_ID_EXT_SYS_CNTL_2, test);
2163 /* Set up graphics engine */
2164 switch (video_mode->xres) {
2165 case 1024:
2166 cr50 |= 0x00;
2167 break;
2169 case 640:
2170 cr50 |= 0x40;
2171 break;
2173 case 800:
2174 cr50 |= 0x80;
2175 break;
2177 case 1280:
2178 cr50 |= 0xC0;
2179 break;
2181 case 1152:
2182 cr50 |= 0x01;
2183 break;
2185 case 1600:
2186 cr50 |= 0x81;
2187 break;
2189 default: /* XXX */
2190 break;
2193 WCrt (regs, CRT_ID_EXT_SYS_CNTL_1, cr50);
2195 udelay(100);
2196 WAttr (regs, ACT_ID_ATTR_MODE_CNTL, (TEXT ? 0x08 : 0x41));
2197 udelay(100);
2198 WAttr (regs, ACT_ID_COLOR_PLANE_ENA,
2199 (video_mode->bits_per_pixel == 1) ? 0x01 : 0x0F);
2200 udelay(100);
2202 tfillm = (96 * (cv64_memclk / 1000)) / 240000;
2204 switch (video_mode->bits_per_pixel) {
2205 case 32:
2206 case 24:
2207 temptym = (24 * (cv64_memclk / 1000)) / (freq / 1000);
2208 break;
2209 case 15:
2210 case 16:
2211 temptym = (48 * (cv64_memclk / 1000)) / (freq / 1000);
2212 break;
2213 case 4:
2214 temptym = (192 * (cv64_memclk / 1000)) / (freq / 1000);
2215 break;
2216 default:
2217 temptym = (96 * (cv64_memclk / 1000)) / (freq / 1000);
2218 break;
2221 m = (temptym - tfillm - 9) / 2;
2222 if (m < 0)
2223 m = 0;
2224 m = (m & 0x1F) << 3;
2225 if (m < 0x18)
2226 m = 0x18;
2227 n = 0xFF;
2229 WCrt (regs, CRT_ID_EXT_MEM_CNTL_2, m);
2230 WCrt (regs, CRT_ID_EXT_MEM_CNTL_3, n);
2231 udelay(10);
2233 /* Text initialization */
2235 if (TEXT) {
2236 /* Do text initialization here ! */
2239 if (CONSOLE) {
2240 int i;
2241 wb_64 (regs, VDAC_ADDRESS_W, 0);
2242 for (i = 0; i < 4; i++) {
2243 wb_64 (regs, VDAC_DATA, cvconscolors [i][0]);
2244 wb_64 (regs, VDAC_DATA, cvconscolors [i][1]);
2245 wb_64 (regs, VDAC_DATA, cvconscolors [i][2]);
2249 WAttr (regs, 0x33, 0);
2251 /* Turn gfx on again */
2252 gfx_on_off (0, (volatile unsigned char *) regs);
2254 /* Pass-through */
2255 cvscreen (0, CyberBase);
2257 DPRINTK("EXIT\n");
2260 void cvision_bitblt (u_short sx, u_short sy, u_short dx, u_short dy,
2261 u_short w, u_short h)
2263 volatile unsigned char *regs = CyberRegs;
2264 unsigned short drawdir = 0;
2266 DPRINTK("ENTER\n");
2267 if (sx > dx) {
2268 drawdir |= 1 << 5;
2269 } else {
2270 sx += w - 1;
2271 dx += w - 1;
2274 if (sy > dy) {
2275 drawdir |= 1 << 7;
2276 } else {
2277 sy += h - 1;
2278 dy += h - 1;
2281 Cyber_WaitBlit();
2282 vgaw16 (regs, ECR_READ_REG_DATA, 0xA000);
2283 vgaw16 (regs, ECR_BKGD_MIX, 0x7);
2284 vgaw16 (regs, ECR_FRGD_MIX, 0x67);
2285 vgaw16 (regs, ECR_BKGD_COLOR, 0x0);
2286 vgaw16 (regs, ECR_FRGD_COLOR, 0x1);
2287 vgaw16 (regs, ECR_BITPLANE_READ_MASK, 0x1);
2288 vgaw16 (regs, ECR_BITPLANE_WRITE_MASK, 0xFFF);
2289 vgaw16 (regs, ECR_CURRENT_Y_POS, sy);
2290 vgaw16 (regs, ECR_CURRENT_X_POS, sx);
2291 vgaw16 (regs, ECR_DEST_Y__AX_STEP, dy);
2292 vgaw16 (regs, ECR_DEST_X__DIA_STEP, dx);
2293 vgaw16 (regs, ECR_READ_REG_DATA, h - 1);
2294 vgaw16 (regs, ECR_MAJ_AXIS_PIX_CNT, w - 1);
2295 vgaw16 (regs, ECR_DRAW_CMD, 0xC051 | drawdir);
2296 DPRINTK("EXIT\n");
2299 void cvision_clear (u_short dx, u_short dy, u_short w, u_short h, u_short bg)
2301 volatile unsigned char *regs = CyberRegs;
2302 DPRINTK("ENTER\n");
2303 Cyber_WaitBlit();
2304 vgaw16 (regs, ECR_FRGD_MIX, 0x0027);
2305 vgaw16 (regs, ECR_FRGD_COLOR, bg);
2306 vgaw16 (regs, ECR_READ_REG_DATA, 0xA000);
2307 vgaw16 (regs, ECR_CURRENT_Y_POS, dy);
2308 vgaw16 (regs, ECR_CURRENT_X_POS, dx);
2309 vgaw16 (regs, ECR_READ_REG_DATA, h - 1);
2310 vgaw16 (regs, ECR_MAJ_AXIS_PIX_CNT, w - 1);
2311 vgaw16 (regs, ECR_DRAW_CMD, 0x40B1);
2312 DPRINTK("EXIT\n");
2315 #ifdef CYBERFBDEBUG
2317 * Dump internal settings of CyberVision board
2319 static void cv64_dump (void)
2321 volatile unsigned char *regs = CyberRegs;
2322 DPRINTK("ENTER\n");
2323 /* Dump the VGA setup values */
2324 *(regs + S3_CRTC_ADR) = 0x00;
2325 DPRINTK("CR00 = %x\n", *(regs + S3_CRTC_DATA));
2326 *(regs + S3_CRTC_ADR) = 0x01;
2327 DPRINTK("CR01 = %x\n", *(regs + S3_CRTC_DATA));
2328 *(regs + S3_CRTC_ADR) = 0x02;
2329 DPRINTK("CR02 = %x\n", *(regs + S3_CRTC_DATA));
2330 *(regs + S3_CRTC_ADR) = 0x03;
2331 DPRINTK("CR03 = %x\n", *(regs + S3_CRTC_DATA));
2332 *(regs + S3_CRTC_ADR) = 0x04;
2333 DPRINTK("CR04 = %x\n", *(regs + S3_CRTC_DATA));
2334 *(regs + S3_CRTC_ADR) = 0x05;
2335 DPRINTK("CR05 = %x\n", *(regs + S3_CRTC_DATA));
2336 *(regs + S3_CRTC_ADR) = 0x06;
2337 DPRINTK("CR06 = %x\n", *(regs + S3_CRTC_DATA));
2338 *(regs + S3_CRTC_ADR) = 0x07;
2339 DPRINTK("CR07 = %x\n", *(regs + S3_CRTC_DATA));
2340 *(regs + S3_CRTC_ADR) = 0x08;
2341 DPRINTK("CR08 = %x\n", *(regs + S3_CRTC_DATA));
2342 *(regs + S3_CRTC_ADR) = 0x09;
2343 DPRINTK("CR09 = %x\n", *(regs + S3_CRTC_DATA));
2344 *(regs + S3_CRTC_ADR) = 0x10;
2345 DPRINTK("CR10 = %x\n", *(regs + S3_CRTC_DATA));
2346 *(regs + S3_CRTC_ADR) = 0x11;
2347 DPRINTK("CR11 = %x\n", *(regs + S3_CRTC_DATA));
2348 *(regs + S3_CRTC_ADR) = 0x12;
2349 DPRINTK("CR12 = %x\n", *(regs + S3_CRTC_DATA));
2350 *(regs + S3_CRTC_ADR) = 0x13;
2351 DPRINTK("CR13 = %x\n", *(regs + S3_CRTC_DATA));
2352 *(regs + S3_CRTC_ADR) = 0x15;
2353 DPRINTK("CR15 = %x\n", *(regs + S3_CRTC_DATA));
2354 *(regs + S3_CRTC_ADR) = 0x16;
2355 DPRINTK("CR16 = %x\n", *(regs + S3_CRTC_DATA));
2356 *(regs + S3_CRTC_ADR) = 0x36;
2357 DPRINTK("CR36 = %x\n", *(regs + S3_CRTC_DATA));
2358 *(regs + S3_CRTC_ADR) = 0x37;
2359 DPRINTK("CR37 = %x\n", *(regs + S3_CRTC_DATA));
2360 *(regs + S3_CRTC_ADR) = 0x42;
2361 DPRINTK("CR42 = %x\n", *(regs + S3_CRTC_DATA));
2362 *(regs + S3_CRTC_ADR) = 0x43;
2363 DPRINTK("CR43 = %x\n", *(regs + S3_CRTC_DATA));
2364 *(regs + S3_CRTC_ADR) = 0x50;
2365 DPRINTK("CR50 = %x\n", *(regs + S3_CRTC_DATA));
2366 *(regs + S3_CRTC_ADR) = 0x51;
2367 DPRINTK("CR51 = %x\n", *(regs + S3_CRTC_DATA));
2368 *(regs + S3_CRTC_ADR) = 0x53;
2369 DPRINTK("CR53 = %x\n", *(regs + S3_CRTC_DATA));
2370 *(regs + S3_CRTC_ADR) = 0x58;
2371 DPRINTK("CR58 = %x\n", *(regs + S3_CRTC_DATA));
2372 *(regs + S3_CRTC_ADR) = 0x59;
2373 DPRINTK("CR59 = %x\n", *(regs + S3_CRTC_DATA));
2374 *(regs + S3_CRTC_ADR) = 0x5A;
2375 DPRINTK("CR5A = %x\n", *(regs + S3_CRTC_DATA));
2376 *(regs + S3_CRTC_ADR) = 0x5D;
2377 DPRINTK("CR5D = %x\n", *(regs + S3_CRTC_DATA));
2378 *(regs + S3_CRTC_ADR) = 0x5E;
2379 DPRINTK("CR5E = %x\n", *(regs + S3_CRTC_DATA));
2380 DPRINTK("MISC = %x\n", *(regs + GREG_MISC_OUTPUT_R));
2381 *(regs + SEQ_ADDRESS) = 0x01;
2382 DPRINTK("SR01 = %x\n", *(regs + SEQ_ADDRESS_R));
2383 *(regs + SEQ_ADDRESS) = 0x02;
2384 DPRINTK("SR02 = %x\n", *(regs + SEQ_ADDRESS_R));
2385 *(regs + SEQ_ADDRESS) = 0x03;
2386 DPRINTK("SR03 = %x\n", *(regs + SEQ_ADDRESS_R));
2387 *(regs + SEQ_ADDRESS) = 0x09;
2388 DPRINTK("SR09 = %x\n", *(regs + SEQ_ADDRESS_R));
2389 *(regs + SEQ_ADDRESS) = 0x10;
2390 DPRINTK("SR10 = %x\n", *(regs + SEQ_ADDRESS_R));
2391 *(regs + SEQ_ADDRESS) = 0x11;
2392 DPRINTK("SR11 = %x\n", *(regs + SEQ_ADDRESS_R));
2393 *(regs + SEQ_ADDRESS) = 0x12;
2394 DPRINTK("SR12 = %x\n", *(regs + SEQ_ADDRESS_R));
2395 *(regs + SEQ_ADDRESS) = 0x13;
2396 DPRINTK("SR13 = %x\n", *(regs + SEQ_ADDRESS_R));
2397 *(regs + SEQ_ADDRESS) = 0x15;
2398 DPRINTK("SR15 = %x\n", *(regs + SEQ_ADDRESS_R));
2400 return;
2402 #endif