linux-old/drivers/video/cyberfb.c
<<
>>
Prefs
   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 $
   4*
   5*    Copyright (C) 1998 Alan Bair
   6*
   7* This file is based on two CyberVision64 frame buffer device drivers
   8*
   9* The second CyberVision64 frame buffer device (cvision.c cvision_core.c):
  10*
  11*   Copyright (c) 1997 Antonio Santos
  12*
  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.
  18*
  19*   Copyright (c) 1995 Michael Teske
  20*
  21* The first CyberVision64 frame buffer device (cyberfb.c):
  22*
  23*    Copyright (C) 1996 Martin Apel
  24*                       Geert Uytterhoeven
  25*
  26* Which is based on the Amiga frame buffer device (amifb.c):
  27*
  28*    Copyright (C) 1995 Geert Uytterhoeven
  29*
  30*
  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.
  39*
  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.
  43*
  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.
  48*
  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.
  53*
  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.
  57*
  58* Revision 1.1  1998/08/29 18:38:31  abair
  59* Initial revision
  60*
  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.
  65*
  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.
  70*
  71*
  72*
  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.
  76*/
  77
  78
  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/slab.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>
  96
  97#include "cyberfb.h"
  98#include <video/fbcon.h>
  99#include <video/fbcon-cfb8.h>
 100#include <video/fbcon-cfb16.h>
 101
 102/*#define CYBERFBDEBUG*/
 103#ifdef CYBERFBDEBUG
 104#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
 105static void cv64_dump(void);
 106#else
 107#define DPRINTK(fmt, args...)
 108#endif
 109
 110#define wb_64(regs,reg,dat) (*(((volatile unsigned char *)regs) + reg) = dat)
 111#define rb_64(regs, reg) (*(((volatile unsigned char *)regs) + reg))
 112
 113#define ww_64(regs,reg,dat) (*((volatile unsigned short *)(regs + reg) = dat)
 114
 115struct cyberfb_par {
 116        struct fb_var_screeninfo var;
 117        __u32 type;
 118        __u32 type_aux;
 119        __u32 visual;
 120        __u32 line_length;
 121};
 122
 123static struct cyberfb_par current_par;
 124
 125static int current_par_valid = 0;
 126static int currcon = 0;
 127
 128static struct display disp;
 129static struct fb_info fb_info;
 130
 131
 132/*
 133 *    Frame Buffer Name
 134 */
 135
 136static char cyberfb_name[16] = "Cybervision";
 137
 138
 139/*
 140 *    CyberVision Graphics Board
 141 */
 142
 143static unsigned char Cyber_colour_table [256][3];
 144static unsigned long CyberSize;
 145static volatile unsigned char *CyberBase;
 146static volatile unsigned char *CyberMem;
 147static volatile unsigned char *CyberRegs;
 148static unsigned long CyberMem_phys;
 149static unsigned long CyberRegs_phys;
 150
 151/*
 152 *    Predefined Video Modes
 153 */
 154
 155static 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
 187        }},
 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.
 191 */
 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
 198        }},
 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
 205        }},
 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
 212        }},
 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
 219        }}
 220};
 221
 222#define NUM_TOTAL_MODES    ARRAY_SIZE(cyberfb_predefined)
 223
 224static int Cyberfb_inverse = 0;
 225
 226/*
 227 *    Some default modes
 228 */
 229
 230#define CYBER8_DEFMODE     (0)
 231#define CYBER16_DEFMODE    (1)
 232
 233static struct fb_var_screeninfo cyberfb_default;
 234static int cyberfb_usermode __initdata = 0;
 235
 236/*
 237 *    Interface used by the world
 238 */
 239
 240int cyberfb_setup(char *options);
 241
 242static int cyberfb_get_fix(struct fb_fix_screeninfo *fix, int con,
 243                           struct fb_info *info);
 244static int cyberfb_get_var(struct fb_var_screeninfo *var, int con,
 245                           struct fb_info *info);
 246static int cyberfb_set_var(struct fb_var_screeninfo *var, int con,
 247                           struct fb_info *info);
 248static int cyberfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
 249                            struct fb_info *info);
 250static int cyberfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
 251                            struct fb_info *info);
 252
 253/*
 254 *    Interface to the low level console driver
 255 */
 256
 257int cyberfb_init(void);
 258static int Cyberfb_switch(int con, struct fb_info *info);
 259static int Cyberfb_updatevar(int con, struct fb_info *info);
 260static void Cyberfb_blank(int blank, struct fb_info *info);
 261
 262/*
 263 *    Text console acceleration
 264 */
 265
 266#ifdef FBCON_HAS_CFB8
 267static struct display_switch fbcon_cyber8;
 268#endif
 269
 270/*
 271 *    Accelerated Functions used by the low level console driver
 272 */
 273
 274static void Cyber_WaitQueue(u_short fifo);
 275static void Cyber_WaitBlit(void);
 276static 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);
 279static 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
 282static void Cyber_MoveCursor(u_short x, u_short y);
 283#endif
 284
 285/*
 286 *   Hardware Specific Routines
 287 */
 288
 289static int Cyber_init(void);
 290static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
 291                            struct cyberfb_par *par);
 292static int Cyber_decode_var(struct fb_var_screeninfo *var,
 293                            struct cyberfb_par *par);
 294static int Cyber_encode_var(struct fb_var_screeninfo *var,
 295                            struct cyberfb_par *par);
 296static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
 297                           u_int *transp, struct fb_info *info);
 298static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 299                           u_int transp, struct fb_info *info);
 300
 301/*
 302 *    Internal routines
 303 */
 304
 305static void cyberfb_get_par(struct cyberfb_par *par);
 306static void cyberfb_set_par(struct cyberfb_par *par);
 307static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
 308static void do_install_cmap(int con, struct fb_info *info);
 309static void cyberfb_set_disp(int con, struct fb_info *info);
 310static int get_video_mode(const char *name);
 311
 312/* For cvision_core.c */
 313static unsigned short cv64_compute_clock(unsigned long);
 314static int cv_has_4mb (volatile unsigned char *);
 315static void cv64_board_init (void);
 316static void cv64_load_video_mode (struct fb_var_screeninfo *);
 317
 318
 319/* -------------------- Hardware specific routines ------------------------- */
 320
 321
 322/*
 323 *    Initialization
 324 *
 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.
 327 */
 328
 329static int Cyber_init(void)
 330{
 331        volatile unsigned char *regs = CyberRegs;
 332        volatile unsigned long *CursorBase;
 333        int i;
 334        DPRINTK("ENTER\n");
 335
 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;
 341        }
 342
 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);
 352
 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);
 363
 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++)
 368        {
 369                *(CursorBase  +(i*4)) = 0xffffff00;
 370                *(CursorBase+1+(i*4)) = 0xffff0000;
 371                *(CursorBase+2+(i*4)) = 0xffff0000;
 372                *(CursorBase+3+(i*4)) = 0xffff0000;
 373        }
 374        for (i=8; i < 64; i++)
 375        {
 376                *(CursorBase  +(i*4)) = 0xffff0000;
 377                *(CursorBase+1+(i*4)) = 0xffff0000;
 378                *(CursorBase+2+(i*4)) = 0xffff0000;
 379                *(CursorBase+3+(i*4)) = 0xffff0000;
 380        }
 381
 382        Cyber_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, NULL /* unused */);
 383        Cyber_setcolreg (254, 0, 0, 0, 0, NULL /* unused */);
 384
 385        DPRINTK("EXIT\n");
 386        return 0;
 387}
 388
 389
 390/*
 391 *    This function should fill in the `fix' structure based on the
 392 *    values in the `par' structure.
 393 */
 394
 395static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
 396                            struct cyberfb_par *par)
 397{
 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;
 405
 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;
 413        }
 414
 415        fix->xpanstep = 0;
 416        fix->ypanstep = 0;
 417        fix->ywrapstep = 0;
 418        fix->line_length = 0;
 419        fix->accel = FB_ACCEL_S3_TRIO64;
 420
 421        DPRINTK("EXIT\n");
 422        return(0);
 423}
 424
 425
 426/*
 427*    Fill the `par' structure based on the values in `var'.
 428*    TODO: Verify and adjust values, return -EINVAL if bad.
 429*/
 430
 431static int Cyber_decode_var(struct fb_var_screeninfo *var,
 432                            struct cyberfb_par *par)
 433{
 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;
 455        }
 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);
 467}
 468
 469/*
 470*    Fill the `var' structure based on the values in `par' and maybe
 471*    other values read out of the hardware.
 472*/
 473
 474static int Cyber_encode_var(struct fb_var_screeninfo *var,
 475                            struct cyberfb_par *par)
 476{
 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;
 484
 485        var->bits_per_pixel = par->var.bits_per_pixel;
 486        var->grayscale = par->var.grayscale;
 487
 488        var->red = par->var.red;
 489        var->green = par->var.green;
 490        var->blue = par->var.blue;
 491        var->transp = par->var.transp;
 492
 493        var->nonstd = par->var.nonstd;
 494        var->activate = par->var.activate;
 495
 496        var->height = par->var.height;
 497        var->width = par->var.width;
 498
 499        var->accel_flags = par->var.accel_flags;
 500
 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;
 510        
 511        DPRINTK("EXIT\n");
 512        return(0);
 513}
 514
 515
 516/*
 517 *    Set a single color register. Return != 0 for invalid regno.
 518 */
 519
 520static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 521                           u_int transp, struct fb_info *info)
 522{
 523        volatile unsigned char *regs = CyberRegs;
 524
 525        /*DPRINTK("ENTER\n");*/
 526        if (regno > 255) {
 527                DPRINTK("EXIT - Register # > 255\n");
 528                return (1);
 529        }
 530
 531        wb_64(regs, 0x3c8, (unsigned char) regno);
 532
 533        red >>= 10;
 534        green >>= 10;
 535        blue >>= 10;
 536
 537        Cyber_colour_table [regno][0] = red;
 538        Cyber_colour_table [regno][1] = green;
 539        Cyber_colour_table [regno][2] = blue;
 540
 541        wb_64(regs, 0x3c9, red);
 542        wb_64(regs, 0x3c9, green);
 543        wb_64(regs, 0x3c9, blue);
 544
 545        /*DPRINTK("EXIT\n");*/
 546        return (0);
 547}
 548
 549
 550/*
 551*    Read a single color register and split it into
 552*    colors/transparent. Return != 0 for invalid regno.
 553*/
 554
 555static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
 556                           u_int *transp, struct fb_info *info)
 557{
 558        int t;
 559
 560        /*DPRINTK("ENTER\n");*/
 561        if (regno > 255) {
 562                DPRINTK("EXIT - Register # > 255\n");
 563                return (1);
 564        }
 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);
 575}
 576
 577
 578/*
 579*    (Un)Blank the screen
 580*    blank: 1 = zero fb cmap
 581*           0 = restore fb cmap from local cmap
 582*/
 583
 584void Cyberfb_blank(int blank, struct fb_info *info)
 585{
 586        volatile unsigned char *regs = CyberRegs;
 587        int i;
 588
 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);
 601                }
 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]);
 608                }
 609        }
 610#endif
 611        DPRINTK("EXIT\n");
 612}
 613
 614
 615/**************************************************************
 616 * We are waiting for "fifo" FIFO-slots empty
 617 */
 618static void Cyber_WaitQueue (u_short fifo)
 619{
 620        unsigned short status;
 621
 622        DPRINTK("ENTER\n");
 623        do {
 624                status = *((u_short volatile *)(CyberRegs + S3_GP_STAT));
 625        } while (status & fifo);
 626        DPRINTK("EXIT\n");
 627}
 628
 629/**************************************************************
 630 * We are waiting for Hardware (Graphics Engine) not busy
 631 */
 632static void Cyber_WaitBlit (void)
 633{
 634        unsigned short status;
 635
 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");
 641}
 642
 643/**************************************************************
 644 * BitBLT - Through the Plane
 645 */
 646static 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)
 649{
 650        volatile unsigned char *regs = CyberRegs;
 651        u_short blitcmd = S3_BITBLT;
 652
 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);
 661        }
 662
 663        if (cury > desty) {
 664                blitcmd |= 0x0080;  /* Drawing direction +Y */
 665        } else {
 666                cury  += (height - 1);
 667                desty += (height - 1);
 668        }
 669
 670        Cyber_WaitQueue (0x8000);
 671
 672        *((u_short volatile *)(regs + S3_PIXEL_CNTL)) = 0xa000;
 673        *((u_short volatile *)(regs + S3_FRGD_MIX)) = (0x0060 | mode);
 674
 675        *((u_short volatile *)(regs + S3_CUR_X)) = curx;
 676        *((u_short volatile *)(regs + S3_CUR_Y)) = cury;
 677
 678        *((u_short volatile *)(regs + S3_DESTX_DIASTP)) = destx;
 679        *((u_short volatile *)(regs + S3_DESTY_AXSTP)) = desty;
 680
 681        *((u_short volatile *)(regs + S3_MIN_AXIS_PCNT)) = height - 1;
 682        *((u_short volatile *)(regs + S3_MAJ_AXIS_PCNT)) = width  - 1;
 683
 684        *((u_short volatile *)(regs + S3_CMD)) = blitcmd;
 685        DPRINTK("EXIT\n");
 686}
 687
 688/**************************************************************
 689 * Rectangle Fill Solid
 690 */
 691static void Cyber_RectFill (u_short x, u_short y, u_short width,
 692                            u_short height, u_short mode, u_short color)
 693{
 694        volatile unsigned char *regs = CyberRegs;
 695        u_short blitcmd = S3_FILLEDRECT;
 696
 697        DPRINTK("ENTER\n");
 698        Cyber_WaitQueue (0x8000);
 699
 700        *((u_short volatile *)(regs + S3_PIXEL_CNTL)) = 0xa000;
 701        *((u_short volatile *)(regs + S3_FRGD_MIX)) = (0x0020 | mode);
 702
 703        *((u_short volatile *)(regs + S3_MULT_MISC)) = 0xe000;
 704        *((u_short volatile *)(regs + S3_FRGD_COLOR)) = color;
 705
 706        *((u_short volatile *)(regs + S3_CUR_X)) = x;
 707        *((u_short volatile *)(regs + S3_CUR_Y)) = y;
 708
 709        *((u_short volatile *)(regs + S3_MIN_AXIS_PCNT)) = height - 1;
 710        *((u_short volatile *)(regs + S3_MAJ_AXIS_PCNT)) = width  - 1;
 711
 712        *((u_short volatile *)(regs + S3_CMD)) = blitcmd;
 713        DPRINTK("EXIT\n");
 714}
 715
 716
 717#if 0
 718/**************************************************************
 719 * Move cursor to x, y
 720 */
 721static void Cyber_MoveCursor (u_short x, u_short y)
 722{
 723        volatile unsigned char *regs = CyberRegs;
 724        DPRINTK("ENTER\n");
 725        *(regs + S3_CRTC_ADR)  = 0x39;
 726        *(regs + S3_CRTC_DATA) = 0xa0;
 727
 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);
 732
 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");
 738}
 739#endif
 740
 741
 742/* -------------------- Generic routines ---------------------------------- */
 743
 744
 745/*
 746 *    Fill the hardware's `par' structure.
 747 */
 748
 749static void cyberfb_get_par(struct cyberfb_par *par)
 750{
 751        DPRINTK("ENTER\n");
 752        if (current_par_valid) {
 753                *par = current_par;
 754        } else {
 755                Cyber_decode_var(&cyberfb_default, par);
 756        }
 757        DPRINTK("EXIT\n");
 758}
 759
 760
 761static void cyberfb_set_par(struct cyberfb_par *par)
 762{
 763        DPRINTK("ENTER\n");
 764        current_par = *par;
 765        current_par_valid = 1;
 766        DPRINTK("EXIT\n");
 767}
 768
 769
 770static void cyber_set_video(struct fb_var_screeninfo *var)
 771{
 772
 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
 779}
 780
 781
 782static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
 783{
 784        int err, activate;
 785        struct cyberfb_par par;
 786
 787        DPRINTK("ENTER\n");
 788        if ((err = Cyber_decode_var(var, &par))) {
 789                DPRINTK("EXIT - decode_var failed\n");
 790                return(err);
 791        }
 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;
 797
 798        cyber_set_video(var);
 799        DPRINTK("EXIT\n");
 800        return 0;
 801}
 802
 803
 804static void do_install_cmap(int con, struct fb_info *info)
 805{
 806        DPRINTK("ENTER\n");
 807        if (con != currcon) {
 808                DPRINTK("EXIT - Not current console\n");
 809                return;
 810        }
 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);
 818        }
 819        DPRINTK("EXIT\n");
 820}
 821
 822/*
 823 *    Get the Fixed Part of the Display
 824 */
 825
 826static int cyberfb_get_fix(struct fb_fix_screeninfo *fix, int con,
 827                           struct fb_info *info)
 828{
 829        struct cyberfb_par par;
 830        int error = 0;
 831
 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);
 837        }
 838        DPRINTK("EXIT\n");
 839        return(error ? error : Cyber_encode_fix(fix, &par));
 840}
 841
 842
 843/*
 844 *    Get the User Defined Part of the Display
 845 */
 846
 847static int cyberfb_get_var(struct fb_var_screeninfo *var, int con,
 848                           struct fb_info *info)
 849{
 850        struct cyberfb_par par;
 851        int error = 0;
 852
 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;
 860        }
 861
 862        DPRINTK("EXIT\n");
 863        return(error);
 864}
 865
 866
 867static void cyberfb_set_disp(int con, struct fb_info *info)
 868{
 869        struct fb_fix_screeninfo fix;
 870        struct display *display;
 871
 872        DPRINTK("ENTER\n");
 873        if (con >= 0)
 874                display = &fb_display[con];
 875        else
 876                display = &disp;        /* used during initialization */
 877
 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;
 907        }
 908        DPRINTK("EXIT\n");
 909}
 910
 911
 912/*
 913 *    Set the User Defined Part of the Display
 914 */
 915
 916static int cyberfb_set_var(struct fb_var_screeninfo *var, int con,
 917                           struct fb_info *info)
 918{
 919        int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel;
 920
 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);
 925        }
 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);
 943                }
 944        }
 945        var->activate = 0;
 946        DPRINTK("EXIT\n");
 947        return(0);
 948}
 949
 950
 951/*
 952 *    Get the Colormap
 953 */
 954
 955static int cyberfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
 956                            struct fb_info *info)
 957{
 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);
 969        }
 970        DPRINTK("EXIT\n");
 971        return(0);
 972}
 973
 974
 975/*
 976 *    Set the Colormap
 977 */
 978
 979static int cyberfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
 980                            struct fb_info *info)
 981{
 982        int err;
 983
 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);
 991                }
 992        }
 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);
 998        }
 999        DPRINTK("EXIT\n");
