Subject: [PATCH] experimental O2 framebuffer driver

From: Vivien Chappelier <[email-masked]>
Date: Fri, 17 May 2002 02:15:54 +0200 (CEST)

Hi,

	Here are two patch for testing framebuffer support on O2.
	linux-O2-console.diff just adds dummy console/keyboard so that
virtual consoles can be compiled.
	linux-O2-fb.diff is an experimental O2 framebuffer driver based on
the sgivwfb driver. It currently supports 8 bit modes, except 800x600
(I tested 640x480,1024x768,1280x1024,1600x1200 @ 60Hz). 16 bit and 32 bit
modes have wrong colors, but the pixels are in the right place ;)
	Feel free to test... You'll probably need all other patches I've
sent to the list some time ago to get O2 booting.

	I've also included a patch needed to get the mips64 kernel compile
on r4k with the new icache functions, that I've just sent to Ralf too for
integration.
	Patches are against CVS/HEAD.

regards,
Vivien.
diff -Naur linux64/arch/mips64/config.in linux64.new/arch/mips64/config.in
--- linux64/arch/mips64/config.in	Thu May 16 19:55:57 2002
+++ linux64.new/arch/mips64/config.in	Tue May  7 00:42:31 2002
@@ -293,6 +293,9 @@
       else
 	 define_bool CONFIG_FONT_8x16 y
       fi
+   fi
+   if [ "$CONFIG_SGI_IP32" = "y" ]; then
+   	 define_bool CONFIG_DUMMY_CONSOLE y
    fi
   endmenu
 fi
diff -Naur linux64/arch/mips64/kernel/setup.c linux64.new/arch/mips64/kernel/setup.c
--- linux64/arch/mips64/kernel/setup.c	Thu May 16 19:55:59 2002
+++ linux64.new/arch/mips64/kernel/setup.c	Tue May  7 00:43:57 2002
@@ -78,8 +78,10 @@
 extern struct rtc_ops no_rtc_ops;
 struct rtc_ops *rtc_ops;
 
+#ifdef CONFIG_PC_KEYB
 extern struct kbd_ops no_kbd_ops;
 struct kbd_ops *kbd_ops;
+#endif
 
 /*
  * Setup information
@@ -721,6 +723,10 @@
 
 void __init setup_arch(char **cmdline_p)
 {
+#ifdef CONFIG_PC_KEYB
+	kbd_ops = &no_kbd_ops;	
+#endif
+
 #ifdef CONFIG_SGI_IP22
 	ip22_setup();
 #endif
diff -Naur linux64/arch/mips64/sgi-ip32/ip32-setup.c linux64.new/arch/mips64/sgi-ip32/ip32-setup.c
--- linux64/arch/mips64/sgi-ip32/ip32-setup.c	Thu May 16 19:56:06 2002
+++ linux64.new/arch/mips64/sgi-ip32/ip32-setup.c	Sun May 12 22:37:51 2002
@@ -12,6 +12,7 @@
 #include <linux/mc146818rtc.h>
 #include <linux/param.h>
 #include <linux/init.h>
+#include <linux/console.h>
 
 #include <asm/time.h>
 #include <asm/mipsregs.h>
--- linux64/include/asm-mips64/pgtable.h	Thu May 16 20:01:12 2002
+++ linux64.new/include/asm-mips64/pgtable.h	Sun May  5 21:52:18 2002
@@ -551,6 +551,8 @@
 #define kern_addr_valid(addr)	(1)
 #endif
 
+#define io_remap_page_range remap_page_range
+
 /*
  * No page table caches to initialise
  */
diff -Naur linux64/drivers/video/Config.in linux64.new/drivers/video/Config.in
--- linux64/drivers/video/Config.in	Thu May 16 19:59:49 2002
+++ linux64.new/drivers/video/Config.in	Tue May 14 23:38:34 2002
@@ -97,6 +97,9 @@
       tristate '  SGI Visual Workstation framebuffer support' CONFIG_FB_SGIVW
       define_bool CONFIG_BUS_I2C y
    fi
+   if [ "$CONFIG_SGI_IP32" = "y" ]; then
+      bool '  SGI O2 frame buffer support' CONFIG_FB_SGIO2
+   fi
    if [ "$CONFIG_SUN3" = "y" -o "$CONFIG_SUN3X" = "y" ]; then
       bool '  Sun3 framebuffer support' CONFIG_FB_SUN3
       if [ "$CONFIG_FB_SUN3" != "n" ]; then
@@ -196,6 +199,7 @@
    if [ "$CONFIG_NINO" = "y" ]; then
       bool '  TMPTX3912/PR31700 frame buffer support' CONFIG_FB_TX3912
    fi
+
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       tristate '  Virtual Frame Buffer support (ONLY FOR TESTING!)' CONFIG_FB_VIRTUAL
    fi
@@ -264,11 +268,11 @@
 	   "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
 	   "$CONFIG_FB_P9100" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
 	   "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \
-	   "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \
+	   "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" \
 	   "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \
 	   "$CONFIG_FB_PMAG_BA" = "y" -o "$CONFIG_FB_PMAGB_B" = "y" -o \
 	   "$CONFIG_FB_MAXINE" = "y" -o "$CONFIG_FB_TX3912" = "y" -o \
-	   "$CONFIG_FB_SIS" = "y" ]; then
+	   "$CONFIG_FB_SIS" = "y"  -o "$CONFIG_FB_SGIO2" = "y"]; then
 	 define_tristate CONFIG_FBCON_CFB8 y
       else
 	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
@@ -284,11 +288,11 @@
 	      "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
 	      "$CONFIG_FB_P9100" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
 	      "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_3DFX" = "m" -o \
-	      "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" -o \
+	      "$CONFIG_FB_SGIVW" = "m"  -o "$CONFIG_FB_CYBER2000" = "m" \
 	      "$CONFIG_FB_PMAG_BA" = "m" -o "$CONFIG_FB_PMAGB_B" = "m" -o \
 	      "$CONFIG_FB_MAXINE" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
 	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
-	      "$CONFIG_FB_TX3912" = "m" ]; then
+	      "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_SGIO2" = "m"]; then
 	    define_tristate CONFIG_FBCON_CFB8 m
 	 fi
       fi
@@ -304,7 +308,8 @@
 	   "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
 	   "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y"  -o \
 	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \
-	   "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" ]; then
+	   "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" -o \
+	   "$CONFIG_FB_SGIO2" = "y"]; then
 	 define_tristate CONFIG_FBCON_CFB16 y
       else
 	 if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
@@ -319,7 +324,8 @@
 	      "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
 	      "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
 	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
-	      "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" ]; then
+	      "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" -o \
+	      "$CONFIG_FB_SGIO2" = "m"]; then
 	    define_tristate CONFIG_FBCON_CFB16 m
 	 fi
       fi
@@ -349,7 +355,7 @@
 	   "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \
 	   "$CONFIG_FB_RADEON" = "y" -o "$CONFIG_FB_PVR2" = "y" -o \
 	   "$CONFIG_FB_3DFX" = "y" -o "$CONFIG_FB_SIS" = "y" -o \
-	   "$CONFIG_FB_VOODOO1" = "y" ]; then
+	   "$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_SGIO2" = "y"]; then
 	 define_tristate CONFIG_FBCON_CFB32 y
       else
 	 if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
@@ -360,7 +366,8 @@
 	      "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
 	      "$CONFIG_FB_3DFX" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
 	      "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
-	      "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" ]; then
+	      "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" -o \
+	      "$CONFIG_FB_SGIO2" = "m" ]; then
 	    define_tristate CONFIG_FBCON_CFB32 m
 	 fi
       fi
diff -Naur linux64/drivers/video/Makefile linux64.new/drivers/video/Makefile
--- linux64/drivers/video/Makefile	Thu May 16 19:59:49 2002
+++ linux64.new/drivers/video/Makefile	Tue May  7 22:02:32 2002
@@ -57,6 +57,7 @@
 obj-$(CONFIG_FB_CYBER)            += cyberfb.o
 obj-$(CONFIG_FB_CYBER2000)        += cyber2000fb.o
 obj-$(CONFIG_FB_SGIVW)            += sgivwfb.o
+obj-$(CONFIG_FB_SGIO2)            += sgio2fb.o
 obj-$(CONFIG_FB_3DFX)             += tdfxfb.o
 obj-$(CONFIG_FB_MAC)              += macfb.o macmodes.o
 obj-$(CONFIG_FB_HP300)            += hpfb.o
@@ -84,7 +85,6 @@
 obj-$(CONFIG_FB_PMAGB_B)          += pmagb-b-fb.o
 obj-$(CONFIG_FB_MAXINE)           += maxinefb.o
 obj-$(CONFIG_FB_TX3912)           += tx3912fb.o
-
 
 subdir-$(CONFIG_FB_MATROX)	  += matrox
 ifeq ($(CONFIG_FB_MATROX),y)
diff -Naur linux64/drivers/video/fbmem.c linux64.new/drivers/video/fbmem.c
--- linux64/drivers/video/fbmem.c	Thu May 16 19:59:53 2002
+++ linux64.new/drivers/video/fbmem.c	Thu May 16 19:47:37 2002
@@ -110,6 +110,8 @@
 extern int sun3fb_setup(char *);
 extern int sgivwfb_init(void);
 extern int sgivwfb_setup(char*);
+extern int sgio2fb_init(void);
+extern int sgio2fb_setup(char*);
 extern int rivafb_init(void);
 extern int rivafb_setup(char*);
 extern int tdfxfb_init(void);
@@ -237,6 +239,9 @@
 #ifdef CONFIG_FB_SGIVW
 	{ "sgivw", sgivwfb_init, sgivwfb_setup },
 #endif
+#ifdef CONFIG_FB_SGIO2
+	{ "sgio2", sgio2fb_init, sgio2fb_setup },
+#endif
 #ifdef CONFIG_FB_ACORN
 	{ "acorn", acornfb_init, acornfb_setup },
 #endif
