]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] M68k update (part 3)
authorGeert Uytterhoeven <geert@linux-m68k.org>
Tue, 23 Jul 2002 13:20:41 +0000 (06:20 -0700)
committerLinus Torvalds <torvalds@home.transmeta.com>
Tue, 23 Jul 2002 13:20:41 +0000 (06:20 -0700)
 Amiga native graphics updates
  - Fix typo
  - Make monitor capability parsing a separate routine (strsep() must be able
    to modify the passed pointer)

 The Cirrus Logic frame buffer device needs access to the memory mapped VGA I/O space on Amiga

 Add video mode initialization code to the CyberVision64/3D driver

 Add S3 ViRGE register definitions for the CyberVision64/3D driver

drivers/video/amifb.c
drivers/video/vga.h
drivers/video/virgefb.c
drivers/video/virgefb.h [new file with mode: 0644]

index f7ff06f62651b1a4f91d6c868e54eb43ec018db0..7bbd9b26cd86a806db66abfe661d2d580116c1cf 100644 (file)
@@ -61,7 +61,6 @@
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
 #include <asm/setup.h>
-#include <asm/io.h>
 
 #include <video/fbcon.h>
 #include <video/fbcon-afb.h>
@@ -1173,16 +1172,51 @@ static struct fb_ops amifb_ops = {
        fb_set_cmap:    gen_set_cmap,
        fb_setcolreg:   amifb_setcolreg,
        fb_pan_display: amifb_pan_display,
-       fb_blankL:      amifb_blank,
+       fb_blank      amifb_blank,
        fb_ioctl:       amifb_ioctl,
 };
 
+static void __init amifb_setup_mcap(char *spec)
+{
+       char *p;
+       int vmin, vmax, hmin, hmax;
+
+       /* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
+        * <V*> vertical freq. in Hz
+        * <H*> horizontal freq. in kHz
+        */
+
+       if (!(p = strsep(&spec, ";")) || !*p)
+               return;
+       vmin = simple_strtoul(p, NULL, 10);
+       if (vmin <= 0)
+               return;
+       if (!(p = strsep(&spec, ";")) || !*p)
+               return;
+       vmax = simple_strtoul(p, NULL, 10);
+       if (vmax <= 0 || vmax <= vmin)
+               return;
+       if (!(p = strsep(&spec, ";")) || !*p)
+               return;
+       hmin = 1000 * simple_strtoul(p, NULL, 10);
+       if (hmin <= 0)
+               return;
+       if (!(p = strsep(&spec, "")) || !*p)
+               return;
+       hmax = 1000 * simple_strtoul(p, NULL, 10);
+       if (hmax <= 0 || hmax <= hmin)
+               return;
+
+       fb_info.monspecs.vfmin = vmin;
+       fb_info.monspecs.vfmax = vmax;
+       fb_info.monspecs.hfmin = hmin;
+       fb_info.monspecs.hfmax = hmax;
+}
+
 int __init amifb_setup(char *options)
 {
        char *this_opt;
-       char mcap_spec[80];
 
-       mcap_spec[0] = '\0';
        fb_info.fontname[0] = '\0';
 
        if (!options || !*options)
@@ -1199,7 +1233,7 @@ int __init amifb_setup(char *options)
                } else if (!strcmp(this_opt, "ilbm"))
                        amifb_ilbm = 1;
                else if (!strncmp(this_opt, "monitorcap:", 11))
-                       strcpy(mcap_spec, this_opt+11);
+                       amifb_setup_mcap(this_opt+11);
                else if (!strncmp(this_opt, "font:", 5))
                        strcpy(fb_info.fontname, this_opt+5);
                else if (!strncmp(this_opt, "fstart:", 7))
@@ -1211,43 +1245,6 @@ int __init amifb_setup(char *options)
        if (min_fstrt < 48)
                min_fstrt = 48;
 
-       if (*mcap_spec) {
-               char *p;
-               int vmin, vmax, hmin, hmax;
-
-       /* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
-        * <V*> vertical freq. in Hz
-        * <H*> horizontal freq. in kHz
-        */
-
-               if (!(p = strsep(&mcap_spec, ";")) || !*p)
-                       goto cap_invalid;
-               vmin = simple_strtoul(p, NULL, 10);
-               if (vmin <= 0)
-                       goto cap_invalid;
-               if (!(p = strsep(&mcap_spec, ";")) || !*p)
-                       goto cap_invalid;
-               vmax = simple_strtoul(p, NULL, 10);
-               if (vmax <= 0 || vmax <= vmin)
-                       goto cap_invalid;
-               if (!(p = strsep(&mcap_spec, ";")) || !*p)
-                       goto cap_invalid;
-               hmin = 1000 * simple_strtoul(p, NULL, 10);
-               if (hmin <= 0)
-                       goto cap_invalid;
-               if (!(p = strsep(&mcap_spec, "")) || !*p)
-                       goto cap_invalid;
-               hmax = 1000 * simple_strtoul(p, NULL, 10);
-               if (hmax <= 0 || hmax <= hmin)
-                       goto cap_invalid;
-
-               fb_info.monspecs.vfmin = vmin;
-               fb_info.monspecs.vfmax = vmax;
-               fb_info.monspecs.hfmin = hmin;
-               fb_info.monspecs.hfmax = hmax;
-cap_invalid:
-               ;
-       }
        return 0;
 }
 
index ce33bef82fc25e826c7ef5feade0590cdd95630f..803743121d3d06e3884469855d95eb1aae6c889c 100644 (file)
 #include <asm/io.h>
 #ifndef CONFIG_AMIGA
 #include <asm/vga.h>
+#else
+/*
+ * FIXME
+ * Ugh, we don't have PCI space, so map readb() and friends to use Zorro space
+ * for MMIO accesses. This should make clgenfb work again on Amiga
+ */
+#define inb(port)      0
+#define inw(port)      0
+#define outb(port, val)        do { } while (0)
+#define outw(port, val)        do { } while (0)
+#define readb          z_readb
+#define writeb         z_writeb
+#define writew         z_writew
 #endif
 #include <asm/byteorder.h>
 
index ec416c8b8a36df674de9dd4dbae125dcdb76743f..be06ea8ee4e6b57cb69911f53e5df2a95819feb5 100644 (file)
@@ -9,12 +9,30 @@
  *    Copyright (C) 1996 Martin Apel
  *                       Geert Uytterhoeven
  *
+ * Zorro II additions :
+ *
+ *    Copyright (C) 1998-2000 Christian T. Steigies
+ *
+ * Initialization additions :
+ *
+ *    Copyright (C) 1998-2000 Ken Tyler
+ *
+ * Parts of the Initialization code are based on Cyberfb.c by Allan Bair,
+ * and on the NetBSD CyberVision64 frame buffer driver by Michael Teske who gave
+ * permission for its use.
+ *
+ * Many thanks to Frank Mariak for his assistance with ZORRO 2 access and other
+ * mysteries.
+ *
+ *
+ *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file COPYING in the main directory of this archive
  * for more details.
  */
 
 #undef VIRGEFBDEBUG
+#undef VIRGEFBDUMP
 
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
 #include <asm/amigahw.h>
 #include <asm/io.h>
-
-#include <video/s3blit.h>
+#include <asm/irq.h>
 #include <video/fbcon.h>
 #include <video/fbcon-cfb8.h>
 #include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb32.h>
 
+#include "virgefb.h"
 
 #ifdef VIRGEFBDEBUG
 #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
 #define DPRINTK(fmt, args...)
 #endif
 
-#if 1
-#define vgawb_3d(reg,dat) \
-       if (cv3d_on_zorro2) { \
-       *((unsigned char volatile *)((Cyber_vcode_switch_base) + 0x04)) = \
-       (0x01 & 0xffff); asm volatile ("nop"); \
-       } \
-       (*((unsigned char *)(CyberVGARegs + (reg ^ 3))) = dat); \
-       if (cv3d_on_zorro2) { \
-       *((unsigned char volatile *)((Cyber_vcode_switch_base) + 0x04)) = \
-       (0x02 & 0xffff); asm volatile ("nop"); \
-       }
-#define vgaww_3d(reg,dat) \
-                (*((unsigned word *)(CyberVGARegs + (reg ^ 2))) = swab16(dat))
-#define vgawl_3d(reg,dat) \
-                (*((unsigned long *)(CyberVGARegs + reg)) = swab32(dat))
+#ifdef VIRGEFBDUMP
+static void cv64_dump(void);
+#define DUMP cv64_dump()
 #else
-     /*
-      * Dunno why this doesn't work at the moment - we'll have to look at
-      * it later.
-      */
-#define vgawb_3d(reg,dat) \
-                (*((unsigned char *)(CyberRegs + 0x8000 + reg)) = dat)
-#define vgaww_3d(reg,dat) \
-                (*((unsigned word *)(CyberRegs + 0x8000 + reg)) = dat)
-#define vgawl_3d(reg,dat) \
-                (*((unsigned long *)(CyberRegs + 0x8000 + reg)) = dat)
+#define DUMP
 #endif
 
-     /*
-      * We asume P5 mapped the big-endian version of these registers.
-      */
-#define wb_3d(reg,dat) \
-                (*((unsigned char volatile *)(CyberRegs + reg)) = dat)
-#define ww_3d(reg,dat) \
-                (*((unsigned word volatile *)(CyberRegs + reg)) = dat)
-#define wl_3d(reg,dat) \
-                (*((unsigned long volatile *)(CyberRegs + reg)) = dat)
-#define rl_3d(reg) \
-                (*((unsigned long volatile *)(CyberRegs + reg)))
-
-#define Select_Zorro2_FrameBuffer(flag) \
-       do { \
-               *((unsigned char volatile *)((Cyber_vcode_switch_base) + 0x08)) = \
-               ((flag * 0x40) & 0xffff); asm volatile ("nop"); \
-       } while (0)
 /*
- *     may be needed when we initialize the board?
- *     8bit: flag = 2, 16 bit: flag = 1, 24/32bit: flag = 0 
- *     _when_ the board is initialized, depth doesnt matter, we allways write
- *     to the same address, aperture seems not to matter on Z2.
+ *     Macros for register access and zorro control
  */
 
+static inline void mb_inline(void) { mb(); }   /* for use in comma expressions */
+
+/* Set zorro 2 map */
+
+#define SelectIO \
+       mb(); \
+       if (on_zorro2) { \
+               (*(volatile u16 *)((u8 *)(vcode_switch_base + 0x04)) = 0x01); \
+               mb(); \
+       }
+
+#define        SelectMMIO \
+       mb(); \
+       if (on_zorro2) { \
+               (*(volatile u16 *)((u8 *)(vcode_switch_base + 0x04)) = 0x02); \
+               mb(); \
+       }
+
+#define        SelectCFG \
+       mb(); \
+       if (on_zorro2) { \
+               (*(volatile u16 *)((u8 *)(vcode_switch_base + 0x04)) = 0x03); \
+               mb(); \
+       }
+
+/* Set pass through, 0 = amiga, !=0 = cv64/3d */
+
+#define SetVSwitch(x) \
+       mb(); \
+       (*(volatile u16 *)((u8 *)(vcode_switch_base)) = \
+       (u16)(x ? 0 : 1)); \
+       mb();
+
+/* Zorro2 endian 'aperture' */
+
+#define ENDIAN_BYTE    2
+#define ENDIAN_WORD    1
+#define ENDIAN_LONG    0
+
+#define Select_Zorro2_FrameBuffer(x) \
+       do { \
+               if (on_zorro2) { \
+                       mb(); \
+                       (*(volatile u16 *)((u8 *)(vcode_switch_base + 0x08)) = \
+                       (x * 0x40)); \
+                       mb(); \
+               } \
+       } while (0)
+
+/* SetPortVal - only used for interrupt enable (not yet implemented) */
+
+#if 0
+#define SetPortVal(x) \
+       mb(); \
+       (*(volatile u16 *)((u8 *)(vcode_switch_base + 0x0c)) = \
+       (u16)x); \
+       mb();
+#endif
+
+/* IO access */
+
+#define byte_access_io(x)      (((x) & 0x3ffc) | (((x) & 3)^3) | (((x) & 3) <<14))
+#define byte_access_mmio(x)    (((x) & 0xfffc) | (((x) & 3)^3))
+
+/* Write 8 bit VGA register - used once for chip wakeup */
+
+#define wb_vgaio(reg, dat) \
+       SelectIO; \
+       (*(volatile u8 *)(vgaio_regs + ((u32)byte_access_io(reg) & 0xffff)) = \
+       (dat & 0xff)); \
+       SelectMMIO;
+
+/* Read 8 bit VGA register - only used in dump (SelectIO not needed on read ?) */
+
+#ifdef VIRGEFBDUMP
+#define rb_vgaio(reg) \
+       ({ \
+       u8 __zzyzx; \
+       SelectIO; \
+       __zzyzx = (*(volatile u8 *)((vgaio_regs)+(u32)byte_access_io(reg))); \
+       SelectMMIO; \
+       __zzyzx; \
+       })
+#endif
+
+/* MMIO access */
+
+/* Read 8 bit MMIO register */
+
+#define rb_mmio(reg) \
+       (mb_inline(), \
+       (*(volatile u8 *)(mmio_regs + 0x8000 + (u32)byte_access_mmio(reg))))
+
+/* Write 8 bit MMIO register */
+
+#define wb_mmio(reg,dat) \
+       mb(); \
+       (*(volatile u8 *)(mmio_regs + 0x8000 + (byte_access_mmio((reg) & 0xffff))) = \
+       (dat & 0xff)); \
+       mb();
+
+/* Read 32 bit MMIO register */
+
+#define rl_mmio(reg) \
+       (mb_inline(), \
+       (*((volatile u32 *)((u8 *)((mmio_regs + (on_zorro2 ? 0x20000 : 0)) + (reg))))))
+
+/* Write 32 bit MMIO register */
+
+#define wl_mmio(reg,dat) \
+       mb(); \
+       ((*(volatile u32 *)((u8 *)((mmio_regs + (on_zorro2 ? 0x20000 : 0)) + (reg)))) = \
+       (u32)(dat)); \
+       mb();
+
+/* Write to virge graphics register */
+
+#define wgfx(reg, dat) do { wb_mmio(GCT_ADDRESS, (reg)); wb_mmio(GCT_ADDRESS_W, (dat)); } while (0)
+
+/* Write to virge sequencer register */
+
+#define wseq(reg, dat) do { wb_mmio(SEQ_ADDRESS, (reg)); wb_mmio(SEQ_ADDRESS_W, (dat)); } while (0)
+
+/* Write to virge CRT controller register */
+
+#define wcrt(reg, dat) do { wb_mmio(CRT_ADDRESS, (reg)); wb_mmio(CRT_ADDRESS_W, (dat)); } while (0)
+
+/* Write to virge attribute register */
+
+#define watr(reg, dat) \
+       do { \
+               volatile unsigned char watr_tmp; \
+               watr_tmp = rb_mmio(ACT_ADDRESS_RESET); \
+               wb_mmio(ACT_ADDRESS_W, (reg)); \
+               wb_mmio(ACT_ADDRESS_W, (dat)); \
+               udelay(10); \
+       } while (0)
+
+/* end of macros */
+
 struct virgefb_par {
-   int xres;
-   int yres;
-   int bpp;
-   int accel;
+   struct fb_var_screeninfo var;
+   __u32 type;
+   __u32 type_aux;
+   __u32 visual;
+   __u32 line_length;
 };
 
 static struct virgefb_par current_par;
@@ -116,6 +233,9 @@ static union {
 #ifdef FBCON_HAS_CFB16
     u16 cfb16[16];
 #endif
+#ifdef FBCON_HAS_CFB32
+    u32 cfb32[16];
+#endif
 } fbcon_cmap;
 
 /*
@@ -138,43 +258,48 @@ static struct fb_hwswitch {
    void (*blank)(int blank);
 } *fbhw;
 
-static int blit_maybe_busy = 0;
+static unsigned char blit_maybe_busy = 0;
 
 /*
  *    Frame Buffer Name
  */
 
-static char virgefb_name[16] = "Cybervision/3D";
-
+static char virgefb_name[16] = "CyberVision/3D";
 
 /*
- *    Cybervision Graphics Board
+ *    CyberVision64/3d Graphics Board
  */
 
-#define VIRGE8_WIDTH 1152
-#define VIRGE8_HEIGHT 886
-#define VIRGE8_PIXCLOCK 12500    /* ++Geert: Just a guess */
+static unsigned char virgefb_colour_table [256][3];
+static unsigned long v_ram;
+static unsigned long v_ram_size;
+static volatile unsigned char *mmio_regs;
+static volatile unsigned char *vgaio_regs;
+
+static unsigned long v_ram_phys;
+static unsigned long mmio_regs_phys;
+static unsigned long vcode_switch_base;
+static unsigned char on_zorro2;
+
+/*
+ * Offsets from start of video ram to appropriate ZIII aperture
+ */
 
-#if 1
-#define VIRGE16_WIDTH 800
-#define VIRGE16_HEIGHT 600
+#ifdef FBCON_HAS_CFB8
+#define CYBMEM_OFFSET_8  0x800000      /* BGRX */
+#endif
+#ifdef FBCON_HAS_CFB16
+#define CYBMEM_OFFSET_16 0x400000      /* GBXR */
+#endif
+#ifdef FBCON_HAS_CFB32
+#define CYBMEM_OFFSET_32 0x000000      /* XRGB */
 #endif