1000        return(0);
1001}
1002
1003
1004static 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,
1011};
1012
1013int __init cyberfb_setup(char *options)
1014{
1015        char *this_opt;
1016        DPRINTK("ENTER\n");
1017
1018        fb_info.fontname[0] = '\0';
1019
1020        if (!options || !*options) {
1021                DPRINTK("EXIT - no options\n");
1022                return 0;
1023        }
1024
1025        while ((this_opt = strsep(&options, ",")) != NULL) {
1026                if (!*this_opt)
1027                        continue;
1028                if (!strcmp(this_opt, "inverse")) {
1029                        Cyberfb_inverse = 1;
1030                        fb_invert_cmaps();
1031                } else if (!strncmp(this_opt, "font:", 5)) {
1032                        strcpy(fb_info.fontname, this_opt+5);
1033                } else if (!strcmp (this_opt, "cyber8")) {
1034                        cyberfb_default = cyberfb_predefined[CYBER8_DEFMODE].var;
1035                        cyberfb_usermode = 1;
1036                } else if (!strcmp (this_opt, "cyber16")) {
1037                        cyberfb_default = cyberfb_predefined[CYBER16_DEFMODE].var;
1038                        cyberfb_usermode = 1;
1039                } else get_video_mode(this_opt);
1040        }
1041
1042        DPRINTK("default mode: xres=%d, yres=%d, bpp=%d\n",
1043                cyberfb_default.xres,
1044                cyberfb_default.yres,
1045                cyberfb_default.bits_per_pixel);
1046        DPRINTK("EXIT\n");
1047        return 0;
1048}
1049
1050/*
1051 *    Initialization
1052 */
1053
1054int __init cyberfb_init(void)
1055{
1056        unsigned long board_addr, board_size;
1057        struct cyberfb_par par;
1058        struct zorro_dev *z = NULL;
1059        DPRINTK("ENTER\n");
1060
1061        while ((z = zorro_find_device(ZORRO_PROD_PHASE5_CYBERVISION64, z))) {
1062            board_addr = z->resource.start;
1063            board_size = z->resource.end-z->resource.start+1;
1064            CyberMem_phys = board_addr + 0x01400000;
1065            CyberRegs_phys = CyberMem_phys + 0x00c00000;
1066            if (!request_mem_region(CyberRegs_phys, 0x10000, "S3 Trio64"))
1067                continue;
1068            if (!request_mem_region(CyberMem_phys, 0x400000, "RAM")) {
1069                release_mem_region(CyberRegs_phys, 0x10000);
1070                continue;
1071            }
1072            DPRINTK("board_addr=%08lx\n", board_addr);
1073            DPRINTK("board_size=%08lx\n", board_size);
1074
1075            CyberBase = ioremap(board_addr, board_size);
1076            CyberRegs = CyberBase + 0x02000000;
1077            CyberMem = CyberBase + 0x01400000;
1078            DPRINTK("CyberBase=%08lx CyberRegs=%08lx CyberMem=%08lx\n",
1079                    CyberBase, (long unsigned int)CyberRegs, CyberMem);
1080
1081#ifdef CYBERFBDEBUG
1082            DPRINTK("Register state just after mapping memory\n");
1083            cv64_dump();
1084#endif
1085
1086            strcpy(fb_info.modename, cyberfb_name);
1087            fb_info.changevar = NULL;
1088            fb_info.node = -1;
1089            fb_info.fbops = &cyberfb_ops;
1090            fb_info.disp = &disp;
1091            fb_info.switch_con = &Cyberfb_switch;
1092            fb_info.updatevar = &Cyberfb_updatevar;
1093            fb_info.blank = &Cyberfb_blank;
1094
1095            Cyber_init();
1096            /* ++Andre: set cyberfb default mode */
1097            if (!cyberfb_usermode) {
1098                    cyberfb_default = cyberfb_predefined[CYBER8_DEFMODE].var;
1099                    DPRINTK("Use default cyber8 mode\n");
1100            }
1101            Cyber_decode_var(&cyberfb_default, &par);
1102            Cyber_encode_var(&cyberfb_default, &par);
1103
1104            do_fb_set_var(&cyberfb_default, 1);
1105            cyberfb_get_var(&fb_display[0].var, -1, &fb_info);
1106            cyberfb_set_disp(-1, &fb_info);
1107            do_install_cmap(0, &fb_info);
1108
1109            if (register_framebuffer(&fb_info) < 0) {
1110                    DPRINTK("EXIT - register_framebuffer failed\n");
1111                    release_mem_region(CyberMem_phys, 0x400000);
1112                    release_mem_region(CyberRegs_phys, 0x10000);
1113                    return -EINVAL;
1114            }
1115
1116            printk("fb%d: %s frame buffer device, using %ldK of video memory\n",
1117                   GET_FB_IDX(fb_info.node), fb_info.modename, CyberSize>>10);
1118
1119            /* TODO: This driver cannot be unloaded yet */
1120            MOD_INC_USE_COUNT;
1121            DPRINTK("EXIT\n");
1122            return 0;
1123        }
1124        return -ENXIO;
1125}
1126
1127
1128static int Cyberfb_switch(int con, struct fb_info *info)
1129{
1130        DPRINTK("ENTER\n");
1131        /* Do we have to save the colormap? */
1132        if (fb_display[currcon].cmap.len) {
1133                fb_get_cmap(&fb_display[currcon].cmap, 1, Cyber_getcolreg,
1134                            info);
1135        }
1136
1137        do_fb_set_var(&fb_display[con].var, 1);
1138        currcon = con;
1139        /* Install new colormap */
1140        do_install_cmap(con, info);
1141        DPRINTK("EXIT\n");
1142        return(0);
1143}
1144
1145
1146/*
1147 *    Update the `var' structure (called by fbcon.c)
1148 *
1149 *    This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
1150 *    Since it's called by a kernel driver, no range checking is done.
1151 */
1152
1153static int Cyberfb_updatevar(int con, struct fb_info *info)
1154{
1155        DPRINTK("Enter - Exit\n");
1156        return(0);
1157}
1158
1159
1160/*
1161 *    Get a Video Mode
1162 */
1163
1164static int __init get_video_mode(const char *name)
1165{
1166        int i;
1167
1168        DPRINTK("ENTER\n");
1169        for (i = 0; i < NUM_TOTAL_MODES; i++) {
1170                if (!strcmp(name, cyberfb_predefined[i].name)) {
1171                        cyberfb_default = cyberfb_predefined[i].var;
1172                        cyberfb_usermode = 1;
1173                        DPRINTK("EXIT - Matched predefined mode\n");
1174                        return(i);
1175                }
1176        }
1177        return(0);
1178}
1179
1180
1181/*
1182 *    Text console acceleration
1183 */
1184
1185#ifdef FBCON_HAS_CFB8
1186static void fbcon_cyber8_bmove(struct display *p, int sy, int sx, int dy,
1187                               int dx, int height, int width)
1188{
1189        DPRINTK("ENTER\n");
1190        sx *= 8; dx *= 8; width *= 8;
1191        Cyber_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx,
1192                     (u_short)(dy*fontheight(p)), (u_short)width,
1193                     (u_short)(height*fontheight(p)), (u_short)S3_NEW);
1194        DPRINTK("EXIT\n");
1195}
1196
1197static void fbcon_cyber8_clear(struct vc_data *conp, struct display *p, int sy,
1198                               int sx, int height, int width)
1199{
1200        unsigned char bg;
1201
1202        DPRINTK("ENTER\n");
1203        sx *= 8; width *= 8;
1204        bg = attr_bgcol_ec(p,conp);
1205        Cyber_RectFill((u_short)sx,
1206                       (u_short)(sy*fontheight(p)),
1207                       (u_short)width,
1208                       (u_short)(height*fontheight(p)),
1209                       (u_short)S3_NEW,
1210                       (u_short)bg);
1211        DPRINTK("EXIT\n");
1212}
1213
1214static void fbcon_cyber8_putc(struct vc_data *conp, struct display *p, int c,
1215                              int yy, int xx)
1216{
1217        DPRINTK("ENTER\n");
1218        Cyber_WaitBlit();
1219        fbcon_cfb8_putc(conp, p, c, yy, xx);
1220        DPRINTK("EXIT\n");
1221}
1222
1223static void fbcon_cyber8_putcs(struct vc_data *conp, struct display *p,
1224                               const unsigned short *s, int count,
1225                               int yy, int xx)
1226{
1227        DPRINTK("ENTER\n");
1228        Cyber_WaitBlit();
1229        fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
1230        DPRINTK("EXIT\n");
1231}
1232
1233static void fbcon_cyber8_revc(struct display *p, int xx, int yy)
1234{
1235        DPRINTK("ENTER\n");
1236        Cyber_WaitBlit();
1237        fbcon_cfb8_revc(p, xx, yy);
1238        DPRINTK("EXIT\n");
1239}
1240
1241static struct display_switch fbcon_cyber8 = {
1242        setup:          fbcon_cfb8_setup,
1243        bmove:          fbcon_cyber8_bmove,
1244        clear:          fbcon_cyber8_clear,
1245        putc:           fbcon_cyber8_putc,
1246        putcs:          fbcon_cyber8_putcs,
1247        revc:           fbcon_cyber8_revc,
1248        clear_margins:  fbcon_cfb8_clear_margins,
1249        fontwidthmask:  FONTWIDTH(8)
1250};
1251#endif
1252
1253
1254#ifdef MODULE
1255MODULE_LICENSE("GPL");
1256
1257int init_module(void)
1258{
1259        return cyberfb_init();
1260}
1261
1262void cleanup_module(void)
1263{
1264        /* Not reached because the usecount will never be
1265           decremented to zero */
1266        unregister_framebuffer(&fb_info);
1267        /* TODO: clean up ... */
1268}
1269#endif /* MODULE */
1270
1271/*
1272 *
1273 * Low level initialization routines for the CyberVision64 graphics card
1274 *
1275 * Most of the following code is from cvision_core.c
1276 *
1277 */
1278
1279#define MAXPIXELCLOCK 135000000 /* safety */
1280
1281#ifdef CV_AGGRESSIVE_TIMING
1282long cv64_memclk = 55000000;
1283#else
1284long cv64_memclk = 50000000;
1285#endif
1286
1287/*********************/
1288
1289static unsigned char clocks[]={
1290  0x13, 0x61, 0x6b, 0x6d, 0x51, 0x69, 0x54, 0x69,
1291  0x4f, 0x68, 0x6b, 0x6b, 0x18, 0x61, 0x7b, 0x6c,
1292  0x51, 0x67, 0x24, 0x62, 0x56, 0x67, 0x77, 0x6a,
1293  0x1d, 0x61, 0x53, 0x66, 0x6b, 0x68, 0x79, 0x69,
1294  0x7c, 0x69, 0x7f, 0x69, 0x22, 0x61, 0x54, 0x65,
1295  0x56, 0x65, 0x58, 0x65, 0x67, 0x66, 0x41, 0x63,
1296  0x27, 0x61, 0x13, 0x41, 0x37, 0x62, 0x6b, 0x4d,
1297  0x23, 0x43, 0x51, 0x49, 0x79, 0x66, 0x54, 0x49,
1298  0x7d, 0x66, 0x34, 0x56, 0x4f, 0x63, 0x1f, 0x42,
1299  0x6b, 0x4b, 0x7e, 0x4d, 0x18, 0x41, 0x2a, 0x43,
1300  0x7b, 0x4c, 0x74, 0x4b, 0x51, 0x47, 0x65, 0x49,
1301  0x24, 0x42, 0x68, 0x49, 0x56, 0x47, 0x75, 0x4a,
1302  0x77, 0x4a, 0x31, 0x43, 0x1d, 0x41, 0x71, 0x49,
1303  0x53, 0x46, 0x29, 0x42, 0x6b, 0x48, 0x1f, 0x41,
1304  0x79, 0x49, 0x6f, 0x48, 0x7c, 0x49, 0x38, 0x43,
1305  0x7f, 0x49, 0x5d, 0x46, 0x22, 0x41, 0x53, 0x45,
1306  0x54, 0x45, 0x55, 0x45, 0x56, 0x45, 0x57, 0x45,
1307  0x58, 0x45, 0x25, 0x41, 0x67, 0x46, 0x5b, 0x45,
1308  0x41, 0x43, 0x78, 0x47, 0x27, 0x41, 0x51, 0x44,
1309  0x13, 0x21, 0x7d, 0x47, 0x37, 0x42, 0x71, 0x46,
1310  0x6b, 0x2d, 0x14, 0x21, 0x23, 0x23, 0x7d, 0x2f,
1311  0x51, 0x29, 0x61, 0x2b, 0x79, 0x46, 0x1d, 0x22,
1312  0x54, 0x29, 0x45, 0x27, 0x7d, 0x46, 0x7f, 0x46,
1313  0x4f, 0x43, 0x2f, 0x41, 0x1f, 0x22, 0x6a, 0x2b,
1314  0x6b, 0x2b, 0x5b, 0x29, 0x7e, 0x2d, 0x65, 0x44,
1315  0x18, 0x21, 0x5e, 0x29, 0x2a, 0x23, 0x45, 0x26,
1316  0x7b, 0x2c, 0x19, 0x21, 0x74, 0x2b, 0x75, 0x2b,
1317  0x51, 0x27, 0x3f, 0x25, 0x65, 0x29, 0x40, 0x25,
1318  0x24, 0x22, 0x41, 0x25, 0x68, 0x29, 0x42, 0x25,
1319  0x56, 0x27, 0x7e, 0x2b, 0x75, 0x2a, 0x1c, 0x21,
1320  0x77, 0x2a, 0x4f, 0x26, 0x31, 0x23, 0x6f, 0x29,
1321  0x1d, 0x21, 0x32, 0x23, 0x71, 0x29, 0x72, 0x29,
1322  0x53, 0x26, 0x69, 0x28, 0x29, 0x22, 0x75, 0x29,
1323  0x6b, 0x28, 0x1f, 0x21, 0x1f, 0x21, 0x6d, 0x28,
1324  0x79, 0x29, 0x2b, 0x22, 0x6f, 0x28, 0x59, 0x26,
1325  0x7c, 0x29, 0x7d, 0x29, 0x38, 0x23, 0x21, 0x21,
1326  0x7f, 0x29, 0x39, 0x23, 0x5d, 0x26, 0x75, 0x28,
1327  0x22, 0x21, 0x77, 0x28, 0x53, 0x25, 0x6c, 0x27,
1328  0x54, 0x25, 0x61, 0x26, 0x55, 0x25, 0x30, 0x22,
1329  0x56, 0x25, 0x63, 0x26, 0x57, 0x25, 0x71, 0x27,
1330  0x58, 0x25, 0x7f, 0x28, 0x25, 0x21, 0x74, 0x27,
1331  0x67, 0x26, 0x40, 0x23, 0x5b, 0x25, 0x26, 0x21,
1332  0x41, 0x23, 0x34, 0x22, 0x78, 0x27, 0x6b, 0x26,
1333  0x27, 0x21, 0x35, 0x22, 0x51, 0x24, 0x7b, 0x27,
1334  0x13, 0x1,  0x13, 0x1,  0x7d, 0x27, 0x4c, 0x9,
1335  0x37, 0x22, 0x5b, 0xb,  0x71, 0x26, 0x5c, 0xb,
1336  0x6b, 0xd,  0x47, 0x23, 0x14, 0x1,  0x4f, 0x9,
1337  0x23, 0x3,  0x75, 0x26, 0x7d, 0xf,  0x1c, 0x2,
1338  0x51, 0x9,  0x59, 0x24, 0x61, 0xb,  0x69, 0x25,
1339  0x79, 0x26, 0x34, 0x5,  0x1d, 0x2,  0x6b, 0x25,
1340  0x54, 0x9,  0x35, 0x5,  0x45, 0x7,  0x6d, 0x25,
1341  0x7d, 0x26, 0x16, 0x1,  0x7f, 0x26, 0x77, 0xd,
1342  0x4f, 0x23, 0x78, 0xd,  0x2f, 0x21, 0x27, 0x3,
1343  0x1f, 0x2,  0x59, 0x9,  0x6a, 0xb,  0x73, 0x25,
1344  0x6b, 0xb,  0x63, 0x24, 0x5b, 0x9,  0x20, 0x2,
1345  0x7e, 0xd,  0x4b, 0x7,  0x65, 0x24, 0x43, 0x22,
1346  0x18, 0x1,  0x6f, 0xb,  0x5e, 0x9,  0x70, 0xb,
1347  0x2a, 0x3,  0x33, 0x4,  0x45, 0x6,  0x60, 0x9,
1348  0x7b, 0xc,  0x19, 0x1,  0x19, 0x1,  0x7d, 0xc,
1349  0x74, 0xb,  0x50, 0x7,  0x75, 0xb,  0x63, 0x9,
1350  0x51, 0x7,  0x23, 0x2,  0x3f, 0x5,  0x1a, 0x1,
1351  0x65, 0x9,  0x2d, 0x3,  0x40, 0x5,  0x0,  0x0,
1352};
1353
1354/* Console colors */
1355unsigned char cvconscolors[16][3] = {   /* background, foreground, hilite */
1356  /*  R     G     B  */
1357  {0x30, 0x30, 0x30},
1358  {0x00, 0x00, 0x00},
1359  {0x80, 0x00, 0x00},
1360  {0x00, 0x80, 0x00},
1361  {0x00, 0x00, 0x80},
1362  {0x80, 0x80, 0x00},
1363  {0x00, 0x80, 0x80},
1364  {0x80, 0x00, 0x80},
1365  {0xff, 0xff, 0xff},
1366  {0x40, 0x40, 0x40},
1367  {0xff, 0x00, 0x00},
1368  {0x00, 0xff, 0x00},
1369  {0x00, 0x00, 0xff},
1370  {0xff, 0xff, 0x00},
1371  {0x00, 0xff, 0xff},
1372  {0x00, 0x00, 0xff}
1373};
1374
1375/* -------------------- Hardware specific routines ------------------------- */
1376
1377/* Read Attribute Controller Register=idx */
1378inline unsigned char RAttr (volatile unsigned char *regs, short idx)
1379{
1380        wb_64 (regs, ACT_ADDRESS_W, idx);
1381        mb();
1382        udelay(100);
1383        return (rb_64(regs, ACT_ADDRESS_R));
1384}
1385
1386/* Read Sequencer Register=idx */
1387inline unsigned char RSeq (volatile unsigned char *regs, short idx)
1388{
1389        wb_64 (regs, SEQ_ADDRESS, idx);
1390        mb();
1391        return (rb_64(regs, SEQ_ADDRESS_R));
1392}
1393
1394/* Read CRT Controller Register=idx */
1395inline unsigned char RCrt (volatile unsigned char *regs, short idx)
1396{
1397        wb_64 (regs, CRT_ADDRESS, idx);
1398        mb();
1399        return (rb_64(regs, CRT_ADDRESS_R));
1400}
1401
1402/* Read Graphics Controller Register=idx */
1403inline unsigned char RGfx (volatile unsigned char *regs, short idx)
1404{
1405        wb_64 (regs, GCT_ADDRESS, idx);
1406        mb();
1407        return (rb_64(regs, GCT_ADDRESS_R));
1408}
1409
1410/*
1411 * Special wakeup/passthrough registers on graphics boards
1412 */
1413
1414inline void cv64_write_port (unsigned short bits,
1415                             volatile unsigned char *base)
1416{
1417        volatile unsigned char *addr;
1418        static unsigned char cvportbits = 0; /* Mirror port bits here */
1419        DPRINTK("ENTER\n");
1420
1421        addr = base + 0x40001;
1422        if (bits & 0x8000) {
1423                cvportbits |= bits & 0xff; /* Set bits */
1424                DPRINTK("Set bits: %04x\n", bits);
1425        } else {
1426                bits = bits & 0xff;
1427                bits = (~bits) & 0xff;
1428                cvportbits &= bits; /* Clear bits */
1429                DPRINTK("Clear bits: %04x\n", bits);
1430        }
1431
1432        *addr = cvportbits;
1433        DPRINTK("EXIT\n");
1434}
1435
1436/*
1437 * Monitor switch on CyberVision board
1438 *
1439 *  toggle:
1440 *    0 = CyberVision Signal
1441 *    1 = Amiga Signal
1442 *  board = board addr
1443 *
1444 */
1445inline void cvscreen (int toggle, volatile unsigned char *board)
1446{
1447        DPRINTK("ENTER\n");
1448        if (toggle == 1) {
1449                DPRINTK("Show Amiga video\n");
1450                cv64_write_port (0x10, board);
1451        } else {
1452                DPRINTK("Show CyberVision video\n");
1453                cv64_write_port (0x8010, board);
1454        }
1455        DPRINTK("EXIT\n");
1456}
1457
1458/* Control screen display */
1459/* toggle: 0 = on, 1 = off */
1460/* board = registerbase */
1461inline void gfx_on_off(int toggle, volatile unsigned char *regs)
1462{
1463        int r;
1464        DPRINTK("ENTER\n");
1465        
1466        toggle &= 0x1;
1467        toggle = toggle << 5;
1468        DPRINTK("Turn display %s\n", (toggle ? "off" : "on"));
1469        
1470        r = (int) RSeq(regs, SEQ_ID_CLOCKING_MODE);
1471        r &= 0xdf;      /* Set bit 5 to 0 */
1472        
1473        WSeq (regs, SEQ_ID_CLOCKING_MODE, r | toggle);
1474        DPRINTK("EXIT\n");
1475}
1476
1477/*
1478 * Computes M, N, and R values from
1479 * given input frequency. It uses a table of
1480 * precomputed values, to keep CPU time low.
1481 *
1482 * The return value consist of:
1483 * lower byte:  Bits 4-0: N Divider Value
1484 *              Bits 5-6: R Value          for e.g. SR10 or SR12
1485 * higher byte: Bits 0-6: M divider value  for e.g. SR11 or SR13
1486 */
1487static unsigned short cv64_compute_clock(unsigned long freq)
1488{
1489        static unsigned char *mnr, *save;       /* M, N + R vals */
1490        unsigned long work_freq, r;
1491        unsigned short erg;
1492        long diff, d2;
1493
1494        DPRINTK("ENTER\n");
1495        if (freq < 12500000 || freq > MAXPIXELCLOCK) {
1496                printk("CV64 driver: Illegal clock frequency %ld, using 25MHz\n",
1497                       freq);
1498                freq = 25000000;
1499        }
1500        DPRINTK("Freq = %ld\n", freq);
1501        mnr = clocks;   /* there the vals are stored */
1502        d2 = 0x7fffffff;
1503
1504        while (*mnr) {  /* mnr vals are 0-terminated */
1505                work_freq = (0x37EE * (mnr[0] + 2)) / ((mnr[1] & 0x1F) + 2);
1506
1507                r = (mnr[1] >> 5) & 0x03;
1508                if (r != 0) {
1509                        work_freq = work_freq >> r;     /* r is the freq divider */
1510                }
1511
1512                work_freq *= 0x3E8;     /* 2nd part of OSC */
1513
1514                diff = abs(freq - work_freq);
1515
1516                if (d2 >= diff) {
1517                        d2 = diff;
1518                        /* In save are the vals for minimal diff */
1519                        save = mnr;
1520                }
1521                mnr += 2;
1522        }
1523        erg = *((unsigned short *)save);
1524
1525        DPRINTK("EXIT\n");
1526        return (erg);
1527}
1528
1529static int cv_has_4mb (volatile unsigned char *fb)
1530{
1531        volatile unsigned long *tr, *tw;
1532        DPRINTK("ENTER\n");
1533
1534        /* write patterns in memory and test if they can be read */
1535        tw = (volatile unsigned long *) fb;
1536        tr = (volatile unsigned long *) (fb + 0x02000000);
1537
1538        *tw = 0x87654321;
1539        
1540        if (*tr != 0x87654321) {
1541                DPRINTK("EXIT - <4MB\n");
1542                return (0);
1543        }
1544
1545        /* upper memory region */
1546        tw = (volatile unsigned long *) (fb + 0x00200000);
1547        tr = (volatile unsigned long *) (fb + 0x02200000);
1548
1549        *tw = 0x87654321;
1550
1551        if (*tr != 0x87654321) {
1552                DPRINTK("EXIT - <4MB\n");
1553                return (0);
1554        }
1555
1556        *tw = 0xAAAAAAAA;
1557
1558        if (*tr != 0xAAAAAAAA) {
1559                DPRINTK("EXIT - <4MB\n");
1560                return (0);
1561        }
1562
1563        *tw = 0x55555555;
1564
1565        if (*tr != 0x55555555) {
1566                DPRINTK("EXIT - <4MB\n");
1567                return (0);
1568        }
1569
1570        DPRINTK("EXIT\n");
1571        return (1);
1572}
1573
1574static void cv64_board_init (void)
1575{
1576        volatile unsigned char *regs = CyberRegs;
1577        int i;
1578        unsigned int clockpar;
1579        unsigned char test;
1580        
1581        DPRINTK("ENTER\n");
1582
1583        /*
1584         * Special CyberVision 64 board operations
1585         */
1586        /* Reset board */
1587        for (i = 0; i < 6; i++) {
1588                cv64_write_port (0xff, CyberBase);
1589        }
1590        /* Return to operational mode */
1591        cv64_write_port (0x8004, CyberBase);
1592        
1593        /*
1594         * Generic (?) S3 chip wakeup
1595         */
1596        /* Disable I/O & memory decoders, video in setup mode */
1597        wb_64 (regs, SREG_VIDEO_SUBS_ENABLE, 0x10);
1598        /* Video responds to cmds, addrs & data */
1599        wb_64 (regs, SREG_OPTION_SELECT, 0x1);
1600        /* Enable I/O & memory decoders, video in operational mode */
1601        wb_64 (regs, SREG_VIDEO_SUBS_ENABLE, 0x8);
1602        /* VGA color emulation, enable cpu access to display mem */ 
1603        wb_64 (regs, GREG_MISC_OUTPUT_W, 0x03);
1604        /* Unlock S3 VGA regs */
1605        WCrt (regs, CRT_ID_REGISTER_LOCK_1, 0x48); 
1606        /* Unlock system control & extension registers */
1607        WCrt (regs, CRT_ID_REGISTER_LOCK_2, 0xA5);
1608/* GRF - Enable interrupts */
1609        /* Enable enhanced regs access, Ready cntl 0 wait states */
1610        test = RCrt (regs, CRT_ID_SYSTEM_CONFIG);
1611        test = test | 0x01;             /* enable enhanced register access */
1612        test = test & 0xEF;             /* clear bit 4, 0 wait state */
1613        WCrt (regs, CRT_ID_SYSTEM_CONFIG, test);
1614        /*
1615         * bit 0=1: Enable enhaced mode functions
1616         * bit 2=0: Enhanced mode 8+ bits/pixel
1617         * bit 4=1: Enable linear addressing
1618         * bit 5=1: Enable MMIO
1619         */
1620        wb_64 (regs, ECR_ADV_FUNC_CNTL, 0x31);
1621        /*
1622         * bit 0=1: Color emulation
1623         * bit 1=1: Enable CPU access to display memory
1624         * bit 5=1: Select high 64K memory page
1625         */
1626/* GRF - 0xE3 */
1627        wb_64 (regs, GREG_MISC_OUTPUT_W, 0x23);
1628        
1629        /* Cpu base addr */
1630        WCrt (regs, CRT_ID_EXT_SYS_CNTL_4, 0x0);
1631        
1632        /* Reset. This does nothing on Trio, but standard VGA practice */
1633        /* WSeq (CyberRegs, SEQ_ID_RESET, 0x03); */
1634        /* Character clocks 8 dots wide */
1635        WSeq (regs, SEQ_ID_CLOCKING_MODE, 0x01);
1636        /* Enable cpu write to all color planes */
1637        WSeq (regs, SEQ_ID_MAP_MASK, 0x0F);
1638        /* Font table in 1st 8k of plane 2, font A=B disables swtich */
1639        WSeq (regs, SEQ_ID_CHAR_MAP_SELECT, 0x0);
1640        /* Allow mem access to 256kb */
1641        WSeq (regs, SEQ_ID_MEMORY_MODE, 0x2);
1642        /* Unlock S3 extensions to VGA Sequencer regs */
1643        WSeq (regs, SEQ_ID_UNLOCK_EXT, 0x6);
1644        
1645        /* Enable 4MB fast page mode */
1646        test = RSeq (regs, SEQ_ID_BUS_REQ_CNTL);
1647        test = test | 1 << 6;
1648        WSeq (regs, SEQ_ID_BUS_REQ_CNTL, test);
1649        
1650        /* Faster LUT write: 1 DCLK LUT write cycle, RAMDAC clk doubled */
1651        WSeq (regs, SEQ_ID_RAMDAC_CNTL, 0xC0);
1652
1653        /* Clear immediate clock load bit */
1654        test = RSeq (regs, SEQ_ID_CLKSYN_CNTL_2);
1655        test = test & 0xDF;
1656        /* If > 55MHz, enable 2 cycle memory write */
1657        if (cv64_memclk >= 55000000) {
1658                test |= 0x80;
1659        }
1660        WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, test);
1661
1662        /* Set MCLK value */
1663        clockpar = cv64_compute_clock (cv64_memclk);
1664        test = (clockpar & 0xFF00) >> 8;
1665        WSeq (regs, SEQ_ID_MCLK_HI, test);
1666        test = clockpar & 0xFF;
1667        WSeq (regs, SEQ_ID_MCLK_LO, test);
1668
1669        /* Chip rev specific: Not in my Trio manual!!! */
1670        if (RCrt (regs, CRT_ID_REVISION) == 0x10)
1671                WSeq (regs, SEQ_ID_MORE_MAGIC, test);
1672
1673        /* We now load an 25 MHz, 31kHz, 640x480 standard VGA Mode. */
1674
1675        /* Set DCLK value */
1676        WSeq (regs, SEQ_ID_DCLK_HI, 0x13);
1677        WSeq (regs, SEQ_ID_DCLK_LO, 0x41);
1678
1679        /* Load DCLK (and MCLK?) immediately */
1680        test = RSeq (regs, SEQ_ID_CLKSYN_CNTL_2);
1681        test = test | 0x22;
1682        WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, test);
1683
1684        /* Enable loading of DCLK */
1685        test = rb_64(regs, GREG_MISC_OUTPUT_R);
1686        test = test | 0x0C;
1687        wb_64 (regs, GREG_MISC_OUTPUT_W, test);
1688
1689        /* Turn off immediate xCLK load */
1690        WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, 0x2);
1691
1692        /* Horizontal character clock counts */
1693        /* 8 LSB of 9 bits = total line - 5 */
1694        WCrt (regs, CRT_ID_HOR_TOTAL, 0x5F);
1695        /* Active display line */
1696        WCrt (regs, CRT_ID_HOR_DISP_ENA_END, 0x4F);
1697        /* Blank assertion start */
1698        WCrt (regs, CRT_ID_START_HOR_BLANK, 0x50);
1699        /* Blank assertion end */
1700        WCrt (regs, CRT_ID_END_HOR_BLANK, 0x82);
1701        /* HSYNC assertion start */
1702        WCrt (regs, CRT_ID_START_HOR_RETR, 0x54);
1703        /* HSYNC assertion end */
1704        WCrt (regs, CRT_ID_END_HOR_RETR, 0x80);
1705        WCrt (regs, CRT_ID_VER_TOTAL, 0xBF);
1706        WCrt (regs, CRT_ID_OVERFLOW, 0x1F);
1707        WCrt (regs, CRT_ID_PRESET_ROW_SCAN, 0x0);
1708        WCrt (regs, CRT_ID_MAX_SCAN_LINE, 0x40);
1709        WCrt (regs, CRT_ID_CURSOR_START, 0x00);
1710        WCrt (regs, CRT_ID_CURSOR_END, 0x00);
1711        WCrt (regs, CRT_ID_START_ADDR_HIGH, 0x00);
1712        WCrt (regs, CRT_ID_START_ADDR_LOW, 0x00);
1713        WCrt (regs, CRT_ID_CURSOR_LOC_HIGH, 0x00);
1714        WCrt (regs, CRT_ID_CURSOR_LOC_LOW, 0x00);
1715        WCrt (regs, CRT_ID_START_VER_RETR, 0x9C);
1716        WCrt (regs, CRT_ID_END_VER_RETR, 0x0E);
1717        WCrt (regs, CRT_ID_VER_DISP_ENA_END, 0x8F);
1718        WCrt (regs, CRT_ID_SCREEN_OFFSET, 0x50);
1719        WCrt (regs, CRT_ID_UNDERLINE_LOC, 0x00);
1720        WCrt (regs, CRT_ID_START_VER_BLANK, 0x96);
1721        WCrt (regs, CRT_ID_END_VER_BLANK, 0xB9);
1722        WCrt (regs, CRT_ID_MODE_CONTROL, 0xE3);
1723        WCrt (regs, CRT_ID_LINE_COMPARE, 0xFF);
1724        WCrt (regs, CRT_ID_BACKWAD_COMP_3, 0x10);       /* FIFO enabled */
1725        WCrt (regs, CRT_ID_MISC_1, 0x35);
1726        WCrt (regs, CRT_ID_DISPLAY_FIFO, 0x5A);
1727        WCrt (regs, CRT_ID_EXT_MEM_CNTL_2, 0x70);
1728        WCrt (regs, CRT_ID_LAW_POS_LO, 0x40);
1729        WCrt (regs, CRT_ID_EXT_MEM_CNTL_3, 0xFF);
1730
1731        WGfx (regs, GCT_ID_SET_RESET, 0x0);
1732        WGfx (regs, GCT_ID_ENABLE_SET_RESET, 0x0);
1733        WGfx (regs, GCT_ID_COLOR_COMPARE, 0x0);
1734        WGfx (regs, GCT_ID_DATA_ROTATE, 0x0);
1735        WGfx (regs, GCT_ID_READ_MAP_SELECT, 0x0);
1736        WGfx (regs, GCT_ID_GRAPHICS_MODE, 0x40);
1737        WGfx (regs, GCT_ID_MISC, 0x01);
1738        WGfx (regs, GCT_ID_COLOR_XCARE, 0x0F);
1739        WGfx (regs, GCT_ID_BITMASK, 0xFF);
1740
1741        /* Colors for text mode */
1742        for (i = 0; i < 0xf; i++)
1743                WAttr (regs, i, i);
1744
1745        WAttr (regs, ACT_ID_ATTR_MODE_CNTL, 0x41);
1746        WAttr (regs, ACT_ID_OVERSCAN_COLOR, 0x01);
1747        WAttr (regs, ACT_ID_COLOR_PLANE_ENA, 0x0F);
1748        WAttr (regs, ACT_ID_HOR_PEL_PANNING, 0x0);
1749        WAttr (regs, ACT_ID_COLOR_SELECT, 0x0);
1750
1751        wb_64 (regs, VDAC_MASK, 0xFF);
1752
1753        *((unsigned long *) (regs + ECR_FRGD_COLOR)) = 0xFF;
1754        *((unsigned long *) (regs + ECR_BKGD_COLOR)) = 0;
1755
1756        /* Colors initially set to grayscale */
1757
1758        wb_64 (regs, VDAC_ADDRESS_W, 0);
1759        for (i = 255; i >= 0; i--) {
1760                wb_64(regs, VDAC_DATA, i);
1761                wb_64(regs, VDAC_DATA, i);
1762                wb_64(regs, VDAC_DATA, i);
1763        }
1764
1765        /* GFx hardware cursor off */
1766        WCrt (regs, CRT_ID_HWGC_MODE, 0x00);
1767
1768        /* Set first to 4MB, so test will work */
1769        WCrt (regs, CRT_ID_LAW_CNTL, 0x13);
1770        /* Find "correct" size of fbmem of Z3 board */
1771        if (cv_has_4mb (CyberMem)) {
1772                CyberSize = 1024 * 1024 * 4;
1773                WCrt (regs, CRT_ID_LAW_CNTL, 0x13);
1774                DPRINTK("4MB board\n");
1775        } else {
1776                CyberSize = 1024 * 1024 * 2;
1777                WCrt (regs, CRT_ID_LAW_CNTL, 0x12);
1778                DPRINTK("2MB board\n");
1779        }
1780
1781        /* Initialize graphics engine */
1782        Cyber_WaitBlit();
1783        vgaw16 (regs, ECR_FRGD_MIX, 0x27);
1784        vgaw16 (regs, ECR_BKGD_MIX, 0x07);
1785        vgaw16 (regs, ECR_READ_REG_DATA, 0x1000);
1786        udelay(200);
1787        vgaw16 (regs, ECR_READ_REG_DATA, 0x2000);
1788        Cyber_WaitBlit();
1789        vgaw16 (regs, ECR_READ_REG_DATA, 0x3FFF);
1790        Cyber_WaitBlit();
1791        udelay(200);
1792        vgaw16 (regs, ECR_READ_REG_DATA, 0x4FFF);
1793        Cyber_WaitBlit();
1794        vgaw16 (regs, ECR_BITPLANE_WRITE_MASK, ~0);
1795        Cyber_WaitBlit();
1796        vgaw16 (regs, ECR_READ_REG_DATA, 0xE000);
1797        vgaw16 (regs, ECR_CURRENT_Y_POS2, 0x00);
1798        vgaw16 (regs, ECR_CURRENT_X_POS2, 0x00);
1799        vgaw16 (regs, ECR_READ_REG_DATA, 0xA000);
1800        vgaw16 (regs, ECR_DEST_Y__AX_STEP, 0x00);
1801        vgaw16 (regs, ECR_DEST_Y2__AX_STEP2, 0x00);
1802        vgaw16 (regs, ECR_DEST_X__DIA_STEP, 0x00);
1803        vgaw16 (regs, ECR_DEST_X2__DIA_STEP2, 0x00);
1804        vgaw16 (regs, ECR_SHORT_STROKE, 0x00);
1805        vgaw16 (regs, ECR_DRAW_CMD, 0x01);
1806
1807        Cyber_WaitBlit();
1808
1809        vgaw16 (regs, ECR_READ_REG_DATA, 0x4FFF);
1810        vgaw16 (regs, ECR_BKGD_COLOR, 0x01);
1811        vgaw16 (regs, ECR_FRGD_COLOR, 0x00);
1812
1813
1814        /* Enable video display (set bit 5) */
1815/* ARB - Would also seem to write to AR13.
1816 *       May want to use parts of WAttr to set JUST bit 5
1817 */
1818        WAttr (regs, 0x33, 0);
1819        
1820/* GRF - function code ended here */
1821
1822        /* Turn gfx on again */
1823        gfx_on_off (0, regs);
1824
1825        /* Pass-through */
1826        cvscreen (0, CyberBase);
1827
1828        DPRINTK("EXIT\n");
1829}
1830
1831static void cv64_load_video_mode (struct fb_var_screeninfo *video_mode)
1832{
1833  volatile unsigned char *regs = CyberRegs;
1834  int fx, fy;
1835  unsigned short mnr;
1836  unsigned short HT, HDE, HBS, HBE, HSS, HSE, VDE, VBS, VBE, VSS, VSE, VT;
1837  char LACE, DBLSCAN, TEXT, CONSOLE;
1838  int cr50, sr15, sr18, clock_mode, test;
1839  int m, n;
1840  int tfillm, temptym;
1841  int hmul;
1842        
1843  /* ---------------- */
1844  int xres, hfront, hsync, hback;
1845  int yres, vfront, vsync, vback;
1846  int bpp;
1847#if 0
1848  float freq_f;
1849#endif
1850  long freq;
1851  /* ---------------- */
1852        
1853  DPRINTK("ENTER\n");
1854  TEXT = 0;     /* if depth == 4 */
1855  CONSOLE = 0;  /* mode num == 255 (console) */
1856  fx = fy = 8;  /* force 8x8 font */
1857
1858/* GRF - Disable interrupts */  
1859        
1860  gfx_on_off (1, regs);
1861        
1862  switch (video_mode->bits_per_pixel) {
1863  case 15:
1864  case 16:
1865    hmul = 2;
1866    break;
1867                
1868  default:
1869    hmul = 1;
1870    break;
1871  }
1872        
1873  bpp = video_mode->bits_per_pixel;
1874  xres = video_mode->xres;
1875  hfront = video_mode->right_margin;
1876  hsync = video_mode->hsync_len;
1877  hback = video_mode->left_margin;
1878
1879  LACE = 0;
1880  DBLSCAN = 0;
1881
1882  if (video_mode->vmode & FB_VMODE_DOUBLE) {
1883    yres = video_mode->yres * 2;
1884    vfront = video_mode->lower_margin * 2;
1885    vsync = video_mode->vsync_len * 2;
1886    vback = video_mode->upper_margin * 2;
1887    DBLSCAN = 1;
1888  } else if (video_mode->vmode & FB_VMODE_INTERLACED) {
1889    yres = (video_mode->yres + 1) / 2;
1890    vfront = (video_mode->lower_margin + 1) / 2;
1891    vsync = (video_mode->vsync_len + 1) / 2;
1892    vback = (video_mode->upper_margin + 1) / 2;
1893    LACE = 1;
1894  } else {
1895    yres = video_mode->yres;
1896    vfront = video_mode->lower_margin;
1897    vsync = video_mode->vsync_len;
1898    vback = video_mode->upper_margin;
1899  }
1900
1901  /* ARB Dropping custom setup method from cvision.c */
1902#if 0
1903  if (cvision_custom_mode) {
1904    HBS = hbs / 8 * hmul;
1905    HBE = hbe / 8 * hmul;
1906    HSS = hss / 8 * hmul;
1907    HSE = hse / 8 * hmul;
1908    HT  = ht / 8 * hmul - 5;
1909                
1910    VBS = vbs - 1;
1911    VSS = vss;
1912    VSE = vse;
1913    VBE = vbe;
1914    VT  = vt - 2;
1915  } else {
1916#else
1917    {
1918#endif
1919    HBS = hmul * (xres / 8);
1920    HBE = hmul * ((xres/8) + (hfront/8) + (hsync/8) + (hback/8) - 2);
1921    HSS = hmul * ((xres/8) + (hfront/8) + 2);
1922    HSE = hmul * ((xres/8) + (hfront/8) + (hsync/8) + 1);
1923    HT  = hmul * ((xres/8) + (hfront/8) + (hsync/8) + (hback/8));
1924        
1925    VBS = yres;
1926    VBE = yres + vfront + vsync + vback - 2;
1927    VSS = yres + vfront - 1;
1928    VSE = yres + vfront + vsync - 1;
1929    VT  = yres + vfront + vsync + vback - 2;
1930  }
1931
1932  wb_64 (regs, ECR_ADV_FUNC_CNTL, (TEXT ? 0x00 : 0x31));
1933        
1934  if (TEXT)
1935    HDE = ((video_mode->xres + fx - 1) / fx) - 1;
1936  else
1937    HDE = (video_mode->xres + 3) * hmul / 8 - 1;
1938        
1939  VDE = video_mode->yres - 1;
1940
1941  WCrt (regs, CRT_ID_HWGC_MODE, 0x00);
1942  WCrt (regs, CRT_ID_EXT_DAC_CNTL, 0x00);
1943        
1944  WSeq (regs, SEQ_ID_MEMORY_MODE,
1945        (TEXT || (video_mode->bits_per_pixel == 1)) ? 0x06 : 0x0e);
1946  WGfx (regs, GCT_ID_READ_MAP_SELECT, 0x00);
1947  WSeq (regs, SEQ_ID_MAP_MASK,
1948        (video_mode->bits_per_pixel == 1) ? 0x01 : 0xFF);
1949  WSeq (regs, SEQ_ID_CHAR_MAP_SELECT, 0x00);
1950        
1951  /* cv64_compute_clock accepts arguments in Hz */
1952  /* pixclock is in ps ... convert to Hz */
1953        
1954#if 0
1955  freq_f = (1.0 / (float) video_mode->pixclock) * 1000000000;
1956  freq = ((long) freq_f) * 1000;
1957#else
1958/* freq = (long) ((long long)1000000000000 / (long long) video_mode->pixclock);
1959 */
1960  freq = (1000000000 / video_mode->pixclock) * 1000;
1961#endif
1962
1963  mnr = cv64_compute_clock (freq);
1964  WSeq (regs, SEQ_ID_DCLK_HI, ((mnr & 0xFF00) >> 8));
1965  WSeq (regs, SEQ_ID_DCLK_LO, (mnr & 0xFF));
1966        
1967  /* Load display parameters into board */
1968  WCrt (regs, CRT_ID_EXT_HOR_OVF,
1969        ((HT & 0x100) ? 0x01 : 0x00) |
1970        ((HDE & 0x100) ? 0x02 : 0x00) |
1971        ((HBS & 0x100) ? 0x04 : 0x00) |
1972        /* ((HBE & 0x40) ? 0x08 : 0x00) | */
1973        ((HSS & 0x100) ? 0x10 : 0x00) |
1974        /* ((HSE & 0x20) ? 0x20 : 0x00) | */
1975        (((HT-5) & 0x100) ? 0x40 : 0x00)
1976        );
1977        
1978  WCrt (regs, CRT_ID_EXT_VER_OVF,
1979        0x40 |
1980        ((VT & 0x400) ? 0x01 : 0x00) |
1981        ((VDE & 0x400) ? 0x02 : 0x00) |
1982        ((VBS & 0x400) ? 0x04 : 0x00) |
1983        ((VSS & 0x400) ? 0x10 : 0x00)
1984        );
1985        
1986  WCrt (regs, CRT_ID_HOR_TOTAL, HT);
1987  WCrt (regs, CRT_ID_DISPLAY_FIFO, HT - 5);
1988  WCrt (regs, CRT_ID_HOR_DISP_ENA_END, ((HDE >= HBS) ? (HBS - 1) : HDE));
1989  WCrt (regs, CRT_ID_START_HOR_BLANK, HBS);
1990  WCrt (regs, CRT_ID_END_HOR_BLANK, ((HBE & 0x1F) | 0x80));
1991  WCrt (regs, CRT_ID_START_HOR_RETR, HSS);
1992  WCrt (regs, CRT_ID_END_HOR_RETR,
1993        (HSE & 0x1F) |
1994        ((HBE & 0x20) ? 0x80 : 0x00)
1995        );
1996  WCrt (regs, CRT_ID_VER_TOTAL, VT);
1997  WCrt (regs, CRT_ID_OVERFLOW,
1998        0x10 |
1999        ((VT & 0x100) ? 0x01 : 0x00) |
2000        ((VDE & 0x100) ? 0x02 : 0x00) |
2001        ((VSS & 0x100) ? 0x04 : 0x00) |
2002        ((VBS & 0x100) ? 0x08 : 0x00) |
2003        ((VT & 0x200) ? 0x20 : 0x00) |
2004        ((VDE & 0x200) ? 0x40 : 0x00) |
2005        ((VSS & 0x200) ? 0x80 : 0x00)
2006        );
2007  WCrt (regs, CRT_ID_MAX_SCAN_LINE,
2008        0x40 |
2009        (DBLSCAN ? 0x80 : 0x00) |
2010        ((VBS & 0x200) ? 0x20 : 0x00) |
2011        (TEXT ? ((fy - 1) & 0x1F) : 0x00)
2012        );
2013        
2014  WCrt (regs, CRT_ID_MODE_CONTROL, 0xE3);
2015
2016  /* Text cursor */
2017        
2018  if (TEXT) {
2019#if 1
2020    WCrt (regs, CRT_ID_CURSOR_START, (fy & 0x1f) - 2);
2021    WCrt (regs, CRT_ID_CURSOR_END, (fy & 0x1F) - 1);
2022#else
2023    WCrt (regs, CRT_ID_CURSOR_START, 0x00);
2024    WCrt (regs, CRT_ID_CURSOR_END, fy & 0x1F);
2025#endif
2026    WCrt (regs, CRT_ID_UNDERLINE_LOC, (fy - 1) & 0x1F);
2027    WCrt (regs, CRT_ID_CURSOR_LOC_HIGH, 0x00);
2028    WCrt (regs, CRT_ID_CURSOR_LOC_LOW, 0x00);
2029  }
2030        
2031  WCrt (regs, CRT_ID_START_ADDR_HIGH, 0x00);
2032  WCrt (regs, CRT_ID_START_ADDR_LOW, 0x00);
2033  WCrt (regs, CRT_ID_START_VER_RETR, VSS);
2034  WCrt (regs, CRT_ID_END_VER_RETR, (VSE & 0x0F));
2035  WCrt (regs, CRT_ID_VER_DISP_ENA_END, VDE);
2036  WCrt (regs, CRT_ID_START_VER_BLANK, VBS);
2037  WCrt (regs, CRT_ID_END_VER_BLANK, VBE);
2038  WCrt (regs, CRT_ID_LINE_COMPARE, 0xFF);
2039  WCrt (regs, CRT_ID_LACE_RETR_START, HT / 2);
2040  WCrt (regs, CRT_ID_LACE_CONTROL, (LACE ? 0x20 : 0x00));
2041  WGfx (regs, GCT_ID_GRAPHICS_MODE,
2042        ((TEXT || (video_mode->bits_per_pixel == 1)) ? 0x00 : 0x40));
2043  WGfx (regs, GCT_ID_MISC, (TEXT ? 0x04 : 0x01));
2044  WSeq (regs, SEQ_ID_MEMORY_MODE,
2045        ((TEXT || (video_mode->bits_per_pixel == 1)) ? 0x06 : 0x02));
2046        
2047  wb_64 (regs, VDAC_MASK, 0xFF);
2048        
2049  /* Blank border */
2050  test = RCrt (regs, CRT_ID_BACKWAD_COMP_2);
2051  WCrt (regs, CRT_ID_BACKWAD_COMP_2, (test | 0x20));
2052        
2053  sr15 = RSeq (regs, SEQ_ID_CLKSYN_CNTL_2);
2054  sr15 &= 0xEF;
2055  sr18 = RSeq (regs, SEQ_ID_RAMDAC_CNTL);
2056  sr18 &= 0x7F;
2057  clock_mode = 0x00;
2058  cr50 = 0x00;
2059        
2060  test = RCrt (regs, CRT_ID_EXT_MISC_CNTL_2);
2061  test &= 0xD;
2062        
2063  /* Clear roxxler byte-swapping... */
2064  cv64_write_port (0x0040, CyberBase);
2065  cv64_write_port (0x0020, CyberBase);
2066        
2067  switch (video_mode->bits_per_pixel) {
2068  case 1:
2069  case 4:       /* text */
2070    HDE = video_mode->xres / 16;
2071    break;
2072                
2073  case 8:
2074    if (freq > 80000000) {
2075      clock_mode = 0x10 | 0x02;
2076      sr15 |= 0x10;
2077      sr18 |= 0x80;
2078    }
2079    HDE = video_mode->xres / 8;
2080    cr50 |= 0x00;
2081    break;
2082                
2083  case 15:
2084    cv64_write_port (0x8020, CyberBase);
2085    clock_mode = 0x30;
2086    HDE = video_mode->xres / 4;
2087    cr50 |= 0x10;
2088    break;
2089                
2090  case 16:
2091    cv64_write_port (0x8020, CyberBase);
2092    clock_mode = 0x50;
2093    HDE = video_mode->xres / 4;
2094    cr50 |= 0x10;
2095    break;
2096                
2097  case 24:
2098  case 32:
2099    cv64_write_port (0x8040, CyberBase);
2100    clock_mode = 0xD0;
2101    HDE = video_mode->xres / 2;
2102    cr50 |= 0x30;
2103    break;
2104  }
2105
2106  WCrt (regs, CRT_ID_EXT_MISC_CNTL_2, clock_mode | test);
2107  WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, sr15);
2108  WSeq (regs, SEQ_ID_RAMDAC_CNTL, sr18);
2109  WCrt (regs, CRT_ID_SCREEN_OFFSET, HDE);
2110
2111  WCrt (regs, CRT_ID_MISC_1, (TEXT ? 0x05 : 0x35));
2112        
2113  test = RCrt (regs, CRT_ID_EXT_SYS_CNTL_2);
2114  test &= ~0x30;
2115  test |= (HDE >> 4) & 0x30;
2116  WCrt (regs, CRT_ID_EXT_SYS_CNTL_2, test);
2117        
2118  /* Set up graphics engine */
2119  switch (video_mode->xres) {
2120  case 1024:
2121    cr50 |= 0x00;
2122    break;
2123                
2124  case 640:
2125    cr50 |= 0x40;
2126    break;
2127                
2128  case 800:
2129    cr50 |= 0x80;
2130    break;
2131                
2132  case 1280:
2133    cr50 |= 0xC0;
2134    break;
2135                
2136  case 1152:
2137    cr50 |= 0x01;
2138    break;
2139                
2140  case 1600:
2141    cr50 |= 0x81;
2142    break;
2143                
2144  default:      /* XXX */
2145    break;
2146  }
2147        
2148  WCrt (regs, CRT_ID_EXT_SYS_CNTL_1, cr50);
2149        
2150  udelay(100);
2151  WAttr (regs, ACT_ID_ATTR_MODE_CNTL, (TEXT ? 0x08 : 0x41));
2152  udelay(100);
2153  WAttr (regs, ACT_ID_COLOR_PLANE_ENA,
2154         (video_mode->bits_per_pixel == 1) ? 0x01 : 0x0F);
2155  udelay(100);
2156        
2157  tfillm = (96 * (cv64_memclk / 1000)) / 240000;
2158        
2159  switch (video_mode->bits_per_pixel) {
2160  case 32:
2161  case 24:
2162    temptym = (24 * (cv64_memclk / 1000)) / (freq / 1000);
2163    break;
2164  case 15:
2165  case 16:
2166    temptym = (48 * (cv64_memclk / 1000)) / (freq / 1000);
2167    break;
2168  case 4:
2169    temptym = (192 * (cv64_memclk / 1000)) / (freq / 1000);
2170    break;
2171  default:
2172    temptym = (96 * (cv64_memclk / 1000)) / (freq / 1000);
2173    break;
2174  }
2175        
2176  m = (temptym - tfillm - 9) / 2;
2177  if (m < 0)
2178    m = 0;
2179  m = (m & 0x1F) << 3;
2180  if (m < 0x18)
2181    m = 0x18;
2182  n = 0xFF;
2183        
2184  WCrt (regs, CRT_ID_EXT_MEM_CNTL_2, m);
2185  WCrt (regs, CRT_ID_EXT_MEM_CNTL_3, n);
2186  udelay(10);
2187        
2188  /* Text initialization */
2189        
2190  if (TEXT) {
2191    /* Do text initialization here ! */
2192  }
2193        
2194  if (CONSOLE) {
2195    int i;
2196    wb_64 (regs, VDAC_ADDRESS_W, 0);
2197    for (i = 0; i < 4; i++) {
2198      wb_64 (regs, VDAC_DATA, cvconscolors [i][0]);
2199      wb_64 (regs, VDAC_DATA, cvconscolors [i][1]);
2200      wb_64 (regs, VDAC_DATA, cvconscolors [i][2]);
2201    }
2202  }
2203        
2204  WAttr (regs, 0x33, 0);
2205        
2206  /* Turn gfx on again */
2207  gfx_on_off (0, (volatile unsigned char *) regs);
2208        
2209  /* Pass-through */
2210  cvscreen (0, CyberBase);
2211
2212DPRINTK("EXIT\n");
2213}
2214
2215void cvision_bitblt (u_short sx, u_short sy, u_short dx, u_short dy,
2216                     u_short w, u_short h)
2217{
2218        volatile unsigned char *regs = CyberRegs;
2219        unsigned short drawdir = 0;
2220        
2221        DPRINTK("ENTER\n");
2222        if (sx > dx) {
2223                drawdir |= 1 << 5;
2224        } else {
2225                sx += w - 1;
2226                dx += w - 1;
2227        }
2228        
2229        if (sy > dy) {
2230                drawdir |= 1 << 7;
2231        } else {
2232                sy += h - 1;
2233                dy += h - 1;
2234        }
2235        
2236        Cyber_WaitBlit();
2237        vgaw16 (regs, ECR_READ_REG_DATA, 0xA000);
2238        vgaw16 (regs, ECR_BKGD_MIX, 0x7);
2239        vgaw16 (regs, ECR_FRGD_MIX, 0x67);
2240        vgaw16 (regs, ECR_BKGD_COLOR, 0x0);
2241        vgaw16 (regs, ECR_FRGD_COLOR, 0x1);
2242        vgaw16 (regs, ECR_BITPLANE_READ_MASK, 0x1);
2243        vgaw16 (regs, ECR_BITPLANE_WRITE_MASK, 0xFFF);
2244        vgaw16 (regs, ECR_CURRENT_Y_POS, sy);
2245        vgaw16 (regs, ECR_CURRENT_X_POS, sx);
2246        vgaw16 (regs, ECR_DEST_Y__AX_STEP, dy);
2247        vgaw16 (regs, ECR_DEST_X__DIA_STEP, dx);
2248        vgaw16 (regs, ECR_READ_REG_DATA, h - 1);
2249        vgaw16 (regs, ECR_MAJ_AXIS_PIX_CNT, w - 1);
2250        vgaw16 (regs, ECR_DRAW_CMD, 0xC051 | drawdir);
2251        DPRINTK("EXIT\n");
2252}
2253
2254void cvision_clear (u_short dx, u_short dy, u_short w, u_short h, u_short bg)
2255{
2256        volatile unsigned char *regs = CyberRegs;
2257        DPRINTK("ENTER\n");
2258        Cyber_WaitBlit();
2259        vgaw16 (regs, ECR_FRGD_MIX, 0x0027);
2260        vgaw16 (regs, ECR_FRGD_COLOR, bg);
2261        vgaw16 (regs, ECR_READ_REG_DATA, 0xA000);
2262        vgaw16 (regs, ECR_CURRENT_Y_POS, dy);
2263        vgaw16 (regs, ECR_CURRENT_X_POS, dx);
2264        vgaw16 (regs, ECR_READ_REG_DATA, h - 1);
2265        vgaw16 (regs, ECR_MAJ_AXIS_PIX_CNT, w - 1);
2266        vgaw16 (regs, ECR_DRAW_CMD, 0x40B1);    
2267        DPRINTK("EXIT\n");
2268}
2269
2270#ifdef CYBERFBDEBUG
2271/*
2272 * Dump internal settings of CyberVision board
2273 */
2274static void cv64_dump (void)
2275{
2276        volatile unsigned char *regs = CyberRegs;
2277        DPRINTK("ENTER\n");
2278        /* Dump the VGA setup values */
2279        *(regs + S3_CRTC_ADR) = 0x00;
2280        DPRINTK("CR00 = %x\n", *(regs + S3_CRTC_DATA));
2281        *(regs + S3_CRTC_ADR) = 0x01;
2282        DPRINTK("CR01 = %x\n", *(regs + S3_CRTC_DATA));
2283        *(regs + S3_CRTC_ADR) = 0x02;
2284        DPRINTK("CR02 = %x\n", *(regs + S3_CRTC_DATA));
2285        *(regs + S3_CRTC_ADR) = 0x03;
2286        DPRINTK("CR03 = %x\n", *(regs + S3_CRTC_DATA));
2287        *(regs + S3_CRTC_ADR) = 0x04;
2288        DPRINTK("CR04 = %x\n", *(regs + S3_CRTC_DATA));
2289        *(regs + S3_CRTC_ADR) = 0x05;
2290        DPRINTK("CR05 = %x\n", *(regs + S3_CRTC_DATA));
2291        *(regs + S3_CRTC_ADR) = 0x06;
2292        DPRINTK("CR06 = %x\n", *(regs + S3_CRTC_DATA));
2293        *(regs + S3_CRTC_ADR) = 0x07;
2294        DPRINTK("CR07 = %x\n", *(regs + S3_CRTC_DATA));
2295        *(regs + S3_CRTC_ADR) = 0x08;
2296        DPRINTK("CR08 = %x\n", *(regs + S3_CRTC_DATA));
2297        *(regs + S3_CRTC_ADR) = 0x09;
2298        DPRINTK("CR09 = %x\n", *(regs + S3_CRTC_DATA));
2299        *(regs + S3_CRTC_ADR) = 0x10;
2300        DPRINTK("CR10 = %x\n", *(regs + S3_CRTC_DATA));
2301        *(regs + S3_CRTC_ADR) = 0x11;
2302        DPRINTK("CR11 = %x\n", *(regs + S3_CRTC_DATA));
2303        *(regs + S3_CRTC_ADR) = 0x12;
2304        DPRINTK("CR12 = %x\n", *(regs + S3_CRTC_DATA));
2305        *(regs + S3_CRTC_ADR) = 0x13;
2306        DPRINTK("CR13 = %x\n", *(regs + S3_CRTC_DATA));
2307        *(regs + S3_CRTC_ADR) = 0x15;
2308        DPRINTK("CR15 = %x\n", *(regs + S3_CRTC_DATA));
2309        *(regs + S3_CRTC_ADR) = 0x16;
2310        DPRINTK("CR16 = %x\n", *(regs + S3_CRTC_DATA));
2311        *(regs + S3_CRTC_ADR) = 0x36;
2312        DPRINTK("CR36 = %x\n", *(regs + S3_CRTC_DATA));
2313        *(regs + S3_CRTC_ADR) = 0x37;
2314        DPRINTK("CR37 = %x\n", *(regs + S3_CRTC_DATA));
2315        *(regs + S3_CRTC_ADR) = 0x42;
2316        DPRINTK("CR42 = %x\n", *(regs + S3_CRTC_DATA));
2317        *(regs + S3_CRTC_ADR) = 0x43;
2318        DPRINTK("CR43 = %x\n", *(regs + S3_CRTC_DATA));
2319        *(regs + S3_CRTC_ADR) = 0x50;
2320        DPRINTK("CR50 = %x\n", *(regs + S3_CRTC_DATA));
2321        *(regs + S3_CRTC_ADR) = 0x51;
2322        DPRINTK("CR51 = %x\n", *(regs + S3_CRTC_DATA));
2323        *(regs + S3_CRTC_ADR) = 0x53;
2324        DPRINTK("CR53 = %x\n", *(regs + S3_CRTC_DATA));
2325        *(regs + S3_CRTC_ADR) = 0x58;
2326        DPRINTK("CR58 = %x\n", *(regs + S3_CRTC_DATA));
2327        *(regs + S3_CRTC_ADR) = 0x59;
2328        DPRINTK("CR59 = %x\n", *(regs + S3_CRTC_DATA));
2329        *(regs + S3_CRTC_ADR) = 0x5A;
2330        DPRINTK("CR5A = %x\n", *(regs + S3_CRTC_DATA));
2331        *(regs + S3_CRTC_ADR) = 0x5D;
2332        DPRINTK("CR5D = %x\n", *(regs + S3_CRTC_DATA));
2333        *(regs + S3_CRTC_ADR) = 0x5E;
2334        DPRINTK("CR5E = %x\n", *(regs + S3_CRTC_DATA));
2335        DPRINTK("MISC = %x\n", *(regs + GREG_MISC_OUTPUT_R));
2336        *(regs + SEQ_ADDRESS) = 0x01;
2337        DPRINTK("SR01 = %x\n", *(regs + SEQ_ADDRESS_R));
2338        *(regs + SEQ_ADDRESS) = 0x02;
2339        DPRINTK("SR02 = %x\n", *(regs + SEQ_ADDRESS_R));
2340        *(regs + SEQ_ADDRESS) = 0x03;
2341        DPRINTK("SR03 = %x\n", *(regs + SEQ_ADDRESS_R));
2342        *(regs + SEQ_ADDRESS) = 0x09;
2343        DPRINTK("SR09 = %x\n", *(regs + SEQ_ADDRESS_R));
2344        *(regs + SEQ_ADDRESS) = 0x10;
2345        DPRINTK("SR10 = %x\n", *(regs + SEQ_ADDRESS_R));
2346        *(regs + SEQ_ADDRESS) = 0x11;
2347        DPRINTK("SR11 = %x\n", *(regs + SEQ_ADDRESS_R));
2348        *(regs + SEQ_ADDRESS) = 0x12;
2349        DPRINTK("SR12 = %x\n", *(regs + SEQ_ADDRESS_R));
2350        *(regs + SEQ_ADDRESS) = 0x13;
2351        DPRINTK("SR13 = %x\n", *(regs + SEQ_ADDRESS_R));
2352        *(regs + SEQ_ADDRESS) = 0x15;
2353        DPRINTK("SR15 = %x\n", *(regs + SEQ_ADDRESS_R));
2354        
2355        return;
2356}
2357#endif
2358