diff -Naur linux64/drivers/video/sgio2fb.c linux64.new/drivers/video/sgio2fb.c
--- linux64/drivers/video/sgio2fb.c	Thu Jan  1 01:00:00 1970
+++ linux64.new/drivers/video/sgio2fb.c	Thu May 16 19:46:29 2002
@@ -0,0 +1,1199 @@
+/*
+ *  linux/drivers/video/sgio2fb.c -- SGI GBE frame buffer device
+ *
+ *	Copyright (C) 1999 Silicon Graphics, Inc.
+ *      Jeffrey Newquist, [email-masked]
+ *     Copyright (C) 2002 Vivien Chappelier, [email-masked] 
+ *      modified from the original SGI VW DBE driver to support the O2 GBE
+ *
+ *  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.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <asm/io.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb32.h>
+
+#define INCLUDE_TIMING_TABLE_DATA
+#define GBE_REG_BASE regs
+#include "sgio2fb.h"
+
+struct sgio2fb_par {
+  struct fb_var_screeninfo var;
+  u_long timing_num;
+  int valid;
+};
+
+/*
+ *  RAM we reserve for the frame buffer. This defines the maximum screen
+ *  size
+ *
+ *  The default can be overridden if the driver is compiled as a module
+ */
+
+/* TODO: add an option */
+#define VIDEOMEMSIZE	(2*1024*1024)	/* 2 MB */
+
+static u16 *sgio2fb_tiles_table;
+static u_long sgio2fb_mem_phys;
+static u_long sgio2fb_mem_size;
+
+static volatile char  *fbmem;
+static asregs         *regs;
+static struct fb_info fb_info;
+static struct { u_char red, green, blue, pad; } palette[256];
+static char           sgio2fb_name[16] = "SGI O2 FB";
+static u32            cmap_fifo;
+static int            ypan       = 0;
+static int            ywrap      = 0;
+static int            video_bpp;
+
+/* console related variables */
+static int currcon = 0;
+static struct display disp;
+
+static union {
+#ifdef FBCON_HAS_CFB16
+  u16 cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+  u32 cfb32[16];
+#endif
+} fbcon_cmap;
+
+static struct sgio2fb_par par_current = {
+  // TEMP: for testing various modes
+#if 0
+  {                             /* var (screeninfo) */
+    /* 640x480, 32 bpp */
+    640, 480, 640, 480, 0, 0, 32, 0,
+    {24, 8, 0}, {16, 8, 0}, {8, 8, 0}, {0, 8, 0},
+    0, 0, -1, -1, 0, 20000, 64, 64, 32, 32, 64, 2,
+    0, FB_VMODE_NONINTERLACED
+  },
+  0,                            /* timing_num */
+  0				/* par not activated */
+#endif
+#if 0
+  {                             /* var (screeninfo) */
+    /* 640x480, 16 bpp */
+    640, 480, 640, 480, 0, 0, 16, 0,
+    {10, 5, 0}, {5, 5, 0}, {0, 5, 0}, {0, 0, 0},
+    0, 0, -1, -1, 0, 20000, 64, 64, 32, 32, 64, 2,
+    0, FB_VMODE_NONINTERLACED
+  },
+  0,                            /* timing_num */
+  0				/* par not activated */
+#endif
+#if 1
+  {                             /* var (screeninfo) */
+    /* 640x480, 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, 0, 20000, 64, 64, 32, 32, 64, 2,
+    0, FB_VMODE_NONINTERLACED
+  },
+  0,                            /* timing_num */
+  0				/* par not activated */
+#endif
+#if 0
+  {                             /* var (screeninfo) */
+    /* 800x600, 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, 0, 20000, 64, 64, 32, 32, 64, 2,
+    0, FB_VMODE_NONINTERLACED
+  },
+  GBE_VT_800_600_75,                            /* timing_num */
+  0				/* par not activated */
+#endif
+#if 0
+  {                             /* var (screeninfo) */
+    /* 800x600, 16 bpp */
+    800, 600, 800, 600, 0, 0, 16, 0,
+    {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+    0, 0, -1, -1, 0, 20000, 64, 64, 32, 32, 64, 2,
+    0, FB_VMODE_NONINTERLACED
+  },
+  GBE_VT_800_600_75,                            /* timing_num */
+  0				/* par not activated */
+#endif
+#if 0
+{                             /* var (screeninfo) */
+    /* 1024x768, 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, 0, 15384, 64, 64, 32, 32, 64, 2,
+    0, FB_VMODE_NONINTERLACED
+  },
+  GBE_VT_1024_768_60,
+  0				/* par not activated */
+#endif
+#if 0
+{                             /* var (screeninfo) */
+    /* 1280x1024, 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, 0, 15384, 64, 64, 32, 32, 64, 2,
+    0, FB_VMODE_NONINTERLACED
+  },
+  GBE_VT_1280_1024_60,
+  0				/* par not activated */
+#endif
+#if 0
+{                             /* var (screeninfo) */
+    /* 1280x1024, 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, 0, 15384, 64, 64, 32, 32, 64, 2,
+    0, FB_VMODE_NONINTERLACED
+  },
+  GBE_VT_1600_1200_60,
+  0				/* par not activated */
+#endif
+};
+
+/*
+ *  Interface used by the world
+ */
+int sgio2fb_setup(char*);
+
+static int sgio2fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			   struct fb_info *info);
+static int sgio2fb_get_var(struct fb_var_screeninfo *var, int con,
+			   struct fb_info *info);
+static int sgio2fb_set_var(struct fb_var_screeninfo *var, int con,
+			   struct fb_info *info);
+static int sgio2fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			    struct fb_info *info);
+static int sgio2fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			    struct fb_info *info);
+static int sgio2fb_mmap(struct fb_info *info, struct file *file,
+                        struct vm_area_struct *vma);
+
+static struct fb_ops sgio2fb_ops = {
+	owner:		THIS_MODULE,
+	fb_get_fix:	sgio2fb_get_fix,
+	fb_get_var:	sgio2fb_get_var,
+	fb_set_var:	sgio2fb_set_var,
+	fb_get_cmap:	sgio2fb_get_cmap,
+	fb_set_cmap:	sgio2fb_set_cmap,
+	fb_mmap:	sgio2fb_mmap,
+};
+
+/*
+ *  Interface to the low level console driver
+ */
+int sgio2fb_init(void);
+static int sgio2fbcon_switch(int con, struct fb_info *info);
+static int sgio2fbcon_updatevar(int con, struct fb_info *info);
+static void sgio2fbcon_blank(int blank, struct fb_info *info);
+
+/*
+ *  Internal routines
+ */
+static u_long get_line_length(int xres_virtual, int bpp);
+static unsigned long bytes_per_pixel(int bpp);
+static void activate_par(struct sgio2fb_par *par);
+static void sgio2fb_encode_fix(struct fb_fix_screeninfo *fix,
+			       struct fb_var_screeninfo *var);
+static int sgio2fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+			     u_int *transp, struct fb_info *info);
+static int sgio2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			     u_int transp, struct fb_info *info);
+static void do_install_cmap(int con, struct fb_info *info);
+
+static unsigned long get_line_length(int xres_virtual, int bpp)
+{
+  return(xres_virtual * bytes_per_pixel(bpp));
+}
+
+static unsigned long bytes_per_pixel(int bpp)
+{
+  unsigned long length;
+
+  switch (bpp) {
+  case 8:
+    length = 1;
+    break;
+  case 16:
+    length = 2;
+    break;
+  case 32:
+    length = 4;
+    break;
+  default:
+    printk(KERN_INFO "sgio2fb: unsupported bpp=%d\n", bpp);
+    length = 0;
+    break;
+  }
+  return(length);
+}
+
+/*
+ * Function:	gbe_TurnOffDma
+ * Parameters:	(None)
+ * Description:	This should turn off the monitor and gbe.  This is used
+ *              when switching between the serial console and the graphics
+ *              console.
+ */
+
+static void gbe_TurnOffDma(void)
+{
+  int i;
+  unsigned int readVal;
+
+  // Check to see if things are already turned off:
+  // 1) Check to see if gbe is not using the internal dotclock.
+  // 2) Check to see if the xy counter in gbe is already off.
+
+  GBE_GETREG(ctrlstat, readVal);
+  if (GET_GBE_FIELD(CTRLSTAT, PCLKSEL, readVal) < 2)
+    return;
+
+  GBE_GETREG(vt_xy, readVal);
+  if (GET_GBE_FIELD(VT_XY, VT_FREEZE, readVal) == 1)
+    return;
+
+  // Otherwise, turn off gbe
+  GBE_GETREG(ovr_control, readVal);
+  SET_GBE_FIELD(OVR_CONTROL, OVR_DMA_ENABLE, readVal, 0);
+  GBE_SETREG(ovr_control, readVal);
+  udelay(1000);
+  GBE_GETREG(frm_control, readVal);
+  SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, readVal, 0);
+  GBE_SETREG(frm_control, readVal);
+  udelay(1000);
+  GBE_GETREG(did_control, readVal);
+  SET_GBE_FIELD(DID_CONTROL, DID_DMA_ENABLE, readVal, 0);
+  GBE_SETREG(did_control, readVal);
+  udelay(1000);
+
+  // XXX HACK:
+  //
+  //    This was necessary for GBE--we had to wait through two
+  //    vertical retrace periods before the pixel DMA was
+  //    turned off for sure.  I've left this in for now, in
+  //    case dbe needs it.
+  // [VC].. well now this is GBE ;)
+
+  for (i = 0; i < 10000; i++)
+    {
+      GBE_GETREG(frm_inhwctrl, readVal);
+      if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, readVal) == 0) {
+        udelay(10);
+      }
+      else
+        {
+          GBE_GETREG(ovr_inhwctrl, readVal);
+          if (GET_GBE_FIELD(OVR_INHWCTRL, OVR_DMA_ENABLE, readVal) == 0) {
+            udelay(10);
+	  }
+          else
+            {
+              GBE_GETREG(did_inhwctrl, readVal);
+              if (GET_GBE_FIELD(DID_INHWCTRL, DID_DMA_ENABLE, readVal) == 0) {
+                udelay(10);
+	      }
+              else
+                break;
+            }
+        }
+    }
+}
+
+/*
+ *  Set the hardware according to 'par'.
+ */
+static void activate_par(struct sgio2fb_par *par)
+{
+  int i,j, htmp, temp;
+  u32 readVal, outputVal;
+  int wholeTilesX, partTilesX, maxPixelsPerTileX;
+  int height_pix;
+  int frmWrite1, frmWrite2, frmWrite3b;
+  gbe_timing_info_t *currentTiming;    /* Current Video Timing */
+  int xpmax, ypmax;                       // Monitor resolution
+  int bytesPerPixel;                      // Bytes per pixel
+
+  currentTiming = &gbeVTimings[par->timing_num];
+  bytesPerPixel = bytes_per_pixel(par->var.bits_per_pixel);
+  xpmax = currentTiming->width;
+  ypmax = currentTiming->height;
+
+  /* gbe_InitGraphicsBase(); */
+  /* Turn on dotclock PLL */
+  GBE_SETREG(ctrlstat, 0x30000000);
+
+  gbe_TurnOffDma();
+
+  /* gbe_CalculateScreenParams(); */
+  /* HACK:
+       The GBE hardware uses a tiled memory to screen mapping. Tiles are blocks of
+       512x128, 256x128 or 128x128 pixels, respectively for 8bit, 16bit and 32 bit
+       modes (64 kB). They cover the screen with partial tiles on the right and/or
+       bottom of the screen if needed. For exemple in 640x480 8 bit mode the mapping
+       is:
+	 
+         <-------- 640 ----->
+         <---- 512 ----><128|384 offscreen>
+    ^  ^
+    | 128    [tile 0]        [tile 1]
+    |  v
+       ^
+    4 128    [tile 2]        [tile 3]
+    8  v
+    0  ^
+      128    [tile 4]        [tile 5]
+    |  v
+    |  ^
+    v  96    [tile 6]        [tile 7]
+       32 offscreen
+
+       Tiles have the advantage that they can be allocated individually in memory.
+       However, this mapping is not linear at all, which is not really convienient.
+       In order to support linear addressing, the GBE DMA hardware is fooled into
+       thinking the screen is only one tile large and but has a greater height, so 
+       that the DMA transfer covers the same region.
+       First a continous region is allocated in memory to serve as the framebuffer.
+       Then the tile table is set up so that each tile reference a 64k block in this
+       memory:
+       GBE DMA ---> tile list             framebuffer
+                   [ tile 0 ] ---> [ 0x00000000:0x0000ffff ]
+                   [ tile 1 ] ---> [ 0x00010000:0x0001ffff ]
+                   [ tile 2 ] ---> [ 0x00020000:0x0002ffff ]
+                   [ tile 3 ] ---> [ 0x00030000:0x0003ffff ]
+		      ...                     ...
+                   [ tile n ] ---> [ 0x000n0000:0x000nffff ]
+
+	The GBE hardware is then told that the buffer is 512xtweaked_height, with 
+	tweaked_height = real_widthxreal_height/pixels_per_tile
+	Thus the GBE hardware will scan the first tile, filing the first 64k covered
+	region of the screen, and then will proceed to the next tile, which is just
+	after the first one in memory, until the whole screen is covered.
+
+	Here is what would happen at 640x480 8bit:
+
+	     normal tiling               linear
+      ^   11111111111111112222    11111111111111111111  ^
+     128  11111111111111112222    11111111111111111111 102 lines
+          11111111111111112222    11111111111111111111  v
+      V   11111111111111112222    11111111222222222222
+	  33333333333333334444    22222222222222222222
+	  33333333333333334444    22222222222222222222
+	  <      512     >        <  256 >               102*640+256 = 64k
+
+     NOTE: The only mode for which this is not working is 800x600 8bit, as
+           800*600/512 = 937.5 which is not integer and thus causes flickering.
+	   I guess this is not so important as one can use 640x480 8bit or
+	   800x600 16bit anyway.
+  */
+  maxPixelsPerTileX = 512/bytesPerPixel;
+  wholeTilesX = 1;
+  partTilesX = 0;
+
+  /* Initialize tile pointers */
+  for(i = 0; i < 128; i++)
+    sgio2fb_tiles_table[i] = (u16) (CPHYSADDR(sgio2fb_mem_phys) >> 16) + i;
+
+  /* gbe_InitGammaMap(); */
+  udelay(10);
+  for (i = 0; i < 256; i++)
+    GBE_ISETREG(gmap, i, (i << 24) | (i << 16) | (i << 8));
+
+  /* gbe_TurnOn(); */
+  GBE_GETREG(vt_xy, readVal);
+  if (GET_GBE_FIELD(VT_XY, VT_FREEZE, readVal) == 1)
+  {
+      GBE_SETREG(vt_xy, 0x00000000);
+      udelay(1);
+  }
+  else
+    gbe_TurnOffDma();
+
+  /* gbe_Initgbe(); */
+  for (i = 0; i < 256; i++)
+  {
+    /* XXX: not working
+      for (j = 0; j < 100; j++)
+      {
+          GBE_GETREG(cm_fifo, cmap_fifo);
+          if (cmap_fifo != 0x00000000)
+            break;
+          else
+            udelay(10);
+      }
+    */
+    GBE_ISETREG(cmap, i, (i<<8)|(i<<16)|(i<<24));
+    udelay(1000); /* leave some delay instead */
+  }
+
+  /* gbe_InitFramebuffer(); */
+  frmWrite1 = 0;
+  SET_GBE_FIELD(FRM_SIZE_TILE, FRM_WIDTH_TILE, frmWrite1, wholeTilesX);
+  SET_GBE_FIELD(FRM_SIZE_TILE, FRM_RHS, frmWrite1, partTilesX);
+
+  switch(bytesPerPixel)
+    {
+      case 1:
+        SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1, GBE_FRM_DEPTH_8);
+        break;
+      case 2:
+        SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1, GBE_FRM_DEPTH_16);
+        break;
+      case 4:
+        SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1, GBE_FRM_DEPTH_32);
+        break;
+    }
+
+  frmWrite2 = 0;
+  // SET_GBE_FIELD(FRM_SIZE_PIXEL, FB_HEIGHT_PIX, frmWrite2, ypmax);
+
+  /* compute tweaked height = real width x real height / pixels per tile */
+  height_pix = xpmax*ypmax/maxPixelsPerTileX;
+
+  if(height_pix * maxPixelsPerTileX != xpmax*ypmax)
+    printk(KERN_DEBUG "sgio2fb: this mode cannot be mapped linearly. Please use another one.\n");
+
+  SET_GBE_FIELD(FRM_SIZE_PIXEL, FB_HEIGHT_PIX, frmWrite2, height_pix);
+
+  // Tell gbe about the framebuffer location and type
+  /* tile_ptr -> [ tile 1 ] -> FB mem */
+  /*             [ tile 2 ] -> FB mem */
+  /*               ...                */
+  frmWrite3b = 0;
+  SET_GBE_FIELD(FRM_CONTROL, FRM_TILE_PTR, frmWrite3b, ((u32)CPHYSADDR(sgio2fb_tiles_table))>>9);
+  SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, frmWrite3b, 1);
+
+  /* Initialize DIDs */
+  outputVal = 0;
+  switch(bytesPerPixel)
+  {
+      case 1:
+        SET_GBE_FIELD(WID, TYP, outputVal, GBE_CMODE_I8);
+        break;
+      case 2:
+        SET_GBE_FIELD(WID, TYP, outputVal, GBE_CMODE_RGBA5);
+        break;
+      case 4:
+        SET_GBE_FIELD(WID, TYP, outputVal, GBE_CMODE_RGB8);
+        break;
+  }
+  SET_GBE_FIELD(WID, BUF, outputVal, GBE_BMODE_BOTH);
+  //  SET_GBE_FIELD(WID, GAMMA, outputVal, 1); /* disable gamma correction */
+
+  for (i = 0; i < 32; i++)
+    {
+      GBE_ISETREG(mode_regs, i, outputVal);
+    }
+
+  /* gbe_InitTiming(); */
+  GBE_SETREG(vt_intr01, 0xffffffff);
+  GBE_SETREG(vt_intr23, 0xffffffff);
+
+  GBE_GETREG(dotclock, readVal);
+  GBE_SETREG(dotclock, readVal & 0xffff);
+
+  GBE_SETREG(vt_xymax, 0x00000000);
+  outputVal = 0;
+  SET_GBE_FIELD(VT_VSYNC, VT_VSYNC_ON, outputVal, currentTiming->vsync_start);
+  SET_GBE_FIELD(VT_VSYNC, VT_VSYNC_OFF, outputVal, currentTiming->vsync_end);
+  GBE_SETREG(vt_vsync, outputVal);
+  outputVal = 0;
+  SET_GBE_FIELD(VT_HSYNC, VT_HSYNC_ON, outputVal, currentTiming->hsync_start);
+  SET_GBE_FIELD(VT_HSYNC, VT_HSYNC_OFF, outputVal, currentTiming->hsync_end);
+  GBE_SETREG(vt_hsync, outputVal);
+  outputVal = 0;
+  SET_GBE_FIELD(VT_VBLANK, VT_VBLANK_ON, outputVal, currentTiming->vblank_start);
+  SET_GBE_FIELD(VT_VBLANK, VT_VBLANK_OFF, outputVal, currentTiming->vblank_end);
+  GBE_SETREG(vt_vblank, outputVal);
+  outputVal = 0;
+  SET_GBE_FIELD(VT_HBLANK, VT_HBLANK_ON, outputVal, currentTiming->hblank_start-5);
+  SET_GBE_FIELD(VT_HBLANK, VT_HBLANK_OFF, outputVal, currentTiming->hblank_end-3);
+  GBE_SETREG(vt_hblank, outputVal);
+  outputVal = 0;
+  SET_GBE_FIELD(VT_VCMAP, VT_VCMAP_ON, outputVal, currentTiming->vblank_start);
+  SET_GBE_FIELD(VT_VCMAP, VT_VCMAP_OFF, outputVal, currentTiming->vblank_end);
+  GBE_SETREG(vt_vcmap, outputVal);
+  outputVal = 0;
+  SET_GBE_FIELD(VT_HCMAP, VT_HCMAP_ON, outputVal, currentTiming->hblank_start);
+  SET_GBE_FIELD(VT_HCMAP, VT_HCMAP_OFF, outputVal, currentTiming->hblank_end-3);
+  GBE_SETREG(vt_hcmap, outputVal);
+
+  /* turn off sync on green */
+  outputVal = 0;
+  SET_GBE_FIELD(VT_FLAGS, VT_SYNC_LOW, outputVal, 1);
+  GBE_SETREG(vt_flags, outputVal);
+
+  outputVal = 0;
+  temp = currentTiming->vblank_start - currentTiming->vblank_end - 1;
+  if (temp > 0)
+    temp = -temp;
+
+  SET_GBE_FIELD(DID_START_XY, DID_STARTY, outputVal, (u32)temp);
+  if (currentTiming->hblank_end >= 20)
+    SET_GBE_FIELD(DID_START_XY, DID_STARTX, outputVal,
+                      currentTiming->hblank_end - 20);
+  else
+    SET_GBE_FIELD(DID_START_XY, DID_STARTX, outputVal,
+                      currentTiming->htotal - (20 - currentTiming->hblank_end));
+  GBE_SETREG(did_start_xy, outputVal);
+
+  outputVal = 0;
+  SET_GBE_FIELD(CRS_START_XY, CRS_STARTY, outputVal, (u32)(temp+1));
+  if (currentTiming->hblank_end >= GBE_CRS_MAGIC)
+    SET_GBE_FIELD(CRS_START_XY, CRS_STARTX, outputVal,
+                      currentTiming->hblank_end - GBE_CRS_MAGIC);
+  else
+    SET_GBE_FIELD(CRS_START_XY, CRS_STARTX, outputVal,
+                      currentTiming->htotal - (GBE_CRS_MAGIC - currentTiming->hblank_end));
+  GBE_SETREG(crs_start_xy, outputVal);
+
+  outputVal = 0;
+  SET_GBE_FIELD(VC_START_XY, VC_STARTY, outputVal, (u32)temp);
+  SET_GBE_FIELD(VC_START_XY, VC_STARTX, outputVal,
+                    currentTiming->hblank_end - 4);
+  GBE_SETREG(vc_start_xy, outputVal);
+
+  GBE_SETREG(frm_size_tile, frmWrite1);
+  GBE_SETREG(frm_size_pixel, frmWrite2);
+
+  outputVal = 0;
+  SET_GBE_FIELD(DOTCLK, M, outputVal, currentTiming->pll_m-1);
+  SET_GBE_FIELD(DOTCLK, N, outputVal, currentTiming->pll_n-1);
+  SET_GBE_FIELD(DOTCLK, P, outputVal, currentTiming->pll_p);
+  SET_GBE_FIELD(DOTCLK, RUN, outputVal, 1);
+  GBE_SETREG(dotclock, outputVal);
+
+  udelay(11*1000);
+
+  GBE_SETREG(vt_vpixen, 0xffffff);
+  GBE_SETREG(vt_hpixen, 0xffffff);
+
+  outputVal = 0;
+  SET_GBE_FIELD(VT_XYMAX, VT_MAXX, outputVal, currentTiming->htotal);
+  SET_GBE_FIELD(VT_XYMAX, VT_MAXY, outputVal, currentTiming->vtotal);
+  GBE_SETREG(vt_xymax, outputVal);
+
+  outputVal = frmWrite1;
+  // SET_GBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, outputVal, 1);
+  GBE_SETREG(frm_size_tile, outputVal);
+  GBE_SETREG(frm_size_tile, frmWrite1);
+
+  outputVal = 0;
+  //  SET_GBE_FIELD(OVR_WIDTH_TILE, OVR_FIFO_RESET, outputVal, 1);
+  GBE_SETREG(ovr_width_tile, outputVal);
+  GBE_SETREG(ovr_width_tile, 0);
+
+  GBE_SETREG(frm_control, frmWrite3b);
+  GBE_SETREG(did_control, 0);
+
+  // Wait for gbe to take frame settings
+  for (i=0; i<100000; i++)
+    {
+      GBE_GETREG(frm_inhwctrl, readVal);
+      if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, readVal) != 0)
+        break;
+      else
+        udelay(1);
+    }
+
+  if (i==100000)
+    printk(KERN_INFO "sgio2fb: timeout waiting for frame DMA enable.\n");
+
+  outputVal = 0;
+  htmp = currentTiming->hblank_end - 19;
+  if (htmp < 0)
+    htmp += currentTiming->htotal;    /* allow blank to wrap around */
+  SET_GBE_FIELD(VT_HPIXEN, VT_HPIXEN_ON, outputVal, htmp);
+  SET_GBE_FIELD(VT_HPIXEN, VT_HPIXEN_OFF, outputVal,
+                    ((htmp + currentTiming->width - 2) % currentTiming->htotal));
+  GBE_SETREG(vt_hpixen, outputVal);
+
+  outputVal = 0;
+  SET_GBE_FIELD(VT_VPIXEN, VT_VPIXEN_OFF, outputVal,
+                    currentTiming->vblank_start);
+  SET_GBE_FIELD(VT_VPIXEN, VT_VPIXEN_ON, outputVal,
+                    currentTiming->vblank_end);
+  GBE_SETREG(vt_vpixen, outputVal);
+
+  // Turn off mouse cursor
+  regs->crs_ctl = 0;
+
+  // XXX What's this section for??
+  GBE_GETREG(ctrlstat, readVal);
+  readVal &= 0x02000000;
+
+  if (readVal != 0)
+  {
+      GBE_SETREG(ctrlstat, 0x30000000);
+  }
+}
+
+static void sgio2fb_encode_fix(struct fb_fix_screeninfo *fix,
+			       struct fb_var_screeninfo *var)
+{
+  memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+  strcpy(fix->id, sgio2fb_name);
+  fix->smem_start = sgio2fb_mem_phys;
+  fix->smem_len = sgio2fb_mem_size;
+  fix->type = FB_TYPE_PACKED_PIXELS;
+  fix->type_aux = 0;
+  switch (var->bits_per_pixel) {
+  case 8:
+    fix->visual = FB_VISUAL_PSEUDOCOLOR;
+    break;
+  default:
+    fix->visual = FB_VISUAL_TRUECOLOR;
+    break;
+  }
+  fix->ywrapstep = ywrap;
+  fix->xpanstep = 0;
+  fix->ypanstep = ypan;
+  fix->line_length = get_line_length(var->xres_virtual, var->bits_per_pixel);
+  fix->mmio_start = GBE_REG_PHYS;
+  fix->mmio_len = GBE_REG_SIZE;
+}
+
+/*
+ *  Read a single color register and split it into
+ *  colors/transparent. Return != 0 for invalid regno.
+ */
+static int sgio2fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+                             u_int *transp, struct fb_info *info)
+{
+  if (regno > 255)
+    return 1;
+
+  *red =   palette[regno].red << 8;
+  *green = palette[regno].green << 8;
+  *blue =  palette[regno].blue << 8;
+  *transp = 0;
+  return 0;
+}
+
+/*
+ *  Set a single color register. The values supplied are already
+ *  rounded down to the hardware's capabilities (according to the
+ *  entries in the var structure). Return != 0 for invalid regno.
+ */
+
+static int sgio2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                             u_int transp, struct fb_info *info)
+{
+  int i;
+
+  if (regno > 255)
+    return 1;
+  red >>= 8;
+  green >>= 8;
+  blue >>= 8;
+  palette[regno].red = red;
+  palette[regno].green = green;
+  palette[regno].blue = blue;
+
+  switch (video_bpp) {
+#ifdef FBCON_HAS_CFB8
+    case 8:
+      /* wait for the color map FIFO to have a free entry */
+      /* XXX: doesn't seem to work, ignoring fifo state 
+	 (this may cause 'snow' artifacts on colormap change)
+	 for(i = 0; i < 10000 && cmap_fifo == 0; i++) {
+	   udelay(10);
+	   cmap_fifo = regs->cm_fifo;
+	 } 
+       if(i == 10000) {
+         printk(KERN_ERR "sgio2fb: cmap FIFO timeout\n");
+         return 1;
+       }
+      */
+      regs->cmap[regno] = (red << 24) | (green << 16) | (blue << 8);
+      udelay(1000); /* leave some delay instead */
+      cmap_fifo--;			/* assume FIFO is filling up */
+      break;
+#endif
+#ifdef FBCON_HAS_CFB16
+    case 15:
+    case 16:
+      if(regno > 15) return 1;
+      fbcon_cmap.cfb16[regno] =
+	((red   & 0xf8) <<  7) |
+	((green & 0xf8) <<  2) |
+	((blue  & 0xf8) >>  3);
+      break;
+#endif
+#ifdef FBCON_HAS_CFB32
+    case 32:
+      if(regno > 15) return 1;
+      fbcon_cmap.cfb32[regno] =
+	(red   << 24) |
+	(green << 16) |
+	(blue  << 8);
+      break;
+#endif
+  }
+
+  return 0;
+}
+
+static void do_install_cmap(int con, struct fb_info *info)
+{
+    if (con != currcon)
+	return;
+    if (fb_display[con].cmap.len)
+	fb_set_cmap(&fb_display[con].cmap, 1, sgio2fb_setcolreg, info);
+    else
+	fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), 1,
+		    sgio2fb_setcolreg, info);
+}
+
+/* ---------------------------------------------------- */
+
+/*
+ *  Get the Fixed Part of the Display
+ */
+static int sgio2fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			   struct fb_info *info)
+{
+  struct fb_var_screeninfo *var;
+
+  if (con == -1)
+    var = &par_current.var;
+  else
+    var = &fb_display[con].var;
+  sgio2fb_encode_fix(fix, var);
+  return 0;
+}
+
+/*
+ *  Get the User Defined Part of the Display. If a real par get it form there
+ */
+static int sgio2fb_get_var(struct fb_var_screeninfo *var, int con,
+			   struct fb_info *info)
+{
+  if (con == -1)
+    *var = par_current.var;
+  else
+    *var = fb_display[con].var;
+  return 0;
+}
+
+/*
+ *  Set the User Defined Part of the Display. Again if par use it to get
+ *  real video mode.
+ */
+static int sgio2fb_set_var(struct fb_var_screeninfo *var, int con,
+			   struct fb_info *info)
+{
+  int err, activate = var->activate;
+  int oldxres, oldyres, oldvxres, oldvyres, oldbpp;
+  u_long line_length;
+  u_long min_mode;
+  int req_dot;
+  int test_mode;
+
+  struct gbe_timing_info *timing;
+
+  struct display *display;
+
+  if (con >= 0)
+    display = &fb_display[con];
+  else
+    display = &disp;	/* used during initialization */
+
+  /*
+   *  FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
+   *  as FB_VMODE_SMOOTH_XPAN is only used internally
+   */
+
+  if (var->vmode & FB_VMODE_CONUPDATE) {
+    var->vmode |= FB_VMODE_YWRAP;
+    var->xoffset = display->var.xoffset;
+    var->yoffset = display->var.yoffset;
+  }
+
+  /* XXX FIXME - forcing var's */
+  var->xoffset = 0;
+  var->yoffset = 0;
+
+  /* Limit bpp to 8, 16, and 32 */
+  if (var->bits_per_pixel <= 8)
+    var->bits_per_pixel = 8;
+  else if (var->bits_per_pixel <= 16)
+    var->bits_per_pixel = 16;
+  else if (var->bits_per_pixel <= 32)
+    var->bits_per_pixel = 32;
+  else
+    return -EINVAL;
+
+  video_bpp = var->bits_per_pixel;
+
+  var->grayscale = 0;           /* No grayscale for now */
+
+  /* determine valid resolution and timing */
+  for (min_mode=0; min_mode<GBE_VT_SIZE; min_mode++) {
+    if (gbeVTimings[min_mode].width >= var->xres &&
+        gbeVTimings[min_mode].height >= var->yres)
+      break;
+  }
+
+  if (min_mode == GBE_VT_SIZE)
+    return -EINVAL;             /* Resolution to high */
+
+  /* XXX FIXME - should try to pick best refresh rate */
+  /* for now, pick closest dot-clock within 3MHz*/
+  req_dot = 1000000000 / var->pixclock;
+  printk(KERN_INFO "sgio2fb: requested pixclock=%d ps (%d KHz)\n", var->pixclock,
+	 req_dot);
+  test_mode=min_mode;
+  while (gbeVTimings[min_mode].width == gbeVTimings[test_mode].width) {
+    if (gbeVTimings[test_mode].cfreq+3000 > req_dot)
+      break;
+    test_mode++;
+  }
+  if (gbeVTimings[min_mode].width != gbeVTimings[test_mode].width)
+    test_mode--;
+  min_mode = test_mode;
+  timing = &gbeVTimings[min_mode];
+  printk(KERN_INFO "sgio2fb: granted dot-clock=%d KHz\n", timing->cfreq);
+
+  /* Adjust virtual resolution, if necessary */
+  if (var->xres > var->xres_virtual || (!ywrap && !ypan))
+    var->xres_virtual = var->xres;
+  if (var->yres > var->yres_virtual || (!ywrap && !ypan))
+    var->yres_virtual = var->yres;
+
+  /*
+   *  Memory limit
+   */
+  line_length = get_line_length(var->xres_virtual, var->bits_per_pixel);
+  if (line_length*var->yres_virtual > sgio2fb_mem_size)
+    return -ENOMEM;             /* Virtual resolution to high */
+
+  switch (var->bits_per_pixel)
+    {
+    case 8:
+      var->red.offset = 0;
+      var->red.length = 8;
+      var->green.offset = 0;
+      var->green.length = 8;
+      var->blue.offset = 0;
+      var->blue.length = 8;
+      var->transp.offset = 0;
+      var->transp.length = 0;
+      break;
+    case 16:	/* RGBA 5551 */
+      var->red.offset = 11;
+      var->red.length = 5;
+      var->green.offset = 6;
+      var->green.length = 5;
+      var->blue.offset = 1;
+      var->blue.length = 5;
+      var->transp.offset = 0;
+      var->transp.length = 0;
+      break;
+    case 32:	/* RGB 8888 */
+      var->red.offset = 0;
+      var->red.length = 8;
+      var->green.offset = 8;
+      var->green.length = 8;
+      var->blue.offset = 16;
+      var->blue.length = 8;
+      var->transp.offset = 24;
+      var->transp.length = 8;
+      break;
+    }
+  var->red.msb_right = 0;
+  var->green.msb_right = 0;
+  var->blue.msb_right = 0;
+  var->transp.msb_right = 0;
+
+  /* set video timing information */
+  var->pixclock = (__u32)(1000000000/timing->cfreq);
+  var->left_margin = timing->htotal - timing->hsync_end;
+  var->right_margin = timing->hsync_start - timing->width;
+  var->upper_margin = timing->vtotal - timing->vsync_end;
+  var->lower_margin = timing->vsync_start - timing->height;
+  var->hsync_len = timing->hsync_end - timing->hsync_start;
+  var->vsync_len = timing->vsync_end -  timing->vsync_start;
+
+  if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+    oldxres = display->var.xres;
+    oldyres = display->var.yres;
+    oldvxres = display->var.xres_virtual;
+    oldvyres = display->var.yres_virtual;
+    oldbpp = display->var.bits_per_pixel;
+    display->var = *var;
+    par_current.var = *var;
+    par_current.timing_num = min_mode;
+    if (oldxres != var->xres || oldyres != var->yres ||
+	oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
+	oldbpp != var->bits_per_pixel || !par_current.valid) {
+      struct fb_fix_screeninfo fix;
+      printk(KERN_INFO "sgio2fb: new video mode xres=%d yres=%d bpp=%d\n",
+	     var->xres, var->yres, var->bits_per_pixel);
+      printk(KERN_INFO "         vxres=%d vyres=%d\n",
+	     var->xres_virtual, var->yres_virtual);
+      activate_par(&par_current);
+      sgio2fb_encode_fix(&fix, var);
+
+      display->screen_base = (char *)fbmem;
+      display->visual = fix.visual;
+      display->type = fix.type;
+      display->type_aux = fix.type_aux;
+      display->ypanstep = fix.ypanstep;
+      display->ywrapstep = fix.ywrapstep;
+      display->line_length = fix.line_length;
+      display->can_soft_blank = 1;
+      display->inverse = 0;
+      if (oldbpp != var->bits_per_pixel || !par_current.valid) {
+	if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
+	  return err;
+	do_install_cmap(con, info);
+      }
+      switch (var->bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
+      case 8:
+	display->dispsw = &fbcon_cfb8;
+	break;
+#endif
+#ifdef FBCON_HAS_CFB16
+      case 16:
+	display->dispsw = &fbcon_cfb16;
+	display->dispsw_data = fbcon_cmap.cfb16;
+	break;
+#endif
+#ifdef FBCON_HAS_CFB32
+      case 32:
+	display->dispsw = &fbcon_cfb32;
+	display->dispsw_data = fbcon_cmap.cfb32;
+	break;
+#endif
+      default:
+	display->dispsw = &fbcon_dummy;
+	break;
+      }
+      par_current.valid = 1;
+      if (fb_info.changevar)
+	(*fb_info.changevar)(con);
+    }
+  }
+
+  return 0;
+}
+
+/*
+ *  Get the Colormap
+ */
+static int sgio2fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			    struct fb_info *info)
+{
+  if (con == currcon) /* current console? */
+    return fb_get_cmap(cmap, kspc, sgio2fb_getcolreg, info);
+  else if (fb_display[con].cmap.len) /* non default colormap? */
+    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),
+		 cmap, kspc ? 0 : 2);
+  return 0;
+}
+
+/*
+ *  Set the Colormap
+ */
+static int sgio2fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			    struct fb_info *info)
+{
+  int err;
+
+  if (!fb_display[con].cmap.len) {	/* no colormap allocated? */
+    int size = fb_display[con].var.bits_per_pixel == 8 ? 256 : 16;
+    if ((err = fb_alloc_cmap(&fb_display[con].cmap, size, 0)))
+      return err;
+  }
+  if (con == currcon)			/* current console? */
+    return fb_set_cmap(cmap, kspc, sgio2fb_setcolreg, info);
+  else
+    fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+  return 0;
+}
+
+static int sgio2fb_mmap(struct fb_info *info, struct file *file,
+                        struct vm_area_struct *vma)
+{
+  unsigned long size = vma->vm_end - vma->vm_start;
+  unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+
+  if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+	return -EINVAL;
+  if (offset+size > sgio2fb_mem_size)
+    return -EINVAL;
+  offset += sgio2fb_mem_phys;
+  pgprot_val(vma->vm_page_prot) = 
+    (pgprot_val(vma->vm_page_prot) & (~_CACHE_MASK)) | _CACHE_UNCACHED;
+  vma->vm_flags |= VM_IO;
+  if (remap_page_range(vma->vm_start, offset, size, vma->vm_page_prot))
+    return -EAGAIN;
+  vma->vm_file = file;
+  printk(KERN_DEBUG "sgio2fb: mmap framebuffer P(%lx)->V(%lx)\n", offset, vma->vm_start);
+  return 0;
+}
+
+int __init sgio2fb_setup(char *options)
+{
+  char *this_opt;
+
+  fb_info.fontname[0] = '\0';
+
+  if (!options || !*options)
+    return 0;
+
+  while ((this_opt = strsep(&options, ",")) != NULL) {
+    if (!strncmp(this_opt, "font:", 5))
+      strcpy(fb_info.fontname, this_opt+5);
+  }
+  return 0;
+}
+
+/*
+ *  Initialisation
+ */
+int __init sgio2fb_init(void)
+{
+  printk(KERN_INFO "sgio2fb: initializing\n");
+
+  sgio2fb_mem_size = VIDEOMEMSIZE;
+
+  if (!(sgio2fb_mem_phys = (u_long)__get_free_pages(GFP_DMA, get_order(sgio2fb_mem_size)))) {
+    printk(KERN_ERR "sgio2fb: couldn't allocate %ld bytes for the framebuffer\n",
+	   sgio2fb_mem_size);
+    return -ENOMEM;
+  }
+
+  /* TEMP: Make sure the framebuffer is uncached */
+  sgio2fb_mem_phys = KSEG1ADDR(CPHYSADDR(sgio2fb_mem_phys));
+
+  if (!(sgio2fb_tiles_table = (u16 *)__get_free_page(GFP_DMA))) {
+      printk("sgio2fb: could not allocate tiles table\n");
+      return -ENOMEM;
+  }
+
+  /* TEMP: Make sure tiles are uncached too */
+  sgio2fb_tiles_table = (u16 *)KSEG1ADDR(CPHYSADDR(sgio2fb_tiles_table));
+
+  memset(sgio2fb_tiles_table, 0, 128*sizeof(u16));
+
+  printk(KERN_INFO "sgio2fb: I/O at 0x%08x\n", GBE_REG_PHYS);
+  printk(KERN_INFO "sgio2fb: framebuffer at 0x%lx, size %ldk\n",
+	 sgio2fb_mem_phys, sgio2fb_mem_size/1024);
+  printk(KERN_INFO "sgio2fb: tiles at %p\n",
+	 sgio2fb_tiles_table);
+
+  regs = (asregs*)GBE_REG_PHYS;
+  if (!regs) {
+    printk(KERN_ERR "sgio2fb: couldn't ioremap registers\n");
+    goto fail_ioremap_regs;
+  }
+
+  /* [VC] TODO: change caching attributes to write combined?
+  mtrr_add((unsigned long)sgio2fb_mem_phys, sgio2fb_mem_size, MTRR_TYPE_WRCOMB, 1);
+  */
+
+  strcpy(fb_info.modename, sgio2fb_name);
+  fb_info.changevar = NULL;
+  fb_info.node = -1;
+  fb_info.fbops = &sgio2fb_ops;
+  fb_info.disp = &disp;
+  fb_info.switch_con = &sgio2fbcon_switch;
+  fb_info.updatevar = &sgio2fbcon_updatevar;
+  fb_info.blank = &sgio2fbcon_blank;
+  fb_info.flags = FBINFO_FLAG_DEFAULT;
+
+  /* TODO: mark pages as uncached (or write combined) */
+  fbmem = (char*)sgio2fb_mem_phys;
+
+  /* turn on default video mode */
+  sgio2fb_set_var(&par_current.var, -1, &fb_info);
+
+  if (register_framebuffer(&fb_info) < 0) {
+    printk(KERN_ERR "sgio2fb: couldn't register framebuffer\n");
+    goto fail_register_framebuffer;
+  }
+
+  printk(KERN_INFO "fb%d: Virtual frame buffer device, using %ldK of video memory\n",
+	 GET_FB_IDX(fb_info.node), sgio2fb_mem_size>>10);
+
+  return 0;
+
+ fail_register_framebuffer:
+ fail_ioremap_regs:
+  return -ENXIO;
+}
+
+static int sgio2fbcon_switch(int con, struct fb_info *info)
+{
+  /* Do we have to save the colormap? */
+  if (fb_display[currcon].cmap.len)
+    fb_get_cmap(&fb_display[currcon].cmap, 1, sgio2fb_getcolreg, info);
+
+  currcon = con;
+
+  /* Install new colormap */
+  do_install_cmap(con, info);
+
+  return 0;
+}
+
+/*
+ *  Update the `var' structure (called by fbcon.c)
+ */
+static int sgio2fbcon_updatevar(int con, struct fb_info *info)
+{
+    /* Nothing */
+    return 0;
+}
+
+/*
+ *  Blank the display.
+ */
+static void sgio2fbcon_blank(int blank, struct fb_info *info)
+{
+    /* Nothing */
+    /* TODO: turn off DMA */
+}
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+
+int init_module(void)
+{
+  return sgio2fb_init();
+}
+
+void cleanup_module(void)
+{
+  unregister_framebuffer(&fb_info);
+  gbe_TurnOffDma();
+  iounmap(regs);
+  iounmap(fbmem);
+}
+
+#endif /* MODULE */
diff -Naur linux64/drivers/video/sgio2fb.h linux64.new/drivers/video/sgio2fb.h
--- linux64/drivers/video/sgio2fb.h	Thu Jan  1 01:00:00 1970
+++ linux64.new/drivers/video/sgio2fb.h	Wed May 15 23:12:24 2002
@@ -0,0 +1,560 @@
+/*
+ *  linux/drivers/video/sgivwfb.h -- SGI GBE frame buffer device header
+ *
+ *      Copyright (C) 1999 Silicon Graphics, Inc.
+ *      Jeffrey Newquist, [email-masked]
+ *
+ *  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.
+ */
+
+#ifndef __SGIO2FB_H__
+#define __SGIO2FB_H__
+
+#include <asm/ip32/crime.h>
+#include <asm/addrspace.h>
+
+#define CRIME_FLUSH crime_read_64(CRIME_CONTROL)
+
+#define GBE_GETREG(reg, dest)       ((dest) = GBE_REG_BASE->##reg)
+#define GBE_SETREG(reg, src)        (GBE_REG_BASE->##reg = (src));CRIME_FLUSH
+#define GBE_IGETREG(reg, idx, dest) ((dest) = GBE_REG_BASE->##reg##[idx])
+#define GBE_ISETREG(reg, idx, src)  (GBE_REG_BASE->##reg##[idx] = (src));CRIME_FLUSH
+
+#define MASK(msb, lsb)          ( (((u32)1<<((msb)-(lsb)+1))-1) << (lsb) )
+#define GET(v, msb, lsb)        ( ((u32)(v) & MASK(msb,lsb)) >> (lsb) )
+#define SET(v, f, msb, lsb)     ( (v) = ((v)&~MASK(msb,lsb)) | (( (u32)(f)<<(lsb) ) & MASK(msb,lsb)) )
+
+#define GET_GBE_FIELD(reg, field, v)        GET((v), GBE_##reg##_##field##_MSB, GBE_##reg##_##field##_LSB)
+#define SET_GBE_FIELD(reg, field, v, f)     SET((v), (f), GBE_##reg##_##field##_MSB, GBE_##reg##_##field##_LSB)
+
+/* NOTE: All loads/stores must be 32 bits and uncached */
+
+#define GBE_REG_PHYS	KSEG1ADDR(0x16000000)
+#define GBE_REG_SIZE    0x01000000
+
+typedef struct {
+  volatile u32 ctrlstat;     /* 0x000000 general control */
+  volatile u32 dotclock;     /* 0x000004 dot clock PLL control */
+  volatile u32 i2c;          /* 0x000008 crt I2C control */
+  volatile u32 sysclk;       /* 0x00000c system clock PLL control */
+  volatile u32 i2cfp;        /* 0x000010 flat panel I2C control */
+  volatile u32 id;           /* 0x000014 device id/chip revision */
+  volatile u32 config;       /* 0x000018 power on configuration */
+  volatile u32 bist;         /* 0x00001c internal bist status */
+
+  char _pad0[ 0x010000 - 0x000020 ];
+
+  volatile u32 vt_xy;        /* 0x010000 current dot coords */
+  volatile u32 vt_xymax;     /* 0x010004 maximum dot coords */
+  volatile u32 vt_vsync;     /* 0x010008 vsync on/off */
+  volatile u32 vt_hsync;     /* 0x01000c hsync on/off */
+  volatile u32 vt_vblank;    /* 0x010010 vblank on/off */
+  volatile u32 vt_hblank;    /* 0x010014 hblank on/off */
+  volatile u32 vt_flags;     /* 0x010018 polarity of vt signals */
+  volatile u32 vt_f2rf_lock; /* 0x01001c f2rf & framelck y coord */
+  volatile u32 vt_intr01;    /* 0x010020 intr 0,1 y coords */
+  volatile u32 vt_intr23;    /* 0x010024 intr 2,3 y coords */
+  volatile u32 fp_hdrv;      /* 0x010028 flat panel hdrv on/off */
+  volatile u32 fp_vdrv;      /* 0x01002c flat panel vdrv on/off */
+  volatile u32 fp_de;        /* 0x010030 flat panel de on/off */
+  volatile u32 vt_hpixen;    /* 0x010034 intrnl horiz pixel on/off*/
+  volatile u32 vt_vpixen;    /* 0x010038 intrnl vert pixel on/off */
+  volatile u32 vt_hcmap;     /* 0x01003c cmap write (horiz) */
+  volatile u32 vt_vcmap;     /* 0x010040 cmap write (vert) */
+  volatile u32 did_start_xy; /* 0x010044 eol/f did/xy reset val */
+  volatile u32 crs_start_xy; /* 0x010048 eol/f crs/xy reset val */
+  volatile u32 vc_start_xy;  /* 0x01004c eol/f vc/xy reset val */
+
+  char _pad1[ 0x020000 - 0x010050 ];
+
+  volatile u32 ovr_width_tile; /* 0x020000 overlay plane ctrl 0 */
+  volatile u32 ovr_inhwctrl;   /* 0x020004 overlay plane ctrl 1 */
+  volatile u32 ovr_control;    /* 0x020008 overlay plane ctrl 1 */
+
+  char _pad2[ 0x030000 - 0x02000C ];
+
+  volatile u32 frm_size_tile;  /* 0x030000 normal plane ctrl 0 */
+  volatile u32 frm_size_pixel; /* 0x030004 normal plane ctrl 1 */
+  volatile u32 frm_inhwctrl;   /* 0x030008 normal plane ctrl 2 */
+  volatile u32 frm_control;    /* 0x03000C normal plane ctrl 3 */
+
+  char _pad3[ 0x040000 - 0x030010 ];
+
+  volatile u32 did_inhwctrl;   /* 0x040000 DID control */
+  volatile u32 did_control;    /* 0x040004 DID shadow */
+
+  char _pad4[ 0x048000 - 0x040008 ];
+
+  volatile u32 mode_regs[32];  /* 0x048000 - 0x04807c WID table */
+
+  char _pad5[ 0x050000 - 0x048080 ];
+
+  volatile u32 cmap[6144];     /* 0x050000 - 0x055ffc color map */
+
+  char _pad6[ 0x058000 - 0x056000 ];
+
+  volatile u32 cm_fifo;        /* 0x058000 color map fifo status */
+
+  char _pad7[ 0x060000 - 0x058004 ];
+
+  volatile u32 gmap[256];      /* 0x060000 - 0x0603fc gamma map */
+
+  char _pad8[ 0x068000 - 0x060400 ];
+
+  volatile u32 gmap10[1024];   /* 0x068000 - 0x068ffc gamma map */
+
+  char _pad9[ 0x070000 - 0x069000 ];
+
+  volatile u32 crs_pos;        /* 0x070000 cusror control 0 */
+  volatile u32 crs_ctl;        /* 0x070004 cusror control 1 */
+  volatile u32 crs_cmap[3];    /* 0x070008 - 0x070010 crs cmap */
+
+  char _pad10[ 0x078000 - 0x070014 ];
+
+  volatile u32 crs_glyph[64];  /* 0x078000 - 0x0780fc crs glyph */
+
+  char _pad11[ 0x080000 - 0x078100 ];
+
+  volatile u32 vc_0;           /* 0x080000 video capture crtl 0 */
+  volatile u32 vc_1;           /* 0x080004 video capture crtl 1 */
+  volatile u32 vc_2;           /* 0x080008 video capture crtl 2 */
+  volatile u32 vc_3;           /* 0x08000c video capture crtl 3 */
+  volatile u32 vc_4;           /* 0x080010 video capture crtl 3 */
+  volatile u32 vc_5;           /* 0x080014 video capture crtl 3 */
+  volatile u32 vc_6;           /* 0x080018 video capture crtl 3 */
+  volatile u32 vc_7;           /* 0x08001c video capture crtl 3 */
+  volatile u32 vc_8;           /* 0x08000c video capture crtl 3 */
+} asregs;
+
+/* Bit mask information */
+
+#define GBE_CTRLSTAT_CHIPID_MSB     3
+#define GBE_CTRLSTAT_CHIPID_LSB     0
+#define GBE_CTRLSTAT_SENSE_N_MSB    4
+#define GBE_CTRLSTAT_SENSE_N_LSB    4
+#define GBE_CTRLSTAT_PCLKSEL_MSB    29
+#define GBE_CTRLSTAT_PCLKSEL_LSB    28
+
+#define GBE_DOTCLK_M_MSB            7
+#define GBE_DOTCLK_M_LSB            0
+#define GBE_DOTCLK_N_MSB            13
+#define GBE_DOTCLK_N_LSB            8
+#define GBE_DOTCLK_P_MSB            15
+#define GBE_DOTCLK_P_LSB            14
+#define GBE_DOTCLK_RUN_MSB          20
+#define GBE_DOTCLK_RUN_LSB          20
+
+#define GBE_VT_XY_VT_FREEZE_MSB     31
+#define GBE_VT_XY_VT_FREEZE_LSB     31
+
+#define GBE_VT_VSYNC_VT_VSYNC_ON_MSB        23
+#define GBE_VT_VSYNC_VT_VSYNC_ON_LSB        12
+#define GBE_VT_VSYNC_VT_VSYNC_OFF_MSB       11
+#define GBE_VT_VSYNC_VT_VSYNC_OFF_LSB       0
+
+#define GBE_VT_HSYNC_VT_HSYNC_ON_MSB        23
+#define GBE_VT_HSYNC_VT_HSYNC_ON_LSB        12
+#define GBE_VT_HSYNC_VT_HSYNC_OFF_MSB       11
+#define GBE_VT_HSYNC_VT_HSYNC_OFF_LSB       0
+
+#define GBE_VT_VBLANK_VT_VBLANK_ON_MSB        23
+#define GBE_VT_VBLANK_VT_VBLANK_ON_LSB        12
+#define GBE_VT_VBLANK_VT_VBLANK_OFF_MSB       11
+#define GBE_VT_VBLANK_VT_VBLANK_OFF_LSB       0
+
+#define GBE_VT_HBLANK_VT_HBLANK_ON_MSB        23
+#define GBE_VT_HBLANK_VT_HBLANK_ON_LSB        12
+#define GBE_VT_HBLANK_VT_HBLANK_OFF_MSB       11
+#define GBE_VT_HBLANK_VT_HBLANK_OFF_LSB       0
+
+#define GBE_VT_FLAGS_VT_F2RF_HIGH_MSB    6
+#define GBE_VT_FLAGS_VT_F2RF_HIGH_LSB    6
+#define GBE_VT_FLAGS_VT_SYNC_LOW_MSB     5
+#define GBE_VT_FLAGS_VT_SYNC_LOW_LSB     5
+#define GBE_VT_FLAGS_VT_SYNC_HIGH_MSB    4
+#define GBE_VT_FLAGS_VT_SYNC_HIGH_LSB    4
+#define GBE_VT_FLAGS_VT_HDRV_LOW_MSB     3
+#define GBE_VT_FLAGS_VT_HDRV_LOW_LSB     3
+#define GBE_VT_FLAGS_VT_HDRV_INVERT_MSB  2
+#define GBE_VT_FLAGS_VT_HDRV_INVERT_LSB  2
+#define GBE_VT_FLAGS_VT_VDRV_LOW_MSB     1
+#define GBE_VT_FLAGS_VT_VDRV_LOW_LSB     1
+#define GBE_VT_FLAGS_VT_VDRV_INVERT_MSB  0
+#define GBE_VT_FLAGS_VT_VDRV_INVERT_LSB  0
+
+#define GBE_VT_VCMAP_VT_VCMAP_ON_MSB        23
+#define GBE_VT_VCMAP_VT_VCMAP_ON_LSB        12
+#define GBE_VT_VCMAP_VT_VCMAP_OFF_MSB       11
+#define GBE_VT_VCMAP_VT_VCMAP_OFF_LSB       0
+
+#define GBE_VT_HCMAP_VT_HCMAP_ON_MSB        23
+#define GBE_VT_HCMAP_VT_HCMAP_ON_LSB        12
+#define GBE_VT_HCMAP_VT_HCMAP_OFF_MSB       11
+#define GBE_VT_HCMAP_VT_HCMAP_OFF_LSB       0
+
+#define GBE_VT_XYMAX_VT_MAXX_MSB    11
+#define GBE_VT_XYMAX_VT_MAXX_LSB    0
+#define GBE_VT_XYMAX_VT_MAXY_MSB    23
+#define GBE_VT_XYMAX_VT_MAXY_LSB    12
+
+#define GBE_VT_HPIXEN_VT_HPIXEN_ON_MSB      23
+#define GBE_VT_HPIXEN_VT_HPIXEN_ON_LSB      12
+#define GBE_VT_HPIXEN_VT_HPIXEN_OFF_MSB     11
+#define GBE_VT_HPIXEN_VT_HPIXEN_OFF_LSB     0
+
+#define GBE_VT_VPIXEN_VT_VPIXEN_ON_MSB      23
+#define GBE_VT_VPIXEN_VT_VPIXEN_ON_LSB      12
+#define GBE_VT_VPIXEN_VT_VPIXEN_OFF_MSB     11
+#define GBE_VT_VPIXEN_VT_VPIXEN_OFF_LSB     0
+
+#define GBE_OVR_CONTROL_OVR_DMA_ENABLE_MSB  0
+#define GBE_OVR_CONTROL_OVR_DMA_ENABLE_LSB  0
+
+#define GBE_OVR_INHWCTRL_OVR_DMA_ENABLE_MSB 0
+#define GBE_OVR_INHWCTRL_OVR_DMA_ENABLE_LSB 0
+
+#define GBE_OVR_WIDTH_TILE_OVR_FIFO_RESET_MSB       13
+#define GBE_OVR_WIDTH_TILE_OVR_FIFO_RESET_LSB       13
+
+#define GBE_FRM_CONTROL_FRM_DMA_ENABLE_MSB  0
+#define GBE_FRM_CONTROL_FRM_DMA_ENABLE_LSB  0
+#define GBE_FRM_CONTROL_FRM_TILE_PTR_MSB    31
+#define GBE_FRM_CONTROL_FRM_TILE_PTR_LSB    9
+#define GBE_FRM_CONTROL_FRM_LINEAR_MSB      1
+#define GBE_FRM_CONTROL_FRM_LINEAR_LSB      1
+
+#define GBE_FRM_INHWCTRL_FRM_DMA_ENABLE_MSB 0
+#define GBE_FRM_INHWCTRL_FRM_DMA_ENABLE_LSB 0
+
+#define GBE_FRM_SIZE_TILE_FRM_WIDTH_TILE_MSB        12
+#define GBE_FRM_SIZE_TILE_FRM_WIDTH_TILE_LSB        5
+#define GBE_FRM_SIZE_TILE_FRM_RHS_MSB       4
+#define GBE_FRM_SIZE_TILE_FRM_RHS_LSB       0
+#define GBE_FRM_SIZE_TILE_FRM_DEPTH_MSB     14
+#define GBE_FRM_SIZE_TILE_FRM_DEPTH_LSB     13
+#define GBE_FRM_SIZE_TILE_FRM_FIFO_RESET_MSB        15
+#define GBE_FRM_SIZE_TILE_FRM_FIFO_RESET_LSB        15
+
+#define GBE_FRM_SIZE_PIXEL_FB_HEIGHT_PIX_MSB        31
+#define GBE_FRM_SIZE_PIXEL_FB_HEIGHT_PIX_LSB        16
+
+#define GBE_DID_CONTROL_DID_DMA_ENABLE_MSB  0
+#define GBE_DID_CONTROL_DID_DMA_ENABLE_LSB  0
+#define GBE_DID_INHWCTRL_DID_DMA_ENABLE_MSB 0
+#define GBE_DID_INHWCTRL_DID_DMA_ENABLE_LSB 0
+
+#define GBE_DID_START_XY_DID_STARTY_MSB     23
+#define GBE_DID_START_XY_DID_STARTY_LSB     12
+#define GBE_DID_START_XY_DID_STARTX_MSB     11
+#define GBE_DID_START_XY_DID_STARTX_LSB     0
+
+#define GBE_CRS_START_XY_CRS_STARTY_MSB     23
+#define GBE_CRS_START_XY_CRS_STARTY_LSB     12
+#define GBE_CRS_START_XY_CRS_STARTX_MSB     11
+#define GBE_CRS_START_XY_CRS_STARTX_LSB     0
+
+#define GBE_WID_AUX_MSB    12
+#define GBE_WID_AUX_LSB    11
+#define GBE_WID_GAMMA_MSB  10
+#define GBE_WID_GAMMA_LSB  10
+#define GBE_WID_CM_MSB      9
+#define GBE_WID_CM_LSB      5
+#define GBE_WID_TYP_MSB     4
+#define GBE_WID_TYP_LSB     2
+#define GBE_WID_BUF_MSB     1
+#define GBE_WID_BUF_LSB     0
+
+#define GBE_VC_START_XY_VC_STARTY_MSB       23
+#define GBE_VC_START_XY_VC_STARTY_LSB       12
+#define GBE_VC_START_XY_VC_STARTX_MSB       11
+#define GBE_VC_START_XY_VC_STARTX_LSB       0
+
+/* Constants */
+
+#define GBE_FRM_DEPTH_8     0
+#define GBE_FRM_DEPTH_16    1
+#define GBE_FRM_DEPTH_32    2
+
+#define GBE_CMODE_I8        0
+#define GBE_CMODE_I12       1
+#define GBE_CMODE_RG3B2     2
+#define GBE_CMODE_RGB4      3
+#define GBE_CMODE_ARGB5     4
+#define GBE_CMODE_RGB8      5
+#define GBE_CMODE_RGBA5     6
+#define GBE_CMODE_RGB10     7
+
+#define GBE_BMODE_BOTH      3
+
+#define GBE_CRS_MAGIC       54
+
+/* Config Register (GBE Only) Definitions */
+
+#define GBE_CONFIG_VDAC_ENABLE       0x00000001
+#define GBE_CONFIG_VDAC_GSYNC        0x00000002
+#define GBE_CONFIG_VDAC_PBLANK       0x00000004
+#define GBE_CONFIG_FPENABLE          0x00000008
+#define GBE_CONFIG_LENDIAN           0x00000020
+#define GBE_CONFIG_TILEHIST          0x00000040
+#define GBE_CONFIG_EXT_ADDR          0x00000080
+
+#define GBE_CONFIG_FBDEV        ( GBE_CONFIG_VDAC_ENABLE | \
+                                      GBE_CONFIG_VDAC_GSYNC  | \
+                                      GBE_CONFIG_VDAC_PBLANK | \
+                                      GBE_CONFIG_LENDIAN     | \
+                                      GBE_CONFIG_EXT_ADDR )
+
+/*
+ * Available Video Timings and Corresponding Indices
+ */
+
+typedef enum {
+  GBE_VT_640_480_60,
+  GBE_VT_800_600_60,
+  GBE_VT_800_600_75,
+
+  GBE_VT_1024_768_60,
+  GBE_VT_1024_768_75,
+  GBE_VT_1024_768_85,
+
+  GBE_VT_1280_1024_50,
+  GBE_VT_1280_1024_60,
+  GBE_VT_1280_1024_75,
+  GBE_VT_1280_1024_85,
+
+  GBE_VT_1600_1024_60,
+
+  GBE_VT_1600_1200_60,
+  GBE_VT_1600_1200_75,
+
+  GBE_VT_1920_1080_60,
+
+  GBE_VT_UNKNOWN
+} gbe_timing_t;
+
+
+
+/*
+ * Crime Video Timing Data Structure
+ */
+
+typedef struct gbe_timing_info
+{
+  gbe_timing_t type;
+  int flags;				
+  short width;		    /* Monitor resolution		*/
+  short height;
+  int fields_sec;	    /* fields/sec  (Hz -3 dec. places */
+  int cfreq;		    /* pixel clock frequency (MHz -3 dec. places) */
+  short htotal;		    /* Horizontal total pixels	*/
+  short hblank_start;	    /* Horizontal blank start	*/
+  short hblank_end;	    /* Horizontal blank end		*/
+  short hsync_start;	    /* Horizontal sync start	*/
+  short hsync_end;	    /* Horizontal sync end		*/
+  short vtotal;		    /* Vertical total lines		*/
+  short vblank_start;	    /* Vertical blank start		*/
+  short vblank_end;	    /* Vertical blank end		*/
+  short vsync_start;	    /* Vertical sync start		*/
+  short vsync_end;	    /* Vertical sync end		*/
+  short pll_m;		    /* PLL M parameter		*/
+  short pll_n;		    /* PLL P parameter		*/
+  short pll_p;		    /* PLL N parameter		*/
+} gbe_timing_info_t;
+
+/* Defines for gbe_vof_info_t flags */
+
+#define GBE_VOF_UNKNOWNMON    1
+#define GBE_VOF_STEREO        2
+#define GBE_VOF_DO_GENSYNC    4          /* enable incoming sync */
+#define GBE_VOF_SYNC_ON_GREEN 8          /* sync on green */
+#define GBE_VOF_FLATPANEL     0x1000     /* FLATPANEL Timing */
+#define GBE_VOF_MAGICKEY      0x2000     /* Backdoor key */
+
+/*
+ * GBE Timing Tables
+ */
+
+#ifdef INCLUDE_TIMING_TABLE_DATA
+
+/* GBE crystal runs at 20Mhz */
+/* pll_m, pll_n, pll_p define the following frequencies */
+/* fvco = pll_m * 20Mhz / pll_n */
+/* fout = fvco / (2**pll_p) */
+
+struct gbe_timing_info gbeVTimings[] = {
+  /* TODO: update timings, since crystal clock is 20Mhz instead of 27Mhz */
+  {
+    GBE_VT_640_480_60,
+    /*	flags,	width,			height,		fields_sec,		cfreq */
+    0,  	640,			480,		59934,			25172,
+    /*	htotal,	hblank_start,	hblank_end,	hsync_start,	hsync_end */
+    800,	640,		    800,		664,	    	760,
+    /*	vtotal,	vblank_start,	vblank_end,	vsync_start,	vsync_end */
+    525,	480,		    525,		491,		493,
+    /*	pll_m,	pll_n,			pll_p */
+    146,	 29,			2
+  },
+
+  {
+    GBE_VT_800_600_60,
+    /*	flags,	width,			height,		fields_sec,		cfreq */
+    0,	    800,			600,		60317,			40000,
+    /*	htotal,	hblank_start,	hblank_end,	hsync_start,	hsync_end */
+    1056,	800,		    1056,		840,		    968,
+    /*	vtotal,	vblank_start,	vblank_end,	vsync_start,	vsync_end */
+    628,	600,		    628,		601,		    605,
+    /*	pll_m,	pll_n,			pll_p */
+    240,	30,			2
+  },
+
+  {
+    GBE_VT_800_600_75,
+    /*	flags,	width,		    height,		fields_sec,	    cfreq */
+    0,	    800,		    600,		75000,		    50000,
+    /*	htotal,	hblank_start,	hblank_end,	hsync_start,	hsync_end */
+    1056,	800,		    1056,		816,		    896,
+    /*	vtotal,	vblank_start,	vblank_end,	vsync_start,	vsync_end */
+    625,	600,		    625,		601,		    604,
+    /*	pll_m,	pll_n,		    pll_p */
+    150,	 30,		        1
+  },
+
+  {
+    GBE_VT_1024_768_60,
+    /*	flags,	width,			height,		fields_sec,		cfreq */
+    0,	    1024,			768,		58663,			63548,
+    /*	htotal,	hblank_start,	hblank_end,	hsync_start,	hsync_end */
+    1344,	1024,		    1344,		1048,		    1184,
+    /*	vtotal,	vblank_start,	vblank_end,	vsync_start,	vsync_end */
+    806,	768,		    806,		771,		    777,
+    /*	pll_m,	pll_n,			pll_p */
+    197,	 31,			1
+  },
+
+  {
+    GBE_VT_1024_768_75,
+    /*	flags,	width,			height,		fields_sec,		cfreq */
+    0,	    1024,			768,		75029,			78750,
+    /*	htotal,	hblank_start,	hblank_end,	hsync_start,	hsync_end */
+    1312,	1024,		    1312,		1040,		    1136,
+    /*	vtotal,	vblank_start,	vblank_end,	vsync_start,	vsync_end */
+    800,	768,		    800,		769,		    772,
+    /*	pll_m,	pll_n,			pll_p */
+    252,	 32,			1
+  },
+
+  {
+    GBE_VT_1024_768_85,
+    /*	flags,	width,			height,		fields_sec,		cfreq */
+    0,	    1024,			768,		84997,			94500,
+    /*	htotal,	hblank_start,	hblank_end,	hsync_start,	hsync_end */
+    1376,	1024,		    1376,		1072,		    1168,
+    /*	vtotal,	vblank_start,	vblank_end,	vsync_start,	vsync_end */
+    808,	768,		    808,		769,		    772,
+    /*	pll_m,	pll_n,			pll_p */
+    189,	 20,			1
+  },
+
+  { 
+    GBE_VT_1280_1024_50,
+    /*	flags,	width,			height,		fields_sec,		cfreq */
+    0,	    1280,			1024,		50000,			89544,
+    /*	htotal,	hblank_start,	hblank_end,	hsync_start,	hsync_end */
+    1680,	1280,		    1680,		1360,		    1480,
+    /*	vtotal,	vblank_start,	vblank_end,	vsync_start,	vsync_end */
+    1065,	1024,		    1065,		1027,		    1030,
+    /*	pll_m,	pll_n,			pll_p */
+    197,	  44,			0
+  },
+
+  {
+    GBE_VT_1280_1024_60,
+    /*	flags,	width,			height,		fields_sec,		cfreq */
+    0,	    1280,			1024,		59916,			107272,
+    /*	htotal,	hblank_start,	hblank_end,	hsync_start,	hsync_end */
+    1688,	1280,		    1688,		1328,		    1440,
+    /*	vtotal,	vblank_start,	vblank_end,	vsync_start,	vsync_end */
+    1066,	1024,		    1066,		1025,		    1028,
+    /*	pll_m,	pll_n,			pll_p */
+    177,       33,			0
+  },
+
+  {
+    GBE_VT_1280_1024_75,
+    /*	flags,	width,			height,		fields_sec,		cfreq */
+    0,	    1280,			1024,		75025,			135000,
+    /*	htotal,	hblank_start,	hblank_end,	hsync_start,	hsync_end */
+    1688,	1280,		    1688,		1296,		    1440,
+    /*	vtotal,	vblank_start,	vblank_end,	vsync_start,	vsync_end */
+    1066,	1024,		    1066,		1025,		    1028,
+    /*	pll_m,	pll_n,			pll_p */
+    216,	  32,			0
+  },
+
+  {
+    GBE_VT_1280_1024_85,
+    /*	flags,	width,		    height,		fields_sec,	    cfreq */
+    0,	    1280,		    1024,		85024,		    157500,
+    /*	htotal,	hblank_start,	hblank_end,	hsync_start,	hsync_end */
+    1728,	1280,		    1728,		1344,		    1504,
+    /*	vtotal,	vblank_start,	vblank_end,	vsync_start,	vsync_end */
+    1072,	1024,		    1072,		1025,		    1028,
+    /*	pll_m,	pll_n,		    pll_p */
+    63,	           8,		        0
+  },
+
+  {
+    GBE_VT_1600_1024_60,
+    /* flags,					width,          height,			fields_sec,     cfreq */
+    GBE_VOF_FLATPANEL,   1600,           1024,			60000,          162925,
+    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
+    1670,   1600,           1670,           1630,           1650,
+    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
+    1067,   1024,           1067,           1027,           1030,
+    /* pll_m,  pll_n,          pll_p */
+    224,      27,              0
+  },
+
+  {
+    GBE_VT_1600_1200_60,
+    /* flags,  width,          height,         fields_sec,     cfreq */
+    0,      1600,           1200,           59940,          162000,
+    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
+    2160,   1600,           2160,           1644,           1856,
+    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
+    1250,   1200,           1250,           1201,           1204,
+    /* pll_m,  pll_n,          pll_p */
+     81,      10,             0
+  },
+
+  {
+    GBE_VT_1600_1200_75,
+    /* flags,  width,          height,         fields_sec,     cfreq */
+    0,      1600,           1200,           75000,          202500,
+    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
+    2160,   1600,           2160,           1644,           1856,
+    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
+    1250,   1200,           1250,           1201,           1204,
+    /* pll_m,  pll_n,          pll_p */
+     81,       8,              0
+  },
+
+  {
+    GBE_VT_1920_1080_60,
+    /* flags,  width,          height,         fields_sec,     cfreq */
+    0,      1920,           1080,           60060,          160000,
+    /* htotal, hblank_start,   hblank_end,     hsync_start,    hsync_end */
+    2368,   1920,           2368,           1952,           2096,
+    /* vtotal, vblank_start,   vblank_end,     vsync_start,    vsync_end */
+    1125,   1080,           1125,           1083,           1086,
+    /* pll_m,  pll_n,          pll_p */
+    8,      1,              0
+  },
+};
+
+#define GBE_VT_SIZE  (sizeof(gbeVTimings)/sizeof(gbeVTimings[0]))
+#endif // INCLUDE_TIMING_TABLE_DATA
+
+#endif // ! __SGIO2FB_H__
 