-#define VIRGE16_PIXCLOCK 25000   /* ++Geert: Just a guess */
-
-
-static unsigned char Cyber_colour_table [256][3];
-static unsigned long CyberMem;
-static unsigned long CyberSize;
-static volatile char *CyberRegs;
-static volatile unsigned long CyberVGARegs; /* ++Andre: for CV64/3D, see macros at the beginning */
-static unsigned long CyberMem_phys;
-static unsigned long CyberRegs_phys;
-static unsigned long Cyber_register_base;
-static unsigned long Cyber_vcode_switch_base;
-static unsigned char cv3d_on_zorro2;
-#define CYBMEM_OFFSET_8  0x800000      /* offsets from start of video - */ 
-#define CYBMEM_OFFSET_16 0x400000      /* ram to appropriate aperture */
+
+/*
+ *    MEMCLOCK was 32MHz, 64MHz works, 72MHz doesn't (on my board)
+ */
+
+#define MEMCLOCK 50000000
 
 /*
  *    Predefined Video Modes
@@ -184,125 +309,350 @@ static struct {
     const char *name;
     struct fb_var_screeninfo var;
 } virgefb_predefined[] __initdata = {
+#ifdef FBCON_HAS_CFB8
     {
        "640x480-8", {          /* Cybervision 8 bpp */
            640, 480, 640, 480, 0, 0, 8, 0,
            {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-           0, 0, -1, -1, FB_ACCELF_TEXT, VIRGE8_PIXCLOCK, 64, 96, 35, 12, 112, 2,
-           FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-       }
+           0, 0, -1, -1, FB_ACCELF_TEXT, 31250, 160, 136, 82, 61, 88, 2,
+           0, FB_VMODE_NONINTERLACED
+           }
+    }, {
+       "768x576-8", {          /* Cybervision 8 bpp */
+           768, 576, 768, 576, 0, 0, 8, 0,
+           {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+           0, 0, -1, -1, FB_ACCELF_TEXT, 29411, 144, 112, 32, 15, 64, 2,
+           0, FB_VMODE_NONINTERLACED
+           }
     }, {
        "800x600-8", {          /* Cybervision 8 bpp */
            800, 600, 800, 600, 0, 0, 8, 0,
            {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-           0, 0, -1, -1, FB_ACCELF_TEXT, VIRGE8_PIXCLOCK, 64, 96, 35, 12, 112, 2,
-           FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-       }
+           0, 0, -1, -1, FB_ACCELF_TEXT, 28571, 168, 104, 22, 1, 48, 2,
+           0, FB_VMODE_NONINTERLACED
+           }
     }, {
+  #if 0 
        "1024x768-8", {         /* Cybervision 8 bpp */
            1024, 768, 1024, 768, 0, 0, 8, 0,
            {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-           0, 0, -1, -1, FB_ACCELF_TEXT, VIRGE8_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+           0, 0, -1, -1, FB_ACCELF_TEXT, 20833, 272, 168, 39, 2, 72, 1,
+           0, FB_VMODE_NONINTERLACED
+           }
+  #else
+       "1024x768-8", {
+           1024, 768, 1024, 768, 0, 0, 8, 0,
+           {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+   #if 0
+           0, 0, -1, -1, FB_ACCELF_TEXT, 12500, 184, 40, 40, 2, 96, 1,
            FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-       }
+           }
+    #else
+           0, 0, -1, -1, FB_ACCELF_TEXT, 12699, 176, 16, 28, 1, 96, 3,
+           FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+           }
+    #endif
+  #endif
     }, {
        "1152x886-8", {         /* Cybervision 8 bpp */
            1152, 886, 1152, 886, 0, 0, 8, 0,
            {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-           0, 0, -1, -1, FB_ACCELF_TEXT, VIRGE8_PIXCLOCK, 64, 96, 35, 12, 112, 2,
-           FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-       }
+           0, 0, -1, -1, FB_ACCELF_TEXT, 19230, 280, 168, 45, 1, 64, 10,
+           0, FB_VMODE_NONINTERLACED
+           }
     }, {
-       "1280x1024-8", {        /* Cybervision 8 bpp */
+       "1280x1024-8", {        /* Cybervision 8 bpp */
            1280, 1024, 1280, 1024, 0, 0, 8, 0,
            {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-           0, 0, -1, -1, FB_ACCELF_TEXT, VIRGE8_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+  #if 0
+           0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12,
+           }
+  #else
+           0, 0, -1, -1, FB_ACCELF_TEXT, 7414, 232, 64, 38, 1, 112, 3,
            FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-       }
+           }
+  #endif
     }, {
-       "1600x1200-8", {        /* Cybervision 8 bpp */
+       "1600x1200-8", {        /* Cybervision 8 bpp */
            1600, 1200, 1600, 1200, 0, 0, 8, 0,
            {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-           0, 0, -1, -1, FB_ACCELF_TEXT, VIRGE8_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+  #if 0
+           0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12,
+           0, FB_VMODE_NONINTERLACED
+           }
+  #else
+           0, 0, -1, -1, FB_ACCELF_TEXT, 6411, 256, 32, 52, 10, 160, 8,
            FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-       }
-    }, {
+           }
+  #endif
+    },
+#endif
+
+#ifdef FBCON_HAS_CFB16
+    {
        "640x480-16", {         /* Cybervision 16 bpp */
            640, 480, 640, 480, 0, 0, 16, 0,
            {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
-           0, 0, -1, -1, FB_ACCELF_TEXT, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
-           FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-       }
+           0, 0, -1, -1, FB_ACCELF_TEXT, 31250, 152, 144, 82, 61, 88, 2,
+           0, FB_VMODE_NONINTERLACED
+           }
+    }, {
+       "768x576-16", {         /* Cybervision 16 bpp */
+           768, 576, 768, 576, 0, 0, 16, 0,
+           {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
+           0, 0, -1, -1, FB_ACCELF_TEXT, 29411, 144, 112, 32, 15, 64, 2,
+           0, FB_VMODE_NONINTERLACED
+           }
     }, {
        "800x600-16", {         /* Cybervision 16 bpp */
            800, 600, 800, 600, 0, 0, 16, 0,
            {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
-           0, 0, -1, -1, FB_ACCELF_TEXT, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
-           FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-       }
+           0, 0, -1, -1, FB_ACCELF_TEXT, 28571, 168, 104, 22, 1, 48, 2,
+           0, FB_VMODE_NONINTERLACED
+           }
     }, {
-       "1024x768-16", {         /* Cybervision 16 bpp */
+#if 0
+       "1024x768-16", {        /* Cybervision 16 bpp */
            1024, 768, 1024, 768, 0, 0, 16, 0,
            {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
-           0, 0, -1, -1, FB_ACCELF_TEXT, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
-           FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-       }
+           0, 0, -1, -1, FB_ACCELF_TEXT, 20833, 272, 168, 39, 2, 72, 1,
+           0, FB_VMODE_NONINTERLACED
+           }
+#else
+         "1024x768-16", {
+             1024, 768, 1024, 768, 0, 0, 16, 0,
+             {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
+             0, 0, -1, -1, FB_ACCELF_TEXT, 12500, 184, 40, 40, 2, 96, 1,
+             FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+         }
+#endif
     }, {
-       "1152x886-16", {         /* Cybervision 16 bpp */
+       "1152x886-16", {        /* Cybervision 16 bpp */
            1152, 886, 1152, 886, 0, 0, 16, 0,
            {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
-           0, 0, -1, -1, FB_ACCELF_TEXT, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
-           FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-       }
+           0, 0, -1, -1, FB_ACCELF_TEXT, 19230, 280, 168, 45, 1, 64, 10,
+           0, FB_VMODE_NONINTERLACED
+           }
     }, {
-       "1280x1024-16", {         /* Cybervision 16 bpp */
+       "1280x1024-16", {       /* Cybervision 16 bpp */
            1280, 1024, 1280, 1024, 0, 0, 16, 0,
            {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
-           0, 0, -1, -1, FB_ACCELF_TEXT, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
-           FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-       }
+           0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12,
+           0, FB_VMODE_NONINTERLACED
+           }
     }, {
-       "1600x1200-16", {         /* Cybervision 16 bpp */
+       "1600x1200-16", {       /* Cybervision 16 bpp */
            1600, 1200, 1600, 1200, 0, 0, 16, 0,
            {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
-           0, 0, -1, -1, FB_ACCELF_TEXT, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
-           FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-       }
-    }
-};
+           0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12,
+           0, FB_VMODE_NONINTERLACED
+           }
+    },
+#endif
+
+#ifdef FBCON_HAS_CFB32
+    {
+       "640x480-32", {         /* Cybervision 32 bpp */
+           640, 480, 640, 480, 0, 0, 32, 0,
+           {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0},
+           0, 0, -1, -1, FB_ACCELF_TEXT, 31250, 160, 136, 82, 61, 88, 2,
+           0, FB_VMODE_NONINTERLACED
+           }
+     }, {
+       "768x576-32", {         /* Cybervision 32 bpp */
+           768, 576, 768, 576, 0, 0, 32, 0,
+           {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0},
+           0, 0, -1, -1, FB_ACCELF_TEXT, 29411, 144, 112, 32, 15, 64, 2,
+           0, FB_VMODE_NONINTERLACED
+           }
+     }, {
+       "800x600-32", {         /* Cybervision 32 bpp */
+           800, 600, 800, 600, 0, 0, 32, 0,
+           {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0},
+           0, 0, -1, -1, FB_ACCELF_TEXT, 28571, 168, 104, 22, 1, 48, 2,
+           0, FB_VMODE_NONINTERLACED
+           }
+     }, {
+       "1024x768-32", {        /* Cybervision 32 bpp */
+           1024, 768, 1024, 768, 0, 0, 32, 0,
+           {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0},
+           0, 0, -1, -1, FB_ACCELF_TEXT, 20833, 272, 168, 39, 2, 72, 1,
+           0, FB_VMODE_NONINTERLACED
+           }
+    }, {
+       "1152x886-32", {        /* Cybervision 32 bpp */
+           1152, 886, 1152, 886, 0, 0, 32, 0,
+           {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0},
+           0, 0, -1, -1, FB_ACCELF_TEXT, 19230, 280, 168, 45, 1, 64, 10,
+           0, FB_VMODE_NONINTERLACED
+           }
+    }, {
+       "1280x1024-32", {       /* Cybervision 32 bpp */
+           1280, 1024, 1280, 1024, 0, 0, 32, 0,
+           {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0},
+           0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12,
+           0, FB_VMODE_NONINTERLACED
+           }
+    }, {
+       "1600x1200-32", {       /* Cybervision 32 bpp */
+           1600, 1200, 1600, 1200, 0, 0, 32, 0,
+           {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0},
+           0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12,
+           0, FB_VMODE_NONINTERLACED
+           }
+    },
+#endif
+
+/* interlaced modes */
 
+#ifdef FBCON_HAS_CFB8
+    {
+       "1024x768-8i", {        /* Cybervision 8 bpp */
+           1024, 768, 1024, 768, 0, 0, 8, 0,
+           {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+           0, 0, -1, -1, FB_ACCELF_TEXT, 20833, 272, 168, 39, 2, 72, 1,
+           0, FB_VMODE_INTERLACED
+           }
+    }, {
+       "1280x1024-8i", {       /* Cybervision 8 bpp */
+           1280, 1024, 1280, 1024, 0, 0, 8, 0,
+           {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+           0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12,
+           0, FB_VMODE_INTERLACED
+           }
+    }, {
+       "1600x1200-8i", {       /* Cybervision 8 bpp */
+           1600, 1200, 1600, 1200, 0, 0, 8, 0,
+           {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+           0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12,
+           0, FB_VMODE_INTERLACED
+           }
+    },
+#endif
 
-#define NUM_TOTAL_MODES    ARRAY_SIZE(virgefb_predefined)
+#ifdef FBCON_HAS_CFB16
+    {
+       "1024x768-16i", {       /* Cybervision 16 bpp */
+           1024, 768, 1024, 768, 0, 0, 16, 0,
+           {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
+           0, 0, -1, -1, FB_ACCELF_TEXT, 20833, 272, 168, 39, 2, 72, 1,
+           0, FB_VMODE_INTERLACED
+           }
+    }, {
+       "1280x1024-16i", {      /* Cybervision 16 bpp */
+           1280, 1024, 1280, 1024, 0, 0, 16, 0,
+           {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
+           0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12,
+           0, FB_VMODE_INTERLACED
+           }
+    }, {
+       "1600x1200-16i", {      /* Cybervision 16 bpp */
+           1600, 1200, 1600, 1200, 0, 0, 16, 0,
+           {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
+           0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12,
+           0, FB_VMODE_INTERLACED
+           }
+    },
+#endif
 
+#ifdef FBCON_HAS_CFB32
+    {
+       "1024x768-32i", {       /* Cybervision 32 bpp */
+           1024, 768, 1024, 768, 0, 0, 32, 0,
+           {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0},
+           0, 0, -1, -1, FB_ACCELF_TEXT, 22222, 216, 144, 39, 2, 72, 1,
+           0, FB_VMODE_INTERLACED
+           }
+    }, {
+       "1280x1024-32i", {      /* Cybervision 32 bpp */
+           1280, 1024, 1280, 1024, 0, 0, 32, 0,
+           {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {23, 0, 0},
+           0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12,
+           0, FB_VMODE_INTERLACED
+           }
+    }, {
+       "1600x1200-32i", {      /* Cybervision 32 bpp */
+           1600, 1200, 1600, 1200, 0, 0, 32, 0,
+           {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0},
+           0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12,
+           0, FB_VMODE_INTERLACED
+           }
+    },
+#endif
 
-static int Cyberfb_inverse = 0;
+/* doublescan modes */
+
+#ifdef FBCON_HAS_CFB8
+    {
+       "320x240-8d", {         /* Cybervision 8 bpp */
+           320, 240, 320, 240, 0, 0, 8, 0,
+           {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+           0, 0, -1, -1, FB_ACCELF_TEXT, 59259, 80, 80, 45, 26, 32, 1,
+           0, FB_VMODE_DOUBLE
+           }
+    },
+#endif
+
+#ifdef FBCON_HAS_CFB16
+    {
+       "320x240-16d", {        /* Cybervision 16 bpp */
+           320, 240, 320, 240, 0, 0, 16, 0,
+           {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
+           0, 0, -1, -1, FB_ACCELF_TEXT, 59259, 80, 80, 45, 26, 32, 1,
+           0, FB_VMODE_DOUBLE
+           }
+    },
+#endif
+
+#ifdef FBCON_HAS_CFB32
+    {
+       "320x240-32d", {        /* Cybervision 32 bpp */
+           320, 240, 320, 240, 0, 0, 32, 0,
+           {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0},
+           0, 0, -1, -1, FB_ACCELF_TEXT, 59259, 80, 80, 45, 26, 32, 1,
+           0, FB_VMODE_DOUBLE
+           }
+    },
+#endif
+};
+
+#define arraysize(x)   (sizeof(x)/sizeof(*(x)))
+#define NUM_TOTAL_MODES        arraysize(virgefb_predefined)
 
 /*
- *    Some default modes
+ *    Default to 800x600 for video=virge8:, virge16: or virge32:
  */
 
-#define VIRGE8_DEFMODE     (1)
-#define VIRGE16_DEFMODE    (7)
+#ifdef FBCON_HAS_CFB8
+#define VIRGE8_DEFMODE (2)
+#endif
 
-static struct fb_var_screeninfo virgefb_default;
+#ifdef FBCON_HAS_CFB16
+#define VIRGE16_DEFMODE        (9)
+#endif
+
+#ifdef FBCON_HAS_CFB32
+#define VIRGE32_DEFMODE        (16)
+#endif
 
+static struct fb_var_screeninfo virgefb_default;
+static int virgefb_inverse = 0;
 
 /*
  *    Interface used by the world
  */
 
 int virgefb_setup(char*);
-
-static int virgefb_get_fix(struct fb_fix_screeninfo *fix, int con, struct
-fb_info *info);
-static int virgefb_get_var(struct fb_var_screeninfo *var, int con, struct
-fb_info *info);
-static int virgefb_set_var(struct fb_var_screeninfo *var, int con, struct
-fb_info *info);
+static int virgefb_get_fix(struct fb_fix_screeninfo *fix, int con,
+                          struct fb_info *info);
+static int virgefb_get_var(struct fb_var_screeninfo *var, int con,
+                          struct fb_info *info);
+static int virgefb_set_var(struct fb_var_screeninfo *var, int con,
+                          struct fb_info *info);
 static int virgefb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-                           struct fb_info *info);
+                          struct fb_info *info);
 static int virgefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                         u_int transp, struct fb_info *info);
+                            u_int transp, struct fb_info *info);
 static int virgefb_blank(int blank, struct fb_info *info);
 
 /*
@@ -310,8 +660,8 @@ static int virgefb_blank(int blank, struct fb_info *info);
  */
 
 int virgefb_init(void);
-static int Cyberfb_switch(int con, struct fb_info *info);
-static int Cyberfb_updatevar(int con, struct fb_info *info);
+static int virgefb_switch(int con, struct fb_info *info);
+static int virgefb_updatevar(int con, struct fb_info *info);
 
 /*
  *    Text console acceleration
@@ -325,21 +675,29 @@ static struct display_switch fbcon_virge8;
 static struct display_switch fbcon_virge16;
 #endif
 
+#ifdef FBCON_HAS_CFB32
+static struct display_switch fbcon_virge32;
+#endif
+
 /*
  *   Hardware Specific Routines
  */
 
-static int Cyber_init(void);
-static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
-                          struct virgefb_par *par);
-static int Cyber_decode_var(struct fb_var_screeninfo *var,
-                          struct virgefb_par *par);
-static int Cyber_encode_var(struct fb_var_screeninfo *var,
-                          struct virgefb_par *par);
-static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-                         u_int *transp, struct fb_info *info);
-static void Cyber_blank(int blank);
-
+static int virge_init(void);
+static int virgefb_encode_fix(struct fb_fix_screeninfo *fix,
+                               struct virgefb_par *par);
+static int virgefb_decode_var(struct fb_var_screeninfo *var,
+                               struct virgefb_par *par);
+static int virgefb_encode_var(struct fb_var_screeninfo *var,
+                               struct virgefb_par *par);
+static int virgefb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+                               u_int *transp, struct fb_info *info);
+static void virgefb_gfx_on_off(int blank);
+static inline void virgefb_wait_for_idle(void);
+static void virgefb_BitBLT(u_short curx, u_short cury, u_short destx, u_short desty,
+               u_short width, u_short height, u_short stride, u_short depth);
+static void virgefb_RectFill(u_short x, u_short y, u_short width, u_short height,
+               u_short color, u_short stride, u_short depth);
 
 /*
  *    Internal routines
@@ -347,69 +705,249 @@ static void Cyber_blank(int blank);
 
 static void virgefb_get_par(struct virgefb_par *par);
 static void virgefb_set_par(struct virgefb_par *par);
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
+static int virgefb_do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
 static void virgefb_set_disp(int con, struct fb_info *info);
-static int get_video_mode(const char *name);
+static int virgefb_get_video_mode(const char *name);
+static void virgefb_set_video(struct fb_var_screeninfo *var);
 
+/*
+ *    Additions for Initialization
+ */
+
+static void virgefb_load_video_mode(struct fb_var_screeninfo *video_mode);
+static int cv3d_has_4mb(void);
+static unsigned short virgefb_compute_clock(unsigned long freq);
+static inline unsigned char rattr(short);
+static inline unsigned char rseq(short);
+static inline unsigned char rcrt(short);
+static inline unsigned char rgfx(short);
+static inline void gfx_on_off(int toggle);
+static void virgefb_pci_init(void);
 
 /* -------------------- Hardware specific routines ------------------------- */
 
+/*
+ *     Functions for register access
+ */
+
+/* Read attribute controller register */
+
+static inline unsigned char rattr(short idx)
+{
+       volatile unsigned char rattr_tmp;
+
+       rattr_tmp = rb_mmio(ACT_ADDRESS_RESET);
+       wb_mmio(ACT_ADDRESS_W, idx);
+       return (rb_mmio(ACT_ADDRESS_R));
+}
+
+/* Read sequencer register */
+
+static inline unsigned char rseq(short idx)
+{
+       wb_mmio(SEQ_ADDRESS, idx);
+       return (rb_mmio(SEQ_ADDRESS_R));
+}
+
+/* Read CRT controller register */
+
+static inline unsigned char rcrt(short idx)
+{
+       wb_mmio(CRT_ADDRESS, idx);
+       return (rb_mmio(CRT_ADDRESS_R));
+}
+
+/* Read graphics controller register */
+
+static inline unsigned char rgfx(short idx)
+{
+       wb_mmio(GCT_ADDRESS, idx);
+       return (rb_mmio(GCT_ADDRESS_R));
+}
+
 
 /*
- *    Initialization
- *
- *    Set the default video mode for this chipset. If a video mode was
- *    specified on the command line, it will override the default mode.
+ *     Initialization
  */
 
-static int Cyber_init(void)
+/* PCI init */
+
+void virgefb_pci_init(void) {
+
+       DPRINTK("ENTER\n");
+
+       SelectCFG;
+
+       if (on_zorro2) {
+               *((short *)(vgaio_regs + 0x00000010)) = 0;
+               *((long  *)(vgaio_regs + 0x00000004)) = 0x02000003;
+       } else {
+               *((short *)(vgaio_regs + 0x000e0010)) = 0;
+               *((long  *)(vgaio_regs + 0x000e0004)) = 0x02000003;
+       }
+
+       /* SelectIO is in wb_vgaio macro */
+       wb_vgaio(SREG_VIDEO_SUBS_ENABLE, 0x01);
+       /* SelectMMIO is in wb_vgaio macro */
+
+       DPRINTK("EXIT\n");
+
+       return;
+}
+
+/* 
+ * Initalize all mode independent regs, find mem size and clear mem
+*/
+
+static int virge_init(void)
 {
        int i;
+       unsigned char tmp;
 
-       for (i = 0; i < 256; i++)
-       {
-               Cyber_colour_table [i][0] = i;
-               Cyber_colour_table [i][1] = i;
-               Cyber_colour_table [i][2] = i;
-       }
+       DPRINTK("ENTER\n");
+
+       virgefb_pci_init();
+
+       wb_mmio(GREG_MISC_OUTPUT_W, 0x07);      /* colour, ram enable, clk sel */
+
+       wseq(SEQ_ID_UNLOCK_EXT, 0x06);          /* unlock extensions */
+       tmp = rb_mmio(GREG_MISC_OUTPUT_R);
+       wcrt(CRT_ID_REGISTER_LOCK_1, 0x48);     /* unlock CR2D to CR3F */
+
+       wcrt(CRT_ID_BACKWAD_COMP_1, 0x00);      /* irq disable */
+
+       wcrt(CRT_ID_REGISTER_LOCK_2, 0xa5);     /* unlock CR40 to CRFF and more */
+       wcrt(CRT_ID_REGISTER_LOCK,0x00);        /* unlock h and v timing */
+       wcrt(CRT_ID_SYSTEM_CONFIG, 0x01);       /* unlock enhanced programming registers */
 
-       /*
-        * Just clear the thing for the biggest mode.
-        *
-        * ++Andre, TODO: determine size first, then clear all memory
-        *                (the 3D penguin might need texture memory :-) )
-        */
+       wb_mmio(GREG_FEATURE_CONTROL_W, 0x00);
 
-       if (cv3d_on_zorro2) {
-               CyberSize = 0x00380000; /* 3.5 MB , we need some space for the registers? */
+       wcrt(CRT_ID_EXT_MISC_CNTL, 0x00);       /* b2 = 0 to allow VDAC mmio access */
+#if 0
+       /* write strap options ... ? */
+       wcrt(CRT_ID_CONFIG_1, 0x08);
+       wcrt(CRT_ID_CONFIG_2, 0xff);            /* 0x0x2 bit needs to be set ?? */
+       wcrt(CRT_ID_CONFIG_3, 0x0f);
+       wcrt(CRT_ID_CONFIG_4, 0x1a);
+#endif
+       wcrt(CRT_ID_EXT_MISC_CNTL_1, 0x82);      /* PCI DE and software reset S3D engine */
+       /* EXT_MISC_CNTL_1, CR66 bit 0 should be the same as bit 0 MR_ADVANCED_FUNCTION_CONTROL - check */
+       wl_mmio(MR_ADVANCED_FUNCTION_CONTROL, 0x00000011); /* enhanced mode, linear addressing */
+
+/* crtc registers */
+
+       wcrt(CRT_ID_PRESET_ROW_SCAN, 0x00);
+
+       /* Disable h/w cursor */
+
+       wcrt(CRT_ID_CURSOR_START, 0x00);
+       wcrt(CRT_ID_CURSOR_END, 0x00);
+       wcrt(CRT_ID_START_ADDR_HIGH, 0x00);
+       wcrt(CRT_ID_START_ADDR_LOW, 0x00);
+       wcrt(CRT_ID_CURSOR_LOC_HIGH, 0x00);
+       wcrt(CRT_ID_CURSOR_LOC_LOW, 0x00);
+       wcrt(CRT_ID_EXT_MODE, 0x00);
+       wcrt(CRT_ID_HWGC_MODE, 0x00);
+       wcrt(CRT_ID_HWGC_ORIGIN_X_HI, 0x00);
+       wcrt(CRT_ID_HWGC_ORIGIN_X_LO, 0x00);
+       wcrt(CRT_ID_HWGC_ORIGIN_Y_HI, 0x00);
+       wcrt(CRT_ID_HWGC_ORIGIN_Y_LO, 0x00);
+       i = rcrt(CRT_ID_HWGC_MODE);
+       wcrt(CRT_ID_HWGC_FG_STACK, 0x00);
+       wcrt(CRT_ID_HWGC_FG_STACK, 0x00);
+       wcrt(CRT_ID_HWGC_FG_STACK, 0x00);
+       wcrt(CRT_ID_HWGC_BG_STACK, 0x00);
+       wcrt(CRT_ID_HWGC_BG_STACK, 0x00);
+       wcrt(CRT_ID_HWGC_BG_STACK, 0x00);
+       wcrt(CRT_ID_HWGC_START_AD_HI, 0x00);
+       wcrt(CRT_ID_HWGC_START_AD_LO, 0x00);
+       wcrt(CRT_ID_HWGC_DSTART_X, 0x00);
+       wcrt(CRT_ID_HWGC_DSTART_Y, 0x00);
+
+       wcrt(CRT_ID_UNDERLINE_LOC, 0x00);
+
+       wcrt(CRT_ID_MODE_CONTROL, 0xe3);
+       wcrt(CRT_ID_BACKWAD_COMP_2, 0x22);      /* blank bdr bit 5 blanking only on 8 bit */
+
+       wcrt(CRT_ID_EX_SYNC_1, 0x00);
+
+       /* memory */
+
+       wcrt(CRT_ID_EXT_SYS_CNTL_3, 0x00);
+       wcrt(CRT_ID_MEMORY_CONF, 0x08);         /* config enhanced map */
+       wcrt(CRT_ID_EXT_MEM_CNTL_1, 0x08);      /* MMIO Select (0x0c works as well)*/
+       wcrt(CRT_ID_EXT_MEM_CNTL_2, 0x02);      /* why 02 big endian 00 works ? */
+       wcrt(CRT_ID_EXT_MEM_CNTL_4, 0x9f);      /* config big endian - 0x00 ?  */
+       wcrt(CRT_ID_LAW_POS_HI, 0x00);
+       wcrt(CRT_ID_LAW_POS_LO, 0x00);
+       wcrt(CRT_ID_EXT_MISC_CNTL_1, 0x81);
+       wcrt(CRT_ID_MISC_1, 0x90);              /* must follow CRT_ID_EXT_MISC_CNTL_1 */
+       wcrt(CRT_ID_LAW_CNTL, 0x13);            /* force 4 Meg for test */
+       if (cv3d_has_4mb()) {
+               v_ram_size = 0x00400000;
+               wcrt(CRT_ID_LAW_CNTL, 0x13);    /* 4 MB */
        } else {
-               CyberSize = 0x00400000; /* 4 MB */
+               v_ram_size = 0x00200000;
+               wcrt(CRT_ID_LAW_CNTL, 0x12);    /* 2 MB */
+       }
+
+       if (on_zorro2)
+               v_ram_size -= 0x60000;          /* we need some space for the registers */
+
+       wcrt(CRT_ID_EXT_SYS_CNTL_4, 0x00);
+       wcrt(CRT_ID_EXT_DAC_CNTL, 0x00);        /* 0x10 for X11 cursor mode */
+
+/* sequencer registers */
+
+       wseq(SEQ_ID_CLOCKING_MODE, 0x01);       /* 8 dot clock */
+       wseq(SEQ_ID_MAP_MASK, 0xff);
+       wseq(SEQ_ID_CHAR_MAP_SELECT, 0x00);
+       wseq(SEQ_ID_MEMORY_MODE, 0x02);
+       wseq(SEQ_ID_RAMDAC_CNTL, 0x00);
+       wseq(SEQ_ID_SIGNAL_SELECT, 0x00);
+       wseq(SEQ_ID_EXT_SEQ_REG9, 0x00);        /* MMIO and PIO reg access enabled */
+       wseq(SEQ_ID_EXT_MISC_SEQ, 0x00);
+       wseq(SEQ_ID_CLKSYN_CNTL_1, 0x00);
+       wseq(SEQ_ID_EXT_SEQ, 0x00);
+
+/* graphic registers */
+
+       wgfx(GCT_ID_SET_RESET, 0x00);
+       wgfx(GCT_ID_ENABLE_SET_RESET, 0x00);
+       wgfx(GCT_ID_COLOR_COMPARE, 0x00);
+       wgfx(GCT_ID_DATA_ROTATE, 0x00);
+       wgfx(GCT_ID_READ_MAP_SELECT, 0x00);
+       wgfx(GCT_ID_GRAPHICS_MODE, 0x40);
+       wgfx(GCT_ID_MISC, 0x01);
+       wgfx(GCT_ID_COLOR_XCARE, 0x0f);
+       wgfx(GCT_ID_BITMASK, 0xff);
+
+/* attribute  registers */
+
+       for(i = 0; i <= 15; i++)
+               watr(ACT_ID_PALETTE0 + i, i);
+       watr(ACT_ID_ATTR_MODE_CNTL, 0x41);
+       watr(ACT_ID_OVERSCAN_COLOR, 0xff);
+       watr(ACT_ID_COLOR_PLANE_ENA, 0x0f);
+       watr(ACT_ID_HOR_PEL_PANNING, 0x00);
+       watr(ACT_ID_COLOR_SELECT, 0x00);
+
+       wb_mmio(VDAC_MASK, 0xff);
+
+/* init local cmap as greyscale levels */
+
+       for (i = 0; i < 256; i++) {
+               virgefb_colour_table [i][0] = i;
+               virgefb_colour_table [i][1] = i;
+               virgefb_colour_table [i][2] = i;
        }
 
-       memset ((char*)CyberMem, 0, CyberSize);
-
-       /* Disable hardware cursor */
-       vgawb_3d(0x3c8, 255);
-       vgawb_3d(0x3c9, 56);
-       vgawb_3d(0x3c9, 100);
-       vgawb_3d(0x3c9, 160);
-
-       vgawb_3d(0x3c8, 254);
-       vgawb_3d(0x3c9, 0);
-       vgawb_3d(0x3c9, 0);
-       vgawb_3d(0x3c9, 0);
-
-       /* Disable hardware cursor */
-       vgawb_3d(S3_CRTC_ADR, S3_REG_LOCK2);
-       vgawb_3d(S3_CRTC_DATA, 0xa0);
-       vgawb_3d(S3_CRTC_ADR, S3_HGC_MODE);
-       vgawb_3d(S3_CRTC_DATA, 0x00);
-       vgawb_3d(S3_CRTC_ADR, S3_HWGC_DX);
-       vgawb_3d(S3_CRTC_DATA, 0x00);
-       vgawb_3d(S3_CRTC_ADR, S3_HWGC_DY);
-       vgawb_3d(S3_CRTC_DATA, 0x00);
-
-       return 0; /* TODO: hardware cursor for CV64/3D */
+/* clear framebuffer memory */
+
+       memset((char*)v_ram, 0x00, v_ram_size);
+
+       DPRINTK("EXIT\n");
+       return 0;
 }
 
 
@@ -418,30 +956,49 @@ static int Cyber_init(void)
  *    values in the `par' structure.
  */
 
-static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
+static int virgefb_encode_fix(struct fb_fix_screeninfo *fix,
                            struct virgefb_par *par)
 {
+       DPRINTK("ENTER set video phys addr\n");
+
        memset(fix, 0, sizeof(struct fb_fix_screeninfo));
        strcpy(fix->id, virgefb_name);
-       if (cv3d_on_zorro2) {
-               fix->smem_start = CyberMem_phys;
-       } else {
-               switch (par->bpp) {
-                       case 8:
-                               fix->smem_start = (CyberMem_phys + CYBMEM_OFFSET_8);
-                               break;
-                       case 16:
-                               fix->smem_start = (CyberMem_phys + CYBMEM_OFFSET_16);
-                               break;
-               }
+       if (on_zorro2)
+               fix->smem_start = v_ram_phys;
+       switch (par->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
+               case 8:
+                       if (on_zorro2)
+                               Select_Zorro2_FrameBuffer(ENDIAN_BYTE);
+                       else
+                               fix->smem_start = (v_ram_phys + CYBMEM_OFFSET_8);
+                       break;
+#endif
+#ifdef FBCON_HAS_CFB16
+               case 16:
+                       if (on_zorro2)
+                               Select_Zorro2_FrameBuffer(ENDIAN_WORD);
+                       else
+                               fix->smem_start = (v_ram_phys + CYBMEM_OFFSET_16);
+                       break;
+#endif
+#ifdef FBCON_HAS_CFB32
+               case 32:
+                       if (on_zorro2)
+                               Select_Zorro2_FrameBuffer(ENDIAN_LONG);
+                       else
+                               fix->smem_start = (v_ram_phys + CYBMEM_OFFSET_32);
+                       break;
+#endif
        }
-       fix->smem_len = CyberSize;
-       fix->mmio_start = CyberRegs_phys;
+
+       fix->smem_len = v_ram_size;
+       fix->mmio_start = mmio_regs_phys;
        fix->mmio_len = 0x10000; /* TODO: verify this for the CV64/3D */
 
        fix->type = FB_TYPE_PACKED_PIXELS;
        fix->type_aux = 0;
-       if (par->bpp == 8)
+       if (par->var.bits_per_pixel == 8)
                fix->visual = FB_VISUAL_PSEUDOCOLOR;
        else
                fix->visual = FB_VISUAL_TRUECOLOR;
@@ -449,116 +1006,117 @@ static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
        fix->xpanstep = 0;
        fix->ypanstep = 0;
        fix->ywrapstep = 0;
-       fix->line_length = 0;
+       fix->line_length = par->var.xres_virtual*par->var.bits_per_pixel/8;
        fix->accel = FB_ACCEL_S3_VIRGE;
-       return(0);
+       DPRINTK("EXIT v_ram_phys = 0x%8.8lx\n", (unsigned long)fix->smem_start);
+       return 0;
 }
 
 
 /*
- *    Get the video params out of `var'. If a value doesn't fit, round
- *    it up, if it's too big, return -EINVAL.
+ *     Fill the `par' structure based on the values in `var'.
+ *     TODO: Verify and adjust values, return -EINVAL if bad.
  */
 
-static int Cyber_decode_var(struct fb_var_screeninfo *var,
+static int virgefb_decode_var(struct fb_var_screeninfo *var,
                            struct virgefb_par *par)
 {
-#if 1
-       par->xres = var->xres;
-       par->yres = var->yres;
-       par->bpp = var->bits_per_pixel;
-       if (var->accel_flags & FB_ACCELF_TEXT)
-           par->accel = FB_ACCELF_TEXT;
+       DPRINTK("ENTER\n");
+       par->var.xres = var->xres;
+       par->var.yres = var->yres;
+       par->var.xres_virtual = var->xres_virtual;
+       par->var.yres_virtual = var->yres_virtual;
+       /* roundup and validate */
+       par->var.xres = (par->var.xres+7) & ~7;
+       par->var.xres_virtual = (par->var.xres_virtual+7) & ~7;
+       if (par->var.xres_virtual < par->var.xres)
+               par->var.xres_virtual = par->var.xres;
+       if (par->var.yres_virtual < par->var.yres)
+               par->var.yres_virtual = par->var.yres;
+       par->var.xoffset = var->xoffset;
+       par->var.yoffset = var->yoffset;
+       par->var.bits_per_pixel = var->bits_per_pixel;
+       if (par->var.bits_per_pixel <= 8)
+               par->var.bits_per_pixel = 8;
+       else if (par->var.bits_per_pixel <= 16)
+               par->var.bits_per_pixel = 16;
        else
-           par->accel = 0;
-#else
-       if (Cyberfb_Cyber8) {
-               par->xres = VIRGE8_WIDTH;
-               par->yres = VIRGE8_HEIGHT;
-               par->bpp = 8;
+               par->var.bits_per_pixel = 32;
+#ifndef FBCON_HAS_CFB32
+       if (par->var.bits_per_pixel == 32)
+               par->var.bits_per_pixel = 16;
+#endif
+#ifndef FBCON_HAS_CFB16
+       if (par->var.bits_per_pixel == 16)
+               par->var.bits_per_pixel = 8;
+#endif
+       par->var.grayscale = var->grayscale;
+       par->var.red = var->red;
+       par->var.green = var->green;
+       par->var.blue = var->blue;
+       par->var.transp = var->transp;
+       par->var.nonstd = var->nonstd;
+       par->var.activate = var->activate;
+       par->var.height = var->height;
+       par->var.width = var->width;
+       if (var->accel_flags & FB_ACCELF_TEXT) {
+               par->var.accel_flags = FB_ACCELF_TEXT;
        } else {
-               par->xres = VIRGE16_WIDTH;
-               par->yres = VIRGE16_HEIGHT;
-               par->bpp = 16;
+               par->var.accel_flags = 0;
        }
-#endif
-       return(0);
+       par->var.pixclock = var->pixclock;
+       par->var.left_margin = var->left_margin;
+       par->var.right_margin = var->right_margin;
+       par->var.upper_margin = var->upper_margin;
+       par->var.lower_margin = var->lower_margin;
+       par->var.hsync_len = var->hsync_len;
+       par->var.vsync_len = var->vsync_len;
+       par->var.sync = var->sync;
+       par->var.vmode = var->vmode;
+       DPRINTK("EXIT\n");
+       return 0;
 }
 
-
 /*
- *    Fill the `var' structure based on the values in `par' and maybe
- *    other values read out of the hardware.
+ *     Fill the `var' structure based on the values in `par' and maybe
+ *     other values read out of the hardware.
  */
 
-static int Cyber_encode_var(struct fb_var_screeninfo *var,
-                           struct virgefb_par *par)
+static int virgefb_encode_var(struct fb_var_screeninfo *var,
+                               struct virgefb_par *par)
 {
-       memset(var, 0, sizeof(struct fb_var_screeninfo));
-       var->xres = par->xres;
-       var->yres = par->yres;
-       var->xres_virtual = par->xres;
-       var->yres_virtual = par->yres;
-       var->xoffset = 0;
-       var->yoffset = 0;
-
-       var->bits_per_pixel = par->bpp;
-       var->grayscale = 0;
-
-       switch (var->bits_per_pixel) {
-               case 8:         /* CLUT */
-                       var->red.offset = 0;
-                       var->red.length = 6;
-                       var->red.msb_right = 0;
-                       var->blue = var->green = var->red;
-                       break;
-               case 16:        /* RGB 565 */
-                       var->red.offset = 11;
-                       var->red.length = 5;
-                       var->green.offset = 5;
-                       var->green.length = 6;
-                       var->blue.offset = 0;
-                       var->blue.length = 5;
-                       var->transp.offset = 0;
-                       var->transp.length = 0;
-                       break;
-       }
-       var->red.msb_right = 0;
-       var->green.msb_right = 0;
-       var->blue.msb_right = 0;
-       var->transp.msb_right = 0;
-
-       var->nonstd = 0;
-       var->activate = 0;
-
-       var->height = -1;
-       var->width = -1;
-
-       var->accel_flags = (par->accel &&
-               ((par->bpp == 8) || (par->bpp == 16))) ? FB_ACCELF_TEXT : 0;
-
-/*     printk("CV64/3D : %s\n",(var->accel_flags ? "accel" : "no accel")); */
-
-       var->vmode = FB_VMODE_NONINTERLACED;
-
-       /* Dummy values */
-
-       if (par->bpp == 8)
-               var->pixclock = VIRGE8_PIXCLOCK;
-       else
-               var->pixclock = VIRGE16_PIXCLOCK;
-       var->sync = 0;
-       var->left_margin = 64;
-       var->right_margin = 96;
-       var->upper_margin = 35;
-       var->lower_margin = 12;
-       var->hsync_len = 112;
-       var->vsync_len = 2;
-
-       return(0);
+       DPRINTK("ENTER\n");
+       memset(var, 0, sizeof(struct fb_var_screeninfo));       /* need this ? */
+       var->xres = par->var.xres;
+       var->yres = par->var.yres;
+       var->xres_virtual = par->var.xres_virtual;
+       var->yres_virtual = par->var.yres_virtual;
+       var->xoffset = par->var.xoffset;
+       var->yoffset = par->var.yoffset;
+       var->bits_per_pixel = par->var.bits_per_pixel;
+       var->grayscale = par->var.grayscale;
+       var->red = par->var.red;
+       var->green = par->var.green;
+       var->blue = par->var.blue;
+       var->transp = par->var.transp;
+       var->nonstd = par->var.nonstd;
+       var->activate = par->var.activate;
+       var->height = par->var.height;
+       var->width = par->var.width;
+       var->accel_flags = par->var.accel_flags;
+       var->pixclock = par->var.pixclock;
+       var->left_margin = par->var.left_margin;
+       var->right_margin = par->var.right_margin;
+       var->upper_margin = par->var.upper_margin;
+       var->lower_margin = par->var.lower_margin;
+       var->hsync_len = par->var.hsync_len;
+       var->vsync_len = par->var.vsync_len;
+       var->sync = par->var.sync;
+       var->vmode = par->var.vmode;
+       DPRINTK("EXIT\n");
+       return 0;
 }
 
-
 /*
  *    Set a single color register. The values supplied are already
  *    rounded down to the hardware's capabilities (according to the
@@ -568,23 +1126,26 @@ static int Cyber_encode_var(struct fb_var_screeninfo *var,
 static int virgefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
                             u_int transp, struct fb_info *info)
 {
-       if (((current_par.bpp==8) && (regno>255)) ||
-               ((current_par.bpp!=8) && (regno>15)))
-                       return (1);
-
-       if (((current_par.bpp==8) && (regno<256)) || ((current_par.bpp==16) &&(regno<16))) {
-               Cyber_colour_table [regno][0] = red >> 10;
-               Cyber_colour_table [regno][1] = green >> 10;
-               Cyber_colour_table [regno][2] = blue >> 10;
+       DPRINTK("ENTER\n");
+       if (((current_par.var.bits_per_pixel==8) && (regno>255)) ||
+               ((current_par.var.bits_per_pixel!=8) && (regno>15))) {
+                       DPRINTK("EXIT\n");
+                       return 1;
+       }
+       if (((current_par.var.bits_per_pixel==8) && (regno<256)) ||
+                       ((current_par.var.bits_per_pixel!=8) && (regno<16))) {
+               virgefb_colour_table [regno][0] = red >> 10;
+               virgefb_colour_table [regno][1] = green >> 10;
+               virgefb_colour_table [regno][2] = blue >> 10;
        }
 
-       switch (current_par.bpp) {
+       switch (current_par.var.bits_per_pixel) {
 #ifdef FBCON_HAS_CFB8
                case 8:
-                       vgawb_3d(0x3c8, (unsigned char) regno);
-                       vgawb_3d(0x3c9, ((unsigned char) (red >> 10)));
-                       vgawb_3d(0x3c9, ((unsigned char) (green >> 10)));
-                       vgawb_3d(0x3c9, ((unsigned char) (blue >> 10)));
+                       wb_mmio(VDAC_ADDRESS_W, (unsigned char)regno);
+                       wb_mmio(VDAC_DATA, ((unsigned char)(red >> 10)));
+                       wb_mmio(VDAC_DATA, ((unsigned char)(green >> 10)));
+                       wb_mmio(VDAC_DATA, ((unsigned char)(blue >> 10)));
                        break;
 #endif
 #ifdef FBCON_HAS_CFB16
@@ -594,9 +1155,19 @@ static int virgefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
                                ((green & 0xfc00) >> 5) |
                                ((blue  & 0xf800) >> 11));
                        break;
+#endif
+#ifdef FBCON_HAS_CFB32
+               case 32:
+                       fbcon_cmap.cfb32[regno] =
+                               /* transp = 0's or 1's  ? */
+                               (((red  & 0xff00) << 8) |
+                               ((green & 0xff00) >> 0) |
+                               ((blue  & 0xff00) >> 8));
+                       break;
 #endif
        }
-       return (0);
+       DPRINTK("EXIT\n");
+       return 0;
 }
 
 
@@ -605,25 +1176,29 @@ static int virgefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
  *    colors/transparent. Return != 0 for invalid regno.
  */
 
-static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+static int virgefb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
                           u_int *transp, struct fb_info *info)
 {
        int t;
 
-       if (regno > 255)
-               return (1);
-
-       if (((current_par.bpp==8) && (regno<256)) || ((current_par.bpp==16) && (regno<16))) {
-
-               t = Cyber_colour_table [regno][0];
-               *red    = (t<<10) | (t<<4) | (t>>2);
-               t = Cyber_colour_table [regno][1];
-               *green  = (t<<10) | (t<<4) | (t>>2);
-               t = Cyber_colour_table [regno][2];
-               *blue   = (t<<10) | (t<<4) | (t>>2);
+       DPRINTK("ENTER\n");
+       if (regno > 255) {
+               DPRINTK("EXIT\n");
+               return 1;
+       }
+       if (((current_par.var.bits_per_pixel==8) && (regno<256)) ||
+                       ((current_par.var.bits_per_pixel!=8) && (regno<16))) {
+
+               t = virgefb_colour_table [regno][0];
+               *red = (t<<10) | (t<<4) | (t>>2);
+               t = virgefb_colour_table [regno][1];
+               *green = (t<<10) | (t<<4) | (t>>2);
+               t = virgefb_colour_table [regno][2];
+               *blue = (t<<10) | (t<<4) | (t>>2);
        }
        *transp = 0;
-       return (0);
+       DPRINTK("EXIT\n");
+       return 0;
 }
 
 
@@ -631,75 +1206,37 @@ static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
  *    (Un)Blank the screen
  */
 
-void Cyber_blank(int blank)
+static void virgefb_gfx_on_off(int blank)
 {
-       int i;
-
-       if (blank)
-       {
-               for (i = 0; i < 256; i++)
-               {
-                       vgawb_3d(0x3c8, (unsigned char) i);
-                       vgawb_3d(0x3c9, 0);
-                       vgawb_3d(0x3c9, 0);
-                       vgawb_3d(0x3c9, 0);
-               }
-       }
-       else
-       {
-               for (i = 0; i < 256; i++)
-               {
-                       vgawb_3d(0x3c8, (unsigned char) i);
-                       vgawb_3d(0x3c9, Cyber_colour_table[i][0]);
-                       vgawb_3d(0x3c9, Cyber_colour_table[i][1]);
-                       vgawb_3d(0x3c9, Cyber_colour_table[i][2]);
-               }
-       }
+       DPRINTK("ENTER\n");
+       gfx_on_off(blank);
+       DPRINTK("EXIT\n");
 }
 
 /*
  * CV3D low-level support
  */
 
-#define Cyber3D_WaitQueue(v) \
-{ \
-        do { \
-               while ((rl_3d(0x8504) & 0x1f00) < (((v)+2) << 8)); \
-        } \
-       while (0); \
-}
 
-static inline void Cyber3D_WaitBusy(void)
+static inline void wait_3d_fifo_slots(int n)   /* WaitQueue */
 {
-unsigned long status;
-
        do {
                mb();
-               status = rl_3d(0x8504);
-       } while (!(status & (1 << 13)));
-       blit_maybe_busy = 0;
+       } while (((rl_mmio(MR_SUBSYSTEM_STATUS_R) >> 8) & 0x1f) < (n + 2));
 }
 
-#define S3V_BITBLT     (0x0 << 27)
-#define S3V_RECTFILL   (0x2 << 27)
-#define S3V_AUTOEXE    0x01
-#define S3V_HWCLIP     0x02
-#define S3V_DRAW       0x20
-#define S3V_DST_8BPP   0x00
-#define S3V_DST_16BPP  0x04
-#define S3V_DST_24BPP  0x08
-#define S3V_MONO_PAT   0x100
-
-#define S3V_BLT_COPY   (0xcc<<17)
-#define S3V_BLT_CLEAR  (0x00<<17)
-#define S3V_BLT_SET    (0xff<<17)
+static inline void virgefb_wait_for_idle(void) /* WaitIdle */
+{
+       while(!(rl_mmio(MR_SUBSYSTEM_STATUS_R) & 0x2000)) ;
+       blit_maybe_busy = 0;
+}
 
  /*
   * BitBLT - Through the Plane
   */
 
-static void Cyber3D_BitBLT(u_short curx, u_short cury, u_short destx,
-                          u_short desty, u_short width, u_short height, u_short depth)
+static void virgefb_BitBLT(u_short curx, u_short cury, u_short destx, u_short desty,
+                       u_short width, u_short height, u_short stride, u_short depth)
 {
        unsigned int blitcmd = S3V_BITBLT | S3V_DRAW | S3V_BLT_COPY;
 
@@ -713,62 +1250,57 @@ static void Cyber3D_BitBLT(u_short curx, u_short cury, u_short destx,
                case 16 :
                        blitcmd |= S3V_DST_16BPP;
                        break;
+#endif
+#ifdef FBCON_HAS_CFB32
+               case 32 :
+                       /* 32 bit uses 2 by 16 bit values, see fbcon_virge32_bmove */
+                       blitcmd |= S3V_DST_16BPP;
+                       break;
 #endif
        }
 
        /* Set drawing direction */
        /* -Y, X maj, -X (default) */
-       if (curx > destx)
-       {
+       if (curx > destx) {
                blitcmd |= (1 << 25);  /* Drawing direction +X */
-       }
-       else
-       {
+       } else {
                curx  += (width - 1);
                destx += (width - 1);
        }
 
-       if (cury > desty)
-       {
+       if (cury > desty) {
                blitcmd |= (1 << 26);  /* Drawing direction +Y */
-       }
-       else
-       {
+       } else {
                cury  += (height - 1);
                desty += (height - 1);
        }
 
+       wait_3d_fifo_slots(8);          /* wait on fifo slots for 8 writes */
+
        if (blit_maybe_busy)
-               Cyber3D_WaitBusy();
+               virgefb_wait_for_idle();
        blit_maybe_busy = 1;
 
-       wl_3d(0xa4f4, 1); /* pattern fb color */
-
-       wl_3d(0xa4e8, ~0); /* mono pat 0 */
-       wl_3d(0xa4ec, ~0); /* mono pat 1 */
-
-       wl_3d(0xa504, ((width << 16) | height));        /* rwidth_height */
-       wl_3d(0xa508, ((curx << 16)  | cury));          /* rsrc_xy */
-       wl_3d(0xa50c, ((destx << 16) | desty));         /* rdest_xy */
-
-       wl_3d(0xa500, blitcmd);                         /* GO! */
+       wl_mmio(BLT_PATTERN_COLOR, 1);  /* pattern fb color */
+       wl_mmio(BLT_MONO_PATTERN_0, ~0);
+       wl_mmio(BLT_MONO_PATTERN_1, ~0);
+       wl_mmio(BLT_SIZE_X_Y, ((width << 16) | height));
+       wl_mmio(BLT_SRC_X_Y, ((curx << 16)  | cury));
+       wl_mmio(BLT_DEST_X_Y, ((destx << 16) | desty));
+       wl_mmio(BLT_SRC_DEST_STRIDE, (((stride << 16) | stride) /* & 0x0ff80ff8 */)); /* why is this needed now ? */
+       wl_mmio(BLT_COMMAND_SET, blitcmd);
 }
 
 /*
  * Rectangle Fill Solid
  */
 
-static void Cyber3D_RectFill(u_short x, u_short y, u_short width,
-                            u_short height, u_short color, u_short depth)
+static void virgefb_RectFill(u_short x, u_short y, u_short width, u_short height,
+                       u_short color,  u_short stride, u_short depth)
 {
-       unsigned int tmp;
        unsigned int blitcmd = S3V_RECTFILL | S3V_DRAW |
                S3V_BLT_CLEAR | S3V_MONO_PAT | (1 << 26) | (1 << 25);
 
-       if (blit_maybe_busy)
-               Cyber3D_WaitBusy();
-       blit_maybe_busy = 1;
-
        switch (depth) {
 #ifdef FBCON_HAS_CFB8
                case 8 :
@@ -779,37 +1311,49 @@ static void Cyber3D_RectFill(u_short x, u_short y, u_short width,
                case 16 :
                        blitcmd |= S3V_DST_16BPP;
                        break;
+#endif
+#ifdef FBCON_HAS_CFB32
+               case 32 :
+                       /* 32 bit uses 2 times 16 bit values, see fbcon_virge32_clear */
+                       blitcmd |= S3V_DST_16BPP;
+                       break;
 #endif
        }
 
-       tmp = color & 0xff;
-       wl_3d(0xa4f4, tmp);
+       wait_3d_fifo_slots(5);          /* wait on fifo slots for 5 writes */
 
-       wl_3d(0xa504, ((width << 16) | height));        /* rwidth_height */
-       wl_3d(0xa50c, ((x << 16) | y));                 /* rdest_xy */
+       if (blit_maybe_busy)
+               virgefb_wait_for_idle();
+       blit_maybe_busy = 1;
 
-       wl_3d(0xa500, blitcmd);                         /* GO! */
+       wl_mmio(BLT_PATTERN_COLOR, (color & 0xff));
+       wl_mmio(BLT_SIZE_X_Y, ((width << 16) | height));
+       wl_mmio(BLT_DEST_X_Y, ((x << 16) | y));
+       wl_mmio(BLT_SRC_DEST_STRIDE, (((stride << 16) | stride) /* & 0x0ff80ff8 */));
+       wl_mmio(BLT_COMMAND_SET, blitcmd);
 }
 
-
-/**************************************************************
+/*
  * Move cursor to x, y
  */
 
 #if 0
-static void Cyber_MoveCursor (u_short x, u_short y)
+static void virgefb_move_cursor(u_short x, u_short y)
 {
-       printk(KERN_DEBUG "Yuck .... MoveCursor on a 3D\n");
-       return;
+       DPRINTK("Yuck .... MoveCursor on a 3D\n");
+       return 0;
 }
 #endif
 
 /* -------------------- Interfaces to hardware functions -------------------- */
 
-
-static struct fb_hwswitch Cyber_switch = {
-       Cyber_init, Cyber_encode_fix, Cyber_decode_var, Cyber_encode_var,
-       Cyber_getcolreg, Cyber_blank
+static struct fb_hwswitch virgefb_hw_switch = {
+       init:           virge_init,
+       encode_fix:     virgefb_encode_fix,
+       decode_var:     virgefb_decode_var,
+       encode_var:     virgefb_encode_var,
+       getcolreg:      virgefb_getcolreg,
+       blank:          virgefb_gfx_on_off
 };
 
 
@@ -822,54 +1366,75 @@ static struct fb_hwswitch Cyber_switch = {
 
 static void virgefb_get_par(struct virgefb_par *par)
 {
-       if (current_par_valid)
-       {
-               *par = current_par;
-       }
-       else
-       {
+       DPRINTK("ENTER\n");
+       if (current_par_valid) {
+               *par = current_par;
+       } else {
                fbhw->decode_var(&virgefb_default, par);
        }
+       DPRINTK("EXIT\n");
 }
 
 
 static void virgefb_set_par(struct virgefb_par *par)
 {
+       DPRINTK("ENTER\n");
        current_par = *par;
        current_par_valid = 1;
+       DPRINTK("EXIT\n");
 }
 
 
-static void virge_set_video(struct fb_var_screeninfo *var)
+static void virgefb_set_video(struct fb_var_screeninfo *var)
 {
-       /* Set clipping rectangle to current screen size */
+/* Set clipping rectangle to current screen size */
+
        unsigned int clip;
 
+       DPRINTK("ENTER\n");
+       wait_3d_fifo_slots(4);
        clip = ((0 << 16) | (var->xres - 1));
-       wl_3d(0xa4dc, clip);
+       wl_mmio(BLT_CLIP_LEFT_RIGHT, clip);
        clip = ((0 << 16) | (var->yres - 1));
-       wl_3d(0xa4e0, clip);
+       wl_mmio(BLT_CLIP_TOP_BOTTOM, clip);
+       wl_mmio(BLT_SRC_BASE, 0);               /* seems we need to clear these two */
+       wl_mmio(BLT_DEST_BASE, 0);
+
+/* Load the video mode defined by the 'var' data */
+
+       virgefb_load_video_mode(var);
+       DPRINTK("EXIT\n");
 }
 
+/*
+Merge these two functions, Geert's suggestion.
+static int virgefb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);
+static int virgefb_do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
+*/
 
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
+static int virgefb_do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
 {
        int err, activate;
        struct virgefb_par par;
 
-       if ((err = fbhw->decode_var(var, &par)))
-               return(err);
+       DPRINTK("ENTER\n");
+       if ((err = fbhw->decode_var(var, &par))) {
+               DPRINTK("EXIT\n");
+               return (err);
+       }
+
        activate = var->activate;
        if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
                virgefb_set_par(&par);
        fbhw->encode_var(var, &par);
        var->activate = activate;
-
-       virge_set_video(var);
+        if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
+               virgefb_set_video(var);
+       DPRINTK("EXIT\n");
        return 0;
 }
 
+
 /*
  *    Get the Fixed Part of the Display
  */
@@ -880,11 +1445,16 @@ static int virgefb_get_fix(struct fb_fix_screeninfo *fix, int con,
        struct virgefb_par par;
        int error = 0;
 
+       DPRINTK("ENTER\n");
        if (con == -1)
                virgefb_get_par(&par);
        else
                error = fbhw->decode_var(&fb_display[con].var, &par);
-       return(error ? error : fbhw->encode_fix(fix, &par));
+
+       if (!error)
+               error = fbhw->encode_fix(fix, &par);
+       DPRINTK("EXIT\n");
+       return(error);
 }
 
 
@@ -898,26 +1468,24 @@ static int virgefb_get_var(struct fb_var_screeninfo *var, int con,
        struct virgefb_par par;
        int error = 0;
 
-       if (con == -1)
-       {
+       DPRINTK("ENTER\n");
+       if (con == -1) {
                virgefb_get_par(&par);
                error = fbhw->encode_var(var, &par);
                disp.var = *var;   /* ++Andre: don't know if this is the right place */
-       }
-       else
-       {
+       } else {
                *var = fb_display[con].var;
        }
-
+       DPRINTK("EXIT\n");
        return(error);
 }
 
-
 static void virgefb_set_disp(int con, struct fb_info *info)
 {
        struct fb_fix_screeninfo fix;
        struct display *display;
 
+       DPRINTK("ENTER\n");
        if (con >= 0)
                display = &fb_display[con];
        else
@@ -926,16 +1494,25 @@ static void virgefb_set_disp(int con, struct fb_info *info)
        virgefb_get_fix(&fix, con, info);
        if (con == -1)
                con = 0;
-       if (cv3d_on_zorro2) {
-               info->screen_base = (char*) CyberMem;
+       if(on_zorro2) {
+               info->screen_base = (char*)v_ram;
        } else {
                switch (display->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
                        case 8:
-                               info->screen_base = (char*) (CyberMem + CYBMEM_OFFSET_8);
+                               info->screen_base = (char*)(v_ram + CYBMEM_OFFSET_8);
                                break;
+#endif
+#ifdef FBCON_HAS_CFB16
                        case 16:
-                               info->screen_base = (char*) (CyberMem + CYBMEM_OFFSET_16);
+                               info->screen_base = (char*)(v_ram + CYBMEM_OFFSET_16);
+                               break;
+#endif
+#ifdef FBCON_HAS_CFB32
+                       case 32:
+                               info->screen_base = (char*)(v_ram + CYBMEM_OFFSET_32);
                                break;
+#endif
                }
        }
        display->visual = fix.visual;
@@ -944,7 +1521,10 @@ static void virgefb_set_disp(int con, struct fb_info *info)
        display->ypanstep = fix.ypanstep;
        display->ywrapstep = fix.ywrapstep;
        display->can_soft_blank = 1;
-       display->inverse = Cyberfb_inverse;
+       display->inverse = virgefb_inverse;
+       display->line_length = display->var.xres_virtual*
+                              display->var.bits_per_pixel/8;
+
        switch (display->var.bits_per_pixel) {
 #ifdef FBCON_HAS_CFB8
                case 8:
@@ -963,11 +1543,21 @@ static void virgefb_set_disp(int con, struct fb_info *info)
                                display->dispsw = &fbcon_cfb16;
                        display->dispsw_data = &fbcon_cmap.cfb16;
                        break;
+#endif
+#ifdef FBCON_HAS_CFB32
+               case 32:
+                       if (display->var.accel_flags & FB_ACCELF_TEXT) {
+                               display->dispsw = &fbcon_virge32;
+                       } else
+                               display->dispsw = &fbcon_cfb32;
+                       display->dispsw_data = &fbcon_cmap.cfb32;
+                       break;
 #endif
                default:
                        display->dispsw = &fbcon_dummy;
                        break;
        }
+       DPRINTK("EXIT v_ram virt = 0x%8.8lx\n",(unsigned long)display->screen_base);
 }
 
 
@@ -980,8 +1570,12 @@ static int virgefb_set_var(struct fb_var_screeninfo *var, int con,
 {
        int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel;
 
-       if ((err = do_fb_set_var(var, con == info->currcon)))
+       DPRINTK("ENTER\n");
+
+       if ((err = virgefb_do_fb_set_var(var, con == info->currcon))) {
+               DPRINTK("EXIT\n");
                return(err);
+       }
        if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
                oldxres = fb_display[con].var.xres;
                oldyres = fb_display[con].var.yres;
@@ -996,13 +1590,15 @@ static int virgefb_set_var(struct fb_var_screeninfo *var, int con,
                    oldbpp != var->bits_per_pixel ||
                    oldaccel != var->accel_flags) {
                        virgefb_set_disp(con, info);
-                       (*fb_info.changevar)(con);
+                       if (fb_info.changevar)
+                               (*fb_info.changevar)(con);
                        fb_alloc_cmap(&fb_display[con].cmap, 0, 0);
                        do_install_cmap(con, info);
                }
        }
        var->activate = 0;
-       return(0);
+       DPRINTK("EXIT\n");
+       return 0;
 }
 
 
@@ -1013,23 +1609,19 @@ static int virgefb_set_var(struct fb_var_screeninfo *var, int con,
 static int virgefb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
                            struct fb_info *info)
 {
-       if (con == info->currcon) /* current console? */
+       DPRINTK("ENTER\n");
+       if (con == info->currcon) { /* current console? */
+               DPRINTK("EXIT - console is current console, fb_get_cmap\n");
                return(fb_get_cmap(cmap, kspc, fbhw->getcolreg, info));
-       else if (fb_display[con].cmap.len) /* non default colormap? */
+       } else if (fb_display[con].cmap.len) { /* non default colormap? */
+               DPRINTK("Use console cmap\n");
                fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
-       else
-               fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
+       } else {
+               DPRINTK("Use default cmap\n");
+               fb_copy_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel==8 ? 256 : 16),
                             cmap, kspc ? 0 : 2);
-       return(0);
-}
-
-/*
- *    Blank the display.
- */
-
-static int virgefb_blank(int blank, struct fb_info *info)
-{
-       fbhw->blank(blank);
+       }
+       DPRINTK("EXIT\n");
        return 0;
 }
 
@@ -1047,37 +1639,81 @@ static struct fb_ops virgefb_ops = {
 int __init virgefb_setup(char *options)
 {
        char *this_opt;
-
        fb_info.fontname[0] = '\0';
 
-       if (!options || !*options)
+       DPRINTK("ENTER\n");
+       if (!options || !*options) {
+               DPRINTK("EXIT\n");
                return 0;
+       }
 
        while ((this_opt = strsep(&options, ",")) != NULL) {
                if (!*this_opt)
                        continue;
                if (!strcmp(this_opt, "inverse")) {
-                       Cyberfb_inverse = 1;
+                       virgefb_inverse = 1;
                        fb_invert_cmaps();
                } else if (!strncmp(this_opt, "font:", 5))
                        strcpy(fb_info.fontname, this_opt+5);
+#ifdef FBCON_HAS_CFB8
                else if (!strcmp (this_opt, "virge8")){
                        virgefb_default = virgefb_predefined[VIRGE8_DEFMODE].var;
                }
+#endif
+#ifdef FBCON_HAS_CFB16
                else if (!strcmp (this_opt, "virge16")){
                        virgefb_default = virgefb_predefined[VIRGE16_DEFMODE].var;
                }
+#endif
+#ifdef FBCON_HAS_CFB32
+               else if (!strcmp (this_opt, "virge32")){
+                       virgefb_default = virgefb_predefined[VIRGE32_DEFMODE].var;
+               }
+#endif
                else
-                       get_video_mode(this_opt);
+                       virgefb_get_video_mode(this_opt);
        }
 
-       DPRINTK("default mode: xres=%d, yres=%d, bpp=%d\n",virgefb_default.xres,
-                                                           virgefb_default.yres,
-                                                          virgefb_default.bits_per_pixel);
+       printk(KERN_INFO "mode : xres=%d, yres=%d, bpp=%d\n", virgefb_default.xres,
+                       virgefb_default.yres, virgefb_default.bits_per_pixel);
+       DPRINTK("EXIT\n");
        return 0;
 }
 
 
+/*
+ *    Get a Video Mode
+ */
+
+static int __init virgefb_get_video_mode(const char *name)
+{
+       int i;
+
+       DPRINTK("ENTER\n");
+       for (i = 0; i < NUM_TOTAL_MODES; i++) {
+               if (!strcmp(name, virgefb_predefined[i].name)) {
+                       virgefb_default = virgefb_predefined[i].var;
+                       DPRINTK("EXIT\n");
+                       return(i);
+               }
+       }
+       /* ++Andre: set virgefb default mode */
+
+/* prefer 16 bit depth, 8 if no 16, if no 8 or 16 use 32 */
+
+#ifdef FBCON_HAS_CFB32
+       virgefb_default = virgefb_predefined[VIRGE32_DEFMODE].var;
+#endif
+#ifdef FBCON_HAS_CFB8
+       virgefb_default = virgefb_predefined[VIRGE8_DEFMODE].var;
+#endif
+#ifdef FBCON_HAS_CFB16
+       virgefb_default = virgefb_predefined[VIRGE16_DEFMODE].var;
+#endif
+       DPRINTK("EXIT\n");
+       return 0;
+}
+
 /*
  *    Initialization
  */
@@ -1085,103 +1721,114 @@ int __init virgefb_setup(char *options)
 int __init virgefb_init(void)
 {
        struct virgefb_par par;
-       unsigned long board_addr, ramsize;
+       unsigned long board_addr, board_size;
        struct zorro_dev *z = NULL;
 
-       while ((z = zorro_find_device(ZORRO_PROD_PHASE5_CYBERVISION64_3D, z))) {
-           board_addr = z->resource.start;
-           if (board_addr < 0x01000000) {
-               /*
-                * Ok we got the board running in Z2 space.
-                */
-                CyberRegs_phys = (unsigned long)(board_addr + 0x003e0000);
-                CyberMem_phys = board_addr;
-                ramsize = 0x00380000;
-           } else {
-               CyberRegs_phys = board_addr + 0x05000000;
-               CyberMem_phys  = board_addr + 0x04000000;       /* was 0x04800000 */
-               ramsize = 0x00400000;
-           }
-           if (!request_mem_region(CyberRegs_phys, 0x10000, "S3 ViRGE"))
-               continue;
-           if (!request_mem_region(CyberMem_phys, ramsize, "RAM")) {
-               release_mem_region(CyberRegs_phys, 0x10000);
-               continue;
-           }
+       DPRINTK("ENTER\n");
 
-           if (board_addr < 0x01000000) {
-               /*
-                * Ok we got the board running in Z2 space.
-                */
-
-               CyberMem = ZTWO_VADDR(CyberMem_phys);
-               CyberVGARegs = (unsigned long) \
-                       ZTWO_VADDR(board_addr + 0x003c0000);
-               CyberRegs = (unsigned char *)ZTWO_VADDR(CyberRegs_phys);
-               Cyber_register_base = (unsigned long) \
-                       ZTWO_VADDR(board_addr + 0x003c8000);
-               Cyber_vcode_switch_base = (unsigned long) \
-                       ZTWO_VADDR(board_addr + 0x003a0000);
-               cv3d_on_zorro2 = 1;
+       z = zorro_find_device(ZORRO_PROD_PHASE5_CYBERVISION64_3D, NULL);
+       if (!z)
+               return -ENODEV;
+
+       board_addr = z->resource.start;
+       if (board_addr < 0x01000000) {
+
+               /* board running in Z2 space. This includes the video memory
+                   as well as the S3 register set */
+
+               on_zorro2 = 1;
+               board_size = 0x00400000;
+
+               if (!request_mem_region(board_addr, board_size, "S3 ViRGE"))
+                       return -ENOMEM;
+
+               v_ram_phys = board_addr;
+               v_ram = ZTWO_VADDR(v_ram_phys);
+               mmio_regs_phys = (unsigned long)(board_addr + 0x003c0000);
+               vgaio_regs = (unsigned char *) ZTWO_VADDR(board_addr + 0x003c0000);
+               mmio_regs = (unsigned char *)ZTWO_VADDR(mmio_regs_phys);
+               vcode_switch_base = (unsigned long) ZTWO_VADDR(board_addr + 0x003a0000);
                printk(KERN_INFO "CV3D detected running in Z2 mode.\n");
-           } else {
-               CyberVGARegs = (unsigned long)ioremap(board_addr+0x0c000000, 0x00010000);
-               CyberRegs = ioremap(CyberRegs_phys, 0x00010000);
-               CyberMem = (unsigned long)ioremap(CyberMem_phys, 0x01000000);   /* was 0x00400000 */
-               cv3d_on_zorro2 = 0;
-               printk(KERN_INFO "CV3D detected running in Z3 mode.\n");
-           }
 
-           fbhw = &Cyber_switch;
+       } else {
+
+               /* board running in Z3 space. Seperate video memory (3 apertures)
+                  and S3 register set */
 
-           strcpy(fb_info.modename, virgefb_name);
-           fb_info.changevar = NULL;
-           fb_info.node = NODEV;
-           fb_info.fbops = &virgefb_ops;
-           fb_info.disp = &disp;
-           fb_info.currcon = -1;       
-           fb_info.switch_con = &Cyberfb_switch;
-           fb_info.updatevar = &Cyberfb_updatevar;
-           fb_info.flags = FBINFO_FLAG_DEFAULT;
+               on_zorro2 = 0;
+               board_size = 0x01000000;
 
-           fbhw->init();
-           fbhw->decode_var(&virgefb_default, &par);
-           fbhw->encode_var(&virgefb_default, &par);
+               if (!request_mem_region(board_addr, board_size, "S3 ViRGE"))
+                       return -ENOMEM;
 
-           do_fb_set_var(&virgefb_default, 1);
-           virgefb_get_var(&fb_display[0].var, -1, &fb_info);
-           virgefb_set_disp(-1, &fb_info);
-           do_install_cmap(0, &fb_info);
+               v_ram_phys  = board_addr + 0x04000000;
+               v_ram = (unsigned long)ioremap(v_ram_phys, 0x01000000);
+               mmio_regs_phys = board_addr + 0x05000000;
+               vgaio_regs = (unsigned char *)ioremap(board_addr +0x0c000000, 0x00100000); /* includes PCI regs */
+               mmio_regs = ioremap(mmio_regs_phys, 0x00010000);
+               vcode_switch_base = (unsigned long)ioremap(board_addr + 0x08000000, 0x1000);
+               printk(KERN_INFO "CV3D detected running in Z3 mode\n");
+       }
 
-           if (register_framebuffer(&fb_info) < 0) {
+#if defined (VIRGEFBDEBUG)
+       DPRINTK("board_addr     : 0x%8.8lx\n",board_addr);
+       DPRINTK("board_size     : 0x%8.8lx\n",board_size);
+       DPRINTK("mmio_regs_phy  : 0x%8.8lx\n",mmio_regs_phys);
+       DPRINTK("v_ram_phys     : 0x%8.8lx\n",v_ram_phys);
+       DPRINTK("vgaio_regs     : 0x%8.8lx\n",(unsigned long)vgaio_regs);
+       DPRINTK("mmio_regs      : 0x%8.8lx\n",(unsigned long)mmio_regs);
+       DPRINTK("v_ram          : 0x%8.8lx\n",v_ram);
+       DPRINTK("vcode sw base  : 0x%8.8lx\n",vcode_switch_base);
+#endif
+       fbhw = &virgefb_hw_switch;
+       strcpy(fb_info.modename, virgefb_name);
+       fb_info.changevar = NULL;
+       fb_info.node = NODEV;
+       fb_info.fbops = &virgefb_ops;
+       fb_info.disp = &disp;
+       fb_info.currcon = -1;
+       fb_info.switch_con = &virgefb_switch;
+       fb_info.updatevar = &virgefb_updatevar;
+       fb_info.flags = FBINFO_FLAG_DEFAULT;
+       fbhw->init();
+       fbhw->decode_var(&virgefb_default, &par);
+       fbhw->encode_var(&virgefb_default, &par);
+       virgefb_do_fb_set_var(&virgefb_default, 1);
+       virgefb_get_var(&fb_display[0].var, -1, &fb_info);
+       virgefb_set_disp(-1, &fb_info);
+       do_install_cmap(0, &fb_info);
+
+       if (register_framebuffer(&fb_info) < 0) {
+               #warning release resources
                printk(KERN_ERR "virgefb.c: register_framebuffer failed\n");
+               DPRINTK("EXIT\n");
                return -EINVAL;
-           }
+       }
 
-           printk(KERN_INFO "fb%d: %s frame buffer device, using %ldK of "
-                  "video memory\n", GET_FB_IDX(fb_info.node),
-                  fb_info.modename, CyberSize>>10);
+       printk(KERN_INFO "fb%d: %s frame buffer device, using %ldK of video memory\n",
+              GET_FB_IDX(fb_info.node), fb_info.modename, v_ram_size>>10);
 
-           /* TODO: This driver cannot be unloaded yet */
-           MOD_INC_USE_COUNT;
-           return 0;
-       }
-       return -ENODEV;
+       /* TODO: This driver cannot be unloaded yet */
+
+       MOD_INC_USE_COUNT;
+       DPRINTK("EXIT\n");
+       return 0;
 }
 
 
-static int Cyberfb_switch(int con, struct fb_info *info)
+static int virgefb_switch(int con, struct fb_info *info)
 {
+       DPRINTK("ENTER\n");
        /* Do we have to save the colormap? */
        if (fb_display[info->currcon].cmap.len)
-               fb_get_cmap(&fb_display[info->currcon].cmap, 1, fbhw->getcolreg,
-                           info);
-
-       do_fb_set_var(&fb_display[con].var, 1);
+               fb_get_cmap(&fb_display[info->currcon].cmap, 1,
+                           fbhw->getcolreg, info);
+       virgefb_do_fb_set_var(&fb_display[con].var, 1);
        info->currcon = con;
        /* Install new colormap */
        do_install_cmap(con, info);
-       return(0);
+       DPRINTK("EXIT\n");
+       return 0;
 }
 
 
@@ -1192,38 +1839,23 @@ static int Cyberfb_switch(int con, struct fb_info *info)
  *    Since it's called by a kernel driver, no range checking is done.
  */
 
-static int Cyberfb_updatevar(int con, struct fb_info *info)
+static int virgefb_updatevar(int con, struct fb_info *info)
 {
-       return(0);
+       DPRINTK("ENTER\n");
+       return 0;
+       DPRINTK("EXIT\n");
 }
 
-
 /*
  *    Blank the display.
  */
 
-static void virgefb_blank(int blank, struct fb_info *info)
+static int virgefb_blank(int blank, struct fb_info *info)
 {
+       DPRINTK("ENTER\n");
        fbhw->blank(blank);
-}
-
-/*
- *    Get a Video Mode
- */
-
-static int __init get_video_mode(const char *name)
-{
-       int i;
-
-       for (i = 0; i < NUM_TOTAL_MODES; i++) {
-               if (!strcmp(name, virgefb_predefined[i].name)) {
-                       virgefb_default = virgefb_predefined[i].var;
-                       return(i);
-               }
-       }
-       /* ++Andre: set virgefb default mode */
-       virgefb_default = virgefb_predefined[VIRGE8_DEFMODE].var;
-       return(0);
+       DPRINTK("EXIT\n");
+       return 0;
 }
 
 
@@ -1236,9 +1868,9 @@ static void fbcon_virge8_bmove(struct display *p, int sy, int sx, int dy,
                               int dx, int height, int width)
 {
         sx *= 8; dx *= 8; width *= 8;
-        Cyber3D_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx,
+        virgefb_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx,
                        (u_short)(dy*fontheight(p)), (u_short)width,
-                       (u_short)(height*fontheight(p)), 8);
+                       (u_short)(height*fontheight(p)), (u_short)p->next_line, 8);
 }
 
 static void fbcon_virge8_clear(struct vc_data *conp, struct display *p, int sy,
@@ -1248,16 +1880,16 @@ static void fbcon_virge8_clear(struct vc_data *conp, struct display *p, int sy,
 
         sx *= 8; width *= 8;
         bg = attr_bgcol_ec(p,conp);
-        Cyber3D_RectFill((u_short)sx, (u_short)(sy*fontheight(p)),
+        virgefb_RectFill((u_short)sx, (u_short)(sy*fontheight(p)),
                          (u_short)width, (u_short)(height*fontheight(p)),
-                         (u_short)bg, 8);
+                         (u_short)bg, (u_short)p->next_line, 8);
 }
 
 static void fbcon_virge8_putc(struct vc_data *conp, struct display *p, int c, int yy,
                               int xx)
 {
        if (blit_maybe_busy)
-               Cyber3D_WaitBusy();
+               virgefb_wait_for_idle();
        fbcon_cfb8_putc(conp, p, c, yy, xx);
 }
 
@@ -1265,14 +1897,14 @@ static void fbcon_virge8_putcs(struct vc_data *conp, struct display *p,
                       const unsigned short *s, int count, int yy, int xx)
 {
        if (blit_maybe_busy)
-               Cyber3D_WaitBusy();
+               virgefb_wait_for_idle();
        fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
 }
 
 static void fbcon_virge8_revc(struct display *p, int xx, int yy)
 {
        if (blit_maybe_busy)
-               Cyber3D_WaitBusy();
+               virgefb_wait_for_idle();
        fbcon_cfb8_revc(p, xx, yy);
 }
 
@@ -1280,19 +1912,19 @@ static void fbcon_virge8_clear_margins(struct vc_data *conp, struct display *p,
                               int bottom_only)
 {
        if (blit_maybe_busy)
-               Cyber3D_WaitBusy();
+               virgefb_wait_for_idle();
        fbcon_cfb8_clear_margins(conp, p, bottom_only);
 }
 
 static struct display_switch fbcon_virge8 = {
-   setup:              fbcon_cfb8_setup,
-   bmove:              fbcon_virge8_bmove,
-   clear:              fbcon_virge8_clear,
-   putc:               fbcon_virge8_putc,
-   putcs:              fbcon_virge8_putcs,
-   revc:               fbcon_virge8_revc,
-   clear_margins:      fbcon_virge8_clear_margins,
-   fontwidthmask:      FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+       setup:          fbcon_cfb8_setup,
+       bmove:          fbcon_virge8_bmove,
+       clear:          fbcon_virge8_clear,
+       putc:           fbcon_virge8_putc,
+       putcs:          fbcon_virge8_putcs,
+       revc:           fbcon_virge8_revc,
+       clear_margins:  fbcon_virge8_clear_margins,
+       fontwidthmask:  FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 #endif
 
@@ -1301,28 +1933,28 @@ static void fbcon_virge16_bmove(struct display *p, int sy, int sx, int dy,
                                int dx, int height, int width)
 {
         sx *= 8; dx *= 8; width *= 8;
-        Cyber3D_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx,
+        virgefb_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx,
                        (u_short)(dy*fontheight(p)), (u_short)width,
-                       (u_short)(height*fontheight(p)), 16);
+                       (u_short)(height*fontheight(p)), (u_short)p->next_line, 16);
 }
-                
+
 static void fbcon_virge16_clear(struct vc_data *conp, struct display *p, int sy,
                                int sx, int height, int width)
 {
-        unsigned char bg;   
-                
+        unsigned char bg;
+
         sx *= 8; width *= 8;
         bg = attr_bgcol_ec(p,conp);
-        Cyber3D_RectFill((u_short)sx, (u_short)(sy*fontheight(p)),
+        virgefb_RectFill((u_short)sx, (u_short)(sy*fontheight(p)),
                          (u_short)width, (u_short)(height*fontheight(p)),
-                         (u_short)bg, 16);
+                         (u_short)bg, (u_short)p->next_line, 16);
 }
-   
+
 static void fbcon_virge16_putc(struct vc_data *conp, struct display *p, int c, int yy,
                               int xx)
 {
        if (blit_maybe_busy)
-               Cyber3D_WaitBusy();
+               virgefb_wait_for_idle();
        fbcon_cfb16_putc(conp, p, c, yy, xx);
 }
 
@@ -1330,14 +1962,14 @@ static void fbcon_virge16_putcs(struct vc_data *conp, struct display *p,
                       const unsigned short *s, int count, int yy, int xx)
 {
        if (blit_maybe_busy)
-               Cyber3D_WaitBusy();
+               virgefb_wait_for_idle();
        fbcon_cfb16_putcs(conp, p, s, count, yy, xx);
 }
 
 static void fbcon_virge16_revc(struct display *p, int xx, int yy)
 {
        if (blit_maybe_busy)
-               Cyber3D_WaitBusy();
+               virgefb_wait_for_idle();
        fbcon_cfb16_revc(p, xx, yy);
 }
 
@@ -1345,19 +1977,84 @@ static void fbcon_virge16_clear_margins(struct vc_data *conp, struct display *p,
                               int bottom_only)
 {
        if (blit_maybe_busy)
-               Cyber3D_WaitBusy();
+               virgefb_wait_for_idle();
        fbcon_cfb16_clear_margins(conp, p, bottom_only);
 }
 
 static struct display_switch fbcon_virge16 = {
-   setup:              fbcon_cfb16_setup,
-   bmove:              fbcon_virge16_bmove,
-   clear:              fbcon_virge16_clear,
-   putc:               fbcon_virge16_putc,
-   putcs:              fbcon_virge16_putcs,
-   revc:               fbcon_virge16_revc,
-   clear_margins:      fbcon_virge16_clear_margins,
-   fontwidthmask:      FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+       setup:          fbcon_cfb16_setup,
+       bmove:          fbcon_virge16_bmove,
+       clear:          fbcon_virge16_clear,
+       putc:           fbcon_virge16_putc,
+       putcs:          fbcon_virge16_putcs,
+       revc:           fbcon_virge16_revc,
+       clear_margins:  fbcon_virge16_clear_margins,
+       fontwidthmask:  FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+
+#ifdef FBCON_HAS_CFB32
+static void fbcon_virge32_bmove(struct display *p, int sy, int sx, int dy,
+                              int dx, int height, int width)
+{
+        sx *= 16; dx *= 16; width *= 16;       /* doubled these values to do 32 bit blit */
+        virgefb_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx,
+                       (u_short)(dy*fontheight(p)), (u_short)width,
+                       (u_short)(height*fontheight(p)), (u_short)p->next_line, 16);
+}
+
+static void fbcon_virge32_clear(struct vc_data *conp, struct display *p, int sy,
+                              int sx, int height, int width)
+{
+        unsigned char bg;
+
+        sx *= 16; width *= 16;                 /* doubled these values to do 32 bit blit */
+        bg = attr_bgcol_ec(p,conp);
+        virgefb_RectFill((u_short)sx, (u_short)(sy*fontheight(p)),
+                         (u_short)width, (u_short)(height*fontheight(p)),
+                         (u_short)bg, (u_short)p->next_line, 16);
+}
+
+static void fbcon_virge32_putc(struct vc_data *conp, struct display *p, int c, int yy,
+                              int xx)
+{
+       if (blit_maybe_busy)
+               virgefb_wait_for_idle();
+       fbcon_cfb32_putc(conp, p, c, yy, xx);
+}
+
+static void fbcon_virge32_putcs(struct vc_data *conp, struct display *p,
+                      const unsigned short *s, int count, int yy, int xx)
+{
+       if (blit_maybe_busy)
+               virgefb_wait_for_idle();
+       fbcon_cfb32_putcs(conp, p, s, count, yy, xx);
+}
+
+static void fbcon_virge32_revc(struct display *p, int xx, int yy)
+{
+       if (blit_maybe_busy)
+               virgefb_wait_for_idle();
+       fbcon_cfb32_revc(p, xx, yy);
+}
+
+static void fbcon_virge32_clear_margins(struct vc_data *conp, struct display *p,
+                              int bottom_only)
+{
+       if (blit_maybe_busy)
+               virgefb_wait_for_idle();
+       fbcon_cfb32_clear_margins(conp, p, bottom_only);
+}
+
+static struct display_switch fbcon_virge32 = {
+       setup:          fbcon_cfb32_setup,
+       bmove:          fbcon_virge32_bmove,
+       clear:          fbcon_virge32_clear,
+       putc:           fbcon_virge32_putc,
+       putcs:          fbcon_virge32_putcs,
+       revc:           fbcon_virge32_revc,
+       clear_margins:  fbcon_virge32_clear_margins,
+       fontwidthmask:  FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 #endif
 
@@ -1377,3 +2074,450 @@ void cleanup_module(void)
        /* TODO: clean up ... */
 }
 #endif /* MODULE */
+
+static int cv3d_has_4mb(void)
+{
+       /* cyberfb version didn't work, neither does this (not reliably)
+       forced to return 4MB */
+#if 0
+       volatile unsigned long *t0, *t2;
+#endif
+       DPRINTK("ENTER\n");
+#if 0
+       /* write patterns in memory and test if they can be read */
+       t0 = (volatile unsigned long *)v_ram;
+       t2 = (volatile unsigned long *)(v_ram + 0x00200000);
+       *t0 = 0x87654321;
+       *t2 = 0x12345678;
+
+       if (*t0 != 0x87654321) {
+               /* read of first location failed */
+               DPRINTK("EXIT - 0MB !\n");
+               return 0;
+       }
+
+       if (*t2 == 0x87654321) {
+               /* should read 0x12345678 if 4MB */
+               DPRINTK("EXIT - 2MB(a) \n");
+               return 0;
+       }
+
+       if (*t2 != 0x12345678) {
+               /* upper 2MB read back match failed */
+               DPRINTK("EXIT - 2MB(b)\n");
+               return 0;
+       }
+
+       /* may have 4MB */
+
+       *t2 = 0xAAAAAAAA;
+
+       if(*t2 != 0xAAAAAAAA) {
+               /* upper 2MB read back match failed */
+               DPRINTK("EXIT - 2MB(c)\n");
+               return 0;
+       }
+
+       *t2 = 0x55555555;
+
+       if(*t2 != 0x55555555) {
+               /* upper 2MB read back match failed */
+               DPRINTK("EXIT - 2MB(d)\n");
+               return 0;
+       }
+
+#endif
+       DPRINTK("EXIT - 4MB\n");
+       return 1;
+}
+
+
+/*
+ * Computes M, N, and R pll params for freq arg.
+ * Returns 16 bits - hi 0MMMMMM lo 0RRNNNNN
+ */
+
+#define REFCLOCK 14318000
+
+static unsigned short virgefb_compute_clock(unsigned long freq)
+{
+
+       unsigned char m, n, r, rpwr;
+       unsigned long diff, ftry, save = ~0UL;
+       unsigned short mnr;
+
+       DPRINTK("ENTER\n");
+
+       for (r = 0, rpwr = 1 ; r < 4 ; r++, rpwr *= 2) {
+               if ((135000000 <= (rpwr * freq)) && ((rpwr * freq) <= 270000000)) {
+                       for (n = 1 ; n < 32 ; n++) {
+                               m = ((freq * (n + 2) * rpwr)/REFCLOCK) - 2;
+                               if (m == 0 || m >127)
+                                       break;
+                               ftry = ((REFCLOCK / (n + 2)) * (m + 2)) / rpwr;
+                               if (ftry > freq)
+                                       diff = ftry - freq;
+                               else
+                                       diff = freq - ftry;
+                               if (diff < save) {
+                                       save = diff;
+                                       mnr =  (m << 8) | (r<<5) | (n & 0x7f);
+                               }
+                       }
+               }
+       }
+       if (save == ~0UL)
+               printk("Can't compute clock PLL values for %ld Hz clock\n", freq);
+       DPRINTK("EXIT\n");
+       return(mnr);
+}
+
+static void virgefb_load_video_mode(struct fb_var_screeninfo *video_mode)
+{
+       unsigned char lace, dblscan, tmp;
+       unsigned short mnr;
+       unsigned short HT, HDE, HBS, HBW, HSS, HSW;
+       unsigned short VT, VDE, VBS, VBW, VSS, VSW;
+       unsigned short SCO;
+       int cr11;
+       int cr67;
+       int hmul;
+       int xres, xres_virtual, hfront, hsync, hback;
+       int yres, vfront, vsync, vback;
+       int bpp;
+       int i;
+       long freq;
+
+       DPRINTK("ENTER : %dx%d-%d\n",video_mode->xres, video_mode->yres,
+                               video_mode->bits_per_pixel);
+
+       bpp = video_mode->bits_per_pixel;
+       xres = video_mode->xres;
+       xres_virtual = video_mode->xres_virtual;
+       hfront = video_mode->right_margin;
+       hsync = video_mode->hsync_len;
+       hback = video_mode->left_margin;
+
+       lace = 0;
+       dblscan = 0;
+
+       if (video_mode->vmode & FB_VMODE_DOUBLE) {
+               yres = video_mode->yres * 2;
+               vfront = video_mode->lower_margin * 2;
+               vsync = video_mode->vsync_len * 2;
+               vback = video_mode->upper_margin * 2;
+               dblscan = 1;
+       } else if (video_mode->vmode & FB_VMODE_INTERLACED) {
+               yres = (video_mode->yres + 1) / 2;
+               vfront = (video_mode->lower_margin + 1) / 2;
+               vsync = (video_mode->vsync_len + 1) / 2;
+               vback = (video_mode->upper_margin + 1) / 2;
+               lace = 1;
+       } else {
+               yres = video_mode->yres;
+               vfront = video_mode->lower_margin;
+               vsync = video_mode->vsync_len;
+               vback = video_mode->upper_margin;
+       }
+
+       switch (bpp) {
+               case 8:
+                       video_mode->red.offset = 0;
+                       video_mode->green.offset = 0;
+                       video_mode->blue.offset = 0;
+                       video_mode->transp.offset = 0;
+                       video_mode->red.length = 8;
+                       video_mode->green.length = 8;
+                       video_mode->blue.length = 8;
+                       video_mode->transp.length = 0;
+                       hmul = 1;
+                       cr67 = 0x00;
+                       SCO = xres_virtual / 8;
+                       break;
+               case 16:
+                       video_mode->red.offset = 11;
+                       video_mode->green.offset = 5;
+                       video_mode->blue.offset = 0;
+                       video_mode->transp.offset = 0;
+                       video_mode->red.length = 5;
+                       video_mode->green.length = 6;
+                       video_mode->blue.length = 5;
+                       video_mode->transp.length = 0;
+                       hmul = 2;
+                       cr67 = 0x50;
+                       SCO = xres_virtual / 4;
+                       break;
+               case 32:
+                       video_mode->red.offset = 16;
+                       video_mode->green.offset = 8;
+                       video_mode->blue.offset = 0;
+                       video_mode->transp.offset = 24;
+                       video_mode->red.length = 8;
+                       video_mode->green.length = 8;
+                       video_mode->blue.length = 8;
+                       video_mode->transp.length = 8;
+                       hmul = 1;
+                       cr67 = 0xd0;
+                       SCO = xres_virtual / 2;
+                       break;
+       }
+
+       HT  = (((xres + hfront + hsync + hback) / 8) * hmul) - 5;
+       HDE = ((xres / 8) * hmul) - 1;
+       HBS = (xres / 8) * hmul;
+       HSS = ((xres + hfront) / 8) * hmul;
+       HSW = (hsync / 8) * hmul;
+       HBW = (((hfront + hsync + hback) / 8) * hmul) - 2;
+
+       VT  = yres + vfront + vsync + vback - 2;
+       VDE = yres - 1;
+       VBS = yres - 1;
+       VSS = yres + vfront;
+       VSW = vsync;
+       VBW = vfront + vsync + vback - 2;
+
+#ifdef VIRGEFBDEBUG
+       DPRINTK("HDE       : 0x%4.4x, %4.4d\n", HDE, HDE);
+       DPRINTK("HBS       : 0x%4.4x, %4.4d\n", HBS, HBS);
+       DPRINTK("HSS       : 0x%4.4x, %4.4d\n", HSS, HSS);
+       DPRINTK("HSW       : 0x%4.4x, %4.4d\n", HSW, HSW);
+       DPRINTK("HBW       : 0x%4.4x, %4.4d\n", HBW, HBW);
+       DPRINTK("HSS + HSW : 0x%4.4x, %4.4d\n", HSS+HSW, HSS+HSW);
+       DPRINTK("HBS + HBW : 0x%4.4x, %4.4d\n", HBS+HBW, HBS+HBW);
+       DPRINTK("HT        : 0x%4.4x, %4.4d\n", HT, HT);
+       DPRINTK("VDE       : 0x%4.4x, %4.4d\n", VDE, VDE);
+       DPRINTK("VBS       : 0x%4.4x, %4.4d\n", VBS, VBS);
+       DPRINTK("VSS       : 0x%4.4x, %4.4d\n", VSS, VSS);
+       DPRINTK("VSW       : 0x%4.4x, %4.4d\n", VSW, VSW);
+       DPRINTK("VBW       : 0x%4.4x, %4.4d\n", VBW, VBW);
+       DPRINTK("VT        : 0x%4.4x, %4.4d\n", VT, VT);
+#endif
+
+/* turn gfx off, don't mess up the display */
+
+       gfx_on_off(1);
+
+/* H and V sync polarity */
+
+       tmp = rb_mmio(GREG_MISC_OUTPUT_R) & 0x2f;               /* colour, ram enable, clk sr12/s13 sel */
+       if (!(video_mode->sync & FB_SYNC_HOR_HIGH_ACT))
+               tmp |= 0x40;                                    /* neg H sync polarity */
+       if (!(video_mode->sync & FB_SYNC_VERT_HIGH_ACT))
+               tmp |= 0x80;                                    /* neg V sync polarity */
+       tmp |= 0x0c;                                            /* clk from sr12/sr13 */
+       wb_mmio(GREG_MISC_OUTPUT_W, tmp);
+
+/* clocks */
+
+       wseq(SEQ_ID_BUS_REQ_CNTL, 0xc0);                        /* 2 clk mem wr and /RAS1 */
+       wseq(SEQ_ID_CLKSYN_CNTL_2, 0x80);                       /* b7 is 2 mem clk wr */
+       mnr = virgefb_compute_clock(MEMCLOCK);
+       DPRINTK("mem clock %d, m %d, n %d, r %d.\n", MEMCLOCK, ((mnr>>8)&0x7f), (mnr&0x1f), ((mnr >> 5)&0x03));
+       wseq(SEQ_ID_MCLK_LO, (mnr & 0x7f));
+       wseq(SEQ_ID_MCLK_HI, ((mnr & 0x7f00) >> 8));
+       freq = (1000000000 / video_mode->pixclock) * 1000;      /* pixclock is in ps ... convert to Hz */
+       mnr = virgefb_compute_clock(freq);
+       DPRINTK("dot clock %ld, m %d, n %d, r %d.\n", freq, ((mnr>>8)&0x7f), (mnr&0x1f), ((mnr>>5)&0x03));
+       wseq(SEQ_ID_DCLK_LO, (mnr & 0x7f));
+       wseq(SEQ_ID_DCLK_HI, ((mnr & 0x7f00) >> 8));
+       wseq(SEQ_ID_CLKSYN_CNTL_2, 0xa0);
+       wseq(SEQ_ID_CLKSYN_CNTL_2, 0x80);
+       udelay(100);
+
+/* load display parameters into board */
+
+       /* not sure about sync and blanking extensions bits in cr5d and cr5 */
+
+       wcrt(CRT_ID_EXT_HOR_OVF,                        /* 0x5d */
+               ((HT & 0x100) ?         0x01 : 0x00) |
+               ((HDE & 0x100) ?        0x02 : 0x00) |
+               ((HBS & 0x100) ?        0x04 : 0x00) |
+       /*      (((HBS + HBW) & 0x40) ? 0x08 : 0x00) |  */
+               ((HSS & 0x100) ?        0x10 : 0x00) |
+       /*      (((HSS + HSW) & 0x20) ? 0x20 : 0x00) |  */
+               ((HSW >= 0x20) ?        0x20 : 0x00) |
+               (((HT-5) & 0x100) ?     0x40 : 0x00));
+
+       wcrt(CRT_ID_EXT_VER_OVF,                        /* 0x5e */
+               ((VT & 0x400) ? 0x01 : 0x00) |
+               ((VDE & 0x400) ? 0x02 : 0x00) |
+               ((VBS & 0x400) ? 0x04 : 0x00) |
+               ((VSS & 0x400) ? 0x10 : 0x00) |
+               0x40);                                  /* line compare */
+
+       wcrt(CRT_ID_START_VER_RETR, VSS);
+       cr11 = rcrt(CRT_ID_END_VER_RETR) | 0x20;        /* vert interrupt flag */
+       wcrt(CRT_ID_END_VER_RETR, ((cr11 & 0x20) | ((VSS + VSW) & 0x0f)));      /* keeps vert irq enable state, also has unlock bit cr0 to 7 */
+       wcrt(CRT_ID_VER_DISP_ENA_END, VDE);
+       wcrt(CRT_ID_START_VER_BLANK, VBS);
+       wcrt(CRT_ID_END_VER_BLANK, VBS + VBW);          /* might be +/- 1 out */
+       wcrt(CRT_ID_HOR_TOTAL, HT);
+       wcrt(CRT_ID_DISPLAY_FIFO, HT - 5);
+       wcrt(CRT_ID_BACKWAD_COMP_3, 0x10);              /* enable display fifo */
+       wcrt(CRT_ID_HOR_DISP_ENA_END, HDE);
+       wcrt(CRT_ID_START_HOR_BLANK , HBS);
+       wcrt(CRT_ID_END_HOR_BLANK, (HBS + HBW) & 0x1f);
+       wcrt(CRT_ID_START_HOR_RETR, HSS);
+       wcrt(CRT_ID_END_HOR_RETR,                       /* cr5 */
+               ((HSS + HSW) & 0x1f) |
+               (((HBS + HBW) & 0x20) ? 0x80 : 0x00));
+       wcrt(CRT_ID_VER_TOTAL, VT);
+       wcrt(CRT_ID_OVERFLOW,
+               ((VT & 0x100) ? 0x01 : 0x00) |
+               ((VDE & 0x100) ? 0x02 : 0x00) |
+               ((VSS & 0x100) ? 0x04 : 0x00) |
+               ((VBS & 0x100) ? 0x08 : 0x00) |
+               0x10 |
+               ((VT & 0x200) ? 0x20 : 0x00) |
+               ((VDE & 0x200) ? 0x40 : 0x00) |
+               ((VSS & 0x200) ? 0x80 : 0x00));
+       wcrt(CRT_ID_MAX_SCAN_LINE,
+               (dblscan ? 0x80 : 0x00) |
+               0x40 |
+               ((VBS & 0x200) ? 0x20 : 0x00));
+       wcrt(CRT_ID_LINE_COMPARE, 0xff);
+       wcrt(CRT_ID_LACE_RETR_START, HT / 2);           /* (HT-5)/2 ? */
+       wcrt(CRT_ID_LACE_CONTROL, (lace ? 0x20 : 0x00));
+
+       wcrt(CRT_ID_SCREEN_OFFSET, SCO);
+       wcrt(CRT_ID_EXT_SYS_CNTL_2, (SCO >> 4) & 0x30 );
+
+       /* wait for vert sync before cr67 update */
+
+       for (i=0; i < 10000; i++) {
+               udelay(10);
+               mb();
+               if (rb_mmio(GREG_INPUT_STATUS1_R) & 0x08)
+                       break;
+       }
+
+       wl_mmio(0x8200, 0x0000c000);    /* fifo control  (0x00110400 ?) */
+       wcrt(CRT_ID_EXT_MISC_CNTL_2, cr67);
+
+/* enable video */
+
+       tmp = rb_mmio(ACT_ADDRESS_RESET);
+       wb_mmio(ACT_ADDRESS_W, ((bpp == 8) ? 0x20 : 0x00));     /* set b5, ENB PLT in attr idx reg) */
+       tmp = rb_mmio(ACT_ADDRESS_RESET);
+
+/* turn gfx on again */
+
+       gfx_on_off(0);
+
+/* pass-through */
+
+       SetVSwitch(1);          /* cv3d */
+
+       DUMP;
+       DPRINTK("EXIT\n");
+}
+
+static inline void gfx_on_off(int toggle)
+{
+       unsigned char tmp;
+
+       DPRINTK("ENTER gfx %s\n", (toggle ? "off" : "on"));
+
+       toggle = (toggle & 0x01) << 5;
+       tmp = rseq(SEQ_ID_CLOCKING_MODE) & (~(0x01 << 5));
+       wseq(SEQ_ID_CLOCKING_MODE, tmp | toggle);
+
+       DPRINTK("EXIT\n");
+}
+
+#if defined (VIRGEFBDUMP)
+
+/*
+ * Dump board registers
+ */
+
+static void cv64_dump(void)
+{
+       int i;
+       u8 c, b;
+        u16 w;
+       u32 l;
+
+       /* crt, seq, gfx and atr regs */
+
+       SelectMMIO;
+
+       printk("\n");
+       for (i = 0; i <= 0x6f; i++) {
+               wb_mmio(CRT_ADDRESS, i);
+               printk("crt idx : 0x%2.2x : 0x%2.2x\n", i, rb_mmio(CRT_ADDRESS_R));
+       }
+       for (i = 0; i <= 0x1c; i++) {
+               wb_mmio(SEQ_ADDRESS, i);
+               printk("seq idx : 0x%2.2x : 0x%2.2x\n", i, rb_mmio(SEQ_ADDRESS_R));
+       }
+       for (i = 0; i <= 8; i++) {
+               wb_mmio(GCT_ADDRESS, i);
+               printk("gfx idx : 0x%2.2x : 0x%2.2x\n", i, rb_mmio(GCT_ADDRESS_R));
+       }
+       for (i = 0; i <= 0x14; i++) {
+               c = rb_mmio(ACT_ADDRESS_RESET);
+               wb_mmio(ACT_ADDRESS_W, i);
+               printk("atr idx : 0x%2.2x : 0x%2.2x\n", i, rb_mmio(ACT_ADDRESS_R));
+       }
+
+       /* re-enable video access to palette */
+
+       c = rb_mmio(ACT_ADDRESS_RESET);
+       udelay(10);
+       wb_mmio(ACT_ADDRESS_W, 0x20);
+       c = rb_mmio(ACT_ADDRESS_RESET);
+       udelay(10);
+
+       /* general regs */
+
+       printk("0x3cc(w 0x3c2) : 0x%2.2x\n", rb_mmio(0x3cc));   /* GREG_MISC_OUTPUT READ */
+       printk("0x3c2(-------) : 0x%2.2x\n", rb_mmio(0x3c2));   /* GREG_INPUT_STATUS 0 READ */
+       printk("0x3c3(w 0x3c3) : 0x%2.2x\n", rb_vgaio(0x3c3));  /* GREG_VIDEO_SUBS_ENABLE */
+       printk("0x3ca(w 0x3da) : 0x%2.2x\n", rb_vgaio(0x3ca));  /* GREG_FEATURE_CONTROL read */
+       printk("0x3da(-------) : 0x%2.2x\n", rb_mmio(0x3da));   /* GREG_INPUT_STATUS 1 READ */
+
+       /* engine regs */
+
+       for (i = 0x8180; i <= 0x8200; i = i + 4)
+               printk("0x%8.8x : 0x%8.8x\n", i, rl_mmio(i));
+
+       i = 0x8504;
+       printk("0x%8.8x : 0x%8.8x\n", i, rl_mmio(i));
+       i = 0x850c;
+       printk("0x%8.8x : 0x%8.8x\n", i, rl_mmio(i));
+       for (i = 0xa4d4; i <= 0xa50c; i = i + 4)
+               printk("0x%8.8x : 0x%8.8x\n", i, rl_mmio(i));
+
+       /* PCI regs */
+
+       SelectCFG;
+
+       for (c = 0; c < 0x08; c = c + 2) {
+               w = (*((u16 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)) ^ 2)));
+               printk("pci 0x%2.2x : 0x%4.4x\n", c, w);
+       }
+       c = 8;
+       l = (*((u32 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)))));
+       printk("pci 0x%2.2x : 0x%8.8x\n", c, l);
+       c = 0x0d;
+       b = (*((u8 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)) ^ 3)));
+       printk("pci 0x%2.2x : 0x%2.2x\n", c, b);
+       c = 0x10;
+       l = (*((u32 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)))));
+       printk("pci 0x%2.2x : 0x%8.8x\n", c, l);
+       c = 0x30;
+       l = (*((u32 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)))));
+       printk("pci 0x%2.2x : 0x%8.8x\n", c, l);
+       c = 0x3c;
+       b = (*((u8 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)) ^ 3)));
+       printk("pci 0x%2.2x : 0x%2.2x\n", c, b);
+       c = 0x3d;
+       b = (*((u8 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)) ^ 3)));
+       printk("pci 0x%2.2x : 0x%2.2x\n", c, b);
+       c = 0x3e;
+       w = (*((u16 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)) ^ 2)));
+       printk("pci 0x%2.2x : 0x%4.4x\n", c, w);
+       SelectMMIO;
+}
+#endif
diff --git a/drivers/video/virgefb.h b/drivers/video/virgefb.h
new file mode 100644 (file)
index 0000000..157d66d
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ * linux/drivers/video/virgefb.h -- CyberVision64 definitions for the
+ *                                  text console driver.
+ *
+ *   Copyright (c) 1998 Alan Bair
+ *
+ * This file is based on the initial port to Linux of grf_cvreg.h:
+ *
+ *   Copyright (c) 1997 Antonio Santos
+ *
+ * The original work is from the NetBSD CyberVision 64 framebuffer driver 
+ * and support files (grf_cv.c, grf_cvreg.h, ite_cv.c):
+ * Permission to use the source of this driver was obtained from the
+ * author Michael Teske by Alan Bair.
+ *
+ *   Copyright (c) 1995 Michael Teske
+ *
+ * History:
+ *
+ *
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+/* Enhanced register mapping (MMIO mode) */
+
+#define S3_CRTC_ADR    0x03d4
+#define S3_CRTC_DATA   0x03d5
+
+#define S3_REG_LOCK2   0x39
+#define S3_HGC_MODE    0x45
+
+#define S3_HWGC_ORGX_H 0x46
+#define S3_HWGC_ORGX_L 0x47
+#define S3_HWGC_ORGY_H 0x48
+#define S3_HWGC_ORGY_L 0x49
+#define S3_HWGC_DX     0x4e
+#define S3_HWGC_DY     0x4f
+
+#define S3_LAW_CTL     0x58
+
+/**************************************************/
+
+/*
+ * Defines for the used register addresses (mw)
+ *
+ * NOTE: There are some registers that have different addresses when
+ *       in mono or color mode. We only support color mode, and thus
+ *       some addresses won't work in mono-mode!
+ *
+ * General and VGA-registers taken from retina driver. Fixed a few
+ * bugs in it. (SR and GR read address is Port + 1, NOT Port)
+ *
+ */
+
+/* General Registers: */
+#define GREG_MISC_OUTPUT_R     0x03CC
+#define GREG_MISC_OUTPUT_W     0x03C2  
+#define GREG_FEATURE_CONTROL_R 0x03CA 
+#define GREG_FEATURE_CONTROL_W 0x03DA
+#define GREG_INPUT_STATUS0_R   0x03C2
+#define GREG_INPUT_STATUS1_R   0x03DA
+
+/* Setup Registers: */
+#define SREG_VIDEO_SUBS_ENABLE 0x03C3  /* virge */
+
+/* Attribute Controller: */
+#define ACT_ADDRESS            0x03C0
+#define ACT_ADDRESS_R          0x03C1
+#define ACT_ADDRESS_W          0x03C0
+#define ACT_ADDRESS_RESET      0x03DA
+#define ACT_ID_PALETTE0                0x00
+#define ACT_ID_PALETTE1                0x01
+#define ACT_ID_PALETTE2                0x02
+#define ACT_ID_PALETTE3                0x03
+#define ACT_ID_PALETTE4                0x04
+#define ACT_ID_PALETTE5                0x05
+#define ACT_ID_PALETTE6                0x06
+#define ACT_ID_PALETTE7                0x07
+#define ACT_ID_PALETTE8                0x08
+#define ACT_ID_PALETTE9                0x09
+#define ACT_ID_PALETTE10       0x0A
+#define ACT_ID_PALETTE11       0x0B
+#define ACT_ID_PALETTE12       0x0C
+#define ACT_ID_PALETTE13       0x0D
+#define ACT_ID_PALETTE14       0x0E
+#define ACT_ID_PALETTE15       0x0F
+#define ACT_ID_ATTR_MODE_CNTL  0x10
+#define ACT_ID_OVERSCAN_COLOR  0x11
+#define ACT_ID_COLOR_PLANE_ENA 0x12
+#define ACT_ID_HOR_PEL_PANNING 0x13
+#define ACT_ID_COLOR_SELECT    0x14    /* virge PX_PADD  pixel padding register */
+
+/* Graphics Controller: */
+#define GCT_ADDRESS            0x03CE
+#define GCT_ADDRESS_R          0x03CF
+#define GCT_ADDRESS_W          0x03CF
+#define GCT_ID_SET_RESET       0x00
+#define GCT_ID_ENABLE_SET_RESET        0x01
+#define GCT_ID_COLOR_COMPARE   0x02
+#define GCT_ID_DATA_ROTATE     0x03
+#define GCT_ID_READ_MAP_SELECT 0x04
+#define GCT_ID_GRAPHICS_MODE   0x05
+#define GCT_ID_MISC            0x06
+#define GCT_ID_COLOR_XCARE     0x07
+#define GCT_ID_BITMASK         0x08
+
+/* Sequencer: */
+#define SEQ_ADDRESS            0x03C4
+#define SEQ_ADDRESS_R          0x03C5
+#define SEQ_ADDRESS_W          0x03C5
+#define SEQ_ID_RESET           0x00
+#define SEQ_ID_CLOCKING_MODE   0x01
+#define SEQ_ID_MAP_MASK                0x02
+#define SEQ_ID_CHAR_MAP_SELECT 0x03
+#define SEQ_ID_MEMORY_MODE     0x04
+#define SEQ_ID_UNKNOWN1                0x05
+#define SEQ_ID_UNKNOWN2                0x06
+#define SEQ_ID_UNKNOWN3                0x07
+/* S3 extensions */
+#define SEQ_ID_UNLOCK_EXT      0x08
+#define SEQ_ID_EXT_SEQ_REG9    0x09    /* b7 = 1 extended reg access by MMIO only */
+#define SEQ_ID_BUS_REQ_CNTL    0x0A
+#define SEQ_ID_EXT_MISC_SEQ    0x0B
+#define SEQ_ID_UNKNOWN4                0x0C
+#define SEQ_ID_EXT_SEQ         0x0D
+#define SEQ_ID_UNKNOWN5                0x0E
+#define SEQ_ID_UNKNOWN6                0x0F
+#define SEQ_ID_MCLK_LO         0x10
+#define SEQ_ID_MCLK_HI         0x11
+#define SEQ_ID_DCLK_LO         0x12
+#define SEQ_ID_DCLK_HI         0x13
+#define SEQ_ID_CLKSYN_CNTL_1   0x14
+#define SEQ_ID_CLKSYN_CNTL_2   0x15
+#define SEQ_ID_CLKSYN_TEST_HI  0x16    /* reserved for S3 testing of the */
+#define SEQ_ID_CLKSYN_TEST_LO  0x17    /* internal clock synthesizer   */
+#define SEQ_ID_RAMDAC_CNTL     0x18
+#define SEQ_ID_MORE_MAGIC      0x1A
+#define SEQ_ID_SIGNAL_SELECT   0x1C    /* new for virge */
+
+/* CRT Controller: */
+#define CRT_ADDRESS            0x03D4
+#define CRT_ADDRESS_R          0x03D5
+#define CRT_ADDRESS_W          0x03D5
+#define CRT_ID_HOR_TOTAL       0x00
+#define CRT_ID_HOR_DISP_ENA_END        0x01
+#define CRT_ID_START_HOR_BLANK 0x02
+#define CRT_ID_END_HOR_BLANK   0x03
+#define CRT_ID_START_HOR_RETR  0x04
+#define CRT_ID_END_HOR_RETR    0x05
+#define CRT_ID_VER_TOTAL       0x06
+#define CRT_ID_OVERFLOW                0x07
+#define CRT_ID_PRESET_ROW_SCAN 0x08
+#define CRT_ID_MAX_SCAN_LINE   0x09
+#define CRT_ID_CURSOR_START    0x0A
+#define CRT_ID_CURSOR_END      0x0B
+#define CRT_ID_START_ADDR_HIGH 0x0C
+#define CRT_ID_START_ADDR_LOW  0x0D
+#define CRT_ID_CURSOR_LOC_HIGH 0x0E
+#define CRT_ID_CURSOR_LOC_LOW  0x0F
+#define CRT_ID_START_VER_RETR  0x10
+#define CRT_ID_END_VER_RETR    0x11
+#define CRT_ID_VER_DISP_ENA_END        0x12
+#define CRT_ID_SCREEN_OFFSET   0x13
+#define CRT_ID_UNDERLINE_LOC   0x14
+#define CRT_ID_START_VER_BLANK 0x15
+#define CRT_ID_END_VER_BLANK   0x16
+#define CRT_ID_MODE_CONTROL    0x17
+#define CRT_ID_LINE_COMPARE    0x18
+#define CRT_ID_GD_LATCH_RBACK  0x22
+#define CRT_ID_ACT_TOGGLE_RBACK        0x24
+#define CRT_ID_ACT_INDEX_RBACK 0x26
+/* S3 extensions: S3 VGA Registers */
+#define CRT_ID_DEVICE_HIGH     0x2D
+#define CRT_ID_DEVICE_LOW      0x2E
+#define CRT_ID_REVISION        0x2F
+#define CRT_ID_CHIP_ID_REV     0x30
+#define CRT_ID_MEMORY_CONF     0x31
+#define CRT_ID_BACKWAD_COMP_1  0x32
+#define CRT_ID_BACKWAD_COMP_2  0x33
+#define CRT_ID_BACKWAD_COMP_3  0x34
+#define CRT_ID_REGISTER_LOCK   0x35
+#define CRT_ID_CONFIG_1        0x36
+#define CRT_ID_CONFIG_2        0x37
+#define CRT_ID_REGISTER_LOCK_1 0x38
+#define CRT_ID_REGISTER_LOCK_2 0x39
+#define CRT_ID_MISC_1          0x3A
+#define CRT_ID_DISPLAY_FIFO    0x3B
+#define CRT_ID_LACE_RETR_START 0x3C
+/* S3 extensions: System Control Registers  */
+#define CRT_ID_SYSTEM_CONFIG   0x40
+#define CRT_ID_BIOS_FLAG       0x41
+#define CRT_ID_LACE_CONTROL    0x42
+#define CRT_ID_EXT_MODE        0x43
+#define CRT_ID_HWGC_MODE       0x45    /* HWGC = Hardware Graphics Cursor */
+#define CRT_ID_HWGC_ORIGIN_X_HI        0x46
+#define CRT_ID_HWGC_ORIGIN_X_LO        0x47
+#define CRT_ID_HWGC_ORIGIN_Y_HI        0x48
+#define CRT_ID_HWGC_ORIGIN_Y_LO        0x49
+#define CRT_ID_HWGC_FG_STACK   0x4A
+#define CRT_ID_HWGC_BG_STACK   0x4B
+#define CRT_ID_HWGC_START_AD_HI        0x4C
+#define CRT_ID_HWGC_START_AD_LO        0x4D
+#define CRT_ID_HWGC_DSTART_X   0x4E
+#define CRT_ID_HWGC_DSTART_Y   0x4F
+/* S3 extensions: System Extension Registers  */
+#define CRT_ID_EXT_SYS_CNTL_1  0x50    /* NOT a virge register */
+#define CRT_ID_EXT_SYS_CNTL_2  0x51
+#define CRT_ID_EXT_BIOS_FLAG_1 0x52
+#define CRT_ID_EXT_MEM_CNTL_1  0x53
+#define CRT_ID_EXT_MEM_CNTL_2  0x54
+#define CRT_ID_EXT_DAC_CNTL    0x55
+#define CRT_ID_EX_SYNC_1       0x56
+#define CRT_ID_EX_SYNC_2       0x57
+#define CRT_ID_LAW_CNTL                0x58    /* LAW = Linear Address Window */
+#define CRT_ID_LAW_POS_HI      0x59
+#define CRT_ID_LAW_POS_LO      0x5A
+#define CRT_ID_GOUT_PORT       0x5C
+#define CRT_ID_EXT_HOR_OVF     0x5D
+#define CRT_ID_EXT_VER_OVF     0x5E
+#define CRT_ID_EXT_MEM_CNTL_3  0x60    /* NOT a virge register */
+#define CRT_ID_EXT_MEM_CNTL_4  0x61
+#define CRT_ID_EX_SYNC_3       0x63    /* NOT a virge register */
+#define CRT_ID_EXT_MISC_CNTL   0x65
+#define CRT_ID_EXT_MISC_CNTL_1 0x66
+#define CRT_ID_EXT_MISC_CNTL_2 0x67
+#define CRT_ID_CONFIG_3        0x68
+#define CRT_ID_EXT_SYS_CNTL_3  0x69
+#define CRT_ID_EXT_SYS_CNTL_4  0x6A
+#define CRT_ID_EXT_BIOS_FLAG_3 0x6B
+#define CRT_ID_EXT_BIOS_FLAG_4 0x6C
+/* S3 virge extensions: more System Extension Registers  */
+#define CRT_ID_EXT_BIOS_FLAG_5 0x6D
+#define CRT_ID_EXT_DAC_TEST    0x6E
+#define CRT_ID_CONFIG_4        0x6F
+
+/* Video DAC */
+#define VDAC_ADDRESS           0x03c8
+#define VDAC_ADDRESS_W         0x03c8
+#define VDAC_ADDRESS_R         0x03c7
+#define VDAC_STATE             0x03c7
+#define VDAC_DATA              0x03c9
+#define VDAC_MASK              0x03c6
+
+/* Miscellaneous Registers */
+#define MR_SUBSYSTEM_STATUS_R          0x8504  /* new for virge */
+#define MR_SUBSYSTEM_CNTL_W            0x8504  /* new for virge */
+#define MR_ADVANCED_FUNCTION_CONTROL   0x850C  /* new for virge */
+
+/* Blitter  */
+#define BLT_COMMAND_SET                0xA500
+#define BLT_SIZE_X_Y           0xA504
+#define BLT_SRC_X_Y            0xA508
+#define BLT_DEST_X_Y           0xA50C
+
+#define BLT_SRC_BASE           0xa4d4
+#define BLT_DEST_BASE          0xa4d8
+#define BLT_CLIP_LEFT_RIGHT    0xa4dc
+#define BLT_CLIP_TOP_BOTTOM    0xa4e0
+#define BLT_SRC_DEST_STRIDE    0xa4e4
+#define BLT_MONO_PATTERN_0     0xa4e8
+#define BLT_MONO_PATTERN_1     0xa4ec
+#define BLT_PATTERN_COLOR      0xa4f4
+
+#define L2D_COMMAND_SET                0xA900
+#define L2D_CLIP_LEFT_RIGHT    0xA8DC
+#define L2D_CLIP_TOP_BOTTOM    0xA8E0
+
+#define P2D_COMMAND_SET                0xAD00
+#define P2D_CLIP_LEFT_RIGHT    0xACDC
+#define P2D_CLIP_TOP_BOTTOM    0xACE0
+
+#define CMD_NOP                (0xf << 27)     /* %1111 << 27, was 0x07 */ 
+#define S3V_BITBLT     (0x0 << 27)
+#define S3V_RECTFILL   (0x2 << 27)
+#define S3V_AUTOEXE    0x01
+#define S3V_HWCLIP     0x02
+#define S3V_DRAW       0x20
+#define S3V_DST_8BPP   0x00
+#define S3V_DST_16BPP  0x04
+#define S3V_DST_24BPP  0x08
+#define S3V_MONO_PAT   0x100
+
+#define S3V_BLT_COPY   (0xcc<<17)
+#define S3V_BLT_CLEAR  (0x00<<17)
+#define S3V_BLT_SET    (0xff<<17)