diff -Naur /share/linux.cvs/arch/mips64/mm/loadmmu.c linux.patched/arch/mips64/mm/loadmmu.c
--- /share/linux.cvs/arch/mips64/mm/loadmmu.c	Sun Mar  3 19:50:39 2002
+++ linux.patched/arch/mips64/mm/loadmmu.c	Thu May 16 23:12:21 2002
@@ -30,11 +30,14 @@
 void (*_flush_cache_page)(struct vm_area_struct *vma, unsigned long page);
 void (*_flush_page_to_ram)(struct page * page);
 
+void (*_flush_icache_range)(unsigned long start, unsigned long end);
+void (*_flush_icache_page)(struct vm_area_struct *vma, struct page *page);
+void (*_flush_icache_all)(void);
+
 /* MIPS specific cache operations */
 void (*_flush_cache_sigtramp)(unsigned long addr);
 void (*_flush_cache_l2)(void);
 void (*_flush_cache_l1)(void);
-
 
 /* DMA cache operations. */
 void (*_dma_cache_wback_inv)(unsigned long start, unsigned long size);
diff -Naur /share/linux.cvs/arch/mips64/mm/r4xx0.c linux.patched/arch/mips64/mm/r4xx0.c
--- /share/linux.cvs/arch/mips64/mm/r4xx0.c	Sun May  5 15:03:17 2002
+++ linux.patched/arch/mips64/mm/r4xx0.c	Thu May 16 23:05:53 2002
@@ -1621,6 +1621,34 @@
 	blast_dcache32_page((unsigned long)page_address(page));
 }
 
+static void
+r4k_flush_icache_range(unsigned long start, unsigned long end)
+{
+	flush_cache_all();
+}
+
+static void
+r4k_flush_icache_page_s(struct vm_area_struct *vma, struct page *page)
+{
+	/*
+	 * We did an scache flush therefore PI is already clean.
+	 */
+}
+
+/*
+ * Ok, this seriously sucks.  We use them to flush a user page but don't
+ * know the virtual address, so we have to blast away the whole icache
+ * which is significantly more expensive than the real thing.
+ */
+static void
+r4k_flush_icache_page_p(struct vm_area_struct *vma, struct page *page)
+{
+	if (!(vma->vm_flags & VM_EXEC))
+		return;
+
+	flush_cache_all();
+}
+
 /*
  * Writeback and invalidate the primary cache dcache before DMA.
  *
@@ -2119,7 +2147,7 @@
 		_flush_page_to_ram = r4k_flush_page_to_ram_d32;
 		break;
 	}
-
+	_flush_icache_page = r4k_flush_icache_page_p;
 	_dma_cache_wback_inv = r4k_dma_cache_wback_inv_pc;
 	_dma_cache_wback = r4k_dma_cache_wback;
 	_dma_cache_inv = r4k_dma_cache_inv_pc;
@@ -2201,6 +2229,7 @@
 		_copy_page = r4k_copy_page_s128;
 		break;
 	}
+	_flush_icache_page = r4k_flush_icache_page_s;
 	_dma_cache_wback_inv = r4k_dma_cache_wback_inv_sc;
 	_dma_cache_wback = r4k_dma_cache_wback;
 	_dma_cache_inv = r4k_dma_cache_inv_sc;
@@ -2253,6 +2282,7 @@
 	if ((read_32bit_cp0_register(CP0_PRID) & 0xfff0) == 0x2020) {
 		_flush_cache_sigtramp = r4600v20k_flush_cache_sigtramp;
 	}
+	_flush_icache_range = r4k_flush_icache_range;	/* Ouch */
 
 	_flush_cache_l2 = r4k_flush_cache_l2;
 
diff -Naur /share/linux.cvs/include/asm-mips64/pgtable.h linux.patched/include/asm-mips64/pgtable.h
--- /share/linux.cvs/include/asm-mips64/pgtable.h	Sun May  5 15:03:39 2002
+++ linux.patched/include/asm-mips64/pgtable.h	Thu May 16 23:01:46 2002
@@ -60,12 +60,22 @@
 
 #else
 
+extern void (*_flush_icache_all)(void);
+extern void (*_flush_icache_range)(unsigned long start, unsigned long end);
+extern void (*_flush_icache_page)(struct vm_area_struct *vma, struct page *page);
+
 #define flush_cache_mm(mm)		_flush_cache_mm(mm)
 #define flush_cache_range(mm,start,end)	_flush_cache_range(mm,start,end)
 #define flush_cache_page(vma,page)	_flush_cache_page(vma, page)
 #define flush_page_to_ram(page)		_flush_page_to_ram(page)
 #define flush_icache_range(start, end)	_flush_icache_range(start, end)
 #define flush_icache_page(vma, page)	_flush_icache_page(vma, page)
+#ifdef CONFIG_VTAG_ICACHE
+#define flush_icache_all()		_flush_icache_all()
+#else
+#define flush_icache_all()		do { } while(0)
+#endif
+
 
 #endif /* !CONFIG_CPU_R10000 */