Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/drivers/video/68328fb.c b/drivers/video/68328fb.c
new file mode 100644
index 0000000..6a3cfbd
--- /dev/null
+++ b/drivers/video/68328fb.c
@@ -0,0 +1,506 @@
+/*
+ *  linux/drivers/video/68328fb.c -- Low level implementation of the
+ *                                   mc68x328 LCD frame buffer device
+ *
+ *	Copyright (C) 2003 Georges Menie
+ *
+ *  This driver assumes an already configured controller (e.g. from config.c)
+ *  Keep the code clean of board specific initialization.
+ *
+ *  This code has not been tested with colors, colormap management functions
+ *  are minimal (no colormap data written to the 68328 registers...)
+ *
+ *  initial version of this driver:
+ *    Copyright (C) 1998,1999 Kenneth Albanowski <kjahds@kjahds.com>,
+ *                            The Silver Hammer Group, Ltd.
+ *
+ *  this version is based on :
+ *
+ *  linux/drivers/video/vfb.c -- Virtual frame buffer device
+ *
+ *      Copyright (C) 2002 James Simmons
+ *
+ *	Copyright (C) 1997 Geert Uytterhoeven
+ *
+ *  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/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>
+
+#if defined(CONFIG_M68VZ328)
+#include <asm/MC68VZ328.h>
+#elif defined(CONFIG_M68EZ328)
+#include <asm/MC68EZ328.h>
+#elif defined(CONFIG_M68328)
+#include <asm/MC68328.h>
+#else
+#error wrong architecture for the MC68x328 frame buffer device
+#endif
+
+#if defined(CONFIG_FB_68328_INVERT)
+#define MC68X328FB_MONO_VISUAL FB_VISUAL_MONO01
+#else
+#define MC68X328FB_MONO_VISUAL FB_VISUAL_MONO10
+#endif
+
+static u_long videomemory;
+static u_long videomemorysize;
+
+static struct fb_info fb_info;
+static u32 mc68x328fb_pseudo_palette[17];
+
+static struct fb_var_screeninfo mc68x328fb_default __initdata = {
+	.red =		{ 0, 8, 0 },
+      	.green =	{ 0, 8, 0 },
+      	.blue =		{ 0, 8, 0 },
+      	.activate =	FB_ACTIVATE_TEST,
+      	.height =	-1,
+      	.width =	-1,
+      	.pixclock =	20000,
+      	.left_margin =	64,
+      	.right_margin =	64,
+      	.upper_margin =	32,
+      	.lower_margin =	32,
+      	.hsync_len =	64,
+      	.vsync_len =	2,
+      	.vmode =	FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_fix_screeninfo mc68x328fb_fix __initdata = {
+	.id =		"68328fb",
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.xpanstep =	1,
+	.ypanstep =	1,
+	.ywrapstep =	1,
+	.accel =	FB_ACCEL_NONE,
+};
+
+    /*
+     *  Interface used by the world
+     */
+int mc68x328fb_init(void);
+int mc68x328fb_setup(char *);
+
+static int mc68x328fb_check_var(struct fb_var_screeninfo *var,
+			 struct fb_info *info);
+static int mc68x328fb_set_par(struct fb_info *info);
+static int mc68x328fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			 u_int transp, struct fb_info *info);
+static int mc68x328fb_pan_display(struct fb_var_screeninfo *var,
+			   struct fb_info *info);
+static int mc68x328fb_mmap(struct fb_info *info, struct file *file,
+		    struct vm_area_struct *vma);
+
+static struct fb_ops mc68x328fb_ops = {
+	.fb_check_var	= mc68x328fb_check_var,
+	.fb_set_par	= mc68x328fb_set_par,
+	.fb_setcolreg	= mc68x328fb_setcolreg,
+	.fb_pan_display	= mc68x328fb_pan_display,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+	.fb_mmap	= mc68x328fb_mmap,
+};
+
+    /*
+     *  Internal routines
+     */
+
+static u_long get_line_length(int xres_virtual, int bpp)
+{
+	u_long length;
+
+	length = xres_virtual * bpp;
+	length = (length + 31) & ~31;
+	length >>= 3;
+	return (length);
+}
+
+    /*
+     *  Setting the video mode has been split into two parts.
+     *  First part, xxxfb_check_var, must not write anything
+     *  to hardware, it should only verify and adjust var.
+     *  This means it doesn't alter par but it does use hardware
+     *  data from it to check this var. 
+     */
+
+static int mc68x328fb_check_var(struct fb_var_screeninfo *var,
+			 struct fb_info *info)
+{
+	u_long line_length;
+
+	/*
+	 *  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 = info->var.xoffset;
+		var->yoffset = info->var.yoffset;
+	}
+
+	/*
+	 *  Some very basic checks
+	 */
+	if (!var->xres)
+		var->xres = 1;
+	if (!var->yres)
+		var->yres = 1;
+	if (var->xres > var->xres_virtual)
+		var->xres_virtual = var->xres;
+	if (var->yres > var->yres_virtual)
+		var->yres_virtual = var->yres;
+	if (var->bits_per_pixel <= 1)
+		var->bits_per_pixel = 1;
+	else 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 <= 24)
+		var->bits_per_pixel = 24;
+	else if (var->bits_per_pixel <= 32)
+		var->bits_per_pixel = 32;
+	else
+		return -EINVAL;
+
+	if (var->xres_virtual < var->xoffset + var->xres)
+		var->xres_virtual = var->xoffset + var->xres;
+	if (var->yres_virtual < var->yoffset + var->yres)
+		var->yres_virtual = var->yoffset + var->yres;
+
+	/*
+	 *  Memory limit
+	 */
+	line_length =
+	    get_line_length(var->xres_virtual, var->bits_per_pixel);
+	if (line_length * var->yres_virtual > videomemorysize)
+		return -ENOMEM;
+
+	/*
+	 * Now that we checked it we alter var. The reason being is that the video
+	 * mode passed in might not work but slight changes to it might make it 
+	 * work. This way we let the user know what is acceptable.
+	 */
+	switch (var->bits_per_pixel) {
+	case 1:
+		var->red.offset = 0;
+		var->red.length = 1;
+		var->green.offset = 0;
+		var->green.length = 1;
+		var->blue.offset = 0;
+		var->blue.length = 1;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		break;
+	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 */
+		if (var->transp.length) {
+			var->red.offset = 0;
+			var->red.length = 5;
+			var->green.offset = 5;
+			var->green.length = 5;
+			var->blue.offset = 10;
+			var->blue.length = 5;
+			var->transp.offset = 15;
+			var->transp.length = 1;
+		} else {	/* RGB 565 */
+			var->red.offset = 0;
+			var->red.length = 5;
+			var->green.offset = 5;
+			var->green.length = 6;
+			var->blue.offset = 11;
+			var->blue.length = 5;
+			var->transp.offset = 0;
+			var->transp.length = 0;
+		}
+		break;
+	case 24:		/* RGB 888 */
+		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 = 0;
+		var->transp.length = 0;
+		break;
+	case 32:		/* RGBA 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;
+
+	return 0;
+}
+
+/* This routine actually sets the video mode. It's in here where we
+ * the hardware state info->par and fix which can be affected by the 
+ * change in par. For this driver it doesn't do much. 
+ */
+static int mc68x328fb_set_par(struct fb_info *info)
+{
+	info->fix.line_length = get_line_length(info->var.xres_virtual,
+						info->var.bits_per_pixel);
+	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 mc68x328fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			 u_int transp, struct fb_info *info)
+{
+	if (regno >= 256)	/* no. of hw registers */
+		return 1;
+	/*
+	 * Program hardware... do anything you want with transp
+	 */
+
+	/* grayscale works only partially under directcolor */
+	if (info->var.grayscale) {
+		/* grayscale = 0.30*R + 0.59*G + 0.11*B */
+		red = green = blue =
+		    (red * 77 + green * 151 + blue * 28) >> 8;
+	}
+
+	/* Directcolor:
+	 *   var->{color}.offset contains start of bitfield
+	 *   var->{color}.length contains length of bitfield
+	 *   {hardwarespecific} contains width of RAMDAC
+	 *   cmap[X] is programmed to (X << red.offset) | (X << green.offset) | (X << blue.offset)
+	 *   RAMDAC[X] is programmed to (red, green, blue)
+	 * 
+	 * Pseudocolor:
+	 *    uses offset = 0 && length = RAMDAC register width.
+	 *    var->{color}.offset is 0
+	 *    var->{color}.length contains widht of DAC
+	 *    cmap is not used
+	 *    RAMDAC[X] is programmed to (red, green, blue)
+	 * Truecolor:
+	 *    does not use DAC. Usually 3 are present.
+	 *    var->{color}.offset contains start of bitfield
+	 *    var->{color}.length contains length of bitfield
+	 *    cmap is programmed to (red << red.offset) | (green << green.offset) |
+	 *                      (blue << blue.offset) | (transp << transp.offset)
+	 *    RAMDAC does not exist
+	 */
+#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+	switch (info->fix.visual) {
+	case FB_VISUAL_TRUECOLOR:
+	case FB_VISUAL_PSEUDOCOLOR:
+		red = CNVT_TOHW(red, info->var.red.length);
+		green = CNVT_TOHW(green, info->var.green.length);
+		blue = CNVT_TOHW(blue, info->var.blue.length);
+		transp = CNVT_TOHW(transp, info->var.transp.length);
+		break;
+	case FB_VISUAL_DIRECTCOLOR:
+		red = CNVT_TOHW(red, 8);	/* expect 8 bit DAC */
+		green = CNVT_TOHW(green, 8);
+		blue = CNVT_TOHW(blue, 8);
+		/* hey, there is bug in transp handling... */
+		transp = CNVT_TOHW(transp, 8);
+		break;
+	}
+#undef CNVT_TOHW
+	/* Truecolor has hardware independent palette */
+	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+		u32 v;
+
+		if (regno >= 16)
+			return 1;
+
+		v = (red << info->var.red.offset) |
+		    (green << info->var.green.offset) |
+		    (blue << info->var.blue.offset) |
+		    (transp << info->var.transp.offset);
+		switch (info->var.bits_per_pixel) {
+		case 8:
+			break;
+		case 16:
+			((u32 *) (info->pseudo_palette))[regno] = v;
+			break;
+		case 24:
+		case 32:
+			((u32 *) (info->pseudo_palette))[regno] = v;
+			break;
+		}
+		return 0;
+	}
+	return 0;
+}
+
+    /*
+     *  Pan or Wrap the Display
+     *
+     *  This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
+     */
+
+static int mc68x328fb_pan_display(struct fb_var_screeninfo *var,
+			   struct fb_info *info)
+{
+	if (var->vmode & FB_VMODE_YWRAP) {
+		if (var->yoffset < 0
+		    || var->yoffset >= info->var.yres_virtual
+		    || var->xoffset)
+			return -EINVAL;
+	} else {
+		if (var->xoffset + var->xres > info->var.xres_virtual ||
+		    var->yoffset + var->yres > info->var.yres_virtual)
+			return -EINVAL;
+	}
+	info->var.xoffset = var->xoffset;
+	info->var.yoffset = var->yoffset;
+	if (var->vmode & FB_VMODE_YWRAP)
+		info->var.vmode |= FB_VMODE_YWRAP;
+	else
+		info->var.vmode &= ~FB_VMODE_YWRAP;
+	return 0;
+}
+
+    /*
+     *  Most drivers don't need their own mmap function 
+     */
+
+static int mc68x328fb_mmap(struct fb_info *info, struct file *file,
+		    struct vm_area_struct *vma)
+{
+#ifndef MMU
+	/* this is uClinux (no MMU) specific code */
+
+	vma->vm_flags |= VM_RESERVED;
+	vma->vm_start = videomemory;
+
+	return 0;
+#else
+	return -EINVAL;
+#endif
+}
+
+int __init mc68x328fb_setup(char *options)
+{
+#if 0
+	char *this_opt;
+#endif
+
+	if (!options || !*options)
+		return 1;
+#if 0
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt)
+			continue;
+		if (!strncmp(this_opt, "disable", 7))
+			mc68x328fb_enable = 0;
+	}
+#endif
+	return 1;
+}
+
+    /*
+     *  Initialisation
+     */
+
+int __init mc68x328fb_init(void)
+{
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("68328fb", &option))
+		return -ENODEV;
+	mc68x328fb_setup(option);
+#endif
+	/*
+	 *  initialize the default mode from the LCD controller registers
+	 */
+	mc68x328fb_default.xres = LXMAX;
+	mc68x328fb_default.yres = LYMAX+1;
+	mc68x328fb_default.xres_virtual = mc68x328fb_default.xres;
+	mc68x328fb_default.yres_virtual = mc68x328fb_default.yres;
+	mc68x328fb_default.bits_per_pixel = 1 + (LPICF & 0x01);
+	videomemory = LSSA;
+	videomemorysize = (mc68x328fb_default.xres_virtual+7) / 8 *
+		mc68x328fb_default.yres_virtual * mc68x328fb_default.bits_per_pixel;
+
+	fb_info.screen_base = (void *)videomemory;
+	fb_info.fbops = &mc68x328fb_ops;
+	fb_info.var = mc68x328fb_default;
+	fb_info.fix = mc68x328fb_fix;
+	fb_info.fix.smem_start = videomemory;
+	fb_info.fix.smem_len = videomemorysize;
+	fb_info.fix.line_length =
+		get_line_length(mc68x328fb_default.xres_virtual, mc68x328fb_default.bits_per_pixel);
+	fb_info.fix.visual = (mc68x328fb_default.bits_per_pixel) == 1 ?
+		MC68X328FB_MONO_VISUAL : FB_VISUAL_PSEUDOCOLOR;
+	if (fb_info.var.bits_per_pixel == 1) {
+		fb_info.var.red.length = fb_info.var.green.length = fb_info.var.blue.length = 1;
+		fb_info.var.red.offset = fb_info.var.green.offset = fb_info.var.blue.offset = 0;
+	}
+	fb_info.pseudo_palette = &mc68x328fb_pseudo_palette;
+	fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+
+	fb_alloc_cmap(&fb_info.cmap, 256, 0);
+
+	if (register_framebuffer(&fb_info) < 0) {
+		return -EINVAL;
+	}
+
+	printk(KERN_INFO
+		"fb%d: %s frame buffer device\n", fb_info.node,	fb_info.fix.id);
+	printk(KERN_INFO
+		"fb%d: %dx%dx%d at 0x%08lx\n", fb_info.node,
+		mc68x328fb_default.xres_virtual, mc68x328fb_default.yres_virtual,
+		1 << mc68x328fb_default.bits_per_pixel, videomemory);
+
+	return 0;
+}
+
+module_init(mc68x328fb_init);
+
+#ifdef MODULE
+
+static void __exit mc68x328fb_cleanup(void)
+{
+	unregister_framebuffer(&fb_info);
+}
+
+module_exit(mc68x328fb_cleanup);
+
+MODULE_LICENSE("GPL");
+#endif				/* MODULE */
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
new file mode 100644
index 0000000..2a1c596
--- /dev/null
+++ b/drivers/video/Kconfig
@@ -0,0 +1,1497 @@
+#
+# Video configuration
+#
+
+menu "Graphics support"
+
+config FB
+	tristate "Support for frame buffer devices"
+	---help---
+	  The frame buffer device provides an abstraction for the graphics
+	  hardware. It represents the frame buffer of some video hardware and
+	  allows application software to access the graphics hardware through
+	  a well-defined interface, so the software doesn't need to know
+	  anything about the low-level (hardware register) stuff.
+
+	  Frame buffer devices work identically across the different
+	  architectures supported by Linux and make the implementation of
+	  application programs easier and more portable; at this point, an X
+	  server exists which uses the frame buffer device exclusively.
+	  On several non-X86 architectures, the frame buffer device is the
+	  only way to use the graphics hardware.
+
+	  The device is accessed through special device nodes, usually located
+	  in the /dev directory, i.e. /dev/fb*.
+
+	  You need an utility program called fbset to make full use of frame
+	  buffer devices. Please read <file:Documentation/fb/framebuffer.txt>
+	  and the Framebuffer-HOWTO at
+	  <http://www.tahallah.demon.co.uk/programming/prog.html> for more
+	  information.
+
+	  Say Y here and to the driver for your graphics board below if you
+	  are compiling a kernel for a non-x86 architecture.
+
+	  If you are compiling for the x86 architecture, you can say Y if you
+	  want to play with it, but it is not essential. Please note that
+	  running graphical applications that directly touch the hardware
+	  (e.g. an accelerated X server) and that are not frame buffer
+	  device-aware may cause unexpected results. If unsure, say N.
+
+config FB_CFB_FILLRECT
+	tristate
+	depends on FB
+	default n
+	---help---
+	  Include the cfb_fillrect function for generic software rectangle
+	  filling. This is used by drivers that don't provide their own
+	  (accelerated) version.
+
+config FB_CFB_COPYAREA
+	tristate
+	depends on FB
+	default n
+	---help---
+	  Include the cfb_copyarea function for generic software area copying.
+	  This is used by drivers that don't provide their own (accelerated)
+	  version.
+
+config FB_CFB_IMAGEBLIT
+	tristate
+	depends on FB
+	default n
+	---help---
+	  Include the cfb_imageblit function for generic software image
+	  blitting. This is used by drivers that don't provide their own
+	  (accelerated) version.
+
+config FB_SOFT_CURSOR
+	tristate
+	depends on FB
+	default n
+	---help---
+	  Include the soft_cursor function for generic software cursor support.
+	  This is used by drivers that don't provide their own (accelerated)
+	  version.
+
+config FB_MACMODES
+       tristate
+       depends on FB
+       default n
+
+config FB_MODE_HELPERS
+        bool "Enable Video Mode Handling Helpers"
+        depends on FB
+	default n
+	---help---
+	  This enables functions for handling video modes using the
+	  Generalized Timing Formula and the EDID parser. A few drivers rely
+          on this feature such as the radeonfb, rivafb, and the i810fb. If
+	  your driver does not take advantage of this feature, choosing Y will
+	  just increase the kernel size by about 5K.
+
+config FB_TILEBLITTING
+       bool "Enable Tile Blitting Support"
+       depends on FB
+       default n
+       ---help---
+         This enables tile blitting.  Tile blitting is a drawing technique
+	 where the screen is divided into rectangular sections (tiles), whereas
+	 the standard blitting divides the screen into pixels. Because the
+	 default drawing element is a tile, drawing functions will be passed
+	 parameters in terms of number of tiles instead of number of pixels.
+	 For example, to draw a single character, instead of using bitmaps,
+	 an index to an array of bitmaps will be used.  To clear or move a
+	 rectangular section of a screen, the rectangle will be described in
+	 terms of number of tiles in the x- and y-axis.
+
+	 This is particularly important to one driver, matroxfb.  If
+	 unsure, say N.
+
+config FB_CIRRUS
+	tristate "Cirrus Logic support"
+	depends on FB && (ZORRO || PCI)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	---help---
+	  This enables support for Cirrus Logic GD542x/543x based boards on
+	  Amiga: SD64, Piccolo, Picasso II/II+, Picasso IV, or EGS Spectrum.
+
+	  If you have a PCI-based system, this enables support for these
+	  chips: GD-543x, GD-544x, GD-5480.
+
+	  Please read the file <file:Documentation/fb/cirrusfb.txt>.
+
+	  Say N unless you have such a graphics board or plan to get one
+	  before you next recompile the kernel.
+
+config FB_PM2
+	tristate "Permedia2 support"
+	depends on FB && ((AMIGA && BROKEN) || PCI)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This is the frame buffer device driver for the Permedia2 AGP frame
+	  buffer card from ASK, aka `Graphic Blaster Exxtreme'.  There is a
+	  product page at
+	  <http://www.ask.com.hk/product/Permedia%202/permedia2.htm>.
+
+config FB_PM2_FIFO_DISCONNECT
+	bool "enable FIFO disconnect feature"
+	depends on FB_PM2 && PCI
+	help
+	  Support the Permedia2 FIFO disconnect feature (see CONFIG_FB_PM2).
+
+config FB_ARMCLCD
+	tristate "ARM PrimeCell PL110 support"
+	depends on FB && ARM && ARM_AMBA
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This framebuffer device driver is for the ARM PrimeCell PL110
+	  Colour LCD controller.  ARM PrimeCells provide the building
+	  blocks for System on a Chip devices.
+
+	  If you want to compile this as a module (=code which can be
+	  inserted into and removed from the running kernel), say M
+	  here and read <file:Documentation/modules.txt>.  The module
+	  will be called amba-clcd.
+
+config FB_ACORN
+	bool "Acorn VIDC support"
+	depends on (FB = y) && ARM && (ARCH_ACORN || ARCH_CLPS7500)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This is the frame buffer device driver for the Acorn VIDC graphics
+	  hardware found in Acorn RISC PCs and other ARM-based machines.  If
+	  unsure, say N.
+
+config FB_CLPS711X
+	bool "CLPS711X LCD support"
+	depends on (FB = y) && ARM && ARCH_CLPS711X
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+
+config FB_SA1100
+	bool "SA-1100 LCD support"
+	depends on (FB = y) && ARM && ARCH_SA1100
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This is a framebuffer device for the SA-1100 LCD Controller.
+	  See <http://www.linux-fbdev.org/> for information on framebuffer
+	  devices.
+
+	  If you plan to use the LCD display with your SA-1100 system, say
+	  Y here.
+
+config FB_CYBER2000
+	tristate "CyberPro 2000/2010/5000 support"
+	depends on FB && PCI && (BROKEN || !SPARC64)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This enables support for the Integraphics CyberPro 20x0 and 5000
+	  VGA chips used in the Rebel.com Netwinder and other machines.
+	  Say Y if you have a NetWinder or a graphics card containing this
+	  device, otherwise say N.
+
+config FB_APOLLO
+	bool
+	depends on (FB = y) && APOLLO
+	default y
+	select FB_CFB_FILLRECT
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+
+config FB_Q40
+	bool
+	depends on (FB = y) && Q40
+	default y
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+
+config FB_AMIGA
+	tristate "Amiga native chipset support"
+	depends on FB && AMIGA
+	select FB_SOFT_CURSOR
+	help
+	  This is the frame buffer device driver for the builtin graphics
+	  chipset found in Amigas.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called amifb.
+
+config FB_AMIGA_OCS
+	bool "Amiga OCS chipset support"
+	depends on FB_AMIGA
+	help
+	  This enables support for the original Agnus and Denise video chips,
+	  found in the Amiga 1000 and most A500's and A2000's. If you intend
+	  to run Linux on any of these systems, say Y; otherwise say N.
+
+config FB_AMIGA_ECS
+	bool "Amiga ECS chipset support"
+	depends on FB_AMIGA
+	help
+	  This enables support for the Enhanced Chip Set, found in later
+	  A500's, later A2000's, the A600, the A3000, the A3000T and CDTV. If
+	  you intend to run Linux on any of these systems, say Y; otherwise
+	  say N.
+
+config FB_AMIGA_AGA
+	bool "Amiga AGA chipset support"
+	depends on FB_AMIGA
+	help
+	  This enables support for the Advanced Graphics Architecture (also
+	  known as the AGA or AA) Chip Set, found in the A1200, A4000, A4000T
+	  and CD32. If you intend to run Linux on any of these systems, say Y;
+	  otherwise say N.
+
+config FB_CYBER
+	tristate "Amiga CyberVision 64 support"
+	depends on FB && ZORRO && BROKEN
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This enables support for the Cybervision 64 graphics card from
+	  Phase5. Please note that its use is not all that intuitive (i.e. if
+	  you have any questions, be sure to ask!). Say N unless you have a
+	  Cybervision 64 or plan to get one before you next recompile the
+	  kernel. Please note that this driver DOES NOT support the
+	  Cybervision 64/3D card, as they use incompatible video chips.
+
+config FB_VIRGE
+	bool "Amiga CyberVision 64/3D support "
+	depends on (FB = y) && ZORRO && BROKEN
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This enables support for the Cybervision 64/3D graphics card from
+	  Phase5. Please note that its use is not all that intuitive (i.e. if
+	  you have any questions, be sure to ask!). Say N unless you have a
+	  Cybervision 64/3D or plan to get one before you next recompile the
+	  kernel. Please note that this driver DOES NOT support the older
+	  Cybervision 64 card, as they use incompatible video chips.
+
+config FB_RETINAZ3
+	tristate "Amiga Retina Z3 support"
+	depends on (FB = y) && ZORRO && BROKEN
+	help
+	  This enables support for the Retina Z3 graphics card. Say N unless
+	  you have a Retina Z3 or plan to get one before you next recompile
+	  the kernel.
+
+config FB_FM2
+	bool "Amiga FrameMaster II/Rainbow II support"
+	depends on (FB = y) && ZORRO
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This is the frame buffer device driver for the Amiga FrameMaster
+	  card from BSC (exhibited 1992 but not shipped as a CBM product).
+
+config FB_ATARI
+	bool "Atari native chipset support"
+	depends on (FB = y) && ATARI && BROKEN
+	help
+	  This is the frame buffer device driver for the builtin graphics
+	  chipset found in Ataris.
+
+config FB_OF
+	bool "Open Firmware frame buffer device support"
+	depends on (FB = y) && (PPC64 || PPC_OF)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	select FB_MACMODES
+	help
+	  Say Y if you want support with Open Firmware for your graphics
+	  board.
+
+config FB_CONTROL
+	bool "Apple \"control\" display support"
+	depends on (FB = y) && PPC_PMAC
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	select FB_MACMODES
+	help
+	  This driver supports a frame buffer for the graphics adapter in the
+	  Power Macintosh 7300 and others.
+
+config FB_PLATINUM
+	bool "Apple \"platinum\" display support"
+	depends on (FB = y) && PPC_PMAC
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	select FB_MACMODES
+	help
+	  This driver supports a frame buffer for the "platinum" graphics
+	  adapter in some Power Macintoshes.
+
+config FB_VALKYRIE
+	bool "Apple \"valkyrie\" display support"
+	depends on (FB = y) && (MAC || PPC_PMAC)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	select FB_MACMODES
+	help
+	  This driver supports a frame buffer for the "valkyrie" graphics
+	  adapter in some Power Macintoshes.
+
+config FB_CT65550
+	bool "Chips 65550 display support"
+	depends on (FB = y) && PPC
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This is the frame buffer device driver for the Chips & Technologies
+	  65550 graphics chip in PowerBooks.
+
+config FB_ASILIANT
+	bool "Chips 69000 display support"
+	depends on (FB = y) && PCI
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+
+config FB_IMSTT
+	bool "IMS Twin Turbo display support"
+	depends on (FB = y) && PCI
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	select FB_MACMODES if PPC
+	help
+	  The IMS Twin Turbo is a PCI-based frame buffer card bundled with
+	  many Macintosh and compatible computers.
+
+config FB_S3TRIO
+	bool "S3 Trio display support"
+	depends on (FB = y) && PPC && BROKEN
+	help
+	  If you have a S3 Trio say Y. Say N for S3 Virge.
+
+config FB_VGA16
+	tristate "VGA 16-color graphics support"
+	depends on FB && (X86 || PPC)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This is the frame buffer device driver for VGA 16 color graphic
+	  cards. Say Y if you have such a card.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called vga16fb.
+
+config FB_STI
+	tristate "HP STI frame buffer device support"
+	depends on FB && PARISC
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	default y
+	---help---
+	  STI refers to the HP "Standard Text Interface" which is a set of
+	  BIOS routines contained in a ROM chip in HP PA-RISC based machines.
+	  Enabling this option will implement the linux framebuffer device
+	  using calls to the STI BIOS routines for initialisation.
+	
+	  If you enable this option, you will get a planar framebuffer device
+	  /dev/fb which will work on the most common HP graphic cards of the
+	  NGLE family, including the artist chips (in the 7xx and Bxxx series),
+	  HCRX, HCRX24, CRX, CRX24 and VisEG series.
+
+	  It is safe to enable this option, so you should probably say "Y".
+
+config FB_MAC
+	bool "Generic Macintosh display support"
+	depends on (FB = y) && MAC
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	select FB_MACMODES
+
+#      bool '  Apple DAFB display support' CONFIG_FB_DAFB
+config FB_HP300
+	bool
+	depends on (FB = y) && HP300
+	select FB_CFB_FILLRECT
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	default y
+
+config FB_TGA
+	tristate "TGA framebuffer support"
+	depends on FB && ALPHA
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This is the frame buffer device driver for generic TGA graphic
+	  cards. Say Y if you have one of those.
+
+config FB_VESA
+	bool "VESA VGA graphics support"
+	depends on (FB = y) && (X86 || X86_64)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This is the frame buffer device driver for generic VESA 2.0
+	  compliant graphic cards. The older VESA 1.2 cards are not supported.
+	  You will get a boot time penguin logo at no additional cost. Please
+	  read <file:Documentation/fb/vesafb.txt>. If unsure, say Y.
+
+config VIDEO_SELECT
+	bool
+	depends on FB_VESA
+	default y
+
+config FB_HGA
+	tristate "Hercules mono graphics support"
+	depends on FB && X86
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  Say Y here if you have a Hercules mono graphics card.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called hgafb.
+
+	  As this card technology is 15 years old, most people will answer N
+	  here.
+
+config FB_HGA_ACCEL
+	bool "Hercules mono Acceleration functions (EXPERIMENTAL)"
+	depends on FB_HGA && EXPERIMENTAL
+	---help---
+	This will compile the Hercules mono graphics with
+	acceleration functions.
+
+
+config VIDEO_SELECT
+	bool
+	depends on (FB = y) && X86
+	default y
+
+config FB_SGIVW
+	tristate "SGI Visual Workstation framebuffer support"
+	depends on FB && X86_VISWS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  SGI Visual Workstation support for framebuffer graphics.
+
+config FB_GBE
+	bool "SGI Graphics Backend frame buffer support"
+	depends on (FB = y) && (SGI_IP32 || X86_VISWS)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+ 	help
+	  This is the frame buffer device driver for SGI Graphics Backend.
+	  This chip is used in SGI O2 and Visual Workstation 320/540.
+
+config FB_GBE_MEM
+	int "Video memory size in MB"
+	depends on FB_GBE
+	default 8
+	help
+	  This is the amount of memory reserved for the framebuffer,
+	  which can be any value between 1MB and 8MB.
+
+config BUS_I2C
+	bool
+	depends on (FB = y) && VISWS
+	default y
+
+config FB_SUN3
+	bool "Sun3 framebuffer support"
+	depends on (FB = y) && (SUN3 || SUN3X) && BROKEN
+
+config FB_BW2
+	bool "BWtwo support"
+	depends on (FB = y) && ((SPARC32 || SPARC64) && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This is the frame buffer device driver for the BWtwo frame buffer.
+
+config FB_CG3
+	bool "CGthree support"
+	depends on (FB = y) && ((SPARC32 || SPARC64) && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3)
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This is the frame buffer device driver for the CGthree frame buffer.
+
+config FB_CG6
+	bool "CGsix (GX,TurboGX) support"
+	depends on (FB = y) && ((SPARC32 || SPARC64) && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3)
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This is the frame buffer device driver for the CGsix (GX, TurboGX)
+	  frame buffer.
+
+config FB_PVR2
+	tristate "NEC PowerVR 2 display support"
+	depends on FB && SH_DREAMCAST
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	---help---
+	  Say Y here if you have a PowerVR 2 card in your box.  If you plan to
+	  run linux on your Dreamcast, you will have to say Y here.
+	  This driver may or may not work on other PowerVR 2 cards, but is
+	  totally untested.  Use at your own risk.  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pvr2fb.
+
+	  You can pass several parameters to the driver at boot time or at
+	  module load time.  The parameters look like "video=pvr2:XXX", where
+	  the meaning of XXX can be found at the end of the main source file
+	  (<file:drivers/video/pvr2fb.c>). Please see the file
+	  <file:Documentation/fb/pvr2fb.txt>.
+
+config FB_EPSON1355
+	bool "Epson 1355 framebuffer support"
+	depends on (FB = y) && (SUPERH || ARCH_CEIVA)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  Build in support for the SED1355 Epson Research Embedded RAMDAC
+	  LCD/CRT Controller (since redesignated as the S1D13505) as a
+	  framebuffer.  Product specs at
+	  <http://www.erd.epson.com/vdc/html/products.htm>.
+
+config FB_NVIDIA
+	tristate "nVidia Framebuffer Support"
+	depends on FB && PCI
+	select I2C_ALGOBIT if FB_NVIDIA_I2C
+	select I2C if FB_NVIDIA_I2C
+	select FB_MODE_HELPERS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This driver supports graphics boards with the nVidia chips, TNT
+	  and newer. For very old chipsets, such as the RIVA128, then use
+	  the rivafb.
+	  Say Y if you have such a graphics board.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called nvidiafb.
+
+config FB_NVIDIA_I2C
+       bool "Enable DDC Support"
+       depends on FB_NVIDIA && !PPC_OF
+       help
+	  This enables I2C support for nVidia Chipsets.  This is used
+	  only for getting EDID information from the attached display
+	  allowing for robust video mode handling and switching.
+
+	  Because fbdev-2.6 requires that drivers must be able to
+	  independently validate video mode parameters, you should say Y
+	  here.
+
+config FB_RIVA
+	tristate "nVidia Riva support"
+	depends on FB && PCI
+	select I2C_ALGOBIT if FB_RIVA_I2C
+	select I2C if FB_RIVA_I2C
+	select FB_MODE_HELPERS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This driver supports graphics boards with the nVidia Riva/Geforce
+	  chips.
+	  Say Y if you have such a graphics board.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called rivafb.
+
+config FB_RIVA_I2C
+       bool "Enable DDC Support"
+       depends on FB_RIVA
+       help
+	  This enables I2C support for nVidia Chipsets.  This is used
+	  only for getting EDID information from the attached display
+	  allowing for robust video mode handling and switching.
+
+	  Because fbdev-2.6 requires that drivers must be able to
+	  independently validate video mode parameters, you should say Y
+	  here.
+
+config FB_RIVA_DEBUG
+	bool "Lots of debug output from Riva(nVidia) driver"
+	depends on FB_RIVA
+	default n
+	help
+	  Say Y here if you want the Riva driver to output all sorts
+	  of debugging informations to provide to the maintainer when
+	  something goes wrong.
+
+config FB_I810
+	tristate "Intel 810/815 support (EXPERIMENTAL)"
+	depends on FB && EXPERIMENTAL && PCI && X86 && !X86_64
+	select AGP
+	select AGP_INTEL
+	select FB_MODE_HELPERS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This driver supports the on-board graphics built in to the Intel 810 
+          and 815 chipsets.  Say Y if you have and plan to use such a board.
+
+          To compile this driver as a module, choose M here: the
+	  module will be called i810fb.
+
+          For more information, please read 
+	  <file:Documentation/fb/intel810.txt>
+
+config FB_I810_GTF
+	bool "use VESA Generalized Timing Formula"
+	depends on FB_I810
+	help
+	  If you say Y, then the VESA standard, Generalized Timing Formula 
+          or GTF, will be used to calculate the required video timing values
+	  per video mode.  Since the GTF allows nondiscrete timings 
+          (nondiscrete being a range of values as opposed to discrete being a
+          set of values), you'll be able to use any combination of horizontal 
+	  and vertical resolutions, and vertical refresh rates without having
+	  to specify your own timing parameters.  This is especially useful
+	  to maximize the performance of an aging display, or if you just 
+          have a display with nonstandard dimensions. A VESA compliant 
+	  monitor is recommended, but can still work with non-compliant ones.
+	  If you need or want this, then select this option. The timings may 
+	  not be compliant with Intel's recommended values. Use at your own 
+	  risk.
+
+          If you say N, the driver will revert to discrete video timings 
+	  using a set recommended by Intel in their documentation.
+  
+          If unsure, say N.
+
+config FB_INTEL
+	tristate "Intel 830M/845G/852GM/855GM/865G support (EXPERIMENTAL)"
+	depends on FB && EXPERIMENTAL && PCI && X86 && !X86_64
+	select AGP
+	select AGP_INTEL
+	select FB_MODE_HELPERS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This driver supports the on-board graphics built in to the Intel
+          830M/845G/852GM/855GM/865G chipsets.
+          Say Y if you have and plan to use such a board.
+
+          To compile this driver as a module, choose M here: the
+	  module will be called intelfb.
+
+config FB_INTEL_DEBUG
+        bool "Intel driver Debug Messages"
+	depends on FB_INTEL
+	---help---
+	  Say Y here if you want the Intel driver to output all sorts
+	  of debugging informations to provide to the maintainer when
+	  something goes wrong.
+
+config FB_MATROX
+	tristate "Matrox acceleration"
+	depends on FB && PCI
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	select FB_TILEBLITTING
+	select FB_MACMODES if PPC_PMAC
+	---help---
+	  Say Y here if you have a Matrox Millennium, Matrox Millennium II,
+	  Matrox Mystique, Matrox Mystique 220, Matrox Productiva G100, Matrox
+	  Mystique G200, Matrox Millennium G200, Matrox Marvel G200 video,
+	  Matrox G400, G450 or G550 card in your box.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called matroxfb.
+
+	  You can pass several parameters to the driver at boot time or at
+	  module load time. The parameters look like "video=matrox:XXX", and
+	  are described in <file:Documentation/fb/matroxfb.txt>.
+
+config FB_MATROX_MILLENIUM
+	bool "Millennium I/II support"
+	depends on FB_MATROX
+	help
+	  Say Y here if you have a Matrox Millennium or Matrox Millennium II
+	  video card. If you select "Advanced lowlevel driver options" below,
+	  you should check 4 bpp packed pixel, 8 bpp packed pixel, 16 bpp
+	  packed pixel, 24 bpp packed pixel and 32 bpp packed pixel. You can
+	  also use font widths different from 8.
+
+config FB_MATROX_MYSTIQUE
+	bool "Mystique support"
+	depends on FB_MATROX
+	help
+	  Say Y here if you have a Matrox Mystique or Matrox Mystique 220
+	  video card. If you select "Advanced lowlevel driver options" below,
+	  you should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp
+	  packed pixel and 32 bpp packed pixel. You can also use font widths
+	  different from 8.
+
+config FB_MATROX_G
+	bool "G100/G200/G400/G450/G550 support"
+	depends on FB_MATROX
+	---help---
+	  Say Y here if you have a Matrox G100, G200, G400, G450 or G550 based
+	  video card. If you select "Advanced lowlevel driver options", you
+	  should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp packed
+	  pixel and 32 bpp packed pixel. You can also use font widths
+	  different from 8.
+
+	  If you need support for G400 secondary head, you must first say Y to
+	  "I2C support" in the character devices section, and then to
+	  "Matrox I2C support" and "G400 second head support" here in the
+	  framebuffer section. G450/G550 secondary head and digital output
+	  are supported without additional modules.
+
+	  The driver starts in monitor mode. You must use the matroxset tool 
+	  (available at <ftp://platan.vc.cvut.cz/pub/linux/matrox-latest/>) to 
+	  swap primary and secondary head outputs, or to change output mode.  
+	  Secondary head driver always start in 640x480 resolution and you 
+	  must use fbset to change it.
+
+	  Do not forget that second head supports only 16 and 32 bpp
+	  packed pixels, so it is a good idea to compile them into the kernel
+	  too. You can use only some font widths, as the driver uses generic
+	  painting procedures (the secondary head does not use acceleration
+	  engine).
+
+	  G450/G550 hardware can display TV picture only from secondary CRTC,
+	  and it performs no scaling, so picture must have 525 or 625 lines.
+
+config FB_MATROX_I2C
+	tristate "Matrox I2C support"
+	depends on FB_MATROX && I2C
+	select I2C_ALGOBIT
+	---help---
+	  This drivers creates I2C buses which are needed for accessing the
+	  DDC (I2C) bus present on all Matroxes, an I2C bus which
+	  interconnects Matrox optional devices, like MGA-TVO on G200 and
+	  G400, and the secondary head DDC bus, present on G400 only.
+
+	  You can say Y or M here if you want to experiment with monitor
+	  detection code. You must say Y or M here if you want to use either
+	  second head of G400 or MGA-TVO on G200 or G400.
+
+	  If you compile it as module, it will create a module named
+	  i2c-matroxfb.
+
+config FB_MATROX_MAVEN
+	tristate "G400 second head support"
+	depends on FB_MATROX_G && FB_MATROX_I2C
+	---help---
+	  WARNING !!! This support does not work with G450 !!!
+
+	  Say Y or M here if you want to use a secondary head (meaning two
+	  monitors in parallel) on G400 or MGA-TVO add-on on G200. Secondary
+	  head is not compatible with accelerated XFree 3.3.x SVGA servers -
+	  secondary head output is blanked while you are in X. With XFree
+	  3.9.17 preview you can use both heads if you use SVGA over fbdev or
+	  the fbdev driver on first head and the fbdev driver on second head.
+
+	  If you compile it as module, two modules are created,
+	  matroxfb_crtc2 and matroxfb_maven. Matroxfb_maven is needed for
+	  both G200 and G400, matroxfb_crtc2 is needed only by G400. You must
+	  also load i2c-matroxfb to get it to run.
+
+	  The driver starts in monitor mode and you must use the matroxset
+	  tool (available at
+	  <ftp://platan.vc.cvut.cz/pub/linux/matrox-latest/>) to switch it to
+	  PAL or NTSC or to swap primary and secondary head outputs.
+	  Secondary head driver also always start in 640x480 resolution, you
+	  must use fbset to change it.
+
+	  Also do not forget that second head supports only 16 and 32 bpp
+	  packed pixels, so it is a good idea to compile them into the kernel
+	  too.  You can use only some font widths, as the driver uses generic
+	  painting procedures (the secondary head does not use acceleration
+	  engine).
+
+config FB_MATROX_MULTIHEAD
+	bool "Multihead support"
+	depends on FB_MATROX
+	---help---
+	  Say Y here if you have more than one (supported) Matrox device in
+	  your computer and you want to use all of them for different monitors
+	  ("multihead"). If you have only one device, you should say N because
+	  the driver compiled with Y is larger and a bit slower, especially on
+	  ia32 (ix86).
+
+	  If you said M to "Matrox unified accelerated driver" and N here, you
+	  will still be able to use several Matrox devices simultaneously:
+	  insert several instances of the module matroxfb into the kernel
+	  with insmod, supplying the parameter "dev=N" where N is 0, 1, etc.
+	  for the different Matrox devices. This method is slightly faster but
+	  uses 40 KB of kernel memory per Matrox card.
+
+	  There is no need for enabling 'Matrox multihead support' if you have
+	  only one Matrox card in the box.
+
+config FB_RADEON_OLD
+	tristate "ATI Radeon display support (Old driver)"
+	depends on FB && PCI
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	select FB_MACMODES if PPC
+	help
+	  Choose this option if you want to use an ATI Radeon graphics card as
+	  a framebuffer device.  There are both PCI and AGP versions.  You
+	  don't need to choose this to run the Radeon in plain VGA mode.
+	  There is a product page at
+	  <http://www.ati.com/na/pages/products/pc/radeon32/index.html>.
+
+config FB_RADEON
+	tristate "ATI Radeon display support"
+	depends on FB && PCI
+	select I2C_ALGOBIT if FB_RADEON_I2C
+	select I2C if FB_RADEON_I2C
+	select FB_MODE_HELPERS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	select FB_MACMODES if PPC_OF
+	help
+	  Choose this option if you want to use an ATI Radeon graphics card as
+	  a framebuffer device.  There are both PCI and AGP versions.  You
+	  don't need to choose this to run the Radeon in plain VGA mode.
+
+	  If you say Y here and want DDC/I2C support you must first say Y to
+	  "I2C support" and "I2C bit-banging support" in the character devices
+	  section.
+
+	  If you say M here then "I2C support" and "I2C bit-banging support" 
+	  can be build either as modules or built-in.
+
+	  There is a product page at
+	  <http://www.ati.com/na/pages/products/pc/radeon32/index.html>.
+
+config FB_RADEON_I2C
+	bool "DDC/I2C for ATI Radeon support"
+	depends on FB_RADEON
+	default y
+	help
+	  Say Y here if you want DDC/I2C support for your Radeon board. 
+
+config FB_RADEON_DEBUG
+	bool "Lots of debug output from Radeon driver"
+	depends on FB_RADEON
+	default n
+	help
+	  Say Y here if you want the Radeon driver to output all sorts
+	  of debugging informations to provide to the maintainer when
+	  something goes wrong.
+
+config FB_ATY128
+	tristate "ATI Rage128 display support"
+	depends on FB && PCI
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	select FB_MACMODES if PPC_PMAC
+	help
+	  This driver supports graphics boards with the ATI Rage128 chips.
+	  Say Y if you have such a graphics board and read
+	  <file:Documentation/fb/aty128fb.txt>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called aty128fb.
+
+config FB_ATY
+	tristate "ATI Mach64 display support" if PCI || ATARI
+	depends on FB
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	select FB_MACMODES if PPC
+	help
+	  This driver supports graphics boards with the ATI Mach64 chips.
+	  Say Y if you have such a graphics board.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called atyfb.
+
+config FB_ATY_CT
+	bool "Mach64 CT/VT/GT/LT (incl. 3D RAGE) support"
+	depends on PCI && FB_ATY
+	default y if SPARC64 && FB_PCI
+	help
+	  Say Y here to support use of ATI's 64-bit Rage boards (or other
+	  boards based on the Mach64 CT, VT, GT, and LT chipsets) as a
+	  framebuffer device.  The ATI product support page for these boards
+	  is at <http://support.ati.com/products/pc/mach64/>.
+
+config FB_ATY_GENERIC_LCD
+	bool "Mach64 generic LCD support (EXPERIMENTAL)"
+	depends on FB_ATY_CT
+	help
+	  Say Y if you have a laptop with an ATI Rage LT PRO, Rage Mobility,
+	  Rage XC, or Rage XL chipset.
+
+config FB_ATY_XL_INIT
+	bool "Rage XL No-BIOS Init support"
+	depends on FB_ATY_CT
+	help
+	  Say Y here to support booting a Rage XL without BIOS support.
+
+config FB_ATY_GX
+	bool "Mach64 GX support" if PCI
+	depends on FB_ATY
+	default y if ATARI
+	help
+	  Say Y here to support use of the ATI Mach64 Graphics Expression
+	  board (or other boards based on the Mach64 GX chipset) as a
+	  framebuffer device.  The ATI product support page for these boards
+	  is at
+	  <http://support.ati.com/products/pc/mach64/graphics_xpression.html>.
+
+config FB_SAVAGE
+	tristate "S3 Savage support"
+	depends on FB && PCI && EXPERIMENTAL
+	select I2C_ALGOBIT if FB_SAVAGE_I2C
+	select I2C if FB_SAVAGE_I2C
+	select FB_MODE_HELPERS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This driver supports notebooks and computers with S3 Savage PCI/AGP
+	  chips.
+
+	  Say Y if you have such a graphics card.
+
+	  To compile this driver as a module, choose M here; the module
+	  will be called savagefb.
+
+config FB_SAVAGE_I2C
+       bool "Enable DDC2 Support"
+       depends on FB_SAVAGE
+       help
+	  This enables I2C support for S3 Savage Chipsets.  This is used
+	  only for getting EDID information from the attached display
+	  allowing for robust video mode handling and switching.
+
+	  Because fbdev-2.6 requires that drivers must be able to
+	  independently validate video mode parameters, you should say Y
+	  here.
+
+config FB_SAVAGE_ACCEL
+       bool "Enable Console Acceleration"
+       depends on FB_SAVAGE
+       default n
+       help
+          This option will compile in console acceleration support. If
+          the resulting framebuffer console has bothersome glitches, then
+          choose N here.
+
+config FB_SIS
+	tristate "SiS acceleration"
+	depends on FB && PCI
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This is the frame buffer device driver for the SiS 300, 315 and
+	  330 series VGA chipsets. Specs available at <http://www.sis.com>
+
+	  To compile this driver as a module, choose M here; the module
+	  will be called sisfb.
+
+config FB_SIS_300
+	bool "SiS 300 series support"
+	depends on FB_SIS
+	help
+	  Say Y here to support use of the SiS 300/305, 540, 630 and 730.
+
+config FB_SIS_315
+	bool "SiS 315/330 series support"
+	depends on FB_SIS
+	help
+	  Say Y here to support use of the SiS 315 and 330 series
+	  (315/H/PRO, 55x, 650, 651, 740, 330, 661, 741, 760).
+
+config FB_NEOMAGIC
+	tristate "NeoMagic display support"
+	depends on FB && PCI
+	select FB_MODE_HELPERS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This driver supports notebooks with NeoMagic PCI chips.
+	  Say Y if you have such a graphics card. 
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called neofb.
+
+config FB_KYRO
+	tristate "IMG Kyro support"
+	depends on FB && PCI
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  Say Y here if you have a STG4000 / Kyro / PowerVR 3 based
+	  graphics board.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called kyrofb.
+
+config FB_3DFX
+	tristate "3Dfx Banshee/Voodoo3 display support"
+	depends on FB && PCI
+	select FB_CFB_IMAGEBLIT
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_SOFT_CURSOR
+	help
+	  This driver supports graphics boards with the 3Dfx Banshee/Voodoo3
+	  chips. Say Y if you have such a graphics board.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tdfxfb.
+
+config FB_3DFX_ACCEL
+	bool "3Dfx Banshee/Voodoo3 Acceleration functions (EXPERIMENTAL)"
+	depends on FB_3DFX && EXPERIMENTAL
+	---help---
+	This will compile the 3Dfx Banshee/Voodoo3 frame buffer device
+	with acceleration functions.
+
+
+config FB_VOODOO1
+	tristate "3Dfx Voodoo Graphics (sst1) support"
+	depends on FB && PCI
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	---help---
+	  Say Y here if you have a 3Dfx Voodoo Graphics (Voodoo1/sst1) or 
+	  Voodoo2 (cvg) based graphics card.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called sstfb.
+
+	  WARNING: Do not use any application that uses the 3D engine
+	  (namely glide) while using this driver.
+	  Please read the <file:Documentation/fb/README-sstfb.txt> for supported
+	  options and other important info  support.
+
+config FB_TRIDENT
+	tristate "Trident support"
+	depends on FB && PCI
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	---help---
+	  This driver is supposed to support graphics boards with the
+	  Trident CyberXXXX/Image/CyberBlade chips mostly found in laptops
+	  but also on some motherboards. For more information, read
+	  <file:Documentation/fb/tridentfb.txt>
+
+	  Say Y if you have such a graphics board.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tridentfb.
+
+config FB_TRIDENT_ACCEL
+	bool "Trident Acceleration functions (EXPERIMENTAL)"
+	depends on FB_TRIDENT && EXPERIMENTAL
+	---help---
+	This will compile the Trident frame buffer device with
+	acceleration functions.
+
+
+config FB_PM3
+	tristate "Permedia3 support"
+	depends on FB && PCI && BROKEN
+	help
+	  This is the frame buffer device driver for the 3DLabs Permedia3
+	  chipset, used in Formac ProFormance III, 3DLabs Oxygen VX1 &
+	  similar boards, 3DLabs Permedia3 Create!, Appian Jeronimo 2000
+	  and maybe other boards.
+
+config FB_E1356
+	tristate "Epson SED1356 framebuffer support"
+	depends on FB && EXPERIMENTAL && PCI && MIPS
+
+config PB1000_CRT
+	bool "Use CRT on Pb1000 (J65)"
+	depends on MIPS_PB1000=y && FB_E1356
+
+config PB1000_NTSC
+	bool "Use Compsite NTSC on Pb1000 (J63)"
+	depends on MIPS_PB1000=y && FB_E1356
+
+config PB1000_TFT
+	bool "Use TFT Panel on Pb1000 (J64)"
+	depends on MIPS_PB1000=y && FB_E1356
+
+config PB1500_CRT
+	bool "Use CRT on Pb1500 " if MIPS_PB1500=y
+	depends on FB_E1356
+
+config PB1500_CRT
+	prompt "Use CRT on Pb1100 "
+	depends on FB_E1356 && MIPS_PB1100=y
+
+config PB1500_TFT
+	bool "Use TFT Panel on Pb1500 " if MIPS_PB1500=y
+	depends on FB_E1356
+
+config PB1500_TFT
+	prompt "Use TFT Panel on Pb1100 "
+	depends on FB_E1356 && MIPS_PB1100=y
+
+config FB_AU1100
+	bool "Au1100 LCD Driver"
+	depends on (FB = y) && EXPERIMENTAL && PCI && MIPS && MIPS_PB1100=y
+
+source "drivers/video/geode/Kconfig"
+
+config FB_SBUS
+	bool "SBUS and UPA framebuffers"
+	depends on (FB = y) && (SPARC32 || SPARC64)
+	help
+	  Say Y if you want support for SBUS or UPA based frame buffer device.
+
+config FB_FFB
+	bool "Creator/Creator3D/Elite3D support"
+	depends on FB_SBUS && SPARC64
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This is the frame buffer device driver for the Creator, Creator3D,
+	  and Elite3D graphics boards.
+
+config FB_TCX
+	bool "TCX (SS4/SS5 only) support"
+	depends on FB_SBUS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This is the frame buffer device driver for the TCX 24/8bit frame
+	  buffer.
+
+config FB_CG14
+	bool "CGfourteen (SX) support"
+	depends on FB_SBUS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This is the frame buffer device driver for the CGfourteen frame
+	  buffer on Desktop SPARCsystems with the SX graphics option.
+
+config FB_P9100
+	bool "P9100 (Sparcbook 3 only) support"
+	depends on FB_SBUS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This is the frame buffer device driver for the P9100 card
+	  supported on Sparcbook 3 machines.
+
+config FB_LEO
+	bool "Leo (ZX) support"
+	depends on FB_SBUS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This is the frame buffer device driver for the SBUS-based Sun ZX
+	  (leo) frame buffer cards.
+
+config FB_PCI
+	bool "PCI framebuffers"
+	depends on (FB = y) && PCI && (SPARC64 || SPARC32)
+
+config FB_IGA
+	bool "IGA 168x display support"
+	depends on SPARC32 && FB_PCI
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This is the framebuffer device for the INTERGRAPHICS 1680 and
+	  successor frame buffer cards.
+
+config FB_HIT
+	tristate "HD64461 Frame Buffer support"
+	depends on FB && HD64461
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  This is the frame buffer device driver for the Hitachi HD64461 LCD
+	  frame buffer card.
+
+config FB_PMAG_AA
+	bool "PMAG-AA TURBOchannel framebuffer support"
+	depends on (FB = y) && MACH_DECSTATION && TC
+ 	select FB_CFB_FILLRECT
+ 	select FB_CFB_COPYAREA
+ 	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  Support for the PMAG-AA TURBOchannel framebuffer card (1280x1024x1)
+	  used mainly in the MIPS-based DECstation series.
+
+config FB_PMAG_BA
+	bool "PMAG-BA TURBOchannel framebuffer support"
+	depends on (FB = y) && MACH_DECSTATION && TC
+ 	select FB_CFB_FILLRECT
+ 	select FB_CFB_COPYAREA
+ 	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  Support for the PMAG-BA TURBOchannel framebuffer card (1024x864x8)
+	  used mainly in the MIPS-based DECstation series.
+
+config FB_PMAGB_B
+	bool "PMAGB-B TURBOchannel framebuffer support"
+	depends on (FB = y) && MACH_DECSTATION && TC
+ 	select FB_CFB_FILLRECT
+ 	select FB_CFB_COPYAREA
+ 	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  Support for the PMAGB-B TURBOchannel framebuffer card used mainly
+	  in the MIPS-based DECstation series. The card is currently only
+	  supported in 1280x1024x8 mode.
+
+config FB_MAXINE
+	bool "Maxine (Personal DECstation) onboard framebuffer support"
+	depends on (FB = y) && MACH_DECSTATION && TC
+ 	select FB_CFB_FILLRECT
+ 	select FB_CFB_COPYAREA
+ 	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  Support for the onboard framebuffer (1024x768x8) in the Personal
+	  DECstation series (Personal DECstation 5000/20, /25, /33, /50,
+	  Codename "Maxine").
+
+config FB_TX3912
+	bool "TMPTX3912/PR31700 frame buffer support"
+	depends on (FB = y) && NINO
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  The TX3912 is a Toshiba RISC processor based on the MIPS 3900 core
+	  see <http://www.toshiba.com/taec/components/Generic/risc/tx3912.htm>.
+
+	  Say Y here to enable kernel support for the on-board framebuffer.
+
+config FB_G364
+	bool
+	depends on MIPS_MAGNUM_4000 || OLIVETTI_M700
+ 	select FB_CFB_FILLRECT
+ 	select FB_CFB_COPYAREA
+ 	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  The G364 driver is the framebuffer used in MIPS Magnum 4000 and
+	  Olivetti M700-10 systems.
+
+config FB_68328
+	bool "Motorola 68328 native frame buffer support"
+	depends on FB && (M68328 || M68EZ328 || M68VZ328)
+ 	select FB_CFB_FILLRECT
+ 	select FB_CFB_COPYAREA
+ 	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  Say Y here if you want to support the built-in frame buffer of
+	  the Motorola 68328 CPU family.
+
+config FB_PXA
+	tristate "PXA LCD framebuffer support"
+	depends on FB && ARCH_PXA
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	---help---
+	  Frame buffer driver for the built-in LCD controller in the Intel
+	  PXA2x0 processor.
+
+	  This driver is also available as a module ( = code which can be
+	  inserted and removed from the running kernel whenever you want). The
+	  module will be called vfb. If you want to compile it as a module,
+	  say M here and read <file:Documentation/modules.txt>.
+
+	  If unsure, say N.
+
+config FB_W100
+	tristate "W100 frame buffer support"
+	depends on FB && PXA_SHARPSL
+ 	select FB_CFB_FILLRECT
+ 	select FB_CFB_COPYAREA
+ 	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	---help---
+	  Frame buffer driver for the w100 as found on the Sharp SL-Cxx series.
+
+	  This driver is also available as a module ( = code which can be
+	  inserted and removed from the running kernel whenever you want). The
+	  module will be called vfb. If you want to compile it as a module,
+	  say M here and read <file:Documentation/modules.txt>.
+
+	  If unsure, say N.
+
+config FB_PXA_PARAMETERS
+	bool "PXA LCD command line parameters"
+	default n
+	depends on FB_PXA
+	---help---
+	  Enable the use of kernel command line or module parameters
+	  to configure the physical properties of the LCD panel when
+	  using the PXA LCD driver.
+
+	  This option allows you to override the panel parameters
+	  supplied by the platform in order to support multiple
+	  different models of flatpanel. If you will only be using a
+	  single model of flatpanel then you can safely leave this
+	  option disabled.
+
+	  <file:Documentation/fb/pxafb.txt> describes the available parameters.
+
+config FB_S1D13XXX
+	tristate "Epson S1D13XXX framebuffer support"
+	depends on FB
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	help
+	  Support for S1D13XXX framebuffer device family (currently only
+	  working with S1D13806). Product specs at
+	  <http://www.erd.epson.com/vdc/html/legacy_13xxx.htm>
+
+config FB_VIRTUAL
+	tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
+	depends on FB
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	---help---
+	  This is a `virtual' frame buffer device. It operates on a chunk of
+	  unswappable kernel memory instead of on the memory of a graphics
+	  board. This means you cannot see any output sent to this frame
+	  buffer device, while it does consume precious memory. The main use
+	  of this frame buffer device is testing and debugging the frame
+	  buffer subsystem. Do NOT enable it for normal systems! To protect
+	  the innocent, it has to be enabled explicitly at boot time using the
+	  kernel option `video=vfb:'.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called vfb.
+
+	  If unsure, say N.
+if VT
+	source "drivers/video/console/Kconfig"
+endif
+
+if FB || SGI_NEWPORT_CONSOLE
+	source "drivers/video/logo/Kconfig"
+endif
+
+if FB && SYSFS
+	source "drivers/video/backlight/Kconfig"
+endif
+
+endmenu
+
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
new file mode 100644
index 0000000..92265b7
--- /dev/null
+++ b/drivers/video/Makefile
@@ -0,0 +1,100 @@
+# Makefile for the Linux video drivers.
+# 5 Aug 1999, James Simmons, <mailto:jsimmons@users.sf.net>
+# Rewritten to use lists instead of if-statements.
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_VT)		  += console/
+obj-$(CONFIG_LOGO)		  += logo/
+obj-$(CONFIG_SYSFS)		  += backlight/
+
+obj-$(CONFIG_FB)                  += fb.o
+fb-y                              := fbmem.o fbmon.o fbcmap.o fbsysfs.o modedb.o
+fb-objs                           := $(fb-y)
+
+obj-$(CONFIG_FB_CFB_FILLRECT)  += cfbfillrect.o
+obj-$(CONFIG_FB_CFB_COPYAREA)  += cfbcopyarea.o
+obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o
+obj-$(CONFIG_FB_SOFT_CURSOR)   += softcursor.o
+obj-$(CONFIG_FB_MACMODES)      += macmodes.o
+
+# Hardware specific drivers go first
+obj-$(CONFIG_FB_RETINAZ3)         += retz3fb.o
+obj-$(CONFIG_FB_AMIGA)            += amifb.o c2p.o
+obj-$(CONFIG_FB_CLPS711X)         += clps711xfb.o
+obj-$(CONFIG_FB_CYBER)            += cyberfb.o
+obj-$(CONFIG_FB_CYBER2000)        += cyber2000fb.o
+obj-$(CONFIG_FB_PM2)              += pm2fb.o
+obj-$(CONFIG_FB_PM3)		  += pm3fb.o
+
+obj-$(CONFIG_FB_MATROX)		  += matrox/
+obj-$(CONFIG_FB_RIVA)		  += riva/ vgastate.o
+obj-$(CONFIG_FB_NVIDIA)		  += nvidia/
+obj-$(CONFIG_FB_ATY)		  += aty/ macmodes.o
+obj-$(CONFIG_FB_ATY128)		  += aty/ macmodes.o
+obj-$(CONFIG_FB_RADEON)		  += aty/
+obj-$(CONFIG_FB_SIS)		  += sis/
+obj-$(CONFIG_FB_KYRO)             += kyro/
+obj-$(CONFIG_FB_SAVAGE)		  += savage/
+obj-$(CONFIG_FB_GEODE)		  += geode/
+obj-$(CONFIG_FB_I810)             += vgastate.o
+obj-$(CONFIG_FB_RADEON_OLD)	  += radeonfb.o
+obj-$(CONFIG_FB_NEOMAGIC)         += neofb.o vgastate.o
+obj-$(CONFIG_FB_VIRGE)            += virgefb.o
+obj-$(CONFIG_FB_3DFX)             += tdfxfb.o
+obj-$(CONFIG_FB_CONTROL)          += controlfb.o
+obj-$(CONFIG_FB_PLATINUM)         += platinumfb.o
+obj-$(CONFIG_FB_VALKYRIE)         += valkyriefb.o
+obj-$(CONFIG_FB_CT65550)          += chipsfb.o
+obj-$(CONFIG_FB_IMSTT)            += imsttfb.o
+obj-$(CONFIG_FB_S3TRIO)           += S3triofb.o
+obj-$(CONFIG_FB_FM2)              += fm2fb.o
+obj-$(CONFIG_FB_TRIDENT)	  += tridentfb.o
+obj-$(CONFIG_FB_STI)              += stifb.o
+obj-$(CONFIG_FB_FFB)              += ffb.o sbuslib.o
+obj-$(CONFIG_FB_CG6)              += cg6.o sbuslib.o
+obj-$(CONFIG_FB_CG3)              += cg3.o sbuslib.o
+obj-$(CONFIG_FB_BW2)              += bw2.o sbuslib.o
+obj-$(CONFIG_FB_CG14)             += cg14.o sbuslib.o
+obj-$(CONFIG_FB_P9100)            += p9100.o sbuslib.o
+obj-$(CONFIG_FB_TCX)              += tcx.o sbuslib.o
+obj-$(CONFIG_FB_LEO)              += leo.o sbuslib.o
+obj-$(CONFIG_FB_SGIVW)            += sgivwfb.o
+obj-$(CONFIG_FB_ACORN)            += acornfb.o
+obj-$(CONFIG_FB_ATARI)            += atafb.o
+obj-$(CONFIG_FB_MAC)              += macfb.o
+obj-$(CONFIG_FB_HGA)              += hgafb.o
+obj-$(CONFIG_FB_IGA)              += igafb.o
+obj-$(CONFIG_FB_APOLLO)           += dnfb.o
+obj-$(CONFIG_FB_Q40)              += q40fb.o
+obj-$(CONFIG_FB_TGA)              += tgafb.o
+obj-$(CONFIG_FB_HP300)            += hpfb.o
+obj-$(CONFIG_FB_G364)             += g364fb.o
+obj-$(CONFIG_FB_SA1100)           += sa1100fb.o
+obj-$(CONFIG_FB_SUN3)             += sun3fb.o
+obj-$(CONFIG_FB_HIT)              += hitfb.o
+obj-$(CONFIG_FB_EPSON1355)	  += epson1355fb.o
+obj-$(CONFIG_FB_PVR2)             += pvr2fb.o
+obj-$(CONFIG_FB_VOODOO1)          += sstfb.o
+obj-$(CONFIG_FB_ARMCLCD)	  += amba-clcd.o
+obj-$(CONFIG_FB_68328)            += 68328fb.o
+obj-$(CONFIG_FB_GBE)              += gbefb.o
+obj-$(CONFIG_FB_CIRRUS)		  += cirrusfb.o
+obj-$(CONFIG_FB_ASILIANT)	  += asiliantfb.o
+obj-$(CONFIG_FB_PXA)		  += pxafb.o
+obj-$(CONFIG_FB_W100)		  += w100fb.o
+obj-$(CONFIG_FB_AU1100)		  += au1100fb.o fbgen.o
+obj-$(CONFIG_FB_PMAG_AA)	  += pmag-aa-fb.o
+obj-$(CONFIG_FB_PMAG_BA)	  += pmag-ba-fb.o
+obj-$(CONFIG_FB_PMAGB_B)	  += pmagb-b-fb.o
+obj-$(CONFIG_FB_MAXINE)		  += maxinefb.o
+obj-$(CONFIG_FB_TX3912)		  += tx3912fb.o
+obj-$(CONFIG_FB_S1D13XXX)	  += s1d13xxxfb.o
+
+# Platform or fallback drivers go here
+obj-$(CONFIG_FB_VESA)             += vesafb.o
+obj-$(CONFIG_FB_VGA16)            += vga16fb.o vgastate.o
+obj-$(CONFIG_FB_OF)               += offb.o
+
+# the test framebuffer is last
+obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
diff --git a/drivers/video/S3triofb.c b/drivers/video/S3triofb.c
new file mode 100644
index 0000000..455fda9
--- /dev/null
+++ b/drivers/video/S3triofb.c
@@ -0,0 +1,789 @@
+/*
+ *  linux/drivers/video/S3Triofb.c -- Open Firmware based frame buffer device
+ *
+ *	Copyright (C) 1997 Peter De Schrijver
+ *
+ *  This driver is partly based on the PowerMac console driver:
+ *
+ *	Copyright (C) 1996 Paul Mackerras
+ *
+ *  and on the Open Firmware based frame buffer device:
+ *
+ *	Copyright (C) 1997 Geert Uytterhoeven
+ *
+ *  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.
+ */
+
+/*
+	Bugs : + OF dependencies should be removed.
+               + This driver should be merged with the CyberVision driver. The
+                 CyberVision is a Zorro III implementation of the S3Trio64 chip.
+
+*/
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.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 <linux/fb.h>
+#include <linux/init.h>
+#include <linux/selection.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <linux/pci.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/s3blit.h>
+
+
+#define mem_in8(addr)           in_8((void *)(addr))
+#define mem_in16(addr)          in_le16((void *)(addr))
+#define mem_in32(addr)          in_le32((void *)(addr))
+
+#define mem_out8(val, addr)     out_8((void *)(addr), val)
+#define mem_out16(val, addr)    out_le16((void *)(addr), val)
+#define mem_out32(val, addr)    out_le32((void *)(addr), val)
+
+#define IO_OUT16VAL(v, r)       (((v) << 8) | (r))
+
+static struct display disp;
+static struct fb_info fb_info;
+static struct { u_char red, green, blue, pad; } palette[256];
+static char s3trio_name[16] = "S3Trio ";
+static char *s3trio_base;
+
+static struct fb_fix_screeninfo fb_fix;
+static struct fb_var_screeninfo fb_var = { 0, };
+
+
+    /*
+     *  Interface used by the world
+     */
+
+static void __init s3triofb_of_init(struct device_node *dp);
+static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con,
+			  struct fb_info *info);
+static int s3trio_get_var(struct fb_var_screeninfo *var, int con,
+			  struct fb_info *info);
+static int s3trio_set_var(struct fb_var_screeninfo *var, int con,
+			  struct fb_info *info);
+static int s3trio_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			   struct fb_info *info);
+static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                         u_int transp, struct fb_info *info);
+static int s3trio_pan_display(struct fb_var_screeninfo *var, int con,
+			      struct fb_info *info);
+static void s3triofb_blank(int blank, struct fb_info *info);
+
+    /*
+     *  Interface to the low level console driver
+     */
+
+int s3triofb_init(void);
+static int s3triofbcon_switch(int con, struct fb_info *info);
+static int s3triofbcon_updatevar(int con, struct fb_info *info);
+
+    /*
+     *  Text console acceleration
+     */
+
+#ifdef FBCON_HAS_CFB8
+static struct display_switch fbcon_trio8;
+#endif
+
+    /*
+     *    Accelerated Functions used by the low level console driver
+     */
+
+static void Trio_WaitQueue(u_short fifo);
+static void Trio_WaitBlit(void);
+static void Trio_BitBLT(u_short curx, u_short cury, u_short destx,
+			u_short desty, u_short width, u_short height,
+			u_short mode);
+static void Trio_RectFill(u_short x, u_short y, u_short width, u_short height,
+			  u_short mode, u_short color);
+static void Trio_MoveCursor(u_short x, u_short y);
+
+
+    /*
+     *  Internal routines
+     */
+
+static int s3trio_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+                         u_int *transp, struct fb_info *info);
+
+static struct fb_ops s3trio_ops = {
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	s3trio_get_fix,
+	.fb_get_var =	s3trio_get_var,
+	.fb_set_var =	s3trio_set_var,
+	.fb_get_cmap =	s3trio_get_cmap,
+	.fb_set_cmap =	gen_set_cmap,
+	.fb_setcolreg =	s3trio_setcolreg,
+	.fb_pan_display =s3trio_pan_display,
+	.fb_blank =	s3triofb_blank,
+};
+
+    /*
+     *  Get the Fixed Part of the Display
+     */
+
+static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con,
+			  struct fb_info *info)
+{
+    memcpy(fix, &fb_fix, sizeof(fb_fix));
+    return 0;
+}
+
+
+    /*
+     *  Get the User Defined Part of the Display
+     */
+
+static int s3trio_get_var(struct fb_var_screeninfo *var, int con,
+			  struct fb_info *info)
+{
+    memcpy(var, &fb_var, sizeof(fb_var));
+    return 0;
+}
+
+
+    /*
+     *  Set the User Defined Part of the Display
+     */
+
+static int s3trio_set_var(struct fb_var_screeninfo *var, int con,
+			  struct fb_info *info)
+{
+    if (var->xres > fb_var.xres || var->yres > fb_var.yres ||
+	var->bits_per_pixel > fb_var.bits_per_pixel )
+	/* || var->nonstd || var->vmode != FB_VMODE_NONINTERLACED) */
+	return -EINVAL;
+    if (var->xres_virtual > fb_var.xres_virtual) {
+	outw(IO_OUT16VAL((var->xres_virtual /8) & 0xff, 0x13), 0x3d4);
+	outw(IO_OUT16VAL(((var->xres_virtual /8 ) & 0x300) >> 3, 0x51), 0x3d4);
+	fb_var.xres_virtual = var->xres_virtual;
+	fb_fix.line_length = var->xres_virtual;
+    }
+    fb_var.yres_virtual = var->yres_virtual;
+    memcpy(var, &fb_var, sizeof(fb_var));
+    return 0;
+}
+
+
+    /*
+     *  Pan or Wrap the Display
+     *
+     *  This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
+     */
+
+static int s3trio_pan_display(struct fb_var_screeninfo *var, int con,
+			      struct fb_info *info)
+{
+    unsigned int base;
+
+    if (var->xoffset > (var->xres_virtual - var->xres))
+	return -EINVAL;
+    if (var->yoffset > (var->yres_virtual - var->yres))
+	return -EINVAL;
+
+    fb_var.xoffset = var->xoffset;
+    fb_var.yoffset = var->yoffset;
+
+    base = var->yoffset * fb_fix.line_length + var->xoffset;
+
+    outw(IO_OUT16VAL((base >> 8) & 0xff, 0x0c),0x03D4);
+    outw(IO_OUT16VAL(base  & 0xff, 0x0d),0x03D4);
+    outw(IO_OUT16VAL((base >> 16) & 0xf, 0x69),0x03D4);
+    return 0;
+}
+
+
+    /*
+     *  Get the Colormap
+     */
+
+static int s3trio_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			   struct fb_info *info)
+{
+    if (con == info->currcon) /* current console? */
+	return fb_get_cmap(cmap, kspc, s3trio_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;
+}
+
+int __init s3triofb_init(void)
+{
+	struct device_node *dp;
+
+	dp = find_devices("S3Trio");
+	if (dp != 0)
+	    s3triofb_of_init(dp);
+	return 0;
+}
+
+void __init s3trio_resetaccel(void){
+
+
+#define EC01_ENH_ENB    0x0005
+#define EC01_LAW_ENB    0x0010
+#define EC01_MMIO_ENB   0x0020
+
+#define EC00_RESET      0x8000
+#define EC00_ENABLE     0x4000
+#define MF_MULT_MISC    0xE000
+#define SRC_FOREGROUND  0x0020
+#define SRC_BACKGROUND  0x0000
+#define MIX_SRC                 0x0007
+#define MF_T_CLIP       0x1000
+#define MF_L_CLIP       0x2000
+#define MF_B_CLIP       0x3000
+#define MF_R_CLIP       0x4000
+#define MF_PIX_CONTROL  0xA000
+#define MFA_SRC_FOREGR_MIX      0x0000
+#define MF_PIX_CONTROL  0xA000
+
+	outw(EC00_RESET,  0x42e8);
+	inw(  0x42e8);
+	outw(EC00_ENABLE,  0x42e8);
+	inw(  0x42e8);
+	outw(EC01_ENH_ENB | EC01_LAW_ENB,
+		   0x4ae8);
+	outw(MF_MULT_MISC,  0xbee8); /* 16 bit I/O registers */
+
+	/* Now set some basic accelerator registers */
+	Trio_WaitQueue(0x0400);
+	outw(SRC_FOREGROUND | MIX_SRC, 0xbae8);
+	outw(SRC_BACKGROUND | MIX_SRC,  0xb6e8);/* direct color*/
+	outw(MF_T_CLIP | 0, 0xbee8 );     /* clip virtual area  */
+	outw(MF_L_CLIP | 0, 0xbee8 );
+	outw(MF_R_CLIP | (640 - 1), 0xbee8);
+	outw(MF_B_CLIP | (480 - 1),  0xbee8);
+	Trio_WaitQueue(0x0400);
+	outw(0xffff,  0xaae8);       /* Enable all planes */
+	outw(0xffff, 0xaae8);       /* Enable all planes */
+	outw( MF_PIX_CONTROL | MFA_SRC_FOREGR_MIX,  0xbee8);
+}
+
+int __init s3trio_init(struct device_node *dp){
+
+    u_char bus, dev;
+    unsigned int t32;
+    unsigned short cmd;
+
+	pci_device_loc(dp,&bus,&dev);
+                pcibios_read_config_dword(bus, dev, PCI_VENDOR_ID, &t32);
+                if(t32 == (PCI_DEVICE_ID_S3_TRIO << 16) + PCI_VENDOR_ID_S3) {
+                        pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
+                        pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_1, &t32);
+			pcibios_read_config_word(bus, dev, PCI_COMMAND,&cmd);
+
+			pcibios_write_config_word(bus, dev, PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+
+			pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_0,0xffffffff);
+                        pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
+
+/* This is a gross hack as OF only maps enough memory for the framebuffer and
+   we want to use MMIO too. We should find out which chunk of address space
+   we can use here */
+			pcibios_write_config_dword(bus,dev,PCI_BASE_ADDRESS_0,0xc6000000);
+
+			/* unlock s3 */
+
+			outb(0x01, 0x3C3);
+
+			outb(inb(0x03CC) | 1, 0x3c2);
+
+			outw(IO_OUT16VAL(0x48, 0x38),0x03D4);
+			outw(IO_OUT16VAL(0xA0, 0x39),0x03D4);
+			outb(0x33,0x3d4);
+			outw(IO_OUT16VAL((inb(0x3d5) & ~(0x2 | 0x10 |  0x40)) |
+					  0x20, 0x33), 0x3d4);
+
+			outw(IO_OUT16VAL(0x6, 0x8), 0x3c4);
+
+			/* switch to MMIO only mode */
+
+			outb(0x58, 0x3d4);
+			outw(IO_OUT16VAL(inb(0x3d5) | 3 | 0x10, 0x58), 0x3d4);
+			outw(IO_OUT16VAL(8, 0x53), 0x3d4);
+
+			/* switch off I/O accesses */
+
+#if 0
+			pcibios_write_config_word(bus, dev, PCI_COMMAND,
+				        PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+#endif
+			return 1;
+                }
+
+	return 0;
+}
+
+
+    /*
+     *  Initialisation
+     *  We heavily rely on OF for the moment. This needs fixing.
+     */
+
+static void __init s3triofb_of_init(struct device_node *dp)
+{
+    int i, *pp, len;
+    unsigned long address, size;
+    u_long *CursorBase;
+
+    strncat(s3trio_name, dp->name, sizeof(s3trio_name));
+    s3trio_name[sizeof(s3trio_name)-1] = '\0';
+    strcpy(fb_fix.id, s3trio_name);
+
+    if((pp = (int *)get_property(dp, "vendor-id", &len)) != NULL
+	&& *pp!=PCI_VENDOR_ID_S3) {
+	printk("%s: can't find S3 Trio board\n", dp->full_name);
+	return;
+    }
+
+    if((pp = (int *)get_property(dp, "device-id", &len)) != NULL
+	&& *pp!=PCI_DEVICE_ID_S3_TRIO) {
+	printk("%s: can't find S3 Trio board\n", dp->full_name);
+	return;
+    }
+
+    if ((pp = (int *)get_property(dp, "depth", &len)) != NULL
+	&& len == sizeof(int) && *pp != 8) {
+	printk("%s: can't use depth = %d\n", dp->full_name, *pp);
+	return;
+    }
+    if ((pp = (int *)get_property(dp, "width", &len)) != NULL
+	&& len == sizeof(int))
+	fb_var.xres = fb_var.xres_virtual = *pp;
+    if ((pp = (int *)get_property(dp, "height", &len)) != NULL
+	&& len == sizeof(int))
+	fb_var.yres = fb_var.yres_virtual = *pp;
+    if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL
+	&& len == sizeof(int))
+	fb_fix.line_length = *pp;
+    else
+	fb_fix.line_length = fb_var.xres_virtual;
+    fb_fix.smem_len = fb_fix.line_length*fb_var.yres;
+
+    address = 0xc6000000;
+    size = 64*1024*1024;
+    if (!request_mem_region(address, size, "S3triofb"))
+	return;
+
+    s3trio_init(dp);
+    s3trio_base = ioremap(address, size);
+    fb_fix.smem_start = address;
+    fb_fix.type = FB_TYPE_PACKED_PIXELS;
+    fb_fix.type_aux = 0;
+    fb_fix.accel = FB_ACCEL_S3_TRIO64;
+    fb_fix.mmio_start = address+0x1000000;
+    fb_fix.mmio_len = 0x1000000;
+
+    fb_fix.xpanstep = 1;
+    fb_fix.ypanstep = 1;
+
+    s3trio_resetaccel();
+
+    mem_out8(0x30, s3trio_base+0x1008000 + 0x03D4);
+    mem_out8(0x2d, s3trio_base+0x1008000 + 0x03D4);
+    mem_out8(0x2e, s3trio_base+0x1008000 + 0x03D4);
+
+    mem_out8(0x50, s3trio_base+0x1008000 + 0x03D4);
+
+    /* disable HW cursor */
+
+    mem_out8(0x39, s3trio_base+0x1008000 + 0x03D4);
+    mem_out8(0xa0, s3trio_base+0x1008000 + 0x03D5);
+
+    mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
+    mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
+
+    mem_out8(0x4e, s3trio_base+0x1008000 + 0x03D4);
+    mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
+
+    mem_out8(0x4f, s3trio_base+0x1008000 + 0x03D4);
+    mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
+
+    /* init HW cursor */
+
+    CursorBase = (u_long *)(s3trio_base + 2*1024*1024 - 0x400);
+	for (i = 0; i < 8; i++) {
+		*(CursorBase  +(i*4)) = 0xffffff00;
+		*(CursorBase+1+(i*4)) = 0xffff0000;
+		*(CursorBase+2+(i*4)) = 0xffff0000;
+		*(CursorBase+3+(i*4)) = 0xffff0000;
+	}
+	for (i = 8; i < 64; i++) {
+		*(CursorBase  +(i*4)) = 0xffff0000;
+		*(CursorBase+1+(i*4)) = 0xffff0000;
+		*(CursorBase+2+(i*4)) = 0xffff0000;
+		*(CursorBase+3+(i*4)) = 0xffff0000;
+	}
+
+
+    mem_out8(0x4c, s3trio_base+0x1008000 + 0x03D4);
+    mem_out8(((2*1024 - 1)&0xf00)>>8, s3trio_base+0x1008000 + 0x03D5);
+
+    mem_out8(0x4d, s3trio_base+0x1008000 + 0x03D4);
+    mem_out8((2*1024 - 1) & 0xff, s3trio_base+0x1008000 + 0x03D5);
+
+    mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
+    mem_in8(s3trio_base+0x1008000 + 0x03D4);
+
+    mem_out8(0x4a, s3trio_base+0x1008000 + 0x03D4);
+    mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
+    mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
+    mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
+
+    mem_out8(0x4b, s3trio_base+0x1008000 + 0x03D4);
+    mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
+    mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
+    mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
+
+    mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
+    mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
+
+    /* setup default color table */
+
+	for(i = 0; i < 16; i++) {
+		int j = color_table[i];
+		palette[i].red=default_red[j];
+		palette[i].green=default_grn[j];
+		palette[i].blue=default_blu[j];
+	}
+
+    s3trio_setcolreg(255, 56, 100, 160, 0, NULL /* not used */);
+    s3trio_setcolreg(254, 0, 0, 0, 0, NULL /* not used */);
+    memset((char *)s3trio_base, 0, 640*480);
+
+#if 0
+    Trio_RectFill(0, 0, 90, 90, 7, 1);
+#endif
+
+    fb_fix.visual = FB_VISUAL_PSEUDOCOLOR ;
+    fb_var.xoffset = fb_var.yoffset = 0;
+    fb_var.bits_per_pixel = 8;
+    fb_var.grayscale = 0;
+    fb_var.red.offset = fb_var.green.offset = fb_var.blue.offset = 0;
+    fb_var.red.length = fb_var.green.length = fb_var.blue.length = 8;
+    fb_var.red.msb_right = fb_var.green.msb_right = fb_var.blue.msb_right = 0;
+    fb_var.transp.offset = fb_var.transp.length = fb_var.transp.msb_right = 0;
+    fb_var.nonstd = 0;
+    fb_var.activate = 0;
+    fb_var.height = fb_var.width = -1;
+    fb_var.accel_flags = FB_ACCELF_TEXT;
+#warning FIXME: always obey fb_var.accel_flags
+    fb_var.pixclock = 1;
+    fb_var.left_margin = fb_var.right_margin = 0;
+    fb_var.upper_margin = fb_var.lower_margin = 0;
+    fb_var.hsync_len = fb_var.vsync_len = 0;
+    fb_var.sync = 0;
+    fb_var.vmode = FB_VMODE_NONINTERLACED;
+
+    disp.var = fb_var;
+    disp.cmap.start = 0;
+    disp.cmap.len = 0;
+    disp.cmap.red = disp.cmap.green = disp.cmap.blue = disp.cmap.transp = NULL;
+    disp.visual = fb_fix.visual;
+    disp.type = fb_fix.type;
+    disp.type_aux = fb_fix.type_aux;
+    disp.ypanstep = 0;
+    disp.ywrapstep = 0;
+    disp.line_length = fb_fix.line_length;
+    disp.can_soft_blank = 1;
+    disp.inverse = 0;
+#ifdef FBCON_HAS_CFB8
+    if (fb_var.accel_flags & FB_ACCELF_TEXT)
+	disp.dispsw = &fbcon_trio8;
+    else
+	disp.dispsw = &fbcon_cfb8;
+#else
+    disp.dispsw = &fbcon_dummy;
+#endif
+    disp.scrollmode = fb_var.accel_flags & FB_ACCELF_TEXT ? 0 : SCROLL_YREDRAW;
+
+    strcpy(fb_info.modename, "Trio64 ");
+    strncat(fb_info.modename, dp->full_name, sizeof(fb_info.modename));
+    fb_info.currcon = -1;
+    fb_info.fbops = &s3trio_ops;
+    fb_info.screen_base = s3trio_base;	
+#if 0
+    fb_info.fbvar_num = 1;
+    fb_info.fbvar = &fb_var;
+#endif
+    fb_info.disp = &disp;
+    fb_info.fontname[0] = '\0';
+    fb_info.changevar = NULL;
+    fb_info.switch_con = &s3triofbcon_switch;
+    fb_info.updatevar = &s3triofbcon_updatevar;
+#if 0
+    fb_info.setcmap = &s3triofbcon_setcmap;
+#endif
+
+    fb_info.flags = FBINFO_FLAG_DEFAULT;
+    if (register_framebuffer(&fb_info) < 0)
+	return;
+
+    printk("fb%d: S3 Trio frame buffer device on %s\n",
+	   fb_info.node, dp->full_name);
+}
+
+
+static int s3triofbcon_switch(int con, struct fb_info *info)
+{
+    /* Do we have to save the colormap? */
+    if (fb_display[info->currcon].cmap.len)
+	fb_get_cmap(&fb_display[info->currcon].cmap, 1, s3trio_getcolreg, info);
+
+    info->currcon = con;
+    /* Install new colormap */
+    do_install_cmap(con,info);
+    return 0;
+}
+
+    /*
+     *  Update the `var' structure (called by fbcon.c)
+     */
+
+static int s3triofbcon_updatevar(int con, struct fb_info *info)
+{
+    /* Nothing */
+    return 0;
+}
+
+    /*
+     *  Blank the display.
+     */
+
+static int s3triofb_blank(int blank, struct fb_info *info)
+{
+    unsigned char x;
+
+    mem_out8(0x1, s3trio_base+0x1008000 + 0x03c4);
+    x = mem_in8(s3trio_base+0x1008000 + 0x03c5);
+    mem_out8((x & (~0x20)) | (blank << 5), s3trio_base+0x1008000 + 0x03c5);
+    return 0;	
+}
+
+    /*
+     *  Read a single color register and split it into
+     *  colors/transparent. Return != 0 for invalid regno.
+     */
+
+static int s3trio_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) | palette[regno].red;
+    *green = (palette[regno].green << 8) | palette[regno].green;
+    *blue = (palette[regno].blue << 8) | palette[regno].blue;
+    *transp = 0;
+    return 0;
+}
+
+
+    /*
+     *  Set a single color register. Return != 0 for invalid regno.
+     */
+
+static int s3trio_setcolreg(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 >>= 8;
+    green >>= 8;
+    blue >>= 8;
+    palette[regno].red = red;
+    palette[regno].green = green;
+    palette[regno].blue = blue;
+
+    mem_out8(regno,s3trio_base+0x1008000 + 0x3c8);
+    mem_out8((red & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
+    mem_out8((green & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
+    mem_out8((blue & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
+
+    return 0;
+}
+
+static void Trio_WaitQueue(u_short fifo) {
+
+	u_short status;
+
+        do
+        {
+		status = mem_in16(s3trio_base + 0x1000000 + 0x9AE8);
+	}  while (!(status & fifo));
+
+}
+
+static void Trio_WaitBlit(void) {
+
+	u_short status;
+
+        do
+        {
+		status = mem_in16(s3trio_base + 0x1000000 + 0x9AE8);
+	}  while (status & 0x200);
+
+}
+
+static void Trio_BitBLT(u_short curx, u_short cury, u_short destx,
+			u_short desty, u_short width, u_short height,
+			u_short mode) {
+
+	u_short blitcmd = 0xc011;
+
+	/* Set drawing direction */
+        /* -Y, X maj, -X (default) */
+
+	if (curx > destx)
+		blitcmd |= 0x0020;  /* Drawing direction +X */
+	else {
+		curx  += (width - 1);
+		destx += (width - 1);
+	}
+
+	if (cury > desty)
+		blitcmd |= 0x0080;  /* Drawing direction +Y */
+	else {
+		cury  += (height - 1);
+		desty += (height - 1);
+	}
+
+	Trio_WaitQueue(0x0400);
+
+	outw(0xa000,  0xBEE8);
+	outw(0x60 | mode,  0xBAE8);
+
+	outw(curx,  0x86E8);
+	outw(cury,  0x82E8);
+
+	outw(destx,  0x8EE8);
+	outw(desty,  0x8AE8);
+
+	outw(height - 1,  0xBEE8);
+	outw(width - 1,  0x96E8);
+
+	outw(blitcmd,  0x9AE8);
+
+}
+
+static void Trio_RectFill(u_short x, u_short y, u_short width, u_short height,
+			  u_short mode, u_short color) {
+
+	u_short blitcmd = 0x40b1;
+
+	Trio_WaitQueue(0x0400);
+
+	outw(0xa000,  0xBEE8);
+	outw((0x20 | mode),  0xBAE8);
+	outw(0xe000,  0xBEE8);
+	outw(color,  0xA6E8);
+	outw(x,  0x86E8);
+	outw(y,  0x82E8);
+	outw((height - 1), 0xBEE8);
+	outw((width - 1), 0x96E8);
+	outw(blitcmd,  0x9AE8);
+
+}
+
+
+static void Trio_MoveCursor(u_short x, u_short y) {
+
+	mem_out8(0x39, s3trio_base + 0x1008000 + 0x3d4);
+	mem_out8(0xa0, s3trio_base + 0x1008000 + 0x3d5);
+
+	mem_out8(0x46, s3trio_base + 0x1008000 + 0x3d4);
+	mem_out8((x & 0x0700) >> 8, s3trio_base + 0x1008000 + 0x3d5);
+	mem_out8(0x47, s3trio_base + 0x1008000 + 0x3d4);
+	mem_out8(x & 0x00ff, s3trio_base + 0x1008000 + 0x3d5);
+
+	mem_out8(0x48, s3trio_base + 0x1008000 + 0x3d4);
+	mem_out8((y & 0x0700) >> 8, s3trio_base + 0x1008000 + 0x3d5);
+	mem_out8(0x49, s3trio_base + 0x1008000 + 0x3d4);
+	mem_out8(y & 0x00ff, s3trio_base + 0x1008000 + 0x3d5);
+
+}
+
+
+    /*
+     *  Text console acceleration
+     */
+
+#ifdef FBCON_HAS_CFB8
+static void fbcon_trio8_bmove(struct display *p, int sy, int sx, int dy,
+			      int dx, int height, int width)
+{
+    sx *= 8; dx *= 8; width *= 8;
+    Trio_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)S3_NEW);
+}
+
+static void fbcon_trio8_clear(struct vc_data *conp, struct display *p, int sy,
+			      int sx, int height, int width)
+{
+    unsigned char bg;
+
+    sx *= 8; width *= 8;
+    bg = attr_bgcol_ec(p,conp);
+    Trio_RectFill((u_short)sx,
+		   (u_short)(sy*fontheight(p)),
+		   (u_short)width,
+		   (u_short)(height*fontheight(p)),
+		   (u_short)S3_NEW,
+		   (u_short)bg);
+}
+
+static void fbcon_trio8_putc(struct vc_data *conp, struct display *p, int c,
+			     int yy, int xx)
+{
+    Trio_WaitBlit();
+    fbcon_cfb8_putc(conp, p, c, yy, xx);
+}
+
+static void fbcon_trio8_putcs(struct vc_data *conp, struct display *p,
+			      const unsigned short *s, int count, int yy, int xx)
+{
+    Trio_WaitBlit();
+    fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
+}
+
+static void fbcon_trio8_revc(struct display *p, int xx, int yy)
+{
+    Trio_WaitBlit();
+    fbcon_cfb8_revc(p, xx, yy);
+}
+
+static struct display_switch fbcon_trio8 = {
+   .setup =		fbcon_cfb8_setup,
+   .bmove =		fbcon_trio8_bmove,
+   .clear =		fbcon_trio8_clear,
+   .putc =		fbcon_trio8_putc,
+   .putcs =		fbcon_trio8_putcs,
+   .revc =		fbcon_trio8_revc,
+   .clear_margins =	fbcon_cfb8_clear_margins,
+   .fontwidthmask =	FONTWIDTH(8)
+};
+#endif
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c
new file mode 100644
index 0000000..f02965f
--- /dev/null
+++ b/drivers/video/acornfb.c
@@ -0,0 +1,1472 @@
+/*
+ *  linux/drivers/video/acornfb.c
+ *
+ *  Copyright (C) 1998-2001 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Frame buffer code for Acorn platforms
+ *
+ * NOTE: Most of the modes with X!=640 will disappear shortly.
+ * NOTE: Startup setting of HS & VS polarity not supported.
+ *       (do we need to support it if we're coming up in 640x480?)
+ *
+ * FIXME: (things broken by the "new improved" FBCON API)
+ *  - Blanking 8bpp displays with VIDC
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+#include <asm/pgtable.h>
+
+#include "acornfb.h"
+
+/*
+ * VIDC machines can't do 16 or 32BPP modes.
+ */
+#ifdef HAS_VIDC
+#undef FBCON_HAS_CFB16
+#undef FBCON_HAS_CFB32
+#endif
+
+/*
+ * Default resolution.
+ * NOTE that it has to be supported in the table towards
+ * the end of this file.
+ */
+#define DEFAULT_XRES	640
+#define DEFAULT_YRES	480
+#define DEFAULT_BPP	4
+
+/*
+ * define this to debug the video mode selection
+ */
+#undef DEBUG_MODE_SELECTION
+
+/*
+ * Translation from RISC OS monitor types to actual
+ * HSYNC and VSYNC frequency ranges.  These are
+ * probably not right, but they're the best info I
+ * have.  Allow 1% either way on the nominal for TVs.
+ */
+#define NR_MONTYPES	6
+static struct fb_monspecs monspecs[NR_MONTYPES] __initdata = {
+	{	/* TV		*/
+		.hfmin	= 15469,
+		.hfmax	= 15781,
+		.vfmin	= 49,
+		.vfmax	= 51,
+	}, {	/* Multi Freq	*/
+		.hfmin	= 0,
+		.hfmax	= 99999,
+		.vfmin	= 0,
+		.vfmax	= 199,
+	}, {	/* Hi-res mono	*/
+		.hfmin	= 58608,
+		.hfmax	= 58608,
+		.vfmin	= 64,
+		.vfmax	= 64,
+	}, {	/* VGA		*/
+		.hfmin	= 30000,
+		.hfmax	= 70000,
+		.vfmin	= 60,
+		.vfmax	= 60,
+	}, {	/* SVGA		*/
+		.hfmin	= 30000,
+		.hfmax	= 70000,
+		.vfmin	= 56,
+		.vfmax	= 75,
+	}, {
+		.hfmin	= 30000,
+		.hfmax	= 70000,
+		.vfmin	= 60,
+		.vfmax	= 60,
+	}
+};
+
+static struct fb_info fb_info;
+static struct acornfb_par current_par;
+static struct vidc_timing current_vidc;
+
+extern unsigned int vram_size;	/* set by setup.c */
+
+#ifdef HAS_VIDC
+
+#define MAX_SIZE	480*1024
+
+/* CTL     VIDC	Actual
+ * 24.000  0	 8.000
+ * 25.175  0	 8.392
+ * 36.000  0	12.000
+ * 24.000  1	12.000
+ * 25.175  1	12.588
+ * 24.000  2	16.000
+ * 25.175  2	16.783
+ * 36.000  1	18.000
+ * 24.000  3	24.000
+ * 36.000  2	24.000
+ * 25.175  3	25.175
+ * 36.000  3	36.000
+ */
+struct pixclock {
+	u_long	min_clock;
+	u_long	max_clock;
+	u_int	vidc_ctl;
+	u_int	vid_ctl;
+};
+
+static struct pixclock arc_clocks[] = {
+	/* we allow +/-1% on these */
+	{ 123750, 126250, VIDC_CTRL_DIV3,   VID_CTL_24MHz },	/*  8.000MHz */
+	{  82500,  84167, VIDC_CTRL_DIV2,   VID_CTL_24MHz },	/* 12.000MHz */
+	{  61875,  63125, VIDC_CTRL_DIV1_5, VID_CTL_24MHz },	/* 16.000MHz */
+	{  41250,  42083, VIDC_CTRL_DIV1,   VID_CTL_24MHz },	/* 24.000MHz */
+};
+
+#ifdef CONFIG_ARCH_A5K
+static struct pixclock a5k_clocks[] = {
+	{ 117974, 120357, VIDC_CTRL_DIV3,   VID_CTL_25MHz },	/*  8.392MHz */
+	{  78649,  80238, VIDC_CTRL_DIV2,   VID_CTL_25MHz },	/* 12.588MHz */
+	{  58987,  60178, VIDC_CTRL_DIV1_5, VID_CTL_25MHz },	/* 16.588MHz */
+	{  55000,  56111, VIDC_CTRL_DIV2,   VID_CTL_36MHz },	/* 18.000MHz */
+	{  39325,  40119, VIDC_CTRL_DIV1,   VID_CTL_25MHz },	/* 25.175MHz */
+	{  27500,  28055, VIDC_CTRL_DIV1,   VID_CTL_36MHz },	/* 36.000MHz */
+};
+#endif
+
+static struct pixclock *
+acornfb_valid_pixrate(struct fb_var_screeninfo *var)
+{
+	u_long pixclock = var->pixclock;
+	u_int i;
+
+	if (!var->pixclock)
+		return NULL;
+
+	for (i = 0; i < ARRAY_SIZE(arc_clocks); i++)
+		if (pixclock > arc_clocks[i].min_clock &&
+		    pixclock < arc_clocks[i].max_clock)
+			return arc_clocks + i;
+
+#ifdef CONFIG_ARCH_A5K
+	if (machine_is_a5k()) {
+		for (i = 0; i < ARRAY_SIZE(a5k_clocks); i++)
+			if (pixclock > a5k_clocks[i].min_clock &&
+			    pixclock < a5k_clocks[i].max_clock)
+				return a5k_clocks + i;
+	}
+#endif
+
+	return NULL;
+}
+
+/* VIDC Rules:
+ * hcr  : must be even (interlace, hcr/2 must be even)
+ * hswr : must be even
+ * hdsr : must be odd
+ * hder : must be odd
+ *
+ * vcr  : must be odd
+ * vswr : >= 1
+ * vdsr : >= 1
+ * vder : >= vdsr
+ * if interlaced, then hcr/2 must be even
+ */
+static void
+acornfb_set_timing(struct fb_var_screeninfo *var)
+{
+	struct pixclock *pclk;
+	struct vidc_timing vidc;
+	u_int horiz_correction;
+	u_int sync_len, display_start, display_end, cycle;
+	u_int is_interlaced;
+	u_int vid_ctl, vidc_ctl;
+	u_int bandwidth;
+
+	memset(&vidc, 0, sizeof(vidc));
+
+	pclk = acornfb_valid_pixrate(var);
+	vidc_ctl = pclk->vidc_ctl;
+	vid_ctl  = pclk->vid_ctl;
+
+	bandwidth = var->pixclock * 8 / var->bits_per_pixel;
+	/* 25.175, 4bpp = 79.444ns per byte, 317.776ns per word: fifo = 2,6 */
+	if (bandwidth > 143500)
+		vidc_ctl |= VIDC_CTRL_FIFO_3_7;
+	else if (bandwidth > 71750)
+		vidc_ctl |= VIDC_CTRL_FIFO_2_6;
+	else if (bandwidth > 35875)
+		vidc_ctl |= VIDC_CTRL_FIFO_1_5;
+	else
+		vidc_ctl |= VIDC_CTRL_FIFO_0_4;
+
+	switch (var->bits_per_pixel) {
+	case 1:
+		horiz_correction = 19;
+		vidc_ctl |= VIDC_CTRL_1BPP;
+		break;
+
+	case 2:
+		horiz_correction = 11;
+		vidc_ctl |= VIDC_CTRL_2BPP;
+		break;
+
+	case 4:
+		horiz_correction = 7;
+		vidc_ctl |= VIDC_CTRL_4BPP;
+		break;
+
+	default:
+	case 8:
+		horiz_correction = 5;
+		vidc_ctl |= VIDC_CTRL_8BPP;
+		break;
+	}
+
+	if (var->sync & FB_SYNC_COMP_HIGH_ACT) /* should be FB_SYNC_COMP */
+		vidc_ctl |= VIDC_CTRL_CSYNC;
+	else {
+		if (!(var->sync & FB_SYNC_HOR_HIGH_ACT))
+			vid_ctl |= VID_CTL_HS_NHSYNC;
+
+		if (!(var->sync & FB_SYNC_VERT_HIGH_ACT))
+			vid_ctl |= VID_CTL_VS_NVSYNC;
+	}
+
+	sync_len	= var->hsync_len;
+	display_start	= sync_len + var->left_margin;
+	display_end	= display_start + var->xres;
+	cycle		= display_end + var->right_margin;
+
+	/* if interlaced, then hcr/2 must be even */
+	is_interlaced = (var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED;
+
+	if (is_interlaced) {
+		vidc_ctl |= VIDC_CTRL_INTERLACE;
+		if (cycle & 2) {
+			cycle += 2;
+			var->right_margin += 2;
+		}
+	}
+
+	vidc.h_cycle		= (cycle - 2) / 2;
+	vidc.h_sync_width	= (sync_len - 2) / 2;
+	vidc.h_border_start	= (display_start - 1) / 2;
+	vidc.h_display_start	= (display_start - horiz_correction) / 2;
+	vidc.h_display_end	= (display_end - horiz_correction) / 2;
+	vidc.h_border_end	= (display_end - 1) / 2;
+	vidc.h_interlace	= (vidc.h_cycle + 1) / 2;
+
+	sync_len	= var->vsync_len;
+	display_start	= sync_len + var->upper_margin;
+	display_end	= display_start + var->yres;
+	cycle		= display_end + var->lower_margin;
+
+	if (is_interlaced)
+		cycle = (cycle - 3) / 2;
+	else
+		cycle = cycle - 1;
+
+	vidc.v_cycle		= cycle;
+	vidc.v_sync_width	= sync_len - 1;
+	vidc.v_border_start	= display_start - 1;
+	vidc.v_display_start	= vidc.v_border_start;
+	vidc.v_display_end	= display_end - 1;
+	vidc.v_border_end	= vidc.v_display_end;
+
+	if (machine_is_a5k())
+		__raw_writeb(vid_ctl, IOEB_VID_CTL);
+
+	if (memcmp(&current_vidc, &vidc, sizeof(vidc))) {
+		current_vidc = vidc;
+
+		vidc_writel(0xe0000000 | vidc_ctl);
+		vidc_writel(0x80000000 | (vidc.h_cycle << 14));
+		vidc_writel(0x84000000 | (vidc.h_sync_width << 14));
+		vidc_writel(0x88000000 | (vidc.h_border_start << 14));
+		vidc_writel(0x8c000000 | (vidc.h_display_start << 14));
+		vidc_writel(0x90000000 | (vidc.h_display_end << 14));
+		vidc_writel(0x94000000 | (vidc.h_border_end << 14));
+		vidc_writel(0x98000000);
+		vidc_writel(0x9c000000 | (vidc.h_interlace << 14));
+		vidc_writel(0xa0000000 | (vidc.v_cycle << 14));
+		vidc_writel(0xa4000000 | (vidc.v_sync_width << 14));
+		vidc_writel(0xa8000000 | (vidc.v_border_start << 14));
+		vidc_writel(0xac000000 | (vidc.v_display_start << 14));
+		vidc_writel(0xb0000000 | (vidc.v_display_end << 14));
+		vidc_writel(0xb4000000 | (vidc.v_border_end << 14));
+		vidc_writel(0xb8000000);
+		vidc_writel(0xbc000000);
+	}
+#ifdef DEBUG_MODE_SELECTION
+	printk(KERN_DEBUG "VIDC registers for %dx%dx%d:\n", var->xres,
+	       var->yres, var->bits_per_pixel);
+	printk(KERN_DEBUG " H-cycle          : %d\n", vidc.h_cycle);
+	printk(KERN_DEBUG " H-sync-width     : %d\n", vidc.h_sync_width);
+	printk(KERN_DEBUG " H-border-start   : %d\n", vidc.h_border_start);
+	printk(KERN_DEBUG " H-display-start  : %d\n", vidc.h_display_start);
+	printk(KERN_DEBUG " H-display-end    : %d\n", vidc.h_display_end);
+	printk(KERN_DEBUG " H-border-end     : %d\n", vidc.h_border_end);
+	printk(KERN_DEBUG " H-interlace      : %d\n", vidc.h_interlace);
+	printk(KERN_DEBUG " V-cycle          : %d\n", vidc.v_cycle);
+	printk(KERN_DEBUG " V-sync-width     : %d\n", vidc.v_sync_width);
+	printk(KERN_DEBUG " V-border-start   : %d\n", vidc.v_border_start);
+	printk(KERN_DEBUG " V-display-start  : %d\n", vidc.v_display_start);
+	printk(KERN_DEBUG " V-display-end    : %d\n", vidc.v_display_end);
+	printk(KERN_DEBUG " V-border-end     : %d\n", vidc.v_border_end);
+	printk(KERN_DEBUG " VIDC Ctrl (E)    : 0x%08X\n", vidc_ctl);
+	printk(KERN_DEBUG " IOEB Ctrl        : 0x%08X\n", vid_ctl);
+#endif
+}
+
+static int
+acornfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+		  u_int trans, struct fb_info *info)
+{
+	union palette pal;
+
+	if (regno >= current_par.palette_size)
+		return 1;
+
+	pal.p = 0;
+	pal.vidc.reg   = regno;
+	pal.vidc.red   = red >> 12;
+	pal.vidc.green = green >> 12;
+	pal.vidc.blue  = blue >> 12;
+
+	current_par.palette[regno] = pal;
+
+	vidc_writel(pal.p);
+
+	return 0;
+}
+#endif
+
+#ifdef HAS_VIDC20
+#include <asm/arch/acornfb.h>
+
+#define MAX_SIZE	2*1024*1024
+
+/* VIDC20 has a different set of rules from the VIDC:
+ *  hcr  : must be multiple of 4
+ *  hswr : must be even
+ *  hdsr : must be even
+ *  hder : must be even
+ *  vcr  : >= 2, (interlace, must be odd)
+ *  vswr : >= 1
+ *  vdsr : >= 1
+ *  vder : >= vdsr
+ */
+static void acornfb_set_timing(struct fb_info *info)
+{
+	struct fb_var_screeninfo *var = &info->var;
+	struct vidc_timing vidc;
+	u_int vcr, fsize;
+	u_int ext_ctl, dat_ctl;
+	u_int words_per_line;
+
+	memset(&vidc, 0, sizeof(vidc));
+
+	vidc.h_sync_width	= var->hsync_len - 8;
+	vidc.h_border_start	= vidc.h_sync_width + var->left_margin + 8 - 12;
+	vidc.h_display_start	= vidc.h_border_start + 12 - 18;
+	vidc.h_display_end	= vidc.h_display_start + var->xres;
+	vidc.h_border_end	= vidc.h_display_end + 18 - 12;
+	vidc.h_cycle		= vidc.h_border_end + var->right_margin + 12 - 8;
+	vidc.h_interlace	= vidc.h_cycle / 2;
+	vidc.v_sync_width	= var->vsync_len - 1;
+	vidc.v_border_start	= vidc.v_sync_width + var->upper_margin;
+	vidc.v_display_start	= vidc.v_border_start;
+	vidc.v_display_end	= vidc.v_display_start + var->yres;
+	vidc.v_border_end	= vidc.v_display_end;
+	vidc.control		= acornfb_default_control();
+
+	vcr = var->vsync_len + var->upper_margin + var->yres +
+	      var->lower_margin;
+
+	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+		vidc.v_cycle = (vcr - 3) / 2;
+		vidc.control |= VIDC20_CTRL_INT;
+	} else
+		vidc.v_cycle = vcr - 2;
+
+	switch (var->bits_per_pixel) {
+	case  1: vidc.control |= VIDC20_CTRL_1BPP;	break;
+	case  2: vidc.control |= VIDC20_CTRL_2BPP;	break;
+	case  4: vidc.control |= VIDC20_CTRL_4BPP;	break;
+	default:
+	case  8: vidc.control |= VIDC20_CTRL_8BPP;	break;
+	case 16: vidc.control |= VIDC20_CTRL_16BPP;	break;
+	case 32: vidc.control |= VIDC20_CTRL_32BPP;	break;
+	}
+
+	acornfb_vidc20_find_rates(&vidc, var);
+	fsize = var->vsync_len + var->upper_margin + var->lower_margin - 1;
+
+	if (memcmp(&current_vidc, &vidc, sizeof(vidc))) {
+		current_vidc = vidc;
+
+		vidc_writel(VIDC20_CTRL| vidc.control);
+		vidc_writel(0xd0000000 | vidc.pll_ctl);
+		vidc_writel(0x80000000 | vidc.h_cycle);
+		vidc_writel(0x81000000 | vidc.h_sync_width);
+		vidc_writel(0x82000000 | vidc.h_border_start);
+		vidc_writel(0x83000000 | vidc.h_display_start);
+		vidc_writel(0x84000000 | vidc.h_display_end);
+		vidc_writel(0x85000000 | vidc.h_border_end);
+		vidc_writel(0x86000000);
+		vidc_writel(0x87000000 | vidc.h_interlace);
+		vidc_writel(0x90000000 | vidc.v_cycle);
+		vidc_writel(0x91000000 | vidc.v_sync_width);
+		vidc_writel(0x92000000 | vidc.v_border_start);
+		vidc_writel(0x93000000 | vidc.v_display_start);
+		vidc_writel(0x94000000 | vidc.v_display_end);
+		vidc_writel(0x95000000 | vidc.v_border_end);
+		vidc_writel(0x96000000);
+		vidc_writel(0x97000000);
+	}
+
+	iomd_writel(fsize, IOMD_FSIZE);
+
+	ext_ctl = acornfb_default_econtrol();
+
+	if (var->sync & FB_SYNC_COMP_HIGH_ACT) /* should be FB_SYNC_COMP */
+		ext_ctl |= VIDC20_ECTL_HS_NCSYNC | VIDC20_ECTL_VS_NCSYNC;
+	else {
+		if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+			ext_ctl |= VIDC20_ECTL_HS_HSYNC;
+		else
+			ext_ctl |= VIDC20_ECTL_HS_NHSYNC;
+
+		if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+			ext_ctl |= VIDC20_ECTL_VS_VSYNC;
+		else
+			ext_ctl |= VIDC20_ECTL_VS_NVSYNC;
+	}
+
+	vidc_writel(VIDC20_ECTL | ext_ctl);
+
+	words_per_line = var->xres * var->bits_per_pixel / 32;
+
+	if (current_par.using_vram && info->fix.smem_len == 2048*1024)
+		words_per_line /= 2;
+
+	/* RiscPC doesn't use the VIDC's VRAM control. */
+	dat_ctl = VIDC20_DCTL_VRAM_DIS | VIDC20_DCTL_SNA | words_per_line;
+
+	/* The data bus width is dependent on both the type
+	 * and amount of video memory.
+	 *     DRAM	32bit low
+	 * 1MB VRAM	32bit
+	 * 2MB VRAM	64bit
+	 */
+	if (current_par.using_vram && current_par.vram_half_sam == 2048)
+		dat_ctl |= VIDC20_DCTL_BUS_D63_0;
+	else
+		dat_ctl |= VIDC20_DCTL_BUS_D31_0;
+
+	vidc_writel(VIDC20_DCTL | dat_ctl);
+
+#ifdef DEBUG_MODE_SELECTION
+	printk(KERN_DEBUG "VIDC registers for %dx%dx%d:\n", var->xres,
+	       var->yres, var->bits_per_pixel);
+	printk(KERN_DEBUG " H-cycle          : %d\n", vidc.h_cycle);
+	printk(KERN_DEBUG " H-sync-width     : %d\n", vidc.h_sync_width);
+	printk(KERN_DEBUG " H-border-start   : %d\n", vidc.h_border_start);
+	printk(KERN_DEBUG " H-display-start  : %d\n", vidc.h_display_start);
+	printk(KERN_DEBUG " H-display-end    : %d\n", vidc.h_display_end);
+	printk(KERN_DEBUG " H-border-end     : %d\n", vidc.h_border_end);
+	printk(KERN_DEBUG " H-interlace      : %d\n", vidc.h_interlace);
+	printk(KERN_DEBUG " V-cycle          : %d\n", vidc.v_cycle);
+	printk(KERN_DEBUG " V-sync-width     : %d\n", vidc.v_sync_width);
+	printk(KERN_DEBUG " V-border-start   : %d\n", vidc.v_border_start);
+	printk(KERN_DEBUG " V-display-start  : %d\n", vidc.v_display_start);
+	printk(KERN_DEBUG " V-display-end    : %d\n", vidc.v_display_end);
+	printk(KERN_DEBUG " V-border-end     : %d\n", vidc.v_border_end);
+	printk(KERN_DEBUG " Ext Ctrl  (C)    : 0x%08X\n", ext_ctl);
+	printk(KERN_DEBUG " PLL Ctrl  (D)    : 0x%08X\n", vidc.pll_ctl);
+	printk(KERN_DEBUG " Ctrl      (E)    : 0x%08X\n", vidc.control);
+	printk(KERN_DEBUG " Data Ctrl (F)    : 0x%08X\n", dat_ctl);
+	printk(KERN_DEBUG " Fsize            : 0x%08X\n", fsize);
+#endif
+}
+
+/*
+ * We have to take note of the VIDC20's 16-bit palette here.
+ * The VIDC20 looks up a 16 bit pixel as follows:
+ *
+ *   bits   111111
+ *          5432109876543210
+ *   red            ++++++++  (8 bits,  7 to 0)
+ *  green       ++++++++      (8 bits, 11 to 4)
+ *   blue   ++++++++          (8 bits, 15 to 8)
+ *
+ * We use a pixel which looks like:
+ *
+ *   bits   111111
+ *          5432109876543210
+ *   red               +++++  (5 bits,  4 to  0)
+ *  green         +++++       (5 bits,  9 to  5)
+ *   blue    +++++            (5 bits, 14 to 10)
+ */
+static int
+acornfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+		  u_int trans, struct fb_info *info)
+{
+	union palette pal;
+
+	if (regno >= current_par.palette_size)
+		return 1;
+
+	if (regno < 16 && info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+		u32 pseudo_val;
+
+		pseudo_val  = regno << info->var.red.offset;
+		pseudo_val |= regno << info->var.green.offset;
+		pseudo_val |= regno << info->var.blue.offset;
+
+		((u32 *)info->pseudo_palette)[regno] = pseudo_val;
+	}
+
+	pal.p = 0;
+	pal.vidc20.red   = red >> 8;
+	pal.vidc20.green = green >> 8;
+	pal.vidc20.blue  = blue >> 8;
+
+	current_par.palette[regno] = pal;
+
+	if (info->var.bits_per_pixel == 16) {
+		int i;
+
+		pal.p = 0;
+		vidc_writel(0x10000000);
+		for (i = 0; i < 256; i += 1) {
+			pal.vidc20.red   = current_par.palette[ i       & 31].vidc20.red;
+			pal.vidc20.green = current_par.palette[(i >> 1) & 31].vidc20.green;
+			pal.vidc20.blue  = current_par.palette[(i >> 2) & 31].vidc20.blue;
+			vidc_writel(pal.p);
+			/* Palette register pointer auto-increments */
+		}
+	} else {
+		vidc_writel(0x10000000 | regno);
+		vidc_writel(pal.p);
+	}
+
+	return 0;
+}
+#endif
+
+/*
+ * Before selecting the timing parameters, adjust
+ * the resolution to fit the rules.
+ */
+static int
+acornfb_adjust_timing(struct fb_info *info, struct fb_var_screeninfo *var, u_int fontht)
+{
+	u_int font_line_len, sam_size, min_size, size, nr_y;
+
+	/* xres must be even */
+	var->xres = (var->xres + 1) & ~1;
+
+	/*
+	 * We don't allow xres_virtual to differ from xres
+	 */
+	var->xres_virtual = var->xres;
+	var->xoffset = 0;
+
+	if (current_par.using_vram)
+		sam_size = current_par.vram_half_sam * 2;
+	else
+		sam_size = 16;
+
+	/*
+	 * Now, find a value for yres_virtual which allows
+	 * us to do ywrap scrolling.  The value of
+	 * yres_virtual must be such that the end of the
+	 * displayable frame buffer must be aligned with
+	 * the start of a font line.
+	 */
+	font_line_len = var->xres * var->bits_per_pixel * fontht / 8;
+	min_size = var->xres * var->yres * var->bits_per_pixel / 8;
+
+	/*
+	 * If minimum screen size is greater than that we have
+	 * available, reject it.
+	 */
+	if (min_size > info->fix.smem_len)
+		return -EINVAL;
+
+	/* Find int 'y', such that y * fll == s * sam < maxsize
+	 * y = s * sam / fll; s = maxsize / sam
+	 */
+	for (size = info->fix.smem_len;
+	     nr_y = size / font_line_len, min_size <= size;
+	     size -= sam_size) {
+		if (nr_y * font_line_len == size)
+			break;
+	}
+	nr_y *= fontht;
+
+	if (var->accel_flags & FB_ACCELF_TEXT) {
+		if (min_size > size) {
+			/*
+			 * failed, use ypan
+			 */
+			size = info->fix.smem_len;
+			var->yres_virtual = size / (font_line_len / fontht);
+		} else
+			var->yres_virtual = nr_y;
+	} else if (var->yres_virtual > nr_y)
+		var->yres_virtual = nr_y;
+
+	current_par.screen_end = info->fix.smem_start + size;
+
+	/*
+	 * Fix yres & yoffset if needed.
+	 */
+	if (var->yres > var->yres_virtual)
+		var->yres = var->yres_virtual;
+
+	if (var->vmode & FB_VMODE_YWRAP) {
+		if (var->yoffset > var->yres_virtual)
+			var->yoffset = var->yres_virtual;
+	} else {
+		if (var->yoffset + var->yres > var->yres_virtual)
+			var->yoffset = var->yres_virtual - var->yres;
+	}
+
+	/* hsync_len must be even */
+	var->hsync_len = (var->hsync_len + 1) & ~1;
+
+#ifdef HAS_VIDC
+	/* left_margin must be odd */
+	if ((var->left_margin & 1) == 0) {
+		var->left_margin -= 1;
+		var->right_margin += 1;
+	}
+
+	/* right_margin must be odd */
+	var->right_margin |= 1;
+#elif defined(HAS_VIDC20)
+	/* left_margin must be even */
+	if (var->left_margin & 1) {
+		var->left_margin += 1;
+		var->right_margin -= 1;
+	}
+
+	/* right_margin must be even */
+	if (var->right_margin & 1)
+		var->right_margin += 1;
+#endif
+
+	if (var->vsync_len < 1)
+		var->vsync_len = 1;
+
+	return 0;
+}
+
+static int
+acornfb_validate_timing(struct fb_var_screeninfo *var,
+			struct fb_monspecs *monspecs)
+{
+	unsigned long hs, vs;
+
+	/*
+	 * hs(Hz) = 10^12 / (pixclock * xtotal)
+	 * vs(Hz) = hs(Hz) / ytotal
+	 *
+	 * No need to do long long divisions or anything
+	 * like that if you factor it correctly
+	 */
+	hs = 1953125000 / var->pixclock;
+	hs = hs * 512 /
+	     (var->xres + var->left_margin + var->right_margin + var->hsync_len);
+	vs = hs /
+	     (var->yres + var->upper_margin + var->lower_margin + var->vsync_len);
+
+	return (vs >= monspecs->vfmin && vs <= monspecs->vfmax &&
+		hs >= monspecs->hfmin && hs <= monspecs->hfmax) ? 0 : -EINVAL;
+}
+
+static inline void
+acornfb_update_dma(struct fb_info *info, struct fb_var_screeninfo *var)
+{
+	u_int off = var->yoffset * info->fix.line_length;
+
+#if defined(HAS_MEMC)
+	memc_write(VDMA_INIT, off >> 2);
+#elif defined(HAS_IOMD)
+	iomd_writel(info->fix.smem_start + off, IOMD_VIDINIT);
+#endif
+}
+
+static int
+acornfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	u_int fontht;
+	int err;
+
+	/*
+	 * FIXME: Find the font height
+	 */
+	fontht = 8;
+
+	var->red.msb_right = 0;
+	var->green.msb_right = 0;
+	var->blue.msb_right = 0;
+	var->transp.msb_right = 0;
+
+	switch (var->bits_per_pixel) {
+	case 1:	case 2:	case 4:	case 8:
+		var->red.offset    = 0;
+		var->red.length    = var->bits_per_pixel;
+		var->green         = var->red;
+		var->blue          = var->red;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		break;
+
+#ifdef HAS_VIDC20
+	case 16:
+		var->red.offset    = 0;
+		var->red.length    = 5;
+		var->green.offset  = 5;
+		var->green.length  = 5;
+		var->blue.offset   = 10;
+		var->blue.length   = 5;
+		var->transp.offset = 15;
+		var->transp.length = 1;
+		break;
+
+	case 32:
+		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 = 4;
+		break;
+#endif
+	default:
+		return -EINVAL;
+	}
+
+	/*
+	 * Check to see if the pixel rate is valid.
+	 */
+	if (!acornfb_valid_pixrate(var))
+		return -EINVAL;
+
+	/*
+	 * Validate and adjust the resolution to
+	 * match the video generator hardware.
+	 */
+	err = acornfb_adjust_timing(info, var, fontht);
+	if (err)
+		return err;
+
+	/*
+	 * Validate the timing against the
+	 * monitor hardware.
+	 */
+	return acornfb_validate_timing(var, &info->monspecs);
+}
+
+static int acornfb_set_par(struct fb_info *info)
+{
+	switch (info->var.bits_per_pixel) {
+	case 1:
+		current_par.palette_size = 2;
+		info->fix.visual = FB_VISUAL_MONO10;
+		break;
+	case 2:
+		current_par.palette_size = 4;
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+		break;
+	case 4:
+		current_par.palette_size = 16;
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+		break;
+	case 8:
+		current_par.palette_size = VIDC_PALETTE_SIZE;
+#ifdef HAS_VIDC
+		info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
+#else
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+#endif
+		break;
+#ifdef HAS_VIDC20
+	case 16:
+		current_par.palette_size = 32;
+		info->fix.visual = FB_VISUAL_DIRECTCOLOR;
+		break;
+	case 32:
+		current_par.palette_size = VIDC_PALETTE_SIZE;
+		info->fix.visual = FB_VISUAL_DIRECTCOLOR;
+		break;
+#endif
+	default:
+		BUG();
+	}
+
+	info->fix.line_length	= (info->var.xres * info->var.bits_per_pixel) / 8;
+
+#if defined(HAS_MEMC)
+	{
+		unsigned long size = info->fix.smem_len - VDMA_XFERSIZE;
+
+		memc_write(VDMA_START, 0);
+		memc_write(VDMA_END, size >> 2);
+	}
+#elif defined(HAS_IOMD)
+	{
+		unsigned long start, size;
+		u_int control;
+
+		start = info->fix.smem_start;
+		size  = current_par.screen_end;
+
+		if (current_par.using_vram) {
+			size -= current_par.vram_half_sam;
+			control = DMA_CR_E | (current_par.vram_half_sam / 256);
+		} else {
+			size -= 16;
+			control = DMA_CR_E | DMA_CR_D | 16;
+		}
+
+		iomd_writel(start,   IOMD_VIDSTART);
+		iomd_writel(size,    IOMD_VIDEND);
+		iomd_writel(control, IOMD_VIDCR);
+	}
+#endif
+
+	acornfb_update_dma(info, &info->var);
+	acornfb_set_timing(info);
+
+	return 0;
+}
+
+static int
+acornfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	u_int y_bottom = var->yoffset;
+
+	if (!(var->vmode & FB_VMODE_YWRAP))
+		y_bottom += var->yres;
+
+	BUG_ON(y_bottom > var->yres_virtual);
+
+	acornfb_update_dma(info, var);
+
+	return 0;
+}
+
+/*
+ * Note that we are entered with the kernel locked.
+ */
+static int
+acornfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+{
+	unsigned long off, start;
+	u32 len;
+
+	off = vma->vm_pgoff << PAGE_SHIFT;
+
+	start = info->fix.smem_start;
+	len = PAGE_ALIGN(start & ~PAGE_MASK) + info->fix.smem_len;
+	start &= PAGE_MASK;
+	if ((vma->vm_end - vma->vm_start + off) > len)
+		return -EINVAL;
+	off += start;
+	vma->vm_pgoff = off >> PAGE_SHIFT;
+
+	/* This is an IO map - tell maydump to skip this VMA */
+	vma->vm_flags |= VM_IO;
+
+	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+	/*
+	 * Don't alter the page protection flags; we want to keep the area
+	 * cached for better performance.  This does mean that we may miss
+	 * some updates to the screen occasionally, but process switches
+	 * should cause the caches and buffers to be flushed often enough.
+	 */
+	if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+				vma->vm_end - vma->vm_start,
+				vma->vm_page_prot))
+		return -EAGAIN;
+	return 0;
+}
+
+static struct fb_ops acornfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= acornfb_check_var,
+	.fb_set_par	= acornfb_set_par,
+	.fb_setcolreg	= acornfb_setcolreg,
+	.fb_pan_display	= acornfb_pan_display,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_mmap	= acornfb_mmap,
+	.fb_cursor	= soft_cursor,
+};
+
+/*
+ * Everything after here is initialisation!!!
+ */
+static struct fb_videomode modedb[] __initdata = {
+	{	/* 320x256 @ 50Hz */
+		NULL, 50,  320,  256, 125000,  92,  62,  35, 19,  38, 2,
+		FB_SYNC_COMP_HIGH_ACT,
+		FB_VMODE_NONINTERLACED
+	}, {	/* 640x250 @ 50Hz, 15.6 kHz hsync */
+		NULL, 50,  640,  250,  62500, 185, 123,  38, 21,  76, 3,
+		0,
+		FB_VMODE_NONINTERLACED
+	}, {	/* 640x256 @ 50Hz, 15.6 kHz hsync */
+		NULL, 50,  640,  256,  62500, 185, 123,  35, 18,  76, 3,
+		0,
+		FB_VMODE_NONINTERLACED
+	}, {	/* 640x512 @ 50Hz, 26.8 kHz hsync */
+		NULL, 50,  640,  512,  41667, 113,  87,  18,  1,  56, 3,
+		0,
+		FB_VMODE_NONINTERLACED
+	}, {	/* 640x250 @ 70Hz, 31.5 kHz hsync */
+		NULL, 70,  640,  250,  39722,  48,  16, 109, 88,  96, 2,
+		0,
+		FB_VMODE_NONINTERLACED
+	}, {	/* 640x256 @ 70Hz, 31.5 kHz hsync */
+		NULL, 70,  640,  256,  39722,  48,  16, 106, 85,  96, 2,
+		0,
+		FB_VMODE_NONINTERLACED
+	}, {	/* 640x352 @ 70Hz, 31.5 kHz hsync */
+		NULL, 70,  640,  352,  39722,  48,  16,  58, 37,  96, 2,
+		0,
+		FB_VMODE_NONINTERLACED
+	}, {	/* 640x480 @ 60Hz, 31.5 kHz hsync */
+		NULL, 60,  640,  480,  39722,  48,  16,  32, 11,  96, 2,
+		0,
+		FB_VMODE_NONINTERLACED
+	}, {	/* 800x600 @ 56Hz, 35.2 kHz hsync */
+		NULL, 56,  800,  600,  27778, 101,  23,  22,  1, 100, 2,
+		0,
+		FB_VMODE_NONINTERLACED
+	}, {	/* 896x352 @ 60Hz, 21.8 kHz hsync */
+		NULL, 60,  896,  352,  41667,  59,  27,   9,  0, 118, 3,
+		0,
+		FB_VMODE_NONINTERLACED
+	}, {	/* 1024x 768 @ 60Hz, 48.4 kHz hsync */
+		NULL, 60, 1024,  768,  15385, 160,  24,  29,  3, 136, 6,
+		0,
+		FB_VMODE_NONINTERLACED
+	}, {	/* 1280x1024 @ 60Hz, 63.8 kHz hsync */
+		NULL, 60, 1280, 1024,   9090, 186,  96,  38,  1, 160, 3,
+		0,
+		FB_VMODE_NONINTERLACED
+	}
+};
+
+static struct fb_videomode __initdata
+acornfb_default_mode = {
+	.name =		NULL,
+	.refresh =	60,
+	.xres =		640,
+	.yres =		480,
+	.pixclock =	39722,
+	.left_margin =	56,
+	.right_margin =	16,
+	.upper_margin =	34,
+	.lower_margin =	9,
+	.hsync_len =	88,
+	.vsync_len =	2,
+	.sync =		0,
+	.vmode =	FB_VMODE_NONINTERLACED
+};
+
+static void __init acornfb_init_fbinfo(void)
+{
+	static int first = 1;
+
+	if (!first)
+		return;
+	first = 0;
+
+	fb_info.fbops		= &acornfb_ops;
+	fb_info.flags		= FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+	fb_info.pseudo_palette	= current_par.pseudo_palette;
+
+	strcpy(fb_info.fix.id, "Acorn");
+	fb_info.fix.type	= FB_TYPE_PACKED_PIXELS;
+	fb_info.fix.type_aux	= 0;
+	fb_info.fix.xpanstep	= 0;
+	fb_info.fix.ypanstep	= 1;
+	fb_info.fix.ywrapstep	= 1;
+	fb_info.fix.line_length	= 0;
+	fb_info.fix.accel	= FB_ACCEL_NONE;
+
+	/*
+	 * setup initial parameters
+	 */
+	memset(&fb_info.var, 0, sizeof(fb_info.var));
+
+#if defined(HAS_VIDC20)
+	fb_info.var.red.length	   = 8;
+	fb_info.var.transp.length  = 4;
+#elif defined(HAS_VIDC)
+	fb_info.var.red.length	   = 4;
+	fb_info.var.transp.length  = 1;
+#endif
+	fb_info.var.green	   = fb_info.var.red;
+	fb_info.var.blue	   = fb_info.var.red;
+	fb_info.var.nonstd	   = 0;
+	fb_info.var.activate	   = FB_ACTIVATE_NOW;
+	fb_info.var.height	   = -1;
+	fb_info.var.width	   = -1;
+	fb_info.var.vmode	   = FB_VMODE_NONINTERLACED;
+	fb_info.var.accel_flags	   = FB_ACCELF_TEXT;
+
+	current_par.dram_size	   = 0;
+	current_par.montype	   = -1;
+	current_par.dpms	   = 0;
+}
+
+/*
+ * setup acornfb options:
+ *
+ *  mon:hmin-hmax:vmin-vmax:dpms:width:height
+ *	Set monitor parameters:
+ *		hmin   = horizontal minimum frequency (Hz)
+ *		hmax   = horizontal maximum frequency (Hz)	(optional)
+ *		vmin   = vertical minimum frequency (Hz)
+ *		vmax   = vertical maximum frequency (Hz)	(optional)
+ *		dpms   = DPMS supported?			(optional)
+ *		width  = width of picture in mm.		(optional)
+ *		height = height of picture in mm.		(optional)
+ *
+ * montype:type
+ *	Set RISC-OS style monitor type:
+ *		0 (or tv)	- TV frequency
+ *		1 (or multi)	- Multi frequency
+ *		2 (or hires)	- Hi-res monochrome
+ *		3 (or vga)	- VGA
+ *		4 (or svga)	- SVGA
+ *		auto, or option missing
+ *				- try hardware detect
+ *
+ * dram:size
+ *	Set the amount of DRAM to use for the frame buffer
+ *	(even if you have VRAM).
+ *	size can optionally be followed by 'M' or 'K' for
+ *	MB or KB respectively.
+ */
+static void __init
+acornfb_parse_mon(char *opt)
+{
+	char *p = opt;
+
+	current_par.montype = -2;
+
+	fb_info.monspecs.hfmin = simple_strtoul(p, &p, 0);
+	if (*p == '-')
+		fb_info.monspecs.hfmax = simple_strtoul(p + 1, &p, 0);
+	else
+		fb_info.monspecs.hfmax = fb_info.monspecs.hfmin;
+
+	if (*p != ':')
+		goto bad;
+
+	fb_info.monspecs.vfmin = simple_strtoul(p + 1, &p, 0);
+	if (*p == '-')
+		fb_info.monspecs.vfmax = simple_strtoul(p + 1, &p, 0);
+	else
+		fb_info.monspecs.vfmax = fb_info.monspecs.vfmin;
+
+	if (*p != ':')
+		goto check_values;
+
+	fb_info.monspecs.dpms = simple_strtoul(p + 1, &p, 0);
+
+	if (*p != ':')
+		goto check_values;
+
+	fb_info.var.width = simple_strtoul(p + 1, &p, 0);
+
+	if (*p != ':')
+		goto check_values;
+
+	fb_info.var.height = simple_strtoul(p + 1, NULL, 0);
+
+check_values:
+	if (fb_info.monspecs.hfmax < fb_info.monspecs.hfmin ||
+	    fb_info.monspecs.vfmax < fb_info.monspecs.vfmin)
+		goto bad;
+	return;
+
+bad:
+	printk(KERN_ERR "Acornfb: bad monitor settings: %s\n", opt);
+	current_par.montype = -1;
+}
+
+static void __init
+acornfb_parse_montype(char *opt)
+{
+	current_par.montype = -2;
+
+	if (strncmp(opt, "tv", 2) == 0) {
+		opt += 2;
+		current_par.montype = 0;
+	} else if (strncmp(opt, "multi", 5) == 0) {
+		opt += 5;
+		current_par.montype = 1;
+	} else if (strncmp(opt, "hires", 5) == 0) {
+		opt += 5;
+		current_par.montype = 2;
+	} else if (strncmp(opt, "vga", 3) == 0) {
+		opt += 3;
+		current_par.montype = 3;
+	} else if (strncmp(opt, "svga", 4) == 0) {
+		opt += 4;
+		current_par.montype = 4;
+	} else if (strncmp(opt, "auto", 4) == 0) {
+		opt += 4;
+		current_par.montype = -1;
+	} else if (isdigit(*opt))
+		current_par.montype = simple_strtoul(opt, &opt, 0);
+
+	if (current_par.montype == -2 ||
+	    current_par.montype > NR_MONTYPES) {
+		printk(KERN_ERR "acornfb: unknown monitor type: %s\n",
+			opt);
+		current_par.montype = -1;
+	} else
+	if (opt && *opt) {
+		if (strcmp(opt, ",dpms") == 0)
+			current_par.dpms = 1;
+		else
+			printk(KERN_ERR
+			       "acornfb: unknown monitor option: %s\n",
+			       opt);
+	}
+}
+
+static void __init
+acornfb_parse_dram(char *opt)
+{
+	unsigned int size;
+
+	size = simple_strtoul(opt, &opt, 0);
+
+	if (opt) {
+		switch (*opt) {
+		case 'M':
+		case 'm':
+			size *= 1024;
+		case 'K':
+		case 'k':
+			size *= 1024;
+		default:
+			break;
+		}
+	}
+
+	current_par.dram_size = size;
+}
+
+static struct options {
+	char *name;
+	void (*parse)(char *opt);
+} opt_table[] __initdata = {
+	{ "mon",     acornfb_parse_mon     },
+	{ "montype", acornfb_parse_montype },
+	{ "dram",    acornfb_parse_dram    },
+	{ NULL, NULL }
+};
+
+int __init
+acornfb_setup(char *options)
+{
+	struct options *optp;
+	char *opt;
+
+	if (!options || !*options)
+		return 0;
+
+	acornfb_init_fbinfo();
+
+	while ((opt = strsep(&options, ",")) != NULL) {
+		if (!*opt)
+			continue;
+
+		for (optp = opt_table; optp->name; optp++) {
+			int optlen;
+
+			optlen = strlen(optp->name);
+
+			if (strncmp(opt, optp->name, optlen) == 0 &&
+			    opt[optlen] == ':') {
+				optp->parse(opt + optlen + 1);
+				break;
+			}
+		}
+
+		if (!optp->name)
+			printk(KERN_ERR "acornfb: unknown parameter: %s\n",
+			       opt);
+	}
+	return 0;
+}
+
+/*
+ * Detect type of monitor connected
+ *  For now, we just assume SVGA
+ */
+static int __init
+acornfb_detect_monitortype(void)
+{
+	return 4;
+}
+
+/*
+ * This enables the unused memory to be freed on older Acorn machines.
+ * We are freeing memory on behalf of the architecture initialisation
+ * code here.
+ */
+static inline void
+free_unused_pages(unsigned int virtual_start, unsigned int virtual_end)
+{
+	int mb_freed = 0;
+
+	/*
+	 * Align addresses
+	 */
+	virtual_start = PAGE_ALIGN(virtual_start);
+	virtual_end = PAGE_ALIGN(virtual_end);
+
+	while (virtual_start < virtual_end) {
+		struct page *page;
+
+		/*
+		 * Clear page reserved bit,
+		 * set count to 1, and free
+		 * the page.
+		 */
+		page = virt_to_page(virtual_start);
+		ClearPageReserved(page);
+		set_page_count(page, 1);
+		free_page(virtual_start);
+
+		virtual_start += PAGE_SIZE;
+		mb_freed += PAGE_SIZE / 1024;
+	}
+
+	printk("acornfb: freed %dK memory\n", mb_freed);
+}
+
+static int __init acornfb_probe(struct device *dev)
+{
+	unsigned long size;
+	u_int h_sync, v_sync;
+	int rc, i;
+	char *option = NULL;
+
+	if (fb_get_options("acornfb", &option))
+		return -ENODEV;
+	acornfb_setup(option);
+
+	acornfb_init_fbinfo();
+
+	current_par.dev = dev;
+
+	if (current_par.montype == -1)
+		current_par.montype = acornfb_detect_monitortype();
+
+	if (current_par.montype == -1 || current_par.montype > NR_MONTYPES)
+		current_par.montype = 4;
+
+	if (current_par.montype >= 0) {
+		fb_info.monspecs = monspecs[current_par.montype];
+		fb_info.monspecs.dpms = current_par.dpms;
+	}
+
+	/*
+	 * Try to select a suitable default mode
+	 */
+	for (i = 0; i < sizeof(modedb) / sizeof(*modedb); i++) {
+		unsigned long hs;
+
+		hs = modedb[i].refresh *
+		     (modedb[i].yres + modedb[i].upper_margin +
+		      modedb[i].lower_margin + modedb[i].vsync_len);
+		if (modedb[i].xres == DEFAULT_XRES &&
+		    modedb[i].yres == DEFAULT_YRES &&
+		    modedb[i].refresh >= fb_info.monspecs.vfmin &&
+		    modedb[i].refresh <= fb_info.monspecs.vfmax &&
+		    hs                >= fb_info.monspecs.hfmin &&
+		    hs                <= fb_info.monspecs.hfmax) {
+			acornfb_default_mode = modedb[i];
+			break;
+		}
+	}
+
+	fb_info.screen_base    = (char *)SCREEN_BASE;
+	fb_info.fix.smem_start = SCREEN_START;
+	current_par.using_vram = 0;
+
+	/*
+	 * If vram_size is set, we are using VRAM in
+	 * a Risc PC.  However, if the user has specified
+	 * an amount of DRAM then use that instead.
+	 */
+	if (vram_size && !current_par.dram_size) {
+		size = vram_size;
+		current_par.vram_half_sam = vram_size / 1024;
+		current_par.using_vram = 1;
+	} else if (current_par.dram_size)
+		size = current_par.dram_size;
+	else
+		size = MAX_SIZE;
+
+	/*
+	 * Limit maximum screen size.
+	 */
+	if (size > MAX_SIZE)
+		size = MAX_SIZE;
+
+	size = PAGE_ALIGN(size);
+
+#if defined(HAS_VIDC20)
+	if (!current_par.using_vram) {
+		dma_addr_t handle;
+		void *base;
+
+		/*
+		 * RiscPC needs to allocate the DRAM memory
+		 * for the framebuffer if we are not using
+		 * VRAM.
+		 */
+		base = dma_alloc_writecombine(current_par.dev, size, &handle,
+					      GFP_KERNEL);
+		if (base == NULL) {
+			printk(KERN_ERR "acornfb: unable to allocate screen "
+			       "memory\n");
+			return -ENOMEM;
+		}
+
+		fb_info.screen_base = base;
+		fb_info.fix.smem_start = handle;
+	}
+#endif
+#if defined(HAS_VIDC)
+	/*
+	 * Archimedes/A5000 machines use a fixed address for their
+	 * framebuffers.  Free unused pages
+	 */
+	free_unused_pages(PAGE_OFFSET + size, PAGE_OFFSET + MAX_SIZE);
+#endif
+	
+	fb_info.fix.smem_len = size;
+	current_par.palette_size   = VIDC_PALETTE_SIZE;
+
+	/*
+	 * Lookup the timing for this resolution.  If we can't
+	 * find it, then we can't restore it if we change
+	 * the resolution, so we disable this feature.
+	 */
+	do {
+		rc = fb_find_mode(&fb_info.var, &fb_info, NULL, modedb,
+				 sizeof(modedb) / sizeof(*modedb),
+				 &acornfb_default_mode, DEFAULT_BPP);
+		/*
+		 * If we found an exact match, all ok.
+		 */
+		if (rc == 1)
+			break;
+
+		rc = fb_find_mode(&fb_info.var, &fb_info, NULL, NULL, 0,
+				  &acornfb_default_mode, DEFAULT_BPP);
+		/*
+		 * If we found an exact match, all ok.
+		 */
+		if (rc == 1)
+			break;
+
+		rc = fb_find_mode(&fb_info.var, &fb_info, NULL, modedb,
+				 sizeof(modedb) / sizeof(*modedb),
+				 &acornfb_default_mode, DEFAULT_BPP);
+		if (rc)
+			break;
+
+		rc = fb_find_mode(&fb_info.var, &fb_info, NULL, NULL, 0,
+				  &acornfb_default_mode, DEFAULT_BPP);
+	} while (0);
+
+	/*
+	 * If we didn't find an exact match, try the
+	 * generic database.
+	 */
+	if (rc == 0) {
+		printk("Acornfb: no valid mode found\n");
+		return -EINVAL;
+	}
+
+	h_sync = 1953125000 / fb_info.var.pixclock;
+	h_sync = h_sync * 512 / (fb_info.var.xres + fb_info.var.left_margin +
+		 fb_info.var.right_margin + fb_info.var.hsync_len);
+	v_sync = h_sync / (fb_info.var.yres + fb_info.var.upper_margin +
+		 fb_info.var.lower_margin + fb_info.var.vsync_len);
+
+	printk(KERN_INFO "Acornfb: %dkB %cRAM, %s, using %dx%d, "
+		"%d.%03dkHz, %dHz\n",
+		fb_info.fix.smem_len / 1024,
+		current_par.using_vram ? 'V' : 'D',
+		VIDC_NAME, fb_info.var.xres, fb_info.var.yres,
+		h_sync / 1000, h_sync % 1000, v_sync);
+
+	printk(KERN_INFO "Acornfb: Monitor: %d.%03d-%d.%03dkHz, %d-%dHz%s\n",
+		fb_info.monspecs.hfmin / 1000, fb_info.monspecs.hfmin % 1000,
+		fb_info.monspecs.hfmax / 1000, fb_info.monspecs.hfmax % 1000,
+		fb_info.monspecs.vfmin, fb_info.monspecs.vfmax,
+		fb_info.monspecs.dpms ? ", DPMS" : "");
+
+	if (fb_set_var(&fb_info, &fb_info.var))
+		printk(KERN_ERR "Acornfb: unable to set display parameters\n");
+
+	if (register_framebuffer(&fb_info) < 0)
+		return -EINVAL;
+	return 0;
+}
+
+static struct device_driver acornfb_driver = {
+	.name	= "acornfb",
+	.bus	= &platform_bus_type,
+	.probe	= acornfb_probe,
+};
+
+static int __init acornfb_init(void)
+{
+	return driver_register(&acornfb_driver);
+}
+
+module_init(acornfb_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("VIDC 1/1a/20 framebuffer driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/acornfb.h b/drivers/video/acornfb.h
new file mode 100644
index 0000000..fb2a7ff
--- /dev/null
+++ b/drivers/video/acornfb.h
@@ -0,0 +1,198 @@
+/*
+ *  linux/drivers/video/acornfb.h
+ *
+ *  Copyright (C) 1998,1999 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Frame buffer code for Acorn platforms
+ */
+#if defined(HAS_VIDC20)
+#include <asm/hardware/iomd.h>
+#define VIDC_PALETTE_SIZE	256
+#define VIDC_NAME		"VIDC20"
+#elif defined(HAS_VIDC)
+#include <asm/hardware/memc.h>
+#define VIDC_PALETTE_SIZE	16
+#define VIDC_NAME		"VIDC"
+#endif
+
+#define EXTEND8(x) ((x)|(x)<<8)
+#define EXTEND4(x) ((x)|(x)<<4|(x)<<8|(x)<<12)
+
+struct vidc20_palette {
+	u_int red:8;
+	u_int green:8;
+	u_int blue:8;
+	u_int ext:4;
+	u_int unused:4;
+};
+
+struct vidc_palette {
+	u_int red:4;
+	u_int green:4;
+	u_int blue:4;
+	u_int trans:1;
+	u_int sbz1:13;
+	u_int reg:4;
+	u_int sbz2:2;
+};
+
+union palette {
+	struct vidc20_palette	vidc20;
+	struct vidc_palette	vidc;
+	u_int	p;
+};
+
+struct acornfb_par {
+	struct device	*dev;
+	unsigned long	screen_end;
+	unsigned int	dram_size;
+	unsigned int	vram_half_sam;
+	unsigned int	palette_size;
+	  signed int	montype;
+	unsigned int	using_vram	: 1;
+	unsigned int	dpms		: 1;
+
+	union palette palette[VIDC_PALETTE_SIZE];
+
+	u32		pseudo_palette[16];
+};
+
+struct vidc_timing {
+	u_int	h_cycle;
+	u_int	h_sync_width;
+	u_int	h_border_start;
+	u_int	h_display_start;
+	u_int	h_display_end;
+	u_int	h_border_end;
+	u_int	h_interlace;
+
+	u_int	v_cycle;
+	u_int	v_sync_width;
+	u_int	v_border_start;
+	u_int	v_display_start;
+	u_int	v_display_end;
+	u_int	v_border_end;
+
+	u_int	control;
+
+	/* VIDC20 only */
+	u_int	pll_ctl;
+};
+
+struct modey_params {
+	u_int	y_res;
+	u_int	u_margin;
+	u_int	b_margin;
+	u_int	vsync_len;
+	u_int	vf;
+};
+
+struct modex_params {
+	u_int	x_res;
+	u_int	l_margin;
+	u_int	r_margin;
+	u_int	hsync_len;
+	u_int	clock;
+	u_int	hf;
+	const struct modey_params *modey;
+};
+
+#ifdef HAS_VIDC
+
+#define VID_CTL_VS_NVSYNC	(1 << 3)
+#define VID_CTL_HS_NHSYNC	(1 << 2)
+#define VID_CTL_24MHz		(0)
+#define VID_CTL_25MHz		(1)
+#define VID_CTL_36MHz		(2)
+
+#define VIDC_CTRL_CSYNC		(1 << 7)
+#define VIDC_CTRL_INTERLACE	(1 << 6)
+#define VIDC_CTRL_FIFO_0_4	(0 << 4)
+#define VIDC_CTRL_FIFO_1_5	(1 << 4)
+#define VIDC_CTRL_FIFO_2_6	(2 << 4)
+#define VIDC_CTRL_FIFO_3_7	(3 << 4)
+#define VIDC_CTRL_1BPP		(0 << 2)
+#define VIDC_CTRL_2BPP		(1 << 2)
+#define VIDC_CTRL_4BPP		(2 << 2)
+#define VIDC_CTRL_8BPP		(3 << 2)
+#define VIDC_CTRL_DIV3		(0 << 0)
+#define VIDC_CTRL_DIV2		(1 << 0)
+#define VIDC_CTRL_DIV1_5	(2 << 0)
+#define VIDC_CTRL_DIV1		(3 << 0)
+
+#endif
+
+#ifdef HAS_VIDC20
+/*
+ * VIDC20 registers
+ */
+#define VIDC20_CTRL		0xe0000000
+#define VIDC20_CTRL_PIX_VCLK	(0 << 0)
+#define VIDC20_CTRL_PIX_HCLK	(1 << 0)
+#define VIDC20_CTRL_PIX_RCLK	(2 << 0)
+#define VIDC20_CTRL_PIX_CK	(0 << 2)
+#define VIDC20_CTRL_PIX_CK2	(1 << 2)
+#define VIDC20_CTRL_PIX_CK3	(2 << 2)
+#define VIDC20_CTRL_PIX_CK4	(3 << 2)
+#define VIDC20_CTRL_PIX_CK5	(4 << 2)
+#define VIDC20_CTRL_PIX_CK6	(5 << 2)
+#define VIDC20_CTRL_PIX_CK7	(6 << 2)
+#define VIDC20_CTRL_PIX_CK8	(7 << 2)
+#define VIDC20_CTRL_1BPP	(0 << 5)
+#define VIDC20_CTRL_2BPP	(1 << 5)
+#define VIDC20_CTRL_4BPP	(2 << 5)
+#define VIDC20_CTRL_8BPP	(3 << 5)
+#define VIDC20_CTRL_16BPP	(4 << 5)
+#define VIDC20_CTRL_32BPP	(6 << 5)
+#define VIDC20_CTRL_FIFO_NS	(0 << 8)
+#define VIDC20_CTRL_FIFO_4	(1 << 8)
+#define VIDC20_CTRL_FIFO_8	(2 << 8)
+#define VIDC20_CTRL_FIFO_12	(3 << 8)
+#define VIDC20_CTRL_FIFO_16	(4 << 8)
+#define VIDC20_CTRL_FIFO_20	(5 << 8)
+#define VIDC20_CTRL_FIFO_24	(6 << 8)
+#define VIDC20_CTRL_FIFO_28	(7 << 8)
+#define VIDC20_CTRL_INT		(1 << 12)
+#define VIDC20_CTRL_DUP		(1 << 13)
+#define VIDC20_CTRL_PDOWN	(1 << 14)
+
+#define VIDC20_ECTL		0xc0000000
+#define VIDC20_ECTL_REG(x)	((x) & 0xf3)
+#define VIDC20_ECTL_ECK		(1 << 2)
+#define VIDC20_ECTL_REDPED	(1 << 8)
+#define VIDC20_ECTL_GREENPED	(1 << 9)
+#define VIDC20_ECTL_BLUEPED	(1 << 10)
+#define VIDC20_ECTL_DAC		(1 << 12)
+#define VIDC20_ECTL_LCDGS	(1 << 13)
+#define VIDC20_ECTL_HRM		(1 << 14)
+
+#define VIDC20_ECTL_HS_MASK	(3 << 16)
+#define VIDC20_ECTL_HS_HSYNC	(0 << 16)
+#define VIDC20_ECTL_HS_NHSYNC	(1 << 16)
+#define VIDC20_ECTL_HS_CSYNC	(2 << 16)
+#define VIDC20_ECTL_HS_NCSYNC	(3 << 16)
+
+#define VIDC20_ECTL_VS_MASK	(3 << 18)
+#define VIDC20_ECTL_VS_VSYNC	(0 << 18)
+#define VIDC20_ECTL_VS_NVSYNC	(1 << 18)
+#define VIDC20_ECTL_VS_CSYNC	(2 << 18)
+#define VIDC20_ECTL_VS_NCSYNC	(3 << 18)
+
+#define VIDC20_DCTL		0xf0000000
+/* 0-9 = number of words in scanline */
+#define VIDC20_DCTL_SNA		(1 << 12)
+#define VIDC20_DCTL_HDIS	(1 << 13)
+#define VIDC20_DCTL_BUS_NS	(0 << 16)
+#define VIDC20_DCTL_BUS_D31_0	(1 << 16)
+#define VIDC20_DCTL_BUS_D63_32	(2 << 16)
+#define VIDC20_DCTL_BUS_D63_0	(3 << 16)
+#define VIDC20_DCTL_VRAM_DIS	(0 << 18)
+#define VIDC20_DCTL_VRAM_PXCLK	(1 << 18)
+#define VIDC20_DCTL_VRAM_PXCLK2	(2 << 18)
+#define VIDC20_DCTL_VRAM_PXCLK4	(3 << 18)
+
+#endif
diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c
new file mode 100644
index 0000000..acdba0c
--- /dev/null
+++ b/drivers/video/amba-clcd.c
@@ -0,0 +1,533 @@
+/*
+ *  linux/drivers/video/amba-clcd.c
+ *
+ * Copyright (C) 2001 ARM Limited, by David A Rusling
+ * Updated to 2.5, Deep Blue Solutions Ltd.
+ *
+ * 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.
+ *
+ *  ARM PrimeCell PL110 Color LCD Controller
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/list.h>
+
+#include <asm/hardware/amba.h>
+#include <asm/hardware/clock.h>
+
+#include <asm/hardware/amba_clcd.h>
+
+#define to_clcd(info)	container_of(info, struct clcd_fb, fb)
+
+/* This is limited to 16 characters when displayed by X startup */
+static const char *clcd_name = "CLCD FB";
+
+/*
+ * Unfortunately, the enable/disable functions may be called either from
+ * process or IRQ context, and we _need_ to delay.  This is _not_ good.
+ */
+static inline void clcdfb_sleep(unsigned int ms)
+{
+	if (in_atomic()) {
+		mdelay(ms);
+	} else {
+		msleep(ms);
+	}
+}
+
+static inline void clcdfb_set_start(struct clcd_fb *fb)
+{
+	unsigned long ustart = fb->fb.fix.smem_start;
+	unsigned long lstart;
+
+	ustart += fb->fb.var.yoffset * fb->fb.fix.line_length;
+	lstart = ustart + fb->fb.var.yres * fb->fb.fix.line_length / 2;
+
+	writel(ustart, fb->regs + CLCD_UBAS);
+	writel(lstart, fb->regs + CLCD_LBAS);
+}
+
+static void clcdfb_disable(struct clcd_fb *fb)
+{
+	u32 val;
+
+	if (fb->board->disable)
+		fb->board->disable(fb);
+
+	val = readl(fb->regs + CLCD_CNTL);
+	if (val & CNTL_LCDPWR) {
+		val &= ~CNTL_LCDPWR;
+		writel(val, fb->regs + CLCD_CNTL);
+
+		clcdfb_sleep(20);
+	}
+	if (val & CNTL_LCDEN) {
+		val &= ~CNTL_LCDEN;
+		writel(val, fb->regs + CLCD_CNTL);
+	}
+
+	/*
+	 * Disable CLCD clock source.
+	 */
+	clk_disable(fb->clk);
+}
+
+static void clcdfb_enable(struct clcd_fb *fb, u32 cntl)
+{
+	/*
+	 * Enable the CLCD clock source.
+	 */
+	clk_enable(fb->clk);
+
+	/*
+	 * Bring up by first enabling..
+	 */
+	cntl |= CNTL_LCDEN;
+	writel(cntl, fb->regs + CLCD_CNTL);
+
+	clcdfb_sleep(20);
+
+	/*
+	 * and now apply power.
+	 */
+	cntl |= CNTL_LCDPWR;
+	writel(cntl, fb->regs + CLCD_CNTL);
+
+	/*
+	 * finally, enable the interface.
+	 */
+	if (fb->board->enable)
+		fb->board->enable(fb);
+}
+
+static int
+clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var)
+{
+	int ret = 0;
+
+	memset(&var->transp, 0, sizeof(var->transp));
+	memset(&var->red, 0, sizeof(var->red));
+	memset(&var->green, 0, sizeof(var->green));
+	memset(&var->blue, 0, sizeof(var->blue));
+
+	switch (var->bits_per_pixel) {
+	case 1:
+	case 2:
+	case 4:
+	case 8:
+		var->red.length		= 8;
+		var->red.offset		= 0;
+		var->green.length	= 8;
+		var->green.offset	= 0;
+		var->blue.length	= 8;
+		var->blue.offset	= 0;
+		break;
+	case 16:
+		var->red.length		= 5;
+		var->green.length	= 5;
+		var->blue.length	= 5;
+		if (fb->panel->cntl & CNTL_BGR) {
+			var->red.offset		= 10;
+			var->green.offset	= 5;
+			var->blue.offset	= 0;
+		} else {
+			var->red.offset		= 0;
+			var->green.offset	= 5;
+			var->blue.offset	= 10;
+		}
+		break;
+	case 24:
+		if (fb->panel->cntl & CNTL_LCDTFT) {
+			var->red.length		= 8;
+			var->green.length	= 8;
+			var->blue.length	= 8;
+
+			if (fb->panel->cntl & CNTL_BGR) {
+				var->red.offset		= 16;
+				var->green.offset	= 8;
+				var->blue.offset	= 0;
+			} else {
+				var->red.offset		= 0;
+				var->green.offset	= 8;
+				var->blue.offset	= 16;
+			}
+			break;
+		}
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int clcdfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct clcd_fb *fb = to_clcd(info);
+	int ret = -EINVAL;
+
+	if (fb->board->check)
+		ret = fb->board->check(fb, var);
+	if (ret == 0)
+		ret = clcdfb_set_bitfields(fb, var);
+
+	return ret;
+}
+
+static int clcdfb_set_par(struct fb_info *info)
+{
+	struct clcd_fb *fb = to_clcd(info);
+	struct clcd_regs regs;
+
+	fb->fb.fix.line_length = fb->fb.var.xres_virtual *
+				 fb->fb.var.bits_per_pixel / 8;
+
+	if (fb->fb.var.bits_per_pixel <= 8)
+		fb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
+	else
+		fb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+
+	fb->board->decode(fb, &regs);
+
+	clcdfb_disable(fb);
+
+	writel(regs.tim0, fb->regs + CLCD_TIM0);
+	writel(regs.tim1, fb->regs + CLCD_TIM1);
+	writel(regs.tim2, fb->regs + CLCD_TIM2);
+	writel(regs.tim3, fb->regs + CLCD_TIM3);
+
+	clcdfb_set_start(fb);
+
+	clk_set_rate(fb->clk, (1000000000 / regs.pixclock) * 1000);
+
+	fb->clcd_cntl = regs.cntl;
+
+	clcdfb_enable(fb, regs.cntl);
+
+#ifdef DEBUG
+	printk(KERN_INFO "CLCD: Registers set to\n"
+	       KERN_INFO "  %08x %08x %08x %08x\n"
+	       KERN_INFO "  %08x %08x %08x %08x\n",
+		readl(fb->regs + CLCD_TIM0), readl(fb->regs + CLCD_TIM1),
+		readl(fb->regs + CLCD_TIM2), readl(fb->regs + CLCD_TIM3),
+		readl(fb->regs + CLCD_UBAS), readl(fb->regs + CLCD_LBAS),
+		readl(fb->regs + CLCD_IENB), readl(fb->regs + CLCD_CNTL));
+#endif
+
+	return 0;
+}
+
+static inline u32 convert_bitfield(int val, struct fb_bitfield *bf)
+{
+	unsigned int mask = (1 << bf->length) - 1;
+
+	return (val >> (16 - bf->length) & mask) << bf->offset;
+}
+
+/*
+ *  Set a single color register. The values supplied have a 16 bit
+ *  magnitude.  Return != 0 for invalid regno.
+ */
+static int
+clcdfb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
+		 unsigned int blue, unsigned int transp, struct fb_info *info)
+{
+	struct clcd_fb *fb = to_clcd(info);
+
+	if (regno < 16)
+		fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) |
+				  convert_bitfield(blue, &fb->fb.var.blue) |
+				  convert_bitfield(green, &fb->fb.var.green) |
+				  convert_bitfield(red, &fb->fb.var.red);
+
+	if (fb->fb.var.bits_per_pixel == 8 && regno < 256) {
+		int hw_reg = CLCD_PALETTE + ((regno * 2) & ~3);
+		u32 val, mask, newval;
+
+		newval  = (red >> 11)  & 0x001f;
+		newval |= (green >> 6) & 0x03e0;
+		newval |= (blue >> 1)  & 0x7c00;
+
+		/*
+		 * 3.2.11: if we're configured for big endian
+		 * byte order, the palette entries are swapped.
+		 */
+		if (fb->clcd_cntl & CNTL_BEBO)
+			regno ^= 1;
+
+		if (regno & 1) {
+			newval <<= 16;
+			mask = 0x0000ffff;
+		} else {
+			mask = 0xffff0000;
+		}
+
+		val = readl(fb->regs + hw_reg) & mask;
+		writel(val | newval, fb->regs + hw_reg);
+	}
+
+	return regno > 255;
+}
+
+/*
+ *  Blank the screen if blank_mode != 0, else unblank. If blank == NULL
+ *  then the caller blanks by setting the CLUT (Color Look Up Table) to all
+ *  black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
+ *  to e.g. a video mode which doesn't support it. Implements VESA suspend
+ *  and powerdown modes on hardware that supports disabling hsync/vsync:
+ *    blank_mode == 2: suspend vsync
+ *    blank_mode == 3: suspend hsync
+ *    blank_mode == 4: powerdown
+ */
+static int clcdfb_blank(int blank_mode, struct fb_info *info)
+{
+	struct clcd_fb *fb = to_clcd(info);
+
+	if (blank_mode != 0) {
+		clcdfb_disable(fb);
+	} else {
+		clcdfb_enable(fb, fb->clcd_cntl);
+	}
+	return 0;
+}
+
+static int clcdfb_mmap(struct fb_info *info, struct file *file,
+		       struct vm_area_struct *vma)
+{
+	struct clcd_fb *fb = to_clcd(info);
+	unsigned long len, off = vma->vm_pgoff << PAGE_SHIFT;
+	int ret = -EINVAL;
+
+	len = info->fix.smem_len;
+
+	if (off <= len && vma->vm_end - vma->vm_start <= len - off &&
+	    fb->board->mmap)
+		ret = fb->board->mmap(fb, vma);
+
+	return ret;
+}
+
+static struct fb_ops clcdfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= clcdfb_check_var,
+	.fb_set_par	= clcdfb_set_par,
+	.fb_setcolreg	= clcdfb_setcolreg,
+	.fb_blank	= clcdfb_blank,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+	.fb_mmap	= clcdfb_mmap,
+};
+
+static int clcdfb_register(struct clcd_fb *fb)
+{
+	int ret;
+
+	fb->clk = clk_get(&fb->dev->dev, "CLCDCLK");
+	if (IS_ERR(fb->clk)) {
+		ret = PTR_ERR(fb->clk);
+		goto out;
+	}
+
+	ret = clk_use(fb->clk);
+	if (ret)
+		goto free_clk;
+
+	fb->fb.fix.mmio_start	= fb->dev->res.start;
+	fb->fb.fix.mmio_len	= SZ_4K;
+
+	fb->regs = ioremap(fb->fb.fix.mmio_start, fb->fb.fix.mmio_len);
+	if (!fb->regs) {
+		printk(KERN_ERR "CLCD: unable to remap registers\n");
+		ret = -ENOMEM;
+		goto unuse_clk;
+	}
+
+	fb->fb.fbops		= &clcdfb_ops;
+	fb->fb.flags		= FBINFO_FLAG_DEFAULT;
+	fb->fb.pseudo_palette	= fb->cmap;
+
+	strncpy(fb->fb.fix.id, clcd_name, sizeof(fb->fb.fix.id));
+	fb->fb.fix.type		= FB_TYPE_PACKED_PIXELS;
+	fb->fb.fix.type_aux	= 0;
+	fb->fb.fix.xpanstep	= 0;
+	fb->fb.fix.ypanstep	= 0;
+	fb->fb.fix.ywrapstep	= 0;
+	fb->fb.fix.accel	= FB_ACCEL_NONE;
+
+	fb->fb.var.xres		= fb->panel->mode.xres;
+	fb->fb.var.yres		= fb->panel->mode.yres;
+	fb->fb.var.xres_virtual	= fb->panel->mode.xres;
+	fb->fb.var.yres_virtual	= fb->panel->mode.yres;
+	fb->fb.var.bits_per_pixel = fb->panel->bpp;
+	fb->fb.var.grayscale	= fb->panel->grayscale;
+	fb->fb.var.pixclock	= fb->panel->mode.pixclock;
+	fb->fb.var.left_margin	= fb->panel->mode.left_margin;
+	fb->fb.var.right_margin	= fb->panel->mode.right_margin;
+	fb->fb.var.upper_margin	= fb->panel->mode.upper_margin;
+	fb->fb.var.lower_margin	= fb->panel->mode.lower_margin;
+	fb->fb.var.hsync_len	= fb->panel->mode.hsync_len;
+	fb->fb.var.vsync_len	= fb->panel->mode.vsync_len;
+	fb->fb.var.sync		= fb->panel->mode.sync;
+	fb->fb.var.vmode	= fb->panel->mode.vmode;
+	fb->fb.var.activate	= FB_ACTIVATE_NOW;
+	fb->fb.var.nonstd	= 0;
+	fb->fb.var.height	= fb->panel->height;
+	fb->fb.var.width	= fb->panel->width;
+	fb->fb.var.accel_flags	= 0;
+
+	fb->fb.monspecs.hfmin	= 0;
+	fb->fb.monspecs.hfmax   = 100000;
+	fb->fb.monspecs.vfmin	= 0;
+	fb->fb.monspecs.vfmax	= 400;
+	fb->fb.monspecs.dclkmin = 1000000;
+	fb->fb.monspecs.dclkmax	= 100000000;
+
+	/*
+	 * Make sure that the bitfields are set appropriately.
+	 */
+	clcdfb_set_bitfields(fb, &fb->fb.var);
+
+	/*
+	 * Allocate colourmap.
+	 */
+	fb_alloc_cmap(&fb->fb.cmap, 256, 0);
+
+	/*
+	 * Ensure interrupts are disabled.
+	 */
+	writel(0, fb->regs + CLCD_IENB);
+
+	fb_set_var(&fb->fb, &fb->fb.var);
+
+        printk(KERN_INFO "CLCD: %s hardware, %s display\n",
+               fb->board->name, fb->panel->mode.name);
+
+	ret = register_framebuffer(&fb->fb);
+	if (ret == 0)
+		goto out;
+
+	printk(KERN_ERR "CLCD: cannot register framebuffer (%d)\n", ret);
+
+	iounmap(fb->regs);
+ unuse_clk:
+	clk_unuse(fb->clk);
+ free_clk:
+	clk_put(fb->clk);
+ out:
+	return ret;
+}
+
+static int clcdfb_probe(struct amba_device *dev, void *id)
+{
+	struct clcd_board *board = dev->dev.platform_data;
+	struct clcd_fb *fb;
+	int ret;
+
+	if (!board)
+		return -EINVAL;
+
+	ret = amba_request_regions(dev, NULL);
+	if (ret) {
+		printk(KERN_ERR "CLCD: unable to reserve regs region\n");
+		goto out;
+	}
+
+	fb = (struct clcd_fb *) kmalloc(sizeof(struct clcd_fb), GFP_KERNEL);
+	if (!fb) {
+		printk(KERN_INFO "CLCD: could not allocate new clcd_fb struct\n");
+		ret = -ENOMEM;
+		goto free_region;
+	}
+	memset(fb, 0, sizeof(struct clcd_fb));
+
+	fb->dev = dev;
+	fb->board = board;
+
+	ret = fb->board->setup(fb);
+	if (ret)
+		goto free_fb;
+
+	ret = clcdfb_register(fb); 
+	if (ret == 0) {
+		amba_set_drvdata(dev, fb);
+		goto out;
+	}
+
+	fb->board->remove(fb);
+ free_fb:
+	kfree(fb);
+ free_region:
+	amba_release_regions(dev);
+ out:
+	return ret;
+}
+
+static int clcdfb_remove(struct amba_device *dev)
+{
+	struct clcd_fb *fb = amba_get_drvdata(dev);
+
+	amba_set_drvdata(dev, NULL);
+
+	clcdfb_disable(fb);
+	unregister_framebuffer(&fb->fb);
+	iounmap(fb->regs);
+	clk_unuse(fb->clk);
+	clk_put(fb->clk);
+
+	fb->board->remove(fb);
+
+	kfree(fb);
+
+	amba_release_regions(dev);
+
+	return 0;
+}
+
+static struct amba_id clcdfb_id_table[] = {
+	{
+		.id	= 0x00041110,
+		.mask	= 0x000fffff,
+	},
+	{ 0, 0 },
+};
+
+static struct amba_driver clcd_driver = {
+	.drv 		= {
+		.name	= "clcd-pl110",
+	},
+	.probe		= clcdfb_probe,
+	.remove		= clcdfb_remove,
+	.id_table	= clcdfb_id_table,
+};
+
+int __init amba_clcdfb_init(void)
+{
+	if (fb_get_options("ambafb", NULL))
+		return -ENODEV;
+
+	return amba_driver_register(&clcd_driver);
+}
+
+module_init(amba_clcdfb_init);
+
+static void __exit amba_clcdfb_exit(void)
+{
+	amba_driver_unregister(&clcd_driver);
+}
+
+module_exit(amba_clcdfb_exit);
+
+MODULE_DESCRIPTION("ARM PrimeCell PL110 CLCD core driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
new file mode 100644
index 0000000..cf8bb67
--- /dev/null
+++ b/drivers/video/amifb.c
@@ -0,0 +1,3812 @@
+/*
+ * linux/drivers/video/amifb.c -- Amiga builtin chipset frame buffer device
+ *
+ *    Copyright (C) 1995-2003 Geert Uytterhoeven
+ *
+ *          with work by Roman Zippel
+ *
+ *
+ * This file is based on the Atari frame buffer device (atafb.c):
+ *
+ *    Copyright (C) 1994 Martin Schaller
+ *                       Roman Hodek
+ *
+ *          with work by Andreas Schwab
+ *                       Guenther Kelleter
+ *
+ * and on the original Amiga console driver (amicon.c):
+ *
+ *    Copyright (C) 1993 Hamish Macdonald
+ *                       Greg Harp
+ *    Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk]
+ *
+ *          with work by William Rucklidge (wjr@cs.cornell.edu)
+ *                       Geert Uytterhoeven
+ *                       Jes Sorensen (jds@kom.auc.dk)
+ *
+ *
+ * History:
+ *
+ *   - 24 Jul 96: Copper generates now vblank interrupt and
+ *                VESA Power Saving Protocol is fully implemented
+ *   - 14 Jul 96: Rework and hopefully last ECS bugs fixed
+ *   -  7 Mar 96: Hardware sprite support by Roman Zippel
+ *   - 18 Feb 96: OCS and ECS support by Roman Zippel
+ *                Hardware functions completely rewritten
+ *   -  2 Dec 95: AGA version by Geert Uytterhoeven
+ *
+ * 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/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/delay.h>
+#include <linux/config.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <asm/setup.h>
+
+#include "c2p.h"
+
+
+#define DEBUG
+
+#if !defined(CONFIG_FB_AMIGA_OCS) && !defined(CONFIG_FB_AMIGA_ECS) && !defined(CONFIG_FB_AMIGA_AGA)
+#define CONFIG_FB_AMIGA_OCS   /* define at least one fb driver, this will change later */
+#endif
+
+#if !defined(CONFIG_FB_AMIGA_OCS)
+#  define IS_OCS (0)
+#elif defined(CONFIG_FB_AMIGA_ECS) || defined(CONFIG_FB_AMIGA_AGA)
+#  define IS_OCS (chipset == TAG_OCS)
+#else
+#  define CONFIG_FB_AMIGA_OCS_ONLY
+#  define IS_OCS (1)
+#endif
+
+#if !defined(CONFIG_FB_AMIGA_ECS)
+#  define IS_ECS (0)
+#elif defined(CONFIG_FB_AMIGA_OCS) || defined(CONFIG_FB_AMIGA_AGA)
+#  define IS_ECS (chipset == TAG_ECS)
+#else
+#  define CONFIG_FB_AMIGA_ECS_ONLY
+#  define IS_ECS (1)
+#endif
+
+#if !defined(CONFIG_FB_AMIGA_AGA)
+#  define IS_AGA (0)
+#elif defined(CONFIG_FB_AMIGA_OCS) || defined(CONFIG_FB_AMIGA_ECS)
+#  define IS_AGA (chipset == TAG_AGA)
+#else
+#  define CONFIG_FB_AMIGA_AGA_ONLY
+#  define IS_AGA (1)
+#endif
+
+#ifdef DEBUG
+#  define DPRINTK(fmt, args...)	printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+#  define DPRINTK(fmt, args...)
+#endif
+
+/*******************************************************************************
+
+
+   Generic video timings
+   ---------------------
+
+   Timings used by the frame buffer interface:
+
+   +----------+---------------------------------------------+----------+-------+
+   |          |                ^                            |          |       |
+   |          |                |upper_margin                |          |       |
+   |          |                ¥                            |          |       |
+   +----------###############################################----------+-------+
+   |          #                ^                            #          |       |
+   |          #                |                            #          |       |
+   |          #                |                            #          |       |
+   |          #                |                            #          |       |
+   |   left   #                |                            #  right   | hsync |
+   |  margin  #                |       xres                 #  margin  |  len  |
+   |<-------->#<---------------+--------------------------->#<-------->|<----->|
+   |          #                |                            #          |       |
+   |          #                |                            #          |       |
+   |          #                |                            #          |       |
+   |          #                |yres                        #          |       |
+   |          #                |                            #          |       |
+   |          #                |                            #          |       |
+   |          #                |                            #          |       |
+   |          #                |                            #          |       |
+   |          #                |                            #          |       |
+   |          #                |                            #          |       |
+   |          #                |                            #          |       |
+   |          #                |                            #          |       |
+   |          #                ¥                            #          |       |
+   +----------###############################################----------+-------+
+   |          |                ^                            |          |       |
+   |          |                |lower_margin                |          |       |
+   |          |                ¥                            |          |       |
+   +----------+---------------------------------------------+----------+-------+
+   |          |                ^                            |          |       |
+   |          |                |vsync_len                   |          |       |
+   |          |                ¥                            |          |       |
+   +----------+---------------------------------------------+----------+-------+
+
+
+   Amiga video timings
+   -------------------
+
+   The Amiga native chipsets uses another timing scheme:
+
+      - hsstrt:   Start of horizontal synchronization pulse
+      - hsstop:   End of horizontal synchronization pulse
+      - htotal:   Last value on the line (i.e. line length = htotal+1)
+      - vsstrt:   Start of vertical synchronization pulse
+      - vsstop:   End of vertical synchronization pulse
+      - vtotal:   Last line value (i.e. number of lines = vtotal+1)
+      - hcenter:  Start of vertical retrace for interlace
+
+   You can specify the blanking timings independently. Currently I just set
+   them equal to the respective synchronization values:
+
+      - hbstrt:   Start of horizontal blank
+      - hbstop:   End of horizontal blank
+      - vbstrt:   Start of vertical blank
+      - vbstop:   End of vertical blank
+
+   Horizontal values are in color clock cycles (280 ns), vertical values are in
+   scanlines.
+
+   (0, 0) is somewhere in the upper-left corner :-)
+
+
+   Amiga visible window definitions
+   --------------------------------
+
+   Currently I only have values for AGA, SHRES (28 MHz dotclock). Feel free to
+   make corrections and/or additions.
+
+   Within the above synchronization specifications, the visible window is
+   defined by the following parameters (actual register resolutions may be
+   different; all horizontal values are normalized with respect to the pixel
+   clock):
+
+      - diwstrt_h:   Horizontal start of the visible window
+      - diwstop_h:   Horizontal stop+1(*) of the visible window
+      - diwstrt_v:   Vertical start of the visible window
+      - diwstop_v:   Vertical stop of the visible window
+      - ddfstrt:     Horizontal start of display DMA
+      - ddfstop:     Horizontal stop of display DMA
+      - hscroll:     Horizontal display output delay
+
+   Sprite positioning:
+
+      - sprstrt_h:   Horizontal start-4 of sprite
+      - sprstrt_v:   Vertical start of sprite
+
+   (*) Even Commodore did it wrong in the AGA monitor drivers by not adding 1.
+
+   Horizontal values are in dotclock cycles (35 ns), vertical values are in
+   scanlines.
+
+   (0, 0) is somewhere in the upper-left corner :-)
+
+
+   Dependencies (AGA, SHRES (35 ns dotclock))
+   -------------------------------------------
+
+   Since there are much more parameters for the Amiga display than for the
+   frame buffer interface, there must be some dependencies among the Amiga
+   display parameters. Here's what I found out:
+
+      - ddfstrt and ddfstop are best aligned to 64 pixels.
+      - the chipset needs 64+4 horizontal pixels after the DMA start before the
+        first pixel is output, so diwstrt_h = ddfstrt+64+4 if you want to
+        display the first pixel on the line too. Increase diwstrt_h for virtual
+        screen panning.
+      - the display DMA always fetches 64 pixels at a time (fmode = 3).
+      - ddfstop is ddfstrt+#pixels-64.
+      - diwstop_h = diwstrt_h+xres+1. Because of the additional 1 this can be 1
+        more than htotal.
+      - hscroll simply adds a delay to the display output. Smooth horizontal
+        panning needs an extra 64 pixels on the left to prefetch the pixels that
+        `fall off' on the left.
+      - if ddfstrt < 192, the sprite DMA cycles are all stolen by the bitplane
+        DMA, so it's best to make the DMA start as late as possible.
+      - you really don't want to make ddfstrt < 128, since this will steal DMA
+        cycles from the other DMA channels (audio, floppy and Chip RAM refresh).
+      - I make diwstop_h and diwstop_v as large as possible.
+
+   General dependencies
+   --------------------
+
+      - all values are SHRES pixel (35ns)
+
+                  table 1:fetchstart  table 2:prefetch    table 3:fetchsize
+                  ------------------  ----------------    -----------------
+   Pixclock     # SHRES|HIRES|LORES # SHRES|HIRES|LORES # SHRES|HIRES|LORES
+   -------------#------+-----+------#------+-----+------#------+-----+------
+   Bus width 1x #   16 |  32 |  64  #   16 |  32 |  64  #   64 |  64 |  64
+   Bus width 2x #   32 |  64 | 128  #   32 |  64 |  64  #   64 |  64 | 128
+   Bus width 4x #   64 | 128 | 256  #   64 |  64 |  64  #   64 | 128 | 256
+
+      - chipset needs 4 pixels before the first pixel is output
+      - ddfstrt must be aligned to fetchstart (table 1)
+      - chipset needs also prefetch (table 2) to get first pixel data, so
+        ddfstrt = ((diwstrt_h-4) & -fetchstart) - prefetch
+      - for horizontal panning decrease diwstrt_h
+      - the length of a fetchline must be aligned to fetchsize (table 3)
+      - if fetchstart is smaller than fetchsize, then ddfstrt can a little bit
+        moved to optimize use of dma (useful for OCS/ECS overscan displays)
+      - ddfstop is ddfstrt+ddfsize-fetchsize
+      - If C= didn't change anything for AGA, then at following positions the
+        dma bus is already used:
+        ddfstrt <  48 -> memory refresh
+                <  96 -> disk dma
+                < 160 -> audio dma
+                < 192 -> sprite 0 dma
+                < 416 -> sprite dma (32 per sprite)
+      - in accordance with the hardware reference manual a hardware stop is at
+        192, but AGA (ECS?) can go below this.
+
+   DMA priorities
+   --------------
+
+   Since there are limits on the earliest start value for display DMA and the
+   display of sprites, I use the following policy on horizontal panning and
+   the hardware cursor:
+
+      - if you want to start display DMA too early, you lose the ability to
+        do smooth horizontal panning (xpanstep 1 -> 64).
+      - if you want to go even further, you lose the hardware cursor too.
+
+   IMHO a hardware cursor is more important for X than horizontal scrolling,
+   so that's my motivation.
+
+
+   Implementation
+   --------------
+
+   ami_decode_var() converts the frame buffer values to the Amiga values. It's
+   just a `straightforward' implementation of the above rules.
+
+
+   Standard VGA timings
+   --------------------
+
+               xres  yres    left  right  upper  lower    hsync    vsync
+               ----  ----    ----  -----  -----  -----    -----    -----
+      80x25     720   400      27     45     35     12      108        2
+      80x30     720   480      27     45     30      9      108        2
+
+   These were taken from a XFree86 configuration file, recalculated for a 28 MHz
+   dotclock (Amigas don't have a 25 MHz dotclock) and converted to frame buffer
+   generic timings.
+
+   As a comparison, graphics/monitor.h suggests the following:
+
+               xres  yres    left  right  upper  lower    hsync    vsync
+               ----  ----    ----  -----  -----  -----    -----    -----
+
+      VGA       640   480      52    112     24     19    112 -      2 +
+      VGA70     640   400      52    112     27     21    112 -      2 -
+
+
+   Sync polarities
+   ---------------
+
+      VSYNC    HSYNC    Vertical size    Vertical total
+      -----    -----    -------------    --------------
+        +        +           Reserved          Reserved
+        +        -                400               414
+        -        +                350               362
+        -        -                480               496
+
+   Source: CL-GD542X Technical Reference Manual, Cirrus Logic, Oct 1992
+
+
+   Broadcast video timings
+   -----------------------
+
+   According to the CCIR and RETMA specifications, we have the following values:
+
+   CCIR -> PAL
+   -----------
+
+      - a scanline is 64 µs long, of which 52.48 µs are visible. This is about
+        736 visible 70 ns pixels per line.
+      - we have 625 scanlines, of which 575 are visible (interlaced); after
+        rounding this becomes 576.
+
+   RETMA -> NTSC
+   -------------
+
+      - a scanline is 63.5 µs long, of which 53.5 µs are visible.  This is about
+        736 visible 70 ns pixels per line.
+      - we have 525 scanlines, of which 485 are visible (interlaced); after
+        rounding this becomes 484.
+
+   Thus if you want a PAL compatible display, you have to do the following:
+
+      - set the FB_SYNC_BROADCAST flag to indicate that standard broadcast
+        timings are to be used.
+      - make sure upper_margin+yres+lower_margin+vsync_len = 625 for an
+        interlaced, 312 for a non-interlaced and 156 for a doublescanned
+        display.
+      - make sure left_margin+xres+right_margin+hsync_len = 1816 for a SHRES,
+        908 for a HIRES and 454 for a LORES display.
+      - the left visible part begins at 360 (SHRES; HIRES:180, LORES:90),
+        left_margin+2*hsync_len must be greater or equal.
+      - the upper visible part begins at 48 (interlaced; non-interlaced:24,
+        doublescanned:12), upper_margin+2*vsync_len must be greater or equal.
+      - ami_encode_var() calculates margins with a hsync of 5320 ns and a vsync
+        of 4 scanlines
+
+   The settings for a NTSC compatible display are straightforward.
+
+   Note that in a strict sense the PAL and NTSC standards only define the
+   encoding of the color part (chrominance) of the video signal and don't say
+   anything about horizontal/vertical synchronization nor refresh rates.
+
+
+                                                            -- Geert --
+
+*******************************************************************************/
+
+
+	/*
+	 * Custom Chipset Definitions
+	 */
+
+#define CUSTOM_OFS(fld) ((long)&((struct CUSTOM*)0)->fld)
+
+	/*
+	 * BPLCON0 -- Bitplane Control Register 0
+	 */
+
+#define BPC0_HIRES	(0x8000)
+#define BPC0_BPU2	(0x4000) /* Bit plane used count */
+#define BPC0_BPU1	(0x2000)
+#define BPC0_BPU0	(0x1000)
+#define BPC0_HAM	(0x0800) /* HAM mode */
+#define BPC0_DPF	(0x0400) /* Double playfield */
+#define BPC0_COLOR	(0x0200) /* Enable colorburst */
+#define BPC0_GAUD	(0x0100) /* Genlock audio enable */
+#define BPC0_UHRES	(0x0080) /* Ultrahi res enable */
+#define BPC0_SHRES	(0x0040) /* Super hi res mode */
+#define BPC0_BYPASS	(0x0020) /* Bypass LUT - AGA */
+#define BPC0_BPU3	(0x0010) /* AGA */
+#define BPC0_LPEN	(0x0008) /* Light pen enable */
+#define BPC0_LACE	(0x0004) /* Interlace */
+#define BPC0_ERSY	(0x0002) /* External resync */
+#define BPC0_ECSENA	(0x0001) /* ECS enable */
+
+	/*
+	 * BPLCON2 -- Bitplane Control Register 2
+	 */
+
+#define BPC2_ZDBPSEL2	(0x4000) /* Bitplane to be used for ZD - AGA */
+#define BPC2_ZDBPSEL1	(0x2000)
+#define BPC2_ZDBPSEL0	(0x1000)
+#define BPC2_ZDBPEN	(0x0800) /* Enable ZD with ZDBPSELx - AGA */
+#define BPC2_ZDCTEN	(0x0400) /* Enable ZD with palette bit #31 - AGA */
+#define BPC2_KILLEHB	(0x0200) /* Kill EHB mode - AGA */
+#define BPC2_RDRAM	(0x0100) /* Color table accesses read, not write - AGA */
+#define BPC2_SOGEN	(0x0080) /* SOG output pin high - AGA */
+#define BPC2_PF2PRI	(0x0040) /* PF2 priority over PF1 */
+#define BPC2_PF2P2	(0x0020) /* PF2 priority wrt sprites */
+#define BPC2_PF2P1	(0x0010)
+#define BPC2_PF2P0	(0x0008)
+#define BPC2_PF1P2	(0x0004) /* ditto PF1 */
+#define BPC2_PF1P1	(0x0002)
+#define BPC2_PF1P0	(0x0001)
+
+	/*
+	 * BPLCON3 -- Bitplane Control Register 3 (AGA)
+	 */
+
+#define BPC3_BANK2	(0x8000) /* Bits to select color register bank */
+#define BPC3_BANK1	(0x4000)
+#define BPC3_BANK0	(0x2000)
+#define BPC3_PF2OF2	(0x1000) /* Bits for color table offset when PF2 */
+#define BPC3_PF2OF1	(0x0800)
+#define BPC3_PF2OF0	(0x0400)
+#define BPC3_LOCT	(0x0200) /* Color register writes go to low bits */
+#define BPC3_SPRES1	(0x0080) /* Sprite resolution bits */
+#define BPC3_SPRES0	(0x0040)
+#define BPC3_BRDRBLNK	(0x0020) /* Border blanked? */
+#define BPC3_BRDRTRAN	(0x0010) /* Border transparent? */
+#define BPC3_ZDCLKEN	(0x0004) /* ZD pin is 14 MHz (HIRES) clock output */
+#define BPC3_BRDRSPRT	(0x0002) /* Sprites in border? */
+#define BPC3_EXTBLKEN	(0x0001) /* BLANK programmable */
+
+	/*
+	 * BPLCON4 -- Bitplane Control Register 4 (AGA)
+	 */
+
+#define BPC4_BPLAM7	(0x8000) /* bitplane color XOR field */
+#define BPC4_BPLAM6	(0x4000)
+#define BPC4_BPLAM5	(0x2000)
+#define BPC4_BPLAM4	(0x1000)
+#define BPC4_BPLAM3	(0x0800)
+#define BPC4_BPLAM2	(0x0400)
+#define BPC4_BPLAM1	(0x0200)
+#define BPC4_BPLAM0	(0x0100)
+#define BPC4_ESPRM7	(0x0080) /* 4 high bits for even sprite colors */
+#define BPC4_ESPRM6	(0x0040)
+#define BPC4_ESPRM5	(0x0020)
+#define BPC4_ESPRM4	(0x0010)
+#define BPC4_OSPRM7	(0x0008) /* 4 high bits for odd sprite colors */
+#define BPC4_OSPRM6	(0x0004)
+#define BPC4_OSPRM5	(0x0002)
+#define BPC4_OSPRM4	(0x0001)
+
+	/*
+	 * BEAMCON0 -- Beam Control Register
+	 */
+
+#define BMC0_HARDDIS	(0x4000) /* Disable hardware limits */
+#define BMC0_LPENDIS	(0x2000) /* Disable light pen latch */
+#define BMC0_VARVBEN	(0x1000) /* Enable variable vertical blank */
+#define BMC0_LOLDIS	(0x0800) /* Disable long/short line toggle */
+#define BMC0_CSCBEN	(0x0400) /* Composite sync/blank */
+#define BMC0_VARVSYEN	(0x0200) /* Enable variable vertical sync */
+#define BMC0_VARHSYEN	(0x0100) /* Enable variable horizontal sync */
+#define BMC0_VARBEAMEN	(0x0080) /* Enable variable beam counters */
+#define BMC0_DUAL	(0x0040) /* Enable alternate horizontal beam counter */
+#define BMC0_PAL	(0x0020) /* Set decodes for PAL */
+#define BMC0_VARCSYEN	(0x0010) /* Enable variable composite sync */
+#define BMC0_BLANKEN	(0x0008) /* Blank enable (no longer used on AGA) */
+#define BMC0_CSYTRUE	(0x0004) /* CSY polarity */
+#define BMC0_VSYTRUE	(0x0002) /* VSY polarity */
+#define BMC0_HSYTRUE	(0x0001) /* HSY polarity */
+
+
+	/*
+	 * FMODE -- Fetch Mode Control Register (AGA)
+	 */
+
+#define FMODE_SSCAN2	(0x8000) /* Sprite scan-doubling */
+#define FMODE_BSCAN2	(0x4000) /* Use PF2 modulus every other line */
+#define FMODE_SPAGEM	(0x0008) /* Sprite page mode */
+#define FMODE_SPR32	(0x0004) /* Sprite 32 bit fetch */
+#define FMODE_BPAGEM	(0x0002) /* Bitplane page mode */
+#define FMODE_BPL32	(0x0001) /* Bitplane 32 bit fetch */
+
+	/*
+	 * Tags used to indicate a specific Pixel Clock
+	 *
+	 * clk_shift is the shift value to get the timings in 35 ns units
+	 */
+
+enum { TAG_SHRES, TAG_HIRES, TAG_LORES };
+
+	/*
+	 * Tags used to indicate the specific chipset
+	 */
+
+enum { TAG_OCS, TAG_ECS, TAG_AGA };
+
+	/*
+	 * Tags used to indicate the memory bandwidth
+	 */
+
+enum { TAG_FMODE_1, TAG_FMODE_2, TAG_FMODE_4 };
+
+
+	/*
+	 * Clock Definitions, Maximum Display Depth
+	 *
+	 * These depend on the E-Clock or the Chipset, so they are filled in
+	 * dynamically
+	 */
+
+static u_long pixclock[3];	/* SHRES/HIRES/LORES: index = clk_shift */
+static u_short maxdepth[3];	/* SHRES/HIRES/LORES: index = clk_shift */
+static u_short maxfmode, chipset;
+
+
+	/*
+	 * Broadcast Video Timings
+	 *
+	 * Horizontal values are in 35 ns (SHRES) units
+	 * Vertical values are in interlaced scanlines
+	 */
+
+#define PAL_DIWSTRT_H	(360)	/* PAL Window Limits */
+#define PAL_DIWSTRT_V	(48)
+#define PAL_HTOTAL	(1816)
+#define PAL_VTOTAL	(625)
+
+#define NTSC_DIWSTRT_H	(360)	/* NTSC Window Limits */
+#define NTSC_DIWSTRT_V	(40)
+#define NTSC_HTOTAL	(1816)
+#define NTSC_VTOTAL	(525)
+
+
+	/*
+	 * Various macros
+	 */
+
+#define up2(v)		(((v)+1) & -2)
+#define down2(v)	((v) & -2)
+#define div2(v)		((v)>>1)
+#define mod2(v)		((v) & 1)
+
+#define up4(v)		(((v)+3) & -4)
+#define down4(v)	((v) & -4)
+#define mul4(v)		((v)<<2)
+#define div4(v)		((v)>>2)
+#define mod4(v)		((v) & 3)
+
+#define up8(v)		(((v)+7) & -8)
+#define down8(v)	((v) & -8)
+#define div8(v)		((v)>>3)
+#define mod8(v)		((v) & 7)
+
+#define up16(v)		(((v)+15) & -16)
+#define down16(v)	((v) & -16)
+#define div16(v)	((v)>>4)
+#define mod16(v)	((v) & 15)
+
+#define up32(v)		(((v)+31) & -32)
+#define down32(v)	((v) & -32)
+#define div32(v)	((v)>>5)
+#define mod32(v)	((v) & 31)
+
+#define up64(v)		(((v)+63) & -64)
+#define down64(v)	((v) & -64)
+#define div64(v)	((v)>>6)
+#define mod64(v)	((v) & 63)
+
+#define upx(x,v)	(((v)+(x)-1) & -(x))
+#define downx(x,v)	((v) & -(x))
+#define modx(x,v)	((v) & ((x)-1))
+
+/* if x1 is not a constant, this macro won't make real sense :-) */
+#ifdef __mc68000__
+#define DIVUL(x1, x2) ({int res; asm("divul %1,%2,%3": "=d" (res): \
+	"d" (x2), "d" ((long)((x1)/0x100000000ULL)), "0" ((long)(x1))); res;})
+#else
+/* We know a bit about the numbers, so we can do it this way */
+#define DIVUL(x1, x2) ((((long)((unsigned long long)x1 >> 8) / x2) << 8) + \
+	((((long)((unsigned long long)x1 >> 8) % x2) << 8) / x2))
+#endif
+
+#define highw(x)	((u_long)(x)>>16 & 0xffff)
+#define loww(x)		((u_long)(x) & 0xffff)
+
+#define VBlankOn()	custom.intena = IF_SETCLR|IF_COPER
+#define VBlankOff()	custom.intena = IF_COPER
+
+
+	/*
+	 * Chip RAM we reserve for the Frame Buffer
+	 *
+	 * This defines the Maximum Virtual Screen Size
+	 * (Setable per kernel options?)
+	 */
+
+#define VIDEOMEMSIZE_AGA_2M	(1310720) /* AGA (2MB) : max 1280*1024*256  */
+#define VIDEOMEMSIZE_AGA_1M	(786432)  /* AGA (1MB) : max 1024*768*256   */
+#define VIDEOMEMSIZE_ECS_2M	(655360)  /* ECS (2MB) : max 1280*1024*16   */
+#define VIDEOMEMSIZE_ECS_1M	(393216)  /* ECS (1MB) : max 1024*768*16    */
+#define VIDEOMEMSIZE_OCS	(262144)  /* OCS       : max ca. 800*600*16 */
+
+#define SPRITEMEMSIZE		(64*64/4) /* max 64*64*4 */
+#define DUMMYSPRITEMEMSIZE	(8)
+static u_long spritememory;
+
+#define CHIPRAM_SAFETY_LIMIT	(16384)
+
+static u_long videomemory;
+
+	/*
+	 * This is the earliest allowed start of fetching display data.
+	 * Only if you really want no hardware cursor and audio,
+	 * set this to 128, but let it better at 192
+	 */
+
+static u_long min_fstrt = 192;
+
+#define assignchunk(name, type, ptr, size) \
+{ \
+	(name) = (type)(ptr); \
+	ptr += size; \
+}
+
+
+	/*
+	 * Copper Instructions
+	 */
+
+#define CMOVE(val, reg)		(CUSTOM_OFS(reg)<<16 | (val))
+#define CMOVE2(val, reg)	((CUSTOM_OFS(reg)+2)<<16 | (val))
+#define CWAIT(x, y)		(((y) & 0x1fe)<<23 | ((x) & 0x7f0)<<13 | 0x0001fffe)
+#define CEND			(0xfffffffe)
+
+
+typedef union {
+	u_long l;
+	u_short w[2];
+} copins;
+
+static struct copdisplay {
+	copins *init;
+	copins *wait;
+	copins *list[2][2];
+	copins *rebuild[2];
+} copdisplay;
+
+static u_short currentcop = 0;
+
+	/*
+	 * Hardware Cursor API Definitions
+	 * These used to be in linux/fb.h, but were preliminary and used by
+	 * amifb only anyway
+	 */
+
+#define FBIOGET_FCURSORINFO     0x4607
+#define FBIOGET_VCURSORINFO     0x4608
+#define FBIOPUT_VCURSORINFO     0x4609
+#define FBIOGET_CURSORSTATE     0x460A
+#define FBIOPUT_CURSORSTATE     0x460B
+
+
+struct fb_fix_cursorinfo {
+	__u16 crsr_width;		/* width and height of the cursor in */
+	__u16 crsr_height;		/* pixels (zero if no cursor)	*/
+	__u16 crsr_xsize;		/* cursor size in display pixels */
+	__u16 crsr_ysize;
+	__u16 crsr_color1;		/* colormap entry for cursor color1 */
+	__u16 crsr_color2;		/* colormap entry for cursor color2 */
+};
+
+struct fb_var_cursorinfo {
+	__u16 width;
+	__u16 height;
+	__u16 xspot;
+	__u16 yspot;
+	__u8 data[1];			/* field with [height][width]        */
+};
+
+struct fb_cursorstate {
+	__s16 xoffset;
+	__s16 yoffset;
+	__u16 mode;
+};
+
+#define FB_CURSOR_OFF		0
+#define FB_CURSOR_ON		1
+#define FB_CURSOR_FLASH		2
+
+
+	/*
+	 * Hardware Cursor
+	 */
+
+static int cursorrate = 20;	/* Number of frames/flash toggle */
+static u_short cursorstate = -1;
+static u_short cursormode = FB_CURSOR_OFF;
+
+static u_short *lofsprite, *shfsprite, *dummysprite;
+
+	/*
+	 * Current Video Mode
+	 */
+
+static struct amifb_par {
+
+	/* General Values */
+
+	int xres;		/* vmode */
+	int yres;		/* vmode */
+	int vxres;		/* vmode */
+	int vyres;		/* vmode */
+	int xoffset;		/* vmode */
+	int yoffset;		/* vmode */
+	u_short bpp;		/* vmode */
+	u_short clk_shift;	/* vmode */
+	u_short line_shift;	/* vmode */
+	int vmode;		/* vmode */
+	u_short diwstrt_h;	/* vmode */
+	u_short diwstop_h;	/* vmode */
+	u_short diwstrt_v;	/* vmode */
+	u_short diwstop_v;	/* vmode */
+	u_long next_line;	/* modulo for next line */
+	u_long next_plane;	/* modulo for next plane */
+
+	/* Cursor Values */
+
+	struct {
+		short crsr_x;	/* movecursor */
+		short crsr_y;	/* movecursor */
+		short spot_x;
+		short spot_y;
+		u_short height;
+		u_short width;
+		u_short fmode;
+	} crsr;
+
+	/* OCS Hardware Registers */
+
+	u_long bplpt0;		/* vmode, pan (Note: physical address) */
+	u_long bplpt0wrap;	/* vmode, pan (Note: physical address) */
+	u_short ddfstrt;
+	u_short ddfstop;
+	u_short bpl1mod;
+	u_short bpl2mod;
+	u_short bplcon0;	/* vmode */
+	u_short bplcon1;	/* vmode */
+	u_short htotal;		/* vmode */
+	u_short vtotal;		/* vmode */
+
+	/* Additional ECS Hardware Registers */
+
+	u_short bplcon3;	/* vmode */
+	u_short beamcon0;	/* vmode */
+	u_short hsstrt;		/* vmode */
+	u_short hsstop;		/* vmode */
+	u_short hbstrt;		/* vmode */
+	u_short hbstop;		/* vmode */
+	u_short vsstrt;		/* vmode */
+	u_short vsstop;		/* vmode */
+	u_short vbstrt;		/* vmode */
+	u_short vbstop;		/* vmode */
+	u_short hcenter;	/* vmode */
+
+	/* Additional AGA Hardware Registers */
+
+	u_short fmode;		/* vmode */
+} currentpar;
+
+
+static struct fb_info fb_info = {
+    .fix = {
+	.id		= "Amiga ",
+	.visual		= FB_VISUAL_PSEUDOCOLOR,
+	.accel		= FB_ACCEL_AMIGABLITT
+    }
+};
+
+
+	/*
+	 *  Saved color entry 0 so we can restore it when unblanking
+	 */
+
+static u_char red0, green0, blue0;
+
+
+#if defined(CONFIG_FB_AMIGA_ECS)
+static u_short ecs_palette[32];
+#endif
+
+
+	/*
+	 * Latches for Display Changes during VBlank
+	 */
+
+static u_short do_vmode_full = 0;	/* Change the Video Mode */
+static u_short do_vmode_pan = 0;	/* Update the Video Mode */
+static short do_blank = 0;		/* (Un)Blank the Screen (±1) */
+static u_short do_cursor = 0;		/* Move the Cursor */
+
+
+	/*
+	 * Various Flags
+	 */
+
+static u_short is_blanked = 0;		/* Screen is Blanked */
+static u_short is_lace = 0;		/* Screen is laced */
+
+	/*
+	 * Predefined Video Modes
+	 *
+	 */
+
+static struct fb_videomode ami_modedb[] __initdata = {
+
+    /*
+     *  AmigaOS Video Modes
+     *
+     *  If you change these, make sure to update DEFMODE_* as well!
+     */
+
+    {
+	/* 640x200, 15 kHz, 60 Hz (NTSC) */
+	"ntsc", 60, 640, 200, TAG_HIRES, 106, 86, 44, 16, 76, 2,
+	FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+    }, {
+	/* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */
+	"ntsc-lace", 60, 640, 400, TAG_HIRES, 106, 86, 88, 33, 76, 4,
+	FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+    }, {
+	/* 640x256, 15 kHz, 50 Hz (PAL) */
+	"pal", 50, 640, 256, TAG_HIRES, 106, 86, 40, 14, 76, 2,
+	FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+    }, {
+	/* 640x512, 15 kHz, 50 Hz interlaced (PAL) */
+	"pal-lace", 50, 640, 512, TAG_HIRES, 106, 86, 80, 29, 76, 4,
+	FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+    }, {
+	/* 640x480, 29 kHz, 57 Hz */
+	"multiscan", 57, 640, 480, TAG_SHRES, 96, 112, 29, 8, 72, 8,
+	0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+    }, {
+	/* 640x960, 29 kHz, 57 Hz interlaced */
+	"multiscan-lace", 57, 640, 960, TAG_SHRES, 96, 112, 58, 16, 72, 16,
+	0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+    }, {
+	/* 640x200, 15 kHz, 72 Hz */
+	"euro36", 72, 640, 200, TAG_HIRES, 92, 124, 6, 6, 52, 5,
+	0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+    }, {
+	/* 640x400, 15 kHz, 72 Hz interlaced */
+	"euro36-lace", 72, 640, 400, TAG_HIRES, 92, 124, 12, 12, 52, 10,
+	0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+    }, {
+	/* 640x400, 29 kHz, 68 Hz */
+	"euro72", 68, 640, 400, TAG_SHRES, 164, 92, 9, 9, 80, 8,
+	0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+    }, {
+	/* 640x800, 29 kHz, 68 Hz interlaced */
+	"euro72-lace", 68, 640, 800, TAG_SHRES, 164, 92, 18, 18, 80, 16,
+	0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+    }, {
+	/* 800x300, 23 kHz, 70 Hz */
+	"super72", 70, 800, 300, TAG_SHRES, 212, 140, 10, 11, 80, 7,
+	0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+    }, {
+	/* 800x600, 23 kHz, 70 Hz interlaced */
+	"super72-lace", 70, 800, 600, TAG_SHRES, 212, 140, 20, 22, 80, 14,
+	0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+    }, {
+	/* 640x200, 27 kHz, 57 Hz doublescan */
+	"dblntsc", 57, 640, 200, TAG_SHRES, 196, 124, 18, 17, 80, 4,
+	0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP
+    }, {
+	/* 640x400, 27 kHz, 57 Hz */
+	"dblntsc-ff", 57, 640, 400, TAG_SHRES, 196, 124, 36, 35, 80, 7,
+	0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+    }, {
+	/* 640x800, 27 kHz, 57 Hz interlaced */
+	"dblntsc-lace", 57, 640, 800, TAG_SHRES, 196, 124, 72, 70, 80, 14,
+	0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+    }, {
+	/* 640x256, 27 kHz, 47 Hz doublescan */
+	"dblpal", 47, 640, 256, TAG_SHRES, 196, 124, 14, 13, 80, 4,
+	0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP
+    }, {
+	/* 640x512, 27 kHz, 47 Hz */
+	"dblpal-ff", 47, 640, 512, TAG_SHRES, 196, 124, 28, 27, 80, 7,
+	0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+    }, {
+	/* 640x1024, 27 kHz, 47 Hz interlaced */
+	"dblpal-lace", 47, 640, 1024, TAG_SHRES, 196, 124, 56, 54, 80, 14,
+	0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+    },
+
+    /*
+     *  VGA Video Modes
+     */
+
+    {
+	/* 640x480, 31 kHz, 60 Hz (VGA) */
+	"vga", 60, 640, 480, TAG_SHRES, 64, 96, 30, 9, 112, 2,
+	0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+    }, {
+	/* 640x400, 31 kHz, 70 Hz (VGA) */
+	"vga70", 70, 640, 400, TAG_SHRES, 64, 96, 35, 12, 112, 2,
+	FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+    },
+
+#if 0
+
+    /*
+     *  A2024 video modes
+     *  These modes don't work yet because there's no A2024 driver.
+     */
+
+    {
+	/* 1024x800, 10 Hz */
+	"a2024-10", 10, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0,
+	0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+    }, {
+	/* 1024x800, 15 Hz */
+	"a2024-15", 15, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0,
+	0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+    }
+#endif
+};
+
+#define NUM_TOTAL_MODES  ARRAY_SIZE(ami_modedb)
+
+static char *mode_option __initdata = NULL;
+static int round_down_bpp = 1;	/* for mode probing */
+
+	/*
+	 * Some default modes
+	 */
+
+
+#define DEFMODE_PAL	    2	/* "pal" for PAL OCS/ECS */
+#define DEFMODE_NTSC	    0	/* "ntsc" for NTSC OCS/ECS */
+#define DEFMODE_AMBER_PAL   3	/* "pal-lace" for flicker fixed PAL (A3000) */
+#define DEFMODE_AMBER_NTSC  1	/* "ntsc-lace" for flicker fixed NTSC (A3000) */
+#define DEFMODE_AGA	    19	/* "vga70" for AGA */
+
+
+static int amifb_ilbm = 0;	/* interleaved or normal bitplanes */
+static int amifb_inverse = 0;
+
+
+	/*
+	 * Macros for the conversion from real world values to hardware register
+	 * values
+	 *
+	 * This helps us to keep our attention on the real stuff...
+	 *
+	 * Hardware limits for AGA:
+	 *
+	 *	parameter  min    max  step
+	 *	---------  ---   ----  ----
+	 *	diwstrt_h    0   2047     1
+	 *	diwstrt_v    0   2047     1
+	 *	diwstop_h    0   4095     1
+	 *	diwstop_v    0   4095     1
+	 *
+	 *	ddfstrt      0   2032    16
+	 *	ddfstop      0   2032    16
+	 *
+	 *	htotal       8   2048     8
+	 *	hsstrt       0   2040     8
+	 *	hsstop       0   2040     8
+	 *	vtotal       1   4096     1
+	 *	vsstrt       0   4095     1
+	 *	vsstop       0   4095     1
+	 *	hcenter      0   2040     8
+	 *
+	 *	hbstrt       0   2047     1
+	 *	hbstop       0   2047     1
+	 *	vbstrt       0   4095     1
+	 *	vbstop       0   4095     1
+	 *
+	 * Horizontal values are in 35 ns (SHRES) pixels
+	 * Vertical values are in half scanlines
+	 */
+
+/* bplcon1 (smooth scrolling) */
+
+#define hscroll2hw(hscroll) \
+	(((hscroll)<<12 & 0x3000) | ((hscroll)<<8 & 0xc300) | \
+	 ((hscroll)<<4 & 0x0c00) | ((hscroll)<<2 & 0x00f0) | ((hscroll)>>2 & 0x000f))
+
+/* diwstrt/diwstop/diwhigh (visible display window) */
+
+#define diwstrt2hw(diwstrt_h, diwstrt_v) \
+	(((diwstrt_v)<<7 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff))
+#define diwstop2hw(diwstop_h, diwstop_v) \
+	(((diwstop_v)<<7 & 0xff00) | ((diwstop_h)>>2 & 0x00ff))
+#define diwhigh2hw(diwstrt_h, diwstrt_v, diwstop_h, diwstop_v) \
+	(((diwstop_h)<<3 & 0x2000) | ((diwstop_h)<<11 & 0x1800) | \
+	 ((diwstop_v)>>1 & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \
+	 ((diwstrt_h)<<3 & 0x0018) | ((diwstrt_v)>>9 & 0x0007))
+
+/* ddfstrt/ddfstop (display DMA) */
+
+#define ddfstrt2hw(ddfstrt)	div8(ddfstrt)
+#define ddfstop2hw(ddfstop)	div8(ddfstop)
+
+/* hsstrt/hsstop/htotal/vsstrt/vsstop/vtotal/hcenter (sync timings) */
+
+#define hsstrt2hw(hsstrt)	(div8(hsstrt))
+#define hsstop2hw(hsstop)	(div8(hsstop))
+#define htotal2hw(htotal)	(div8(htotal)-1)
+#define vsstrt2hw(vsstrt)	(div2(vsstrt))
+#define vsstop2hw(vsstop)	(div2(vsstop))
+#define vtotal2hw(vtotal)	(div2(vtotal)-1)
+#define hcenter2hw(htotal)	(div8(htotal))
+
+/* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */
+
+#define hbstrt2hw(hbstrt)	(((hbstrt)<<8 & 0x0700) | ((hbstrt)>>3 & 0x00ff))
+#define hbstop2hw(hbstop)	(((hbstop)<<8 & 0x0700) | ((hbstop)>>3 & 0x00ff))
+#define vbstrt2hw(vbstrt)	(div2(vbstrt))
+#define vbstop2hw(vbstop)	(div2(vbstop))
+
+/* colour */
+
+#define rgb2hw8_high(red, green, blue) \
+	(((red & 0xf0)<<4) | (green & 0xf0) | ((blue & 0xf0)>>4))
+#define rgb2hw8_low(red, green, blue) \
+	(((red & 0x0f)<<8) | ((green & 0x0f)<<4) | (blue & 0x0f))
+#define rgb2hw4(red, green, blue) \
+	(((red & 0xf0)<<4) | (green & 0xf0) | ((blue & 0xf0)>>4))
+#define rgb2hw2(red, green, blue) \
+	(((red & 0xc0)<<4) | (green & 0xc0) | ((blue & 0xc0)>>4))
+
+/* sprpos/sprctl (sprite positioning) */
+
+#define spr2hw_pos(start_v, start_h) \
+	(((start_v)<<7&0xff00) | ((start_h)>>3&0x00ff))
+#define spr2hw_ctl(start_v, start_h, stop_v) \
+	(((stop_v)<<7&0xff00) | ((start_v)>>4&0x0040) | ((stop_v)>>5&0x0020) | \
+	 ((start_h)<<3&0x0018) | ((start_v)>>7&0x0004) | ((stop_v)>>8&0x0002) | \
+	 ((start_h)>>2&0x0001))
+
+/* get current vertical position of beam */
+#define get_vbpos()	((u_short)((*(u_long volatile *)&custom.vposr >> 7) & 0xffe))
+
+	/*
+	 * Copper Initialisation List
+	 */
+
+#define COPINITSIZE (sizeof(copins)*40)
+
+enum {
+	cip_bplcon0
+};
+
+	/*
+	 * Long Frame/Short Frame Copper List
+	 * Don't change the order, build_copper()/rebuild_copper() rely on this
+	 */
+
+#define COPLISTSIZE (sizeof(copins)*64)
+
+enum {
+	cop_wait, cop_bplcon0,
+	cop_spr0ptrh, cop_spr0ptrl,
+	cop_diwstrt, cop_diwstop,
+	cop_diwhigh,
+};
+
+	/*
+	 * Pixel modes for Bitplanes and Sprites
+	 */
+
+static u_short bplpixmode[3] = {
+	BPC0_SHRES,			/*  35 ns */
+	BPC0_HIRES,			/*  70 ns */
+	0				/* 140 ns */
+};
+
+static u_short sprpixmode[3] = {
+	BPC3_SPRES1 | BPC3_SPRES0,	/*  35 ns */
+	BPC3_SPRES1,			/*  70 ns */
+	BPC3_SPRES0			/* 140 ns */
+};
+
+	/*
+	 * Fetch modes for Bitplanes and Sprites
+	 */
+
+static u_short bplfetchmode[3] = {
+	0,				/* 1x */
+	FMODE_BPL32,			/* 2x */
+	FMODE_BPAGEM | FMODE_BPL32	/* 4x */
+};
+
+static u_short sprfetchmode[3] = {
+	0,				/* 1x */
+	FMODE_SPR32,			/* 2x */
+	FMODE_SPAGEM | FMODE_SPR32	/* 4x */
+};
+
+
+	/*
+	 * Interface used by the world
+	 */
+
+int amifb_setup(char*);
+
+static int amifb_check_var(struct fb_var_screeninfo *var,
+			   struct fb_info *info);
+static int amifb_set_par(struct fb_info *info);
+static int amifb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp,
+			   struct fb_info *info);
+static int amifb_blank(int blank, struct fb_info *info);
+static int amifb_pan_display(struct fb_var_screeninfo *var,
+			     struct fb_info *info);
+static void amifb_fillrect(struct fb_info *info,
+			   const struct fb_fillrect *rect);
+static void amifb_copyarea(struct fb_info *info,
+			   const struct fb_copyarea *region);
+static void amifb_imageblit(struct fb_info *info,
+			    const struct fb_image *image);
+static int amifb_ioctl(struct inode *inode, struct file *file,
+		       unsigned int cmd, unsigned long arg,
+		       struct fb_info *info);
+
+
+	/*
+	 * Interface to the low level console driver
+	 */
+
+int amifb_init(void);
+static void amifb_deinit(void);
+
+	/*
+	 * Internal routines
+	 */
+
+static int flash_cursor(void);
+static irqreturn_t amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp);
+static u_long chipalloc(u_long size);
+static void chipfree(void);
+
+	/*
+	 * Hardware routines
+	 */
+
+static int ami_decode_var(struct fb_var_screeninfo *var,
+                          struct amifb_par *par);
+static int ami_encode_var(struct fb_var_screeninfo *var,
+                          struct amifb_par *par);
+static void ami_pan_var(struct fb_var_screeninfo *var);
+static int ami_update_par(void);
+static void ami_update_display(void);
+static void ami_init_display(void);
+static void ami_do_blank(void);
+static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix);
+static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data);
+static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data);
+static int ami_get_cursorstate(struct fb_cursorstate *state);
+static int ami_set_cursorstate(struct fb_cursorstate *state);
+static void ami_set_sprite(void);
+static void ami_init_copper(void);
+static void ami_reinit_copper(void);
+static void ami_build_copper(void);
+static void ami_rebuild_copper(void);
+
+
+static struct fb_ops amifb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= amifb_check_var,
+	.fb_set_par	= amifb_set_par,
+	.fb_setcolreg	= amifb_setcolreg,
+	.fb_blank	= amifb_blank,
+	.fb_pan_display	= amifb_pan_display,
+	.fb_fillrect	= amifb_fillrect,
+	.fb_copyarea	= amifb_copyarea,
+	.fb_imageblit	= amifb_imageblit,
+	.fb_cursor	= soft_cursor,
+	.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;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt)
+			continue;
+		if (!strcmp(this_opt, "inverse")) {
+			amifb_inverse = 1;
+			fb_invert_cmaps();
+		} else if (!strcmp(this_opt, "ilbm"))
+			amifb_ilbm = 1;
+		else if (!strncmp(this_opt, "monitorcap:", 11))
+			amifb_setup_mcap(this_opt+11);
+		else if (!strncmp(this_opt, "fstart:", 7))
+			min_fstrt = simple_strtoul(this_opt+7, NULL, 0);
+		else
+			mode_option = this_opt;
+	}
+
+	if (min_fstrt < 48)
+		min_fstrt = 48;
+
+	return 0;
+}
+
+
+static int amifb_check_var(struct fb_var_screeninfo *var,
+			   struct fb_info *info)
+{
+	int err;
+	struct amifb_par par;
+
+	/* Validate wanted screen parameters */
+	if ((err = ami_decode_var(var, &par)))
+		return err;
+
+	/* Encode (possibly rounded) screen parameters */
+	ami_encode_var(var, &par);
+	return 0;
+}
+
+
+static int amifb_set_par(struct fb_info *info)
+{
+	struct amifb_par *par = (struct amifb_par *)info->par;
+
+	do_vmode_pan = 0;
+	do_vmode_full = 0;
+
+	/* Decode wanted screen parameters */
+	ami_decode_var(&info->var, par);
+
+	/* Set new videomode */
+	ami_build_copper();
+
+	/* Set VBlank trigger */
+	do_vmode_full = 1;
+
+	/* Update fix for new screen parameters */
+	if (par->bpp == 1) {
+		info->fix.type = FB_TYPE_PACKED_PIXELS;
+		info->fix.type_aux = 0;
+	} else if (amifb_ilbm) {
+		info->fix.type = FB_TYPE_INTERLEAVED_PLANES;
+		info->fix.type_aux = par->next_line;
+	} else {
+		info->fix.type = FB_TYPE_PLANES;
+		info->fix.type_aux = 0;
+	}
+	info->fix.line_length = div8(upx(16<<maxfmode, par->vxres));
+
+	if (par->vmode & FB_VMODE_YWRAP) {
+		info->fix.ywrapstep = 1;
+		info->fix.xpanstep = 0;
+		info->fix.ypanstep = 0;
+		info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YWRAP |
+		    FBINFO_READS_FAST; /* override SCROLL_REDRAW */
+	} else {
+		info->fix.ywrapstep = 0;
+		if (par->vmode & FB_VMODE_SMOOTH_XPAN)
+			info->fix.xpanstep = 1;
+		else
+			info->fix.xpanstep = 16<<maxfmode;
+		info->fix.ypanstep = 1;
+		info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+	}
+	return 0;
+}
+
+
+	/*
+	 * Pan or Wrap the Display
+	 *
+	 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
+	 */
+
+static int amifb_pan_display(struct fb_var_screeninfo *var,
+			     struct fb_info *info)
+{
+	if (var->vmode & FB_VMODE_YWRAP) {
+		if (var->yoffset < 0 ||
+		    var->yoffset >= info->var.yres_virtual || var->xoffset)
+			return -EINVAL;
+	} else {
+		/*
+		 * TODO: There will be problems when xpan!=1, so some columns
+		 * on the right side will never be seen
+		 */
+		if (var->xoffset+info->var.xres > upx(16<<maxfmode, info->var.xres_virtual) ||
+		    var->yoffset+info->var.yres > info->var.yres_virtual)
+			return -EINVAL;
+	}
+	ami_pan_var(var);
+	info->var.xoffset = var->xoffset;
+	info->var.yoffset = var->yoffset;
+	if (var->vmode & FB_VMODE_YWRAP)
+		info->var.vmode |= FB_VMODE_YWRAP;
+	else
+		info->var.vmode &= ~FB_VMODE_YWRAP;
+	return 0;
+}
+
+
+#if BITS_PER_LONG == 32
+#define BYTES_PER_LONG	4
+#define SHIFT_PER_LONG	5
+#elif BITS_PER_LONG == 64
+#define BYTES_PER_LONG	8
+#define SHIFT_PER_LONG	6
+#else
+#define Please update me
+#endif
+
+
+    /*
+     *  Compose two values, using a bitmask as decision value
+     *  This is equivalent to (a & mask) | (b & ~mask)
+     */
+
+static inline unsigned long comp(unsigned long a, unsigned long b,
+				 unsigned long mask)
+{
+	return ((a ^ b) & mask) ^ b;
+}
+
+
+static inline unsigned long xor(unsigned long a, unsigned long b,
+				unsigned long mask)
+{
+	return (a & mask) ^ b;
+}
+
+
+    /*
+     *  Unaligned forward bit copy using 32-bit or 64-bit memory accesses
+     */
+
+static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src,
+		   int src_idx, u32 n)
+{
+	unsigned long first, last;
+	int shift = dst_idx-src_idx, left, right;
+	unsigned long d0, d1;
+	int m;
+
+	if (!n)
+		return;
+
+	shift = dst_idx-src_idx;
+	first = ~0UL >> dst_idx;
+	last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
+
+	if (!shift) {
+		// Same alignment for source and dest
+
+		if (dst_idx+n <= BITS_PER_LONG) {
+			// Single word
+			if (last)
+				first &= last;
+			*dst = comp(*src, *dst, first);
+		} else {
+			// Multiple destination words
+			// Leading bits
+			if (first) {
+				*dst = comp(*src, *dst, first);
+				dst++;
+				src++;
+				n -= BITS_PER_LONG-dst_idx;
+			}
+
+			// Main chunk
+			n /= BITS_PER_LONG;
+			while (n >= 8) {
+				*dst++ = *src++;
+				*dst++ = *src++;
+				*dst++ = *src++;
+				*dst++ = *src++;
+				*dst++ = *src++;
+				*dst++ = *src++;
+				*dst++ = *src++;
+				*dst++ = *src++;
+				n -= 8;
+			}
+			while (n--)
+				*dst++ = *src++;
+
+			// Trailing bits
+			if (last)
+				*dst = comp(*src, *dst, last);
+		}
+	} else {
+		// Different alignment for source and dest
+
+		right = shift & (BITS_PER_LONG-1);
+		left = -shift & (BITS_PER_LONG-1);
+
+		if (dst_idx+n <= BITS_PER_LONG) {
+			// Single destination word
+			if (last)
+				first &= last;
+			if (shift > 0) {
+				// Single source word
+				*dst = comp(*src >> right, *dst, first);
+			} else if (src_idx+n <= BITS_PER_LONG) {
+				// Single source word
+				*dst = comp(*src << left, *dst, first);
+			} else {
+				// 2 source words
+				d0 = *src++;
+				d1 = *src;
+				*dst = comp(d0 << left | d1 >> right, *dst,
+					    first);
+			}
+		} else {
+			// Multiple destination words
+			d0 = *src++;
+			// Leading bits
+			if (shift > 0) {
+				// Single source word
+				*dst = comp(d0 >> right, *dst, first);
+				dst++;
+				n -= BITS_PER_LONG-dst_idx;
+			} else {
+				// 2 source words
+				d1 = *src++;
+				*dst = comp(d0 << left | d1 >> right, *dst,
+					    first);
+				d0 = d1;
+				dst++;
+				n -= BITS_PER_LONG-dst_idx;
+			}
+
+			// Main chunk
+			m = n % BITS_PER_LONG;
+			n /= BITS_PER_LONG;
+			while (n >= 4) {
+				d1 = *src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				d1 = *src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				d1 = *src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				d1 = *src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				n -= 4;
+			}
+			while (n--) {
+				d1 = *src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+			}
+
+			// Trailing bits
+			if (last) {
+				if (m <= right) {
+					// Single source word
+					*dst = comp(d0 << left, *dst, last);
+				} else {
+					// 2 source words
+					d1 = *src;
+					*dst = comp(d0 << left | d1 >> right,
+						    *dst, last);
+				}
+			}
+		}
+	}
+}
+
+
+    /*
+     *  Unaligned reverse bit copy using 32-bit or 64-bit memory accesses
+     */
+
+static void bitcpy_rev(unsigned long *dst, int dst_idx,
+		       const unsigned long *src, int src_idx, u32 n)
+{
+	unsigned long first, last;
+	int shift = dst_idx-src_idx, left, right;
+	unsigned long d0, d1;
+	int m;
+
+	if (!n)
+		return;
+
+	dst += (n-1)/BITS_PER_LONG;
+	src += (n-1)/BITS_PER_LONG;
+	if ((n-1) % BITS_PER_LONG) {
+		dst_idx += (n-1) % BITS_PER_LONG;
+		dst += dst_idx >> SHIFT_PER_LONG;
+		dst_idx &= BITS_PER_LONG-1;
+		src_idx += (n-1) % BITS_PER_LONG;
+		src += src_idx >> SHIFT_PER_LONG;
+		src_idx &= BITS_PER_LONG-1;
+	}
+
+	shift = dst_idx-src_idx;
+	first = ~0UL << (BITS_PER_LONG-1-dst_idx);
+	last = ~(~0UL << (BITS_PER_LONG-1-((dst_idx-n) % BITS_PER_LONG)));
+
+	if (!shift) {
+		// Same alignment for source and dest
+
+		if ((unsigned long)dst_idx+1 >= n) {
+			// Single word
+			if (last)
+				first &= last;
+			*dst = comp(*src, *dst, first);
+		} else {
+			// Multiple destination words
+			// Leading bits
+			if (first) {
+				*dst = comp(*src, *dst, first);
+				dst--;
+				src--;
+				n -= dst_idx+1;
+			}
+
+			// Main chunk
+			n /= BITS_PER_LONG;
+			while (n >= 8) {
+				*dst-- = *src--;
+				*dst-- = *src--;
+				*dst-- = *src--;
+				*dst-- = *src--;
+				*dst-- = *src--;
+				*dst-- = *src--;
+				*dst-- = *src--;
+				*dst-- = *src--;
+				n -= 8;
+			}
+			while (n--)
+				*dst-- = *src--;
+
+			// Trailing bits
+			if (last)
+				*dst = comp(*src, *dst, last);
+		}
+	} else {
+		// Different alignment for source and dest
+
+		right = shift & (BITS_PER_LONG-1);
+		left = -shift & (BITS_PER_LONG-1);
+
+		if ((unsigned long)dst_idx+1 >= n) {
+			// Single destination word
+			if (last)
+				first &= last;
+			if (shift < 0) {
+				// Single source word
+				*dst = comp(*src << left, *dst, first);
+			} else if (1+(unsigned long)src_idx >= n) {
+				// Single source word
+				*dst = comp(*src >> right, *dst, first);
+			} else {
+				// 2 source words
+				d0 = *src--;
+				d1 = *src;
+				*dst = comp(d0 >> right | d1 << left, *dst,
+					    first);
+			}
+		} else {
+			// Multiple destination words
+			d0 = *src--;
+			// Leading bits
+			if (shift < 0) {
+				// Single source word
+				*dst = comp(d0 << left, *dst, first);
+				dst--;
+				n -= dst_idx+1;
+			} else {
+				// 2 source words
+				d1 = *src--;
+				*dst = comp(d0 >> right | d1 << left, *dst,
+					    first);
+				d0 = d1;
+				dst--;
+				n -= dst_idx+1;
+			}
+
+			// Main chunk
+			m = n % BITS_PER_LONG;
+			n /= BITS_PER_LONG;
+			while (n >= 4) {
+				d1 = *src--;
+				*dst-- = d0 >> right | d1 << left;
+				d0 = d1;
+				d1 = *src--;
+				*dst-- = d0 >> right | d1 << left;
+				d0 = d1;
+				d1 = *src--;
+				*dst-- = d0 >> right | d1 << left;
+				d0 = d1;
+				d1 = *src--;
+				*dst-- = d0 >> right | d1 << left;
+				d0 = d1;
+				n -= 4;
+			}
+			while (n--) {
+				d1 = *src--;
+				*dst-- = d0 >> right | d1 << left;
+				d0 = d1;
+			}
+
+			// Trailing bits
+			if (last) {
+				if (m <= left) {
+					// Single source word
+					*dst = comp(d0 >> right, *dst, last);
+				} else {
+					// 2 source words
+					d1 = *src;
+					*dst = comp(d0 >> right | d1 << left,
+						    *dst, last);
+				}
+			}
+		}
+	}
+}
+
+
+    /*
+     *  Unaligned forward inverting bit copy using 32-bit or 64-bit memory
+     *  accesses
+     */
+
+static void bitcpy_not(unsigned long *dst, int dst_idx,
+		       const unsigned long *src, int src_idx, u32 n)
+{
+	unsigned long first, last;
+	int shift = dst_idx-src_idx, left, right;
+	unsigned long d0, d1;
+	int m;
+
+	if (!n)
+		return;
+
+	shift = dst_idx-src_idx;
+	first = ~0UL >> dst_idx;
+	last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
+
+	if (!shift) {
+		// Same alignment for source and dest
+
+		if (dst_idx+n <= BITS_PER_LONG) {
+			// Single word
+			if (last)
+				first &= last;
+			*dst = comp(~*src, *dst, first);
+		} else {
+			// Multiple destination words
+			// Leading bits
+			if (first) {
+				*dst = comp(~*src, *dst, first);
+				dst++;
+				src++;
+				n -= BITS_PER_LONG-dst_idx;
+			}
+
+			// Main chunk
+			n /= BITS_PER_LONG;
+			while (n >= 8) {
+				*dst++ = ~*src++;
+				*dst++ = ~*src++;
+				*dst++ = ~*src++;
+				*dst++ = ~*src++;
+				*dst++ = ~*src++;
+				*dst++ = ~*src++;
+				*dst++ = ~*src++;
+				*dst++ = ~*src++;
+				n -= 8;
+			}
+			while (n--)
+				*dst++ = ~*src++;
+
+			// Trailing bits
+			if (last)
+				*dst = comp(~*src, *dst, last);
+		}
+	} else {
+		// Different alignment for source and dest
+
+		right = shift & (BITS_PER_LONG-1);
+		left = -shift & (BITS_PER_LONG-1);
+
+		if (dst_idx+n <= BITS_PER_LONG) {
+			// Single destination word
+			if (last)
+				first &= last;
+			if (shift > 0) {
+				// Single source word
+				*dst = comp(~*src >> right, *dst, first);
+			} else if (src_idx+n <= BITS_PER_LONG) {
+				// Single source word
+				*dst = comp(~*src << left, *dst, first);
+			} else {
+				// 2 source words
+				d0 = ~*src++;
+				d1 = ~*src;
+				*dst = comp(d0 << left | d1 >> right, *dst,
+					    first);
+			}
+		} else {
+			// Multiple destination words
+			d0 = ~*src++;
+			// Leading bits
+			if (shift > 0) {
+				// Single source word
+				*dst = comp(d0 >> right, *dst, first);
+				dst++;
+				n -= BITS_PER_LONG-dst_idx;
+			} else {
+				// 2 source words
+				d1 = ~*src++;
+				*dst = comp(d0 << left | d1 >> right, *dst,
+					    first);
+				d0 = d1;
+				dst++;
+				n -= BITS_PER_LONG-dst_idx;
+			}
+
+			// Main chunk
+			m = n % BITS_PER_LONG;
+			n /= BITS_PER_LONG;
+			while (n >= 4) {
+				d1 = ~*src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				d1 = ~*src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				d1 = ~*src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				d1 = ~*src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				n -= 4;
+			}
+			while (n--) {
+				d1 = ~*src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+			}
+
+			// Trailing bits
+			if (last) {
+				if (m <= right) {
+					// Single source word
+					*dst = comp(d0 << left, *dst, last);
+				} else {
+					// 2 source words
+					d1 = ~*src;
+					*dst = comp(d0 << left | d1 >> right,
+						    *dst, last);
+				}
+			}
+		}
+	}
+}
+
+
+    /*
+     *  Unaligned 32-bit pattern fill using 32/64-bit memory accesses
+     */
+
+static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n)
+{
+	unsigned long val = pat;
+	unsigned long first, last;
+
+	if (!n)
+		return;
+
+#if BITS_PER_LONG == 64
+	val |= val << 32;
+#endif
+
+	first = ~0UL >> dst_idx;
+	last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
+
+	if (dst_idx+n <= BITS_PER_LONG) {
+		// Single word
+		if (last)
+			first &= last;
+		*dst = comp(val, *dst, first);
+	} else {
+		// Multiple destination words
+		// Leading bits
+		if (first) {
+			*dst = comp(val, *dst, first);
+			dst++;
+			n -= BITS_PER_LONG-dst_idx;
+		}
+
+		// Main chunk
+		n /= BITS_PER_LONG;
+		while (n >= 8) {
+			*dst++ = val;
+			*dst++ = val;
+			*dst++ = val;
+			*dst++ = val;
+			*dst++ = val;
+			*dst++ = val;
+			*dst++ = val;
+			*dst++ = val;
+			n -= 8;
+		}
+		while (n--)
+			*dst++ = val;
+
+		// Trailing bits
+		if (last)
+			*dst = comp(val, *dst, last);
+	}
+}
+
+
+    /*
+     *  Unaligned 32-bit pattern xor using 32/64-bit memory accesses
+     */
+
+static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n)
+{
+	unsigned long val = pat;
+	unsigned long first, last;
+
+	if (!n)
+		return;
+
+#if BITS_PER_LONG == 64
+	val |= val << 32;
+#endif
+
+	first = ~0UL >> dst_idx;
+	last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
+
+	if (dst_idx+n <= BITS_PER_LONG) {
+		// Single word
+		if (last)
+			first &= last;
+		*dst = xor(val, *dst, first);
+	} else {
+		// Multiple destination words
+		// Leading bits
+		if (first) {
+			*dst = xor(val, *dst, first);
+			dst++;
+			n -= BITS_PER_LONG-dst_idx;
+		}
+
+		// Main chunk
+		n /= BITS_PER_LONG;
+		while (n >= 4) {
+			*dst++ ^= val;
+			*dst++ ^= val;
+			*dst++ ^= val;
+			*dst++ ^= val;
+			n -= 4;
+		}
+		while (n--)
+			*dst++ ^= val;
+
+		// Trailing bits
+		if (last)
+			*dst = xor(val, *dst, last);
+	}
+}
+
+static inline void fill_one_line(int bpp, unsigned long next_plane,
+				 unsigned long *dst, int dst_idx, u32 n,
+				 u32 color)
+{
+	while (1) {
+		dst += dst_idx >> SHIFT_PER_LONG;
+		dst_idx &= (BITS_PER_LONG-1);
+		bitfill32(dst, dst_idx, color & 1 ? ~0 : 0, n);
+		if (!--bpp)
+			break;
+		color >>= 1;
+		dst_idx += next_plane*8;
+	}
+}
+
+static inline void xor_one_line(int bpp, unsigned long next_plane,
+				unsigned long *dst, int dst_idx, u32 n,
+				u32 color)
+{
+	while (color) {
+		dst += dst_idx >> SHIFT_PER_LONG;
+		dst_idx &= (BITS_PER_LONG-1);
+		bitxor32(dst, dst_idx, color & 1 ? ~0 : 0, n);
+		if (!--bpp)
+			break;
+		color >>= 1;
+		dst_idx += next_plane*8;
+	}
+}
+
+
+static void amifb_fillrect(struct fb_info *info,
+			   const struct fb_fillrect *rect)
+{
+	struct amifb_par *par = (struct amifb_par *)info->par;
+	int dst_idx, x2, y2;
+	unsigned long *dst;
+	u32 width, height;
+
+	if (!rect->width || !rect->height)
+		return;
+
+	/*
+	 * We could use hardware clipping but on many cards you get around
+	 * hardware clipping by writing to framebuffer directly.
+	 * */
+	x2 = rect->dx + rect->width;
+	y2 = rect->dy + rect->height;
+	x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
+	y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
+	width = x2 - rect->dx;
+	height = y2 - rect->dy;
+
+	dst = (unsigned long *)
+		((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1));
+	dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8;
+	dst_idx += rect->dy*par->next_line*8+rect->dx;
+	while (height--) {
+		switch (rect->rop) {
+		    case ROP_COPY:
+			fill_one_line(info->var.bits_per_pixel,
+				      par->next_plane, dst, dst_idx, width,
+				      rect->color);
+			break;
+
+		    case ROP_XOR:
+			xor_one_line(info->var.bits_per_pixel, par->next_plane,
+				     dst, dst_idx, width, rect->color);
+			break;
+		}
+		dst_idx += par->next_line*8;
+	}
+}
+
+static inline void copy_one_line(int bpp, unsigned long next_plane,
+				 unsigned long *dst, int dst_idx,
+				 unsigned long *src, int src_idx, u32 n)
+{
+	while (1) {
+		dst += dst_idx >> SHIFT_PER_LONG;
+		dst_idx &= (BITS_PER_LONG-1);
+		src += src_idx >> SHIFT_PER_LONG;
+		src_idx &= (BITS_PER_LONG-1);
+		bitcpy(dst, dst_idx, src, src_idx, n);
+		if (!--bpp)
+			break;
+		dst_idx += next_plane*8;
+		src_idx += next_plane*8;
+	}
+}
+
+static inline void copy_one_line_rev(int bpp, unsigned long next_plane,
+				     unsigned long *dst, int dst_idx,
+				     unsigned long *src, int src_idx, u32 n)
+{
+	while (1) {
+		dst += dst_idx >> SHIFT_PER_LONG;
+		dst_idx &= (BITS_PER_LONG-1);
+		src += src_idx >> SHIFT_PER_LONG;
+		src_idx &= (BITS_PER_LONG-1);
+		bitcpy_rev(dst, dst_idx, src, src_idx, n);
+		if (!--bpp)
+			break;
+		dst_idx += next_plane*8;
+		src_idx += next_plane*8;
+	}
+}
+
+
+static void amifb_copyarea(struct fb_info *info,
+			   const struct fb_copyarea *area)
+{
+	struct amifb_par *par = (struct amifb_par *)info->par;
+	int x2, y2;
+	u32 dx, dy, sx, sy, width, height;
+	unsigned long *dst, *src;
+	int dst_idx, src_idx;
+	int rev_copy = 0;
+
+	/* clip the destination */
+	x2 = area->dx + area->width;
+	y2 = area->dy + area->height;
+	dx = area->dx > 0 ? area->dx : 0;
+	dy = area->dy > 0 ? area->dy : 0;
+	x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
+	y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
+	width = x2 - dx;
+	height = y2 - dy;
+
+	/* update sx,sy */
+	sx = area->sx + (dx - area->dx);
+	sy = area->sy + (dy - area->dy);
+
+	/* the source must be completely inside the virtual screen */
+	if (sx < 0 || sy < 0 || (sx + width) > info->var.xres_virtual ||
+	    (sy + height) > info->var.yres_virtual)
+		return;
+
+	if (dy > sy || (dy == sy && dx > sx)) {
+		dy += height;
+		sy += height;
+		rev_copy = 1;
+	}
+	dst = (unsigned long *)
+		((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1));
+	src = dst;
+	dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8;
+	src_idx = dst_idx;
+	dst_idx += dy*par->next_line*8+dx;
+	src_idx += sy*par->next_line*8+sx;
+	if (rev_copy) {
+		while (height--) {
+			dst_idx -= par->next_line*8;
+			src_idx -= par->next_line*8;
+			copy_one_line_rev(info->var.bits_per_pixel,
+					  par->next_plane, dst, dst_idx, src,
+					  src_idx, width);
+		}
+	} else {
+		while (height--) {
+			copy_one_line(info->var.bits_per_pixel,
+				      par->next_plane, dst, dst_idx, src,
+				      src_idx, width);
+			dst_idx += par->next_line*8;
+			src_idx += par->next_line*8;
+		}
+	}
+}
+
+
+static inline void expand_one_line(int bpp, unsigned long next_plane,
+				   unsigned long *dst, int dst_idx, u32 n,
+				   const u8 *data, u32 bgcolor, u32 fgcolor)
+{
+    const unsigned long *src;
+    int src_idx;
+
+    while (1) {
+	dst += dst_idx >> SHIFT_PER_LONG;
+	dst_idx &= (BITS_PER_LONG-1);
+	if ((bgcolor ^ fgcolor) & 1) {
+	    src = (unsigned long *)((unsigned long)data & ~(BYTES_PER_LONG-1));
+	    src_idx = ((unsigned long)data & (BYTES_PER_LONG-1))*8;
+	    if (fgcolor & 1)
+		bitcpy(dst, dst_idx, src, src_idx, n);
+	    else
+		bitcpy_not(dst, dst_idx, src, src_idx, n);
+	    /* set or clear */
+	} else
+	    bitfill32(dst, dst_idx, fgcolor & 1 ? ~0 : 0, n);
+	if (!--bpp)
+	    break;
+	bgcolor >>= 1;
+	fgcolor >>= 1;
+	dst_idx += next_plane*8;
+    }
+}
+
+
+static void amifb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	struct amifb_par *par = (struct amifb_par *)info->par;
+	int x2, y2;
+	unsigned long *dst;
+	int dst_idx;
+	const char *src;
+	u32 dx, dy, width, height, pitch;
+
+	/*
+	 * We could use hardware clipping but on many cards you get around
+	 * hardware clipping by writing to framebuffer directly like we are
+	 * doing here.
+	 */
+	x2 = image->dx + image->width;
+	y2 = image->dy + image->height;
+	dx = image->dx;
+	dy = image->dy;
+	x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
+	y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
+	width  = x2 - dx;
+	height = y2 - dy;
+
+	if (image->depth == 1) {
+		dst = (unsigned long *)
+			((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1));
+		dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8;
+		dst_idx += dy*par->next_line*8+dx;
+		src = image->data;
+		pitch = (image->width+7)/8;
+		while (height--) {
+			expand_one_line(info->var.bits_per_pixel,
+					par->next_plane, dst, dst_idx, width,
+					src, image->bg_color,
+					image->fg_color);
+			dst_idx += par->next_line*8;
+			src += pitch;
+		}
+	} else {
+		c2p(info->screen_base, image->data, dx, dy, width, height,
+		    par->next_line, par->next_plane, image->width,
+		    info->var.bits_per_pixel);
+	}
+}
+
+
+	/*
+	 * Amiga Frame Buffer Specific ioctls
+	 */
+
+static int amifb_ioctl(struct inode *inode, struct file *file,
+		       unsigned int cmd, unsigned long arg,
+		       struct fb_info *info)
+{
+	union {
+		struct fb_fix_cursorinfo fix;
+		struct fb_var_cursorinfo var;
+		struct fb_cursorstate state;
+	} crsr;
+	int i;
+
+	switch (cmd) {
+		case FBIOGET_FCURSORINFO:
+			i = ami_get_fix_cursorinfo(&crsr.fix);
+			if (i)
+				return i;
+			return copy_to_user((void *)arg, &crsr.fix,
+					    sizeof(crsr.fix)) ? -EFAULT : 0;
+
+		case FBIOGET_VCURSORINFO:
+			i = ami_get_var_cursorinfo(&crsr.var,
+				((struct fb_var_cursorinfo *)arg)->data);
+			if (i)
+				return i;
+			return copy_to_user((void *)arg, &crsr.var,
+					    sizeof(crsr.var)) ? -EFAULT : 0;
+
+		case FBIOPUT_VCURSORINFO:
+			if (copy_from_user(&crsr.var, (void *)arg,
+					   sizeof(crsr.var)))
+				return -EFAULT;
+			return ami_set_var_cursorinfo(&crsr.var,
+				((struct fb_var_cursorinfo *)arg)->data);
+
+		case FBIOGET_CURSORSTATE:
+			i = ami_get_cursorstate(&crsr.state);
+			if (i)
+				return i;
+			return copy_to_user((void *)arg, &crsr.state,
+					    sizeof(crsr.state)) ? -EFAULT : 0;
+
+		case FBIOPUT_CURSORSTATE:
+			if (copy_from_user(&crsr.state, (void *)arg,
+					   sizeof(crsr.state)))
+				return -EFAULT;
+			return ami_set_cursorstate(&crsr.state);
+	}
+	return -EINVAL;
+}
+
+
+	/*
+	 * Allocate, Clear and Align a Block of Chip Memory
+	 */
+
+static u_long unaligned_chipptr = 0;
+
+static inline u_long __init chipalloc(u_long size)
+{
+	size += PAGE_SIZE-1;
+	if (!(unaligned_chipptr = (u_long)amiga_chip_alloc(size,
+							   "amifb [RAM]")))
+		panic("No Chip RAM for frame buffer");
+	memset((void *)unaligned_chipptr, 0, size);
+	return PAGE_ALIGN(unaligned_chipptr);
+}
+
+static inline void chipfree(void)
+{
+	if (unaligned_chipptr)
+		amiga_chip_free((void *)unaligned_chipptr);
+}
+
+
+	/*
+	 * Initialisation
+	 */
+
+int __init amifb_init(void)
+{
+	int tag, i, err = 0;
+	u_long chipptr;
+	u_int defmode;
+
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("amifb", &option)) {
+		amifb_video_off();
+		return -ENODEV;
+	}
+	amifb_setup(option);
+#endif
+	if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_VIDEO))
+		return -ENXIO;
+
+	/*
+	 * We request all registers starting from bplpt[0]
+	 */
+	if (!request_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120,
+				"amifb [Denise/Lisa]"))
+		return -EBUSY;
+
+	custom.dmacon = DMAF_ALL | DMAF_MASTER;
+
+	switch (amiga_chipset) {
+#ifdef CONFIG_FB_AMIGA_OCS
+		case CS_OCS:
+			strcat(fb_info.fix.id, "OCS");
+default_chipset:
+			chipset = TAG_OCS;
+			maxdepth[TAG_SHRES] = 0;	/* OCS means no SHRES */
+			maxdepth[TAG_HIRES] = 4;
+			maxdepth[TAG_LORES] = 6;
+			maxfmode = TAG_FMODE_1;
+			defmode = amiga_vblank == 50 ? DEFMODE_PAL
+						     : DEFMODE_NTSC;
+			fb_info.fix.smem_len = VIDEOMEMSIZE_OCS;
+			break;
+#endif /* CONFIG_FB_AMIGA_OCS */
+
+#ifdef CONFIG_FB_AMIGA_ECS
+		case CS_ECS:
+			strcat(fb_info.fix.id, "ECS");
+			chipset = TAG_ECS;
+			maxdepth[TAG_SHRES] = 2;
+			maxdepth[TAG_HIRES] = 4;
+			maxdepth[TAG_LORES] = 6;
+			maxfmode = TAG_FMODE_1;
+			if (AMIGAHW_PRESENT(AMBER_FF))
+			    defmode = amiga_vblank == 50 ? DEFMODE_AMBER_PAL
+							 : DEFMODE_AMBER_NTSC;
+			else
+			    defmode = amiga_vblank == 50 ? DEFMODE_PAL
+							 : DEFMODE_NTSC;
+			if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
+			    VIDEOMEMSIZE_ECS_1M)
+				fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_2M;
+			else
+				fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_1M;
+			break;
+#endif /* CONFIG_FB_AMIGA_ECS */
+
+#ifdef CONFIG_FB_AMIGA_AGA
+		case CS_AGA:
+			strcat(fb_info.fix.id, "AGA");
+			chipset = TAG_AGA;
+			maxdepth[TAG_SHRES] = 8;
+			maxdepth[TAG_HIRES] = 8;
+			maxdepth[TAG_LORES] = 8;
+			maxfmode = TAG_FMODE_4;
+			defmode = DEFMODE_AGA;
+			if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
+			    VIDEOMEMSIZE_AGA_1M)
+				fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_2M;
+			else
+				fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_1M;
+			break;
+#endif /* CONFIG_FB_AMIGA_AGA */
+
+		default:
+#ifdef CONFIG_FB_AMIGA_OCS
+			printk("Unknown graphics chipset, defaulting to OCS\n");
+			strcat(fb_info.fix.id, "Unknown");
+			goto default_chipset;
+#else /* CONFIG_FB_AMIGA_OCS */
+			err = -ENXIO;
+			goto amifb_error;
+#endif /* CONFIG_FB_AMIGA_OCS */
+			break;
+	}
+
+	/*
+	 * Calculate the Pixel Clock Values for this Machine
+	 */
+
+	{
+	u_long tmp = DIVUL(200000000000ULL, amiga_eclock);
+
+	pixclock[TAG_SHRES] = (tmp + 4) / 8;	/* SHRES:  35 ns / 28 MHz */
+	pixclock[TAG_HIRES] = (tmp + 2) / 4;	/* HIRES:  70 ns / 14 MHz */
+	pixclock[TAG_LORES] = (tmp + 1) / 2;	/* LORES: 140 ns /  7 MHz */
+	}
+
+	/*
+	 * Replace the Tag Values with the Real Pixel Clock Values
+	 */
+
+	for (i = 0; i < NUM_TOTAL_MODES; i++) {
+		struct fb_videomode *mode = &ami_modedb[i];
+		tag = mode->pixclock;
+		if (tag == TAG_SHRES || tag == TAG_HIRES || tag == TAG_LORES) {
+			mode->pixclock = pixclock[tag];
+		}
+	}
+
+	/*
+	 *  These monitor specs are for a typical Amiga monitor (e.g. A1960)
+	 */
+	if (fb_info.monspecs.hfmin == 0) {
+	    fb_info.monspecs.hfmin = 15000;
+	    fb_info.monspecs.hfmax = 38000;
+	    fb_info.monspecs.vfmin = 49;
+	    fb_info.monspecs.vfmax = 90;
+	}
+
+	fb_info.fbops = &amifb_ops;
+	fb_info.par = &currentpar;
+	fb_info.flags = FBINFO_DEFAULT;
+
+	if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, ami_modedb,
+			  NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) {
+		err = -EINVAL;
+		goto amifb_error;
+	}
+
+	round_down_bpp = 0;
+	chipptr = chipalloc(fb_info.fix.smem_len+
+	                    SPRITEMEMSIZE+
+	                    DUMMYSPRITEMEMSIZE+
+	                    COPINITSIZE+
+	                    4*COPLISTSIZE);
+
+	assignchunk(videomemory, u_long, chipptr, fb_info.fix.smem_len);
+	assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE);
+	assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE);
+	assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE);
+	assignchunk(copdisplay.list[0][0], copins *, chipptr, COPLISTSIZE);
+	assignchunk(copdisplay.list[0][1], copins *, chipptr, COPLISTSIZE);
+	assignchunk(copdisplay.list[1][0], copins *, chipptr, COPLISTSIZE);
+	assignchunk(copdisplay.list[1][1], copins *, chipptr, COPLISTSIZE);
+
+	/*
+	 * access the videomem with writethrough cache
+	 */
+	fb_info.fix.smem_start = (u_long)ZTWO_PADDR(videomemory);
+	videomemory = (u_long)ioremap_writethrough(fb_info.fix.smem_start,
+						   fb_info.fix.smem_len);
+	if (!videomemory) {
+		printk("amifb: WARNING! unable to map videomem cached writethrough\n");
+		videomemory = ZTWO_VADDR(fb_info.fix.smem_start);
+	}
+
+	fb_info.screen_base = (char *)videomemory;
+	memset(dummysprite, 0, DUMMYSPRITEMEMSIZE);
+
+	/*
+	 * Enable Display DMA
+	 */
+
+	custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
+	                DMAF_BLITTER | DMAF_SPRITE;
+
+	/*
+	 * Make sure the Copper has something to do
+	 */
+
+	ami_init_copper();
+
+	if (request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0,
+	                "fb vertb handler", &currentpar)) {
+		err = -EBUSY;
+		goto amifb_error;
+	}
+
+	fb_alloc_cmap(&fb_info.cmap, 1<<fb_info.var.bits_per_pixel, 0);
+
+	if (register_framebuffer(&fb_info) < 0) {
+		err = -EINVAL;
+		goto amifb_error;
+	}
+
+	printk("fb%d: %s frame buffer device, using %dK of video memory\n",
+	       fb_info.node, fb_info.fix.id, fb_info.fix.smem_len>>10);
+
+	return 0;
+
+amifb_error:
+	amifb_deinit();
+	return err;
+}
+
+static void amifb_deinit(void)
+{
+	fb_dealloc_cmap(&fb_info.cmap);
+	chipfree();
+	release_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120);
+	custom.dmacon = DMAF_ALL | DMAF_MASTER;
+}
+
+
+	/*
+	 * Blank the display.
+	 */
+
+static int amifb_blank(int blank, struct fb_info *info)
+{
+	do_blank = blank ? blank : -1;
+
+	return 0;
+}
+
+	/*
+	 * Flash the cursor (called by VBlank interrupt)
+	 */
+
+static int flash_cursor(void)
+{
+	static int cursorcount = 1;
+
+	if (cursormode == FB_CURSOR_FLASH) {
+		if (!--cursorcount) {
+			cursorstate = -cursorstate;
+			cursorcount = cursorrate;
+			if (!is_blanked)
+				return 1;
+		}
+	}
+	return 0;
+}
+
+	/*
+	 * VBlank Display Interrupt
+	 */
+
+static irqreturn_t amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp)
+{
+	if (do_vmode_pan || do_vmode_full)
+		ami_update_display();
+
+	if (do_vmode_full)
+		ami_init_display();
+
+	if (do_vmode_pan) {
+		flash_cursor();
+		ami_rebuild_copper();
+		do_cursor = do_vmode_pan = 0;
+	} else if (do_cursor) {
+		flash_cursor();
+		ami_set_sprite();
+		do_cursor = 0;
+	} else {
+		if (flash_cursor())
+			ami_set_sprite();
+	}
+
+	if (do_blank) {
+		ami_do_blank();
+		do_blank = 0;
+	}
+
+	if (do_vmode_full) {
+		ami_reinit_copper();
+		do_vmode_full = 0;
+	}
+	return IRQ_HANDLED;
+}
+
+/* --------------------------- Hardware routines --------------------------- */
+
+	/*
+	 * Get the video params out of `var'. If a value doesn't fit, round
+	 * it up, if it's too big, return -EINVAL.
+	 */
+
+static int ami_decode_var(struct fb_var_screeninfo *var,
+                          struct amifb_par *par)
+{
+	u_short clk_shift, line_shift;
+	u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n;
+	u_int htotal, vtotal;
+
+	/*
+	 * Find a matching Pixel Clock
+	 */
+
+	for (clk_shift = TAG_SHRES; clk_shift <= TAG_LORES; clk_shift++)
+		if (var->pixclock <= pixclock[clk_shift])
+			break;
+	if (clk_shift > TAG_LORES) {
+		DPRINTK("pixclock too high\n");
+		return -EINVAL;
+	}
+	par->clk_shift = clk_shift;
+
+	/*
+	 * Check the Geometry Values
+	 */
+
+	if ((par->xres = var->xres) < 64)
+		par->xres = 64;
+	if ((par->yres = var->yres) < 64)
+		par->yres = 64;
+	if ((par->vxres = var->xres_virtual) < par->xres)
+		par->vxres = par->xres;
+	if ((par->vyres = var->yres_virtual) < par->yres)
+		par->vyres = par->yres;
+
+	par->bpp = var->bits_per_pixel;
+	if (!var->nonstd) {
+		if (par->bpp < 1)
+			par->bpp = 1;
+		if (par->bpp > maxdepth[clk_shift]) {
+			if (round_down_bpp && maxdepth[clk_shift])
+				par->bpp = maxdepth[clk_shift];
+			else {
+				DPRINTK("invalid bpp\n");
+				return -EINVAL;
+			}
+		}
+	} else if (var->nonstd == FB_NONSTD_HAM) {
+		if (par->bpp < 6)
+			par->bpp = 6;
+		if (par->bpp != 6) {
+			if (par->bpp < 8)
+				par->bpp = 8;
+			if (par->bpp != 8 || !IS_AGA) {
+				DPRINTK("invalid bpp for ham mode\n");
+				return -EINVAL;
+			}
+		}
+	} else {
+		DPRINTK("unknown nonstd mode\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the folloing
+	 * checks failed and smooth scrolling is not possible
+	 */
+
+	par->vmode = var->vmode | FB_VMODE_SMOOTH_XPAN;
+	switch (par->vmode & FB_VMODE_MASK) {
+		case FB_VMODE_INTERLACED:
+			line_shift = 0;
+			break;
+		case FB_VMODE_NONINTERLACED:
+			line_shift = 1;
+			break;
+		case FB_VMODE_DOUBLE:
+			if (!IS_AGA) {
+				DPRINTK("double mode only possible with aga\n");
+				return -EINVAL;
+			}
+			line_shift = 2;
+			break;
+		default:
+			DPRINTK("unknown video mode\n");
+			return -EINVAL;
+			break;
+	}
+	par->line_shift = line_shift;
+
+	/*
+	 * Vertical and Horizontal Timings
+	 */
+
+	xres_n = par->xres<<clk_shift;
+	yres_n = par->yres<<line_shift;
+	par->htotal = down8((var->left_margin+par->xres+var->right_margin+var->hsync_len)<<clk_shift);
+	par->vtotal = down2(((var->upper_margin+par->yres+var->lower_margin+var->vsync_len)<<line_shift)+1);
+
+	if (IS_AGA)
+		par->bplcon3 = sprpixmode[clk_shift];
+	else
+		par->bplcon3 = 0;
+	if (var->sync & FB_SYNC_BROADCAST) {
+		par->diwstop_h = par->htotal-((var->right_margin-var->hsync_len)<<clk_shift);
+		if (IS_AGA)
+			par->diwstop_h += mod4(var->hsync_len);
+		else
+			par->diwstop_h = down4(par->diwstop_h);
+
+		par->diwstrt_h = par->diwstop_h - xres_n;
+		par->diwstop_v = par->vtotal-((var->lower_margin-var->vsync_len)<<line_shift);
+		par->diwstrt_v = par->diwstop_v - yres_n;
+		if (par->diwstop_h >= par->htotal+8) {
+			DPRINTK("invalid diwstop_h\n");
+			return -EINVAL;
+		}
+		if (par->diwstop_v > par->vtotal) {
+			DPRINTK("invalid diwstop_v\n");
+			return -EINVAL;
+		}
+
+		if (!IS_OCS) {
+			/* Initialize sync with some reasonable values for pwrsave */
+			par->hsstrt = 160;
+			par->hsstop = 320;
+			par->vsstrt = 30;
+			par->vsstop = 34;
+		} else {
+			par->hsstrt = 0;
+			par->hsstop = 0;
+			par->vsstrt = 0;
+			par->vsstop = 0;
+		}
+		if (par->vtotal > (PAL_VTOTAL+NTSC_VTOTAL)/2) {
+			/* PAL video mode */
+			if (par->htotal != PAL_HTOTAL) {
+				DPRINTK("htotal invalid for pal\n");
+				return -EINVAL;
+			}
+			if (par->diwstrt_h < PAL_DIWSTRT_H) {
+				DPRINTK("diwstrt_h too low for pal\n");
+				return -EINVAL;
+			}
+			if (par->diwstrt_v < PAL_DIWSTRT_V) {
+				DPRINTK("diwstrt_v too low for pal\n");
+				return -EINVAL;
+			}
+			htotal = PAL_HTOTAL>>clk_shift;
+			vtotal = PAL_VTOTAL>>1;
+			if (!IS_OCS) {
+				par->beamcon0 = BMC0_PAL;
+				par->bplcon3 |= BPC3_BRDRBLNK;
+			} else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
+			           AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
+				par->beamcon0 = BMC0_PAL;
+				par->hsstop = 1;
+			} else if (amiga_vblank != 50) {
+				DPRINTK("pal not supported by this chipset\n");
+				return -EINVAL;
+			}
+		} else {
+			/* NTSC video mode
+			 * In the AGA chipset seems to be hardware bug with BPC3_BRDRBLNK
+			 * and NTSC activated, so than better let diwstop_h <= 1812
+			 */
+			if (par->htotal != NTSC_HTOTAL) {
+				DPRINTK("htotal invalid for ntsc\n");
+				return -EINVAL;
+			}
+			if (par->diwstrt_h < NTSC_DIWSTRT_H) {
+				DPRINTK("diwstrt_h too low for ntsc\n");
+				return -EINVAL;
+			}
+			if (par->diwstrt_v < NTSC_DIWSTRT_V) {
+				DPRINTK("diwstrt_v too low for ntsc\n");
+				return -EINVAL;
+			}
+			htotal = NTSC_HTOTAL>>clk_shift;
+			vtotal = NTSC_VTOTAL>>1;
+			if (!IS_OCS) {
+				par->beamcon0 = 0;
+				par->bplcon3 |= BPC3_BRDRBLNK;
+			} else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
+			           AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
+				par->beamcon0 = 0;
+				par->hsstop = 1;
+			} else if (amiga_vblank != 60) {
+				DPRINTK("ntsc not supported by this chipset\n");
+				return -EINVAL;
+			}
+		}
+		if (IS_OCS) {
+			if (par->diwstrt_h >= 1024 || par->diwstop_h < 1024 ||
+			    par->diwstrt_v >=  512 || par->diwstop_v <  256) {
+				DPRINTK("invalid position for display on ocs\n");
+				return -EINVAL;
+			}
+		}
+	} else if (!IS_OCS) {
+		/* Programmable video mode */
+		par->hsstrt = var->right_margin<<clk_shift;
+		par->hsstop = (var->right_margin+var->hsync_len)<<clk_shift;
+		par->diwstop_h = par->htotal - mod8(par->hsstrt) + 8 - (1 << clk_shift);
+		if (!IS_AGA)
+			par->diwstop_h = down4(par->diwstop_h) - 16;
+		par->diwstrt_h = par->diwstop_h - xres_n;
+		par->hbstop = par->diwstrt_h + 4;
+		par->hbstrt = par->diwstop_h + 4;
+		if (par->hbstrt >= par->htotal + 8)
+			par->hbstrt -= par->htotal;
+		par->hcenter = par->hsstrt + (par->htotal >> 1);
+		par->vsstrt = var->lower_margin<<line_shift;
+		par->vsstop = (var->lower_margin+var->vsync_len)<<line_shift;
+		par->diwstop_v = par->vtotal;
+		if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
+			par->diwstop_v -= 2;
+		par->diwstrt_v = par->diwstop_v - yres_n;
+		par->vbstop = par->diwstrt_v - 2;
+		par->vbstrt = par->diwstop_v - 2;
+		if (par->vtotal > 2048) {
+			DPRINTK("vtotal too high\n");
+			return -EINVAL;
+		}
+		if (par->htotal > 2048) {
+			DPRINTK("htotal too high\n");
+			return -EINVAL;
+		}
+		par->bplcon3 |= BPC3_EXTBLKEN;
+		par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS |
+		                BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN |
+		                BMC0_PAL | BMC0_VARCSYEN;
+		if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+			par->beamcon0 |= BMC0_HSYTRUE;
+		if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+			par->beamcon0 |= BMC0_VSYTRUE;
+		if (var->sync & FB_SYNC_COMP_HIGH_ACT)
+			par->beamcon0 |= BMC0_CSYTRUE;
+		htotal = par->htotal>>clk_shift;
+		vtotal = par->vtotal>>1;
+	} else {
+		DPRINTK("only broadcast modes possible for ocs\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Checking the DMA timing
+	 */
+
+	fconst = 16<<maxfmode<<clk_shift;
+
+	/*
+	 * smallest window start value without turn off other dma cycles
+	 * than sprite1-7, unless you change min_fstrt
+	 */
+
+
+	fsize = ((maxfmode+clk_shift <= 1) ? fconst : 64);
+	fstrt = downx(fconst, par->diwstrt_h-4) - fsize;
+	if (fstrt < min_fstrt) {
+		DPRINTK("fetch start too low\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * smallest window start value where smooth scrolling is possible
+	 */
+
+	fstrt = downx(fconst, par->diwstrt_h-fconst+(1<<clk_shift)-4) - fsize;
+	if (fstrt < min_fstrt)
+		par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
+
+	maxfetchstop = down16(par->htotal - 80);
+
+	fstrt = downx(fconst, par->diwstrt_h-4) - 64 - fconst;
+	fsize = upx(fconst, xres_n + modx(fconst, downx(1<<clk_shift, par->diwstrt_h-4)));
+	if (fstrt + fsize > maxfetchstop)
+		par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
+
+	fsize = upx(fconst, xres_n);
+	if (fstrt + fsize > maxfetchstop) {
+		DPRINTK("fetch stop too high\n");
+		return -EINVAL;
+	}
+
+	if (maxfmode + clk_shift <= 1) {
+		fsize = up64(xres_n + fconst - 1);
+		if (min_fstrt + fsize - 64 > maxfetchstop)
+			par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
+
+		fsize = up64(xres_n);
+		if (min_fstrt + fsize - 64 > maxfetchstop) {
+			DPRINTK("fetch size too high\n");
+			return -EINVAL;
+		}
+
+		fsize -= 64;
+	} else
+		fsize -= fconst;
+
+	/*
+	 * Check if there is enough time to update the bitplane pointers for ywrap
+	 */
+
+	if (par->htotal-fsize-64 < par->bpp*64)
+		par->vmode &= ~FB_VMODE_YWRAP;
+
+	/*
+	 * Bitplane calculations and check the Memory Requirements
+	 */
+
+	if (amifb_ilbm) {
+		par->next_plane = div8(upx(16<<maxfmode, par->vxres));
+		par->next_line = par->bpp*par->next_plane;
+		if (par->next_line * par->vyres > fb_info.fix.smem_len) {
+			DPRINTK("too few video mem\n");
+			return -EINVAL;
+		}
+	} else {
+		par->next_line = div8(upx(16<<maxfmode, par->vxres));
+		par->next_plane = par->vyres*par->next_line;
+		if (par->next_plane * par->bpp > fb_info.fix.smem_len) {
+			DPRINTK("too few video mem\n");
+			return -EINVAL;
+		}
+	}
+
+	/*
+	 * Hardware Register Values
+	 */
+
+	par->bplcon0 = BPC0_COLOR | bplpixmode[clk_shift];
+	if (!IS_OCS)
+		par->bplcon0 |= BPC0_ECSENA;
+	if (par->bpp == 8)
+		par->bplcon0 |= BPC0_BPU3;
+	else
+		par->bplcon0 |= par->bpp<<12;
+	if (var->nonstd == FB_NONSTD_HAM)
+		par->bplcon0 |= BPC0_HAM;
+	if (var->sync & FB_SYNC_EXT)
+		par->bplcon0 |= BPC0_ERSY;
+
+	if (IS_AGA)
+		par->fmode = bplfetchmode[maxfmode];
+
+	switch (par->vmode & FB_VMODE_MASK) {
+		case FB_VMODE_INTERLACED:
+			par->bplcon0 |= BPC0_LACE;
+			break;
+		case FB_VMODE_DOUBLE:
+			if (IS_AGA)
+				par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2;
+			break;
+	}
+
+	if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) {
+		par->xoffset = var->xoffset;
+		par->yoffset = var->yoffset;
+		if (par->vmode & FB_VMODE_YWRAP) {
+			if (par->xoffset || par->yoffset < 0 || par->yoffset >= par->vyres)
+				par->xoffset = par->yoffset = 0;
+		} else {
+			if (par->xoffset < 0 || par->xoffset > upx(16<<maxfmode, par->vxres-par->xres) ||
+			    par->yoffset < 0 || par->yoffset > par->vyres-par->yres)
+				par->xoffset = par->yoffset = 0;
+		}
+	} else
+		par->xoffset = par->yoffset = 0;
+
+	par->crsr.crsr_x = par->crsr.crsr_y = 0;
+	par->crsr.spot_x = par->crsr.spot_y = 0;
+	par->crsr.height = par->crsr.width = 0;
+
+#if 0	/* fbmon not done.  uncomment for 2.5.x -brad */
+	if (!fbmon_valid_timings(pixclock[clk_shift], htotal, vtotal,
+				 &fb_info)) {
+		DPRINTK("mode doesn't fit for monitor\n");
+		return -EINVAL;
+	}
+#endif
+
+	return 0;
+}
+
+	/*
+	 * Fill the `var' structure based on the values in `par' and maybe
+	 * other values read out of the hardware.
+	 */
+
+static int ami_encode_var(struct fb_var_screeninfo *var,
+                          struct amifb_par *par)
+{
+	u_short clk_shift, line_shift;
+
+	memset(var, 0, sizeof(struct fb_var_screeninfo));
+
+	clk_shift = par->clk_shift;
+	line_shift = par->line_shift;
+
+	var->xres = par->xres;
+	var->yres = par->yres;
+	var->xres_virtual = par->vxres;
+	var->yres_virtual = par->vyres;
+	var->xoffset = par->xoffset;
+	var->yoffset = par->yoffset;
+
+	var->bits_per_pixel = par->bpp;
+	var->grayscale = 0;
+
+	var->red.offset = 0;
+	var->red.msb_right = 0;
+	var->red.length = par->bpp;
+	if (par->bplcon0 & BPC0_HAM)
+	    var->red.length -= 2;
+	var->blue = var->green = var->red;
+	var->transp.offset = 0;
+	var->transp.length = 0;
+	var->transp.msb_right = 0;
+
+	if (par->bplcon0 & BPC0_HAM)
+		var->nonstd = FB_NONSTD_HAM;
+	else
+		var->nonstd = 0;
+	var->activate = 0;
+
+	var->height = -1;
+	var->width = -1;
+
+	var->pixclock = pixclock[clk_shift];
+
+	if (IS_AGA && par->fmode & FMODE_BSCAN2)
+		var->vmode = FB_VMODE_DOUBLE;
+	else if (par->bplcon0 & BPC0_LACE)
+		var->vmode = FB_VMODE_INTERLACED;
+	else
+		var->vmode = FB_VMODE_NONINTERLACED;
+
+	if (!IS_OCS && par->beamcon0 & BMC0_VARBEAMEN) {
+		var->hsync_len = (par->hsstop-par->hsstrt)>>clk_shift;
+		var->right_margin = par->hsstrt>>clk_shift;
+		var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len;
+		var->vsync_len = (par->vsstop-par->vsstrt)>>line_shift;
+		var->lower_margin = par->vsstrt>>line_shift;
+		var->upper_margin = (par->vtotal>>line_shift) - var->yres - var->lower_margin - var->vsync_len;
+		var->sync = 0;
+		if (par->beamcon0 & BMC0_HSYTRUE)
+			var->sync |= FB_SYNC_HOR_HIGH_ACT;
+		if (par->beamcon0 & BMC0_VSYTRUE)
+			var->sync |= FB_SYNC_VERT_HIGH_ACT;
+		if (par->beamcon0 & BMC0_CSYTRUE)
+			var->sync |= FB_SYNC_COMP_HIGH_ACT;
+	} else {
+		var->sync = FB_SYNC_BROADCAST;
+		var->hsync_len = (152>>clk_shift) + mod4(par->diwstop_h);
+		var->right_margin = ((par->htotal - down4(par->diwstop_h))>>clk_shift) + var->hsync_len;
+		var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len;
+		var->vsync_len = 4>>line_shift;
+		var->lower_margin = ((par->vtotal - par->diwstop_v)>>line_shift) + var->vsync_len;
+		var->upper_margin = (((par->vtotal - 2)>>line_shift) + 1) - var->yres -
+		                    var->lower_margin - var->vsync_len;
+	}
+
+	if (par->bplcon0 & BPC0_ERSY)
+		var->sync |= FB_SYNC_EXT;
+	if (par->vmode & FB_VMODE_YWRAP)
+		var->vmode |= FB_VMODE_YWRAP;
+
+	return 0;
+}
+
+
+	/*
+	 * Pan or Wrap the Display
+	 *
+	 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
+	 * in `var'.
+	 */
+
+static void ami_pan_var(struct fb_var_screeninfo *var)
+{
+	struct amifb_par *par = &currentpar;
+
+	par->xoffset = var->xoffset;
+	par->yoffset = var->yoffset;
+	if (var->vmode & FB_VMODE_YWRAP)
+		par->vmode |= FB_VMODE_YWRAP;
+	else
+		par->vmode &= ~FB_VMODE_YWRAP;
+
+	do_vmode_pan = 0;
+	ami_update_par();
+	do_vmode_pan = 1;
+}
+
+	/*
+	 * Update hardware
+	 */
+
+static int ami_update_par(void)
+{
+	struct amifb_par *par = &currentpar;
+	short clk_shift, vshift, fstrt, fsize, fstop, fconst,  shift, move, mod;
+
+	clk_shift = par->clk_shift;
+
+	if (!(par->vmode & FB_VMODE_SMOOTH_XPAN))
+		par->xoffset = upx(16<<maxfmode, par->xoffset);
+
+	fconst = 16<<maxfmode<<clk_shift;
+	vshift = modx(16<<maxfmode, par->xoffset);
+	fstrt = par->diwstrt_h - (vshift<<clk_shift) - 4;
+	fsize = (par->xres+vshift)<<clk_shift;
+	shift = modx(fconst, fstrt);
+	move = downx(2<<maxfmode, div8(par->xoffset));
+	if (maxfmode + clk_shift > 1) {
+		fstrt = downx(fconst, fstrt) - 64;
+		fsize = upx(fconst, fsize);
+		fstop = fstrt + fsize - fconst;
+	} else {
+		mod = fstrt = downx(fconst, fstrt) - fconst;
+		fstop = fstrt + upx(fconst, fsize) - 64;
+		fsize = up64(fsize);
+		fstrt = fstop - fsize + 64;
+		if (fstrt < min_fstrt) {
+			fstop += min_fstrt - fstrt;
+			fstrt = min_fstrt;
+		}
+		move = move - div8((mod-fstrt)>>clk_shift);
+	}
+	mod = par->next_line - div8(fsize>>clk_shift);
+	par->ddfstrt = fstrt;
+	par->ddfstop = fstop;
+	par->bplcon1 = hscroll2hw(shift);
+	par->bpl2mod = mod;
+	if (par->bplcon0 & BPC0_LACE)
+		par->bpl2mod += par->next_line;
+	if (IS_AGA && (par->fmode & FMODE_BSCAN2))
+		par->bpl1mod = -div8(fsize>>clk_shift);
+	else
+		par->bpl1mod = par->bpl2mod;
+
+	if (par->yoffset) {
+		par->bplpt0 = fb_info.fix.smem_start + par->next_line*par->yoffset + move;
+		if (par->vmode & FB_VMODE_YWRAP) {
+			if (par->yoffset > par->vyres-par->yres) {
+				par->bplpt0wrap = fb_info.fix.smem_start + move;
+				if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v+par->vyres-par->yoffset))
+					par->bplpt0wrap += par->next_line;
+			}
+		}
+	} else
+		par->bplpt0 = fb_info.fix.smem_start + move;
+
+	if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v))
+		par->bplpt0 += par->next_line;
+
+	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 amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                           u_int transp, struct fb_info *info)
+{
+	if (IS_AGA) {
+		if (regno > 255)
+			return 1;
+	} else if (currentpar.bplcon0 & BPC0_SHRES) {
+		if (regno > 3)
+			return 1;
+	} else {
+		if (regno > 31)
+			return 1;
+	}
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+	if (!regno) {
+		red0 = red;
+		green0 = green;
+		blue0 = blue;
+	}
+
+	/*
+	 * Update the corresponding Hardware Color Register, unless it's Color
+	 * Register 0 and the screen is blanked.
+	 *
+	 * VBlank is switched off to protect bplcon3 or ecs_palette[] from
+	 * being changed by ami_do_blank() during the VBlank.
+	 */
+
+	if (regno || !is_blanked) {
+#if defined(CONFIG_FB_AMIGA_AGA)
+		if (IS_AGA) {
+			u_short bplcon3 = currentpar.bplcon3;
+			VBlankOff();
+			custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000);
+			custom.color[regno&31] = rgb2hw8_high(red, green, blue);
+			custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000) | BPC3_LOCT;
+			custom.color[regno&31] = rgb2hw8_low(red, green, blue);
+			custom.bplcon3 = bplcon3;
+			VBlankOn();
+		} else
+#endif
+#if defined(CONFIG_FB_AMIGA_ECS)
+		if (currentpar.bplcon0 & BPC0_SHRES) {
+			u_short color, mask;
+			int i;
+
+			mask = 0x3333;
+			color = rgb2hw2(red, green, blue);
+			VBlankOff();
+			for (i = regno+12; i >= (int)regno; i -= 4)
+				custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
+			mask <<=2; color >>= 2;
+			regno = down16(regno)+mul4(mod4(regno));
+			for (i = regno+3; i >= (int)regno; i--)
+				custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
+			VBlankOn();
+		} else
+#endif
+			custom.color[regno] = rgb2hw4(red, green, blue);
+	}
+	return 0;
+}
+
+static void ami_update_display(void)
+{
+	struct amifb_par *par = &currentpar;
+
+	custom.bplcon1 = par->bplcon1;
+	custom.bpl1mod = par->bpl1mod;
+	custom.bpl2mod = par->bpl2mod;
+	custom.ddfstrt = ddfstrt2hw(par->ddfstrt);
+	custom.ddfstop = ddfstop2hw(par->ddfstop);
+}
+
+	/*
+	 * Change the video mode (called by VBlank interrupt)
+	 */
+
+static void ami_init_display(void)
+{
+	struct amifb_par *par = &currentpar;
+	int i;
+
+	custom.bplcon0 = par->bplcon0 & ~BPC0_LACE;
+	custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2;
+	if (!IS_OCS) {
+		custom.bplcon3 = par->bplcon3;
+		if (IS_AGA)
+			custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4;
+		if (par->beamcon0 & BMC0_VARBEAMEN) {
+			custom.htotal = htotal2hw(par->htotal);
+			custom.hbstrt = hbstrt2hw(par->hbstrt);
+			custom.hbstop = hbstop2hw(par->hbstop);
+			custom.hsstrt = hsstrt2hw(par->hsstrt);
+			custom.hsstop = hsstop2hw(par->hsstop);
+			custom.hcenter = hcenter2hw(par->hcenter);
+			custom.vtotal = vtotal2hw(par->vtotal);
+			custom.vbstrt = vbstrt2hw(par->vbstrt);
+			custom.vbstop = vbstop2hw(par->vbstop);
+			custom.vsstrt = vsstrt2hw(par->vsstrt);
+			custom.vsstop = vsstop2hw(par->vsstop);
+		}
+	}
+	if (!IS_OCS || par->hsstop)
+		custom.beamcon0 = par->beamcon0;
+	if (IS_AGA)
+		custom.fmode = par->fmode;
+
+	/*
+	 * The minimum period for audio depends on htotal
+	 */
+
+	amiga_audio_min_period = div16(par->htotal);
+
+	is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0;
+#if 1
+	if (is_lace) {
+		i = custom.vposr >> 15;
+	} else {
+		custom.vposw = custom.vposr | 0x8000;
+		i = 1;
+	}
+#else
+	i = 1;
+	custom.vposw = custom.vposr | 0x8000;
+#endif
+	custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][i]);
+}
+
+	/*
+	 * (Un)Blank the screen (called by VBlank interrupt)
+	 */
+
+static void ami_do_blank(void)
+{
+	struct amifb_par *par = &currentpar;
+#if defined(CONFIG_FB_AMIGA_AGA)
+	u_short bplcon3 = par->bplcon3;
+#endif
+	u_char red, green, blue;
+
+	if (do_blank > 0) {
+		custom.dmacon = DMAF_RASTER | DMAF_SPRITE;
+		red = green = blue = 0;
+		if (!IS_OCS && do_blank > 1) {
+			switch (do_blank) {
+				case FB_BLANK_VSYNC_SUSPEND:
+					custom.hsstrt = hsstrt2hw(par->hsstrt);
+					custom.hsstop = hsstop2hw(par->hsstop);
+					custom.vsstrt = vsstrt2hw(par->vtotal+4);
+					custom.vsstop = vsstop2hw(par->vtotal+4);
+					break;
+				case FB_BLANK_HSYNC_SUSPEND:
+					custom.hsstrt = hsstrt2hw(par->htotal+16);
+					custom.hsstop = hsstop2hw(par->htotal+16);
+					custom.vsstrt = vsstrt2hw(par->vsstrt);
+					custom.vsstop = vsstrt2hw(par->vsstop);
+					break;
+				case FB_BLANK_POWERDOWN:
+					custom.hsstrt = hsstrt2hw(par->htotal+16);
+					custom.hsstop = hsstop2hw(par->htotal+16);
+					custom.vsstrt = vsstrt2hw(par->vtotal+4);
+					custom.vsstop = vsstop2hw(par->vtotal+4);
+					break;
+			}
+			if (!(par->beamcon0 & BMC0_VARBEAMEN)) {
+				custom.htotal = htotal2hw(par->htotal);
+				custom.vtotal = vtotal2hw(par->vtotal);
+				custom.beamcon0 = BMC0_HARDDIS | BMC0_VARBEAMEN |
+				                  BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARCSYEN;
+			}
+		}
+	} else {
+		custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE;
+		red = red0;
+		green = green0;
+		blue = blue0;
+		if (!IS_OCS) {
+			custom.hsstrt = hsstrt2hw(par->hsstrt);
+			custom.hsstop = hsstop2hw(par->hsstop);
+			custom.vsstrt = vsstrt2hw(par->vsstrt);
+			custom.vsstop = vsstop2hw(par->vsstop);
+			custom.beamcon0 = par->beamcon0;
+		}
+	}
+#if defined(CONFIG_FB_AMIGA_AGA)
+	if (IS_AGA) {
+		custom.bplcon3 = bplcon3;
+		custom.color[0] = rgb2hw8_high(red, green, blue);
+		custom.bplcon3 = bplcon3 | BPC3_LOCT;
+		custom.color[0] = rgb2hw8_low(red, green, blue);
+		custom.bplcon3 = bplcon3;
+	} else
+#endif
+#if defined(CONFIG_FB_AMIGA_ECS)
+	if (par->bplcon0 & BPC0_SHRES) {
+		u_short color, mask;
+		int i;
+
+		mask = 0x3333;
+		color = rgb2hw2(red, green, blue);
+		for (i = 12; i >= 0; i -= 4)
+			custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
+		mask <<=2; color >>= 2;
+		for (i = 3; i >= 0; i--)
+			custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
+	} else
+#endif
+		custom.color[0] = rgb2hw4(red, green, blue);
+	is_blanked = do_blank > 0 ? do_blank : 0;
+}
+
+static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix)
+{
+	struct amifb_par *par = &currentpar;
+
+	fix->crsr_width = fix->crsr_xsize = par->crsr.width;
+	fix->crsr_height = fix->crsr_ysize = par->crsr.height;
+	fix->crsr_color1 = 17;
+	fix->crsr_color2 = 18;
+	return 0;
+}
+
+static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data)
+{
+	struct amifb_par *par = &currentpar;
+	register u_short *lspr, *sspr;
+#ifdef __mc68000__
+	register u_long datawords asm ("d2");
+#else
+	register u_long datawords;
+#endif
+	register short delta;
+	register u_char color;
+	short height, width, bits, words;
+	int size, alloc;
+
+	size = par->crsr.height*par->crsr.width;
+	alloc = var->height*var->width;
+	var->height = par->crsr.height;
+	var->width = par->crsr.width;
+	var->xspot = par->crsr.spot_x;
+	var->yspot = par->crsr.spot_y;
+	if (size > var->height*var->width)
+		return -ENAMETOOLONG;
+	if (!access_ok(VERIFY_WRITE, (void *)data, size))
+		return -EFAULT;
+	delta = 1<<par->crsr.fmode;
+	lspr = lofsprite + (delta<<1);
+	if (par->bplcon0 & BPC0_LACE)
+		sspr = shfsprite + (delta<<1);
+	else
+		sspr = 0;
+	for (height = (short)var->height-1; height >= 0; height--) {
+		bits = 0; words = delta; datawords = 0;
+		for (width = (short)var->width-1; width >= 0; width--) {
+			if (bits == 0) {
+				bits = 16; --words;
+#ifdef __mc68000__
+				asm volatile ("movew %1@(%3:w:2),%0 ; swap %0 ; movew %1@+,%0"
+					: "=d" (datawords), "=a" (lspr) : "1" (lspr), "d" (delta));
+#else
+				datawords = (*(lspr+delta) << 16) | (*lspr++);
+#endif
+			}
+			--bits;
+#ifdef __mc68000__
+			asm volatile (
+				"clrb %0 ; swap %1 ; lslw #1,%1 ; roxlb #1,%0 ; "
+				"swap %1 ; lslw #1,%1 ; roxlb #1,%0"
+				: "=d" (color), "=d" (datawords) : "1" (datawords));
+#else
+			color = (((datawords >> 30) & 2)
+				 | ((datawords >> 15) & 1));
+			datawords <<= 1;
+#endif
+			put_user(color, data++);
+		}
+		if (bits > 0) {
+			--words; ++lspr;
+		}
+		while (--words >= 0)
+			++lspr;
+#ifdef __mc68000__
+		asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"
+			: "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta));
+#else
+		lspr += delta;
+		if (sspr) {
+			u_short *tmp = lspr;
+			lspr = sspr;
+			sspr = tmp;
+		}
+#endif
+	}
+	return 0;
+}
+
+static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data)
+{
+	struct amifb_par *par = &currentpar;
+	register u_short *lspr, *sspr;
+#ifdef __mc68000__
+	register u_long datawords asm ("d2");
+#else
+	register u_long datawords;
+#endif
+	register short delta;
+	u_short fmode;
+	short height, width, bits, words;
+
+	if (!var->width)
+		return -EINVAL;
+	else if (var->width <= 16)
+		fmode = TAG_FMODE_1;
+	else if (var->width <= 32)
+		fmode = TAG_FMODE_2;
+	else if (var->width <= 64)
+		fmode = TAG_FMODE_4;
+	else
+		return -EINVAL;
+	if (fmode > maxfmode)
+		return -EINVAL;
+	if (!var->height)
+		return -EINVAL;
+	if (!access_ok(VERIFY_READ, (void *)data, var->width*var->height))
+		return -EFAULT;
+	delta = 1<<fmode;
+	lofsprite = shfsprite = (u_short *)spritememory;
+	lspr = lofsprite + (delta<<1);
+	if (par->bplcon0 & BPC0_LACE) {
+		if (((var->height+4)<<fmode<<2) > SPRITEMEMSIZE)
+			return -EINVAL;
+		memset(lspr, 0, (var->height+4)<<fmode<<2);
+		shfsprite += ((var->height+5)&-2)<<fmode;
+		sspr = shfsprite + (delta<<1);
+	} else {
+		if (((var->height+2)<<fmode<<2) > SPRITEMEMSIZE)
+			return -EINVAL;
+		memset(lspr, 0, (var->height+2)<<fmode<<2);
+		sspr = 0;
+	}
+	for (height = (short)var->height-1; height >= 0; height--) {
+		bits = 16; words = delta; datawords = 0;
+		for (width = (short)var->width-1; width >= 0; width--) {
+			unsigned long tdata = 0;
+			get_user(tdata, (char *)data);
+			data++;
+#ifdef __mc68000__
+			asm volatile (
+				"lsrb #1,%2 ; roxlw #1,%0 ; swap %0 ; "
+				"lsrb #1,%2 ; roxlw #1,%0 ; swap %0"
+				: "=d" (datawords)
+				: "0" (datawords), "d" (tdata));
+#else
+			datawords = ((datawords << 1) & 0xfffefffe);
+			datawords |= tdata & 1;
+			datawords |= (tdata & 2) << (16-1);
+#endif
+			if (--bits == 0) {
+				bits = 16; --words;
+#ifdef __mc68000__
+				asm volatile ("swap %2 ; movew %2,%0@(%3:w:2) ; swap %2 ; movew %2,%0@+"
+					: "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta));
+#else
+				*(lspr+delta) = (u_short) (datawords >> 16);
+				*lspr++ = (u_short) (datawords & 0xffff);
+#endif
+			}
+		}
+		if (bits < 16) {
+			--words;
+#ifdef __mc68000__
+			asm volatile (
+				"swap %2 ; lslw %4,%2 ; movew %2,%0@(%3:w:2) ; "
+				"swap %2 ; lslw %4,%2 ; movew %2,%0@+"
+				: "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta), "d" (bits));
+#else
+			*(lspr+delta) = (u_short) (datawords >> (16+bits));
+			*lspr++ = (u_short) ((datawords & 0x0000ffff) >> bits);
+#endif
+		}
+		while (--words >= 0) {
+#ifdef __mc68000__
+			asm volatile ("moveql #0,%%d0 ; movew %%d0,%0@(%2:w:2) ; movew %%d0,%0@+"
+				: "=a" (lspr) : "0" (lspr), "d" (delta) : "d0");
+#else
+			*(lspr+delta) = 0;
+			*lspr++ = 0;
+#endif
+		}
+#ifdef __mc68000__
+		asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"
+			: "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta));
+#else
+		lspr += delta;
+		if (sspr) {
+			u_short *tmp = lspr;
+			lspr = sspr;
+			sspr = tmp;
+		}
+#endif
+	}
+	par->crsr.height = var->height;
+	par->crsr.width = var->width;
+	par->crsr.spot_x = var->xspot;
+	par->crsr.spot_y = var->yspot;
+	par->crsr.fmode = fmode;
+	if (IS_AGA) {
+		par->fmode &= ~(FMODE_SPAGEM | FMODE_SPR32);
+		par->fmode |= sprfetchmode[fmode];
+		custom.fmode = par->fmode;
+	}
+	return 0;
+}
+
+static int ami_get_cursorstate(struct fb_cursorstate *state)
+{
+	struct amifb_par *par = &currentpar;
+
+	state->xoffset = par->crsr.crsr_x;
+	state->yoffset = par->crsr.crsr_y;
+	state->mode = cursormode;
+	return 0;
+}
+
+static int ami_set_cursorstate(struct fb_cursorstate *state)
+{
+	struct amifb_par *par = &currentpar;
+
+	par->crsr.crsr_x = state->xoffset;
+	par->crsr.crsr_y = state->yoffset;
+	if ((cursormode = state->mode) == FB_CURSOR_OFF)
+		cursorstate = -1;
+	do_cursor = 1;
+	return 0;
+}
+
+static void ami_set_sprite(void)
+{
+	struct amifb_par *par = &currentpar;
+	copins *copl, *cops;
+	u_short hs, vs, ve;
+	u_long pl, ps, pt;
+	short mx, my;
+
+	cops = copdisplay.list[currentcop][0];
+	copl = copdisplay.list[currentcop][1];
+	ps = pl = ZTWO_PADDR(dummysprite);
+	mx = par->crsr.crsr_x-par->crsr.spot_x;
+	my = par->crsr.crsr_y-par->crsr.spot_y;
+	if (!(par->vmode & FB_VMODE_YWRAP)) {
+		mx -= par->xoffset;
+		my -= par->yoffset;
+	}
+	if (!is_blanked && cursorstate > 0 && par->crsr.height > 0 &&
+	    mx > -(short)par->crsr.width && mx < par->xres &&
+	    my > -(short)par->crsr.height && my < par->yres) {
+		pl = ZTWO_PADDR(lofsprite);
+		hs = par->diwstrt_h + (mx<<par->clk_shift) - 4;
+		vs = par->diwstrt_v + (my<<par->line_shift);
+		ve = vs + (par->crsr.height<<par->line_shift);
+		if (par->bplcon0 & BPC0_LACE) {
+			ps = ZTWO_PADDR(shfsprite);
+			lofsprite[0] = spr2hw_pos(vs, hs);
+			shfsprite[0] = spr2hw_pos(vs+1, hs);
+			if (mod2(vs)) {
+				lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve);
+				shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve+1);
+				pt = pl; pl = ps; ps = pt;
+			} else {
+				lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve+1);
+				shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve);
+			}
+		} else {
+			lofsprite[0] = spr2hw_pos(vs, hs) | (IS_AGA && (par->fmode & FMODE_BSCAN2) ? 0x80 : 0);
+			lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve);
+		}
+	}
+	copl[cop_spr0ptrh].w[1] = highw(pl);
+	copl[cop_spr0ptrl].w[1] = loww(pl);
+	if (par->bplcon0 & BPC0_LACE) {
+		cops[cop_spr0ptrh].w[1] = highw(ps);
+		cops[cop_spr0ptrl].w[1] = loww(ps);
+	}
+}
+
+
+	/*
+	 * Initialise the Copper Initialisation List
+	 */
+
+static void __init ami_init_copper(void)
+{
+	copins *cop = copdisplay.init;
+	u_long p;
+	int i;
+
+	if (!IS_OCS) {
+		(cop++)->l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0);
+		(cop++)->l = CMOVE(0x0181, diwstrt);
+		(cop++)->l = CMOVE(0x0281, diwstop);
+		(cop++)->l = CMOVE(0x0000, diwhigh);
+	} else
+		(cop++)->l = CMOVE(BPC0_COLOR, bplcon0);
+	p = ZTWO_PADDR(dummysprite);
+	for (i = 0; i < 8; i++) {
+		(cop++)->l = CMOVE(0, spr[i].pos);
+		(cop++)->l = CMOVE(highw(p), sprpt[i]);
+		(cop++)->l = CMOVE2(loww(p), sprpt[i]);
+	}
+
+	(cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq);
+	copdisplay.wait = cop;
+	(cop++)->l = CEND;
+	(cop++)->l = CMOVE(0, copjmp2);
+	cop->l = CEND;
+
+	custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init);
+	custom.copjmp1 = 0;
+}
+
+static void ami_reinit_copper(void)
+{
+	struct amifb_par *par = &currentpar;
+
+	copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0;
+	copdisplay.wait->l = CWAIT(32, par->diwstrt_v-4);
+}
+
+	/*
+	 * Build the Copper List
+	 */
+
+static void ami_build_copper(void)
+{
+	struct amifb_par *par = &currentpar;
+	copins *copl, *cops;
+	u_long p;
+
+	currentcop = 1 - currentcop;
+
+	copl = copdisplay.list[currentcop][1];
+
+	(copl++)->l = CWAIT(0, 10);
+	(copl++)->l = CMOVE(par->bplcon0, bplcon0);
+	(copl++)->l = CMOVE(0, sprpt[0]);
+	(copl++)->l = CMOVE2(0, sprpt[0]);
+
+	if (par->bplcon0 & BPC0_LACE) {
+		cops = copdisplay.list[currentcop][0];
+
+		(cops++)->l = CWAIT(0, 10);
+		(cops++)->l = CMOVE(par->bplcon0, bplcon0);
+		(cops++)->l = CMOVE(0, sprpt[0]);
+		(cops++)->l = CMOVE2(0, sprpt[0]);
+
+		(copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v+1), diwstrt);
+		(copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v+1), diwstop);
+		(cops++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt);
+		(cops++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop);
+		if (!IS_OCS) {
+			(copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v+1,
+			                    par->diwstop_h, par->diwstop_v+1), diwhigh);
+			(cops++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v,
+			                    par->diwstop_h, par->diwstop_v), diwhigh);
+#if 0
+			if (par->beamcon0 & BMC0_VARBEAMEN) {
+				(copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
+				(copl++)->l = CMOVE(vbstrt2hw(par->vbstrt+1), vbstrt);
+				(copl++)->l = CMOVE(vbstop2hw(par->vbstop+1), vbstop);
+				(cops++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
+				(cops++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt);
+				(cops++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop);
+			}
+#endif
+		}
+		p = ZTWO_PADDR(copdisplay.list[currentcop][0]);
+		(copl++)->l = CMOVE(highw(p), cop2lc);
+		(copl++)->l = CMOVE2(loww(p), cop2lc);
+		p = ZTWO_PADDR(copdisplay.list[currentcop][1]);
+		(cops++)->l = CMOVE(highw(p), cop2lc);
+		(cops++)->l = CMOVE2(loww(p), cop2lc);
+		copdisplay.rebuild[0] = cops;
+	} else {
+		(copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt);
+		(copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop);
+		if (!IS_OCS) {
+			(copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v,
+			                    par->diwstop_h, par->diwstop_v), diwhigh);
+#if 0
+			if (par->beamcon0 & BMC0_VARBEAMEN) {
+				(copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
+				(copl++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt);
+				(copl++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop);
+			}
+#endif
+		}
+	}
+	copdisplay.rebuild[1] = copl;
+
+	ami_update_par();
+	ami_rebuild_copper();
+}
+
+	/*
+	 * Rebuild the Copper List
+	 *
+	 * We only change the things that are not static
+	 */
+
+static void ami_rebuild_copper(void)
+{
+	struct amifb_par *par = &currentpar;
+	copins *copl, *cops;
+	u_short line, h_end1, h_end2;
+	short i;
+	u_long p;
+
+	if (IS_AGA && maxfmode + par->clk_shift == 0)
+		h_end1 = par->diwstrt_h-64;
+	else
+		h_end1 = par->htotal-32;
+	h_end2 = par->ddfstop+64;
+
+	ami_set_sprite();
+
+	copl = copdisplay.rebuild[1];
+	p = par->bplpt0;
+	if (par->vmode & FB_VMODE_YWRAP) {
+		if ((par->vyres-par->yoffset) != 1 || !mod2(par->diwstrt_v)) {
+			if (par->yoffset > par->vyres-par->yres) {
+				for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
+					(copl++)->l = CMOVE(highw(p), bplpt[i]);
+					(copl++)->l = CMOVE2(loww(p), bplpt[i]);
+				}
+				line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 1;
+				while (line >= 512) {
+					(copl++)->l = CWAIT(h_end1, 510);
+					line -= 512;
+				}
+				if (line >= 510 && IS_AGA && maxfmode + par->clk_shift == 0)
+					(copl++)->l = CWAIT(h_end1, line);
+				else
+					(copl++)->l = CWAIT(h_end2, line);
+				p = par->bplpt0wrap;
+			}
+		} else p = par->bplpt0wrap;
+	}
+	for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
+		(copl++)->l = CMOVE(highw(p), bplpt[i]);
+		(copl++)->l = CMOVE2(loww(p), bplpt[i]);
+	}
+	copl->l = CEND;
+
+	if (par->bplcon0 & BPC0_LACE) {
+		cops = copdisplay.rebuild[0];
+		p = par->bplpt0;
+		if (mod2(par->diwstrt_v))
+			p -= par->next_line;
+		else
+			p += par->next_line;
+		if (par->vmode & FB_VMODE_YWRAP) {
+			if ((par->vyres-par->yoffset) != 1 || mod2(par->diwstrt_v)) {
+				if (par->yoffset > par->vyres-par->yres+1) {
+					for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
+						(cops++)->l = CMOVE(highw(p), bplpt[i]);
+						(cops++)->l = CMOVE2(loww(p), bplpt[i]);
+					}
+					line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 2;
+					while (line >= 512) {
+						(cops++)->l = CWAIT(h_end1, 510);
+						line -= 512;
+					}
+					if (line > 510 && IS_AGA && maxfmode + par->clk_shift == 0)
+						(cops++)->l = CWAIT(h_end1, line);
+					else
+						(cops++)->l = CWAIT(h_end2, line);
+					p = par->bplpt0wrap;
+					if (mod2(par->diwstrt_v+par->vyres-par->yoffset))
+						p -= par->next_line;
+					else
+						p += par->next_line;
+				}
+			} else p = par->bplpt0wrap - par->next_line;
+		}
+		for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
+			(cops++)->l = CMOVE(highw(p), bplpt[i]);
+			(cops++)->l = CMOVE2(loww(p), bplpt[i]);
+		}
+		cops->l = CEND;
+	}
+}
+
+
+module_init(amifb_init);
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+
+void cleanup_module(void)
+{
+	unregister_framebuffer(&fb_info);
+	amifb_deinit();
+	amifb_video_off();
+}
+#endif /* MODULE */
diff --git a/drivers/video/asiliantfb.c b/drivers/video/asiliantfb.c
new file mode 100644
index 0000000..f4729f4
--- /dev/null
+++ b/drivers/video/asiliantfb.c
@@ -0,0 +1,617 @@
+/*
+ * drivers/video/asiliantfb.c
+ *  frame buffer driver for Asiliant 69000 chip
+ *  Copyright (C) 2001-2003 Saito.K & Jeanne
+ *
+ *  from driver/video/chipsfb.c and,
+ *
+ *  drivers/video/asiliantfb.c -- frame buffer device for
+ *  Asiliant 69030 chip (formerly Intel, formerly Chips & Technologies)
+ *  Author: apc@agelectronics.co.uk
+ *  Copyright (C) 2000 AG Electronics
+ *  Note: the data sheets don't seem to be available from Asiliant.
+ *  They are available by searching developer.intel.com, but are not otherwise
+ *  linked to.
+ *
+ *  This driver should be portable with minimal effort to the 69000 display
+ *  chip, and to the twin-display mode of the 69030.
+ *  Contains code from Thomas Hhenleitner <th@visuelle-maschinen.de> (thanks)
+ *
+ *  Derived from the CT65550 driver chipsfb.c:
+ *  Copyright (C) 1998 Paul Mackerras
+ *  ...which was derived from the Powermac "chips" driver:
+ *  Copyright (C) 1997 Fabio Riccardi.
+ *  And from the frame buffer device for Open Firmware-initialized devices:
+ *  Copyright (C) 1997 Geert Uytterhoeven.
+ *
+ *  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 <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+/* Built in clock of the 69030 */
+static const unsigned Fref = 14318180;
+
+#define mmio_base (p->screen_base + 0x400000)
+
+#define mm_write_ind(num, val, ap, dp)	do { \
+	writeb((num), mmio_base + (ap)); writeb((val), mmio_base + (dp)); \
+} while (0)
+
+static void mm_write_xr(struct fb_info *p, u8 reg, u8 data)
+{
+	mm_write_ind(reg, data, 0x7ac, 0x7ad);
+}
+#define write_xr(num, val)	mm_write_xr(p, num, val)
+
+static void mm_write_fr(struct fb_info *p, u8 reg, u8 data)
+{
+	mm_write_ind(reg, data, 0x7a0, 0x7a1);
+}
+#define write_fr(num, val)	mm_write_fr(p, num, val)
+
+static void mm_write_cr(struct fb_info *p, u8 reg, u8 data)
+{
+	mm_write_ind(reg, data, 0x7a8, 0x7a9);
+}
+#define write_cr(num, val)	mm_write_cr(p, num, val)
+
+static void mm_write_gr(struct fb_info *p, u8 reg, u8 data)
+{
+	mm_write_ind(reg, data, 0x79c, 0x79d);
+}
+#define write_gr(num, val)	mm_write_gr(p, num, val)
+
+static void mm_write_sr(struct fb_info *p, u8 reg, u8 data)
+{
+	mm_write_ind(reg, data, 0x788, 0x789);
+}
+#define write_sr(num, val)	mm_write_sr(p, num, val)
+
+static void mm_write_ar(struct fb_info *p, u8 reg, u8 data)
+{
+	readb(mmio_base + 0x7b4);
+	mm_write_ind(reg, data, 0x780, 0x780);
+}
+#define write_ar(num, val)	mm_write_ar(p, num, val)
+
+static int asiliantfb_pci_init(struct pci_dev *dp, const struct pci_device_id *);
+static int asiliantfb_check_var(struct fb_var_screeninfo *var,
+				struct fb_info *info);
+static int asiliantfb_set_par(struct fb_info *info);
+static int asiliantfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+				u_int transp, struct fb_info *info);
+
+static struct fb_ops asiliantfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= asiliantfb_check_var,
+	.fb_set_par	= asiliantfb_set_par,
+	.fb_setcolreg	= asiliantfb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+/* Calculate the ratios for the dot clocks without using a single long long
+ * value */
+static void asiliant_calc_dclk2(u32 *ppixclock, u8 *dclk2_m, u8 *dclk2_n, u8 *dclk2_div)
+{
+	unsigned pixclock = *ppixclock;
+	unsigned Ftarget = 1000000 * (1000000 / pixclock);
+	unsigned n;
+	unsigned best_error = 0xffffffff;
+	unsigned best_m = 0xffffffff,
+	         best_n = 0xffffffff;
+	unsigned ratio;
+	unsigned remainder;
+	unsigned char divisor = 0;
+
+	/* Calculate the frequency required. This is hard enough. */
+	ratio = 1000000 / pixclock;
+	remainder = 1000000 % pixclock;
+	Ftarget = 1000000 * ratio + (1000000 * remainder) / pixclock;
+
+	while (Ftarget < 100000000) {
+		divisor += 0x10;
+		Ftarget <<= 1;
+	}
+
+	ratio = Ftarget / Fref;
+	remainder = Ftarget % Fref;
+
+	/* This expresses the constraint that 150kHz <= Fref/n <= 5Mhz,
+	 * together with 3 <= n <= 257. */
+	for (n = 3; n <= 257; n++) {
+		unsigned m = n * ratio + (n * remainder) / Fref;
+
+		/* 3 <= m <= 257 */
+		if (m >= 3 && m <= 257) {
+			unsigned new_error = ((Ftarget * n) - (Fref * m)) >= 0 ?
+					       ((Ftarget * n) - (Fref * m)) : ((Fref * m) - (Ftarget * n));
+			if (new_error < best_error) {
+				best_n = n;
+				best_m = m;
+				best_error = new_error;
+			}
+		}
+		/* But if VLD = 4, then 4m <= 1028 */
+		else if (m <= 1028) {
+			/* remember there are still only 8-bits of precision in m, so
+			 * avoid over-optimistic error calculations */
+			unsigned new_error = ((Ftarget * n) - (Fref * (m & ~3))) >= 0 ?
+					       ((Ftarget * n) - (Fref * (m & ~3))) : ((Fref * (m & ~3)) - (Ftarget * n));
+			if (new_error < best_error) {
+				best_n = n;
+				best_m = m;
+				best_error = new_error;
+			}
+		}
+	}
+	if (best_m > 257)
+		best_m >>= 2;	/* divide m by 4, and leave VCO loop divide at 4 */
+	else
+		divisor |= 4;	/* or set VCO loop divide to 1 */
+	*dclk2_m = best_m - 2;
+	*dclk2_n = best_n - 2;
+	*dclk2_div = divisor;
+	*ppixclock = pixclock;
+	return;
+}
+
+static void asiliant_set_timing(struct fb_info *p)
+{
+	unsigned hd = p->var.xres / 8;
+	unsigned hs = (p->var.xres + p->var.right_margin) / 8;
+       	unsigned he = (p->var.xres + p->var.right_margin + p->var.hsync_len) / 8;
+	unsigned ht = (p->var.left_margin + p->var.xres + p->var.right_margin + p->var.hsync_len) / 8;
+	unsigned vd = p->var.yres;
+	unsigned vs = p->var.yres + p->var.lower_margin;
+	unsigned ve = p->var.yres + p->var.lower_margin + p->var.vsync_len;
+	unsigned vt = p->var.upper_margin + p->var.yres + p->var.lower_margin + p->var.vsync_len;
+	unsigned wd = (p->var.xres_virtual * ((p->var.bits_per_pixel+7)/8)) / 8;
+
+	if ((p->var.xres == 640) && (p->var.yres == 480) && (p->var.pixclock == 39722)) {
+	  write_fr(0x01, 0x02);  /* LCD */
+	} else {
+	  write_fr(0x01, 0x01);  /* CRT */
+	}
+
+	write_cr(0x11, (ve - 1) & 0x0f);
+	write_cr(0x00, (ht - 5) & 0xff);
+	write_cr(0x01, hd - 1);
+	write_cr(0x02, hd);
+	write_cr(0x03, ((ht - 1) & 0x1f) | 0x80);
+	write_cr(0x04, hs);
+	write_cr(0x05, (((ht - 1) & 0x20) <<2) | (he & 0x1f));
+	write_cr(0x3c, (ht - 1) & 0xc0);
+	write_cr(0x06, (vt - 2) & 0xff);
+	write_cr(0x30, (vt - 2) >> 8);
+	write_cr(0x07, 0x00);
+	write_cr(0x08, 0x00);
+	write_cr(0x09, 0x00);
+	write_cr(0x10, (vs - 1) & 0xff);
+	write_cr(0x32, ((vs - 1) >> 8) & 0xf);
+	write_cr(0x11, ((ve - 1) & 0x0f) | 0x80);
+	write_cr(0x12, (vd - 1) & 0xff);
+	write_cr(0x31, ((vd - 1) & 0xf00) >> 8);
+	write_cr(0x13, wd & 0xff);
+	write_cr(0x41, (wd & 0xf00) >> 8);
+	write_cr(0x15, (vs - 1) & 0xff);
+	write_cr(0x33, ((vs - 1) >> 8) & 0xf);
+	write_cr(0x38, ((ht - 5) & 0x100) >> 8);
+	write_cr(0x16, (vt - 1) & 0xff);
+	write_cr(0x18, 0x00);
+
+	if (p->var.xres == 640) {
+	  writeb(0xc7, mmio_base + 0x784);	/* set misc output reg */
+	} else {
+	  writeb(0x07, mmio_base + 0x784);	/* set misc output reg */
+	}
+}
+
+static int asiliantfb_check_var(struct fb_var_screeninfo *var,
+			     struct fb_info *p)
+{
+	unsigned long Ftarget, ratio, remainder;
+
+	ratio = 1000000 / var->pixclock;
+	remainder = 1000000 % var->pixclock;
+	Ftarget = 1000000 * ratio + (1000000 * remainder) / var->pixclock;
+
+	/* First check the constraint that the maximum post-VCO divisor is 32,
+	 * and the maximum Fvco is 220MHz */
+	if (Ftarget > 220000000 || Ftarget < 3125000) {
+		printk(KERN_ERR "asiliantfb dotclock must be between 3.125 and 220MHz\n");
+		return -ENXIO;
+	}
+	var->xres_virtual = var->xres;
+	var->yres_virtual = var->yres;
+
+	if (var->bits_per_pixel == 24) {
+		var->red.offset = 16;
+		var->green.offset = 8;
+		var->blue.offset = 0;
+		var->red.length = var->blue.length = var->green.length = 8;
+	} else if (var->bits_per_pixel == 16) {
+		switch (var->red.offset) {
+			case 11:
+				var->green.length = 6;
+				break;
+			case 10:
+				var->green.length = 5;
+				break;
+			default:
+				return -EINVAL;
+		}
+		var->green.offset = 5;
+		var->blue.offset = 0;
+		var->red.length = var->blue.length = 5;
+	} else if (var->bits_per_pixel == 8) {
+		var->red.offset = var->green.offset = var->blue.offset = 0;
+		var->red.length = var->green.length = var->blue.length = 8;
+	}
+	return 0;
+}
+
+static int asiliantfb_set_par(struct fb_info *p)
+{
+	u8 dclk2_m;		/* Holds m-2 value for register */
+	u8 dclk2_n;		/* Holds n-2 value for register */
+	u8 dclk2_div;		/* Holds divisor bitmask */
+
+	/* Set pixclock */
+	asiliant_calc_dclk2(&p->var.pixclock, &dclk2_m, &dclk2_n, &dclk2_div);
+
+	/* Set color depth */
+	if (p->var.bits_per_pixel == 24) {
+		write_xr(0x81, 0x16);	/* 24 bit packed color mode */
+		write_xr(0x82, 0x00);	/* Disable palettes */
+		write_xr(0x20, 0x20);	/* 24 bit blitter mode */
+	} else if (p->var.bits_per_pixel == 16) {
+		if (p->var.red.offset == 11)
+			write_xr(0x81, 0x15);	/* 16 bit color mode */
+		else
+			write_xr(0x81, 0x14);	/* 15 bit color mode */
+		write_xr(0x82, 0x00);	/* Disable palettes */
+		write_xr(0x20, 0x10);	/* 16 bit blitter mode */
+	} else if (p->var.bits_per_pixel == 8) {
+		write_xr(0x0a, 0x02);	/* Linear */
+		write_xr(0x81, 0x12);	/* 8 bit color mode */
+		write_xr(0x82, 0x00);	/* Graphics gamma enable */
+		write_xr(0x20, 0x00);	/* 8 bit blitter mode */
+	}
+	p->fix.line_length = p->var.xres * (p->var.bits_per_pixel >> 3);
+	p->fix.visual = (p->var.bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+	write_xr(0xc4, dclk2_m);
+	write_xr(0xc5, dclk2_n);
+	write_xr(0xc7, dclk2_div);
+	/* Set up the CR registers */
+	asiliant_set_timing(p);
+	return 0;
+}
+
+static int asiliantfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			     u_int transp, struct fb_info *p)
+{
+	if (regno > 255)
+		return 1;
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+        /* Set hardware palete */
+	writeb(regno, mmio_base + 0x790);
+	udelay(1);
+	writeb(red, mmio_base + 0x791);
+	writeb(green, mmio_base + 0x791);
+	writeb(blue, mmio_base + 0x791);
+
+	switch(p->var.bits_per_pixel) {
+	case 15:
+		if (regno < 16) {
+			((u32 *)(p->pseudo_palette))[regno] =
+				((red & 0xf8) << 7) |
+				((green & 0xf8) << 2) |
+				((blue & 0xf8) >> 3);
+		}
+		break;
+	case 16:
+		if (regno < 16) {
+			((u32 *)(p->pseudo_palette))[regno] =
+				((red & 0xf8) << 8) |
+				((green & 0xfc) << 3) |
+				((blue & 0xf8) >> 3);
+		}
+		break;
+	case 24:
+		if (regno < 24) {
+			((u32 *)(p->pseudo_palette))[regno] =
+				(red << 16)  |
+				(green << 8) |
+				(blue);
+		}
+		break;
+	}
+	return 0;
+}
+
+struct chips_init_reg {
+	unsigned char addr;
+	unsigned char data;
+};
+
+#define N_ELTS(x)	(sizeof(x) / sizeof(x[0]))
+
+static struct chips_init_reg chips_init_sr[] =
+{
+	{0x00, 0x03},		/* Reset register */
+	{0x01, 0x01},		/* Clocking mode */
+	{0x02, 0x0f},		/* Plane mask */
+	{0x04, 0x0e}		/* Memory mode */
+};
+
+static struct chips_init_reg chips_init_gr[] =
+{
+        {0x03, 0x00},		/* Data rotate */
+	{0x05, 0x00},		/* Graphics mode */
+	{0x06, 0x01},		/* Miscellaneous */
+	{0x08, 0x00}		/* Bit mask */
+};
+
+static struct chips_init_reg chips_init_ar[] =
+{
+	{0x10, 0x01},		/* Mode control */
+	{0x11, 0x00},		/* Overscan */
+	{0x12, 0x0f},		/* Memory plane enable */
+	{0x13, 0x00}		/* Horizontal pixel panning */
+};
+
+static struct chips_init_reg chips_init_cr[] =
+{
+	{0x0c, 0x00},		/* Start address high */
+	{0x0d, 0x00},		/* Start address low */
+	{0x40, 0x00},		/* Extended Start Address */
+	{0x41, 0x00},		/* Extended Start Address */
+	{0x14, 0x00},		/* Underline location */
+	{0x17, 0xe3},		/* CRT mode control */
+	{0x70, 0x00}		/* Interlace control */
+};
+
+
+static struct chips_init_reg chips_init_fr[] =
+{
+	{0x01, 0x02},
+	{0x03, 0x08},
+	{0x08, 0xcc},
+	{0x0a, 0x08},
+	{0x18, 0x00},
+	{0x1e, 0x80},
+	{0x40, 0x83},
+	{0x41, 0x00},
+	{0x48, 0x13},
+	{0x4d, 0x60},
+	{0x4e, 0x0f},
+
+	{0x0b, 0x01},
+
+	{0x21, 0x51},
+	{0x22, 0x1d},
+	{0x23, 0x5f},
+	{0x20, 0x4f},
+	{0x34, 0x00},
+	{0x24, 0x51},
+	{0x25, 0x00},
+	{0x27, 0x0b},
+	{0x26, 0x00},
+	{0x37, 0x80},
+	{0x33, 0x0b},
+	{0x35, 0x11},
+	{0x36, 0x02},
+	{0x31, 0xea},
+	{0x32, 0x0c},
+	{0x30, 0xdf},
+	{0x10, 0x0c},
+	{0x11, 0xe0},
+	{0x12, 0x50},
+	{0x13, 0x00},
+	{0x16, 0x03},
+	{0x17, 0xbd},
+	{0x1a, 0x00},
+};
+
+
+static struct chips_init_reg chips_init_xr[] =
+{
+	{0xce, 0x00},		/* set default memory clock */
+	{0xcc, 200 },	        /* MCLK ratio M */
+	{0xcd, 18  },	        /* MCLK ratio N */
+	{0xce, 0x90},		/* MCLK divisor = 2 */
+
+	{0xc4, 209 },
+	{0xc5, 118 },
+	{0xc7, 32  },
+	{0xcf, 0x06},
+	{0x09, 0x01},		/* IO Control - CRT controller extensions */
+	{0x0a, 0x02},		/* Frame buffer mapping */
+	{0x0b, 0x01},		/* PCI burst write */
+	{0x40, 0x03},		/* Memory access control */
+	{0x80, 0x82},		/* Pixel pipeline configuration 0 */
+	{0x81, 0x12},		/* Pixel pipeline configuration 1 */
+	{0x82, 0x08},		/* Pixel pipeline configuration 2 */
+
+	{0xd0, 0x0f},
+	{0xd1, 0x01},
+};
+
+static void __devinit chips_hw_init(struct fb_info *p)
+{
+	int i;
+
+	for (i = 0; i < N_ELTS(chips_init_xr); ++i)
+		write_xr(chips_init_xr[i].addr, chips_init_xr[i].data);
+	write_xr(0x81, 0x12);
+	write_xr(0x82, 0x08);
+	write_xr(0x20, 0x00);
+	for (i = 0; i < N_ELTS(chips_init_sr); ++i)
+		write_sr(chips_init_sr[i].addr, chips_init_sr[i].data);
+	for (i = 0; i < N_ELTS(chips_init_gr); ++i)
+		write_gr(chips_init_gr[i].addr, chips_init_gr[i].data);
+	for (i = 0; i < N_ELTS(chips_init_ar); ++i)
+		write_ar(chips_init_ar[i].addr, chips_init_ar[i].data);
+	/* Enable video output in attribute index register */
+	writeb(0x20, mmio_base + 0x780);
+	for (i = 0; i < N_ELTS(chips_init_cr); ++i)
+		write_cr(chips_init_cr[i].addr, chips_init_cr[i].data);
+	for (i = 0; i < N_ELTS(chips_init_fr); ++i)
+		write_fr(chips_init_fr[i].addr, chips_init_fr[i].data);
+}
+
+static struct fb_fix_screeninfo asiliantfb_fix __devinitdata = {
+	.id =		"Asiliant 69000",
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_PSEUDOCOLOR,
+	.accel =	FB_ACCEL_NONE,
+	.line_length =	640,
+	.smem_len =	0x200000,	/* 2MB */
+};
+
+static struct fb_var_screeninfo asiliantfb_var __devinitdata = {
+	.xres 		= 640,
+	.yres 		= 480,
+	.xres_virtual 	= 640,
+	.yres_virtual 	= 480,
+	.bits_per_pixel = 8,
+	.red 		= { .length = 8 },
+	.green 		= { .length = 8 },
+	.blue 		= { .length = 8 },
+	.height 	= -1,
+	.width 		= -1,
+	.vmode 		= FB_VMODE_NONINTERLACED,
+	.pixclock 	= 39722,
+	.left_margin 	= 48,
+	.right_margin 	= 16,
+	.upper_margin 	= 33,
+	.lower_margin 	= 10,
+	.hsync_len 	= 96,
+	.vsync_len 	= 2,
+};
+
+static void __devinit init_asiliant(struct fb_info *p, unsigned long addr)
+{
+	p->fix			= asiliantfb_fix;
+	p->fix.smem_start	= addr;
+	p->var			= asiliantfb_var;
+	p->fbops		= &asiliantfb_ops;
+	p->flags		= FBINFO_DEFAULT;
+
+	fb_alloc_cmap(&p->cmap, 256, 0);
+
+	if (register_framebuffer(p) < 0) {
+		printk(KERN_ERR "C&T 69000 framebuffer failed to register\n");
+		return;
+	}
+
+	printk(KERN_INFO "fb%d: Asiliant 69000 frame buffer (%dK RAM detected)\n",
+		p->node, p->fix.smem_len / 1024);
+
+	writeb(0xff, mmio_base + 0x78c);
+	chips_hw_init(p);
+}
+
+static int __devinit
+asiliantfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
+{
+	unsigned long addr, size;
+	struct fb_info *p;
+
+	if ((dp->resource[0].flags & IORESOURCE_MEM) == 0)
+		return -ENODEV;
+	addr = pci_resource_start(dp, 0);
+	size = pci_resource_len(dp, 0);
+	if (addr == 0)
+		return -ENODEV;
+	if (!request_mem_region(addr, size, "asiliantfb"))
+		return -EBUSY;
+
+	p = framebuffer_alloc(sizeof(u32) * 256, &dp->dev);
+	if (!p)	{
+		release_mem_region(addr, size);
+		return -ENOMEM;
+	}
+	p->pseudo_palette = p->par;
+	p->par = NULL;
+
+	p->screen_base = ioremap(addr, 0x800000);
+	if (p->screen_base == NULL) {
+		release_mem_region(addr, size);
+		framebuffer_release(p);
+		return -ENOMEM;
+	}
+
+	pci_write_config_dword(dp, 4, 0x02800083);
+	writeb(3, p->screen_base + 0x400784);
+
+	init_asiliant(p, addr);
+
+	pci_set_drvdata(dp, p);
+	return 0;
+}
+
+static void __devexit asiliantfb_remove(struct pci_dev *dp)
+{
+	struct fb_info *p = pci_get_drvdata(dp);
+
+	unregister_framebuffer(p);
+	iounmap(p->screen_base);
+	release_mem_region(pci_resource_start(dp, 0), pci_resource_len(dp, 0));
+	pci_set_drvdata(dp, NULL);
+	framebuffer_release(p);
+}
+
+static struct pci_device_id asiliantfb_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_CT, PCI_DEVICE_ID_CT_69000, PCI_ANY_ID, PCI_ANY_ID },
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, asiliantfb_pci_tbl);
+
+static struct pci_driver asiliantfb_driver = {
+	.name =		"asiliantfb",
+	.id_table =	asiliantfb_pci_tbl,
+	.probe =	asiliantfb_pci_init,
+	.remove =	__devexit_p(asiliantfb_remove),
+};
+
+static int __init asiliantfb_init(void)
+{
+	if (fb_get_options("asiliantfb", NULL))
+		return -ENODEV;
+
+	return pci_register_driver(&asiliantfb_driver);
+}
+
+module_init(asiliantfb_init);
+
+static void __exit asiliantfb_exit(void)
+{
+	pci_unregister_driver(&asiliantfb_driver);
+}
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c
new file mode 100644
index 0000000..15ec129
--- /dev/null
+++ b/drivers/video/atafb.c
@@ -0,0 +1,3098 @@
+/*
+ * linux/drivers/video/atafb.c -- Atari builtin chipset frame buffer device
+ *
+ *  Copyright (C) 1994 Martin Schaller & Roman Hodek
+ *  
+ * 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.
+ *
+ * History:
+ *   - 03 Jan 95: Original version by Martin Schaller: The TT driver and
+ *                all the device independent stuff
+ *   - 09 Jan 95: Roman: I've added the hardware abstraction (hw_switch)
+ *                and wrote the Falcon, ST(E), and External drivers
+ *                based on the original TT driver.
+ *   - 07 May 95: Martin: Added colormap operations for the external driver
+ *   - 21 May 95: Martin: Added support for overscan
+ *		  Andreas: some bug fixes for this
+ *   -    Jul 95: Guenther Kelleter <guenther@pool.informatik.rwth-aachen.de>:
+ *                Programmable Falcon video modes
+ *                (thanks to Christian Cartus for documentation
+ *                of VIDEL registers).
+ *   - 27 Dec 95: Guenther: Implemented user definable video modes "user[0-7]"
+ *                on minor 24...31. "user0" may be set on commandline by
+ *                "R<x>;<y>;<depth>". (Makes sense only on Falcon)
+ *                Video mode switch on Falcon now done at next VBL interrupt
+ *                to avoid the annoying right shift of the screen.
+ *   - 23 Sep 97: Juergen: added xres_virtual for cards like ProMST
+ *                The external-part is legacy, therefore hardware-specific
+ *                functions like panning/hardwarescrolling/blanking isn't
+ *				  supported.
+ *   - 29 Sep 97: Juergen: added Romans suggestion for pan_display
+ *				  (var->xoffset was changed even if no set_screen_base avail.)
+ *	 - 05 Oct 97: Juergen: extfb (PACKED_PIXEL) is FB_PSEUDOCOLOR 'cause
+ *				  we know how to set the colors
+ *				  ext_*palette: read from ext_colors (former MV300_colors)
+ *							    write to ext_colors and RAMDAC
+ *
+ * To do:
+ *   - For the Falcon it is not possible to set random video modes on
+ *     SM124 and SC/TV, only the bootup resolution is supported.
+ *
+ */
+
+#define ATAFB_TT
+#define ATAFB_STE
+#define ATAFB_EXT
+#define ATAFB_FALCON
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include <asm/setup.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#include <asm/atari_stram.h>
+
+#include <linux/fb.h>
+#include <asm/atarikb.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-iplan2p2.h>
+#include <video/fbcon-iplan2p4.h>
+#include <video/fbcon-iplan2p8.h>
+#include <video/fbcon-mfb.h>
+
+
+#define SWITCH_ACIA 0x01		/* modes for switch on OverScan */
+#define SWITCH_SND6 0x40
+#define SWITCH_SND7 0x80
+#define SWITCH_NONE 0x00
+
+
+#define up(x, r) (((x) + (r) - 1) & ~((r)-1))
+
+
+static int default_par=0;	/* default resolution (0=none) */
+
+static unsigned long default_mem_req=0;
+
+static int hwscroll=-1;
+
+static int use_hwscroll = 1;
+
+static int sttt_xres=640,st_yres=400,tt_yres=480;
+static int sttt_xres_virtual=640,sttt_yres_virtual=400;
+static int ovsc_offset=0, ovsc_addlen=0;
+
+static struct atafb_par {
+	void *screen_base;
+	int yres_virtual;
+#if defined ATAFB_TT || defined ATAFB_STE
+	union {
+		struct {
+			int mode;
+			int sync;
+		} tt, st;
+#endif
+#ifdef ATAFB_FALCON
+		struct falcon_hw {
+			/* Here are fields for storing a video mode, as direct
+			 * parameters for the hardware.
+			 */
+			short sync;
+			short line_width;
+			short line_offset;
+			short st_shift;
+			short f_shift;
+			short vid_control;
+			short vid_mode;
+			short xoffset;
+			short hht, hbb, hbe, hdb, hde, hss;
+			short vft, vbb, vbe, vdb, vde, vss;
+			/* auxiliary information */
+			short mono;
+			short ste_mode;
+			short bpp;
+		} falcon;
+#endif
+		/* Nothing needed for external mode */
+	} hw;
+} current_par;
+
+/* Don't calculate an own resolution, and thus don't change the one found when
+ * booting (currently used for the Falcon to keep settings for internal video
+ * hardware extensions (e.g. ScreenBlaster)  */
+static int DontCalcRes = 0; 
+
+#ifdef ATAFB_FALCON
+#define HHT hw.falcon.hht
+#define HBB hw.falcon.hbb
+#define HBE hw.falcon.hbe
+#define HDB hw.falcon.hdb
+#define HDE hw.falcon.hde
+#define HSS hw.falcon.hss
+#define VFT hw.falcon.vft
+#define VBB hw.falcon.vbb
+#define VBE hw.falcon.vbe
+#define VDB hw.falcon.vdb
+#define VDE hw.falcon.vde
+#define VSS hw.falcon.vss
+#define VCO_CLOCK25		0x04
+#define VCO_CSYPOS		0x10
+#define VCO_VSYPOS		0x20
+#define VCO_HSYPOS		0x40
+#define VCO_SHORTOFFS	0x100
+#define VMO_DOUBLE		0x01
+#define VMO_INTER		0x02
+#define VMO_PREMASK		0x0c
+#endif
+
+static struct fb_info fb_info;
+
+static void *screen_base;	/* base address of screen */
+static void *real_screen_base;	/* (only for Overscan) */
+
+static int screen_len;
+
+static int current_par_valid=0; 
+
+static int mono_moni=0;
+
+static struct display disp;
+
+
+#ifdef ATAFB_EXT
+/* external video handling */
+
+static unsigned			external_xres;
+static unsigned			external_xres_virtual;
+static unsigned			external_yres;
+/* not needed - atafb will never support panning/hardwarescroll with external
+ * static unsigned		external_yres_virtual;	
+*/
+
+static unsigned			external_depth;
+static int				external_pmode;
+static void *external_addr = 0;
+static unsigned long	external_len;
+static unsigned long	external_vgaiobase = 0;
+static unsigned int		external_bitspercol = 6;
+
+/* 
+JOE <joe@amber.dinoco.de>: 
+added card type for external driver, is only needed for
+colormap handling.
+*/
+
+enum cardtype { IS_VGA, IS_MV300 };
+static enum cardtype external_card_type = IS_VGA;
+
+/*
+The MV300 mixes the color registers. So we need an array of munged
+indices in order to access the correct reg.
+*/
+static int MV300_reg_1bit[2]={0,1};
+static int MV300_reg_4bit[16]={
+0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };
+static int MV300_reg_8bit[256]={
+0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, 
+8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, 
+4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, 
+12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, 
+2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, 
+10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, 
+6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, 
+14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, 
+1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, 
+9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, 
+5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, 
+13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, 
+3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, 
+11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, 
+7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, 
+15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255 }; 
+
+static int *MV300_reg = MV300_reg_8bit;
+
+/*
+And on the MV300 it's difficult to read out the hardware palette. So we
+just keep track of the set colors in our own array here, and use that!
+*/
+
+static struct { unsigned char red,green,blue,pad; } ext_color[256];
+#endif /* ATAFB_EXT */
+
+
+static int inverse=0;
+
+extern int fontheight_8x8;
+extern int fontwidth_8x8;
+extern unsigned char fontdata_8x8[];
+
+extern int fontheight_8x16;
+extern int fontwidth_8x16;
+extern unsigned char fontdata_8x16[];
+
+/* ++roman: This structure abstracts from the underlying hardware (ST(e),
+ * TT, or Falcon.
+ *
+ * int (*detect)( void )
+ *   This function should detect the current video mode settings and
+ *   store them in atafb_predefined[0] for later reference by the
+ *   user. Return the index+1 of an equivalent predefined mode or 0
+ *   if there is no such.
+ * 
+ * int (*encode_fix)( struct fb_fix_screeninfo *fix,
+ *                    struct atafb_par *par )
+ *   This function should fill in the 'fix' structure based on the
+ *   values in the 'par' structure.
+ *   
+ * int (*decode_var)( struct fb_var_screeninfo *var,
+ *                    struct atafb_par *par )
+ *   Get the video params out of 'var'. If a value doesn't fit, round
+ *   it up, if it's too big, return EINVAL.
+ *   Round up in the following order: bits_per_pixel, xres, yres, 
+ *   xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields, 
+ *   horizontal timing, vertical timing.
+ *
+ * int (*encode_var)( struct fb_var_screeninfo *var,
+ *                    struct atafb_par *par );
+ *   Fill the 'var' structure based on the values in 'par' and maybe
+ *   other values read out of the hardware.
+ *   
+ * void (*get_par)( struct atafb_par *par )
+ *   Fill the hardware's 'par' structure.
+ *   
+ * void (*set_par)( struct atafb_par *par )
+ *   Set the hardware according to 'par'.
+ *   
+ * int (*getcolreg)( unsigned regno, unsigned *red,
+ *                   unsigned *green, unsigned *blue,
+ *                   unsigned *transp, struct fb_info *info )
+ *   Read a single color register and split it into
+ *   colors/transparent. Return != 0 for invalid regno.
+ *
+ * void (*set_screen_base)(void *s_base)
+ *   Set the base address of the displayed frame buffer. Only called
+ *   if yres_virtual > yres or xres_virtual > xres.
+ *
+ * int (*blank)( int blank_mode )
+ *   Blank the screen if blank_mode!=0, else unblank. If blank==NULL then
+ *   the caller blanks by setting the CLUT to all black. Return 0 if blanking
+ *   succeeded, !=0 if un-/blanking failed due to e.g. a video mode which
+ *   doesn't support it. Implements VESA suspend and powerdown modes on
+ *   hardware that supports disabling hsync/vsync:
+ *       blank_mode==2: suspend vsync, 3:suspend hsync, 4: powerdown.
+ */
+
+static struct fb_hwswitch {
+	int  (*detect)( void );
+	int  (*encode_fix)( struct fb_fix_screeninfo *fix,
+						struct atafb_par *par );
+	int  (*decode_var)( struct fb_var_screeninfo *var,
+						struct atafb_par *par );
+	int  (*encode_var)( struct fb_var_screeninfo *var,
+						struct atafb_par *par );
+	void (*get_par)( struct atafb_par *par );
+	void (*set_par)( struct atafb_par *par );
+	int  (*getcolreg)( unsigned regno, unsigned *red,
+					   unsigned *green, unsigned *blue,
+					   unsigned *transp, struct fb_info *info );
+	void (*set_screen_base)(void *s_base);
+	int  (*blank)( int blank_mode );
+	int  (*pan_display)( struct fb_var_screeninfo *var,
+						 struct atafb_par *par);
+} *fbhw;
+
+static char *autodetect_names[] = {"autodetect", NULL};
+static char *stlow_names[] = {"stlow", NULL};
+static char *stmid_names[] = {"stmid", "default5", NULL};
+static char *sthigh_names[] = {"sthigh", "default4", NULL};
+static char *ttlow_names[] = {"ttlow", NULL};
+static char *ttmid_names[]= {"ttmid", "default1", NULL};
+static char *tthigh_names[]= {"tthigh", "default2", NULL};
+static char *vga2_names[] = {"vga2", NULL};
+static char *vga4_names[] = {"vga4", NULL};
+static char *vga16_names[] = {"vga16", "default3", NULL};
+static char *vga256_names[] = {"vga256", NULL};
+static char *falh2_names[] = {"falh2", NULL};
+static char *falh16_names[] = {"falh16", NULL};
+
+static char **fb_var_names[] = {
+	/* Writing the name arrays directly in this array (via "(char *[]){...}")
+	 * crashes gcc 2.5.8 (sigsegv) if the inner array
+	 * contains more than two items. I've also seen that all elements
+	 * were identical to the last (my cross-gcc) :-(*/
+	autodetect_names,
+	stlow_names,
+	stmid_names,
+	sthigh_names,
+	ttlow_names,
+	ttmid_names,
+	tthigh_names,
+	vga2_names,
+	vga4_names,
+	vga16_names,
+	vga256_names,
+	falh2_names,
+	falh16_names,
+	NULL
+	/* ,NULL */ /* this causes a sigsegv on my gcc-2.5.8 */
+};
+
+static struct fb_var_screeninfo atafb_predefined[] = {
+ 	/*
+ 	 * yres_virtual==0 means use hw-scrolling if possible, else yres
+ 	 */
+ 	{ /* autodetect */
+	  0, 0, 0, 0, 0, 0, 0, 0,   		/* xres-grayscale */
+	  {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, 	/* red green blue tran*/
+	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+ 	{ /* st low */
+	  320, 200, 320, 0, 0, 0, 4, 0,
+	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
+	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+	{ /* st mid */
+	  640, 200, 640, 0, 0, 0, 2, 0,
+	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
+	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+	{ /* st high */
+	  640, 400, 640, 0, 0, 0, 1, 0,
+	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
+	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+	{ /* tt low */
+	  320, 480, 320, 0, 0, 0, 8, 0,
+	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
+	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+	{ /* tt mid */
+	  640, 480, 640, 0, 0, 0, 4, 0,
+	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
+	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+	{ /* tt high */
+	  1280, 960, 1280, 0, 0, 0, 1, 0,
+	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
+	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+	{ /* vga2 */
+	  640, 480, 640, 0, 0, 0, 1, 0,
+	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
+	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+	{ /* vga4 */
+	  640, 480, 640, 0, 0, 0, 2, 0,
+	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
+	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+	{ /* vga16 */
+	  640, 480, 640, 0, 0, 0, 4, 0,
+	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
+	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+	{ /* vga256 */
+	  640, 480, 640, 0, 0, 0, 8, 0,
+	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
+	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+	{ /* falh2 */
+	  896, 608, 896, 0, 0, 0, 1, 0,
+	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
+	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+	{ /* falh16 */
+	  896, 608, 896, 0, 0, 0, 4, 0,
+	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
+	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+};
+
+static int num_atafb_predefined=ARRAY_SIZE(atafb_predefined);
+
+
+static int
+get_video_mode(char *vname)
+{
+    char ***name_list;
+    char **name;
+    int i;
+    name_list=fb_var_names;
+    for (i = 0 ; i < num_atafb_predefined ; i++) {
+	name=*(name_list++);
+	if (! name || ! *name)
+	    break;
+	while (*name) {
+	    if (! strcmp(vname, *name))
+		return i+1;
+	    name++;
+	}
+    }
+    return 0;
+}
+
+
+
+/* ------------------- TT specific functions ---------------------- */
+
+#ifdef ATAFB_TT
+
+static int tt_encode_fix( struct fb_fix_screeninfo *fix,
+						  struct atafb_par *par )
+
+{
+	int mode;
+
+	strcpy(fix->id,"Atari Builtin");
+	fix->smem_start = (unsigned long)real_screen_base;
+	fix->smem_len = screen_len;
+	fix->type=FB_TYPE_INTERLEAVED_PLANES;
+	fix->type_aux=2;
+	fix->visual=FB_VISUAL_PSEUDOCOLOR;
+	mode = par->hw.tt.mode & TT_SHIFTER_MODEMASK;
+	if (mode == TT_SHIFTER_TTHIGH || mode == TT_SHIFTER_STHIGH) {
+		fix->type=FB_TYPE_PACKED_PIXELS;
+		fix->type_aux=0;
+		if (mode == TT_SHIFTER_TTHIGH)
+			fix->visual=FB_VISUAL_MONO01;
+	}
+	fix->xpanstep=0;
+	fix->ypanstep=1;
+	fix->ywrapstep=0;
+	fix->line_length = 0;
+	fix->accel = FB_ACCEL_ATARIBLITT;
+	return 0;
+}
+
+
+static int tt_decode_var( struct fb_var_screeninfo *var,
+						  struct atafb_par *par )
+{
+	int xres=var->xres;
+	int yres=var->yres;
+	int bpp=var->bits_per_pixel;
+	int linelen;
+	int yres_virtual = var->yres_virtual;
+
+	if (mono_moni) {
+		if (bpp > 1 || xres > sttt_xres*2 || yres >tt_yres*2)
+			return -EINVAL;
+		par->hw.tt.mode=TT_SHIFTER_TTHIGH;
+		xres=sttt_xres*2;
+		yres=tt_yres*2;
+		bpp=1;
+	} else {
+		if (bpp > 8 || xres > sttt_xres || yres > tt_yres)
+			return -EINVAL;
+		if (bpp > 4) {
+			if (xres > sttt_xres/2 || yres > tt_yres)
+				return -EINVAL;
+			par->hw.tt.mode=TT_SHIFTER_TTLOW;
+			xres=sttt_xres/2;
+			yres=tt_yres;
+			bpp=8;
+		}
+		else if (bpp > 2) {
+			if (xres > sttt_xres || yres > tt_yres)
+				return -EINVAL;
+			if (xres > sttt_xres/2 || yres > st_yres/2) {
+				par->hw.tt.mode=TT_SHIFTER_TTMID;
+				xres=sttt_xres;
+				yres=tt_yres;
+				bpp=4;
+			}
+			else {
+				par->hw.tt.mode=TT_SHIFTER_STLOW;
+				xres=sttt_xres/2;
+				yres=st_yres/2;
+				bpp=4;
+			}
+		}
+		else if (bpp > 1) {
+			if (xres > sttt_xres || yres > st_yres/2)
+				return -EINVAL;
+			par->hw.tt.mode=TT_SHIFTER_STMID;
+			xres=sttt_xres;
+			yres=st_yres/2;
+			bpp=2;
+		}
+		else if (var->xres > sttt_xres || var->yres > st_yres) {
+			return -EINVAL;
+		}
+		else {
+			par->hw.tt.mode=TT_SHIFTER_STHIGH;
+			xres=sttt_xres;
+			yres=st_yres;
+			bpp=1;
+		}
+	}
+	if (yres_virtual <= 0)
+		yres_virtual = 0;
+	else if (yres_virtual < yres)
+		yres_virtual = yres;
+	if (var->sync & FB_SYNC_EXT)
+		par->hw.tt.sync=0;
+	else
+		par->hw.tt.sync=1;
+	linelen=xres*bpp/8;
+	if (yres_virtual * linelen > screen_len && screen_len)
+		return -EINVAL;
+	if (yres * linelen > screen_len && screen_len)
+		return -EINVAL;
+	if (var->yoffset + yres > yres_virtual && yres_virtual)
+		return -EINVAL;
+	par->yres_virtual = yres_virtual;
+	par->screen_base = screen_base + var->yoffset * linelen;
+	return 0;
+}
+
+static int tt_encode_var( struct fb_var_screeninfo *var,
+						  struct atafb_par *par )
+{
+	int linelen;
+	memset(var, 0, sizeof(struct fb_var_screeninfo));
+	var->red.offset=0;
+	var->red.length=4;
+	var->red.msb_right=0;
+	var->grayscale=0;
+
+	var->pixclock=31041;
+	var->left_margin=120;		/* these may be incorrect 	*/
+	var->right_margin=100;
+	var->upper_margin=8;
+	var->lower_margin=16;
+	var->hsync_len=140;
+	var->vsync_len=30;
+
+	var->height=-1;
+	var->width=-1;
+
+	if (par->hw.tt.sync & 1)
+		var->sync=0;
+	else
+		var->sync=FB_SYNC_EXT;
+
+	switch (par->hw.tt.mode & TT_SHIFTER_MODEMASK) {
+	case TT_SHIFTER_STLOW:
+		var->xres=sttt_xres/2;
+		var->xres_virtual=sttt_xres_virtual/2;
+		var->yres=st_yres/2;
+		var->bits_per_pixel=4;
+		break;
+	case TT_SHIFTER_STMID:
+		var->xres=sttt_xres;
+		var->xres_virtual=sttt_xres_virtual;
+		var->yres=st_yres/2;
+		var->bits_per_pixel=2;
+		break;
+	case TT_SHIFTER_STHIGH:
+		var->xres=sttt_xres;
+		var->xres_virtual=sttt_xres_virtual;
+		var->yres=st_yres;
+		var->bits_per_pixel=1;
+		break;
+	case TT_SHIFTER_TTLOW:
+		var->xres=sttt_xres/2;
+		var->xres_virtual=sttt_xres_virtual/2;
+		var->yres=tt_yres;
+		var->bits_per_pixel=8;
+		break;
+	case TT_SHIFTER_TTMID:
+		var->xres=sttt_xres;
+		var->xres_virtual=sttt_xres_virtual;
+		var->yres=tt_yres;
+		var->bits_per_pixel=4;
+		break;
+	case TT_SHIFTER_TTHIGH:
+		var->red.length=0;
+		var->xres=sttt_xres*2;
+		var->xres_virtual=sttt_xres_virtual*2;
+		var->yres=tt_yres*2;
+		var->bits_per_pixel=1;
+		break;
+	}		
+	var->blue=var->green=var->red;
+	var->transp.offset=0;
+	var->transp.length=0;
+	var->transp.msb_right=0;
+	linelen=var->xres_virtual * var->bits_per_pixel / 8;
+	if (! use_hwscroll)
+		var->yres_virtual=var->yres;
+	else if (screen_len) {
+		if (par->yres_virtual)
+			var->yres_virtual = par->yres_virtual;
+		else
+			/* yres_virtual==0 means use maximum */
+			var->yres_virtual = screen_len / linelen;
+	} else {
+		if (hwscroll < 0)
+			var->yres_virtual = 2 * var->yres;
+		else
+			var->yres_virtual=var->yres+hwscroll * 16;
+	}
+	var->xoffset=0;
+	if (screen_base)
+		var->yoffset=(par->screen_base - screen_base)/linelen;
+	else
+		var->yoffset=0;
+	var->nonstd=0;
+	var->activate=0;
+	var->vmode=FB_VMODE_NONINTERLACED;
+	return 0;
+}
+
+
+static void tt_get_par( struct atafb_par *par )
+{
+	unsigned long addr;
+	par->hw.tt.mode=shifter_tt.tt_shiftmode;
+	par->hw.tt.sync=shifter.syncmode;
+	addr = ((shifter.bas_hi & 0xff) << 16) |
+	       ((shifter.bas_md & 0xff) << 8)  |
+	       ((shifter.bas_lo & 0xff));
+	par->screen_base = phys_to_virt(addr);
+}
+
+static void tt_set_par( struct atafb_par *par )
+{
+	shifter_tt.tt_shiftmode=par->hw.tt.mode;
+	shifter.syncmode=par->hw.tt.sync;
+	/* only set screen_base if really necessary */
+	if (current_par.screen_base != par->screen_base)
+		fbhw->set_screen_base(par->screen_base);
+}
+
+
+static int tt_getcolreg(unsigned regno, unsigned *red,
+			unsigned *green, unsigned *blue,
+			unsigned *transp, struct fb_info *info)
+{
+	int t, col;
+
+	if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH)
+		regno += 254;
+	if (regno > 255)
+		return 1;
+	t = tt_palette[regno];
+	col = t & 15;
+	col |= col << 4;
+	col |= col << 8;
+	*blue = col;
+	col = (t >> 4) & 15;
+	col |= col << 4;
+	col |= col << 8;
+	*green = col;
+	col = (t >> 8) & 15;
+	col |= col << 4;
+	col |= col << 8;
+	*red = col;
+	*transp = 0;
+	return 0;
+}
+
+
+static int tt_setcolreg(unsigned regno, unsigned red,
+			unsigned green, unsigned blue,
+			unsigned transp, struct fb_info *info)
+{
+	if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH)
+		regno += 254;
+	if (regno > 255)
+		return 1;
+	tt_palette[regno] = (((red >> 12) << 8) | ((green >> 12) << 4) |
+			     (blue >> 12));
+	if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) ==
+		TT_SHIFTER_STHIGH && regno == 254)
+		tt_palette[0] = 0;
+	return 0;
+}
+
+						  
+static int tt_detect( void )
+
+{	struct atafb_par par;
+
+	/* Determine the connected monitor: The DMA sound must be
+	 * disabled before reading the MFP GPIP, because the Sound
+	 * Done Signal and the Monochrome Detect are XORed together!
+	 *
+	 * Even on a TT, we should look if there is a DMA sound. It was
+	 * announced that the Eagle is TT compatible, but only the PCM is
+	 * missing...
+	 */
+	if (ATARIHW_PRESENT(PCM_8BIT)) { 
+		tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+		udelay(20);	/* wait a while for things to settle down */
+	}
+	mono_moni = (mfp.par_dt_reg & 0x80) == 0;
+
+	tt_get_par(&par);
+	tt_encode_var(&atafb_predefined[0], &par);
+
+	return 1;
+}
+
+#endif /* ATAFB_TT */
+
+/* ------------------- Falcon specific functions ---------------------- */
+
+#ifdef ATAFB_FALCON
+
+static int mon_type;		/* Falcon connected monitor */
+static int f030_bus_width;	/* Falcon ram bus width (for vid_control) */
+#define F_MON_SM	0
+#define F_MON_SC	1
+#define F_MON_VGA	2
+#define F_MON_TV	3
+
+static struct pixel_clock {
+	unsigned long f;	/* f/[Hz] */
+	unsigned long t;	/* t/[ps] (=1/f) */
+	int right, hsync, left;	/* standard timing in clock cycles, not pixel */
+		/* hsync initialized in falcon_detect() */
+	int sync_mask;		/* or-mask for hw.falcon.sync to set this clock */
+	int control_mask;	/* ditto, for hw.falcon.vid_control */
+}
+f25  = {25175000, 39721, 18, 0, 42, 0x0, VCO_CLOCK25},
+f32  = {32000000, 31250, 18, 0, 42, 0x0, 0},
+fext = {       0,     0, 18, 0, 42, 0x1, 0};
+
+/* VIDEL-prescale values [mon_type][pixel_length from VCO] */
+static int vdl_prescale[4][3] = {{4,2,1}, {4,2,1}, {4,2,2}, {4,2,1}};
+
+/* Default hsync timing [mon_type] in picoseconds */
+static long h_syncs[4] = {3000000, 4875000, 4000000, 4875000};
+
+#ifdef FBCON_HAS_CFB16
+static u16 fbcon_cfb16_cmap[16];
+#endif
+
+static inline int hxx_prescale(struct falcon_hw *hw)
+{
+	return hw->ste_mode ? 16 :
+		   vdl_prescale[mon_type][hw->vid_mode >> 2 & 0x3];
+}
+
+static int falcon_encode_fix( struct fb_fix_screeninfo *fix,
+							  struct atafb_par *par )
+{
+	strcpy(fix->id, "Atari Builtin");
+	fix->smem_start = (unsigned long)real_screen_base;
+	fix->smem_len = screen_len;
+	fix->type = FB_TYPE_INTERLEAVED_PLANES;
+	fix->type_aux = 2;
+	fix->visual = FB_VISUAL_PSEUDOCOLOR;
+	fix->xpanstep = 1;
+	fix->ypanstep = 1;
+	fix->ywrapstep = 0;
+	if (par->hw.falcon.mono) {
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->type_aux = 0;
+		/* no smooth scrolling with longword aligned video mem */
+		fix->xpanstep = 32;
+	}
+	else if (par->hw.falcon.f_shift & 0x100) {
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->type_aux = 0;
+		/* Is this ok or should it be DIRECTCOLOR? */
+		fix->visual = FB_VISUAL_TRUECOLOR;
+		fix->xpanstep = 2;
+	}
+	fix->line_length = 0;
+	fix->accel = FB_ACCEL_ATARIBLITT;
+	return 0;
+}
+
+
+static int falcon_decode_var( struct fb_var_screeninfo *var,
+							  struct atafb_par *par )
+{
+	int bpp = var->bits_per_pixel;
+	int xres = var->xres;
+	int yres = var->yres;
+	int xres_virtual = var->xres_virtual;
+	int yres_virtual = var->yres_virtual;
+	int left_margin, right_margin, hsync_len;
+	int upper_margin, lower_margin, vsync_len;
+	int linelen;
+	int interlace = 0, doubleline = 0;
+	struct pixel_clock *pclock;
+	int plen; /* width of pixel in clock cycles */
+	int xstretch;
+	int prescale;
+	int longoffset = 0;
+	int hfreq, vfreq;
+
+/*
+	Get the video params out of 'var'. If a value doesn't fit, round
+	it up, if it's too big, return EINVAL.
+	Round up in the following order: bits_per_pixel, xres, yres, 
+	xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields, 
+	horizontal timing, vertical timing.
+
+	There is a maximum of screen resolution determined by pixelclock
+	and minimum frame rate -- (X+hmarg.)*(Y+vmarg.)*vfmin <= pixelclock.
+	In interlace mode this is     "     *    "     *vfmin <= pixelclock.
+	Additional constraints: hfreq.
+	Frequency range for multisync monitors is given via command line.
+	For TV and SM124 both frequencies are fixed.
+
+	X % 16 == 0 to fit 8x?? font (except 1 bitplane modes must use X%32==0)
+	Y % 16 == 0 to fit 8x16 font
+	Y % 8 == 0 if Y<400
+
+	Currently interlace and doubleline mode in var are ignored. 
+	On SM124 and TV only the standard resolutions can be used.
+*/
+
+	/* Reject uninitialized mode */
+	if (!xres || !yres || !bpp)
+		return -EINVAL;
+
+	if (mon_type == F_MON_SM && bpp != 1) {
+		return -EINVAL;
+	}
+	else if (bpp <= 1) {
+		bpp = 1;
+		par->hw.falcon.f_shift = 0x400;
+		par->hw.falcon.st_shift = 0x200;
+	}
+	else if (bpp <= 2) {
+		bpp = 2;
+		par->hw.falcon.f_shift = 0x000;
+		par->hw.falcon.st_shift = 0x100;
+	}
+	else if (bpp <= 4) {
+		bpp = 4;
+		par->hw.falcon.f_shift = 0x000;
+		par->hw.falcon.st_shift = 0x000;
+	}
+	else if (bpp <= 8) {
+		bpp = 8;
+		par->hw.falcon.f_shift = 0x010;
+	}
+	else if (bpp <= 16) {
+		bpp = 16; /* packed pixel mode */
+		par->hw.falcon.f_shift = 0x100; /* hicolor, no overlay */
+	}
+	else
+		return -EINVAL;
+	par->hw.falcon.bpp = bpp;
+
+	if (mon_type == F_MON_SM || DontCalcRes) {
+		/* Skip all calculations. VGA/TV/SC1224 only supported. */
+		struct fb_var_screeninfo *myvar = &atafb_predefined[0];
+		
+		if (bpp > myvar->bits_per_pixel ||
+			var->xres > myvar->xres ||
+			var->yres > myvar->yres)
+			return -EINVAL;
+		fbhw->get_par(par);	/* Current par will be new par */
+		goto set_screen_base;	/* Don't forget this */
+	}
+
+	/* Only some fixed resolutions < 640x400 */
+	if (xres <= 320)
+		xres = 320;
+	else if (xres <= 640 && bpp != 16)
+		xres = 640;
+	if (yres <= 200)
+		yres = 200;
+	else if (yres <= 240)
+		yres = 240;
+	else if (yres <= 400)
+		yres = 400;
+
+	/* 2 planes must use STE compatibility mode */
+	par->hw.falcon.ste_mode = bpp==2;
+	par->hw.falcon.mono = bpp==1;
+
+	/* Total and visible scanline length must be a multiple of one longword,
+	 * this and the console fontwidth yields the alignment for xres and
+	 * xres_virtual.
+	 * TODO: this way "odd" fontheights are not supported
+	 *
+	 * Special case in STE mode: blank and graphic positions don't align,
+	 * avoid trash at right margin
+	 */
+	if (par->hw.falcon.ste_mode)
+		xres = (xres + 63) & ~63;
+	else if (bpp == 1)
+		xres = (xres + 31) & ~31;
+	else
+		xres = (xres + 15) & ~15;
+	if (yres >= 400)
+		yres = (yres + 15) & ~15;
+	else
+		yres = (yres + 7) & ~7;
+
+	if (xres_virtual < xres)
+		xres_virtual = xres;
+	else if (bpp == 1)
+		xres_virtual = (xres_virtual + 31) & ~31;
+	else
+		xres_virtual = (xres_virtual + 15) & ~15;
+
+	if (yres_virtual <= 0)
+		yres_virtual = 0;
+	else if (yres_virtual < yres)
+		yres_virtual = yres;
+
+	/* backward bug-compatibility */
+	if (var->pixclock > 1)
+		var->pixclock -= 1;
+
+	par->hw.falcon.line_width = bpp * xres / 16;
+	par->hw.falcon.line_offset = bpp * (xres_virtual - xres) / 16;
+
+	/* single or double pixel width */
+	xstretch = (xres < 640) ? 2 : 1;
+
+#if 0 /* SM124 supports only 640x400, this is rejected above */
+	if (mon_type == F_MON_SM) {
+		if (xres != 640 && yres != 400)
+			return -EINVAL;
+		plen = 1;
+		pclock = &f32;
+		/* SM124-mode is special */
+		par->hw.falcon.ste_mode = 1;
+		par->hw.falcon.f_shift = 0x000;
+		par->hw.falcon.st_shift = 0x200;
+		left_margin = hsync_len = 128 / plen;
+		right_margin = 0;
+		/* TODO set all margins */
+	}
+	else
+#endif
+	if (mon_type == F_MON_SC || mon_type == F_MON_TV) {
+		plen = 2 * xstretch;
+		if (var->pixclock > f32.t * plen)
+			return -EINVAL;
+		pclock = &f32;
+		if (yres > 240)
+			interlace = 1;
+		if (var->pixclock == 0) {
+			/* set some minimal margins which center the screen */
+			left_margin = 32;
+			right_margin = 18;
+			hsync_len = pclock->hsync / plen;
+			upper_margin = 31;
+			lower_margin = 14;
+			vsync_len = interlace ? 3 : 4;
+		} else {
+			left_margin = var->left_margin;
+			right_margin = var->right_margin;
+			hsync_len = var->hsync_len;
+			upper_margin = var->upper_margin;
+			lower_margin = var->lower_margin;
+			vsync_len = var->vsync_len;
+			if (var->vmode & FB_VMODE_INTERLACED) {
+				upper_margin = (upper_margin + 1) / 2;
+				lower_margin = (lower_margin + 1) / 2;
+				vsync_len = (vsync_len + 1) / 2;
+			} else if (var->vmode & FB_VMODE_DOUBLE) {
+				upper_margin *= 2;
+				lower_margin *= 2;
+				vsync_len *= 2;
+			}
+		}
+	}
+	else
+	{	/* F_MON_VGA */
+		if (bpp == 16)
+			xstretch = 2; /* Double pixel width only for hicolor */
+		/* Default values are used for vert./hor. timing if no pixelclock given. */
+		if (var->pixclock == 0) {
+			int linesize;
+
+			/* Choose master pixelclock depending on hor. timing */
+			plen = 1 * xstretch;
+			if ((plen * xres + f25.right+f25.hsync+f25.left) *
+			    fb_info.monspecs.hfmin < f25.f)
+				pclock = &f25;
+			else if ((plen * xres + f32.right+f32.hsync+f32.left) * 
+			    fb_info.monspecs.hfmin < f32.f)
+				pclock = &f32;
+			else if ((plen * xres + fext.right+fext.hsync+fext.left) * 
+			    fb_info.monspecs.hfmin < fext.f
+			         && fext.f)
+				pclock = &fext;
+			else
+				return -EINVAL;
+
+			left_margin = pclock->left / plen;
+			right_margin = pclock->right / plen;
+			hsync_len = pclock->hsync / plen;
+			linesize = left_margin + xres + right_margin + hsync_len;
+			upper_margin = 31;
+			lower_margin = 11;
+			vsync_len = 3;
+		}
+		else {
+			/* Choose largest pixelclock <= wanted clock */
+			int i;
+			unsigned long pcl = ULONG_MAX;
+			pclock = 0;
+			for (i=1; i <= 4; i *= 2) {
+				if (f25.t*i >= var->pixclock && f25.t*i < pcl) {
+					pcl = f25.t * i;
+					pclock = &f25;
+				}
+				if (f32.t*i >= var->pixclock && f32.t*i < pcl) {
+					pcl = f32.t * i;
+					pclock = &f32;
+				}
+				if (fext.t && fext.t*i >= var->pixclock && fext.t*i < pcl) {
+					pcl = fext.t * i;
+					pclock = &fext;
+				}
+			}
+			if (!pclock)
+				return -EINVAL;
+			plen = pcl / pclock->t;
+
+			left_margin = var->left_margin;
+			right_margin = var->right_margin;
+			hsync_len = var->hsync_len;
+			upper_margin = var->upper_margin;
+			lower_margin = var->lower_margin;
+			vsync_len = var->vsync_len;
+			/* Internal unit is [single lines per (half-)frame] */
+			if (var->vmode & FB_VMODE_INTERLACED) {
+				/* # lines in half frame */
+				/* External unit is [lines per full frame] */
+				upper_margin = (upper_margin + 1) / 2;
+				lower_margin = (lower_margin + 1) / 2;
+				vsync_len = (vsync_len + 1) / 2;
+			}
+			else if (var->vmode & FB_VMODE_DOUBLE) {
+				/* External unit is [double lines per frame] */
+				upper_margin *= 2;
+				lower_margin *= 2;
+				vsync_len *= 2;
+			}
+		}
+		if (pclock == &fext)
+			longoffset = 1; /* VIDEL doesn't synchronize on short offset */
+	}
+	/* Is video bus bandwidth (32MB/s) too low for this resolution? */
+	/* this is definitely wrong if bus clock != 32MHz */
+	if (pclock->f / plen / 8 * bpp > 32000000L)
+		return -EINVAL;
+
+	if (vsync_len < 1)
+		vsync_len = 1;
+
+	/* include sync lengths in right/lower margin for all calculations */
+	right_margin += hsync_len;
+	lower_margin += vsync_len;
+
+	/* ! In all calculations of margins we use # of lines in half frame
+	 * (which is a full frame in non-interlace mode), so we can switch
+	 * between interlace and non-interlace without messing around
+	 * with these.
+	 */
+  again:
+	/* Set base_offset 128 and video bus width */
+	par->hw.falcon.vid_control = mon_type | f030_bus_width;
+	if (!longoffset)
+		par->hw.falcon.vid_control |= VCO_SHORTOFFS;	/* base_offset 64 */
+	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+		par->hw.falcon.vid_control |= VCO_HSYPOS;
+	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+		par->hw.falcon.vid_control |= VCO_VSYPOS;
+	/* Pixelclock */
+	par->hw.falcon.vid_control |= pclock->control_mask;
+	/* External or internal clock */
+	par->hw.falcon.sync = pclock->sync_mask | 0x2;
+	/* Pixellength and prescale */
+	par->hw.falcon.vid_mode = (2/plen) << 2;
+	if (doubleline)
+		par->hw.falcon.vid_mode |= VMO_DOUBLE;
+	if (interlace)
+		par->hw.falcon.vid_mode |= VMO_INTER;
+
+	/*********************
+	Horizontal timing: unit = [master clock cycles]
+	unit of hxx-registers: [master clock cycles * prescale]
+	Hxx-registers are 9 bit wide
+
+	1 line = ((hht + 2) * 2 * prescale) clock cycles
+
+	graphic output = hdb & 0x200 ?
+	       ((hht+2)*2 - hdb + hde) * prescale - hdboff + hdeoff:
+	       ( hht + 2  - hdb + hde) * prescale - hdboff + hdeoff
+	(this must be a multiple of plen*128/bpp, on VGA pixels
+	 to the right may be cut off with a bigger right margin)
+
+	start of graphics relative to start of 1st halfline = hdb & 0x200 ?
+	       (hdb - hht - 2) * prescale + hdboff :
+	       hdb * prescale + hdboff
+
+	end of graphics relative to start of 1st halfline =
+	       (hde + hht + 2) * prescale + hdeoff
+	*********************/
+	/* Calculate VIDEL registers */
+	{
+	int hdb_off, hde_off, base_off;
+	int gstart, gend1, gend2, align;
+
+	prescale = hxx_prescale(&par->hw.falcon);
+	base_off = par->hw.falcon.vid_control & VCO_SHORTOFFS ? 64 : 128;
+
+	/* Offsets depend on video mode */
+	/* Offsets are in clock cycles, divide by prescale to
+	 * calculate hd[be]-registers
+	 */
+	if (par->hw.falcon.f_shift & 0x100) {
+		align = 1;
+		hde_off = 0;
+		hdb_off = (base_off + 16 * plen) + prescale;
+	}
+	else {
+		align = 128 / bpp;
+		hde_off = ((128 / bpp + 2) * plen);
+		if (par->hw.falcon.ste_mode)
+			hdb_off = (64 + base_off + (128 / bpp + 2) * plen) + prescale;
+		else
+			hdb_off = (base_off + (128 / bpp + 18) * plen) + prescale;
+	}
+
+	gstart = (prescale/2 + plen * left_margin) / prescale;
+	/* gend1 is for hde (gend-gstart multiple of align), shifter's xres */
+	gend1 = gstart + ((xres + align-1) / align)*align * plen / prescale;
+	/* gend2 is for hbb, visible xres (rest to gend1 is cut off by hblank) */
+	gend2 = gstart + xres * plen / prescale;
+	par->HHT = plen * (left_margin + xres + right_margin) /
+			   (2 * prescale) - 2;
+/*	par->HHT = (gend2 + plen * right_margin / prescale) / 2 - 2;*/
+
+	par->HDB = gstart - hdb_off/prescale;
+	par->HBE = gstart;
+	if (par->HDB < 0) par->HDB += par->HHT + 2 + 0x200;
+	par->HDE = gend1 - par->HHT - 2 - hde_off/prescale;
+	par->HBB = gend2 - par->HHT - 2;
+#if 0
+	/* One more Videl constraint: data fetch of two lines must not overlap */
+	if ((par->HDB & 0x200)  &&  (par->HDB & ~0x200) - par->HDE <= 5) {
+		/* if this happens increase margins, decrease hfreq. */
+	}
+#endif
+	if (hde_off % prescale)
+		par->HBB++;		/* compensate for non matching hde and hbb */
+	par->HSS = par->HHT + 2 - plen * hsync_len / prescale;
+	if (par->HSS < par->HBB)
+		par->HSS = par->HBB;
+	}
+
+	/*  check hor. frequency */
+	hfreq = pclock->f / ((par->HHT+2)*prescale*2);
+	if (hfreq > fb_info.monspecs.hfmax && mon_type!=F_MON_VGA) {
+		/* ++guenther:   ^^^^^^^^^^^^^^^^^^^ can't remember why I did this */
+		/* Too high -> enlarge margin */
+		left_margin += 1;
+		right_margin += 1;
+		goto again;
+	}
+	if (hfreq > fb_info.monspecs.hfmax || hfreq < fb_info.monspecs.hfmin)
+		return -EINVAL;
+
+	/* Vxx-registers */
+	/* All Vxx must be odd in non-interlace, since frame starts in the middle
+	 * of the first displayed line!
+	 * One frame consists of VFT+1 half lines. VFT+1 must be even in
+	 * non-interlace, odd in interlace mode for synchronisation.
+	 * Vxx-registers are 11 bit wide
+	 */
+	par->VBE = (upper_margin * 2 + 1); /* must begin on odd halfline */
+	par->VDB = par->VBE;
+	par->VDE = yres;
+	if (!interlace) par->VDE <<= 1;
+	if (doubleline) par->VDE <<= 1;  /* VDE now half lines per (half-)frame */
+	par->VDE += par->VDB;
+	par->VBB = par->VDE;
+	par->VFT = par->VBB + (lower_margin * 2 - 1) - 1;
+	par->VSS = par->VFT+1 - (vsync_len * 2 - 1);
+	/* vbb,vss,vft must be even in interlace mode */
+	if (interlace) {
+		par->VBB++;
+		par->VSS++;
+		par->VFT++;
+	}
+
+	/* V-frequency check, hope I didn't create any loop here. */
+	/* Interlace and doubleline are mutually exclusive. */
+	vfreq = (hfreq * 2) / (par->VFT + 1);
+	if      (vfreq > fb_info.monspecs.vfmax && !doubleline && !interlace) {
+		/* Too high -> try again with doubleline */
+		doubleline = 1;
+		goto again;
+	}
+	else if (vfreq < fb_info.monspecs.vfmin && !interlace && !doubleline) {
+		/* Too low -> try again with interlace */
+		interlace = 1;
+		goto again;
+	}
+	else if (vfreq < fb_info.monspecs.vfmin && doubleline) {
+		/* Doubleline too low -> clear doubleline and enlarge margins */
+		int lines;
+		doubleline = 0;
+		for (lines=0;
+		     (hfreq*2)/(par->VFT+1+4*lines-2*yres)>fb_info.monspecs.vfmax;
+		     lines++)
+			;
+		upper_margin += lines;
+		lower_margin += lines;
+		goto again;
+	}
+	else if (vfreq > fb_info.monspecs.vfmax && doubleline) {
+		/* Doubleline too high -> enlarge margins */
+		int lines;
+		for (lines=0;
+		     (hfreq*2)/(par->VFT+1+4*lines)>fb_info.monspecs.vfmax;
+		     lines+=2)
+			;
+		upper_margin += lines;
+		lower_margin += lines;
+		goto again;
+	}
+	else if (vfreq > fb_info.monspecs.vfmax && interlace) {
+		/* Interlace, too high -> enlarge margins */
+		int lines;
+		for (lines=0;
+		     (hfreq*2)/(par->VFT+1+4*lines)>fb_info.monspecs.vfmax;
+		     lines++)
+			;
+		upper_margin += lines;
+		lower_margin += lines;
+		goto again;
+	}
+	else if (vfreq < fb_info.monspecs.vfmin ||
+		 vfreq > fb_info.monspecs.vfmax)
+		return -EINVAL;
+
+  set_screen_base:
+	linelen = xres_virtual * bpp / 8;
+	if (yres_virtual * linelen > screen_len && screen_len)
+		return -EINVAL;
+	if (yres * linelen > screen_len && screen_len)
+		return -EINVAL;
+	if (var->yoffset + yres > yres_virtual && yres_virtual)
+		return -EINVAL;
+	par->yres_virtual = yres_virtual;
+	par->screen_base = screen_base + var->yoffset * linelen;
+	par->hw.falcon.xoffset = 0;
+
+	return 0;
+}
+
+static int falcon_encode_var( struct fb_var_screeninfo *var,
+							  struct atafb_par *par )
+{
+/* !!! only for VGA !!! */
+	int linelen;
+	int prescale, plen;
+	int hdb_off, hde_off, base_off;
+	struct falcon_hw *hw = &par->hw.falcon;
+
+	memset(var, 0, sizeof(struct fb_var_screeninfo));
+	/* possible frequencies: 25.175 or 32MHz */
+	var->pixclock = hw->sync & 0x1 ? fext.t :
+	                hw->vid_control & VCO_CLOCK25 ? f25.t : f32.t;
+
+	var->height=-1;
+	var->width=-1;
+
+	var->sync=0;
+	if (hw->vid_control & VCO_HSYPOS)
+		var->sync |= FB_SYNC_HOR_HIGH_ACT;
+	if (hw->vid_control & VCO_VSYPOS)
+		var->sync |= FB_SYNC_VERT_HIGH_ACT;
+
+	var->vmode = FB_VMODE_NONINTERLACED;
+	if (hw->vid_mode & VMO_INTER)
+		var->vmode |= FB_VMODE_INTERLACED;
+	if (hw->vid_mode & VMO_DOUBLE)
+		var->vmode |= FB_VMODE_DOUBLE;
+	
+	/* visible y resolution:
+	 * Graphics display starts at line VDB and ends at line
+	 * VDE. If interlace mode off unit of VC-registers is
+	 * half lines, else lines.
+	 */
+	var->yres = hw->vde - hw->vdb;
+	if (!(var->vmode & FB_VMODE_INTERLACED))
+		var->yres >>= 1;
+	if (var->vmode & FB_VMODE_DOUBLE)
+		var->yres >>= 1;
+
+	/* to get bpp, we must examine f_shift and st_shift.
+	 * f_shift is valid if any of bits no. 10, 8 or 4
+	 * is set. Priority in f_shift is: 10 ">" 8 ">" 4, i.e.
+	 * if bit 10 set then bit 8 and bit 4 don't care...
+	 * If all these bits are 0 get display depth from st_shift
+	 * (as for ST and STE)
+	 */
+	if (hw->f_shift & 0x400)		/* 2 colors */
+		var->bits_per_pixel = 1;
+	else if (hw->f_shift & 0x100)	/* hicolor */
+		var->bits_per_pixel = 16;
+	else if (hw->f_shift & 0x010)	/* 8 bitplanes */
+		var->bits_per_pixel = 8;
+	else if (hw->st_shift == 0)
+		var->bits_per_pixel = 4;
+	else if (hw->st_shift == 0x100)
+		var->bits_per_pixel = 2;
+	else /* if (hw->st_shift == 0x200) */
+		var->bits_per_pixel = 1;
+
+	var->xres = hw->line_width * 16 / var->bits_per_pixel;
+	var->xres_virtual = var->xres + hw->line_offset * 16 / var->bits_per_pixel;
+	if (hw->xoffset)
+		var->xres_virtual += 16;
+
+	if (var->bits_per_pixel == 16) {
+		var->red.offset=11;
+		var->red.length=5;
+		var->red.msb_right=0;
+		var->green.offset=5;
+		var->green.length=6;
+		var->green.msb_right=0;
+		var->blue.offset=0;
+		var->blue.length=5;
+		var->blue.msb_right=0;
+	}
+	else {
+		var->red.offset=0;
+		var->red.length = hw->ste_mode ? 4 : 6;
+		var->red.msb_right=0;
+		var->grayscale=0;
+		var->blue=var->green=var->red;
+	}
+	var->transp.offset=0;
+	var->transp.length=0;
+	var->transp.msb_right=0;
+
+	linelen = var->xres_virtual * var->bits_per_pixel / 8;
+	if (screen_len) {
+		if (par->yres_virtual)
+			var->yres_virtual = par->yres_virtual;
+		else
+			/* yres_virtual==0 means use maximum */
+			var->yres_virtual = screen_len / linelen;
+	}
+	else {
+		if (hwscroll < 0)
+			var->yres_virtual = 2 * var->yres;
+		else
+			var->yres_virtual=var->yres+hwscroll * 16;
+	}
+	var->xoffset=0; /* TODO change this */
+
+	/* hdX-offsets */
+	prescale = hxx_prescale(hw);
+	plen = 4 >> (hw->vid_mode >> 2 & 0x3);
+	base_off = hw->vid_control & VCO_SHORTOFFS ? 64 : 128;
+	if (hw->f_shift & 0x100) {
+		hde_off = 0;
+		hdb_off = (base_off + 16 * plen) + prescale;
+	}
+	else {
+		hde_off = ((128 / var->bits_per_pixel + 2) * plen);
+		if (hw->ste_mode)
+			hdb_off = (64 + base_off + (128 / var->bits_per_pixel + 2) * plen)
+					 + prescale;
+		else
+			hdb_off = (base_off + (128 / var->bits_per_pixel + 18) * plen)
+					 + prescale;
+	}
+
+	/* Right margin includes hsync */
+	var->left_margin = hdb_off + prescale * ((hw->hdb & 0x1ff) -
+					   (hw->hdb & 0x200 ? 2+hw->hht : 0));
+	if (hw->ste_mode || mon_type!=F_MON_VGA)
+		var->right_margin = prescale * (hw->hht + 2 - hw->hde) - hde_off;
+	else
+		/* can't use this in ste_mode, because hbb is +1 off */
+		var->right_margin = prescale * (hw->hht + 2 - hw->hbb);
+	var->hsync_len = prescale * (hw->hht + 2 - hw->hss);
+
+	/* Lower margin includes vsync */
+	var->upper_margin = hw->vdb / 2 ;  /* round down to full lines */
+	var->lower_margin = (hw->vft+1 - hw->vde + 1) / 2; /* round up */
+	var->vsync_len    = (hw->vft+1 - hw->vss + 1) / 2; /* round up */
+	if (var->vmode & FB_VMODE_INTERLACED) {
+		var->upper_margin *= 2;
+		var->lower_margin *= 2;
+		var->vsync_len *= 2;
+	}
+	else if (var->vmode & FB_VMODE_DOUBLE) {
+		var->upper_margin = (var->upper_margin + 1) / 2;
+		var->lower_margin = (var->lower_margin + 1) / 2;
+		var->vsync_len = (var->vsync_len + 1) / 2;
+	}
+
+	var->pixclock *= plen;
+	var->left_margin /= plen;
+	var->right_margin /= plen;
+	var->hsync_len /= plen;
+
+	var->right_margin -= var->hsync_len;
+	var->lower_margin -= var->vsync_len;
+
+	if (screen_base)
+		var->yoffset=(par->screen_base - screen_base)/linelen;
+	else
+		var->yoffset=0;
+	var->nonstd=0;	/* what is this for? */
+	var->activate=0;
+	return 0;
+}
+
+
+static int f_change_mode = 0;
+static struct falcon_hw f_new_mode;
+static int f_pan_display = 0;
+
+static void falcon_get_par( struct atafb_par *par )
+{
+	unsigned long addr;
+	struct falcon_hw *hw = &par->hw.falcon;
+
+	hw->line_width = shifter_f030.scn_width;
+	hw->line_offset = shifter_f030.off_next;
+	hw->st_shift = videl.st_shift & 0x300;
+	hw->f_shift = videl.f_shift;
+	hw->vid_control = videl.control;
+	hw->vid_mode = videl.mode;
+	hw->sync = shifter.syncmode & 0x1;
+	hw->xoffset = videl.xoffset & 0xf;
+	hw->hht = videl.hht;
+	hw->hbb = videl.hbb;
+	hw->hbe = videl.hbe;
+	hw->hdb = videl.hdb;
+	hw->hde = videl.hde;
+	hw->hss = videl.hss;
+	hw->vft = videl.vft;
+	hw->vbb = videl.vbb;
+	hw->vbe = videl.vbe;
+	hw->vdb = videl.vdb;
+	hw->vde = videl.vde;
+	hw->vss = videl.vss;
+
+	addr = (shifter.bas_hi & 0xff) << 16 |
+	       (shifter.bas_md & 0xff) << 8  |
+	       (shifter.bas_lo & 0xff);
+	par->screen_base = phys_to_virt(addr);
+
+	/* derived parameters */
+	hw->ste_mode = (hw->f_shift & 0x510)==0 && hw->st_shift==0x100;
+	hw->mono = (hw->f_shift & 0x400) ||
+	           ((hw->f_shift & 0x510)==0 && hw->st_shift==0x200);
+}
+
+static void falcon_set_par( struct atafb_par *par )
+{
+	f_change_mode = 0;
+
+	/* only set screen_base if really necessary */
+	if (current_par.screen_base != par->screen_base)
+		fbhw->set_screen_base(par->screen_base);
+
+	/* Don't touch any other registers if we keep the default resolution */
+	if (DontCalcRes)
+		return;
+
+	/* Tell vbl-handler to change video mode.
+	 * We change modes only on next VBL, to avoid desynchronisation
+	 * (a shift to the right and wrap around by a random number of pixels
+	 * in all monochrome modes).
+	 * This seems to work on my Falcon.
+	 */
+	f_new_mode = par->hw.falcon;
+	f_change_mode = 1;
+}
+
+
+static irqreturn_t falcon_vbl_switcher( int irq, void *dummy, struct pt_regs *fp )
+{
+	struct falcon_hw *hw = &f_new_mode;
+
+	if (f_change_mode) {
+		f_change_mode = 0;
+
+		if (hw->sync & 0x1) {
+			/* Enable external pixelclock. This code only for ScreenWonder */
+			*(volatile unsigned short*)0xffff9202 = 0xffbf;
+		}
+		else {
+			/* Turn off external clocks. Read sets all output bits to 1. */
+			*(volatile unsigned short*)0xffff9202;
+		}
+		shifter.syncmode = hw->sync;
+
+		videl.hht = hw->hht;
+		videl.hbb = hw->hbb;
+		videl.hbe = hw->hbe;
+		videl.hdb = hw->hdb;
+		videl.hde = hw->hde;
+		videl.hss = hw->hss;
+		videl.vft = hw->vft;
+		videl.vbb = hw->vbb;
+		videl.vbe = hw->vbe;
+		videl.vdb = hw->vdb;
+		videl.vde = hw->vde;
+		videl.vss = hw->vss;
+
+		videl.f_shift = 0; /* write enables Falcon palette, 0: 4 planes */
+		if (hw->ste_mode) {
+			videl.st_shift = hw->st_shift; /* write enables STE palette */
+		}
+		else {
+			/* IMPORTANT:
+			 * set st_shift 0, so we can tell the screen-depth if f_shift==0.
+			 * Writing 0 to f_shift enables 4 plane Falcon mode but
+			 * doesn't set st_shift. st_shift!=0 (!=4planes) is impossible
+			 * with Falcon palette.
+			 */
+			videl.st_shift = 0;
+			/* now back to Falcon palette mode */
+			videl.f_shift = hw->f_shift;
+		}
+		/* writing to st_shift changed scn_width and vid_mode */
+		videl.xoffset = hw->xoffset;
+		shifter_f030.scn_width = hw->line_width;
+		shifter_f030.off_next = hw->line_offset;
+		videl.control = hw->vid_control;
+		videl.mode = hw->vid_mode;
+	}
+	if (f_pan_display) {
+		f_pan_display = 0;
+		videl.xoffset = current_par.hw.falcon.xoffset;
+		shifter_f030.off_next = current_par.hw.falcon.line_offset;
+	}
+	return IRQ_HANDLED;
+}
+
+
+static int falcon_pan_display( struct fb_var_screeninfo *var,
+							   struct atafb_par *par )
+{
+	int xoffset;
+	int bpp = fb_display[fb_info.currcon].var.bits_per_pixel;
+
+	if (bpp == 1)
+		var->xoffset = up(var->xoffset, 32);
+	if (bpp != 16)
+		par->hw.falcon.xoffset = var->xoffset & 15;
+	else {
+		par->hw.falcon.xoffset = 0;
+		var->xoffset = up(var->xoffset, 2);
+	}
+	par->hw.falcon.line_offset = bpp *
+	       	(fb_display[fb_info.currcon].var.xres_virtual - fb_display[fb_info.currcon].var.xres) / 16;
+	if (par->hw.falcon.xoffset)
+		par->hw.falcon.line_offset -= bpp;
+	xoffset = var->xoffset - par->hw.falcon.xoffset;
+
+	par->screen_base = screen_base +
+	        (var->yoffset * fb_display[fb_info.currcon].var.xres_virtual + xoffset) * bpp / 8;
+	if (fbhw->set_screen_base)
+		fbhw->set_screen_base (par->screen_base);
+	else
+		return -EINVAL; /* shouldn't happen */
+	f_pan_display = 1;
+	return 0;
+}
+
+
+static int falcon_getcolreg( unsigned regno, unsigned *red,
+				 unsigned *green, unsigned *blue,
+				 unsigned *transp, struct fb_info *info )
+{	unsigned long col;
+	
+	if (regno > 255)
+		return 1;
+	/* This works in STE-mode (with 4bit/color) since f030_col-registers
+	 * hold up to 6bit/color.
+	 * Even with hicolor r/g/b=5/6/5 bit!
+	 */
+	col = f030_col[regno];
+	*red = (col >> 16) & 0xff00;
+	*green = (col >> 8) & 0xff00;
+	*blue = (col << 8) & 0xff00;
+	*transp = 0;
+	return 0;
+}
+
+
+static int falcon_setcolreg( unsigned regno, unsigned red,
+							 unsigned green, unsigned blue,
+							 unsigned transp, struct fb_info *info )
+{
+	if (regno > 255)
+		return 1;
+	f030_col[regno] = (((red & 0xfc00) << 16) |
+			   ((green & 0xfc00) << 8) |
+			   ((blue & 0xfc00) >> 8));
+	if (regno < 16) {
+		shifter_tt.color_reg[regno] =
+			(((red & 0xe000) >> 13) | ((red & 0x1000) >> 12) << 8) |
+			(((green & 0xe000) >> 13) | ((green & 0x1000) >> 12) << 4) |
+			((blue & 0xe000) >> 13) | ((blue & 0x1000) >> 12);
+#ifdef FBCON_HAS_CFB16
+		fbcon_cfb16_cmap[regno] = ((red & 0xf800) |
+					   ((green & 0xfc00) >> 5) |
+					   ((blue & 0xf800) >> 11));
+#endif
+	}
+	return 0;
+}
+
+
+static int falcon_blank( int blank_mode )
+{
+/* ++guenther: we can switch off graphics by changing VDB and VDE,
+ * so VIDEL doesn't hog the bus while saving.
+ * (this may affect usleep()).
+ */
+	int vdb, vss, hbe, hss;
+
+	if (mon_type == F_MON_SM)	/* this doesn't work on SM124 */
+		return 1;
+
+	vdb = current_par.VDB;
+	vss = current_par.VSS;
+	hbe = current_par.HBE;
+	hss = current_par.HSS;
+
+	if (blank_mode >= 1) {
+		/* disable graphics output (this speeds up the CPU) ... */
+		vdb = current_par.VFT + 1;
+		/* ... and blank all lines */
+		hbe = current_par.HHT + 2;
+	}
+	/* use VESA suspend modes on VGA monitors */
+	if (mon_type == F_MON_VGA) {
+		if (blank_mode == 2 || blank_mode == 4)
+			vss = current_par.VFT + 1;
+		if (blank_mode == 3 || blank_mode == 4)
+			hss = current_par.HHT + 2;
+	}
+
+	videl.vdb = vdb;
+	videl.vss = vss;
+	videl.hbe = hbe;
+	videl.hss = hss;
+
+	return 0;
+}
+
+ 
+static int falcon_detect( void )
+{
+	struct atafb_par par;
+	unsigned char fhw;
+
+	/* Determine connected monitor and set monitor parameters */
+	fhw = *(unsigned char*)0xffff8006;
+	mon_type = fhw >> 6 & 0x3;
+	/* bit 1 of fhw: 1=32 bit ram bus, 0=16 bit */
+	f030_bus_width = fhw << 6 & 0x80;
+	switch (mon_type) {
+	case F_MON_SM:
+		fb_info.monspecs.vfmin = 70;
+		fb_info.monspecs.vfmax = 72;
+		fb_info.monspecs.hfmin = 35713;
+		fb_info.monspecs.hfmax = 35715;
+		break;
+	case F_MON_SC:
+	case F_MON_TV:
+		/* PAL...NTSC */
+		fb_info.monspecs.vfmin = 49; /* not 50, since TOS defaults to 49.9x Hz */
+		fb_info.monspecs.vfmax = 60;
+		fb_info.monspecs.hfmin = 15620;
+		fb_info.monspecs.hfmax = 15755;
+		break;
+	}
+	/* initialize hsync-len */
+	f25.hsync = h_syncs[mon_type] / f25.t;
+	f32.hsync = h_syncs[mon_type] / f32.t;
+	if (fext.t)
+		fext.hsync = h_syncs[mon_type] / fext.t;
+
+	falcon_get_par(&par);
+	falcon_encode_var(&atafb_predefined[0], &par);
+
+	/* Detected mode is always the "autodetect" slot */
+	return 1;
+}
+
+#endif /* ATAFB_FALCON */
+
+/* ------------------- ST(E) specific functions ---------------------- */
+
+#ifdef ATAFB_STE
+
+static int stste_encode_fix( struct fb_fix_screeninfo *fix,
+							 struct atafb_par *par )
+
+{
+	int mode;
+
+	strcpy(fix->id,"Atari Builtin");
+	fix->smem_start = (unsigned long)real_screen_base;
+	fix->smem_len = screen_len;
+	fix->type = FB_TYPE_INTERLEAVED_PLANES;
+	fix->type_aux = 2;
+	fix->visual = FB_VISUAL_PSEUDOCOLOR;
+	mode = par->hw.st.mode & 3;
+	if (mode == ST_HIGH) {
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->type_aux = 0;
+		fix->visual = FB_VISUAL_MONO10;
+	}
+	if (ATARIHW_PRESENT(EXTD_SHIFTER)) {
+		fix->xpanstep = 16;
+		fix->ypanstep = 1;
+	} else {
+		fix->xpanstep = 0;
+		fix->ypanstep = 0;
+	}
+	fix->ywrapstep = 0;
+	fix->line_length = 0;
+	fix->accel = FB_ACCEL_ATARIBLITT;
+	return 0;
+}
+
+
+static int stste_decode_var( struct fb_var_screeninfo *var,
+						  struct atafb_par *par )
+{
+	int xres=var->xres;
+	int yres=var->yres;
+	int bpp=var->bits_per_pixel;
+	int linelen;
+	int yres_virtual = var->yres_virtual;
+
+	if (mono_moni) {
+		if (bpp > 1 || xres > sttt_xres || yres > st_yres)
+			return -EINVAL;
+		par->hw.st.mode=ST_HIGH;
+		xres=sttt_xres;
+		yres=st_yres;
+		bpp=1;
+	} else {
+		if (bpp > 4 || xres > sttt_xres || yres > st_yres)
+			return -EINVAL;
+		if (bpp > 2) {
+			if (xres > sttt_xres/2 || yres > st_yres/2)
+				return -EINVAL;
+			par->hw.st.mode=ST_LOW;
+			xres=sttt_xres/2;
+			yres=st_yres/2;
+			bpp=4;
+		}
+		else if (bpp > 1) {
+			if (xres > sttt_xres || yres > st_yres/2)
+				return -EINVAL;
+			par->hw.st.mode=ST_MID;
+			xres=sttt_xres;
+			yres=st_yres/2;
+			bpp=2;
+		}
+		else
+			return -EINVAL;
+	}
+	if (yres_virtual <= 0)
+		yres_virtual = 0;
+	else if (yres_virtual < yres)
+		yres_virtual = yres;
+	if (var->sync & FB_SYNC_EXT)
+		par->hw.st.sync=(par->hw.st.sync & ~1) | 1;
+	else
+		par->hw.st.sync=(par->hw.st.sync & ~1);
+	linelen=xres*bpp/8;
+	if (yres_virtual * linelen > screen_len && screen_len)
+		return -EINVAL;
+	if (yres * linelen > screen_len && screen_len)
+		return -EINVAL;
+	if (var->yoffset + yres > yres_virtual && yres_virtual)
+		return -EINVAL;
+	par->yres_virtual = yres_virtual;
+	par->screen_base=screen_base+ var->yoffset*linelen;
+	return 0;
+}
+
+static int stste_encode_var( struct fb_var_screeninfo *var,
+						  struct atafb_par *par )
+{
+	int linelen;
+	memset(var, 0, sizeof(struct fb_var_screeninfo));
+	var->red.offset=0;
+	var->red.length = ATARIHW_PRESENT(EXTD_SHIFTER) ? 4 : 3;
+	var->red.msb_right=0;
+	var->grayscale=0;
+
+	var->pixclock=31041;
+	var->left_margin=120;		/* these are incorrect */
+	var->right_margin=100;
+	var->upper_margin=8;
+	var->lower_margin=16;
+	var->hsync_len=140;
+	var->vsync_len=30;
+
+	var->height=-1;
+	var->width=-1;
+
+	if (!(par->hw.st.sync & 1))
+		var->sync=0;
+	else
+		var->sync=FB_SYNC_EXT;
+
+	switch (par->hw.st.mode & 3) {
+	case ST_LOW:
+		var->xres=sttt_xres/2;
+		var->yres=st_yres/2;
+		var->bits_per_pixel=4;
+		break;
+	case ST_MID:
+		var->xres=sttt_xres;
+		var->yres=st_yres/2;
+		var->bits_per_pixel=2;
+		break;
+	case ST_HIGH:
+		var->xres=sttt_xres;
+		var->yres=st_yres;
+		var->bits_per_pixel=1;
+		break;
+	}		
+	var->blue=var->green=var->red;
+	var->transp.offset=0;
+	var->transp.length=0;
+	var->transp.msb_right=0;
+	var->xres_virtual=sttt_xres_virtual;
+	linelen=var->xres_virtual * var->bits_per_pixel / 8;
+	ovsc_addlen=linelen*(sttt_yres_virtual - st_yres);
+	
+	if (! use_hwscroll)
+		var->yres_virtual=var->yres;
+	else if (screen_len) {
+		if (par->yres_virtual)
+			var->yres_virtual = par->yres_virtual;
+		else
+			/* yres_virtual==0 means use maximum */
+			var->yres_virtual = screen_len / linelen;
+	}
+	else {
+		if (hwscroll < 0)
+			var->yres_virtual = 2 * var->yres;
+		else
+			var->yres_virtual=var->yres+hwscroll * 16;
+	}
+	var->xoffset=0;
+	if (screen_base)
+		var->yoffset=(par->screen_base - screen_base)/linelen;
+	else
+		var->yoffset=0;
+	var->nonstd=0;
+	var->activate=0;
+	var->vmode=FB_VMODE_NONINTERLACED;
+	return 0;
+}
+
+
+static void stste_get_par( struct atafb_par *par )
+{
+	unsigned long addr;
+	par->hw.st.mode=shifter_tt.st_shiftmode;
+	par->hw.st.sync=shifter.syncmode;
+	addr = ((shifter.bas_hi & 0xff) << 16) |
+	       ((shifter.bas_md & 0xff) << 8);
+	if (ATARIHW_PRESENT(EXTD_SHIFTER))
+		addr |= (shifter.bas_lo & 0xff);
+	par->screen_base = phys_to_virt(addr);
+}
+
+static void stste_set_par( struct atafb_par *par )
+{
+	shifter_tt.st_shiftmode=par->hw.st.mode;
+	shifter.syncmode=par->hw.st.sync;
+	/* only set screen_base if really necessary */
+	if (current_par.screen_base != par->screen_base)
+		fbhw->set_screen_base(par->screen_base);
+}
+
+
+static int stste_getcolreg(unsigned regno, unsigned *red,
+			   unsigned *green, unsigned *blue,
+			   unsigned *transp, struct fb_info *info)
+{
+	unsigned col, t;
+	
+	if (regno > 15)
+		return 1;
+	col = shifter_tt.color_reg[regno];
+	if (ATARIHW_PRESENT(EXTD_SHIFTER)) {
+		t = ((col >> 7) & 0xe) | ((col >> 11) & 1);
+		t |= t << 4;
+		*red = t | (t << 8);
+		t = ((col >> 3) & 0xe) | ((col >> 7) & 1);
+		t |= t << 4;
+		*green = t | (t << 8);
+		t = ((col << 1) & 0xe) | ((col >> 3) & 1);
+		t |= t << 4;
+		*blue = t | (t << 8);
+	}
+	else {
+		t = (col >> 7) & 0xe;
+		t |= t << 4;
+		*red = t | (t << 8);
+		t = (col >> 3) & 0xe;
+		t |= t << 4;
+		*green = t | (t << 8);
+		t = (col << 1) & 0xe;
+		t |= t << 4;
+		*blue = t | (t << 8);
+	}
+	*transp = 0;
+	return 0;
+}
+
+
+static int stste_setcolreg(unsigned regno, unsigned red,
+			   unsigned green, unsigned blue,
+			   unsigned transp, struct fb_info *info)
+{
+	if (regno > 15)
+		return 1;
+	red >>= 12;
+	blue >>= 12;
+	green >>= 12;
+	if (ATARIHW_PRESENT(EXTD_SHIFTER))
+		shifter_tt.color_reg[regno] =
+			(((red & 0xe) >> 1) | ((red & 1) << 3) << 8) |
+			(((green & 0xe) >> 1) | ((green & 1) << 3) << 4) |
+			((blue & 0xe) >> 1) | ((blue & 1) << 3);
+	else
+		shifter_tt.color_reg[regno] =
+			((red & 0xe) << 7) |
+			((green & 0xe) << 3) |
+			((blue & 0xe) >> 1);
+	return 0;
+}
+
+						  
+static int stste_detect( void )
+
+{	struct atafb_par par;
+
+	/* Determine the connected monitor: The DMA sound must be
+	 * disabled before reading the MFP GPIP, because the Sound
+	 * Done Signal and the Monochrome Detect are XORed together!
+	 */
+	if (ATARIHW_PRESENT(PCM_8BIT)) {
+		tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+		udelay(20);	/* wait a while for things to settle down */
+	}
+	mono_moni = (mfp.par_dt_reg & 0x80) == 0;
+
+	stste_get_par(&par);
+	stste_encode_var(&atafb_predefined[0], &par);
+
+	if (!ATARIHW_PRESENT(EXTD_SHIFTER))
+		use_hwscroll = 0;
+	return 1;
+}
+
+static void stste_set_screen_base(void *s_base)
+{
+	unsigned long addr;
+	addr= virt_to_phys(s_base);
+	/* Setup Screen Memory */
+	shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16);
+  	shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8);
+	if (ATARIHW_PRESENT(EXTD_SHIFTER))
+		shifter.bas_lo=(unsigned char)  (addr & 0x0000ff);
+}
+
+#endif /* ATAFB_STE */
+
+/* Switching the screen size should be done during vsync, otherwise
+ * the margins may get messed up. This is a well known problem of
+ * the ST's video system.
+ *
+ * Unfortunately there is hardly any way to find the vsync, as the
+ * vertical blank interrupt is no longer in time on machines with
+ * overscan type modifications.
+ *
+ * We can, however, use Timer B to safely detect the black shoulder,
+ * but then we've got to guess an appropriate delay to find the vsync.
+ * This might not work on every machine.
+ *
+ * martin_rogge @ ki.maus.de, 8th Aug 1995
+ */
+
+#define LINE_DELAY  (mono_moni ? 30 : 70)
+#define SYNC_DELAY  (mono_moni ? 1500 : 2000)
+
+/* SWITCH_ACIA may be used for Falcon (ScreenBlaster III internal!) */
+static void st_ovsc_switch(void)
+{
+    unsigned long flags;
+    register unsigned char old, new;
+
+    if (!(atari_switches & ATARI_SWITCH_OVSC_MASK))
+	return;
+    local_irq_save(flags);
+
+    mfp.tim_ct_b = 0x10;
+    mfp.active_edge |= 8;
+    mfp.tim_ct_b = 0;
+    mfp.tim_dt_b = 0xf0;
+    mfp.tim_ct_b = 8;
+    while (mfp.tim_dt_b > 1)	/* TOS does it this way, don't ask why */
+	;
+    new = mfp.tim_dt_b;
+    do {
+	udelay(LINE_DELAY);
+	old = new;
+	new = mfp.tim_dt_b;
+    } while (old != new);
+    mfp.tim_ct_b = 0x10;
+    udelay(SYNC_DELAY);
+
+    if (atari_switches & ATARI_SWITCH_OVSC_IKBD)
+	acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID | ACIA_RIE;
+    if (atari_switches & ATARI_SWITCH_OVSC_MIDI)
+	acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID;
+    if (atari_switches & (ATARI_SWITCH_OVSC_SND6|ATARI_SWITCH_OVSC_SND7)) {
+	sound_ym.rd_data_reg_sel = 14;
+	sound_ym.wd_data = sound_ym.rd_data_reg_sel |
+			   ((atari_switches&ATARI_SWITCH_OVSC_SND6) ? 0x40:0) |
+			   ((atari_switches&ATARI_SWITCH_OVSC_SND7) ? 0x80:0);
+    }
+    local_irq_restore(flags);
+}
+
+/* ------------------- External Video ---------------------- */
+
+#ifdef ATAFB_EXT
+
+static int ext_encode_fix( struct fb_fix_screeninfo *fix,
+						   struct atafb_par *par )
+
+{
+	strcpy(fix->id,"Unknown Extern");
+	fix->smem_start = (unsigned long)external_addr;
+	fix->smem_len = PAGE_ALIGN(external_len);
+	if (external_depth == 1) {
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		/* The letters 'n' and 'i' in the "atavideo=external:" stand
+		 * for "normal" and "inverted", rsp., in the monochrome case */
+		fix->visual =
+			(external_pmode == FB_TYPE_INTERLEAVED_PLANES ||
+			 external_pmode == FB_TYPE_PACKED_PIXELS) ?
+				FB_VISUAL_MONO10 :
+					FB_VISUAL_MONO01;
+	}
+	else {
+		/* Use STATIC if we don't know how to access color registers */
+		int visual = external_vgaiobase ?
+					 FB_VISUAL_PSEUDOCOLOR :
+					 FB_VISUAL_STATIC_PSEUDOCOLOR;
+		switch (external_pmode) {
+		    case -1:              /* truecolor */
+			fix->type=FB_TYPE_PACKED_PIXELS;
+			fix->visual=FB_VISUAL_TRUECOLOR;
+			break;
+		    case FB_TYPE_PACKED_PIXELS:
+			fix->type=FB_TYPE_PACKED_PIXELS;
+			fix->visual=visual;
+			break;
+		    case FB_TYPE_PLANES:
+			fix->type=FB_TYPE_PLANES;
+			fix->visual=visual;
+			break;
+		    case FB_TYPE_INTERLEAVED_PLANES:
+			fix->type=FB_TYPE_INTERLEAVED_PLANES;
+			fix->type_aux=2;
+			fix->visual=visual;
+			break;
+		}
+	}
+	fix->xpanstep = 0;
+	fix->ypanstep = 0;
+	fix->ywrapstep = 0;
+	fix->line_length = 0;
+	return 0;
+}
+
+
+static int ext_decode_var( struct fb_var_screeninfo *var,
+						   struct atafb_par *par )
+{
+	struct fb_var_screeninfo *myvar = &atafb_predefined[0];
+	
+	if (var->bits_per_pixel > myvar->bits_per_pixel ||
+		var->xres > myvar->xres ||
+		var->xres_virtual > myvar->xres_virtual ||
+		var->yres > myvar->yres ||
+		var->xoffset > 0 ||
+		var->yoffset > 0)
+		return -EINVAL;
+	return 0;
+}
+
+
+static int ext_encode_var( struct fb_var_screeninfo *var,
+						   struct atafb_par *par )
+{
+	memset(var, 0, sizeof(struct fb_var_screeninfo));
+	var->red.offset=0;
+	var->red.length=(external_pmode == -1) ? external_depth/3 : 
+			(external_vgaiobase ? external_bitspercol : 0);
+	var->red.msb_right=0;
+	var->grayscale=0;
+
+	var->pixclock=31041;
+	var->left_margin=120;		/* these are surely incorrect 	*/
+	var->right_margin=100;
+	var->upper_margin=8;
+	var->lower_margin=16;
+	var->hsync_len=140;
+	var->vsync_len=30;
+
+	var->height=-1;
+	var->width=-1;
+
+	var->sync=0;
+
+	var->xres = external_xres;
+	var->yres = external_yres;
+	var->xres_virtual = external_xres_virtual;
+	var->bits_per_pixel = external_depth;
+	
+	var->blue=var->green=var->red;
+	var->transp.offset=0;
+	var->transp.length=0;
+	var->transp.msb_right=0;
+	var->yres_virtual=var->yres;
+	var->xoffset=0;
+	var->yoffset=0;
+	var->nonstd=0;
+	var->activate=0;
+	var->vmode=FB_VMODE_NONINTERLACED;
+	return 0;
+}
+
+
+static void ext_get_par( struct atafb_par *par )
+{
+	par->screen_base = external_addr;
+}
+
+static void ext_set_par( struct atafb_par *par )
+{
+}
+
+#define OUTB(port,val) \
+	*((unsigned volatile char *) ((port)+external_vgaiobase))=(val)
+#define INB(port) \
+	(*((unsigned volatile char *) ((port)+external_vgaiobase)))
+#define DACDelay 				\
+	do {					\
+		unsigned char tmp=INB(0x3da);	\
+		tmp=INB(0x3da);			\
+	} while (0)
+
+static int ext_getcolreg( unsigned regno, unsigned *red,
+						  unsigned *green, unsigned *blue,
+						  unsigned *transp, struct fb_info *info )
+{
+	if (! external_vgaiobase)
+		return 1;
+
+	    *red   = ext_color[regno].red;
+	    *green = ext_color[regno].green;
+	    *blue  = ext_color[regno].blue;
+	    *transp=0;
+	    return 0;
+}
+	
+static int ext_setcolreg( unsigned regno, unsigned red,
+						  unsigned green, unsigned blue,
+						  unsigned transp, struct fb_info *info )
+
+{	unsigned char colmask = (1 << external_bitspercol) - 1;
+
+	if (! external_vgaiobase)
+		return 1;
+
+	ext_color[regno].red = red;
+	ext_color[regno].green = green;
+	ext_color[regno].blue = blue;
+
+	switch (external_card_type) {
+	  case IS_VGA:
+	    OUTB(0x3c8, regno);
+	    DACDelay;
+	    OUTB(0x3c9, red & colmask);
+	    DACDelay;
+	    OUTB(0x3c9, green & colmask);
+	    DACDelay;
+	    OUTB(0x3c9, blue & colmask);
+	    DACDelay;
+	    return 0;
+
+	  case IS_MV300:
+	    OUTB((MV300_reg[regno] << 2)+1, red);
+	    OUTB((MV300_reg[regno] << 2)+1, green);
+	    OUTB((MV300_reg[regno] << 2)+1, blue);
+	    return 0;
+
+	  default:
+	    return 1;
+	  }
+}
+	
+
+static int ext_detect( void )
+
+{
+	struct fb_var_screeninfo *myvar = &atafb_predefined[0];
+	struct atafb_par dummy_par;
+
+	myvar->xres = external_xres;
+	myvar->xres_virtual = external_xres_virtual;
+	myvar->yres = external_yres;
+	myvar->bits_per_pixel = external_depth;
+	ext_encode_var(myvar, &dummy_par);
+	return 1;
+}
+
+#endif /* ATAFB_EXT */
+
+/* ------ This is the same for most hardware types -------- */
+
+static void set_screen_base(void *s_base)
+{
+	unsigned long addr;
+	addr= virt_to_phys(s_base);
+	/* Setup Screen Memory */
+	shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16);
+  	shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8);
+  	shifter.bas_lo=(unsigned char)  (addr & 0x0000ff);
+}
+
+
+static int pan_display( struct fb_var_screeninfo *var,
+                        struct atafb_par *par )
+{
+	if (!fbhw->set_screen_base ||
+		(!ATARIHW_PRESENT(EXTD_SHIFTER) && var->xoffset))
+		return -EINVAL;
+	var->xoffset = up(var->xoffset, 16);
+	par->screen_base = screen_base +
+	        (var->yoffset * fb_display[fb_info.currcon].var.xres_virtual + var->xoffset)
+	        * fb_display[fb_info.currcon].var.bits_per_pixel / 8;
+	fbhw->set_screen_base (par->screen_base);
+	return 0;
+}
+
+
+/* ------------ Interfaces to hardware functions ------------ */
+
+
+#ifdef ATAFB_TT
+static struct fb_hwswitch tt_switch = {
+	tt_detect, tt_encode_fix, tt_decode_var, tt_encode_var,
+	tt_get_par, tt_set_par, tt_getcolreg, 
+	set_screen_base, NULL, pan_display
+};
+#endif
+
+#ifdef ATAFB_FALCON
+static struct fb_hwswitch falcon_switch = {
+	falcon_detect, falcon_encode_fix, falcon_decode_var, falcon_encode_var,
+	falcon_get_par, falcon_set_par, falcon_getcolreg,
+	set_screen_base, falcon_blank, falcon_pan_display
+};
+#endif
+
+#ifdef ATAFB_STE
+static struct fb_hwswitch st_switch = {
+	stste_detect, stste_encode_fix, stste_decode_var, stste_encode_var,
+	stste_get_par, stste_set_par, stste_getcolreg,
+	stste_set_screen_base, NULL, pan_display
+};
+#endif
+
+#ifdef ATAFB_EXT
+static struct fb_hwswitch ext_switch = {
+	ext_detect, ext_encode_fix, ext_decode_var, ext_encode_var,
+	ext_get_par, ext_set_par, ext_getcolreg, NULL, NULL, NULL
+};
+#endif
+
+
+
+static void atafb_get_par( struct atafb_par *par )
+{
+	if (current_par_valid) {
+		*par=current_par;
+	}
+	else
+		fbhw->get_par(par);
+}
+
+
+static void atafb_set_par( struct atafb_par *par )
+{
+	fbhw->set_par(par);
+	current_par=*par;
+	current_par_valid=1;
+}
+
+
+
+/* =========================================================== */
+/* ============== Hardware Independent Functions ============= */
+/* =========================================================== */
+
+
+/* used for hardware scrolling */
+
+static int
+fb_update_var(int con, struct fb_info *info)
+{
+	int off=fb_display[con].var.yoffset*fb_display[con].var.xres_virtual*
+			fb_display[con].var.bits_per_pixel>>3;
+
+	current_par.screen_base=screen_base + off;
+
+	if (fbhw->set_screen_base)
+		fbhw->set_screen_base(current_par.screen_base);
+	return 0;
+}
+
+static int
+do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
+{
+	int err,activate;
+	struct atafb_par par;
+	if ((err=fbhw->decode_var(var, &par)))
+		return err;
+	activate=var->activate;
+	if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive)
+		atafb_set_par(&par);
+	fbhw->encode_var(var, &par);
+	var->activate=activate;
+	return 0;
+}
+
+static int
+atafb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
+{
+	struct atafb_par par;
+	if (con == -1)
+		atafb_get_par(&par);
+	else {
+	  int err;
+		if ((err=fbhw->decode_var(&fb_display[con].var,&par)))
+		  return err;
+	}
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+	return fbhw->encode_fix(fix, &par);
+}
+	
+static int
+atafb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+{
+	struct atafb_par par;
+	if (con == -1) {
+		atafb_get_par(&par);
+		fbhw->encode_var(var, &par);
+	}
+	else
+		*var=fb_display[con].var;
+	return 0;
+}
+
+static void
+atafb_set_disp(int con, struct fb_info *info)
+{
+	struct fb_fix_screeninfo fix;
+	struct fb_var_screeninfo var;
+	struct display *display;
+
+	if (con >= 0)
+		display = &fb_display[con];
+	else
+		display = &disp;	/* used during initialization */
+
+	atafb_get_fix(&fix, con, info);
+	atafb_get_var(&var, con, info);
+	if (con == -1)
+		con=0;
+	info->screen_base = (void *)fix.smem_start;
+	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;
+	if (fix.visual != FB_VISUAL_PSEUDOCOLOR &&
+		fix.visual != FB_VISUAL_DIRECTCOLOR)
+		display->can_soft_blank = 0;
+	else
+		display->can_soft_blank = 1;
+	display->inverse =
+	    (fix.visual == FB_VISUAL_MONO01 ? !inverse : inverse);
+	switch (fix.type) {
+	    case FB_TYPE_INTERLEAVED_PLANES:
+		switch (var.bits_per_pixel) {
+#ifdef FBCON_HAS_IPLAN2P2
+		    case 2:
+			display->dispsw = &fbcon_iplan2p2;
+			break;
+#endif
+#ifdef FBCON_HAS_IPLAN2P4
+		    case 4:
+			display->dispsw = &fbcon_iplan2p4;
+			break;
+#endif
+#ifdef FBCON_HAS_IPLAN2P8
+		    case 8:
+			display->dispsw = &fbcon_iplan2p8;
+			break;
+#endif
+		}
+		break;
+	    case FB_TYPE_PACKED_PIXELS:
+		switch (var.bits_per_pixel) {
+#ifdef FBCON_HAS_MFB
+		    case 1:
+			display->dispsw = &fbcon_mfb;
+			break;
+#endif
+#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_cfb16_cmap;
+			break;
+#endif
+		}
+		break;
+	}
+}
+
+static int
+atafb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+{
+	int err,oldxres,oldyres,oldbpp,oldxres_virtual,
+	    oldyres_virtual,oldyoffset;
+	if ((err=do_fb_set_var(var, con==info->currcon)))
+		return err;
+	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+		oldxres=fb_display[con].var.xres;
+		oldyres=fb_display[con].var.yres;
+		oldxres_virtual=fb_display[con].var.xres_virtual;
+		oldyres_virtual=fb_display[con].var.yres_virtual;
+		oldbpp=fb_display[con].var.bits_per_pixel;
+		oldyoffset=fb_display[con].var.yoffset;
+		fb_display[con].var=*var;
+		if (oldxres != var->xres || oldyres != var->yres 
+		    || oldxres_virtual != var->xres_virtual
+		    || oldyres_virtual != var->yres_virtual
+		    || oldbpp != var->bits_per_pixel
+		    || oldyoffset != var->yoffset) {
+			atafb_set_disp(con, info);
+			(*fb_info.changevar)(con);
+			fb_alloc_cmap(&fb_display[con].cmap, 0, 0);
+			do_install_cmap(con, info);
+		}
+	}
+	var->activate=0;
+	return 0;
+}
+
+
+
+static int
+atafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
+{
+	if (con == info->currcon) /* current console ? */
+		return fb_get_cmap(cmap, kspc, fbhw->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;
+}
+
+static int
+atafb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+{
+	int xoffset = var->xoffset;
+	int yoffset = var->yoffset;
+	int err;
+
+	if (   xoffset < 0 || xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual
+	    || yoffset < 0 || yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual)
+		return -EINVAL;
+
+	if (con == info->currcon) {
+		if (fbhw->pan_display) {
+			if ((err = fbhw->pan_display(var, &current_par)))
+				return err;
+		}
+		else
+			return -EINVAL;
+	}
+	fb_display[con].var.xoffset = var->xoffset;
+	fb_display[con].var.yoffset = var->yoffset;
+	return 0;
+}
+
+static int
+atafb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	       unsigned long arg, int con, struct fb_info *info)
+{
+	switch (cmd) {
+#ifdef FBCMD_GET_CURRENTPAR
+	case FBCMD_GET_CURRENTPAR:
+		if (copy_to_user((void *)arg, (void *)&current_par,
+				 sizeof(struct atafb_par)))
+			return -EFAULT;
+		return 0;
+#endif
+#ifdef FBCMD_SET_CURRENTPAR
+	case FBCMD_SET_CURRENTPAR:
+		if (copy_from_user((void *)&current_par, (void *)arg,
+				   sizeof(struct atafb_par)))
+			return -EFAULT;
+		atafb_set_par(&current_par);
+		return 0;
+#endif
+	}
+	return -EINVAL;
+}
+
+/* (un)blank/poweroff
+ * 0 = unblank
+ * 1 = blank
+ * 2 = suspend vsync
+ * 3 = suspend hsync
+ * 4 = off
+ */
+static int 
+atafb_blank(int blank, struct fb_info *info)
+{
+	unsigned short black[16];
+	struct fb_cmap cmap;
+	if (fbhw->blank && !fbhw->blank(blank))
+		return 1;
+	if (blank) {
+		memset(black, 0, 16*sizeof(unsigned short));
+		cmap.red=black;
+		cmap.green=black;
+		cmap.blue=black;
+		cmap.transp=NULL;
+		cmap.start=0;
+		cmap.len=16;
+		fb_set_cmap(&cmap, 1, info);
+	}
+	else
+		do_install_cmap(info->currcon, info);
+	return 0;
+}
+
+static struct fb_ops atafb_ops = {
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	atafb_get_fix,
+	.fb_get_var =	atafb_get_var,
+	.fb_set_var =	atafb_set_var,
+	.fb_get_cmap =	atafb_get_cmap,
+	.fb_set_cmap =	gen_set_cmap,
+	.fb_pan_display =atafb_pan_display,
+	.fb_blank =	atafb_blank,
+	.fb_ioctl =	atafb_ioctl,
+};
+
+static void
+check_default_par( int detected_mode )
+{
+	char default_name[10];
+	int i;
+	struct fb_var_screeninfo var;
+	unsigned long min_mem;
+
+	/* First try the user supplied mode */
+	if (default_par) {
+		var=atafb_predefined[default_par-1];
+		var.activate = FB_ACTIVATE_TEST;
+		if (do_fb_set_var(&var,1))
+			default_par=0;		/* failed */
+	}
+	/* Next is the autodetected one */
+	if (! default_par) {
+		var=atafb_predefined[detected_mode-1]; /* autodetect */
+		var.activate = FB_ACTIVATE_TEST;
+		if (!do_fb_set_var(&var,1))
+			default_par=detected_mode;
+	}
+	/* If that also failed, try some default modes... */
+	if (! default_par) {
+		/* try default1, default2... */
+		for (i=1 ; i < 10 ; i++) {
+			sprintf(default_name,"default%d",i);
+			default_par=get_video_mode(default_name);
+			if (! default_par)
+				panic("can't set default video mode");
+			var=atafb_predefined[default_par-1];
+			var.activate = FB_ACTIVATE_TEST;
+			if (! do_fb_set_var(&var,1))
+				break;	/* ok */
+		}
+	}
+	min_mem=var.xres_virtual * var.yres_virtual * var.bits_per_pixel/8;
+	if (default_mem_req < min_mem)
+		default_mem_req=min_mem;
+}
+
+static int
+atafb_switch(int con, struct fb_info *info)
+{
+	/* 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);
+	info->currcon=con;
+	/* Install new colormap */
+	do_install_cmap(con, info);
+	return 0;
+}
+
+int __init atafb_init(void)
+{
+	int pad;
+	int detected_mode;
+	unsigned long mem_req;
+
+	if (!MACH_IS_ATARI)
+	        return -ENXIO;
+
+	do {
+#ifdef ATAFB_EXT
+		if (external_addr) {
+			fbhw = &ext_switch;
+			atafb_ops.fb_setcolreg = &ext_setcolreg;
+			break;
+		}
+#endif
+#ifdef ATAFB_TT
+		if (ATARIHW_PRESENT(TT_SHIFTER)) {
+			fbhw = &tt_switch;
+			atafb_ops.fb_setcolreg = &tt_setcolreg;
+			break;
+		}
+#endif
+#ifdef ATAFB_FALCON
+		if (ATARIHW_PRESENT(VIDEL_SHIFTER)) {
+			fbhw = &falcon_switch;
+			atafb_ops.fb_setcolreg = &falcon_setcolreg;
+			request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO,
+			            "framebuffer/modeswitch", falcon_vbl_switcher);
+			break;
+		}
+#endif
+#ifdef ATAFB_STE
+		if (ATARIHW_PRESENT(STND_SHIFTER) ||
+		    ATARIHW_PRESENT(EXTD_SHIFTER)) {
+			fbhw = &st_switch;
+			atafb_ops.fb_setcolreg = &stste_setcolreg;
+			break;
+		}
+		fbhw = &st_switch;
+		atafb_ops.fb_setcolreg = &stste_setcolreg;
+		printk("Cannot determine video hardware; defaulting to ST(e)\n");
+#else /* ATAFB_STE */
+		/* no default driver included */
+		/* Nobody will ever see this message :-) */
+		panic("Cannot initialize video hardware");
+#endif
+	} while (0);
+
+	/* Multisync monitor capabilities */
+	/* Atari-TOS defaults if no boot option present */
+	if (fb_info.monspecs.hfmin == 0) {
+	    fb_info.monspecs.hfmin = 31000;
+	    fb_info.monspecs.hfmax = 32000;
+	    fb_info.monspecs.vfmin = 58;
+	    fb_info.monspecs.vfmax = 62;
+	}
+
+	detected_mode = fbhw->detect();
+	check_default_par(detected_mode);
+#ifdef ATAFB_EXT
+	if (!external_addr) {
+#endif /* ATAFB_EXT */
+		mem_req = default_mem_req + ovsc_offset + ovsc_addlen;
+		mem_req = PAGE_ALIGN(mem_req) + PAGE_SIZE;
+		screen_base = atari_stram_alloc(mem_req, "atafb");
+		if (!screen_base)
+			panic("Cannot allocate screen memory");
+		memset(screen_base, 0, mem_req);
+		pad = -(unsigned long)screen_base & (PAGE_SIZE-1);
+		screen_base+=pad;
+		real_screen_base=screen_base+ovsc_offset;
+		screen_len = (mem_req - pad - ovsc_offset) & PAGE_MASK;
+		st_ovsc_switch();
+		if (CPU_IS_040_OR_060) {
+			/* On a '040+, the cache mode of video RAM must be set to
+			 * write-through also for internal video hardware! */
+			cache_push(virt_to_phys(screen_base), screen_len);
+			kernel_set_cachemode(screen_base, screen_len,
+					     IOMAP_WRITETHROUGH);
+		}
+#ifdef ATAFB_EXT
+	}
+	else {
+		/* Map the video memory (physical address given) to somewhere
+		 * in the kernel address space.
+		 */
+		external_addr =
+		  ioremap_writethrough((unsigned long)external_addr,
+				       external_len);
+		if (external_vgaiobase)
+			external_vgaiobase =
+			  (unsigned long)ioremap(external_vgaiobase, 0x10000);
+		screen_base      =
+		real_screen_base = external_addr;
+		screen_len       = external_len & PAGE_MASK;
+		memset (screen_base, 0, external_len);
+	}
+#endif /* ATAFB_EXT */
+
+	strcpy(fb_info.modename, "Atari Builtin ");
+	fb_info.changevar = NULL;
+	fb_info.fbops = &atafb_ops;
+	fb_info.disp = &disp;
+	fb_info.currcon = -1;
+	fb_info.switch_con = &atafb_switch;
+	fb_info.updatevar = &fb_update_var;
+	fb_info.flags = FBINFO_FLAG_DEFAULT;
+	do_fb_set_var(&atafb_predefined[default_par-1], 1);
+	strcat(fb_info.modename, fb_var_names[default_par-1][0]);
+
+	atafb_get_var(&disp.var, -1, &fb_info);
+	atafb_set_disp(-1, &fb_info);
+	do_install_cmap(0, &fb_info);
+
+	if (register_framebuffer(&fb_info) < 0)
+		return -EINVAL;
+
+	printk("Determined %dx%d, depth %d\n",
+	       disp.var.xres, disp.var.yres, disp.var.bits_per_pixel);
+	if ((disp.var.xres != disp.var.xres_virtual) ||
+	    (disp.var.yres != disp.var.yres_virtual))
+	   printk("   virtual %dx%d\n",
+			  disp.var.xres_virtual, disp.var.yres_virtual);
+	printk("fb%d: %s frame buffer device, using %dK of video memory\n",
+	       fb_info.node, fb_info.modename, screen_len>>10);
+
+	/* TODO: This driver cannot be unloaded yet */
+	return 0;
+}
+
+
+#ifdef ATAFB_EXT
+static void __init atafb_setup_ext(char *spec)
+{
+	int		xres, xres_virtual, yres, depth, planes;
+	unsigned long addr, len;
+	char *p;
+
+	/* Format is: <xres>;<yres>;<depth>;<plane organ.>;
+	 *            <screen mem addr>
+	 *	      [;<screen mem length>[;<vgaiobase>[;<bits-per-col>[;<colorreg-type>
+	 *	      [;<xres-virtual>]]]]]
+	 *
+	 * 09/23/97	Juergen
+	 * <xres_virtual>:	hardware's x-resolution (f.e. ProMST)
+	 *
+	 * Even xres_virtual is available, we neither support panning nor hw-scrolling!
+	 */
+	if (!(p = strsep(&spec, ";")) || !*p)
+	    return;
+	xres_virtual = xres = simple_strtoul(p, NULL, 10);
+	if (xres <= 0)
+	    return;
+
+	if (!(p = strsep(&spec, ";")) || !*p)
+	    return;
+	yres = simple_strtoul(p, NULL, 10);
+	if (yres <= 0)
+	    return;
+
+	if (!(p = strsep(&spec, ";")) || !*p)
+	    return;
+	depth = simple_strtoul(p, NULL, 10);
+	if (depth != 1 && depth != 2 && depth != 4 && depth != 8 &&
+		depth != 16 && depth != 24)
+	    return;
+
+	if (!(p = strsep(&spec, ";")) || !*p)
+	    return;
+	if (*p == 'i')
+		planes = FB_TYPE_INTERLEAVED_PLANES;
+	else if (*p == 'p')
+		planes = FB_TYPE_PACKED_PIXELS;
+	else if (*p == 'n')
+		planes = FB_TYPE_PLANES;
+	else if (*p == 't')
+		planes = -1; /* true color */
+	else
+		return;
+
+
+	if (!(p = strsep(&spec, ";")) || !*p)
+		return;
+	addr = simple_strtoul(p, NULL, 0);
+
+	if (!(p = strsep(&spec, ";")) || !*p)
+		len = xres*yres*depth/8;
+	else
+		len = simple_strtoul(p, NULL, 0);
+
+	if ((p = strsep(&spec, ";")) && *p) {
+		external_vgaiobase=simple_strtoul(p, NULL, 0);
+	}
+
+	if ((p = strsep(&spec, ";")) && *p) {
+		external_bitspercol = simple_strtoul(p, NULL, 0);
+		if (external_bitspercol > 8)
+			external_bitspercol = 8;
+		else if (external_bitspercol < 1)
+			external_bitspercol = 1;
+	}
+
+	if ((p = strsep(&spec, ";")) && *p) {
+		if (!strcmp(p, "vga"))
+			external_card_type = IS_VGA;
+		if (!strcmp(p, "mv300"))
+			external_card_type = IS_MV300;
+	}
+
+	if ((p = strsep(&spec, ";")) && *p) {
+		xres_virtual = simple_strtoul(p, NULL, 10);
+		if (xres_virtual < xres)
+			xres_virtual = xres;
+		if (xres_virtual*yres*depth/8 > len)
+			len=xres_virtual*yres*depth/8;
+	}
+
+	external_xres  = xres;
+	external_xres_virtual  = xres_virtual;
+	external_yres  = yres;
+	external_depth = depth;
+	external_pmode = planes;
+	external_addr  = (void *)addr;
+	external_len   = len;
+
+	if (external_card_type == IS_MV300)
+	  switch (external_depth) {
+	    case 1:
+	      MV300_reg = MV300_reg_1bit;
+	      break;
+	    case 4:
+	      MV300_reg = MV300_reg_4bit;
+	      break;
+	    case 8:
+	      MV300_reg = MV300_reg_8bit;
+	      break;
+	    }
+}
+#endif /* ATAFB_EXT */
+
+
+static void __init atafb_setup_int(char *spec)
+{
+	/* Format to config extended internal video hardware like OverScan:
+	"internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset>"
+	Explanation:
+	<xres>: x-resolution 
+	<yres>: y-resolution
+	The following are only needed if you have an overscan which
+	needs a black border:
+	<xres_max>: max. length of a line in pixels your OverScan hardware would allow
+	<yres_max>: max. number of lines your OverScan hardware would allow
+	<offset>: Offset from physical beginning to visible beginning
+		  of screen in bytes
+	*/
+	int xres;
+	char *p;
+
+	if (!(p = strsep(&spec, ";")) || !*p)
+		return;
+	xres = simple_strtoul(p, NULL, 10);
+	if (!(p = strsep(&spec, ";")) || !*p)
+		return;
+	sttt_xres=xres;
+	tt_yres=st_yres=simple_strtoul(p, NULL, 10);
+	if ((p=strsep(&spec, ";")) && *p) {
+		sttt_xres_virtual=simple_strtoul(p, NULL, 10);
+	}
+	if ((p=strsep(&spec, ";")) && *p) {
+		sttt_yres_virtual=simple_strtoul(p, NULL, 0);
+	}
+	if ((p=strsep(&spec, ";")) && *p) {
+		ovsc_offset=simple_strtoul(p, NULL, 0);
+	}
+
+	if (ovsc_offset || (sttt_yres_virtual != st_yres))
+		use_hwscroll=0;
+}
+
+
+#ifdef ATAFB_FALCON
+static void __init atafb_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;
+}
+#endif /* ATAFB_FALCON */
+
+
+static void __init atafb_setup_user(char *spec)
+{
+	/* Format of user defined video mode is: <xres>;<yres>;<depth>
+	 */
+	char *p;
+	int xres, yres, depth, temp;
+
+	if (!(p = strsep(&spec, ";")) || !*p)
+		return;
+	xres = simple_strtoul(p, NULL, 10);
+	if (!(p = strsep(&spec, ";")) || !*p)
+		return;
+	yres = simple_strtoul(p, NULL, 10);
+	if (!(p = strsep(&spec, "")) || !*p)
+		return;
+	depth = simple_strtoul(p, NULL, 10);
+	if ((temp=get_video_mode("user0"))) {
+		default_par=temp;
+		atafb_predefined[default_par-1].xres = xres;
+		atafb_predefined[default_par-1].yres = yres;
+		atafb_predefined[default_par-1].bits_per_pixel = depth;
+	}
+}
+
+int __init atafb_setup( char *options )
+{
+    char *this_opt;
+    int temp;
+
+    fb_info.fontname[0] = '\0';
+
+    if (!options || !*options)
+		return 0;
+    
+    while ((this_opt = strsep(&options, ",")) != NULL) {	 
+	if (!*this_opt) continue;
+	if ((temp=get_video_mode(this_opt)))
+		default_par=temp;
+	else if (! strcmp(this_opt, "inverse"))
+		inverse=1;
+	else if (!strncmp(this_opt, "font:", 5))
+	   strcpy(fb_info.fontname, this_opt+5);
+	else if (! strncmp(this_opt, "hwscroll_",9)) {
+		hwscroll=simple_strtoul(this_opt+9, NULL, 10);
+		if (hwscroll < 0)
+			hwscroll = 0;
+		if (hwscroll > 200)
+			hwscroll = 200;
+	}
+#ifdef ATAFB_EXT
+	else if (!strcmp(this_opt,"mv300")) {
+		external_bitspercol = 8;
+		external_card_type = IS_MV300;
+	}
+	else if (!strncmp(this_opt,"external:",9))
+		atafb_setup_ext(this_opt+9);
+#endif
+	else if (!strncmp(this_opt,"internal:",9))
+		atafb_setup_int(this_opt+9);
+#ifdef ATAFB_FALCON
+	else if (!strncmp(this_opt, "eclock:", 7)) {
+		fext.f = simple_strtoul(this_opt+7, NULL, 10);
+		/* external pixelclock in kHz --> ps */
+		fext.t = 1000000000/fext.f;
+		fext.f *= 1000;
+	}
+	else if (!strncmp(this_opt, "monitorcap:", 11))
+		atafb_setup_mcap(this_opt+11);
+#endif
+	else if (!strcmp(this_opt, "keep"))
+		DontCalcRes = 1;
+	else if (!strncmp(this_opt, "R", 1))
+		atafb_setup_user(this_opt+1);
+    }
+    return 0;
+}
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+
+int init_module(void)
+{
+	return atafb_init();
+}
+#endif /* MODULE */
diff --git a/drivers/video/aty/Makefile b/drivers/video/aty/Makefile
new file mode 100644
index 0000000..9dec962
--- /dev/null
+++ b/drivers/video/aty/Makefile
@@ -0,0 +1,15 @@
+obj-$(CONFIG_FB_ATY) += atyfb.o
+obj-$(CONFIG_FB_ATY128) += aty128fb.o
+obj-$(CONFIG_FB_RADEON) += radeonfb.o
+
+atyfb-y				:= atyfb_base.o mach64_accel.o mach64_cursor.o
+atyfb-$(CONFIG_FB_ATY_GX)	+= mach64_gx.o
+atyfb-$(CONFIG_FB_ATY_CT)	+= mach64_ct.o
+atyfb-$(CONFIG_FB_ATY_XL_INIT)  += xlinit.o
+
+atyfb-objs			:= $(atyfb-y)
+
+radeonfb-y			:= radeon_base.o radeon_pm.o radeon_monitor.o radeon_accel.o
+radeonfb-$(CONFIG_FB_RADEON_I2C)	+= radeon_i2c.o
+radeonfb-objs			:= $(radeonfb-y)
+
diff --git a/drivers/video/aty/ati_ids.h b/drivers/video/aty/ati_ids.h
new file mode 100644
index 0000000..13321c6
--- /dev/null
+++ b/drivers/video/aty/ati_ids.h
@@ -0,0 +1,211 @@
+/*
+ * ATI PCI IDs from XFree86, kept here to make sync'ing with
+ * XFree much simpler. Currently, this list is only used by
+ * radeonfb
+ */
+
+#define PCI_CHIP_RV380_3150             0x3150
+#define PCI_CHIP_RV380_3151             0x3151
+#define PCI_CHIP_RV380_3152             0x3152
+#define PCI_CHIP_RV380_3153             0x3153
+#define PCI_CHIP_RV380_3154             0x3154
+#define PCI_CHIP_RV380_3156             0x3156
+#define PCI_CHIP_RV380_3E50             0x3E50
+#define PCI_CHIP_RV380_3E51             0x3E51
+#define PCI_CHIP_RV380_3E52             0x3E52
+#define PCI_CHIP_RV380_3E53             0x3E53
+#define PCI_CHIP_RV380_3E54             0x3E54
+#define PCI_CHIP_RV380_3E56             0x3E56
+#define PCI_CHIP_RS100_4136		0x4136
+#define PCI_CHIP_RS200_4137		0x4137
+#define PCI_CHIP_R300_AD		0x4144
+#define PCI_CHIP_R300_AE		0x4145
+#define PCI_CHIP_R300_AF		0x4146
+#define PCI_CHIP_R300_AG		0x4147
+#define PCI_CHIP_R350_AH                0x4148
+#define PCI_CHIP_R350_AI                0x4149
+#define PCI_CHIP_R350_AJ                0x414A
+#define PCI_CHIP_R350_AK                0x414B
+#define PCI_CHIP_RV350_AP               0x4150
+#define PCI_CHIP_RV350_AQ               0x4151
+#define PCI_CHIP_RV360_AR               0x4152
+#define PCI_CHIP_RV350_AS               0x4153
+#define PCI_CHIP_RV350_AT               0x4154
+#define PCI_CHIP_RV350_AV               0x4156
+#define PCI_CHIP_MACH32			0x4158
+#define PCI_CHIP_RS250_4237		0x4237
+#define PCI_CHIP_R200_BB		0x4242
+#define PCI_CHIP_R200_BC		0x4243
+#define PCI_CHIP_RS100_4336		0x4336
+#define PCI_CHIP_RS200_4337		0x4337
+#define PCI_CHIP_MACH64CT		0x4354
+#define PCI_CHIP_MACH64CX		0x4358
+#define PCI_CHIP_RS250_4437		0x4437
+#define PCI_CHIP_MACH64ET		0x4554
+#define PCI_CHIP_MACH64GB		0x4742
+#define PCI_CHIP_MACH64GD		0x4744
+#define PCI_CHIP_MACH64GI		0x4749
+#define PCI_CHIP_MACH64GL		0x474C
+#define PCI_CHIP_MACH64GM		0x474D
+#define PCI_CHIP_MACH64GN		0x474E
+#define PCI_CHIP_MACH64GO		0x474F
+#define PCI_CHIP_MACH64GP		0x4750
+#define PCI_CHIP_MACH64GQ		0x4751
+#define PCI_CHIP_MACH64GR		0x4752
+#define PCI_CHIP_MACH64GS		0x4753
+#define PCI_CHIP_MACH64GT		0x4754
+#define PCI_CHIP_MACH64GU		0x4755
+#define PCI_CHIP_MACH64GV		0x4756
+#define PCI_CHIP_MACH64GW		0x4757
+#define PCI_CHIP_MACH64GX		0x4758
+#define PCI_CHIP_MACH64GY		0x4759
+#define PCI_CHIP_MACH64GZ		0x475A
+#define PCI_CHIP_RV250_Id		0x4964
+#define PCI_CHIP_RV250_Ie		0x4965
+#define PCI_CHIP_RV250_If		0x4966
+#define PCI_CHIP_RV250_Ig		0x4967
+#define PCI_CHIP_R420_JH                0x4A48
+#define PCI_CHIP_R420_JI                0x4A49
+#define PCI_CHIP_R420_JJ                0x4A4A
+#define PCI_CHIP_R420_JK                0x4A4B
+#define PCI_CHIP_R420_JL                0x4A4C
+#define PCI_CHIP_R420_JM                0x4A4D
+#define PCI_CHIP_R420_JN                0x4A4E
+#define PCI_CHIP_R420_JP                0x4A50
+#define PCI_CHIP_MACH64LB		0x4C42
+#define PCI_CHIP_MACH64LD		0x4C44
+#define PCI_CHIP_RAGE128LE		0x4C45
+#define PCI_CHIP_RAGE128LF		0x4C46
+#define PCI_CHIP_MACH64LG		0x4C47
+#define PCI_CHIP_MACH64LI		0x4C49
+#define PCI_CHIP_MACH64LM		0x4C4D
+#define PCI_CHIP_MACH64LN		0x4C4E
+#define PCI_CHIP_MACH64LP		0x4C50
+#define PCI_CHIP_MACH64LQ		0x4C51
+#define PCI_CHIP_MACH64LR		0x4C52
+#define PCI_CHIP_MACH64LS		0x4C53
+#define PCI_CHIP_MACH64LT		0x4C54
+#define PCI_CHIP_RADEON_LW		0x4C57
+#define PCI_CHIP_RADEON_LX		0x4C58
+#define PCI_CHIP_RADEON_LY		0x4C59
+#define PCI_CHIP_RADEON_LZ		0x4C5A
+#define PCI_CHIP_RV250_Ld		0x4C64
+#define PCI_CHIP_RV250_Le		0x4C65
+#define PCI_CHIP_RV250_Lf		0x4C66
+#define PCI_CHIP_RV250_Lg		0x4C67
+#define PCI_CHIP_RV250_Ln		0x4C6E
+#define PCI_CHIP_RAGE128MF		0x4D46
+#define PCI_CHIP_RAGE128ML		0x4D4C
+#define PCI_CHIP_R300_ND		0x4E44
+#define PCI_CHIP_R300_NE		0x4E45
+#define PCI_CHIP_R300_NF		0x4E46
+#define PCI_CHIP_R300_NG		0x4E47
+#define PCI_CHIP_R350_NH                0x4E48  
+#define PCI_CHIP_R350_NI                0x4E49  
+#define PCI_CHIP_R360_NJ                0x4E4A  
+#define PCI_CHIP_R350_NK                0x4E4B  
+#define PCI_CHIP_RV350_NP               0x4E50
+#define PCI_CHIP_RV350_NQ               0x4E51
+#define PCI_CHIP_RV350_NR               0x4E52
+#define PCI_CHIP_RV350_NS               0x4E53
+#define PCI_CHIP_RV350_NT               0x4E54
+#define PCI_CHIP_RV350_NV               0x4E56
+#define PCI_CHIP_RAGE128PA		0x5041
+#define PCI_CHIP_RAGE128PB		0x5042
+#define PCI_CHIP_RAGE128PC		0x5043
+#define PCI_CHIP_RAGE128PD		0x5044
+#define PCI_CHIP_RAGE128PE		0x5045
+#define PCI_CHIP_RAGE128PF		0x5046
+#define PCI_CHIP_RAGE128PG		0x5047
+#define PCI_CHIP_RAGE128PH		0x5048
+#define PCI_CHIP_RAGE128PI		0x5049
+#define PCI_CHIP_RAGE128PJ		0x504A
+#define PCI_CHIP_RAGE128PK		0x504B
+#define PCI_CHIP_RAGE128PL		0x504C
+#define PCI_CHIP_RAGE128PM		0x504D
+#define PCI_CHIP_RAGE128PN		0x504E
+#define PCI_CHIP_RAGE128PO		0x504F
+#define PCI_CHIP_RAGE128PP		0x5050
+#define PCI_CHIP_RAGE128PQ		0x5051
+#define PCI_CHIP_RAGE128PR		0x5052
+#define PCI_CHIP_RAGE128PS		0x5053
+#define PCI_CHIP_RAGE128PT		0x5054
+#define PCI_CHIP_RAGE128PU		0x5055
+#define PCI_CHIP_RAGE128PV		0x5056
+#define PCI_CHIP_RAGE128PW		0x5057
+#define PCI_CHIP_RAGE128PX		0x5058
+#define PCI_CHIP_RADEON_QD		0x5144
+#define PCI_CHIP_RADEON_QE		0x5145
+#define PCI_CHIP_RADEON_QF		0x5146
+#define PCI_CHIP_RADEON_QG		0x5147
+#define PCI_CHIP_R200_QH		0x5148
+#define PCI_CHIP_R200_QI		0x5149
+#define PCI_CHIP_R200_QJ		0x514A
+#define PCI_CHIP_R200_QK		0x514B
+#define PCI_CHIP_R200_QL		0x514C
+#define PCI_CHIP_R200_QM		0x514D
+#define PCI_CHIP_R200_QN		0x514E
+#define PCI_CHIP_R200_QO		0x514F
+#define PCI_CHIP_RV200_QW		0x5157
+#define PCI_CHIP_RV200_QX		0x5158
+#define PCI_CHIP_RV100_QY		0x5159
+#define PCI_CHIP_RV100_QZ		0x515A
+#define PCI_CHIP_RAGE128RE		0x5245
+#define PCI_CHIP_RAGE128RF		0x5246
+#define PCI_CHIP_RAGE128RG		0x5247
+#define PCI_CHIP_RAGE128RK		0x524B
+#define PCI_CHIP_RAGE128RL		0x524C
+#define PCI_CHIP_RAGE128SE		0x5345
+#define PCI_CHIP_RAGE128SF		0x5346
+#define PCI_CHIP_RAGE128SG		0x5347
+#define PCI_CHIP_RAGE128SH		0x5348
+#define PCI_CHIP_RAGE128SK		0x534B
+#define PCI_CHIP_RAGE128SL		0x534C
+#define PCI_CHIP_RAGE128SM		0x534D
+#define PCI_CHIP_RAGE128SN		0x534E
+#define PCI_CHIP_RAGE128TF		0x5446
+#define PCI_CHIP_RAGE128TL		0x544C
+#define PCI_CHIP_RAGE128TR		0x5452
+#define PCI_CHIP_RAGE128TS		0x5453
+#define PCI_CHIP_RAGE128TT		0x5454
+#define PCI_CHIP_RAGE128TU		0x5455
+#define PCI_CHIP_RV370_5460             0x5460
+#define PCI_CHIP_RV370_5461             0x5461
+#define PCI_CHIP_RV370_5462             0x5462
+#define PCI_CHIP_RV370_5463             0x5463
+#define PCI_CHIP_RV370_5464             0x5464
+#define PCI_CHIP_RV370_5465             0x5465
+#define PCI_CHIP_RV370_5466             0x5466
+#define PCI_CHIP_RV370_5467             0x5467
+#define PCI_CHIP_R423_UH                0x5548
+#define PCI_CHIP_R423_UI                0x5549
+#define PCI_CHIP_R423_UJ                0x554A
+#define PCI_CHIP_R423_UK                0x554B
+#define PCI_CHIP_R423_UQ                0x5551
+#define PCI_CHIP_R423_UR                0x5552
+#define PCI_CHIP_R423_UT                0x5554
+#define PCI_CHIP_MACH64VT		0x5654
+#define PCI_CHIP_MACH64VU		0x5655
+#define PCI_CHIP_MACH64VV		0x5656
+#define PCI_CHIP_RS300_5834		0x5834
+#define PCI_CHIP_RS300_5835		0x5835
+#define PCI_CHIP_RS300_5836		0x5836
+#define PCI_CHIP_RS300_5837		0x5837
+#define PCI_CHIP_RV370_5B60             0x5B60
+#define PCI_CHIP_RV370_5B61             0x5B61
+#define PCI_CHIP_RV370_5B62             0x5B62
+#define PCI_CHIP_RV370_5B63             0x5B63
+#define PCI_CHIP_RV370_5B64             0x5B64
+#define PCI_CHIP_RV370_5B65             0x5B65
+#define PCI_CHIP_RV370_5B66             0x5B66
+#define PCI_CHIP_RV370_5B67             0x5B67
+#define PCI_CHIP_RV280_5960		0x5960
+#define PCI_CHIP_RV280_5961		0x5961
+#define PCI_CHIP_RV280_5962		0x5962
+#define PCI_CHIP_RV280_5964		0x5964
+#define PCI_CHIP_RV280_5C61		0x5C61
+#define PCI_CHIP_RV280_5C63		0x5C63
+#define PCI_CHIP_R423_5D57              0x5D57
+#define PCI_CHIP_RS350_7834             0x7834
+#define PCI_CHIP_RS350_7835             0x7835
+
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
new file mode 100644
index 0000000..8a4ba3b
--- /dev/null
+++ b/drivers/video/aty/aty128fb.c
@@ -0,0 +1,2485 @@
+/* $Id: aty128fb.c,v 1.1.1.1.36.1 1999/12/11 09:03:05 Exp $
+ *  linux/drivers/video/aty128fb.c -- Frame buffer device for ATI Rage128
+ *
+ *  Copyright (C) 1999-2003, Brad Douglas <brad@neruo.com>
+ *  Copyright (C) 1999, Anthony Tong <atong@uiuc.edu>
+ *
+ *                Ani Joshi / Jeff Garzik
+ *                      - Code cleanup
+ *
+ *                Michel Danzer <michdaen@iiic.ethz.ch>
+ *                      - 15/16 bit cleanup
+ *                      - fix panning
+ *
+ *                Benjamin Herrenschmidt
+ *                      - pmac-specific PM stuff
+ *			- various fixes & cleanups
+ *
+ *                Andreas Hundt <andi@convergence.de>
+ *                      - FB_ACTIVATE fixes
+ *
+ *		  Paul Mackerras <paulus@samba.org>
+ *			- Convert to new framebuffer API,
+ *			  fix colormap setting at 16 bits/pixel (565)
+ *
+ *		  Paul Mundt 
+ *		  	- PCI hotplug
+ *
+ *		  Jon Smirl <jonsmirl@yahoo.com>
+ * 			- PCI ID update
+ * 			- replace ROM BIOS search
+ *
+ *  Based off of Geert's atyfb.c and vfb.c.
+ *
+ *  TODO:
+ *		- monitor sensing (DDC)
+ *              - virtual display
+ *		- other platform support (only ppc/x86 supported)
+ *		- hardware cursor support
+ *
+ *    Please cc: your patches to brad@neruo.com.
+ */
+
+/*
+ * A special note of gratitude to ATI's devrel for providing documentation,
+ * example code and hardware. Thanks Nitya.	-atong and brad
+ */
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.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 <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/console.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_PPC_PMAC
+#include <asm/pmac_feature.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include "../macmodes.h"
+#endif
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+
+#ifdef CONFIG_BOOTX_TEXT
+#include <asm/btext.h>
+#endif /* CONFIG_BOOTX_TEXT */
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include <video/aty128.h>
+
+/* Debug flag */
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt, args...)		printk(KERN_DEBUG "aty128fb: %s " fmt, __FUNCTION__, ##args);
+#else
+#define DBG(fmt, args...)
+#endif
+
+#ifndef CONFIG_PPC_PMAC
+/* default mode */
+static struct fb_var_screeninfo default_var __initdata = {
+	/* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
+	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, 39722, 48, 16, 33, 10, 96, 2,
+	0, FB_VMODE_NONINTERLACED
+};
+
+#else /* CONFIG_PPC_PMAC */
+/* default to 1024x768 at 75Hz on PPC - this will work
+ * on the iMac, the usual 640x480 @ 60Hz doesn't. */
+static struct fb_var_screeninfo default_var = {
+	/* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */
+	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, 12699, 160, 32, 28, 1, 96, 3,
+	FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	FB_VMODE_NONINTERLACED
+};
+#endif /* CONFIG_PPC_PMAC */
+
+/* default modedb mode */
+/* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */
+static struct fb_videomode defaultmode __initdata = {
+	.refresh =	60,
+	.xres =		640,
+	.yres =		480,
+	.pixclock =	39722,
+	.left_margin =	48,
+	.right_margin =	16,
+	.upper_margin =	33,
+	.lower_margin =	10,
+	.hsync_len =	96,
+	.vsync_len =	2,
+	.sync =		0,
+	.vmode =	FB_VMODE_NONINTERLACED
+};
+
+/* Chip generations */
+enum {
+	rage_128,
+	rage_128_pci,
+	rage_128_pro,
+	rage_128_pro_pci,
+	rage_M3,
+	rage_M3_pci,
+	rage_M4,
+	rage_128_ultra,
+};
+
+/* Must match above enum */
+static const char *r128_family[] __devinitdata = {
+	"AGP",
+	"PCI",
+	"PRO AGP",
+	"PRO PCI",
+	"M3 AGP",
+	"M3 PCI",
+	"M4 AGP",
+	"Ultra AGP",
+};
+
+/*
+ * PCI driver prototypes
+ */
+static int aty128_probe(struct pci_dev *pdev,
+                               const struct pci_device_id *ent);
+static void aty128_remove(struct pci_dev *pdev);
+static int aty128_pci_suspend(struct pci_dev *pdev, pm_message_t state);
+static int aty128_pci_resume(struct pci_dev *pdev);
+static int aty128_do_resume(struct pci_dev *pdev);
+
+/* supported Rage128 chipsets */
+static struct pci_device_id aty128_pci_tbl[] = {
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LE,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3_pci },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LF,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_MF,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M4 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_ML,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M4 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PA,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PB,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PC,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PD,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro_pci },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PE,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PF,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PG,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PH,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PI,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PJ,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PK,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PL,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PM,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PN,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PO,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PP,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro_pci },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PQ,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PR,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro_pci },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PS,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PT,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PU,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PV,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PW,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PX,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RE,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pci },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RF,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RG,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RK,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pci },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RL,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SE,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SF,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pci },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SG,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SH,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SK,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SL,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SM,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SN,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TF,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TL,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TR,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TS,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TT,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TU,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, aty128_pci_tbl);
+
+static struct pci_driver aty128fb_driver = {
+	.name		= "aty128fb",
+	.id_table	= aty128_pci_tbl,
+	.probe		= aty128_probe,
+	.remove		= __devexit_p(aty128_remove),
+	.suspend	= aty128_pci_suspend,
+	.resume		= aty128_pci_resume,
+};
+
+/* packed BIOS settings */
+#ifndef CONFIG_PPC
+typedef struct {
+	u8 clock_chip_type;
+	u8 struct_size;
+	u8 accelerator_entry;
+	u8 VGA_entry;
+	u16 VGA_table_offset;
+	u16 POST_table_offset;
+	u16 XCLK;
+	u16 MCLK;
+	u8 num_PLL_blocks;
+	u8 size_PLL_blocks;
+	u16 PCLK_ref_freq;
+	u16 PCLK_ref_divider;
+	u32 PCLK_min_freq;
+	u32 PCLK_max_freq;
+	u16 MCLK_ref_freq;
+	u16 MCLK_ref_divider;
+	u32 MCLK_min_freq;
+	u32 MCLK_max_freq;
+	u16 XCLK_ref_freq;
+	u16 XCLK_ref_divider;
+	u32 XCLK_min_freq;
+	u32 XCLK_max_freq;
+} __attribute__ ((packed)) PLL_BLOCK;
+#endif /* !CONFIG_PPC */
+
+/* onboard memory information */
+struct aty128_meminfo {
+	u8 ML;
+	u8 MB;
+	u8 Trcd;
+	u8 Trp;
+	u8 Twr;
+	u8 CL;
+	u8 Tr2w;
+	u8 LoopLatency;
+	u8 DspOn;
+	u8 Rloop;
+	const char *name;
+};
+
+/* various memory configurations */
+static const struct aty128_meminfo sdr_128   =
+	{ 4, 4, 3, 3, 1, 3, 1, 16, 30, 16, "128-bit SDR SGRAM (1:1)" };
+static const struct aty128_meminfo sdr_64    =
+	{ 4, 8, 3, 3, 1, 3, 1, 17, 46, 17, "64-bit SDR SGRAM (1:1)" };
+static const struct aty128_meminfo sdr_sgram =
+	{ 4, 4, 1, 2, 1, 2, 1, 16, 24, 16, "64-bit SDR SGRAM (2:1)" };
+static const struct aty128_meminfo ddr_sgram =
+	{ 4, 4, 3, 3, 2, 3, 1, 16, 31, 16, "64-bit DDR SGRAM" };
+
+static struct fb_fix_screeninfo aty128fb_fix __initdata = {
+	.id		= "ATY Rage128",
+	.type		= FB_TYPE_PACKED_PIXELS,
+	.visual		= FB_VISUAL_PSEUDOCOLOR,
+	.xpanstep	= 8,
+	.ypanstep	= 1,
+	.mmio_len	= 0x2000,
+	.accel		= FB_ACCEL_ATI_RAGE128,
+};
+
+static char *mode_option __initdata = NULL;
+
+#ifdef CONFIG_PPC_PMAC
+static int default_vmode __initdata = VMODE_1024_768_60;
+static int default_cmode __initdata = CMODE_8;
+#endif
+
+#ifdef CONFIG_PMAC_PBOOK
+static int default_crt_on __initdata = 0;
+static int default_lcd_on __initdata = 1;
+#endif
+
+#ifdef CONFIG_MTRR
+static int mtrr = 1;
+#endif
+
+/* PLL constants */
+struct aty128_constants {
+	u32 ref_clk;
+	u32 ppll_min;
+	u32 ppll_max;
+	u32 ref_divider;
+	u32 xclk;
+	u32 fifo_width;
+	u32 fifo_depth;
+};
+
+struct aty128_crtc {
+	u32 gen_cntl;
+	u32 h_total, h_sync_strt_wid;
+	u32 v_total, v_sync_strt_wid;
+	u32 pitch;
+	u32 offset, offset_cntl;
+	u32 xoffset, yoffset;
+	u32 vxres, vyres;
+	u32 depth, bpp;
+};
+
+struct aty128_pll {
+	u32 post_divider;
+	u32 feedback_divider;
+	u32 vclk;
+};
+
+struct aty128_ddafifo {
+	u32 dda_config;
+	u32 dda_on_off;
+};
+
+/* register values for a specific mode */
+struct aty128fb_par {
+	struct aty128_crtc crtc;
+	struct aty128_pll pll;
+	struct aty128_ddafifo fifo_reg;
+	u32 accel_flags;
+	struct aty128_constants constants;  /* PLL and others      */
+	void __iomem *regbase;              /* remapped mmio       */
+	u32 vram_size;                      /* onboard video ram   */
+	int chip_gen;
+	const struct aty128_meminfo *mem;   /* onboard mem info    */
+#ifdef CONFIG_MTRR
+	struct { int vram; int vram_valid; } mtrr;
+#endif
+	int blitter_may_be_busy;
+	int fifo_slots;                 /* free slots in FIFO (64 max) */
+
+	int	pm_reg;
+	int crt_on, lcd_on;
+	struct pci_dev *pdev;
+	struct fb_info *next;
+	int	asleep;
+	int	lock_blank;
+
+	u8	red[32];		/* see aty128fb_setcolreg */
+	u8	green[64];
+	u8	blue[32];
+	u32	pseudo_palette[16];	/* used for TRUECOLOR */
+};
+
+
+#define round_div(n, d) ((n+(d/2))/d)
+
+static int aty128fb_check_var(struct fb_var_screeninfo *var,
+			      struct fb_info *info);
+static int aty128fb_set_par(struct fb_info *info);
+static int aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			      u_int transp, struct fb_info *info);
+static int aty128fb_pan_display(struct fb_var_screeninfo *var,
+			   struct fb_info *fb);
+static int aty128fb_blank(int blank, struct fb_info *fb);
+static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+			  u_long arg, struct fb_info *info);
+static int aty128fb_sync(struct fb_info *info);
+
+    /*
+     *  Internal routines
+     */
+
+static int aty128_encode_var(struct fb_var_screeninfo *var,
+                             const struct aty128fb_par *par);
+static int aty128_decode_var(struct fb_var_screeninfo *var,
+                             struct aty128fb_par *par);
+#if 0
+static void __init aty128_get_pllinfo(struct aty128fb_par *par,
+				      void __iomem *bios);
+static void __init __iomem *aty128_map_ROM(struct pci_dev *pdev, const struct aty128fb_par *par);
+#endif
+static void aty128_timings(struct aty128fb_par *par);
+static void aty128_init_engine(struct aty128fb_par *par);
+static void aty128_reset_engine(const struct aty128fb_par *par);
+static void aty128_flush_pixel_cache(const struct aty128fb_par *par);
+static void do_wait_for_fifo(u16 entries, struct aty128fb_par *par);
+static void wait_for_fifo(u16 entries, struct aty128fb_par *par);
+static void wait_for_idle(struct aty128fb_par *par);
+static u32 depth_to_dst(u32 depth);
+
+#define BIOS_IN8(v)  	(readb(bios + (v)))
+#define BIOS_IN16(v) 	(readb(bios + (v)) | \
+			  (readb(bios + (v) + 1) << 8))
+#define BIOS_IN32(v) 	(readb(bios + (v)) | \
+			  (readb(bios + (v) + 1) << 8) | \
+			  (readb(bios + (v) + 2) << 16) | \
+			  (readb(bios + (v) + 3) << 24))
+
+
+static struct fb_ops aty128fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= aty128fb_check_var,
+	.fb_set_par	= aty128fb_set_par,
+	.fb_setcolreg	= aty128fb_setcolreg,
+	.fb_pan_display = aty128fb_pan_display,
+	.fb_blank	= aty128fb_blank,
+	.fb_ioctl	= aty128fb_ioctl,
+	.fb_sync	= aty128fb_sync,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+static int aty128_set_backlight_enable(int on, int level, void* data);
+static int aty128_set_backlight_level(int level, void* data);
+
+static struct backlight_controller aty128_backlight_controller = {
+	aty128_set_backlight_enable,
+	aty128_set_backlight_level
+};
+#endif /* CONFIG_PMAC_BACKLIGHT */
+
+    /*
+     * Functions to read from/write to the mmio registers
+     *	- endian conversions may possibly be avoided by
+     *    using the other register aperture. TODO.
+     */
+static inline u32 _aty_ld_le32(volatile unsigned int regindex, 
+			       const struct aty128fb_par *par)
+{
+	return readl (par->regbase + regindex);
+}
+
+static inline void _aty_st_le32(volatile unsigned int regindex, u32 val, 
+				const struct aty128fb_par *par)
+{
+	writel (val, par->regbase + regindex);
+}
+
+static inline u8 _aty_ld_8(unsigned int regindex,
+			   const struct aty128fb_par *par)
+{
+	return readb (par->regbase + regindex);
+}
+
+static inline void _aty_st_8(unsigned int regindex, u8 val,
+			     const struct aty128fb_par *par)
+{
+	writeb (val, par->regbase + regindex);
+}
+
+#define aty_ld_le32(regindex)		_aty_ld_le32(regindex, par)
+#define aty_st_le32(regindex, val)	_aty_st_le32(regindex, val, par)
+#define aty_ld_8(regindex)		_aty_ld_8(regindex, par)
+#define aty_st_8(regindex, val)		_aty_st_8(regindex, val, par)
+
+    /*
+     * Functions to read from/write to the pll registers
+     */
+
+#define aty_ld_pll(pll_index)		_aty_ld_pll(pll_index, par)
+#define aty_st_pll(pll_index, val)	_aty_st_pll(pll_index, val, par)
+
+
+static u32 _aty_ld_pll(unsigned int pll_index,
+		       const struct aty128fb_par *par)
+{       
+	aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x3F);
+	return aty_ld_le32(CLOCK_CNTL_DATA);
+}
+
+    
+static void _aty_st_pll(unsigned int pll_index, u32 val,
+			const struct aty128fb_par *par)
+{
+	aty_st_8(CLOCK_CNTL_INDEX, (pll_index & 0x3F) | PLL_WR_EN);
+	aty_st_le32(CLOCK_CNTL_DATA, val);
+}
+
+
+/* return true when the PLL has completed an atomic update */
+static int aty_pll_readupdate(const struct aty128fb_par *par)
+{
+	return !(aty_ld_pll(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R);
+}
+
+
+static void aty_pll_wait_readupdate(const struct aty128fb_par *par)
+{
+	unsigned long timeout = jiffies + HZ/100; // should be more than enough
+	int reset = 1;
+
+	while (time_before(jiffies, timeout))
+		if (aty_pll_readupdate(par)) {
+			reset = 0;
+			break;
+		}
+
+	if (reset)	/* reset engine?? */
+		printk(KERN_DEBUG "aty128fb: PLL write timeout!\n");
+}
+
+
+/* tell PLL to update */
+static void aty_pll_writeupdate(const struct aty128fb_par *par)
+{
+	aty_pll_wait_readupdate(par);
+
+	aty_st_pll(PPLL_REF_DIV,
+		   aty_ld_pll(PPLL_REF_DIV) | PPLL_ATOMIC_UPDATE_W);
+}
+
+
+/* write to the scratch register to test r/w functionality */
+static int __init register_test(const struct aty128fb_par *par)
+{
+	u32 val;
+	int flag = 0;
+
+	val = aty_ld_le32(BIOS_0_SCRATCH);
+
+	aty_st_le32(BIOS_0_SCRATCH, 0x55555555);
+	if (aty_ld_le32(BIOS_0_SCRATCH) == 0x55555555) {
+		aty_st_le32(BIOS_0_SCRATCH, 0xAAAAAAAA);
+
+		if (aty_ld_le32(BIOS_0_SCRATCH) == 0xAAAAAAAA)
+			flag = 1; 
+	}
+
+	aty_st_le32(BIOS_0_SCRATCH, val);	// restore value
+	return flag;
+}
+
+
+/*
+ * Accelerator engine functions
+ */
+static void do_wait_for_fifo(u16 entries, struct aty128fb_par *par)
+{
+	int i;
+
+	for (;;) {
+		for (i = 0; i < 2000000; i++) {
+			par->fifo_slots = aty_ld_le32(GUI_STAT) & 0x0fff;
+			if (par->fifo_slots >= entries)
+				return;
+		}
+		aty128_reset_engine(par);
+	}
+}
+
+
+static void wait_for_idle(struct aty128fb_par *par)
+{
+	int i;
+
+	do_wait_for_fifo(64, par);
+
+	for (;;) {
+		for (i = 0; i < 2000000; i++) {
+			if (!(aty_ld_le32(GUI_STAT) & (1 << 31))) {
+				aty128_flush_pixel_cache(par);
+				par->blitter_may_be_busy = 0;
+				return;
+			}
+		}
+		aty128_reset_engine(par);
+	}
+}
+
+
+static void wait_for_fifo(u16 entries, struct aty128fb_par *par)
+{
+	if (par->fifo_slots < entries)
+		do_wait_for_fifo(64, par);
+	par->fifo_slots -= entries;
+}
+
+
+static void aty128_flush_pixel_cache(const struct aty128fb_par *par)
+{
+	int i;
+	u32 tmp;
+
+	tmp = aty_ld_le32(PC_NGUI_CTLSTAT);
+	tmp &= ~(0x00ff);
+	tmp |= 0x00ff;
+	aty_st_le32(PC_NGUI_CTLSTAT, tmp);
+
+	for (i = 0; i < 2000000; i++)
+		if (!(aty_ld_le32(PC_NGUI_CTLSTAT) & PC_BUSY))
+			break;
+}
+
+
+static void aty128_reset_engine(const struct aty128fb_par *par)
+{
+	u32 gen_reset_cntl, clock_cntl_index, mclk_cntl;
+
+	aty128_flush_pixel_cache(par);
+
+	clock_cntl_index = aty_ld_le32(CLOCK_CNTL_INDEX);
+	mclk_cntl = aty_ld_pll(MCLK_CNTL);
+
+	aty_st_pll(MCLK_CNTL, mclk_cntl | 0x00030000);
+
+	gen_reset_cntl = aty_ld_le32(GEN_RESET_CNTL);
+	aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl | SOFT_RESET_GUI);
+	aty_ld_le32(GEN_RESET_CNTL);
+	aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl & ~(SOFT_RESET_GUI));
+	aty_ld_le32(GEN_RESET_CNTL);
+
+	aty_st_pll(MCLK_CNTL, mclk_cntl);
+	aty_st_le32(CLOCK_CNTL_INDEX, clock_cntl_index);
+	aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl);
+
+	/* use old pio mode */
+	aty_st_le32(PM4_BUFFER_CNTL, PM4_BUFFER_CNTL_NONPM4);
+
+	DBG("engine reset");
+}
+
+
+static void aty128_init_engine(struct aty128fb_par *par)
+{
+	u32 pitch_value;
+
+	wait_for_idle(par);
+
+	/* 3D scaler not spoken here */
+	wait_for_fifo(1, par);
+	aty_st_le32(SCALE_3D_CNTL, 0x00000000);
+
+	aty128_reset_engine(par);
+
+	pitch_value = par->crtc.pitch;
+	if (par->crtc.bpp == 24) {
+		pitch_value = pitch_value * 3;
+	}
+
+	wait_for_fifo(4, par);
+	/* setup engine offset registers */
+	aty_st_le32(DEFAULT_OFFSET, 0x00000000);
+
+	/* setup engine pitch registers */
+	aty_st_le32(DEFAULT_PITCH, pitch_value);
+
+	/* set the default scissor register to max dimensions */
+	aty_st_le32(DEFAULT_SC_BOTTOM_RIGHT, (0x1FFF << 16) | 0x1FFF);
+
+	/* set the drawing controls registers */
+	aty_st_le32(DP_GUI_MASTER_CNTL,
+		    GMC_SRC_PITCH_OFFSET_DEFAULT		|
+		    GMC_DST_PITCH_OFFSET_DEFAULT		|
+		    GMC_SRC_CLIP_DEFAULT			|
+		    GMC_DST_CLIP_DEFAULT			|
+		    GMC_BRUSH_SOLIDCOLOR			|
+		    (depth_to_dst(par->crtc.depth) << 8)	|
+		    GMC_SRC_DSTCOLOR			|
+		    GMC_BYTE_ORDER_MSB_TO_LSB		|
+		    GMC_DP_CONVERSION_TEMP_6500		|
+		    ROP3_PATCOPY				|
+		    GMC_DP_SRC_RECT				|
+		    GMC_3D_FCN_EN_CLR			|
+		    GMC_DST_CLR_CMP_FCN_CLEAR		|
+		    GMC_AUX_CLIP_CLEAR			|
+		    GMC_WRITE_MASK_SET);
+
+	wait_for_fifo(8, par);
+	/* clear the line drawing registers */
+	aty_st_le32(DST_BRES_ERR, 0);
+	aty_st_le32(DST_BRES_INC, 0);
+	aty_st_le32(DST_BRES_DEC, 0);
+
+	/* set brush color registers */
+	aty_st_le32(DP_BRUSH_FRGD_CLR, 0xFFFFFFFF); /* white */
+	aty_st_le32(DP_BRUSH_BKGD_CLR, 0x00000000); /* black */
+
+	/* set source color registers */
+	aty_st_le32(DP_SRC_FRGD_CLR, 0xFFFFFFFF);   /* white */
+	aty_st_le32(DP_SRC_BKGD_CLR, 0x00000000);   /* black */
+
+	/* default write mask */
+	aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF);
+
+	/* Wait for all the writes to be completed before returning */
+	wait_for_idle(par);
+}
+
+
+/* convert depth values to their register representation */
+static u32 depth_to_dst(u32 depth)
+{
+	if (depth <= 8)
+		return DST_8BPP;
+	else if (depth <= 15)
+		return DST_15BPP;
+	else if (depth == 16)
+		return DST_16BPP;
+	else if (depth <= 24)
+		return DST_24BPP;
+	else if (depth <= 32)
+		return DST_32BPP;
+
+	return -EINVAL;
+}
+
+/*
+ * PLL informations retreival
+ */
+
+
+#ifndef __sparc__
+static void __iomem * __init aty128_map_ROM(const struct aty128fb_par *par, struct pci_dev *dev)
+{
+	u16 dptr;
+	u8 rom_type;
+	void __iomem *bios;
+	size_t rom_size;
+
+    	/* Fix from ATI for problem with Rage128 hardware not leaving ROM enabled */
+    	unsigned int temp;
+	temp = aty_ld_le32(RAGE128_MPP_TB_CONFIG);
+	temp &= 0x00ffffffu;
+	temp |= 0x04 << 24;
+	aty_st_le32(RAGE128_MPP_TB_CONFIG, temp);
+	temp = aty_ld_le32(RAGE128_MPP_TB_CONFIG);
+
+	bios = pci_map_rom(dev, &rom_size);
+
+	if (!bios) {
+		printk(KERN_ERR "aty128fb: ROM failed to map\n");
+		return NULL;
+	}
+
+	/* Very simple test to make sure it appeared */
+	if (BIOS_IN16(0) != 0xaa55) {
+		printk(KERN_ERR "aty128fb: Invalid ROM signature %x should be 0xaa55\n",
+		       BIOS_IN16(0));
+		goto failed;
+	}
+
+	/* Look for the PCI data to check the ROM type */
+	dptr = BIOS_IN16(0x18);
+
+	/* Check the PCI data signature. If it's wrong, we still assume a normal x86 ROM
+	 * for now, until I've verified this works everywhere. The goal here is more
+	 * to phase out Open Firmware images.
+	 *
+	 * Currently, we only look at the first PCI data, we could iteratre and deal with
+	 * them all, and we should use fb_bios_start relative to start of image and not
+	 * relative start of ROM, but so far, I never found a dual-image ATI card
+	 *
+	 * typedef struct {
+	 * 	u32	signature;	+ 0x00
+	 * 	u16	vendor;		+ 0x04
+	 * 	u16	device;		+ 0x06
+	 * 	u16	reserved_1;	+ 0x08
+	 * 	u16	dlen;		+ 0x0a
+	 * 	u8	drevision;	+ 0x0c
+	 * 	u8	class_hi;	+ 0x0d
+	 * 	u16	class_lo;	+ 0x0e
+	 * 	u16	ilen;		+ 0x10
+	 * 	u16	irevision;	+ 0x12
+	 * 	u8	type;		+ 0x14
+	 * 	u8	indicator;	+ 0x15
+	 * 	u16	reserved_2;	+ 0x16
+	 * } pci_data_t;
+	 */
+	if (BIOS_IN32(dptr) !=  (('R' << 24) | ('I' << 16) | ('C' << 8) | 'P')) {
+		printk(KERN_WARNING "aty128fb: PCI DATA signature in ROM incorrect: %08x\n",
+		       BIOS_IN32(dptr));
+		goto anyway;
+	}
+	rom_type = BIOS_IN8(dptr + 0x14);
+	switch(rom_type) {
+	case 0:
+		printk(KERN_INFO "aty128fb: Found Intel x86 BIOS ROM Image\n");
+		break;
+	case 1:
+		printk(KERN_INFO "aty128fb: Found Open Firmware ROM Image\n");
+		goto failed;
+	case 2:
+		printk(KERN_INFO "aty128fb: Found HP PA-RISC ROM Image\n");
+		goto failed;
+	default:
+		printk(KERN_INFO "aty128fb: Found unknown type %d ROM Image\n", rom_type);
+		goto failed;
+	}
+ anyway:
+	return bios;
+
+ failed:
+	pci_unmap_rom(dev, bios);
+	return NULL;
+}
+
+static void __init aty128_get_pllinfo(struct aty128fb_par *par, unsigned char __iomem *bios)
+{
+	unsigned int bios_hdr;
+	unsigned int bios_pll;
+
+	bios_hdr = BIOS_IN16(0x48);
+	bios_pll = BIOS_IN16(bios_hdr + 0x30);
+	
+	par->constants.ppll_max = BIOS_IN32(bios_pll + 0x16);
+	par->constants.ppll_min = BIOS_IN32(bios_pll + 0x12);
+	par->constants.xclk = BIOS_IN16(bios_pll + 0x08);
+	par->constants.ref_divider = BIOS_IN16(bios_pll + 0x10);
+	par->constants.ref_clk = BIOS_IN16(bios_pll + 0x0e);
+
+	DBG("ppll_max %d ppll_min %d xclk %d ref_divider %d ref clock %d\n",
+			par->constants.ppll_max, par->constants.ppll_min,
+			par->constants.xclk, par->constants.ref_divider,
+			par->constants.ref_clk);
+
+}           
+
+#ifdef CONFIG_X86
+static void __iomem *  __devinit aty128_find_mem_vbios(struct aty128fb_par *par)
+{
+	/* I simplified this code as we used to miss the signatures in
+	 * a lot of case. It's now closer to XFree, we just don't check
+	 * for signatures at all... Something better will have to be done
+	 * if we end up having conflicts
+	 */
+        u32  segstart;
+        unsigned char __iomem *rom_base = NULL;
+                                                
+        for (segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
+                rom_base = ioremap(segstart, 0x10000);
+		if (rom_base == NULL)
+			return NULL;
+		if (readb(rom_base) == 0x55 && readb(rom_base + 1) == 0xaa)
+	                break;
+                iounmap(rom_base);
+		rom_base = NULL;
+        }
+	return rom_base;
+}
+#endif
+#endif /* ndef(__sparc__) */
+
+/* fill in known card constants if pll_block is not available */
+static void __init aty128_timings(struct aty128fb_par *par)
+{
+#ifdef CONFIG_PPC_OF
+	/* instead of a table lookup, assume OF has properly
+	 * setup the PLL registers and use their values
+	 * to set the XCLK values and reference divider values */
+
+	u32 x_mpll_ref_fb_div;
+	u32 xclk_cntl;
+	u32 Nx, M;
+	unsigned PostDivSet[] = { 0, 1, 2, 4, 8, 3, 6, 12 };
+#endif
+
+	if (!par->constants.ref_clk)
+		par->constants.ref_clk = 2950;
+
+#ifdef CONFIG_PPC_OF
+	x_mpll_ref_fb_div = aty_ld_pll(X_MPLL_REF_FB_DIV);
+	xclk_cntl = aty_ld_pll(XCLK_CNTL) & 0x7;
+	Nx = (x_mpll_ref_fb_div & 0x00ff00) >> 8;
+	M  = x_mpll_ref_fb_div & 0x0000ff;
+
+	par->constants.xclk = round_div((2 * Nx * par->constants.ref_clk),
+					(M * PostDivSet[xclk_cntl]));
+
+	par->constants.ref_divider =
+		aty_ld_pll(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;
+#endif
+
+	if (!par->constants.ref_divider) {
+		par->constants.ref_divider = 0x3b;
+
+		aty_st_pll(X_MPLL_REF_FB_DIV, 0x004c4c1e);
+		aty_pll_writeupdate(par);
+	}
+	aty_st_pll(PPLL_REF_DIV, par->constants.ref_divider);
+	aty_pll_writeupdate(par);
+
+	/* from documentation */
+	if (!par->constants.ppll_min)
+		par->constants.ppll_min = 12500;
+	if (!par->constants.ppll_max)
+		par->constants.ppll_max = 25000;    /* 23000 on some cards? */
+	if (!par->constants.xclk)
+		par->constants.xclk = 0x1d4d;	     /* same as mclk */
+
+	par->constants.fifo_width = 128;
+	par->constants.fifo_depth = 32;
+
+	switch (aty_ld_le32(MEM_CNTL) & 0x3) {
+	case 0:
+		par->mem = &sdr_128;
+		break;
+	case 1:
+		par->mem = &sdr_sgram;
+		break;
+	case 2:
+		par->mem = &ddr_sgram;
+		break;
+	default:
+		par->mem = &sdr_sgram;
+	}
+}
+
+
+
+/*
+ * CRTC programming
+ */
+
+/* Program the CRTC registers */
+static void aty128_set_crtc(const struct aty128_crtc *crtc,
+			    const struct aty128fb_par *par)
+{
+	aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl);
+	aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_total);
+	aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid);
+	aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_total);
+	aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid);
+	aty_st_le32(CRTC_PITCH, crtc->pitch);
+	aty_st_le32(CRTC_OFFSET, crtc->offset);
+	aty_st_le32(CRTC_OFFSET_CNTL, crtc->offset_cntl);
+	/* Disable ATOMIC updating.  Is this the right place? */
+	aty_st_pll(PPLL_CNTL, aty_ld_pll(PPLL_CNTL) & ~(0x00030000));
+}
+
+
+static int aty128_var_to_crtc(const struct fb_var_screeninfo *var,
+			      struct aty128_crtc *crtc,
+			      const struct aty128fb_par *par)
+{
+	u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp, dst;
+	u32 left, right, upper, lower, hslen, vslen, sync, vmode;
+	u32 h_total, h_disp, h_sync_strt, h_sync_wid, h_sync_pol;
+	u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync;
+	u32 depth, bytpp;
+	u8 mode_bytpp[7] = { 0, 0, 1, 2, 2, 3, 4 };
+
+	/* input */
+	xres = var->xres;
+	yres = var->yres;
+	vxres   = var->xres_virtual;
+	vyres   = var->yres_virtual;
+	xoffset = var->xoffset;
+	yoffset = var->yoffset;
+	bpp   = var->bits_per_pixel;
+	left  = var->left_margin;
+	right = var->right_margin;
+	upper = var->upper_margin;
+	lower = var->lower_margin;
+	hslen = var->hsync_len;
+	vslen = var->vsync_len;
+	sync  = var->sync;
+	vmode = var->vmode;
+
+	if (bpp != 16)
+		depth = bpp;
+	else
+		depth = (var->green.length == 6) ? 16 : 15;
+
+	/* check for mode eligibility
+	 * accept only non interlaced modes */
+	if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+		return -EINVAL;
+
+	/* convert (and round up) and validate */
+	xres = (xres + 7) & ~7;
+	xoffset = (xoffset + 7) & ~7;
+
+	if (vxres < xres + xoffset)
+		vxres = xres + xoffset;
+
+	if (vyres < yres + yoffset)
+		vyres = yres + yoffset;
+
+	/* convert depth into ATI register depth */
+	dst = depth_to_dst(depth);
+
+	if (dst == -EINVAL) {
+		printk(KERN_ERR "aty128fb: Invalid depth or RGBA\n");
+		return -EINVAL;
+	}
+
+	/* convert register depth to bytes per pixel */
+	bytpp = mode_bytpp[dst];
+
+	/* make sure there is enough video ram for the mode */
+	if ((u32)(vxres * vyres * bytpp) > par->vram_size) {
+		printk(KERN_ERR "aty128fb: Not enough memory for mode\n");
+		return -EINVAL;
+	}
+
+	h_disp = (xres >> 3) - 1;
+	h_total = (((xres + right + hslen + left) >> 3) - 1) & 0xFFFFL;
+
+	v_disp = yres - 1;
+	v_total = (yres + upper + vslen + lower - 1) & 0xFFFFL;
+
+	/* check to make sure h_total and v_total are in range */
+	if (((h_total >> 3) - 1) > 0x1ff || (v_total - 1) > 0x7FF) {
+		printk(KERN_ERR "aty128fb: invalid width ranges\n");
+		return -EINVAL;
+	}
+
+	h_sync_wid = (hslen + 7) >> 3;
+	if (h_sync_wid == 0)
+		h_sync_wid = 1;
+	else if (h_sync_wid > 0x3f)        /* 0x3f = max hwidth */
+		h_sync_wid = 0x3f;
+
+	h_sync_strt = (h_disp << 3) + right;
+
+	v_sync_wid = vslen;
+	if (v_sync_wid == 0)
+		v_sync_wid = 1;
+	else if (v_sync_wid > 0x1f)        /* 0x1f = max vwidth */
+		v_sync_wid = 0x1f;
+    
+	v_sync_strt = v_disp + lower;
+
+	h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
+	v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;
+    
+	c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0;
+
+	crtc->gen_cntl = 0x3000000L | c_sync | (dst << 8);
+
+	crtc->h_total = h_total | (h_disp << 16);
+	crtc->v_total = v_total | (v_disp << 16);
+
+	crtc->h_sync_strt_wid = h_sync_strt | (h_sync_wid << 16) |
+	        (h_sync_pol << 23);
+	crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid << 16) |
+                (v_sync_pol << 23);
+
+	crtc->pitch = vxres >> 3;
+
+	crtc->offset = 0;
+
+	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW)
+		crtc->offset_cntl = 0x00010000;
+	else
+		crtc->offset_cntl = 0;
+
+	crtc->vxres = vxres;
+	crtc->vyres = vyres;
+	crtc->xoffset = xoffset;
+	crtc->yoffset = yoffset;
+	crtc->depth = depth;
+	crtc->bpp = bpp;
+
+	return 0;
+}
+
+
+static int aty128_pix_width_to_var(int pix_width, struct fb_var_screeninfo *var)
+{
+
+	/* fill in pixel info */
+	var->red.msb_right = 0;
+	var->green.msb_right = 0;
+	var->blue.offset = 0;
+	var->blue.msb_right = 0;
+	var->transp.offset = 0;
+	var->transp.length = 0;
+	var->transp.msb_right = 0;
+	switch (pix_width) {
+	case CRTC_PIX_WIDTH_8BPP:
+		var->bits_per_pixel = 8;
+		var->red.offset = 0;
+		var->red.length = 8;
+		var->green.offset = 0;
+		var->green.length = 8;
+		var->blue.length = 8;
+		break;
+	case CRTC_PIX_WIDTH_15BPP:
+		var->bits_per_pixel = 16;
+		var->red.offset = 10;
+		var->red.length = 5;
+		var->green.offset = 5;
+		var->green.length = 5;
+		var->blue.length = 5;
+		break;
+	case CRTC_PIX_WIDTH_16BPP:
+		var->bits_per_pixel = 16;
+		var->red.offset = 11;
+		var->red.length = 5;
+		var->green.offset = 5;
+		var->green.length = 6;
+		var->blue.length = 5;
+		break;
+	case CRTC_PIX_WIDTH_24BPP:
+		var->bits_per_pixel = 24;
+		var->red.offset = 16;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.length = 8;
+		break;
+	case CRTC_PIX_WIDTH_32BPP:
+		var->bits_per_pixel = 32;
+		var->red.offset = 16;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.length = 8;
+		var->transp.offset = 24;
+		var->transp.length = 8;
+		break;
+	default:
+		printk(KERN_ERR "aty128fb: Invalid pixel width\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+static int aty128_crtc_to_var(const struct aty128_crtc *crtc,
+			      struct fb_var_screeninfo *var)
+{
+	u32 xres, yres, left, right, upper, lower, hslen, vslen, sync;
+	u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol;
+	u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync;
+	u32 pix_width;
+
+	/* fun with masking */
+	h_total     = crtc->h_total & 0x1ff;
+	h_disp      = (crtc->h_total >> 16) & 0xff;
+	h_sync_strt = (crtc->h_sync_strt_wid >> 3) & 0x1ff;
+	h_sync_dly  = crtc->h_sync_strt_wid & 0x7;
+	h_sync_wid  = (crtc->h_sync_strt_wid >> 16) & 0x3f;
+	h_sync_pol  = (crtc->h_sync_strt_wid >> 23) & 0x1;
+	v_total     = crtc->v_total & 0x7ff;
+	v_disp      = (crtc->v_total >> 16) & 0x7ff;
+	v_sync_strt = crtc->v_sync_strt_wid & 0x7ff;
+	v_sync_wid  = (crtc->v_sync_strt_wid >> 16) & 0x1f;
+	v_sync_pol  = (crtc->v_sync_strt_wid >> 23) & 0x1;
+	c_sync      = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0;
+	pix_width   = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK;
+
+	/* do conversions */
+	xres  = (h_disp + 1) << 3;
+	yres  = v_disp + 1;
+	left  = ((h_total - h_sync_strt - h_sync_wid) << 3) - h_sync_dly;
+	right = ((h_sync_strt - h_disp) << 3) + h_sync_dly;
+	hslen = h_sync_wid << 3;
+	upper = v_total - v_sync_strt - v_sync_wid;
+	lower = v_sync_strt - v_disp;
+	vslen = v_sync_wid;
+	sync  = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) |
+		(v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) |
+		(c_sync ? FB_SYNC_COMP_HIGH_ACT : 0);
+
+	aty128_pix_width_to_var(pix_width, var);
+
+	var->xres = xres;
+	var->yres = yres;
+	var->xres_virtual = crtc->vxres;
+	var->yres_virtual = crtc->vyres;
+	var->xoffset = crtc->xoffset;
+	var->yoffset = crtc->yoffset;
+	var->left_margin  = left;
+	var->right_margin = right;
+	var->upper_margin = upper;
+	var->lower_margin = lower;
+	var->hsync_len = hslen;
+	var->vsync_len = vslen;
+	var->sync  = sync;
+	var->vmode = FB_VMODE_NONINTERLACED;
+
+	return 0;
+}
+
+#ifdef CONFIG_PMAC_PBOOK
+static void aty128_set_crt_enable(struct aty128fb_par *par, int on)
+{
+	if (on) {
+		aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) | CRT_CRTC_ON);
+		aty_st_le32(DAC_CNTL, (aty_ld_le32(DAC_CNTL) | DAC_PALETTE2_SNOOP_EN));
+	} else
+		aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) & ~CRT_CRTC_ON);
+}
+
+static void aty128_set_lcd_enable(struct aty128fb_par *par, int on)
+{
+	u32 reg;
+
+	if (on) {
+		reg = aty_ld_le32(LVDS_GEN_CNTL);
+		reg |= LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION;
+		reg &= ~LVDS_DISPLAY_DIS;
+		aty_st_le32(LVDS_GEN_CNTL, reg);
+#ifdef CONFIG_PMAC_BACKLIGHT
+		aty128_set_backlight_enable(get_backlight_enable(),
+					    get_backlight_level(), par);
+#endif	
+	} else {
+#ifdef CONFIG_PMAC_BACKLIGHT
+		aty128_set_backlight_enable(0, 0, par);
+#endif	
+		reg = aty_ld_le32(LVDS_GEN_CNTL);
+		reg |= LVDS_DISPLAY_DIS;
+		aty_st_le32(LVDS_GEN_CNTL, reg);
+		mdelay(100);
+		reg &= ~(LVDS_ON /*| LVDS_EN*/);
+		aty_st_le32(LVDS_GEN_CNTL, reg);
+	}
+}
+#endif /* CONFIG_PMAC_PBOOK */
+
+static void aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par)
+{
+	u32 div3;
+
+	unsigned char post_conv[] =	/* register values for post dividers */
+        { 2, 0, 1, 4, 2, 2, 6, 2, 3, 2, 2, 2, 7 };
+
+	/* select PPLL_DIV_3 */
+	aty_st_le32(CLOCK_CNTL_INDEX, aty_ld_le32(CLOCK_CNTL_INDEX) | (3 << 8));
+
+	/* reset PLL */
+	aty_st_pll(PPLL_CNTL,
+		   aty_ld_pll(PPLL_CNTL) | PPLL_RESET | PPLL_ATOMIC_UPDATE_EN);
+
+	/* write the reference divider */
+	aty_pll_wait_readupdate(par);
+	aty_st_pll(PPLL_REF_DIV, par->constants.ref_divider & 0x3ff);
+	aty_pll_writeupdate(par);
+
+	div3 = aty_ld_pll(PPLL_DIV_3);
+	div3 &= ~PPLL_FB3_DIV_MASK;
+	div3 |= pll->feedback_divider;
+	div3 &= ~PPLL_POST3_DIV_MASK;
+	div3 |= post_conv[pll->post_divider] << 16;
+
+	/* write feedback and post dividers */
+	aty_pll_wait_readupdate(par);
+	aty_st_pll(PPLL_DIV_3, div3);
+	aty_pll_writeupdate(par);
+
+	aty_pll_wait_readupdate(par);
+	aty_st_pll(HTOTAL_CNTL, 0);	/* no horiz crtc adjustment */
+	aty_pll_writeupdate(par);
+
+	/* clear the reset, just in case */
+	aty_st_pll(PPLL_CNTL, aty_ld_pll(PPLL_CNTL) & ~PPLL_RESET);
+}
+
+
+static int aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll,
+			     const struct aty128fb_par *par)
+{
+	const struct aty128_constants c = par->constants;
+	unsigned char post_dividers[] = {1,2,4,8,3,6,12};
+	u32 output_freq;
+	u32 vclk;        /* in .01 MHz */
+	int i;
+	u32 n, d;
+
+	vclk = 100000000 / period_in_ps;	/* convert units to 10 kHz */
+
+	/* adjust pixel clock if necessary */
+	if (vclk > c.ppll_max)
+		vclk = c.ppll_max;
+	if (vclk * 12 < c.ppll_min)
+		vclk = c.ppll_min/12;
+
+	/* now, find an acceptable divider */
+	for (i = 0; i < sizeof(post_dividers); i++) {
+		output_freq = post_dividers[i] * vclk;
+		if (output_freq >= c.ppll_min && output_freq <= c.ppll_max)
+			break;
+	}
+
+	/* calculate feedback divider */
+	n = c.ref_divider * output_freq;
+	d = c.ref_clk;
+
+	pll->post_divider = post_dividers[i];
+	pll->feedback_divider = round_div(n, d);
+	pll->vclk = vclk;
+
+	DBG("post %d feedback %d vlck %d output %d ref_divider %d "
+	    "vclk_per: %d\n", pll->post_divider,
+	    pll->feedback_divider, vclk, output_freq,
+	    c.ref_divider, period_in_ps);
+
+	return 0;
+}
+
+
+static int aty128_pll_to_var(const struct aty128_pll *pll, struct fb_var_screeninfo *var)
+{
+	var->pixclock = 100000000 / pll->vclk;
+
+	return 0;
+}
+
+
+static void aty128_set_fifo(const struct aty128_ddafifo *dsp,
+			    const struct aty128fb_par *par)
+{
+	aty_st_le32(DDA_CONFIG, dsp->dda_config);
+	aty_st_le32(DDA_ON_OFF, dsp->dda_on_off);
+}
+
+
+static int aty128_ddafifo(struct aty128_ddafifo *dsp,
+			  const struct aty128_pll *pll,
+			  u32 depth,
+			  const struct aty128fb_par *par)
+{
+	const struct aty128_meminfo *m = par->mem;
+	u32 xclk = par->constants.xclk;
+	u32 fifo_width = par->constants.fifo_width;
+	u32 fifo_depth = par->constants.fifo_depth;
+	s32 x, b, p, ron, roff;
+	u32 n, d, bpp;
+
+	/* round up to multiple of 8 */
+	bpp = (depth+7) & ~7;
+
+	n = xclk * fifo_width;
+	d = pll->vclk * bpp;
+	x = round_div(n, d);
+
+	ron = 4 * m->MB +
+		3 * ((m->Trcd - 2 > 0) ? m->Trcd - 2 : 0) +
+		2 * m->Trp +
+		m->Twr +
+		m->CL +
+		m->Tr2w +
+		x;
+
+	DBG("x %x\n", x);
+
+	b = 0;
+	while (x) {
+		x >>= 1;
+		b++;
+	}
+	p = b + 1;
+
+	ron <<= (11 - p);
+
+	n <<= (11 - p);
+	x = round_div(n, d);
+	roff = x * (fifo_depth - 4);
+
+	if ((ron + m->Rloop) >= roff) {
+		printk(KERN_ERR "aty128fb: Mode out of range!\n");
+		return -EINVAL;
+	}
+
+	DBG("p: %x rloop: %x x: %x ron: %x roff: %x\n",
+	    p, m->Rloop, x, ron, roff);
+
+	dsp->dda_config = p << 16 | m->Rloop << 20 | x;
+	dsp->dda_on_off = ron << 16 | roff;
+
+	return 0;
+}
+
+
+/*
+ * This actually sets the video mode.
+ */
+static int aty128fb_set_par(struct fb_info *info)
+{ 
+	struct aty128fb_par *par = info->par;
+	u32 config;
+	int err;
+
+	if ((err = aty128_decode_var(&info->var, par)) != 0)
+		return err;
+
+	if (par->blitter_may_be_busy)
+		wait_for_idle(par);
+
+	/* clear all registers that may interfere with mode setting */
+	aty_st_le32(OVR_CLR, 0);
+	aty_st_le32(OVR_WID_LEFT_RIGHT, 0);
+	aty_st_le32(OVR_WID_TOP_BOTTOM, 0);
+	aty_st_le32(OV0_SCALE_CNTL, 0);
+	aty_st_le32(MPP_TB_CONFIG, 0);
+	aty_st_le32(MPP_GP_CONFIG, 0);
+	aty_st_le32(SUBPIC_CNTL, 0);
+	aty_st_le32(VIPH_CONTROL, 0);
+	aty_st_le32(I2C_CNTL_1, 0);         /* turn off i2c */
+	aty_st_le32(GEN_INT_CNTL, 0);	/* turn off interrupts */
+	aty_st_le32(CAP0_TRIG_CNTL, 0);
+	aty_st_le32(CAP1_TRIG_CNTL, 0);
+
+	aty_st_8(CRTC_EXT_CNTL + 1, 4);	/* turn video off */
+
+	aty128_set_crtc(&par->crtc, par);
+	aty128_set_pll(&par->pll, par);
+	aty128_set_fifo(&par->fifo_reg, par);
+
+	config = aty_ld_le32(CONFIG_CNTL) & ~3;
+
+#if defined(__BIG_ENDIAN)
+	if (par->crtc.bpp == 32)
+		config |= 2;	/* make aperture do 32 bit swapping */
+	else if (par->crtc.bpp == 16)
+		config |= 1;	/* make aperture do 16 bit swapping */
+#endif
+
+	aty_st_le32(CONFIG_CNTL, config);
+	aty_st_8(CRTC_EXT_CNTL + 1, 0);	/* turn the video back on */
+
+	info->fix.line_length = (par->crtc.vxres * par->crtc.bpp) >> 3;
+	info->fix.visual = par->crtc.bpp == 8 ? FB_VISUAL_PSEUDOCOLOR
+		: FB_VISUAL_DIRECTCOLOR;
+
+#ifdef CONFIG_PMAC_PBOOK
+	if (par->chip_gen == rage_M3) {
+		aty128_set_crt_enable(par, par->crt_on);
+		aty128_set_lcd_enable(par, par->lcd_on);
+	}
+#endif
+	if (par->accel_flags & FB_ACCELF_TEXT)
+		aty128_init_engine(par);
+
+#ifdef CONFIG_BOOTX_TEXT
+	btext_update_display(info->fix.smem_start,
+			     (((par->crtc.h_total>>16) & 0xff)+1)*8,
+			     ((par->crtc.v_total>>16) & 0x7ff)+1,
+			     par->crtc.bpp,
+			     par->crtc.vxres*par->crtc.bpp/8);
+#endif /* CONFIG_BOOTX_TEXT */
+
+	return 0;
+}
+
+/*
+ *  encode/decode the User Defined Part of the Display
+ */
+
+static int aty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par)
+{
+	int err;
+	struct aty128_crtc crtc;
+	struct aty128_pll pll;
+	struct aty128_ddafifo fifo_reg;
+
+	if ((err = aty128_var_to_crtc(var, &crtc, par)))
+		return err;
+
+	if ((err = aty128_var_to_pll(var->pixclock, &pll, par)))
+		return err;
+
+	if ((err = aty128_ddafifo(&fifo_reg, &pll, crtc.depth, par)))
+		return err;
+
+	par->crtc = crtc;
+	par->pll = pll;
+	par->fifo_reg = fifo_reg;
+	par->accel_flags = var->accel_flags;
+
+	return 0;
+}
+
+
+static int aty128_encode_var(struct fb_var_screeninfo *var,
+			     const struct aty128fb_par *par)
+{
+	int err;
+
+	if ((err = aty128_crtc_to_var(&par->crtc, var)))
+		return err;
+
+	if ((err = aty128_pll_to_var(&par->pll, var)))
+		return err;
+
+	var->nonstd = 0;
+	var->activate = 0;
+
+	var->height = -1;
+	var->width = -1;
+	var->accel_flags = par->accel_flags;
+
+	return 0;
+}           
+
+
+static int aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct aty128fb_par par;
+	int err;
+
+	par = *(struct aty128fb_par *)info->par;
+	if ((err = aty128_decode_var(var, &par)) != 0)
+		return err;
+	aty128_encode_var(var, &par);
+	return 0;
+}
+
+
+/*
+ *  Pan or Wrap the Display
+ */
+static int aty128fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb) 
+{
+	struct aty128fb_par *par = fb->par;
+	u32 xoffset, yoffset;
+	u32 offset;
+	u32 xres, yres;
+
+	xres = (((par->crtc.h_total >> 16) & 0xff) + 1) << 3;
+	yres = ((par->crtc.v_total >> 16) & 0x7ff) + 1;
+
+	xoffset = (var->xoffset +7) & ~7;
+	yoffset = var->yoffset;
+
+	if (xoffset+xres > par->crtc.vxres || yoffset+yres > par->crtc.vyres)
+		return -EINVAL;
+
+	par->crtc.xoffset = xoffset;
+	par->crtc.yoffset = yoffset;
+
+	offset = ((yoffset * par->crtc.vxres + xoffset)*(par->crtc.bpp >> 3)) & ~7;
+
+	if (par->crtc.bpp == 24)
+		offset += 8 * (offset % 3); /* Must be multiple of 8 and 3 */
+
+	aty_st_le32(CRTC_OFFSET, offset);
+
+	return 0;
+}
+
+
+/*
+ *  Helper function to store a single palette register
+ */
+static void aty128_st_pal(u_int regno, u_int red, u_int green, u_int blue,
+			  struct aty128fb_par *par)
+{
+	if (par->chip_gen == rage_M3) {
+#if 0
+		/* Note: For now, on M3, we set palette on both heads, which may
+		 * be useless. Can someone with a M3 check this ?
+		 * 
+		 * This code would still be useful if using the second CRTC to 
+		 * do mirroring
+		 */
+
+		aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PALETTE_ACCESS_CNTL);
+		aty_st_8(PALETTE_INDEX, regno);
+		aty_st_le32(PALETTE_DATA, (red<<16)|(green<<8)|blue);
+#endif
+		aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL);
+	}
+
+	aty_st_8(PALETTE_INDEX, regno);
+	aty_st_le32(PALETTE_DATA, (red<<16)|(green<<8)|blue);
+}
+
+static int aty128fb_sync(struct fb_info *info)
+{
+	struct aty128fb_par *par = info->par;
+
+	if (par->blitter_may_be_busy)
+		wait_for_idle(par);
+	return 0;
+}
+
+#ifndef MODULE
+static int __init aty128fb_setup(char *options)
+{
+	char *this_opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+#ifdef CONFIG_PMAC_PBOOK
+		if (!strncmp(this_opt, "lcd:", 4)) {
+			default_lcd_on = simple_strtoul(this_opt+4, NULL, 0);
+			continue;
+		} else if (!strncmp(this_opt, "crt:", 4)) {
+			default_crt_on = simple_strtoul(this_opt+4, NULL, 0);
+			continue;
+		}
+#endif
+#ifdef CONFIG_MTRR
+		if(!strncmp(this_opt, "nomtrr", 6)) {
+			mtrr = 0;
+			continue;
+		}
+#endif
+#ifdef CONFIG_PPC_PMAC
+		/* vmode and cmode deprecated */
+		if (!strncmp(this_opt, "vmode:", 6)) {
+			unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
+			if (vmode > 0 && vmode <= VMODE_MAX)
+				default_vmode = vmode;
+			continue;
+		} else if (!strncmp(this_opt, "cmode:", 6)) {
+			unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0);
+			switch (cmode) {
+			case 0:
+			case 8:
+				default_cmode = CMODE_8;
+				break;
+			case 15:
+			case 16:
+				default_cmode = CMODE_16;
+				break;
+			case 24:
+			case 32:
+				default_cmode = CMODE_32;
+				break;
+			}
+			continue;
+		}
+#endif /* CONFIG_PPC_PMAC */
+		mode_option = this_opt;
+	}
+	return 0;
+}
+#endif  /*  MODULE  */
+
+
+/*
+ *  Initialisation
+ */
+
+#ifdef CONFIG_PPC_PMAC
+static void aty128_early_resume(void *data)
+{
+        struct aty128fb_par *par = data;
+
+	if (try_acquire_console_sem())
+		return;
+	aty128_do_resume(par->pdev);
+	release_console_sem();
+}
+#endif /* CONFIG_PPC_PMAC */
+
+static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	struct fb_info *info = pci_get_drvdata(pdev);
+	struct aty128fb_par *par = info->par;
+	struct fb_var_screeninfo var;
+	char video_card[DEVICE_NAME_SIZE];
+	u8 chip_rev;
+	u32 dac;
+
+	if (!par->vram_size)	/* may have already been probed */
+		par->vram_size = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF;
+
+	/* Get the chip revision */
+	chip_rev = (aty_ld_le32(CONFIG_CNTL) >> 16) & 0x1F;
+
+	strcpy(video_card, "Rage128 XX ");
+	video_card[8] = ent->device >> 8;
+	video_card[9] = ent->device & 0xFF;
+	    
+	/* range check to make sure */
+	if (ent->driver_data < (sizeof(r128_family)/sizeof(char *)))
+	    strncat(video_card, r128_family[ent->driver_data], sizeof(video_card));
+
+	printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] ", video_card, chip_rev);
+
+	if (par->vram_size % (1024 * 1024) == 0)
+		printk("%dM %s\n", par->vram_size / (1024*1024), par->mem->name);
+	else
+		printk("%dk %s\n", par->vram_size / 1024, par->mem->name);
+
+	par->chip_gen = ent->driver_data;
+
+	/* fill in info */
+	info->fbops = &aty128fb_ops;
+	info->flags = FBINFO_FLAG_DEFAULT;
+
+#ifdef CONFIG_PMAC_PBOOK
+	par->lcd_on = default_lcd_on;
+	par->crt_on = default_crt_on;
+#endif
+
+	var = default_var;
+#ifdef CONFIG_PPC_PMAC
+	if (_machine == _MACH_Pmac) {
+		/* Indicate sleep capability */
+		if (par->chip_gen == rage_M3) {
+			pmac_call_feature(PMAC_FTR_DEVICE_CAN_WAKE, NULL, 0, 1);
+			pmac_set_early_video_resume(aty128_early_resume, par);
+		}
+
+		/* Find default mode */
+		if (mode_option) {
+			if (!mac_find_mode(&var, info, mode_option, 8))
+				var = default_var;
+		} else {
+			if (default_vmode <= 0 || default_vmode > VMODE_MAX)
+				default_vmode = VMODE_1024_768_60;
+
+			/* iMacs need that resolution
+			 * PowerMac2,1 first r128 iMacs
+			 * PowerMac2,2 summer 2000 iMacs
+			 * PowerMac4,1 january 2001 iMacs "flower power"
+			 */
+			if (machine_is_compatible("PowerMac2,1") ||
+			    machine_is_compatible("PowerMac2,2") ||
+			    machine_is_compatible("PowerMac4,1"))
+				default_vmode = VMODE_1024_768_75;
+
+			/* iBook SE */
+			if (machine_is_compatible("PowerBook2,2"))
+				default_vmode = VMODE_800_600_60;
+
+			/* PowerBook Firewire (Pismo), iBook Dual USB */
+			if (machine_is_compatible("PowerBook3,1") ||
+			    machine_is_compatible("PowerBook4,1"))
+				default_vmode = VMODE_1024_768_60;
+
+			/* PowerBook Titanium */
+			if (machine_is_compatible("PowerBook3,2"))
+				default_vmode = VMODE_1152_768_60;
+	
+			if (default_cmode > 16) 
+			    default_cmode = CMODE_32;
+			else if (default_cmode > 8) 
+			    default_cmode = CMODE_16;
+			else 
+			    default_cmode = CMODE_8;
+
+			if (mac_vmode_to_var(default_vmode, default_cmode, &var))
+				var = default_var;
+		}
+	} else
+#endif /* CONFIG_PPC_PMAC */
+	{
+		if (mode_option)
+			if (fb_find_mode(&var, info, mode_option, NULL, 
+					 0, &defaultmode, 8) == 0)
+				var = default_var;
+	}
+
+	var.accel_flags &= ~FB_ACCELF_TEXT;
+//	var.accel_flags |= FB_ACCELF_TEXT;/* FIXME Will add accel later */
+
+	if (aty128fb_check_var(&var, info)) {
+		printk(KERN_ERR "aty128fb: Cannot set default mode.\n");
+		return 0;
+	}
+
+	/* setup the DAC the way we like it */
+	dac = aty_ld_le32(DAC_CNTL);
+	dac |= (DAC_8BIT_EN | DAC_RANGE_CNTL);
+	dac |= DAC_MASK;
+	if (par->chip_gen == rage_M3)
+		dac |= DAC_PALETTE2_SNOOP_EN;
+	aty_st_le32(DAC_CNTL, dac);
+
+	/* turn off bus mastering, just in case */
+	aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL) | BUS_MASTER_DIS);
+
+	info->var = var;
+	fb_alloc_cmap(&info->cmap, 256, 0);
+
+	var.activate = FB_ACTIVATE_NOW;
+
+	aty128_init_engine(par);
+
+	if (register_framebuffer(info) < 0)
+		return 0;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	/* Could be extended to Rage128Pro LVDS output too */
+	if (par->chip_gen == rage_M3)
+		register_backlight_controller(&aty128_backlight_controller, par, "ati");
+#endif /* CONFIG_PMAC_BACKLIGHT */
+
+	par->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM);
+	par->pdev = pdev;
+	par->asleep = 0;
+	par->lock_blank = 0;
+	
+	printk(KERN_INFO "fb%d: %s frame buffer device on %s\n",
+	       info->node, info->fix.id, video_card);
+
+	return 1;	/* success! */
+}
+
+#ifdef CONFIG_PCI
+/* register a card    ++ajoshi */
+static int __init aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	unsigned long fb_addr, reg_addr;
+	struct aty128fb_par *par;
+	struct fb_info *info;
+	int err;
+#ifndef __sparc__
+	void __iomem *bios = NULL;
+#endif
+
+	/* Enable device in PCI config */
+	if ((err = pci_enable_device(pdev))) {
+		printk(KERN_ERR "aty128fb: Cannot enable PCI device: %d\n",
+				err);
+		return -ENODEV;
+	}
+
+	fb_addr = pci_resource_start(pdev, 0);
+	if (!request_mem_region(fb_addr, pci_resource_len(pdev, 0),
+				"aty128fb FB")) {
+		printk(KERN_ERR "aty128fb: cannot reserve frame "
+				"buffer memory\n");
+		return -ENODEV;
+	}
+
+	reg_addr = pci_resource_start(pdev, 2);
+	if (!request_mem_region(reg_addr, pci_resource_len(pdev, 2),
+				"aty128fb MMIO")) {
+		printk(KERN_ERR "aty128fb: cannot reserve MMIO region\n");
+		goto err_free_fb;
+	}
+
+	/* We have the resources. Now virtualize them */
+	info = framebuffer_alloc(sizeof(struct aty128fb_par), &pdev->dev);
+	if (info == NULL) {
+		printk(KERN_ERR "aty128fb: can't alloc fb_info_aty128\n");
+		goto err_free_mmio;
+	}
+	par = info->par;
+
+	info->pseudo_palette = par->pseudo_palette;
+	info->fix = aty128fb_fix;
+
+	/* Virtualize mmio region */
+	info->fix.mmio_start = reg_addr;
+	par->regbase = ioremap(reg_addr, pci_resource_len(pdev, 2));
+	if (!par->regbase)
+		goto err_free_info;
+
+	/* Grab memory size from the card */
+	// How does this relate to the resource length from the PCI hardware?
+	par->vram_size = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF;
+
+	/* Virtualize the framebuffer */
+	info->screen_base = ioremap(fb_addr, par->vram_size);
+	if (!info->screen_base)
+		goto err_unmap_out;
+
+	/* Set up info->fix */
+	info->fix = aty128fb_fix;
+	info->fix.smem_start = fb_addr;
+	info->fix.smem_len = par->vram_size;
+	info->fix.mmio_start = reg_addr;
+
+	/* If we can't test scratch registers, something is seriously wrong */
+	if (!register_test(par)) {
+		printk(KERN_ERR "aty128fb: Can't write to video register!\n");
+		goto err_out;
+	}
+
+#ifndef __sparc__
+	bios = aty128_map_ROM(par, pdev);
+#ifdef CONFIG_X86
+	if (bios == NULL)
+		bios = aty128_find_mem_vbios(par);
+#endif
+	if (bios == NULL)
+		printk(KERN_INFO "aty128fb: BIOS not located, guessing timings.\n");
+	else {
+		printk(KERN_INFO "aty128fb: Rage128 BIOS located\n");
+		aty128_get_pllinfo(par, bios);
+		pci_unmap_rom(pdev, bios);
+	}
+#endif /* __sparc__ */
+
+	aty128_timings(par);
+	pci_set_drvdata(pdev, info);
+
+	if (!aty128_init(pdev, ent))
+		goto err_out;
+
+#ifdef CONFIG_MTRR
+	if (mtrr) {
+		par->mtrr.vram = mtrr_add(info->fix.smem_start,
+				par->vram_size, MTRR_TYPE_WRCOMB, 1);
+		par->mtrr.vram_valid = 1;
+		/* let there be speed */
+		printk(KERN_INFO "aty128fb: Rage128 MTRR set to ON\n");
+	}
+#endif /* CONFIG_MTRR */
+	return 0;
+
+err_out:
+	iounmap(info->screen_base);
+err_unmap_out:
+	iounmap(par->regbase);
+err_free_info:
+	framebuffer_release(info);
+err_free_mmio:
+	release_mem_region(pci_resource_start(pdev, 2),
+			pci_resource_len(pdev, 2));
+err_free_fb:
+	release_mem_region(pci_resource_start(pdev, 0),
+			pci_resource_len(pdev, 0));
+	return -ENODEV;
+}
+
+static void __devexit aty128_remove(struct pci_dev *pdev)
+{
+	struct fb_info *info = pci_get_drvdata(pdev);
+	struct aty128fb_par *par;
+
+	if (!info)
+		return;
+
+	par = info->par;
+
+	unregister_framebuffer(info);
+#ifdef CONFIG_MTRR
+	if (par->mtrr.vram_valid)
+		mtrr_del(par->mtrr.vram, info->fix.smem_start,
+			 par->vram_size);
+#endif /* CONFIG_MTRR */
+	iounmap(par->regbase);
+	iounmap(info->screen_base);
+
+	release_mem_region(pci_resource_start(pdev, 0),
+			   pci_resource_len(pdev, 0));
+	release_mem_region(pci_resource_start(pdev, 2),
+			   pci_resource_len(pdev, 2));
+	framebuffer_release(info);
+}
+#endif /* CONFIG_PCI */
+
+
+
+    /*
+     *  Blank the display.
+     */
+static int aty128fb_blank(int blank, struct fb_info *fb)
+{
+	struct aty128fb_par *par = fb->par;
+	u8 state = 0;
+
+	if (par->lock_blank || par->asleep)
+		return 0;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	if ((_machine == _MACH_Pmac) && blank)
+		set_backlight_enable(0);
+#endif /* CONFIG_PMAC_BACKLIGHT */
+
+	if (blank & FB_BLANK_VSYNC_SUSPEND)
+		state |= 2;
+	if (blank & FB_BLANK_HSYNC_SUSPEND)
+		state |= 1;
+	if (blank & FB_BLANK_POWERDOWN)
+		state |= 4;
+
+	aty_st_8(CRTC_EXT_CNTL+1, state);
+
+#ifdef CONFIG_PMAC_PBOOK
+	if (par->chip_gen == rage_M3) {
+		aty128_set_crt_enable(par, par->crt_on && !blank);
+		aty128_set_lcd_enable(par, par->lcd_on && !blank);
+	}
+#endif	
+#ifdef CONFIG_PMAC_BACKLIGHT
+	if ((_machine == _MACH_Pmac) && !blank)
+		set_backlight_enable(1);
+#endif /* CONFIG_PMAC_BACKLIGHT */
+	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 aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			      u_int transp, struct fb_info *info)
+{
+	struct aty128fb_par *par = info->par;
+
+	if (regno > 255
+	    || (par->crtc.depth == 16 && regno > 63)
+	    || (par->crtc.depth == 15 && regno > 31))
+		return 1;
+
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	if (regno < 16) {
+		int i;
+		u32 *pal = info->pseudo_palette;
+
+		switch (par->crtc.depth) {
+		case 15:
+			pal[regno] = (regno << 10) | (regno << 5) | regno;
+			break;
+		case 16:
+			pal[regno] = (regno << 11) | (regno << 6) | regno;
+			break;
+		case 24:
+			pal[regno] = (regno << 16) | (regno << 8) | regno;
+			break;
+		case 32:
+			i = (regno << 8) | regno;
+			pal[regno] = (i << 16) | i;
+			break;
+		}
+	}
+
+	if (par->crtc.depth == 16 && regno > 0) {
+		/*
+		 * With the 5-6-5 split of bits for RGB at 16 bits/pixel, we
+		 * have 32 slots for R and B values but 64 slots for G values.
+		 * Thus the R and B values go in one slot but the G value
+		 * goes in a different slot, and we have to avoid disturbing
+		 * the other fields in the slots we touch.
+		 */
+		par->green[regno] = green;
+		if (regno < 32) {
+			par->red[regno] = red;
+			par->blue[regno] = blue;
+			aty128_st_pal(regno * 8, red, par->green[regno*2],
+				      blue, par);
+		}
+		red = par->red[regno/2];
+		blue = par->blue[regno/2];
+		regno <<= 2;
+	} else if (par->crtc.bpp == 16)
+		regno <<= 3;
+	aty128_st_pal(regno, red, green, blue, par);
+
+	return 0;
+}
+
+#define ATY_MIRROR_LCD_ON	0x00000001
+#define ATY_MIRROR_CRT_ON	0x00000002
+
+/* out param: u32*	backlight value: 0 to 15 */
+#define FBIO_ATY128_GET_MIRROR	_IOR('@', 1, __u32)
+/* in param: u32*	backlight value: 0 to 15 */
+#define FBIO_ATY128_SET_MIRROR	_IOW('@', 2, __u32)
+
+static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+			  u_long arg, struct fb_info *info)
+{
+#ifdef CONFIG_PMAC_PBOOK
+	struct aty128fb_par *par = info->par;
+	u32 value;
+	int rc;
+    
+	switch (cmd) {
+	case FBIO_ATY128_SET_MIRROR:
+		if (par->chip_gen != rage_M3)
+			return -EINVAL;
+		rc = get_user(value, (__u32 __user *)arg);
+		if (rc)
+			return rc;
+		par->lcd_on = (value & 0x01) != 0;
+		par->crt_on = (value & 0x02) != 0;
+		if (!par->crt_on && !par->lcd_on)
+			par->lcd_on = 1;
+		aty128_set_crt_enable(par, par->crt_on);	
+		aty128_set_lcd_enable(par, par->lcd_on);	
+		return 0;
+	case FBIO_ATY128_GET_MIRROR:
+		if (par->chip_gen != rage_M3)
+			return -EINVAL;
+		value = (par->crt_on << 1) | par->lcd_on;
+		return put_user(value, (__u32 __user *)arg);
+	}
+#endif
+	return -EINVAL;
+}
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+static int backlight_conv[] = {
+	0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e,
+	0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
+};
+
+/* We turn off the LCD completely instead of just dimming the backlight.
+ * This provides greater power saving and the display is useless without
+ * backlight anyway
+ */
+#define BACKLIGHT_LVDS_OFF
+/* That one prevents proper CRT output with LCD off */
+#undef BACKLIGHT_DAC_OFF
+
+static int aty128_set_backlight_enable(int on, int level, void *data)
+{
+	struct aty128fb_par *par = data;
+	unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
+
+	if (!par->lcd_on)
+		on = 0;
+	reg |= LVDS_BL_MOD_EN | LVDS_BLON;
+	if (on && level > BACKLIGHT_OFF) {
+		reg |= LVDS_DIGION;
+		if (!(reg & LVDS_ON)) {
+			reg &= ~LVDS_BLON;
+			aty_st_le32(LVDS_GEN_CNTL, reg);
+			(void)aty_ld_le32(LVDS_GEN_CNTL);
+			mdelay(10);
+			reg |= LVDS_BLON;
+			aty_st_le32(LVDS_GEN_CNTL, reg);
+		}
+		reg &= ~LVDS_BL_MOD_LEVEL_MASK;
+		reg |= (backlight_conv[level] << LVDS_BL_MOD_LEVEL_SHIFT);
+#ifdef BACKLIGHT_LVDS_OFF
+		reg |= LVDS_ON | LVDS_EN;
+		reg &= ~LVDS_DISPLAY_DIS;
+#endif
+		aty_st_le32(LVDS_GEN_CNTL, reg);
+#ifdef BACKLIGHT_DAC_OFF
+		aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & (~DAC_PDWN));
+#endif		
+	} else {
+		reg &= ~LVDS_BL_MOD_LEVEL_MASK;
+		reg |= (backlight_conv[0] << LVDS_BL_MOD_LEVEL_SHIFT);
+#ifdef BACKLIGHT_LVDS_OFF
+		reg |= LVDS_DISPLAY_DIS;
+		aty_st_le32(LVDS_GEN_CNTL, reg);
+		(void)aty_ld_le32(LVDS_GEN_CNTL);
+		udelay(10);
+		reg &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION);
+#endif		
+		aty_st_le32(LVDS_GEN_CNTL, reg);
+#ifdef BACKLIGHT_DAC_OFF
+		aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PDWN);
+#endif		
+	}
+
+	return 0;
+}
+
+static int aty128_set_backlight_level(int level, void* data)
+{
+	return aty128_set_backlight_enable(1, level, data);
+}
+#endif /* CONFIG_PMAC_BACKLIGHT */
+
+#if 0
+    /*
+     *  Accelerated functions
+     */
+
+static inline void aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
+				   u_int width, u_int height,
+				   struct fb_info_aty128 *par)
+{
+    u32 save_dp_datatype, save_dp_cntl, dstval;
+
+    if (!width || !height)
+        return;
+
+    dstval = depth_to_dst(par->current_par.crtc.depth);
+    if (dstval == DST_24BPP) {
+        srcx *= 3;
+        dstx *= 3;
+        width *= 3;
+    } else if (dstval == -EINVAL) {
+        printk("aty128fb: invalid depth or RGBA\n");
+        return;
+    }
+
+    wait_for_fifo(2, par);
+    save_dp_datatype = aty_ld_le32(DP_DATATYPE);
+    save_dp_cntl     = aty_ld_le32(DP_CNTL);
+
+    wait_for_fifo(6, par);
+    aty_st_le32(SRC_Y_X, (srcy << 16) | srcx);
+    aty_st_le32(DP_MIX, ROP3_SRCCOPY | DP_SRC_RECT);
+    aty_st_le32(DP_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM);
+    aty_st_le32(DP_DATATYPE, save_dp_datatype | dstval | SRC_DSTCOLOR);
+
+    aty_st_le32(DST_Y_X, (dsty << 16) | dstx);
+    aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width);
+
+    par->blitter_may_be_busy = 1;
+
+    wait_for_fifo(2, par);
+    aty_st_le32(DP_DATATYPE, save_dp_datatype);
+    aty_st_le32(DP_CNTL, save_dp_cntl); 
+}
+
+
+    /*
+     * Text mode accelerated functions
+     */
+
+static void fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx,
+			int height, int width)
+{
+    sx     *= fontwidth(p);
+    sy     *= fontheight(p);
+    dx     *= fontwidth(p);
+    dy     *= fontheight(p);
+    width  *= fontwidth(p);
+    height *= fontheight(p);
+
+    aty128_rectcopy(sx, sy, dx, dy, width, height,
+			(struct fb_info_aty128 *)p->fb_info);
+}
+#endif /* 0 */
+
+static void aty128_set_suspend(struct aty128fb_par *par, int suspend)
+{
+	u32	pmgt;
+	u16	pwr_command;
+	struct pci_dev *pdev = par->pdev;
+
+	if (!par->pm_reg)
+		return;
+		
+	/* Set the chip into the appropriate suspend mode (we use D2,
+	 * D3 would require a complete re-initialisation of the chip,
+	 * including PCI config registers, clocks, AGP configuration, ...)
+	 */
+	if (suspend) {
+		/* Make sure CRTC2 is reset. Remove that the day we decide to
+		 * actually use CRTC2 and replace it with real code for disabling
+		 * the CRTC2 output during sleep
+		 */
+		aty_st_le32(CRTC2_GEN_CNTL, aty_ld_le32(CRTC2_GEN_CNTL) &
+			~(CRTC2_EN));
+
+		/* Set the power management mode to be PCI based */
+		/* Use this magic value for now */
+		pmgt = 0x0c005407;
+		aty_st_pll(POWER_MANAGEMENT, pmgt);
+		(void)aty_ld_pll(POWER_MANAGEMENT);
+		aty_st_le32(BUS_CNTL1, 0x00000010);
+		aty_st_le32(MEM_POWER_MISC, 0x0c830000);
+		mdelay(100);
+		pci_read_config_word(pdev, par->pm_reg+PCI_PM_CTRL, &pwr_command);
+		/* Switch PCI power management to D2 */
+		pci_write_config_word(pdev, par->pm_reg+PCI_PM_CTRL,
+			(pwr_command & ~PCI_PM_CTRL_STATE_MASK) | 2);
+		pci_read_config_word(pdev, par->pm_reg+PCI_PM_CTRL, &pwr_command);
+	} else {
+		/* Switch back PCI power management to D0 */
+		mdelay(100);
+		pci_write_config_word(pdev, par->pm_reg+PCI_PM_CTRL, 0);
+		pci_read_config_word(pdev, par->pm_reg+PCI_PM_CTRL, &pwr_command);
+		mdelay(100);
+	}
+}
+
+static int aty128_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct fb_info *info = pci_get_drvdata(pdev);
+	struct aty128fb_par *par = info->par;
+	u8 agp;
+
+	/* We don't do anything but D2, for now we return 0, but
+	 * we may want to change that. How do we know if the BIOS
+	 * can properly take care of D3 ? Also, with swsusp, we
+	 * know we'll be rebooted, ...
+	 */
+#ifdef CONFIG_PPC_PMAC
+	/* HACK ALERT ! Once I find a proper way to say to each driver
+	 * individually what will happen with it's PCI slot, I'll change
+	 * that. On laptops, the AGP slot is just unclocked, so D2 is
+	 * expected, while on desktops, the card is powered off
+	 */
+	if (state >= 3)
+		state = 2;
+#endif /* CONFIG_PPC_PMAC */
+	 
+	if (state != 2 || state == pdev->dev.power.power_state)
+		return 0;
+
+	printk(KERN_DEBUG "aty128fb: suspending...\n");
+	
+	acquire_console_sem();
+
+	fb_set_suspend(info, 1);
+
+	/* Make sure engine is reset */
+	wait_for_idle(par);
+	aty128_reset_engine(par);
+	wait_for_idle(par);
+
+	/* Blank display and LCD */
+	aty128fb_blank(VESA_POWERDOWN, info);
+
+	/* Sleep */
+	par->asleep = 1;
+	par->lock_blank = 1;
+
+	/* Disable AGP. The AGP host should have done it, but since ordering
+	 * isn't always properly guaranteed in this specific case, let's make
+	 * sure it's disabled on card side now. Ultimately, when merging fbdev
+	 * and dri into some common infrastructure, this will be handled
+	 * more nicely. The host bridge side will (or will not) be dealt with
+	 * by the bridge AGP driver, we don't attempt to touch it here.
+	 */
+	agp = pci_find_capability(pdev, PCI_CAP_ID_AGP);
+	if (agp) {
+		u32 cmd;
+
+		pci_read_config_dword(pdev, agp + PCI_AGP_COMMAND, &cmd);
+		if (cmd & PCI_AGP_COMMAND_AGP) {
+			printk(KERN_INFO "aty128fb: AGP was enabled, "
+			       "disabling ...\n");
+			cmd &= ~PCI_AGP_COMMAND_AGP;
+			pci_write_config_dword(pdev, agp + PCI_AGP_COMMAND,
+					       cmd);
+		}
+	}
+
+	/* We need a way to make sure the fbdev layer will _not_ touch the
+	 * framebuffer before we put the chip to suspend state. On 2.4, I
+	 * used dummy fb ops, 2.5 need proper support for this at the
+	 * fbdev level
+	 */
+	if (state == 2)
+		aty128_set_suspend(par, 1);
+
+	release_console_sem();
+
+	pdev->dev.power.power_state = state;
+
+	return 0;
+}
+
+static int aty128_do_resume(struct pci_dev *pdev)
+{
+	struct fb_info *info = pci_get_drvdata(pdev);
+	struct aty128fb_par *par = info->par;
+
+	if (pdev->dev.power.power_state == 0)
+		return 0;
+
+	/* Wakeup chip */
+	if (pdev->dev.power.power_state == 2)
+		aty128_set_suspend(par, 0);
+	par->asleep = 0;
+
+	/* Restore display & engine */
+	aty128_reset_engine(par);
+	wait_for_idle(par);
+	aty128fb_set_par(info);
+	fb_pan_display(info, &info->var);
+	fb_set_cmap(&info->cmap, info);
+
+	/* Refresh */
+	fb_set_suspend(info, 0);
+
+	/* Unblank */
+	par->lock_blank = 0;
+	aty128fb_blank(0, info);
+
+	pdev->dev.power.power_state = PMSG_ON;
+
+	printk(KERN_DEBUG "aty128fb: resumed !\n");
+
+	return 0;
+}
+
+static int aty128_pci_resume(struct pci_dev *pdev)
+{
+	int rc;
+
+	acquire_console_sem();
+	rc = aty128_do_resume(pdev);
+	release_console_sem();
+
+	return rc;
+}
+
+
+static int __init aty128fb_init(void)
+{
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("aty128fb", &option))
+		return -ENODEV;
+	aty128fb_setup(option);
+#endif
+
+	return pci_register_driver(&aty128fb_driver);
+}
+
+static void __exit aty128fb_exit(void)
+{
+	pci_unregister_driver(&aty128fb_driver);
+}
+
+module_init(aty128fb_init);
+
+module_exit(aty128fb_exit);
+
+MODULE_AUTHOR("(c)1999-2003 Brad Douglas <brad@neruo.com>");
+MODULE_DESCRIPTION("FBDev driver for ATI Rage128 / Pro cards");
+MODULE_LICENSE("GPL");
+module_param(mode_option, charp, 0);
+MODULE_PARM_DESC(mode_option, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
+#ifdef CONFIG_MTRR
+module_param_named(nomtrr, mtrr, invbool, 0);
+MODULE_PARM_DESC(nomtrr, "bool: Disable MTRR support (0 or 1=disabled) (default=0)");
+#endif
+
diff --git a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h
new file mode 100644
index 0000000..09de173
--- /dev/null
+++ b/drivers/video/aty/atyfb.h
@@ -0,0 +1,359 @@
+/*
+ *  ATI Frame Buffer Device Driver Core Definitions
+ */
+
+#include <linux/config.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+    /*
+     *  Elements of the hardware specific atyfb_par structure
+     */
+
+struct crtc {
+	u32 vxres;
+	u32 vyres;
+	u32 xoffset;
+	u32 yoffset;
+	u32 bpp;
+	u32 h_tot_disp;
+	u32 h_sync_strt_wid;
+	u32 v_tot_disp;
+	u32 v_sync_strt_wid;
+	u32 vline_crnt_vline;
+	u32 off_pitch;
+	u32 gen_cntl;
+	u32 dp_pix_width;	/* acceleration */
+	u32 dp_chain_mask;	/* acceleration */
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+	u32 horz_stretching;
+	u32 vert_stretching;
+	u32 ext_vert_stretch;
+	u32 shadow_h_tot_disp;
+	u32 shadow_h_sync_strt_wid;
+	u32 shadow_v_tot_disp;
+	u32 shadow_v_sync_strt_wid;
+	u32 lcd_gen_cntl;
+	u32 lcd_config_panel;
+	u32 lcd_index;
+#endif
+};
+
+struct aty_interrupt {
+	wait_queue_head_t wait;
+	unsigned int count;
+	int pan_display;
+};
+
+struct pll_info {
+	int pll_max;
+	int pll_min;
+	int sclk, mclk, mclk_pm, xclk;
+	int ref_div;
+	int ref_clk;
+};
+
+typedef struct {
+	u16 unknown1;
+	u16 PCLK_min_freq;
+	u16 PCLK_max_freq;
+	u16 unknown2;
+	u16 ref_freq;
+	u16 ref_divider;
+	u16 unknown3;
+	u16 MCLK_pwd;
+	u16 MCLK_max_freq;
+	u16 XCLK_max_freq;
+	u16 SCLK_freq;
+} __attribute__ ((packed)) PLL_BLOCK_MACH64;
+
+struct pll_514 {
+	u8 m;
+	u8 n;
+};
+
+struct pll_18818 {
+	u32 program_bits;
+	u32 locationAddr;
+	u32 period_in_ps;
+	u32 post_divider;
+};
+
+struct pll_ct {
+	u8 pll_ref_div;
+	u8 pll_gen_cntl;
+	u8 mclk_fb_div;
+	u8 mclk_fb_mult; /* 2 ro 4 */
+	u8 sclk_fb_div;
+	u8 pll_vclk_cntl;
+	u8 vclk_post_div;
+	u8 vclk_fb_div;
+	u8 pll_ext_cntl;
+	u8 ext_vpll_cntl;
+	u8 spll_cntl2;
+	u32 dsp_config; /* Mach64 GTB DSP */
+	u32 dsp_on_off; /* Mach64 GTB DSP */
+	u32 dsp_loop_latency;
+	u32 fifo_size;
+	u32 xclkpagefaultdelay;
+	u32 xclkmaxrasdelay;
+	u8 xclk_ref_div;
+	u8 xclk_post_div;
+	u8 mclk_post_div_real;
+	u8 xclk_post_div_real;
+	u8 vclk_post_div_real;
+	u8 features;
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+	u32 xres; /* use for LCD stretching/scaling */
+#endif
+};
+
+/*
+	for pll_ct.features
+*/
+#define DONT_USE_SPLL 0x1
+#define DONT_USE_XDLL 0x2
+#define USE_CPUCLK    0x4
+#define POWERDOWN_PLL 0x8
+
+union aty_pll {
+	struct pll_ct ct;
+	struct pll_514 ibm514;
+	struct pll_18818 ics2595;
+};
+
+    /*
+     *  The hardware parameters for each card
+     */
+
+struct atyfb_par {
+	struct aty_cmap_regs __iomem *aty_cmap_regs;
+	struct { u8 red, green, blue; } palette[256];
+	const struct aty_dac_ops *dac_ops;
+	const struct aty_pll_ops *pll_ops;
+	void __iomem *ati_regbase;
+	unsigned long clk_wr_offset; /* meaning overloaded, clock id by CT */
+	struct crtc crtc;
+	union aty_pll pll;
+	struct pll_info pll_limits;
+	u32 features;
+	u32 ref_clk_per;
+	u32 pll_per;
+	u32 mclk_per;
+	u32 xclk_per;
+	u8 bus_type;
+	u8 ram_type;
+	u8 mem_refresh_rate;
+	u16 pci_id;
+	u32 accel_flags;
+	int blitter_may_be_busy;
+	int asleep;
+	int lock_blank;
+	unsigned long res_start;
+	unsigned long res_size;
+#ifdef __sparc__
+	struct pci_mmap_map *mmap_map;
+	u8 mmaped;
+#endif
+	int open;
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+	unsigned long bios_base_phys;
+	unsigned long bios_base;
+	unsigned long lcd_table;
+	u16 lcd_width;
+	u16 lcd_height;
+	u32 lcd_pixclock;
+	u16 lcd_refreshrate;
+	u16 lcd_htotal;
+	u16 lcd_hdisp;
+	u16 lcd_hsync_dly;
+	u16 lcd_hsync_len;
+	u16 lcd_vtotal;
+	u16 lcd_vdisp;
+	u16 lcd_vsync_len;
+	u16 lcd_right_margin;
+	u16 lcd_lower_margin;
+	u16 lcd_hblank_len;
+	u16 lcd_vblank_len;
+#endif
+	unsigned long aux_start; /* auxiliary aperture */
+	unsigned long aux_size;
+	struct aty_interrupt vblank;
+	unsigned long irq_flags;
+	unsigned int irq;
+	spinlock_t int_lock;
+#ifdef CONFIG_MTRR
+	int mtrr_aper;
+	int mtrr_reg;
+#endif
+};
+
+    /*
+     *  ATI Mach64 features
+     */
+
+#define M64_HAS(feature)	((par)->features & (M64F_##feature))
+
+#define M64F_RESET_3D		0x00000001
+#define M64F_MAGIC_FIFO		0x00000002
+#define M64F_GTB_DSP		0x00000004
+#define M64F_FIFO_32		0x00000008
+#define M64F_SDRAM_MAGIC_PLL	0x00000010
+#define M64F_MAGIC_POSTDIV	0x00000020
+#define M64F_INTEGRATED		0x00000040
+#define M64F_CT_BUS		0x00000080
+#define M64F_VT_BUS		0x00000100
+#define M64F_MOBIL_BUS		0x00000200
+#define M64F_GX			0x00000400
+#define M64F_CT			0x00000800
+#define M64F_VT			0x00001000
+#define M64F_GT			0x00002000
+#define M64F_MAGIC_VRAM_SIZE	0x00004000
+#define M64F_G3_PB_1_1		0x00008000
+#define M64F_G3_PB_1024x768	0x00010000
+#define M64F_EXTRA_BRIGHT	0x00020000
+#define M64F_LT_LCD_REGS	0x00040000
+#define M64F_XL_DLL		0x00080000
+#define M64F_MFB_FORCE_4	0x00100000
+#define M64F_HW_TRIPLE		0x00200000
+    /*
+     *  Register access
+     */
+
+static inline u32 aty_ld_le32(int regindex, const struct atyfb_par *par)
+{
+	/* Hack for bloc 1, should be cleanly optimized by compiler */
+	if (regindex >= 0x400)
+		regindex -= 0x800;
+
+#ifdef CONFIG_ATARI
+	return in_le32((volatile u32 *)(par->ati_regbase + regindex));
+#else
+	return readl(par->ati_regbase + regindex);
+#endif
+}
+
+static inline void aty_st_le32(int regindex, u32 val, const struct atyfb_par *par)
+{
+	/* Hack for bloc 1, should be cleanly optimized by compiler */
+	if (regindex >= 0x400)
+		regindex -= 0x800;
+
+#ifdef CONFIG_ATARI
+	out_le32((volatile u32 *)(par->ati_regbase + regindex), val);
+#else
+	writel(val, par->ati_regbase + regindex);
+#endif
+}
+
+static inline void aty_st_le16(int regindex, u16 val,
+			       const struct atyfb_par *par)
+{
+	/* Hack for bloc 1, should be cleanly optimized by compiler */
+	if (regindex >= 0x400)
+		regindex -= 0x800;
+#ifdef CONFIG_ATARI
+	out_le16((volatile u16 *)(par->ati_regbase + regindex), val);
+#else
+	writel(val, par->ati_regbase + regindex);
+#endif
+}
+
+static inline u8 aty_ld_8(int regindex, const struct atyfb_par *par)
+{
+	/* Hack for bloc 1, should be cleanly optimized by compiler */
+	if (regindex >= 0x400)
+		regindex -= 0x800;
+#ifdef CONFIG_ATARI
+	return in_8(par->ati_regbase + regindex);
+#else
+	return readb(par->ati_regbase + regindex);
+#endif
+}
+
+static inline void aty_st_8(int regindex, u8 val, const struct atyfb_par *par)
+{
+	/* Hack for bloc 1, should be cleanly optimized by compiler */
+	if (regindex >= 0x400)
+		regindex -= 0x800;
+
+#ifdef CONFIG_ATARI
+	out_8(par->ati_regbase + regindex, val);
+#else
+	writeb(val, par->ati_regbase + regindex);
+#endif
+}
+
+#if defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD)
+extern void aty_st_lcd(int index, u32 val, const struct atyfb_par *par);
+extern u32 aty_ld_lcd(int index, const struct atyfb_par *par);
+#endif
+
+    /*
+     *  DAC operations
+     */
+
+struct aty_dac_ops {
+	int (*set_dac) (const struct fb_info * info,
+		const union aty_pll * pll, u32 bpp, u32 accel);
+};
+
+extern const struct aty_dac_ops aty_dac_ibm514; /* IBM RGB514 */
+extern const struct aty_dac_ops aty_dac_ati68860b; /* ATI 68860-B */
+extern const struct aty_dac_ops aty_dac_att21c498; /* AT&T 21C498 */
+extern const struct aty_dac_ops aty_dac_unsupported; /* unsupported */
+extern const struct aty_dac_ops aty_dac_ct; /* Integrated */
+
+
+    /*
+     *  Clock operations
+     */
+
+struct aty_pll_ops {
+	int (*var_to_pll) (const struct fb_info * info, u32 vclk_per, u32 bpp, union aty_pll * pll);
+	u32 (*pll_to_var) (const struct fb_info * info, const union aty_pll * pll);
+	void (*set_pll)   (const struct fb_info * info, const union aty_pll * pll);
+	void (*get_pll)   (const struct fb_info *info, union aty_pll * pll);
+	int (*init_pll)   (const struct fb_info * info, union aty_pll * pll);
+};
+
+extern const struct aty_pll_ops aty_pll_ati18818_1; /* ATI 18818 */
+extern const struct aty_pll_ops aty_pll_stg1703; /* STG 1703 */
+extern const struct aty_pll_ops aty_pll_ch8398; /* Chrontel 8398 */
+extern const struct aty_pll_ops aty_pll_att20c408; /* AT&T 20C408 */
+extern const struct aty_pll_ops aty_pll_ibm514; /* IBM RGB514 */
+extern const struct aty_pll_ops aty_pll_unsupported; /* unsupported */
+extern const struct aty_pll_ops aty_pll_ct; /* Integrated */
+
+
+extern void aty_set_pll_ct(const struct fb_info *info, const union aty_pll *pll);
+extern u8 aty_ld_pll_ct(int offset, const struct atyfb_par *par);
+
+
+    /*
+     *  Hardware cursor support
+     */
+
+extern int aty_init_cursor(struct fb_info *info);
+
+    /*
+     *  Hardware acceleration
+     */
+
+static inline void wait_for_fifo(u16 entries, const struct atyfb_par *par)
+{
+	while ((aty_ld_le32(FIFO_STAT, par) & 0xffff) >
+	       ((u32) (0x8000 >> entries)));
+}
+
+static inline void wait_for_idle(struct atyfb_par *par)
+{
+	wait_for_fifo(16, par);
+	while ((aty_ld_le32(GUI_STAT, par) & 1) != 0);
+	par->blitter_may_be_busy = 0;
+}
+
+extern void aty_reset_engine(const struct atyfb_par *par);
+extern void aty_init_engine(struct atyfb_par *par, struct fb_info *info);
+extern int  atyfb_xl_init(struct fb_info *info);
+extern void aty_st_pll_ct(int offset, u8 val, const struct atyfb_par *par);
+extern u8   aty_ld_pll_ct(int offset, const struct atyfb_par *par);
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
new file mode 100644
index 0000000..8c42538
--- /dev/null
+++ b/drivers/video/aty/atyfb_base.c
@@ -0,0 +1,3720 @@
+/*
+ *  ATI Frame Buffer Device Driver Core
+ *
+ *	Copyright (C) 2004  Alex Kern <alex.kern@gmx.de>
+ *	Copyright (C) 1997-2001  Geert Uytterhoeven
+ *	Copyright (C) 1998  Bernd Harries
+ *	Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
+ *
+ *  This driver supports the following ATI graphics chips:
+ *    - ATI Mach64
+ *
+ *  To do: add support for
+ *    - ATI Rage128 (from aty128fb.c)
+ *    - ATI Radeon (from radeonfb.c)
+ *
+ *  This driver is partly based on the PowerMac console driver:
+ *
+ *	Copyright (C) 1996 Paul Mackerras
+ *
+ *  and on the PowerMac ATI/mach64 display driver:
+ *
+ *	Copyright (C) 1997 Michael AK Tesch
+ *
+ *	      with work by Jon Howell
+ *			   Harry AC Eaton
+ *			   Anthony Tong <atong@uiuc.edu>
+ *
+ *  Generic LCD support written by Daniel Mantione, ported from 2.4.20 by Alex Kern
+ *  Many Thanks to Ville Syrjälä for patches and fixing nasting 16 bit color bug.
+ *
+ *  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.
+ *
+ *  Many thanks to Nitya from ATI devrel for support and patience !
+ */
+
+/******************************************************************************
+
+  TODO:
+
+    - cursor support on all cards and all ramdacs.
+    - cursor parameters controlable via ioctl()s.
+    - guess PLL and MCLK based on the original PLL register values initialized
+      by Open Firmware (if they are initialized). BIOS is done
+
+    (Anyone with Mac to help with this?)
+
+******************************************************************************/
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/console.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include <video/mach64.h>
+#include "atyfb.h"
+#include "ati_ids.h"
+
+#ifdef __powerpc__
+#include <asm/prom.h>
+#include "../macmodes.h"
+#endif
+#ifdef __sparc__
+#include <asm/pbm.h>
+#include <asm/fbio.h>
+#endif
+
+#ifdef CONFIG_ADB_PMU
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#endif
+#ifdef CONFIG_BOOTX_TEXT
+#include <asm/btext.h>
+#endif
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+/*
+ * Debug flags.
+ */
+#undef DEBUG
+/*#define DEBUG*/
+
+/* Make sure n * PAGE_SIZE is protected at end of Aperture for GUI-regs */
+/*  - must be large enough to catch all GUI-Regs   */
+/*  - must be aligned to a PAGE boundary           */
+#define GUI_RESERVE	(1 * PAGE_SIZE)
+
+/* FIXME: remove the FAIL definition */
+#define FAIL(msg) do { printk(KERN_CRIT "atyfb: " msg "\n"); return -EINVAL; } while (0)
+#define FAIL_MAX(msg, x, _max_) do { if(x > _max_) { printk(KERN_CRIT "atyfb: " msg " %x(%x)\n", x, _max_); return -EINVAL; } } while (0)
+
+#ifdef DEBUG
+#define DPRINTK(fmt, args...)	printk(KERN_DEBUG "atyfb: " fmt, ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#define PRINTKI(fmt, args...)	printk(KERN_INFO "atyfb: " fmt, ## args)
+#define PRINTKE(fmt, args...)	 printk(KERN_ERR "atyfb: " fmt, ## args)
+
+#if defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD)
+static const u32 lt_lcd_regs[] = {
+	CONFIG_PANEL_LG,
+	LCD_GEN_CNTL_LG,
+	DSTN_CONTROL_LG,
+	HFB_PITCH_ADDR_LG,
+	HORZ_STRETCHING_LG,
+	VERT_STRETCHING_LG,
+	0, /* EXT_VERT_STRETCH */
+	LT_GIO_LG,
+	POWER_MANAGEMENT_LG
+};
+
+void aty_st_lcd(int index, u32 val, const struct atyfb_par *par)
+{
+	if (M64_HAS(LT_LCD_REGS)) {
+		aty_st_le32(lt_lcd_regs[index], val, par);
+	} else {
+		unsigned long temp;
+
+		/* write addr byte */
+		temp = aty_ld_le32(LCD_INDEX, par);
+		aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, par);
+		/* write the register value */
+		aty_st_le32(LCD_DATA, val, par);
+	}
+}
+
+u32 aty_ld_lcd(int index, const struct atyfb_par *par)
+{
+	if (M64_HAS(LT_LCD_REGS)) {
+		return aty_ld_le32(lt_lcd_regs[index], par);
+	} else {
+		unsigned long temp;
+
+		/* write addr byte */
+		temp = aty_ld_le32(LCD_INDEX, par);
+		aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, par);
+		/* read the register value */
+		return aty_ld_le32(LCD_DATA, par);
+	}
+}
+#endif /* defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD) */
+
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+/*
+ * ATIReduceRatio --
+ *
+ * Reduce a fraction by factoring out the largest common divider of the
+ * fraction's numerator and denominator.
+ */
+static void ATIReduceRatio(int *Numerator, int *Denominator)
+{
+    int Multiplier, Divider, Remainder;
+
+    Multiplier = *Numerator;
+    Divider = *Denominator;
+
+    while ((Remainder = Multiplier % Divider))
+    {
+        Multiplier = Divider;
+        Divider = Remainder;
+    }
+
+    *Numerator /= Divider;
+    *Denominator /= Divider;
+}
+#endif
+    /*
+     *  The Hardware parameters for each card
+     */
+
+struct aty_cmap_regs {
+	u8 windex;
+	u8 lut;
+	u8 mask;
+	u8 rindex;
+	u8 cntl;
+};
+
+struct pci_mmap_map {
+	unsigned long voff;
+	unsigned long poff;
+	unsigned long size;
+	unsigned long prot_flag;
+	unsigned long prot_mask;
+};
+
+static struct fb_fix_screeninfo atyfb_fix __devinitdata = {
+	.id		= "ATY Mach64",
+	.type		= FB_TYPE_PACKED_PIXELS,
+	.visual		= FB_VISUAL_PSEUDOCOLOR,
+	.xpanstep	= 8,
+	.ypanstep	= 1,
+};
+
+    /*
+     *  Frame buffer device API
+     */
+
+static int atyfb_open(struct fb_info *info, int user);
+static int atyfb_release(struct fb_info *info, int user);
+static int atyfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info);
+static int atyfb_set_par(struct fb_info *info);
+static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+	u_int transp, struct fb_info *info);
+static int atyfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
+static int atyfb_blank(int blank, struct fb_info *info);
+static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+	u_long arg, struct fb_info *info);
+extern void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
+extern void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
+extern void atyfb_imageblit(struct fb_info *info, const struct fb_image *image);
+#ifdef __sparc__
+static int atyfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma);
+#endif
+static int atyfb_sync(struct fb_info *info);
+
+    /*
+     *  Internal routines
+     */
+
+static int aty_init(struct fb_info *info, const char *name);
+#ifdef CONFIG_ATARI
+static int store_video_par(char *videopar, unsigned char m64_num);
+#endif
+
+static struct crtc saved_crtc;
+static union aty_pll saved_pll;
+static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc);
+
+static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc);
+static int aty_var_to_crtc(const struct fb_info *info, const struct fb_var_screeninfo *var, struct crtc *crtc);
+static int aty_crtc_to_var(const struct crtc *crtc, struct fb_var_screeninfo *var);
+static void set_off_pitch(struct atyfb_par *par, const struct fb_info *info);
+#ifdef CONFIG_PPC
+static int read_aty_sense(const struct atyfb_par *par);
+#endif
+
+
+    /*
+     *  Interface used by the world
+     */
+
+static struct fb_var_screeninfo default_var = {
+	/* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
+	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, 39722, 48, 16, 33, 10, 96, 2,
+	0, FB_VMODE_NONINTERLACED
+};
+
+static struct fb_videomode defmode = {
+	/* 640x480 @ 60 Hz, 31.5 kHz hsync */
+	NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2,
+	0, FB_VMODE_NONINTERLACED
+};
+
+static struct fb_ops atyfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_open	= atyfb_open,
+	.fb_release	= atyfb_release,
+	.fb_check_var	= atyfb_check_var,
+	.fb_set_par	= atyfb_set_par,
+	.fb_setcolreg	= atyfb_setcolreg,
+	.fb_pan_display	= atyfb_pan_display,
+	.fb_blank	= atyfb_blank,
+	.fb_ioctl	= atyfb_ioctl,
+	.fb_fillrect	= atyfb_fillrect,
+	.fb_copyarea	= atyfb_copyarea,
+	.fb_imageblit	= atyfb_imageblit,
+	.fb_cursor	= soft_cursor,
+#ifdef __sparc__
+	.fb_mmap	= atyfb_mmap,
+#endif
+	.fb_sync	= atyfb_sync,
+};
+
+static int noaccel;
+#ifdef CONFIG_MTRR
+static int nomtrr;
+#endif
+static int vram;
+static int pll;
+static int mclk;
+static int xclk;
+static int comp_sync __initdata = -1;
+static char *mode;
+
+#ifdef CONFIG_PPC
+static int default_vmode __initdata = VMODE_CHOOSE;
+static int default_cmode __initdata = CMODE_CHOOSE;
+
+module_param_named(vmode, default_vmode, int, 0);
+MODULE_PARM_DESC(vmode, "int: video mode for mac");
+module_param_named(cmode, default_cmode, int, 0);
+MODULE_PARM_DESC(cmode, "int: color mode for mac");
+#endif
+
+#ifdef CONFIG_ATARI
+static unsigned int mach64_count __initdata = 0;
+static unsigned long phys_vmembase[FB_MAX] __initdata = { 0, };
+static unsigned long phys_size[FB_MAX] __initdata = { 0, };
+static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, };
+#endif
+
+/* top -> down is an evolution of mach64 chipset, any corrections? */
+#define ATI_CHIP_88800GX   (M64F_GX)
+#define ATI_CHIP_88800CX   (M64F_GX)
+
+#define ATI_CHIP_264CT     (M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | M64F_MAGIC_FIFO)
+#define ATI_CHIP_264ET     (M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | M64F_MAGIC_FIFO)
+
+#define ATI_CHIP_264VT     (M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_MAGIC_FIFO)
+#define ATI_CHIP_264GT     (M64F_GT | M64F_INTEGRATED               | M64F_MAGIC_FIFO | M64F_EXTRA_BRIGHT)
+
+#define ATI_CHIP_264VTB    (M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_GTB_DSP)
+#define ATI_CHIP_264VT3    (M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL)
+#define ATI_CHIP_264VT4    (M64F_VT | M64F_INTEGRATED               | M64F_GTB_DSP)
+
+#define ATI_CHIP_264LT     (M64F_GT | M64F_INTEGRATED               | M64F_GTB_DSP)
+
+/* make sets shorter */
+#define ATI_MODERN_SET     (M64F_GT | M64F_INTEGRATED               | M64F_GTB_DSP | M64F_EXTRA_BRIGHT)
+
+#define ATI_CHIP_264GTB    (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL)
+/*#define ATI_CHIP_264GTDVD  ?*/
+#define ATI_CHIP_264LTG    (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL)
+
+#define ATI_CHIP_264GT2C   (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL | M64F_HW_TRIPLE)
+#define ATI_CHIP_264GTPRO  (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D)
+#define ATI_CHIP_264LTPRO  (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D)
+
+#define ATI_CHIP_264XL     (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4)
+#define ATI_CHIP_MOBILITY  (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4 | M64F_MOBIL_BUS)
+
+static struct {
+	u16 pci_id;
+	const char *name;
+	int pll, mclk, xclk;
+	u32 features;
+} aty_chips[] __devinitdata = {
+#ifdef CONFIG_FB_ATY_GX
+	/* Mach64 GX */
+	{ PCI_CHIP_MACH64GX, "ATI888GX00 (Mach64 GX)", 135, 50, 50, ATI_CHIP_88800GX },
+	{ PCI_CHIP_MACH64CX, "ATI888CX00 (Mach64 CX)", 135, 50, 50, ATI_CHIP_88800CX },
+#endif /* CONFIG_FB_ATY_GX */
+
+#ifdef CONFIG_FB_ATY_CT
+	{ PCI_CHIP_MACH64CT, "ATI264CT (Mach64 CT)", 135, 60, 60, ATI_CHIP_264CT },
+	{ PCI_CHIP_MACH64ET, "ATI264ET (Mach64 ET)", 135, 60, 60, ATI_CHIP_264ET },
+	{ PCI_CHIP_MACH64VT, "ATI264VT? (Mach64 VT)", 170, 67, 67, ATI_CHIP_264VT },
+	{ PCI_CHIP_MACH64GT, "3D RAGE (Mach64 GT)", 135, 63, 63, ATI_CHIP_264GT },
+	/* FIXME { ...ATI_264GU, maybe ATI_CHIP_264GTDVD }, */
+	{ PCI_CHIP_MACH64GU, "3D RAGE II+ (Mach64 GTB)", 200, 67, 67, ATI_CHIP_264GTB  },
+	{ PCI_CHIP_MACH64VU, "ATI264VTB (Mach64 VU)", 200, 67, 67, ATI_CHIP_264VT3 },
+
+	{ PCI_CHIP_MACH64LT, "3D RAGE LT (Mach64 LT)", 135, 63, 63, ATI_CHIP_264LT },
+	 /* FIXME chipset maybe ATI_CHIP_264LTPRO ? */
+	{ PCI_CHIP_MACH64LG, "3D RAGE LT-G (Mach64 LG)", 230, 63, 63, ATI_CHIP_264LTG | M64F_LT_LCD_REGS | M64F_G3_PB_1024x768 },
+
+	{ PCI_CHIP_MACH64VV, "ATI264VT4 (Mach64 VV)", 230, 83, 83, ATI_CHIP_264VT4 },
+
+	{ PCI_CHIP_MACH64GV, "3D RAGE IIC (Mach64 GV, PCI)", 230, 83, 83, ATI_CHIP_264GT2C },
+	{ PCI_CHIP_MACH64GW, "3D RAGE IIC (Mach64 GW, AGP)", 230, 83, 83, ATI_CHIP_264GT2C },
+	{ PCI_CHIP_MACH64GY, "3D RAGE IIC (Mach64 GY, PCI)", 230, 83, 83, ATI_CHIP_264GT2C },
+	{ PCI_CHIP_MACH64GZ, "3D RAGE IIC (Mach64 GZ, AGP)", 230, 83, 83, ATI_CHIP_264GT2C },
+
+	{ PCI_CHIP_MACH64GB, "3D RAGE PRO (Mach64 GB, BGA, AGP)", 230, 100, 100, ATI_CHIP_264GTPRO },
+	{ PCI_CHIP_MACH64GD, "3D RAGE PRO (Mach64 GD, BGA, AGP 1x)", 230, 100, 100, ATI_CHIP_264GTPRO },
+	{ PCI_CHIP_MACH64GI, "3D RAGE PRO (Mach64 GI, BGA, PCI)", 230, 100, 100, ATI_CHIP_264GTPRO | M64F_MAGIC_VRAM_SIZE },
+	{ PCI_CHIP_MACH64GP, "3D RAGE PRO (Mach64 GP, PQFP, PCI)", 230, 100, 100, ATI_CHIP_264GTPRO },
+	{ PCI_CHIP_MACH64GQ, "3D RAGE PRO (Mach64 GQ, PQFP, PCI, limited 3D)", 230, 100, 100, ATI_CHIP_264GTPRO },
+
+	{ PCI_CHIP_MACH64LB, "3D RAGE LT PRO (Mach64 LB, AGP)", 236, 75, 100, ATI_CHIP_264LTPRO },
+	{ PCI_CHIP_MACH64LD, "3D RAGE LT PRO (Mach64 LD, AGP)", 230, 100, 100, ATI_CHIP_264LTPRO },
+	{ PCI_CHIP_MACH64LI, "3D RAGE LT PRO (Mach64 LI, PCI)", 230, 100, 100, ATI_CHIP_264LTPRO | M64F_G3_PB_1_1 | M64F_G3_PB_1024x768 },
+	{ PCI_CHIP_MACH64LP, "3D RAGE LT PRO (Mach64 LP, PCI)", 230, 100, 100, ATI_CHIP_264LTPRO },
+	{ PCI_CHIP_MACH64LQ, "3D RAGE LT PRO (Mach64 LQ, PCI)", 230, 100, 100, ATI_CHIP_264LTPRO },
+
+	{ PCI_CHIP_MACH64GM, "3D RAGE XL (Mach64 GM, AGP)", 230, 83, 63, ATI_CHIP_264XL },
+	{ PCI_CHIP_MACH64GN, "3D RAGE XL (Mach64 GN, AGP)", 230, 83, 63, ATI_CHIP_264XL },
+	{ PCI_CHIP_MACH64GO, "3D RAGE XL (Mach64 GO, PCI-66/BGA)", 230, 83, 63, ATI_CHIP_264XL },
+	{ PCI_CHIP_MACH64GR, "3D RAGE XL (Mach64 GR, PCI-33MHz)", 230, 83, 63, ATI_CHIP_264XL },
+	{ PCI_CHIP_MACH64GL, "3D RAGE XL (Mach64 GL, PCI)", 230, 83, 63, ATI_CHIP_264XL },
+	{ PCI_CHIP_MACH64GS, "3D RAGE XL (Mach64 GS, PCI)", 230, 83, 63, ATI_CHIP_264XL },
+
+	{ PCI_CHIP_MACH64LM, "3D RAGE Mobility P/M (Mach64 LM, AGP 2x)", 230, 83, 125, ATI_CHIP_MOBILITY },
+	{ PCI_CHIP_MACH64LN, "3D RAGE Mobility L (Mach64 LN, AGP 2x)", 230, 83, 125, ATI_CHIP_MOBILITY },
+	{ PCI_CHIP_MACH64LR, "3D RAGE Mobility P/M (Mach64 LR, PCI)", 230, 83, 125, ATI_CHIP_MOBILITY },
+	{ PCI_CHIP_MACH64LS, "3D RAGE Mobility L (Mach64 LS, PCI)", 230, 83, 125, ATI_CHIP_MOBILITY },
+#endif /* CONFIG_FB_ATY_CT */
+};
+
+/* can not fail */
+static int __devinit correct_chipset(struct atyfb_par *par)
+{
+	u8 rev;
+	u16 type;
+	u32 chip_id;
+	const char *name;
+	int i;
+
+	for (i = sizeof(aty_chips) / sizeof(*aty_chips) - 1; i >= 0; i--)
+		if (par->pci_id == aty_chips[i].pci_id)
+			break;
+
+	name = aty_chips[i].name;
+	par->pll_limits.pll_max = aty_chips[i].pll;
+	par->pll_limits.mclk = aty_chips[i].mclk;
+	par->pll_limits.xclk = aty_chips[i].xclk;
+	par->features = aty_chips[i].features;
+
+	chip_id = aty_ld_le32(CONFIG_CHIP_ID, par);
+	type = chip_id & CFG_CHIP_TYPE;
+	rev = (chip_id & CFG_CHIP_REV) >> 24;
+
+	switch(par->pci_id) {
+#ifdef CONFIG_FB_ATY_GX
+	case PCI_CHIP_MACH64GX:
+		if(type != 0x00d7)
+			return -ENODEV;
+		break;
+	case PCI_CHIP_MACH64CX:
+		if(type != 0x0057)
+			return -ENODEV;
+		break;
+#endif
+#ifdef CONFIG_FB_ATY_CT
+	case PCI_CHIP_MACH64VT:
+		rev &= 0xc7;
+		if(rev == 0x00) {
+			name = "ATI264VTA3 (Mach64 VT)";
+			par->pll_limits.pll_max = 170;
+			par->pll_limits.mclk = 67;
+			par->pll_limits.xclk = 67;
+			par->features = ATI_CHIP_264VT;
+		} else if(rev == 0x40) {
+			name = "ATI264VTA4 (Mach64 VT)";
+			par->pll_limits.pll_max = 200;
+			par->pll_limits.mclk = 67;
+			par->pll_limits.xclk = 67;
+			par->features = ATI_CHIP_264VT | M64F_MAGIC_POSTDIV;
+		} else {
+			name = "ATI264VTB (Mach64 VT)";
+			par->pll_limits.pll_max = 200;
+			par->pll_limits.mclk = 67;
+			par->pll_limits.xclk = 67;
+			par->features = ATI_CHIP_264VTB;
+		}
+		break;
+	case PCI_CHIP_MACH64GT:
+		rev &= 0x07;
+		if(rev == 0x01) {
+			par->pll_limits.pll_max = 170;
+			par->pll_limits.mclk = 67;
+			par->pll_limits.xclk = 67;
+			par->features = ATI_CHIP_264GTB;
+		} else if(rev == 0x02) {
+			par->pll_limits.pll_max = 200;
+			par->pll_limits.mclk = 67;
+			par->pll_limits.xclk = 67;
+			par->features = ATI_CHIP_264GTB;
+		}
+		break;
+#endif
+	}
+
+	PRINTKI("%s [0x%04x rev 0x%02x]\n", name, type, rev);
+	return 0;
+}
+
+static char ram_dram[] __devinitdata = "DRAM";
+static char ram_resv[] __devinitdata = "RESV";
+#ifdef CONFIG_FB_ATY_GX
+static char ram_vram[] __devinitdata = "VRAM";
+#endif /* CONFIG_FB_ATY_GX */
+#ifdef CONFIG_FB_ATY_CT
+static char ram_edo[] __devinitdata = "EDO";
+static char ram_sdram[] __devinitdata = "SDRAM (1:1)";
+static char ram_sgram[] __devinitdata = "SGRAM (1:1)";
+static char ram_sdram32[] __devinitdata = "SDRAM (2:1) (32-bit)";
+static char ram_off[] __devinitdata = "OFF";
+#endif /* CONFIG_FB_ATY_CT */
+
+
+static u32 pseudo_palette[17];
+
+#ifdef CONFIG_FB_ATY_GX
+static char *aty_gx_ram[8] __devinitdata = {
+	ram_dram, ram_vram, ram_vram, ram_dram,
+	ram_dram, ram_vram, ram_vram, ram_resv
+};
+#endif /* CONFIG_FB_ATY_GX */
+
+#ifdef CONFIG_FB_ATY_CT
+static char *aty_ct_ram[8] __devinitdata = {
+	ram_off, ram_dram, ram_edo, ram_edo,
+	ram_sdram, ram_sgram, ram_sdram32, ram_resv
+};
+#endif /* CONFIG_FB_ATY_CT */
+
+static u32 atyfb_get_pixclock(struct fb_var_screeninfo *var, struct atyfb_par *par)
+{
+	u32 pixclock = var->pixclock;
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+	u32 lcd_on_off;
+	par->pll.ct.xres = 0;
+	if (par->lcd_table != 0) {
+		lcd_on_off = aty_ld_lcd(LCD_GEN_CNTL, par);
+		if(lcd_on_off & LCD_ON) {
+			par->pll.ct.xres = var->xres;
+			pixclock = par->lcd_pixclock;
+		}
+	}
+#endif
+	return pixclock;
+}
+
+#if defined(CONFIG_PPC)
+
+/*
+ *  Apple monitor sense
+ */
+
+static int __init read_aty_sense(const struct atyfb_par *par)
+{
+	int sense, i;
+
+	aty_st_le32(GP_IO, 0x31003100, par); /* drive outputs high */
+	__delay(200);
+	aty_st_le32(GP_IO, 0, par); /* turn off outputs */
+	__delay(2000);
+	i = aty_ld_le32(GP_IO, par); /* get primary sense value */
+	sense = ((i & 0x3000) >> 3) | (i & 0x100);
+
+	/* drive each sense line low in turn and collect the other 2 */
+	aty_st_le32(GP_IO, 0x20000000, par); /* drive A low */
+	__delay(2000);
+	i = aty_ld_le32(GP_IO, par);
+	sense |= ((i & 0x1000) >> 7) | ((i & 0x100) >> 4);
+	aty_st_le32(GP_IO, 0x20002000, par); /* drive A high again */
+	__delay(200);
+
+	aty_st_le32(GP_IO, 0x10000000, par); /* drive B low */
+	__delay(2000);
+	i = aty_ld_le32(GP_IO, par);
+	sense |= ((i & 0x2000) >> 10) | ((i & 0x100) >> 6);
+	aty_st_le32(GP_IO, 0x10001000, par); /* drive B high again */
+	__delay(200);
+
+	aty_st_le32(GP_IO, 0x01000000, par); /* drive C low */
+	__delay(2000);
+	sense |= (aty_ld_le32(GP_IO, par) & 0x3000) >> 12;
+	aty_st_le32(GP_IO, 0, par); /* turn off outputs */
+	return sense;
+}
+
+#endif /* defined(CONFIG_PPC) */
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ *  CRTC programming
+ */
+
+static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc)
+{
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+	if (par->lcd_table != 0) {
+		if(!M64_HAS(LT_LCD_REGS)) {
+		    crtc->lcd_index = aty_ld_le32(LCD_INDEX, par);
+		    aty_st_le32(LCD_INDEX, crtc->lcd_index, par);
+		}
+		crtc->lcd_config_panel = aty_ld_lcd(CONFIG_PANEL, par);
+		crtc->lcd_gen_cntl = aty_ld_lcd(LCD_GEN_CNTL, par);
+
+
+		/* switch to non shadow registers */
+		aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl &
+                    ~(CRTC_RW_SELECT | SHADOW_EN | SHADOW_RW_EN), par);
+
+		/* save stretching */
+		crtc->horz_stretching = aty_ld_lcd(HORZ_STRETCHING, par);
+		crtc->vert_stretching = aty_ld_lcd(VERT_STRETCHING, par);
+		if (!M64_HAS(LT_LCD_REGS))
+			crtc->ext_vert_stretch = aty_ld_lcd(EXT_VERT_STRETCH, par);
+	}
+#endif
+	crtc->h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, par);
+	crtc->h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, par);
+	crtc->v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, par);
+	crtc->v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, par);
+	crtc->vline_crnt_vline = aty_ld_le32(CRTC_VLINE_CRNT_VLINE, par);
+	crtc->off_pitch = aty_ld_le32(CRTC_OFF_PITCH, par);
+	crtc->gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par);
+
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+	if (par->lcd_table != 0) {
+		/* switch to shadow registers */
+		aty_st_lcd(LCD_GEN_CNTL, (crtc->lcd_gen_cntl & ~CRTC_RW_SELECT) |
+			SHADOW_EN | SHADOW_RW_EN, par);
+
+		crtc->shadow_h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, par);
+		crtc->shadow_h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, par);
+		crtc->shadow_v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, par);
+		crtc->shadow_v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, par);
+
+		aty_st_le32(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par);
+	}
+#endif /* CONFIG_FB_ATY_GENERIC_LCD */
+}
+
+static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc)
+{
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+	if (par->lcd_table != 0) {
+		/* stop CRTC */
+		aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl & ~(CRTC_EXT_DISP_EN | CRTC_EN), par);
+
+		/* update non-shadow registers first */
+		aty_st_lcd(CONFIG_PANEL, crtc->lcd_config_panel, par);
+		aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl &
+			~(CRTC_RW_SELECT | SHADOW_EN | SHADOW_RW_EN), par);
+
+		/* temporarily disable stretching */
+		aty_st_lcd(HORZ_STRETCHING,
+			crtc->horz_stretching &
+			~(HORZ_STRETCH_MODE | HORZ_STRETCH_EN), par);
+		aty_st_lcd(VERT_STRETCHING,
+			crtc->vert_stretching &
+			~(VERT_STRETCH_RATIO1 | VERT_STRETCH_RATIO2 |
+			VERT_STRETCH_USE0 | VERT_STRETCH_EN), par);
+	}
+#endif
+	/* turn off CRT */
+	aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl & ~CRTC_EN, par);
+
+	DPRINTK("setting up CRTC\n");
+	DPRINTK("set primary CRT to %ix%i %c%c composite %c\n",
+	    ((((crtc->h_tot_disp>>16) & 0xff) + 1)<<3), (((crtc->v_tot_disp>>16) & 0x7ff) + 1),
+	    (crtc->h_sync_strt_wid & 0x200000)?'N':'P', (crtc->v_sync_strt_wid & 0x200000)?'N':'P',
+	    (crtc->gen_cntl & CRTC_CSYNC_EN)?'P':'N');
+
+	DPRINTK("CRTC_H_TOTAL_DISP: %x\n",crtc->h_tot_disp);
+	DPRINTK("CRTC_H_SYNC_STRT_WID: %x\n",crtc->h_sync_strt_wid);
+	DPRINTK("CRTC_V_TOTAL_DISP: %x\n",crtc->v_tot_disp);
+	DPRINTK("CRTC_V_SYNC_STRT_WID: %x\n",crtc->v_sync_strt_wid);
+	DPRINTK("CRTC_OFF_PITCH: %x\n", crtc->off_pitch);
+	DPRINTK("CRTC_VLINE_CRNT_VLINE: %x\n", crtc->vline_crnt_vline);
+	DPRINTK("CRTC_GEN_CNTL: %x\n",crtc->gen_cntl);
+
+	aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_tot_disp, par);
+	aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid, par);
+	aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_tot_disp, par);
+	aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid, par);
+	aty_st_le32(CRTC_OFF_PITCH, crtc->off_pitch, par);
+	aty_st_le32(CRTC_VLINE_CRNT_VLINE, crtc->vline_crnt_vline, par);
+
+	aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl, par);
+#if 0
+	FIXME
+	if (par->accel_flags & FB_ACCELF_TEXT)
+		aty_init_engine(par, info);
+#endif
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+	/* after setting the CRTC registers we should set the LCD registers. */
+	if (par->lcd_table != 0) {
+		/* switch to shadow registers */
+		aty_st_lcd(LCD_GEN_CNTL, (crtc->lcd_gen_cntl & ~CRTC_RW_SELECT) |
+			(SHADOW_EN | SHADOW_RW_EN), par);
+
+		DPRINTK("set secondary CRT to %ix%i %c%c\n",
+		    ((((crtc->shadow_h_tot_disp>>16) & 0xff) + 1)<<3), (((crtc->shadow_v_tot_disp>>16) & 0x7ff) + 1),
+		    (crtc->shadow_h_sync_strt_wid & 0x200000)?'N':'P', (crtc->shadow_v_sync_strt_wid & 0x200000)?'N':'P');
+
+		DPRINTK("SHADOW CRTC_H_TOTAL_DISP: %x\n", crtc->shadow_h_tot_disp);
+		DPRINTK("SHADOW CRTC_H_SYNC_STRT_WID: %x\n", crtc->shadow_h_sync_strt_wid);
+		DPRINTK("SHADOW CRTC_V_TOTAL_DISP: %x\n", crtc->shadow_v_tot_disp);
+		DPRINTK("SHADOW CRTC_V_SYNC_STRT_WID: %x\n", crtc->shadow_v_sync_strt_wid);
+
+		aty_st_le32(CRTC_H_TOTAL_DISP, crtc->shadow_h_tot_disp, par);
+		aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->shadow_h_sync_strt_wid, par);
+		aty_st_le32(CRTC_V_TOTAL_DISP, crtc->shadow_v_tot_disp, par);
+		aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->shadow_v_sync_strt_wid, par);
+
+		/* restore CRTC selection & shadow state and enable stretching */
+		DPRINTK("LCD_GEN_CNTL: %x\n", crtc->lcd_gen_cntl);
+		DPRINTK("HORZ_STRETCHING: %x\n", crtc->horz_stretching);
+		DPRINTK("VERT_STRETCHING: %x\n", crtc->vert_stretching);
+		if(!M64_HAS(LT_LCD_REGS))
+		    DPRINTK("EXT_VERT_STRETCH: %x\n", crtc->ext_vert_stretch);
+
+		aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par);
+		aty_st_lcd(HORZ_STRETCHING, crtc->horz_stretching, par);
+		aty_st_lcd(VERT_STRETCHING, crtc->vert_stretching, par);
+		if(!M64_HAS(LT_LCD_REGS)) {
+		    aty_st_lcd(EXT_VERT_STRETCH, crtc->ext_vert_stretch, par);
+		    aty_ld_le32(LCD_INDEX, par);
+		    aty_st_le32(LCD_INDEX, crtc->lcd_index, par);
+		}
+	}
+#endif /* CONFIG_FB_ATY_GENERIC_LCD */
+}
+
+static int aty_var_to_crtc(const struct fb_info *info,
+	const struct fb_var_screeninfo *var, struct crtc *crtc)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp;
+	u32 sync, vmode, vdisplay;
+	u32 h_total, h_disp, h_sync_strt, h_sync_end, h_sync_dly, h_sync_wid, h_sync_pol;
+	u32 v_total, v_disp, v_sync_strt, v_sync_end, v_sync_wid, v_sync_pol, c_sync;
+	u32 pix_width, dp_pix_width, dp_chain_mask;
+
+	/* input */
+	xres = var->xres;
+	yres = var->yres;
+	vxres = var->xres_virtual;
+	vyres = var->yres_virtual;
+	xoffset = var->xoffset;
+	yoffset = var->yoffset;
+	bpp = var->bits_per_pixel;
+	if (bpp == 16)
+		bpp = (var->green.length == 5) ? 15 : 16;
+	sync = var->sync;
+	vmode = var->vmode;
+
+	/* convert (and round up) and validate */
+	if (vxres < xres + xoffset)
+		vxres = xres + xoffset;
+	h_disp = xres;
+
+	if (vyres < yres + yoffset)
+		vyres = yres + yoffset;
+	v_disp = yres;
+
+	if (bpp <= 8) {
+		bpp = 8;
+		pix_width = CRTC_PIX_WIDTH_8BPP;
+		dp_pix_width =
+		    HOST_8BPP | SRC_8BPP | DST_8BPP |
+		    BYTE_ORDER_LSB_TO_MSB;
+		dp_chain_mask = DP_CHAIN_8BPP;
+	} else if (bpp <= 15) {
+		bpp = 16;
+		pix_width = CRTC_PIX_WIDTH_15BPP;
+		dp_pix_width = HOST_15BPP | SRC_15BPP | DST_15BPP |
+		    BYTE_ORDER_LSB_TO_MSB;
+		dp_chain_mask = DP_CHAIN_15BPP;
+	} else if (bpp <= 16) {
+		bpp = 16;
+		pix_width = CRTC_PIX_WIDTH_16BPP;
+		dp_pix_width = HOST_16BPP | SRC_16BPP | DST_16BPP |
+		    BYTE_ORDER_LSB_TO_MSB;
+		dp_chain_mask = DP_CHAIN_16BPP;
+	} else if (bpp <= 24 && M64_HAS(INTEGRATED)) {
+		bpp = 24;
+		pix_width = CRTC_PIX_WIDTH_24BPP;
+		dp_pix_width =
+		    HOST_8BPP | SRC_8BPP | DST_8BPP |
+		    BYTE_ORDER_LSB_TO_MSB;
+		dp_chain_mask = DP_CHAIN_24BPP;
+	} else if (bpp <= 32) {
+		bpp = 32;
+		pix_width = CRTC_PIX_WIDTH_32BPP;
+		dp_pix_width = HOST_32BPP | SRC_32BPP | DST_32BPP |
+		    BYTE_ORDER_LSB_TO_MSB;
+		dp_chain_mask = DP_CHAIN_32BPP;
+	} else
+		FAIL("invalid bpp");
+
+	if (vxres * vyres * bpp / 8 > info->fix.smem_len)
+		FAIL("not enough video RAM");
+
+	h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
+	v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;
+
+	if((xres > 1600) || (yres > 1200)) {
+		FAIL("MACH64 chips are designed for max 1600x1200\n"
+		"select anoter resolution.");
+	}
+	h_sync_strt = h_disp + var->right_margin;
+	h_sync_end = h_sync_strt + var->hsync_len;
+	h_sync_dly  = var->right_margin & 7;
+	h_total = h_sync_end + h_sync_dly + var->left_margin;
+
+	v_sync_strt = v_disp + var->lower_margin;
+	v_sync_end = v_sync_strt + var->vsync_len;
+	v_total = v_sync_end + var->upper_margin;
+
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+	if (par->lcd_table != 0) {
+		if(!M64_HAS(LT_LCD_REGS)) {
+		    u32 lcd_index = aty_ld_le32(LCD_INDEX, par);
+		    crtc->lcd_index = lcd_index &
+			~(LCD_INDEX_MASK | LCD_DISPLAY_DIS | LCD_SRC_SEL | CRTC2_DISPLAY_DIS);
+		    aty_st_le32(LCD_INDEX, lcd_index, par);
+		}
+
+		if (!M64_HAS(MOBIL_BUS))
+			crtc->lcd_index |= CRTC2_DISPLAY_DIS;
+
+		crtc->lcd_config_panel = aty_ld_lcd(CONFIG_PANEL, par) | 0x4000;
+		crtc->lcd_gen_cntl = aty_ld_lcd(LCD_GEN_CNTL, par) & ~CRTC_RW_SELECT;
+
+		crtc->lcd_gen_cntl &=
+			~(HORZ_DIVBY2_EN | DIS_HOR_CRT_DIVBY2 | TVCLK_PM_EN |
+			/*VCLK_DAC_PM_EN | USE_SHADOWED_VEND |*/
+			USE_SHADOWED_ROWCUR | SHADOW_EN | SHADOW_RW_EN);
+		crtc->lcd_gen_cntl |= DONT_SHADOW_VPAR | LOCK_8DOT;
+
+		if((crtc->lcd_gen_cntl & LCD_ON) &&
+			((xres > par->lcd_width) || (yres > par->lcd_height))) {
+			/* We cannot display the mode on the LCD. If the CRT is enabled
+			   we can turn off the LCD.
+			   If the CRT is off, it isn't a good idea to switch it on; we don't
+			   know if one is connected. So it's better to fail then.
+			 */
+			if (crtc->lcd_gen_cntl & CRT_ON) {
+				PRINTKI("Disable lcd panel, because video mode does not fit.\n");
+				crtc->lcd_gen_cntl &= ~LCD_ON;
+				/*aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par);*/
+			} else {
+				FAIL("Video mode exceeds size of lcd panel.\nConnect this computer to a conventional monitor if you really need this mode.");
+			}
+		}
+	}
+
+	if ((par->lcd_table != 0) && (crtc->lcd_gen_cntl & LCD_ON)) {
+		int VScan = 1;
+		/* bpp -> bytespp, 1,4 -> 0; 8 -> 2; 15,16 -> 1; 24 -> 6; 32 -> 5
+		const u8 DFP_h_sync_dly_LT[] = { 0, 2, 1, 6, 5 };
+		const u8 ADD_to_strt_wid_and_dly_LT_DAC[] = { 0, 5, 6, 9, 9, 12, 12 };  */
+
+		vmode &= ~(FB_VMODE_DOUBLE | FB_VMODE_INTERLACED);
+
+		/* This is horror! When we simulate, say 640x480 on an 800x600
+		   lcd monitor, the CRTC should be programmed 800x600 values for
+		   the non visible part, but 640x480 for the visible part.
+		   This code has been tested on a laptop with it's 1400x1050 lcd
+		   monitor and a conventional monitor both switched on.
+		   Tested modes: 1280x1024, 1152x864, 1024x768, 800x600,
+		    works with little glitches also with DOUBLESCAN modes
+		 */
+		if (yres < par->lcd_height) {
+			VScan = par->lcd_height / yres;
+			if(VScan > 1) {
+				VScan = 2;
+				vmode |= FB_VMODE_DOUBLE;
+			}
+		}
+
+		h_sync_strt = h_disp + par->lcd_right_margin;
+		h_sync_end = h_sync_strt + par->lcd_hsync_len;
+		h_sync_dly = /*DFP_h_sync_dly[ ( bpp + 1 ) / 3 ]; */par->lcd_hsync_dly;
+		h_total = h_disp + par->lcd_hblank_len;
+
+		v_sync_strt = v_disp + par->lcd_lower_margin / VScan;
+		v_sync_end = v_sync_strt + par->lcd_vsync_len / VScan;
+		v_total = v_disp + par->lcd_vblank_len / VScan;
+	}
+#endif /* CONFIG_FB_ATY_GENERIC_LCD */
+
+	h_disp = (h_disp >> 3) - 1;
+	h_sync_strt = (h_sync_strt >> 3) - 1;
+	h_sync_end = (h_sync_end >> 3) - 1;
+	h_total = (h_total >> 3) - 1;
+	h_sync_wid = h_sync_end - h_sync_strt;
+
+	FAIL_MAX("h_disp too large", h_disp, 0xff);
+	FAIL_MAX("h_sync_strt too large", h_sync_strt, 0x1ff);
+	/*FAIL_MAX("h_sync_wid too large", h_sync_wid, 0x1f);*/
+	if(h_sync_wid > 0x1f)
+		h_sync_wid = 0x1f;
+	FAIL_MAX("h_total too large", h_total, 0x1ff);
+
+	if (vmode & FB_VMODE_DOUBLE) {
+		v_disp <<= 1;
+		v_sync_strt <<= 1;
+		v_sync_end <<= 1;
+		v_total <<= 1;
+	}
+
+	vdisplay = yres;
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+	if ((par->lcd_table != 0) && (crtc->lcd_gen_cntl & LCD_ON))
+		vdisplay  = par->lcd_height;
+#endif
+
+	if(vdisplay < 400) {
+		h_sync_pol = 1;
+		v_sync_pol = 0;
+	} else if(vdisplay < 480) {
+		h_sync_pol = 0;
+		v_sync_pol = 1;
+	} else if(vdisplay < 768) {
+		h_sync_pol = 0;
+		v_sync_pol = 0;
+	} else {
+		h_sync_pol = 1;
+		v_sync_pol = 1;
+	}
+
+	v_disp--;
+	v_sync_strt--;
+	v_sync_end--;
+	v_total--;
+	v_sync_wid = v_sync_end - v_sync_strt;
+
+	FAIL_MAX("v_disp too large", v_disp, 0x7ff);
+	FAIL_MAX("v_sync_stsrt too large", v_sync_strt, 0x7ff);
+	/*FAIL_MAX("v_sync_wid too large", v_sync_wid, 0x1f);*/
+	if(v_sync_wid > 0x1f)
+		v_sync_wid = 0x1f;
+	FAIL_MAX("v_total too large", v_total, 0x7ff);
+
+	c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? CRTC_CSYNC_EN : 0;
+
+	/* output */
+	crtc->vxres = vxres;
+	crtc->vyres = vyres;
+	crtc->xoffset = xoffset;
+	crtc->yoffset = yoffset;
+	crtc->bpp = bpp;
+	crtc->off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19);
+	crtc->vline_crnt_vline = 0;
+
+	crtc->h_tot_disp = h_total | (h_disp<<16);
+	crtc->h_sync_strt_wid = (h_sync_strt & 0xff) | (h_sync_dly<<8) |
+		((h_sync_strt & 0x100)<<4) | (h_sync_wid<<16) | (h_sync_pol<<21);
+	crtc->v_tot_disp = v_total | (v_disp<<16);
+	crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid<<16) | (v_sync_pol<<21);
+
+	/* crtc->gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par) & CRTC_PRESERVED_MASK; */
+	crtc->gen_cntl = CRTC_EXT_DISP_EN | CRTC_EN | pix_width | c_sync;
+	crtc->gen_cntl |= CRTC_VGA_LINEAR;
+
+	/* Enable doublescan mode if requested */
+	if (vmode & FB_VMODE_DOUBLE)
+		crtc->gen_cntl |= CRTC_DBL_SCAN_EN;
+	/* Enable interlaced mode if requested */
+	if (vmode & FB_VMODE_INTERLACED)
+		crtc->gen_cntl |= CRTC_INTERLACE_EN;
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+	if (par->lcd_table != 0) {
+		vdisplay = yres;
+		if(vmode & FB_VMODE_DOUBLE)
+			vdisplay <<= 1;
+		if(vmode & FB_VMODE_INTERLACED) {
+			vdisplay >>= 1;
+
+			/* The prefered mode for the lcd is not interlaced, so disable it if
+			   it was enabled. For doublescan there is no problem, because we can
+			   compensate for it in the hardware stretching (we stretch half as much)
+			 */
+			vmode &= ~FB_VMODE_INTERLACED;
+			/*crtc->gen_cntl &= ~CRTC_INTERLACE_EN;*/
+		}
+		crtc->gen_cntl &= ~(CRTC2_EN | CRTC2_PIX_WIDTH);
+		crtc->lcd_gen_cntl &= ~(HORZ_DIVBY2_EN | DIS_HOR_CRT_DIVBY2 |
+			/*TVCLK_PM_EN | VCLK_DAC_PM_EN |*/
+			USE_SHADOWED_VEND | USE_SHADOWED_ROWCUR | SHADOW_EN | SHADOW_RW_EN);
+		crtc->lcd_gen_cntl |= (DONT_SHADOW_VPAR/* | LOCK_8DOT*/);
+
+		/* MOBILITY M1 tested, FIXME: LT */
+		crtc->horz_stretching = aty_ld_lcd(HORZ_STRETCHING, par);
+		if (!M64_HAS(LT_LCD_REGS))
+			crtc->ext_vert_stretch = aty_ld_lcd(EXT_VERT_STRETCH, par) &
+				~(AUTO_VERT_RATIO | VERT_STRETCH_MODE | VERT_STRETCH_RATIO3);
+
+		crtc->horz_stretching &=
+			~(HORZ_STRETCH_RATIO | HORZ_STRETCH_LOOP | AUTO_HORZ_RATIO |
+			HORZ_STRETCH_MODE | HORZ_STRETCH_EN);
+		if (xres < par->lcd_width) {
+			do {
+				/*
+				* The horizontal blender misbehaves when HDisplay is less than a
+				* a certain threshold (440 for a 1024-wide panel).  It doesn't
+				* stretch such modes enough.  Use pixel replication instead of
+				* blending to stretch modes that can be made to exactly fit the
+				* panel width.  The undocumented "NoLCDBlend" option allows the
+				* pixel-replicated mode to be slightly wider or narrower than the
+				* panel width.  It also causes a mode that is exactly half as wide
+				* as the panel to be pixel-replicated, rather than blended.
+				*/
+				int HDisplay  = xres & ~7;
+				int nStretch  = par->lcd_width / HDisplay;
+				int Remainder = par->lcd_width % HDisplay;
+
+				if ((!Remainder && ((nStretch > 2))) ||
+					(((HDisplay * 16) / par->lcd_width) < 7)) {
+					static const char StretchLoops[] = {10, 12, 13, 15, 16};
+					int horz_stretch_loop = -1, BestRemainder;
+					int Numerator = HDisplay, Denominator = par->lcd_width;
+					int Index = 5;
+					ATIReduceRatio(&Numerator, &Denominator);
+
+					BestRemainder = (Numerator * 16) / Denominator;
+					while (--Index >= 0) {
+						Remainder = ((Denominator - Numerator) * StretchLoops[Index]) %
+							Denominator;
+						if (Remainder < BestRemainder) {
+							horz_stretch_loop = Index;
+							if (!(BestRemainder = Remainder))
+								break;
+						}
+					}
+
+					if ((horz_stretch_loop >= 0) && !BestRemainder) {
+						int horz_stretch_ratio = 0, Accumulator = 0;
+						int reuse_previous = 1;
+
+						Index = StretchLoops[horz_stretch_loop];
+
+						while (--Index >= 0) {
+							if (Accumulator > 0)
+								horz_stretch_ratio |= reuse_previous;
+							else
+								Accumulator += Denominator;
+							Accumulator -= Numerator;
+							reuse_previous <<= 1;
+						}
+
+						crtc->horz_stretching |= (HORZ_STRETCH_EN |
+							((horz_stretch_loop & HORZ_STRETCH_LOOP) << 16) |
+							(horz_stretch_ratio & HORZ_STRETCH_RATIO));
+						break;      /* Out of the do { ... } while (0) */
+					}
+				}
+
+				crtc->horz_stretching |= (HORZ_STRETCH_MODE | HORZ_STRETCH_EN |
+					(((HDisplay * (HORZ_STRETCH_BLEND + 1)) / par->lcd_width) & HORZ_STRETCH_BLEND));
+			} while (0);
+		}
+
+		if (vdisplay < par->lcd_height) {
+			crtc->vert_stretching = (VERT_STRETCH_USE0 | VERT_STRETCH_EN |
+				(((vdisplay * (VERT_STRETCH_RATIO0 + 1)) / par->lcd_height) & VERT_STRETCH_RATIO0));
+
+			if (!M64_HAS(LT_LCD_REGS) &&
+			    xres <= (M64_HAS(MOBIL_BUS)?1024:800))
+				crtc->ext_vert_stretch |= VERT_STRETCH_MODE;
+		} else {
+			/*
+			 * Don't use vertical blending if the mode is too wide or not
+			 * vertically stretched.
+			 */
+			crtc->vert_stretching = 0;
+		}
+		/* copy to shadow crtc */
+		crtc->shadow_h_tot_disp = crtc->h_tot_disp;
+		crtc->shadow_h_sync_strt_wid = crtc->h_sync_strt_wid;
+		crtc->shadow_v_tot_disp = crtc->v_tot_disp;
+		crtc->shadow_v_sync_strt_wid = crtc->v_sync_strt_wid;
+	}
+#endif /* CONFIG_FB_ATY_GENERIC_LCD */
+
+	if (M64_HAS(MAGIC_FIFO)) {
+		/* Not VTB/GTB */
+		/* FIXME: magic FIFO values */
+		crtc->gen_cntl |= (aty_ld_le32(CRTC_GEN_CNTL, par) & CRTC2_PIX_WIDTH);
+	}
+	crtc->dp_pix_width = dp_pix_width;
+	crtc->dp_chain_mask = dp_chain_mask;
+
+	return 0;
+}
+
+static int aty_crtc_to_var(const struct crtc *crtc, struct fb_var_screeninfo *var)
+{
+	u32 xres, yres, bpp, left, right, upper, lower, hslen, vslen, sync;
+	u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid,
+	    h_sync_pol;
+	u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync;
+	u32 pix_width;
+	u32 double_scan, interlace;
+
+	/* input */
+	h_total = crtc->h_tot_disp & 0x1ff;
+	h_disp = (crtc->h_tot_disp >> 16) & 0xff;
+	h_sync_strt = (crtc->h_sync_strt_wid & 0xff) | ((crtc->h_sync_strt_wid >> 4) & 0x100);
+	h_sync_dly = (crtc->h_sync_strt_wid >> 8) & 0x7;
+	h_sync_wid = (crtc->h_sync_strt_wid >> 16) & 0x1f;
+	h_sync_pol = (crtc->h_sync_strt_wid >> 21) & 0x1;
+	v_total = crtc->v_tot_disp & 0x7ff;
+	v_disp = (crtc->v_tot_disp >> 16) & 0x7ff;
+	v_sync_strt = crtc->v_sync_strt_wid & 0x7ff;
+	v_sync_wid = (crtc->v_sync_strt_wid >> 16) & 0x1f;
+	v_sync_pol = (crtc->v_sync_strt_wid >> 21) & 0x1;
+	c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0;
+	pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK;
+	double_scan = crtc->gen_cntl & CRTC_DBL_SCAN_EN;
+	interlace = crtc->gen_cntl & CRTC_INTERLACE_EN;
+
+	/* convert */
+	xres = (h_disp + 1) * 8;
+	yres = v_disp + 1;
+	left = (h_total - h_sync_strt - h_sync_wid) * 8 - h_sync_dly;
+	right = (h_sync_strt - h_disp) * 8 + h_sync_dly;
+	hslen = h_sync_wid * 8;
+	upper = v_total - v_sync_strt - v_sync_wid;
+	lower = v_sync_strt - v_disp;
+	vslen = v_sync_wid;
+	sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) |
+	    (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) |
+	    (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0);
+
+	switch (pix_width) {
+#if 0
+	case CRTC_PIX_WIDTH_4BPP:
+		bpp = 4;
+		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;
+#endif
+	case CRTC_PIX_WIDTH_8BPP:
+		bpp = 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 CRTC_PIX_WIDTH_15BPP:	/* RGB 555 */
+		bpp = 16;
+		var->red.offset = 10;
+		var->red.length = 5;
+		var->green.offset = 5;
+		var->green.length = 5;
+		var->blue.offset = 0;
+		var->blue.length = 5;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		break;
+	case CRTC_PIX_WIDTH_16BPP:	/* RGB 565 */
+		bpp = 16;
+		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;
+	case CRTC_PIX_WIDTH_24BPP:	/* RGB 888 */
+		bpp = 24;
+		var->red.offset = 16;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		break;
+	case CRTC_PIX_WIDTH_32BPP:	/* ARGB 8888 */
+		bpp = 32;
+		var->red.offset = 16;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		var->transp.offset = 24;
+		var->transp.length = 8;
+		break;
+	default:
+		FAIL("Invalid pixel width");
+	}
+
+	/* output */
+	var->xres = xres;
+	var->yres = yres;
+	var->xres_virtual = crtc->vxres;
+	var->yres_virtual = crtc->vyres;
+	var->bits_per_pixel = bpp;
+	var->left_margin = left;
+	var->right_margin = right;
+	var->upper_margin = upper;
+	var->lower_margin = lower;
+	var->hsync_len = hslen;
+	var->vsync_len = vslen;
+	var->sync = sync;
+	var->vmode = FB_VMODE_NONINTERLACED;
+	/* In double scan mode, the vertical parameters are doubled, so we need to
+	   half them to get the right values.
+	   In interlaced mode the values are already correct, so no correction is
+	   necessary.
+	 */
+	if (interlace)
+		var->vmode = FB_VMODE_INTERLACED;
+
+	if (double_scan) {
+		var->vmode = FB_VMODE_DOUBLE;
+		var->yres>>=1;
+		var->upper_margin>>=1;
+		var->lower_margin>>=1;
+		var->vsync_len>>=1;
+	}
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int atyfb_set_par(struct fb_info *info)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	struct fb_var_screeninfo *var = &info->var;
+	u32 tmp, pixclock;
+	int err;
+#ifdef DEBUG
+	struct fb_var_screeninfo debug;
+	u32 pixclock_in_ps;
+#endif
+	if (par->asleep)
+		return 0;
+
+	if ((err = aty_var_to_crtc(info, var, &par->crtc)))
+		return err;
+
+	pixclock = atyfb_get_pixclock(var, par);
+
+	if (pixclock == 0) {
+		FAIL("Invalid pixclock");
+	} else {
+		if((err = par->pll_ops->var_to_pll(info, pixclock, var->bits_per_pixel, &par->pll)))
+			return err;
+	}
+
+	par->accel_flags = var->accel_flags; /* hack */
+
+	if (par->blitter_may_be_busy)
+		wait_for_idle(par);
+
+	aty_set_crtc(par, &par->crtc);
+	par->dac_ops->set_dac(info, &par->pll, var->bits_per_pixel, par->accel_flags);
+	par->pll_ops->set_pll(info, &par->pll);
+
+#ifdef DEBUG
+	if(par->pll_ops && par->pll_ops->pll_to_var)
+		pixclock_in_ps = par->pll_ops->pll_to_var(info, &(par->pll));
+	else
+		pixclock_in_ps = 0;
+
+	if(0 == pixclock_in_ps) {
+		PRINTKE("ALERT ops->pll_to_var get 0\n");
+		pixclock_in_ps = pixclock;
+	}
+
+	memset(&debug, 0, sizeof(debug));
+	if(!aty_crtc_to_var(&(par->crtc), &debug)) {
+		u32 hSync, vRefresh;
+		u32 h_disp, h_sync_strt, h_sync_end, h_total;
+		u32 v_disp, v_sync_strt, v_sync_end, v_total;
+
+		h_disp = debug.xres;
+		h_sync_strt = h_disp + debug.right_margin;
+		h_sync_end = h_sync_strt + debug.hsync_len;
+		h_total = h_sync_end + debug.left_margin;
+		v_disp = debug.yres;
+		v_sync_strt = v_disp + debug.lower_margin;
+		v_sync_end = v_sync_strt + debug.vsync_len;
+		v_total = v_sync_end + debug.upper_margin;
+
+		hSync = 1000000000 / (pixclock_in_ps * h_total);
+		vRefresh = (hSync * 1000) / v_total;
+        	if (par->crtc.gen_cntl & CRTC_INTERLACE_EN)
+            	vRefresh *= 2;
+        	if (par->crtc.gen_cntl & CRTC_DBL_SCAN_EN)
+            	vRefresh /= 2;
+
+		DPRINTK("atyfb_set_par\n");
+		DPRINTK(" Set Visible Mode to %ix%i-%i\n", var->xres, var->yres, var->bits_per_pixel);
+		DPRINTK(" Virtual resolution %ix%i, pixclock_in_ps %i (calculated %i)\n",
+			var->xres_virtual, var->yres_virtual, pixclock, pixclock_in_ps);
+		DPRINTK(" Dot clock:           %i MHz\n", 1000000 / pixclock_in_ps);
+		DPRINTK(" Horizontal sync:     %i kHz\n", hSync);
+		DPRINTK(" Vertical refresh:    %i Hz\n", vRefresh);
+		DPRINTK(" x  style: %i.%03i %i %i %i %i   %i %i %i %i\n",
+			1000000 / pixclock_in_ps, 1000000 % pixclock_in_ps,
+			h_disp, h_sync_strt, h_sync_end, h_total,
+			v_disp, v_sync_strt, v_sync_end, v_total);
+		DPRINTK(" fb style: %i  %i %i %i %i %i %i %i %i\n",
+			pixclock_in_ps,
+			debug.left_margin, h_disp, debug.right_margin, debug.hsync_len,
+			debug.upper_margin, v_disp, debug.lower_margin, debug.vsync_len);
+	}
+#endif /* DEBUG */
+
+	if (!M64_HAS(INTEGRATED)) {
+		/* Don't forget MEM_CNTL */
+		tmp = aty_ld_le32(MEM_CNTL, par) & 0xf0ffffff;
+		switch (var->bits_per_pixel) {
+		case 8:
+			tmp |= 0x02000000;
+			break;
+		case 16:
+			tmp |= 0x03000000;
+			break;
+		case 32:
+			tmp |= 0x06000000;
+			break;
+		}
+		aty_st_le32(MEM_CNTL, tmp, par);
+	} else {
+		tmp = aty_ld_le32(MEM_CNTL, par) & 0xf00fffff;
+		if (!M64_HAS(MAGIC_POSTDIV))
+			tmp |= par->mem_refresh_rate << 20;
+		switch (var->bits_per_pixel) {
+		case 8:
+		case 24:
+			tmp |= 0x00000000;
+			break;
+		case 16:
+			tmp |= 0x04000000;
+			break;
+		case 32:
+			tmp |= 0x08000000;
+			break;
+		}
+		if (M64_HAS(CT_BUS)) {
+			aty_st_le32(DAC_CNTL, 0x87010184, par);
+			aty_st_le32(BUS_CNTL, 0x680000f9, par);
+		} else if (M64_HAS(VT_BUS)) {
+			aty_st_le32(DAC_CNTL, 0x87010184, par);
+			aty_st_le32(BUS_CNTL, 0x680000f9, par);
+		} else if (M64_HAS(MOBIL_BUS)) {
+			aty_st_le32(DAC_CNTL, 0x80010102, par);
+			aty_st_le32(BUS_CNTL, 0x7b33a040 | (par->aux_start ? BUS_APER_REG_DIS : 0), par);
+		} else {
+			/* GT */
+			aty_st_le32(DAC_CNTL, 0x86010102, par);
+			aty_st_le32(BUS_CNTL, 0x7b23a040 | (par->aux_start ? BUS_APER_REG_DIS : 0), par);
+			aty_st_le32(EXT_MEM_CNTL, aty_ld_le32(EXT_MEM_CNTL, par) | 0x5000001, par);
+		}
+		aty_st_le32(MEM_CNTL, tmp, par);
+	}
+	aty_st_8(DAC_MASK, 0xff, par);
+
+	info->fix.line_length = var->xres_virtual * var->bits_per_pixel/8;
+	info->fix.visual = var->bits_per_pixel <= 8 ?
+		FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
+
+	/* Initialize the graphics engine */
+	if (par->accel_flags & FB_ACCELF_TEXT)
+		aty_init_engine(par, info);
+
+#ifdef CONFIG_BOOTX_TEXT
+	btext_update_display(info->fix.smem_start,
+		(((par->crtc.h_tot_disp >> 16) & 0xff) + 1) * 8,
+		((par->crtc.v_tot_disp >> 16) & 0x7ff) + 1,
+		var->bits_per_pixel,
+		par->crtc.vxres * var->bits_per_pixel / 8);
+#endif /* CONFIG_BOOTX_TEXT */
+#if 0
+	/* switch to accelerator mode */
+	if (!(par->crtc.gen_cntl & CRTC_EXT_DISP_EN))
+		aty_st_le32(CRTC_GEN_CNTL, par->crtc.gen_cntl | CRTC_EXT_DISP_EN, par);
+#endif
+#ifdef DEBUG
+{
+	/* dump non shadow CRTC, pll, LCD registers */
+	int i; u32 base;
+
+	/* CRTC registers */
+	base = 0x2000;
+	printk("debug atyfb: Mach64 non-shadow register values:");
+	for (i = 0; i < 256; i = i+4) {
+		if(i%16 == 0) printk("\ndebug atyfb: 0x%04X: ", base + i);
+		printk(" %08X", aty_ld_le32(i, par));
+	}
+	printk("\n\n");
+
+#ifdef CONFIG_FB_ATY_CT
+	/* PLL registers */
+	base = 0x00;
+	printk("debug atyfb: Mach64 PLL register values:");
+	for (i = 0; i < 64; i++) {
+		if(i%16 == 0) printk("\ndebug atyfb: 0x%02X: ", base + i);
+		if(i%4 == 0)  printk(" ");
+		printk("%02X", aty_ld_pll_ct(i, par));
+	}
+	printk("\n\n");
+#endif	/* CONFIG_FB_ATY_CT */
+
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+	if (par->lcd_table != 0) {
+		/* LCD registers */
+		base = 0x00;
+		printk("debug atyfb: LCD register values:");
+		if(M64_HAS(LT_LCD_REGS)) {
+		    for(i = 0; i <= POWER_MANAGEMENT; i++) {
+			if(i == EXT_VERT_STRETCH)
+			    continue;
+			printk("\ndebug atyfb: 0x%04X: ", lt_lcd_regs[i]);
+			printk(" %08X", aty_ld_lcd(i, par));
+		    }
+
+		} else {
+		    for (i = 0; i < 64; i++) {
+			if(i%4 == 0) printk("\ndebug atyfb: 0x%02X: ", base + i);
+			printk(" %08X", aty_ld_lcd(i, par));
+		    }
+		}
+		printk("\n\n");
+	}
+#endif /* CONFIG_FB_ATY_GENERIC_LCD */
+}
+#endif /* DEBUG */
+	return 0;
+}
+
+static int atyfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	int err;
+	struct crtc crtc;
+	union aty_pll pll;
+	u32 pixclock;
+
+	memcpy(&pll, &(par->pll), sizeof(pll));
+
+	if((err = aty_var_to_crtc(info, var, &crtc)))
+		return err;
+
+	pixclock = atyfb_get_pixclock(var, par);
+
+	if (pixclock == 0) {
+		FAIL("Invalid pixclock");
+	} else {
+		if((err = par->pll_ops->var_to_pll(info, pixclock, var->bits_per_pixel, &pll)))
+			return err;
+	}
+
+	if (var->accel_flags & FB_ACCELF_TEXT)
+		info->var.accel_flags = FB_ACCELF_TEXT;
+	else
+		info->var.accel_flags = 0;
+
+#if 0 /* fbmon is not done. uncomment for 2.5.x -brad */
+	if (!fbmon_valid_timings(pixclock, htotal, vtotal, info))
+		return -EINVAL;
+#endif
+	aty_crtc_to_var(&crtc, var);
+	var->pixclock = par->pll_ops->pll_to_var(info, &pll);
+	return 0;
+}
+
+static void set_off_pitch(struct atyfb_par *par, const struct fb_info *info)
+{
+	u32 xoffset = info->var.xoffset;
+	u32 yoffset = info->var.yoffset;
+	u32 vxres = par->crtc.vxres;
+	u32 bpp = info->var.bits_per_pixel;
+
+	par->crtc.off_pitch = ((yoffset * vxres + xoffset) * bpp / 64) | (vxres << 19);
+}
+
+
+    /*
+     *  Open/Release the frame buffer device
+     */
+
+static int atyfb_open(struct fb_info *info, int user)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+
+	if (user) {
+		par->open++;
+#ifdef __sparc__
+		par->mmaped = 0;
+#endif
+	}
+	return (0);
+}
+
+static irqreturn_t aty_irq(int irq, void *dev_id, struct pt_regs *fp)
+{
+	struct atyfb_par *par = dev_id;
+	int handled = 0;
+	u32 int_cntl;
+
+	spin_lock(&par->int_lock);
+
+	int_cntl = aty_ld_le32(CRTC_INT_CNTL, par);
+
+	if (int_cntl & CRTC_VBLANK_INT) {
+		/* clear interrupt */
+		aty_st_le32(CRTC_INT_CNTL, (int_cntl & CRTC_INT_EN_MASK) | CRTC_VBLANK_INT_AK, par);
+		par->vblank.count++;
+		if (par->vblank.pan_display) {
+			par->vblank.pan_display = 0;
+			aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par);
+		}
+		wake_up_interruptible(&par->vblank.wait);
+		handled = 1;
+	}
+
+	spin_unlock(&par->int_lock);
+
+	return IRQ_RETVAL(handled);
+}
+
+static int aty_enable_irq(struct atyfb_par *par, int reenable)
+{
+	u32 int_cntl;
+
+	if (!test_and_set_bit(0, &par->irq_flags)) {
+		if (request_irq(par->irq, aty_irq, SA_SHIRQ, "atyfb", par)) {
+			clear_bit(0, &par->irq_flags);
+			return -EINVAL;
+		}
+		spin_lock_irq(&par->int_lock);
+		int_cntl = aty_ld_le32(CRTC_INT_CNTL, par) & CRTC_INT_EN_MASK;
+		/* clear interrupt */
+		aty_st_le32(CRTC_INT_CNTL, int_cntl | CRTC_VBLANK_INT_AK, par);
+		/* enable interrupt */
+		aty_st_le32(CRTC_INT_CNTL, int_cntl | CRTC_VBLANK_INT_EN, par);
+		spin_unlock_irq(&par->int_lock);
+	} else if (reenable) {
+		spin_lock_irq(&par->int_lock);
+		int_cntl = aty_ld_le32(CRTC_INT_CNTL, par) & CRTC_INT_EN_MASK;
+		if (!(int_cntl & CRTC_VBLANK_INT_EN)) {
+			printk("atyfb: someone disabled IRQ [%08x]\n", int_cntl);
+			/* re-enable interrupt */
+			aty_st_le32(CRTC_INT_CNTL, int_cntl | CRTC_VBLANK_INT_EN, par );
+		}
+		spin_unlock_irq(&par->int_lock);
+	}
+
+	return 0;
+}
+
+static int aty_disable_irq(struct atyfb_par *par)
+{
+	u32 int_cntl;
+
+	if (test_and_clear_bit(0, &par->irq_flags)) {
+		if (par->vblank.pan_display) {
+			par->vblank.pan_display = 0;
+			aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par);
+		}
+		spin_lock_irq(&par->int_lock);
+		int_cntl = aty_ld_le32(CRTC_INT_CNTL, par) & CRTC_INT_EN_MASK;
+		/* disable interrupt */
+		aty_st_le32(CRTC_INT_CNTL, int_cntl & ~CRTC_VBLANK_INT_EN, par );
+		spin_unlock_irq(&par->int_lock);
+		free_irq(par->irq, par);
+	}
+
+	return 0;
+}
+
+static int atyfb_release(struct fb_info *info, int user)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	if (user) {
+		par->open--;
+		mdelay(1);
+		wait_for_idle(par);
+		if (!par->open) {
+#ifdef __sparc__
+			int was_mmaped = par->mmaped;
+
+			par->mmaped = 0;
+
+			if (was_mmaped) {
+				struct fb_var_screeninfo var;
+
+				/* Now reset the default display config, we have no
+				 * idea what the program(s) which mmap'd the chip did
+				 * to the configuration, nor whether it restored it
+				 * correctly.
+				 */
+				var = default_var;
+				if (noaccel)
+					var.accel_flags &= ~FB_ACCELF_TEXT;
+				else
+					var.accel_flags |= FB_ACCELF_TEXT;
+				if (var.yres == var.yres_virtual) {
+					u32 videoram = (info->fix.smem_len - (PAGE_SIZE << 2));
+					var.yres_virtual = ((videoram * 8) / var.bits_per_pixel) / var.xres_virtual;
+					if (var.yres_virtual < var.yres)
+						var.yres_virtual = var.yres;
+				}
+			}
+#endif
+			aty_disable_irq(par);
+		}
+	}
+	return (0);
+}
+
+    /*
+     *  Pan or Wrap the Display
+     *
+     *  This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
+     */
+
+static int atyfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	u32 xres, yres, xoffset, yoffset;
+
+	xres = (((par->crtc.h_tot_disp >> 16) & 0xff) + 1) * 8;
+	yres = ((par->crtc.v_tot_disp >> 16) & 0x7ff) + 1;
+	if (par->crtc.gen_cntl & CRTC_DBL_SCAN_EN)
+		yres >>= 1;
+	xoffset = (var->xoffset + 7) & ~7;
+	yoffset = var->yoffset;
+	if (xoffset + xres > par->crtc.vxres || yoffset + yres > par->crtc.vyres)
+		return -EINVAL;
+	info->var.xoffset = xoffset;
+	info->var.yoffset = yoffset;
+	if (par->asleep)
+		return 0;
+
+	set_off_pitch(par, info);
+	if ((var->activate & FB_ACTIVATE_VBL) && !aty_enable_irq(par, 0)) {
+		par->vblank.pan_display = 1;
+	} else {
+		par->vblank.pan_display = 0;
+		aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par);
+	}
+
+	return 0;
+}
+
+static int aty_waitforvblank(struct atyfb_par *par, u32 crtc)
+{
+	struct aty_interrupt *vbl;
+	unsigned int count;
+	int ret;
+
+	switch (crtc) {
+	case 0:
+		vbl = &par->vblank;
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	ret = aty_enable_irq(par, 0);
+	if (ret)
+		return ret;
+
+	count = vbl->count;
+	ret = wait_event_interruptible_timeout(vbl->wait, count != vbl->count, HZ/10);
+	if (ret < 0) {
+		return ret;
+	}
+	if (ret == 0) {
+		aty_enable_irq(par, 1);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+
+#ifdef DEBUG
+#define ATYIO_CLKR		0x41545900	/* ATY\00 */
+#define ATYIO_CLKW		0x41545901	/* ATY\01 */
+
+struct atyclk {
+	u32 ref_clk_per;
+	u8 pll_ref_div;
+	u8 mclk_fb_div;
+	u8 mclk_post_div;	/* 1,2,3,4,8 */
+	u8 mclk_fb_mult;	/* 2 or 4 */
+	u8 xclk_post_div;	/* 1,2,3,4,8 */
+	u8 vclk_fb_div;
+	u8 vclk_post_div;	/* 1,2,3,4,6,8,12 */
+	u32 dsp_xclks_per_row;	/* 0-16383 */
+	u32 dsp_loop_latency;	/* 0-15 */
+	u32 dsp_precision;	/* 0-7 */
+	u32 dsp_on;		/* 0-2047 */
+	u32 dsp_off;		/* 0-2047 */
+};
+
+#define ATYIO_FEATR		0x41545902	/* ATY\02 */
+#define ATYIO_FEATW		0x41545903	/* ATY\03 */
+#endif
+
+#ifndef FBIO_WAITFORVSYNC
+#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
+#endif
+
+static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+	u_long arg, struct fb_info *info)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+#ifdef __sparc__
+	struct fbtype fbtyp;
+#endif
+
+	switch (cmd) {
+#ifdef __sparc__
+	case FBIOGTYPE:
+		fbtyp.fb_type = FBTYPE_PCI_GENERIC;
+		fbtyp.fb_width = par->crtc.vxres;
+		fbtyp.fb_height = par->crtc.vyres;
+		fbtyp.fb_depth = info->var.bits_per_pixel;
+		fbtyp.fb_cmsize = info->cmap.len;
+		fbtyp.fb_size = info->fix.smem_len;
+		if (copy_to_user((struct fbtype __user *) arg, &fbtyp, sizeof(fbtyp)))
+			return -EFAULT;
+		break;
+#endif /* __sparc__ */
+
+	case FBIO_WAITFORVSYNC:
+		{
+			u32 crtc;
+
+			if (get_user(crtc, (__u32 __user *) arg))
+				return -EFAULT;
+
+			return aty_waitforvblank(par, crtc);
+		}
+		break;
+
+#if defined(DEBUG) && defined(CONFIG_FB_ATY_CT)
+	case ATYIO_CLKR:
+		if (M64_HAS(INTEGRATED)) {
+			struct atyclk clk;
+			union aty_pll *pll = &(par->pll);
+			u32 dsp_config = pll->ct.dsp_config;
+			u32 dsp_on_off = pll->ct.dsp_on_off;
+			clk.ref_clk_per = par->ref_clk_per;
+			clk.pll_ref_div = pll->ct.pll_ref_div;
+			clk.mclk_fb_div = pll->ct.mclk_fb_div;
+			clk.mclk_post_div = pll->ct.mclk_post_div_real;
+			clk.mclk_fb_mult = pll->ct.mclk_fb_mult;
+			clk.xclk_post_div = pll->ct.xclk_post_div_real;
+			clk.vclk_fb_div = pll->ct.vclk_fb_div;
+			clk.vclk_post_div = pll->ct.vclk_post_div_real;
+			clk.dsp_xclks_per_row = dsp_config & 0x3fff;
+			clk.dsp_loop_latency = (dsp_config >> 16) & 0xf;
+			clk.dsp_precision = (dsp_config >> 20) & 7;
+			clk.dsp_off = dsp_on_off & 0x7ff;
+			clk.dsp_on = (dsp_on_off >> 16) & 0x7ff;
+			if (copy_to_user((struct atyclk __user *) arg, &clk,
+					 sizeof(clk)))
+				return -EFAULT;
+		} else
+			return -EINVAL;
+		break;
+	case ATYIO_CLKW:
+		if (M64_HAS(INTEGRATED)) {
+			struct atyclk clk;
+			union aty_pll *pll = &(par->pll);
+			if (copy_from_user(&clk, (struct atyclk __user *) arg, sizeof(clk)))
+				return -EFAULT;
+			par->ref_clk_per = clk.ref_clk_per;
+			pll->ct.pll_ref_div = clk.pll_ref_div;
+			pll->ct.mclk_fb_div = clk.mclk_fb_div;
+			pll->ct.mclk_post_div_real = clk.mclk_post_div;
+			pll->ct.mclk_fb_mult = clk.mclk_fb_mult;
+			pll->ct.xclk_post_div_real = clk.xclk_post_div;
+			pll->ct.vclk_fb_div = clk.vclk_fb_div;
+			pll->ct.vclk_post_div_real = clk.vclk_post_div;
+			pll->ct.dsp_config = (clk.dsp_xclks_per_row & 0x3fff) |
+				((clk.dsp_loop_latency & 0xf)<<16)| ((clk.dsp_precision & 7)<<20);
+			pll->ct.dsp_on_off = (clk.dsp_off & 0x7ff) | ((clk.dsp_on & 0x7ff)<<16);
+			/*aty_calc_pll_ct(info, &pll->ct);*/
+			aty_set_pll_ct(info, pll);
+		} else
+			return -EINVAL;
+		break;
+	case ATYIO_FEATR:
+		if (get_user(par->features, (u32 __user *) arg))
+			return -EFAULT;
+		break;
+	case ATYIO_FEATW:
+		if (put_user(par->features, (u32 __user *) arg))
+			return -EFAULT;
+		break;
+#endif /* DEBUG && CONFIG_FB_ATY_CT */
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int atyfb_sync(struct fb_info *info)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+
+	if (par->blitter_may_be_busy)
+		wait_for_idle(par);
+	return 0;
+}
+
+#ifdef __sparc__
+static int atyfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	unsigned int size, page, map_size = 0;
+	unsigned long map_offset = 0;
+	unsigned long off;
+	int i;
+
+	if (!par->mmap_map)
+		return -ENXIO;
+
+	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+		return -EINVAL;
+
+	off = vma->vm_pgoff << PAGE_SHIFT;
+	size = vma->vm_end - vma->vm_start;
+
+	/* To stop the swapper from even considering these pages. */
+	vma->vm_flags |= (VM_IO | VM_RESERVED);
+
+	if (((vma->vm_pgoff == 0) && (size == info->fix.smem_len)) ||
+	    ((off == info->fix.smem_len) && (size == PAGE_SIZE)))
+		off += 0x8000000000000000UL;
+
+	vma->vm_pgoff = off >> PAGE_SHIFT;	/* propagate off changes */
+
+	/* Each page, see which map applies */
+	for (page = 0; page < size;) {
+		map_size = 0;
+		for (i = 0; par->mmap_map[i].size; i++) {
+			unsigned long start = par->mmap_map[i].voff;
+			unsigned long end = start + par->mmap_map[i].size;
+			unsigned long offset = off + page;
+
+			if (start > offset)
+				continue;
+			if (offset >= end)
+				continue;
+
+			map_size = par->mmap_map[i].size - (offset - start);
+			map_offset =
+			    par->mmap_map[i].poff + (offset - start);
+			break;
+		}
+		if (!map_size) {
+			page += PAGE_SIZE;
+			continue;
+		}
+		if (page + map_size > size)
+			map_size = size - page;
+
+		pgprot_val(vma->vm_page_prot) &=
+		    ~(par->mmap_map[i].prot_mask);
+		pgprot_val(vma->vm_page_prot) |= par->mmap_map[i].prot_flag;
+
+		if (remap_pfn_range(vma, vma->vm_start + page,
+			map_offset >> PAGE_SHIFT, map_size, vma->vm_page_prot))
+			return -EAGAIN;
+
+		page += map_size;
+	}
+
+	if (!map_size)
+		return -EINVAL;
+
+	if (!par->mmaped)
+		par->mmaped = 1;
+	return 0;
+}
+
+static struct {
+	u32 yoffset;
+	u8 r[2][256];
+	u8 g[2][256];
+	u8 b[2][256];
+} atyfb_save;
+
+static void atyfb_save_palette(struct atyfb_par *par, int enter)
+{
+	int i, tmp;
+
+	for (i = 0; i < 256; i++) {
+		tmp = aty_ld_8(DAC_CNTL, par) & 0xfc;
+		if (M64_HAS(EXTRA_BRIGHT))
+			tmp |= 0x2;
+		aty_st_8(DAC_CNTL, tmp, par);
+		aty_st_8(DAC_MASK, 0xff, par);
+
+		writeb(i, &par->aty_cmap_regs->rindex);
+		atyfb_save.r[enter][i] = readb(&par->aty_cmap_regs->lut);
+		atyfb_save.g[enter][i] = readb(&par->aty_cmap_regs->lut);
+		atyfb_save.b[enter][i] = readb(&par->aty_cmap_regs->lut);
+		writeb(i, &par->aty_cmap_regs->windex);
+		writeb(atyfb_save.r[1 - enter][i],
+		       &par->aty_cmap_regs->lut);
+		writeb(atyfb_save.g[1 - enter][i],
+		       &par->aty_cmap_regs->lut);
+		writeb(atyfb_save.b[1 - enter][i],
+		       &par->aty_cmap_regs->lut);
+	}
+}
+
+static void atyfb_palette(int enter)
+{
+	struct atyfb_par *par;
+	struct fb_info *info;
+	int i;
+
+	for (i = 0; i < FB_MAX; i++) {
+		info = registered_fb[i];
+		if (info && info->fbops == &atyfb_ops) {
+			par = (struct atyfb_par *) info->par;
+			
+			atyfb_save_palette(par, enter);
+			if (enter) {
+				atyfb_save.yoffset = info->var.yoffset;
+				info->var.yoffset = 0;
+				set_off_pitch(par, info);
+			} else {
+				info->var.yoffset = atyfb_save.yoffset;
+				set_off_pitch(par, info);
+			}
+			aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par);
+			break;
+		}
+	}
+}
+#endif /* __sparc__ */
+
+
+
+#if defined(CONFIG_PM) && defined(CONFIG_PCI)
+
+/* Power management routines. Those are used for PowerBook sleep.
+ */
+static int aty_power_mgmt(int sleep, struct atyfb_par *par)
+{
+	u32 pm;
+	int timeout;
+
+	pm = aty_ld_lcd(POWER_MANAGEMENT, par);
+	pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG;
+	aty_st_lcd(POWER_MANAGEMENT, pm, par);
+	pm = aty_ld_lcd(POWER_MANAGEMENT, par);
+
+	timeout = 2000;
+	if (sleep) {
+		/* Sleep */
+		pm &= ~PWR_MGT_ON;
+		aty_st_lcd(POWER_MANAGEMENT, pm, par);
+		pm = aty_ld_lcd(POWER_MANAGEMENT, par);
+		udelay(10);
+		pm &= ~(PWR_BLON | AUTO_PWR_UP);
+		pm |= SUSPEND_NOW;
+		aty_st_lcd(POWER_MANAGEMENT, pm, par);
+		pm = aty_ld_lcd(POWER_MANAGEMENT, par);
+		udelay(10);
+		pm |= PWR_MGT_ON;
+		aty_st_lcd(POWER_MANAGEMENT, pm, par);
+		do {
+			pm = aty_ld_lcd(POWER_MANAGEMENT, par);
+			mdelay(1);
+			if ((--timeout) == 0)
+				break;
+		} while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND);
+	} else {
+		/* Wakeup */
+		pm &= ~PWR_MGT_ON;
+		aty_st_lcd(POWER_MANAGEMENT, pm, par);
+		pm = aty_ld_lcd(POWER_MANAGEMENT, par);
+		udelay(10);
+		pm &= ~SUSPEND_NOW;
+		pm |= (PWR_BLON | AUTO_PWR_UP);
+		aty_st_lcd(POWER_MANAGEMENT, pm, par);
+		pm = aty_ld_lcd(POWER_MANAGEMENT, par);
+		udelay(10);
+		pm |= PWR_MGT_ON;
+		aty_st_lcd(POWER_MANAGEMENT, pm, par);
+		do {
+			pm = aty_ld_lcd(POWER_MANAGEMENT, par);
+			mdelay(1);
+			if ((--timeout) == 0)
+				break;
+		} while ((pm & PWR_MGT_STATUS_MASK) != 0);
+	}
+	mdelay(500);
+
+	return timeout ? 0 : -EIO;
+}
+
+static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct fb_info *info = pci_get_drvdata(pdev);
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+
+#ifdef CONFIG_PPC_PMAC
+	/* HACK ALERT ! Once I find a proper way to say to each driver
+	 * individually what will happen with it's PCI slot, I'll change
+	 * that. On laptops, the AGP slot is just unclocked, so D2 is
+	 * expected, while on desktops, the card is powered off
+	 */
+	if (state >= 3)
+		state = 2;
+#endif /* CONFIG_PPC_PMAC */
+
+	if (state != 2 || state == pdev->dev.power.power_state)
+		return 0;
+
+	acquire_console_sem();
+
+	fb_set_suspend(info, 1);
+
+	/* Idle & reset engine */
+	wait_for_idle(par);
+	aty_reset_engine(par);
+
+	/* Blank display and LCD */
+	atyfb_blank(FB_BLANK_POWERDOWN, info);
+
+	par->asleep = 1;
+	par->lock_blank = 1;
+
+	/* Set chip to "suspend" mode */
+	if (aty_power_mgmt(1, par)) {
+		par->asleep = 0;
+		par->lock_blank = 0;
+		atyfb_blank(FB_BLANK_UNBLANK, info);
+		fb_set_suspend(info, 0);
+		release_console_sem();
+		return -EIO;
+	}
+
+	release_console_sem();
+
+	pdev->dev.power.power_state = state;
+
+	return 0;
+}
+
+static int atyfb_pci_resume(struct pci_dev *pdev)
+{
+	struct fb_info *info = pci_get_drvdata(pdev);
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+
+	if (pdev->dev.power.power_state == 0)
+		return 0;
+
+	acquire_console_sem();
+
+	if (pdev->dev.power.power_state == 2)
+		aty_power_mgmt(0, par);
+	par->asleep = 0;
+
+	/* Restore display */
+	atyfb_set_par(info);
+
+	/* Refresh */
+	fb_set_suspend(info, 0);
+
+	/* Unblank */
+	par->lock_blank = 0;
+	atyfb_blank(FB_BLANK_UNBLANK, info);
+
+	release_console_sem();
+
+	pdev->dev.power.power_state = PMSG_ON;
+
+	return 0;
+}
+
+#endif /*  defined(CONFIG_PM) && defined(CONFIG_PCI) */
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+
+    /*
+     *   LCD backlight control
+     */
+
+static int backlight_conv[] = {
+	0x00, 0x3f, 0x4c, 0x59, 0x66, 0x73, 0x80, 0x8d,
+	0x9a, 0xa7, 0xb4, 0xc1, 0xcf, 0xdc, 0xe9, 0xff
+};
+
+static int aty_set_backlight_enable(int on, int level, void *data)
+{
+	struct fb_info *info = (struct fb_info *) data;
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par);
+
+	reg |= (BLMOD_EN | BIASMOD_EN);
+	if (on && level > BACKLIGHT_OFF) {
+		reg &= ~BIAS_MOD_LEVEL_MASK;
+		reg |= (backlight_conv[level] << BIAS_MOD_LEVEL_SHIFT);
+	} else {
+		reg &= ~BIAS_MOD_LEVEL_MASK;
+		reg |= (backlight_conv[0] << BIAS_MOD_LEVEL_SHIFT);
+	}
+	aty_st_lcd(LCD_MISC_CNTL, reg, par);
+	return 0;
+}
+
+static int aty_set_backlight_level(int level, void *data)
+{
+	return aty_set_backlight_enable(1, level, data);
+}
+
+static struct backlight_controller aty_backlight_controller = {
+	aty_set_backlight_enable,
+	aty_set_backlight_level
+};
+#endif /* CONFIG_PMAC_BACKLIGHT */
+
+static void __init aty_calc_mem_refresh(struct atyfb_par *par, int xclk)
+{
+	const int ragepro_tbl[] = {
+		44, 50, 55, 66, 75, 80, 100
+	};
+	const int ragexl_tbl[] = {
+		50, 66, 75, 83, 90, 95, 100, 105,
+		110, 115, 120, 125, 133, 143, 166
+	};
+	const int *refresh_tbl;
+	int i, size;
+
+	if (IS_XL(par->pci_id) || IS_MOBILITY(par->pci_id)) {
+		refresh_tbl = ragexl_tbl;
+		size = sizeof(ragexl_tbl)/sizeof(int);
+	} else {
+		refresh_tbl = ragepro_tbl;
+		size = sizeof(ragepro_tbl)/sizeof(int);
+	}
+
+	for (i=0; i < size; i++) {
+		if (xclk < refresh_tbl[i])
+		break;
+	}
+	par->mem_refresh_rate = i;
+}
+
+    /*
+     *  Initialisation
+     */
+
+static struct fb_info *fb_list = NULL;
+
+static int __init aty_init(struct fb_info *info, const char *name)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	const char *ramname = NULL, *xtal;
+	int gtb_memsize;
+	struct fb_var_screeninfo var;
+	u8 pll_ref_div;
+	u32 i;
+#if defined(CONFIG_PPC)
+	int sense;
+#endif
+
+	init_waitqueue_head(&par->vblank.wait);
+	spin_lock_init(&par->int_lock);
+
+	par->aty_cmap_regs =
+	    (struct aty_cmap_regs __iomem *) (par->ati_regbase + 0xc0);
+
+#ifdef CONFIG_PPC_PMAC
+	/* The Apple iBook1 uses non-standard memory frequencies. We detect it
+	 * and set the frequency manually. */
+	if (machine_is_compatible("PowerBook2,1")) {
+		par->pll_limits.mclk = 70;
+		par->pll_limits.xclk = 53;
+	}
+#endif
+	if (pll)
+		par->pll_limits.pll_max = pll;
+	if (mclk)
+		par->pll_limits.mclk = mclk;
+	if (xclk)
+		par->pll_limits.xclk = xclk;
+
+	aty_calc_mem_refresh(par, par->pll_limits.xclk);
+	par->pll_per = 1000000/par->pll_limits.pll_max;
+	par->mclk_per = 1000000/par->pll_limits.mclk;
+	par->xclk_per = 1000000/par->pll_limits.xclk;
+
+	par->ref_clk_per = 1000000000000ULL / 14318180;
+	xtal = "14.31818";
+
+#ifdef CONFIG_FB_ATY_GX
+	if (!M64_HAS(INTEGRATED)) {
+		u32 stat0;
+		u8 dac_type, dac_subtype, clk_type;
+		stat0 = aty_ld_le32(CONFIG_STAT0, par);
+		par->bus_type = (stat0 >> 0) & 0x07;
+		par->ram_type = (stat0 >> 3) & 0x07;
+		ramname = aty_gx_ram[par->ram_type];
+		/* FIXME: clockchip/RAMDAC probing? */
+		dac_type = (aty_ld_le32(DAC_CNTL, par) >> 16) & 0x07;
+#ifdef CONFIG_ATARI
+		clk_type = CLK_ATI18818_1;
+		dac_type = (stat0 >> 9) & 0x07;
+		if (dac_type == 0x07)
+			dac_subtype = DAC_ATT20C408;
+		else
+			dac_subtype = (aty_ld_8(SCRATCH_REG1 + 1, par) & 0xF0) | dac_type;
+#else
+		dac_type = DAC_IBMRGB514;
+		dac_subtype = DAC_IBMRGB514;
+		clk_type = CLK_IBMRGB514;
+#endif
+		switch (dac_subtype) {
+		case DAC_IBMRGB514:
+			par->dac_ops = &aty_dac_ibm514;
+			break;
+		case DAC_ATI68860_B:
+		case DAC_ATI68860_C:
+			par->dac_ops = &aty_dac_ati68860b;
+			break;
+		case DAC_ATT20C408:
+		case DAC_ATT21C498:
+			par->dac_ops = &aty_dac_att21c498;
+			break;
+		default:
+			PRINTKI("aty_init: DAC type not implemented yet!\n");
+			par->dac_ops = &aty_dac_unsupported;
+			break;
+		}
+		switch (clk_type) {
+		case CLK_ATI18818_1:
+			par->pll_ops = &aty_pll_ati18818_1;
+			break;
+		case CLK_STG1703:
+			par->pll_ops = &aty_pll_stg1703;
+			break;
+		case CLK_CH8398:
+			par->pll_ops = &aty_pll_ch8398;
+			break;
+		case CLK_ATT20C408:
+			par->pll_ops = &aty_pll_att20c408;
+			break;
+		case CLK_IBMRGB514:
+			par->pll_ops = &aty_pll_ibm514;
+			break;
+		default:
+			PRINTKI("aty_init: CLK type not implemented yet!");
+			par->pll_ops = &aty_pll_unsupported;
+			break;
+		}
+	}
+#endif /* CONFIG_FB_ATY_GX */
+#ifdef CONFIG_FB_ATY_CT
+	if (M64_HAS(INTEGRATED)) {
+		par->dac_ops = &aty_dac_ct;
+		par->pll_ops = &aty_pll_ct;
+		par->bus_type = PCI;
+#ifdef CONFIG_FB_ATY_XL_INIT
+		if (IS_XL(par->pci_id))
+			atyfb_xl_init(info);
+#endif
+		par->ram_type = (aty_ld_le32(CONFIG_STAT0, par) & 0x07);
+		ramname = aty_ct_ram[par->ram_type];
+		/* for many chips, the mclk is 67 MHz for SDRAM, 63 MHz otherwise */
+		if (par->pll_limits.mclk == 67 && par->ram_type < SDRAM)
+			par->pll_limits.mclk = 63;
+	}
+
+	if (M64_HAS(GTB_DSP)
+	    && (pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par))) {
+		int diff1, diff2;
+		diff1 = 510 * 14 / pll_ref_div - par->pll_limits.pll_max;
+		diff2 = 510 * 29 / pll_ref_div - par->pll_limits.pll_max;
+		if (diff1 < 0)
+			diff1 = -diff1;
+		if (diff2 < 0)
+			diff2 = -diff2;
+		if (diff2 < diff1) {
+			par->ref_clk_per = 1000000000000ULL / 29498928;
+			xtal = "29.498928";
+		}
+	}
+#endif /* CONFIG_FB_ATY_CT */
+
+	/* save previous video mode */
+	aty_get_crtc(par, &saved_crtc);
+	if(par->pll_ops->get_pll)
+		par->pll_ops->get_pll(info, &saved_pll);
+
+	i = aty_ld_le32(MEM_CNTL, par);
+	gtb_memsize = M64_HAS(GTB_DSP);
+	if (gtb_memsize)
+		switch (i & 0xF) {	/* 0xF used instead of MEM_SIZE_ALIAS */
+		case MEM_SIZE_512K:
+			info->fix.smem_len = 0x80000;
+			break;
+		case MEM_SIZE_1M:
+			info->fix.smem_len = 0x100000;
+			break;
+		case MEM_SIZE_2M_GTB:
+			info->fix.smem_len = 0x200000;
+			break;
+		case MEM_SIZE_4M_GTB:
+			info->fix.smem_len = 0x400000;
+			break;
+		case MEM_SIZE_6M_GTB:
+			info->fix.smem_len = 0x600000;
+			break;
+		case MEM_SIZE_8M_GTB:
+			info->fix.smem_len = 0x800000;
+			break;
+		default:
+			info->fix.smem_len = 0x80000;
+	} else
+		switch (i & MEM_SIZE_ALIAS) {
+		case MEM_SIZE_512K:
+			info->fix.smem_len = 0x80000;
+			break;
+		case MEM_SIZE_1M:
+			info->fix.smem_len = 0x100000;
+			break;
+		case MEM_SIZE_2M:
+			info->fix.smem_len = 0x200000;
+			break;
+		case MEM_SIZE_4M:
+			info->fix.smem_len = 0x400000;
+			break;
+		case MEM_SIZE_6M:
+			info->fix.smem_len = 0x600000;
+			break;
+		case MEM_SIZE_8M:
+			info->fix.smem_len = 0x800000;
+			break;
+		default:
+			info->fix.smem_len = 0x80000;
+		}
+
+	if (M64_HAS(MAGIC_VRAM_SIZE)) {
+		if (aty_ld_le32(CONFIG_STAT1, par) & 0x40000000)
+			info->fix.smem_len += 0x400000;
+	}
+
+	if (vram) {
+		info->fix.smem_len = vram * 1024;
+		i = i & ~(gtb_memsize ? 0xF : MEM_SIZE_ALIAS);
+		if (info->fix.smem_len <= 0x80000)
+			i |= MEM_SIZE_512K;
+		else if (info->fix.smem_len <= 0x100000)
+			i |= MEM_SIZE_1M;
+		else if (info->fix.smem_len <= 0x200000)
+			i |= gtb_memsize ? MEM_SIZE_2M_GTB : MEM_SIZE_2M;
+		else if (info->fix.smem_len <= 0x400000)
+			i |= gtb_memsize ? MEM_SIZE_4M_GTB : MEM_SIZE_4M;
+		else if (info->fix.smem_len <= 0x600000)
+			i |= gtb_memsize ? MEM_SIZE_6M_GTB : MEM_SIZE_6M;
+		else
+			i |= gtb_memsize ? MEM_SIZE_8M_GTB : MEM_SIZE_8M;
+		aty_st_le32(MEM_CNTL, i, par);
+	}
+
+	/*
+	 *  Reg Block 0 (CT-compatible block) is at mmio_start
+	 *  Reg Block 1 (multimedia extensions) is at mmio_start - 0x400
+	 */
+	if (M64_HAS(GX)) {
+		info->fix.mmio_len = 0x400;
+		info->fix.accel = FB_ACCEL_ATI_MACH64GX;
+	} else if (M64_HAS(CT)) {
+		info->fix.mmio_len = 0x400;
+		info->fix.accel = FB_ACCEL_ATI_MACH64CT;
+	} else if (M64_HAS(VT)) {
+		info->fix.mmio_start -= 0x400;
+		info->fix.mmio_len = 0x800;
+		info->fix.accel = FB_ACCEL_ATI_MACH64VT;
+	} else {/* GT */
+		info->fix.mmio_start -= 0x400;
+		info->fix.mmio_len = 0x800;
+		info->fix.accel = FB_ACCEL_ATI_MACH64GT;
+	}
+
+	PRINTKI("%d%c %s, %s MHz XTAL, %d MHz PLL, %d Mhz MCLK, %d MHz XCLK\n",
+	       info->fix.smem_len == 0x80000 ? 512 : (info->fix.smem_len >> 20),
+	       info->fix.smem_len == 0x80000 ? 'K' : 'M', ramname, xtal, par->pll_limits.pll_max,
+	       par->pll_limits.mclk, par->pll_limits.xclk);
+
+#if defined(DEBUG) && defined(CONFIG_ATY_CT)
+	if (M64_HAS(INTEGRATED)) {
+		int i;
+		printk("debug atyfb: BUS_CNTL DAC_CNTL MEM_CNTL EXT_MEM_CNTL CRTC_GEN_CNTL "
+		       "DSP_CONFIG DSP_ON_OFF CLOCK_CNTL\n"
+		       "debug atyfb: %08x %08x %08x %08x     %08x      %08x   %08x   %08x\n"
+		       "debug atyfb: PLL",
+			aty_ld_le32(BUS_CNTL, par), aty_ld_le32(DAC_CNTL, par),
+			aty_ld_le32(MEM_CNTL, par), aty_ld_le32(EXT_MEM_CNTL, par),
+			aty_ld_le32(CRTC_GEN_CNTL, par), aty_ld_le32(DSP_CONFIG, par),
+			aty_ld_le32(DSP_ON_OFF, par), aty_ld_le32(CLOCK_CNTL, par));
+		for (i = 0; i < 40; i++)
+			printk(" %02x", aty_ld_pll_ct(i, par));
+		printk("\n");
+	}
+#endif
+	if(par->pll_ops->init_pll)
+		par->pll_ops->init_pll(info, &par->pll);
+
+	/*
+	 *  Last page of 8 MB (4 MB on ISA) aperture is MMIO
+	 *  FIXME: we should use the auxiliary aperture instead so we can access
+	 *  the full 8 MB of video RAM on 8 MB boards
+	 */
+
+	if (!par->aux_start &&
+		(info->fix.smem_len == 0x800000 || (par->bus_type == ISA && info->fix.smem_len == 0x400000)))
+		info->fix.smem_len -= GUI_RESERVE;
+
+	/*
+	 *  Disable register access through the linear aperture
+	 *  if the auxiliary aperture is used so we can access
+	 *  the full 8 MB of video RAM on 8 MB boards.
+	 */
+	if (par->aux_start)
+		aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL, par) | BUS_APER_REG_DIS, par);
+
+#ifdef CONFIG_MTRR
+	par->mtrr_aper = -1;
+	par->mtrr_reg = -1;
+	if (!nomtrr) {
+		/* Cover the whole resource. */
+		 par->mtrr_aper = mtrr_add(par->res_start, par->res_size, MTRR_TYPE_WRCOMB, 1);
+		 if (par->mtrr_aper >= 0 && !par->aux_start) {
+			/* Make a hole for mmio. */
+			par->mtrr_reg = mtrr_add(par->res_start + 0x800000 - GUI_RESERVE,
+				GUI_RESERVE, MTRR_TYPE_UNCACHABLE, 1);
+			if (par->mtrr_reg < 0) {
+				mtrr_del(par->mtrr_aper, 0, 0);
+				par->mtrr_aper = -1;
+			}
+		 }
+	}
+#endif
+
+	info->fbops = &atyfb_ops;
+	info->pseudo_palette = pseudo_palette;
+	info->flags = FBINFO_FLAG_DEFAULT;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	if (M64_HAS(G3_PB_1_1) && machine_is_compatible("PowerBook1,1")) {
+		/* these bits let the 101 powerbook wake up from sleep -- paulus */
+		aty_st_lcd(POWER_MANAGEMENT, aty_ld_lcd(POWER_MANAGEMENT, par)
+			   | (USE_F32KHZ | TRISTATE_MEM_EN), par);
+	} else if (M64_HAS(MOBIL_BUS))
+		register_backlight_controller(&aty_backlight_controller, info, "ati");
+#endif /* CONFIG_PMAC_BACKLIGHT */
+
+	memset(&var, 0, sizeof(var));
+#ifdef CONFIG_PPC
+	if (_machine == _MACH_Pmac) {
+		/*
+		 *  FIXME: The NVRAM stuff should be put in a Mac-specific file, as it
+		 *         applies to all Mac video cards
+		 */
+		if (mode) {
+			if (!mac_find_mode(&var, info, mode, 8))
+				var = default_var;
+		} else {
+			if (default_vmode == VMODE_CHOOSE) {
+				if (M64_HAS(G3_PB_1024x768))
+					/* G3 PowerBook with 1024x768 LCD */
+					default_vmode = VMODE_1024_768_60;
+				else if (machine_is_compatible("iMac"))
+					default_vmode = VMODE_1024_768_75;
+				else if (machine_is_compatible
+					 ("PowerBook2,1"))
+					/* iBook with 800x600 LCD */
+					default_vmode = VMODE_800_600_60;
+				else
+					default_vmode = VMODE_640_480_67;
+				sense = read_aty_sense(par);
+				PRINTKI("monitor sense=%x, mode %d\n",
+					sense,  mac_map_monitor_sense(sense));
+			}
+			if (default_vmode <= 0 || default_vmode > VMODE_MAX)
+				default_vmode = VMODE_640_480_60;
+			if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
+				default_cmode = CMODE_8;
+			if (mac_vmode_to_var(default_vmode, default_cmode, &var))
+				var = default_var;
+		}
+	} else
+#endif /* !CONFIG_PPC */
+	if (
+#if defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64)
+	   /* On Sparc, unless the user gave a specific mode
+	    * specification, use the PROM probed values in
+	    * default_var.
+	    */
+	    !mode ||
+#endif
+	    !fb_find_mode(&var, info, mode, NULL, 0, &defmode, 8))
+		var = default_var;
+
+	if (noaccel)
+		var.accel_flags &= ~FB_ACCELF_TEXT;
+	else
+		var.accel_flags |= FB_ACCELF_TEXT;
+
+	if (comp_sync != -1) {
+		if (!comp_sync)
+			var.sync &= ~FB_SYNC_COMP_HIGH_ACT;
+		else
+			var.sync |= FB_SYNC_COMP_HIGH_ACT;
+	}
+
+	if (var.yres == var.yres_virtual) {
+		u32 videoram = (info->fix.smem_len - (PAGE_SIZE << 2));
+		var.yres_virtual = ((videoram * 8) / var.bits_per_pixel) / var.xres_virtual;
+		if (var.yres_virtual < var.yres)
+			var.yres_virtual = var.yres;
+	}
+
+	if (atyfb_check_var(&var, info)) {
+		PRINTKE("can't set default video mode\n");
+		goto aty_init_exit;
+	}
+
+#ifdef __sparc__
+	atyfb_save_palette(par, 0);
+#endif
+
+#ifdef CONFIG_FB_ATY_CT
+	if (!noaccel && M64_HAS(INTEGRATED))
+		aty_init_cursor(info);
+#endif /* CONFIG_FB_ATY_CT */
+	info->var = var;
+
+	fb_alloc_cmap(&info->cmap, 256, 0);
+
+	if (register_framebuffer(info) < 0)
+		goto aty_init_exit;
+
+	fb_list = info;
+
+	PRINTKI("fb%d: %s frame buffer device on %s\n",
+	       info->node, info->fix.id, name);
+	return 0;
+
+aty_init_exit:
+	/* restore video mode */
+	aty_set_crtc(par, &saved_crtc);
+	par->pll_ops->set_pll(info, &saved_pll);
+
+#ifdef CONFIG_MTRR
+	if (par->mtrr_reg >= 0) {
+	    mtrr_del(par->mtrr_reg, 0, 0);
+	    par->mtrr_reg = -1;
+	}
+	if (par->mtrr_aper >= 0) {
+	    mtrr_del(par->mtrr_aper, 0, 0);
+	    par->mtrr_aper = -1;
+	}
+#endif
+	return -1;
+}
+
+#ifdef CONFIG_ATARI
+static int __init store_video_par(char *video_str, unsigned char m64_num)
+{
+	char *p;
+	unsigned long vmembase, size, guiregbase;
+
+	PRINTKI("store_video_par() '%s' \n", video_str);
+
+	if (!(p = strsep(&video_str, ";")) || !*p)
+		goto mach64_invalid;
+	vmembase = simple_strtoul(p, NULL, 0);
+	if (!(p = strsep(&video_str, ";")) || !*p)
+		goto mach64_invalid;
+	size = simple_strtoul(p, NULL, 0);
+	if (!(p = strsep(&video_str, ";")) || !*p)
+		goto mach64_invalid;
+	guiregbase = simple_strtoul(p, NULL, 0);
+
+	phys_vmembase[m64_num] = vmembase;
+	phys_size[m64_num] = size;
+	phys_guiregbase[m64_num] = guiregbase;
+	PRINTKI("stored them all: $%08lX $%08lX $%08lX \n", vmembase, size,
+	       guiregbase);
+	return 0;
+
+      mach64_invalid:
+	phys_vmembase[m64_num] = 0;
+	return -1;
+}
+#endif /* CONFIG_ATARI */
+
+    /*
+     *  Blank the display.
+     */
+
+static int atyfb_blank(int blank, struct fb_info *info)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	u8 gen_cntl;
+
+	if (par->lock_blank || par->asleep)
+		return 0;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	if ((_machine == _MACH_Pmac) && blank)
+		set_backlight_enable(0);
+#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
+	if (par->lcd_table && blank &&
+	    (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
+		u32 pm = aty_ld_lcd(POWER_MANAGEMENT, par);
+		pm &= ~PWR_BLON;
+		aty_st_lcd(POWER_MANAGEMENT, pm, par);
+	}
+#endif
+
+	gen_cntl = aty_ld_8(CRTC_GEN_CNTL, par);
+	switch (blank) {
+        	case FB_BLANK_UNBLANK:
+			gen_cntl &= ~(0x4c);
+			break;
+		case FB_BLANK_NORMAL:
+			gen_cntl |= 0x40;
+			break;
+		case FB_BLANK_VSYNC_SUSPEND:
+			gen_cntl |= 0x8;
+			break;
+		case FB_BLANK_HSYNC_SUSPEND:
+			gen_cntl |= 0x4;
+			break;
+		case FB_BLANK_POWERDOWN:
+			gen_cntl |= 0x4c;
+			break;
+	}
+	aty_st_8(CRTC_GEN_CNTL, gen_cntl, par);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	if ((_machine == _MACH_Pmac) && !blank)
+		set_backlight_enable(1);
+#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
+	if (par->lcd_table && !blank &&
+	    (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
+		u32 pm = aty_ld_lcd(POWER_MANAGEMENT, par);
+		pm |= PWR_BLON;
+		aty_st_lcd(POWER_MANAGEMENT, pm, par);
+	}
+#endif
+
+	return 0;
+}
+
+static void aty_st_pal(u_int regno, u_int red, u_int green, u_int blue,
+		       const struct atyfb_par *par)
+{
+#ifdef CONFIG_ATARI
+	out_8(&par->aty_cmap_regs->windex, regno);
+	out_8(&par->aty_cmap_regs->lut, red);
+	out_8(&par->aty_cmap_regs->lut, green);
+	out_8(&par->aty_cmap_regs->lut, blue);
+#else
+	writeb(regno, &par->aty_cmap_regs->windex);
+	writeb(red, &par->aty_cmap_regs->lut);
+	writeb(green, &par->aty_cmap_regs->lut);
+	writeb(blue, &par->aty_cmap_regs->lut);
+#endif
+}
+
+    /*
+     *  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.
+     *  !! 4 & 8 =  PSEUDO, > 8 = DIRECTCOLOR
+     */
+
+static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+	u_int transp, struct fb_info *info)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	int i, depth;
+	u32 *pal = info->pseudo_palette;
+
+	depth = info->var.bits_per_pixel;
+	if (depth == 16)
+		depth = (info->var.green.length == 5) ? 15 : 16;
+
+	if (par->asleep)
+		return 0;
+
+	if (regno > 255 ||
+	    (depth == 16 && regno > 63) ||
+	    (depth == 15 && regno > 31))
+		return 1;
+
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	par->palette[regno].red = red;
+	par->palette[regno].green = green;
+	par->palette[regno].blue = blue;
+
+	if (regno < 16) {
+		switch (depth) {
+		case 15:
+			pal[regno] = (regno << 10) | (regno << 5) | regno;
+			break;
+		case 16:
+			pal[regno] = (regno << 11) | (regno << 5) | regno;
+			break;
+		case 24:
+			pal[regno] = (regno << 16) | (regno << 8) | regno;
+			break;
+		case 32:
+			i = (regno << 8) | regno;
+			pal[regno] = (i << 16) | i;
+			break;
+		}
+	}
+
+	i = aty_ld_8(DAC_CNTL, par) & 0xfc;
+	if (M64_HAS(EXTRA_BRIGHT))
+		i |= 0x2; /* DAC_CNTL | 0x2 turns off the extra brightness for gt */
+	aty_st_8(DAC_CNTL, i, par);
+	aty_st_8(DAC_MASK, 0xff, par);
+
+	if (M64_HAS(INTEGRATED)) {
+		if (depth == 16) {
+			if (regno < 32)
+				aty_st_pal(regno << 3, red,
+					   par->palette[regno<<1].green,
+					   blue, par);
+			red = par->palette[regno>>1].red;
+			blue = par->palette[regno>>1].blue;
+			regno <<= 2;
+		} else if (depth == 15) {
+			regno <<= 3;
+			for(i = 0; i < 8; i++) {
+			    aty_st_pal(regno + i, red, green, blue, par);
+			}
+		}
+	}
+	aty_st_pal(regno, red, green, blue, par);
+
+	return 0;
+}
+
+#ifdef CONFIG_PCI
+
+#ifdef __sparc__
+
+extern void (*prom_palette) (int);
+
+static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
+			struct fb_info *info, unsigned long addr)
+{
+	extern int con_is_present(void);
+
+	struct atyfb_par *par = info->par;
+	struct pcidev_cookie *pcp;
+	char prop[128];
+	int node, len, i, j, ret;
+	u32 mem, chip_id;
+
+	/* Do not attach when we have a serial console. */
+	if (!con_is_present())
+		return -ENXIO;
+
+	/*
+	 * Map memory-mapped registers.
+	 */
+	par->ati_regbase = (void *)addr + 0x7ffc00UL;
+	info->fix.mmio_start = addr + 0x7ffc00UL;
+
+	/*
+	 * Map in big-endian aperture.
+	 */
+	info->screen_base = (char *) (addr + 0x800000UL);
+	info->fix.smem_start = addr + 0x800000UL;
+
+	/*
+	 * Figure mmap addresses from PCI config space.
+	 * Split Framebuffer in big- and little-endian halfs.
+	 */
+	for (i = 0; i < 6 && pdev->resource[i].start; i++)
+		/* nothing */ ;
+	j = i + 4;
+
+	par->mmap_map = kmalloc(j * sizeof(*par->mmap_map), GFP_ATOMIC);
+	if (!par->mmap_map) {
+		PRINTKE("atyfb_setup_sparc() can't alloc mmap_map\n");
+		return -ENOMEM;
+	}
+	memset(par->mmap_map, 0, j * sizeof(*par->mmap_map));
+
+	for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) {
+		struct resource *rp = &pdev->resource[i];
+		int io, breg = PCI_BASE_ADDRESS_0 + (i << 2);
+		unsigned long base;
+		u32 size, pbase;
+
+		base = rp->start;
+
+		io = (rp->flags & IORESOURCE_IO);
+
+		size = rp->end - base + 1;
+
+		pci_read_config_dword(pdev, breg, &pbase);
+
+		if (io)
+			size &= ~1;
+
+		/*
+		 * Map the framebuffer a second time, this time without
+		 * the braindead _PAGE_IE setting. This is used by the
+		 * fixed Xserver, but we need to maintain the old mapping
+		 * to stay compatible with older ones...
+		 */
+		if (base == addr) {
+			par->mmap_map[j].voff = (pbase + 0x10000000) & PAGE_MASK;
+			par->mmap_map[j].poff = base & PAGE_MASK;
+			par->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK;
+			par->mmap_map[j].prot_mask = _PAGE_CACHE;
+			par->mmap_map[j].prot_flag = _PAGE_E;
+			j++;
+		}
+
+		/*
+		 * Here comes the old framebuffer mapping with _PAGE_IE
+		 * set for the big endian half of the framebuffer...
+		 */
+		if (base == addr) {
+			par->mmap_map[j].voff = (pbase + 0x800000) & PAGE_MASK;
+			par->mmap_map[j].poff = (base + 0x800000) & PAGE_MASK;
+			par->mmap_map[j].size = 0x800000;
+			par->mmap_map[j].prot_mask = _PAGE_CACHE;
+			par->mmap_map[j].prot_flag = _PAGE_E | _PAGE_IE;
+			size -= 0x800000;
+			j++;
+		}
+
+		par->mmap_map[j].voff = pbase & PAGE_MASK;
+		par->mmap_map[j].poff = base & PAGE_MASK;
+		par->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK;
+		par->mmap_map[j].prot_mask = _PAGE_CACHE;
+		par->mmap_map[j].prot_flag = _PAGE_E;
+		j++;
+	}
+
+	if((ret = correct_chipset(par)))
+		return ret;
+
+	if (IS_XL(pdev->device)) {
+		/*
+		 * Fix PROMs idea of MEM_CNTL settings...
+		 */
+		mem = aty_ld_le32(MEM_CNTL, par);
+		chip_id = aty_ld_le32(CONFIG_CHIP_ID, par);
+		if (((chip_id & CFG_CHIP_TYPE) == VT_CHIP_ID) && !((chip_id >> 24) & 1)) {
+			switch (mem & 0x0f) {
+			case 3:
+				mem = (mem & ~(0x0f)) | 2;
+				break;
+			case 7:
+				mem = (mem & ~(0x0f)) | 3;
+				break;
+			case 9:
+				mem = (mem & ~(0x0f)) | 4;
+				break;
+			case 11:
+				mem = (mem & ~(0x0f)) | 5;
+				break;
+			default:
+				break;
+			}
+			if ((aty_ld_le32(CONFIG_STAT0, par) & 7) >= SDRAM)
+				mem &= ~(0x00700000);
+		}
+		mem &= ~(0xcf80e000);	/* Turn off all undocumented bits. */
+		aty_st_le32(MEM_CNTL, mem, par);
+	}
+
+	/*
+	 * If this is the console device, we will set default video
+	 * settings to what the PROM left us with.
+	 */
+	node = prom_getchild(prom_root_node);
+	node = prom_searchsiblings(node, "aliases");
+	if (node) {
+		len = prom_getproperty(node, "screen", prop, sizeof(prop));
+		if (len > 0) {
+			prop[len] = '\0';
+			node = prom_finddevice(prop);
+		} else
+			node = 0;
+	}
+
+	pcp = pdev->sysdata;
+	if (node == pcp->prom_node) {
+		struct fb_var_screeninfo *var = &default_var;
+		unsigned int N, P, Q, M, T, R;
+		u32 v_total, h_total;
+		struct crtc crtc;
+		u8 pll_regs[16];
+		u8 clock_cntl;
+
+		crtc.vxres = prom_getintdefault(node, "width", 1024);
+		crtc.vyres = prom_getintdefault(node, "height", 768);
+		var->bits_per_pixel = prom_getintdefault(node, "depth", 8);
+		var->xoffset = var->yoffset = 0;
+		crtc.h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, par);
+		crtc.h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, par);
+		crtc.v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, par);
+		crtc.v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, par);
+		crtc.gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par);
+		aty_crtc_to_var(&crtc, var);
+
+		h_total = var->xres + var->right_margin + var->hsync_len + var->left_margin;
+		v_total = var->yres + var->lower_margin + var->vsync_len + var->upper_margin;
+
+		/*
+		 * Read the PLL to figure actual Refresh Rate.
+		 */
+		clock_cntl = aty_ld_8(CLOCK_CNTL, par);
+		/* DPRINTK("CLOCK_CNTL %02x\n", clock_cntl); */
+		for (i = 0; i < 16; i++)
+			pll_regs[i] = aty_ld_pll_ct(i, par);
+
+		/*
+		 * PLL Reference Divider M:
+		 */
+		M = pll_regs[2];
+
+		/*
+		 * PLL Feedback Divider N (Dependant on CLOCK_CNTL):
+		 */
+		N = pll_regs[7 + (clock_cntl & 3)];
+
+		/*
+		 * PLL Post Divider P (Dependant on CLOCK_CNTL):
+		 */
+		P = 1 << (pll_regs[6] >> ((clock_cntl & 3) << 1));
+
+		/*
+		 * PLL Divider Q:
+		 */
+		Q = N / P;
+
+		/*
+		 * Target Frequency:
+		 *
+		 *      T * M
+		 * Q = -------
+		 *      2 * R
+		 *
+		 * where R is XTALIN (= 14318 or 29498 kHz).
+		 */
+		if (IS_XL(pdev->device))
+			R = 29498;
+		else
+			R = 14318;
+
+		T = 2 * Q * R / M;
+
+		default_var.pixclock = 1000000000 / T;
+	}
+
+	return 0;
+}
+
+#else /* __sparc__ */
+
+#ifdef __i386__
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+static void aty_init_lcd(struct atyfb_par *par, u32 bios_base)
+{
+	u32 driv_inf_tab, sig;
+	u16 lcd_ofs;
+
+	/* To support an LCD panel, we should know it's dimensions and
+	 *  it's desired pixel clock.
+	 * There are two ways to do it:
+	 *  - Check the startup video mode and calculate the panel
+	 *    size from it. This is unreliable.
+	 *  - Read it from the driver information table in the video BIOS.
+	*/
+	/* Address of driver information table is at offset 0x78. */
+	driv_inf_tab = bios_base + *((u16 *)(bios_base+0x78));
+
+	/* Check for the driver information table signature. */
+	sig = (*(u32 *)driv_inf_tab);
+	if ((sig == 0x54504c24) || /* Rage LT pro */
+		(sig == 0x544d5224) || /* Rage mobility */
+		(sig == 0x54435824) || /* Rage XC */
+		(sig == 0x544c5824)) { /* Rage XL */
+		PRINTKI("BIOS contains driver information table.\n");
+		lcd_ofs = (*(u16 *)(driv_inf_tab + 10));
+		par->lcd_table = 0;
+		if (lcd_ofs != 0) {
+			par->lcd_table = bios_base + lcd_ofs;
+		}
+	}
+
+	if (par->lcd_table != 0) {
+		char model[24];
+		char strbuf[16];
+		char refresh_rates_buf[100];
+		int id, tech, f, i, m, default_refresh_rate;
+		char *txtcolour;
+		char *txtmonitor;
+		char *txtdual;
+		char *txtformat;
+		u16 width, height, panel_type, refresh_rates;
+		u16 *lcdmodeptr;
+		u32 format;
+		u8 lcd_refresh_rates[16] = {50,56,60,67,70,72,75,76,85,90,100,120,140,150,160,200};
+		/* The most important information is the panel size at
+		 * offset 25 and 27, but there's some other nice information
+		 * which we print to the screen.
+		 */
+		id = *(u8 *)par->lcd_table;
+		strncpy(model,(char *)par->lcd_table+1,24);
+		model[23]=0;
+
+		width = par->lcd_width = *(u16 *)(par->lcd_table+25);
+		height = par->lcd_height = *(u16 *)(par->lcd_table+27);
+		panel_type = *(u16 *)(par->lcd_table+29);
+		if (panel_type & 1)
+			txtcolour = "colour";
+		else
+			txtcolour = "monochrome";
+		if (panel_type & 2)
+			txtdual = "dual (split) ";
+		else
+			txtdual = "";
+		tech = (panel_type>>2) & 63;
+		switch (tech) {
+		case 0:
+			txtmonitor = "passive matrix";
+			break;
+		case 1:
+			txtmonitor = "active matrix";
+			break;
+		case 2:
+			txtmonitor = "active addressed STN";
+			break;
+		case 3:
+			txtmonitor = "EL";
+			break;
+		case 4:
+			txtmonitor = "plasma";
+			break;
+		default:
+			txtmonitor = "unknown";
+		}
+		format = *(u32 *)(par->lcd_table+57);
+		if (tech == 0 || tech == 2) {
+			switch (format & 7) {
+			case 0:
+				txtformat = "12 bit interface";
+				break;
+			case 1:
+				txtformat = "16 bit interface";
+				break;
+			case 2:
+				txtformat = "24 bit interface";
+				break;
+			default:
+				txtformat = "unkown format";
+			}
+		} else {
+			switch (format & 7) {
+			case 0:
+				txtformat = "8 colours";
+				break;
+			case 1:
+				txtformat = "512 colours";
+				break;
+			case 2:
+				txtformat = "4096 colours";
+				break;
+			case 4:
+				txtformat = "262144 colours (LT mode)";
+				break;
+			case 5:
+				txtformat = "16777216 colours";
+				break;
+			case 6:
+				txtformat = "262144 colours (FDPI-2 mode)";
+				break;
+			default:
+				txtformat = "unkown format";
+			}
+		}
+		PRINTKI("%s%s %s monitor detected: %s\n",
+			txtdual ,txtcolour, txtmonitor, model);
+		PRINTKI("       id=%d, %dx%d pixels, %s\n",
+			id, width, height, txtformat);
+		refresh_rates_buf[0] = 0;
+		refresh_rates = *(u16 *)(par->lcd_table+62);
+		m = 1;
+		f = 0;
+		for (i=0;i<16;i++) {
+			if (refresh_rates & m) {
+				if (f == 0) {
+					sprintf(strbuf, "%d", lcd_refresh_rates[i]);
+					f++;
+				} else {
+					sprintf(strbuf, ",%d", lcd_refresh_rates[i]);
+				}
+				strcat(refresh_rates_buf,strbuf);
+			}
+			m = m << 1;
+		}
+		default_refresh_rate = (*(u8 *)(par->lcd_table+61) & 0xf0) >> 4;
+		PRINTKI("       supports refresh rates [%s], default %d Hz\n",
+			refresh_rates_buf, lcd_refresh_rates[default_refresh_rate]);
+		par->lcd_refreshrate = lcd_refresh_rates[default_refresh_rate];
+		/* We now need to determine the crtc parameters for the
+		 * lcd monitor. This is tricky, because they are not stored
+		 * individually in the BIOS. Instead, the BIOS contains a
+		 * table of display modes that work for this monitor.
+		 *
+		 * The idea is that we search for a mode of the same dimensions
+		 * as the dimensions of the lcd monitor. Say our lcd monitor
+		 * is 800x600 pixels, we search for a 800x600 monitor.
+		 * The CRTC parameters we find here are the ones that we need
+		 * to use to simulate other resolutions on the lcd screen.
+		 */
+		lcdmodeptr = (u16 *)(par->lcd_table + 64);
+		while (*lcdmodeptr != 0) {
+			u32 modeptr;
+			u16 mwidth, mheight, lcd_hsync_start, lcd_vsync_start;
+			modeptr = bios_base + *lcdmodeptr;
+
+			mwidth = *((u16 *)(modeptr+0));
+			mheight = *((u16 *)(modeptr+2));
+
+			if (mwidth == width && mheight == height) {
+				par->lcd_pixclock = 100000000 / *((u16 *)(modeptr+9));
+				par->lcd_htotal = *((u16 *)(modeptr+17)) & 511;
+				par->lcd_hdisp = *((u16 *)(modeptr+19)) & 511;
+				lcd_hsync_start = *((u16 *)(modeptr+21)) & 511;
+				par->lcd_hsync_dly = (*((u16 *)(modeptr+21)) >> 9) & 7;
+				par->lcd_hsync_len = *((u8 *)(modeptr+23)) & 63;
+
+				par->lcd_vtotal = *((u16 *)(modeptr+24)) & 2047;
+				par->lcd_vdisp = *((u16 *)(modeptr+26)) & 2047;
+				lcd_vsync_start = *((u16 *)(modeptr+28)) & 2047;
+				par->lcd_vsync_len = (*((u16 *)(modeptr+28)) >> 11) & 31;
+
+				par->lcd_htotal = (par->lcd_htotal + 1) * 8;
+				par->lcd_hdisp = (par->lcd_hdisp + 1) * 8;
+				lcd_hsync_start = (lcd_hsync_start + 1) * 8;
+				par->lcd_hsync_len = par->lcd_hsync_len * 8;
+
+				par->lcd_vtotal++;
+				par->lcd_vdisp++;
+				lcd_vsync_start++;
+
+				par->lcd_right_margin = lcd_hsync_start - par->lcd_hdisp;
+				par->lcd_lower_margin = lcd_vsync_start - par->lcd_vdisp;
+				par->lcd_hblank_len = par->lcd_htotal - par->lcd_hdisp;
+				par->lcd_vblank_len = par->lcd_vtotal - par->lcd_vdisp;
+				break;
+			}
+
+			lcdmodeptr++;
+		}
+		if (*lcdmodeptr == 0) {
+			PRINTKE("LCD monitor CRTC parameters not found!!!\n");
+			/* To do: Switch to CRT if possible. */
+		} else {
+			PRINTKI("       LCD CRTC parameters: %d.%d  %d %d %d %d  %d %d %d %d\n",
+				1000000 / par->lcd_pixclock, 1000000 % par->lcd_pixclock,
+				par->lcd_hdisp,
+				par->lcd_hdisp + par->lcd_right_margin,
+				par->lcd_hdisp + par->lcd_right_margin
+					+ par->lcd_hsync_dly + par->lcd_hsync_len,
+				par->lcd_htotal,
+				par->lcd_vdisp,
+				par->lcd_vdisp + par->lcd_lower_margin,
+				par->lcd_vdisp + par->lcd_lower_margin + par->lcd_vsync_len,
+				par->lcd_vtotal);
+			PRINTKI("                          : %d %d %d %d %d %d %d %d %d\n",
+				par->lcd_pixclock,
+				par->lcd_hblank_len - (par->lcd_right_margin +
+					par->lcd_hsync_dly + par->lcd_hsync_len),
+				par->lcd_hdisp,
+				par->lcd_right_margin,
+				par->lcd_hsync_len,
+				par->lcd_vblank_len - (par->lcd_lower_margin + par->lcd_vsync_len),
+				par->lcd_vdisp,
+				par->lcd_lower_margin,
+				par->lcd_vsync_len);
+		}
+	}
+}
+#endif /* CONFIG_FB_ATY_GENERIC_LCD */
+
+static int __devinit init_from_bios(struct atyfb_par *par)
+{
+	u32 bios_base, rom_addr;
+	int ret;
+
+	rom_addr = 0xc0000 + ((aty_ld_le32(SCRATCH_REG1, par) & 0x7f) << 11);
+	bios_base = (unsigned long)ioremap(rom_addr, 0x10000);
+
+	/* The BIOS starts with 0xaa55. */
+	if (*((u16 *)bios_base) == 0xaa55) {
+
+		u8 *bios_ptr;
+		u16 rom_table_offset, freq_table_offset;
+		PLL_BLOCK_MACH64 pll_block;
+
+		PRINTKI("Mach64 BIOS is located at %x, mapped at %x.\n", rom_addr, bios_base);
+
+		/* check for frequncy table */
+		bios_ptr = (u8*)bios_base;
+		rom_table_offset = (u16)(bios_ptr[0x48] | (bios_ptr[0x49] << 8));
+		freq_table_offset = bios_ptr[rom_table_offset + 16] | (bios_ptr[rom_table_offset + 17] << 8);
+		memcpy(&pll_block, bios_ptr + freq_table_offset, sizeof(PLL_BLOCK_MACH64));
+
+		PRINTKI("BIOS frequency table:\n");
+		PRINTKI("PCLK_min_freq %d, PCLK_max_freq %d, ref_freq %d, ref_divider %d\n",
+			pll_block.PCLK_min_freq, pll_block.PCLK_max_freq,
+			pll_block.ref_freq, pll_block.ref_divider);
+		PRINTKI("MCLK_pwd %d, MCLK_max_freq %d, XCLK_max_freq %d, SCLK_freq %d\n",
+			pll_block.MCLK_pwd, pll_block.MCLK_max_freq,
+			pll_block.XCLK_max_freq, pll_block.SCLK_freq);
+
+		par->pll_limits.pll_min = pll_block.PCLK_min_freq/100;
+		par->pll_limits.pll_max = pll_block.PCLK_max_freq/100;
+		par->pll_limits.ref_clk = pll_block.ref_freq/100;
+		par->pll_limits.ref_div = pll_block.ref_divider;
+		par->pll_limits.sclk = pll_block.SCLK_freq/100;
+		par->pll_limits.mclk = pll_block.MCLK_max_freq/100;
+		par->pll_limits.mclk_pm = pll_block.MCLK_pwd/100;
+		par->pll_limits.xclk = pll_block.XCLK_max_freq/100;
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+		aty_init_lcd(par, bios_base);
+#endif
+		ret = 0;
+	} else {
+		PRINTKE("no BIOS frequency table found, use parameters\n");
+		ret = -ENXIO;
+	}
+	iounmap((void* __iomem )bios_base);
+
+	return ret;
+}
+#endif /* __i386__ */
+
+static int __devinit atyfb_setup_generic(struct pci_dev *pdev, struct fb_info *info, unsigned long addr)
+{
+	struct atyfb_par *par = info->par;
+	u16 tmp;
+	unsigned long raddr;
+	struct resource *rrp;
+	int ret = 0;
+
+	raddr = addr + 0x7ff000UL;
+	rrp = &pdev->resource[2];
+	if ((rrp->flags & IORESOURCE_MEM) && request_mem_region(rrp->start, rrp->end - rrp->start + 1, "atyfb")) {
+		par->aux_start = rrp->start;
+		par->aux_size = rrp->end - rrp->start + 1;
+		raddr = rrp->start;
+		PRINTKI("using auxiliary register aperture\n");
+	}
+
+	info->fix.mmio_start = raddr;
+	par->ati_regbase = ioremap(info->fix.mmio_start, 0x1000);
+	if (par->ati_regbase == 0)
+		return -ENOMEM;
+
+	info->fix.mmio_start += par->aux_start ? 0x400 : 0xc00;
+	par->ati_regbase += par->aux_start ? 0x400 : 0xc00;
+
+	/*
+	 * Enable memory-space accesses using config-space
+	 * command register.
+	 */
+	pci_read_config_word(pdev, PCI_COMMAND, &tmp);
+	if (!(tmp & PCI_COMMAND_MEMORY)) {
+		tmp |= PCI_COMMAND_MEMORY;
+		pci_write_config_word(pdev, PCI_COMMAND, tmp);
+	}
+#ifdef __BIG_ENDIAN
+	/* Use the big-endian aperture */
+	addr += 0x800000;
+#endif
+
+	/* Map in frame buffer */
+	info->fix.smem_start = addr;
+	info->screen_base = ioremap(addr, 0x800000);
+	if (info->screen_base == NULL) {
+		ret = -ENOMEM;
+		goto atyfb_setup_generic_fail;
+	}
+
+	if((ret = correct_chipset(par)))
+		goto atyfb_setup_generic_fail;
+#ifdef __i386__
+	if((ret = init_from_bios(par)))
+		goto atyfb_setup_generic_fail;
+#endif
+	if (!(aty_ld_le32(CRTC_GEN_CNTL, par) & CRTC_EXT_DISP_EN))
+		par->clk_wr_offset = (inb(R_GENMO) & 0x0CU) >> 2;
+	else
+		par->clk_wr_offset = aty_ld_8(CLOCK_CNTL, par) & 0x03U;
+
+	/* according to ATI, we should use clock 3 for acelerated mode */
+	par->clk_wr_offset = 3;
+
+	return 0;
+
+atyfb_setup_generic_fail:
+	iounmap(par->ati_regbase);
+	par->ati_regbase = NULL;
+	return ret;
+}
+
+#endif /* !__sparc__ */
+
+static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	unsigned long addr, res_start, res_size;
+	struct fb_info *info;
+	struct resource *rp;
+	struct atyfb_par *par;
+	int i, rc = -ENOMEM;
+
+	for (i = sizeof(aty_chips) / sizeof(*aty_chips) - 1; i >= 0; i--)
+		if (pdev->device == aty_chips[i].pci_id)
+			break;
+
+	if (i < 0)
+		return -ENODEV;
+
+	/* Enable device in PCI config */
+	if (pci_enable_device(pdev)) {
+		PRINTKE("Cannot enable PCI device\n");
+		return -ENXIO;
+	}
+
+	/* Find which resource to use */
+	rp = &pdev->resource[0];
+	if (rp->flags & IORESOURCE_IO)
+		rp = &pdev->resource[1];
+	addr = rp->start;
+	if (!addr)
+		return -ENXIO;
+
+	/* Reserve space */
+	res_start = rp->start;
+	res_size = rp->end - rp->start + 1;
+	if (!request_mem_region (res_start, res_size, "atyfb"))
+		return -EBUSY;
+
+        /* Allocate framebuffer */
+	info = framebuffer_alloc(sizeof(struct atyfb_par), &pdev->dev);
+	if (!info) {
+		PRINTKE("atyfb_pci_probe() can't alloc fb_info\n");
+		return -ENOMEM;
+	}
+	par = info->par;
+	info->fix = atyfb_fix;
+	info->device = &pdev->dev;
+	par->pci_id = aty_chips[i].pci_id;
+	par->res_start = res_start;
+	par->res_size = res_size;
+	par->irq = pdev->irq;
+
+	/* Setup "info" structure */
+#ifdef __sparc__
+	rc = atyfb_setup_sparc(pdev, info, addr);
+#else
+	rc = atyfb_setup_generic(pdev, info, addr);
+#endif
+	if (rc)
+		goto err_release_mem;
+
+	pci_set_drvdata(pdev, info);
+
+	/* Init chip & register framebuffer */
+	if (aty_init(info, "PCI"))
+		goto err_release_io;
+
+#ifdef __sparc__
+	if (!prom_palette)
+		prom_palette = atyfb_palette;
+
+	/*
+	 * Add /dev/fb mmap values.
+	 */
+	par->mmap_map[0].voff = 0x8000000000000000UL;
+	par->mmap_map[0].poff = (unsigned long) info->screen_base & PAGE_MASK;
+	par->mmap_map[0].size = info->fix.smem_len;
+	par->mmap_map[0].prot_mask = _PAGE_CACHE;
+	par->mmap_map[0].prot_flag = _PAGE_E;
+	par->mmap_map[1].voff = par->mmap_map[0].voff + info->fix.smem_len;
+	par->mmap_map[1].poff = (long)par->ati_regbase & PAGE_MASK;
+	par->mmap_map[1].size = PAGE_SIZE;
+	par->mmap_map[1].prot_mask = _PAGE_CACHE;
+	par->mmap_map[1].prot_flag = _PAGE_E;
+#endif /* __sparc__ */
+
+	return 0;
+
+err_release_io:
+#ifdef __sparc__
+	kfree(par->mmap_map);
+#else
+	if (par->ati_regbase)
+		iounmap(par->ati_regbase);
+	if (info->screen_base)
+		iounmap(info->screen_base);
+#endif
+err_release_mem:
+	if (par->aux_start)
+		release_mem_region(par->aux_start, par->aux_size);
+
+	release_mem_region(par->res_start, par->res_size);
+	framebuffer_release(info);
+
+	return rc;
+}
+
+#endif /* CONFIG_PCI */
+
+#ifdef CONFIG_ATARI
+
+static int __devinit atyfb_atari_probe(void)
+{
+	struct aty_par *par;
+	struct fb_info *info;
+	int m64_num;
+	u32 clock_r;
+
+	for (m64_num = 0; m64_num < mach64_count; m64_num++) {
+		if (!phys_vmembase[m64_num] || !phys_size[m64_num] ||
+		    !phys_guiregbase[m64_num]) {
+		    PRINTKI("phys_*[%d] parameters not set => returning early. \n", m64_num);
+			continue;
+		}
+
+		info = framebuffer_alloc(sizeof(struct atyfb_par), NULL);
+		if (!info) {
+			PRINTKE("atyfb_atari_probe() can't alloc fb_info\n");
+			return -ENOMEM;
+		}
+		par = info->par;
+
+		info->fix = atyfb_fix;
+
+		par->irq = (unsigned int) -1; /* something invalid */
+
+		/*
+		 *  Map the video memory (physical address given) to somewhere in the
+		 *  kernel address space.
+		 */
+		info->screen_base = ioremap(phys_vmembase[m64_num], phys_size[m64_num]);
+		info->fix.smem_start = (unsigned long)info->screen_base; /* Fake! */
+		par->ati_regbase = ioremap(phys_guiregbase[m64_num], 0x10000) +
+						0xFC00ul;
+		info->fix.mmio_start = (unsigned long)par->ati_regbase; /* Fake! */
+
+		aty_st_le32(CLOCK_CNTL, 0x12345678, par);
+		clock_r = aty_ld_le32(CLOCK_CNTL, par);
+
+		switch (clock_r & 0x003F) {
+		case 0x12:
+			par->clk_wr_offset = 3; /*  */
+			break;
+		case 0x34:
+			par->clk_wr_offset = 2; /* Medusa ST-IO ISA Adapter etc. */
+			break;
+		case 0x16:
+			par->clk_wr_offset = 1; /*  */
+			break;
+		case 0x38:
+			par->clk_wr_offset = 0; /* Panther 1 ISA Adapter (Gerald) */
+			break;
+		}
+
+		if (aty_init(info, "ISA bus")) {
+			framebuffer_release(info);
+			/* This is insufficient! kernel_map has added two large chunks!! */
+			return -ENXIO;
+		}
+	}
+}
+
+#endif /* CONFIG_ATARI */
+
+static void __devexit atyfb_remove(struct fb_info *info)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+
+	/* restore video mode */
+	aty_set_crtc(par, &saved_crtc);
+	par->pll_ops->set_pll(info, &saved_pll);
+
+	unregister_framebuffer(info);
+
+#ifdef CONFIG_MTRR
+	if (par->mtrr_reg >= 0) {
+	    mtrr_del(par->mtrr_reg, 0, 0);
+	    par->mtrr_reg = -1;
+	}
+	if (par->mtrr_aper >= 0) {
+	    mtrr_del(par->mtrr_aper, 0, 0);
+	    par->mtrr_aper = -1;
+	}
+#endif
+#ifndef __sparc__
+	if (par->ati_regbase)
+		iounmap(par->ati_regbase);
+	if (info->screen_base)
+		iounmap(info->screen_base);
+#ifdef __BIG_ENDIAN
+	if (info->sprite.addr)
+		iounmap(info->sprite.addr);
+#endif
+#endif
+#ifdef __sparc__
+	kfree(par->mmap_map);
+#endif
+	if (par->aux_start)
+		release_mem_region(par->aux_start, par->aux_size);
+
+	if (par->res_start)
+		release_mem_region(par->res_start, par->res_size);
+
+	framebuffer_release(info);
+}
+
+#ifdef CONFIG_PCI
+
+static void __devexit atyfb_pci_remove(struct pci_dev *pdev)
+{
+	struct fb_info *info = pci_get_drvdata(pdev);
+
+	atyfb_remove(info);
+}
+
+/*
+ * This driver uses its own matching table. That will be more difficult
+ * to fix, so for now, we just match against any ATI ID and let the
+ * probe() function find out what's up. That also mean we don't have
+ * a module ID table though.
+ */
+static struct pci_device_id atyfb_pci_tbl[] = {
+	{ PCI_VENDOR_ID_ATI, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+	  PCI_BASE_CLASS_DISPLAY << 16, 0xff0000, 0 },
+	{ 0, }
+};
+
+static struct pci_driver atyfb_driver = {
+	.name		= "atyfb",
+	.id_table	= atyfb_pci_tbl,
+	.probe		= atyfb_pci_probe,
+	.remove		= __devexit_p(atyfb_pci_remove),
+#ifdef CONFIG_PM
+	.suspend	= atyfb_pci_suspend,
+	.resume		= atyfb_pci_resume,
+#endif /* CONFIG_PM */
+};
+
+#endif /* CONFIG_PCI */
+
+#ifndef MODULE
+static int __init atyfb_setup(char *options)
+{
+	char *this_opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!strncmp(this_opt, "noaccel", 7)) {
+			noaccel = 1;
+#ifdef CONFIG_MTRR
+		} else if (!strncmp(this_opt, "nomtrr", 6)) {
+			nomtrr = 1;
+#endif
+		} else if (!strncmp(this_opt, "vram:", 5))
+			vram = simple_strtoul(this_opt + 5, NULL, 0);
+		else if (!strncmp(this_opt, "pll:", 4))
+			pll = simple_strtoul(this_opt + 4, NULL, 0);
+		else if (!strncmp(this_opt, "mclk:", 5))
+			mclk = simple_strtoul(this_opt + 5, NULL, 0);
+		else if (!strncmp(this_opt, "xclk:", 5))
+			xclk = simple_strtoul(this_opt+5, NULL, 0);
+		else if (!strncmp(this_opt, "comp_sync:", 10))
+			comp_sync = simple_strtoul(this_opt+10, NULL, 0);
+#ifdef CONFIG_PPC
+		else if (!strncmp(this_opt, "vmode:", 6)) {
+			unsigned int vmode =
+			    simple_strtoul(this_opt + 6, NULL, 0);
+			if (vmode > 0 && vmode <= VMODE_MAX)
+				default_vmode = vmode;
+		} else if (!strncmp(this_opt, "cmode:", 6)) {
+			unsigned int cmode =
+			    simple_strtoul(this_opt + 6, NULL, 0);
+			switch (cmode) {
+			case 0:
+			case 8:
+				default_cmode = CMODE_8;
+				break;
+			case 15:
+			case 16:
+				default_cmode = CMODE_16;
+				break;
+			case 24:
+			case 32:
+				default_cmode = CMODE_32;
+				break;
+			}
+		}
+#endif
+#ifdef CONFIG_ATARI
+		/*
+		 * Why do we need this silly Mach64 argument?
+		 * We are already here because of mach64= so its redundant.
+		 */
+		else if (MACH_IS_ATARI
+			 && (!strncmp(this_opt, "Mach64:", 7))) {
+			static unsigned char m64_num;
+			static char mach64_str[80];
+			strlcpy(mach64_str, this_opt + 7, sizeof(mach64_str));
+			if (!store_video_par(mach64_str, m64_num)) {
+				m64_num++;
+				mach64_count = m64_num;
+			}
+		}
+#endif
+		else
+			mode = this_opt;
+	}
+	return 0;
+}
+#endif  /*  MODULE  */
+
+static int __init atyfb_init(void)
+{
+#ifndef MODULE
+    char *option = NULL;
+
+    if (fb_get_options("atyfb", &option))
+	return -ENODEV;
+    atyfb_setup(option);
+#endif
+
+#ifdef CONFIG_PCI
+    pci_register_driver(&atyfb_driver);
+#endif
+#ifdef CONFIG_ATARI
+    atyfb_atari_probe();
+#endif
+    return 0;
+}
+
+static void __exit atyfb_exit(void)
+{
+#ifdef CONFIG_PCI
+	pci_unregister_driver(&atyfb_driver);
+#endif
+}
+
+module_init(atyfb_init);
+module_exit(atyfb_exit);
+
+MODULE_DESCRIPTION("FBDev driver for ATI Mach64 cards");
+MODULE_LICENSE("GPL");
+module_param(noaccel, bool, 0);
+MODULE_PARM_DESC(noaccel, "bool: disable acceleration");
+module_param(vram, int, 0);
+MODULE_PARM_DESC(vram, "int: override size of video ram");
+module_param(pll, int, 0);
+MODULE_PARM_DESC(pll, "int: override video clock");
+module_param(mclk, int, 0);
+MODULE_PARM_DESC(mclk, "int: override memory clock");
+module_param(xclk, int, 0);
+MODULE_PARM_DESC(xclk, "int: override accelerated engine clock");
+module_param(comp_sync, int, 0);
+MODULE_PARM_DESC(comp_sync,
+		 "Set composite sync signal to low (0) or high (1)");
+module_param(mode, charp, 0);
+MODULE_PARM_DESC(mode, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
+#ifdef CONFIG_MTRR
+module_param(nomtrr, bool, 0);
+MODULE_PARM_DESC(nomtrr, "bool: disable use of MTRR registers");
+#endif
diff --git a/drivers/video/aty/mach64_accel.c b/drivers/video/aty/mach64_accel.c
new file mode 100644
index 0000000..c98f4a4
--- /dev/null
+++ b/drivers/video/aty/mach64_accel.c
@@ -0,0 +1,433 @@
+
+/*
+ *  ATI Mach64 Hardware Acceleration
+ */
+
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <video/mach64.h>
+#include "atyfb.h"
+
+    /*
+     *  Generic Mach64 routines
+     */
+
+/* this is for DMA GUI engine! work in progress */
+typedef struct {
+	u32 frame_buf_offset;
+	u32 system_mem_addr;
+	u32 command;
+	u32 reserved;
+} BM_DESCRIPTOR_ENTRY;
+
+#define LAST_DESCRIPTOR (1 << 31)
+#define SYSTEM_TO_FRAME_BUFFER 0
+
+static u32 rotation24bpp(u32 dx, u32 direction)
+{
+	u32 rotation;
+	if (direction & DST_X_LEFT_TO_RIGHT) {
+		rotation = (dx / 4) % 6;
+	} else {
+		rotation = ((dx + 2) / 4) % 6;
+	}
+
+	return ((rotation << 8) | DST_24_ROTATION_ENABLE);
+}
+
+void aty_reset_engine(const struct atyfb_par *par)
+{
+	/* reset engine */
+	aty_st_le32(GEN_TEST_CNTL,
+		aty_ld_le32(GEN_TEST_CNTL, par) & ~GUI_ENGINE_ENABLE, par);
+	/* enable engine */
+	aty_st_le32(GEN_TEST_CNTL,
+		aty_ld_le32(GEN_TEST_CNTL, par) | GUI_ENGINE_ENABLE, par);
+	/* ensure engine is not locked up by clearing any FIFO or */
+	/* HOST errors */
+	aty_st_le32(BUS_CNTL,
+		aty_ld_le32(BUS_CNTL, par) | BUS_HOST_ERR_ACK | BUS_FIFO_ERR_ACK, par);
+}
+
+static void reset_GTC_3D_engine(const struct atyfb_par *par)
+{
+	aty_st_le32(SCALE_3D_CNTL, 0xc0, par);
+	mdelay(GTC_3D_RESET_DELAY);
+	aty_st_le32(SETUP_CNTL, 0x00, par);
+	mdelay(GTC_3D_RESET_DELAY);
+	aty_st_le32(SCALE_3D_CNTL, 0x00, par);
+	mdelay(GTC_3D_RESET_DELAY);
+}
+
+void aty_init_engine(struct atyfb_par *par, struct fb_info *info)
+{
+	u32 pitch_value;
+
+	/* determine modal information from global mode structure */
+	pitch_value = info->var.xres_virtual;
+
+	if (info->var.bits_per_pixel == 24) {
+		/* In 24 bpp, the engine is in 8 bpp - this requires that all */
+		/* horizontal coordinates and widths must be adjusted */
+		pitch_value *= 3;
+	}
+
+	/* On GTC (RagePro), we need to reset the 3D engine before */
+	if (M64_HAS(RESET_3D))
+		reset_GTC_3D_engine(par);
+
+	/* Reset engine, enable, and clear any engine errors */
+	aty_reset_engine(par);
+	/* Ensure that vga page pointers are set to zero - the upper */
+	/* page pointers are set to 1 to handle overflows in the */
+	/* lower page */
+	aty_st_le32(MEM_VGA_WP_SEL, 0x00010000, par);
+	aty_st_le32(MEM_VGA_RP_SEL, 0x00010000, par);
+
+	/* ---- Setup standard engine context ---- */
+
+	/* All GUI registers here are FIFOed - therefore, wait for */
+	/* the appropriate number of empty FIFO entries */
+	wait_for_fifo(14, par);
+
+	/* enable all registers to be loaded for context loads */
+	aty_st_le32(CONTEXT_MASK, 0xFFFFFFFF, par);
+
+	/* set destination pitch to modal pitch, set offset to zero */
+	aty_st_le32(DST_OFF_PITCH, (pitch_value / 8) << 22, par);
+
+	/* zero these registers (set them to a known state) */
+	aty_st_le32(DST_Y_X, 0, par);
+	aty_st_le32(DST_HEIGHT, 0, par);
+	aty_st_le32(DST_BRES_ERR, 0, par);
+	aty_st_le32(DST_BRES_INC, 0, par);
+	aty_st_le32(DST_BRES_DEC, 0, par);
+
+	/* set destination drawing attributes */
+	aty_st_le32(DST_CNTL, DST_LAST_PEL | DST_Y_TOP_TO_BOTTOM |
+		    DST_X_LEFT_TO_RIGHT, par);
+
+	/* set source pitch to modal pitch, set offset to zero */
+	aty_st_le32(SRC_OFF_PITCH, (pitch_value / 8) << 22, par);
+
+	/* set these registers to a known state */
+	aty_st_le32(SRC_Y_X, 0, par);
+	aty_st_le32(SRC_HEIGHT1_WIDTH1, 1, par);
+	aty_st_le32(SRC_Y_X_START, 0, par);
+	aty_st_le32(SRC_HEIGHT2_WIDTH2, 1, par);
+
+	/* set source pixel retrieving attributes */
+	aty_st_le32(SRC_CNTL, SRC_LINE_X_LEFT_TO_RIGHT, par);
+
+	/* set host attributes */
+	wait_for_fifo(13, par);
+	aty_st_le32(HOST_CNTL, 0, par);
+
+	/* set pattern attributes */
+	aty_st_le32(PAT_REG0, 0, par);
+	aty_st_le32(PAT_REG1, 0, par);
+	aty_st_le32(PAT_CNTL, 0, par);
+
+	/* set scissors to modal size */
+	aty_st_le32(SC_LEFT, 0, par);
+	aty_st_le32(SC_TOP, 0, par);
+	aty_st_le32(SC_BOTTOM, par->crtc.vyres - 1, par);
+	aty_st_le32(SC_RIGHT, pitch_value - 1, par);
+
+	/* set background color to minimum value (usually BLACK) */
+	aty_st_le32(DP_BKGD_CLR, 0, par);
+
+	/* set foreground color to maximum value (usually WHITE) */
+	aty_st_le32(DP_FRGD_CLR, 0xFFFFFFFF, par);
+
+	/* set write mask to effect all pixel bits */
+	aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF, par);
+
+	/* set foreground mix to overpaint and background mix to */
+	/* no-effect */
+	aty_st_le32(DP_MIX, FRGD_MIX_S | BKGD_MIX_D, par);
+
+	/* set primary source pixel channel to foreground color */
+	/* register */
+	aty_st_le32(DP_SRC, FRGD_SRC_FRGD_CLR, par);
+
+	/* set compare functionality to false (no-effect on */
+	/* destination) */
+	wait_for_fifo(3, par);
+	aty_st_le32(CLR_CMP_CLR, 0, par);
+	aty_st_le32(CLR_CMP_MASK, 0xFFFFFFFF, par);
+	aty_st_le32(CLR_CMP_CNTL, 0, par);
+
+	/* set pixel depth */
+	wait_for_fifo(2, par);
+	aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, par);
+	aty_st_le32(DP_CHAIN_MASK, par->crtc.dp_chain_mask, par);
+
+	wait_for_fifo(5, par);
+ 	aty_st_le32(SCALE_3D_CNTL, 0, par);
+	aty_st_le32(Z_CNTL, 0, par);
+	aty_st_le32(CRTC_INT_CNTL, aty_ld_le32(CRTC_INT_CNTL, par) & ~0x20,
+		    par);
+	aty_st_le32(GUI_TRAJ_CNTL, 0x100023, par);
+
+	/* insure engine is idle before leaving */
+	wait_for_idle(par);
+}
+
+    /*
+     *  Accelerated functions
+     */
+
+static inline void draw_rect(s16 x, s16 y, u16 width, u16 height,
+			     struct atyfb_par *par)
+{
+	/* perform rectangle fill */
+	wait_for_fifo(2, par);
+	aty_st_le32(DST_Y_X, (x << 16) | y, par);
+	aty_st_le32(DST_HEIGHT_WIDTH, (width << 16) | height, par);
+	par->blitter_may_be_busy = 1;
+}
+
+void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	u32 dy = area->dy, sy = area->sy, direction = DST_LAST_PEL;
+	u32 sx = area->sx, dx = area->dx, width = area->width, rotation = 0;
+
+	if (par->asleep)
+		return;
+	if (!area->width || !area->height)
+		return;
+	if (!par->accel_flags) {
+		if (par->blitter_may_be_busy)
+			wait_for_idle(par);
+		cfb_copyarea(info, area);
+		return;
+	}
+
+	if (info->var.bits_per_pixel == 24) {
+		/* In 24 bpp, the engine is in 8 bpp - this requires that all */
+		/* horizontal coordinates and widths must be adjusted */
+		sx *= 3;
+		dx *= 3;
+		width *= 3;
+	}
+
+	if (area->sy < area->dy) {
+		dy += area->height - 1;
+		sy += area->height - 1;
+	} else
+		direction |= DST_Y_TOP_TO_BOTTOM;
+
+	if (sx < dx) {
+		dx += width - 1;
+		sx += width - 1;
+	} else
+		direction |= DST_X_LEFT_TO_RIGHT;
+
+	if (info->var.bits_per_pixel == 24) {
+		rotation = rotation24bpp(dx, direction);
+	}
+
+	wait_for_fifo(4, par);
+	aty_st_le32(DP_SRC, FRGD_SRC_BLIT, par);
+	aty_st_le32(SRC_Y_X, (sx << 16) | sy, par);
+	aty_st_le32(SRC_HEIGHT1_WIDTH1, (width << 16) | area->height, par);
+	aty_st_le32(DST_CNTL, direction | rotation, par);
+	draw_rect(dx, dy, width, area->height, par);
+}
+
+void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	u32 color = rect->color, dx = rect->dx, width = rect->width, rotation = 0;
+
+	if (par->asleep)
+		return;
+	if (!rect->width || !rect->height)
+		return;
+	if (!par->accel_flags) {
+		if (par->blitter_may_be_busy)
+			wait_for_idle(par);
+		cfb_fillrect(info, rect);
+		return;
+	}
+
+	color |= (rect->color << 8);
+	color |= (rect->color << 16);
+
+	if (info->var.bits_per_pixel == 24) {
+		/* In 24 bpp, the engine is in 8 bpp - this requires that all */
+		/* horizontal coordinates and widths must be adjusted */
+		dx *= 3;
+		width *= 3;
+		rotation = rotation24bpp(dx, DST_X_LEFT_TO_RIGHT);
+	}
+
+	wait_for_fifo(3, par);
+	aty_st_le32(DP_FRGD_CLR, color, par);
+	aty_st_le32(DP_SRC,
+		    BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE,
+		    par);
+	aty_st_le32(DST_CNTL,
+		    DST_LAST_PEL | DST_Y_TOP_TO_BOTTOM |
+		    DST_X_LEFT_TO_RIGHT | rotation, par);
+	draw_rect(dx, rect->dy, width, rect->height, par);
+}
+
+void atyfb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	u32 src_bytes, dx = image->dx, dy = image->dy, width = image->width;
+	u32 pix_width_save, pix_width, host_cntl, rotation = 0, src, mix;
+
+	if (par->asleep)
+		return;
+	if (!image->width || !image->height)
+		return;
+	if (!par->accel_flags ||
+	    (image->depth != 1 && info->var.bits_per_pixel != image->depth)) {
+		if (par->blitter_may_be_busy)
+			wait_for_idle(par);
+
+		cfb_imageblit(info, image);
+		return;
+	}
+
+	wait_for_idle(par);
+	pix_width = pix_width_save = aty_ld_le32(DP_PIX_WIDTH, par);
+	host_cntl = aty_ld_le32(HOST_CNTL, par) | HOST_BYTE_ALIGN;
+
+	switch (image->depth) {
+	case 1:
+	    pix_width &= ~(BYTE_ORDER_MASK | HOST_MASK);
+	    pix_width |= (BYTE_ORDER_MSB_TO_LSB | HOST_1BPP);
+	    break;
+	case 4:
+	    pix_width &= ~(BYTE_ORDER_MASK | HOST_MASK);
+	    pix_width |= (BYTE_ORDER_MSB_TO_LSB | HOST_4BPP);
+	    break;
+	case 8:
+	    pix_width &= ~HOST_MASK;
+	    pix_width |= HOST_8BPP;
+	    break;
+	case 15:
+	    pix_width &= ~HOST_MASK;
+	    pix_width |= HOST_15BPP;
+	    break;
+	case 16:
+	    pix_width &= ~HOST_MASK;
+	    pix_width |= HOST_16BPP;
+	    break;
+	case 24:
+	    pix_width &= ~HOST_MASK;
+	    pix_width |= HOST_24BPP;
+	    break;
+	case 32:
+	    pix_width &= ~HOST_MASK;
+	    pix_width |= HOST_32BPP;
+	    break;
+	}
+
+	if (info->var.bits_per_pixel == 24) {
+		/* In 24 bpp, the engine is in 8 bpp - this requires that all */
+		/* horizontal coordinates and widths must be adjusted */
+		dx *= 3;
+		width *= 3;
+
+		rotation = rotation24bpp(dx, DST_X_LEFT_TO_RIGHT);
+
+		pix_width &= ~DST_MASK;
+		pix_width |= DST_8BPP;
+
+		/*
+		 * since Rage 3D IIc we have DP_HOST_TRIPLE_EN bit
+		 * this hwaccelerated triple has an issue with not aligned data
+		 */
+		if (M64_HAS(HW_TRIPLE) && image->width % 8 == 0)
+			pix_width |= DP_HOST_TRIPLE_EN;
+	}
+
+	if (image->depth == 1) {
+		u32 fg, bg;
+		if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
+		    info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+			fg = ((u32*)(info->pseudo_palette))[image->fg_color];
+			bg = ((u32*)(info->pseudo_palette))[image->bg_color];
+		} else {
+			fg = image->fg_color;
+			bg = image->bg_color;
+		}
+
+		wait_for_fifo(2, par);
+		aty_st_le32(DP_BKGD_CLR, bg, par);
+		aty_st_le32(DP_FRGD_CLR, fg, par);
+		src = MONO_SRC_HOST | FRGD_SRC_FRGD_CLR | BKGD_SRC_BKGD_CLR;
+		mix = FRGD_MIX_S | BKGD_MIX_S;
+	} else {
+		src = MONO_SRC_ONE | FRGD_SRC_HOST;
+		mix = FRGD_MIX_D_XOR_S | BKGD_MIX_D;
+	}
+
+	wait_for_fifo(6, par);
+	aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF, par);
+	aty_st_le32(DP_PIX_WIDTH, pix_width, par);
+	aty_st_le32(DP_MIX, mix, par);
+	aty_st_le32(DP_SRC, src, par);
+	aty_st_le32(HOST_CNTL, host_cntl, par);
+	aty_st_le32(DST_CNTL, DST_Y_TOP_TO_BOTTOM | DST_X_LEFT_TO_RIGHT | rotation, par);
+
+	draw_rect(dx, dy, width, image->height, par);
+	src_bytes = (((image->width * image->depth) + 7) / 8) * image->height;
+
+	/* manual triple each pixel */
+	if (info->var.bits_per_pixel == 24 && !(pix_width & DP_HOST_TRIPLE_EN)) {
+		int inbit, outbit, mult24, byte_id_in_dword, width;
+		u8 *pbitmapin = (u8*)image->data, *pbitmapout;
+		u32 hostdword;
+
+		for (width = image->width, inbit = 7, mult24 = 0; src_bytes; ) {
+			for (hostdword = 0, pbitmapout = (u8*)&hostdword, byte_id_in_dword = 0;
+				byte_id_in_dword < 4 && src_bytes;
+				byte_id_in_dword++, pbitmapout++) {
+				for (outbit = 7; outbit >= 0; outbit--) {
+					*pbitmapout |= (((*pbitmapin >> inbit) & 1) << outbit);
+					mult24++;
+					/* next bit */
+					if (mult24 == 3) {
+						mult24 = 0;
+						inbit--;
+						width--;
+					}
+
+					/* next byte */
+					if (inbit < 0 || width == 0) {
+						src_bytes--;
+						pbitmapin++;
+						inbit = 7;
+
+						if (width == 0) {
+						    width = image->width;
+						    outbit = 0;
+						}
+					}
+				}
+			}
+			wait_for_fifo(1, par);
+			aty_st_le32(HOST_DATA0, hostdword, par);
+		}
+	} else {
+		u32 *pbitmap, dwords = (src_bytes + 3) / 4;
+		for (pbitmap = (u32*)(image->data); dwords; dwords--, pbitmap++) {
+			wait_for_fifo(1, par);
+			aty_st_le32(HOST_DATA0, le32_to_cpup(pbitmap), par);
+		}
+	}
+
+	wait_for_idle(par);
+
+	/* restore pix_width */
+	wait_for_fifo(1, par);
+	aty_st_le32(DP_PIX_WIDTH, pix_width_save, par);
+}
diff --git a/drivers/video/aty/mach64_ct.c b/drivers/video/aty/mach64_ct.c
new file mode 100644
index 0000000..9bdb2aa
--- /dev/null
+++ b/drivers/video/aty/mach64_ct.c
@@ -0,0 +1,619 @@
+
+/*
+ *  ATI Mach64 CT/VT/GT/LT Support
+ */
+
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <video/mach64.h>
+#include "atyfb.h"
+
+#undef DEBUG
+
+static int aty_valid_pll_ct (const struct fb_info *info, u32 vclk_per, struct pll_ct *pll);
+static int aty_dsp_gt       (const struct fb_info *info, u32 bpp, struct pll_ct *pll);
+static int aty_var_to_pll_ct(const struct fb_info *info, u32 vclk_per, u32 bpp, union aty_pll *pll);
+static u32 aty_pll_to_var_ct(const struct fb_info *info, const union aty_pll *pll);
+
+u8 aty_ld_pll_ct(int offset, const struct atyfb_par *par)
+{
+	u8 res;
+
+	/* write addr byte */
+	aty_st_8(CLOCK_CNTL_ADDR, (offset << 2) & PLL_ADDR, par);
+	/* read the register value */
+	res = aty_ld_8(CLOCK_CNTL_DATA, par);
+	return res;
+}
+
+void aty_st_pll_ct(int offset, u8 val, const struct atyfb_par *par)
+{
+	/* write addr byte */
+	aty_st_8(CLOCK_CNTL_ADDR, ((offset << 2) & PLL_ADDR) | PLL_WR_EN, par);
+	/* write the register value */
+	aty_st_8(CLOCK_CNTL_DATA, val & PLL_DATA, par);
+	aty_st_8(CLOCK_CNTL_ADDR, ((offset << 2) & PLL_ADDR) & ~PLL_WR_EN, par);
+}
+
+/*
+ * by Daniel Mantione
+ *                                  <daniel.mantione@freepascal.org>
+ *
+ *
+ * ATI Mach64 CT clock synthesis description.
+ *
+ * All clocks on the Mach64 can be calculated using the same principle:
+ *
+ *       XTALIN * x * FB_DIV
+ * CLK = ----------------------
+ *       PLL_REF_DIV * POST_DIV
+ *
+ * XTALIN is a fixed speed clock. Common speeds are 14.31 MHz and 29.50 MHz.
+ * PLL_REF_DIV can be set by the user, but is the same for all clocks.
+ * FB_DIV can be set by the user for each clock individually, it should be set
+ * between 128 and 255, the chip will generate a bad clock signal for too low
+ * values.
+ * x depends on the type of clock; usually it is 2, but for the MCLK it can also
+ * be set to 4.
+ * POST_DIV can be set by the user for each clock individually, Possible values
+ * are 1,2,4,8 and for some clocks other values are available too.
+ * CLK is of course the clock speed that is generated.
+ *
+ * The Mach64 has these clocks:
+ *
+ * MCLK			The clock rate of the chip
+ * XCLK			The clock rate of the on-chip memory
+ * VCLK0		First pixel clock of first CRT controller
+ * VCLK1    Second pixel clock of first CRT controller
+ * VCLK2		Third pixel clock of first CRT controller
+ * VCLK3    Fourth pixel clock of first CRT controller
+ * VCLK			Selected pixel clock, one of VCLK0, VCLK1, VCLK2, VCLK3
+ * V2CLK		Pixel clock of the second CRT controller.
+ * SCLK			Multi-purpose clock
+ *
+ * - MCLK and XCLK use the same FB_DIV
+ * - VCLK0 .. VCLK3 use the same FB_DIV
+ * - V2CLK is needed when the second CRTC is used (can be used for dualhead);
+ *   i.e. CRT monitor connected to laptop has different resolution than built
+ *   in LCD monitor.
+ * - SCLK is not available on all cards; it is know to exist on the Rage LT-PRO,
+ *   Rage XL and Rage Mobility. It is know not to exist on the Mach64 VT.
+ * - V2CLK is not available on all cards, most likely only the Rage LT-PRO,
+ *   the Rage XL and the Rage Mobility
+ *
+ * SCLK can be used to:
+ * - Clock the chip instead of MCLK
+ * - Replace XTALIN with a user defined frequency
+ * - Generate the pixel clock for the LCD monitor (instead of VCLK)
+ */
+
+ /*
+  * It can be quite hard to calculate XCLK and MCLK if they don't run at the
+  * same frequency. Luckily, until now all cards that need asynchrone clock
+  * speeds seem to have SCLK.
+  * So this driver uses SCLK to clock the chip and XCLK to clock the memory.
+  */
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ *  PLL programming (Mach64 CT family)
+ *
+ *
+ * This procedure sets the display fifo. The display fifo is a buffer that
+ * contains data read from the video memory that waits to be processed by
+ * the CRT controller.
+ *
+ * On the more modern Mach64 variants, the chip doesn't calculate the
+ * interval after which the display fifo has to be reloaded from memory
+ * automatically, the driver has to do it instead.
+ */
+
+#define Maximum_DSP_PRECISION 7
+static u8 postdividers[] = {1,2,4,8,3};
+
+static int aty_dsp_gt(const struct fb_info *info, u32 bpp, struct pll_ct *pll)
+{
+	u32 dsp_off, dsp_on, dsp_xclks;
+	u32 multiplier, divider, ras_multiplier, ras_divider, tmp;
+	u8 vshift, xshift;
+	s8 dsp_precision;
+
+	multiplier = ((u32)pll->mclk_fb_div) * pll->vclk_post_div_real;
+	divider = ((u32)pll->vclk_fb_div) * pll->xclk_ref_div;
+
+	ras_multiplier = pll->xclkmaxrasdelay;
+	ras_divider = 1;
+
+	if (bpp>=8)
+		divider = divider * (bpp >> 2);
+
+	vshift = (6 - 2) - pll->xclk_post_div;	/* FIFO is 64 bits wide in accelerator mode ... */
+
+	if (bpp == 0)
+		vshift--;	/* ... but only 32 bits in VGA mode. */
+
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+	if (pll->xres != 0) {
+		struct atyfb_par *par = (struct atyfb_par *) info->par;
+
+		multiplier = multiplier * par->lcd_width;
+		divider = divider * pll->xres & ~7;
+
+		ras_multiplier = ras_multiplier * par->lcd_width;
+		ras_divider = ras_divider * pll->xres & ~7;
+	}
+#endif
+	/* If we don't do this, 32 bits for multiplier & divider won't be
+	enough in certain situations! */
+	while (((multiplier | divider) & 1) == 0) {
+		multiplier = multiplier >> 1;
+		divider = divider >> 1;
+	}
+
+	/* Determine DSP precision first */
+	tmp = ((multiplier * pll->fifo_size) << vshift) / divider;
+
+	for (dsp_precision = -5;  tmp;  dsp_precision++)
+		tmp >>= 1;
+	if (dsp_precision < 0)
+		dsp_precision = 0;
+	else if (dsp_precision > Maximum_DSP_PRECISION)
+		dsp_precision = Maximum_DSP_PRECISION;
+
+	xshift = 6 - dsp_precision;
+	vshift += xshift;
+
+	/* Move on to dsp_off */
+	dsp_off = ((multiplier * (pll->fifo_size - 1)) << vshift) / divider -
+		(1 << (vshift - xshift));
+
+/*    if (bpp == 0)
+        dsp_on = ((multiplier * 20 << vshift) + divider) / divider;
+    else */
+	{
+		dsp_on = ((multiplier << vshift) + divider) / divider;
+		tmp = ((ras_multiplier << xshift) + ras_divider) / ras_divider;
+		if (dsp_on < tmp)
+		dsp_on = tmp;
+		dsp_on = dsp_on + (tmp * 2) + (pll->xclkpagefaultdelay << xshift);
+	}
+
+	/* Calculate rounding factor and apply it to dsp_on */
+	tmp = ((1 << (Maximum_DSP_PRECISION - dsp_precision)) - 1) >> 1;
+	dsp_on = ((dsp_on + tmp) / (tmp + 1)) * (tmp + 1);
+
+	if (dsp_on >= ((dsp_off / (tmp + 1)) * (tmp + 1))) {
+		dsp_on = dsp_off - (multiplier << vshift) / divider;
+		dsp_on = (dsp_on / (tmp + 1)) * (tmp + 1);
+	}
+
+	/* Last but not least:  dsp_xclks */
+	dsp_xclks = ((multiplier << (vshift + 5)) + divider) / divider;
+
+	/* Get register values. */
+	pll->dsp_on_off = (dsp_on << 16) + dsp_off;
+	pll->dsp_config = (dsp_precision << 20) | (pll->dsp_loop_latency << 16) | dsp_xclks;
+#ifdef DEBUG
+	printk("atyfb(%s): dsp_config 0x%08x, dsp_on_off 0x%08x\n",
+		__FUNCTION__, pll->dsp_config, pll->dsp_on_off);
+#endif
+	return 0;
+}
+
+static int aty_valid_pll_ct(const struct fb_info *info, u32 vclk_per, struct pll_ct *pll)
+{
+	u32 q;
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+#ifdef DEBUG
+	int pllvclk;
+#endif
+
+	/* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */
+	q = par->ref_clk_per * pll->pll_ref_div * 4 / vclk_per;
+	if (q < 16*8 || q > 255*8) {
+		printk(KERN_CRIT "atyfb: vclk out of range\n");
+		return -EINVAL;
+	} else {
+		pll->vclk_post_div  = (q < 128*8);
+		pll->vclk_post_div += (q <  64*8);
+		pll->vclk_post_div += (q <  32*8);
+	}
+	pll->vclk_post_div_real = postdividers[pll->vclk_post_div];
+	//    pll->vclk_post_div <<= 6;
+	pll->vclk_fb_div = q * pll->vclk_post_div_real / 8;
+#ifdef DEBUG
+	pllvclk = (1000000 * 2 * pll->vclk_fb_div) /
+		(par->ref_clk_per * pll->pll_ref_div);
+	printk("atyfb(%s): pllvclk=%d MHz, vclk=%d MHz\n",
+		__FUNCTION__, pllvclk, pllvclk / pll->vclk_post_div_real);
+#endif
+	pll->pll_vclk_cntl = 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */
+	return 0;
+}
+
+static int aty_var_to_pll_ct(const struct fb_info *info, u32 vclk_per, u32 bpp, union aty_pll *pll)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	int err;
+
+	if ((err = aty_valid_pll_ct(info, vclk_per, &pll->ct)))
+		return err;
+	if (M64_HAS(GTB_DSP) && (err = aty_dsp_gt(info, bpp, &pll->ct)))
+		return err;
+	/*aty_calc_pll_ct(info, &pll->ct);*/
+	return 0;
+}
+
+static u32 aty_pll_to_var_ct(const struct fb_info *info, const union aty_pll *pll)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	u32 ret;
+	ret = par->ref_clk_per * pll->ct.pll_ref_div * pll->ct.vclk_post_div_real / pll->ct.vclk_fb_div / 2;
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+	if(pll->ct.xres > 0) {
+		ret *= par->lcd_width;
+		ret /= pll->ct.xres;
+	}
+#endif
+#ifdef DEBUG
+	printk("atyfb(%s): calculated 0x%08X(%i)\n", __FUNCTION__, ret, ret);
+#endif
+	return ret;
+}
+
+void aty_set_pll_ct(const struct fb_info *info, const union aty_pll *pll)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	u32 crtc_gen_cntl, lcd_gen_cntrl;
+	u8 tmp, tmp2;
+
+	lcd_gen_cntrl = 0;
+#ifdef DEBUG
+	printk("atyfb(%s): about to program:\n"
+		"pll_ext_cntl=0x%02x pll_gen_cntl=0x%02x pll_vclk_cntl=0x%02x\n",
+		__FUNCTION__,
+		pll->ct.pll_ext_cntl, pll->ct.pll_gen_cntl, pll->ct.pll_vclk_cntl);
+
+	printk("atyfb(%s): setting clock %lu for FeedBackDivider %i, ReferenceDivider %i, PostDivider %i(%i)\n",
+		__FUNCTION__,
+		par->clk_wr_offset, pll->ct.vclk_fb_div,
+		pll->ct.pll_ref_div, pll->ct.vclk_post_div, pll->ct.vclk_post_div_real);
+#endif
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+	if (par->lcd_table != 0) {
+		/* turn off LCD */
+		lcd_gen_cntrl = aty_ld_lcd(LCD_GEN_CNTL, par);
+		aty_st_lcd(LCD_GEN_CNTL, lcd_gen_cntrl & ~LCD_ON, par);
+	}
+#endif
+	aty_st_8(CLOCK_CNTL, par->clk_wr_offset | CLOCK_STROBE, par);
+
+	/* Temporarily switch to accelerator mode */
+	crtc_gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par);
+	if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN))
+		aty_st_le32(CRTC_GEN_CNTL, crtc_gen_cntl | CRTC_EXT_DISP_EN, par);
+
+	/* Reset VCLK generator */
+	aty_st_pll_ct(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl, par);
+
+	/* Set post-divider */
+	tmp2 = par->clk_wr_offset << 1;
+	tmp = aty_ld_pll_ct(VCLK_POST_DIV, par);
+	tmp &= ~(0x03U << tmp2);
+	tmp |= ((pll->ct.vclk_post_div & 0x03U) << tmp2);
+	aty_st_pll_ct(VCLK_POST_DIV, tmp, par);
+
+	/* Set extended post-divider */
+	tmp = aty_ld_pll_ct(PLL_EXT_CNTL, par);
+	tmp &= ~(0x10U << par->clk_wr_offset);
+	tmp &= 0xF0U;
+	tmp |= pll->ct.pll_ext_cntl;
+	aty_st_pll_ct(PLL_EXT_CNTL, tmp, par);
+
+	/* Set feedback divider */
+	tmp = VCLK0_FB_DIV + par->clk_wr_offset;
+	aty_st_pll_ct(tmp, (pll->ct.vclk_fb_div & 0xFFU), par);
+
+	aty_st_pll_ct(PLL_GEN_CNTL, (pll->ct.pll_gen_cntl & (~(PLL_OVERRIDE | PLL_MCLK_RST))) | OSC_EN, par);
+
+	/* End VCLK generator reset */
+	aty_st_pll_ct(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl & ~(PLL_VCLK_RST), par);
+	mdelay(5);
+
+	aty_st_pll_ct(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, par);
+	aty_st_pll_ct(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl, par);
+	mdelay(1);
+
+	/* Restore mode register */
+	if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN))
+		aty_st_le32(CRTC_GEN_CNTL, crtc_gen_cntl, par);
+
+	if (M64_HAS(GTB_DSP)) {
+		u8 dll_cntl;
+
+		if (M64_HAS(XL_DLL))
+			dll_cntl = 0x80;
+		else if (par->ram_type >= SDRAM)
+			dll_cntl = 0xa6;
+		else
+			dll_cntl = 0xa0;
+		aty_st_pll_ct(DLL_CNTL, dll_cntl, par);
+		aty_st_pll_ct(VFC_CNTL, 0x1b, par);
+		aty_st_le32(DSP_CONFIG, pll->ct.dsp_config, par);
+		aty_st_le32(DSP_ON_OFF, pll->ct.dsp_on_off, par);
+
+		mdelay(10);
+		aty_st_pll_ct(DLL_CNTL, dll_cntl, par);
+		mdelay(10);
+		aty_st_pll_ct(DLL_CNTL, dll_cntl | 0x40, par);
+		mdelay(10);
+		aty_st_pll_ct(DLL_CNTL, dll_cntl & ~0x40, par);
+	}
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+	if (par->lcd_table != 0) {
+		/* restore LCD */
+		aty_st_lcd(LCD_GEN_CNTL, lcd_gen_cntrl, par);
+	}
+#endif
+}
+
+static void __init aty_get_pll_ct(const struct fb_info *info,
+				  union aty_pll *pll)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	u8 tmp, clock;
+
+	clock = aty_ld_8(CLOCK_CNTL, par) & 0x03U;
+	tmp = clock << 1;
+	pll->ct.vclk_post_div = (aty_ld_pll_ct(VCLK_POST_DIV, par) >> tmp) & 0x03U;
+
+	pll->ct.pll_ext_cntl = aty_ld_pll_ct(PLL_EXT_CNTL, par) & 0x0FU;
+	pll->ct.vclk_fb_div = aty_ld_pll_ct(VCLK0_FB_DIV + clock, par) & 0xFFU;
+	pll->ct.pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par);
+	pll->ct.mclk_fb_div = aty_ld_pll_ct(MCLK_FB_DIV, par);
+
+	pll->ct.pll_gen_cntl = aty_ld_pll_ct(PLL_GEN_CNTL, par);
+	pll->ct.pll_vclk_cntl = aty_ld_pll_ct(PLL_VCLK_CNTL, par);
+
+	if (M64_HAS(GTB_DSP)) {
+		pll->ct.dsp_config = aty_ld_le32(DSP_CONFIG, par);
+		pll->ct.dsp_on_off = aty_ld_le32(DSP_ON_OFF, par);
+	}
+}
+
+static int __init aty_init_pll_ct(const struct fb_info *info,
+				 union aty_pll *pll)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	u8 mpost_div, xpost_div, sclk_post_div_real, sclk_fb_div, spll_cntl2;
+	u32 q, i, memcntl, trp;
+	u32 dsp_config, dsp_on_off, vga_dsp_config, vga_dsp_on_off;
+#ifdef DEBUG
+	int pllmclk, pllsclk;
+#endif
+	pll->ct.pll_ext_cntl = aty_ld_pll_ct(PLL_EXT_CNTL, par);
+	pll->ct.xclk_post_div = pll->ct.pll_ext_cntl & 0x07;
+	pll->ct.xclk_ref_div = 1;
+	switch (pll->ct.xclk_post_div) {
+	case 0:  case 1:  case 2:  case 3:
+		break;
+
+	case 4:
+		pll->ct.xclk_ref_div = 3;
+		pll->ct.xclk_post_div = 0;
+		break;
+
+	default:
+		printk(KERN_CRIT "atyfb: Unsupported xclk source:  %d.\n", pll->ct.xclk_post_div);
+		return -EINVAL;
+	}
+	pll->ct.mclk_fb_mult = 2;
+	if(pll->ct.pll_ext_cntl & PLL_MFB_TIMES_4_2B) {
+		pll->ct.mclk_fb_mult = 4;
+		pll->ct.xclk_post_div -= 1;
+	}
+
+#ifdef DEBUG
+	printk("atyfb(%s): mclk_fb_mult=%d, xclk_post_div=%d\n",
+		__FUNCTION__, pll->ct.mclk_fb_mult, pll->ct.xclk_post_div);
+#endif
+
+	memcntl = aty_ld_le32(MEM_CNTL, par);
+	trp = (memcntl & 0x300) >> 8;
+
+	pll->ct.xclkpagefaultdelay = ((memcntl & 0xc00) >> 10) + ((memcntl & 0x1000) >> 12) + trp + 2;
+	pll->ct.xclkmaxrasdelay = ((memcntl & 0x70000) >> 16) + trp + 2;
+
+	if (M64_HAS(FIFO_32)) {
+		pll->ct.fifo_size = 32;
+	} else {
+		pll->ct.fifo_size = 24;
+		pll->ct.xclkpagefaultdelay += 2;
+		pll->ct.xclkmaxrasdelay += 3;
+	}
+
+	switch (par->ram_type) {
+	case DRAM:
+		if (info->fix.smem_len<=ONE_MB) {
+			pll->ct.dsp_loop_latency = 10;
+		} else {
+			pll->ct.dsp_loop_latency = 8;
+			pll->ct.xclkpagefaultdelay += 2;
+		}
+		break;
+	case EDO:
+	case PSEUDO_EDO:
+		if (info->fix.smem_len<=ONE_MB) {
+			pll->ct.dsp_loop_latency = 9;
+		} else {
+			pll->ct.dsp_loop_latency = 8;
+			pll->ct.xclkpagefaultdelay += 1;
+		}
+		break;
+	case SDRAM:
+		if (info->fix.smem_len<=ONE_MB) {
+			pll->ct.dsp_loop_latency = 11;
+		} else {
+			pll->ct.dsp_loop_latency = 10;
+			pll->ct.xclkpagefaultdelay += 1;
+		}
+		break;
+	case SGRAM:
+		pll->ct.dsp_loop_latency = 8;
+		pll->ct.xclkpagefaultdelay += 3;
+		break;
+	default:
+		pll->ct.dsp_loop_latency = 11;
+		pll->ct.xclkpagefaultdelay += 3;
+		break;
+	}
+
+	if (pll->ct.xclkmaxrasdelay <= pll->ct.xclkpagefaultdelay)
+		pll->ct.xclkmaxrasdelay = pll->ct.xclkpagefaultdelay + 1;
+
+	/* Allow BIOS to override */
+	dsp_config = aty_ld_le32(DSP_CONFIG, par);
+	dsp_on_off = aty_ld_le32(DSP_ON_OFF, par);
+	vga_dsp_config = aty_ld_le32(VGA_DSP_CONFIG, par);
+	vga_dsp_on_off = aty_ld_le32(VGA_DSP_ON_OFF, par);
+
+	if (dsp_config)
+		pll->ct.dsp_loop_latency = (dsp_config & DSP_LOOP_LATENCY) >> 16;
+#if 0
+	FIXME: is it relevant for us?
+	if ((!dsp_on_off && !M64_HAS(RESET_3D)) ||
+		((dsp_on_off == vga_dsp_on_off) &&
+		(!dsp_config || !((dsp_config ^ vga_dsp_config) & DSP_XCLKS_PER_QW)))) {
+		vga_dsp_on_off &= VGA_DSP_OFF;
+		vga_dsp_config &= VGA_DSP_XCLKS_PER_QW;
+		if (ATIDivide(vga_dsp_on_off, vga_dsp_config, 5, 1) > 24)
+			pll->ct.fifo_size = 32;
+		else
+			pll->ct.fifo_size = 24;
+	}
+#endif
+	/* Exit if the user does not want us to tamper with the clock
+	rates of her chip. */
+	if (par->mclk_per == 0) {
+		u8 mclk_fb_div, pll_ext_cntl;
+		pll->ct.pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par);
+		pll_ext_cntl = aty_ld_pll_ct(PLL_EXT_CNTL, par);
+		pll->ct.xclk_post_div_real = postdividers[pll_ext_cntl & 0x07];
+		mclk_fb_div = aty_ld_pll_ct(MCLK_FB_DIV, par);
+		if (pll_ext_cntl & PLL_MFB_TIMES_4_2B)
+			mclk_fb_div <<= 1;
+		pll->ct.mclk_fb_div = mclk_fb_div;
+		return 0;
+	}
+
+	pll->ct.pll_ref_div = par->pll_per * 2 * 255 / par->ref_clk_per;
+
+	/* FIXME: use the VTB/GTB /3 post divider if it's better suited */
+	q = par->ref_clk_per * pll->ct.pll_ref_div * 8 /
+		(pll->ct.mclk_fb_mult * par->xclk_per);
+
+	if (q < 16*8 || q > 255*8) {
+		printk(KERN_CRIT "atxfb: xclk out of range\n");
+		return -EINVAL;
+	} else {
+		xpost_div  = (q < 128*8);
+		xpost_div += (q <  64*8);
+		xpost_div += (q <  32*8);
+	}
+	pll->ct.xclk_post_div_real = postdividers[xpost_div];
+	pll->ct.mclk_fb_div = q * pll->ct.xclk_post_div_real / 8;
+
+#ifdef DEBUG
+	pllmclk = (1000000 * pll->ct.mclk_fb_mult * pll->ct.mclk_fb_div) /
+			(par->ref_clk_per * pll->ct.pll_ref_div);
+	printk("atyfb(%s): pllmclk=%d MHz, xclk=%d MHz\n",
+		__FUNCTION__, pllmclk, pllmclk / pll->ct.xclk_post_div_real);
+#endif
+
+	if (M64_HAS(SDRAM_MAGIC_PLL) && (par->ram_type >= SDRAM))
+		pll->ct.pll_gen_cntl = OSC_EN;
+	else
+		pll->ct.pll_gen_cntl = OSC_EN | DLL_PWDN /* | FORCE_DCLK_TRI_STATE */;
+
+	if (M64_HAS(MAGIC_POSTDIV))
+		pll->ct.pll_ext_cntl = 0;
+	else
+		pll->ct.pll_ext_cntl = xpost_div;
+
+	if (pll->ct.mclk_fb_mult == 4)
+		pll->ct.pll_ext_cntl |= PLL_MFB_TIMES_4_2B;
+
+	if (par->mclk_per == par->xclk_per) {
+		pll->ct.pll_gen_cntl |= (xpost_div << 4); /* mclk == xclk */
+	} else {
+		/*
+		* The chip clock is not equal to the memory clock.
+		* Therefore we will use sclk to clock the chip.
+		*/
+		pll->ct.pll_gen_cntl |= (6 << 4); /* mclk == sclk */
+
+		q = par->ref_clk_per * pll->ct.pll_ref_div * 4 / par->mclk_per;
+		if (q < 16*8 || q > 255*8) {
+			printk(KERN_CRIT "atyfb: mclk out of range\n");
+			return -EINVAL;
+		} else {
+			mpost_div  = (q < 128*8);
+			mpost_div += (q <  64*8);
+			mpost_div += (q <  32*8);
+		}
+		sclk_post_div_real = postdividers[mpost_div];
+		sclk_fb_div = q * sclk_post_div_real / 8;
+		spll_cntl2 = mpost_div << 4;
+#ifdef DEBUG
+		pllsclk = (1000000 * 2 * sclk_fb_div) /
+			(par->ref_clk_per * pll->ct.pll_ref_div);
+		printk("atyfb(%s): use sclk, pllsclk=%d MHz, sclk=mclk=%d MHz\n",
+			__FUNCTION__, pllsclk, pllsclk / sclk_post_div_real);
+#endif
+		/*
+		* This disables the sclk, crashes the computer as reported:
+		* aty_st_pll_ct(SPLL_CNTL2, 3, info);
+		*
+		* So it seems the sclk must be enabled before it is used;
+		* so PLL_GEN_CNTL must be programmed *after* the sclk.
+		*/
+		aty_st_pll_ct(SCLK_FB_DIV, sclk_fb_div, par);
+		aty_st_pll_ct(SPLL_CNTL2, spll_cntl2, par);
+		/*
+		 * The sclk has been started. However, I believe the first clock
+		 * ticks it generates are not very stable. Hope this primitive loop
+		 * helps for Rage Mobilities that sometimes crash when
+		 * we switch to sclk. (Daniel Mantione, 13-05-2003)
+		 */
+		for (i=0;i<=0x1ffff;i++);
+	}
+
+	aty_st_pll_ct(PLL_REF_DIV, pll->ct.pll_ref_div, par);
+	aty_st_pll_ct(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, par);
+	aty_st_pll_ct(MCLK_FB_DIV, pll->ct.mclk_fb_div, par);
+	aty_st_pll_ct(PLL_EXT_CNTL, pll->ct.pll_ext_cntl, par);
+	/* Disable the extra precision pixel clock controls since we do not use them. */
+	aty_st_pll_ct(EXT_VPLL_CNTL, aty_ld_pll_ct(EXT_VPLL_CNTL, par) &
+		~(EXT_VPLL_EN | EXT_VPLL_VGA_EN | EXT_VPLL_INSYNC), par);
+
+	return 0;
+}
+
+static int dummy(void)
+{
+	return 0;
+}
+
+const struct aty_dac_ops aty_dac_ct = {
+	.set_dac	= (void *) dummy,
+};
+
+const struct aty_pll_ops aty_pll_ct = {
+	.var_to_pll	= aty_var_to_pll_ct,
+	.pll_to_var	= aty_pll_to_var_ct,
+	.set_pll	= aty_set_pll_ct,
+	.get_pll	= aty_get_pll_ct,
+	.init_pll       = aty_init_pll_ct
+};
diff --git a/drivers/video/aty/mach64_cursor.c b/drivers/video/aty/mach64_cursor.c
new file mode 100644
index 0000000..ad8b749
--- /dev/null
+++ b/drivers/video/aty/mach64_cursor.c
@@ -0,0 +1,226 @@
+/*
+ *  ATI Mach64 CT/VT/GT/LT Cursor Support
+ */
+
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#ifdef __sparc__
+#include <asm/pbm.h>
+#include <asm/fbio.h>
+#endif
+
+#include <video/mach64.h>
+#include "atyfb.h"
+
+/*
+ * The hardware cursor definition requires 2 bits per pixel. The
+ * Cursor size reguardless of the visible cursor size is 64 pixels
+ * by 64 lines. The total memory required to define the cursor is
+ * 16 bytes / line for 64 lines or 1024 bytes of data. The data
+ * must be in a contigiuos format. The 2 bit cursor code values are
+ * as follows:
+ *
+ *	00 - pixel colour = CURSOR_CLR_0
+ *	01 - pixel colour = CURSOR_CLR_1
+ *	10 - pixel colour = transparent (current display pixel)
+ *	11 - pixel colour = 1's complement of current display pixel
+ *
+ *	Cursor Offset        64 pixels		 Actual Displayed Area
+ *            \_________________________/
+ *	      |			|	|	|
+ *	      |<--------------->|	|	|
+ *	      | CURS_HORZ_OFFSET|	|	|
+ *	      |			|_______|	|  64 Lines
+ *	      |			   ^	|	|
+ *	      |			   |	|	|
+ *	      |		CURS_VERT_OFFSET|	|
+ *	      |			   |	|	|
+ *	      |____________________|____|	|
+ *
+ *
+ * The Screen position of the top left corner of the displayed
+ * cursor is specificed by CURS_HORZ_VERT_POSN. Care must be taken
+ * when the cursor hot spot is not the top left corner and the
+ * physical cursor position becomes negative. It will be be displayed
+ * if either the horizontal or vertical cursor position is negative
+ *
+ * If x becomes negative the cursor manager must adjust the CURS_HORZ_OFFSET
+ * to a larger number and saturate CUR_HORZ_POSN to zero.
+ *
+ * if Y becomes negative, CUR_VERT_OFFSET must be adjusted to a larger number,
+ * CUR_OFFSET must be adjusted to a point to the appropraite line in the cursor
+ * definitation and CUR_VERT_POSN must be saturated to zero.
+ */
+
+    /*
+     *  Hardware Cursor support.
+     */
+static const u8 cursor_bits_lookup[16] = {
+	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
+	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
+};
+
+static const u8 cursor_mask_lookup[16] = {
+	0xaa, 0x2a, 0x8a, 0x0a, 0xa2, 0x22, 0x82, 0x02,
+	0xa8, 0x28, 0x88, 0x08, 0xa0, 0x20, 0x80, 0x00
+};
+
+static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	u16 xoff, yoff;
+	int x, y, h;
+
+#ifdef __sparc__
+	if (par->mmaped)
+		return -EPERM;
+#endif
+	if (par->asleep)
+		return -EPERM;
+
+	/* Hide cursor */
+	wait_for_fifo(1, par);
+	aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par) & ~HWCURSOR_ENABLE, par);
+
+	/* set position */
+	if (cursor->set & FB_CUR_SETPOS) {
+		x = cursor->image.dx - cursor->hot.x - info->var.xoffset;
+		if (x < 0) {
+			xoff = -x;
+			x = 0;
+		} else {
+			xoff = 0;
+		}
+
+		y = cursor->image.dy - cursor->hot.y - info->var.yoffset;
+		if (y < 0) {
+			yoff = -y;
+			y = 0;
+		} else {
+			yoff = 0;
+		}
+
+		h = cursor->image.height;
+
+		/*
+		 * In doublescan mode, the cursor location
+		 * and heigh also needs to be doubled.
+		 */
+                if (par->crtc.gen_cntl & CRTC_DBL_SCAN_EN) {
+			y<<=1;
+			h<<=1;
+		}
+		wait_for_fifo(4, par);
+		aty_st_le32(CUR_OFFSET, (info->fix.smem_len >> 3) + (yoff << 1), par);
+		aty_st_le32(CUR_HORZ_VERT_OFF,
+			    ((u32) (64 - h + yoff) << 16) | xoff, par);
+		aty_st_le32(CUR_HORZ_VERT_POSN, ((u32) y << 16) | x, par);
+	}
+
+	/* Set color map */
+	if (cursor->set & FB_CUR_SETCMAP) {
+		u32 fg_idx, bg_idx, fg, bg;
+
+		fg_idx = cursor->image.fg_color;
+		bg_idx = cursor->image.bg_color;
+
+		fg = (info->cmap.red[fg_idx] << 24) |
+		     (info->cmap.green[fg_idx] << 16) |
+		     (info->cmap.blue[fg_idx] << 8) | 15;
+
+		bg = (info->cmap.red[bg_idx] << 24) |
+		     (info->cmap.green[bg_idx] << 16) |
+		     (info->cmap.blue[bg_idx] << 8);
+
+		wait_for_fifo(2, par);
+		aty_st_le32(CUR_CLR0, bg, par);
+		aty_st_le32(CUR_CLR1, fg, par);
+	}
+
+	if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
+	    u8 *src = (u8 *)cursor->image.data;
+	    u8 *msk = (u8 *)cursor->mask;
+	    u8 __iomem *dst = (u8 __iomem *)info->sprite.addr;
+	    unsigned int width = (cursor->image.width + 7) >> 3;
+	    unsigned int height = cursor->image.height;
+	    unsigned int align = info->sprite.scan_align;
+
+	    unsigned int i, j, offset;
+	    u8 m, b;
+
+	    // Clear cursor image with 1010101010...
+	    fb_memset(dst, 0xaa, 1024);
+
+	    offset = align - width*2;
+
+	    for (i = 0; i < height; i++) {
+		for (j = 0; j < width; j++) {
+			b = *src++;
+			m = *msk++;
+			switch (cursor->rop) {
+			case ROP_XOR:
+			    // Upper 4 bits of mask data
+			    fb_writeb(cursor_mask_lookup[m >> 4 ] |
+				cursor_bits_lookup[(b ^ m) >> 4], dst++);
+			    // Lower 4 bits of mask
+			    fb_writeb(cursor_mask_lookup[m & 0x0f ] |
+				cursor_bits_lookup[(b ^ m) & 0x0f], dst++);
+			    break;
+			case ROP_COPY:
+			    // Upper 4 bits of mask data
+			    fb_writeb(cursor_mask_lookup[m >> 4 ] |
+				cursor_bits_lookup[(b & m) >> 4], dst++);
+			    // Lower 4 bits of mask
+			    fb_writeb(cursor_mask_lookup[m & 0x0f ] |
+				cursor_bits_lookup[(b & m) & 0x0f], dst++);
+			    break;
+			}
+		}
+		dst += offset;
+	    }
+	}
+
+	if (cursor->enable) {
+		wait_for_fifo(1, par);
+		aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par)
+			    | HWCURSOR_ENABLE, par);
+	}
+	return 0;
+}
+
+int __init aty_init_cursor(struct fb_info *info)
+{
+	unsigned long addr;
+
+	info->fix.smem_len -= PAGE_SIZE;
+
+#ifdef __sparc__
+	addr = (unsigned long) info->screen_base - 0x800000 + info->fix.smem_len;
+	info->sprite.addr = (u8 *) addr;
+#else
+#ifdef __BIG_ENDIAN
+	addr = info->fix.smem_start - 0x800000 + info->fix.smem_len;
+	info->sprite.addr = (u8 *) ioremap(addr, 1024);
+#else
+	addr = (unsigned long) info->screen_base + info->fix.smem_len;
+	info->sprite.addr = (u8 *) addr;
+#endif
+#endif
+	if (!info->sprite.addr)
+		return -ENXIO;
+	info->sprite.size = PAGE_SIZE;
+	info->sprite.scan_align = 16;	/* Scratch pad 64 bytes wide */
+	info->sprite.buf_align = 16; 	/* and 64 lines tall. */
+	info->sprite.flags = FB_PIXMAP_IO;
+
+	info->fbops->fb_cursor = atyfb_cursor;
+
+	return 0;
+}
+
diff --git a/drivers/video/aty/mach64_gx.c b/drivers/video/aty/mach64_gx.c
new file mode 100644
index 0000000..01fdff7
--- /dev/null
+++ b/drivers/video/aty/mach64_gx.c
@@ -0,0 +1,912 @@
+
+/*
+ *  ATI Mach64 GX Support
+ */
+
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/sched.h>
+
+#include <asm/io.h>
+
+#include <video/mach64.h>
+#include "atyfb.h"
+
+/* Definitions for the ICS 2595 == ATI 18818_1 Clockchip */
+
+#define REF_FREQ_2595       1432	/*  14.33 MHz  (exact   14.31818) */
+#define REF_DIV_2595          46	/* really 43 on ICS 2595 !!!  */
+				  /* ohne Prescaler */
+#define MAX_FREQ_2595      15938	/* 159.38 MHz  (really 170.486) */
+#define MIN_FREQ_2595       8000	/*  80.00 MHz  (        85.565) */
+				  /* mit Prescaler 2, 4, 8 */
+#define ABS_MIN_FREQ_2595   1000	/*  10.00 MHz  (really  10.697) */
+#define N_ADJ_2595           257
+
+#define STOP_BITS_2595     0x1800
+
+
+#define MIN_N_408		2
+
+#define MIN_N_1703		6
+
+#define MIN_M		2
+#define MAX_M		30
+#define MIN_N		35
+#define MAX_N		255-8
+
+
+    /*
+     *  Support Functions
+     */
+
+static void aty_dac_waste4(const struct atyfb_par *par)
+{
+	(void) aty_ld_8(DAC_REGS, par);
+
+	(void) aty_ld_8(DAC_REGS + 2, par);
+	(void) aty_ld_8(DAC_REGS + 2, par);
+	(void) aty_ld_8(DAC_REGS + 2, par);
+	(void) aty_ld_8(DAC_REGS + 2, par);
+}
+
+static void aty_StrobeClock(const struct atyfb_par *par)
+{
+	u8 tmp;
+
+	udelay(26);
+
+	tmp = aty_ld_8(CLOCK_CNTL, par);
+	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, tmp | CLOCK_STROBE, par);
+	return;
+}
+
+
+    /*
+     *  IBM RGB514 DAC and Clock Chip
+     */
+
+static void aty_st_514(int offset, u8 val, const struct atyfb_par *par)
+{
+	aty_st_8(DAC_CNTL, 1, par);
+	/* right addr byte */
+	aty_st_8(DAC_W_INDEX, offset & 0xff, par);
+	/* left addr byte */
+	aty_st_8(DAC_DATA, (offset >> 8) & 0xff, par);
+	aty_st_8(DAC_MASK, val, par);
+	aty_st_8(DAC_CNTL, 0, par);
+}
+
+static int aty_set_dac_514(const struct fb_info *info,
+			   const union aty_pll *pll, u32 bpp, u32 accel)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	static struct {
+		u8 pixel_dly;
+		u8 misc2_cntl;
+		u8 pixel_rep;
+		u8 pixel_cntl_index;
+		u8 pixel_cntl_v1;
+	} tab[3] = {
+		{
+		0, 0x41, 0x03, 0x71, 0x45},	/* 8 bpp */
+		{
+		0, 0x45, 0x04, 0x0c, 0x01},	/* 555 */
+		{
+		0, 0x45, 0x06, 0x0e, 0x00},	/* XRGB */
+	};
+	int i;
+
+	switch (bpp) {
+	case 8:
+	default:
+		i = 0;
+		break;
+	case 16:
+		i = 1;
+		break;
+	case 32:
+		i = 2;
+		break;
+	}
+	aty_st_514(0x90, 0x00, par);	/* VRAM Mask Low */
+	aty_st_514(0x04, tab[i].pixel_dly, par);	/* Horizontal Sync Control */
+	aty_st_514(0x05, 0x00, par);	/* Power Management */
+	aty_st_514(0x02, 0x01, par);	/* Misc Clock Control */
+	aty_st_514(0x71, tab[i].misc2_cntl, par);	/* Misc Control 2 */
+	aty_st_514(0x0a, tab[i].pixel_rep, par);	/* Pixel Format */
+	aty_st_514(tab[i].pixel_cntl_index, tab[i].pixel_cntl_v1, par);
+	/* Misc Control 2 / 16 BPP Control / 32 BPP Control */
+	return 0;
+}
+
+static int aty_var_to_pll_514(const struct fb_info *info, u32 vclk_per,
+			      u32 bpp, union aty_pll *pll)
+{
+	/*
+	 *  FIXME: use real calculations instead of using fixed values from the old
+	 *         driver
+	 */
+	static struct {
+		u32 limit;	/* pixlock rounding limit (arbitrary) */
+		u8 m;		/* (df<<6) | vco_div_count */
+		u8 n;		/* ref_div_count */
+	} RGB514_clocks[7] = {
+		{
+		8000, (3 << 6) | 20, 9},	/*  7395 ps / 135.2273 MHz */
+		{
+		10000, (1 << 6) | 19, 3},	/*  9977 ps / 100.2273 MHz */
+		{
+		13000, (1 << 6) | 2, 3},	/* 12509 ps /  79.9432 MHz */
+		{
+		14000, (2 << 6) | 8, 7},	/* 13394 ps /  74.6591 MHz */
+		{
+		16000, (1 << 6) | 44, 6},	/* 15378 ps /  65.0284 MHz */
+		{
+		25000, (1 << 6) | 15, 5},	/* 17460 ps /  57.2727 MHz */
+		{
+		50000, (0 << 6) | 53, 7},	/* 33145 ps /  30.1705 MHz */
+	};
+	int i;
+
+	for (i = 0; i < sizeof(RGB514_clocks) / sizeof(*RGB514_clocks);
+	     i++)
+		if (vclk_per <= RGB514_clocks[i].limit) {
+			pll->ibm514.m = RGB514_clocks[i].m;
+			pll->ibm514.n = RGB514_clocks[i].n;
+			return 0;
+		}
+	return -EINVAL;
+}
+
+static u32 aty_pll_514_to_var(const struct fb_info *info,
+			      const union aty_pll *pll)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	u8 df, vco_div_count, ref_div_count;
+
+	df = pll->ibm514.m >> 6;
+	vco_div_count = pll->ibm514.m & 0x3f;
+	ref_div_count = pll->ibm514.n;
+
+	return ((par->ref_clk_per * ref_div_count) << (3 - df))/
+	    		(vco_div_count + 65);
+}
+
+static void aty_set_pll_514(const struct fb_info *info,
+			    const union aty_pll *pll)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+
+	aty_st_514(0x06, 0x02, par);	/* DAC Operation */
+	aty_st_514(0x10, 0x01, par);	/* PLL Control 1 */
+	aty_st_514(0x70, 0x01, par);	/* Misc Control 1 */
+	aty_st_514(0x8f, 0x1f, par);	/* PLL Ref. Divider Input */
+	aty_st_514(0x03, 0x00, par);	/* Sync Control */
+	aty_st_514(0x05, 0x00, par);	/* Power Management */
+	aty_st_514(0x20, pll->ibm514.m, par);	/* F0 / M0 */
+	aty_st_514(0x21, pll->ibm514.n, par);	/* F1 / N0 */
+}
+
+const struct aty_dac_ops aty_dac_ibm514 = {
+	.set_dac	= aty_set_dac_514,
+};
+
+const struct aty_pll_ops aty_pll_ibm514 = {
+	.var_to_pll	= aty_var_to_pll_514,
+	.pll_to_var	= aty_pll_514_to_var,
+	.set_pll	= aty_set_pll_514,
+};
+
+
+    /*
+     *  ATI 68860-B DAC
+     */
+
+static int aty_set_dac_ATI68860_B(const struct fb_info *info,
+				  const union aty_pll *pll, u32 bpp,
+				  u32 accel)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	u32 gModeReg, devSetupRegA, temp, mask;
+
+	gModeReg = 0;
+	devSetupRegA = 0;
+
+	switch (bpp) {
+	case 8:
+		gModeReg = 0x83;
+		devSetupRegA =
+		    0x60 | 0x00 /*(info->mach64DAC8Bit ? 0x00 : 0x01) */ ;
+		break;
+	case 15:
+		gModeReg = 0xA0;
+		devSetupRegA = 0x60;
+		break;
+	case 16:
+		gModeReg = 0xA1;
+		devSetupRegA = 0x60;
+		break;
+	case 24:
+		gModeReg = 0xC0;
+		devSetupRegA = 0x60;
+		break;
+	case 32:
+		gModeReg = 0xE3;
+		devSetupRegA = 0x60;
+		break;
+	}
+
+	if (!accel) {
+		gModeReg = 0x80;
+		devSetupRegA = 0x61;
+	}
+
+	temp = aty_ld_8(DAC_CNTL, par);
+	aty_st_8(DAC_CNTL, (temp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3,
+		 par);
+
+	aty_st_8(DAC_REGS + 2, 0x1D, par);
+	aty_st_8(DAC_REGS + 3, gModeReg, par);
+	aty_st_8(DAC_REGS, 0x02, par);
+
+	temp = aty_ld_8(DAC_CNTL, par);
+	aty_st_8(DAC_CNTL, temp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, par);
+
+	if (info->fix.smem_len < ONE_MB)
+		mask = 0x04;
+	else if (info->fix.smem_len == ONE_MB)
+		mask = 0x08;
+	else
+		mask = 0x0C;
+
+	/* The following assumes that the BIOS has correctly set R7 of the
+	 * Device Setup Register A at boot time.
+	 */
+#define A860_DELAY_L	0x80
+
+	temp = aty_ld_8(DAC_REGS, par);
+	aty_st_8(DAC_REGS, (devSetupRegA | mask) | (temp & A860_DELAY_L),
+		 par);
+	temp = aty_ld_8(DAC_CNTL, par);
+	aty_st_8(DAC_CNTL, (temp & ~(DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3)),
+		 par);
+
+	aty_st_le32(BUS_CNTL, 0x890e20f1, par);
+	aty_st_le32(DAC_CNTL, 0x47052100, par);
+	return 0;
+}
+
+const struct aty_dac_ops aty_dac_ati68860b = {
+	.set_dac	= aty_set_dac_ATI68860_B,
+};
+
+
+    /*
+     *  AT&T 21C498 DAC
+     */
+
+static int aty_set_dac_ATT21C498(const struct fb_info *info,
+				 const union aty_pll *pll, u32 bpp,
+				 u32 accel)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	u32 dotClock;
+	int muxmode = 0;
+	int DACMask = 0;
+
+	dotClock = 100000000 / pll->ics2595.period_in_ps;
+
+	switch (bpp) {
+	case 8:
+		if (dotClock > 8000) {
+			DACMask = 0x24;
+			muxmode = 1;
+		} else
+			DACMask = 0x04;
+		break;
+	case 15:
+		DACMask = 0x16;
+		break;
+	case 16:
+		DACMask = 0x36;
+		break;
+	case 24:
+		DACMask = 0xE6;
+		break;
+	case 32:
+		DACMask = 0xE6;
+		break;
+	}
+
+	if (1 /* info->mach64DAC8Bit */ )
+		DACMask |= 0x02;
+
+	aty_dac_waste4(par);
+	aty_st_8(DAC_REGS + 2, DACMask, par);
+
+	aty_st_le32(BUS_CNTL, 0x890e20f1, par);
+	aty_st_le32(DAC_CNTL, 0x00072000, par);
+	return muxmode;
+}
+
+const struct aty_dac_ops aty_dac_att21c498 = {
+	.set_dac	= aty_set_dac_ATT21C498,
+};
+
+
+    /*
+     *  ATI 18818 / ICS 2595 Clock Chip
+     */
+
+static int aty_var_to_pll_18818(const struct fb_info *info, u32 vclk_per,
+				u32 bpp, union aty_pll *pll)
+{
+	u32 MHz100;		/* in 0.01 MHz */
+	u32 program_bits;
+	u32 post_divider;
+
+	/* Calculate the programming word */
+	MHz100 = 100000000 / vclk_per;
+
+	program_bits = -1;
+	post_divider = 1;
+
+	if (MHz100 > MAX_FREQ_2595) {
+		MHz100 = MAX_FREQ_2595;
+		return -EINVAL;
+	} else if (MHz100 < ABS_MIN_FREQ_2595) {
+		program_bits = 0;	/* MHz100 = 257 */
+		return -EINVAL;
+	} else {
+		while (MHz100 < MIN_FREQ_2595) {
+			MHz100 *= 2;
+			post_divider *= 2;
+		}
+	}
+	MHz100 *= 1000;
+	MHz100 = (REF_DIV_2595 * MHz100) / REF_FREQ_2595;
+ 
+	MHz100 += 500;		/* + 0.5 round */
+	MHz100 /= 1000;
+
+	if (program_bits == -1) {
+		program_bits = MHz100 - N_ADJ_2595;
+		switch (post_divider) {
+		case 1:
+			program_bits |= 0x0600;
+			break;
+		case 2:
+			program_bits |= 0x0400;
+			break;
+		case 4:
+			program_bits |= 0x0200;
+			break;
+		case 8:
+		default:
+			break;
+		}
+	}
+
+	program_bits |= STOP_BITS_2595;
+
+	pll->ics2595.program_bits = program_bits;
+	pll->ics2595.locationAddr = 0;
+	pll->ics2595.post_divider = post_divider;
+	pll->ics2595.period_in_ps = vclk_per;
+
+	return 0;
+}
+
+static u32 aty_pll_18818_to_var(const struct fb_info *info,
+				const union aty_pll *pll)
+{
+	return (pll->ics2595.period_in_ps);	/* default for now */
+}
+
+static void aty_ICS2595_put1bit(u8 data, const struct atyfb_par *par)
+{
+	u8 tmp;
+
+	data &= 0x01;
+	tmp = aty_ld_8(CLOCK_CNTL, par);
+	aty_st_8(CLOCK_CNTL + par->clk_wr_offset,
+		 (tmp & ~0x04) | (data << 2), par);
+
+	tmp = aty_ld_8(CLOCK_CNTL, par);
+	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, (tmp & ~0x08) | (0 << 3),
+		 par);
+
+	aty_StrobeClock(par);
+
+	tmp = aty_ld_8(CLOCK_CNTL, par);
+	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, (tmp & ~0x08) | (1 << 3),
+		 par);
+
+	aty_StrobeClock(par);
+	return;
+}
+
+static void aty_set_pll18818(const struct fb_info *info,
+			     const union aty_pll *pll)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	u32 program_bits;
+	u32 locationAddr;
+
+	u32 i;
+
+	u8 old_clock_cntl;
+	u8 old_crtc_ext_disp;
+
+	old_clock_cntl = aty_ld_8(CLOCK_CNTL, par);
+	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, 0, par);
+
+	old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par);
+	aty_st_8(CRTC_GEN_CNTL + 3,
+		 old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par);
+
+	mdelay(15);		/* delay for 50 (15) ms */
+
+	program_bits = pll->ics2595.program_bits;
+	locationAddr = pll->ics2595.locationAddr;
+
+	/* Program the clock chip */
+	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, 0, par);	/* Strobe = 0 */
+	aty_StrobeClock(par);
+	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, 1, par);	/* Strobe = 0 */
+	aty_StrobeClock(par);
+
+	aty_ICS2595_put1bit(1, par);	/* Send start bits */
+	aty_ICS2595_put1bit(0, par);	/* Start bit */
+	aty_ICS2595_put1bit(0, par);	/* Read / ~Write */
+
+	for (i = 0; i < 5; i++) {	/* Location 0..4 */
+		aty_ICS2595_put1bit(locationAddr & 1, par);
+		locationAddr >>= 1;
+	}
+
+	for (i = 0; i < 8 + 1 + 2 + 2; i++) {
+		aty_ICS2595_put1bit(program_bits & 1, par);
+		program_bits >>= 1;
+	}
+
+	mdelay(1);		/* delay for 1 ms */
+
+	(void) aty_ld_8(DAC_REGS, par);	/* Clear DAC Counter */
+	aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par);
+	aty_st_8(CLOCK_CNTL + par->clk_wr_offset,
+		 old_clock_cntl | CLOCK_STROBE, par);
+
+	mdelay(50);		/* delay for 50 (15) ms */
+	aty_st_8(CLOCK_CNTL + par->clk_wr_offset,
+		 ((pll->ics2595.locationAddr & 0x0F) | CLOCK_STROBE), par);
+	return;
+}
+
+const struct aty_pll_ops aty_pll_ati18818_1 = {
+	.var_to_pll	= aty_var_to_pll_18818,
+	.pll_to_var	= aty_pll_18818_to_var,
+	.set_pll	= aty_set_pll18818,
+};
+
+
+    /*
+     *  STG 1703 Clock Chip
+     */
+
+static int aty_var_to_pll_1703(const struct fb_info *info, u32 vclk_per,
+			       u32 bpp, union aty_pll *pll)
+{
+	u32 mhz100;		/* in 0.01 MHz */
+	u32 program_bits;
+	/* u32 post_divider; */
+	u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;
+	u32 temp, tempB;
+	u16 remainder, preRemainder;
+	short divider = 0, tempA;
+
+	/* Calculate the programming word */
+	mhz100 = 100000000 / vclk_per;
+	mach64MinFreq = MIN_FREQ_2595;
+	mach64MaxFreq = MAX_FREQ_2595;
+	mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
+
+	/* Calculate program word */
+	if (mhz100 == 0)
+		program_bits = 0xE0;
+	else {
+		if (mhz100 < mach64MinFreq)
+			mhz100 = mach64MinFreq;
+		if (mhz100 > mach64MaxFreq)
+			mhz100 = mach64MaxFreq;
+
+		divider = 0;
+		while (mhz100 < (mach64MinFreq << 3)) {
+			mhz100 <<= 1;
+			divider += 0x20;
+		}
+
+		temp = (unsigned int) (mhz100);
+		temp = (unsigned int) (temp * (MIN_N_1703 + 2));
+		temp -= (short) (mach64RefFreq << 1);
+
+		tempA = MIN_N_1703;
+		preRemainder = 0xffff;
+
+		do {
+			tempB = temp;
+			remainder = tempB % mach64RefFreq;
+			tempB = tempB / mach64RefFreq;
+
+			if ((tempB & 0xffff) <= 127
+			    && (remainder <= preRemainder)) {
+				preRemainder = remainder;
+				divider &= ~0x1f;
+				divider |= tempA;
+				divider =
+				    (divider & 0x00ff) +
+				    ((tempB & 0xff) << 8);
+			}
+
+			temp += mhz100;
+			tempA++;
+		} while (tempA <= (MIN_N_1703 << 1));
+
+		program_bits = divider;
+	}
+
+	pll->ics2595.program_bits = program_bits;
+	pll->ics2595.locationAddr = 0;
+	pll->ics2595.post_divider = divider;	/* fuer nix */
+	pll->ics2595.period_in_ps = vclk_per;
+
+	return 0;
+}
+
+static u32 aty_pll_1703_to_var(const struct fb_info *info,
+			       const union aty_pll *pll)
+{
+	return (pll->ics2595.period_in_ps);	/* default for now */
+}
+
+static void aty_set_pll_1703(const struct fb_info *info,
+			     const union aty_pll *pll)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	u32 program_bits;
+	u32 locationAddr;
+
+	char old_crtc_ext_disp;
+
+	old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par);
+	aty_st_8(CRTC_GEN_CNTL + 3,
+		 old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par);
+
+	program_bits = pll->ics2595.program_bits;
+	locationAddr = pll->ics2595.locationAddr;
+
+	/* Program clock */
+	aty_dac_waste4(par);
+
+	(void) aty_ld_8(DAC_REGS + 2, par);
+	aty_st_8(DAC_REGS + 2, (locationAddr << 1) + 0x20, par);
+	aty_st_8(DAC_REGS + 2, 0, par);
+	aty_st_8(DAC_REGS + 2, (program_bits & 0xFF00) >> 8, par);
+	aty_st_8(DAC_REGS + 2, (program_bits & 0xFF), par);
+
+	(void) aty_ld_8(DAC_REGS, par);	/* Clear DAC Counter */
+	aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par);
+	return;
+}
+
+const struct aty_pll_ops aty_pll_stg1703 = {
+	.var_to_pll	= aty_var_to_pll_1703,
+	.pll_to_var	= aty_pll_1703_to_var,
+	.set_pll	= aty_set_pll_1703,
+};
+
+
+    /*
+     *  Chrontel 8398 Clock Chip
+     */
+
+static int aty_var_to_pll_8398(const struct fb_info *info, u32 vclk_per,
+			       u32 bpp, union aty_pll *pll)
+{
+	u32 tempA, tempB, fOut, longMHz100, diff, preDiff;
+
+	u32 mhz100;		/* in 0.01 MHz */
+	u32 program_bits;
+	/* u32 post_divider; */
+	u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;
+	u16 m, n, k = 0, save_m, save_n, twoToKth;
+
+	/* Calculate the programming word */
+	mhz100 = 100000000 / vclk_per;
+	mach64MinFreq = MIN_FREQ_2595;
+	mach64MaxFreq = MAX_FREQ_2595;
+	mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
+
+	save_m = 0;
+	save_n = 0;
+
+	/* Calculate program word */
+	if (mhz100 == 0)
+		program_bits = 0xE0;
+	else {
+		if (mhz100 < mach64MinFreq)
+			mhz100 = mach64MinFreq;
+		if (mhz100 > mach64MaxFreq)
+			mhz100 = mach64MaxFreq;
+
+		longMHz100 = mhz100 * 256 / 100;	/* 8 bit scale this */
+
+		while (mhz100 < (mach64MinFreq << 3)) {
+			mhz100 <<= 1;
+			k++;
+		}
+
+		twoToKth = 1 << k;
+		diff = 0;
+		preDiff = 0xFFFFFFFF;
+
+		for (m = MIN_M; m <= MAX_M; m++) {
+			for (n = MIN_N; n <= MAX_N; n++) {
+				tempA = 938356;		/* 14.31818 * 65536 */
+				tempA *= (n + 8);	/* 43..256 */
+				tempB = twoToKth * 256;
+				tempB *= (m + 2);	/* 4..32 */
+				fOut = tempA / tempB;	/* 8 bit scale */
+
+				if (longMHz100 > fOut)
+					diff = longMHz100 - fOut;
+				else
+					diff = fOut - longMHz100;
+
+				if (diff < preDiff) {
+					save_m = m;
+					save_n = n;
+					preDiff = diff;
+				}
+			}
+		}
+
+		program_bits = (k << 6) + (save_m) + (save_n << 8);
+	}
+
+	pll->ics2595.program_bits = program_bits;
+	pll->ics2595.locationAddr = 0;
+	pll->ics2595.post_divider = 0;
+	pll->ics2595.period_in_ps = vclk_per;
+
+	return 0;
+}
+
+static u32 aty_pll_8398_to_var(const struct fb_info *info,
+			       const union aty_pll *pll)
+{
+	return (pll->ics2595.period_in_ps);	/* default for now */
+}
+
+static void aty_set_pll_8398(const struct fb_info *info,
+			     const union aty_pll *pll)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	u32 program_bits;
+	u32 locationAddr;
+
+	char old_crtc_ext_disp;
+	char tmp;
+
+	old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par);
+	aty_st_8(CRTC_GEN_CNTL + 3,
+		 old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par);
+
+	program_bits = pll->ics2595.program_bits;
+	locationAddr = pll->ics2595.locationAddr;
+
+	/* Program clock */
+	tmp = aty_ld_8(DAC_CNTL, par);
+	aty_st_8(DAC_CNTL, tmp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, par);
+
+	aty_st_8(DAC_REGS, locationAddr, par);
+	aty_st_8(DAC_REGS + 1, (program_bits & 0xff00) >> 8, par);
+	aty_st_8(DAC_REGS + 1, (program_bits & 0xff), par);
+
+	tmp = aty_ld_8(DAC_CNTL, par);
+	aty_st_8(DAC_CNTL, (tmp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3,
+		 par);
+
+	(void) aty_ld_8(DAC_REGS, par);	/* Clear DAC Counter */
+	aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par);
+
+	return;
+}
+
+const struct aty_pll_ops aty_pll_ch8398 = {
+	.var_to_pll	= aty_var_to_pll_8398,
+	.pll_to_var	= aty_pll_8398_to_var,
+	.set_pll	= aty_set_pll_8398,
+};
+
+
+    /*
+     *  AT&T 20C408 Clock Chip
+     */
+
+static int aty_var_to_pll_408(const struct fb_info *info, u32 vclk_per,
+			      u32 bpp, union aty_pll *pll)
+{
+	u32 mhz100;		/* in 0.01 MHz */
+	u32 program_bits;
+	/* u32 post_divider; */
+	u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;
+	u32 temp, tempB;
+	u16 remainder, preRemainder;
+	short divider = 0, tempA;
+
+	/* Calculate the programming word */
+	mhz100 = 100000000 / vclk_per;
+	mach64MinFreq = MIN_FREQ_2595;
+	mach64MaxFreq = MAX_FREQ_2595;
+	mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
+
+	/* Calculate program word */
+	if (mhz100 == 0)
+		program_bits = 0xFF;
+	else {
+		if (mhz100 < mach64MinFreq)
+			mhz100 = mach64MinFreq;
+		if (mhz100 > mach64MaxFreq)
+			mhz100 = mach64MaxFreq;
+
+		while (mhz100 < (mach64MinFreq << 3)) {
+			mhz100 <<= 1;
+			divider += 0x40;
+		}
+
+		temp = (unsigned int) mhz100;
+		temp = (unsigned int) (temp * (MIN_N_408 + 2));
+		temp -= ((short) (mach64RefFreq << 1));
+
+		tempA = MIN_N_408;
+		preRemainder = 0xFFFF;
+
+		do {
+			tempB = temp;
+			remainder = tempB % mach64RefFreq;
+			tempB = tempB / mach64RefFreq;
+			if (((tempB & 0xFFFF) <= 255)
+			    && (remainder <= preRemainder)) {
+				preRemainder = remainder;
+				divider &= ~0x3f;
+				divider |= tempA;
+				divider =
+				    (divider & 0x00FF) +
+				    ((tempB & 0xFF) << 8);
+			}
+			temp += mhz100;
+			tempA++;
+		} while (tempA <= 32);
+
+		program_bits = divider;
+	}
+
+	pll->ics2595.program_bits = program_bits;
+	pll->ics2595.locationAddr = 0;
+	pll->ics2595.post_divider = divider;	/* fuer nix */
+	pll->ics2595.period_in_ps = vclk_per;
+
+	return 0;
+}
+
+static u32 aty_pll_408_to_var(const struct fb_info *info,
+			      const union aty_pll *pll)
+{
+	return (pll->ics2595.period_in_ps);	/* default for now */
+}
+
+static void aty_set_pll_408(const struct fb_info *info,
+			    const union aty_pll *pll)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	u32 program_bits;
+	u32 locationAddr;
+
+	u8 tmpA, tmpB, tmpC;
+	char old_crtc_ext_disp;
+
+	old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par);
+	aty_st_8(CRTC_GEN_CNTL + 3,
+		 old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par);
+
+	program_bits = pll->ics2595.program_bits;
+	locationAddr = pll->ics2595.locationAddr;
+
+	/* Program clock */
+	aty_dac_waste4(par);
+	tmpB = aty_ld_8(DAC_REGS + 2, par) | 1;
+	aty_dac_waste4(par);
+	aty_st_8(DAC_REGS + 2, tmpB, par);
+
+	tmpA = tmpB;
+	tmpC = tmpA;
+	tmpA |= 8;
+	tmpB = 1;
+
+	aty_st_8(DAC_REGS, tmpB, par);
+	aty_st_8(DAC_REGS + 2, tmpA, par);
+
+	udelay(400);		/* delay for 400 us */
+
+	locationAddr = (locationAddr << 2) + 0x40;
+	tmpB = locationAddr;
+	tmpA = program_bits >> 8;
+
+	aty_st_8(DAC_REGS, tmpB, par);
+	aty_st_8(DAC_REGS + 2, tmpA, par);
+
+	tmpB = locationAddr + 1;
+	tmpA = (u8) program_bits;
+
+	aty_st_8(DAC_REGS, tmpB, par);
+	aty_st_8(DAC_REGS + 2, tmpA, par);
+
+	tmpB = locationAddr + 2;
+	tmpA = 0x77;
+
+	aty_st_8(DAC_REGS, tmpB, par);
+	aty_st_8(DAC_REGS + 2, tmpA, par);
+
+	udelay(400);		/* delay for 400 us */
+	tmpA = tmpC & (~(1 | 8));
+	tmpB = 1;
+
+	aty_st_8(DAC_REGS, tmpB, par);
+	aty_st_8(DAC_REGS + 2, tmpA, par);
+
+	(void) aty_ld_8(DAC_REGS, par);	/* Clear DAC Counter */
+	aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par);
+	return;
+}
+
+const struct aty_pll_ops aty_pll_att20c408 = {
+	.var_to_pll	= aty_var_to_pll_408,
+	.pll_to_var	= aty_pll_408_to_var,
+	.set_pll	= aty_set_pll_408,
+};
+
+
+    /*
+     *  Unsupported DAC and Clock Chip
+     */
+
+static int aty_set_dac_unsupported(const struct fb_info *info,
+				   const union aty_pll *pll, u32 bpp,
+				   u32 accel)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+
+	aty_st_le32(BUS_CNTL, 0x890e20f1, par);
+	aty_st_le32(DAC_CNTL, 0x47052100, par);
+	/* new in 2.2.3p1 from Geert. ???????? */
+	aty_st_le32(BUS_CNTL, 0x590e10ff, par);
+	aty_st_le32(DAC_CNTL, 0x47012100, par);
+	return 0;
+}
+
+static int dummy(void)
+{
+	return 0;
+}
+
+const struct aty_dac_ops aty_dac_unsupported = {
+	.set_dac	= aty_set_dac_unsupported,
+};
+
+const struct aty_pll_ops aty_pll_unsupported = {
+	.var_to_pll	= (void *) dummy,
+	.pll_to_var	= (void *) dummy,
+	.set_pll	= (void *) dummy,
+};
diff --git a/drivers/video/aty/radeon_accel.c b/drivers/video/aty/radeon_accel.c
new file mode 100644
index 0000000..3ca27cb
--- /dev/null
+++ b/drivers/video/aty/radeon_accel.c
@@ -0,0 +1,316 @@
+#include "radeonfb.h"
+
+/* the accelerated functions here are patterned after the 
+ * "ACCEL_MMIO" ifdef branches in XFree86
+ * --dte
+ */
+
+static void radeon_fixup_offset(struct radeonfb_info *rinfo)
+{
+	u32 local_base;
+
+	/* *** Ugly workaround *** */
+	/*
+	 * On some platforms, the video memory is mapped at 0 in radeon chip space
+	 * (like PPCs) by the firmware. X will always move it up so that it's seen
+	 * by the chip to be at the same address as the PCI BAR.
+	 * That means that when switching back from X, there is a mismatch between
+	 * the offsets programmed into the engine. This means that potentially,
+	 * accel operations done before radeonfb has a chance to re-init the engine
+	 * will have incorrect offsets, and potentially trash system memory !
+	 *
+	 * The correct fix is for fbcon to never call any accel op before the engine
+	 * has properly been re-initialized (by a call to set_var), but this is a
+	 * complex fix. This workaround in the meantime, called before every accel
+	 * operation, makes sure the offsets are in sync.
+	 */
+
+	radeon_fifo_wait (1);
+	local_base = INREG(MC_FB_LOCATION) << 16;
+	if (local_base == rinfo->fb_local_base)
+		return;
+
+	rinfo->fb_local_base = local_base;
+
+	radeon_fifo_wait (3);
+	OUTREG(DEFAULT_PITCH_OFFSET, (rinfo->pitch << 0x16) |
+				     (rinfo->fb_local_base >> 10));
+	OUTREG(DST_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10));
+	OUTREG(SRC_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10));
+}
+
+static void radeonfb_prim_fillrect(struct radeonfb_info *rinfo, 
+				   const struct fb_fillrect *region)
+{
+	radeon_fifo_wait(4);  
+  
+	OUTREG(DP_GUI_MASTER_CNTL,  
+		rinfo->dp_gui_master_cntl  /* contains, like GMC_DST_32BPP */
+                | GMC_BRUSH_SOLID_COLOR
+                | ROP3_P);
+	if (radeon_get_dstbpp(rinfo->depth) != DST_8BPP)
+		OUTREG(DP_BRUSH_FRGD_CLR, rinfo->pseudo_palette[region->color]);
+	else
+		OUTREG(DP_BRUSH_FRGD_CLR, region->color);
+	OUTREG(DP_WRITE_MSK, 0xffffffff);
+	OUTREG(DP_CNTL, (DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM));
+
+	radeon_fifo_wait(2);  
+	OUTREG(DST_Y_X, (region->dy << 16) | region->dx);
+	OUTREG(DST_WIDTH_HEIGHT, (region->width << 16) | region->height);
+}
+
+void radeonfb_fillrect(struct fb_info *info, const struct fb_fillrect *region)
+{
+	struct radeonfb_info *rinfo = info->par;
+	struct fb_fillrect modded;
+	int vxres, vyres;
+  
+	if (info->state != FBINFO_STATE_RUNNING)
+		return;
+	if (info->flags & FBINFO_HWACCEL_DISABLED) {
+		cfb_fillrect(info, region);
+		return;
+	}
+
+	radeon_fixup_offset(rinfo);
+
+	vxres = info->var.xres_virtual;
+	vyres = info->var.yres_virtual;
+
+	memcpy(&modded, region, sizeof(struct fb_fillrect));
+
+	if(!modded.width || !modded.height ||
+	   modded.dx >= vxres || modded.dy >= vyres)
+		return;
+  
+	if(modded.dx + modded.width  > vxres) modded.width  = vxres - modded.dx;
+	if(modded.dy + modded.height > vyres) modded.height = vyres - modded.dy;
+
+	radeonfb_prim_fillrect(rinfo, &modded);
+}
+
+static void radeonfb_prim_copyarea(struct radeonfb_info *rinfo, 
+				   const struct fb_copyarea *area)
+{
+	int xdir, ydir;
+	u32 sx, sy, dx, dy, w, h;
+
+	w = area->width; h = area->height;
+	dx = area->dx; dy = area->dy;
+	sx = area->sx; sy = area->sy;
+	xdir = sx - dx;
+	ydir = sy - dy;
+
+	if ( xdir < 0 ) { sx += w-1; dx += w-1; }
+	if ( ydir < 0 ) { sy += h-1; dy += h-1; }
+
+	radeon_fifo_wait(3);
+	OUTREG(DP_GUI_MASTER_CNTL,
+		rinfo->dp_gui_master_cntl /* i.e. GMC_DST_32BPP */
+		| GMC_BRUSH_NONE
+		| GMC_SRC_DSTCOLOR
+		| ROP3_S 
+		| DP_SRC_SOURCE_MEMORY );
+	OUTREG(DP_WRITE_MSK, 0xffffffff);
+	OUTREG(DP_CNTL, (xdir>=0 ? DST_X_LEFT_TO_RIGHT : 0)
+			| (ydir>=0 ? DST_Y_TOP_TO_BOTTOM : 0));
+
+	radeon_fifo_wait(3);
+	OUTREG(SRC_Y_X, (sy << 16) | sx);
+	OUTREG(DST_Y_X, (dy << 16) | dx);
+	OUTREG(DST_HEIGHT_WIDTH, (h << 16) | w);
+}
+
+
+void radeonfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+	struct radeonfb_info *rinfo = info->par;
+	struct fb_copyarea modded;
+	u32 vxres, vyres;
+	modded.sx = area->sx;
+	modded.sy = area->sy;
+	modded.dx = area->dx;
+	modded.dy = area->dy;
+	modded.width  = area->width;
+	modded.height = area->height;
+  
+	if (info->state != FBINFO_STATE_RUNNING)
+		return;
+	if (info->flags & FBINFO_HWACCEL_DISABLED) {
+		cfb_copyarea(info, area);
+		return;
+	}
+
+	radeon_fixup_offset(rinfo);
+
+	vxres = info->var.xres_virtual;
+	vyres = info->var.yres_virtual;
+
+	if(!modded.width || !modded.height ||
+	   modded.sx >= vxres || modded.sy >= vyres ||
+	   modded.dx >= vxres || modded.dy >= vyres)
+		return;
+  
+	if(modded.sx + modded.width > vxres)  modded.width = vxres - modded.sx;
+	if(modded.dx + modded.width > vxres)  modded.width = vxres - modded.dx;
+	if(modded.sy + modded.height > vyres) modded.height = vyres - modded.sy;
+	if(modded.dy + modded.height > vyres) modded.height = vyres - modded.dy;
+  
+	radeonfb_prim_copyarea(rinfo, &modded);
+}
+
+void radeonfb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	struct radeonfb_info *rinfo = info->par;
+
+	if (info->state != FBINFO_STATE_RUNNING)
+		return;
+	radeon_engine_idle();
+
+	cfb_imageblit(info, image);
+}
+
+int radeonfb_sync(struct fb_info *info)
+{
+	struct radeonfb_info *rinfo = info->par;
+
+	if (info->state != FBINFO_STATE_RUNNING)
+		return 0;
+	radeon_engine_idle();
+
+	return 0;
+}
+
+void radeonfb_engine_reset(struct radeonfb_info *rinfo)
+{
+	u32 clock_cntl_index, mclk_cntl, rbbm_soft_reset;
+	u32 host_path_cntl;
+
+	radeon_engine_flush (rinfo);
+
+	clock_cntl_index = INREG(CLOCK_CNTL_INDEX);
+	mclk_cntl = INPLL(MCLK_CNTL);
+
+	OUTPLL(MCLK_CNTL, (mclk_cntl |
+			   FORCEON_MCLKA |
+			   FORCEON_MCLKB |
+			   FORCEON_YCLKA |
+			   FORCEON_YCLKB |
+			   FORCEON_MC |
+			   FORCEON_AIC));
+
+	host_path_cntl = INREG(HOST_PATH_CNTL);
+	rbbm_soft_reset = INREG(RBBM_SOFT_RESET);
+
+	if (rinfo->family == CHIP_FAMILY_R300 ||
+	    rinfo->family == CHIP_FAMILY_R350 ||
+	    rinfo->family == CHIP_FAMILY_RV350) {
+		u32 tmp;
+
+		OUTREG(RBBM_SOFT_RESET, (rbbm_soft_reset |
+					 SOFT_RESET_CP |
+					 SOFT_RESET_HI |
+					 SOFT_RESET_E2));
+		INREG(RBBM_SOFT_RESET);
+		OUTREG(RBBM_SOFT_RESET, 0);
+		tmp = INREG(RB2D_DSTCACHE_MODE);
+		OUTREG(RB2D_DSTCACHE_MODE, tmp | (1 << 17)); /* FIXME */
+	} else {
+		OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset |
+					SOFT_RESET_CP |
+					SOFT_RESET_HI |
+					SOFT_RESET_SE |
+					SOFT_RESET_RE |
+					SOFT_RESET_PP |
+					SOFT_RESET_E2 |
+					SOFT_RESET_RB);
+		INREG(RBBM_SOFT_RESET);
+		OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset & (u32)
+					~(SOFT_RESET_CP |
+					  SOFT_RESET_HI |
+					  SOFT_RESET_SE |
+					  SOFT_RESET_RE |
+					  SOFT_RESET_PP |
+					  SOFT_RESET_E2 |
+					  SOFT_RESET_RB));
+		INREG(RBBM_SOFT_RESET);
+	}
+
+	OUTREG(HOST_PATH_CNTL, host_path_cntl | HDP_SOFT_RESET);
+	INREG(HOST_PATH_CNTL);
+	OUTREG(HOST_PATH_CNTL, host_path_cntl);
+
+	if (rinfo->family != CHIP_FAMILY_R300 ||
+	    rinfo->family != CHIP_FAMILY_R350 ||
+	    rinfo->family != CHIP_FAMILY_RV350)
+		OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset);
+
+	OUTREG(CLOCK_CNTL_INDEX, clock_cntl_index);
+	OUTPLL(MCLK_CNTL, mclk_cntl);
+}
+
+void radeonfb_engine_init (struct radeonfb_info *rinfo)
+{
+	unsigned long temp;
+
+	/* disable 3D engine */
+	OUTREG(RB3D_CNTL, 0);
+
+	radeonfb_engine_reset(rinfo);
+
+	radeon_fifo_wait (1);
+	if ((rinfo->family != CHIP_FAMILY_R300) &&
+	    (rinfo->family != CHIP_FAMILY_R350) &&
+	    (rinfo->family != CHIP_FAMILY_RV350))
+		OUTREG(RB2D_DSTCACHE_MODE, 0);
+
+	radeon_fifo_wait (3);
+	/* We re-read MC_FB_LOCATION from card as it can have been
+	 * modified by XFree drivers (ouch !)
+	 */
+	rinfo->fb_local_base = INREG(MC_FB_LOCATION) << 16;
+
+	OUTREG(DEFAULT_PITCH_OFFSET, (rinfo->pitch << 0x16) |
+				     (rinfo->fb_local_base >> 10));
+	OUTREG(DST_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10));
+	OUTREG(SRC_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10));
+
+	radeon_fifo_wait (1);
+#if defined(__BIG_ENDIAN)
+	OUTREGP(DP_DATATYPE, HOST_BIG_ENDIAN_EN, ~HOST_BIG_ENDIAN_EN);
+#else
+	OUTREGP(DP_DATATYPE, 0, ~HOST_BIG_ENDIAN_EN);
+#endif
+	radeon_fifo_wait (2);
+	OUTREG(DEFAULT_SC_TOP_LEFT, 0);
+	OUTREG(DEFAULT_SC_BOTTOM_RIGHT, (DEFAULT_SC_RIGHT_MAX |
+					 DEFAULT_SC_BOTTOM_MAX));
+
+	temp = radeon_get_dstbpp(rinfo->depth);
+	rinfo->dp_gui_master_cntl = ((temp << 8) | GMC_CLR_CMP_CNTL_DIS);
+
+	radeon_fifo_wait (1);
+	OUTREG(DP_GUI_MASTER_CNTL, (rinfo->dp_gui_master_cntl |
+				    GMC_BRUSH_SOLID_COLOR |
+				    GMC_SRC_DATATYPE_COLOR));
+
+	radeon_fifo_wait (7);
+
+	/* clear line drawing regs */
+	OUTREG(DST_LINE_START, 0);
+	OUTREG(DST_LINE_END, 0);
+
+	/* set brush color regs */
+	OUTREG(DP_BRUSH_FRGD_CLR, 0xffffffff);
+	OUTREG(DP_BRUSH_BKGD_CLR, 0x00000000);
+
+	/* set source color regs */
+	OUTREG(DP_SRC_FRGD_CLR, 0xffffffff);
+	OUTREG(DP_SRC_BKGD_CLR, 0x00000000);
+
+	/* default write mask */
+	OUTREG(DP_WRITE_MSK, 0xffffffff);
+
+	radeon_engine_idle ();
+}
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
new file mode 100644
index 0000000..e8eb124
--- /dev/null
+++ b/drivers/video/aty/radeon_base.c
@@ -0,0 +1,2587 @@
+/*
+ *	drivers/video/aty/radeon_base.c
+ *
+ *	framebuffer driver for ATI Radeon chipset video boards
+ *
+ *	Copyright 2003	Ben. Herrenschmidt <benh@kernel.crashing.org>
+ *	Copyright 2000	Ani Joshi <ajoshi@kernel.crashing.org>
+ *
+ *	i2c bits from Luca Tettamanti <kronos@kronoz.cjb.net>
+ *	
+ *	Special thanks to ATI DevRel team for their hardware donations.
+ *
+ *	...Insert GPL boilerplate here...
+ *
+ *	Significant portions of this driver apdated from XFree86 Radeon
+ *	driver which has the following copyright notice:
+ *
+ *	Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
+ *                     VA Linux Systems Inc., Fremont, California.
+ *
+ *	All Rights Reserved.
+ *
+ *	Permission is hereby granted, free of charge, to any person obtaining
+ *	a copy of this software and associated documentation files (the
+ *	"Software"), to deal in the Software without restriction, including
+ *	without limitation on the rights to use, copy, modify, merge,
+ *	publish, distribute, sublicense, and/or sell copies of the Software,
+ *	and to permit persons to whom the Software is furnished to do so,
+ *	subject to the following conditions:
+ *
+ *	The above copyright notice and this permission notice (including the
+ *	next paragraph) shall be included in all copies or substantial
+ *	portions of the Software.
+ *
+ *	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * 	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *	MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *	NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR
+ *	THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *	WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ *	DEALINGS IN THE SOFTWARE.
+ *
+ *	XFree86 driver authors:
+ *
+ *	   Kevin E. Martin <martin@xfree86.org>
+ *	   Rickard E. Faith <faith@valinux.com>
+ *	   Alan Hourihane <alanh@fairlite.demon.co.uk>
+ *
+ */
+
+
+#define RADEON_VERSION	"0.2.0"
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.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/delay.h>
+#include <linux/time.h>
+#include <linux/fb.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_PPC_OF
+
+#include <asm/pci-bridge.h>
+#include "../macmodes.h"
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+
+#ifdef CONFIG_BOOTX_TEXT
+#include <asm/btext.h>
+#endif
+
+#endif /* CONFIG_PPC_OF */
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include <video/radeon.h>
+#include <linux/radeonfb.h>
+
+#include "../edid.h" // MOVE THAT TO include/video
+#include "ati_ids.h"
+#include "radeonfb.h"		    
+
+#define MAX_MAPPED_VRAM	(2048*2048*4)
+#define MIN_MAPPED_VRAM	(1024*768*1)
+
+#define CHIP_DEF(id, family, flags)					\
+	{ PCI_VENDOR_ID_ATI, id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (flags) | (CHIP_FAMILY_##family) }
+
+static struct pci_device_id radeonfb_pci_table[] = {
+	/* Mobility M6 */
+	CHIP_DEF(PCI_CHIP_RADEON_LY, 	RV100,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+	CHIP_DEF(PCI_CHIP_RADEON_LZ,	RV100,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+	/* Radeon VE/7000 */
+	CHIP_DEF(PCI_CHIP_RV100_QY, 	RV100,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_RV100_QZ, 	RV100,	CHIP_HAS_CRTC2),
+	/* Radeon IGP320M (U1) */
+	CHIP_DEF(PCI_CHIP_RS100_4336,	RS100,	CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
+	/* Radeon IGP320 (A3) */
+	CHIP_DEF(PCI_CHIP_RS100_4136,	RS100,	CHIP_HAS_CRTC2 | CHIP_IS_IGP), 
+	/* IGP330M/340M/350M (U2) */
+	CHIP_DEF(PCI_CHIP_RS200_4337,	RS200,	CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
+	/* IGP330/340/350 (A4) */
+	CHIP_DEF(PCI_CHIP_RS200_4137,	RS200,	CHIP_HAS_CRTC2 | CHIP_IS_IGP),
+	/* Mobility 7000 IGP */
+	CHIP_DEF(PCI_CHIP_RS250_4437,	RS200,	CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
+	/* 7000 IGP (A4+) */
+	CHIP_DEF(PCI_CHIP_RS250_4237,	RS200,	CHIP_HAS_CRTC2 | CHIP_IS_IGP),
+	/* 8500 AIW */
+	CHIP_DEF(PCI_CHIP_R200_BB,	R200,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R200_BC,	R200,	CHIP_HAS_CRTC2),
+	/* 8700/8800 */
+	CHIP_DEF(PCI_CHIP_R200_QH,	R200,	CHIP_HAS_CRTC2),
+	/* 8500 */
+	CHIP_DEF(PCI_CHIP_R200_QL,	R200,	CHIP_HAS_CRTC2),
+	/* 9100 */
+	CHIP_DEF(PCI_CHIP_R200_QM,	R200,	CHIP_HAS_CRTC2),
+	/* Mobility M7 */
+	CHIP_DEF(PCI_CHIP_RADEON_LW,	RV200,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+	CHIP_DEF(PCI_CHIP_RADEON_LX,	RV200,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+	/* 7500 */
+	CHIP_DEF(PCI_CHIP_RV200_QW,	RV200,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_RV200_QX,	RV200,	CHIP_HAS_CRTC2),
+	/* Mobility M9 */
+	CHIP_DEF(PCI_CHIP_RV250_Ld,	RV250,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+	CHIP_DEF(PCI_CHIP_RV250_Le,	RV250,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+	CHIP_DEF(PCI_CHIP_RV250_Lf,	RV250,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+	CHIP_DEF(PCI_CHIP_RV250_Lg,	RV250,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+	/* 9000/Pro */
+	CHIP_DEF(PCI_CHIP_RV250_If,	RV250,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_RV250_Ig,	RV250,	CHIP_HAS_CRTC2),
+	/* Mobility 9100 IGP (U3) */
+	CHIP_DEF(PCI_CHIP_RS300_5835,	RS300,	CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
+	CHIP_DEF(PCI_CHIP_RS350_7835,	RS300,	CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
+	/* 9100 IGP (A5) */
+	CHIP_DEF(PCI_CHIP_RS300_5834,	RS300,	CHIP_HAS_CRTC2 | CHIP_IS_IGP),
+	CHIP_DEF(PCI_CHIP_RS350_7834,	RS300,	CHIP_HAS_CRTC2 | CHIP_IS_IGP),
+	/* Mobility 9200 (M9+) */
+	CHIP_DEF(PCI_CHIP_RV280_5C61,	RV280,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+	CHIP_DEF(PCI_CHIP_RV280_5C63,	RV280,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+	/* 9200 */
+	CHIP_DEF(PCI_CHIP_RV280_5960,	RV280,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_RV280_5961,	RV280,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_RV280_5962,	RV280,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_RV280_5964,	RV280,	CHIP_HAS_CRTC2),
+	/* 9500 */
+	CHIP_DEF(PCI_CHIP_R300_AD,	R300,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R300_AE,	R300,	CHIP_HAS_CRTC2),
+	/* 9600TX / FireGL Z1 */
+	CHIP_DEF(PCI_CHIP_R300_AF,	R300,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R300_AG,	R300,	CHIP_HAS_CRTC2),
+	/* 9700/9500/Pro/FireGL X1 */
+	CHIP_DEF(PCI_CHIP_R300_ND,	R300,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R300_NE,	R300,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R300_NF,	R300,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R300_NG,	R300,	CHIP_HAS_CRTC2),
+	/* Mobility M10/M11 */
+	CHIP_DEF(PCI_CHIP_RV350_NP,	RV350,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+	CHIP_DEF(PCI_CHIP_RV350_NQ,	RV350,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+	CHIP_DEF(PCI_CHIP_RV350_NR,	RV350,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+	CHIP_DEF(PCI_CHIP_RV350_NS,	RV350,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+	CHIP_DEF(PCI_CHIP_RV350_NT,	RV350,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+	CHIP_DEF(PCI_CHIP_RV350_NV,	RV350,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+	/* 9600/FireGL T2 */
+	CHIP_DEF(PCI_CHIP_RV350_AP,	RV350,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_RV350_AQ,	RV350,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_RV360_AR,	RV350,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_RV350_AS,	RV350,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_RV350_AT,	RV350,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_RV350_AV,	RV350,	CHIP_HAS_CRTC2),
+	/* 9800/Pro/FileGL X2 */
+	CHIP_DEF(PCI_CHIP_R350_AH,	R350,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R350_AI,	R350,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R350_AJ,	R350,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R350_AK,	R350,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R350_NH,	R350,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R350_NI,	R350,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R360_NJ,	R350,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R350_NK,	R350,	CHIP_HAS_CRTC2),
+	/* Newer stuff */
+	CHIP_DEF(PCI_CHIP_RV380_3E50,	RV380,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_RV380_3E54,	RV380,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_RV380_3150,	RV380,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+	CHIP_DEF(PCI_CHIP_RV380_3154,	RV380,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+	CHIP_DEF(PCI_CHIP_RV370_5B60,	RV380,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_RV370_5B62,	RV380,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_RV370_5B64,	RV380,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_RV370_5B65,	RV380,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_RV370_5460,	RV380,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+	CHIP_DEF(PCI_CHIP_RV370_5464,	RV380,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+	CHIP_DEF(PCI_CHIP_R420_JH,	R420,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R420_JI,	R420,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R420_JJ,	R420,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R420_JK,	R420,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R420_JL,	R420,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R420_JM,	R420,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R420_JN,	R420,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+	CHIP_DEF(PCI_CHIP_R420_JP,	R420,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R423_UH,	R420,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R423_UI,	R420,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R423_UJ,	R420,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R423_UK,	R420,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R423_UQ,	R420,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R423_UR,	R420,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R423_UT,	R420,	CHIP_HAS_CRTC2),
+	CHIP_DEF(PCI_CHIP_R423_5D57,	R420,	CHIP_HAS_CRTC2),
+	/* Original Radeon/7200 */
+	CHIP_DEF(PCI_CHIP_RADEON_QD,	RADEON,	0),
+	CHIP_DEF(PCI_CHIP_RADEON_QE,	RADEON,	0),
+	CHIP_DEF(PCI_CHIP_RADEON_QF,	RADEON,	0),
+	CHIP_DEF(PCI_CHIP_RADEON_QG,	RADEON,	0),
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, radeonfb_pci_table);
+
+
+typedef struct {
+	u16 reg;
+	u32 val;
+} reg_val;
+
+
+/* these common regs are cleared before mode setting so they do not
+ * interfere with anything
+ */
+static reg_val common_regs[] = {
+	{ OVR_CLR, 0 },	
+	{ OVR_WID_LEFT_RIGHT, 0 },
+	{ OVR_WID_TOP_BOTTOM, 0 },
+	{ OV0_SCALE_CNTL, 0 },
+	{ SUBPIC_CNTL, 0 },
+	{ VIPH_CONTROL, 0 },
+	{ I2C_CNTL_1, 0 },
+	{ GEN_INT_CNTL, 0 },
+	{ CAP0_TRIG_CNTL, 0 },
+	{ CAP1_TRIG_CNTL, 0 },
+};
+
+/*
+ * globals
+ */
+        
+static char *mode_option;
+static char *monitor_layout;
+static int noaccel = 0;
+static int default_dynclk = -2;
+static int nomodeset = 0;
+static int ignore_edid = 0;
+static int mirror = 0;
+static int panel_yres = 0;
+static int force_dfp = 0;
+static int force_measure_pll = 0;
+#ifdef CONFIG_MTRR
+static int nomtrr = 0;
+#endif
+
+/*
+ * prototypes
+ */
+
+
+#ifdef CONFIG_PPC_OF
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+static int radeon_set_backlight_enable(int on, int level, void *data);
+static int radeon_set_backlight_level(int level, void *data);
+static struct backlight_controller radeon_backlight_controller = {
+	radeon_set_backlight_enable,
+	radeon_set_backlight_level
+};
+#endif /* CONFIG_PMAC_BACKLIGHT */
+
+#endif /* CONFIG_PPC_OF */
+
+static void radeon_unmap_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev)
+{
+	if (!rinfo->bios_seg)
+		return;
+	pci_unmap_rom(dev, rinfo->bios_seg);
+}
+
+static int __devinit radeon_map_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev)
+{
+	void __iomem *rom;
+	u16 dptr;
+	u8 rom_type;
+	size_t rom_size;
+
+	/* If this is a primary card, there is a shadow copy of the
+	 * ROM somewhere in the first meg. We will just ignore the copy
+	 * and use the ROM directly.
+	 */
+    
+    	/* Fix from ATI for problem with Radeon hardware not leaving ROM enabled */
+    	unsigned int temp;
+	temp = INREG(MPP_TB_CONFIG);
+	temp &= 0x00ffffffu;
+	temp |= 0x04 << 24;
+	OUTREG(MPP_TB_CONFIG, temp);
+	temp = INREG(MPP_TB_CONFIG);
+                                                                                                          
+	rom = pci_map_rom(dev, &rom_size);
+	if (!rom) {
+		printk(KERN_ERR "radeonfb (%s): ROM failed to map\n",
+		       pci_name(rinfo->pdev));
+		return -ENOMEM;
+	}
+	
+	rinfo->bios_seg = rom;
+
+	/* Very simple test to make sure it appeared */
+	if (BIOS_IN16(0) != 0xaa55) {
+		printk(KERN_ERR "radeonfb (%s): Invalid ROM signature %x should be"
+		       "0xaa55\n", pci_name(rinfo->pdev), BIOS_IN16(0));
+		goto failed;
+	}
+	/* Look for the PCI data to check the ROM type */
+	dptr = BIOS_IN16(0x18);
+
+	/* Check the PCI data signature. If it's wrong, we still assume a normal x86 ROM
+	 * for now, until I've verified this works everywhere. The goal here is more
+	 * to phase out Open Firmware images.
+	 *
+	 * Currently, we only look at the first PCI data, we could iteratre and deal with
+	 * them all, and we should use fb_bios_start relative to start of image and not
+	 * relative start of ROM, but so far, I never found a dual-image ATI card
+	 *
+	 * typedef struct {
+	 * 	u32	signature;	+ 0x00
+	 * 	u16	vendor;		+ 0x04
+	 * 	u16	device;		+ 0x06
+	 * 	u16	reserved_1;	+ 0x08
+	 * 	u16	dlen;		+ 0x0a
+	 * 	u8	drevision;	+ 0x0c
+	 * 	u8	class_hi;	+ 0x0d
+	 * 	u16	class_lo;	+ 0x0e
+	 * 	u16	ilen;		+ 0x10
+	 * 	u16	irevision;	+ 0x12
+	 * 	u8	type;		+ 0x14
+	 * 	u8	indicator;	+ 0x15
+	 * 	u16	reserved_2;	+ 0x16
+	 * } pci_data_t;
+	 */
+	if (BIOS_IN32(dptr) !=  (('R' << 24) | ('I' << 16) | ('C' << 8) | 'P')) {
+		printk(KERN_WARNING "radeonfb (%s): PCI DATA signature in ROM"
+		       "incorrect: %08x\n", pci_name(rinfo->pdev), BIOS_IN32(dptr));
+		goto anyway;
+	}
+	rom_type = BIOS_IN8(dptr + 0x14);
+	switch(rom_type) {
+	case 0:
+		printk(KERN_INFO "radeonfb: Found Intel x86 BIOS ROM Image\n");
+		break;
+	case 1:
+		printk(KERN_INFO "radeonfb: Found Open Firmware ROM Image\n");
+		goto failed;
+	case 2:
+		printk(KERN_INFO "radeonfb: Found HP PA-RISC ROM Image\n");
+		goto failed;
+	default:
+		printk(KERN_INFO "radeonfb: Found unknown type %d ROM Image\n", rom_type);
+		goto failed;
+	}
+ anyway:
+	/* Locate the flat panel infos, do some sanity checking !!! */
+	rinfo->fp_bios_start = BIOS_IN16(0x48);
+	return 0;
+
+ failed:
+	rinfo->bios_seg = NULL;
+	radeon_unmap_ROM(rinfo, dev);
+	return -ENXIO;
+}
+
+#ifdef CONFIG_X86
+static int  __devinit radeon_find_mem_vbios(struct radeonfb_info *rinfo)
+{
+	/* I simplified this code as we used to miss the signatures in
+	 * a lot of case. It's now closer to XFree, we just don't check
+	 * for signatures at all... Something better will have to be done
+	 * if we end up having conflicts
+	 */
+        u32  segstart;
+	void __iomem *rom_base = NULL;
+                                                
+        for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
+                rom_base = ioremap(segstart, 0x10000);
+		if (rom_base == NULL)
+			return -ENOMEM;
+                if (readb(rom_base) == 0x55 && readb(rom_base + 1) == 0xaa)
+	                break;
+                iounmap(rom_base);
+		rom_base = NULL;
+        }
+	if (rom_base == NULL)
+		return -ENXIO;
+
+	/* Locate the flat panel infos, do some sanity checking !!! */
+	rinfo->bios_seg = rom_base;
+	rinfo->fp_bios_start = BIOS_IN16(0x48);
+
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_PPC_OF
+/*
+ * Read XTAL (ref clock), SCLK and MCLK from Open Firmware device
+ * tree. Hopefully, ATI OF driver is kind enough to fill these
+ */
+static int __devinit radeon_read_xtal_OF (struct radeonfb_info *rinfo)
+{
+	struct device_node *dp = rinfo->of_node;
+	u32 *val;
+
+	if (dp == NULL)
+		return -ENODEV;
+	val = (u32 *) get_property(dp, "ATY,RefCLK", NULL);
+	if (!val || !*val) {
+		printk(KERN_WARNING "radeonfb: No ATY,RefCLK property !\n");
+		return -EINVAL;
+	}
+
+	rinfo->pll.ref_clk = (*val) / 10;
+
+	val = (u32 *) get_property(dp, "ATY,SCLK", NULL);
+	if (val && *val)
+		rinfo->pll.sclk = (*val) / 10;
+
+	val = (u32 *) get_property(dp, "ATY,MCLK", NULL);
+	if (val && *val)
+		rinfo->pll.mclk = (*val) / 10;
+
+       	return 0;
+}
+#endif /* CONFIG_PPC_OF */
+
+/*
+ * Read PLL infos from chip registers
+ */
+static int __devinit radeon_probe_pll_params(struct radeonfb_info *rinfo)
+{
+	unsigned char ppll_div_sel;
+	unsigned Ns, Nm, M;
+	unsigned sclk, mclk, tmp, ref_div;
+	int hTotal, vTotal, num, denom, m, n;
+	unsigned long long hz, vclk;
+	long xtal;
+	struct timeval start_tv, stop_tv;
+	long total_secs, total_usecs;
+	int i;
+
+	/* Ugh, we cut interrupts, bad bad bad, but we want some precision
+	 * here, so... --BenH
+	 */
+
+	/* Flush PCI buffers ? */
+	tmp = INREG(DEVICE_ID);
+
+	local_irq_disable();
+
+	for(i=0; i<1000000; i++)
+		if (((INREG(CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) == 0)
+			break;
+
+	do_gettimeofday(&start_tv);
+
+	for(i=0; i<1000000; i++)
+		if (((INREG(CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) != 0)
+			break;
+
+	for(i=0; i<1000000; i++)
+		if (((INREG(CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) == 0)
+			break;
+	
+	do_gettimeofday(&stop_tv);
+	
+	local_irq_enable();
+
+	total_secs = stop_tv.tv_sec - start_tv.tv_sec;
+	if (total_secs > 10)
+		return -1;
+	total_usecs = stop_tv.tv_usec - start_tv.tv_usec;
+	total_usecs += total_secs * 1000000;
+	if (total_usecs < 0)
+		total_usecs = -total_usecs;
+	hz = 1000000/total_usecs;
+ 
+	hTotal = ((INREG(CRTC_H_TOTAL_DISP) & 0x1ff) + 1) * 8;
+	vTotal = ((INREG(CRTC_V_TOTAL_DISP) & 0x3ff) + 1);
+	vclk = (long long)hTotal * (long long)vTotal * hz;
+
+	switch((INPLL(PPLL_REF_DIV) & 0x30000) >> 16) {
+	case 0:
+	default:
+		num = 1;
+		denom = 1;
+		break;
+	case 1:
+		n = ((INPLL(M_SPLL_REF_FB_DIV) >> 16) & 0xff);
+		m = (INPLL(M_SPLL_REF_FB_DIV) & 0xff);
+		num = 2*n;
+		denom = 2*m;
+		break;
+	case 2:
+		n = ((INPLL(M_SPLL_REF_FB_DIV) >> 8) & 0xff);
+		m = (INPLL(M_SPLL_REF_FB_DIV) & 0xff);
+		num = 2*n;
+		denom = 2*m;
+        break;
+	}
+
+	ppll_div_sel = INREG8(CLOCK_CNTL_INDEX + 1) & 0x3;
+	radeon_pll_errata_after_index(rinfo);
+
+	n = (INPLL(PPLL_DIV_0 + ppll_div_sel) & 0x7ff);
+	m = (INPLL(PPLL_REF_DIV) & 0x3ff);
+
+	num *= n;
+	denom *= m;
+
+	switch ((INPLL(PPLL_DIV_0 + ppll_div_sel) >> 16) & 0x7) {
+	case 1:
+		denom *= 2;
+		break;
+	case 2:
+		denom *= 4;
+		break;
+	case 3:
+		denom *= 8;
+		break;
+	case 4:
+		denom *= 3;
+		break;
+	case 6:
+		denom *= 6;   
+		break;
+	case 7:
+		denom *= 12;
+		break;
+	}
+
+	vclk *= denom;
+	do_div(vclk, 1000 * num);
+	xtal = vclk;
+
+	if ((xtal > 26900) && (xtal < 27100))
+		xtal = 2700;
+	else if ((xtal > 14200) && (xtal < 14400))
+		xtal = 1432;
+	else if ((xtal > 29400) && (xtal < 29600))
+		xtal = 2950;
+	else {
+		printk(KERN_WARNING "xtal calculation failed: %ld\n", xtal);
+		return -1;
+	}
+
+	tmp = INPLL(M_SPLL_REF_FB_DIV);
+	ref_div = INPLL(PPLL_REF_DIV) & 0x3ff;
+
+	Ns = (tmp & 0xff0000) >> 16;
+	Nm = (tmp & 0xff00) >> 8;
+	M = (tmp & 0xff);
+	sclk = round_div((2 * Ns * xtal), (2 * M));
+	mclk = round_div((2 * Nm * xtal), (2 * M));
+
+	/* we're done, hopefully these are sane values */
+	rinfo->pll.ref_clk = xtal;
+	rinfo->pll.ref_div = ref_div;
+	rinfo->pll.sclk = sclk;
+	rinfo->pll.mclk = mclk;
+
+	return 0;
+}
+
+/*
+ * Retreive PLL infos by different means (BIOS, Open Firmware, register probing...)
+ */
+static void __devinit radeon_get_pllinfo(struct radeonfb_info *rinfo)
+{
+	/*
+	 * In the case nothing works, these are defaults; they are mostly
+	 * incomplete, however.  It does provide ppll_max and _min values
+	 * even for most other methods, however.
+	 */
+	switch (rinfo->chipset) {
+	case PCI_DEVICE_ID_ATI_RADEON_QW:
+	case PCI_DEVICE_ID_ATI_RADEON_QX:
+		rinfo->pll.ppll_max = 35000;
+		rinfo->pll.ppll_min = 12000;
+		rinfo->pll.mclk = 23000;
+		rinfo->pll.sclk = 23000;
+		rinfo->pll.ref_clk = 2700;
+		break;
+	case PCI_DEVICE_ID_ATI_RADEON_QL:
+	case PCI_DEVICE_ID_ATI_RADEON_QN:
+	case PCI_DEVICE_ID_ATI_RADEON_QO:
+	case PCI_DEVICE_ID_ATI_RADEON_Ql:
+	case PCI_DEVICE_ID_ATI_RADEON_BB:
+		rinfo->pll.ppll_max = 35000;
+		rinfo->pll.ppll_min = 12000;
+		rinfo->pll.mclk = 27500;
+		rinfo->pll.sclk = 27500;
+		rinfo->pll.ref_clk = 2700;
+		break;
+	case PCI_DEVICE_ID_ATI_RADEON_Id:
+	case PCI_DEVICE_ID_ATI_RADEON_Ie:
+	case PCI_DEVICE_ID_ATI_RADEON_If:
+	case PCI_DEVICE_ID_ATI_RADEON_Ig:
+		rinfo->pll.ppll_max = 35000;
+		rinfo->pll.ppll_min = 12000;
+		rinfo->pll.mclk = 25000;
+		rinfo->pll.sclk = 25000;
+		rinfo->pll.ref_clk = 2700;
+		break;
+	case PCI_DEVICE_ID_ATI_RADEON_ND:
+	case PCI_DEVICE_ID_ATI_RADEON_NE:
+	case PCI_DEVICE_ID_ATI_RADEON_NF:
+	case PCI_DEVICE_ID_ATI_RADEON_NG:
+		rinfo->pll.ppll_max = 40000;
+		rinfo->pll.ppll_min = 20000;
+		rinfo->pll.mclk = 27000;
+		rinfo->pll.sclk = 27000;
+		rinfo->pll.ref_clk = 2700;
+		break;
+	case PCI_DEVICE_ID_ATI_RADEON_QD:
+	case PCI_DEVICE_ID_ATI_RADEON_QE:
+	case PCI_DEVICE_ID_ATI_RADEON_QF:
+	case PCI_DEVICE_ID_ATI_RADEON_QG:
+	default:
+		rinfo->pll.ppll_max = 35000;
+		rinfo->pll.ppll_min = 12000;
+		rinfo->pll.mclk = 16600;
+		rinfo->pll.sclk = 16600;
+		rinfo->pll.ref_clk = 2700;
+		break;
+	}
+	rinfo->pll.ref_div = INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;
+
+
+#ifdef CONFIG_PPC_OF
+	/*
+	 * Retreive PLL infos from Open Firmware first
+	 */
+       	if (!force_measure_pll && radeon_read_xtal_OF(rinfo) == 0) {
+       		printk(KERN_INFO "radeonfb: Retreived PLL infos from Open Firmware\n");
+		goto found;
+	}
+#endif /* CONFIG_PPC_OF */
+
+	/*
+	 * Check out if we have an X86 which gave us some PLL informations
+	 * and if yes, retreive them
+	 */
+	if (!force_measure_pll && rinfo->bios_seg) {
+		u16 pll_info_block = BIOS_IN16(rinfo->fp_bios_start + 0x30);
+
+		rinfo->pll.sclk		= BIOS_IN16(pll_info_block + 0x08);
+		rinfo->pll.mclk		= BIOS_IN16(pll_info_block + 0x0a);
+		rinfo->pll.ref_clk	= BIOS_IN16(pll_info_block + 0x0e);
+		rinfo->pll.ref_div	= BIOS_IN16(pll_info_block + 0x10);
+		rinfo->pll.ppll_min	= BIOS_IN32(pll_info_block + 0x12);
+		rinfo->pll.ppll_max	= BIOS_IN32(pll_info_block + 0x16);
+
+		printk(KERN_INFO "radeonfb: Retreived PLL infos from BIOS\n");
+		goto found;
+	}
+
+	/*
+	 * We didn't get PLL parameters from either OF or BIOS, we try to
+	 * probe them
+	 */
+	if (radeon_probe_pll_params(rinfo) == 0) {
+		printk(KERN_INFO "radeonfb: Retreived PLL infos from registers\n");
+		goto found;
+	}
+
+	/*
+	 * Fall back to already-set defaults...
+	 */
+       	printk(KERN_INFO "radeonfb: Used default PLL infos\n");
+
+found:
+	/*
+	 * Some methods fail to retreive SCLK and MCLK values, we apply default
+	 * settings in this case (200Mhz). If that really happne often, we could
+	 * fetch from registers instead...
+	 */
+	if (rinfo->pll.mclk == 0)
+		rinfo->pll.mclk = 20000;
+	if (rinfo->pll.sclk == 0)
+		rinfo->pll.sclk = 20000;
+
+	printk("radeonfb: Reference=%d.%02d MHz (RefDiv=%d) Memory=%d.%02d Mhz, System=%d.%02d MHz\n",
+	       rinfo->pll.ref_clk / 100, rinfo->pll.ref_clk % 100,
+	       rinfo->pll.ref_div,
+	       rinfo->pll.mclk / 100, rinfo->pll.mclk % 100,
+	       rinfo->pll.sclk / 100, rinfo->pll.sclk % 100);
+	printk("radeonfb: PLL min %d max %d\n", rinfo->pll.ppll_min, rinfo->pll.ppll_max);
+}
+
+static int radeonfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct radeonfb_info *rinfo = info->par;
+        struct fb_var_screeninfo v;
+        int nom, den;
+	unsigned int pitch;
+
+	if (radeon_match_mode(rinfo, &v, var))
+		return -EINVAL;
+
+        switch (v.bits_per_pixel) {
+		case 0 ... 8:
+			v.bits_per_pixel = 8;
+			break;
+		case 9 ... 16:
+			v.bits_per_pixel = 16;
+			break;
+		case 17 ... 24:
+#if 0 /* Doesn't seem to work */
+			v.bits_per_pixel = 24;
+			break;
+#endif			
+			return -EINVAL;
+		case 25 ... 32:
+			v.bits_per_pixel = 32;
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	switch (var_to_depth(&v)) {
+                case 8:
+                        nom = den = 1;
+                        v.red.offset = v.green.offset = v.blue.offset = 0;
+                        v.red.length = v.green.length = v.blue.length = 8;
+                        v.transp.offset = v.transp.length = 0;
+                        break;
+		case 15:
+			nom = 2;
+			den = 1;
+			v.red.offset = 10;
+			v.green.offset = 5;
+			v.blue.offset = 0;
+			v.red.length = v.green.length = v.blue.length = 5;
+			v.transp.offset = v.transp.length = 0;
+			break;
+                case 16:
+                        nom = 2;
+                        den = 1;
+                        v.red.offset = 11;
+                        v.green.offset = 5;
+                        v.blue.offset = 0;
+                        v.red.length = 5;
+                        v.green.length = 6;
+                        v.blue.length = 5;
+                        v.transp.offset = v.transp.length = 0;
+                        break;                          
+                case 24:
+                        nom = 4;
+                        den = 1;
+                        v.red.offset = 16;
+                        v.green.offset = 8;
+                        v.blue.offset = 0;
+                        v.red.length = v.blue.length = v.green.length = 8;
+                        v.transp.offset = v.transp.length = 0;
+                        break;
+                case 32:
+                        nom = 4;
+                        den = 1;
+                        v.red.offset = 16;
+                        v.green.offset = 8;
+                        v.blue.offset = 0;
+                        v.red.length = v.blue.length = v.green.length = 8;
+                        v.transp.offset = 24;
+                        v.transp.length = 8;
+                        break;
+                default:
+                        printk ("radeonfb: mode %dx%dx%d rejected, color depth invalid\n",
+                                var->xres, var->yres, var->bits_per_pixel);
+                        return -EINVAL;
+        }
+
+	if (v.yres_virtual < v.yres)
+		v.yres_virtual = v.yres;
+	if (v.xres_virtual < v.xres)
+		v.xres_virtual = v.xres;
+                
+
+	/* XXX I'm adjusting xres_virtual to the pitch, that may help XFree
+	 * with some panels, though I don't quite like this solution
+	 */
+  	if (rinfo->info->flags & FBINFO_HWACCEL_DISABLED) {
+		v.xres_virtual = v.xres_virtual & ~7ul;
+	} else {
+		pitch = ((v.xres_virtual * ((v.bits_per_pixel + 1) / 8) + 0x3f)
+ 				& ~(0x3f)) >> 6;
+		v.xres_virtual = (pitch << 6) / ((v.bits_per_pixel + 1) / 8);
+	}
+
+	if (((v.xres_virtual * v.yres_virtual * nom) / den) > rinfo->mapped_vram)
+		return -EINVAL;
+
+	if (v.xres_virtual < v.xres)
+		v.xres = v.xres_virtual;
+
+	if (v.xoffset < 0)
+                v.xoffset = 0;
+        if (v.yoffset < 0)
+                v.yoffset = 0;
+         
+        if (v.xoffset > v.xres_virtual - v.xres)
+                v.xoffset = v.xres_virtual - v.xres - 1;
+                        
+        if (v.yoffset > v.yres_virtual - v.yres)
+                v.yoffset = v.yres_virtual - v.yres - 1;
+         
+        v.red.msb_right = v.green.msb_right = v.blue.msb_right =
+                          v.transp.offset = v.transp.length =
+                          v.transp.msb_right = 0;
+	
+        memcpy(var, &v, sizeof(v));
+
+        return 0;
+}
+
+
+static int radeonfb_pan_display (struct fb_var_screeninfo *var,
+                                 struct fb_info *info)
+{
+        struct radeonfb_info *rinfo = info->par;
+
+        if ((var->xoffset + var->xres > var->xres_virtual)
+	    || (var->yoffset + var->yres > var->yres_virtual))
+               return -EINVAL;
+                
+        if (rinfo->asleep)
+        	return 0;
+
+	radeon_fifo_wait(2);
+        OUTREG(CRTC_OFFSET, ((var->yoffset * var->xres_virtual + var->xoffset)
+			     * var->bits_per_pixel / 8) & ~7);
+        return 0;
+}
+
+
+static int radeonfb_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
+                           unsigned long arg, struct fb_info *info)
+{
+        struct radeonfb_info *rinfo = info->par;
+	unsigned int tmp;
+	u32 value = 0;
+	int rc;
+
+	switch (cmd) {
+		/*
+		 * TODO:  set mirror accordingly for non-Mobility chipsets with 2 CRTC's
+		 *        and do something better using 2nd CRTC instead of just hackish
+		 *        routing to second output
+		 */
+		case FBIO_RADEON_SET_MIRROR:
+			if (!rinfo->is_mobility)
+				return -EINVAL;
+
+			rc = get_user(value, (__u32 __user *)arg);
+
+			if (rc)
+				return rc;
+
+			radeon_fifo_wait(2);
+			if (value & 0x01) {
+				tmp = INREG(LVDS_GEN_CNTL);
+
+				tmp |= (LVDS_ON | LVDS_BLON);
+			} else {
+				tmp = INREG(LVDS_GEN_CNTL);
+
+				tmp &= ~(LVDS_ON | LVDS_BLON);
+			}
+
+			OUTREG(LVDS_GEN_CNTL, tmp);
+
+			if (value & 0x02) {
+				tmp = INREG(CRTC_EXT_CNTL);
+				tmp |= CRTC_CRT_ON;
+
+				mirror = 1;
+			} else {
+				tmp = INREG(CRTC_EXT_CNTL);
+				tmp &= ~CRTC_CRT_ON;
+
+				mirror = 0;
+			}
+
+			OUTREG(CRTC_EXT_CNTL, tmp);
+
+			return 0;
+		case FBIO_RADEON_GET_MIRROR:
+			if (!rinfo->is_mobility)
+				return -EINVAL;
+
+			tmp = INREG(LVDS_GEN_CNTL);
+			if ((LVDS_ON | LVDS_BLON) & tmp)
+				value |= 0x01;
+
+			tmp = INREG(CRTC_EXT_CNTL);
+			if (CRTC_CRT_ON & tmp)
+				value |= 0x02;
+
+			return put_user(value, (__u32 __user *)arg);
+		default:
+			return -EINVAL;
+	}
+
+	return -EINVAL;
+}
+
+
+int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch)
+{
+        u32 val;
+	u32 tmp_pix_clks;
+	int unblank = 0;
+
+	if (rinfo->lock_blank)
+		return 0;
+
+	radeon_engine_idle();
+
+	val = INREG(CRTC_EXT_CNTL);
+        val &= ~(CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS |
+                 CRTC_VSYNC_DIS);
+        switch (blank) {
+	case FB_BLANK_VSYNC_SUSPEND:
+		val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS);
+		break;
+	case FB_BLANK_HSYNC_SUSPEND:
+		val |= (CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS);
+		break;
+	case FB_BLANK_POWERDOWN:
+		val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS |
+			CRTC_HSYNC_DIS);
+		break;
+	case FB_BLANK_NORMAL:
+		val |= CRTC_DISPLAY_DIS;
+		break;
+	case FB_BLANK_UNBLANK:
+	default:
+		unblank = 1;
+        }
+	OUTREG(CRTC_EXT_CNTL, val);
+
+
+	switch (rinfo->mon1_type) {
+	case MT_DFP:
+		if (unblank)
+			OUTREGP(FP_GEN_CNTL, (FP_FPON | FP_TMDS_EN),
+				~(FP_FPON | FP_TMDS_EN));
+		else {
+			if (mode_switch || blank == FB_BLANK_NORMAL)
+				break;
+			OUTREGP(FP_GEN_CNTL, 0, ~(FP_FPON | FP_TMDS_EN));
+		}
+		break;
+	case MT_LCD:
+		del_timer_sync(&rinfo->lvds_timer);
+		val = INREG(LVDS_GEN_CNTL);
+		if (unblank) {
+			u32 target_val = (val & ~LVDS_DISPLAY_DIS) | LVDS_BLON | LVDS_ON
+				| LVDS_EN | (rinfo->init_state.lvds_gen_cntl
+					     & (LVDS_DIGON | LVDS_BL_MOD_EN));
+			if ((val ^ target_val) == LVDS_DISPLAY_DIS)
+				OUTREG(LVDS_GEN_CNTL, target_val);
+			else if ((val ^ target_val) != 0) {
+				OUTREG(LVDS_GEN_CNTL, target_val
+				       & ~(LVDS_ON | LVDS_BL_MOD_EN));
+				rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
+				rinfo->init_state.lvds_gen_cntl |=
+					target_val & LVDS_STATE_MASK;
+				if (mode_switch) {
+					radeon_msleep(rinfo->panel_info.pwr_delay);
+					OUTREG(LVDS_GEN_CNTL, target_val);
+				}
+				else {
+					rinfo->pending_lvds_gen_cntl = target_val;
+					mod_timer(&rinfo->lvds_timer,
+					   jiffies +
+					   msecs_to_jiffies(rinfo->panel_info.pwr_delay));
+				}
+			}
+		} else {
+			val |= LVDS_DISPLAY_DIS;
+			OUTREG(LVDS_GEN_CNTL, val);
+
+			/* We don't do a full switch-off on a simple mode switch */
+			if (mode_switch || blank == FB_BLANK_NORMAL)
+				break;
+
+			/* Asic bug, when turning off LVDS_ON, we have to make sure
+			 * RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
+			 */
+			tmp_pix_clks = INPLL(PIXCLKS_CNTL);
+			if (rinfo->is_mobility || rinfo->is_IGP)
+				OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
+			val &= ~(LVDS_BL_MOD_EN);
+			OUTREG(LVDS_GEN_CNTL, val);
+			udelay(100);
+			val &= ~(LVDS_ON | LVDS_EN);
+			OUTREG(LVDS_GEN_CNTL, val);
+			val &= ~LVDS_DIGON;
+			rinfo->pending_lvds_gen_cntl = val;
+			mod_timer(&rinfo->lvds_timer,
+				  jiffies +
+				  msecs_to_jiffies(rinfo->panel_info.pwr_delay));
+			rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
+			rinfo->init_state.lvds_gen_cntl |= val & LVDS_STATE_MASK;
+			if (rinfo->is_mobility || rinfo->is_IGP)
+				OUTPLL(PIXCLKS_CNTL, tmp_pix_clks);
+		}
+		break;
+	case MT_CRT:
+		// todo: powerdown DAC
+	default:
+		break;
+	}
+
+	/* let fbcon do a soft blank for us */
+	return (blank == FB_BLANK_NORMAL) ? -EINVAL : 0;
+}
+
+static int radeonfb_blank (int blank, struct fb_info *info)
+{
+        struct radeonfb_info *rinfo = info->par;
+
+	if (rinfo->asleep)
+		return 0;
+		
+	return radeon_screen_blank(rinfo, blank, 0);
+}
+
+static int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green,
+                             unsigned blue, unsigned transp, struct fb_info *info)
+{
+        struct radeonfb_info *rinfo = info->par;
+	u32 pindex;
+	unsigned int i;
+	
+	if (regno > 255)
+		return 1;
+
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+	rinfo->palette[regno].red = red;
+	rinfo->palette[regno].green = green;
+	rinfo->palette[regno].blue = blue;
+
+        /* default */
+        pindex = regno;
+
+        if (!rinfo->asleep) {
+        	u32 dac_cntl2, vclk_cntl = 0;
+        	
+		radeon_fifo_wait(9);
+		if (rinfo->is_mobility) {
+			vclk_cntl = INPLL(VCLK_ECP_CNTL);
+			OUTPLL(VCLK_ECP_CNTL, vclk_cntl & ~PIXCLK_DAC_ALWAYS_ONb);
+		}
+
+		/* Make sure we are on first palette */
+		if (rinfo->has_CRTC2) {
+			dac_cntl2 = INREG(DAC_CNTL2);
+			dac_cntl2 &= ~DAC2_PALETTE_ACCESS_CNTL;
+			OUTREG(DAC_CNTL2, dac_cntl2);
+		}
+
+		if (rinfo->bpp == 16) {
+			pindex = regno * 8;
+
+			if (rinfo->depth == 16 && regno > 63)
+				return 1;
+			if (rinfo->depth == 15 && regno > 31)
+				return 1;
+
+			/* For 565, the green component is mixed one order below */
+			if (rinfo->depth == 16) {
+		                OUTREG(PALETTE_INDEX, pindex>>1);
+	       	         	OUTREG(PALETTE_DATA, (rinfo->palette[regno>>1].red << 16) |
+	                        	(green << 8) | (rinfo->palette[regno>>1].blue));
+	                	green = rinfo->palette[regno<<1].green;
+	        	}
+		}
+
+		if (rinfo->depth != 16 || regno < 32) {
+			OUTREG(PALETTE_INDEX, pindex);
+			OUTREG(PALETTE_DATA, (red << 16) | (green << 8) | blue);
+		}
+		if (rinfo->is_mobility)
+			OUTPLL(VCLK_ECP_CNTL, vclk_cntl);
+	}
+ 	if (regno < 16) {
+		u32 *pal = info->pseudo_palette;
+        	switch (rinfo->depth) {
+		case 15:
+			pal[regno] = (regno << 10) | (regno << 5) | regno;
+			break;
+		case 16:
+			pal[regno] = (regno << 11) | (regno << 5) | regno;
+			break;
+		case 24:
+			pal[regno] = (regno << 16) | (regno << 8) | regno;
+			break;
+		case 32:
+			i = (regno << 8) | regno;
+			pal[regno] = (i << 16) | i;
+			break;
+		}
+        }
+	return 0;
+}
+
+
+static void radeon_save_state (struct radeonfb_info *rinfo,
+			       struct radeon_regs *save)
+{
+	/* CRTC regs */
+	save->crtc_gen_cntl = INREG(CRTC_GEN_CNTL);
+	save->crtc_ext_cntl = INREG(CRTC_EXT_CNTL);
+	save->crtc_more_cntl = INREG(CRTC_MORE_CNTL);
+	save->dac_cntl = INREG(DAC_CNTL);
+        save->crtc_h_total_disp = INREG(CRTC_H_TOTAL_DISP);
+        save->crtc_h_sync_strt_wid = INREG(CRTC_H_SYNC_STRT_WID);
+        save->crtc_v_total_disp = INREG(CRTC_V_TOTAL_DISP);
+        save->crtc_v_sync_strt_wid = INREG(CRTC_V_SYNC_STRT_WID);
+	save->crtc_pitch = INREG(CRTC_PITCH);
+	save->surface_cntl = INREG(SURFACE_CNTL);
+
+	/* FP regs */
+	save->fp_crtc_h_total_disp = INREG(FP_CRTC_H_TOTAL_DISP);
+	save->fp_crtc_v_total_disp = INREG(FP_CRTC_V_TOTAL_DISP);
+	save->fp_gen_cntl = INREG(FP_GEN_CNTL);
+	save->fp_h_sync_strt_wid = INREG(FP_H_SYNC_STRT_WID);
+	save->fp_horz_stretch = INREG(FP_HORZ_STRETCH);
+	save->fp_v_sync_strt_wid = INREG(FP_V_SYNC_STRT_WID);
+	save->fp_vert_stretch = INREG(FP_VERT_STRETCH);
+	save->lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
+	save->lvds_pll_cntl = INREG(LVDS_PLL_CNTL);
+	save->tmds_crc = INREG(TMDS_CRC);
+	save->tmds_transmitter_cntl = INREG(TMDS_TRANSMITTER_CNTL);
+	save->vclk_ecp_cntl = INPLL(VCLK_ECP_CNTL);
+
+	/* PLL regs */
+	save->clk_cntl_index = INREG(CLOCK_CNTL_INDEX) & ~0x3f;
+	radeon_pll_errata_after_index(rinfo);
+	save->ppll_div_3 = INPLL(PPLL_DIV_3);
+	save->ppll_ref_div = INPLL(PPLL_REF_DIV);
+}
+
+
+static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs *mode)
+{
+	int i;
+
+	radeon_fifo_wait(20);
+
+	/* Workaround from XFree */
+	if (rinfo->is_mobility) {
+	        /* A temporal workaround for the occational blanking on certain laptop
+		 * panels. This appears to related to the PLL divider registers
+		 * (fail to lock?). It occurs even when all dividers are the same
+		 * with their old settings. In this case we really don't need to
+		 * fiddle with PLL registers. By doing this we can avoid the blanking
+		 * problem with some panels.
+	         */
+		if ((mode->ppll_ref_div == (INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK)) &&
+		    (mode->ppll_div_3 == (INPLL(PPLL_DIV_3) &
+					  (PPLL_POST3_DIV_MASK | PPLL_FB3_DIV_MASK)))) {
+			/* We still have to force a switch to selected PPLL div thanks to
+			 * an XFree86 driver bug which will switch it away in some cases
+			 * even when using UseFDev */
+			OUTREGP(CLOCK_CNTL_INDEX,
+				mode->clk_cntl_index & PPLL_DIV_SEL_MASK,
+				~PPLL_DIV_SEL_MASK);
+			radeon_pll_errata_after_index(rinfo);
+			radeon_pll_errata_after_data(rinfo);
+            		return;
+		}
+	}
+
+	/* Swich VCKL clock input to CPUCLK so it stays fed while PPLL updates*/
+	OUTPLLP(VCLK_ECP_CNTL, VCLK_SRC_SEL_CPUCLK, ~VCLK_SRC_SEL_MASK);
+
+	/* Reset PPLL & enable atomic update */
+	OUTPLLP(PPLL_CNTL,
+		PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN,
+		~(PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN));
+
+	/* Switch to selected PPLL divider */
+	OUTREGP(CLOCK_CNTL_INDEX,
+		mode->clk_cntl_index & PPLL_DIV_SEL_MASK,
+		~PPLL_DIV_SEL_MASK);
+	radeon_pll_errata_after_index(rinfo);
+	radeon_pll_errata_after_data(rinfo);
+
+	/* Set PPLL ref. div */
+	if (rinfo->family == CHIP_FAMILY_R300 ||
+	    rinfo->family == CHIP_FAMILY_RS300 ||
+	    rinfo->family == CHIP_FAMILY_R350 ||
+	    rinfo->family == CHIP_FAMILY_RV350) {
+		if (mode->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) {
+			/* When restoring console mode, use saved PPLL_REF_DIV
+			 * setting.
+			 */
+			OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, 0);
+		} else {
+			/* R300 uses ref_div_acc field as real ref divider */
+			OUTPLLP(PPLL_REF_DIV,
+				(mode->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT), 
+				~R300_PPLL_REF_DIV_ACC_MASK);
+		}
+	} else
+		OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, ~PPLL_REF_DIV_MASK);
+
+	/* Set PPLL divider 3 & post divider*/
+	OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_FB3_DIV_MASK);
+	OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_POST3_DIV_MASK);
+
+	/* Write update */
+	while (INPLL(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R)
+		;
+	OUTPLLP(PPLL_REF_DIV, PPLL_ATOMIC_UPDATE_W, ~PPLL_ATOMIC_UPDATE_W);
+
+	/* Wait read update complete */
+	/* FIXME: Certain revisions of R300 can't recover here.  Not sure of
+	   the cause yet, but this workaround will mask the problem for now.
+	   Other chips usually will pass at the very first test, so the
+	   workaround shouldn't have any effect on them. */
+	for (i = 0; (i < 10000 && INPLL(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R); i++)
+		;
+	
+	OUTPLL(HTOTAL_CNTL, 0);
+
+	/* Clear reset & atomic update */
+	OUTPLLP(PPLL_CNTL, 0,
+		~(PPLL_RESET | PPLL_SLEEP | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN));
+
+	/* We may want some locking ... oh well */
+       	radeon_msleep(5);
+
+	/* Switch back VCLK source to PPLL */
+	OUTPLLP(VCLK_ECP_CNTL, VCLK_SRC_SEL_PPLLCLK, ~VCLK_SRC_SEL_MASK);
+}
+
+/*
+ * Timer function for delayed LVDS panel power up/down
+ */
+static void radeon_lvds_timer_func(unsigned long data)
+{
+	struct radeonfb_info *rinfo = (struct radeonfb_info *)data;
+
+	radeon_engine_idle();
+
+	OUTREG(LVDS_GEN_CNTL, rinfo->pending_lvds_gen_cntl);
+}
+
+/*
+ * Apply a video mode. This will apply the whole register set, including
+ * the PLL registers, to the card
+ */
+void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode,
+			int regs_only)
+{
+	int i;
+	int primary_mon = PRIMARY_MONITOR(rinfo);
+
+	if (nomodeset)
+		return;
+
+	if (!regs_only)
+		radeon_screen_blank(rinfo, FB_BLANK_NORMAL, 0);
+
+	radeon_fifo_wait(31);
+	for (i=0; i<10; i++)
+		OUTREG(common_regs[i].reg, common_regs[i].val);
+
+	/* Apply surface registers */
+	for (i=0; i<8; i++) {
+		OUTREG(SURFACE0_LOWER_BOUND + 0x10*i, mode->surf_lower_bound[i]);
+		OUTREG(SURFACE0_UPPER_BOUND + 0x10*i, mode->surf_upper_bound[i]);
+		OUTREG(SURFACE0_INFO + 0x10*i, mode->surf_info[i]);
+	}
+
+	OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl);
+	OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl,
+		~(CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS));
+	OUTREG(CRTC_MORE_CNTL, mode->crtc_more_cntl);
+	OUTREGP(DAC_CNTL, mode->dac_cntl, DAC_RANGE_CNTL | DAC_BLANKING);
+	OUTREG(CRTC_H_TOTAL_DISP, mode->crtc_h_total_disp);
+	OUTREG(CRTC_H_SYNC_STRT_WID, mode->crtc_h_sync_strt_wid);
+	OUTREG(CRTC_V_TOTAL_DISP, mode->crtc_v_total_disp);
+	OUTREG(CRTC_V_SYNC_STRT_WID, mode->crtc_v_sync_strt_wid);
+	OUTREG(CRTC_OFFSET, 0);
+	OUTREG(CRTC_OFFSET_CNTL, 0);
+	OUTREG(CRTC_PITCH, mode->crtc_pitch);
+	OUTREG(SURFACE_CNTL, mode->surface_cntl);
+
+	radeon_write_pll_regs(rinfo, mode);
+
+	if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {
+		radeon_fifo_wait(10);
+		OUTREG(FP_CRTC_H_TOTAL_DISP, mode->fp_crtc_h_total_disp);
+		OUTREG(FP_CRTC_V_TOTAL_DISP, mode->fp_crtc_v_total_disp);
+		OUTREG(FP_H_SYNC_STRT_WID, mode->fp_h_sync_strt_wid);
+		OUTREG(FP_V_SYNC_STRT_WID, mode->fp_v_sync_strt_wid);
+		OUTREG(FP_HORZ_STRETCH, mode->fp_horz_stretch);
+		OUTREG(FP_VERT_STRETCH, mode->fp_vert_stretch);
+		OUTREG(FP_GEN_CNTL, mode->fp_gen_cntl);
+		OUTREG(TMDS_CRC, mode->tmds_crc);
+		OUTREG(TMDS_TRANSMITTER_CNTL, mode->tmds_transmitter_cntl);
+	}
+
+	if (!regs_only)
+		radeon_screen_blank(rinfo, FB_BLANK_UNBLANK, 0);
+
+	radeon_fifo_wait(2);
+	OUTPLL(VCLK_ECP_CNTL, mode->vclk_ecp_cntl);
+	
+	return;
+}
+
+/*
+ * Calculate the PLL values for a given mode
+ */
+static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs *regs,
+				 unsigned long freq)
+{
+	const struct {
+		int divider;
+		int bitvalue;
+	} *post_div,
+	  post_divs[] = {
+		{ 1,  0 },
+		{ 2,  1 },
+		{ 4,  2 },
+		{ 8,  3 },
+		{ 3,  4 },
+		{ 16, 5 },
+		{ 6,  6 },
+		{ 12, 7 },
+		{ 0,  0 },
+	};
+	int fb_div, pll_output_freq = 0;
+	int uses_dvo = 0;
+
+	/* Check if the DVO port is enabled and sourced from the primary CRTC. I'm
+	 * not sure which model starts having FP2_GEN_CNTL, I assume anything more
+	 * recent than an r(v)100...
+	 */
+#if 1
+	/* XXX I had reports of flicker happening with the cinema display
+	 * on TMDS1 that seem to be fixed if I also forbit odd dividers in
+	 * this case. This could just be a bandwidth calculation issue, I
+	 * haven't implemented the bandwidth code yet, but in the meantime,
+	 * forcing uses_dvo to 1 fixes it and shouln't have bad side effects,
+	 * I haven't seen a case were were absolutely needed an odd PLL
+	 * divider. I'll find a better fix once I have more infos on the
+	 * real cause of the problem.
+	 */
+	while (rinfo->has_CRTC2) {
+		u32 fp2_gen_cntl = INREG(FP2_GEN_CNTL);
+		u32 disp_output_cntl;
+		int source;
+
+		/* FP2 path not enabled */
+		if ((fp2_gen_cntl & FP2_ON) == 0)
+			break;
+		/* Not all chip revs have the same format for this register,
+		 * extract the source selection
+		 */
+		if (rinfo->family == CHIP_FAMILY_R200 ||
+		    rinfo->family == CHIP_FAMILY_R300 ||
+		    rinfo->family == CHIP_FAMILY_R350 ||
+		    rinfo->family == CHIP_FAMILY_RV350) {
+			source = (fp2_gen_cntl >> 10) & 0x3;
+			/* sourced from transform unit, check for transform unit
+			 * own source
+			 */
+			if (source == 3) {
+				disp_output_cntl = INREG(DISP_OUTPUT_CNTL);
+				source = (disp_output_cntl >> 12) & 0x3;
+			}
+		} else
+			source = (fp2_gen_cntl >> 13) & 0x1;
+		/* sourced from CRTC2 -> exit */
+		if (source == 1)
+			break;
+
+		/* so we end up on CRTC1, let's set uses_dvo to 1 now */
+		uses_dvo = 1;
+		break;
+	}
+#else
+	uses_dvo = 1;
+#endif
+	if (freq > rinfo->pll.ppll_max)
+		freq = rinfo->pll.ppll_max;
+	if (freq*12 < rinfo->pll.ppll_min)
+		freq = rinfo->pll.ppll_min / 12;
+	RTRACE("freq = %lu, PLL min = %u, PLL max = %u\n",
+	       freq, rinfo->pll.ppll_min, rinfo->pll.ppll_max);
+
+	for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
+		pll_output_freq = post_div->divider * freq;
+		/* If we output to the DVO port (external TMDS), we don't allow an
+		 * odd PLL divider as those aren't supported on this path
+		 */
+		if (uses_dvo && (post_div->divider & 1))
+			continue;
+		if (pll_output_freq >= rinfo->pll.ppll_min  &&
+		    pll_output_freq <= rinfo->pll.ppll_max)
+			break;
+	}
+
+	/* If we fall through the bottom, try the "default value"
+	   given by the terminal post_div->bitvalue */
+	if ( !post_div->divider ) {
+		post_div = &post_divs[post_div->bitvalue];
+		pll_output_freq = post_div->divider * freq;
+	}
+	RTRACE("ref_div = %d, ref_clk = %d, output_freq = %d\n",
+	       rinfo->pll.ref_div, rinfo->pll.ref_clk,
+	       pll_output_freq);
+
+	/* If we fall through the bottom, try the "default value"
+	   given by the terminal post_div->bitvalue */
+	if ( !post_div->divider ) {
+		post_div = &post_divs[post_div->bitvalue];
+		pll_output_freq = post_div->divider * freq;
+	}
+	RTRACE("ref_div = %d, ref_clk = %d, output_freq = %d\n",
+	       rinfo->pll.ref_div, rinfo->pll.ref_clk,
+	       pll_output_freq);
+
+	fb_div = round_div(rinfo->pll.ref_div*pll_output_freq,
+				  rinfo->pll.ref_clk);
+	regs->ppll_ref_div = rinfo->pll.ref_div;
+	regs->ppll_div_3 = fb_div | (post_div->bitvalue << 16);
+
+	RTRACE("post div = 0x%x\n", post_div->bitvalue);
+	RTRACE("fb_div = 0x%x\n", fb_div);
+	RTRACE("ppll_div_3 = 0x%x\n", regs->ppll_div_3);
+}
+
+static int radeonfb_set_par(struct fb_info *info)
+{
+	struct radeonfb_info *rinfo = info->par;
+	struct fb_var_screeninfo *mode = &info->var;
+	struct radeon_regs *newmode;
+	int hTotal, vTotal, hSyncStart, hSyncEnd,
+	    hSyncPol, vSyncStart, vSyncEnd, vSyncPol, cSync;
+	u8 hsync_adj_tab[] = {0, 0x12, 9, 9, 6, 5};
+	u8 hsync_fudge_fp[] = {2, 2, 0, 0, 5, 5};
+	u32 sync, h_sync_pol, v_sync_pol, dotClock, pixClock;
+	int i, freq;
+	int format = 0;
+	int nopllcalc = 0;
+	int hsync_start, hsync_fudge, bytpp, hsync_wid, vsync_wid;
+	int primary_mon = PRIMARY_MONITOR(rinfo);
+	int depth = var_to_depth(mode);
+	int use_rmx = 0;
+
+	newmode = kmalloc(sizeof(struct radeon_regs), GFP_KERNEL);
+	if (!newmode)
+		return -ENOMEM;
+
+	/* We always want engine to be idle on a mode switch, even
+	 * if we won't actually change the mode
+	 */
+	radeon_engine_idle();
+
+	hSyncStart = mode->xres + mode->right_margin;
+	hSyncEnd = hSyncStart + mode->hsync_len;
+	hTotal = hSyncEnd + mode->left_margin;
+
+	vSyncStart = mode->yres + mode->lower_margin;
+	vSyncEnd = vSyncStart + mode->vsync_len;
+	vTotal = vSyncEnd + mode->upper_margin;
+	pixClock = mode->pixclock;
+
+	sync = mode->sync;
+	h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
+	v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;
+
+	if (primary_mon == MT_DFP || primary_mon == MT_LCD) {
+		if (rinfo->panel_info.xres < mode->xres)
+			mode->xres = rinfo->panel_info.xres;
+		if (rinfo->panel_info.yres < mode->yres)
+			mode->yres = rinfo->panel_info.yres;
+
+		hTotal = mode->xres + rinfo->panel_info.hblank;
+		hSyncStart = mode->xres + rinfo->panel_info.hOver_plus;
+		hSyncEnd = hSyncStart + rinfo->panel_info.hSync_width;
+
+		vTotal = mode->yres + rinfo->panel_info.vblank;
+		vSyncStart = mode->yres + rinfo->panel_info.vOver_plus;
+		vSyncEnd = vSyncStart + rinfo->panel_info.vSync_width;
+
+		h_sync_pol = !rinfo->panel_info.hAct_high;
+		v_sync_pol = !rinfo->panel_info.vAct_high;
+
+		pixClock = 100000000 / rinfo->panel_info.clock;
+
+		if (rinfo->panel_info.use_bios_dividers) {
+			nopllcalc = 1;
+			newmode->ppll_div_3 = rinfo->panel_info.fbk_divider |
+				(rinfo->panel_info.post_divider << 16);
+			newmode->ppll_ref_div = rinfo->panel_info.ref_divider;
+		}
+	}
+	dotClock = 1000000000 / pixClock;
+	freq = dotClock / 10; /* x100 */
+
+	RTRACE("hStart = %d, hEnd = %d, hTotal = %d\n",
+		hSyncStart, hSyncEnd, hTotal);
+	RTRACE("vStart = %d, vEnd = %d, vTotal = %d\n",
+		vSyncStart, vSyncEnd, vTotal);
+
+	hsync_wid = (hSyncEnd - hSyncStart) / 8;
+	vsync_wid = vSyncEnd - vSyncStart;
+	if (hsync_wid == 0)
+		hsync_wid = 1;
+	else if (hsync_wid > 0x3f)	/* max */
+		hsync_wid = 0x3f;
+
+	if (vsync_wid == 0)
+		vsync_wid = 1;
+	else if (vsync_wid > 0x1f)	/* max */
+		vsync_wid = 0x1f;
+
+	hSyncPol = mode->sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
+	vSyncPol = mode->sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;
+
+	cSync = mode->sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0;
+
+	format = radeon_get_dstbpp(depth);
+	bytpp = mode->bits_per_pixel >> 3;
+
+	if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD))
+		hsync_fudge = hsync_fudge_fp[format-1];
+	else
+		hsync_fudge = hsync_adj_tab[format-1];
+
+	hsync_start = hSyncStart - 8 + hsync_fudge;
+
+	newmode->crtc_gen_cntl = CRTC_EXT_DISP_EN | CRTC_EN |
+				(format << 8);
+
+	/* Clear auto-center etc... */
+	newmode->crtc_more_cntl = rinfo->init_state.crtc_more_cntl;
+	newmode->crtc_more_cntl &= 0xfffffff0;
+	
+	if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {
+		newmode->crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN;
+		if (mirror)
+			newmode->crtc_ext_cntl |= CRTC_CRT_ON;
+
+		newmode->crtc_gen_cntl &= ~(CRTC_DBL_SCAN_EN |
+					   CRTC_INTERLACE_EN);
+	} else {
+		newmode->crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN |
+					CRTC_CRT_ON;
+	}
+
+	newmode->dac_cntl = /* INREG(DAC_CNTL) | */ DAC_MASK_ALL | DAC_VGA_ADR_EN |
+			   DAC_8BIT_EN;
+
+	newmode->crtc_h_total_disp = ((((hTotal / 8) - 1) & 0x3ff) |
+				     (((mode->xres / 8) - 1) << 16));
+
+	newmode->crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) |
+					(hsync_wid << 16) | (h_sync_pol << 23));
+
+	newmode->crtc_v_total_disp = ((vTotal - 1) & 0xffff) |
+				    ((mode->yres - 1) << 16);
+
+	newmode->crtc_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff) |
+					 (vsync_wid << 16) | (v_sync_pol  << 23));
+
+	if (!(info->flags & FBINFO_HWACCEL_DISABLED)) {
+		/* We first calculate the engine pitch */
+		rinfo->pitch = ((mode->xres_virtual * ((mode->bits_per_pixel + 1) / 8) + 0x3f)
+ 				& ~(0x3f)) >> 6;
+
+		/* Then, re-multiply it to get the CRTC pitch */
+		newmode->crtc_pitch = (rinfo->pitch << 3) / ((mode->bits_per_pixel + 1) / 8);
+	} else
+		newmode->crtc_pitch = (mode->xres_virtual >> 3);
+
+	newmode->crtc_pitch |= (newmode->crtc_pitch << 16);
+
+	/*
+	 * It looks like recent chips have a problem with SURFACE_CNTL,
+	 * setting SURF_TRANSLATION_DIS completely disables the
+	 * swapper as well, so we leave it unset now.
+	 */
+	newmode->surface_cntl = 0;
+
+#if defined(__BIG_ENDIAN)
+
+	/* Setup swapping on both apertures, though we currently
+	 * only use aperture 0, enabling swapper on aperture 1
+	 * won't harm
+	 */
+	switch (mode->bits_per_pixel) {
+		case 16:
+			newmode->surface_cntl |= NONSURF_AP0_SWP_16BPP;
+			newmode->surface_cntl |= NONSURF_AP1_SWP_16BPP;
+			break;
+		case 24:	
+		case 32:
+			newmode->surface_cntl |= NONSURF_AP0_SWP_32BPP;
+			newmode->surface_cntl |= NONSURF_AP1_SWP_32BPP;
+			break;
+	}
+#endif
+
+	/* Clear surface registers */
+	for (i=0; i<8; i++) {
+		newmode->surf_lower_bound[i] = 0;
+		newmode->surf_upper_bound[i] = 0x1f;
+		newmode->surf_info[i] = 0;
+	}
+
+	RTRACE("h_total_disp = 0x%x\t   hsync_strt_wid = 0x%x\n",
+		newmode->crtc_h_total_disp, newmode->crtc_h_sync_strt_wid);
+	RTRACE("v_total_disp = 0x%x\t   vsync_strt_wid = 0x%x\n",
+		newmode->crtc_v_total_disp, newmode->crtc_v_sync_strt_wid);
+
+	rinfo->bpp = mode->bits_per_pixel;
+	rinfo->depth = depth;
+
+	RTRACE("pixclock = %lu\n", (unsigned long)pixClock);
+	RTRACE("freq = %lu\n", (unsigned long)freq);
+
+	/* We use PPLL_DIV_3 */
+	newmode->clk_cntl_index = 0x300;
+
+	/* Calculate PPLL value if necessary */
+	if (!nopllcalc)
+		radeon_calc_pll_regs(rinfo, newmode, freq);
+
+	newmode->vclk_ecp_cntl = rinfo->init_state.vclk_ecp_cntl;
+
+	if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {
+		unsigned int hRatio, vRatio;
+
+		if (mode->xres > rinfo->panel_info.xres)
+			mode->xres = rinfo->panel_info.xres;
+		if (mode->yres > rinfo->panel_info.yres)
+			mode->yres = rinfo->panel_info.yres;
+
+		newmode->fp_horz_stretch = (((rinfo->panel_info.xres / 8) - 1)
+					   << HORZ_PANEL_SHIFT);
+		newmode->fp_vert_stretch = ((rinfo->panel_info.yres - 1)
+					   << VERT_PANEL_SHIFT);
+
+		if (mode->xres != rinfo->panel_info.xres) {
+			hRatio = round_div(mode->xres * HORZ_STRETCH_RATIO_MAX,
+					   rinfo->panel_info.xres);
+			newmode->fp_horz_stretch = (((((unsigned long)hRatio) & HORZ_STRETCH_RATIO_MASK)) |
+						   (newmode->fp_horz_stretch &
+						    (HORZ_PANEL_SIZE | HORZ_FP_LOOP_STRETCH |
+						     HORZ_AUTO_RATIO_INC)));
+			newmode->fp_horz_stretch |= (HORZ_STRETCH_BLEND |
+						    HORZ_STRETCH_ENABLE);
+			use_rmx = 1;
+		}
+		newmode->fp_horz_stretch &= ~HORZ_AUTO_RATIO;
+
+		if (mode->yres != rinfo->panel_info.yres) {
+			vRatio = round_div(mode->yres * VERT_STRETCH_RATIO_MAX,
+					   rinfo->panel_info.yres);
+			newmode->fp_vert_stretch = (((((unsigned long)vRatio) & VERT_STRETCH_RATIO_MASK)) |
+						   (newmode->fp_vert_stretch &
+						   (VERT_PANEL_SIZE | VERT_STRETCH_RESERVED)));
+			newmode->fp_vert_stretch |= (VERT_STRETCH_BLEND |
+						    VERT_STRETCH_ENABLE);
+			use_rmx = 1;
+		}
+		newmode->fp_vert_stretch &= ~VERT_AUTO_RATIO_EN;
+
+		newmode->fp_gen_cntl = (rinfo->init_state.fp_gen_cntl & (u32)
+				       ~(FP_SEL_CRTC2 |
+					 FP_RMX_HVSYNC_CONTROL_EN |
+					 FP_DFP_SYNC_SEL |
+					 FP_CRT_SYNC_SEL |
+					 FP_CRTC_LOCK_8DOT |
+					 FP_USE_SHADOW_EN |
+					 FP_CRTC_USE_SHADOW_VEND |
+					 FP_CRT_SYNC_ALT));
+
+		newmode->fp_gen_cntl |= (FP_CRTC_DONT_SHADOW_VPAR |
+					FP_CRTC_DONT_SHADOW_HEND |
+					FP_PANEL_FORMAT);
+
+		if (IS_R300_VARIANT(rinfo) ||
+		    (rinfo->family == CHIP_FAMILY_R200)) {
+			newmode->fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK;
+			if (use_rmx)
+				newmode->fp_gen_cntl |= R200_FP_SOURCE_SEL_RMX;
+			else
+				newmode->fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC1;
+		} else
+			newmode->fp_gen_cntl |= FP_SEL_CRTC1;
+
+		newmode->lvds_gen_cntl = rinfo->init_state.lvds_gen_cntl;
+		newmode->lvds_pll_cntl = rinfo->init_state.lvds_pll_cntl;
+		newmode->tmds_crc = rinfo->init_state.tmds_crc;
+		newmode->tmds_transmitter_cntl = rinfo->init_state.tmds_transmitter_cntl;
+
+		if (primary_mon == MT_LCD) {
+			newmode->lvds_gen_cntl |= (LVDS_ON | LVDS_BLON);
+			newmode->fp_gen_cntl &= ~(FP_FPON | FP_TMDS_EN);
+		} else {
+			/* DFP */
+			newmode->fp_gen_cntl |= (FP_FPON | FP_TMDS_EN);
+			newmode->tmds_transmitter_cntl &= ~(TMDS_PLLRST);
+			/* TMDS_PLL_EN bit is reversed on RV (and mobility) chips */
+			if (IS_R300_VARIANT(rinfo) ||
+			    (rinfo->family == CHIP_FAMILY_R200) || !rinfo->has_CRTC2)
+				newmode->tmds_transmitter_cntl &= ~TMDS_PLL_EN;
+			else
+				newmode->tmds_transmitter_cntl |= TMDS_PLL_EN;
+			newmode->crtc_ext_cntl &= ~CRTC_CRT_ON;
+		}
+
+		newmode->fp_crtc_h_total_disp = (((rinfo->panel_info.hblank / 8) & 0x3ff) |
+				(((mode->xres / 8) - 1) << 16));
+		newmode->fp_crtc_v_total_disp = (rinfo->panel_info.vblank & 0xffff) |
+				((mode->yres - 1) << 16);
+		newmode->fp_h_sync_strt_wid = ((rinfo->panel_info.hOver_plus & 0x1fff) |
+				(hsync_wid << 16) | (h_sync_pol << 23));
+		newmode->fp_v_sync_strt_wid = ((rinfo->panel_info.vOver_plus & 0xfff) |
+				(vsync_wid << 16) | (v_sync_pol  << 23));
+	}
+
+	/* do it! */
+	if (!rinfo->asleep) {
+		memcpy(&rinfo->state, newmode, sizeof(*newmode));
+		radeon_write_mode (rinfo, newmode, 0);
+		/* (re)initialize the engine */
+		if (!(info->flags & FBINFO_HWACCEL_DISABLED))
+			radeonfb_engine_init (rinfo);
+	}
+	/* Update fix */
+	if (!(info->flags & FBINFO_HWACCEL_DISABLED))
+        	info->fix.line_length = rinfo->pitch*64;
+        else
+		info->fix.line_length = mode->xres_virtual
+			* ((mode->bits_per_pixel + 1) / 8);
+        info->fix.visual = rinfo->depth == 8 ? FB_VISUAL_PSEUDOCOLOR
+		: FB_VISUAL_DIRECTCOLOR;
+
+#ifdef CONFIG_BOOTX_TEXT
+	/* Update debug text engine */
+	btext_update_display(rinfo->fb_base_phys, mode->xres, mode->yres,
+			     rinfo->depth, info->fix.line_length);
+#endif
+
+	kfree(newmode);
+	return 0;
+}
+
+
+static struct fb_ops radeonfb_ops = {
+	.owner			= THIS_MODULE,
+	.fb_check_var		= radeonfb_check_var,
+	.fb_set_par		= radeonfb_set_par,
+	.fb_setcolreg		= radeonfb_setcolreg,
+	.fb_pan_display 	= radeonfb_pan_display,
+	.fb_blank		= radeonfb_blank,
+	.fb_ioctl		= radeonfb_ioctl,
+	.fb_sync		= radeonfb_sync,
+	.fb_fillrect		= radeonfb_fillrect,
+	.fb_copyarea		= radeonfb_copyarea,
+	.fb_imageblit		= radeonfb_imageblit,
+	.fb_cursor		= soft_cursor,
+};
+
+
+static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo)
+{
+	struct fb_info *info = rinfo->info;
+
+	info->par = rinfo;
+	info->pseudo_palette = rinfo->pseudo_palette;
+	info->flags = FBINFO_DEFAULT
+		    | FBINFO_HWACCEL_COPYAREA
+		    | FBINFO_HWACCEL_FILLRECT
+		    | FBINFO_HWACCEL_XPAN
+		    | FBINFO_HWACCEL_YPAN;
+	info->fbops = &radeonfb_ops;
+	info->screen_base = rinfo->fb_base;
+	info->screen_size = rinfo->mapped_vram;
+	/* Fill fix common fields */
+	strlcpy(info->fix.id, rinfo->name, sizeof(info->fix.id));
+        info->fix.smem_start = rinfo->fb_base_phys;
+        info->fix.smem_len = rinfo->video_ram;
+        info->fix.type = FB_TYPE_PACKED_PIXELS;
+        info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+        info->fix.xpanstep = 8;
+        info->fix.ypanstep = 1;
+        info->fix.ywrapstep = 0;
+        info->fix.type_aux = 0;
+        info->fix.mmio_start = rinfo->mmio_base_phys;
+        info->fix.mmio_len = RADEON_REGSIZE;
+	info->fix.accel = FB_ACCEL_ATI_RADEON;
+
+	fb_alloc_cmap(&info->cmap, 256, 0);
+
+	if (noaccel)
+		info->flags |= FBINFO_HWACCEL_DISABLED;
+
+        return 0;
+}
+
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+
+/* TODO: Dbl check these tables, we don't go up to full ON backlight
+ * in these, possibly because we noticed MacOS doesn't, but I'd prefer
+ * having some more official numbers from ATI
+ */
+static int backlight_conv_m6[] = {
+	0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e,
+	0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
+};
+static int backlight_conv_m7[] = {
+	0x00, 0x3f, 0x4a, 0x55, 0x60, 0x6b, 0x76, 0x81,
+	0x8c, 0x97, 0xa2, 0xad, 0xb8, 0xc3, 0xce, 0xd9
+};
+
+#define BACKLIGHT_LVDS_OFF
+#undef BACKLIGHT_DAC_OFF
+
+/* We turn off the LCD completely instead of just dimming the backlight.
+ * This provides some greater power saving and the display is useless
+ * without backlight anyway.
+ */
+static int radeon_set_backlight_enable(int on, int level, void *data)
+{
+	struct radeonfb_info *rinfo = (struct radeonfb_info *)data;
+	u32 lvds_gen_cntl, tmpPixclksCntl;
+	int* conv_table;
+
+	if (rinfo->mon1_type != MT_LCD)
+		return 0;
+
+	/* Pardon me for that hack... maybe some day we can figure
+	 * out in what direction backlight should work on a given
+	 * panel ?
+	 */
+	if ((rinfo->family == CHIP_FAMILY_RV200 ||
+	     rinfo->family == CHIP_FAMILY_RV250 ||
+	     rinfo->family == CHIP_FAMILY_RV280 ||
+	     rinfo->family == CHIP_FAMILY_RV350) &&
+	    !machine_is_compatible("PowerBook4,3") &&
+	    !machine_is_compatible("PowerBook6,3") &&
+	    !machine_is_compatible("PowerBook6,5"))
+		conv_table = backlight_conv_m7;
+	else
+		conv_table = backlight_conv_m6;
+
+	del_timer_sync(&rinfo->lvds_timer);
+	radeon_engine_idle();
+
+	lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
+	if (on && (level > BACKLIGHT_OFF)) {
+		lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
+		if (!(lvds_gen_cntl & LVDS_BLON) || !(lvds_gen_cntl & LVDS_ON)) {
+			lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON);
+			lvds_gen_cntl |= LVDS_BLON | LVDS_EN;
+			OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+			lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
+			lvds_gen_cntl |= (conv_table[level] <<
+					  LVDS_BL_MOD_LEVEL_SHIFT);
+			lvds_gen_cntl |= LVDS_ON;
+			lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN);
+			rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
+			mod_timer(&rinfo->lvds_timer,
+				  jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
+		} else {
+			lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
+			lvds_gen_cntl |= (conv_table[level] <<
+					  LVDS_BL_MOD_LEVEL_SHIFT);
+			OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+		}
+		rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
+		rinfo->init_state.lvds_gen_cntl |= rinfo->pending_lvds_gen_cntl
+			& LVDS_STATE_MASK;
+	} else {
+		/* Asic bug, when turning off LVDS_ON, we have to make sure
+		   RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
+		*/
+		tmpPixclksCntl = INPLL(PIXCLKS_CNTL);
+		if (rinfo->is_mobility || rinfo->is_IGP)
+			OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
+		lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN);
+		lvds_gen_cntl |= (conv_table[0] <<
+				  LVDS_BL_MOD_LEVEL_SHIFT);
+		lvds_gen_cntl |= LVDS_DISPLAY_DIS;
+		OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+		udelay(100);
+		lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN);
+		OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+		lvds_gen_cntl &= ~(LVDS_DIGON);
+		rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
+		mod_timer(&rinfo->lvds_timer,
+			  jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
+		if (rinfo->is_mobility || rinfo->is_IGP)
+			OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl);
+	}
+	rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
+	rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK);
+
+	return 0;
+}
+
+
+static int radeon_set_backlight_level(int level, void *data)
+{
+	return radeon_set_backlight_enable(1, level, data);
+}
+#endif /* CONFIG_PMAC_BACKLIGHT */
+
+
+/*
+ * This reconfigure the card's internal memory map. In theory, we'd like
+ * to setup the card's memory at the same address as it's PCI bus address,
+ * and the AGP aperture right after that so that system RAM on 32 bits
+ * machines at least, is directly accessible. However, doing so would
+ * conflict with the current XFree drivers...
+ * Ultimately, I hope XFree, GATOS and ATI binary drivers will all agree
+ * on the proper way to set this up and duplicate this here. In the meantime,
+ * I put the card's memory at 0 in card space and AGP at some random high
+ * local (0xe0000000 for now) that will be changed by XFree/DRI anyway
+ */
+#ifdef CONFIG_PPC_OF
+#undef SET_MC_FB_FROM_APERTURE
+static void fixup_memory_mappings(struct radeonfb_info *rinfo)
+{
+	u32 save_crtc_gen_cntl, save_crtc2_gen_cntl = 0;
+	u32 save_crtc_ext_cntl;
+	u32 aper_base, aper_size;
+	u32 agp_base;
+
+	/* First, we disable display to avoid interfering */
+	if (rinfo->has_CRTC2) {
+		save_crtc2_gen_cntl = INREG(CRTC2_GEN_CNTL);
+		OUTREG(CRTC2_GEN_CNTL, save_crtc2_gen_cntl | CRTC2_DISP_REQ_EN_B);
+	}
+	save_crtc_gen_cntl = INREG(CRTC_GEN_CNTL);
+	save_crtc_ext_cntl = INREG(CRTC_EXT_CNTL);
+	
+	OUTREG(CRTC_EXT_CNTL, save_crtc_ext_cntl | CRTC_DISPLAY_DIS);
+	OUTREG(CRTC_GEN_CNTL, save_crtc_gen_cntl | CRTC_DISP_REQ_EN_B);
+	mdelay(100);
+
+	aper_base = INREG(CONFIG_APER_0_BASE);
+	aper_size = INREG(CONFIG_APER_SIZE);
+
+#ifdef SET_MC_FB_FROM_APERTURE
+	/* Set framebuffer to be at the same address as set in PCI BAR */
+	OUTREG(MC_FB_LOCATION, 
+		((aper_base + aper_size - 1) & 0xffff0000) | (aper_base >> 16));
+	rinfo->fb_local_base = aper_base;
+#else
+	OUTREG(MC_FB_LOCATION, 0x7fff0000);
+	rinfo->fb_local_base = 0;
+#endif
+	agp_base = aper_base + aper_size;
+	if (agp_base & 0xf0000000)
+		agp_base = (aper_base | 0x0fffffff) + 1;
+
+	/* Set AGP to be just after the framebuffer on a 256Mb boundary. This
+	 * assumes the FB isn't mapped to 0xf0000000 or above, but this is
+	 * always the case on PPCs afaik.
+	 */
+#ifdef SET_MC_FB_FROM_APERTURE
+	OUTREG(MC_AGP_LOCATION, 0xffff0000 | (agp_base >> 16));
+#else
+	OUTREG(MC_AGP_LOCATION, 0xffffe000);
+#endif
+
+	/* Fixup the display base addresses & engine offsets while we
+	 * are at it as well
+	 */
+#ifdef SET_MC_FB_FROM_APERTURE
+	OUTREG(DISPLAY_BASE_ADDR, aper_base);
+	if (rinfo->has_CRTC2)
+		OUTREG(CRTC2_DISPLAY_BASE_ADDR, aper_base);
+	OUTREG(OV0_BASE_ADDR, aper_base);
+#else
+	OUTREG(DISPLAY_BASE_ADDR, 0);
+	if (rinfo->has_CRTC2)
+		OUTREG(CRTC2_DISPLAY_BASE_ADDR, 0);
+	OUTREG(OV0_BASE_ADDR, 0);
+#endif
+	mdelay(100);
+
+	/* Restore display settings */
+	OUTREG(CRTC_GEN_CNTL, save_crtc_gen_cntl);
+	OUTREG(CRTC_EXT_CNTL, save_crtc_ext_cntl);
+	if (rinfo->has_CRTC2)
+		OUTREG(CRTC2_GEN_CNTL, save_crtc2_gen_cntl);	
+
+	RTRACE("aper_base: %08x MC_FB_LOC to: %08x, MC_AGP_LOC to: %08x\n",
+		aper_base,
+		((aper_base + aper_size - 1) & 0xffff0000) | (aper_base >> 16),
+		0xffff0000 | (agp_base >> 16));
+}
+#endif /* CONFIG_PPC_OF */
+
+
+static void radeon_identify_vram(struct radeonfb_info *rinfo)
+{
+	u32 tmp;
+
+	/* framebuffer size */
+        if ((rinfo->family == CHIP_FAMILY_RS100) ||
+            (rinfo->family == CHIP_FAMILY_RS200) ||
+            (rinfo->family == CHIP_FAMILY_RS300)) {
+          u32 tom = INREG(NB_TOM);
+          tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024);
+
+ 		radeon_fifo_wait(6);
+          OUTREG(MC_FB_LOCATION, tom);
+          OUTREG(DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
+          OUTREG(CRTC2_DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
+          OUTREG(OV0_BASE_ADDR, (tom & 0xffff) << 16);
+
+          /* This is supposed to fix the crtc2 noise problem. */
+          OUTREG(GRPH2_BUFFER_CNTL, INREG(GRPH2_BUFFER_CNTL) & ~0x7f0000);
+
+          if ((rinfo->family == CHIP_FAMILY_RS100) ||
+              (rinfo->family == CHIP_FAMILY_RS200)) {
+             /* This is to workaround the asic bug for RMX, some versions
+                of BIOS dosen't have this register initialized correctly.
+             */
+             OUTREGP(CRTC_MORE_CNTL, CRTC_H_CUTOFF_ACTIVE_EN,
+                     ~CRTC_H_CUTOFF_ACTIVE_EN);
+          }
+        } else {
+          tmp = INREG(CONFIG_MEMSIZE);
+        }
+
+	/* mem size is bits [28:0], mask off the rest */
+	rinfo->video_ram = tmp & CONFIG_MEMSIZE_MASK;
+
+	/*
+	 * Hack to get around some busted production M6's
+	 * reporting no ram
+	 */
+	if (rinfo->video_ram == 0) {
+		switch (rinfo->pdev->device) {
+	       	case PCI_CHIP_RADEON_LY:
+		case PCI_CHIP_RADEON_LZ:
+	       		rinfo->video_ram = 8192 * 1024;
+	       		break;
+	       	default:
+	       		break;
+		}
+	}
+
+
+	/*
+	 * Now try to identify VRAM type
+	 */
+	if (rinfo->is_IGP || (rinfo->family >= CHIP_FAMILY_R300) ||
+	    (INREG(MEM_SDRAM_MODE_REG) & (1<<30)))
+		rinfo->vram_ddr = 1;
+	else
+		rinfo->vram_ddr = 0;
+
+	tmp = INREG(MEM_CNTL);
+	if (IS_R300_VARIANT(rinfo)) {
+		tmp &=  R300_MEM_NUM_CHANNELS_MASK;
+		switch (tmp) {
+		case 0:  rinfo->vram_width = 64; break;
+		case 1:  rinfo->vram_width = 128; break;
+		case 2:  rinfo->vram_width = 256; break;
+		default: rinfo->vram_width = 128; break;
+		}
+	} else if ((rinfo->family == CHIP_FAMILY_RV100) ||
+		   (rinfo->family == CHIP_FAMILY_RS100) ||
+		   (rinfo->family == CHIP_FAMILY_RS200)){
+		if (tmp & RV100_MEM_HALF_MODE)
+			rinfo->vram_width = 32;
+		else
+			rinfo->vram_width = 64;
+	} else {
+		if (tmp & MEM_NUM_CHANNELS_MASK)
+			rinfo->vram_width = 128;
+		else
+			rinfo->vram_width = 64;
+	}
+
+	/* This may not be correct, as some cards can have half of channel disabled
+	 * ToDo: identify these cases
+	 */
+
+	RTRACE("radeonfb (%s): Found %ldk of %s %d bits wide videoram\n",
+	       pci_name(rinfo->pdev),
+	       rinfo->video_ram / 1024,
+	       rinfo->vram_ddr ? "DDR" : "SDRAM",
+	       rinfo->vram_width);
+}
+
+/*
+ * Sysfs
+ */
+
+static ssize_t radeon_show_one_edid(char *buf, loff_t off, size_t count, const u8 *edid)
+{
+	if (off > EDID_LENGTH)
+		return 0;
+
+	if (off + count > EDID_LENGTH)
+		count = EDID_LENGTH - off;
+
+	memcpy(buf, edid + off, count);
+
+	return count;
+}
+
+
+static ssize_t radeon_show_edid1(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct pci_dev *pdev = to_pci_dev(dev);
+        struct fb_info *info = pci_get_drvdata(pdev);
+        struct radeonfb_info *rinfo = info->par;
+
+	return radeon_show_one_edid(buf, off, count, rinfo->mon1_EDID);
+}
+
+
+static ssize_t radeon_show_edid2(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct pci_dev *pdev = to_pci_dev(dev);
+        struct fb_info *info = pci_get_drvdata(pdev);
+        struct radeonfb_info *rinfo = info->par;
+
+	return radeon_show_one_edid(buf, off, count, rinfo->mon2_EDID);
+}
+
+static struct bin_attribute edid1_attr = {
+	.attr   = {
+		.name	= "edid1",
+		.owner	= THIS_MODULE,
+		.mode	= 0444,
+	},
+	.size	= EDID_LENGTH,
+	.read	= radeon_show_edid1,
+};
+
+static struct bin_attribute edid2_attr = {
+	.attr   = {
+		.name	= "edid2",
+		.owner	= THIS_MODULE,
+		.mode	= 0444,
+	},
+	.size	= EDID_LENGTH,
+	.read	= radeon_show_edid2,
+};
+
+
+static int radeonfb_pci_register (struct pci_dev *pdev,
+				  const struct pci_device_id *ent)
+{
+	struct fb_info *info;
+	struct radeonfb_info *rinfo;
+	int ret;
+
+	RTRACE("radeonfb_pci_register BEGIN\n");
+	
+	/* Enable device in PCI config */
+	ret = pci_enable_device(pdev);
+	if (ret < 0) {
+		printk(KERN_ERR "radeonfb (%s): Cannot enable PCI device\n",
+		       pci_name(pdev));
+		goto err_out;
+	}
+
+	info = framebuffer_alloc(sizeof(struct radeonfb_info), &pdev->dev);
+	if (!info) {
+		printk (KERN_ERR "radeonfb (%s): could not allocate memory\n",
+			pci_name(pdev));
+		ret = -ENOMEM;
+		goto err_disable;
+	}
+	rinfo = info->par;
+	rinfo->info = info;	
+	rinfo->pdev = pdev;
+	
+	spin_lock_init(&rinfo->reg_lock);
+	init_timer(&rinfo->lvds_timer);
+	rinfo->lvds_timer.function = radeon_lvds_timer_func;
+	rinfo->lvds_timer.data = (unsigned long)rinfo;
+
+	strcpy(rinfo->name, "ATI Radeon XX ");
+	rinfo->name[11] = ent->device >> 8;
+	rinfo->name[12] = ent->device & 0xFF;
+	rinfo->family = ent->driver_data & CHIP_FAMILY_MASK;
+	rinfo->chipset = pdev->device;
+	rinfo->has_CRTC2 = (ent->driver_data & CHIP_HAS_CRTC2) != 0;
+	rinfo->is_mobility = (ent->driver_data & CHIP_IS_MOBILITY) != 0;
+	rinfo->is_IGP = (ent->driver_data & CHIP_IS_IGP) != 0;
+
+	/* Set base addrs */
+	rinfo->fb_base_phys = pci_resource_start (pdev, 0);
+	rinfo->mmio_base_phys = pci_resource_start (pdev, 2);
+
+	/* request the mem regions */
+	ret = pci_request_regions(pdev, "radeonfb");
+	if (ret < 0) {
+		printk( KERN_ERR "radeonfb (%s): cannot reserve PCI regions."
+			"  Someone already got them?\n", pci_name(rinfo->pdev));
+		goto err_release_fb;
+	}
+
+	/* map the regions */
+	rinfo->mmio_base = ioremap(rinfo->mmio_base_phys, RADEON_REGSIZE);
+	if (!rinfo->mmio_base) {
+		printk(KERN_ERR "radeonfb (%s): cannot map MMIO\n", pci_name(rinfo->pdev));
+		ret = -EIO;
+		goto err_release_pci;
+	}
+
+	rinfo->fb_local_base = INREG(MC_FB_LOCATION) << 16;
+
+	/*
+	 * Check for errata
+	 */
+	rinfo->errata = 0;
+	if (rinfo->family == CHIP_FAMILY_R300 &&
+	    (INREG(CONFIG_CNTL) & CFG_ATI_REV_ID_MASK)
+	    == CFG_ATI_REV_A11)
+		rinfo->errata |= CHIP_ERRATA_R300_CG;
+
+	if (rinfo->family == CHIP_FAMILY_RV200 ||
+	    rinfo->family == CHIP_FAMILY_RS200)
+		rinfo->errata |= CHIP_ERRATA_PLL_DUMMYREADS;
+
+	if (rinfo->family == CHIP_FAMILY_RV100 ||
+	    rinfo->family == CHIP_FAMILY_RS100 ||
+	    rinfo->family == CHIP_FAMILY_RS200)
+		rinfo->errata |= CHIP_ERRATA_PLL_DELAY;
+
+#ifdef CONFIG_PPC_OF
+	/* On PPC, we obtain the OF device-node pointer to the firmware
+	 * data for this chip
+	 */
+	rinfo->of_node = pci_device_to_OF_node(pdev);
+	if (rinfo->of_node == NULL)
+		printk(KERN_WARNING "radeonfb (%s): Cannot match card to OF node !\n",
+		       pci_name(rinfo->pdev));
+
+	/* On PPC, the firmware sets up a memory mapping that tends
+	 * to cause lockups when enabling the engine. We reconfigure
+	 * the card internal memory mappings properly
+	 */
+	fixup_memory_mappings(rinfo);
+#endif /* CONFIG_PPC_OF */
+
+	/* Get VRAM size and type */
+	radeon_identify_vram(rinfo);
+
+	rinfo->mapped_vram = min_t(unsigned long, MAX_MAPPED_VRAM, rinfo->video_ram);
+
+	do {
+		rinfo->fb_base = ioremap (rinfo->fb_base_phys,
+					  rinfo->mapped_vram);
+	} while (   rinfo->fb_base == 0 &&
+		  ((rinfo->mapped_vram /=2) >= MIN_MAPPED_VRAM) );
+
+	if (rinfo->fb_base)
+		memset_io(rinfo->fb_base, 0, rinfo->mapped_vram);
+	else {
+		printk (KERN_ERR "radeonfb (%s): cannot map FB\n", pci_name(rinfo->pdev));
+		ret = -EIO;
+		goto err_unmap_rom;
+	}
+
+	RTRACE("radeonfb (%s): mapped %ldk videoram\n", pci_name(rinfo->pdev),
+	       rinfo->mapped_vram/1024);
+
+	/*
+	 * Map the BIOS ROM if any and retreive PLL parameters from
+	 * the BIOS. We skip that on mobility chips as the real panel
+	 * values we need aren't in the ROM but in the BIOS image in
+	 * memory. This is definitely not the best meacnism though,
+	 * we really need the arch code to tell us which is the "primary"
+	 * video adapter to use the memory image (or better, the arch
+	 * should provide us a copy of the BIOS image to shield us from
+	 * archs who would store that elsewhere and/or could initialize
+	 * more than one adapter during boot).
+	 */
+	if (!rinfo->is_mobility)
+		radeon_map_ROM(rinfo, pdev);
+
+	/*
+	 * On x86, the primary display on laptop may have it's BIOS
+	 * ROM elsewhere, try to locate it at the legacy memory hole.
+	 * We probably need to make sure this is the primary display,
+	 * but that is difficult without some arch support.
+	 */
+#ifdef CONFIG_X86
+	if (rinfo->bios_seg == NULL)
+		radeon_find_mem_vbios(rinfo);
+#endif
+
+	/* If both above failed, try the BIOS ROM again for mobility
+	 * chips
+	 */
+	if (rinfo->bios_seg == NULL && rinfo->is_mobility)
+		radeon_map_ROM(rinfo, pdev);
+
+	/* Get informations about the board's PLL */
+	radeon_get_pllinfo(rinfo);
+
+#ifdef CONFIG_FB_RADEON_I2C
+	/* Register I2C bus */
+	radeon_create_i2c_busses(rinfo);
+#endif
+
+	/* set all the vital stuff */
+	radeon_set_fbinfo (rinfo);
+
+	/* Probe screen types */
+	radeon_probe_screens(rinfo, monitor_layout, ignore_edid);
+
+	/* Build mode list, check out panel native model */
+	radeon_check_modes(rinfo, mode_option);
+
+	/* Register some sysfs stuff (should be done better) */
+	if (rinfo->mon1_EDID)
+		sysfs_create_bin_file(&rinfo->pdev->dev.kobj, &edid1_attr);
+	if (rinfo->mon2_EDID)
+		sysfs_create_bin_file(&rinfo->pdev->dev.kobj, &edid2_attr);
+
+	/* save current mode regs before we switch into the new one
+	 * so we can restore this upon __exit
+	 */
+	radeon_save_state (rinfo, &rinfo->init_state);
+	memcpy(&rinfo->state, &rinfo->init_state, sizeof(struct radeon_regs));
+
+	/* Setup Power Management capabilities */
+	if (default_dynclk < -1) {
+		/* -2 is special: means  ON on mobility chips and do not
+		 * change on others
+		 */
+		radeonfb_pm_init(rinfo, rinfo->is_mobility ? 1 : -1);
+	} else
+		radeonfb_pm_init(rinfo, default_dynclk);
+
+	pci_set_drvdata(pdev, info);
+
+	/* Register with fbdev layer */
+	ret = register_framebuffer(info);
+	if (ret < 0) {
+		printk (KERN_ERR "radeonfb (%s): could not register framebuffer\n",
+			pci_name(rinfo->pdev));
+		goto err_unmap_fb;
+	}
+
+#ifdef CONFIG_MTRR
+	rinfo->mtrr_hdl = nomtrr ? -1 : mtrr_add(rinfo->fb_base_phys,
+						 rinfo->video_ram,
+						 MTRR_TYPE_WRCOMB, 1);
+#endif
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	if (rinfo->mon1_type == MT_LCD) {
+		register_backlight_controller(&radeon_backlight_controller,
+					      rinfo, "ati");
+		register_backlight_controller(&radeon_backlight_controller,
+					      rinfo, "mnca");
+	}
+#endif
+
+	printk ("radeonfb (%s): %s\n", pci_name(rinfo->pdev), rinfo->name);
+
+	if (rinfo->bios_seg)
+		radeon_unmap_ROM(rinfo, pdev);
+	RTRACE("radeonfb_pci_register END\n");
+
+	return 0;
+err_unmap_fb:
+	iounmap(rinfo->fb_base);
+err_unmap_rom:
+	kfree(rinfo->mon1_EDID);
+	kfree(rinfo->mon2_EDID);
+	if (rinfo->mon1_modedb)
+		fb_destroy_modedb(rinfo->mon1_modedb);
+	fb_dealloc_cmap(&info->cmap);
+#ifdef CONFIG_FB_RADEON_I2C
+	radeon_delete_i2c_busses(rinfo);
+#endif
+	if (rinfo->bios_seg)
+		radeon_unmap_ROM(rinfo, pdev);
+	iounmap(rinfo->mmio_base);
+err_release_pci:
+	pci_release_regions(pdev);
+err_release_fb:
+	framebuffer_release(info);
+err_disable:
+	pci_disable_device(pdev);
+err_out:
+	return ret;
+}
+
+
+
+static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev)
+{
+        struct fb_info *info = pci_get_drvdata(pdev);
+        struct radeonfb_info *rinfo = info->par;
+ 
+        if (!rinfo)
+                return;
+ 
+	radeonfb_pm_exit(rinfo);
+
+#if 0
+	/* restore original state
+	 * 
+	 * Doesn't quite work yet, I suspect if we come from a legacy
+	 * VGA mode (or worse, text mode), we need to do some VGA black
+	 * magic here that I know nothing about. --BenH
+	 */
+        radeon_write_mode (rinfo, &rinfo->init_state, 1);
+ #endif
+
+	del_timer_sync(&rinfo->lvds_timer);
+
+#ifdef CONFIG_MTRR
+	if (rinfo->mtrr_hdl >= 0)
+		mtrr_del(rinfo->mtrr_hdl, 0, 0);
+#endif
+
+        unregister_framebuffer(info);
+
+        iounmap(rinfo->mmio_base);
+        iounmap(rinfo->fb_base);
+ 
+ 	pci_release_regions(pdev);
+
+	kfree(rinfo->mon1_EDID);
+	kfree(rinfo->mon2_EDID);
+	if (rinfo->mon1_modedb)
+		fb_destroy_modedb(rinfo->mon1_modedb);
+#ifdef CONFIG_FB_RADEON_I2C
+	radeon_delete_i2c_busses(rinfo);
+#endif        
+	fb_dealloc_cmap(&info->cmap);
+        framebuffer_release(info);
+	pci_disable_device(pdev);
+}
+
+
+static struct pci_driver radeonfb_driver = {
+	.name		= "radeonfb",
+	.id_table	= radeonfb_pci_table,
+	.probe		= radeonfb_pci_register,
+	.remove		= __devexit_p(radeonfb_pci_unregister),
+#ifdef CONFIG_PM
+	.suspend       	= radeonfb_pci_suspend,
+	.resume		= radeonfb_pci_resume,
+#endif /* CONFIG_PM */
+};
+
+#ifndef MODULE
+static int __init radeonfb_setup (char *options)
+{
+	char *this_opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep (&options, ",")) != NULL) {
+		if (!*this_opt)
+			continue;
+
+		if (!strncmp(this_opt, "noaccel", 7)) {
+			noaccel = 1;
+		} else if (!strncmp(this_opt, "mirror", 6)) {
+			mirror = 1;
+		} else if (!strncmp(this_opt, "force_dfp", 9)) {
+			force_dfp = 1;
+		} else if (!strncmp(this_opt, "panel_yres:", 11)) {
+			panel_yres = simple_strtoul((this_opt+11), NULL, 0);
+#ifdef CONFIG_MTRR
+		} else if (!strncmp(this_opt, "nomtrr", 6)) {
+			nomtrr = 1;
+#endif
+		} else if (!strncmp(this_opt, "nomodeset", 9)) {
+			nomodeset = 1;
+		} else if (!strncmp(this_opt, "force_measure_pll", 17)) {
+			force_measure_pll = 1;
+		} else if (!strncmp(this_opt, "ignore_edid", 11)) {
+			ignore_edid = 1;
+		} else
+			mode_option = this_opt;
+	}
+	return 0;
+}
+#endif  /*  MODULE  */
+
+static int __init radeonfb_init (void)
+{
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("radeonfb", &option))
+		return -ENODEV;
+	radeonfb_setup(option);
+#endif
+	return pci_register_driver (&radeonfb_driver);
+}
+
+
+static void __exit radeonfb_exit (void)
+{
+	pci_unregister_driver (&radeonfb_driver);
+}
+
+module_init(radeonfb_init);
+module_exit(radeonfb_exit);
+
+MODULE_AUTHOR("Ani Joshi");
+MODULE_DESCRIPTION("framebuffer driver for ATI Radeon chipset");
+MODULE_LICENSE("GPL");
+module_param(noaccel, bool, 0);
+module_param(default_dynclk, int, 0);
+MODULE_PARM_DESC(default_dynclk, "int: -2=enable on mobility only,-1=do not change,0=off,1=on");
+MODULE_PARM_DESC(noaccel, "bool: disable acceleration");
+module_param(nomodeset, bool, 0);
+MODULE_PARM_DESC(nomodeset, "bool: disable actual setting of video mode");
+module_param(mirror, bool, 0);
+MODULE_PARM_DESC(mirror, "bool: mirror the display to both monitors");
+module_param(force_dfp, bool, 0);
+MODULE_PARM_DESC(force_dfp, "bool: force display to dfp");
+module_param(ignore_edid, bool, 0);
+MODULE_PARM_DESC(ignore_edid, "bool: Ignore EDID data when doing DDC probe");
+module_param(monitor_layout, charp, 0);
+MODULE_PARM_DESC(monitor_layout, "Specify monitor mapping (like XFree86)");
+module_param(force_measure_pll, bool, 0);
+MODULE_PARM_DESC(force_measure_pll, "Force measurement of PLL (debug)");
+#ifdef CONFIG_MTRR
+module_param(nomtrr, bool, 0);
+MODULE_PARM_DESC(nomtrr, "bool: disable use of MTRR registers");
+#endif
+module_param(panel_yres, int, 0);
+MODULE_PARM_DESC(panel_yres, "int: set panel yres");
+module_param(mode_option, charp, 0);
+MODULE_PARM_DESC(mode_option, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
diff --git a/drivers/video/aty/radeon_i2c.c b/drivers/video/aty/radeon_i2c.c
new file mode 100644
index 0000000..7622441
--- /dev/null
+++ b/drivers/video/aty/radeon_i2c.c
@@ -0,0 +1,265 @@
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/fb.h>
+
+
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/i2c-algo-bit.h>
+
+#include <asm/io.h>
+
+#include <video/radeon.h>
+#include "radeonfb.h"
+#include "../edid.h"
+
+#define RADEON_DDC 	0x50
+
+static void radeon_gpio_setscl(void* data, int state)
+{
+	struct radeon_i2c_chan 	*chan = data;
+	struct radeonfb_info	*rinfo = chan->rinfo;
+	u32			val;
+	
+	val = INREG(chan->ddc_reg) & ~(VGA_DDC_CLK_OUT_EN);
+	if (!state)
+		val |= VGA_DDC_CLK_OUT_EN;
+
+	OUTREG(chan->ddc_reg, val);
+	(void)INREG(chan->ddc_reg);
+}
+
+static void radeon_gpio_setsda(void* data, int state)
+{
+	struct radeon_i2c_chan 	*chan = data;
+	struct radeonfb_info	*rinfo = chan->rinfo;
+	u32			val;
+	
+	val = INREG(chan->ddc_reg) & ~(VGA_DDC_DATA_OUT_EN);
+	if (!state)
+		val |= VGA_DDC_DATA_OUT_EN;
+
+	OUTREG(chan->ddc_reg, val);
+	(void)INREG(chan->ddc_reg);
+}
+
+static int radeon_gpio_getscl(void* data)
+{
+	struct radeon_i2c_chan 	*chan = data;
+	struct radeonfb_info	*rinfo = chan->rinfo;
+	u32			val;
+	
+	val = INREG(chan->ddc_reg);
+
+	return (val & VGA_DDC_CLK_INPUT) ? 1 : 0;
+}
+
+static int radeon_gpio_getsda(void* data)
+{
+	struct radeon_i2c_chan 	*chan = data;
+	struct radeonfb_info	*rinfo = chan->rinfo;
+	u32			val;
+	
+	val = INREG(chan->ddc_reg);
+
+	return (val & VGA_DDC_DATA_INPUT) ? 1 : 0;
+}
+
+static int radeon_setup_i2c_bus(struct radeon_i2c_chan *chan, const char *name)
+{
+	int rc;
+
+	strcpy(chan->adapter.name, name);
+	chan->adapter.owner		= THIS_MODULE;
+	chan->adapter.id		= I2C_ALGO_ATI;
+	chan->adapter.algo_data		= &chan->algo;
+	chan->adapter.dev.parent	= &chan->rinfo->pdev->dev;
+	chan->algo.setsda		= radeon_gpio_setsda;
+	chan->algo.setscl		= radeon_gpio_setscl;
+	chan->algo.getsda		= radeon_gpio_getsda;
+	chan->algo.getscl		= radeon_gpio_getscl;
+	chan->algo.udelay		= 40;
+	chan->algo.timeout		= 20;
+	chan->algo.data 		= chan;	
+	
+	i2c_set_adapdata(&chan->adapter, chan);
+	
+	/* Raise SCL and SDA */
+	radeon_gpio_setsda(chan, 1);
+	radeon_gpio_setscl(chan, 1);
+	udelay(20);
+
+	rc = i2c_bit_add_bus(&chan->adapter);
+	if (rc == 0)
+		dev_dbg(&chan->rinfo->pdev->dev, "I2C bus %s registered.\n", name);
+	else
+		dev_warn(&chan->rinfo->pdev->dev, "Failed to register I2C bus %s.\n", name);
+	return rc;
+}
+
+void radeon_create_i2c_busses(struct radeonfb_info *rinfo)
+{
+	rinfo->i2c[0].rinfo	= rinfo;
+	rinfo->i2c[0].ddc_reg	= GPIO_MONID;
+	radeon_setup_i2c_bus(&rinfo->i2c[0], "monid");
+
+	rinfo->i2c[1].rinfo	= rinfo;
+	rinfo->i2c[1].ddc_reg	= GPIO_DVI_DDC;
+	radeon_setup_i2c_bus(&rinfo->i2c[1], "dvi");
+
+	rinfo->i2c[2].rinfo	= rinfo;
+	rinfo->i2c[2].ddc_reg	= GPIO_VGA_DDC;
+	radeon_setup_i2c_bus(&rinfo->i2c[2], "vga");
+
+	rinfo->i2c[3].rinfo	= rinfo;
+	rinfo->i2c[3].ddc_reg	= GPIO_CRT2_DDC;
+	radeon_setup_i2c_bus(&rinfo->i2c[3], "crt2");
+}
+
+void radeon_delete_i2c_busses(struct radeonfb_info *rinfo)
+{
+	if (rinfo->i2c[0].rinfo)
+		i2c_bit_del_bus(&rinfo->i2c[0].adapter);
+	rinfo->i2c[0].rinfo = NULL;
+
+	if (rinfo->i2c[1].rinfo)
+		i2c_bit_del_bus(&rinfo->i2c[1].adapter);
+	rinfo->i2c[1].rinfo = NULL;
+
+	if (rinfo->i2c[2].rinfo)
+		i2c_bit_del_bus(&rinfo->i2c[2].adapter);
+	rinfo->i2c[2].rinfo = NULL;
+
+	if (rinfo->i2c[3].rinfo)
+		i2c_bit_del_bus(&rinfo->i2c[3].adapter);
+	rinfo->i2c[3].rinfo = NULL;
+}
+
+
+static u8 *radeon_do_probe_i2c_edid(struct radeon_i2c_chan *chan)
+{
+	u8 start = 0x0;
+	struct i2c_msg msgs[] = {
+		{
+			.addr	= RADEON_DDC,
+			.len	= 1,
+			.buf	= &start,
+		}, {
+			.addr	= RADEON_DDC,
+			.flags	= I2C_M_RD,
+			.len	= EDID_LENGTH,
+		},
+	};
+	u8 *buf;
+
+	buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
+	if (!buf) {
+		dev_warn(&chan->rinfo->pdev->dev, "Out of memory!\n");
+		return NULL;
+	}
+	msgs[1].buf = buf;
+
+	if (i2c_transfer(&chan->adapter, msgs, 2) == 2)
+		return buf;
+	dev_dbg(&chan->rinfo->pdev->dev, "Unable to read EDID block.\n");
+	kfree(buf);
+	return NULL;
+}
+
+
+int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn, u8 **out_edid)
+{
+	u32 reg = rinfo->i2c[conn-1].ddc_reg;
+	u8 *edid = NULL;
+	int i, j;
+
+	OUTREG(reg, INREG(reg) & 
+			~(VGA_DDC_DATA_OUTPUT | VGA_DDC_CLK_OUTPUT));
+
+	OUTREG(reg, INREG(reg) & ~(VGA_DDC_CLK_OUT_EN));
+	(void)INREG(reg);
+
+	for (i = 0; i < 3; i++) {
+		/* For some old monitors we need the
+		 * following process to initialize/stop DDC
+		 */
+		OUTREG(reg, INREG(reg) & ~(VGA_DDC_DATA_OUT_EN));
+		(void)INREG(reg);
+		msleep(13);
+
+		OUTREG(reg, INREG(reg) & ~(VGA_DDC_CLK_OUT_EN));
+		(void)INREG(reg);
+		for (j = 0; j < 5; j++) {
+			msleep(10);
+			if (INREG(reg) & VGA_DDC_CLK_INPUT)
+				break;
+		}
+		if (j == 5)
+			continue;
+
+		OUTREG(reg, INREG(reg) | VGA_DDC_DATA_OUT_EN);
+		(void)INREG(reg);
+		msleep(15);
+		OUTREG(reg, INREG(reg) | VGA_DDC_CLK_OUT_EN);
+		(void)INREG(reg);
+		msleep(15);
+		OUTREG(reg, INREG(reg) & ~(VGA_DDC_DATA_OUT_EN));
+		(void)INREG(reg);
+		msleep(15);
+
+		/* Do the real work */
+		edid = radeon_do_probe_i2c_edid(&rinfo->i2c[conn-1]);
+
+		OUTREG(reg, INREG(reg) | 
+				(VGA_DDC_DATA_OUT_EN | VGA_DDC_CLK_OUT_EN));
+		(void)INREG(reg);
+		msleep(15);
+		
+		OUTREG(reg, INREG(reg) & ~(VGA_DDC_CLK_OUT_EN));
+		(void)INREG(reg);
+		for (j = 0; j < 10; j++) {
+			msleep(10);
+			if (INREG(reg) & VGA_DDC_CLK_INPUT)
+				break;
+		}
+
+		OUTREG(reg, INREG(reg) & ~(VGA_DDC_DATA_OUT_EN));
+		(void)INREG(reg);
+		msleep(15);
+		OUTREG(reg, INREG(reg) |
+				(VGA_DDC_DATA_OUT_EN | VGA_DDC_CLK_OUT_EN));
+		(void)INREG(reg);
+		if (edid)
+			break;
+	}
+	/* Release the DDC lines when done or the Apple Cinema HD display
+	 * will switch off
+	 */
+	OUTREG(reg, INREG(reg) & ~(VGA_DDC_CLK_OUT_EN | VGA_DDC_DATA_OUT_EN));
+	(void)INREG(reg);
+
+	if (out_edid)
+		*out_edid = edid;
+	if (!edid) {
+		RTRACE("radeonfb: I2C (port %d) ... not found\n", conn);
+		return MT_NONE;
+	}
+	if (edid[0x14] & 0x80) {
+		/* Fix detection using BIOS tables */
+		if (rinfo->is_mobility /*&& conn == ddc_dvi*/ &&
+		    (INREG(LVDS_GEN_CNTL) & LVDS_ON)) {
+			RTRACE("radeonfb: I2C (port %d) ... found LVDS panel\n", conn);
+			return MT_LCD;
+		} else {
+			RTRACE("radeonfb: I2C (port %d) ... found TMDS panel\n", conn);
+			return MT_DFP;
+		}
+	}
+       	RTRACE("radeonfb: I2C (port %d) ... found CRT display\n", conn);
+	return MT_CRT;
+}
+
diff --git a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c
new file mode 100644
index 0000000..ea7c863
--- /dev/null
+++ b/drivers/video/aty/radeon_monitor.c
@@ -0,0 +1,1010 @@
+#include "radeonfb.h"
+#include "../edid.h"
+
+static struct fb_var_screeninfo radeonfb_default_var = {
+	.xres		= 640,
+	.yres		= 480,
+	.xres_virtual	= 640,
+	.yres_virtual	= 480,
+	.bits_per_pixel = 8,
+	.red		= { .length = 8 },
+	.green		= { .length = 8 },
+	.blue		= { .length = 8 },
+	.activate	= FB_ACTIVATE_NOW,
+	.height		= -1,
+	.width		= -1,
+	.pixclock	= 39721,
+	.left_margin	= 40,
+	.right_margin	= 24,
+	.upper_margin	= 32,
+	.lower_margin	= 11,
+	.hsync_len	= 96,
+	.vsync_len	= 2,
+	.vmode		= FB_VMODE_NONINTERLACED
+};
+
+static char *radeon_get_mon_name(int type)
+{
+	char *pret = NULL;
+
+	switch (type) {
+		case MT_NONE:
+			pret = "no";
+			break;
+		case MT_CRT:
+			pret = "CRT";
+			break;
+		case MT_DFP:
+			pret = "DFP";
+			break;
+		case MT_LCD:
+			pret = "LCD";
+			break;
+		case MT_CTV:
+			pret = "CTV";
+			break;
+		case MT_STV:
+			pret = "STV";
+			break;
+	}
+
+	return pret;
+}
+
+
+#ifdef CONFIG_PPC_OF
+/*
+ * Try to find monitor informations & EDID data out of the Open Firmware
+ * device-tree. This also contains some "hacks" to work around a few machine
+ * models with broken OF probing by hard-coding known EDIDs for some Mac
+ * laptops internal LVDS panel. (XXX: not done yet)
+ */
+static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_EDID,
+					       int hdno)
+{
+        static char *propnames[] = { "DFP,EDID", "LCD,EDID", "EDID",
+				     "EDID1", "EDID2",  NULL };
+	u8 *pedid = NULL;
+	u8 *pmt = NULL;
+	u8 *tmp;
+        int i, mt = MT_NONE;  
+	
+	RTRACE("analyzing OF properties...\n");
+	pmt = (u8 *)get_property(dp, "display-type", NULL);
+	if (!pmt)
+		return MT_NONE;
+	RTRACE("display-type: %s\n", pmt);
+	/* OF says "LCD" for DFP as well, we discriminate from the caller of this
+	 * function
+	 */
+	if (!strcmp(pmt, "LCD") || !strcmp(pmt, "DFP"))
+		mt = MT_DFP;
+	else if (!strcmp(pmt, "CRT"))
+		mt = MT_CRT;
+	else {
+		if (strcmp(pmt, "NONE") != 0)
+			printk(KERN_WARNING "radeonfb: Unknown OF display-type: %s\n",
+			       pmt);
+		return MT_NONE;
+	}
+
+	for (i = 0; propnames[i] != NULL; ++i) {
+		pedid = (u8 *)get_property(dp, propnames[i], NULL);
+		if (pedid != NULL)
+			break;
+	}
+	/* We didn't find the EDID in the leaf node, some cards will actually
+	 * put EDID1/EDID2 in the parent, look for these (typically M6 tipb).
+	 * single-head cards have hdno == -1 and skip this step
+	 */
+	if (pedid == NULL && dp->parent && (hdno != -1))
+		pedid = get_property(dp->parent, (hdno == 0) ? "EDID1" : "EDID2", NULL);
+	if (pedid == NULL && dp->parent && (hdno == 0))
+		pedid = get_property(dp->parent, "EDID", NULL);
+	if (pedid == NULL)
+		return mt;
+
+	tmp = (u8 *)kmalloc(EDID_LENGTH, GFP_KERNEL);
+	if (!tmp)
+		return mt;
+	memcpy(tmp, pedid, EDID_LENGTH);
+	*out_EDID = tmp;
+	return mt;
+}
+
+static int __devinit radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_no,
+					  u8 **out_EDID)
+{
+        struct device_node *dp;
+
+	RTRACE("radeon_probe_OF_head\n");
+
+        dp = rinfo->of_node;
+        while (dp == NULL)
+		return MT_NONE;
+
+	if (rinfo->has_CRTC2) {
+		char *pname;
+		int len, second = 0;
+
+		dp = dp->child;
+		do {
+			if (!dp)
+				return MT_NONE;
+			pname = (char *)get_property(dp, "name", NULL);
+			if (!pname)
+				return MT_NONE;
+			len = strlen(pname);
+			RTRACE("head: %s (letter: %c, head_no: %d)\n",
+			       pname, pname[len-1], head_no);
+			if (pname[len-1] == 'A' && head_no == 0) {
+				int mt = radeon_parse_montype_prop(dp, out_EDID, 0);
+				/* Maybe check for LVDS_GEN_CNTL here ? I need to check out
+				 * what OF does when booting with lid closed
+				 */
+				if (mt == MT_DFP && rinfo->is_mobility)
+					mt = MT_LCD;
+				return mt;
+			} else if (pname[len-1] == 'B' && head_no == 1)
+				return radeon_parse_montype_prop(dp, out_EDID, 1);
+			second = 1;
+			dp = dp->sibling;
+		} while(!second);
+	} else {
+		if (head_no > 0)
+			return MT_NONE;
+		return radeon_parse_montype_prop(dp, out_EDID, -1);
+	}
+        return MT_NONE;
+}
+#endif /* CONFIG_PPC_OF */
+
+
+static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo)
+{
+	unsigned long tmp, tmp0;
+	char stmp[30];
+	int i;
+
+	if (!rinfo->bios_seg)
+		return 0;
+
+	if (!(tmp = BIOS_IN16(rinfo->fp_bios_start + 0x40))) {
+		printk(KERN_ERR "radeonfb: Failed to detect DFP panel info using BIOS\n");
+		rinfo->panel_info.pwr_delay = 200;
+		return 0;
+	}
+
+	for(i=0; i<24; i++)
+		stmp[i] = BIOS_IN8(tmp+i+1);
+	stmp[24] = 0;
+	printk("radeonfb: panel ID string: %s\n", stmp);
+	rinfo->panel_info.xres = BIOS_IN16(tmp + 25);
+	rinfo->panel_info.yres = BIOS_IN16(tmp + 27);
+	printk("radeonfb: detected LVDS panel size from BIOS: %dx%d\n",
+		rinfo->panel_info.xres, rinfo->panel_info.yres);
+
+	rinfo->panel_info.pwr_delay = BIOS_IN16(tmp + 44);
+	RTRACE("BIOS provided panel power delay: %d\n", rinfo->panel_info.pwr_delay);
+	if (rinfo->panel_info.pwr_delay > 2000 || rinfo->panel_info.pwr_delay <= 0)
+		rinfo->panel_info.pwr_delay = 2000;
+
+	/*
+	 * Some panels only work properly with some divider combinations
+	 */
+	rinfo->panel_info.ref_divider = BIOS_IN16(tmp + 46);
+	rinfo->panel_info.post_divider = BIOS_IN8(tmp + 48);
+	rinfo->panel_info.fbk_divider = BIOS_IN16(tmp + 49);
+	if (rinfo->panel_info.ref_divider != 0 &&
+	    rinfo->panel_info.fbk_divider > 3) {
+		rinfo->panel_info.use_bios_dividers = 1;
+		printk(KERN_INFO "radeondb: BIOS provided dividers will be used\n");
+		RTRACE("ref_divider = %x\n", rinfo->panel_info.ref_divider);
+		RTRACE("post_divider = %x\n", rinfo->panel_info.post_divider);
+		RTRACE("fbk_divider = %x\n", rinfo->panel_info.fbk_divider);
+	}
+	RTRACE("Scanning BIOS table ...\n");
+	for(i=0; i<32; i++) {
+		tmp0 = BIOS_IN16(tmp+64+i*2);
+		if (tmp0 == 0)
+			break;
+		RTRACE(" %d x %d\n", BIOS_IN16(tmp0), BIOS_IN16(tmp0+2));
+		if ((BIOS_IN16(tmp0) == rinfo->panel_info.xres) &&
+		    (BIOS_IN16(tmp0+2) == rinfo->panel_info.yres)) {
+			rinfo->panel_info.hblank = (BIOS_IN16(tmp0+17) - BIOS_IN16(tmp0+19)) * 8;
+			rinfo->panel_info.hOver_plus = ((BIOS_IN16(tmp0+21) -
+							 BIOS_IN16(tmp0+19) -1) * 8) & 0x7fff;
+			rinfo->panel_info.hSync_width = BIOS_IN8(tmp0+23) * 8;
+			rinfo->panel_info.vblank = BIOS_IN16(tmp0+24) - BIOS_IN16(tmp0+26);
+			rinfo->panel_info.vOver_plus = (BIOS_IN16(tmp0+28) & 0x7ff) - BIOS_IN16(tmp0+26);
+			rinfo->panel_info.vSync_width = (BIOS_IN16(tmp0+28) & 0xf800) >> 11;
+			rinfo->panel_info.clock = BIOS_IN16(tmp0+9);
+			/* Assume high active syncs for now until ATI tells me more... maybe we
+			 * can probe register values here ?
+			 */
+			rinfo->panel_info.hAct_high = 1;
+			rinfo->panel_info.vAct_high = 1;
+			/* Mark panel infos valid */
+			rinfo->panel_info.valid = 1;
+
+			RTRACE("Found panel in BIOS table:\n");
+			RTRACE("  hblank: %d\n", rinfo->panel_info.hblank);
+			RTRACE("  hOver_plus: %d\n", rinfo->panel_info.hOver_plus);
+			RTRACE("  hSync_width: %d\n", rinfo->panel_info.hSync_width);
+			RTRACE("  vblank: %d\n", rinfo->panel_info.vblank);
+			RTRACE("  vOver_plus: %d\n", rinfo->panel_info.vOver_plus);
+			RTRACE("  vSync_width: %d\n", rinfo->panel_info.vSync_width);
+			RTRACE("  clock: %d\n", rinfo->panel_info.clock);
+				
+			return 1;
+		}
+	}
+	RTRACE("Didn't find panel in BIOS table !\n");
+
+	return 0;
+}
+
+/* Try to extract the connector informations from the BIOS. This
+ * doesn't quite work yet, but it's output is still useful for
+ * debugging
+ */
+static void __devinit radeon_parse_connector_info(struct radeonfb_info *rinfo)
+{
+	int offset, chips, connectors, tmp, i, conn, type;
+
+	static char* __conn_type_table[16] = {
+		"NONE", "Proprietary", "CRT", "DVI-I", "DVI-D", "Unknown", "Unknown",
+		"Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown",
+		"Unknown", "Unknown", "Unknown"
+	};
+
+	if (!rinfo->bios_seg)
+		return;
+
+	offset = BIOS_IN16(rinfo->fp_bios_start + 0x50);
+	if (offset == 0) {
+		printk(KERN_WARNING "radeonfb: No connector info table detected\n");
+		return;
+	}
+
+	/* Don't do much more at this point but displaying the data if
+	 * DEBUG is enabled
+	 */
+	chips = BIOS_IN8(offset++) >> 4;
+	RTRACE("%d chips in connector info\n", chips);
+	for (i = 0; i < chips; i++) {
+		tmp = BIOS_IN8(offset++);
+		connectors = tmp & 0x0f;
+		RTRACE(" - chip %d has %d connectors\n", tmp >> 4, connectors);
+		for (conn = 0; ; conn++) {
+			tmp = BIOS_IN16(offset);
+			if (tmp == 0)
+				break;
+			offset += 2;
+			type = (tmp >> 12) & 0x0f;
+			RTRACE("  * connector %d of type %d (%s) : %04x\n",
+			       conn, type, __conn_type_table[type], tmp);
+		}
+	}
+}
+
+
+/*
+ * Probe physical connection of a CRT. This code comes from XFree
+ * as well and currently is only implemented for the CRT DAC, the
+ * code for the TVDAC is commented out in XFree as "non working"
+ */
+static int __devinit radeon_crt_is_connected(struct radeonfb_info *rinfo, int is_crt_dac)
+{
+    int	          connected = 0;
+
+    /* the monitor either wasn't connected or it is a non-DDC CRT.
+     * try to probe it
+     */
+    if (is_crt_dac) {
+	unsigned long ulOrigVCLK_ECP_CNTL;
+	unsigned long ulOrigDAC_CNTL;
+	unsigned long ulOrigDAC_EXT_CNTL;
+	unsigned long ulOrigCRTC_EXT_CNTL;
+	unsigned long ulData;
+	unsigned long ulMask;
+
+	ulOrigVCLK_ECP_CNTL = INPLL(VCLK_ECP_CNTL);
+
+	ulData              = ulOrigVCLK_ECP_CNTL;
+	ulData             &= ~(PIXCLK_ALWAYS_ONb
+				| PIXCLK_DAC_ALWAYS_ONb);
+	ulMask              = ~(PIXCLK_ALWAYS_ONb
+				| PIXCLK_DAC_ALWAYS_ONb);
+	OUTPLLP(VCLK_ECP_CNTL, ulData, ulMask);
+
+	ulOrigCRTC_EXT_CNTL = INREG(CRTC_EXT_CNTL);
+	ulData              = ulOrigCRTC_EXT_CNTL;
+	ulData             |= CRTC_CRT_ON;
+	OUTREG(CRTC_EXT_CNTL, ulData);
+   
+	ulOrigDAC_EXT_CNTL = INREG(DAC_EXT_CNTL);
+	ulData             = ulOrigDAC_EXT_CNTL;
+	ulData            &= ~DAC_FORCE_DATA_MASK;
+	ulData            |=  (DAC_FORCE_BLANK_OFF_EN
+			       |DAC_FORCE_DATA_EN
+			       |DAC_FORCE_DATA_SEL_MASK);
+	if ((rinfo->family == CHIP_FAMILY_RV250) ||
+	    (rinfo->family == CHIP_FAMILY_RV280))
+	    ulData |= (0x01b6 << DAC_FORCE_DATA_SHIFT);
+	else
+	    ulData |= (0x01ac << DAC_FORCE_DATA_SHIFT);
+
+	OUTREG(DAC_EXT_CNTL, ulData);
+
+	ulOrigDAC_CNTL     = INREG(DAC_CNTL);
+	ulData             = ulOrigDAC_CNTL;
+	ulData            |= DAC_CMP_EN;
+	ulData            &= ~(DAC_RANGE_CNTL_MASK
+			       | DAC_PDWN);
+	ulData            |= 0x2;
+	OUTREG(DAC_CNTL, ulData);
+
+	mdelay(1);
+
+	ulData     = INREG(DAC_CNTL);
+	connected =  (DAC_CMP_OUTPUT & ulData) ? 1 : 0;
+  
+	ulData    = ulOrigVCLK_ECP_CNTL;
+	ulMask    = 0xFFFFFFFFL;
+	OUTPLLP(VCLK_ECP_CNTL, ulData, ulMask);
+
+	OUTREG(DAC_CNTL,      ulOrigDAC_CNTL     );
+	OUTREG(DAC_EXT_CNTL,  ulOrigDAC_EXT_CNTL );
+	OUTREG(CRTC_EXT_CNTL, ulOrigCRTC_EXT_CNTL);
+    }
+
+    return connected ? MT_CRT : MT_NONE;
+}
+
+/*
+ * Parse the "monitor_layout" string if any. This code is mostly
+ * copied from XFree's radeon driver
+ */
+static int __devinit radeon_parse_monitor_layout(struct radeonfb_info *rinfo,
+						 const char *monitor_layout)
+{
+	char s1[5], s2[5];
+	int i = 0, second = 0;
+	const char *s;
+
+	if (!monitor_layout)
+		return 0;
+
+	s = monitor_layout;
+	do {
+		switch(*s) {
+		case ',':
+			s1[i] = '\0';
+			i = 0;
+			second = 1;
+			break;
+		case ' ':
+		case '\0':
+			break;
+		default:
+			if (i > 4)
+				break;
+			if (second)
+				s2[i] = *s;
+			else
+				s1[i] = *s;
+			i++;
+		}
+	} while (*s++);
+	if (second)
+		s2[i] = 0;
+	else {
+		s1[i] = 0;
+		s2[0] = 0;
+	}
+	if (strcmp(s1, "CRT") == 0)
+		rinfo->mon1_type = MT_CRT;
+	else if (strcmp(s1, "TMDS") == 0)
+		rinfo->mon1_type = MT_DFP;
+	else if (strcmp(s1, "LVDS") == 0)
+		rinfo->mon1_type = MT_LCD;
+
+	if (strcmp(s2, "CRT") == 0)
+		rinfo->mon2_type = MT_CRT;
+	else if (strcmp(s2, "TMDS") == 0)
+		rinfo->mon2_type = MT_DFP;
+	else if (strcmp(s2, "LVDS") == 0)
+		rinfo->mon2_type = MT_LCD;
+
+	return 1;
+}
+
+/*
+ * Probe display on both primary and secondary card's connector (if any)
+ * by various available techniques (i2c, OF device tree, BIOS, ...) and
+ * try to retreive EDID. The algorithm here comes from XFree's radeon
+ * driver
+ */
+void __devinit radeon_probe_screens(struct radeonfb_info *rinfo,
+				    const char *monitor_layout, int ignore_edid)
+{
+#ifdef CONFIG_FB_RADEON_I2C
+	int ddc_crt2_used = 0;	
+#endif
+	int tmp, i;
+
+	radeon_parse_connector_info(rinfo);
+
+	if (radeon_parse_monitor_layout(rinfo, monitor_layout)) {
+
+		/*
+		 * If user specified a monitor_layout option, use it instead
+		 * of auto-detecting. Maybe we should only use this argument
+		 * on the first radeon card probed or provide a way to specify
+		 * a layout for each card ?
+		 */
+
+		RTRACE("Using specified monitor layout: %s", monitor_layout);
+#ifdef CONFIG_FB_RADEON_I2C
+		if (!ignore_edid) {
+			if (rinfo->mon1_type != MT_NONE)
+				if (!radeon_probe_i2c_connector(rinfo, ddc_dvi, &rinfo->mon1_EDID)) {
+					radeon_probe_i2c_connector(rinfo, ddc_crt2, &rinfo->mon1_EDID);
+					ddc_crt2_used = 1;
+				}
+			if (rinfo->mon2_type != MT_NONE)
+				if (!radeon_probe_i2c_connector(rinfo, ddc_vga, &rinfo->mon2_EDID) &&
+				    !ddc_crt2_used)
+					radeon_probe_i2c_connector(rinfo, ddc_crt2, &rinfo->mon2_EDID);
+		}
+#endif /* CONFIG_FB_RADEON_I2C */
+		if (rinfo->mon1_type == MT_NONE) {
+			if (rinfo->mon2_type != MT_NONE) {
+				rinfo->mon1_type = rinfo->mon2_type;
+				rinfo->mon1_EDID = rinfo->mon2_EDID;
+			} else {
+				rinfo->mon1_type = MT_CRT;
+				printk(KERN_INFO "radeonfb: No valid monitor, assuming CRT on first port\n");
+			}
+			rinfo->mon2_type = MT_NONE;
+			rinfo->mon2_EDID = NULL;
+		}
+	} else {
+		/*
+		 * Auto-detecting display type (well... trying to ...)
+		 */
+		
+		RTRACE("Starting monitor auto detection...\n");
+
+#if DEBUG && defined(CONFIG_FB_RADEON_I2C)
+		{
+			u8 *EDIDs[4] = { NULL, NULL, NULL, NULL };
+			int mon_types[4] = {MT_NONE, MT_NONE, MT_NONE, MT_NONE};
+			int i;
+
+			for (i = 0; i < 4; i++)
+				mon_types[i] = radeon_probe_i2c_connector(rinfo,
+									  i+1, &EDIDs[i]);
+		}
+#endif /* DEBUG */
+		/*
+		 * Old single head cards
+		 */
+		if (!rinfo->has_CRTC2) {
+#ifdef CONFIG_PPC_OF
+			if (rinfo->mon1_type == MT_NONE)
+				rinfo->mon1_type = radeon_probe_OF_head(rinfo, 0,
+									&rinfo->mon1_EDID);
+#endif /* CONFIG_PPC_OF */
+#ifdef CONFIG_FB_RADEON_I2C
+			if (rinfo->mon1_type == MT_NONE)
+				rinfo->mon1_type =
+					radeon_probe_i2c_connector(rinfo, ddc_dvi,
+								   &rinfo->mon1_EDID);
+			if (rinfo->mon1_type == MT_NONE)
+				rinfo->mon1_type =
+					radeon_probe_i2c_connector(rinfo, ddc_vga,
+								   &rinfo->mon1_EDID);
+			if (rinfo->mon1_type == MT_NONE)
+				rinfo->mon1_type =
+					radeon_probe_i2c_connector(rinfo, ddc_crt2,
+								   &rinfo->mon1_EDID);	
+#endif /* CONFIG_FB_RADEON_I2C */
+			if (rinfo->mon1_type == MT_NONE)
+				rinfo->mon1_type = MT_CRT;
+			goto bail;
+		}
+
+		/*
+		 * Check for cards with reversed DACs or TMDS controllers using BIOS
+		 */
+		if (rinfo->bios_seg &&
+		    (tmp = BIOS_IN16(rinfo->fp_bios_start + 0x50))) {
+			for (i = 1; i < 4; i++) {
+				unsigned int tmp0;
+
+				if (!BIOS_IN8(tmp + i*2) && i > 1)
+					break;
+				tmp0 = BIOS_IN16(tmp + i*2);
+				if ((!(tmp0 & 0x01)) && (((tmp0 >> 8) & 0x0f) == ddc_dvi)) {
+					rinfo->reversed_DAC = 1;
+					printk(KERN_INFO "radeonfb: Reversed DACs detected\n");
+				}
+				if ((((tmp0 >> 8) & 0x0f) == ddc_dvi) && ((tmp0 >> 4) & 0x01)) {
+					rinfo->reversed_TMDS = 1;
+					printk(KERN_INFO "radeonfb: Reversed TMDS detected\n");
+				}
+			}
+		}
+
+		/*
+		 * Probe primary head (DVI or laptop internal panel)
+		 */
+#ifdef CONFIG_PPC_OF
+		if (rinfo->mon1_type == MT_NONE)
+			rinfo->mon1_type = radeon_probe_OF_head(rinfo, 0,
+								&rinfo->mon1_EDID);
+#endif /* CONFIG_PPC_OF */
+#ifdef CONFIG_FB_RADEON_I2C
+		if (rinfo->mon1_type == MT_NONE)
+			rinfo->mon1_type = radeon_probe_i2c_connector(rinfo, ddc_dvi,
+								      &rinfo->mon1_EDID);
+		if (rinfo->mon1_type == MT_NONE) {
+			rinfo->mon1_type = radeon_probe_i2c_connector(rinfo, ddc_crt2,
+								      &rinfo->mon1_EDID);
+			if (rinfo->mon1_type != MT_NONE)
+				ddc_crt2_used = 1;
+		}
+#endif /* CONFIG_FB_RADEON_I2C */
+		if (rinfo->mon1_type == MT_NONE && rinfo->is_mobility &&
+		    ((rinfo->bios_seg && (INREG(BIOS_4_SCRATCH) & 4))
+		     || (INREG(LVDS_GEN_CNTL) & LVDS_ON))) {
+			rinfo->mon1_type = MT_LCD;
+			printk("Non-DDC laptop panel detected\n");
+		}
+		if (rinfo->mon1_type == MT_NONE)
+			rinfo->mon1_type = radeon_crt_is_connected(rinfo, rinfo->reversed_DAC);
+
+		/*
+		 * Probe secondary head (mostly VGA, can be DVI)
+		 */
+#ifdef CONFIG_PPC_OF
+		if (rinfo->mon2_type == MT_NONE)
+			rinfo->mon2_type = radeon_probe_OF_head(rinfo, 1,
+								&rinfo->mon2_EDID);
+#endif /* CONFIG_PPC_OF */
+#ifdef CONFIG_FB_RADEON_I2C
+		if (rinfo->mon2_type == MT_NONE)
+			rinfo->mon2_type = radeon_probe_i2c_connector(rinfo, ddc_vga,
+								      &rinfo->mon2_EDID);
+		if (rinfo->mon2_type == MT_NONE && !ddc_crt2_used)
+			rinfo->mon2_type = radeon_probe_i2c_connector(rinfo, ddc_crt2,
+								      &rinfo->mon2_EDID);
+#endif /* CONFIG_FB_RADEON_I2C */
+		if (rinfo->mon2_type == MT_NONE)
+			rinfo->mon2_type = radeon_crt_is_connected(rinfo, !rinfo->reversed_DAC);
+
+		/*
+		 * If we only detected port 2, we swap them, if none detected,
+		 * assume CRT (maybe fallback to old BIOS_SCRATCH stuff ? or look
+		 * at FP registers ?)
+		 */
+		if (rinfo->mon1_type == MT_NONE) {
+			if (rinfo->mon2_type != MT_NONE) {
+				rinfo->mon1_type = rinfo->mon2_type;
+				rinfo->mon1_EDID = rinfo->mon2_EDID;
+			} else
+				rinfo->mon1_type = MT_CRT;
+			rinfo->mon2_type = MT_NONE;
+			rinfo->mon2_EDID = NULL;
+		}
+
+		/*
+		 * Deal with reversed TMDS
+		 */
+		if (rinfo->reversed_TMDS) {
+			/* Always keep internal TMDS as primary head */
+			if (rinfo->mon1_type == MT_DFP || rinfo->mon2_type == MT_DFP) {
+				int tmp_type = rinfo->mon1_type;
+				u8 *tmp_EDID = rinfo->mon1_EDID;
+				rinfo->mon1_type = rinfo->mon2_type;
+				rinfo->mon1_EDID = rinfo->mon2_EDID;
+				rinfo->mon2_type = tmp_type;
+				rinfo->mon2_EDID = tmp_EDID;
+				if (rinfo->mon1_type == MT_CRT || rinfo->mon2_type == MT_CRT)
+					rinfo->reversed_DAC ^= 1;
+			}
+		}
+	}
+	if (ignore_edid) {
+		kfree(rinfo->mon1_EDID);
+		rinfo->mon1_EDID = NULL;
+		kfree(rinfo->mon2_EDID);
+		rinfo->mon2_EDID = NULL;
+	}
+
+ bail:
+	printk(KERN_INFO "radeonfb: Monitor 1 type %s found\n",
+	       radeon_get_mon_name(rinfo->mon1_type));
+	if (rinfo->mon1_EDID)
+		printk(KERN_INFO "radeonfb: EDID probed\n");
+	if (!rinfo->has_CRTC2)
+		return;
+	printk(KERN_INFO "radeonfb: Monitor 2 type %s found\n",
+	       radeon_get_mon_name(rinfo->mon2_type));
+	if (rinfo->mon2_EDID)
+		printk(KERN_INFO "radeonfb: EDID probed\n");
+}
+
+
+/*
+ * This functions applyes any arch/model/machine specific fixups
+ * to the panel info. It may eventually alter EDID block as
+ * well or whatever is specific to a given model and not probed
+ * properly by the default code
+ */
+static void radeon_fixup_panel_info(struct radeonfb_info *rinfo)
+{
+#ifdef CONFIG_PPC_OF
+	/*
+	 * LCD Flat panels should use fixed dividers, we enfore that on
+	 * PPC only for now...
+	 */
+	if (!rinfo->panel_info.use_bios_dividers && rinfo->mon1_type == MT_LCD
+	    && rinfo->is_mobility) {
+		int ppll_div_sel;
+		u32 ppll_divn;
+		ppll_div_sel = INREG8(CLOCK_CNTL_INDEX + 1) & 0x3;
+		radeon_pll_errata_after_index(rinfo);
+		ppll_divn = INPLL(PPLL_DIV_0 + ppll_div_sel);
+		rinfo->panel_info.ref_divider = rinfo->pll.ref_div;
+		rinfo->panel_info.fbk_divider = ppll_divn & 0x7ff;
+		rinfo->panel_info.post_divider = (ppll_divn >> 16) & 0x7;
+		rinfo->panel_info.use_bios_dividers = 1;
+
+		printk(KERN_DEBUG "radeonfb: Using Firmware dividers 0x%08x "
+		       "from PPLL %d\n",
+		       rinfo->panel_info.fbk_divider |
+		       (rinfo->panel_info.post_divider << 16),
+		       ppll_div_sel);
+	}
+#endif /* CONFIG_PPC_OF */
+}
+
+
+/*
+ * Fill up panel infos from a mode definition, either returned by the EDID
+ * or from the default mode when we can't do any better
+ */
+static void radeon_var_to_panel_info(struct radeonfb_info *rinfo, struct fb_var_screeninfo *var)
+{
+	rinfo->panel_info.xres = var->xres;
+	rinfo->panel_info.yres = var->yres;
+	rinfo->panel_info.clock = 100000000 / var->pixclock;
+	rinfo->panel_info.hOver_plus = var->right_margin;
+	rinfo->panel_info.hSync_width = var->hsync_len;
+       	rinfo->panel_info.hblank = var->left_margin +
+		(var->right_margin + var->hsync_len);
+	rinfo->panel_info.vOver_plus = var->lower_margin;
+	rinfo->panel_info.vSync_width = var->vsync_len;
+       	rinfo->panel_info.vblank = var->upper_margin +
+		(var->lower_margin + var->vsync_len);
+	rinfo->panel_info.hAct_high =
+		(var->sync & FB_SYNC_HOR_HIGH_ACT) != 0;
+	rinfo->panel_info.vAct_high =
+		(var->sync & FB_SYNC_VERT_HIGH_ACT) != 0;
+	rinfo->panel_info.valid = 1;
+	/* We use a default of 200ms for the panel power delay, 
+	 * I need to have a real schedule() instead of mdelay's in the panel code.
+	 * we might be possible to figure out a better power delay either from
+	 * MacOS OF tree or from the EDID block (proprietary extensions ?)
+	 */
+	rinfo->panel_info.pwr_delay = 200;
+}
+
+static void radeon_videomode_to_var(struct fb_var_screeninfo *var,
+				    const struct fb_videomode *mode)
+{
+	var->xres = mode->xres;
+	var->yres = mode->yres;
+	var->xres_virtual = mode->xres;
+	var->yres_virtual = mode->yres;
+	var->xoffset = 0;
+	var->yoffset = 0;
+	var->pixclock = mode->pixclock;
+	var->left_margin = mode->left_margin;
+	var->right_margin = mode->right_margin;
+	var->upper_margin = mode->upper_margin;
+	var->lower_margin = mode->lower_margin;
+	var->hsync_len = mode->hsync_len;
+	var->vsync_len = mode->vsync_len;
+	var->sync = mode->sync;
+	var->vmode = mode->vmode;
+}
+
+/*
+ * Build the modedb for head 1 (head 2 will come later), check panel infos
+ * from either BIOS or EDID, and pick up the default mode
+ */
+void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_option)
+{
+	struct fb_info * info = rinfo->info;
+	int has_default_mode = 0;
+
+	/*
+	 * Fill default var first
+	 */
+	info->var = radeonfb_default_var;
+	INIT_LIST_HEAD(&info->modelist);
+
+	/*
+	 * First check out what BIOS has to say
+	 */
+	if (rinfo->mon1_type == MT_LCD)
+		radeon_get_panel_info_BIOS(rinfo);
+
+	/*
+	 * Parse EDID detailed timings and deduce panel infos if any. Right now
+	 * we only deal with first entry returned by parse_EDID, we may do better
+	 * some day...
+	 */
+	if (!rinfo->panel_info.use_bios_dividers && rinfo->mon1_type != MT_CRT
+	    && rinfo->mon1_EDID) {
+		struct fb_var_screeninfo var;
+		RTRACE("Parsing EDID data for panel info\n");
+		if (fb_parse_edid(rinfo->mon1_EDID, &var) == 0) {
+			if (var.xres >= rinfo->panel_info.xres &&
+			    var.yres >= rinfo->panel_info.yres)
+				radeon_var_to_panel_info(rinfo, &var);
+		}
+	}
+
+	/*
+	 * Do any additional platform/arch fixups to the panel infos
+	 */
+	radeon_fixup_panel_info(rinfo);
+
+	/*
+	 * If we have some valid panel infos, we setup the default mode based on
+	 * those
+	 */
+	if (rinfo->mon1_type != MT_CRT && rinfo->panel_info.valid) {
+		struct fb_var_screeninfo *var = &info->var;
+
+		RTRACE("Setting up default mode based on panel info\n");
+		var->xres = rinfo->panel_info.xres;
+		var->yres = rinfo->panel_info.yres;
+		var->xres_virtual = rinfo->panel_info.xres;
+		var->yres_virtual = rinfo->panel_info.yres;
+		var->xoffset = var->yoffset = 0;
+		var->bits_per_pixel = 8;
+		var->pixclock = 100000000 / rinfo->panel_info.clock;
+		var->left_margin = (rinfo->panel_info.hblank - rinfo->panel_info.hOver_plus
+				    - rinfo->panel_info.hSync_width);
+		var->right_margin = rinfo->panel_info.hOver_plus;
+		var->upper_margin = (rinfo->panel_info.vblank - rinfo->panel_info.vOver_plus
+				     - rinfo->panel_info.vSync_width);
+		var->lower_margin = rinfo->panel_info.vOver_plus;
+		var->hsync_len = rinfo->panel_info.hSync_width;
+		var->vsync_len = rinfo->panel_info.vSync_width;
+		var->sync = 0;
+		if (rinfo->panel_info.hAct_high)
+			var->sync |= FB_SYNC_HOR_HIGH_ACT;
+		if (rinfo->panel_info.vAct_high)
+			var->sync |= FB_SYNC_VERT_HIGH_ACT;
+		var->vmode = 0;
+		has_default_mode = 1;
+	}
+
+	/*
+	 * Now build modedb from EDID
+	 */
+	if (rinfo->mon1_EDID) {
+		fb_edid_to_monspecs(rinfo->mon1_EDID, &info->monspecs);
+		fb_videomode_to_modelist(info->monspecs.modedb,
+					 info->monspecs.modedb_len,
+					 &info->modelist);
+		rinfo->mon1_modedb = info->monspecs.modedb;
+		rinfo->mon1_dbsize = info->monspecs.modedb_len;
+	}
+
+	
+	/*
+	 * Finally, if we don't have panel infos we need to figure some (or
+	 * we try to read it from card), we try to pick a default mode
+	 * and create some panel infos. Whatever...
+	 */
+	if (rinfo->mon1_type != MT_CRT && !rinfo->panel_info.valid) {
+		struct fb_videomode	*modedb;
+		int			dbsize;
+		char			modename[32];
+
+		RTRACE("Guessing panel info...\n");
+		if (rinfo->panel_info.xres == 0 || rinfo->panel_info.yres == 0) {
+			u32 tmp = INREG(FP_HORZ_STRETCH) & HORZ_PANEL_SIZE;
+			rinfo->panel_info.xres = ((tmp >> HORZ_PANEL_SHIFT) + 1) * 8;
+			tmp = INREG(FP_VERT_STRETCH) & VERT_PANEL_SIZE;
+			rinfo->panel_info.yres = (tmp >> VERT_PANEL_SHIFT) + 1;
+		}
+		if (rinfo->panel_info.xres == 0 || rinfo->panel_info.yres == 0) {
+			printk(KERN_WARNING "radeonfb: Can't find panel size, going back to CRT\n");
+			rinfo->mon1_type = MT_CRT;
+			goto pickup_default;
+		}
+		printk(KERN_WARNING "radeonfb: Assuming panel size %dx%d\n",
+		       rinfo->panel_info.xres, rinfo->panel_info.yres);
+		modedb = rinfo->mon1_modedb;
+		dbsize = rinfo->mon1_dbsize;
+		snprintf(modename, 31, "%dx%d", rinfo->panel_info.xres, rinfo->panel_info.yres);
+		if (fb_find_mode(&info->var, info, modename,
+				 modedb, dbsize, NULL, 8) == 0) {
+			printk(KERN_WARNING "radeonfb: Can't find mode for panel size, going back to CRT\n");
+			rinfo->mon1_type = MT_CRT;
+			goto pickup_default;
+		}
+		has_default_mode = 1;
+		radeon_var_to_panel_info(rinfo, &info->var);
+	}
+
+ pickup_default:
+	/*
+	 * Apply passed-in mode option if any
+	 */
+	if (mode_option) {
+		if (fb_find_mode(&info->var, info, mode_option,
+				 info->monspecs.modedb,
+				 info->monspecs.modedb_len, NULL, 8) != 0)
+			has_default_mode = 1;
+ 	}
+
+	/*
+	 * Still no mode, let's pick up a default from the db
+	 */
+	if (!has_default_mode && info->monspecs.modedb != NULL) {
+		struct fb_monspecs *specs = &info->monspecs;
+		struct fb_videomode *modedb = NULL;
+
+		/* get preferred timing */
+		if (specs->misc & FB_MISC_1ST_DETAIL) {
+			int i;
+
+			for (i = 0; i < specs->modedb_len; i++) {
+				if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {
+					modedb = &specs->modedb[i];
+					break;
+				}
+			}
+		} else {
+			/* otherwise, get first mode in database */
+			modedb = &specs->modedb[0];
+		}
+		if (modedb != NULL) {
+			info->var.bits_per_pixel = 8;
+			radeon_videomode_to_var(&info->var, modedb);
+			has_default_mode = 1;
+		}
+	}
+	if (1) {
+		struct fb_videomode mode;
+		/* Make sure that whatever mode got selected is actually in the
+		 * modelist or the kernel may die
+		 */
+		fb_var_to_videomode(&mode, &info->var);
+		fb_add_videomode(&mode, &info->modelist);
+	}
+}
+
+/*
+ * The code below is used to pick up a mode in check_var and
+ * set_var. It should be made generic
+ */
+
+/*
+ * This is used when looking for modes. We assign a "distance" value
+ * to a mode in the modedb depending how "close" it is from what we
+ * are looking for.
+ * Currently, we don't compare that much, we could do better but
+ * the current fbcon doesn't quite mind ;)
+ */
+static int radeon_compare_modes(const struct fb_var_screeninfo *var,
+				const struct fb_videomode *mode)
+{
+	int distance = 0;
+
+	distance = mode->yres - var->yres;
+	distance += (mode->xres - var->xres)/2;
+	return distance;
+}
+
+/*
+ * This function is called by check_var, it gets the passed in mode parameter, and
+ * outputs a valid mode matching the passed-in one as closely as possible.
+ * We need something better ultimately. Things like fbcon basically pass us out
+ * current mode with xres/yres hacked, while things like XFree will actually
+ * produce a full timing that we should respect as much as possible.
+ *
+ * This is why I added the FB_ACTIVATE_FIND that is used by fbcon. Without this,
+ * we do a simple spec match, that's all. With it, we actually look for a mode in
+ * either our monitor modedb or the vesa one if none
+ *
+ */
+int  radeon_match_mode(struct radeonfb_info *rinfo,
+		       struct fb_var_screeninfo *dest,
+		       const struct fb_var_screeninfo *src)
+{
+	const struct fb_videomode	*db = vesa_modes;
+	int				i, dbsize = 34;
+	int				has_rmx, native_db = 0;
+	int				distance = INT_MAX;
+	const struct fb_videomode	*candidate = NULL;
+
+	/* Start with a copy of the requested mode */
+	memcpy(dest, src, sizeof(struct fb_var_screeninfo));
+
+	/* Check if we have a modedb built from EDID */
+	if (rinfo->mon1_modedb) {
+		db = rinfo->mon1_modedb;
+		dbsize = rinfo->mon1_dbsize;
+		native_db = 1;
+	}
+
+	/* Check if we have a scaler allowing any fancy mode */
+	has_rmx = rinfo->mon1_type == MT_LCD || rinfo->mon1_type == MT_DFP;
+
+	/* If we have a scaler and are passed FB_ACTIVATE_TEST or
+	 * FB_ACTIVATE_NOW, just do basic checking and return if the
+	 * mode match
+	 */
+	if ((src->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST ||
+	    (src->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+		/* We don't have an RMX, validate timings. If we don't have
+	 	 * monspecs, we should be paranoid and not let use go above
+		 * 640x480-60, but I assume userland knows what it's doing here
+		 * (though I may be proven wrong...)
+		 */
+		if (has_rmx == 0 && rinfo->mon1_modedb)
+			if (fb_validate_mode((struct fb_var_screeninfo *)src, rinfo->info))
+				return -EINVAL;
+		return 0;
+	}
+
+	/* Now look for a mode in the database */
+	while (db) {
+		for (i = 0; i < dbsize; i++) {
+			int d;
+
+			if (db[i].yres < src->yres)
+				continue;	
+			if (db[i].xres < src->xres)
+				continue;
+			d = radeon_compare_modes(src, &db[i]);
+			/* If the new mode is at least as good as the previous one,
+			 * then it's our new candidate
+			 */
+			if (d < distance) {
+				candidate = &db[i];
+				distance = d;
+			}
+		}
+		db = NULL;
+		/* If we have a scaler, we allow any mode from the database */
+		if (native_db && has_rmx) {
+			db = vesa_modes;
+			dbsize = 34;
+			native_db = 0;
+		}
+	}
+
+	/* If we have found a match, return it */
+	if (candidate != NULL) {
+		radeon_videomode_to_var(dest, candidate);
+		return 0;
+	}
+
+	/* If we haven't and don't have a scaler, fail */
+	if (!has_rmx)
+		return -EINVAL;
+
+	return 0;
+}
diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c
new file mode 100644
index 0000000..23c677e
--- /dev/null
+++ b/drivers/video/aty/radeon_pm.c
@@ -0,0 +1,2801 @@
+/*
+ *	drivers/video/aty/radeon_pm.c
+ *
+ *	Copyright 2003,2004 Ben. Herrenschmidt <benh@kernel.crashing.org>
+ *	Copyright 2004 Paul Mackerras <paulus@samba.org>
+ *
+ *	This is the power management code for ATI radeon chipsets. It contains
+ *	some dynamic clock PM enable/disable code similar to what X.org does,
+ *	some D2-state (APM-style) sleep/wakeup code for use on some PowerMacs,
+ *	and the necessary bits to re-initialize from scratch a few chips found
+ *	on PowerMacs as well. The later could be extended to more platforms
+ *	provided the memory controller configuration code be made more generic,
+ *	and you can get the proper mode register commands for your RAMs.
+ *	Those things may be found in the BIOS image...
+ */
+
+#include "radeonfb.h"
+
+#include <linux/console.h>
+#include <linux/agp_backend.h>
+
+#ifdef CONFIG_PPC_PMAC
+#include <asm/processor.h>
+#include <asm/prom.h>
+#include <asm/pmac_feature.h>
+#endif
+
+#include "ati_ids.h"
+
+static void radeon_pm_disable_dynamic_mode(struct radeonfb_info *rinfo)
+{
+	u32 tmp;
+
+	/* RV100 */
+	if ((rinfo->family == CHIP_FAMILY_RV100) && (!rinfo->is_mobility)) {
+		if (rinfo->has_CRTC2) {
+			tmp = INPLL(pllSCLK_CNTL);
+			tmp &= ~SCLK_CNTL__DYN_STOP_LAT_MASK;
+			tmp |= SCLK_CNTL__CP_MAX_DYN_STOP_LAT | SCLK_CNTL__FORCEON_MASK;
+			OUTPLL(pllSCLK_CNTL, tmp);
+		}
+		tmp = INPLL(pllMCLK_CNTL);
+		tmp |= (MCLK_CNTL__FORCE_MCLKA |
+		        MCLK_CNTL__FORCE_MCLKB |
+		        MCLK_CNTL__FORCE_YCLKA |
+		        MCLK_CNTL__FORCE_YCLKB |
+			MCLK_CNTL__FORCE_AIC |
+			MCLK_CNTL__FORCE_MC);
+                OUTPLL(pllMCLK_CNTL, tmp);
+		return;
+	}
+	/* R100 */
+	if (!rinfo->has_CRTC2) {
+                tmp = INPLL(pllSCLK_CNTL);
+                tmp |= (SCLK_CNTL__FORCE_CP	| SCLK_CNTL__FORCE_HDP	|
+			SCLK_CNTL__FORCE_DISP1	| SCLK_CNTL__FORCE_TOP	|
+                        SCLK_CNTL__FORCE_E2	| SCLK_CNTL__FORCE_SE 	|
+			SCLK_CNTL__FORCE_IDCT	| SCLK_CNTL__FORCE_VIP	|
+			SCLK_CNTL__FORCE_RE	| SCLK_CNTL__FORCE_PB 	|
+			SCLK_CNTL__FORCE_TAM	| SCLK_CNTL__FORCE_TDM	|
+                        SCLK_CNTL__FORCE_RB);
+                OUTPLL(pllSCLK_CNTL, tmp);
+		return;
+	}
+	/* RV350 (M10) */
+	if (rinfo->family == CHIP_FAMILY_RV350) {
+                /* for RV350/M10, no delays are required. */
+                tmp = INPLL(pllSCLK_CNTL2);
+                tmp |= (SCLK_CNTL2__R300_FORCE_TCL |
+                        SCLK_CNTL2__R300_FORCE_GA  |
+			SCLK_CNTL2__R300_FORCE_CBA);
+                OUTPLL(pllSCLK_CNTL2, tmp);
+
+                tmp = INPLL(pllSCLK_CNTL);
+                tmp |= (SCLK_CNTL__FORCE_DISP2		| SCLK_CNTL__FORCE_CP		|
+                        SCLK_CNTL__FORCE_HDP		| SCLK_CNTL__FORCE_DISP1	|
+                        SCLK_CNTL__FORCE_TOP		| SCLK_CNTL__FORCE_E2		|
+                        SCLK_CNTL__R300_FORCE_VAP	| SCLK_CNTL__FORCE_IDCT    	|
+			SCLK_CNTL__FORCE_VIP		| SCLK_CNTL__R300_FORCE_SR	|
+			SCLK_CNTL__R300_FORCE_PX	| SCLK_CNTL__R300_FORCE_TX	|
+			SCLK_CNTL__R300_FORCE_US	| SCLK_CNTL__FORCE_TV_SCLK	|
+                        SCLK_CNTL__R300_FORCE_SU	| SCLK_CNTL__FORCE_OV0);
+                OUTPLL(pllSCLK_CNTL, tmp);
+
+                tmp = INPLL(pllSCLK_MORE_CNTL);
+		tmp |= (SCLK_MORE_CNTL__FORCE_DISPREGS	| SCLK_MORE_CNTL__FORCE_MC_GUI	|
+			SCLK_MORE_CNTL__FORCE_MC_HOST);
+                OUTPLL(pllSCLK_MORE_CNTL, tmp);
+
+		tmp = INPLL(pllMCLK_CNTL);
+		tmp |= (MCLK_CNTL__FORCE_MCLKA |
+		        MCLK_CNTL__FORCE_MCLKB |
+		        MCLK_CNTL__FORCE_YCLKA |
+		        MCLK_CNTL__FORCE_YCLKB |
+			MCLK_CNTL__FORCE_MC);
+                OUTPLL(pllMCLK_CNTL, tmp);
+
+                tmp = INPLL(pllVCLK_ECP_CNTL);
+                tmp &= ~(VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb  |
+                         VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb |
+			 VCLK_ECP_CNTL__R300_DISP_DAC_PIXCLK_DAC_BLANK_OFF);
+                OUTPLL(pllVCLK_ECP_CNTL, tmp);
+
+                tmp = INPLL(pllPIXCLKS_CNTL);
+                tmp &= ~(PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb		|
+			 PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb		|
+			 PIXCLKS_CNTL__DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb	|
+			 PIXCLKS_CNTL__R300_DVOCLK_ALWAYS_ONb		|
+			 PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb		|
+			 PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb		|
+			 PIXCLKS_CNTL__R300_PIXCLK_DVO_ALWAYS_ONb	|
+			 PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb		|
+			 PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb		|
+			 PIXCLKS_CNTL__R300_PIXCLK_TRANS_ALWAYS_ONb	|
+			 PIXCLKS_CNTL__R300_PIXCLK_TVO_ALWAYS_ONb	|
+			 PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb		|
+			 PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb		|
+			 PIXCLKS_CNTL__R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF);
+                OUTPLL(pllPIXCLKS_CNTL, tmp);
+
+		return;
+	}
+	
+	/* Default */
+
+	/* Force Core Clocks */
+	tmp = INPLL(pllSCLK_CNTL);
+	tmp |= (SCLK_CNTL__FORCE_CP | SCLK_CNTL__FORCE_E2);
+
+	/* XFree doesn't do that case, but we had this code from Apple and it
+	 * seem necessary for proper suspend/resume operations
+	 */
+	if (rinfo->is_mobility) {
+		tmp |= 	SCLK_CNTL__FORCE_HDP|
+			SCLK_CNTL__FORCE_DISP1|
+			SCLK_CNTL__FORCE_DISP2|
+			SCLK_CNTL__FORCE_TOP|
+			SCLK_CNTL__FORCE_SE|
+			SCLK_CNTL__FORCE_IDCT|
+			SCLK_CNTL__FORCE_VIP|
+			SCLK_CNTL__FORCE_PB|
+			SCLK_CNTL__FORCE_RE|
+			SCLK_CNTL__FORCE_TAM|
+			SCLK_CNTL__FORCE_TDM|
+			SCLK_CNTL__FORCE_RB|
+			SCLK_CNTL__FORCE_TV_SCLK|
+			SCLK_CNTL__FORCE_SUBPIC|
+			SCLK_CNTL__FORCE_OV0;
+	}
+	else if (rinfo->family == CHIP_FAMILY_R300 ||
+		   rinfo->family == CHIP_FAMILY_R350) {
+		tmp |=  SCLK_CNTL__FORCE_HDP   |
+			SCLK_CNTL__FORCE_DISP1 |
+			SCLK_CNTL__FORCE_DISP2 |
+			SCLK_CNTL__FORCE_TOP   |
+			SCLK_CNTL__FORCE_IDCT  |
+			SCLK_CNTL__FORCE_VIP;
+	}
+    	OUTPLL(pllSCLK_CNTL, tmp);
+	radeon_msleep(16);
+
+	if (rinfo->family == CHIP_FAMILY_R300 || rinfo->family == CHIP_FAMILY_R350) {
+		tmp = INPLL(pllSCLK_CNTL2);
+		tmp |=  SCLK_CNTL2__R300_FORCE_TCL |
+			SCLK_CNTL2__R300_FORCE_GA  |
+			SCLK_CNTL2__R300_FORCE_CBA;
+		OUTPLL(pllSCLK_CNTL2, tmp);
+		radeon_msleep(16);
+	}
+
+	tmp = INPLL(pllCLK_PIN_CNTL);
+	tmp &= ~CLK_PIN_CNTL__SCLK_DYN_START_CNTL;
+	OUTPLL(pllCLK_PIN_CNTL, tmp);
+	radeon_msleep(15);
+
+	if (rinfo->is_IGP) {
+		/* Weird  ... X is _un_ forcing clocks here, I think it's
+		 * doing backward. Imitate it for now...
+		 */
+		tmp = INPLL(pllMCLK_CNTL);
+		tmp &= ~(MCLK_CNTL__FORCE_MCLKA |
+			 MCLK_CNTL__FORCE_YCLKA);
+		OUTPLL(pllMCLK_CNTL, tmp);
+		radeon_msleep(16);
+	}
+	/* Hrm... same shit, X doesn't do that but I have to */
+	else if (rinfo->is_mobility) {
+		tmp = INPLL(pllMCLK_CNTL);
+		tmp |= (MCLK_CNTL__FORCE_MCLKA |
+			MCLK_CNTL__FORCE_MCLKB |
+			MCLK_CNTL__FORCE_YCLKA |
+			MCLK_CNTL__FORCE_YCLKB);
+		OUTPLL(pllMCLK_CNTL, tmp);
+		radeon_msleep(16);
+
+		tmp = INPLL(pllMCLK_MISC);
+		tmp &= 	~(MCLK_MISC__MC_MCLK_MAX_DYN_STOP_LAT|
+			  MCLK_MISC__IO_MCLK_MAX_DYN_STOP_LAT|
+			  MCLK_MISC__MC_MCLK_DYN_ENABLE|
+			  MCLK_MISC__IO_MCLK_DYN_ENABLE);
+		OUTPLL(pllMCLK_MISC, tmp);
+		radeon_msleep(15);
+	}
+
+	if (rinfo->is_mobility) {
+		tmp = INPLL(pllSCLK_MORE_CNTL);
+		tmp |= 	SCLK_MORE_CNTL__FORCE_DISPREGS|
+			SCLK_MORE_CNTL__FORCE_MC_GUI|
+			SCLK_MORE_CNTL__FORCE_MC_HOST;
+		OUTPLL(pllSCLK_MORE_CNTL, tmp);
+		radeon_msleep(16);
+	}
+
+	tmp = INPLL(pllPIXCLKS_CNTL);
+	tmp &= ~(PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb |
+		 PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb|
+		 PIXCLKS_CNTL__PIXCLK_DIG_TMDS_ALWAYS_ONb |
+		 PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb|
+		 PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb|
+		 PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb|
+		 PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb);
+ 	OUTPLL(pllPIXCLKS_CNTL, tmp);
+	radeon_msleep(16);
+
+	tmp = INPLL( pllVCLK_ECP_CNTL);
+	tmp &= ~(VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb |
+		 VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb);
+	OUTPLL( pllVCLK_ECP_CNTL, tmp);
+	radeon_msleep(16);
+}
+
+static void radeon_pm_enable_dynamic_mode(struct radeonfb_info *rinfo)
+{
+	u32 tmp;
+
+	/* R100 */
+	if (!rinfo->has_CRTC2) {
+                tmp = INPLL(pllSCLK_CNTL);
+
+		if ((INREG(CONFIG_CNTL) & CFG_ATI_REV_ID_MASK) > CFG_ATI_REV_A13)
+                    tmp &= ~(SCLK_CNTL__FORCE_CP	| SCLK_CNTL__FORCE_RB);
+                tmp &= ~(SCLK_CNTL__FORCE_HDP		| SCLK_CNTL__FORCE_DISP1 |
+			 SCLK_CNTL__FORCE_TOP		| SCLK_CNTL__FORCE_SE   |
+			 SCLK_CNTL__FORCE_IDCT		| SCLK_CNTL__FORCE_RE   |
+			 SCLK_CNTL__FORCE_PB		| SCLK_CNTL__FORCE_TAM  |
+			 SCLK_CNTL__FORCE_TDM);
+                OUTPLL(pllSCLK_CNTL, tmp);
+		return;
+	}
+
+	/* M10 */
+	if (rinfo->family == CHIP_FAMILY_RV350) {
+		tmp = INPLL(pllSCLK_CNTL2);
+		tmp &= ~(SCLK_CNTL2__R300_FORCE_TCL |
+			 SCLK_CNTL2__R300_FORCE_GA  |
+			 SCLK_CNTL2__R300_FORCE_CBA);
+		tmp |=  (SCLK_CNTL2__R300_TCL_MAX_DYN_STOP_LAT |
+			 SCLK_CNTL2__R300_GA_MAX_DYN_STOP_LAT  |
+			 SCLK_CNTL2__R300_CBA_MAX_DYN_STOP_LAT);
+		OUTPLL(pllSCLK_CNTL2, tmp);
+
+		tmp = INPLL(pllSCLK_CNTL);
+		tmp &= ~(SCLK_CNTL__FORCE_DISP2 | SCLK_CNTL__FORCE_CP      |
+			 SCLK_CNTL__FORCE_HDP   | SCLK_CNTL__FORCE_DISP1   |
+			 SCLK_CNTL__FORCE_TOP   | SCLK_CNTL__FORCE_E2      |
+			 SCLK_CNTL__R300_FORCE_VAP | SCLK_CNTL__FORCE_IDCT |
+			 SCLK_CNTL__FORCE_VIP   | SCLK_CNTL__R300_FORCE_SR |
+			 SCLK_CNTL__R300_FORCE_PX | SCLK_CNTL__R300_FORCE_TX |
+			 SCLK_CNTL__R300_FORCE_US | SCLK_CNTL__FORCE_TV_SCLK |
+			 SCLK_CNTL__R300_FORCE_SU | SCLK_CNTL__FORCE_OV0);
+		tmp |= SCLK_CNTL__DYN_STOP_LAT_MASK;
+		OUTPLL(pllSCLK_CNTL, tmp);
+
+		tmp = INPLL(pllSCLK_MORE_CNTL);
+		tmp &= ~SCLK_MORE_CNTL__FORCEON;
+		tmp |=  SCLK_MORE_CNTL__DISPREGS_MAX_DYN_STOP_LAT |
+			SCLK_MORE_CNTL__MC_GUI_MAX_DYN_STOP_LAT |
+			SCLK_MORE_CNTL__MC_HOST_MAX_DYN_STOP_LAT;
+		OUTPLL(pllSCLK_MORE_CNTL, tmp);
+
+		tmp = INPLL(pllVCLK_ECP_CNTL);
+		tmp |= (VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb |
+			VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb);
+		OUTPLL(pllVCLK_ECP_CNTL, tmp);
+
+		tmp = INPLL(pllPIXCLKS_CNTL);
+		tmp |= (PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb         |
+			PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb     |
+			PIXCLKS_CNTL__DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb |
+			PIXCLKS_CNTL__R300_DVOCLK_ALWAYS_ONb            |
+			PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb    |
+			PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb       |
+			PIXCLKS_CNTL__R300_PIXCLK_DVO_ALWAYS_ONb        |
+			PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb     |
+			PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb     |
+			PIXCLKS_CNTL__R300_PIXCLK_TRANS_ALWAYS_ONb      |
+			PIXCLKS_CNTL__R300_PIXCLK_TVO_ALWAYS_ONb        |
+			PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb           |
+			PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb);
+		OUTPLL(pllPIXCLKS_CNTL, tmp);
+
+		tmp = INPLL(pllMCLK_MISC);
+		tmp |= (MCLK_MISC__MC_MCLK_DYN_ENABLE |
+			MCLK_MISC__IO_MCLK_DYN_ENABLE);
+		OUTPLL(pllMCLK_MISC, tmp);
+
+		tmp = INPLL(pllMCLK_CNTL);
+		tmp |= (MCLK_CNTL__FORCE_MCLKA | MCLK_CNTL__FORCE_MCLKB);
+		tmp &= ~(MCLK_CNTL__FORCE_YCLKA  |
+			 MCLK_CNTL__FORCE_YCLKB  |
+			 MCLK_CNTL__FORCE_MC);
+
+		/* Some releases of vbios have set DISABLE_MC_MCLKA
+		 * and DISABLE_MC_MCLKB bits in the vbios table.  Setting these
+		 * bits will cause H/W hang when reading video memory with dynamic
+		 * clocking enabled.
+		 */
+		if ((tmp & MCLK_CNTL__R300_DISABLE_MC_MCLKA) &&
+		    (tmp & MCLK_CNTL__R300_DISABLE_MC_MCLKB)) {
+			/* If both bits are set, then check the active channels */
+			tmp = INPLL(pllMCLK_CNTL);
+			if (rinfo->vram_width == 64) {
+			    if (INREG(MEM_CNTL) & R300_MEM_USE_CD_CH_ONLY)
+				tmp &= ~MCLK_CNTL__R300_DISABLE_MC_MCLKB;
+			    else
+				tmp &= ~MCLK_CNTL__R300_DISABLE_MC_MCLKA;
+			} else {
+			    tmp &= ~(MCLK_CNTL__R300_DISABLE_MC_MCLKA |
+				     MCLK_CNTL__R300_DISABLE_MC_MCLKB);
+			}
+		}
+		OUTPLL(pllMCLK_CNTL, tmp);
+		return;
+	}
+
+	/* R300 */
+	if (rinfo->family == CHIP_FAMILY_R300 || rinfo->family == CHIP_FAMILY_R350) {
+		tmp = INPLL(pllSCLK_CNTL);
+		tmp &= ~(SCLK_CNTL__R300_FORCE_VAP);
+		tmp |= SCLK_CNTL__FORCE_CP;
+		OUTPLL(pllSCLK_CNTL, tmp);
+		radeon_msleep(15);
+
+		tmp = INPLL(pllSCLK_CNTL2);
+		tmp &= ~(SCLK_CNTL2__R300_FORCE_TCL |
+			 SCLK_CNTL2__R300_FORCE_GA  |
+			 SCLK_CNTL2__R300_FORCE_CBA);
+		OUTPLL(pllSCLK_CNTL2, tmp);
+	}
+
+	/* Others */
+
+	tmp = INPLL( pllCLK_PWRMGT_CNTL);
+	tmp &= ~(CLK_PWRMGT_CNTL__ACTIVE_HILO_LAT_MASK|
+		 CLK_PWRMGT_CNTL__DISP_DYN_STOP_LAT_MASK|
+		 CLK_PWRMGT_CNTL__DYN_STOP_MODE_MASK);
+	tmp |= CLK_PWRMGT_CNTL__ENGINE_DYNCLK_MODE_MASK |
+	       (0x01 << CLK_PWRMGT_CNTL__ACTIVE_HILO_LAT__SHIFT);
+	OUTPLL( pllCLK_PWRMGT_CNTL, tmp);
+	radeon_msleep(15);
+
+	tmp = INPLL(pllCLK_PIN_CNTL);
+	tmp |= CLK_PIN_CNTL__SCLK_DYN_START_CNTL;
+	OUTPLL(pllCLK_PIN_CNTL, tmp);
+	radeon_msleep(15);
+
+	/* When DRI is enabled, setting DYN_STOP_LAT to zero can cause some R200
+	 * to lockup randomly, leave them as set by BIOS.
+	 */
+	tmp = INPLL(pllSCLK_CNTL);
+	tmp &= ~SCLK_CNTL__FORCEON_MASK;
+
+	/*RAGE_6::A11 A12 A12N1 A13, RV250::A11 A12, R300*/
+	if ((rinfo->family == CHIP_FAMILY_RV250 &&
+	     ((INREG(CONFIG_CNTL) & CFG_ATI_REV_ID_MASK) < CFG_ATI_REV_A13)) ||
+	    ((rinfo->family == CHIP_FAMILY_RV100) &&
+	     ((INREG(CONFIG_CNTL) & CFG_ATI_REV_ID_MASK) <= CFG_ATI_REV_A13))) {
+		tmp |= SCLK_CNTL__FORCE_CP;
+		tmp |= SCLK_CNTL__FORCE_VIP;
+	}
+	OUTPLL(pllSCLK_CNTL, tmp);
+	radeon_msleep(15);
+
+	if ((rinfo->family == CHIP_FAMILY_RV200) ||
+	    (rinfo->family == CHIP_FAMILY_RV250) ||
+	    (rinfo->family == CHIP_FAMILY_RV280)) {
+		tmp = INPLL(pllSCLK_MORE_CNTL);
+		tmp &= ~SCLK_MORE_CNTL__FORCEON;
+
+		/* RV200::A11 A12 RV250::A11 A12 */
+		if (((rinfo->family == CHIP_FAMILY_RV200) ||
+		     (rinfo->family == CHIP_FAMILY_RV250)) &&
+		    ((INREG(CONFIG_CNTL) & CFG_ATI_REV_ID_MASK) < CFG_ATI_REV_A13))
+			tmp |= SCLK_MORE_CNTL__FORCEON;
+
+		OUTPLL(pllSCLK_MORE_CNTL, tmp);
+		radeon_msleep(15);
+	}
+	
+
+	/* RV200::A11 A12, RV250::A11 A12 */
+	if (((rinfo->family == CHIP_FAMILY_RV200) ||
+	     (rinfo->family == CHIP_FAMILY_RV250)) &&
+	    ((INREG(CONFIG_CNTL) & CFG_ATI_REV_ID_MASK) < CFG_ATI_REV_A13)) {
+		tmp = INPLL(pllPLL_PWRMGT_CNTL);
+		tmp |= PLL_PWRMGT_CNTL__TCL_BYPASS_DISABLE;
+		OUTPLL(pllPLL_PWRMGT_CNTL, tmp);
+		radeon_msleep(15);
+	}
+
+	tmp = INPLL(pllPIXCLKS_CNTL);
+	tmp |=  PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb |
+		PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb|
+		PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb|
+		PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb|
+		PIXCLKS_CNTL__PIXCLK_DIG_TMDS_ALWAYS_ONb|
+		PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb|
+		PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb;
+	OUTPLL(pllPIXCLKS_CNTL, tmp);
+	radeon_msleep(15);
+		
+	tmp = INPLL(pllVCLK_ECP_CNTL);
+	tmp |=  VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb |
+		VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb;
+	OUTPLL(pllVCLK_ECP_CNTL, tmp);
+
+	/* X doesn't do that ... hrm, we do on mobility && Macs */
+#ifdef CONFIG_PPC_OF
+	if (rinfo->is_mobility) {
+		tmp  = INPLL(pllMCLK_CNTL);
+		tmp &= ~(MCLK_CNTL__FORCE_MCLKA |
+			 MCLK_CNTL__FORCE_MCLKB |
+			 MCLK_CNTL__FORCE_YCLKA |
+			 MCLK_CNTL__FORCE_YCLKB);
+		OUTPLL(pllMCLK_CNTL, tmp);
+		radeon_msleep(15);
+
+		tmp = INPLL(pllMCLK_MISC);
+		tmp |= 	MCLK_MISC__MC_MCLK_MAX_DYN_STOP_LAT|
+			MCLK_MISC__IO_MCLK_MAX_DYN_STOP_LAT|
+			MCLK_MISC__MC_MCLK_DYN_ENABLE|
+			MCLK_MISC__IO_MCLK_DYN_ENABLE;
+		OUTPLL(pllMCLK_MISC, tmp);
+		radeon_msleep(15);
+	}
+#endif /* CONFIG_PPC_OF */
+}
+
+#ifdef CONFIG_PM
+
+static void OUTMC( struct radeonfb_info *rinfo, u8 indx, u32 value)
+{
+	OUTREG( MC_IND_INDEX, indx | MC_IND_INDEX__MC_IND_WR_EN);	
+	OUTREG( MC_IND_DATA, value);		
+}
+
+static u32 INMC(struct radeonfb_info *rinfo, u8 indx)
+{
+	OUTREG( MC_IND_INDEX, indx);					
+	return INREG( MC_IND_DATA);
+}
+
+static void radeon_pm_save_regs(struct radeonfb_info *rinfo, int saving_for_d3)
+{
+	rinfo->save_regs[0] = INPLL(PLL_PWRMGT_CNTL);
+	rinfo->save_regs[1] = INPLL(CLK_PWRMGT_CNTL);
+	rinfo->save_regs[2] = INPLL(MCLK_CNTL);
+	rinfo->save_regs[3] = INPLL(SCLK_CNTL);
+	rinfo->save_regs[4] = INPLL(CLK_PIN_CNTL);
+	rinfo->save_regs[5] = INPLL(VCLK_ECP_CNTL);
+	rinfo->save_regs[6] = INPLL(PIXCLKS_CNTL);
+	rinfo->save_regs[7] = INPLL(MCLK_MISC);
+	rinfo->save_regs[8] = INPLL(P2PLL_CNTL);
+	
+	rinfo->save_regs[9] = INREG(DISP_MISC_CNTL);
+	rinfo->save_regs[10] = INREG(DISP_PWR_MAN);
+	rinfo->save_regs[11] = INREG(LVDS_GEN_CNTL);
+	rinfo->save_regs[13] = INREG(TV_DAC_CNTL);
+	rinfo->save_regs[14] = INREG(BUS_CNTL1);
+	rinfo->save_regs[15] = INREG(CRTC_OFFSET_CNTL);
+	rinfo->save_regs[16] = INREG(AGP_CNTL);
+	rinfo->save_regs[17] = (INREG(CRTC_GEN_CNTL) & 0xfdffffff) | 0x04000000;
+	rinfo->save_regs[18] = (INREG(CRTC2_GEN_CNTL) & 0xfdffffff) | 0x04000000;
+	rinfo->save_regs[19] = INREG(GPIOPAD_A);
+	rinfo->save_regs[20] = INREG(GPIOPAD_EN);
+	rinfo->save_regs[21] = INREG(GPIOPAD_MASK);
+	rinfo->save_regs[22] = INREG(ZV_LCDPAD_A);
+	rinfo->save_regs[23] = INREG(ZV_LCDPAD_EN);
+	rinfo->save_regs[24] = INREG(ZV_LCDPAD_MASK);
+	rinfo->save_regs[25] = INREG(GPIO_VGA_DDC);
+	rinfo->save_regs[26] = INREG(GPIO_DVI_DDC);
+	rinfo->save_regs[27] = INREG(GPIO_MONID);
+	rinfo->save_regs[28] = INREG(GPIO_CRT2_DDC);
+
+	rinfo->save_regs[29] = INREG(SURFACE_CNTL);
+	rinfo->save_regs[30] = INREG(MC_FB_LOCATION);
+	rinfo->save_regs[31] = INREG(DISPLAY_BASE_ADDR);
+	rinfo->save_regs[32] = INREG(MC_AGP_LOCATION);
+	rinfo->save_regs[33] = INREG(CRTC2_DISPLAY_BASE_ADDR);
+
+	rinfo->save_regs[34] = INPLL(SCLK_MORE_CNTL);
+	rinfo->save_regs[35] = INREG(MEM_SDRAM_MODE_REG);
+	rinfo->save_regs[36] = INREG(BUS_CNTL);
+	rinfo->save_regs[39] = INREG(RBBM_CNTL);
+	rinfo->save_regs[40] = INREG(DAC_CNTL);
+	rinfo->save_regs[41] = INREG(HOST_PATH_CNTL);
+	rinfo->save_regs[37] = INREG(MPP_TB_CONFIG);
+	rinfo->save_regs[38] = INREG(FCP_CNTL);
+
+	if (rinfo->is_mobility) {
+		rinfo->save_regs[12] = INREG(LVDS_PLL_CNTL);
+		rinfo->save_regs[43] = INPLL(pllSSPLL_CNTL);
+		rinfo->save_regs[44] = INPLL(pllSSPLL_REF_DIV);
+		rinfo->save_regs[45] = INPLL(pllSSPLL_DIV_0);
+		rinfo->save_regs[90] = INPLL(pllSS_INT_CNTL);
+		rinfo->save_regs[91] = INPLL(pllSS_TST_CNTL);
+		rinfo->save_regs[81] = INREG(LVDS_GEN_CNTL);
+	}
+
+	if (rinfo->family >= CHIP_FAMILY_RV200) {
+		rinfo->save_regs[42] = INREG(MEM_REFRESH_CNTL);
+		rinfo->save_regs[46] = INREG(MC_CNTL);
+		rinfo->save_regs[47] = INREG(MC_INIT_GFX_LAT_TIMER);
+		rinfo->save_regs[48] = INREG(MC_INIT_MISC_LAT_TIMER);
+		rinfo->save_regs[49] = INREG(MC_TIMING_CNTL);
+		rinfo->save_regs[50] = INREG(MC_READ_CNTL_AB);
+		rinfo->save_regs[51] = INREG(MC_IOPAD_CNTL);
+		rinfo->save_regs[52] = INREG(MC_CHIP_IO_OE_CNTL_AB);
+		rinfo->save_regs[53] = INREG(MC_DEBUG);
+	}
+	rinfo->save_regs[54] = INREG(PAMAC0_DLY_CNTL);
+	rinfo->save_regs[55] = INREG(PAMAC1_DLY_CNTL);
+	rinfo->save_regs[56] = INREG(PAD_CTLR_MISC);
+	rinfo->save_regs[57] = INREG(FW_CNTL);
+
+	if (rinfo->family >= CHIP_FAMILY_R300) {
+		rinfo->save_regs[58] = INMC(rinfo, ixR300_MC_MC_INIT_WR_LAT_TIMER);
+		rinfo->save_regs[59] = INMC(rinfo, ixR300_MC_IMP_CNTL);
+		rinfo->save_regs[60] = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_C0);
+		rinfo->save_regs[61] = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_C1);
+		rinfo->save_regs[62] = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_D0);
+		rinfo->save_regs[63] = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_D1);
+		rinfo->save_regs[64] = INMC(rinfo, ixR300_MC_BIST_CNTL_3);
+		rinfo->save_regs[65] = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_A0);
+		rinfo->save_regs[66] = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_A1);
+		rinfo->save_regs[67] = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_B0);
+		rinfo->save_regs[68] = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_B1);
+		rinfo->save_regs[69] = INMC(rinfo, ixR300_MC_DEBUG_CNTL);
+		rinfo->save_regs[70] = INMC(rinfo, ixR300_MC_DLL_CNTL);
+		rinfo->save_regs[71] = INMC(rinfo, ixR300_MC_IMP_CNTL_0);
+		rinfo->save_regs[72] = INMC(rinfo, ixR300_MC_ELPIDA_CNTL);
+		rinfo->save_regs[96] = INMC(rinfo, ixR300_MC_READ_CNTL_CD);
+	} else {
+		rinfo->save_regs[59] = INMC(rinfo, ixMC_IMP_CNTL);
+		rinfo->save_regs[65] = INMC(rinfo, ixMC_CHP_IO_CNTL_A0);
+		rinfo->save_regs[66] = INMC(rinfo, ixMC_CHP_IO_CNTL_A1);
+		rinfo->save_regs[67] = INMC(rinfo, ixMC_CHP_IO_CNTL_B0);
+		rinfo->save_regs[68] = INMC(rinfo, ixMC_CHP_IO_CNTL_B1);
+		rinfo->save_regs[71] = INMC(rinfo, ixMC_IMP_CNTL_0);
+	}
+
+	rinfo->save_regs[73] = INPLL(pllMPLL_CNTL);
+	rinfo->save_regs[74] = INPLL(pllSPLL_CNTL);
+	rinfo->save_regs[75] = INPLL(pllMPLL_AUX_CNTL);
+	rinfo->save_regs[76] = INPLL(pllSPLL_AUX_CNTL);
+	rinfo->save_regs[77] = INPLL(pllM_SPLL_REF_FB_DIV);
+	rinfo->save_regs[78] = INPLL(pllAGP_PLL_CNTL);
+	rinfo->save_regs[79] = INREG(PAMAC2_DLY_CNTL);
+
+	rinfo->save_regs[80] = INREG(OV0_BASE_ADDR);
+	rinfo->save_regs[82] = INREG(FP_GEN_CNTL);
+	rinfo->save_regs[83] = INREG(FP2_GEN_CNTL);
+	rinfo->save_regs[84] = INREG(TMDS_CNTL);
+	rinfo->save_regs[85] = INREG(TMDS_TRANSMITTER_CNTL);
+	rinfo->save_regs[86] = INREG(DISP_OUTPUT_CNTL);
+	rinfo->save_regs[87] = INREG(DISP_HW_DEBUG);
+	rinfo->save_regs[88] = INREG(TV_MASTER_CNTL);
+	rinfo->save_regs[89] = INPLL(pllP2PLL_REF_DIV);
+	rinfo->save_regs[92] = INPLL(pllPPLL_DIV_0);
+	rinfo->save_regs[93] = INPLL(pllPPLL_CNTL);
+	rinfo->save_regs[94] = INREG(GRPH_BUFFER_CNTL);
+	rinfo->save_regs[95] = INREG(GRPH2_BUFFER_CNTL);
+	rinfo->save_regs[96] = INREG(HDP_DEBUG);
+	rinfo->save_regs[97] = INPLL(pllMDLL_CKO);
+	rinfo->save_regs[98] = INPLL(pllMDLL_RDCKA);
+	rinfo->save_regs[99] = INPLL(pllMDLL_RDCKB);
+}
+
+static void radeon_pm_restore_regs(struct radeonfb_info *rinfo)
+{
+	OUTPLL(P2PLL_CNTL, rinfo->save_regs[8] & 0xFFFFFFFE); /* First */
+	
+	OUTPLL(PLL_PWRMGT_CNTL, rinfo->save_regs[0]);
+	OUTPLL(CLK_PWRMGT_CNTL, rinfo->save_regs[1]);
+	OUTPLL(MCLK_CNTL, rinfo->save_regs[2]);
+	OUTPLL(SCLK_CNTL, rinfo->save_regs[3]);
+	OUTPLL(CLK_PIN_CNTL, rinfo->save_regs[4]);
+	OUTPLL(VCLK_ECP_CNTL, rinfo->save_regs[5]);
+	OUTPLL(PIXCLKS_CNTL, rinfo->save_regs[6]);
+	OUTPLL(MCLK_MISC, rinfo->save_regs[7]);
+	if (rinfo->family == CHIP_FAMILY_RV350)
+		OUTPLL(SCLK_MORE_CNTL, rinfo->save_regs[34]);
+
+	OUTREG(SURFACE_CNTL, rinfo->save_regs[29]);
+	OUTREG(MC_FB_LOCATION, rinfo->save_regs[30]);
+	OUTREG(DISPLAY_BASE_ADDR, rinfo->save_regs[31]);
+	OUTREG(MC_AGP_LOCATION, rinfo->save_regs[32]);
+	OUTREG(CRTC2_DISPLAY_BASE_ADDR, rinfo->save_regs[33]);
+	OUTREG(CONFIG_MEMSIZE, rinfo->video_ram);
+
+	OUTREG(DISP_MISC_CNTL, rinfo->save_regs[9]);
+	OUTREG(DISP_PWR_MAN, rinfo->save_regs[10]);
+	OUTREG(LVDS_GEN_CNTL, rinfo->save_regs[11]);
+	OUTREG(LVDS_PLL_CNTL,rinfo->save_regs[12]);
+	OUTREG(TV_DAC_CNTL, rinfo->save_regs[13]);
+	OUTREG(BUS_CNTL1, rinfo->save_regs[14]);
+	OUTREG(CRTC_OFFSET_CNTL, rinfo->save_regs[15]);
+	OUTREG(AGP_CNTL, rinfo->save_regs[16]);
+	OUTREG(CRTC_GEN_CNTL, rinfo->save_regs[17]);
+	OUTREG(CRTC2_GEN_CNTL, rinfo->save_regs[18]);
+	OUTPLL(P2PLL_CNTL, rinfo->save_regs[8]);
+
+	OUTREG(GPIOPAD_A, rinfo->save_regs[19]);
+	OUTREG(GPIOPAD_EN, rinfo->save_regs[20]);
+	OUTREG(GPIOPAD_MASK, rinfo->save_regs[21]);
+	OUTREG(ZV_LCDPAD_A, rinfo->save_regs[22]);
+	OUTREG(ZV_LCDPAD_EN, rinfo->save_regs[23]);
+	OUTREG(ZV_LCDPAD_MASK, rinfo->save_regs[24]);
+	OUTREG(GPIO_VGA_DDC, rinfo->save_regs[25]);
+	OUTREG(GPIO_DVI_DDC, rinfo->save_regs[26]);
+	OUTREG(GPIO_MONID, rinfo->save_regs[27]);
+	OUTREG(GPIO_CRT2_DDC, rinfo->save_regs[28]);
+}
+
+static void radeon_pm_disable_iopad(struct radeonfb_info *rinfo)
+{		
+	OUTREG(GPIOPAD_MASK, 0x0001ffff);
+	OUTREG(GPIOPAD_EN, 0x00000400);
+	OUTREG(GPIOPAD_A, 0x00000000);		
+        OUTREG(ZV_LCDPAD_MASK, 0x00000000);
+        OUTREG(ZV_LCDPAD_EN, 0x00000000);
+      	OUTREG(ZV_LCDPAD_A, 0x00000000); 	
+	OUTREG(GPIO_VGA_DDC, 0x00030000);
+	OUTREG(GPIO_DVI_DDC, 0x00000000);
+	OUTREG(GPIO_MONID, 0x00030000);
+	OUTREG(GPIO_CRT2_DDC, 0x00000000);
+}
+
+static void radeon_pm_program_v2clk(struct radeonfb_info *rinfo)
+{
+	/* Set v2clk to 65MHz */
+	if (rinfo->family <= CHIP_FAMILY_RV280) {
+		OUTPLL(pllPIXCLKS_CNTL,
+			 __INPLL(rinfo, pllPIXCLKS_CNTL)
+			 & ~PIXCLKS_CNTL__PIX2CLK_SRC_SEL_MASK);
+	 
+		OUTPLL(pllP2PLL_REF_DIV, 0x0000000c);
+		OUTPLL(pllP2PLL_CNTL, 0x0000bf00);
+	} else {
+		OUTPLL(pllP2PLL_REF_DIV, 0x0000000c);
+		INPLL(pllP2PLL_REF_DIV);
+		OUTPLL(pllP2PLL_CNTL, 0x0000a700);
+	}
+
+	OUTPLL(pllP2PLL_DIV_0, 0x00020074 | P2PLL_DIV_0__P2PLL_ATOMIC_UPDATE_W);
+	
+	OUTPLL(pllP2PLL_CNTL, INPLL(pllP2PLL_CNTL) & ~P2PLL_CNTL__P2PLL_SLEEP);
+	mdelay(1);
+
+	OUTPLL(pllP2PLL_CNTL, INPLL(pllP2PLL_CNTL) & ~P2PLL_CNTL__P2PLL_RESET);
+	mdelay( 1);
+
+  	OUTPLL(pllPIXCLKS_CNTL,
+  		(INPLL(pllPIXCLKS_CNTL) & ~PIXCLKS_CNTL__PIX2CLK_SRC_SEL_MASK)
+  		| (0x03 << PIXCLKS_CNTL__PIX2CLK_SRC_SEL__SHIFT));
+	mdelay( 1);	
+}
+
+static void radeon_pm_low_current(struct radeonfb_info *rinfo)
+{
+	u32 reg;
+
+	reg  = INREG(BUS_CNTL1);
+	if (rinfo->family <= CHIP_FAMILY_RV280) {
+		reg &= ~BUS_CNTL1_MOBILE_PLATFORM_SEL_MASK;
+		reg |= BUS_CNTL1_AGPCLK_VALID | (1<<BUS_CNTL1_MOBILE_PLATFORM_SEL_SHIFT);
+	} else {
+		reg |= 0x4080;
+	}
+	OUTREG(BUS_CNTL1, reg);
+	
+	reg  = INPLL(PLL_PWRMGT_CNTL);
+	reg |= PLL_PWRMGT_CNTL_SPLL_TURNOFF | PLL_PWRMGT_CNTL_PPLL_TURNOFF |
+		PLL_PWRMGT_CNTL_P2PLL_TURNOFF | PLL_PWRMGT_CNTL_TVPLL_TURNOFF;
+	reg &= ~PLL_PWRMGT_CNTL_SU_MCLK_USE_BCLK;
+	reg &= ~PLL_PWRMGT_CNTL_MOBILE_SU;
+	OUTPLL(PLL_PWRMGT_CNTL, reg);
+	
+	reg  = INREG(TV_DAC_CNTL);
+	reg &= ~(TV_DAC_CNTL_BGADJ_MASK |TV_DAC_CNTL_DACADJ_MASK);
+	reg |=TV_DAC_CNTL_BGSLEEP | TV_DAC_CNTL_RDACPD | TV_DAC_CNTL_GDACPD |
+		TV_DAC_CNTL_BDACPD |
+		(8<<TV_DAC_CNTL_BGADJ__SHIFT) | (8<<TV_DAC_CNTL_DACADJ__SHIFT);
+	OUTREG(TV_DAC_CNTL, reg);
+	
+	reg  = INREG(TMDS_TRANSMITTER_CNTL);
+	reg &= ~(TMDS_PLL_EN | TMDS_PLLRST);
+	OUTREG(TMDS_TRANSMITTER_CNTL, reg);
+
+	reg = INREG(DAC_CNTL);
+	reg &= ~DAC_CMP_EN;
+	OUTREG(DAC_CNTL, reg);
+
+	reg = INREG(DAC_CNTL2);
+	reg &= ~DAC2_CMP_EN;
+	OUTREG(DAC_CNTL2, reg);
+	
+	reg  = INREG(TV_DAC_CNTL);
+	reg &= ~TV_DAC_CNTL_DETECT;
+	OUTREG(TV_DAC_CNTL, reg);
+}
+
+static void radeon_pm_setup_for_suspend(struct radeonfb_info *rinfo)
+{
+
+	u32 sclk_cntl, mclk_cntl, sclk_more_cntl;
+
+	u32 pll_pwrmgt_cntl;
+	u32 clk_pwrmgt_cntl;
+	u32 clk_pin_cntl;
+	u32 vclk_ecp_cntl; 
+	u32 pixclks_cntl;
+	u32 disp_mis_cntl;
+	u32 disp_pwr_man;
+	u32 tmp;
+	
+	/* Force Core Clocks */
+	sclk_cntl = INPLL( pllSCLK_CNTL);
+	sclk_cntl |= 	SCLK_CNTL__IDCT_MAX_DYN_STOP_LAT|
+			SCLK_CNTL__VIP_MAX_DYN_STOP_LAT|
+			SCLK_CNTL__RE_MAX_DYN_STOP_LAT|
+			SCLK_CNTL__PB_MAX_DYN_STOP_LAT|
+			SCLK_CNTL__TAM_MAX_DYN_STOP_LAT|
+			SCLK_CNTL__TDM_MAX_DYN_STOP_LAT|
+			SCLK_CNTL__RB_MAX_DYN_STOP_LAT|
+			
+			SCLK_CNTL__FORCE_DISP2|
+			SCLK_CNTL__FORCE_CP|
+			SCLK_CNTL__FORCE_HDP|
+			SCLK_CNTL__FORCE_DISP1|
+			SCLK_CNTL__FORCE_TOP|
+			SCLK_CNTL__FORCE_E2|
+			SCLK_CNTL__FORCE_SE|
+			SCLK_CNTL__FORCE_IDCT|
+			SCLK_CNTL__FORCE_VIP|
+			
+			SCLK_CNTL__FORCE_PB|
+			SCLK_CNTL__FORCE_TAM|
+			SCLK_CNTL__FORCE_TDM|
+			SCLK_CNTL__FORCE_RB|
+			SCLK_CNTL__FORCE_TV_SCLK|
+			SCLK_CNTL__FORCE_SUBPIC|
+			SCLK_CNTL__FORCE_OV0;
+	if (rinfo->family <= CHIP_FAMILY_RV280)
+		sclk_cntl |= SCLK_CNTL__FORCE_RE;
+	else
+		sclk_cntl |= SCLK_CNTL__SE_MAX_DYN_STOP_LAT |
+			SCLK_CNTL__E2_MAX_DYN_STOP_LAT |
+			SCLK_CNTL__TV_MAX_DYN_STOP_LAT |
+			SCLK_CNTL__HDP_MAX_DYN_STOP_LAT |
+			SCLK_CNTL__CP_MAX_DYN_STOP_LAT;
+
+	OUTPLL( pllSCLK_CNTL, sclk_cntl);
+
+	sclk_more_cntl = INPLL(pllSCLK_MORE_CNTL);
+	sclk_more_cntl |= 	SCLK_MORE_CNTL__FORCE_DISPREGS |
+				SCLK_MORE_CNTL__FORCE_MC_GUI |
+				SCLK_MORE_CNTL__FORCE_MC_HOST;
+
+	OUTPLL(pllSCLK_MORE_CNTL, sclk_more_cntl);		
+
+	
+	mclk_cntl = INPLL( pllMCLK_CNTL);
+	mclk_cntl &= ~(	MCLK_CNTL__FORCE_MCLKA |
+			MCLK_CNTL__FORCE_MCLKB |
+			MCLK_CNTL__FORCE_YCLKA |
+			MCLK_CNTL__FORCE_YCLKB |
+			MCLK_CNTL__FORCE_MC
+		      );	
+    	OUTPLL( pllMCLK_CNTL, mclk_cntl);
+	
+	/* Force Display clocks	*/
+	vclk_ecp_cntl = INPLL( pllVCLK_ECP_CNTL);
+	vclk_ecp_cntl &= ~(VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb
+			   | VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb);
+	vclk_ecp_cntl |= VCLK_ECP_CNTL__ECP_FORCE_ON;
+	OUTPLL( pllVCLK_ECP_CNTL, vclk_ecp_cntl);
+	
+	
+	pixclks_cntl = INPLL( pllPIXCLKS_CNTL);
+	pixclks_cntl &= ~(	PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb | 
+				PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb|
+				PIXCLKS_CNTL__PIXCLK_DIG_TMDS_ALWAYS_ONb |
+				PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb|
+				PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb|
+				PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb|
+				PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb);
+						
+ 	OUTPLL( pllPIXCLKS_CNTL, pixclks_cntl);
+
+	/* Switch off LVDS interface */
+	OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) &
+	       ~(LVDS_BLON | LVDS_EN | LVDS_ON | LVDS_DIGON));
+
+	/* Enable System power management */
+	pll_pwrmgt_cntl = INPLL( pllPLL_PWRMGT_CNTL);
+	
+	pll_pwrmgt_cntl |= 	PLL_PWRMGT_CNTL__SPLL_TURNOFF |
+				PLL_PWRMGT_CNTL__MPLL_TURNOFF|
+				PLL_PWRMGT_CNTL__PPLL_TURNOFF|
+				PLL_PWRMGT_CNTL__P2PLL_TURNOFF|
+				PLL_PWRMGT_CNTL__TVPLL_TURNOFF;
+						
+	OUTPLL( pllPLL_PWRMGT_CNTL, pll_pwrmgt_cntl);
+	
+	clk_pwrmgt_cntl	 = INPLL( pllCLK_PWRMGT_CNTL);
+	
+	clk_pwrmgt_cntl &= ~(	CLK_PWRMGT_CNTL__MPLL_PWRMGT_OFF|
+				CLK_PWRMGT_CNTL__SPLL_PWRMGT_OFF|
+				CLK_PWRMGT_CNTL__PPLL_PWRMGT_OFF|
+				CLK_PWRMGT_CNTL__P2PLL_PWRMGT_OFF|
+				CLK_PWRMGT_CNTL__MCLK_TURNOFF|
+				CLK_PWRMGT_CNTL__SCLK_TURNOFF|
+				CLK_PWRMGT_CNTL__PCLK_TURNOFF|
+				CLK_PWRMGT_CNTL__P2CLK_TURNOFF|
+				CLK_PWRMGT_CNTL__TVPLL_PWRMGT_OFF|
+				CLK_PWRMGT_CNTL__GLOBAL_PMAN_EN|
+				CLK_PWRMGT_CNTL__ENGINE_DYNCLK_MODE|
+				CLK_PWRMGT_CNTL__ACTIVE_HILO_LAT_MASK|
+				CLK_PWRMGT_CNTL__CG_NO1_DEBUG_MASK
+			);
+						
+	clk_pwrmgt_cntl |= CLK_PWRMGT_CNTL__GLOBAL_PMAN_EN
+		| CLK_PWRMGT_CNTL__DISP_PM;
+	
+	OUTPLL( pllCLK_PWRMGT_CNTL, clk_pwrmgt_cntl);
+	
+	clk_pin_cntl = INPLL( pllCLK_PIN_CNTL);
+	
+	clk_pin_cntl &= ~CLK_PIN_CNTL__ACCESS_REGS_IN_SUSPEND;
+
+	/* because both INPLL and OUTPLL take the same lock, that's why. */
+	tmp = INPLL( pllMCLK_MISC) | MCLK_MISC__EN_MCLK_TRISTATE_IN_SUSPEND;
+	OUTPLL( pllMCLK_MISC, tmp);
+	
+	/* AGP PLL control */
+	if (rinfo->family <= CHIP_FAMILY_RV280) {
+		OUTREG(BUS_CNTL1, INREG(BUS_CNTL1) |  BUS_CNTL1__AGPCLK_VALID);
+
+		OUTREG(BUS_CNTL1,
+		       (INREG(BUS_CNTL1) & ~BUS_CNTL1__MOBILE_PLATFORM_SEL_MASK)
+		       | (2<<BUS_CNTL1__MOBILE_PLATFORM_SEL__SHIFT));	// 440BX
+	} else {
+		OUTREG(BUS_CNTL1, INREG(BUS_CNTL1));
+		OUTREG(BUS_CNTL1, (INREG(BUS_CNTL1) & ~0x4000) | 0x8000);
+	}
+
+	OUTREG(CRTC_OFFSET_CNTL, (INREG(CRTC_OFFSET_CNTL)
+				  & ~CRTC_OFFSET_CNTL__CRTC_STEREO_SYNC_OUT_EN));
+	
+	clk_pin_cntl &= ~CLK_PIN_CNTL__CG_CLK_TO_OUTPIN;
+	clk_pin_cntl |= CLK_PIN_CNTL__XTALIN_ALWAYS_ONb;	
+	OUTPLL( pllCLK_PIN_CNTL, clk_pin_cntl);
+
+	/* Solano2M */
+	OUTREG(AGP_CNTL,
+		(INREG(AGP_CNTL) & ~(AGP_CNTL__MAX_IDLE_CLK_MASK))
+		| (0x20<<AGP_CNTL__MAX_IDLE_CLK__SHIFT));
+
+	/* ACPI mode */
+	/* because both INPLL and OUTPLL take the same lock, that's why. */
+	tmp = INPLL( pllPLL_PWRMGT_CNTL) & ~PLL_PWRMGT_CNTL__PM_MODE_SEL;
+	OUTPLL( pllPLL_PWRMGT_CNTL, tmp);
+
+
+	disp_mis_cntl = INREG(DISP_MISC_CNTL);
+	
+	disp_mis_cntl &= ~(	DISP_MISC_CNTL__SOFT_RESET_GRPH_PP | 
+				DISP_MISC_CNTL__SOFT_RESET_SUBPIC_PP | 
+				DISP_MISC_CNTL__SOFT_RESET_OV0_PP |
+				DISP_MISC_CNTL__SOFT_RESET_GRPH_SCLK|
+				DISP_MISC_CNTL__SOFT_RESET_SUBPIC_SCLK|
+				DISP_MISC_CNTL__SOFT_RESET_OV0_SCLK|
+				DISP_MISC_CNTL__SOFT_RESET_GRPH2_PP|
+				DISP_MISC_CNTL__SOFT_RESET_GRPH2_SCLK|
+				DISP_MISC_CNTL__SOFT_RESET_LVDS|
+				DISP_MISC_CNTL__SOFT_RESET_TMDS|
+				DISP_MISC_CNTL__SOFT_RESET_DIG_TMDS|
+				DISP_MISC_CNTL__SOFT_RESET_TV);
+	
+	OUTREG(DISP_MISC_CNTL, disp_mis_cntl);
+						
+	disp_pwr_man = INREG(DISP_PWR_MAN);
+	
+	disp_pwr_man &= ~(	DISP_PWR_MAN__DISP_PWR_MAN_D3_CRTC_EN	| 
+				DISP_PWR_MAN__DISP2_PWR_MAN_D3_CRTC2_EN |
+				DISP_PWR_MAN__DISP_PWR_MAN_DPMS_MASK|
+				DISP_PWR_MAN__DISP_D3_RST|
+				DISP_PWR_MAN__DISP_D3_REG_RST
+				);
+	
+	disp_pwr_man |= DISP_PWR_MAN__DISP_D3_GRPH_RST|
+					DISP_PWR_MAN__DISP_D3_SUBPIC_RST|
+					DISP_PWR_MAN__DISP_D3_OV0_RST|
+					DISP_PWR_MAN__DISP_D1D2_GRPH_RST|
+					DISP_PWR_MAN__DISP_D1D2_SUBPIC_RST|
+					DISP_PWR_MAN__DISP_D1D2_OV0_RST|
+					DISP_PWR_MAN__DIG_TMDS_ENABLE_RST|
+					DISP_PWR_MAN__TV_ENABLE_RST| 
+//					DISP_PWR_MAN__AUTO_PWRUP_EN|
+					0;
+	
+	OUTREG(DISP_PWR_MAN, disp_pwr_man);					
+							
+	clk_pwrmgt_cntl = INPLL( pllCLK_PWRMGT_CNTL);
+	pll_pwrmgt_cntl = INPLL( pllPLL_PWRMGT_CNTL) ;
+	clk_pin_cntl 	= INPLL( pllCLK_PIN_CNTL);
+	disp_pwr_man	= INREG(DISP_PWR_MAN);
+		
+	
+	/* D2 */
+	clk_pwrmgt_cntl |= CLK_PWRMGT_CNTL__DISP_PM;
+	pll_pwrmgt_cntl |= PLL_PWRMGT_CNTL__MOBILE_SU | PLL_PWRMGT_CNTL__SU_SCLK_USE_BCLK;
+	clk_pin_cntl	|= CLK_PIN_CNTL__XTALIN_ALWAYS_ONb;
+	disp_pwr_man 	&= ~(DISP_PWR_MAN__DISP_PWR_MAN_D3_CRTC_EN_MASK
+			     | DISP_PWR_MAN__DISP2_PWR_MAN_D3_CRTC2_EN_MASK);
+
+	OUTPLL( pllCLK_PWRMGT_CNTL, clk_pwrmgt_cntl);
+	OUTPLL( pllPLL_PWRMGT_CNTL, pll_pwrmgt_cntl);
+	OUTPLL( pllCLK_PIN_CNTL, clk_pin_cntl);
+	OUTREG(DISP_PWR_MAN, disp_pwr_man);
+
+	/* disable display request & disable display */
+	OUTREG( CRTC_GEN_CNTL, (INREG( CRTC_GEN_CNTL) & ~CRTC_GEN_CNTL__CRTC_EN)
+		| CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B);
+	OUTREG( CRTC2_GEN_CNTL, (INREG( CRTC2_GEN_CNTL) & ~CRTC2_GEN_CNTL__CRTC2_EN)
+		| CRTC2_GEN_CNTL__CRTC2_DISP_REQ_EN_B);
+
+	mdelay(17);				   
+
+}
+
+static void radeon_pm_yclk_mclk_sync(struct radeonfb_info *rinfo)
+{
+	u32 mc_chp_io_cntl_a1, mc_chp_io_cntl_b1;
+
+	mc_chp_io_cntl_a1 = INMC( rinfo, ixMC_CHP_IO_CNTL_A1)
+		& ~MC_CHP_IO_CNTL_A1__MEM_SYNC_ENA_MASK;
+	mc_chp_io_cntl_b1 = INMC( rinfo, ixMC_CHP_IO_CNTL_B1)
+		& ~MC_CHP_IO_CNTL_B1__MEM_SYNC_ENB_MASK;
+
+	OUTMC( rinfo, ixMC_CHP_IO_CNTL_A1, mc_chp_io_cntl_a1
+	       | (1<<MC_CHP_IO_CNTL_A1__MEM_SYNC_ENA__SHIFT));
+	OUTMC( rinfo, ixMC_CHP_IO_CNTL_B1, mc_chp_io_cntl_b1
+	       | (1<<MC_CHP_IO_CNTL_B1__MEM_SYNC_ENB__SHIFT));
+
+	OUTMC( rinfo, ixMC_CHP_IO_CNTL_A1, mc_chp_io_cntl_a1);
+	OUTMC( rinfo, ixMC_CHP_IO_CNTL_B1, mc_chp_io_cntl_b1);
+
+	mdelay( 1);
+}
+
+static void radeon_pm_yclk_mclk_sync_m10(struct radeonfb_info *rinfo)
+{
+	u32 mc_chp_io_cntl_a1, mc_chp_io_cntl_b1;
+
+	mc_chp_io_cntl_a1 = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_A1)
+		& ~MC_CHP_IO_CNTL_A1__MEM_SYNC_ENA_MASK;
+	mc_chp_io_cntl_b1 = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_B1)
+		& ~MC_CHP_IO_CNTL_B1__MEM_SYNC_ENB_MASK;
+
+	OUTMC( rinfo, ixR300_MC_CHP_IO_CNTL_A1,
+	       mc_chp_io_cntl_a1 | (1<<MC_CHP_IO_CNTL_A1__MEM_SYNC_ENA__SHIFT));
+	OUTMC( rinfo, ixR300_MC_CHP_IO_CNTL_B1,
+	       mc_chp_io_cntl_b1 | (1<<MC_CHP_IO_CNTL_B1__MEM_SYNC_ENB__SHIFT));
+
+	OUTMC( rinfo, ixR300_MC_CHP_IO_CNTL_A1, mc_chp_io_cntl_a1);
+	OUTMC( rinfo, ixR300_MC_CHP_IO_CNTL_B1, mc_chp_io_cntl_b1);
+
+	mdelay( 1);
+}
+
+static void radeon_pm_program_mode_reg(struct radeonfb_info *rinfo, u16 value,
+				       u8 delay_required)
+{  
+	u32 mem_sdram_mode;
+
+	mem_sdram_mode  = INREG( MEM_SDRAM_MODE_REG);
+
+	mem_sdram_mode &= ~MEM_SDRAM_MODE_REG__MEM_MODE_REG_MASK;
+	mem_sdram_mode |= (value<<MEM_SDRAM_MODE_REG__MEM_MODE_REG__SHIFT)
+		| MEM_SDRAM_MODE_REG__MEM_CFG_TYPE;
+	OUTREG( MEM_SDRAM_MODE_REG, mem_sdram_mode);
+	if (delay_required >= 2)
+		mdelay(1);
+
+	mem_sdram_mode |=  MEM_SDRAM_MODE_REG__MEM_SDRAM_RESET;
+	OUTREG( MEM_SDRAM_MODE_REG, mem_sdram_mode);
+	if (delay_required >= 2)
+		mdelay(1);
+
+	mem_sdram_mode &= ~MEM_SDRAM_MODE_REG__MEM_SDRAM_RESET;
+	OUTREG( MEM_SDRAM_MODE_REG, mem_sdram_mode);
+	if (delay_required >= 2)
+		mdelay(1);
+
+	if (delay_required) {
+		do {
+			if (delay_required >= 2)
+				mdelay(1);
+		} while ((INREG(MC_STATUS)
+			  & (MC_STATUS__MEM_PWRUP_COMPL_A |
+			     MC_STATUS__MEM_PWRUP_COMPL_B)) == 0);
+	}
+}
+
+static void radeon_pm_m10_program_mode_wait(struct radeonfb_info *rinfo)
+{
+	int cnt;
+
+	for (cnt = 0; cnt < 100; ++cnt) {
+		mdelay(1);
+		if (INREG(MC_STATUS) & (MC_STATUS__MEM_PWRUP_COMPL_A
+					| MC_STATUS__MEM_PWRUP_COMPL_B))
+			break;
+	}
+}
+
+
+static void radeon_pm_enable_dll(struct radeonfb_info *rinfo)
+{  
+#define DLL_RESET_DELAY 	5
+#define DLL_SLEEP_DELAY		1
+
+	u32 cko = INPLL(pllMDLL_CKO)   | MDLL_CKO__MCKOA_SLEEP
+		| MDLL_CKO__MCKOA_RESET;
+	u32 cka = INPLL(pllMDLL_RDCKA) | MDLL_RDCKA__MRDCKA0_SLEEP
+		| MDLL_RDCKA__MRDCKA1_SLEEP | MDLL_RDCKA__MRDCKA0_RESET
+		| MDLL_RDCKA__MRDCKA1_RESET;
+	u32 ckb = INPLL(pllMDLL_RDCKB) | MDLL_RDCKB__MRDCKB0_SLEEP
+		| MDLL_RDCKB__MRDCKB1_SLEEP | MDLL_RDCKB__MRDCKB0_RESET
+		| MDLL_RDCKB__MRDCKB1_RESET;
+
+	/* Setting up the DLL range for write */
+	OUTPLL(pllMDLL_CKO,   	cko);
+	OUTPLL(pllMDLL_RDCKA,  	cka);
+	OUTPLL(pllMDLL_RDCKB,	ckb);
+
+	mdelay(DLL_RESET_DELAY*2);
+
+	cko &= ~(MDLL_CKO__MCKOA_SLEEP | MDLL_CKO__MCKOB_SLEEP);
+	OUTPLL(pllMDLL_CKO, cko);
+	mdelay(DLL_SLEEP_DELAY);
+	cko &= ~(MDLL_CKO__MCKOA_RESET | MDLL_CKO__MCKOB_RESET);
+	OUTPLL(pllMDLL_CKO, cko);
+	mdelay(DLL_RESET_DELAY);
+
+	cka &= ~(MDLL_RDCKA__MRDCKA0_SLEEP | MDLL_RDCKA__MRDCKA1_SLEEP);
+	OUTPLL(pllMDLL_RDCKA, cka);
+	mdelay(DLL_SLEEP_DELAY);
+	cka &= ~(MDLL_RDCKA__MRDCKA0_RESET | MDLL_RDCKA__MRDCKA1_RESET);
+	OUTPLL(pllMDLL_RDCKA, cka);
+	mdelay(DLL_RESET_DELAY);
+
+	ckb &= ~(MDLL_RDCKB__MRDCKB0_SLEEP | MDLL_RDCKB__MRDCKB1_SLEEP);
+	OUTPLL(pllMDLL_RDCKB, ckb);
+	mdelay(DLL_SLEEP_DELAY);
+	ckb &= ~(MDLL_RDCKB__MRDCKB0_RESET | MDLL_RDCKB__MRDCKB1_RESET);
+	OUTPLL(pllMDLL_RDCKB, ckb);
+	mdelay(DLL_RESET_DELAY);
+
+
+#undef DLL_RESET_DELAY
+#undef DLL_SLEEP_DELAY
+}
+
+static void radeon_pm_enable_dll_m10(struct radeonfb_info *rinfo)
+{
+	u32 dll_value;
+	u32 dll_sleep_mask = 0;
+	u32 dll_reset_mask = 0;
+	u32 mc;
+
+#define DLL_RESET_DELAY 	5
+#define DLL_SLEEP_DELAY		1
+
+	OUTMC(rinfo, ixR300_MC_DLL_CNTL, rinfo->save_regs[70]);
+	mc = INREG(MC_CNTL);
+	/* Check which channels are enabled */
+	switch (mc & 0x3) {
+	case 1:
+		if (mc & 0x4)
+			break;
+	case 2:
+		dll_sleep_mask |= MDLL_R300_RDCK__MRDCKB_SLEEP;
+		dll_reset_mask |= MDLL_R300_RDCK__MRDCKB_RESET;
+	case 0:
+		dll_sleep_mask |= MDLL_R300_RDCK__MRDCKA_SLEEP;
+		dll_reset_mask |= MDLL_R300_RDCK__MRDCKA_RESET;
+	}
+	switch (mc & 0x3) {
+	case 1:
+		if (!(mc & 0x4))
+			break;
+	case 2:
+		dll_sleep_mask |= MDLL_R300_RDCK__MRDCKD_SLEEP;
+		dll_reset_mask |= MDLL_R300_RDCK__MRDCKD_RESET;
+		dll_sleep_mask |= MDLL_R300_RDCK__MRDCKC_SLEEP;
+		dll_reset_mask |= MDLL_R300_RDCK__MRDCKC_RESET;
+	}
+
+	dll_value = INPLL(pllMDLL_RDCKA);
+
+	/* Power Up */
+	dll_value &= ~(dll_sleep_mask);
+	OUTPLL(pllMDLL_RDCKA, dll_value);
+	mdelay( DLL_SLEEP_DELAY);  		
+
+	dll_value &= ~(dll_reset_mask);
+	OUTPLL(pllMDLL_RDCKA, dll_value);
+	mdelay( DLL_RESET_DELAY);  		
+
+#undef DLL_RESET_DELAY 
+#undef DLL_SLEEP_DELAY
+}
+
+
+static void radeon_pm_full_reset_sdram(struct radeonfb_info *rinfo)
+{
+	u32 crtcGenCntl, crtcGenCntl2, memRefreshCntl, crtc_more_cntl,
+		fp_gen_cntl, fp2_gen_cntl;
+ 
+	crtcGenCntl  = INREG( CRTC_GEN_CNTL);
+	crtcGenCntl2 = INREG( CRTC2_GEN_CNTL);
+
+	crtc_more_cntl 	= INREG( CRTC_MORE_CNTL);
+	fp_gen_cntl 	= INREG( FP_GEN_CNTL);
+	fp2_gen_cntl 	= INREG( FP2_GEN_CNTL);
+ 
+
+	OUTREG( CRTC_MORE_CNTL, 0);
+	OUTREG( FP_GEN_CNTL, 0);
+	OUTREG( FP2_GEN_CNTL,0);
+ 
+	OUTREG( CRTC_GEN_CNTL,  (crtcGenCntl | CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B) );
+	OUTREG( CRTC2_GEN_CNTL, (crtcGenCntl2 | CRTC2_GEN_CNTL__CRTC2_DISP_REQ_EN_B) );
+  
+	/* This is the code for the Aluminium PowerBooks M10 */
+	if (rinfo->family == CHIP_FAMILY_RV350) {
+		u32 sdram_mode_reg = rinfo->save_regs[35];
+		static u32 default_mrtable[] =
+			{ 0x21320032,
+			  0x21321000, 0xa1321000, 0x21321000, 0xffffffff,
+			  0x21320032, 0xa1320032, 0x21320032, 0xffffffff,
+			  0x21321002, 0xa1321002, 0x21321002, 0xffffffff,
+			  0x21320132, 0xa1320132, 0x21320132, 0xffffffff,
+			  0x21320032, 0xa1320032, 0x21320032, 0xffffffff,
+			  0x31320032 };
+
+		u32 *mrtable = default_mrtable;
+		int i, mrtable_size = ARRAY_SIZE(default_mrtable);
+
+		mdelay(30);
+
+		/* Disable refresh */
+		memRefreshCntl 	= INREG( MEM_REFRESH_CNTL)
+			& ~MEM_REFRESH_CNTL__MEM_REFRESH_DIS;
+		OUTREG( MEM_REFRESH_CNTL, memRefreshCntl
+			| MEM_REFRESH_CNTL__MEM_REFRESH_DIS);
+
+		/* Configure and enable M & SPLLs */
+       		radeon_pm_enable_dll_m10(rinfo);
+		radeon_pm_yclk_mclk_sync_m10(rinfo);
+
+#ifdef CONFIG_PPC_OF
+		if (rinfo->of_node != NULL) {
+			int size;
+
+			mrtable = (u32 *)get_property(rinfo->of_node, "ATY,MRT", &size);
+			if (mrtable)
+				mrtable_size = size >> 2;
+			else
+				mrtable = default_mrtable;
+		}
+#endif /* CONFIG_PPC_OF */
+
+		/* Program the SDRAM */
+		sdram_mode_reg = mrtable[0];
+		OUTREG(MEM_SDRAM_MODE_REG, sdram_mode_reg);
+		for (i = 0; i < mrtable_size; i++) {
+			if (mrtable[i] == 0xffffffffu)
+				radeon_pm_m10_program_mode_wait(rinfo);
+			else {
+				sdram_mode_reg &= ~(MEM_SDRAM_MODE_REG__MEM_MODE_REG_MASK
+						    | MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE
+						    | MEM_SDRAM_MODE_REG__MEM_SDRAM_RESET);
+				sdram_mode_reg |= mrtable[i];
+
+				OUTREG(MEM_SDRAM_MODE_REG, sdram_mode_reg);
+				mdelay(1);
+			}
+		}
+
+		/* Restore memory refresh */
+		OUTREG(MEM_REFRESH_CNTL, memRefreshCntl);
+		mdelay(30);
+
+	}
+	/* Here come the desktop RV200 "QW" card */
+	else if (!rinfo->is_mobility && rinfo->family == CHIP_FAMILY_RV200) {
+		/* Disable refresh */
+		memRefreshCntl 	= INREG( MEM_REFRESH_CNTL)
+			& ~MEM_REFRESH_CNTL__MEM_REFRESH_DIS;
+		OUTREG(MEM_REFRESH_CNTL, memRefreshCntl
+		       | MEM_REFRESH_CNTL__MEM_REFRESH_DIS);
+		mdelay(30);
+
+		/* Reset memory */
+		OUTREG(MEM_SDRAM_MODE_REG,
+		       INREG( MEM_SDRAM_MODE_REG) & ~MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE);
+
+		radeon_pm_program_mode_reg(rinfo, 0x2002, 2);
+		radeon_pm_program_mode_reg(rinfo, 0x0132, 2);
+		radeon_pm_program_mode_reg(rinfo, 0x0032, 2);
+
+		OUTREG(MEM_SDRAM_MODE_REG,
+		       INREG(MEM_SDRAM_MODE_REG) | MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE);
+
+		OUTREG( MEM_REFRESH_CNTL, 	memRefreshCntl);
+
+	}
+	/* The M6 */
+	else if (rinfo->is_mobility && rinfo->family == CHIP_FAMILY_RV100) {
+		/* Disable refresh */
+		memRefreshCntl = INREG(EXT_MEM_CNTL) & ~(1 << 20);
+		OUTREG( EXT_MEM_CNTL, memRefreshCntl | (1 << 20));
+ 
+		/* Reset memory */
+		OUTREG( MEM_SDRAM_MODE_REG,
+			INREG( MEM_SDRAM_MODE_REG)
+			& ~MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE);
+
+		/* DLL */
+		radeon_pm_enable_dll(rinfo);
+
+		/* MLCK / YCLK sync */
+		radeon_pm_yclk_mclk_sync(rinfo);
+
+		/* Program Mode Register */
+		radeon_pm_program_mode_reg(rinfo, 0x2000, 1);   
+		radeon_pm_program_mode_reg(rinfo, 0x2001, 1);   
+		radeon_pm_program_mode_reg(rinfo, 0x2002, 1);   
+		radeon_pm_program_mode_reg(rinfo, 0x0132, 1);   
+		radeon_pm_program_mode_reg(rinfo, 0x0032, 1); 
+
+		/* Complete & re-enable refresh */
+		OUTREG( MEM_SDRAM_MODE_REG,
+			INREG( MEM_SDRAM_MODE_REG) | MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE);
+
+		OUTREG(EXT_MEM_CNTL, memRefreshCntl);
+	}
+	/* And finally, the M7..M9 models, including M9+ (RV280) */
+	else if (rinfo->is_mobility) {
+
+		/* Disable refresh */
+		memRefreshCntl 	= INREG( MEM_REFRESH_CNTL)
+			& ~MEM_REFRESH_CNTL__MEM_REFRESH_DIS;
+		OUTREG( MEM_REFRESH_CNTL, memRefreshCntl
+			| MEM_REFRESH_CNTL__MEM_REFRESH_DIS);
+
+		/* Reset memory */
+		OUTREG( MEM_SDRAM_MODE_REG,
+			INREG( MEM_SDRAM_MODE_REG)
+			& ~MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE);
+
+		/* DLL */
+		radeon_pm_enable_dll(rinfo);
+
+		/* MLCK / YCLK sync */
+		radeon_pm_yclk_mclk_sync(rinfo);
+
+		/* M6, M7 and M9 so far ... */
+		if (rinfo->family <= CHIP_FAMILY_RV250) {
+			radeon_pm_program_mode_reg(rinfo, 0x2000, 1);
+			radeon_pm_program_mode_reg(rinfo, 0x2001, 1);
+			radeon_pm_program_mode_reg(rinfo, 0x2002, 1);
+			radeon_pm_program_mode_reg(rinfo, 0x0132, 1);
+			radeon_pm_program_mode_reg(rinfo, 0x0032, 1);
+		}
+		/* M9+ (iBook G4) */
+		else if (rinfo->family == CHIP_FAMILY_RV280) {
+			radeon_pm_program_mode_reg(rinfo, 0x2000, 1);
+			radeon_pm_program_mode_reg(rinfo, 0x0132, 1);
+			radeon_pm_program_mode_reg(rinfo, 0x0032, 1);
+		}
+
+		/* Complete & re-enable refresh */
+		OUTREG( MEM_SDRAM_MODE_REG,
+			INREG( MEM_SDRAM_MODE_REG) | MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE);
+
+		OUTREG( MEM_REFRESH_CNTL, 	memRefreshCntl);
+	}
+
+	OUTREG( CRTC_GEN_CNTL, 		crtcGenCntl);
+	OUTREG( CRTC2_GEN_CNTL, 	crtcGenCntl2);
+	OUTREG( FP_GEN_CNTL, 		fp_gen_cntl);
+	OUTREG( FP2_GEN_CNTL, 		fp2_gen_cntl);
+
+	OUTREG( CRTC_MORE_CNTL, 	crtc_more_cntl);
+
+	mdelay( 15);
+}
+
+#ifdef CONFIG_PPC_OF
+
+static void radeon_pm_reset_pad_ctlr_strength(struct radeonfb_info *rinfo)
+{
+	u32 tmp, tmp2;
+	int i,j;
+
+	/* Reset the PAD_CTLR_STRENGTH & wait for it to be stable */
+	INREG(PAD_CTLR_STRENGTH);
+	OUTREG(PAD_CTLR_STRENGTH, INREG(PAD_CTLR_STRENGTH) & ~PAD_MANUAL_OVERRIDE);
+	tmp = INREG(PAD_CTLR_STRENGTH);
+	for (i = j = 0; i < 65; ++i) {
+		mdelay(1);
+		tmp2 = INREG(PAD_CTLR_STRENGTH);
+		if (tmp != tmp2) {
+			tmp = tmp2;
+			i = 0;
+			j++;
+			if (j > 10) {
+				printk(KERN_WARNING "radeon: PAD_CTLR_STRENGTH doesn't "
+				       "stabilize !\n");
+				break;
+			}
+		}
+	}
+}
+
+static void radeon_pm_all_ppls_off(struct radeonfb_info *rinfo)
+{
+	u32 tmp;
+
+	tmp = INPLL(pllPPLL_CNTL);
+	OUTPLL(pllPPLL_CNTL, tmp | 0x3);
+	tmp = INPLL(pllP2PLL_CNTL);
+	OUTPLL(pllP2PLL_CNTL, tmp | 0x3);
+	tmp = INPLL(pllSPLL_CNTL);
+	OUTPLL(pllSPLL_CNTL, tmp | 0x3);
+	tmp = INPLL(pllMPLL_CNTL);
+	OUTPLL(pllMPLL_CNTL, tmp | 0x3);
+}
+
+static void radeon_pm_start_mclk_sclk(struct radeonfb_info *rinfo)
+{
+	u32 tmp;
+
+	/* Switch SPLL to PCI source */
+	tmp = INPLL(pllSCLK_CNTL);
+	OUTPLL(pllSCLK_CNTL, tmp & ~SCLK_CNTL__SCLK_SRC_SEL_MASK);
+
+	/* Reconfigure SPLL charge pump, VCO gain, duty cycle */
+	tmp = INPLL(pllSPLL_CNTL);
+	OUTREG8(CLOCK_CNTL_INDEX, pllSPLL_CNTL + PLL_WR_EN);
+	radeon_pll_errata_after_index(rinfo);
+	OUTREG8(CLOCK_CNTL_DATA + 1, (tmp >> 8) & 0xff);
+	radeon_pll_errata_after_data(rinfo);
+
+	/* Set SPLL feedback divider */
+	tmp = INPLL(pllM_SPLL_REF_FB_DIV);
+	tmp = (tmp & 0xff00fffful) | (rinfo->save_regs[77] & 0x00ff0000ul);
+	OUTPLL(pllM_SPLL_REF_FB_DIV, tmp);
+
+	/* Power up SPLL */
+	tmp = INPLL(pllSPLL_CNTL);
+	OUTPLL(pllSPLL_CNTL, tmp & ~1);
+	(void)INPLL(pllSPLL_CNTL);
+
+	mdelay(10);
+
+	/* Release SPLL reset */
+	tmp = INPLL(pllSPLL_CNTL);
+	OUTPLL(pllSPLL_CNTL, tmp & ~0x2);
+	(void)INPLL(pllSPLL_CNTL);
+
+	mdelay(10);
+
+	/* Select SCLK source  */
+	tmp = INPLL(pllSCLK_CNTL);
+	tmp &= ~SCLK_CNTL__SCLK_SRC_SEL_MASK;
+	tmp |= rinfo->save_regs[3] & SCLK_CNTL__SCLK_SRC_SEL_MASK;
+	OUTPLL(pllSCLK_CNTL, tmp);
+	(void)INPLL(pllSCLK_CNTL);
+
+	mdelay(10);
+
+	/* Reconfigure MPLL charge pump, VCO gain, duty cycle */
+	tmp = INPLL(pllMPLL_CNTL);
+	OUTREG8(CLOCK_CNTL_INDEX, pllMPLL_CNTL + PLL_WR_EN);
+	radeon_pll_errata_after_index(rinfo);
+	OUTREG8(CLOCK_CNTL_DATA + 1, (tmp >> 8) & 0xff);
+	radeon_pll_errata_after_data(rinfo);
+
+	/* Set MPLL feedback divider */
+	tmp = INPLL(pllM_SPLL_REF_FB_DIV);
+	tmp = (tmp & 0xffff00fful) | (rinfo->save_regs[77] & 0x0000ff00ul);
+
+	OUTPLL(pllM_SPLL_REF_FB_DIV, tmp);
+	/* Power up MPLL */
+	tmp = INPLL(pllMPLL_CNTL);
+	OUTPLL(pllMPLL_CNTL, tmp & ~0x2);
+	(void)INPLL(pllMPLL_CNTL);
+
+	mdelay(10);
+
+	/* Un-reset MPLL */
+	tmp = INPLL(pllMPLL_CNTL);
+	OUTPLL(pllMPLL_CNTL, tmp & ~0x1);
+	(void)INPLL(pllMPLL_CNTL);
+
+	mdelay(10);
+
+	/* Select source for MCLK */
+	tmp = INPLL(pllMCLK_CNTL);
+	tmp |= rinfo->save_regs[2] & 0xffff;
+	OUTPLL(pllMCLK_CNTL, tmp);
+	(void)INPLL(pllMCLK_CNTL);
+
+	mdelay(10);
+}
+
+static void radeon_pm_m10_disable_spread_spectrum(struct radeonfb_info *rinfo)
+{
+	u32 r2ec;
+
+	/* GACK ! I though we didn't have a DDA on Radeon's anymore
+	 * here we rewrite with the same value, ... I suppose we clear
+	 * some bits that are already clear ? Or maybe this 0x2ec
+	 * register is something new ?
+	 */
+	mdelay(20);
+	r2ec = INREG(VGA_DDA_ON_OFF);
+	OUTREG(VGA_DDA_ON_OFF, r2ec);
+	mdelay(1);
+
+	/* Spread spectrum PLLL off */
+	OUTPLL(pllSSPLL_CNTL, 0xbf03);
+
+	/* Spread spectrum disabled */
+	OUTPLL(pllSS_INT_CNTL, rinfo->save_regs[90] & ~3);
+
+	/* The trace shows read & rewrite of LVDS_PLL_CNTL here with same
+	 * value, not sure what for...
+	 */
+
+	r2ec |= 0x3f0;
+	OUTREG(VGA_DDA_ON_OFF, r2ec);
+	mdelay(1);
+}
+
+static void radeon_pm_m10_enable_lvds_spread_spectrum(struct radeonfb_info *rinfo)
+{
+	u32 r2ec, tmp;
+
+	/* GACK (bis) ! I though we didn't have a DDA on Radeon's anymore
+	 * here we rewrite with the same value, ... I suppose we clear/set
+	 * some bits that are already clear/set ?
+	 */
+	r2ec = INREG(VGA_DDA_ON_OFF);
+	OUTREG(VGA_DDA_ON_OFF, r2ec);
+	mdelay(1);
+
+	/* Enable spread spectrum */
+	OUTPLL(pllSSPLL_CNTL, rinfo->save_regs[43] | 3);
+	mdelay(3);
+
+	OUTPLL(pllSSPLL_REF_DIV, rinfo->save_regs[44]);
+	OUTPLL(pllSSPLL_DIV_0, rinfo->save_regs[45]);
+	tmp = INPLL(pllSSPLL_CNTL);
+	OUTPLL(pllSSPLL_CNTL, tmp & ~0x2);
+	mdelay(6);
+	tmp = INPLL(pllSSPLL_CNTL);
+	OUTPLL(pllSSPLL_CNTL, tmp & ~0x1);
+	mdelay(5);
+
+       	OUTPLL(pllSS_INT_CNTL, rinfo->save_regs[90]);
+
+	r2ec |= 8;
+	OUTREG(VGA_DDA_ON_OFF, r2ec);
+	mdelay(20);
+
+	/* Enable LVDS interface */
+	tmp = INREG(LVDS_GEN_CNTL);
+	OUTREG(LVDS_GEN_CNTL, tmp | LVDS_EN);
+
+	/* Enable LVDS_PLL */
+	tmp = INREG(LVDS_PLL_CNTL);
+	tmp &= ~0x30000;
+	tmp |= 0x10000;
+	OUTREG(LVDS_PLL_CNTL, tmp);
+
+	OUTPLL(pllSCLK_MORE_CNTL, rinfo->save_regs[34]);
+	OUTPLL(pllSS_TST_CNTL, rinfo->save_regs[91]);
+
+	/* The trace reads that one here, waiting for something to settle down ? */
+	INREG(RBBM_STATUS);
+
+	/* Ugh ? SS_TST_DEC is supposed to be a read register in the
+	 * R300 register spec at least...
+	 */
+	tmp = INPLL(pllSS_TST_CNTL);
+	tmp |= 0x00400000;
+	OUTPLL(pllSS_TST_CNTL, tmp);
+}
+
+static void radeon_pm_restore_pixel_pll(struct radeonfb_info *rinfo)
+{
+	u32 tmp;
+
+	OUTREG8(CLOCK_CNTL_INDEX, pllHTOTAL_CNTL + PLL_WR_EN);
+	radeon_pll_errata_after_index(rinfo);
+	OUTREG8(CLOCK_CNTL_DATA, 0);
+	radeon_pll_errata_after_data(rinfo);
+
+	tmp = INPLL(pllVCLK_ECP_CNTL);
+	OUTPLL(pllVCLK_ECP_CNTL, tmp | 0x80);
+	mdelay(5);
+
+	tmp = INPLL(pllPPLL_REF_DIV);
+	tmp = (tmp & ~PPLL_REF_DIV_MASK) | rinfo->pll.ref_div;
+	OUTPLL(pllPPLL_REF_DIV, tmp);
+	INPLL(pllPPLL_REF_DIV);
+
+	/* Reconfigure SPLL charge pump, VCO gain, duty cycle,
+	 * probably useless since we already did it ...
+	 */
+	tmp = INPLL(pllPPLL_CNTL);
+	OUTREG8(CLOCK_CNTL_INDEX, pllSPLL_CNTL + PLL_WR_EN);
+	radeon_pll_errata_after_index(rinfo);
+	OUTREG8(CLOCK_CNTL_DATA + 1, (tmp >> 8) & 0xff);
+	radeon_pll_errata_after_data(rinfo);
+
+	/* Restore our "reference" PPLL divider set by firmware
+	 * according to proper spread spectrum calculations
+	 */
+	OUTPLL(pllPPLL_DIV_0, rinfo->save_regs[92]);
+
+	tmp = INPLL(pllPPLL_CNTL);
+	OUTPLL(pllPPLL_CNTL, tmp & ~0x2);
+	mdelay(5);
+
+	tmp = INPLL(pllPPLL_CNTL);
+	OUTPLL(pllPPLL_CNTL, tmp & ~0x1);
+	mdelay(5);
+
+	tmp = INPLL(pllVCLK_ECP_CNTL);
+	OUTPLL(pllVCLK_ECP_CNTL, tmp | 3);
+	mdelay(5);
+
+	tmp = INPLL(pllVCLK_ECP_CNTL);
+	OUTPLL(pllVCLK_ECP_CNTL, tmp | 3);
+	mdelay(5);
+
+	/* Switch pixel clock to firmware default div 0 */
+	OUTREG8(CLOCK_CNTL_INDEX+1, 0);
+	radeon_pll_errata_after_index(rinfo);
+	radeon_pll_errata_after_data(rinfo);
+}
+
+static void radeon_pm_m10_reconfigure_mc(struct radeonfb_info *rinfo)
+{
+	OUTREG(MC_CNTL, rinfo->save_regs[46]);
+	OUTREG(MC_INIT_GFX_LAT_TIMER, rinfo->save_regs[47]);
+	OUTREG(MC_INIT_MISC_LAT_TIMER, rinfo->save_regs[48]);
+	OUTREG(MEM_SDRAM_MODE_REG,
+	       rinfo->save_regs[35] & ~MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE);
+	OUTREG(MC_TIMING_CNTL, rinfo->save_regs[49]);
+	OUTREG(MEM_REFRESH_CNTL, rinfo->save_regs[42]);
+	OUTREG(MC_READ_CNTL_AB, rinfo->save_regs[50]);
+	OUTREG(MC_CHIP_IO_OE_CNTL_AB, rinfo->save_regs[52]);
+	OUTREG(MC_IOPAD_CNTL, rinfo->save_regs[51]);
+	OUTREG(MC_DEBUG, rinfo->save_regs[53]);
+
+	OUTMC(rinfo, ixR300_MC_MC_INIT_WR_LAT_TIMER, rinfo->save_regs[58]);
+	OUTMC(rinfo, ixR300_MC_IMP_CNTL, rinfo->save_regs[59]);
+	OUTMC(rinfo, ixR300_MC_CHP_IO_CNTL_C0, rinfo->save_regs[60]);
+	OUTMC(rinfo, ixR300_MC_CHP_IO_CNTL_C1, rinfo->save_regs[61]);
+	OUTMC(rinfo, ixR300_MC_CHP_IO_CNTL_D0, rinfo->save_regs[62]);
+	OUTMC(rinfo, ixR300_MC_CHP_IO_CNTL_D1, rinfo->save_regs[63]);
+	OUTMC(rinfo, ixR300_MC_BIST_CNTL_3, rinfo->save_regs[64]);
+	OUTMC(rinfo, ixR300_MC_CHP_IO_CNTL_A0, rinfo->save_regs[65]);
+	OUTMC(rinfo, ixR300_MC_CHP_IO_CNTL_A1, rinfo->save_regs[66]);
+	OUTMC(rinfo, ixR300_MC_CHP_IO_CNTL_B0, rinfo->save_regs[67]);
+	OUTMC(rinfo, ixR300_MC_CHP_IO_CNTL_B1, rinfo->save_regs[68]);
+	OUTMC(rinfo, ixR300_MC_DEBUG_CNTL, rinfo->save_regs[69]);
+	OUTMC(rinfo, ixR300_MC_DLL_CNTL, rinfo->save_regs[70]);
+	OUTMC(rinfo, ixR300_MC_IMP_CNTL_0, rinfo->save_regs[71]);
+	OUTMC(rinfo, ixR300_MC_ELPIDA_CNTL, rinfo->save_regs[72]);
+	OUTMC(rinfo, ixR300_MC_READ_CNTL_CD, rinfo->save_regs[96]);
+	OUTREG(MC_IND_INDEX, 0);
+}
+
+static void radeon_reinitialize_M10(struct radeonfb_info *rinfo)
+{
+	u32 tmp, i;
+
+	/* Restore a bunch of registers first */
+	OUTREG(MC_AGP_LOCATION, rinfo->save_regs[32]);
+	OUTREG(DISPLAY_BASE_ADDR, rinfo->save_regs[31]);
+	OUTREG(CRTC2_DISPLAY_BASE_ADDR, rinfo->save_regs[33]);
+	OUTREG(MC_FB_LOCATION, rinfo->save_regs[30]);
+	OUTREG(OV0_BASE_ADDR, rinfo->save_regs[80]);
+	OUTREG(CONFIG_MEMSIZE, rinfo->video_ram);
+	OUTREG(BUS_CNTL, rinfo->save_regs[36]);
+	OUTREG(BUS_CNTL1, rinfo->save_regs[14]);
+	OUTREG(MPP_TB_CONFIG, rinfo->save_regs[37]);
+	OUTREG(FCP_CNTL, rinfo->save_regs[38]);
+	OUTREG(RBBM_CNTL, rinfo->save_regs[39]);
+	OUTREG(DAC_CNTL, rinfo->save_regs[40]);
+	OUTREG(DAC_MACRO_CNTL, (INREG(DAC_MACRO_CNTL) & ~0x6) | 8);
+	OUTREG(DAC_MACRO_CNTL, (INREG(DAC_MACRO_CNTL) & ~0x6) | 8);
+
+	/* Hrm... */
+	OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) | DAC2_EXPAND_MODE);
+
+	/* Reset the PAD CTLR */
+	radeon_pm_reset_pad_ctlr_strength(rinfo);
+
+	/* Some PLLs are Read & written identically in the trace here...
+	 * I suppose it's actually to switch them all off & reset,
+	 * let's assume off is what we want. I'm just doing that for all major PLLs now.
+	 */
+	radeon_pm_all_ppls_off(rinfo);
+
+	/* Clear tiling, reset swappers */
+	INREG(SURFACE_CNTL);
+	OUTREG(SURFACE_CNTL, 0);
+
+	/* Some black magic with TV_DAC_CNTL, we should restore those from backups
+	 * rather than hard coding...
+	 */
+	tmp = INREG(TV_DAC_CNTL) & ~TV_DAC_CNTL_BGADJ_MASK;
+	tmp |= 8 << TV_DAC_CNTL_BGADJ__SHIFT;
+	OUTREG(TV_DAC_CNTL, tmp);
+
+	tmp = INREG(TV_DAC_CNTL) & ~TV_DAC_CNTL_DACADJ_MASK;
+	tmp |= 7 << TV_DAC_CNTL_DACADJ__SHIFT;
+	OUTREG(TV_DAC_CNTL, tmp);
+
+	/* More registers restored */
+	OUTREG(AGP_CNTL, rinfo->save_regs[16]);
+	OUTREG(HOST_PATH_CNTL, rinfo->save_regs[41]);
+	OUTREG(DISP_MISC_CNTL, rinfo->save_regs[9]);
+
+	/* Hrmmm ... What is that ? */
+	tmp = rinfo->save_regs[1]
+		& ~(CLK_PWRMGT_CNTL__ACTIVE_HILO_LAT_MASK |
+		    CLK_PWRMGT_CNTL__MC_BUSY);
+	OUTPLL(pllCLK_PWRMGT_CNTL, tmp);
+
+	OUTREG(PAD_CTLR_MISC, rinfo->save_regs[56]);
+	OUTREG(FW_CNTL, rinfo->save_regs[57]);
+	OUTREG(HDP_DEBUG, rinfo->save_regs[96]);
+	OUTREG(PAMAC0_DLY_CNTL, rinfo->save_regs[54]);
+	OUTREG(PAMAC1_DLY_CNTL, rinfo->save_regs[55]);
+	OUTREG(PAMAC2_DLY_CNTL, rinfo->save_regs[79]);
+
+	/* Restore Memory Controller configuration */
+	radeon_pm_m10_reconfigure_mc(rinfo);
+
+	/* Make sure CRTC's dont touch memory */
+	OUTREG(CRTC_GEN_CNTL, INREG(CRTC_GEN_CNTL)
+	       | CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B);
+	OUTREG(CRTC2_GEN_CNTL, INREG(CRTC2_GEN_CNTL)
+	       | CRTC2_GEN_CNTL__CRTC2_DISP_REQ_EN_B);
+	mdelay(30);
+
+	/* Disable SDRAM refresh */
+	OUTREG(MEM_REFRESH_CNTL, INREG(MEM_REFRESH_CNTL)
+	       | MEM_REFRESH_CNTL__MEM_REFRESH_DIS);
+
+	/* Restore XTALIN routing (CLK_PIN_CNTL) */
+	OUTPLL(pllCLK_PIN_CNTL, rinfo->save_regs[4]);
+
+	/* Switch MCLK, YCLK and SCLK PLLs to PCI source & force them ON */
+	tmp = rinfo->save_regs[2] & 0xff000000;
+	tmp |=	MCLK_CNTL__FORCE_MCLKA |
+		MCLK_CNTL__FORCE_MCLKB |
+		MCLK_CNTL__FORCE_YCLKA |
+		MCLK_CNTL__FORCE_YCLKB |
+		MCLK_CNTL__FORCE_MC;
+	OUTPLL(pllMCLK_CNTL, tmp);
+
+	/* Force all clocks on in SCLK */
+	tmp = INPLL(pllSCLK_CNTL);
+	tmp |=	SCLK_CNTL__FORCE_DISP2|
+		SCLK_CNTL__FORCE_CP|
+		SCLK_CNTL__FORCE_HDP|
+		SCLK_CNTL__FORCE_DISP1|
+		SCLK_CNTL__FORCE_TOP|
+		SCLK_CNTL__FORCE_E2|
+		SCLK_CNTL__FORCE_SE|
+		SCLK_CNTL__FORCE_IDCT|
+		SCLK_CNTL__FORCE_VIP|
+		SCLK_CNTL__FORCE_PB|
+		SCLK_CNTL__FORCE_TAM|
+		SCLK_CNTL__FORCE_TDM|
+		SCLK_CNTL__FORCE_RB|
+		SCLK_CNTL__FORCE_TV_SCLK|
+		SCLK_CNTL__FORCE_SUBPIC|
+		SCLK_CNTL__FORCE_OV0;
+	tmp |=	SCLK_CNTL__CP_MAX_DYN_STOP_LAT  |
+		SCLK_CNTL__HDP_MAX_DYN_STOP_LAT |
+		SCLK_CNTL__TV_MAX_DYN_STOP_LAT  |
+		SCLK_CNTL__E2_MAX_DYN_STOP_LAT  |
+		SCLK_CNTL__SE_MAX_DYN_STOP_LAT  |
+		SCLK_CNTL__IDCT_MAX_DYN_STOP_LAT|
+		SCLK_CNTL__VIP_MAX_DYN_STOP_LAT |
+		SCLK_CNTL__RE_MAX_DYN_STOP_LAT  |
+		SCLK_CNTL__PB_MAX_DYN_STOP_LAT  |
+		SCLK_CNTL__TAM_MAX_DYN_STOP_LAT |
+		SCLK_CNTL__TDM_MAX_DYN_STOP_LAT |
+		SCLK_CNTL__RB_MAX_DYN_STOP_LAT;
+	OUTPLL(pllSCLK_CNTL, tmp);
+
+	OUTPLL(pllVCLK_ECP_CNTL, 0);
+	OUTPLL(pllPIXCLKS_CNTL, 0);
+	OUTPLL(pllMCLK_MISC,
+	       MCLK_MISC__MC_MCLK_MAX_DYN_STOP_LAT |
+	       MCLK_MISC__IO_MCLK_MAX_DYN_STOP_LAT);
+
+	mdelay(5);
+
+	/* Restore the M_SPLL_REF_FB_DIV, MPLL_AUX_CNTL and SPLL_AUX_CNTL values */
+	OUTPLL(pllM_SPLL_REF_FB_DIV, rinfo->save_regs[77]);
+	OUTPLL(pllMPLL_AUX_CNTL, rinfo->save_regs[75]);
+	OUTPLL(pllSPLL_AUX_CNTL, rinfo->save_regs[76]);
+
+	/* Now restore the major PLLs settings, keeping them off & reset though */
+	OUTPLL(pllPPLL_CNTL, rinfo->save_regs[93] | 0x3);
+	OUTPLL(pllP2PLL_CNTL, rinfo->save_regs[8] | 0x3);
+	OUTPLL(pllMPLL_CNTL, rinfo->save_regs[73] | 0x03);
+	OUTPLL(pllSPLL_CNTL, rinfo->save_regs[74] | 0x03);
+
+	/* Restore MC DLL state and switch it off/reset too  */
+	OUTMC(rinfo, ixR300_MC_DLL_CNTL, rinfo->save_regs[70]);
+
+	/* Switch MDLL off & reset */
+	OUTPLL(pllMDLL_RDCKA, rinfo->save_regs[98] | 0xff);
+	mdelay(5);
+
+	/* Setup some black magic bits in PLL_PWRMGT_CNTL. Hrm... we saved
+	 * 0xa1100007... and MacOS writes 0xa1000007 ..
+	 */
+	OUTPLL(pllPLL_PWRMGT_CNTL, rinfo->save_regs[0]);
+
+	/* Restore more stuffs */
+	OUTPLL(pllHTOTAL_CNTL, 0);
+	OUTPLL(pllHTOTAL2_CNTL, 0);
+
+	/* More PLL initial configuration */
+	tmp = INPLL(pllSCLK_CNTL2); /* What for ? */
+	OUTPLL(pllSCLK_CNTL2, tmp);
+
+	tmp = INPLL(pllSCLK_MORE_CNTL);
+	tmp |= 	SCLK_MORE_CNTL__FORCE_DISPREGS |	/* a guess */
+		SCLK_MORE_CNTL__FORCE_MC_GUI |
+		SCLK_MORE_CNTL__FORCE_MC_HOST;
+	OUTPLL(pllSCLK_MORE_CNTL, tmp);
+
+	/* Now we actually start MCLK and SCLK */
+	radeon_pm_start_mclk_sclk(rinfo);
+
+	/* Full reset sdrams, this also re-inits the MDLL */
+	radeon_pm_full_reset_sdram(rinfo);
+
+	/* Fill palettes */
+	OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) | 0x20);
+	for (i=0; i<256; i++)
+		OUTREG(PALETTE_30_DATA, 0x15555555);
+	OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) & ~20);
+	udelay(20);
+	for (i=0; i<256; i++)
+		OUTREG(PALETTE_30_DATA, 0x15555555);
+
+	OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) & ~0x20);
+	mdelay(3);
+
+	/* Restore TMDS */
+	OUTREG(FP_GEN_CNTL, rinfo->save_regs[82]);
+	OUTREG(FP2_GEN_CNTL, rinfo->save_regs[83]);
+
+	/* Set LVDS registers but keep interface & pll down */
+	OUTREG(LVDS_GEN_CNTL, rinfo->save_regs[11] &
+	       ~(LVDS_EN | LVDS_ON | LVDS_DIGON | LVDS_BLON | LVDS_BL_MOD_EN));
+	OUTREG(LVDS_PLL_CNTL, (rinfo->save_regs[12] & ~0xf0000) | 0x20000);
+
+	OUTREG(DISP_OUTPUT_CNTL, rinfo->save_regs[86]);
+
+	/* Restore GPIOPAD state */
+	OUTREG(GPIOPAD_A, rinfo->save_regs[19]);
+	OUTREG(GPIOPAD_EN, rinfo->save_regs[20]);
+	OUTREG(GPIOPAD_MASK, rinfo->save_regs[21]);
+
+	/* write some stuff to the framebuffer... */
+	for (i = 0; i < 0x8000; ++i)
+		writeb(0, rinfo->fb_base + i);
+
+	mdelay(40);
+	OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) | LVDS_DIGON | LVDS_ON);
+	mdelay(40);
+
+	/* Restore a few more things */
+	OUTREG(GRPH_BUFFER_CNTL, rinfo->save_regs[94]);
+	OUTREG(GRPH2_BUFFER_CNTL, rinfo->save_regs[95]);
+
+	/* Take care of spread spectrum & PPLLs now */
+	radeon_pm_m10_disable_spread_spectrum(rinfo);
+	radeon_pm_restore_pixel_pll(rinfo);
+
+	/* GRRRR... I can't figure out the proper LVDS power sequence, and the
+	 * code I have for blank/unblank doesn't quite work on some laptop models
+	 * it seems ... Hrm. What I have here works most of the time ...
+	 */
+	radeon_pm_m10_enable_lvds_spread_spectrum(rinfo);
+}
+
+static void radeon_pm_m9p_reconfigure_mc(struct radeonfb_info *rinfo)
+{
+	OUTREG(MC_CNTL, rinfo->save_regs[46]);
+	OUTREG(MC_INIT_GFX_LAT_TIMER, rinfo->save_regs[47]);
+	OUTREG(MC_INIT_MISC_LAT_TIMER, rinfo->save_regs[48]);
+	OUTREG(MEM_SDRAM_MODE_REG,
+	       rinfo->save_regs[35] & ~MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE);
+	OUTREG(MC_TIMING_CNTL, rinfo->save_regs[49]);
+	OUTREG(MC_READ_CNTL_AB, rinfo->save_regs[50]);
+	OUTREG(MEM_REFRESH_CNTL, rinfo->save_regs[42]);
+	OUTREG(MC_IOPAD_CNTL, rinfo->save_regs[51]);
+	OUTREG(MC_DEBUG, rinfo->save_regs[53]);
+	OUTREG(MC_CHIP_IO_OE_CNTL_AB, rinfo->save_regs[52]);
+
+	OUTMC(rinfo, ixMC_IMP_CNTL, rinfo->save_regs[59] /*0x00f460d6*/);
+	OUTMC(rinfo, ixMC_CHP_IO_CNTL_A0, rinfo->save_regs[65] /*0xfecfa666*/);
+	OUTMC(rinfo, ixMC_CHP_IO_CNTL_A1, rinfo->save_regs[66] /*0x141555ff*/);
+	OUTMC(rinfo, ixMC_CHP_IO_CNTL_B0, rinfo->save_regs[67] /*0xfecfa666*/);
+	OUTMC(rinfo, ixMC_CHP_IO_CNTL_B1, rinfo->save_regs[68] /*0x141555ff*/);
+	OUTMC(rinfo, ixMC_IMP_CNTL_0, rinfo->save_regs[71] /*0x00009249*/);
+	OUTREG(MC_IND_INDEX, 0);
+	OUTREG(CONFIG_MEMSIZE, rinfo->video_ram);
+
+	mdelay(20);
+}
+
+static void radeon_reinitialize_M9P(struct radeonfb_info *rinfo)
+{
+	u32 tmp, i;
+
+	/* Restore a bunch of registers first */
+	OUTREG(SURFACE_CNTL, rinfo->save_regs[29]);
+	OUTREG(MC_AGP_LOCATION, rinfo->save_regs[32]);
+	OUTREG(DISPLAY_BASE_ADDR, rinfo->save_regs[31]);
+	OUTREG(CRTC2_DISPLAY_BASE_ADDR, rinfo->save_regs[33]);
+	OUTREG(MC_FB_LOCATION, rinfo->save_regs[30]);
+	OUTREG(OV0_BASE_ADDR, rinfo->save_regs[80]);
+	OUTREG(BUS_CNTL, rinfo->save_regs[36]);
+	OUTREG(BUS_CNTL1, rinfo->save_regs[14]);
+	OUTREG(MPP_TB_CONFIG, rinfo->save_regs[37]);
+	OUTREG(FCP_CNTL, rinfo->save_regs[38]);
+	OUTREG(RBBM_CNTL, rinfo->save_regs[39]);
+
+	OUTREG(DAC_CNTL, rinfo->save_regs[40]);
+	OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) | DAC2_EXPAND_MODE);
+
+	/* Reset the PAD CTLR */
+	radeon_pm_reset_pad_ctlr_strength(rinfo);
+
+	/* Some PLLs are Read & written identically in the trace here...
+	 * I suppose it's actually to switch them all off & reset,
+	 * let's assume off is what we want. I'm just doing that for all major PLLs now.
+	 */
+	radeon_pm_all_ppls_off(rinfo);
+
+	/* Clear tiling, reset swappers */
+	INREG(SURFACE_CNTL);
+	OUTREG(SURFACE_CNTL, 0);
+
+	/* Some black magic with TV_DAC_CNTL, we should restore those from backups
+	 * rather than hard coding...
+	 */
+	tmp = INREG(TV_DAC_CNTL) & ~TV_DAC_CNTL_BGADJ_MASK;
+	tmp |= 6 << TV_DAC_CNTL_BGADJ__SHIFT;
+	OUTREG(TV_DAC_CNTL, tmp);
+
+	tmp = INREG(TV_DAC_CNTL) & ~TV_DAC_CNTL_DACADJ_MASK;
+	tmp |= 6 << TV_DAC_CNTL_DACADJ__SHIFT;
+	OUTREG(TV_DAC_CNTL, tmp);
+
+	OUTPLL(pllAGP_PLL_CNTL, rinfo->save_regs[78]);
+
+	OUTREG(PAMAC0_DLY_CNTL, rinfo->save_regs[54]);
+	OUTREG(PAMAC1_DLY_CNTL, rinfo->save_regs[55]);
+	OUTREG(PAMAC2_DLY_CNTL, rinfo->save_regs[79]);
+
+	OUTREG(AGP_CNTL, rinfo->save_regs[16]);
+	OUTREG(HOST_PATH_CNTL, rinfo->save_regs[41]); /* MacOS sets that to 0 !!! */
+	OUTREG(DISP_MISC_CNTL, rinfo->save_regs[9]);
+
+	tmp  = rinfo->save_regs[1]
+		& ~(CLK_PWRMGT_CNTL__ACTIVE_HILO_LAT_MASK |
+		    CLK_PWRMGT_CNTL__MC_BUSY);
+	OUTPLL(pllCLK_PWRMGT_CNTL, tmp);
+
+	OUTREG(FW_CNTL, rinfo->save_regs[57]);
+
+	/* Disable SDRAM refresh */
+	OUTREG(MEM_REFRESH_CNTL, INREG(MEM_REFRESH_CNTL)
+	       | MEM_REFRESH_CNTL__MEM_REFRESH_DIS);
+
+	/* Restore XTALIN routing (CLK_PIN_CNTL) */
+       	OUTPLL(pllCLK_PIN_CNTL, rinfo->save_regs[4]);
+
+	/* Force MCLK to be PCI sourced and forced ON */
+	tmp = rinfo->save_regs[2] & 0xff000000;
+	tmp |=	MCLK_CNTL__FORCE_MCLKA |
+		MCLK_CNTL__FORCE_MCLKB |
+		MCLK_CNTL__FORCE_YCLKA |
+		MCLK_CNTL__FORCE_YCLKB |
+		MCLK_CNTL__FORCE_MC    |
+		MCLK_CNTL__FORCE_AIC;
+	OUTPLL(pllMCLK_CNTL, tmp);
+
+	/* Force SCLK to be PCI sourced with a bunch forced */
+	tmp =	0 |
+		SCLK_CNTL__FORCE_DISP2|
+		SCLK_CNTL__FORCE_CP|
+		SCLK_CNTL__FORCE_HDP|
+		SCLK_CNTL__FORCE_DISP1|
+		SCLK_CNTL__FORCE_TOP|
+		SCLK_CNTL__FORCE_E2|
+		SCLK_CNTL__FORCE_SE|
+		SCLK_CNTL__FORCE_IDCT|
+		SCLK_CNTL__FORCE_VIP|
+		SCLK_CNTL__FORCE_RE|
+		SCLK_CNTL__FORCE_PB|
+		SCLK_CNTL__FORCE_TAM|
+		SCLK_CNTL__FORCE_TDM|
+		SCLK_CNTL__FORCE_RB;
+	OUTPLL(pllSCLK_CNTL, tmp);
+
+	/* Clear VCLK_ECP_CNTL & PIXCLKS_CNTL  */
+	OUTPLL(pllVCLK_ECP_CNTL, 0);
+	OUTPLL(pllPIXCLKS_CNTL, 0);
+
+	/* Setup MCLK_MISC, non dynamic mode */
+	OUTPLL(pllMCLK_MISC,
+	       MCLK_MISC__MC_MCLK_MAX_DYN_STOP_LAT |
+	       MCLK_MISC__IO_MCLK_MAX_DYN_STOP_LAT);
+
+	mdelay(5);
+
+	/* Set back the default clock dividers */
+	OUTPLL(pllM_SPLL_REF_FB_DIV, rinfo->save_regs[77]);
+	OUTPLL(pllMPLL_AUX_CNTL, rinfo->save_regs[75]);
+	OUTPLL(pllSPLL_AUX_CNTL, rinfo->save_regs[76]);
+
+	/* PPLL and P2PLL default values & off */
+	OUTPLL(pllPPLL_CNTL, rinfo->save_regs[93] | 0x3);
+	OUTPLL(pllP2PLL_CNTL, rinfo->save_regs[8] | 0x3);
+
+	/* S and M PLLs are reset & off, configure them */
+	OUTPLL(pllMPLL_CNTL, rinfo->save_regs[73] | 0x03);
+	OUTPLL(pllSPLL_CNTL, rinfo->save_regs[74] | 0x03);
+
+	/* Default values for MDLL ... fixme */
+	OUTPLL(pllMDLL_CKO, 0x9c009c);
+	OUTPLL(pllMDLL_RDCKA, 0x08830883);
+	OUTPLL(pllMDLL_RDCKB, 0x08830883);
+	mdelay(5);
+
+	/* Restore PLL_PWRMGT_CNTL */ // XXXX
+	tmp = rinfo->save_regs[0];
+	tmp &= ~PLL_PWRMGT_CNTL_SU_SCLK_USE_BCLK;
+	tmp |= PLL_PWRMGT_CNTL_SU_MCLK_USE_BCLK;
+	OUTPLL(PLL_PWRMGT_CNTL,  tmp);
+
+	/* Clear HTOTAL_CNTL & HTOTAL2_CNTL */
+	OUTPLL(pllHTOTAL_CNTL, 0);
+	OUTPLL(pllHTOTAL2_CNTL, 0);
+
+	/* All outputs off */
+	OUTREG(CRTC_GEN_CNTL, 0x04000000);
+	OUTREG(CRTC2_GEN_CNTL, 0x04000000);
+	OUTREG(FP_GEN_CNTL, 0x00004008);
+	OUTREG(FP2_GEN_CNTL, 0x00000008);
+	OUTREG(LVDS_GEN_CNTL, 0x08000008);
+
+	/* Restore Memory Controller configuration */
+	radeon_pm_m9p_reconfigure_mc(rinfo);
+
+	/* Now we actually start MCLK and SCLK */
+	radeon_pm_start_mclk_sclk(rinfo);
+
+	/* Full reset sdrams, this also re-inits the MDLL */
+	radeon_pm_full_reset_sdram(rinfo);
+
+	/* Fill palettes */
+	OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) | 0x20);
+	for (i=0; i<256; i++)
+		OUTREG(PALETTE_30_DATA, 0x15555555);
+	OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) & ~20);
+	udelay(20);
+	for (i=0; i<256; i++)
+		OUTREG(PALETTE_30_DATA, 0x15555555);
+
+	OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) & ~0x20);
+	mdelay(3);
+
+	/* Restore TV stuff, make sure TV DAC is down */
+	OUTREG(TV_MASTER_CNTL, rinfo->save_regs[88]);
+	OUTREG(TV_DAC_CNTL, rinfo->save_regs[13] | 0x07000000);
+
+	/* Restore GPIOS. MacOS does some magic here with one of the GPIO bits,
+	 * possibly related to the weird PLL related workarounds and to the
+	 * fact that CLK_PIN_CNTL is tweaked in ways I don't fully understand,
+	 * but we keep things the simple way here
+	 */
+	OUTREG(GPIOPAD_A, rinfo->save_regs[19]);
+	OUTREG(GPIOPAD_EN, rinfo->save_regs[20]);
+	OUTREG(GPIOPAD_MASK, rinfo->save_regs[21]);
+
+	/* Now do things with SCLK_MORE_CNTL. Force bits are already set, copy
+	 * high bits from backup
+	 */
+	tmp = INPLL(pllSCLK_MORE_CNTL) & 0x0000ffff;
+	tmp |= rinfo->save_regs[34] & 0xffff0000;
+	tmp |= SCLK_MORE_CNTL__FORCE_DISPREGS;
+	OUTPLL(pllSCLK_MORE_CNTL, tmp);
+
+	tmp = INPLL(pllSCLK_MORE_CNTL) & 0x0000ffff;
+	tmp |= rinfo->save_regs[34] & 0xffff0000;
+	tmp |= SCLK_MORE_CNTL__FORCE_DISPREGS;
+	OUTPLL(pllSCLK_MORE_CNTL, tmp);
+
+	OUTREG(LVDS_GEN_CNTL, rinfo->save_regs[11] &
+	       ~(LVDS_EN | LVDS_ON | LVDS_DIGON | LVDS_BLON | LVDS_BL_MOD_EN));
+	OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) | LVDS_BLON);
+	OUTREG(LVDS_PLL_CNTL, (rinfo->save_regs[12] & ~0xf0000) | 0x20000);
+	mdelay(20);
+
+	/* write some stuff to the framebuffer... */
+	for (i = 0; i < 0x8000; ++i)
+		writeb(0, rinfo->fb_base + i);
+
+	OUTREG(0x2ec, 0x6332a020);
+	OUTPLL(pllSSPLL_REF_DIV, rinfo->save_regs[44] /*0x3f */);
+	OUTPLL(pllSSPLL_DIV_0, rinfo->save_regs[45] /*0x000081bb */);
+	tmp = INPLL(pllSSPLL_CNTL);
+	tmp &= ~2;
+	OUTPLL(pllSSPLL_CNTL, tmp);
+	mdelay(6);
+	tmp &= ~1;
+	OUTPLL(pllSSPLL_CNTL, tmp);
+	mdelay(5);
+	tmp |= 3;
+	OUTPLL(pllSSPLL_CNTL, tmp);
+	mdelay(5);
+
+	OUTPLL(pllSS_INT_CNTL, rinfo->save_regs[90] & ~3);/*0x0020300c*/
+	OUTREG(0x2ec, 0x6332a3f0);
+	mdelay(17);
+
+	OUTPLL(pllPPLL_REF_DIV, rinfo->pll.ref_div);;
+	OUTPLL(pllPPLL_DIV_0, rinfo->save_regs[92]);
+
+	mdelay(40);
+	OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) | LVDS_DIGON | LVDS_ON);
+	mdelay(40);
+
+	/* Restore a few more things */
+	OUTREG(GRPH_BUFFER_CNTL, rinfo->save_regs[94]);
+	OUTREG(GRPH2_BUFFER_CNTL, rinfo->save_regs[95]);
+
+	/* Restore PPLL, spread spectrum & LVDS */
+	radeon_pm_m10_disable_spread_spectrum(rinfo);
+	radeon_pm_restore_pixel_pll(rinfo);
+	radeon_pm_m10_enable_lvds_spread_spectrum(rinfo);
+}
+
+#if 0 /* Not ready yet */
+static void radeon_reinitialize_QW(struct radeonfb_info *rinfo)
+{
+	int i;
+	u32 tmp, tmp2;
+	u32 cko, cka, ckb;
+	u32 cgc, cec, c2gc;
+
+	OUTREG(MC_AGP_LOCATION, rinfo->save_regs[32]);
+	OUTREG(DISPLAY_BASE_ADDR, rinfo->save_regs[31]);
+	OUTREG(CRTC2_DISPLAY_BASE_ADDR, rinfo->save_regs[33]);
+	OUTREG(MC_FB_LOCATION, rinfo->save_regs[30]);
+	OUTREG(BUS_CNTL, rinfo->save_regs[36]);
+	OUTREG(RBBM_CNTL, rinfo->save_regs[39]);
+
+	INREG(PAD_CTLR_STRENGTH);
+	OUTREG(PAD_CTLR_STRENGTH, INREG(PAD_CTLR_STRENGTH) & ~0x10000);
+	for (i = 0; i < 65; ++i) {
+		mdelay(1);
+		INREG(PAD_CTLR_STRENGTH);
+	}
+
+	OUTREG(DISP_TEST_DEBUG_CNTL, INREG(DISP_TEST_DEBUG_CNTL) | 0x10000000);
+	OUTREG(OV0_FLAG_CNTRL, INREG(OV0_FLAG_CNTRL) | 0x100);
+	OUTREG(CRTC_GEN_CNTL, INREG(CRTC_GEN_CNTL));
+	OUTREG(DAC_CNTL, 0xff00410a);
+	OUTREG(CRTC2_GEN_CNTL, INREG(CRTC2_GEN_CNTL));
+	OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) | 0x4000);
+
+	OUTREG(SURFACE_CNTL, rinfo->save_regs[29]);
+	OUTREG(AGP_CNTL, rinfo->save_regs[16]);
+	OUTREG(HOST_PATH_CNTL, rinfo->save_regs[41]);
+	OUTREG(DISP_MISC_CNTL, rinfo->save_regs[9]);
+
+	OUTMC(rinfo, ixMC_CHP_IO_CNTL_A0, 0xf7bb4433);
+	OUTREG(MC_IND_INDEX, 0);
+	OUTMC(rinfo, ixMC_CHP_IO_CNTL_B0, 0xf7bb4433);
+	OUTREG(MC_IND_INDEX, 0);
+
+	OUTREG(CRTC_MORE_CNTL, INREG(CRTC_MORE_CNTL));
+
+	tmp = INPLL(pllVCLK_ECP_CNTL);
+	OUTPLL(pllVCLK_ECP_CNTL, tmp);
+	tmp = INPLL(pllPIXCLKS_CNTL);
+	OUTPLL(pllPIXCLKS_CNTL, tmp);
+
+	OUTPLL(MCLK_CNTL, 0xaa3f0000);
+	OUTPLL(SCLK_CNTL, 0xffff0000);
+	OUTPLL(pllMPLL_AUX_CNTL, 6);
+	OUTPLL(pllSPLL_AUX_CNTL, 1);
+	OUTPLL(MDLL_CKO, 0x9f009f);
+	OUTPLL(MDLL_RDCKA, 0x830083);
+	OUTPLL(pllMDLL_RDCKB, 0x830083);
+	OUTPLL(PPLL_CNTL, 0xa433);
+	OUTPLL(P2PLL_CNTL, 0xa433);
+	OUTPLL(MPLL_CNTL, 0x0400a403);
+	OUTPLL(SPLL_CNTL, 0x0400a433);
+
+	tmp = INPLL(M_SPLL_REF_FB_DIV);
+	OUTPLL(M_SPLL_REF_FB_DIV, tmp);
+	tmp = INPLL(M_SPLL_REF_FB_DIV);
+	OUTPLL(M_SPLL_REF_FB_DIV, tmp | 0xc);
+	INPLL(M_SPLL_REF_FB_DIV);
+
+	tmp = INPLL(MPLL_CNTL);
+	OUTREG8(CLOCK_CNTL_INDEX, MPLL_CNTL + PLL_WR_EN);
+	radeon_pll_errata_after_index(rinfo);
+	OUTREG8(CLOCK_CNTL_DATA + 1, (tmp >> 8) & 0xff);
+	radeon_pll_errata_after_data(rinfo);
+
+	tmp = INPLL(M_SPLL_REF_FB_DIV);
+	OUTPLL(M_SPLL_REF_FB_DIV, tmp | 0x5900);
+
+	tmp = INPLL(MPLL_CNTL);
+	OUTPLL(MPLL_CNTL, tmp & ~0x2);
+	mdelay(1);
+	tmp = INPLL(MPLL_CNTL);
+	OUTPLL(MPLL_CNTL, tmp & ~0x1);
+	mdelay(10);
+
+	OUTPLL(MCLK_CNTL, 0xaa3f1212);
+	mdelay(1);
+
+	INPLL(M_SPLL_REF_FB_DIV);
+	INPLL(MCLK_CNTL);
+	INPLL(M_SPLL_REF_FB_DIV);
+
+	tmp = INPLL(SPLL_CNTL);
+	OUTREG8(CLOCK_CNTL_INDEX, SPLL_CNTL + PLL_WR_EN);
+	radeon_pll_errata_after_index(rinfo);
+	OUTREG8(CLOCK_CNTL_DATA + 1, (tmp >> 8) & 0xff);
+	radeon_pll_errata_after_data(rinfo);
+
+	tmp = INPLL(M_SPLL_REF_FB_DIV);
+	OUTPLL(M_SPLL_REF_FB_DIV, tmp | 0x780000);
+
+	tmp = INPLL(SPLL_CNTL);
+	OUTPLL(SPLL_CNTL, tmp & ~0x1);
+	mdelay(1);
+	tmp = INPLL(SPLL_CNTL);
+	OUTPLL(SPLL_CNTL, tmp & ~0x2);
+	mdelay(10);
+
+	tmp = INPLL(SCLK_CNTL);
+	OUTPLL(SCLK_CNTL, tmp | 2);
+	mdelay(1);
+
+	cko = INPLL(pllMDLL_CKO);
+	cka = INPLL(pllMDLL_RDCKA);
+	ckb = INPLL(pllMDLL_RDCKB);
+
+	cko &= ~(MDLL_CKO__MCKOA_SLEEP | MDLL_CKO__MCKOB_SLEEP);
+	OUTPLL(pllMDLL_CKO, cko);
+	mdelay(1);
+	cko &= ~(MDLL_CKO__MCKOA_RESET | MDLL_CKO__MCKOB_RESET);
+	OUTPLL(pllMDLL_CKO, cko);
+	mdelay(5);
+
+	cka &= ~(MDLL_RDCKA__MRDCKA0_SLEEP | MDLL_RDCKA__MRDCKA1_SLEEP);
+	OUTPLL(pllMDLL_RDCKA, cka);
+	mdelay(1);
+	cka &= ~(MDLL_RDCKA__MRDCKA0_RESET | MDLL_RDCKA__MRDCKA1_RESET);
+	OUTPLL(pllMDLL_RDCKA, cka);
+	mdelay(5);
+
+	ckb &= ~(MDLL_RDCKB__MRDCKB0_SLEEP | MDLL_RDCKB__MRDCKB1_SLEEP);
+	OUTPLL(pllMDLL_RDCKB, ckb);
+	mdelay(1);
+	ckb &= ~(MDLL_RDCKB__MRDCKB0_RESET | MDLL_RDCKB__MRDCKB1_RESET);
+	OUTPLL(pllMDLL_RDCKB, ckb);
+	mdelay(5);
+
+	OUTMC(rinfo, ixMC_CHP_IO_CNTL_A1, 0x151550ff);
+	OUTREG(MC_IND_INDEX, 0);
+	OUTMC(rinfo, ixMC_CHP_IO_CNTL_B1, 0x151550ff);
+	OUTREG(MC_IND_INDEX, 0);
+	mdelay(1);
+	OUTMC(rinfo, ixMC_CHP_IO_CNTL_A1, 0x141550ff);
+	OUTREG(MC_IND_INDEX, 0);
+	OUTMC(rinfo, ixMC_CHP_IO_CNTL_B1, 0x141550ff);
+	OUTREG(MC_IND_INDEX, 0);
+	mdelay(1);
+
+	OUTPLL(pllHTOTAL_CNTL, 0);
+	OUTPLL(pllHTOTAL2_CNTL, 0);
+
+	OUTREG(MEM_CNTL, 0x29002901);
+	OUTREG(MEM_SDRAM_MODE_REG, 0x45320032);	/* XXX use save_regs[35]? */
+	OUTREG(EXT_MEM_CNTL, 0x1a394333);
+	OUTREG(MEM_IO_CNTL_A1, 0x0aac0aac);
+	OUTREG(MEM_INIT_LATENCY_TIMER, 0x34444444);
+	OUTREG(MEM_REFRESH_CNTL, 0x1f1f7218);	/* XXX or save_regs[42]? */
+	OUTREG(MC_DEBUG, 0);
+	OUTREG(MEM_IO_OE_CNTL, 0x04300430);
+
+	OUTMC(rinfo, ixMC_IMP_CNTL, 0x00f460d6);
+	OUTREG(MC_IND_INDEX, 0);
+	OUTMC(rinfo, ixMC_IMP_CNTL_0, 0x00009249);
+	OUTREG(MC_IND_INDEX, 0);
+
+	OUTREG(CONFIG_MEMSIZE, rinfo->video_ram);
+
+	radeon_pm_full_reset_sdram(rinfo);
+
+	INREG(FP_GEN_CNTL);
+	OUTREG(TMDS_CNTL, 0x01000000);	/* XXX ? */
+	tmp = INREG(FP_GEN_CNTL);
+	tmp |= FP_CRTC_DONT_SHADOW_HEND | FP_CRTC_DONT_SHADOW_VPAR | 0x200;
+	OUTREG(FP_GEN_CNTL, tmp);
+
+	tmp = INREG(DISP_OUTPUT_CNTL);
+	tmp &= ~0x400;
+	OUTREG(DISP_OUTPUT_CNTL, tmp);
+
+	OUTPLL(CLK_PIN_CNTL, rinfo->save_regs[4]);
+	OUTPLL(CLK_PWRMGT_CNTL, rinfo->save_regs[1]);
+	OUTPLL(PLL_PWRMGT_CNTL, rinfo->save_regs[0]);
+
+	tmp = INPLL(MCLK_MISC);
+	tmp |= MCLK_MISC__MC_MCLK_DYN_ENABLE | MCLK_MISC__IO_MCLK_DYN_ENABLE;
+	OUTPLL(MCLK_MISC, tmp);
+
+	tmp = INPLL(SCLK_CNTL);
+	OUTPLL(SCLK_CNTL, tmp);
+
+	OUTREG(CRTC_MORE_CNTL, 0);
+	OUTREG8(CRTC_GEN_CNTL+1, 6);
+	OUTREG8(CRTC_GEN_CNTL+3, 1);
+	OUTREG(CRTC_PITCH, 32);
+
+	tmp = INPLL(VCLK_ECP_CNTL);
+	OUTPLL(VCLK_ECP_CNTL, tmp);
+
+	tmp = INPLL(PPLL_CNTL);
+	OUTPLL(PPLL_CNTL, tmp);
+
+	/* palette stuff and BIOS_1_SCRATCH... */
+
+	tmp = INREG(FP_GEN_CNTL);
+	tmp2 = INREG(TMDS_TRANSMITTER_CNTL);
+	tmp |= 2;
+	OUTREG(FP_GEN_CNTL, tmp);
+	mdelay(5);
+	OUTREG(FP_GEN_CNTL, tmp);
+	mdelay(5);
+	OUTREG(TMDS_TRANSMITTER_CNTL, tmp2);
+	OUTREG(CRTC_MORE_CNTL, 0);
+	mdelay(20);
+
+	tmp = INREG(CRTC_MORE_CNTL);
+	OUTREG(CRTC_MORE_CNTL, tmp);
+
+	cgc = INREG(CRTC_GEN_CNTL);
+	cec = INREG(CRTC_EXT_CNTL);
+	c2gc = INREG(CRTC2_GEN_CNTL);
+
+	OUTREG(CRTC_H_SYNC_STRT_WID, 0x008e0580);
+	OUTREG(CRTC_H_TOTAL_DISP, 0x009f00d2);
+	OUTREG8(CLOCK_CNTL_INDEX, HTOTAL_CNTL + PLL_WR_EN);
+	radeon_pll_errata_after_index(rinfo);
+	OUTREG8(CLOCK_CNTL_DATA, 0);
+	radeon_pll_errata_after_data(rinfo);
+	OUTREG(CRTC_V_SYNC_STRT_WID, 0x00830403);
+	OUTREG(CRTC_V_TOTAL_DISP, 0x03ff0429);
+	OUTREG(FP_CRTC_H_TOTAL_DISP, 0x009f0033);
+	OUTREG(FP_H_SYNC_STRT_WID, 0x008e0080);
+	OUTREG(CRT_CRTC_H_SYNC_STRT_WID, 0x008e0080);
+	OUTREG(FP_CRTC_V_TOTAL_DISP, 0x03ff002a);
+	OUTREG(FP_V_SYNC_STRT_WID, 0x00830004);
+	OUTREG(CRT_CRTC_V_SYNC_STRT_WID, 0x00830004);
+	OUTREG(FP_HORZ_VERT_ACTIVE, 0x009f03ff);
+	OUTREG(FP_HORZ_STRETCH, 0);
+	OUTREG(FP_VERT_STRETCH, 0);
+	OUTREG(OVR_CLR, 0);
+	OUTREG(OVR_WID_LEFT_RIGHT, 0);
+	OUTREG(OVR_WID_TOP_BOTTOM, 0);
+
+	tmp = INPLL(PPLL_REF_DIV);
+	tmp = (tmp & ~PPLL_REF_DIV_MASK) | rinfo->pll.ref_div;
+	OUTPLL(PPLL_REF_DIV, tmp);
+	INPLL(PPLL_REF_DIV);
+
+	OUTREG8(CLOCK_CNTL_INDEX, PPLL_CNTL + PLL_WR_EN);
+	radeon_pll_errata_after_index(rinfo);
+	OUTREG8(CLOCK_CNTL_DATA + 1, 0xbc);
+	radeon_pll_errata_after_data(rinfo);
+
+	tmp = INREG(CLOCK_CNTL_INDEX);
+	radeon_pll_errata_after_index(rinfo);
+	OUTREG(CLOCK_CNTL_INDEX, tmp & 0xff);
+	radeon_pll_errata_after_index(rinfo);
+	radeon_pll_errata_after_data(rinfo);
+
+	OUTPLL(PPLL_DIV_0, 0x48090);
+
+	tmp = INPLL(PPLL_CNTL);
+	OUTPLL(PPLL_CNTL, tmp & ~0x2);
+	mdelay(1);
+	tmp = INPLL(PPLL_CNTL);
+	OUTPLL(PPLL_CNTL, tmp & ~0x1);
+	mdelay(10);
+
+	tmp = INPLL(VCLK_ECP_CNTL);
+	OUTPLL(VCLK_ECP_CNTL, tmp | 3);
+	mdelay(1);
+
+	tmp = INPLL(VCLK_ECP_CNTL);
+	OUTPLL(VCLK_ECP_CNTL, tmp);
+
+	c2gc |= CRTC2_DISP_REQ_EN_B;
+	OUTREG(CRTC2_GEN_CNTL, c2gc);
+	cgc |= CRTC_EN;
+	OUTREG(CRTC_GEN_CNTL, cgc);
+	OUTREG(CRTC_EXT_CNTL, cec);
+	OUTREG(CRTC_PITCH, 0xa0);
+	OUTREG(CRTC_OFFSET, 0);
+	OUTREG(CRTC_OFFSET_CNTL, 0);
+
+	OUTREG(GRPH_BUFFER_CNTL, 0x20117c7c);
+	OUTREG(GRPH2_BUFFER_CNTL, 0x00205c5c);
+
+	tmp2 = INREG(FP_GEN_CNTL);
+	tmp = INREG(TMDS_TRANSMITTER_CNTL);
+	OUTREG(0x2a8, 0x0000061b);
+	tmp |= TMDS_PLL_EN;
+	OUTREG(TMDS_TRANSMITTER_CNTL, tmp);
+	mdelay(1);
+	tmp &= ~TMDS_PLLRST;
+	OUTREG(TMDS_TRANSMITTER_CNTL, tmp);
+	tmp2 &= ~2;
+	tmp2 |= FP_TMDS_EN;
+	OUTREG(FP_GEN_CNTL, tmp2);
+	mdelay(5);
+	tmp2 |= FP_FPON;
+	OUTREG(FP_GEN_CNTL, tmp2);
+
+	OUTREG(CUR_HORZ_VERT_OFF, CUR_LOCK | 1);
+	cgc = INREG(CRTC_GEN_CNTL);
+	OUTREG(CUR_HORZ_VERT_POSN, 0xbfff0fff);
+	cgc |= 0x10000;
+	OUTREG(CUR_OFFSET, 0);
+}
+#endif /* 0 */
+
+#endif /* CONFIG_PPC_OF */
+
+static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend)
+{
+	u16 pwr_cmd;
+	u32 tmp;
+	int i;
+
+	if (!rinfo->pm_reg)
+		return;
+
+	/* Set the chip into appropriate suspend mode (we use D2,
+	 * D3 would require a compete re-initialization of the chip,
+	 * including PCI config registers, clocks, AGP conf, ...)
+	 */
+	if (suspend) {
+		printk(KERN_DEBUG "radeonfb (%s): switching to D2 state...\n",
+		       pci_name(rinfo->pdev));
+
+		/* Disable dynamic power management of clocks for the
+		 * duration of the suspend/resume process
+		 */
+		radeon_pm_disable_dynamic_mode(rinfo);
+
+		/* Save some registers */
+		radeon_pm_save_regs(rinfo, 0);
+
+		/* Prepare mobility chips for suspend.
+		 */
+		if (rinfo->is_mobility) {
+			/* Program V2CLK */
+			radeon_pm_program_v2clk(rinfo);
+		
+			/* Disable IO PADs */
+			radeon_pm_disable_iopad(rinfo);
+
+			/* Set low current */
+			radeon_pm_low_current(rinfo);
+
+			/* Prepare chip for power management */
+			radeon_pm_setup_for_suspend(rinfo);
+
+			if (rinfo->family <= CHIP_FAMILY_RV280) {
+				/* Reset the MDLL */
+				/* because both INPLL and OUTPLL take the same
+				 * lock, that's why. */
+				tmp = INPLL( pllMDLL_CKO) | MDLL_CKO__MCKOA_RESET
+					| MDLL_CKO__MCKOB_RESET;
+				OUTPLL( pllMDLL_CKO, tmp );
+			}
+		}
+
+		for (i = 0; i < 64; ++i)
+			pci_read_config_dword(rinfo->pdev, i * 4,
+					      &rinfo->cfg_save[i]);
+
+		/* Switch PCI power managment to D2. */
+		pci_disable_device(rinfo->pdev);
+		for (;;) {
+			pci_read_config_word(
+				rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL,
+				&pwr_cmd);
+			if (pwr_cmd & 2)
+				break;			
+			pci_write_config_word(
+				rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL,
+				(pwr_cmd & ~PCI_PM_CTRL_STATE_MASK) | 2);
+			mdelay(500);
+		}
+	} else {
+		printk(KERN_DEBUG "radeonfb (%s): switching to D0 state...\n",
+		       pci_name(rinfo->pdev));
+
+		/* Switch back PCI powermanagment to D0 */
+		mdelay(200);
+		pci_write_config_word(rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL, 0);
+		mdelay(500);
+
+		if (rinfo->family <= CHIP_FAMILY_RV250) {
+			/* Reset the SDRAM controller  */
+			radeon_pm_full_reset_sdram(rinfo);
+
+			/* Restore some registers */
+			radeon_pm_restore_regs(rinfo);
+		} else {
+			/* Restore registers first */
+			radeon_pm_restore_regs(rinfo);
+			/* init sdram controller */
+			radeon_pm_full_reset_sdram(rinfo);
+		}
+	}
+}
+
+static int radeon_restore_pci_cfg(struct radeonfb_info *rinfo)
+{
+	int i;
+	static u32 radeon_cfg_after_resume[64];
+
+	for (i = 0; i < 64; ++i)
+		pci_read_config_dword(rinfo->pdev, i * 4,
+				      &radeon_cfg_after_resume[i]);
+
+	if (radeon_cfg_after_resume[PCI_BASE_ADDRESS_0/4]
+	    == rinfo->cfg_save[PCI_BASE_ADDRESS_0/4])
+		return 0;	/* assume everything is ok */
+
+	for (i = PCI_BASE_ADDRESS_0/4; i < 64; ++i) {
+		if (radeon_cfg_after_resume[i] != rinfo->cfg_save[i])
+			pci_write_config_dword(rinfo->pdev, i * 4,
+					       rinfo->cfg_save[i]);
+	}
+	pci_write_config_word(rinfo->pdev, PCI_CACHE_LINE_SIZE,
+			      rinfo->cfg_save[PCI_CACHE_LINE_SIZE/4]);
+	pci_write_config_word(rinfo->pdev, PCI_COMMAND,
+			      rinfo->cfg_save[PCI_COMMAND/4]);
+	return 1;
+}
+
+
+static/*extern*/ int susdisking = 0;
+
+int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+        struct fb_info *info = pci_get_drvdata(pdev);
+        struct radeonfb_info *rinfo = info->par;
+	u8 agp;
+	int i;
+
+	if (state == pdev->dev.power.power_state)
+		return 0;
+
+	printk(KERN_DEBUG "radeonfb (%s): suspending to state: %d...\n",
+	       pci_name(pdev), state);
+
+	/* For suspend-to-disk, we cheat here. We don't suspend anything and
+	 * let fbcon continue drawing until we are all set. That shouldn't
+	 * really cause any problem at this point, provided that the wakeup
+	 * code knows that any state in memory may not match the HW
+	 */
+	if (state != PM_SUSPEND_MEM)
+		goto done;
+	if (susdisking) {
+		printk("radeonfb (%s): suspending to disk but state = %d\n",
+		       pci_name(pdev), state);
+		goto done;
+	}
+
+	acquire_console_sem();
+
+	fb_set_suspend(info, 1);
+
+	if (!(info->flags & FBINFO_HWACCEL_DISABLED)) {
+		/* Make sure engine is reset */
+		radeon_engine_idle();
+		radeonfb_engine_reset(rinfo);
+		radeon_engine_idle();
+	}
+
+	/* Blank display and LCD */
+	radeon_screen_blank(rinfo, FB_BLANK_POWERDOWN, 1);
+
+	/* Sleep */
+	rinfo->asleep = 1;
+	rinfo->lock_blank = 1;
+	del_timer_sync(&rinfo->lvds_timer);
+
+	/* Disable AGP. The AGP host should have done it, but since ordering
+	 * isn't always properly guaranteed in this specific case, let's make
+	 * sure it's disabled on card side now. Ultimately, when merging fbdev
+	 * and dri into some common infrastructure, this will be handled
+	 * more nicely. The host bridge side will (or will not) be dealt with
+	 * by the bridge AGP driver, we don't attempt to touch it here.
+	 */
+	agp = pci_find_capability(pdev, PCI_CAP_ID_AGP);
+	if (agp) {
+		u32 cmd;
+
+		pci_read_config_dword(pdev, agp + PCI_AGP_COMMAND, &cmd);
+		if (cmd & PCI_AGP_COMMAND_AGP) {
+			printk(KERN_INFO "radeonfb (%s): AGP was enabled, "
+			       "disabling ...\n",
+			       pci_name(pdev));
+			cmd &= ~PCI_AGP_COMMAND_AGP;
+			pci_write_config_dword(pdev, agp + PCI_AGP_COMMAND,
+					       cmd);
+		}
+	}
+
+	/* If we support wakeup from poweroff, we save all regs we can including cfg
+	 * space
+	 */
+	if (rinfo->pm_mode & radeon_pm_off) {
+		/* Always disable dynamic clocks or weird things are happening when
+		 * the chip goes off (basically the panel doesn't shut down properly
+		 * and we crash on wakeup),
+		 * also, we want the saved regs context to have no dynamic clocks in
+		 * it, we'll restore the dynamic clocks state on wakeup
+		 */
+		radeon_pm_disable_dynamic_mode(rinfo);
+		mdelay(50);
+		radeon_pm_save_regs(rinfo, 1);
+
+		if (rinfo->is_mobility && !(rinfo->pm_mode & radeon_pm_d2)) {
+			/* Switch off LVDS interface */
+			mdelay(1);
+			OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) & ~(LVDS_BL_MOD_EN));
+			mdelay(1);
+			OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) & ~(LVDS_EN | LVDS_ON));
+			OUTREG(LVDS_PLL_CNTL, (INREG(LVDS_PLL_CNTL) & ~30000) | 0x20000);
+			mdelay(20);
+			OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) & ~(LVDS_DIGON));
+		}
+		// FIXME: Use PCI layer
+		for (i = 0; i < 64; ++i)
+			pci_read_config_dword(pdev, i * 4, &rinfo->cfg_save[i]);
+		pci_disable_device(pdev);
+	}
+	/* If we support D2, we go to it (should be fixed later with a flag forcing
+	 * D3 only for some laptops)
+	 */
+	if (rinfo->pm_mode & radeon_pm_d2)
+		radeon_set_suspend(rinfo, 1);
+
+	release_console_sem();
+
+ done:
+	pdev->dev.power.power_state = state;
+
+	return 0;
+}
+
+int radeonfb_pci_resume(struct pci_dev *pdev)
+{
+        struct fb_info *info = pci_get_drvdata(pdev);
+        struct radeonfb_info *rinfo = info->par;
+	int rc = 0;
+
+	if (pdev->dev.power.power_state == 0)
+		return 0;
+
+	if (rinfo->no_schedule) {
+		if (try_acquire_console_sem())
+			return 0;
+	} else
+		acquire_console_sem();
+
+	printk(KERN_DEBUG "radeonfb (%s): resuming from state: %d...\n",
+	       pci_name(pdev), pdev->dev.power.power_state);
+
+
+	if (pci_enable_device(pdev)) {
+		rc = -ENODEV;
+		printk(KERN_ERR "radeonfb (%s): can't enable PCI device !\n",
+		       pci_name(pdev));
+		goto bail;
+	}
+	pci_set_master(pdev);
+
+	if (pdev->dev.power.power_state == PM_SUSPEND_MEM) {
+		/* Wakeup chip. Check from config space if we were powered off
+		 * (todo: additionally, check CLK_PIN_CNTL too)
+		 */
+		if ((rinfo->pm_mode & radeon_pm_off) && radeon_restore_pci_cfg(rinfo)) {
+			if (rinfo->reinit_func != NULL)
+				rinfo->reinit_func(rinfo);
+			else {
+				printk(KERN_ERR "radeonfb (%s): can't resume radeon from"
+				       " D3 cold, need softboot !", pci_name(pdev));
+				rc = -EIO;
+				goto bail;
+			}
+		}
+		/* If we support D2, try to resume... we should check what was our
+		 * state though... (were we really in D2 state ?). Right now, this code
+		 * is only enable on Macs so it's fine.
+		 */
+		else if (rinfo->pm_mode & radeon_pm_d2)
+			radeon_set_suspend(rinfo, 0);
+
+		rinfo->asleep = 0;
+	} else
+		radeon_engine_idle();
+
+	/* Restore display & engine */
+	radeon_write_mode (rinfo, &rinfo->state, 1);
+	if (!(info->flags & FBINFO_HWACCEL_DISABLED))
+		radeonfb_engine_init (rinfo);
+
+	fb_pan_display(info, &info->var);
+	fb_set_cmap(&info->cmap, info);
+
+	/* Refresh */
+	fb_set_suspend(info, 0);
+
+	/* Unblank */
+	rinfo->lock_blank = 0;
+	radeon_screen_blank(rinfo, FB_BLANK_UNBLANK, 1);
+
+	/* Check status of dynclk */
+	if (rinfo->dynclk == 1)
+		radeon_pm_enable_dynamic_mode(rinfo);
+	else if (rinfo->dynclk == 0)
+		radeon_pm_disable_dynamic_mode(rinfo);
+
+	pdev->dev.power.power_state = PMSG_ON;
+
+ bail:
+	release_console_sem();
+
+	return rc;
+}
+
+#ifdef CONFIG_PPC_OF
+static void radeonfb_early_resume(void *data)
+{
+        struct radeonfb_info *rinfo = data;
+
+	rinfo->no_schedule = 1;
+	radeonfb_pci_resume(rinfo->pdev);
+	rinfo->no_schedule = 0;
+}
+#endif /* CONFIG_PPC_OF */
+
+#endif /* CONFIG_PM */
+
+void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk)
+{
+	/* Find PM registers in config space if any*/
+	rinfo->pm_reg = pci_find_capability(rinfo->pdev, PCI_CAP_ID_PM);
+
+	/* Enable/Disable dynamic clocks: TODO add sysfs access */
+	rinfo->dynclk = dynclk;
+	if (dynclk == 1) {
+		radeon_pm_enable_dynamic_mode(rinfo);
+		printk("radeonfb: Dynamic Clock Power Management enabled\n");
+	} else if (dynclk == 0) {
+		radeon_pm_disable_dynamic_mode(rinfo);
+		printk("radeonfb: Dynamic Clock Power Management disabled\n");
+	}
+
+	/* Check if we can power manage on suspend/resume. We can do
+	 * D2 on M6, M7 and M9, and we can resume from D3 cold a few other
+	 * "Mac" cards, but that's all. We need more infos about what the
+	 * BIOS does tho. Right now, all this PM stuff is pmac-only for that
+	 * reason. --BenH
+	 */
+#if defined(CONFIG_PM) && defined(CONFIG_PPC_OF)
+	if (_machine == _MACH_Pmac && rinfo->of_node) {
+		if (rinfo->is_mobility && rinfo->pm_reg &&
+		    rinfo->family <= CHIP_FAMILY_RV250)
+			rinfo->pm_mode |= radeon_pm_d2;
+
+		/* We can restart Jasper (M10 chip in albooks), BlueStone (7500 chip
+		 * in some desktop G4s), and Via (M9+ chip on iBook G4)
+		 */
+		if (!strcmp(rinfo->of_node->name, "ATY,JasperParent")) {
+			rinfo->reinit_func = radeon_reinitialize_M10;
+			rinfo->pm_mode |= radeon_pm_off;
+		}
+#if 0 /* Not ready yet */
+		if (!strcmp(rinfo->of_node->name, "ATY,BlueStoneParent")) {
+			rinfo->reinit_func = radeon_reinitialize_QW;
+			rinfo->pm_mode |= radeon_pm_off;
+		}
+#endif
+		if (!strcmp(rinfo->of_node->name, "ATY,ViaParent")) {
+			rinfo->reinit_func = radeon_reinitialize_M9P;
+			rinfo->pm_mode |= radeon_pm_off;
+		}
+
+		/* If any of the above is set, we assume the machine can sleep/resume.
+		 * It's a bit of a "shortcut" but will work fine. Ideally, we need infos
+		 * from the platform about what happens to the chip...
+		 * Now we tell the platform about our capability
+		 */
+		if (rinfo->pm_mode != radeon_pm_none) {
+			pmac_call_feature(PMAC_FTR_DEVICE_CAN_WAKE, rinfo->of_node, 0, 1);
+			pmac_set_early_video_resume(radeonfb_early_resume, rinfo);
+		}
+
+#if 0
+		/* Power down TV DAC, taht saves a significant amount of power,
+		 * we'll have something better once we actually have some TVOut
+		 * support
+		 */
+		OUTREG(TV_DAC_CNTL, INREG(TV_DAC_CNTL) | 0x07000000);
+#endif
+	}
+#endif /* defined(CONFIG_PM) && defined(CONFIG_PPC_OF) */
+}
+
+void radeonfb_pm_exit(struct radeonfb_info *rinfo)
+{
+#if defined(CONFIG_PM) && defined(CONFIG_PPC_OF)
+	if (rinfo->pm_mode != radeon_pm_none)
+		pmac_set_early_video_resume(NULL, NULL);
+#endif
+}
diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h
new file mode 100644
index 0000000..659bc9f
--- /dev/null
+++ b/drivers/video/aty/radeonfb.h
@@ -0,0 +1,625 @@
+#ifndef __RADEONFB_H__
+#define __RADEONFB_H__
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/fb.h>
+
+
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/i2c-algo-bit.h>
+
+#include <asm/io.h>
+
+#ifdef CONFIG_PPC_OF
+#include <asm/prom.h>
+#endif
+
+#include <video/radeon.h>
+
+/***************************************************************
+ * Most of the definitions here are adapted right from XFree86 *
+ ***************************************************************/
+
+
+/*
+ * Chip families. Must fit in the low 16 bits of a long word
+ */
+enum radeon_family {
+	CHIP_FAMILY_UNKNOW,
+	CHIP_FAMILY_LEGACY,
+	CHIP_FAMILY_RADEON,
+	CHIP_FAMILY_RV100,
+	CHIP_FAMILY_RS100,    /* U1 (IGP320M) or A3 (IGP320)*/
+	CHIP_FAMILY_RV200,
+	CHIP_FAMILY_RS200,    /* U2 (IGP330M/340M/350M) or A4 (IGP330/340/345/350),
+				 RS250 (IGP 7000) */
+	CHIP_FAMILY_R200,
+	CHIP_FAMILY_RV250,
+	CHIP_FAMILY_RS300,    /* Radeon 9000 IGP */
+	CHIP_FAMILY_RV280,
+	CHIP_FAMILY_R300,
+	CHIP_FAMILY_R350,
+	CHIP_FAMILY_RV350,
+	CHIP_FAMILY_RV380,    /* RV370/RV380/M22/M24 */
+	CHIP_FAMILY_R420,     /* R420/R423/M18 */
+	CHIP_FAMILY_LAST,
+};
+
+#define IS_RV100_VARIANT(rinfo) (((rinfo)->family == CHIP_FAMILY_RV100)  || \
+				 ((rinfo)->family == CHIP_FAMILY_RV200)  || \
+				 ((rinfo)->family == CHIP_FAMILY_RS100)  || \
+				 ((rinfo)->family == CHIP_FAMILY_RS200)  || \
+				 ((rinfo)->family == CHIP_FAMILY_RV250)  || \
+				 ((rinfo)->family == CHIP_FAMILY_RV280)  || \
+				 ((rinfo)->family == CHIP_FAMILY_RS300))
+
+
+#define IS_R300_VARIANT(rinfo) (((rinfo)->family == CHIP_FAMILY_R300)  || \
+				((rinfo)->family == CHIP_FAMILY_RV350) || \
+				((rinfo)->family == CHIP_FAMILY_R350)  || \
+				((rinfo)->family == CHIP_FAMILY_RV380) || \
+				((rinfo)->family == CHIP_FAMILY_R420))
+
+/*
+ * Chip flags
+ */
+enum radeon_chip_flags {
+	CHIP_FAMILY_MASK	= 0x0000ffffUL,
+	CHIP_FLAGS_MASK		= 0xffff0000UL,
+	CHIP_IS_MOBILITY	= 0x00010000UL,
+	CHIP_IS_IGP		= 0x00020000UL,
+	CHIP_HAS_CRTC2		= 0x00040000UL,	
+};
+
+/*
+ * Errata workarounds
+ */
+enum radeon_errata {
+	CHIP_ERRATA_R300_CG		= 0x00000001,
+	CHIP_ERRATA_PLL_DUMMYREADS	= 0x00000002,
+	CHIP_ERRATA_PLL_DELAY		= 0x00000004,
+};
+
+
+/*
+ * Monitor types
+ */
+enum radeon_montype {
+	MT_NONE = 0,
+	MT_CRT,		/* CRT */
+	MT_LCD,		/* LCD */
+	MT_DFP,		/* DVI */
+	MT_CTV,		/* composite TV */
+	MT_STV		/* S-Video out */
+};
+
+/*
+ * DDC i2c ports
+ */
+enum ddc_type {
+	ddc_none,
+	ddc_monid,
+	ddc_dvi,
+	ddc_vga,
+	ddc_crt2,
+};
+
+/*
+ * Connector types
+ */
+enum conn_type {
+	conn_none,
+	conn_proprietary,
+	conn_crt,
+	conn_DVI_I,
+	conn_DVI_D,
+};
+
+
+/*
+ * PLL infos
+ */
+struct pll_info {
+	int ppll_max;
+	int ppll_min;
+	int sclk, mclk;
+	int ref_div;
+	int ref_clk;
+};
+
+
+/*
+ * This structure contains the various registers manipulated by this
+ * driver for setting or restoring a mode. It's mostly copied from
+ * XFree's RADEONSaveRec structure. A few chip settings might still be
+ * tweaked without beeing reflected or saved in these registers though
+ */
+struct radeon_regs {
+	/* Common registers */
+	u32		ovr_clr;
+	u32		ovr_wid_left_right;
+	u32		ovr_wid_top_bottom;
+	u32		ov0_scale_cntl;
+	u32		mpp_tb_config;
+	u32		mpp_gp_config;
+	u32		subpic_cntl;
+	u32		viph_control;
+	u32		i2c_cntl_1;
+	u32		gen_int_cntl;
+	u32		cap0_trig_cntl;
+	u32		cap1_trig_cntl;
+	u32		bus_cntl;
+	u32		surface_cntl;
+	u32		bios_5_scratch;
+
+	/* Other registers to save for VT switches or driver load/unload */
+	u32		dp_datatype;
+	u32		rbbm_soft_reset;
+	u32		clock_cntl_index;
+	u32		amcgpio_en_reg;
+	u32		amcgpio_mask;
+
+	/* Surface/tiling registers */
+	u32		surf_lower_bound[8];
+	u32		surf_upper_bound[8];
+	u32		surf_info[8];
+
+	/* CRTC registers */
+	u32		crtc_gen_cntl;
+	u32		crtc_ext_cntl;
+	u32		dac_cntl;
+	u32		crtc_h_total_disp;
+	u32		crtc_h_sync_strt_wid;
+	u32		crtc_v_total_disp;
+	u32		crtc_v_sync_strt_wid;
+	u32		crtc_offset;
+	u32		crtc_offset_cntl;
+	u32		crtc_pitch;
+	u32		disp_merge_cntl;
+	u32		grph_buffer_cntl;
+	u32		crtc_more_cntl;
+
+	/* CRTC2 registers */
+	u32		crtc2_gen_cntl;
+	u32		dac2_cntl;
+	u32		disp_output_cntl;
+	u32		disp_hw_debug;
+	u32		disp2_merge_cntl;
+	u32		grph2_buffer_cntl;
+	u32		crtc2_h_total_disp;
+	u32		crtc2_h_sync_strt_wid;
+	u32		crtc2_v_total_disp;
+	u32		crtc2_v_sync_strt_wid;
+	u32		crtc2_offset;
+	u32		crtc2_offset_cntl;
+	u32		crtc2_pitch;
+
+	/* Flat panel regs */
+	u32 		fp_crtc_h_total_disp;
+	u32		fp_crtc_v_total_disp;
+	u32		fp_gen_cntl;
+	u32		fp2_gen_cntl;
+	u32		fp_h_sync_strt_wid;
+	u32		fp2_h_sync_strt_wid;
+	u32		fp_horz_stretch;
+	u32		fp_panel_cntl;
+	u32		fp_v_sync_strt_wid;
+	u32		fp2_v_sync_strt_wid;
+	u32		fp_vert_stretch;
+	u32		lvds_gen_cntl;
+	u32		lvds_pll_cntl;
+	u32		tmds_crc;
+	u32		tmds_transmitter_cntl;
+
+	/* Computed values for PLL */
+	u32		dot_clock_freq;
+	int		feedback_div;
+	int		post_div;	
+
+	/* PLL registers */
+	u32		ppll_div_3;
+	u32		ppll_ref_div;
+	u32		vclk_ecp_cntl;
+	u32		clk_cntl_index;
+
+	/* Computed values for PLL2 */
+	u32		dot_clock_freq_2;
+	int		feedback_div_2;
+	int		post_div_2;
+
+	/* PLL2 registers */
+	u32		p2pll_ref_div;
+	u32		p2pll_div_0;
+	u32		htotal_cntl2;
+
+       	/* Palette */
+	int		palette_valid;
+};
+
+struct panel_info {
+	int xres, yres;
+	int valid;
+	int clock;
+	int hOver_plus, hSync_width, hblank;
+	int vOver_plus, vSync_width, vblank;
+	int hAct_high, vAct_high, interlaced;
+	int pwr_delay;
+	int use_bios_dividers;
+	int ref_divider;
+	int post_divider;
+	int fbk_divider;
+};
+
+struct radeonfb_info;
+
+#ifdef CONFIG_FB_RADEON_I2C
+struct radeon_i2c_chan {
+	struct radeonfb_info		*rinfo;
+	u32		 		ddc_reg;
+	struct i2c_adapter		adapter;
+	struct i2c_algo_bit_data	algo;
+};
+#endif
+
+enum radeon_pm_mode {
+	radeon_pm_none	= 0,		/* Nothing supported */
+	radeon_pm_d2	= 0x00000001,	/* Can do D2 state */
+	radeon_pm_off	= 0x00000002,	/* Can resume from D3 cold */
+};
+
+struct radeonfb_info {
+	struct fb_info		*info;
+
+	struct radeon_regs 	state;
+	struct radeon_regs	init_state;
+
+	char			name[DEVICE_NAME_SIZE];
+
+	unsigned long		mmio_base_phys;
+	unsigned long		fb_base_phys;
+
+	void __iomem		*mmio_base;
+	void __iomem		*fb_base;
+
+	unsigned long		fb_local_base;
+
+	struct pci_dev		*pdev;
+#ifdef CONFIG_PPC_OF
+	struct device_node	*of_node;
+#endif
+
+	void __iomem		*bios_seg;
+	int			fp_bios_start;
+
+	u32			pseudo_palette[17];
+	struct { u8 red, green, blue, pad; }
+				palette[256];
+
+	int			chipset;
+	u8			family;
+	u8			rev;
+	unsigned int		errata;
+	unsigned long		video_ram;
+	unsigned long		mapped_vram;
+	int			vram_width;
+	int			vram_ddr;
+
+	int			pitch, bpp, depth;
+
+	int			has_CRTC2;
+	int			is_mobility;
+	int			is_IGP;
+	int			reversed_DAC;
+	int			reversed_TMDS;
+	struct panel_info	panel_info;
+	int			mon1_type;
+	u8			*mon1_EDID;
+	struct fb_videomode	*mon1_modedb;
+	int			mon1_dbsize;
+	int			mon2_type;
+	u8		        *mon2_EDID;
+
+	u32			dp_gui_master_cntl;
+
+	struct pll_info		pll;
+
+	int			mtrr_hdl;
+
+	int			pm_reg;
+	u32			save_regs[100];
+	int			asleep;
+	int			lock_blank;
+	int			dynclk;
+	int			no_schedule;
+	enum radeon_pm_mode	pm_mode;
+	void			(*reinit_func)(struct radeonfb_info *rinfo);
+
+	/* Lock on register access */
+	spinlock_t		reg_lock;
+
+	/* Timer used for delayed LVDS operations */
+	struct timer_list	lvds_timer;
+	u32			pending_lvds_gen_cntl;
+
+#ifdef CONFIG_FB_RADEON_I2C
+	struct radeon_i2c_chan 	i2c[4];
+#endif
+
+	u32			cfg_save[64];
+};
+
+
+#define PRIMARY_MONITOR(rinfo)	(rinfo->mon1_type)
+
+
+/*
+ * Debugging stuffs
+ */
+#ifdef CONFIG_FB_RADEON_DEBUG
+#define DEBUG		1
+#else
+#define DEBUG		0
+#endif
+
+#if DEBUG
+#define RTRACE		printk
+#else
+#define RTRACE		if(0) printk
+#endif
+
+
+/*
+ * IO macros
+ */
+
+/* Note about this function: we have some rare cases where we must not schedule,
+ * this typically happen with our special "wake up early" hook which allows us to
+ * wake up the graphic chip (and thus get the console back) before everything else
+ * on some machines that support that mecanism. At this point, interrupts are off
+ * and scheduling is not permitted
+ */
+static inline void _radeon_msleep(struct radeonfb_info *rinfo, unsigned long ms)
+{
+	if (rinfo->no_schedule || oops_in_progress)
+		mdelay(ms);
+	else
+		msleep(ms);
+}
+
+
+#define INREG8(addr)		readb((rinfo->mmio_base)+addr)
+#define OUTREG8(addr,val)	writeb(val, (rinfo->mmio_base)+addr)
+#define INREG(addr)		readl((rinfo->mmio_base)+addr)
+#define OUTREG(addr,val)	writel(val, (rinfo->mmio_base)+addr)
+
+static inline void _OUTREGP(struct radeonfb_info *rinfo, u32 addr,
+		       u32 val, u32 mask)
+{
+	unsigned long flags;
+	unsigned int tmp;
+
+	spin_lock_irqsave(&rinfo->reg_lock, flags);
+	tmp = INREG(addr);
+	tmp &= (mask);
+	tmp |= (val);
+	OUTREG(addr, tmp);
+	spin_unlock_irqrestore(&rinfo->reg_lock, flags);
+}
+
+#define OUTREGP(addr,val,mask)	_OUTREGP(rinfo, addr, val,mask)
+
+/*
+ * Note about PLL register accesses:
+ *
+ * I have removed the spinlock on them on purpose. The driver now
+ * expects that it will only manipulate the PLL registers in normal
+ * task environment, where radeon_msleep() will be called, protected
+ * by a semaphore (currently the console semaphore) so that no conflict
+ * will happen on the PLL register index.
+ *
+ * With the latest changes to the VT layer, this is guaranteed for all
+ * calls except the actual drawing/blits which aren't supposed to use
+ * the PLL registers anyway
+ *
+ * This is very important for the workarounds to work properly. The only
+ * possible exception to this rule is the call to unblank(), which may
+ * be done at irq time if an oops is in progress.
+ */
+static inline void radeon_pll_errata_after_index(struct radeonfb_info *rinfo)
+{
+	if (!(rinfo->errata & CHIP_ERRATA_PLL_DUMMYREADS))
+		return;
+
+	(void)INREG(CLOCK_CNTL_DATA);
+	(void)INREG(CRTC_GEN_CNTL);
+}
+
+static inline void radeon_pll_errata_after_data(struct radeonfb_info *rinfo)
+{
+	if (rinfo->errata & CHIP_ERRATA_PLL_DELAY) {
+		/* we can't deal with posted writes here ... */
+		_radeon_msleep(rinfo, 5);
+	}
+	if (rinfo->errata & CHIP_ERRATA_R300_CG) {
+		u32 save, tmp;
+		save = INREG(CLOCK_CNTL_INDEX);
+		tmp = save & ~(0x3f | PLL_WR_EN);
+		OUTREG(CLOCK_CNTL_INDEX, tmp);
+		tmp = INREG(CLOCK_CNTL_DATA);
+		OUTREG(CLOCK_CNTL_INDEX, save);
+	}
+}
+
+static inline u32 __INPLL(struct radeonfb_info *rinfo, u32 addr)
+{
+	u32 data;
+
+	OUTREG8(CLOCK_CNTL_INDEX, addr & 0x0000003f);
+	radeon_pll_errata_after_index(rinfo);
+	data = INREG(CLOCK_CNTL_DATA);
+	radeon_pll_errata_after_data(rinfo);
+	return data;
+}
+
+static inline void __OUTPLL(struct radeonfb_info *rinfo, unsigned int index,
+			    u32 val)
+{
+
+	OUTREG8(CLOCK_CNTL_INDEX, (index & 0x0000003f) | 0x00000080);
+	radeon_pll_errata_after_index(rinfo);
+	OUTREG(CLOCK_CNTL_DATA, val);
+	radeon_pll_errata_after_data(rinfo);
+}
+
+
+static inline void __OUTPLLP(struct radeonfb_info *rinfo, unsigned int index,
+			     u32 val, u32 mask)
+{
+	unsigned int tmp;
+
+	tmp  = __INPLL(rinfo, index);
+	tmp &= (mask);
+	tmp |= (val);
+	__OUTPLL(rinfo, index, tmp);
+}
+
+
+#define INPLL(addr)			__INPLL(rinfo, addr)
+#define OUTPLL(index, val)		__OUTPLL(rinfo, index, val)
+#define OUTPLLP(index, val, mask)	__OUTPLLP(rinfo, index, val, mask)
+
+
+#define BIOS_IN8(v)  	(readb(rinfo->bios_seg + (v)))
+#define BIOS_IN16(v) 	(readb(rinfo->bios_seg + (v)) | \
+			  (readb(rinfo->bios_seg + (v) + 1) << 8))
+#define BIOS_IN32(v) 	(readb(rinfo->bios_seg + (v)) | \
+			  (readb(rinfo->bios_seg + (v) + 1) << 8) | \
+			  (readb(rinfo->bios_seg + (v) + 2) << 16) | \
+			  (readb(rinfo->bios_seg + (v) + 3) << 24))
+
+/*
+ * Inline utilities
+ */
+static inline int round_div(int num, int den)
+{
+        return (num + (den / 2)) / den;
+}
+
+static inline int var_to_depth(const struct fb_var_screeninfo *var)
+{
+	if (var->bits_per_pixel != 16)
+		return var->bits_per_pixel;
+	return (var->green.length == 5) ? 15 : 16;
+}
+
+static inline u32 radeon_get_dstbpp(u16 depth)
+{
+	switch (depth) {
+       	case 8:
+       		return DST_8BPP;
+       	case 15:
+       		return DST_15BPP;
+       	case 16:
+       		return DST_16BPP;
+       	case 32:
+       		return DST_32BPP;
+       	default:
+       		return 0;
+	}
+}
+
+/*
+ * 2D Engine helper routines
+ */
+static inline void radeon_engine_flush (struct radeonfb_info *rinfo)
+{
+	int i;
+
+	/* initiate flush */
+	OUTREGP(RB2D_DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL,
+	        ~RB2D_DC_FLUSH_ALL);
+
+	for (i=0; i < 2000000; i++) {
+		if (!(INREG(RB2D_DSTCACHE_CTLSTAT) & RB2D_DC_BUSY))
+			return;
+		udelay(1);
+	}
+	printk(KERN_ERR "radeonfb: Flush Timeout !\n");
+}
+
+
+static inline void _radeon_fifo_wait(struct radeonfb_info *rinfo, int entries)
+{
+	int i;
+
+	for (i=0; i<2000000; i++) {
+		if ((INREG(RBBM_STATUS) & 0x7f) >= entries)
+			return;
+		udelay(1);
+	}
+	printk(KERN_ERR "radeonfb: FIFO Timeout !\n");
+}
+
+
+static inline void _radeon_engine_idle(struct radeonfb_info *rinfo)
+{
+	int i;
+
+	/* ensure FIFO is empty before waiting for idle */
+	_radeon_fifo_wait (rinfo, 64);
+
+	for (i=0; i<2000000; i++) {
+		if (((INREG(RBBM_STATUS) & GUI_ACTIVE)) == 0) {
+			radeon_engine_flush (rinfo);
+			return;
+		}
+		udelay(1);
+	}
+	printk(KERN_ERR "radeonfb: Idle Timeout !\n");
+}
+
+
+#define radeon_engine_idle()		_radeon_engine_idle(rinfo)
+#define radeon_fifo_wait(entries)	_radeon_fifo_wait(rinfo,entries)
+#define radeon_msleep(ms)		_radeon_msleep(rinfo,ms)
+
+
+/* I2C Functions */
+extern void radeon_create_i2c_busses(struct radeonfb_info *rinfo);
+extern void radeon_delete_i2c_busses(struct radeonfb_info *rinfo);
+extern int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn, u8 **out_edid);
+
+/* PM Functions */
+extern int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t state);
+extern int radeonfb_pci_resume(struct pci_dev *pdev);
+extern void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk);
+extern void radeonfb_pm_exit(struct radeonfb_info *rinfo);
+
+/* Monitor probe functions */
+extern void radeon_probe_screens(struct radeonfb_info *rinfo,
+				 const char *monitor_layout, int ignore_edid);
+extern void radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_option);
+extern int radeon_match_mode(struct radeonfb_info *rinfo,
+			     struct fb_var_screeninfo *dest,
+			     const struct fb_var_screeninfo *src);
+
+/* Accel functions */
+extern void radeonfb_fillrect(struct fb_info *info, const struct fb_fillrect *region);
+extern void radeonfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
+extern void radeonfb_imageblit(struct fb_info *p, const struct fb_image *image);
+extern int radeonfb_sync(struct fb_info *info);
+extern void radeonfb_engine_init (struct radeonfb_info *rinfo);
+extern void radeonfb_engine_reset(struct radeonfb_info *rinfo);
+
+/* Other functions */
+extern int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch);
+extern void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode,
+			       int reg_only);
+
+#endif /* __RADEONFB_H__ */
diff --git a/drivers/video/aty/xlinit.c b/drivers/video/aty/xlinit.c
new file mode 100644
index 0000000..92643af
--- /dev/null
+++ b/drivers/video/aty/xlinit.c
@@ -0,0 +1,354 @@
+/*
+ *  ATI Rage XL Initialization. Support for Xpert98 and Victoria
+ *  PCI cards.
+ *
+ *  Copyright (C) 2002 MontaVista Software Inc.
+ *  Author: MontaVista Software, Inc.
+ *         	stevel@mvista.com or source@mvista.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#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/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <video/mach64.h>
+#include "atyfb.h"
+
+#define MPLL_GAIN       0xad
+#define VPLL_GAIN       0xd5
+
+enum {
+	VICTORIA = 0,
+	XPERT98,
+	NUM_XL_CARDS
+};
+
+extern const struct aty_pll_ops aty_pll_ct;
+
+#define DEFAULT_CARD XPERT98
+static int xl_card = DEFAULT_CARD;
+
+static const struct xl_card_cfg_t {
+	int ref_crystal; // 10^4 Hz
+	int mem_type;
+	int mem_size;
+	u32 mem_cntl;
+	u32 ext_mem_cntl;
+	u32 mem_addr_config;
+	u32 bus_cntl;
+	u32 dac_cntl;
+	u32 hw_debug;
+	u32 custom_macro_cntl;
+	u8  dll2_cntl;
+	u8  pll_yclk_cntl;
+} card_cfg[NUM_XL_CARDS] = {
+	// VICTORIA
+	{	2700, SDRAM, 0x800000,
+		0x10757A3B, 0x64000C81, 0x00110202, 0x7b33A040,
+		0x82010102, 0x48803800, 0x005E0179,
+		0x50, 0x25
+	},
+	// XPERT98
+	{	1432,  WRAM, 0x800000,
+		0x00165A2B, 0xE0000CF1, 0x00200213, 0x7333A001,
+		0x8000000A, 0x48833800, 0x007F0779,
+		0x10, 0x19
+	}
+};
+	  
+typedef struct {
+	u8 lcd_reg;
+	u32 val;
+} lcd_tbl_t;
+
+static const lcd_tbl_t lcd_tbl[] = {
+	{ 0x01,	0x000520C0 },
+	{ 0x08,	0x02000408 },
+	{ 0x03,	0x00000F00 },
+	{ 0x00,	0x00000000 },
+	{ 0x02,	0x00000000 },
+	{ 0x04,	0x00000000 },
+	{ 0x05,	0x00000000 },
+	{ 0x06,	0x00000000 },
+	{ 0x33,	0x00000000 },
+	{ 0x34,	0x00000000 },
+	{ 0x35,	0x00000000 },
+	{ 0x36,	0x00000000 },
+	{ 0x37,	0x00000000 }
+};
+
+static void reset_gui(struct atyfb_par *par)
+{
+	aty_st_8(GEN_TEST_CNTL+1, 0x01, par);
+	aty_st_8(GEN_TEST_CNTL+1, 0x00, par);
+	aty_st_8(GEN_TEST_CNTL+1, 0x02, par);
+	mdelay(5);
+}
+
+static void reset_sdram(struct atyfb_par *par)
+{
+	u8 temp;
+
+	temp = aty_ld_8(EXT_MEM_CNTL, par);
+	temp |= 0x02;
+	aty_st_8(EXT_MEM_CNTL, temp, par); // MEM_SDRAM_RESET = 1b
+	temp |= 0x08;
+	aty_st_8(EXT_MEM_CNTL, temp, par); // MEM_CYC_TEST    = 10b
+	temp |= 0x0c;
+	aty_st_8(EXT_MEM_CNTL, temp, par); // MEM_CYC_TEST    = 11b
+	mdelay(5);
+	temp &= 0xf3;
+	aty_st_8(EXT_MEM_CNTL, temp, par); // MEM_CYC_TEST    = 00b
+	temp &= 0xfd;
+	aty_st_8(EXT_MEM_CNTL, temp, par); // MEM_SDRAM_REST  = 0b
+	mdelay(5);
+}
+
+static void init_dll(struct atyfb_par *par)
+{
+	// enable DLL
+	aty_st_pll_ct(PLL_GEN_CNTL,
+		   aty_ld_pll_ct(PLL_GEN_CNTL, par) & 0x7f,
+		   par);
+
+	// reset DLL
+	aty_st_pll_ct(DLL_CNTL, 0x82, par);
+	aty_st_pll_ct(DLL_CNTL, 0xE2, par);
+	mdelay(5);
+	aty_st_pll_ct(DLL_CNTL, 0x82, par);
+	mdelay(6);
+}
+
+static void reset_clocks(struct atyfb_par *par, struct pll_ct *pll,
+			 int hsync_enb)
+{
+	reset_gui(par);
+	aty_st_pll_ct(MCLK_FB_DIV, pll->mclk_fb_div, par);
+	aty_st_pll_ct(SCLK_FB_DIV, pll->sclk_fb_div, par);
+
+	mdelay(15);
+	init_dll(par);
+	aty_st_8(GEN_TEST_CNTL+1, 0x00, par);
+	mdelay(5);
+	aty_st_8(CRTC_GEN_CNTL+3, 0x04, par);
+	mdelay(6);
+	reset_sdram(par);
+	aty_st_8(CRTC_GEN_CNTL+3,
+		 hsync_enb ? 0x00 : 0x04, par);
+
+	aty_st_pll_ct(SPLL_CNTL2, pll->spll_cntl2, par);
+	aty_st_pll_ct(PLL_GEN_CNTL, pll->pll_gen_cntl, par);
+	aty_st_pll_ct(PLL_VCLK_CNTL, pll->pll_vclk_cntl, par);
+}
+
+int atyfb_xl_init(struct fb_info *info)
+{
+	const struct xl_card_cfg_t * card = &card_cfg[xl_card];
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	union aty_pll pll;
+	int i, err;
+	u32 temp;
+	
+	aty_st_8(CONFIG_STAT0, 0x85, par);
+	mdelay(10);
+
+	/*
+	 * The following needs to be set before the call
+	 * to var_to_pll() below. They'll be re-set again
+	 * to the same values in aty_init().
+	 */
+	par->ref_clk_per = 100000000UL/card->ref_crystal;
+	par->ram_type = card->mem_type;
+	info->fix.smem_len = card->mem_size;
+	if (xl_card == VICTORIA) {
+		// the MCLK, XCLK are 120MHz on victoria card
+		par->mclk_per = 1000000/120;
+		par->xclk_per = 1000000/120;
+		par->features &= ~M64F_MFB_FORCE_4;
+	}
+	
+	/*
+	 * Calculate mclk and xclk dividers, etc. The passed
+	 * pixclock and bpp values don't matter yet, the vclk
+	 * isn't programmed until later.
+	 */
+	if ((err = aty_pll_ct.var_to_pll(info, 39726, 8, &pll)))
+		return err;
+
+	aty_st_pll_ct(LVDS_CNTL0, 0x00, par);
+	aty_st_pll_ct(DLL2_CNTL, card->dll2_cntl, par);
+	aty_st_pll_ct(V2PLL_CNTL, 0x10, par);
+	aty_st_pll_ct(MPLL_CNTL, MPLL_GAIN, par);
+	aty_st_pll_ct(VPLL_CNTL, VPLL_GAIN, par);
+	aty_st_pll_ct(PLL_VCLK_CNTL, 0x00, par);
+	aty_st_pll_ct(VFC_CNTL, 0x1B, par);
+	aty_st_pll_ct(PLL_REF_DIV, pll.ct.pll_ref_div, par);
+	aty_st_pll_ct(PLL_EXT_CNTL, pll.ct.pll_ext_cntl, par);
+	aty_st_pll_ct(SPLL_CNTL2, 0x03, par);
+	aty_st_pll_ct(PLL_GEN_CNTL, 0x44, par);
+
+	reset_clocks(par, &pll.ct, 0);
+	mdelay(10);
+
+	aty_st_pll_ct(VCLK_POST_DIV, 0x03, par);
+	aty_st_pll_ct(VCLK0_FB_DIV, 0xDA, par);
+	aty_st_pll_ct(VCLK_POST_DIV, 0x0F, par);
+	aty_st_pll_ct(VCLK1_FB_DIV, 0xF5, par);
+	aty_st_pll_ct(VCLK_POST_DIV, 0x3F, par);
+	aty_st_pll_ct(PLL_EXT_CNTL, 0x40 | pll.ct.pll_ext_cntl, par);
+	aty_st_pll_ct(VCLK2_FB_DIV, 0x00, par);
+	aty_st_pll_ct(VCLK_POST_DIV, 0xFF, par);
+	aty_st_pll_ct(PLL_EXT_CNTL, 0xC0 | pll.ct.pll_ext_cntl, par);
+	aty_st_pll_ct(VCLK3_FB_DIV, 0x00, par);
+
+	aty_st_8(BUS_CNTL, 0x01, par);
+	aty_st_le32(BUS_CNTL, card->bus_cntl | 0x08000000, par);
+
+	aty_st_le32(CRTC_GEN_CNTL, 0x04000200, par);
+	aty_st_le16(CONFIG_STAT0, 0x0020, par);
+	aty_st_le32(MEM_CNTL, 0x10151A33, par);
+	aty_st_le32(EXT_MEM_CNTL, 0xE0000C01, par);
+	aty_st_le16(CRTC_GEN_CNTL+2, 0x0000, par);
+	aty_st_le32(DAC_CNTL, card->dac_cntl, par);
+	aty_st_le16(GEN_TEST_CNTL, 0x0100, par);
+	aty_st_le32(CUSTOM_MACRO_CNTL, 0x003C0171, par);
+	aty_st_le32(MEM_BUF_CNTL, 0x00382848, par);
+
+	aty_st_le32(HW_DEBUG, card->hw_debug, par);
+	aty_st_le16(MEM_ADDR_CONFIG, 0x0000, par);
+	aty_st_le16(GP_IO+2, 0x0000, par);
+	aty_st_le16(GEN_TEST_CNTL, 0x0000, par);
+	aty_st_le16(EXT_DAC_REGS+2, 0x0000, par);
+	aty_st_le32(CRTC_INT_CNTL, 0x00000000, par);
+	aty_st_le32(TIMER_CONFIG, 0x00000000, par);
+	aty_st_le32(0xEC, 0x00000000, par);
+	aty_st_le32(0xFC, 0x00000000, par);
+
+	for (i=0; i<sizeof(lcd_tbl)/sizeof(lcd_tbl_t); i++) {
+		aty_st_lcd(lcd_tbl[i].lcd_reg, lcd_tbl[i].val, par);
+	}
+
+	aty_st_le16(CONFIG_STAT0, 0x00A4, par);
+	mdelay(10);
+
+	aty_st_8(BUS_CNTL+1, 0xA0, par);
+	mdelay(10);
+	
+	reset_clocks(par, &pll.ct, 1);
+	mdelay(10);
+
+	// something about power management
+	aty_st_8(LCD_INDEX, 0x08, par);
+	aty_st_8(LCD_DATA, 0x0A, par);
+	aty_st_8(LCD_INDEX, 0x08, par);
+	aty_st_8(LCD_DATA+3, 0x02, par);
+	aty_st_8(LCD_INDEX, 0x08, par);
+	aty_st_8(LCD_DATA, 0x0B, par);
+	mdelay(2);
+	
+	// enable display requests, enable CRTC
+	aty_st_8(CRTC_GEN_CNTL+3, 0x02, par);
+	// disable display
+	aty_st_8(CRTC_GEN_CNTL, 0x40, par);
+	// disable display requests, disable CRTC
+	aty_st_8(CRTC_GEN_CNTL+3, 0x04, par);
+	mdelay(10);
+
+	aty_st_pll_ct(PLL_YCLK_CNTL, 0x25, par);
+
+	aty_st_le16(CUSTOM_MACRO_CNTL, 0x0179, par);
+	aty_st_le16(CUSTOM_MACRO_CNTL+2, 0x005E, par);
+	aty_st_le16(CUSTOM_MACRO_CNTL+2, card->custom_macro_cntl>>16, par);
+	aty_st_8(CUSTOM_MACRO_CNTL+1,
+		 (card->custom_macro_cntl>>8) & 0xff, par);
+
+	aty_st_le32(MEM_ADDR_CONFIG, card->mem_addr_config, par);
+	aty_st_le32(MEM_CNTL, card->mem_cntl, par);
+	aty_st_le32(EXT_MEM_CNTL, card->ext_mem_cntl, par);
+
+	aty_st_8(CONFIG_STAT0, 0xA0 | card->mem_type, par);
+
+	aty_st_pll_ct(PLL_YCLK_CNTL, 0x01, par);
+	mdelay(15);
+	aty_st_pll_ct(PLL_YCLK_CNTL, card->pll_yclk_cntl, par);
+	mdelay(1);
+	
+	reset_clocks(par, &pll.ct, 0);
+	mdelay(50);
+	reset_clocks(par, &pll.ct, 0);
+	mdelay(50);
+
+	// enable extended register block
+	aty_st_8(BUS_CNTL+3, 0x7B, par);
+	mdelay(1);
+	// disable extended register block
+	aty_st_8(BUS_CNTL+3, 0x73, par);
+
+	aty_st_8(CONFIG_STAT0, 0x80 | card->mem_type, par);
+
+	// disable display requests, disable CRTC
+	aty_st_8(CRTC_GEN_CNTL+3, 0x04, par);
+	// disable mapping registers in VGA aperture
+	aty_st_8(CONFIG_CNTL, aty_ld_8(CONFIG_CNTL, par) & ~0x04, par);
+	mdelay(50);
+	// enable display requests, enable CRTC
+	aty_st_8(CRTC_GEN_CNTL+3, 0x02, par);
+
+	// make GPIO's 14,15,16 all inputs
+	aty_st_8(LCD_INDEX, 0x07, par);
+	aty_st_8(LCD_DATA+3, 0x00, par);
+
+	// enable the display
+	aty_st_8(CRTC_GEN_CNTL, 0x00, par);
+	mdelay(17);
+	// reset the memory controller
+	aty_st_8(GEN_TEST_CNTL+1, 0x02, par);
+	mdelay(15);
+	aty_st_8(GEN_TEST_CNTL+1, 0x00, par);
+	mdelay(30);
+
+	// enable extended register block
+	aty_st_8(BUS_CNTL+3,
+		 (u8)(aty_ld_8(BUS_CNTL+3, par) | 0x08),
+		 par);
+	// set FIFO size to 512 (PIO)
+	aty_st_le32(GUI_CNTL,
+		    aty_ld_le32(GUI_CNTL, par) & ~0x3,
+		    par);
+
+	// enable CRT and disable lcd
+	aty_st_8(LCD_INDEX, 0x01, par);
+	temp = aty_ld_le32(LCD_DATA, par);
+	temp = (temp | 0x01) & ~0x02;
+	aty_st_le32(LCD_DATA, temp, par);
+	return 0;
+}
+
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c
new file mode 100644
index 0000000..cacd88c
--- /dev/null
+++ b/drivers/video/au1100fb.c
@@ -0,0 +1,676 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ *	Au1100 LCD Driver.
+ *
+ * Copyright 2002 MontaVista Software
+ * Author: MontaVista Software, Inc.
+ *		ppopov@mvista.com or source@mvista.com
+ *
+ * Copyright 2002 Alchemy Semiconductor
+ * Author: Alchemy Semiconductor
+ *
+ * Based on:
+ * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device
+ *  Created 28 Dec 1997 by Geert Uytterhoeven
+ *
+ *  This program is free software; you can redistribute	 it and/or modify it
+ *  under  the terms of	 the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the	License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED
+ *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF
+ *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#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/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/au1000.h>
+#include <asm/pb1100.h>
+#include "au1100fb.h"
+
+#include <video/fbcon.h>
+#include <video/fbcon-mfb.h>
+#include <video/fbcon-cfb2.h>
+#include <video/fbcon-cfb4.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+
+/*
+ * Sanity check. If this is a new Au1100 based board, search for
+ * the PB1100 ifdefs to make sure you modify the code accordingly.
+ */
+#if defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_DB1100) || defined(CONFIG_MIPS_HYDROGEN3)
+#else
+error Unknown Au1100 board
+#endif
+
+#define CMAPSIZE 16
+
+static int my_lcd_index; /* default is zero */
+struct known_lcd_panels *p_lcd;
+AU1100_LCD *p_lcd_reg = (AU1100_LCD *)AU1100_LCD_ADDR;
+
+struct au1100fb_info {
+	struct fb_info_gen gen;
+	unsigned long fb_virt_start;
+	unsigned long fb_size;
+	unsigned long fb_phys;
+	int mmaped;
+	int nohwcursor;
+
+	struct { unsigned red, green, blue, pad; } palette[256];
+
+#if defined(FBCON_HAS_CFB16)
+	u16 fbcon_cmap16[16];
+#endif
+};
+
+
+struct au1100fb_par {
+        struct fb_var_screeninfo var;
+
+	int line_length;  // in bytes
+	int cmap_len;     // color-map length
+};
+
+
+static struct au1100fb_info fb_info;
+static struct au1100fb_par current_par;
+static struct display disp;
+
+int au1100fb_init(void);
+void au1100fb_setup(char *options, int *ints);
+static int au1100fb_mmap(struct fb_info *fb, struct file *file,
+		struct vm_area_struct *vma);
+static int au1100_blank(int blank_mode, struct fb_info_gen *info);
+static int au1100fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+			  u_long arg, int con, struct fb_info *info);
+
+void au1100_nocursor(struct display *p, int mode, int xx, int yy){};
+
+static struct fb_ops au1100fb_ops = {
+	owner:		THIS_MODULE,
+	fb_get_fix:	fbgen_get_fix,
+	fb_get_var:	fbgen_get_var,
+	fb_set_var:	fbgen_set_var,
+	fb_get_cmap:	fbgen_get_cmap,
+	fb_set_cmap:	fbgen_set_cmap,
+	fb_pan_display: fbgen_pan_display,
+        fb_ioctl:       au1100fb_ioctl,
+	fb_mmap:        au1100fb_mmap,
+};
+
+static void au1100_detect(void)
+{
+	/*
+	 *  This function should detect the current video mode settings
+	 *  and store it as the default video mode
+	 */
+
+	/*
+	 * Yeh, well, we're not going to change any settings so we're
+	 * always stuck with the default ...
+	 */
+
+}
+
+static int au1100_encode_fix(struct fb_fix_screeninfo *fix,
+		const void *_par, struct fb_info_gen *_info)
+{
+        struct au1100fb_info *info = (struct au1100fb_info *) _info;
+        struct au1100fb_par *par = (struct au1100fb_par *) _par;
+	struct fb_var_screeninfo *var = &par->var;
+
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+
+	fix->smem_start = info->fb_phys;
+	fix->smem_len = info->fb_size;
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->type_aux = 0;
+        fix->visual = (var->bits_per_pixel == 8) ?
+	       	FB_VISUAL_PSEUDOCOLOR	: FB_VISUAL_TRUECOLOR;
+	fix->ywrapstep = 0;
+	fix->xpanstep = 1;
+	fix->ypanstep = 1;
+	fix->line_length = current_par.line_length;
+	return 0;
+}
+
+static void set_color_bitfields(struct fb_var_screeninfo *var)
+{
+	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:	/* 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;
+}
+
+static int au1100_decode_var(const struct fb_var_screeninfo *var,
+		void *_par, struct fb_info_gen *_info)
+{
+
+	struct au1100fb_par *par = (struct au1100fb_par *)_par;
+
+	/*
+	 * Don't allow setting any of these yet: xres and yres don't
+	 * make sense for LCD panels.
+	 */
+	if (var->xres != p_lcd->xres ||
+	    var->yres != p_lcd->yres ||
+	    var->xres != p_lcd->xres ||
+	    var->yres != p_lcd->yres) {
+		return -EINVAL;
+	}
+	if(var->bits_per_pixel != p_lcd->bpp) {
+		return -EINVAL;
+	}
+
+	memset(par, 0, sizeof(struct au1100fb_par));
+	par->var = *var;
+
+	/* FIXME */
+	switch (var->bits_per_pixel) {
+		case 8:
+			par->var.bits_per_pixel = 8;
+			break;
+		case 16:
+			par->var.bits_per_pixel = 16;
+			break;
+		default:
+			printk("color depth %d bpp not supported\n",
+					var->bits_per_pixel);
+			return -EINVAL;
+
+	}
+	set_color_bitfields(&par->var);
+	par->cmap_len = (par->var.bits_per_pixel == 8) ? 256 : 16;
+	return 0;
+}
+
+static int au1100_encode_var(struct fb_var_screeninfo *var,
+		const void *par, struct fb_info_gen *_info)
+{
+
+	*var = ((struct au1100fb_par *)par)->var;
+	return 0;
+}
+
+static void
+au1100_get_par(void *_par, struct fb_info_gen *_info)
+{
+	*(struct au1100fb_par *)_par = current_par;
+}
+
+static void au1100_set_par(const void *par, struct fb_info_gen *info)
+{
+	/* nothing to do: we don't change any settings */
+}
+
+static int au1100_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+			 unsigned *blue, unsigned *transp,
+			 struct fb_info *info)
+{
+
+	struct au1100fb_info* i = (struct au1100fb_info*)info;
+
+	if (regno > 255)
+		return 1;
+
+	*red    = i->palette[regno].red;
+	*green  = i->palette[regno].green;
+	*blue   = i->palette[regno].blue;
+	*transp = 0;
+
+	return 0;
+}
+
+static int au1100_setcolreg(unsigned regno, unsigned red, unsigned green,
+			 unsigned blue, unsigned transp,
+			 struct fb_info *info)
+{
+	struct au1100fb_info* i = (struct au1100fb_info *)info;
+	u32 rgbcol;
+
+	if (regno > 255)
+		return 1;
+
+	i->palette[regno].red    = red;
+	i->palette[regno].green  = green;
+	i->palette[regno].blue   = blue;
+
+	switch(p_lcd->bpp) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		red >>= 10;
+		green >>= 10;
+		blue >>= 10;
+		p_lcd_reg->lcd_pallettebase[regno] = (blue&0x1f) |
+			((green&0x3f)<<5) | ((red&0x1f)<<11);
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		i->fbcon_cmap16[regno] =
+			((red & 0xf800) >> 0) |
+			((green & 0xfc00) >> 5) |
+			((blue & 0xf800) >> 11);
+		break;
+#endif
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+
+static int  au1100_blank(int blank_mode, struct fb_info_gen *_info)
+{
+
+	switch (blank_mode) {
+	case VESA_NO_BLANKING:
+		/* turn on panel */
+		//printk("turn on panel\n");
+#ifdef CONFIG_MIPS_PB1100
+		p_lcd_reg->lcd_control |= LCD_CONTROL_GO;
+		au_writew(au_readw(PB1100_G_CONTROL) | p_lcd->mode_backlight,
+			PB1100_G_CONTROL);
+#endif
+#ifdef CONFIG_MIPS_HYDROGEN3
+		/*  Turn controller & power supply on,  GPIO213 */
+		au_writel(0x20002000, 0xB1700008);
+		au_writel(0x00040000, 0xB1900108);
+		au_writel(0x01000100, 0xB1700008);
+#endif
+		au_sync();
+		break;
+
+	case VESA_VSYNC_SUSPEND:
+	case VESA_HSYNC_SUSPEND:
+	case VESA_POWERDOWN:
+		/* turn off panel */
+		//printk("turn off panel\n");
+#ifdef CONFIG_MIPS_PB1100
+		au_writew(au_readw(PB1100_G_CONTROL) & ~p_lcd->mode_backlight,
+			PB1100_G_CONTROL);
+		p_lcd_reg->lcd_control &= ~LCD_CONTROL_GO;
+#endif
+		au_sync();
+		break;
+	default:
+		break;
+
+	}
+	return 0;
+}
+
+static void au1100_set_disp(const void *unused, struct display *disp,
+			 struct fb_info_gen *info)
+{
+	disp->screen_base = (char *)fb_info.fb_virt_start;
+
+	switch (disp->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		disp->dispsw = &fbcon_cfb8;
+		if (fb_info.nohwcursor)
+			fbcon_cfb8.cursor = au1100_nocursor;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		disp->dispsw = &fbcon_cfb16;
+		disp->dispsw_data = fb_info.fbcon_cmap16;
+		if (fb_info.nohwcursor)
+			fbcon_cfb16.cursor = au1100_nocursor;
+		break;
+#endif
+	default:
+		disp->dispsw = &fbcon_dummy;
+		disp->dispsw_data = NULL;
+		break;
+	}
+}
+
+static int
+au1100fb_mmap(struct fb_info *_fb,
+	     struct file *file,
+	     struct vm_area_struct *vma)
+{
+	unsigned int len;
+	unsigned long start=0, off;
+	struct au1100fb_info *fb = (struct au1100fb_info *)_fb;
+
+	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) {
+		return -EINVAL;
+	}
+
+	start = fb_info.fb_phys & PAGE_MASK;
+	len = PAGE_ALIGN((start & ~PAGE_MASK) + fb_info.fb_size);
+
+	off = vma->vm_pgoff << PAGE_SHIFT;
+
+	if ((vma->vm_end - vma->vm_start + off) > len) {
+		return -EINVAL;
+	}
+
+	off += start;
+	vma->vm_pgoff = off >> PAGE_SHIFT;
+
+	pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;
+	//pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NONCOHERENT;
+	pgprot_val(vma->vm_page_prot) |= (6 << 9); //CCA=6
+
+	/* This is an IO map - tell maydump to skip this VMA */
+	vma->vm_flags |= VM_IO;
+
+	if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+				vma->vm_end - vma->vm_start,
+				vma->vm_page_prot)) {
+		return -EAGAIN;
+	}
+
+	fb->mmaped = 1;
+	return 0;
+}
+
+int au1100_pan_display(const struct fb_var_screeninfo *var,
+		       struct fb_info_gen *info)
+{
+	return 0;
+}
+
+static int au1100fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+			  u_long arg, int con, struct fb_info *info)
+{
+	/* nothing to do yet */
+	return -EINVAL;
+}
+
+static struct fbgen_hwswitch au1100_switch = {
+	au1100_detect,
+	au1100_encode_fix,
+	au1100_decode_var,
+	au1100_encode_var,
+	au1100_get_par,
+	au1100_set_par,
+	au1100_getcolreg,
+	au1100_setcolreg,
+	au1100_pan_display,
+	au1100_blank,
+	au1100_set_disp
+};
+
+
+int au1100_setmode(void)
+{
+	int words;
+
+	/* FIXME Need to accomodate for swivel mode and 12bpp, <8bpp*/
+	switch (p_lcd->mode_control & LCD_CONTROL_SM)
+	{
+		case LCD_CONTROL_SM_0:
+		case LCD_CONTROL_SM_180:
+		words = (p_lcd->xres * p_lcd->yres * p_lcd->bpp) / 32;
+			break;
+		case LCD_CONTROL_SM_90:
+		case LCD_CONTROL_SM_270:
+			/* is this correct? */
+		words = (p_lcd->xres * p_lcd->bpp) / 8;
+			break;
+		default:
+			printk("mode_control reg not initialized\n");
+			return -EINVAL;
+	}
+
+	/*
+	 * Setup LCD controller
+	 */
+
+	p_lcd_reg->lcd_control = p_lcd->mode_control;
+	p_lcd_reg->lcd_intstatus = 0;
+	p_lcd_reg->lcd_intenable = 0;
+	p_lcd_reg->lcd_horztiming = p_lcd->mode_horztiming;
+	p_lcd_reg->lcd_verttiming = p_lcd->mode_verttiming;
+	p_lcd_reg->lcd_clkcontrol = p_lcd->mode_clkcontrol;
+	p_lcd_reg->lcd_words = words - 1;
+	p_lcd_reg->lcd_dmaaddr0 = fb_info.fb_phys;
+
+	/* turn on panel */
+#ifdef CONFIG_MIPS_PB1100
+	au_writew(au_readw(PB1100_G_CONTROL) | p_lcd->mode_backlight,
+			PB1100_G_CONTROL);
+#endif
+#ifdef CONFIG_MIPS_HYDROGEN3
+	/*  Turn controller & power supply on,  GPIO213 */
+	au_writel(0x20002000, 0xB1700008);
+	au_writel(0x00040000, 0xB1900108);
+	au_writel(0x01000100, 0xB1700008);
+#endif
+
+	p_lcd_reg->lcd_control |= LCD_CONTROL_GO;
+
+	return 0;
+}
+
+
+int __init au1100fb_init(void)
+{
+	uint32 sys_clksrc;
+	unsigned long page;
+
+	/*
+	* Get the panel information/display mode and update the registry
+	*/
+	p_lcd = &panels[my_lcd_index];
+
+	switch (p_lcd->mode_control & LCD_CONTROL_SM)
+	{
+		case LCD_CONTROL_SM_0:
+		case LCD_CONTROL_SM_180:
+		p_lcd->xres =
+			(p_lcd->mode_horztiming & LCD_HORZTIMING_PPL) + 1;
+		p_lcd->yres =
+			(p_lcd->mode_verttiming & LCD_VERTTIMING_LPP) + 1;
+			break;
+		case LCD_CONTROL_SM_90:
+		case LCD_CONTROL_SM_270:
+		p_lcd->yres =
+			(p_lcd->mode_horztiming & LCD_HORZTIMING_PPL) + 1;
+		p_lcd->xres =
+			(p_lcd->mode_verttiming & LCD_VERTTIMING_LPP) + 1;
+			break;
+	}
+
+	/*
+	 * Panel dimensions x bpp must be divisible by 32
+	 */
+	if (((p_lcd->yres * p_lcd->bpp) % 32) != 0)
+		printk("VERT %% 32\n");
+	if (((p_lcd->xres * p_lcd->bpp) % 32) != 0)
+		printk("HORZ %% 32\n");
+
+	/*
+	 * Allocate LCD framebuffer from system memory
+	 */
+	fb_info.fb_size = (p_lcd->xres * p_lcd->yres * p_lcd->bpp) / 8;
+
+	current_par.var.xres = p_lcd->xres;
+	current_par.var.xres_virtual = p_lcd->xres;
+	current_par.var.yres = p_lcd->yres;
+	current_par.var.yres_virtual = p_lcd->yres;
+	current_par.var.bits_per_pixel = p_lcd->bpp;
+
+	/* FIX!!! only works for 8/16 bpp */
+	current_par.line_length = p_lcd->xres * p_lcd->bpp / 8; /* in bytes */
+	fb_info.fb_virt_start = (unsigned long )
+		__get_free_pages(GFP_ATOMIC | GFP_DMA,
+				get_order(fb_info.fb_size + 0x1000));
+	if (!fb_info.fb_virt_start) {
+		printk("Unable to allocate fb memory\n");
+		return -ENOMEM;
+	}
+	fb_info.fb_phys = virt_to_bus((void *)fb_info.fb_virt_start);
+
+	/*
+	 * Set page reserved so that mmap will work. This is necessary
+	 * since we'll be remapping normal memory.
+	 */
+	for (page = fb_info.fb_virt_start;
+	     page < PAGE_ALIGN(fb_info.fb_virt_start + fb_info.fb_size);
+	     page += PAGE_SIZE) {
+		SetPageReserved(virt_to_page(page));
+	}
+
+	memset((void *)fb_info.fb_virt_start, 0, fb_info.fb_size);
+
+	/* set freqctrl now to allow more time to stabilize */
+	/* zero-out out LCD bits */
+	sys_clksrc = au_readl(SYS_CLKSRC) & ~0x000003e0;
+	sys_clksrc |= p_lcd->mode_toyclksrc;
+	au_writel(sys_clksrc, SYS_CLKSRC);
+
+	/* FIXME add check to make sure auxpll is what is expected! */
+	au1100_setmode();
+
+	fb_info.gen.parsize = sizeof(struct au1100fb_par);
+	fb_info.gen.fbhw = &au1100_switch;
+
+	strcpy(fb_info.gen.info.modename, "Au1100 LCD");
+	fb_info.gen.info.changevar = NULL;
+	fb_info.gen.info.node = -1;
+
+	fb_info.gen.info.fbops = &au1100fb_ops;
+	fb_info.gen.info.disp = &disp;
+	fb_info.gen.info.switch_con = &fbgen_switch;
+	fb_info.gen.info.updatevar = &fbgen_update_var;
+	fb_info.gen.info.blank = &fbgen_blank;
+	fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
+
+	/* This should give a reasonable default video mode */
+	fbgen_get_var(&disp.var, -1, &fb_info.gen.info);
+	fbgen_do_set_var(&disp.var, 1, &fb_info.gen);
+	fbgen_set_disp(-1, &fb_info.gen);
+	fbgen_install_cmap(0, &fb_info.gen);
+	if (register_framebuffer(&fb_info.gen.info) < 0)
+		return -EINVAL;
+	printk(KERN_INFO "fb%d: %s frame buffer device\n",
+			GET_FB_IDX(fb_info.gen.info.node),
+			fb_info.gen.info.modename);
+
+	return 0;
+}
+
+
+void au1100fb_cleanup(struct fb_info *info)
+{
+	unregister_framebuffer(info);
+}
+
+
+void au1100fb_setup(char *options, int *ints)
+{
+	char* this_opt;
+	int i;
+	int num_panels = sizeof(panels)/sizeof(struct known_lcd_panels);
+
+
+	if (!options || !*options)
+		return;
+
+	for(this_opt=strtok(options, ","); this_opt;
+	    this_opt=strtok(NULL, ",")) {
+		if (!strncmp(this_opt, "panel:", 6)) {
+#if defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_DB1100)
+			/* Read Pb1100 Switch S10 ? */
+			if (!strncmp(this_opt+6, "s10", 3))
+			{
+				int panel;
+				panel = *(volatile int *)0xAE000008; /* BCSR SWITCHES */
+				panel >>= 8;
+				panel &= 0x0F;
+				if (panel >= num_panels) panel = 0;
+				my_lcd_index = panel;
+			}
+			else
+#endif
+			/* Get the panel name, everything else if fixed */
+			for (i=0; i<num_panels; i++) {
+				if (!strncmp(this_opt+6, panels[i].panel_name,
+							strlen(this_opt))) {
+					my_lcd_index = i;
+					break;
+				}
+			}
+		}
+		else if (!strncmp(this_opt, "nohwcursor", 10)) {
+			printk("nohwcursor\n");
+			fb_info.nohwcursor = 1;
+		}
+	}
+
+	printk("au1100fb: Panel %d %s\n", my_lcd_index,
+		panels[my_lcd_index].panel_name);
+}
+
+
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+int init_module(void)
+{
+	return au1100fb_init();
+}
+
+void cleanup_module(void)
+{
+	au1100fb_cleanup(void);
+}
+
+MODULE_AUTHOR("Pete Popov <ppopov@mvista.com>");
+MODULE_DESCRIPTION("Au1100 LCD framebuffer device driver");
+#endif /* MODULE */
diff --git a/drivers/video/au1100fb.h b/drivers/video/au1100fb.h
new file mode 100644
index 0000000..657c560
--- /dev/null
+++ b/drivers/video/au1100fb.h
@@ -0,0 +1,381 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ *	Hardware definitions for the Au1100 LCD controller
+ *
+ * Copyright 2002 MontaVista Software
+ * Copyright 2002 Alchemy Semiconductor
+ * Author:	Alchemy Semiconductor, MontaVista Software
+ *
+ *  This program is free software; you can redistribute	 it and/or modify it
+ *  under  the terms of	 the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the	License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED
+ *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF
+ *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _AU1100LCD_H
+#define _AU1100LCD_H
+
+/********************************************************************/
+#define uint32 unsigned long
+typedef volatile struct
+{
+	uint32	lcd_control;
+	uint32	lcd_intstatus;
+	uint32	lcd_intenable;
+	uint32	lcd_horztiming;
+	uint32	lcd_verttiming;
+	uint32	lcd_clkcontrol;
+	uint32	lcd_dmaaddr0;
+	uint32	lcd_dmaaddr1;
+	uint32	lcd_words;
+	uint32	lcd_pwmdiv;
+	uint32	lcd_pwmhi;
+	uint32	reserved[(0x0400-0x002C)/4];
+	uint32	lcd_pallettebase[256];
+
+} AU1100_LCD;
+
+/********************************************************************/
+
+#define AU1100_LCD_ADDR		0xB5000000
+
+/*
+ * Register bit definitions
+ */
+
+/* lcd_control */
+#define LCD_CONTROL_SBPPF		(7<<18)
+#define LCD_CONTROL_SBPPF_655	(0<<18)
+#define LCD_CONTROL_SBPPF_565	(1<<18)
+#define LCD_CONTROL_SBPPF_556	(2<<18)
+#define LCD_CONTROL_SBPPF_1555	(3<<18)
+#define LCD_CONTROL_SBPPF_5551	(4<<18)
+#define LCD_CONTROL_WP			(1<<17)
+#define LCD_CONTROL_WD			(1<<16)
+#define LCD_CONTROL_C			(1<<15)
+#define LCD_CONTROL_SM			(3<<13)
+#define LCD_CONTROL_SM_0		(0<<13)
+#define LCD_CONTROL_SM_90		(1<<13)
+#define LCD_CONTROL_SM_180		(2<<13)
+#define LCD_CONTROL_SM_270		(3<<13)
+#define LCD_CONTROL_DB			(1<<12)
+#define LCD_CONTROL_CCO			(1<<11)
+#define LCD_CONTROL_DP			(1<<10)
+#define LCD_CONTROL_PO			(3<<8)
+#define LCD_CONTROL_PO_00		(0<<8)
+#define LCD_CONTROL_PO_01		(1<<8)
+#define LCD_CONTROL_PO_10		(2<<8)
+#define LCD_CONTROL_PO_11		(3<<8)
+#define LCD_CONTROL_MPI			(1<<7)
+#define LCD_CONTROL_PT			(1<<6)
+#define LCD_CONTROL_PC			(1<<5)
+#define LCD_CONTROL_BPP			(7<<1)
+#define LCD_CONTROL_BPP_1		(0<<1)
+#define LCD_CONTROL_BPP_2		(1<<1)
+#define LCD_CONTROL_BPP_4		(2<<1)
+#define LCD_CONTROL_BPP_8		(3<<1)
+#define LCD_CONTROL_BPP_12		(4<<1)
+#define LCD_CONTROL_BPP_16		(5<<1)
+#define LCD_CONTROL_GO			(1<<0)
+
+/* lcd_intstatus, lcd_intenable */
+#define LCD_INT_SD				(1<<7)
+#define LCD_INT_OF				(1<<6)
+#define LCD_INT_UF				(1<<5)
+#define LCD_INT_SA				(1<<3)
+#define LCD_INT_SS				(1<<2)
+#define LCD_INT_S1				(1<<1)
+#define LCD_INT_S0				(1<<0)
+
+/* lcd_horztiming */
+#define LCD_HORZTIMING_HN2		(255<<24)
+#define LCD_HORZTIMING_HN2_N(N)	(((N)-1)<<24)
+#define LCD_HORZTIMING_HN1		(255<<16)
+#define LCD_HORZTIMING_HN1_N(N)	(((N)-1)<<16)
+#define LCD_HORZTIMING_HPW		(63<<10)
+#define LCD_HORZTIMING_HPW_N(N)	(((N)-1)<<10)
+#define LCD_HORZTIMING_PPL		(1023<<0)
+#define LCD_HORZTIMING_PPL_N(N)	(((N)-1)<<0)
+
+/* lcd_verttiming */
+#define LCD_VERTTIMING_VN2		(255<<24)
+#define LCD_VERTTIMING_VN2_N(N)	(((N)-1)<<24)
+#define LCD_VERTTIMING_VN1		(255<<16)
+#define LCD_VERTTIMING_VN1_N(N)	(((N)-1)<<16)
+#define LCD_VERTTIMING_VPW		(63<<10)
+#define LCD_VERTTIMING_VPW_N(N)	(((N)-1)<<10)
+#define LCD_VERTTIMING_LPP		(1023<<0)
+#define LCD_VERTTIMING_LPP_N(N)	(((N)-1)<<0)
+
+/* lcd_clkcontrol */
+#define LCD_CLKCONTROL_IB		(1<<18)
+#define LCD_CLKCONTROL_IC		(1<<17)
+#define LCD_CLKCONTROL_IH		(1<<16)
+#define LCD_CLKCONTROL_IV		(1<<15)
+#define LCD_CLKCONTROL_BF		(31<<10)
+#define LCD_CLKCONTROL_BF_N(N)	(((N)-1)<<10)
+#define LCD_CLKCONTROL_PCD		(1023<<0)
+#define LCD_CLKCONTROL_PCD_N(N)	((N)<<0)
+
+/* lcd_pwmdiv */
+#define LCD_PWMDIV_EN			(1<<12)
+#define LCD_PWMDIV_PWMDIV		(2047<<0)
+#define LCD_PWMDIV_PWMDIV_N(N)	(((N)-1)<<0)
+
+/* lcd_pwmhi */
+#define LCD_PWMHI_PWMHI1		(2047<<12)
+#define LCD_PWMHI_PWMHI1_N(N)	((N)<<12)
+#define LCD_PWMHI_PWMHI0		(2047<<0)
+#define LCD_PWMHI_PWMHI0_N(N)	((N)<<0)
+
+/* lcd_pallettebase - MONOCHROME */
+#define LCD_PALLETTE_MONO_MI		(15<<0)
+#define LCD_PALLETTE_MONO_MI_N(N)	((N)<<0)
+
+/* lcd_pallettebase - COLOR */
+#define LCD_PALLETTE_COLOR_BI		(15<<8)
+#define LCD_PALLETTE_COLOR_BI_N(N)	((N)<<8)
+#define LCD_PALLETTE_COLOR_GI		(15<<4)
+#define LCD_PALLETTE_COLOR_GI_N(N)	((N)<<4)
+#define LCD_PALLETTE_COLOR_RI		(15<<0)
+#define LCD_PALLETTE_COLOR_RI_N(N)	((N)<<0)
+
+/* lcd_palletebase - COLOR TFT PALLETIZED */
+#define LCD_PALLETTE_TFT_DC			(65535<<0)
+#define LCD_PALLETTE_TFT_DC_N(N)	((N)<<0)
+
+/********************************************************************/
+
+struct known_lcd_panels
+{
+	uint32 xres;
+	uint32 yres;
+	uint32 bpp;
+	unsigned char  panel_name[256];
+	uint32 mode_control;
+	uint32 mode_horztiming;
+	uint32 mode_verttiming;
+	uint32 mode_clkcontrol;
+	uint32 mode_pwmdiv;
+	uint32 mode_pwmhi;
+	uint32 mode_toyclksrc;
+	uint32 mode_backlight;
+
+};
+
+#if defined(__BIG_ENDIAN)
+#define LCD_DEFAULT_PIX_FORMAT LCD_CONTROL_PO_11
+#else
+#define LCD_DEFAULT_PIX_FORMAT LCD_CONTROL_PO_00
+#endif
+
+/*
+ * The fb driver assumes that AUX PLL is at 48MHz.  That can
+ * cover up to 800x600 resolution; if you need higher resolution,
+ * you should modify the driver as needed, not just this structure.
+ */
+struct known_lcd_panels panels[] =
+{
+	{ /* 0: Pb1100 LCDA: Sharp 320x240 TFT panel */
+		320, /* xres */
+		240, /* yres */
+		16,  /* bpp  */
+
+		"Sharp_320x240_16",
+		/* mode_control */
+		( LCD_CONTROL_SBPPF_565
+		/*LCD_CONTROL_WP*/
+		/*LCD_CONTROL_WD*/
+		| LCD_CONTROL_C
+		| LCD_CONTROL_SM_0
+		/*LCD_CONTROL_DB*/
+		/*LCD_CONTROL_CCO*/
+		/*LCD_CONTROL_DP*/
+		| LCD_DEFAULT_PIX_FORMAT
+		/*LCD_CONTROL_MPI*/
+		| LCD_CONTROL_PT
+		| LCD_CONTROL_PC
+		| LCD_CONTROL_BPP_16 ),
+
+		/* mode_horztiming */
+		( LCD_HORZTIMING_HN2_N(8)
+		| LCD_HORZTIMING_HN1_N(60)
+		| LCD_HORZTIMING_HPW_N(12)
+		| LCD_HORZTIMING_PPL_N(320) ),
+
+		/* mode_verttiming */
+		( LCD_VERTTIMING_VN2_N(5)
+		| LCD_VERTTIMING_VN1_N(17)
+		| LCD_VERTTIMING_VPW_N(1)
+		| LCD_VERTTIMING_LPP_N(240) ),
+
+		/* mode_clkcontrol */
+		( 0
+		/*LCD_CLKCONTROL_IB*/
+		/*LCD_CLKCONTROL_IC*/
+		/*LCD_CLKCONTROL_IH*/
+		/*LCD_CLKCONTROL_IV*/
+		| LCD_CLKCONTROL_PCD_N(1) ),
+
+		/* mode_pwmdiv */
+		0,
+
+		/* mode_pwmhi */
+		0,
+
+		/* mode_toyclksrc */
+		((1<<7) | (1<<6) | (1<<5)),
+
+		/* mode_backlight */
+		6
+	},
+
+	{ /* 1: Pb1100 LCDC 640x480 TFT panel */
+		640, /* xres */
+		480, /* yres */
+		16,  /* bpp  */
+
+		"Generic_640x480_16",
+
+		/* mode_control */
+		0x004806a | LCD_DEFAULT_PIX_FORMAT,
+
+		/* mode_horztiming */
+		0x3434d67f,
+
+		/* mode_verttiming */
+		0x0e0e39df,
+
+		/* mode_clkcontrol */
+		( 0
+		/*LCD_CLKCONTROL_IB*/
+		/*LCD_CLKCONTROL_IC*/
+		/*LCD_CLKCONTROL_IH*/
+		/*LCD_CLKCONTROL_IV*/
+		| LCD_CLKCONTROL_PCD_N(1) ),
+
+		/* mode_pwmdiv */
+		0,
+
+		/* mode_pwmhi */
+		0,
+
+		/* mode_toyclksrc */
+		((1<<7) | (1<<6) | (0<<5)),
+
+		/* mode_backlight */
+		7
+	},
+
+	{ /* 2: Pb1100 LCDB 640x480 PrimeView TFT panel */
+		640, /* xres */
+		480, /* yres */
+		16,  /* bpp  */
+
+		"PrimeView_640x480_16",
+
+		/* mode_control */
+		0x0004886a | LCD_DEFAULT_PIX_FORMAT,
+
+		/* mode_horztiming */
+		0x0e4bfe7f,
+
+		/* mode_verttiming */
+		0x210805df,
+
+		/* mode_clkcontrol */
+		0x00038001,
+
+		/* mode_pwmdiv */
+		0,
+
+		/* mode_pwmhi */
+		0,
+
+		/* mode_toyclksrc */
+		((1<<7) | (1<<6) | (0<<5)),
+
+		/* mode_backlight */
+		7
+	},
+
+	{ /* 3: Pb1100 800x600x16bpp NEON CRT */
+		800, /* xres */
+		600, /* yres */
+		16,  /* bpp */
+
+		"NEON_800x600_16",
+
+		/* mode_control */
+		0x0004886A | LCD_DEFAULT_PIX_FORMAT,
+
+		/* mode_horztiming */
+		0x005AFF1F,
+
+		/* mode_verttiming */
+		0x16000E57,
+
+		/* mode_clkcontrol */
+		0x00020000,
+
+		/* mode_pwmdiv */
+		0,
+
+		/* mode_pwmhi */
+		0,
+
+		/* mode_toyclksrc */
+		((1<<7) | (1<<6) | (0<<5)),
+
+		/* mode_backlight */
+		7
+	},
+
+	{ /* 4: Pb1100 640x480x16bpp NEON CRT */
+		640, /* xres */
+		480, /* yres */
+		16,  /* bpp */
+
+		"NEON_640x480_16",
+
+		/* mode_control */
+		0x0004886A | LCD_DEFAULT_PIX_FORMAT,
+
+		/* mode_horztiming */
+		0x0052E27F,
+
+		/* mode_verttiming */
+		0x18000DDF,
+
+		/* mode_clkcontrol */
+		0x00020000,
+
+		/* mode_pwmdiv */
+		0,
+
+		/* mode_pwmhi */
+		0,
+
+		/* mode_toyclksrc */
+		((1<<7) | (1<<6) | (0<<5)),
+
+		/* mode_backlight */
+		7
+	},
+};
+#endif /* _AU1100LCD_H */
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
new file mode 100644
index 0000000..996d543
--- /dev/null
+++ b/drivers/video/backlight/Kconfig
@@ -0,0 +1,52 @@
+#
+# Backlight & LCD drivers configuration
+#
+
+menuconfig BACKLIGHT_LCD_SUPPORT
+	bool "Backlight & LCD device support"
+	help
+	  Enable this to be able to choose the drivers for controlling the
+	  backlight and the LCD panel on some platforms, for example on PDAs.
+
+config BACKLIGHT_CLASS_DEVICE
+        tristate "Lowlevel Backlight controls"
+	depends on BACKLIGHT_LCD_SUPPORT
+	default m
+	help
+	  This framework adds support for low-level control of the LCD
+          backlight. This includes support for brightness and power.
+
+	  To have support for your specific LCD panel you will have to
+	  select the proper drivers which depend on this option.
+
+config BACKLIGHT_DEVICE
+	bool
+	depends on BACKLIGHT_CLASS_DEVICE
+	default y
+
+config LCD_CLASS_DEVICE
+        tristate "Lowlevel LCD controls"
+	depends on BACKLIGHT_LCD_SUPPORT
+	default m
+	help
+	  This framework adds support for low-level control of LCD.
+	  Some framebuffer devices connect to platform-specific LCD modules
+	  in order to have a platform-specific way to control the flat panel
+	  (contrast and applying power to the LCD (not to the backlight!)).
+
+	  To have support for your specific LCD panel you will have to
+	  select the proper drivers which depend on this option.
+
+config LCD_DEVICE
+	bool
+	depends on LCD_CLASS_DEVICE
+	default y
+
+config BACKLIGHT_CORGI
+	tristate "Sharp Corgi Backlight Driver (SL-C7xx Series)"
+	depends on BACKLIGHT_DEVICE && PXA_SHARPSL
+	default y
+	help
+	  If you have a Sharp Zaurus SL-C7xx, say y to enable the
+	  backlight driver.
+
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
new file mode 100644
index 0000000..9aae884
--- /dev/null
+++ b/drivers/video/backlight/Makefile
@@ -0,0 +1,5 @@
+# Backlight & LCD drivers
+
+obj-$(CONFIG_LCD_CLASS_DEVICE)     += lcd.o
+obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
+obj-$(CONFIG_BACKLIGHT_CORGI)	+= corgi_bl.o
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
new file mode 100644
index 0000000..acc81cb
--- /dev/null
+++ b/drivers/video/backlight/backlight.c
@@ -0,0 +1,264 @@
+/*
+ * Backlight Lowlevel Control Abstraction
+ *
+ * Copyright (C) 2003,2004 Hewlett-Packard Company
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/backlight.h>
+#include <linux/notifier.h>
+#include <linux/ctype.h>
+#include <linux/err.h>
+#include <linux/fb.h>
+#include <asm/bug.h>
+
+static ssize_t backlight_show_power(struct class_device *cdev, char *buf)
+{
+	int rc;
+	struct backlight_device *bd = to_backlight_device(cdev);
+
+	down(&bd->sem);
+	if (likely(bd->props && bd->props->get_power))
+		rc = sprintf(buf, "%d\n", bd->props->get_power(bd));
+	else
+		rc = -ENXIO;
+	up(&bd->sem);
+
+	return rc;
+}
+
+static ssize_t backlight_store_power(struct class_device *cdev, const char *buf, size_t count)
+{
+	int rc, power;
+	char *endp;
+	struct backlight_device *bd = to_backlight_device(cdev);
+
+	power = simple_strtoul(buf, &endp, 0);
+	if (*endp && !isspace(*endp))
+		return -EINVAL;
+
+	down(&bd->sem);
+	if (likely(bd->props && bd->props->set_power)) {
+		pr_debug("backlight: set power to %d\n", power);
+		bd->props->set_power(bd, power);
+		rc = count;
+	} else
+		rc = -ENXIO;
+	up(&bd->sem);
+
+	return rc;
+}
+
+static ssize_t backlight_show_brightness(struct class_device *cdev, char *buf)
+{
+	int rc;
+	struct backlight_device *bd = to_backlight_device(cdev);
+
+	down(&bd->sem);
+	if (likely(bd->props && bd->props->get_brightness))
+		rc = sprintf(buf, "%d\n", bd->props->get_brightness(bd));
+	else
+		rc = -ENXIO;
+	up(&bd->sem);
+
+	return rc;
+}
+
+static ssize_t backlight_store_brightness(struct class_device *cdev, const char *buf, size_t count)
+{
+	int rc, brightness;
+	char *endp;
+	struct backlight_device *bd = to_backlight_device(cdev);
+
+	brightness = simple_strtoul(buf, &endp, 0);
+	if (*endp && !isspace(*endp))
+		return -EINVAL;
+
+	down(&bd->sem);
+	if (likely(bd->props && bd->props->set_brightness)) {
+		pr_debug("backlight: set brightness to %d\n", brightness);
+		bd->props->set_brightness(bd, brightness);
+		rc = count;
+	} else
+		rc = -ENXIO;
+	up(&bd->sem);
+
+	return rc;
+}
+
+static ssize_t backlight_show_max_brightness(struct class_device *cdev, char *buf)
+{
+	int rc;
+	struct backlight_device *bd = to_backlight_device(cdev);
+
+	down(&bd->sem);
+	if (likely(bd->props))
+		rc = sprintf(buf, "%d\n", bd->props->max_brightness);
+	else
+		rc = -ENXIO;
+	up(&bd->sem);
+
+	return rc;
+}
+
+static void backlight_class_release(struct class_device *dev)
+{
+	struct backlight_device *bd = to_backlight_device(dev);
+	kfree(bd);
+}
+
+static struct class backlight_class = {
+	.name = "backlight",
+	.release = backlight_class_release,
+};
+
+#define DECLARE_ATTR(_name,_mode,_show,_store)			\
+{							 	\
+	.attr	= { .name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE },	\
+	.show	= _show,					\
+	.store	= _store,					\
+}
+
+static struct class_device_attribute bl_class_device_attributes[] = {
+	DECLARE_ATTR(power, 0644, backlight_show_power, backlight_store_power),
+	DECLARE_ATTR(brightness, 0644, backlight_show_brightness, backlight_store_brightness),
+	DECLARE_ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL),
+};
+
+/* This callback gets called when something important happens inside a
+ * framebuffer driver. We're looking if that important event is blanking,
+ * and if it is, we're switching backlight power as well ...
+ */
+static int fb_notifier_callback(struct notifier_block *self,
+				unsigned long event, void *data)
+{
+	struct backlight_device *bd;
+	struct fb_event *evdata =(struct fb_event *)data;
+
+	/* If we aren't interested in this event, skip it immediately ... */
+	if (event != FB_EVENT_BLANK)
+		return 0;
+
+	bd = container_of(self, struct backlight_device, fb_notif);
+	down(&bd->sem);
+	if (bd->props)
+		if (!bd->props->check_fb || bd->props->check_fb(evdata->info))
+			bd->props->set_power(bd, *(int *)evdata->data);
+	up(&bd->sem);
+	return 0;
+}
+
+/**
+ * backlight_device_register - create and register a new object of
+ *   backlight_device class.
+ * @name: the name of the new object(must be the same as the name of the
+ *   respective framebuffer device).
+ * @devdata: an optional pointer to be stored in the class_device. The
+ *   methods may retrieve it by using class_get_devdata(&bd->class_dev).
+ * @bp: the backlight properties structure.
+ *
+ * Creates and registers new backlight class_device. Returns either an
+ * ERR_PTR() or a pointer to the newly allocated device.
+ */
+struct backlight_device *backlight_device_register(const char *name, void *devdata,
+						   struct backlight_properties *bp)
+{
+	int i, rc;
+	struct backlight_device *new_bd;
+
+	pr_debug("backlight_device_alloc: name=%s\n", name);
+
+	new_bd = kmalloc(sizeof(struct backlight_device), GFP_KERNEL);
+	if (unlikely(!new_bd))
+		return ERR_PTR(ENOMEM);
+
+	init_MUTEX(&new_bd->sem);
+	new_bd->props = bp;
+	memset(&new_bd->class_dev, 0, sizeof(new_bd->class_dev));
+	new_bd->class_dev.class = &backlight_class;
+	strlcpy(new_bd->class_dev.class_id, name, KOBJ_NAME_LEN);
+	class_set_devdata(&new_bd->class_dev, devdata);
+
+	rc = class_device_register(&new_bd->class_dev);
+	if (unlikely(rc)) {
+error:		kfree(new_bd);
+		return ERR_PTR(rc);
+	}
+
+	memset(&new_bd->fb_notif, 0, sizeof(new_bd->fb_notif));
+	new_bd->fb_notif.notifier_call = fb_notifier_callback;
+
+	rc = fb_register_client(&new_bd->fb_notif);
+	if (unlikely(rc))
+		goto error;
+
+	for (i = 0; i < ARRAY_SIZE(bl_class_device_attributes); i++) {
+		rc = class_device_create_file(&new_bd->class_dev,
+					      &bl_class_device_attributes[i]);
+		if (unlikely(rc)) {
+			while (--i >= 0)
+				class_device_remove_file(&new_bd->class_dev,
+							 &bl_class_device_attributes[i]);
+			class_device_unregister(&new_bd->class_dev);
+			/* No need to kfree(new_bd) since release() method was called */
+			return ERR_PTR(rc);
+		}
+	}
+
+	return new_bd;
+}
+EXPORT_SYMBOL(backlight_device_register);
+
+/**
+ * backlight_device_unregister - unregisters a backlight device object.
+ * @bd: the backlight device object to be unregistered and freed.
+ *
+ * Unregisters a previously registered via backlight_device_register object.
+ */
+void backlight_device_unregister(struct backlight_device *bd)
+{
+	int i;
+
+	if (!bd)
+		return;
+
+	pr_debug("backlight_device_unregister: name=%s\n", bd->class_dev.class_id);
+
+	for (i = 0; i < ARRAY_SIZE(bl_class_device_attributes); i++)
+		class_device_remove_file(&bd->class_dev,
+					 &bl_class_device_attributes[i]);
+
+	down(&bd->sem);
+	bd->props = NULL;
+	up(&bd->sem);
+
+	fb_unregister_client(&bd->fb_notif);
+
+	class_device_unregister(&bd->class_dev);
+}
+EXPORT_SYMBOL(backlight_device_unregister);
+
+static void __exit backlight_class_exit(void)
+{
+	class_unregister(&backlight_class);
+}
+
+static int __init backlight_class_init(void)
+{
+	return class_register(&backlight_class);
+}
+
+/*
+ * if this is compiled into the kernel, we need to ensure that the
+ * class is registered before users of the class try to register lcd's
+ */
+postcore_initcall(backlight_class_init);
+module_exit(backlight_class_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jamey Hicks <jamey.hicks@hp.com>, Andrew Zabolotny <zap@homelink.ru>");
+MODULE_DESCRIPTION("Backlight Lowlevel Control Abstraction");
diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c
new file mode 100644
index 0000000..3c026b0
--- /dev/null
+++ b/drivers/video/backlight/corgi_bl.c
@@ -0,0 +1,198 @@
+/*
+ *  Backlight Driver for Sharp Corgi
+ *
+ *  Copyright (c) 2004-2005 Richard Purdie
+ *
+ *  Based on Sharp's 2.4 Backlight Driver
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+
+#include <asm/arch-pxa/corgi.h>
+#include <asm/hardware/scoop.h>
+
+#define CORGI_MAX_INTENSITY 		0x3e
+#define CORGI_DEFAULT_INTENSITY		0x1f
+#define CORGI_LIMIT_MASK			0x0b
+
+static int corgibl_powermode = FB_BLANK_UNBLANK;
+static int current_intensity = 0;
+static int corgibl_limit = 0;
+static spinlock_t bl_lock = SPIN_LOCK_UNLOCKED;
+
+static void corgibl_send_intensity(int intensity)
+{
+	unsigned long flags;
+	void (*corgi_kick_batt)(void);
+
+	if (corgibl_powermode != FB_BLANK_UNBLANK) {
+		intensity = 0;
+	} else {
+		if (corgibl_limit)
+			intensity &= CORGI_LIMIT_MASK;
+	}
+
+	/* Skip 0x20 as it will blank the display */
+	if (intensity >= 0x20)
+		intensity++;
+
+	spin_lock_irqsave(&bl_lock, flags);
+	/* Bits 0-4 are accessed via the SSP interface */
+	corgi_ssp_blduty_set(intensity & 0x1f);
+	/* Bit 5 is via SCOOP */
+	if (intensity & 0x0020)
+		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT);
+	else
+		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT);
+	spin_unlock_irqrestore(&bl_lock, flags);
+}
+
+static void corgibl_blank(int blank)
+{
+	switch(blank) {
+
+	case FB_BLANK_NORMAL:
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_POWERDOWN:
+		if (corgibl_powermode == FB_BLANK_UNBLANK) {
+			corgibl_send_intensity(0);
+			corgibl_powermode = blank;
+		}
+		break;
+	case FB_BLANK_UNBLANK:
+		if (corgibl_powermode != FB_BLANK_UNBLANK) {
+			corgibl_powermode = blank;
+			corgibl_send_intensity(current_intensity);
+		}
+		break;
+	}
+}
+
+#ifdef CONFIG_PM
+static int corgibl_suspend(struct device *dev, u32 state, u32 level)
+{
+	if (level == SUSPEND_POWER_DOWN)
+		corgibl_blank(FB_BLANK_POWERDOWN);
+	return 0;
+}
+
+static int corgibl_resume(struct device *dev, u32 level)
+{
+	if (level == RESUME_POWER_ON)
+		corgibl_blank(FB_BLANK_UNBLANK);
+	return 0;
+}
+#else
+#define corgibl_suspend	NULL
+#define corgibl_resume	NULL
+#endif
+
+
+static int corgibl_set_power(struct backlight_device *bd, int state)
+{
+	corgibl_blank(state);
+	return 0;
+}
+
+static int corgibl_get_power(struct backlight_device *bd)
+{
+	return corgibl_powermode;
+}
+
+static int corgibl_set_intensity(struct backlight_device *bd, int intensity)
+{
+	if (intensity > CORGI_MAX_INTENSITY)
+		intensity = CORGI_MAX_INTENSITY;
+	corgibl_send_intensity(intensity);
+	current_intensity=intensity;
+	return 0;
+}
+
+static int corgibl_get_intensity(struct backlight_device *bd)
+{
+	return current_intensity;
+}
+
+/*
+ * Called when the battery is low to limit the backlight intensity.
+ * If limit==0 clear any limit, otherwise limit the intensity
+ */
+void corgibl_limit_intensity(int limit)
+{
+	corgibl_limit = (limit ? 1 : 0);
+	corgibl_send_intensity(current_intensity);
+}
+EXPORT_SYMBOL(corgibl_limit_intensity);
+
+
+static struct backlight_properties corgibl_data = {
+	.owner		= THIS_MODULE,
+	.get_power      = corgibl_get_power,
+	.set_power      = corgibl_set_power,
+	.max_brightness = CORGI_MAX_INTENSITY,
+	.get_brightness = corgibl_get_intensity,
+	.set_brightness = corgibl_set_intensity,
+};
+
+static struct backlight_device *corgi_backlight_device;
+
+static int __init corgibl_probe(struct device *dev)
+{
+	corgi_backlight_device = backlight_device_register ("corgi-bl",
+		NULL, &corgibl_data);
+	if (IS_ERR (corgi_backlight_device))
+		return PTR_ERR (corgi_backlight_device);
+
+	corgibl_set_intensity(NULL, CORGI_DEFAULT_INTENSITY);
+
+	printk("Corgi Backlight Driver Initialized.\n");
+	return 0;
+}
+
+static int corgibl_remove(struct device *dev)
+{
+	backlight_device_unregister(corgi_backlight_device);
+
+	corgibl_set_intensity(NULL, 0);
+
+	printk("Corgi Backlight Driver Unloaded\n");
+	return 0;
+}
+
+static struct device_driver corgibl_driver = {
+	.name		= "corgi-bl",
+	.bus		= &platform_bus_type,
+	.probe		= corgibl_probe,
+	.remove		= corgibl_remove,
+	.suspend	= corgibl_suspend,
+	.resume		= corgibl_resume,
+};
+
+static int __init corgibl_init(void)
+{
+	return driver_register(&corgibl_driver);
+}
+
+static void __exit corgibl_exit(void)
+{
+ 	driver_unregister(&corgibl_driver);
+}
+
+module_init(corgibl_init);
+module_exit(corgibl_exit);
+
+MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
+MODULE_DESCRIPTION("Corgi Backlight Driver");
+MODULE_LICENSE("GPLv2");
diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c
new file mode 100644
index 0000000..470e6f0
--- /dev/null
+++ b/drivers/video/backlight/lcd.c
@@ -0,0 +1,263 @@
+/*
+ * LCD Lowlevel Control Abstraction
+ *
+ * Copyright (C) 2003,2004 Hewlett-Packard Company
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/lcd.h>
+#include <linux/notifier.h>
+#include <linux/ctype.h>
+#include <linux/err.h>
+#include <linux/fb.h>
+#include <asm/bug.h>
+
+static ssize_t lcd_show_power(struct class_device *cdev, char *buf)
+{
+	int rc;
+	struct lcd_device *ld = to_lcd_device(cdev);
+
+	down(&ld->sem);
+	if (likely(ld->props && ld->props->get_power))
+		rc = sprintf(buf, "%d\n", ld->props->get_power(ld));
+	else
+		rc = -ENXIO;
+	up(&ld->sem);
+
+	return rc;
+}
+
+static ssize_t lcd_store_power(struct class_device *cdev, const char *buf, size_t count)
+{
+	int rc, power;
+	char *endp;
+	struct lcd_device *ld = to_lcd_device(cdev);
+
+	power = simple_strtoul(buf, &endp, 0);
+	if (*endp && !isspace(*endp))
+		return -EINVAL;
+
+	down(&ld->sem);
+	if (likely(ld->props && ld->props->set_power)) {
+		pr_debug("lcd: set power to %d\n", power);
+		ld->props->set_power(ld, power);
+		rc = count;
+	} else
+		rc = -ENXIO;
+	up(&ld->sem);
+
+	return rc;
+}
+
+static ssize_t lcd_show_contrast(struct class_device *cdev, char *buf)
+{
+	int rc;
+	struct lcd_device *ld = to_lcd_device(cdev);
+
+	down(&ld->sem);
+	if (likely(ld->props && ld->props->get_contrast))
+		rc = sprintf(buf, "%d\n", ld->props->get_contrast(ld));
+	else
+		rc = -ENXIO;
+	up(&ld->sem);
+
+	return rc;
+}
+
+static ssize_t lcd_store_contrast(struct class_device *cdev, const char *buf, size_t count)
+{
+	int rc, contrast;
+	char *endp;
+	struct lcd_device *ld = to_lcd_device(cdev);
+
+	contrast = simple_strtoul(buf, &endp, 0);
+	if (*endp && !isspace(*endp))
+		return -EINVAL;
+
+	down(&ld->sem);
+	if (likely(ld->props && ld->props->set_contrast)) {
+		pr_debug("lcd: set contrast to %d\n", contrast);
+		ld->props->set_contrast(ld, contrast);
+		rc = count;
+	} else
+		rc = -ENXIO;
+	up(&ld->sem);
+
+	return rc;
+}
+
+static ssize_t lcd_show_max_contrast(struct class_device *cdev, char *buf)
+{
+	int rc;
+	struct lcd_device *ld = to_lcd_device(cdev);
+
+	down(&ld->sem);
+	if (likely(ld->props))
+		rc = sprintf(buf, "%d\n", ld->props->max_contrast);
+	else
+		rc = -ENXIO;
+	up(&ld->sem);
+
+	return rc;
+}
+
+static void lcd_class_release(struct class_device *dev)
+{
+	struct lcd_device *ld = to_lcd_device(dev);
+	kfree(ld);
+}
+
+static struct class lcd_class = {
+	.name = "lcd",
+	.release = lcd_class_release,
+};
+
+#define DECLARE_ATTR(_name,_mode,_show,_store)			\
+{							 	\
+	.attr	= { .name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE },	\
+	.show	= _show,					\
+	.store	= _store,					\
+}
+
+static struct class_device_attribute lcd_class_device_attributes[] = {
+	DECLARE_ATTR(power, 0644, lcd_show_power, lcd_store_power),
+	DECLARE_ATTR(contrast, 0644, lcd_show_contrast, lcd_store_contrast),
+	DECLARE_ATTR(max_contrast, 0444, lcd_show_max_contrast, NULL),
+};
+
+/* This callback gets called when something important happens inside a
+ * framebuffer driver. We're looking if that important event is blanking,
+ * and if it is, we're switching lcd power as well ...
+ */
+static int fb_notifier_callback(struct notifier_block *self,
+				 unsigned long event, void *data)
+{
+	struct lcd_device *ld;
+	struct fb_event *evdata =(struct fb_event *)data;
+
+	/* If we aren't interested in this event, skip it immediately ... */
+	if (event != FB_EVENT_BLANK)
+		return 0;
+
+	ld = container_of(self, struct lcd_device, fb_notif);
+	down(&ld->sem);
+	if (ld->props)
+		if (!ld->props->check_fb || ld->props->check_fb(evdata->info))
+			ld->props->set_power(ld, *(int *)evdata->data);
+	up(&ld->sem);
+	return 0;
+}
+
+/**
+ * lcd_device_register - register a new object of lcd_device class.
+ * @name: the name of the new object(must be the same as the name of the
+ *   respective framebuffer device).
+ * @devdata: an optional pointer to be stored in the class_device. The
+ *   methods may retrieve it by using class_get_devdata(ld->class_dev).
+ * @lp: the lcd properties structure.
+ *
+ * Creates and registers a new lcd class_device. Returns either an ERR_PTR()
+ * or a pointer to the newly allocated device.
+ */
+struct lcd_device *lcd_device_register(const char *name, void *devdata,
+				       struct lcd_properties *lp)
+{
+	int i, rc;
+	struct lcd_device *new_ld;
+
+	pr_debug("lcd_device_register: name=%s\n", name);
+
+	new_ld = kmalloc(sizeof(struct lcd_device), GFP_KERNEL);
+	if (unlikely(!new_ld))
+		return ERR_PTR(ENOMEM);
+
+	init_MUTEX(&new_ld->sem);
+	new_ld->props = lp;
+	memset(&new_ld->class_dev, 0, sizeof(new_ld->class_dev));
+	new_ld->class_dev.class = &lcd_class;
+	strlcpy(new_ld->class_dev.class_id, name, KOBJ_NAME_LEN);
+	class_set_devdata(&new_ld->class_dev, devdata);
+
+	rc = class_device_register(&new_ld->class_dev);
+	if (unlikely(rc)) {
+error:		kfree(new_ld);
+		return ERR_PTR(rc);
+	}
+
+	memset(&new_ld->fb_notif, 0, sizeof(new_ld->fb_notif));
+	new_ld->fb_notif.notifier_call = fb_notifier_callback;
+
+	rc = fb_register_client(&new_ld->fb_notif);
+	if (unlikely(rc))
+		goto error;
+
+	for (i = 0; i < ARRAY_SIZE(lcd_class_device_attributes); i++) {
+		rc = class_device_create_file(&new_ld->class_dev,
+					      &lcd_class_device_attributes[i]);
+		if (unlikely(rc)) {
+			while (--i >= 0)
+				class_device_remove_file(&new_ld->class_dev,
+							 &lcd_class_device_attributes[i]);
+			class_device_unregister(&new_ld->class_dev);
+			/* No need to kfree(new_ld) since release() method was called */
+			return ERR_PTR(rc);
+		}
+	}
+
+	return new_ld;
+}
+EXPORT_SYMBOL(lcd_device_register);
+
+/**
+ * lcd_device_unregister - unregisters a object of lcd_device class.
+ * @ld: the lcd device object to be unregistered and freed.
+ *
+ * Unregisters a previously registered via lcd_device_register object.
+ */
+void lcd_device_unregister(struct lcd_device *ld)
+{
+	int i;
+
+	if (!ld)
+		return;
+
+	pr_debug("lcd_device_unregister: name=%s\n", ld->class_dev.class_id);
+
+	for (i = 0; i < ARRAY_SIZE(lcd_class_device_attributes); i++)
+		class_device_remove_file(&ld->class_dev,
+					 &lcd_class_device_attributes[i]);
+
+	down(&ld->sem);
+	ld->props = NULL;
+	up(&ld->sem);
+
+	fb_unregister_client(&ld->fb_notif);
+
+	class_device_unregister(&ld->class_dev);
+}
+EXPORT_SYMBOL(lcd_device_unregister);
+
+static void __exit lcd_class_exit(void)
+{
+	class_unregister(&lcd_class);
+}
+
+static int __init lcd_class_init(void)
+{
+	return class_register(&lcd_class);
+}
+
+/*
+ * if this is compiled into the kernel, we need to ensure that the
+ * class is registered before users of the class try to register lcd's
+ */
+postcore_initcall(lcd_class_init);
+module_exit(lcd_class_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jamey Hicks <jamey.hicks@hp.com>, Andrew Zabolotny <zap@homelink.ru>");
+MODULE_DESCRIPTION("LCD Lowlevel Control Abstraction");
diff --git a/drivers/video/bt431.h b/drivers/video/bt431.h
new file mode 100644
index 0000000..c826f27
--- /dev/null
+++ b/drivers/video/bt431.h
@@ -0,0 +1,236 @@
+/*
+ *	linux/drivers/video/bt431.h
+ *
+ *	Copyright 2003  Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de>
+ *
+ *	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/types.h>
+#include <asm/system.h>
+
+/*
+ * Bt431 cursor generator registers, 32-bit aligned.
+ * Two twin Bt431 are used on the DECstation's PMAG-AA.
+ */
+struct bt431_regs {
+	volatile u16 addr_lo;
+	u16 pad0;
+	volatile u16 addr_hi;
+	u16 pad1;
+	volatile u16 addr_cmap;
+	u16 pad2;
+	volatile u16 addr_reg;
+	u16 pad3;
+};
+
+static inline u16 bt431_set_value(u8 val)
+{
+	return ((val << 8) | (val & 0xff)) & 0xffff;
+}
+
+static inline u8 bt431_get_value(u16 val)
+{
+	return val & 0xff;
+}
+
+/*
+ * Additional registers addressed indirectly.
+ */
+#define BT431_REG_CMD		0x0000
+#define BT431_REG_CXLO		0x0001
+#define BT431_REG_CXHI		0x0002
+#define BT431_REG_CYLO		0x0003
+#define BT431_REG_CYHI		0x0004
+#define BT431_REG_WXLO		0x0005
+#define BT431_REG_WXHI		0x0006
+#define BT431_REG_WYLO		0x0007
+#define BT431_REG_WYHI		0x0008
+#define BT431_REG_WWLO		0x0009
+#define BT431_REG_WWHI		0x000a
+#define BT431_REG_WHLO		0x000b
+#define BT431_REG_WHHI		0x000c
+
+#define BT431_REG_CRAM_BASE	0x0000
+#define BT431_REG_CRAM_END	0x01ff
+
+/*
+ * Command register.
+ */
+#define BT431_CMD_CURS_ENABLE	0x40
+#define BT431_CMD_XHAIR_ENABLE	0x20
+#define BT431_CMD_OR_CURSORS	0x10
+#define BT431_CMD_AND_CURSORS	0x00
+#define BT431_CMD_1_1_MUX	0x00
+#define BT431_CMD_4_1_MUX	0x04
+#define BT431_CMD_5_1_MUX	0x08
+#define BT431_CMD_xxx_MUX	0x0c
+#define BT431_CMD_THICK_1	0x00
+#define BT431_CMD_THICK_3	0x01
+#define BT431_CMD_THICK_5	0x02
+#define BT431_CMD_THICK_7	0x03
+
+static inline void bt431_select_reg(struct bt431_regs *regs, int ir)
+{
+	/*
+	 * The compiler splits the write in two bytes without these
+	 * helper variables.
+	 */
+	volatile u16 *lo = &(regs->addr_lo);
+	volatile u16 *hi = &(regs->addr_hi);
+
+	mb();
+	*lo = bt431_set_value(ir & 0xff);
+	wmb();
+	*hi = bt431_set_value((ir >> 8) & 0xff);
+}
+
+/* Autoincrement read/write. */
+static inline u8 bt431_read_reg_inc(struct bt431_regs *regs)
+{
+	/*
+	 * The compiler splits the write in two bytes without the
+	 * helper variable.
+	 */
+	volatile u16 *r = &(regs->addr_reg);
+
+	mb();
+	return bt431_get_value(*r);
+}
+
+static inline void bt431_write_reg_inc(struct bt431_regs *regs, u8 value)
+{
+	/*
+	 * The compiler splits the write in two bytes without the
+	 * helper variable.
+	 */
+	volatile u16 *r = &(regs->addr_reg);
+
+	mb();
+	*r = bt431_set_value(value);
+}
+
+static inline u8 bt431_read_reg(struct bt431_regs *regs, int ir)
+{
+	bt431_select_reg(regs, ir);
+	return bt431_read_reg_inc(regs);
+}
+
+static inline void bt431_write_reg(struct bt431_regs *regs, int ir, u8 value)
+{
+	bt431_select_reg(regs, ir);
+	bt431_write_reg_inc(regs, value);
+}
+
+/* Autoincremented read/write for the cursor map. */
+static inline u16 bt431_read_cmap_inc(struct bt431_regs *regs)
+{
+	/*
+	 * The compiler splits the write in two bytes without the
+	 * helper variable.
+	 */
+	volatile u16 *r = &(regs->addr_cmap);
+
+	mb();
+	return *r;
+}
+
+static inline void bt431_write_cmap_inc(struct bt431_regs *regs, u16 value)
+{
+	/*
+	 * The compiler splits the write in two bytes without the
+	 * helper variable.
+	 */
+	volatile u16 *r = &(regs->addr_cmap);
+
+	mb();
+	*r = value;
+}
+
+static inline u16 bt431_read_cmap(struct bt431_regs *regs, int cr)
+{
+	bt431_select_reg(regs, cr);
+	return bt431_read_cmap_inc(regs);
+}
+
+static inline void bt431_write_cmap(struct bt431_regs *regs, int cr, u16 value)
+{
+	bt431_select_reg(regs, cr);
+	bt431_write_cmap_inc(regs, value);
+}
+
+static inline void bt431_enable_cursor(struct bt431_regs *regs)
+{
+	bt431_write_reg(regs, BT431_REG_CMD,
+			BT431_CMD_CURS_ENABLE | BT431_CMD_OR_CURSORS
+			| BT431_CMD_4_1_MUX | BT431_CMD_THICK_1);
+}
+
+static inline void bt431_erase_cursor(struct bt431_regs *regs)
+{
+	bt431_write_reg(regs, BT431_REG_CMD, BT431_CMD_4_1_MUX);
+}
+
+static inline void bt431_position_cursor(struct bt431_regs *regs, u16 x, u16 y)
+{
+	/*
+	 * Magic from the MACH sources.
+	 *
+	 * Cx = x + D + H - P
+	 *  P = 37 if 1:1, 52 if 4:1, 57 if 5:1
+	 *  D = pixel skew between outdata and external data
+	 *  H = pixels between HSYNCH falling and active video
+	 *
+	 * Cy = y + V - 32
+	 *  V = scanlines between HSYNCH falling, two or more
+	 *      clocks after VSYNCH falling, and active video
+	 */
+	x += 412 - 52;
+	y += 68 - 32;
+
+	/* Use autoincrement. */
+	bt431_select_reg(regs, BT431_REG_CXLO);
+	bt431_write_reg_inc(regs, x & 0xff); /* BT431_REG_CXLO */
+	bt431_write_reg_inc(regs, (x >> 8) & 0x0f); /* BT431_REG_CXHI */
+	bt431_write_reg_inc(regs, y & 0xff); /* BT431_REG_CYLO */
+	bt431_write_reg_inc(regs, (y >> 8) & 0x0f); /* BT431_REG_CYHI */
+}
+
+static inline void bt431_set_font(struct bt431_regs *regs, u8 fgc,
+				  u16 width, u16 height)
+{
+	int i;
+	u16 fgp = fgc ? 0xffff : 0x0000;
+	u16 bgp = fgc ? 0x0000 : 0xffff;
+
+	bt431_select_reg(regs, BT431_REG_CRAM_BASE);
+	for (i = BT431_REG_CRAM_BASE; i <= BT431_REG_CRAM_END; i++) {
+		u16 value;
+
+		if (height << 6 <= i << 3)
+			value = bgp;
+		else if (width <= i % 8 << 3)
+			value = bgp;
+		else if (((width >> 3) & 0xffff) > i % 8)
+			value = fgp;
+		else
+			value = fgp & ~(bgp << (width % 8 << 1));
+
+		bt431_write_cmap_inc(regs, value);
+	}
+}
+
+static inline void bt431_init_cursor(struct bt431_regs *regs)
+{
+	/* no crosshair window */
+	bt431_select_reg(regs, BT431_REG_WXLO);
+	bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WXLO */
+	bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WXHI */
+	bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WYLO */
+	bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WYHI */
+	bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WWLO */
+	bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WWHI */
+	bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WHLO */
+	bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WHHI */
+}
diff --git a/drivers/video/bt455.h b/drivers/video/bt455.h
new file mode 100644
index 0000000..b7591fe
--- /dev/null
+++ b/drivers/video/bt455.h
@@ -0,0 +1,95 @@
+/*
+ *	linux/drivers/video/bt455.h
+ *
+ *	Copyright 2003  Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de>
+ *
+ *	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/types.h>
+#include <asm/system.h>
+
+/*
+ * Bt455 byte-wide registers, 32-bit aligned.
+ */
+struct bt455_regs {
+	volatile u8 addr_cmap;
+	u8 pad0[3];
+	volatile u8 addr_cmap_data;
+	u8 pad1[3];
+	volatile u8 addr_clr;
+	u8 pad2[3];
+	volatile u8 addr_ovly;
+	u8 pad3[3];
+};
+
+static inline void bt455_select_reg(struct bt455_regs *regs, int ir)
+{
+	mb();
+	regs->addr_cmap = ir & 0x0f;
+}
+
+/*
+ * Read/write to a Bt455 color map register.
+ */
+static inline void bt455_read_cmap_entry(struct bt455_regs *regs, int cr,
+					 u8* red, u8* green, u8* blue)
+{
+	bt455_select_reg(regs, cr);
+	mb();
+	*red = regs->addr_cmap_data & 0x0f;
+	rmb();
+	*green = regs->addr_cmap_data & 0x0f;
+	rmb();
+	*blue = regs->addr_cmap_data & 0x0f;
+}
+
+static inline void bt455_write_cmap_entry(struct bt455_regs *regs, int cr,
+					  u8 red, u8 green, u8 blue)
+{
+	bt455_select_reg(regs, cr);
+	wmb();
+	regs->addr_cmap_data = red & 0x0f;
+	wmb();
+	regs->addr_cmap_data = green & 0x0f;
+	wmb();
+	regs->addr_cmap_data = blue & 0x0f;
+}
+
+static inline void bt455_write_ovly_entry(struct bt455_regs *regs, int cr,
+					  u8 red, u8 green, u8 blue)
+{
+	bt455_select_reg(regs, cr);
+	wmb();
+	regs->addr_ovly = red & 0x0f;
+	wmb();
+	regs->addr_ovly = green & 0x0f;
+	wmb();
+	regs->addr_ovly = blue & 0x0f;
+}
+
+static inline void bt455_set_cursor(struct bt455_regs *regs)
+{
+	mb();
+	regs->addr_ovly = 0x0f;
+	wmb();
+	regs->addr_ovly = 0x0f;
+	wmb();
+	regs->addr_ovly = 0x0f;
+}
+
+static inline void bt455_erase_cursor(struct bt455_regs *regs)
+{
+	/* bt455_write_cmap_entry(regs, 8, 0x00, 0x00, 0x00); */
+	/* bt455_write_cmap_entry(regs, 9, 0x00, 0x00, 0x00); */
+	bt455_write_ovly_entry(regs, 8, 0x03, 0x03, 0x03);
+	bt455_write_ovly_entry(regs, 9, 0x07, 0x07, 0x07);
+
+	wmb();
+	regs->addr_ovly = 0x09;
+	wmb();
+	regs->addr_ovly = 0x09;
+	wmb();
+	regs->addr_ovly = 0x09;
+}
diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c
new file mode 100644
index 0000000..3d20b2d
--- /dev/null
+++ b/drivers/video/bw2.c
@@ -0,0 +1,428 @@
+/* bw2.c: BWTWO frame buffer driver
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ *
+ * Driver layout based loosely on tgafb.c, see that file for credits.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/mm.h>
+
+#include <asm/io.h>
+#include <asm/sbus.h>
+#include <asm/oplib.h>
+#include <asm/fbio.h>
+
+#ifdef CONFIG_SPARC32
+#include <asm/sun4paddr.h>
+#endif
+
+#include "sbuslib.h"
+
+/*
+ * Local functions.
+ */
+
+static int bw2_blank(int, struct fb_info *);
+
+static int bw2_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
+static int bw2_ioctl(struct inode *, struct file *, unsigned int,
+		     unsigned long, struct fb_info *);
+
+/*
+ *  Frame buffer operations
+ */
+
+static struct fb_ops bw2_ops = {
+	.owner			= THIS_MODULE,
+	.fb_blank		= bw2_blank,
+	.fb_fillrect		= cfb_fillrect,
+	.fb_copyarea		= cfb_copyarea,
+	.fb_imageblit		= cfb_imageblit,
+	.fb_mmap		= bw2_mmap,
+	.fb_ioctl		= bw2_ioctl,
+	.fb_cursor		= soft_cursor,
+};
+
+/* OBio addresses for the bwtwo registers */
+#define BWTWO_REGISTER_OFFSET 0x400000
+
+struct bt_regs {
+	volatile u32 addr;
+	volatile u32 color_map;
+	volatile u32 control;
+	volatile u32 cursor;
+};
+
+struct bw2_regs {
+	struct bt_regs	cmap;
+	volatile u8	control;
+	volatile u8	status;
+	volatile u8	cursor_start;
+	volatile u8	cursor_end;
+	volatile u8	h_blank_start;
+	volatile u8	h_blank_end;
+	volatile u8	h_sync_start;
+	volatile u8	h_sync_end;
+	volatile u8	comp_sync_end;
+	volatile u8	v_blank_start_high;
+	volatile u8	v_blank_start_low;
+	volatile u8	v_blank_end;
+	volatile u8	v_sync_start;
+	volatile u8	v_sync_end;
+	volatile u8	xfer_holdoff_start;
+	volatile u8	xfer_holdoff_end;
+};
+
+/* Status Register Constants */
+#define BWTWO_SR_RES_MASK	0x70
+#define BWTWO_SR_1600_1280	0x50
+#define BWTWO_SR_1152_900_76_A	0x40
+#define BWTWO_SR_1152_900_76_B	0x60
+#define BWTWO_SR_ID_MASK	0x0f
+#define BWTWO_SR_ID_MONO	0x02
+#define BWTWO_SR_ID_MONO_ECL	0x03
+#define BWTWO_SR_ID_MSYNC	0x04
+#define BWTWO_SR_ID_NOCONN	0x0a
+
+/* Control Register Constants */
+#define BWTWO_CTL_ENABLE_INTS   0x80
+#define BWTWO_CTL_ENABLE_VIDEO  0x40
+#define BWTWO_CTL_ENABLE_TIMING 0x20
+#define BWTWO_CTL_ENABLE_CURCMP 0x10
+#define BWTWO_CTL_XTAL_MASK     0x0C
+#define BWTWO_CTL_DIVISOR_MASK  0x03
+
+/* Status Register Constants */
+#define BWTWO_STAT_PENDING_INT  0x80
+#define BWTWO_STAT_MSENSE_MASK  0x70
+#define BWTWO_STAT_ID_MASK      0x0f
+
+struct bw2_par {
+	spinlock_t		lock;
+	struct bw2_regs		__iomem *regs;
+
+	u32			flags;
+#define BW2_FLAG_BLANKED	0x00000001
+
+	unsigned long		physbase;
+	unsigned long		fbsize;
+
+	struct sbus_dev		*sdev;
+	struct list_head	list;
+};
+
+/**
+ *      bw2_blank - Optional function.  Blanks the display.
+ *      @blank_mode: the blank mode we want.
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+bw2_blank(int blank, struct fb_info *info)
+{
+	struct bw2_par *par = (struct bw2_par *) info->par;
+	struct bw2_regs __iomem *regs = par->regs;
+	unsigned long flags;
+	u8 val;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	switch (blank) {
+	case FB_BLANK_UNBLANK: /* Unblanking */
+		val = sbus_readb(&regs->control);
+		val |= BWTWO_CTL_ENABLE_VIDEO;
+		sbus_writeb(val, &regs->control);
+		par->flags &= ~BW2_FLAG_BLANKED;
+		break;
+
+	case FB_BLANK_NORMAL: /* Normal blanking */
+	case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
+	case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
+	case FB_BLANK_POWERDOWN: /* Poweroff */
+		val = sbus_readb(&regs->control);
+		val &= ~BWTWO_CTL_ENABLE_VIDEO;
+		sbus_writeb(val, &regs->control);
+		par->flags |= BW2_FLAG_BLANKED;
+		break;
+	}
+
+	spin_unlock_irqrestore(&par->lock, flags);
+
+	return 0;
+}
+
+static struct sbus_mmap_map bw2_mmap_map[] = {
+	{
+		.size = SBUS_MMAP_FBSIZE(1)
+	},
+	{ .size = 0 }
+};
+
+static int bw2_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+{
+	struct bw2_par *par = (struct bw2_par *)info->par;
+
+	return sbusfb_mmap_helper(bw2_mmap_map,
+				  par->physbase, par->fbsize,
+				  (par->sdev ?
+				   par->sdev->reg_addrs[0].which_io :
+				   0),
+				  vma);
+}
+
+static int bw2_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		     unsigned long arg, struct fb_info *info)
+{
+	struct bw2_par *par = (struct bw2_par *) info->par;
+
+	return sbusfb_ioctl_helper(cmd, arg, info,
+				   FBTYPE_SUN2BW, 1, par->fbsize);
+}
+
+/*
+ *  Initialisation
+ */
+
+static void
+bw2_init_fix(struct fb_info *info, int linebytes)
+{
+	strlcpy(info->fix.id, "bwtwo", sizeof(info->fix.id));
+
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.visual = FB_VISUAL_MONO01;
+
+	info->fix.line_length = linebytes;
+
+	info->fix.accel = FB_ACCEL_SUN_BWTWO;
+}
+
+static u8 bw2regs_1600[] __initdata = {
+	0x14, 0x8b,	0x15, 0x28,	0x16, 0x03,	0x17, 0x13,
+	0x18, 0x7b,	0x19, 0x05,	0x1a, 0x34,	0x1b, 0x2e,
+	0x1c, 0x00,	0x1d, 0x0a,	0x1e, 0xff,	0x1f, 0x01,
+	0x10, 0x21,	0
+};
+
+static u8 bw2regs_ecl[] __initdata = {
+	0x14, 0x65,	0x15, 0x1e,	0x16, 0x04,	0x17, 0x0c,
+	0x18, 0x5e,	0x19, 0x03,	0x1a, 0xa7,	0x1b, 0x23,
+	0x1c, 0x00,	0x1d, 0x08,	0x1e, 0xff,	0x1f, 0x01,
+	0x10, 0x20,	0
+};
+
+static u8 bw2regs_analog[] __initdata = {
+	0x14, 0xbb,	0x15, 0x2b,	0x16, 0x03,	0x17, 0x13,
+	0x18, 0xb0,	0x19, 0x03,	0x1a, 0xa6,	0x1b, 0x22,
+	0x1c, 0x01,	0x1d, 0x05,	0x1e, 0xff,	0x1f, 0x01,
+	0x10, 0x20,	0
+};
+
+static u8 bw2regs_76hz[] __initdata = {
+	0x14, 0xb7,	0x15, 0x27,	0x16, 0x03,	0x17, 0x0f,
+	0x18, 0xae,	0x19, 0x03,	0x1a, 0xae,	0x1b, 0x2a,
+	0x1c, 0x01,	0x1d, 0x09,	0x1e, 0xff,	0x1f, 0x01,
+	0x10, 0x24,	0
+};
+
+static u8 bw2regs_66hz[] __initdata = {
+	0x14, 0xbb,	0x15, 0x2b,	0x16, 0x04,	0x17, 0x14,
+	0x18, 0xae,	0x19, 0x03,	0x1a, 0xa8,	0x1b, 0x24,
+	0x1c, 0x01,	0x1d, 0x05,	0x1e, 0xff,	0x1f, 0x01,
+	0x10, 0x20,	0
+};
+
+static void bw2_do_default_mode(struct bw2_par *par, struct fb_info *info,
+				int *linebytes)
+{
+	u8 status, mon;
+	u8 *p;
+
+	status = sbus_readb(&par->regs->status);
+	mon = status & BWTWO_SR_RES_MASK;
+	switch (status & BWTWO_SR_ID_MASK) {
+	case BWTWO_SR_ID_MONO_ECL:
+		if (mon == BWTWO_SR_1600_1280) {
+			p = bw2regs_1600;
+			info->var.xres = info->var.xres_virtual = 1600;
+			info->var.yres = info->var.yres_virtual = 1280;
+			*linebytes = 1600 / 8;
+		} else
+			p = bw2regs_ecl;
+		break;
+
+	case BWTWO_SR_ID_MONO:
+		p = bw2regs_analog;
+		break;
+
+	case BWTWO_SR_ID_MSYNC:
+		if (mon == BWTWO_SR_1152_900_76_A ||
+		    mon == BWTWO_SR_1152_900_76_B)
+			p = bw2regs_76hz;
+		else
+			p = bw2regs_66hz;
+		break;
+
+	case BWTWO_SR_ID_NOCONN:
+		return;
+
+	default:
+		prom_printf("bw2: can't handle SR %02x\n",
+			    status);
+		prom_halt();
+	}
+	for ( ; *p; p += 2) {
+		u8 __iomem *regp = &((u8 __iomem *)par->regs)[p[0]];
+		sbus_writeb(p[1], regp);
+	}
+}
+
+struct all_info {
+	struct fb_info info;
+	struct bw2_par par;
+	struct list_head list;
+};
+static LIST_HEAD(bw2_list);
+
+static void bw2_init_one(struct sbus_dev *sdev)
+{
+	struct all_info *all;
+	struct resource *resp;
+#ifdef CONFIG_SUN4
+	struct resource res;
+#endif
+	int linebytes;
+
+	all = kmalloc(sizeof(*all), GFP_KERNEL);
+	if (!all) {
+		printk(KERN_ERR "bw2: Cannot allocate memory.\n");
+		return;
+	}
+	memset(all, 0, sizeof(*all));
+
+	INIT_LIST_HEAD(&all->list);
+
+	spin_lock_init(&all->par.lock);
+	all->par.sdev = sdev;
+
+#ifdef CONFIG_SUN4
+	if (!sdev) {
+		all->par.physbase = sun4_bwtwo_physaddr;
+		res.start = sun4_bwtwo_physaddr;
+		res.end = res.start + BWTWO_REGISTER_OFFSET + sizeof(struct bw2_regs) - 1;
+		res.flags = IORESOURCE_IO;
+		resp = &res;
+		all->info.var.xres = all->info.var.xres_virtual = 1152;
+		all->info.var.yres = all->info.var.yres_virtual = 900;
+		all->info.var.bits_per_pixel = 1;
+		linebytes = 1152 / 8;
+	} else
+#else
+	{
+		if (!sdev)
+			BUG();
+		all->par.physbase = sdev->reg_addrs[0].phys_addr;
+		resp = &sdev->resource[0];
+		sbusfb_fill_var(&all->info.var, (sdev ? sdev->prom_node : 0), 1);
+		linebytes = prom_getintdefault(sdev->prom_node, "linebytes",
+					       all->info.var.xres);
+	}
+#endif
+	all->info.var.red.length = all->info.var.green.length =
+		all->info.var.blue.length = all->info.var.bits_per_pixel;
+	all->info.var.red.offset = all->info.var.green.offset =
+		all->info.var.blue.offset = 0;
+
+	all->par.regs = sbus_ioremap(resp, BWTWO_REGISTER_OFFSET,
+			     sizeof(struct bw2_regs), "bw2 regs");
+
+	if (sdev && !prom_getbool(sdev->prom_node, "width"))
+		bw2_do_default_mode(&all->par, &all->info, &linebytes);
+
+	all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
+
+	all->info.flags = FBINFO_DEFAULT;
+	all->info.fbops = &bw2_ops;
+#if defined(CONFIG_SPARC32)
+	if (sdev)
+		all->info.screen_base = (char __iomem *)
+			prom_getintdefault(sdev->prom_node, "address", 0);
+#endif
+	if (!all->info.screen_base)
+		all->info.screen_base =
+			sbus_ioremap(resp, 0, all->par.fbsize, "bw2 ram");
+	all->info.par = &all->par;
+
+	bw2_blank(0, &all->info);
+
+	bw2_init_fix(&all->info, linebytes);
+
+	if (register_framebuffer(&all->info) < 0) {
+		printk(KERN_ERR "bw2: Could not register framebuffer.\n");
+		kfree(all);
+		return;
+	}
+
+	list_add(&all->list, &bw2_list);
+
+	printk("bw2: bwtwo at %lx:%lx\n",
+	       (long) (sdev ? sdev->reg_addrs[0].which_io : 0),
+	       (long) all->par.physbase);
+}
+
+int __init bw2_init(void)
+{
+	struct sbus_bus *sbus;
+	struct sbus_dev *sdev;
+
+	if (fb_get_options("bw2fb", NULL))
+		return -ENODEV;
+
+#ifdef CONFIG_SUN4
+	bw2_init_one(NULL);
+#endif
+	for_all_sbusdev(sdev, sbus) {
+		if (!strcmp(sdev->prom_name, "bwtwo"))
+			bw2_init_one(sdev);
+	}
+
+	return 0;
+}
+
+void __exit bw2_exit(void)
+{
+	struct list_head *pos, *tmp;
+
+	list_for_each_safe(pos, tmp, &bw2_list) {
+		struct all_info *all = list_entry(pos, typeof(*all), list);
+
+		unregister_framebuffer(&all->info);
+		kfree(all);
+	}
+}
+
+int __init
+bw2_setup(char *arg)
+{
+	/* No cmdline options yet... */
+	return 0;
+}
+
+module_init(bw2_init);
+
+#ifdef MODULE
+module_exit(bw2_exit);
+#endif
+
+MODULE_DESCRIPTION("framebuffer driver for BWTWO chipsets");
+MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/c2p.c b/drivers/video/c2p.c
new file mode 100644
index 0000000..5c30bbd
--- /dev/null
+++ b/drivers/video/c2p.c
@@ -0,0 +1,229 @@
+/*
+ *  Fast C2P (Chunky-to-Planar) Conversion
+ *
+ *  Copyright (C) 2003 Geert Uytterhoeven
+ *
+ *  NOTES:
+ *    - This code was inspired by Scout's C2P tutorial
+ *    - It assumes to run on a big endian system
+ *
+ *  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/string.h>
+#include "c2p.h"
+
+
+    /*
+     *  Basic transpose step
+     */
+
+#define _transp(d, i1, i2, shift, mask)			\
+    do {						\
+	u32 t = (d[i1] ^ (d[i2] >> shift)) & mask;	\
+	d[i1] ^= t;					\
+	d[i2] ^= t << shift;				\
+    } while (0)
+
+static inline u32 get_mask(int n)
+{
+    switch (n) {
+	case 1:
+	    return 0x55555555;
+	    break;
+
+	case 2:
+	    return 0x33333333;
+	    break;
+
+	case 4:
+	    return 0x0f0f0f0f;
+	    break;
+
+	case 8:
+	    return 0x00ff00ff;
+	    break;
+
+	case 16:
+	    return 0x0000ffff;
+	    break;
+    }
+    return 0;
+}
+
+#define transp_nx1(d, n)				\
+    do {						\
+	u32 mask = get_mask(n);				\
+	/* First block */				\
+	_transp(d, 0, 1, n, mask);			\
+	/* Second block */				\
+	_transp(d, 2, 3, n, mask);			\
+	/* Third block */				\
+	_transp(d, 4, 5, n, mask);			\
+	/* Fourth block */				\
+	_transp(d, 6, 7, n, mask);			\
+    } while (0)
+
+#define transp_nx2(d, n)				\
+    do {						\
+	u32 mask = get_mask(n);				\
+	/* First block */				\
+	_transp(d, 0, 2, n, mask);			\
+	_transp(d, 1, 3, n, mask);			\
+	/* Second block */				\
+	_transp(d, 4, 6, n, mask);			\
+	_transp(d, 5, 7, n, mask);			\
+    } while (0)
+
+#define transp_nx4(d, n)				\
+    do {						\
+	u32 mask = get_mask(n);				\
+	_transp(d, 0, 4, n, mask);			\
+	_transp(d, 1, 5, n, mask);			\
+	_transp(d, 2, 6, n, mask);			\
+	_transp(d, 3, 7, n, mask);			\
+    } while (0)
+
+#define transp(d, n, m)	transp_nx ## m(d, n)
+
+
+    /*
+     *  Perform a full C2P step on 32 8-bit pixels, stored in 8 32-bit words
+     *  containing
+     *    - 32 8-bit chunky pixels on input
+     *    - permuted planar data on output
+     */
+
+static void c2p_8bpp(u32 d[8])
+{
+    transp(d, 16, 4);
+    transp(d, 8, 2);
+    transp(d, 4, 1);
+    transp(d, 2, 4);
+    transp(d, 1, 2);
+}
+
+
+    /*
+     *  Array containing the permution indices of the planar data after c2p
+     */
+
+static const int perm_c2p_8bpp[8] = { 7, 5, 3, 1, 6, 4, 2, 0 };
+
+
+    /*
+     *  Compose two values, using a bitmask as decision value
+     *  This is equivalent to (a & mask) | (b & ~mask)
+     */
+
+static inline unsigned long comp(unsigned long a, unsigned long b,
+				 unsigned long mask)
+{
+	return ((a ^ b) & mask) ^ b;
+}
+
+
+    /*
+     *  Store a full block of planar data after c2p conversion
+     */
+
+static inline void store_planar(char *dst, u32 dst_inc, u32 bpp, u32 d[8])
+{
+    int i;
+
+    for (i = 0; i < bpp; i++, dst += dst_inc)
+	*(u32 *)dst = d[perm_c2p_8bpp[i]];
+}
+
+
+    /*
+     *  Store a partial block of planar data after c2p conversion
+     */
+
+static inline void store_planar_masked(char *dst, u32 dst_inc, u32 bpp,
+				       u32 d[8], u32 mask)
+{
+    int i;
+
+    for (i = 0; i < bpp; i++, dst += dst_inc)
+	*(u32 *)dst = comp(d[perm_c2p_8bpp[i]], *(u32 *)dst, mask);
+}
+
+
+    /*
+     *  c2p - Copy 8-bit chunky image data to a planar frame buffer
+     *  @dst: Starting address of the planar frame buffer
+     *  @dx: Horizontal destination offset (in pixels)
+     *  @dy: Vertical destination offset (in pixels)
+     *  @width: Image width (in pixels)
+     *  @height: Image height (in pixels)
+     *  @dst_nextline: Frame buffer offset to the next line (in bytes)
+     *  @dst_nextplane: Frame buffer offset to the next plane (in bytes)
+     *  @src_nextline: Image offset to the next line (in bytes)
+     *  @bpp: Bits per pixel of the planar frame buffer (1-8)
+     */
+
+void c2p(u8 *dst, const u8 *src, u32 dx, u32 dy, u32 width, u32 height,
+	 u32 dst_nextline, u32 dst_nextplane, u32 src_nextline, u32 bpp)
+{
+    int dst_idx;
+    u32 d[8], first, last, w;
+    const u8 *c;
+    u8 *p;
+
+    dst += dy*dst_nextline+(dx & ~31);
+    dst_idx = dx % 32;
+    first = ~0UL >> dst_idx;
+    last = ~(~0UL >> ((dst_idx+width) % 32));
+    while (height--) {
+	c = src;
+	p = dst;
+	w = width;
+	if (dst_idx+width <= 32) {
+	    /* Single destination word */
+	    first &= last;
+	    memset(d, 0, sizeof(d));
+	    memcpy((u8 *)d+dst_idx, c, width);
+	    c += width;
+	    c2p_8bpp(d);
+	    store_planar_masked(p, dst_nextplane, bpp, d, first);
+	    p += 4;
+	} else {
+	    /* Multiple destination words */
+	    w = width;
+	    /* Leading bits */
+	    if (dst_idx) {
+		w = 32 - dst_idx;
+		memset(d, 0, dst_idx);
+		memcpy((u8 *)d+dst_idx, c, w);
+		c += w;
+		c2p_8bpp(d);
+		store_planar_masked(p, dst_nextplane, bpp, d, first);
+		p += 4;
+		w = width-w;
+	    }
+	    /* Main chunk */
+	    while (w >= 32) {
+		memcpy(d, c, 32);
+		c += 32;
+		c2p_8bpp(d);
+		store_planar(p, dst_nextplane, bpp, d);
+		p += 4;
+		w -= 32;
+	    }
+	    /* Trailing bits */
+	    w %= 32;
+	    if (w > 0) {
+		memcpy(d, c, w);
+		memset((u8 *)d+w, 0, 32-w);
+		c2p_8bpp(d);
+		store_planar_masked(p, dst_nextplane, bpp, d, last);
+	    }
+	}
+	src += src_nextline;
+	dst += dst_nextline;
+    }
+}
+
diff --git a/drivers/video/c2p.h b/drivers/video/c2p.h
new file mode 100644
index 0000000..c77cbf1
--- /dev/null
+++ b/drivers/video/c2p.h
@@ -0,0 +1,16 @@
+/*
+ *  Fast C2P (Chunky-to-Planar) Conversion
+ *
+ *  Copyright (C) 2003 Geert Uytterhoeven
+ *
+ *  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/types.h>
+
+extern void c2p(u8 *dst, const u8 *src, u32 dx, u32 dy, u32 width, u32 height,
+		u32 dst_nextline, u32 dst_nextplane, u32 src_nextline,
+		u32 bpp);
+
diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c
new file mode 100644
index 0000000..67711f7
--- /dev/null
+++ b/drivers/video/cfbcopyarea.c
@@ -0,0 +1,441 @@
+/*
+ *  Generic function for frame buffer with packed pixels of any depth.
+ *
+ *      Copyright (C)  1999-2005 James Simmons <jsimmons@www.infradead.org>
+ *
+ *  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.
+ *
+ * NOTES:
+ *
+ *  This is for cfb packed pixels. Iplan and such are incorporated in the
+ *  drivers that need them.
+ *
+ *  FIXME
+ *
+ *  Also need to add code to deal with cards endians that are different than
+ *  the native cpu endians. I also need to deal with MSB position in the word.
+ *
+ *  The two functions or copying forward and backward could be split up like
+ *  the ones for filling, i.e. in aligned and unaligned versions. This would
+ *  help moving some redundant computations and branches out of the loop, too.
+ */
+
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <linux/slab.h>
+#include <asm/types.h>
+#include <asm/io.h>
+
+#if BITS_PER_LONG == 32
+#  define FB_WRITEL fb_writel
+#  define FB_READL  fb_readl
+#else
+#  define FB_WRITEL fb_writeq
+#  define FB_READL  fb_readq
+#endif
+
+    /*
+     *  Compose two values, using a bitmask as decision value
+     *  This is equivalent to (a & mask) | (b & ~mask)
+     */
+
+static inline unsigned long
+comp(unsigned long a, unsigned long b, unsigned long mask)
+{
+    return ((a ^ b) & mask) ^ b;
+}
+
+    /*
+     *  Generic bitwise copy algorithm
+     */
+
+static void
+bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src,
+	int src_idx, int bits, unsigned n)
+{
+	unsigned long first, last;
+	int const shift = dst_idx-src_idx;
+	int left, right;
+
+	first = ~0UL >> dst_idx;
+	last = ~(~0UL >> ((dst_idx+n) % bits));
+
+	if (!shift) {
+		// Same alignment for source and dest
+
+		if (dst_idx+n <= bits) {
+			// Single word
+			if (last)
+				first &= last;
+			FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
+		} else {
+			// Multiple destination words
+
+			// Leading bits
+			if (first != ~0UL) {
+				FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
+				dst++;
+				src++;
+				n -= bits - dst_idx;
+			}
+
+			// Main chunk
+			n /= bits;
+			while (n >= 8) {
+				FB_WRITEL(FB_READL(src++), dst++);
+				FB_WRITEL(FB_READL(src++), dst++);
+				FB_WRITEL(FB_READL(src++), dst++);
+				FB_WRITEL(FB_READL(src++), dst++);
+				FB_WRITEL(FB_READL(src++), dst++);
+				FB_WRITEL(FB_READL(src++), dst++);
+				FB_WRITEL(FB_READL(src++), dst++);
+				FB_WRITEL(FB_READL(src++), dst++);
+				n -= 8;
+			}
+			while (n--)
+				FB_WRITEL(FB_READL(src++), dst++);
+
+			// Trailing bits
+			if (last)
+				FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
+		}
+	} else {
+		unsigned long d0, d1;
+		int m;
+		// Different alignment for source and dest
+
+		right = shift & (bits - 1);
+		left = -shift & (bits - 1);
+
+		if (dst_idx+n <= bits) {
+			// Single destination word
+			if (last)
+				first &= last;
+			if (shift > 0) {
+				// Single source word
+				FB_WRITEL( comp( FB_READL(src) >> right, FB_READL(dst), first), dst);
+			} else if (src_idx+n <= bits) {
+				// Single source word
+				FB_WRITEL( comp(FB_READL(src) << left, FB_READL(dst), first), dst);
+			} else {
+				// 2 source words
+				d0 = FB_READL(src++);
+				d1 = FB_READL(src);
+				FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), first), dst);
+			}
+		} else {
+			// Multiple destination words
+			/** We must always remember the last value read, because in case
+			SRC and DST overlap bitwise (e.g. when moving just one pixel in
+			1bpp), we always collect one full long for DST and that might
+			overlap with the current long from SRC. We store this value in
+			'd0'. */
+			d0 = FB_READL(src++);
+			// Leading bits
+			if (shift > 0) {
+				// Single source word
+				FB_WRITEL( comp(d0 >> right, FB_READL(dst), first), dst);
+				dst++;
+				n -= bits - dst_idx;
+			} else {
+				// 2 source words
+				d1 = FB_READL(src++);
+				FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), first), dst);
+				d0 = d1;
+				dst++;
+				n -= bits - dst_idx;
+			}
+
+			// Main chunk
+			m = n % bits;
+			n /= bits;
+			while (n >= 4) {
+				d1 = FB_READL(src++);
+				FB_WRITEL(d0 << left | d1 >> right, dst++);
+				d0 = d1;
+				d1 = FB_READL(src++);
+				FB_WRITEL(d0 << left | d1 >> right, dst++);
+				d0 = d1;
+				d1 = FB_READL(src++);
+				FB_WRITEL(d0 << left | d1 >> right, dst++);
+				d0 = d1;
+				d1 = FB_READL(src++);
+				FB_WRITEL(d0 << left | d1 >> right, dst++);
+				d0 = d1;
+				n -= 4;
+			}
+			while (n--) {
+				d1 = FB_READL(src++);
+				FB_WRITEL(d0 << left | d1 >> right, dst++);
+				d0 = d1;
+			}
+
+			// Trailing bits
+			if (last) {
+				if (m <= right) {
+					// Single source word
+					FB_WRITEL( comp(d0 << left, FB_READL(dst), last), dst);
+				} else {
+					// 2 source words
+					d1 = FB_READL(src);
+					FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), last), dst);
+				}
+			}
+		}
+	}
+}
+
+    /*
+     *  Generic bitwise copy algorithm, operating backward
+     */
+
+static void
+bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src,
+		int src_idx, int bits, unsigned n)
+{
+	unsigned long first, last;
+	int shift;
+
+	dst += (n-1)/bits;
+	src += (n-1)/bits;
+	if ((n-1) % bits) {
+		dst_idx += (n-1) % bits;
+		dst += dst_idx >> (ffs(bits) - 1);
+		dst_idx &= bits - 1;
+		src_idx += (n-1) % bits;
+		src += src_idx >> (ffs(bits) - 1);
+		src_idx &= bits - 1;
+	}
+
+	shift = dst_idx-src_idx;
+
+	first = ~0UL << (bits - 1 - dst_idx);
+	last = ~(~0UL << (bits - 1 - ((dst_idx-n) % bits)));
+
+	if (!shift) {
+		// Same alignment for source and dest
+
+		if ((unsigned long)dst_idx+1 >= n) {
+			// Single word
+			if (last)
+				first &= last;
+			FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
+		} else {
+			// Multiple destination words
+
+			// Leading bits
+			if (first != ~0UL) {
+				FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
+				dst--;
+				src--;
+				n -= dst_idx+1;
+			}
+
+			// Main chunk
+			n /= bits;
+			while (n >= 8) {
+				FB_WRITEL(FB_READL(src--), dst--);
+				FB_WRITEL(FB_READL(src--), dst--);
+				FB_WRITEL(FB_READL(src--), dst--);
+				FB_WRITEL(FB_READL(src--), dst--);
+				FB_WRITEL(FB_READL(src--), dst--);
+				FB_WRITEL(FB_READL(src--), dst--);
+				FB_WRITEL(FB_READL(src--), dst--);
+				FB_WRITEL(FB_READL(src--), dst--);
+				n -= 8;
+			}
+			while (n--)
+				FB_WRITEL(FB_READL(src--), dst--);
+
+			// Trailing bits
+			if (last)
+				FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
+		}
+	} else {
+		// Different alignment for source and dest
+
+		int const left = -shift & (bits-1);
+		int const right = shift & (bits-1);
+
+		if ((unsigned long)dst_idx+1 >= n) {
+			// Single destination word
+			if (last)
+				first &= last;
+			if (shift < 0) {
+				// Single source word
+				FB_WRITEL( comp( FB_READL(src)<<left, FB_READL(dst), first), dst);
+			} else if (1+(unsigned long)src_idx >= n) {
+				// Single source word
+				FB_WRITEL( comp( FB_READL(src)>>right, FB_READL(dst), first), dst);
+			} else {
+				// 2 source words
+				FB_WRITEL( comp( (FB_READL(src)>>right | FB_READL(src-1)<<left), FB_READL(dst), first), dst);
+			}
+		} else {
+			// Multiple destination words
+			/** We must always remember the last value read, because in case
+			SRC and DST overlap bitwise (e.g. when moving just one pixel in
+			1bpp), we always collect one full long for DST and that might
+			overlap with the current long from SRC. We store this value in
+			'd0'. */
+			unsigned long d0, d1;
+			int m;
+
+			d0 = FB_READL(src--);
+			// Leading bits
+			if (shift < 0) {
+				// Single source word
+				FB_WRITEL( comp( (d0 << left), FB_READL(dst), first), dst);
+			} else {
+				// 2 source words
+				d1 = FB_READL(src--);
+				FB_WRITEL( comp( (d0>>right | d1<<left), FB_READL(dst), first), dst);
+				d0 = d1;
+			}
+			dst--;
+			n -= dst_idx+1;
+
+			// Main chunk
+			m = n % bits;
+			n /= bits;
+			while (n >= 4) {
+				d1 = FB_READL(src--);
+				FB_WRITEL(d0 >> right | d1 << left, dst--);
+				d0 = d1;
+				d1 = FB_READL(src--);
+				FB_WRITEL(d0 >> right | d1 << left, dst--);
+				d0 = d1;
+				d1 = FB_READL(src--);
+				FB_WRITEL(d0 >> right | d1 << left, dst--);
+				d0 = d1;
+				d1 = FB_READL(src--);
+				FB_WRITEL(d0 >> right | d1 << left, dst--);
+				d0 = d1;
+				n -= 4;
+			}
+			while (n--) {
+				d1 = FB_READL(src--);
+				FB_WRITEL(d0 >> right | d1 << left, dst--);
+				d0 = d1;
+			}
+
+			// Trailing bits
+			if (last) {
+				if (m <= left) {
+					// Single source word
+					FB_WRITEL( comp(d0 >> right, FB_READL(dst), last), dst);
+				} else {
+					// 2 source words
+					d1 = FB_READL(src);
+					FB_WRITEL( comp(d0>>right | d1<<left, FB_READL(dst), last), dst);
+				}
+			}
+		}
+	}
+}
+
+void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
+{
+	u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
+	u32 height = area->height, width = area->width;
+	unsigned long const bits_per_line = p->fix.line_length*8u;
+	unsigned long __iomem *dst = NULL, *src = NULL;
+	int bits = BITS_PER_LONG, bytes = bits >> 3;
+	int dst_idx = 0, src_idx = 0, rev_copy = 0;
+	int x2, y2, vxres, vyres;
+
+	if (p->state != FBINFO_STATE_RUNNING)
+		return;
+
+	/* We want rotation but lack hardware to do it for us. */
+	if (!p->fbops->fb_rotate && p->var.rotate) {
+	}
+
+	vxres = p->var.xres_virtual;
+	vyres = p->var.yres_virtual;
+
+	if (area->dx > vxres || area->sx > vxres ||
+	    area->dy > vyres || area->sy > vyres)
+		return;
+
+	/* clip the destination
+	 * We could use hardware clipping but on many cards you get around
+	 * hardware clipping by writing to framebuffer directly.
+	 */
+	x2 = area->dx + area->width;
+	y2 = area->dy + area->height;
+	dx = area->dx > 0 ? area->dx : 0;
+	dy = area->dy > 0 ? area->dy : 0;
+	x2 = x2 < vxres ? x2 : vxres;
+	y2 = y2 < vyres ? y2 : vyres;
+	width = x2 - dx;
+	height = y2 - dy;
+
+	if ((width==0) ||(height==0))
+		return;
+
+	/* update sx1,sy1 */
+	sx += (dx - area->dx);
+	sy += (dy - area->dy);
+
+	/* the source must be completely inside the virtual screen */
+	if (sx < 0 || sy < 0 || (sx + width) > vxres || (sy + height) > vyres)
+		return;
+
+	/* if the beginning of the target area might overlap with the end of
+	the source area, be have to copy the area reverse. */
+	if ((dy == sy && dx > sx) || (dy > sy)) {
+		dy += height;
+		sy += height;
+		rev_copy = 1;
+	}
+
+	// split the base of the framebuffer into a long-aligned address and the
+	// index of the first bit
+	dst = src = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
+	dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
+	// add offset of source and target area
+	dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
+	src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
+
+	if (p->fbops->fb_sync)
+		p->fbops->fb_sync(p);
+
+	if (rev_copy) {
+		while (height--) {
+			dst_idx -= bits_per_line;
+			src_idx -= bits_per_line;
+			dst += dst_idx >> (ffs(bits) - 1);
+			dst_idx &= (bytes - 1);
+			src += src_idx >> (ffs(bits) - 1);
+			src_idx &= (bytes - 1);
+			bitcpy_rev(dst, dst_idx, src, src_idx, bits,
+				width*p->var.bits_per_pixel);
+		}
+	} else {
+		while (height--) {
+			dst += dst_idx >> (ffs(bits) - 1);
+			dst_idx &= (bytes - 1);
+			src += src_idx >> (ffs(bits) - 1);
+			src_idx &= (bytes - 1);
+			bitcpy(dst, dst_idx, src, src_idx, bits,
+				width*p->var.bits_per_pixel);
+			dst_idx += bits_per_line;
+			src_idx += bits_per_line;
+		}
+	}
+}
+
+EXPORT_SYMBOL(cfb_copyarea);
+
+MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
+MODULE_DESCRIPTION("Generic software accelerated copyarea");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c
new file mode 100644
index 0000000..e4fc42b
--- /dev/null
+++ b/drivers/video/cfbfillrect.c
@@ -0,0 +1,454 @@
+/*
+ *  Generic fillrect for frame buffers with packed pixels of any depth.
+ *
+ *      Copyright (C)  2000 James Simmons (jsimmons@linux-fbdev.org)
+ *
+ *  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.
+ *
+ * NOTES:
+ *
+ *  The code for depths like 24 that don't have integer number of pixels per
+ *  long is broken and needs to be fixed. For now I turned these types of
+ *  mode off.
+ *
+ *  Also need to add code to deal with cards endians that are different than
+ *  the native cpu endians. I also need to deal with MSB position in the word.
+ *
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <asm/types.h>
+
+#if BITS_PER_LONG == 32
+#  define FB_WRITEL fb_writel
+#  define FB_READL  fb_readl
+#else
+#  define FB_WRITEL fb_writeq
+#  define FB_READL  fb_readq
+#endif
+
+    /*
+     *  Compose two values, using a bitmask as decision value
+     *  This is equivalent to (a & mask) | (b & ~mask)
+     */
+
+static inline unsigned long
+comp(unsigned long a, unsigned long b, unsigned long mask)
+{
+    return ((a ^ b) & mask) ^ b;
+}
+
+    /*
+     *  Create a pattern with the given pixel's color
+     */
+
+#if BITS_PER_LONG == 64
+static inline unsigned long
+pixel_to_pat( u32 bpp, u32 pixel)
+{
+	switch (bpp) {
+	case 1:
+		return 0xfffffffffffffffful*pixel;
+	case 2:
+		return 0x5555555555555555ul*pixel;
+	case 4:
+		return 0x1111111111111111ul*pixel;
+	case 8:
+		return 0x0101010101010101ul*pixel;
+	case 12:
+		return 0x0001001001001001ul*pixel;
+	case 16:
+		return 0x0001000100010001ul*pixel;
+	case 24:
+		return 0x0000000001000001ul*pixel;
+	case 32:
+		return 0x0000000100000001ul*pixel;
+	default:
+		panic("pixel_to_pat(): unsupported pixelformat\n");
+    }
+}
+#else
+static inline unsigned long
+pixel_to_pat( u32 bpp, u32 pixel)
+{
+	switch (bpp) {
+	case 1:
+		return 0xfffffffful*pixel;
+	case 2:
+		return 0x55555555ul*pixel;
+	case 4:
+		return 0x11111111ul*pixel;
+	case 8:
+		return 0x01010101ul*pixel;
+	case 12:
+		return 0x00001001ul*pixel;
+	case 16:
+		return 0x00010001ul*pixel;
+	case 24:
+		return 0x00000001ul*pixel;
+	case 32:
+		return 0x00000001ul*pixel;
+	default:
+		panic("pixel_to_pat(): unsupported pixelformat\n");
+    }
+}
+#endif
+
+    /*
+     *  Aligned pattern fill using 32/64-bit memory accesses
+     */
+
+static void
+bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits)
+{
+	unsigned long first, last;
+
+	if (!n)
+		return;
+
+	first = ~0UL >> dst_idx;
+	last = ~(~0UL >> ((dst_idx+n) % bits));
+
+	if (dst_idx+n <= bits) {
+		// Single word
+		if (last)
+			first &= last;
+		FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
+	} else {
+		// Multiple destination words
+
+		// Leading bits
+		if (first!= ~0UL) {
+			FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
+			dst++;
+			n -= bits - dst_idx;
+		}
+
+		// Main chunk
+		n /= bits;
+		while (n >= 8) {
+			FB_WRITEL(pat, dst++);
+			FB_WRITEL(pat, dst++);
+			FB_WRITEL(pat, dst++);
+			FB_WRITEL(pat, dst++);
+			FB_WRITEL(pat, dst++);
+			FB_WRITEL(pat, dst++);
+			FB_WRITEL(pat, dst++);
+			FB_WRITEL(pat, dst++);
+			n -= 8;
+		}
+		while (n--)
+			FB_WRITEL(pat, dst++);
+
+		// Trailing bits
+		if (last)
+			FB_WRITEL(comp(pat, FB_READL(dst), last), dst);
+	}
+}
+
+
+    /*
+     *  Unaligned generic pattern fill using 32/64-bit memory accesses
+     *  The pattern must have been expanded to a full 32/64-bit value
+     *  Left/right are the appropriate shifts to convert to the pattern to be
+     *  used for the next 32/64-bit word
+     */
+
+static void
+bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
+			int left, int right, unsigned n, int bits)
+{
+	unsigned long first, last;
+
+	if (!n)
+		return;
+
+	first = ~0UL >> dst_idx;
+	last = ~(~0UL >> ((dst_idx+n) % bits));
+
+	if (dst_idx+n <= bits) {
+		// Single word
+		if (last)
+			first &= last;
+		FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
+	} else {
+		// Multiple destination words
+		// Leading bits
+		if (first) {
+			FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
+			dst++;
+			pat = pat << left | pat >> right;
+			n -= bits - dst_idx;
+		}
+
+		// Main chunk
+		n /= bits;
+		while (n >= 4) {
+			FB_WRITEL(pat, dst++);
+			pat = pat << left | pat >> right;
+			FB_WRITEL(pat, dst++);
+			pat = pat << left | pat >> right;
+			FB_WRITEL(pat, dst++);
+			pat = pat << left | pat >> right;
+			FB_WRITEL(pat, dst++);
+			pat = pat << left | pat >> right;
+			n -= 4;
+		}
+		while (n--) {
+			FB_WRITEL(pat, dst++);
+			pat = pat << left | pat >> right;
+		}
+
+		// Trailing bits
+		if (last)
+			FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
+	}
+}
+
+    /*
+     *  Aligned pattern invert using 32/64-bit memory accesses
+     */
+static void
+bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits)
+{
+	unsigned long val = pat, dat;
+	unsigned long first, last;
+
+	if (!n)
+		return;
+
+	first = ~0UL >> dst_idx;
+	last = ~(~0UL >> ((dst_idx+n) % bits));
+
+	if (dst_idx+n <= bits) {
+		// Single word
+		if (last)
+			first &= last;
+		dat = FB_READL(dst);
+		FB_WRITEL(comp(dat ^ val, dat, first), dst);
+	} else {
+		// Multiple destination words
+		// Leading bits
+		if (first!=0UL) {
+			dat = FB_READL(dst);
+			FB_WRITEL(comp(dat ^ val, dat, first), dst);
+			dst++;
+			n -= bits - dst_idx;
+		}
+
+		// Main chunk
+		n /= bits;
+		while (n >= 8) {
+			FB_WRITEL(FB_READL(dst) ^ val, dst);
+			dst++;
+			FB_WRITEL(FB_READL(dst) ^ val, dst);
+			dst++;
+			FB_WRITEL(FB_READL(dst) ^ val, dst);
+			dst++;
+			FB_WRITEL(FB_READL(dst) ^ val, dst);
+			dst++;
+			FB_WRITEL(FB_READL(dst) ^ val, dst);
+			dst++;
+			FB_WRITEL(FB_READL(dst) ^ val, dst);
+			dst++;
+			FB_WRITEL(FB_READL(dst) ^ val, dst);
+			dst++;
+			FB_WRITEL(FB_READL(dst) ^ val, dst);
+			dst++;
+			n -= 8;
+		}
+		while (n--) {
+			FB_WRITEL(FB_READL(dst) ^ val, dst);
+			dst++;
+		}
+		// Trailing bits
+		if (last) {
+			dat = FB_READL(dst);
+			FB_WRITEL(comp(dat ^ val, dat, last), dst);
+		}
+	}
+}
+
+
+    /*
+     *  Unaligned generic pattern invert using 32/64-bit memory accesses
+     *  The pattern must have been expanded to a full 32/64-bit value
+     *  Left/right are the appropriate shifts to convert to the pattern to be
+     *  used for the next 32/64-bit word
+     */
+
+static void
+bitfill_unaligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
+			int left, int right, unsigned n, int bits)
+{
+	unsigned long first, last, dat;
+
+	if (!n)
+		return;
+
+	first = ~0UL >> dst_idx;
+	last = ~(~0UL >> ((dst_idx+n) % bits));
+
+	if (dst_idx+n <= bits) {
+		// Single word
+		if (last)
+			first &= last;
+		dat = FB_READL(dst);
+		FB_WRITEL(comp(dat ^ pat, dat, first), dst);
+	} else {
+		// Multiple destination words
+
+		// Leading bits
+		if (first != 0UL) {
+			dat = FB_READL(dst);
+			FB_WRITEL(comp(dat ^ pat, dat, first), dst);
+			dst++;
+			pat = pat << left | pat >> right;
+			n -= bits - dst_idx;
+		}
+
+		// Main chunk
+		n /= bits;
+		while (n >= 4) {
+			FB_WRITEL(FB_READL(dst) ^ pat, dst);
+			dst++;
+			pat = pat << left | pat >> right;
+			FB_WRITEL(FB_READL(dst) ^ pat, dst);
+			dst++;
+			pat = pat << left | pat >> right;
+			FB_WRITEL(FB_READL(dst) ^ pat, dst);
+			dst++;
+			pat = pat << left | pat >> right;
+			FB_WRITEL(FB_READL(dst) ^ pat, dst);
+			dst++;
+			pat = pat << left | pat >> right;
+			n -= 4;
+		}
+		while (n--) {
+			FB_WRITEL(FB_READL(dst) ^ pat, dst);
+			dst++;
+			pat = pat << left | pat >> right;
+		}
+
+		// Trailing bits
+		if (last) {
+			dat = FB_READL(dst);
+			FB_WRITEL(comp(dat ^ pat, dat, last), dst);
+		}
+	}
+}
+
+void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
+{
+	unsigned long x2, y2, vxres, vyres, height, width, pat, fg;
+	int bits = BITS_PER_LONG, bytes = bits >> 3;
+	u32 bpp = p->var.bits_per_pixel;
+	unsigned long __iomem *dst;
+	int dst_idx, left;
+
+	if (p->state != FBINFO_STATE_RUNNING)
+		return;
+
+	/* We want rotation but lack hardware to do it for us. */
+	if (!p->fbops->fb_rotate && p->var.rotate) {
+	}
+
+	vxres = p->var.xres_virtual;
+	vyres = p->var.yres_virtual;
+
+	if (!rect->width || !rect->height ||
+	    rect->dx > vxres || rect->dy > vyres)
+		return;
+
+	/* We could use hardware clipping but on many cards you get around
+	 * hardware clipping by writing to framebuffer directly. */
+
+	x2 = rect->dx + rect->width;
+	y2 = rect->dy + rect->height;
+	x2 = x2 < vxres ? x2 : vxres;
+	y2 = y2 < vyres ? y2 : vyres;
+	width = x2 - rect->dx;
+	height = y2 - rect->dy;
+
+	if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
+	    p->fix.visual == FB_VISUAL_DIRECTCOLOR )
+		fg = ((u32 *) (p->pseudo_palette))[rect->color];
+	else
+		fg = rect->color;
+
+	pat = pixel_to_pat( bpp, fg);
+
+	dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
+	dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
+	dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
+	/* FIXME For now we support 1-32 bpp only */
+	left = bits % bpp;
+	if (p->fbops->fb_sync)
+		p->fbops->fb_sync(p);
+	if (!left) {
+		void (*fill_op32)(unsigned long __iomem *dst, int dst_idx,
+		                  unsigned long pat, unsigned n, int bits) = NULL;
+
+		switch (rect->rop) {
+		case ROP_XOR:
+			fill_op32 = bitfill_aligned_rev;
+			break;
+		case ROP_COPY:
+			fill_op32 = bitfill_aligned;
+			break;
+		default:
+			printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
+			fill_op32 = bitfill_aligned;
+			break;
+		}
+		while (height--) {
+			dst += dst_idx >> (ffs(bits) - 1);
+			dst_idx &= (bits - 1);
+			fill_op32(dst, dst_idx, pat, width*bpp, bits);
+			dst_idx += p->fix.line_length*8;
+		}
+	} else {
+		int right;
+		int r;
+		int rot = (left-dst_idx) % bpp;
+		void (*fill_op)(unsigned long __iomem *dst, int dst_idx,
+		                unsigned long pat, int left, int right,
+		                unsigned n, int bits) = NULL;
+
+		/* rotate pattern to correct start position */
+		pat = pat << rot | pat >> (bpp-rot);
+
+		right = bpp-left;
+		switch (rect->rop) {
+		case ROP_XOR:
+			fill_op = bitfill_unaligned_rev;
+			break;
+		case ROP_COPY:
+			fill_op = bitfill_unaligned;
+			break;
+		default:
+			printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
+			fill_op = bitfill_unaligned;
+			break;
+		}
+		while (height--) {
+			dst += dst_idx >> (ffs(bits) - 1);
+			dst_idx &= (bits - 1);
+			fill_op(dst, dst_idx, pat, left, right,
+				width*bpp, bits);
+			r = (p->fix.line_length*8) % bpp;
+			pat = pat << (bpp-r) | pat >> r;
+			dst_idx += p->fix.line_length*8;
+		}
+	}
+}
+
+EXPORT_SYMBOL(cfb_fillrect);
+
+MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
+MODULE_DESCRIPTION("Generic software accelerated fill rectangle");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c
new file mode 100644
index 0000000..4c123ab
--- /dev/null
+++ b/drivers/video/cfbimgblt.c
@@ -0,0 +1,339 @@
+/*
+ *  Generic BitBLT function for frame buffer with packed pixels of any depth.
+ *
+ *      Copyright (C)  June 1999 James Simmons
+ *
+ *  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.
+ *
+ * NOTES:
+ *
+ *    This function copys a image from system memory to video memory. The
+ *  image can be a bitmap where each 0 represents the background color and
+ *  each 1 represents the foreground color. Great for font handling. It can
+ *  also be a color image. This is determined by image_depth. The color image
+ *  must be laid out exactly in the same format as the framebuffer. Yes I know
+ *  their are cards with hardware that coverts images of various depths to the
+ *  framebuffer depth. But not every card has this. All images must be rounded
+ *  up to the nearest byte. For example a bitmap 12 bits wide must be two 
+ *  bytes width. 
+ *
+ *  Tony: 
+ *  Incorporate mask tables similar to fbcon-cfb*.c in 2.4 API.  This speeds 
+ *  up the code significantly.
+ *  
+ *  Code for depths not multiples of BITS_PER_LONG is still kludgy, which is
+ *  still processed a bit at a time.   
+ *
+ *  Also need to add code to deal with cards endians that are different than
+ *  the native cpu endians. I also need to deal with MSB position in the word.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <asm/types.h>
+
+#define DEBUG
+
+#ifdef DEBUG
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__FUNCTION__,## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+static u32 cfb_tab8[] = {
+#if defined(__BIG_ENDIAN)
+    0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
+    0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
+    0xff000000,0xff0000ff,0xff00ff00,0xff00ffff,
+    0xffff0000,0xffff00ff,0xffffff00,0xffffffff
+#elif defined(__LITTLE_ENDIAN)
+    0x00000000,0xff000000,0x00ff0000,0xffff0000,
+    0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00,
+    0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff,
+    0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff
+#else
+#error FIXME: No endianness??
+#endif
+};
+
+static u32 cfb_tab16[] = {
+#if defined(__BIG_ENDIAN)
+    0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
+#elif defined(__LITTLE_ENDIAN)
+    0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
+#else
+#error FIXME: No endianness??
+#endif
+};
+
+static u32 cfb_tab32[] = {
+	0x00000000, 0xffffffff
+};
+
+#define FB_WRITEL fb_writel
+#define FB_READL  fb_readl
+
+#if defined (__BIG_ENDIAN)
+#define LEFT_POS(bpp)          (32 - bpp)
+#define SHIFT_HIGH(val, bits)  ((val) >> (bits))
+#define SHIFT_LOW(val, bits)   ((val) << (bits))
+#else
+#define LEFT_POS(bpp)          (0)
+#define SHIFT_HIGH(val, bits)  ((val) << (bits))
+#define SHIFT_LOW(val, bits)   ((val) >> (bits))
+#endif
+
+static inline void color_imageblit(const struct fb_image *image, 
+				   struct fb_info *p, u8 __iomem *dst1, 
+				   u32 start_index,
+				   u32 pitch_index)
+{
+	/* Draw the penguin */
+	u32 __iomem *dst, *dst2;
+	u32 color = 0, val, shift;
+	int i, n, bpp = p->var.bits_per_pixel;
+	u32 null_bits = 32 - bpp;
+	u32 *palette = (u32 *) p->pseudo_palette;
+	const u8 *src = image->data;
+
+	dst2 = (u32 __iomem *) dst1;
+	for (i = image->height; i--; ) {
+		n = image->width;
+		dst = (u32 __iomem *) dst1;
+		shift = 0;
+		val = 0;
+		
+		if (start_index) {
+			u32 start_mask = ~(SHIFT_HIGH(~(u32)0, start_index));
+			val = FB_READL(dst) & start_mask;
+			shift = start_index;
+		}
+		while (n--) {
+			if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
+			    p->fix.visual == FB_VISUAL_DIRECTCOLOR )
+				color = palette[*src];
+			else
+				color = *src;
+			color <<= LEFT_POS(bpp);
+			val |= SHIFT_HIGH(color, shift);
+			if (shift >= null_bits) {
+				FB_WRITEL(val, dst++);
+	
+				val = (shift == null_bits) ? 0 : 
+					SHIFT_LOW(color, 32 - shift);
+			}
+			shift += bpp;
+			shift &= (32 - 1);
+			src++;
+		}
+		if (shift) {
+			u32 end_mask = SHIFT_HIGH(~(u32)0, shift);
+
+			FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
+		}
+		dst1 += p->fix.line_length;
+		if (pitch_index) {
+			dst2 += p->fix.line_length;
+			dst1 = (u8 __iomem *)((long __force)dst2 & ~(sizeof(u32) - 1));
+
+			start_index += pitch_index;
+			start_index &= 32 - 1;
+		}
+	}
+}
+
+static inline void slow_imageblit(const struct fb_image *image, struct fb_info *p, 
+				  u8 __iomem *dst1, u32 fgcolor,
+				  u32 bgcolor, 
+				  u32 start_index,
+				  u32 pitch_index)
+{
+	u32 shift, color = 0, bpp = p->var.bits_per_pixel;
+	u32 __iomem *dst, *dst2;
+	u32 val, pitch = p->fix.line_length;
+	u32 null_bits = 32 - bpp;
+	u32 spitch = (image->width+7)/8;
+	const u8 *src = image->data, *s;
+	u32 i, j, l;
+	
+	dst2 = (u32 __iomem *) dst1;
+
+	for (i = image->height; i--; ) {
+		shift = val = 0;
+		l = 8;
+		j = image->width;
+		dst = (u32 __iomem *) dst1;
+		s = src;
+
+		/* write leading bits */
+		if (start_index) {
+			u32 start_mask = ~(SHIFT_HIGH(~(u32)0, start_index));
+			val = FB_READL(dst) & start_mask;
+			shift = start_index;
+		}
+
+		while (j--) {
+			l--;
+			color = (*s & (1 << l)) ? fgcolor : bgcolor;
+			color <<= LEFT_POS(bpp);
+			val |= SHIFT_HIGH(color, shift);
+			
+			/* Did the bitshift spill bits to the next long? */
+			if (shift >= null_bits) {
+				FB_WRITEL(val, dst++);
+				val = (shift == null_bits) ? 0 :
+					 SHIFT_LOW(color,32 - shift);
+			}
+			shift += bpp;
+			shift &= (32 - 1);
+			if (!l) { l = 8; s++; };
+		}
+
+		/* write trailing bits */
+ 		if (shift) {
+			u32 end_mask = SHIFT_HIGH(~(u32)0, shift);
+
+			FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
+		}
+		
+		dst1 += pitch;
+		src += spitch;	
+		if (pitch_index) {
+			dst2 += pitch;
+			dst1 = (u8 __iomem *)((long __force)dst2 & ~(sizeof(u32) - 1));
+			start_index += pitch_index;
+			start_index &= 32 - 1;
+		}
+		
+	}
+}
+
+/*
+ * fast_imageblit - optimized monochrome color expansion
+ *
+ * Only if:  bits_per_pixel == 8, 16, or 32
+ *           image->width is divisible by pixel/dword (ppw);
+ *           fix->line_legth is divisible by 4;
+ *           beginning and end of a scanline is dword aligned
+ */
+static inline void fast_imageblit(const struct fb_image *image, struct fb_info *p, 
+				  u8 __iomem *dst1, u32 fgcolor, 
+				  u32 bgcolor) 
+{
+	u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel;
+	u32 ppw = 32/bpp, spitch = (image->width + 7)/8;
+	u32 bit_mask, end_mask, eorx, shift;
+	const char *s = image->data, *src;
+	u32 __iomem *dst;
+	u32 *tab = NULL;
+	int i, j, k;
+		
+	switch (bpp) {
+	case 8:
+		tab = cfb_tab8;
+		break;
+	case 16:
+		tab = cfb_tab16;
+		break;
+	case 32:
+		tab = cfb_tab32;
+		break;
+	}
+
+	for (i = ppw-1; i--; ) {
+		fgx <<= bpp;
+		bgx <<= bpp;
+		fgx |= fgcolor;
+		bgx |= bgcolor;
+	}
+	
+	bit_mask = (1 << ppw) - 1;
+	eorx = fgx ^ bgx;
+	k = image->width/ppw;
+
+	for (i = image->height; i--; ) {
+		dst = (u32 __iomem *) dst1, shift = 8; src = s;
+		
+		for (j = k; j--; ) {
+			shift -= ppw;
+			end_mask = tab[(*src >> shift) & bit_mask];
+			FB_WRITEL((end_mask & eorx)^bgx, dst++);
+			if (!shift) { shift = 8; src++; }		
+		}
+		dst1 += p->fix.line_length;
+		s += spitch;
+	}
+}	
+	
+void cfb_imageblit(struct fb_info *p, const struct fb_image *image)
+{
+	u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;
+	u32 bpl = sizeof(u32), bpp = p->var.bits_per_pixel;
+	u32 width = image->width, height = image->height; 
+	u32 dx = image->dx, dy = image->dy;
+	int x2, y2, vxres, vyres;
+	u8 __iomem *dst1;
+
+	if (p->state != FBINFO_STATE_RUNNING)
+		return;
+
+	vxres = p->var.xres_virtual;
+	vyres = p->var.yres_virtual;
+	/* 
+	 * We could use hardware clipping but on many cards you get around
+	 * hardware clipping by writing to framebuffer directly like we are
+	 * doing here. 
+	 */
+	if (image->dx > vxres || image->dy > vyres)
+		return;
+
+	x2 = image->dx + image->width;
+	y2 = image->dy + image->height;
+	dx = image->dx > 0 ? image->dx : 0;
+	dy = image->dy > 0 ? image->dy : 0;
+	x2 = x2 < vxres ? x2 : vxres;
+	y2 = y2 < vyres ? y2 : vyres;
+	width  = x2 - dx;
+	height = y2 - dy;
+
+	bitstart = (dy * p->fix.line_length * 8) + (dx * bpp);
+	start_index = bitstart & (32 - 1);
+	pitch_index = (p->fix.line_length & (bpl - 1)) * 8;
+
+	bitstart /= 8;
+	bitstart &= ~(bpl - 1);
+	dst1 = p->screen_base + bitstart;
+
+	if (p->fbops->fb_sync)
+		p->fbops->fb_sync(p);
+
+	if (image->depth == 1) {
+		if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
+		    p->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+			fgcolor = ((u32*)(p->pseudo_palette))[image->fg_color];
+			bgcolor = ((u32*)(p->pseudo_palette))[image->bg_color];
+		} else {
+			fgcolor = image->fg_color;
+			bgcolor = image->bg_color;
+		}	
+		
+		if (32 % bpp == 0 && !start_index && !pitch_index && 
+		    ((width & (32/bpp-1)) == 0) &&
+		    bpp >= 8 && bpp <= 32) 			
+			fast_imageblit(image, p, dst1, fgcolor, bgcolor);
+		else 
+			slow_imageblit(image, p, dst1, fgcolor, bgcolor,
+					start_index, pitch_index);
+	} else
+		color_imageblit(image, p, dst1, start_index, pitch_index);
+}
+
+EXPORT_SYMBOL(cfb_imageblit);
+
+MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
+MODULE_DESCRIPTION("Generic software accelerated imaging drawing");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c
new file mode 100644
index 0000000..18e60b9
--- /dev/null
+++ b/drivers/video/cg14.c
@@ -0,0 +1,648 @@
+/* cg14.c: CGFOURTEEN frame buffer driver
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * Driver layout based loosely on tgafb.c, see that file for credits.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/mm.h>
+
+#include <asm/io.h>
+#include <asm/sbus.h>
+#include <asm/oplib.h>
+#include <asm/fbio.h>
+
+#include "sbuslib.h"
+
+/*
+ * Local functions.
+ */
+
+static int cg14_setcolreg(unsigned, unsigned, unsigned, unsigned,
+			 unsigned, struct fb_info *);
+
+static int cg14_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
+static int cg14_ioctl(struct inode *, struct file *, unsigned int,
+		      unsigned long, struct fb_info *);
+static int cg14_pan_display(struct fb_var_screeninfo *, struct fb_info *);
+
+/*
+ *  Frame buffer operations
+ */
+
+static struct fb_ops cg14_ops = {
+	.owner			= THIS_MODULE,
+	.fb_setcolreg		= cg14_setcolreg,
+	.fb_pan_display		= cg14_pan_display,
+	.fb_fillrect		= cfb_fillrect,
+	.fb_copyarea		= cfb_copyarea,
+	.fb_imageblit		= cfb_imageblit,
+	.fb_mmap		= cg14_mmap,
+	.fb_ioctl		= cg14_ioctl,
+	.fb_cursor		= soft_cursor,
+};
+
+#define CG14_MCR_INTENABLE_SHIFT	7
+#define CG14_MCR_INTENABLE_MASK		0x80
+#define CG14_MCR_VIDENABLE_SHIFT	6
+#define CG14_MCR_VIDENABLE_MASK		0x40
+#define CG14_MCR_PIXMODE_SHIFT		4
+#define CG14_MCR_PIXMODE_MASK		0x30
+#define CG14_MCR_TMR_SHIFT		2
+#define CG14_MCR_TMR_MASK		0x0c
+#define CG14_MCR_TMENABLE_SHIFT		1
+#define CG14_MCR_TMENABLE_MASK		0x02
+#define CG14_MCR_RESET_SHIFT		0
+#define CG14_MCR_RESET_MASK		0x01
+#define CG14_REV_REVISION_SHIFT		4
+#define CG14_REV_REVISION_MASK		0xf0
+#define CG14_REV_IMPL_SHIFT		0
+#define CG14_REV_IMPL_MASK		0x0f
+#define CG14_VBR_FRAMEBASE_SHIFT	12
+#define CG14_VBR_FRAMEBASE_MASK		0x00fff000
+#define CG14_VMCR1_SETUP_SHIFT		0
+#define CG14_VMCR1_SETUP_MASK		0x000001ff
+#define CG14_VMCR1_VCONFIG_SHIFT	9
+#define CG14_VMCR1_VCONFIG_MASK		0x00000e00
+#define CG14_VMCR2_REFRESH_SHIFT	0
+#define CG14_VMCR2_REFRESH_MASK		0x00000001
+#define CG14_VMCR2_TESTROWCNT_SHIFT	1
+#define CG14_VMCR2_TESTROWCNT_MASK	0x00000002
+#define CG14_VMCR2_FBCONFIG_SHIFT	2
+#define CG14_VMCR2_FBCONFIG_MASK	0x0000000c
+#define CG14_VCR_REFRESHREQ_SHIFT	0
+#define CG14_VCR_REFRESHREQ_MASK	0x000003ff
+#define CG14_VCR1_REFRESHENA_SHIFT	10
+#define CG14_VCR1_REFRESHENA_MASK	0x00000400
+#define CG14_VCA_CAD_SHIFT		0
+#define CG14_VCA_CAD_MASK		0x000003ff
+#define CG14_VCA_VERS_SHIFT		10
+#define CG14_VCA_VERS_MASK		0x00000c00
+#define CG14_VCA_RAMSPEED_SHIFT		12
+#define CG14_VCA_RAMSPEED_MASK		0x00001000
+#define CG14_VCA_8MB_SHIFT		13
+#define CG14_VCA_8MB_MASK		0x00002000
+
+#define CG14_MCR_PIXMODE_8		0
+#define CG14_MCR_PIXMODE_16		2
+#define CG14_MCR_PIXMODE_32		3
+
+struct cg14_regs{
+	volatile u8 mcr;	/* Master Control Reg */
+	volatile u8 ppr;	/* Packed Pixel Reg */
+	volatile u8 tms[2];	/* Test Mode Status Regs */
+	volatile u8 msr;	/* Master Status Reg */
+	volatile u8 fsr;	/* Fault Status Reg */
+	volatile u8 rev;	/* Revision & Impl */
+	volatile u8 ccr;	/* Clock Control Reg */
+	volatile u32 tmr;	/* Test Mode Read Back */
+	volatile u8 mod;	/* Monitor Operation Data Reg */
+	volatile u8 acr;	/* Aux Control */
+	u8 xxx0[6];
+	volatile u16 hct;	/* Hor Counter */
+	volatile u16 vct;	/* Vert Counter */
+	volatile u16 hbs;	/* Hor Blank Start */
+	volatile u16 hbc;	/* Hor Blank Clear */
+	volatile u16 hss;	/* Hor Sync Start */
+	volatile u16 hsc;	/* Hor Sync Clear */
+	volatile u16 csc;	/* Composite Sync Clear */
+	volatile u16 vbs;	/* Vert Blank Start */
+	volatile u16 vbc;	/* Vert Blank Clear */
+	volatile u16 vss;	/* Vert Sync Start */
+	volatile u16 vsc;	/* Vert Sync Clear */
+	volatile u16 xcs;
+	volatile u16 xcc;
+	volatile u16 fsa;	/* Fault Status Address */
+	volatile u16 adr;	/* Address Registers */
+	u8 xxx1[0xce];
+	volatile u8 pcg[0x100]; /* Pixel Clock Generator */
+	volatile u32 vbr;	/* Frame Base Row */
+	volatile u32 vmcr;	/* VBC Master Control */
+	volatile u32 vcr;	/* VBC refresh */
+	volatile u32 vca;	/* VBC Config */
+};
+
+#define CG14_CCR_ENABLE	0x04
+#define CG14_CCR_SELECT 0x02	/* HW/Full screen */
+
+struct cg14_cursor {
+	volatile u32 cpl0[32];	/* Enable plane 0 */
+	volatile u32 cpl1[32];  /* Color selection plane */
+	volatile u8 ccr;	/* Cursor Control Reg */
+	u8 xxx0[3];
+	volatile u16 cursx;	/* Cursor x,y position */
+	volatile u16 cursy;	/* Cursor x,y position */
+	volatile u32 color0;
+	volatile u32 color1;
+	u32 xxx1[0x1bc];
+	volatile u32 cpl0i[32];	/* Enable plane 0 autoinc */
+	volatile u32 cpl1i[32]; /* Color selection autoinc */
+};
+
+struct cg14_dac {
+	volatile u8 addr;	/* Address Register */
+	u8 xxx0[255];
+	volatile u8 glut;	/* Gamma table */
+	u8 xxx1[255];
+	volatile u8 select;	/* Register Select */
+	u8 xxx2[255];
+	volatile u8 mode;	/* Mode Register */
+};
+
+struct cg14_xlut{
+	volatile u8 x_xlut [256];
+	volatile u8 x_xlutd [256];
+	u8 xxx0[0x600];
+	volatile u8 x_xlut_inc [256];
+	volatile u8 x_xlutd_inc [256];
+};
+
+/* Color look up table (clut) */
+/* Each one of these arrays hold the color lookup table (for 256
+ * colors) for each MDI page (I assume then there should be 4 MDI
+ * pages, I still wonder what they are.  I have seen NeXTStep split
+ * the screen in four parts, while operating in 24 bits mode.  Each
+ * integer holds 4 values: alpha value (transparency channel, thanks
+ * go to John Stone (johns@umr.edu) from OpenBSD), red, green and blue
+ *
+ * I currently use the clut instead of the Xlut
+ */
+struct cg14_clut {
+	u32 c_clut [256];
+	u32 c_clutd [256];    /* i wonder what the 'd' is for */
+	u32 c_clut_inc [256];
+	u32 c_clutd_inc [256];
+};
+
+#define CG14_MMAP_ENTRIES	16
+
+struct cg14_par {
+	spinlock_t		lock;
+	struct cg14_regs	__iomem *regs;
+	struct cg14_clut	__iomem *clut;
+	struct cg14_cursor	__iomem *cursor;
+
+	u32			flags;
+#define CG14_FLAG_BLANKED	0x00000001
+
+	unsigned long		physbase;
+	unsigned long		iospace;
+	unsigned long		fbsize;
+
+	struct sbus_mmap_map	mmap_map[CG14_MMAP_ENTRIES];
+
+	int			mode;
+	int			ramsize;
+	struct sbus_dev		*sdev;
+	struct list_head	list;
+};
+
+static void __cg14_reset(struct cg14_par *par)
+{
+	struct cg14_regs __iomem *regs = par->regs;
+	u8 val;
+
+	val = sbus_readb(&regs->mcr);
+	val &= ~(CG14_MCR_PIXMODE_MASK);
+	sbus_writeb(val, &regs->mcr);
+}
+
+static int cg14_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct cg14_par *par = (struct cg14_par *) info->par;
+	unsigned long flags;
+
+	/* We just use this to catch switches out of
+	 * graphics mode.
+	 */
+	spin_lock_irqsave(&par->lock, flags);
+	__cg14_reset(par);
+	spin_unlock_irqrestore(&par->lock, flags);
+
+	if (var->xoffset || var->yoffset || var->vmode)
+		return -EINVAL;
+	return 0;
+}
+
+/**
+ *      cg14_setcolreg - Optional function. Sets a color register.
+ *      @regno: boolean, 0 copy local, 1 get_user() function
+ *      @red: frame buffer colormap structure
+ *      @green: The green value which can be up to 16 bits wide
+ *      @blue:  The blue value which can be up to 16 bits wide.
+ *      @transp: If supported the alpha value which can be up to 16 bits wide.
+ *      @info: frame buffer info structure
+ */
+static int cg14_setcolreg(unsigned regno,
+			  unsigned red, unsigned green, unsigned blue,
+			  unsigned transp, struct fb_info *info)
+{
+	struct cg14_par *par = (struct cg14_par *) info->par;
+	struct cg14_clut __iomem *clut = par->clut;
+	unsigned long flags;
+	u32 val;
+
+	if (regno >= 256)
+		return 1;
+
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+	val = (red | (green << 8) | (blue << 16));
+
+	spin_lock_irqsave(&par->lock, flags);
+	sbus_writel(val, &clut->c_clut[regno]);
+	spin_unlock_irqrestore(&par->lock, flags);
+
+	return 0;
+}
+
+static int cg14_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+{
+	struct cg14_par *par = (struct cg14_par *) info->par;
+
+	return sbusfb_mmap_helper(par->mmap_map,
+				  par->physbase, par->fbsize,
+				  par->iospace, vma);
+}
+
+static int cg14_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		      unsigned long arg, struct fb_info *info)
+{
+	struct cg14_par *par = (struct cg14_par *) info->par;
+	struct cg14_regs __iomem *regs = par->regs;
+	struct mdi_cfginfo kmdi, __user *mdii;
+	unsigned long flags;
+	int cur_mode, mode, ret = 0;
+
+	switch (cmd) {
+	case MDI_RESET:
+		spin_lock_irqsave(&par->lock, flags);
+		__cg14_reset(par);
+		spin_unlock_irqrestore(&par->lock, flags);
+		break;
+
+	case MDI_GET_CFGINFO:
+		memset(&kmdi, 0, sizeof(kmdi));
+
+		spin_lock_irqsave(&par->lock, flags);
+		kmdi.mdi_type = FBTYPE_MDICOLOR;
+		kmdi.mdi_height = info->var.yres;
+		kmdi.mdi_width = info->var.xres;
+		kmdi.mdi_mode = par->mode;
+		kmdi.mdi_pixfreq = 72; /* FIXME */
+		kmdi.mdi_size = par->ramsize;
+		spin_unlock_irqrestore(&par->lock, flags);
+
+		mdii = (struct mdi_cfginfo __user *) arg;
+		if (copy_to_user(mdii, &kmdi, sizeof(kmdi)))
+			ret = -EFAULT;
+		break;
+
+	case MDI_SET_PIXELMODE:
+		if (get_user(mode, (int __user *) arg)) {
+			ret = -EFAULT;
+			break;
+		}
+
+		spin_lock_irqsave(&par->lock, flags);
+		cur_mode = sbus_readb(&regs->mcr);
+		cur_mode &= ~CG14_MCR_PIXMODE_MASK;
+		switch(mode) {
+		case MDI_32_PIX:
+			cur_mode |= (CG14_MCR_PIXMODE_32 <<
+				     CG14_MCR_PIXMODE_SHIFT);
+			break;
+
+		case MDI_16_PIX:
+			cur_mode |= (CG14_MCR_PIXMODE_16 <<
+				     CG14_MCR_PIXMODE_SHIFT);
+			break;
+
+		case MDI_8_PIX:
+			break;
+
+		default:
+			ret = -ENOSYS;
+			break;
+		};
+		if (!ret) {
+			sbus_writeb(cur_mode, &regs->mcr);
+			par->mode = mode;
+		}
+		spin_unlock_irqrestore(&par->lock, flags);
+		break;
+
+	default:
+		ret = sbusfb_ioctl_helper(cmd, arg, info,
+					  FBTYPE_MDICOLOR, 8, par->fbsize);
+		break;
+	};
+
+	return ret;
+}
+
+/*
+ *  Initialisation
+ */
+
+static void cg14_init_fix(struct fb_info *info, int linebytes)
+{
+	struct cg14_par *par = (struct cg14_par *)info->par;
+	const char *name;
+
+	name = "cgfourteen";
+	if (par->sdev)
+		name = par->sdev->prom_name;
+
+	strlcpy(info->fix.id, name, sizeof(info->fix.id));
+
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+
+	info->fix.line_length = linebytes;
+
+	info->fix.accel = FB_ACCEL_SUN_CG14;
+}
+
+static struct sbus_mmap_map __cg14_mmap_map[CG14_MMAP_ENTRIES] __initdata = {
+	{
+		.voff	= CG14_REGS,
+		.poff	= 0x80000000,
+		.size	= 0x1000
+	},
+	{
+		.voff	= CG14_XLUT,
+		.poff	= 0x80003000,
+		.size	= 0x1000
+	},
+	{
+		.voff	= CG14_CLUT1,
+		.poff	= 0x80004000,
+		.size	= 0x1000
+	},
+	{
+		.voff	= CG14_CLUT2,
+		.poff	= 0x80005000,
+		.size	= 0x1000
+	},
+	{
+		.voff	= CG14_CLUT3,
+		.poff	= 0x80006000,
+		.size	= 0x1000
+	},
+	{
+		.voff	= CG3_MMAP_OFFSET - 0x7000,
+		.poff	= 0x80000000,
+		.size	= 0x7000
+	},
+	{
+		.voff	= CG3_MMAP_OFFSET,
+		.poff	= 0x00000000,
+		.size	= SBUS_MMAP_FBSIZE(1)
+	},
+	{
+		.voff	= MDI_CURSOR_MAP,
+		.poff	= 0x80001000,
+		.size	= 0x1000
+	},
+	{
+		.voff	= MDI_CHUNKY_BGR_MAP,
+		.poff	= 0x01000000,
+		.size	= 0x400000
+	},
+	{
+		.voff	= MDI_PLANAR_X16_MAP,
+		.poff	= 0x02000000,
+		.size	= 0x200000
+	},
+	{
+		.voff	= MDI_PLANAR_C16_MAP,
+		.poff	= 0x02800000,
+		.size	= 0x200000
+	},
+	{
+		.voff	= MDI_PLANAR_X32_MAP,
+		.poff	= 0x03000000,
+		.size	= 0x100000
+	},
+	{
+		.voff	= MDI_PLANAR_B32_MAP,
+		.poff	= 0x03400000,
+		.size	= 0x100000
+	},
+	{
+		.voff	= MDI_PLANAR_G32_MAP,
+		.poff	= 0x03800000,
+		.size	= 0x100000
+	},
+	{
+		.voff	= MDI_PLANAR_R32_MAP,
+		.poff	= 0x03c00000,
+		.size	= 0x100000
+	},
+	{ .size = 0 }
+};
+
+struct all_info {
+	struct fb_info info;
+	struct cg14_par par;
+	struct list_head list;
+};
+static LIST_HEAD(cg14_list);
+
+static void cg14_init_one(struct sbus_dev *sdev, int node, int parent_node)
+{
+	struct all_info *all;
+	unsigned long phys, rphys;
+	u32 bases[6];
+	int is_8mb, linebytes, i;
+
+	if (!sdev) {
+		if (prom_getproperty(node, "address",
+				     (char *) &bases[0], sizeof(bases)) <= 0
+		    || !bases[0]) {
+			printk(KERN_ERR "cg14: Device is not mapped.\n");
+			return;
+		}
+		if (__get_iospace(bases[0]) != __get_iospace(bases[1])) {
+			printk(KERN_ERR "cg14: I/O spaces don't match.\n");
+			return;
+		}
+	}
+
+	all = kmalloc(sizeof(*all), GFP_KERNEL);
+	if (!all) {
+		printk(KERN_ERR "cg14: Cannot allocate memory.\n");
+		return;
+	}
+	memset(all, 0, sizeof(*all));
+
+	INIT_LIST_HEAD(&all->list);
+
+	spin_lock_init(&all->par.lock);
+
+	sbusfb_fill_var(&all->info.var, node, 8);
+	all->info.var.red.length = 8;
+	all->info.var.green.length = 8;
+	all->info.var.blue.length = 8;
+
+	linebytes = prom_getintdefault(node, "linebytes",
+				       all->info.var.xres);
+	all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
+
+	all->par.sdev = sdev;
+	if (sdev) {
+		rphys = sdev->reg_addrs[0].phys_addr;
+		all->par.physbase = phys = sdev->reg_addrs[1].phys_addr;
+		all->par.iospace = sdev->reg_addrs[0].which_io;
+
+		all->par.regs = sbus_ioremap(&sdev->resource[0], 0,
+				     sizeof(struct cg14_regs),
+				     "cg14 regs");
+		all->par.clut = sbus_ioremap(&sdev->resource[0], CG14_CLUT1,
+				     sizeof(struct cg14_clut),
+				     "cg14 clut");
+		all->par.cursor = sbus_ioremap(&sdev->resource[0], CG14_CURSORREGS,
+				     sizeof(struct cg14_cursor),
+				     "cg14 cursor");
+		all->info.screen_base = sbus_ioremap(&sdev->resource[1], 0,
+				     all->par.fbsize, "cg14 ram");
+	} else {
+		rphys = __get_phys(bases[0]);
+		all->par.physbase = phys = __get_phys(bases[1]);
+		all->par.iospace = __get_iospace(bases[0]);
+		all->par.regs = (struct cg14_regs __iomem *)(unsigned long)bases[0];
+		all->par.clut = (struct cg14_clut __iomem *)((unsigned long)bases[0] +
+						     CG14_CLUT1);
+		all->par.cursor =
+			(struct cg14_cursor __iomem *)((unsigned long)bases[0] +
+					       CG14_CURSORREGS);
+
+		all->info.screen_base = (char __iomem *)(unsigned long)bases[1];
+	}
+
+	prom_getproperty(node, "reg", (char *) &bases[0], sizeof(bases));
+	is_8mb = (bases[5] == 0x800000);
+
+	if (sizeof(all->par.mmap_map) != sizeof(__cg14_mmap_map)) {
+		extern void __cg14_mmap_sized_wrongly(void);
+
+		__cg14_mmap_sized_wrongly();
+	}
+		
+	memcpy(&all->par.mmap_map, &__cg14_mmap_map, sizeof(all->par.mmap_map));
+	for (i = 0; i < CG14_MMAP_ENTRIES; i++) {
+		struct sbus_mmap_map *map = &all->par.mmap_map[i];
+
+		if (!map->size)
+			break;
+		if (map->poff & 0x80000000)
+			map->poff = (map->poff & 0x7fffffff) + rphys - phys;
+		if (is_8mb &&
+		    map->size >= 0x100000 &&
+		    map->size <= 0x400000)
+			map->size *= 2;
+	}
+
+	all->par.mode = MDI_8_PIX;
+	all->par.ramsize = (is_8mb ? 0x800000 : 0x400000);
+
+	all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+	all->info.fbops = &cg14_ops;
+	all->info.par = &all->par;
+
+	__cg14_reset(&all->par);
+
+	if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
+		printk(KERN_ERR "cg14: Could not allocate color map.\n");
+		kfree(all);
+		return;
+	}
+	fb_set_cmap(&all->info.cmap, &all->info);
+
+	cg14_init_fix(&all->info, linebytes);
+
+	if (register_framebuffer(&all->info) < 0) {
+		printk(KERN_ERR "cg14: Could not register framebuffer.\n");
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+		return;
+	}
+
+	list_add(&all->list, &cg14_list);
+
+	printk("cg14: cgfourteen at %lx:%lx, %dMB\n",
+	       all->par.iospace, all->par.physbase, all->par.ramsize >> 20);
+
+}
+
+int __init cg14_init(void)
+{
+	struct sbus_bus *sbus;
+	struct sbus_dev *sdev;
+
+	if (fb_get_options("cg14fb", NULL))
+		return -ENODEV;
+
+#ifdef CONFIG_SPARC32
+	{
+		int root, node;
+
+		root = prom_getchild(prom_root_node);
+		root = prom_searchsiblings(root, "obio");
+		if (root) {
+			node = prom_searchsiblings(prom_getchild(root),
+						   "cgfourteen");
+			if (node)
+				cg14_init_one(NULL, node, root);
+		}
+	}
+#endif
+	for_all_sbusdev(sdev, sbus) {
+		if (!strcmp(sdev->prom_name, "cgfourteen"))
+			cg14_init_one(sdev, sdev->prom_node, sbus->prom_node);
+	}
+
+	return 0;
+}
+
+void __exit cg14_exit(void)
+{
+	struct list_head *pos, *tmp;
+
+	list_for_each_safe(pos, tmp, &cg14_list) {
+		struct all_info *all = list_entry(pos, typeof(*all), list);
+
+		unregister_framebuffer(&all->info);
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+	}
+}
+
+int __init
+cg14_setup(char *arg)
+{
+	/* No cmdline options yet... */
+	return 0;
+}
+
+module_init(cg14_init);
+
+#ifdef MODULE
+module_exit(cg14_exit);
+#endif
+
+MODULE_DESCRIPTION("framebuffer driver for CGfourteen chipsets");
+MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c
new file mode 100644
index 0000000..6e7d8d4
--- /dev/null
+++ b/drivers/video/cg3.c
@@ -0,0 +1,489 @@
+/* cg3.c: CGTHREE frame buffer driver
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ *
+ * Driver layout based loosely on tgafb.c, see that file for credits.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/mm.h>
+
+#include <asm/io.h>
+#include <asm/sbus.h>
+#include <asm/oplib.h>
+#include <asm/fbio.h>
+
+#include "sbuslib.h"
+
+/*
+ * Local functions.
+ */
+
+static int cg3_setcolreg(unsigned, unsigned, unsigned, unsigned,
+			 unsigned, struct fb_info *);
+static int cg3_blank(int, struct fb_info *);
+
+static int cg3_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
+static int cg3_ioctl(struct inode *, struct file *, unsigned int,
+		     unsigned long, struct fb_info *);
+
+/*
+ *  Frame buffer operations
+ */
+
+static struct fb_ops cg3_ops = {
+	.owner			= THIS_MODULE,
+	.fb_setcolreg		= cg3_setcolreg,
+	.fb_blank		= cg3_blank,
+	.fb_fillrect		= cfb_fillrect,
+	.fb_copyarea		= cfb_copyarea,
+	.fb_imageblit		= cfb_imageblit,
+	.fb_mmap		= cg3_mmap,
+	.fb_ioctl		= cg3_ioctl,
+	.fb_cursor		= soft_cursor,
+};
+
+
+/* Control Register Constants */
+#define CG3_CR_ENABLE_INTS      0x80
+#define CG3_CR_ENABLE_VIDEO     0x40
+#define CG3_CR_ENABLE_TIMING    0x20
+#define CG3_CR_ENABLE_CURCMP    0x10
+#define CG3_CR_XTAL_MASK        0x0c
+#define CG3_CR_DIVISOR_MASK     0x03
+
+/* Status Register Constants */
+#define CG3_SR_PENDING_INT      0x80
+#define CG3_SR_RES_MASK         0x70
+#define CG3_SR_1152_900_76_A    0x40
+#define CG3_SR_1152_900_76_B    0x60
+#define CG3_SR_ID_MASK          0x0f
+#define CG3_SR_ID_COLOR         0x01
+#define CG3_SR_ID_MONO          0x02
+#define CG3_SR_ID_MONO_ECL      0x03
+
+enum cg3_type {
+	CG3_AT_66HZ = 0,
+	CG3_AT_76HZ,
+	CG3_RDI
+};
+
+struct bt_regs {
+	volatile u32 addr;
+	volatile u32 color_map;
+	volatile u32 control;
+	volatile u32 cursor;
+};
+
+struct cg3_regs {
+	struct bt_regs	cmap;
+	volatile u8	control;
+	volatile u8	status;
+	volatile u8	cursor_start;
+	volatile u8	cursor_end;
+	volatile u8	h_blank_start;
+	volatile u8	h_blank_end;
+	volatile u8	h_sync_start;
+	volatile u8	h_sync_end;
+	volatile u8	comp_sync_end;
+	volatile u8	v_blank_start_high;
+	volatile u8	v_blank_start_low;
+	volatile u8	v_blank_end;
+	volatile u8	v_sync_start;
+	volatile u8	v_sync_end;
+	volatile u8	xfer_holdoff_start;
+	volatile u8	xfer_holdoff_end;
+};
+
+/* Offset of interesting structures in the OBIO space */
+#define CG3_REGS_OFFSET	     0x400000UL
+#define CG3_RAM_OFFSET	     0x800000UL
+
+struct cg3_par {
+	spinlock_t		lock;
+	struct cg3_regs		__iomem *regs;
+	u32			sw_cmap[((256 * 3) + 3) / 4];
+
+	u32			flags;
+#define CG3_FLAG_BLANKED	0x00000001
+#define CG3_FLAG_RDI		0x00000002
+
+	unsigned long		physbase;
+	unsigned long		fbsize;
+
+	struct sbus_dev		*sdev;
+	struct list_head	list;
+};
+
+/**
+ *      cg3_setcolreg - Optional function. Sets a color register.
+ *      @regno: boolean, 0 copy local, 1 get_user() function
+ *      @red: frame buffer colormap structure
+ *      @green: The green value which can be up to 16 bits wide
+ *      @blue:  The blue value which can be up to 16 bits wide.
+ *      @transp: If supported the alpha value which can be up to 16 bits wide.
+ *      @info: frame buffer info structure
+ *
+ * The cg3 palette is loaded with 4 color values at each time
+ * so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on.
+ * We keep a sw copy of the hw cmap to assist us in this esoteric
+ * loading procedure.
+ */
+static int cg3_setcolreg(unsigned regno,
+			 unsigned red, unsigned green, unsigned blue,
+			 unsigned transp, struct fb_info *info)
+{
+	struct cg3_par *par = (struct cg3_par *) info->par;
+	struct bt_regs __iomem *bt = &par->regs->cmap;
+	unsigned long flags;
+	u32 *p32;
+	u8 *p8;
+	int count;
+
+	if (regno >= 256)
+		return 1;
+
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	p8 = (u8 *)par->sw_cmap + (regno * 3);
+	p8[0] = red;
+	p8[1] = green;
+	p8[2] = blue;
+
+#define D4M3(x) ((((x)>>2)<<1) + ((x)>>2))      /* (x/4)*3 */
+#define D4M4(x) ((x)&~0x3)                      /* (x/4)*4 */
+
+	count = 3;
+	p32 = &par->sw_cmap[D4M3(regno)];
+	sbus_writel(D4M4(regno), &bt->addr);
+	while (count--)
+		sbus_writel(*p32++, &bt->color_map);
+
+#undef D4M3
+#undef D4M4
+
+	spin_unlock_irqrestore(&par->lock, flags);
+
+	return 0;
+}
+
+/**
+ *      cg3_blank - Optional function.  Blanks the display.
+ *      @blank_mode: the blank mode we want.
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+cg3_blank(int blank, struct fb_info *info)
+{
+	struct cg3_par *par = (struct cg3_par *) info->par;
+	struct cg3_regs __iomem *regs = par->regs;
+	unsigned long flags;
+	u8 val;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	switch (blank) {
+	case FB_BLANK_UNBLANK: /* Unblanking */
+		val = sbus_readb(&regs->control);
+		val |= CG3_CR_ENABLE_VIDEO;
+		sbus_writeb(val, &regs->control);
+		par->flags &= ~CG3_FLAG_BLANKED;
+		break;
+
+	case FB_BLANK_NORMAL: /* Normal blanking */
+	case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
+	case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
+	case FB_BLANK_POWERDOWN: /* Poweroff */
+		val = sbus_readb(&regs->control);
+		val &= ~CG3_CR_ENABLE_VIDEO;
+		sbus_writeb(val, &regs->control);
+		par->flags |= CG3_FLAG_BLANKED;
+		break;
+	}
+
+	spin_unlock_irqrestore(&par->lock, flags);
+
+	return 0;
+}
+
+static struct sbus_mmap_map cg3_mmap_map[] = {
+	{
+		.voff	= CG3_MMAP_OFFSET,
+		.poff	= CG3_RAM_OFFSET,
+		.size	= SBUS_MMAP_FBSIZE(1)
+	},
+	{ .size = 0 }
+};
+
+static int cg3_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+{
+	struct cg3_par *par = (struct cg3_par *)info->par;
+
+	return sbusfb_mmap_helper(cg3_mmap_map,
+				  par->physbase, par->fbsize,
+				  par->sdev->reg_addrs[0].which_io,
+				  vma);
+}
+
+static int cg3_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		     unsigned long arg, struct fb_info *info)
+{
+	struct cg3_par *par = (struct cg3_par *) info->par;
+
+	return sbusfb_ioctl_helper(cmd, arg, info,
+				   FBTYPE_SUN3COLOR, 8, par->fbsize);
+}
+
+/*
+ *  Initialisation
+ */
+
+static void
+cg3_init_fix(struct fb_info *info, int linebytes)
+{
+	struct cg3_par *par = (struct cg3_par *)info->par;
+
+	strlcpy(info->fix.id, par->sdev->prom_name, sizeof(info->fix.id));
+
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+
+	info->fix.line_length = linebytes;
+
+	info->fix.accel = FB_ACCEL_SUN_CGTHREE;
+}
+
+static void cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo *var,
+				    struct sbus_dev *sdev)
+{
+	char buffer[40];
+	char *p;
+	int ww, hh;
+
+	*buffer = 0;
+	prom_getstring(sdev->prom_node, "params", buffer, sizeof(buffer));
+	if (*buffer) {
+		ww = simple_strtoul(buffer, &p, 10);
+		if (ww && *p == 'x') {
+			hh = simple_strtoul(p + 1, &p, 10);
+			if (hh && *p == '-') {
+				if (var->xres != ww ||
+				    var->yres != hh) {
+					var->xres = var->xres_virtual = ww;
+					var->yres = var->yres_virtual = hh;
+				}
+			}
+		}
+	}
+}
+
+static u8 cg3regvals_66hz[] __initdata = {	/* 1152 x 900, 66 Hz */
+	0x14, 0xbb,	0x15, 0x2b,	0x16, 0x04,	0x17, 0x14,
+	0x18, 0xae,	0x19, 0x03,	0x1a, 0xa8,	0x1b, 0x24,
+	0x1c, 0x01,	0x1d, 0x05,	0x1e, 0xff,	0x1f, 0x01,
+	0x10, 0x20,	0
+};
+
+static u8 cg3regvals_76hz[] __initdata = {	/* 1152 x 900, 76 Hz */
+	0x14, 0xb7,	0x15, 0x27,	0x16, 0x03,	0x17, 0x0f,
+	0x18, 0xae,	0x19, 0x03,	0x1a, 0xae,	0x1b, 0x2a,
+	0x1c, 0x01,	0x1d, 0x09,	0x1e, 0xff,	0x1f, 0x01,
+	0x10, 0x24,	0
+};
+
+static u8 cg3regvals_rdi[] __initdata = {	/* 640 x 480, cgRDI */
+	0x14, 0x70,	0x15, 0x20,	0x16, 0x08,	0x17, 0x10,
+	0x18, 0x06,	0x19, 0x02,	0x1a, 0x31,	0x1b, 0x51,
+	0x1c, 0x06,	0x1d, 0x0c,	0x1e, 0xff,	0x1f, 0x01,
+	0x10, 0x22,	0
+};
+
+static u8 *cg3_regvals[] __initdata = {
+	cg3regvals_66hz, cg3regvals_76hz, cg3regvals_rdi
+};
+
+static u_char cg3_dacvals[] __initdata = {
+	4, 0xff,	5, 0x00,	6, 0x70,	7, 0x00,	0
+};
+
+static void cg3_do_default_mode(struct cg3_par *par)
+{
+	enum cg3_type type;
+	u8 *p;
+
+	if (par->flags & CG3_FLAG_RDI)
+		type = CG3_RDI;
+	else {
+		u8 status = sbus_readb(&par->regs->status), mon;
+		if ((status & CG3_SR_ID_MASK) == CG3_SR_ID_COLOR) {
+			mon = status & CG3_SR_RES_MASK;
+			if (mon == CG3_SR_1152_900_76_A ||
+			    mon == CG3_SR_1152_900_76_B)
+				type = CG3_AT_76HZ;
+			else
+				type = CG3_AT_66HZ;
+		} else {
+			prom_printf("cgthree: can't handle SR %02x\n",
+				    status);
+			prom_halt();
+			return;
+		}
+	}
+
+	for (p = cg3_regvals[type]; *p; p += 2) {
+		u8 __iomem *regp = &((u8 __iomem *)par->regs)[p[0]];
+		sbus_writeb(p[1], regp);
+	}
+	for (p = cg3_dacvals; *p; p += 2) {
+		volatile u8 __iomem *regp;
+
+		regp = (volatile u8 __iomem *)&par->regs->cmap.addr;
+		sbus_writeb(p[0], regp);
+		regp = (volatile u8 __iomem *)&par->regs->cmap.control;
+		sbus_writeb(p[1], regp);
+	}
+}
+
+struct all_info {
+	struct fb_info info;
+	struct cg3_par par;
+	struct list_head list;
+};
+static LIST_HEAD(cg3_list);
+
+static void cg3_init_one(struct sbus_dev *sdev)
+{
+	struct all_info *all;
+	int linebytes;
+
+	all = kmalloc(sizeof(*all), GFP_KERNEL);
+	if (!all) {
+		printk(KERN_ERR "cg3: Cannot allocate memory.\n");
+		return;
+	}
+	memset(all, 0, sizeof(*all));
+
+	INIT_LIST_HEAD(&all->list);
+
+	spin_lock_init(&all->par.lock);
+	all->par.sdev = sdev;
+
+	all->par.physbase = sdev->reg_addrs[0].phys_addr;
+
+	sbusfb_fill_var(&all->info.var, sdev->prom_node, 8);
+	all->info.var.red.length = 8;
+	all->info.var.green.length = 8;
+	all->info.var.blue.length = 8;
+	if (!strcmp(sdev->prom_name, "cgRDI"))
+		all->par.flags |= CG3_FLAG_RDI;
+	if (all->par.flags & CG3_FLAG_RDI)
+		cg3_rdi_maybe_fixup_var(&all->info.var, sdev);
+
+	linebytes = prom_getintdefault(sdev->prom_node, "linebytes",
+				       all->info.var.xres);
+	all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
+
+	all->par.regs = sbus_ioremap(&sdev->resource[0], CG3_REGS_OFFSET,
+			     sizeof(struct cg3_regs), "cg3 regs");
+
+	all->info.flags = FBINFO_DEFAULT;
+	all->info.fbops = &cg3_ops;
+#ifdef CONFIG_SPARC32
+	all->info.screen_base = (char __iomem *)
+		prom_getintdefault(sdev->prom_node, "address", 0);
+#endif
+	if (!all->info.screen_base)
+		all->info.screen_base =
+			sbus_ioremap(&sdev->resource[0], CG3_RAM_OFFSET,
+				     all->par.fbsize, "cg3 ram");
+	all->info.par = &all->par;
+
+	cg3_blank(0, &all->info);
+
+	if (!prom_getbool(sdev->prom_node, "width"))
+		cg3_do_default_mode(&all->par);
+
+	if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
+		printk(KERN_ERR "cg3: Could not allocate color map.\n");
+		kfree(all);
+		return;
+	}
+	fb_set_cmap(&all->info.cmap, &all->info);
+
+	cg3_init_fix(&all->info, linebytes);
+
+	if (register_framebuffer(&all->info) < 0) {
+		printk(KERN_ERR "cg3: Could not register framebuffer.\n");
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+		return;
+	}
+
+	list_add(&all->list, &cg3_list);
+
+	printk("cg3: %s at %lx:%lx\n",
+	       sdev->prom_name,
+	       (long) sdev->reg_addrs[0].which_io,
+	       (long) sdev->reg_addrs[0].phys_addr);
+}
+
+int __init cg3_init(void)
+{
+	struct sbus_bus *sbus;
+	struct sbus_dev *sdev;
+
+	if (fb_get_options("cg3fb", NULL))
+		return -ENODEV;
+
+	for_all_sbusdev(sdev, sbus) {
+		if (!strcmp(sdev->prom_name, "cgthree") ||
+		    !strcmp(sdev->prom_name, "cgRDI"))
+			cg3_init_one(sdev);
+	}
+
+	return 0;
+}
+
+void __exit cg3_exit(void)
+{
+	struct list_head *pos, *tmp;
+
+	list_for_each_safe(pos, tmp, &cg3_list) {
+		struct all_info *all = list_entry(pos, typeof(*all), list);
+
+		unregister_framebuffer(&all->info);
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+	}
+}
+
+int __init
+cg3_setup(char *arg)
+{
+	/* No cmdline options yet... */
+	return 0;
+}
+
+module_init(cg3_init);
+
+#ifdef MODULE
+module_exit(cg3_exit);
+#endif
+
+MODULE_DESCRIPTION("framebuffer driver for CGthree chipsets");
+MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c
new file mode 100644
index 0000000..49a2545
--- /dev/null
+++ b/drivers/video/cg6.c
@@ -0,0 +1,801 @@
+/* cg6.c: CGSIX (GX, GXplus, TGX) frame buffer driver
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ *
+ * Driver layout based loosely on tgafb.c, see that file for credits.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/mm.h>
+
+#include <asm/io.h>
+#include <asm/sbus.h>
+#include <asm/oplib.h>
+#include <asm/fbio.h>
+
+#include "sbuslib.h"
+
+/*
+ * Local functions.
+ */
+
+static int cg6_setcolreg(unsigned, unsigned, unsigned, unsigned,
+			 unsigned, struct fb_info *);
+static int cg6_blank(int, struct fb_info *);
+
+static void cg6_imageblit(struct fb_info *, const struct fb_image *);
+static void cg6_fillrect(struct fb_info *, const struct fb_fillrect *);
+static int cg6_sync(struct fb_info *);
+static int cg6_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
+static int cg6_ioctl(struct inode *, struct file *, unsigned int,
+		     unsigned long, struct fb_info *);
+
+/*
+ *  Frame buffer operations
+ */
+
+static struct fb_ops cg6_ops = {
+	.owner			= THIS_MODULE,
+	.fb_setcolreg		= cg6_setcolreg,
+	.fb_blank		= cg6_blank,
+	.fb_fillrect		= cg6_fillrect,
+	.fb_copyarea		= cfb_copyarea,
+	.fb_imageblit		= cg6_imageblit,
+	.fb_sync		= cg6_sync,
+	.fb_mmap		= cg6_mmap,
+	.fb_ioctl		= cg6_ioctl,
+	.fb_cursor		= soft_cursor,
+};
+
+/* Offset of interesting structures in the OBIO space */
+/*
+ * Brooktree is the video dac and is funny to program on the cg6.
+ * (it's even funnier on the cg3)
+ * The FBC could be the frame buffer control
+ * The FHC could is the frame buffer hardware control.
+ */
+#define CG6_ROM_OFFSET       0x0UL
+#define CG6_BROOKTREE_OFFSET 0x200000UL
+#define CG6_DHC_OFFSET       0x240000UL
+#define CG6_ALT_OFFSET       0x280000UL
+#define CG6_FHC_OFFSET       0x300000UL
+#define CG6_THC_OFFSET       0x301000UL
+#define CG6_FBC_OFFSET       0x700000UL
+#define CG6_TEC_OFFSET       0x701000UL
+#define CG6_RAM_OFFSET       0x800000UL
+
+/* FHC definitions */
+#define CG6_FHC_FBID_SHIFT           24
+#define CG6_FHC_FBID_MASK            255
+#define CG6_FHC_REV_SHIFT            20
+#define CG6_FHC_REV_MASK             15
+#define CG6_FHC_FROP_DISABLE         (1 << 19)
+#define CG6_FHC_ROW_DISABLE          (1 << 18)
+#define CG6_FHC_SRC_DISABLE          (1 << 17)
+#define CG6_FHC_DST_DISABLE          (1 << 16)
+#define CG6_FHC_RESET                (1 << 15)
+#define CG6_FHC_LITTLE_ENDIAN        (1 << 13)
+#define CG6_FHC_RES_MASK             (3 << 11)
+#define CG6_FHC_1024                 (0 << 11)
+#define CG6_FHC_1152                 (1 << 11)
+#define CG6_FHC_1280                 (2 << 11)
+#define CG6_FHC_1600                 (3 << 11)
+#define CG6_FHC_CPU_MASK             (3 << 9)
+#define CG6_FHC_CPU_SPARC            (0 << 9)
+#define CG6_FHC_CPU_68020            (1 << 9)
+#define CG6_FHC_CPU_386              (2 << 9)
+#define CG6_FHC_TEST		     (1 << 8)
+#define CG6_FHC_TEST_X_SHIFT	     4
+#define CG6_FHC_TEST_X_MASK	     15
+#define CG6_FHC_TEST_Y_SHIFT	     0
+#define CG6_FHC_TEST_Y_MASK	     15
+
+/* FBC mode definitions */
+#define CG6_FBC_BLIT_IGNORE		0x00000000
+#define CG6_FBC_BLIT_NOSRC		0x00100000
+#define CG6_FBC_BLIT_SRC		0x00200000
+#define CG6_FBC_BLIT_ILLEGAL		0x00300000
+#define CG6_FBC_BLIT_MASK		0x00300000
+
+#define CG6_FBC_VBLANK			0x00080000
+
+#define CG6_FBC_MODE_IGNORE		0x00000000
+#define CG6_FBC_MODE_COLOR8		0x00020000
+#define CG6_FBC_MODE_COLOR1		0x00040000
+#define CG6_FBC_MODE_HRMONO		0x00060000
+#define CG6_FBC_MODE_MASK		0x00060000
+
+#define CG6_FBC_DRAW_IGNORE		0x00000000
+#define CG6_FBC_DRAW_RENDER		0x00008000
+#define CG6_FBC_DRAW_PICK		0x00010000
+#define CG6_FBC_DRAW_ILLEGAL		0x00018000
+#define CG6_FBC_DRAW_MASK		0x00018000
+
+#define CG6_FBC_BWRITE0_IGNORE		0x00000000
+#define CG6_FBC_BWRITE0_ENABLE		0x00002000
+#define CG6_FBC_BWRITE0_DISABLE		0x00004000
+#define CG6_FBC_BWRITE0_ILLEGAL		0x00006000
+#define CG6_FBC_BWRITE0_MASK		0x00006000
+
+#define CG6_FBC_BWRITE1_IGNORE		0x00000000
+#define CG6_FBC_BWRITE1_ENABLE		0x00000800
+#define CG6_FBC_BWRITE1_DISABLE		0x00001000
+#define CG6_FBC_BWRITE1_ILLEGAL		0x00001800
+#define CG6_FBC_BWRITE1_MASK		0x00001800
+
+#define CG6_FBC_BREAD_IGNORE		0x00000000
+#define CG6_FBC_BREAD_0			0x00000200
+#define CG6_FBC_BREAD_1			0x00000400
+#define CG6_FBC_BREAD_ILLEGAL		0x00000600
+#define CG6_FBC_BREAD_MASK		0x00000600
+
+#define CG6_FBC_BDISP_IGNORE		0x00000000
+#define CG6_FBC_BDISP_0			0x00000080
+#define CG6_FBC_BDISP_1			0x00000100
+#define CG6_FBC_BDISP_ILLEGAL		0x00000180
+#define CG6_FBC_BDISP_MASK		0x00000180
+
+#define CG6_FBC_INDEX_MOD		0x00000040
+#define CG6_FBC_INDEX_MASK		0x00000030
+
+/* THC definitions */
+#define CG6_THC_MISC_REV_SHIFT       16
+#define CG6_THC_MISC_REV_MASK        15
+#define CG6_THC_MISC_RESET           (1 << 12)
+#define CG6_THC_MISC_VIDEO           (1 << 10)
+#define CG6_THC_MISC_SYNC            (1 << 9)
+#define CG6_THC_MISC_VSYNC           (1 << 8)
+#define CG6_THC_MISC_SYNC_ENAB       (1 << 7)
+#define CG6_THC_MISC_CURS_RES        (1 << 6)
+#define CG6_THC_MISC_INT_ENAB        (1 << 5)
+#define CG6_THC_MISC_INT             (1 << 4)
+#define CG6_THC_MISC_INIT            0x9f
+
+/* The contents are unknown */
+struct cg6_tec {
+	volatile int tec_matrix;
+	volatile int tec_clip;
+	volatile int tec_vdc;
+};
+
+struct cg6_thc {
+        uint thc_pad0[512];
+	volatile uint thc_hs;		/* hsync timing */
+	volatile uint thc_hsdvs;
+	volatile uint thc_hd;
+	volatile uint thc_vs;		/* vsync timing */
+	volatile uint thc_vd;
+	volatile uint thc_refresh;
+	volatile uint thc_misc;
+	uint thc_pad1[56];
+	volatile uint thc_cursxy;	/* cursor x,y position (16 bits each) */
+	volatile uint thc_cursmask[32];	/* cursor mask bits */
+	volatile uint thc_cursbits[32];	/* what to show where mask enabled */
+};
+
+struct cg6_fbc {
+	u32		xxx0[1];
+	volatile u32	mode;
+	volatile u32	clip;
+	u32		xxx1[1];	    
+	volatile u32	s;
+	volatile u32	draw;
+	volatile u32	blit;
+	volatile u32	font;
+	u32		xxx2[24];
+	volatile u32	x0, y0, z0, color0;
+	volatile u32	x1, y1, z1, color1;
+	volatile u32	x2, y2, z2, color2;
+	volatile u32	x3, y3, z3, color3;
+	volatile u32	offx, offy;
+	u32		xxx3[2];
+	volatile u32	incx, incy;
+	u32		xxx4[2];
+	volatile u32	clipminx, clipminy;
+	u32		xxx5[2];
+	volatile u32	clipmaxx, clipmaxy;
+	u32		xxx6[2];
+	volatile u32	fg;
+	volatile u32	bg;
+	volatile u32	alu;
+	volatile u32	pm;
+	volatile u32	pixelm;
+	u32		xxx7[2];
+	volatile u32	patalign;
+	volatile u32	pattern[8];
+	u32		xxx8[432];
+	volatile u32	apointx, apointy, apointz;
+	u32		xxx9[1];
+	volatile u32	rpointx, rpointy, rpointz;
+	u32		xxx10[5];
+	volatile u32	pointr, pointg, pointb, pointa;
+	volatile u32	alinex, aliney, alinez;
+	u32		xxx11[1];
+	volatile u32	rlinex, rliney, rlinez;
+	u32		xxx12[5];
+	volatile u32	liner, lineg, lineb, linea;
+	volatile u32	atrix, atriy, atriz;
+	u32		xxx13[1];
+	volatile u32	rtrix, rtriy, rtriz;
+	u32		xxx14[5];
+	volatile u32	trir, trig, trib, tria;
+	volatile u32	aquadx, aquady, aquadz;
+	u32		xxx15[1];
+	volatile u32	rquadx, rquady, rquadz;
+	u32		xxx16[5];
+	volatile u32	quadr, quadg, quadb, quada;
+	volatile u32	arectx, arecty, arectz;
+	u32		xxx17[1];
+	volatile u32	rrectx, rrecty, rrectz;
+	u32		xxx18[5];
+	volatile u32	rectr, rectg, rectb, recta;
+};
+
+struct bt_regs {
+	volatile u32 addr;
+	volatile u32 color_map;
+	volatile u32 control;
+	volatile u32 cursor;
+};
+
+struct cg6_par {
+	spinlock_t		lock;
+	struct bt_regs		__iomem *bt;
+	struct cg6_fbc		__iomem *fbc;
+	struct cg6_thc		__iomem *thc;
+	struct cg6_tec		__iomem *tec;
+	volatile u32		__iomem *fhc;
+
+	u32			flags;
+#define CG6_FLAG_BLANKED	0x00000001
+
+	unsigned long		physbase;
+	unsigned long		fbsize;
+
+	struct sbus_dev		*sdev;
+	struct list_head	list;
+};
+
+static int cg6_sync(struct fb_info *info)
+{
+	struct cg6_par *par = (struct cg6_par *) info->par;
+	struct cg6_fbc __iomem *fbc = par->fbc;
+	int limit = 10000;
+
+	do {
+		if (!(sbus_readl(&fbc->s) & 0x10000000))
+			break;
+		udelay(10);
+	} while (--limit > 0);
+
+	return 0;
+}
+
+/**
+ *      cg6_fillrect - REQUIRED function. Can use generic routines if 
+ *                     non acclerated hardware and packed pixel based.
+ *                     Draws a rectangle on the screen.               
+ *
+ *      @info: frame buffer structure that represents a single frame buffer
+ *      @rect: structure defining the rectagle and operation.
+ */
+static void cg6_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+	struct cg6_par *par = (struct cg6_par *) info->par;
+	struct cg6_fbc __iomem *fbc = par->fbc;
+	unsigned long flags;
+	s32 val;
+
+	/* XXX doesn't handle ROP_XOR */
+
+	spin_lock_irqsave(&par->lock, flags);
+	cg6_sync(info);
+	sbus_writel(rect->color, &fbc->fg);
+	sbus_writel(~(u32)0, &fbc->pixelm);
+	sbus_writel(0xea80ff00, &fbc->alu);
+	sbus_writel(0, &fbc->s);
+	sbus_writel(0, &fbc->clip);
+	sbus_writel(~(u32)0, &fbc->pm);
+	sbus_writel(rect->dy, &fbc->arecty);
+	sbus_writel(rect->dx, &fbc->arectx);
+	sbus_writel(rect->dy + rect->height, &fbc->arecty);
+	sbus_writel(rect->dx + rect->width, &fbc->arectx);
+	do {
+		val = sbus_readl(&fbc->draw);
+	} while (val < 0 && (val & 0x20000000));
+	spin_unlock_irqrestore(&par->lock, flags);
+}
+
+/**
+ *      cg6_imageblit - REQUIRED function. Can use generic routines if
+ *                      non acclerated hardware and packed pixel based.
+ *                      Copies a image from system memory to the screen. 
+ *
+ *      @info: frame buffer structure that represents a single frame buffer
+ *      @image: structure defining the image.
+ */
+static void cg6_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	struct cg6_par *par = (struct cg6_par *) info->par;
+	struct cg6_fbc __iomem *fbc = par->fbc;
+	const u8 *data = image->data;
+	unsigned long flags;
+	u32 x, y;
+	int i, width;
+
+	if (image->depth > 1) {
+		cfb_imageblit(info, image);
+		return;
+	}
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	cg6_sync(info);
+
+	sbus_writel(image->fg_color, &fbc->fg);
+	sbus_writel(image->bg_color, &fbc->bg);
+	sbus_writel(0x140000, &fbc->mode);
+	sbus_writel(0xe880fc30, &fbc->alu);
+	sbus_writel(~(u32)0, &fbc->pixelm);
+	sbus_writel(0, &fbc->s);
+	sbus_writel(0, &fbc->clip);
+	sbus_writel(0xff, &fbc->pm);
+	sbus_writel(32, &fbc->incx);
+	sbus_writel(0, &fbc->incy);
+
+	x = image->dx;
+	y = image->dy;
+	for (i = 0; i < image->height; i++) {
+		width = image->width;
+
+		while (width >= 32) {
+			u32 val;
+
+			sbus_writel(y, &fbc->y0);
+			sbus_writel(x, &fbc->x0);
+			sbus_writel(x + 32 - 1, &fbc->x1);
+			
+			val = ((u32)data[0] << 24) |
+			      ((u32)data[1] << 16) |
+			      ((u32)data[2] <<  8) |
+			      ((u32)data[3] <<  0);
+			sbus_writel(val, &fbc->font);
+
+			data += 4;
+			x += 32;
+			width -= 32;
+		}
+		if (width) {
+			u32 val;
+
+			sbus_writel(y, &fbc->y0);
+			sbus_writel(x, &fbc->x0);
+			sbus_writel(x + width - 1, &fbc->x1);
+			if (width <= 8) {
+				val = (u32) data[0] << 24;
+				data += 1;
+			} else if (width <= 16) {
+				val = ((u32) data[0] << 24) |
+				      ((u32) data[1] << 16);
+				data += 2;
+			} else {
+				val = ((u32) data[0] << 24) |
+				      ((u32) data[1] << 16) |
+				      ((u32) data[2] <<  8);
+				data += 3;
+			}
+			sbus_writel(val, &fbc->font);
+		}
+
+		y += 1;
+		x = image->dx;
+	}
+
+	spin_unlock_irqrestore(&par->lock, flags);
+}
+
+/**
+ *      cg6_setcolreg - Optional function. Sets a color register.
+ *      @regno: boolean, 0 copy local, 1 get_user() function
+ *      @red: frame buffer colormap structure
+ *      @green: The green value which can be up to 16 bits wide
+ *      @blue:  The blue value which can be up to 16 bits wide.
+ *      @transp: If supported the alpha value which can be up to 16 bits wide.
+ *      @info: frame buffer info structure
+ */
+static int cg6_setcolreg(unsigned regno,
+			 unsigned red, unsigned green, unsigned blue,
+			 unsigned transp, struct fb_info *info)
+{
+	struct cg6_par *par = (struct cg6_par *) info->par;
+	struct bt_regs __iomem *bt = par->bt;
+	unsigned long flags;
+
+	if (regno >= 256)
+		return 1;
+
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	sbus_writel((u32)regno << 24, &bt->addr);
+	sbus_writel((u32)red << 24, &bt->color_map);
+	sbus_writel((u32)green << 24, &bt->color_map);
+	sbus_writel((u32)blue << 24, &bt->color_map);
+
+	spin_unlock_irqrestore(&par->lock, flags);
+
+	return 0;
+}
+
+/**
+ *      cg6_blank - Optional function.  Blanks the display.
+ *      @blank_mode: the blank mode we want.
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+cg6_blank(int blank, struct fb_info *info)
+{
+	struct cg6_par *par = (struct cg6_par *) info->par;
+	struct cg6_thc __iomem *thc = par->thc;
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	switch (blank) {
+	case FB_BLANK_UNBLANK: /* Unblanking */
+		val = sbus_readl(&thc->thc_misc);
+		val |= CG6_THC_MISC_VIDEO;
+		sbus_writel(val, &thc->thc_misc);
+		par->flags &= ~CG6_FLAG_BLANKED;
+		break;
+
+	case FB_BLANK_NORMAL: /* Normal blanking */
+	case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
+	case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
+	case FB_BLANK_POWERDOWN: /* Poweroff */
+		val = sbus_readl(&thc->thc_misc);
+		val &= ~CG6_THC_MISC_VIDEO;
+		sbus_writel(val, &thc->thc_misc);
+		par->flags |= CG6_FLAG_BLANKED;
+		break;
+	}
+
+	spin_unlock_irqrestore(&par->lock, flags);
+
+	return 0;
+}
+
+static struct sbus_mmap_map cg6_mmap_map[] = {
+	{
+		.voff	= CG6_FBC,
+		.poff	= CG6_FBC_OFFSET,
+		.size	= PAGE_SIZE
+	},
+	{
+		.voff	= CG6_TEC,
+		.poff	= CG6_TEC_OFFSET,
+		.size	= PAGE_SIZE
+	},
+	{
+		.voff	= CG6_BTREGS,
+		.poff	= CG6_BROOKTREE_OFFSET,
+		.size	= PAGE_SIZE
+	},
+	{
+		.voff	= CG6_FHC,
+		.poff	= CG6_FHC_OFFSET,
+		.size	= PAGE_SIZE
+	},
+	{
+		.voff	= CG6_THC,
+		.poff	= CG6_THC_OFFSET,
+		.size	= PAGE_SIZE
+	},
+	{
+		.voff	= CG6_ROM,
+		.poff	= CG6_ROM_OFFSET,
+		.size	= 0x10000
+	},
+	{
+		.voff	= CG6_RAM,
+		.poff	= CG6_RAM_OFFSET,
+		.size	= SBUS_MMAP_FBSIZE(1)
+	},
+	{
+		.voff	= CG6_DHC,
+		.poff	= CG6_DHC_OFFSET,
+		.size	= 0x40000
+	},
+	{ .size	= 0 }
+};
+
+static int cg6_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+{
+	struct cg6_par *par = (struct cg6_par *)info->par;
+
+	return sbusfb_mmap_helper(cg6_mmap_map,
+				  par->physbase, par->fbsize,
+				  par->sdev->reg_addrs[0].which_io,
+				  vma);
+}
+
+static int cg6_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		     unsigned long arg, struct fb_info *info)
+{
+	struct cg6_par *par = (struct cg6_par *) info->par;
+
+	return sbusfb_ioctl_helper(cmd, arg, info,
+				   FBTYPE_SUNFAST_COLOR, 8, par->fbsize);
+}
+
+/*
+ *  Initialisation
+ */
+
+static void
+cg6_init_fix(struct fb_info *info, int linebytes)
+{
+	struct cg6_par *par = (struct cg6_par *)info->par;
+	const char *cg6_cpu_name, *cg6_card_name;
+	u32 conf;
+
+	conf = sbus_readl(par->fhc);
+	switch(conf & CG6_FHC_CPU_MASK) {
+	case CG6_FHC_CPU_SPARC:
+		cg6_cpu_name = "sparc";
+		break;
+	case CG6_FHC_CPU_68020:
+		cg6_cpu_name = "68020";
+		break;
+	default:
+		cg6_cpu_name = "i386";
+		break;
+	};
+	if (((conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK) >= 11) {
+		if (par->fbsize <= 0x100000) {
+			cg6_card_name = "TGX";
+		} else {
+			cg6_card_name = "TGX+";
+		}
+	} else {
+		if (par->fbsize <= 0x100000) {
+			cg6_card_name = "GX";
+		} else {
+			cg6_card_name = "GX+";
+		}
+	}
+
+	sprintf(info->fix.id, "%s %s", cg6_card_name, cg6_cpu_name);
+	info->fix.id[sizeof(info->fix.id)-1] = 0;
+
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+
+	info->fix.line_length = linebytes;
+
+	info->fix.accel = FB_ACCEL_SUN_CGSIX;
+}
+
+/* Initialize Brooktree DAC */
+static void cg6_bt_init(struct cg6_par *par)
+{
+	struct bt_regs __iomem *bt = par->bt;
+
+	sbus_writel(0x04 << 24, &bt->addr);         /* color planes */
+	sbus_writel(0xff << 24, &bt->control);
+	sbus_writel(0x05 << 24, &bt->addr);
+	sbus_writel(0x00 << 24, &bt->control);
+	sbus_writel(0x06 << 24, &bt->addr);         /* overlay plane */
+	sbus_writel(0x73 << 24, &bt->control);
+	sbus_writel(0x07 << 24, &bt->addr);
+	sbus_writel(0x00 << 24, &bt->control);
+}
+
+static void cg6_chip_init(struct fb_info *info)
+{
+	struct cg6_par *par = (struct cg6_par *) info->par;
+	struct cg6_tec __iomem *tec = par->tec;
+	struct cg6_fbc __iomem *fbc = par->fbc;
+	u32 rev, conf, mode, tmp;
+	int i;
+	
+	/* Turn off stuff in the Transform Engine. */
+	sbus_writel(0, &tec->tec_matrix);
+	sbus_writel(0, &tec->tec_clip);
+	sbus_writel(0, &tec->tec_vdc);
+
+	/* Take care of bugs in old revisions. */
+	rev = (sbus_readl(par->fhc) >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK;
+	if (rev < 5) {
+		conf = (sbus_readl(par->fhc) & CG6_FHC_RES_MASK) |
+			CG6_FHC_CPU_68020 | CG6_FHC_TEST |
+			(11 << CG6_FHC_TEST_X_SHIFT) |
+			(11 << CG6_FHC_TEST_Y_SHIFT);
+		if (rev < 2)
+			conf |= CG6_FHC_DST_DISABLE;
+		sbus_writel(conf, par->fhc);
+	}
+
+	/* Set things in the FBC. Bad things appear to happen if we do
+	 * back to back store/loads on the mode register, so copy it
+	 * out instead. */
+	mode = sbus_readl(&fbc->mode);
+	do {
+		i = sbus_readl(&fbc->s);
+	} while (i & 0x10000000);
+	mode &= ~(CG6_FBC_BLIT_MASK | CG6_FBC_MODE_MASK |
+		       CG6_FBC_DRAW_MASK | CG6_FBC_BWRITE0_MASK |
+		       CG6_FBC_BWRITE1_MASK | CG6_FBC_BREAD_MASK |
+		       CG6_FBC_BDISP_MASK);
+	mode |= (CG6_FBC_BLIT_SRC | CG6_FBC_MODE_COLOR8 |
+		      CG6_FBC_DRAW_RENDER | CG6_FBC_BWRITE0_ENABLE |
+		      CG6_FBC_BWRITE1_DISABLE | CG6_FBC_BREAD_0 |
+		      CG6_FBC_BDISP_0);
+	sbus_writel(mode, &fbc->mode);
+
+	sbus_writel(0, &fbc->clip);
+	sbus_writel(0, &fbc->offx);
+	sbus_writel(0, &fbc->offy);
+	sbus_writel(0, &fbc->clipminx);
+	sbus_writel(0, &fbc->clipminy);
+	sbus_writel(info->var.xres - 1, &fbc->clipmaxx);
+	sbus_writel(info->var.yres - 1, &fbc->clipmaxy);
+
+	/* Disable cursor in Brooktree DAC. */
+	sbus_writel(0x06 << 24, &par->bt->addr);
+	tmp = sbus_readl(&par->bt->control);
+	tmp &= ~(0x03 << 24);
+	sbus_writel(tmp, &par->bt->control);
+}
+
+struct all_info {
+	struct fb_info info;
+	struct cg6_par par;
+	struct list_head list;
+};
+static LIST_HEAD(cg6_list);
+
+static void cg6_init_one(struct sbus_dev *sdev)
+{
+	struct all_info *all;
+	int linebytes;
+
+	all = kmalloc(sizeof(*all), GFP_KERNEL);
+	if (!all) {
+		printk(KERN_ERR "cg6: Cannot allocate memory.\n");
+		return;
+	}
+	memset(all, 0, sizeof(*all));
+
+	INIT_LIST_HEAD(&all->list);
+
+	spin_lock_init(&all->par.lock);
+	all->par.sdev = sdev;
+
+	all->par.physbase = sdev->reg_addrs[0].phys_addr;
+
+	sbusfb_fill_var(&all->info.var, sdev->prom_node, 8);
+	all->info.var.red.length = 8;
+	all->info.var.green.length = 8;
+	all->info.var.blue.length = 8;
+
+	linebytes = prom_getintdefault(sdev->prom_node, "linebytes",
+				       all->info.var.xres);
+	all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
+	if (prom_getbool(sdev->prom_node, "dblbuf"))
+		all->par.fbsize *= 4;
+
+	all->par.fbc = sbus_ioremap(&sdev->resource[0], CG6_FBC_OFFSET,
+			     4096, "cgsix fbc");
+	all->par.tec = sbus_ioremap(&sdev->resource[0], CG6_TEC_OFFSET,
+			     sizeof(struct cg6_tec), "cgsix tec");
+	all->par.thc = sbus_ioremap(&sdev->resource[0], CG6_THC_OFFSET,
+			     sizeof(struct cg6_thc), "cgsix thc");
+	all->par.bt = sbus_ioremap(&sdev->resource[0], CG6_BROOKTREE_OFFSET,
+			     sizeof(struct bt_regs), "cgsix dac");
+	all->par.fhc = sbus_ioremap(&sdev->resource[0], CG6_FHC_OFFSET,
+			     sizeof(u32), "cgsix fhc");
+
+	all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT |
+                          FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
+	all->info.fbops = &cg6_ops;
+#ifdef CONFIG_SPARC32
+	all->info.screen_base = (char __iomem *)
+		prom_getintdefault(sdev->prom_node, "address", 0);
+#endif
+	if (!all->info.screen_base)
+		all->info.screen_base = 
+			sbus_ioremap(&sdev->resource[0], CG6_RAM_OFFSET,
+				     all->par.fbsize, "cgsix ram");
+	all->info.par = &all->par;
+
+	all->info.var.accel_flags = FB_ACCELF_TEXT;
+
+	cg6_bt_init(&all->par);
+	cg6_chip_init(&all->info);
+	cg6_blank(0, &all->info);
+
+	if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
+		printk(KERN_ERR "cg6: Could not allocate color map.\n");
+		kfree(all);
+		return;
+	}
+
+	fb_set_cmap(&all->info.cmap, &all->info);
+	cg6_init_fix(&all->info, linebytes);
+
+	if (register_framebuffer(&all->info) < 0) {
+		printk(KERN_ERR "cg6: Could not register framebuffer.\n");
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+		return;
+	}
+
+	list_add(&all->list, &cg6_list);
+
+	printk("cg6: CGsix [%s] at %lx:%lx\n",
+	       all->info.fix.id,
+	       (long) sdev->reg_addrs[0].which_io,
+	       (long) sdev->reg_addrs[0].phys_addr);
+}
+
+int __init cg6_init(void)
+{
+	struct sbus_bus *sbus;
+	struct sbus_dev *sdev;
+
+	if (fb_get_options("cg6fb", NULL))
+		return -ENODEV;
+
+	for_all_sbusdev(sdev, sbus) {
+		if (!strcmp(sdev->prom_name, "cgsix") ||
+		    !strcmp(sdev->prom_name, "cgthree+"))
+			cg6_init_one(sdev);
+	}
+
+	return 0;
+}
+
+void __exit cg6_exit(void)
+{
+	struct list_head *pos, *tmp;
+
+	list_for_each_safe(pos, tmp, &cg6_list) {
+		struct all_info *all = list_entry(pos, typeof(*all), list);
+
+		unregister_framebuffer(&all->info);
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+	}
+}
+
+int __init
+cg6_setup(char *arg)
+{
+	/* No cmdline options yet... */
+	return 0;
+}
+
+module_init(cg6_init);
+
+#ifdef MODULE
+module_exit(cg6_exit);
+#endif
+
+MODULE_DESCRIPTION("framebuffer driver for CGsix chipsets");
+MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c
new file mode 100644
index 0000000..ab98f22
--- /dev/null
+++ b/drivers/video/chipsfb.c
@@ -0,0 +1,522 @@
+/*
+ *  drivers/video/chipsfb.c -- frame buffer device for
+ *  Chips & Technologies 65550 chip.
+ *
+ *  Copyright (C) 1998-2002 Paul Mackerras
+ *
+ *  This file is derived from the Powermac "chips" driver:
+ *  Copyright (C) 1997 Fabio Riccardi.
+ *  And from the frame buffer device for Open Firmware-initialized devices:
+ *  Copyright (C) 1997 Geert Uytterhoeven.
+ *
+ *  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 <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+#ifdef CONFIG_PMAC_PBOOK
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#endif
+
+/*
+ * Since we access the display with inb/outb to fixed port numbers,
+ * we can only handle one 6555x chip.  -- paulus
+ */
+static struct fb_info chipsfb_info;
+
+#define write_ind(num, val, ap, dp)	do { \
+	outb((num), (ap)); outb((val), (dp)); \
+} while (0)
+#define read_ind(num, var, ap, dp)	do { \
+	outb((num), (ap)); var = inb((dp)); \
+} while (0)
+
+/* extension registers */
+#define write_xr(num, val)	write_ind(num, val, 0x3d6, 0x3d7)
+#define read_xr(num, var)	read_ind(num, var, 0x3d6, 0x3d7)
+/* flat panel registers */
+#define write_fr(num, val)	write_ind(num, val, 0x3d0, 0x3d1)
+#define read_fr(num, var)	read_ind(num, var, 0x3d0, 0x3d1)
+/* CRTC registers */
+#define write_cr(num, val)	write_ind(num, val, 0x3d4, 0x3d5)
+#define read_cr(num, var)	read_ind(num, var, 0x3d4, 0x3d5)
+/* graphics registers */
+#define write_gr(num, val)	write_ind(num, val, 0x3ce, 0x3cf)
+#define read_gr(num, var)	read_ind(num, var, 0x3ce, 0x3cf)
+/* sequencer registers */
+#define write_sr(num, val)	write_ind(num, val, 0x3c4, 0x3c5)
+#define read_sr(num, var)	read_ind(num, var, 0x3c4, 0x3c5)
+/* attribute registers - slightly strange */
+#define write_ar(num, val)	do { \
+	inb(0x3da); write_ind(num, val, 0x3c0, 0x3c0); \
+} while (0)
+#define read_ar(num, var)	do { \
+	inb(0x3da); read_ind(num, var, 0x3c0, 0x3c1); \
+} while (0)
+
+#ifdef CONFIG_PMAC_PBOOK
+static unsigned char *save_framebuffer;
+int chips_sleep_notify(struct pmu_sleep_notifier *self, int when);
+static struct pmu_sleep_notifier chips_sleep_notifier = {
+	chips_sleep_notify, SLEEP_LEVEL_VIDEO,
+};
+#endif
+
+/*
+ * Exported functions
+ */
+int chips_init(void);
+
+static int chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *);
+static int chipsfb_check_var(struct fb_var_screeninfo *var,
+			     struct fb_info *info);
+static int chipsfb_set_par(struct fb_info *info);
+static int chipsfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			     u_int transp, struct fb_info *info);
+static int chipsfb_blank(int blank, struct fb_info *info);
+
+static struct fb_ops chipsfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= chipsfb_check_var,
+	.fb_set_par	= chipsfb_set_par,
+	.fb_setcolreg	= chipsfb_setcolreg,
+	.fb_blank	= chipsfb_blank,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+static int chipsfb_check_var(struct fb_var_screeninfo *var,
+			     struct fb_info *info)
+{
+	if (var->xres > 800 || var->yres > 600
+	    || var->xres_virtual > 800 || var->yres_virtual > 600
+	    || (var->bits_per_pixel != 8 && var->bits_per_pixel != 16)
+	    || var->nonstd
+	    || (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+		return -EINVAL;
+
+	var->xres = var->xres_virtual = 800;
+	var->yres = var->yres_virtual = 600;
+
+	return 0;
+}
+
+static int chipsfb_set_par(struct fb_info *info)
+{
+	if (info->var.bits_per_pixel == 16) {
+		write_cr(0x13, 200);		// Set line length (doublewords)
+		write_xr(0x81, 0x14);		// 15 bit (555) color mode
+		write_xr(0x82, 0x00);		// Disable palettes
+		write_xr(0x20, 0x10);		// 16 bit blitter mode
+
+		info->fix.line_length = 800*2;
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+
+		info->var.red.offset = 10;
+		info->var.green.offset = 5;
+		info->var.blue.offset = 0;
+		info->var.red.length = info->var.green.length =
+			info->var.blue.length = 5;
+		
+	} else {
+		/* p->var.bits_per_pixel == 8 */
+		write_cr(0x13, 100);		// Set line length (doublewords)
+		write_xr(0x81, 0x12);		// 8 bit color mode
+		write_xr(0x82, 0x08);		// Graphics gamma enable
+		write_xr(0x20, 0x00);		// 8 bit blitter mode
+
+		info->fix.line_length = 800;
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;		
+
+ 		info->var.red.offset = info->var.green.offset =
+			info->var.blue.offset = 0;
+		info->var.red.length = info->var.green.length =
+			info->var.blue.length = 8;
+		
+	}
+	return 0;
+}
+
+static int chipsfb_blank(int blank, struct fb_info *info)
+{
+#ifdef CONFIG_PMAC_BACKLIGHT
+	// used to disable backlight only for blank > 1, but it seems
+	// useful at blank = 1 too (saves battery, extends backlight life)
+	set_backlight_enable(!blank);
+#endif /* CONFIG_PMAC_BACKLIGHT */
+
+	return 1;	/* get fb_blank to set the colormap to all black */
+}
+
+static int chipsfb_setcolreg(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 >>= 8;
+	green >>= 8;
+	blue >>= 8;
+	outb(regno, 0x3c8);
+	udelay(1);
+	outb(red, 0x3c9);
+	outb(green, 0x3c9);
+	outb(blue, 0x3c9);
+
+	return 0;
+}
+
+struct chips_init_reg {
+	unsigned char addr;
+	unsigned char data;
+};
+
+#define N_ELTS(x)	(sizeof(x) / sizeof(x[0]))
+
+static struct chips_init_reg chips_init_sr[] = {
+	{ 0x00, 0x03 },
+	{ 0x01, 0x01 },
+	{ 0x02, 0x0f },
+	{ 0x04, 0x0e }
+};
+
+static struct chips_init_reg chips_init_gr[] = {
+	{ 0x05, 0x00 },
+	{ 0x06, 0x0d },
+	{ 0x08, 0xff }
+};
+
+static struct chips_init_reg chips_init_ar[] = {
+	{ 0x10, 0x01 },
+	{ 0x12, 0x0f },
+	{ 0x13, 0x00 }
+};
+
+static struct chips_init_reg chips_init_cr[] = {
+	{ 0x00, 0x7f },
+	{ 0x01, 0x63 },
+	{ 0x02, 0x63 },
+	{ 0x03, 0x83 },
+	{ 0x04, 0x66 },
+	{ 0x05, 0x10 },
+	{ 0x06, 0x72 },
+	{ 0x07, 0x3e },
+	{ 0x08, 0x00 },
+	{ 0x09, 0x40 },
+	{ 0x0c, 0x00 },
+	{ 0x0d, 0x00 },
+	{ 0x10, 0x59 },
+	{ 0x11, 0x0d },
+	{ 0x12, 0x57 },
+	{ 0x13, 0x64 },
+	{ 0x14, 0x00 },
+	{ 0x15, 0x57 },
+	{ 0x16, 0x73 },
+	{ 0x17, 0xe3 },
+	{ 0x18, 0xff },
+	{ 0x30, 0x02 },
+	{ 0x31, 0x02 },
+	{ 0x32, 0x02 },
+	{ 0x33, 0x02 },
+	{ 0x40, 0x00 },
+	{ 0x41, 0x00 },
+	{ 0x40, 0x80 }
+};
+
+static struct chips_init_reg chips_init_fr[] = {
+	{ 0x01, 0x02 },
+	{ 0x03, 0x08 },
+	{ 0x04, 0x81 },
+	{ 0x05, 0x21 },
+	{ 0x08, 0x0c },
+	{ 0x0a, 0x74 },
+	{ 0x0b, 0x11 },
+	{ 0x10, 0x0c },
+	{ 0x11, 0xe0 },
+	/* { 0x12, 0x40 }, -- 3400 needs 40, 2400 needs 48, no way to tell */
+	{ 0x20, 0x63 },
+	{ 0x21, 0x68 },
+	{ 0x22, 0x19 },
+	{ 0x23, 0x7f },
+	{ 0x24, 0x68 },
+	{ 0x26, 0x00 },
+	{ 0x27, 0x0f },
+	{ 0x30, 0x57 },
+	{ 0x31, 0x58 },
+	{ 0x32, 0x0d },
+	{ 0x33, 0x72 },
+	{ 0x34, 0x02 },
+	{ 0x35, 0x22 },
+	{ 0x36, 0x02 },
+	{ 0x37, 0x00 }
+};
+
+static struct chips_init_reg chips_init_xr[] = {
+	{ 0xce, 0x00 },		/* set default memory clock */
+	{ 0xcc, 0x43 },		/* memory clock ratio */
+	{ 0xcd, 0x18 },
+	{ 0xce, 0xa1 },
+	{ 0xc8, 0x84 },
+	{ 0xc9, 0x0a },
+	{ 0xca, 0x00 },
+	{ 0xcb, 0x20 },
+	{ 0xcf, 0x06 },
+	{ 0xd0, 0x0e },
+	{ 0x09, 0x01 },
+	{ 0x0a, 0x02 },
+	{ 0x0b, 0x01 },
+	{ 0x20, 0x00 },
+	{ 0x40, 0x03 },
+	{ 0x41, 0x01 },
+	{ 0x42, 0x00 },
+	{ 0x80, 0x82 },
+	{ 0x81, 0x12 },
+	{ 0x82, 0x08 },
+	{ 0xa0, 0x00 },
+	{ 0xa8, 0x00 }
+};
+
+static void __init chips_hw_init(void)
+{
+	int i;
+
+	for (i = 0; i < N_ELTS(chips_init_xr); ++i)
+		write_xr(chips_init_xr[i].addr, chips_init_xr[i].data);
+	outb(0x29, 0x3c2); /* set misc output reg */
+	for (i = 0; i < N_ELTS(chips_init_sr); ++i)
+		write_sr(chips_init_sr[i].addr, chips_init_sr[i].data);
+	for (i = 0; i < N_ELTS(chips_init_gr); ++i)
+		write_gr(chips_init_gr[i].addr, chips_init_gr[i].data);
+	for (i = 0; i < N_ELTS(chips_init_ar); ++i)
+		write_ar(chips_init_ar[i].addr, chips_init_ar[i].data);
+	for (i = 0; i < N_ELTS(chips_init_cr); ++i)
+		write_cr(chips_init_cr[i].addr, chips_init_cr[i].data);
+	for (i = 0; i < N_ELTS(chips_init_fr); ++i)
+		write_fr(chips_init_fr[i].addr, chips_init_fr[i].data);
+}
+
+static struct fb_fix_screeninfo chipsfb_fix __initdata = {
+	.id =		"C&T 65550",
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_PSEUDOCOLOR,
+	.accel =	FB_ACCEL_NONE,
+	.line_length =	800,
+
+// FIXME: Assumes 1MB frame buffer, but 65550 supports 1MB or 2MB.
+// * "3500" PowerBook G3 (the original PB G3) has 2MB.
+// * 2400 has 1MB composed of 2 Mitsubishi M5M4V4265CTP DRAM chips.
+//   Motherboard actually supports 2MB -- there are two blank locations
+//   for a second pair of DRAMs.  (Thanks, Apple!)
+// * 3400 has 1MB (I think).  Don't know if it's expandable.
+// -- Tim Seufert
+	.smem_len =	0x100000,	/* 1MB */
+};
+
+static struct fb_var_screeninfo chipsfb_var __initdata = {
+	.xres = 800,
+	.yres = 600,
+	.xres_virtual = 800,
+	.yres_virtual = 600,
+	.bits_per_pixel = 8,
+	.red = { .length = 8 },
+	.green = { .length = 8 },
+	.blue = { .length = 8 },
+	.height = -1,
+	.width = -1,
+	.vmode = FB_VMODE_NONINTERLACED,
+	.pixclock = 10000,
+	.left_margin = 16,
+	.right_margin = 16,
+	.upper_margin = 16,
+	.lower_margin = 16,
+	.hsync_len = 8,
+	.vsync_len = 8,
+};
+
+static void __init init_chips(struct fb_info *p, unsigned long addr)
+{
+	p->fix = chipsfb_fix;
+	p->fix.smem_start = addr;
+
+	p->var = chipsfb_var;
+
+	p->fbops = &chipsfb_ops;
+	p->flags = FBINFO_DEFAULT;
+
+	fb_alloc_cmap(&p->cmap, 256, 0);
+
+	if (register_framebuffer(p) < 0) {
+		printk(KERN_ERR "C&T 65550 framebuffer failed to register\n");
+		return;
+	}
+
+	printk(KERN_INFO "fb%d: Chips 65550 frame buffer (%dK RAM detected)\n",
+		p->node, p->fix.smem_len / 1024);
+
+	chips_hw_init();
+}
+
+static int __devinit
+chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
+{
+	struct fb_info *p = &chipsfb_info;
+	unsigned long addr, size;
+	unsigned short cmd;
+
+	if ((dp->resource[0].flags & IORESOURCE_MEM) == 0)
+		return -ENODEV;
+	addr = pci_resource_start(dp, 0);
+	size = pci_resource_len(dp, 0);
+	if (addr == 0)
+		return -ENODEV;
+	if (p->screen_base != 0)
+		return -EBUSY;
+	if (!request_mem_region(addr, size, "chipsfb"))
+		return -EBUSY;
+
+#ifdef __BIG_ENDIAN
+	addr += 0x800000;	// Use big-endian aperture
+#endif
+
+	/* we should use pci_enable_device here, but,
+	   the device doesn't declare its I/O ports in its BARs
+	   so pci_enable_device won't turn on I/O responses */
+	pci_read_config_word(dp, PCI_COMMAND, &cmd);
+	cmd |= 3;	/* enable memory and IO space */
+	pci_write_config_word(dp, PCI_COMMAND, cmd);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	/* turn on the backlight */
+	set_backlight_enable(1);
+#endif /* CONFIG_PMAC_BACKLIGHT */
+
+	p->screen_base = __ioremap(addr, 0x200000, _PAGE_NO_CACHE);
+	if (p->screen_base == NULL) {
+		release_mem_region(addr, size);
+		return -ENOMEM;
+	}
+	p->device = &dp->dev;
+	init_chips(p, addr);
+
+#ifdef CONFIG_PMAC_PBOOK
+	pmu_register_sleep_notifier(&chips_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
+
+	/* Clear the entire framebuffer */
+	memset(p->screen_base, 0, 0x100000);
+
+	pci_set_drvdata(dp, p);
+	return 0;
+}
+
+static void __devexit chipsfb_remove(struct pci_dev *dp)
+{
+	struct fb_info *p = pci_get_drvdata(dp);
+
+	if (p != &chipsfb_info || p->screen_base == NULL)
+		return;
+	unregister_framebuffer(p);
+	iounmap(p->screen_base);
+	p->screen_base = NULL;
+	release_mem_region(pci_resource_start(dp, 0), pci_resource_len(dp, 0));
+
+#ifdef CONFIG_PMAC_PBOOK
+	pmu_unregister_sleep_notifier(&chips_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
+}
+
+static struct pci_device_id chipsfb_pci_tbl[] = {
+	{ PCI_VENDOR_ID_CT, PCI_DEVICE_ID_CT_65550, PCI_ANY_ID, PCI_ANY_ID },
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, chipsfb_pci_tbl);
+
+static struct pci_driver chipsfb_driver = {
+	.name =		"chipsfb",
+	.id_table =	chipsfb_pci_tbl,
+	.probe =	chipsfb_pci_init,
+	.remove =	__devexit_p(chipsfb_remove),
+};
+
+int __init chips_init(void)
+{
+	if (fb_get_options("chipsfb", NULL))
+		return -ENODEV;
+
+	return pci_register_driver(&chipsfb_driver);
+}
+
+module_init(chips_init);
+
+static void __exit chipsfb_exit(void)
+{
+	pci_unregister_driver(&chipsfb_driver);
+}
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * Save the contents of the frame buffer when we go to sleep,
+ * and restore it when we wake up again.
+ */
+int
+chips_sleep_notify(struct pmu_sleep_notifier *self, int when)
+{
+	struct fb_info *p = &chipsfb_info;
+	int nb = p->var.yres * p->fix.line_length;
+
+	if (p->screen_base == NULL)
+		return PBOOK_SLEEP_OK;
+
+	switch (when) {
+	case PBOOK_SLEEP_REQUEST:
+		save_framebuffer = vmalloc(nb);
+		if (save_framebuffer == NULL)
+			return PBOOK_SLEEP_REFUSE;
+		break;
+	case PBOOK_SLEEP_REJECT:
+		if (save_framebuffer) {
+			vfree(save_framebuffer);
+			save_framebuffer = NULL;
+		}
+		break;
+	case PBOOK_SLEEP_NOW:
+		chipsfb_blank(1, p);
+		if (save_framebuffer)
+			memcpy(save_framebuffer, p->screen_base, nb);
+		break;
+	case PBOOK_WAKE:
+		if (save_framebuffer) {
+			memcpy(p->screen_base, save_framebuffer, nb);
+			vfree(save_framebuffer);
+			save_framebuffer = NULL;
+		}
+		chipsfb_blank(0, p);
+		break;
+	}
+	return PBOOK_SLEEP_OK;
+}
+#endif /* CONFIG_PMAC_PBOOK */
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c
new file mode 100644
index 0000000..a304042
--- /dev/null
+++ b/drivers/video/cirrusfb.c
@@ -0,0 +1,3326 @@
+/*
+ * drivers/video/cirrusfb.c - driver for Cirrus Logic chipsets
+ *
+ * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com>
+ *
+ * Contributors (thanks, all!)
+ *
+ *	David Eger:
+ *	Overhaul for Linux 2.6
+ *
+ *      Jeff Rugen:
+ *      Major contributions;  Motorola PowerStack (PPC and PCI) support,
+ *      GD54xx, 1280x1024 mode support, change MCLK based on VCLK.
+ *
+ *	Geert Uytterhoeven:
+ *	Excellent code review.
+ *
+ *	Lars Hecking:
+ *	Amiga updates and testing.
+ *
+ * Original cirrusfb author:  Frank Neumann
+ *
+ * Based on retz3fb.c and cirrusfb.c:
+ *      Copyright (C) 1997 Jes Sorensen
+ *      Copyright (C) 1996 Frank Neumann
+ *
+ ***************************************************************
+ *
+ * Format this code with GNU indent '-kr -i8 -pcs' options.
+ *
+ * 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.
+ *
+ */
+
+#define CIRRUSFB_VERSION "2.0-pre2"
+
+#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/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/selection.h>
+#include <asm/pgtable.h>
+
+#ifdef CONFIG_ZORRO
+#include <linux/zorro.h>
+#endif
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#endif
+#ifdef CONFIG_AMIGA
+#include <asm/amigahw.h>
+#endif
+#ifdef CONFIG_PPC_PREP
+#include <asm/processor.h>
+#define isPReP (_machine == _MACH_prep)
+#else
+#define isPReP 0
+#endif
+
+#include "video/vga.h"
+#include "video/cirrus.h"
+
+
+/*****************************************************************
+ *
+ * debugging and utility macros
+ *
+ */
+
+/* enable debug output? */
+/* #define CIRRUSFB_DEBUG 1 */
+
+/* disable runtime assertions? */
+/* #define CIRRUSFB_NDEBUG */
+
+/* debug output */
+#ifdef CIRRUSFB_DEBUG
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+/* debugging assertions */
+#ifndef CIRRUSFB_NDEBUG
+#define assert(expr) \
+        if(!(expr)) { \
+        printk( "Assertion failed! %s,%s,%s,line=%d\n",\
+        #expr,__FILE__,__FUNCTION__,__LINE__); \
+        }
+#else
+#define assert(expr)
+#endif
+
+#ifdef TRUE
+#undef TRUE
+#endif
+#ifdef FALSE
+#undef FALSE
+#endif
+#define TRUE  1
+#define FALSE 0
+
+#define MB_ (1024*1024)
+#define KB_ (1024)
+
+#define MAX_NUM_BOARDS 7
+
+
+/*****************************************************************
+ *
+ * chipset information
+ *
+ */
+
+/* board types */
+typedef enum {
+	BT_NONE = 0,
+	BT_SD64,
+	BT_PICCOLO,
+	BT_PICASSO,
+	BT_SPECTRUM,
+	BT_PICASSO4,	/* GD5446 */
+	BT_ALPINE,	/* GD543x/4x */
+	BT_GD5480,
+	BT_LAGUNA,	/* GD546x */
+} cirrusfb_board_t;
+
+
+/*
+ * per-board-type information, used for enumerating and abstracting
+ * chip-specific information
+ * NOTE: MUST be in the same order as cirrusfb_board_t in order to
+ * use direct indexing on this array
+ * NOTE: '__initdata' cannot be used as some of this info
+ * is required at runtime.  Maybe separate into an init-only and
+ * a run-time table?
+ */
+static const struct cirrusfb_board_info_rec {
+	char *name;		/* ASCII name of chipset */
+	long maxclock[5];		/* maximum video clock */
+	/* for  1/4bpp, 8bpp 15/16bpp, 24bpp, 32bpp - numbers from xorg code */
+	unsigned init_sr07 : 1;	/* init SR07 during init_vgachip() */
+	unsigned init_sr1f : 1; /* write SR1F during init_vgachip() */
+	unsigned scrn_start_bit19 : 1; /* construct bit 19 of screen start address */
+
+	/* initial SR07 value, then for each mode */
+	unsigned char sr07;
+	unsigned char sr07_1bpp;
+	unsigned char sr07_1bpp_mux;
+	unsigned char sr07_8bpp;
+	unsigned char sr07_8bpp_mux;
+
+	unsigned char sr1f;	/* SR1F VGA initial register value */
+} cirrusfb_board_info[] = {
+	[BT_SD64] = {
+		.name			= "CL SD64",
+		.maxclock		= {
+			/* guess */
+			/* the SD64/P4 have a higher max. videoclock */
+			140000, 140000, 140000, 140000, 140000,
+		},
+		.init_sr07		= TRUE,
+		.init_sr1f		= TRUE,
+		.scrn_start_bit19	= TRUE,
+		.sr07			= 0xF0,
+		.sr07_1bpp		= 0xF0,
+		.sr07_8bpp		= 0xF1,
+		.sr1f			= 0x20
+	},
+	[BT_PICCOLO] = {
+		.name			= "CL Piccolo",
+		.maxclock		= {
+			/* guess */
+			90000, 90000, 90000, 90000, 90000
+		},
+		.init_sr07		= TRUE,
+		.init_sr1f		= TRUE,
+		.scrn_start_bit19	= FALSE,
+		.sr07			= 0x80,
+		.sr07_1bpp		= 0x80,
+		.sr07_8bpp		= 0x81,
+		.sr1f			= 0x22
+	},
+	[BT_PICASSO] = {
+		.name			= "CL Picasso",
+		.maxclock		= {
+			/* guess */
+			90000, 90000, 90000, 90000, 90000
+		},
+		.init_sr07		= TRUE,
+		.init_sr1f		= TRUE,
+		.scrn_start_bit19	= FALSE,
+		.sr07			= 0x20,
+		.sr07_1bpp		= 0x20,
+		.sr07_8bpp		= 0x21,
+		.sr1f			= 0x22
+	},
+	[BT_SPECTRUM] = {
+		.name			= "CL Spectrum",
+		.maxclock		= {
+			/* guess */
+			90000, 90000, 90000, 90000, 90000
+		},
+		.init_sr07		= TRUE,
+		.init_sr1f		= TRUE,
+		.scrn_start_bit19	= FALSE,
+		.sr07			= 0x80,
+		.sr07_1bpp		= 0x80,
+		.sr07_8bpp		= 0x81,
+		.sr1f			= 0x22
+	},
+	[BT_PICASSO4] = {
+		.name			= "CL Picasso4",
+		.maxclock		= {
+			135100, 135100, 85500, 85500, 0
+		},
+		.init_sr07		= TRUE,
+		.init_sr1f		= FALSE,
+		.scrn_start_bit19	= TRUE,
+		.sr07			= 0x20,
+		.sr07_1bpp		= 0x20,
+		.sr07_8bpp		= 0x21,
+		.sr1f			= 0
+	},
+	[BT_ALPINE] = {
+		.name			= "CL Alpine",
+		.maxclock		= {
+			/* for the GD5430.  GD5446 can do more... */
+			85500, 85500, 50000, 28500, 0
+		},
+		.init_sr07		= TRUE,
+		.init_sr1f		= TRUE,
+		.scrn_start_bit19	= TRUE,
+		.sr07			= 0xA0,
+		.sr07_1bpp		= 0xA1,
+		.sr07_1bpp_mux		= 0xA7,
+		.sr07_8bpp		= 0xA1,
+		.sr07_8bpp_mux		= 0xA7,
+		.sr1f			= 0x1C
+	},
+	[BT_GD5480] = {
+		.name			= "CL GD5480",
+		.maxclock		= {
+			135100, 200000, 200000, 135100, 135100
+		},
+		.init_sr07		= TRUE,
+		.init_sr1f		= TRUE,
+		.scrn_start_bit19	= TRUE,
+		.sr07			= 0x10,
+		.sr07_1bpp		= 0x11,
+		.sr07_8bpp		= 0x11,
+		.sr1f			= 0x1C
+	},
+	[BT_LAGUNA] = {
+		.name			= "CL Laguna",
+		.maxclock		= {
+			/* guess */
+			135100, 135100, 135100, 135100, 135100,
+		},
+		.init_sr07		= FALSE,
+		.init_sr1f		= FALSE,
+		.scrn_start_bit19	= TRUE,
+	}
+};
+
+
+#ifdef CONFIG_PCI
+#define CHIP(id, btype) \
+	{ PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_##id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (btype) }
+
+static struct pci_device_id cirrusfb_pci_table[] = {
+	CHIP( CIRRUS_5436,	BT_ALPINE ),
+	CHIP( CIRRUS_5434_8,	BT_ALPINE ),
+	CHIP( CIRRUS_5434_4,	BT_ALPINE ),
+	CHIP( CIRRUS_5430,	BT_ALPINE ), /* GD-5440 has identical id */
+	CHIP( CIRRUS_7543,	BT_ALPINE ),
+	CHIP( CIRRUS_7548,	BT_ALPINE ),
+	CHIP( CIRRUS_5480,	BT_GD5480 ), /* MacPicasso probably */
+	CHIP( CIRRUS_5446,	BT_PICASSO4 ), /* Picasso 4 is a GD5446 */
+	CHIP( CIRRUS_5462,	BT_LAGUNA ), /* CL Laguna */
+	CHIP( CIRRUS_5464,	BT_LAGUNA ), /* CL Laguna 3D */
+	CHIP( CIRRUS_5465,	BT_LAGUNA ), /* CL Laguna 3DA*/
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table);
+#undef CHIP
+#endif /* CONFIG_PCI */
+
+
+#ifdef CONFIG_ZORRO
+static const struct zorro_device_id cirrusfb_zorro_table[] = {
+	{
+		.id		= ZORRO_PROD_HELFRICH_SD64_RAM,
+		.driver_data	= BT_SD64,
+	}, {
+		.id		= ZORRO_PROD_HELFRICH_PICCOLO_RAM,
+		.driver_data	= BT_PICCOLO,
+	}, {
+		.id		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM,
+		.driver_data	= BT_PICASSO,
+	}, {
+		.id		= ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM,
+		.driver_data	= BT_SPECTRUM,
+	}, {
+		.id		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3,
+		.driver_data	= BT_PICASSO4,
+	},
+	{ 0 }
+};
+
+static const struct {
+	zorro_id id2;
+	unsigned long size;
+} cirrusfb_zorro_table2[] = {
+	[BT_SD64] = {
+		.id2	= ZORRO_PROD_HELFRICH_SD64_REG,
+		.size	= 0x400000
+	},
+	[BT_PICCOLO] = {
+		.id2	= ZORRO_PROD_HELFRICH_PICCOLO_REG,
+		.size	= 0x200000
+	},
+	[BT_PICASSO] = {
+		.id2	= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG,
+		.size	= 0x200000
+	},
+	[BT_SPECTRUM] = {
+		.id2	= ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG,
+		.size	= 0x200000
+	},
+	[BT_PICASSO4] = {
+		.id2	= 0,
+		.size	= 0x400000
+	}
+};
+#endif /* CONFIG_ZORRO */
+
+
+struct cirrusfb_regs {
+	__u32 line_length;	/* in BYTES! */
+	__u32 visual;
+	__u32 type;
+
+	long freq;
+	long nom;
+	long den;
+	long div;
+	long multiplexing;
+	long mclk;
+	long divMCLK;
+
+	long HorizRes;		/* The x resolution in pixel */
+	long HorizTotal;
+	long HorizDispEnd;
+	long HorizBlankStart;
+	long HorizBlankEnd;
+	long HorizSyncStart;
+	long HorizSyncEnd;
+
+	long VertRes;		/* the physical y resolution in scanlines */
+	long VertTotal;
+	long VertDispEnd;
+	long VertSyncStart;
+	long VertSyncEnd;
+	long VertBlankStart;
+	long VertBlankEnd;
+};
+
+
+
+#ifdef CIRRUSFB_DEBUG
+typedef enum {
+        CRT,
+        SEQ
+} cirrusfb_dbg_reg_class_t;
+#endif                          /* CIRRUSFB_DEBUG */
+
+
+
+
+/* info about board */
+struct cirrusfb_info {
+	struct fb_info *info;
+
+	u8 __iomem *fbmem;
+	u8 __iomem *regbase;
+	u8 __iomem *mem;
+	unsigned long size;
+	cirrusfb_board_t btype;
+	unsigned char SFR;	/* Shadow of special function register */
+
+	unsigned long fbmem_phys;
+	unsigned long fbregs_phys;
+
+	struct cirrusfb_regs currentmode;
+	int blank_mode;
+
+	u32	pseudo_palette[17];
+	struct { u8 red, green, blue, pad; } palette[256];
+
+#ifdef CONFIG_ZORRO
+	struct zorro_dev *zdev;
+#endif
+#ifdef CONFIG_PCI
+	struct pci_dev *pdev;
+#endif
+	void (*unmap)(struct cirrusfb_info *cinfo);
+};
+
+
+static unsigned cirrusfb_def_mode = 1;
+static int noaccel = 0;
+
+/*
+ *    Predefined Video Modes
+ */
+
+static const struct {
+	const char *name;
+	struct fb_var_screeninfo var;
+} cirrusfb_predefined[] = {
+	{
+		/* autodetect mode */
+		.name	= "Autodetect",
+	}, {
+		/* 640x480, 31.25 kHz, 60 Hz, 25 MHz PixClock */
+		.name	= "640x480",
+		.var	= {
+			.xres		= 640,
+			.yres		= 480,
+			.xres_virtual	= 640,
+			.yres_virtual	= 480,
+			.bits_per_pixel	= 8,
+			.red		= { .length = 8 },
+			.green		= { .length = 8 },
+			.blue		= { .length = 8 },
+			.width		= -1,
+			.height		= -1,
+			.pixclock	= 40000,
+			.left_margin	= 48,
+			.right_margin	= 16,
+			.upper_margin	= 32,
+			.lower_margin	= 8,
+			.hsync_len	= 96,
+			.vsync_len	= 4,
+			.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+			.vmode		= FB_VMODE_NONINTERLACED
+		 }
+	}, {
+		/* 800x600, 48 kHz, 76 Hz, 50 MHz PixClock */
+		.name	= "800x600",
+		.var	= {
+			.xres		= 800,
+			.yres		= 600,
+			.xres_virtual	= 800,
+			.yres_virtual	= 600,
+			.bits_per_pixel	= 8,
+			.red		= { .length = 8 },
+			.green		= { .length = 8 },
+			.blue		= { .length = 8 },
+			.width		= -1,
+			.height		= -1,
+			.pixclock	= 20000,
+			.left_margin	= 128,
+			.right_margin	= 16,
+			.upper_margin	= 24,
+			.lower_margin	= 2,
+			.hsync_len	= 96,
+			.vsync_len	= 6,
+			.vmode		= FB_VMODE_NONINTERLACED
+		 }
+	}, {
+		/*
+		 * Modeline from XF86Config:
+		 * Mode "1024x768" 80  1024 1136 1340 1432  768 770 774 805
+		 */
+		/* 1024x768, 55.8 kHz, 70 Hz, 80 MHz PixClock */
+		.name	= "1024x768",
+		.var	= {
+			.xres		= 1024,
+			.yres		= 768,
+			.xres_virtual	= 1024,
+			.yres_virtual	= 768,
+			.bits_per_pixel	= 8,
+			.red		= { .length = 8 },
+			.green		= { .length = 8 },
+			.blue		= { .length = 8 },
+			.width		= -1,
+			.height		= -1,
+			.pixclock	= 12500,
+			.left_margin	= 144,
+			.right_margin	= 32,
+			.upper_margin	= 30,
+			.lower_margin	= 2,
+			.hsync_len	= 192,
+			.vsync_len	= 6,
+			.vmode		= FB_VMODE_NONINTERLACED
+		}
+	}
+};
+
+#define NUM_TOTAL_MODES    ARRAY_SIZE(cirrusfb_predefined)
+
+/****************************************************************************/
+/**** BEGIN PROTOTYPES ******************************************************/
+
+
+/*--- Interface used by the world ------------------------------------------*/
+static int cirrusfb_init (void);
+#ifndef MODULE
+static int cirrusfb_setup (char *options);
+#endif
+
+static int cirrusfb_open (struct fb_info *info, int user);
+static int cirrusfb_release (struct fb_info *info, int user);
+static int cirrusfb_setcolreg (unsigned regno, unsigned red, unsigned green,
+			       unsigned blue, unsigned transp,
+			       struct fb_info *info);
+static int cirrusfb_check_var (struct fb_var_screeninfo *var,
+			       struct fb_info *info);
+static int cirrusfb_set_par (struct fb_info *info);
+static int cirrusfb_pan_display (struct fb_var_screeninfo *var,
+				 struct fb_info *info);
+static int cirrusfb_blank (int blank_mode, struct fb_info *info);
+static void cirrusfb_fillrect (struct fb_info *info, const struct fb_fillrect *region);
+static void cirrusfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
+static void cirrusfb_imageblit(struct fb_info *info, const struct fb_image *image);
+
+/* function table of the above functions */
+static struct fb_ops cirrusfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_open	= cirrusfb_open,
+	.fb_release	= cirrusfb_release,
+	.fb_setcolreg	= cirrusfb_setcolreg,
+	.fb_check_var	= cirrusfb_check_var,
+	.fb_set_par	= cirrusfb_set_par,
+	.fb_pan_display = cirrusfb_pan_display,
+	.fb_blank	= cirrusfb_blank,
+	.fb_fillrect	= cirrusfb_fillrect,
+	.fb_copyarea	= cirrusfb_copyarea,
+	.fb_imageblit	= cirrusfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+/*--- Hardware Specific Routines -------------------------------------------*/
+static int cirrusfb_decode_var (const struct fb_var_screeninfo *var,
+				struct cirrusfb_regs *regs,
+				const struct fb_info *info);
+/*--- Internal routines ----------------------------------------------------*/
+static void init_vgachip (struct cirrusfb_info *cinfo);
+static void switch_monitor (struct cirrusfb_info *cinfo, int on);
+static void WGen (const struct cirrusfb_info *cinfo,
+		  int regnum, unsigned char val);
+static unsigned char RGen (const struct cirrusfb_info *cinfo, int regnum);
+static void AttrOn (const struct cirrusfb_info *cinfo);
+static void WHDR (const struct cirrusfb_info *cinfo, unsigned char val);
+static void WSFR (struct cirrusfb_info *cinfo, unsigned char val);
+static void WSFR2 (struct cirrusfb_info *cinfo, unsigned char val);
+static void WClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char red,
+		   unsigned char green,
+		   unsigned char blue);
+#if 0
+static void RClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char *red,
+		   unsigned char *green,
+		   unsigned char *blue);
+#endif
+static void cirrusfb_WaitBLT (u8 __iomem *regbase);
+static void cirrusfb_BitBLT (u8 __iomem *regbase, int bits_per_pixel,
+			     u_short curx, u_short cury,
+			     u_short destx, u_short desty,
+			     u_short width, u_short height,
+			     u_short line_length);
+static void cirrusfb_RectFill (u8 __iomem *regbase, int bits_per_pixel,
+			       u_short x, u_short y,
+			       u_short width, u_short height,
+			       u_char color, u_short line_length);
+
+static void bestclock (long freq, long *best,
+		       long *nom, long *den,
+		       long *div, long maxfreq);
+
+#ifdef CIRRUSFB_DEBUG
+static void cirrusfb_dump (void);
+static void cirrusfb_dbg_reg_dump (caddr_t regbase);
+static void cirrusfb_dbg_print_regs (caddr_t regbase, cirrusfb_dbg_reg_class_t reg_class,...);
+static void cirrusfb_dbg_print_byte (const char *name, unsigned char val);
+#endif /* CIRRUSFB_DEBUG */
+
+/*** END   PROTOTYPES ********************************************************/
+/*****************************************************************************/
+/*** BEGIN Interface Used by the World ***************************************/
+
+static int opencount = 0;
+
+/*--- Open /dev/fbx ---------------------------------------------------------*/
+static int cirrusfb_open (struct fb_info *info, int user)
+{
+	if (opencount++ == 0)
+		switch_monitor (info->par, 1);
+	return 0;
+}
+
+/*--- Close /dev/fbx --------------------------------------------------------*/
+static int cirrusfb_release (struct fb_info *info, int user)
+{
+	if (--opencount == 0)
+		switch_monitor (info->par, 0);
+	return 0;
+}
+
+/**** END   Interface used by the World *************************************/
+/****************************************************************************/
+/**** BEGIN Hardware specific Routines **************************************/
+
+/* Get a good MCLK value */
+static long cirrusfb_get_mclk (long freq, int bpp, long *div)
+{
+	long mclk;
+
+	assert (div != NULL);
+
+	/* Calculate MCLK, in case VCLK is high enough to require > 50MHz.
+	 * Assume a 64-bit data path for now.  The formula is:
+	 * ((B * PCLK * 2)/W) * 1.2
+	 * B = bytes per pixel, PCLK = pixclock, W = data width in bytes */
+	mclk = ((bpp / 8) * freq * 2) / 4;
+	mclk = (mclk * 12) / 10;
+	if (mclk < 50000)
+		mclk = 50000;
+	DPRINTK ("Use MCLK of %ld kHz\n", mclk);
+
+	/* Calculate value for SR1F.  Multiply by 2 so we can round up. */
+	mclk = ((mclk * 16) / 14318);
+	mclk = (mclk + 1) / 2;
+	DPRINTK ("Set SR1F[5:0] to 0x%lx\n", mclk);
+
+	/* Determine if we should use MCLK instead of VCLK, and if so, what we
+	   * should divide it by to get VCLK */
+	switch (freq) {
+	case 24751 ... 25249:
+		*div = 2;
+		DPRINTK ("Using VCLK = MCLK/2\n");
+		break;
+	case 49501 ... 50499:
+		*div = 1;
+		DPRINTK ("Using VCLK = MCLK\n");
+		break;
+	default:
+		*div = 0;
+		break;
+	}
+
+	return mclk;
+}
+
+static int cirrusfb_check_var(struct fb_var_screeninfo *var,
+			      struct fb_info *info)
+{
+	struct cirrusfb_info *cinfo = info->par;
+	int nom, den;		/* translyting from pixels->bytes */
+	int yres, i;
+	static struct { int xres, yres; } modes[] =
+	{ { 1600, 1280 },
+	  { 1280, 1024 },
+	  { 1024, 768 },
+	  { 800, 600 },
+	  { 640, 480 },
+	  { -1, -1 } };
+
+	switch (var->bits_per_pixel) {
+	case 0 ... 1:
+		var->bits_per_pixel = 1;
+		nom = 4;
+		den = 8;
+		break;		/* 8 pixel per byte, only 1/4th of mem usable */
+	case 2 ... 8:
+		var->bits_per_pixel = 8;
+		nom = 1;
+		den = 1;
+		break;		/* 1 pixel == 1 byte */
+	case 9 ... 16:
+		var->bits_per_pixel = 16;
+		nom = 2;
+		den = 1;
+		break;		/* 2 bytes per pixel */
+	case 17 ... 24:
+		var->bits_per_pixel = 24;
+		nom = 3;
+		den = 1;
+		break;		/* 3 bytes per pixel */
+	case 25 ... 32:
+		var->bits_per_pixel = 32;
+		nom = 4;
+		den = 1;
+		break;		/* 4 bytes per pixel */
+	default:
+		printk ("cirrusfb: mode %dx%dx%d rejected...color depth not supported.\n",
+			var->xres, var->yres, var->bits_per_pixel);
+		DPRINTK ("EXIT - EINVAL error\n");
+		return -EINVAL;
+	}
+
+	if (var->xres * nom / den * var->yres > cinfo->size) {
+		printk ("cirrusfb: mode %dx%dx%d rejected...resolution too high to fit into video memory!\n",
+			var->xres, var->yres, var->bits_per_pixel);
+		DPRINTK ("EXIT - EINVAL error\n");
+		return -EINVAL;
+	}
+
+	/* use highest possible virtual resolution */
+	if (var->xres_virtual == -1 &&
+	    var->yres_virtual == -1) {
+		printk ("cirrusfb: using maximum available virtual resolution\n");
+		for (i = 0; modes[i].xres != -1; i++) {
+			if (modes[i].xres * nom / den * modes[i].yres < cinfo->size / 2)
+				break;
+		}
+		if (modes[i].xres == -1) {
+			printk ("cirrusfb: could not find a virtual resolution that fits into video memory!!\n");
+			DPRINTK ("EXIT - EINVAL error\n");
+			return -EINVAL;
+		}
+		var->xres_virtual = modes[i].xres;
+		var->yres_virtual = modes[i].yres;
+
+		printk ("cirrusfb: virtual resolution set to maximum of %dx%d\n",
+			var->xres_virtual, var->yres_virtual);
+	}
+
+	if (var->xres_virtual < var->xres)
+		var->xres_virtual = var->xres;
+	if (var->yres_virtual < var->yres)
+		var->yres_virtual = var->yres;
+
+	if (var->xoffset < 0)
+		var->xoffset = 0;
+	if (var->yoffset < 0)
+		var->yoffset = 0;
+
+	/* truncate xoffset and yoffset to maximum if too high */
+	if (var->xoffset > var->xres_virtual - var->xres)
+		var->xoffset = var->xres_virtual - var->xres - 1;
+	if (var->yoffset > var->yres_virtual - var->yres)
+		var->yoffset = var->yres_virtual - var->yres - 1;
+
+	switch (var->bits_per_pixel) {
+	case 1:
+		var->red.offset = 0;
+		var->red.length = 1;
+		var->green.offset = 0;
+		var->green.length = 1;
+		var->blue.offset = 0;
+		var->blue.length = 1;
+		break;
+
+	case 8:
+		var->red.offset = 0;
+		var->red.length = 6;
+		var->green.offset = 0;
+		var->green.length = 6;
+		var->blue.offset = 0;
+		var->blue.length = 6;
+		break;
+
+	case 16:
+		if(isPReP) {
+			var->red.offset = 2;
+			var->green.offset = -3;
+			var->blue.offset = 8;
+		} else {
+			var->red.offset = 10;
+			var->green.offset = 5;
+			var->blue.offset = 0;
+		}
+		var->red.length = 5;
+		var->green.length = 5;
+		var->blue.length = 5;
+		break;
+
+	case 24:
+		if(isPReP) {
+			var->red.offset = 8;
+			var->green.offset = 16;
+			var->blue.offset = 24;
+		} else {
+			var->red.offset = 16;
+			var->green.offset = 8;
+			var->blue.offset = 0;
+		}
+		var->red.length = 8;
+		var->green.length = 8;
+		var->blue.length = 8;
+		break;
+
+	case 32:
+		if(isPReP) {
+			var->red.offset = 8;
+			var->green.offset = 16;
+			var->blue.offset = 24;
+		} else {
+			var->red.offset = 16;
+			var->green.offset = 8;
+			var->blue.offset = 0;
+		}
+		var->red.length = 8;
+		var->green.length = 8;
+		var->blue.length = 8;
+		break;
+
+	default:
+		DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel);
+		assert (FALSE);
+		/* should never occur */
+		break;
+	}
+
+	var->red.msb_right =
+	    var->green.msb_right =
+	    var->blue.msb_right =
+	    var->transp.offset =
+	    var->transp.length =
+	    var->transp.msb_right = 0;
+
+	yres = var->yres;
+	if (var->vmode & FB_VMODE_DOUBLE)
+		yres *= 2;
+	else if (var->vmode & FB_VMODE_INTERLACED)
+		yres = (yres + 1) / 2;
+
+	if (yres >= 1280) {
+		printk (KERN_WARNING "cirrusfb: ERROR: VerticalTotal >= 1280; special treatment required! (TODO)\n");
+		DPRINTK ("EXIT - EINVAL error\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cirrusfb_decode_var (const struct fb_var_screeninfo *var,
+				struct cirrusfb_regs *regs,
+				const struct fb_info *info)
+{
+	long freq;
+	long maxclock;
+	int maxclockidx = 0;
+	struct cirrusfb_info *cinfo = info->par;
+	int xres, hfront, hsync, hback;
+	int yres, vfront, vsync, vback;
+
+	switch(var->bits_per_pixel) {
+	case 1:
+		regs->line_length = var->xres_virtual / 8;
+		regs->visual = FB_VISUAL_MONO10;
+		maxclockidx = 0;
+		break;
+
+	case 8:
+		regs->line_length = var->xres_virtual;
+		regs->visual = FB_VISUAL_PSEUDOCOLOR;
+		maxclockidx = 1;
+		break;
+
+	case 16:
+		regs->line_length = var->xres_virtual * 2;
+		regs->visual = FB_VISUAL_DIRECTCOLOR;
+		maxclockidx = 2;
+		break;
+
+	case 24:
+		regs->line_length = var->xres_virtual * 3;
+		regs->visual = FB_VISUAL_DIRECTCOLOR;
+		maxclockidx = 3;
+		break;
+
+	case 32:
+		regs->line_length = var->xres_virtual * 4;
+		regs->visual = FB_VISUAL_DIRECTCOLOR;
+		maxclockidx = 4;
+		break;
+
+	default:
+		DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel);
+		assert (FALSE);
+		/* should never occur */
+		break;
+	}
+
+	regs->type = FB_TYPE_PACKED_PIXELS;
+
+	/* convert from ps to kHz */
+	freq = 1000000000 / var->pixclock;
+
+	DPRINTK ("desired pixclock: %ld kHz\n", freq);
+
+	maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx];
+	regs->multiplexing = 0;
+
+	/* If the frequency is greater than we can support, we might be able
+	 * to use multiplexing for the video mode */
+	if (freq > maxclock) {
+		switch (cinfo->btype) {
+		case BT_ALPINE:
+		case BT_GD5480:
+			regs->multiplexing = 1;
+			break;
+
+		default:
+			printk (KERN_WARNING "cirrusfb: ERROR: Frequency greater than maxclock (%ld kHz)\n", maxclock);
+			DPRINTK ("EXIT - return -EINVAL\n");
+			return -EINVAL;
+		}
+	}
+#if 0
+	/* TODO: If we have a 1MB 5434, we need to put ourselves in a mode where
+	 * the VCLK is double the pixel clock. */
+	switch (var->bits_per_pixel) {
+	case 16:
+	case 32:
+		if (regs->HorizRes <= 800)
+			freq /= 2;	/* Xbh has this type of clock for 32-bit */
+		break;
+	}
+#endif
+
+	bestclock (freq, &regs->freq, &regs->nom, &regs->den, &regs->div,
+		   maxclock);
+	regs->mclk = cirrusfb_get_mclk (freq, var->bits_per_pixel, &regs->divMCLK);
+
+	xres = var->xres;
+	hfront = var->right_margin;
+	hsync = var->hsync_len;
+	hback = var->left_margin;
+
+	yres = var->yres;
+	vfront = var->lower_margin;
+	vsync = var->vsync_len;
+	vback = var->upper_margin;
+
+	if (var->vmode & FB_VMODE_DOUBLE) {
+		yres *= 2;
+		vfront *= 2;
+		vsync *= 2;
+		vback *= 2;
+	} else if (var->vmode & FB_VMODE_INTERLACED) {
+		yres = (yres + 1) / 2;
+		vfront = (vfront + 1) / 2;
+		vsync = (vsync + 1) / 2;
+		vback = (vback + 1) / 2;
+	}
+	regs->HorizRes = xres;
+	regs->HorizTotal = (xres + hfront + hsync + hback) / 8 - 5;
+	regs->HorizDispEnd = xres / 8 - 1;
+	regs->HorizBlankStart = xres / 8;
+	regs->HorizBlankEnd = regs->HorizTotal + 5;	/* does not count with "-5" */
+	regs->HorizSyncStart = (xres + hfront) / 8 + 1;
+	regs->HorizSyncEnd = (xres + hfront + hsync) / 8 + 1;
+
+	regs->VertRes = yres;
+	regs->VertTotal = yres + vfront + vsync + vback - 2;
+	regs->VertDispEnd = yres - 1;
+	regs->VertBlankStart = yres;
+	regs->VertBlankEnd = regs->VertTotal;
+	regs->VertSyncStart = yres + vfront - 1;
+	regs->VertSyncEnd = yres + vfront + vsync - 1;
+
+	if (regs->VertRes >= 1024) {
+		regs->VertTotal /= 2;
+		regs->VertSyncStart /= 2;
+		regs->VertSyncEnd /= 2;
+		regs->VertDispEnd /= 2;
+	}
+	if (regs->multiplexing) {
+		regs->HorizTotal /= 2;
+		regs->HorizSyncStart /= 2;
+		regs->HorizSyncEnd /= 2;
+		regs->HorizDispEnd /= 2;
+	}
+
+	return 0;
+}
+
+
+static void cirrusfb_set_mclk (const struct cirrusfb_info *cinfo, int val, int div)
+{
+	assert (cinfo != NULL);
+
+	if (div == 2) {
+		/* VCLK = MCLK/2 */
+		unsigned char old = vga_rseq (cinfo->regbase, CL_SEQR1E);
+		vga_wseq (cinfo->regbase, CL_SEQR1E, old | 0x1);
+		vga_wseq (cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f));
+	} else if (div == 1) {
+		/* VCLK = MCLK */
+		unsigned char old = vga_rseq (cinfo->regbase, CL_SEQR1E);
+		vga_wseq (cinfo->regbase, CL_SEQR1E, old & ~0x1);
+		vga_wseq (cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f));
+	} else {
+		vga_wseq (cinfo->regbase, CL_SEQR1F, val & 0x3f);
+	}
+}
+
+/*************************************************************************
+	cirrusfb_set_par_foo()
+
+	actually writes the values for a new video mode into the hardware,
+**************************************************************************/
+static int cirrusfb_set_par_foo (struct fb_info *info)
+{
+	struct cirrusfb_info *cinfo = info->par;
+	struct fb_var_screeninfo *var = &info->var;
+	struct cirrusfb_regs regs;
+	u8 __iomem *regbase = cinfo->regbase;
+	unsigned char tmp;
+	int offset = 0, err;
+	const struct cirrusfb_board_info_rec *bi;
+
+	DPRINTK ("ENTER\n");
+	DPRINTK ("Requested mode: %dx%dx%d\n",
+	       var->xres, var->yres, var->bits_per_pixel);
+	DPRINTK ("pixclock: %d\n", var->pixclock);
+
+	init_vgachip (cinfo);
+
+	err = cirrusfb_decode_var(var, &regs, info);
+	if(err) {
+		/* should never happen */
+		DPRINTK("mode change aborted.  invalid var.\n");
+		return -EINVAL;
+	}
+
+	bi = &cirrusfb_board_info[cinfo->btype];
+
+
+	/* unlock register VGA_CRTC_H_TOTAL..CRT7 */
+	vga_wcrt (regbase, VGA_CRTC_V_SYNC_END, 0x20);	/* previously: 0x00) */
+
+	/* if debugging is enabled, all parameters get output before writing */
+	DPRINTK ("CRT0: %ld\n", regs.HorizTotal);
+	vga_wcrt (regbase, VGA_CRTC_H_TOTAL, regs.HorizTotal);
+
+	DPRINTK ("CRT1: %ld\n", regs.HorizDispEnd);
+	vga_wcrt (regbase, VGA_CRTC_H_DISP, regs.HorizDispEnd);
+
+	DPRINTK ("CRT2: %ld\n", regs.HorizBlankStart);
+	vga_wcrt (regbase, VGA_CRTC_H_BLANK_START, regs.HorizBlankStart);
+
+	DPRINTK ("CRT3: 128+%ld\n", regs.HorizBlankEnd % 32);	/*  + 128: Compatible read */
+	vga_wcrt (regbase, VGA_CRTC_H_BLANK_END, 128 + (regs.HorizBlankEnd % 32));
+
+	DPRINTK ("CRT4: %ld\n", regs.HorizSyncStart);
+	vga_wcrt (regbase, VGA_CRTC_H_SYNC_START, regs.HorizSyncStart);
+
+	tmp = regs.HorizSyncEnd % 32;
+	if (regs.HorizBlankEnd & 32)
+		tmp += 128;
+	DPRINTK ("CRT5: %d\n", tmp);
+	vga_wcrt (regbase, VGA_CRTC_H_SYNC_END, tmp);
+
+	DPRINTK ("CRT6: %ld\n", regs.VertTotal & 0xff);
+	vga_wcrt (regbase, VGA_CRTC_V_TOTAL, (regs.VertTotal & 0xff));
+
+	tmp = 16;		/* LineCompare bit #9 */
+	if (regs.VertTotal & 256)
+		tmp |= 1;
+	if (regs.VertDispEnd & 256)
+		tmp |= 2;
+	if (regs.VertSyncStart & 256)
+		tmp |= 4;
+	if (regs.VertBlankStart & 256)
+		tmp |= 8;
+	if (regs.VertTotal & 512)
+		tmp |= 32;
+	if (regs.VertDispEnd & 512)
+		tmp |= 64;
+	if (regs.VertSyncStart & 512)
+		tmp |= 128;
+	DPRINTK ("CRT7: %d\n", tmp);
+	vga_wcrt (regbase, VGA_CRTC_OVERFLOW, tmp);
+
+	tmp = 0x40;		/* LineCompare bit #8 */
+	if (regs.VertBlankStart & 512)
+		tmp |= 0x20;
+	if (var->vmode & FB_VMODE_DOUBLE)
+		tmp |= 0x80;
+	DPRINTK ("CRT9: %d\n", tmp);
+	vga_wcrt (regbase, VGA_CRTC_MAX_SCAN, tmp);
+
+	DPRINTK ("CRT10: %ld\n", regs.VertSyncStart & 0xff);
+	vga_wcrt (regbase, VGA_CRTC_V_SYNC_START, (regs.VertSyncStart & 0xff));
+
+	DPRINTK ("CRT11: 64+32+%ld\n", regs.VertSyncEnd % 16);
+	vga_wcrt (regbase, VGA_CRTC_V_SYNC_END, (regs.VertSyncEnd % 16 + 64 + 32));
+
+	DPRINTK ("CRT12: %ld\n", regs.VertDispEnd & 0xff);
+	vga_wcrt (regbase, VGA_CRTC_V_DISP_END, (regs.VertDispEnd & 0xff));
+
+	DPRINTK ("CRT15: %ld\n", regs.VertBlankStart & 0xff);
+	vga_wcrt (regbase, VGA_CRTC_V_BLANK_START, (regs.VertBlankStart & 0xff));
+
+	DPRINTK ("CRT16: %ld\n", regs.VertBlankEnd & 0xff);
+	vga_wcrt (regbase, VGA_CRTC_V_BLANK_END, (regs.VertBlankEnd & 0xff));
+
+	DPRINTK ("CRT18: 0xff\n");
+	vga_wcrt (regbase, VGA_CRTC_LINE_COMPARE, 0xff);
+
+	tmp = 0;
+	if (var->vmode & FB_VMODE_INTERLACED)
+		tmp |= 1;
+	if (regs.HorizBlankEnd & 64)
+		tmp |= 16;
+	if (regs.HorizBlankEnd & 128)
+		tmp |= 32;
+	if (regs.VertBlankEnd & 256)
+		tmp |= 64;
+	if (regs.VertBlankEnd & 512)
+		tmp |= 128;
+
+	DPRINTK ("CRT1a: %d\n", tmp);
+	vga_wcrt (regbase, CL_CRT1A, tmp);
+
+	/* set VCLK0 */
+	/* hardware RefClock: 14.31818 MHz */
+	/* formula: VClk = (OSC * N) / (D * (1+P)) */
+	/* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */
+
+	vga_wseq (regbase, CL_SEQRB, regs.nom);
+	tmp = regs.den << 1;
+	if (regs.div != 0)
+		tmp |= 1;
+
+	if ((cinfo->btype == BT_SD64) ||
+	    (cinfo->btype == BT_ALPINE) ||
+	    (cinfo->btype == BT_GD5480))
+		tmp |= 0x80;	/* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
+
+	DPRINTK ("CL_SEQR1B: %ld\n", (long) tmp);
+	vga_wseq (regbase, CL_SEQR1B, tmp);
+
+	if (regs.VertRes >= 1024)
+		/* 1280x1024 */
+		vga_wcrt (regbase, VGA_CRTC_MODE, 0xc7);
+	else
+		/* mode control: VGA_CRTC_START_HI enable, ROTATE(?), 16bit
+		 * address wrap, no compat. */
+		vga_wcrt (regbase, VGA_CRTC_MODE, 0xc3);
+
+/* HAEH?        vga_wcrt (regbase, VGA_CRTC_V_SYNC_END, 0x20);  * previously: 0x00  unlock VGA_CRTC_H_TOTAL..CRT7 */
+
+	/* don't know if it would hurt to also program this if no interlaced */
+	/* mode is used, but I feel better this way.. :-) */
+	if (var->vmode & FB_VMODE_INTERLACED)
+		vga_wcrt (regbase, VGA_CRTC_REGS, regs.HorizTotal / 2);
+	else
+		vga_wcrt (regbase, VGA_CRTC_REGS, 0x00);	/* interlace control */
+
+	vga_wseq (regbase, VGA_SEQ_CHARACTER_MAP, 0);
+
+	/* adjust horizontal/vertical sync type (low/high) */
+	tmp = 0x03;		/* enable display memory & CRTC I/O address for color mode */
+	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+		tmp |= 0x40;
+	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+		tmp |= 0x80;
+	WGen (cinfo, VGA_MIS_W, tmp);
+
+	vga_wcrt (regbase, VGA_CRTC_PRESET_ROW, 0);	/* Screen A Preset Row-Scan register */
+	vga_wcrt (regbase, VGA_CRTC_CURSOR_START, 0);	/* text cursor on and start line */
+	vga_wcrt (regbase, VGA_CRTC_CURSOR_END, 31);	/* text cursor end line */
+
+	/******************************************************
+	 *
+	 * 1 bpp
+	 *
+	 */
+
+	/* programming for different color depths */
+	if (var->bits_per_pixel == 1) {
+		DPRINTK ("cirrusfb: preparing for 1 bit deep display\n");
+		vga_wgfx (regbase, VGA_GFX_MODE, 0);	/* mode register */
+
+		/* SR07 */
+		switch (cinfo->btype) {
+		case BT_SD64:
+		case BT_PICCOLO:
+		case BT_PICASSO:
+		case BT_SPECTRUM:
+		case BT_PICASSO4:
+		case BT_ALPINE:
+		case BT_GD5480:
+			DPRINTK (" (for GD54xx)\n");
+			vga_wseq (regbase, CL_SEQR7,
+				  regs.multiplexing ?
+					bi->sr07_1bpp_mux : bi->sr07_1bpp);
+			break;
+
+		case BT_LAGUNA:
+			DPRINTK (" (for GD546x)\n");
+			vga_wseq (regbase, CL_SEQR7,
+				vga_rseq (regbase, CL_SEQR7) & ~0x01);
+			break;
+
+		default:
+			printk (KERN_WARNING "cirrusfb: unknown Board\n");
+			break;
+		}
+
+		/* Extended Sequencer Mode */
+		switch (cinfo->btype) {
+		case BT_SD64:
+			/* setting the SEQRF on SD64 is not necessary (only during init) */
+			DPRINTK ("(for SD64)\n");
+			vga_wseq (regbase, CL_SEQR1F, 0x1a);		/*  MCLK select */
+			break;
+
+		case BT_PICCOLO:
+			DPRINTK ("(for Piccolo)\n");
+/* ### ueberall 0x22? */
+			vga_wseq (regbase, CL_SEQR1F, 0x22);		/* ##vorher 1c MCLK select */
+			vga_wseq (regbase, CL_SEQRF, 0xb0);	/* evtl d0 bei 1 bit? avoid FIFO underruns..? */
+			break;
+
+		case BT_PICASSO:
+			DPRINTK ("(for Picasso)\n");
+			vga_wseq (regbase, CL_SEQR1F, 0x22);		/* ##vorher 22 MCLK select */
+			vga_wseq (regbase, CL_SEQRF, 0xd0);	/* ## vorher d0 avoid FIFO underruns..? */
+			break;
+
+		case BT_SPECTRUM:
+			DPRINTK ("(for Spectrum)\n");
+/* ### ueberall 0x22? */
+			vga_wseq (regbase, CL_SEQR1F, 0x22);		/* ##vorher 1c MCLK select */
+			vga_wseq (regbase, CL_SEQRF, 0xb0);	/* evtl d0? avoid FIFO underruns..? */
+			break;
+
+		case BT_PICASSO4:
+		case BT_ALPINE:
+		case BT_GD5480:
+		case BT_LAGUNA:
+			DPRINTK (" (for GD54xx)\n");
+			/* do nothing */
+			break;
+
+		default:
+			printk (KERN_WARNING "cirrusfb: unknown Board\n");
+			break;
+		}
+
+		WGen (cinfo, VGA_PEL_MSK, 0x01);	/* pixel mask: pass-through for first plane */
+		if (regs.multiplexing)
+			WHDR (cinfo, 0x4a);	/* hidden dac reg: 1280x1024 */
+		else
+			WHDR (cinfo, 0);	/* hidden dac: nothing */
+		vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x06);	/* memory mode: odd/even, ext. memory */
+		vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0x01);	/* plane mask: only write to first plane */
+		offset = var->xres_virtual / 16;
+	}
+
+	/******************************************************
+	 *
+	 * 8 bpp
+	 *
+	 */
+
+	else if (var->bits_per_pixel == 8) {
+		DPRINTK ("cirrusfb: preparing for 8 bit deep display\n");
+		switch (cinfo->btype) {
+		case BT_SD64:
+		case BT_PICCOLO:
+		case BT_PICASSO:
+		case BT_SPECTRUM:
+		case BT_PICASSO4:
+		case BT_ALPINE:
+		case BT_GD5480:
+			DPRINTK (" (for GD54xx)\n");
+			vga_wseq (regbase, CL_SEQR7,
+				  regs.multiplexing ?
+					bi->sr07_8bpp_mux : bi->sr07_8bpp);
+			break;
+
+		case BT_LAGUNA:
+			DPRINTK (" (for GD546x)\n");
+			vga_wseq (regbase, CL_SEQR7,
+				vga_rseq (regbase, CL_SEQR7) | 0x01);
+			break;
+
+		default:
+			printk (KERN_WARNING "cirrusfb: unknown Board\n");
+			break;
+		}
+
+		switch (cinfo->btype) {
+		case BT_SD64:
+			vga_wseq (regbase, CL_SEQR1F, 0x1d);		/* MCLK select */
+			break;
+
+		case BT_PICCOLO:
+			vga_wseq (regbase, CL_SEQR1F, 0x22);		/* ### vorher 1c MCLK select */
+			vga_wseq (regbase, CL_SEQRF, 0xb0);	/* Fast Page-Mode writes */
+			break;
+
+		case BT_PICASSO:
+			vga_wseq (regbase, CL_SEQR1F, 0x22);		/* ### vorher 1c MCLK select */
+			vga_wseq (regbase, CL_SEQRF, 0xb0);	/* Fast Page-Mode writes */
+			break;
+
+		case BT_SPECTRUM:
+			vga_wseq (regbase, CL_SEQR1F, 0x22);		/* ### vorher 1c MCLK select */
+			vga_wseq (regbase, CL_SEQRF, 0xb0);	/* Fast Page-Mode writes */
+			break;
+
+		case BT_PICASSO4:
+#ifdef CONFIG_ZORRO
+			vga_wseq (regbase, CL_SEQRF, 0xb8);	/* ### INCOMPLETE!! */
+#endif
+/*          vga_wseq (regbase, CL_SEQR1F, 0x1c); */
+			break;
+
+		case BT_ALPINE:
+			DPRINTK (" (for GD543x)\n");
+			cirrusfb_set_mclk (cinfo, regs.mclk, regs.divMCLK);
+			/* We already set SRF and SR1F */
+			break;
+
+		case BT_GD5480:
+		case BT_LAGUNA:
+			DPRINTK (" (for GD54xx)\n");
+			/* do nothing */
+			break;
+
+		default:
+			printk (KERN_WARNING "cirrusfb: unknown Board\n");
+			break;
+		}
+
+		vga_wgfx (regbase, VGA_GFX_MODE, 64);	/* mode register: 256 color mode */
+		WGen (cinfo, VGA_PEL_MSK, 0xff);	/* pixel mask: pass-through all planes */
+		if (regs.multiplexing)
+			WHDR (cinfo, 0x4a);	/* hidden dac reg: 1280x1024 */
+		else
+			WHDR (cinfo, 0);	/* hidden dac: nothing */
+		vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x0a);	/* memory mode: chain4, ext. memory */
+		vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0xff);	/* plane mask: enable writing to all 4 planes */
+		offset = var->xres_virtual / 8;
+	}
+
+	/******************************************************
+	 *
+	 * 16 bpp
+	 *
+	 */
+
+	else if (var->bits_per_pixel == 16) {
+		DPRINTK ("cirrusfb: preparing for 16 bit deep display\n");
+		switch (cinfo->btype) {
+		case BT_SD64:
+			vga_wseq (regbase, CL_SEQR7, 0xf7);	/* Extended Sequencer Mode: 256c col. mode */
+			vga_wseq (regbase, CL_SEQR1F, 0x1e);		/* MCLK select */
+			break;
+
+		case BT_PICCOLO:
+			vga_wseq (regbase, CL_SEQR7, 0x87);
+			vga_wseq (regbase, CL_SEQRF, 0xb0);	/* Fast Page-Mode writes */
+			vga_wseq (regbase, CL_SEQR1F, 0x22);		/* MCLK select */
+			break;
+
+		case BT_PICASSO:
+			vga_wseq (regbase, CL_SEQR7, 0x27);
+			vga_wseq (regbase, CL_SEQRF, 0xb0);	/* Fast Page-Mode writes */
+			vga_wseq (regbase, CL_SEQR1F, 0x22);		/* MCLK select */
+			break;
+
+		case BT_SPECTRUM:
+			vga_wseq (regbase, CL_SEQR7, 0x87);
+			vga_wseq (regbase, CL_SEQRF, 0xb0);	/* Fast Page-Mode writes */
+			vga_wseq (regbase, CL_SEQR1F, 0x22);		/* MCLK select */
+			break;
+
+		case BT_PICASSO4:
+			vga_wseq (regbase, CL_SEQR7, 0x27);
+/*          vga_wseq (regbase, CL_SEQR1F, 0x1c);  */
+			break;
+
+		case BT_ALPINE:
+			DPRINTK (" (for GD543x)\n");
+			if (regs.HorizRes >= 1024)
+				vga_wseq (regbase, CL_SEQR7, 0xa7);
+			else
+				vga_wseq (regbase, CL_SEQR7, 0xa3);
+			cirrusfb_set_mclk (cinfo, regs.mclk, regs.divMCLK);
+			break;
+
+		case BT_GD5480:
+			DPRINTK (" (for GD5480)\n");
+			vga_wseq (regbase, CL_SEQR7, 0x17);
+			/* We already set SRF and SR1F */
+			break;
+
+		case BT_LAGUNA:
+			DPRINTK (" (for GD546x)\n");
+			vga_wseq (regbase, CL_SEQR7,
+				vga_rseq (regbase, CL_SEQR7) & ~0x01);
+			break;
+
+		default:
+			printk (KERN_WARNING "CIRRUSFB: unknown Board\n");
+			break;
+		}
+
+		vga_wgfx (regbase, VGA_GFX_MODE, 64);	/* mode register: 256 color mode */
+		WGen (cinfo, VGA_PEL_MSK, 0xff);	/* pixel mask: pass-through all planes */
+#ifdef CONFIG_PCI
+		WHDR (cinfo, 0xc0);	/* Copy Xbh */
+#elif defined(CONFIG_ZORRO)
+		/* FIXME: CONFIG_PCI and CONFIG_ZORRO may be defined both */
+		WHDR (cinfo, 0xa0);	/* hidden dac reg: nothing special */
+#endif
+		vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x0a);	/* memory mode: chain4, ext. memory */
+		vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0xff);	/* plane mask: enable writing to all 4 planes */
+		offset = var->xres_virtual / 4;
+	}
+
+	/******************************************************
+	 *
+	 * 32 bpp
+	 *
+	 */
+
+	else if (var->bits_per_pixel == 32) {
+		DPRINTK ("cirrusfb: preparing for 24/32 bit deep display\n");
+		switch (cinfo->btype) {
+		case BT_SD64:
+			vga_wseq (regbase, CL_SEQR7, 0xf9);	/* Extended Sequencer Mode: 256c col. mode */
+			vga_wseq (regbase, CL_SEQR1F, 0x1e);		/* MCLK select */
+			break;
+
+		case BT_PICCOLO:
+			vga_wseq (regbase, CL_SEQR7, 0x85);
+			vga_wseq (regbase, CL_SEQRF, 0xb0);	/* Fast Page-Mode writes */
+			vga_wseq (regbase, CL_SEQR1F, 0x22);		/* MCLK select */
+			break;
+
+		case BT_PICASSO:
+			vga_wseq (regbase, CL_SEQR7, 0x25);
+			vga_wseq (regbase, CL_SEQRF, 0xb0);	/* Fast Page-Mode writes */
+			vga_wseq (regbase, CL_SEQR1F, 0x22);		/* MCLK select */
+			break;
+
+		case BT_SPECTRUM:
+			vga_wseq (regbase, CL_SEQR7, 0x85);
+			vga_wseq (regbase, CL_SEQRF, 0xb0);	/* Fast Page-Mode writes */
+			vga_wseq (regbase, CL_SEQR1F, 0x22);		/* MCLK select */
+			break;
+
+		case BT_PICASSO4:
+			vga_wseq (regbase, CL_SEQR7, 0x25);
+/*          vga_wseq (regbase, CL_SEQR1F, 0x1c);  */
+			break;
+
+		case BT_ALPINE:
+			DPRINTK (" (for GD543x)\n");
+			vga_wseq (regbase, CL_SEQR7, 0xa9);
+			cirrusfb_set_mclk (cinfo, regs.mclk, regs.divMCLK);
+			break;
+
+		case BT_GD5480:
+			DPRINTK (" (for GD5480)\n");
+			vga_wseq (regbase, CL_SEQR7, 0x19);
+			/* We already set SRF and SR1F */
+			break;
+
+		case BT_LAGUNA:
+			DPRINTK (" (for GD546x)\n");
+			vga_wseq (regbase, CL_SEQR7,
+				vga_rseq (regbase, CL_SEQR7) & ~0x01);
+			break;
+
+		default:
+			printk (KERN_WARNING "cirrusfb: unknown Board\n");
+			break;
+		}
+
+		vga_wgfx (regbase, VGA_GFX_MODE, 64);	/* mode register: 256 color mode */
+		WGen (cinfo, VGA_PEL_MSK, 0xff);	/* pixel mask: pass-through all planes */
+		WHDR (cinfo, 0xc5);	/* hidden dac reg: 8-8-8 mode (24 or 32) */
+		vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x0a);	/* memory mode: chain4, ext. memory */
+		vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0xff);	/* plane mask: enable writing to all 4 planes */
+		offset = var->xres_virtual / 4;
+	}
+
+	/******************************************************
+	 *
+	 * unknown/unsupported bpp
+	 *
+	 */
+
+	else {
+		printk (KERN_ERR "cirrusfb: What's this?? requested color depth == %d.\n",
+			var->bits_per_pixel);
+	}
+
+	vga_wcrt (regbase, VGA_CRTC_OFFSET, offset & 0xff);
+	tmp = 0x22;
+	if (offset & 0x100)
+		tmp |= 0x10;	/* offset overflow bit */
+
+	vga_wcrt (regbase, CL_CRT1B, tmp);	/* screen start addr #16-18, fastpagemode cycles */
+
+	if (cinfo->btype == BT_SD64 ||
+	    cinfo->btype == BT_PICASSO4 ||
+	    cinfo->btype == BT_ALPINE ||
+	    cinfo->btype == BT_GD5480)
+		vga_wcrt (regbase, CL_CRT1D, 0x00);	/* screen start address bit 19 */
+
+	vga_wcrt (regbase, VGA_CRTC_CURSOR_HI, 0);	/* text cursor location high */
+	vga_wcrt (regbase, VGA_CRTC_CURSOR_LO, 0);	/* text cursor location low */
+	vga_wcrt (regbase, VGA_CRTC_UNDERLINE, 0);	/* underline row scanline = at very bottom */
+
+	vga_wattr (regbase, VGA_ATC_MODE, 1);	/* controller mode */
+	vga_wattr (regbase, VGA_ATC_OVERSCAN, 0);		/* overscan (border) color */
+	vga_wattr (regbase, VGA_ATC_PLANE_ENABLE, 15);	/* color plane enable */
+	vga_wattr (regbase, CL_AR33, 0);	/* pixel panning */
+	vga_wattr (regbase, VGA_ATC_COLOR_PAGE, 0);	/* color select */
+
+	/* [ EGS: SetOffset(); ] */
+	/* From SetOffset(): Turn on VideoEnable bit in Attribute controller */
+	AttrOn (cinfo);
+
+	vga_wgfx (regbase, VGA_GFX_SR_VALUE, 0);	/* set/reset register */
+	vga_wgfx (regbase, VGA_GFX_SR_ENABLE, 0);		/* set/reset enable */
+	vga_wgfx (regbase, VGA_GFX_COMPARE_VALUE, 0);	/* color compare */
+	vga_wgfx (regbase, VGA_GFX_DATA_ROTATE, 0);	/* data rotate */
+	vga_wgfx (regbase, VGA_GFX_PLANE_READ, 0);	/* read map select */
+	vga_wgfx (regbase, VGA_GFX_MISC, 1);	/* miscellaneous register */
+	vga_wgfx (regbase, VGA_GFX_COMPARE_MASK, 15);	/* color don't care */
+	vga_wgfx (regbase, VGA_GFX_BIT_MASK, 255);	/* bit mask */
+
+	vga_wseq (regbase, CL_SEQR12, 0x0);	/* graphics cursor attributes: nothing special */
+
+	/* finally, turn on everything - turn off "FullBandwidth" bit */
+	/* also, set "DotClock%2" bit where requested */
+	tmp = 0x01;
+
+/*** FB_VMODE_CLOCK_HALVE in linux/fb.h not defined anymore ?
+    if (var->vmode & FB_VMODE_CLOCK_HALVE)
+	tmp |= 0x08;
+*/
+
+	vga_wseq (regbase, VGA_SEQ_CLOCK_MODE, tmp);
+	DPRINTK ("CL_SEQR1: %d\n", tmp);
+
+	cinfo->currentmode = regs;
+	info->fix.type = regs.type;
+	info->fix.visual = regs.visual;
+	info->fix.line_length = regs.line_length;
+
+	/* pan to requested offset */
+	cirrusfb_pan_display (var, info);
+
+#ifdef CIRRUSFB_DEBUG
+	cirrusfb_dump ();
+#endif
+
+	DPRINTK ("EXIT\n");
+	return 0;
+}
+
+/* for some reason incomprehensible to me, cirrusfb requires that you write
+ * the registers twice for the settings to take..grr. -dte */
+static int cirrusfb_set_par (struct fb_info *info)
+{
+	cirrusfb_set_par_foo (info);
+	return cirrusfb_set_par_foo (info);
+}
+
+static int cirrusfb_setcolreg (unsigned regno, unsigned red, unsigned green,
+			       unsigned blue, unsigned transp,
+			       struct fb_info *info)
+{
+	struct cirrusfb_info *cinfo = info->par;
+
+	if (regno > 255)
+		return -EINVAL;
+
+	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+		u32 v;
+		red >>= (16 - info->var.red.length);
+		green >>= (16 - info->var.green.length);
+		blue >>= (16 - info->var.blue.length);
+
+		if (regno>=16)
+			return 1;
+		v = (red << info->var.red.offset) |
+		    (green << info->var.green.offset) |
+		    (blue << info->var.blue.offset);
+
+		switch (info->var.bits_per_pixel) {
+			case 8:
+				((u8*)(info->pseudo_palette))[regno] = v;
+				break;
+			case 16:
+				((u16*)(info->pseudo_palette))[regno] = v;
+				break;
+			case 24:
+			case 32:
+				((u32*)(info->pseudo_palette))[regno] = v;
+				break;
+		}
+		return 0;
+	}
+
+	cinfo->palette[regno].red = red;
+	cinfo->palette[regno].green = green;
+	cinfo->palette[regno].blue = blue;
+
+	if (info->var.bits_per_pixel == 8) {
+			WClut (cinfo, regno, red >> 10, green >> 10, blue >> 10);
+	}
+
+	return 0;
+
+}
+
+/*************************************************************************
+	cirrusfb_pan_display()
+
+	performs display panning - provided hardware permits this
+**************************************************************************/
+static int cirrusfb_pan_display (struct fb_var_screeninfo *var,
+				 struct fb_info *info)
+{
+	int xoffset = 0;
+	int yoffset = 0;
+	unsigned long base;
+	unsigned char tmp = 0, tmp2 = 0, xpix;
+	struct cirrusfb_info *cinfo = info->par;
+
+	DPRINTK ("ENTER\n");
+	DPRINTK ("virtual offset: (%d,%d)\n", var->xoffset, var->yoffset);
+
+	/* no range checks for xoffset and yoffset,   */
+	/* as fb_pan_display has already done this */
+	if (var->vmode & FB_VMODE_YWRAP)
+		return -EINVAL;
+
+	info->var.xoffset = var->xoffset;
+	info->var.yoffset = var->yoffset;
+
+	xoffset = var->xoffset * info->var.bits_per_pixel / 8;
+	yoffset = var->yoffset;
+
+	base = yoffset * cinfo->currentmode.line_length + xoffset;
+
+	if (info->var.bits_per_pixel == 1) {
+		/* base is already correct */
+		xpix = (unsigned char) (var->xoffset % 8);
+	} else {
+		base /= 4;
+		xpix = (unsigned char) ((xoffset % 4) * 2);
+	}
+
+        cirrusfb_WaitBLT(cinfo->regbase); /* make sure all the BLT's are done */
+
+	/* lower 8 + 8 bits of screen start address */
+	vga_wcrt (cinfo->regbase, VGA_CRTC_START_LO, (unsigned char) (base & 0xff));
+	vga_wcrt (cinfo->regbase, VGA_CRTC_START_HI, (unsigned char) (base >> 8));
+
+	/* construct bits 16, 17 and 18 of screen start address */
+	if (base & 0x10000)
+		tmp |= 0x01;
+	if (base & 0x20000)
+		tmp |= 0x04;
+	if (base & 0x40000)
+		tmp |= 0x08;
+
+	tmp2 = (vga_rcrt (cinfo->regbase, CL_CRT1B) & 0xf2) | tmp;	/* 0xf2 is %11110010, exclude tmp bits */
+	vga_wcrt (cinfo->regbase, CL_CRT1B, tmp2);
+
+	/* construct bit 19 of screen start address */
+	if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19) {
+		tmp2 = 0;
+		if (base & 0x80000)
+			tmp2 = 0x80;
+		vga_wcrt (cinfo->regbase, CL_CRT1D, tmp2);
+	}
+
+	/* write pixel panning value to AR33; this does not quite work in 8bpp */
+	/* ### Piccolo..? Will this work? */
+	if (info->var.bits_per_pixel == 1)
+		vga_wattr (cinfo->regbase, CL_AR33, xpix);
+
+	cirrusfb_WaitBLT (cinfo->regbase);
+
+	DPRINTK ("EXIT\n");
+	return (0);
+}
+
+
+static int cirrusfb_blank (int blank_mode, struct fb_info *info)
+{
+	/*
+	 *  Blank the screen if blank_mode != 0, else unblank. If blank == NULL
+	 *  then the caller blanks by setting the CLUT (Color Look Up Table) to all
+	 *  black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
+	 *  to e.g. a video mode which doesn't support it. Implements VESA suspend
+	 *  and powerdown modes on hardware that supports disabling hsync/vsync:
+	 *    blank_mode == 2: suspend vsync
+	 *    blank_mode == 3: suspend hsync
+	 *    blank_mode == 4: powerdown
+	 */
+	unsigned char val;
+	struct cirrusfb_info *cinfo = info->par;
+	int current_mode = cinfo->blank_mode;
+
+	DPRINTK ("ENTER, blank mode = %d\n", blank_mode);
+
+	if (info->state != FBINFO_STATE_RUNNING ||
+	    current_mode == blank_mode) {
+		DPRINTK ("EXIT, returning 0\n");
+		return 0;
+	}
+
+	/* Undo current */
+	if (current_mode == FB_BLANK_NORMAL ||
+	    current_mode == FB_BLANK_UNBLANK) {
+		/* unblank the screen */
+		val = vga_rseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE);
+		vga_wseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE, val & 0xdf);	/* clear "FullBandwidth" bit */
+		/* and undo VESA suspend trickery */
+		vga_wgfx (cinfo->regbase, CL_GRE, 0x00);
+	}
+
+	/* set new */
+	if(blank_mode > FB_BLANK_NORMAL) {
+		/* blank the screen */
+		val = vga_rseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE);
+		vga_wseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE, val | 0x20);	/* set "FullBandwidth" bit */
+	}
+
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANK:
+	case FB_BLANK_NORMAL:
+		break;
+	case FB_BLANK_VSYNC_SUSPEND:
+		vga_wgfx (cinfo->regbase, CL_GRE, 0x04);
+		break;
+	case FB_BLANK_HSYNC_SUSPEND:
+		vga_wgfx (cinfo->regbase, CL_GRE, 0x02);
+		break;
+	case FB_BLANK_POWERDOWN:
+		vga_wgfx (cinfo->regbase, CL_GRE, 0x06);
+		break;
+	default:
+		DPRINTK ("EXIT, returning 1\n");
+		return 1;
+	}
+
+	cinfo->blank_mode = blank_mode;
+	DPRINTK ("EXIT, returning 0\n");
+
+	/* Let fbcon do a soft blank for us */
+	return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
+}
+/**** END   Hardware specific Routines **************************************/
+/****************************************************************************/
+/**** BEGIN Internal Routines ***********************************************/
+
+static void init_vgachip (struct cirrusfb_info *cinfo)
+{
+	const struct cirrusfb_board_info_rec *bi;
+
+	DPRINTK ("ENTER\n");
+
+	assert (cinfo != NULL);
+
+	bi = &cirrusfb_board_info[cinfo->btype];
+
+	/* reset board globally */
+	switch (cinfo->btype) {
+	case BT_PICCOLO:
+		WSFR (cinfo, 0x01);
+		udelay (500);
+		WSFR (cinfo, 0x51);
+		udelay (500);
+		break;
+	case BT_PICASSO:
+		WSFR2 (cinfo, 0xff);
+		udelay (500);
+		break;
+	case BT_SD64:
+	case BT_SPECTRUM:
+		WSFR (cinfo, 0x1f);
+		udelay (500);
+		WSFR (cinfo, 0x4f);
+		udelay (500);
+		break;
+	case BT_PICASSO4:
+		vga_wcrt (cinfo->regbase, CL_CRT51, 0x00);	/* disable flickerfixer */
+		mdelay (100);
+		vga_wgfx (cinfo->regbase, CL_GR2F, 0x00);	/* from Klaus' NetBSD driver: */
+		vga_wgfx (cinfo->regbase, CL_GR33, 0x00);	/* put blitter into 542x compat */
+		vga_wgfx (cinfo->regbase, CL_GR31, 0x00);	/* mode */
+		break;
+
+	case BT_GD5480:
+		vga_wgfx (cinfo->regbase, CL_GR2F, 0x00);	/* from Klaus' NetBSD driver: */
+		break;
+
+	case BT_ALPINE:
+		/* Nothing to do to reset the board. */
+		break;
+
+	default:
+		printk (KERN_ERR "cirrusfb: Warning: Unknown board type\n");
+		break;
+	}
+
+	assert (cinfo->size > 0); /* make sure RAM size set by this point */
+
+	/* the P4 is not fully initialized here; I rely on it having been */
+	/* inited under AmigaOS already, which seems to work just fine    */
+	/* (Klaus advised to do it this way)                              */
+
+	if (cinfo->btype != BT_PICASSO4) {
+		WGen (cinfo, CL_VSSM, 0x10);	/* EGS: 0x16 */
+		WGen (cinfo, CL_POS102, 0x01);
+		WGen (cinfo, CL_VSSM, 0x08);	/* EGS: 0x0e */
+
+		if (cinfo->btype != BT_SD64)
+			WGen (cinfo, CL_VSSM2, 0x01);
+
+		vga_wseq (cinfo->regbase, CL_SEQR0, 0x03);	/* reset sequencer logic */
+
+		vga_wseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE, 0x21);	/* FullBandwidth (video off) and 8/9 dot clock */
+		WGen (cinfo, VGA_MIS_W, 0xc1);	/* polarity (-/-), disable access to display memory, VGA_CRTC_START_HI base address: color */
+
+/*      vga_wgfx (cinfo->regbase, CL_GRA, 0xce);    "magic cookie" - doesn't make any sense to me.. */
+		vga_wseq (cinfo->regbase, CL_SEQR6, 0x12);	/* unlock all extension registers */
+
+		vga_wgfx (cinfo->regbase, CL_GR31, 0x04);	/* reset blitter */
+
+		switch (cinfo->btype) {
+		case BT_GD5480:
+			vga_wseq (cinfo->regbase, CL_SEQRF, 0x98);
+			break;
+		case BT_ALPINE:
+			break;
+		case BT_SD64:
+			vga_wseq (cinfo->regbase, CL_SEQRF, 0xb8);
+			break;
+		default:
+			vga_wseq (cinfo->regbase, CL_SEQR16, 0x0f);
+			vga_wseq (cinfo->regbase, CL_SEQRF, 0xb0);
+			break;
+		}
+	}
+	vga_wseq (cinfo->regbase, VGA_SEQ_PLANE_WRITE, 0xff);	/* plane mask: nothing */
+	vga_wseq (cinfo->regbase, VGA_SEQ_CHARACTER_MAP, 0x00);	/* character map select: doesn't even matter in gx mode */
+	vga_wseq (cinfo->regbase, VGA_SEQ_MEMORY_MODE, 0x0e);	/* memory mode: chain-4, no odd/even, ext. memory */
+
+	/* controller-internal base address of video memory */
+	if (bi->init_sr07)
+		vga_wseq (cinfo->regbase, CL_SEQR7, bi->sr07);
+
+	/*  vga_wseq (cinfo->regbase, CL_SEQR8, 0x00); *//* EEPROM control: shouldn't be necessary to write to this at all.. */
+
+	vga_wseq (cinfo->regbase, CL_SEQR10, 0x00);		/* graphics cursor X position (incomplete; position gives rem. 3 bits */
+	vga_wseq (cinfo->regbase, CL_SEQR11, 0x00);		/* graphics cursor Y position (..."... ) */
+	vga_wseq (cinfo->regbase, CL_SEQR12, 0x00);		/* graphics cursor attributes */
+	vga_wseq (cinfo->regbase, CL_SEQR13, 0x00);		/* graphics cursor pattern address */
+
+	/* writing these on a P4 might give problems..  */
+	if (cinfo->btype != BT_PICASSO4) {
+		vga_wseq (cinfo->regbase, CL_SEQR17, 0x00);		/* configuration readback and ext. color */
+		vga_wseq (cinfo->regbase, CL_SEQR18, 0x02);		/* signature generator */
+	}
+
+	/* MCLK select etc. */
+	if (bi->init_sr1f)
+		vga_wseq (cinfo->regbase, CL_SEQR1F, bi->sr1f);
+
+	vga_wcrt (cinfo->regbase, VGA_CRTC_PRESET_ROW, 0x00);	/* Screen A preset row scan: none */
+	vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_START, 0x20);	/* Text cursor start: disable text cursor */
+	vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_END, 0x00);	/* Text cursor end: - */
+	vga_wcrt (cinfo->regbase, VGA_CRTC_START_HI, 0x00);	/* Screen start address high: 0 */
+	vga_wcrt (cinfo->regbase, VGA_CRTC_START_LO, 0x00);	/* Screen start address low: 0 */
+	vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_HI, 0x00);	/* text cursor location high: 0 */
+	vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_LO, 0x00);	/* text cursor location low: 0 */
+
+	vga_wcrt (cinfo->regbase, VGA_CRTC_UNDERLINE, 0x00);	/* Underline Row scanline: - */
+	vga_wcrt (cinfo->regbase, VGA_CRTC_MODE, 0xc3);	/* mode control: timing enable, byte mode, no compat modes */
+	vga_wcrt (cinfo->regbase, VGA_CRTC_LINE_COMPARE, 0x00);	/* Line Compare: not needed */
+	/* ### add 0x40 for text modes with > 30 MHz pixclock */
+	vga_wcrt (cinfo->regbase, CL_CRT1B, 0x02);	/* ext. display controls: ext.adr. wrap */
+
+	vga_wgfx (cinfo->regbase, VGA_GFX_SR_VALUE, 0x00);	/* Set/Reset registes: - */
+	vga_wgfx (cinfo->regbase, VGA_GFX_SR_ENABLE, 0x00);	/* Set/Reset enable: - */
+	vga_wgfx (cinfo->regbase, VGA_GFX_COMPARE_VALUE, 0x00);	/* Color Compare: - */
+	vga_wgfx (cinfo->regbase, VGA_GFX_DATA_ROTATE, 0x00);	/* Data Rotate: - */
+	vga_wgfx (cinfo->regbase, VGA_GFX_PLANE_READ, 0x00);	/* Read Map Select: - */
+	vga_wgfx (cinfo->regbase, VGA_GFX_MODE, 0x00);	/* Mode: conf. for 16/4/2 color mode, no odd/even, read/write mode 0 */
+	vga_wgfx (cinfo->regbase, VGA_GFX_MISC, 0x01);	/* Miscellaneous: memory map base address, graphics mode */
+	vga_wgfx (cinfo->regbase, VGA_GFX_COMPARE_MASK, 0x0f);	/* Color Don't care: involve all planes */
+	vga_wgfx (cinfo->regbase, VGA_GFX_BIT_MASK, 0xff);	/* Bit Mask: no mask at all */
+	if (cinfo->btype == BT_ALPINE)
+		vga_wgfx (cinfo->regbase, CL_GRB, 0x20);	/* (5434 can't have bit 3 set for bitblt) */
+	else
+		vga_wgfx (cinfo->regbase, CL_GRB, 0x28);	/* Graphics controller mode extensions: finer granularity, 8byte data latches */
+
+	vga_wgfx (cinfo->regbase, CL_GRC, 0xff);	/* Color Key compare: - */
+	vga_wgfx (cinfo->regbase, CL_GRD, 0x00);	/* Color Key compare mask: - */
+	vga_wgfx (cinfo->regbase, CL_GRE, 0x00);	/* Miscellaneous control: - */
+	/*  vga_wgfx (cinfo->regbase, CL_GR10, 0x00); *//* Background color byte 1: - */
+/*  vga_wgfx (cinfo->regbase, CL_GR11, 0x00); */
+
+	vga_wattr (cinfo->regbase, VGA_ATC_PALETTE0, 0x00);	/* Attribute Controller palette registers: "identity mapping" */
+	vga_wattr (cinfo->regbase, VGA_ATC_PALETTE1, 0x01);
+	vga_wattr (cinfo->regbase, VGA_ATC_PALETTE2, 0x02);
+	vga_wattr (cinfo->regbase, VGA_ATC_PALETTE3, 0x03);
+	vga_wattr (cinfo->regbase, VGA_ATC_PALETTE4, 0x04);
+	vga_wattr (cinfo->regbase, VGA_ATC_PALETTE5, 0x05);
+	vga_wattr (cinfo->regbase, VGA_ATC_PALETTE6, 0x06);
+	vga_wattr (cinfo->regbase, VGA_ATC_PALETTE7, 0x07);
+	vga_wattr (cinfo->regbase, VGA_ATC_PALETTE8, 0x08);
+	vga_wattr (cinfo->regbase, VGA_ATC_PALETTE9, 0x09);
+	vga_wattr (cinfo->regbase, VGA_ATC_PALETTEA, 0x0a);
+	vga_wattr (cinfo->regbase, VGA_ATC_PALETTEB, 0x0b);
+	vga_wattr (cinfo->regbase, VGA_ATC_PALETTEC, 0x0c);
+	vga_wattr (cinfo->regbase, VGA_ATC_PALETTED, 0x0d);
+	vga_wattr (cinfo->regbase, VGA_ATC_PALETTEE, 0x0e);
+	vga_wattr (cinfo->regbase, VGA_ATC_PALETTEF, 0x0f);
+
+	vga_wattr (cinfo->regbase, VGA_ATC_MODE, 0x01);	/* Attribute Controller mode: graphics mode */
+	vga_wattr (cinfo->regbase, VGA_ATC_OVERSCAN, 0x00);	/* Overscan color reg.: reg. 0 */
+	vga_wattr (cinfo->regbase, VGA_ATC_PLANE_ENABLE, 0x0f);	/* Color Plane enable: Enable all 4 planes */
+/* ###  vga_wattr (cinfo->regbase, CL_AR33, 0x00); * Pixel Panning: - */
+	vga_wattr (cinfo->regbase, VGA_ATC_COLOR_PAGE, 0x00);	/* Color Select: - */
+
+	WGen (cinfo, VGA_PEL_MSK, 0xff);	/* Pixel mask: no mask */
+
+	if (cinfo->btype != BT_ALPINE && cinfo->btype != BT_GD5480)
+		WGen (cinfo, VGA_MIS_W, 0xc3);	/* polarity (-/-), enable display mem, VGA_CRTC_START_HI i/o base = color */
+
+	vga_wgfx (cinfo->regbase, CL_GR31, 0x04);	/* BLT Start/status: Blitter reset */
+	vga_wgfx (cinfo->regbase, CL_GR31, 0x00);	/* - " -           : "end-of-reset" */
+
+	/* misc... */
+	WHDR (cinfo, 0);	/* Hidden DAC register: - */
+
+	printk (KERN_DEBUG "cirrusfb: This board has %ld bytes of DRAM memory\n", cinfo->size);
+	DPRINTK ("EXIT\n");
+	return;
+}
+
+static void switch_monitor (struct cirrusfb_info *cinfo, int on)
+{
+#ifdef CONFIG_ZORRO /* only works on Zorro boards */
+	static int IsOn = 0;	/* XXX not ok for multiple boards */
+
+	DPRINTK ("ENTER\n");
+
+	if (cinfo->btype == BT_PICASSO4)
+		return;		/* nothing to switch */
+	if (cinfo->btype == BT_ALPINE)
+		return;		/* nothing to switch */
+	if (cinfo->btype == BT_GD5480)
+		return;		/* nothing to switch */
+	if (cinfo->btype == BT_PICASSO) {
+		if ((on && !IsOn) || (!on && IsOn))
+			WSFR (cinfo, 0xff);
+
+		DPRINTK ("EXIT\n");
+		return;
+	}
+	if (on) {
+		switch (cinfo->btype) {
+		case BT_SD64:
+			WSFR (cinfo, cinfo->SFR | 0x21);
+			break;
+		case BT_PICCOLO:
+			WSFR (cinfo, cinfo->SFR | 0x28);
+			break;
+		case BT_SPECTRUM:
+			WSFR (cinfo, 0x6f);
+			break;
+		default: /* do nothing */ break;
+		}
+	} else {
+		switch (cinfo->btype) {
+		case BT_SD64:
+			WSFR (cinfo, cinfo->SFR & 0xde);
+			break;
+		case BT_PICCOLO:
+			WSFR (cinfo, cinfo->SFR & 0xd7);
+			break;
+		case BT_SPECTRUM:
+			WSFR (cinfo, 0x4f);
+			break;
+		default: /* do nothing */ break;
+		}
+	}
+
+	DPRINTK ("EXIT\n");
+#endif /* CONFIG_ZORRO */
+}
+
+
+/******************************************/
+/* Linux 2.6-style  accelerated functions */
+/******************************************/
+
+static void cirrusfb_prim_fillrect(struct cirrusfb_info *cinfo,
+				   const struct fb_fillrect *region)
+{
+	int m; /* bytes per pixel */
+	if(cinfo->info->var.bits_per_pixel == 1) {
+		cirrusfb_RectFill(cinfo->regbase, cinfo->info->var.bits_per_pixel,
+				  region->dx / 8, region->dy,
+				  region->width / 8, region->height,
+				  region->color,
+				  cinfo->currentmode.line_length);
+	} else {
+		m = ( cinfo->info->var.bits_per_pixel + 7 ) / 8;
+		cirrusfb_RectFill(cinfo->regbase, cinfo->info->var.bits_per_pixel,
+				  region->dx * m, region->dy,
+				  region->width * m, region->height,
+				  region->color,
+				  cinfo->currentmode.line_length);
+	}
+	return;
+}
+
+static void cirrusfb_fillrect (struct fb_info *info, const struct fb_fillrect *region)
+{
+	struct cirrusfb_info *cinfo = info->par;
+	struct fb_fillrect modded;
+	int vxres, vyres;
+
+	if (info->state != FBINFO_STATE_RUNNING)
+		return;
+	if (info->flags & FBINFO_HWACCEL_DISABLED) {
+		cfb_fillrect(info, region);
+		return;
+	}
+
+	vxres = info->var.xres_virtual;
+	vyres = info->var.yres_virtual;
+
+	memcpy(&modded, region, sizeof(struct fb_fillrect));
+
+	if(!modded.width || !modded.height ||
+	   modded.dx >= vxres || modded.dy >= vyres)
+		return;
+
+	if(modded.dx + modded.width  > vxres) modded.width  = vxres - modded.dx;
+	if(modded.dy + modded.height > vyres) modded.height = vyres - modded.dy;
+
+	cirrusfb_prim_fillrect(cinfo, &modded);
+}
+
+static void cirrusfb_prim_copyarea(struct cirrusfb_info *cinfo,
+				   const struct fb_copyarea *area)
+{
+	int m; /* bytes per pixel */
+	if(cinfo->info->var.bits_per_pixel == 1) {
+		cirrusfb_BitBLT(cinfo->regbase, cinfo->info->var.bits_per_pixel,
+				area->sx / 8, area->sy,
+				area->dx / 8, area->dy,
+				area->width / 8, area->height,
+				cinfo->currentmode.line_length);
+	} else {
+		m = ( cinfo->info->var.bits_per_pixel + 7 ) / 8;
+		cirrusfb_BitBLT(cinfo->regbase, cinfo->info->var.bits_per_pixel,
+				area->sx * m, area->sy,
+				area->dx * m, area->dy,
+				area->width * m, area->height,
+				cinfo->currentmode.line_length);
+	}
+	return;
+}
+
+
+static void cirrusfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+	struct cirrusfb_info *cinfo = info->par;
+	struct fb_copyarea modded;
+	u32 vxres, vyres;
+	modded.sx = area->sx;
+	modded.sy = area->sy;
+	modded.dx = area->dx;
+	modded.dy = area->dy;
+	modded.width  = area->width;
+	modded.height = area->height;
+
+	if (info->state != FBINFO_STATE_RUNNING)
+		return;
+	if (info->flags & FBINFO_HWACCEL_DISABLED) {
+		cfb_copyarea(info, area);
+		return;
+	}
+
+	vxres = info->var.xres_virtual;
+	vyres = info->var.yres_virtual;
+
+	if(!modded.width || !modded.height ||
+	   modded.sx >= vxres || modded.sy >= vyres ||
+	   modded.dx >= vxres || modded.dy >= vyres)
+		return;
+
+	if(modded.sx + modded.width > vxres)  modded.width = vxres - modded.sx;
+	if(modded.dx + modded.width > vxres)  modded.width = vxres - modded.dx;
+	if(modded.sy + modded.height > vyres) modded.height = vyres - modded.sy;
+	if(modded.dy + modded.height > vyres) modded.height = vyres - modded.dy;
+
+	cirrusfb_prim_copyarea(cinfo, &modded);
+}
+
+static void cirrusfb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	struct cirrusfb_info *cinfo = info->par;
+
+        cirrusfb_WaitBLT(cinfo->regbase);
+	cfb_imageblit(info, image);
+}
+
+
+#ifdef CONFIG_PPC_PREP
+#define PREP_VIDEO_BASE ((volatile unsigned long) 0xC0000000)
+#define PREP_IO_BASE    ((volatile unsigned char *) 0x80000000)
+static void get_prep_addrs (unsigned long *display, unsigned long *registers)
+{
+	DPRINTK ("ENTER\n");
+
+	*display = PREP_VIDEO_BASE;
+	*registers = (unsigned long) PREP_IO_BASE;
+
+	DPRINTK ("EXIT\n");
+}
+
+#endif				/* CONFIG_PPC_PREP */
+
+
+#ifdef CONFIG_PCI
+static int release_io_ports = 0;
+
+/* Pulled the logic from XFree86 Cirrus driver to get the memory size,
+ * based on the DRAM bandwidth bit and DRAM bank switching bit.  This
+ * works with 1MB, 2MB and 4MB configurations (which the Motorola boards
+ * seem to have. */
+static unsigned int cirrusfb_get_memsize (u8 __iomem *regbase)
+{
+	unsigned long mem;
+	unsigned char SRF;
+
+	DPRINTK ("ENTER\n");
+
+	SRF = vga_rseq (regbase, CL_SEQRF);
+	switch ((SRF & 0x18)) {
+	    case 0x08: mem = 512 * 1024; break;
+	    case 0x10: mem = 1024 * 1024; break;
+		/* 64-bit DRAM data bus width; assume 2MB. Also indicates 2MB memory
+		   * on the 5430. */
+	    case 0x18: mem = 2048 * 1024; break;
+	    default: printk ("CLgenfb: Unknown memory size!\n");
+		mem = 1024 * 1024;
+	}
+	if (SRF & 0x80) {
+		/* If DRAM bank switching is enabled, there must be twice as much
+		   * memory installed. (4MB on the 5434) */
+		mem *= 2;
+	}
+	/* TODO: Handling of GD5446/5480 (see XF86 sources ...) */
+
+	DPRINTK ("EXIT\n");
+	return mem;
+}
+
+
+
+static void get_pci_addrs (const struct pci_dev *pdev,
+			   unsigned long *display, unsigned long *registers)
+{
+	assert (pdev != NULL);
+	assert (display != NULL);
+	assert (registers != NULL);
+
+	DPRINTK ("ENTER\n");
+
+	*display = 0;
+	*registers = 0;
+
+	/* This is a best-guess for now */
+
+	if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) {
+		*display = pci_resource_start(pdev, 1);
+		*registers = pci_resource_start(pdev, 0);
+	} else {
+		*display = pci_resource_start(pdev, 0);
+		*registers = pci_resource_start(pdev, 1);
+	}
+
+	assert (*display != 0);
+
+	DPRINTK ("EXIT\n");
+}
+
+
+static void cirrusfb_pci_unmap (struct cirrusfb_info *cinfo)
+{
+	struct pci_dev *pdev = cinfo->pdev;
+
+	iounmap(cinfo->fbmem);
+#if 0 /* if system didn't claim this region, we would... */
+	release_mem_region(0xA0000, 65535);
+#endif
+	if (release_io_ports)
+		release_region(0x3C0, 32);
+	pci_release_regions(pdev);
+	framebuffer_release(cinfo->info);
+	pci_disable_device(pdev);
+}
+#endif /* CONFIG_PCI */
+
+
+#ifdef CONFIG_ZORRO
+static void __devexit cirrusfb_zorro_unmap (struct cirrusfb_info *cinfo)
+{
+	zorro_release_device(cinfo->zdev);
+
+	if (cinfo->btype == BT_PICASSO4) {
+		cinfo->regbase -= 0x600000;
+		iounmap ((void *)cinfo->regbase);
+		iounmap ((void *)cinfo->fbmem);
+	} else {
+		if (zorro_resource_start(cinfo->zdev) > 0x01000000)
+			iounmap ((void *)cinfo->fbmem);
+	}
+	framebuffer_release(cinfo->info);
+}
+#endif /* CONFIG_ZORRO */
+
+static int cirrusfb_set_fbinfo(struct cirrusfb_info *cinfo)
+{
+	struct fb_info *info = cinfo->info;
+	struct fb_var_screeninfo *var = &info->var;
+
+	info->par = cinfo;
+	info->pseudo_palette = cinfo->pseudo_palette;
+	info->flags = FBINFO_DEFAULT
+		    | FBINFO_HWACCEL_XPAN
+		    | FBINFO_HWACCEL_YPAN
+		    | FBINFO_HWACCEL_FILLRECT
+		    | FBINFO_HWACCEL_COPYAREA;
+	if (noaccel)
+		info->flags |= FBINFO_HWACCEL_DISABLED;
+	info->fbops = &cirrusfb_ops;
+	info->screen_base = cinfo->fbmem;
+	if (cinfo->btype == BT_GD5480) {
+		if (var->bits_per_pixel == 16)
+			info->screen_base += 1 * MB_;
+		if (var->bits_per_pixel == 24 || var->bits_per_pixel == 32)
+			info->screen_base += 2 * MB_;
+	}
+
+	/* Fill fix common fields */
+	strlcpy(info->fix.id, cirrusfb_board_info[cinfo->btype].name,
+		sizeof(info->fix.id));
+
+	/* monochrome: only 1 memory plane */
+	/* 8 bit and above: Use whole memory area */
+	info->fix.smem_start = cinfo->fbmem_phys;
+	info->fix.smem_len   = (var->bits_per_pixel == 1) ? cinfo->size / 4 : cinfo->size;
+	info->fix.type       = cinfo->currentmode.type;
+	info->fix.type_aux   = 0;
+	info->fix.visual     = cinfo->currentmode.visual;
+	info->fix.xpanstep   = 1;
+	info->fix.ypanstep   = 1;
+	info->fix.ywrapstep  = 0;
+	info->fix.line_length = cinfo->currentmode.line_length;
+
+	/* FIXME: map region at 0xB8000 if available, fill in here */
+	info->fix.mmio_start = cinfo->fbregs_phys;
+	info->fix.mmio_len   = 0;
+	info->fix.accel = FB_ACCEL_NONE;
+
+	fb_alloc_cmap(&info->cmap, 256, 0);
+
+	return 0;
+}
+
+static int cirrusfb_register(struct cirrusfb_info *cinfo)
+{
+	struct fb_info *info;
+	int err;
+	cirrusfb_board_t btype;
+
+	DPRINTK ("ENTER\n");
+
+	printk (KERN_INFO "cirrusfb: Driver for Cirrus Logic based graphic boards, v" CIRRUSFB_VERSION "\n");
+
+	info = cinfo->info;
+	btype = cinfo->btype;
+
+	/* sanity checks */
+	assert (btype != BT_NONE);
+
+	DPRINTK ("cirrusfb: (RAM start set to: 0x%p)\n", cinfo->fbmem);
+
+	/* Make pretend we've set the var so our structures are in a "good" */
+	/* state, even though we haven't written the mode to the hw yet...  */
+	info->var = cirrusfb_predefined[cirrusfb_def_mode].var;
+	info->var.activate = FB_ACTIVATE_NOW;
+
+	err = cirrusfb_decode_var(&info->var, &cinfo->currentmode, info);
+	if (err < 0) {
+		/* should never happen */
+		DPRINTK("choking on default var... umm, no good.\n");
+		goto err_unmap_cirrusfb;
+	}
+
+	/* set all the vital stuff */
+	cirrusfb_set_fbinfo(cinfo);
+
+	err = register_framebuffer(info);
+	if (err < 0) {
+		printk (KERN_ERR "cirrusfb: could not register fb device; err = %d!\n", err);
+		goto err_dealloc_cmap;
+	}
+
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+
+err_dealloc_cmap:
+	fb_dealloc_cmap(&info->cmap);
+err_unmap_cirrusfb:
+	cinfo->unmap(cinfo);
+	return err;
+}
+
+static void __devexit cirrusfb_cleanup (struct fb_info *info)
+{
+	struct cirrusfb_info *cinfo = info->par;
+	DPRINTK ("ENTER\n");
+
+	switch_monitor (cinfo, 0);
+
+	unregister_framebuffer (info);
+	fb_dealloc_cmap (&info->cmap);
+	printk ("Framebuffer unregistered\n");
+	cinfo->unmap(cinfo);
+
+	DPRINTK ("EXIT\n");
+}
+
+
+#ifdef CONFIG_PCI
+static int cirrusfb_pci_register (struct pci_dev *pdev,
+				  const struct pci_device_id *ent)
+{
+	struct cirrusfb_info *cinfo;
+	struct fb_info *info;
+	cirrusfb_board_t btype;
+	unsigned long board_addr, board_size;
+	int ret;
+
+	ret = pci_enable_device(pdev);
+	if (ret < 0) {
+		printk(KERN_ERR "cirrusfb: Cannot enable PCI device\n");
+		goto err_out;
+	}
+
+	info = framebuffer_alloc(sizeof(struct cirrusfb_info), &pdev->dev);
+	if (!info) {
+		printk(KERN_ERR "cirrusfb: could not allocate memory\n");
+		ret = -ENOMEM;
+		goto err_disable;
+	}
+
+	cinfo = info->par;
+	cinfo->info = info;
+	cinfo->pdev = pdev;
+	cinfo->btype = btype = (cirrusfb_board_t) ent->driver_data;
+
+	DPRINTK (" Found PCI device, base address 0 is 0x%lx, btype set to %d\n",
+		pdev->resource[0].start, btype);
+	DPRINTK (" base address 1 is 0x%lx\n", pdev->resource[1].start);
+
+	if(isPReP) {
+		pci_write_config_dword (pdev, PCI_BASE_ADDRESS_0, 0x00000000);
+#ifdef CONFIG_PPC_PREP
+		get_prep_addrs (&board_addr, &cinfo->fbregs_phys);
+#endif
+		/* PReP dies if we ioremap the IO registers, but it works w/out... */
+		cinfo->regbase = (char __iomem *) cinfo->fbregs_phys;
+	} else {
+		DPRINTK ("Attempt to get PCI info for Cirrus Graphics Card\n");
+		get_pci_addrs (pdev, &board_addr, &cinfo->fbregs_phys);
+		cinfo->regbase = NULL;		/* FIXME: this forces VGA.  alternatives? */
+	}
+
+	DPRINTK ("Board address: 0x%lx, register address: 0x%lx\n", board_addr, cinfo->fbregs_phys);
+
+	board_size = (btype == BT_GD5480) ?
+		32 * MB_ : cirrusfb_get_memsize (cinfo->regbase);
+
+	ret = pci_request_regions(pdev, "cirrusfb");
+	if (ret <0) {
+		printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n",
+		       board_addr);
+		goto err_release_fb;
+	}
+#if 0 /* if the system didn't claim this region, we would... */
+	if (!request_mem_region(0xA0000, 65535, "cirrusfb")) {
+		printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n"
+,
+		       0xA0000L);
+		ret = -EBUSY;
+		goto err_release_regions;
+	}
+#endif
+	if (request_region(0x3C0, 32, "cirrusfb"))
+		release_io_ports = 1;
+
+	cinfo->fbmem = ioremap(board_addr, board_size);
+	if (!cinfo->fbmem) {
+		ret = -EIO;
+		goto err_release_legacy;
+	}
+
+	cinfo->fbmem_phys = board_addr;
+	cinfo->size = board_size;
+	cinfo->unmap = cirrusfb_pci_unmap;
+
+	printk (" RAM (%lu kB) at 0xx%lx, ", cinfo->size / KB_, board_addr);
+	printk ("Cirrus Logic chipset on PCI bus\n");
+	pci_set_drvdata(pdev, info);
+
+	return cirrusfb_register(cinfo);
+
+err_release_legacy:
+	if (release_io_ports)
+		release_region(0x3C0, 32);
+#if 0
+	release_mem_region(0xA0000, 65535);
+err_release_regions:
+#endif
+	pci_release_regions(pdev);
+err_release_fb:
+	framebuffer_release(info);
+err_disable:
+	pci_disable_device(pdev);
+err_out:
+	return ret;
+}
+
+static void __devexit cirrusfb_pci_unregister (struct pci_dev *pdev)
+{
+	struct fb_info *info = pci_get_drvdata(pdev);
+	DPRINTK ("ENTER\n");
+
+	cirrusfb_cleanup (info);
+
+	DPRINTK ("EXIT\n");
+}
+
+static struct pci_driver cirrusfb_pci_driver = {
+	.name		= "cirrusfb",
+	.id_table	= cirrusfb_pci_table,
+	.probe		= cirrusfb_pci_register,
+	.remove		= __devexit_p(cirrusfb_pci_unregister),
+#ifdef CONFIG_PM
+#if 0
+	.suspend	= cirrusfb_pci_suspend,
+	.resume		= cirrusfb_pci_resume,
+#endif
+#endif
+};
+#endif /* CONFIG_PCI */
+
+
+#ifdef CONFIG_ZORRO
+static int cirrusfb_zorro_register(struct zorro_dev *z,
+				   const struct zorro_device_id *ent)
+{
+	struct cirrusfb_info *cinfo;
+	struct fb_info *info;
+	cirrusfb_board_t btype;
+	struct zorro_dev *z2 = NULL;
+	unsigned long board_addr, board_size, size;
+	int ret;
+
+	btype = ent->driver_data;
+	if (cirrusfb_zorro_table2[btype].id2)
+		z2 = zorro_find_device(cirrusfb_zorro_table2[btype].id2, NULL);
+	size = cirrusfb_zorro_table2[btype].size;
+	printk(KERN_INFO "cirrusfb: %s board detected; ",
+	       cirrusfb_board_info[btype].name);
+
+	info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev);
+	if (!info) {
+		printk (KERN_ERR "cirrusfb: could not allocate memory\n");
+		ret = -ENOMEM;
+		goto err_out;
+	}
+
+	cinfo = info->par;
+	cinfo->info = info;
+	cinfo->btype = btype;
+
+	assert (z > 0);
+	assert (z2 >= 0);
+	assert (btype != BT_NONE);
+
+	cinfo->zdev = z;
+	board_addr = zorro_resource_start(z);
+	board_size = zorro_resource_len(z);
+	cinfo->size = size;
+
+	if (!zorro_request_device(z, "cirrusfb")) {
+		printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n",
+		       board_addr);
+		ret = -EBUSY;
+		goto err_release_fb;
+	}
+
+	printk (" RAM (%lu MB) at $%lx, ", board_size / MB_, board_addr);
+
+	ret = -EIO;
+
+	if (btype == BT_PICASSO4) {
+		printk (" REG at $%lx\n", board_addr + 0x600000);
+
+		/* To be precise, for the P4 this is not the */
+		/* begin of the board, but the begin of RAM. */
+		/* for P4, map in its address space in 2 chunks (### TEST! ) */
+		/* (note the ugly hardcoded 16M number) */
+		cinfo->regbase = ioremap (board_addr, 16777216);
+		if (!cinfo->regbase)
+			goto err_release_region;
+
+		DPRINTK ("cirrusfb: Virtual address for board set to: $%p\n", cinfo->regbase);
+		cinfo->regbase += 0x600000;
+		cinfo->fbregs_phys = board_addr + 0x600000;
+
+		cinfo->fbmem_phys = board_addr + 16777216;
+		cinfo->fbmem = ioremap (cinfo->fbmem_phys, 16777216);
+		if (!cinfo->fbmem)
+			goto err_unmap_regbase;
+	} else {
+		printk (" REG at $%lx\n", (unsigned long) z2->resource.start);
+
+		cinfo->fbmem_phys = board_addr;
+		if (board_addr > 0x01000000)
+			cinfo->fbmem = ioremap (board_addr, board_size);
+		else
+			cinfo->fbmem = (caddr_t) ZTWO_VADDR (board_addr);
+		if (!cinfo->fbmem)
+			goto err_release_region;
+
+		/* set address for REG area of board */
+		cinfo->regbase = (caddr_t) ZTWO_VADDR (z2->resource.start);
+		cinfo->fbregs_phys = z2->resource.start;
+
+		DPRINTK ("cirrusfb: Virtual address for board set to: $%p\n", cinfo->regbase);
+	}
+	cinfo->unmap = cirrusfb_zorro_unmap;
+
+	printk (KERN_INFO "Cirrus Logic chipset on Zorro bus\n");
+	zorro_set_drvdata(z, info);
+
+	return cirrusfb_register(cinfo);
+
+err_unmap_regbase:
+	/* Parental advisory: explicit hack */
+	iounmap(cinfo->regbase - 0x600000);
+err_release_region:
+	release_region(board_addr, board_size);
+err_release_fb:
+	framebuffer_release(info);
+err_out:
+	return ret;
+}
+
+void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z)
+{
+	struct fb_info *info = zorro_get_drvdata(z);
+	DPRINTK ("ENTER\n");
+
+	cirrusfb_cleanup (info);
+
+	DPRINTK ("EXIT\n");
+}
+
+static struct zorro_driver cirrusfb_zorro_driver = {
+	.name		= "cirrusfb",
+	.id_table	= cirrusfb_zorro_table,
+	.probe		= cirrusfb_zorro_register,
+	.remove		= __devexit_p(cirrusfb_zorro_unregister),
+};
+#endif /* CONFIG_ZORRO */
+
+static int __init cirrusfb_init(void)
+{
+	int error = 0;
+
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("cirrusfb", &option))
+		return -ENODEV;
+	cirrusfb_setup(option);
+#endif
+
+#ifdef CONFIG_ZORRO
+	error |= zorro_module_init(&cirrusfb_zorro_driver);
+#endif
+#ifdef CONFIG_PCI
+	error |= pci_register_driver(&cirrusfb_pci_driver);
+#endif
+	return error;
+}
+
+
+
+#ifndef MODULE
+static int __init cirrusfb_setup(char *options) {
+	char *this_opt, s[32];
+	int i;
+
+	DPRINTK ("ENTER\n");
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep (&options, ",")) != NULL) {	
+		if (!*this_opt) continue;
+
+		DPRINTK("cirrusfb_setup: option '%s'\n", this_opt);
+
+		for (i = 0; i < NUM_TOTAL_MODES; i++) {
+			sprintf (s, "mode:%s", cirrusfb_predefined[i].name);
+			if (strcmp (this_opt, s) == 0)
+				cirrusfb_def_mode = i;
+		}
+		if (!strcmp(this_opt, "noaccel"))
+			noaccel = 1;
+	}
+	return 0;
+}
+#endif
+
+
+    /*
+     *  Modularization
+     */
+
+MODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik <jgarzik@pobox.com>");
+MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips");
+MODULE_LICENSE("GPL");
+
+static void __exit cirrusfb_exit (void)
+{
+#ifdef CONFIG_PCI
+	pci_unregister_driver(&cirrusfb_pci_driver);
+#endif
+#ifdef CONFIG_ZORRO
+	zorro_unregister_driver(&cirrusfb_zorro_driver);
+#endif
+}
+
+module_init(cirrusfb_init);
+
+#ifdef MODULE
+module_exit(cirrusfb_exit);
+#endif
+
+
+/**********************************************************************/
+/* about the following functions - I have used the same names for the */
+/* functions as Markus Wild did in his Retina driver for NetBSD as    */
+/* they just made sense for this purpose. Apart from that, I wrote    */
+/* these functions myself.                                            */
+/**********************************************************************/
+
+/*** WGen() - write into one of the external/general registers ***/
+static void WGen (const struct cirrusfb_info *cinfo,
+		  int regnum, unsigned char val)
+{
+	unsigned long regofs = 0;
+
+	if (cinfo->btype == BT_PICASSO) {
+		/* Picasso II specific hack */
+/*              if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || regnum == CL_VSSM2) */
+		if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
+			regofs = 0xfff;
+	}
+
+	vga_w (cinfo->regbase, regofs + regnum, val);
+}
+
+/*** RGen() - read out one of the external/general registers ***/
+static unsigned char RGen (const struct cirrusfb_info *cinfo, int regnum)
+{
+	unsigned long regofs = 0;
+
+	if (cinfo->btype == BT_PICASSO) {
+		/* Picasso II specific hack */
+/*              if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || regnum == CL_VSSM2) */
+		if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
+			regofs = 0xfff;
+	}
+
+	return vga_r (cinfo->regbase, regofs + regnum);
+}
+
+/*** AttrOn() - turn on VideoEnable for Attribute controller ***/
+static void AttrOn (const struct cirrusfb_info *cinfo)
+{
+	assert (cinfo != NULL);
+
+	DPRINTK ("ENTER\n");
+
+	if (vga_rcrt (cinfo->regbase, CL_CRT24) & 0x80) {
+		/* if we're just in "write value" mode, write back the */
+		/* same value as before to not modify anything */
+		vga_w (cinfo->regbase, VGA_ATT_IW,
+		       vga_r (cinfo->regbase, VGA_ATT_R));
+	}
+	/* turn on video bit */
+/*      vga_w (cinfo->regbase, VGA_ATT_IW, 0x20); */
+	vga_w (cinfo->regbase, VGA_ATT_IW, 0x33);
+
+	/* dummy write on Reg0 to be on "write index" mode next time */
+	vga_w (cinfo->regbase, VGA_ATT_IW, 0x00);
+
+	DPRINTK ("EXIT\n");
+}
+
+/*** WHDR() - write into the Hidden DAC register ***/
+/* as the HDR is the only extension register that requires special treatment
+ * (the other extension registers are accessible just like the "ordinary"
+ * registers of their functional group) here is a specialized routine for
+ * accessing the HDR
+ */
+static void WHDR (const struct cirrusfb_info *cinfo, unsigned char val)
+{
+	unsigned char dummy;
+
+	if (cinfo->btype == BT_PICASSO) {
+		/* Klaus' hint for correct access to HDR on some boards */
+		/* first write 0 to pixel mask (3c6) */
+		WGen (cinfo, VGA_PEL_MSK, 0x00);
+		udelay (200);
+		/* next read dummy from pixel address (3c8) */
+		dummy = RGen (cinfo, VGA_PEL_IW);
+		udelay (200);
+	}
+	/* now do the usual stuff to access the HDR */
+
+	dummy = RGen (cinfo, VGA_PEL_MSK);
+	udelay (200);
+	dummy = RGen (cinfo, VGA_PEL_MSK);
+	udelay (200);
+	dummy = RGen (cinfo, VGA_PEL_MSK);
+	udelay (200);
+	dummy = RGen (cinfo, VGA_PEL_MSK);
+	udelay (200);
+
+	WGen (cinfo, VGA_PEL_MSK, val);
+	udelay (200);
+
+	if (cinfo->btype == BT_PICASSO) {
+		/* now first reset HDR access counter */
+		dummy = RGen (cinfo, VGA_PEL_IW);
+		udelay (200);
+
+		/* and at the end, restore the mask value */
+		/* ## is this mask always 0xff? */
+		WGen (cinfo, VGA_PEL_MSK, 0xff);
+		udelay (200);
+	}
+}
+
+
+/*** WSFR() - write to the "special function register" (SFR) ***/
+static void WSFR (struct cirrusfb_info *cinfo, unsigned char val)
+{
+#ifdef CONFIG_ZORRO
+	assert (cinfo->regbase != NULL);
+	cinfo->SFR = val;
+	z_writeb (val, cinfo->regbase + 0x8000);
+#endif
+}
+
+/* The Picasso has a second register for switching the monitor bit */
+static void WSFR2 (struct cirrusfb_info *cinfo, unsigned char val)
+{
+#ifdef CONFIG_ZORRO
+	/* writing an arbitrary value to this one causes the monitor switcher */
+	/* to flip to Amiga display */
+	assert (cinfo->regbase != NULL);
+	cinfo->SFR = val;
+	z_writeb (val, cinfo->regbase + 0x9000);
+#endif
+}
+
+
+/*** WClut - set CLUT entry (range: 0..63) ***/
+static void WClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char red,
+	    unsigned char green, unsigned char blue)
+{
+	unsigned int data = VGA_PEL_D;
+
+	/* address write mode register is not translated.. */
+	vga_w (cinfo->regbase, VGA_PEL_IW, regnum);
+
+	if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 ||
+	    cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) {
+		/* but DAC data register IS, at least for Picasso II */
+		if (cinfo->btype == BT_PICASSO)
+			data += 0xfff;
+		vga_w (cinfo->regbase, data, red);
+		vga_w (cinfo->regbase, data, green);
+		vga_w (cinfo->regbase, data, blue);
+	} else {
+		vga_w (cinfo->regbase, data, blue);
+		vga_w (cinfo->regbase, data, green);
+		vga_w (cinfo->regbase, data, red);
+	}
+}
+
+
+#if 0
+/*** RClut - read CLUT entry (range 0..63) ***/
+static void RClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char *red,
+	    unsigned char *green, unsigned char *blue)
+{
+	unsigned int data = VGA_PEL_D;
+
+	vga_w (cinfo->regbase, VGA_PEL_IR, regnum);
+
+	if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 ||
+	    cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) {
+		if (cinfo->btype == BT_PICASSO)
+			data += 0xfff;
+		*red = vga_r (cinfo->regbase, data);
+		*green = vga_r (cinfo->regbase, data);
+		*blue = vga_r (cinfo->regbase, data);
+	} else {
+		*blue = vga_r (cinfo->regbase, data);
+		*green = vga_r (cinfo->regbase, data);
+		*red = vga_r (cinfo->regbase, data);
+	}
+}
+#endif
+
+
+/*******************************************************************
+	cirrusfb_WaitBLT()
+
+	Wait for the BitBLT engine to complete a possible earlier job
+*********************************************************************/
+
+/* FIXME: use interrupts instead */
+static void cirrusfb_WaitBLT (u8 __iomem *regbase)
+{
+	/* now busy-wait until we're done */
+	while (vga_rgfx (regbase, CL_GR31) & 0x08)
+		/* do nothing */ ;
+}
+
+/*******************************************************************
+	cirrusfb_BitBLT()
+
+	perform accelerated "scrolling"
+********************************************************************/
+
+static void cirrusfb_BitBLT (u8 __iomem *regbase, int bits_per_pixel,
+			     u_short curx, u_short cury, u_short destx, u_short desty,
+			     u_short width, u_short height, u_short line_length)
+{
+	u_short nwidth, nheight;
+	u_long nsrc, ndest;
+	u_char bltmode;
+
+	DPRINTK ("ENTER\n");
+
+	nwidth = width - 1;
+	nheight = height - 1;
+
+	bltmode = 0x00;
+	/* if source adr < dest addr, do the Blt backwards */
+	if (cury <= desty) {
+		if (cury == desty) {
+			/* if src and dest are on the same line, check x */
+			if (curx < destx)
+				bltmode |= 0x01;
+		} else
+			bltmode |= 0x01;
+	}
+	if (!bltmode) {
+		/* standard case: forward blitting */
+		nsrc = (cury * line_length) + curx;
+		ndest = (desty * line_length) + destx;
+	} else {
+		/* this means start addresses are at the end, counting backwards */
+		nsrc = cury * line_length + curx + nheight * line_length + nwidth;
+		ndest = desty * line_length + destx + nheight * line_length + nwidth;
+	}
+
+	/*
+	   run-down of registers to be programmed:
+	   destination pitch
+	   source pitch
+	   BLT width/height
+	   source start
+	   destination start
+	   BLT mode
+	   BLT ROP
+	   VGA_GFX_SR_VALUE / VGA_GFX_SR_ENABLE: "fill color"
+	   start/stop
+	 */
+
+        cirrusfb_WaitBLT(regbase);
+
+	/* pitch: set to line_length */
+	vga_wgfx (regbase, CL_GR24, line_length & 0xff);	/* dest pitch low */
+	vga_wgfx (regbase, CL_GR25, (line_length >> 8));	/* dest pitch hi */
+	vga_wgfx (regbase, CL_GR26, line_length & 0xff);	/* source pitch low */
+	vga_wgfx (regbase, CL_GR27, (line_length >> 8));	/* source pitch hi */
+
+	/* BLT width: actual number of pixels - 1 */
+	vga_wgfx (regbase, CL_GR20, nwidth & 0xff);	/* BLT width low */
+	vga_wgfx (regbase, CL_GR21, (nwidth >> 8));	/* BLT width hi */
+
+	/* BLT height: actual number of lines -1 */
+	vga_wgfx (regbase, CL_GR22, nheight & 0xff);	/* BLT height low */
+	vga_wgfx (regbase, CL_GR23, (nheight >> 8));	/* BLT width hi */
+
+	/* BLT destination */
+	vga_wgfx (regbase, CL_GR28, (u_char) (ndest & 0xff));	/* BLT dest low */
+	vga_wgfx (regbase, CL_GR29, (u_char) (ndest >> 8));	/* BLT dest mid */
+	vga_wgfx (regbase, CL_GR2A, (u_char) (ndest >> 16));	/* BLT dest hi */
+
+	/* BLT source */
+	vga_wgfx (regbase, CL_GR2C, (u_char) (nsrc & 0xff));	/* BLT src low */
+	vga_wgfx (regbase, CL_GR2D, (u_char) (nsrc >> 8));		/* BLT src mid */
+	vga_wgfx (regbase, CL_GR2E, (u_char) (nsrc >> 16));	/* BLT src hi */
+
+	/* BLT mode */
+	vga_wgfx (regbase, CL_GR30, bltmode);	/* BLT mode */
+
+	/* BLT ROP: SrcCopy */
+	vga_wgfx (regbase, CL_GR32, 0x0d);		/* BLT ROP */
+
+	/* and finally: GO! */
+	vga_wgfx (regbase, CL_GR31, 0x02);		/* BLT Start/status */
+
+	DPRINTK ("EXIT\n");
+}
+
+
+/*******************************************************************
+	cirrusfb_RectFill()
+
+	perform accelerated rectangle fill
+********************************************************************/
+
+static void cirrusfb_RectFill (u8 __iomem *regbase, int bits_per_pixel,
+		     u_short x, u_short y, u_short width, u_short height,
+		     u_char color, u_short line_length)
+{
+	u_short nwidth, nheight;
+	u_long ndest;
+	u_char op;
+
+	DPRINTK ("ENTER\n");
+
+	nwidth = width - 1;
+	nheight = height - 1;
+
+	ndest = (y * line_length) + x;
+
+        cirrusfb_WaitBLT(regbase);
+
+	/* pitch: set to line_length */
+	vga_wgfx (regbase, CL_GR24, line_length & 0xff);	/* dest pitch low */
+	vga_wgfx (regbase, CL_GR25, (line_length >> 8));	/* dest pitch hi */
+	vga_wgfx (regbase, CL_GR26, line_length & 0xff);	/* source pitch low */
+	vga_wgfx (regbase, CL_GR27, (line_length >> 8));	/* source pitch hi */
+
+	/* BLT width: actual number of pixels - 1 */
+	vga_wgfx (regbase, CL_GR20, nwidth & 0xff);	/* BLT width low */
+	vga_wgfx (regbase, CL_GR21, (nwidth >> 8));	/* BLT width hi */
+
+	/* BLT height: actual number of lines -1 */
+	vga_wgfx (regbase, CL_GR22, nheight & 0xff);		/* BLT height low */
+	vga_wgfx (regbase, CL_GR23, (nheight >> 8));		/* BLT width hi */
+
+	/* BLT destination */
+	vga_wgfx (regbase, CL_GR28, (u_char) (ndest & 0xff));	/* BLT dest low */
+	vga_wgfx (regbase, CL_GR29, (u_char) (ndest >> 8));	/* BLT dest mid */
+	vga_wgfx (regbase, CL_GR2A, (u_char) (ndest >> 16));		/* BLT dest hi */
+
+	/* BLT source: set to 0 (is a dummy here anyway) */
+	vga_wgfx (regbase, CL_GR2C, 0x00);	/* BLT src low */
+	vga_wgfx (regbase, CL_GR2D, 0x00);	/* BLT src mid */
+	vga_wgfx (regbase, CL_GR2E, 0x00);	/* BLT src hi */
+
+	/* This is a ColorExpand Blt, using the */
+	/* same color for foreground and background */
+	vga_wgfx (regbase, VGA_GFX_SR_VALUE, color);	/* foreground color */
+	vga_wgfx (regbase, VGA_GFX_SR_ENABLE, color);	/* background color */
+
+	op = 0xc0;
+	if (bits_per_pixel == 16) {
+		vga_wgfx (regbase, CL_GR10, color);	/* foreground color */
+		vga_wgfx (regbase, CL_GR11, color);	/* background color */
+		op = 0x50;
+		op = 0xd0;
+	} else if (bits_per_pixel == 32) {
+		vga_wgfx (regbase, CL_GR10, color);	/* foreground color */
+		vga_wgfx (regbase, CL_GR11, color);	/* background color */
+		vga_wgfx (regbase, CL_GR12, color);	/* foreground color */
+		vga_wgfx (regbase, CL_GR13, color);	/* background color */
+		vga_wgfx (regbase, CL_GR14, 0);	/* foreground color */
+		vga_wgfx (regbase, CL_GR15, 0);	/* background color */
+		op = 0x50;
+		op = 0xf0;
+	}
+	/* BLT mode: color expand, Enable 8x8 copy (faster?) */
+	vga_wgfx (regbase, CL_GR30, op);	/* BLT mode */
+
+	/* BLT ROP: SrcCopy */
+	vga_wgfx (regbase, CL_GR32, 0x0d);	/* BLT ROP */
+
+	/* and finally: GO! */
+	vga_wgfx (regbase, CL_GR31, 0x02);	/* BLT Start/status */
+
+	DPRINTK ("EXIT\n");
+}
+
+
+/**************************************************************************
+ * bestclock() - determine closest possible clock lower(?) than the
+ * desired pixel clock
+ **************************************************************************/
+static void bestclock (long freq, long *best, long *nom,
+		       long *den, long *div, long maxfreq)
+{
+	long n, h, d, f;
+
+	assert (best != NULL);
+	assert (nom != NULL);
+	assert (den != NULL);
+	assert (div != NULL);
+	assert (maxfreq > 0);
+
+	*nom = 0;
+	*den = 0;
+	*div = 0;
+
+	DPRINTK ("ENTER\n");
+
+	if (freq < 8000)
+		freq = 8000;
+
+	if (freq > maxfreq)
+		freq = maxfreq;
+
+	*best = 0;
+	f = freq * 10;
+
+	for (n = 32; n < 128; n++) {
+		d = (143181 * n) / f;
+		if ((d >= 7) && (d <= 63)) {
+			if (d > 31)
+				d = (d / 2) * 2;
+			h = (14318 * n) / d;
+			if (abs (h - freq) < abs (*best - freq)) {
+				*best = h;
+				*nom = n;
+				if (d < 32) {
+					*den = d;
+					*div = 0;
+				} else {
+					*den = d / 2;
+					*div = 1;
+				}
+			}
+		}
+		d = ((143181 * n) + f - 1) / f;
+		if ((d >= 7) && (d <= 63)) {
+			if (d > 31)
+				d = (d / 2) * 2;
+			h = (14318 * n) / d;
+			if (abs (h - freq) < abs (*best - freq)) {
+				*best = h;
+				*nom = n;
+				if (d < 32) {
+					*den = d;
+					*div = 0;
+				} else {
+					*den = d / 2;
+					*div = 1;
+				}
+			}
+		}
+	}
+
+	DPRINTK ("Best possible values for given frequency:\n");
+	DPRINTK ("        best: %ld kHz  nom: %ld  den: %ld  div: %ld\n",
+		 freq, *nom, *den, *div);
+
+	DPRINTK ("EXIT\n");
+}
+
+
+/* -------------------------------------------------------------------------
+ *
+ * debugging functions
+ *
+ * -------------------------------------------------------------------------
+ */
+
+#ifdef CIRRUSFB_DEBUG
+
+/**
+ * cirrusfb_dbg_print_byte
+ * @name: name associated with byte value to be displayed
+ * @val: byte value to be displayed
+ *
+ * DESCRIPTION:
+ * Display an indented string, along with a hexidecimal byte value, and
+ * its decoded bits.  Bits 7 through 0 are listed in left-to-right
+ * order.
+ */
+
+static
+void cirrusfb_dbg_print_byte (const char *name, unsigned char val)
+{
+	DPRINTK ("%8s = 0x%02X (bits 7-0: %c%c%c%c%c%c%c%c)\n",
+		 name, val,
+		 val & 0x80 ? '1' : '0',
+		 val & 0x40 ? '1' : '0',
+		 val & 0x20 ? '1' : '0',
+		 val & 0x10 ? '1' : '0',
+		 val & 0x08 ? '1' : '0',
+		 val & 0x04 ? '1' : '0',
+		 val & 0x02 ? '1' : '0',
+		 val & 0x01 ? '1' : '0');
+}
+
+
+/**
+ * cirrusfb_dbg_print_regs
+ * @base: If using newmmio, the newmmio base address, otherwise %NULL
+ * @reg_class: type of registers to read: %CRT, or %SEQ
+ *
+ * DESCRIPTION:
+ * Dumps the given list of VGA CRTC registers.  If @base is %NULL,
+ * old-style I/O ports are queried for information, otherwise MMIO is
+ * used at the given @base address to query the information.
+ */
+
+static
+void cirrusfb_dbg_print_regs (caddr_t regbase, cirrusfb_dbg_reg_class_t reg_class,...)
+{
+	va_list list;
+	unsigned char val = 0;
+	unsigned reg;
+	char *name;
+
+	va_start (list, reg_class);
+
+	name = va_arg (list, char *);
+	while (name != NULL) {
+		reg = va_arg (list, int);
+
+		switch (reg_class) {
+		case CRT:
+			val = vga_rcrt (regbase, (unsigned char) reg);
+			break;
+		case SEQ:
+			val = vga_rseq (regbase, (unsigned char) reg);
+			break;
+		default:
+			/* should never occur */
+			assert (FALSE);
+			break;
+		}
+
+		cirrusfb_dbg_print_byte (name, val);
+
+		name = va_arg (list, char *);
+	}
+
+	va_end (list);
+}
+
+
+/**
+ * cirrusfb_dump
+ * @cirrusfbinfo:
+ *
+ * DESCRIPTION:
+ */
+
+static
+void cirrusfb_dump (void)
+{
+	cirrusfb_dbg_reg_dump (NULL);
+}
+
+
+/**
+ * cirrusfb_dbg_reg_dump
+ * @base: If using newmmio, the newmmio base address, otherwise %NULL
+ *
+ * DESCRIPTION:
+ * Dumps a list of interesting VGA and CIRRUSFB registers.  If @base is %NULL,
+ * old-style I/O ports are queried for information, otherwise MMIO is
+ * used at the given @base address to query the information.
+ */
+
+static
+void cirrusfb_dbg_reg_dump (caddr_t regbase)
+{
+	DPRINTK ("CIRRUSFB VGA CRTC register dump:\n");
+
+	cirrusfb_dbg_print_regs (regbase, CRT,
+			   "CR00", 0x00,
+			   "CR01", 0x01,
+			   "CR02", 0x02,
+			   "CR03", 0x03,
+			   "CR04", 0x04,
+			   "CR05", 0x05,
+			   "CR06", 0x06,
+			   "CR07", 0x07,
+			   "CR08", 0x08,
+			   "CR09", 0x09,
+			   "CR0A", 0x0A,
+			   "CR0B", 0x0B,
+			   "CR0C", 0x0C,
+			   "CR0D", 0x0D,
+			   "CR0E", 0x0E,
+			   "CR0F", 0x0F,
+			   "CR10", 0x10,
+			   "CR11", 0x11,
+			   "CR12", 0x12,
+			   "CR13", 0x13,
+			   "CR14", 0x14,
+			   "CR15", 0x15,
+			   "CR16", 0x16,
+			   "CR17", 0x17,
+			   "CR18", 0x18,
+			   "CR22", 0x22,
+			   "CR24", 0x24,
+			   "CR26", 0x26,
+			   "CR2D", 0x2D,
+			   "CR2E", 0x2E,
+			   "CR2F", 0x2F,
+			   "CR30", 0x30,
+			   "CR31", 0x31,
+			   "CR32", 0x32,
+			   "CR33", 0x33,
+			   "CR34", 0x34,
+			   "CR35", 0x35,
+			   "CR36", 0x36,
+			   "CR37", 0x37,
+			   "CR38", 0x38,
+			   "CR39", 0x39,
+			   "CR3A", 0x3A,
+			   "CR3B", 0x3B,
+			   "CR3C", 0x3C,
+			   "CR3D", 0x3D,
+			   "CR3E", 0x3E,
+			   "CR3F", 0x3F,
+			   NULL);
+
+	DPRINTK ("\n");
+
+	DPRINTK ("CIRRUSFB VGA SEQ register dump:\n");
+
+	cirrusfb_dbg_print_regs (regbase, SEQ,
+			   "SR00", 0x00,
+			   "SR01", 0x01,
+			   "SR02", 0x02,
+			   "SR03", 0x03,
+			   "SR04", 0x04,
+			   "SR08", 0x08,
+			   "SR09", 0x09,
+			   "SR0A", 0x0A,
+			   "SR0B", 0x0B,
+			   "SR0D", 0x0D,
+			   "SR10", 0x10,
+			   "SR11", 0x11,
+			   "SR12", 0x12,
+			   "SR13", 0x13,
+			   "SR14", 0x14,
+			   "SR15", 0x15,
+			   "SR16", 0x16,
+			   "SR17", 0x17,
+			   "SR18", 0x18,
+			   "SR19", 0x19,
+			   "SR1A", 0x1A,
+			   "SR1B", 0x1B,
+			   "SR1C", 0x1C,
+			   "SR1D", 0x1D,
+			   "SR1E", 0x1E,
+			   "SR1F", 0x1F,
+			   NULL);
+
+	DPRINTK ("\n");
+}
+
+#endif				/* CIRRUSFB_DEBUG */
+
diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c
new file mode 100644
index 0000000..8692e00
--- /dev/null
+++ b/drivers/video/clps711xfb.c
@@ -0,0 +1,443 @@
+/*
+ *  linux/drivers/video/clps711xfb.c
+ *
+ *  Copyright (C) 2000-2001 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  Framebuffer driver for the CLPS7111 and EP7212 processors.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/uaccess.h>
+
+#include <asm/hardware/clps7111.h>
+#include <asm/arch/syspld.h>
+
+struct fb_info	*cfb;
+
+#define CMAP_MAX_SIZE	16
+
+/* The /proc entry for the backlight. */
+static struct proc_dir_entry *clps7111fb_backlight_proc_entry = NULL;
+
+static int clps7111fb_proc_backlight_read(char *page, char **start, off_t off,
+		int count, int *eof, void *data);
+static int clps7111fb_proc_backlight_write(struct file *file, 
+		const char *buffer, unsigned long count, void *data);
+
+/*
+ * LCD AC Prescale.  This comes from the LCD panel manufacturers specifications.
+ * This determines how many clocks + 1 of CL1 before the M signal toggles.
+ * The number of lines on the display must not be divisible by this number.
+ */
+static unsigned int lcd_ac_prescale = 13;
+
+/*
+ *    Set a single color register. Return != 0 for invalid regno.
+ */
+static int
+clps7111fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+		     u_int transp, struct fb_info *info)
+{
+	unsigned int level, mask, shift, pal;
+
+	if (regno >= (1 << info->var.bits_per_pixel))
+		return 1;
+
+	/* gray = 0.30*R + 0.58*G + 0.11*B */
+	level = (red * 77 + green * 151 + blue * 28) >> 20;
+
+	/*
+	 * On an LCD, a high value is dark, while a low value is light. 
+	 * So we invert the level.
+	 *
+	 * This isn't true on all machines, so we only do it on EDB7211.
+	 *  --rmk
+	 */
+	if (machine_is_edb7211()) {
+		level = 15 - level;
+	}
+
+	shift = 4 * (regno & 7);
+	level <<= shift;
+	mask  = 15 << shift;
+	level &= mask;
+
+	regno = regno < 8 ? PALLSW : PALMSW;
+
+	pal = clps_readl(regno);
+	pal = (pal & ~mask) | level;
+	clps_writel(pal, regno);
+
+	return 0;
+}
+
+/*
+ * Validate the purposed mode.
+ */	
+static int
+clps7111fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	var->transp.msb_right	= 0;
+	var->transp.offset	= 0;
+	var->transp.length	= 0;
+	var->red.msb_right	= 0;
+	var->red.offset		= 0;
+	var->red.length		= var->bits_per_pixel;
+	var->green		= var->red;
+	var->blue		= var->red;
+
+	if (var->bits_per_pixel > 4) 
+		return -EINVAL;
+
+	return 0;
+}
+
+/*
+ * Set the hardware state.
+ */ 
+static int 
+clps7111fb_set_par(struct fb_info *info)
+{
+	unsigned int lcdcon, syscon, pixclock;
+
+	switch (info->var.bits_per_pixel) {
+	case 1:
+		info->fix.visual = FB_VISUAL_MONO01;
+		break;
+	case 2:
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+		break;
+	case 4:
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+		break;
+	}
+
+	info->fix.line_length = info->var.xres_virtual * info->var.bits_per_pixel / 8;
+
+	lcdcon = (info->var.xres_virtual * info->var.yres_virtual * info->var.bits_per_pixel) / 128 - 1;
+	lcdcon |= ((info->var.xres_virtual / 16) - 1) << 13;
+	lcdcon |= lcd_ac_prescale << 25;
+
+	/*
+	 * Calculate pixel prescale value from the pixclock.  This is:
+	 *  36.864MHz / pixclock_mhz - 1.
+	 * However, pixclock is in picoseconds, so this ends up being:
+	 *  36864000 * pixclock_ps / 10^12 - 1
+	 * and this will overflow the 32-bit math.  We perform this as
+	 * (9 * 4096000 == 36864000):
+	 *  pixclock_ps * 9 * (4096000 / 10^12) - 1
+	 */
+	pixclock = 9 * info->var.pixclock / 244140 - 1;
+	lcdcon |= pixclock << 19;
+
+	if (info->var.bits_per_pixel == 4)
+		lcdcon |= LCDCON_GSMD;
+	if (info->var.bits_per_pixel >= 2)
+		lcdcon |= LCDCON_GSEN;
+
+	/*
+	 * LCDCON must only be changed while the LCD is disabled
+	 */
+	syscon = clps_readl(SYSCON1);
+	clps_writel(syscon & ~SYSCON1_LCDEN, SYSCON1);
+	clps_writel(lcdcon, LCDCON);
+	clps_writel(syscon | SYSCON1_LCDEN, SYSCON1);
+	return 0;
+}
+
+static int clps7111fb_blank(int blank, struct fb_info *info)
+{
+    	if (blank) {
+		if (machine_is_edb7211()) {
+			/* Turn off the LCD backlight. */
+			clps_writeb(clps_readb(PDDR) & ~EDB_PD3_LCDBL, PDDR);
+
+			/* Power off the LCD DC-DC converter. */
+			clps_writeb(clps_readb(PDDR) & ~EDB_PD1_LCD_DC_DC_EN, PDDR);
+
+			/* Delay for a little while (half a second). */
+			udelay(100);
+
+			/* Power off the LCD panel. */
+			clps_writeb(clps_readb(PDDR) & ~EDB_PD2_LCDEN, PDDR);
+
+			/* Power off the LCD controller. */
+			clps_writel(clps_readl(SYSCON1) & ~SYSCON1_LCDEN, 
+					SYSCON1);
+		}
+	} else {
+		if (machine_is_edb7211()) {
+			/* Power up the LCD controller. */
+			clps_writel(clps_readl(SYSCON1) | SYSCON1_LCDEN,
+					SYSCON1);
+
+			/* Power up the LCD panel. */
+			clps_writeb(clps_readb(PDDR) | EDB_PD2_LCDEN, PDDR);
+
+			/* Delay for a little while. */
+			udelay(100);
+
+			/* Power up the LCD DC-DC converter. */
+			clps_writeb(clps_readb(PDDR) | EDB_PD1_LCD_DC_DC_EN,
+					PDDR);
+
+			/* Turn on the LCD backlight. */
+			clps_writeb(clps_readb(PDDR) | EDB_PD3_LCDBL, PDDR);
+		}
+	}
+	return 0;
+}
+
+static struct fb_ops clps7111fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= clps7111fb_check_var,
+	.fb_set_par	= clps7111fb_set_par,
+	.fb_setcolreg	= clps7111fb_setcolreg,
+	.fb_blank	= clps7111fb_blank,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+static int 
+clps7111fb_proc_backlight_read(char *page, char **start, off_t off,
+		int count, int *eof, void *data)
+{
+	/* We need at least two characters, one for the digit, and one for
+	 * the terminating NULL. */
+	if (count < 2) 
+		return -EINVAL;
+
+	if (machine_is_edb7211()) {
+		return sprintf(page, "%d\n", 
+				(clps_readb(PDDR) & EDB_PD3_LCDBL) ? 1 : 0);
+	}
+
+	return 0;
+}
+
+static int 
+clps7111fb_proc_backlight_write(struct file *file, const char *buffer, 
+		unsigned long count, void *data)
+{
+	unsigned char char_value;
+	int value;
+
+	if (count < 1) {
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&char_value, buffer, 1)) 
+		return -EFAULT;
+
+	value = char_value - '0';
+
+	if (machine_is_edb7211()) {
+		unsigned char port_d;
+
+		port_d = clps_readb(PDDR);
+
+		if (value) {
+			port_d |= EDB_PD3_LCDBL;
+		} else {
+			port_d &= ~EDB_PD3_LCDBL;
+		}
+
+		clps_writeb(port_d, PDDR);
+	}
+
+	return count;
+}
+
+static void __init clps711x_guess_lcd_params(struct fb_info *info)
+{
+	unsigned int lcdcon, syscon, size;
+	unsigned long phys_base = PAGE_OFFSET;
+	void *virt_base = (void *)PAGE_OFFSET;
+
+	info->var.xres_virtual	 = 640;
+	info->var.yres_virtual	 = 240;
+	info->var.bits_per_pixel = 4;
+	info->var.activate	 = FB_ACTIVATE_NOW;
+	info->var.height	 = -1;
+	info->var.width		 = -1;
+	info->var.pixclock	 = 93006; /* 10.752MHz pixel clock */
+
+	/*
+	 * If the LCD controller is already running, decode the values
+	 * in LCDCON to xres/yres/bpp/pixclock/acprescale
+	 */
+	syscon = clps_readl(SYSCON1);
+	if (syscon & SYSCON1_LCDEN) {
+		lcdcon = clps_readl(LCDCON);
+
+		/*
+		 * Decode GSMD and GSEN bits to bits per pixel
+		 */
+		switch (lcdcon & (LCDCON_GSMD | LCDCON_GSEN)) {
+		case LCDCON_GSMD | LCDCON_GSEN:
+			info->var.bits_per_pixel = 4;
+			break;
+
+		case LCDCON_GSEN:
+			info->var.bits_per_pixel = 2;
+			break;
+
+		default:
+			info->var.bits_per_pixel = 1;
+			break;
+		}
+
+		/*
+		 * Decode xres/yres
+		 */
+		info->var.xres_virtual = (((lcdcon >> 13) & 0x3f) + 1) * 16;
+		info->var.yres_virtual = (((lcdcon & 0x1fff) + 1) * 128) /
+					  (info->var.xres_virtual *
+					   info->var.bits_per_pixel);
+
+		/*
+		 * Calculate pixclock
+		 */
+		info->var.pixclock = (((lcdcon >> 19) & 0x3f) + 1) * 244140 / 9;
+
+		/*
+		 * Grab AC prescale
+		 */
+		lcd_ac_prescale = (lcdcon >> 25) & 0x1f;
+	}
+
+	info->var.xres = info->var.xres_virtual;
+	info->var.yres = info->var.yres_virtual;
+	info->var.grayscale = info->var.bits_per_pixel > 1;
+
+	size = info->var.xres * info->var.yres * info->var.bits_per_pixel / 8;
+
+	/*
+	 * Might be worth checking to see if we can use the on-board
+	 * RAM if size here...
+	 * CLPS7110 - no on-board SRAM
+	 * EP7212   - 38400 bytes
+	 */
+	if (size <= 38400) {
+		printk(KERN_INFO "CLPS711xFB: could use on-board SRAM?\n");
+	}
+
+	if ((syscon & SYSCON1_LCDEN) == 0) {
+		/*
+		 * The display isn't running.  Ensure that
+		 * the display memory is empty.
+		 */
+		memset(virt_base, 0, size);
+	}
+
+	info->screen_base    = virt_base;
+	info->fix.smem_start = phys_base;
+	info->fix.smem_len   = PAGE_ALIGN(size);
+	info->fix.type       = FB_TYPE_PACKED_PIXELS;
+}
+
+int __init clps711xfb_init(void)
+{
+	int err = -ENOMEM;
+
+	if (fb_get_options("clps711xfb", NULL))
+		return -ENODEV;
+
+	cfb = kmalloc(sizeof(*cfb), GFP_KERNEL);
+	if (!cfb)
+		goto out;
+
+	memset(cfb, 0, sizeof(*cfb));
+	strcpy(cfb->fix.id, "clps711x");
+
+	cfb->fbops		= &clps7111fb_ops;
+	cfb->flags		= FBINFO_DEFAULT;
+
+	clps711x_guess_lcd_params(cfb);
+
+	fb_alloc_cmap(&cfb->cmap, CMAP_MAX_SIZE, 0);
+
+	/* Register the /proc entries. */
+	clps7111fb_backlight_proc_entry = create_proc_entry("backlight", 0444,
+		&proc_root);
+	if (clps7111fb_backlight_proc_entry == NULL) {
+		printk("Couldn't create the /proc entry for the backlight.\n");
+		return -EINVAL;
+	}
+
+	clps7111fb_backlight_proc_entry->read_proc = 
+		&clps7111fb_proc_backlight_read;
+	clps7111fb_backlight_proc_entry->write_proc = 
+		&clps7111fb_proc_backlight_write;
+
+	/*
+	 * Power up the LCD
+	 */
+	if (machine_is_p720t()) {
+		PLD_LCDEN = PLD_LCDEN_EN;
+		PLD_PWR |= (PLD_S4_ON|PLD_S3_ON|PLD_S2_ON|PLD_S1_ON);
+	}
+
+	if (machine_is_edb7211()) {
+		/* Power up the LCD panel. */
+		clps_writeb(clps_readb(PDDR) | EDB_PD2_LCDEN, PDDR);
+
+		/* Delay for a little while. */
+		udelay(100);
+
+		/* Power up the LCD DC-DC converter. */
+		clps_writeb(clps_readb(PDDR) | EDB_PD1_LCD_DC_DC_EN, PDDR);
+
+		/* Turn on the LCD backlight. */
+		clps_writeb(clps_readb(PDDR) | EDB_PD3_LCDBL, PDDR);
+	}
+
+	err = register_framebuffer(cfb);
+
+out:	return err;
+}
+
+static void __exit clps711xfb_exit(void)
+{
+	unregister_framebuffer(cfb);
+	kfree(cfb);
+
+	/*
+	 * Power down the LCD
+	 */
+	if (machine_is_p720t()) {
+		PLD_LCDEN = 0;
+		PLD_PWR &= ~(PLD_S4_ON|PLD_S3_ON|PLD_S2_ON|PLD_S1_ON);
+	}
+}
+
+module_init(clps711xfb_init);
+module_exit(clps711xfb_exit);
+
+MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
+MODULE_DESCRIPTION("CLPS711x framebuffer driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
new file mode 100644
index 0000000..ccf5581
--- /dev/null
+++ b/drivers/video/console/Kconfig
@@ -0,0 +1,191 @@
+#
+# Video configuration
+#
+
+menu "Console display driver support"
+
+config VGA_CONSOLE
+	bool "VGA text console" if EMBEDDED || !X86
+	depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC32 && !SPARC64 && !M68K && !PARISC
+	default y
+	help
+	  Saying Y here will allow you to use Linux in text mode through a
+	  display that complies with the generic VGA standard. Virtually
+	  everyone wants that.
+
+	  The program SVGATextMode can be used to utilize SVGA video cards to
+	  their full potential in text mode. Download it from
+	  <ftp://ibiblio.org/pub/Linux/utils/console/>.
+
+	  Say Y.
+
+#	if [ "$CONFIG_PCI" = "y" -a "$CONFIG_VGA_CONSOLE" = "y" ]; then
+#	   bool '   Allow VGA on any bus?' CONFIG_VGA_HOSE
+#	   if [ "$CONFIG_VGA_HOSE" = "y" ]; then
+#	      define_bool CONFIG_DUMMY_CONSOLE y
+#	   fi
+#	fi
+
+config VIDEO_SELECT
+	bool "Video mode selection support"
+	depends on  (X86 || X86_64) && VGA_CONSOLE
+	---help---
+	  This enables support for text mode selection on kernel startup. If
+	  you want to take advantage of some high-resolution text mode your
+	  card's BIOS offers, but the traditional Linux utilities like
+	  SVGATextMode don't, you can say Y here and set the mode using the
+	  "vga=" option from your boot loader (lilo or loadlin) or set
+	  "vga=ask" which brings up a video mode menu on kernel startup. (Try
+	  "man bootparam" or see the documentation of your boot loader about
+	  how to pass options to the kernel.)
+
+	  Read the file <file:Documentation/svga.txt> for more information
+	  about the Video mode selection support. If unsure, say N.
+
+config MDA_CONSOLE
+	depends on !M68K && !PARISC && ISA
+	tristate "MDA text console (dual-headed) (EXPERIMENTAL)"
+	---help---
+	  Say Y here if you have an old MDA or monochrome Hercules graphics
+	  adapter in your system acting as a second head ( = video card). You
+	  will then be able to use two monitors with your Linux system. Do not
+	  say Y here if your MDA card is the primary card in your system; the
+	  normal VGA driver will handle it.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mdacon.
+
+	  If unsure, say N.
+
+config SGI_NEWPORT_CONSOLE
+        tristate "SGI Newport Console support"
+        depends on SGI_IP22 
+        help
+          Say Y here if you want the console on the Newport aka XL graphics
+          card of your Indy.  Most people say Y here.
+
+#  bool 'IODC console' CONFIG_IODC_CONSOLE
+
+config PROM_CONSOLE
+	bool "PROM console"
+	depends on SPARC32 || SPARC64
+	help
+	  Say Y to build a console driver for Sun machines that uses the
+	  terminal emulation built into their console PROMS.
+
+config DUMMY_CONSOLE
+	bool
+	depends on PROM_CONSOLE!=y || VGA_CONSOLE!=y || SGI_NEWPORT_CONSOLE!=y 
+	default y
+
+config DUMMY_CONSOLE_COLUMNS
+        int "Initial number of console screen columns"
+        depends on PARISC && DUMMY_CONSOLE
+        default "160"
+        help
+          The default value is 160, which should fit a 1280x1024 monitor.
+          Select 80 if you use a 640x480 resolution by default.
+
+config DUMMY_CONSOLE_ROWS
+        int "Initial number of console screen rows"
+        depends on PARISC && DUMMY_CONSOLE
+        default "64"
+        help
+          The default value is 64, which should fit a 1280x1024 monitor.
+          Select 25 if you use a 640x480 resolution by default.
+
+config FRAMEBUFFER_CONSOLE
+	tristate "Framebuffer Console support"
+	depends on FB
+	select CRC32
+
+config STI_CONSOLE
+        tristate "STI text console" 
+        depends on PARISC
+        default y
+        help
+          The STI console is the builtin display/keyboard on HP-PARISC
+          machines.  Say Y here to build support for it into your kernel.
+          The alternative is to use your primary serial port as a console.
+
+config FONTS
+	bool "Select compiled-in fonts"
+	depends on FRAMEBUFFER_CONSOLE
+	help
+	  Say Y here if you would like to use fonts other than the default
+	  your frame buffer console usually use.
+
+	  Note that the answer to this question won't directly affect the
+	  kernel: saying N will just cause the configurator to skip all
+	  the questions about foreign fonts.
+
+	  If unsure, say N (the default choices are safe).
+
+config FONT_8x8
+	bool "VGA 8x8 font" if FONTS
+	depends on FRAMEBUFFER_CONSOLE
+	default y if !SPARC32 && !SPARC64 && !FONTS
+	help
+	  This is the "high resolution" font for the VGA frame buffer (the one
+	  provided by the text console 80x50 (and higher) modes).
+
+	  Note that this is a poor quality font. The VGA 8x16 font is quite a
+	  lot more readable.
+
+	  Given the resolution provided by the frame buffer device, answer N
+	  here is safe.
+
+config FONT_8x16
+	bool "VGA 8x16 font" if FONTS
+	depends on FRAMEBUFFER_CONSOLE || SGI_NEWPORT_CONSOLE=y
+	default y if !SPARC32 && !SPARC64 && !FONTS
+	help
+	  This is the "high resolution" font for the VGA frame buffer (the one
+	  provided by the VGA text console 80x25 mode.
+
+	  If unsure, say Y.
+
+config FONT_6x11
+	bool "Mac console 6x11 font (not supported by all drivers)" if FONTS
+	depends on FRAMEBUFFER_CONSOLE
+	default y if !SPARC32 && !SPARC64 && !FONTS && MAC
+	help
+	  Small console font with Macintosh-style high-half glyphs.  Some Mac
+	  framebuffer drivers don't support this one at all.
+
+config FONT_PEARL_8x8
+	bool "Pearl (old m68k) console 8x8 font" if FONTS
+	depends on FRAMEBUFFER_CONSOLE
+	default y if !SPARC32 && !SPARC64 && !FONTS && AMIGA
+	help
+	  Small console font with PC-style control-character and high-half
+	  glyphs.
+
+config FONT_ACORN_8x8
+	bool "Acorn console 8x8 font" if FONTS
+	depends on FRAMEBUFFER_CONSOLE
+	default y if !SPARC32 && !SPARC64 && !FONTS && ARM && ARCH_ACORN
+	help
+	  Small console font with PC-style control characters and high-half
+	  glyphs.
+
+config FONT_MINI_4x6
+	bool "Mini 4x6 font"
+	depends on !SPARC32 && !SPARC64 && FONTS
+
+config FONT_SUN8x16
+	bool "Sparc console 8x16 font"
+	depends on FRAMEBUFFER_CONSOLE && (!SPARC32 && !SPARC64 && FONTS || SPARC32 || SPARC64)
+	help
+	  This is the high resolution console font for Sun machines. Say Y.
+
+config FONT_SUN12x22
+	bool "Sparc console 12x22 font (not supported by all drivers)"
+	depends on FRAMEBUFFER_CONSOLE && (!SPARC32 && !SPARC64 && FONTS || SPARC32 || SPARC64)
+	help
+	  This is the high resolution console font for Sun machines with very
+	  big letters (like the letters used in the SPARC PROM). If the
+	  standard font is unreadable for you, say Y, otherwise say N.
+
+endmenu
+
diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile
new file mode 100644
index 0000000..3351644
--- /dev/null
+++ b/drivers/video/console/Makefile
@@ -0,0 +1,43 @@
+# Makefile for the Linux graphics to console drivers.
+# 5 Aug 1999, James Simmons, <mailto:jsimmons@users.sf.net>
+# Rewritten to use lists instead of if-statements.
+
+# Font handling
+font-objs := fonts.o
+
+font-objs-$(CONFIG_FONT_SUN8x16)   += font_sun8x16.o
+font-objs-$(CONFIG_FONT_SUN12x22)  += font_sun12x22.o
+font-objs-$(CONFIG_FONT_8x8)       += font_8x8.o
+font-objs-$(CONFIG_FONT_8x16)      += font_8x16.o
+font-objs-$(CONFIG_FONT_6x11)      += font_6x11.o
+font-objs-$(CONFIG_FONT_PEARL_8x8) += font_pearl_8x8.o
+font-objs-$(CONFIG_FONT_ACORN_8x8) += font_acorn_8x8.o
+font-objs-$(CONFIG_FONT_MINI_4x6)  += font_mini_4x6.o
+
+font-objs += $(font-objs-y)
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_DUMMY_CONSOLE)       += dummycon.o
+obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o font.o
+obj-$(CONFIG_PROM_CONSOLE)        += promcon.o promcon_tbl.o
+obj-$(CONFIG_STI_CONSOLE)         += sticon.o sticore.o font.o
+obj-$(CONFIG_VGA_CONSOLE)         += vgacon.o
+obj-$(CONFIG_MDA_CONSOLE)         += mdacon.o
+obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o bitblit.o font.o
+ifeq ($(CONFIG_FB_TILEBLITTING),y)
+obj-$(CONFIG_FRAMEBUFFER_CONSOLE)     += tileblit.o
+endif
+
+obj-$(CONFIG_FB_STI)              += sticore.o font.o
+
+# Targets that kbuild needs to know about
+targets := promcon_tbl.c
+
+quiet_cmd_conmakehash = CNMKHSH $@
+      cmd_conmakehash = scripts/conmakehash $< | \
+		sed -e '/\#include <[^>]*>/p' -e 's/types/init/' \
+		-e 's/dfont\(_uni.*\]\)/promfont\1 __initdata/' > $@
+
+$(obj)/promcon_tbl.c: $(src)/prom.uni
+	$(call cmd,conmakehash)
diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c
new file mode 100644
index 0000000..b28a4b0
--- /dev/null
+++ b/drivers/video/console/bitblit.c
@@ -0,0 +1,405 @@
+/*
+ *  linux/drivers/video/console/bitblit.c -- BitBlitting Operation
+ *
+ *  Originally from the 'accel_*' routines in drivers/video/console/fbcon.c
+ *
+ *      Copyright (C) 2004 Antonino Daplas <adaplas @pol.net>
+ *
+ *  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/string.h>
+#include <linux/fb.h>
+#include <linux/vt_kern.h>
+#include <linux/console.h>
+#include <asm/types.h>
+#include "fbcon.h"
+
+/*
+ * Accelerated handlers.
+ */
+#define FBCON_ATTRIBUTE_UNDERLINE 1
+#define FBCON_ATTRIBUTE_REVERSE   2
+#define FBCON_ATTRIBUTE_BOLD      4
+
+static inline int real_y(struct display *p, int ypos)
+{
+	int rows = p->vrows;
+
+	ypos += p->yscroll;
+	return ypos < rows ? ypos : ypos - rows;
+}
+
+
+static inline int get_attribute(struct fb_info *info, u16 c)
+{
+	int attribute = 0;
+
+	if (fb_get_color_depth(&info->var) == 1) {
+		if (attr_underline(c))
+			attribute |= FBCON_ATTRIBUTE_UNDERLINE;
+		if (attr_reverse(c))
+			attribute |= FBCON_ATTRIBUTE_REVERSE;
+		if (attr_bold(c))
+			attribute |= FBCON_ATTRIBUTE_BOLD;
+	}
+
+	return attribute;
+}
+
+static inline void update_attr(u8 *dst, u8 *src, int attribute,
+			       struct vc_data *vc)
+{
+	int i, offset = (vc->vc_font.height < 10) ? 1 : 2;
+	int width = (vc->vc_font.width + 7) >> 3;
+	unsigned int cellsize = vc->vc_font.height * width;
+	u8 c;
+
+	offset = cellsize - (offset * width);
+	for (i = 0; i < cellsize; i++) {
+		c = src[i];
+		if (attribute & FBCON_ATTRIBUTE_UNDERLINE && i >= offset)
+			c = 0xff;
+		if (attribute & FBCON_ATTRIBUTE_BOLD)
+			c |= c >> 1;
+		if (attribute & FBCON_ATTRIBUTE_REVERSE)
+			c = ~c;
+		dst[i] = c;
+	}
+}
+
+static void bit_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+		      int sx, int dy, int dx, int height, int width)
+{
+	struct fb_copyarea area;
+
+	area.sx = sx * vc->vc_font.width;
+	area.sy = sy * vc->vc_font.height;
+	area.dx = dx * vc->vc_font.width;
+	area.dy = dy * vc->vc_font.height;
+	area.height = height * vc->vc_font.height;
+	area.width = width * vc->vc_font.width;
+
+	info->fbops->fb_copyarea(info, &area);
+}
+
+static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy,
+		      int sx, int height, int width)
+{
+	int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+	struct fb_fillrect region;
+
+	region.color = attr_bgcol_ec(bgshift, vc);
+	region.dx = sx * vc->vc_font.width;
+	region.dy = sy * vc->vc_font.height;
+	region.width = width * vc->vc_font.width;
+	region.height = height * vc->vc_font.height;
+	region.rop = ROP_COPY;
+
+	info->fbops->fb_fillrect(info, &region);
+}
+
+static void bit_putcs(struct vc_data *vc, struct fb_info *info,
+		      const unsigned short *s, int count, int yy, int xx,
+		      int fg, int bg)
+{
+	void (*move_unaligned)(struct fb_info *info, struct fb_pixmap *buf,
+			       u8 *dst, u32 d_pitch, u8 *src, u32 idx,
+			       u32 height, u32 shift_high, u32 shift_low,
+			       u32 mod);
+	void (*move_aligned)(struct fb_info *info, struct fb_pixmap *buf,
+			     u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch,
+			     u32 height);
+	unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+	unsigned int width = (vc->vc_font.width + 7) >> 3;
+	unsigned int cellsize = vc->vc_font.height * width;
+	unsigned int maxcnt = info->pixmap.size/cellsize;
+	unsigned int scan_align = info->pixmap.scan_align - 1;
+	unsigned int buf_align = info->pixmap.buf_align - 1;
+	unsigned int shift_low = 0, mod = vc->vc_font.width % 8;
+	unsigned int shift_high = 8, pitch, cnt, size, k;
+	unsigned int idx = vc->vc_font.width >> 3;
+	unsigned int attribute = get_attribute(info, scr_readw(s));
+	struct fb_image image;
+	u8 *src, *dst, *buf = NULL;
+
+	if (attribute) {
+		buf = kmalloc(cellsize, GFP_KERNEL);
+		if (!buf)
+			return;
+	}
+
+	image.fg_color = fg;
+	image.bg_color = bg;
+
+	image.dx = xx * vc->vc_font.width;
+	image.dy = yy * vc->vc_font.height;
+	image.height = vc->vc_font.height;
+	image.depth = 1;
+
+	if (info->pixmap.outbuf && info->pixmap.inbuf) {
+		move_aligned = fb_iomove_buf_aligned;
+		move_unaligned = fb_iomove_buf_unaligned;
+	} else {
+		move_aligned = fb_sysmove_buf_aligned;
+		move_unaligned = fb_sysmove_buf_unaligned;
+	}
+	while (count) {
+		if (count > maxcnt)
+			cnt = k = maxcnt;
+		else
+			cnt = k = count;
+
+		image.width = vc->vc_font.width * cnt;
+		pitch = ((image.width + 7) >> 3) + scan_align;
+		pitch &= ~scan_align;
+		size = pitch * image.height + buf_align;
+		size &= ~buf_align;
+		dst = fb_get_buffer_offset(info, &info->pixmap, size);
+		image.data = dst;
+		if (mod) {
+			while (k--) {
+				src = vc->vc_font.data + (scr_readw(s++)&
+							  charmask)*cellsize;
+
+				if (attribute) {
+					update_attr(buf, src, attribute, vc);
+					src = buf;
+				}
+
+				move_unaligned(info, &info->pixmap, dst, pitch,
+					       src, idx, image.height,
+					       shift_high, shift_low, mod);
+				shift_low += mod;
+				dst += (shift_low >= 8) ? width : width - 1;
+				shift_low &= 7;
+				shift_high = 8 - shift_low;
+			}
+		} else {
+			while (k--) {
+				src = vc->vc_font.data + (scr_readw(s++)&
+							  charmask)*cellsize;
+
+				if (attribute) {
+					update_attr(buf, src, attribute, vc);
+					src = buf;
+				}
+
+				move_aligned(info, &info->pixmap, dst, pitch,
+					     src, idx, image.height);
+				dst += width;
+			}
+		}
+		info->fbops->fb_imageblit(info, &image);
+		image.dx += cnt * vc->vc_font.width;
+		count -= cnt;
+	}
+
+	/* buf is always NULL except when in monochrome mode, so in this case
+	   it's a gain to check buf against NULL even though kfree() handles
+	   NULL pointers just fine */
+	if (unlikely(buf))
+		kfree(buf);
+}
+
+static void bit_clear_margins(struct vc_data *vc, struct fb_info *info,
+			      int bottom_only)
+{
+	int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+	unsigned int cw = vc->vc_font.width;
+	unsigned int ch = vc->vc_font.height;
+	unsigned int rw = info->var.xres - (vc->vc_cols*cw);
+	unsigned int bh = info->var.yres - (vc->vc_rows*ch);
+	unsigned int rs = info->var.xres - rw;
+	unsigned int bs = info->var.yres - bh;
+	struct fb_fillrect region;
+
+	region.color = attr_bgcol_ec(bgshift, vc);
+	region.rop = ROP_COPY;
+
+	if (rw && !bottom_only) {
+		region.dx = info->var.xoffset + rs;
+		region.dy = 0;
+		region.width = rw;
+		region.height = info->var.yres_virtual;
+		info->fbops->fb_fillrect(info, &region);
+	}
+
+	if (bh) {
+		region.dx = info->var.xoffset;
+		region.dy = info->var.yoffset + bs;
+		region.width = rs;
+		region.height = bh;
+		info->fbops->fb_fillrect(info, &region);
+	}
+}
+
+static void bit_cursor(struct vc_data *vc, struct fb_info *info,
+		       struct display *p, int mode, int softback_lines, int fg, int bg)
+{
+	struct fb_cursor cursor;
+	struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par;
+	unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+	int w = (vc->vc_font.width + 7) >> 3, c;
+	int y = real_y(p, vc->vc_y);
+	int attribute, use_sw = (vc->vc_cursor_type & 0x10);
+	char *src;
+
+	cursor.set = 0;
+
+	if (softback_lines) {
+		if (y + softback_lines >= vc->vc_rows) {
+			mode = CM_ERASE;
+			ops->cursor_flash = 0;
+			return;
+		} else
+			y += softback_lines;
+	}
+
+ 	c = scr_readw((u16 *) vc->vc_pos);
+	attribute = get_attribute(info, c);
+	src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height));
+
+	if (ops->cursor_state.image.data != src ||
+	    ops->cursor_reset) {
+	    ops->cursor_state.image.data = src;
+	    cursor.set |= FB_CUR_SETIMAGE;
+	}
+
+	if (attribute) {
+		u8 *dst;
+
+		dst = kmalloc(w * vc->vc_font.height, GFP_ATOMIC);
+		if (!dst)
+			return;
+		kfree(ops->cursor_data);
+		ops->cursor_data = dst;
+		update_attr(dst, src, attribute, vc);
+		src = dst;
+	}
+
+	if (ops->cursor_state.image.fg_color != fg ||
+	    ops->cursor_state.image.bg_color != bg ||
+	    ops->cursor_reset) {
+		ops->cursor_state.image.fg_color = fg;
+		ops->cursor_state.image.bg_color = bg;
+		cursor.set |= FB_CUR_SETCMAP;
+	}
+
+	if ((ops->cursor_state.image.dx != (vc->vc_font.width * vc->vc_x)) ||
+	    (ops->cursor_state.image.dy != (vc->vc_font.height * y)) ||
+	    ops->cursor_reset) {
+		ops->cursor_state.image.dx = vc->vc_font.width * vc->vc_x;
+		ops->cursor_state.image.dy = vc->vc_font.height * y;
+		cursor.set |= FB_CUR_SETPOS;
+	}
+
+	if (ops->cursor_state.image.height != vc->vc_font.height ||
+	    ops->cursor_state.image.width != vc->vc_font.width ||
+	    ops->cursor_reset) {
+		ops->cursor_state.image.height = vc->vc_font.height;
+		ops->cursor_state.image.width = vc->vc_font.width;
+		cursor.set |= FB_CUR_SETSIZE;
+	}
+
+	if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
+	    ops->cursor_reset) {
+		ops->cursor_state.hot.x = cursor.hot.y = 0;
+		cursor.set |= FB_CUR_SETHOT;
+	}
+
+	if (cursor.set & FB_CUR_SETSIZE ||
+	    vc->vc_cursor_type != p->cursor_shape ||
+	    ops->cursor_state.mask == NULL ||
+	    ops->cursor_reset) {
+		char *mask = kmalloc(w*vc->vc_font.height, GFP_ATOMIC);
+		int cur_height, size, i = 0;
+		u8 msk = 0xff;
+
+		if (!mask)
+			return;
+
+		kfree(ops->cursor_state.mask);
+		ops->cursor_state.mask = mask;
+
+		p->cursor_shape = vc->vc_cursor_type;
+		cursor.set |= FB_CUR_SETSHAPE;
+
+		switch (p->cursor_shape & CUR_HWMASK) {
+		case CUR_NONE:
+			cur_height = 0;
+			break;
+		case CUR_UNDERLINE:
+			cur_height = (vc->vc_font.height < 10) ? 1 : 2;
+			break;
+		case CUR_LOWER_THIRD:
+			cur_height = vc->vc_font.height/3;
+			break;
+		case CUR_LOWER_HALF:
+			cur_height = vc->vc_font.height >> 1;
+			break;
+		case CUR_TWO_THIRDS:
+			cur_height = (vc->vc_font.height << 1)/3;
+			break;
+		case CUR_BLOCK:
+		default:
+			cur_height = vc->vc_font.height;
+			break;
+		}
+		size = (vc->vc_font.height - cur_height) * w;
+		while (size--)
+			mask[i++] = ~msk;
+		size = cur_height * w;
+		while (size--)
+			mask[i++] = msk;
+	}
+
+	switch (mode) {
+	case CM_ERASE:
+		ops->cursor_state.enable = 0;
+		break;
+	case CM_DRAW:
+	case CM_MOVE:
+	default:
+		ops->cursor_state.enable = (use_sw) ? 0 : 1;
+		break;
+	}
+
+	cursor.image.data = src;
+	cursor.image.fg_color = ops->cursor_state.image.fg_color;
+	cursor.image.bg_color = ops->cursor_state.image.bg_color;
+	cursor.image.dx = ops->cursor_state.image.dx;
+	cursor.image.dy = ops->cursor_state.image.dy;
+	cursor.image.height = ops->cursor_state.image.height;
+	cursor.image.width = ops->cursor_state.image.width;
+	cursor.hot.x = ops->cursor_state.hot.x;
+	cursor.hot.y = ops->cursor_state.hot.y;
+	cursor.mask = ops->cursor_state.mask;
+	cursor.enable = ops->cursor_state.enable;
+	cursor.image.depth = 1;
+	cursor.rop = ROP_XOR;
+
+	info->fbops->fb_cursor(info, &cursor);
+
+	ops->cursor_reset = 0;
+}
+
+void fbcon_set_bitops(struct fbcon_ops *ops)
+{
+	ops->bmove = bit_bmove;
+	ops->clear = bit_clear;
+	ops->putcs = bit_putcs;
+	ops->clear_margins = bit_clear_margins;
+	ops->cursor = bit_cursor;
+}
+
+EXPORT_SYMBOL(fbcon_set_bitops);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Bit Blitting Operation");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c
new file mode 100644
index 0000000..1ecda91
--- /dev/null
+++ b/drivers/video/console/dummycon.c
@@ -0,0 +1,80 @@
+/*
+ *  linux/drivers/video/dummycon.c -- A dummy console driver
+ *
+ *  To be used if there's no other console driver (e.g. for plain VGA text)
+ *  available, usually until fbcon takes console over.
+ */
+
+#include <linux/types.h>
+#include <linux/kdev_t.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/vt_kern.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+/*
+ *  Dummy console driver
+ */
+
+#if defined(__arm__)
+#define DUMMY_COLUMNS	ORIG_VIDEO_COLS
+#define DUMMY_ROWS	ORIG_VIDEO_LINES
+#elif defined(__hppa__)
+/* set by Kconfig. Use 80x25 for 640x480 and 160x64 for 1280x1024 */
+#include <linux/config.h>
+#define DUMMY_COLUMNS	CONFIG_DUMMY_CONSOLE_COLUMNS
+#define DUMMY_ROWS	CONFIG_DUMMY_CONSOLE_ROWS
+#else
+#define DUMMY_COLUMNS	80
+#define DUMMY_ROWS	25
+#endif
+
+static const char *dummycon_startup(void)
+{
+    return "dummy device";
+}
+
+static void dummycon_init(struct vc_data *vc, int init)
+{
+    vc->vc_can_do_color = 1;
+    if (init) {
+	vc->vc_cols = DUMMY_COLUMNS;
+	vc->vc_rows = DUMMY_ROWS;
+    } else
+	vc_resize(vc, DUMMY_COLUMNS, DUMMY_ROWS);
+}
+
+static int dummycon_dummy(void)
+{
+    return 0;
+}
+
+#define DUMMY	(void *)dummycon_dummy
+
+/*
+ *  The console `switch' structure for the dummy console
+ *
+ *  Most of the operations are dummies.
+ */
+
+const struct consw dummy_con = {
+    .owner =		THIS_MODULE,
+    .con_startup =	dummycon_startup,
+    .con_init =		dummycon_init,
+    .con_deinit =	DUMMY,
+    .con_clear =	DUMMY,
+    .con_putc =		DUMMY,
+    .con_putcs =	DUMMY,
+    .con_cursor =	DUMMY,
+    .con_scroll =	DUMMY,
+    .con_bmove =	DUMMY,
+    .con_switch =	DUMMY,
+    .con_blank =	DUMMY,
+    .con_font_set =	DUMMY,
+    .con_font_get =	DUMMY,
+    .con_font_default =	DUMMY,
+    .con_font_copy =	DUMMY,
+    .con_set_palette =	DUMMY,
+    .con_scrolldelta =	DUMMY,
+};
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
new file mode 100644
index 0000000..59e3b4b
--- /dev/null
+++ b/drivers/video/console/fbcon.c
@@ -0,0 +1,2814 @@
+/*
+ *  linux/drivers/video/fbcon.c -- Low level frame buffer based console driver
+ *
+ *	Copyright (C) 1995 Geert Uytterhoeven
+ *
+ *
+ *  This file is based on the original Amiga console driver (amicon.c):
+ *
+ *	Copyright (C) 1993 Hamish Macdonald
+ *			   Greg Harp
+ *	Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk]
+ *
+ *	      with work by William Rucklidge (wjr@cs.cornell.edu)
+ *			   Geert Uytterhoeven
+ *			   Jes Sorensen (jds@kom.auc.dk)
+ *			   Martin Apel
+ *
+ *  and on the original Atari console driver (atacon.c):
+ *
+ *	Copyright (C) 1993 Bjoern Brauel
+ *			   Roman Hodek
+ *
+ *	      with work by Guenther Kelleter
+ *			   Martin Schaller
+ *			   Andreas Schwab
+ *
+ *  Hardware cursor support added by Emmanuel Marty (core@ggi-project.org)
+ *  Smart redraw scrolling, arbitrary font width support, 512char font support
+ *  and software scrollback added by 
+ *                         Jakub Jelinek (jj@ultra.linux.cz)
+ *
+ *  Random hacking by Martin Mares <mj@ucw.cz>
+ *
+ *	2001 - Documented with DocBook
+ *	- Brad Douglas <brad@neruo.com>
+ *
+ *  The low level operations for the various display memory organizations are
+ *  now in separate source files.
+ *
+ *  Currently the following organizations are supported:
+ *
+ *    o afb			Amiga bitplanes
+ *    o cfb{2,4,8,16,24,32}	Packed pixels
+ *    o ilbm			Amiga interleaved bitplanes
+ *    o iplan2p[248]		Atari interleaved bitplanes
+ *    o mfb			Monochrome
+ *    o vga			VGA characters/attributes
+ *
+ *  To do:
+ *
+ *    - Implement 16 plane mode (iplan2p16)
+ *
+ *
+ *  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 FBCONDEBUG
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>	/* MSch: for IRQ probe */
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/string.h>
+#include <linux/kd.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/font.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/crc32.h> /* For counting font checksums */
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#ifdef CONFIG_ATARI
+#include <asm/atariints.h>
+#endif
+#ifdef CONFIG_MAC
+#include <asm/macints.h>
+#endif
+#if defined(__mc68000__) || defined(CONFIG_APUS)
+#include <asm/machdep.h>
+#include <asm/setup.h>
+#endif
+
+#include "fbcon.h"
+
+#ifdef FBCONDEBUG
+#  define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+#  define DPRINTK(fmt, args...)
+#endif
+
+enum {
+	FBCON_LOGO_CANSHOW	= -1,	/* the logo can be shown */
+	FBCON_LOGO_DRAW		= -2,	/* draw the logo to a console */
+	FBCON_LOGO_DONTSHOW	= -3	/* do not show the logo */
+};
+
+struct display fb_display[MAX_NR_CONSOLES];
+static signed char con2fb_map[MAX_NR_CONSOLES];
+static signed char con2fb_map_boot[MAX_NR_CONSOLES];
+static int logo_height;
+static int logo_lines;
+/* logo_shown is an index to vc_cons when >= 0; otherwise follows FBCON_LOGO
+   enums.  */
+static int logo_shown = FBCON_LOGO_CANSHOW;
+/* Software scrollback */
+static int fbcon_softback_size = 32768;
+static unsigned long softback_buf, softback_curr;
+static unsigned long softback_in;
+static unsigned long softback_top, softback_end;
+static int softback_lines;
+/* console mappings */
+static int first_fb_vc;
+static int last_fb_vc = MAX_NR_CONSOLES - 1;
+static int fbcon_is_default = 1; 
+/* font data */
+static char fontname[40];
+
+/* current fb_info */
+static int info_idx = -1;
+
+static const struct consw fb_con;
+
+#define CM_SOFTBACK	(8)
+
+#define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row)
+
+static void fbcon_free_font(struct display *);
+static int fbcon_set_origin(struct vc_data *);
+
+#define CURSOR_DRAW_DELAY		(1)
+
+/* # VBL ints between cursor state changes */
+#define ARM_CURSOR_BLINK_RATE		(10)
+#define ATARI_CURSOR_BLINK_RATE		(42)
+#define MAC_CURSOR_BLINK_RATE		(32)
+#define DEFAULT_CURSOR_BLINK_RATE	(20)
+
+static int vbl_cursor_cnt;
+
+#define divides(a, b)	((!(a) || (b)%(a)) ? 0 : 1)
+
+/*
+ *  Interface used by the world
+ */
+
+static const char *fbcon_startup(void);
+static void fbcon_init(struct vc_data *vc, int init);
+static void fbcon_deinit(struct vc_data *vc);
+static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
+			int width);
+static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos);
+static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
+			int count, int ypos, int xpos);
+static void fbcon_clear_margins(struct vc_data *vc, int bottom_only);
+static void fbcon_cursor(struct vc_data *vc, int mode);
+static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
+			int count);
+static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
+			int height, int width);
+static int fbcon_switch(struct vc_data *vc);
+static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch);
+static int fbcon_set_palette(struct vc_data *vc, unsigned char *table);
+static int fbcon_scrolldelta(struct vc_data *vc, int lines);
+
+/*
+ *  Internal routines
+ */
+static __inline__ int real_y(struct display *p, int ypos);
+static __inline__ void ywrap_up(struct vc_data *vc, int count);
+static __inline__ void ywrap_down(struct vc_data *vc, int count);
+static __inline__ void ypan_up(struct vc_data *vc, int count);
+static __inline__ void ypan_down(struct vc_data *vc, int count);
+static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx,
+			    int dy, int dx, int height, int width, u_int y_break);
+static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
+			   struct vc_data *vc);
+static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *var,
+			      int unit);
+static void fbcon_redraw_move(struct vc_data *vc, struct display *p,
+			      int line, int count, int dy);
+
+#ifdef CONFIG_MAC
+/*
+ * On the Macintoy, there may or may not be a working VBL int. We need to probe
+ */
+static int vbl_detected;
+
+static irqreturn_t fb_vbl_detect(int irq, void *dummy, struct pt_regs *fp)
+{
+	vbl_detected++;
+	return IRQ_HANDLED;
+}
+#endif
+
+static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info)
+{
+	struct fbcon_ops *ops = info->fbcon_par;
+
+	return (info->state != FBINFO_STATE_RUNNING ||
+		vc->vc_mode != KD_TEXT || ops->graphics);
+}
+
+static inline int get_color(struct vc_data *vc, struct fb_info *info,
+	      u16 c, int is_fg)
+{
+	int depth = fb_get_color_depth(&info->var);
+	int color = 0;
+
+	if (console_blanked) {
+		unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+
+		c = vc->vc_video_erase_char & charmask;
+	}
+
+	if (depth != 1)
+		color = (is_fg) ? attr_fgcol((vc->vc_hi_font_mask) ? 9 : 8, c)
+			: attr_bgcol((vc->vc_hi_font_mask) ? 13 : 12, c);
+
+	switch (depth) {
+	case 1:
+	{
+		/* 0 or 1 */
+		int fg = (info->fix.visual != FB_VISUAL_MONO01) ? 1 : 0;
+		int bg = (info->fix.visual != FB_VISUAL_MONO01) ? 0 : 1;
+
+		if (console_blanked)
+			fg = bg;
+
+		color = (is_fg) ? fg : bg;
+		break;
+	}
+	case 2:
+		/*
+		 * Scale down 16-colors to 4 colors. Default 4-color palette
+		 * is grayscale.
+		 */
+		color /= 4;
+		break;
+	case 3:
+		/*
+		 * Last 8 entries of default 16-color palette is a more intense
+		 * version of the first 8 (i.e., same chrominance, different
+		 * luminance).
+		 */
+		color &= 7;
+		break;
+	}
+
+
+	return color;
+}
+
+static void fb_flashcursor(void *private)
+{
+	struct fb_info *info = private;
+	struct fbcon_ops *ops = info->fbcon_par;
+	struct display *p;
+	struct vc_data *vc = NULL;
+	int c;
+	int mode;
+
+	if (ops->currcon != -1)
+		vc = vc_cons[ops->currcon].d;
+
+	if (!vc || !CON_IS_VISIBLE(vc) ||
+	    fbcon_is_inactive(vc, info) ||
+ 	    registered_fb[con2fb_map[vc->vc_num]] != info)
+		return;
+	acquire_console_sem();
+	p = &fb_display[vc->vc_num];
+	c = scr_readw((u16 *) vc->vc_pos);
+	mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
+		CM_ERASE : CM_DRAW;
+	ops->cursor(vc, info, p, mode, softback_lines, get_color(vc, info, c, 1),
+		    get_color(vc, info, c, 0));
+	release_console_sem();
+}
+
+#if (defined(__arm__) && defined(IRQ_VSYNCPULSE)) || defined(CONFIG_ATARI) || defined(CONFIG_MAC)
+static int cursor_blink_rate;
+static irqreturn_t fb_vbl_handler(int irq, void *dev_id, struct pt_regs *fp)
+{
+	struct fb_info *info = dev_id;
+
+	if (vbl_cursor_cnt && --vbl_cursor_cnt == 0) {
+		schedule_work(&info->queue);	
+		vbl_cursor_cnt = cursor_blink_rate; 
+	}
+	return IRQ_HANDLED;
+}
+#endif
+	
+static void cursor_timer_handler(unsigned long dev_addr)
+{
+	struct fb_info *info = (struct fb_info *) dev_addr;
+	struct fbcon_ops *ops = info->fbcon_par;
+
+	schedule_work(&info->queue);
+	mod_timer(&ops->cursor_timer, jiffies + HZ/5);
+}
+
+#ifndef MODULE
+static int __init fb_console_setup(char *this_opt)
+{
+	char *options;
+	int i, j;
+
+	if (!this_opt || !*this_opt)
+		return 0;
+
+	while ((options = strsep(&this_opt, ",")) != NULL) {
+		if (!strncmp(options, "font:", 5))
+			strcpy(fontname, options + 5);
+		
+		if (!strncmp(options, "scrollback:", 11)) {
+			options += 11;
+			if (*options) {
+				fbcon_softback_size = simple_strtoul(options, &options, 0);
+				if (*options == 'k' || *options == 'K') {
+					fbcon_softback_size *= 1024;
+					options++;
+				}
+				if (*options != ',')
+					return 0;
+				options++;
+			} else
+				return 0;
+		}
+		
+		if (!strncmp(options, "map:", 4)) {
+			options += 4;
+			if (*options)
+				for (i = 0, j = 0; i < MAX_NR_CONSOLES; i++) {
+					if (!options[j])
+						j = 0;
+					con2fb_map_boot[i] =
+						(options[j++]-'0') % FB_MAX;
+				}
+			return 0;
+		}
+
+		if (!strncmp(options, "vc:", 3)) {
+			options += 3;
+			if (*options)
+				first_fb_vc = simple_strtoul(options, &options, 10) - 1;
+			if (first_fb_vc < 0)
+				first_fb_vc = 0;
+			if (*options++ == '-')
+				last_fb_vc = simple_strtoul(options, &options, 10) - 1;
+			fbcon_is_default = 0; 
+		}	
+	}
+	return 0;
+}
+
+__setup("fbcon=", fb_console_setup);
+#endif
+
+static int search_fb_in_map(int idx)
+{
+	int i, retval = 0;
+
+	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+		if (con2fb_map[i] == idx)
+			retval = 1;
+	}
+	return retval;
+}
+
+static int search_for_mapped_con(void)
+{
+	int i, retval = 0;
+
+	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+		if (con2fb_map[i] != -1)
+			retval = 1;
+	}
+	return retval;
+}
+
+static int fbcon_takeover(int show_logo)
+{
+	int err, i;
+
+	if (!num_registered_fb)
+		return -ENODEV;
+
+	if (!show_logo)
+		logo_shown = FBCON_LOGO_DONTSHOW;
+
+	for (i = first_fb_vc; i <= last_fb_vc; i++)
+		con2fb_map[i] = info_idx;
+
+	err = take_over_console(&fb_con, first_fb_vc, last_fb_vc,
+				fbcon_is_default);
+	if (err) {
+		for (i = first_fb_vc; i <= last_fb_vc; i++) {
+			con2fb_map[i] = -1;
+		}
+		info_idx = -1;
+	}
+
+	return err;
+}
+
+static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
+			       int cols, int rows, int new_cols, int new_rows)
+{
+	/* Need to make room for the logo */
+	int cnt, erase = vc->vc_video_erase_char, step;
+	unsigned short *save = NULL, *r, *q;
+
+	/*
+	 * remove underline attribute from erase character
+	 * if black and white framebuffer.
+	 */
+	if (fb_get_color_depth(&info->var) == 1)
+		erase &= ~0x400;
+	logo_height = fb_prepare_logo(info);
+	logo_lines = (logo_height + vc->vc_font.height - 1) /
+		vc->vc_font.height;
+	q = (unsigned short *) (vc->vc_origin +
+				vc->vc_size_row * rows);
+	step = logo_lines * cols;
+	for (r = q - logo_lines * cols; r < q; r++)
+		if (scr_readw(r) != vc->vc_video_erase_char)
+			break;
+	if (r != q && new_rows >= rows + logo_lines) {
+		save = kmalloc(logo_lines * new_cols * 2, GFP_KERNEL);
+		if (save) {
+			int i = cols < new_cols ? cols : new_cols;
+			scr_memsetw(save, erase, logo_lines * new_cols * 2);
+			r = q - step;
+			for (cnt = 0; cnt < logo_lines; cnt++, r += i)
+				scr_memcpyw(save + cnt * new_cols, r, 2 * i);
+			r = q;
+		}
+	}
+	if (r == q) {
+		/* We can scroll screen down */
+		r = q - step - cols;
+		for (cnt = rows - logo_lines; cnt > 0; cnt--) {
+			scr_memcpyw(r + step, r, vc->vc_size_row);
+			r -= cols;
+		}
+		if (!save) {
+			vc->vc_y += logo_lines;
+			vc->vc_pos += logo_lines * vc->vc_size_row;
+		}
+	}
+	scr_memsetw((unsigned short *) vc->vc_origin,
+		    erase,
+		    vc->vc_size_row * logo_lines);
+
+	if (CON_IS_VISIBLE(vc) && vc->vc_mode == KD_TEXT) {
+		fbcon_clear_margins(vc, 0);
+		update_screen(vc);
+	}
+
+	if (save) {
+		q = (unsigned short *) (vc->vc_origin +
+					vc->vc_size_row *
+					rows);
+		scr_memcpyw(q, save, logo_lines * new_cols * 2);
+		vc->vc_y += logo_lines;
+		vc->vc_pos += logo_lines * vc->vc_size_row;
+		kfree(save);
+	}
+
+	if (logo_lines > vc->vc_bottom) {
+		logo_shown = FBCON_LOGO_CANSHOW;
+		printk(KERN_INFO
+		       "fbcon_init: disable boot-logo (boot-logo bigger than screen).\n");
+	} else if (logo_shown != FBCON_LOGO_DONTSHOW) {
+		logo_shown = FBCON_LOGO_DRAW;
+		vc->vc_top = logo_lines;
+	}
+}
+
+#ifdef CONFIG_FB_TILEBLITTING
+static void set_blitting_type(struct vc_data *vc, struct fb_info *info,
+			      struct display *p)
+{
+	struct fbcon_ops *ops = info->fbcon_par;
+
+	if ((info->flags & FBINFO_MISC_TILEBLITTING))
+		fbcon_set_tileops(vc, info, p, ops);
+	else
+		fbcon_set_bitops(ops);
+}
+#else
+static void set_blitting_type(struct vc_data *vc, struct fb_info *info,
+			      struct display *p)
+{
+	struct fbcon_ops *ops = info->fbcon_par;
+
+	info->flags &= ~FBINFO_MISC_TILEBLITTING;
+	fbcon_set_bitops(ops);
+}
+#endif /* CONFIG_MISC_TILEBLITTING */
+
+
+static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,
+				  int unit, int oldidx)
+{
+	struct fbcon_ops *ops = NULL;
+	int err = 0;
+
+	if (!try_module_get(info->fbops->owner))
+		err = -ENODEV;
+
+	if (!err && info->fbops->fb_open &&
+	    info->fbops->fb_open(info, 0))
+		err = -ENODEV;
+
+	if (!err) {
+		ops = kmalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
+		if (!ops)
+			err = -ENOMEM;
+	}
+
+	if (!err) {
+		memset(ops, 0, sizeof(struct fbcon_ops));
+		info->fbcon_par = ops;
+		set_blitting_type(vc, info, NULL);
+	}
+
+	if (err) {
+		con2fb_map[unit] = oldidx;
+		module_put(info->fbops->owner);
+	}
+
+	return err;
+}
+
+static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo,
+				  struct fb_info *newinfo, int unit,
+				  int oldidx, int found)
+{
+	struct fbcon_ops *ops = oldinfo->fbcon_par;
+	int err = 0;
+
+	if (oldinfo->fbops->fb_release &&
+	    oldinfo->fbops->fb_release(oldinfo, 0)) {
+		con2fb_map[unit] = oldidx;
+		if (!found && newinfo->fbops->fb_release)
+			newinfo->fbops->fb_release(newinfo, 0);
+		if (!found)
+			module_put(newinfo->fbops->owner);
+		err = -ENODEV;
+	}
+
+	if (!err) {
+		if (oldinfo->queue.func == fb_flashcursor)
+			del_timer_sync(&ops->cursor_timer);
+
+		kfree(ops->cursor_state.mask);
+		kfree(ops->cursor_data);
+		kfree(oldinfo->fbcon_par);
+		oldinfo->fbcon_par = NULL;
+		module_put(oldinfo->fbops->owner);
+	}
+
+	return err;
+}
+
+static void con2fb_init_newinfo(struct fb_info *info)
+{
+	if (!info->queue.func || info->queue.func == fb_flashcursor) {
+		struct fbcon_ops *ops = info->fbcon_par;
+
+		if (!info->queue.func)
+			INIT_WORK(&info->queue, fb_flashcursor, info);
+
+		init_timer(&ops->cursor_timer);
+		ops->cursor_timer.function = cursor_timer_handler;
+		ops->cursor_timer.expires = jiffies + HZ / 5;
+		ops->cursor_timer.data = (unsigned long ) info;
+		add_timer(&ops->cursor_timer);
+	}
+}
+
+static void con2fb_init_display(struct vc_data *vc, struct fb_info *info,
+				int unit, int show_logo)
+{
+	struct fbcon_ops *ops = info->fbcon_par;
+
+	ops->currcon = fg_console;
+
+	if (info->fbops->fb_set_par && !(ops->flags & FBCON_FLAGS_INIT))
+		info->fbops->fb_set_par(info);
+
+	ops->flags |= FBCON_FLAGS_INIT;
+	ops->graphics = 0;
+
+	if (vc)
+		fbcon_set_disp(info, &info->var, vc);
+	else
+		fbcon_preset_disp(info, &info->var, unit);
+
+	if (show_logo) {
+		struct vc_data *fg_vc = vc_cons[fg_console].d;
+		struct fb_info *fg_info =
+			registered_fb[con2fb_map[fg_console]];
+
+		fbcon_prepare_logo(fg_vc, fg_info, fg_vc->vc_cols,
+				   fg_vc->vc_rows, fg_vc->vc_cols,
+				   fg_vc->vc_rows);
+	}
+
+	update_screen(vc_cons[fg_console].d);
+}
+
+/**
+ *	set_con2fb_map - map console to frame buffer device
+ *	@unit: virtual console number to map
+ *	@newidx: frame buffer index to map virtual console to
+ *      @user: user request
+ *
+ *	Maps a virtual console @unit to a frame buffer device
+ *	@newidx.
+ */
+static int set_con2fb_map(int unit, int newidx, int user)
+{
+	struct vc_data *vc = vc_cons[unit].d;
+	int oldidx = con2fb_map[unit];
+	struct fb_info *info = registered_fb[newidx];
+	struct fb_info *oldinfo = NULL;
+ 	int found, err = 0;
+
+	if (oldidx == newidx)
+		return 0;
+
+	if (!info)
+ 		err =  -EINVAL;
+
+ 	if (!err && !search_for_mapped_con()) {
+		info_idx = newidx;
+		return fbcon_takeover(0);
+	}
+
+	if (oldidx != -1)
+		oldinfo = registered_fb[oldidx];
+
+	found = search_fb_in_map(newidx);
+
+	acquire_console_sem();
+	con2fb_map[unit] = newidx;
+	if (!err && !found)
+ 		err = con2fb_acquire_newinfo(vc, info, unit, oldidx);
+
+
+	/*
+	 * If old fb is not mapped to any of the consoles,
+	 * fbcon should release it.
+	 */
+ 	if (!err && oldinfo && !search_fb_in_map(oldidx))
+ 		err = con2fb_release_oldinfo(vc, oldinfo, info, unit, oldidx,
+ 					     found);
+
+ 	if (!err) {
+ 		int show_logo = (fg_console == 0 && !user &&
+ 				 logo_shown != FBCON_LOGO_DONTSHOW);
+
+ 		if (!found)
+ 			con2fb_init_newinfo(info);
+ 		con2fb_map_boot[unit] = newidx;
+ 		con2fb_init_display(vc, info, unit, show_logo);
+	}
+
+	release_console_sem();
+ 	return err;
+}
+
+/*
+ *  Low Level Operations
+ */
+/* NOTE: fbcon cannot be __init: it may be called from take_over_console later */
+static int var_to_display(struct display *disp,
+			  struct fb_var_screeninfo *var,
+			  struct fb_info *info)
+{
+	disp->xres_virtual = var->xres_virtual;
+	disp->yres_virtual = var->yres_virtual;
+	disp->bits_per_pixel = var->bits_per_pixel;
+	disp->grayscale = var->grayscale;
+	disp->nonstd = var->nonstd;
+	disp->accel_flags = var->accel_flags;
+	disp->height = var->height;
+	disp->width = var->width;
+	disp->red = var->red;
+	disp->green = var->green;
+	disp->blue = var->blue;
+	disp->transp = var->transp;
+	disp->rotate = var->rotate;
+	disp->mode = fb_match_mode(var, &info->modelist);
+	if (disp->mode == NULL)
+		/* This should not happen */
+		return -EINVAL;
+	return 0;
+}
+
+static void display_to_var(struct fb_var_screeninfo *var,
+			   struct display *disp)
+{
+	fb_videomode_to_var(var, disp->mode);
+	var->xres_virtual = disp->xres_virtual;
+	var->yres_virtual = disp->yres_virtual;
+	var->bits_per_pixel = disp->bits_per_pixel;
+	var->grayscale = disp->grayscale;
+	var->nonstd = disp->nonstd;
+	var->accel_flags = disp->accel_flags;
+	var->height = disp->height;
+	var->width = disp->width;
+	var->red = disp->red;
+	var->green = disp->green;
+	var->blue = disp->blue;
+	var->transp = disp->transp;
+	var->rotate = disp->rotate;
+}
+
+static const char *fbcon_startup(void)
+{
+	const char *display_desc = "frame buffer device";
+	struct display *p = &fb_display[fg_console];
+	struct vc_data *vc = vc_cons[fg_console].d;
+	struct font_desc *font = NULL;
+	struct module *owner;
+	struct fb_info *info = NULL;
+	struct fbcon_ops *ops;
+	int rows, cols;
+	int irqres;
+
+	irqres = 1;
+	/*
+	 *  If num_registered_fb is zero, this is a call for the dummy part.
+	 *  The frame buffer devices weren't initialized yet.
+	 */
+	if (!num_registered_fb || info_idx == -1)
+		return display_desc;
+	/*
+	 * Instead of blindly using registered_fb[0], we use info_idx, set by
+	 * fb_console_init();
+	 */
+	info = registered_fb[info_idx];
+	if (!info)
+		return NULL;
+	
+	owner = info->fbops->owner;
+	if (!try_module_get(owner))
+		return NULL;
+	if (info->fbops->fb_open && info->fbops->fb_open(info, 0)) {
+		module_put(owner);
+		return NULL;
+	}
+
+	ops = kmalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
+	if (!ops) {
+		module_put(owner);
+		return NULL;
+	}
+
+	memset(ops, 0, sizeof(struct fbcon_ops));
+	ops->currcon = -1;
+	ops->graphics = 1;
+	info->fbcon_par = ops;
+	set_blitting_type(vc, info, NULL);
+
+	if (info->fix.type != FB_TYPE_TEXT) {
+		if (fbcon_softback_size) {
+			if (!softback_buf) {
+				softback_buf =
+				    (unsigned long)
+				    kmalloc(fbcon_softback_size,
+					    GFP_KERNEL);
+				if (!softback_buf) {
+					fbcon_softback_size = 0;
+					softback_top = 0;
+				}
+			}
+		} else {
+			if (softback_buf) {
+				kfree((void *) softback_buf);
+				softback_buf = 0;
+				softback_top = 0;
+			}
+		}
+		if (softback_buf)
+			softback_in = softback_top = softback_curr =
+			    softback_buf;
+		softback_lines = 0;
+	}
+
+	/* Setup default font */
+	if (!p->fontdata) {
+		if (!fontname[0] || !(font = find_font(fontname)))
+			font = get_default_font(info->var.xres,
+						info->var.yres);
+		vc->vc_font.width = font->width;
+		vc->vc_font.height = font->height;
+		vc->vc_font.data = p->fontdata = font->data;
+		vc->vc_font.charcount = 256; /* FIXME  Need to support more fonts */
+	}
+
+	cols = info->var.xres / vc->vc_font.width;
+	rows = info->var.yres / vc->vc_font.height;
+	vc_resize(vc, cols, rows);
+
+	DPRINTK("mode:   %s\n", info->fix.id);
+	DPRINTK("visual: %d\n", info->fix.visual);
+	DPRINTK("res:    %dx%d-%d\n", info->var.xres,
+		info->var.yres,
+		info->var.bits_per_pixel);
+
+#ifdef CONFIG_ATARI
+	if (MACH_IS_ATARI) {
+		cursor_blink_rate = ATARI_CURSOR_BLINK_RATE;
+		irqres =
+		    request_irq(IRQ_AUTO_4, fb_vbl_handler,
+				IRQ_TYPE_PRIO, "framebuffer vbl",
+				info);
+	}
+#endif				/* CONFIG_ATARI */
+
+#ifdef CONFIG_MAC
+	/*
+	 * On a Macintoy, the VBL interrupt may or may not be active. 
+	 * As interrupt based cursor is more reliable and race free, we 
+	 * probe for VBL interrupts.
+	 */
+	if (MACH_IS_MAC) {
+		int ct = 0;
+		/*
+		 * Probe for VBL: set temp. handler ...
+		 */
+		irqres = request_irq(IRQ_MAC_VBL, fb_vbl_detect, 0,
+				     "framebuffer vbl", info);
+		vbl_detected = 0;
+
+		/*
+		 * ... and spin for 20 ms ...
+		 */
+		while (!vbl_detected && ++ct < 1000)
+			udelay(20);
+
+		if (ct == 1000)
+			printk
+			    ("fbcon_startup: No VBL detected, using timer based cursor.\n");
+
+		free_irq(IRQ_MAC_VBL, fb_vbl_detect);
+
+		if (vbl_detected) {
+			/*
+			 * interrupt based cursor ok
+			 */
+			cursor_blink_rate = MAC_CURSOR_BLINK_RATE;
+			irqres =
+			    request_irq(IRQ_MAC_VBL, fb_vbl_handler, 0,
+					"framebuffer vbl", info);
+		} else {
+			/*
+			 * VBL not detected: fall through, use timer based cursor
+			 */
+			irqres = 1;
+		}
+	}
+#endif				/* CONFIG_MAC */
+
+#if defined(__arm__) && defined(IRQ_VSYNCPULSE)
+	cursor_blink_rate = ARM_CURSOR_BLINK_RATE;
+	irqres = request_irq(IRQ_VSYNCPULSE, fb_vbl_handler, SA_SHIRQ,
+			     "framebuffer vbl", info);
+#endif
+	/* Initialize the work queue. If the driver provides its
+	 * own work queue this means it will use something besides 
+	 * default timer to flash the cursor. */
+	if (!info->queue.func) {
+		INIT_WORK(&info->queue, fb_flashcursor, info);
+
+		init_timer(&ops->cursor_timer);
+		ops->cursor_timer.function = cursor_timer_handler;
+		ops->cursor_timer.expires = jiffies + HZ / 5;
+		ops->cursor_timer.data = (unsigned long ) info;
+		add_timer(&ops->cursor_timer);
+	}
+	return display_desc;
+}
+
+static void fbcon_init(struct vc_data *vc, int init)
+{
+	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct fbcon_ops *ops;
+	struct vc_data **default_mode = vc->vc_display_fg;
+	struct vc_data *svc = *default_mode;
+	struct display *t, *p = &fb_display[vc->vc_num];
+	int logo = 1, new_rows, new_cols, rows, cols, charcnt = 256;
+	int cap = info->flags;
+
+	if (info_idx == -1 || info == NULL)
+	    return;
+	if (vc != svc || logo_shown == FBCON_LOGO_DONTSHOW ||
+	    (info->fix.type == FB_TYPE_TEXT))
+		logo = 0;
+
+	info->var.xoffset = info->var.yoffset = p->yscroll = 0;	/* reset wrap/pan */
+
+	if (var_to_display(p, &info->var, info))
+		return;
+
+	/* If we are not the first console on this
+	   fb, copy the font from that console */
+	t = &fb_display[svc->vc_num];
+	if (!vc->vc_font.data) {
+		vc->vc_font.data = p->fontdata = t->fontdata;
+		vc->vc_font.width = (*default_mode)->vc_font.width;
+		vc->vc_font.height = (*default_mode)->vc_font.height;
+		p->userfont = t->userfont;
+		if (p->userfont)
+			REFCOUNT(p->fontdata)++;
+	}
+	if (p->userfont)
+		charcnt = FNTCHARCNT(p->fontdata);
+	vc->vc_can_do_color = (fb_get_color_depth(&info->var) != 1);
+	vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
+	if (charcnt == 256) {
+		vc->vc_hi_font_mask = 0;
+	} else {
+		vc->vc_hi_font_mask = 0x100;
+		if (vc->vc_can_do_color)
+			vc->vc_complement_mask <<= 1;
+	}
+
+	if (!*svc->vc_uni_pagedir_loc)
+		con_set_default_unimap(svc);
+	if (!*vc->vc_uni_pagedir_loc)
+		con_copy_unimap(vc, svc);
+
+	cols = vc->vc_cols;
+	rows = vc->vc_rows;
+	new_cols = info->var.xres / vc->vc_font.width;
+	new_rows = info->var.yres / vc->vc_font.height;
+	vc_resize(vc, new_cols, new_rows);
+
+	ops = info->fbcon_par;
+	/*
+	 * We must always set the mode. The mode of the previous console
+	 * driver could be in the same resolution but we are using different
+	 * hardware so we have to initialize the hardware.
+	 *
+	 * We need to do it in fbcon_init() to prevent screen corruption.
+	 */
+	if (CON_IS_VISIBLE(vc)) {
+		if (info->fbops->fb_set_par &&
+		    !(ops->flags & FBCON_FLAGS_INIT))
+			info->fbops->fb_set_par(info);
+		ops->flags |= FBCON_FLAGS_INIT;
+	}
+
+	ops->graphics = 0;
+
+	if ((cap & FBINFO_HWACCEL_COPYAREA) &&
+	    !(cap & FBINFO_HWACCEL_DISABLED))
+		p->scrollmode = SCROLL_MOVE;
+	else /* default to something safe */
+		p->scrollmode = SCROLL_REDRAW;
+
+	/*
+	 *  ++guenther: console.c:vc_allocate() relies on initializing
+	 *  vc_{cols,rows}, but we must not set those if we are only
+	 *  resizing the console.
+	 */
+	if (!init) {
+		vc->vc_cols = new_cols;
+		vc->vc_rows = new_rows;
+	}
+
+	if (logo)
+		fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows);
+
+	if (vc == svc && softback_buf) {
+		int l = fbcon_softback_size / vc->vc_size_row;
+		if (l > 5)
+			softback_end = softback_buf + l * vc->vc_size_row;
+		else {
+			/* Smaller scrollback makes no sense, and 0 would screw
+			   the operation totally */
+			softback_top = 0;
+		}
+	}
+}
+
+static void fbcon_deinit(struct vc_data *vc)
+{
+	struct display *p = &fb_display[vc->vc_num];
+
+	if (info_idx != -1)
+	    return;
+	fbcon_free_font(p);
+}
+
+/* ====================================================================== */
+
+/*  fbcon_XXX routines - interface used by the world
+ *
+ *  This system is now divided into two levels because of complications
+ *  caused by hardware scrolling. Top level functions:
+ *
+ *	fbcon_bmove(), fbcon_clear(), fbcon_putc(), fbcon_clear_margins()
+ *
+ *  handles y values in range [0, scr_height-1] that correspond to real
+ *  screen positions. y_wrap shift means that first line of bitmap may be
+ *  anywhere on this display. These functions convert lineoffsets to
+ *  bitmap offsets and deal with the wrap-around case by splitting blits.
+ *
+ *	fbcon_bmove_physical_8()    -- These functions fast implementations
+ *	fbcon_clear_physical_8()    -- of original fbcon_XXX fns.
+ *	fbcon_putc_physical_8()	    -- (font width != 8) may be added later
+ *
+ *  WARNING:
+ *
+ *  At the moment fbcon_putc() cannot blit across vertical wrap boundary
+ *  Implies should only really hardware scroll in rows. Only reason for
+ *  restriction is simplicity & efficiency at the moment.
+ */
+
+static __inline__ int real_y(struct display *p, int ypos)
+{
+	int rows = p->vrows;
+
+	ypos += p->yscroll;
+	return ypos < rows ? ypos : ypos - rows;
+}
+
+
+static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
+			int width)
+{
+	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct fbcon_ops *ops = info->fbcon_par;
+
+	struct display *p = &fb_display[vc->vc_num];
+	u_int y_break;
+
+	if (fbcon_is_inactive(vc, info))
+		return;
+
+	if (!height || !width)
+		return;
+
+	/* Split blits that cross physical y_wrap boundary */
+
+	y_break = p->vrows - p->yscroll;
+	if (sy < y_break && sy + height - 1 >= y_break) {
+		u_int b = y_break - sy;
+		ops->clear(vc, info, real_y(p, sy), sx, b, width);
+		ops->clear(vc, info, real_y(p, sy + b), sx, height - b,
+				 width);
+	} else
+		ops->clear(vc, info, real_y(p, sy), sx, height, width);
+}
+
+static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
+			int count, int ypos, int xpos)
+{
+	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct display *p = &fb_display[vc->vc_num];
+	struct fbcon_ops *ops = info->fbcon_par;
+
+	if (!fbcon_is_inactive(vc, info))
+		ops->putcs(vc, info, s, count, real_y(p, ypos), xpos,
+			   get_color(vc, info, scr_readw(s), 1),
+			   get_color(vc, info, scr_readw(s), 0));
+}
+
+static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos)
+{
+	unsigned short chr;
+
+	scr_writew(c, &chr);
+	fbcon_putcs(vc, &chr, 1, ypos, xpos);
+}
+
+static void fbcon_clear_margins(struct vc_data *vc, int bottom_only)
+{
+	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct fbcon_ops *ops = info->fbcon_par;
+
+	if (!fbcon_is_inactive(vc, info))
+		ops->clear_margins(vc, info, bottom_only);
+}
+
+static void fbcon_cursor(struct vc_data *vc, int mode)
+{
+	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct fbcon_ops *ops = info->fbcon_par;
+	struct display *p = &fb_display[vc->vc_num];
+	int y;
+ 	int c = scr_readw((u16 *) vc->vc_pos);
+
+	if (fbcon_is_inactive(vc, info))
+		return;
+
+	ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
+	if (mode & CM_SOFTBACK) {
+		mode &= ~CM_SOFTBACK;
+		y = softback_lines;
+	} else {
+		if (softback_lines)
+			fbcon_set_origin(vc);
+		y = 0;
+	}
+
+	ops->cursor(vc, info, p, mode, y, get_color(vc, info, c, 1),
+		    get_color(vc, info, c, 0));
+	vbl_cursor_cnt = CURSOR_DRAW_DELAY;
+}
+
+static int scrollback_phys_max = 0;
+static int scrollback_max = 0;
+static int scrollback_current = 0;
+
+static int update_var(int con, struct fb_info *info)
+{
+	if (con == ((struct fbcon_ops *)info->fbcon_par)->currcon)
+		return fb_pan_display(info, &info->var);
+	return 0;
+}
+
+/*
+ * If no vc is existent yet, just set struct display
+ */
+static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *var,
+			      int unit)
+{
+	struct display *p = &fb_display[unit];
+	struct display *t = &fb_display[fg_console];
+
+	var->xoffset = var->yoffset = p->yscroll = 0;
+	if (var_to_display(p, var, info))
+		return;
+
+	p->fontdata = t->fontdata;
+	p->userfont = t->userfont;
+	if (p->userfont)
+		REFCOUNT(p->fontdata)++;
+}
+
+static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
+			   struct vc_data *vc)
+{
+	struct display *p = &fb_display[vc->vc_num], *t;
+	struct vc_data **default_mode = vc->vc_display_fg;
+	struct vc_data *svc = *default_mode;
+	int rows, cols, charcnt = 256;
+
+	var->xoffset = var->yoffset = p->yscroll = 0;
+	if (var_to_display(p, var, info))
+		return;
+	t = &fb_display[svc->vc_num];
+	if (!vc->vc_font.data) {
+		vc->vc_font.data = p->fontdata = t->fontdata;
+		vc->vc_font.width = (*default_mode)->vc_font.width;
+		vc->vc_font.height = (*default_mode)->vc_font.height;
+		p->userfont = t->userfont;
+		if (p->userfont)
+			REFCOUNT(p->fontdata)++;
+	}
+	if (p->userfont)
+		charcnt = FNTCHARCNT(p->fontdata);
+
+	vc->vc_can_do_color = (fb_get_color_depth(var) != 1);
+	vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
+	if (charcnt == 256) {
+		vc->vc_hi_font_mask = 0;
+	} else {
+		vc->vc_hi_font_mask = 0x100;
+		if (vc->vc_can_do_color)
+			vc->vc_complement_mask <<= 1;
+	}
+
+	if (!*svc->vc_uni_pagedir_loc)
+		con_set_default_unimap(svc);
+	if (!*vc->vc_uni_pagedir_loc)
+		con_copy_unimap(vc, svc);
+
+	cols = var->xres / vc->vc_font.width;
+	rows = var->yres / vc->vc_font.height;
+	vc_resize(vc, cols, rows);
+	if (CON_IS_VISIBLE(vc)) {
+		update_screen(vc);
+		if (softback_buf) {
+			int l = fbcon_softback_size / vc->vc_size_row;
+
+			if (l > 5)
+				softback_end = softback_buf + l *
+					vc->vc_size_row;
+			else {
+				/* Smaller scrollback makes no sense, and 0
+				   would screw the operation totally */
+				softback_top = 0;
+			}
+		}
+	}
+}
+
+static __inline__ void ywrap_up(struct vc_data *vc, int count)
+{
+	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct display *p = &fb_display[vc->vc_num];
+	
+	p->yscroll += count;
+	if (p->yscroll >= p->vrows)	/* Deal with wrap */
+		p->yscroll -= p->vrows;
+	info->var.xoffset = 0;
+	info->var.yoffset = p->yscroll * vc->vc_font.height;
+	info->var.vmode |= FB_VMODE_YWRAP;
+	update_var(vc->vc_num, info);
+	scrollback_max += count;
+	if (scrollback_max > scrollback_phys_max)
+		scrollback_max = scrollback_phys_max;
+	scrollback_current = 0;
+}
+
+static __inline__ void ywrap_down(struct vc_data *vc, int count)
+{
+	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct display *p = &fb_display[vc->vc_num];
+	
+	p->yscroll -= count;
+	if (p->yscroll < 0)	/* Deal with wrap */
+		p->yscroll += p->vrows;
+	info->var.xoffset = 0;
+	info->var.yoffset = p->yscroll * vc->vc_font.height;
+	info->var.vmode |= FB_VMODE_YWRAP;
+	update_var(vc->vc_num, info);
+	scrollback_max -= count;
+	if (scrollback_max < 0)
+		scrollback_max = 0;
+	scrollback_current = 0;
+}
+
+static __inline__ void ypan_up(struct vc_data *vc, int count)
+{
+	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct display *p = &fb_display[vc->vc_num];
+	struct fbcon_ops *ops = info->fbcon_par;
+
+	p->yscroll += count;
+	if (p->yscroll > p->vrows - vc->vc_rows) {
+		ops->bmove(vc, info, p->vrows - vc->vc_rows,
+			    0, 0, 0, vc->vc_rows, vc->vc_cols);
+		p->yscroll -= p->vrows - vc->vc_rows;
+	}
+	info->var.xoffset = 0;
+	info->var.yoffset = p->yscroll * vc->vc_font.height;
+	info->var.vmode &= ~FB_VMODE_YWRAP;
+	update_var(vc->vc_num, info);
+	fbcon_clear_margins(vc, 1);
+	scrollback_max += count;
+	if (scrollback_max > scrollback_phys_max)
+		scrollback_max = scrollback_phys_max;
+	scrollback_current = 0;
+}
+
+static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)
+{
+	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct display *p = &fb_display[vc->vc_num];
+	int redraw = 0;
+
+	p->yscroll += count;
+	if (p->yscroll > p->vrows - vc->vc_rows) {
+		p->yscroll -= p->vrows - vc->vc_rows;
+		redraw = 1;
+	}
+
+	info->var.xoffset = 0;
+	info->var.yoffset = p->yscroll * vc->vc_font.height;
+	info->var.vmode &= ~FB_VMODE_YWRAP;
+	if (redraw)
+		fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t);
+	update_var(vc->vc_num, info);
+	fbcon_clear_margins(vc, 1);
+	scrollback_max += count;
+	if (scrollback_max > scrollback_phys_max)
+		scrollback_max = scrollback_phys_max;
+	scrollback_current = 0;
+}
+
+static __inline__ void ypan_down(struct vc_data *vc, int count)
+{
+	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct display *p = &fb_display[vc->vc_num];
+	struct fbcon_ops *ops = info->fbcon_par;
+	
+	p->yscroll -= count;
+	if (p->yscroll < 0) {
+		ops->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows,
+			    0, vc->vc_rows, vc->vc_cols);
+		p->yscroll += p->vrows - vc->vc_rows;
+	}
+	info->var.xoffset = 0;
+	info->var.yoffset = p->yscroll * vc->vc_font.height;
+	info->var.vmode &= ~FB_VMODE_YWRAP;
+	update_var(vc->vc_num, info);
+	fbcon_clear_margins(vc, 1);
+	scrollback_max -= count;
+	if (scrollback_max < 0)
+		scrollback_max = 0;
+	scrollback_current = 0;
+}
+
+static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
+{
+	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct display *p = &fb_display[vc->vc_num];
+	int redraw = 0;
+
+	p->yscroll -= count;
+	if (p->yscroll < 0) {
+		p->yscroll += p->vrows - vc->vc_rows;
+		redraw = 1;
+	}
+	info->var.xoffset = 0;
+	info->var.yoffset = p->yscroll * vc->vc_font.height;
+	info->var.vmode &= ~FB_VMODE_YWRAP;
+	if (redraw)
+		fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count);
+	update_var(vc->vc_num, info);
+	fbcon_clear_margins(vc, 1);
+	scrollback_max -= count;
+	if (scrollback_max < 0)
+		scrollback_max = 0;
+	scrollback_current = 0;
+}
+
+static void fbcon_redraw_softback(struct vc_data *vc, struct display *p,
+				  long delta)
+{
+	int count = vc->vc_rows;
+	unsigned short *d, *s;
+	unsigned long n;
+	int line = 0;
+
+	d = (u16 *) softback_curr;
+	if (d == (u16 *) softback_in)
+		d = (u16 *) vc->vc_origin;
+	n = softback_curr + delta * vc->vc_size_row;
+	softback_lines -= delta;
+	if (delta < 0) {
+		if (softback_curr < softback_top && n < softback_buf) {
+			n += softback_end - softback_buf;
+			if (n < softback_top) {
+				softback_lines -=
+				    (softback_top - n) / vc->vc_size_row;
+				n = softback_top;
+			}
+		} else if (softback_curr >= softback_top
+			   && n < softback_top) {
+			softback_lines -=
+			    (softback_top - n) / vc->vc_size_row;
+			n = softback_top;
+		}
+	} else {
+		if (softback_curr > softback_in && n >= softback_end) {
+			n += softback_buf - softback_end;
+			if (n > softback_in) {
+				n = softback_in;
+				softback_lines = 0;
+			}
+		} else if (softback_curr <= softback_in && n > softback_in) {
+			n = softback_in;
+			softback_lines = 0;
+		}
+	}
+	if (n == softback_curr)
+		return;
+	softback_curr = n;
+	s = (u16 *) softback_curr;
+	if (s == (u16 *) softback_in)
+		s = (u16 *) vc->vc_origin;
+	while (count--) {
+		unsigned short *start;
+		unsigned short *le;
+		unsigned short c;
+		int x = 0;
+		unsigned short attr = 1;
+
+		start = s;
+		le = advance_row(s, 1);
+		do {
+			c = scr_readw(s);
+			if (attr != (c & 0xff00)) {
+				attr = c & 0xff00;
+				if (s > start) {
+					fbcon_putcs(vc, start, s - start,
+						    line, x);
+					x += s - start;
+					start = s;
+				}
+			}
+			if (c == scr_readw(d)) {
+				if (s > start) {
+					fbcon_putcs(vc, start, s - start,
+						    line, x);
+					x += s - start + 1;
+					start = s + 1;
+				} else {
+					x++;
+					start++;
+				}
+			}
+			s++;
+			d++;
+		} while (s < le);
+		if (s > start)
+			fbcon_putcs(vc, start, s - start, line, x);
+		line++;
+		if (d == (u16 *) softback_end)
+			d = (u16 *) softback_buf;
+		if (d == (u16 *) softback_in)
+			d = (u16 *) vc->vc_origin;
+		if (s == (u16 *) softback_end)
+			s = (u16 *) softback_buf;
+		if (s == (u16 *) softback_in)
+			s = (u16 *) vc->vc_origin;
+	}
+}
+
+static void fbcon_redraw_move(struct vc_data *vc, struct display *p,
+			      int line, int count, int dy)
+{
+	unsigned short *s = (unsigned short *)
+		(vc->vc_origin + vc->vc_size_row * line);
+
+	while (count--) {
+		unsigned short *start = s;
+		unsigned short *le = advance_row(s, 1);
+		unsigned short c;
+		int x = 0;
+		unsigned short attr = 1;
+
+		do {
+			c = scr_readw(s);
+			if (attr != (c & 0xff00)) {
+				attr = c & 0xff00;
+				if (s > start) {
+					fbcon_putcs(vc, start, s - start,
+						    dy, x);
+					x += s - start;
+					start = s;
+				}
+			}
+			console_conditional_schedule();
+			s++;
+		} while (s < le);
+		if (s > start)
+			fbcon_putcs(vc, start, s - start, dy, x);
+		console_conditional_schedule();
+		dy++;
+	}
+}
+
+static void fbcon_redraw(struct vc_data *vc, struct display *p,
+			 int line, int count, int offset)
+{
+	unsigned short *d = (unsigned short *)
+	    (vc->vc_origin + vc->vc_size_row * line);
+	unsigned short *s = d + offset;
+
+	while (count--) {
+		unsigned short *start = s;
+		unsigned short *le = advance_row(s, 1);
+		unsigned short c;
+		int x = 0;
+		unsigned short attr = 1;
+
+		do {
+			c = scr_readw(s);
+			if (attr != (c & 0xff00)) {
+				attr = c & 0xff00;
+				if (s > start) {
+					fbcon_putcs(vc, start, s - start,
+						    line, x);
+					x += s - start;
+					start = s;
+				}
+			}
+			if (c == scr_readw(d)) {
+				if (s > start) {
+					fbcon_putcs(vc, start, s - start,
+						     line, x);
+					x += s - start + 1;
+					start = s + 1;
+				} else {
+					x++;
+					start++;
+				}
+			}
+			scr_writew(c, d);
+			console_conditional_schedule();
+			s++;
+			d++;
+		} while (s < le);
+		if (s > start)
+			fbcon_putcs(vc, start, s - start, line, x);
+		console_conditional_schedule();
+		if (offset > 0)
+			line++;
+		else {
+			line--;
+			/* NOTE: We subtract two lines from these pointers */
+			s -= vc->vc_size_row;
+			d -= vc->vc_size_row;
+		}
+	}
+}
+
+static inline void fbcon_softback_note(struct vc_data *vc, int t,
+				       int count)
+{
+	unsigned short *p;
+
+	if (vc->vc_num != fg_console)
+		return;
+	p = (unsigned short *) (vc->vc_origin + t * vc->vc_size_row);
+
+	while (count) {
+		scr_memcpyw((u16 *) softback_in, p, vc->vc_size_row);
+		count--;
+		p = advance_row(p, 1);
+		softback_in += vc->vc_size_row;
+		if (softback_in == softback_end)
+			softback_in = softback_buf;
+		if (softback_in == softback_top) {
+			softback_top += vc->vc_size_row;
+			if (softback_top == softback_end)
+				softback_top = softback_buf;
+		}
+	}
+	softback_curr = softback_in;
+}
+
+static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
+			int count)
+{
+	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct display *p = &fb_display[vc->vc_num];
+	struct fbcon_ops *ops = info->fbcon_par;
+	int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK;
+
+	if (fbcon_is_inactive(vc, info))
+		return -EINVAL;
+
+	fbcon_cursor(vc, CM_ERASE);
+
+	/*
+	 * ++Geert: Only use ywrap/ypan if the console is in text mode
+	 * ++Andrew: Only use ypan on hardware text mode when scrolling the
+	 *           whole screen (prevents flicker).
+	 */
+
+	switch (dir) {
+	case SM_UP:
+		if (count > vc->vc_rows)	/* Maximum realistic size */
+			count = vc->vc_rows;
+		if (softback_top)
+			fbcon_softback_note(vc, t, count);
+		if (logo_shown >= 0)
+			goto redraw_up;
+		switch (p->scrollmode) {
+		case SCROLL_MOVE:
+			ops->bmove(vc, info, t + count, 0, t, 0,
+				    b - t - count, vc->vc_cols);
+			ops->clear(vc, info, b - count, 0, count,
+				  vc->vc_cols);
+			break;
+
+		case SCROLL_WRAP_MOVE:
+			if (b - t - count > 3 * vc->vc_rows >> 2) {
+				if (t > 0)
+					fbcon_bmove(vc, 0, 0, count, 0, t,
+						    vc->vc_cols);
+				ywrap_up(vc, count);
+				if (vc->vc_rows - b > 0)
+					fbcon_bmove(vc, b - count, 0, b, 0,
+						    vc->vc_rows - b,
+						    vc->vc_cols);
+			} else if (info->flags & FBINFO_READS_FAST)
+				fbcon_bmove(vc, t + count, 0, t, 0,
+					    b - t - count, vc->vc_cols);
+			else
+				goto redraw_up;
+			fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+			break;
+
+		case SCROLL_PAN_REDRAW:
+			if ((p->yscroll + count <=
+			     2 * (p->vrows - vc->vc_rows))
+			    && ((!scroll_partial && (b - t == vc->vc_rows))
+				|| (scroll_partial
+				    && (b - t - count >
+					3 * vc->vc_rows >> 2)))) {
+				if (t > 0)
+					fbcon_redraw_move(vc, p, 0, t, count);
+				ypan_up_redraw(vc, t, count);
+				if (vc->vc_rows - b > 0)
+					fbcon_redraw_move(vc, p, b - count,
+							  vc->vc_rows - b, b);
+			} else
+				fbcon_redraw_move(vc, p, t + count, b - t - count, t);
+			fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+			break;
+
+		case SCROLL_PAN_MOVE:
+			if ((p->yscroll + count <=
+			     2 * (p->vrows - vc->vc_rows))
+			    && ((!scroll_partial && (b - t == vc->vc_rows))
+				|| (scroll_partial
+				    && (b - t - count >
+					3 * vc->vc_rows >> 2)))) {
+				if (t > 0)
+					fbcon_bmove(vc, 0, 0, count, 0, t,
+						    vc->vc_cols);
+				ypan_up(vc, count);
+				if (vc->vc_rows - b > 0)
+					fbcon_bmove(vc, b - count, 0, b, 0,
+						    vc->vc_rows - b,
+						    vc->vc_cols);
+			} else if (info->flags & FBINFO_READS_FAST)
+				fbcon_bmove(vc, t + count, 0, t, 0,
+					    b - t - count, vc->vc_cols);
+			else
+				goto redraw_up;
+			fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+			break;
+
+		case SCROLL_REDRAW:
+		      redraw_up:
+			fbcon_redraw(vc, p, t, b - t - count,
+				     count * vc->vc_cols);
+			fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+			scr_memsetw((unsigned short *) (vc->vc_origin +
+							vc->vc_size_row *
+							(b - count)),
+				    vc->vc_video_erase_char,
+				    vc->vc_size_row * count);
+			return 1;
+		}
+		break;
+
+	case SM_DOWN:
+		if (count > vc->vc_rows)	/* Maximum realistic size */
+			count = vc->vc_rows;
+		switch (p->scrollmode) {
+		case SCROLL_MOVE:
+			ops->bmove(vc, info, t, 0, t + count, 0,
+				    b - t - count, vc->vc_cols);
+			ops->clear(vc, info, t, 0, count, vc->vc_cols);
+			break;
+
+		case SCROLL_WRAP_MOVE:
+			if (b - t - count > 3 * vc->vc_rows >> 2) {
+				if (vc->vc_rows - b > 0)
+					fbcon_bmove(vc, b, 0, b - count, 0,
+						    vc->vc_rows - b,
+						    vc->vc_cols);
+				ywrap_down(vc, count);
+				if (t > 0)
+					fbcon_bmove(vc, count, 0, 0, 0, t,
+						    vc->vc_cols);
+			} else if (info->flags & FBINFO_READS_FAST)
+				fbcon_bmove(vc, t, 0, t + count, 0,
+					    b - t - count, vc->vc_cols);
+			else
+				goto redraw_down;
+			fbcon_clear(vc, t, 0, count, vc->vc_cols);
+			break;
+
+		case SCROLL_PAN_MOVE:
+			if ((count - p->yscroll <= p->vrows - vc->vc_rows)
+			    && ((!scroll_partial && (b - t == vc->vc_rows))
+				|| (scroll_partial
+				    && (b - t - count >
+					3 * vc->vc_rows >> 2)))) {
+				if (vc->vc_rows - b > 0)
+					fbcon_bmove(vc, b, 0, b - count, 0,
+						    vc->vc_rows - b,
+						    vc->vc_cols);
+				ypan_down(vc, count);
+				if (t > 0)
+					fbcon_bmove(vc, count, 0, 0, 0, t,
+						    vc->vc_cols);
+			} else if (info->flags & FBINFO_READS_FAST)
+				fbcon_bmove(vc, t, 0, t + count, 0,
+					    b - t - count, vc->vc_cols);
+			else
+				goto redraw_down;
+			fbcon_clear(vc, t, 0, count, vc->vc_cols);
+			break;
+
+		case SCROLL_PAN_REDRAW:
+			if ((count - p->yscroll <= p->vrows - vc->vc_rows)
+			    && ((!scroll_partial && (b - t == vc->vc_rows))
+				|| (scroll_partial
+				    && (b - t - count >
+					3 * vc->vc_rows >> 2)))) {
+				if (vc->vc_rows - b > 0)
+					fbcon_redraw_move(vc, p, b, vc->vc_rows - b,
+							  b - count);
+				ypan_down_redraw(vc, t, count);
+				if (t > 0)
+					fbcon_redraw_move(vc, p, count, t, 0);
+			} else
+				fbcon_redraw_move(vc, p, t, b - t - count, t + count);
+			fbcon_clear(vc, t, 0, count, vc->vc_cols);
+			break;
+
+		case SCROLL_REDRAW:
+		      redraw_down:
+			fbcon_redraw(vc, p, b - 1, b - t - count,
+				     -count * vc->vc_cols);
+			fbcon_clear(vc, t, 0, count, vc->vc_cols);
+			scr_memsetw((unsigned short *) (vc->vc_origin +
+							vc->vc_size_row *
+							t),
+				    vc->vc_video_erase_char,
+				    vc->vc_size_row * count);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+
+static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
+			int height, int width)
+{
+	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct display *p = &fb_display[vc->vc_num];
+	
+	if (fbcon_is_inactive(vc, info))
+		return;
+
+	if (!width || !height)
+		return;
+
+	/*  Split blits that cross physical y_wrap case.
+	 *  Pathological case involves 4 blits, better to use recursive
+	 *  code rather than unrolled case
+	 *
+	 *  Recursive invocations don't need to erase the cursor over and
+	 *  over again, so we use fbcon_bmove_rec()
+	 */
+	fbcon_bmove_rec(vc, p, sy, sx, dy, dx, height, width,
+			p->vrows - p->yscroll);
+}
+
+static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx, 
+			    int dy, int dx, int height, int width, u_int y_break)
+{
+	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct fbcon_ops *ops = info->fbcon_par;
+	u_int b;
+
+	if (sy < y_break && sy + height > y_break) {
+		b = y_break - sy;
+		if (dy < sy) {	/* Avoid trashing self */
+			fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
+					y_break);
+			fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
+					height - b, width, y_break);
+		} else {
+			fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
+					height - b, width, y_break);
+			fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
+					y_break);
+		}
+		return;
+	}
+
+	if (dy < y_break && dy + height > y_break) {
+		b = y_break - dy;
+		if (dy < sy) {	/* Avoid trashing self */
+			fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
+					y_break);
+			fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
+					height - b, width, y_break);
+		} else {
+			fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
+					height - b, width, y_break);
+			fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
+					y_break);
+		}
+		return;
+	}
+	ops->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx,
+		   height, width);
+}
+
+static __inline__ void updatescrollmode(struct display *p, struct fb_info *info,
+					struct vc_data *vc)
+{
+	int fh = vc->vc_font.height;
+	int cap = info->flags;
+	int good_pan = (cap & FBINFO_HWACCEL_YPAN)
+		 && divides(info->fix.ypanstep, vc->vc_font.height)
+		 && info->var.yres_virtual > info->var.yres;
+	int good_wrap = (cap & FBINFO_HWACCEL_YWRAP)
+		 && divides(info->fix.ywrapstep, vc->vc_font.height)
+		 && divides(vc->vc_font.height, info->var.yres_virtual);
+	int reading_fast = cap & FBINFO_READS_FAST;
+	int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) && !(cap & FBINFO_HWACCEL_DISABLED);
+	int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) && !(cap & FBINFO_HWACCEL_DISABLED);
+
+	p->vrows = info->var.yres_virtual/fh;
+	if (info->var.yres > (fh * (vc->vc_rows + 1)))
+		p->vrows -= (info->var.yres - (fh * vc->vc_rows)) / fh;
+	if ((info->var.yres % fh) && (info->var.yres_virtual % fh <
+				      info->var.yres % fh))
+		p->vrows--;
+
+	if (good_wrap || good_pan) {
+		if (reading_fast || fast_copyarea)
+			p->scrollmode = good_wrap ? SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE;
+		else
+			p->scrollmode = good_wrap ? SCROLL_REDRAW :
+				SCROLL_PAN_REDRAW;
+	} else {
+		if (reading_fast || (fast_copyarea && !fast_imageblit))
+			p->scrollmode = SCROLL_MOVE;
+		else
+			p->scrollmode = SCROLL_REDRAW;
+	}
+}
+
+static int fbcon_resize(struct vc_data *vc, unsigned int width, 
+			unsigned int height)
+{
+	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct display *p = &fb_display[vc->vc_num];
+	struct fb_var_screeninfo var = info->var;
+	int x_diff, y_diff;
+	int fw = vc->vc_font.width;
+	int fh = vc->vc_font.height;
+
+	var.xres = width * fw;
+	var.yres = height * fh;
+	x_diff = info->var.xres - var.xres;
+	y_diff = info->var.yres - var.yres;
+	if (x_diff < 0 || x_diff > fw || (y_diff < 0 || y_diff > fh)) {
+		struct fb_videomode *mode;
+
+		DPRINTK("attempting resize %ix%i\n", var.xres, var.yres);
+		mode = fb_find_best_mode(&var, &info->modelist);
+		if (mode == NULL)
+			return -EINVAL;
+		fb_videomode_to_var(&var, mode);
+		if (width > var.xres/fw || height > var.yres/fh)
+			return -EINVAL;
+		/*
+		 * The following can probably have any value... Do we need to
+		 * set all of them?
+		 */
+		var.bits_per_pixel = p->bits_per_pixel;
+		var.xres_virtual = p->xres_virtual;
+		var.yres_virtual = p->yres_virtual;
+		var.accel_flags = p->accel_flags;
+		var.width = p->width;
+		var.height = p->height;
+		var.red = p->red;
+		var.green = p->green;
+		var.blue = p->blue;
+		var.transp = p->transp;
+		var.nonstd = p->nonstd;
+
+		DPRINTK("resize now %ix%i\n", var.xres, var.yres);
+		if (CON_IS_VISIBLE(vc)) {
+			var.activate = FB_ACTIVATE_NOW |
+				FB_ACTIVATE_FORCE;
+			fb_set_var(info, &var);
+		}
+		var_to_display(p, &info->var, info);
+	}
+	updatescrollmode(p, info, vc);
+	return 0;
+}
+
+static int fbcon_switch(struct vc_data *vc)
+{
+	struct fb_info *info;
+	struct display *p = &fb_display[vc->vc_num];
+	struct fb_var_screeninfo var;
+	int i, prev_console;
+
+	info = registered_fb[con2fb_map[vc->vc_num]];
+
+	if (softback_top) {
+		int l = fbcon_softback_size / vc->vc_size_row;
+		if (softback_lines)
+			fbcon_set_origin(vc);
+		softback_top = softback_curr = softback_in = softback_buf;
+		softback_lines = 0;
+
+		if (l > 5)
+			softback_end = softback_buf + l * vc->vc_size_row;
+		else {
+			/* Smaller scrollback makes no sense, and 0 would screw
+			   the operation totally */
+			softback_top = 0;
+		}
+	}
+
+	if (logo_shown >= 0) {
+		struct vc_data *conp2 = vc_cons[logo_shown].d;
+
+		if (conp2->vc_top == logo_lines
+		    && conp2->vc_bottom == conp2->vc_rows)
+			conp2->vc_top = 0;
+		logo_shown = FBCON_LOGO_CANSHOW;
+	}
+
+	prev_console = ((struct fbcon_ops *)info->fbcon_par)->currcon;
+
+	/*
+	 * FIXME: If we have multiple fbdev's loaded, we need to
+	 * update all info->currcon.  Perhaps, we can place this
+	 * in a centralized structure, but this might break some
+	 * drivers.
+	 *
+	 * info->currcon = vc->vc_num;
+	 */
+	for (i = 0; i < FB_MAX; i++) {
+		if (registered_fb[i] != NULL && registered_fb[i]->fbcon_par) {
+			struct fbcon_ops *ops = registered_fb[i]->fbcon_par;
+
+			ops->currcon = vc->vc_num;
+		}
+	}
+	memset(&var, 0, sizeof(struct fb_var_screeninfo));
+	display_to_var(&var, p);
+	var.activate = FB_ACTIVATE_NOW;
+
+	/*
+	 * make sure we don't unnecessarily trip the memcmp()
+	 * in fb_set_var()
+	 */
+	info->var.activate = var.activate;
+	info->var.yoffset = info->var.xoffset = p->yscroll = 0;
+	fb_set_var(info, &var);
+
+	if (prev_console != -1 &&
+	    registered_fb[con2fb_map[prev_console]] != info &&
+	    info->fbops->fb_set_par)
+		info->fbops->fb_set_par(info);
+
+	set_blitting_type(vc, info, p);
+	((struct fbcon_ops *)info->fbcon_par)->cursor_reset = 1;
+
+	vc->vc_can_do_color = (fb_get_color_depth(&info->var) != 1);
+	vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
+	updatescrollmode(p, info, vc);
+
+	switch (p->scrollmode) {
+	case SCROLL_WRAP_MOVE:
+		scrollback_phys_max = p->vrows - vc->vc_rows;
+		break;
+	case SCROLL_PAN_MOVE:
+	case SCROLL_PAN_REDRAW:
+		scrollback_phys_max = p->vrows - 2 * vc->vc_rows;
+		if (scrollback_phys_max < 0)
+			scrollback_phys_max = 0;
+		break;
+	default:
+		scrollback_phys_max = 0;
+		break;
+	}
+	scrollback_max = 0;
+	scrollback_current = 0;
+
+	update_var(vc->vc_num, info);
+	fbcon_set_palette(vc, color_table); 	
+	fbcon_clear_margins(vc, 0);
+
+	if (logo_shown == FBCON_LOGO_DRAW) {
+
+		logo_shown = fg_console;
+		/* This is protected above by initmem_freed */
+		fb_show_logo(info);
+		update_region(vc,
+			      vc->vc_origin + vc->vc_size_row * vc->vc_top,
+			      vc->vc_size_row * (vc->vc_bottom -
+						 vc->vc_top) / 2);
+		return 0;
+	}
+	return 1;
+}
+
+static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info,
+				int blank)
+{
+	if (blank) {
+		unsigned short charmask = vc->vc_hi_font_mask ?
+			0x1ff : 0xff;
+		unsigned short oldc;
+
+		oldc = vc->vc_video_erase_char;
+		vc->vc_video_erase_char &= charmask;
+		fbcon_clear(vc, 0, 0, vc->vc_rows, vc->vc_cols);
+		vc->vc_video_erase_char = oldc;
+	}
+}
+
+static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
+{
+	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct fbcon_ops *ops = info->fbcon_par;
+
+	if (mode_switch) {
+		struct fb_var_screeninfo var = info->var;
+
+		ops->graphics = 1;
+
+		if (!blank) {
+			var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
+			fb_set_var(info, &var);
+			ops->graphics = 0;
+		}
+	}
+
+ 	if (!fbcon_is_inactive(vc, info)) {
+		if (ops->blank_state != blank) {
+			ops->blank_state = blank;
+			fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW);
+			ops->cursor_flash = (!blank);
+
+			if (fb_blank(info, blank))
+				fbcon_generic_blank(vc, info, blank);
+		}
+
+ 		if (!blank)
+ 			update_screen(vc);
+ 	}
+
+ 	return 0;
+}
+
+static void fbcon_free_font(struct display *p)
+{
+	if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0))
+		kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int));
+	p->fontdata = NULL;
+	p->userfont = 0;
+}
+
+static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
+{
+	u8 *fontdata = vc->vc_font.data;
+	u8 *data = font->data;
+	int i, j;
+
+	font->width = vc->vc_font.width;
+	font->height = vc->vc_font.height;
+	font->charcount = vc->vc_hi_font_mask ? 512 : 256;
+	if (!font->data)
+		return 0;
+
+	if (font->width <= 8) {
+		j = vc->vc_font.height;
+		for (i = 0; i < font->charcount; i++) {
+			memcpy(data, fontdata, j);
+			memset(data + j, 0, 32 - j);
+			data += 32;
+			fontdata += j;
+		}
+	} else if (font->width <= 16) {
+		j = vc->vc_font.height * 2;
+		for (i = 0; i < font->charcount; i++) {
+			memcpy(data, fontdata, j);
+			memset(data + j, 0, 64 - j);
+			data += 64;
+			fontdata += j;
+		}
+	} else if (font->width <= 24) {
+		for (i = 0; i < font->charcount; i++) {
+			for (j = 0; j < vc->vc_font.height; j++) {
+				*data++ = fontdata[0];
+				*data++ = fontdata[1];
+				*data++ = fontdata[2];
+				fontdata += sizeof(u32);
+			}
+			memset(data, 0, 3 * (32 - j));
+			data += 3 * (32 - j);
+		}
+	} else {
+		j = vc->vc_font.height * 4;
+		for (i = 0; i < font->charcount; i++) {
+			memcpy(data, fontdata, j);
+			memset(data + j, 0, 128 - j);
+			data += 128;
+			fontdata += j;
+		}
+	}
+	return 0;
+}
+
+static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
+			     u8 * data, int userfont)
+{
+	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct display *p = &fb_display[vc->vc_num];
+	int resize;
+	int cnt;
+	char *old_data = NULL;
+
+	if (CON_IS_VISIBLE(vc) && softback_lines)
+		fbcon_set_origin(vc);
+
+	resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
+	if (p->userfont)
+		old_data = vc->vc_font.data;
+	if (userfont)
+		cnt = FNTCHARCNT(data);
+	else
+		cnt = 256;
+	vc->vc_font.data = p->fontdata = data;
+	if ((p->userfont = userfont))
+		REFCOUNT(data)++;
+	vc->vc_font.width = w;
+	vc->vc_font.height = h;
+	if (vc->vc_hi_font_mask && cnt == 256) {
+		vc->vc_hi_font_mask = 0;
+		if (vc->vc_can_do_color) {
+			vc->vc_complement_mask >>= 1;
+			vc->vc_s_complement_mask >>= 1;
+		}
+			
+		/* ++Edmund: reorder the attribute bits */
+		if (vc->vc_can_do_color) {
+			unsigned short *cp =
+			    (unsigned short *) vc->vc_origin;
+			int count = vc->vc_screenbuf_size / 2;
+			unsigned short c;
+			for (; count > 0; count--, cp++) {
+				c = scr_readw(cp);
+				scr_writew(((c & 0xfe00) >> 1) |
+					   (c & 0xff), cp);
+			}
+			c = vc->vc_video_erase_char;
+			vc->vc_video_erase_char =
+			    ((c & 0xfe00) >> 1) | (c & 0xff);
+			vc->vc_attr >>= 1;
+		}
+	} else if (!vc->vc_hi_font_mask && cnt == 512) {
+		vc->vc_hi_font_mask = 0x100;
+		if (vc->vc_can_do_color) {
+			vc->vc_complement_mask <<= 1;
+			vc->vc_s_complement_mask <<= 1;
+		}
+			
+		/* ++Edmund: reorder the attribute bits */
+		{
+			unsigned short *cp =
+			    (unsigned short *) vc->vc_origin;
+			int count = vc->vc_screenbuf_size / 2;
+			unsigned short c;
+			for (; count > 0; count--, cp++) {
+				unsigned short newc;
+				c = scr_readw(cp);
+				if (vc->vc_can_do_color)
+					newc =
+					    ((c & 0xff00) << 1) | (c &
+								   0xff);
+				else
+					newc = c & ~0x100;
+				scr_writew(newc, cp);
+			}
+			c = vc->vc_video_erase_char;
+			if (vc->vc_can_do_color) {
+				vc->vc_video_erase_char =
+				    ((c & 0xff00) << 1) | (c & 0xff);
+				vc->vc_attr <<= 1;
+			} else
+				vc->vc_video_erase_char = c & ~0x100;
+		}
+
+	}
+
+	if (resize) {
+		/* reset wrap/pan */
+		info->var.xoffset = info->var.yoffset = p->yscroll = 0;
+		vc_resize(vc, info->var.xres / w, info->var.yres / h);
+		if (CON_IS_VISIBLE(vc) && softback_buf) {
+			int l = fbcon_softback_size / vc->vc_size_row;
+			if (l > 5)
+				softback_end =
+				    softback_buf + l * vc->vc_size_row;
+			else {
+				/* Smaller scrollback makes no sense, and 0 would screw
+				   the operation totally */
+				softback_top = 0;
+			}
+		}
+	} else if (CON_IS_VISIBLE(vc)
+		   && vc->vc_mode == KD_TEXT) {
+		fbcon_clear_margins(vc, 0);
+		update_screen(vc);
+	}
+
+	if (old_data && (--REFCOUNT(old_data) == 0))
+		kfree(old_data - FONT_EXTRA_WORDS * sizeof(int));
+	return 0;
+}
+
+static int fbcon_copy_font(struct vc_data *vc, int con)
+{
+	struct display *od = &fb_display[con];
+	struct console_font *f = &vc->vc_font;
+
+	if (od->fontdata == f->data)
+		return 0;	/* already the same font... */
+	return fbcon_do_set_font(vc, f->width, f->height, od->fontdata, od->userfont);
+}
+
+/*
+ *  User asked to set font; we are guaranteed that
+ *	a) width and height are in range 1..32
+ *	b) charcount does not exceed 512
+ *  but lets not assume that, since someone might someday want to use larger
+ *  fonts. And charcount of 512 is small for unicode support.
+ *
+ *  However, user space gives the font in 32 rows , regardless of
+ *  actual font height. So a new API is needed if support for larger fonts
+ *  is ever implemented.
+ */
+
+static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigned flags)
+{
+	unsigned charcount = font->charcount;
+	int w = font->width;
+	int h = font->height;
+	int size;
+	int i, csum;
+	u8 *new_data, *data = font->data;
+	int pitch = (font->width+7) >> 3;
+
+	/* Is there a reason why fbconsole couldn't handle any charcount >256?
+	 * If not this check should be changed to charcount < 256 */
+	if (charcount != 256 && charcount != 512)
+		return -EINVAL;
+
+	size = h * pitch * charcount;
+
+	new_data = kmalloc(FONT_EXTRA_WORDS * sizeof(int) + size, GFP_USER);
+
+	if (!new_data)
+		return -ENOMEM;
+
+	new_data += FONT_EXTRA_WORDS * sizeof(int);
+	FNTSIZE(new_data) = size;
+	FNTCHARCNT(new_data) = charcount;
+	REFCOUNT(new_data) = 0;	/* usage counter */
+	for (i=0; i< charcount; i++) {
+		memcpy(new_data + i*h*pitch, data +  i*32*pitch, h*pitch);
+	}
+
+	/* Since linux has a nice crc32 function use it for counting font
+	 * checksums. */
+	csum = crc32(0, new_data, size);
+
+	FNTSUM(new_data) = csum;
+	/* Check if the same font is on some other console already */
+	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+		struct vc_data *tmp = vc_cons[i].d;
+		
+		if (fb_display[i].userfont &&
+		    fb_display[i].fontdata &&
+		    FNTSUM(fb_display[i].fontdata) == csum &&
+		    FNTSIZE(fb_display[i].fontdata) == size &&
+		    tmp->vc_font.width == w &&
+		    !memcmp(fb_display[i].fontdata, new_data, size)) {
+			kfree(new_data - FONT_EXTRA_WORDS * sizeof(int));
+			new_data = fb_display[i].fontdata;
+			break;
+		}
+	}
+	return fbcon_do_set_font(vc, font->width, font->height, new_data, 1);
+}
+
+static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font, char *name)
+{
+	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	struct font_desc *f;
+
+	if (!name)
+		f = get_default_font(info->var.xres, info->var.yres);
+	else if (!(f = find_font(name)))
+		return -ENOENT;
+
+	font->width = f->width;
+	font->height = f->height;
+	return fbcon_do_set_font(vc, f->width, f->height, f->data, 0);
+}
+
+static u16 palette_red[16];
+static u16 palette_green[16];
+static u16 palette_blue[16];
+
+static struct fb_cmap palette_cmap = {
+	0, 16, palette_red, palette_green, palette_blue, NULL
+};
+
+static int fbcon_set_palette(struct vc_data *vc, unsigned char *table)
+{
+	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+	int i, j, k, depth;
+	u8 val;
+
+	if (fbcon_is_inactive(vc, info))
+		return -EINVAL;
+
+	if (!CON_IS_VISIBLE(vc))
+		return 0;
+
+	depth = fb_get_color_depth(&info->var);
+	if (depth > 3) {
+		for (i = j = 0; i < 16; i++) {
+			k = table[i];
+			val = vc->vc_palette[j++];
+			palette_red[k] = (val << 8) | val;
+			val = vc->vc_palette[j++];
+			palette_green[k] = (val << 8) | val;
+			val = vc->vc_palette[j++];
+			palette_blue[k] = (val << 8) | val;
+		}
+		palette_cmap.len = 16;
+		palette_cmap.start = 0;
+	/*
+	 * If framebuffer is capable of less than 16 colors,
+	 * use default palette of fbcon.
+	 */
+	} else
+		fb_copy_cmap(fb_default_cmap(1 << depth), &palette_cmap);
+
+	return fb_set_cmap(&palette_cmap, info);
+}
+
+static u16 *fbcon_screen_pos(struct vc_data *vc, int offset)
+{
+	unsigned long p;
+	int line;
+	
+	if (vc->vc_num != fg_console || !softback_lines)
+		return (u16 *) (vc->vc_origin + offset);
+	line = offset / vc->vc_size_row;
+	if (line >= softback_lines)
+		return (u16 *) (vc->vc_origin + offset -
+				softback_lines * vc->vc_size_row);
+	p = softback_curr + offset;
+	if (p >= softback_end)
+		p += softback_buf - softback_end;
+	return (u16 *) p;
+}
+
+static unsigned long fbcon_getxy(struct vc_data *vc, unsigned long pos,
+				 int *px, int *py)
+{
+	unsigned long ret;
+	int x, y;
+
+	if (pos >= vc->vc_origin && pos < vc->vc_scr_end) {
+		unsigned long offset = (pos - vc->vc_origin) / 2;
+
+		x = offset % vc->vc_cols;
+		y = offset / vc->vc_cols;
+		if (vc->vc_num == fg_console)
+			y += softback_lines;
+		ret = pos + (vc->vc_cols - x) * 2;
+	} else if (vc->vc_num == fg_console && softback_lines) {
+		unsigned long offset = pos - softback_curr;
+
+		if (pos < softback_curr)
+			offset += softback_end - softback_buf;
+		offset /= 2;
+		x = offset % vc->vc_cols;
+		y = offset / vc->vc_cols;
+		ret = pos + (vc->vc_cols - x) * 2;
+		if (ret == softback_end)
+			ret = softback_buf;
+		if (ret == softback_in)
+			ret = vc->vc_origin;
+	} else {
+		/* Should not happen */
+		x = y = 0;
+		ret = vc->vc_origin;
+	}
+	if (px)
+		*px = x;
+	if (py)
+		*py = y;
+	return ret;
+}
+
+/* As we might be inside of softback, we may work with non-contiguous buffer,
+   that's why we have to use a separate routine. */
+static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt)
+{
+	while (cnt--) {
+		u16 a = scr_readw(p);
+		if (!vc->vc_can_do_color)
+			a ^= 0x0800;
+		else if (vc->vc_hi_font_mask == 0x100)
+			a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) |
+			    (((a) & 0x0e00) << 4);
+		else
+			a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
+			    (((a) & 0x0700) << 4);
+		scr_writew(a, p++);
+		if (p == (u16 *) softback_end)
+			p = (u16 *) softback_buf;
+		if (p == (u16 *) softback_in)
+			p = (u16 *) vc->vc_origin;
+	}
+}
+
+static int fbcon_scrolldelta(struct vc_data *vc, int lines)
+{
+	struct fb_info *info = registered_fb[con2fb_map[fg_console]];
+	struct display *p = &fb_display[fg_console];
+	int offset, limit, scrollback_old;
+
+	if (softback_top) {
+		if (vc->vc_num != fg_console)
+			return 0;
+		if (vc->vc_mode != KD_TEXT || !lines)
+			return 0;
+		if (logo_shown >= 0) {
+			struct vc_data *conp2 = vc_cons[logo_shown].d;
+
+			if (conp2->vc_top == logo_lines
+			    && conp2->vc_bottom == conp2->vc_rows)
+				conp2->vc_top = 0;
+			if (logo_shown == vc->vc_num) {
+				unsigned long p, q;
+				int i;
+
+				p = softback_in;
+				q = vc->vc_origin +
+				    logo_lines * vc->vc_size_row;
+				for (i = 0; i < logo_lines; i++) {
+					if (p == softback_top)
+						break;
+					if (p == softback_buf)
+						p = softback_end;
+					p -= vc->vc_size_row;
+					q -= vc->vc_size_row;
+					scr_memcpyw((u16 *) q, (u16 *) p,
+						    vc->vc_size_row);
+				}
+				softback_in = p;
+				update_region(vc, vc->vc_origin,
+					      logo_lines * vc->vc_cols);
+			}
+			logo_shown = FBCON_LOGO_CANSHOW;
+		}
+		fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK);
+		fbcon_redraw_softback(vc, p, lines);
+		fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK);
+		return 0;
+	}
+
+	if (!scrollback_phys_max)
+		return -ENOSYS;
+
+	scrollback_old = scrollback_current;
+	scrollback_current -= lines;
+	if (scrollback_current < 0)
+		scrollback_current = 0;
+	else if (scrollback_current > scrollback_max)
+		scrollback_current = scrollback_max;
+	if (scrollback_current == scrollback_old)
+		return 0;
+
+	if (fbcon_is_inactive(vc, info))
+		return 0;
+
+	fbcon_cursor(vc, CM_ERASE);
+
+	offset = p->yscroll - scrollback_current;
+	limit = p->vrows;
+	switch (p->scrollmode) {
+	case SCROLL_WRAP_MOVE:
+		info->var.vmode |= FB_VMODE_YWRAP;
+		break;
+	case SCROLL_PAN_MOVE:
+	case SCROLL_PAN_REDRAW:
+		limit -= vc->vc_rows;
+		info->var.vmode &= ~FB_VMODE_YWRAP;
+		break;
+	}
+	if (offset < 0)
+		offset += limit;
+	else if (offset >= limit)
+		offset -= limit;
+	info->var.xoffset = 0;
+	info->var.yoffset = offset * vc->vc_font.height;
+	update_var(vc->vc_num, info);
+	if (!scrollback_current)
+		fbcon_cursor(vc, CM_DRAW);
+	return 0;
+}
+
+static int fbcon_set_origin(struct vc_data *vc)
+{
+	if (softback_lines)
+		fbcon_scrolldelta(vc, softback_lines);
+	return 0;
+}
+
+static void fbcon_suspended(struct fb_info *info)
+{
+	struct vc_data *vc = NULL;
+	struct fbcon_ops *ops = info->fbcon_par;
+
+	if (!ops || ops->currcon < 0)
+		return;
+	vc = vc_cons[ops->currcon].d;
+
+	/* Clear cursor, restore saved data */
+	fbcon_cursor(vc, CM_ERASE);
+}
+
+static void fbcon_resumed(struct fb_info *info)
+{
+	struct vc_data *vc;
+	struct fbcon_ops *ops = info->fbcon_par;
+
+	if (!ops || ops->currcon < 0)
+		return;
+	vc = vc_cons[ops->currcon].d;
+
+	update_screen(vc);
+}
+
+static void fbcon_modechanged(struct fb_info *info)
+{
+	struct fbcon_ops *ops = info->fbcon_par;
+	struct vc_data *vc;
+	struct display *p;
+	int rows, cols;
+
+	if (!ops || ops->currcon < 0)
+		return;
+	vc = vc_cons[ops->currcon].d;
+	if (vc->vc_mode != KD_TEXT || registered_fb[con2fb_map[ops->currcon]] != info)
+		return;
+
+	p = &fb_display[vc->vc_num];
+
+	info->var.xoffset = info->var.yoffset = p->yscroll = 0;
+
+	if (CON_IS_VISIBLE(vc)) {
+		var_to_display(p, &info->var, info);
+		cols = info->var.xres / vc->vc_font.width;
+		rows = info->var.yres / vc->vc_font.height;
+		vc_resize(vc, cols, rows);
+		updatescrollmode(p, info, vc);
+		scrollback_max = 0;
+		scrollback_current = 0;
+		update_var(vc->vc_num, info);
+		fbcon_set_palette(vc, color_table);
+		update_screen(vc);
+		if (softback_buf) {
+			int l = fbcon_softback_size / vc->vc_size_row;
+			if (l > 5)
+				softback_end = softback_buf + l * vc->vc_size_row;
+			else {
+				/* Smaller scrollback makes no sense, and 0
+				   would screw the operation totally */
+				softback_top = 0;
+			}
+		}
+	}
+}
+
+static int fbcon_mode_deleted(struct fb_info *info,
+			      struct fb_videomode *mode)
+{
+	struct fb_info *fb_info;
+	struct display *p;
+	int i, j, found = 0;
+
+	/* before deletion, ensure that mode is not in use */
+	for (i = first_fb_vc; i <= last_fb_vc; i++) {
+		j = con2fb_map[i];
+		if (j == -1)
+			continue;
+		fb_info = registered_fb[j];
+		if (fb_info != info)
+			continue;
+		p = &fb_display[i];
+		if (!p || !p->mode)
+			continue;
+		if (fb_mode_is_equal(p->mode, mode)) {
+			found = 1;
+			break;
+		}
+	}
+	return found;
+}
+
+static int fbcon_fb_registered(int idx)
+{
+	int ret = 0, i;
+
+	if (info_idx == -1) {
+		for (i = 0; i < MAX_NR_CONSOLES; i++) {
+			if (con2fb_map_boot[i] == idx) {
+				info_idx = idx;
+				break;
+			}
+		}
+		if (info_idx != -1)
+			ret = fbcon_takeover(1);
+	} else {
+		for (i = 0; i < MAX_NR_CONSOLES; i++) {
+			if (con2fb_map_boot[i] == idx)
+				set_con2fb_map(i, idx, 0);
+		}
+	}
+
+	return ret;
+}
+
+static void fbcon_fb_blanked(struct fb_info *info, int blank)
+{
+	struct fbcon_ops *ops = info->fbcon_par;
+	struct vc_data *vc;
+
+	if (!ops || ops->currcon < 0)
+		return;
+
+	vc = vc_cons[ops->currcon].d;
+	if (vc->vc_mode != KD_TEXT ||
+			registered_fb[con2fb_map[ops->currcon]] != info)
+		return;
+
+	if (CON_IS_VISIBLE(vc)) {
+		if (blank)
+			do_blank_screen(0);
+		else
+			do_unblank_screen(0);
+	}
+	ops->blank_state = blank;
+}
+
+static void fbcon_new_modelist(struct fb_info *info)
+{
+	int i;
+	struct vc_data *vc;
+	struct fb_var_screeninfo var;
+	struct fb_videomode *mode;
+
+	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+		if (registered_fb[con2fb_map[i]] != info)
+			continue;
+		if (!fb_display[i].mode)
+			continue;
+		vc = vc_cons[i].d;
+		display_to_var(&var, &fb_display[i]);
+		mode = fb_find_nearest_mode(&var, &info->modelist);
+		fb_videomode_to_var(&var, mode);
+
+		if (vc)
+			fbcon_set_disp(info, &var, vc);
+		else
+			fbcon_preset_disp(info, &var, i);
+
+	}
+}
+
+static int fbcon_event_notify(struct notifier_block *self, 
+			      unsigned long action, void *data)
+{
+	struct fb_event *event = data;
+	struct fb_info *info = event->info;
+	struct fb_videomode *mode;
+	struct fb_con2fbmap *con2fb;
+	int ret = 0;
+
+	switch(action) {
+	case FB_EVENT_SUSPEND:
+		fbcon_suspended(info);
+		break;
+	case FB_EVENT_RESUME:
+		fbcon_resumed(info);
+		break;
+	case FB_EVENT_MODE_CHANGE:
+		fbcon_modechanged(info);
+		break;
+	case FB_EVENT_MODE_DELETE:
+		mode = event->data;
+		ret = fbcon_mode_deleted(info, mode);
+		break;
+	case FB_EVENT_FB_REGISTERED:
+		ret = fbcon_fb_registered(info->node);
+		break;
+	case FB_EVENT_SET_CONSOLE_MAP:
+		con2fb = event->data;
+		ret = set_con2fb_map(con2fb->console - 1,
+				     con2fb->framebuffer, 1);
+		break;
+	case FB_EVENT_GET_CONSOLE_MAP:
+		con2fb = event->data;
+		con2fb->framebuffer = con2fb_map[con2fb->console - 1];
+		break;
+	case FB_EVENT_BLANK:
+		fbcon_fb_blanked(info, *(int *)event->data);
+		break;
+	case FB_EVENT_NEW_MODELIST:
+		fbcon_new_modelist(info);
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ *  The console `switch' structure for the frame buffer based console
+ */
+
+static const struct consw fb_con = {
+	.owner			= THIS_MODULE,
+	.con_startup 		= fbcon_startup,
+	.con_init 		= fbcon_init,
+	.con_deinit 		= fbcon_deinit,
+	.con_clear 		= fbcon_clear,
+	.con_putc 		= fbcon_putc,
+	.con_putcs 		= fbcon_putcs,
+	.con_cursor 		= fbcon_cursor,
+	.con_scroll 		= fbcon_scroll,
+	.con_bmove 		= fbcon_bmove,
+	.con_switch 		= fbcon_switch,
+	.con_blank 		= fbcon_blank,
+	.con_font_set 		= fbcon_set_font,
+	.con_font_get 		= fbcon_get_font,
+	.con_font_default	= fbcon_set_def_font,
+	.con_font_copy 		= fbcon_copy_font,
+	.con_set_palette 	= fbcon_set_palette,
+	.con_scrolldelta 	= fbcon_scrolldelta,
+	.con_set_origin 	= fbcon_set_origin,
+	.con_invert_region 	= fbcon_invert_region,
+	.con_screen_pos 	= fbcon_screen_pos,
+	.con_getxy 		= fbcon_getxy,
+	.con_resize             = fbcon_resize,
+};
+
+static struct notifier_block fbcon_event_notifier = {
+	.notifier_call	= fbcon_event_notify,
+};
+
+static int __init fb_console_init(void)
+{
+	int i;
+
+	acquire_console_sem();
+	fb_register_client(&fbcon_event_notifier);
+	release_console_sem();
+
+	for (i = 0; i < MAX_NR_CONSOLES; i++)
+		con2fb_map[i] = -1;
+
+	if (num_registered_fb) {
+		for (i = 0; i < FB_MAX; i++) {
+			if (registered_fb[i] != NULL) {
+				info_idx = i;
+				break;
+			}
+		}
+		fbcon_takeover(0);
+	}
+
+	return 0;
+}
+
+module_init(fb_console_init);
+
+#ifdef MODULE
+
+static void __exit fb_console_exit(void)
+{
+	acquire_console_sem();
+	fb_unregister_client(&fbcon_event_notifier);
+	release_console_sem();
+	give_up_console(&fb_con);
+}	
+
+module_exit(fb_console_exit);
+
+#endif
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h
new file mode 100644
index 0000000..5d37786
--- /dev/null
+++ b/drivers/video/console/fbcon.h
@@ -0,0 +1,170 @@
+/*
+ *  linux/drivers/video/console/fbcon.h -- Low level frame buffer based console driver
+ *
+ *	Copyright (C) 1997 Geert Uytterhoeven
+ *
+ *  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 _VIDEO_FBCON_H
+#define _VIDEO_FBCON_H
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/vt_buffer.h>
+#include <linux/vt_kern.h>
+
+#include <asm/io.h>
+
+#define FBCON_FLAGS_INIT 1
+
+   /*
+    *    This is the interface between the low-level console driver and the
+    *    low-level frame buffer device
+    */
+
+struct display {
+    /* Filled in by the frame buffer device */
+    u_short inverse;                /* != 0 text black on white as default */
+    /* Filled in by the low-level console driver */
+    u_char *fontdata;
+    int userfont;                   /* != 0 if fontdata kmalloc()ed */
+    u_short scrollmode;             /* Scroll Method */
+    short yscroll;                  /* Hardware scrolling */
+    int vrows;                      /* number of virtual rows */
+    int cursor_shape;
+    u32 xres_virtual;
+    u32 yres_virtual;
+    u32 height;
+    u32 width;
+    u32 bits_per_pixel;
+    u32 grayscale;
+    u32 nonstd;
+    u32 accel_flags;
+    u32 rotate;
+    struct fb_bitfield red;
+    struct fb_bitfield green;
+    struct fb_bitfield blue;
+    struct fb_bitfield transp;
+    struct fb_videomode *mode;
+};
+
+struct fbcon_ops {
+	void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy,
+		      int sx, int dy, int dx, int height, int width);
+	void (*clear)(struct vc_data *vc, struct fb_info *info, int sy,
+		      int sx, int height, int width);
+	void (*putcs)(struct vc_data *vc, struct fb_info *info,
+		      const unsigned short *s, int count, int yy, int xx,
+		      int fg, int bg);
+	void (*clear_margins)(struct vc_data *vc, struct fb_info *info,
+			      int bottom_only);
+	void (*cursor)(struct vc_data *vc, struct fb_info *info,
+		       struct display *p, int mode, int softback_lines, int fg, int bg);
+
+	struct timer_list cursor_timer; /* Cursor timer */
+	struct fb_cursor cursor_state;
+        int    currcon;	                /* Current VC. */
+	int    cursor_flash;
+	int    cursor_reset;
+	int    blank_state;
+	int    graphics;
+	int    flags;
+	char  *cursor_data;
+};
+    /*
+     *  Attribute Decoding
+     */
+
+/* Color */
+#define attr_fgcol(fgshift,s)    \
+	(((s) >> (fgshift)) & 0x0f)
+#define attr_bgcol(bgshift,s)    \
+	(((s) >> (bgshift)) & 0x0f)
+#define	attr_bgcol_ec(bgshift,vc) \
+	((vc) ? (((vc)->vc_video_erase_char >> (bgshift)) & 0x0f) : 0)
+#define attr_fgcol_ec(fgshift,vc) \
+	((vc) ? (((vc)->vc_video_erase_char >> (fgshift)) & 0x0f) : 0)
+
+/* Monochrome */
+#define attr_bold(s) \
+	((s) & 0x200)
+#define attr_reverse(s) \
+	((s) & 0x800)
+#define attr_underline(s) \
+	((s) & 0x400)
+#define attr_blink(s) \
+	((s) & 0x8000)
+	
+/* Font */
+#define REFCOUNT(fd)	(((int *)(fd))[-1])
+#define FNTSIZE(fd)	(((int *)(fd))[-2])
+#define FNTCHARCNT(fd)	(((int *)(fd))[-3])
+#define FNTSUM(fd)	(((int *)(fd))[-4])
+#define FONT_EXTRA_WORDS 4
+
+    /*
+     *  Scroll Method
+     */
+     
+/* There are several methods fbcon can use to move text around the screen:
+ *
+ *                     Operation   Pan    Wrap
+ *---------------------------------------------
+ * SCROLL_MOVE         copyarea    No     No
+ * SCROLL_PAN_MOVE     copyarea    Yes    No
+ * SCROLL_WRAP_MOVE    copyarea    No     Yes
+ * SCROLL_REDRAW       imageblit   No     No
+ * SCROLL_PAN_REDRAW   imageblit   Yes    No
+ * SCROLL_WRAP_REDRAW  imageblit   No     Yes
+ *
+ * (SCROLL_WRAP_REDRAW is not implemented yet)
+ *
+ * In general, fbcon will choose the best scrolling
+ * method based on the rule below:
+ *
+ * Pan/Wrap > accel imageblit > accel copyarea >
+ * soft imageblit > (soft copyarea)
+ *
+ * Exception to the rule: Pan + accel copyarea is
+ * preferred over Pan + accel imageblit.
+ *
+ * The above is typical for PCI/AGP cards. Unless
+ * overridden, fbcon will never use soft copyarea.
+ *
+ * If you need to override the above rule, set the
+ * appropriate flags in fb_info->flags.  For example,
+ * to prefer copyarea over imageblit, set
+ * FBINFO_READS_FAST.
+ *
+ * Other notes:
+ * + use the hardware engine to move the text
+ *    (hw-accelerated copyarea() and fillrect())
+ * + use hardware-supported panning on a large virtual screen
+ * + amifb can not only pan, but also wrap the display by N lines
+ *    (i.e. visible line i = physical line (i+N) % yres).
+ * + read what's already rendered on the screen and
+ *     write it in a different place (this is cfb_copyarea())
+ * + re-render the text to the screen
+ *
+ * Whether to use wrapping or panning can only be figured out at
+ * runtime (when we know whether our font height is a multiple
+ * of the pan/wrap step)
+ *
+ */
+
+#define SCROLL_MOVE	   0x001
+#define SCROLL_PAN_MOVE	   0x002
+#define SCROLL_WRAP_MOVE   0x003
+#define SCROLL_REDRAW	   0x004
+#define SCROLL_PAN_REDRAW  0x005
+
+#ifdef CONFIG_FB_TILEBLITTING
+extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info,
+			      struct display *p, struct fbcon_ops *ops);
+#endif
+extern void fbcon_set_bitops(struct fbcon_ops *ops);
+
+#endif /* _VIDEO_FBCON_H */
diff --git a/drivers/video/console/font_6x11.c b/drivers/video/console/font_6x11.c
new file mode 100644
index 0000000..c52f129
--- /dev/null
+++ b/drivers/video/console/font_6x11.c
@@ -0,0 +1,3351 @@
+/**********************************************/
+/*                                            */
+/*       Font file generated by rthelen       */
+/*                                            */
+/**********************************************/
+
+#include <linux/font.h>
+
+#define FONTDATAMAX (11*256)
+
+static unsigned char fontdata_6x11[FONTDATAMAX] = {
+
+	/* 0 0x00 '^@' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 1 0x01 '^A' */
+	0x00, /* 00000000 */
+	0x78, /* 0    000 */
+	0x84, /*  0000 00 */
+	0xcc, /*   00  00 */
+	0x84, /*  0000 00 */
+	0xb4, /*  0  0 00 */
+	0x84, /*  0000 00 */
+	0x78, /* 0    000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 2 0x02 '^B' */
+	0x00, /* 00000000 */
+	0x78, /* 0    000 */
+	0xfc, /*       00 */
+	0xb4, /*  0  0 00 */
+	0xfc, /*       00 */
+	0xcc, /*   00  00 */
+	0xfc, /*       00 */
+	0x78, /* 0    000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 3 0x03 '^C' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x28, /* 00 0 000 */
+	0x7c, /* 0     00 */
+	0x7c, /* 0     00 */
+	0x38, /* 00   000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 4 0x04 '^D' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x38, /* 00   000 */
+	0x7c, /* 0     00 */
+	0x38, /* 00   000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 5 0x05 '^E' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x38, /* 00   000 */
+	0x6c, /* 0  0  00 */
+	0x6c, /* 0  0  00 */
+	0x10, /* 000 0000 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 6 0x06 '^F' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x38, /* 00   000 */
+	0x7c, /* 0     00 */
+	0x7c, /* 0     00 */
+	0x10, /* 000 0000 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 7 0x07 '^G' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x30, /* 00  0000 */
+	0x78, /* 0    000 */
+	0x30, /* 00  0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 8 0x08 '^H' */
+	0xff, /*          */
+	0xff, /*          */
+	0xff, /*          */
+	0xcf, /*   00     */
+	0x87, /*  0000    */
+	0xcf, /*   00     */
+	0xff, /*          */
+	0xff, /*          */
+	0xff, /*          */
+	0xff, /*          */
+	0xff, /*          */
+
+	/* 9 0x09 '^I' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x30, /* 00  0000 */
+	0x48, /* 0 00 000 */
+	0x84, /*  0000 00 */
+	0x48, /* 0 00 000 */
+	0x30, /* 00  0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 10 0x0a '^J' */
+	0xff, /*          */
+	0xff, /*          */
+	0xcf, /*   00     */
+	0xb7, /*  0  0    */
+	0x7b, /* 0    0   */
+	0xb7, /*  0  0    */
+	0xcf, /*   00     */
+	0xff, /*          */
+	0xff, /*          */
+	0xff, /*          */
+	0xff, /*          */
+
+	/* 11 0x0b '^K' */
+	0x00, /* 00000000 */
+	0x3c, /* 00    00 */
+	0x14, /* 000 0 00 */
+	0x20, /* 00 00000 */
+	0x78, /* 0    000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 12 0x0c '^L' */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x10, /* 000 0000 */
+	0x7c, /* 0     00 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 13 0x0d '^M' */
+	0x00, /* 00000000 */
+	0x3c, /* 00    00 */
+	0x24, /* 00 00 00 */
+	0x3c, /* 00    00 */
+	0x20, /* 00 00000 */
+	0x20, /* 00 00000 */
+	0xe0, /*    00000 */
+	0xc0, /*   000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 14 0x0e '^N' */
+	0x00, /* 00000000 */
+	0x7c, /* 0     00 */
+	0x44, /* 0 000 00 */
+	0x7c, /* 0     00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0xcc, /*   00  00 */
+	0xcc, /*   00  00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 15 0x0f '^O' */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x54, /* 0 0 0 00 */
+	0x38, /* 00   000 */
+	0x6c, /* 0  0  00 */
+	0x38, /* 00   000 */
+	0x54, /* 0 0 0 00 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 16 0x10 '^P' */
+	0x00, /* 00000000 */
+	0x40, /* 0 000000 */
+	0x60, /* 0  00000 */
+	0x70, /* 0   0000 */
+	0x7c, /* 0     00 */
+	0x70, /* 0   0000 */
+	0x60, /* 0  00000 */
+	0x40, /* 0 000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 17 0x11 '^Q' */
+	0x00, /* 00000000 */
+	0x04, /* 00000 00 */
+	0x0c, /* 0000  00 */
+	0x1c, /* 000   00 */
+	0x7c, /* 0     00 */
+	0x1c, /* 000   00 */
+	0x0c, /* 0000  00 */
+	0x04, /* 00000 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 18 0x12 '^R' */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x38, /* 00   000 */
+	0x54, /* 0 0 0 00 */
+	0x10, /* 000 0000 */
+	0x54, /* 0 0 0 00 */
+	0x38, /* 00   000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 19 0x13 '^S' */
+	0x00, /* 00000000 */
+	0x48, /* 0 00 000 */
+	0x48, /* 0 00 000 */
+	0x48, /* 0 00 000 */
+	0x48, /* 0 00 000 */
+	0x48, /* 0 00 000 */
+	0x00, /* 00000000 */
+	0x48, /* 0 00 000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 20 0x14 '^T' */
+	0x3c, /* 00    00 */
+	0x54, /* 0 0 0 00 */
+	0x54, /* 0 0 0 00 */
+	0x54, /* 0 0 0 00 */
+	0x3c, /* 00    00 */
+	0x14, /* 000 0 00 */
+	0x14, /* 000 0 00 */
+	0x14, /* 000 0 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 21 0x15 '^U' */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x24, /* 00 00 00 */
+	0x50, /* 0 0 0000 */
+	0x48, /* 0 00 000 */
+	0x24, /* 00 00 00 */
+	0x14, /* 000 0 00 */
+	0x48, /* 0 00 000 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+
+	/* 22 0x16 '^V' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xf8, /*      000 */
+	0xf8, /*      000 */
+	0xf8, /*      000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 23 0x17 '^W' */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x38, /* 00   000 */
+	0x54, /* 0 0 0 00 */
+	0x10, /* 000 0000 */
+	0x54, /* 0 0 0 00 */
+	0x38, /* 00   000 */
+	0x10, /* 000 0000 */
+	0x7c, /* 0     00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 24 0x18 '^X' */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x38, /* 00   000 */
+	0x54, /* 0 0 0 00 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 25 0x19 '^Y' */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x54, /* 0 0 0 00 */
+	0x38, /* 00   000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 26 0x1a '^Z' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x08, /* 0000 000 */
+	0x7c, /* 0     00 */
+	0x08, /* 0000 000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 27 0x1b '^[' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x20, /* 00 00000 */
+	0x7c, /* 0     00 */
+	0x20, /* 00 00000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 28 0x1c '^\' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x78, /* 0    000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 29 0x1d '^]' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x48, /* 0 00 000 */
+	0x84, /*  0000 00 */
+	0xfc, /*       00 */
+	0x84, /*  0000 00 */
+	0x48, /* 0 00 000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 30 0x1e '^^' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x38, /* 00   000 */
+	0x38, /* 00   000 */
+	0x7c, /* 0     00 */
+	0x7c, /* 0     00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 31 0x1f '^`' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 0     00 */
+	0x7c, /* 0     00 */
+	0x38, /* 00   000 */
+	0x38, /* 00   000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 32 0x20 ' ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 33 0x21 '!' */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 34 0x22 '"' */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 35 0x23 '#' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x28, /* 00 0 000 */
+	0x7c, /* 0     00 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x7c, /* 0     00 */
+	0x28, /* 00 0 000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 36 0x24 '$' */
+	0x10, /* 000 0000 */
+	0x38, /* 00   000 */
+	0x54, /* 0 0 0 00 */
+	0x50, /* 0 0 0000 */
+	0x38, /* 00   000 */
+	0x14, /* 000 0 00 */
+	0x54, /* 0 0 0 00 */
+	0x38, /* 00   000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 37 0x25 '%' */
+	0x00, /* 00000000 */
+	0x64, /* 0  00 00 */
+	0x64, /* 0  00 00 */
+	0x08, /* 0000 000 */
+	0x10, /* 000 0000 */
+	0x20, /* 00 00000 */
+	0x4c, /* 0 00  00 */
+	0x4c, /* 0 00  00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 38 0x26 '&' */
+	0x00, /* 00000000 */
+	0x30, /* 00  0000 */
+	0x48, /* 0 00 000 */
+	0x50, /* 0 0 0000 */
+	0x20, /* 00 00000 */
+	0x54, /* 0 0 0 00 */
+	0x48, /* 0 00 000 */
+	0x34, /* 00  0 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 39 0x27 ''' */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 40 0x28 '(' */
+	0x04, /* 00000 00 */
+	0x08, /* 0000 000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x08, /* 0000 000 */
+	0x04, /* 00000 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 41 0x29 ')' */
+	0x20, /* 00 00000 */
+	0x10, /* 000 0000 */
+	0x08, /* 0000 000 */
+	0x08, /* 0000 000 */
+	0x08, /* 0000 000 */
+	0x08, /* 0000 000 */
+	0x08, /* 0000 000 */
+	0x10, /* 000 0000 */
+	0x20, /* 00 00000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 42 0x2a '*' */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x54, /* 0 0 0 00 */
+	0x38, /* 00   000 */
+	0x54, /* 0 0 0 00 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 43 0x2b '+' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x7c, /* 0     00 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 44 0x2c ',' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x30, /* 00  0000 */
+	0x30, /* 00  0000 */
+	0x10, /* 000 0000 */
+	0x20, /* 00 00000 */
+	0x00, /* 00000000 */
+
+	/* 45 0x2d '-' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 0     00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 46 0x2e '.' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 000  000 */
+	0x18, /* 000  000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 47 0x2f '/' */
+	0x04, /* 00000 00 */
+	0x04, /* 00000 00 */
+	0x08, /* 0000 000 */
+	0x08, /* 0000 000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x20, /* 00 00000 */
+	0x20, /* 00 00000 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x00, /* 00000000 */
+
+	/* 48 0x30 '0' */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x4c, /* 0 00  00 */
+	0x54, /* 0 0 0 00 */
+	0x64, /* 0  00 00 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 49 0x31 '1' */
+	0x00, /* 00000000 */
+	0x08, /* 0000 000 */
+	0x18, /* 000  000 */
+	0x08, /* 0000 000 */
+	0x08, /* 0000 000 */
+	0x08, /* 0000 000 */
+	0x08, /* 0000 000 */
+	0x1c, /* 000   00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 50 0x32 '2' */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x04, /* 00000 00 */
+	0x08, /* 0000 000 */
+	0x10, /* 000 0000 */
+	0x20, /* 00 00000 */
+	0x7c, /* 0     00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 51 0x33 '3' */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x04, /* 00000 00 */
+	0x18, /* 000  000 */
+	0x04, /* 00000 00 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 52 0x34 '4' */
+	0x00, /* 00000000 */
+	0x08, /* 0000 000 */
+	0x18, /* 000  000 */
+	0x28, /* 00 0 000 */
+	0x48, /* 0 00 000 */
+	0x7c, /* 0     00 */
+	0x08, /* 0000 000 */
+	0x1c, /* 000   00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 53 0x35 '5' */
+	0x00, /* 00000000 */
+	0x7c, /* 0     00 */
+	0x40, /* 0 000000 */
+	0x78, /* 0    000 */
+	0x04, /* 00000 00 */
+	0x04, /* 00000 00 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 54 0x36 '6' */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x40, /* 0 000000 */
+	0x78, /* 0    000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 55 0x37 '7' */
+	0x00, /* 00000000 */
+	0x7c, /* 0     00 */
+	0x04, /* 00000 00 */
+	0x04, /* 00000 00 */
+	0x08, /* 0000 000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 56 0x38 '8' */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 57 0x39 '9' */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x3c, /* 00    00 */
+	0x04, /* 00000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 58 0x3a ':' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 000  000 */
+	0x18, /* 000  000 */
+	0x00, /* 00000000 */
+	0x18, /* 000  000 */
+	0x18, /* 000  000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 59 0x3b ';' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x30, /* 00  0000 */
+	0x30, /* 00  0000 */
+	0x00, /* 00000000 */
+	0x30, /* 00  0000 */
+	0x30, /* 00  0000 */
+	0x10, /* 000 0000 */
+	0x20, /* 00 00000 */
+	0x00, /* 00000000 */
+
+	/* 60 0x3c '<' */
+	0x00, /* 00000000 */
+	0x04, /* 00000 00 */
+	0x08, /* 0000 000 */
+	0x10, /* 000 0000 */
+	0x20, /* 00 00000 */
+	0x10, /* 000 0000 */
+	0x08, /* 0000 000 */
+	0x04, /* 00000 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 61 0x3d '=' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 0     00 */
+	0x00, /* 00000000 */
+	0x7c, /* 0     00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 62 0x3e '>' */
+	0x00, /* 00000000 */
+	0x20, /* 00 00000 */
+	0x10, /* 000 0000 */
+	0x08, /* 0000 000 */
+	0x04, /* 00000 00 */
+	0x08, /* 0000 000 */
+	0x10, /* 000 0000 */
+	0x20, /* 00 00000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 63 0x3f '?' */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x04, /* 00000 00 */
+	0x08, /* 0000 000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 64 0x40 '@' */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x74, /* 0   0 00 */
+	0x54, /* 0 0 0 00 */
+	0x78, /* 0    000 */
+	0x40, /* 0 000000 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 65 0x41 'A' */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x7c, /* 0     00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 66 0x42 'B' */
+	0x00, /* 00000000 */
+	0x78, /* 0    000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x78, /* 0    000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x78, /* 0    000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 67 0x43 'C' */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 68 0x44 'D' */
+	0x00, /* 00000000 */
+	0x78, /* 0    000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x78, /* 0    000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 69 0x45 'E' */
+	0x00, /* 00000000 */
+	0x7c, /* 0     00 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x78, /* 0    000 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x7c, /* 0     00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 70 0x46 'F' */
+	0x00, /* 00000000 */
+	0x7c, /* 0     00 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x78, /* 0    000 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 71 0x47 'G' */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x40, /* 0 000000 */
+	0x4c, /* 0 00  00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 72 0x48 'H' */
+	0x00, /* 00000000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x7c, /* 0     00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 73 0x49 'I' */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 74 0x4a 'J' */
+	0x00, /* 00000000 */
+	0x04, /* 00000 00 */
+	0x04, /* 00000 00 */
+	0x04, /* 00000 00 */
+	0x04, /* 00000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 75 0x4b 'K' */
+	0x00, /* 00000000 */
+	0x44, /* 0 000 00 */
+	0x48, /* 0 00 000 */
+	0x50, /* 0 0 0000 */
+	0x60, /* 0  00000 */
+	0x50, /* 0 0 0000 */
+	0x48, /* 0 00 000 */
+	0x44, /* 0 000 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 76 0x4c 'L' */
+	0x00, /* 00000000 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x7c, /* 0     00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 77 0x4d 'M' */
+	0x00, /* 00000000 */
+	0x44, /* 0 000 00 */
+	0x6c, /* 0  0  00 */
+	0x54, /* 0 0 0 00 */
+	0x54, /* 0 0 0 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 78 0x4e 'N' */
+	0x00, /* 00000000 */
+	0x44, /* 0 000 00 */
+	0x64, /* 0  00 00 */
+	0x54, /* 0 0 0 00 */
+	0x4c, /* 0 00  00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 79 0x4f 'O' */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 80 0x50 'P' */
+	0x00, /* 00000000 */
+	0x78, /* 0    000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x78, /* 0    000 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 81 0x51 'Q' */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x54, /* 0 0 0 00 */
+	0x38, /* 00   000 */
+	0x04, /* 00000 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 82 0x52 'R' */
+	0x00, /* 00000000 */
+	0x78, /* 0    000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x78, /* 0    000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 83 0x53 'S' */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x40, /* 0 000000 */
+	0x38, /* 00   000 */
+	0x04, /* 00000 00 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 84 0x54 'T' */
+	0x00, /* 00000000 */
+	0x7c, /* 0     00 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 85 0x55 'U' */
+	0x00, /* 00000000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 86 0x56 'V' */
+	0x00, /* 00000000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x28, /* 00 0 000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 87 0x57 'W' */
+	0x00, /* 00000000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x54, /* 0 0 0 00 */
+	0x54, /* 0 0 0 00 */
+	0x6c, /* 0  0  00 */
+	0x44, /* 0 000 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 88 0x58 'X' */
+	0x00, /* 00000000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x28, /* 00 0 000 */
+	0x10, /* 000 0000 */
+	0x28, /* 00 0 000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 89 0x59 'Y' */
+	0x00, /* 00000000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x28, /* 00 0 000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 90 0x5a 'Z' */
+	0x00, /* 00000000 */
+	0x7c, /* 0     00 */
+	0x04, /* 00000 00 */
+	0x08, /* 0000 000 */
+	0x10, /* 000 0000 */
+	0x20, /* 00 00000 */
+	0x40, /* 0 000000 */
+	0x7c, /* 0     00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 91 0x5b '[' */
+	0x0c, /* 0000  00 */
+	0x08, /* 0000 000 */
+	0x08, /* 0000 000 */
+	0x08, /* 0000 000 */
+	0x08, /* 0000 000 */
+	0x08, /* 0000 000 */
+	0x08, /* 0000 000 */
+	0x08, /* 0000 000 */
+	0x0c, /* 0000  00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 92 0x5c '\' */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x20, /* 00 00000 */
+	0x20, /* 00 00000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x08, /* 0000 000 */
+	0x08, /* 0000 000 */
+	0x04, /* 00000 00 */
+	0x04, /* 00000 00 */
+	0x00, /* 00000000 */
+
+	/* 93 0x5d ']' */
+	0x30, /* 00  0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x30, /* 00  0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 94 0x5e '^' */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x28, /* 00 0 000 */
+	0x44, /* 0 000 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 95 0x5f '_' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfc, /*       00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 96 0x60 '`' */
+	0x20, /* 00 00000 */
+	0x10, /* 000 0000 */
+	0x08, /* 0000 000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 97 0x61 'a' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00    00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x4c, /* 0 00  00 */
+	0x34, /* 00  0 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 98 0x62 'b' */
+	0x00, /* 00000000 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x78, /* 0    000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x78, /* 0    000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 99 0x63 'c' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x40, /* 0 000000 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 100 0x64 'd' */
+	0x00, /* 00000000 */
+	0x04, /* 00000 00 */
+	0x04, /* 00000 00 */
+	0x3c, /* 00    00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x3c, /* 00    00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 101 0x65 'e' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x7c, /* 0     00 */
+	0x40, /* 0 000000 */
+	0x3c, /* 00    00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 102 0x66 'f' */
+	0x00, /* 00000000 */
+	0x0c, /* 0000  00 */
+	0x10, /* 000 0000 */
+	0x38, /* 00   000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 103 0x67 'g' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00    00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x3c, /* 00    00 */
+	0x04, /* 00000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+
+	/* 104 0x68 'h' */
+	0x00, /* 00000000 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x78, /* 0    000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 105 0x69 'i' */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x30, /* 00  0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 106 0x6a 'j' */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x30, /* 00  0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x60, /* 0  00000 */
+	0x00, /* 00000000 */
+
+	/* 107 0x6b 'k' */
+	0x00, /* 00000000 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x48, /* 0 00 000 */
+	0x50, /* 0 0 0000 */
+	0x70, /* 0   0000 */
+	0x48, /* 0 00 000 */
+	0x44, /* 0 000 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 108 0x6c 'l' */
+	0x00, /* 00000000 */
+	0x30, /* 00  0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 109 0x6d 'm' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x78, /* 0    000 */
+	0x54, /* 0 0 0 00 */
+	0x54, /* 0 0 0 00 */
+	0x54, /* 0 0 0 00 */
+	0x54, /* 0 0 0 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 110 0x6e 'n' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x58, /* 0 0  000 */
+	0x64, /* 0  00 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 111 0x6f 'o' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 112 0x70 'p' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x78, /* 0    000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x78, /* 0    000 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x00, /* 00000000 */
+
+	/* 113 0x71 'q' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00    00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x3c, /* 00    00 */
+	0x04, /* 00000 00 */
+	0x04, /* 00000 00 */
+	0x00, /* 00000000 */
+
+	/* 114 0x72 'r' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x58, /* 0 0  000 */
+	0x64, /* 0  00 00 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 115 0x73 's' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00    00 */
+	0x40, /* 0 000000 */
+	0x38, /* 00   000 */
+	0x04, /* 00000 00 */
+	0x78, /* 0    000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 116 0x74 't' */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x38, /* 00   000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x0c, /* 0000  00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 117 0x75 'u' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x4c, /* 0 00  00 */
+	0x34, /* 00  0 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 118 0x76 'v' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x28, /* 00 0 000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 119 0x77 'w' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x54, /* 0 0 0 00 */
+	0x54, /* 0 0 0 00 */
+	0x54, /* 0 0 0 00 */
+	0x54, /* 0 0 0 00 */
+	0x28, /* 00 0 000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 120 0x78 'x' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x44, /* 0 000 00 */
+	0x28, /* 00 0 000 */
+	0x10, /* 000 0000 */
+	0x28, /* 00 0 000 */
+	0x44, /* 0 000 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 121 0x79 'y' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x3c, /* 00    00 */
+	0x04, /* 00000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+
+	/* 122 0x7a 'z' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 0     00 */
+	0x08, /* 0000 000 */
+	0x10, /* 000 0000 */
+	0x20, /* 00 00000 */
+	0x7c, /* 0     00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 123 0x7b '{' */
+	0x04, /* 00000 00 */
+	0x08, /* 0000 000 */
+	0x08, /* 0000 000 */
+	0x08, /* 0000 000 */
+	0x08, /* 0000 000 */
+	0x10, /* 000 0000 */
+	0x08, /* 0000 000 */
+	0x08, /* 0000 000 */
+	0x08, /* 0000 000 */
+	0x08, /* 0000 000 */
+	0x04, /* 00000 00 */
+
+	/* 124 0x7c '|' */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 125 0x7d '}' */
+	0x20, /* 00 00000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x08, /* 0000 000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x20, /* 00 00000 */
+
+	/* 126 0x7e '~' */
+	0x00, /* 00000000 */
+	0x34, /* 00  0 00 */
+	0x58, /* 0 0  000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 127 0x7f '^?' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x28, /* 00 0 000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x7c, /* 0     00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 128 0x80 '\200' */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x10, /* 000 0000 */
+	0x20, /* 00 00000 */
+	0x00, /* 00000000 */
+
+	/* 129 0x81 '\201' */
+	0x00, /* 00000000 */
+	0x28, /* 00 0 000 */
+	0x00, /* 00000000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x4c, /* 0 00  00 */
+	0x34, /* 00  0 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 130 0x82 '\202' */
+	0x08, /* 0000 000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x7c, /* 0     00 */
+	0x40, /* 0 000000 */
+	0x3c, /* 00    00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 131 0x83 '\203' */
+	0x10, /* 000 0000 */
+	0x28, /* 00 0 000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00    00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x4c, /* 0 00  00 */
+	0x34, /* 00  0 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 132 0x84 '\204' */
+	0x00, /* 00000000 */
+	0x28, /* 00 0 000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00    00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x4c, /* 0 00  00 */
+	0x34, /* 00  0 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 133 0x85 '\205' */
+	0x10, /* 000 0000 */
+	0x08, /* 0000 000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00    00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x4c, /* 0 00  00 */
+	0x34, /* 00  0 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 134 0x86 '\206' */
+	0x18, /* 000  000 */
+	0x24, /* 00 00 00 */
+	0x18, /* 000  000 */
+	0x3c, /* 00    00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x4c, /* 0 00  00 */
+	0x34, /* 00  0 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 135 0x87 '\207' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x3c, /* 00    00 */
+	0x10, /* 000 0000 */
+	0x20, /* 00 00000 */
+	0x00, /* 00000000 */
+
+	/* 136 0x88 '\210' */
+	0x10, /* 000 0000 */
+	0x28, /* 00 0 000 */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x7c, /* 0     00 */
+	0x40, /* 0 000000 */
+	0x3c, /* 00    00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 137 0x89 '\211' */
+	0x00, /* 00000000 */
+	0x28, /* 00 0 000 */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x7c, /* 0     00 */
+	0x40, /* 0 000000 */
+	0x3c, /* 00    00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 138 0x8a '\212' */
+	0x20, /* 00 00000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x7c, /* 0     00 */
+	0x40, /* 0 000000 */
+	0x3c, /* 00    00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 139 0x8b '\213' */
+	0x00, /* 00000000 */
+	0x28, /* 00 0 000 */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 140 0x8c '\214' */
+	0x10, /* 000 0000 */
+	0x28, /* 00 0 000 */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 141 0x8d '\215' */
+	0x20, /* 00 00000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 142 0x8e '\216' */
+	0x84, /*  0000 00 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x7c, /* 0     00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 143 0x8f '\217' */
+	0x58, /* 0 0  000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x7c, /* 0     00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 144 0x90 '\220' */
+	0x10, /* 000 0000 */
+	0x7c, /* 0     00 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x78, /* 0    000 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x7c, /* 0     00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 145 0x91 '\221' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x54, /* 0 0 0 00 */
+	0x5c, /* 0 0   00 */
+	0x50, /* 0 0 0000 */
+	0x3c, /* 00    00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 146 0x92 '\222' */
+	0x00, /* 00000000 */
+	0x3c, /* 00    00 */
+	0x50, /* 0 0 0000 */
+	0x50, /* 0 0 0000 */
+	0x78, /* 0    000 */
+	0x50, /* 0 0 0000 */
+	0x50, /* 0 0 0000 */
+	0x5c, /* 0 0   00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 147 0x93 '\223' */
+	0x10, /* 000 0000 */
+	0x28, /* 00 0 000 */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 148 0x94 '\224' */
+	0x00, /* 00000000 */
+	0x28, /* 00 0 000 */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 149 0x95 '\225' */
+	0x20, /* 00 00000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 150 0x96 '\226' */
+	0x10, /* 000 0000 */
+	0x28, /* 00 0 000 */
+	0x00, /* 00000000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x4c, /* 0 00  00 */
+	0x34, /* 00  0 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 151 0x97 '\227' */
+	0x20, /* 00 00000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x4c, /* 0 00  00 */
+	0x34, /* 00  0 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 152 0x98 '\230' */
+	0x00, /* 00000000 */
+	0x28, /* 00 0 000 */
+	0x00, /* 00000000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x3c, /* 00    00 */
+	0x04, /* 00000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+
+	/* 153 0x99 '\231' */
+	0x84, /*  0000 00 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 154 0x9a '\232' */
+	0x88, /*  000 000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 155 0x9b '\233' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x38, /* 00   000 */
+	0x54, /* 0 0 0 00 */
+	0x50, /* 0 0 0000 */
+	0x54, /* 0 0 0 00 */
+	0x38, /* 00   000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 156 0x9c '\234' */
+	0x30, /* 00  0000 */
+	0x48, /* 0 00 000 */
+	0x40, /* 0 000000 */
+	0x70, /* 0   0000 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x44, /* 0 000 00 */
+	0x78, /* 0    000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 157 0x9d '\235' */
+	0x00, /* 00000000 */
+	0x44, /* 0 000 00 */
+	0x28, /* 00 0 000 */
+	0x7c, /* 0     00 */
+	0x10, /* 000 0000 */
+	0x7c, /* 0     00 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 158 0x9e '\236' */
+	0x00, /* 00000000 */
+	0x70, /* 0   0000 */
+	0x48, /* 0 00 000 */
+	0x70, /* 0   0000 */
+	0x48, /* 0 00 000 */
+	0x5c, /* 0 0   00 */
+	0x48, /* 0 00 000 */
+	0x44, /* 0 000 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 159 0x9f '\237' */
+	0x00, /* 00000000 */
+	0x0c, /* 0000  00 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x38, /* 00   000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x60, /* 0  00000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 160 0xa0 '\240' */
+	0x08, /* 0000 000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00    00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x4c, /* 0 00  00 */
+	0x34, /* 00  0 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 161 0xa1 '\241' */
+	0x08, /* 0000 000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 162 0xa2 '\242' */
+	0x08, /* 0000 000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 163 0xa3 '\243' */
+	0x08, /* 0000 000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x4c, /* 0 00  00 */
+	0x34, /* 00  0 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 164 0xa4 '\244' */
+	0x34, /* 00  0 00 */
+	0x58, /* 0 0  000 */
+	0x00, /* 00000000 */
+	0x58, /* 0 0  000 */
+	0x64, /* 0  00 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 165 0xa5 '\245' */
+	0x58, /* 0 0  000 */
+	0x44, /* 0 000 00 */
+	0x64, /* 0  00 00 */
+	0x54, /* 0 0 0 00 */
+	0x4c, /* 0 00  00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 166 0xa6 '\246' */
+	0x00, /* 00000000 */
+	0x1c, /* 000   00 */
+	0x24, /* 00 00 00 */
+	0x24, /* 00 00 00 */
+	0x1c, /* 000   00 */
+	0x00, /* 00000000 */
+	0x3c, /* 00    00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 167 0xa7 '\247' */
+	0x00, /* 00000000 */
+	0x18, /* 000  000 */
+	0x24, /* 00 00 00 */
+	0x24, /* 00 00 00 */
+	0x18, /* 000  000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00    00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 168 0xa8 '\250' */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x20, /* 00 00000 */
+	0x40, /* 0 000000 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 169 0xa9 '\251' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 0     00 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 170 0xaa '\252' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 0     00 */
+	0x04, /* 00000 00 */
+	0x04, /* 00000 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 171 0xab '\253' */
+	0x20, /* 00 00000 */
+	0x60, /* 0  00000 */
+	0x24, /* 00 00 00 */
+	0x28, /* 00 0 000 */
+	0x10, /* 000 0000 */
+	0x28, /* 00 0 000 */
+	0x44, /* 0 000 00 */
+	0x08, /* 0000 000 */
+	0x1c, /* 000   00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 172 0xac '\254' */
+	0x20, /* 00 00000 */
+	0x60, /* 0  00000 */
+	0x24, /* 00 00 00 */
+	0x28, /* 00 0 000 */
+	0x10, /* 000 0000 */
+	0x28, /* 00 0 000 */
+	0x58, /* 0 0  000 */
+	0x3c, /* 00    00 */
+	0x08, /* 0000 000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 173 0xad '\255' */
+	0x00, /* 00000000 */
+	0x08, /* 0000 000 */
+	0x00, /* 00000000 */
+	0x08, /* 0000 000 */
+	0x08, /* 0000 000 */
+	0x08, /* 0000 000 */
+	0x08, /* 0000 000 */
+	0x08, /* 0000 000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 174 0xae '\256' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x24, /* 00 00 00 */
+	0x48, /* 0 00 000 */
+	0x48, /* 0 00 000 */
+	0x24, /* 00 00 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 175 0xaf '\257' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x48, /* 0 00 000 */
+	0x24, /* 00 00 00 */
+	0x24, /* 00 00 00 */
+	0x48, /* 0 00 000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 176 0xb0 '\260' */
+	0x11, /* 000 000  */
+	0x44, /* 0 000 00 */
+	0x11, /* 000 000  */
+	0x44, /* 0 000 00 */
+	0x11, /* 000 000  */
+	0x44, /* 0 000 00 */
+	0x11, /* 000 000  */
+	0x44, /* 0 000 00 */
+	0x11, /* 000 000  */
+	0x44, /* 0 000 00 */
+	0x11, /* 000 000  */
+
+	/* 177 0xb1 '\261' */
+	0x55, /* 0 0 0 0  */
+	0xaa, /*  0 0 0 0 */
+	0x55, /* 0 0 0 0  */
+	0xaa, /*  0 0 0 0 */
+	0x55, /* 0 0 0 0  */
+	0xaa, /*  0 0 0 0 */
+	0x55, /* 0 0 0 0  */
+	0xaa, /*  0 0 0 0 */
+	0x55, /* 0 0 0 0  */
+	0xaa, /*  0 0 0 0 */
+	0x55, /* 0 0 0 0  */
+
+	/* 178 0xb2 '\262' */
+	0xdd, /*   0   0  */
+	0x77, /* 0   0    */
+	0xdd, /*   0   0  */
+	0x77, /* 0   0    */
+	0xdd, /*   0   0  */
+	0x77, /* 0   0    */
+	0xdd, /*   0   0  */
+	0x77, /* 0   0    */
+	0xdd, /*   0   0  */
+	0x77, /* 0   0    */
+	0xdd, /*   0   0  */
+
+	/* 179 0xb3 '\263' */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+
+	/* 180 0xb4 '\264' */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0xf0, /*     0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+
+	/* 181 0xb5 '\265' */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0xf0, /*     0000 */
+	0x10, /* 000 0000 */
+	0xf0, /*     0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+
+	/* 182 0xb6 '\266' */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0xe8, /*    0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+
+	/* 183 0xb7 '\267' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xf8, /*      000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+
+	/* 184 0xb8 '\270' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xf0, /*     0000 */
+	0x10, /* 000 0000 */
+	0xf0, /*     0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+
+	/* 185 0xb9 '\271' */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0xe8, /*    0 000 */
+	0x08, /* 0000 000 */
+	0xe8, /*    0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+
+	/* 186 0xba '\272' */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+
+	/* 187 0xbb '\273' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xf8, /*      000 */
+	0x08, /* 0000 000 */
+	0xe8, /*    0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+
+	/* 188 0xbc '\274' */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0xe8, /*    0 000 */
+	0x08, /* 0000 000 */
+	0xf8, /*      000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 189 0xbd '\275' */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0xf8, /*      000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 190 0xbe '\276' */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0xf0, /*     0000 */
+	0x10, /* 000 0000 */
+	0xf0, /*     0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 191 0xbf '\277' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xf0, /*     0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+
+	/* 192 0xc0 '\300' */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x1c, /* 000   00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 193 0xc1 '\301' */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0xfc, /*       00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 194 0xc2 '\302' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfc, /*       00 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+
+	/* 195 0xc3 '\303' */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x1c, /* 000   00 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+
+	/* 196 0xc4 '\304' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfc, /*       00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 197 0xc5 '\305' */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0xfc, /*       00 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+
+	/* 198 0xc6 '\306' */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x1c, /* 000   00 */
+	0x10, /* 000 0000 */
+	0x1c, /* 000   00 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+
+	/* 199 0xc7 '\307' */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x2c, /* 00 0  00 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+
+	/* 200 0xc8 '\310' */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x2c, /* 00 0  00 */
+	0x20, /* 00 00000 */
+	0x3c, /* 00    00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 201 0xc9 '\311' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00    00 */
+	0x20, /* 00 00000 */
+	0x2c, /* 00 0  00 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+
+	/* 202 0xca '\312' */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0xec, /*    0  00 */
+	0x00, /* 00000000 */
+	0xfc, /*       00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 203 0xcb '\313' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfc, /*       00 */
+	0x00, /* 00000000 */
+	0xec, /*    0  00 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+
+	/* 204 0xcc '\314' */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x2c, /* 00 0  00 */
+	0x20, /* 00 00000 */
+	0x2c, /* 00 0  00 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+
+	/* 205 0xcd '\315' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfc, /*       00 */
+	0x00, /* 00000000 */
+	0xfc, /*       00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 206 0xce '\316' */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0xec, /*    0  00 */
+	0x00, /* 00000000 */
+	0xec, /*    0  00 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+
+	/* 207 0xcf '\317' */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0xfc, /*       00 */
+	0x00, /* 00000000 */
+	0xfc, /*       00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 208 0xd0 '\320' */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0xfc, /*       00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 209 0xd1 '\321' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfc, /*       00 */
+	0x00, /* 00000000 */
+	0xfc, /*       00 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+
+	/* 210 0xd2 '\322' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfc, /*       00 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+
+	/* 211 0xd3 '\323' */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x3c, /* 00    00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 212 0xd4 '\324' */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x1c, /* 000   00 */
+	0x10, /* 000 0000 */
+	0x1c, /* 000   00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 213 0xd5 '\325' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1c, /* 000   00 */
+	0x10, /* 000 0000 */
+	0x1c, /* 000   00 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+
+	/* 214 0xd6 '\326' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00    00 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+
+	/* 215 0xd7 '\327' */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0xfc, /*       00 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+
+	/* 216 0xd8 '\330' */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0xfc, /*       00 */
+	0x10, /* 000 0000 */
+	0xfc, /*       00 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+
+	/* 217 0xd9 '\331' */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0xf0, /*     0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 218 0xda '\332' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1f, /* 000      */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+
+	/* 219 0xdb '\333' */
+	0xfc, /*       00 */
+	0xfc, /*       00 */
+	0xfc, /*       00 */
+	0xfc, /*       00 */
+	0xfc, /*       00 */
+	0xfc, /*       00 */
+	0xfc, /*       00 */
+	0xfc, /*       00 */
+	0xfc, /*       00 */
+	0xfc, /*       00 */
+	0xfc, /*       00 */
+
+	/* 220 0xdc '\334' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfc, /*       00 */
+	0xfc, /*       00 */
+	0xfc, /*       00 */
+	0xfc, /*       00 */
+	0xfc, /*       00 */
+	0xfc, /*       00 */
+
+	/* 221 0xdd '\335' */
+	0xe0, /*    00000 */
+	0xe0, /*    00000 */
+	0xe0, /*    00000 */
+	0xe0, /*    00000 */
+	0xe0, /*    00000 */
+	0xe0, /*    00000 */
+	0xe0, /*    00000 */
+	0xe0, /*    00000 */
+	0xe0, /*    00000 */
+	0xe0, /*    00000 */
+	0xe0, /*    00000 */
+
+	/* 222 0xde '\336' */
+	0x1c, /* 000   00 */
+	0x1c, /* 000   00 */
+	0x1c, /* 000   00 */
+	0x1c, /* 000   00 */
+	0x1c, /* 000   00 */
+	0x1c, /* 000   00 */
+	0x1c, /* 000   00 */
+	0x1c, /* 000   00 */
+	0x1c, /* 000   00 */
+	0x1c, /* 000   00 */
+	0x1c, /* 000   00 */
+
+	/* 223 0xdf '\337' */
+	0xfc, /*       00 */
+	0xfc, /*       00 */
+	0xfc, /*       00 */
+	0xfc, /*       00 */
+	0xfc, /*       00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 224 0xe0 '\340' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x24, /* 00 00 00 */
+	0x58, /* 0 0  000 */
+	0x50, /* 0 0 0000 */
+	0x54, /* 0 0 0 00 */
+	0x2c, /* 00 0  00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 225 0xe1 '\341' */
+	0x18, /* 000  000 */
+	0x24, /* 00 00 00 */
+	0x44, /* 0 000 00 */
+	0x48, /* 0 00 000 */
+	0x48, /* 0 00 000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x58, /* 0 0  000 */
+	0x40, /* 0 000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 226 0xe2 '\342' */
+	0x00, /* 00000000 */
+	0x7c, /* 0     00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 227 0xe3 '\343' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 0     00 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 228 0xe4 '\344' */
+	0x00, /* 00000000 */
+	0x7c, /* 0     00 */
+	0x24, /* 00 00 00 */
+	0x10, /* 000 0000 */
+	0x08, /* 0000 000 */
+	0x10, /* 000 0000 */
+	0x24, /* 00 00 00 */
+	0x7c, /* 0     00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 229 0xe5 '\345' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00    00 */
+	0x48, /* 0 00 000 */
+	0x48, /* 0 00 000 */
+	0x48, /* 0 00 000 */
+	0x30, /* 00  0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 230 0xe6 '\346' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x48, /* 0 00 000 */
+	0x48, /* 0 00 000 */
+	0x48, /* 0 00 000 */
+	0x48, /* 0 00 000 */
+	0x74, /* 0   0 00 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x00, /* 00000000 */
+
+	/* 231 0xe7 '\347' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x6c, /* 0  0  00 */
+	0x98, /*  00  000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 232 0xe8 '\350' */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x10, /* 000 0000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x10, /* 000 0000 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 233 0xe9 '\351' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x4c, /* 0 00  00 */
+	0x54, /* 0 0 0 00 */
+	0x64, /* 0  00 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 234 0xea '\352' */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x28, /* 00 0 000 */
+	0x6c, /* 0  0  00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 235 0xeb '\353' */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x08, /* 0000 000 */
+	0x0c, /* 0000  00 */
+	0x14, /* 000 0 00 */
+	0x24, /* 00 00 00 */
+	0x24, /* 00 00 00 */
+	0x18, /* 000  000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 236 0xec '\354' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x54, /* 0 0 0 00 */
+	0x54, /* 0 0 0 00 */
+	0x54, /* 0 0 0 00 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 237 0xed '\355' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x04, /* 00000 00 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x38, /* 00   000 */
+	0x40, /* 0 000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 238 0xee '\356' */
+	0x00, /* 00000000 */
+	0x3c, /* 00    00 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x78, /* 0    000 */
+	0x40, /* 0 000000 */
+	0x40, /* 0 000000 */
+	0x3c, /* 00    00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 239 0xef '\357' */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x44, /* 0 000 00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 240 0xf0 '\360' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfc, /*       00 */
+	0x00, /* 00000000 */
+	0xfc, /*       00 */
+	0x00, /* 00000000 */
+	0xfc, /*       00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 241 0xf1 '\361' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x7c, /* 0     00 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x7c, /* 0     00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 242 0xf2 '\362' */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x08, /* 0000 000 */
+	0x04, /* 00000 00 */
+	0x08, /* 0000 000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x1c, /* 000   00 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 243 0xf3 '\363' */
+	0x00, /* 00000000 */
+	0x08, /* 0000 000 */
+	0x10, /* 000 0000 */
+	0x20, /* 00 00000 */
+	0x10, /* 000 0000 */
+	0x08, /* 0000 000 */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 244 0xf4 '\364' */
+	0x00, /* 00000000 */
+	0x0c, /* 0000  00 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+
+	/* 245 0xf5 '\365' */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x10, /* 000 0000 */
+	0x60, /* 0  00000 */
+	0x00, /* 00000000 */
+
+	/* 246 0xf6 '\366' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x7c, /* 0     00 */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 247 0xf7 '\367' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x34, /* 00  0 00 */
+	0x48, /* 0 00 000 */
+	0x00, /* 00000000 */
+	0x34, /* 00  0 00 */
+	0x48, /* 0 00 000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 248 0xf8 '\370' */
+	0x18, /* 000  000 */
+	0x24, /* 00 00 00 */
+	0x24, /* 00 00 00 */
+	0x18, /* 000  000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 249 0xf9 '\371' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x38, /* 00   000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 250 0xfa '\372' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 000 0000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 251 0xfb '\373' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x0c, /* 0000  00 */
+	0x08, /* 0000 000 */
+	0x10, /* 000 0000 */
+	0x50, /* 0 0 0000 */
+	0x20, /* 00 00000 */
+	0x20, /* 00 00000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 252 0xfc '\374' */
+	0x00, /* 00000000 */
+	0x50, /* 0 0 0000 */
+	0x28, /* 00 0 000 */
+	0x28, /* 00 0 000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 253 0xfd '\375' */
+	0x00, /* 00000000 */
+	0x70, /* 0   0000 */
+	0x08, /* 0000 000 */
+	0x20, /* 00 00000 */
+	0x78, /* 0    000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 254 0xfe '\376' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00   000 */
+	0x38, /* 00   000 */
+	0x38, /* 00   000 */
+	0x38, /* 00   000 */
+	0x38, /* 00   000 */
+	0x38, /* 00   000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 255 0xff '\377' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+};
+
+
+struct font_desc font_vga_6x11 = {
+	VGA6x11_IDX,
+	"ProFont6x11",
+	6,
+	11,
+	fontdata_6x11,
+	-2000	/* Try avoiding this font if possible unless on MAC */
+};
diff --git a/drivers/video/console/font_8x16.c b/drivers/video/console/font_8x16.c
new file mode 100644
index 0000000..e6f8dba
--- /dev/null
+++ b/drivers/video/console/font_8x16.c
@@ -0,0 +1,4631 @@
+/**********************************************/
+/*                                            */
+/*       Font file generated by cpi2fnt       */
+/*                                            */
+/**********************************************/
+
+#include <linux/font.h>
+
+#define FONTDATAMAX 4096
+
+static unsigned char fontdata_8x16[FONTDATAMAX] = {
+
+	/* 0 0x00 '^@' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 1 0x01 '^A' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x81, /* 10000001 */
+	0xa5, /* 10100101 */
+	0x81, /* 10000001 */
+	0x81, /* 10000001 */
+	0xbd, /* 10111101 */
+	0x99, /* 10011001 */
+	0x81, /* 10000001 */
+	0x81, /* 10000001 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 2 0x02 '^B' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0xff, /* 11111111 */
+	0xdb, /* 11011011 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xc3, /* 11000011 */
+	0xe7, /* 11100111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 3 0x03 '^C' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x6c, /* 01101100 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0x7c, /* 01111100 */
+	0x38, /* 00111000 */
+	0x10, /* 00010000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 4 0x04 '^D' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x7c, /* 01111100 */
+	0xfe, /* 11111110 */
+	0x7c, /* 01111100 */
+	0x38, /* 00111000 */
+	0x10, /* 00010000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 5 0x05 '^E' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0xe7, /* 11100111 */
+	0xe7, /* 11100111 */
+	0xe7, /* 11100111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 6 0x06 '^F' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x7e, /* 01111110 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 7 0x07 '^G' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 8 0x08 '^H' */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xe7, /* 11100111 */
+	0xc3, /* 11000011 */
+	0xc3, /* 11000011 */
+	0xe7, /* 11100111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+
+	/* 9 0x09 '^I' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x42, /* 01000010 */
+	0x42, /* 01000010 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 10 0x0a '^J' */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xc3, /* 11000011 */
+	0x99, /* 10011001 */
+	0xbd, /* 10111101 */
+	0xbd, /* 10111101 */
+	0x99, /* 10011001 */
+	0xc3, /* 11000011 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+
+	/* 11 0x0b '^K' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1e, /* 00011110 */
+	0x0e, /* 00001110 */
+	0x1a, /* 00011010 */
+	0x32, /* 00110010 */
+	0x78, /* 01111000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x78, /* 01111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 12 0x0c '^L' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 13 0x0d '^M' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3f, /* 00111111 */
+	0x33, /* 00110011 */
+	0x3f, /* 00111111 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x70, /* 01110000 */
+	0xf0, /* 11110000 */
+	0xe0, /* 11100000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 14 0x0e '^N' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7f, /* 01111111 */
+	0x63, /* 01100011 */
+	0x7f, /* 01111111 */
+	0x63, /* 01100011 */
+	0x63, /* 01100011 */
+	0x63, /* 01100011 */
+	0x63, /* 01100011 */
+	0x67, /* 01100111 */
+	0xe7, /* 11100111 */
+	0xe6, /* 11100110 */
+	0xc0, /* 11000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 15 0x0f '^O' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xdb, /* 11011011 */
+	0x3c, /* 00111100 */
+	0xe7, /* 11100111 */
+	0x3c, /* 00111100 */
+	0xdb, /* 11011011 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 16 0x10 '^P' */
+	0x00, /* 00000000 */
+	0x80, /* 10000000 */
+	0xc0, /* 11000000 */
+	0xe0, /* 11100000 */
+	0xf0, /* 11110000 */
+	0xf8, /* 11111000 */
+	0xfe, /* 11111110 */
+	0xf8, /* 11111000 */
+	0xf0, /* 11110000 */
+	0xe0, /* 11100000 */
+	0xc0, /* 11000000 */
+	0x80, /* 10000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 17 0x11 '^Q' */
+	0x00, /* 00000000 */
+	0x02, /* 00000010 */
+	0x06, /* 00000110 */
+	0x0e, /* 00001110 */
+	0x1e, /* 00011110 */
+	0x3e, /* 00111110 */
+	0xfe, /* 11111110 */
+	0x3e, /* 00111110 */
+	0x1e, /* 00011110 */
+	0x0e, /* 00001110 */
+	0x06, /* 00000110 */
+	0x02, /* 00000010 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 18 0x12 '^R' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 19 0x13 '^S' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 20 0x14 '^T' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7f, /* 01111111 */
+	0xdb, /* 11011011 */
+	0xdb, /* 11011011 */
+	0xdb, /* 11011011 */
+	0x7b, /* 01111011 */
+	0x1b, /* 00011011 */
+	0x1b, /* 00011011 */
+	0x1b, /* 00011011 */
+	0x1b, /* 00011011 */
+	0x1b, /* 00011011 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 21 0x15 '^U' */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0x60, /* 01100000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x0c, /* 00001100 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 22 0x16 '^V' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 23 0x17 '^W' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 24 0x18 '^X' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 25 0x19 '^Y' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 26 0x1a '^Z' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0xfe, /* 11111110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 27 0x1b '^[' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xfe, /* 11111110 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 28 0x1c '^\' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 29 0x1d '^]' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x28, /* 00101000 */
+	0x6c, /* 01101100 */
+	0xfe, /* 11111110 */
+	0x6c, /* 01101100 */
+	0x28, /* 00101000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 30 0x1e '^^' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x38, /* 00111000 */
+	0x7c, /* 01111100 */
+	0x7c, /* 01111100 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 31 0x1f '^_' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0x7c, /* 01111100 */
+	0x7c, /* 01111100 */
+	0x38, /* 00111000 */
+	0x38, /* 00111000 */
+	0x10, /* 00010000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 32 0x20 ' ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 33 0x21 '!' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 34 0x22 '"' */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x24, /* 00100100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 35 0x23 '#' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0xfe, /* 11111110 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0xfe, /* 11111110 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 36 0x24 '$' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc2, /* 11000010 */
+	0xc0, /* 11000000 */
+	0x7c, /* 01111100 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x86, /* 10000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 37 0x25 '%' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc2, /* 11000010 */
+	0xc6, /* 11000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xc6, /* 11000110 */
+	0x86, /* 10000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 38 0x26 '&' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 39 0x27 ''' */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 40 0x28 '(' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 41 0x29 ')' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 42 0x2a '*' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0xff, /* 11111111 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 43 0x2b '+' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 44 0x2c ',' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 45 0x2d '-' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 46 0x2e '.' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 47 0x2f '/' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x02, /* 00000010 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xc0, /* 11000000 */
+	0x80, /* 10000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 48 0x30 '0' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 49 0x31 '1' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x38, /* 00111000 */
+	0x78, /* 01111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 50 0x32 '2' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 51 0x33 '3' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x3c, /* 00111100 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 52 0x34 '4' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x0c, /* 00001100 */
+	0x1c, /* 00011100 */
+	0x3c, /* 00111100 */
+	0x6c, /* 01101100 */
+	0xcc, /* 11001100 */
+	0xfe, /* 11111110 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x1e, /* 00011110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 53 0x35 '5' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xfc, /* 11111100 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 54 0x36 '6' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x60, /* 01100000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xfc, /* 11111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 55 0x37 '7' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 56 0x38 '8' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 57 0x39 '9' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7e, /* 01111110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x78, /* 01111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 58 0x3a ':' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 59 0x3b ';' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 60 0x3c '<' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x06, /* 00000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 61 0x3d '=' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 62 0x3e '>' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 63 0x3f '?' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 64 0x40 '@' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xde, /* 11011110 */
+	0xde, /* 11011110 */
+	0xde, /* 11011110 */
+	0xdc, /* 11011100 */
+	0xc0, /* 11000000 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 65 0x41 'A' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 66 0x42 'B' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfc, /* 11111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x7c, /* 01111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0xfc, /* 11111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 67 0x43 'C' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0xc2, /* 11000010 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc2, /* 11000010 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 68 0x44 'D' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xf8, /* 11111000 */
+	0x6c, /* 01101100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x6c, /* 01101100 */
+	0xf8, /* 11111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 69 0x45 'E' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x66, /* 01100110 */
+	0x62, /* 01100010 */
+	0x68, /* 01101000 */
+	0x78, /* 01111000 */
+	0x68, /* 01101000 */
+	0x60, /* 01100000 */
+	0x62, /* 01100010 */
+	0x66, /* 01100110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 70 0x46 'F' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x66, /* 01100110 */
+	0x62, /* 01100010 */
+	0x68, /* 01101000 */
+	0x78, /* 01111000 */
+	0x68, /* 01101000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0xf0, /* 11110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 71 0x47 'G' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0xc2, /* 11000010 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xde, /* 11011110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x66, /* 01100110 */
+	0x3a, /* 00111010 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 72 0x48 'H' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 73 0x49 'I' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 74 0x4a 'J' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1e, /* 00011110 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x78, /* 01111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 75 0x4b 'K' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xe6, /* 11100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x6c, /* 01101100 */
+	0x78, /* 01111000 */
+	0x78, /* 01111000 */
+	0x6c, /* 01101100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0xe6, /* 11100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 76 0x4c 'L' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xf0, /* 11110000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x62, /* 01100010 */
+	0x66, /* 01100110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 77 0x4d 'M' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xee, /* 11101110 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0xd6, /* 11010110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 78 0x4e 'N' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xe6, /* 11100110 */
+	0xf6, /* 11110110 */
+	0xfe, /* 11111110 */
+	0xde, /* 11011110 */
+	0xce, /* 11001110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 79 0x4f 'O' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 80 0x50 'P' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfc, /* 11111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x7c, /* 01111100 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0xf0, /* 11110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 81 0x51 'Q' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xd6, /* 11010110 */
+	0xde, /* 11011110 */
+	0x7c, /* 01111100 */
+	0x0c, /* 00001100 */
+	0x0e, /* 00001110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 82 0x52 'R' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfc, /* 11111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x7c, /* 01111100 */
+	0x6c, /* 01101100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0xe6, /* 11100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 83 0x53 'S' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x60, /* 01100000 */
+	0x38, /* 00111000 */
+	0x0c, /* 00001100 */
+	0x06, /* 00000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 84 0x54 'T' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x5a, /* 01011010 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 85 0x55 'U' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 86 0x56 'V' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x10, /* 00010000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 87 0x57 'W' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xfe, /* 11111110 */
+	0xee, /* 11101110 */
+	0x6c, /* 01101100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 88 0x58 'X' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x7c, /* 01111100 */
+	0x38, /* 00111000 */
+	0x38, /* 00111000 */
+	0x7c, /* 01111100 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 89 0x59 'Y' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 90 0x5a 'Z' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0x86, /* 10000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xc2, /* 11000010 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 91 0x5b '[' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 92 0x5c '\' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x80, /* 10000000 */
+	0xc0, /* 11000000 */
+	0xe0, /* 11100000 */
+	0x70, /* 01110000 */
+	0x38, /* 00111000 */
+	0x1c, /* 00011100 */
+	0x0e, /* 00001110 */
+	0x06, /* 00000110 */
+	0x02, /* 00000010 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 93 0x5d ']' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 94 0x5e '^' */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 95 0x5f '_' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 96 0x60 '`' */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 97 0x61 'a' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x7c, /* 01111100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 98 0x62 'b' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xe0, /* 11100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x78, /* 01111000 */
+	0x6c, /* 01101100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 99 0x63 'c' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 100 0x64 'd' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1c, /* 00011100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x3c, /* 00111100 */
+	0x6c, /* 01101100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 101 0x65 'e' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 102 0x66 'f' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1c, /* 00011100 */
+	0x36, /* 00110110 */
+	0x32, /* 00110010 */
+	0x30, /* 00110000 */
+	0x78, /* 01111000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x78, /* 01111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 103 0x67 'g' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x7c, /* 01111100 */
+	0x0c, /* 00001100 */
+	0xcc, /* 11001100 */
+	0x78, /* 01111000 */
+	0x00, /* 00000000 */
+
+	/* 104 0x68 'h' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xe0, /* 11100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x6c, /* 01101100 */
+	0x76, /* 01110110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0xe6, /* 11100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 105 0x69 'i' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 106 0x6a 'j' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x00, /* 00000000 */
+	0x0e, /* 00001110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+
+	/* 107 0x6b 'k' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xe0, /* 11100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x66, /* 01100110 */
+	0x6c, /* 01101100 */
+	0x78, /* 01111000 */
+	0x78, /* 01111000 */
+	0x6c, /* 01101100 */
+	0x66, /* 01100110 */
+	0xe6, /* 11100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 108 0x6c 'l' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 109 0x6d 'm' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xec, /* 11101100 */
+	0xfe, /* 11111110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 110 0x6e 'n' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xdc, /* 11011100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 111 0x6f 'o' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 112 0x70 'p' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xdc, /* 11011100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x7c, /* 01111100 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0xf0, /* 11110000 */
+	0x00, /* 00000000 */
+
+	/* 113 0x71 'q' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x7c, /* 01111100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x1e, /* 00011110 */
+	0x00, /* 00000000 */
+
+	/* 114 0x72 'r' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xdc, /* 11011100 */
+	0x76, /* 01110110 */
+	0x66, /* 01100110 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0xf0, /* 11110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 115 0x73 's' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0x60, /* 01100000 */
+	0x38, /* 00111000 */
+	0x0c, /* 00001100 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 116 0x74 't' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0xfc, /* 11111100 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x36, /* 00110110 */
+	0x1c, /* 00011100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 117 0x75 'u' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 118 0x76 'v' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 119 0x77 'w' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xfe, /* 11111110 */
+	0x6c, /* 01101100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 120 0x78 'x' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x38, /* 00111000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 121 0x79 'y' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7e, /* 01111110 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0xf8, /* 11111000 */
+	0x00, /* 00000000 */
+
+	/* 122 0x7a 'z' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xcc, /* 11001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 123 0x7b '{' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x0e, /* 00001110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x70, /* 01110000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x0e, /* 00001110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 124 0x7c '|' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 125 0x7d '}' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x70, /* 01110000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x0e, /* 00001110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x70, /* 01110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 126 0x7e '~' */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 127 0x7f '' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 128 0x80 '€' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0xc2, /* 11000010 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc2, /* 11000010 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x70, /* 01110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 129 0x81 '' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xcc, /* 11001100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 130 0x82 '‚' */
+	0x00, /* 00000000 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 131 0x83 'ƒ' */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x00, /* 00000000 */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x7c, /* 01111100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 132 0x84 '„' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xcc, /* 11001100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x7c, /* 01111100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 133 0x85 '…' */
+	0x00, /* 00000000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x7c, /* 01111100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 134 0x86 '†' */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x00, /* 00000000 */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x7c, /* 01111100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 135 0x87 '‡' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x18, /* 00011000 */
+	0x70, /* 01110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 136 0x88 'ˆ' */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 137 0x89 '‰' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 138 0x8a 'Š' */
+	0x00, /* 00000000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 139 0x8b '‹' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 140 0x8c 'Œ' */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 141 0x8d '' */
+	0x00, /* 00000000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 142 0x8e 'Ž' */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 143 0x8f '' */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 144 0x90 '' */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x66, /* 01100110 */
+	0x62, /* 01100010 */
+	0x68, /* 01101000 */
+	0x78, /* 01111000 */
+	0x68, /* 01101000 */
+	0x62, /* 01100010 */
+	0x66, /* 01100110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 145 0x91 '‘' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xec, /* 11101100 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x7e, /* 01111110 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0x6e, /* 01101110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 146 0x92 '’' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3e, /* 00111110 */
+	0x6c, /* 01101100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xfe, /* 11111110 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xce, /* 11001110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 147 0x93 '“' */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 148 0x94 '”' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 149 0x95 '•' */
+	0x00, /* 00000000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 150 0x96 '–' */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x78, /* 01111000 */
+	0xcc, /* 11001100 */
+	0x00, /* 00000000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 151 0x97 '—' */
+	0x00, /* 00000000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 152 0x98 '˜' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7e, /* 01111110 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x78, /* 01111000 */
+	0x00, /* 00000000 */
+
+	/* 153 0x99 '™' */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 154 0x9a 'š' */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 155 0x9b '›' */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 156 0x9c 'œ' */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x64, /* 01100100 */
+	0x60, /* 01100000 */
+	0xf0, /* 11110000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0xe6, /* 11100110 */
+	0xfc, /* 11111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 157 0x9d '' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 158 0x9e 'ž' */
+	0x00, /* 00000000 */
+	0xf8, /* 11111000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xf8, /* 11111000 */
+	0xc4, /* 11000100 */
+	0xcc, /* 11001100 */
+	0xde, /* 11011110 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 159 0x9f 'Ÿ' */
+	0x00, /* 00000000 */
+	0x0e, /* 00001110 */
+	0x1b, /* 00011011 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xd8, /* 11011000 */
+	0x70, /* 01110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 160 0xa0 ' ' */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x00, /* 00000000 */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x7c, /* 01111100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 161 0xa1 '¡' */
+	0x00, /* 00000000 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 162 0xa2 '¢' */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 163 0xa3 '£' */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x00, /* 00000000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 164 0xa4 '¤' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0x00, /* 00000000 */
+	0xdc, /* 11011100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 165 0xa5 '¥' */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xe6, /* 11100110 */
+	0xf6, /* 11110110 */
+	0xfe, /* 11111110 */
+	0xde, /* 11011110 */
+	0xce, /* 11001110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 166 0xa6 '¦' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x3e, /* 00111110 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 167 0xa7 '§' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 168 0xa8 '¨' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 169 0xa9 '©' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 170 0xaa 'ª' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 171 0xab '«' */
+	0x00, /* 00000000 */
+	0x60, /* 01100000 */
+	0xe0, /* 11100000 */
+	0x62, /* 01100010 */
+	0x66, /* 01100110 */
+	0x6c, /* 01101100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xdc, /* 11011100 */
+	0x86, /* 10000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x3e, /* 00111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 172 0xac '¬' */
+	0x00, /* 00000000 */
+	0x60, /* 01100000 */
+	0xe0, /* 11100000 */
+	0x62, /* 01100010 */
+	0x66, /* 01100110 */
+	0x6c, /* 01101100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x66, /* 01100110 */
+	0xce, /* 11001110 */
+	0x9a, /* 10011010 */
+	0x3f, /* 00111111 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 173 0xad '­' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 174 0xae '®' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x36, /* 00110110 */
+	0x6c, /* 01101100 */
+	0xd8, /* 11011000 */
+	0x6c, /* 01101100 */
+	0x36, /* 00110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 175 0xaf '¯' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xd8, /* 11011000 */
+	0x6c, /* 01101100 */
+	0x36, /* 00110110 */
+	0x6c, /* 01101100 */
+	0xd8, /* 11011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 176 0xb0 '°' */
+	0x11, /* 00010001 */
+	0x44, /* 01000100 */
+	0x11, /* 00010001 */
+	0x44, /* 01000100 */
+	0x11, /* 00010001 */
+	0x44, /* 01000100 */
+	0x11, /* 00010001 */
+	0x44, /* 01000100 */
+	0x11, /* 00010001 */
+	0x44, /* 01000100 */
+	0x11, /* 00010001 */
+	0x44, /* 01000100 */
+	0x11, /* 00010001 */
+	0x44, /* 01000100 */
+	0x11, /* 00010001 */
+	0x44, /* 01000100 */
+
+	/* 177 0xb1 '±' */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+
+	/* 178 0xb2 '²' */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+
+	/* 179 0xb3 '³' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 180 0xb4 '´' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 181 0xb5 'µ' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 182 0xb6 '¶' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xf6, /* 11110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 183 0xb7 '·' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 184 0xb8 '¸' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 185 0xb9 '¹' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xf6, /* 11110110 */
+	0x06, /* 00000110 */
+	0xf6, /* 11110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 186 0xba 'º' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 187 0xbb '»' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x06, /* 00000110 */
+	0xf6, /* 11110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 188 0xbc '¼' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xf6, /* 11110110 */
+	0x06, /* 00000110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 189 0xbd '½' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 190 0xbe '¾' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 191 0xbf '¿' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 192 0xc0 'À' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 193 0xc1 'Á' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 194 0xc2 'Â' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 195 0xc3 'Ã' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 196 0xc4 'Ä' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 197 0xc5 'Å' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xff, /* 11111111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 198 0xc6 'Æ' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 199 0xc7 'Ç' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x37, /* 00110111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 200 0xc8 'È' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x37, /* 00110111 */
+	0x30, /* 00110000 */
+	0x3f, /* 00111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 201 0xc9 'É' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3f, /* 00111111 */
+	0x30, /* 00110000 */
+	0x37, /* 00110111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 202 0xca 'Ê' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xf7, /* 11110111 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 203 0xcb 'Ë' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0xf7, /* 11110111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 204 0xcc 'Ì' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x37, /* 00110111 */
+	0x30, /* 00110000 */
+	0x37, /* 00110111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 205 0xcd 'Í' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 206 0xce 'Î' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xf7, /* 11110111 */
+	0x00, /* 00000000 */
+	0xf7, /* 11110111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 207 0xcf 'Ï' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 208 0xd0 'Ð' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 209 0xd1 'Ñ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 210 0xd2 'Ò' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 211 0xd3 'Ó' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x3f, /* 00111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 212 0xd4 'Ô' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 213 0xd5 'Õ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 214 0xd6 'Ö' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3f, /* 00111111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 215 0xd7 '×' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xff, /* 11111111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 216 0xd8 'Ø' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xff, /* 11111111 */
+	0x18, /* 00011000 */
+	0xff, /* 11111111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 217 0xd9 'Ù' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 218 0xda 'Ú' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 219 0xdb 'Û' */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+
+	/* 220 0xdc 'Ü' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+
+	/* 221 0xdd 'Ý' */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+
+	/* 222 0xde 'Þ' */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+
+	/* 223 0xdf 'ß' */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 224 0xe0 'à' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0xdc, /* 11011100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 225 0xe1 'á' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x78, /* 01111000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xd8, /* 11011000 */
+	0xcc, /* 11001100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xcc, /* 11001100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 226 0xe2 'â' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 227 0xe3 'ã' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 228 0xe4 'ä' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 229 0xe5 'å' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0x70, /* 01110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 230 0xe6 'æ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x7c, /* 01111100 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0xc0, /* 11000000 */
+	0x00, /* 00000000 */
+
+	/* 231 0xe7 'ç' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 232 0xe8 'è' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 233 0xe9 'é' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 234 0xea 'ê' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0xee, /* 11101110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 235 0xeb 'ë' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1e, /* 00011110 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x3e, /* 00111110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 236 0xec 'ì' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0xdb, /* 11011011 */
+	0xdb, /* 11011011 */
+	0xdb, /* 11011011 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 237 0xed 'í' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x03, /* 00000011 */
+	0x06, /* 00000110 */
+	0x7e, /* 01111110 */
+	0xdb, /* 11011011 */
+	0xdb, /* 11011011 */
+	0xf3, /* 11110011 */
+	0x7e, /* 01111110 */
+	0x60, /* 01100000 */
+	0xc0, /* 11000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 238 0xee 'î' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1c, /* 00011100 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x7c, /* 01111100 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x1c, /* 00011100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 239 0xef 'ï' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 240 0xf0 'ð' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 241 0xf1 'ñ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 242 0xf2 'ò' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 243 0xf3 'ó' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 244 0xf4 'ô' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x0e, /* 00001110 */
+	0x1b, /* 00011011 */
+	0x1b, /* 00011011 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 245 0xf5 'õ' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0x70, /* 01110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 246 0xf6 'ö' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 247 0xf7 '÷' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 248 0xf8 'ø' */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 249 0xf9 'ù' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 250 0xfa 'ú' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 251 0xfb 'û' */
+	0x00, /* 00000000 */
+	0x0f, /* 00001111 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0xec, /* 11101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x3c, /* 00111100 */
+	0x1c, /* 00011100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 252 0xfc 'ü' */
+	0x00, /* 00000000 */
+	0x6c, /* 01101100 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 253 0xfd 'ý' */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x32, /* 00110010 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 254 0xfe 'þ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 255 0xff 'ÿ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+};
+
+
+struct font_desc font_vga_8x16 = {
+	VGA8x16_IDX,
+	"VGA8x16",
+	8,
+	16,
+	fontdata_8x16,
+	0
+};
diff --git a/drivers/video/console/font_8x8.c b/drivers/video/console/font_8x8.c
new file mode 100644
index 0000000..57fbe26
--- /dev/null
+++ b/drivers/video/console/font_8x8.c
@@ -0,0 +1,2583 @@
+/**********************************************/
+/*                                            */
+/*       Font file generated by cpi2fnt       */
+/*                                            */
+/**********************************************/
+
+#include <linux/font.h>
+
+#define FONTDATAMAX 2048
+
+static unsigned char fontdata_8x8[FONTDATAMAX] = {
+
+	/* 0 0x00 '^@' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 1 0x01 '^A' */
+	0x7e, /* 01111110 */
+	0x81, /* 10000001 */
+	0xa5, /* 10100101 */
+	0x81, /* 10000001 */
+	0xbd, /* 10111101 */
+	0x99, /* 10011001 */
+	0x81, /* 10000001 */
+	0x7e, /* 01111110 */
+
+	/* 2 0x02 '^B' */
+	0x7e, /* 01111110 */
+	0xff, /* 11111111 */
+	0xdb, /* 11011011 */
+	0xff, /* 11111111 */
+	0xc3, /* 11000011 */
+	0xe7, /* 11100111 */
+	0xff, /* 11111111 */
+	0x7e, /* 01111110 */
+
+	/* 3 0x03 '^C' */
+	0x6c, /* 01101100 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0x7c, /* 01111100 */
+	0x38, /* 00111000 */
+	0x10, /* 00010000 */
+	0x00, /* 00000000 */
+
+	/* 4 0x04 '^D' */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x7c, /* 01111100 */
+	0xfe, /* 11111110 */
+	0x7c, /* 01111100 */
+	0x38, /* 00111000 */
+	0x10, /* 00010000 */
+	0x00, /* 00000000 */
+
+	/* 5 0x05 '^E' */
+	0x38, /* 00111000 */
+	0x7c, /* 01111100 */
+	0x38, /* 00111000 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0xd6, /* 11010110 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+
+	/* 6 0x06 '^F' */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x7c, /* 01111100 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0x7c, /* 01111100 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+
+	/* 7 0x07 '^G' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 8 0x08 '^H' */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xe7, /* 11100111 */
+	0xc3, /* 11000011 */
+	0xc3, /* 11000011 */
+	0xe7, /* 11100111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+
+	/* 9 0x09 '^I' */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x42, /* 01000010 */
+	0x42, /* 01000010 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+
+	/* 10 0x0a '^J' */
+	0xff, /* 11111111 */
+	0xc3, /* 11000011 */
+	0x99, /* 10011001 */
+	0xbd, /* 10111101 */
+	0xbd, /* 10111101 */
+	0x99, /* 10011001 */
+	0xc3, /* 11000011 */
+	0xff, /* 11111111 */
+
+	/* 11 0x0b '^K' */
+	0x0f, /* 00001111 */
+	0x07, /* 00000111 */
+	0x0f, /* 00001111 */
+	0x7d, /* 01111101 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x78, /* 01111000 */
+
+	/* 12 0x0c '^L' */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+
+	/* 13 0x0d '^M' */
+	0x3f, /* 00111111 */
+	0x33, /* 00110011 */
+	0x3f, /* 00111111 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x70, /* 01110000 */
+	0xf0, /* 11110000 */
+	0xe0, /* 11100000 */
+
+	/* 14 0x0e '^N' */
+	0x7f, /* 01111111 */
+	0x63, /* 01100011 */
+	0x7f, /* 01111111 */
+	0x63, /* 01100011 */
+	0x63, /* 01100011 */
+	0x67, /* 01100111 */
+	0xe6, /* 11100110 */
+	0xc0, /* 11000000 */
+
+	/* 15 0x0f '^O' */
+	0x18, /* 00011000 */
+	0xdb, /* 11011011 */
+	0x3c, /* 00111100 */
+	0xe7, /* 11100111 */
+	0xe7, /* 11100111 */
+	0x3c, /* 00111100 */
+	0xdb, /* 11011011 */
+	0x18, /* 00011000 */
+
+	/* 16 0x10 '^P' */
+	0x80, /* 10000000 */
+	0xe0, /* 11100000 */
+	0xf8, /* 11111000 */
+	0xfe, /* 11111110 */
+	0xf8, /* 11111000 */
+	0xe0, /* 11100000 */
+	0x80, /* 10000000 */
+	0x00, /* 00000000 */
+
+	/* 17 0x11 '^Q' */
+	0x02, /* 00000010 */
+	0x0e, /* 00001110 */
+	0x3e, /* 00111110 */
+	0xfe, /* 11111110 */
+	0x3e, /* 00111110 */
+	0x0e, /* 00001110 */
+	0x02, /* 00000010 */
+	0x00, /* 00000000 */
+
+	/* 18 0x12 '^R' */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+
+	/* 19 0x13 '^S' */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+
+	/* 20 0x14 '^T' */
+	0x7f, /* 01111111 */
+	0xdb, /* 11011011 */
+	0xdb, /* 11011011 */
+	0x7b, /* 01111011 */
+	0x1b, /* 00011011 */
+	0x1b, /* 00011011 */
+	0x1b, /* 00011011 */
+	0x00, /* 00000000 */
+
+	/* 21 0x15 '^U' */
+	0x3e, /* 00111110 */
+	0x61, /* 01100001 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x86, /* 10000110 */
+	0x7c, /* 01111100 */
+
+	/* 22 0x16 '^V' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+
+	/* 23 0x17 '^W' */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0xff, /* 11111111 */
+
+	/* 24 0x18 '^X' */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+
+	/* 25 0x19 '^Y' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+
+	/* 26 0x1a '^Z' */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0xfe, /* 11111110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 27 0x1b '^[' */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xfe, /* 11111110 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 28 0x1c '^\' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 29 0x1d '^]' */
+	0x00, /* 00000000 */
+	0x24, /* 00100100 */
+	0x66, /* 01100110 */
+	0xff, /* 11111111 */
+	0x66, /* 01100110 */
+	0x24, /* 00100100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 30 0x1e '^^' */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x7e, /* 01111110 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 31 0x1f '^_' */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0x7e, /* 01111110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 32 0x20 ' ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 33 0x21 '!' */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+
+	/* 34 0x22 '"' */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x24, /* 00100100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 35 0x23 '#' */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0xfe, /* 11111110 */
+	0x6c, /* 01101100 */
+	0xfe, /* 11111110 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x00, /* 00000000 */
+
+	/* 36 0x24 '$' */
+	0x18, /* 00011000 */
+	0x3e, /* 00111110 */
+	0x60, /* 01100000 */
+	0x3c, /* 00111100 */
+	0x06, /* 00000110 */
+	0x7c, /* 01111100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+
+	/* 37 0x25 '%' */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xcc, /* 11001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x66, /* 01100110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+
+	/* 38 0x26 '&' */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+
+	/* 39 0x27 ''' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 40 0x28 '(' */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x00, /* 00000000 */
+
+	/* 41 0x29 ')' */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+
+	/* 42 0x2a '*' */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0xff, /* 11111111 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 43 0x2b '+' */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 44 0x2c ',' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+
+	/* 45 0x2d '-' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 46 0x2e '.' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+
+	/* 47 0x2f '/' */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xc0, /* 11000000 */
+	0x80, /* 10000000 */
+	0x00, /* 00000000 */
+
+	/* 48 0x30 '0' */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xd6, /* 11010110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x00, /* 00000000 */
+
+	/* 49 0x31 '1' */
+	0x18, /* 00011000 */
+	0x38, /* 00111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+
+	/* 50 0x32 '2' */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0x06, /* 00000110 */
+	0x1c, /* 00011100 */
+	0x30, /* 00110000 */
+	0x66, /* 01100110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+
+	/* 51 0x33 '3' */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0x06, /* 00000110 */
+	0x3c, /* 00111100 */
+	0x06, /* 00000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+
+	/* 52 0x34 '4' */
+	0x1c, /* 00011100 */
+	0x3c, /* 00111100 */
+	0x6c, /* 01101100 */
+	0xcc, /* 11001100 */
+	0xfe, /* 11111110 */
+	0x0c, /* 00001100 */
+	0x1e, /* 00011110 */
+	0x00, /* 00000000 */
+
+	/* 53 0x35 '5' */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xfc, /* 11111100 */
+	0x06, /* 00000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+
+	/* 54 0x36 '6' */
+	0x38, /* 00111000 */
+	0x60, /* 01100000 */
+	0xc0, /* 11000000 */
+	0xfc, /* 11111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+
+	/* 55 0x37 '7' */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+
+	/* 56 0x38 '8' */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+
+	/* 57 0x39 '9' */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7e, /* 01111110 */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x78, /* 01111000 */
+	0x00, /* 00000000 */
+
+	/* 58 0x3a ':' */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+
+	/* 59 0x3b ';' */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+
+	/* 60 0x3c '<' */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x06, /* 00000110 */
+	0x00, /* 00000000 */
+
+	/* 61 0x3d '=' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 62 0x3e '>' */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x00, /* 00000000 */
+
+	/* 63 0x3f '?' */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+
+	/* 64 0x40 '@' */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xde, /* 11011110 */
+	0xde, /* 11011110 */
+	0xde, /* 11011110 */
+	0xc0, /* 11000000 */
+	0x78, /* 01111000 */
+	0x00, /* 00000000 */
+
+	/* 65 0x41 'A' */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+
+	/* 66 0x42 'B' */
+	0xfc, /* 11111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x7c, /* 01111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0xfc, /* 11111100 */
+	0x00, /* 00000000 */
+
+	/* 67 0x43 'C' */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+
+	/* 68 0x44 'D' */
+	0xf8, /* 11111000 */
+	0x6c, /* 01101100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x6c, /* 01101100 */
+	0xf8, /* 11111000 */
+	0x00, /* 00000000 */
+
+	/* 69 0x45 'E' */
+	0xfe, /* 11111110 */
+	0x62, /* 01100010 */
+	0x68, /* 01101000 */
+	0x78, /* 01111000 */
+	0x68, /* 01101000 */
+	0x62, /* 01100010 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+
+	/* 70 0x46 'F' */
+	0xfe, /* 11111110 */
+	0x62, /* 01100010 */
+	0x68, /* 01101000 */
+	0x78, /* 01111000 */
+	0x68, /* 01101000 */
+	0x60, /* 01100000 */
+	0xf0, /* 11110000 */
+	0x00, /* 00000000 */
+
+	/* 71 0x47 'G' */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xce, /* 11001110 */
+	0x66, /* 01100110 */
+	0x3a, /* 00111010 */
+	0x00, /* 00000000 */
+
+	/* 72 0x48 'H' */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+
+	/* 73 0x49 'I' */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+
+	/* 74 0x4a 'J' */
+	0x1e, /* 00011110 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x78, /* 01111000 */
+	0x00, /* 00000000 */
+
+	/* 75 0x4b 'K' */
+	0xe6, /* 11100110 */
+	0x66, /* 01100110 */
+	0x6c, /* 01101100 */
+	0x78, /* 01111000 */
+	0x6c, /* 01101100 */
+	0x66, /* 01100110 */
+	0xe6, /* 11100110 */
+	0x00, /* 00000000 */
+
+	/* 76 0x4c 'L' */
+	0xf0, /* 11110000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0x62, /* 01100010 */
+	0x66, /* 01100110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+
+	/* 77 0x4d 'M' */
+	0xc6, /* 11000110 */
+	0xee, /* 11101110 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0xd6, /* 11010110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+
+	/* 78 0x4e 'N' */
+	0xc6, /* 11000110 */
+	0xe6, /* 11100110 */
+	0xf6, /* 11110110 */
+	0xde, /* 11011110 */
+	0xce, /* 11001110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+
+	/* 79 0x4f 'O' */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+
+	/* 80 0x50 'P' */
+	0xfc, /* 11111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x7c, /* 01111100 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0xf0, /* 11110000 */
+	0x00, /* 00000000 */
+
+	/* 81 0x51 'Q' */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xce, /* 11001110 */
+	0x7c, /* 01111100 */
+	0x0e, /* 00001110 */
+
+	/* 82 0x52 'R' */
+	0xfc, /* 11111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x7c, /* 01111100 */
+	0x6c, /* 01101100 */
+	0x66, /* 01100110 */
+	0xe6, /* 11100110 */
+	0x00, /* 00000000 */
+
+	/* 83 0x53 'S' */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+
+	/* 84 0x54 'T' */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x5a, /* 01011010 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+
+	/* 85 0x55 'U' */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+
+	/* 86 0x56 'V' */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x00, /* 00000000 */
+
+	/* 87 0x57 'W' */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xfe, /* 11111110 */
+	0x6c, /* 01101100 */
+	0x00, /* 00000000 */
+
+	/* 88 0x58 'X' */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+
+	/* 89 0x59 'Y' */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+
+	/* 90 0x5a 'Z' */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0x8c, /* 10001100 */
+	0x18, /* 00011000 */
+	0x32, /* 00110010 */
+	0x66, /* 01100110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+
+	/* 91 0x5b '[' */
+	0x3c, /* 00111100 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+
+	/* 92 0x5c '\' */
+	0xc0, /* 11000000 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x06, /* 00000110 */
+	0x02, /* 00000010 */
+	0x00, /* 00000000 */
+
+	/* 93 0x5d ']' */
+	0x3c, /* 00111100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+
+	/* 94 0x5e '^' */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 95 0x5f '_' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+
+	/* 96 0x60 '`' */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 97 0x61 'a' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x7c, /* 01111100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+
+	/* 98 0x62 'b' */
+	0xe0, /* 11100000 */
+	0x60, /* 01100000 */
+	0x7c, /* 01111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0xdc, /* 11011100 */
+	0x00, /* 00000000 */
+
+	/* 99 0x63 'c' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+
+	/* 100 0x64 'd' */
+	0x1c, /* 00011100 */
+	0x0c, /* 00001100 */
+	0x7c, /* 01111100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+
+	/* 101 0x65 'e' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+
+	/* 102 0x66 'f' */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x60, /* 01100000 */
+	0xf8, /* 11111000 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0xf0, /* 11110000 */
+	0x00, /* 00000000 */
+
+	/* 103 0x67 'g' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x7c, /* 01111100 */
+	0x0c, /* 00001100 */
+	0xf8, /* 11111000 */
+
+	/* 104 0x68 'h' */
+	0xe0, /* 11100000 */
+	0x60, /* 01100000 */
+	0x6c, /* 01101100 */
+	0x76, /* 01110110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0xe6, /* 11100110 */
+	0x00, /* 00000000 */
+
+	/* 105 0x69 'i' */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+
+	/* 106 0x6a 'j' */
+	0x06, /* 00000110 */
+	0x00, /* 00000000 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+
+	/* 107 0x6b 'k' */
+	0xe0, /* 11100000 */
+	0x60, /* 01100000 */
+	0x66, /* 01100110 */
+	0x6c, /* 01101100 */
+	0x78, /* 01111000 */
+	0x6c, /* 01101100 */
+	0xe6, /* 11100110 */
+	0x00, /* 00000000 */
+
+	/* 108 0x6c 'l' */
+	0x38, /* 00111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+
+	/* 109 0x6d 'm' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xec, /* 11101100 */
+	0xfe, /* 11111110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0x00, /* 00000000 */
+
+	/* 110 0x6e 'n' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xdc, /* 11011100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+
+	/* 111 0x6f 'o' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+
+	/* 112 0x70 'p' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xdc, /* 11011100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x7c, /* 01111100 */
+	0x60, /* 01100000 */
+	0xf0, /* 11110000 */
+
+	/* 113 0x71 'q' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x7c, /* 01111100 */
+	0x0c, /* 00001100 */
+	0x1e, /* 00011110 */
+
+	/* 114 0x72 'r' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xdc, /* 11011100 */
+	0x76, /* 01110110 */
+	0x60, /* 01100000 */
+	0x60, /* 01100000 */
+	0xf0, /* 11110000 */
+	0x00, /* 00000000 */
+
+	/* 115 0x73 's' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0xc0, /* 11000000 */
+	0x7c, /* 01111100 */
+	0x06, /* 00000110 */
+	0xfc, /* 11111100 */
+	0x00, /* 00000000 */
+
+	/* 116 0x74 't' */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0xfc, /* 11111100 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x36, /* 00110110 */
+	0x1c, /* 00011100 */
+	0x00, /* 00000000 */
+
+	/* 117 0x75 'u' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+
+	/* 118 0x76 'v' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x00, /* 00000000 */
+
+	/* 119 0x77 'w' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xd6, /* 11010110 */
+	0xd6, /* 11010110 */
+	0xfe, /* 11111110 */
+	0x6c, /* 01101100 */
+	0x00, /* 00000000 */
+
+	/* 120 0x78 'x' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+
+	/* 121 0x79 'y' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7e, /* 01111110 */
+	0x06, /* 00000110 */
+	0xfc, /* 11111100 */
+
+	/* 122 0x7a 'z' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x4c, /* 01001100 */
+	0x18, /* 00011000 */
+	0x32, /* 00110010 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+
+	/* 123 0x7b '{' */
+	0x0e, /* 00001110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x70, /* 01110000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x0e, /* 00001110 */
+	0x00, /* 00000000 */
+
+	/* 124 0x7c '|' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+
+	/* 125 0x7d '}' */
+	0x70, /* 01110000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x0e, /* 00001110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x70, /* 01110000 */
+	0x00, /* 00000000 */
+
+	/* 126 0x7e '~' */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 127 0x7f '' */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+
+	/* 128 0x80 '€' */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x0c, /* 00001100 */
+	0x78, /* 01111000 */
+
+	/* 129 0x81 '' */
+	0xcc, /* 11001100 */
+	0x00, /* 00000000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+
+	/* 130 0x82 '‚' */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+
+	/* 131 0x83 'ƒ' */
+	0x7c, /* 01111100 */
+	0x82, /* 10000010 */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x7c, /* 01111100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+
+	/* 132 0x84 '„' */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x7c, /* 01111100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+
+	/* 133 0x85 '…' */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x7c, /* 01111100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+
+	/* 134 0x86 '†' */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x7c, /* 01111100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+
+	/* 135 0x87 '‡' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0x7e, /* 01111110 */
+	0x0c, /* 00001100 */
+	0x38, /* 00111000 */
+
+	/* 136 0x88 'ˆ' */
+	0x7c, /* 01111100 */
+	0x82, /* 10000010 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+
+	/* 137 0x89 '‰' */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+
+	/* 138 0x8a 'Š' */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+
+	/* 139 0x8b '‹' */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+
+	/* 140 0x8c 'Œ' */
+	0x7c, /* 01111100 */
+	0x82, /* 10000010 */
+	0x38, /* 00111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+
+	/* 141 0x8d '' */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+
+	/* 142 0x8e 'Ž' */
+	0xc6, /* 11000110 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+
+	/* 143 0x8f '' */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+
+	/* 144 0x90 '' */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0xf8, /* 11111000 */
+	0xc0, /* 11000000 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+
+	/* 145 0x91 '‘' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0xd8, /* 11011000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+
+	/* 146 0x92 '’' */
+	0x3e, /* 00111110 */
+	0x6c, /* 01101100 */
+	0xcc, /* 11001100 */
+	0xfe, /* 11111110 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xce, /* 11001110 */
+	0x00, /* 00000000 */
+
+	/* 147 0x93 '“' */
+	0x7c, /* 01111100 */
+	0x82, /* 10000010 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+
+	/* 148 0x94 '”' */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+
+	/* 149 0x95 '•' */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+
+	/* 150 0x96 '–' */
+	0x78, /* 01111000 */
+	0x84, /* 10000100 */
+	0x00, /* 00000000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+
+	/* 151 0x97 '—' */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+
+	/* 152 0x98 '˜' */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7e, /* 01111110 */
+	0x06, /* 00000110 */
+	0xfc, /* 11111100 */
+
+	/* 153 0x99 '™' */
+	0xc6, /* 11000110 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x00, /* 00000000 */
+
+	/* 154 0x9a 'š' */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+
+	/* 155 0x9b '›' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 156 0x9c 'œ' */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x64, /* 01100100 */
+	0xf0, /* 11110000 */
+	0x60, /* 01100000 */
+	0x66, /* 01100110 */
+	0xfc, /* 11111100 */
+	0x00, /* 00000000 */
+
+	/* 157 0x9d '' */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 158 0x9e 'ž' */
+	0xf8, /* 11111000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xfa, /* 11111010 */
+	0xc6, /* 11000110 */
+	0xcf, /* 11001111 */
+	0xc6, /* 11000110 */
+	0xc7, /* 11000111 */
+
+	/* 159 0x9f 'Ÿ' */
+	0x0e, /* 00001110 */
+	0x1b, /* 00011011 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0xd8, /* 11011000 */
+	0x70, /* 01110000 */
+	0x00, /* 00000000 */
+
+	/* 160 0xa0 ' ' */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x7c, /* 01111100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+
+	/* 161 0xa1 '¡' */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x38, /* 00111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+
+	/* 162 0xa2 '¢' */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+
+	/* 163 0xa3 '£' */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+
+	/* 164 0xa4 '¤' */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0x00, /* 00000000 */
+	0xdc, /* 11011100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+
+	/* 165 0xa5 '¥' */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0x00, /* 00000000 */
+	0xe6, /* 11100110 */
+	0xf6, /* 11110110 */
+	0xde, /* 11011110 */
+	0xce, /* 11001110 */
+	0x00, /* 00000000 */
+
+	/* 166 0xa6 '¦' */
+	0x3c, /* 00111100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x3e, /* 00111110 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 167 0xa7 '§' */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 168 0xa8 '¨' */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x63, /* 01100011 */
+	0x3e, /* 00111110 */
+	0x00, /* 00000000 */
+
+	/* 169 0xa9 '©' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 170 0xaa 'ª' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x06, /* 00000110 */
+	0x06, /* 00000110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 171 0xab '«' */
+	0x63, /* 01100011 */
+	0xe6, /* 11100110 */
+	0x6c, /* 01101100 */
+	0x7e, /* 01111110 */
+	0x33, /* 00110011 */
+	0x66, /* 01100110 */
+	0xcc, /* 11001100 */
+	0x0f, /* 00001111 */
+
+	/* 172 0xac '¬' */
+	0x63, /* 01100011 */
+	0xe6, /* 11100110 */
+	0x6c, /* 01101100 */
+	0x7a, /* 01111010 */
+	0x36, /* 00110110 */
+	0x6a, /* 01101010 */
+	0xdf, /* 11011111 */
+	0x06, /* 00000110 */
+
+	/* 173 0xad '­' */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+
+	/* 174 0xae '®' */
+	0x00, /* 00000000 */
+	0x33, /* 00110011 */
+	0x66, /* 01100110 */
+	0xcc, /* 11001100 */
+	0x66, /* 01100110 */
+	0x33, /* 00110011 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 175 0xaf '¯' */
+	0x00, /* 00000000 */
+	0xcc, /* 11001100 */
+	0x66, /* 01100110 */
+	0x33, /* 00110011 */
+	0x66, /* 01100110 */
+	0xcc, /* 11001100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 176 0xb0 '°' */
+	0x22, /* 00100010 */
+	0x88, /* 10001000 */
+	0x22, /* 00100010 */
+	0x88, /* 10001000 */
+	0x22, /* 00100010 */
+	0x88, /* 10001000 */
+	0x22, /* 00100010 */
+	0x88, /* 10001000 */
+
+	/* 177 0xb1 '±' */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+
+	/* 178 0xb2 '²' */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+
+	/* 179 0xb3 '³' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 180 0xb4 '´' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 181 0xb5 'µ' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 182 0xb6 '¶' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xf6, /* 11110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 183 0xb7 '·' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 184 0xb8 '¸' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 185 0xb9 '¹' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xf6, /* 11110110 */
+	0x06, /* 00000110 */
+	0xf6, /* 11110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 186 0xba 'º' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 187 0xbb '»' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x06, /* 00000110 */
+	0xf6, /* 11110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 188 0xbc '¼' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xf6, /* 11110110 */
+	0x06, /* 00000110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 189 0xbd '½' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 190 0xbe '¾' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 191 0xbf '¿' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xf8, /* 11111000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 192 0xc0 'À' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 193 0xc1 'Á' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 194 0xc2 'Â' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 195 0xc3 'Ã' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 196 0xc4 'Ä' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 197 0xc5 'Å' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xff, /* 11111111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 198 0xc6 'Æ' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 199 0xc7 'Ç' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x37, /* 00110111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 200 0xc8 'È' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x37, /* 00110111 */
+	0x30, /* 00110000 */
+	0x3f, /* 00111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 201 0xc9 'É' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3f, /* 00111111 */
+	0x30, /* 00110000 */
+	0x37, /* 00110111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 202 0xca 'Ê' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xf7, /* 11110111 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 203 0xcb 'Ë' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0xf7, /* 11110111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 204 0xcc 'Ì' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x37, /* 00110111 */
+	0x30, /* 00110000 */
+	0x37, /* 00110111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 205 0xcd 'Í' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 206 0xce 'Î' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xf7, /* 11110111 */
+	0x00, /* 00000000 */
+	0xf7, /* 11110111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 207 0xcf 'Ï' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 208 0xd0 'Ð' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 209 0xd1 'Ñ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 210 0xd2 'Ò' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 211 0xd3 'Ó' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x3f, /* 00111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 212 0xd4 'Ô' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 213 0xd5 'Õ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 214 0xd6 'Ö' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3f, /* 00111111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 215 0xd7 '×' */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0xff, /* 11111111 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+
+	/* 216 0xd8 'Ø' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xff, /* 11111111 */
+	0x18, /* 00011000 */
+	0xff, /* 11111111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 217 0xd9 'Ù' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xf8, /* 11111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 218 0xda 'Ú' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x1f, /* 00011111 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 219 0xdb 'Û' */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+
+	/* 220 0xdc 'Ü' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+
+	/* 221 0xdd 'Ý' */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+	0xf0, /* 11110000 */
+
+	/* 222 0xde 'Þ' */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+	0x0f, /* 00001111 */
+
+	/* 223 0xdf 'ß' */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 224 0xe0 'à' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0xc8, /* 11001000 */
+	0xdc, /* 11011100 */
+	0x76, /* 01110110 */
+	0x00, /* 00000000 */
+
+	/* 225 0xe1 'á' */
+	0x78, /* 01111000 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xd8, /* 11011000 */
+	0xcc, /* 11001100 */
+	0xc6, /* 11000110 */
+	0xcc, /* 11001100 */
+	0x00, /* 00000000 */
+
+	/* 226 0xe2 'â' */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0x00, /* 00000000 */
+
+	/* 227 0xe3 'ã' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x00, /* 00000000 */
+
+	/* 228 0xe4 'ä' */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+
+	/* 229 0xe5 'å' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0x70, /* 01110000 */
+	0x00, /* 00000000 */
+
+	/* 230 0xe6 'æ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x7c, /* 01111100 */
+	0xc0, /* 11000000 */
+
+	/* 231 0xe7 'ç' */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+
+	/* 232 0xe8 'è' */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+
+	/* 233 0xe9 'é' */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x00, /* 00000000 */
+
+	/* 234 0xea 'ê' */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0xee, /* 11101110 */
+	0x00, /* 00000000 */
+
+	/* 235 0xeb 'ë' */
+	0x0e, /* 00001110 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x3e, /* 00111110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+
+	/* 236 0xec 'ì' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0xdb, /* 11011011 */
+	0xdb, /* 11011011 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 237 0xed 'í' */
+	0x06, /* 00000110 */
+	0x0c, /* 00001100 */
+	0x7e, /* 01111110 */
+	0xdb, /* 11011011 */
+	0xdb, /* 11011011 */
+	0x7e, /* 01111110 */
+	0x60, /* 01100000 */
+	0xc0, /* 11000000 */
+
+	/* 238 0xee 'î' */
+	0x1e, /* 00011110 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0x7e, /* 01111110 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x1e, /* 00011110 */
+	0x00, /* 00000000 */
+
+	/* 239 0xef 'ï' */
+	0x00, /* 00000000 */
+	0x7c, /* 01111100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0x00, /* 00000000 */
+
+	/* 240 0xf0 'ð' */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 241 0xf1 'ñ' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+
+	/* 242 0xf2 'ò' */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+
+	/* 243 0xf3 'ó' */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+
+	/* 244 0xf4 'ô' */
+	0x0e, /* 00001110 */
+	0x1b, /* 00011011 */
+	0x1b, /* 00011011 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+
+	/* 245 0xf5 'õ' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0xd8, /* 11011000 */
+	0xd8, /* 11011000 */
+	0x70, /* 01110000 */
+
+	/* 246 0xf6 'ö' */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 247 0xf7 '÷' */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0x00, /* 00000000 */
+	0x76, /* 01110110 */
+	0xdc, /* 11011100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 248 0xf8 'ø' */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0x6c, /* 01101100 */
+	0x38, /* 00111000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 249 0xf9 'ù' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 250 0xfa 'ú' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 251 0xfb 'û' */
+	0x0f, /* 00001111 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0x0c, /* 00001100 */
+	0xec, /* 11101100 */
+	0x6c, /* 01101100 */
+	0x3c, /* 00111100 */
+	0x1c, /* 00011100 */
+
+	/* 252 0xfc 'ü' */
+	0x6c, /* 01101100 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x36, /* 00110110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 253 0xfd 'ý' */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 254 0xfe 'þ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+	/* 255 0xff 'ÿ' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+
+};
+
+
+struct font_desc font_vga_8x8 = {
+	VGA8x8_IDX,
+	"VGA8x8",
+	8,
+	8,
+	fontdata_8x8,
+	0
+};
diff --git a/drivers/video/console/font_acorn_8x8.c b/drivers/video/console/font_acorn_8x8.c
new file mode 100644
index 0000000..d565505
--- /dev/null
+++ b/drivers/video/console/font_acorn_8x8.c
@@ -0,0 +1,276 @@
+/* Acorn-like font definition, with PC graphics characters */
+
+#include <linux/config.h>
+#include <linux/font.h>
+
+static unsigned char acorndata_8x8[] = {
+/* 00 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ^@ */
+/* 01 */  0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, /* ^A */
+/* 02 */  0x7e, 0xff, 0xbd, 0xff, 0xc3, 0xe7, 0xff, 0x7e, /* ^B */
+/* 03 */  0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, /* ^C */
+/* 04 */  0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, /* ^D */
+/* 05 */  0x00, 0x18, 0x3c, 0xe7, 0xe7, 0x3c, 0x18, 0x00, /* ^E */
+/* 06 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* 07 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* 08 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* 09 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* 0A */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* 0B */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* 0C */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* 0D */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* 0E */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* 0F */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* 10 */  0x00, 0x60, 0x78, 0x7e, 0x7e, 0x78, 0x60, 0x00, /* |> */
+/* 11 */  0x00, 0x06, 0x1e, 0x7e, 0x7e, 0x1e, 0x06, 0x00, /* <| */
+/* 12 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* 13 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* 14 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* 15 */  0x3c, 0x60, 0x3c, 0x66, 0x3c, 0x06, 0x3c, 0x00,
+/* 16 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* 17 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* 18 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* 19 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* 1A */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* 1B */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* 1C */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* 1D */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* 1E */  0x00, 0x18, 0x18, 0x3c, 0x3c, 0x7e, 0x7e, 0x00, /* /\ */
+/* 1F */  0x00, 0x7e, 0x7e, 0x3c, 0x3c, 0x18, 0x18, 0x00, /* \/ */
+/* 20 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*   */
+/* 21 */  0x18, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x00, /* ! */
+/* 22 */  0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, /* " */
+/* 23 */  0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00, /* # */
+/* 24 */  0x0C, 0x3F, 0x68, 0x3E, 0x0B, 0x7E, 0x18, 0x00, /* $ */
+/* 25 */  0x60, 0x66, 0x0C, 0x18, 0x30, 0x66, 0x06, 0x00, /* % */
+/* 26 */  0x38, 0x6C, 0x6C, 0x38, 0x6D, 0x66, 0x3B, 0x00, /* & */
+/* 27 */  0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' */
+/* 28 */  0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00, /* ( */
+/* 29 */  0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, /* ) */
+/* 2A */  0x00, 0x18, 0x7E, 0x3C, 0x7E, 0x18, 0x00, 0x00, /* * */
+/* 2B */  0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, /* + */
+/* 2C */  0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, /* , */
+/* 2D */  0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, /* - */
+/* 2E */  0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, /* . */
+/* 2F */  0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, /* / */
+/* 30 */  0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x3C, 0x00, /* 0 */
+/* 31 */  0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, /* 1 */
+/* 32 */  0x3C, 0x66, 0x06, 0x0C, 0x18, 0x30, 0x7E, 0x00, /* 2 */
+/* 33 */  0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00, /* 3 */
+/* 34 */  0x0C, 0x1C, 0x3C, 0x6C, 0x7E, 0x0C, 0x0C, 0x00, /* 4 */
+/* 35 */  0x7E, 0x60, 0x7C, 0x06, 0x06, 0x66, 0x3C, 0x00, /* 5 */
+/* 36 */  0x1C, 0x30, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0x00, /* 6 */
+/* 37 */  0x7E, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00, /* 7 */
+/* 38 */  0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, /* 8 */
+/* 39 */  0x3C, 0x66, 0x66, 0x3E, 0x06, 0x0C, 0x38, 0x00, /* 9 */
+/* 3A */  0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, /* : */
+/* 3B */  0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x30, /* ; */
+/* 3C */  0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, /* < */
+/* 3D */  0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, /* = */ 
+/* 3E */  0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00, /* > */
+/* 3F */  0x3C, 0x66, 0x0C, 0x18, 0x18, 0x00, 0x18, 0x00, /* ? */
+/* 40 */  0x3C, 0x66, 0x6E, 0x6A, 0x6E, 0x60, 0x3C, 0x00, /* @ */
+/* 41 */  0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, /* A */
+/* 42 */  0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00, /* B */
+/* 43 */  0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00, /* C */
+/* 44 */  0x78, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0x78, 0x00, /* D */
+/* 45 */  0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00, /* E */
+/* 46 */  0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x60, 0x00, /* F */
+/* 47 */  0x3C, 0x66, 0x60, 0x6E, 0x66, 0x66, 0x3C, 0x00, /* G */
+/* 48 */  0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, /* H */
+/* 49 */  0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, /* I */
+/* 4A */  0x3E, 0x0C, 0x0C, 0x0C, 0x0C, 0x6C, 0x38, 0x00, /* J */
+/* 4B */  0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00, /* K */
+/* 4C */  0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x00, /* L */
+/* 4D */  0x63, 0x77, 0x7F, 0x6B, 0x6B, 0x63, 0x63, 0x00, /* M */
+/* 4E */  0x66, 0x66, 0x76, 0x7E, 0x6E, 0x66, 0x66, 0x00, /* N */
+/* 4F */  0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, /* O */
+/* 50 */  0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x00, /* P */
+/* 51 */  0x3C, 0x66, 0x66, 0x66, 0x6A, 0x6C, 0x36, 0x00, /* Q */
+/* 52 */  0x7C, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0x00, /* R */
+/* 53 */  0x3C, 0x66, 0x60, 0x3C, 0x06, 0x66, 0x3C, 0x00, /* S */
+/* 54 */  0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, /* T */
+/* 55 */  0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, /* U */
+/* 56 */  0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, /* V */
+/* 57 */  0x63, 0x63, 0x6B, 0x6B, 0x7F, 0x77, 0x63, 0x00, /* W */
+/* 58 */  0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00, /* X */
+/* 59 */  0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00, /* Y */
+/* 5A */  0x7E, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x7E, 0x00, /* Z */
+/* 5B */  0x7C, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7C, 0x00, /* [ */
+/* 5C */  0x00, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00, /* \ */
+/* 5D */  0x3E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x3E, 0x00, /* ] */
+/* 5E */  0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ^ */
+/* 5F */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, /* _ */
+/* 60 */  0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ` */
+/* 61 */  0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00, /* a */
+/* 62 */  0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x00, /* b */
+/* 63 */  0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00, /* c */
+/* 64 */  0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x00, /* d */
+/* 65 */  0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, /* e */
+/* 66 */  0x1C, 0x30, 0x30, 0x7C, 0x30, 0x30, 0x30, 0x00, /* f */
+/* 67 */  0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x3C, /* g */
+/* 68 */  0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00, /* h */
+/* 69 */  0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00, /* i */
+/* 6A */  0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x70, /* j */
+/* 6B */  0x60, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00, /* k */
+/* 6C */  0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, /* l */
+/* 6D */  0x00, 0x00, 0x36, 0x7F, 0x6B, 0x6B, 0x63, 0x00, /* m */
+/* 6E */  0x00, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00, /* n */
+/* 6F */  0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, /* o */
+/* 70 */  0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, /* p */
+/* 71 */  0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x07, /* q */
+/* 72 */  0x00, 0x00, 0x6C, 0x76, 0x60, 0x60, 0x60, 0x00, /* r */
+/* 73 */  0x00, 0x00, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x00, /* s */
+/* 74 */  0x30, 0x30, 0x7C, 0x30, 0x30, 0x30, 0x1C, 0x00, /* t */
+/* 75 */  0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00, /* u */
+/* 76 */  0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, /* v */
+/* 77 */  0x00, 0x00, 0x63, 0x6B, 0x6B, 0x7F, 0x36, 0x00, /* w */
+/* 78 */  0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, /* x */
+/* 79 */  0x00, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x3C, /* y */
+/* 7A */  0x00, 0x00, 0x7E, 0x0C, 0x18, 0x30, 0x7E, 0x00, /* z */
+/* 7B */  0x0C, 0x18, 0x18, 0x70, 0x18, 0x18, 0x0C, 0x00, /* { */
+/* 7C */  0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, /* | */
+/* 7D */  0x30, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x30, 0x00, /* } */
+/* 7E */  0x31, 0x6B, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, /* ~ */
+/* 7F */  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /*  */
+/* 80 */  0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x30, 0x60,
+/* 81 */  0x66, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x00,
+/* 82 */  0x0c, 0x18, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
+/* 83 */  0x18, 0x66, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00,
+/* 84 */  0x66, 0x00, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00,
+/* 85 */  0x30, 0x18, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00,
+/* 86 */  0x3c, 0x66, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00,
+/* 87 */  0x00, 0x00, 0x3c, 0x66, 0x60, 0x66, 0x3c, 0x60,
+/* 88 */  0x3c, 0x66, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
+/* 89 */  0x66, 0x00, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
+/* 8A */  0x30, 0x18, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
+/* 8B */  0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00,
+/* 8C */  0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00,
+/* 8D */  0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00,
+/* 8E */  0x66, 0x66, 0x00, 0x3c, 0x66, 0x7e, 0x66, 0x00,
+/* 8F */  0x18, 0x66, 0x00, 0x3c, 0x66, 0x7e, 0x66, 0x00,
+/* 90 */  0x0c, 0x18, 0x7e, 0x60, 0x7c, 0x60, 0x7e, 0x00,
+/* 91 */  0x00, 0x00, 0x3f, 0x0d, 0x3f, 0x6c, 0x3f, 0x00,
+/* 92 */  0x3f, 0x66, 0x66, 0x7f, 0x66, 0x66, 0x67, 0x00,
+/* 93 */  0x3c, 0x66, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x00,
+/* 94 */  0x66, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x00,
+/* 95 */  0x30, 0x18, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x00,
+/* 96 */  0x3c, 0x66, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x00,
+/* 97 */  0x30, 0x18, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x00,
+/* 98 */  0x66, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x3c,
+/* 99 */  0x66, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x00,
+/* 9A */  0x66, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00,
+/* 9B */  0x08, 0x3e, 0x6b, 0x68, 0x6b, 0x3e, 0x08, 0x00,
+/* 9C */  0x1c, 0x36, 0x30, 0x7c, 0x30, 0x30, 0x7e, 0x00,
+/* 9D */  0x66, 0x3c, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00,
+/* 9E */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* 9F */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* A0 */  0x0c, 0x18, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00,
+/* A1 */  0x0c, 0x18, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00,
+/* A2 */  0x0c, 0x18, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x00,
+/* A3 */  0x0c, 0x18, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x00,
+/* A4 */  0x36, 0x6c, 0x00, 0x7c, 0x66, 0x66, 0x66, 0x00,
+/* A5 */  0x36, 0x6c, 0x00, 0x66, 0x76, 0x6e, 0x66, 0x00,
+/* A6 */  0x1c, 0x06, 0x1e, 0x36, 0x1e, 0x00, 0x3e, 0x00,
+/* A7 */  0x1c, 0x36, 0x36, 0x36, 0x1c, 0x00, 0x3e, 0x00,
+/* A8 */  0x18, 0x00, 0x18, 0x18, 0x30, 0x66, 0x3c, 0x00,
+/* A9 */  0x7e, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* AA */  0x7e, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* AB */  0x40, 0xc0, 0x40, 0x4f, 0x41, 0x0f, 0x08, 0x0f,
+/* AC */  0x40, 0xc0, 0x40, 0x48, 0x48, 0x0a, 0x0f, 0x02,
+/* AD */  0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
+/* AE */  0x00, 0x33, 0x66, 0xcc, 0xcc, 0x66, 0x33, 0x00,
+/* AF */  0x00, 0xcc, 0x66, 0x33, 0x33, 0x66, 0xcc, 0x00,
+/* B0 */  0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
+/* B1 */  0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+/* B2 */  0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+/* B3 */  0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+/* B4 */  0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18,
+/* B5 */  0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
+/* B6 */  0x66, 0x66, 0x66, 0xe6, 0x66, 0x66, 0x66, 0x66,
+/* B7 */  0x00, 0x00, 0x00, 0xfe, 0x66, 0x66, 0x66, 0x66,
+/* B8 */  0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
+/* B9 */  0x66, 0x66, 0xe6, 0x06, 0xe6, 0x66, 0x66, 0x66,
+/* BA */  0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+/* BB */  0x00, 0x00, 0xfe, 0x06, 0xe6, 0x66, 0x66, 0x66,
+/* BC */  0x66, 0x66, 0xe6, 0x06, 0xfe, 0x00, 0x00, 0x00,
+/* BD */  0x66, 0x66, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+/* BE */  0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00,
+/* BF */  0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18,
+/* C0 */  0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00,
+/* C1 */  0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00,
+/* C2 */  0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18,
+/* C3 */  0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
+/* C4 */  0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+/* C5 */  0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18,
+/* C6 */  0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
+/* C7 */  0x66, 0x66, 0x66, 0x67, 0x66, 0x66, 0x66, 0x66,
+/* C8 */  0x66, 0x66, 0x67, 0x60, 0x7f, 0x00, 0x00, 0x00,
+/* C9 */  0x00, 0x00, 0x7f, 0x60, 0x67, 0x66, 0x66, 0x66,
+/* CA */  0x66, 0x66, 0xe7, 0x00, 0xff, 0x00, 0x00, 0x00,
+/* CB */  0x00, 0x00, 0xff, 0x00, 0xe7, 0x66, 0x66, 0x66,
+/* CC */  0x66, 0x66, 0x67, 0x60, 0x67, 0x66, 0x66, 0x66,
+/* CD */  0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
+/* CE */  0x66, 0x66, 0xe7, 0x00, 0xe7, 0x66, 0x66, 0x66,
+/* CF */  0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
+/* D0 */  0x66, 0x66, 0x66, 0xff, 0x00, 0x00, 0x00, 0x00,
+/* D1 */  0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18,
+/* D2 */  0x00, 0x00, 0x00, 0xff, 0x66, 0x66, 0x66, 0x66,
+/* D3 */  0x66, 0x66, 0x66, 0x7f, 0x00, 0x00, 0x00, 0x00,
+/* D4 */  0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00,
+/* D5 */  0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
+/* D6 */  0x00, 0x00, 0x00, 0x7f, 0x66, 0x66, 0x66, 0x66,
+/* D7 */  0x66, 0x66, 0x66, 0xff, 0x66, 0x66, 0x66, 0x66,
+/* D8 */  0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18,
+/* D9 */  0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00,
+/* DA */  0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18,
+/* DB */  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+/* DC */  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+/* DD */  0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+/* DE */  0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+/* DF */  0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+/* E0 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* E1 */  0x3c, 0x66, 0x66, 0x6c, 0x66, 0x66, 0x6c, 0xc0,
+/* E2 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* E3 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* E4 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* E5 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* E6 */  0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x3e, 0x60,
+/* E7 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* E8 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* E9 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* EA */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* EB */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* EC */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* ED */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* EE */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* EF */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* F0 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* F1 */  0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x7e, 0x00,
+/* F2 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* F3 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* F4 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* F5 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* F6 */  0x00, 0x18, 0x00, 0xff, 0x00, 0x18, 0x00, 0x00,
+/* F7 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* F8 */  0x3c, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* F9 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* FA */  0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+/* FB */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* FC */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* FD */  0x38, 0x04, 0x18, 0x20, 0x3c, 0x00, 0x00, 0x00,
+/* FE */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+/* FF */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+struct font_desc font_acorn_8x8 = {
+	ACORN8x8_IDX,
+	"Acorn8x8",
+	8,
+	8,
+	acorndata_8x8,
+#ifdef CONFIG_ARCH_ACORN
+	20
+#else
+	0
+#endif
+};
diff --git a/drivers/video/console/font_mini_4x6.c b/drivers/video/console/font_mini_4x6.c
new file mode 100644
index 0000000..593b955
--- /dev/null
+++ b/drivers/video/console/font_mini_4x6.c
@@ -0,0 +1,2158 @@
+
+/* Hand composed "Miniscule" 4x6 font, with binary data generated using
+ * Perl stub.
+ *
+ * Use 'perl -x mini_4x6.c < mini_4x6.c > new_version.c' to regenerate
+ * binary data.
+ *
+ * Created by Kenneth Albanowski.
+ * No rights reserved, released to the public domain.
+ *
+ * Version 1.0
+ */
+
+/*
+
+#!/usr/bin/perl -pn
+
+s{((0x)?[0-9a-fA-F]+)(.*\[([\*\ ]{4})\])}{
+
+	($num,$pat,$bits) = ($1,$3,$4);
+	
+	$bits =~ s/([^\s0])|(.)/ defined($1) + 0 /ge;
+	
+	$num = ord(pack("B8", $bits));
+	$num |= $num >> 4;
+	$num = sprintf("0x%.2x", $num);
+	
+	#print "$num,$pat,$bits\n";
+	
+	$num . $pat;
+}ge;
+
+__END__;
+*/
+
+/* Note: binary data consists of one byte for each row of each character top
+   to bottom, character 0 to character 255, six bytes per character. Each
+   byte contains the same four character bits in both nybbles.
+   MSBit to LSBit = left to right.
+ */
+
+#include <linux/font.h>
+
+#define FONTDATAMAX 1536
+
+static unsigned char fontdata_mini_4x6[FONTDATAMAX] = {
+
+	/*{*/
+	  	/*   Char 0: ' '  */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 1: ' '  */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 2: ' '  */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 3: ' '  */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 4: ' '  */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 5: ' '  */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 6: ' '  */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 7: ' '  */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 8: ' '  */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 9: ' '  */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 10: '' */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 11: ' ' */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 12: ' ' */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 13: ' ' */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 14: ' ' */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 15: ' ' */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 16: ' ' */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 17: ' ' */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 18: ' ' */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 19: ' ' */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 20: ' ' */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 21: ' ' */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 22: ' ' */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 23: ' ' */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 24: ' ' */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 25: ' ' */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 26: ' ' */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 27: ' ' */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 28: ' ' */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 29: ' ' */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 30: ' ' */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 31: ' ' */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 32: ' ' */
+	0x00,	/*=  [    ]       */
+	0x00,	/*=  [    ]       */
+	0x00,	/*=  [    ]       */
+	0x00,	/*=  [    ]       */
+	0x00,	/*=  [    ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 33: '!' */
+	0x44,	/*=  [ *  ]       */
+	0x44,	/*=  [ *  ]       */
+	0x44,	/*=  [ *  ]       */
+	0x00,	/*=  [    ]       */
+	0x44,	/*=  [ *  ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 34: '"' */
+	0xaa,	/*=  [* * ]       */
+	0xaa,	/*=  [* * ]       */
+	0x00,	/*=  [    ]       */
+	0x00,	/*=  [    ]       */
+	0x00,	/*=  [    ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 35: '#' */
+	0xaa,	/*=  [* * ]       */
+	0xff,	/*=  [****]       */
+	0xff,	/*=  [****]       */
+	0xaa,	/*=  [* * ]       */
+	0x00,	/*=  [    ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 36: '$' */
+	0x44,	/*=  [ *  ]       */
+	0x66,	/*=  [ ** ]       */
+	0xee,	/*=  [*** ]       */
+	0xcc,	/*=  [**  ]       */
+	0x44,	/*=  [ *  ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 37: '%' */
+	0xaa,	/*=  [* * ]       */
+	0x22,	/*=  [  * ]       */
+	0x44,	/*=  [ *  ]       */
+	0x88,	/*=  [*   ]       */
+	0xaa,	/*=  [* * ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 38: '&' */
+	0x66,	/*=  [ ** ]       */
+	0x99,	/*=  [*  *]       */
+	0x66,	/*=  [ ** ]       */
+	0xaa,	/*=  [* * ]       */
+	0xdd,	/*=  [** *]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 39: ''' */
+	0x22,	/*=  [  * ]       */
+	0x44,	/*=  [ *  ]       */
+	0x00,	/*=  [    ]       */
+	0x00,	/*=  [    ]       */
+	0x00,	/*=  [    ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 40: '(' */
+	0x22,	/*=  [  * ]       */
+	0x44,	/*=  [ *  ]       */
+	0x44,	/*=  [ *  ]       */
+	0x44,	/*=  [ *  ]       */
+	0x22,	/*=  [  * ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 41: ')' */
+	0x44,	/*=  [ *  ]       */
+	0x22,	/*=  [  * ]       */
+	0x22,	/*=  [  * ]       */
+	0x22,	/*=  [  * ]       */
+	0x44,	/*=  [ *  ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 42: '*' */
+	0x00,	/*=  [    ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 43: '+' */
+	0x00,	/*=  [    ]       */
+	0x44,	/*=  [ *  ]       */
+	0xee,	/*=  [*** ]       */
+	0x44,	/*=  [ *  ]       */
+	0x00,	/*=  [    ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 44: ',' */
+	0x00,	/*=  [    ]       */
+	0x00,	/*=  [    ]       */
+	0x00,	/*=  [    ]       */
+	0x44,	/*=  [ *  ]       */
+	0x88,	/*=  [*   ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 45: '-' */
+	0x00,	/*=  [    ]       */
+	0x00,	/*=  [    ]       */
+	0xee,	/*=  [*** ]       */
+	0x00,	/*=  [    ]       */
+	0x00,	/*=  [    ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 46: '.' */
+	0x00,	/*=  [    ]       */
+	0x00,	/*=  [    ]       */
+	0x00,	/*=  [    ]       */
+	0x00,	/*=  [    ]       */
+	0x44,	/*=  [ *  ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 47: '/' */
+	0x00,	/*=  [    ]       */
+	0x22,	/*=  [  * ]       */
+	0x44,	/*=  [ *  ]       */
+	0x88,	/*=  [*   ]       */
+	0x00,	/*=  [    ]       */
+	0x00,	/*=  [    ]       */
+	/*}*/
+	/*{*/
+	  	/*   Char 48: '0'   */
+	0x44,	/*=   [ *  ]        */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0x44,	/*=   [ *  ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/
+	  	/*   Char 49: '1'   */
+	0x44,	/*=   [ *  ]        */
+	0xcc,	/*=   [**  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/
+	  	/*   Char 50: '2'   */
+	0xcc,	/*=   [**  ]        */
+	0x22,	/*=   [  * ]        */
+	0x44,	/*=   [ *  ]        */
+	0x88,	/*=   [*   ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/
+	  	/*   Char 51: '3'   */
+	0xee,	/*=   [*** ]        */
+	0x22,	/*=   [  * ]        */
+	0x66,	/*=   [ ** ]        */
+	0x22,	/*=   [  * ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 52: '4'   */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0xee,	/*=   [*** ]        */
+	0x22,	/*=   [  * ]        */
+	0x22,	/*=   [  * ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 53: '5'   */
+	0xee,	/*=   [*** ]        */
+	0x88,	/*=   [*   ]        */
+	0xee,	/*=   [*** ]        */
+	0x22,	/*=   [  * ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 54: '6'   */
+	0xee,	/*=   [*** ]        */
+	0x88,	/*=   [*   ]        */
+	0xee,	/*=   [*** ]        */
+	0xaa,	/*=   [* * ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 55: '7'   */
+	0xee,	/*=   [*** ]        */
+	0x22,	/*=   [  * ]        */
+	0x22,	/*=   [  * ]        */
+	0x22,	/*=   [  * ]        */
+	0x22,	/*=   [  * ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 56: '8'   */
+	0xee,	/*=   [*** ]        */
+	0xaa,	/*=   [* * ]        */
+	0xee,	/*=   [*** ]        */
+	0xaa,	/*=   [* * ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 57: '9'   */
+	0xee,	/*=   [*** ]        */
+	0xaa,	/*=   [* * ]        */
+	0xee,	/*=   [*** ]        */
+	0x22,	/*=   [  * ]        */
+	0x22,	/*=   [  * ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 58: ':'   */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x44,	/*=   [ *  ]        */
+	0x00,	/*=   [    ]        */
+	0x44,	/*=   [ *  ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 59: ';'   */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x44,	/*=   [ *  ]        */
+	0x00,	/*=   [    ]        */
+	0x44,	/*=   [ *  ]        */
+	0x88,	/*=   [*   ]        */
+	/*}*/
+	/*{*/ 	/*   Char 60: '<'   */
+	0x22,	/*=   [  * ]        */
+	0x44,	/*=   [ *  ]        */
+	0x88,	/*=   [*   ]        */
+	0x44,	/*=   [ *  ]        */
+	0x22,	/*=   [  * ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 61: '='   */
+	0x00,	/*=   [    ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 62: '>'   */
+	0x88,	/*=   [*   ]        */
+	0x44,	/*=   [ *  ]        */
+	0x22,	/*=   [  * ]        */
+	0x44,	/*=   [ *  ]        */
+	0x88,	/*=   [*   ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 63: '?'   */
+	0xee,	/*=   [*** ]        */
+	0x22,	/*=   [  * ]        */
+	0x66,	/*=   [ ** ]        */
+	0x00,	/*=   [    ]        */
+	0x44,	/*=   [ *  ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 64: '@'   */
+	0x44,	/*=   [ *  ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x88,	/*=   [*   ]        */
+	0x44,	/*=   [ *  ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 65: 'A'   */
+	0x44,	/*=   [ *  ]        */
+	0xaa,	/*=   [* * ]        */
+	0xee,	/*=   [*** ]        */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 66: 'B'   */
+	0xcc,	/*=   [**  ]        */
+	0xaa,	/*=   [* * ]        */
+	0xcc,	/*=   [**  ]        */
+	0xaa,	/*=   [* * ]        */
+	0xcc,	/*=   [**  ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 67: 'C'   */
+	0x66,	/*=   [ ** ]        */
+	0x88,	/*=   [*   ]        */
+	0x88,	/*=   [*   ]        */
+	0x88,	/*=   [*   ]        */
+	0x66,	/*=   [ ** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 68: 'D'   */
+	0xcc,	/*=   [**  ]        */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0xcc,	/*=   [**  ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 69: 'E'   */
+	0xee,	/*=   [*** ]        */
+	0x88,	/*=   [*   ]        */
+	0xee,	/*=   [*** ]        */
+	0x88,	/*=   [*   ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 70: 'F'   */
+	0xee,	/*=   [*** ]        */
+	0x88,	/*=   [*   ]        */
+	0xee,	/*=   [*** ]        */
+	0x88,	/*=   [*   ]        */
+	0x88,	/*=   [*   ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 71: 'G'   */
+	0x66,	/*=   [ ** ]        */
+	0x88,	/*=   [*   ]        */
+	0xee,	/*=   [*** ]        */
+	0xaa,	/*=   [* * ]        */
+	0x66,	/*=   [ ** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 72: 'H'   */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0xee,	/*=   [*** ]        */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 73: 'I'   */
+	0xee,	/*=   [*** ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 74: 'J'   */
+	0x22,	/*=   [  * ]        */
+	0x22,	/*=   [  * ]        */
+	0x22,	/*=   [  * ]        */
+	0xaa,	/*=   [* * ]        */
+	0x44,	/*=   [ *  ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 75: 'K'   */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0xcc,	/*=   [**  ]        */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 76: 'L'   */
+	0x88,	/*=   [*   ]        */
+	0x88,	/*=   [*   ]        */
+	0x88,	/*=   [*   ]        */
+	0x88,	/*=   [*   ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 77: 'M'   */
+	0xaa,	/*=   [* * ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 78: 'N'   */
+	0xaa,	/*=   [* * ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xaa,	/*=   [* * ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 79: 'O'   */
+	0x44,	/*=   [ *  ]        */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0x44,	/*=   [ *  ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 80: 'P'   */
+	0xcc,	/*=   [**  ]        */
+	0xaa,	/*=   [* * ]        */
+	0xcc,	/*=   [**  ]        */
+	0x88,	/*=   [*   ]        */
+	0x88,	/*=   [*   ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 81: 'Q'   */
+	0x44,	/*=   [ *  ]        */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0xee,	/*=   [*** ]        */
+	0x66,	/*=   [ ** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 82: 'R'   */
+	0xcc,	/*=   [**  ]        */
+	0xaa,	/*=   [* * ]        */
+	0xee,	/*=   [*** ]        */
+	0xcc,	/*=   [**  ]        */
+	0xaa,	/*=   [* * ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 83: 'S'   */
+	0x66,	/*=   [ ** ]        */
+	0x88,	/*=   [*   ]        */
+	0x44,	/*=   [ *  ]        */
+	0x22,	/*=   [  * ]        */
+	0xcc,	/*=   [**  ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 84: 'T'   */
+	0xee,	/*=   [*** ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 85: 'U'   */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0x66,	/*=   [ ** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 86: 'V'   */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 87: 'W'   */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xaa,	/*=   [* * ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 88: 'X'   */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0x44,	/*=   [ *  ]        */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 89: 'Y'   */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 90: 'Z'   */
+	0xee,	/*=   [*** ]        */
+	0x22,	/*=   [  * ]        */
+	0x44,	/*=   [ *  ]        */
+	0x88,	/*=   [*   ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 91: '['   */
+	0x66,	/*=   [ ** ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x66,	/*=   [ ** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 92: '\'   */
+	0x00,	/*=   [    ]        */
+	0x88,	/*=   [*   ]        */
+	0x44,	/*=   [ *  ]        */
+	0x22,	/*=   [  * ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 93: ']'   */
+	0x66,	/*=   [ ** ]        */
+	0x22,	/*=   [  * ]        */
+	0x22,	/*=   [  * ]        */
+	0x22,	/*=   [  * ]        */
+	0x66,	/*=   [ ** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 94: '^'   */
+	0x44,	/*=   [ *  ]        */
+	0xaa,	/*=   [* * ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 95: '_'   */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0xff,	/*=   [****]        */
+	/*}*/
+	/*{*/ 	/*   Char 96: '`'   */
+	0x88,	/*=   [*   ]        */
+	0x44,	/*=   [ *  ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 97: 'a'   */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x66,	/*=   [ ** ]        */
+	0xaa,	/*=   [* * ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 98: 'b'   */
+	0x88,	/*=   [*   ]        */
+	0x88,	/*=   [*   ]        */
+	0xcc,	/*=   [**  ]        */
+	0xaa,	/*=   [* * ]        */
+	0xcc,	/*=   [**  ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 99: 'c'   */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x66,	/*=   [ ** ]        */
+	0x88,	/*=   [*   ]        */
+	0x66,	/*=   [ ** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 100: 'd'   */
+	0x22,	/*=   [  * ]        */
+	0x22,	/*=   [  * ]        */
+	0x66,	/*=   [ ** ]        */
+	0xaa,	/*=   [* * ]        */
+	0x66,	/*=   [ ** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 101: 'e'   */
+	0x00,	/*=   [    ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x88,	/*=   [*   ]        */
+	0x66,	/*=   [ ** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 102: 'f'   */
+	0x22,	/*=   [  * ]        */
+	0x44,	/*=   [ *  ]        */
+	0xee,	/*=   [*** ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 103: 'g'   */
+	0x00,	/*=   [    ]        */
+	0x66,	/*=   [ ** ]        */
+	0xaa,	/*=   [* * ]        */
+	0x66,	/*=   [ ** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 104: 'h'   */
+	0x88,	/*=   [*   ]        */
+	0x88,	/*=   [*   ]        */
+	0xcc,	/*=   [**  ]        */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 105: 'i'   */
+	0x44,	/*=   [ *  ]        */
+	0x00,	/*=   [    ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 106: 'j'   */
+	0x44,	/*=   [ *  ]        */
+	0x00,	/*=   [    ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x88,	/*=   [*   ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 107: 'k'   */
+	0x00,	/*=   [    ]        */
+	0x88,	/*=   [*   ]        */
+	0xaa,	/*=   [* * ]        */
+	0xcc,	/*=   [**  ]        */
+	0xaa,	/*=   [* * ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 108: 'l'   */
+	0x00,	/*=   [    ]        */
+	0xcc,	/*=   [**  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 109: 'm'   */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xaa,	/*=   [* * ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 110: 'n'   */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0xcc,	/*=   [**  ]        */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 111: 'o'   */
+	0x00,	/*=   [    ]        */
+	0x44,	/*=   [ *  ]        */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0x44,	/*=   [ *  ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 112: 'p'   */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0xcc,	/*=   [**  ]        */
+	0xaa,	/*=   [* * ]        */
+	0xcc,	/*=   [**  ]        */
+	0x88,	/*=   [*   ]        */
+	/*}*/
+	/*{*/ 	/*   Char 113: 'q'   */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x66,	/*=   [ ** ]        */
+	0xaa,	/*=   [* * ]        */
+	0x66,	/*=   [ ** ]        */
+	0x22,	/*=   [  * ]        */
+	/*}*/
+	/*{*/ 	/*   Char 114: 'r'   */
+	0x00,	/*=   [    ]        */
+	0xcc,	/*=   [**  ]        */
+	0xaa,	/*=   [* * ]        */
+	0x88,	/*=   [*   ]        */
+	0x88,	/*=   [*   ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 115: 's'   */
+	0x00,	/*=   [    ]        */
+	0x66,	/*=   [ ** ]        */
+	0xcc,	/*=   [**  ]        */
+	0x22,	/*=   [  * ]        */
+	0xcc,	/*=   [**  ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 116: 't'   */
+	0x00,	/*=   [    ]        */
+	0x44,	/*=   [ *  ]        */
+	0xee,	/*=   [*** ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 117: 'u'   */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0x66,	/*=   [ ** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 118: 'v'   */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0xaa,	/*=   [* * ]        */
+	0xee,	/*=   [*** ]        */
+	0x44,	/*=   [ *  ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 119: 'w'   */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0xaa,	/*=   [* * ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 120: 'x'   */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0xaa,	/*=   [* * ]        */
+	0x44,	/*=   [ *  ]        */
+	0xaa,	/*=   [* * ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 121: 'y'   */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0xaa,	/*=   [* * ]        */
+	0xee,	/*=   [*** ]        */
+	0x22,	/*=   [  * ]        */
+	0xcc,	/*=   [**  ]        */
+	/*}*/
+	/*{*/ 	/*   Char 122: 'z' */
+	0x00,	/*=   [    ]        */
+	0xee,	/*=   [*** ]        */
+	0x66,	/*=   [ ** ]        */
+	0xcc,	/*=   [**  ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 123: '{' */
+	0x22,	/*=   [  * ]        */
+	0x44,	/*=   [ *  ]        */
+	0xcc,	/*=   [**  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x22,	/*=   [  * ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 124: '|' */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x00,	/*=   [    ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 125: '}' */
+	0x88,	/*=   [*   ]        */
+	0x44,	/*=   [ *  ]        */
+	0x66,	/*=   [ ** ]        */
+	0x44,	/*=   [ *  ]        */
+	0x88,	/*=   [*   ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 126: '~' */
+	0x55,	/*=   [ * *]        */
+	0xaa,	/*=   [* * ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 127: '' */
+	0x44,	/*=   [ *  ]        */
+	0xaa,	/*=   [* * ]        */
+	0xaa,	/*=   [* * ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 128:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 129:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 130:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 131:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 132:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 133:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 134:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 135:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 136:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 137:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 138:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 139:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 140:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 141:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 142:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 143:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 144:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 145:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 146:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 147:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 148:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 149:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 150:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 151:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 152:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 153:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 154:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 155:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 156:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 157:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 158:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 159:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 160:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 161:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 162:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 163:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 164:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 165:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 166:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 167:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 168:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 169:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 170:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 171:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 172:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 173:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 174:  */
+	0x00,	/*=   [    ]        */
+	0x66,	/*=   [ ** ]        */
+	0xcc,	/*=   [**  ]        */
+	0x66,	/*=   [ ** ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 175:  */
+	0x00,	/*=   [    ]        */
+	0xcc,	/*=   [**  ]        */
+	0x66,	/*=   [ ** ]        */
+	0xcc,	/*=   [**  ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 176:  */
+	0x88,	/*=   [*   ]        */
+	0x22,	/*=   [  * ]        */
+	0x88,	/*=   [*   ]        */
+	0x22,	/*=   [  * ]        */
+	0x88,	/*=   [*   ]        */
+	0x22,	/*=   [  * ]        */
+	/*}*/
+	/*{*/ 	/*   Char 177:  */
+	0xaa,	/*=   [* * ]        */
+	0x55,	/*=   [ * *]        */
+	0xaa,	/*=   [* * ]        */
+	0x55,	/*=   [ * *]        */
+	0xaa,	/*=   [* * ]        */
+	0x55,	/*=   [ * *]        */
+	/*}*/
+	/*{*/ 	/*   Char 178:  */
+	0xdd,	/*=   [** *]        */
+	0xbb,	/*=   [* **]        */
+	0xdd,	/*=   [** *]        */
+	0xbb,	/*=   [* **]        */
+	0xdd,	/*=   [** *]        */
+	0xbb,	/*=   [* **]        */
+	/*}*/
+	/*{*/ 	/*   Char 179:  */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	/*}*/
+	/*{*/ 	/*   Char 180:  */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0xcc,	/*=   [**  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	/*}*/
+	/*{*/ 	/*   Char 181:  */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0xcc,	/*=   [**  ]        */
+	0xcc,	/*=   [**  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	/*}*/
+	/*{*/ 	/*   Char 182:  */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	0xee,	/*=   [*** ]        */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	/*}*/
+	/*{*/ 	/*   Char 183:  */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0xee,	/*=   [*** ]        */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	/*}*/
+	/*{*/ 	/*   Char 184:  */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0xcc,	/*=   [**  ]        */
+	0xcc,	/*=   [**  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	/*}*/
+	/*{*/ 	/*   Char 185:  */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	/*}*/
+	/*{*/ 	/*   Char 186:  */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	/*}*/
+	/*{*/ 	/*   Char 187:  */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	/*}*/
+	/*{*/ 	/*   Char 188:  */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 189:  */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 190:  */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0xcc,	/*=   [**  ]        */
+	0xcc,	/*=   [**  ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 191:  */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0xcc,	/*=   [**  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	/*}*/
+	/*{*/ 	/*   Char 192:  */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x77,	/*=   [ ***]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 193:  */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0xff,	/*=   [****]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 194:  */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0xff,	/*=   [****]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	/*}*/
+	/*{*/ 	/*   Char 195:  */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x77,	/*=   [ ***]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	/*}*/
+	/*{*/ 	/*   Char 196:  */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0xff,	/*=   [****]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 197:  */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0xff,	/*=   [****]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	/*}*/
+	/*{*/ 	/*   Char 198:  */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x77,	/*=   [ ***]        */
+	0x77,	/*=   [ ***]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	/*}*/
+	/*{*/ 	/*   Char 199:  */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	0x77,	/*=   [ ***]        */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	/*}*/
+	/*{*/ 	/*   Char 200:  */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	0x77,	/*=   [ ***]        */
+	0x77,	/*=   [ ***]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 201:  */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x77,	/*=   [ ***]        */
+	0x77,	/*=   [ ***]        */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	/*}*/
+	/*{*/ 	/*   Char 202:  */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	0xff,	/*=   [****]        */
+	0xff,	/*=   [****]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 203:  */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0xff,	/*=   [****]        */
+	0xff,	/*=   [****]        */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	/*}*/
+	/*{*/ 	/*   Char 204:  */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	0x77,	/*=   [ ***]        */
+	0x77,	/*=   [ ***]        */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	/*}*/
+	/*{*/ 	/*   Char 205:  */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0xff,	/*=   [****]        */
+	0xff,	/*=   [****]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 206:  */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	0xff,	/*=   [****]        */
+	0xff,	/*=   [****]        */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	/*}*/
+	/*{*/ 	/*   Char 207:  */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0xff,	/*=   [****]        */
+	0xff,	/*=   [****]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 208:  */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	0xff,	/*=   [****]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 209:  */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0xff,	/*=   [****]        */
+	0xff,	/*=   [****]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	/*}*/
+	/*{*/ 	/*   Char 210:  */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0xff,	/*=   [****]        */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	/*}*/
+	/*{*/ 	/*   Char 211:  */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	0x77,	/*=   [ ***]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 212:  */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x77,	/*=   [ ***]        */
+	0x77,	/*=   [ ***]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 213:  */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x77,	/*=   [ ***]        */
+	0x77,	/*=   [ ***]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	/*}*/
+	/*{*/ 	/*   Char 214:  */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x77,	/*=   [ ***]        */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	/*}*/
+	/*{*/ 	/*   Char 215:  */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	0xff,	/*=   [****]        */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	/*}*/
+	/*{*/ 	/*   Char 216:  */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0xff,	/*=   [****]        */
+	0xff,	/*=   [****]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	/*}*/
+	/*{*/ 	/*   Char 217:  */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0xcc,	/*=   [**  ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 218:  */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x77,	/*=   [ ***]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	0x44,	/*=   [ *  ]        */
+	/*}*/
+	/*{*/ 	/*   Char 219:  */
+	0xff,	/*=   [****]        */
+	0xff,	/*=   [****]        */
+	0xff,	/*=   [****]        */
+	0xff,	/*=   [****]        */
+	0xff,	/*=   [****]        */
+	0xff,	/*=   [****]        */
+	/*}*/
+	/*{*/ 	/*   Char 220:  */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0xff,	/*=   [****]        */
+	0xff,	/*=   [****]        */
+	0xff,	/*=   [****]        */
+	/*}*/
+	/*{*/ 	/*   Char 221:  */
+	0xcc,	/*=   [**  ]        */
+	0xcc,	/*=   [**  ]        */
+	0xcc,	/*=   [**  ]        */
+	0xcc,	/*=   [**  ]        */
+	0xcc,	/*=   [**  ]        */
+	0xcc,	/*=   [**  ]        */
+	/*}*/
+	/*{*/ 	/*   Char 222:  */
+	0x33,	/*=   [  **]        */
+	0x33,	/*=   [  **]        */
+	0x33,	/*=   [  **]        */
+	0x33,	/*=   [  **]        */
+	0x33,	/*=   [  **]        */
+	0x33,	/*=   [  **]        */
+	/*}*/
+	/*{*/ 	/*   Char 223:  */
+	0xff,	/*=   [****]        */
+	0xff,	/*=   [****]        */
+	0xff,	/*=   [****]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 224:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 225:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 226:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 227:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 228:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 229:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 230:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 231:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 232:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 233:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 234:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 235:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 236:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 237:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 238:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 239:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 240:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 241:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 242:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 243:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 244:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 245:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 246:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 247:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 248:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 249:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 250:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 251:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 252:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 253:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 254:  */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	0x66,	/*=   [ ** ]        */
+	0x66,	/*=   [ ** ]        */
+	0x00,	/*=   [    ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+	/*{*/ 	/*   Char 255:  */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0xee,	/*=   [*** ]        */
+	0x00,	/*=   [    ]        */
+	/*}*/
+};
+
+struct font_desc font_mini_4x6 = {
+	MINI4x6_IDX,
+	"MINI4x6",
+	4,
+	6,
+	fontdata_mini_4x6,
+	3
+};
+
diff --git a/drivers/video/console/font_pearl_8x8.c b/drivers/video/console/font_pearl_8x8.c
new file mode 100644
index 0000000..5fa95f1
--- /dev/null
+++ b/drivers/video/console/font_pearl_8x8.c
@@ -0,0 +1,2587 @@
+/**********************************************/
+/*                                            */
+/*       Font file generated by cpi2fnt       */
+/*       ------------------------------       */
+/*       Combined with the alpha-numeric      */
+/*       portion of Greg Harp's old PEARL     */
+/*       font (from earlier versions of       */
+/*       linux-m86k) by John Shifflett        */
+/*                                            */
+/**********************************************/
+
+#include <linux/font.h>
+
+#define FONTDATAMAX 2048
+
+static unsigned char fontdata_pearl8x8[FONTDATAMAX] = {
+
+   /* 0 0x00 '^@' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 1 0x01 '^A' */
+   0x7e, /* 01111110 */
+   0x81, /* 10000001 */
+   0xa5, /* 10100101 */
+   0x81, /* 10000001 */
+   0xbd, /* 10111101 */
+   0x99, /* 10011001 */
+   0x81, /* 10000001 */
+   0x7e, /* 01111110 */
+
+   /* 2 0x02 '^B' */
+   0x7e, /* 01111110 */
+   0xff, /* 11111111 */
+   0xdb, /* 11011011 */
+   0xff, /* 11111111 */
+   0xc3, /* 11000011 */
+   0xe7, /* 11100111 */
+   0xff, /* 11111111 */
+   0x7e, /* 01111110 */
+
+   /* 3 0x03 '^C' */
+   0x6c, /* 01101100 */
+   0xfe, /* 11111110 */
+   0xfe, /* 11111110 */
+   0xfe, /* 11111110 */
+   0x7c, /* 01111100 */
+   0x38, /* 00111000 */
+   0x10, /* 00010000 */
+   0x00, /* 00000000 */
+
+   /* 4 0x04 '^D' */
+   0x10, /* 00010000 */
+   0x38, /* 00111000 */
+   0x7c, /* 01111100 */
+   0xfe, /* 11111110 */
+   0x7c, /* 01111100 */
+   0x38, /* 00111000 */
+   0x10, /* 00010000 */
+   0x00, /* 00000000 */
+
+   /* 5 0x05 '^E' */
+   0x38, /* 00111000 */
+   0x7c, /* 01111100 */
+   0x38, /* 00111000 */
+   0xfe, /* 11111110 */
+   0xfe, /* 11111110 */
+   0xd6, /* 11010110 */
+   0x10, /* 00010000 */
+   0x38, /* 00111000 */
+
+   /* 6 0x06 '^F' */
+   0x10, /* 00010000 */
+   0x38, /* 00111000 */
+   0x7c, /* 01111100 */
+   0xfe, /* 11111110 */
+   0xfe, /* 11111110 */
+   0x7c, /* 01111100 */
+   0x10, /* 00010000 */
+   0x38, /* 00111000 */
+
+   /* 7 0x07 '^G' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x18, /* 00011000 */
+   0x3c, /* 00111100 */
+   0x3c, /* 00111100 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 8 0x08 '^H' */
+   0xff, /* 11111111 */
+   0xff, /* 11111111 */
+   0xe7, /* 11100111 */
+   0xc3, /* 11000011 */
+   0xc3, /* 11000011 */
+   0xe7, /* 11100111 */
+   0xff, /* 11111111 */
+   0xff, /* 11111111 */
+
+   /* 9 0x09 '^I' */
+   0x00, /* 00000000 */
+   0x3c, /* 00111100 */
+   0x66, /* 01100110 */
+   0x42, /* 01000010 */
+   0x42, /* 01000010 */
+   0x66, /* 01100110 */
+   0x3c, /* 00111100 */
+   0x00, /* 00000000 */
+
+   /* 10 0x0a '^J' */
+   0xff, /* 11111111 */
+   0xc3, /* 11000011 */
+   0x99, /* 10011001 */
+   0xbd, /* 10111101 */
+   0xbd, /* 10111101 */
+   0x99, /* 10011001 */
+   0xc3, /* 11000011 */
+   0xff, /* 11111111 */
+
+   /* 11 0x0b '^K' */
+   0x0f, /* 00001111 */
+   0x07, /* 00000111 */
+   0x0f, /* 00001111 */
+   0x7d, /* 01111101 */
+   0xcc, /* 11001100 */
+   0xcc, /* 11001100 */
+   0xcc, /* 11001100 */
+   0x78, /* 01111000 */
+
+   /* 12 0x0c '^L' */
+   0x3c, /* 00111100 */
+   0x66, /* 01100110 */
+   0x66, /* 01100110 */
+   0x66, /* 01100110 */
+   0x3c, /* 00111100 */
+   0x18, /* 00011000 */
+   0x7e, /* 01111110 */
+   0x18, /* 00011000 */
+
+   /* 13 0x0d '^M' */
+   0x3f, /* 00111111 */
+   0x33, /* 00110011 */
+   0x3f, /* 00111111 */
+   0x30, /* 00110000 */
+   0x30, /* 00110000 */
+   0x70, /* 01110000 */
+   0xf0, /* 11110000 */
+   0xe0, /* 11100000 */
+
+   /* 14 0x0e '^N' */
+   0x7f, /* 01111111 */
+   0x63, /* 01100011 */
+   0x7f, /* 01111111 */
+   0x63, /* 01100011 */
+   0x63, /* 01100011 */
+   0x67, /* 01100111 */
+   0xe6, /* 11100110 */
+   0xc0, /* 11000000 */
+
+   /* 15 0x0f '^O' */
+   0x18, /* 00011000 */
+   0xdb, /* 11011011 */
+   0x3c, /* 00111100 */
+   0xe7, /* 11100111 */
+   0xe7, /* 11100111 */
+   0x3c, /* 00111100 */
+   0xdb, /* 11011011 */
+   0x18, /* 00011000 */
+
+   /* 16 0x10 '^P' */
+   0x80, /* 10000000 */
+   0xe0, /* 11100000 */
+   0xf8, /* 11111000 */
+   0xfe, /* 11111110 */
+   0xf8, /* 11111000 */
+   0xe0, /* 11100000 */
+   0x80, /* 10000000 */
+   0x00, /* 00000000 */
+
+   /* 17 0x11 '^Q' */
+   0x02, /* 00000010 */
+   0x0e, /* 00001110 */
+   0x3e, /* 00111110 */
+   0xfe, /* 11111110 */
+   0x3e, /* 00111110 */
+   0x0e, /* 00001110 */
+   0x02, /* 00000010 */
+   0x00, /* 00000000 */
+
+   /* 18 0x12 '^R' */
+   0x18, /* 00011000 */
+   0x3c, /* 00111100 */
+   0x7e, /* 01111110 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x7e, /* 01111110 */
+   0x3c, /* 00111100 */
+   0x18, /* 00011000 */
+
+   /* 19 0x13 '^S' */
+   0x66, /* 01100110 */
+   0x66, /* 01100110 */
+   0x66, /* 01100110 */
+   0x66, /* 01100110 */
+   0x66, /* 01100110 */
+   0x00, /* 00000000 */
+   0x66, /* 01100110 */
+   0x00, /* 00000000 */
+
+   /* 20 0x14 '^T' */
+   0x7f, /* 01111111 */
+   0xdb, /* 11011011 */
+   0xdb, /* 11011011 */
+   0x7b, /* 01111011 */
+   0x1b, /* 00011011 */
+   0x1b, /* 00011011 */
+   0x1b, /* 00011011 */
+   0x00, /* 00000000 */
+
+   /* 21 0x15 '^U' */
+   0x3e, /* 00111110 */
+   0x61, /* 01100001 */
+   0x3c, /* 00111100 */
+   0x66, /* 01100110 */
+   0x66, /* 01100110 */
+   0x3c, /* 00111100 */
+   0x86, /* 10000110 */
+   0x7c, /* 01111100 */
+
+   /* 22 0x16 '^V' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x7e, /* 01111110 */
+   0x7e, /* 01111110 */
+   0x7e, /* 01111110 */
+   0x00, /* 00000000 */
+
+   /* 23 0x17 '^W' */
+   0x18, /* 00011000 */
+   0x3c, /* 00111100 */
+   0x7e, /* 01111110 */
+   0x18, /* 00011000 */
+   0x7e, /* 01111110 */
+   0x3c, /* 00111100 */
+   0x18, /* 00011000 */
+   0xff, /* 11111111 */
+
+   /* 24 0x18 '^X' */
+   0x18, /* 00011000 */
+   0x3c, /* 00111100 */
+   0x7e, /* 01111110 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+
+   /* 25 0x19 '^Y' */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x7e, /* 01111110 */
+   0x3c, /* 00111100 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+
+   /* 26 0x1a '^Z' */
+   0x00, /* 00000000 */
+   0x18, /* 00011000 */
+   0x0c, /* 00001100 */
+   0xfe, /* 11111110 */
+   0x0c, /* 00001100 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 27 0x1b '^[' */
+   0x00, /* 00000000 */
+   0x30, /* 00110000 */
+   0x60, /* 01100000 */
+   0xfe, /* 11111110 */
+   0x60, /* 01100000 */
+   0x30, /* 00110000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 28 0x1c '^\' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0xfe, /* 11111110 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 29 0x1d '^]' */
+   0x00, /* 00000000 */
+   0x24, /* 00100100 */
+   0x66, /* 01100110 */
+   0xff, /* 11111111 */
+   0x66, /* 01100110 */
+   0x24, /* 00100100 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 30 0x1e '^^' */
+   0x00, /* 00000000 */
+   0x18, /* 00011000 */
+   0x3c, /* 00111100 */
+   0x7e, /* 01111110 */
+   0xff, /* 11111111 */
+   0xff, /* 11111111 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 31 0x1f '^_' */
+   0x00, /* 00000000 */
+   0xff, /* 11111111 */
+   0xff, /* 11111111 */
+   0x7e, /* 01111110 */
+   0x3c, /* 00111100 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 32 0x20 ' ' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 33 0x21 '!' */
+   0x18, /* 00011000 */
+   0x3c, /* 00111100 */
+   0x3c, /* 00111100 */
+   0x3c, /* 00111100 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+
+   /* 34 0x22 '"' */
+   0x6c, /* 01101100 */
+   0x6c, /* 01101100 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 35 0x23 '#' */
+   0x6c, /* 01101100 */
+   0x6c, /* 01101100 */
+   0xfe, /* 11111110 */
+   0x6c, /* 01101100 */
+   0xfe, /* 11111110 */
+   0x6c, /* 01101100 */
+   0x6c, /* 01101100 */
+   0x00, /* 00000000 */
+
+   /* 36 0x24 '$' */
+   0x18, /* 00011000 */
+   0x3e, /* 00111110 */
+   0x60, /* 01100000 */
+   0x3c, /* 00111100 */
+   0x06, /* 00000110 */
+   0x7c, /* 01111100 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+
+   /* 37 0x25 '%' */
+   0x00, /* 00000000 */
+   0xc6, /* 11000110 */
+   0xcc, /* 11001100 */
+   0x18, /* 00011000 */
+   0x30, /* 00110000 */
+   0x66, /* 01100110 */
+   0xc6, /* 11000110 */
+   0x00, /* 00000000 */
+
+   /* 38 0x26 '&' */
+   0x38, /* 00111000 */
+   0x6c, /* 01101100 */
+   0x68, /* 01101000 */
+   0x76, /* 01110110 */
+   0xdc, /* 11011100 */
+   0xcc, /* 11001100 */
+   0x76, /* 01110110 */
+   0x00, /* 00000000 */
+
+   /* 39 0x27 ''' */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x30, /* 00110000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 40 0x28 '(' */
+   0x0c, /* 00001100 */
+   0x18, /* 00011000 */
+   0x30, /* 00110000 */
+   0x30, /* 00110000 */
+   0x30, /* 00110000 */
+   0x18, /* 00011000 */
+   0x0c, /* 00001100 */
+   0x00, /* 00000000 */
+
+   /* 41 0x29 ')' */
+   0x30, /* 00110000 */
+   0x18, /* 00011000 */
+   0x0c, /* 00001100 */
+   0x0c, /* 00001100 */
+   0x0c, /* 00001100 */
+   0x18, /* 00011000 */
+   0x30, /* 00110000 */
+   0x00, /* 00000000 */
+
+   /* 42 0x2a '*' */
+   0x00, /* 00000000 */
+   0x66, /* 01100110 */
+   0x3c, /* 00111100 */
+   0xff, /* 11111111 */
+   0x3c, /* 00111100 */
+   0x66, /* 01100110 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 43 0x2b '+' */
+   0x00, /* 00000000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x7e, /* 01111110 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 44 0x2c ',' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x30, /* 00110000 */
+
+   /* 45 0x2d '-' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x7e, /* 01111110 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 46 0x2e '.' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+
+   /* 47 0x2f '/' */
+   0x03, /* 00000011 */
+   0x06, /* 00000110 */
+   0x0c, /* 00001100 */
+   0x18, /* 00011000 */
+   0x30, /* 00110000 */
+   0x60, /* 01100000 */
+   0xc0, /* 11000000 */
+   0x00, /* 00000000 */
+
+   /* 48 0x30 '0' */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0xde, /* 11011110 */
+   0xfe, /* 11111110 */
+   0xf6, /* 11110110 */
+   0xc6, /* 11000110 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+
+   /* 49 0x31 '1' */
+   0x18, /* 00011000 */
+   0x78, /* 01111000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+
+   /* 50 0x32 '2' */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0x0c, /* 00001100 */
+   0x18, /* 00011000 */
+   0x30, /* 00110000 */
+   0x60, /* 01100000 */
+   0xfe, /* 11111110 */
+   0x00, /* 00000000 */
+
+   /* 51 0x33 '3' */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0x06, /* 00000110 */
+   0x1c, /* 00011100 */
+   0x06, /* 00000110 */
+   0xc6, /* 11000110 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+
+   /* 52 0x34 '4' */
+   0x1c, /* 00011100 */
+   0x3c, /* 00111100 */
+   0x6c, /* 01101100 */
+   0xcc, /* 11001100 */
+   0xfe, /* 11111110 */
+   0x0c, /* 00001100 */
+   0x0c, /* 00001100 */
+   0x00, /* 00000000 */
+
+   /* 53 0x35 '5' */
+   0xfe, /* 11111110 */
+   0xc0, /* 11000000 */
+   0xfc, /* 11111100 */
+   0x06, /* 00000110 */
+   0x06, /* 00000110 */
+   0xc6, /* 11000110 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+
+   /* 54 0x36 '6' */
+   0x38, /* 00111000 */
+   0x60, /* 01100000 */
+   0xc0, /* 11000000 */
+   0xfc, /* 11111100 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+
+   /* 55 0x37 '7' */
+   0xfe, /* 11111110 */
+   0x06, /* 00000110 */
+   0x0c, /* 00001100 */
+   0x18, /* 00011000 */
+   0x30, /* 00110000 */
+   0x60, /* 01100000 */
+   0x60, /* 01100000 */
+   0x00, /* 00000000 */
+
+   /* 56 0x38 '8' */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+
+   /* 57 0x39 '9' */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x7e, /* 01111110 */
+   0x06, /* 00000110 */
+   0x0c, /* 00001100 */
+   0x38, /* 00111000 */
+   0x00, /* 00000000 */
+
+   /* 58 0x3a ':' */
+   0x00, /* 00000000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+
+   /* 59 0x3b ';' */
+   0x00, /* 00000000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x30, /* 00110000 */
+
+   /* 60 0x3c '<' */
+   0x0c, /* 00001100 */
+   0x18, /* 00011000 */
+   0x30, /* 00110000 */
+   0x60, /* 01100000 */
+   0x30, /* 00110000 */
+   0x18, /* 00011000 */
+   0x0c, /* 00001100 */
+   0x00, /* 00000000 */
+
+   /* 61 0x3d '=' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x7e, /* 01111110 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x7e, /* 01111110 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 62 0x3e '>' */
+   0x30, /* 00110000 */
+   0x18, /* 00011000 */
+   0x0c, /* 00001100 */
+   0x06, /* 00000110 */
+   0x0c, /* 00001100 */
+   0x18, /* 00011000 */
+   0x30, /* 00110000 */
+   0x00, /* 00000000 */
+
+   /* 63 0x3f '?' */
+   0x3c, /* 00111100 */
+   0x66, /* 01100110 */
+   0x06, /* 00000110 */
+   0x0c, /* 00001100 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+
+   /* 64 0x40 '@' */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0xde, /* 11011110 */
+   0xde, /* 11011110 */
+   0xde, /* 11011110 */
+   0xc0, /* 11000000 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+
+   /* 65 0x41 'A' */
+   0x10, /* 00010000 */
+   0x38, /* 00111000 */
+   0x6c, /* 01101100 */
+   0xc6, /* 11000110 */
+   0xfe, /* 11111110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x00, /* 00000000 */
+
+   /* 66 0x42 'B' */
+   0xfc, /* 11111100 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xfc, /* 11111100 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xfc, /* 11111100 */
+   0x00, /* 00000000 */
+
+   /* 67 0x43 'C' */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0xc6, /* 11000110 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+
+   /* 68 0x44 'D' */
+   0xfc, /* 11111100 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xfc, /* 11111100 */
+   0x00, /* 00000000 */
+
+   /* 69 0x45 'E' */
+   0xfe, /* 11111110 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0xf8, /* 11111000 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0xfe, /* 11111110 */
+   0x00, /* 00000000 */
+
+   /* 70 0x46 'F' */
+   0xfe, /* 11111110 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0xf8, /* 11111000 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0x00, /* 00000000 */
+
+   /* 71 0x47 'G' */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0xc0, /* 11000000 */
+   0xce, /* 11001110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+
+   /* 72 0x48 'H' */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xfe, /* 11111110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x00, /* 00000000 */
+
+   /* 73 0x49 'I' */
+   0x7e, /* 01111110 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x7e, /* 01111110 */
+   0x00, /* 00000000 */
+
+   /* 74 0x4a 'J' */
+   0x06, /* 00000110 */
+   0x06, /* 00000110 */
+   0x06, /* 00000110 */
+   0x06, /* 00000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+
+   /* 75 0x4b 'K' */
+   0xc6, /* 11000110 */
+   0xcc, /* 11001100 */
+   0xd8, /* 11011000 */
+   0xf0, /* 11110000 */
+   0xd8, /* 11011000 */
+   0xcc, /* 11001100 */
+   0xc6, /* 11000110 */
+   0x00, /* 00000000 */
+
+   /* 76 0x4c 'L' */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0xfe, /* 11111110 */
+   0x00, /* 00000000 */
+
+   /* 77 0x4d 'M' */
+   0x82, /* 10000010 */
+   0xc6, /* 11000110 */
+   0xee, /* 11101110 */
+   0xfe, /* 11111110 */
+   0xd6, /* 11010110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x00, /* 00000000 */
+
+   /* 78 0x4e 'N' */
+   0xc6, /* 11000110 */
+   0xe6, /* 11100110 */
+   0xf6, /* 11110110 */
+   0xde, /* 11011110 */
+   0xce, /* 11001110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x00, /* 00000000 */
+
+   /* 79 0x4f 'O' */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+
+   /* 80 0x50 'P' */
+   0xfc, /* 11111100 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xfc, /* 11111100 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0x00, /* 00000000 */
+
+   /* 81 0x51 'Q' */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xf6, /* 11110110 */
+   0xde, /* 11011110 */
+   0x7c, /* 01111100 */
+   0x06, /* 00000110 */
+
+   /* 82 0x52 'R' */
+   0xfc, /* 11111100 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xfc, /* 11111100 */
+   0xd8, /* 11011000 */
+   0xcc, /* 11001100 */
+   0xc6, /* 11000110 */
+   0x00, /* 00000000 */
+
+   /* 83 0x53 'S' */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0x60, /* 01100000 */
+   0x38, /* 00111000 */
+   0x0c, /* 00001100 */
+   0xc6, /* 11000110 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+
+   /* 84 0x54 'T' */
+   0x7e, /* 01111110 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+
+   /* 85 0x55 'U' */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+
+   /* 86 0x56 'V' */
+   0xc3, /* 11000011 */
+   0xc3, /* 11000011 */
+   0x66, /* 01100110 */
+   0x66, /* 01100110 */
+   0x3c, /* 00111100 */
+   0x3c, /* 00111100 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+
+   /* 87 0x57 'W' */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xd6, /* 11010110 */
+   0xfe, /* 11111110 */
+   0xee, /* 11101110 */
+   0xc6, /* 11000110 */
+   0x00, /* 00000000 */
+
+   /* 88 0x58 'X' */
+   0xc3, /* 11000011 */
+   0x66, /* 01100110 */
+   0x3c, /* 00111100 */
+   0x18, /* 00011000 */
+   0x3c, /* 00111100 */
+   0x66, /* 01100110 */
+   0xc3, /* 11000011 */
+   0x00, /* 00000000 */
+
+   /* 89 0x59 'Y' */
+   0xc3, /* 11000011 */
+   0xc3, /* 11000011 */
+   0x66, /* 01100110 */
+   0x3c, /* 00111100 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+
+   /* 90 0x5a 'Z' */
+   0xfe, /* 11111110 */
+   0x06, /* 00000110 */
+   0x0c, /* 00001100 */
+   0x18, /* 00011000 */
+   0x30, /* 00110000 */
+   0x60, /* 01100000 */
+   0xfe, /* 11111110 */
+   0x00, /* 00000000 */
+
+   /* 91 0x5b '[' */
+   0x3c, /* 00111100 */
+   0x30, /* 00110000 */
+   0x30, /* 00110000 */
+   0x30, /* 00110000 */
+   0x30, /* 00110000 */
+   0x30, /* 00110000 */
+   0x3c, /* 00111100 */
+   0x00, /* 00000000 */
+
+   /* 92 0x5c '\' */
+   0xc0, /* 11000000 */
+   0x60, /* 01100000 */
+   0x30, /* 00110000 */
+   0x18, /* 00011000 */
+   0x0c, /* 00001100 */
+   0x06, /* 00000110 */
+   0x03, /* 00000011 */
+   0x00, /* 00000000 */
+
+   /* 93 0x5d ']' */
+   0x3c, /* 00111100 */
+   0x0c, /* 00001100 */
+   0x0c, /* 00001100 */
+   0x0c, /* 00001100 */
+   0x0c, /* 00001100 */
+   0x0c, /* 00001100 */
+   0x3c, /* 00111100 */
+   0x00, /* 00000000 */
+
+   /* 94 0x5e '^' */
+   0x10, /* 00010000 */
+   0x38, /* 00111000 */
+   0x6c, /* 01101100 */
+   0xc6, /* 11000110 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 95 0x5f '_' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xfe, /* 11111110 */
+
+   /* 96 0x60 '`' */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x0c, /* 00001100 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 97 0x61 'a' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x7c, /* 01111100 */
+   0x06, /* 00000110 */
+   0x7e, /* 01111110 */
+   0xc6, /* 11000110 */
+   0x7e, /* 01111110 */
+   0x00, /* 00000000 */
+
+   /* 98 0x62 'b' */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0xfc, /* 11111100 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xfc, /* 11111100 */
+   0x00, /* 00000000 */
+
+   /* 99 0x63 'c' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0xc0, /* 11000000 */
+   0xc6, /* 11000110 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+
+   /* 100 0x64 'd' */
+   0x06, /* 00000110 */
+   0x06, /* 00000110 */
+   0x7e, /* 01111110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x7e, /* 01111110 */
+   0x00, /* 00000000 */
+
+   /* 101 0x65 'e' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0xfe, /* 11111110 */
+   0xc0, /* 11000000 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+
+   /* 102 0x66 'f' */
+   0x3c, /* 00111100 */
+   0x66, /* 01100110 */
+   0x60, /* 01100000 */
+   0xf0, /* 11110000 */
+   0x60, /* 01100000 */
+   0x60, /* 01100000 */
+   0x60, /* 01100000 */
+   0x00, /* 00000000 */
+
+   /* 103 0x67 'g' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x7e, /* 01111110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x7e, /* 01111110 */
+   0x06, /* 00000110 */
+   0x7c, /* 01111100 */
+
+   /* 104 0x68 'h' */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0xfc, /* 11111100 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x00, /* 00000000 */
+
+   /* 105 0x69 'i' */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+   0x38, /* 00111000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+
+   /* 106 0x6a 'j' */
+   0x06, /* 00000110 */
+   0x00, /* 00000000 */
+   0x06, /* 00000110 */
+   0x06, /* 00000110 */
+   0x06, /* 00000110 */
+   0x06, /* 00000110 */
+   0xc6, /* 11000110 */
+   0x7c, /* 01111100 */
+
+   /* 107 0x6b 'k' */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0xcc, /* 11001100 */
+   0xd8, /* 11011000 */
+   0xf0, /* 11110000 */
+   0xd8, /* 11011000 */
+   0xcc, /* 11001100 */
+   0x00, /* 00000000 */
+
+   /* 108 0x6c 'l' */
+   0x38, /* 00111000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+
+   /* 109 0x6d 'm' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xec, /* 11101100 */
+   0xfe, /* 11111110 */
+   0xd6, /* 11010110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x00, /* 00000000 */
+
+   /* 110 0x6e 'n' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xfc, /* 11111100 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x00, /* 00000000 */
+
+   /* 111 0x6f 'o' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+
+   /* 112 0x70 'p' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xfc, /* 11111100 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xfc, /* 11111100 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+
+   /* 113 0x71 'q' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x7e, /* 01111110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x7e, /* 01111110 */
+   0x06, /* 00000110 */
+   0x06, /* 00000110 */
+
+   /* 114 0x72 'r' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xdc, /* 11011100 */
+   0xe6, /* 11100110 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0x00, /* 00000000 */
+
+   /* 115 0x73 's' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x7e, /* 01111110 */
+   0xc0, /* 11000000 */
+   0x7c, /* 01111100 */
+   0x06, /* 00000110 */
+   0xfc, /* 11111100 */
+   0x00, /* 00000000 */
+
+   /* 116 0x74 't' */
+   0x30, /* 00110000 */
+   0x30, /* 00110000 */
+   0x7c, /* 01111100 */
+   0x30, /* 00110000 */
+   0x30, /* 00110000 */
+   0x36, /* 00110110 */
+   0x1c, /* 00011100 */
+   0x00, /* 00000000 */
+
+   /* 117 0x75 'u' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+
+   /* 118 0x76 'v' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x6c, /* 01101100 */
+   0x38, /* 00111000 */
+   0x00, /* 00000000 */
+
+   /* 119 0x77 'w' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xd6, /* 11010110 */
+   0xfe, /* 11111110 */
+   0x6c, /* 01101100 */
+   0x00, /* 00000000 */
+
+   /* 120 0x78 'x' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xc6, /* 11000110 */
+   0x6c, /* 01101100 */
+   0x38, /* 00111000 */
+   0x6c, /* 01101100 */
+   0xc6, /* 11000110 */
+   0x00, /* 00000000 */
+
+   /* 121 0x79 'y' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xc3, /* 11000011 */
+   0x66, /* 01100110 */
+   0x3c, /* 00111100 */
+   0x18, /* 00011000 */
+   0x30, /* 00110000 */
+   0x60, /* 01100000 */
+
+   /* 122 0x7a 'z' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xfe, /* 11111110 */
+   0x0c, /* 00001100 */
+   0x38, /* 00111000 */
+   0x60, /* 01100000 */
+   0xfe, /* 11111110 */
+   0x00, /* 00000000 */
+
+   /* 123 0x7b '{' */
+   0x0e, /* 00001110 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x70, /* 01110000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x0e, /* 00001110 */
+   0x00, /* 00000000 */
+
+   /* 124 0x7c '|' */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+
+   /* 125 0x7d '}' */
+   0x70, /* 01110000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x0e, /* 00001110 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x70, /* 01110000 */
+   0x00, /* 00000000 */
+
+   /* 126 0x7e '~' */
+   0x72, /* 01110010 */
+   0x9c, /* 10011100 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 127 0x7f '' */
+   0x00, /* 00000000 */
+   0x10, /* 00010000 */
+   0x38, /* 00111000 */
+   0x6c, /* 01101100 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xfe, /* 11111110 */
+   0x00, /* 00000000 */
+
+   /* 128 0x80 '€' */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0xc6, /* 11000110 */
+   0x7c, /* 01111100 */
+   0x0c, /* 00001100 */
+   0x78, /* 01111000 */
+
+   /* 129 0x81 '' */
+   0xcc, /* 11001100 */
+   0x00, /* 00000000 */
+   0xcc, /* 11001100 */
+   0xcc, /* 11001100 */
+   0xcc, /* 11001100 */
+   0xcc, /* 11001100 */
+   0x76, /* 01110110 */
+   0x00, /* 00000000 */
+
+   /* 130 0x82 '‚' */
+   0x0c, /* 00001100 */
+   0x18, /* 00011000 */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0xfe, /* 11111110 */
+   0xc0, /* 11000000 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+
+   /* 131 0x83 'ƒ' */
+   0x7c, /* 01111100 */
+   0x82, /* 10000010 */
+   0x78, /* 01111000 */
+   0x0c, /* 00001100 */
+   0x7c, /* 01111100 */
+   0xcc, /* 11001100 */
+   0x76, /* 01110110 */
+   0x00, /* 00000000 */
+
+   /* 132 0x84 '„' */
+   0xc6, /* 11000110 */
+   0x00, /* 00000000 */
+   0x78, /* 01111000 */
+   0x0c, /* 00001100 */
+   0x7c, /* 01111100 */
+   0xcc, /* 11001100 */
+   0x76, /* 01110110 */
+   0x00, /* 00000000 */
+
+   /* 133 0x85 '…' */
+   0x30, /* 00110000 */
+   0x18, /* 00011000 */
+   0x78, /* 01111000 */
+   0x0c, /* 00001100 */
+   0x7c, /* 01111100 */
+   0xcc, /* 11001100 */
+   0x76, /* 01110110 */
+   0x00, /* 00000000 */
+
+   /* 134 0x86 '†' */
+   0x30, /* 00110000 */
+   0x30, /* 00110000 */
+   0x78, /* 01111000 */
+   0x0c, /* 00001100 */
+   0x7c, /* 01111100 */
+   0xcc, /* 11001100 */
+   0x76, /* 01110110 */
+   0x00, /* 00000000 */
+
+   /* 135 0x87 '‡' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x7e, /* 01111110 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0x7e, /* 01111110 */
+   0x0c, /* 00001100 */
+   0x38, /* 00111000 */
+
+   /* 136 0x88 'ˆ' */
+   0x7c, /* 01111100 */
+   0x82, /* 10000010 */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0xfe, /* 11111110 */
+   0xc0, /* 11000000 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+
+   /* 137 0x89 '‰' */
+   0xc6, /* 11000110 */
+   0x00, /* 00000000 */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0xfe, /* 11111110 */
+   0xc0, /* 11000000 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+
+   /* 138 0x8a 'Š' */
+   0x30, /* 00110000 */
+   0x18, /* 00011000 */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0xfe, /* 11111110 */
+   0xc0, /* 11000000 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+
+   /* 139 0x8b '‹' */
+   0x66, /* 01100110 */
+   0x00, /* 00000000 */
+   0x38, /* 00111000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x3c, /* 00111100 */
+   0x00, /* 00000000 */
+
+   /* 140 0x8c 'Œ' */
+   0x7c, /* 01111100 */
+   0x82, /* 10000010 */
+   0x38, /* 00111000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x3c, /* 00111100 */
+   0x00, /* 00000000 */
+
+   /* 141 0x8d '' */
+   0x30, /* 00110000 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+   0x38, /* 00111000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x3c, /* 00111100 */
+   0x00, /* 00000000 */
+
+   /* 142 0x8e 'Ž' */
+   0xc6, /* 11000110 */
+   0x38, /* 00111000 */
+   0x6c, /* 01101100 */
+   0xc6, /* 11000110 */
+   0xfe, /* 11111110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x00, /* 00000000 */
+
+   /* 143 0x8f '' */
+   0x38, /* 00111000 */
+   0x6c, /* 01101100 */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0xfe, /* 11111110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x00, /* 00000000 */
+
+   /* 144 0x90 '' */
+   0x18, /* 00011000 */
+   0x30, /* 00110000 */
+   0xfe, /* 11111110 */
+   0xc0, /* 11000000 */
+   0xf8, /* 11111000 */
+   0xc0, /* 11000000 */
+   0xfe, /* 11111110 */
+   0x00, /* 00000000 */
+
+   /* 145 0x91 '‘' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x7e, /* 01111110 */
+   0x18, /* 00011000 */
+   0x7e, /* 01111110 */
+   0xd8, /* 11011000 */
+   0x7e, /* 01111110 */
+   0x00, /* 00000000 */
+
+   /* 146 0x92 '’' */
+   0x3e, /* 00111110 */
+   0x6c, /* 01101100 */
+   0xcc, /* 11001100 */
+   0xfe, /* 11111110 */
+   0xcc, /* 11001100 */
+   0xcc, /* 11001100 */
+   0xce, /* 11001110 */
+   0x00, /* 00000000 */
+
+   /* 147 0x93 '“' */
+   0x7c, /* 01111100 */
+   0x82, /* 10000010 */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+
+   /* 148 0x94 '”' */
+   0xc6, /* 11000110 */
+   0x00, /* 00000000 */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+
+   /* 149 0x95 '•' */
+   0x30, /* 00110000 */
+   0x18, /* 00011000 */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+
+   /* 150 0x96 '–' */
+   0x78, /* 01111000 */
+   0x84, /* 10000100 */
+   0x00, /* 00000000 */
+   0xcc, /* 11001100 */
+   0xcc, /* 11001100 */
+   0xcc, /* 11001100 */
+   0x76, /* 01110110 */
+   0x00, /* 00000000 */
+
+   /* 151 0x97 '—' */
+   0x60, /* 01100000 */
+   0x30, /* 00110000 */
+   0xcc, /* 11001100 */
+   0xcc, /* 11001100 */
+   0xcc, /* 11001100 */
+   0xcc, /* 11001100 */
+   0x76, /* 01110110 */
+   0x00, /* 00000000 */
+
+   /* 152 0x98 '˜' */
+   0xc6, /* 11000110 */
+   0x00, /* 00000000 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x7e, /* 01111110 */
+   0x06, /* 00000110 */
+   0xfc, /* 11111100 */
+
+   /* 153 0x99 '™' */
+   0xc6, /* 11000110 */
+   0x38, /* 00111000 */
+   0x6c, /* 01101100 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x6c, /* 01101100 */
+   0x38, /* 00111000 */
+   0x00, /* 00000000 */
+
+   /* 154 0x9a 'š' */
+   0xc6, /* 11000110 */
+   0x00, /* 00000000 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+
+   /* 155 0x9b '›' */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x7e, /* 01111110 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0x7e, /* 01111110 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+
+   /* 156 0x9c 'œ' */
+   0x38, /* 00111000 */
+   0x6c, /* 01101100 */
+   0x64, /* 01100100 */
+   0xf0, /* 11110000 */
+   0x60, /* 01100000 */
+   0x66, /* 01100110 */
+   0xfc, /* 11111100 */
+   0x00, /* 00000000 */
+
+   /* 157 0x9d '' */
+   0x66, /* 01100110 */
+   0x66, /* 01100110 */
+   0x3c, /* 00111100 */
+   0x7e, /* 01111110 */
+   0x18, /* 00011000 */
+   0x7e, /* 01111110 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+
+   /* 158 0x9e 'ž' */
+   0xf8, /* 11111000 */
+   0xcc, /* 11001100 */
+   0xcc, /* 11001100 */
+   0xfa, /* 11111010 */
+   0xc6, /* 11000110 */
+   0xcf, /* 11001111 */
+   0xc6, /* 11000110 */
+   0xc7, /* 11000111 */
+
+   /* 159 0x9f 'Ÿ' */
+   0x0e, /* 00001110 */
+   0x1b, /* 00011011 */
+   0x18, /* 00011000 */
+   0x3c, /* 00111100 */
+   0x18, /* 00011000 */
+   0xd8, /* 11011000 */
+   0x70, /* 01110000 */
+   0x00, /* 00000000 */
+
+   /* 160 0xa0 ' ' */
+   0x18, /* 00011000 */
+   0x30, /* 00110000 */
+   0x78, /* 01111000 */
+   0x0c, /* 00001100 */
+   0x7c, /* 01111100 */
+   0xcc, /* 11001100 */
+   0x76, /* 01110110 */
+   0x00, /* 00000000 */
+
+   /* 161 0xa1 '¡' */
+   0x0c, /* 00001100 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+   0x38, /* 00111000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x3c, /* 00111100 */
+   0x00, /* 00000000 */
+
+   /* 162 0xa2 '¢' */
+   0x0c, /* 00001100 */
+   0x18, /* 00011000 */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+
+   /* 163 0xa3 '£' */
+   0x18, /* 00011000 */
+   0x30, /* 00110000 */
+   0xcc, /* 11001100 */
+   0xcc, /* 11001100 */
+   0xcc, /* 11001100 */
+   0xcc, /* 11001100 */
+   0x76, /* 01110110 */
+   0x00, /* 00000000 */
+
+   /* 164 0xa4 '¤' */
+   0x76, /* 01110110 */
+   0xdc, /* 11011100 */
+   0x00, /* 00000000 */
+   0xdc, /* 11011100 */
+   0x66, /* 01100110 */
+   0x66, /* 01100110 */
+   0x66, /* 01100110 */
+   0x00, /* 00000000 */
+
+   /* 165 0xa5 '¥' */
+   0x76, /* 01110110 */
+   0xdc, /* 11011100 */
+   0x00, /* 00000000 */
+   0xe6, /* 11100110 */
+   0xf6, /* 11110110 */
+   0xde, /* 11011110 */
+   0xce, /* 11001110 */
+   0x00, /* 00000000 */
+
+   /* 166 0xa6 '¦' */
+   0x3c, /* 00111100 */
+   0x6c, /* 01101100 */
+   0x6c, /* 01101100 */
+   0x3e, /* 00111110 */
+   0x00, /* 00000000 */
+   0x7e, /* 01111110 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 167 0xa7 '§' */
+   0x38, /* 00111000 */
+   0x6c, /* 01101100 */
+   0x6c, /* 01101100 */
+   0x38, /* 00111000 */
+   0x00, /* 00000000 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 168 0xa8 '¨' */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x30, /* 00110000 */
+   0x63, /* 01100011 */
+   0x3e, /* 00111110 */
+   0x00, /* 00000000 */
+
+   /* 169 0xa9 '©' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xfe, /* 11111110 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 170 0xaa 'ª' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xfe, /* 11111110 */
+   0x06, /* 00000110 */
+   0x06, /* 00000110 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 171 0xab '«' */
+   0x63, /* 01100011 */
+   0xe6, /* 11100110 */
+   0x6c, /* 01101100 */
+   0x7e, /* 01111110 */
+   0x33, /* 00110011 */
+   0x66, /* 01100110 */
+   0xcc, /* 11001100 */
+   0x0f, /* 00001111 */
+
+   /* 172 0xac '¬' */
+   0x63, /* 01100011 */
+   0xe6, /* 11100110 */
+   0x6c, /* 01101100 */
+   0x7a, /* 01111010 */
+   0x36, /* 00110110 */
+   0x6a, /* 01101010 */
+   0xdf, /* 11011111 */
+   0x06, /* 00000110 */
+
+   /* 173 0xad '­' */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x3c, /* 00111100 */
+   0x3c, /* 00111100 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+
+   /* 174 0xae '®' */
+   0x00, /* 00000000 */
+   0x33, /* 00110011 */
+   0x66, /* 01100110 */
+   0xcc, /* 11001100 */
+   0x66, /* 01100110 */
+   0x33, /* 00110011 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 175 0xaf '¯' */
+   0x00, /* 00000000 */
+   0xcc, /* 11001100 */
+   0x66, /* 01100110 */
+   0x33, /* 00110011 */
+   0x66, /* 01100110 */
+   0xcc, /* 11001100 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 176 0xb0 '°' */
+   0x22, /* 00100010 */
+   0x88, /* 10001000 */
+   0x22, /* 00100010 */
+   0x88, /* 10001000 */
+   0x22, /* 00100010 */
+   0x88, /* 10001000 */
+   0x22, /* 00100010 */
+   0x88, /* 10001000 */
+
+   /* 177 0xb1 '±' */
+   0x55, /* 01010101 */
+   0xaa, /* 10101010 */
+   0x55, /* 01010101 */
+   0xaa, /* 10101010 */
+   0x55, /* 01010101 */
+   0xaa, /* 10101010 */
+   0x55, /* 01010101 */
+   0xaa, /* 10101010 */
+
+   /* 178 0xb2 '²' */
+   0x77, /* 01110111 */
+   0xdd, /* 11011101 */
+   0x77, /* 01110111 */
+   0xdd, /* 11011101 */
+   0x77, /* 01110111 */
+   0xdd, /* 11011101 */
+   0x77, /* 01110111 */
+   0xdd, /* 11011101 */
+
+   /* 179 0xb3 '³' */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+
+   /* 180 0xb4 '´' */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0xf8, /* 11111000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+
+   /* 181 0xb5 'µ' */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0xf8, /* 11111000 */
+   0x18, /* 00011000 */
+   0xf8, /* 11111000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+
+   /* 182 0xb6 '¶' */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0xf6, /* 11110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+
+   /* 183 0xb7 '·' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xfe, /* 11111110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+
+   /* 184 0xb8 '¸' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xf8, /* 11111000 */
+   0x18, /* 00011000 */
+   0xf8, /* 11111000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+
+   /* 185 0xb9 '¹' */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0xf6, /* 11110110 */
+   0x06, /* 00000110 */
+   0xf6, /* 11110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+
+   /* 186 0xba 'º' */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+
+   /* 187 0xbb '»' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xfe, /* 11111110 */
+   0x06, /* 00000110 */
+   0xf6, /* 11110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+
+   /* 188 0xbc '¼' */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0xf6, /* 11110110 */
+   0x06, /* 00000110 */
+   0xfe, /* 11111110 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 189 0xbd '½' */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0xfe, /* 11111110 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 190 0xbe '¾' */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0xf8, /* 11111000 */
+   0x18, /* 00011000 */
+   0xf8, /* 11111000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 191 0xbf '¿' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xf8, /* 11111000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+
+   /* 192 0xc0 'À' */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x1f, /* 00011111 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 193 0xc1 'Á' */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0xff, /* 11111111 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 194 0xc2 'Â' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xff, /* 11111111 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+
+   /* 195 0xc3 'Ã' */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x1f, /* 00011111 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+
+   /* 196 0xc4 'Ä' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xff, /* 11111111 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 197 0xc5 'Å' */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0xff, /* 11111111 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+
+   /* 198 0xc6 'Æ' */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x1f, /* 00011111 */
+   0x18, /* 00011000 */
+   0x1f, /* 00011111 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+
+   /* 199 0xc7 'Ç' */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x37, /* 00110111 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+
+   /* 200 0xc8 'È' */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x37, /* 00110111 */
+   0x30, /* 00110000 */
+   0x3f, /* 00111111 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 201 0xc9 'É' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x3f, /* 00111111 */
+   0x30, /* 00110000 */
+   0x37, /* 00110111 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+
+   /* 202 0xca 'Ê' */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0xf7, /* 11110111 */
+   0x00, /* 00000000 */
+   0xff, /* 11111111 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 203 0xcb 'Ë' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xff, /* 11111111 */
+   0x00, /* 00000000 */
+   0xf7, /* 11110111 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+
+   /* 204 0xcc 'Ì' */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x37, /* 00110111 */
+   0x30, /* 00110000 */
+   0x37, /* 00110111 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+
+   /* 205 0xcd 'Í' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xff, /* 11111111 */
+   0x00, /* 00000000 */
+   0xff, /* 11111111 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 206 0xce 'Î' */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0xf7, /* 11110111 */
+   0x00, /* 00000000 */
+   0xf7, /* 11110111 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+
+   /* 207 0xcf 'Ï' */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0xff, /* 11111111 */
+   0x00, /* 00000000 */
+   0xff, /* 11111111 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 208 0xd0 'Ð' */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0xff, /* 11111111 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 209 0xd1 'Ñ' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xff, /* 11111111 */
+   0x00, /* 00000000 */
+   0xff, /* 11111111 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+
+   /* 210 0xd2 'Ò' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xff, /* 11111111 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+
+   /* 211 0xd3 'Ó' */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x3f, /* 00111111 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 212 0xd4 'Ô' */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x1f, /* 00011111 */
+   0x18, /* 00011000 */
+   0x1f, /* 00011111 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 213 0xd5 'Õ' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x1f, /* 00011111 */
+   0x18, /* 00011000 */
+   0x1f, /* 00011111 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+
+   /* 214 0xd6 'Ö' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x3f, /* 00111111 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+
+   /* 215 0xd7 '×' */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0xff, /* 11111111 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+
+   /* 216 0xd8 'Ø' */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0xff, /* 11111111 */
+   0x18, /* 00011000 */
+   0xff, /* 11111111 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+
+   /* 217 0xd9 'Ù' */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0xf8, /* 11111000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 218 0xda 'Ú' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x1f, /* 00011111 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+
+   /* 219 0xdb 'Û' */
+   0xff, /* 11111111 */
+   0xff, /* 11111111 */
+   0xff, /* 11111111 */
+   0xff, /* 11111111 */
+   0xff, /* 11111111 */
+   0xff, /* 11111111 */
+   0xff, /* 11111111 */
+   0xff, /* 11111111 */
+
+   /* 220 0xdc 'Ü' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xff, /* 11111111 */
+   0xff, /* 11111111 */
+   0xff, /* 11111111 */
+   0xff, /* 11111111 */
+
+   /* 221 0xdd 'Ý' */
+   0xf0, /* 11110000 */
+   0xf0, /* 11110000 */
+   0xf0, /* 11110000 */
+   0xf0, /* 11110000 */
+   0xf0, /* 11110000 */
+   0xf0, /* 11110000 */
+   0xf0, /* 11110000 */
+   0xf0, /* 11110000 */
+
+   /* 222 0xde 'Þ' */
+   0x0f, /* 00001111 */
+   0x0f, /* 00001111 */
+   0x0f, /* 00001111 */
+   0x0f, /* 00001111 */
+   0x0f, /* 00001111 */
+   0x0f, /* 00001111 */
+   0x0f, /* 00001111 */
+   0x0f, /* 00001111 */
+
+   /* 223 0xdf 'ß' */
+   0xff, /* 11111111 */
+   0xff, /* 11111111 */
+   0xff, /* 11111111 */
+   0xff, /* 11111111 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 224 0xe0 'à' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x76, /* 01110110 */
+   0xdc, /* 11011100 */
+   0xc8, /* 11001000 */
+   0xdc, /* 11011100 */
+   0x76, /* 01110110 */
+   0x00, /* 00000000 */
+
+   /* 225 0xe1 'á' */
+   0x78, /* 01111000 */
+   0xcc, /* 11001100 */
+   0xcc, /* 11001100 */
+   0xd8, /* 11011000 */
+   0xcc, /* 11001100 */
+   0xc6, /* 11000110 */
+   0xcc, /* 11001100 */
+   0x00, /* 00000000 */
+
+   /* 226 0xe2 'â' */
+   0xfe, /* 11111110 */
+   0xc6, /* 11000110 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0xc0, /* 11000000 */
+   0x00, /* 00000000 */
+
+   /* 227 0xe3 'ã' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0xfe, /* 11111110 */
+   0x6c, /* 01101100 */
+   0x6c, /* 01101100 */
+   0x6c, /* 01101100 */
+   0x6c, /* 01101100 */
+   0x00, /* 00000000 */
+
+   /* 228 0xe4 'ä' */
+   0xfe, /* 11111110 */
+   0xc6, /* 11000110 */
+   0x60, /* 01100000 */
+   0x30, /* 00110000 */
+   0x60, /* 01100000 */
+   0xc6, /* 11000110 */
+   0xfe, /* 11111110 */
+   0x00, /* 00000000 */
+
+   /* 229 0xe5 'å' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x7e, /* 01111110 */
+   0xd8, /* 11011000 */
+   0xd8, /* 11011000 */
+   0xd8, /* 11011000 */
+   0x70, /* 01110000 */
+   0x00, /* 00000000 */
+
+   /* 230 0xe6 'æ' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x66, /* 01100110 */
+   0x66, /* 01100110 */
+   0x66, /* 01100110 */
+   0x66, /* 01100110 */
+   0x7c, /* 01111100 */
+   0xc0, /* 11000000 */
+
+   /* 231 0xe7 'ç' */
+   0x00, /* 00000000 */
+   0x76, /* 01110110 */
+   0xdc, /* 11011100 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+
+   /* 232 0xe8 'è' */
+   0x7e, /* 01111110 */
+   0x18, /* 00011000 */
+   0x3c, /* 00111100 */
+   0x66, /* 01100110 */
+   0x66, /* 01100110 */
+   0x3c, /* 00111100 */
+   0x18, /* 00011000 */
+   0x7e, /* 01111110 */
+
+   /* 233 0xe9 'é' */
+   0x38, /* 00111000 */
+   0x6c, /* 01101100 */
+   0xc6, /* 11000110 */
+   0xfe, /* 11111110 */
+   0xc6, /* 11000110 */
+   0x6c, /* 01101100 */
+   0x38, /* 00111000 */
+   0x00, /* 00000000 */
+
+   /* 234 0xea 'ê' */
+   0x38, /* 00111000 */
+   0x6c, /* 01101100 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x6c, /* 01101100 */
+   0x6c, /* 01101100 */
+   0xee, /* 11101110 */
+   0x00, /* 00000000 */
+
+   /* 235 0xeb 'ë' */
+   0x0e, /* 00001110 */
+   0x18, /* 00011000 */
+   0x0c, /* 00001100 */
+   0x3e, /* 00111110 */
+   0x66, /* 01100110 */
+   0x66, /* 01100110 */
+   0x3c, /* 00111100 */
+   0x00, /* 00000000 */
+
+   /* 236 0xec 'ì' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x7e, /* 01111110 */
+   0xdb, /* 11011011 */
+   0xdb, /* 11011011 */
+   0x7e, /* 01111110 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 237 0xed 'í' */
+   0x06, /* 00000110 */
+   0x0c, /* 00001100 */
+   0x7e, /* 01111110 */
+   0xdb, /* 11011011 */
+   0xdb, /* 11011011 */
+   0x7e, /* 01111110 */
+   0x60, /* 01100000 */
+   0xc0, /* 11000000 */
+
+   /* 238 0xee 'î' */
+   0x1e, /* 00011110 */
+   0x30, /* 00110000 */
+   0x60, /* 01100000 */
+   0x7e, /* 01111110 */
+   0x60, /* 01100000 */
+   0x30, /* 00110000 */
+   0x1e, /* 00011110 */
+   0x00, /* 00000000 */
+
+   /* 239 0xef 'ï' */
+   0x00, /* 00000000 */
+   0x7c, /* 01111100 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0xc6, /* 11000110 */
+   0x00, /* 00000000 */
+
+   /* 240 0xf0 'ð' */
+   0x00, /* 00000000 */
+   0xfe, /* 11111110 */
+   0x00, /* 00000000 */
+   0xfe, /* 11111110 */
+   0x00, /* 00000000 */
+   0xfe, /* 11111110 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 241 0xf1 'ñ' */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x7e, /* 01111110 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+   0x7e, /* 01111110 */
+   0x00, /* 00000000 */
+
+   /* 242 0xf2 'ò' */
+   0x30, /* 00110000 */
+   0x18, /* 00011000 */
+   0x0c, /* 00001100 */
+   0x18, /* 00011000 */
+   0x30, /* 00110000 */
+   0x00, /* 00000000 */
+   0x7e, /* 01111110 */
+   0x00, /* 00000000 */
+
+   /* 243 0xf3 'ó' */
+   0x0c, /* 00001100 */
+   0x18, /* 00011000 */
+   0x30, /* 00110000 */
+   0x18, /* 00011000 */
+   0x0c, /* 00001100 */
+   0x00, /* 00000000 */
+   0x7e, /* 01111110 */
+   0x00, /* 00000000 */
+
+   /* 244 0xf4 'ô' */
+   0x0e, /* 00001110 */
+   0x1b, /* 00011011 */
+   0x1b, /* 00011011 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+
+   /* 245 0xf5 'õ' */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0xd8, /* 11011000 */
+   0xd8, /* 11011000 */
+   0x70, /* 01110000 */
+
+   /* 246 0xf6 'ö' */
+   0x00, /* 00000000 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+   0x7e, /* 01111110 */
+   0x00, /* 00000000 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 247 0xf7 '÷' */
+   0x00, /* 00000000 */
+   0x76, /* 01110110 */
+   0xdc, /* 11011100 */
+   0x00, /* 00000000 */
+   0x76, /* 01110110 */
+   0xdc, /* 11011100 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 248 0xf8 'ø' */
+   0x38, /* 00111000 */
+   0x6c, /* 01101100 */
+   0x6c, /* 01101100 */
+   0x38, /* 00111000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 249 0xf9 'ù' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x18, /* 00011000 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 250 0xfa 'ú' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x18, /* 00011000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 251 0xfb 'û' */
+   0x0f, /* 00001111 */
+   0x0c, /* 00001100 */
+   0x0c, /* 00001100 */
+   0x0c, /* 00001100 */
+   0xec, /* 11101100 */
+   0x6c, /* 01101100 */
+   0x3c, /* 00111100 */
+   0x1c, /* 00011100 */
+
+   /* 252 0xfc 'ü' */
+   0x6c, /* 01101100 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x36, /* 00110110 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 253 0xfd 'ý' */
+   0x78, /* 01111000 */
+   0x0c, /* 00001100 */
+   0x18, /* 00011000 */
+   0x30, /* 00110000 */
+   0x7c, /* 01111100 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 254 0xfe 'þ' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x3c, /* 00111100 */
+   0x3c, /* 00111100 */
+   0x3c, /* 00111100 */
+   0x3c, /* 00111100 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+   /* 255 0xff 'ÿ' */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+   0x00, /* 00000000 */
+
+};
+
+struct font_desc font_pearl_8x8 = {
+	PEARL8x8_IDX,
+	"PEARL8x8",
+	8,
+	8,
+	fontdata_pearl8x8,
+	2
+};
diff --git a/drivers/video/console/font_sun12x22.c b/drivers/video/console/font_sun12x22.c
new file mode 100644
index 0000000..05215d0
--- /dev/null
+++ b/drivers/video/console/font_sun12x22.c
@@ -0,0 +1,6220 @@
+#include <linux/font.h>
+
+#define FONTDATAMAX 11264
+
+static unsigned char fontdata_sun12x22[FONTDATAMAX] = {
+
+	/* 0 0x00 '^@' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 1 0x01 '^A' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 2 0x02 '^B' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 3 0x03 '^C' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 4 0x04 '^D' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 5 0x05 '^E' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 6 0x06 '^F' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 7 0x07 '^G' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 8 0x08 '^H' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 9 0x09 '^I' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 10 0x0a '^J' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 11 0x0b '^K' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 12 0x0c '^L' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 13 0x0d '^M' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 14 0x0e '^N' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 15 0x0f '^O' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 16 0x10 '^P' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 17 0x11 '^Q' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 18 0x12 '^R' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 19 0x13 '^S' */
+	0x00, 0x00, /* 000000000000 */
+	0x31, 0x80, /* 001100011000 */
+	0x31, 0x80, /* 001100011000 */
+	0x31, 0x80, /* 001100011000 */
+	0x31, 0x80, /* 001100011000 */
+	0x31, 0x80, /* 001100011000 */
+	0x31, 0x80, /* 001100011000 */
+	0x31, 0x80, /* 001100011000 */
+	0x31, 0x80, /* 001100011000 */
+	0x31, 0x80, /* 001100011000 */
+	0x31, 0x80, /* 001100011000 */
+	0x31, 0x80, /* 001100011000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x31, 0x80, /* 001100011000 */
+	0x31, 0x80, /* 001100011000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 20 0x14 '^T' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x1f, 0xf0, /* 000111111111 */
+	0x3c, 0xc0, /* 001111001100 */
+	0x7c, 0xc0, /* 011111001100 */
+	0x7c, 0xc0, /* 011111001100 */
+	0x7c, 0xc0, /* 011111001100 */
+	0x3c, 0xc0, /* 001111001100 */
+	0x1c, 0xc0, /* 000111001100 */
+	0x0c, 0xc0, /* 000011001100 */
+	0x0c, 0xc0, /* 000011001100 */
+	0x0c, 0xc0, /* 000011001100 */
+	0x0c, 0xc0, /* 000011001100 */
+	0x0c, 0xc0, /* 000011001100 */
+	0x0c, 0xc0, /* 000011001100 */
+	0x1c, 0xe0, /* 000111001110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 21 0x15 '^U' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x1f, 0x00, /* 000111110000 */
+	0x31, 0x80, /* 001100011000 */
+	0x31, 0x80, /* 001100011000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x1f, 0x00, /* 000111110000 */
+	0x31, 0x80, /* 001100011000 */
+	0x31, 0x80, /* 001100011000 */
+	0x1f, 0x00, /* 000111110000 */
+	0x01, 0x80, /* 000000011000 */
+	0x01, 0x80, /* 000000011000 */
+	0x31, 0x80, /* 001100011000 */
+	0x31, 0x80, /* 001100011000 */
+	0x1f, 0x00, /* 000111110000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 22 0x16 '^V' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 23 0x17 '^W' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 24 0x18 '^X' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 25 0x19 '^Y' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 26 0x1a '^Z' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 27 0x1b '^[' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 28 0x1c '^\' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 29 0x1d '^]' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 30 0x1e '^^' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 31 0x1f '^_' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 32 0x20 ' ' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 33 0x21 '!' */
+	0x00, 0x00, /* 000000000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 34 0x22 '"' */
+	0x00, 0x00, /* 000000000000 */
+	0x19, 0x80, /* 000110011000 */
+	0x19, 0x80, /* 000110011000 */
+	0x19, 0x80, /* 000110011000 */
+	0x19, 0x80, /* 000110011000 */
+	0x19, 0x80, /* 000110011000 */
+	0x19, 0x80, /* 000110011000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 35 0x23 '#' */
+	0x00, 0x00, /* 000000000000 */
+	0x03, 0x30, /* 000000110011 */
+	0x03, 0x30, /* 000000110011 */
+	0x03, 0x30, /* 000000110011 */
+	0x06, 0x60, /* 000001100110 */
+	0x1f, 0xf0, /* 000111111111 */
+	0x1f, 0xf0, /* 000111111111 */
+	0x0c, 0xc0, /* 000011001100 */
+	0x0c, 0xc0, /* 000011001100 */
+	0x19, 0x80, /* 000110011000 */
+	0x19, 0x80, /* 000110011000 */
+	0x7f, 0xc0, /* 011111111100 */
+	0x7f, 0xc0, /* 011111111100 */
+	0x33, 0x00, /* 001100110000 */
+	0x66, 0x00, /* 011001100000 */
+	0x66, 0x00, /* 011001100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 36 0x24 '$' */
+	0x00, 0x00, /* 000000000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x1f, 0x80, /* 000111111000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x66, 0xe0, /* 011001101110 */
+	0x66, 0x60, /* 011001100110 */
+	0x66, 0x00, /* 011001100000 */
+	0x3e, 0x00, /* 001111100000 */
+	0x1f, 0x80, /* 000111111000 */
+	0x07, 0xc0, /* 000001111100 */
+	0x06, 0x60, /* 000001100110 */
+	0x06, 0x60, /* 000001100110 */
+	0x66, 0x60, /* 011001100110 */
+	0x7f, 0xc0, /* 011111111100 */
+	0x3f, 0x80, /* 001111111000 */
+	0x06, 0x00, /* 000001100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 37 0x25 '%' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x38, 0xc0, /* 001110001100 */
+	0x4c, 0xc0, /* 010011001100 */
+	0x45, 0x80, /* 010001011000 */
+	0x65, 0x80, /* 011001011000 */
+	0x3b, 0x00, /* 001110110000 */
+	0x03, 0x00, /* 000000110000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0d, 0xc0, /* 000011011100 */
+	0x1a, 0x60, /* 000110100110 */
+	0x1a, 0x20, /* 000110100010 */
+	0x33, 0x20, /* 001100110010 */
+	0x31, 0xc0, /* 001100011100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 38 0x26 '&' */
+	0x00, 0x00, /* 000000000000 */
+	0x07, 0x00, /* 000001110000 */
+	0x0f, 0x80, /* 000011111000 */
+	0x18, 0xc0, /* 000110001100 */
+	0x18, 0xc0, /* 000110001100 */
+	0x18, 0xc0, /* 000110001100 */
+	0x0f, 0x80, /* 000011111000 */
+	0x1e, 0x00, /* 000111100000 */
+	0x3e, 0x00, /* 001111100000 */
+	0x77, 0x00, /* 011101110000 */
+	0x63, 0x60, /* 011000110110 */
+	0x61, 0xe0, /* 011000011110 */
+	0x61, 0xc0, /* 011000011100 */
+	0x61, 0x80, /* 011000011000 */
+	0x3f, 0xe0, /* 001111111110 */
+	0x1e, 0x60, /* 000111100110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 39 0x27 ''' */
+	0x00, 0x00, /* 000000000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x1e, 0x00, /* 000111100000 */
+	0x1e, 0x00, /* 000111100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x18, 0x00, /* 000110000000 */
+	0x10, 0x00, /* 000100000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 40 0x28 '(' */
+	0x00, 0x00, /* 000000000000 */
+	0x01, 0x80, /* 000000011000 */
+	0x03, 0x00, /* 000000110000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x03, 0x00, /* 000000110000 */
+	0x01, 0x80, /* 000000011000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 41 0x29 ')' */
+	0x00, 0x00, /* 000000000000 */
+	0x18, 0x00, /* 000110000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x03, 0x00, /* 000000110000 */
+	0x03, 0x00, /* 000000110000 */
+	0x03, 0x00, /* 000000110000 */
+	0x03, 0x00, /* 000000110000 */
+	0x03, 0x00, /* 000000110000 */
+	0x03, 0x00, /* 000000110000 */
+	0x03, 0x00, /* 000000110000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x18, 0x00, /* 000110000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 42 0x2a '*' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x06, 0x00, /* 000001100000 */
+	0x66, 0x60, /* 011001100110 */
+	0x76, 0xe0, /* 011101101110 */
+	0x19, 0x80, /* 000110011000 */
+	0x00, 0x00, /* 000000000000 */
+	0x19, 0x80, /* 000110011000 */
+	0x76, 0xe0, /* 011101101110 */
+	0x66, 0x60, /* 011001100110 */
+	0x06, 0x00, /* 000001100000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 43 0x2b '+' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 44 0x2c ',' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x1e, 0x00, /* 000111100000 */
+	0x1e, 0x00, /* 000111100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x18, 0x00, /* 000110000000 */
+	0x10, 0x00, /* 000100000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 45 0x2d '-' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 46 0x2e '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x1e, 0x00, /* 000111100000 */
+	0x1e, 0x00, /* 000111100000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 47 0x2f '/' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x60, /* 000000000110 */
+	0x00, 0xc0, /* 000000001100 */
+	0x00, 0xc0, /* 000000001100 */
+	0x01, 0x80, /* 000000011000 */
+	0x01, 0x80, /* 000000011000 */
+	0x03, 0x00, /* 000000110000 */
+	0x03, 0x00, /* 000000110000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x18, 0x00, /* 000110000000 */
+	0x18, 0x00, /* 000110000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 48 0x30 '0' */
+	0x00, 0x00, /* 000000000000 */
+	0x07, 0x00, /* 000001110000 */
+	0x0f, 0x80, /* 000011111000 */
+	0x11, 0x80, /* 000100011000 */
+	0x10, 0xc0, /* 000100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0x80, /* 001100001000 */
+	0x18, 0x80, /* 000110001000 */
+	0x1f, 0x00, /* 000111110000 */
+	0x0e, 0x00, /* 000011100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 49 0x31 '1' */
+	0x00, 0x00, /* 000000000000 */
+	0x02, 0x00, /* 000000100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x0e, 0x00, /* 000011100000 */
+	0x1e, 0x00, /* 000111100000 */
+	0x36, 0x00, /* 001101100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 50 0x32 '2' */
+	0x00, 0x00, /* 000000000000 */
+	0x1f, 0x00, /* 000111110000 */
+	0x3f, 0x80, /* 001111111000 */
+	0x61, 0xc0, /* 011000011100 */
+	0x40, 0xc0, /* 010000001100 */
+	0x00, 0xc0, /* 000000001100 */
+	0x00, 0xc0, /* 000000001100 */
+	0x00, 0xc0, /* 000000001100 */
+	0x01, 0x80, /* 000000011000 */
+	0x03, 0x00, /* 000000110000 */
+	0x06, 0x00, /* 000001100000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x18, 0x00, /* 000110000000 */
+	0x30, 0x20, /* 001100000010 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 51 0x33 '3' */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x80, /* 000011111000 */
+	0x1f, 0xc0, /* 000111111100 */
+	0x20, 0xe0, /* 001000001110 */
+	0x40, 0x60, /* 010000000110 */
+	0x00, 0x60, /* 000000000110 */
+	0x00, 0xe0, /* 000000001110 */
+	0x07, 0xc0, /* 000001111100 */
+	0x0f, 0xc0, /* 000011111100 */
+	0x00, 0xe0, /* 000000001110 */
+	0x00, 0x60, /* 000000000110 */
+	0x00, 0x60, /* 000000000110 */
+	0x40, 0x60, /* 010000000110 */
+	0x60, 0x40, /* 011000000100 */
+	0x3f, 0x80, /* 001111111000 */
+	0x1f, 0x00, /* 000111110000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 52 0x34 '4' */
+	0x00, 0x00, /* 000000000000 */
+	0x01, 0x80, /* 000000011000 */
+	0x03, 0x80, /* 000000111000 */
+	0x03, 0x80, /* 000000111000 */
+	0x05, 0x80, /* 000001011000 */
+	0x05, 0x80, /* 000001011000 */
+	0x09, 0x80, /* 000010011000 */
+	0x09, 0x80, /* 000010011000 */
+	0x11, 0x80, /* 000100011000 */
+	0x11, 0x80, /* 000100011000 */
+	0x21, 0x80, /* 001000011000 */
+	0x3f, 0xe0, /* 001111111110 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x01, 0x80, /* 000000011000 */
+	0x01, 0x80, /* 000000011000 */
+	0x01, 0x80, /* 000000011000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 53 0x35 '5' */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0xc0, /* 000011111100 */
+	0x0f, 0xc0, /* 000011111100 */
+	0x10, 0x00, /* 000100000000 */
+	0x10, 0x00, /* 000100000000 */
+	0x20, 0x00, /* 001000000000 */
+	0x3f, 0x80, /* 001111111000 */
+	0x31, 0xc0, /* 001100011100 */
+	0x00, 0xe0, /* 000000001110 */
+	0x00, 0x60, /* 000000000110 */
+	0x00, 0x60, /* 000000000110 */
+	0x00, 0x60, /* 000000000110 */
+	0x40, 0x60, /* 010000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x30, 0xc0, /* 001100001100 */
+	0x1f, 0x80, /* 000111111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 54 0x36 '6' */
+	0x00, 0x00, /* 000000000000 */
+	0x07, 0x00, /* 000001110000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x18, 0x00, /* 000110000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x67, 0x80, /* 011001111000 */
+	0x6f, 0xc0, /* 011011111100 */
+	0x70, 0xe0, /* 011100001110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x70, 0x40, /* 011100000100 */
+	0x3f, 0x80, /* 001111111000 */
+	0x1f, 0x00, /* 000111110000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 55 0x37 '7' */
+	0x00, 0x00, /* 000000000000 */
+	0x1f, 0xe0, /* 000111111110 */
+	0x3f, 0xe0, /* 001111111110 */
+	0x60, 0x40, /* 011000000100 */
+	0x00, 0x40, /* 000000000100 */
+	0x00, 0xc0, /* 000000001100 */
+	0x00, 0x80, /* 000000001000 */
+	0x00, 0x80, /* 000000001000 */
+	0x01, 0x80, /* 000000011000 */
+	0x01, 0x00, /* 000000010000 */
+	0x01, 0x00, /* 000000010000 */
+	0x03, 0x00, /* 000000110000 */
+	0x02, 0x00, /* 000000100000 */
+	0x02, 0x00, /* 000000100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x04, 0x00, /* 000001000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 56 0x38 '8' */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x11, 0x80, /* 000100011000 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x18, 0x80, /* 000110001000 */
+	0x0d, 0x00, /* 000011010000 */
+	0x06, 0x00, /* 000001100000 */
+	0x0b, 0x00, /* 000010110000 */
+	0x11, 0x80, /* 000100011000 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x18, 0x80, /* 000110001000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 57 0x39 '9' */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x80, /* 000011111000 */
+	0x11, 0xc0, /* 000100011100 */
+	0x20, 0xe0, /* 001000001110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x70, 0xe0, /* 011100001110 */
+	0x3f, 0x60, /* 001111110110 */
+	0x1e, 0x60, /* 000111100110 */
+	0x00, 0x60, /* 000000000110 */
+	0x00, 0xc0, /* 000000001100 */
+	0x00, 0xc0, /* 000000001100 */
+	0x01, 0x80, /* 000000011000 */
+	0x07, 0x00, /* 000001110000 */
+	0x3c, 0x00, /* 001111000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 58 0x3a ':' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x1e, 0x00, /* 000111100000 */
+	0x1e, 0x00, /* 000111100000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x1e, 0x00, /* 000111100000 */
+	0x1e, 0x00, /* 000111100000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 59 0x3b ';' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x1e, 0x00, /* 000111100000 */
+	0x1e, 0x00, /* 000111100000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x1e, 0x00, /* 000111100000 */
+	0x1e, 0x00, /* 000111100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x18, 0x00, /* 000110000000 */
+	0x10, 0x00, /* 000100000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 60 0x3c '<' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x60, /* 000000000110 */
+	0x01, 0xc0, /* 000000011100 */
+	0x07, 0x00, /* 000001110000 */
+	0x1c, 0x00, /* 000111000000 */
+	0x70, 0x00, /* 011100000000 */
+	0x70, 0x00, /* 011100000000 */
+	0x1c, 0x00, /* 000111000000 */
+	0x07, 0x00, /* 000001110000 */
+	0x01, 0xc0, /* 000000011100 */
+	0x00, 0x60, /* 000000000110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 61 0x3d '=' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 62 0x3e '>' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x38, 0x00, /* 001110000000 */
+	0x0e, 0x00, /* 000011100000 */
+	0x03, 0x80, /* 000000111000 */
+	0x00, 0xe0, /* 000000001110 */
+	0x00, 0xe0, /* 000000001110 */
+	0x03, 0x80, /* 000000111000 */
+	0x0e, 0x00, /* 000011100000 */
+	0x38, 0x00, /* 001110000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 63 0x3f '?' */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x1f, 0x80, /* 000111111000 */
+	0x39, 0xc0, /* 001110011100 */
+	0x20, 0xc0, /* 001000001100 */
+	0x00, 0xc0, /* 000000001100 */
+	0x00, 0xc0, /* 000000001100 */
+	0x01, 0x80, /* 000000011000 */
+	0x03, 0x00, /* 000000110000 */
+	0x06, 0x00, /* 000001100000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 64 0x40 '@' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x80, /* 000011111000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x30, 0x60, /* 001100000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x67, 0x20, /* 011001110010 */
+	0x6f, 0xa0, /* 011011111010 */
+	0x6c, 0xa0, /* 011011001010 */
+	0x6c, 0xa0, /* 011011001010 */
+	0x67, 0xe0, /* 011001111110 */
+	0x60, 0x00, /* 011000000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x3f, 0xe0, /* 001111111110 */
+	0x0f, 0xe0, /* 000011111110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 65 0x41 'A' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x0b, 0x00, /* 000010110000 */
+	0x0b, 0x00, /* 000010110000 */
+	0x09, 0x00, /* 000010010000 */
+	0x11, 0x80, /* 000100011000 */
+	0x11, 0x80, /* 000100011000 */
+	0x10, 0x80, /* 000100001000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x20, 0xc0, /* 001000001100 */
+	0x20, 0x40, /* 001000000100 */
+	0x40, 0x60, /* 010000000110 */
+	0x40, 0x60, /* 010000000110 */
+	0xe0, 0xf0, /* 111000001111 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 66 0x42 'B' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xff, 0x00, /* 111111110000 */
+	0x60, 0x80, /* 011000001000 */
+	0x60, 0xc0, /* 011000001100 */
+	0x60, 0xc0, /* 011000001100 */
+	0x60, 0xc0, /* 011000001100 */
+	0x61, 0x80, /* 011000011000 */
+	0x7f, 0x80, /* 011111111000 */
+	0x60, 0xc0, /* 011000001100 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0xc0, /* 011000001100 */
+	0xff, 0x80, /* 111111111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 67 0x43 'C' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0xc0, /* 000011111100 */
+	0x10, 0x60, /* 000100000110 */
+	0x20, 0x20, /* 001000000010 */
+	0x20, 0x00, /* 001000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x20, 0x00, /* 001000000000 */
+	0x30, 0x20, /* 001100000010 */
+	0x18, 0x40, /* 000110000100 */
+	0x0f, 0x80, /* 000011111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 68 0x44 'D' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xff, 0x00, /* 111111110000 */
+	0x61, 0xc0, /* 011000011100 */
+	0x60, 0xc0, /* 011000001100 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x40, /* 011000000100 */
+	0x61, 0x80, /* 011000011000 */
+	0xfe, 0x00, /* 111111100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 69 0x45 'E' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x7f, 0xc0, /* 011111111100 */
+	0x30, 0x40, /* 001100000100 */
+	0x30, 0x40, /* 001100000100 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x80, /* 001100001000 */
+	0x3f, 0x80, /* 001111111000 */
+	0x30, 0x80, /* 001100001000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x20, /* 001100000010 */
+	0x30, 0x20, /* 001100000010 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 70 0x46 'F' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x7f, 0xc0, /* 011111111100 */
+	0x30, 0x40, /* 001100000100 */
+	0x30, 0x40, /* 001100000100 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x80, /* 001100001000 */
+	0x3f, 0x80, /* 001111111000 */
+	0x30, 0x80, /* 001100001000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x78, 0x00, /* 011110000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 71 0x47 'G' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0xc0, /* 000011111100 */
+	0x10, 0x60, /* 000100000110 */
+	0x20, 0x20, /* 001000000010 */
+	0x20, 0x00, /* 001000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x61, 0xf0, /* 011000011111 */
+	0x60, 0x60, /* 011000000110 */
+	0x20, 0x60, /* 001000000110 */
+	0x30, 0x60, /* 001100000110 */
+	0x18, 0x60, /* 000110000110 */
+	0x0f, 0x80, /* 000011111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 72 0x48 'H' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xf0, 0xf0, /* 111100001111 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0xf0, 0xf0, /* 111100001111 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 73 0x49 'I' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x1f, 0x80, /* 000111111000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x1f, 0x80, /* 000111111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 74 0x4a 'J' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x1f, 0x80, /* 000111111000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x04, 0x00, /* 000001000000 */
+	0x38, 0x00, /* 001110000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 75 0x4b 'K' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xf0, 0xe0, /* 111100001110 */
+	0x61, 0x80, /* 011000011000 */
+	0x63, 0x00, /* 011000110000 */
+	0x66, 0x00, /* 011001100000 */
+	0x6c, 0x00, /* 011011000000 */
+	0x78, 0x00, /* 011110000000 */
+	0x78, 0x00, /* 011110000000 */
+	0x7c, 0x00, /* 011111000000 */
+	0x6e, 0x00, /* 011011100000 */
+	0x67, 0x00, /* 011001110000 */
+	0x63, 0x80, /* 011000111000 */
+	0x61, 0xc0, /* 011000011100 */
+	0x60, 0xe0, /* 011000001110 */
+	0xf0, 0x70, /* 111100000111 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 76 0x4c 'L' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x78, 0x00, /* 011110000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x20, /* 001100000010 */
+	0x30, 0x20, /* 001100000010 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 77 0x4d 'M' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xe0, 0x70, /* 111000000111 */
+	0x60, 0xe0, /* 011000001110 */
+	0x70, 0xe0, /* 011100001110 */
+	0x70, 0xe0, /* 011100001110 */
+	0x70, 0xe0, /* 011100001110 */
+	0x59, 0x60, /* 010110010110 */
+	0x59, 0x60, /* 010110010110 */
+	0x59, 0x60, /* 010110010110 */
+	0x4d, 0x60, /* 010011010110 */
+	0x4e, 0x60, /* 010011100110 */
+	0x4e, 0x60, /* 010011100110 */
+	0x44, 0x60, /* 010001000110 */
+	0x44, 0x60, /* 010001000110 */
+	0xe4, 0xf0, /* 111001001111 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 78 0x4e 'N' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xc0, 0x70, /* 110000000111 */
+	0x60, 0x20, /* 011000000010 */
+	0x70, 0x20, /* 011100000010 */
+	0x78, 0x20, /* 011110000010 */
+	0x58, 0x20, /* 010110000010 */
+	0x4c, 0x20, /* 010011000010 */
+	0x46, 0x20, /* 010001100010 */
+	0x47, 0x20, /* 010001110010 */
+	0x43, 0x20, /* 010000110010 */
+	0x41, 0xa0, /* 010000011010 */
+	0x40, 0xe0, /* 010000001110 */
+	0x40, 0xe0, /* 010000001110 */
+	0x40, 0x60, /* 010000000110 */
+	0xe0, 0x30, /* 111000000011 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 79 0x4f 'O' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x11, 0xc0, /* 000100011100 */
+	0x20, 0xc0, /* 001000001100 */
+	0x20, 0x60, /* 001000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x20, 0x40, /* 001000000100 */
+	0x30, 0x40, /* 001100000100 */
+	0x18, 0x80, /* 000110001000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 80 0x50 'P' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x7f, 0x80, /* 011111111000 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0x60, /* 001100000110 */
+	0x30, 0x60, /* 001100000110 */
+	0x30, 0x60, /* 001100000110 */
+	0x30, 0xc0, /* 001100001100 */
+	0x37, 0x80, /* 001101111000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x78, 0x00, /* 011110000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 81 0x51 'Q' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x11, 0xc0, /* 000100011100 */
+	0x20, 0xc0, /* 001000001100 */
+	0x20, 0x60, /* 001000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x30, 0x40, /* 001100000100 */
+	0x38, 0x40, /* 001110000100 */
+	0x1f, 0x80, /* 000111111000 */
+	0x0e, 0x00, /* 000011100000 */
+	0x1f, 0x00, /* 000111110000 */
+	0x23, 0x90, /* 001000111001 */
+	0x01, 0xe0, /* 000000011110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 82 0x52 'R' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xff, 0x00, /* 111111110000 */
+	0x61, 0x80, /* 011000011000 */
+	0x60, 0xc0, /* 011000001100 */
+	0x60, 0xc0, /* 011000001100 */
+	0x60, 0xc0, /* 011000001100 */
+	0x60, 0x80, /* 011000001000 */
+	0x7f, 0x00, /* 011111110000 */
+	0x7c, 0x00, /* 011111000000 */
+	0x6e, 0x00, /* 011011100000 */
+	0x67, 0x00, /* 011001110000 */
+	0x63, 0x80, /* 011000111000 */
+	0x61, 0xc0, /* 011000011100 */
+	0x60, 0xe0, /* 011000001110 */
+	0xf0, 0x70, /* 111100000111 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 83 0x53 'S' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x1f, 0xe0, /* 000111111110 */
+	0x30, 0x60, /* 001100000110 */
+	0x60, 0x20, /* 011000000010 */
+	0x60, 0x20, /* 011000000010 */
+	0x70, 0x00, /* 011100000000 */
+	0x3c, 0x00, /* 001111000000 */
+	0x1e, 0x00, /* 000111100000 */
+	0x07, 0x80, /* 000001111000 */
+	0x01, 0xc0, /* 000000011100 */
+	0x00, 0xe0, /* 000000001110 */
+	0x40, 0x60, /* 010000000110 */
+	0x40, 0x60, /* 010000000110 */
+	0x60, 0xc0, /* 011000001100 */
+	0x7f, 0x80, /* 011111111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 84 0x54 'T' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x46, 0x20, /* 010001100010 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x1f, 0x80, /* 000111111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 85 0x55 'U' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xf0, 0x70, /* 111100000111 */
+	0x60, 0x20, /* 011000000010 */
+	0x60, 0x20, /* 011000000010 */
+	0x60, 0x20, /* 011000000010 */
+	0x60, 0x20, /* 011000000010 */
+	0x60, 0x20, /* 011000000010 */
+	0x60, 0x20, /* 011000000010 */
+	0x60, 0x20, /* 011000000010 */
+	0x60, 0x20, /* 011000000010 */
+	0x60, 0x20, /* 011000000010 */
+	0x60, 0x20, /* 011000000010 */
+	0x70, 0x40, /* 011100000100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x1f, 0x80, /* 000111111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 86 0x56 'V' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xe0, 0xe0, /* 111000001110 */
+	0x60, 0x40, /* 011000000100 */
+	0x30, 0x80, /* 001100001000 */
+	0x30, 0x80, /* 001100001000 */
+	0x30, 0x80, /* 001100001000 */
+	0x19, 0x00, /* 000110010000 */
+	0x19, 0x00, /* 000110010000 */
+	0x19, 0x00, /* 000110010000 */
+	0x0a, 0x00, /* 000010100000 */
+	0x0e, 0x00, /* 000011100000 */
+	0x0e, 0x00, /* 000011100000 */
+	0x04, 0x00, /* 000001000000 */
+	0x04, 0x00, /* 000001000000 */
+	0x04, 0x00, /* 000001000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 87 0x57 'W' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xfe, 0xf0, /* 111111101111 */
+	0x66, 0x20, /* 011001100010 */
+	0x66, 0x20, /* 011001100010 */
+	0x66, 0x20, /* 011001100010 */
+	0x76, 0x20, /* 011101100010 */
+	0x77, 0x40, /* 011101110100 */
+	0x33, 0x40, /* 001100110100 */
+	0x37, 0x40, /* 001101110100 */
+	0x3b, 0xc0, /* 001110111100 */
+	0x3b, 0x80, /* 001110111000 */
+	0x19, 0x80, /* 000110011000 */
+	0x19, 0x80, /* 000110011000 */
+	0x19, 0x80, /* 000110011000 */
+	0x19, 0x80, /* 000110011000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 88 0x58 'X' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xf0, 0x70, /* 111100000111 */
+	0x60, 0x20, /* 011000000010 */
+	0x30, 0x40, /* 001100000100 */
+	0x38, 0x80, /* 001110001000 */
+	0x18, 0x80, /* 000110001000 */
+	0x0d, 0x00, /* 000011010000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x0b, 0x00, /* 000010110000 */
+	0x11, 0x80, /* 000100011000 */
+	0x11, 0xc0, /* 000100011100 */
+	0x20, 0xc0, /* 001000001100 */
+	0x40, 0x60, /* 010000000110 */
+	0xe0, 0xf0, /* 111000001111 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 89 0x59 'Y' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xf0, 0x70, /* 111100000111 */
+	0x60, 0x20, /* 011000000010 */
+	0x30, 0x40, /* 001100000100 */
+	0x18, 0x80, /* 000110001000 */
+	0x18, 0x80, /* 000110001000 */
+	0x0d, 0x00, /* 000011010000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 90 0x5a 'Z' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xe0, /* 001111111110 */
+	0x20, 0xc0, /* 001000001100 */
+	0x00, 0xc0, /* 000000001100 */
+	0x01, 0x80, /* 000000011000 */
+	0x01, 0x80, /* 000000011000 */
+	0x03, 0x00, /* 000000110000 */
+	0x03, 0x00, /* 000000110000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x18, 0x00, /* 000110000000 */
+	0x18, 0x20, /* 000110000010 */
+	0x3f, 0xe0, /* 001111111110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 91 0x5b '[' */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x80, /* 000011111000 */
+	0x0f, 0x80, /* 000011111000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0f, 0x80, /* 000011111000 */
+	0x0f, 0x80, /* 000011111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 92 0x5c '\' */
+	0x00, 0x00, /* 000000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x18, 0x00, /* 000110000000 */
+	0x18, 0x00, /* 000110000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x03, 0x00, /* 000000110000 */
+	0x03, 0x00, /* 000000110000 */
+	0x01, 0x80, /* 000000011000 */
+	0x01, 0x80, /* 000000011000 */
+	0x00, 0xc0, /* 000000001100 */
+	0x00, 0xc0, /* 000000001100 */
+	0x00, 0x60, /* 000000000110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 93 0x5d ']' */
+	0x00, 0x00, /* 000000000000 */
+	0x1f, 0x00, /* 000111110000 */
+	0x1f, 0x00, /* 000111110000 */
+	0x03, 0x00, /* 000000110000 */
+	0x03, 0x00, /* 000000110000 */
+	0x03, 0x00, /* 000000110000 */
+	0x03, 0x00, /* 000000110000 */
+	0x03, 0x00, /* 000000110000 */
+	0x03, 0x00, /* 000000110000 */
+	0x03, 0x00, /* 000000110000 */
+	0x03, 0x00, /* 000000110000 */
+	0x03, 0x00, /* 000000110000 */
+	0x03, 0x00, /* 000000110000 */
+	0x03, 0x00, /* 000000110000 */
+	0x1f, 0x00, /* 000111110000 */
+	0x1f, 0x00, /* 000111110000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 94 0x5e '^' */
+	0x00, 0x00, /* 000000000000 */
+	0x04, 0x00, /* 000001000000 */
+	0x0e, 0x00, /* 000011100000 */
+	0x1b, 0x00, /* 000110110000 */
+	0x31, 0x80, /* 001100011000 */
+	0x60, 0xc0, /* 011000001100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 95 0x5f '_' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 96 0x60 '`' */
+	0x00, 0x00, /* 000000000000 */
+	0x01, 0x00, /* 000000010000 */
+	0x03, 0x00, /* 000000110000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x07, 0x80, /* 000001111000 */
+	0x07, 0x80, /* 000001111000 */
+	0x03, 0x00, /* 000000110000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 97 0x61 'a' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x80, /* 000011111000 */
+	0x18, 0xc0, /* 000110001100 */
+	0x10, 0xc0, /* 000100001100 */
+	0x03, 0xc0, /* 000000111100 */
+	0x1c, 0xc0, /* 000111001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x39, 0xc0, /* 001110011100 */
+	0x1e, 0xe0, /* 000111101110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 98 0x62 'b' */
+	0x00, 0x00, /* 000000000000 */
+	0x20, 0x00, /* 001000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0xe0, 0x00, /* 111000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x67, 0x80, /* 011001111000 */
+	0x6f, 0xc0, /* 011011111100 */
+	0x70, 0xe0, /* 011100001110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x70, 0x60, /* 011100000110 */
+	0x78, 0xc0, /* 011110001100 */
+	0x4f, 0x80, /* 010011111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 99 0x63 'c' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x1f, 0x80, /* 000111111000 */
+	0x31, 0xc0, /* 001100011100 */
+	0x20, 0xc0, /* 001000001100 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x70, 0x40, /* 011100000100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x1f, 0x80, /* 000111111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 100 0x64 'd' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x60, /* 000000000110 */
+	0x00, 0xe0, /* 000000001110 */
+	0x00, 0x60, /* 000000000110 */
+	0x00, 0x60, /* 000000000110 */
+	0x00, 0x60, /* 000000000110 */
+	0x0f, 0x60, /* 000011110110 */
+	0x31, 0xe0, /* 001100011110 */
+	0x20, 0xe0, /* 001000001110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x70, 0xe0, /* 011100001110 */
+	0x39, 0x60, /* 001110010110 */
+	0x1e, 0x70, /* 000111100111 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 101 0x65 'e' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x30, 0xc0, /* 001100001100 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x18, 0x60, /* 000110000110 */
+	0x0f, 0x80, /* 000011111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 102 0x66 'f' */
+	0x00, 0x00, /* 000000000000 */
+	0x03, 0x80, /* 000000111000 */
+	0x04, 0xc0, /* 000001001100 */
+	0x04, 0xc0, /* 000001001100 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x3f, 0x80, /* 001111111000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x1e, 0x00, /* 000111100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 103 0x67 'g' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x1f, 0x20, /* 000111110010 */
+	0x31, 0xe0, /* 001100011110 */
+	0x60, 0xc0, /* 011000001100 */
+	0x60, 0xc0, /* 011000001100 */
+	0x60, 0xc0, /* 011000001100 */
+	0x31, 0x80, /* 001100011000 */
+	0x3f, 0x00, /* 001111110000 */
+	0x60, 0x00, /* 011000000000 */
+	0x7f, 0xc0, /* 011111111100 */
+	0x3f, 0xe0, /* 001111111110 */
+	0x20, 0x60, /* 001000000110 */
+	0x40, 0x20, /* 010000000010 */
+	0x40, 0x20, /* 010000000010 */
+	0x7f, 0xc0, /* 011111111100 */
+	0x3f, 0x80, /* 001111111000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 104 0x68 'h' */
+	0x00, 0x00, /* 000000000000 */
+	0x10, 0x00, /* 000100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x70, 0x00, /* 011100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x37, 0x80, /* 001101111000 */
+	0x39, 0xc0, /* 001110011100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x79, 0xe0, /* 011110011110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 105 0x69 'i' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x1e, 0x00, /* 000111100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x1f, 0x80, /* 000111111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 106 0x6a 'j' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0xc0, /* 000000001100 */
+	0x00, 0xc0, /* 000000001100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x03, 0xc0, /* 000000111100 */
+	0x00, 0xc0, /* 000000001100 */
+	0x00, 0xc0, /* 000000001100 */
+	0x00, 0xc0, /* 000000001100 */
+	0x00, 0xc0, /* 000000001100 */
+	0x00, 0xc0, /* 000000001100 */
+	0x00, 0xc0, /* 000000001100 */
+	0x00, 0xc0, /* 000000001100 */
+	0x00, 0xc0, /* 000000001100 */
+	0x00, 0xc0, /* 000000001100 */
+	0x20, 0xc0, /* 001000001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x38, 0x80, /* 001110001000 */
+	0x1f, 0x00, /* 000111110000 */
+	0x0e, 0x00, /* 000011100000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 107 0x6b 'k' */
+	0x00, 0x00, /* 000000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0xe0, 0x00, /* 111000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x61, 0xc0, /* 011000011100 */
+	0x63, 0x00, /* 011000110000 */
+	0x66, 0x00, /* 011001100000 */
+	0x7c, 0x00, /* 011111000000 */
+	0x78, 0x00, /* 011110000000 */
+	0x7c, 0x00, /* 011111000000 */
+	0x6e, 0x00, /* 011011100000 */
+	0x67, 0x00, /* 011001110000 */
+	0x63, 0x80, /* 011000111000 */
+	0xf1, 0xe0, /* 111100011110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 108 0x6c 'l' */
+	0x00, 0x00, /* 000000000000 */
+	0x1e, 0x00, /* 000111100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x1f, 0x80, /* 000111111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 109 0x6d 'm' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xdd, 0xc0, /* 110111011100 */
+	0x6e, 0xe0, /* 011011101110 */
+	0x66, 0x60, /* 011001100110 */
+	0x66, 0x60, /* 011001100110 */
+	0x66, 0x60, /* 011001100110 */
+	0x66, 0x60, /* 011001100110 */
+	0x66, 0x60, /* 011001100110 */
+	0x66, 0x60, /* 011001100110 */
+	0x66, 0x60, /* 011001100110 */
+	0xef, 0x70, /* 111011110111 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 110 0x6e 'n' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x27, 0x80, /* 001001111000 */
+	0x79, 0xc0, /* 011110011100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x79, 0xe0, /* 011110011110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 111 0x6f 'o' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x80, /* 000011111000 */
+	0x11, 0xc0, /* 000100011100 */
+	0x20, 0xe0, /* 001000001110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x70, 0x40, /* 011100000100 */
+	0x38, 0x80, /* 001110001000 */
+	0x1f, 0x00, /* 000111110000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 112 0x70 'p' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xef, 0x80, /* 111011111000 */
+	0x71, 0xc0, /* 011100011100 */
+	0x60, 0xe0, /* 011000001110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x40, /* 011000000100 */
+	0x70, 0x80, /* 011100001000 */
+	0x7f, 0x00, /* 011111110000 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0xf0, 0x00, /* 111100000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 113 0x71 'q' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x20, /* 000011110010 */
+	0x11, 0xe0, /* 000100011110 */
+	0x20, 0xe0, /* 001000001110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x70, 0x60, /* 011100000110 */
+	0x38, 0xe0, /* 001110001110 */
+	0x1f, 0xe0, /* 000111111110 */
+	0x00, 0x60, /* 000000000110 */
+	0x00, 0x60, /* 000000000110 */
+	0x00, 0x60, /* 000000000110 */
+	0x00, 0x60, /* 000000000110 */
+	0x00, 0xf0, /* 000000001111 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 114 0x72 'r' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x73, 0x80, /* 011100111000 */
+	0x34, 0xc0, /* 001101001100 */
+	0x38, 0xc0, /* 001110001100 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x78, 0x00, /* 011110000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 115 0x73 's' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x1f, 0xc0, /* 000111111100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0x40, /* 001100000100 */
+	0x38, 0x00, /* 001110000000 */
+	0x1e, 0x00, /* 000111100000 */
+	0x07, 0x80, /* 000001111000 */
+	0x01, 0xc0, /* 000000011100 */
+	0x20, 0xc0, /* 001000001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x3f, 0x80, /* 001111111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 116 0x74 't' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x04, 0x00, /* 000001000000 */
+	0x04, 0x00, /* 000001000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x7f, 0xc0, /* 011111111100 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0c, 0x20, /* 000011000010 */
+	0x0e, 0x40, /* 000011100100 */
+	0x07, 0x80, /* 000001111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 117 0x75 'u' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x79, 0xe0, /* 011110011110 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x39, 0xc0, /* 001110011100 */
+	0x1e, 0x60, /* 000111100110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 118 0x76 'v' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xf0, 0x70, /* 111100000111 */
+	0x60, 0x20, /* 011000000010 */
+	0x30, 0x40, /* 001100000100 */
+	0x30, 0x40, /* 001100000100 */
+	0x18, 0x80, /* 000110001000 */
+	0x18, 0x80, /* 000110001000 */
+	0x0d, 0x00, /* 000011010000 */
+	0x0d, 0x00, /* 000011010000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 119 0x77 'w' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xff, 0x70, /* 111111110111 */
+	0x66, 0x20, /* 011001100010 */
+	0x66, 0x20, /* 011001100010 */
+	0x66, 0x20, /* 011001100010 */
+	0x37, 0x40, /* 001101110100 */
+	0x3b, 0x40, /* 001110110100 */
+	0x3b, 0x40, /* 001110110100 */
+	0x19, 0x80, /* 000110011000 */
+	0x19, 0x80, /* 000110011000 */
+	0x19, 0x80, /* 000110011000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 120 0x78 'x' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xf8, 0xf0, /* 111110001111 */
+	0x70, 0x40, /* 011100000100 */
+	0x38, 0x80, /* 001110001000 */
+	0x1d, 0x00, /* 000111010000 */
+	0x0e, 0x00, /* 000011100000 */
+	0x07, 0x00, /* 000001110000 */
+	0x0b, 0x80, /* 000010111000 */
+	0x11, 0xc0, /* 000100011100 */
+	0x20, 0xe0, /* 001000001110 */
+	0xf1, 0xf0, /* 111100011111 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 121 0x79 'y' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xf0, 0xf0, /* 111100001111 */
+	0x60, 0x20, /* 011000000010 */
+	0x30, 0x40, /* 001100000100 */
+	0x30, 0x40, /* 001100000100 */
+	0x18, 0x80, /* 000110001000 */
+	0x18, 0x80, /* 000110001000 */
+	0x0d, 0x00, /* 000011010000 */
+	0x0d, 0x00, /* 000011010000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x04, 0x00, /* 000001000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x08, 0x00, /* 000010000000 */
+	0x78, 0x00, /* 011110000000 */
+	0x70, 0x00, /* 011100000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 122 0x7a 'z' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x60, 0xe0, /* 011000001110 */
+	0x41, 0xc0, /* 010000011100 */
+	0x03, 0x80, /* 000000111000 */
+	0x07, 0x00, /* 000001110000 */
+	0x0e, 0x00, /* 000011100000 */
+	0x1c, 0x00, /* 000111000000 */
+	0x38, 0x20, /* 001110000010 */
+	0x70, 0x60, /* 011100000110 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 123 0x7b '{' */
+	0x00, 0x00, /* 000000000000 */
+	0x03, 0x80, /* 000000111000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x38, 0x00, /* 001110000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x03, 0x80, /* 000000111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 124 0x7c '|' */
+	0x00, 0x00, /* 000000000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 125 0x7d '}' */
+	0x00, 0x00, /* 000000000000 */
+	0x1c, 0x00, /* 000111000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x03, 0x00, /* 000000110000 */
+	0x01, 0xc0, /* 000000011100 */
+	0x03, 0x00, /* 000000110000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x1c, 0x00, /* 000111000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 126 0x7e '~' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x1c, 0x20, /* 000111000010 */
+	0x3e, 0x60, /* 001111100110 */
+	0x67, 0xc0, /* 011001111100 */
+	0x43, 0x80, /* 010000111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 127 0x7f '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 128 0x80 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0xc0, /* 000011111100 */
+	0x10, 0x60, /* 000100000110 */
+	0x20, 0x20, /* 001000000010 */
+	0x20, 0x00, /* 001000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x20, 0x00, /* 001000000000 */
+	0x30, 0x20, /* 001100000010 */
+	0x18, 0x40, /* 000110000100 */
+	0x0f, 0x80, /* 000011111000 */
+	0x06, 0x00, /* 000001100000 */
+	0x03, 0x00, /* 000000110000 */
+	0x01, 0x80, /* 000000011000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 129 0x81 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x19, 0x80, /* 000110011000 */
+	0x19, 0x80, /* 000110011000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x79, 0xe0, /* 011110011110 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x39, 0xc0, /* 001110011100 */
+	0x1e, 0x60, /* 000111100110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 130 0x82 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x01, 0x80, /* 000000011000 */
+	0x03, 0x00, /* 000000110000 */
+	0x06, 0x00, /* 000001100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x30, 0xc0, /* 001100001100 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x18, 0x60, /* 000110000110 */
+	0x0f, 0x80, /* 000011111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 131 0x83 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x02, 0x00, /* 000000100000 */
+	0x07, 0x00, /* 000001110000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x18, 0xc0, /* 000110001100 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x80, /* 000011111000 */
+	0x18, 0xc0, /* 000110001100 */
+	0x10, 0xc0, /* 000100001100 */
+	0x03, 0xc0, /* 000000111100 */
+	0x1c, 0xc0, /* 000111001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x39, 0xc0, /* 001110011100 */
+	0x1e, 0xe0, /* 000111101110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 132 0x84 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x19, 0x80, /* 000110011000 */
+	0x19, 0x80, /* 000110011000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x80, /* 000011111000 */
+	0x18, 0xc0, /* 000110001100 */
+	0x10, 0xc0, /* 000100001100 */
+	0x03, 0xc0, /* 000000111100 */
+	0x1c, 0xc0, /* 000111001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x39, 0xc0, /* 001110011100 */
+	0x1e, 0xe0, /* 000111101110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 133 0x85 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x03, 0x00, /* 000000110000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x80, /* 000011111000 */
+	0x18, 0xc0, /* 000110001100 */
+	0x10, 0xc0, /* 000100001100 */
+	0x03, 0xc0, /* 000000111100 */
+	0x1c, 0xc0, /* 000111001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x39, 0xc0, /* 001110011100 */
+	0x1e, 0xe0, /* 000111101110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 134 0x86 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x07, 0x00, /* 000001110000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x07, 0x00, /* 000001110000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x80, /* 000011111000 */
+	0x18, 0xc0, /* 000110001100 */
+	0x10, 0xc0, /* 000100001100 */
+	0x03, 0xc0, /* 000000111100 */
+	0x1c, 0xc0, /* 000111001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x39, 0xc0, /* 001110011100 */
+	0x1e, 0xe0, /* 000111101110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 135 0x87 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x1f, 0x80, /* 000111111000 */
+	0x31, 0xc0, /* 001100011100 */
+	0x20, 0xc0, /* 001000001100 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x70, 0x40, /* 011100000100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x1f, 0x80, /* 000111111000 */
+	0x06, 0x00, /* 000001100000 */
+	0x03, 0x00, /* 000000110000 */
+	0x01, 0x80, /* 000000011000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 136 0x88 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x02, 0x00, /* 000000100000 */
+	0x07, 0x00, /* 000001110000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x18, 0xc0, /* 000110001100 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x30, 0xc0, /* 001100001100 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x18, 0x60, /* 000110000110 */
+	0x0f, 0x80, /* 000011111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 137 0x89 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x19, 0x80, /* 000110011000 */
+	0x19, 0x80, /* 000110011000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x30, 0xc0, /* 001100001100 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x18, 0x60, /* 000110000110 */
+	0x0f, 0x80, /* 000011111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 138 0x8a '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x03, 0x00, /* 000000110000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x30, 0xc0, /* 001100001100 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x60, 0x00, /* 011000000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x18, 0x60, /* 000110000110 */
+	0x0f, 0x80, /* 000011111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 139 0x8b '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x19, 0x80, /* 000110011000 */
+	0x19, 0x80, /* 000110011000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x1e, 0x00, /* 000111100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x1f, 0x80, /* 000111111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 140 0x8c '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x04, 0x00, /* 000001000000 */
+	0x0e, 0x00, /* 000011100000 */
+	0x1b, 0x00, /* 000110110000 */
+	0x31, 0x80, /* 001100011000 */
+	0x00, 0x00, /* 000000000000 */
+	0x1e, 0x00, /* 000111100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x1f, 0x80, /* 000111111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 141 0x8d '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x18, 0x00, /* 000110000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x1e, 0x00, /* 000111100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x1f, 0x80, /* 000111111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 142 0x8e '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x19, 0x80, /* 000110011000 */
+	0x19, 0x80, /* 000110011000 */
+	0x00, 0x00, /* 000000000000 */
+	0x04, 0x00, /* 000001000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x0b, 0x00, /* 000010110000 */
+	0x0b, 0x00, /* 000010110000 */
+	0x19, 0x80, /* 000110011000 */
+	0x11, 0x80, /* 000100011000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x20, 0xc0, /* 001000001100 */
+	0x60, 0x60, /* 011000000110 */
+	0x40, 0x60, /* 010000000110 */
+	0xe0, 0xf0, /* 111000001111 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 143 0x8f '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x19, 0x80, /* 000110011000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x04, 0x00, /* 000001000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x0b, 0x00, /* 000010110000 */
+	0x0b, 0x00, /* 000010110000 */
+	0x19, 0x80, /* 000110011000 */
+	0x11, 0x80, /* 000100011000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x20, 0xc0, /* 001000001100 */
+	0x60, 0x60, /* 011000000110 */
+	0x40, 0x60, /* 010000000110 */
+	0xe0, 0xf0, /* 111000001111 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 144 0x90 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x03, 0x00, /* 000000110000 */
+	0x06, 0x00, /* 000001100000 */
+	0x08, 0x00, /* 000010000000 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x30, 0x20, /* 001100000010 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x80, /* 001100001000 */
+	0x3f, 0x80, /* 001111111000 */
+	0x30, 0x80, /* 001100001000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x20, /* 001100000010 */
+	0x30, 0x20, /* 001100000010 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 145 0x91 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3d, 0xe0, /* 001111011110 */
+	0x66, 0x30, /* 011001100011 */
+	0x46, 0x30, /* 010001100011 */
+	0x06, 0x30, /* 000001100011 */
+	0x3f, 0xf0, /* 001111111111 */
+	0x66, 0x00, /* 011001100000 */
+	0xc6, 0x00, /* 110001100000 */
+	0xc6, 0x00, /* 110001100000 */
+	0xe7, 0x30, /* 111001110011 */
+	0x7d, 0xe0, /* 011111011110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 146 0x92 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x03, 0xf0, /* 000000111111 */
+	0x07, 0x10, /* 000001110001 */
+	0x07, 0x10, /* 000001110001 */
+	0x0b, 0x00, /* 000010110000 */
+	0x0b, 0x00, /* 000010110000 */
+	0x0b, 0x20, /* 000010110010 */
+	0x13, 0xe0, /* 000100111110 */
+	0x13, 0x20, /* 000100110010 */
+	0x3f, 0x00, /* 001111110000 */
+	0x23, 0x00, /* 001000110000 */
+	0x23, 0x00, /* 001000110000 */
+	0x43, 0x10, /* 010000110001 */
+	0x43, 0x10, /* 010000110001 */
+	0xe7, 0xf0, /* 111001111111 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 147 0x93 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x02, 0x00, /* 000000100000 */
+	0x07, 0x00, /* 000001110000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x18, 0xc0, /* 000110001100 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x80, /* 000011111000 */
+	0x11, 0xc0, /* 000100011100 */
+	0x20, 0xe0, /* 001000001110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x70, 0x40, /* 011100000100 */
+	0x38, 0x80, /* 001110001000 */
+	0x1f, 0x00, /* 000111110000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 148 0x94 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x19, 0x80, /* 000110011000 */
+	0x19, 0x80, /* 000110011000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x80, /* 000011111000 */
+	0x11, 0xc0, /* 000100011100 */
+	0x20, 0xe0, /* 001000001110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x70, 0x40, /* 011100000100 */
+	0x38, 0x80, /* 001110001000 */
+	0x1f, 0x00, /* 000111110000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 149 0x95 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x03, 0x00, /* 000000110000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x80, /* 000011111000 */
+	0x11, 0xc0, /* 000100011100 */
+	0x20, 0xe0, /* 001000001110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x70, 0x40, /* 011100000100 */
+	0x38, 0x80, /* 001110001000 */
+	0x1f, 0x00, /* 000111110000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 150 0x96 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x02, 0x00, /* 000000100000 */
+	0x07, 0x00, /* 000001110000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x18, 0xc0, /* 000110001100 */
+	0x00, 0x00, /* 000000000000 */
+	0x79, 0xe0, /* 011110011110 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x39, 0xc0, /* 001110011100 */
+	0x1e, 0x60, /* 000111100110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 151 0x97 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x18, 0x00, /* 000110000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x79, 0xe0, /* 011110011110 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x39, 0xc0, /* 001110011100 */
+	0x1e, 0x60, /* 000111100110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 152 0x98 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x19, 0x80, /* 000110011000 */
+	0x19, 0x80, /* 000110011000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xf0, 0xf0, /* 111100001111 */
+	0x60, 0x20, /* 011000000010 */
+	0x30, 0x40, /* 001100000100 */
+	0x30, 0x40, /* 001100000100 */
+	0x18, 0x80, /* 000110001000 */
+	0x18, 0x80, /* 000110001000 */
+	0x0d, 0x00, /* 000011010000 */
+	0x0d, 0x00, /* 000011010000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x04, 0x00, /* 000001000000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x08, 0x00, /* 000010000000 */
+	0x78, 0x00, /* 011110000000 */
+	0x70, 0x00, /* 011100000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 153 0x99 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x19, 0x80, /* 000110011000 */
+	0x19, 0x80, /* 000110011000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x80, /* 000011111000 */
+	0x11, 0xc0, /* 000100011100 */
+	0x20, 0xc0, /* 001000001100 */
+	0x20, 0x60, /* 001000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x20, 0x40, /* 001000000100 */
+	0x30, 0x40, /* 001100000100 */
+	0x18, 0x80, /* 000110001000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 154 0x9a '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x19, 0x80, /* 000110011000 */
+	0x19, 0x80, /* 000110011000 */
+	0xe0, 0x30, /* 111000000011 */
+	0x60, 0x20, /* 011000000010 */
+	0x60, 0x20, /* 011000000010 */
+	0x60, 0x20, /* 011000000010 */
+	0x60, 0x20, /* 011000000010 */
+	0x60, 0x20, /* 011000000010 */
+	0x60, 0x20, /* 011000000010 */
+	0x60, 0x20, /* 011000000010 */
+	0x60, 0x20, /* 011000000010 */
+	0x60, 0x20, /* 011000000010 */
+	0x70, 0x40, /* 011100000100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x1f, 0x80, /* 000111111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 155 0x9b '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x1f, 0x80, /* 000111111000 */
+	0x36, 0xc0, /* 001101101100 */
+	0x26, 0xc0, /* 001001101100 */
+	0x66, 0x00, /* 011001100000 */
+	0x66, 0x00, /* 011001100000 */
+	0x66, 0x00, /* 011001100000 */
+	0x66, 0x00, /* 011001100000 */
+	0x76, 0x40, /* 011101100100 */
+	0x36, 0xc0, /* 001101101100 */
+	0x1f, 0x80, /* 000111111000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 156 0x9c '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x80, /* 000011111000 */
+	0x1c, 0xc0, /* 000111001100 */
+	0x18, 0xc0, /* 000110001100 */
+	0x18, 0x00, /* 000110000000 */
+	0x18, 0x00, /* 000110000000 */
+	0x18, 0x00, /* 000110000000 */
+	0x7e, 0x00, /* 011111100000 */
+	0x7e, 0x00, /* 011111100000 */
+	0x18, 0x00, /* 000110000000 */
+	0x18, 0x00, /* 000110000000 */
+	0x18, 0x00, /* 000110000000 */
+	0x18, 0x00, /* 000110000000 */
+	0x3e, 0x20, /* 001111100010 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x61, 0xc0, /* 011000011100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 157 0x9d '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x30, 0xc0, /* 001100001100 */
+	0x19, 0x80, /* 000110011000 */
+	0x19, 0x80, /* 000110011000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x06, 0x00, /* 000001100000 */
+	0x1f, 0x80, /* 000111111000 */
+	0x06, 0x00, /* 000001100000 */
+	0x1f, 0x80, /* 000111111000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 158 0x9e '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 159 0x9f '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 160 0xa0 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x01, 0x80, /* 000000011000 */
+	0x03, 0x00, /* 000000110000 */
+	0x06, 0x00, /* 000001100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x80, /* 000011111000 */
+	0x18, 0xc0, /* 000110001100 */
+	0x10, 0xc0, /* 000100001100 */
+	0x03, 0xc0, /* 000000111100 */
+	0x1c, 0xc0, /* 000111001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x39, 0xc0, /* 001110011100 */
+	0x1e, 0xe0, /* 000111101110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 161 0xa1 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x01, 0x80, /* 000000011000 */
+	0x03, 0x00, /* 000000110000 */
+	0x06, 0x00, /* 000001100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x1e, 0x00, /* 000111100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x1f, 0x80, /* 000111111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 162 0xa2 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x01, 0x80, /* 000000011000 */
+	0x03, 0x00, /* 000000110000 */
+	0x06, 0x00, /* 000001100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x80, /* 000011111000 */
+	0x11, 0xc0, /* 000100011100 */
+	0x20, 0xe0, /* 001000001110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x60, 0x60, /* 011000000110 */
+	0x70, 0x40, /* 011100000100 */
+	0x38, 0x80, /* 001110001000 */
+	0x1f, 0x00, /* 000111110000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 163 0xa3 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x01, 0x80, /* 000000011000 */
+	0x03, 0x00, /* 000000110000 */
+	0x06, 0x00, /* 000001100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x79, 0xe0, /* 011110011110 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x39, 0xc0, /* 001110011100 */
+	0x1e, 0x60, /* 000111100110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 164 0xa4 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x1c, 0x40, /* 000111000100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x23, 0x80, /* 001000111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x27, 0x80, /* 001001111000 */
+	0x79, 0xc0, /* 011110011100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x79, 0xe0, /* 011110011110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 165 0xa5 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x1c, 0x40, /* 000111000100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x23, 0x80, /* 001000111000 */
+	0xc0, 0x70, /* 110000000111 */
+	0x60, 0x20, /* 011000000010 */
+	0x70, 0x20, /* 011100000010 */
+	0x78, 0x20, /* 011110000010 */
+	0x5c, 0x20, /* 010111000010 */
+	0x4e, 0x20, /* 010011100010 */
+	0x47, 0x20, /* 010001110010 */
+	0x43, 0xa0, /* 010000111010 */
+	0x41, 0xe0, /* 010000011110 */
+	0x40, 0xe0, /* 010000001110 */
+	0x40, 0x60, /* 010000000110 */
+	0xe0, 0x30, /* 111000000011 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 166 0xa6 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x1f, 0x00, /* 000111110000 */
+	0x31, 0x80, /* 001100011000 */
+	0x01, 0x80, /* 000000011000 */
+	0x07, 0x80, /* 000001111000 */
+	0x19, 0x80, /* 000110011000 */
+	0x31, 0x80, /* 001100011000 */
+	0x31, 0x80, /* 001100011000 */
+	0x33, 0x80, /* 001100111000 */
+	0x1d, 0xc0, /* 000111011100 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 167 0xa7 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x07, 0x00, /* 000001110000 */
+	0x19, 0x80, /* 000110011000 */
+	0x10, 0xc0, /* 000100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0x80, /* 001100001000 */
+	0x19, 0x80, /* 000110011000 */
+	0x0e, 0x00, /* 000011100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 168 0xa8 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x03, 0x00, /* 000000110000 */
+	0x03, 0x00, /* 000000110000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x03, 0x00, /* 000000110000 */
+	0x03, 0x00, /* 000000110000 */
+	0x06, 0x00, /* 000001100000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x18, 0x00, /* 000110000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x40, /* 001100000100 */
+	0x39, 0xc0, /* 001110011100 */
+	0x1f, 0x80, /* 000111111000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 169 0xa9 '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 170 0xaa '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0xc0, /* 000000001100 */
+	0x00, 0xc0, /* 000000001100 */
+	0x00, 0xc0, /* 000000001100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 171 0xab '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x10, 0x00, /* 000100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x10, 0x00, /* 000100000000 */
+	0x10, 0x40, /* 000100000100 */
+	0x10, 0x80, /* 000100001000 */
+	0x11, 0x00, /* 000100010000 */
+	0x3a, 0x00, /* 001110100000 */
+	0x05, 0xc0, /* 000001011100 */
+	0x0a, 0x20, /* 000010100010 */
+	0x10, 0x20, /* 000100000010 */
+	0x20, 0xc0, /* 001000001100 */
+	0x41, 0x00, /* 010000010000 */
+	0x02, 0x00, /* 000000100000 */
+	0x03, 0xe0, /* 000000111110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 172 0xac '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x10, 0x00, /* 000100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x10, 0x00, /* 000100000000 */
+	0x10, 0x40, /* 000100000100 */
+	0x10, 0x80, /* 000100001000 */
+	0x11, 0x00, /* 000100010000 */
+	0x3a, 0x40, /* 001110100100 */
+	0x04, 0xc0, /* 000001001100 */
+	0x09, 0x40, /* 000010010100 */
+	0x12, 0x40, /* 000100100100 */
+	0x24, 0x40, /* 001001000100 */
+	0x47, 0xe0, /* 010001111110 */
+	0x00, 0x40, /* 000000000100 */
+	0x00, 0x40, /* 000000000100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 173 0xad '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 174 0xae '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x06, 0x60, /* 000001100110 */
+	0x0c, 0xc0, /* 000011001100 */
+	0x19, 0x80, /* 000110011000 */
+	0x33, 0x00, /* 001100110000 */
+	0x66, 0x00, /* 011001100000 */
+	0x33, 0x00, /* 001100110000 */
+	0x19, 0x80, /* 000110011000 */
+	0x0c, 0xc0, /* 000011001100 */
+	0x06, 0x60, /* 000001100110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 175 0xaf '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x66, 0x00, /* 011001100000 */
+	0x33, 0x00, /* 001100110000 */
+	0x19, 0x80, /* 000110011000 */
+	0x0c, 0xc0, /* 000011001100 */
+	0x06, 0x60, /* 000001100110 */
+	0x0c, 0xc0, /* 000011001100 */
+	0x19, 0x80, /* 000110011000 */
+	0x33, 0x00, /* 001100110000 */
+	0x66, 0x00, /* 011001100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 176 0xb0 '.' */
+	0x0c, 0x30, /* 000011000011 */
+	0x08, 0x20, /* 000010000010 */
+	0x61, 0x80, /* 011000011000 */
+	0x20, 0x80, /* 001000001000 */
+	0x0c, 0x30, /* 000011000011 */
+	0x08, 0x20, /* 000010000010 */
+	0x61, 0x80, /* 011000011000 */
+	0x20, 0x80, /* 001000001000 */
+	0x0c, 0x30, /* 000011000011 */
+	0x08, 0x20, /* 000010000010 */
+	0x61, 0x80, /* 011000011000 */
+	0x20, 0x80, /* 001000001000 */
+	0x0c, 0x30, /* 000011000011 */
+	0x08, 0x20, /* 000010000010 */
+	0x61, 0x80, /* 011000011000 */
+	0x20, 0x80, /* 001000001000 */
+	0x0c, 0x30, /* 000011000011 */
+	0x08, 0x20, /* 000010000010 */
+	0x61, 0x80, /* 011000011000 */
+	0x20, 0x80, /* 001000001000 */
+	0x0c, 0x30, /* 000011000011 */
+	0x08, 0x20, /* 000010000010 */
+
+	/* 177 0xb1 '.' */
+	0x77, 0x70, /* 011101110111 */
+	0x22, 0x20, /* 001000100010 */
+	0x88, 0x80, /* 100010001000 */
+	0xdd, 0xd0, /* 110111011101 */
+	0x88, 0x80, /* 100010001000 */
+	0x22, 0x20, /* 001000100010 */
+	0x77, 0x70, /* 011101110111 */
+	0x22, 0x20, /* 001000100010 */
+	0x88, 0x80, /* 100010001000 */
+	0xdd, 0xd0, /* 110111011101 */
+	0x88, 0x80, /* 100010001000 */
+	0x22, 0x20, /* 001000100010 */
+	0x77, 0x70, /* 011101110111 */
+	0x22, 0x20, /* 001000100010 */
+	0x88, 0x80, /* 100010001000 */
+	0xdd, 0xd0, /* 110111011101 */
+	0x88, 0x80, /* 100010001000 */
+	0x22, 0x20, /* 001000100010 */
+	0x77, 0x70, /* 011101110111 */
+	0x22, 0x20, /* 001000100010 */
+	0x88, 0x80, /* 100010001000 */
+	0xdd, 0xd0, /* 110111011101 */
+
+	/* 178 0xb2 '.' */
+	0xf3, 0xc0, /* 111100111100 */
+	0xf7, 0xd0, /* 111101111101 */
+	0x9e, 0x70, /* 100111100111 */
+	0xdf, 0x70, /* 110111110111 */
+	0xf3, 0xc0, /* 111100111100 */
+	0xf7, 0xd0, /* 111101111101 */
+	0x9e, 0x70, /* 100111100111 */
+	0xdf, 0x70, /* 110111110111 */
+	0xf3, 0xc0, /* 111100111100 */
+	0xf7, 0xd0, /* 111101111101 */
+	0x9e, 0x70, /* 100111100111 */
+	0xdf, 0x70, /* 110111110111 */
+	0xf3, 0xc0, /* 111100111100 */
+	0xf7, 0xd0, /* 111101111101 */
+	0x9e, 0x70, /* 100111100111 */
+	0xdf, 0x70, /* 110111110111 */
+	0xf3, 0xc0, /* 111100111100 */
+	0xf7, 0xd0, /* 111101111101 */
+	0x9e, 0x70, /* 100111100111 */
+	0xdf, 0x70, /* 110111110111 */
+	0xf3, 0xc0, /* 111100111100 */
+	0xf7, 0xd0, /* 111101111101 */
+
+	/* 179 0xb3 '.' */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+
+	/* 180 0xb4 '.' */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0xfe, 0x00, /* 111111100000 */
+	0xfe, 0x00, /* 111111100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+
+	/* 181 0xb5 '.' */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0xfe, 0x00, /* 111111100000 */
+	0xfe, 0x00, /* 111111100000 */
+	0x06, 0x00, /* 000001100000 */
+	0xfe, 0x00, /* 111111100000 */
+	0xfe, 0x00, /* 111111100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+
+	/* 182 0xb6 '.' */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0xfd, 0x80, /* 111111011000 */
+	0xfd, 0x80, /* 111111011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+
+	/* 183 0xb7 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xff, 0x80, /* 111111111000 */
+	0xff, 0x80, /* 111111111000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+
+	/* 184 0xb8 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xfe, 0x00, /* 111111100000 */
+	0xfe, 0x00, /* 111111100000 */
+	0x06, 0x00, /* 000001100000 */
+	0xfe, 0x00, /* 111111100000 */
+	0xfe, 0x00, /* 111111100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+
+	/* 185 0xb9 '.' */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0xfd, 0x80, /* 111111011000 */
+	0xfd, 0x80, /* 111111011000 */
+	0x01, 0x80, /* 000000011000 */
+	0xfd, 0x80, /* 111111011000 */
+	0xfd, 0x80, /* 111111011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+
+	/* 186 0xba '.' */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+
+	/* 187 0xbb '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xff, 0x80, /* 111111111000 */
+	0xff, 0x80, /* 111111111000 */
+	0x01, 0x80, /* 000000011000 */
+	0xfd, 0x80, /* 111111011000 */
+	0xfd, 0x80, /* 111111011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+
+	/* 188 0xbc '.' */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0xfd, 0x80, /* 111111011000 */
+	0xfd, 0x80, /* 111111011000 */
+	0x01, 0x80, /* 000000011000 */
+	0xff, 0x80, /* 111111111000 */
+	0xff, 0x80, /* 111111111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 189 0xbd '.' */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0xff, 0x80, /* 111111111000 */
+	0xff, 0x80, /* 111111111000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 190 0xbe '.' */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0xfe, 0x00, /* 111111100000 */
+	0xfe, 0x00, /* 111111100000 */
+	0x06, 0x00, /* 000001100000 */
+	0xfe, 0x00, /* 111111100000 */
+	0xfe, 0x00, /* 111111100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 191 0xbf '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xfe, 0x00, /* 111111100000 */
+	0xfe, 0x00, /* 111111100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+
+	/* 192 0xc0 '.' */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x07, 0xf0, /* 000001111111 */
+	0x07, 0xf0, /* 000001111111 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 193 0xc1 '.' */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 194 0xc2 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+
+	/* 195 0xc3 '.' */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x07, 0xf0, /* 000001111111 */
+	0x07, 0xf0, /* 000001111111 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+
+	/* 196 0xc4 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 197 0xc5 '.' */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+
+	/* 198 0xc6 '.' */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x07, 0xf0, /* 000001111111 */
+	0x07, 0xf0, /* 000001111111 */
+	0x06, 0x00, /* 000001100000 */
+	0x07, 0xf0, /* 000001111111 */
+	0x07, 0xf0, /* 000001111111 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+
+	/* 199 0xc7 '.' */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0xf0, /* 000011011111 */
+	0x0d, 0xf0, /* 000011011111 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+
+	/* 200 0xc8 '.' */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0xf0, /* 000011011111 */
+	0x0d, 0xf0, /* 000011011111 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0f, 0xf0, /* 000011111111 */
+	0x0f, 0xf0, /* 000011111111 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 201 0xc9 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0xf0, /* 000011111111 */
+	0x0f, 0xf0, /* 000011111111 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0d, 0xf0, /* 000011011111 */
+	0x0d, 0xf0, /* 000011011111 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+
+	/* 202 0xca '.' */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0xfd, 0xf0, /* 111111011111 */
+	0xfd, 0xf0, /* 111111011111 */
+	0x00, 0x00, /* 000000000000 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 203 0xcb '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0x00, 0x00, /* 000000000000 */
+	0xfd, 0xf0, /* 111111011111 */
+	0xfd, 0xf0, /* 111111011111 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+
+	/* 204 0xcc '.' */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0xf0, /* 000011011111 */
+	0x0d, 0xf0, /* 000011011111 */
+	0x0c, 0x00, /* 000011000000 */
+	0x0d, 0xf0, /* 000011011111 */
+	0x0d, 0xf0, /* 000011011111 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+
+	/* 205 0xcd '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0x00, 0x00, /* 000000000000 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 206 0xce '.' */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0xfd, 0xf0, /* 111111011111 */
+	0xfd, 0xf0, /* 111111011111 */
+	0x00, 0x00, /* 000000000000 */
+	0xfd, 0xf0, /* 111111011111 */
+	0xfd, 0xf0, /* 111111011111 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+
+	/* 207 0xcf '.' */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0x00, 0x00, /* 000000000000 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 208 0xd0 '.' */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 209 0xd1 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0x00, 0x00, /* 000000000000 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+
+	/* 210 0xd2 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+
+	/* 211 0xd3 '.' */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0f, 0xf0, /* 000011111111 */
+	0x0f, 0xf0, /* 000011111111 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 212 0xd4 '.' */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x07, 0xf0, /* 000001111111 */
+	0x07, 0xf0, /* 000001111111 */
+	0x06, 0x00, /* 000001100000 */
+	0x07, 0xf0, /* 000001111111 */
+	0x07, 0xf0, /* 000001111111 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 213 0xd5 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x07, 0xf0, /* 000001111111 */
+	0x07, 0xf0, /* 000001111111 */
+	0x06, 0x00, /* 000001100000 */
+	0x07, 0xf0, /* 000001111111 */
+	0x07, 0xf0, /* 000001111111 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+
+	/* 214 0xd6 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0xf0, /* 000011111111 */
+	0x0f, 0xf0, /* 000011111111 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+
+	/* 215 0xd7 '.' */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+	0x0d, 0x80, /* 000011011000 */
+
+	/* 216 0xd8 '.' */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0x06, 0x00, /* 000001100000 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+
+	/* 217 0xd9 '.' */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0xfe, 0x00, /* 111111100000 */
+	0xfe, 0x00, /* 111111100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 218 0xda '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x07, 0xf0, /* 000001111111 */
+	0x07, 0xf0, /* 000001111111 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+
+	/* 219 0xdb '.' */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+
+	/* 220 0xdc '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+
+	/* 221 0xdd '.' */
+	0xfc, 0x00, /* 111111000000 */
+	0xfc, 0x00, /* 111111000000 */
+	0xfc, 0x00, /* 111111000000 */
+	0xfc, 0x00, /* 111111000000 */
+	0xfc, 0x00, /* 111111000000 */
+	0xfc, 0x00, /* 111111000000 */
+	0xfc, 0x00, /* 111111000000 */
+	0xfc, 0x00, /* 111111000000 */
+	0xfc, 0x00, /* 111111000000 */
+	0xfc, 0x00, /* 111111000000 */
+	0xfc, 0x00, /* 111111000000 */
+	0xfc, 0x00, /* 111111000000 */
+	0xfc, 0x00, /* 111111000000 */
+	0xfc, 0x00, /* 111111000000 */
+	0xfc, 0x00, /* 111111000000 */
+	0xfc, 0x00, /* 111111000000 */
+	0xfc, 0x00, /* 111111000000 */
+	0xfc, 0x00, /* 111111000000 */
+	0xfc, 0x00, /* 111111000000 */
+	0xfc, 0x00, /* 111111000000 */
+	0xfc, 0x00, /* 111111000000 */
+	0xfc, 0x00, /* 111111000000 */
+
+	/* 222 0xde '.' */
+	0x03, 0xf0, /* 000000111111 */
+	0x03, 0xf0, /* 000000111111 */
+	0x03, 0xf0, /* 000000111111 */
+	0x03, 0xf0, /* 000000111111 */
+	0x03, 0xf0, /* 000000111111 */
+	0x03, 0xf0, /* 000000111111 */
+	0x03, 0xf0, /* 000000111111 */
+	0x03, 0xf0, /* 000000111111 */
+	0x03, 0xf0, /* 000000111111 */
+	0x03, 0xf0, /* 000000111111 */
+	0x03, 0xf0, /* 000000111111 */
+	0x03, 0xf0, /* 000000111111 */
+	0x03, 0xf0, /* 000000111111 */
+	0x03, 0xf0, /* 000000111111 */
+	0x03, 0xf0, /* 000000111111 */
+	0x03, 0xf0, /* 000000111111 */
+	0x03, 0xf0, /* 000000111111 */
+	0x03, 0xf0, /* 000000111111 */
+	0x03, 0xf0, /* 000000111111 */
+	0x03, 0xf0, /* 000000111111 */
+	0x03, 0xf0, /* 000000111111 */
+	0x03, 0xf0, /* 000000111111 */
+
+	/* 223 0xdf '.' */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0xff, 0xf0, /* 111111111111 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 224 0xe0 '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 225 0xe1 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x19, 0x80, /* 000110011000 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x31, 0x80, /* 001100011000 */
+	0x37, 0x80, /* 001101111000 */
+	0x31, 0x80, /* 001100011000 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x31, 0x80, /* 001100011000 */
+	0x77, 0x00, /* 011101110000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 226 0xe2 '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 227 0xe3 '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 228 0xe4 '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 229 0xe5 '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 230 0xe6 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x30, 0xc0, /* 001100001100 */
+	0x39, 0xc0, /* 001110011100 */
+	0x36, 0xe0, /* 001101101110 */
+	0x30, 0x00, /* 001100000000 */
+	0x30, 0x00, /* 001100000000 */
+	0x60, 0x00, /* 011000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 231 0xe7 '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 232 0xe8 '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 233 0xe9 '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 234 0xea '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 235 0xeb '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 236 0xec '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 237 0xed '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 238 0xee '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 239 0xef '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 240 0xf0 '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 241 0xf1 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 242 0xf2 '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 243 0xf3 '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 244 0xf4 '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 245 0xf5 '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 246 0xf6 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x7f, 0xe0, /* 011111111110 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x06, 0x00, /* 000001100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 247 0xf7 '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 248 0xf8 '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x19, 0x80, /* 000110011000 */
+	0x19, 0x80, /* 000110011000 */
+	0x19, 0x80, /* 000110011000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 249 0xf9 '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 250 0xfa '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x06, 0x00, /* 000001100000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x06, 0x00, /* 000001100000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 251 0xfb '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 252 0xfc '.' */
+	/* FIXME */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 253 0xfd '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x0f, 0x00, /* 000011110000 */
+	0x1f, 0x80, /* 000111111000 */
+	0x31, 0x80, /* 001100011000 */
+	0x21, 0x80, /* 001000011000 */
+	0x03, 0x00, /* 000000110000 */
+	0x06, 0x00, /* 000001100000 */
+	0x0c, 0x00, /* 000011000000 */
+	0x18, 0x40, /* 000110000100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 254 0xfe '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x3f, 0xc0, /* 001111111100 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+	/* 255 0xff '.' */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+	0x00, 0x00, /* 000000000000 */
+
+};
+
+
+struct font_desc font_sun_12x22 = {
+	SUN12x22_IDX,
+	"SUN12x22",
+	12,
+	22,
+	fontdata_sun12x22,
+#ifdef __sparc__
+	5
+#else
+	-1
+#endif
+};
diff --git a/drivers/video/console/font_sun8x16.c b/drivers/video/console/font_sun8x16.c
new file mode 100644
index 0000000..2af3ab3
--- /dev/null
+++ b/drivers/video/console/font_sun8x16.c
@@ -0,0 +1,275 @@
+#include <linux/font.h>
+
+#define FONTDATAMAX 4096
+
+static unsigned char fontdata_sun8x16[FONTDATAMAX] = {
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x7e,0x81,0xa5,0x81,0x81,0xbd,0x99,0x81,0x81,0x7e,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x7e,0xff,0xdb,0xff,0xff,0xc3,0xe7,0xff,0xff,0x7e,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x6c,0xfe,0xfe,0xfe,0xfe,0x7c,0x38,0x10,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x10,0x38,0x7c,0xfe,0x7c,0x38,0x10,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x18,0x3c,0x3c,0xe7,0xe7,0xe7,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x18,0x3c,0x7e,0xff,0xff,0x7e,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x3c,0x3c,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0xff,0xff,0xff,0xff,0xff,0xff,0xe7,0xc3,0xc3,0xe7,0xff,0xff,0xff,0xff,0xff,0xff,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x3c,0x66,0x42,0x42,0x66,0x3c,0x00,0x00,0x00,0x00,0x00,
+/* */ 0xff,0xff,0xff,0xff,0xff,0xc3,0x99,0xbd,0xbd,0x99,0xc3,0xff,0xff,0xff,0xff,0xff,
+/* */ 0x00,0x00,0x1e,0x0e,0x1a,0x32,0x78,0xcc,0xcc,0xcc,0xcc,0x78,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x3c,0x66,0x66,0x66,0x66,0x3c,0x18,0x7e,0x18,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x3f,0x33,0x3f,0x30,0x30,0x30,0x30,0x70,0xf0,0xe0,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x7f,0x63,0x7f,0x63,0x63,0x63,0x63,0x67,0xe7,0xe6,0xc0,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x18,0x18,0xdb,0x3c,0xe7,0x3c,0xdb,0x18,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfe,0xf8,0xf0,0xe0,0xc0,0x80,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x02,0x06,0x0e,0x1e,0x3e,0xfe,0x3e,0x1e,0x0e,0x06,0x02,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x18,0x3c,0x7e,0x18,0x18,0x18,0x7e,0x3c,0x18,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x66,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x7f,0xdb,0xdb,0xdb,0x7b,0x1b,0x1b,0x1b,0x1b,0x1b,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x7c,0xc6,0x60,0x38,0x6c,0xc6,0xc6,0x6c,0x38,0x0c,0xc6,0x7c,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xfe,0xfe,0xfe,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x18,0x3c,0x7e,0x18,0x18,0x18,0x7e,0x3c,0x18,0x7e,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x18,0x3c,0x7e,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7e,0x3c,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x18,0x0c,0xfe,0x0c,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x30,0x60,0xfe,0x60,0x30,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xc0,0xc0,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x24,0x66,0xff,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x10,0x38,0x38,0x7c,0x7c,0xfe,0xfe,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0xfe,0xfe,0x7c,0x7c,0x38,0x38,0x10,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*!*/ 0x00,0x00,0x18,0x3c,0x3c,0x3c,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
+/*"*/ 0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*#*/ 0x00,0x00,0x00,0x6c,0x6c,0xfe,0x6c,0x6c,0x6c,0xfe,0x6c,0x6c,0x00,0x00,0x00,0x00,
+/*$*/ 0x18,0x18,0x7c,0xc6,0xc2,0xc0,0x7c,0x06,0x06,0x86,0xc6,0x7c,0x18,0x18,0x00,0x00,
+/*%*/ 0x00,0x00,0x00,0x00,0xc2,0xc6,0x0c,0x18,0x30,0x60,0xc6,0x86,0x00,0x00,0x00,0x00,
+/*&*/ 0x00,0x00,0x38,0x6c,0x6c,0x38,0x76,0xdc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/*'*/ 0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*(*/ 0x00,0x00,0x0c,0x18,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x0c,0x00,0x00,0x00,0x00,
+/*)*/ 0x00,0x00,0x30,0x18,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x18,0x30,0x00,0x00,0x00,0x00,
+/***/ 0x00,0x00,0x00,0x00,0x00,0x66,0x3c,0xff,0x3c,0x66,0x00,0x00,0x00,0x00,0x00,0x00,
+/*+*/ 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7e,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+/*,*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00,
+/*-*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*.*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x02,0x06,0x0c,0x18,0x30,0x60,0xc0,0x80,0x00,0x00,0x00,0x00,
+/*0*/ 0x00,0x00,0x7c,0xc6,0xc6,0xce,0xde,0xf6,0xe6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*1*/ 0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x7e,0x00,0x00,0x00,0x00,
+/*2*/ 0x00,0x00,0x7c,0xc6,0x06,0x0c,0x18,0x30,0x60,0xc0,0xc6,0xfe,0x00,0x00,0x00,0x00,
+/*3*/ 0x00,0x00,0x7c,0xc6,0x06,0x06,0x3c,0x06,0x06,0x06,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*4*/ 0x00,0x00,0x0c,0x1c,0x3c,0x6c,0xcc,0xfe,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x00,
+/*5*/ 0x00,0x00,0xfe,0xc0,0xc0,0xc0,0xfc,0x06,0x06,0x06,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*6*/ 0x00,0x00,0x38,0x60,0xc0,0xc0,0xfc,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*7*/ 0x00,0x00,0xfe,0xc6,0x06,0x06,0x0c,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00,
+/*8*/ 0x00,0x00,0x7c,0xc6,0xc6,0xc6,0x7c,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*9*/ 0x00,0x00,0x7c,0xc6,0xc6,0xc6,0x7e,0x06,0x06,0x06,0x0c,0x78,0x00,0x00,0x00,0x00,
+/*:*/ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,
+/*;*/ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00,
+/*<*/ 0x00,0x00,0x00,0x06,0x0c,0x18,0x30,0x60,0x30,0x18,0x0c,0x06,0x00,0x00,0x00,0x00,
+/*=*/ 0x00,0x00,0x00,0x00,0x00,0x7e,0x00,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*>*/ 0x00,0x00,0x00,0x60,0x30,0x18,0x0c,0x06,0x0c,0x18,0x30,0x60,0x00,0x00,0x00,0x00,
+/*?*/ 0x00,0x00,0x7c,0xc6,0xc6,0x0c,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
+/*@*/ 0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xde,0xde,0xde,0xdc,0xc0,0x7c,0x00,0x00,0x00,0x00,
+/*A*/ 0x00,0x00,0x10,0x38,0x6c,0xc6,0xc6,0xfe,0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
+/*B*/ 0x00,0x00,0xfc,0x66,0x66,0x66,0x7c,0x66,0x66,0x66,0x66,0xfc,0x00,0x00,0x00,0x00,
+/*C*/ 0x00,0x00,0x3c,0x66,0xc2,0xc0,0xc0,0xc0,0xc0,0xc2,0x66,0x3c,0x00,0x00,0x00,0x00,
+/*D*/ 0x00,0x00,0xf8,0x6c,0x66,0x66,0x66,0x66,0x66,0x66,0x6c,0xf8,0x00,0x00,0x00,0x00,
+/*E*/ 0x00,0x00,0xfe,0x66,0x62,0x68,0x78,0x68,0x60,0x62,0x66,0xfe,0x00,0x00,0x00,0x00,
+/*F*/ 0x00,0x00,0xfe,0x66,0x62,0x68,0x78,0x68,0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00,
+/*G*/ 0x00,0x00,0x3c,0x66,0xc2,0xc0,0xc0,0xde,0xc6,0xc6,0x66,0x3a,0x00,0x00,0x00,0x00,
+/*H*/ 0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xfe,0xc6,0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
+/*I*/ 0x00,0x00,0x3c,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/*J*/ 0x00,0x00,0x1e,0x0c,0x0c,0x0c,0x0c,0x0c,0xcc,0xcc,0xcc,0x78,0x00,0x00,0x00,0x00,
+/*K*/ 0x00,0x00,0xe6,0x66,0x66,0x6c,0x78,0x78,0x6c,0x66,0x66,0xe6,0x00,0x00,0x00,0x00,
+/*L*/ 0x00,0x00,0xf0,0x60,0x60,0x60,0x60,0x60,0x60,0x62,0x66,0xfe,0x00,0x00,0x00,0x00,
+/*M*/ 0x00,0x00,0xc3,0xe7,0xff,0xff,0xdb,0xc3,0xc3,0xc3,0xc3,0xc3,0x00,0x00,0x00,0x00,
+/*N*/ 0x00,0x00,0xc6,0xe6,0xf6,0xfe,0xde,0xce,0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
+/*O*/ 0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*P*/ 0x00,0x00,0xfc,0x66,0x66,0x66,0x7c,0x60,0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00,
+/*Q*/ 0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xd6,0xde,0x7c,0x0c,0x0e,0x00,0x00,
+/*R*/ 0x00,0x00,0xfc,0x66,0x66,0x66,0x7c,0x6c,0x66,0x66,0x66,0xe6,0x00,0x00,0x00,0x00,
+/*S*/ 0x00,0x00,0x7c,0xc6,0xc6,0x60,0x38,0x0c,0x06,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*T*/ 0x00,0x00,0xff,0xdb,0x99,0x18,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/*U*/ 0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*V*/ 0x00,0x00,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0x66,0x3c,0x18,0x00,0x00,0x00,0x00,
+/*W*/ 0x00,0x00,0xc3,0xc3,0xc3,0xc3,0xc3,0xdb,0xdb,0xff,0x66,0x66,0x00,0x00,0x00,0x00,
+/*X*/ 0x00,0x00,0xc3,0xc3,0x66,0x3c,0x18,0x18,0x3c,0x66,0xc3,0xc3,0x00,0x00,0x00,0x00,
+/*Y*/ 0x00,0x00,0xc3,0xc3,0xc3,0x66,0x3c,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/*Z*/ 0x00,0x00,0xff,0xc3,0x86,0x0c,0x18,0x30,0x60,0xc1,0xc3,0xff,0x00,0x00,0x00,0x00,
+/*[*/ 0x00,0x00,0x3c,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3c,0x00,0x00,0x00,0x00,
+/*\*/ 0x00,0x00,0x00,0x80,0xc0,0xe0,0x70,0x38,0x1c,0x0e,0x06,0x02,0x00,0x00,0x00,0x00,
+/*]*/ 0x00,0x00,0x3c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x3c,0x00,0x00,0x00,0x00,
+/*^*/ 0x10,0x38,0x6c,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*_*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0x00,
+/*`*/ 0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*a*/ 0x00,0x00,0x00,0x00,0x00,0x78,0x0c,0x7c,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/*b*/ 0x00,0x00,0xe0,0x60,0x60,0x78,0x6c,0x66,0x66,0x66,0x66,0x7c,0x00,0x00,0x00,0x00,
+/*c*/ 0x00,0x00,0x00,0x00,0x00,0x7c,0xc6,0xc0,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*d*/ 0x00,0x00,0x1c,0x0c,0x0c,0x3c,0x6c,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/*e*/ 0x00,0x00,0x00,0x00,0x00,0x7c,0xc6,0xfe,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*f*/ 0x00,0x00,0x38,0x6c,0x64,0x60,0xf0,0x60,0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00,
+/*g*/ 0x00,0x00,0x00,0x00,0x00,0x76,0xcc,0xcc,0xcc,0xcc,0xcc,0x7c,0x0c,0xcc,0x78,0x00,
+/*h*/ 0x00,0x00,0xe0,0x60,0x60,0x6c,0x76,0x66,0x66,0x66,0x66,0xe6,0x00,0x00,0x00,0x00,
+/*i*/ 0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/*j*/ 0x00,0x00,0x06,0x06,0x00,0x0e,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3c,0x00,
+/*k*/ 0x00,0x00,0xe0,0x60,0x60,0x66,0x6c,0x78,0x78,0x6c,0x66,0xe6,0x00,0x00,0x00,0x00,
+/*l*/ 0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/*m*/ 0x00,0x00,0x00,0x00,0x00,0xe6,0xff,0xdb,0xdb,0xdb,0xdb,0xdb,0x00,0x00,0x00,0x00,
+/*n*/ 0x00,0x00,0x00,0x00,0x00,0xdc,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,
+/*o*/ 0x00,0x00,0x00,0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*p*/ 0x00,0x00,0x00,0x00,0x00,0xdc,0x66,0x66,0x66,0x66,0x66,0x7c,0x60,0x60,0xf0,0x00,
+/*q*/ 0x00,0x00,0x00,0x00,0x00,0x76,0xcc,0xcc,0xcc,0xcc,0xcc,0x7c,0x0c,0x0c,0x1e,0x00,
+/*r*/ 0x00,0x00,0x00,0x00,0x00,0xdc,0x76,0x66,0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00,
+/*s*/ 0x00,0x00,0x00,0x00,0x00,0x7c,0xc6,0x60,0x38,0x0c,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*t*/ 0x00,0x00,0x10,0x30,0x30,0xfc,0x30,0x30,0x30,0x30,0x36,0x1c,0x00,0x00,0x00,0x00,
+/*u*/ 0x00,0x00,0x00,0x00,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/*v*/ 0x00,0x00,0x00,0x00,0x00,0xc3,0xc3,0xc3,0xc3,0x66,0x3c,0x18,0x00,0x00,0x00,0x00,
+/*w*/ 0x00,0x00,0x00,0x00,0x00,0xc3,0xc3,0xc3,0xdb,0xdb,0xff,0x66,0x00,0x00,0x00,0x00,
+/*x*/ 0x00,0x00,0x00,0x00,0x00,0xc3,0x66,0x3c,0x18,0x3c,0x66,0xc3,0x00,0x00,0x00,0x00,
+/*y*/ 0x00,0x00,0x00,0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7e,0x06,0x0c,0xf8,0x00,
+/*z*/ 0x00,0x00,0x00,0x00,0x00,0xfe,0xcc,0x18,0x30,0x60,0xc6,0xfe,0x00,0x00,0x00,0x00,
+/*{*/ 0x00,0x00,0x0e,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0e,0x00,0x00,0x00,0x00,
+/*|*/ 0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+/*}*/ 0x00,0x00,0x70,0x18,0x18,0x18,0x0e,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00,
+/*~*/ 0x00,0x00,0x76,0xdc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x10,0x38,0x6c,0xc6,0xc6,0xc6,0xfe,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x3c,0x66,0xc2,0xc0,0xc0,0xc0,0xc2,0x66,0x3c,0x0c,0x06,0x7c,0x00,0x00,
+/* */ 0x00,0x00,0xcc,0x00,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x0c,0x18,0x30,0x00,0x7c,0xc6,0xfe,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x10,0x38,0x6c,0x00,0x78,0x0c,0x7c,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0xcc,0x00,0x00,0x78,0x0c,0x7c,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x60,0x30,0x18,0x00,0x78,0x0c,0x7c,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x38,0x6c,0x38,0x00,0x78,0x0c,0x7c,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x3c,0x66,0x60,0x60,0x66,0x3c,0x0c,0x06,0x3c,0x00,0x00,0x00,
+/* */ 0x00,0x10,0x38,0x6c,0x00,0x7c,0xc6,0xfe,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0xc6,0x00,0x00,0x7c,0xc6,0xfe,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x60,0x30,0x18,0x00,0x7c,0xc6,0xfe,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x66,0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x18,0x3c,0x66,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x60,0x30,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0xc6,0x00,0x10,0x38,0x6c,0xc6,0xc6,0xfe,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
+/* */ 0x38,0x6c,0x38,0x00,0x38,0x6c,0xc6,0xc6,0xfe,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
+/* */ 0x18,0x30,0x60,0x00,0xfe,0x66,0x60,0x7c,0x60,0x60,0x66,0xfe,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x6e,0x3b,0x1b,0x7e,0xd8,0xdc,0x77,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x3e,0x6c,0xcc,0xcc,0xfe,0xcc,0xcc,0xcc,0xcc,0xce,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x10,0x38,0x6c,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0xc6,0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x60,0x30,0x18,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x30,0x78,0xcc,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x60,0x30,0x18,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0xc6,0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7e,0x06,0x0c,0x78,0x00,
+/* */ 0x00,0xc6,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0xc6,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x18,0x18,0x7e,0xc3,0xc0,0xc0,0xc0,0xc3,0x7e,0x18,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x38,0x6c,0x64,0x60,0xf0,0x60,0x60,0x60,0x60,0xe6,0xfc,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0xc3,0x66,0x3c,0x18,0xff,0x18,0xff,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0xfc,0x66,0x66,0x7c,0x62,0x66,0x6f,0x66,0x66,0x66,0xf3,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x0e,0x1b,0x18,0x18,0x18,0x7e,0x18,0x18,0x18,0x18,0x18,0xd8,0x70,0x00,0x00,
+/* */ 0x00,0x18,0x30,0x60,0x00,0x78,0x0c,0x7c,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x0c,0x18,0x30,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x18,0x30,0x60,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x18,0x30,0x60,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x76,0xdc,0x00,0xdc,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,
+/* */ 0x76,0xdc,0x00,0xc6,0xe6,0xf6,0xfe,0xde,0xce,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x3c,0x6c,0x6c,0x3e,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x38,0x6c,0x6c,0x38,0x00,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x60,0xc0,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xc0,0xc0,0xc0,0xc0,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0xc0,0xc0,0xc2,0xc6,0xcc,0x18,0x30,0x60,0xce,0x9b,0x06,0x0c,0x1f,0x00,0x00,
+/* */ 0x00,0xc0,0xc0,0xc2,0xc6,0xcc,0x18,0x30,0x66,0xce,0x96,0x3e,0x06,0x06,0x00,0x00,
+/* */ 0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x18,0x3c,0x3c,0x3c,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x36,0x6c,0xd8,0x6c,0x36,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0xd8,0x6c,0x36,0x6c,0xd8,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,
+/* */ 0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,
+/* */ 0xdd,0x77,0xdd,0x77,0xdd,0x77,0xdd,0x77,0xdd,0x77,0xdd,0x77,0xdd,0x77,0xdd,0x77,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xf8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x18,0x18,0x18,0x18,0x18,0xf8,0x18,0xf8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xf6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x00,0x00,0x00,0x00,0x00,0xf8,0x18,0xf8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x36,0x36,0x36,0x36,0x36,0xf6,0x06,0xf6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x00,0x00,0x00,0x00,0x00,0xfe,0x06,0xf6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x36,0x36,0x36,0x36,0x36,0xf6,0x06,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x18,0x18,0x18,0x18,0x18,0xf8,0x18,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1f,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x1f,0x18,0x1f,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x3f,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x36,0x36,0x36,0x36,0x36,0xf7,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xf7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x36,0x36,0x36,0x36,0x36,0xf7,0x00,0xf7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x18,0x18,0x18,0x18,0x18,0xff,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x1f,0x18,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x1f,0x18,0x1f,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xff,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x18,0x18,0x18,0x18,0x18,0xff,0x18,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+/* */ 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,
+/* */ 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,
+/* */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x76,0xdc,0xd8,0xd8,0xd8,0xdc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x78,0xcc,0xcc,0xcc,0xd8,0xcc,0xc6,0xc6,0xc6,0xcc,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0xfe,0xc6,0xc6,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0xfe,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0xfe,0xc6,0x60,0x30,0x18,0x30,0x60,0xc6,0xfe,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x7e,0xd8,0xd8,0xd8,0xd8,0xd8,0x70,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x7c,0x60,0x60,0xc0,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x76,0xdc,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x7e,0x18,0x3c,0x66,0x66,0x66,0x3c,0x18,0x7e,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x38,0x6c,0xc6,0xc6,0xfe,0xc6,0xc6,0x6c,0x38,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x38,0x6c,0xc6,0xc6,0xc6,0x6c,0x6c,0x6c,0x6c,0xee,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x1e,0x30,0x18,0x0c,0x3e,0x66,0x66,0x66,0x66,0x3c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x7e,0xdb,0xdb,0xdb,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x03,0x06,0x7e,0xdb,0xdb,0xf3,0x7e,0x60,0xc0,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x1c,0x30,0x60,0x60,0x7c,0x60,0x60,0x60,0x30,0x1c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0xfe,0x00,0x00,0xfe,0x00,0x00,0xfe,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x18,0x18,0x7e,0x18,0x18,0x00,0x00,0xff,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x30,0x18,0x0c,0x06,0x0c,0x18,0x30,0x00,0x7e,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x0c,0x18,0x30,0x60,0x30,0x18,0x0c,0x00,0x7e,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x0e,0x1b,0x1b,0x1b,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xd8,0xd8,0xd8,0x70,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x7e,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x76,0xdc,0x00,0x76,0xdc,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x38,0x6c,0x6c,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x0f,0x0c,0x0c,0x0c,0x0c,0x0c,0xec,0x6c,0x6c,0x3c,0x1c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0xd8,0x6c,0x6c,0x6c,0x6c,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x70,0xd8,0x30,0x60,0xc8,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+
+struct font_desc font_sun_8x16 = {
+	SUN8x16_IDX,
+	"SUN8x16",
+	8,
+	16,
+	fontdata_sun8x16,
+#ifdef __sparc__
+	10
+#else
+	-1
+#endif
+};
diff --git a/drivers/video/console/fonts.c b/drivers/video/console/fonts.c
new file mode 100644
index 0000000..465d678
--- /dev/null
+++ b/drivers/video/console/fonts.c
@@ -0,0 +1,139 @@
+/*
+ * linux/drivers/video/fonts.c -- `Soft' font definitions
+ *
+ *    Created 1995 by Geert Uytterhoeven
+ *    Rewritten 1998 by Martin Mares <mj@ucw.cz>
+ *
+ *	2001 - Documented with DocBook
+ *	- Brad Douglas <brad@neruo.com>
+ *
+ * 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/types.h>
+#include <linux/string.h>
+#if defined(__mc68000__) || defined(CONFIG_APUS)
+#include <asm/setup.h>
+#endif
+#include <linux/font.h>
+
+#define NO_FONTS
+
+static struct font_desc *fonts[] = {
+#ifdef CONFIG_FONT_8x8
+#undef NO_FONTS
+    &font_vga_8x8,
+#endif
+#ifdef CONFIG_FONT_8x16
+#undef NO_FONTS
+    &font_vga_8x16,
+#endif
+#ifdef CONFIG_FONT_6x11
+#undef NO_FONTS
+    &font_vga_6x11,
+#endif
+#ifdef CONFIG_FONT_SUN8x16
+#undef NO_FONTS
+    &font_sun_8x16,
+#endif
+#ifdef CONFIG_FONT_SUN12x22
+#undef NO_FONTS
+    &font_sun_12x22,
+#endif
+#ifdef CONFIG_FONT_ACORN_8x8
+#undef NO_FONTS
+    &font_acorn_8x8,
+#endif
+#ifdef CONFIG_FONT_PEARL_8x8
+#undef NO_FONTS
+    &font_pearl_8x8,
+#endif
+#ifdef CONFIG_FONT_MINI_4x6
+#undef NO_FONTS
+    &font_mini_4x6,
+#endif
+};
+
+#define num_fonts (sizeof(fonts)/sizeof(*fonts))
+
+#ifdef NO_FONTS
+#error No fonts configured.
+#endif
+
+
+/**
+ *	find_font - find a font
+ *	@name: string name of a font
+ *
+ *	Find a specified font with string name @name.
+ *
+ *	Returns %NULL if no font found, or a pointer to the
+ *	specified font.
+ *
+ */
+
+struct font_desc *find_font(char *name)
+{
+   unsigned int i;
+
+   for (i = 0; i < num_fonts; i++)
+      if (!strcmp(fonts[i]->name, name))
+	  return fonts[i];
+   return NULL;
+}
+
+
+/**
+ *	get_default_font - get default font
+ *	@xres: screen size of X
+ *	@yres: screen size of Y
+ *
+ *	Get the default font for a specified screen size.
+ *	Dimensions are in pixels.
+ *
+ *	Returns %NULL if no font is found, or a pointer to the
+ *	chosen font.
+ *
+ */
+
+struct font_desc *get_default_font(int xres, int yres)
+{
+    int i, c, cc;
+    struct font_desc *f, *g;
+
+    g = NULL;
+    cc = -10000;
+    for(i=0; i<num_fonts; i++) {
+	f = fonts[i];
+	c = f->pref;
+#if defined(__mc68000__) || defined(CONFIG_APUS)
+#ifdef CONFIG_FONT_PEARL_8x8
+	if (MACH_IS_AMIGA && f->idx == PEARL8x8_IDX)
+	    c = 100;
+#endif
+#ifdef CONFIG_FONT_6x11
+	if (MACH_IS_MAC && xres < 640 && f->idx == VGA6x11_IDX)
+	    c = 100;
+#endif
+#endif
+	if ((yres < 400) == (f->height <= 8))
+	    c += 1000;
+	if (c > cc) {
+	    cc = c;
+	    g = f;
+	}
+    }
+    return g;
+}
+
+EXPORT_SYMBOL(fonts);
+EXPORT_SYMBOL(find_font);
+EXPORT_SYMBOL(get_default_font);
+
+MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
+MODULE_DESCRIPTION("Console Fonts");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c
new file mode 100644
index 0000000..989e4d4
--- /dev/null
+++ b/drivers/video/console/mdacon.c
@@ -0,0 +1,603 @@
+/*
+ *  linux/drivers/video/mdacon.c -- Low level MDA based console driver
+ *
+ *	(c) 1998 Andrew Apted <ajapted@netspace.net.au>
+ *
+ *      including portions (c) 1995-1998 Patrick Caulfield.
+ *
+ *      slight improvements (c) 2000 Edward Betts <edward@debian.org>
+ *
+ *  This file is based on the VGA console driver (vgacon.c):
+ *	
+ *	Created 28 Sep 1997 by Geert Uytterhoeven
+ *
+ *	Rewritten by Martin Mares <mj@ucw.cz>, July 1998
+ *
+ *  and on the old console.c, vga.c and vesa_blank.c drivers:
+ *
+ *	Copyright (C) 1991, 1992  Linus Torvalds
+ *			    1995  Jay Estabrook
+ *
+ *  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.
+ *
+ *  Changelog:
+ *  Paul G. (03/2001) Fix mdacon= boot prompt to use __setup().
+ */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/string.h>
+#include <linux/kd.h>
+#include <linux/slab.h>
+#include <linux/vt_kern.h>
+#include <linux/vt_buffer.h>
+#include <linux/selection.h>
+#include <linux/spinlock.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/vga.h>
+
+static DEFINE_SPINLOCK(mda_lock);
+
+/* description of the hardware layout */
+
+static unsigned long	mda_vram_base;		/* Base of video memory */
+static unsigned long	mda_vram_len;		/* Size of video memory */
+static unsigned int	mda_num_columns;	/* Number of text columns */
+static unsigned int	mda_num_lines;		/* Number of text lines */
+
+static unsigned int	mda_index_port;		/* Register select port */
+static unsigned int	mda_value_port;		/* Register value port */
+static unsigned int	mda_mode_port;		/* Mode control port */
+static unsigned int	mda_status_port;	/* Status and Config port */
+static unsigned int	mda_gfx_port;		/* Graphics control port */
+
+/* current hardware state */
+
+static int	mda_cursor_loc=-1;
+static int	mda_cursor_size_from=-1;
+static int	mda_cursor_size_to=-1;
+
+static enum { TYPE_MDA, TYPE_HERC, TYPE_HERCPLUS, TYPE_HERCCOLOR } mda_type;
+static char *mda_type_name;
+
+/* console information */
+
+static int	mda_first_vc = 1;
+static int	mda_last_vc  = 16;
+
+static struct vc_data	*mda_display_fg = NULL;
+
+module_param(mda_first_vc, int, 0);
+module_param(mda_last_vc, int, 0);
+
+/* MDA register values
+ */
+
+#define MDA_CURSOR_BLINKING	0x00
+#define MDA_CURSOR_OFF		0x20
+#define MDA_CURSOR_SLOWBLINK	0x60
+
+#define MDA_MODE_GRAPHICS	0x02
+#define MDA_MODE_VIDEO_EN	0x08
+#define MDA_MODE_BLINK_EN	0x20
+#define MDA_MODE_GFX_PAGE1	0x80
+
+#define MDA_STATUS_HSYNC	0x01
+#define MDA_STATUS_VSYNC	0x80
+#define MDA_STATUS_VIDEO	0x08
+
+#define MDA_CONFIG_COL132	0x08
+#define MDA_GFX_MODE_EN		0x01
+#define MDA_GFX_PAGE_EN		0x02
+
+
+/*
+ * MDA could easily be classified as "pre-dinosaur hardware".
+ */
+
+static void write_mda_b(unsigned int val, unsigned char reg)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mda_lock, flags);	
+
+	outb_p(reg, mda_index_port); 
+	outb_p(val, mda_value_port);
+
+	spin_unlock_irqrestore(&mda_lock, flags);
+}
+
+static void write_mda_w(unsigned int val, unsigned char reg)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mda_lock, flags);
+
+	outb_p(reg,   mda_index_port); outb_p(val >> 8,   mda_value_port);
+	outb_p(reg+1, mda_index_port); outb_p(val & 0xff, mda_value_port);
+
+	spin_unlock_irqrestore(&mda_lock, flags);
+}
+
+#ifdef TEST_MDA_B
+static int test_mda_b(unsigned char val, unsigned char reg)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mda_lock, flags);
+
+	outb_p(reg, mda_index_port); 
+	outb  (val, mda_value_port);
+
+	udelay(20); val = (inb_p(mda_value_port) == val);
+
+	spin_unlock_irqrestore(&mda_lock, flags);
+	return val;
+}
+#endif
+
+static inline void mda_set_cursor(unsigned int location) 
+{
+	if (mda_cursor_loc == location)
+		return;
+
+	write_mda_w(location >> 1, 0x0e);
+
+	mda_cursor_loc = location;
+}
+
+static inline void mda_set_cursor_size(int from, int to)
+{
+	if (mda_cursor_size_from==from && mda_cursor_size_to==to)
+		return;
+	
+	if (from > to) {
+		write_mda_b(MDA_CURSOR_OFF, 0x0a);	/* disable cursor */
+	} else {
+		write_mda_b(from, 0x0a);	/* cursor start */
+		write_mda_b(to,   0x0b);	/* cursor end */
+	}
+
+	mda_cursor_size_from = from;
+	mda_cursor_size_to   = to;
+}
+
+
+#ifndef MODULE
+static int __init mdacon_setup(char *str)
+{
+	/* command line format: mdacon=<first>,<last> */
+
+	int ints[3];
+
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+
+	if (ints[0] < 2)
+		return 0;
+
+	if (ints[1] < 1 || ints[1] > MAX_NR_CONSOLES || 
+	    ints[2] < 1 || ints[2] > MAX_NR_CONSOLES)
+		return 0;
+
+	mda_first_vc = ints[1];
+	mda_last_vc  = ints[2];
+	return 1;
+}
+
+__setup("mdacon=", mdacon_setup);
+#endif
+
+static int __init mda_detect(void)
+{
+	int count=0;
+	u16 *p, p_save;
+	u16 *q, q_save;
+
+	/* do a memory check */
+
+	p = (u16 *) mda_vram_base;
+	q = (u16 *) (mda_vram_base + 0x01000);
+
+	p_save = scr_readw(p); q_save = scr_readw(q);
+
+	scr_writew(0xAA55, p); if (scr_readw(p) == 0xAA55) count++;
+	scr_writew(0x55AA, p); if (scr_readw(p) == 0x55AA) count++;
+	scr_writew(p_save, p);
+
+	if (count != 2) {
+		return 0;
+	}
+
+	/* check if we have 4K or 8K */
+
+	scr_writew(0xA55A, q); scr_writew(0x0000, p);
+	if (scr_readw(q) == 0xA55A) count++;
+	
+	scr_writew(0x5AA5, q); scr_writew(0x0000, p);
+	if (scr_readw(q) == 0x5AA5) count++;
+
+	scr_writew(p_save, p); scr_writew(q_save, q);
+	
+	if (count == 4) {
+		mda_vram_len = 0x02000;
+	}
+	
+	/* Ok, there is definitely a card registering at the correct
+	 * memory location, so now we do an I/O port test.
+	 */
+
+#ifdef TEST_MDA_B
+	/* Edward: These two mess `tests' mess up my cursor on bootup */
+
+	/* cursor low register */
+	if (! test_mda_b(0x66, 0x0f)) {
+		return 0;
+	}
+
+	/* cursor low register */
+	if (! test_mda_b(0x99, 0x0f)) {
+		return 0;
+	}
+#endif
+
+	/* See if the card is a Hercules, by checking whether the vsync
+	 * bit of the status register is changing.  This test lasts for
+	 * approximately 1/10th of a second.
+	 */
+	
+	p_save = q_save = inb_p(mda_status_port) & MDA_STATUS_VSYNC;
+
+	for (count=0; count < 50000 && p_save == q_save; count++) {
+		q_save = inb(mda_status_port) & MDA_STATUS_VSYNC;
+		udelay(2);
+	}
+
+	if (p_save != q_save) {
+		switch (inb_p(mda_status_port) & 0x70) {
+			case 0x10:
+				mda_type = TYPE_HERCPLUS;
+				mda_type_name = "HerculesPlus";
+				break;
+			case 0x50:
+				mda_type = TYPE_HERCCOLOR;
+				mda_type_name = "HerculesColor";
+				break;
+			default:
+				mda_type = TYPE_HERC;
+				mda_type_name = "Hercules";
+				break;
+		}
+	}
+
+	return 1;
+}
+
+static void __init mda_initialize(void)
+{
+	write_mda_b(97, 0x00);		/* horizontal total */
+	write_mda_b(80, 0x01);		/* horizontal displayed */
+	write_mda_b(82, 0x02);		/* horizontal sync pos */
+	write_mda_b(15, 0x03);		/* horizontal sync width */
+
+	write_mda_b(25, 0x04);		/* vertical total */
+	write_mda_b(6,  0x05);		/* vertical total adjust */
+	write_mda_b(25, 0x06);		/* vertical displayed */
+	write_mda_b(25, 0x07);		/* vertical sync pos */
+
+	write_mda_b(2,  0x08);		/* interlace mode */
+	write_mda_b(13, 0x09);		/* maximum scanline */
+	write_mda_b(12, 0x0a);		/* cursor start */
+	write_mda_b(13, 0x0b);		/* cursor end */
+
+	write_mda_w(0x0000, 0x0c);	/* start address */
+	write_mda_w(0x0000, 0x0e);	/* cursor location */
+
+	outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN, mda_mode_port);
+	outb_p(0x00, mda_status_port);
+	outb_p(0x00, mda_gfx_port);
+}
+
+static const char __init *mdacon_startup(void)
+{
+	mda_num_columns = 80;
+	mda_num_lines   = 25;
+
+	mda_vram_base = VGA_MAP_MEM(0xb0000);
+	mda_vram_len  = 0x01000;
+
+	mda_index_port  = 0x3b4;
+	mda_value_port  = 0x3b5;
+	mda_mode_port   = 0x3b8;
+	mda_status_port = 0x3ba;
+	mda_gfx_port    = 0x3bf;
+
+	mda_type = TYPE_MDA;
+	mda_type_name = "MDA";
+
+	if (! mda_detect()) {
+		printk("mdacon: MDA card not detected.\n");
+		return NULL;
+	}
+
+	if (mda_type != TYPE_MDA) {
+		mda_initialize();
+	}
+
+	/* cursor looks ugly during boot-up, so turn it off */
+	mda_set_cursor(mda_vram_len - 1);
+
+	printk("mdacon: %s with %ldK of memory detected.\n",
+		mda_type_name, mda_vram_len/1024);
+
+	return "MDA-2";
+}
+
+static void mdacon_init(struct vc_data *c, int init)
+{
+	c->vc_complement_mask = 0x0800;	 /* reverse video */
+	c->vc_display_fg = &mda_display_fg;
+
+	if (init) {
+		c->vc_cols = mda_num_columns;
+		c->vc_rows = mda_num_lines;
+	} else
+		vc_resize(c, mda_num_columns, mda_num_lines);
+
+	/* make the first MDA console visible */
+
+	if (mda_display_fg == NULL)
+		mda_display_fg = c;
+}
+
+static void mdacon_deinit(struct vc_data *c)
+{
+	/* con_set_default_unimap(c->vc_num); */
+
+	if (mda_display_fg == c)
+		mda_display_fg = NULL;
+}
+
+static inline u16 mda_convert_attr(u16 ch)
+{
+	u16 attr = 0x0700;
+
+	/* Underline and reverse-video are mutually exclusive on MDA.
+	 * Since reverse-video is used for cursors and selected areas,
+	 * it takes precedence. 
+	 */
+
+	if (ch & 0x0800)	attr = 0x7000;	/* reverse */
+	else if (ch & 0x0400)	attr = 0x0100;	/* underline */
+
+	return ((ch & 0x0200) << 2) | 		/* intensity */ 
+		(ch & 0x8000) |			/* blink */ 
+		(ch & 0x00ff) | attr;
+}
+
+static u8 mdacon_build_attr(struct vc_data *c, u8 color, u8 intensity, 
+			    u8 blink, u8 underline, u8 reverse)
+{
+	/* The attribute is just a bit vector:
+	 *
+	 *	Bit 0..1 : intensity (0..2)
+	 *	Bit 2    : underline
+	 *	Bit 3    : reverse
+	 *	Bit 7    : blink
+	 */
+
+	return (intensity & 3) |
+		((underline & 1) << 2) |
+		((reverse   & 1) << 3) |
+		((blink     & 1) << 7);
+}
+
+static void mdacon_invert_region(struct vc_data *c, u16 *p, int count)
+{
+	for (; count > 0; count--) {
+		scr_writew(scr_readw(p) ^ 0x0800, p);
+		p++;
+	}
+}
+
+#define MDA_ADDR(x,y)  ((u16 *) mda_vram_base + (y)*mda_num_columns + (x))
+
+static void mdacon_putc(struct vc_data *c, int ch, int y, int x)
+{
+	scr_writew(mda_convert_attr(ch), MDA_ADDR(x, y));
+}
+
+static void mdacon_putcs(struct vc_data *c, const unsigned short *s,
+		         int count, int y, int x)
+{
+	u16 *dest = MDA_ADDR(x, y);
+
+	for (; count > 0; count--) {
+		scr_writew(mda_convert_attr(scr_readw(s++)), dest++);
+	}
+}
+
+static void mdacon_clear(struct vc_data *c, int y, int x, 
+			  int height, int width)
+{
+	u16 *dest = MDA_ADDR(x, y);
+	u16 eattr = mda_convert_attr(c->vc_video_erase_char);
+
+	if (width <= 0 || height <= 0)
+		return;
+
+	if (x==0 && width==mda_num_columns) {
+		scr_memsetw(dest, eattr, height*width*2);
+	} else {
+		for (; height > 0; height--, dest+=mda_num_columns)
+			scr_memsetw(dest, eattr, width*2);
+	}
+}
+                        
+static void mdacon_bmove(struct vc_data *c, int sy, int sx, 
+			 int dy, int dx, int height, int width)
+{
+	u16 *src, *dest;
+
+	if (width <= 0 || height <= 0)
+		return;
+		
+	if (sx==0 && dx==0 && width==mda_num_columns) {
+		scr_memmovew(MDA_ADDR(0,dy), MDA_ADDR(0,sy), height*width*2);
+
+	} else if (dy < sy || (dy == sy && dx < sx)) {
+		src  = MDA_ADDR(sx, sy);
+		dest = MDA_ADDR(dx, dy);
+
+		for (; height > 0; height--) {
+			scr_memmovew(dest, src, width*2);
+			src  += mda_num_columns;
+			dest += mda_num_columns;
+		}
+	} else {
+		src  = MDA_ADDR(sx, sy+height-1);
+		dest = MDA_ADDR(dx, dy+height-1);
+
+		for (; height > 0; height--) {
+			scr_memmovew(dest, src, width*2);
+			src  -= mda_num_columns;
+			dest -= mda_num_columns;
+		}
+	}
+}
+
+static int mdacon_switch(struct vc_data *c)
+{
+	return 1;	/* redrawing needed */
+}
+
+static int mdacon_set_palette(struct vc_data *c, unsigned char *table)
+{
+	return -EINVAL;
+}
+
+static int mdacon_blank(struct vc_data *c, int blank, int mode_switch)
+{
+	if (mda_type == TYPE_MDA) {
+		if (blank) 
+			scr_memsetw((void *)mda_vram_base, 
+				mda_convert_attr(c->vc_video_erase_char),
+				c->vc_screenbuf_size);
+		/* Tell console.c that it has to restore the screen itself */
+		return 1;
+	} else {
+		if (blank)
+			outb_p(0x00, mda_mode_port);	/* disable video */
+		else
+			outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN, 
+				mda_mode_port);
+		return 0;
+	}
+}
+
+static int mdacon_scrolldelta(struct vc_data *c, int lines)
+{
+	return 0;
+}
+
+static void mdacon_cursor(struct vc_data *c, int mode)
+{
+	if (mode == CM_ERASE) {
+		mda_set_cursor(mda_vram_len - 1);
+		return;
+	}
+
+	mda_set_cursor(c->vc_y*mda_num_columns*2 + c->vc_x*2);
+
+	switch (c->vc_cursor_type & 0x0f) {
+
+		case CUR_LOWER_THIRD:	mda_set_cursor_size(10, 13); break;
+		case CUR_LOWER_HALF:	mda_set_cursor_size(7,  13); break;
+		case CUR_TWO_THIRDS:	mda_set_cursor_size(4,  13); break;
+		case CUR_BLOCK:		mda_set_cursor_size(1,  13); break;
+		case CUR_NONE:		mda_set_cursor_size(14, 13); break;
+		default:		mda_set_cursor_size(12, 13); break;
+	}
+}
+
+static int mdacon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
+{
+	u16 eattr = mda_convert_attr(c->vc_video_erase_char);
+
+	if (!lines)
+		return 0;
+
+	if (lines > c->vc_rows)   /* maximum realistic size */
+		lines = c->vc_rows;
+
+	switch (dir) {
+
+	case SM_UP:
+		scr_memmovew(MDA_ADDR(0,t), MDA_ADDR(0,t+lines),
+				(b-t-lines)*mda_num_columns*2);
+		scr_memsetw(MDA_ADDR(0,b-lines), eattr,
+				lines*mda_num_columns*2);
+		break;
+
+	case SM_DOWN:
+		scr_memmovew(MDA_ADDR(0,t+lines), MDA_ADDR(0,t),
+				(b-t-lines)*mda_num_columns*2);
+		scr_memsetw(MDA_ADDR(0,t), eattr, lines*mda_num_columns*2);
+		break;
+	}
+
+	return 0;
+}
+
+
+/*
+ *  The console `switch' structure for the MDA based console
+ */
+
+static const struct consw mda_con = {
+	.owner =		THIS_MODULE,
+	.con_startup =		mdacon_startup,
+	.con_init =		mdacon_init,
+	.con_deinit =		mdacon_deinit,
+	.con_clear =		mdacon_clear,
+	.con_putc =		mdacon_putc,
+	.con_putcs =		mdacon_putcs,
+	.con_cursor =		mdacon_cursor,
+	.con_scroll =		mdacon_scroll,
+	.con_bmove =		mdacon_bmove,
+	.con_switch =		mdacon_switch,
+	.con_blank =		mdacon_blank,
+	.con_set_palette =	mdacon_set_palette,
+	.con_scrolldelta =	mdacon_scrolldelta,
+	.con_build_attr =	mdacon_build_attr,
+	.con_invert_region =	mdacon_invert_region,
+};
+
+int __init mda_console_init(void)
+{
+	if (mda_first_vc > mda_last_vc)
+		return 1;
+
+	return take_over_console(&mda_con, mda_first_vc-1, mda_last_vc-1, 0);
+}
+
+static void __exit mda_console_exit(void)
+{
+	give_up_console(&mda_con);
+}
+
+module_init(mda_console_init);
+module_exit(mda_console_exit);
+
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
new file mode 100644
index 0000000..e793ffd
--- /dev/null
+++ b/drivers/video/console/newport_con.c
@@ -0,0 +1,745 @@
+/*
+ * newport_con.c: Abscon for newport hardware
+ * 
+ * (C) 1998 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ * (C) 1999 Ulf Carlsson (ulfc@thepuffingruop.com)
+ * 
+ * This driver is based on sgicons.c and cons_newport.
+ * 
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/kd.h>
+#include <linux/selection.h>
+#include <linux/console.h>
+#include <linux/vt_kern.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <video/newport.h>
+
+#include <linux/linux_logo.h>
+#include <linux/font.h>
+
+
+extern struct font_desc font_vga_8x16;
+extern unsigned long sgi_gfxaddr;
+
+#define FONT_DATA ((unsigned char *)font_vga_8x16.data)
+
+/* borrowed from fbcon.c */
+#define REFCOUNT(fd)	(((int *)(fd))[-1])
+#define FNTSIZE(fd)	(((int *)(fd))[-2])
+#define FNTCHARCNT(fd)	(((int *)(fd))[-3])
+#define FONT_EXTRA_WORDS 3
+
+static unsigned char *font_data[MAX_NR_CONSOLES];
+
+static struct newport_regs *npregs;
+
+static int logo_active;
+static int topscan;
+static int xcurs_correction = 29;
+static int newport_xsize;
+static int newport_ysize;
+
+static int newport_set_def_font(int unit, struct console_font *op);
+
+#define BMASK(c) (c << 24)
+
+#define RENDER(regs, cp) do { \
+(regs)->go.zpattern = BMASK((cp)[0x0]); (regs)->go.zpattern = BMASK((cp)[0x1]); \
+(regs)->go.zpattern = BMASK((cp)[0x2]); (regs)->go.zpattern = BMASK((cp)[0x3]); \
+(regs)->go.zpattern = BMASK((cp)[0x4]); (regs)->go.zpattern = BMASK((cp)[0x5]); \
+(regs)->go.zpattern = BMASK((cp)[0x6]); (regs)->go.zpattern = BMASK((cp)[0x7]); \
+(regs)->go.zpattern = BMASK((cp)[0x8]); (regs)->go.zpattern = BMASK((cp)[0x9]); \
+(regs)->go.zpattern = BMASK((cp)[0xa]); (regs)->go.zpattern = BMASK((cp)[0xb]); \
+(regs)->go.zpattern = BMASK((cp)[0xc]); (regs)->go.zpattern = BMASK((cp)[0xd]); \
+(regs)->go.zpattern = BMASK((cp)[0xe]); (regs)->go.zpattern = BMASK((cp)[0xf]); \
+} while(0)
+
+#define TESTVAL 0xdeadbeef
+#define XSTI_TO_FXSTART(val) (((val) & 0xffff) << 11)
+
+static inline void newport_render_background(int xstart, int ystart,
+					     int xend, int yend, int ci)
+{
+	newport_wait(npregs);
+	npregs->set.wrmask = 0xffffffff;
+	npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+				 NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX
+				 | NPORT_DMODE0_STOPY);
+	npregs->set.colori = ci;
+	npregs->set.xystarti =
+	    (xstart << 16) | ((ystart + topscan) & 0x3ff);
+	npregs->go.xyendi =
+	    ((xend + 7) << 16) | ((yend + topscan + 15) & 0x3ff);
+}
+
+static inline void newport_init_cmap(void)
+{
+	unsigned short i;
+
+	for (i = 0; i < 16; i++) {
+		newport_bfwait(npregs);
+		newport_cmap_setaddr(npregs, color_table[i]);
+		newport_cmap_setrgb(npregs,
+				    default_red[i],
+				    default_grn[i], default_blu[i]);
+	}
+}
+
+static void newport_show_logo(void)
+{
+#ifdef CONFIG_LOGO_SGI_CLUT224
+	const struct linux_logo *logo = fb_find_logo(8);
+	const unsigned char *clut = logo->clut;
+	const unsigned char *data = logo->data;
+	unsigned long i;
+
+	for (i = 0; i < logo->clutsize; i++) {
+		newport_bfwait(npregs);
+		newport_cmap_setaddr(npregs, i + 0x20);
+		newport_cmap_setrgb(npregs, clut[0], clut[1], clut[2]);
+		clut += 3;
+	}
+
+	newport_wait(npregs);
+	npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+				 NPORT_DMODE0_CHOST);
+
+	npregs->set.xystarti = ((newport_xsize - logo->width) << 16) | (0);
+	npregs->set.xyendi = ((newport_xsize - 1) << 16);
+	newport_wait(npregs);
+
+	for (i = 0; i < logo->width*logo->height; i++)
+		npregs->go.hostrw0 = *data++ << 24;
+#endif /* CONFIG_LOGO_SGI_CLUT224 */
+}
+
+static inline void newport_clear_screen(int xstart, int ystart, int xend,
+					int yend, int ci)
+{
+	if (logo_active)
+		return;
+
+	newport_wait(npregs);
+	npregs->set.wrmask = 0xffffffff;
+	npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+				 NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX
+				 | NPORT_DMODE0_STOPY);
+	npregs->set.colori = ci;
+	npregs->set.xystarti = (xstart << 16) | ystart;
+	npregs->go.xyendi = (xend << 16) | yend;
+}
+
+static inline void newport_clear_lines(int ystart, int yend, int ci)
+{
+	ystart = ((ystart << 4) + topscan) & 0x3ff;
+	yend = ((yend << 4) + topscan + 15) & 0x3ff;
+	newport_clear_screen(0, ystart, 1280 + 63, yend, ci);
+}
+
+void newport_reset(void)
+{
+	unsigned short treg;
+	int i;
+
+	newport_wait(npregs);
+	treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
+	newport_vc2_set(npregs, VC2_IREG_CONTROL,
+			(treg | VC2_CTRL_EVIDEO));
+
+	treg = newport_vc2_get(npregs, VC2_IREG_CENTRY);
+	newport_vc2_set(npregs, VC2_IREG_RADDR, treg);
+	npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM |
+			       NPORT_DMODE_W2 | VC2_PROTOCOL);
+	for (i = 0; i < 128; i++) {
+		newport_bfwait(npregs);
+		if (i == 92 || i == 94)
+			npregs->set.dcbdata0.byshort.s1 = 0xff00;
+		else
+			npregs->set.dcbdata0.byshort.s1 = 0x0000;
+	}
+
+	newport_init_cmap();
+
+	/* turn off popup plane */
+	npregs->set.dcbmode = (DCB_XMAP0 | R_DCB_XMAP9_PROTOCOL |
+			       XM9_CRS_CONFIG | NPORT_DMODE_W1);
+	npregs->set.dcbdata0.bybytes.b3 &= ~XM9_PUPMODE;
+	npregs->set.dcbmode = (DCB_XMAP1 | R_DCB_XMAP9_PROTOCOL |
+			       XM9_CRS_CONFIG | NPORT_DMODE_W1);
+	npregs->set.dcbdata0.bybytes.b3 &= ~XM9_PUPMODE;
+
+	topscan = 0;
+	npregs->cset.topscan = 0x3ff;
+	npregs->cset.xywin = (4096 << 16) | 4096;
+
+	/* Clear the screen. */
+	newport_clear_screen(0, 0, 1280 + 63, 1024, 0);
+}
+
+/*
+ * calculate the actual screen size by reading
+ * the video timing out of the VC2
+ */
+void newport_get_screensize(void)
+{
+	int i, cols;
+	unsigned short ventry, treg;
+	unsigned short linetable[128];	/* should be enough */
+
+	ventry = newport_vc2_get(npregs, VC2_IREG_VENTRY);
+	newport_vc2_set(npregs, VC2_IREG_RADDR, ventry);
+	npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM |
+			       NPORT_DMODE_W2 | VC2_PROTOCOL);
+	for (i = 0; i < 128; i++) {
+		newport_bfwait(npregs);
+		linetable[i] = npregs->set.dcbdata0.byshort.s1;
+	}
+
+	newport_xsize = newport_ysize = 0;
+	for (i = 0; linetable[i + 1] && (i < sizeof(linetable)); i += 2) {
+		cols = 0;
+		newport_vc2_set(npregs, VC2_IREG_RADDR, linetable[i]);
+		npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM |
+				       NPORT_DMODE_W2 | VC2_PROTOCOL);
+		do {
+			newport_bfwait(npregs);
+			treg = npregs->set.dcbdata0.byshort.s1;
+			if ((treg & 1) == 0)
+				cols += (treg >> 7) & 0xfe;
+			if ((treg & 0x80) == 0) {
+				newport_bfwait(npregs);
+				treg = npregs->set.dcbdata0.byshort.s1;
+			}
+		} while ((treg & 0x8000) == 0);
+		if (cols) {
+			if (cols > newport_xsize)
+				newport_xsize = cols;
+			newport_ysize += linetable[i + 1];
+		}
+	}
+	printk("NG1: Screensize %dx%d\n", newport_xsize, newport_ysize);
+}
+
+static void newport_get_revisions(void)
+{
+	unsigned int tmp;
+	unsigned int board_rev;
+	unsigned int rex3_rev;
+	unsigned int vc2_rev;
+	unsigned int cmap_rev;
+	unsigned int xmap9_rev;
+	unsigned int bt445_rev;
+	unsigned int bitplanes;
+
+	rex3_rev = npregs->cset.status & NPORT_STAT_VERS;
+
+	npregs->set.dcbmode = (DCB_CMAP0 | NCMAP_PROTOCOL |
+			       NCMAP_REGADDR_RREG | NPORT_DMODE_W1);
+	tmp = npregs->set.dcbdata0.bybytes.b3;
+	cmap_rev = tmp & 7;
+	board_rev = (tmp >> 4) & 7;
+	bitplanes = ((board_rev > 1) && (tmp & 0x80)) ? 8 : 24;
+
+	npregs->set.dcbmode = (DCB_CMAP1 | NCMAP_PROTOCOL |
+			       NCMAP_REGADDR_RREG | NPORT_DMODE_W1);
+	tmp = npregs->set.dcbdata0.bybytes.b3;
+	if ((tmp & 7) < cmap_rev)
+		cmap_rev = (tmp & 7);
+
+	vc2_rev = (newport_vc2_get(npregs, VC2_IREG_CONFIG) >> 5) & 7;
+
+	npregs->set.dcbmode = (DCB_XMAP0 | R_DCB_XMAP9_PROTOCOL |
+			       XM9_CRS_REVISION | NPORT_DMODE_W1);
+	xmap9_rev = npregs->set.dcbdata0.bybytes.b3 & 7;
+
+	npregs->set.dcbmode = (DCB_BT445 | BT445_PROTOCOL |
+			       BT445_CSR_ADDR_REG | NPORT_DMODE_W1);
+	npregs->set.dcbdata0.bybytes.b3 = BT445_REVISION_REG;
+	npregs->set.dcbmode = (DCB_BT445 | BT445_PROTOCOL |
+			       BT445_CSR_REVISION | NPORT_DMODE_W1);
+	bt445_rev = (npregs->set.dcbdata0.bybytes.b3 >> 4) - 0x0a;
+
+#define L(a)     (char)('A'+(a))
+	printk
+	    ("NG1: Revision %d, %d bitplanes, REX3 revision %c, VC2 revision %c, xmap9 revision %c, cmap revision %c, bt445 revision %c\n",
+	     board_rev, bitplanes, L(rex3_rev), L(vc2_rev), L(xmap9_rev),
+	     L(cmap_rev ? (cmap_rev + 1) : 0), L(bt445_rev));
+#undef L
+
+	if (board_rev == 3)	/* I don't know all affected revisions */
+		xcurs_correction = 21;
+}
+
+/* Can't be __init, take_over_console may call it later */
+static const char *newport_startup(void)
+{
+	int i;
+
+	if (!sgi_gfxaddr)
+		return NULL;
+	npregs = (struct newport_regs *)	/* ioremap cannot fail */
+		 ioremap(sgi_gfxaddr, sizeof(struct newport_regs));
+	npregs->cset.config = NPORT_CFG_GD0;
+
+	if (newport_wait(npregs))
+		goto out_unmap;
+
+	npregs->set.xstarti = TESTVAL;
+	if (npregs->set._xstart.word != XSTI_TO_FXSTART(TESTVAL))
+		goto out_unmap;
+
+	for (i = 0; i < MAX_NR_CONSOLES; i++)
+		font_data[i] = FONT_DATA;
+
+	newport_reset();
+	newport_get_revisions();
+	newport_get_screensize();
+
+	return "SGI Newport";
+
+out_unmap:
+	iounmap((void *)npregs);
+	return NULL;
+}
+
+static void newport_init(struct vc_data *vc, int init)
+{
+	vc->vc_cols = newport_xsize / 8;
+	vc->vc_rows = newport_ysize / 16;
+	vc->vc_can_do_color = 1;
+}
+
+static void newport_deinit(struct vc_data *c)
+{
+	int i;
+
+	/* free memory used by user font */
+	for (i = 0; i < MAX_NR_CONSOLES; i++)
+		newport_set_def_font(i, NULL);
+}
+
+static void newport_clear(struct vc_data *vc, int sy, int sx, int height,
+			  int width)
+{
+	int xend = ((sx + width) << 3) - 1;
+	int ystart = ((sy << 4) + topscan) & 0x3ff;
+	int yend = (((sy + height) << 4) + topscan - 1) & 0x3ff;
+
+	if (logo_active)
+		return;
+
+	if (ystart < yend) {
+		newport_clear_screen(sx << 3, ystart, xend, yend,
+				     (vc->vc_color & 0xf0) >> 4);
+	} else {
+		newport_clear_screen(sx << 3, ystart, xend, 1023,
+				     (vc->vc_color & 0xf0) >> 4);
+		newport_clear_screen(sx << 3, 0, xend, yend,
+				     (vc->vc_color & 0xf0) >> 4);
+	}
+}
+
+static void newport_putc(struct vc_data *vc, int charattr, int ypos,
+			 int xpos)
+{
+	unsigned char *p;
+
+	p = &font_data[vc->vc_num][(charattr & 0xff) << 4];
+	charattr = (charattr >> 8) & 0xff;
+	xpos <<= 3;
+	ypos <<= 4;
+
+	newport_render_background(xpos, ypos, xpos, ypos,
+				  (charattr & 0xf0) >> 4);
+
+	/* Set the color and drawing mode. */
+	newport_wait(npregs);
+	npregs->set.colori = charattr & 0xf;
+	npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+				 NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB |
+				 NPORT_DMODE0_L32);
+
+	/* Set coordinates for bitmap operation. */
+	npregs->set.xystarti = (xpos << 16) | ((ypos + topscan) & 0x3ff);
+	npregs->set.xyendi = ((xpos + 7) << 16);
+	newport_wait(npregs);
+
+	/* Go, baby, go... */
+	RENDER(npregs, p);
+}
+
+static void newport_putcs(struct vc_data *vc, const unsigned short *s,
+			  int count, int ypos, int xpos)
+{
+	int i;
+	int charattr;
+	unsigned char *p;
+
+	charattr = (scr_readw(s) >> 8) & 0xff;
+
+	xpos <<= 3;
+	ypos <<= 4;
+
+	if (!logo_active)
+		/* Clear the area behing the string */
+		newport_render_background(xpos, ypos,
+					  xpos + ((count - 1) << 3), ypos,
+					  (charattr & 0xf0) >> 4);
+
+	newport_wait(npregs);
+
+	/* Set the color and drawing mode. */
+	npregs->set.colori = charattr & 0xf;
+	npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+				 NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB |
+				 NPORT_DMODE0_L32);
+
+	for (i = 0; i < count; i++, xpos += 8) {
+		p = &font_data[vc->vc_num][(scr_readw(s++) & 0xff) << 4];
+
+		newport_wait(npregs);
+
+		/* Set coordinates for bitmap operation. */
+		npregs->set.xystarti =
+		    (xpos << 16) | ((ypos + topscan) & 0x3ff);
+		npregs->set.xyendi = ((xpos + 7) << 16);
+
+		/* Go, baby, go... */
+		RENDER(npregs, p);
+	}
+}
+
+static void newport_cursor(struct vc_data *vc, int mode)
+{
+	unsigned short treg;
+	int xcurs, ycurs;
+
+	switch (mode) {
+	case CM_ERASE:
+		treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
+		newport_vc2_set(npregs, VC2_IREG_CONTROL,
+				(treg & ~(VC2_CTRL_ECDISP)));
+		break;
+
+	case CM_MOVE:
+	case CM_DRAW:
+		treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
+		newport_vc2_set(npregs, VC2_IREG_CONTROL,
+				(treg | VC2_CTRL_ECDISP));
+		xcurs = (vc->vc_pos - vc->vc_visible_origin) / 2;
+		ycurs = ((xcurs / vc->vc_cols) << 4) + 31;
+		xcurs = ((xcurs % vc->vc_cols) << 3) + xcurs_correction;
+		newport_vc2_set(npregs, VC2_IREG_CURSX, xcurs);
+		newport_vc2_set(npregs, VC2_IREG_CURSY, ycurs);
+	}
+}
+
+static int newport_switch(struct vc_data *vc)
+{
+	static int logo_drawn = 0;
+
+	topscan = 0;
+	npregs->cset.topscan = 0x3ff;
+
+	if (!logo_drawn) {
+		newport_show_logo();
+		logo_drawn = 1;
+		logo_active = 1;
+	}
+
+	return 1;
+}
+
+static int newport_blank(struct vc_data *c, int blank, int mode_switch)
+{
+	unsigned short treg;
+
+	if (blank == 0) {
+		/* unblank console */
+		treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
+		newport_vc2_set(npregs, VC2_IREG_CONTROL,
+				(treg | VC2_CTRL_EDISP));
+	} else {
+		/* blank console */
+		treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
+		newport_vc2_set(npregs, VC2_IREG_CONTROL,
+				(treg & ~(VC2_CTRL_EDISP)));
+	}
+	return 1;
+}
+
+static int newport_set_font(int unit, struct console_font *op)
+{
+	int w = op->width;
+	int h = op->height;
+	int size = h * op->charcount;
+	int i;
+	unsigned char *new_data, *data = op->data, *p;
+
+	/* ladis: when I grow up, there will be a day... and more sizes will
+	 * be supported ;-) */
+	if ((w != 8) || (h != 16)
+	    || (op->charcount != 256 && op->charcount != 512))
+		return -EINVAL;
+
+	if (!(new_data = kmalloc(FONT_EXTRA_WORDS * sizeof(int) + size,
+	     GFP_USER))) return -ENOMEM;
+
+	new_data += FONT_EXTRA_WORDS * sizeof(int);
+	FNTSIZE(new_data) = size;
+	FNTCHARCNT(new_data) = op->charcount;
+	REFCOUNT(new_data) = 0;	/* usage counter */
+
+	p = new_data;
+	for (i = 0; i < op->charcount; i++) {
+		memcpy(p, data, h);
+		data += 32;
+		p += h;
+	}
+
+	/* check if font is already used by other console */
+	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+		if (font_data[i] != FONT_DATA
+		    && FNTSIZE(font_data[i]) == size
+		    && !memcmp(font_data[i], new_data, size)) {
+			kfree(new_data - FONT_EXTRA_WORDS * sizeof(int));
+			/* current font is the same as the new one */
+			if (i == unit)
+				return 0;
+			new_data = font_data[i];
+			break;
+		}
+	}
+	/* old font is user font */
+	if (font_data[unit] != FONT_DATA) {
+		if (--REFCOUNT(font_data[unit]) == 0)
+			kfree(font_data[unit] -
+			      FONT_EXTRA_WORDS * sizeof(int));
+	}
+	REFCOUNT(new_data)++;
+	font_data[unit] = new_data;
+
+	return 0;
+}
+
+static int newport_set_def_font(int unit, struct console_font *op)
+{
+	if (font_data[unit] != FONT_DATA) {
+		if (--REFCOUNT(font_data[unit]) == 0)
+			kfree(font_data[unit] -
+			      FONT_EXTRA_WORDS * sizeof(int));
+		font_data[unit] = FONT_DATA;
+	}
+
+	return 0;
+}
+
+static int newport_font_default(struct vc_data *vc, struct console_font *op, char *name)
+{
+	return newport_set_def_font(vc->vc_num, op);
+}
+
+static int newport_font_set(struct vc_data *vc, struct console_font *font, unsigned flags)
+{
+	return newport_set_font(vc->vc_num, font);
+}
+
+static int newport_set_palette(struct vc_data *vc, unsigned char *table)
+{
+	return -EINVAL;
+}
+
+static int newport_scrolldelta(struct vc_data *vc, int lines)
+{
+	/* there is (nearly) no off-screen memory, so we can't scroll back */
+	return 0;
+}
+
+static int newport_scroll(struct vc_data *vc, int t, int b, int dir,
+			  int lines)
+{
+	int count, x, y;
+	unsigned short *s, *d;
+	unsigned short chattr;
+
+	logo_active = 0;	/* it's time to disable the logo now.. */
+
+	if (t == 0 && b == vc->vc_rows) {
+		if (dir == SM_UP) {
+			topscan = (topscan + (lines << 4)) & 0x3ff;
+			newport_clear_lines(vc->vc_rows - lines,
+					    vc->vc_rows - 1,
+					    (vc->vc_color & 0xf0) >> 4);
+		} else {
+			topscan = (topscan + (-lines << 4)) & 0x3ff;
+			newport_clear_lines(0, lines - 1,
+					    (vc->vc_color & 0xf0) >> 4);
+		}
+		npregs->cset.topscan = (topscan - 1) & 0x3ff;
+		return 0;
+	}
+
+	count = (b - t - lines) * vc->vc_cols;
+	if (dir == SM_UP) {
+		x = 0;
+		y = t;
+		s = (unsigned short *) (vc->vc_origin +
+					vc->vc_size_row * (t + lines));
+		d = (unsigned short *) (vc->vc_origin +
+					vc->vc_size_row * t);
+		while (count--) {
+			chattr = scr_readw(s++);
+			if (chattr != scr_readw(d)) {
+				newport_putc(vc, chattr, y, x);
+				scr_writew(chattr, d);
+			}
+			d++;
+			if (++x == vc->vc_cols) {
+				x = 0;
+				y++;
+			}
+		}
+		d = (unsigned short *) (vc->vc_origin +
+					vc->vc_size_row * (b - lines));
+		x = 0;
+		y = b - lines;
+		for (count = 0; count < (lines * vc->vc_cols); count++) {
+			if (scr_readw(d) != vc->vc_video_erase_char) {
+				newport_putc(vc, vc->vc_video_erase_char,
+					     y, x);
+				scr_writew(vc->vc_video_erase_char, d);
+			}
+			d++;
+			if (++x == vc->vc_cols) {
+				x = 0;
+				y++;
+			}
+		}
+	} else {
+		x = vc->vc_cols - 1;
+		y = b - 1;
+		s = (unsigned short *) (vc->vc_origin +
+					vc->vc_size_row * (b - lines) - 2);
+		d = (unsigned short *) (vc->vc_origin +
+					vc->vc_size_row * b - 2);
+		while (count--) {
+			chattr = scr_readw(s--);
+			if (chattr != scr_readw(d)) {
+				newport_putc(vc, chattr, y, x);
+				scr_writew(chattr, d);
+			}
+			d--;
+			if (x-- == 0) {
+				x = vc->vc_cols - 1;
+				y--;
+			}
+		}
+		d = (unsigned short *) (vc->vc_origin +
+					vc->vc_size_row * t);
+		x = 0;
+		y = t;
+		for (count = 0; count < (lines * vc->vc_cols); count++) {
+			if (scr_readw(d) != vc->vc_video_erase_char) {
+				newport_putc(vc, vc->vc_video_erase_char,
+					     y, x);
+				scr_writew(vc->vc_video_erase_char, d);
+			}
+			d++;
+			if (++x == vc->vc_cols) {
+				x = 0;
+				y++;
+			}
+		}
+	}
+	return 1;
+}
+
+static void newport_bmove(struct vc_data *vc, int sy, int sx, int dy,
+			  int dx, int h, int w)
+{
+	short xs, ys, xe, ye, xoffs, yoffs, tmp;
+
+	xs = sx << 3;
+	xe = ((sx + w) << 3) - 1;
+	/*
+	 * as bmove is only used to move stuff around in the same line
+	 * (h == 1), we don't care about wrap arounds caused by topscan != 0
+	 */
+	ys = ((sy << 4) + topscan) & 0x3ff;
+	ye = (((sy + h) << 4) - 1 + topscan) & 0x3ff;
+	xoffs = (dx - sx) << 3;
+	yoffs = (dy - sy) << 4;
+	if (xoffs > 0) {
+		/* move to the right, exchange starting points */
+		tmp = xe;
+		xe = xs;
+		xs = tmp;
+	}
+	newport_wait(npregs);
+	npregs->set.drawmode0 = (NPORT_DMODE0_S2S | NPORT_DMODE0_BLOCK |
+				 NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX
+				 | NPORT_DMODE0_STOPY);
+	npregs->set.xystarti = (xs << 16) | ys;
+	npregs->set.xyendi = (xe << 16) | ye;
+	npregs->go.xymove = (xoffs << 16) | yoffs;
+}
+
+static int newport_dummy(struct vc_data *c)
+{
+	return 0;
+}
+
+#define DUMMY (void *) newport_dummy
+
+const struct consw newport_con = {
+	.owner		  = THIS_MODULE,
+	.con_startup	  = newport_startup,
+	.con_init	  = newport_init,
+	.con_deinit	  = newport_deinit,
+	.con_clear	  = newport_clear,
+	.con_putc	  = newport_putc,
+	.con_putcs	  = newport_putcs,
+	.con_cursor	  = newport_cursor,
+	.con_scroll	  = newport_scroll,
+	.con_bmove 	  = newport_bmove,
+	.con_switch	  = newport_switch,
+	.con_blank	  = newport_blank,
+	.con_font_set	  = newport_font_set,
+	.con_font_default = newport_font_default,
+	.con_set_palette  = newport_set_palette,
+	.con_scrolldelta  = newport_scrolldelta,
+	.con_set_origin	  = DUMMY,
+	.con_save_screen  = DUMMY
+};
+
+#ifdef MODULE
+static int __init newport_console_init(void)
+{
+	return take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1);
+}
+
+static void __exit newport_console_exit(void)
+{
+	give_up_console(&newport_con);
+	iounmap((void *)npregs);
+}
+
+module_init(newport_console_init);
+module_exit(newport_console_exit);
+#endif
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/console/prom.uni b/drivers/video/console/prom.uni
new file mode 100644
index 0000000..58f9c04
--- /dev/null
+++ b/drivers/video/console/prom.uni
@@ -0,0 +1,11 @@
+#
+# Unicode mapping table for font in Sun PROM
+# 
+#
+0x20-0x7e	idem
+0xa0-0xff	idem
+#
+0x7c		U+2502
+0x2d		U+2500
+0x2b		U+250c U+2510 U+2514 U+2518 U+251c U+2524 U+252c U+2534 U+253c
+0xa4		U+fffd
diff --git a/drivers/video/console/promcon.c b/drivers/video/console/promcon.c
new file mode 100644
index 0000000..04f42fc
--- /dev/null
+++ b/drivers/video/console/promcon.c
@@ -0,0 +1,599 @@
+/* $Id: promcon.c,v 1.17 2000/07/26 23:02:52 davem Exp $
+ * Console driver utilizing PROM sun terminal emulation
+ *
+ * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
+ * Copyright (C) 1998  Jakub Jelinek  (jj@ultra.linux.cz)
+ */
+
+#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/delay.h>
+#include <linux/console.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/kd.h>
+
+#include <asm/oplib.h>
+#include <asm/uaccess.h>
+
+static short pw = 80 - 1, ph = 34 - 1;
+static short px, py;
+static unsigned long promcon_uni_pagedir[2];
+
+extern u8 promfont_unicount[];
+extern u16 promfont_unitable[];
+
+#define PROMCON_COLOR 0
+
+#if PROMCON_COLOR
+#define inverted(s)	((((s) & 0x7700) == 0x0700) ? 0 : 1)
+#else
+#define inverted(s)	(((s) & 0x0800) ? 1 : 0)
+#endif
+
+static __inline__ void
+promcon_puts(char *buf, int cnt)
+{
+	prom_printf("%*.*s", cnt, cnt, buf);
+}
+
+static int
+promcon_start(struct vc_data *conp, char *b)
+{
+	unsigned short *s = (unsigned short *)
+			(conp->vc_origin + py * conp->vc_size_row + (px << 1));
+	u16 cs;
+
+	cs = scr_readw(s);
+	if (px == pw) {
+		unsigned short *t = s - 1;
+		u16 ct = scr_readw(t);
+
+		if (inverted(cs) && inverted(ct))
+			return sprintf(b, "\b\033[7m%c\b\033[@%c\033[m", cs,
+				       ct);
+		else if (inverted(cs))
+			return sprintf(b, "\b\033[7m%c\033[m\b\033[@%c", cs,
+				       ct);
+		else if (inverted(ct))
+			return sprintf(b, "\b%c\b\033[@\033[7m%c\033[m", cs,
+				       ct);
+		else
+			return sprintf(b, "\b%c\b\033[@%c", cs, ct);
+	}
+
+	if (inverted(cs))
+		return sprintf(b, "\033[7m%c\033[m\b", cs);
+	else
+		return sprintf(b, "%c\b", cs);
+}
+
+static int
+promcon_end(struct vc_data *conp, char *b)
+{
+	unsigned short *s = (unsigned short *)
+			(conp->vc_origin + py * conp->vc_size_row + (px << 1));
+	char *p = b;
+	u16 cs;
+
+	b += sprintf(b, "\033[%d;%dH", py + 1, px + 1);
+
+	cs = scr_readw(s);
+	if (px == pw) {
+		unsigned short *t = s - 1;
+		u16 ct = scr_readw(t);
+
+		if (inverted(cs) && inverted(ct))
+			b += sprintf(b, "\b%c\b\033[@\033[7m%c\033[m", cs, ct);
+		else if (inverted(cs))
+			b += sprintf(b, "\b%c\b\033[@%c", cs, ct);
+		else if (inverted(ct))
+			b += sprintf(b, "\b\033[7m%c\b\033[@%c\033[m", cs, ct);
+		else
+			b += sprintf(b, "\b\033[7m%c\033[m\b\033[@%c", cs, ct);
+		return b - p;
+	}
+
+	if (inverted(cs))
+		b += sprintf(b, "%c\b", cs);
+	else
+		b += sprintf(b, "\033[7m%c\033[m\b", cs);
+	return b - p;
+}
+
+const char __init *promcon_startup(void)
+{
+	const char *display_desc = "PROM";
+	int node;
+	char buf[40];
+	
+	node = prom_getchild(prom_root_node);
+	node = prom_searchsiblings(node, "options");
+	if (prom_getproperty(node,  "screen-#columns", buf, 40) != -1) {
+		pw = simple_strtoul(buf, NULL, 0);
+		if (pw < 10 || pw > 256)
+			pw = 80;
+		pw--;
+	}
+	if (prom_getproperty(node,  "screen-#rows", buf, 40) != -1) {
+		ph = simple_strtoul(buf, NULL, 0);
+		if (ph < 10 || ph > 256)
+			ph = 34;
+		ph--;
+	}
+	promcon_puts("\033[H\033[J", 6);
+	return display_desc;
+}
+
+static void __init 
+promcon_init_unimap(struct vc_data *conp)
+{
+	mm_segment_t old_fs = get_fs();
+	struct unipair *p, *p1;
+	u16 *q;
+	int i, j, k;
+	
+	p = kmalloc(256*sizeof(struct unipair), GFP_KERNEL);
+	if (!p) return;
+	
+	q = promfont_unitable;
+	p1 = p;
+	k = 0;
+	for (i = 0; i < 256; i++)
+		for (j = promfont_unicount[i]; j; j--) {
+			p1->unicode = *q++;
+			p1->fontpos = i;
+			p1++;
+			k++;
+		}
+	set_fs(KERNEL_DS);
+	con_clear_unimap(conp, NULL);
+	con_set_unimap(conp, k, p);
+	con_protect_unimap(conp, 1);
+	set_fs(old_fs);
+	kfree(p);
+}
+
+static void
+promcon_init(struct vc_data *conp, int init)
+{
+	unsigned long p;
+	
+	conp->vc_can_do_color = PROMCON_COLOR;
+	if (init) {
+		conp->vc_cols = pw + 1;
+		conp->vc_rows = ph + 1;
+	}
+	p = *conp->vc_uni_pagedir_loc;
+	if (conp->vc_uni_pagedir_loc == &conp->vc_uni_pagedir ||
+	    !--conp->vc_uni_pagedir_loc[1])
+		con_free_unimap(conp);
+	conp->vc_uni_pagedir_loc = promcon_uni_pagedir;
+	promcon_uni_pagedir[1]++;
+	if (!promcon_uni_pagedir[0] && p) {
+		promcon_init_unimap(conp);
+	}
+	if (!init) {
+		if (conp->vc_cols != pw + 1 || conp->vc_rows != ph + 1)
+			vc_resize(conp, pw + 1, ph + 1);
+	}
+}
+
+static void
+promcon_deinit(struct vc_data *conp)
+{
+	/* When closing the last console, reset video origin */
+	if (!--promcon_uni_pagedir[1])
+		con_free_unimap(conp);
+	conp->vc_uni_pagedir_loc = &conp->vc_uni_pagedir;
+	con_set_default_unimap(conp);
+}
+
+static int
+promcon_switch(struct vc_data *conp)
+{
+	return 1;
+}
+
+static unsigned short *
+promcon_repaint_line(unsigned short *s, unsigned char *buf, unsigned char **bp)
+{
+	int cnt = pw + 1;
+	int attr = -1;
+	unsigned char *b = *bp;
+
+	while (cnt--) {
+		u16 c = scr_readw(s);
+		if (attr != inverted(c)) {
+			attr = inverted(c);
+			if (attr) {
+				strcpy (b, "\033[7m");
+				b += 4;
+			} else {
+				strcpy (b, "\033[m");
+				b += 3;
+			}
+		}
+		*b++ = c;
+		s++;
+		if (b - buf >= 224) {
+			promcon_puts(buf, b - buf);
+			b = buf;
+		}
+	}
+	*bp = b;
+	return s;
+}
+
+static void
+promcon_putcs(struct vc_data *conp, const unsigned short *s,
+	      int count, int y, int x)
+{
+	unsigned char buf[256], *b = buf;
+	unsigned short attr = scr_readw(s);
+	unsigned char save;
+	int i, last = 0;
+
+	if (console_blanked)
+		return;
+	
+	if (count <= 0)
+		return;
+
+	b += promcon_start(conp, b);
+
+	if (x + count >= pw + 1) {
+		if (count == 1) {
+			x -= 1;
+			save = scr_readw((unsigned short *)(conp->vc_origin
+						   + y * conp->vc_size_row
+						   + (x << 1)));
+
+			if (px != x || py != y) {
+				b += sprintf(b, "\033[%d;%dH", y + 1, x + 1);
+				px = x;
+				py = y;
+			}
+
+			if (inverted(attr))
+				b += sprintf(b, "\033[7m%c\033[m", scr_readw(s++));
+			else
+				b += sprintf(b, "%c", scr_readw(s++));
+
+			strcpy(b, "\b\033[@");
+			b += 4;
+
+			if (inverted(save))
+				b += sprintf(b, "\033[7m%c\033[m", save);
+			else
+				b += sprintf(b, "%c", save);
+
+			px++;
+
+			b += promcon_end(conp, b);
+			promcon_puts(buf, b - buf);
+			return;
+		} else {
+			last = 1;
+			count = pw - x - 1;
+		}
+	}
+
+	if (inverted(attr)) {
+		strcpy(b, "\033[7m");
+		b += 4;
+	}
+
+	if (px != x || py != y) {
+		b += sprintf(b, "\033[%d;%dH", y + 1, x + 1);
+		px = x;
+		py = y;
+	}
+
+	for (i = 0; i < count; i++) {
+		if (b - buf >= 224) {
+			promcon_puts(buf, b - buf);
+			b = buf;
+		}
+		*b++ = scr_readw(s++);
+	}
+
+	px += count;
+
+	if (last) {
+		save = scr_readw(s++);
+		b += sprintf(b, "%c\b\033[@%c", scr_readw(s++), save);
+		px++;
+	}
+
+	if (inverted(attr)) {
+		strcpy(b, "\033[m");
+		b += 3;
+	}
+
+	b += promcon_end(conp, b);
+	promcon_puts(buf, b - buf);
+}
+
+static void
+promcon_putc(struct vc_data *conp, int c, int y, int x)
+{
+	unsigned short s;
+
+	if (console_blanked)
+		return;
+	
+	scr_writew(c, &s);
+	promcon_putcs(conp, &s, 1, y, x);
+}
+
+static void
+promcon_clear(struct vc_data *conp, int sy, int sx, int height, int width)
+{
+	unsigned char buf[256], *b = buf;
+	int i, j;
+
+	if (console_blanked)
+		return;
+	
+	b += promcon_start(conp, b);
+
+	if (!sx && width == pw + 1) {
+
+		if (!sy && height == ph + 1) {
+			strcpy(b, "\033[H\033[J");
+			b += 6;
+			b += promcon_end(conp, b);
+			promcon_puts(buf, b - buf);
+			return;
+		} else if (sy + height == ph + 1) {
+			b += sprintf(b, "\033[%dH\033[J", sy + 1);
+			b += promcon_end(conp, b);
+			promcon_puts(buf, b - buf);
+			return;
+		}
+
+		b += sprintf(b, "\033[%dH", sy + 1);
+		for (i = 1; i < height; i++) {
+			strcpy(b, "\033[K\n");
+			b += 4;
+		}
+
+		strcpy(b, "\033[K");
+		b += 3;
+
+		b += promcon_end(conp, b);
+		promcon_puts(buf, b - buf);
+		return;
+
+	} else if (sx + width == pw + 1) {
+
+		b += sprintf(b, "\033[%d;%dH", sy + 1, sx + 1);
+		for (i = 1; i < height; i++) {
+			strcpy(b, "\033[K\n");
+			b += 4;
+		}
+
+		strcpy(b, "\033[K");
+		b += 3;
+
+		b += promcon_end(conp, b);
+		promcon_puts(buf, b - buf);
+		return;
+	}
+
+	for (i = sy + 1; i <= sy + height; i++) {
+		b += sprintf(b, "\033[%d;%dH", i, sx + 1);
+		for (j = 0; j < width; j++)
+			*b++ = ' ';
+		if (b - buf + width >= 224) {
+			promcon_puts(buf, b - buf);
+			b = buf;
+		}
+	}
+
+	b += promcon_end(conp, b);
+	promcon_puts(buf, b - buf);
+}
+                        
+static void
+promcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
+	      int height, int width)
+{
+	char buf[256], *b = buf;
+
+	if (console_blanked)
+		return;
+	
+	b += promcon_start(conp, b);
+	if (sy == dy && height == 1) {
+		if (dx > sx && dx + width == conp->vc_cols)
+			b += sprintf(b, "\033[%d;%dH\033[%d@\033[%d;%dH",
+				     sy + 1, sx + 1, dx - sx, py + 1, px + 1);
+		else if (dx < sx && sx + width == conp->vc_cols)
+			b += sprintf(b, "\033[%d;%dH\033[%dP\033[%d;%dH",
+				     dy + 1, dx + 1, sx - dx, py + 1, px + 1);
+
+		b += promcon_end(conp, b);
+		promcon_puts(buf, b - buf);
+		return;
+	}
+
+	/*
+	 * FIXME: What to do here???
+	 * Current console.c should not call it like that ever.
+	 */
+	prom_printf("\033[7mFIXME: bmove not handled\033[m\n");
+}
+
+static void
+promcon_cursor(struct vc_data *conp, int mode)
+{
+	char buf[32], *b = buf;
+
+	switch (mode) {
+	case CM_ERASE:
+		break;
+
+	case CM_MOVE:
+	case CM_DRAW:
+		b += promcon_start(conp, b);
+		if (px != conp->vc_x || py != conp->vc_y) {
+			px = conp->vc_x;
+			py = conp->vc_y;
+			b += sprintf(b, "\033[%d;%dH", py + 1, px + 1);
+		}
+		promcon_puts(buf, b - buf);
+		break;
+	}
+}
+
+static int
+promcon_blank(struct vc_data *conp, int blank, int mode_switch)
+{
+	if (blank) {
+		promcon_puts("\033[H\033[J\033[7m \033[m\b", 15);
+		return 0;
+	} else {
+		/* Let console.c redraw */
+		return 1;
+	}
+}
+
+static int
+promcon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
+{
+	unsigned char buf[256], *p = buf;
+	unsigned short *s;
+	int i;
+
+	if (console_blanked)
+		return 0;
+	
+	p += promcon_start(conp, p);
+
+	switch (dir) {
+	case SM_UP:
+		if (b == ph + 1) {
+			p += sprintf(p, "\033[%dH\033[%dM", t + 1, count);
+			px = 0;
+			py = t;
+			p += promcon_end(conp, p);
+			promcon_puts(buf, p - buf);
+			break;
+		}
+
+		s = (unsigned short *)(conp->vc_origin
+				       + (t + count) * conp->vc_size_row);
+
+		p += sprintf(p, "\033[%dH", t + 1);
+
+		for (i = t; i < b - count; i++)
+			s = promcon_repaint_line(s, buf, &p);
+
+		for (; i < b - 1; i++) {
+			strcpy(p, "\033[K\n");
+			p += 4;
+			if (p - buf >= 224) {
+				promcon_puts(buf, p - buf);
+				p = buf;
+			}
+		}
+
+		strcpy(p, "\033[K");
+		p += 3;
+
+		p += promcon_end(conp, p);
+		promcon_puts(buf, p - buf);
+		break;
+
+	case SM_DOWN:
+		if (b == ph + 1) {
+			p += sprintf(p, "\033[%dH\033[%dL", t + 1, count);
+			px = 0;
+			py = t;
+			p += promcon_end(conp, p);
+			promcon_puts(buf, p - buf);
+			break;
+		}
+
+		s = (unsigned short *)(conp->vc_origin + t * conp->vc_size_row);
+
+		p += sprintf(p, "\033[%dH", t + 1);
+
+		for (i = t; i < t + count; i++) {
+			strcpy(p, "\033[K\n");
+			p += 4;
+			if (p - buf >= 224) {
+				promcon_puts(buf, p - buf);
+				p = buf;
+			}
+		}
+
+		for (; i < b; i++)
+			s = promcon_repaint_line(s, buf, &p);
+
+		p += promcon_end(conp, p);
+		promcon_puts(buf, p - buf);
+		break;
+	}
+
+	return 0;
+}
+
+#if !(PROMCON_COLOR)
+static u8 promcon_build_attr(struct vc_data *conp, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse)
+{
+	return (_reverse) ? 0xf : 0x7;
+}
+#endif
+
+/*
+ *  The console 'switch' structure for the VGA based console
+ */
+
+static int promcon_dummy(void)
+{
+        return 0;
+}
+
+#define DUMMY (void *) promcon_dummy
+
+const struct consw prom_con = {
+	.owner =		THIS_MODULE,
+	.con_startup =		promcon_startup,
+	.con_init =		promcon_init,
+	.con_deinit =		promcon_deinit,
+	.con_clear =		promcon_clear,
+	.con_putc =		promcon_putc,
+	.con_putcs =		promcon_putcs,
+	.con_cursor =		promcon_cursor,
+	.con_scroll =		promcon_scroll,
+	.con_bmove =		promcon_bmove,
+	.con_switch =		promcon_switch,
+	.con_blank =		promcon_blank,
+	.con_set_palette =	DUMMY,
+	.con_scrolldelta =	DUMMY,
+#if !(PROMCON_COLOR)
+	.con_build_attr =	promcon_build_attr,
+#endif
+};
+
+void __init prom_con_init(void)
+{
+#ifdef CONFIG_DUMMY_CONSOLE
+	if (conswitchp == &dummy_con)
+		take_over_console(&prom_con, 0, MAX_NR_CONSOLES-1, 1);
+	else
+#endif
+	if (conswitchp == &prom_con)
+		promcon_init_unimap(vc_cons[fg_console].d);
+}
diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c
new file mode 100644
index 0000000..fd5940f
--- /dev/null
+++ b/drivers/video/console/sticon.c
@@ -0,0 +1,392 @@
+/*
+ *  linux/drivers/video/console/sticon.c - console driver using HP's STI firmware
+ *
+ *	Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ *	Copyright (C) 2002 Helge Deller <deller@gmx.de>
+ *
+ *  Based on linux/drivers/video/vgacon.c and linux/drivers/video/fbcon.c,
+ *  which were
+ *
+ *	Created 28 Sep 1997 by Geert Uytterhoeven
+ *	Rewritten by Martin Mares <mj@ucw.cz>, July 1998
+ *	Copyright (C) 1991, 1992  Linus Torvalds
+ *			    1995  Jay Estabrook
+ *	Copyright (C) 1995 Geert Uytterhoeven
+ *	Copyright (C) 1993 Bjoern Brauel
+ *			   Roman Hodek
+ *	Copyright (C) 1993 Hamish Macdonald
+ *			   Greg Harp
+ *	Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk]
+ *
+ *	      with work by William Rucklidge (wjr@cs.cornell.edu)
+ *			   Geert Uytterhoeven
+ *			   Jes Sorensen (jds@kom.auc.dk)
+ *			   Martin Apel
+ *	      with work by Guenther Kelleter
+ *			   Martin Schaller
+ *			   Andreas Schwab
+ *			   Emmanuel Marty (core@ggi-project.org)
+ *			   Jakub Jelinek (jj@ultra.linux.cz)
+ *			   Martin Mares <mj@ucw.cz>
+ *
+ *  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/init.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/errno.h>
+#include <linux/vt_kern.h>
+#include <linux/kd.h>
+#include <linux/selection.h>
+#include <linux/module.h>
+
+#include <asm/io.h>
+
+#include "../sticore.h"
+
+/* switching to graphics mode */
+#define BLANK 0
+static int vga_is_gfx;
+
+/* this is the sti_struct used for this console */
+static struct sti_struct *sticon_sti;
+
+/* Software scrollback */
+static unsigned long softback_buf, softback_curr;
+static unsigned long softback_in;
+static unsigned long /* softback_top, */ softback_end;
+static int softback_lines;
+
+/* software cursor */
+static int cursor_drawn;
+#define CURSOR_DRAW_DELAY		(1)
+#define DEFAULT_CURSOR_BLINK_RATE	(20)
+
+static int vbl_cursor_cnt;
+
+static inline void cursor_undrawn(void)
+{
+    vbl_cursor_cnt = 0;
+    cursor_drawn = 0;
+}
+
+static const char *__init sticon_startup(void)
+{
+    return "STI console";
+}
+
+static int sticon_set_palette(struct vc_data *c, unsigned char *table)
+{
+    return -EINVAL;
+}
+
+static void sticon_putc(struct vc_data *conp, int c, int ypos, int xpos)
+{
+    int redraw_cursor = 0;
+
+    if (vga_is_gfx || console_blanked)
+	    return;
+
+    if (conp->vc_mode != KD_TEXT)
+    	    return;
+#if 0
+    if ((p->cursor_x == xpos) && (p->cursor_y == ypos)) {
+	    cursor_undrawn();
+	    redraw_cursor = 1;
+    }
+#endif
+
+    sti_putc(sticon_sti, c, ypos, xpos);
+
+    if (redraw_cursor)
+	    vbl_cursor_cnt = CURSOR_DRAW_DELAY;
+}
+
+static void sticon_putcs(struct vc_data *conp, const unsigned short *s,
+			 int count, int ypos, int xpos)
+{
+    int redraw_cursor = 0;
+
+    if (vga_is_gfx || console_blanked)
+	    return;
+
+    if (conp->vc_mode != KD_TEXT)
+    	    return;
+
+#if 0
+    if ((p->cursor_y == ypos) && (xpos <= p->cursor_x) &&
+	(p->cursor_x < (xpos + count))) {
+	    cursor_undrawn();
+	    redraw_cursor = 1;
+    }
+#endif
+
+    while (count--) {
+	sti_putc(sticon_sti, scr_readw(s++), ypos, xpos++);
+    }
+
+    if (redraw_cursor)
+	    vbl_cursor_cnt = CURSOR_DRAW_DELAY;
+}
+
+static void sticon_cursor(struct vc_data *conp, int mode)
+{
+    unsigned short car1;
+
+    car1 = conp->vc_screenbuf[conp->vc_x + conp->vc_y * conp->vc_cols];
+    switch (mode) {
+    case CM_ERASE:
+	sti_putc(sticon_sti, car1, conp->vc_y, conp->vc_x);
+	break;
+    case CM_MOVE:
+    case CM_DRAW:
+	switch (conp->vc_cursor_type & 0x0f) {
+	case CUR_UNDERLINE:
+	case CUR_LOWER_THIRD:
+	case CUR_LOWER_HALF:
+	case CUR_TWO_THIRDS:
+	case CUR_BLOCK:
+	    sti_putc(sticon_sti, (car1 & 255) + (0 << 8) + (7 << 11),
+		     conp->vc_y, conp->vc_x);
+	    break;
+	}
+	break;
+    }
+}
+
+static int sticon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
+{
+    struct sti_struct *sti = sticon_sti;
+
+    if (vga_is_gfx)
+        return 0;
+
+    sticon_cursor(conp, CM_ERASE);
+
+    switch (dir) {
+    case SM_UP:
+	sti_bmove(sti, t + count, 0, t, 0, b - t - count, conp->vc_cols);
+	sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_video_erase_char);
+	break;
+
+    case SM_DOWN:
+	sti_bmove(sti, t, 0, t + count, 0, b - t - count, conp->vc_cols);
+	sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_video_erase_char);
+	break;
+    }
+
+    return 0;
+}
+
+static void sticon_bmove(struct vc_data *conp, int sy, int sx, 
+	int dy, int dx, int height, int width)
+{
+    if (!width || !height)
+	    return;
+#if 0
+    if (((sy <= p->cursor_y) && (p->cursor_y < sy+height) &&
+	(sx <= p->cursor_x) && (p->cursor_x < sx+width)) ||
+	((dy <= p->cursor_y) && (p->cursor_y < dy+height) &&
+	(dx <= p->cursor_x) && (p->cursor_x < dx+width)))
+		sticon_cursor(p, CM_ERASE /*|CM_SOFTBACK*/);
+#endif
+
+    sti_bmove(sticon_sti, sy, sx, dy, dx, height, width);
+}
+
+static void sticon_init(struct vc_data *c, int init)
+{
+    struct sti_struct *sti = sticon_sti;
+    int vc_cols, vc_rows;
+
+    sti_set(sti, 0, 0, sti_onscreen_y(sti), sti_onscreen_x(sti), 0);
+    vc_cols = sti_onscreen_x(sti) / sti->font_width;
+    vc_rows = sti_onscreen_y(sti) / sti->font_height;
+    c->vc_can_do_color = 1;
+    
+    if (init) {
+	c->vc_cols = vc_cols;
+	c->vc_rows = vc_rows;
+    } else {
+	/* vc_rows = (c->vc_rows > vc_rows) ? vc_rows : c->vc_rows; */
+	/* vc_cols = (c->vc_cols > vc_cols) ? vc_cols : c->vc_cols; */
+	vc_resize(c, vc_cols, vc_rows);
+/*	vc_resize_con(vc_rows, vc_cols, c->vc_num); */
+    }
+}
+
+static void sticon_deinit(struct vc_data *c)
+{
+}
+
+static void sticon_clear(struct vc_data *conp, int sy, int sx, int height,
+			 int width)
+{
+    if (!height || !width)
+	return;
+
+    sti_clear(sticon_sti, sy, sx, height, width, conp->vc_video_erase_char);
+}
+
+static int sticon_switch(struct vc_data *conp)
+{
+    return 1;	/* needs refreshing */
+}
+
+static int sticon_set_origin(struct vc_data *conp)
+{
+    return 0;
+}
+
+static int sticon_blank(struct vc_data *c, int blank, int mode_switch)
+{
+    if (blank == 0) {
+	if (mode_switch)
+	    vga_is_gfx = 0;
+	return 1;
+    }
+    sticon_set_origin(c);
+    sti_clear(sticon_sti, 0,0, c->vc_rows, c->vc_cols, BLANK);
+    if (mode_switch)
+	vga_is_gfx = 1;
+    return 1;
+}
+
+static int sticon_scrolldelta(struct vc_data *conp, int lines)
+{
+    return 0;
+}
+
+static u16 *sticon_screen_pos(struct vc_data *conp, int offset)
+{
+    int line;
+    unsigned long p;
+
+    if (conp->vc_num != fg_console || !softback_lines)
+    	return (u16 *)(conp->vc_origin + offset);
+    line = offset / conp->vc_size_row;
+    if (line >= softback_lines)
+    	return (u16 *)(conp->vc_origin + offset - softback_lines * conp->vc_size_row);
+    p = softback_curr + offset;
+    if (p >= softback_end)
+    	p += softback_buf - softback_end;
+    return (u16 *)p;
+}
+
+static unsigned long sticon_getxy(struct vc_data *conp, unsigned long pos,
+				  int *px, int *py)
+{
+    int x, y;
+    unsigned long ret;
+    if (pos >= conp->vc_origin && pos < conp->vc_scr_end) {
+    	unsigned long offset = (pos - conp->vc_origin) / 2;
+    	
+    	x = offset % conp->vc_cols;
+    	y = offset / conp->vc_cols;
+    	if (conp->vc_num == fg_console)
+    	    y += softback_lines;
+    	ret = pos + (conp->vc_cols - x) * 2;
+    } else if (conp->vc_num == fg_console && softback_lines) {
+    	unsigned long offset = pos - softback_curr;
+    	
+    	if (pos < softback_curr)
+    	    offset += softback_end - softback_buf;
+    	offset /= 2;
+    	x = offset % conp->vc_cols;
+    	y = offset / conp->vc_cols;
+	ret = pos + (conp->vc_cols - x) * 2;
+	if (ret == softback_end)
+	    ret = softback_buf;
+	if (ret == softback_in)
+	    ret = conp->vc_origin;
+    } else {
+    	/* Should not happen */
+    	x = y = 0;
+    	ret = conp->vc_origin;
+    }
+    if (px) *px = x;
+    if (py) *py = y;
+    return ret;
+}
+
+static u8 sticon_build_attr(struct vc_data *conp, u8 color, u8 intens,
+			    u8 blink, u8 underline, u8 reverse)
+{
+    u8 attr = ((color & 0x70) >> 1) | ((color & 7));
+
+    if (reverse) {
+	color = ((color >> 3) & 0x7) | ((color & 0x7) << 3);
+    }
+
+    return attr;
+}
+
+static void sticon_invert_region(struct vc_data *conp, u16 *p, int count)
+{
+    int col = 1; /* vga_can_do_color; */
+
+    while (count--) {
+	u16 a = scr_readw(p);
+
+	if (col)
+		a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
+	else
+		a = ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
+
+	scr_writew(a, p++);
+    }
+}
+
+static void sticon_save_screen(struct vc_data *conp)
+{
+}
+
+static struct consw sti_con = {
+	.owner			= THIS_MODULE,
+	.con_startup		= sticon_startup,
+	.con_init		= sticon_init,
+	.con_deinit		= sticon_deinit,
+	.con_clear		= sticon_clear,
+	.con_putc		= sticon_putc,
+	.con_putcs		= sticon_putcs,
+	.con_cursor		= sticon_cursor,
+	.con_scroll		= sticon_scroll,
+	.con_bmove		= sticon_bmove,
+	.con_switch		= sticon_switch,
+	.con_blank		= sticon_blank,
+	.con_set_palette	= sticon_set_palette,
+	.con_scrolldelta	= sticon_scrolldelta,
+	.con_set_origin		= sticon_set_origin,
+	.con_save_screen	= sticon_save_screen, 
+	.con_build_attr		= sticon_build_attr,
+	.con_invert_region	= sticon_invert_region, 
+	.con_screen_pos		= sticon_screen_pos,
+	.con_getxy		= sticon_getxy,
+};
+
+
+
+int __init sticonsole_init(void)
+{
+    /* already initialized ? */
+    if (sticon_sti)
+	 return 0;
+
+    sticon_sti = sti_get_rom(0);
+    if (!sticon_sti)
+	return -ENODEV;
+
+    if (conswitchp == &dummy_con) {
+	printk(KERN_INFO "sticon: Initializing STI text console.\n");
+	return take_over_console(&sti_con, 0, MAX_NR_CONSOLES - 1, 1);
+    }
+    return 0;
+}
+
+module_init(sticonsole_init);
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/console/sticore.c b/drivers/video/console/sticore.c
new file mode 100644
index 0000000..d940f60
--- /dev/null
+++ b/drivers/video/console/sticore.c
@@ -0,0 +1,1088 @@
+/*
+ *  linux/drivers/video/console/sticore.c -
+ *	core code for console driver using HP's STI firmware
+ *
+ *	Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ *	Copyright (C) 2001-2003 Helge Deller <deller@gmx.de>
+ *	Copyright (C) 2001-2002 Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+ * 
+ * TODO:
+ * - call STI in virtual mode rather than in real mode
+ * - screen blanking with state_mgmt() in text mode STI ? 
+ * - try to make it work on m68k hp workstations ;)
+ * 
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/font.h>
+
+#include <asm/hardware.h>
+#include <asm/parisc-device.h>
+#include <asm/cacheflush.h>
+
+#include "../sticore.h"
+
+#define STI_DRIVERVERSION "Version 0.9a"
+
+struct sti_struct *default_sti;
+
+static int num_sti_roms;			  /* # of STI ROMS found */
+static struct sti_struct *sti_roms[MAX_STI_ROMS]; /* ptr to each sti_struct */
+
+
+/* The colour indices used by STI are
+ *   0 - Black
+ *   1 - White
+ *   2 - Red
+ *   3 - Yellow/Brown
+ *   4 - Green
+ *   5 - Cyan
+ *   6 - Blue
+ *   7 - Magenta
+ *
+ * So we have the same colours as VGA (basically one bit each for R, G, B),
+ * but have to translate them, anyway. */
+
+static const u8 col_trans[8] = {
+        0, 6, 4, 5,
+        2, 7, 3, 1
+};
+
+#define c_fg(sti, c) col_trans[((c>> 8) & 7)]
+#define c_bg(sti, c) col_trans[((c>>11) & 7)]
+#define c_index(sti, c) ((c) & 0xff)
+
+static const struct sti_init_flags default_init_flags = {
+	.wait	= STI_WAIT, 
+	.reset	= 1,
+	.text	= 1, 
+	.nontext = 1,
+	.no_chg_bet = 1, 
+	.no_chg_bei = 1, 
+	.init_cmap_tx = 1,
+};
+
+int
+sti_init_graph(struct sti_struct *sti) 
+{
+	struct sti_init_inptr_ext inptr_ext = { 0, };
+	struct sti_init_inptr inptr = {
+		.text_planes	= 3, /* # of text planes (max 3 for STI) */
+		.ext_ptr	= STI_PTR(&inptr_ext)
+	};
+	struct sti_init_outptr outptr = { 0, };
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&sti->lock, flags);
+
+	ret = STI_CALL(sti->init_graph, &default_init_flags, &inptr,
+		&outptr, sti->glob_cfg);
+
+	spin_unlock_irqrestore(&sti->lock, flags);
+
+	if (ret < 0) {
+		printk(KERN_ERR "STI init_graph failed (ret %d, errno %d)\n",ret,outptr.errno);
+		return -1;
+	}
+	
+	sti->text_planes = outptr.text_planes;
+	return 0;
+}
+
+static const struct sti_conf_flags default_conf_flags = {
+	.wait	= STI_WAIT,
+};
+
+void
+sti_inq_conf(struct sti_struct *sti)
+{
+	struct sti_conf_inptr inptr = { 0, };
+	unsigned long flags;
+	s32 ret;
+
+	sti->outptr.ext_ptr = STI_PTR(&sti->outptr_ext);
+	
+	do {
+		spin_lock_irqsave(&sti->lock, flags);
+		ret = STI_CALL(sti->inq_conf, &default_conf_flags,
+			&inptr, &sti->outptr, sti->glob_cfg);
+		spin_unlock_irqrestore(&sti->lock, flags);
+	} while (ret == 1);
+}
+
+static const struct sti_font_flags default_font_flags = {
+	.wait		= STI_WAIT,
+	.non_text	= 0,
+};
+
+void
+sti_putc(struct sti_struct *sti, int c, int y, int x)
+{
+	struct sti_font_inptr inptr = {
+		.font_start_addr= STI_PTR(sti->font->raw),
+		.index		= c_index(sti, c),
+		.fg_color	= c_fg(sti, c),
+		.bg_color	= c_bg(sti, c),
+		.dest_x		= x * sti->font_width,
+		.dest_y		= y * sti->font_height,
+	};
+	struct sti_font_outptr outptr = { 0, };
+	s32 ret;
+	unsigned long flags;
+
+	do {
+		spin_lock_irqsave(&sti->lock, flags);
+		ret = STI_CALL(sti->font_unpmv, &default_font_flags,
+			&inptr, &outptr, sti->glob_cfg);
+		spin_unlock_irqrestore(&sti->lock, flags);
+	} while (ret == 1);
+}
+
+static const struct sti_blkmv_flags clear_blkmv_flags = {
+	.wait	= STI_WAIT, 
+	.color	= 1, 
+	.clear	= 1, 
+};
+
+void
+sti_set(struct sti_struct *sti, int src_y, int src_x,
+	int height, int width, u8 color)
+{
+	struct sti_blkmv_inptr inptr = {
+		.fg_color	= color,
+		.bg_color	= color,
+		.src_x		= src_x,
+		.src_y		= src_y,
+		.dest_x		= src_x,
+		.dest_y		= src_y,
+		.width		= width,
+		.height		= height,
+	};
+	struct sti_blkmv_outptr outptr = { 0, };
+	s32 ret;
+	unsigned long flags;
+	
+	do {
+		spin_lock_irqsave(&sti->lock, flags);
+		ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
+			&inptr, &outptr, sti->glob_cfg);
+		spin_unlock_irqrestore(&sti->lock, flags);
+	} while (ret == 1);
+}
+
+void
+sti_clear(struct sti_struct *sti, int src_y, int src_x,
+	  int height, int width, int c)
+{
+	struct sti_blkmv_inptr inptr = {
+		.fg_color	= c_fg(sti, c),
+		.bg_color	= c_bg(sti, c),
+		.src_x		= src_x * sti->font_width,
+		.src_y		= src_y * sti->font_height,
+		.dest_x		= src_x * sti->font_width,
+		.dest_y		= src_y * sti->font_height,
+		.width		= width * sti->font_width,
+		.height		= height* sti->font_height,
+	};
+	struct sti_blkmv_outptr outptr = { 0, };
+	s32 ret;
+	unsigned long flags;
+
+	do {
+		spin_lock_irqsave(&sti->lock, flags);
+		ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
+			&inptr, &outptr, sti->glob_cfg);
+		spin_unlock_irqrestore(&sti->lock, flags);
+	} while (ret == 1);
+}
+
+static const struct sti_blkmv_flags default_blkmv_flags = {
+	.wait = STI_WAIT, 
+};
+
+void
+sti_bmove(struct sti_struct *sti, int src_y, int src_x,
+	  int dst_y, int dst_x, int height, int width)
+{
+	struct sti_blkmv_inptr inptr = {
+		.src_x		= src_x * sti->font_width,
+		.src_y		= src_y * sti->font_height,
+		.dest_x		= dst_x * sti->font_width,
+		.dest_y		= dst_y * sti->font_height,
+		.width		= width * sti->font_width,
+		.height		= height* sti->font_height,
+	};
+	struct sti_blkmv_outptr outptr = { 0, };
+	s32 ret;
+	unsigned long flags;
+
+	do {
+		spin_lock_irqsave(&sti->lock, flags);
+		ret = STI_CALL(sti->block_move, &default_blkmv_flags,
+			&inptr, &outptr, sti->glob_cfg);
+		spin_unlock_irqrestore(&sti->lock, flags);
+	} while (ret == 1);
+}
+
+
+/* FIXME: Do we have another solution for this ? */
+static void sti_flush(unsigned long from, unsigned long len)
+{
+	flush_data_cache();
+	flush_kernel_dcache_range(from, len);
+	flush_icache_range(from, from+len);
+}
+
+void __init
+sti_rom_copy(unsigned long base, unsigned long count, void *dest)
+{
+	unsigned long dest_len = count;
+	unsigned long dest_start = (unsigned long) dest;
+
+	/* this still needs to be revisited (see arch/parisc/mm/init.c:246) ! */
+	while (count >= 4) {
+		count -= 4;
+		*(u32 *)dest = gsc_readl(base);
+		base += 4;
+		dest += 4;
+	}
+	while (count) {
+		count--;
+		*(u8 *)dest = gsc_readb(base);
+		base++;
+		dest++;
+	}
+
+	sti_flush(dest_start, dest_len);
+}
+
+
+
+
+static char default_sti_path[21];
+
+#ifndef MODULE
+static int __init sti_setup(char *str)
+{
+	if (str)
+		strlcpy (default_sti_path, str, sizeof (default_sti_path));
+	
+	return 0;
+}
+
+/*	Assuming the machine has multiple STI consoles (=graphic cards) which
+ *	all get detected by sticon, the user may define with the linux kernel
+ *	parameter sti=<x> which of them will be the initial boot-console.
+ *	<x> is a number between 0 and MAX_STI_ROMS, with 0 as the default 
+ *	STI screen.
+ */
+__setup("sti=", sti_setup);
+#endif
+
+
+
+static char __initdata	*font_name[MAX_STI_ROMS] = { "VGA8x16", };
+static int __initdata	font_index[MAX_STI_ROMS], 
+			font_height[MAX_STI_ROMS],
+			font_width[MAX_STI_ROMS];
+#ifndef MODULE
+static int __init sti_font_setup(char *str)
+{
+	char *x;
+	int i = 0;
+
+	/* we accept sti_font=VGA8x16, sti_font=10x20, sti_font=10*20 
+	 * or sti_font=7 style command lines. */
+
+	while (i<MAX_STI_ROMS && str && *str) {
+		if (*str>='0' && *str<='9') {
+			if ((x = strchr(str, 'x')) || (x = strchr(str, '*'))) {
+				font_height[i] = simple_strtoul(str, NULL, 0);
+				font_width[i] = simple_strtoul(x+1, NULL, 0);
+			} else {
+				font_index[i] = simple_strtoul(str, NULL, 0);
+			}
+		} else {
+			font_name[i] = str;	/* fb font name */
+		}
+
+		if ((x = strchr(str, ',')))
+			*x++ = 0;
+		str = x;
+
+		i++;
+	}
+
+	return 0;
+}
+
+/*	The optional linux kernel parameter "sti_font" defines which font
+ *	should be used by the sticon driver to draw characters to the screen.
+ *	Possible values are:
+ *	- sti_font=<fb_fontname>:
+ *		<fb_fontname> is the name of one of the linux-kernel built-in 
+ *		framebuffer font names (e.g. VGA8x16, SUN22x18). 
+ *		This is only available if the fonts have been statically compiled 
+ *		in with e.g. the CONFIG_FONT_8x16 or CONFIG_FONT_SUN12x22 options.
+ *	- sti_font=<number>
+ *		most STI ROMs have built-in HP specific fonts, which can be selected
+ *		by giving the desired number to the sticon driver. 
+ *		NOTE: This number is machine and STI ROM dependend.
+ *	- sti_font=<height>x<width>  (e.g. sti_font=16x8)
+ *		<height> and <width> gives hints to the height and width of the
+ *		font which the user wants. The sticon driver will try to use
+ *		a font with this height and width, but if no suitable font is
+ *		found, sticon will use the default 8x8 font.
+ */
+__setup("sti_font=", sti_font_setup);
+#endif
+
+
+	
+static void __init
+sti_dump_globcfg(struct sti_glob_cfg *glob_cfg, unsigned int sti_mem_request)
+{
+	struct sti_glob_cfg_ext *cfg;
+	
+	DPRINTK((KERN_INFO
+		"%d text planes\n"
+		"%4d x %4d screen resolution\n"
+		"%4d x %4d offscreen\n"
+		"%4d x %4d layout\n"
+		"regions at %08x %08x %08x %08x\n"
+		"regions at %08x %08x %08x %08x\n"
+		"reent_lvl %d\n"
+		"save_addr %08x\n",
+		glob_cfg->text_planes,
+		glob_cfg->onscreen_x, glob_cfg->onscreen_y,
+		glob_cfg->offscreen_x, glob_cfg->offscreen_y,
+		glob_cfg->total_x, glob_cfg->total_y,
+		glob_cfg->region_ptrs[0], glob_cfg->region_ptrs[1],
+		glob_cfg->region_ptrs[2], glob_cfg->region_ptrs[3],
+		glob_cfg->region_ptrs[4], glob_cfg->region_ptrs[5],
+		glob_cfg->region_ptrs[6], glob_cfg->region_ptrs[7],
+		glob_cfg->reent_lvl,
+		glob_cfg->save_addr));
+
+	/* dump extended cfg */ 
+	cfg = PTR_STI(glob_cfg->ext_ptr);
+	DPRINTK(( KERN_INFO
+		"monitor %d\n"
+		"in friendly mode: %d\n"
+		"power consumption %d watts\n"
+		"freq ref %d\n"
+		"sti_mem_addr %08x (size=%d bytes)\n",
+		cfg->curr_mon,
+		cfg->friendly_boot,
+		cfg->power,
+		cfg->freq_ref,
+		cfg->sti_mem_addr, sti_mem_request));
+}
+
+static void __init
+sti_dump_outptr(struct sti_struct *sti)
+{
+	DPRINTK((KERN_INFO
+		"%d bits per pixel\n"
+		"%d used bits\n"
+		"%d planes\n"
+		"attributes %08x\n",
+		 sti->outptr.bits_per_pixel,
+		 sti->outptr.bits_used,
+		 sti->outptr.planes,
+		 sti->outptr.attributes));
+}
+
+static int __init
+sti_init_glob_cfg(struct sti_struct *sti,
+	    unsigned long rom_address, unsigned long hpa)
+{
+	struct sti_glob_cfg *glob_cfg;
+	struct sti_glob_cfg_ext *glob_cfg_ext;
+	void *save_addr;
+	void *sti_mem_addr;
+	const int save_addr_size = 1024;	/* XXX */
+	int i;
+
+	if (!sti->sti_mem_request)
+		sti->sti_mem_request = 256; /* STI default */
+
+	glob_cfg = kmalloc(sizeof(*sti->glob_cfg), GFP_KERNEL);
+	glob_cfg_ext = kmalloc(sizeof(*glob_cfg_ext), GFP_KERNEL);
+	save_addr = kmalloc(save_addr_size, GFP_KERNEL);
+	sti_mem_addr = kmalloc(sti->sti_mem_request, GFP_KERNEL);
+
+	if (!(glob_cfg && glob_cfg_ext && save_addr && sti_mem_addr)) {
+		kfree(glob_cfg);
+		kfree(glob_cfg_ext);
+		kfree(save_addr);
+		kfree(sti_mem_addr);
+		return -ENOMEM;
+	}
+
+	memset(glob_cfg, 0, sizeof(*glob_cfg));
+	memset(glob_cfg_ext, 0, sizeof(*glob_cfg_ext));
+	memset(save_addr, 0, save_addr_size);
+	memset(sti_mem_addr, 0, sti->sti_mem_request);
+
+	glob_cfg->ext_ptr = STI_PTR(glob_cfg_ext);
+	glob_cfg->save_addr = STI_PTR(save_addr);
+	for (i=0; i<8; i++) {
+		unsigned long newhpa, len;
+	       
+		if (sti->pd) {
+			unsigned char offs = sti->rm_entry[i];
+				
+			if (offs == 0)
+				continue;
+			if (offs != PCI_ROM_ADDRESS &&
+			    (offs < PCI_BASE_ADDRESS_0 ||
+			     offs > PCI_BASE_ADDRESS_5)) {
+				printk (KERN_WARNING
+					"STI pci region maping for region %d (%02x) can't be mapped\n",
+					i,sti->rm_entry[i]);
+				continue;
+			}
+			newhpa = pci_resource_start (sti->pd, (offs - PCI_BASE_ADDRESS_0) / 4);
+		} else
+			newhpa = (i == 0) ? rom_address : hpa;
+
+		sti->regions_phys[i] =
+			REGION_OFFSET_TO_PHYS(sti->regions[i], newhpa);
+		
+		/* remap virtually */
+		/* FIXME: add BTLB support if btlb==1 */
+		len = sti->regions[i].region_desc.length * 4096;
+
+/* XXX: Enabling IOREMAP debugging causes a crash, so we must be passing
+ * a virtual address to something expecting a physical address that doesn't
+ * go through a readX macro */
+#if 0
+		if (len)
+		   glob_cfg->region_ptrs[i] = (unsigned long) (
+			sti->regions[i].region_desc.cache ?
+			ioremap(sti->regions_phys[i], len) :
+			ioremap_nocache(sti->regions_phys[i], len) );
+#else
+		if (len)
+			glob_cfg->region_ptrs[i] = sti->regions_phys[i];
+#endif
+		
+		DPRINTK(("region #%d: phys %08lx, virt %08x, len=%lukB, "
+			 "btlb=%d, sysonly=%d, cache=%d, last=%d\n",
+			i, sti->regions_phys[i], glob_cfg->region_ptrs[i],
+			len/1024,
+			sti->regions[i].region_desc.btlb,
+			sti->regions[i].region_desc.sys_only,
+			sti->regions[i].region_desc.cache, 
+			sti->regions[i].region_desc.last));
+
+		/* last entry reached ? */
+		if (sti->regions[i].region_desc.last)
+			break;
+	}
+
+	if (++i<8 && sti->regions[i].region)
+		printk(KERN_WARNING "%s: *future ptr (0x%8x) not yet supported !\n",
+				__FILE__, sti->regions[i].region);
+
+	glob_cfg_ext->sti_mem_addr = STI_PTR(sti_mem_addr);
+
+	sti->glob_cfg = glob_cfg;
+	
+	return 0;
+}
+
+#ifdef CONFIG_FB
+struct sti_cooked_font * __init
+sti_select_fbfont( struct sti_cooked_rom *cooked_rom, char *fbfont_name )
+{
+	struct font_desc *fbfont;
+	unsigned int size, bpc;
+	void *dest;
+	struct sti_rom_font *nf;
+	struct sti_cooked_font *cooked_font;
+	
+	if (!fbfont_name || !strlen(fbfont_name))
+	    return NULL;
+	fbfont = find_font(fbfont_name);
+	if (!fbfont)
+	    fbfont = get_default_font(1024,768);
+	if (!fbfont)
+	    return NULL;
+
+	DPRINTK((KERN_DEBUG "selected %dx%d fb-font %s\n",
+			fbfont->width, fbfont->height, fbfont->name));
+			
+	bpc = ((fbfont->width+7)/8) * fbfont->height; 
+	size = bpc * 256;
+	size += sizeof(struct sti_rom_font);
+
+	nf = kmalloc(size, GFP_KERNEL);
+	if (!nf)
+	    return NULL;
+	memset(nf, 0, size);
+
+	nf->first_char = 0;
+	nf->last_char = 255;
+	nf->width = fbfont->width;
+	nf->height = fbfont->height;
+	nf->font_type = STI_FONT_HPROMAN8;
+	nf->bytes_per_char = bpc;
+	nf->next_font = 0;
+	nf->underline_height = 1;
+	nf->underline_pos = fbfont->height - nf->underline_height;
+
+	dest = nf;
+	dest += sizeof(struct sti_rom_font);
+	memcpy(dest, fbfont->data, bpc*256);
+
+	cooked_font = kmalloc(sizeof(*cooked_font), GFP_KERNEL);
+	if (!cooked_font) {
+	    kfree(nf);
+	    return NULL;
+	}
+	
+	cooked_font->raw = nf;
+	cooked_font->next_font = NULL;
+
+	cooked_rom->font_start = cooked_font;
+
+	return cooked_font;
+}
+#else
+struct sti_cooked_font * __init
+sti_select_fbfont(struct sti_cooked_rom *cooked_rom, char *fbfont_name)
+{
+	return NULL;
+}
+#endif
+
+struct sti_cooked_font * __init
+sti_select_font(struct sti_cooked_rom *rom,
+	    int (*search_font_fnc) (struct sti_cooked_rom *,int,int) )
+{
+	struct sti_cooked_font *font;
+	int i;
+	int index = num_sti_roms;
+
+	/* check for framebuffer-font first */
+	if ((font = sti_select_fbfont(rom, font_name[index])))
+		return font;
+
+	if (font_width[index] && font_height[index])
+		font_index[index] = search_font_fnc(rom, 
+				font_height[index], font_width[index]);
+
+	for (font = rom->font_start, i = font_index[index];
+	    font && (i > 0);
+	    font = font->next_font, i--);
+
+	if (font)
+		return font;
+	else
+		return rom->font_start;
+}
+
+
+static void __init 
+sti_dump_rom(struct sti_rom *rom)
+{
+        printk(KERN_INFO "    id %04x-%04x, conforms to spec rev. %d.%02x\n",
+		rom->graphics_id[0], 
+		rom->graphics_id[1],
+		rom->revno[0] >> 4, 
+		rom->revno[0] & 0x0f);
+	DPRINTK(("      supports %d monitors\n", rom->num_mons));
+	DPRINTK(("      font start %08x\n", rom->font_start));
+	DPRINTK(("      region list %08x\n", rom->region_list));
+	DPRINTK(("      init_graph %08x\n", rom->init_graph));
+	DPRINTK(("      bus support %02x\n", rom->bus_support));
+	DPRINTK(("      ext bus support %02x\n", rom->ext_bus_support));
+	DPRINTK(("      alternate code type %d\n", rom->alt_code_type));
+}
+
+
+static int __init 
+sti_cook_fonts(struct sti_cooked_rom *cooked_rom,
+			struct sti_rom *raw_rom)
+{
+	struct sti_rom_font *raw_font, *font_start;
+	struct sti_cooked_font *cooked_font;
+	
+	cooked_font = kmalloc(sizeof(*cooked_font), GFP_KERNEL);
+	if (!cooked_font)
+		return 0;
+
+	cooked_rom->font_start = cooked_font;
+
+	raw_font = ((void *)raw_rom) + (raw_rom->font_start);
+
+	font_start = raw_font;
+	cooked_font->raw = raw_font;
+
+	while (raw_font->next_font) {
+		raw_font = ((void *)font_start) + (raw_font->next_font);
+
+		cooked_font->next_font = kmalloc(sizeof(*cooked_font), GFP_KERNEL);
+		if (!cooked_font->next_font)
+			return 1;
+
+		cooked_font = cooked_font->next_font;
+
+		cooked_font->raw = raw_font;
+	}
+
+	cooked_font->next_font = NULL;
+	return 1;
+}
+
+
+static int __init 
+sti_search_font(struct sti_cooked_rom *rom, int height, int width)
+{
+	struct sti_cooked_font *font;
+	int i = 0;
+	
+	for(font = rom->font_start; font; font = font->next_font, i++) {
+	    if((font->raw->width == width) && (font->raw->height == height))
+			return i;
+	}
+	return 0;
+}
+
+#define BMODE_RELOCATE(offset)        offset = (offset) / 4;
+#define BMODE_LAST_ADDR_OFFS          0x50
+
+static void * __init
+sti_bmode_font_raw(struct sti_cooked_font *f)
+{
+	unsigned char *n, *p, *q;
+	int size = f->raw->bytes_per_char*256+sizeof(struct sti_rom_font);
+	
+	n = kmalloc (4*size, GFP_KERNEL);
+	if (!n)
+		return NULL;
+	memset (n, 0, 4*size);
+	p = n + 3;
+	q = (unsigned char *)f->raw;
+	while (size--) {
+		*p = *q++;
+		p+=4;
+	}
+	return n + 3;
+}
+
+static void __init
+sti_bmode_rom_copy(unsigned long base, unsigned long count, void *dest)
+{
+	unsigned long dest_len = count;
+	unsigned long dest_start = (unsigned long) dest;
+
+	while (count) {
+		count--;
+		*(u8 *)dest = gsc_readl(base);
+		base += 4;
+		dest++;
+	}
+	sti_flush(dest_start, dest_len);
+}
+
+static struct sti_rom * __init
+sti_get_bmode_rom (unsigned long address)
+{
+	struct sti_rom *raw;
+	u32 size;
+        struct sti_rom_font *raw_font, *font_start;
+    
+	sti_bmode_rom_copy(address + BMODE_LAST_ADDR_OFFS, sizeof(size), &size);
+    
+        size = (size+3) / 4;
+	raw = kmalloc(size, GFP_KERNEL);
+	if (raw) {
+	    sti_bmode_rom_copy(address, size, raw);
+	    memmove (&raw->res004, &raw->type[0], 0x3c);
+    	    raw->type[3] = raw->res004;
+
+	    BMODE_RELOCATE (raw->region_list);
+	    BMODE_RELOCATE (raw->font_start);
+
+	    BMODE_RELOCATE (raw->init_graph);
+	    BMODE_RELOCATE (raw->state_mgmt);
+	    BMODE_RELOCATE (raw->font_unpmv);
+	    BMODE_RELOCATE (raw->block_move);
+	    BMODE_RELOCATE (raw->inq_conf);
+
+	    raw_font = ((void *)raw) + raw->font_start;
+	    font_start = raw_font;
+		
+	    while (raw_font->next_font) {
+		    BMODE_RELOCATE (raw_font->next_font);
+		    raw_font = ((void *)font_start) + raw_font->next_font;
+	    }
+	}
+        return raw;
+}
+
+struct sti_rom * __init
+sti_get_wmode_rom (unsigned long address)
+{
+	struct sti_rom *raw;
+	unsigned long size;
+    
+	/* read the ROM size directly from the struct in ROM */ 
+	size = gsc_readl(address + offsetof(struct sti_rom,last_addr));
+
+	raw = kmalloc(size, GFP_KERNEL);
+	if(raw)
+	        sti_rom_copy(address, size, raw);
+
+        return raw;
+}
+
+int __init
+sti_read_rom(int wordmode, struct sti_struct *sti, unsigned long address)
+{
+	struct sti_cooked_rom *cooked;
+	struct sti_rom *raw = NULL;
+
+	cooked = kmalloc(sizeof *cooked, GFP_KERNEL);
+	if (!cooked)
+		goto out_err;
+
+        if (wordmode)
+                raw = sti_get_wmode_rom (address);
+        else
+	        raw = sti_get_bmode_rom (address);
+
+        if (!raw)
+	        goto out_err;
+    
+	if (!sti_cook_fonts(cooked, raw)) {
+		printk(KERN_ERR "No font found for STI at %08lx\n", address);
+		goto out_err;
+	}
+
+	if (raw->region_list)
+		memcpy(sti->regions, ((void *)raw)+raw->region_list, sizeof(sti->regions));
+
+	address = (unsigned long) STI_PTR(raw);
+
+	sti->font_unpmv = address + (raw->font_unpmv & 0x03ffffff);
+	sti->block_move = address + (raw->block_move & 0x03ffffff);
+	sti->init_graph = address + (raw->init_graph & 0x03ffffff);
+	sti->inq_conf   = address + (raw->inq_conf   & 0x03ffffff);
+
+	sti->rom = cooked;
+	sti->rom->raw = raw;
+	
+	sti->font = sti_select_font(sti->rom, sti_search_font);
+	sti->font_width = sti->font->raw->width;
+	sti->font_height = sti->font->raw->height;
+	if (!wordmode)
+	        sti->font->raw = sti_bmode_font_raw(sti->font);
+
+	sti->sti_mem_request = raw->sti_mem_req;
+	sti->graphics_id[0] = raw->graphics_id[0];
+	sti->graphics_id[1] = raw->graphics_id[1];
+	
+	sti_dump_rom(raw);
+	
+	return 1;
+
+out_err:
+	kfree(raw);
+	kfree(cooked);
+	return 0;
+}
+
+static struct sti_struct * __init
+sti_try_rom_generic(unsigned long address, unsigned long hpa, struct pci_dev *pd)
+{
+	struct sti_struct *sti;
+	int ok;
+	u32 sig;
+
+	if (num_sti_roms >= MAX_STI_ROMS) {
+	    printk(KERN_WARNING "maximum number of STI ROMS reached !\n");
+	    return NULL;
+	}
+	
+	sti = kmalloc(sizeof(*sti), GFP_KERNEL);
+	if (!sti) {
+	    printk(KERN_ERR "Not enough memory !\n");
+	    return NULL;
+	}
+		    
+	memset(sti, 0, sizeof(*sti));
+	spin_lock_init(&sti->lock);
+
+test_rom:
+	/* if we can't read the ROM, bail out early.  Not being able
+	 * to read the hpa is okay, for romless sti */
+	if (pdc_add_valid(address))
+		goto out_err;
+
+	sig = gsc_readl(address);
+
+	/* check for a PCI ROM structure */
+	if ((le32_to_cpu(sig)==0xaa55)) {
+		unsigned int i, rm_offset;
+		u32 *rm;
+		i = gsc_readl(address+0x04);
+		if (i != 1) {
+			/* The ROM could have multiple architecture 
+			 * dependent images (e.g. i386, parisc,...) */
+			printk(KERN_WARNING 
+				"PCI ROM is not a STI ROM type image (0x%8x)\n", i);
+			goto out_err;
+		}
+		
+		sti->pd = pd;
+
+		i = gsc_readl(address+0x0c);
+		DPRINTK(("PCI ROM size (from header) = %d kB\n",
+			le16_to_cpu(i>>16)*512/1024));
+		rm_offset = le16_to_cpu(i & 0xffff);
+		if (rm_offset) { 
+			/* read 16 bytes from the pci region mapper array */
+			rm = (u32*) &sti->rm_entry;
+			*rm++ = gsc_readl(address+rm_offset+0x00);
+			*rm++ = gsc_readl(address+rm_offset+0x04);
+			*rm++ = gsc_readl(address+rm_offset+0x08);
+			*rm++ = gsc_readl(address+rm_offset+0x0c);
+			DPRINTK(("PCI region Mapper offset = %08x: ",
+				rm_offset));
+			for (i=0; i<16; i++)
+				DPRINTK(("%02x ", sti->rm_entry[i]));
+			DPRINTK(("\n"));
+		}
+
+		address += le32_to_cpu(gsc_readl(address+8));
+		DPRINTK(("sig %04x, PCI STI ROM at %08lx\n", sig, address));
+		goto test_rom;
+	}
+	
+	ok = 0;
+	
+	if ((sig & 0xff) == 0x01) {
+		DPRINTK(("    byte mode ROM at %08lx, hpa at %08lx\n",
+		       address, hpa));
+		ok = sti_read_rom(0, sti, address);
+	}
+
+	if ((sig & 0xffff) == 0x0303) {
+		DPRINTK(("    word mode ROM at %08lx, hpa at %08lx\n",
+		       address, hpa));
+		ok = sti_read_rom(1, sti, address);
+	}
+
+	if (!ok)
+		goto out_err;
+
+	if (sti_init_glob_cfg(sti, address, hpa))
+		goto out_err; /* not enough memory */
+
+	/* disable STI PCI ROM. ROM and card RAM overlap and
+	 * leaving it enabled would force HPMCs
+	 */
+	if (sti->pd) {
+		unsigned long rom_base;
+		rom_base = pci_resource_start(sti->pd, PCI_ROM_RESOURCE);	
+		pci_write_config_dword(sti->pd, PCI_ROM_ADDRESS, rom_base & ~PCI_ROM_ADDRESS_ENABLE);
+		DPRINTK((KERN_DEBUG "STI PCI ROM disabled\n"));
+	}
+
+	if (sti_init_graph(sti))
+		goto out_err;
+
+	sti_inq_conf(sti);
+	sti_dump_globcfg(sti->glob_cfg, sti->sti_mem_request);
+	sti_dump_outptr(sti);
+	
+	printk(KERN_INFO "    graphics card name: %s\n", sti->outptr.dev_name );
+
+	sti_roms[num_sti_roms] = sti;
+	num_sti_roms++;
+	
+	return sti;
+
+out_err:
+	kfree(sti);
+	return NULL;
+}
+
+static void __init sticore_check_for_default_sti(struct sti_struct *sti, char *path)
+{
+	if (strcmp (path, default_sti_path) == 0)
+		default_sti = sti;
+}
+
+/*
+ * on newer systems PDC gives the address of the ROM 
+ * in the additional address field addr[1] while on
+ * older Systems the PDC stores it in page0->proc_sti 
+ */
+static int __init sticore_pa_init(struct parisc_device *dev)
+{
+	unsigned long rom = 0;
+	char pa_path[21];
+	struct sti_struct *sti = NULL;
+	
+	if(dev->num_addrs) {
+		rom = dev->addr[0];
+	}
+	if (!rom) {
+		rom = dev->hpa;
+		DPRINTK((KERN_DEBUG "Trying STI ROM at %08lx, hpa at %08lx\n", rom, dev->hpa));
+		sti = sti_try_rom_generic(rom, dev->hpa, NULL);
+		rom = PAGE0->proc_sti;
+	}
+	if (!sti) {
+		DPRINTK((KERN_DEBUG "Trying STI ROM at %08lx, hpa at %08lx\n", rom, dev->hpa));
+		sti = sti_try_rom_generic(rom, dev->hpa, NULL);
+	}
+	if (!sti)
+		return 1;
+	
+	print_pa_hwpath(dev, pa_path);
+	sticore_check_for_default_sti (sti, pa_path);
+	return 0;
+}
+
+
+static int __devinit sticore_pci_init(struct pci_dev *pd,
+		const struct pci_device_id *ent)
+{
+#ifdef CONFIG_PCI
+	unsigned long fb_base, rom_base;
+	unsigned int fb_len, rom_len;
+	struct sti_struct *sti;
+	
+	pci_enable_device(pd);
+
+	fb_base = pci_resource_start(pd, 0);
+	fb_len = pci_resource_len(pd, 0);
+	rom_base = pci_resource_start(pd, PCI_ROM_RESOURCE);
+	rom_len = pci_resource_len(pd, PCI_ROM_RESOURCE);
+	if (rom_base) {
+		pci_write_config_dword(pd, PCI_ROM_ADDRESS, rom_base | PCI_ROM_ADDRESS_ENABLE);
+		DPRINTK((KERN_DEBUG "STI PCI ROM enabled at 0x%08lx\n", rom_base));
+	}
+
+	printk(KERN_INFO "STI PCI graphic ROM found at %08lx (%u kB), fb at %08lx (%u MB)\n",
+		rom_base, rom_len/1024, fb_base, fb_len/1024/1024);
+
+	DPRINTK((KERN_DEBUG "Trying PCI STI ROM at %08lx, PCI hpa at %08lx\n",
+		    rom_base, fb_base));
+
+	sti = sti_try_rom_generic(rom_base, fb_base, pd);
+	if (sti) {
+		char pa_path[30];
+		print_pci_hwpath(pd, pa_path);
+		sticore_check_for_default_sti(sti, pa_path);
+	}
+	
+	if (!sti) {
+		printk(KERN_WARNING "Unable to handle STI device '%s'\n",
+			pci_name(pd));
+		return -ENODEV;
+	}
+#endif /* CONFIG_PCI */
+
+	return 0;
+}
+
+
+static void __devexit sticore_pci_remove(struct pci_dev *pd)
+{
+	BUG();
+}
+
+
+static struct pci_device_id sti_pci_tbl[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_VISUALIZE_EG) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_VISUALIZE_FX6) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_VISUALIZE_FX4) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_VISUALIZE_FX2) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_VISUALIZE_FXE) },
+	{ 0, } /* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, sti_pci_tbl);
+
+static struct pci_driver pci_sti_driver = {
+	.name		= "sti",
+	.id_table	= sti_pci_tbl,
+	.probe		= sticore_pci_init,
+	.remove		= sticore_pci_remove,
+};
+
+static struct parisc_device_id sti_pa_tbl[] = {
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00077 },
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00085 },
+	{ 0, }
+};
+
+static struct parisc_driver pa_sti_driver = {
+	.name		= "sti",
+	.id_table	= sti_pa_tbl,
+	.probe		= sticore_pa_init,
+};
+
+
+/*
+ * sti_init_roms() - detects all STI ROMs and stores them in sti_roms[]
+ */
+
+static int sticore_initialized;
+
+static void __init sti_init_roms(void)
+{
+	if (sticore_initialized)
+		return;
+
+	sticore_initialized = 1;
+
+	printk(KERN_INFO "STI GSC/PCI core graphics driver "
+			STI_DRIVERVERSION "\n");
+
+	/* Register drivers for native & PCI cards */
+	register_parisc_driver(&pa_sti_driver);
+	pci_register_driver(&pci_sti_driver);
+
+	/* if we didn't find the given default sti, take the first one */
+	if (!default_sti)
+		default_sti = sti_roms[0];
+
+}
+
+/*
+ * index = 0 gives default sti
+ * index > 0 gives other stis in detection order
+ */
+struct sti_struct * sti_get_rom(unsigned int index)
+{
+	if (!sticore_initialized)
+		sti_init_roms();
+
+	if (index == 0)
+		return default_sti;
+
+	if (index > num_sti_roms)
+		return NULL;
+
+	return sti_roms[index-1];
+}
+EXPORT_SYMBOL(sti_get_rom);
+
+MODULE_AUTHOR("Philipp Rumpf, Helge Deller, Thomas Bogendoerfer");
+MODULE_DESCRIPTION("Core STI driver for HP's NGLE series graphics cards in HP PARISC machines");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/video/console/tileblit.c b/drivers/video/console/tileblit.c
new file mode 100644
index 0000000..7f76e2c
--- /dev/null
+++ b/drivers/video/console/tileblit.c
@@ -0,0 +1,148 @@
+/*
+ *  linux/drivers/video/console/tileblit.c -- Tile Blitting Operation
+ *
+ *      Copyright (C) 2004 Antonino Daplas <adaplas @pol.net>
+ *
+ *  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/string.h>
+#include <linux/fb.h>
+#include <linux/vt_kern.h>
+#include <linux/console.h>
+#include <asm/types.h>
+#include "fbcon.h"
+
+static void tile_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+		       int sx, int dy, int dx, int height, int width)
+{
+	struct fb_tilearea area;
+
+	area.sx = sx;
+	area.sy = sy;
+	area.dx = dx;
+	area.dy = dy;
+	area.height = height;
+	area.width = width;
+
+	info->tileops->fb_tilecopy(info, &area);
+}
+
+static void tile_clear(struct vc_data *vc, struct fb_info *info, int sy,
+		       int sx, int height, int width)
+{
+	struct fb_tilerect rect;
+	int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+	int fgshift = (vc->vc_hi_font_mask) ? 9 : 8;
+
+	rect.index = vc->vc_video_erase_char &
+		((vc->vc_hi_font_mask) ? 0x1ff : 0xff);
+	rect.fg = attr_fgcol_ec(fgshift, vc);
+	rect.bg = attr_bgcol_ec(bgshift, vc);
+	rect.sx = sx;
+	rect.sy = sy;
+	rect.width = width;
+	rect.height = height;
+	rect.rop = ROP_COPY;
+
+	info->tileops->fb_tilefill(info, &rect);
+}
+
+static void tile_putcs(struct vc_data *vc, struct fb_info *info,
+		       const unsigned short *s, int count, int yy, int xx,
+		       int fg, int bg)
+{
+	struct fb_tileblit blit;
+	unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+	int size = sizeof(u32) * count, i;
+
+	blit.sx = xx;
+	blit.sy = yy;
+	blit.width = count;
+	blit.height = 1;
+	blit.fg = fg;
+	blit.bg = bg;
+	blit.length = count;
+	blit.indices = (u32 *) fb_get_buffer_offset(info, &info->pixmap, size);
+	for (i = 0; i < count; i++)
+		blit.indices[i] = (u32)(scr_readw(s++) & charmask);
+
+	info->tileops->fb_tileblit(info, &blit);
+}
+
+static void tile_clear_margins(struct vc_data *vc, struct fb_info *info,
+			       int bottom_only)
+{
+	return;
+}
+
+static void tile_cursor(struct vc_data *vc, struct fb_info *info,
+			struct display *p, int mode, int softback_lines,
+			int fg, int bg)
+{
+	struct fb_tilecursor cursor;
+	int use_sw = (vc->vc_cursor_type & 0x01);
+
+	cursor.sx = vc->vc_x;
+	cursor.sy = vc->vc_y;
+	cursor.mode = (mode == CM_ERASE || use_sw) ? 0 : 1;
+	cursor.fg = fg;
+	cursor.bg = bg;
+
+	switch (vc->vc_cursor_type & 0x0f) {
+	case CUR_NONE:
+		cursor.shape = FB_TILE_CURSOR_NONE;
+		break;
+	case CUR_UNDERLINE:
+		cursor.shape = FB_TILE_CURSOR_UNDERLINE;
+		break;
+	case CUR_LOWER_THIRD:
+		cursor.shape = FB_TILE_CURSOR_LOWER_THIRD;
+		break;
+	case CUR_LOWER_HALF:
+		cursor.shape = FB_TILE_CURSOR_LOWER_HALF;
+		break;
+	case CUR_TWO_THIRDS:
+		cursor.shape = FB_TILE_CURSOR_TWO_THIRDS;
+		break;
+	case CUR_BLOCK:
+	default:
+		cursor.shape = FB_TILE_CURSOR_BLOCK;
+		break;
+	}
+
+	info->tileops->fb_tilecursor(info, &cursor);
+}
+
+void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info,
+		       struct display *p, struct fbcon_ops *ops)
+{
+	struct fb_tilemap map;
+
+	ops->bmove = tile_bmove;
+	ops->clear = tile_clear;
+	ops->putcs = tile_putcs;
+	ops->clear_margins = tile_clear_margins;
+	ops->cursor = tile_cursor;
+
+	if (p) {
+		map.width = vc->vc_font.width;
+		map.height = vc->vc_font.height;
+		map.depth = 1;
+		map.length = (p->userfont) ?
+			FNTCHARCNT(p->fontdata) : 256;
+		map.data = p->fontdata;
+		info->tileops->fb_settile(info, &map);
+	}
+}
+
+EXPORT_SYMBOL(fbcon_set_tileops);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Tile Blitting Operation");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
new file mode 100644
index 0000000..7d1ae06
--- /dev/null
+++ b/drivers/video/console/vgacon.c
@@ -0,0 +1,1103 @@
+/*
+ *  linux/drivers/video/vgacon.c -- Low level VGA based console driver
+ *
+ *	Created 28 Sep 1997 by Geert Uytterhoeven
+ *
+ *	Rewritten by Martin Mares <mj@ucw.cz>, July 1998
+ *
+ *  This file is based on the old console.c, vga.c and vesa_blank.c drivers.
+ *
+ *	Copyright (C) 1991, 1992  Linus Torvalds
+ *			    1995  Jay Estabrook
+ *
+ *	User definable mapping table and font loading by Eugene G. Crosser,
+ *	<crosser@average.org>
+ *
+ *	Improved loadable font/UTF-8 support by H. Peter Anvin
+ *	Feb-Sep 1995 <peter.anvin@linux.org>
+ *
+ *	Colour palette handling, by Simon Tatham
+ *	17-Jun-95 <sgt20@cam.ac.uk>
+ *
+ *	if 512 char mode is already enabled don't re-enable it,
+ *	because it causes screen to flicker, by Mitja Horvat
+ *	5-May-96 <mitja.horvat@guest.arnes.si>
+ *
+ *	Use 2 outw instead of 4 outb_p to reduce erroneous text
+ *	flashing on RHS of screen during heavy console scrolling .
+ *	Oct 1996, Paul Gortmaker.
+ *
+ *
+ *  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/types.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/string.h>
+#include <linux/kd.h>
+#include <linux/slab.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/spinlock.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+#include <video/vga.h>
+#include <asm/io.h>
+
+static DEFINE_SPINLOCK(vga_lock);
+static int cursor_size_lastfrom;
+static int cursor_size_lastto;
+static struct vgastate state;
+
+#define BLANK 0x0020
+
+#define CAN_LOAD_EGA_FONTS	/* undefine if the user must not do this */
+#define CAN_LOAD_PALETTE	/* undefine if the user must not do this */
+
+/* You really do _NOT_ want to define this, unless you have buggy
+ * Trident VGA which will resize cursor when moving it between column
+ * 15 & 16. If you define this and your VGA is OK, inverse bug will
+ * appear.
+ */
+#undef TRIDENT_GLITCH
+
+/*
+ *  Interface used by the world
+ */
+
+static const char *vgacon_startup(void);
+static void vgacon_init(struct vc_data *c, int init);
+static void vgacon_deinit(struct vc_data *c);
+static void vgacon_cursor(struct vc_data *c, int mode);
+static int vgacon_switch(struct vc_data *c);
+static int vgacon_blank(struct vc_data *c, int blank, int mode_switch);
+static int vgacon_set_palette(struct vc_data *vc, unsigned char *table);
+static int vgacon_scrolldelta(struct vc_data *c, int lines);
+static int vgacon_set_origin(struct vc_data *c);
+static void vgacon_save_screen(struct vc_data *c);
+static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
+			 int lines);
+static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
+			    u8 blink, u8 underline, u8 reverse);
+static void vgacon_invert_region(struct vc_data *c, u16 * p, int count);
+static unsigned long vgacon_uni_pagedir[2];
+
+
+/* Description of the hardware situation */
+static unsigned long	vga_vram_base;		/* Base of video memory */
+static unsigned long	vga_vram_end;		/* End of video memory */
+static u16		vga_video_port_reg;	/* Video register select port */
+static u16		vga_video_port_val;	/* Video register value port */
+static unsigned int	vga_video_num_columns;	/* Number of text columns */
+static unsigned int	vga_video_num_lines;	/* Number of text lines */
+static int		vga_can_do_color = 0;	/* Do we support colors? */
+static unsigned int	vga_default_font_height;/* Height of default screen font */
+static unsigned char	vga_video_type;		/* Card type */
+static unsigned char	vga_hardscroll_enabled;
+static unsigned char	vga_hardscroll_user_enable = 1;
+static unsigned char	vga_font_is_default = 1;
+static int		vga_vesa_blanked;
+static int 		vga_palette_blanked;
+static int 		vga_is_gfx;
+static int 		vga_512_chars;
+static int 		vga_video_font_height;
+static int 		vga_scan_lines;
+static unsigned int 	vga_rolled_over = 0;
+
+static int __init no_scroll(char *str)
+{
+	/*
+	 * Disabling scrollback is required for the Braillex ib80-piezo
+	 * Braille reader made by F.H. Papenmeier (Germany).
+	 * Use the "no-scroll" bootflag.
+	 */
+	vga_hardscroll_user_enable = vga_hardscroll_enabled = 0;
+	return 1;
+}
+
+__setup("no-scroll", no_scroll);
+
+/*
+ * By replacing the four outb_p with two back to back outw, we can reduce
+ * the window of opportunity to see text mislocated to the RHS of the
+ * console during heavy scrolling activity. However there is the remote
+ * possibility that some pre-dinosaur hardware won't like the back to back
+ * I/O. Since the Xservers get away with it, we should be able to as well.
+ */
+static inline void write_vga(unsigned char reg, unsigned int val)
+{
+	unsigned int v1, v2;
+	unsigned long flags;
+
+	/*
+	 * ddprintk might set the console position from interrupt
+	 * handlers, thus the write has to be IRQ-atomic.
+	 */
+	spin_lock_irqsave(&vga_lock, flags);
+
+#ifndef SLOW_VGA
+	v1 = reg + (val & 0xff00);
+	v2 = reg + 1 + ((val << 8) & 0xff00);
+	outw(v1, vga_video_port_reg);
+	outw(v2, vga_video_port_reg);
+#else
+	outb_p(reg, vga_video_port_reg);
+	outb_p(val >> 8, vga_video_port_val);
+	outb_p(reg + 1, vga_video_port_reg);
+	outb_p(val & 0xff, vga_video_port_val);
+#endif
+	spin_unlock_irqrestore(&vga_lock, flags);
+}
+
+static const char __init *vgacon_startup(void)
+{
+	const char *display_desc = NULL;
+	u16 saved1, saved2;
+	volatile u16 *p;
+
+	if (ORIG_VIDEO_ISVGA == VIDEO_TYPE_VLFB) {
+	      no_vga:
+#ifdef CONFIG_DUMMY_CONSOLE
+		conswitchp = &dummy_con;
+		return conswitchp->con_startup();
+#else
+		return NULL;
+#endif
+	}
+
+	/* VGA16 modes are not handled by VGACON */
+	if ((ORIG_VIDEO_MODE == 0x0D) ||	/* 320x200/4 */
+	    (ORIG_VIDEO_MODE == 0x0E) ||	/* 640x200/4 */
+	    (ORIG_VIDEO_MODE == 0x10) ||	/* 640x350/4 */
+	    (ORIG_VIDEO_MODE == 0x12) ||	/* 640x480/4 */
+	    (ORIG_VIDEO_MODE == 0x6A))	/* 800x600/4, 0x6A is very common */
+		goto no_vga;
+
+	vga_video_num_lines = ORIG_VIDEO_LINES;
+	vga_video_num_columns = ORIG_VIDEO_COLS;
+	state.vgabase = NULL;
+
+	if (ORIG_VIDEO_MODE == 7) {	/* Is this a monochrome display? */
+		vga_vram_base = 0xb0000;
+		vga_video_port_reg = VGA_CRT_IM;
+		vga_video_port_val = VGA_CRT_DM;
+		if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) {
+			static struct resource ega_console_resource =
+			    { "ega", 0x3B0, 0x3BF };
+			vga_video_type = VIDEO_TYPE_EGAM;
+			vga_vram_end = 0xb8000;
+			display_desc = "EGA+";
+			request_resource(&ioport_resource,
+					 &ega_console_resource);
+		} else {
+			static struct resource mda1_console_resource =
+			    { "mda", 0x3B0, 0x3BB };
+			static struct resource mda2_console_resource =
+			    { "mda", 0x3BF, 0x3BF };
+			vga_video_type = VIDEO_TYPE_MDA;
+			vga_vram_end = 0xb2000;
+			display_desc = "*MDA";
+			request_resource(&ioport_resource,
+					 &mda1_console_resource);
+			request_resource(&ioport_resource,
+					 &mda2_console_resource);
+			vga_video_font_height = 14;
+		}
+	} else {
+		/* If not, it is color. */
+		vga_can_do_color = 1;
+		vga_vram_base = 0xb8000;
+		vga_video_port_reg = VGA_CRT_IC;
+		vga_video_port_val = VGA_CRT_DC;
+		if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) {
+			int i;
+
+			vga_vram_end = 0xc0000;
+
+			if (!ORIG_VIDEO_ISVGA) {
+				static struct resource ega_console_resource
+				    = { "ega", 0x3C0, 0x3DF };
+				vga_video_type = VIDEO_TYPE_EGAC;
+				display_desc = "EGA";
+				request_resource(&ioport_resource,
+						 &ega_console_resource);
+			} else {
+				static struct resource vga_console_resource
+				    = { "vga+", 0x3C0, 0x3DF };
+				vga_video_type = VIDEO_TYPE_VGAC;
+				display_desc = "VGA+";
+				request_resource(&ioport_resource,
+						 &vga_console_resource);
+
+#ifdef VGA_CAN_DO_64KB
+				/*
+				 * get 64K rather than 32K of video RAM.
+				 * This doesn't actually work on all "VGA"
+				 * controllers (it seems like setting MM=01
+				 * and COE=1 isn't necessarily a good idea)
+				 */
+				vga_vram_base = 0xa0000;
+				vga_vram_end = 0xb0000;
+				outb_p(6, VGA_GFX_I);
+				outb_p(6, VGA_GFX_D);
+#endif
+				/*
+				 * Normalise the palette registers, to point
+				 * the 16 screen colours to the first 16
+				 * DAC entries.
+				 */
+
+				for (i = 0; i < 16; i++) {
+					inb_p(VGA_IS1_RC);
+					outb_p(i, VGA_ATT_W);
+					outb_p(i, VGA_ATT_W);
+				}
+				outb_p(0x20, VGA_ATT_W);
+
+				/*
+				 * Now set the DAC registers back to their
+				 * default values
+				 */
+				for (i = 0; i < 16; i++) {
+					outb_p(color_table[i], VGA_PEL_IW);
+					outb_p(default_red[i], VGA_PEL_D);
+					outb_p(default_grn[i], VGA_PEL_D);
+					outb_p(default_blu[i], VGA_PEL_D);
+				}
+			}
+		} else {
+			static struct resource cga_console_resource =
+			    { "cga", 0x3D4, 0x3D5 };
+			vga_video_type = VIDEO_TYPE_CGA;
+			vga_vram_end = 0xba000;
+			display_desc = "*CGA";
+			request_resource(&ioport_resource,
+					 &cga_console_resource);
+			vga_video_font_height = 8;
+		}
+	}
+
+	vga_vram_base = VGA_MAP_MEM(vga_vram_base);
+	vga_vram_end = VGA_MAP_MEM(vga_vram_end);
+
+	/*
+	 *      Find out if there is a graphics card present.
+	 *      Are there smarter methods around?
+	 */
+	p = (volatile u16 *) vga_vram_base;
+	saved1 = scr_readw(p);
+	saved2 = scr_readw(p + 1);
+	scr_writew(0xAA55, p);
+	scr_writew(0x55AA, p + 1);
+	if (scr_readw(p) != 0xAA55 || scr_readw(p + 1) != 0x55AA) {
+		scr_writew(saved1, p);
+		scr_writew(saved2, p + 1);
+		goto no_vga;
+	}
+	scr_writew(0x55AA, p);
+	scr_writew(0xAA55, p + 1);
+	if (scr_readw(p) != 0x55AA || scr_readw(p + 1) != 0xAA55) {
+		scr_writew(saved1, p);
+		scr_writew(saved2, p + 1);
+		goto no_vga;
+	}
+	scr_writew(saved1, p);
+	scr_writew(saved2, p + 1);
+
+	if (vga_video_type == VIDEO_TYPE_EGAC
+	    || vga_video_type == VIDEO_TYPE_VGAC
+	    || vga_video_type == VIDEO_TYPE_EGAM) {
+		vga_hardscroll_enabled = vga_hardscroll_user_enable;
+		vga_default_font_height = ORIG_VIDEO_POINTS;
+		vga_video_font_height = ORIG_VIDEO_POINTS;
+		/* This may be suboptimal but is a safe bet - go with it */
+		vga_scan_lines =
+		    vga_video_font_height * vga_video_num_lines;
+	}
+	return display_desc;
+}
+
+static void vgacon_init(struct vc_data *c, int init)
+{
+	unsigned long p;
+
+	/* We cannot be loaded as a module, therefore init is always 1 */
+	c->vc_can_do_color = vga_can_do_color;
+	c->vc_cols = vga_video_num_columns;
+	c->vc_rows = vga_video_num_lines;
+	c->vc_scan_lines = vga_scan_lines;
+	c->vc_font.height = vga_video_font_height;
+	c->vc_complement_mask = 0x7700;
+	p = *c->vc_uni_pagedir_loc;
+	if (c->vc_uni_pagedir_loc == &c->vc_uni_pagedir ||
+	    !--c->vc_uni_pagedir_loc[1])
+		con_free_unimap(c);
+	c->vc_uni_pagedir_loc = vgacon_uni_pagedir;
+	vgacon_uni_pagedir[1]++;
+	if (!vgacon_uni_pagedir[0] && p)
+		con_set_default_unimap(c);
+}
+
+static inline void vga_set_mem_top(struct vc_data *c)
+{
+	write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);
+}
+
+static void vgacon_deinit(struct vc_data *c)
+{
+	/* When closing the last console, reset video origin */
+	if (!--vgacon_uni_pagedir[1]) {
+		c->vc_visible_origin = vga_vram_base;
+		vga_set_mem_top(c);
+		con_free_unimap(c);
+	}
+	c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
+	con_set_default_unimap(c);
+}
+
+static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
+			    u8 blink, u8 underline, u8 reverse)
+{
+	u8 attr = color;
+
+	if (vga_can_do_color) {
+		if (underline)
+			attr = (attr & 0xf0) | c->vc_ulcolor;
+		else if (intensity == 0)
+			attr = (attr & 0xf0) | c->vc_halfcolor;
+	}
+	if (reverse)
+		attr =
+		    ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) &
+				       0x77);
+	if (blink)
+		attr ^= 0x80;
+	if (intensity == 2)
+		attr ^= 0x08;
+	if (!vga_can_do_color) {
+		if (underline)
+			attr = (attr & 0xf8) | 0x01;
+		else if (intensity == 0)
+			attr = (attr & 0xf0) | 0x08;
+	}
+	return attr;
+}
+
+static void vgacon_invert_region(struct vc_data *c, u16 * p, int count)
+{
+	int col = vga_can_do_color;
+
+	while (count--) {
+		u16 a = scr_readw(p);
+		if (col)
+			a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
+			    (((a) & 0x0700) << 4);
+		else
+			a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
+		scr_writew(a, p++);
+	}
+}
+
+static void vgacon_set_cursor_size(int xpos, int from, int to)
+{
+	unsigned long flags;
+	int curs, cure;
+
+#ifdef TRIDENT_GLITCH
+	if (xpos < 16)
+		from--, to--;
+#endif
+
+	if ((from == cursor_size_lastfrom) && (to == cursor_size_lastto))
+		return;
+	cursor_size_lastfrom = from;
+	cursor_size_lastto = to;
+
+	spin_lock_irqsave(&vga_lock, flags);
+	outb_p(0x0a, vga_video_port_reg);	/* Cursor start */
+	curs = inb_p(vga_video_port_val);
+	outb_p(0x0b, vga_video_port_reg);	/* Cursor end */
+	cure = inb_p(vga_video_port_val);
+
+	curs = (curs & 0xc0) | from;
+	cure = (cure & 0xe0) | to;
+
+	outb_p(0x0a, vga_video_port_reg);	/* Cursor start */
+	outb_p(curs, vga_video_port_val);
+	outb_p(0x0b, vga_video_port_reg);	/* Cursor end */
+	outb_p(cure, vga_video_port_val);
+	spin_unlock_irqrestore(&vga_lock, flags);
+}
+
+static void vgacon_cursor(struct vc_data *c, int mode)
+{
+	if (c->vc_origin != c->vc_visible_origin)
+		vgacon_scrolldelta(c, 0);
+	switch (mode) {
+	case CM_ERASE:
+		write_vga(14, (vga_vram_end - vga_vram_base - 1) / 2);
+		break;
+
+	case CM_MOVE:
+	case CM_DRAW:
+		write_vga(14, (c->vc_pos - vga_vram_base) / 2);
+		switch (c->vc_cursor_type & 0x0f) {
+		case CUR_UNDERLINE:
+			vgacon_set_cursor_size(c->vc_x,
+					       c->vc_font.height -
+					       (c->vc_font.height <
+						10 ? 2 : 3),
+					       c->vc_font.height -
+					       (c->vc_font.height <
+						10 ? 1 : 2));
+			break;
+		case CUR_TWO_THIRDS:
+			vgacon_set_cursor_size(c->vc_x,
+					       c->vc_font.height / 3,
+					       c->vc_font.height -
+					       (c->vc_font.height <
+						10 ? 1 : 2));
+			break;
+		case CUR_LOWER_THIRD:
+			vgacon_set_cursor_size(c->vc_x,
+					       (c->vc_font.height * 2) / 3,
+					       c->vc_font.height -
+					       (c->vc_font.height <
+						10 ? 1 : 2));
+			break;
+		case CUR_LOWER_HALF:
+			vgacon_set_cursor_size(c->vc_x,
+					       c->vc_font.height / 2,
+					       c->vc_font.height -
+					       (c->vc_font.height <
+						10 ? 1 : 2));
+			break;
+		case CUR_NONE:
+			vgacon_set_cursor_size(c->vc_x, 31, 30);
+			break;
+		default:
+			vgacon_set_cursor_size(c->vc_x, 1,
+					       c->vc_font.height);
+			break;
+		}
+		break;
+	}
+}
+
+static int vgacon_switch(struct vc_data *c)
+{
+	/*
+	 * We need to save screen size here as it's the only way
+	 * we can spot the screen has been resized and we need to
+	 * set size of freshly allocated screens ourselves.
+	 */
+	vga_video_num_columns = c->vc_cols;
+	vga_video_num_lines = c->vc_rows;
+	if (!vga_is_gfx)
+		scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
+			    c->vc_screenbuf_size);
+	return 0;		/* Redrawing not needed */
+}
+
+static void vga_set_palette(struct vc_data *vc, unsigned char *table)
+{
+	int i, j;
+
+	for (i = j = 0; i < 16; i++) {
+		vga_w(state.vgabase, VGA_PEL_IW, table[i]);
+		vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
+		vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
+		vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
+	}
+}
+
+static int vgacon_set_palette(struct vc_data *vc, unsigned char *table)
+{
+#ifdef CAN_LOAD_PALETTE
+	if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked
+	    || !CON_IS_VISIBLE(vc))
+		return -EINVAL;
+	vga_set_palette(vc, table);
+	return 0;
+#else
+	return -EINVAL;
+#endif
+}
+
+/* structure holding original VGA register settings */
+static struct {
+	unsigned char SeqCtrlIndex;	/* Sequencer Index reg.   */
+	unsigned char CrtCtrlIndex;	/* CRT-Contr. Index reg.  */
+	unsigned char CrtMiscIO;	/* Miscellaneous register */
+	unsigned char HorizontalTotal;	/* CRT-Controller:00h */
+	unsigned char HorizDisplayEnd;	/* CRT-Controller:01h */
+	unsigned char StartHorizRetrace;	/* CRT-Controller:04h */
+	unsigned char EndHorizRetrace;	/* CRT-Controller:05h */
+	unsigned char Overflow;	/* CRT-Controller:07h */
+	unsigned char StartVertRetrace;	/* CRT-Controller:10h */
+	unsigned char EndVertRetrace;	/* CRT-Controller:11h */
+	unsigned char ModeControl;	/* CRT-Controller:17h */
+	unsigned char ClockingMode;	/* Seq-Controller:01h */
+} vga_state;
+
+static void vga_vesa_blank(struct vgastate *state, int mode)
+{
+	/* save original values of VGA controller registers */
+	if (!vga_vesa_blanked) {
+		spin_lock_irq(&vga_lock);
+		vga_state.SeqCtrlIndex = vga_r(state->vgabase, VGA_SEQ_I);
+		vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg);
+		vga_state.CrtMiscIO = vga_r(state->vgabase, VGA_MIS_R);
+		spin_unlock_irq(&vga_lock);
+
+		outb_p(0x00, vga_video_port_reg);	/* HorizontalTotal */
+		vga_state.HorizontalTotal = inb_p(vga_video_port_val);
+		outb_p(0x01, vga_video_port_reg);	/* HorizDisplayEnd */
+		vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
+		outb_p(0x04, vga_video_port_reg);	/* StartHorizRetrace */
+		vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
+		outb_p(0x05, vga_video_port_reg);	/* EndHorizRetrace */
+		vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
+		outb_p(0x07, vga_video_port_reg);	/* Overflow */
+		vga_state.Overflow = inb_p(vga_video_port_val);
+		outb_p(0x10, vga_video_port_reg);	/* StartVertRetrace */
+		vga_state.StartVertRetrace = inb_p(vga_video_port_val);
+		outb_p(0x11, vga_video_port_reg);	/* EndVertRetrace */
+		vga_state.EndVertRetrace = inb_p(vga_video_port_val);
+		outb_p(0x17, vga_video_port_reg);	/* ModeControl */
+		vga_state.ModeControl = inb_p(vga_video_port_val);
+		vga_state.ClockingMode = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
+	}
+
+	/* assure that video is enabled */
+	/* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
+	spin_lock_irq(&vga_lock);
+	vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode | 0x20);
+
+	/* test for vertical retrace in process.... */
+	if ((vga_state.CrtMiscIO & 0x80) == 0x80)
+		vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO & 0xEF);
+
+	/*
+	 * Set <End of vertical retrace> to minimum (0) and
+	 * <Start of vertical Retrace> to maximum (incl. overflow)
+	 * Result: turn off vertical sync (VSync) pulse.
+	 */
+	if (mode & VESA_VSYNC_SUSPEND) {
+		outb_p(0x10, vga_video_port_reg);	/* StartVertRetrace */
+		outb_p(0xff, vga_video_port_val);	/* maximum value */
+		outb_p(0x11, vga_video_port_reg);	/* EndVertRetrace */
+		outb_p(0x40, vga_video_port_val);	/* minimum (bits 0..3)  */
+		outb_p(0x07, vga_video_port_reg);	/* Overflow */
+		outb_p(vga_state.Overflow | 0x84, vga_video_port_val);	/* bits 9,10 of vert. retrace */
+	}
+
+	if (mode & VESA_HSYNC_SUSPEND) {
+		/*
+		 * Set <End of horizontal retrace> to minimum (0) and
+		 *  <Start of horizontal Retrace> to maximum
+		 * Result: turn off horizontal sync (HSync) pulse.
+		 */
+		outb_p(0x04, vga_video_port_reg);	/* StartHorizRetrace */
+		outb_p(0xff, vga_video_port_val);	/* maximum */
+		outb_p(0x05, vga_video_port_reg);	/* EndHorizRetrace */
+		outb_p(0x00, vga_video_port_val);	/* minimum (0) */
+	}
+
+	/* restore both index registers */
+	vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
+	outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
+	spin_unlock_irq(&vga_lock);
+}
+
+static void vga_vesa_unblank(struct vgastate *state)
+{
+	/* restore original values of VGA controller registers */
+	spin_lock_irq(&vga_lock);
+	vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO);
+
+	outb_p(0x00, vga_video_port_reg);	/* HorizontalTotal */
+	outb_p(vga_state.HorizontalTotal, vga_video_port_val);
+	outb_p(0x01, vga_video_port_reg);	/* HorizDisplayEnd */
+	outb_p(vga_state.HorizDisplayEnd, vga_video_port_val);
+	outb_p(0x04, vga_video_port_reg);	/* StartHorizRetrace */
+	outb_p(vga_state.StartHorizRetrace, vga_video_port_val);
+	outb_p(0x05, vga_video_port_reg);	/* EndHorizRetrace */
+	outb_p(vga_state.EndHorizRetrace, vga_video_port_val);
+	outb_p(0x07, vga_video_port_reg);	/* Overflow */
+	outb_p(vga_state.Overflow, vga_video_port_val);
+	outb_p(0x10, vga_video_port_reg);	/* StartVertRetrace */
+	outb_p(vga_state.StartVertRetrace, vga_video_port_val);
+	outb_p(0x11, vga_video_port_reg);	/* EndVertRetrace */
+	outb_p(vga_state.EndVertRetrace, vga_video_port_val);
+	outb_p(0x17, vga_video_port_reg);	/* ModeControl */
+	outb_p(vga_state.ModeControl, vga_video_port_val);
+	/* ClockingMode */
+	vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode);
+
+	/* restore index/control registers */
+	vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
+	outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
+	spin_unlock_irq(&vga_lock);
+}
+
+static void vga_pal_blank(struct vgastate *state)
+{
+	int i;
+
+	for (i = 0; i < 16; i++) {
+		vga_w(state->vgabase, VGA_PEL_IW, i);
+		vga_w(state->vgabase, VGA_PEL_D, 0);
+		vga_w(state->vgabase, VGA_PEL_D, 0);
+		vga_w(state->vgabase, VGA_PEL_D, 0);
+	}
+}
+
+static int vgacon_blank(struct vc_data *c, int blank, int mode_switch)
+{
+	switch (blank) {
+	case 0:		/* Unblank */
+		if (vga_vesa_blanked) {
+			vga_vesa_unblank(&state);
+			vga_vesa_blanked = 0;
+		}
+		if (vga_palette_blanked) {
+			vga_set_palette(c, color_table);
+			vga_palette_blanked = 0;
+			return 0;
+		}
+		vga_is_gfx = 0;
+		/* Tell console.c that it has to restore the screen itself */
+		return 1;
+	case 1:		/* Normal blanking */
+	case -1:	/* Obsolete */
+		if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) {
+			vga_pal_blank(&state);
+			vga_palette_blanked = 1;
+			return 0;
+		}
+		vgacon_set_origin(c);
+		scr_memsetw((void *) vga_vram_base, BLANK,
+			    c->vc_screenbuf_size);
+		if (mode_switch)
+			vga_is_gfx = 1;
+		return 1;
+	default:		/* VESA blanking */
+		if (vga_video_type == VIDEO_TYPE_VGAC) {
+			vga_vesa_blank(&state, blank - 1);
+			vga_vesa_blanked = blank;
+		}
+		return 0;
+	}
+}
+
+/*
+ * PIO_FONT support.
+ *
+ * The font loading code goes back to the codepage package by
+ * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
+ * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
+ * Video Systems_ by Richard Wilton. 1987.  Microsoft Press".)
+ *
+ * Change for certain monochrome monitors by Yury Shevchuck
+ * (sizif@botik.yaroslavl.su).
+ */
+
+#ifdef CAN_LOAD_EGA_FONTS
+
+#define colourmap 0xa0000
+/* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
+   should use 0xA0000 for the bwmap as well.. */
+#define blackwmap 0xa0000
+#define cmapsz 8192
+
+static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
+{
+	unsigned short video_port_status = vga_video_port_reg + 6;
+	int font_select = 0x00, beg, i;
+	char *charmap;
+	
+	if (vga_video_type != VIDEO_TYPE_EGAM) {
+		charmap = (char *) VGA_MAP_MEM(colourmap);
+		beg = 0x0e;
+#ifdef VGA_CAN_DO_64KB
+		if (vga_video_type == VIDEO_TYPE_VGAC)
+			beg = 0x06;
+#endif
+	} else {
+		charmap = (char *) VGA_MAP_MEM(blackwmap);
+		beg = 0x0a;
+	}
+
+#ifdef BROKEN_GRAPHICS_PROGRAMS
+	/*
+	 * All fonts are loaded in slot 0 (0:1 for 512 ch)
+	 */
+
+	if (!arg)
+		return -EINVAL;	/* Return to default font not supported */
+
+	vga_font_is_default = 0;
+	font_select = ch512 ? 0x04 : 0x00;
+#else
+	/*
+	 * The default font is kept in slot 0 and is never touched.
+	 * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch)
+	 */
+
+	if (set) {
+		vga_font_is_default = !arg;
+		if (!arg)
+			ch512 = 0;	/* Default font is always 256 */
+		font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00;
+	}
+
+	if (!vga_font_is_default)
+		charmap += 4 * cmapsz;
+#endif
+
+	unlock_kernel();
+	spin_lock_irq(&vga_lock);
+	/* First, the Sequencer */
+	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
+	/* CPU writes only to map 2 */
+	vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x04);	
+	/* Sequential addressing */
+	vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x07);	
+	/* Clear synchronous reset */
+	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
+
+	/* Now, the graphics controller, select map 2 */
+	vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x02);		
+	/* disable odd-even addressing */
+	vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x00);
+	/* map start at A000:0000 */
+	vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x00);
+	spin_unlock_irq(&vga_lock);
+
+	if (arg) {
+		if (set)
+			for (i = 0; i < cmapsz; i++)
+				vga_writeb(arg[i], charmap + i);
+		else
+			for (i = 0; i < cmapsz; i++)
+				arg[i] = vga_readb(charmap + i);
+
+		/*
+		 * In 512-character mode, the character map is not contiguous if
+		 * we want to remain EGA compatible -- which we do
+		 */
+
+		if (ch512) {
+			charmap += 2 * cmapsz;
+			arg += cmapsz;
+			if (set)
+				for (i = 0; i < cmapsz; i++)
+					vga_writeb(arg[i], charmap + i);
+			else
+				for (i = 0; i < cmapsz; i++)
+					arg[i] = vga_readb(charmap + i);
+		}
+	}
+
+	spin_lock_irq(&vga_lock);
+	/* First, the sequencer, Synchronous reset */
+	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01);	
+	/* CPU writes to maps 0 and 1 */
+	vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x03);
+	/* odd-even addressing */
+	vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x03);
+	/* Character Map Select */
+	if (set)
+		vga_wseq(state->vgabase, VGA_SEQ_CHARACTER_MAP, font_select);
+	/* clear synchronous reset */
+	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
+
+	/* Now, the graphics controller, select map 0 for CPU */
+	vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x00);
+	/* enable even-odd addressing */
+	vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x10);
+	/* map starts at b800:0 or b000:0 */
+	vga_wgfx(state->vgabase, VGA_GFX_MISC, beg);
+
+	/* if 512 char mode is already enabled don't re-enable it. */
+	if ((set) && (ch512 != vga_512_chars)) {
+		int i;	
+		
+		/* attribute controller */
+		for (i = 0; i < MAX_NR_CONSOLES; i++) {
+			struct vc_data *c = vc_cons[i].d;
+			if (c && c->vc_sw == &vga_con)
+				c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
+		}
+		vga_512_chars = ch512;
+		/* 256-char: enable intensity bit
+		   512-char: disable intensity bit */
+		inb_p(video_port_status);	/* clear address flip-flop */
+		/* color plane enable register */
+		vga_wattr(state->vgabase, VGA_ATC_PLANE_ENABLE, ch512 ? 0x07 : 0x0f);
+		/* Wilton (1987) mentions the following; I don't know what
+		   it means, but it works, and it appears necessary */
+		inb_p(video_port_status);
+		vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0);	
+	}
+	spin_unlock_irq(&vga_lock);
+	lock_kernel();
+	return 0;
+}
+
+/*
+ * Adjust the screen to fit a font of a certain height
+ */
+static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
+{
+	unsigned char ovr, vde, fsr;
+	int rows, maxscan, i;
+
+	rows = vc->vc_scan_lines / fontheight;	/* Number of video rows we end up with */
+	maxscan = rows * fontheight - 1;	/* Scan lines to actually display-1 */
+
+	/* Reprogram the CRTC for the new font size
+	   Note: the attempt to read the overflow register will fail
+	   on an EGA, but using 0xff for the previous value appears to
+	   be OK for EGA text modes in the range 257-512 scan lines, so I
+	   guess we don't need to worry about it.
+
+	   The same applies for the spill bits in the font size and cursor
+	   registers; they are write-only on EGA, but it appears that they
+	   are all don't care bits on EGA, so I guess it doesn't matter. */
+
+	spin_lock_irq(&vga_lock);
+	outb_p(0x07, vga_video_port_reg);	/* CRTC overflow register */
+	ovr = inb_p(vga_video_port_val);
+	outb_p(0x09, vga_video_port_reg);	/* Font size register */
+	fsr = inb_p(vga_video_port_val);
+	spin_unlock_irq(&vga_lock);
+
+	vde = maxscan & 0xff;	/* Vertical display end reg */
+	ovr = (ovr & 0xbd) +	/* Overflow register */
+	    ((maxscan & 0x100) >> 7) + ((maxscan & 0x200) >> 3);
+	fsr = (fsr & 0xe0) + (fontheight - 1);	/*  Font size register */
+
+	spin_lock_irq(&vga_lock);
+	outb_p(0x07, vga_video_port_reg);	/* CRTC overflow register */
+	outb_p(ovr, vga_video_port_val);
+	outb_p(0x09, vga_video_port_reg);	/* Font size */
+	outb_p(fsr, vga_video_port_val);
+	outb_p(0x12, vga_video_port_reg);	/* Vertical display limit */
+	outb_p(vde, vga_video_port_val);
+	spin_unlock_irq(&vga_lock);
+
+	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+		struct vc_data *c = vc_cons[i].d;
+
+		if (c && c->vc_sw == &vga_con) {
+			if (CON_IS_VISIBLE(c)) {
+			        /* void size to cause regs to be rewritten */
+				cursor_size_lastfrom = 0;
+				cursor_size_lastto = 0;
+				c->vc_sw->con_cursor(c, CM_DRAW);
+			}
+			c->vc_font.height = fontheight;
+			vc_resize(c, 0, rows);	/* Adjust console size */
+		}
+	}
+	return 0;
+}
+
+static int vgacon_font_set(struct vc_data *c, struct console_font *font, unsigned flags)
+{
+	unsigned charcount = font->charcount;
+	int rc;
+
+	if (vga_video_type < VIDEO_TYPE_EGAM)
+		return -EINVAL;
+
+	if (font->width != 8 || (charcount != 256 && charcount != 512))
+		return -EINVAL;
+
+	rc = vgacon_do_font_op(&state, font->data, 1, charcount == 512);
+	if (rc)
+		return rc;
+
+	if (!(flags & KD_FONT_FLAG_DONT_RECALC))
+		rc = vgacon_adjust_height(c, font->height);
+	return rc;
+}
+
+static int vgacon_font_get(struct vc_data *c, struct console_font *font)
+{
+	if (vga_video_type < VIDEO_TYPE_EGAM)
+		return -EINVAL;
+
+	font->width = 8;
+	font->height = c->vc_font.height;
+	font->charcount = vga_512_chars ? 512 : 256;
+	if (!font->data)
+		return 0;
+	return vgacon_do_font_op(&state, font->data, 0, 0);
+}
+
+#else
+
+#define vgacon_font_set NULL
+#define vgacon_font_get NULL
+
+#endif
+
+static int vgacon_scrolldelta(struct vc_data *c, int lines)
+{
+	if (!lines)		/* Turn scrollback off */
+		c->vc_visible_origin = c->vc_origin;
+	else {
+		int vram_size = vga_vram_end - vga_vram_base;
+		int margin = c->vc_size_row * 4;
+		int ul, we, p, st;
+
+		if (vga_rolled_over >
+		    (c->vc_scr_end - vga_vram_base) + margin) {
+			ul = c->vc_scr_end - vga_vram_base;
+			we = vga_rolled_over + c->vc_size_row;
+		} else {
+			ul = 0;
+			we = vram_size;
+		}
+		p = (c->vc_visible_origin - vga_vram_base - ul + we) % we +
+		    lines * c->vc_size_row;
+		st = (c->vc_origin - vga_vram_base - ul + we) % we;
+		if (st < 2 * margin)
+			margin = 0;
+		if (p < margin)
+			p = 0;
+		if (p > st - margin)
+			p = st;
+		c->vc_visible_origin = vga_vram_base + (p + ul) % we;
+	}
+	vga_set_mem_top(c);
+	return 1;
+}
+
+static int vgacon_set_origin(struct vc_data *c)
+{
+	if (vga_is_gfx ||	/* We don't play origin tricks in graphic modes */
+	    (console_blanked && !vga_palette_blanked))	/* Nor we write to blanked screens */
+		return 0;
+	c->vc_origin = c->vc_visible_origin = vga_vram_base;
+	vga_set_mem_top(c);
+	vga_rolled_over = 0;
+	return 1;
+}
+
+static void vgacon_save_screen(struct vc_data *c)
+{
+	static int vga_bootup_console = 0;
+
+	if (!vga_bootup_console) {
+		/* This is a gross hack, but here is the only place we can
+		 * set bootup console parameters without messing up generic
+		 * console initialization routines.
+		 */
+		vga_bootup_console = 1;
+		c->vc_x = ORIG_X;
+		c->vc_y = ORIG_Y;
+	}
+	if (!vga_is_gfx)
+		scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin,
+			    c->vc_screenbuf_size);
+}
+
+static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
+			 int lines)
+{
+	unsigned long oldo;
+	unsigned int delta;
+
+	if (t || b != c->vc_rows || vga_is_gfx)
+		return 0;
+
+	if (c->vc_origin != c->vc_visible_origin)
+		vgacon_scrolldelta(c, 0);
+
+	if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2)
+		return 0;
+
+	oldo = c->vc_origin;
+	delta = lines * c->vc_size_row;
+	if (dir == SM_UP) {
+		if (c->vc_scr_end + delta >= vga_vram_end) {
+			scr_memcpyw((u16 *) vga_vram_base,
+				    (u16 *) (oldo + delta),
+				    c->vc_screenbuf_size - delta);
+			c->vc_origin = vga_vram_base;
+			vga_rolled_over = oldo - vga_vram_base;
+		} else
+			c->vc_origin += delta;
+		scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size -
+				     delta), c->vc_video_erase_char,
+			    delta);
+	} else {
+		if (oldo - delta < vga_vram_base) {
+			scr_memmovew((u16 *) (vga_vram_end -
+					      c->vc_screenbuf_size +
+					      delta), (u16 *) oldo,
+				     c->vc_screenbuf_size - delta);
+			c->vc_origin = vga_vram_end - c->vc_screenbuf_size;
+			vga_rolled_over = 0;
+		} else
+			c->vc_origin -= delta;
+		c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
+		scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char,
+			    delta);
+	}
+	c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
+	c->vc_visible_origin = c->vc_origin;
+	vga_set_mem_top(c);
+	c->vc_pos = (c->vc_pos - oldo) + c->vc_origin;
+	return 1;
+}
+
+
+/*
+ *  The console `switch' structure for the VGA based console
+ */
+
+static int vgacon_dummy(struct vc_data *c)
+{
+	return 0;
+}
+
+#define DUMMY (void *) vgacon_dummy
+
+const struct consw vga_con = {
+	.owner = THIS_MODULE,
+	.con_startup = vgacon_startup,
+	.con_init = vgacon_init,
+	.con_deinit = vgacon_deinit,
+	.con_clear = DUMMY,
+	.con_putc = DUMMY,
+	.con_putcs = DUMMY,
+	.con_cursor = vgacon_cursor,
+	.con_scroll = vgacon_scroll,
+	.con_bmove = DUMMY,
+	.con_switch = vgacon_switch,
+	.con_blank = vgacon_blank,
+	.con_font_set = vgacon_font_set,
+	.con_font_get = vgacon_font_get,
+	.con_set_palette = vgacon_set_palette,
+	.con_scrolldelta = vgacon_scrolldelta,
+	.con_set_origin = vgacon_set_origin,
+	.con_save_screen = vgacon_save_screen,
+	.con_build_attr = vgacon_build_attr,
+	.con_invert_region = vgacon_invert_region,
+};
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c
new file mode 100644
index 0000000..989e700
--- /dev/null
+++ b/drivers/video/controlfb.c
@@ -0,0 +1,1102 @@
+/*
+ *  controlfb.c -- frame buffer device for the PowerMac 'control' display
+ *
+ *  Created 12 July 1998 by Dan Jacobowitz <dan@debian.org>
+ *  Copyright (C) 1998 Dan Jacobowitz
+ *  Copyright (C) 2001 Takashi Oe
+ *
+ *  Mmap code by Michel Lanners <mlan@cpu.lu>
+ *
+ *  Frame buffer structure from:
+ *    drivers/video/chipsfb.c -- frame buffer device for
+ *    Chips & Technologies 65550 chip.
+ *
+ *    Copyright (C) 1998 Paul Mackerras
+ *
+ *    This file is derived from the Powermac "chips" driver:
+ *    Copyright (C) 1997 Fabio Riccardi.
+ *    And from the frame buffer device for Open Firmware-initialized devices:
+ *    Copyright (C) 1997 Geert Uytterhoeven.
+ *
+ *  Hardware information from:
+ *    control.c: Console support for PowerMac "control" display adaptor.
+ *    Copyright (C) 1996 Paul Mackerras
+ *
+ *  Updated to 2.5 framebuffer API by Ben Herrenschmidt
+ *  <benh@kernel.crashing.org>, Paul Mackerras <paulus@samba.org>,
+ *  and James Simmons <jsimmons@infradead.org>.
+ *
+ *  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 <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/nvram.h>
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pgtable.h>
+#include <asm/btext.h>
+
+#include "macmodes.h"
+#include "controlfb.h"
+
+struct fb_par_control {
+	int	vmode, cmode;
+	int	xres, yres;
+	int	vxres, vyres;
+	int	xoffset, yoffset;
+	int	pitch;
+	struct control_regvals	regvals;
+	unsigned long sync;
+	unsigned char ctrl;
+};
+
+#define DIRTY(z) ((x)->z != (y)->z)
+#define DIRTY_CMAP(z) (memcmp(&((x)->z), &((y)->z), sizeof((y)->z)))
+static inline int PAR_EQUAL(struct fb_par_control *x, struct fb_par_control *y)
+{
+	int i, results;
+
+	results = 1;
+	for (i = 0; i < 3; i++)
+		results &= !DIRTY(regvals.clock_params[i]);
+	if (!results)
+		return 0;
+	for (i = 0; i < 16; i++)
+		results &= !DIRTY(regvals.regs[i]);
+	if (!results)
+		return 0;
+	return (!DIRTY(cmode) && !DIRTY(xres) && !DIRTY(yres)
+		&& !DIRTY(vxres) && !DIRTY(vyres));
+}
+static inline int VAR_MATCH(struct fb_var_screeninfo *x, struct fb_var_screeninfo *y)
+{
+	return (!DIRTY(bits_per_pixel) && !DIRTY(xres)
+		&& !DIRTY(yres) && !DIRTY(xres_virtual)
+		&& !DIRTY(yres_virtual)
+		&& !DIRTY_CMAP(red) && !DIRTY_CMAP(green) && !DIRTY_CMAP(blue));
+}
+
+struct fb_info_control {
+	struct fb_info		info;
+	struct fb_par_control	par;
+	u32			pseudo_palette[17];
+		
+	struct cmap_regs	__iomem *cmap_regs;
+	unsigned long		cmap_regs_phys;
+	
+	struct control_regs	__iomem *control_regs;
+	unsigned long		control_regs_phys;
+	unsigned long		control_regs_size;
+	
+	__u8			__iomem *frame_buffer;
+	unsigned long		frame_buffer_phys;
+	unsigned long		fb_orig_base;
+	unsigned long		fb_orig_size;
+
+	int			control_use_bank2;
+	unsigned long		total_vram;
+	unsigned char		vram_attr;
+};
+
+/* control register access macro */
+#define CNTRL_REG(INFO,REG) (&(((INFO)->control_regs->REG).r))
+
+
+/******************** Prototypes for exported functions ********************/
+/*
+ * struct fb_ops
+ */
+static int controlfb_pan_display(struct fb_var_screeninfo *var,
+	struct fb_info *info);
+static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+	u_int transp, struct fb_info *info);
+static int controlfb_blank(int blank_mode, struct fb_info *info);
+static int controlfb_mmap(struct fb_info *info, struct file *file,
+	struct vm_area_struct *vma);
+static int controlfb_set_par (struct fb_info *info);
+static int controlfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info);
+
+/*
+ * inititialization
+ */
+int control_init(void);
+void control_setup(char *);
+
+/******************** Prototypes for internal functions **********************/
+
+static void set_control_clock(unsigned char *params);
+static int init_control(struct fb_info_control *p);
+static void control_set_hardware(struct fb_info_control *p,
+	struct fb_par_control *par);
+static int control_of_init(struct device_node *dp);
+static void find_vram_size(struct fb_info_control *p);
+static int read_control_sense(struct fb_info_control *p);
+static int calc_clock_params(unsigned long clk, unsigned char *param);
+static int control_var_to_par(struct fb_var_screeninfo *var,
+	struct fb_par_control *par, const struct fb_info *fb_info);
+static inline void control_par_to_var(struct fb_par_control *par,
+	struct fb_var_screeninfo *var);
+static void control_init_info(struct fb_info *info, struct fb_info_control *p);
+static void control_cleanup(void);
+
+
+/************************** Internal variables *******************************/
+
+static struct fb_info_control *control_fb;
+
+static int default_vmode __initdata = VMODE_NVRAM;
+static int default_cmode __initdata = CMODE_NVRAM;
+
+
+static struct fb_ops controlfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= controlfb_check_var,
+	.fb_set_par	= controlfb_set_par,
+	.fb_setcolreg	= controlfb_setcolreg,
+	.fb_pan_display = controlfb_pan_display,
+	.fb_blank	= controlfb_blank,
+	.fb_mmap	= controlfb_mmap,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+
+/********************  The functions for controlfb_ops ********************/
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+
+int init_module(void)
+{
+	struct device_node *dp;
+
+	dp = find_devices("control");
+	if (dp != 0 && !control_of_init(dp))
+		return 0;
+
+	return -ENXIO;
+}
+
+void cleanup_module(void)
+{
+	control_cleanup();
+}
+#endif
+
+/*
+ * Checks a var structure
+ */
+static int controlfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct fb_par_control par;
+	int err;
+
+	err = control_var_to_par(var, &par, info);
+	if (err)
+		return err;	
+	control_par_to_var(&par, var);
+
+	return 0;
+}
+
+/*
+ * Applies current var to display
+ */
+static int controlfb_set_par (struct fb_info *info)
+{
+	struct fb_info_control *p = (struct fb_info_control *) info;
+	struct fb_par_control par;
+	int err;
+
+	if((err = control_var_to_par(&info->var, &par, info))) {
+		printk (KERN_ERR "controlfb_set_par: error calling"
+				 " control_var_to_par: %d.\n", err);
+		return err;
+	}
+	
+	control_set_hardware(p, &par);
+
+	info->fix.visual = (p->par.cmode == CMODE_8) ?
+		FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
+	info->fix.line_length = p->par.pitch;
+	info->fix.xpanstep = 32 >> p->par.cmode;
+	info->fix.ypanstep = 1;
+
+	return 0;
+}
+
+/*
+ * Set screen start address according to var offset values
+ */
+static inline void set_screen_start(int xoffset, int yoffset,
+	struct fb_info_control *p)
+{
+	struct fb_par_control *par = &p->par;
+
+	par->xoffset = xoffset;
+	par->yoffset = yoffset;
+	out_le32(CNTRL_REG(p,start_addr),
+		 par->yoffset * par->pitch + (par->xoffset << par->cmode));
+}
+
+
+static int controlfb_pan_display(struct fb_var_screeninfo *var,
+				 struct fb_info *info)
+{
+	unsigned int xoffset, hstep;
+	struct fb_info_control *p = (struct fb_info_control *)info;
+	struct fb_par_control *par = &p->par;
+
+	/*
+	 * make sure start addr will be 32-byte aligned
+	 */
+	hstep = 0x1f >> par->cmode;
+	xoffset = (var->xoffset + hstep) & ~hstep;
+
+	if (xoffset+par->xres > par->vxres ||
+	    var->yoffset+par->yres > par->vyres)
+		return -EINVAL;
+
+	set_screen_start(xoffset, var->yoffset, p);
+
+	return 0;
+}
+
+
+/*
+ * Private mmap since we want to have a different caching on the framebuffer
+ * for controlfb.
+ * Note there's no locking in here; it's done in fb_mmap() in fbmem.c.
+ */
+static int controlfb_mmap(struct fb_info *info, struct file *file,
+                       struct vm_area_struct *vma)
+{
+       unsigned long off, start;
+       u32 len;
+
+       off = vma->vm_pgoff << PAGE_SHIFT;
+
+       /* frame buffer memory */
+       start = info->fix.smem_start;
+       len = PAGE_ALIGN((start & ~PAGE_MASK)+info->fix.smem_len);
+       if (off >= len) {
+               /* memory mapped io */
+               off -= len;
+               if (info->var.accel_flags)
+                       return -EINVAL;
+               start = info->fix.mmio_start;
+               len = PAGE_ALIGN((start & ~PAGE_MASK)+info->fix.mmio_len);
+               pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED;
+       } else {
+               /* framebuffer */
+               pgprot_val(vma->vm_page_prot) |= _PAGE_WRITETHRU;
+       }
+       start &= PAGE_MASK;
+       if ((vma->vm_end - vma->vm_start + off) > len)
+       		return -EINVAL;
+       off += start;
+       vma->vm_pgoff = off >> PAGE_SHIFT;
+       if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+           vma->vm_end - vma->vm_start, vma->vm_page_prot))
+               return -EAGAIN;
+
+       return 0;
+}
+
+static int controlfb_blank(int blank_mode, struct fb_info *info)
+{
+	struct fb_info_control *p = (struct fb_info_control *) info;
+	unsigned ctrl;
+
+	ctrl = ld_le32(CNTRL_REG(p,ctrl));
+	if (blank_mode > 0)
+		switch (blank_mode) {
+		case FB_BLANK_VSYNC_SUSPEND:
+			ctrl &= ~3;
+			break;
+		case FB_BLANK_HSYNC_SUSPEND:
+			ctrl &= ~0x30;
+			break;
+		case FB_BLANK_POWERDOWN:
+			ctrl &= ~0x33;
+			/* fall through */
+		case FB_BLANK_NORMAL:
+			ctrl |= 0x400;
+			break;
+		default:
+			break;
+		}
+	else {
+		ctrl &= ~0x400;
+		ctrl |= 0x33;
+	}
+	out_le32(CNTRL_REG(p,ctrl), ctrl);
+
+	return 0;
+}
+
+static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			     u_int transp, struct fb_info *info)
+{
+	struct fb_info_control *p = (struct fb_info_control *) info;
+	__u8 r, g, b;
+
+	if (regno > 255)
+		return 1;
+
+	r = red >> 8;
+	g = green >> 8;
+	b = blue >> 8;
+
+	out_8(&p->cmap_regs->addr, regno);	/* tell clut what addr to fill	*/
+	out_8(&p->cmap_regs->lut, r);		/* send one color channel at	*/
+	out_8(&p->cmap_regs->lut, g);		/* a time...			*/
+	out_8(&p->cmap_regs->lut, b);
+
+	if (regno < 16) {
+		int i;
+		switch (p->par.cmode) {
+		case CMODE_16:
+			p->pseudo_palette[regno] =
+			    (regno << 10) | (regno << 5) | regno;
+			break;
+		case CMODE_32:
+			i = (regno << 8) | regno;
+			p->pseudo_palette[regno] = (i << 16) | i;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+
+/********************  End of controlfb_ops implementation  ******************/
+
+
+
+static void set_control_clock(unsigned char *params)
+{
+#ifdef CONFIG_ADB_CUDA
+	struct adb_request req;
+	int i;
+
+	for (i = 0; i < 3; ++i) {
+		cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+			     0x50, i + 1, params[i]);
+		while (!req.complete)
+			cuda_poll();
+	}
+#endif	
+}
+
+
+/*
+ * finish off the driver initialization and register
+ */
+static int __init init_control(struct fb_info_control *p)
+{
+	int full, sense, vmode, cmode, vyres;
+	struct fb_var_screeninfo var;
+	int rc;
+	
+	printk(KERN_INFO "controlfb: ");
+
+	full = p->total_vram == 0x400000;
+
+	/* Try to pick a video mode out of NVRAM if we have one. */
+	if (default_cmode == CMODE_NVRAM){
+		cmode = nvram_read_byte(NV_CMODE);
+		if(cmode < CMODE_8 || cmode > CMODE_32)
+			cmode = CMODE_8;
+	} else
+		cmode=default_cmode;
+
+	if (default_vmode == VMODE_NVRAM) {
+		vmode = nvram_read_byte(NV_VMODE);
+		if (vmode < 1 || vmode > VMODE_MAX ||
+		    control_mac_modes[vmode - 1].m[full] < cmode) {
+			sense = read_control_sense(p);
+			printk("Monitor sense value = 0x%x, ", sense);
+			vmode = mac_map_monitor_sense(sense);
+			if (control_mac_modes[vmode - 1].m[full] < cmode)
+				vmode = VMODE_640_480_60;
+		}
+	} else {
+		vmode=default_vmode;
+		if (control_mac_modes[vmode - 1].m[full] < cmode) {
+			if (cmode > CMODE_8)
+				cmode--;
+			else
+				vmode = VMODE_640_480_60;
+		}
+	}
+
+	/* Initialize info structure */
+	control_init_info(&p->info, p);
+
+	/* Setup default var */
+	if (mac_vmode_to_var(vmode, cmode, &var) < 0) {
+		/* This shouldn't happen! */
+		printk("mac_vmode_to_var(%d, %d,) failed\n", vmode, cmode);
+try_again:
+		vmode = VMODE_640_480_60;
+		cmode = CMODE_8;
+		if (mac_vmode_to_var(vmode, cmode, &var) < 0) {
+			printk(KERN_ERR "controlfb: mac_vmode_to_var() failed\n");
+			return -ENXIO;
+		}
+		printk(KERN_INFO "controlfb: ");
+	}
+	printk("using video mode %d and color mode %d.\n", vmode, cmode);
+
+	vyres = (p->total_vram - CTRLFB_OFF) / (var.xres << cmode);
+	if (vyres > var.yres)
+		var.yres_virtual = vyres;
+
+	/* Apply default var */
+	var.activate = FB_ACTIVATE_NOW;
+	rc = fb_set_var(&p->info, &var);
+	if (rc && (vmode != VMODE_640_480_60 || cmode != CMODE_8))
+		goto try_again;
+
+	/* Register with fbdev layer */
+	if (register_framebuffer(&p->info) < 0)
+		return -ENXIO;
+	
+	printk(KERN_INFO "fb%d: control display adapter\n", p->info.node);	
+
+	return 0;
+}
+
+#define RADACAL_WRITE(a,d) \
+	out_8(&p->cmap_regs->addr, (a)); \
+	out_8(&p->cmap_regs->dat,   (d))
+
+/* Now how about actually saying, Make it so! */
+/* Some things in here probably don't need to be done each time. */
+static void control_set_hardware(struct fb_info_control *p, struct fb_par_control *par)
+{
+	struct control_regvals	*r;
+	volatile struct preg	__iomem *rp;
+	int			i, cmode;
+
+	if (PAR_EQUAL(&p->par, par)) {
+		/*
+		 * check if only xoffset or yoffset differs.
+		 * this prevents flickers in typical VT switch case.
+		 */
+		if (p->par.xoffset != par->xoffset ||
+		    p->par.yoffset != par->yoffset)
+			set_screen_start(par->xoffset, par->yoffset, p);
+			
+		return;
+	}
+	
+	p->par = *par;
+	cmode = p->par.cmode;
+	r = &par->regvals;
+	
+	/* Turn off display */
+	out_le32(CNTRL_REG(p,ctrl), 0x400 | par->ctrl);
+	
+	set_control_clock(r->clock_params);
+	
+	RADACAL_WRITE(0x20, r->radacal_ctrl);
+	RADACAL_WRITE(0x21, p->control_use_bank2 ? 0 : 1);
+	RADACAL_WRITE(0x10, 0);
+	RADACAL_WRITE(0x11, 0);
+
+	rp = &p->control_regs->vswin;
+	for (i = 0; i < 16; ++i, ++rp)
+		out_le32(&rp->r, r->regs[i]);
+	
+	out_le32(CNTRL_REG(p,pitch), par->pitch);
+	out_le32(CNTRL_REG(p,mode), r->mode);
+	out_le32(CNTRL_REG(p,vram_attr), p->vram_attr);
+	out_le32(CNTRL_REG(p,start_addr), par->yoffset * par->pitch
+		 + (par->xoffset << cmode));
+	out_le32(CNTRL_REG(p,rfrcnt), 0x1e5);
+	out_le32(CNTRL_REG(p,intr_ena), 0);
+
+	/* Turn on display */
+	out_le32(CNTRL_REG(p,ctrl), par->ctrl);
+
+#ifdef CONFIG_BOOTX_TEXT
+	btext_update_display(p->frame_buffer_phys + CTRLFB_OFF,
+			     p->par.xres, p->par.yres,
+			     (cmode == CMODE_32? 32: cmode == CMODE_16? 16: 8),
+			     p->par.pitch);
+#endif /* CONFIG_BOOTX_TEXT */
+}
+
+
+/*
+ * Called from fbmem.c for probing & initializing
+ */
+int __init control_init(void)
+{
+	struct device_node *dp;
+	char *option = NULL;
+
+	if (fb_get_options("controlfb", &option))
+		return -ENODEV;
+	control_setup(option);
+
+	dp = find_devices("control");
+	if (dp != 0 && !control_of_init(dp))
+		return 0;
+
+	return -ENXIO;
+}
+
+module_init(control_init);
+
+/* Work out which banks of VRAM we have installed. */
+/* danj: I guess the card just ignores writes to nonexistant VRAM... */
+
+static void __init find_vram_size(struct fb_info_control *p)
+{
+	int bank1, bank2;
+
+	/*
+	 * Set VRAM in 2MB (bank 1) mode
+	 * VRAM Bank 2 will be accessible through offset 0x600000 if present
+	 * and VRAM Bank 1 will not respond at that offset even if present
+	 */
+	out_le32(CNTRL_REG(p,vram_attr), 0x31);
+
+	out_8(&p->frame_buffer[0x600000], 0xb3);
+	out_8(&p->frame_buffer[0x600001], 0x71);
+	asm volatile("eieio; dcbf 0,%0" : : "r" (&p->frame_buffer[0x600000])
+					: "memory" );
+	mb();
+	asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x600000])
+					: "memory" );
+	mb();
+
+	bank2 = (in_8(&p->frame_buffer[0x600000]) == 0xb3)
+		&& (in_8(&p->frame_buffer[0x600001]) == 0x71);
+
+	/*
+	 * Set VRAM in 2MB (bank 2) mode
+	 * VRAM Bank 1 will be accessible through offset 0x000000 if present
+	 * and VRAM Bank 2 will not respond at that offset even if present
+	 */
+	out_le32(CNTRL_REG(p,vram_attr), 0x39);
+
+	out_8(&p->frame_buffer[0], 0x5a);
+	out_8(&p->frame_buffer[1], 0xc7);
+	asm volatile("eieio; dcbf 0,%0" : : "r" (&p->frame_buffer[0])
+					: "memory" );
+	mb();
+	asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0])
+					: "memory" );
+	mb();
+
+	bank1 = (in_8(&p->frame_buffer[0]) == 0x5a)
+		&& (in_8(&p->frame_buffer[1]) == 0xc7);
+
+	if (bank2) {
+		if (!bank1) {
+			/*
+			 * vram bank 2 only
+			 */
+			p->control_use_bank2 = 1;
+			p->vram_attr = 0x39;
+			p->frame_buffer += 0x600000;
+			p->frame_buffer_phys += 0x600000;
+		} else {
+			/*
+			 * 4 MB vram
+			 */
+			p->vram_attr = 0x51;
+		}
+	} else {
+		/*
+		 * vram bank 1 only
+		 */
+		p->vram_attr = 0x31;
+	}
+
+        p->total_vram = (bank1 + bank2) * 0x200000;
+
+	printk(KERN_INFO "controlfb: VRAM Total = %dMB "
+			"(%dMB @ bank 1, %dMB @ bank 2)\n",
+			(bank1 + bank2) << 1, bank1 << 1, bank2 << 1);
+}
+
+
+/*
+ * find "control" and initialize
+ */
+static int __init control_of_init(struct device_node *dp)
+{
+	struct fb_info_control	*p;
+	unsigned long		addr;
+	int			i;
+
+	if (control_fb) {
+		printk(KERN_ERR "controlfb: only one control is supported\n");
+		return -ENXIO;
+	}
+	if(dp->n_addrs != 2) {
+		printk(KERN_ERR "expecting 2 address for control (got %d)", dp->n_addrs);
+		return -ENXIO;
+	}
+	p = kmalloc(sizeof(*p), GFP_KERNEL);
+	if (p == 0)
+		return -ENXIO;
+	control_fb = p;	/* save it for cleanups */
+	memset(p, 0, sizeof(*p));
+
+	/* Map in frame buffer and registers */
+	for (i = 0; i < dp->n_addrs; ++i) {
+		addr = dp->addrs[i].address;
+		if (dp->addrs[i].size >= 0x800000) {
+			p->fb_orig_base = addr;
+			p->fb_orig_size = dp->addrs[i].size;
+			/* use the big-endian aperture (??) */
+			p->frame_buffer_phys = addr + 0x800000;
+		} else {
+			p->control_regs_phys = addr;
+			p->control_regs_size = dp->addrs[i].size;
+		}
+	}
+
+	if (!p->fb_orig_base ||
+	    !request_mem_region(p->fb_orig_base,p->fb_orig_size,"controlfb")) {
+		p->fb_orig_base = 0;
+		goto error_out;
+	}
+	/* map at most 8MB for the frame buffer */
+	p->frame_buffer = __ioremap(p->frame_buffer_phys, 0x800000,
+				    _PAGE_WRITETHRU);
+
+	if (!p->control_regs_phys ||
+	    !request_mem_region(p->control_regs_phys, p->control_regs_size,
+	    "controlfb regs")) {
+		p->control_regs_phys = 0;
+		goto error_out;
+	}
+	p->control_regs = ioremap(p->control_regs_phys, p->control_regs_size);
+
+	p->cmap_regs_phys = 0xf301b000;	 /* XXX not in prom? */
+	if (!request_mem_region(p->cmap_regs_phys, 0x1000, "controlfb cmap")) {
+		p->cmap_regs_phys = 0;
+		goto error_out;
+	}
+	p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000);
+
+	if (!p->cmap_regs || !p->control_regs || !p->frame_buffer)
+		goto error_out;
+
+	find_vram_size(p);
+	if (!p->total_vram)
+		goto error_out;
+
+	if (init_control(p) < 0)
+		goto error_out;
+
+	return 0;
+
+error_out:
+	control_cleanup();
+	return -ENXIO;
+}
+
+/*
+ * Get the monitor sense value.
+ * Note that this can be called before calibrate_delay,
+ * so we can't use udelay.
+ */
+static int read_control_sense(struct fb_info_control *p)
+{
+	int sense;
+
+	out_le32(CNTRL_REG(p,mon_sense), 7);	/* drive all lines high */
+	__delay(200);
+	out_le32(CNTRL_REG(p,mon_sense), 077);	/* turn off drivers */
+	__delay(2000);
+	sense = (in_le32(CNTRL_REG(p,mon_sense)) & 0x1c0) << 2;
+
+	/* drive each sense line low in turn and collect the other 2 */
+	out_le32(CNTRL_REG(p,mon_sense), 033);	/* drive A low */
+	__delay(2000);
+	sense |= (in_le32(CNTRL_REG(p,mon_sense)) & 0xc0) >> 2;
+	out_le32(CNTRL_REG(p,mon_sense), 055);	/* drive B low */
+	__delay(2000);
+	sense |= ((in_le32(CNTRL_REG(p,mon_sense)) & 0x100) >> 5)
+		| ((in_le32(CNTRL_REG(p,mon_sense)) & 0x40) >> 4);
+	out_le32(CNTRL_REG(p,mon_sense), 066);	/* drive C low */
+	__delay(2000);
+	sense |= (in_le32(CNTRL_REG(p,mon_sense)) & 0x180) >> 7;
+
+	out_le32(CNTRL_REG(p,mon_sense), 077);	/* turn off drivers */
+	
+	return sense;
+}
+
+/**********************  Various translation functions  **********************/
+
+#define CONTROL_PIXCLOCK_BASE	256016
+#define CONTROL_PIXCLOCK_MIN	5000	/* ~ 200 MHz dot clock */
+
+/*
+ * calculate the clock paramaters to be sent to CUDA according to given
+ * pixclock in pico second.
+ */
+static int calc_clock_params(unsigned long clk, unsigned char *param)
+{
+	unsigned long p0, p1, p2, k, l, m, n, min;
+
+	if (clk > (CONTROL_PIXCLOCK_BASE << 3))
+		return 1;
+
+	p2 = ((clk << 4) < CONTROL_PIXCLOCK_BASE)? 3: 2;
+	l = clk << p2;
+	p0 = 0;
+	p1 = 0;
+	for (k = 1, min = l; k < 32; k++) {
+		unsigned long rem;
+
+		m = CONTROL_PIXCLOCK_BASE * k;
+		n = m / l;
+		rem = m % l;
+		if (n && (n < 128) && rem < min) {
+			p0 = k;
+			p1 = n;
+			min = rem;
+		}
+	}
+	if (!p0 || !p1)
+		return 1;
+
+	param[0] = p0;
+	param[1] = p1;
+	param[2] = p2;
+
+	return 0;
+}
+
+
+/*
+ * This routine takes a user-supplied var, and picks the best vmode/cmode
+ * from it.
+ */
+
+static int control_var_to_par(struct fb_var_screeninfo *var,
+	struct fb_par_control *par, const struct fb_info *fb_info)
+{
+	int cmode, piped_diff, hstep;
+	unsigned hperiod, hssync, hsblank, hesync, heblank, piped, heq, hlfln,
+		 hserr, vperiod, vssync, vesync, veblank, vsblank, vswin, vewin;
+	unsigned long pixclock;
+	struct fb_info_control *p = (struct fb_info_control *) fb_info;
+	struct control_regvals *r = &par->regvals;
+
+	switch (var->bits_per_pixel) {
+	case 8:
+		par->cmode = CMODE_8;
+		if (p->total_vram > 0x200000) {
+			r->mode = 3;
+			r->radacal_ctrl = 0x20;
+			piped_diff = 13;
+		} else {
+			r->mode = 2;
+			r->radacal_ctrl = 0x10;
+			piped_diff = 9;
+		}
+		break;
+	case 15:
+	case 16:
+		par->cmode = CMODE_16;
+		if (p->total_vram > 0x200000) {
+			r->mode = 2;
+			r->radacal_ctrl = 0x24;
+			piped_diff = 5;
+		} else {
+			r->mode = 1;
+			r->radacal_ctrl = 0x14;
+			piped_diff = 3;
+		}
+		break;
+	case 32:
+		par->cmode = CMODE_32;
+		if (p->total_vram > 0x200000) {
+			r->mode = 1;
+			r->radacal_ctrl = 0x28;
+		} else {
+			r->mode = 0;
+			r->radacal_ctrl = 0x18;
+		}
+		piped_diff = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/*
+	 * adjust xres and vxres so that the corresponding memory widths are
+	 * 32-byte aligned
+	 */
+	hstep = 31 >> par->cmode;
+	par->xres = (var->xres + hstep) & ~hstep;
+	par->vxres = (var->xres_virtual + hstep) & ~hstep;
+	par->xoffset = (var->xoffset + hstep) & ~hstep;
+	if (par->vxres < par->xres)
+		par->vxres = par->xres;
+	par->pitch = par->vxres << par->cmode;
+
+	par->yres = var->yres;
+	par->vyres = var->yres_virtual;
+	par->yoffset = var->yoffset;
+	if (par->vyres < par->yres)
+		par->vyres = par->yres;
+
+	par->sync = var->sync;
+
+	if (par->pitch * par->vyres + CTRLFB_OFF > p->total_vram)
+		return -EINVAL;
+
+	if (par->xoffset + par->xres > par->vxres)
+		par->xoffset = par->vxres - par->xres;
+	if (par->yoffset + par->yres > par->vyres)
+		par->yoffset = par->vyres - par->yres;
+
+	pixclock = (var->pixclock < CONTROL_PIXCLOCK_MIN)? CONTROL_PIXCLOCK_MIN:
+		   var->pixclock;
+	if (calc_clock_params(pixclock, r->clock_params))
+		return -EINVAL;
+
+	hperiod = ((var->left_margin + par->xres + var->right_margin
+		    + var->hsync_len) >> 1) - 2;
+	hssync = hperiod + 1;
+	hsblank = hssync - (var->right_margin >> 1);
+	hesync = (var->hsync_len >> 1) - 1;
+	heblank = (var->left_margin >> 1) + hesync;
+	piped = heblank - piped_diff;
+	heq = var->hsync_len >> 2;
+	hlfln = (hperiod+2) >> 1;
+	hserr = hssync-hesync;
+	vperiod = (var->vsync_len + var->lower_margin + par->yres
+		   + var->upper_margin) << 1;
+	vssync = vperiod - 2;
+	vesync = (var->vsync_len << 1) - vperiod + vssync;
+	veblank = (var->upper_margin << 1) + vesync;
+	vsblank = vssync - (var->lower_margin << 1);
+	vswin = (vsblank+vssync) >> 1;
+	vewin = (vesync+veblank) >> 1;
+
+	r->regs[0] = vswin;
+	r->regs[1] = vsblank;
+	r->regs[2] = veblank;
+	r->regs[3] = vewin;
+	r->regs[4] = vesync;
+	r->regs[5] = vssync;
+	r->regs[6] = vperiod;
+	r->regs[7] = piped;
+	r->regs[8] = hperiod;
+	r->regs[9] = hsblank;
+	r->regs[10] = heblank;
+	r->regs[11] = hesync;
+	r->regs[12] = hssync;
+	r->regs[13] = heq;
+	r->regs[14] = hlfln;
+	r->regs[15] = hserr;
+
+	if (par->xres >= 1280 && par->cmode >= CMODE_16)
+		par->ctrl = 0x7f;
+	else
+		par->ctrl = 0x3b;
+
+	if (mac_var_to_vmode(var, &par->vmode, &cmode))
+		par->vmode = 0;
+
+	return 0;
+}
+
+
+/*
+ * Convert hardware data in par to an fb_var_screeninfo
+ */
+
+static void control_par_to_var(struct fb_par_control *par, struct fb_var_screeninfo *var)
+{
+	struct control_regints *rv;
+	
+	rv = (struct control_regints *) par->regvals.regs;
+	
+	memset(var, 0, sizeof(*var));
+	var->xres = par->xres;
+	var->yres = par->yres;
+	var->xres_virtual = par->vxres;
+	var->yres_virtual = par->vyres;
+	var->xoffset = par->xoffset;
+	var->yoffset = par->yoffset;
+	
+	switch(par->cmode) {
+	default:
+	case CMODE_8:
+		var->bits_per_pixel = 8;
+		var->red.length = 8;
+		var->green.length = 8;
+		var->blue.length = 8;
+		break;
+	case CMODE_16:	/* RGB 555 */
+		var->bits_per_pixel = 16;
+		var->red.offset = 10;
+		var->red.length = 5;
+		var->green.offset = 5;
+		var->green.length = 5;
+		var->blue.length = 5;
+		break;
+	case CMODE_32:	/* RGB 888 */
+		var->bits_per_pixel = 32;
+		var->red.offset = 16;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.length = 8;
+		var->transp.offset = 24;
+		var->transp.length = 8;
+		break;
+	}
+	var->height = -1;
+	var->width = -1;
+	var->vmode = FB_VMODE_NONINTERLACED;
+
+	var->left_margin = (rv->heblank - rv->hesync) << 1;
+	var->right_margin = (rv->hssync - rv->hsblank) << 1;
+	var->hsync_len = (rv->hperiod + 2 - rv->hssync + rv->hesync) << 1;
+
+	var->upper_margin = (rv->veblank - rv->vesync) >> 1;
+	var->lower_margin = (rv->vssync - rv->vsblank) >> 1;
+	var->vsync_len = (rv->vperiod - rv->vssync + rv->vesync) >> 1;
+
+	var->sync = par->sync;
+
+	/*
+	 * 10^12 * clock_params[0] / (3906400 * clock_params[1]
+	 *			      * 2^clock_params[2])
+	 * (10^12 * clock_params[0] / (3906400 * clock_params[1]))
+	 * >> clock_params[2]
+	 */
+	/* (255990.17 * clock_params[0] / clock_params[1]) >> clock_params[2] */
+	var->pixclock = CONTROL_PIXCLOCK_BASE * par->regvals.clock_params[0];
+	var->pixclock /= par->regvals.clock_params[1];
+	var->pixclock >>= par->regvals.clock_params[2];
+}
+
+/*
+ * Set misc info vars for this driver
+ */
+static void __init control_init_info(struct fb_info *info, struct fb_info_control *p)
+{
+	/* Fill fb_info */
+	info->par = &p->par;
+	info->fbops = &controlfb_ops;
+	info->pseudo_palette = p->pseudo_palette;
+        info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+	info->screen_base = p->frame_buffer + CTRLFB_OFF;
+
+	fb_alloc_cmap(&info->cmap, 256, 0);
+
+	/* Fill fix common fields */
+	strcpy(info->fix.id, "control");
+	info->fix.mmio_start = p->control_regs_phys;
+	info->fix.mmio_len = sizeof(struct control_regs);
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.smem_start = p->frame_buffer_phys + CTRLFB_OFF;
+	info->fix.smem_len = p->total_vram - CTRLFB_OFF;
+        info->fix.ywrapstep = 0;
+        info->fix.type_aux = 0;
+        info->fix.accel = FB_ACCEL_NONE;
+}
+
+
+static void control_cleanup(void)
+{
+	struct fb_info_control	*p = control_fb;
+
+	if (!p)
+		return;
+
+	if (p->cmap_regs)
+		iounmap(p->cmap_regs);
+	if (p->control_regs)
+		iounmap(p->control_regs);
+	if (p->frame_buffer) {
+		if (p->control_use_bank2)
+			p->frame_buffer -= 0x600000;
+		iounmap(p->frame_buffer);
+	}
+	if (p->cmap_regs_phys)
+		release_mem_region(p->cmap_regs_phys, 0x1000);
+	if (p->control_regs_phys)
+		release_mem_region(p->control_regs_phys, p->control_regs_size);
+	if (p->fb_orig_base)
+		release_mem_region(p->fb_orig_base, p->fb_orig_size);
+	kfree(p);
+}
+
+
+/*
+ * Parse user speficied options (`video=controlfb:')
+ */
+void __init control_setup(char *options)
+{
+	char *this_opt;
+
+	if (!options || !*options)
+		return;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!strncmp(this_opt, "vmode:", 6)) {
+			int vmode = simple_strtoul(this_opt+6, NULL, 0);
+			if (vmode > 0 && vmode <= VMODE_MAX &&
+			    control_mac_modes[vmode - 1].m[1] >= 0)
+				default_vmode = vmode;
+		} else if (!strncmp(this_opt, "cmode:", 6)) {
+			int depth = simple_strtoul(this_opt+6, NULL, 0);
+			switch (depth) {
+			 case CMODE_8:
+			 case CMODE_16:
+			 case CMODE_32:
+			 	default_cmode = depth;
+			 	break;
+			 case 8:
+				default_cmode = CMODE_8;
+				break;
+			 case 15:
+			 case 16:
+				default_cmode = CMODE_16;
+				break;
+			 case 24:
+			 case 32:
+				default_cmode = CMODE_32;
+				break;
+			}
+		}
+	}
+}
+
diff --git a/drivers/video/controlfb.h b/drivers/video/controlfb.h
new file mode 100644
index 0000000..6026c60
--- /dev/null
+++ b/drivers/video/controlfb.h
@@ -0,0 +1,145 @@
+/*
+ * controlfb_hw.h: Constants of all sorts for controlfb
+ *
+ * Copyright (C) 1998 Daniel Jacobowitz <dan@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Based on an awful lot of code, including:
+ *
+ * control.c: Console support for PowerMac "control" display adaptor.
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * The so far unpublished platinumfb.c
+ * Copyright (C) 1998 Jon Howell
+ */
+
+/*
+ * Structure of the registers for the RADACAL colormap device.
+ */
+struct cmap_regs {
+	unsigned char addr;	/* index for both cmap and misc registers */
+	char pad1[15];
+	unsigned char crsr;	/* cursor palette */
+	char pad2[15];
+	unsigned char dat;	/* RADACAL misc register data */
+	char pad3[15];
+	unsigned char lut;	/* cmap data */
+	char pad4[15];
+};
+
+/*
+ * Structure of the registers for the "control" display adaptor.
+ */
+#define PAD(x)	char x[12]
+
+struct preg {			/* padded register */
+	unsigned r;
+	char pad[12];
+};
+
+struct control_regs {
+	struct preg vcount;	/* vertical counter */
+	/* Vertical parameters are in units of 1/2 scan line */
+	struct preg vswin;	/* between vsblank and vssync */
+	struct preg vsblank;	/* vert start blank */
+	struct preg veblank;	/* vert end blank (display start) */
+	struct preg vewin;	/* between vesync and veblank */
+	struct preg vesync;	/* vert end sync */
+	struct preg vssync;	/* vert start sync */
+	struct preg vperiod;	/* vert period */
+	struct preg piped;	/* pipe delay hardware cursor */
+	/* Horizontal params are in units of 2 pixels */
+	struct preg hperiod;	/* horiz period - 2 */
+	struct preg hsblank;	/* horiz start blank */
+	struct preg heblank;	/* horiz end blank */
+	struct preg hesync;	/* horiz end sync */
+	struct preg hssync;	/* horiz start sync */
+	struct preg heq;	/* half horiz sync len */
+	struct preg hlfln;	/* half horiz period */
+	struct preg hserr;	/* horiz period - horiz sync len */
+	struct preg cnttst;
+	struct preg ctrl;	/* display control */
+	struct preg start_addr;	/* start address: 5 lsbs zero */
+	struct preg pitch;	/* addrs diff between scan lines */
+	struct preg mon_sense;	/* monitor sense bits */
+	struct preg vram_attr;	/* enable vram banks */
+	struct preg mode;
+	struct preg rfrcnt;	/* refresh count */
+	struct preg intr_ena;	/* interrupt enable */
+	struct preg intr_stat;	/* interrupt status */
+	struct preg res[5];
+};
+
+struct control_regints {
+	/* Vertical parameters are in units of 1/2 scan line */
+	unsigned vswin;	/* between vsblank and vssync */
+	unsigned vsblank;	/* vert start blank */
+	unsigned veblank;	/* vert end blank (display start) */
+	unsigned vewin;	/* between vesync and veblank */
+	unsigned vesync;	/* vert end sync */
+	unsigned vssync;	/* vert start sync */
+	unsigned vperiod;	/* vert period */
+	unsigned piped;		/* pipe delay hardware cursor */
+	/* Horizontal params are in units of 2 pixels */
+	/* Except, apparently, for hres > 1024 (or == 1280?) */
+	unsigned hperiod;	/* horiz period - 2 */
+	unsigned hsblank;	/* horiz start blank */
+	unsigned heblank;	/* horiz end blank */
+	unsigned hesync;	/* horiz end sync */
+	unsigned hssync;	/* horiz start sync */
+	unsigned heq;		/* half horiz sync len */
+	unsigned hlfln;		/* half horiz period */
+	unsigned hserr;		/* horiz period - horiz sync len */
+};
+	
+/*
+ * Dot clock rate is
+ * 3.9064MHz * 2**clock_params[2] * clock_params[1] / clock_params[0].
+ */
+struct control_regvals {
+	unsigned regs[16];		/* for vswin .. hserr */
+	unsigned char mode;
+	unsigned char radacal_ctrl;
+	unsigned char clock_params[3];
+};
+
+#define CTRLFB_OFF 16	/* position of pixel 0 in frame buffer */
+
+
+/*
+ * Best cmode supported by control
+ */
+struct max_cmodes {
+	int m[2];	/* 0: 2MB vram, 1: 4MB vram */
+};
+
+/*
+ * Video modes supported by macmodes.c
+ */
+static struct max_cmodes control_mac_modes[] = {
+	{{-1,-1}},	/* 512x384, 60Hz interlaced (NTSC) */
+	{{-1,-1}},	/* 512x384, 60Hz */
+	{{-1,-1}},	/* 640x480, 50Hz interlaced (PAL) */
+	{{-1,-1}},	/* 640x480, 60Hz interlaced (NTSC) */
+	{{ 2, 2}},	/* 640x480, 60Hz (VGA) */
+	{{ 2, 2}},	/* 640x480, 67Hz */
+	{{-1,-1}},	/* 640x870, 75Hz (portrait) */
+	{{-1,-1}},	/* 768x576, 50Hz (PAL full frame) */
+	{{ 2, 2}},	/* 800x600, 56Hz */
+	{{ 2, 2}},	/* 800x600, 60Hz */
+	{{ 2, 2}},	/* 800x600, 72Hz */
+	{{ 2, 2}},	/* 800x600, 75Hz */
+	{{ 1, 2}},	/* 832x624, 75Hz */
+	{{ 1, 2}},	/* 1024x768, 60Hz */
+	{{ 1, 2}},	/* 1024x768, 70Hz (or 72Hz?) */
+	{{ 1, 2}},	/* 1024x768, 75Hz (VESA) */
+	{{ 1, 2}},	/* 1024x768, 75Hz */
+	{{ 1, 2}},	/* 1152x870, 75Hz */
+	{{ 0, 1}},	/* 1280x960, 75Hz */
+	{{ 0, 1}},	/* 1280x1024, 75Hz */
+};
+
diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c
new file mode 100644
index 0000000..8b1b7c6
--- /dev/null
+++ b/drivers/video/cyber2000fb.c
@@ -0,0 +1,1761 @@
+/*
+ *  linux/drivers/video/cyber2000fb.c
+ *
+ *  Copyright (C) 1998-2002 Russell King
+ *
+ *  MIPS and 50xx clock support
+ *  Copyright (C) 2001 Bradley D. LaRonde <brad@ltc.com>
+ *
+ *  32 bit support, text color and panning fixes for modes != 8 bit
+ *  Copyright (C) 2002 Denis Oliver Kropp <dok@directfb.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Integraphics CyberPro 2000, 2010 and 5000 frame buffer device
+ *
+ * Based on cyberfb.c.
+ *
+ * Note that we now use the new fbcon fix, var and cmap scheme.  We do
+ * still have to check which console is the currently displayed one
+ * however, especially for the colourmap stuff.
+ *
+ * We also use the new hotplug PCI subsystem.  I'm not sure if there
+ * are any such cards, but I'm erring on the side of caution.  We don't
+ * want to go pop just because someone does have one.
+ *
+ * Note that this doesn't work fully in the case of multiple CyberPro
+ * cards with grabbers.  We currently can only attach to the first
+ * CyberPro card found.
+ *
+ * When we're in truecolour mode, we power down the LUT RAM as a power
+ * saving feature.  Also, when we enter any of the powersaving modes
+ * (except soft blanking) we power down the RAMDACs.  This saves about
+ * 1W, which is roughly 8% of the power consumption of a NetWinder
+ * (which, incidentally, is about the same saving as a 2.5in hard disk
+ * entering standby mode.)
+ */
+#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/delay.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#ifdef __arm__
+#include <asm/mach-types.h>
+#endif
+
+#include "cyber2000fb.h"
+
+struct cfb_info {
+	struct fb_info		fb;
+	struct display_switch	*dispsw;
+	struct display		*display;
+	struct pci_dev		*dev;
+	unsigned char 		__iomem *region;
+	unsigned char		__iomem *regs;
+	u_int			id;
+	int			func_use_count;
+	u_long			ref_ps;
+
+	/*
+	 * Clock divisors
+	 */
+	u_int			divisors[4];
+
+	struct {
+		u8 red, green, blue;
+	} palette[NR_PALETTE];
+
+	u_char			mem_ctl1;
+	u_char			mem_ctl2;
+	u_char			mclk_mult;
+	u_char			mclk_div;
+	/*
+	 * RAMDAC control register is both of these or'ed together
+	 */
+	u_char			ramdac_ctrl;
+	u_char			ramdac_powerdown;
+};
+
+static char *default_font = "Acorn8x8";
+module_param(default_font, charp, 0);
+MODULE_PARM_DESC(default_font, "Default font name");
+
+/*
+ * Our access methods.
+ */
+#define cyber2000fb_writel(val,reg,cfb)	writel(val, (cfb)->regs + (reg))
+#define cyber2000fb_writew(val,reg,cfb)	writew(val, (cfb)->regs + (reg))
+#define cyber2000fb_writeb(val,reg,cfb)	writeb(val, (cfb)->regs + (reg))
+
+#define cyber2000fb_readb(reg,cfb)	readb((cfb)->regs + (reg))
+
+static inline void
+cyber2000_crtcw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
+{
+	cyber2000fb_writew((reg & 255) | val << 8, 0x3d4, cfb);
+}
+
+static inline void
+cyber2000_grphw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
+{
+	cyber2000fb_writew((reg & 255) | val << 8, 0x3ce, cfb);
+}
+
+static inline unsigned int
+cyber2000_grphr(unsigned int reg, struct cfb_info *cfb)
+{
+	cyber2000fb_writeb(reg, 0x3ce, cfb);
+	return cyber2000fb_readb(0x3cf, cfb);
+}
+
+static inline void
+cyber2000_attrw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
+{
+	cyber2000fb_readb(0x3da, cfb);
+	cyber2000fb_writeb(reg, 0x3c0, cfb);
+	cyber2000fb_readb(0x3c1, cfb);
+	cyber2000fb_writeb(val, 0x3c0, cfb);
+}
+
+static inline void
+cyber2000_seqw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
+{
+	cyber2000fb_writew((reg & 255) | val << 8, 0x3c4, cfb);
+}
+
+/* -------------------- Hardware specific routines ------------------------- */
+
+/*
+ * Hardware Cyber2000 Acceleration
+ */
+static void
+cyber2000fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+	struct cfb_info *cfb = (struct cfb_info *)info;
+	unsigned long dst, col;
+
+	if (!(cfb->fb.var.accel_flags & FB_ACCELF_TEXT)) {
+		cfb_fillrect(info, rect);
+		return;
+	}
+
+	cyber2000fb_writeb(0, CO_REG_CONTROL, cfb);
+	cyber2000fb_writew(rect->width - 1, CO_REG_PIXWIDTH, cfb);
+	cyber2000fb_writew(rect->height - 1, CO_REG_PIXHEIGHT, cfb);
+
+	col = rect->color;
+	if (cfb->fb.var.bits_per_pixel > 8)
+		col = ((u32 *)cfb->fb.pseudo_palette)[col];
+	cyber2000fb_writel(col, CO_REG_FGCOLOUR, cfb);
+
+	dst = rect->dx + rect->dy * cfb->fb.var.xres_virtual;
+	if (cfb->fb.var.bits_per_pixel == 24) {
+		cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb);
+		dst *= 3;
+	}
+
+	cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
+	cyber2000fb_writeb(CO_FG_MIX_SRC, CO_REG_FGMIX, cfb);
+	cyber2000fb_writew(CO_CMD_L_PATTERN_FGCOL, CO_REG_CMD_L, cfb);
+	cyber2000fb_writew(CO_CMD_H_BLITTER, CO_REG_CMD_H, cfb);
+}
+
+static void
+cyber2000fb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
+{
+	struct cfb_info *cfb = (struct cfb_info *)info;
+	unsigned int cmd = CO_CMD_L_PATTERN_FGCOL;
+	unsigned long src, dst;
+
+	if (!(cfb->fb.var.accel_flags & FB_ACCELF_TEXT)) {
+		cfb_copyarea(info, region);
+		return;
+	}
+
+	cyber2000fb_writeb(0, CO_REG_CONTROL, cfb);
+	cyber2000fb_writew(region->width - 1, CO_REG_PIXWIDTH, cfb);
+	cyber2000fb_writew(region->height - 1, CO_REG_PIXHEIGHT, cfb);
+
+	src = region->sx + region->sy * cfb->fb.var.xres_virtual;
+	dst = region->dx + region->dy * cfb->fb.var.xres_virtual;
+
+	if (region->sx < region->dx) {
+		src += region->width - 1;
+		dst += region->width - 1;
+		cmd |= CO_CMD_L_INC_LEFT;
+	}
+
+	if (region->sy < region->dy) {
+		src += (region->height - 1) * cfb->fb.var.xres_virtual;
+		dst += (region->height - 1) * cfb->fb.var.xres_virtual;
+		cmd |= CO_CMD_L_INC_UP;
+	}
+
+	if (cfb->fb.var.bits_per_pixel == 24) {
+		cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb);
+		src *= 3;
+		dst *= 3;
+	}
+	cyber2000fb_writel(src, CO_REG_SRC1_PTR, cfb);
+	cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
+	cyber2000fb_writew(CO_FG_MIX_SRC, CO_REG_FGMIX, cfb);
+	cyber2000fb_writew(cmd, CO_REG_CMD_L, cfb);
+	cyber2000fb_writew(CO_CMD_H_FGSRCMAP | CO_CMD_H_BLITTER,
+			   CO_REG_CMD_H, cfb);
+}
+
+static void
+cyber2000fb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+//	struct cfb_info *cfb = (struct cfb_info *)info;
+
+//	if (!(cfb->fb.var.accel_flags & FB_ACCELF_TEXT)) {
+		cfb_imageblit(info, image);
+		return;
+//	}
+}
+
+static int cyber2000fb_sync(struct fb_info *info)
+{
+	struct cfb_info *cfb = (struct cfb_info *)info;
+	int count = 100000;
+
+	if (!(cfb->fb.var.accel_flags & FB_ACCELF_TEXT))
+		return 0;
+
+	while (cyber2000fb_readb(CO_REG_CONTROL, cfb) & CO_CTRL_BUSY) {
+		if (!count--) {
+			debug_printf("accel_wait timed out\n");
+			cyber2000fb_writeb(0, CO_REG_CONTROL, cfb);
+			break;
+		}
+		udelay(1);
+	}
+	return 0;
+}
+
+/*
+ * ===========================================================================
+ */
+
+static inline u32 convert_bitfield(u_int val, struct fb_bitfield *bf)
+{
+	u_int mask = (1 << bf->length) - 1;
+
+	return (val >> (16 - bf->length) & mask) << bf->offset;
+}
+
+/*
+ *    Set a single color register. Return != 0 for invalid regno.
+ */
+static int
+cyber2000fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+		      u_int transp, struct fb_info *info)
+{
+	struct cfb_info *cfb = (struct cfb_info *)info;
+	struct fb_var_screeninfo *var = &cfb->fb.var;
+	u32 pseudo_val;
+	int ret = 1;
+
+	switch (cfb->fb.fix.visual) {
+	default:
+		return 1;
+
+	/*
+	 * Pseudocolour:
+	 *         8     8
+	 * pixel --/--+--/-->  red lut  --> red dac
+	 *            |  8
+	 *            +--/--> green lut --> green dac
+	 *            |  8
+	 *            +--/-->  blue lut --> blue dac
+	 */
+	case FB_VISUAL_PSEUDOCOLOR:
+		if (regno >= NR_PALETTE)
+			return 1;
+
+		red >>= 8;
+		green >>= 8;
+		blue >>= 8;
+
+		cfb->palette[regno].red   = red;
+		cfb->palette[regno].green = green;
+		cfb->palette[regno].blue  = blue;
+
+		cyber2000fb_writeb(regno, 0x3c8, cfb);
+		cyber2000fb_writeb(red, 0x3c9, cfb);
+		cyber2000fb_writeb(green, 0x3c9, cfb);
+		cyber2000fb_writeb(blue, 0x3c9, cfb);
+		return 0;
+
+	/*
+	 * Direct colour:
+	 *          n     rl
+	 *  pixel --/--+--/-->  red lut  --> red dac
+	 *             |  gl
+	 *             +--/--> green lut --> green dac
+	 *             |  bl
+	 *             +--/-->  blue lut --> blue dac
+	 * n = bpp, rl = red length, gl = green length, bl = blue length
+	 */
+	case FB_VISUAL_DIRECTCOLOR:
+		red >>= 8;
+		green >>= 8;
+		blue >>= 8;
+
+		if (var->green.length == 6 && regno < 64) {
+			cfb->palette[regno << 2].green = green;
+
+			/*
+			 * The 6 bits of the green component are applied
+			 * to the high 6 bits of the LUT.
+			 */
+			cyber2000fb_writeb(regno << 2, 0x3c8, cfb);
+			cyber2000fb_writeb(cfb->palette[regno >> 1].red, 0x3c9, cfb);
+			cyber2000fb_writeb(green, 0x3c9, cfb);
+			cyber2000fb_writeb(cfb->palette[regno >> 1].blue, 0x3c9, cfb);
+
+			green = cfb->palette[regno << 3].green;
+
+			ret = 0;
+		}
+
+		if (var->green.length >= 5 && regno < 32) {
+			cfb->palette[regno << 3].red   = red;
+			cfb->palette[regno << 3].green = green;
+			cfb->palette[regno << 3].blue  = blue;
+
+			/*
+			 * The 5 bits of each colour component are
+			 * applied to the high 5 bits of the LUT.
+			 */
+			cyber2000fb_writeb(regno << 3, 0x3c8, cfb);
+			cyber2000fb_writeb(red, 0x3c9, cfb);
+			cyber2000fb_writeb(green, 0x3c9, cfb);
+			cyber2000fb_writeb(blue, 0x3c9, cfb);
+			ret = 0;
+		}
+
+		if (var->green.length == 4 && regno < 16) {
+			cfb->palette[regno << 4].red   = red;
+			cfb->palette[regno << 4].green = green;
+			cfb->palette[regno << 4].blue  = blue;
+
+			/*
+			 * The 5 bits of each colour component are
+			 * applied to the high 5 bits of the LUT.
+			 */
+			cyber2000fb_writeb(regno << 4, 0x3c8, cfb);
+			cyber2000fb_writeb(red, 0x3c9, cfb);
+			cyber2000fb_writeb(green, 0x3c9, cfb);
+			cyber2000fb_writeb(blue, 0x3c9, cfb);
+			ret = 0;
+		}
+
+		/*
+		 * Since this is only used for the first 16 colours, we
+		 * don't have to care about overflowing for regno >= 32
+		 */
+		pseudo_val = regno << var->red.offset |
+			     regno << var->green.offset |
+			     regno << var->blue.offset;
+		break;
+
+	/*
+	 * True colour:
+	 *          n     rl
+	 *  pixel --/--+--/--> red dac
+	 *             |  gl
+	 *             +--/--> green dac
+	 *             |  bl
+	 *             +--/--> blue dac
+	 * n = bpp, rl = red length, gl = green length, bl = blue length
+	 */
+	case FB_VISUAL_TRUECOLOR:
+		pseudo_val = convert_bitfield(transp ^ 0xffff, &var->transp);
+		pseudo_val |= convert_bitfield(red, &var->red);
+		pseudo_val |= convert_bitfield(green, &var->green);
+		pseudo_val |= convert_bitfield(blue, &var->blue);
+		break;
+	}
+
+	/*
+	 * Now set our pseudo palette for the CFB16/24/32 drivers.
+	 */
+	if (regno < 16)
+		((u32 *)cfb->fb.pseudo_palette)[regno] = pseudo_val;
+
+	return ret;
+}
+
+struct par_info {
+	/*
+	 * Hardware
+	 */
+	u_char	clock_mult;
+	u_char	clock_div;
+	u_char	extseqmisc;
+	u_char	co_pixfmt;
+	u_char	crtc_ofl;
+	u_char	crtc[19];
+	u_int	width;
+	u_int	pitch;
+	u_int	fetch;
+
+	/*
+	 * Other
+	 */
+	u_char	ramdac;
+};
+
+static const u_char crtc_idx[] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	0x08, 0x09,
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18
+};
+
+static void cyber2000fb_write_ramdac_ctrl(struct cfb_info *cfb)
+{
+	unsigned int i;
+	unsigned int val = cfb->ramdac_ctrl | cfb->ramdac_powerdown;
+
+	cyber2000fb_writeb(0x56, 0x3ce, cfb);
+	i = cyber2000fb_readb(0x3cf, cfb);
+	cyber2000fb_writeb(i | 4, 0x3cf, cfb);
+	cyber2000fb_writeb(val, 0x3c6, cfb);
+	cyber2000fb_writeb(i, 0x3cf, cfb);
+}
+
+static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw)
+{
+	u_int i;
+
+	/*
+	 * Blank palette
+	 */
+	for (i = 0; i < NR_PALETTE; i++) {
+		cyber2000fb_writeb(i, 0x3c8, cfb);
+		cyber2000fb_writeb(0, 0x3c9, cfb);
+		cyber2000fb_writeb(0, 0x3c9, cfb);
+		cyber2000fb_writeb(0, 0x3c9, cfb);
+	}
+
+	cyber2000fb_writeb(0xef, 0x3c2, cfb);
+	cyber2000_crtcw(0x11, 0x0b, cfb);
+	cyber2000_attrw(0x11, 0x00, cfb);
+
+	cyber2000_seqw(0x00, 0x01, cfb);
+	cyber2000_seqw(0x01, 0x01, cfb);
+	cyber2000_seqw(0x02, 0x0f, cfb);
+	cyber2000_seqw(0x03, 0x00, cfb);
+	cyber2000_seqw(0x04, 0x0e, cfb);
+	cyber2000_seqw(0x00, 0x03, cfb);
+
+	for (i = 0; i < sizeof(crtc_idx); i++)
+		cyber2000_crtcw(crtc_idx[i], hw->crtc[i], cfb);
+
+	for (i = 0x0a; i < 0x10; i++)
+		cyber2000_crtcw(i, 0, cfb);
+
+	cyber2000_grphw(EXT_CRT_VRTOFL, hw->crtc_ofl, cfb);
+	cyber2000_grphw(0x00, 0x00, cfb);
+	cyber2000_grphw(0x01, 0x00, cfb);
+	cyber2000_grphw(0x02, 0x00, cfb);
+	cyber2000_grphw(0x03, 0x00, cfb);
+	cyber2000_grphw(0x04, 0x00, cfb);
+	cyber2000_grphw(0x05, 0x60, cfb);
+	cyber2000_grphw(0x06, 0x05, cfb);
+	cyber2000_grphw(0x07, 0x0f, cfb);
+	cyber2000_grphw(0x08, 0xff, cfb);
+
+	/* Attribute controller registers */
+	for (i = 0; i < 16; i++)
+		cyber2000_attrw(i, i, cfb);
+
+	cyber2000_attrw(0x10, 0x01, cfb);
+	cyber2000_attrw(0x11, 0x00, cfb);
+	cyber2000_attrw(0x12, 0x0f, cfb);
+	cyber2000_attrw(0x13, 0x00, cfb);
+	cyber2000_attrw(0x14, 0x00, cfb);
+
+	/* PLL registers */
+	cyber2000_grphw(EXT_DCLK_MULT, hw->clock_mult, cfb);
+	cyber2000_grphw(EXT_DCLK_DIV,  hw->clock_div, cfb);
+	cyber2000_grphw(EXT_MCLK_MULT, cfb->mclk_mult, cfb);
+	cyber2000_grphw(EXT_MCLK_DIV,  cfb->mclk_div, cfb);
+	cyber2000_grphw(0x90, 0x01, cfb);
+	cyber2000_grphw(0xb9, 0x80, cfb);
+	cyber2000_grphw(0xb9, 0x00, cfb);
+
+	cfb->ramdac_ctrl = hw->ramdac;
+	cyber2000fb_write_ramdac_ctrl(cfb);
+
+	cyber2000fb_writeb(0x20, 0x3c0, cfb);
+	cyber2000fb_writeb(0xff, 0x3c6, cfb);
+
+	cyber2000_grphw(0x14, hw->fetch, cfb);
+	cyber2000_grphw(0x15, ((hw->fetch >> 8) & 0x03) |
+			      ((hw->pitch >> 4) & 0x30), cfb);
+	cyber2000_grphw(EXT_SEQ_MISC, hw->extseqmisc, cfb);
+
+	/*
+	 * Set up accelerator registers
+	 */
+	cyber2000fb_writew(hw->width,     CO_REG_SRC_WIDTH,  cfb);
+	cyber2000fb_writew(hw->width,     CO_REG_DEST_WIDTH, cfb);
+	cyber2000fb_writeb(hw->co_pixfmt, CO_REG_PIXFMT, cfb);
+}
+
+static inline int
+cyber2000fb_update_start(struct cfb_info *cfb, struct fb_var_screeninfo *var)
+{
+	u_int base = var->yoffset * var->xres_virtual + var->xoffset;
+
+	base *= var->bits_per_pixel;
+
+	/*
+	 * Convert to bytes and shift two extra bits because DAC
+	 * can only start on 4 byte aligned data.
+	 */
+	base >>= 5;
+
+	if (base >= 1 << 20)
+		return -EINVAL;
+
+	cyber2000_grphw(0x10, base >> 16 | 0x10, cfb);
+	cyber2000_crtcw(0x0c, base >> 8, cfb);
+	cyber2000_crtcw(0x0d, base, cfb);
+
+	return 0;
+}
+
+static int
+cyber2000fb_decode_crtc(struct par_info *hw, struct cfb_info *cfb,
+			struct fb_var_screeninfo *var)
+{
+	u_int Htotal, Hblankend, Hsyncend;
+	u_int Vtotal, Vdispend, Vblankstart, Vblankend, Vsyncstart, Vsyncend;
+#define BIT(v,b1,m,b2) (((v >> b1) & m) << b2)
+
+	hw->crtc[13] = hw->pitch;
+	hw->crtc[17] = 0xe3;
+	hw->crtc[14] = 0;
+	hw->crtc[8]  = 0;
+
+	Htotal      = var->xres + var->right_margin +
+		      var->hsync_len + var->left_margin;
+
+	if (Htotal > 2080)
+		return -EINVAL;
+
+	hw->crtc[0] = (Htotal >> 3) - 5;
+	hw->crtc[1] = (var->xres >> 3) - 1;
+	hw->crtc[2] = var->xres >> 3;
+	hw->crtc[4] = (var->xres + var->right_margin) >> 3;
+
+	Hblankend   = (Htotal - 4*8) >> 3;
+
+	hw->crtc[3] = BIT(Hblankend,  0, 0x1f,  0) |
+		      BIT(1,          0, 0x01,  7);
+
+	Hsyncend    = (var->xres + var->right_margin + var->hsync_len) >> 3;
+
+	hw->crtc[5] = BIT(Hsyncend,   0, 0x1f,  0) |
+		      BIT(Hblankend,  5, 0x01,  7);
+
+	Vdispend    = var->yres - 1;
+	Vsyncstart  = var->yres + var->lower_margin;
+	Vsyncend    = var->yres + var->lower_margin + var->vsync_len;
+	Vtotal      = var->yres + var->lower_margin + var->vsync_len +
+		      var->upper_margin - 2;
+
+	if (Vtotal > 2047)
+		return -EINVAL;
+
+	Vblankstart = var->yres + 6;
+	Vblankend   = Vtotal - 10;
+
+	hw->crtc[6]  = Vtotal;
+	hw->crtc[7]  = BIT(Vtotal,     8, 0x01,  0) |
+			BIT(Vdispend,   8, 0x01,  1) |
+			BIT(Vsyncstart, 8, 0x01,  2) |
+			BIT(Vblankstart,8, 0x01,  3) |
+			BIT(1,          0, 0x01,  4) |
+	        	BIT(Vtotal,     9, 0x01,  5) |
+			BIT(Vdispend,   9, 0x01,  6) |
+			BIT(Vsyncstart, 9, 0x01,  7);
+	hw->crtc[9]  = BIT(0,          0, 0x1f,  0) |
+		        BIT(Vblankstart,9, 0x01,  5) |
+			BIT(1,          0, 0x01,  6);
+	hw->crtc[10] = Vsyncstart;
+	hw->crtc[11] = BIT(Vsyncend,   0, 0x0f,  0) |
+		       BIT(1,          0, 0x01,  7);
+	hw->crtc[12] = Vdispend;
+	hw->crtc[15] = Vblankstart;
+	hw->crtc[16] = Vblankend;
+	hw->crtc[18] = 0xff;
+
+	/*
+	 * overflow - graphics reg 0x11
+	 * 0=VTOTAL:10 1=VDEND:10 2=VRSTART:10 3=VBSTART:10
+	 * 4=LINECOMP:10 5-IVIDEO 6=FIXCNT
+	 */
+	hw->crtc_ofl =
+		BIT(Vtotal,     10, 0x01,  0) |
+		BIT(Vdispend,   10, 0x01,  1) |
+		BIT(Vsyncstart, 10, 0x01,  2) |
+		BIT(Vblankstart,10, 0x01,  3) |
+		EXT_CRT_VRTOFL_LINECOMP10;
+
+	/* woody: set the interlaced bit... */
+	/* FIXME: what about doublescan? */
+	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
+		hw->crtc_ofl |= EXT_CRT_VRTOFL_INTERLACE;
+
+	return 0;
+}
+
+/*
+ * The following was discovered by a good monitor, bit twiddling, theorising
+ * and but mostly luck.  Strangely, it looks like everyone elses' PLL!
+ *
+ * Clock registers:
+ *   fclock = fpll / div2
+ *   fpll   = fref * mult / div1
+ * where:
+ *   fref = 14.318MHz (69842ps)
+ *   mult = reg0xb0.7:0
+ *   div1 = (reg0xb1.5:0 + 1)
+ *   div2 =  2^(reg0xb1.7:6)
+ *   fpll should be between 115 and 260 MHz
+ *  (8696ps and 3846ps)
+ */
+static int
+cyber2000fb_decode_clock(struct par_info *hw, struct cfb_info *cfb,
+			 struct fb_var_screeninfo *var)
+{
+	u_long pll_ps = var->pixclock;
+	const u_long ref_ps = cfb->ref_ps;
+	u_int div2, t_div1, best_div1, best_mult;
+	int best_diff;
+	int vco;
+
+	/*
+	 * Step 1:
+	 *   find div2 such that 115MHz < fpll < 260MHz
+	 *   and 0 <= div2 < 4
+	 */
+	for (div2 = 0; div2 < 4; div2++) {
+		u_long new_pll;
+
+		new_pll = pll_ps / cfb->divisors[div2];
+		if (8696 > new_pll && new_pll > 3846) {
+			pll_ps = new_pll;
+			break;
+		}
+	}
+
+	if (div2 == 4)
+		return -EINVAL;
+
+	/*
+	 * Step 2:
+	 *  Given pll_ps and ref_ps, find:
+	 *    pll_ps * 0.995 < pll_ps_calc < pll_ps * 1.005
+	 *  where { 1 < best_div1 < 32, 1 < best_mult < 256 }
+	 *    pll_ps_calc = best_div1 / (ref_ps * best_mult)
+	 */
+	best_diff = 0x7fffffff;
+	best_mult = 32;
+	best_div1 = 255;
+	for (t_div1 = 32; t_div1 > 1; t_div1 -= 1) {
+		u_int rr, t_mult, t_pll_ps;
+		int diff;
+
+		/*
+		 * Find the multiplier for this divisor
+		 */
+		rr = ref_ps * t_div1;
+		t_mult = (rr + pll_ps / 2) / pll_ps;
+
+		/*
+		 * Is the multiplier within the correct range?
+		 */
+		if (t_mult > 256 || t_mult < 2)
+			continue;
+
+		/*
+		 * Calculate the actual clock period from this multiplier
+		 * and divisor, and estimate the error.
+		 */
+		t_pll_ps = (rr + t_mult / 2) / t_mult;
+		diff = pll_ps - t_pll_ps;
+		if (diff < 0)
+			diff = -diff;
+
+		if (diff < best_diff) {
+			best_diff = diff;
+			best_mult = t_mult;
+			best_div1 = t_div1;
+		}
+
+		/*
+		 * If we hit an exact value, there is no point in continuing.
+		 */
+		if (diff == 0)
+			break;
+	}
+
+	/*
+	 * Step 3:
+	 *  combine values
+	 */
+	hw->clock_mult = best_mult - 1;
+	hw->clock_div  = div2 << 6 | (best_div1 - 1);
+
+	vco = ref_ps * best_div1 / best_mult;
+	if ((ref_ps == 40690) && (vco < 5556))
+		/* Set VFSEL when VCO > 180MHz (5.556 ps). */
+		hw->clock_div |= EXT_DCLK_DIV_VFSEL;
+
+	return 0;
+}
+
+/*
+ *    Set the User Defined Part of the Display
+ */
+static int
+cyber2000fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct cfb_info *cfb = (struct cfb_info *)info;
+	struct par_info hw;
+	unsigned int mem;
+	int err;
+
+	var->transp.msb_right	= 0;
+	var->red.msb_right	= 0;
+	var->green.msb_right	= 0;
+	var->blue.msb_right	= 0;
+
+	switch (var->bits_per_pixel) {
+	case 8:	/* PSEUDOCOLOUR, 256 */
+		var->transp.offset	= 0;
+		var->transp.length	= 0;
+		var->red.offset		= 0;
+		var->red.length		= 8;
+		var->green.offset	= 0;
+		var->green.length	= 8;
+		var->blue.offset	= 0;
+		var->blue.length	= 8;
+		break;
+
+	case 16:/* DIRECTCOLOUR, 64k or 32k */
+		switch (var->green.length) {
+		case 6: /* RGB565, 64k */
+			var->transp.offset	= 0;
+			var->transp.length	= 0;
+			var->red.offset		= 11;
+			var->red.length		= 5;
+			var->green.offset	= 5;
+			var->green.length	= 6;
+			var->blue.offset	= 0;
+			var->blue.length	= 5;
+			break;
+
+		default:
+		case 5: /* RGB555, 32k */
+			var->transp.offset	= 0;
+			var->transp.length	= 0;
+			var->red.offset		= 10;
+			var->red.length		= 5;
+			var->green.offset	= 5;
+			var->green.length	= 5;
+			var->blue.offset	= 0;
+			var->blue.length	= 5;
+			break;
+
+		case 4: /* RGB444, 4k + transparency? */
+			var->transp.offset	= 12;
+			var->transp.length	= 4;
+			var->red.offset		= 8;
+			var->red.length		= 4;
+			var->green.offset	= 4;
+			var->green.length	= 4;
+			var->blue.offset	= 0;
+			var->blue.length	= 4;
+			break;
+		}
+		break;
+
+	case 24:/* TRUECOLOUR, 16m */
+		var->transp.offset	= 0;
+		var->transp.length	= 0;
+		var->red.offset		= 16;
+		var->red.length		= 8;
+		var->green.offset	= 8;
+		var->green.length	= 8;
+		var->blue.offset	= 0;
+		var->blue.length	= 8;
+		break;
+
+	case 32:/* TRUECOLOUR, 16m */
+		var->transp.offset	= 24;
+		var->transp.length	= 8;
+		var->red.offset		= 16;
+		var->red.length		= 8;
+		var->green.offset	= 8;
+		var->green.length	= 8;
+		var->blue.offset	= 0;
+		var->blue.length	= 8;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	mem = var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8);
+	if (mem > cfb->fb.fix.smem_len)
+		var->yres_virtual = cfb->fb.fix.smem_len * 8 /
+			(var->bits_per_pixel * var->xres_virtual);
+
+	if (var->yres > var->yres_virtual)
+		var->yres = var->yres_virtual;
+	if (var->xres > var->xres_virtual)
+		var->xres = var->xres_virtual;
+
+	err = cyber2000fb_decode_clock(&hw, cfb, var);
+	if (err)
+		return err;
+
+	err = cyber2000fb_decode_crtc(&hw, cfb, var);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static int cyber2000fb_set_par(struct fb_info *info)
+{
+	struct cfb_info *cfb = (struct cfb_info *)info;
+	struct fb_var_screeninfo *var = &cfb->fb.var;
+	struct par_info hw;
+	unsigned int mem;
+
+	hw.width = var->xres_virtual;
+	hw.ramdac = RAMDAC_VREFEN | RAMDAC_DAC8BIT;
+
+	switch (var->bits_per_pixel) {
+	case 8:
+		hw.co_pixfmt		= CO_PIXFMT_8BPP;
+		hw.pitch		= hw.width >> 3;
+		hw.extseqmisc		= EXT_SEQ_MISC_8;
+		break;
+
+	case 16:
+		hw.co_pixfmt		= CO_PIXFMT_16BPP;
+		hw.pitch		= hw.width >> 2;
+
+		switch (var->green.length) {
+		case 6: /* RGB565, 64k */
+			hw.extseqmisc	= EXT_SEQ_MISC_16_RGB565;
+			break;
+		case 5: /* RGB555, 32k */
+			hw.extseqmisc	= EXT_SEQ_MISC_16_RGB555;
+			break;
+		case 4: /* RGB444, 4k + transparency? */
+			hw.extseqmisc	= EXT_SEQ_MISC_16_RGB444;
+			break;
+		default:
+			BUG();
+		}
+	case 24:/* TRUECOLOUR, 16m */
+		hw.co_pixfmt		= CO_PIXFMT_24BPP;
+		hw.width		*= 3;
+		hw.pitch		= hw.width >> 3;
+		hw.ramdac		|= (RAMDAC_BYPASS | RAMDAC_RAMPWRDN);
+		hw.extseqmisc		= EXT_SEQ_MISC_24_RGB888;
+		break;
+
+	case 32:/* TRUECOLOUR, 16m */
+		hw.co_pixfmt		= CO_PIXFMT_32BPP;
+		hw.pitch		= hw.width >> 1;
+		hw.ramdac		|= (RAMDAC_BYPASS | RAMDAC_RAMPWRDN);
+		hw.extseqmisc		= EXT_SEQ_MISC_32;
+		break;
+
+	default:
+		BUG();
+	}
+
+	/*
+	 * Sigh, this is absolutely disgusting, but caused by
+	 * the way the fbcon developers want to separate out
+	 * the "checking" and the "setting" of the video mode.
+	 *
+	 * If the mode is not suitable for the hardware here,
+	 * we can't prevent it being set by returning an error.
+	 *
+	 * In theory, since NetWinders contain just one VGA card,
+	 * we should never end up hitting this problem.
+	 */
+	BUG_ON(cyber2000fb_decode_clock(&hw, cfb, var) != 0);
+	BUG_ON(cyber2000fb_decode_crtc(&hw, cfb, var) != 0);
+
+	hw.width -= 1;
+	hw.fetch = hw.pitch;
+	if (!(cfb->mem_ctl2 & MEM_CTL2_64BIT))
+		hw.fetch <<= 1;
+	hw.fetch += 1;
+
+	cfb->fb.fix.line_length	= var->xres_virtual * var->bits_per_pixel / 8;
+
+	/*
+	 * Same here - if the size of the video mode exceeds the
+	 * available RAM, we can't prevent this mode being set.
+	 *
+	 * In theory, since NetWinders contain just one VGA card,
+	 * we should never end up hitting this problem.
+	 */
+	mem = cfb->fb.fix.line_length * var->yres_virtual;
+	BUG_ON(mem > cfb->fb.fix.smem_len);
+
+	/*
+	 * 8bpp displays are always pseudo colour.  16bpp and above
+	 * are direct colour or true colour, depending on whether
+	 * the RAMDAC palettes are bypassed.  (Direct colour has
+	 * palettes, true colour does not.)
+	 */
+	if (var->bits_per_pixel == 8)
+		cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
+	else if (hw.ramdac & RAMDAC_BYPASS)
+		cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+	else
+		cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR;
+
+	cyber2000fb_set_timing(cfb, &hw);
+	cyber2000fb_update_start(cfb, var);
+
+	return 0;
+}
+
+
+/*
+ *    Pan or Wrap the Display
+ */
+static int
+cyber2000fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct cfb_info *cfb = (struct cfb_info *)info;
+
+	if (cyber2000fb_update_start(cfb, var))
+		return -EINVAL;
+
+	cfb->fb.var.xoffset = var->xoffset;
+	cfb->fb.var.yoffset = var->yoffset;
+
+	if (var->vmode & FB_VMODE_YWRAP) {
+		cfb->fb.var.vmode |= FB_VMODE_YWRAP;
+	} else {
+		cfb->fb.var.vmode &= ~FB_VMODE_YWRAP;
+	}
+
+	return 0;
+}
+
+/*
+ *    (Un)Blank the display.
+ *
+ *  Blank the screen if blank_mode != 0, else unblank. If
+ *  blank == NULL then the caller blanks by setting the CLUT
+ *  (Color Look Up Table) to all black. Return 0 if blanking
+ *  succeeded, != 0 if un-/blanking failed due to e.g. a
+ *  video mode which doesn't support it. Implements VESA
+ *  suspend and powerdown modes on hardware that supports
+ *  disabling hsync/vsync:
+ *    blank_mode == 2: suspend vsync
+ *    blank_mode == 3: suspend hsync
+ *    blank_mode == 4: powerdown
+ *
+ *  wms...Enable VESA DMPS compatible powerdown mode
+ *  run "setterm -powersave powerdown" to take advantage
+ */
+static int cyber2000fb_blank(int blank, struct fb_info *info)
+{
+	struct cfb_info *cfb = (struct cfb_info *)info;
+	unsigned int sync = 0;
+	int i;
+
+	switch (blank) {
+	case FB_BLANK_POWERDOWN:	/* powerdown - both sync lines down */
+		sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_0;
+		break;	
+	case FB_BLANK_HSYNC_SUSPEND:	/* hsync off */
+		sync = EXT_SYNC_CTL_VS_NORMAL | EXT_SYNC_CTL_HS_0;
+		break;	
+	case FB_BLANK_VSYNC_SUSPEND:	/* vsync off */
+		sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_NORMAL;
+		break;
+	case FB_BLANK_NORMAL:	        /* soft blank */
+	default: /* unblank */
+		break;
+	}
+
+	cyber2000_grphw(EXT_SYNC_CTL, sync, cfb);
+
+	if (blank <= 1) {
+		/* turn on ramdacs */
+		cfb->ramdac_powerdown &= ~(RAMDAC_DACPWRDN | RAMDAC_BYPASS | RAMDAC_RAMPWRDN);
+		cyber2000fb_write_ramdac_ctrl(cfb);
+	}
+
+	/*
+	 * Soft blank/unblank the display.
+	 */
+	if (blank) {	/* soft blank */
+		for (i = 0; i < NR_PALETTE; i++) {
+			cyber2000fb_writeb(i, 0x3c8, cfb);
+			cyber2000fb_writeb(0, 0x3c9, cfb);
+			cyber2000fb_writeb(0, 0x3c9, cfb);
+			cyber2000fb_writeb(0, 0x3c9, cfb);
+		}
+	} else {	/* unblank */
+		for (i = 0; i < NR_PALETTE; i++) {
+			cyber2000fb_writeb(i, 0x3c8, cfb);
+			cyber2000fb_writeb(cfb->palette[i].red, 0x3c9, cfb);
+			cyber2000fb_writeb(cfb->palette[i].green, 0x3c9, cfb);
+			cyber2000fb_writeb(cfb->palette[i].blue, 0x3c9, cfb);
+		}
+	}
+
+	if (blank >= 2) {
+		/* turn off ramdacs */
+		cfb->ramdac_powerdown |= RAMDAC_DACPWRDN | RAMDAC_BYPASS | RAMDAC_RAMPWRDN;
+		cyber2000fb_write_ramdac_ctrl(cfb);
+	}
+
+	return 0;
+}
+
+static struct fb_ops cyber2000fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= cyber2000fb_check_var,
+	.fb_set_par	= cyber2000fb_set_par,
+	.fb_setcolreg	= cyber2000fb_setcolreg,
+	.fb_blank	= cyber2000fb_blank,
+	.fb_pan_display	= cyber2000fb_pan_display,
+	.fb_fillrect	= cyber2000fb_fillrect,
+	.fb_copyarea	= cyber2000fb_copyarea,
+	.fb_imageblit	= cyber2000fb_imageblit,
+	.fb_cursor	= soft_cursor,
+	.fb_sync	= cyber2000fb_sync,
+};
+
+/*
+ * This is the only "static" reference to the internal data structures
+ * of this driver.  It is here solely at the moment to support the other
+ * CyberPro modules external to this driver.
+ */
+static struct cfb_info		*int_cfb_info;
+
+/*
+ * Enable access to the extended registers
+ */
+void cyber2000fb_enable_extregs(struct cfb_info *cfb)
+{
+	cfb->func_use_count += 1;
+
+	if (cfb->func_use_count == 1) {
+		int old;
+
+		old = cyber2000_grphr(EXT_FUNC_CTL, cfb);
+		old |= EXT_FUNC_CTL_EXTREGENBL;
+		cyber2000_grphw(EXT_FUNC_CTL, old, cfb);
+	}
+}
+
+/*
+ * Disable access to the extended registers
+ */
+void cyber2000fb_disable_extregs(struct cfb_info *cfb)
+{
+	if (cfb->func_use_count == 1) {
+		int old;
+
+		old = cyber2000_grphr(EXT_FUNC_CTL, cfb);
+		old &= ~EXT_FUNC_CTL_EXTREGENBL;
+		cyber2000_grphw(EXT_FUNC_CTL, old, cfb);
+	}
+
+	if (cfb->func_use_count == 0)
+		printk(KERN_ERR "disable_extregs: count = 0\n");
+	else
+		cfb->func_use_count -= 1;
+}
+
+void cyber2000fb_get_fb_var(struct cfb_info *cfb, struct fb_var_screeninfo *var)
+{
+	memcpy(var, &cfb->fb.var, sizeof(struct fb_var_screeninfo));
+}
+
+/*
+ * Attach a capture/tv driver to the core CyberX0X0 driver.
+ */
+int cyber2000fb_attach(struct cyberpro_info *info, int idx)
+{
+	if (int_cfb_info != NULL) {
+		info->dev	      = int_cfb_info->dev;
+		info->regs	      = int_cfb_info->regs;
+		info->fb	      = int_cfb_info->fb.screen_base;
+		info->fb_size	      = int_cfb_info->fb.fix.smem_len;
+		info->enable_extregs  = cyber2000fb_enable_extregs;
+		info->disable_extregs = cyber2000fb_disable_extregs;
+		info->info            = int_cfb_info;
+
+		strlcpy(info->dev_name, int_cfb_info->fb.fix.id, sizeof(info->dev_name));
+	}
+
+	return int_cfb_info != NULL;
+}
+
+/*
+ * Detach a capture/tv driver from the core CyberX0X0 driver.
+ */
+void cyber2000fb_detach(int idx)
+{
+}
+
+EXPORT_SYMBOL(cyber2000fb_attach);
+EXPORT_SYMBOL(cyber2000fb_detach);
+EXPORT_SYMBOL(cyber2000fb_enable_extregs);
+EXPORT_SYMBOL(cyber2000fb_disable_extregs);
+EXPORT_SYMBOL(cyber2000fb_get_fb_var);
+
+/*
+ * These parameters give
+ * 640x480, hsync 31.5kHz, vsync 60Hz
+ */
+static struct fb_videomode __devinitdata cyber2000fb_default_mode = {
+	.refresh	= 60,
+	.xres		= 640,
+	.yres		= 480,
+	.pixclock	= 39722,
+	.left_margin	= 56,
+	.right_margin	= 16,
+	.upper_margin	= 34,
+	.lower_margin	= 9,
+	.hsync_len	= 88,
+	.vsync_len	= 2,
+	.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	.vmode		= FB_VMODE_NONINTERLACED
+};
+
+static char igs_regs[] = {
+	EXT_CRT_IRQ,		0,
+	EXT_CRT_TEST,		0,
+	EXT_SYNC_CTL,		0,
+	EXT_SEG_WRITE_PTR,	0,
+	EXT_SEG_READ_PTR,	0,
+	EXT_BIU_MISC,		EXT_BIU_MISC_LIN_ENABLE |
+				EXT_BIU_MISC_COP_ENABLE |
+				EXT_BIU_MISC_COP_BFC,
+	EXT_FUNC_CTL,		0,
+	CURS_H_START,		0,
+	CURS_H_START + 1,	0,
+	CURS_H_PRESET,		0,
+	CURS_V_START,		0,
+	CURS_V_START + 1,	0,
+	CURS_V_PRESET,		0,
+	CURS_CTL,		0,
+	EXT_ATTRIB_CTL,		EXT_ATTRIB_CTL_EXT,
+	EXT_OVERSCAN_RED,	0,
+	EXT_OVERSCAN_GREEN,	0,
+	EXT_OVERSCAN_BLUE,	0,
+
+	/* some of these are questionable when we have a BIOS */
+	EXT_MEM_CTL0,		EXT_MEM_CTL0_7CLK |
+				EXT_MEM_CTL0_RAS_1 |
+				EXT_MEM_CTL0_MULTCAS,
+	EXT_HIDDEN_CTL1,	0x30,
+	EXT_FIFO_CTL,		0x0b,
+	EXT_FIFO_CTL + 1,	0x17,
+	0x76,			0x00,
+	EXT_HIDDEN_CTL4,	0xc8
+};
+
+/*
+ * Initialise the CyberPro hardware.  On the CyberPro5XXXX,
+ * ensure that we're using the correct PLL (5XXX's may be
+ * programmed to use an additional set of PLLs.)
+ */
+static void cyberpro_init_hw(struct cfb_info *cfb)
+{
+	int i;
+
+	for (i = 0; i < sizeof(igs_regs); i += 2)
+		cyber2000_grphw(igs_regs[i], igs_regs[i+1], cfb);
+
+	if (cfb->id == ID_CYBERPRO_5000) {
+		unsigned char val;
+		cyber2000fb_writeb(0xba, 0x3ce, cfb);
+		val = cyber2000fb_readb(0x3cf, cfb) & 0x80;
+		cyber2000fb_writeb(val, 0x3cf, cfb);
+	}
+}
+
+static struct cfb_info * __devinit
+cyberpro_alloc_fb_info(unsigned int id, char *name)
+{
+	struct cfb_info *cfb;
+
+	cfb = kmalloc(sizeof(struct cfb_info) +
+		       sizeof(u32) * 16, GFP_KERNEL);
+
+	if (!cfb)
+		return NULL;
+
+	memset(cfb, 0, sizeof(struct cfb_info));
+
+	cfb->id			= id;
+
+	if (id == ID_CYBERPRO_5000)
+		cfb->ref_ps	= 40690; // 24.576 MHz
+	else
+		cfb->ref_ps	= 69842; // 14.31818 MHz (69841?)
+
+	cfb->divisors[0]	= 1;
+	cfb->divisors[1]	= 2;
+	cfb->divisors[2]	= 4;
+
+	if (id == ID_CYBERPRO_2000)
+		cfb->divisors[3] = 8;
+	else
+		cfb->divisors[3] = 6;
+
+	strcpy(cfb->fb.fix.id, name);
+
+	cfb->fb.fix.type	= FB_TYPE_PACKED_PIXELS;
+	cfb->fb.fix.type_aux	= 0;
+	cfb->fb.fix.xpanstep	= 0;
+	cfb->fb.fix.ypanstep	= 1;
+	cfb->fb.fix.ywrapstep	= 0;
+
+	switch (id) {
+	case ID_IGA_1682:
+		cfb->fb.fix.accel = 0;
+		break;
+
+	case ID_CYBERPRO_2000:
+		cfb->fb.fix.accel = FB_ACCEL_IGS_CYBER2000;
+		break;
+
+	case ID_CYBERPRO_2010:
+		cfb->fb.fix.accel = FB_ACCEL_IGS_CYBER2010;
+		break;
+
+	case ID_CYBERPRO_5000:
+		cfb->fb.fix.accel = FB_ACCEL_IGS_CYBER5000;
+		break;
+	}
+
+	cfb->fb.var.nonstd	= 0;
+	cfb->fb.var.activate	= FB_ACTIVATE_NOW;
+	cfb->fb.var.height	= -1;
+	cfb->fb.var.width	= -1;
+	cfb->fb.var.accel_flags	= FB_ACCELF_TEXT;
+
+	cfb->fb.fbops		= &cyber2000fb_ops;
+	cfb->fb.flags		= FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+	cfb->fb.pseudo_palette	= (void *)(cfb + 1);
+
+	fb_alloc_cmap(&cfb->fb.cmap, NR_PALETTE, 0);
+
+	return cfb;
+}
+
+static void
+cyberpro_free_fb_info(struct cfb_info *cfb)
+{
+	if (cfb) {
+		/*
+		 * Free the colourmap
+		 */
+		fb_alloc_cmap(&cfb->fb.cmap, 0, 0);
+
+		kfree(cfb);
+	}
+}
+
+/*
+ * Parse Cyber2000fb options.  Usage:
+ *  video=cyber2000:font:fontname
+ */
+#ifndef MODULE
+static int
+cyber2000fb_setup(char *options)
+{
+	char *opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((opt = strsep(&options, ",")) != NULL) {
+		if (!*opt)
+			continue;
+
+		if (strncmp(opt, "font:", 5) == 0) {
+			static char default_font_storage[40];
+
+			strlcpy(default_font_storage, opt + 5, sizeof(default_font_storage));
+			default_font = default_font_storage;
+			continue;
+		}
+
+		printk(KERN_ERR "CyberPro20x0: unknown parameter: %s\n", opt);
+	}
+	return 0;
+}
+#endif  /*  MODULE  */
+
+/*
+ * The CyberPro chips can be placed on many different bus types.
+ * This probe function is common to all bus types.  The bus-specific
+ * probe function is expected to have:
+ *  - enabled access to the linear memory region
+ *  - memory mapped access to the registers
+ *  - initialised mem_ctl1 and mem_ctl2 appropriately.
+ */
+static int __devinit cyberpro_common_probe(struct cfb_info *cfb)
+{
+	u_long smem_size;
+	u_int h_sync, v_sync;
+	int err;
+
+	cyberpro_init_hw(cfb);
+
+	/*
+	 * Get the video RAM size and width from the VGA register.
+	 * This should have been already initialised by the BIOS,
+	 * but if it's garbage, claim default 1MB VRAM (woody)
+	 */
+	cfb->mem_ctl1 = cyber2000_grphr(EXT_MEM_CTL1, cfb);
+	cfb->mem_ctl2 = cyber2000_grphr(EXT_MEM_CTL2, cfb);
+
+	/*
+	 * Determine the size of the memory.
+	 */
+	switch (cfb->mem_ctl2 & MEM_CTL2_SIZE_MASK) {
+	case MEM_CTL2_SIZE_4MB:	smem_size = 0x00400000; break;
+	case MEM_CTL2_SIZE_2MB:	smem_size = 0x00200000; break;
+	case MEM_CTL2_SIZE_1MB: smem_size = 0x00100000; break;
+	default:		smem_size = 0x00100000; break;
+	}
+
+	cfb->fb.fix.smem_len   = smem_size;
+	cfb->fb.fix.mmio_len   = MMIO_SIZE;
+	cfb->fb.screen_base    = cfb->region;
+
+	err = -EINVAL;
+	if (!fb_find_mode(&cfb->fb.var, &cfb->fb, NULL, NULL, 0,
+	    		  &cyber2000fb_default_mode, 8)) {
+		printk("%s: no valid mode found\n", cfb->fb.fix.id);
+		goto failed;
+	}
+
+	cfb->fb.var.yres_virtual = cfb->fb.fix.smem_len * 8 /
+			(cfb->fb.var.bits_per_pixel * cfb->fb.var.xres_virtual);
+
+	if (cfb->fb.var.yres_virtual < cfb->fb.var.yres)
+		cfb->fb.var.yres_virtual = cfb->fb.var.yres;
+
+//	fb_set_var(&cfb->fb.var, -1, &cfb->fb);
+
+	/*
+	 * Calculate the hsync and vsync frequencies.  Note that
+	 * we split the 1e12 constant up so that we can preserve
+	 * the precision and fit the results into 32-bit registers.
+	 *  (1953125000 * 512 = 1e12)
+	 */
+	h_sync = 1953125000 / cfb->fb.var.pixclock;
+	h_sync = h_sync * 512 / (cfb->fb.var.xres + cfb->fb.var.left_margin +
+		 cfb->fb.var.right_margin + cfb->fb.var.hsync_len);
+	v_sync = h_sync / (cfb->fb.var.yres + cfb->fb.var.upper_margin +
+		 cfb->fb.var.lower_margin + cfb->fb.var.vsync_len);
+
+	printk(KERN_INFO "%s: %dKiB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
+		cfb->fb.fix.id, cfb->fb.fix.smem_len >> 10,
+		cfb->fb.var.xres, cfb->fb.var.yres,
+		h_sync / 1000, h_sync % 1000, v_sync);
+
+	if (cfb->dev)
+		cfb->fb.device = &cfb->dev->dev;
+	err = register_framebuffer(&cfb->fb);
+
+failed:
+	return err;
+}
+
+static void cyberpro_common_resume(struct cfb_info *cfb)
+{
+	cyberpro_init_hw(cfb);
+
+	/*
+	 * Reprogram the MEM_CTL1 and MEM_CTL2 registers
+	 */
+	cyber2000_grphw(EXT_MEM_CTL1, cfb->mem_ctl1, cfb);
+	cyber2000_grphw(EXT_MEM_CTL2, cfb->mem_ctl2, cfb);
+
+	/*
+	 * Restore the old video mode and the palette.
+	 * We also need to tell fbcon to redraw the console.
+	 */
+	cyber2000fb_set_par(&cfb->fb);
+}
+
+#ifdef CONFIG_ARCH_SHARK
+
+#include <asm/arch/hardware.h>
+
+static int __devinit
+cyberpro_vl_probe(void)
+{
+	struct cfb_info *cfb;
+	int err = -ENOMEM;
+
+	if (!request_mem_region(FB_START,FB_SIZE,"CyberPro2010")) return err;
+
+	cfb = cyberpro_alloc_fb_info(ID_CYBERPRO_2010, "CyberPro2010");
+	if (!cfb)
+		goto failed_release;
+
+	cfb->dev = NULL;
+	cfb->region = ioremap(FB_START,FB_SIZE);
+	if (!cfb->region)
+		goto failed_ioremap;
+
+	cfb->regs = cfb->region + MMIO_OFFSET;
+	cfb->fb.fix.mmio_start = FB_START + MMIO_OFFSET;
+	cfb->fb.fix.smem_start = FB_START;
+
+	/*
+	 * Bring up the hardware.  This is expected to enable access
+	 * to the linear memory region, and allow access to the memory
+	 * mapped registers.  Also, mem_ctl1 and mem_ctl2 must be
+	 * initialised.
+	 */
+	cyber2000fb_writeb(0x18, 0x46e8, cfb);
+	cyber2000fb_writeb(0x01, 0x102, cfb);
+	cyber2000fb_writeb(0x08, 0x46e8, cfb);
+	cyber2000fb_writeb(EXT_BIU_MISC, 0x3ce, cfb);
+	cyber2000fb_writeb(EXT_BIU_MISC_LIN_ENABLE, 0x3cf, cfb);
+
+	cfb->mclk_mult = 0xdb;
+	cfb->mclk_div  = 0x54;
+
+	err = cyberpro_common_probe(cfb);
+	if (err)
+		goto failed;
+
+	if (int_cfb_info == NULL)
+		int_cfb_info = cfb;
+
+	return 0;
+
+failed:
+	iounmap(cfb->region);
+failed_ioremap:
+	cyberpro_free_fb_info(cfb);
+failed_release:
+	release_mem_region(FB_START,FB_SIZE);
+
+	return err;
+}
+#endif /* CONFIG_ARCH_SHARK */
+
+/*
+ * PCI specific support.
+ */
+#ifdef CONFIG_PCI
+/*
+ * We need to wake up the CyberPro, and make sure its in linear memory
+ * mode.  Unfortunately, this is specific to the platform and card that
+ * we are running on.
+ *
+ * On x86 and ARM, should we be initialising the CyberPro first via the
+ * IO registers, and then the MMIO registers to catch all cases?  Can we
+ * end up in the situation where the chip is in MMIO mode, but not awake
+ * on an x86 system?
+ */
+static int cyberpro_pci_enable_mmio(struct cfb_info *cfb)
+{
+	unsigned char val;
+
+#if defined(__sparc_v9__)
+#error "You lose, consult DaveM."
+#elif defined(__sparc__)
+	/*
+	 * SPARC does not have an "outb" instruction, so we generate
+	 * I/O cycles storing into a reserved memory space at
+	 * physical address 0x3000000
+	 */
+	unsigned char *iop;
+
+	iop = ioremap(0x3000000, 0x5000);
+	if (iop == NULL) {
+		prom_printf("iga5000: cannot map I/O\n");
+		return -ENOMEM;
+	}
+
+	writeb(0x18, iop + 0x46e8);
+	writeb(0x01, iop + 0x102);
+	writeb(0x08, iop + 0x46e8);
+	writeb(EXT_BIU_MISC, iop + 0x3ce);
+	writeb(EXT_BIU_MISC_LIN_ENABLE, iop + 0x3cf);
+
+	iounmap((void *)iop);
+#else
+	/*
+	 * Most other machine types are "normal", so
+	 * we use the standard IO-based wakeup.
+	 */
+	outb(0x18, 0x46e8);
+	outb(0x01, 0x102);
+	outb(0x08, 0x46e8);
+	outb(EXT_BIU_MISC, 0x3ce);
+	outb(EXT_BIU_MISC_LIN_ENABLE, 0x3cf);
+#endif
+
+	/*
+	 * Allow the CyberPro to accept PCI burst accesses
+	 */
+	val = cyber2000_grphr(EXT_BUS_CTL, cfb);
+	if (!(val & EXT_BUS_CTL_PCIBURST_WRITE)) {
+		printk(KERN_INFO "%s: enabling PCI bursts\n", cfb->fb.fix.id);
+
+		val |= EXT_BUS_CTL_PCIBURST_WRITE;
+
+		if (cfb->id == ID_CYBERPRO_5000)
+			val |= EXT_BUS_CTL_PCIBURST_READ;
+
+		cyber2000_grphw(EXT_BUS_CTL, val, cfb);
+	}
+
+	return 0;
+}
+
+static int __devinit
+cyberpro_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct cfb_info *cfb;
+	char name[16];
+	int err;
+
+	sprintf(name, "CyberPro%4X", id->device);
+
+	err = pci_enable_device(dev);
+	if (err)
+		return err;
+
+	err = pci_request_regions(dev, name);
+	if (err)
+		return err;
+
+	err = -ENOMEM;
+	cfb = cyberpro_alloc_fb_info(id->driver_data, name);
+	if (!cfb)
+		goto failed_release;
+
+	cfb->dev = dev;
+	cfb->region = ioremap(pci_resource_start(dev, 0),
+			      pci_resource_len(dev, 0));
+	if (!cfb->region)
+		goto failed_ioremap;
+
+	cfb->regs = cfb->region + MMIO_OFFSET;
+	cfb->fb.fix.mmio_start = pci_resource_start(dev, 0) + MMIO_OFFSET;
+	cfb->fb.fix.smem_start = pci_resource_start(dev, 0);
+
+	/*
+	 * Bring up the hardware.  This is expected to enable access
+	 * to the linear memory region, and allow access to the memory
+	 * mapped registers.  Also, mem_ctl1 and mem_ctl2 must be
+	 * initialised.
+	 */
+	err = cyberpro_pci_enable_mmio(cfb);
+	if (err)
+		goto failed;
+
+	/*
+	 * Use MCLK from BIOS. FIXME: what about hotplug?
+	 */
+	cfb->mclk_mult = cyber2000_grphr(EXT_MCLK_MULT, cfb);
+	cfb->mclk_div  = cyber2000_grphr(EXT_MCLK_DIV, cfb);
+
+#ifdef __arm__
+	/*
+	 * MCLK on the NetWinder and the Shark is fixed at 75MHz
+	 */
+	if (machine_is_netwinder()) {
+		cfb->mclk_mult = 0xdb;
+		cfb->mclk_div  = 0x54;
+	}
+#endif
+
+	err = cyberpro_common_probe(cfb);
+	if (err)
+		goto failed;
+
+	/*
+	 * Our driver data
+	 */
+	pci_set_drvdata(dev, cfb);
+	if (int_cfb_info == NULL)
+		int_cfb_info = cfb;
+
+	return 0;
+
+failed:
+	iounmap(cfb->region);
+failed_ioremap:
+	cyberpro_free_fb_info(cfb);
+failed_release:
+	pci_release_regions(dev);
+
+	return err;
+}
+
+static void __devexit cyberpro_pci_remove(struct pci_dev *dev)
+{
+	struct cfb_info *cfb = pci_get_drvdata(dev);
+
+	if (cfb) {
+		/*
+		 * If unregister_framebuffer fails, then
+		 * we will be leaving hooks that could cause
+		 * oopsen laying around.
+		 */
+		if (unregister_framebuffer(&cfb->fb))
+			printk(KERN_WARNING "%s: danger Will Robinson, "
+				"danger danger!  Oopsen imminent!\n",
+				cfb->fb.fix.id);
+		iounmap(cfb->region);
+		cyberpro_free_fb_info(cfb);
+
+		/*
+		 * Ensure that the driver data is no longer
+		 * valid.
+		 */
+		pci_set_drvdata(dev, NULL);
+		if (cfb == int_cfb_info)
+			int_cfb_info = NULL;
+
+		pci_release_regions(dev);
+	}
+}
+
+static int cyberpro_pci_suspend(struct pci_dev *dev, pm_message_t state)
+{
+	return 0;
+}
+
+/*
+ * Re-initialise the CyberPro hardware
+ */
+static int cyberpro_pci_resume(struct pci_dev *dev)
+{
+	struct cfb_info *cfb = pci_get_drvdata(dev);
+
+	if (cfb) {
+		cyberpro_pci_enable_mmio(cfb);
+		cyberpro_common_resume(cfb);
+	}
+
+	return 0;
+}
+
+static struct pci_device_id cyberpro_pci_table[] = {
+//	Not yet
+//	{ PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_1682,
+//		PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_IGA_1682 },
+	{ PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_2000 },
+	{ PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_2010 },
+	{ PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5000,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_5000 },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci,cyberpro_pci_table);
+
+static struct pci_driver cyberpro_driver = {
+	.name		= "CyberPro",
+	.probe		= cyberpro_pci_probe,
+	.remove		= __devexit_p(cyberpro_pci_remove),
+	.suspend	= cyberpro_pci_suspend,
+	.resume		= cyberpro_pci_resume,
+	.id_table	= cyberpro_pci_table
+};
+#endif
+
+/*
+ * I don't think we can use the "module_init" stuff here because
+ * the fbcon stuff may not be initialised yet.  Hence the #ifdef
+ * around module_init.
+ *
+ * Tony: "module_init" is now required
+ */
+static int __init cyber2000fb_init(void)
+{
+	int ret = -1, err;
+
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("cyber2000fb", &option))
+		return -ENODEV;
+	cyber2000fb_setup(option);
+#endif
+
+#ifdef CONFIG_ARCH_SHARK
+	err = cyberpro_vl_probe();
+	if (!err) {
+		ret = 0;
+		__module_get(THIS_MODULE);
+	}
+#endif
+#ifdef CONFIG_PCI
+	err = pci_register_driver(&cyberpro_driver);
+	if (!err)
+		ret = 0;
+#endif
+
+	return ret ? err : 0;
+}
+
+static void __exit cyberpro_exit(void)
+{
+	pci_unregister_driver(&cyberpro_driver);
+}
+
+module_init(cyber2000fb_init);
+module_exit(cyberpro_exit);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("CyberPro 2000, 2010 and 5000 framebuffer driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/cyber2000fb.h b/drivers/video/cyber2000fb.h
new file mode 100644
index 0000000..bd7e1c0
--- /dev/null
+++ b/drivers/video/cyber2000fb.h
@@ -0,0 +1,508 @@
+/*
+ *  linux/drivers/video/cyber2000fb.h
+ *
+ *  Copyright (C) 1998-2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Integraphics Cyber2000 frame buffer device
+ */
+#include <linux/config.h>
+
+/*
+ * Internal CyberPro sizes and offsets.
+ */
+#define MMIO_OFFSET	0x00800000
+#define MMIO_SIZE	0x000c0000
+
+#define NR_PALETTE	256
+
+#if defined(DEBUG) && defined(CONFIG_DEBUG_LL)
+static void debug_printf(char *fmt, ...)
+{
+	extern void printascii(const char *);
+	char buffer[128];
+	va_list ap;
+
+	va_start(ap, fmt);
+	vsprintf(buffer, fmt, ap);
+	va_end(ap);
+
+	printascii(buffer);
+}
+#else
+#define debug_printf(x...) do { } while (0)
+#endif
+
+#define RAMDAC_RAMPWRDN		0x01
+#define RAMDAC_DAC8BIT		0x02
+#define RAMDAC_VREFEN		0x04
+#define RAMDAC_BYPASS		0x10
+#define RAMDAC_DACPWRDN		0x40
+
+#define EXT_CRT_VRTOFL		0x11
+#define EXT_CRT_VRTOFL_LINECOMP10	0x10
+#define EXT_CRT_VRTOFL_INTERLACE	0x20
+
+#define EXT_CRT_IRQ		0x12
+#define EXT_CRT_IRQ_ENABLE		0x01
+#define EXT_CRT_IRQ_ACT_HIGH		0x04
+
+#define EXT_CRT_TEST		0x13
+
+#define EXT_SYNC_CTL		0x16
+#define EXT_SYNC_CTL_HS_NORMAL		0x00
+#define EXT_SYNC_CTL_HS_0		0x01
+#define EXT_SYNC_CTL_HS_1		0x02
+#define EXT_SYNC_CTL_HS_HSVS		0x03
+#define EXT_SYNC_CTL_VS_NORMAL		0x00
+#define EXT_SYNC_CTL_VS_0		0x04
+#define EXT_SYNC_CTL_VS_1		0x08
+#define EXT_SYNC_CTL_VS_COMP		0x0c
+
+#define EXT_BUS_CTL		0x30
+#define EXT_BUS_CTL_LIN_1MB		0x00
+#define EXT_BUS_CTL_LIN_2MB		0x01
+#define EXT_BUS_CTL_LIN_4MB		0x02
+#define EXT_BUS_CTL_ZEROWAIT		0x04
+#define EXT_BUS_CTL_PCIBURST_WRITE	0x20
+#define EXT_BUS_CTL_PCIBURST_READ	0x80	/* CyberPro 5000 only */
+
+#define EXT_SEG_WRITE_PTR	0x31
+#define EXT_SEG_READ_PTR	0x32
+#define EXT_BIU_MISC		0x33
+#define EXT_BIU_MISC_LIN_ENABLE		0x01
+#define EXT_BIU_MISC_COP_ENABLE		0x04
+#define EXT_BIU_MISC_COP_BFC		0x08
+
+#define EXT_FUNC_CTL		0x3c
+#define EXT_FUNC_CTL_EXTREGENBL		0x80	/* enable access to 0xbcxxx		*/
+
+#define PCI_BM_CTL		0x3e
+#define PCI_BM_CTL_ENABLE		0x01	/* enable bus-master			*/
+#define PCI_BM_CTL_BURST		0x02	/* enable burst				*/
+#define PCI_BM_CTL_BACK2BACK		0x04	/* enable back to back			*/
+#define PCI_BM_CTL_DUMMY		0x08	/* insert dummy cycle			*/
+
+#define X_V2_VID_MEM_START	0x40
+#define X_V2_VID_SRC_WIDTH	0x43
+#define X_V2_X_START		0x45
+#define X_V2_X_END		0x47
+#define X_V2_Y_START		0x49
+#define X_V2_Y_END		0x4b
+#define X_V2_VID_SRC_WIN_WIDTH	0x4d
+
+#define Y_V2_DDA_X_INC		0x43
+#define Y_V2_DDA_Y_INC		0x47
+#define Y_V2_VID_FIFO_CTL	0x49
+#define Y_V2_VID_FMT		0x4b
+#define Y_V2_VID_DISP_CTL1	0x4c
+#define Y_V2_VID_FIFO_CTL1	0x4d
+
+#define J_X2_VID_MEM_START	0x40
+#define J_X2_VID_SRC_WIDTH	0x43
+#define J_X2_X_START		0x47
+#define J_X2_X_END		0x49
+#define J_X2_Y_START		0x4b
+#define J_X2_Y_END		0x4d
+#define J_X2_VID_SRC_WIN_WIDTH	0x4f
+
+#define K_X2_DDA_X_INIT		0x40
+#define K_X2_DDA_X_INC		0x42
+#define K_X2_DDA_Y_INIT		0x44
+#define K_X2_DDA_Y_INC		0x46
+#define K_X2_VID_FMT		0x48
+#define K_X2_VID_DISP_CTL1	0x49
+
+#define K_CAP_X2_CTL1		0x49
+
+#define CURS_H_START		0x50
+#define CURS_H_PRESET		0x52
+#define CURS_V_START		0x53
+#define CURS_V_PRESET		0x55
+#define CURS_CTL		0x56
+
+#define EXT_ATTRIB_CTL		0x57
+#define EXT_ATTRIB_CTL_EXT		0x01
+
+#define EXT_OVERSCAN_RED	0x58
+#define EXT_OVERSCAN_GREEN	0x59
+#define EXT_OVERSCAN_BLUE	0x5a
+
+#define CAP_X_START		0x60
+#define CAP_X_END		0x62
+#define CAP_Y_START		0x64
+#define CAP_Y_END		0x66
+#define CAP_DDA_X_INIT		0x68
+#define CAP_DDA_X_INC		0x6a
+#define CAP_DDA_Y_INIT		0x6c
+#define CAP_DDA_Y_INC		0x6e
+
+#define EXT_MEM_CTL0		0x70
+#define EXT_MEM_CTL0_7CLK		0x01
+#define EXT_MEM_CTL0_RAS_1		0x02
+#define EXT_MEM_CTL0_RAS2CAS_1		0x04
+#define EXT_MEM_CTL0_MULTCAS		0x08
+#define EXT_MEM_CTL0_ASYM		0x10
+#define EXT_MEM_CTL0_CAS1ON		0x20
+#define EXT_MEM_CTL0_FIFOFLUSH		0x40
+#define EXT_MEM_CTL0_SEQRESET		0x80
+
+#define EXT_MEM_CTL1		0x71
+#define EXT_MEM_CTL1_PAR		0x00
+#define EXT_MEM_CTL1_SERPAR		0x01
+#define EXT_MEM_CTL1_SER		0x03
+#define EXT_MEM_CTL1_SYNC		0x04
+#define EXT_MEM_CTL1_VRAM		0x08
+#define EXT_MEM_CTL1_4K_REFRESH		0x10
+#define EXT_MEM_CTL1_256Kx4		0x00
+#define EXT_MEM_CTL1_512Kx8		0x40
+#define EXT_MEM_CTL1_1Mx16		0x60
+
+#define EXT_MEM_CTL2		0x72
+#define MEM_CTL2_SIZE_1MB		0x00
+#define MEM_CTL2_SIZE_2MB		0x01
+#define MEM_CTL2_SIZE_4MB		0x02
+#define MEM_CTL2_SIZE_MASK		0x03
+#define MEM_CTL2_64BIT			0x04
+
+#define EXT_HIDDEN_CTL1		0x73
+
+#define EXT_FIFO_CTL		0x74
+
+#define EXT_SEQ_MISC		0x77
+#define EXT_SEQ_MISC_8			0x01
+#define EXT_SEQ_MISC_16_RGB565		0x02
+#define EXT_SEQ_MISC_32			0x03
+#define EXT_SEQ_MISC_24_RGB888		0x04
+#define EXT_SEQ_MISC_16_RGB555		0x06
+#define EXT_SEQ_MISC_8_RGB332		0x09
+#define EXT_SEQ_MISC_16_RGB444		0x0a
+
+#define EXT_HIDDEN_CTL4		0x7a
+
+#define CURS_MEM_START		0x7e		/* bits 23..12 */
+
+#define CAP_PIP_X_START		0x80
+#define CAP_PIP_X_END		0x82
+#define CAP_PIP_Y_START		0x84
+#define CAP_PIP_Y_END		0x86
+
+#define EXT_CAP_CTL1		0x88
+
+#define EXT_CAP_CTL2		0x89
+#define EXT_CAP_CTL2_ODDFRAMEIRQ	0x01
+#define EXT_CAP_CTL2_ANYFRAMEIRQ	0x02
+
+#define BM_CTRL0		0x9c
+#define BM_CTRL1		0x9d
+
+#define EXT_CAP_MODE1		0xa4
+#define EXT_CAP_MODE1_8BIT		0x01	/* enable 8bit capture mode		*/
+#define EXT_CAP_MODE1_CCIR656		0x02	/* CCIR656 mode				*/
+#define EXT_CAP_MODE1_IGNOREVGT		0x04	/* ignore VGT				*/
+#define EXT_CAP_MODE1_ALTFIFO		0x10	/* use alternate FIFO for capture	*/
+#define EXT_CAP_MODE1_SWAPUV		0x20	/* swap UV bytes			*/
+#define EXT_CAP_MODE1_MIRRORY		0x40	/* mirror vertically			*/
+#define EXT_CAP_MODE1_MIRRORX		0x80	/* mirror horizontally			*/
+
+#define EXT_CAP_MODE2		0xa5
+#define EXT_CAP_MODE2_CCIRINVOE		0x01
+#define EXT_CAP_MODE2_CCIRINVVGT	0x02
+#define EXT_CAP_MODE2_CCIRINVHGT	0x04
+#define EXT_CAP_MODE2_CCIRINVDG		0x08
+#define EXT_CAP_MODE2_DATEND		0x10
+#define EXT_CAP_MODE2_CCIRDGH		0x20
+#define EXT_CAP_MODE2_FIXSONY		0x40
+#define EXT_CAP_MODE2_SYNCFREEZE	0x80
+
+#define EXT_TV_CTL		0xae
+
+#define EXT_DCLK_MULT		0xb0
+#define EXT_DCLK_DIV		0xb1
+#define EXT_DCLK_DIV_VFSEL		0x20
+#define EXT_MCLK_MULT		0xb2
+#define EXT_MCLK_DIV		0xb3
+
+#define EXT_LATCH1		0xb5
+#define EXT_LATCH1_VAFC_EN		0x01	/* enable VAFC				*/
+
+#define EXT_FEATURE		0xb7
+#define EXT_FEATURE_BUS_MASK		0x07	/* host bus mask			*/
+#define EXT_FEATURE_BUS_PCI		0x00
+#define EXT_FEATURE_BUS_VL_STD		0x04
+#define EXT_FEATURE_BUS_VL_LINEAR	0x05
+#define EXT_FEATURE_1682		0x20	/* IGS 1682 compatibility		*/
+
+#define EXT_LATCH2		0xb6
+#define EXT_LATCH2_I2C_CLKEN		0x10
+#define EXT_LATCH2_I2C_CLK		0x20
+#define EXT_LATCH2_I2C_DATEN		0x40
+#define EXT_LATCH2_I2C_DAT		0x80
+
+#define EXT_XT_CTL		0xbe
+#define EXT_XT_CAP16			0x04
+#define EXT_XT_LINEARFB			0x08
+#define EXT_XT_PAL			0x10
+
+#define EXT_MEM_START		0xc0		/* ext start address 21 bits		*/
+#define HOR_PHASE_SHIFT		0xc2		/* high 3 bits				*/
+#define EXT_SRC_WIDTH		0xc3		/* ext offset phase  10 bits		*/
+#define EXT_SRC_HEIGHT		0xc4		/* high 6 bits				*/
+#define EXT_X_START		0xc5		/* ext->screen, 16 bits			*/
+#define EXT_X_END		0xc7		/* ext->screen, 16 bits			*/
+#define EXT_Y_START		0xc9		/* ext->screen, 16 bits			*/
+#define EXT_Y_END		0xcb		/* ext->screen, 16 bits			*/
+#define EXT_SRC_WIN_WIDTH	0xcd		/* 8 bits				*/
+#define EXT_COLOUR_COMPARE	0xce		/* 24 bits				*/
+#define EXT_DDA_X_INIT		0xd1		/* ext->screen 16 bits			*/
+#define EXT_DDA_X_INC		0xd3		/* ext->screen 16 bits			*/
+#define EXT_DDA_Y_INIT		0xd5		/* ext->screen 16 bits			*/
+#define EXT_DDA_Y_INC		0xd7		/* ext->screen 16 bits			*/
+
+#define EXT_VID_FIFO_CTL	0xd9
+
+#define EXT_VID_FMT		0xdb
+#define EXT_VID_FMT_YUV422		0x00	/* formats - does this cause conversion? */
+#define EXT_VID_FMT_RGB555		0x01
+#define EXT_VID_FMT_RGB565		0x02
+#define EXT_VID_FMT_RGB888_24		0x03
+#define EXT_VID_FMT_RGB888_32		0x04
+#define EXT_VID_FMT_RGB8		0x05
+#define EXT_VID_FMT_RGB4444		0x06
+#define EXT_VID_FMT_RGB8T		0x07
+#define EXT_VID_FMT_DUP_PIX_ZOON	0x08	/* duplicate pixel zoom			*/
+#define EXT_VID_FMT_MOD_3RD_PIX		0x20	/* modify 3rd duplicated pixel		*/
+#define EXT_VID_FMT_DBL_H_PIX		0x40	/* double horiz pixels			*/
+#define EXT_VID_FMT_YUV128		0x80	/* YUV data offset by 128		*/
+
+#define EXT_VID_DISP_CTL1	0xdc
+#define EXT_VID_DISP_CTL1_INTRAM	0x01	/* video pixels go to internal RAM	*/
+#define EXT_VID_DISP_CTL1_IGNORE_CCOMP	0x02	/* ignore colour compare registers	*/
+#define EXT_VID_DISP_CTL1_NOCLIP	0x04	/* do not clip to 16235,16240		*/
+#define EXT_VID_DISP_CTL1_UV_AVG	0x08	/* U/V data is averaged			*/
+#define EXT_VID_DISP_CTL1_Y128		0x10	/* Y data offset by 128 (if YUV128 set)	*/
+#define EXT_VID_DISP_CTL1_VINTERPOL_OFF	0x20	/* disable vertical interpolation	*/
+#define EXT_VID_DISP_CTL1_FULL_WIN	0x40	/* video out window full		*/
+#define EXT_VID_DISP_CTL1_ENABLE_WINDOW	0x80	/* enable video window			*/
+
+#define EXT_VID_FIFO_CTL1	0xdd
+#define EXT_VID_FIFO_CTL1_OE_HIGH	0x02
+#define EXT_VID_FIFO_CTL1_INTERLEAVE	0x04	/* enable interleaved memory read	*/
+
+#define EXT_ROM_UCB4GH		0xe5
+#define EXT_ROM_UCB4GH_FREEZE		0x02	/* capture frozen			*/
+#define EXT_ROM_UCB4GH_ODDFRAME		0x04	/* 1 = odd frame captured		*/
+#define EXT_ROM_UCB4GH_1HL		0x08	/* first horizonal line after VGT falling edge */
+#define EXT_ROM_UCB4GH_ODD		0x10	/* odd frame indicator			*/
+#define EXT_ROM_UCB4GH_INTSTAT		0x20	/* video interrupt			*/
+
+#define VFAC_CTL1		0xe8
+#define VFAC_CTL1_CAPTURE		0x01	/* capture enable (only when VSYNC high)*/
+#define VFAC_CTL1_VFAC_ENABLE		0x02	/* vfac enable				*/
+#define VFAC_CTL1_FREEZE_CAPTURE	0x04	/* freeze capture			*/
+#define VFAC_CTL1_FREEZE_CAPTURE_SYNC	0x08	/* sync freeze capture			*/
+#define VFAC_CTL1_VALIDFRAME_SRC	0x10	/* select valid frame source		*/
+#define VFAC_CTL1_PHILIPS		0x40	/* select Philips mode			*/
+#define VFAC_CTL1_MODVINTERPOLCLK	0x80	/* modify vertical interpolation clocl	*/
+
+#define VFAC_CTL2		0xe9
+#define VFAC_CTL2_INVERT_VIDDATAVALID	0x01	/* invert video data valid		*/
+#define VFAC_CTL2_INVERT_GRAPHREADY	0x02	/* invert graphic ready output sig	*/
+#define VFAC_CTL2_INVERT_DATACLK	0x04	/* invert data clock signal		*/
+#define VFAC_CTL2_INVERT_HSYNC		0x08	/* invert hsync input			*/
+#define VFAC_CTL2_INVERT_VSYNC		0x10	/* invert vsync input			*/
+#define VFAC_CTL2_INVERT_FRAME		0x20	/* invert frame odd/even input		*/
+#define VFAC_CTL2_INVERT_BLANK		0x40	/* invert blank output			*/
+#define VFAC_CTL2_INVERT_OVSYNC		0x80	/* invert other vsync input		*/
+
+#define VFAC_CTL3		0xea
+#define VFAC_CTL3_CAP_LARGE_FIFO	0x01	/* large capture fifo			*/
+#define VFAC_CTL3_CAP_INTERLACE		0x02	/* capture odd and even fields		*/
+#define VFAC_CTL3_CAP_HOLD_4NS		0x00	/* hold capture data for 4ns		*/
+#define VFAC_CTL3_CAP_HOLD_2NS		0x04	/* hold capture data for 2ns		*/
+#define VFAC_CTL3_CAP_HOLD_6NS		0x08	/* hold capture data for 6ns		*/
+#define VFAC_CTL3_CAP_HOLD_0NS		0x0c	/* hold capture data for 0ns		*/
+#define VFAC_CTL3_CHROMAKEY		0x20	/* capture data will be chromakeyed	*/
+#define VFAC_CTL3_CAP_IRQ		0x40	/* enable capture interrupt		*/
+
+#define CAP_MEM_START		0xeb		/* 18 bits				*/
+#define CAP_MAP_WIDTH		0xed		/* high 6 bits				*/
+#define CAP_PITCH		0xee		/* 8 bits				*/
+
+#define CAP_CTL_MISC		0xef
+#define CAP_CTL_MISC_HDIV		0x01
+#define CAP_CTL_MISC_HDIV4		0x02
+#define CAP_CTL_MISC_ODDEVEN		0x04
+#define CAP_CTL_MISC_HSYNCDIV2		0x08
+#define CAP_CTL_MISC_SYNCTZHIGH		0x10
+#define CAP_CTL_MISC_SYNCTZOR		0x20
+#define CAP_CTL_MISC_DISPUSED		0x80
+
+#define REG_BANK		0xfa
+#define REG_BANK_X			0x00
+#define REG_BANK_Y			0x01
+#define REG_BANK_W			0x02
+#define REG_BANK_T			0x03
+#define REG_BANK_J			0x04
+#define REG_BANK_K			0x05
+
+/*
+ * Bus-master
+ */
+#define BM_VID_ADDR_LOW		0xbc040
+#define BM_VID_ADDR_HIGH	0xbc044
+#define BM_ADDRESS_LOW		0xbc080
+#define BM_ADDRESS_HIGH		0xbc084
+#define BM_LENGTH		0xbc088
+#define BM_CONTROL		0xbc08c
+#define BM_CONTROL_ENABLE		0x01	/* enable transfer			*/
+#define BM_CONTROL_IRQEN		0x02	/* enable IRQ at end of transfer	*/
+#define BM_CONTROL_INIT			0x04	/* initialise status & count		*/
+#define BM_COUNT		0xbc090		/* read-only				*/
+
+/*
+ * TV registers
+ */
+#define TV_VBLANK_EVEN_START	0xbe43c
+#define TV_VBLANK_EVEN_END	0xbe440
+#define TV_VBLANK_ODD_START	0xbe444
+#define TV_VBLANK_ODD_END	0xbe448
+#define TV_SYNC_YGAIN		0xbe44c
+#define TV_UV_GAIN		0xbe450
+#define TV_PED_UVDET		0xbe454
+#define TV_UV_BURST_AMP		0xbe458
+#define TV_HSYNC_START		0xbe45c
+#define TV_HSYNC_END		0xbe460
+#define TV_Y_DELAY1		0xbe464
+#define TV_Y_DELAY2		0xbe468
+#define TV_UV_DELAY1		0xbe46c
+#define TV_BURST_START		0xbe470
+#define TV_BURST_END		0xbe474
+#define TV_HBLANK_START		0xbe478
+#define TV_HBLANK_END		0xbe47c
+#define TV_PED_EVEN_START	0xbe480
+#define TV_PED_EVEN_END		0xbe484
+#define TV_PED_ODD_START	0xbe488
+#define TV_PED_ODD_END		0xbe48c
+#define TV_VSYNC_EVEN_START	0xbe490
+#define TV_VSYNC_EVEN_END	0xbe494
+#define TV_VSYNC_ODD_START	0xbe498
+#define TV_VSYNC_ODD_END	0xbe49c
+#define TV_SCFL			0xbe4a0
+#define TV_SCFH			0xbe4a4
+#define TV_SCP			0xbe4a8
+#define TV_DELAYBYPASS		0xbe4b4
+#define TV_EQL_END		0xbe4bc
+#define TV_SERR_START		0xbe4c0
+#define TV_SERR_END		0xbe4c4
+#define TV_CTL			0xbe4dc	/* reflects a previous register- MVFCLR, MVPCLR etc P241*/
+#define TV_VSYNC_VGA_HS		0xbe4e8
+#define TV_FLICK_XMIN		0xbe514
+#define TV_FLICK_XMAX		0xbe518
+#define TV_FLICK_YMIN		0xbe51c
+#define TV_FLICK_YMAX		0xbe520
+
+/*
+ * Graphics Co-processor
+ */
+#define CO_REG_CONTROL		0xbf011
+#define CO_CTRL_BUSY			0x80
+#define CO_CTRL_CMDFULL			0x04
+#define CO_CTRL_FIFOEMPTY		0x02
+#define CO_CTRL_READY			0x01
+
+#define CO_REG_SRC_WIDTH	0xbf018
+#define CO_REG_PIXFMT		0xbf01c
+#define CO_PIXFMT_32BPP			0x03
+#define CO_PIXFMT_24BPP			0x02
+#define CO_PIXFMT_16BPP			0x01
+#define CO_PIXFMT_8BPP			0x00
+
+#define CO_REG_FGMIX		0xbf048
+#define CO_FG_MIX_ZERO			0x00
+#define CO_FG_MIX_SRC_AND_DST		0x01
+#define CO_FG_MIX_SRC_AND_NDST		0x02
+#define CO_FG_MIX_SRC			0x03
+#define CO_FG_MIX_NSRC_AND_DST		0x04
+#define CO_FG_MIX_DST			0x05
+#define CO_FG_MIX_SRC_XOR_DST		0x06
+#define CO_FG_MIX_SRC_OR_DST		0x07
+#define CO_FG_MIX_NSRC_AND_NDST		0x08
+#define CO_FG_MIX_SRC_XOR_NDST		0x09
+#define CO_FG_MIX_NDST			0x0a
+#define CO_FG_MIX_SRC_OR_NDST		0x0b
+#define CO_FG_MIX_NSRC			0x0c
+#define CO_FG_MIX_NSRC_OR_DST		0x0d
+#define CO_FG_MIX_NSRC_OR_NDST		0x0e
+#define CO_FG_MIX_ONES			0x0f
+
+#define CO_REG_FGCOLOUR		0xbf058
+#define CO_REG_BGCOLOUR		0xbf05c
+#define CO_REG_PIXWIDTH		0xbf060
+#define CO_REG_PIXHEIGHT	0xbf062
+#define CO_REG_X_PHASE		0xbf078
+#define CO_REG_CMD_L		0xbf07c
+#define CO_CMD_L_PATTERN_FGCOL		0x8000
+#define CO_CMD_L_INC_LEFT		0x0004
+#define CO_CMD_L_INC_UP			0x0002
+
+#define CO_REG_CMD_H		0xbf07e
+#define CO_CMD_H_BGSRCMAP		0x8000	/* otherwise bg colour */
+#define CO_CMD_H_FGSRCMAP		0x2000	/* otherwise fg colour */
+#define CO_CMD_H_BLITTER		0x0800
+
+#define CO_REG_SRC1_PTR		0xbf170
+#define CO_REG_SRC2_PTR		0xbf174
+#define CO_REG_DEST_PTR		0xbf178
+#define CO_REG_DEST_WIDTH	0xbf218
+
+/*
+ * Private structure
+ */
+struct cfb_info;
+
+struct cyberpro_info {
+	struct pci_dev	*dev;
+	unsigned char	__iomem *regs;
+	char		__iomem *fb;
+	char		dev_name[32];
+	unsigned int	fb_size;
+	unsigned int	chip_id;
+
+	/*
+	 * The following is a pointer to be passed into the
+	 * functions below.  The modules outside the main
+	 * cyber2000fb.c driver have no knowledge as to what
+	 * is within this structure.
+	 */
+	struct cfb_info *info;
+
+	/*
+	 * Use these to enable the BM or TV registers.  In an SMP
+	 * environment, these two function pointers should only be
+	 * called from the module_init() or module_exit()
+	 * functions.
+	 */
+	void (*enable_extregs)(struct cfb_info *);
+	void (*disable_extregs)(struct cfb_info *);
+};
+
+#define ID_IGA_1682		0
+#define ID_CYBERPRO_2000	1
+#define ID_CYBERPRO_2010	2
+#define ID_CYBERPRO_5000	3
+
+struct fb_var_screeninfo;
+
+/*
+ * Note! Writing to the Cyber20x0 registers from an interrupt
+ * routine is definitely a bad idea atm.
+ */
+int cyber2000fb_attach(struct cyberpro_info *info, int idx);
+void cyber2000fb_detach(int idx);
+void cyber2000fb_enable_extregs(struct cfb_info *cfb);
+void cyber2000fb_disable_extregs(struct cfb_info *cfb);
+void cyber2000fb_get_fb_var(struct cfb_info *cfb, struct fb_var_screeninfo *var);
diff --git a/drivers/video/cyberfb.c b/drivers/video/cyberfb.c
new file mode 100644
index 0000000..a3e189f
--- /dev/null
+++ b/drivers/video/cyberfb.c
@@ -0,0 +1,2296 @@
+/*
+* linux/drivers/video/cyberfb.c -- CyberVision64 frame buffer device
+* $Id: cyberfb.c,v 1.6 1998/09/11 04:54:58 abair Exp $
+*
+*    Copyright (C) 1998 Alan Bair
+*
+* This file is based on two CyberVision64 frame buffer device drivers
+*
+* The second CyberVision64 frame buffer device (cvision.c cvision_core.c):
+*
+*   Copyright (c) 1997 Antonio Santos
+*
+* Released as a patch to 2.1.35, but never included in the source tree.
+* This is based on work from the NetBSD CyberVision64 frame buffer 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
+*
+* The first CyberVision64 frame buffer device (cyberfb.c):
+*
+*    Copyright (C) 1996 Martin Apel
+*                       Geert Uytterhoeven
+*
+* Which is based on the Amiga frame buffer device (amifb.c):
+*
+*    Copyright (C) 1995 Geert Uytterhoeven
+*
+*
+* History:
+*   - 22 Dec 95: Original version by Martin Apel
+*   - 05 Jan 96: Geert: integration into the current source tree
+*   - 01 Aug 98: Alan: Merge in code from cvision.c and cvision_core.c
+* $Log: cyberfb.c,v $
+* Revision 1.6  1998/09/11 04:54:58  abair
+* Update for 2.1.120 change in include file location.
+* Clean up for public release.
+*
+* Revision 1.5  1998/09/03 04:27:13  abair
+* Move cv64_load_video_mode to cyber_set_video so a new video mode is install
+* with each change of the 'var' data.
+*
+* Revision 1.4  1998/09/01 00:31:17  abair
+* Put in a set of default 8,16,24 bpp modes and map cyber8,16 to them.
+* Update operations with 'par' to handle a more complete set of parameter
+* values for encode/decode process.
+*
+* Revision 1.3  1998/08/31 21:31:33  abair
+* Swap 800x490 for 640x480 video mode and more cleanup.
+* Abandon idea to resurrect "custom" mode setting via kernel opts,
+* instead work on making use of fbset program to do this.
+*
+* Revision 1.2  1998/08/31 06:17:08  abair
+* Make updates for changes in cyberfb.c released in 2.1.119
+* and do some cleanup of the code.
+*
+* Revision 1.1  1998/08/29 18:38:31  abair
+* Initial revision
+*
+* Revision 1.3  1998/08/17 06:21:53  abair
+* Remove more redundant code after merging in cvision_core.c
+* Set blanking by colormap to pale red to detect this vs trying to
+* use video blanking. More formating to Linux code style.
+*
+* Revision 1.2  1998/08/15 17:51:37  abair
+* Added cvision_core.c code from 2.1.35 patches.
+* Changed to compile correctly and switch to using initialization
+* code. Added debugging and dropping of duplicate code.
+*
+*
+*
+* 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/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/delay.h>
+#include <linux/zorro.h>
+#include <linux/fb.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 "cyberfb.h"
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+
+/*#define CYBERFBDEBUG*/
+#ifdef CYBERFBDEBUG
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+static void cv64_dump(void);
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#define wb_64(regs,reg,dat) (*(((volatile unsigned char *)regs) + reg) = dat)
+#define rb_64(regs, reg) (*(((volatile unsigned char *)regs) + reg))
+
+#define ww_64(regs,reg,dat) (*((volatile unsigned short *)(regs + reg) = dat)
+
+struct cyberfb_par {
+	struct fb_var_screeninfo var;
+	__u32 type;
+	__u32 type_aux;
+	__u32 visual;
+	__u32 line_length;
+};
+
+static struct cyberfb_par current_par;
+
+static int current_par_valid = 0;
+
+static struct display disp;
+static struct fb_info fb_info;
+
+
+/*
+ *    Frame Buffer Name
+ */
+
+static char cyberfb_name[16] = "Cybervision";
+
+
+/*
+ *    CyberVision Graphics Board
+ */
+
+static unsigned char Cyber_colour_table [256][3];
+static unsigned long CyberSize;
+static volatile unsigned char *CyberBase;
+static volatile unsigned char *CyberMem;
+static volatile unsigned char *CyberRegs;
+static unsigned long CyberMem_phys;
+static unsigned long CyberRegs_phys;
+
+/*
+ *    Predefined Video Modes
+ */
+
+static struct {
+    const char *name;
+    struct fb_var_screeninfo var;
+} cyberfb_predefined[] __initdata = {
+	{ "640x480-8", {		/* Default 8 BPP mode (cyber8) */
+		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, 39722, 40, 24, 32, 11, 96, 2,
+		FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, 
+		FB_VMODE_NONINTERLACED
+	}}, 
+	{ "640x480-16", {		/* Default 16 BPP mode (cyber16) */
+		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, 39722, 40, 24, 32, 11, 96, 2,
+		FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, 
+		FB_VMODE_NONINTERLACED
+	}}, 
+	{ "640x480-24", {		/* Default 24 BPP mode */
+		640, 480, 640, 480, 0, 0, 24, 0,
+		{16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0},
+		0, 0, -1, -1, FB_ACCELF_TEXT, 39722, 40, 24, 32, 11, 96, 2,
+		FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, 
+		FB_VMODE_NONINTERLACED
+	}}, 
+	{ "800x490-8", {		/* Cybervision 8 bpp */
+		/* NO Acceleration */
+		800, 490, 800, 490, 0, 0, 8, 0,
+		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+		0, 0, -1, -1, FB_ACCEL_NONE, 33333, 80, 24, 23, 1, 56, 8,
+		FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
+		FB_VMODE_NONINTERLACED
+	}},
+/* I can't test these with my monitor, but I suspect they will
+ * be OK, since Antonio Santos indicated he had tested them in
+ * his system.
+ */
+	{ "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, 27778, 64, 24, 22, 1, 72, 2,
+		FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
+		FB_VMODE_NONINTERLACED
+	}},
+	{ "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, 16667, 224, 72, 60, 12, 168, 4,
+		FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
+		FB_VMODE_NONINTERLACED
+	}},
+	{ "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, 15873, 184, 40, 24, 1, 56, 16,
+		FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
+		FB_VMODE_NONINTERLACED
+	}},
+	{ "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, 16667, 256, 48, 50, 12, 72, 4,
+		FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
+		FB_VMODE_INTERLACED
+	}}
+};
+
+#define NUM_TOTAL_MODES    ARRAY_SIZE(cyberfb_predefined)
+
+static int Cyberfb_inverse = 0;
+
+/*
+ *    Some default modes
+ */
+
+#define CYBER8_DEFMODE     (0)
+#define CYBER16_DEFMODE    (1)
+
+static struct fb_var_screeninfo cyberfb_default;
+static int cyberfb_usermode __initdata = 0;
+
+/*
+ *    Interface used by the world
+ */
+
+int cyberfb_setup(char *options);
+
+static int cyberfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			   struct fb_info *info);
+static int cyberfb_get_var(struct fb_var_screeninfo *var, int con,
+			   struct fb_info *info);
+static int cyberfb_set_var(struct fb_var_screeninfo *var, int con,
+			   struct fb_info *info);
+static int cyberfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			    struct fb_info *info);
+static int cyberfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			     u_int transp, struct fb_info *info);
+static int cyberfb_blank(int blank, struct fb_info *info);
+
+/*
+ *    Interface to the low level console driver
+ */
+
+int cyberfb_init(void);
+static int Cyberfb_switch(int con, struct fb_info *info);
+static int Cyberfb_updatevar(int con, struct fb_info *info);
+
+/*
+ *    Text console acceleration
+ */
+
+#ifdef FBCON_HAS_CFB8
+static struct display_switch fbcon_cyber8;
+#endif
+
+/*
+ *    Accelerated Functions used by the low level console driver
+ */
+
+static void Cyber_WaitQueue(u_short fifo);
+static void Cyber_WaitBlit(void);
+static void Cyber_BitBLT(u_short curx, u_short cury, u_short destx,
+			 u_short desty, u_short width, u_short height,
+			 u_short mode);
+static void Cyber_RectFill(u_short x, u_short y, u_short width, u_short height,
+			   u_short mode, u_short color);
+#if 0
+static void Cyber_MoveCursor(u_short x, u_short y);
+#endif
+
+/*
+ *   Hardware Specific Routines
+ */
+
+static int Cyber_init(void);
+static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
+			    struct cyberfb_par *par);
+static int Cyber_decode_var(struct fb_var_screeninfo *var,
+			    struct cyberfb_par *par);
+static int Cyber_encode_var(struct fb_var_screeninfo *var,
+			    struct cyberfb_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);
+
+/*
+ *    Internal routines
+ */
+
+static void cyberfb_get_par(struct cyberfb_par *par);
+static void cyberfb_set_par(struct cyberfb_par *par);
+static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
+static void cyberfb_set_disp(int con, struct fb_info *info);
+static int get_video_mode(const char *name);
+
+/* For cvision_core.c */
+static unsigned short cv64_compute_clock(unsigned long);
+static int cv_has_4mb (volatile unsigned char *);
+static void cv64_board_init (void);
+static void cv64_load_video_mode (struct fb_var_screeninfo *);
+
+
+/* -------------------- Hardware specific routines ------------------------- */
+
+
+/*
+ *    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.
+ */
+
+static int Cyber_init(void)
+{
+	volatile unsigned char *regs = CyberRegs;
+	volatile unsigned long *CursorBase;
+	int i;
+	DPRINTK("ENTER\n");
+
+/* Init local cmap as greyscale levels */
+	for (i = 0; i < 256; i++) {
+		Cyber_colour_table [i][0] = i;
+		Cyber_colour_table [i][1] = i;
+		Cyber_colour_table [i][2] = i;
+	}
+
+/* Initialize the board and determine fbmem size */
+	cv64_board_init(); 
+#ifdef CYBERFBDEBUG
+	DPRINTK("Register state after initing board\n");
+	cv64_dump();
+#endif
+/* Clear framebuffer memory */
+	DPRINTK("Clear framebuffer memory\n");
+	memset ((char *)CyberMem, 0, CyberSize);
+
+/* Disable hardware cursor */
+	DPRINTK("Disable HW cursor\n");
+	wb_64(regs, S3_CRTC_ADR, S3_REG_LOCK2);
+	wb_64(regs, S3_CRTC_DATA, 0xa0);
+	wb_64(regs, S3_CRTC_ADR, S3_HGC_MODE);
+	wb_64(regs, S3_CRTC_DATA, 0x00);
+	wb_64(regs, S3_CRTC_ADR, S3_HWGC_DX);
+	wb_64(regs, S3_CRTC_DATA, 0x00);
+	wb_64(regs, S3_CRTC_ADR, S3_HWGC_DY);
+	wb_64(regs, S3_CRTC_DATA, 0x00);
+
+/* Initialize hardware cursor */
+	DPRINTK("Init HW cursor\n");
+	CursorBase = (u_long *)((char *)(CyberMem) + CyberSize - 0x400);
+	for (i=0; i < 8; i++)
+	{
+		*(CursorBase  +(i*4)) = 0xffffff00;
+		*(CursorBase+1+(i*4)) = 0xffff0000;
+		*(CursorBase+2+(i*4)) = 0xffff0000;
+		*(CursorBase+3+(i*4)) = 0xffff0000;
+	}
+	for (i=8; i < 64; i++)
+	{
+		*(CursorBase  +(i*4)) = 0xffff0000;
+		*(CursorBase+1+(i*4)) = 0xffff0000;
+		*(CursorBase+2+(i*4)) = 0xffff0000;
+		*(CursorBase+3+(i*4)) = 0xffff0000;
+	}
+
+	cyberfb_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, NULL /* unused */);
+	cyberfb_setcolreg (254, 0, 0, 0, 0, NULL /* unused */);
+
+	DPRINTK("EXIT\n");
+	return 0;
+}
+
+
+/*
+ *    This function should fill in the `fix' structure based on the
+ *    values in the `par' structure.
+ */
+
+static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
+			    struct cyberfb_par *par)
+{
+	DPRINTK("ENTER\n");
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+	strcpy(fix->id, cyberfb_name);
+	fix->smem_start = CyberMem_phys;
+	fix->smem_len = CyberSize;
+	fix->mmio_start = CyberRegs_phys;
+	fix->mmio_len = 0x10000;
+
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->type_aux = 0;
+	if (par->var.bits_per_pixel == 15 || par->var.bits_per_pixel == 16 ||
+	    par->var.bits_per_pixel == 24 || par->var.bits_per_pixel == 32) {
+		fix->visual = FB_VISUAL_DIRECTCOLOR;
+	} else {
+		fix->visual = FB_VISUAL_PSEUDOCOLOR;
+	}
+
+	fix->xpanstep = 0;
+	fix->ypanstep = 0;
+	fix->ywrapstep = 0;
+	fix->line_length = 0;
+	fix->accel = FB_ACCEL_S3_TRIO64;
+
+	DPRINTK("EXIT\n");
+	return(0);
+}
+
+
+/*
+*    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,
+			    struct cyberfb_par *par)
+{
+	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;
+	par->var.xoffset = var->xoffset;
+	par->var.yoffset = var->yoffset;
+	par->var.bits_per_pixel = var->bits_per_pixel;
+	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->var.accel_flags = 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.
+*/
+
+static int Cyber_encode_var(struct fb_var_screeninfo *var,
+			    struct cyberfb_par *par)
+{
+	DPRINTK("ENTER\n");
+	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. Return != 0 for invalid regno.
+ */
+
+static int cyberfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			   u_int transp, struct fb_info *info)
+{
+	volatile unsigned char *regs = CyberRegs;
+
+	/*DPRINTK("ENTER\n");*/
+	if (regno > 255) {
+		DPRINTK("EXIT - Register # > 255\n");
+		return (1);
+	}
+
+	wb_64(regs, 0x3c8, (unsigned char) regno);
+
+ 	red >>= 10;
+ 	green >>= 10;
+ 	blue >>= 10;
+
+	Cyber_colour_table [regno][0] = red;
+	Cyber_colour_table [regno][1] = green;
+	Cyber_colour_table [regno][2] = blue;
+
+	wb_64(regs, 0x3c9, red);
+	wb_64(regs, 0x3c9, green);
+	wb_64(regs, 0x3c9, blue);
+
+	/*DPRINTK("EXIT\n");*/
+	return (0);
+}
+
+
+/*
+*    Read a single color register and split it into
+*    colors/transparent. Return != 0 for invalid regno.
+*/
+
+static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+			   u_int *transp, struct fb_info *info)
+{
+	int t;
+
+	/*DPRINTK("ENTER\n");*/
+	if (regno > 255) {
+		DPRINTK("EXIT - Register # > 255\n");
+		return (1);
+	}
+	/* ARB This shifting & oring seems VERY strange */
+ 	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);
+ 	*transp = 0;
+	/*DPRINTK("EXIT\n");*/
+	return (0);
+}
+
+
+/*
+*    (Un)Blank the screen
+*    blank: 1 = zero fb cmap
+*           0 = restore fb cmap from local cmap
+*/
+static int cyberfb_blank(int blank, struct fb_info *info)
+{
+	volatile unsigned char *regs = CyberRegs;
+	int i;
+
+	DPRINTK("ENTER\n");
+#if 0
+/* Blank by turning gfx off */
+	gfx_on_off (1, regs);
+#else
+	if (blank) {
+		for (i = 0; i < 256; i++) {
+			wb_64(regs, 0x3c8, (unsigned char) i);
+			/* ARB Pale red to detect this blanking method */
+			wb_64(regs, 0x3c9, 48); 
+			wb_64(regs, 0x3c9, 0);
+			wb_64(regs, 0x3c9, 0);
+		}
+	} else {
+		for (i = 0; i < 256; i++) {
+			wb_64(regs, 0x3c8, (unsigned char) i);
+			wb_64(regs, 0x3c9, Cyber_colour_table[i][0]);
+			wb_64(regs, 0x3c9, Cyber_colour_table[i][1]);
+			wb_64(regs, 0x3c9, Cyber_colour_table[i][2]);
+		}
+	}
+#endif
+	DPRINTK("EXIT\n");
+	return 0;
+}
+
+
+/**************************************************************
+ * We are waiting for "fifo" FIFO-slots empty
+ */
+static void Cyber_WaitQueue (u_short fifo)
+{
+	unsigned short status;
+
+	DPRINTK("ENTER\n");
+	do {
+		status = *((u_short volatile *)(CyberRegs + S3_GP_STAT));
+	} while (status & fifo);
+	DPRINTK("EXIT\n");
+}
+
+/**************************************************************
+ * We are waiting for Hardware (Graphics Engine) not busy
+ */
+static void Cyber_WaitBlit (void)
+{
+	unsigned short status;
+
+	DPRINTK("ENTER\n");
+	do {
+		status = *((u_short volatile *)(CyberRegs + S3_GP_STAT));
+	} while (status & S3_HDW_BUSY);
+	DPRINTK("EXIT\n");
+}
+
+/**************************************************************
+ * BitBLT - Through the Plane
+ */
+static void Cyber_BitBLT (u_short curx, u_short cury, u_short destx,
+			  u_short desty, u_short width, u_short height,
+			  u_short mode)
+{
+	volatile unsigned char *regs = CyberRegs;
+	u_short blitcmd = S3_BITBLT;
+
+	DPRINTK("ENTER\n");
+	/* Set drawing direction */
+	/* -Y, X maj, -X (default) */
+	if (curx > destx) {
+		blitcmd |= 0x0020;  /* Drawing direction +X */
+	} else {
+		curx  += (width - 1);
+		destx += (width - 1);
+	}
+
+	if (cury > desty) {
+		blitcmd |= 0x0080;  /* Drawing direction +Y */
+	} else {
+		cury  += (height - 1);
+		desty += (height - 1);
+	}
+
+	Cyber_WaitQueue (0x8000);
+
+	*((u_short volatile *)(regs + S3_PIXEL_CNTL)) = 0xa000;
+	*((u_short volatile *)(regs + S3_FRGD_MIX)) = (0x0060 | mode);
+
+	*((u_short volatile *)(regs + S3_CUR_X)) = curx;
+	*((u_short volatile *)(regs + S3_CUR_Y)) = cury;
+
+	*((u_short volatile *)(regs + S3_DESTX_DIASTP)) = destx;
+	*((u_short volatile *)(regs + S3_DESTY_AXSTP)) = desty;
+
+	*((u_short volatile *)(regs + S3_MIN_AXIS_PCNT)) = height - 1;
+	*((u_short volatile *)(regs + S3_MAJ_AXIS_PCNT)) = width  - 1;
+
+	*((u_short volatile *)(regs + S3_CMD)) = blitcmd;
+	DPRINTK("EXIT\n");
+}
+
+/**************************************************************
+ * Rectangle Fill Solid
+ */
+static void Cyber_RectFill (u_short x, u_short y, u_short width,
+			    u_short height, u_short mode, u_short color)
+{
+	volatile unsigned char *regs = CyberRegs;
+	u_short blitcmd = S3_FILLEDRECT;
+
+	DPRINTK("ENTER\n");
+	Cyber_WaitQueue (0x8000);
+
+	*((u_short volatile *)(regs + S3_PIXEL_CNTL)) = 0xa000;
+	*((u_short volatile *)(regs + S3_FRGD_MIX)) = (0x0020 | mode);
+
+	*((u_short volatile *)(regs + S3_MULT_MISC)) = 0xe000;
+	*((u_short volatile *)(regs + S3_FRGD_COLOR)) = color;
+
+	*((u_short volatile *)(regs + S3_CUR_X)) = x;
+	*((u_short volatile *)(regs + S3_CUR_Y)) = y;
+
+	*((u_short volatile *)(regs + S3_MIN_AXIS_PCNT)) = height - 1;
+	*((u_short volatile *)(regs + S3_MAJ_AXIS_PCNT)) = width  - 1;
+
+	*((u_short volatile *)(regs + S3_CMD)) = blitcmd;
+	DPRINTK("EXIT\n");
+}
+
+
+#if 0
+/**************************************************************
+ * Move cursor to x, y
+ */
+static void Cyber_MoveCursor (u_short x, u_short y)
+{
+	volatile unsigned char *regs = CyberRegs;
+	DPRINTK("ENTER\n");
+	*(regs + S3_CRTC_ADR)  = 0x39;
+	*(regs + S3_CRTC_DATA) = 0xa0;
+
+	*(regs + S3_CRTC_ADR)  = S3_HWGC_ORGX_H;
+	*(regs + S3_CRTC_DATA) = (char)((x & 0x0700) >> 8);
+	*(regs + S3_CRTC_ADR)  = S3_HWGC_ORGX_L;
+	*(regs + S3_CRTC_DATA) = (char)(x & 0x00ff);
+
+	*(regs + S3_CRTC_ADR)  = S3_HWGC_ORGY_H;
+	*(regs + S3_CRTC_DATA) = (char)((y & 0x0700) >> 8);
+	*(regs + S3_CRTC_ADR)  = S3_HWGC_ORGY_L;
+	*(regs + S3_CRTC_DATA) = (char)(y & 0x00ff);
+	DPRINTK("EXIT\n");
+}
+#endif
+
+
+/* -------------------- Generic routines ---------------------------------- */
+
+
+/*
+ *    Fill the hardware's `par' structure.
+ */
+
+static void cyberfb_get_par(struct cyberfb_par *par)
+{
+	DPRINTK("ENTER\n");
+	if (current_par_valid) {
+		*par = current_par;
+	} else {
+		Cyber_decode_var(&cyberfb_default, par);
+	}
+	DPRINTK("EXIT\n");
+}
+
+
+static void cyberfb_set_par(struct cyberfb_par *par)
+{
+	DPRINTK("ENTER\n");
+	current_par = *par;
+	current_par_valid = 1;
+	DPRINTK("EXIT\n");
+}
+
+
+static void cyber_set_video(struct fb_var_screeninfo *var)
+{
+
+	/* Load the video mode defined by the 'var' data */
+	cv64_load_video_mode (var);
+#ifdef CYBERFBDEBUG
+	DPRINTK("Register state after loading video mode\n");
+	cv64_dump();
+#endif
+}
+
+
+static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
+{
+	int err, activate;
+	struct cyberfb_par par;
+
+	DPRINTK("ENTER\n");
+	if ((err = Cyber_decode_var(var, &par))) {
+		DPRINTK("EXIT - decode_var failed\n");
+		return(err);
+	}
+	activate = var->activate;
+	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
+		cyberfb_set_par(&par);
+	Cyber_encode_var(var, &par);
+	var->activate = activate;
+
+	cyber_set_video(var);
+	DPRINTK("EXIT\n");
+	return 0;
+}
+
+/*
+ *    Get the Fixed Part of the Display
+ */
+
+static int cyberfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			   struct fb_info *info)
+{
+	struct cyberfb_par par;
+	int error = 0;
+
+	DPRINTK("ENTER\n");
+	if (con == -1) {
+		cyberfb_get_par(&par);
+	} else {
+		error = Cyber_decode_var(&fb_display[con].var, &par);
+	}
+	DPRINTK("EXIT\n");
+	return(error ? error : Cyber_encode_fix(fix, &par));
+}
+
+
+/*
+ *    Get the User Defined Part of the Display
+ */
+
+static int cyberfb_get_var(struct fb_var_screeninfo *var, int con,
+			   struct fb_info *info)
+{
+	struct cyberfb_par par;
+	int error = 0;
+
+	DPRINTK("ENTER\n");
+	if (con == -1) {
+		cyberfb_get_par(&par);
+		error = Cyber_encode_var(var, &par);
+		disp.var = *var;   /* ++Andre: don't know if this is the right place */
+	} else {
+		*var = fb_display[con].var;
+	}
+
+	DPRINTK("EXIT\n");
+	return(error);
+}
+
+
+static void cyberfb_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
+		display = &disp;	/* used during initialization */
+
+	cyberfb_get_fix(&fix, con, info);
+	if (con == -1)
+		con = 0;
+	display->visual = fix.visual;
+	display->type = fix.type;
+	display->type_aux = fix.type_aux;
+	display->ypanstep = fix.ypanstep;
+	display->ywrapstep = fix.ywrapstep;
+	display->can_soft_blank = 1;
+	display->inverse = Cyberfb_inverse;
+	switch (display->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
+	    case 8:
+		if (display->var.accel_flags & FB_ACCELF_TEXT) {
+		    display->dispsw = &fbcon_cyber8;
+#warning FIXME: We should reinit the graphics engine here
+		} else
+		    display->dispsw = &fbcon_cfb8;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	    case 16:
+		display->dispsw = &fbcon_cfb16;
+		break;
+#endif
+	    default:
+		display->dispsw = NULL;
+		break;
+	}
+	DPRINTK("EXIT\n");
+}
+
+
+/*
+ *    Set the User Defined Part of the Display
+ */
+
+static int cyberfb_set_var(struct fb_var_screeninfo *var, int con,
+			   struct fb_info *info)
+{
+	int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel;
+
+	DPRINTK("ENTER\n");
+	if ((err = do_fb_set_var(var, con == info->currcon))) {
+		DPRINTK("EXIT - do_fb_set_var failed\n");
+		return(err);
+	}
+	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+		oldxres = fb_display[con].var.xres;
+		oldyres = fb_display[con].var.yres;
+		oldvxres = fb_display[con].var.xres_virtual;
+		oldvyres = fb_display[con].var.yres_virtual;
+		oldbpp = fb_display[con].var.bits_per_pixel;
+		oldaccel = fb_display[con].var.accel_flags;
+		fb_display[con].var = *var;
+		if (oldxres != var->xres || oldyres != var->yres ||
+		    oldvxres != var->xres_virtual ||
+		    oldvyres != var->yres_virtual ||
+		    oldbpp != var->bits_per_pixel ||
+		    oldaccel != var->accel_flags) {
+			cyberfb_set_disp(con, info);
+			(*fb_info.changevar)(con);
+			fb_alloc_cmap(&fb_display[con].cmap, 0, 0);
+			do_install_cmap(con, info);
+		}
+	}
+	var->activate = 0;
+	DPRINTK("EXIT\n");
+	return(0);
+}
+
+
+/*
+ *    Get the Colormap
+ */
+
+static int cyberfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			    struct fb_info *info)
+{
+	DPRINTK("ENTER\n");
+	if (con == info->currcon) { /* current console? */
+		DPRINTK("EXIT - console is current console\n");
+		return(fb_get_cmap(cmap, kspc, Cyber_getcolreg, info));
+	} 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 {
+		DPRINTK("Use default cmap\n");
+		fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
+			     cmap, kspc ? 0 : 2);
+	}
+	DPRINTK("EXIT\n");
+	return(0);
+}
+
+static struct fb_ops cyberfb_ops = {
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	cyberfb_get_fix,
+	.fb_get_var =	cyberfb_get_var,
+	.fb_set_var =	cyberfb_set_var,
+	.fb_get_cmap =	cyberfb_get_cmap,
+	.fb_set_cmap =	gen_set_cmap,
+	.fb_setcolreg =	cyberfb_setcolreg,
+	.fb_blank =	cyberfb_blank,
+};
+
+int __init cyberfb_setup(char *options)
+{
+	char *this_opt;
+	DPRINTK("ENTER\n");
+
+	fb_info.fontname[0] = '\0';
+
+	if (!options || !*options) {
+		DPRINTK("EXIT - no options\n");
+		return 0;
+	}
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt)
+			continue;
+		if (!strcmp(this_opt, "inverse")) {
+			Cyberfb_inverse = 1;
+			fb_invert_cmaps();
+		} else if (!strncmp(this_opt, "font:", 5)) {
+			strcpy(fb_info.fontname, this_opt+5);
+		} else if (!strcmp (this_opt, "cyber8")) {
+			cyberfb_default = cyberfb_predefined[CYBER8_DEFMODE].var;
+			cyberfb_usermode = 1;
+		} else if (!strcmp (this_opt, "cyber16")) {
+			cyberfb_default = cyberfb_predefined[CYBER16_DEFMODE].var;
+			cyberfb_usermode = 1;
+		} else get_video_mode(this_opt);
+	}
+
+	DPRINTK("default mode: xres=%d, yres=%d, bpp=%d\n",
+		cyberfb_default.xres,
+		cyberfb_default.yres,
+		cyberfb_default.bits_per_pixel);
+	DPRINTK("EXIT\n");
+	return 0;
+}
+
+/*
+ *    Initialization
+ */
+
+int __init cyberfb_init(void)
+{
+	unsigned long board_addr, board_size;
+	struct cyberfb_par par;
+	struct zorro_dev *z = NULL;
+	DPRINTK("ENTER\n");
+
+	while ((z = zorro_find_device(ZORRO_PROD_PHASE5_CYBERVISION64, z))) {
+	    board_addr = z->resource.start;
+	    board_size = z->resource.end-z->resource.start+1;
+	    CyberMem_phys = board_addr + 0x01400000;
+	    CyberRegs_phys = CyberMem_phys + 0x00c00000;
+	    if (!request_mem_region(CyberRegs_phys, 0x10000, "S3 Trio64"))
+		continue;
+	    if (!request_mem_region(CyberMem_phys, 0x400000, "RAM")) {
+		release_mem_region(CyberRegs_phys, 0x10000);
+		continue;
+	    }
+	    DPRINTK("board_addr=%08lx\n", board_addr);
+	    DPRINTK("board_size=%08lx\n", board_size);
+
+	    CyberBase = ioremap(board_addr, board_size);
+	    CyberRegs = CyberBase + 0x02000000;
+	    CyberMem = CyberBase + 0x01400000;
+	    DPRINTK("CyberBase=%08lx CyberRegs=%08lx CyberMem=%08lx\n",
+		    CyberBase, (long unsigned int)CyberRegs, CyberMem);
+
+#ifdef CYBERFBDEBUG
+	    DPRINTK("Register state just after mapping memory\n");
+	    cv64_dump();
+#endif
+
+	    strcpy(fb_info.modename, cyberfb_name);
+	    fb_info.changevar = NULL;
+	    fb_info.fbops = &cyberfb_ops;
+	    fb_info.screen_base = (unsigned char *)CyberMem;
+	    fb_info.disp = &disp;
+	    fb_info.currcon = -1;
+	    fb_info.switch_con = &Cyberfb_switch;
+	    fb_info.updatevar = &Cyberfb_updatevar;
+
+	    Cyber_init();
+	    /* ++Andre: set cyberfb default mode */
+	    if (!cyberfb_usermode) {
+		    cyberfb_default = cyberfb_predefined[CYBER8_DEFMODE].var;
+		    DPRINTK("Use default cyber8 mode\n");
+	    }
+	    Cyber_decode_var(&cyberfb_default, &par);
+	    Cyber_encode_var(&cyberfb_default, &par);
+
+	    do_fb_set_var(&cyberfb_default, 1);
+	    cyberfb_get_var(&fb_display[0].var, -1, &fb_info);
+	    cyberfb_set_disp(-1, &fb_info);
+	    do_install_cmap(0, &fb_info);
+
+	    if (register_framebuffer(&fb_info) < 0) {
+		    DPRINTK("EXIT - register_framebuffer failed\n");
+		    release_mem_region(CyberMem_phys, 0x400000);
+		    release_mem_region(CyberRegs_phys, 0x10000);
+		    return -EINVAL;
+	    }
+
+	    printk("fb%d: %s frame buffer device, using %ldK of video memory\n",
+		   fb_info.node, fb_info.modename, CyberSize>>10);
+
+	    /* TODO: This driver cannot be unloaded yet */
+	    DPRINTK("EXIT\n");
+	    return 0;
+	}
+	return -ENXIO;
+}
+
+
+static int Cyberfb_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, Cyber_getcolreg,
+			    info);
+	}
+
+	do_fb_set_var(&fb_display[con].var, 1);
+	info->currcon = con;
+	/* Install new colormap */
+	do_install_cmap(con, info);
+	DPRINTK("EXIT\n");
+	return(0);
+}
+
+
+/*
+ *    Update the `var' structure (called by fbcon.c)
+ *
+ *    This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
+ *    Since it's called by a kernel driver, no range checking is done.
+ */
+
+static int Cyberfb_updatevar(int con, struct fb_info *info)
+{
+	DPRINTK("Enter - Exit\n");
+	return(0);
+}
+
+
+/*
+ *    Get a Video Mode
+ */
+
+static int __init get_video_mode(const char *name)
+{
+	int i;
+
+	DPRINTK("ENTER\n");
+	for (i = 0; i < NUM_TOTAL_MODES; i++) {
+		if (!strcmp(name, cyberfb_predefined[i].name)) {
+			cyberfb_default = cyberfb_predefined[i].var;
+			cyberfb_usermode = 1;
+			DPRINTK("EXIT - Matched predefined mode\n");
+			return(i);
+		}
+	}
+	return(0);
+}
+
+
+/*
+ *    Text console acceleration
+ */
+
+#ifdef FBCON_HAS_CFB8
+static void fbcon_cyber8_bmove(struct display *p, int sy, int sx, int dy,
+			       int dx, int height, int width)
+{
+	DPRINTK("ENTER\n");
+	sx *= 8; dx *= 8; width *= 8;
+	Cyber_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)S3_NEW);
+	DPRINTK("EXIT\n");
+}
+
+static void fbcon_cyber8_clear(struct vc_data *conp, struct display *p, int sy,
+			       int sx, int height, int width)
+{
+	unsigned char bg;
+
+	DPRINTK("ENTER\n");
+	sx *= 8; width *= 8;
+	bg = attr_bgcol_ec(p,conp);
+	Cyber_RectFill((u_short)sx,
+		       (u_short)(sy*fontheight(p)),
+		       (u_short)width,
+		       (u_short)(height*fontheight(p)),
+		       (u_short)S3_NEW,
+		       (u_short)bg);
+	DPRINTK("EXIT\n");
+}
+
+static void fbcon_cyber8_putc(struct vc_data *conp, struct display *p, int c,
+			      int yy, int xx)
+{
+	DPRINTK("ENTER\n");
+	Cyber_WaitBlit();
+	fbcon_cfb8_putc(conp, p, c, yy, xx);
+	DPRINTK("EXIT\n");
+}
+
+static void fbcon_cyber8_putcs(struct vc_data *conp, struct display *p,
+			       const unsigned short *s, int count,
+			       int yy, int xx)
+{
+	DPRINTK("ENTER\n");
+	Cyber_WaitBlit();
+	fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
+	DPRINTK("EXIT\n");
+}
+
+static void fbcon_cyber8_revc(struct display *p, int xx, int yy)
+{
+	DPRINTK("ENTER\n");
+	Cyber_WaitBlit();
+	fbcon_cfb8_revc(p, xx, yy);
+	DPRINTK("EXIT\n");
+}
+
+static struct display_switch fbcon_cyber8 = {
+	.setup =	fbcon_cfb8_setup,
+	.bmove =	fbcon_cyber8_bmove,
+	.clear =	fbcon_cyber8_clear,
+	.putc =		fbcon_cyber8_putc,
+	.putcs =	fbcon_cyber8_putcs,
+	.revc =		fbcon_cyber8_revc,
+	.clear_margins =fbcon_cfb8_clear_margins,
+	.fontwidthmask =FONTWIDTH(8)
+};
+#endif
+
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+
+int init_module(void)
+{
+	return cyberfb_init();
+}
+#endif /* MODULE */
+
+/*
+ *
+ * Low level initialization routines for the CyberVision64 graphics card
+ *
+ * Most of the following code is from cvision_core.c
+ *
+ */
+
+#define MAXPIXELCLOCK 135000000 /* safety */
+
+#ifdef CV_AGGRESSIVE_TIMING
+long cv64_memclk = 55000000;
+#else
+long cv64_memclk = 50000000;
+#endif
+
+/*********************/
+
+static unsigned char clocks[]={
+  0x13, 0x61, 0x6b, 0x6d, 0x51, 0x69, 0x54, 0x69,
+  0x4f, 0x68, 0x6b, 0x6b, 0x18, 0x61, 0x7b, 0x6c,
+  0x51, 0x67, 0x24, 0x62, 0x56, 0x67, 0x77, 0x6a,
+  0x1d, 0x61, 0x53, 0x66, 0x6b, 0x68, 0x79, 0x69,
+  0x7c, 0x69, 0x7f, 0x69, 0x22, 0x61, 0x54, 0x65,
+  0x56, 0x65, 0x58, 0x65, 0x67, 0x66, 0x41, 0x63,
+  0x27, 0x61, 0x13, 0x41, 0x37, 0x62, 0x6b, 0x4d,
+  0x23, 0x43, 0x51, 0x49, 0x79, 0x66, 0x54, 0x49,
+  0x7d, 0x66, 0x34, 0x56, 0x4f, 0x63, 0x1f, 0x42,
+  0x6b, 0x4b, 0x7e, 0x4d, 0x18, 0x41, 0x2a, 0x43,
+  0x7b, 0x4c, 0x74, 0x4b, 0x51, 0x47, 0x65, 0x49,
+  0x24, 0x42, 0x68, 0x49, 0x56, 0x47, 0x75, 0x4a,
+  0x77, 0x4a, 0x31, 0x43, 0x1d, 0x41, 0x71, 0x49,
+  0x53, 0x46, 0x29, 0x42, 0x6b, 0x48, 0x1f, 0x41,
+  0x79, 0x49, 0x6f, 0x48, 0x7c, 0x49, 0x38, 0x43,
+  0x7f, 0x49, 0x5d, 0x46, 0x22, 0x41, 0x53, 0x45,
+  0x54, 0x45, 0x55, 0x45, 0x56, 0x45, 0x57, 0x45,
+  0x58, 0x45, 0x25, 0x41, 0x67, 0x46, 0x5b, 0x45,
+  0x41, 0x43, 0x78, 0x47, 0x27, 0x41, 0x51, 0x44,
+  0x13, 0x21, 0x7d, 0x47, 0x37, 0x42, 0x71, 0x46,
+  0x6b, 0x2d, 0x14, 0x21, 0x23, 0x23, 0x7d, 0x2f,
+  0x51, 0x29, 0x61, 0x2b, 0x79, 0x46, 0x1d, 0x22,
+  0x54, 0x29, 0x45, 0x27, 0x7d, 0x46, 0x7f, 0x46,
+  0x4f, 0x43, 0x2f, 0x41, 0x1f, 0x22, 0x6a, 0x2b,
+  0x6b, 0x2b, 0x5b, 0x29, 0x7e, 0x2d, 0x65, 0x44,
+  0x18, 0x21, 0x5e, 0x29, 0x2a, 0x23, 0x45, 0x26,
+  0x7b, 0x2c, 0x19, 0x21, 0x74, 0x2b, 0x75, 0x2b,
+  0x51, 0x27, 0x3f, 0x25, 0x65, 0x29, 0x40, 0x25,
+  0x24, 0x22, 0x41, 0x25, 0x68, 0x29, 0x42, 0x25,
+  0x56, 0x27, 0x7e, 0x2b, 0x75, 0x2a, 0x1c, 0x21,
+  0x77, 0x2a, 0x4f, 0x26, 0x31, 0x23, 0x6f, 0x29,
+  0x1d, 0x21, 0x32, 0x23, 0x71, 0x29, 0x72, 0x29,
+  0x53, 0x26, 0x69, 0x28, 0x29, 0x22, 0x75, 0x29,
+  0x6b, 0x28, 0x1f, 0x21, 0x1f, 0x21, 0x6d, 0x28,
+  0x79, 0x29, 0x2b, 0x22, 0x6f, 0x28, 0x59, 0x26,
+  0x7c, 0x29, 0x7d, 0x29, 0x38, 0x23, 0x21, 0x21,
+  0x7f, 0x29, 0x39, 0x23, 0x5d, 0x26, 0x75, 0x28,
+  0x22, 0x21, 0x77, 0x28, 0x53, 0x25, 0x6c, 0x27,
+  0x54, 0x25, 0x61, 0x26, 0x55, 0x25, 0x30, 0x22,
+  0x56, 0x25, 0x63, 0x26, 0x57, 0x25, 0x71, 0x27,
+  0x58, 0x25, 0x7f, 0x28, 0x25, 0x21, 0x74, 0x27,
+  0x67, 0x26, 0x40, 0x23, 0x5b, 0x25, 0x26, 0x21,
+  0x41, 0x23, 0x34, 0x22, 0x78, 0x27, 0x6b, 0x26,
+  0x27, 0x21, 0x35, 0x22, 0x51, 0x24, 0x7b, 0x27,
+  0x13, 0x1,  0x13, 0x1,  0x7d, 0x27, 0x4c, 0x9,
+  0x37, 0x22, 0x5b, 0xb,  0x71, 0x26, 0x5c, 0xb,
+  0x6b, 0xd,  0x47, 0x23, 0x14, 0x1,  0x4f, 0x9,
+  0x23, 0x3,  0x75, 0x26, 0x7d, 0xf,  0x1c, 0x2,
+  0x51, 0x9,  0x59, 0x24, 0x61, 0xb,  0x69, 0x25,
+  0x79, 0x26, 0x34, 0x5,  0x1d, 0x2,  0x6b, 0x25,
+  0x54, 0x9,  0x35, 0x5,  0x45, 0x7,  0x6d, 0x25,
+  0x7d, 0x26, 0x16, 0x1,  0x7f, 0x26, 0x77, 0xd,
+  0x4f, 0x23, 0x78, 0xd,  0x2f, 0x21, 0x27, 0x3,
+  0x1f, 0x2,  0x59, 0x9,  0x6a, 0xb,  0x73, 0x25,
+  0x6b, 0xb,  0x63, 0x24, 0x5b, 0x9,  0x20, 0x2,
+  0x7e, 0xd,  0x4b, 0x7,  0x65, 0x24, 0x43, 0x22,
+  0x18, 0x1,  0x6f, 0xb,  0x5e, 0x9,  0x70, 0xb,
+  0x2a, 0x3,  0x33, 0x4,  0x45, 0x6,  0x60, 0x9,
+  0x7b, 0xc,  0x19, 0x1,  0x19, 0x1,  0x7d, 0xc,
+  0x74, 0xb,  0x50, 0x7,  0x75, 0xb,  0x63, 0x9,
+  0x51, 0x7,  0x23, 0x2,  0x3f, 0x5,  0x1a, 0x1,
+  0x65, 0x9,  0x2d, 0x3,  0x40, 0x5,  0x0,  0x0,
+};
+
+/* Console colors */
+unsigned char cvconscolors[16][3] = {	/* background, foreground, hilite */
+  /*  R     G     B  */
+  {0x30, 0x30, 0x30},
+  {0x00, 0x00, 0x00},
+  {0x80, 0x00, 0x00},
+  {0x00, 0x80, 0x00},
+  {0x00, 0x00, 0x80},
+  {0x80, 0x80, 0x00},
+  {0x00, 0x80, 0x80},
+  {0x80, 0x00, 0x80},
+  {0xff, 0xff, 0xff},
+  {0x40, 0x40, 0x40},
+  {0xff, 0x00, 0x00},
+  {0x00, 0xff, 0x00},
+  {0x00, 0x00, 0xff},
+  {0xff, 0xff, 0x00},
+  {0x00, 0xff, 0xff},
+  {0x00, 0x00, 0xff}
+};
+
+/* -------------------- Hardware specific routines ------------------------- */
+
+/* Read Attribute Controller Register=idx */
+inline unsigned char RAttr (volatile unsigned char *regs, short idx)
+{
+	wb_64 (regs, ACT_ADDRESS_W, idx);
+	mb();
+	udelay(100);
+	return (rb_64(regs, ACT_ADDRESS_R));
+}
+
+/* Read Sequencer Register=idx */
+inline unsigned char RSeq (volatile unsigned char *regs, short idx)
+{
+	wb_64 (regs, SEQ_ADDRESS, idx);
+	mb();
+	return (rb_64(regs, SEQ_ADDRESS_R));
+}
+
+/* Read CRT Controller Register=idx */
+inline unsigned char RCrt (volatile unsigned char *regs, short idx)
+{
+	wb_64 (regs, CRT_ADDRESS, idx);
+	mb();
+	return (rb_64(regs, CRT_ADDRESS_R));
+}
+
+/* Read Graphics Controller Register=idx */
+inline unsigned char RGfx (volatile unsigned char *regs, short idx)
+{
+	wb_64 (regs, GCT_ADDRESS, idx);
+	mb();
+	return (rb_64(regs, GCT_ADDRESS_R));
+}
+
+/*
+ * Special wakeup/passthrough registers on graphics boards
+ */
+
+inline void cv64_write_port (unsigned short bits,
+			     volatile unsigned char *base)
+{
+	volatile unsigned char *addr;
+	static unsigned char cvportbits = 0; /* Mirror port bits here */
+	DPRINTK("ENTER\n");
+
+	addr = base + 0x40001;
+	if (bits & 0x8000) {
+		cvportbits |= bits & 0xff; /* Set bits */
+		DPRINTK("Set bits: %04x\n", bits);
+	} else {
+		bits = bits & 0xff;
+		bits = (~bits) & 0xff;
+		cvportbits &= bits; /* Clear bits */
+		DPRINTK("Clear bits: %04x\n", bits);
+	}
+
+	*addr = cvportbits;
+	DPRINTK("EXIT\n");
+}
+
+/*
+ * Monitor switch on CyberVision board
+ *
+ *  toggle:
+ *    0 = CyberVision Signal
+ *    1 = Amiga Signal
+ *  board = board addr
+ *
+ */
+inline void cvscreen (int toggle, volatile unsigned char *board)
+{
+	DPRINTK("ENTER\n");
+	if (toggle == 1) {
+		DPRINTK("Show Amiga video\n");
+		cv64_write_port (0x10, board);
+	} else {
+		DPRINTK("Show CyberVision video\n");
+		cv64_write_port (0x8010, board);
+	}
+	DPRINTK("EXIT\n");
+}
+
+/* Control screen display */
+/* toggle: 0 = on, 1 = off */
+/* board = registerbase */
+inline void gfx_on_off(int toggle, volatile unsigned char *regs)
+{
+	int r;
+	DPRINTK("ENTER\n");
+	
+	toggle &= 0x1;
+	toggle = toggle << 5;
+	DPRINTK("Turn display %s\n", (toggle ? "off" : "on"));
+	
+	r = (int) RSeq(regs, SEQ_ID_CLOCKING_MODE);
+	r &= 0xdf;	/* Set bit 5 to 0 */
+	
+	WSeq (regs, SEQ_ID_CLOCKING_MODE, r | toggle);
+	DPRINTK("EXIT\n");
+}
+
+/*
+ * Computes M, N, and R values from
+ * given input frequency. It uses a table of
+ * precomputed values, to keep CPU time low.
+ *
+ * The return value consist of:
+ * lower byte:  Bits 4-0: N Divider Value
+ *	        Bits 5-6: R Value          for e.g. SR10 or SR12
+ * higher byte: Bits 0-6: M divider value  for e.g. SR11 or SR13
+ */
+static unsigned short cv64_compute_clock(unsigned long freq)
+{
+	static unsigned char *mnr, *save;	/* M, N + R vals */
+	unsigned long work_freq, r;
+	unsigned short erg;
+	long diff, d2;
+
+	DPRINTK("ENTER\n");
+	if (freq < 12500000 || freq > MAXPIXELCLOCK) {
+		printk("CV64 driver: Illegal clock frequency %ld, using 25MHz\n",
+		       freq);
+		freq = 25000000;
+	}
+	DPRINTK("Freq = %ld\n", freq);
+	mnr = clocks;	/* there the vals are stored */
+	d2 = 0x7fffffff;
+
+	while (*mnr) {	/* mnr vals are 0-terminated */
+		work_freq = (0x37EE * (mnr[0] + 2)) / ((mnr[1] & 0x1F) + 2);
+
+		r = (mnr[1] >> 5) & 0x03;
+		if (r != 0) {
+			work_freq = work_freq >> r;	/* r is the freq divider */
+		}
+
+		work_freq *= 0x3E8;	/* 2nd part of OSC */
+
+		diff = abs(freq - work_freq);
+
+		if (d2 >= diff) {
+			d2 = diff;
+			/* In save are the vals for minimal diff */
+			save = mnr;
+		}
+		mnr += 2;
+	}
+	erg = *((unsigned short *)save);
+
+	DPRINTK("EXIT\n");
+	return (erg);
+}
+
+static int cv_has_4mb (volatile unsigned char *fb)
+{
+	volatile unsigned long *tr, *tw;
+	DPRINTK("ENTER\n");
+
+	/* write patterns in memory and test if they can be read */
+	tw = (volatile unsigned long *) fb;
+	tr = (volatile unsigned long *) (fb + 0x02000000);
+
+	*tw = 0x87654321;
+	
+	if (*tr != 0x87654321) {
+		DPRINTK("EXIT - <4MB\n");
+		return (0);
+	}
+
+	/* upper memory region */
+	tw = (volatile unsigned long *) (fb + 0x00200000);
+	tr = (volatile unsigned long *) (fb + 0x02200000);
+
+	*tw = 0x87654321;
+
+	if (*tr != 0x87654321) {
+		DPRINTK("EXIT - <4MB\n");
+		return (0);
+	}
+
+	*tw = 0xAAAAAAAA;
+
+	if (*tr != 0xAAAAAAAA) {
+		DPRINTK("EXIT - <4MB\n");
+		return (0);
+	}
+
+	*tw = 0x55555555;
+
+	if (*tr != 0x55555555) {
+		DPRINTK("EXIT - <4MB\n");
+		return (0);
+	}
+
+	DPRINTK("EXIT\n");
+	return (1);
+}
+
+static void cv64_board_init (void)
+{
+	volatile unsigned char *regs = CyberRegs;
+	int i;
+	unsigned int clockpar;
+	unsigned char test;
+	
+	DPRINTK("ENTER\n");
+
+	/*
+	 * Special CyberVision 64 board operations
+	 */
+	/* Reset board */
+	for (i = 0; i < 6; i++) {
+		cv64_write_port (0xff, CyberBase);
+	}
+	/* Return to operational mode */
+	cv64_write_port (0x8004, CyberBase);
+	
+	/*
+	 * Generic (?) S3 chip wakeup
+	 */
+	/* Disable I/O & memory decoders, video in setup mode */
+	wb_64 (regs, SREG_VIDEO_SUBS_ENABLE, 0x10);
+	/* Video responds to cmds, addrs & data */
+	wb_64 (regs, SREG_OPTION_SELECT, 0x1);
+	/* Enable I/O & memory decoders, video in operational mode */
+	wb_64 (regs, SREG_VIDEO_SUBS_ENABLE, 0x8);
+	/* VGA color emulation, enable cpu access to display mem */ 
+	wb_64 (regs, GREG_MISC_OUTPUT_W, 0x03);
+	/* Unlock S3 VGA regs */
+	WCrt (regs, CRT_ID_REGISTER_LOCK_1, 0x48); 
+	/* Unlock system control & extension registers */
+	WCrt (regs, CRT_ID_REGISTER_LOCK_2, 0xA5);
+/* GRF - Enable interrupts */
+	/* Enable enhanced regs access, Ready cntl 0 wait states */
+	test = RCrt (regs, CRT_ID_SYSTEM_CONFIG);
+	test = test | 0x01;		/* enable enhanced register access */
+	test = test & 0xEF;		/* clear bit 4, 0 wait state */
+	WCrt (regs, CRT_ID_SYSTEM_CONFIG, test);
+	/*
+	 * bit 0=1: Enable enhaced mode functions
+	 * bit 2=0: Enhanced mode 8+ bits/pixel
+	 * bit 4=1: Enable linear addressing
+	 * bit 5=1: Enable MMIO
+	 */
+	wb_64 (regs, ECR_ADV_FUNC_CNTL, 0x31);
+	/*
+	 * bit 0=1: Color emulation
+	 * bit 1=1: Enable CPU access to display memory
+	 * bit 5=1: Select high 64K memory page
+	 */
+/* GRF - 0xE3 */
+	wb_64 (regs, GREG_MISC_OUTPUT_W, 0x23);
+	
+	/* Cpu base addr */
+	WCrt (regs, CRT_ID_EXT_SYS_CNTL_4, 0x0);
+	
+	/* Reset. This does nothing on Trio, but standard VGA practice */
+	/* WSeq (CyberRegs, SEQ_ID_RESET, 0x03); */
+	/* Character clocks 8 dots wide */
+	WSeq (regs, SEQ_ID_CLOCKING_MODE, 0x01);
+	/* Enable cpu write to all color planes */
+	WSeq (regs, SEQ_ID_MAP_MASK, 0x0F);
+	/* Font table in 1st 8k of plane 2, font A=B disables swtich */
+	WSeq (regs, SEQ_ID_CHAR_MAP_SELECT, 0x0);
+	/* Allow mem access to 256kb */
+	WSeq (regs, SEQ_ID_MEMORY_MODE, 0x2);
+	/* Unlock S3 extensions to VGA Sequencer regs */
+	WSeq (regs, SEQ_ID_UNLOCK_EXT, 0x6);
+	
+	/* Enable 4MB fast page mode */
+	test = RSeq (regs, SEQ_ID_BUS_REQ_CNTL);
+	test = test | 1 << 6;
+	WSeq (regs, SEQ_ID_BUS_REQ_CNTL, test);
+	
+	/* Faster LUT write: 1 DCLK LUT write cycle, RAMDAC clk doubled */
+	WSeq (regs, SEQ_ID_RAMDAC_CNTL, 0xC0);
+
+	/* Clear immediate clock load bit */
+	test = RSeq (regs, SEQ_ID_CLKSYN_CNTL_2);
+	test = test & 0xDF;
+	/* If > 55MHz, enable 2 cycle memory write */
+	if (cv64_memclk >= 55000000) {
+		test |= 0x80;
+	}
+	WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, test);
+
+	/* Set MCLK value */
+	clockpar = cv64_compute_clock (cv64_memclk);
+	test = (clockpar & 0xFF00) >> 8;
+	WSeq (regs, SEQ_ID_MCLK_HI, test);
+	test = clockpar & 0xFF;
+	WSeq (regs, SEQ_ID_MCLK_LO, test);
+
+	/* Chip rev specific: Not in my Trio manual!!! */
+	if (RCrt (regs, CRT_ID_REVISION) == 0x10)
+		WSeq (regs, SEQ_ID_MORE_MAGIC, test);
+
+	/* We now load an 25 MHz, 31kHz, 640x480 standard VGA Mode. */
+
+	/* Set DCLK value */
+	WSeq (regs, SEQ_ID_DCLK_HI, 0x13);
+	WSeq (regs, SEQ_ID_DCLK_LO, 0x41);
+
+	/* Load DCLK (and MCLK?) immediately */
+	test = RSeq (regs, SEQ_ID_CLKSYN_CNTL_2);
+	test = test | 0x22;
+	WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, test);
+
+	/* Enable loading of DCLK */
+	test = rb_64(regs, GREG_MISC_OUTPUT_R);
+	test = test | 0x0C;
+	wb_64 (regs, GREG_MISC_OUTPUT_W, test);
+
+	/* Turn off immediate xCLK load */
+	WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, 0x2);
+
+	/* Horizontal character clock counts */
+	/* 8 LSB of 9 bits = total line - 5 */
+	WCrt (regs, CRT_ID_HOR_TOTAL, 0x5F);
+	/* Active display line */
+	WCrt (regs, CRT_ID_HOR_DISP_ENA_END, 0x4F);
+	/* Blank assertion start */
+	WCrt (regs, CRT_ID_START_HOR_BLANK, 0x50);
+	/* Blank assertion end */
+	WCrt (regs, CRT_ID_END_HOR_BLANK, 0x82);
+	/* HSYNC assertion start */
+	WCrt (regs, CRT_ID_START_HOR_RETR, 0x54);
+	/* HSYNC assertion end */
+	WCrt (regs, CRT_ID_END_HOR_RETR, 0x80);
+	WCrt (regs, CRT_ID_VER_TOTAL, 0xBF);
+	WCrt (regs, CRT_ID_OVERFLOW, 0x1F);
+	WCrt (regs, CRT_ID_PRESET_ROW_SCAN, 0x0);
+	WCrt (regs, CRT_ID_MAX_SCAN_LINE, 0x40);
+	WCrt (regs, CRT_ID_CURSOR_START, 0x00);
+	WCrt (regs, CRT_ID_CURSOR_END, 0x00);
+	WCrt (regs, CRT_ID_START_ADDR_HIGH, 0x00);
+	WCrt (regs, CRT_ID_START_ADDR_LOW, 0x00);
+	WCrt (regs, CRT_ID_CURSOR_LOC_HIGH, 0x00);
+	WCrt (regs, CRT_ID_CURSOR_LOC_LOW, 0x00);
+	WCrt (regs, CRT_ID_START_VER_RETR, 0x9C);
+	WCrt (regs, CRT_ID_END_VER_RETR, 0x0E);
+	WCrt (regs, CRT_ID_VER_DISP_ENA_END, 0x8F);
+	WCrt (regs, CRT_ID_SCREEN_OFFSET, 0x50);
+	WCrt (regs, CRT_ID_UNDERLINE_LOC, 0x00);
+	WCrt (regs, CRT_ID_START_VER_BLANK, 0x96);
+	WCrt (regs, CRT_ID_END_VER_BLANK, 0xB9);
+	WCrt (regs, CRT_ID_MODE_CONTROL, 0xE3);
+	WCrt (regs, CRT_ID_LINE_COMPARE, 0xFF);
+	WCrt (regs, CRT_ID_BACKWAD_COMP_3, 0x10);	/* FIFO enabled */
+	WCrt (regs, CRT_ID_MISC_1, 0x35);
+	WCrt (regs, CRT_ID_DISPLAY_FIFO, 0x5A);
+	WCrt (regs, CRT_ID_EXT_MEM_CNTL_2, 0x70);
+	WCrt (regs, CRT_ID_LAW_POS_LO, 0x40);
+	WCrt (regs, CRT_ID_EXT_MEM_CNTL_3, 0xFF);
+
+	WGfx (regs, GCT_ID_SET_RESET, 0x0);
+	WGfx (regs, GCT_ID_ENABLE_SET_RESET, 0x0);
+	WGfx (regs, GCT_ID_COLOR_COMPARE, 0x0);
+	WGfx (regs, GCT_ID_DATA_ROTATE, 0x0);
+	WGfx (regs, GCT_ID_READ_MAP_SELECT, 0x0);
+	WGfx (regs, GCT_ID_GRAPHICS_MODE, 0x40);
+	WGfx (regs, GCT_ID_MISC, 0x01);
+	WGfx (regs, GCT_ID_COLOR_XCARE, 0x0F);
+	WGfx (regs, GCT_ID_BITMASK, 0xFF);
+
+	/* Colors for text mode */
+	for (i = 0; i < 0xf; i++)
+		WAttr (regs, i, i);
+
+	WAttr (regs, ACT_ID_ATTR_MODE_CNTL, 0x41);
+	WAttr (regs, ACT_ID_OVERSCAN_COLOR, 0x01);
+	WAttr (regs, ACT_ID_COLOR_PLANE_ENA, 0x0F);
+	WAttr (regs, ACT_ID_HOR_PEL_PANNING, 0x0);
+	WAttr (regs, ACT_ID_COLOR_SELECT, 0x0);
+
+	wb_64 (regs, VDAC_MASK, 0xFF);
+
+	*((unsigned long *) (regs + ECR_FRGD_COLOR)) = 0xFF;
+	*((unsigned long *) (regs + ECR_BKGD_COLOR)) = 0;
+
+	/* Colors initially set to grayscale */
+
+	wb_64 (regs, VDAC_ADDRESS_W, 0);
+	for (i = 255; i >= 0; i--) {
+		wb_64(regs, VDAC_DATA, i);
+		wb_64(regs, VDAC_DATA, i);
+		wb_64(regs, VDAC_DATA, i);
+	}
+
+	/* GFx hardware cursor off */
+	WCrt (regs, CRT_ID_HWGC_MODE, 0x00);
+
+	/* Set first to 4MB, so test will work */
+	WCrt (regs, CRT_ID_LAW_CNTL, 0x13);
+	/* Find "correct" size of fbmem of Z3 board */
+	if (cv_has_4mb (CyberMem)) {
+		CyberSize = 1024 * 1024 * 4;
+		WCrt (regs, CRT_ID_LAW_CNTL, 0x13);
+		DPRINTK("4MB board\n");
+	} else {
+		CyberSize = 1024 * 1024 * 2;
+		WCrt (regs, CRT_ID_LAW_CNTL, 0x12);
+		DPRINTK("2MB board\n");
+	}
+
+	/* Initialize graphics engine */
+	Cyber_WaitBlit();
+	vgaw16 (regs, ECR_FRGD_MIX, 0x27);
+	vgaw16 (regs, ECR_BKGD_MIX, 0x07);
+	vgaw16 (regs, ECR_READ_REG_DATA, 0x1000);
+	udelay(200);
+	vgaw16 (regs, ECR_READ_REG_DATA, 0x2000);
+	Cyber_WaitBlit();
+	vgaw16 (regs, ECR_READ_REG_DATA, 0x3FFF);
+	Cyber_WaitBlit();
+	udelay(200);
+	vgaw16 (regs, ECR_READ_REG_DATA, 0x4FFF);
+	Cyber_WaitBlit();
+	vgaw16 (regs, ECR_BITPLANE_WRITE_MASK, ~0);
+	Cyber_WaitBlit();
+	vgaw16 (regs, ECR_READ_REG_DATA, 0xE000);
+	vgaw16 (regs, ECR_CURRENT_Y_POS2, 0x00);
+	vgaw16 (regs, ECR_CURRENT_X_POS2, 0x00);
+	vgaw16 (regs, ECR_READ_REG_DATA, 0xA000);
+	vgaw16 (regs, ECR_DEST_Y__AX_STEP, 0x00);
+	vgaw16 (regs, ECR_DEST_Y2__AX_STEP2, 0x00);
+	vgaw16 (regs, ECR_DEST_X__DIA_STEP, 0x00);
+	vgaw16 (regs, ECR_DEST_X2__DIA_STEP2, 0x00);
+	vgaw16 (regs, ECR_SHORT_STROKE, 0x00);
+	vgaw16 (regs, ECR_DRAW_CMD, 0x01);
+
+	Cyber_WaitBlit();
+
+	vgaw16 (regs, ECR_READ_REG_DATA, 0x4FFF);
+	vgaw16 (regs, ECR_BKGD_COLOR, 0x01);
+	vgaw16 (regs, ECR_FRGD_COLOR, 0x00);
+
+
+	/* Enable video display (set bit 5) */
+/* ARB - Would also seem to write to AR13.
+ *       May want to use parts of WAttr to set JUST bit 5
+ */
+	WAttr (regs, 0x33, 0);
+	
+/* GRF - function code ended here */
+
+	/* Turn gfx on again */
+	gfx_on_off (0, regs);
+
+	/* Pass-through */
+	cvscreen (0, CyberBase);
+
+	DPRINTK("EXIT\n");
+}
+
+static void cv64_load_video_mode (struct fb_var_screeninfo *video_mode)
+{
+  volatile unsigned char *regs = CyberRegs;
+  int fx, fy;
+  unsigned short mnr;
+  unsigned short HT, HDE, HBS, HBE, HSS, HSE, VDE, VBS, VBE, VSS, VSE, VT;
+  char LACE, DBLSCAN, TEXT, CONSOLE;
+  int cr50, sr15, sr18, clock_mode, test;
+  int m, n;
+  int tfillm, temptym;
+  int hmul;
+	
+  /* ---------------- */
+  int xres, hfront, hsync, hback;
+  int yres, vfront, vsync, vback;
+  int bpp;
+#if 0
+  float freq_f;
+#endif
+  long freq;
+  /* ---------------- */
+	
+  DPRINTK("ENTER\n");
+  TEXT = 0;	/* if depth == 4 */
+  CONSOLE = 0;	/* mode num == 255 (console) */
+  fx = fy = 8;	/* force 8x8 font */
+
+/* GRF - Disable interrupts */	
+	
+  gfx_on_off (1, regs);
+	
+  switch (video_mode->bits_per_pixel) {
+  case 15:
+  case 16:
+    hmul = 2;
+    break;
+		
+  default:
+    hmul = 1;
+    break;
+  }
+	
+  bpp = video_mode->bits_per_pixel;
+  xres = video_mode->xres;
+  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;
+  }
+
+  /* ARB Dropping custom setup method from cvision.c */
+#if 0
+  if (cvision_custom_mode) {
+    HBS = hbs / 8 * hmul;
+    HBE = hbe / 8 * hmul;
+    HSS = hss / 8 * hmul;
+    HSE = hse / 8 * hmul;
+    HT  = ht / 8 * hmul - 5;
+		
+    VBS = vbs - 1;
+    VSS = vss;
+    VSE = vse;
+    VBE = vbe;
+    VT  = vt - 2;
+  } else {
+#else
+    {
+#endif
+    HBS = hmul * (xres / 8);
+    HBE = hmul * ((xres/8) + (hfront/8) + (hsync/8) + (hback/8) - 2);
+    HSS = hmul * ((xres/8) + (hfront/8) + 2);
+    HSE = hmul * ((xres/8) + (hfront/8) + (hsync/8) + 1);
+    HT  = hmul * ((xres/8) + (hfront/8) + (hsync/8) + (hback/8));
+	
+    VBS = yres;
+    VBE = yres + vfront + vsync + vback - 2;
+    VSS = yres + vfront - 1;
+    VSE = yres + vfront + vsync - 1;
+    VT  = yres + vfront + vsync + vback - 2;
+  }
+
+  wb_64 (regs, ECR_ADV_FUNC_CNTL, (TEXT ? 0x00 : 0x31));
+	
+  if (TEXT)
+    HDE = ((video_mode->xres + fx - 1) / fx) - 1;
+  else
+    HDE = (video_mode->xres + 3) * hmul / 8 - 1;
+	
+  VDE = video_mode->yres - 1;
+
+  WCrt (regs, CRT_ID_HWGC_MODE, 0x00);
+  WCrt (regs, CRT_ID_EXT_DAC_CNTL, 0x00);
+	
+  WSeq (regs, SEQ_ID_MEMORY_MODE,
+	(TEXT || (video_mode->bits_per_pixel == 1)) ? 0x06 : 0x0e);
+  WGfx (regs, GCT_ID_READ_MAP_SELECT, 0x00);
+  WSeq (regs, SEQ_ID_MAP_MASK,
+	(video_mode->bits_per_pixel == 1) ? 0x01 : 0xFF);
+  WSeq (regs, SEQ_ID_CHAR_MAP_SELECT, 0x00);
+	
+  /* cv64_compute_clock accepts arguments in Hz */
+  /* pixclock is in ps ... convert to Hz */
+	
+#if 0
+  freq_f = (1.0 / (float) video_mode->pixclock) * 1000000000;
+  freq = ((long) freq_f) * 1000;
+#else
+/* freq = (long) ((long long)1000000000000 / (long long) video_mode->pixclock);
+ */
+  freq = (1000000000 / video_mode->pixclock) * 1000;
+#endif
+
+  mnr = cv64_compute_clock (freq);
+  WSeq (regs, SEQ_ID_DCLK_HI, ((mnr & 0xFF00) >> 8));
+  WSeq (regs, SEQ_ID_DCLK_LO, (mnr & 0xFF));
+	
+  /* Load display parameters into board */
+  WCrt (regs, CRT_ID_EXT_HOR_OVF,
+	((HT & 0x100) ? 0x01 : 0x00) |
+	((HDE & 0x100) ? 0x02 : 0x00) |
+	((HBS & 0x100) ? 0x04 : 0x00) |
+	/* ((HBE & 0x40) ? 0x08 : 0x00) | */
+	((HSS & 0x100) ? 0x10 : 0x00) |
+	/* ((HSE & 0x20) ? 0x20 : 0x00) | */
+	(((HT-5) & 0x100) ? 0x40 : 0x00)
+	);
+	
+  WCrt (regs, CRT_ID_EXT_VER_OVF,
+	0x40 |
+	((VT & 0x400) ? 0x01 : 0x00) |
+	((VDE & 0x400) ? 0x02 : 0x00) |
+	((VBS & 0x400) ? 0x04 : 0x00) |
+	((VSS & 0x400) ? 0x10 : 0x00)
+	);
+	
+  WCrt (regs, CRT_ID_HOR_TOTAL, HT);
+  WCrt (regs, CRT_ID_DISPLAY_FIFO, HT - 5);
+  WCrt (regs, CRT_ID_HOR_DISP_ENA_END, ((HDE >= HBS) ? (HBS - 1) : HDE));
+  WCrt (regs, CRT_ID_START_HOR_BLANK, HBS);
+  WCrt (regs, CRT_ID_END_HOR_BLANK, ((HBE & 0x1F) | 0x80));
+  WCrt (regs, CRT_ID_START_HOR_RETR, HSS);
+  WCrt (regs, CRT_ID_END_HOR_RETR,
+	(HSE & 0x1F) |
+	((HBE & 0x20) ? 0x80 : 0x00)
+	);
+  WCrt (regs, CRT_ID_VER_TOTAL, VT);
+  WCrt (regs, CRT_ID_OVERFLOW,
+	0x10 |
+	((VT & 0x100) ? 0x01 : 0x00) |
+	((VDE & 0x100) ? 0x02 : 0x00) |
+	((VSS & 0x100) ? 0x04 : 0x00) |
+	((VBS & 0x100) ? 0x08 : 0x00) |
+	((VT & 0x200) ? 0x20 : 0x00) |
+	((VDE & 0x200) ? 0x40 : 0x00) |
+	((VSS & 0x200) ? 0x80 : 0x00)
+	);
+  WCrt (regs, CRT_ID_MAX_SCAN_LINE,
+	0x40 |
+	(DBLSCAN ? 0x80 : 0x00) |
+	((VBS & 0x200) ? 0x20 : 0x00) |
+	(TEXT ? ((fy - 1) & 0x1F) : 0x00)
+	);
+	
+  WCrt (regs, CRT_ID_MODE_CONTROL, 0xE3);
+
+  /* Text cursor */
+	
+  if (TEXT) {
+#if 1
+    WCrt (regs, CRT_ID_CURSOR_START, (fy & 0x1f) - 2);
+    WCrt (regs, CRT_ID_CURSOR_END, (fy & 0x1F) - 1);
+#else
+    WCrt (regs, CRT_ID_CURSOR_START, 0x00);
+    WCrt (regs, CRT_ID_CURSOR_END, fy & 0x1F);
+#endif
+    WCrt (regs, CRT_ID_UNDERLINE_LOC, (fy - 1) & 0x1F);
+    WCrt (regs, CRT_ID_CURSOR_LOC_HIGH, 0x00);
+    WCrt (regs, CRT_ID_CURSOR_LOC_LOW, 0x00);
+  }
+	
+  WCrt (regs, CRT_ID_START_ADDR_HIGH, 0x00);
+  WCrt (regs, CRT_ID_START_ADDR_LOW, 0x00);
+  WCrt (regs, CRT_ID_START_VER_RETR, VSS);
+  WCrt (regs, CRT_ID_END_VER_RETR, (VSE & 0x0F));
+  WCrt (regs, CRT_ID_VER_DISP_ENA_END, VDE);
+  WCrt (regs, CRT_ID_START_VER_BLANK, VBS);
+  WCrt (regs, CRT_ID_END_VER_BLANK, VBE);
+  WCrt (regs, CRT_ID_LINE_COMPARE, 0xFF);
+  WCrt (regs, CRT_ID_LACE_RETR_START, HT / 2);
+  WCrt (regs, CRT_ID_LACE_CONTROL, (LACE ? 0x20 : 0x00));
+  WGfx (regs, GCT_ID_GRAPHICS_MODE,
+	((TEXT || (video_mode->bits_per_pixel == 1)) ? 0x00 : 0x40));
+  WGfx (regs, GCT_ID_MISC, (TEXT ? 0x04 : 0x01));
+  WSeq (regs, SEQ_ID_MEMORY_MODE,
+	((TEXT || (video_mode->bits_per_pixel == 1)) ? 0x06 : 0x02));
+	
+  wb_64 (regs, VDAC_MASK, 0xFF);
+	
+  /* Blank border */
+  test = RCrt (regs, CRT_ID_BACKWAD_COMP_2);
+  WCrt (regs, CRT_ID_BACKWAD_COMP_2, (test | 0x20));
+	
+  sr15 = RSeq (regs, SEQ_ID_CLKSYN_CNTL_2);
+  sr15 &= 0xEF;
+  sr18 = RSeq (regs, SEQ_ID_RAMDAC_CNTL);
+  sr18 &= 0x7F;
+  clock_mode = 0x00;
+  cr50 = 0x00;
+	
+  test = RCrt (regs, CRT_ID_EXT_MISC_CNTL_2);
+  test &= 0xD;
+	
+  /* Clear roxxler byte-swapping... */
+  cv64_write_port (0x0040, CyberBase);
+  cv64_write_port (0x0020, CyberBase);
+	
+  switch (video_mode->bits_per_pixel) {
+  case 1:
+  case 4:	/* text */
+    HDE = video_mode->xres / 16;
+    break;
+		
+  case 8:
+    if (freq > 80000000) {
+      clock_mode = 0x10 | 0x02;
+      sr15 |= 0x10;
+      sr18 |= 0x80;
+    }
+    HDE = video_mode->xres / 8;
+    cr50 |= 0x00;
+    break;
+		
+  case 15:
+    cv64_write_port (0x8020, CyberBase);
+    clock_mode = 0x30;
+    HDE = video_mode->xres / 4;
+    cr50 |= 0x10;
+    break;
+		
+  case 16:
+    cv64_write_port (0x8020, CyberBase);
+    clock_mode = 0x50;
+    HDE = video_mode->xres / 4;
+    cr50 |= 0x10;
+    break;
+		
+  case 24:
+  case 32:
+    cv64_write_port (0x8040, CyberBase);
+    clock_mode = 0xD0;
+    HDE = video_mode->xres / 2;
+    cr50 |= 0x30;
+    break;
+  }
+
+  WCrt (regs, CRT_ID_EXT_MISC_CNTL_2, clock_mode | test);
+  WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, sr15);
+  WSeq (regs, SEQ_ID_RAMDAC_CNTL, sr18);
+  WCrt (regs, CRT_ID_SCREEN_OFFSET, HDE);
+
+  WCrt (regs, CRT_ID_MISC_1, (TEXT ? 0x05 : 0x35));
+	
+  test = RCrt (regs, CRT_ID_EXT_SYS_CNTL_2);
+  test &= ~0x30;
+  test |= (HDE >> 4) & 0x30;
+  WCrt (regs, CRT_ID_EXT_SYS_CNTL_2, test);
+	
+  /* Set up graphics engine */
+  switch (video_mode->xres) {
+  case 1024:
+    cr50 |= 0x00;
+    break;
+		
+  case 640:
+    cr50 |= 0x40;
+    break;
+		
+  case 800:
+    cr50 |= 0x80;
+    break;
+		
+  case 1280:
+    cr50 |= 0xC0;
+    break;
+		
+  case 1152:
+    cr50 |= 0x01;
+    break;
+		
+  case 1600:
+    cr50 |= 0x81;
+    break;
+		
+  default:	/* XXX */
+    break;
+  }
+	
+  WCrt (regs, CRT_ID_EXT_SYS_CNTL_1, cr50);
+	
+  udelay(100);
+  WAttr (regs, ACT_ID_ATTR_MODE_CNTL, (TEXT ? 0x08 : 0x41));
+  udelay(100);
+  WAttr (regs, ACT_ID_COLOR_PLANE_ENA,
+	 (video_mode->bits_per_pixel == 1) ? 0x01 : 0x0F);
+  udelay(100);
+	
+  tfillm = (96 * (cv64_memclk / 1000)) / 240000;
+	
+  switch (video_mode->bits_per_pixel) {
+  case 32:
+  case 24:
+    temptym = (24 * (cv64_memclk / 1000)) / (freq / 1000);
+    break;
+  case 15:
+  case 16:
+    temptym = (48 * (cv64_memclk / 1000)) / (freq / 1000);
+    break;
+  case 4:
+    temptym = (192 * (cv64_memclk / 1000)) / (freq / 1000);
+    break;
+  default:
+    temptym = (96 * (cv64_memclk / 1000)) / (freq / 1000);
+    break;
+  }
+	
+  m = (temptym - tfillm - 9) / 2;
+  if (m < 0)
+    m = 0;
+  m = (m & 0x1F) << 3;
+  if (m < 0x18)
+    m = 0x18;
+  n = 0xFF;
+	
+  WCrt (regs, CRT_ID_EXT_MEM_CNTL_2, m);
+  WCrt (regs, CRT_ID_EXT_MEM_CNTL_3, n);
+  udelay(10);
+	
+  /* Text initialization */
+	
+  if (TEXT) {
+    /* Do text initialization here ! */
+  }
+	
+  if (CONSOLE) {
+    int i;
+    wb_64 (regs, VDAC_ADDRESS_W, 0);
+    for (i = 0; i < 4; i++) {
+      wb_64 (regs, VDAC_DATA, cvconscolors [i][0]);
+      wb_64 (regs, VDAC_DATA, cvconscolors [i][1]);
+      wb_64 (regs, VDAC_DATA, cvconscolors [i][2]);
+    }
+  }
+	
+  WAttr (regs, 0x33, 0);
+	
+  /* Turn gfx on again */
+  gfx_on_off (0, (volatile unsigned char *) regs);
+	
+  /* Pass-through */
+  cvscreen (0, CyberBase);
+
+DPRINTK("EXIT\n");
+}
+
+void cvision_bitblt (u_short sx, u_short sy, u_short dx, u_short dy,
+		     u_short w, u_short h)
+{
+	volatile unsigned char *regs = CyberRegs;
+	unsigned short drawdir = 0;
+	
+	DPRINTK("ENTER\n");
+	if (sx > dx) {
+		drawdir |= 1 << 5;
+	} else {
+		sx += w - 1;
+		dx += w - 1;
+	}
+	
+	if (sy > dy) {
+		drawdir |= 1 << 7;
+	} else {
+		sy += h - 1;
+		dy += h - 1;
+	}
+	
+	Cyber_WaitBlit();
+	vgaw16 (regs, ECR_READ_REG_DATA, 0xA000);
+	vgaw16 (regs, ECR_BKGD_MIX, 0x7);
+	vgaw16 (regs, ECR_FRGD_MIX, 0x67);
+	vgaw16 (regs, ECR_BKGD_COLOR, 0x0);
+	vgaw16 (regs, ECR_FRGD_COLOR, 0x1);
+	vgaw16 (regs, ECR_BITPLANE_READ_MASK, 0x1);
+	vgaw16 (regs, ECR_BITPLANE_WRITE_MASK, 0xFFF);
+	vgaw16 (regs, ECR_CURRENT_Y_POS, sy);
+	vgaw16 (regs, ECR_CURRENT_X_POS, sx);
+	vgaw16 (regs, ECR_DEST_Y__AX_STEP, dy);
+	vgaw16 (regs, ECR_DEST_X__DIA_STEP, dx);
+	vgaw16 (regs, ECR_READ_REG_DATA, h - 1);
+	vgaw16 (regs, ECR_MAJ_AXIS_PIX_CNT, w - 1);
+	vgaw16 (regs, ECR_DRAW_CMD, 0xC051 | drawdir);
+	DPRINTK("EXIT\n");
+}
+
+void cvision_clear (u_short dx, u_short dy, u_short w, u_short h, u_short bg)
+{
+	volatile unsigned char *regs = CyberRegs;
+	DPRINTK("ENTER\n");
+	Cyber_WaitBlit();
+	vgaw16 (regs, ECR_FRGD_MIX, 0x0027);
+	vgaw16 (regs, ECR_FRGD_COLOR, bg);
+	vgaw16 (regs, ECR_READ_REG_DATA, 0xA000);
+	vgaw16 (regs, ECR_CURRENT_Y_POS, dy);
+	vgaw16 (regs, ECR_CURRENT_X_POS, dx);
+	vgaw16 (regs, ECR_READ_REG_DATA, h - 1);
+	vgaw16 (regs, ECR_MAJ_AXIS_PIX_CNT, w - 1);
+	vgaw16 (regs, ECR_DRAW_CMD, 0x40B1);	
+	DPRINTK("EXIT\n");
+}
+
+#ifdef CYBERFBDEBUG
+/*
+ * Dump internal settings of CyberVision board
+ */
+static void cv64_dump (void)
+{
+	volatile unsigned char *regs = CyberRegs;
+	DPRINTK("ENTER\n");
+        /* Dump the VGA setup values */
+	*(regs + S3_CRTC_ADR) = 0x00;
+	DPRINTK("CR00 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x01;
+	DPRINTK("CR01 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x02;
+	DPRINTK("CR02 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x03;
+	DPRINTK("CR03 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x04;
+	DPRINTK("CR04 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x05;
+	DPRINTK("CR05 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x06;
+	DPRINTK("CR06 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x07;
+	DPRINTK("CR07 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x08;
+	DPRINTK("CR08 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x09;
+	DPRINTK("CR09 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x10;
+	DPRINTK("CR10 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x11;
+	DPRINTK("CR11 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x12;
+	DPRINTK("CR12 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x13;
+	DPRINTK("CR13 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x15;
+	DPRINTK("CR15 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x16;
+	DPRINTK("CR16 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x36;
+	DPRINTK("CR36 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x37;
+	DPRINTK("CR37 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x42;
+	DPRINTK("CR42 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x43;
+	DPRINTK("CR43 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x50;
+	DPRINTK("CR50 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x51;
+	DPRINTK("CR51 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x53;
+	DPRINTK("CR53 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x58;
+	DPRINTK("CR58 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x59;
+	DPRINTK("CR59 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x5A;
+	DPRINTK("CR5A = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x5D;
+	DPRINTK("CR5D = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x5E;
+	DPRINTK("CR5E = %x\n", *(regs + S3_CRTC_DATA));
+	DPRINTK("MISC = %x\n", *(regs + GREG_MISC_OUTPUT_R));
+	*(regs + SEQ_ADDRESS) = 0x01;
+	DPRINTK("SR01 = %x\n", *(regs + SEQ_ADDRESS_R));
+	*(regs + SEQ_ADDRESS) = 0x02;
+	DPRINTK("SR02 = %x\n", *(regs + SEQ_ADDRESS_R));
+	*(regs + SEQ_ADDRESS) = 0x03;
+	DPRINTK("SR03 = %x\n", *(regs + SEQ_ADDRESS_R));
+	*(regs + SEQ_ADDRESS) = 0x09;
+	DPRINTK("SR09 = %x\n", *(regs + SEQ_ADDRESS_R));
+	*(regs + SEQ_ADDRESS) = 0x10;
+	DPRINTK("SR10 = %x\n", *(regs + SEQ_ADDRESS_R));
+	*(regs + SEQ_ADDRESS) = 0x11;
+	DPRINTK("SR11 = %x\n", *(regs + SEQ_ADDRESS_R));
+	*(regs + SEQ_ADDRESS) = 0x12;
+	DPRINTK("SR12 = %x\n", *(regs + SEQ_ADDRESS_R));
+	*(regs + SEQ_ADDRESS) = 0x13;
+	DPRINTK("SR13 = %x\n", *(regs + SEQ_ADDRESS_R));
+	*(regs + SEQ_ADDRESS) = 0x15;
+	DPRINTK("SR15 = %x\n", *(regs + SEQ_ADDRESS_R));
+	
+	return;
+}
+#endif
diff --git a/drivers/video/cyberfb.h b/drivers/video/cyberfb.h
new file mode 100644
index 0000000..8435c43
--- /dev/null
+++ b/drivers/video/cyberfb.h
@@ -0,0 +1,415 @@
+/*
+ * linux/arch/m68k/console/cvision.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.
+ */
+
+/* s3 commands */
+#define S3_BITBLT       0xc011
+#define S3_TWOPOINTLINE 0x2811
+#define S3_FILLEDRECT   0x40b1
+
+#define S3_FIFO_EMPTY 0x0400
+#define S3_HDW_BUSY   0x0200
+
+/* Enhanced register mapping (MMIO mode) */
+
+#define S3_READ_SEL      0xbee8 /* offset f */
+#define S3_MULT_MISC     0xbee8 /* offset e */
+#define S3_ERR_TERM      0x92e8
+#define S3_FRGD_COLOR    0xa6e8
+#define S3_BKGD_COLOR    0xa2e8
+#define S3_PIXEL_CNTL    0xbee8 /* offset a */
+#define S3_FRGD_MIX      0xbae8
+#define S3_BKGD_MIX      0xb6e8
+#define S3_CUR_Y         0x82e8
+#define S3_CUR_X         0x86e8
+#define S3_DESTY_AXSTP   0x8ae8
+#define S3_DESTX_DIASTP  0x8ee8
+#define S3_MIN_AXIS_PCNT 0xbee8 /* offset 0 */
+#define S3_MAJ_AXIS_PCNT 0x96e8
+#define S3_CMD           0x9ae8
+#define S3_GP_STAT       0x9ae8
+#define S3_ADVFUNC_CNTL  0x4ae8
+#define S3_WRT_MASK      0xaae8
+#define S3_RD_MASK       0xaee8
+
+/* Enhanced register mapping (Packed MMIO mode, write only) */
+#define S3_ALT_CURXY     0x8100
+#define S3_ALT_CURXY2    0x8104
+#define S3_ALT_STEP      0x8108
+#define S3_ALT_STEP2     0x810c
+#define S3_ALT_ERR       0x8110
+#define S3_ALT_CMD       0x8118
+#define S3_ALT_MIX       0x8134
+#define S3_ALT_PCNT      0x8148
+#define S3_ALT_PAT       0x8168
+
+/* Drawing modes */
+#define S3_NOTCUR          0x0000
+#define S3_LOGICALZERO     0x0001
+#define S3_LOGICALONE      0x0002
+#define S3_LEAVEASIS       0x0003
+#define S3_NOTNEW          0x0004
+#define S3_CURXORNEW       0x0005
+#define S3_NOT_CURXORNEW   0x0006
+#define S3_NEW             0x0007
+#define S3_NOTCURORNOTNEW  0x0008
+#define S3_CURORNOTNEW     0x0009
+#define S3_NOTCURORNEW     0x000a
+#define S3_CURORNEW        0x000b
+#define S3_CURANDNEW       0x000c
+#define S3_NOTCURANDNEW    0x000d
+#define S3_CURANDNOTNEW    0x000e
+#define S3_NOTCURANDNOTNEW 0x000f
+
+#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
+
+/**************************************************/
+
+/* support for a BitBlt operation. The op-codes are identical
+   to X11 GCs */
+#define	GRFBBOPclear		0x0	/* 0 */
+#define GRFBBOPand		0x1	/* src AND dst */
+#define GRFBBOPandReverse	0x2	/* src AND NOT dst */
+#define GRFBBOPcopy		0x3	/* src */
+#define GRFBBOPandInverted	0x4	/* NOT src AND dst */
+#define	GRFBBOPnoop		0x5	/* dst */
+#define GRFBBOPxor		0x6	/* src XOR dst */
+#define GRFBBOPor		0x7	/* src OR dst */
+#define GRFBBOPnor		0x8	/* NOT src AND NOT dst */
+#define GRFBBOPequiv		0x9	/* NOT src XOR dst */
+#define GRFBBOPinvert		0xa	/* NOT dst */
+#define GRFBBOPorReverse	0xb	/* src OR NOT dst */
+#define GRFBBOPcopyInverted	0xc	/* NOT src */
+#define GRFBBOPorInverted	0xd	/* NOT src OR dst */
+#define GRFBBOPnand		0xe	/* NOT src OR NOT dst */
+#define GRFBBOPset		0xf	/* 1 */
+
+
+/* Write 16 Bit VGA register */
+#define vgaw16(ba, reg, val) \
+*((unsigned short *)  (((volatile unsigned char *)ba)+reg)) = val
+
+/*
+ * 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_OPTION_SELECT	0x0102
+#define SREG_VIDEO_SUBS_ENABLE	0x46E8
+
+/* 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
+
+/* 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
+#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
+
+/* 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
+#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
+#define CRT_ID_EX_SYNC_3	0x63
+#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
+
+/* Enhanced Commands Registers: */
+#define ECR_SUBSYSTEM_STAT	0x42E8
+#define ECR_SUBSYSTEM_CNTL	0x42E8
+#define ECR_ADV_FUNC_CNTL	0x4AE8
+#define ECR_CURRENT_Y_POS	0x82E8
+#define ECR_CURRENT_Y_POS2	0x82EA	/* Trio64 only */
+#define ECR_CURRENT_X_POS	0x86E8
+#define ECR_CURRENT_X_POS2	0x86EA	/* Trio64 only */
+#define ECR_DEST_Y__AX_STEP	0x8AE8
+#define ECR_DEST_Y2__AX_STEP2	0x8AEA	/* Trio64 only */
+#define ECR_DEST_X__DIA_STEP	0x8EE8
+#define ECR_DEST_X2__DIA_STEP2	0x8EEA	/* Trio64 only */
+#define ECR_ERR_TERM		0x92E8
+#define ECR_ERR_TERM2		0x92EA	/* Trio64 only */
+#define ECR_MAJ_AXIS_PIX_CNT	0x96E8
+#define ECR_MAJ_AXIS_PIX_CNT2	0x96EA	/* Trio64 only */
+#define ECR_GP_STAT		0x9AE8	/* GP = Graphics Processor */
+#define ECR_DRAW_CMD		0x9AE8
+#define ECR_DRAW_CMD2		0x9AEA	/* Trio64 only */
+#define ECR_SHORT_STROKE	0x9EE8
+#define ECR_BKGD_COLOR		0xA2E8	/* BKGD = Background */
+#define ECR_FRGD_COLOR		0xA6E8	/* FRGD = Foreground */
+#define ECR_BITPLANE_WRITE_MASK	0xAAE8
+#define ECR_BITPLANE_READ_MASK	0xAEE8
+#define ECR_COLOR_COMPARE	0xB2E8
+#define ECR_BKGD_MIX		0xB6E8
+#define ECR_FRGD_MIX		0xBAE8
+#define ECR_READ_REG_DATA	0xBEE8
+#define ECR_ID_MIN_AXIS_PIX_CNT	0x00
+#define ECR_ID_SCISSORS_TOP	0x01
+#define ECR_ID_SCISSORS_LEFT	0x02
+#define ECR_ID_SCISSORS_BUTTOM	0x03
+#define ECR_ID_SCISSORS_RIGHT	0x04
+#define ECR_ID_PIX_CNTL		0x0A
+#define ECR_ID_MULT_CNTL_MISC_2	0x0D
+#define ECR_ID_MULT_CNTL_MISC	0x0E
+#define ECR_ID_READ_SEL		0x0F
+#define ECR_PIX_TRANS		0xE2E8
+#define ECR_PIX_TRANS_EXT	0xE2EA
+#define ECR_PATTERN_Y		0xEAE8	/* Trio64 only */
+#define ECR_PATTERN_X		0xEAEA	/* Trio64 only */
+
+
+/* Pass-through */
+#define PASS_ADDRESS		0x40001
+#define PASS_ADDRESS_W		0x40001
+
+/* 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
+
+
+#define WGfx(ba, idx, val) \
+do { wb_64(ba, GCT_ADDRESS, idx); wb_64(ba, GCT_ADDRESS_W , val); } while (0)
+
+#define WSeq(ba, idx, val) \
+do { wb_64(ba, SEQ_ADDRESS, idx); wb_64(ba, SEQ_ADDRESS_W , val); } while (0)
+
+#define WCrt(ba, idx, val) \
+do { wb_64(ba, CRT_ADDRESS, idx); wb_64(ba, CRT_ADDRESS_W , val); } while (0)
+
+#define WAttr(ba, idx, val) \
+do { \
+  unsigned char tmp;\
+  tmp = rb_64(ba, ACT_ADDRESS_RESET);\
+  wb_64(ba, ACT_ADDRESS_W, idx);\
+  wb_64(ba, ACT_ADDRESS_W, val);\
+} while (0)
+
+#define SetTextPlane(ba, m) \
+do { \
+  WGfx(ba, GCT_ID_READ_MAP_SELECT, m & 3 );\
+  WSeq(ba, SEQ_ID_MAP_MASK, (1 << (m & 3)));\
+} while (0)
+
+     /* --------------------------------- */
+     /* prototypes                        */
+     /* --------------------------------- */
+
+inline unsigned char RAttr(volatile unsigned char * board, short idx);
+inline unsigned char RSeq(volatile unsigned char * board, short idx);
+inline unsigned char RCrt(volatile unsigned char * board, short idx);
+inline unsigned char RGfx(volatile unsigned char * board, short idx);
+inline void cv64_write_port(unsigned short bits,
+			    volatile unsigned char *board);
+inline void cvscreen(int toggle, volatile unsigned char *board);
+inline void gfx_on_off(int toggle, volatile unsigned char *board);
+#if 0
+unsigned short cv64_compute_clock(unsigned long freq);
+int cv_has_4mb(volatile unsigned char * fb);
+void cv64_board_init(void);
+void cv64_load_video_mode(struct fb_var_screeninfo *video_mode);
+#endif
+
+void cvision_bitblt(u_short sx, u_short sy, u_short dx, u_short dy, u_short w,
+		    u_short h);
+void cvision_clear(u_short dx, u_short dy, u_short w, u_short h, u_short bg);
diff --git a/drivers/video/dnfb.c b/drivers/video/dnfb.c
new file mode 100644
index 0000000..1dbb82d
--- /dev/null
+++ b/drivers/video/dnfb.c
@@ -0,0 +1,302 @@
+#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/delay.h>
+#include <linux/interrupt.h>
+#include <asm/setup.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <asm/apollohw.h>
+#include <linux/fb.h>
+#include <linux/module.h>
+
+/* apollo video HW definitions */
+
+/*
+ * Control Registers.   IOBASE + $x
+ *
+ * Note: these are the Memory/IO BASE definitions for a mono card set to the
+ * alternate address
+ *
+ * Control 3A and 3B serve identical functions except that 3A
+ * deals with control 1 and 3b deals with Color LUT reg.
+ */
+
+#define AP_IOBASE       0x3b0	/* Base address of 1 plane board. */
+#define AP_STATUS       isaIO2mem(AP_IOBASE+0)	/* Status register.  Read */
+#define AP_WRITE_ENABLE isaIO2mem(AP_IOBASE+0)	/* Write Enable Register Write */
+#define AP_DEVICE_ID    isaIO2mem(AP_IOBASE+1)	/* Device ID Register. Read */
+#define AP_ROP_1        isaIO2mem(AP_IOBASE+2)	/* Raster Operation reg. Write Word */
+#define AP_DIAG_MEM_REQ isaIO2mem(AP_IOBASE+4)	/* Diagnostic Memory Request. Write Word */
+#define AP_CONTROL_0    isaIO2mem(AP_IOBASE+8)	/* Control Register 0.  Read/Write */
+#define AP_CONTROL_1    isaIO2mem(AP_IOBASE+0xa)	/* Control Register 1.  Read/Write */
+#define AP_CONTROL_3A   isaIO2mem(AP_IOBASE+0xe)	/* Control Register 3a. Read/Write */
+#define AP_CONTROL_2    isaIO2mem(AP_IOBASE+0xc)	/* Control Register 2. Read/Write */
+
+
+#define FRAME_BUFFER_START 0x0FA0000
+#define FRAME_BUFFER_LEN 0x40000
+
+/* CREG 0 */
+#define VECTOR_MODE 0x40	/* 010x.xxxx */
+#define DBLT_MODE   0x80	/* 100x.xxxx */
+#define NORMAL_MODE 0xE0	/* 111x.xxxx */
+#define SHIFT_BITS  0x1F	/* xxx1.1111 */
+	/* other bits are Shift value */
+
+/* CREG 1 */
+#define AD_BLT      0x80	/* 1xxx.xxxx */
+#define NORMAL      0x80 /* 1xxx.xxxx */	/* What is happening here ?? */
+#define INVERSE     0x00 /* 0xxx.xxxx */	/* Clearing this reverses the screen */
+#define PIX_BLT     0x00	/* 0xxx.xxxx */
+
+#define AD_HIBIT        0x40	/* xIxx.xxxx */
+
+#define ROP_EN          0x10	/* xxx1.xxxx */
+#define DST_EQ_SRC      0x00	/* xxx0.xxxx */
+#define nRESET_SYNC     0x08	/* xxxx.1xxx */
+#define SYNC_ENAB       0x02	/* xxxx.xx1x */
+
+#define BLANK_DISP      0x00	/* xxxx.xxx0 */
+#define ENAB_DISP       0x01	/* xxxx.xxx1 */
+
+#define NORM_CREG1      (nRESET_SYNC | SYNC_ENAB | ENAB_DISP)	/* no reset sync */
+
+/* CREG 2 */
+
+/*
+ * Following 3 defines are common to 1, 4 and 8 plane.
+ */
+
+#define S_DATA_1s   0x00 /* 00xx.xxxx */	/* set source to all 1's -- vector drawing */
+#define S_DATA_PIX  0x40 /* 01xx.xxxx */	/* takes source from ls-bits and replicates over 16 bits */
+#define S_DATA_PLN  0xC0 /* 11xx.xxxx */	/* normal, each data access =16-bits in
+						   one plane of image mem */
+
+/* CREG 3A/CREG 3B */
+#       define RESET_CREG 0x80	/* 1000.0000 */
+
+/* ROP REG  -  all one nibble */
+/*      ********* NOTE : this is used r0,r1,r2,r3 *********** */
+#define ROP(r2,r3,r0,r1) ( (U_SHORT)((r0)|((r1)<<4)|((r2)<<8)|((r3)<<12)) )
+#define DEST_ZERO               0x0
+#define SRC_AND_DEST    0x1
+#define SRC_AND_nDEST   0x2
+#define SRC                             0x3
+#define nSRC_AND_DEST   0x4
+#define DEST                    0x5
+#define SRC_XOR_DEST    0x6
+#define SRC_OR_DEST             0x7
+#define SRC_NOR_DEST    0x8
+#define SRC_XNOR_DEST   0x9
+#define nDEST                   0xA
+#define SRC_OR_nDEST    0xB
+#define nSRC                    0xC
+#define nSRC_OR_DEST    0xD
+#define SRC_NAND_DEST   0xE
+#define DEST_ONE                0xF
+
+#define SWAP(A) ((A>>8) | ((A&0xff) <<8))
+
+/* frame buffer operations */
+
+static int dnfb_blank(int blank, struct fb_info *info);
+static void dnfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
+
+static struct fb_ops dn_fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_blank	= dnfb_blank,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= dnfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+struct fb_var_screeninfo dnfb_var __devinitdata = {
+	.xres		= 1280,
+	.yres		= 1024,
+	.xres_virtual	= 2048,
+	.yres_virtual	= 1024,
+	.bits_per_pixel	= 1,
+	.height		= -1,
+	.width		= -1,
+	.vmode		= FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_fix_screeninfo dnfb_fix __devinitdata = {
+	.id		= "Apollo Mono",
+	.smem_start	= (FRAME_BUFFER_START + IO_BASE),
+	.smem_len	= FRAME_BUFFER_LEN,
+	.type		= FB_TYPE_PACKED_PIXELS,
+	.visual		= FB_VISUAL_MONO10,
+	.line_length	= 256,
+};
+
+static int dnfb_blank(int blank, struct fb_info *info)
+{
+	if (blank)
+		out_8(AP_CONTROL_3A, 0x0);
+	else
+		out_8(AP_CONTROL_3A, 0x1);
+	return 0;
+}
+
+static
+void dnfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+
+	int incr, y_delta, pre_read = 0, x_end, x_word_count;
+	uint start_mask, end_mask, dest;
+	ushort *src, dummy;
+	short i, j;
+
+	incr = (area->dy <= area->sy) ? 1 : -1;
+
+	src = (ushort *)(info->screen_base + area->sy * info->fix.line_length +
+			(area->sx >> 4));
+	dest = area->dy * (info->fix.line_length >> 1) + (area->dx >> 4);
+
+	if (incr > 0) {
+		y_delta = (info->fix.line_length * 8) - area->sx - area->width;
+		x_end = area->dx + area->width - 1;
+		x_word_count = (x_end >> 4) - (area->dx >> 4) + 1;
+		start_mask = 0xffff0000 >> (area->dx & 0xf);
+		end_mask = 0x7ffff >> (x_end & 0xf);
+		out_8(AP_CONTROL_0,
+		     (((area->dx & 0xf) - (area->sx & 0xf)) % 16) | (0x4 << 5));
+		if ((area->dx & 0xf) < (area->sx & 0xf))
+			pre_read = 1;
+	} else {
+		y_delta = -((info->fix.line_length * 8) - area->sx - area->width);
+		x_end = area->dx - area->width + 1;
+		x_word_count = (area->dx >> 4) - (x_end >> 4) + 1;
+		start_mask = 0x7ffff >> (area->dx & 0xf);
+		end_mask = 0xffff0000 >> (x_end & 0xf);
+		out_8(AP_CONTROL_0,
+		     ((-((area->sx & 0xf) - (area->dx & 0xf))) % 16) |
+		     (0x4 << 5));
+		if ((area->dx & 0xf) > (area->sx & 0xf))
+			pre_read = 1;
+	}
+
+	for (i = 0; i < area->height; i++) {
+
+		out_8(AP_CONTROL_3A, 0xc | (dest >> 16));
+
+		if (pre_read) {
+			dummy = *src;
+			src += incr;
+		}
+
+		if (x_word_count) {
+			out_8(AP_WRITE_ENABLE, start_mask);
+			*src = dest;
+			src += incr;
+			dest += incr;
+			out_8(AP_WRITE_ENABLE, 0);
+
+			for (j = 1; j < (x_word_count - 1); j++) {
+				*src = dest;
+				src += incr;
+				dest += incr;
+			}
+
+			out_8(AP_WRITE_ENABLE, start_mask);
+			*src = dest;
+			dest += incr;
+			src += incr;
+		} else {
+			out_8(AP_WRITE_ENABLE, start_mask | end_mask);
+			*src = dest;
+			dest += incr;
+			src += incr;
+		}
+		src += (y_delta / 16);
+		dest += (y_delta / 16);
+	}
+	out_8(AP_CONTROL_0, NORMAL_MODE);
+}
+
+/*
+ * Initialization
+ */
+
+static int __devinit dnfb_probe(struct device *device)
+{
+	struct platform_device *dev = to_platform_device(device);
+	struct fb_info *info;
+	int err = 0;
+
+	info = framebuffer_alloc(0, &dev->dev);
+	if (!info)
+		return -ENOMEM;
+
+	info->fbops = &dn_fb_ops;
+	info->fix = dnfb_fix;
+	info->var = dnfb_var;
+	info->var.red.length = 1;
+	info->var.red.offset = 0;
+	info->var.green = info->var.blue = info->var.red;
+	info->screen_base = (u_char *) info->fix.smem_start;
+
+	err = fb_alloc_cmap(&info->cmap, 2, 0);
+	if (err < 0) {
+		framebuffer_release(info);
+		return err;
+	}
+
+	err = register_framebuffer(info);
+	if (err < 0) {
+		fb_dealloc_cmap(&info->cmap);
+		framebuffer_release(info);
+		return err;
+	}
+	dev_set_drvdata(&dev->dev, info);
+
+	/* now we have registered we can safely setup the hardware */
+	out_8(AP_CONTROL_3A, RESET_CREG);
+	out_be16(AP_WRITE_ENABLE, 0x0);
+	out_8(AP_CONTROL_0, NORMAL_MODE);
+	out_8(AP_CONTROL_1, (AD_BLT | DST_EQ_SRC | NORM_CREG1));
+	out_8(AP_CONTROL_2, S_DATA_PLN);
+	out_be16(AP_ROP_1, SWAP(0x3));
+
+	printk("apollo frame buffer alive and kicking !\n");
+	return err;
+}
+
+static struct device_driver dnfb_driver = {
+	.name	= "dnfb",
+	.bus	= &platform_bus_type,
+	.probe	= dnfb_probe,
+};
+
+static struct platform_device dnfb_device = {
+	.name	= "dnfb",
+};
+
+int __init dnfb_init(void)
+{
+	int ret;
+
+	if (fb_get_options("dnfb", NULL))
+		return -ENODEV;
+
+	ret = driver_register(&dnfb_driver);
+
+	if (!ret) {
+		ret = platform_device_register(&dnfb_device);
+		if (ret)
+			driver_unregister(&dnfb_driver);
+	}
+	return ret;
+}
+
+module_init(dnfb_init);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/edid.h b/drivers/video/edid.h
new file mode 100644
index 0000000..bd89fb3
--- /dev/null
+++ b/drivers/video/edid.h
@@ -0,0 +1,138 @@
+/* 
+ * drivers/video/edid.h - EDID/DDC Header
+ *
+ * Based on:
+ *   1. XFree86 4.3.0, edid.h
+ *      Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE>
+ * 
+ *   2. John Fremlin <vii@users.sourceforge.net> and 
+ *      Ani Joshi <ajoshi@unixbox.com>
+ *
+ * DDC is a Trademark of VESA (Video Electronics Standard Association).
+ *
+ * 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 __EDID_H__
+#define __EDID_H__
+
+#define EDID_LENGTH				0x80
+#define EDID_HEADER				0x00
+#define EDID_HEADER_END				0x07
+
+#define ID_MANUFACTURER_NAME			0x08
+#define ID_MANUFACTURER_NAME_END		0x09
+#define ID_MODEL				0x0a
+
+#define ID_SERIAL_NUMBER			0x0c
+
+#define MANUFACTURE_WEEK			0x10
+#define MANUFACTURE_YEAR			0x11
+
+#define EDID_STRUCT_VERSION			0x12
+#define EDID_STRUCT_REVISION			0x13
+
+#define EDID_STRUCT_DISPLAY                     0x14
+
+#define DPMS_FLAGS				0x18
+#define ESTABLISHED_TIMING_1			0x23
+#define ESTABLISHED_TIMING_2			0x24
+#define MANUFACTURERS_TIMINGS			0x25
+
+/* standard timings supported */
+#define STD_TIMING                              8
+#define STD_TIMING_DESCRIPTION_SIZE             2
+#define STD_TIMING_DESCRIPTIONS_START           0x26
+
+#define DETAILED_TIMING_DESCRIPTIONS_START	0x36
+#define DETAILED_TIMING_DESCRIPTION_SIZE	18
+#define NO_DETAILED_TIMING_DESCRIPTIONS		4
+
+#define DETAILED_TIMING_DESCRIPTION_1		0x36
+#define DETAILED_TIMING_DESCRIPTION_2		0x48
+#define DETAILED_TIMING_DESCRIPTION_3		0x5a
+#define DETAILED_TIMING_DESCRIPTION_4		0x6c
+
+#define DESCRIPTOR_DATA				5
+
+#define UPPER_NIBBLE( x ) \
+        (((128|64|32|16) & (x)) >> 4)
+
+#define LOWER_NIBBLE( x ) \
+        ((1|2|4|8) & (x))
+
+#define COMBINE_HI_8LO( hi, lo ) \
+        ( (((unsigned)hi) << 8) | (unsigned)lo )
+
+#define COMBINE_HI_4LO( hi, lo ) \
+        ( (((unsigned)hi) << 4) | (unsigned)lo )
+
+#define PIXEL_CLOCK_LO     (unsigned)block[ 0 ]
+#define PIXEL_CLOCK_HI     (unsigned)block[ 1 ]
+#define PIXEL_CLOCK	   (COMBINE_HI_8LO( PIXEL_CLOCK_HI,PIXEL_CLOCK_LO )*10000)
+#define H_ACTIVE_LO        (unsigned)block[ 2 ]
+#define H_BLANKING_LO      (unsigned)block[ 3 ]
+#define H_ACTIVE_HI        UPPER_NIBBLE( (unsigned)block[ 4 ] )
+#define H_ACTIVE           COMBINE_HI_8LO( H_ACTIVE_HI, H_ACTIVE_LO )
+#define H_BLANKING_HI      LOWER_NIBBLE( (unsigned)block[ 4 ] )
+#define H_BLANKING         COMBINE_HI_8LO( H_BLANKING_HI, H_BLANKING_LO )
+
+#define V_ACTIVE_LO        (unsigned)block[ 5 ]
+#define V_BLANKING_LO      (unsigned)block[ 6 ]
+#define V_ACTIVE_HI        UPPER_NIBBLE( (unsigned)block[ 7 ] )
+#define V_ACTIVE           COMBINE_HI_8LO( V_ACTIVE_HI, V_ACTIVE_LO )
+#define V_BLANKING_HI      LOWER_NIBBLE( (unsigned)block[ 7 ] )
+#define V_BLANKING         COMBINE_HI_8LO( V_BLANKING_HI, V_BLANKING_LO )
+
+#define H_SYNC_OFFSET_LO   (unsigned)block[ 8 ]
+#define H_SYNC_WIDTH_LO    (unsigned)block[ 9 ]
+
+#define V_SYNC_OFFSET_LO   UPPER_NIBBLE( (unsigned)block[ 10 ] )
+#define V_SYNC_WIDTH_LO    LOWER_NIBBLE( (unsigned)block[ 10 ] )
+
+#define V_SYNC_WIDTH_HI    ((unsigned)block[ 11 ] & (1|2))
+#define V_SYNC_OFFSET_HI   (((unsigned)block[ 11 ] & (4|8)) >> 2)
+
+#define H_SYNC_WIDTH_HI    (((unsigned)block[ 11 ] & (16|32)) >> 4)
+#define H_SYNC_OFFSET_HI   (((unsigned)block[ 11 ] & (64|128)) >> 6)
+
+#define V_SYNC_WIDTH       COMBINE_HI_4LO( V_SYNC_WIDTH_HI, V_SYNC_WIDTH_LO )
+#define V_SYNC_OFFSET      COMBINE_HI_4LO( V_SYNC_OFFSET_HI, V_SYNC_OFFSET_LO )
+
+#define H_SYNC_WIDTH       COMBINE_HI_4LO( H_SYNC_WIDTH_HI, H_SYNC_WIDTH_LO )
+#define H_SYNC_OFFSET      COMBINE_HI_4LO( H_SYNC_OFFSET_HI, H_SYNC_OFFSET_LO )
+
+#define H_SIZE_LO          (unsigned)block[ 12 ]
+#define V_SIZE_LO          (unsigned)block[ 13 ]
+
+#define H_SIZE_HI          UPPER_NIBBLE( (unsigned)block[ 14 ] )
+#define V_SIZE_HI          LOWER_NIBBLE( (unsigned)block[ 14 ] )
+
+#define H_SIZE             COMBINE_HI_8LO( H_SIZE_HI, H_SIZE_LO )
+#define V_SIZE             COMBINE_HI_8LO( V_SIZE_HI, V_SIZE_LO )
+
+#define H_BORDER           (unsigned)block[ 15 ]
+#define V_BORDER           (unsigned)block[ 16 ]
+
+#define FLAGS              (unsigned)block[ 17 ]
+
+#define INTERLACED         (FLAGS&128)
+#define SYNC_TYPE          (FLAGS&3<<3)	/* bits 4,3 */
+#define SYNC_SEPARATE      (3<<3)
+#define HSYNC_POSITIVE     (FLAGS & 4)
+#define VSYNC_POSITIVE     (FLAGS & 2)
+
+#define V_MIN_RATE              block[ 5 ]
+#define V_MAX_RATE              block[ 6 ]
+#define H_MIN_RATE              block[ 7 ]
+#define H_MAX_RATE              block[ 8 ]
+#define MAX_PIXEL_CLOCK         (((int)block[ 9 ]) * 10)
+#define GTF_SUPPORT		block[10]
+
+#define DPMS_ACTIVE_OFF		(1 << 5)
+#define DPMS_SUSPEND		(1 << 6)
+#define DPMS_STANDBY		(1 << 7)
+
+#endif /* __EDID_H__ */
diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c
new file mode 100644
index 0000000..116e808
--- /dev/null
+++ b/drivers/video/epson1355fb.c
@@ -0,0 +1,774 @@
+/*
+ * linux/drivers/video/epson1355fb.c -- Epson S1D13505 frame buffer for 2.5.
+ *
+ * Epson Research S1D13505 Embedded RAMDAC LCD/CRT Controller
+ *   (previously known as SED1355)
+ *
+ * Cf. http://www.erd.epson.com/vdc/html/S1D13505.html
+ *
+ *
+ * Copyright (C) Hewlett-Packard Company.  All rights reserved.
+ *
+ * Written by Christopher Hoover <ch@hpl.hp.com>
+ *
+ * Adapted from:
+ *
+ *  linux/drivers/video/skeletonfb.c
+ *  Modified to new api Jan 2001 by James Simmons (jsimmons@infradead.org)
+ *  Created 28 Dec 1997 by Geert Uytterhoeven
+ *
+ *  linux/drivers/video/epson1355fb.c (2.4 driver)
+ *  Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ *
+ * 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.
+ *
+ *
+ * Noteworthy Issues
+ * -----------------
+ *
+ * This driver is complicated by the fact that this is a 16-bit chip
+ * and, on at least one platform (ceiva), we can only do 16-bit reads
+ * and writes to the framebuffer.  We hide this from user space
+ * except in the case of mmap().
+ *
+ *
+ * To Do
+ * -----
+ *
+ * - Test 8-bit pseudocolor mode
+ * - Allow setting bpp, virtual resolution
+ * - Implement horizontal panning
+ * - (maybe) Implement hardware cursor
+ */
+
+#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/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <asm/types.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include <video/epson1355.h>
+
+struct epson1355_par {
+	unsigned long reg_addr;
+};
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_SUPERH
+
+static inline u8 epson1355_read_reg(int index)
+{
+	return ctrl_inb(par.reg_addr + index);
+}
+
+static inline void epson1355_write_reg(u8 data, int index)
+{
+	ctrl_outb(data, par.reg_addr + index);
+}
+
+#elif defined(CONFIG_ARM)
+
+# ifdef CONFIG_ARCH_CEIVA
+#  include <asm/arch/hardware.h>
+#  define EPSON1355FB_BASE_PHYS	(CEIVA_PHYS_SED1355)
+# endif
+
+static inline u8 epson1355_read_reg(struct epson1355_par *par, int index)
+{
+	return __raw_readb(par->reg_addr + index);
+}
+
+static inline void epson1355_write_reg(struct epson1355_par *par, u8 data, int index)
+{
+	__raw_writeb(data, par->reg_addr + index);
+}
+
+#else
+# error "no architecture-specific epson1355_{read,write}_reg"
+#endif
+
+#ifndef EPSON1355FB_BASE_PHYS
+# error  "EPSON1355FB_BASE_PHYS is not defined"
+#endif
+
+#define EPSON1355FB_REGS_OFS	(0)
+#define EPSON1355FB_REGS_PHYS	(EPSON1355FB_BASE_PHYS + EPSON1355FB_REGS_OFS)
+#define EPSON1355FB_REGS_LEN	(64)
+
+#define EPSON1355FB_FB_OFS	(0x00200000)
+#define EPSON1355FB_FB_PHYS	(EPSON1355FB_BASE_PHYS + EPSON1355FB_FB_OFS)
+#define EPSON1355FB_FB_LEN	(2 * 1024 * 1024)
+
+/* ------------------------------------------------------------------------- */
+
+static inline u16 epson1355_read_reg16(struct epson1355_par *par, int index)
+{
+	u8 lo = epson1355_read_reg(par, index);
+	u8 hi = epson1355_read_reg(par, index + 1);
+
+	return (hi << 8) | lo;
+}
+
+static inline void epson1355_write_reg16(struct epson1355_par *par, u16 data, int index)
+{
+	u8 lo = data & 0xff;
+	u8 hi = (data >> 8) & 0xff;
+
+	epson1355_write_reg(par, lo, index);
+	epson1355_write_reg(par, hi, index + 1);
+}
+
+static inline u32 epson1355_read_reg20(struct epson1355_par *par, int index)
+{
+	u8 b0 = epson1355_read_reg(par, index);
+	u8 b1 = epson1355_read_reg(par, index + 1);
+	u8 b2 = epson1355_read_reg(par, index + 2);
+
+	return (b2 & 0x0f) << 16 | (b1 << 8) | b0;
+}
+
+static inline void epson1355_write_reg20(struct epson1355_par *par, u32 data, int index)
+{
+	u8 b0 = data & 0xff;
+	u8 b1 = (data >> 8) & 0xff;
+	u8 b2 = (data >> 16) & 0x0f;
+
+	epson1355_write_reg(par, b0, index);
+	epson1355_write_reg(par, b1, index + 1);
+	epson1355_write_reg(par, b2, index + 2);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void set_lut(struct epson1355_par *par, u8 index, u8 r, u8 g, u8 b)
+{
+	epson1355_write_reg(par, index, REG_LUT_ADDR);
+	epson1355_write_reg(par, r, REG_LUT_DATA);
+	epson1355_write_reg(par, g, REG_LUT_DATA);
+	epson1355_write_reg(par, b, REG_LUT_DATA);
+}
+
+
+/**
+ *  	epson1355fb_setcolreg - sets a color register.
+ *      @regno: Which register in the CLUT we are programming
+ *      @red: The red value which can be up to 16 bits wide
+ *	@green: The green value which can be up to 16 bits wide
+ *	@blue:  The blue value which can be up to 16 bits wide.
+ *	@transp: If supported the alpha value which can be up to 16 bits wide.
+ *      @info: frame buffer info structure
+ *
+ *	Returns negative errno on error, or zero on success.
+ */
+static int epson1355fb_setcolreg(unsigned regno, unsigned r, unsigned g,
+				 unsigned b, unsigned transp,
+				 struct fb_info *info)
+{
+	struct epson1355_par *par = info->par;
+
+	if (info->var.grayscale)
+		r = g = b = (19595 * r + 38470 * g + 7471 * b) >> 16;
+
+	switch (info->fix.visual) {
+	case FB_VISUAL_TRUECOLOR:
+		if (regno >= 16)
+			return -EINVAL;
+
+		((u32 *) info->pseudo_palette)[regno] =
+		    (r & 0xf800) | (g & 0xfc00) >> 5 | (b & 0xf800) >> 11;
+
+		break;
+	case FB_VISUAL_PSEUDOCOLOR:
+		if (regno >= 256)
+			return -EINVAL;
+
+		set_lut(par, regno, r >> 8, g >> 8, b >> 8);
+
+		break;
+	default:
+		return -ENOSYS;
+	}
+	return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ *      epson1355fb_pan_display - Pans the display.
+ *      @var: frame buffer variable screen structure
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ *	Pan (or wrap, depending on the `vmode' field) the display using the
+ *  	`xoffset' and `yoffset' fields of the `var' structure.
+ *  	If the values don't fit, return -EINVAL.
+ *
+ *      Returns negative errno on error, or zero on success.
+ */
+static int epson1355fb_pan_display(struct fb_var_screeninfo *var,
+				   struct fb_info *info)
+{
+	struct epson1355_par *par = info->par;
+	u32 start;
+
+	if (var->xoffset != 0)	/* not yet ... */
+		return -EINVAL;
+
+	if (var->yoffset + info->var.yres > info->var.yres_virtual)
+		return -EINVAL;
+
+	start = (info->fix.line_length >> 1) * var->yoffset;
+
+	epson1355_write_reg20(par, start, REG_SCRN1_DISP_START_ADDR0);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void lcd_enable(struct epson1355_par *par, int enable)
+{
+	u8 mode = epson1355_read_reg(par, REG_DISPLAY_MODE);
+
+	if (enable)
+		mode |= 1;
+	else
+		mode &= ~1;
+
+	epson1355_write_reg(par, mode, REG_DISPLAY_MODE);
+}
+
+#if defined(CONFIG_ARCH_CEIVA)
+static void backlight_enable(int enable)
+{
+	/* ### this should be protected by a spinlock ... */
+	u8 pddr = clps_readb(PDDR);
+	if (enable)
+		pddr |= (1 << 5);
+	else
+		pddr &= ~(1 << 5);
+	clps_writeb(pddr, PDDR);
+}
+#else
+static void backlight_enable(int enable)
+{
+}
+#endif
+
+
+/**
+ *      epson1355fb_blank - blanks the display.
+ *      @blank_mode: the blank mode we want.
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ *      Blank the screen if blank_mode != 0, else unblank. Return 0 if
+ *      blanking succeeded, != 0 if un-/blanking failed due to e.g. a
+ *      video mode which doesn't support it. Implements VESA suspend
+ *      and powerdown modes on hardware that supports disabling hsync/vsync:
+ *      blank_mode == 2: suspend vsync
+ *      blank_mode == 3: suspend hsync
+ *      blank_mode == 4: powerdown
+ *
+ *      Returns negative errno on error, or zero on success.
+ *
+ */
+static int epson1355fb_blank(int blank_mode, struct fb_info *info)
+{
+	struct epson1355_par *par = info->par;
+
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANKING:
+	case FB_BLANK_NORMAL:
+		lcd_enable(par, 1);
+		backlight_enable(1);
+		break;
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+		backlight_enable(0);
+		break;
+	case FB_BLANK_POWERDOWN:
+		backlight_enable(0);
+		lcd_enable(par, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* let fbcon do a soft blank for us */
+	return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * We can't use the cfb generic routines, as we have to limit
+ * ourselves to 16-bit or 8-bit loads and stores to this 16-bit
+ * chip.
+ */
+
+static inline void epson1355fb_fb_writel(unsigned long v, unsigned long *a)
+{
+	u16 *p = (u16 *) a;
+	u16 l = v & 0xffff;
+	u16 h = v >> 16;
+
+	fb_writew(l, p);
+	fb_writew(h, p + 1);
+}
+
+static inline unsigned long epson1355fb_fb_readl(const unsigned long *a)
+{
+	const u16 *p = (u16 *) a;
+	u16 l = fb_readw(p);
+	u16 h = fb_readw(p + 1);
+
+	return (h << 16) | l;
+}
+
+#define FB_READL epson1355fb_fb_readl
+#define FB_WRITEL epson1355fb_fb_writel
+
+/* ------------------------------------------------------------------------- */
+
+static inline unsigned long copy_from_user16(void *to, const void *from,
+					     unsigned long n)
+{
+	u16 *dst = (u16 *) to;
+	u16 *src = (u16 *) from;
+
+	if (!access_ok(VERIFY_READ, from, n))
+		return n;
+
+	while (n > 1) {
+		u16 v;
+		if (__get_user(v, src))
+			return n;
+
+		fb_writew(v, dst);
+
+		src++, dst++;
+		n -= 2;
+	}
+
+	if (n) {
+		u8 v;
+
+		if (__get_user(v, ((u8 *) src)))
+			return n;
+
+		fb_writeb(v, dst);
+	}
+	return 0;
+}
+
+static inline unsigned long copy_to_user16(void *to, const void *from,
+					   unsigned long n)
+{
+	u16 *dst = (u16 *) to;
+	u16 *src = (u16 *) from;
+
+	if (!access_ok(VERIFY_WRITE, to, n))
+		return n;
+
+	while (n > 1) {
+		u16 v = fb_readw(src);
+
+		if (__put_user(v, dst))
+			return n;
+
+		src++, dst++;
+		n -= 2;
+	}
+
+	if (n) {
+		u8 v = fb_readb(src);
+
+		if (__put_user(v, ((u8 *) dst)))
+			return n;
+	}
+	return 0;
+}
+
+
+static ssize_t
+epson1355fb_read(struct file *file, char *buf, size_t count, loff_t * ppos)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	int fbidx = iminor(inode);
+	struct fb_info *info = registered_fb[fbidx];
+	unsigned long p = *ppos;
+
+	/* from fbmem.c except for our own copy_*_user */
+	if (!info || !info->screen_base)
+		return -ENODEV;
+
+	if (p >= info->fix.smem_len)
+		return 0;
+	if (count >= info->fix.smem_len)
+		count = info->fix.smem_len;
+	if (count + p > info->fix.smem_len)
+		count = info->fix.smem_len - p;
+
+	if (count) {
+		char *base_addr;
+
+		base_addr = info->screen_base;
+		count -= copy_to_user16(buf, base_addr + p, count);
+		if (!count)
+			return -EFAULT;
+		*ppos += count;
+	}
+	return count;
+}
+
+static ssize_t
+epson1355fb_write(struct file *file, const char *buf,
+		  size_t count, loff_t * ppos)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	int fbidx = iminor(inode);
+	struct fb_info *info = registered_fb[fbidx];
+	unsigned long p = *ppos;
+	int err;
+
+	/* from fbmem.c except for our own copy_*_user */
+	if (!info || !info->screen_base)
+		return -ENODEV;
+
+	/* from fbmem.c except for our own copy_*_user */
+	if (p > info->fix.smem_len)
+		return -ENOSPC;
+	if (count >= info->fix.smem_len)
+		count = info->fix.smem_len;
+	err = 0;
+	if (count + p > info->fix.smem_len) {
+		count = info->fix.smem_len - p;
+		err = -ENOSPC;
+	}
+
+	if (count) {
+		char *base_addr;
+
+		base_addr = info->screen_base;
+		count -= copy_from_user16(base_addr + p, buf, count);
+		*ppos += count;
+		err = -EFAULT;
+	}
+	if (count)
+		return count;
+	return err;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static struct fb_ops epson1355fb_fbops = {
+	.owner 		= THIS_MODULE,
+	.fb_setcolreg 	= epson1355fb_setcolreg,
+	.fb_pan_display = epson1355fb_pan_display,
+	.fb_blank 	= epson1355fb_blank,
+	.fb_fillrect 	= cfb_fillrect,
+	.fb_copyarea 	= cfb_copyarea,
+	.fb_imageblit 	= cfb_imageblit,
+	.fb_read 	= epson1355fb_read,
+	.fb_write 	= epson1355fb_write,
+	.fb_cursor 	= soft_cursor,
+};
+
+/* ------------------------------------------------------------------------- */
+
+static __init unsigned int get_fb_size(struct fb_info *info)
+{
+	unsigned int size = 2 * 1024 * 1024;
+	char *p = info->screen_base;
+
+	/* the 512k framebuffer is aliased at start + 0x80000 * n */
+	fb_writeb(1, p);
+	fb_writeb(0, p + 0x80000);
+	if (!fb_readb(p))
+		size = 512 * 1024;
+
+	fb_writeb(0, p);
+
+	return size;
+}
+
+static int epson1355_width_tab[2][4] __initdata =
+    { {4, 8, 16, -1}, {9, 12, 16, -1} };
+static int epson1355_bpp_tab[8] __initdata = { 1, 2, 4, 8, 15, 16 };
+
+static void __init fetch_hw_state(struct fb_info *info, struct epson1355_par *par)
+{
+	struct fb_var_screeninfo *var = &info->var;
+	struct fb_fix_screeninfo *fix = &info->fix;
+	u8 panel, display;
+	u16 offset;
+	u32 xres, yres;
+	u32 xres_virtual, yres_virtual;
+	int bpp, lcd_bpp;
+	int is_color, is_dual, is_tft;
+	int lcd_enabled, crt_enabled;
+
+	fix->type = FB_TYPE_PACKED_PIXELS;
+
+	display = epson1355_read_reg(par, REG_DISPLAY_MODE);
+	bpp = epson1355_bpp_tab[(display >> 2) & 7];
+
+	switch (bpp) {
+	case 8:
+		fix->visual = FB_VISUAL_PSEUDOCOLOR;
+		var->bits_per_pixel = 8;
+		var->red.offset = var->green.offset = var->blue.offset = 0;
+		var->red.length = var->green.length = var->blue.length = 8;
+		break;
+	case 16:
+		/* 5-6-5 RGB */
+		fix->visual = FB_VISUAL_TRUECOLOR;
+		var->bits_per_pixel = 16;
+		var->red.offset = 11;
+		var->red.length = 5;
+		var->green.offset = 5;
+		var->green.length = 6;
+		var->blue.offset = 0;
+		var->blue.length = 5;
+		break;
+	default:
+		BUG();
+	}
+	fb_alloc_cmap(&(info->cmap), 256, 0);
+
+	panel = epson1355_read_reg(par, REG_PANEL_TYPE);
+	is_color = (panel & 0x04) != 0;
+	is_dual = (panel & 0x02) != 0;
+	is_tft = (panel & 0x01) != 0;
+	crt_enabled = (display & 0x02) != 0;
+	lcd_enabled = (display & 0x01) != 0;
+	lcd_bpp = epson1355_width_tab[is_tft][(panel >> 4) & 3];
+
+	xres = (epson1355_read_reg(par, REG_HORZ_DISP_WIDTH) + 1) * 8;
+	yres = (epson1355_read_reg16(par, REG_VERT_DISP_HEIGHT0) + 1) *
+	    ((is_dual && !crt_enabled) ? 2 : 1);
+	offset = epson1355_read_reg16(par, REG_MEM_ADDR_OFFSET0) & 0x7ff;
+	xres_virtual = offset * 16 / bpp;
+	yres_virtual = fix->smem_len / (offset * 2);
+
+	var->xres = xres;
+	var->yres = yres;
+	var->xres_virtual = xres_virtual;
+	var->yres_virtual = yres_virtual;
+	var->xoffset = var->yoffset = 0;
+
+	fix->line_length = offset * 2;
+
+	fix->xpanstep = 0;	/* no pan yet */
+	fix->ypanstep = 1;
+	fix->ywrapstep = 0;
+	fix->accel = FB_ACCEL_NONE;
+
+	var->grayscale = !is_color;
+
+#ifdef DEBUG
+	printk(KERN_INFO
+	       "epson1355fb: xres=%d, yres=%d, "
+	       "is_color=%d, is_dual=%d, is_tft=%d\n",
+	       xres, yres, is_color, is_dual, is_tft);
+	printk(KERN_INFO
+	       "epson1355fb: bpp=%d, lcd_bpp=%d, "
+	       "crt_enabled=%d, lcd_enabled=%d\n",
+	       bpp, lcd_bpp, crt_enabled, lcd_enabled);
+#endif
+}
+
+
+static void clearfb16(struct fb_info *info)
+{
+	u16 *dst = (u16 *) info->screen_base;
+	unsigned long n = info->fix.smem_len;
+
+	while (n > 1) {
+		fb_writew(0, dst);
+		dst++, n -= 2;
+	}
+
+	if (n)
+		fb_writeb(0, dst);
+}
+
+static void epson1355fb_platform_release(struct device *device)
+{
+}
+
+static int epson1355fb_remove(struct device *device)
+{
+	struct fb_info *info = dev_get_drvdata(device);
+	struct epson1355_par *par = info->par;
+
+	backlight_enable(0);
+	if (par) {
+		lcd_enable(par, 0);
+		if (par && par->reg_addr)
+			iounmap((void *) par->reg_addr);
+	}
+
+	if (info) {
+		fb_dealloc_cmap(&info->cmap);
+		if (info->screen_base)
+			iounmap(info->screen_base);
+		framebuffer_release(info);
+	}
+	release_mem_region(EPSON1355FB_FB_PHYS, EPSON1355FB_FB_LEN);
+	release_mem_region(EPSON1355FB_REGS_PHYS, EPSON1355FB_REGS_LEN);
+	return 0;
+}
+
+int __init epson1355fb_probe(struct device *device)
+{
+	struct platform_device *dev = to_platform_device(device);
+	struct epson1355_par *default_par;
+	struct fb_info *info;
+	u8 revision;
+	int rc = 0;
+
+	if (!request_mem_region(EPSON1355FB_REGS_PHYS, EPSON1355FB_REGS_LEN, "S1D13505 registers")) {
+		printk(KERN_ERR "epson1355fb: unable to reserve "
+		       "registers at 0x%0x\n", EPSON1355FB_REGS_PHYS);
+		rc = -EBUSY;
+		goto bail;
+	}
+
+	if (!request_mem_region(EPSON1355FB_FB_PHYS, EPSON1355FB_FB_LEN,
+				"S1D13505 framebuffer")) {
+		printk(KERN_ERR "epson1355fb: unable to reserve "
+		       "framebuffer at 0x%0x\n", EPSON1355FB_FB_PHYS);
+		rc = -EBUSY;
+		goto bail;
+	}
+
+	info = framebuffer_alloc(sizeof(struct epson1355_par) + sizeof(u32) * 256, &dev->dev);
+	if (!info)
+		rc = -ENOMEM;
+		goto bail;
+
+	default_par = info->par;
+	default_par->reg_addr = (unsigned long) ioremap(EPSON1355FB_REGS_PHYS, EPSON1355FB_REGS_LEN);
+	if (!default_par->reg_addr) {
+		printk(KERN_ERR "epson1355fb: unable to map registers\n");
+		rc = -ENOMEM;
+		goto bail;
+	}
+	info->pseudo_palette = (void *)(default_par + 1);
+
+	info->screen_base = ioremap(EPSON1355FB_FB_PHYS, EPSON1355FB_FB_LEN);
+	if (!info->screen_base) {
+		printk(KERN_ERR "epson1355fb: unable to map framebuffer\n");
+		rc = -ENOMEM;
+		goto bail;
+	}
+
+	revision = epson1355_read_reg(default_par, REG_REVISION_CODE);
+	if ((revision >> 2) != 3) {
+		printk(KERN_INFO "epson1355fb: epson1355 not found\n");
+		rc = -ENODEV;
+		goto bail;
+	}
+
+	info->fix.mmio_start = EPSON1355FB_REGS_PHYS;
+	info->fix.mmio_len = EPSON1355FB_REGS_LEN;
+	info->fix.smem_start = EPSON1355FB_FB_PHYS;
+	info->fix.smem_len = get_fb_size(info);
+
+	printk(KERN_INFO "epson1355fb: regs mapped at 0x%lx, fb %d KiB mapped at 0x%p\n",
+	       default_par->reg_addr, info->fix.smem_len / 1024, info->screen_base);
+
+	strcpy(info->fix.id, "S1D13505");
+	info->par = default_par;
+	info->fbops = &epson1355fb_fbops;
+	info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+
+	/* we expect the boot loader to have initialized the chip
+	   with appropriate parameters from which we can determinte
+	   the flavor of lcd panel attached */
+	fetch_hw_state(info, default_par);
+
+	/* turn this puppy on ... */
+	clearfb16(info);
+	backlight_enable(1);
+	lcd_enable(default_par, 1);
+
+	if (register_framebuffer(info) < 0) {
+		rc = -EINVAL;
+		goto bail;
+	}
+	/*
+	 * Our driver data.
+	 */
+	dev_set_drvdata(&dev->dev, info);
+
+	printk(KERN_INFO "fb%d: %s frame buffer device\n",
+	       info->node, info->fix.id);
+
+	return 0;
+
+      bail:
+	epson1355fb_remove(device);
+	return rc;
+}
+
+static struct device_driver epson1355fb_driver = {
+	.name	= "epson1355fb",
+	.bus	= &platform_bus_type,
+	.probe	= epson1355fb_probe,
+	.remove	= epson1355fb_remove,
+};
+
+static struct platform_device epson1355fb_device = {
+	.name	= "epson1355fb",
+	.id	= 0,
+	.dev	= {
+		.release = epson1355fb_platform_release,
+	}
+};
+
+int __init epson1355fb_init(void)
+{
+	int ret = 0;
+
+	if (fb_get_options("epson1355fb", NULL))
+		return -ENODEV;
+
+	ret = driver_register(&epson1355fb_driver);
+	if (!ret) {
+		ret = platform_device_register(&epson1355fb_device);
+		if (ret)
+			driver_unregister(&epson1355fb_driver);
+	}
+	return ret;
+}
+
+module_init(epson1355fb_init);
+	
+#ifdef MODULE
+static void __exit epson1355fb_exit(void)
+{
+	platform_device_unregister(&epson1355fb_device);
+	driver_unregister(&epson1355fb_driver);
+}
+
+/* ------------------------------------------------------------------------- */
+
+module_exit(epson1355fb_exit);
+#endif
+
+MODULE_AUTHOR("Christopher Hoover <ch@hpl.hp.com>");
+MODULE_DESCRIPTION("Framebuffer driver for Epson S1D13505");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c
new file mode 100644
index 0000000..c51f8fb
--- /dev/null
+++ b/drivers/video/fbcmap.c
@@ -0,0 +1,337 @@
+/*
+ *  linux/drivers/video/fbcmap.c -- Colormap handling for frame buffer devices
+ *
+ *	Created 15 Jun 1997 by Geert Uytterhoeven
+ *
+ *	2001 - Documented with DocBook
+ *	- Brad Douglas <brad@neruo.com>
+ *
+ *  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/string.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/fb.h>
+#include <linux/slab.h>
+
+#include <asm/uaccess.h>
+
+static u16 red2[] = {
+    0x0000, 0xaaaa
+};
+static u16 green2[] = {
+    0x0000, 0xaaaa
+};
+static u16 blue2[] = {
+    0x0000, 0xaaaa
+};
+
+static u16 red4[] = {
+    0x0000, 0xaaaa, 0x5555, 0xffff
+};
+static u16 green4[] = {
+    0x0000, 0xaaaa, 0x5555, 0xffff
+};
+static u16 blue4[] = {
+    0x0000, 0xaaaa, 0x5555, 0xffff
+};
+
+static u16 red8[] = {
+    0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa
+};
+static u16 green8[] = {
+    0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa
+};
+static u16 blue8[] = {
+    0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa
+};
+
+static u16 red16[] = {
+    0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa,
+    0x5555, 0x5555, 0x5555, 0x5555, 0xffff, 0xffff, 0xffff, 0xffff
+};
+static u16 green16[] = {
+    0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa,
+    0x5555, 0x5555, 0xffff, 0xffff, 0x5555, 0x5555, 0xffff, 0xffff
+};
+static u16 blue16[] = {
+    0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa,
+    0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff
+};
+
+static struct fb_cmap default_2_colors = {
+    0, 2, red2, green2, blue2, NULL
+};
+static struct fb_cmap default_8_colors = {
+    0, 8, red8, green8, blue8, NULL
+};
+static struct fb_cmap default_4_colors = {
+    0, 4, red4, green4, blue4, NULL
+};
+static struct fb_cmap default_16_colors = {
+    0, 16, red16, green16, blue16, NULL
+};
+
+
+/**
+ *	fb_alloc_cmap - allocate a colormap
+ *	@cmap: frame buffer colormap structure
+ *	@len: length of @cmap
+ *	@transp: boolean, 1 if there is transparency, 0 otherwise
+ *
+ *	Allocates memory for a colormap @cmap.  @len is the
+ *	number of entries in the palette.
+ *
+ *	Returns -1 errno on error, or zero on success.
+ *
+ */
+
+int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp)
+{
+    int size = len*sizeof(u16);
+
+    if (cmap->len != len) {
+	fb_dealloc_cmap(cmap);
+	if (!len)
+	    return 0;
+	if (!(cmap->red = kmalloc(size, GFP_ATOMIC)))
+	    goto fail;
+	if (!(cmap->green = kmalloc(size, GFP_ATOMIC)))
+	    goto fail;
+	if (!(cmap->blue = kmalloc(size, GFP_ATOMIC)))
+	    goto fail;
+	if (transp) {
+	    if (!(cmap->transp = kmalloc(size, GFP_ATOMIC)))
+		goto fail;
+	} else
+	    cmap->transp = NULL;
+    }
+    cmap->start = 0;
+    cmap->len = len;
+    fb_copy_cmap(fb_default_cmap(len), cmap);
+    return 0;
+
+fail:
+    fb_dealloc_cmap(cmap);
+    return -1;
+}
+
+/**
+ *      fb_dealloc_cmap - deallocate a colormap
+ *      @cmap: frame buffer colormap structure
+ *
+ *      Deallocates a colormap that was previously allocated with
+ *      fb_alloc_cmap().
+ *
+ */
+
+void fb_dealloc_cmap(struct fb_cmap *cmap)
+{
+	kfree(cmap->red);
+	kfree(cmap->green);
+	kfree(cmap->blue);
+	kfree(cmap->transp);
+
+	cmap->red = cmap->green = cmap->blue = cmap->transp = NULL;
+	cmap->len = 0;
+}
+
+/**
+ *	fb_copy_cmap - copy a colormap
+ *	@from: frame buffer colormap structure
+ *	@to: frame buffer colormap structure
+ *
+ *	Copy contents of colormap from @from to @to.
+ */
+
+int fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to)
+{
+	int tooff = 0, fromoff = 0;
+	int size;
+
+	if (to->start > from->start)
+		fromoff = to->start - from->start;
+	else
+		tooff = from->start - to->start;
+	size = to->len - tooff;
+	if (size > (int) (from->len - fromoff))
+		size = from->len - fromoff;
+	if (size <= 0)
+		return -EINVAL;
+	size *= sizeof(u16);
+
+	memcpy(to->red+tooff, from->red+fromoff, size);
+	memcpy(to->green+tooff, from->green+fromoff, size);
+	memcpy(to->blue+tooff, from->blue+fromoff, size);
+	if (from->transp && to->transp)
+		memcpy(to->transp+tooff, from->transp+fromoff, size);
+	return 0;
+}
+
+int fb_cmap_to_user(struct fb_cmap *from, struct fb_cmap_user *to)
+{
+	int tooff = 0, fromoff = 0;
+	int size;
+
+	if (to->start > from->start)
+		fromoff = to->start - from->start;
+	else
+		tooff = from->start - to->start;
+	size = to->len - tooff;
+	if (size > (int) (from->len - fromoff))
+		size = from->len - fromoff;
+	if (size <= 0)
+		return -EINVAL;
+	size *= sizeof(u16);
+
+	if (copy_to_user(to->red+tooff, from->red+fromoff, size))
+		return -EFAULT;
+	if (copy_to_user(to->green+tooff, from->green+fromoff, size))
+		return -EFAULT;
+	if (copy_to_user(to->blue+tooff, from->blue+fromoff, size))
+		return -EFAULT;
+	if (from->transp && to->transp)
+		if (copy_to_user(to->transp+tooff, from->transp+fromoff, size))
+			return -EFAULT;
+	return 0;
+}
+
+/**
+ *	fb_set_cmap - set the colormap
+ *	@cmap: frame buffer colormap structure
+ *	@info: frame buffer info structure
+ *
+ *	Sets the colormap @cmap for a screen of device @info.
+ *
+ *	Returns negative errno on error, or zero on success.
+ *
+ */
+
+int fb_set_cmap(struct fb_cmap *cmap, struct fb_info *info)
+{
+	int i, start;
+	u16 *red, *green, *blue, *transp;
+	u_int hred, hgreen, hblue, htransp = 0xffff;
+
+	red = cmap->red;
+	green = cmap->green;
+	blue = cmap->blue;
+	transp = cmap->transp;
+	start = cmap->start;
+
+	if (start < 0 || !info->fbops->fb_setcolreg)
+		return -EINVAL;
+	for (i = 0; i < cmap->len; i++) {
+		hred = *red++;
+		hgreen = *green++;
+		hblue = *blue++;
+		if (transp)
+			htransp = *transp++;
+		if (info->fbops->fb_setcolreg(start++,
+					      hred, hgreen, hblue, htransp,
+					      info))
+			break;
+	}
+	return 0;
+}
+
+int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *info)
+{
+	int i, start;
+	u16 __user *red, *green, *blue, *transp;
+	u_int hred, hgreen, hblue, htransp = 0xffff;
+
+	red = cmap->red;
+	green = cmap->green;
+	blue = cmap->blue;
+	transp = cmap->transp;
+	start = cmap->start;
+
+	if (start < 0 || !info->fbops->fb_setcolreg)
+		return -EINVAL;
+	for (i = 0; i < cmap->len; i++, red++, blue++, green++) {
+		if (get_user(hred, red) ||
+		    get_user(hgreen, green) ||
+		    get_user(hblue, blue) ||
+		    (transp && get_user(htransp, transp)))
+			return -EFAULT;
+		if (info->fbops->fb_setcolreg(start++,
+					      hred, hgreen, hblue, htransp,
+					      info))
+			return 0;
+		if (transp)
+			transp++;
+	}
+	return 0;
+}
+
+/**
+ *	fb_default_cmap - get default colormap
+ *	@len: size of palette for a depth
+ *
+ *	Gets the default colormap for a specific screen depth.  @len
+ *	is the size of the palette for a particular screen depth.
+ *
+ *	Returns pointer to a frame buffer colormap structure.
+ *
+ */
+
+struct fb_cmap *fb_default_cmap(int len)
+{
+    if (len <= 2)
+	return &default_2_colors;
+    if (len <= 4)
+	return &default_4_colors;
+    if (len <= 8)
+	return &default_8_colors;
+    return &default_16_colors;
+}
+
+
+/**
+ *	fb_invert_cmaps - invert all defaults colormaps
+ *
+ *	Invert all default colormaps.
+ *
+ */
+
+void fb_invert_cmaps(void)
+{
+    u_int i;
+
+    for (i = 0; i < 2; i++) {
+	red2[i] = ~red2[i];
+	green2[i] = ~green2[i];
+	blue2[i] = ~blue2[i];
+    }
+    for (i = 0; i < 4; i++) {
+	red4[i] = ~red4[i];
+	green4[i] = ~green4[i];
+	blue4[i] = ~blue4[i];
+    }
+    for (i = 0; i < 8; i++) {
+	red8[i] = ~red8[i];
+	green8[i] = ~green8[i];
+	blue8[i] = ~blue8[i];
+    }
+    for (i = 0; i < 16; i++) {
+	red16[i] = ~red16[i];
+	green16[i] = ~green16[i];
+	blue16[i] = ~blue16[i];
+    }
+}
+
+
+    /*
+     *  Visible symbols for modules
+     */
+
+EXPORT_SYMBOL(fb_alloc_cmap);
+EXPORT_SYMBOL(fb_dealloc_cmap);
+EXPORT_SYMBOL(fb_copy_cmap);
+EXPORT_SYMBOL(fb_set_cmap);
+EXPORT_SYMBOL(fb_default_cmap);
+EXPORT_SYMBOL(fb_invert_cmaps);
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
new file mode 100644
index 0000000..25f460c
--- /dev/null
+++ b/drivers/video/fbmem.c
@@ -0,0 +1,1371 @@
+/*
+ *  linux/drivers/video/fbmem.c
+ *
+ *  Copyright (C) 1994 Martin Schaller
+ *
+ *	2001 - Documented with DocBook
+ *	- Brad Douglas <brad@neruo.com>
+ *
+ * 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/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/tty.h>
+#include <linux/init.h>
+#include <linux/linux_logo.h>
+#include <linux/proc_fs.h>
+#include <linux/console.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+#include <linux/devfs_fs_kernel.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/efi.h>
+
+#if defined(__mc68000__) || defined(CONFIG_APUS)
+#include <asm/setup.h>
+#endif
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#include <linux/fb.h>
+
+    /*
+     *  Frame buffer device initialization and setup routines
+     */
+
+#define FBPIXMAPSIZE	(1024 * 8)
+
+static struct notifier_block *fb_notifier_list;
+struct fb_info *registered_fb[FB_MAX];
+int num_registered_fb;
+
+/*
+ * Helpers
+ */
+
+int fb_get_color_depth(struct fb_var_screeninfo *var)
+{
+	if (var->green.length == var->blue.length &&
+	    var->green.length == var->red.length &&
+	    !var->green.offset && !var->blue.offset &&
+	    !var->red.offset)
+		return var->green.length;
+	else
+		return (var->green.length + var->red.length +
+			var->blue.length);
+}
+EXPORT_SYMBOL(fb_get_color_depth);
+
+/*
+ * Drawing helpers.
+ */
+void fb_iomove_buf_aligned(struct fb_info *info, struct fb_pixmap *buf,
+			   u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch,
+			   u32 height)
+{
+	int i;
+
+	for (i = height; i--; ) {
+		buf->outbuf(info, dst, src, s_pitch);
+		src += s_pitch;
+		dst += d_pitch;
+	}
+}
+
+void fb_sysmove_buf_aligned(struct fb_info *info, struct fb_pixmap *buf,
+			    u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch,
+			    u32 height)
+{
+	int i, j;
+
+	for (i = height; i--; ) {
+		for (j = 0; j < s_pitch; j++)
+			dst[j] = src[j];
+		src += s_pitch;
+		dst += d_pitch;
+	}
+}
+
+void fb_iomove_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf,
+			     u8 *dst, u32 d_pitch, u8 *src, u32 idx,
+			     u32 height, u32 shift_high, u32 shift_low,
+			     u32 mod)
+{
+	u8 mask = (u8) (0xfff << shift_high), tmp;
+	int i, j;
+
+	for (i = height; i--; ) {
+		for (j = 0; j < idx; j++) {
+			tmp = buf->inbuf(info, dst+j);
+			tmp &= mask;
+			tmp |= *src >> shift_low;
+			buf->outbuf(info, dst+j, &tmp, 1);
+			tmp = *src << shift_high;
+			buf->outbuf(info, dst+j+1, &tmp, 1);
+			src++;
+		}
+		tmp = buf->inbuf(info, dst+idx);
+		tmp &= mask;
+		tmp |= *src >> shift_low;
+		buf->outbuf(info, dst+idx, &tmp, 1);
+		if (shift_high < mod) {
+			tmp = *src << shift_high;
+			buf->outbuf(info, dst+idx+1, &tmp, 1);
+		}	
+		src++;
+		dst += d_pitch;
+	}
+}
+
+void fb_sysmove_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf,
+			      u8 *dst, u32 d_pitch, u8 *src, u32 idx,
+			      u32 height, u32 shift_high, u32 shift_low,
+			      u32 mod)
+{
+	u8 mask = (u8) (0xfff << shift_high), tmp;
+	int i, j;
+
+	for (i = height; i--; ) {
+		for (j = 0; j < idx; j++) {
+			tmp = dst[j];
+			tmp &= mask;
+			tmp |= *src >> shift_low;
+			dst[j] = tmp;
+			tmp = *src << shift_high;
+			dst[j+1] = tmp;
+			src++;
+		}
+		tmp = dst[idx];
+		tmp &= mask;
+		tmp |= *src >> shift_low;
+		dst[idx] = tmp;
+		if (shift_high < mod) {
+			tmp = *src << shift_high;
+			dst[idx+1] = tmp;
+		}
+		src++;
+		dst += d_pitch;
+	}
+}
+
+/*
+ * we need to lock this section since fb_cursor
+ * may use fb_imageblit()
+ */
+char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size)
+{
+	u32 align = buf->buf_align - 1, offset;
+	char *addr = buf->addr;
+
+	/* If IO mapped, we need to sync before access, no sharing of
+	 * the pixmap is done
+	 */
+	if (buf->flags & FB_PIXMAP_IO) {
+		if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))
+			info->fbops->fb_sync(info);
+		return addr;
+	}
+
+	/* See if we fit in the remaining pixmap space */
+	offset = buf->offset + align;
+	offset &= ~align;
+	if (offset + size > buf->size) {
+		/* We do not fit. In order to be able to re-use the buffer,
+		 * we must ensure no asynchronous DMA'ing or whatever operation
+		 * is in progress, we sync for that.
+		 */
+		if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))
+			info->fbops->fb_sync(info);
+		offset = 0;
+	}
+	buf->offset = offset + size;
+	addr += offset;
+
+	return addr;
+}
+
+#ifdef CONFIG_LOGO
+#include <linux/linux_logo.h>
+
+static inline unsigned safe_shift(unsigned d, int n)
+{
+	return n < 0 ? d >> -n : d << n;
+}
+
+static void fb_set_logocmap(struct fb_info *info,
+				   const struct linux_logo *logo)
+{
+	struct fb_cmap palette_cmap;
+	u16 palette_green[16];
+	u16 palette_blue[16];
+	u16 palette_red[16];
+	int i, j, n;
+	const unsigned char *clut = logo->clut;
+
+	palette_cmap.start = 0;
+	palette_cmap.len = 16;
+	palette_cmap.red = palette_red;
+	palette_cmap.green = palette_green;
+	palette_cmap.blue = palette_blue;
+	palette_cmap.transp = NULL;
+
+	for (i = 0; i < logo->clutsize; i += n) {
+		n = logo->clutsize - i;
+		/* palette_cmap provides space for only 16 colors at once */
+		if (n > 16)
+			n = 16;
+		palette_cmap.start = 32 + i;
+		palette_cmap.len = n;
+		for (j = 0; j < n; ++j) {
+			palette_cmap.red[j] = clut[0] << 8 | clut[0];
+			palette_cmap.green[j] = clut[1] << 8 | clut[1];
+			palette_cmap.blue[j] = clut[2] << 8 | clut[2];
+			clut += 3;
+		}
+		fb_set_cmap(&palette_cmap, info);
+	}
+}
+
+static void  fb_set_logo_truepalette(struct fb_info *info,
+					    const struct linux_logo *logo,
+					    u32 *palette)
+{
+	unsigned char mask[9] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
+	unsigned char redmask, greenmask, bluemask;
+	int redshift, greenshift, blueshift;
+	int i;
+	const unsigned char *clut = logo->clut;
+
+	/*
+	 * We have to create a temporary palette since console palette is only
+	 * 16 colors long.
+	 */
+	/* Bug: Doesn't obey msb_right ... (who needs that?) */
+	redmask   = mask[info->var.red.length   < 8 ? info->var.red.length   : 8];
+	greenmask = mask[info->var.green.length < 8 ? info->var.green.length : 8];
+	bluemask  = mask[info->var.blue.length  < 8 ? info->var.blue.length  : 8];
+	redshift   = info->var.red.offset   - (8 - info->var.red.length);
+	greenshift = info->var.green.offset - (8 - info->var.green.length);
+	blueshift  = info->var.blue.offset  - (8 - info->var.blue.length);
+
+	for ( i = 0; i < logo->clutsize; i++) {
+		palette[i+32] = (safe_shift((clut[0] & redmask), redshift) |
+				 safe_shift((clut[1] & greenmask), greenshift) |
+				 safe_shift((clut[2] & bluemask), blueshift));
+		clut += 3;
+	}
+}
+
+static void fb_set_logo_directpalette(struct fb_info *info,
+					     const struct linux_logo *logo,
+					     u32 *palette)
+{
+	int redshift, greenshift, blueshift;
+	int i;
+
+	redshift = info->var.red.offset;
+	greenshift = info->var.green.offset;
+	blueshift = info->var.blue.offset;
+
+	for (i = 32; i < logo->clutsize; i++)
+		palette[i] = i << redshift | i << greenshift | i << blueshift;
+}
+
+static void fb_set_logo(struct fb_info *info,
+			       const struct linux_logo *logo, u8 *dst,
+			       int depth)
+{
+	int i, j, k, fg = 1;
+	const u8 *src = logo->data;
+	u8 d, xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0;
+
+	if (fb_get_color_depth(&info->var) == 3)
+		fg = 7;
+
+	switch (depth) {
+	case 4:
+		for (i = 0; i < logo->height; i++)
+			for (j = 0; j < logo->width; src++) {
+				*dst++ = *src >> 4;
+				j++;
+				if (j < logo->width) {
+					*dst++ = *src & 0x0f;
+					j++;
+				}
+			}
+		break;
+	case 1:
+		for (i = 0; i < logo->height; i++) {
+			for (j = 0; j < logo->width; src++) {
+				d = *src ^ xor;
+				for (k = 7; k >= 0; k--) {
+					*dst++ = ((d >> k) & 1) ? fg : 0;
+					j++;
+				}
+			}
+		}
+		break;
+	}
+}
+
+/*
+ * Three (3) kinds of logo maps exist.  linux_logo_clut224 (>16 colors),
+ * linux_logo_vga16 (16 colors) and linux_logo_mono (2 colors).  Depending on
+ * the visual format and color depth of the framebuffer, the DAC, the
+ * pseudo_palette, and the logo data will be adjusted accordingly.
+ *
+ * Case 1 - linux_logo_clut224:
+ * Color exceeds the number of console colors (16), thus we set the hardware DAC
+ * using fb_set_cmap() appropriately.  The "needs_cmapreset"  flag will be set.
+ *
+ * For visuals that require color info from the pseudo_palette, we also construct
+ * one for temporary use. The "needs_directpalette" or "needs_truepalette" flags
+ * will be set.
+ *
+ * Case 2 - linux_logo_vga16:
+ * The number of colors just matches the console colors, thus there is no need
+ * to set the DAC or the pseudo_palette.  However, the bitmap is packed, ie,
+ * each byte contains color information for two pixels (upper and lower nibble).
+ * To be consistent with fb_imageblit() usage, we therefore separate the two
+ * nibbles into separate bytes. The "depth" flag will be set to 4.
+ *
+ * Case 3 - linux_logo_mono:
+ * This is similar with Case 2.  Each byte contains information for 8 pixels.
+ * We isolate each bit and expand each into a byte. The "depth" flag will
+ * be set to 1.
+ */
+static struct logo_data {
+	int depth;
+	int needs_directpalette;
+	int needs_truepalette;
+	int needs_cmapreset;
+	const struct linux_logo *logo;
+} fb_logo;
+
+int fb_prepare_logo(struct fb_info *info)
+{
+	int depth = fb_get_color_depth(&info->var);
+
+	memset(&fb_logo, 0, sizeof(struct logo_data));
+
+	if (info->flags & FBINFO_MISC_TILEBLITTING)
+		return 0;
+
+	if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+		depth = info->var.blue.length;
+		if (info->var.red.length < depth)
+			depth = info->var.red.length;
+		if (info->var.green.length < depth)
+			depth = info->var.green.length;
+	}
+
+	if (depth >= 8) {
+		switch (info->fix.visual) {
+		case FB_VISUAL_TRUECOLOR:
+			fb_logo.needs_truepalette = 1;
+			break;
+		case FB_VISUAL_DIRECTCOLOR:
+			fb_logo.needs_directpalette = 1;
+			fb_logo.needs_cmapreset = 1;
+			break;
+		case FB_VISUAL_PSEUDOCOLOR:
+			fb_logo.needs_cmapreset = 1;
+			break;
+		}
+	}
+
+	/* Return if no suitable logo was found */
+	fb_logo.logo = fb_find_logo(depth);
+	
+	if (!fb_logo.logo || fb_logo.logo->height > info->var.yres) {
+		fb_logo.logo = NULL;
+		return 0;
+	}
+	/* What depth we asked for might be different from what we get */
+	if (fb_logo.logo->type == LINUX_LOGO_CLUT224)
+		fb_logo.depth = 8;
+	else if (fb_logo.logo->type == LINUX_LOGO_VGA16)
+		fb_logo.depth = 4;
+	else
+		fb_logo.depth = 1;		
+	return fb_logo.logo->height;
+}
+
+int fb_show_logo(struct fb_info *info)
+{
+	u32 *palette = NULL, *saved_pseudo_palette = NULL;
+	unsigned char *logo_new = NULL;
+	struct fb_image image;
+	int x;
+
+	/* Return if the frame buffer is not mapped or suspended */
+	if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING)
+		return 0;
+
+	image.depth = 8;
+	image.data = fb_logo.logo->data;
+
+	if (fb_logo.needs_cmapreset)
+		fb_set_logocmap(info, fb_logo.logo);
+
+	if (fb_logo.needs_truepalette || 
+	    fb_logo.needs_directpalette) {
+		palette = kmalloc(256 * 4, GFP_KERNEL);
+		if (palette == NULL)
+			return 0;
+
+		if (fb_logo.needs_truepalette)
+			fb_set_logo_truepalette(info, fb_logo.logo, palette);
+		else
+			fb_set_logo_directpalette(info, fb_logo.logo, palette);
+
+		saved_pseudo_palette = info->pseudo_palette;
+		info->pseudo_palette = palette;
+	}
+
+	if (fb_logo.depth <= 4) {
+		logo_new = kmalloc(fb_logo.logo->width * fb_logo.logo->height, 
+				   GFP_KERNEL);
+		if (logo_new == NULL) {
+			kfree(palette);
+			if (saved_pseudo_palette)
+				info->pseudo_palette = saved_pseudo_palette;
+			return 0;
+		}
+		image.data = logo_new;
+		fb_set_logo(info, fb_logo.logo, logo_new, fb_logo.depth);
+	}
+
+	image.width = fb_logo.logo->width;
+	image.height = fb_logo.logo->height;
+	image.dy = 0;
+
+	for (x = 0; x < num_online_cpus() * (fb_logo.logo->width + 8) &&
+	     x <= info->var.xres-fb_logo.logo->width; x += (fb_logo.logo->width + 8)) {
+		image.dx = x;
+		info->fbops->fb_imageblit(info, &image);
+	}
+	
+	kfree(palette);
+	if (saved_pseudo_palette != NULL)
+		info->pseudo_palette = saved_pseudo_palette;
+	kfree(logo_new);
+	return fb_logo.logo->height;
+}
+#else
+int fb_prepare_logo(struct fb_info *info) { return 0; }
+int fb_show_logo(struct fb_info *info) { return 0; }
+#endif /* CONFIG_LOGO */
+
+static int fbmem_read_proc(char *buf, char **start, off_t offset,
+			   int len, int *eof, void *private)
+{
+	struct fb_info **fi;
+	int clen;
+
+	clen = 0;
+	for (fi = registered_fb; fi < &registered_fb[FB_MAX] && len < 4000; fi++)
+		if (*fi)
+			clen += sprintf(buf + clen, "%d %s\n",
+				        (*fi)->node,
+				        (*fi)->fix.id);
+	*start = buf + offset;
+	if (clen > offset)
+		clen -= offset;
+	else
+		clen = 0;
+	return clen < len ? clen : len;
+}
+
+static ssize_t
+fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+	unsigned long p = *ppos;
+	struct inode *inode = file->f_dentry->d_inode;
+	int fbidx = iminor(inode);
+	struct fb_info *info = registered_fb[fbidx];
+	u32 *buffer, *dst;
+	u32 __iomem *src;
+	int c, i, cnt = 0, err = 0;
+	unsigned long total_size;
+
+	if (!info || ! info->screen_base)
+		return -ENODEV;
+
+	if (info->state != FBINFO_STATE_RUNNING)
+		return -EPERM;
+
+	if (info->fbops->fb_read)
+		return info->fbops->fb_read(file, buf, count, ppos);
+	
+	total_size = info->screen_size;
+	if (total_size == 0)
+		total_size = info->fix.smem_len;
+
+	if (p >= total_size)
+	    return 0;
+	if (count >= total_size)
+	    count = total_size;
+	if (count + p > total_size)
+		count = total_size - p;
+
+	cnt = 0;
+	buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
+			 GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	src = (u32 __iomem *) (info->screen_base + p);
+
+	if (info->fbops->fb_sync)
+		info->fbops->fb_sync(info);
+
+	while (count) {
+		c  = (count > PAGE_SIZE) ? PAGE_SIZE : count;
+		dst = buffer;
+		for (i = c >> 2; i--; )
+			*dst++ = fb_readl(src++);
+		if (c & 3) {
+			u8 *dst8 = (u8 *) dst;
+			u8 __iomem *src8 = (u8 __iomem *) src;
+
+			for (i = c & 3; i--;)
+				*dst8++ = fb_readb(src8++);
+
+			src = (u32 __iomem *) src8;
+		}
+
+		if (copy_to_user(buf, buffer, c)) {
+			err = -EFAULT;
+			break;
+		}
+		*ppos += c;
+		buf += c;
+		cnt += c;
+		count -= c;
+	}
+
+	kfree(buffer);
+	return (err) ? err : cnt;
+}
+
+static ssize_t
+fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+{
+	unsigned long p = *ppos;
+	struct inode *inode = file->f_dentry->d_inode;
+	int fbidx = iminor(inode);
+	struct fb_info *info = registered_fb[fbidx];
+	u32 *buffer, *src;
+	u32 __iomem *dst;
+	int c, i, cnt = 0, err;
+	unsigned long total_size;
+
+	if (!info || !info->screen_base)
+		return -ENODEV;
+
+	if (info->state != FBINFO_STATE_RUNNING)
+		return -EPERM;
+
+	if (info->fbops->fb_write)
+		return info->fbops->fb_write(file, buf, count, ppos);
+	
+	total_size = info->screen_size;
+	if (total_size == 0)
+		total_size = info->fix.smem_len;
+
+	if (p > total_size)
+	    return -ENOSPC;
+	if (count >= total_size)
+	    count = total_size;
+	err = 0;
+	if (count + p > total_size) {
+	    count = total_size - p;
+	    err = -ENOSPC;
+	}
+	cnt = 0;
+	buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
+			 GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	dst = (u32 __iomem *) (info->screen_base + p);
+
+	if (info->fbops->fb_sync)
+		info->fbops->fb_sync(info);
+
+	while (count) {
+		c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
+		src = buffer;
+		if (copy_from_user(src, buf, c)) {
+			err = -EFAULT;
+			break;
+		}
+		for (i = c >> 2; i--; )
+			fb_writel(*src++, dst++);
+		if (c & 3) {
+			u8 *src8 = (u8 *) src;
+			u8 __iomem *dst8 = (u8 __iomem *) dst;
+
+			for (i = c & 3; i--; )
+				fb_writeb(*src8++, dst8++);
+
+			dst = (u32 __iomem *) dst8;
+		}
+		*ppos += c;
+		buf += c;
+		cnt += c;
+		count -= c;
+	}
+	kfree(buffer);
+
+	return (err) ? err : cnt;
+}
+
+#ifdef CONFIG_KMOD
+static void try_to_load(int fb)
+{
+	request_module("fb%d", fb);
+}
+#endif /* CONFIG_KMOD */
+
+int
+fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var)
+{
+        int xoffset = var->xoffset;
+        int yoffset = var->yoffset;
+        int err;
+
+        if (xoffset < 0 || yoffset < 0 || !info->fbops->fb_pan_display ||
+            xoffset + info->var.xres > info->var.xres_virtual ||
+            yoffset + info->var.yres > info->var.yres_virtual)
+                return -EINVAL;
+	if ((err = info->fbops->fb_pan_display(var, info)))
+		return err;
+        info->var.xoffset = var->xoffset;
+        info->var.yoffset = var->yoffset;
+        if (var->vmode & FB_VMODE_YWRAP)
+                info->var.vmode |= FB_VMODE_YWRAP;
+        else
+                info->var.vmode &= ~FB_VMODE_YWRAP;
+        return 0;
+}
+
+int
+fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
+{
+	int err;
+
+	if (var->activate & FB_ACTIVATE_INV_MODE) {
+		struct fb_videomode mode1, mode2;
+		int ret = 0;
+
+		fb_var_to_videomode(&mode1, var);
+		fb_var_to_videomode(&mode2, &info->var);
+		/* make sure we don't delete the videomode of current var */
+		ret = fb_mode_is_equal(&mode1, &mode2);
+
+		if (!ret) {
+		    struct fb_event event;
+
+		    event.info = info;
+		    event.data = &mode1;
+		    ret = notifier_call_chain(&fb_notifier_list,
+					      FB_EVENT_MODE_DELETE, &event);
+		}
+
+		if (!ret)
+		    fb_delete_videomode(&mode1, &info->modelist);
+
+		return ret;
+	}
+
+	if ((var->activate & FB_ACTIVATE_FORCE) ||
+	    memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) {
+		if (!info->fbops->fb_check_var) {
+			*var = info->var;
+			return 0;
+		}
+
+		if ((err = info->fbops->fb_check_var(var, info)))
+			return err;
+
+		if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+			struct fb_videomode mode;
+			int err = 0;
+
+			info->var = *var;
+			if (info->fbops->fb_set_par)
+				info->fbops->fb_set_par(info);
+
+			fb_pan_display(info, &info->var);
+
+			fb_set_cmap(&info->cmap, info);
+
+			fb_var_to_videomode(&mode, &info->var);
+
+			if (info->modelist.prev && info->modelist.next &&
+			    !list_empty(&info->modelist))
+				err = fb_add_videomode(&mode, &info->modelist);
+
+			if (!err && info->flags & FBINFO_MISC_USEREVENT) {
+				struct fb_event event;
+
+				info->flags &= ~FBINFO_MISC_USEREVENT;
+				event.info = info;
+				notifier_call_chain(&fb_notifier_list,
+						    FB_EVENT_MODE_CHANGE,
+						    &event);
+			}
+		}
+	}
+	return 0;
+}
+
+int
+fb_blank(struct fb_info *info, int blank)
+{	
+ 	int ret = -EINVAL;
+
+ 	if (blank > FB_BLANK_POWERDOWN)
+ 		blank = FB_BLANK_POWERDOWN;
+
+	if (info->fbops->fb_blank)
+ 		ret = info->fbops->fb_blank(blank, info);
+
+ 	if (!ret) {
+		struct fb_event event;
+
+		event.info = info;
+		event.data = &blank;
+		notifier_call_chain(&fb_notifier_list, FB_EVENT_BLANK, &event);
+	}
+
+ 	return ret;
+}
+
+static int 
+fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	 unsigned long arg)
+{
+	int fbidx = iminor(inode);
+	struct fb_info *info = registered_fb[fbidx];
+	struct fb_ops *fb = info->fbops;
+	struct fb_var_screeninfo var;
+	struct fb_fix_screeninfo fix;
+	struct fb_con2fbmap con2fb;
+	struct fb_cmap_user cmap;
+	struct fb_event event;
+	void __user *argp = (void __user *)arg;
+	int i;
+	
+	if (!fb)
+		return -ENODEV;
+	switch (cmd) {
+	case FBIOGET_VSCREENINFO:
+		return copy_to_user(argp, &info->var,
+				    sizeof(var)) ? -EFAULT : 0;
+	case FBIOPUT_VSCREENINFO:
+		if (copy_from_user(&var, argp, sizeof(var)))
+			return -EFAULT;
+		acquire_console_sem();
+		info->flags |= FBINFO_MISC_USEREVENT;
+		i = fb_set_var(info, &var);
+		info->flags &= ~FBINFO_MISC_USEREVENT;
+		release_console_sem();
+		if (i) return i;
+		if (copy_to_user(argp, &var, sizeof(var)))
+			return -EFAULT;
+		return 0;
+	case FBIOGET_FSCREENINFO:
+		return copy_to_user(argp, &info->fix,
+				    sizeof(fix)) ? -EFAULT : 0;
+	case FBIOPUTCMAP:
+		if (copy_from_user(&cmap, argp, sizeof(cmap)))
+			return -EFAULT;
+		return (fb_set_user_cmap(&cmap, info));
+	case FBIOGETCMAP:
+		if (copy_from_user(&cmap, argp, sizeof(cmap)))
+			return -EFAULT;
+		return fb_cmap_to_user(&info->cmap, &cmap);
+	case FBIOPAN_DISPLAY:
+		if (copy_from_user(&var, argp, sizeof(var)))
+			return -EFAULT;
+		acquire_console_sem();
+		i = fb_pan_display(info, &var);
+		release_console_sem();
+		if (i)
+			return i;
+		if (copy_to_user(argp, &var, sizeof(var)))
+			return -EFAULT;
+		return 0;
+	case FBIO_CURSOR:
+		return -EINVAL;
+	case FBIOGET_CON2FBMAP:
+		if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
+			return -EFAULT;
+		if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
+		    return -EINVAL;
+		con2fb.framebuffer = -1;
+		event.info = info;
+		event.data = &con2fb;
+		notifier_call_chain(&fb_notifier_list,
+				    FB_EVENT_GET_CONSOLE_MAP, &event);
+		return copy_to_user(argp, &con2fb,
+				    sizeof(con2fb)) ? -EFAULT : 0;
+	case FBIOPUT_CON2FBMAP:
+		if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
+			return - EFAULT;
+		if (con2fb.console < 0 || con2fb.console > MAX_NR_CONSOLES)
+		    return -EINVAL;
+		if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)
+		    return -EINVAL;
+#ifdef CONFIG_KMOD
+		if (!registered_fb[con2fb.framebuffer])
+		    try_to_load(con2fb.framebuffer);
+#endif /* CONFIG_KMOD */
+		if (!registered_fb[con2fb.framebuffer])
+		    return -EINVAL;
+		event.info = info;
+		event.data = &con2fb;
+		return notifier_call_chain(&fb_notifier_list,
+					   FB_EVENT_SET_CONSOLE_MAP,
+					   &event);
+	case FBIOBLANK:
+		acquire_console_sem();
+		info->flags |= FBINFO_MISC_USEREVENT;
+		i = fb_blank(info, arg);
+		info->flags &= ~FBINFO_MISC_USEREVENT;
+		release_console_sem();
+		return i;
+	default:
+		if (fb->fb_ioctl == NULL)
+			return -EINVAL;
+		return fb->fb_ioctl(inode, file, cmd, arg, info);
+	}
+}
+
+#ifdef CONFIG_COMPAT
+static long
+fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int fbidx = iminor(file->f_dentry->d_inode);
+	struct fb_info *info = registered_fb[fbidx];
+	struct fb_ops *fb = info->fbops;
+	long ret;
+
+	if (fb->fb_compat_ioctl == NULL)
+		return -ENOIOCTLCMD;
+	lock_kernel();
+	ret = fb->fb_compat_ioctl(file, cmd, arg, info);
+	unlock_kernel();
+	return ret;
+}
+#endif
+
+static int 
+fb_mmap(struct file *file, struct vm_area_struct * vma)
+{
+	int fbidx = iminor(file->f_dentry->d_inode);
+	struct fb_info *info = registered_fb[fbidx];
+	struct fb_ops *fb = info->fbops;
+	unsigned long off;
+#if !defined(__sparc__) || defined(__sparc_v9__)
+	unsigned long start;
+	u32 len;
+#endif
+
+	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+		return -EINVAL;
+	off = vma->vm_pgoff << PAGE_SHIFT;
+	if (!fb)
+		return -ENODEV;
+	if (fb->fb_mmap) {
+		int res;
+		lock_kernel();
+		res = fb->fb_mmap(info, file, vma);
+		unlock_kernel();
+		return res;
+	}
+
+#if defined(__sparc__) && !defined(__sparc_v9__)
+	/* Should never get here, all fb drivers should have their own
+	   mmap routines */
+	return -EINVAL;
+#else
+	/* !sparc32... */
+	lock_kernel();
+
+	/* frame buffer memory */
+	start = info->fix.smem_start;
+	len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
+	if (off >= len) {
+		/* memory mapped io */
+		off -= len;
+		if (info->var.accel_flags) {
+			unlock_kernel();
+			return -EINVAL;
+		}
+		start = info->fix.mmio_start;
+		len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
+	}
+	unlock_kernel();
+	start &= PAGE_MASK;
+	if ((vma->vm_end - vma->vm_start + off) > len)
+		return -EINVAL;
+	off += start;
+	vma->vm_pgoff = off >> PAGE_SHIFT;
+	/* This is an IO map - tell maydump to skip this VMA */
+	vma->vm_flags |= VM_IO | VM_RESERVED;
+#if defined(__sparc_v9__)
+	if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+				vma->vm_end - vma->vm_start, vma->vm_page_prot))
+		return -EAGAIN;
+#else
+#if defined(__mc68000__)
+#if defined(CONFIG_SUN3)
+	pgprot_val(vma->vm_page_prot) |= SUN3_PAGE_NOCACHE;
+#elif defined(CONFIG_MMU)
+	if (CPU_IS_020_OR_030)
+		pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030;
+	if (CPU_IS_040_OR_060) {
+		pgprot_val(vma->vm_page_prot) &= _CACHEMASK040;
+		/* Use no-cache mode, serialized */
+		pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE_S;
+	}
+#endif
+#elif defined(__powerpc__)
+	vma->vm_page_prot = phys_mem_access_prot(file, off,
+						 vma->vm_end - vma->vm_start,
+						 vma->vm_page_prot);
+#elif defined(__alpha__)
+	/* Caching is off in the I/O space quadrant by design.  */
+#elif defined(__i386__) || defined(__x86_64__)
+	if (boot_cpu_data.x86 > 3)
+		pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+#elif defined(__mips__)
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+#elif defined(__hppa__)
+	pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
+#elif defined(__arm__) || defined(__sh__) || defined(__m32r__)
+	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+#elif defined(__ia64__)
+	if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start))
+		vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+	else
+		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+#else
+#warning What do we have to do here??
+#endif
+	if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+			     vma->vm_end - vma->vm_start, vma->vm_page_prot))
+		return -EAGAIN;
+#endif /* !__sparc_v9__ */
+	return 0;
+#endif /* !sparc32 */
+}
+
+static int
+fb_open(struct inode *inode, struct file *file)
+{
+	int fbidx = iminor(inode);
+	struct fb_info *info;
+	int res = 0;
+
+	if (fbidx >= FB_MAX)
+		return -ENODEV;
+#ifdef CONFIG_KMOD
+	if (!(info = registered_fb[fbidx]))
+		try_to_load(fbidx);
+#endif /* CONFIG_KMOD */
+	if (!(info = registered_fb[fbidx]))
+		return -ENODEV;
+	if (!try_module_get(info->fbops->owner))
+		return -ENODEV;
+	if (info->fbops->fb_open) {
+		res = info->fbops->fb_open(info,1);
+		if (res)
+			module_put(info->fbops->owner);
+	}
+	return res;
+}
+
+static int 
+fb_release(struct inode *inode, struct file *file)
+{
+	int fbidx = iminor(inode);
+	struct fb_info *info;
+
+	lock_kernel();
+	info = registered_fb[fbidx];
+	if (info->fbops->fb_release)
+		info->fbops->fb_release(info,1);
+	module_put(info->fbops->owner);
+	unlock_kernel();
+	return 0;
+}
+
+static struct file_operations fb_fops = {
+	.owner =	THIS_MODULE,
+	.read =		fb_read,
+	.write =	fb_write,
+	.ioctl =	fb_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = fb_compat_ioctl,
+#endif
+	.mmap =		fb_mmap,
+	.open =		fb_open,
+	.release =	fb_release,
+#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
+	.get_unmapped_area = get_fb_unmapped_area,
+#endif
+};
+
+static struct class_simple *fb_class;
+
+/**
+ *	register_framebuffer - registers a frame buffer device
+ *	@fb_info: frame buffer info structure
+ *
+ *	Registers a frame buffer device @fb_info.
+ *
+ *	Returns negative errno on error, or zero for success.
+ *
+ */
+
+int
+register_framebuffer(struct fb_info *fb_info)
+{
+	int i;
+	struct fb_event event;
+
+	if (num_registered_fb == FB_MAX)
+		return -ENXIO;
+	num_registered_fb++;
+	for (i = 0 ; i < FB_MAX; i++)
+		if (!registered_fb[i])
+			break;
+	fb_info->node = i;
+
+	fb_info->class_device = class_simple_device_add(fb_class, MKDEV(FB_MAJOR, i),
+				    fb_info->device, "fb%d", i);
+	if (IS_ERR(fb_info->class_device)) {
+		/* Not fatal */
+		printk(KERN_WARNING "Unable to create class_device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->class_device));
+		fb_info->class_device = NULL;
+	} else
+		fb_init_class_device(fb_info);
+
+	if (fb_info->pixmap.addr == NULL) {
+		fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
+		if (fb_info->pixmap.addr) {
+			fb_info->pixmap.size = FBPIXMAPSIZE;
+			fb_info->pixmap.buf_align = 1;
+			fb_info->pixmap.scan_align = 1;
+			fb_info->pixmap.access_align = 4;
+			fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
+		}
+	}	
+	fb_info->pixmap.offset = 0;
+
+	if (!fb_info->modelist.prev ||
+	    !fb_info->modelist.next ||
+	    list_empty(&fb_info->modelist)) {
+	        struct fb_videomode mode;
+
+		INIT_LIST_HEAD(&fb_info->modelist);
+		fb_var_to_videomode(&mode, &fb_info->var);
+		fb_add_videomode(&mode, &fb_info->modelist);
+	}
+
+	registered_fb[i] = fb_info;
+
+	devfs_mk_cdev(MKDEV(FB_MAJOR, i),
+			S_IFCHR | S_IRUGO | S_IWUGO, "fb/%d", i);
+	event.info = fb_info;
+	notifier_call_chain(&fb_notifier_list,
+			    FB_EVENT_FB_REGISTERED, &event);
+	return 0;
+}
+
+
+/**
+ *	unregister_framebuffer - releases a frame buffer device
+ *	@fb_info: frame buffer info structure
+ *
+ *	Unregisters a frame buffer device @fb_info.
+ *
+ *	Returns negative errno on error, or zero for success.
+ *
+ */
+
+int
+unregister_framebuffer(struct fb_info *fb_info)
+{
+	int i;
+
+	i = fb_info->node;
+	if (!registered_fb[i])
+		return -EINVAL;
+	devfs_remove("fb/%d", i);
+
+	if (fb_info->pixmap.addr && (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
+		kfree(fb_info->pixmap.addr);
+	fb_destroy_modelist(&fb_info->modelist);
+	registered_fb[i]=NULL;
+	num_registered_fb--;
+	fb_cleanup_class_device(fb_info);
+	class_simple_device_remove(MKDEV(FB_MAJOR, i));
+	return 0;
+}
+
+/**
+ *	fb_register_client - register a client notifier
+ *	@nb: notifier block to callback on events
+ */
+int fb_register_client(struct notifier_block *nb)
+{
+	return notifier_chain_register(&fb_notifier_list, nb);
+}
+
+/**
+ *	fb_unregister_client - unregister a client notifier
+ *	@nb: notifier block to callback on events
+ */
+int fb_unregister_client(struct notifier_block *nb)
+{
+	return notifier_chain_unregister(&fb_notifier_list, nb);
+}
+
+/**
+ *	fb_set_suspend - low level driver signals suspend
+ *	@info: framebuffer affected
+ *	@state: 0 = resuming, !=0 = suspending
+ *
+ *	This is meant to be used by low level drivers to
+ * 	signal suspend/resume to the core & clients.
+ *	It must be called with the console semaphore held
+ */
+void fb_set_suspend(struct fb_info *info, int state)
+{
+	struct fb_event event;
+
+	event.info = info;
+	if (state) {
+		notifier_call_chain(&fb_notifier_list, FB_EVENT_SUSPEND, &event);
+		info->state = FBINFO_STATE_SUSPENDED;
+	} else {
+		info->state = FBINFO_STATE_RUNNING;
+		notifier_call_chain(&fb_notifier_list, FB_EVENT_RESUME, &event);
+	}
+}
+
+/**
+ *	fbmem_init - init frame buffer subsystem
+ *
+ *	Initialize the frame buffer subsystem.
+ *
+ *	NOTE: This function is _only_ to be called by drivers/char/mem.c.
+ *
+ */
+
+static int __init
+fbmem_init(void)
+{
+	create_proc_read_entry("fb", 0, NULL, fbmem_read_proc, NULL);
+
+	devfs_mk_dir("fb");
+	if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
+		printk("unable to get major %d for fb devs\n", FB_MAJOR);
+
+	fb_class = class_simple_create(THIS_MODULE, "graphics");
+	if (IS_ERR(fb_class)) {
+		printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));
+		fb_class = NULL;
+	}
+	return 0;
+}
+
+#ifdef MODULE
+module_init(fbmem_init);
+static void __exit
+fbmem_exit(void)
+{
+	class_simple_destroy(fb_class);
+}
+
+module_exit(fbmem_exit);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Framebuffer base");
+#else
+subsys_initcall(fbmem_init);
+#endif
+
+int fb_new_modelist(struct fb_info *info)
+{
+	struct fb_event event;
+	struct fb_var_screeninfo var = info->var;
+	struct list_head *pos, *n;
+	struct fb_modelist *modelist;
+	struct fb_videomode *m, mode;
+	int err = 1;
+
+	list_for_each_safe(pos, n, &info->modelist) {
+		modelist = list_entry(pos, struct fb_modelist, list);
+		m = &modelist->mode;
+		fb_videomode_to_var(&var, m);
+		var.activate = FB_ACTIVATE_TEST;
+		err = fb_set_var(info, &var);
+		fb_var_to_videomode(&mode, &var);
+		if (err || !fb_mode_is_equal(m, &mode)) {
+			list_del(pos);
+			kfree(pos);
+		}
+	}
+
+	err = 1;
+
+	if (!list_empty(&info->modelist)) {
+		event.info = info;
+		err = notifier_call_chain(&fb_notifier_list,
+					   FB_EVENT_NEW_MODELIST,
+					   &event);
+	}
+
+	return err;
+}
+
+static char *video_options[FB_MAX];
+static int ofonly;
+
+/**
+ * fb_get_options - get kernel boot parameters
+ * @name:   framebuffer name as it would appear in
+ *          the boot parameter line
+ *          (video=<name>:<options>)
+ * @option: the option will be stored here
+ *
+ * NOTE: Needed to maintain backwards compatibility
+ */
+int fb_get_options(char *name, char **option)
+{
+	char *opt, *options = NULL;
+	int opt_len, retval = 0;
+	int name_len = strlen(name), i;
+
+	if (name_len && ofonly && strncmp(name, "offb", 4))
+		retval = 1;
+
+	if (name_len && !retval) {
+		for (i = 0; i < FB_MAX; i++) {
+			if (video_options[i] == NULL)
+				continue;
+			opt_len = strlen(video_options[i]);
+			if (!opt_len)
+				continue;
+			opt = video_options[i];
+			if (!strncmp(name, opt, name_len) &&
+			    opt[name_len] == ':')
+				options = opt + name_len + 1;
+		}
+	}
+	if (options && !strncmp(options, "off", 3))
+		retval = 1;
+
+	if (option)
+		*option = options;
+
+	return retval;
+}
+
+
+extern const char *global_mode_option;
+
+/**
+ *	video_setup - process command line options
+ *	@options: string of options
+ *
+ *	Process command line options for frame buffer subsystem.
+ *
+ *	NOTE: This function is a __setup and __init function.
+ *            It only stores the options.  Drivers have to call
+ *            fb_get_options() as necessary.
+ *
+ *	Returns zero.
+ *
+ */
+int __init video_setup(char *options)
+{
+	int i, global = 0;
+
+	if (!options || !*options)
+ 		global = 1;
+
+ 	if (!global && !strncmp(options, "ofonly", 6)) {
+ 		ofonly = 1;
+ 		global = 1;
+ 	}
+
+ 	if (!global && !strstr(options, "fb:")) {
+ 		global_mode_option = options;
+ 		global = 1;
+ 	}
+
+ 	if (!global) {
+ 		for (i = 0; i < FB_MAX; i++) {
+ 			if (video_options[i] == NULL) {
+ 				video_options[i] = options;
+ 				break;
+ 			}
+
+		}
+	}
+
+	return 0;
+}
+__setup("video=", video_setup);
+
+    /*
+     *  Visible symbols for modules
+     */
+
+EXPORT_SYMBOL(register_framebuffer);
+EXPORT_SYMBOL(unregister_framebuffer);
+EXPORT_SYMBOL(num_registered_fb);
+EXPORT_SYMBOL(registered_fb);
+EXPORT_SYMBOL(fb_prepare_logo);
+EXPORT_SYMBOL(fb_show_logo);
+EXPORT_SYMBOL(fb_set_var);
+EXPORT_SYMBOL(fb_blank);
+EXPORT_SYMBOL(fb_pan_display);
+EXPORT_SYMBOL(fb_get_buffer_offset);
+EXPORT_SYMBOL(fb_iomove_buf_unaligned);
+EXPORT_SYMBOL(fb_iomove_buf_aligned);
+EXPORT_SYMBOL(fb_sysmove_buf_unaligned);
+EXPORT_SYMBOL(fb_sysmove_buf_aligned);
+EXPORT_SYMBOL(fb_set_suspend);
+EXPORT_SYMBOL(fb_register_client);
+EXPORT_SYMBOL(fb_unregister_client);
+EXPORT_SYMBOL(fb_get_options);
+EXPORT_SYMBOL(fb_new_modelist);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
new file mode 100644
index 0000000..978def0
--- /dev/null
+++ b/drivers/video/fbmon.c
@@ -0,0 +1,1258 @@
+/*
+ * linux/drivers/video/fbmon.c
+ *
+ * Copyright (C) 2002 James Simmons <jsimmons@users.sf.net>
+ *
+ * Credits:
+ * 
+ * The EDID Parser is a conglomeration from the following sources:
+ *
+ *   1. SciTech SNAP Graphics Architecture
+ *      Copyright (C) 1991-2002 SciTech Software, Inc. All rights reserved.
+ *
+ *   2. XFree86 4.3.0, interpret_edid.c
+ *      Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE>
+ * 
+ *   3. John Fremlin <vii@users.sourceforge.net> and 
+ *      Ani Joshi <ajoshi@unixbox.com>
+ *  
+ * Generalized Timing Formula is derived from:
+ *
+ *      GTF Spreadsheet by Andy Morrish (1/5/97) 
+ *      available at http://www.vesa.org
+ *
+ * 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/tty.h>
+#include <linux/fb.h>
+#include <linux/module.h>
+#ifdef CONFIG_PPC_OF
+#include <linux/pci.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#endif
+#include <video/edid.h>
+#include "edid.h"
+
+/* 
+ * EDID parser
+ */
+
+#undef DEBUG  /* define this for verbose EDID parsing output */
+
+#ifdef DEBUG
+#define DPRINTK(fmt, args...) printk(fmt,## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#define FBMON_FIX_HEADER 1
+#define FBMON_FIX_INPUT  2
+
+#ifdef CONFIG_FB_MODE_HELPERS
+struct broken_edid {
+	u8  manufacturer[4];
+	u32 model;
+	u32 fix;
+};
+
+static struct broken_edid brokendb[] = {
+	/* DEC FR-PCXAV-YZ */
+	{
+		.manufacturer = "DEC",
+		.model        = 0x073a,
+		.fix          = FBMON_FIX_HEADER,
+	},
+	/* ViewSonic PF775a */
+	{
+		.manufacturer = "VSC",
+		.model        = 0x5a44,
+		.fix          = FBMON_FIX_INPUT,
+	},
+};
+
+static const unsigned char edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0x00
+};
+
+static void copy_string(unsigned char *c, unsigned char *s)
+{
+  int i;
+  c = c + 5;
+  for (i = 0; (i < 13 && *c != 0x0A); i++)
+    *(s++) = *(c++);
+  *s = 0;
+  while (i-- && (*--s == 0x20)) *s = 0;
+}
+
+static int check_edid(unsigned char *edid)
+{
+	unsigned char *block = edid + ID_MANUFACTURER_NAME, manufacturer[4];
+	unsigned char *b;
+	u32 model;
+	int i, fix = 0, ret = 0;
+
+	manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@';
+	manufacturer[1] = ((block[0] & 0x03) << 3) +
+		((block[1] & 0xe0) >> 5) + '@';
+	manufacturer[2] = (block[1] & 0x1f) + '@';
+	manufacturer[3] = 0;
+	model = block[2] + (block[3] << 8);
+
+	for (i = 0; i < ARRAY_SIZE(brokendb); i++) {
+		if (!strncmp(manufacturer, brokendb[i].manufacturer, 4) &&
+			brokendb[i].model == model) {
+			printk("fbmon: The EDID Block of "
+			       "Manufacturer: %s Model: 0x%x is known to "
+			       "be broken,\n",  manufacturer, model);
+ 			fix = brokendb[i].fix;
+ 			break;
+		}
+	}
+
+	switch (fix) {
+	case FBMON_FIX_HEADER:
+		for (i = 0; i < 8; i++) {
+			if (edid[i] != edid_v1_header[i])
+				ret = fix;
+		}
+		break;
+	case FBMON_FIX_INPUT:
+		b = edid + EDID_STRUCT_DISPLAY;
+		/* Only if display is GTF capable will
+		   the input type be reset to analog */
+		if (b[4] & 0x01 && b[0] & 0x80)
+			ret = fix;
+		break;
+	}
+
+	return ret;
+}
+
+static void fix_edid(unsigned char *edid, int fix)
+{
+	unsigned char *b;
+
+	switch (fix) {
+	case FBMON_FIX_HEADER:
+		printk("fbmon: trying a header reconstruct\n");
+		memcpy(edid, edid_v1_header, 8);
+		break;
+	case FBMON_FIX_INPUT:
+		printk("fbmon: trying to fix input type\n");
+		b = edid + EDID_STRUCT_DISPLAY;
+		b[0] &= ~0x80;
+		edid[127] += 0x80;
+	}
+}
+
+static int edid_checksum(unsigned char *edid)
+{
+	unsigned char i, csum = 0, all_null = 0;
+	int err = 0, fix = check_edid(edid);
+
+	if (fix)
+		fix_edid(edid, fix);
+
+	for (i = 0; i < EDID_LENGTH; i++) {
+		csum += edid[i];
+		all_null |= edid[i];
+	}
+
+	if (csum == 0x00 && all_null) {
+		/* checksum passed, everything's good */
+		err = 1;
+	}
+
+	return err;
+}
+
+static int edid_check_header(unsigned char *edid)
+{
+	int i, err = 1, fix = check_edid(edid);
+
+	if (fix)
+		fix_edid(edid, fix);
+
+	for (i = 0; i < 8; i++) {
+		if (edid[i] != edid_v1_header[i])
+			err = 0;
+	}
+
+	return err;
+}
+
+static void parse_vendor_block(unsigned char *block, struct fb_monspecs *specs)
+{
+	specs->manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@';
+	specs->manufacturer[1] = ((block[0] & 0x03) << 3) +
+		((block[1] & 0xe0) >> 5) + '@';
+	specs->manufacturer[2] = (block[1] & 0x1f) + '@';
+	specs->manufacturer[3] = 0;
+	specs->model = block[2] + (block[3] << 8);
+	specs->serial = block[4] + (block[5] << 8) +
+	       (block[6] << 16) + (block[7] << 24);
+	specs->year = block[9] + 1990;
+	specs->week = block[8];
+	DPRINTK("   Manufacturer: %s\n", specs->manufacturer);
+	DPRINTK("   Model: %x\n", specs->model);
+	DPRINTK("   Serial#: %u\n", specs->serial);
+	DPRINTK("   Year: %u Week %u\n", specs->year, specs->week);
+}
+
+static void get_dpms_capabilities(unsigned char flags,
+				  struct fb_monspecs *specs)
+{
+	specs->dpms = 0;
+	if (flags & DPMS_ACTIVE_OFF)
+		specs->dpms |= FB_DPMS_ACTIVE_OFF;
+	if (flags & DPMS_SUSPEND)
+		specs->dpms |= FB_DPMS_SUSPEND;
+	if (flags & DPMS_STANDBY)
+		specs->dpms |= FB_DPMS_STANDBY;
+	DPRINTK("      DPMS: Active %s, Suspend %s, Standby %s\n",
+	       (flags & DPMS_ACTIVE_OFF) ? "yes" : "no",
+	       (flags & DPMS_SUSPEND)    ? "yes" : "no",
+	       (flags & DPMS_STANDBY)    ? "yes" : "no");
+}
+	
+static void get_chroma(unsigned char *block, struct fb_monspecs *specs)
+{
+	int tmp;
+
+	DPRINTK("      Chroma\n");
+	/* Chromaticity data */
+	tmp = ((block[5] & (3 << 6)) >> 6) | (block[0x7] << 2);
+	tmp *= 1000;
+	tmp += 512;
+	specs->chroma.redx = tmp/1024;
+	DPRINTK("         RedX:     0.%03d ", specs->chroma.redx);
+
+	tmp = ((block[5] & (3 << 4)) >> 4) | (block[0x8] << 2);
+	tmp *= 1000;
+	tmp += 512;
+	specs->chroma.redy = tmp/1024;
+	DPRINTK("RedY:     0.%03d\n", specs->chroma.redy);
+
+	tmp = ((block[5] & (3 << 2)) >> 2) | (block[0x9] << 2);
+	tmp *= 1000;
+	tmp += 512;
+	specs->chroma.greenx = tmp/1024;
+	DPRINTK("         GreenX:   0.%03d ", specs->chroma.greenx);
+
+	tmp = (block[5] & 3) | (block[0xa] << 2);
+	tmp *= 1000;
+	tmp += 512;
+	specs->chroma.greeny = tmp/1024;
+	DPRINTK("GreenY:   0.%03d\n", specs->chroma.greeny);
+
+	tmp = ((block[6] & (3 << 6)) >> 6) | (block[0xb] << 2);
+	tmp *= 1000;
+	tmp += 512;
+	specs->chroma.bluex = tmp/1024;
+	DPRINTK("         BlueX:    0.%03d ", specs->chroma.bluex);
+
+	tmp = ((block[6] & (3 << 4)) >> 4) | (block[0xc] << 2);
+	tmp *= 1000;
+	tmp += 512;
+	specs->chroma.bluey = tmp/1024;
+	DPRINTK("BlueY:    0.%03d\n", specs->chroma.bluey);
+	
+	tmp = ((block[6] & (3 << 2)) >> 2) | (block[0xd] << 2);
+	tmp *= 1000;
+	tmp += 512;
+	specs->chroma.whitex = tmp/1024;
+	DPRINTK("         WhiteX:   0.%03d ", specs->chroma.whitex);
+
+	tmp = (block[6] & 3) | (block[0xe] << 2);
+	tmp *= 1000;
+	tmp += 512;
+	specs->chroma.whitey = tmp/1024;
+	DPRINTK("WhiteY:   0.%03d\n", specs->chroma.whitey);
+}
+
+static int edid_is_serial_block(unsigned char *block)
+{
+	if ((block[0] == 0x00) && (block[1] == 0x00) && 
+	    (block[2] == 0x00) && (block[3] == 0xff) &&
+	    (block[4] == 0x00))
+		return 1;
+	else
+		return 0;
+}
+
+static int edid_is_ascii_block(unsigned char *block)
+{
+	if ((block[0] == 0x00) && (block[1] == 0x00) && 
+	    (block[2] == 0x00) && (block[3] == 0xfe) &&
+	    (block[4] == 0x00))
+		return 1;
+	else
+		return 0;
+}
+
+static int edid_is_limits_block(unsigned char *block)
+{
+	if ((block[0] == 0x00) && (block[1] == 0x00) && 
+	    (block[2] == 0x00) && (block[3] == 0xfd) &&
+	    (block[4] == 0x00))
+		return 1;
+	else
+		return 0;
+}
+
+static int edid_is_monitor_block(unsigned char *block)
+{
+	if ((block[0] == 0x00) && (block[1] == 0x00) && 
+	    (block[2] == 0x00) && (block[3] == 0xfc) &&
+	    (block[4] == 0x00))
+		return 1;
+	else
+		return 0;
+}
+
+static void calc_mode_timings(int xres, int yres, int refresh, struct fb_videomode *mode)
+{
+	struct fb_var_screeninfo var;
+	struct fb_info info;
+	
+	var.xres = xres;
+	var.yres = yres;
+	fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 
+		    refresh, &var, &info);
+	mode->xres = xres;
+	mode->yres = yres;
+	mode->pixclock = var.pixclock;
+	mode->refresh = refresh;
+	mode->left_margin = var.left_margin;
+	mode->right_margin = var.right_margin;
+	mode->upper_margin = var.upper_margin;
+	mode->lower_margin = var.lower_margin;
+	mode->hsync_len = var.hsync_len;
+	mode->vsync_len = var.vsync_len;
+	mode->vmode = 0;
+	mode->sync = 0;
+}
+
+static int get_est_timing(unsigned char *block, struct fb_videomode *mode)
+{
+	int num = 0;
+	unsigned char c;
+
+	c = block[0];
+	if (c&0x80) {
+		calc_mode_timings(720, 400, 70, &mode[num]);
+		mode[num++].flag = FB_MODE_IS_CALCULATED;
+		DPRINTK("      720x400@70Hz\n");
+	}
+	if (c&0x40) {
+		calc_mode_timings(720, 400, 88, &mode[num]);
+		mode[num++].flag = FB_MODE_IS_CALCULATED;
+		DPRINTK("      720x400@88Hz\n");
+	}
+	if (c&0x20) {
+		mode[num++] = vesa_modes[3];
+		DPRINTK("      640x480@60Hz\n");
+	}
+	if (c&0x10) {
+		calc_mode_timings(640, 480, 67, &mode[num]);
+		mode[num++].flag = FB_MODE_IS_CALCULATED;
+		DPRINTK("      640x480@67Hz\n");
+	}
+	if (c&0x08) {
+		mode[num++] = vesa_modes[4];
+		DPRINTK("      640x480@72Hz\n");
+	}
+	if (c&0x04) {
+		mode[num++] = vesa_modes[5];
+		DPRINTK("      640x480@75Hz\n");
+	}
+	if (c&0x02) {
+		mode[num++] = vesa_modes[7];
+		DPRINTK("      800x600@56Hz\n");
+	}
+	if (c&0x01) {
+		mode[num++] = vesa_modes[8];
+		DPRINTK("      800x600@60Hz\n");
+	}
+
+	c = block[1];
+	if (c&0x80) {
+ 		mode[num++] = vesa_modes[9];
+		DPRINTK("      800x600@72Hz\n");
+	}
+	if (c&0x40) {
+ 		mode[num++] = vesa_modes[10];
+		DPRINTK("      800x600@75Hz\n");
+	}
+	if (c&0x20) {
+		calc_mode_timings(832, 624, 75, &mode[num]);
+		mode[num++].flag = FB_MODE_IS_CALCULATED;
+		DPRINTK("      832x624@75Hz\n");
+	}
+	if (c&0x10) {
+		mode[num++] = vesa_modes[12];
+		DPRINTK("      1024x768@87Hz Interlaced\n");
+	}
+	if (c&0x08) {
+		mode[num++] = vesa_modes[13];
+		DPRINTK("      1024x768@60Hz\n");
+	}
+	if (c&0x04) {
+		mode[num++] = vesa_modes[14];
+		DPRINTK("      1024x768@70Hz\n");
+	}
+	if (c&0x02) {
+		mode[num++] = vesa_modes[15];
+		DPRINTK("      1024x768@75Hz\n");
+	}
+	if (c&0x01) {
+		mode[num++] = vesa_modes[21];
+		DPRINTK("      1280x1024@75Hz\n");
+	}
+	c = block[2];
+	if (c&0x80) {
+		mode[num++] = vesa_modes[17];
+		DPRINTK("      1152x870@75Hz\n");
+	}
+	DPRINTK("      Manufacturer's mask: %x\n",c&0x7F);
+	return num;
+}
+
+static int get_std_timing(unsigned char *block, struct fb_videomode *mode)
+{
+	int xres, yres = 0, refresh, ratio, i;
+	
+	xres = (block[0] + 31) * 8;
+	if (xres <= 256)
+		return 0;
+
+	ratio = (block[1] & 0xc0) >> 6;
+	switch (ratio) {
+	case 0:
+		yres = xres;
+		break;
+	case 1:
+		yres = (xres * 3)/4;
+		break;
+	case 2:
+		yres = (xres * 4)/5;
+		break;
+	case 3:
+		yres = (xres * 9)/16;
+		break;
+	}
+	refresh = (block[1] & 0x3f) + 60;
+
+	DPRINTK("      %dx%d@%dHz\n", xres, yres, refresh);
+	for (i = 0; i < VESA_MODEDB_SIZE; i++) {
+		if (vesa_modes[i].xres == xres && 
+		    vesa_modes[i].yres == yres &&
+		    vesa_modes[i].refresh == refresh) {
+			*mode = vesa_modes[i];
+			mode->flag |= FB_MODE_IS_STANDARD;
+			return 1;
+		}
+	}
+	calc_mode_timings(xres, yres, refresh, mode);
+	return 1;
+}
+
+static int get_dst_timing(unsigned char *block,
+			  struct fb_videomode *mode)
+{
+	int j, num = 0;
+
+	for (j = 0; j < 6; j++, block+= STD_TIMING_DESCRIPTION_SIZE) 
+		num += get_std_timing(block, &mode[num]);
+
+	return num;
+}
+
+static void get_detailed_timing(unsigned char *block, 
+				struct fb_videomode *mode)
+{
+	mode->xres = H_ACTIVE;
+	mode->yres = V_ACTIVE;
+	mode->pixclock = PIXEL_CLOCK;
+	mode->pixclock /= 1000;
+	mode->pixclock = KHZ2PICOS(mode->pixclock);
+	mode->right_margin = H_SYNC_OFFSET;
+	mode->left_margin = (H_ACTIVE + H_BLANKING) -
+		(H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
+	mode->upper_margin = V_BLANKING - V_SYNC_OFFSET - 
+		V_SYNC_WIDTH;
+	mode->lower_margin = V_SYNC_OFFSET;
+	mode->hsync_len = H_SYNC_WIDTH;
+	mode->vsync_len = V_SYNC_WIDTH;
+	if (HSYNC_POSITIVE)
+		mode->sync |= FB_SYNC_HOR_HIGH_ACT;
+	if (VSYNC_POSITIVE)
+		mode->sync |= FB_SYNC_VERT_HIGH_ACT;
+	mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) *
+				     (V_ACTIVE + V_BLANKING));
+	mode->vmode = 0;
+	mode->flag = FB_MODE_IS_DETAILED;
+
+	DPRINTK("      %d MHz ",  PIXEL_CLOCK/1000000);
+	DPRINTK("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET,
+	       H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING);
+	DPRINTK("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET,
+	       V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING);
+	DPRINTK("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-",
+	       (VSYNC_POSITIVE) ? "+" : "-");
+}
+
+/**
+ * fb_create_modedb - create video mode database
+ * @edid: EDID data
+ * @dbsize: database size
+ *
+ * RETURNS: struct fb_videomode, @dbsize contains length of database
+ *
+ * DESCRIPTION:
+ * This function builds a mode database using the contents of the EDID
+ * data
+ */
+static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
+{
+	struct fb_videomode *mode, *m;
+	unsigned char *block;
+	int num = 0, i;
+
+	mode = kmalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL);
+	if (mode == NULL)
+		return NULL;
+	memset(mode, 0, 50 * sizeof(struct fb_videomode));
+
+	if (edid == NULL || !edid_checksum(edid) || 
+	    !edid_check_header(edid)) {
+		kfree(mode);
+		return NULL;
+	}
+
+	*dbsize = 0;
+
+	DPRINTK("   Supported VESA Modes\n");
+	block = edid + ESTABLISHED_TIMING_1;
+	num += get_est_timing(block, &mode[num]);
+
+	DPRINTK("   Standard Timings\n");
+	block = edid + STD_TIMING_DESCRIPTIONS_START;
+	for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE) 
+		num += get_std_timing(block, &mode[num]);
+
+	DPRINTK("   Detailed Timings\n");
+	block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
+	for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {
+	        int first = 1;
+
+		if (block[0] == 0x00 && block[1] == 0x00) {
+			if (block[3] == 0xfa) {
+				num += get_dst_timing(block + 5, &mode[num]);
+			}
+		} else  {
+			get_detailed_timing(block, &mode[num]);
+			if (first) {
+			        mode[num].flag |= FB_MODE_IS_FIRST;
+				first = 0;
+			}
+			num++;
+		}
+	}
+	
+	/* Yikes, EDID data is totally useless */
+	if (!num) {
+		kfree(mode);
+		return NULL;
+	}
+
+	*dbsize = num;
+	m = kmalloc(num * sizeof(struct fb_videomode), GFP_KERNEL);
+	if (!m)
+		return mode;
+	memmove(m, mode, num * sizeof(struct fb_videomode));
+	kfree(mode);
+	return m;
+}
+
+/**
+ * fb_destroy_modedb - destroys mode database
+ * @modedb: mode database to destroy
+ *
+ * DESCRIPTION:
+ * Destroy mode database created by fb_create_modedb
+ */
+void fb_destroy_modedb(struct fb_videomode *modedb)
+{
+	kfree(modedb);
+}
+
+static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
+{
+	int i, retval = 1;
+	unsigned char *block;
+
+	block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
+
+	DPRINTK("      Monitor Operating Limits: ");
+	for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
+		if (edid_is_limits_block(block)) {
+			specs->hfmin = H_MIN_RATE * 1000;
+			specs->hfmax = H_MAX_RATE * 1000;
+			specs->vfmin = V_MIN_RATE;
+			specs->vfmax = V_MAX_RATE;
+			specs->dclkmax = MAX_PIXEL_CLOCK * 1000000;
+			specs->gtf = (GTF_SUPPORT) ? 1 : 0;
+			retval = 0;
+			DPRINTK("From EDID\n");
+			break;
+		}
+	}
+	
+	/* estimate monitor limits based on modes supported */
+	if (retval) {
+		struct fb_videomode *modes;
+		int num_modes, i, hz, hscan, pixclock;
+
+		modes = fb_create_modedb(edid, &num_modes);
+		if (!modes) {
+			DPRINTK("None Available\n");
+			return 1;
+		}
+
+		retval = 0;
+		for (i = 0; i < num_modes; i++) {
+			hz = modes[i].refresh;
+			pixclock = PICOS2KHZ(modes[i].pixclock) * 1000;
+			hscan = (modes[i].yres * 105 * hz + 5000)/100;
+			
+			if (specs->dclkmax == 0 || specs->dclkmax < pixclock)
+				specs->dclkmax = pixclock;
+			if (specs->dclkmin == 0 || specs->dclkmin > pixclock)
+				specs->dclkmin = pixclock;
+			if (specs->hfmax == 0 || specs->hfmax < hscan)
+				specs->hfmax = hscan;
+			if (specs->hfmin == 0 || specs->hfmin > hscan)
+				specs->hfmin = hscan;
+			if (specs->vfmax == 0 || specs->vfmax < hz)
+				specs->vfmax = hz;
+			if (specs->vfmin == 0 || specs->vfmin > hz)
+				specs->vfmin = hz;
+		}
+		DPRINTK("Extrapolated\n");
+		fb_destroy_modedb(modes);
+	}
+	DPRINTK("           H: %d-%dKHz V: %d-%dHz DCLK: %dMHz\n",
+		specs->hfmin/1000, specs->hfmax/1000, specs->vfmin,
+		specs->vfmax, specs->dclkmax/1000000);
+	return retval;
+}
+
+static void get_monspecs(unsigned char *edid, struct fb_monspecs *specs)
+{
+	unsigned char c, *block;
+
+	block = edid + EDID_STRUCT_DISPLAY;
+
+	fb_get_monitor_limits(edid, specs);
+
+	c = block[0] & 0x80;
+	specs->input = 0;
+	if (c) {
+		specs->input |= FB_DISP_DDI;
+		DPRINTK("      Digital Display Input");
+	} else {
+		DPRINTK("      Analog Display Input: Input Voltage - ");
+		switch ((block[0] & 0x60) >> 5) {
+		case 0:
+			DPRINTK("0.700V/0.300V");
+			specs->input |= FB_DISP_ANA_700_300;
+			break;
+		case 1:
+			DPRINTK("0.714V/0.286V");
+			specs->input |= FB_DISP_ANA_714_286;
+			break;
+		case 2:
+			DPRINTK("1.000V/0.400V");
+			specs->input |= FB_DISP_ANA_1000_400;
+			break;
+		case 3:
+			DPRINTK("0.700V/0.000V");
+			specs->input |= FB_DISP_ANA_700_000;
+			break;
+		}
+	}
+	DPRINTK("\n      Sync: ");
+	c = block[0] & 0x10;
+	if (c)
+		DPRINTK("      Configurable signal level\n");
+	c = block[0] & 0x0f;
+	specs->signal = 0;
+	if (c & 0x10) {
+		DPRINTK("Blank to Blank ");
+		specs->signal |= FB_SIGNAL_BLANK_BLANK;
+	}
+	if (c & 0x08) {
+		DPRINTK("Separate ");
+		specs->signal |= FB_SIGNAL_SEPARATE;
+	}
+	if (c & 0x04) {
+		DPRINTK("Composite ");
+		specs->signal |= FB_SIGNAL_COMPOSITE;
+	}
+	if (c & 0x02) {
+		DPRINTK("Sync on Green ");
+		specs->signal |= FB_SIGNAL_SYNC_ON_GREEN;
+	}
+	if (c & 0x01) {
+		DPRINTK("Serration on ");
+		specs->signal |= FB_SIGNAL_SERRATION_ON;
+	}
+	DPRINTK("\n");
+	specs->max_x = block[1];
+	specs->max_y = block[2];
+	DPRINTK("      Max H-size in cm: ");
+	if (specs->max_x)
+		DPRINTK("%d\n", specs->max_x);
+	else
+		DPRINTK("variable\n");
+	DPRINTK("      Max V-size in cm: ");
+	if (specs->max_y)
+		DPRINTK("%d\n", specs->max_y);
+	else
+		DPRINTK("variable\n");
+
+	c = block[3];
+	specs->gamma = c+100;
+	DPRINTK("      Gamma: ");
+	DPRINTK("%d.%d\n", specs->gamma/100, specs->gamma % 100);
+
+	get_dpms_capabilities(block[4], specs);
+
+	switch ((block[4] & 0x18) >> 3) {
+	case 0:
+		DPRINTK("      Monochrome/Grayscale\n");
+		specs->input |= FB_DISP_MONO;
+		break;
+	case 1:
+		DPRINTK("      RGB Color Display\n");
+		specs->input |= FB_DISP_RGB;
+		break;
+	case 2:
+		DPRINTK("      Non-RGB Multicolor Display\n");
+		specs->input |= FB_DISP_MULTI;
+		break;
+	default:
+		DPRINTK("      Unknown\n");
+		specs->input |= FB_DISP_UNKNOWN;
+		break;
+	}
+
+	get_chroma(block, specs);
+
+	specs->misc = 0;
+	c = block[4] & 0x7;
+	if (c & 0x04) {
+		DPRINTK("      Default color format is primary\n");
+		specs->misc |= FB_MISC_PRIM_COLOR;
+	}
+	if (c & 0x02) {
+		DPRINTK("      First DETAILED Timing is preferred\n");
+		specs->misc |= FB_MISC_1ST_DETAIL;
+	}
+	if (c & 0x01) {
+		printk("      Display is GTF capable\n");
+		specs->gtf = 1;
+	}
+}
+
+static int edid_is_timing_block(unsigned char *block)
+{
+	if ((block[0] != 0x00) || (block[1] != 0x00) ||
+	    (block[2] != 0x00) || (block[4] != 0x00))
+		return 1;
+	else
+		return 0;
+}
+
+int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
+{
+	int i;
+	unsigned char *block;
+
+	if (edid == NULL || var == NULL)
+		return 1;
+
+	if (!(edid_checksum(edid)))
+		return 1;
+
+	if (!(edid_check_header(edid)))
+		return 1;
+
+	block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
+
+	for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
+		if (edid_is_timing_block(block)) {
+			var->xres = var->xres_virtual = H_ACTIVE;
+			var->yres = var->yres_virtual = V_ACTIVE;
+			var->height = var->width = -1;
+			var->right_margin = H_SYNC_OFFSET;
+			var->left_margin = (H_ACTIVE + H_BLANKING) -
+				(H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
+			var->upper_margin = V_BLANKING - V_SYNC_OFFSET -
+				V_SYNC_WIDTH;
+			var->lower_margin = V_SYNC_OFFSET;
+			var->hsync_len = H_SYNC_WIDTH;
+			var->vsync_len = V_SYNC_WIDTH;
+			var->pixclock = PIXEL_CLOCK;
+			var->pixclock /= 1000;
+			var->pixclock = KHZ2PICOS(var->pixclock);
+
+			if (HSYNC_POSITIVE)
+				var->sync |= FB_SYNC_HOR_HIGH_ACT;
+			if (VSYNC_POSITIVE)
+				var->sync |= FB_SYNC_VERT_HIGH_ACT;
+			return 0;
+		}
+	}
+	return 1;
+}
+
+void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
+{
+	unsigned char *block;
+	int i;
+
+	if (edid == NULL)
+		return;
+
+	if (!(edid_checksum(edid)))
+		return;
+
+	if (!(edid_check_header(edid)))
+		return;
+
+	memset(specs, 0, sizeof(struct fb_monspecs));
+
+	specs->version = edid[EDID_STRUCT_VERSION];
+	specs->revision = edid[EDID_STRUCT_REVISION];
+
+	DPRINTK("========================================\n");
+	DPRINTK("Display Information (EDID)\n");
+	DPRINTK("========================================\n");
+	DPRINTK("   EDID Version %d.%d\n", (int) specs->version,
+	       (int) specs->revision);
+
+	parse_vendor_block(edid + ID_MANUFACTURER_NAME, specs);
+
+	block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
+	for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
+		if (edid_is_serial_block(block)) {
+			copy_string(block, specs->serial_no);
+			DPRINTK("   Serial Number: %s\n", specs->serial_no);
+		} else if (edid_is_ascii_block(block)) {
+			copy_string(block, specs->ascii);
+			DPRINTK("   ASCII Block: %s\n", specs->ascii);
+		} else if (edid_is_monitor_block(block)) {
+			copy_string(block, specs->monitor);
+			DPRINTK("   Monitor Name: %s\n", specs->monitor);
+		}
+	}
+
+	DPRINTK("   Display Characteristics:\n");
+	get_monspecs(edid, specs);
+
+	specs->modedb = fb_create_modedb(edid, &specs->modedb_len);
+	DPRINTK("========================================\n");
+}
+
+/* 
+ * VESA Generalized Timing Formula (GTF) 
+ */
+
+#define FLYBACK                     550
+#define V_FRONTPORCH                1
+#define H_OFFSET                    40
+#define H_SCALEFACTOR               20
+#define H_BLANKSCALE                128
+#define H_GRADIENT                  600
+#define C_VAL                       30
+#define M_VAL                       300
+
+struct __fb_timings {
+	u32 dclk;
+	u32 hfreq;
+	u32 vfreq;
+	u32 hactive;
+	u32 vactive;
+	u32 hblank;
+	u32 vblank;
+	u32 htotal;
+	u32 vtotal;
+};
+
+/**
+ * fb_get_vblank - get vertical blank time
+ * @hfreq: horizontal freq
+ *
+ * DESCRIPTION:
+ * vblank = right_margin + vsync_len + left_margin 
+ *
+ *    given: right_margin = 1 (V_FRONTPORCH)
+ *           vsync_len    = 3
+ *           flyback      = 550
+ *
+ *                          flyback * hfreq
+ *           left_margin  = --------------- - vsync_len
+ *                           1000000
+ */
+static u32 fb_get_vblank(u32 hfreq)
+{
+	u32 vblank;
+
+	vblank = (hfreq * FLYBACK)/1000; 
+	vblank = (vblank + 500)/1000;
+	return (vblank + V_FRONTPORCH);
+}
+
+/** 
+ * fb_get_hblank_by_freq - get horizontal blank time given hfreq
+ * @hfreq: horizontal freq
+ * @xres: horizontal resolution in pixels
+ *
+ * DESCRIPTION:
+ *
+ *           xres * duty_cycle
+ * hblank = ------------------
+ *           100 - duty_cycle
+ *
+ * duty cycle = percent of htotal assigned to inactive display
+ * duty cycle = C - (M/Hfreq)
+ *
+ * where: C = ((offset - scale factor) * blank_scale)
+ *            -------------------------------------- + scale factor
+ *                        256 
+ *        M = blank_scale * gradient
+ *
+ */
+static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres)
+{
+	u32 c_val, m_val, duty_cycle, hblank;
+
+	c_val = (((H_OFFSET - H_SCALEFACTOR) * H_BLANKSCALE)/256 + 
+		 H_SCALEFACTOR) * 1000;
+	m_val = (H_BLANKSCALE * H_GRADIENT)/256;
+	m_val = (m_val * 1000000)/hfreq;
+	duty_cycle = c_val - m_val;
+	hblank = (xres * duty_cycle)/(100000 - duty_cycle);
+	return (hblank);
+}
+
+/** 
+ * fb_get_hblank_by_dclk - get horizontal blank time given pixelclock
+ * @dclk: pixelclock in Hz
+ * @xres: horizontal resolution in pixels
+ *
+ * DESCRIPTION:
+ *
+ *           xres * duty_cycle
+ * hblank = ------------------
+ *           100 - duty_cycle
+ *
+ * duty cycle = percent of htotal assigned to inactive display
+ * duty cycle = C - (M * h_period)
+ * 
+ * where: h_period = SQRT(100 - C + (0.4 * xres * M)/dclk) + C - 100
+ *                   -----------------------------------------------
+ *                                    2 * M
+ *        M = 300;
+ *        C = 30;
+
+ */
+static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres)
+{
+	u32 duty_cycle, h_period, hblank;
+
+	dclk /= 1000;
+	h_period = 100 - C_VAL;
+	h_period *= h_period;
+	h_period += (M_VAL * xres * 2 * 1000)/(5 * dclk);
+	h_period *=10000; 
+
+	h_period = int_sqrt(h_period);
+	h_period -= (100 - C_VAL) * 100;
+	h_period *= 1000; 
+	h_period /= 2 * M_VAL;
+
+	duty_cycle = C_VAL * 1000 - (M_VAL * h_period)/100;
+	hblank = (xres * duty_cycle)/(100000 - duty_cycle) + 8;
+	hblank &= ~15;
+	return (hblank);
+}
+	
+/**
+ * fb_get_hfreq - estimate hsync
+ * @vfreq: vertical refresh rate
+ * @yres: vertical resolution
+ *
+ * DESCRIPTION:
+ *
+ *          (yres + front_port) * vfreq * 1000000
+ * hfreq = -------------------------------------
+ *          (1000000 - (vfreq * FLYBACK)
+ * 
+ */
+
+static u32 fb_get_hfreq(u32 vfreq, u32 yres)
+{
+	u32 divisor, hfreq;
+	
+	divisor = (1000000 - (vfreq * FLYBACK))/1000;
+	hfreq = (yres + V_FRONTPORCH) * vfreq  * 1000;
+	return (hfreq/divisor);
+}
+
+static void fb_timings_vfreq(struct __fb_timings *timings)
+{
+	timings->hfreq = fb_get_hfreq(timings->vfreq, timings->vactive);
+	timings->vblank = fb_get_vblank(timings->hfreq);
+	timings->vtotal = timings->vactive + timings->vblank;
+	timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq, 
+						 timings->hactive);
+	timings->htotal = timings->hactive + timings->hblank;
+	timings->dclk = timings->htotal * timings->hfreq;
+}
+
+static void fb_timings_hfreq(struct __fb_timings *timings)
+{
+	timings->vblank = fb_get_vblank(timings->hfreq);
+	timings->vtotal = timings->vactive + timings->vblank;
+	timings->vfreq = timings->hfreq/timings->vtotal;
+	timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq, 
+						 timings->hactive);
+	timings->htotal = timings->hactive + timings->hblank;
+	timings->dclk = timings->htotal * timings->hfreq;
+}
+
+static void fb_timings_dclk(struct __fb_timings *timings)
+{
+	timings->hblank = fb_get_hblank_by_dclk(timings->dclk, 
+						timings->hactive);
+	timings->htotal = timings->hactive + timings->hblank;
+	timings->hfreq = timings->dclk/timings->htotal;
+	timings->vblank = fb_get_vblank(timings->hfreq);
+	timings->vtotal = timings->vactive + timings->vblank;
+	timings->vfreq = timings->hfreq/timings->vtotal;
+}
+
+/*
+ * fb_get_mode - calculates video mode using VESA GTF
+ * @flags: if: 0 - maximize vertical refresh rate
+ *             1 - vrefresh-driven calculation;
+ *             2 - hscan-driven calculation;
+ *             3 - pixelclock-driven calculation;
+ * @val: depending on @flags, ignored, vrefresh, hsync or pixelclock
+ * @var: pointer to fb_var_screeninfo
+ * @info: pointer to fb_info
+ *
+ * DESCRIPTION:
+ * Calculates video mode based on monitor specs using VESA GTF. 
+ * The GTF is best for VESA GTF compliant monitors but is 
+ * specifically formulated to work for older monitors as well.
+ *
+ * If @flag==0, the function will attempt to maximize the 
+ * refresh rate.  Otherwise, it will calculate timings based on
+ * the flag and accompanying value.  
+ *
+ * If FB_IGNOREMON bit is set in @flags, monitor specs will be 
+ * ignored and @var will be filled with the calculated timings.
+ *
+ * All calculations are based on the VESA GTF Spreadsheet
+ * available at VESA's public ftp (http://www.vesa.org).
+ * 
+ * NOTES:
+ * The timings generated by the GTF will be different from VESA
+ * DMT.  It might be a good idea to keep a table of standard
+ * VESA modes as well.  The GTF may also not work for some displays,
+ * such as, and especially, analog TV.
+ *   
+ * REQUIRES:
+ * A valid info->monspecs, otherwise 'safe numbers' will be used.
+ */ 
+int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct __fb_timings timings;
+	u32 interlace = 1, dscan = 1;
+	u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax;
+
+	/* 
+	 * If monspecs are invalid, use values that are enough
+	 * for 640x480@60
+	 */
+	if (!info->monspecs.hfmax || !info->monspecs.vfmax ||
+	    !info->monspecs.dclkmax ||
+	    info->monspecs.hfmax < info->monspecs.hfmin ||
+	    info->monspecs.vfmax < info->monspecs.vfmin ||
+	    info->monspecs.dclkmax < info->monspecs.dclkmin) {
+		hfmin = 29000; hfmax = 30000;
+		vfmin = 60; vfmax = 60;
+		dclkmin = 0; dclkmax = 25000000;
+	} else {
+		hfmin = info->monspecs.hfmin;
+		hfmax = info->monspecs.hfmax;
+		vfmin = info->monspecs.vfmin;
+		vfmax = info->monspecs.vfmax;
+		dclkmin = info->monspecs.dclkmin;
+		dclkmax = info->monspecs.dclkmax;
+	}
+
+	memset(&timings, 0, sizeof(struct __fb_timings));
+	timings.hactive = var->xres;
+	timings.vactive = var->yres;
+	if (var->vmode & FB_VMODE_INTERLACED) { 
+		timings.vactive /= 2;
+		interlace = 2;
+	}
+	if (var->vmode & FB_VMODE_DOUBLE) {
+		timings.vactive *= 2;
+		dscan = 2;
+	}
+
+	switch (flags & ~FB_IGNOREMON) {
+	case FB_MAXTIMINGS: /* maximize refresh rate */
+		timings.hfreq = hfmax;
+		fb_timings_hfreq(&timings);
+		if (timings.vfreq > vfmax) {
+			timings.vfreq = vfmax;
+			fb_timings_vfreq(&timings);
+		}
+		if (timings.dclk > dclkmax) {
+			timings.dclk = dclkmax;
+			fb_timings_dclk(&timings);
+		}
+		break;
+	case FB_VSYNCTIMINGS: /* vrefresh driven */
+		timings.vfreq = val;
+		fb_timings_vfreq(&timings);
+		break;
+	case FB_HSYNCTIMINGS: /* hsync driven */
+		timings.hfreq = val;
+		fb_timings_hfreq(&timings);
+		break;
+	case FB_DCLKTIMINGS: /* pixelclock driven */
+		timings.dclk = PICOS2KHZ(val) * 1000;
+		fb_timings_dclk(&timings);
+		break;
+	default:
+		return -EINVAL;
+		
+	} 
+	
+	if (!(flags & FB_IGNOREMON) && 
+	    (timings.vfreq < vfmin || timings.vfreq > vfmax || 
+	     timings.hfreq < hfmin || timings.hfreq > hfmax ||
+	     timings.dclk < dclkmin || timings.dclk > dclkmax))
+		return -EINVAL;
+
+	var->pixclock = KHZ2PICOS(timings.dclk/1000);
+	var->hsync_len = (timings.htotal * 8)/100;
+	var->right_margin = (timings.hblank/2) - var->hsync_len;
+	var->left_margin = timings.hblank - var->right_margin - var->hsync_len;
+	
+	var->vsync_len = (3 * interlace)/dscan;
+	var->lower_margin = (1 * interlace)/dscan;
+	var->upper_margin = (timings.vblank * interlace)/dscan - 
+		(var->vsync_len + var->lower_margin);
+	
+	return 0;
+}
+#else
+int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
+{
+	return 1;
+}
+void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
+{
+	specs = NULL;
+}
+void fb_destroy_modedb(struct fb_videomode *modedb)
+{
+}
+int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var,
+		struct fb_info *info)
+{
+	return -EINVAL;
+}
+#endif /* CONFIG_FB_MODE_HELPERS */
+	
+/*
+ * fb_validate_mode - validates var against monitor capabilities
+ * @var: pointer to fb_var_screeninfo
+ * @info: pointer to fb_info
+ *
+ * DESCRIPTION:
+ * Validates video mode against monitor capabilities specified in
+ * info->monspecs.
+ *
+ * REQUIRES:
+ * A valid info->monspecs.
+ */
+int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	u32 hfreq, vfreq, htotal, vtotal, pixclock;
+	u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax;
+
+	/* 
+	 * If monspecs are invalid, use values that are enough
+	 * for 640x480@60
+	 */
+	if (!info->monspecs.hfmax || !info->monspecs.vfmax ||
+	    !info->monspecs.dclkmax ||
+	    info->monspecs.hfmax < info->monspecs.hfmin ||
+	    info->monspecs.vfmax < info->monspecs.vfmin ||
+	    info->monspecs.dclkmax < info->monspecs.dclkmin) {
+		hfmin = 29000; hfmax = 30000;
+		vfmin = 60; vfmax = 60;
+		dclkmin = 0; dclkmax = 25000000;
+	} else {
+		hfmin = info->monspecs.hfmin;
+		hfmax = info->monspecs.hfmax;
+		vfmin = info->monspecs.vfmin;
+		vfmax = info->monspecs.vfmax;
+		dclkmin = info->monspecs.dclkmin;
+		dclkmax = info->monspecs.dclkmax;
+	}
+
+	if (!var->pixclock)
+		return -EINVAL;
+	pixclock = PICOS2KHZ(var->pixclock) * 1000;
+	   
+	htotal = var->xres + var->right_margin + var->hsync_len + 
+		var->left_margin;
+	vtotal = var->yres + var->lower_margin + var->vsync_len + 
+		var->upper_margin;
+
+	if (var->vmode & FB_VMODE_INTERLACED)
+		vtotal /= 2;
+	if (var->vmode & FB_VMODE_DOUBLE)
+		vtotal *= 2;
+
+	hfreq = pixclock/htotal;
+	vfreq = hfreq/vtotal;
+
+	return (vfreq < vfmin || vfreq > vfmax || 
+		hfreq < hfmin || hfreq > hfmax ||
+		pixclock < dclkmin || pixclock > dclkmax) ?
+		-EINVAL : 0;
+}
+
+EXPORT_SYMBOL(fb_parse_edid);
+EXPORT_SYMBOL(fb_edid_to_monspecs);
+
+EXPORT_SYMBOL(fb_get_mode);
+EXPORT_SYMBOL(fb_validate_mode);
+EXPORT_SYMBOL(fb_destroy_modedb);
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
new file mode 100644
index 0000000..2bdda40
--- /dev/null
+++ b/drivers/video/fbsysfs.c
@@ -0,0 +1,389 @@
+/*
+ * fbsysfs.c - framebuffer device class and attributes
+ *
+ * Copyright (c) 2004 James Simmons <jsimmons@infradead.org>
+ * 
+ *	This program is free software you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+/*
+ * Note:  currently there's only stubs for framebuffer_alloc and
+ * framebuffer_release here.  The reson for that is that until all drivers
+ * are converted to use it a sysfsification will open OOPSable races.
+ */
+
+#include <linux/kernel.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+
+/**
+ * framebuffer_alloc - creates a new frame buffer info structure
+ *
+ * @size: size of driver private data, can be zero
+ * @dev: pointer to the device for this fb, this can be NULL
+ *
+ * Creates a new frame buffer info structure. Also reserves @size bytes
+ * for driver private data (info->par). info->par (if any) will be
+ * aligned to sizeof(long).
+ *
+ * Returns the new structure, or NULL if an error occured.
+ *
+ */
+struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
+{
+#define BYTES_PER_LONG (BITS_PER_LONG/8)
+#define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG))
+	int fb_info_size = sizeof(struct fb_info);
+	struct fb_info *info;
+	char *p;
+
+	if (size)
+		fb_info_size += PADDING;
+
+	p = kmalloc(fb_info_size + size, GFP_KERNEL);
+	if (!p)
+		return NULL;
+	memset(p, 0, fb_info_size + size);
+	info = (struct fb_info *) p;
+
+	if (size)
+		info->par = p + fb_info_size;
+
+	info->device = dev;
+
+	return info;
+#undef PADDING
+#undef BYTES_PER_LONG
+}
+EXPORT_SYMBOL(framebuffer_alloc);
+
+/**
+ * framebuffer_release - marks the structure available for freeing
+ *
+ * @info: frame buffer info structure
+ *
+ * Drop the reference count of the class_device embedded in the
+ * framebuffer info structure.
+ *
+ */
+void framebuffer_release(struct fb_info *info)
+{
+	kfree(info);
+}
+EXPORT_SYMBOL(framebuffer_release);
+
+static int activate(struct fb_info *fb_info, struct fb_var_screeninfo *var)
+{
+	int err;
+
+	var->activate |= FB_ACTIVATE_FORCE;
+	acquire_console_sem();
+	fb_info->flags |= FBINFO_MISC_USEREVENT;
+	err = fb_set_var(fb_info, var);
+	fb_info->flags &= ~FBINFO_MISC_USEREVENT;
+	release_console_sem();
+	if (err)
+		return err;
+	return 0;
+}
+
+static int mode_string(char *buf, unsigned int offset,
+		       const struct fb_videomode *mode)
+{
+	char m = 'U';
+	if (mode->flag & FB_MODE_IS_DETAILED)
+		m = 'D';
+	if (mode->flag & FB_MODE_IS_VESA)
+		m = 'V';
+	if (mode->flag & FB_MODE_IS_STANDARD)
+		m = 'S';
+	return snprintf(&buf[offset], PAGE_SIZE - offset, "%c:%dx%d-%d\n", m, mode->xres, mode->yres, mode->refresh);
+}
+
+static ssize_t store_mode(struct class_device *class_device, const char * buf,
+			  size_t count)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	char mstr[100];
+	struct fb_var_screeninfo var;
+	struct fb_modelist *modelist;
+	struct fb_videomode *mode;
+	struct list_head *pos;
+	size_t i;
+	int err;
+
+	memset(&var, 0, sizeof(var));
+
+	list_for_each(pos, &fb_info->modelist) {
+		modelist = list_entry(pos, struct fb_modelist, list);
+		mode = &modelist->mode;
+		i = mode_string(mstr, 0, mode);
+		if (strncmp(mstr, buf, max(count, i)) == 0) {
+
+			var = fb_info->var;
+			fb_videomode_to_var(&var, mode);
+			if ((err = activate(fb_info, &var)))
+				return err;
+			fb_info->mode = mode;
+			return count;
+		}
+	}
+	return -EINVAL;
+}
+
+static ssize_t show_mode(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+
+	if (!fb_info->mode)
+		return 0;
+
+	return mode_string(buf, 0, fb_info->mode);
+}
+
+static ssize_t store_modes(struct class_device *class_device, const char * buf,
+			   size_t count)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	LIST_HEAD(old_list);
+	int i = count / sizeof(struct fb_videomode);
+
+	if (i * sizeof(struct fb_videomode) != count)
+		return -EINVAL;
+
+	acquire_console_sem();
+	list_splice(&fb_info->modelist, &old_list);
+	fb_videomode_to_modelist((struct fb_videomode *)buf, i,
+				 &fb_info->modelist);
+	if (fb_new_modelist(fb_info)) {
+		fb_destroy_modelist(&fb_info->modelist);
+		list_splice(&old_list, &fb_info->modelist);
+	} else
+		fb_destroy_modelist(&old_list);
+
+	release_console_sem();
+
+	return 0;
+}
+
+static ssize_t show_modes(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	unsigned int i;
+	struct list_head *pos;
+	struct fb_modelist *modelist;
+	const struct fb_videomode *mode;
+
+	i = 0;
+	list_for_each(pos, &fb_info->modelist) {
+		modelist = list_entry(pos, struct fb_modelist, list);
+		mode = &modelist->mode;
+		i += mode_string(buf, i, mode);
+	}
+	return i;
+}
+
+static ssize_t store_bpp(struct class_device *class_device, const char * buf,
+			 size_t count)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	struct fb_var_screeninfo var;
+	char ** last = NULL;
+	int err;
+
+	var = fb_info->var;
+	var.bits_per_pixel = simple_strtoul(buf, last, 0);
+	if ((err = activate(fb_info, &var)))
+		return err;
+	return count;
+}
+
+static ssize_t show_bpp(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.bits_per_pixel);
+}
+
+static ssize_t store_virtual(struct class_device *class_device,
+			     const char * buf, size_t count)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	struct fb_var_screeninfo var;
+	char *last = NULL;
+	int err;
+
+	var = fb_info->var;
+	var.xres_virtual = simple_strtoul(buf, &last, 0);
+	last++;
+	if (last - buf >= count)
+		return -EINVAL;
+	var.yres_virtual = simple_strtoul(last, &last, 0);
+	printk(KERN_ERR "fb: xres %d yres %d\n", var.xres_virtual,
+	       var.yres_virtual);
+
+	if ((err = activate(fb_info, &var)))
+		return err;
+	return count;
+}
+
+static ssize_t show_virtual(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xres_virtual,
+			fb_info->var.xres_virtual);
+}
+
+static ssize_t store_cmap(struct class_device *class_device, const char * buf,
+			  size_t count)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t show_cmap(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	unsigned int offset = 0, i;
+
+	if (!fb_info->cmap.red || !fb_info->cmap.blue ||
+	    fb_info->cmap.green || fb_info->cmap.transp)
+		return -EINVAL;
+
+	for (i = 0; i < fb_info->cmap.len; i++) {
+		offset += snprintf(buf, PAGE_SIZE - offset,
+				   "%d,%d,%d,%d,%d\n", i + fb_info->cmap.start,
+				   fb_info->cmap.red[i], fb_info->cmap.blue[i],
+				   fb_info->cmap.green[i],
+				   fb_info->cmap.transp[i]);
+	}
+	return offset;
+}
+
+static ssize_t store_blank(struct class_device *class_device, const char * buf,
+			   size_t count)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	char *last = NULL;
+	int err;
+
+	acquire_console_sem();
+	fb_info->flags |= FBINFO_MISC_USEREVENT;
+	err = fb_blank(fb_info, simple_strtoul(buf, &last, 0));
+	fb_info->flags &= ~FBINFO_MISC_USEREVENT;
+	release_console_sem();
+	if (err < 0)
+		return err;
+	return count;
+}
+
+static ssize_t show_blank(struct class_device *class_device, char *buf)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t store_console(struct class_device *class_device,
+			     const char * buf, size_t count)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t show_console(struct class_device *class_device, char *buf)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t store_cursor(struct class_device *class_device,
+			    const char * buf, size_t count)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t show_cursor(struct class_device *class_device, char *buf)
+{
+//	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
+	return 0;
+}
+
+static ssize_t store_pan(struct class_device *class_device, const char * buf,
+			 size_t count)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	struct fb_var_screeninfo var;
+	char *last = NULL;
+	int err;
+
+	var = fb_info->var;
+	var.xoffset = simple_strtoul(buf, &last, 0);
+	last++;
+	if (last - buf >= count)
+		return -EINVAL;
+	var.yoffset = simple_strtoul(last, &last, 0);
+
+	acquire_console_sem();
+	err = fb_pan_display(fb_info, &var);
+	release_console_sem();
+
+	if (err < 0)
+		return err;
+	return count;
+}
+
+static ssize_t show_pan(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info =
+		(struct fb_info *)class_get_devdata(class_device);
+	return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xoffset,
+			fb_info->var.xoffset);
+}
+
+struct class_device_attribute class_device_attrs[] = {
+	__ATTR(bits_per_pixel, S_IRUGO|S_IWUSR, show_bpp, store_bpp),
+	__ATTR(blank, S_IRUGO|S_IWUSR, show_blank, store_blank),
+	__ATTR(color_map, S_IRUGO|S_IWUSR, show_cmap, store_cmap),
+	__ATTR(console, S_IRUGO|S_IWUSR, show_console, store_console),
+	__ATTR(cursor, S_IRUGO|S_IWUSR, show_cursor, store_cursor),
+	__ATTR(mode, S_IRUGO|S_IWUSR, show_mode, store_mode),
+	__ATTR(modes, S_IRUGO|S_IWUSR, show_modes, store_modes),
+	__ATTR(pan, S_IRUGO|S_IWUSR, show_pan, store_pan),
+	__ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual),
+};
+
+int fb_init_class_device(struct fb_info *fb_info)
+{
+	unsigned int i;
+	class_set_devdata(fb_info->class_device, fb_info);
+
+	for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+		class_device_create_file(fb_info->class_device,
+					 &class_device_attrs[i]);
+	return 0;
+}
+
+void fb_cleanup_class_device(struct fb_info *fb_info)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+		class_device_remove_file(fb_info->class_device,
+					 &class_device_attrs[i]);
+}
+
+
diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c
new file mode 100644
index 0000000..10cd050
--- /dev/null
+++ b/drivers/video/ffb.c
@@ -0,0 +1,1092 @@
+/* ffb.c: Creator/Elite3D frame buffer driver
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
+ *
+ * Driver layout based loosely on tgafb.c, see that file for credits.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/mm.h>
+#include <linux/timer.h>
+
+#include <asm/io.h>
+#include <asm/upa.h>
+#include <asm/oplib.h>
+#include <asm/fbio.h>
+
+#include "sbuslib.h"
+
+/*
+ * Local functions.
+ */
+
+static int ffb_setcolreg(unsigned, unsigned, unsigned, unsigned,
+			 unsigned, struct fb_info *);
+static int ffb_blank(int, struct fb_info *);
+static void ffb_init_fix(struct fb_info *);
+
+static void ffb_imageblit(struct fb_info *, const struct fb_image *);
+static void ffb_fillrect(struct fb_info *, const struct fb_fillrect *);
+static void ffb_copyarea(struct fb_info *, const struct fb_copyarea *);
+static int ffb_sync(struct fb_info *);
+static int ffb_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
+static int ffb_ioctl(struct inode *, struct file *, unsigned int,
+		     unsigned long, struct fb_info *);
+static int ffb_pan_display(struct fb_var_screeninfo *, struct fb_info *);
+
+/*
+ *  Frame buffer operations
+ */
+
+static struct fb_ops ffb_ops = {
+	.owner			= THIS_MODULE,
+	.fb_setcolreg		= ffb_setcolreg,
+	.fb_blank		= ffb_blank,
+	.fb_pan_display		= ffb_pan_display,
+	.fb_fillrect		= ffb_fillrect,
+	.fb_copyarea		= ffb_copyarea,
+	.fb_imageblit		= ffb_imageblit,
+	.fb_sync		= ffb_sync,
+	.fb_mmap		= ffb_mmap,
+	.fb_ioctl		= ffb_ioctl,
+
+	/* XXX Use FFB hw cursor once fb cursor API is better understood... */
+	.fb_cursor		= soft_cursor,
+};
+
+/* Register layout and definitions */
+#define	FFB_SFB8R_VOFF		0x00000000
+#define	FFB_SFB8G_VOFF		0x00400000
+#define	FFB_SFB8B_VOFF		0x00800000
+#define	FFB_SFB8X_VOFF		0x00c00000
+#define	FFB_SFB32_VOFF		0x01000000
+#define	FFB_SFB64_VOFF		0x02000000
+#define	FFB_FBC_REGS_VOFF	0x04000000
+#define	FFB_BM_FBC_REGS_VOFF	0x04002000
+#define	FFB_DFB8R_VOFF		0x04004000
+#define	FFB_DFB8G_VOFF		0x04404000
+#define	FFB_DFB8B_VOFF		0x04804000
+#define	FFB_DFB8X_VOFF		0x04c04000
+#define	FFB_DFB24_VOFF		0x05004000
+#define	FFB_DFB32_VOFF		0x06004000
+#define	FFB_DFB422A_VOFF	0x07004000	/* DFB 422 mode write to A */
+#define	FFB_DFB422AD_VOFF	0x07804000	/* DFB 422 mode with line doubling */
+#define	FFB_DFB24B_VOFF		0x08004000	/* DFB 24bit mode write to B */
+#define	FFB_DFB422B_VOFF	0x09004000	/* DFB 422 mode write to B */
+#define	FFB_DFB422BD_VOFF	0x09804000	/* DFB 422 mode with line doubling */
+#define	FFB_SFB16Z_VOFF		0x0a004000	/* 16bit mode Z planes */
+#define	FFB_SFB8Z_VOFF		0x0a404000	/* 8bit mode Z planes */
+#define	FFB_SFB422_VOFF		0x0ac04000	/* SFB 422 mode write to A/B */
+#define	FFB_SFB422D_VOFF	0x0b404000	/* SFB 422 mode with line doubling */
+#define	FFB_FBC_KREGS_VOFF	0x0bc04000
+#define	FFB_DAC_VOFF		0x0bc06000
+#define	FFB_PROM_VOFF		0x0bc08000
+#define	FFB_EXP_VOFF		0x0bc18000
+
+#define	FFB_SFB8R_POFF		0x04000000UL
+#define	FFB_SFB8G_POFF		0x04400000UL
+#define	FFB_SFB8B_POFF		0x04800000UL
+#define	FFB_SFB8X_POFF		0x04c00000UL
+#define	FFB_SFB32_POFF		0x05000000UL
+#define	FFB_SFB64_POFF		0x06000000UL
+#define	FFB_FBC_REGS_POFF	0x00600000UL
+#define	FFB_BM_FBC_REGS_POFF	0x00600000UL
+#define	FFB_DFB8R_POFF		0x01000000UL
+#define	FFB_DFB8G_POFF		0x01400000UL
+#define	FFB_DFB8B_POFF		0x01800000UL
+#define	FFB_DFB8X_POFF		0x01c00000UL
+#define	FFB_DFB24_POFF		0x02000000UL
+#define	FFB_DFB32_POFF		0x03000000UL
+#define	FFB_FBC_KREGS_POFF	0x00610000UL
+#define	FFB_DAC_POFF		0x00400000UL
+#define	FFB_PROM_POFF		0x00000000UL
+#define	FFB_EXP_POFF		0x00200000UL
+#define FFB_DFB422A_POFF	0x09000000UL
+#define FFB_DFB422AD_POFF	0x09800000UL
+#define FFB_DFB24B_POFF		0x0a000000UL
+#define FFB_DFB422B_POFF	0x0b000000UL
+#define FFB_DFB422BD_POFF	0x0b800000UL
+#define FFB_SFB16Z_POFF		0x0c800000UL
+#define FFB_SFB8Z_POFF		0x0c000000UL
+#define FFB_SFB422_POFF		0x0d000000UL
+#define FFB_SFB422D_POFF	0x0d800000UL
+
+/* Draw operations */
+#define FFB_DRAWOP_DOT		0x00
+#define FFB_DRAWOP_AADOT	0x01
+#define FFB_DRAWOP_BRLINECAP	0x02
+#define FFB_DRAWOP_BRLINEOPEN	0x03
+#define FFB_DRAWOP_DDLINE	0x04
+#define FFB_DRAWOP_AALINE	0x05
+#define FFB_DRAWOP_TRIANGLE	0x06
+#define FFB_DRAWOP_POLYGON	0x07
+#define FFB_DRAWOP_RECTANGLE	0x08
+#define FFB_DRAWOP_FASTFILL	0x09
+#define FFB_DRAWOP_BCOPY	0x0a
+#define FFB_DRAWOP_VSCROLL	0x0b
+
+/* Pixel processor control */
+/* Force WID */
+#define FFB_PPC_FW_DISABLE	0x800000
+#define FFB_PPC_FW_ENABLE	0xc00000
+/* Auxiliary clip */
+#define FFB_PPC_ACE_DISABLE	0x040000
+#define FFB_PPC_ACE_AUX_SUB	0x080000
+#define FFB_PPC_ACE_AUX_ADD	0x0c0000
+/* Depth cue */
+#define FFB_PPC_DCE_DISABLE	0x020000
+#define FFB_PPC_DCE_ENABLE	0x030000
+/* Alpha blend */
+#define FFB_PPC_ABE_DISABLE	0x008000
+#define FFB_PPC_ABE_ENABLE	0x00c000
+/* View clip */
+#define FFB_PPC_VCE_DISABLE	0x001000
+#define FFB_PPC_VCE_2D		0x002000
+#define FFB_PPC_VCE_3D		0x003000
+/* Area pattern */
+#define FFB_PPC_APE_DISABLE	0x000800
+#define FFB_PPC_APE_ENABLE	0x000c00
+/* Transparent background */
+#define FFB_PPC_TBE_OPAQUE	0x000200
+#define FFB_PPC_TBE_TRANSPARENT	0x000300
+/* Z source */
+#define FFB_PPC_ZS_VAR		0x000080
+#define FFB_PPC_ZS_CONST	0x0000c0
+/* Y source */
+#define FFB_PPC_YS_VAR		0x000020
+#define FFB_PPC_YS_CONST	0x000030
+/* X source */
+#define FFB_PPC_XS_WID		0x000004
+#define FFB_PPC_XS_VAR		0x000008
+#define FFB_PPC_XS_CONST	0x00000c
+/* Color (BGR) source */
+#define FFB_PPC_CS_VAR		0x000002
+#define FFB_PPC_CS_CONST	0x000003
+
+#define FFB_ROP_NEW                  0x83
+#define FFB_ROP_OLD                  0x85
+#define FFB_ROP_NEW_XOR_OLD          0x86
+
+#define FFB_UCSR_FIFO_MASK     0x00000fff
+#define FFB_UCSR_FB_BUSY       0x01000000
+#define FFB_UCSR_RP_BUSY       0x02000000
+#define FFB_UCSR_ALL_BUSY      (FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY)
+#define FFB_UCSR_READ_ERR      0x40000000
+#define FFB_UCSR_FIFO_OVFL     0x80000000
+#define FFB_UCSR_ALL_ERRORS    (FFB_UCSR_READ_ERR|FFB_UCSR_FIFO_OVFL)
+
+struct ffb_fbc {
+	/* Next vertex registers */
+	u32		xxx1[3];
+	volatile u32	alpha;
+	volatile u32	red;
+	volatile u32	green;
+	volatile u32	blue;
+	volatile u32	depth;
+	volatile u32	y;
+	volatile u32	x;
+	u32		xxx2[2];
+	volatile u32	ryf;
+	volatile u32	rxf;
+	u32		xxx3[2];
+	
+	volatile u32	dmyf;
+	volatile u32	dmxf;
+	u32		xxx4[2];
+	volatile u32	ebyi;
+	volatile u32	ebxi;
+	u32		xxx5[2];
+	volatile u32	by;
+	volatile u32	bx;
+	u32		dy;
+	u32		dx;
+	volatile u32	bh;
+	volatile u32	bw;
+	u32		xxx6[2];
+	
+	u32		xxx7[32];
+	
+	/* Setup unit vertex state register */
+	volatile u32	suvtx;
+	u32		xxx8[63];
+	
+	/* Control registers */
+	volatile u32	ppc;
+	volatile u32	wid;
+	volatile u32	fg;
+	volatile u32	bg;
+	volatile u32	consty;
+	volatile u32	constz;
+	volatile u32	xclip;
+	volatile u32	dcss;
+	volatile u32	vclipmin;
+	volatile u32	vclipmax;
+	volatile u32	vclipzmin;
+	volatile u32	vclipzmax;
+	volatile u32	dcsf;
+	volatile u32	dcsb;
+	volatile u32	dczf;
+	volatile u32	dczb;
+	
+	u32		xxx9;
+	volatile u32	blendc;
+	volatile u32	blendc1;
+	volatile u32	blendc2;
+	volatile u32	fbramitc;
+	volatile u32	fbc;
+	volatile u32	rop;
+	volatile u32	cmp;
+	volatile u32	matchab;
+	volatile u32	matchc;
+	volatile u32	magnab;
+	volatile u32	magnc;
+	volatile u32	fbcfg0;
+	volatile u32	fbcfg1;
+	volatile u32	fbcfg2;
+	volatile u32	fbcfg3;
+	
+	u32		ppcfg;
+	volatile u32	pick;
+	volatile u32	fillmode;
+	volatile u32	fbramwac;
+	volatile u32	pmask;
+	volatile u32	xpmask;
+	volatile u32	ypmask;
+	volatile u32	zpmask;
+	volatile u32	clip0min;
+	volatile u32	clip0max;
+	volatile u32	clip1min;
+	volatile u32	clip1max;
+	volatile u32	clip2min;
+	volatile u32	clip2max;
+	volatile u32	clip3min;
+	volatile u32	clip3max;
+	
+	/* New 3dRAM III support regs */
+	volatile u32	rawblend2;
+	volatile u32	rawpreblend;
+	volatile u32	rawstencil;
+	volatile u32	rawstencilctl;
+	volatile u32	threedram1;
+	volatile u32	threedram2;
+	volatile u32	passin;
+	volatile u32	rawclrdepth;
+	volatile u32	rawpmask;
+	volatile u32	rawcsrc;
+	volatile u32	rawmatch;
+	volatile u32	rawmagn;
+	volatile u32	rawropblend;
+	volatile u32	rawcmp;
+	volatile u32	rawwac;
+	volatile u32	fbramid;
+	
+	volatile u32	drawop;
+	u32		xxx10[2];
+	volatile u32	fontlpat;
+	u32		xxx11;
+	volatile u32	fontxy;
+	volatile u32	fontw;
+	volatile u32	fontinc;
+	volatile u32	font;
+	u32		xxx12[3];
+	volatile u32	blend2;
+	volatile u32	preblend;
+	volatile u32	stencil;
+	volatile u32	stencilctl;
+
+	u32		xxx13[4];	
+	volatile u32	dcss1;
+	volatile u32	dcss2;
+	volatile u32	dcss3;
+	volatile u32	widpmask;
+	volatile u32	dcs2;
+	volatile u32	dcs3;
+	volatile u32	dcs4;
+	u32		xxx14;
+	volatile u32	dcd2;
+	volatile u32	dcd3;
+	volatile u32	dcd4;
+	u32		xxx15;
+	
+	volatile u32	pattern[32];
+	
+	u32		xxx16[256];
+	
+	volatile u32	devid;
+	u32		xxx17[63];
+	
+	volatile u32	ucsr;
+	u32		xxx18[31];
+	
+	volatile u32	mer;
+};
+
+struct ffb_dac {
+	volatile u32	type;
+	volatile u32	value;
+	volatile u32	type2;
+	volatile u32	value2;
+};
+
+struct ffb_par {
+	spinlock_t		lock;
+	struct ffb_fbc		*fbc;
+	struct ffb_dac		*dac;
+
+	u32			flags;
+#define FFB_FLAG_AFB		0x00000001
+#define FFB_FLAG_BLANKED	0x00000002
+
+	u32			fg_cache __attribute__((aligned (8)));
+	u32			bg_cache;
+	u32			rop_cache;
+
+	int			fifo_cache;
+
+	unsigned long		physbase;
+	unsigned long		fbsize;
+
+	char			name[64];
+	int			prom_node;
+	int			prom_parent_node;
+	int			dac_rev;
+	int			board_type;
+	struct list_head	list;
+};
+
+static void FFBFifo(struct ffb_par *par, int n)
+{
+	struct ffb_fbc *fbc;
+	int cache = par->fifo_cache;
+
+	if (cache - n < 0) {
+		fbc = par->fbc;
+		do {	cache = (upa_readl(&fbc->ucsr) & FFB_UCSR_FIFO_MASK) - 8;
+		} while (cache - n < 0);
+	}
+	par->fifo_cache = cache - n;
+}
+
+static void FFBWait(struct ffb_par *par)
+{
+	struct ffb_fbc *fbc;
+	int limit = 10000;
+
+	fbc = par->fbc;
+	do {
+		if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_BUSY) == 0)
+			break;
+		if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0) {
+			upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr);
+		}
+		udelay(10);
+	} while(--limit > 0);
+}
+
+static int ffb_sync(struct fb_info *p)
+{
+	struct ffb_par *par = (struct ffb_par *) p->par;
+
+	FFBWait(par);
+	return 0;
+}
+
+static __inline__ void ffb_rop(struct ffb_par *par, u32 rop)
+{
+	if (par->rop_cache != rop) {
+		FFBFifo(par, 1);
+		upa_writel(rop, &par->fbc->rop);
+		par->rop_cache = rop;
+	}
+}
+
+static void ffb_switch_from_graph(struct ffb_par *par)
+{
+	struct ffb_fbc *fbc = par->fbc;
+	struct ffb_dac *dac = par->dac;
+	unsigned long flags;
+
+	spin_lock_irqsave(&par->lock, flags);
+	FFBWait(par);
+	par->fifo_cache = 0;
+	FFBFifo(par, 7);
+	upa_writel(FFB_PPC_VCE_DISABLE|FFB_PPC_TBE_OPAQUE|
+		   FFB_PPC_APE_DISABLE|FFB_PPC_CS_CONST,
+		   &fbc->ppc);
+	upa_writel(0x2000707f, &fbc->fbc);
+	upa_writel(par->rop_cache, &fbc->rop);
+	upa_writel(0xffffffff, &fbc->pmask);
+	upa_writel((1 << 16) | (0 << 0), &fbc->fontinc);
+	upa_writel(par->fg_cache, &fbc->fg);
+	upa_writel(par->bg_cache, &fbc->bg);
+	FFBWait(par);
+
+	/* Disable cursor.  */
+	upa_writel(0x100, &dac->type2);
+	if (par->dac_rev <= 2)
+		upa_writel(0, &dac->value2);
+	else
+		upa_writel(3, &dac->value2);
+
+	spin_unlock_irqrestore(&par->lock, flags);
+}
+
+static int ffb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct ffb_par *par = (struct ffb_par *) info->par;
+
+	/* We just use this to catch switches out of
+	 * graphics mode.
+	 */
+	ffb_switch_from_graph(par);
+
+	if (var->xoffset || var->yoffset || var->vmode)
+		return -EINVAL;
+	return 0;
+}
+
+/**
+ *      ffb_fillrect - REQUIRED function. Can use generic routines if 
+ *                     non acclerated hardware and packed pixel based.
+ *                     Draws a rectangle on the screen.               
+ *
+ *      @info: frame buffer structure that represents a single frame buffer
+ *      @rect: structure defining the rectagle and operation.
+ */
+static void ffb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+	struct ffb_par *par = (struct ffb_par *) info->par;
+	struct ffb_fbc *fbc = par->fbc;
+	unsigned long flags;
+	u32 fg;
+
+	if (rect->rop != ROP_COPY && rect->rop != ROP_XOR)
+		BUG();
+
+	fg = ((u32 *)info->pseudo_palette)[rect->color];
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	if (fg != par->fg_cache) {
+		FFBFifo(par, 1);
+		upa_writel(fg, &fbc->fg);
+		par->fg_cache = fg;
+	}
+
+	ffb_rop(par, (rect->rop == ROP_COPY ?
+		      FFB_ROP_NEW :
+		      FFB_ROP_NEW_XOR_OLD));
+
+	FFBFifo(par, 5);
+	upa_writel(FFB_DRAWOP_RECTANGLE, &fbc->drawop);
+	upa_writel(rect->dy, &fbc->by);
+	upa_writel(rect->dx, &fbc->bx);
+	upa_writel(rect->height, &fbc->bh);
+	upa_writel(rect->width, &fbc->bw);
+
+	spin_unlock_irqrestore(&par->lock, flags);
+}
+
+/**
+ *      ffb_copyarea - REQUIRED function. Can use generic routines if
+ *                     non acclerated hardware and packed pixel based.
+ *                     Copies on area of the screen to another area.
+ *
+ *      @info: frame buffer structure that represents a single frame buffer
+ *      @area: structure defining the source and destination.
+ */
+
+static void
+ffb_copyarea(struct fb_info *info, const struct fb_copyarea *area) 
+{
+	struct ffb_par *par = (struct ffb_par *) info->par;
+	struct ffb_fbc *fbc = par->fbc;
+	unsigned long flags;
+
+	if (area->dx != area->sx ||
+	    area->dy == area->sy) {
+		cfb_copyarea(info, area);
+		return;
+	}
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	ffb_rop(par, FFB_ROP_OLD);
+
+	FFBFifo(par, 7);
+	upa_writel(FFB_DRAWOP_VSCROLL, &fbc->drawop);
+	upa_writel(area->sy, &fbc->by);
+	upa_writel(area->sx, &fbc->bx);
+	upa_writel(area->dy, &fbc->dy);
+	upa_writel(area->dx, &fbc->dx);
+	upa_writel(area->height, &fbc->bh);
+	upa_writel(area->width, &fbc->bw);
+
+	spin_unlock_irqrestore(&par->lock, flags);
+}
+
+/**
+ *      ffb_imageblit - REQUIRED function. Can use generic routines if
+ *                      non acclerated hardware and packed pixel based.
+ *                      Copies a image from system memory to the screen. 
+ *
+ *      @info: frame buffer structure that represents a single frame buffer
+ *      @image: structure defining the image.
+ */
+static void ffb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	struct ffb_par *par = (struct ffb_par *) info->par;
+	struct ffb_fbc *fbc = par->fbc;
+	const u8 *data = image->data;
+	unsigned long flags;
+	u32 fg, bg, xy;
+	u64 fgbg;
+	int i, width, stride;
+
+	if (image->depth > 1) {
+		cfb_imageblit(info, image);
+		return;
+	}
+
+	fg = ((u32 *)info->pseudo_palette)[image->fg_color];
+	bg = ((u32 *)info->pseudo_palette)[image->bg_color];
+	fgbg = ((u64) fg << 32) | (u64) bg;
+	xy = (image->dy << 16) | image->dx;
+	width = image->width;
+	stride = ((width + 7) >> 3);
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	if (fgbg != *(u64 *)&par->fg_cache) {
+		FFBFifo(par, 2);
+		upa_writeq(fgbg, &fbc->fg);
+		*(u64 *)&par->fg_cache = fgbg;
+	}
+
+	if (width >= 32) {
+		FFBFifo(par, 1);
+		upa_writel(32, &fbc->fontw);
+	}
+
+	while (width >= 32) {
+		const u8 *next_data = data + 4;
+
+		FFBFifo(par, 1);
+		upa_writel(xy, &fbc->fontxy);
+		xy += (32 << 0);
+
+		for (i = 0; i < image->height; i++) {
+			u32 val = (((u32)data[0] << 24) |
+				   ((u32)data[1] << 16) |
+				   ((u32)data[2] <<  8) |
+				   ((u32)data[3] <<  0));
+			FFBFifo(par, 1);
+			upa_writel(val, &fbc->font);
+
+			data += stride;
+		}
+
+		data = next_data;
+		width -= 32;
+	}
+
+	if (width) {
+		FFBFifo(par, 2);
+		upa_writel(width, &fbc->fontw);
+		upa_writel(xy, &fbc->fontxy);
+
+		for (i = 0; i < image->height; i++) {
+			u32 val = (((u32)data[0] << 24) |
+				   ((u32)data[1] << 16) |
+				   ((u32)data[2] <<  8) |
+				   ((u32)data[3] <<  0));
+			FFBFifo(par, 1);
+			upa_writel(val, &fbc->font);
+
+			data += stride;
+		}
+	}
+
+	spin_unlock_irqrestore(&par->lock, flags);
+}
+
+static void ffb_fixup_var_rgb(struct fb_var_screeninfo *var)
+{
+	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 = 0;
+	var->transp.length = 0;
+}
+
+/**
+ *      ffb_setcolreg - Optional function. Sets a color register.
+ *      @regno: boolean, 0 copy local, 1 get_user() function
+ *      @red: frame buffer colormap structure
+ *      @green: The green value which can be up to 16 bits wide
+ *      @blue:  The blue value which can be up to 16 bits wide.
+ *      @transp: If supported the alpha value which can be up to 16 bits wide.
+ *      @info: frame buffer info structure
+ */
+static int ffb_setcolreg(unsigned regno,
+			 unsigned red, unsigned green, unsigned blue,
+			 unsigned transp, struct fb_info *info)
+{
+	u32 value;
+
+	if (regno >= 256)
+		return 1;
+
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	value = (blue << 16) | (green << 8) | red;
+	((u32 *)info->pseudo_palette)[regno] = value;
+
+	return 0;
+}
+
+/**
+ *      ffb_blank - Optional function.  Blanks the display.
+ *      @blank_mode: the blank mode we want.
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+ffb_blank(int blank, struct fb_info *info)
+{
+	struct ffb_par *par = (struct ffb_par *) info->par;
+	struct ffb_dac *dac = par->dac;
+	unsigned long flags;
+	u32 tmp;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	FFBWait(par);
+
+	switch (blank) {
+	case FB_BLANK_UNBLANK: /* Unblanking */
+		upa_writel(0x6000, &dac->type);
+		tmp = (upa_readl(&dac->value) | 0x1);
+		upa_writel(0x6000, &dac->type);
+		upa_writel(tmp, &dac->value);
+		par->flags &= ~FFB_FLAG_BLANKED;
+		break;
+
+	case FB_BLANK_NORMAL: /* Normal blanking */
+	case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
+	case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
+	case FB_BLANK_POWERDOWN: /* Poweroff */
+		upa_writel(0x6000, &dac->type);
+		tmp = (upa_readl(&dac->value) & ~0x1);
+		upa_writel(0x6000, &dac->type);
+		upa_writel(tmp, &dac->value);
+		par->flags |= FFB_FLAG_BLANKED;
+		break;
+	}
+
+	spin_unlock_irqrestore(&par->lock, flags);
+
+	return 0;
+}
+
+static struct sbus_mmap_map ffb_mmap_map[] = {
+	{
+		.voff	= FFB_SFB8R_VOFF,
+		.poff	= FFB_SFB8R_POFF,
+		.size	= 0x0400000
+	},
+	{
+		.voff	= FFB_SFB8G_VOFF,
+		.poff	= FFB_SFB8G_POFF,
+		.size	= 0x0400000
+	},
+	{
+		.voff	= FFB_SFB8B_VOFF,
+		.poff	= FFB_SFB8B_POFF,
+		.size	= 0x0400000
+	},
+	{
+		.voff	= FFB_SFB8X_VOFF,
+		.poff	= FFB_SFB8X_POFF,
+		.size	= 0x0400000
+	},
+	{
+		.voff	= FFB_SFB32_VOFF,
+		.poff	= FFB_SFB32_POFF,
+		.size	= 0x1000000
+	},
+	{
+		.voff	= FFB_SFB64_VOFF,
+		.poff	= FFB_SFB64_POFF,
+		.size	= 0x2000000
+	},
+	{
+		.voff	= FFB_FBC_REGS_VOFF,
+		.poff	= FFB_FBC_REGS_POFF,
+		.size	= 0x0002000
+	},
+	{
+		.voff	= FFB_BM_FBC_REGS_VOFF,
+		.poff	= FFB_BM_FBC_REGS_POFF,
+		.size	= 0x0002000
+	},
+	{
+		.voff	= FFB_DFB8R_VOFF,
+		.poff	= FFB_DFB8R_POFF,
+		.size	= 0x0400000
+	},
+	{
+		.voff	= FFB_DFB8G_VOFF,
+		.poff	= FFB_DFB8G_POFF,
+		.size	= 0x0400000
+	},
+	{
+		.voff	= FFB_DFB8B_VOFF,
+		.poff	= FFB_DFB8B_POFF,
+		.size	= 0x0400000
+	},
+	{
+		.voff	= FFB_DFB8X_VOFF,
+		.poff	= FFB_DFB8X_POFF,
+		.size	= 0x0400000
+	},
+	{
+		.voff	= FFB_DFB24_VOFF,
+		.poff	= FFB_DFB24_POFF,
+		.size	= 0x1000000
+	},
+	{
+		.voff	= FFB_DFB32_VOFF,
+		.poff	= FFB_DFB32_POFF,
+		.size	= 0x1000000
+	},
+	{
+		.voff	= FFB_FBC_KREGS_VOFF,
+		.poff	= FFB_FBC_KREGS_POFF,
+		.size	= 0x0002000
+	},
+	{
+		.voff	= FFB_DAC_VOFF,
+		.poff	= FFB_DAC_POFF,
+		.size	= 0x0002000
+	},
+	{
+		.voff	= FFB_PROM_VOFF,
+		.poff	= FFB_PROM_POFF,
+		.size	= 0x0010000
+	},
+	{
+		.voff	= FFB_EXP_VOFF,
+		.poff	= FFB_EXP_POFF,
+		.size	= 0x0002000
+	},
+	{
+		.voff	= FFB_DFB422A_VOFF,
+		.poff	= FFB_DFB422A_POFF,
+		.size	= 0x0800000
+	},
+	{
+		.voff	= FFB_DFB422AD_VOFF,
+		.poff	= FFB_DFB422AD_POFF,
+		.size	= 0x0800000
+	},
+	{
+		.voff	= FFB_DFB24B_VOFF,
+		.poff	= FFB_DFB24B_POFF,
+		.size	= 0x1000000
+	},
+	{
+		.voff	= FFB_DFB422B_VOFF,
+		.poff	= FFB_DFB422B_POFF,
+		.size	= 0x0800000
+	},
+	{
+		.voff	= FFB_DFB422BD_VOFF,
+		.poff	= FFB_DFB422BD_POFF,
+		.size	= 0x0800000
+	},
+	{
+		.voff	= FFB_SFB16Z_VOFF,
+		.poff	= FFB_SFB16Z_POFF,
+		.size	= 0x0800000
+	},
+	{
+		.voff	= FFB_SFB8Z_VOFF,
+		.poff	= FFB_SFB8Z_POFF,
+		.size	= 0x0800000
+	},
+	{
+		.voff	= FFB_SFB422_VOFF,
+		.poff	= FFB_SFB422_POFF,
+		.size	= 0x0800000
+	},
+	{
+		.voff	= FFB_SFB422D_VOFF,
+		.poff	= FFB_SFB422D_POFF,
+		.size	= 0x0800000
+	},
+	{ .size = 0 }
+};
+
+static int ffb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+{
+	struct ffb_par *par = (struct ffb_par *)info->par;
+
+	return sbusfb_mmap_helper(ffb_mmap_map,
+				  par->physbase, par->fbsize,
+				  0, vma);
+}
+
+static int ffb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		     unsigned long arg, struct fb_info *info)
+{
+	struct ffb_par *par = (struct ffb_par *) info->par;
+
+	return sbusfb_ioctl_helper(cmd, arg, info,
+				   FBTYPE_CREATOR, 24, par->fbsize);
+}
+
+/*
+ *  Initialisation
+ */
+
+static void
+ffb_init_fix(struct fb_info *info)
+{
+	struct ffb_par *par = (struct ffb_par *)info->par;
+	const char *ffb_type_name;
+
+	if (!(par->flags & FFB_FLAG_AFB)) {
+		if ((par->board_type & 0x7) == 0x3)
+			ffb_type_name = "Creator 3D";
+		else
+			ffb_type_name = "Creator";
+	} else
+		ffb_type_name = "Elite 3D";
+
+	strlcpy(info->fix.id, ffb_type_name, sizeof(info->fix.id));
+
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.visual = FB_VISUAL_TRUECOLOR;
+
+	/* Framebuffer length is the same regardless of resolution. */
+	info->fix.line_length = 8192;
+
+	info->fix.accel = FB_ACCEL_SUN_CREATOR;
+}
+
+static int ffb_apply_upa_parent_ranges(int parent,
+				       struct linux_prom64_registers *regs)
+{
+	struct linux_prom64_ranges ranges[PROMREG_MAX];
+	char name[128];
+	int len, i;
+
+	prom_getproperty(parent, "name", name, sizeof(name));
+	if (strcmp(name, "upa") != 0)
+		return 0;
+
+	len = prom_getproperty(parent, "ranges", (void *) ranges, sizeof(ranges));
+	if (len <= 0)
+		return 1;
+
+	len /= sizeof(struct linux_prom64_ranges);
+	for (i = 0; i < len; i++) {
+		struct linux_prom64_ranges *rng = &ranges[i];
+		u64 phys_addr = regs->phys_addr;
+
+		if (phys_addr >= rng->ot_child_base &&
+		    phys_addr < (rng->ot_child_base + rng->or_size)) {
+			regs->phys_addr -= rng->ot_child_base;
+			regs->phys_addr += rng->ot_parent_base;
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+struct all_info {
+	struct fb_info info;
+	struct ffb_par par;
+	u32 pseudo_palette[256];
+	struct list_head list;
+};
+static LIST_HEAD(ffb_list);
+
+static void ffb_init_one(int node, int parent)
+{
+	struct linux_prom64_registers regs[2*PROMREG_MAX];
+	struct ffb_fbc *fbc;
+	struct ffb_dac *dac;
+	struct all_info *all;
+
+	if (prom_getproperty(node, "reg", (void *) regs, sizeof(regs)) <= 0) {
+		printk("ffb: Cannot get reg device node property.\n");
+		return;
+	}
+
+	if (ffb_apply_upa_parent_ranges(parent, &regs[0])) {
+		printk("ffb: Cannot apply parent ranges to regs.\n");
+		return;
+	}
+
+	all = kmalloc(sizeof(*all), GFP_KERNEL);
+	if (!all) {
+		printk(KERN_ERR "ffb: Cannot allocate memory.\n");
+		return;
+	}
+	memset(all, 0, sizeof(*all));
+
+	INIT_LIST_HEAD(&all->list);	
+
+	spin_lock_init(&all->par.lock);
+	all->par.fbc = (struct ffb_fbc *)(regs[0].phys_addr + FFB_FBC_REGS_POFF);
+	all->par.dac = (struct ffb_dac *)(regs[0].phys_addr + FFB_DAC_POFF);
+	all->par.rop_cache = FFB_ROP_NEW;
+	all->par.physbase = regs[0].phys_addr;
+	all->par.prom_node = node;
+	all->par.prom_parent_node = parent;
+
+	/* Don't mention copyarea, so SCROLL_REDRAW is always
+	 * used.  It is the fastest on this chip.
+	 */
+	all->info.flags = (FBINFO_DEFAULT |
+			   /* FBINFO_HWACCEL_COPYAREA | */
+			   FBINFO_HWACCEL_FILLRECT |
+			   FBINFO_HWACCEL_IMAGEBLIT);
+	all->info.fbops = &ffb_ops;
+	all->info.screen_base = (char *) all->par.physbase + FFB_DFB24_POFF;
+	all->info.par = &all->par;
+	all->info.pseudo_palette = all->pseudo_palette;
+
+	sbusfb_fill_var(&all->info.var, all->par.prom_node, 32);
+	all->par.fbsize = PAGE_ALIGN(all->info.var.xres *
+				     all->info.var.yres *
+				     4);
+	ffb_fixup_var_rgb(&all->info.var);
+
+	all->info.var.accel_flags = FB_ACCELF_TEXT;
+
+	prom_getstring(node, "name", all->par.name, sizeof(all->par.name));
+	if (!strcmp(all->par.name, "SUNW,afb"))
+		all->par.flags |= FFB_FLAG_AFB;
+
+	all->par.board_type = prom_getintdefault(node, "board_type", 0);
+
+	fbc = all->par.fbc;
+	if((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0)
+		upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr);
+
+	ffb_switch_from_graph(&all->par);
+
+	dac = all->par.dac;
+	upa_writel(0x8000, &dac->type);
+	all->par.dac_rev = upa_readl(&dac->value) >> 0x1c;
+
+	/* Elite3D has different DAC revision numbering, and no DAC revisions
+	 * have the reversed meaning of cursor enable.
+	 */
+	if (all->par.flags & FFB_FLAG_AFB)
+		all->par.dac_rev = 10;
+
+	/* Unblank it just to be sure.  When there are multiple
+	 * FFB/AFB cards in the system, or it is not the OBP
+	 * chosen console, it will have video outputs off in
+	 * the DAC.
+	 */
+	ffb_blank(0, &all->info);
+
+	if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
+		printk(KERN_ERR "ffb: Could not allocate color map.\n");
+		kfree(all);
+		return;
+	}
+
+	ffb_init_fix(&all->info);
+
+	if (register_framebuffer(&all->info) < 0) {
+		printk(KERN_ERR "ffb: Could not register framebuffer.\n");
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+		return;
+	}
+
+	list_add(&all->list, &ffb_list);
+
+	printk("ffb: %s at %016lx type %d DAC %d\n",
+	       ((all->par.flags & FFB_FLAG_AFB) ? "AFB" : "FFB"),
+	       regs[0].phys_addr, all->par.board_type, all->par.dac_rev);
+}
+
+static void ffb_scan_siblings(int root)
+{
+	int node, child;
+
+	child = prom_getchild(root);
+	for (node = prom_searchsiblings(child, "SUNW,ffb"); node;
+	     node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb"))
+		ffb_init_one(node, root);
+	for (node = prom_searchsiblings(child, "SUNW,afb"); node;
+	     node = prom_searchsiblings(prom_getsibling(node), "SUNW,afb"))
+		ffb_init_one(node, root);
+}
+
+int __init ffb_init(void)
+{
+	int root;
+
+	if (fb_get_options("ffb", NULL))
+		return -ENODEV;
+
+	ffb_scan_siblings(prom_root_node);
+
+	root = prom_getchild(prom_root_node);
+	for (root = prom_searchsiblings(root, "upa"); root;
+	     root = prom_searchsiblings(prom_getsibling(root), "upa"))
+		ffb_scan_siblings(root);
+
+	return 0;
+}
+
+void __exit ffb_exit(void)
+{
+	struct list_head *pos, *tmp;
+
+	list_for_each_safe(pos, tmp, &ffb_list) {
+		struct all_info *all = list_entry(pos, typeof(*all), list);
+
+		unregister_framebuffer(&all->info);
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+	}
+}
+
+int __init
+ffb_setup(char *arg)
+{
+	/* No cmdline options yet... */
+	return 0;
+}
+
+module_init(ffb_init);
+
+#ifdef MODULE
+module_exit(ffb_exit);
+#endif
+
+MODULE_DESCRIPTION("framebuffer driver for Creator/Elite3D chipsets");
+MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fm2fb.c b/drivers/video/fm2fb.c
new file mode 100644
index 0000000..a076328
--- /dev/null
+++ b/drivers/video/fm2fb.c
@@ -0,0 +1,322 @@
+/*
+ *  linux/drivers/video/fm2fb.c -- BSC FrameMaster II/Rainbow II frame buffer
+ *				   device
+ *
+ *	Copyright (C) 1998 Steffen A. Mork (linux-dev@morknet.de)
+ *	Copyright (C) 1999 Geert Uytterhoeven
+ *
+ *  Written for 2.0.x by Steffen A. Mork
+ *  Ported to 2.1.x by Geert Uytterhoeven
+ *  Ported to new api by James Simmons
+ *
+ *  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/module.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/zorro.h>
+#include <asm/io.h>
+
+/*
+ *	Some technical notes:
+ *
+ *	The BSC FrameMaster II (or Rainbow II) is a simple very dumb
+ *	frame buffer which allows to display 24 bit true color images.
+ *	Each pixel is 32 bit width so it's very easy to maintain the
+ *	frame buffer. One long word has the following layout:
+ *	AARRGGBB which means: AA the alpha channel byte, RR the red
+ *	channel, GG the green channel and BB the blue channel.
+ *
+ *	The FrameMaster II supports the following video modes.
+ *	- PAL/NTSC
+ *	- interlaced/non interlaced
+ *	- composite sync/sync/sync over green
+ *
+ *	The resolution is to the following both ones:
+ *	- 768x576 (PAL)
+ *	- 768x480 (NTSC)
+ *
+ *	This means that pixel access per line is fixed due to the
+ *	fixed line width. In case of maximal resolution the frame
+ *	buffer needs an amount of memory of 1.769.472 bytes which
+ *	is near to 2 MByte (the allocated address space of Zorro2).
+ *	The memory is channel interleaved. That means every channel
+ *	owns four VRAMs. Unfortunatly most FrameMasters II are
+ *	not assembled with memory for the alpha channel. In this
+ *	case it could be possible to add the frame buffer into the
+ *	normal memory pool.
+ *
+ *	At relative address 0x1ffff8 of the frame buffers base address
+ *	there exists a control register with the number of
+ *	four control bits. They have the following meaning:
+ *	bit value meaning
+ *
+ *	 0    1   0=interlaced/1=non interlaced
+ *	 1    2   0=video out disabled/1=video out enabled
+ *	 2    4   0=normal mode as jumpered via JP8/1=complement mode
+ *	 3    8   0=read  onboard ROM/1 normal operation (required)
+ *
+ *	As mentioned above there are several jumper. I think there
+ *	is not very much information about the FrameMaster II in
+ *	the world so I add these information for completeness.
+ *
+ *	JP1  interlace selection (1-2 non interlaced/2-3 interlaced)
+ *	JP2  wait state creation (leave as is!)
+ *	JP3  wait state creation (leave as is!)
+ *	JP4  modulate composite sync on green output (1-2 composite
+ *	     sync on green channel/2-3 normal composite sync)
+ *	JP5  create test signal, shorting this jumper will create
+ *	     a white screen
+ *	JP6  sync creation (1-2 composite sync/2-3 H-sync output)
+ *	JP8  video mode (1-2 PAL/2-3 NTSC)
+ *
+ *	With the following jumpering table you can connect the
+ *	FrameMaster II to a normal TV via SCART connector:
+ *	JP1:  2-3
+ *	JP4:  2-3
+ *	JP6:  2-3
+ *	JP8:  1-2 (means PAL for Europe)
+ *
+ *	NOTE:
+ *	There is no other possibility to change the video timings
+ *	except the interlaced/non interlaced, sync control and the
+ *	video mode PAL (50 Hz)/NTSC (60 Hz). Inside this
+ *	FrameMaster II driver are assumed values to avoid anomalies
+ *	to a future X server. Except the pixel clock is really
+ *	constant at 30 MHz.
+ *
+ *	9 pin female video connector:
+ *
+ *	1  analog red 0.7 Vss
+ *	2  analog green 0.7 Vss
+ *	3  analog blue 0.7 Vss
+ *	4  H-sync TTL
+ *	5  V-sync TTL
+ *	6  ground
+ *	7  ground
+ *	8  ground
+ *	9  ground
+ *
+ *	Some performance notes:
+ *	The FrameMaster II was not designed to display a console
+ *	this driver would do! It was designed to display still true
+ *	color images. Imagine: When scroll up a text line there
+ *	must copied ca. 1.7 MBytes to another place inside this
+ *	frame buffer. This means 1.7 MByte read and 1.7 MByte write
+ *	over the slow 16 bit wide Zorro2 bus! A scroll of one
+ *	line needs 1 second so do not expect to much from this
+ *	driver - he is at the limit!
+ *
+ */
+
+/*
+ *	definitions
+ */
+
+#define FRAMEMASTER_SIZE	0x200000
+#define FRAMEMASTER_REG		0x1ffff8
+
+#define FRAMEMASTER_NOLACE	1
+#define FRAMEMASTER_ENABLE	2
+#define FRAMEMASTER_COMPL	4
+#define FRAMEMASTER_ROM		8
+
+static volatile unsigned char *fm2fb_reg;
+
+static struct fb_fix_screeninfo fb_fix __devinitdata = {
+	.smem_len =	FRAMEMASTER_REG,
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_TRUECOLOR,
+	.line_length =	(768 << 2),
+	.mmio_len =	(8),
+	.accel =	FB_ACCEL_NONE,
+};
+
+static int fm2fb_mode __devinitdata = -1;
+
+#define FM2FB_MODE_PAL	0
+#define FM2FB_MODE_NTSC	1
+
+static struct fb_var_screeninfo fb_var_modes[] __devinitdata = {
+    {
+	/* 768 x 576, 32 bpp (PAL) */
+	768, 576, 768, 576, 0, 0, 32, 0,
+	{ 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 24, 8, 0 },
+	0, FB_ACTIVATE_NOW, -1, -1, FB_ACCEL_NONE,
+	33333, 10, 102, 10, 5, 80, 34, FB_SYNC_COMP_HIGH_ACT, 0
+    }, {
+	/* 768 x 480, 32 bpp (NTSC - not supported yet */
+	768, 480, 768, 480, 0, 0, 32, 0,
+	{ 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 24, 8, 0 },
+	0, FB_ACTIVATE_NOW, -1, -1, FB_ACCEL_NONE,
+	33333, 10, 102, 10, 5, 80, 34, FB_SYNC_COMP_HIGH_ACT, 0
+    }
+};
+
+    /*
+     *  Interface used by the world
+     */
+
+static int fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                           u_int transp, struct fb_info *info);
+static int fm2fb_blank(int blank, struct fb_info *info);
+
+static struct fb_ops fm2fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_setcolreg	= fm2fb_setcolreg,
+	.fb_blank	= fm2fb_blank,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+    /*
+     *  Blank the display.
+     */
+static int fm2fb_blank(int blank, struct fb_info *info)
+{
+	unsigned char t = FRAMEMASTER_ROM;
+
+	if (!blank)
+		t |= FRAMEMASTER_ENABLE | FRAMEMASTER_NOLACE;
+	fm2fb_reg[0] = t;
+	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 fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                         u_int transp, struct fb_info *info)
+{
+	if (regno > info->cmap.len)
+		return 1;
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	((u32*)(info->pseudo_palette))[regno] = (red << 16) | (green << 8) | blue;
+	return 0;
+}
+
+    /*
+     *  Initialisation
+     */
+
+static int __devinit fm2fb_probe(struct zorro_dev *z,
+				 const struct zorro_device_id *id);
+
+static struct zorro_device_id fm2fb_devices[] __devinitdata = {
+	{ ZORRO_PROD_BSC_FRAMEMASTER_II },
+	{ ZORRO_PROD_HELFRICH_RAINBOW_II },
+	{ 0 }
+};
+
+static struct zorro_driver fm2fb_driver = {
+	.name		= "fm2fb",
+	.id_table	= fm2fb_devices,
+	.probe		= fm2fb_probe,
+};
+
+static int __devinit fm2fb_probe(struct zorro_dev *z,
+				 const struct zorro_device_id *id)
+{
+	struct fb_info *info;
+	unsigned long *ptr;
+	int is_fm;
+	int x, y;
+
+	is_fm = z->id == ZORRO_PROD_BSC_FRAMEMASTER_II;
+
+	if (!zorro_request_device(z,"fm2fb"))
+		return -ENXIO;
+
+	info = framebuffer_alloc(256 * sizeof(u32), &z->dev);
+	if (!info) {
+		zorro_release_device(z);
+		return -ENOMEM;
+	}
+
+	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+		framebuffer_release(info);
+		zorro_release_device(z);
+		return -ENOMEM;
+	}
+
+	/* assigning memory to kernel space */
+	fb_fix.smem_start = zorro_resource_start(z);
+	info->screen_base = ioremap(fb_fix.smem_start, FRAMEMASTER_SIZE);
+	fb_fix.mmio_start = fb_fix.smem_start + FRAMEMASTER_REG;
+	fm2fb_reg  = (unsigned char *)(info->screen_base+FRAMEMASTER_REG);
+
+	strcpy(fb_fix.id, is_fm ? "FrameMaster II" : "Rainbow II");
+
+	/* make EBU color bars on display */
+	ptr = (unsigned long *)fb_fix.smem_start;
+	for (y = 0; y < 576; y++) {
+		for (x = 0; x < 96; x++) *ptr++ = 0xffffff;/* white */
+		for (x = 0; x < 96; x++) *ptr++ = 0xffff00;/* yellow */
+		for (x = 0; x < 96; x++) *ptr++ = 0x00ffff;/* cyan */
+		for (x = 0; x < 96; x++) *ptr++ = 0x00ff00;/* green */
+		for (x = 0; x < 96; x++) *ptr++ = 0xff00ff;/* magenta */
+		for (x = 0; x < 96; x++) *ptr++ = 0xff0000;/* red */
+		for (x = 0; x < 96; x++) *ptr++ = 0x0000ff;/* blue */
+		for (x = 0; x < 96; x++) *ptr++ = 0x000000;/* black */
+	}
+	fm2fb_blank(0, info);
+
+	if (fm2fb_mode == -1)
+		fm2fb_mode = FM2FB_MODE_PAL;
+
+	info->fbops = &fm2fb_ops;
+	info->var = fb_var_modes[fm2fb_mode];
+	info->pseudo_palette = info->par;
+	info->par = NULL;
+	info->fix = fb_fix;
+	info->flags = FBINFO_DEFAULT;
+
+	if (register_framebuffer(info) < 0) {
+		fb_dealloc_cmap(&info->cmap);
+		framebuffer_release(info);
+		zorro_release_device(z);
+		return -EINVAL;
+	}
+	printk("fb%d: %s frame buffer device\n", info->node, fb_fix.id);
+	return 0;
+}
+
+int __init fm2fb_setup(char *options)
+{
+	char *this_opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!strncmp(this_opt, "pal", 3))
+			fm2fb_mode = FM2FB_MODE_PAL;
+		else if (!strncmp(this_opt, "ntsc", 4))
+			fm2fb_mode = FM2FB_MODE_NTSC;
+	}
+	return 0;
+}
+
+int __init fm2fb_init(void)
+{
+	char *option = NULL;
+
+	if (fb_get_options("fm2fb", &option))
+		return -ENODEV;
+	fm2fb_setup(option);
+	return zorro_register_driver(&fm2fb_driver);
+}
+
+module_init(fm2fb_init);
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/g364fb.c b/drivers/video/g364fb.c
new file mode 100644
index 0000000..605d1a1
--- /dev/null
+++ b/drivers/video/g364fb.c
@@ -0,0 +1,258 @@
+/* $Id: g364fb.c,v 1.3 1998/08/28 22:43:00 tsbogend Exp $
+ *
+ * linux/drivers/video/g364fb.c -- Mips Magnum frame buffer device
+ *
+ * (C) 1998 Thomas Bogendoerfer
+ *
+ *  This driver is based on tgafb.c
+ *
+ *	Copyright (C) 1997 Geert Uytterhoeven 
+ *	Copyright (C) 1995  Jay Estabrook
+ *
+ *  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/module.h>
+#include <linux/console.h>
+#include <linux/sched.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 <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/jazz.h>
+
+/* 
+ * Various defines for the G364
+ */
+#define G364_MEM_BASE   0xe4400000
+#define G364_PORT_BASE  0xe4000000
+#define ID_REG 		0xe4000000	/* Read only */
+#define BOOT_REG 	0xe4080000
+#define TIMING_REG 	0xe4080108	/* to 0x080170 - DON'T TOUCH! */
+#define DISPLAY_REG 	0xe4080118
+#define VDISPLAY_REG 	0xe4080150
+#define MASK_REG 	0xe4080200
+#define CTLA_REG 	0xe4080300
+#define CURS_TOGGLE 	0x800000
+#define BIT_PER_PIX	0x700000	/* bits 22 to 20 of Control A */
+#define DELAY_SAMPLE    0x080000
+#define PORT_INTER	0x040000
+#define PIX_PIPE_DEL	0x030000	/* bits 17 and 16 of Control A */
+#define PIX_PIPE_DEL2	0x008000	/* same as above - don't ask me why */
+#define TR_CYCLE_TOG	0x004000
+#define VRAM_ADR_INC	0x003000	/* bits 13 and 12 of Control A */
+#define BLANK_OFF	0x000800
+#define FORCE_BLANK	0x000400
+#define BLK_FUN_SWTCH	0x000200
+#define BLANK_IO	0x000100
+#define BLANK_LEVEL	0x000080
+#define A_VID_FORM	0x000040
+#define D_SYNC_FORM	0x000020
+#define FRAME_FLY_PAT	0x000010
+#define OP_MODE		0x000008
+#define INTL_STAND	0x000004
+#define SCRN_FORM	0x000002
+#define ENABLE_VTG	0x000001
+#define TOP_REG 	0xe4080400
+#define CURS_PAL_REG 	0xe4080508	/* to 0x080518 */
+#define CHKSUM_REG 	0xe4080600	/* to 0x080610 - unused */
+#define CURS_POS_REG 	0xe4080638
+#define CLR_PAL_REG 	0xe4080800	/* to 0x080ff8 */
+#define CURS_PAT_REG 	0xe4081000	/* to 0x081ff8 */
+#define MON_ID_REG 	0xe4100000	/* unused */
+#define RESET_REG 	0xe4180000	/* Write only */
+
+static struct fb_info fb_info;
+
+static struct fb_fix_screeninfo fb_fix __initdata = {
+	.id 		= "G364 8plane",
+	.smem_start 	= 0x40000000,	/* physical address */
+	.type 		= FB_TYPE_PACKED_PIXELS,
+	.visual 	= FB_VISUAL_PSEUDOCOLOR,
+	.ypanstep 	= 1,
+	.accel 		= FB_ACCEL_NONE,
+};
+
+static struct fb_var_screeninfo fb_var __initdata = {
+	.bits_per_pixel = 8,
+	.red 		= { 0, 8, 0 },
+      	.green 		= { 0, 8, 0 },
+      	.blue		= { 0, 8, 0 },
+      	.activate	= FB_ACTIVATE_NOW,
+      	.height		= -1,
+      	.width		= -1,
+      	.pixclock	= 39722,
+      	.left_margin	= 40,
+      	.right_margin	= 24,
+      	.upper_margin	= 32,
+      	.lower_margin	= 11,
+      	.hsync_len 	= 96,
+      	.vsync_len 	= 2,
+      	.vmode		= FB_VMODE_NONINTERLACED,
+};
+
+/*
+ *  Interface used by the world
+ */
+int g364fb_init(void);
+
+static int g364fb_pan_display(struct fb_var_screeninfo *var,
+			      struct fb_info *info);
+static int g364fb_setcolreg(u_int regno, u_int red, u_int green,
+			    u_int blue, u_int transp,
+			    struct fb_info *info);
+static int g364fb_cursor(struct fb_info *info, struct fb_cursor *cursor);
+static int g364fb_blank(int blank, struct fb_info *info);
+
+static struct fb_ops g364fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_setcolreg	= g364fb_setcolreg,
+	.fb_pan_display	= g364fb_pan_display,
+	.fb_blank	= g364fb_blank,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= g364fb_cursor,
+};
+
+int g364fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+	
+	switch (cursor->enable) {
+	case CM_ERASE:
+		*(unsigned int *) CTLA_REG |= CURS_TOGGLE;
+		break;
+
+	case CM_MOVE:
+	case CM_DRAW:
+		*(unsigned int *) CTLA_REG &= ~CURS_TOGGLE;
+		*(unsigned int *) CURS_POS_REG =
+		    ((x * fontwidth(p)) << 12) | ((y * fontheight(p)) -
+						  info->var.yoffset);
+		break;
+	}
+	return 0;
+}
+
+/*
+ *  Pan or Wrap the Display
+ *
+ *  This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
+ */
+static int g364fb_pan_display(struct fb_var_screeninfo *var, 
+			      struct fb_info *info)
+{
+	if (var->xoffset || var->yoffset + var->yres > var->yres_virtual)
+		return -EINVAL;
+
+	*(unsigned int *) TOP_REG = var->yoffset * var->xres;
+	return 0;
+}
+
+/*
+ *  Blank the display.
+ */
+static int g364fb_blank(int blank, struct fb_info *info)
+{
+	if (blank)
+		*(unsigned int *) CTLA_REG |= FORCE_BLANK;
+	else
+		*(unsigned int *) CTLA_REG &= ~FORCE_BLANK;
+	return 0;
+}
+
+/*
+ *  Set a single color register. Return != 0 for invalid regno.
+ */
+static int g364fb_setcolreg(u_int regno, u_int red, u_int green,
+			    u_int blue, u_int transp, struct fb_info *info)
+{
+	volatile unsigned int *ptr = (volatile unsigned int *) CLR_PAL_REG;
+
+	if (regno > 255)
+		return 1;
+
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	ptr[regno << 1] = (red << 16) | (green << 8) | blue;
+
+	return 0;
+}
+
+/*
+ *  Initialisation
+ */
+int __init g364fb_init(void)
+{
+	volatile unsigned int *pal_ptr =
+	    (volatile unsigned int *) CLR_PAL_REG;
+	volatile unsigned int *curs_pal_ptr =
+	    (volatile unsigned int *) CURS_PAL_REG;
+	int mem, i, j;
+
+	if (fb_get_options("g364fb", NULL))
+		return -ENODEV;
+
+	/* TBD: G364 detection */
+
+	/* get the resolution set by ARC console */
+	*(volatile unsigned int *) CTLA_REG &= ~ENABLE_VTG;
+	fb_var.xres =
+	    (*((volatile unsigned int *) DISPLAY_REG) & 0x00ffffff) * 4;
+	fb_var.yres =
+	    (*((volatile unsigned int *) VDISPLAY_REG) & 0x00ffffff) / 2;
+	*(volatile unsigned int *) CTLA_REG |= ENABLE_VTG;
+
+	/* setup cursor */
+	curs_pal_ptr[0] |= 0x00ffffff;
+	curs_pal_ptr[2] |= 0x00ffffff;
+	curs_pal_ptr[4] |= 0x00ffffff;
+
+	/*
+	 * first set the whole cursor to transparent
+	 */
+	for (i = 0; i < 512; i++)
+		*(unsigned short *) (CURS_PAT_REG + i * 8) = 0;
+
+	/*
+	 * switch the last two lines to cursor palette 3
+	 * we assume here, that FONTSIZE_X is 8
+	 */
+	*(unsigned short *) (CURS_PAT_REG + 14 * 64) = 0xffff;
+	*(unsigned short *) (CURS_PAT_REG + 15 * 64) = 0xffff;
+	fb_var.xres_virtual = fbvar.xres;
+	fb_fix.line_length = (xres / 8) * fb_var.bits_per_pixel;
+	fb_fix.smem_start = 0x40000000;	/* physical address */
+	/* get size of video memory; this is special for the JAZZ hardware */
+	mem = (r4030_read_reg32(JAZZ_R4030_CONFIG) >> 8) & 3;
+	fb_fix.smem_len = (1 << (mem * 2)) * 512 * 1024;
+	fb_var.yres_virtual = fb_fix.smem_len / fb_var.xres;
+
+	fb_info.fbops = &g364fb_ops;
+	fb_info.screen_base = (char *) G364_MEM_BASE;	/* virtual kernel address */
+	fb_info.var = fb_var;
+	fb_info.fix = fb_fix;
+	fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+
+	fb_alloc_cmap(&fb_info.cmap, 255, 0);
+
+	if (register_framebuffer(&fb_info) < 0)
+		return -EINVAL;
+	return 0;
+}
+
+module_init(g364fb_init);
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c
new file mode 100644
index 0000000..2a02328
--- /dev/null
+++ b/drivers/video/gbefb.c
@@ -0,0 +1,1280 @@
+/*
+ *  SGI GBE frame buffer driver
+ *
+ *  Copyright (C) 1999 Silicon Graphics, Inc. - Jeffrey Newquist
+ *  Copyright (C) 2002 Vivien Chappelier <vivien.chappelier@linux-mips.org>
+ *
+ *  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/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+
+#ifdef CONFIG_X86
+#include <asm/mtrr.h>
+#endif
+#ifdef CONFIG_MIPS
+#include <asm/addrspace.h>
+#endif
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/tlbflush.h>
+
+#include <video/gbe.h>
+
+static struct sgi_gbe *gbe;
+
+struct gbefb_par {
+	struct fb_var_screeninfo var;
+	struct gbe_timing_info timing;
+	int valid;
+};
+
+#ifdef CONFIG_SGI_IP32
+#define GBE_BASE	0x16000000 /* SGI O2 */
+#endif
+
+#ifdef CONFIG_X86_VISWS
+#define GBE_BASE	0xd0000000 /* SGI Visual Workstation */
+#endif
+
+/* macro for fastest write-though access to the framebuffer */
+#ifdef CONFIG_MIPS
+#ifdef CONFIG_CPU_R10000
+#define pgprot_fb(_prot) (((_prot) & (~_CACHE_MASK)) | _CACHE_UNCACHED_ACCELERATED)
+#else
+#define pgprot_fb(_prot) (((_prot) & (~_CACHE_MASK)) | _CACHE_CACHABLE_NO_WA)
+#endif
+#endif
+#ifdef CONFIG_X86
+#define pgprot_fb(_prot) ((_prot) | _PAGE_PCD)
+#endif
+
+/*
+ *  RAM we reserve for the frame buffer. This defines the maximum screen
+ *  size
+ */
+#if CONFIG_FB_GBE_MEM > 8
+#error GBE Framebuffer cannot use more than 8MB of memory
+#endif
+
+#define TILE_SHIFT 16
+#define TILE_SIZE (1 << TILE_SHIFT)
+#define TILE_MASK (TILE_SIZE - 1)
+
+static unsigned int gbe_mem_size = CONFIG_FB_GBE_MEM * 1024*1024;
+static void *gbe_mem;
+static dma_addr_t gbe_dma_addr;
+unsigned long gbe_mem_phys;
+
+static struct {
+	uint16_t *cpu;
+	dma_addr_t dma;
+} gbe_tiles;
+
+static int gbe_revision;
+
+static int ypan, ywrap;
+
+static uint32_t pseudo_palette[256];
+
+static char *mode_option __initdata = NULL;
+
+/* default CRT mode */
+static struct fb_var_screeninfo default_var_CRT __initdata = {
+	/* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
+	.xres		= 640,
+	.yres		= 480,
+	.xres_virtual	= 640,
+	.yres_virtual	= 480,
+	.xoffset	= 0,
+	.yoffset	= 0,
+	.bits_per_pixel	= 8,
+	.grayscale	= 0,
+	.red		= { 0, 8, 0 },
+	.green		= { 0, 8, 0 },
+	.blue		= { 0, 8, 0 },
+	.transp		= { 0, 0, 0 },
+	.nonstd		= 0,
+	.activate	= 0,
+	.height		= -1,
+	.width		= -1,
+	.accel_flags	= 0,
+	.pixclock	= 39722,	/* picoseconds */
+	.left_margin	= 48,
+	.right_margin	= 16,
+	.upper_margin	= 33,
+	.lower_margin	= 10,
+	.hsync_len	= 96,
+	.vsync_len	= 2,
+	.sync		= 0,
+	.vmode		= FB_VMODE_NONINTERLACED,
+};
+
+/* default LCD mode */
+static struct fb_var_screeninfo default_var_LCD __initdata = {
+	/* 1600x1024, 8 bpp */
+	.xres		= 1600,
+	.yres		= 1024,
+	.xres_virtual	= 1600,
+	.yres_virtual	= 1024,
+	.xoffset	= 0,
+	.yoffset	= 0,
+	.bits_per_pixel	= 8,
+	.grayscale	= 0,
+	.red		= { 0, 8, 0 },
+	.green		= { 0, 8, 0 },
+	.blue		= { 0, 8, 0 },
+	.transp		= { 0, 0, 0 },
+	.nonstd		= 0,
+	.activate	= 0,
+	.height		= -1,
+	.width		= -1,
+	.accel_flags	= 0,
+	.pixclock	= 9353,
+	.left_margin	= 20,
+	.right_margin	= 30,
+	.upper_margin	= 37,
+	.lower_margin	= 3,
+	.hsync_len	= 20,
+	.vsync_len	= 3,
+	.sync		= 0,
+	.vmode		= FB_VMODE_NONINTERLACED
+};
+
+/* default modedb mode */
+/* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */
+static struct fb_videomode default_mode_CRT __initdata = {
+	.refresh	= 60,
+	.xres		= 640,
+	.yres		= 480,
+	.pixclock	= 39722,
+	.left_margin	= 48,
+	.right_margin	= 16,
+	.upper_margin	= 33,
+	.lower_margin	= 10,
+	.hsync_len	= 96,
+	.vsync_len	= 2,
+	.sync		= 0,
+	.vmode		= FB_VMODE_NONINTERLACED,
+};
+/* 1600x1024 SGI flatpanel 1600sw */
+static struct fb_videomode default_mode_LCD __initdata = {
+	/* 1600x1024, 8 bpp */
+	.xres		= 1600,
+	.yres		= 1024,
+	.pixclock	= 9353,
+	.left_margin	= 20,
+	.right_margin	= 30,
+	.upper_margin	= 37,
+	.lower_margin	= 3,
+	.hsync_len	= 20,
+	.vsync_len	= 3,
+	.vmode		= FB_VMODE_NONINTERLACED,
+};
+
+struct fb_videomode *default_mode = &default_mode_CRT;
+struct fb_var_screeninfo *default_var = &default_var_CRT;
+
+static int flat_panel_enabled = 0;
+
+static void gbe_reset(void)
+{
+	/* Turn on dotclock PLL */
+	gbe->ctrlstat = 0x300aa000;
+}
+
+
+/*
+ * Function:	gbe_turn_off
+ * Parameters:	(None)
+ * Description:	This should turn off the monitor and gbe.  This is used
+ *              when switching between the serial console and the graphics
+ *              console.
+ */
+
+void gbe_turn_off(void)
+{
+	int i;
+	unsigned int val, x, y, vpixen_off;
+
+	/* check if pixel counter is on */
+	val = gbe->vt_xy;
+	if (GET_GBE_FIELD(VT_XY, FREEZE, val) == 1)
+		return;
+
+	/* turn off DMA */
+	val = gbe->ovr_control;
+	SET_GBE_FIELD(OVR_CONTROL, OVR_DMA_ENABLE, val, 0);
+	gbe->ovr_control = val;
+	udelay(1000);
+	val = gbe->frm_control;
+	SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 0);
+	gbe->frm_control = val;
+	udelay(1000);
+	val = gbe->did_control;
+	SET_GBE_FIELD(DID_CONTROL, DID_DMA_ENABLE, val, 0);
+	gbe->did_control = val;
+	udelay(1000);
+
+	/* We have to wait through two vertical retrace periods before
+	 * the pixel DMA is turned off for sure. */
+	for (i = 0; i < 10000; i++) {
+		val = gbe->frm_inhwctrl;
+		if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, val)) {
+			udelay(10);
+		} else {
+			val = gbe->ovr_inhwctrl;
+			if (GET_GBE_FIELD(OVR_INHWCTRL, OVR_DMA_ENABLE, val)) {
+				udelay(10);
+			} else {
+				val = gbe->did_inhwctrl;
+				if (GET_GBE_FIELD(DID_INHWCTRL, DID_DMA_ENABLE, val)) {
+					udelay(10);
+				} else
+					break;
+			}
+		}
+	}
+	if (i == 10000)
+		printk(KERN_ERR "gbefb: turn off DMA timed out\n");
+
+	/* wait for vpixen_off */
+	val = gbe->vt_vpixen;
+	vpixen_off = GET_GBE_FIELD(VT_VPIXEN, VPIXEN_OFF, val);
+
+	for (i = 0; i < 100000; i++) {
+		val = gbe->vt_xy;
+		x = GET_GBE_FIELD(VT_XY, X, val);
+		y = GET_GBE_FIELD(VT_XY, Y, val);
+		if (y < vpixen_off)
+			break;
+		udelay(1);
+	}
+	if (i == 100000)
+		printk(KERN_ERR
+		       "gbefb: wait for vpixen_off timed out\n");
+	for (i = 0; i < 10000; i++) {
+		val = gbe->vt_xy;
+		x = GET_GBE_FIELD(VT_XY, X, val);
+		y = GET_GBE_FIELD(VT_XY, Y, val);
+		if (y > vpixen_off)
+			break;
+		udelay(1);
+	}
+	if (i == 10000)
+		printk(KERN_ERR "gbefb: wait for vpixen_off timed out\n");
+
+	/* turn off pixel counter */
+	val = 0;
+	SET_GBE_FIELD(VT_XY, FREEZE, val, 1);
+	gbe->vt_xy = val;
+	udelay(10000);
+	for (i = 0; i < 10000; i++) {
+		val = gbe->vt_xy;
+		if (GET_GBE_FIELD(VT_XY, FREEZE, val) != 1)
+			udelay(10);
+		else
+			break;
+	}
+	if (i == 10000)
+		printk(KERN_ERR "gbefb: turn off pixel clock timed out\n");
+
+	/* turn off dot clock */
+	val = gbe->dotclock;
+	SET_GBE_FIELD(DOTCLK, RUN, val, 0);
+	gbe->dotclock = val;
+	udelay(10000);
+	for (i = 0; i < 10000; i++) {
+		val = gbe->dotclock;
+		if (GET_GBE_FIELD(DOTCLK, RUN, val))
+			udelay(10);
+		else
+			break;
+	}
+	if (i == 10000)
+		printk(KERN_ERR "gbefb: turn off dotclock timed out\n");
+
+	/* reset the frame DMA FIFO */
+	val = gbe->frm_size_tile;
+	SET_GBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, val, 1);
+	gbe->frm_size_tile = val;
+	SET_GBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, val, 0);
+	gbe->frm_size_tile = val;
+}
+
+static void gbe_turn_on(void)
+{
+	unsigned int val, i;
+
+	/*
+	 * Check if pixel counter is off, for unknown reason this
+	 * code hangs Visual Workstations
+	 */
+	if (gbe_revision < 2) {
+		val = gbe->vt_xy;
+		if (GET_GBE_FIELD(VT_XY, FREEZE, val) == 0)
+			return;
+	}
+
+	/* turn on dot clock */
+	val = gbe->dotclock;
+	SET_GBE_FIELD(DOTCLK, RUN, val, 1);
+	gbe->dotclock = val;
+	udelay(10000);
+	for (i = 0; i < 10000; i++) {
+		val = gbe->dotclock;
+		if (GET_GBE_FIELD(DOTCLK, RUN, val) != 1)
+			udelay(10);
+		else
+			break;
+	}
+	if (i == 10000)
+		printk(KERN_ERR "gbefb: turn on dotclock timed out\n");
+
+	/* turn on pixel counter */
+	val = 0;
+	SET_GBE_FIELD(VT_XY, FREEZE, val, 0);
+	gbe->vt_xy = val;
+	udelay(10000);
+	for (i = 0; i < 10000; i++) {
+		val = gbe->vt_xy;
+		if (GET_GBE_FIELD(VT_XY, FREEZE, val))
+			udelay(10);
+		else
+			break;
+	}
+	if (i == 10000)
+		printk(KERN_ERR "gbefb: turn on pixel clock timed out\n");
+
+	/* turn on DMA */
+	val = gbe->frm_control;
+	SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 1);
+	gbe->frm_control = val;
+	udelay(1000);
+	for (i = 0; i < 10000; i++) {
+		val = gbe->frm_inhwctrl;
+		if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, val) != 1)
+			udelay(10);
+		else
+			break;
+	}
+	if (i == 10000)
+		printk(KERN_ERR "gbefb: turn on DMA timed out\n");
+}
+
+/*
+ *  Blank the display.
+ */
+static int gbefb_blank(int blank, struct fb_info *info)
+{
+	/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+	switch (blank) {
+	case FB_BLANK_UNBLANK:		/* unblank */
+		gbe_turn_on();
+		break;
+
+	case FB_BLANK_NORMAL:		/* blank */
+		gbe_turn_off();
+		break;
+
+	default:
+		/* Nothing */
+		break;
+	}
+	return 0;
+}
+
+/*
+ *  Setup flatpanel related registers.
+ */
+static void gbefb_setup_flatpanel(struct gbe_timing_info *timing)
+{
+	int fp_wid, fp_hgt, fp_vbs, fp_vbe;
+	u32 outputVal = 0;
+
+	SET_GBE_FIELD(VT_FLAGS, HDRV_INVERT, outputVal,
+		(timing->flags & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1);
+	SET_GBE_FIELD(VT_FLAGS, VDRV_INVERT, outputVal,
+		(timing->flags & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1);
+	gbe->vt_flags = outputVal;
+
+	/* Turn on the flat panel */
+	fp_wid = 1600;
+	fp_hgt = 1024;
+	fp_vbs = 0;
+	fp_vbe = 1600;
+	timing->pll_m = 4;
+	timing->pll_n = 1;
+	timing->pll_p = 0;
+
+	outputVal = 0;
+	SET_GBE_FIELD(FP_DE, ON, outputVal, fp_vbs);
+	SET_GBE_FIELD(FP_DE, OFF, outputVal, fp_vbe);
+	gbe->fp_de = outputVal;
+	outputVal = 0;
+	SET_GBE_FIELD(FP_HDRV, OFF, outputVal, fp_wid);
+	gbe->fp_hdrv = outputVal;
+	outputVal = 0;
+	SET_GBE_FIELD(FP_VDRV, ON, outputVal, 1);
+	SET_GBE_FIELD(FP_VDRV, OFF, outputVal, fp_hgt + 1);
+	gbe->fp_vdrv = outputVal;
+}
+
+struct gbe_pll_info {
+	int clock_rate;
+	int fvco_min;
+	int fvco_max;
+};
+
+static struct gbe_pll_info gbe_pll_table[2] = {
+	{ 20, 80, 220 },
+	{ 27, 80, 220 },
+};
+
+static int compute_gbe_timing(struct fb_var_screeninfo *var,
+			      struct gbe_timing_info *timing)
+{
+	int pll_m, pll_n, pll_p, error, best_m, best_n, best_p, best_error;
+	int pixclock;
+	struct gbe_pll_info *gbe_pll;
+
+	if (gbe_revision < 2)
+		gbe_pll = &gbe_pll_table[0];
+	else
+		gbe_pll = &gbe_pll_table[1];
+
+	/* Determine valid resolution and timing
+	 * GBE crystal runs at 20Mhz or 27Mhz
+	 * pll_m, pll_n, pll_p define the following frequencies
+	 * fvco = pll_m * 20Mhz / pll_n
+	 * fout = fvco / (2**pll_p) */
+	best_error = 1000000000;
+	best_n = best_m = best_p = 0;
+	for (pll_p = 0; pll_p < 4; pll_p++)
+		for (pll_m = 1; pll_m < 256; pll_m++)
+			for (pll_n = 1; pll_n < 64; pll_n++) {
+				pixclock = (1000000 / gbe_pll->clock_rate) *
+						(pll_n << pll_p) / pll_m;
+
+				error = var->pixclock - pixclock;
+
+				if (error < 0)
+					error = -error;
+
+				if (error < best_error &&
+				    pll_m / pll_n >
+				    gbe_pll->fvco_min / gbe_pll->clock_rate &&
+ 				    pll_m / pll_n <
+				    gbe_pll->fvco_max / gbe_pll->clock_rate) {
+					best_error = error;
+					best_m = pll_m;
+					best_n = pll_n;
+					best_p = pll_p;
+				}
+			}
+
+	if (!best_n || !best_m)
+		return -EINVAL;	/* Resolution to high */
+
+	pixclock = (1000000 / gbe_pll->clock_rate) *
+		(best_n << best_p) / best_m;
+
+	/* set video timing information */
+	if (timing) {
+		timing->width = var->xres;
+		timing->height = var->yres;
+		timing->pll_m = best_m;
+		timing->pll_n = best_n;
+		timing->pll_p = best_p;
+		timing->cfreq = gbe_pll->clock_rate * 1000 * timing->pll_m /
+			(timing->pll_n << timing->pll_p);
+		timing->htotal = var->left_margin + var->xres +
+				var->right_margin + var->hsync_len;
+		timing->vtotal = var->upper_margin + var->yres +
+				var->lower_margin + var->vsync_len;
+		timing->fields_sec = 1000 * timing->cfreq / timing->htotal *
+				1000 / timing->vtotal;
+		timing->hblank_start = var->xres;
+		timing->vblank_start = var->yres;
+		timing->hblank_end = timing->htotal;
+		timing->hsync_start = var->xres + var->right_margin + 1;
+		timing->hsync_end = timing->hsync_start + var->hsync_len;
+		timing->vblank_end = timing->vtotal;
+		timing->vsync_start = var->yres + var->lower_margin + 1;
+		timing->vsync_end = timing->vsync_start + var->vsync_len;
+	}
+
+	return pixclock;
+}
+
+static void gbe_set_timing_info(struct gbe_timing_info *timing)
+{
+	int temp;
+	unsigned int val;
+
+	/* setup dot clock PLL */
+	val = 0;
+	SET_GBE_FIELD(DOTCLK, M, val, timing->pll_m - 1);
+	SET_GBE_FIELD(DOTCLK, N, val, timing->pll_n - 1);
+	SET_GBE_FIELD(DOTCLK, P, val, timing->pll_p);
+	SET_GBE_FIELD(DOTCLK, RUN, val, 0);	/* do not start yet */
+	gbe->dotclock = val;
+	udelay(10000);
+
+	/* setup pixel counter */
+	val = 0;
+	SET_GBE_FIELD(VT_XYMAX, MAXX, val, timing->htotal);
+	SET_GBE_FIELD(VT_XYMAX, MAXY, val, timing->vtotal);
+	gbe->vt_xymax = val;
+
+	/* setup video timing signals */
+	val = 0;
+	SET_GBE_FIELD(VT_VSYNC, VSYNC_ON, val, timing->vsync_start);
+	SET_GBE_FIELD(VT_VSYNC, VSYNC_OFF, val, timing->vsync_end);
+	gbe->vt_vsync = val;
+	val = 0;
+	SET_GBE_FIELD(VT_HSYNC, HSYNC_ON, val, timing->hsync_start);
+	SET_GBE_FIELD(VT_HSYNC, HSYNC_OFF, val, timing->hsync_end);
+	gbe->vt_hsync = val;
+	val = 0;
+	SET_GBE_FIELD(VT_VBLANK, VBLANK_ON, val, timing->vblank_start);
+	SET_GBE_FIELD(VT_VBLANK, VBLANK_OFF, val, timing->vblank_end);
+	gbe->vt_vblank = val;
+	val = 0;
+	SET_GBE_FIELD(VT_HBLANK, HBLANK_ON, val,
+		      timing->hblank_start - 5);
+	SET_GBE_FIELD(VT_HBLANK, HBLANK_OFF, val,
+		      timing->hblank_end - 3);
+	gbe->vt_hblank = val;
+
+	/* setup internal timing signals */
+	val = 0;
+	SET_GBE_FIELD(VT_VCMAP, VCMAP_ON, val, timing->vblank_start);
+	SET_GBE_FIELD(VT_VCMAP, VCMAP_OFF, val, timing->vblank_end);
+	gbe->vt_vcmap = val;
+	val = 0;
+	SET_GBE_FIELD(VT_HCMAP, HCMAP_ON, val, timing->hblank_start);
+	SET_GBE_FIELD(VT_HCMAP, HCMAP_OFF, val, timing->hblank_end);
+	gbe->vt_hcmap = val;
+
+	val = 0;
+	temp = timing->vblank_start - timing->vblank_end - 1;
+	if (temp > 0)
+		temp = -temp;
+
+	if (flat_panel_enabled)
+		gbefb_setup_flatpanel(timing);
+
+	SET_GBE_FIELD(DID_START_XY, DID_STARTY, val, (u32) temp);
+	if (timing->hblank_end >= 20)
+		SET_GBE_FIELD(DID_START_XY, DID_STARTX, val,
+			      timing->hblank_end - 20);
+	else
+		SET_GBE_FIELD(DID_START_XY, DID_STARTX, val,
+			      timing->htotal - (20 - timing->hblank_end));
+	gbe->did_start_xy = val;
+
+	val = 0;
+	SET_GBE_FIELD(CRS_START_XY, CRS_STARTY, val, (u32) (temp + 1));
+	if (timing->hblank_end >= GBE_CRS_MAGIC)
+		SET_GBE_FIELD(CRS_START_XY, CRS_STARTX, val,
+			      timing->hblank_end - GBE_CRS_MAGIC);
+	else
+		SET_GBE_FIELD(CRS_START_XY, CRS_STARTX, val,
+			      timing->htotal - (GBE_CRS_MAGIC -
+						timing->hblank_end));
+	gbe->crs_start_xy = val;
+
+	val = 0;
+	SET_GBE_FIELD(VC_START_XY, VC_STARTY, val, (u32) temp);
+	SET_GBE_FIELD(VC_START_XY, VC_STARTX, val, timing->hblank_end - 4);
+	gbe->vc_start_xy = val;
+
+	val = 0;
+	temp = timing->hblank_end - GBE_PIXEN_MAGIC_ON;
+	if (temp < 0)
+		temp += timing->htotal;	/* allow blank to wrap around */
+
+	SET_GBE_FIELD(VT_HPIXEN, HPIXEN_ON, val, temp);
+	SET_GBE_FIELD(VT_HPIXEN, HPIXEN_OFF, val,
+		      ((temp + timing->width -
+			GBE_PIXEN_MAGIC_OFF) % timing->htotal));
+	gbe->vt_hpixen = val;
+
+	val = 0;
+	SET_GBE_FIELD(VT_VPIXEN, VPIXEN_ON, val, timing->vblank_end);
+	SET_GBE_FIELD(VT_VPIXEN, VPIXEN_OFF, val, timing->vblank_start);
+	gbe->vt_vpixen = val;
+
+	/* turn off sync on green */
+	val = 0;
+	SET_GBE_FIELD(VT_FLAGS, SYNC_LOW, val, 1);
+	gbe->vt_flags = val;
+}
+
+/*
+ *  Set the hardware according to 'par'.
+ */
+
+static int gbefb_set_par(struct fb_info *info)
+{
+	int i;
+	unsigned int val;
+	int wholeTilesX, partTilesX, maxPixelsPerTileX;
+	int height_pix;
+	int xpmax, ypmax;	/* Monitor resolution */
+	int bytesPerPixel;	/* Bytes per pixel */
+	struct gbefb_par *par = (struct gbefb_par *) info->par;
+
+	compute_gbe_timing(&info->var, &par->timing);
+
+	bytesPerPixel = info->var.bits_per_pixel / 8;
+	info->fix.line_length = info->var.xres_virtual * bytesPerPixel;
+	xpmax = par->timing.width;
+	ypmax = par->timing.height;
+
+	/* turn off GBE */
+	gbe_turn_off();
+
+	/* set timing info */
+	gbe_set_timing_info(&par->timing);
+
+	/* initialize DIDs */
+	val = 0;
+	switch (bytesPerPixel) {
+	case 1:
+		SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_I8);
+		break;
+	case 2:
+		SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_ARGB5);
+		break;
+	case 4:
+		SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_RGB8);
+		break;
+	}
+	SET_GBE_FIELD(WID, BUF, val, GBE_BMODE_BOTH);
+
+	for (i = 0; i < 32; i++)
+		gbe->mode_regs[i] = val;
+
+	/* Initialize interrupts */
+	gbe->vt_intr01 = 0xffffffff;
+	gbe->vt_intr23 = 0xffffffff;
+
+	/* 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.
+	   Tiles are still allocated as independent chunks of 64KB of
+	   continuous physical memory and remapped so that the kernel sees the
+	   framebuffer as a continuous virtual memory. The GBE tile table is
+	   set up so that each tile references one of these 64k blocks:
+
+	   GBE -> tile list    framebuffer           TLB   <------------ CPU
+	          [ tile 0 ] -> [ 64KB ]  <- [ 16x 4KB page entries ]     ^
+	             ...           ...              ...       linear virtual FB
+	          [ tile n ] -> [ 64KB ]  <- [ 16x 4KB page entries ]     v
+
+
+	   The GBE hardware is then told that the buffer is 512*tweaked_height,
+	   with tweaked_height = real_width*real_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, 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.
+	 */
+
+	/* Tell gbe about the tiles table location */
+	/* tile_ptr -> [ tile 1 ] -> FB mem */
+	/*             [ tile 2 ] -> FB mem */
+	/*               ...                */
+	val = 0;
+	SET_GBE_FIELD(FRM_CONTROL, FRM_TILE_PTR, val, gbe_tiles.dma >> 9);
+	SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 0); /* do not start */
+	SET_GBE_FIELD(FRM_CONTROL, FRM_LINEAR, val, 0);
+	gbe->frm_control = val;
+
+	maxPixelsPerTileX = 512 / bytesPerPixel;
+	wholeTilesX = 1;
+	partTilesX = 0;
+
+	/* Initialize the framebuffer */
+	val = 0;
+	SET_GBE_FIELD(FRM_SIZE_TILE, FRM_WIDTH_TILE, val, wholeTilesX);
+	SET_GBE_FIELD(FRM_SIZE_TILE, FRM_RHS, val, partTilesX);
+
+	switch (bytesPerPixel) {
+	case 1:
+		SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
+			      GBE_FRM_DEPTH_8);
+		break;
+	case 2:
+		SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
+			      GBE_FRM_DEPTH_16);
+		break;
+	case 4:
+		SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
+			      GBE_FRM_DEPTH_32);
+		break;
+	}
+	gbe->frm_size_tile = val;
+
+	/* compute tweaked height */
+	height_pix = xpmax * ypmax / maxPixelsPerTileX;
+
+	val = 0;
+	SET_GBE_FIELD(FRM_SIZE_PIXEL, FB_HEIGHT_PIX, val, height_pix);
+	gbe->frm_size_pixel = val;
+
+	/* turn off DID and overlay DMA */
+	gbe->did_control = 0;
+	gbe->ovr_width_tile = 0;
+
+	/* Turn off mouse cursor */
+	gbe->crs_ctl = 0;
+
+	/* Turn on GBE */
+	gbe_turn_on();
+
+	/* Initialize the gamma map */
+	udelay(10);
+	for (i = 0; i < 256; i++)
+		gbe->gmap[i] = (i << 24) | (i << 16) | (i << 8);
+
+	/* Initialize the color map */
+	for (i = 0; i < 256; i++) {
+		int j;
+
+		for (j = 0; j < 1000 && gbe->cm_fifo >= 63; j++)
+			udelay(10);
+		if (j == 1000)
+			printk(KERN_ERR "gbefb: cmap FIFO timeout\n");
+
+		gbe->cmap[i] = (i << 8) | (i << 16) | (i << 24);
+	}
+
+	return 0;
+}
+
+static void gbefb_encode_fix(struct fb_fix_screeninfo *fix,
+			     struct fb_var_screeninfo *var)
+{
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+	strcpy(fix->id, "SGI GBE");
+	fix->smem_start = (unsigned long) gbe_mem;
+	fix->smem_len = gbe_mem_size;
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->type_aux = 0;
+	fix->accel = FB_ACCEL_NONE;
+	switch (var->bits_per_pixel) {
+	case 8:
+		fix->visual = FB_VISUAL_PSEUDOCOLOR;
+		break;
+	default:
+		fix->visual = FB_VISUAL_TRUECOLOR;
+		break;
+	}
+	fix->ywrapstep = 0;
+	fix->xpanstep = 0;
+	fix->ypanstep = 0;
+	fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
+	fix->mmio_start = GBE_BASE;
+	fix->mmio_len = sizeof(struct sgi_gbe);
+}
+
+/*
+ *  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 gbefb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			     unsigned blue, unsigned transp,
+			     struct fb_info *info)
+{
+	int i;
+
+	if (regno > 255)
+		return 1;
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	switch (info->var.bits_per_pixel) {
+	case 8:
+		/* wait for the color map FIFO to have a free entry */
+		for (i = 0; i < 1000 && gbe->cm_fifo >= 63; i++)
+			udelay(10);
+		if (i == 1000) {
+			printk(KERN_ERR "gbefb: cmap FIFO timeout\n");
+			return 1;
+		}
+		gbe->cmap[regno] = (red << 24) | (green << 16) | (blue << 8);
+		break;
+	case 15:
+	case 16:
+		red >>= 3;
+		green >>= 3;
+		blue >>= 3;
+		pseudo_palette[regno] =
+			(red << info->var.red.offset) |
+			(green << info->var.green.offset) |
+			(blue << info->var.blue.offset);
+		break;
+	case 32:
+		pseudo_palette[regno] =
+			(red << info->var.red.offset) |
+			(green << info->var.green.offset) |
+			(blue << info->var.blue.offset);
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ *  Check video mode validity, eventually modify var to best match.
+ */
+static int gbefb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	unsigned int line_length;
+	struct gbe_timing_info timing;
+
+	/* 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;
+
+	/* Check the mode can be mapped linearly with the tile table trick. */
+	/* This requires width x height x bytes/pixel be a multiple of 512 */
+	if ((var->xres * var->yres * var->bits_per_pixel) & 4095)
+		return -EINVAL;
+
+	var->grayscale = 0;	/* No grayscale for now */
+
+	if ((var->pixclock = compute_gbe_timing(var, &timing)) < 0)
+		return(-EINVAL);
+
+	/* 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;
+
+	if (var->vmode & FB_VMODE_CONUPDATE) {
+		var->vmode |= FB_VMODE_YWRAP;
+		var->xoffset = info->var.xoffset;
+		var->yoffset = info->var.yoffset;
+	}
+
+	/* No grayscale for now */
+	var->grayscale = 0;
+
+	/* Memory limit */
+	line_length = var->xres_virtual * var->bits_per_pixel / 8;
+	if (line_length * var->yres_virtual > gbe_mem_size)
+		return -ENOMEM;	/* Virtual resolution too 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:		/* RGB 1555 */
+		var->red.offset = 10;
+		var->red.length = 5;
+		var->green.offset = 5;
+		var->green.length = 5;
+		var->blue.offset = 0;
+		var->blue.length = 5;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		break;
+	case 32:		/* RGB 8888 */
+		var->red.offset = 24;
+		var->red.length = 8;
+		var->green.offset = 16;
+		var->green.length = 8;
+		var->blue.offset = 8;
+		var->blue.length = 8;
+		var->transp.offset = 0;
+		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;
+
+	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;
+
+	return 0;
+}
+
+static int gbefb_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;
+	unsigned long addr;
+	unsigned long phys_addr, phys_size;
+	u16 *tile;
+
+	/* check range */
+	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+		return -EINVAL;
+	if (offset + size > gbe_mem_size)
+		return -EINVAL;
+
+	/* remap using the fastest write-through mode on architecture */
+	/* try not polluting the cache when possible */
+	pgprot_val(vma->vm_page_prot) =
+		pgprot_fb(pgprot_val(vma->vm_page_prot));
+
+	vma->vm_flags |= VM_IO | VM_RESERVED;
+	vma->vm_file = file;
+
+	/* look for the starting tile */
+	tile = &gbe_tiles.cpu[offset >> TILE_SHIFT];
+	addr = vma->vm_start;
+	offset &= TILE_MASK;
+
+	/* remap each tile separately */
+	do {
+		phys_addr = (((unsigned long) (*tile)) << TILE_SHIFT) + offset;
+		if ((offset + size) < TILE_SIZE)
+			phys_size = size;
+		else
+			phys_size = TILE_SIZE - offset;
+
+		if (remap_pfn_range(vma, addr, phys_addr >> PAGE_SHIFT,
+						phys_size, vma->vm_page_prot))
+			return -EAGAIN;
+
+		offset = 0;
+		size -= phys_size;
+		addr += phys_size;
+		tile++;
+	} while (size);
+
+	return 0;
+}
+
+static struct fb_ops gbefb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= gbefb_check_var,
+	.fb_set_par	= gbefb_set_par,
+	.fb_setcolreg	= gbefb_setcolreg,
+	.fb_mmap	= gbefb_mmap,
+	.fb_blank	= gbefb_blank,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+/*
+ * sysfs
+ */
+
+static ssize_t gbefb_show_memsize(struct device *dev, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", gbe_mem_size);
+}
+
+static DEVICE_ATTR(size, S_IRUGO, gbefb_show_memsize, NULL);
+
+static ssize_t gbefb_show_rev(struct device *device, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", gbe_revision);
+}
+
+static DEVICE_ATTR(revision, S_IRUGO, gbefb_show_rev, NULL);
+
+static void __devexit gbefb_remove_sysfs(struct device *dev)
+{
+	device_remove_file(dev, &dev_attr_size);
+	device_remove_file(dev, &dev_attr_revision);
+}
+
+static void gbefb_create_sysfs(struct device *dev)
+{
+	device_create_file(dev, &dev_attr_size);
+	device_create_file(dev, &dev_attr_revision);
+}
+
+/*
+ * Initialization
+ */
+
+int __init gbefb_setup(char *options)
+{
+	char *this_opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!strncmp(this_opt, "monitor:", 8)) {
+			if (!strncmp(this_opt + 8, "crt", 3)) {
+				flat_panel_enabled = 0;
+				default_var = &default_var_CRT;
+				default_mode = &default_mode_CRT;
+			} else if (!strncmp(this_opt + 8, "1600sw", 6) ||
+				   !strncmp(this_opt + 8, "lcd", 3)) {
+				flat_panel_enabled = 1;
+				default_var = &default_var_LCD;
+				default_mode = &default_mode_LCD;
+			}
+		} else if (!strncmp(this_opt, "mem:", 4)) {
+			gbe_mem_size = memparse(this_opt + 4, &this_opt);
+			if (gbe_mem_size > CONFIG_FB_GBE_MEM * 1024 * 1024)
+				gbe_mem_size = CONFIG_FB_GBE_MEM * 1024 * 1024;
+			if (gbe_mem_size < TILE_SIZE)
+				gbe_mem_size = TILE_SIZE;
+		} else
+			mode_option = this_opt;
+	}
+	return 0;
+}
+
+static int __init gbefb_probe(struct device *dev)
+{
+	int i, ret = 0;
+	struct fb_info *info;
+	struct gbefb_par *par;
+	struct platform_device *p_dev = to_platform_device(dev);
+#ifndef MODULE
+	char *options = NULL;
+#endif
+
+	info = framebuffer_alloc(sizeof(struct gbefb_par), &p_dev->dev);
+	if (!info)
+		return -ENOMEM;
+
+#ifndef MODULE
+	if (fb_get_options("gbefb", &options))
+		return -ENODEV;
+	gbefb_setup(options);
+#endif
+
+	if (!request_mem_region(GBE_BASE, sizeof(struct sgi_gbe), "GBE")) {
+		printk(KERN_ERR "gbefb: couldn't reserve mmio region\n");
+		ret = -EBUSY;
+		goto out_release_framebuffer;
+	}
+
+	gbe = (struct sgi_gbe *) ioremap(GBE_BASE, sizeof(struct sgi_gbe));
+	if (!gbe) {
+		printk(KERN_ERR "gbefb: couldn't map mmio region\n");
+		ret = -ENXIO;
+		goto out_release_mem_region;
+	}
+	gbe_revision = gbe->ctrlstat & 15;
+
+	gbe_tiles.cpu =
+		dma_alloc_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),
+				   &gbe_tiles.dma, GFP_KERNEL);
+	if (!gbe_tiles.cpu) {
+		printk(KERN_ERR "gbefb: couldn't allocate tiles table\n");
+		ret = -ENOMEM;
+		goto out_unmap;
+	}
+
+	if (gbe_mem_phys) {
+		/* memory was allocated at boot time */
+		gbe_mem = ioremap_nocache(gbe_mem_phys, gbe_mem_size);
+		gbe_dma_addr = 0;
+	} else {
+		/* try to allocate memory with the classical allocator
+		 * this has high chance to fail on low memory machines */
+		gbe_mem = dma_alloc_coherent(NULL, gbe_mem_size, &gbe_dma_addr,
+					     GFP_KERNEL);
+		gbe_mem_phys = (unsigned long) gbe_dma_addr;
+	}
+
+#ifdef CONFIG_X86
+	mtrr_add(gbe_mem_phys, gbe_mem_size, MTRR_TYPE_WRCOMB, 1);
+#endif
+
+	if (!gbe_mem) {
+		printk(KERN_ERR "gbefb: couldn't map framebuffer\n");
+		ret = -ENXIO;
+		goto out_tiles_free;
+	}
+
+	/* map framebuffer memory into tiles table */
+	for (i = 0; i < (gbe_mem_size >> TILE_SHIFT); i++)
+		gbe_tiles.cpu[i] = (gbe_mem_phys >> TILE_SHIFT) + i;
+
+	info->fbops = &gbefb_ops;
+	info->pseudo_palette = pseudo_palette;
+	info->flags = FBINFO_DEFAULT;
+	info->screen_base = gbe_mem;
+	fb_alloc_cmap(&info->cmap, 256, 0);
+
+	/* reset GBE */
+	gbe_reset();
+
+	par = info->par;
+	/* turn on default video mode */
+	if (fb_find_mode(&par->var, info, mode_option, NULL, 0,
+			 default_mode, 8) == 0)
+		par->var = *default_var;
+	info->var = par->var;
+	gbefb_check_var(&par->var, info);
+	gbefb_encode_fix(&info->fix, &info->var);
+
+	if (register_framebuffer(info) < 0) {
+		printk(KERN_ERR "gbefb: couldn't register framebuffer\n");
+		ret = -ENXIO;
+		goto out_gbe_unmap;
+	}
+
+	dev_set_drvdata(&p_dev->dev, info);
+	gbefb_create_sysfs(dev);
+
+	printk(KERN_INFO "fb%d: %s rev %d @ 0x%08x using %dkB memory\n",
+	       info->node, info->fix.id, gbe_revision, (unsigned) GBE_BASE,
+	       gbe_mem_size >> 10);
+
+	return 0;
+
+out_gbe_unmap:
+	if (gbe_dma_addr)
+		dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys);
+	else
+		iounmap(gbe_mem);
+out_tiles_free:
+	dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),
+			  (void *)gbe_tiles.cpu, gbe_tiles.dma);
+out_unmap:
+	iounmap(gbe);
+out_release_mem_region:
+	release_mem_region(GBE_BASE, sizeof(struct sgi_gbe));
+out_release_framebuffer:
+	framebuffer_release(info);
+
+	return ret;
+}
+
+static int __devexit gbefb_remove(struct device* dev)
+{
+	struct platform_device *p_dev = to_platform_device(dev);
+	struct fb_info *info = dev_get_drvdata(&p_dev->dev);
+
+	unregister_framebuffer(info);
+	gbe_turn_off();
+	if (gbe_dma_addr)
+		dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys);
+	else
+		iounmap(gbe_mem);
+	dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),
+			  (void *)gbe_tiles.cpu, gbe_tiles.dma);
+	release_mem_region(GBE_BASE, sizeof(struct sgi_gbe));
+	iounmap(gbe);
+	gbefb_remove_sysfs(dev);
+	framebuffer_release(info);
+
+	return 0;
+}
+
+static struct device_driver gbefb_driver = {
+	.name = "gbefb",
+	.bus = &platform_bus_type,
+	.probe = gbefb_probe,
+	.remove = __devexit_p(gbefb_remove),
+};
+
+static struct platform_device gbefb_device = {
+	.name = "gbefb",
+};
+
+int __init gbefb_init(void)
+{
+	int ret = driver_register(&gbefb_driver);
+	if (!ret) {
+		ret = platform_device_register(&gbefb_device);
+		if (ret)
+			driver_unregister(&gbefb_driver);
+	}
+	return ret;
+}
+
+void __exit gbefb_exit(void)
+{
+	 driver_unregister(&gbefb_driver);
+}
+
+module_init(gbefb_init);
+module_exit(gbefb_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/geode/Kconfig b/drivers/video/geode/Kconfig
new file mode 100644
index 0000000..b075fd0
--- /dev/null
+++ b/drivers/video/geode/Kconfig
@@ -0,0 +1,29 @@
+#
+# Geode family framebuffer configuration
+#
+config FB_GEODE
+	bool "AMD Geode family framebuffer support (EXPERIMENTAL)"
+	default n
+	depends on FB && EXPERIMENTAL && X86
+	---help---
+	  Say 'Y' here to allow you to select framebuffer drivers for
+	  the AMD Geode family of processors.
+
+config FB_GEODE_GX1
+	tristate "AMD Geode GX1 framebuffer support (EXPERIMENTAL)"
+	default n
+	depends on FB_GEODE && EXPERIMENTAL
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_SOFT_CURSOR
+	---help---
+	  Framebuffer driver for the display controller integrated into the
+	  AMD Geode GX1 processor.
+
+	  This driver is also available as a module ( = code which can be
+	  inserted and removed from the running kernel whenever you want). The
+	  module will be called gx1fb. If you want to compile it as a module,
+	  say M here and read <file:Documentation/modules.txt>.
+
+	  If unsure, say N.
diff --git a/drivers/video/geode/Makefile b/drivers/video/geode/Makefile
new file mode 100644
index 0000000..13ad501e
--- /dev/null
+++ b/drivers/video/geode/Makefile
@@ -0,0 +1,5 @@
+# Makefile for the Geode family framebuffer drivers
+
+obj-$(CONFIG_FB_GEODE_GX1) += gx1fb.o
+
+gx1fb-objs   		:= gx1fb_core.o display_gx1.o video_cs5530.o
diff --git a/drivers/video/geode/display_gx1.c b/drivers/video/geode/display_gx1.c
new file mode 100644
index 0000000..f498387
--- /dev/null
+++ b/drivers/video/geode/display_gx1.c
@@ -0,0 +1,214 @@
+/*
+ * drivers/video/geode/display_gx1.c
+ *   -- Geode GX1 display controller
+ *
+ * Copyright (C) 2005 Arcom Control Systems Ltd.
+ *
+ * Based on AMD's original 2.4 driver:
+ *   Copyright (C) 2004 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/spinlock.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/div64.h>
+#include <asm/delay.h>
+
+#include "geodefb.h"
+#include "display_gx1.h"
+
+static spinlock_t gx1_conf_reg_lock = SPIN_LOCK_UNLOCKED;
+
+static u8 gx1_read_conf_reg(u8 reg)
+{
+	u8 val, ccr3;
+	unsigned long flags;
+
+	spin_lock_irqsave(&gx1_conf_reg_lock, flags);
+
+	outb(CONFIG_CCR3, 0x22);
+	ccr3 = inb(0x23);
+	outb(CONFIG_CCR3, 0x22);
+	outb(ccr3 | CONFIG_CCR3_MAPEN, 0x23);
+	outb(reg, 0x22);
+	val = inb(0x23);
+	outb(CONFIG_CCR3, 0x22);
+	outb(ccr3, 0x23);
+
+	spin_unlock_irqrestore(&gx1_conf_reg_lock, flags);
+
+	return val;
+}
+
+unsigned gx1_gx_base(void)
+{
+	return (gx1_read_conf_reg(CONFIG_GCR) & 0x03) << 30;
+}
+
+int gx1_frame_buffer_size(void)
+{
+	void __iomem *mc_regs;
+	u32 bank_cfg;
+	int d;
+	unsigned dram_size = 0, fb_base;
+
+	mc_regs = ioremap(gx1_gx_base() + 0x8400, 0x100);
+	if (!mc_regs)
+		return -ENOMEM;
+
+
+	/* Calculate the total size of both DIMM0 and DIMM1. */
+	bank_cfg = readl(mc_regs + MC_BANK_CFG);
+
+	for (d = 0; d < 2; d++) {
+		if ((bank_cfg & MC_BCFG_DIMM0_PG_SZ_MASK) != MC_BCFG_DIMM0_PG_SZ_NO_DIMM)
+			dram_size += 0x400000 << ((bank_cfg & MC_BCFG_DIMM0_SZ_MASK) >> 8);
+		bank_cfg >>= 16; /* look at DIMM1 next */
+	}
+
+	fb_base = (readl(mc_regs + MC_GBASE_ADD) & MC_GADD_GBADD_MASK) << 19;
+
+	iounmap(mc_regs);
+
+	return dram_size - fb_base;
+}
+
+static void gx1_set_mode(struct fb_info *info)
+{
+	struct geodefb_par *par = info->par;
+	u32 gcfg, tcfg, ocfg, dclk_div, val;
+	int hactive, hblankstart, hsyncstart, hsyncend, hblankend, htotal;
+	int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal;
+
+	/* Unlock the display controller registers. */
+	readl(par->dc_regs + DC_UNLOCK);
+	writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK);
+
+	gcfg = readl(par->dc_regs + DC_GENERAL_CFG);
+	tcfg = readl(par->dc_regs + DC_TIMING_CFG);
+
+	/* Blank the display and disable the timing generator. */
+	tcfg &= ~(DC_TCFG_BLKE | DC_TCFG_TGEN);
+	writel(tcfg, par->dc_regs + DC_TIMING_CFG);
+
+	/* Wait for pending memory requests before disabling the FIFO load. */
+	udelay(100);
+
+	/* Disable FIFO load and compression. */
+	gcfg &= ~(DC_GCFG_DFLE | DC_GCFG_CMPE | DC_GCFG_DECE);
+	writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
+
+	/* Setup DCLK and its divisor. */
+	gcfg &= ~DC_GCFG_DCLK_MASK;
+	writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
+
+	par->vid_ops->set_dclk(info);
+
+	dclk_div = DC_GCFG_DCLK_DIV_1; /* FIXME: may need to divide DCLK by 2 sometimes? */
+	gcfg |= dclk_div;
+	writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
+
+	/* Wait for the clock generatation to settle.  This is needed since
+	 * some of the register writes that follow require that clock to be
+	 * present. */
+	udelay(1000); /* FIXME: seems a little long */
+
+	/*
+	 * Setup new mode.
+	 */
+
+	/* Clear all unused feature bits. */
+	gcfg = DC_GCFG_VRDY | dclk_div;
+
+	/* Set FIFO priority (default 6/5) and enable. */
+	/* FIXME: increase fifo priority for 1280x1024 modes? */
+	gcfg |= (6 << DC_GCFG_DFHPEL_POS) | (5 << DC_GCFG_DFHPSL_POS) | DC_GCFG_DFLE;
+
+	/* FIXME: Set pixel and line double bits if necessary. */
+
+	/* Framebuffer start offset. */
+	writel(0, par->dc_regs + DC_FB_ST_OFFSET);
+
+	/* Line delta and line buffer length. */
+	writel(info->fix.line_length >> 2, par->dc_regs + DC_LINE_DELTA);
+	writel(((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2,
+	       par->dc_regs + DC_BUF_SIZE);
+
+	/* Output configuration. Enable panel data, set pixel format. */
+	ocfg = DC_OCFG_PCKE | DC_OCFG_PDEL | DC_OCFG_PDEH;
+	if (info->var.bits_per_pixel == 8) ocfg |= DC_OCFG_8BPP;
+
+	/* Enable timing generator, sync and FP data. */
+	tcfg = DC_TCFG_FPPE | DC_TCFG_HSYE | DC_TCFG_VSYE | DC_TCFG_BLKE
+		| DC_TCFG_TGEN;
+
+	/* Horizontal and vertical timings. */
+	hactive = info->var.xres;
+	hblankstart = hactive;
+	hsyncstart = hblankstart + info->var.right_margin;
+	hsyncend =  hsyncstart + info->var.hsync_len;
+	hblankend = hsyncend + info->var.left_margin;
+	htotal = hblankend;
+
+	vactive = info->var.yres;
+	vblankstart = vactive;
+	vsyncstart = vblankstart + info->var.lower_margin;
+	vsyncend =  vsyncstart + info->var.vsync_len;
+	vblankend = vsyncend + info->var.upper_margin;
+	vtotal = vblankend;
+
+	val = (hactive - 1) | ((htotal - 1) << 16);
+	writel(val, par->dc_regs + DC_H_TIMING_1);
+	val = (hblankstart - 1) | ((hblankend - 1) << 16);
+	writel(val, par->dc_regs + DC_H_TIMING_2);
+	val = (hsyncstart - 1) | ((hsyncend - 1) << 16);
+	writel(val, par->dc_regs + DC_H_TIMING_3);
+	writel(val, par->dc_regs + DC_FP_H_TIMING);
+	val = (vactive - 1) | ((vtotal - 1) << 16);
+	writel(val, par->dc_regs + DC_V_TIMING_1);
+	val = (vblankstart - 1) | ((vblankend - 1) << 16);
+	writel(val, par->dc_regs + DC_V_TIMING_2);
+	val = (vsyncstart - 1) | ((vsyncend - 1) << 16);
+	writel(val, par->dc_regs + DC_V_TIMING_3);
+	val = (vsyncstart - 2) | ((vsyncend - 2) << 16);
+	writel(val, par->dc_regs + DC_FP_V_TIMING);
+
+	/* Write final register values. */
+	writel(ocfg, par->dc_regs + DC_OUTPUT_CFG);
+	writel(tcfg, par->dc_regs + DC_TIMING_CFG);
+	udelay(1000); /* delay after TIMING_CFG. FIXME: perhaps a little long */
+	writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
+
+	par->vid_ops->configure_display(info);
+
+	/* Relock display controller registers */
+	writel(0, par->dc_regs + DC_UNLOCK);
+
+	/* FIXME: write line_length and bpp to Graphics Pipeline GP_BLT_STATUS
+	 * register. */
+}
+
+static void gx1_set_hw_palette_reg(struct fb_info *info, unsigned regno,
+				   unsigned red, unsigned green, unsigned blue)
+{
+	struct geodefb_par *par = info->par;
+	int val;
+
+	/* Hardware palette is in RGB 6-6-6 format. */
+	val  = (red   <<  2) & 0x3f000;
+	val |= (green >>  4) & 0x00fc0;
+	val |= (blue  >> 10) & 0x0003f;
+
+	writel(regno, par->dc_regs + DC_PAL_ADDRESS);
+	writel(val, par->dc_regs + DC_PAL_DATA);
+}
+
+struct geode_dc_ops gx1_dc_ops = {
+	.set_mode	 = gx1_set_mode,
+	.set_palette_reg = gx1_set_hw_palette_reg,
+};
diff --git a/drivers/video/geode/display_gx1.h b/drivers/video/geode/display_gx1.h
new file mode 100644
index 0000000..671c055
--- /dev/null
+++ b/drivers/video/geode/display_gx1.h
@@ -0,0 +1,154 @@
+/*
+ * drivers/video/geode/display_gx1.h
+ *   -- Geode GX1 display controller
+ *
+ * Copyright (C) 2005 Arcom Control Systems Ltd.
+ *
+ * Based on AMD's original 2.4 driver:
+ *   Copyright (C) 2004 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef __DISPLAY_GX1_H__
+#define __DISPLAY_GX1_H__
+
+unsigned gx1_gx_base(void);
+int gx1_frame_buffer_size(void);
+
+extern struct geode_dc_ops gx1_dc_ops;
+
+/* GX1 configuration I/O registers */
+
+#define CONFIG_CCR3 0xc3
+#  define CONFIG_CCR3_MAPEN 0x10
+#define CONFIG_GCR  0xb8
+
+/* Memory controller registers */
+
+#define MC_BANK_CFG		0x08
+#  define MC_BCFG_DIMM0_SZ_MASK		0x00000700
+#  define MC_BCFG_DIMM0_PG_SZ_MASK	0x00000070
+#  define MC_BCFG_DIMM0_PG_SZ_NO_DIMM	0x00000070
+
+#define MC_GBASE_ADD		0x14
+#  define MC_GADD_GBADD_MASK		0x000003ff
+
+/* Display controller registers */
+
+#define DC_PAL_ADDRESS		0x70
+#define DC_PAL_DATA		0x74
+
+#define DC_UNLOCK		0x00
+#  define DC_UNLOCK_CODE		0x00004758
+
+#define DC_GENERAL_CFG		0x04
+#  define DC_GCFG_DFLE			0x00000001
+#  define DC_GCFG_CURE			0x00000002
+#  define DC_GCFG_VCLK_DIV		0x00000004
+#  define DC_GCFG_PLNO			0x00000004
+#  define DC_GCFG_PPC			0x00000008
+#  define DC_GCFG_CMPE			0x00000010
+#  define DC_GCFG_DECE			0x00000020
+#  define DC_GCFG_DCLK_MASK		0x000000C0
+#  define DC_GCFG_DCLK_DIV_1		0x00000080
+#  define DC_GCFG_DFHPSL_MASK		0x00000F00
+#  define DC_GCFG_DFHPSL_POS			 8
+#  define DC_GCFG_DFHPEL_MASK		0x0000F000
+#  define DC_GCFG_DFHPEL_POS			12
+#  define DC_GCFG_CIM_MASK		0x00030000
+#  define DC_GCFG_CIM_POS			16
+#  define DC_GCFG_FDTY			0x00040000
+#  define DC_GCFG_RTPM			0x00080000
+#  define DC_GCFG_DAC_RS_MASK		0x00700000
+#  define DC_GCFG_DAC_RS_POS			20
+#  define DC_GCFG_CKWR			0x00800000
+#  define DC_GCFG_LDBL			0x01000000
+#  define DC_GCFG_DIAG			0x02000000
+#  define DC_GCFG_CH4S			0x04000000
+#  define DC_GCFG_SSLC			0x08000000
+#  define DC_GCFG_VIDE			0x10000000
+#  define DC_GCFG_VRDY			0x20000000
+#  define DC_GCFG_DPCK			0x40000000
+#  define DC_GCFG_DDCK			0x80000000
+
+#define DC_TIMING_CFG		0x08
+#  define DC_TCFG_FPPE			0x00000001
+#  define DC_TCFG_HSYE			0x00000002
+#  define DC_TCFG_VSYE			0x00000004
+#  define DC_TCFG_BLKE			0x00000008
+#  define DC_TCFG_DDCK			0x00000010
+#  define DC_TCFG_TGEN			0x00000020
+#  define DC_TCFG_VIEN			0x00000040
+#  define DC_TCFG_BLNK			0x00000080
+#  define DC_TCFG_CHSP			0x00000100
+#  define DC_TCFG_CVSP			0x00000200
+#  define DC_TCFG_FHSP			0x00000400
+#  define DC_TCFG_FVSP			0x00000800
+#  define DC_TCFG_FCEN			0x00001000
+#  define DC_TCFG_CDCE			0x00002000
+#  define DC_TCFG_PLNR			0x00002000
+#  define DC_TCFG_INTL			0x00004000
+#  define DC_TCFG_PXDB			0x00008000
+#  define DC_TCFG_BKRT			0x00010000
+#  define DC_TCFG_PSD_MASK		0x000E0000
+#  define DC_TCFG_PSD_POS			17
+#  define DC_TCFG_DDCI			0x08000000
+#  define DC_TCFG_SENS			0x10000000
+#  define DC_TCFG_DNA			0x20000000
+#  define DC_TCFG_VNA			0x40000000
+#  define DC_TCFG_VINT			0x80000000
+
+#define DC_OUTPUT_CFG		0x0C
+#  define DC_OCFG_8BPP			0x00000001
+#  define DC_OCFG_555			0x00000002
+#  define DC_OCFG_PCKE			0x00000004
+#  define DC_OCFG_FRME			0x00000008
+#  define DC_OCFG_DITE			0x00000010
+#  define DC_OCFG_2PXE			0x00000020
+#  define DC_OCFG_2XCK			0x00000040
+#  define DC_OCFG_2IND			0x00000080
+#  define DC_OCFG_34ADD			0x00000100
+#  define DC_OCFG_FRMS			0x00000200
+#  define DC_OCFG_CKSL			0x00000400
+#  define DC_OCFG_PRMP			0x00000800
+#  define DC_OCFG_PDEL			0x00001000
+#  define DC_OCFG_PDEH			0x00002000
+#  define DC_OCFG_CFRW			0x00004000
+#  define DC_OCFG_DIAG			0x00008000
+
+#define DC_FB_ST_OFFSET		0x10
+#define DC_CB_ST_OFFSET		0x14
+#define DC_CURS_ST_OFFSET	0x18
+#define DC_ICON_ST_OFFSET	0x1C
+#define DC_VID_ST_OFFSET	0x20
+#define DC_LINE_DELTA		0x24
+#define DC_BUF_SIZE		0x28
+
+#define DC_H_TIMING_1		0x30
+#define DC_H_TIMING_2		0x34
+#define DC_H_TIMING_3		0x38
+#define DC_FP_H_TIMING		0x3C
+
+#define DC_V_TIMING_1		0x40
+#define DC_V_TIMING_2		0x44
+#define DC_V_TIMING_3		0x48
+#define DC_FP_V_TIMING		0x4C
+
+#define DC_CURSOR_X		0x50
+#define DC_ICON_X		0x54
+#define DC_V_LINE_CNT		0x54
+#define DC_CURSOR_Y		0x58
+#define DC_ICON_Y		0x5C
+#define DC_SS_LINE_CMP		0x5C
+#define DC_CURSOR_COLOR		0x60
+#define DC_ICON_COLOR		0x64
+#define DC_BORDER_COLOR		0x68
+#define DC_PAL_ADDRESS		0x70
+#define DC_PAL_DATA		0x74
+#define DC_DFIFO_DIAG		0x78
+#define DC_CFIFO_DIAG		0x7C
+
+#endif /* !__DISPLAY_GX1_H__ */
diff --git a/drivers/video/geode/geodefb.h b/drivers/video/geode/geodefb.h
new file mode 100644
index 0000000..b7bac0a
--- /dev/null
+++ b/drivers/video/geode/geodefb.h
@@ -0,0 +1,39 @@
+/*
+ * drivers/video/geode/geodefb.h
+ *   -- Geode framebuffer driver
+ *
+ * Copyright (C) 2005 Arcom Control Systems Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef __GEODEFB_H__
+#define __GEODEFB_H__
+
+struct geodefb_info;
+
+struct geode_dc_ops {
+	void (*set_mode)(struct fb_info *);
+	void (*set_palette_reg)(struct fb_info *, unsigned, unsigned, unsigned, unsigned);
+};
+
+struct geode_vid_ops {
+	void (*set_dclk)(struct fb_info *);
+	void (*configure_display)(struct fb_info *);
+	int  (*blank_display)(struct fb_info *, int blank_mode);
+};
+
+struct geodefb_par {
+	int enable_crt;
+	int panel_x; /* dimensions of an attached flat panel, non-zero => enable panel */
+	int panel_y;
+	struct pci_dev *vid_dev;
+	void __iomem *dc_regs;
+	void __iomem *vid_regs;
+	struct geode_dc_ops  *dc_ops;
+	struct geode_vid_ops *vid_ops;
+};
+
+#endif /* !__GEODEFB_H__ */
diff --git a/drivers/video/geode/gx1fb_core.c b/drivers/video/geode/gx1fb_core.c
new file mode 100644
index 0000000..83830d2
--- /dev/null
+++ b/drivers/video/geode/gx1fb_core.c
@@ -0,0 +1,359 @@
+/*
+ * drivers/video/geode/gx1fb_core.c
+ *   -- Geode GX1 framebuffer driver
+ *
+ * Copyright (C) 2005 Arcom Control Systems Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#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/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include "geodefb.h"
+#include "display_gx1.h"
+#include "video_cs5530.h"
+
+static char mode_option[32] = "640x480-16@60";
+static int  crt_option = 1;
+static char panel_option[32] = "";
+
+static int gx1_line_delta(int xres, int bpp)
+{
+	int line_delta = xres * (bpp >> 3);
+
+	if (line_delta > 2048)
+		line_delta = 4096;
+	else if (line_delta > 1024)
+		line_delta = 2048;
+	else
+		line_delta = 1024;
+	return line_delta;
+}
+
+static int gx1fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct geodefb_par *par = info->par;
+
+	printk(KERN_DEBUG "%s()\n", __FUNCTION__);
+
+	/* Maximum resolution is 1280x1024. */
+	if (var->xres > 1280 || var->yres > 1024)
+		return -EINVAL;
+
+	if (par->panel_x && (var->xres > par->panel_x || var->yres > par->panel_y))
+		return -EINVAL;
+
+	/* Only 16 bpp and 8 bpp is supported by the hardware. */
+	if (var->bits_per_pixel == 16) {
+		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;
+	} else if (var->bits_per_pixel == 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;
+	} else
+		return -EINVAL;
+
+	/* Enough video memory? */
+	if (gx1_line_delta(var->xres, var->bits_per_pixel) * var->yres > info->fix.smem_len)
+		return -EINVAL;
+
+	/* FIXME: Check timing parameters here? */
+
+	return 0;
+}
+
+static int gx1fb_set_par(struct fb_info *info)
+{
+	struct geodefb_par *par = info->par;
+
+	if (info->var.bits_per_pixel == 16) {
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+		fb_dealloc_cmap(&info->cmap);
+	} else {
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+		fb_alloc_cmap(&info->cmap, 1<<info->var.bits_per_pixel, 0);
+	}
+
+	info->fix.line_length = gx1_line_delta(info->var.xres, info->var.bits_per_pixel);
+
+	par->dc_ops->set_mode(info);
+
+	return 0;
+}
+
+static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
+{
+	chan &= 0xffff;
+	chan >>= 16 - bf->length;
+	return chan << bf->offset;
+}
+
+static int gx1fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp,
+			   struct fb_info *info)
+{
+	struct geodefb_par *par = info->par;
+
+	if (info->var.grayscale) {
+		/* grayscale = 0.30*R + 0.59*G + 0.11*B */
+		red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+	}
+
+	/* Truecolor has hardware independent palette */
+	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+		u32 *pal = info->pseudo_palette;
+		u32 v;
+
+		if (regno >= 16)
+			return -EINVAL;
+
+		v  = chan_to_field(red, &info->var.red);
+		v |= chan_to_field(green, &info->var.green);
+		v |= chan_to_field(blue, &info->var.blue);
+
+		pal[regno] = v;
+	} else {
+		if (regno >= 256)
+			return -EINVAL;
+
+		par->dc_ops->set_palette_reg(info, regno, red, green, blue);
+	}
+
+	return 0;
+}
+
+static int gx1fb_blank(int blank_mode, struct fb_info *info)
+{
+	struct geodefb_par *par = info->par;
+
+	return par->vid_ops->blank_display(info, blank_mode);
+}
+
+static int __init gx1fb_map_video_memory(struct fb_info *info)
+{
+	struct geodefb_par *par = info->par;
+	unsigned gx_base;
+	int fb_len;
+
+	gx_base = gx1_gx_base();
+	if (!gx_base)
+		return -ENODEV;
+
+	par->vid_dev = pci_get_device(PCI_VENDOR_ID_CYRIX,
+				      PCI_DEVICE_ID_CYRIX_5530_VIDEO, NULL);
+	if (!par->vid_dev)
+		return -ENODEV;
+
+	par->vid_regs = ioremap(pci_resource_start(par->vid_dev, 1),
+				pci_resource_len(par->vid_dev, 1));
+	if (!par->vid_regs)
+		return -ENOMEM;
+
+	par->dc_regs = ioremap(gx_base + 0x8300, 0x100);
+	if (!par->dc_regs)
+		return -ENOMEM;
+
+	info->fix.smem_start = gx_base + 0x800000;
+	if ((fb_len = gx1_frame_buffer_size()) < 0)
+		return -ENOMEM;
+	info->fix.smem_len = fb_len;
+	info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+	if (!info->screen_base)
+		return -ENOMEM;
+
+	printk(KERN_INFO "%s: %d Kibyte of video memory at 0x%lx\n",
+	       info->fix.id, info->fix.smem_len / 1024, info->fix.smem_start);
+
+	return 0;
+}
+
+static int parse_panel_option(struct fb_info *info)
+{
+	struct geodefb_par *par = info->par;
+
+	if (strcmp(panel_option, "") != 0) {
+		int x, y;
+		char *s;
+		x = simple_strtol(panel_option, &s, 10);
+		if (!x)
+			return -EINVAL;
+		y = simple_strtol(s + 1, NULL, 10);
+		if (!y)
+			return -EINVAL;
+		par->panel_x = x;
+		par->panel_y = y;
+	}
+	return 0;
+}
+
+static struct fb_ops gx1fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= gx1fb_check_var,
+	.fb_set_par	= gx1fb_set_par,
+	.fb_setcolreg	= gx1fb_setcolreg,
+	.fb_blank       = gx1fb_blank,
+	/* No HW acceleration for now. */
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+static struct fb_info * __init gx1fb_init_fbinfo(void)
+{
+	struct fb_info *info;
+	struct geodefb_par *par;
+
+	/* Alloc enough space for the pseudo palette. */
+	info = framebuffer_alloc(sizeof(struct geodefb_par) + sizeof(u32) * 16, NULL);
+	if (!info)
+		return NULL;
+
+	par = info->par;
+
+	strcpy(info->fix.id, "GX1");
+
+	info->fix.type		= FB_TYPE_PACKED_PIXELS;
+	info->fix.type_aux	= 0;
+	info->fix.xpanstep	= 0;
+	info->fix.ypanstep	= 0;
+	info->fix.ywrapstep	= 0;
+	info->fix.accel		= FB_ACCEL_NONE;
+
+	info->var.nonstd	= 0;
+	info->var.activate	= FB_ACTIVATE_NOW;
+	info->var.height	= -1;
+	info->var.width	= -1;
+	info->var.accel_flags = 0;
+	info->var.vmode	= FB_VMODE_NONINTERLACED;
+
+	info->fbops		= &gx1fb_ops;
+	info->flags		= FBINFO_DEFAULT;
+	info->node		= -1;
+
+	info->pseudo_palette	= (void *)par + sizeof(struct geodefb_par);
+
+	info->var.grayscale	= 0;
+
+	/* CRT and panel options */
+	par->enable_crt = crt_option;
+	if (parse_panel_option(info) < 0)
+		printk(KERN_WARNING "%s: invalid 'panel' option -- disabling flat panel\n",
+		       info->fix.id);
+	if (!par->panel_x)
+		par->enable_crt = 1; /* fall back to CRT if no panel is specified */
+
+	return info;
+}
+
+
+static struct fb_info *gx1fb_info;
+
+static int __init gx1fb_init(void)
+{
+	struct fb_info *info;
+        struct geodefb_par *par;
+	int ret;
+
+#ifndef MODULE
+	if (fb_get_options("gx1fb", NULL))
+		return -ENODEV;
+#endif
+
+	info = gx1fb_init_fbinfo();
+	if (!info)
+		return -ENOMEM;
+	gx1fb_info = info;
+
+	par = info->par;
+
+	/* GX1 display controller and CS5530 video device */
+	par->dc_ops  = &gx1_dc_ops;
+	par->vid_ops = &cs5530_vid_ops;
+
+	if ((ret = gx1fb_map_video_memory(info)) < 0) {
+		printk(KERN_ERR "%s: gx1fb_map_video_memory() failed\n", info->fix.id);
+		goto err;
+	}
+
+	ret = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 16);
+	if (ret == 0 || ret == 4) {
+		printk(KERN_ERR "%s: could not find valid video mode\n", info->fix.id);
+		ret = -EINVAL;
+		goto err;
+	}
+
+        /* Clear the frame buffer of garbage. */
+        memset_io(info->screen_base, 0, info->fix.smem_len);
+
+	gx1fb_check_var(&info->var, info);
+	gx1fb_set_par(info);
+
+	if (register_framebuffer(info) < 0) {
+		ret = -EINVAL;
+		goto err;
+	}
+	printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id);
+	return 0;
+
+  err:
+	if (info->screen_base)
+		iounmap(info->screen_base);
+	if (par->vid_regs)
+		iounmap(par->vid_regs);
+	if (par->dc_regs)
+		iounmap(par->dc_regs);
+	if (par->vid_dev)
+		pci_dev_put(par->vid_dev);
+	if (info)
+		framebuffer_release(info);
+	return ret;
+}
+
+static void __exit gx1fb_cleanup(void)
+{
+	struct fb_info *info = gx1fb_info;
+	struct geodefb_par *par = gx1fb_info->par;
+
+	unregister_framebuffer(info);
+
+	iounmap((void __iomem *)info->screen_base);
+	iounmap(par->vid_regs);
+	iounmap(par->dc_regs);
+
+	pci_dev_put(par->vid_dev);
+
+	framebuffer_release(info);
+}
+
+module_init(gx1fb_init);
+module_exit(gx1fb_cleanup);
+
+module_param_string(mode, mode_option, sizeof(mode_option), 0444);
+MODULE_PARM_DESC(mode, "video mode (<x>x<y>[-<bpp>][@<refr>])");
+
+module_param_named(crt, crt_option, int, 0444);
+MODULE_PARM_DESC(crt, "enable CRT output. 0 = off, 1 = on (default)");
+
+module_param_string(panel, panel_option, sizeof(panel_option), 0444);
+MODULE_PARM_DESC(panel, "size of attached flat panel (<x>x<y>)");
+
+MODULE_DESCRIPTION("framebuffer driver for the AMD Geode GX1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/geode/video_cs5530.c b/drivers/video/geode/video_cs5530.c
new file mode 100644
index 0000000..d3764ac
--- /dev/null
+++ b/drivers/video/geode/video_cs5530.c
@@ -0,0 +1,195 @@
+/*
+ * drivers/video/geode/video_cs5530.c
+ *   -- CS5530 video device
+ *
+ * Copyright (C) 2005 Arcom Control Systems Ltd.
+ *
+ * Based on AMD's original 2.4 driver:
+ *   Copyright (C) 2004 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+
+#include "geodefb.h"
+#include "video_cs5530.h"
+
+/*
+ * CS5530 PLL table. This maps pixclocks to the appropriate PLL register
+ * value.
+ */
+struct cs5530_pll_entry {
+	long pixclock; /* ps */
+	u32 pll_value;
+};
+
+static const struct cs5530_pll_entry cs5530_pll_table[] = {
+	{ 39721, 0x31C45801, }, /*  25.1750 MHz */
+	{ 35308, 0x20E36802, }, /*  28.3220 */
+	{ 31746, 0x33915801, }, /*  31.5000 */
+	{ 27777, 0x31EC4801, }, /*  36.0000 */
+	{ 26666, 0x21E22801, }, /*  37.5000 */
+	{ 25000, 0x33088801, }, /*  40.0000 */
+	{ 22271, 0x33E22801, }, /*  44.9000 */
+	{ 20202, 0x336C4801, }, /*  49.5000 */
+	{ 20000, 0x23088801, }, /*  50.0000 */
+	{ 19860, 0x23088801, }, /*  50.3500 */
+	{ 18518, 0x3708A801, }, /*  54.0000 */
+	{ 17777, 0x23E36802, }, /*  56.2500 */
+	{ 17733, 0x23E36802, }, /*  56.3916 */
+	{ 17653, 0x23E36802, }, /*  56.6444 */
+	{ 16949, 0x37C45801, }, /*  59.0000 */
+	{ 15873, 0x23EC4801, }, /*  63.0000 */
+	{ 15384, 0x37911801, }, /*  65.0000 */
+	{ 14814, 0x37963803, }, /*  67.5000 */
+	{ 14124, 0x37058803, }, /*  70.8000 */
+	{ 13888, 0x3710C805, }, /*  72.0000 */
+	{ 13333, 0x37E22801, }, /*  75.0000 */
+	{ 12698, 0x27915801, }, /*  78.7500 */
+	{ 12500, 0x37D8D802, }, /*  80.0000 */
+	{ 11135, 0x27588802, }, /*  89.8000 */
+	{ 10582, 0x27EC4802, }, /*  94.5000 */
+	{ 10101, 0x27AC6803, }, /*  99.0000 */
+	{ 10000, 0x27088801, }, /* 100.0000 */
+	{  9259, 0x2710C805, }, /* 108.0000 */
+	{  8888, 0x27E36802, }, /* 112.5000 */
+	{  7692, 0x27C58803, }, /* 130.0000 */
+	{  7407, 0x27316803, }, /* 135.0000 */
+	{  6349, 0x2F915801, }, /* 157.5000 */
+	{  6172, 0x2F08A801, }, /* 162.0000 */
+	{  5714, 0x2FB11802, }, /* 175.0000 */
+	{  5291, 0x2FEC4802, }, /* 189.0000 */
+	{  4950, 0x2F963803, }, /* 202.0000 */
+	{  4310, 0x2FB1B802, }, /* 232.0000 */
+};
+
+#define NUM_CS5530_FREQUENCIES sizeof(cs5530_pll_table)/sizeof(struct cs5530_pll_entry)
+
+static void cs5530_set_dclk_frequency(struct fb_info *info)
+{
+	struct geodefb_par *par = info->par;
+	int i;
+	u32 value;
+	long min, diff;
+
+	/* Search the table for the closest pixclock. */
+	value = cs5530_pll_table[0].pll_value;
+	min = cs5530_pll_table[0].pixclock - info->var.pixclock;
+	if (min < 0) min = -min;
+	for (i = 1; i < NUM_CS5530_FREQUENCIES; i++) {
+		diff = cs5530_pll_table[i].pixclock - info->var.pixclock;
+		if (diff < 0L) diff = -diff;
+		if (diff < min) {
+			min = diff;
+			value = cs5530_pll_table[i].pll_value;
+		}
+	}
+
+	writel(value, par->vid_regs + CS5530_DOT_CLK_CONFIG);
+	writel(value | 0x80000100, par->vid_regs + CS5530_DOT_CLK_CONFIG); /* set reset and bypass */
+	udelay(500); /* wait for PLL to settle */
+	writel(value & 0x7FFFFFFF, par->vid_regs + CS5530_DOT_CLK_CONFIG); /* clear reset */
+	writel(value & 0x7FFFFEFF, par->vid_regs + CS5530_DOT_CLK_CONFIG); /* clear bypass */
+}
+
+static void cs5530_configure_display(struct fb_info *info)
+{
+	struct geodefb_par *par = info->par;
+	u32 dcfg;
+
+	dcfg = readl(par->vid_regs + CS5530_DISPLAY_CONFIG);
+
+	/* Clear bits from existing mode. */
+	dcfg &= ~(CS5530_DCFG_CRT_SYNC_SKW_MASK | CS5530_DCFG_PWR_SEQ_DLY_MASK
+		  | CS5530_DCFG_CRT_HSYNC_POL   | CS5530_DCFG_CRT_VSYNC_POL
+		  | CS5530_DCFG_FP_PWR_EN       | CS5530_DCFG_FP_DATA_EN
+		  | CS5530_DCFG_DAC_PWR_EN      | CS5530_DCFG_VSYNC_EN
+		  | CS5530_DCFG_HSYNC_EN);
+
+	/* Set default sync skew and power sequence delays.  */
+	dcfg |= (CS5530_DCFG_CRT_SYNC_SKW_INIT | CS5530_DCFG_PWR_SEQ_DLY_INIT
+		 | CS5530_DCFG_GV_PAL_BYP);
+
+	/* Enable DACs, hsync and vsync for CRTs */
+	if (par->enable_crt) {
+		dcfg |= CS5530_DCFG_DAC_PWR_EN;
+		dcfg |= CS5530_DCFG_HSYNC_EN | CS5530_DCFG_VSYNC_EN;
+	}
+	/* Enable panel power and data if using a flat panel. */
+	if (par->panel_x > 0) {
+		dcfg |= CS5530_DCFG_FP_PWR_EN;
+		dcfg |= CS5530_DCFG_FP_DATA_EN;
+	}
+
+	/* Sync polarities. */
+	if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
+		dcfg |= CS5530_DCFG_CRT_HSYNC_POL;
+	if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
+		dcfg |= CS5530_DCFG_CRT_VSYNC_POL;
+
+	writel(dcfg, par->vid_regs + CS5530_DISPLAY_CONFIG);
+}
+
+static int cs5530_blank_display(struct fb_info *info, int blank_mode)
+{
+	struct geodefb_par *par = info->par;
+	u32 dcfg;
+	int blank, hsync, vsync;
+
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANK:
+		blank = 0; hsync = 1; vsync = 1;
+		break;
+	case FB_BLANK_NORMAL:
+		blank = 1; hsync = 1; vsync = 1;
+		break;
+	case FB_BLANK_VSYNC_SUSPEND:
+		blank = 1; hsync = 1; vsync = 0;
+		break;
+	case FB_BLANK_HSYNC_SUSPEND:
+		blank = 1; hsync = 0; vsync = 1;
+		break;
+	case FB_BLANK_POWERDOWN:
+		blank = 1; hsync = 0; vsync = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	dcfg = readl(par->vid_regs + CS5530_DISPLAY_CONFIG);
+
+	dcfg &= ~(CS5530_DCFG_DAC_BL_EN | CS5530_DCFG_DAC_PWR_EN
+		  | CS5530_DCFG_HSYNC_EN | CS5530_DCFG_VSYNC_EN
+		  | CS5530_DCFG_FP_DATA_EN | CS5530_DCFG_FP_PWR_EN);
+
+	if (par->enable_crt) {
+		if (!blank)
+			dcfg |= CS5530_DCFG_DAC_BL_EN | CS5530_DCFG_DAC_PWR_EN;
+		if (hsync)
+			dcfg |= CS5530_DCFG_HSYNC_EN;
+		if (vsync)
+			dcfg |= CS5530_DCFG_VSYNC_EN;
+	}
+	if (par->panel_x > 0) {
+		if (!blank)
+			dcfg |= CS5530_DCFG_FP_DATA_EN;
+		if (hsync && vsync)
+			dcfg |= CS5530_DCFG_FP_PWR_EN;
+	}
+
+	writel(dcfg, par->vid_regs + CS5530_DISPLAY_CONFIG);
+
+	return 0;
+}
+
+struct geode_vid_ops cs5530_vid_ops = {
+	.set_dclk          = cs5530_set_dclk_frequency,
+	.configure_display = cs5530_configure_display,
+	.blank_display     = cs5530_blank_display,
+};
diff --git a/drivers/video/geode/video_cs5530.h b/drivers/video/geode/video_cs5530.h
new file mode 100644
index 0000000..56cecca
--- /dev/null
+++ b/drivers/video/geode/video_cs5530.h
@@ -0,0 +1,75 @@
+/*
+ * drivers/video/geode/video_cs5530.h
+ *   -- CS5530 video device
+ *
+ * Copyright (C) 2005 Arcom Control Systems Ltd.
+ *
+ * Based on AMD's original 2.4 driver:
+ *   Copyright (C) 2004 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef __VIDEO_CS5530_H__
+#define __VIDEO_CS5530_H__
+
+extern struct geode_vid_ops cs5530_vid_ops;
+
+/* CS5530 Video device registers */
+
+#define CS5530_VIDEO_CONFIG	0x0000
+#  define CS5530_VCFG_VID_EN			0x00000001
+#  define CS5530_VCFG_VID_REG_UPDATE		0x00000002
+#  define CS5530_VCFG_VID_INP_FORMAT		0x0000000C
+#  define CS5530_VCFG_8_BIT_4_2_0		0x00000004
+#  define CS5530_VCFG_16_BIT_4_2_0		0x00000008
+#  define CS5530_VCFG_GV_SEL			0x00000010
+#  define CS5530_VCFG_CSC_BYPASS		0x00000020
+#  define CS5530_VCFG_X_FILTER_EN		0x00000040
+#  define CS5530_VCFG_Y_FILTER_EN		0x00000080
+#  define CS5530_VCFG_LINE_SIZE_LOWER_MASK	0x0000FF00
+#  define CS5530_VCFG_INIT_READ_MASK		0x01FF0000
+#  define CS5530_VCFG_EARLY_VID_RDY		0x02000000
+#  define CS5530_VCFG_LINE_SIZE_UPPER		0x08000000
+#  define CS5530_VCFG_4_2_0_MODE		0x10000000
+#  define CS5530_VCFG_16_BIT_EN			0x20000000
+#  define CS5530_VCFG_HIGH_SPD_INT		0x40000000
+
+#define CS5530_DISPLAY_CONFIG	0x0004
+#  define CS5530_DCFG_DIS_EN			0x00000001
+#  define CS5530_DCFG_HSYNC_EN			0x00000002
+#  define CS5530_DCFG_VSYNC_EN			0x00000004
+#  define CS5530_DCFG_DAC_BL_EN			0x00000008
+#  define CS5530_DCFG_DAC_PWR_EN		0x00000020
+#  define CS5530_DCFG_FP_PWR_EN			0x00000040
+#  define CS5530_DCFG_FP_DATA_EN		0x00000080
+#  define CS5530_DCFG_CRT_HSYNC_POL		0x00000100
+#  define CS5530_DCFG_CRT_VSYNC_POL		0x00000200
+#  define CS5530_DCFG_FP_HSYNC_POL		0x00000400
+#  define CS5530_DCFG_FP_VSYNC_POL		0x00000800
+#  define CS5530_DCFG_XGA_FP			0x00001000
+#  define CS5530_DCFG_FP_DITH_EN		0x00002000
+#  define CS5530_DCFG_CRT_SYNC_SKW_MASK		0x0001C000
+#  define CS5530_DCFG_CRT_SYNC_SKW_INIT		0x00010000
+#  define CS5530_DCFG_PWR_SEQ_DLY_MASK		0x000E0000
+#  define CS5530_DCFG_PWR_SEQ_DLY_INIT		0x00080000
+#  define CS5530_DCFG_VG_CK			0x00100000
+#  define CS5530_DCFG_GV_PAL_BYP		0x00200000
+#  define CS5530_DCFG_DDC_SCL			0x00400000
+#  define CS5530_DCFG_DDC_SDA			0x00800000
+#  define CS5530_DCFG_DDC_OE			0x01000000
+#  define CS5530_DCFG_16_BIT_EN			0x02000000
+
+#define CS5530_VIDEO_X_POS	0x0008
+#define CS5530_VIDEO_Y_POS	0x000C
+#define CS5530_VIDEO_SCALE	0x0010
+#define CS5530_VIDEO_COLOR_KEY	0x0014
+#define CS5530_VIDEO_COLOR_MASK 0x0018
+#define CS5530_PALETTE_ADDRESS	0x001C
+#define CS5530_PALETTE_DATA	0x0020
+#define CS5530_DOT_CLK_CONFIG	0x0024
+#define CS5530_CRCSIG_TFT_TV	0x0028
+
+#endif /* !__VIDEO_CS5530_H__ */
diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c
new file mode 100644
index 0000000..b37cea7
--- /dev/null
+++ b/drivers/video/hgafb.c
@@ -0,0 +1,619 @@
+/*
+ * linux/drivers/video/hgafb.c -- Hercules graphics adaptor frame buffer device
+ * 
+ *      Created 25 Nov 1999 by Ferenc Bakonyi (fero@drama.obuda.kando.hu)
+ *      Based on skeletonfb.c by Geert Uytterhoeven and
+ *               mdacon.c by Andrew Apted
+ *
+ * History:
+ *
+ * - Revision 0.1.8 (23 Oct 2002): Ported to new framebuffer api.
+ * 
+ * - Revision 0.1.7 (23 Jan 2001): fix crash resulting from MDA only cards 
+ *				   being detected as Hercules.	 (Paul G.)
+ * - Revision 0.1.6 (17 Aug 2000): new style structs
+ *                                 documentation
+ * - Revision 0.1.5 (13 Mar 2000): spinlocks instead of saveflags();cli();etc
+ *                                 minor fixes
+ * - Revision 0.1.4 (24 Jan 2000): fixed a bug in hga_card_detect() for 
+ *                                  HGA-only systems
+ * - Revision 0.1.3 (22 Jan 2000): modified for the new fb_info structure
+ *                                 screen is cleared after rmmod
+ *                                 virtual resolutions
+ *                                 module parameter 'nologo={0|1}'
+ *                                 the most important: boot logo :)
+ * - Revision 0.1.0  (6 Dec 1999): faster scrolling and minor fixes
+ * - First release  (25 Nov 1999)
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/vga.h>
+
+#if 0
+#define DPRINTK(args...) printk(KERN_DEBUG __FILE__": " ##args)
+#else
+#define DPRINTK(args...)
+#endif
+
+#if 0
+#define CHKINFO(ret) if (info != &fb_info) { printk(KERN_DEBUG __FILE__": This should never happen, line:%d \n", __LINE__); return ret; }
+#else
+#define CHKINFO(ret)
+#endif
+
+/* Description of the hardware layout */
+
+static void __iomem *hga_vram;			/* Base of video memory */
+static unsigned long hga_vram_len;		/* Size of video memory */
+
+#define HGA_ROWADDR(row) ((row%4)*8192 + (row>>2)*90)
+#define HGA_TXT			0
+#define HGA_GFX			1
+
+static inline u8 __iomem * rowaddr(struct fb_info *info, u_int row)
+{
+	return info->screen_base + HGA_ROWADDR(row);
+}
+
+static int hga_mode = -1;			/* 0 = txt, 1 = gfx mode */
+
+static enum { TYPE_HERC, TYPE_HERCPLUS, TYPE_HERCCOLOR } hga_type;
+static char *hga_type_name;
+
+#define HGA_INDEX_PORT		0x3b4		/* Register select port */
+#define HGA_VALUE_PORT		0x3b5		/* Register value port */
+#define HGA_MODE_PORT		0x3b8		/* Mode control port */
+#define HGA_STATUS_PORT		0x3ba		/* Status and Config port */
+#define HGA_GFX_PORT		0x3bf		/* Graphics control port */
+
+/* HGA register values */
+
+#define HGA_CURSOR_BLINKING	0x00
+#define HGA_CURSOR_OFF		0x20
+#define HGA_CURSOR_SLOWBLINK	0x60
+
+#define HGA_MODE_GRAPHICS	0x02
+#define HGA_MODE_VIDEO_EN	0x08
+#define HGA_MODE_BLINK_EN	0x20
+#define HGA_MODE_GFX_PAGE1	0x80
+
+#define HGA_STATUS_HSYNC	0x01
+#define HGA_STATUS_VSYNC	0x80
+#define HGA_STATUS_VIDEO	0x08
+
+#define HGA_CONFIG_COL132	0x08
+#define HGA_GFX_MODE_EN		0x01
+#define HGA_GFX_PAGE_EN		0x02
+
+/* Global locks */
+
+static DEFINE_SPINLOCK(hga_reg_lock);
+
+/* Framebuffer driver structures */
+
+static struct fb_var_screeninfo hga_default_var = {
+	.xres		= 720,
+	.yres 		= 348,
+	.xres_virtual 	= 720,
+	.yres_virtual	= 348,
+	.bits_per_pixel = 1,
+	.red 		= {0, 1, 0},
+	.green 		= {0, 1, 0},
+	.blue 		= {0, 1, 0},
+	.transp 	= {0, 0, 0},
+	.height 	= -1,
+	.width 		= -1,
+};
+
+static struct fb_fix_screeninfo hga_fix = {
+	.id 		= "HGA",
+	.type 		= FB_TYPE_PACKED_PIXELS,	/* (not sure) */
+	.visual 	= FB_VISUAL_MONO10,
+	.xpanstep 	= 8,
+	.ypanstep 	= 8,
+	.line_length 	= 90,
+	.accel 		= FB_ACCEL_NONE
+};
+
+static struct fb_info fb_info;
+
+/* Don't assume that tty1 will be the initial current console. */
+static int release_io_port = 0;
+static int release_io_ports = 0;
+static int nologo = 0;
+
+/* -------------------------------------------------------------------------
+ *
+ * Low level hardware functions
+ *
+ * ------------------------------------------------------------------------- */
+
+static void write_hga_b(unsigned int val, unsigned char reg)
+{
+	outb_p(reg, HGA_INDEX_PORT); 
+	outb_p(val, HGA_VALUE_PORT);
+}
+
+static void write_hga_w(unsigned int val, unsigned char reg)
+{
+	outb_p(reg,   HGA_INDEX_PORT); outb_p(val >> 8,   HGA_VALUE_PORT);
+	outb_p(reg+1, HGA_INDEX_PORT); outb_p(val & 0xff, HGA_VALUE_PORT);
+}
+
+static int test_hga_b(unsigned char val, unsigned char reg)
+{
+	outb_p(reg, HGA_INDEX_PORT); 
+	outb  (val, HGA_VALUE_PORT);
+	udelay(20); val = (inb_p(HGA_VALUE_PORT) == val);
+	return val;
+}
+
+static void hga_clear_screen(void)
+{
+	unsigned char fillchar = 0xbf; /* magic */
+	unsigned long flags;
+
+	spin_lock_irqsave(&hga_reg_lock, flags);
+	if (hga_mode == HGA_TXT)
+		fillchar = ' ';
+	else if (hga_mode == HGA_GFX)
+		fillchar = 0x00;
+	spin_unlock_irqrestore(&hga_reg_lock, flags);
+	if (fillchar != 0xbf)
+		memset_io(hga_vram, fillchar, hga_vram_len);
+}
+
+static void hga_txt_mode(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&hga_reg_lock, flags);
+	outb_p(HGA_MODE_VIDEO_EN | HGA_MODE_BLINK_EN, HGA_MODE_PORT);
+	outb_p(0x00, HGA_GFX_PORT);
+	outb_p(0x00, HGA_STATUS_PORT);
+
+	write_hga_b(0x61, 0x00);	/* horizontal total */
+	write_hga_b(0x50, 0x01);	/* horizontal displayed */
+	write_hga_b(0x52, 0x02);	/* horizontal sync pos */
+	write_hga_b(0x0f, 0x03);	/* horizontal sync width */
+
+	write_hga_b(0x19, 0x04);	/* vertical total */
+	write_hga_b(0x06, 0x05);	/* vertical total adjust */
+	write_hga_b(0x19, 0x06);	/* vertical displayed */
+	write_hga_b(0x19, 0x07);	/* vertical sync pos */
+
+	write_hga_b(0x02, 0x08);	/* interlace mode */
+	write_hga_b(0x0d, 0x09);	/* maximum scanline */
+	write_hga_b(0x0c, 0x0a);	/* cursor start */
+	write_hga_b(0x0d, 0x0b);	/* cursor end */
+
+	write_hga_w(0x0000, 0x0c);	/* start address */
+	write_hga_w(0x0000, 0x0e);	/* cursor location */
+
+	hga_mode = HGA_TXT;
+	spin_unlock_irqrestore(&hga_reg_lock, flags);
+}
+
+static void hga_gfx_mode(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&hga_reg_lock, flags);
+	outb_p(0x00, HGA_STATUS_PORT);
+	outb_p(HGA_GFX_MODE_EN, HGA_GFX_PORT);
+	outb_p(HGA_MODE_VIDEO_EN | HGA_MODE_GRAPHICS, HGA_MODE_PORT);
+
+	write_hga_b(0x35, 0x00);	/* horizontal total */
+	write_hga_b(0x2d, 0x01);	/* horizontal displayed */
+	write_hga_b(0x2e, 0x02);	/* horizontal sync pos */
+	write_hga_b(0x07, 0x03);	/* horizontal sync width */
+
+	write_hga_b(0x5b, 0x04);	/* vertical total */
+	write_hga_b(0x02, 0x05);	/* vertical total adjust */
+	write_hga_b(0x57, 0x06);	/* vertical displayed */
+	write_hga_b(0x57, 0x07);	/* vertical sync pos */
+
+	write_hga_b(0x02, 0x08);	/* interlace mode */
+	write_hga_b(0x03, 0x09);	/* maximum scanline */
+	write_hga_b(0x00, 0x0a);	/* cursor start */
+	write_hga_b(0x00, 0x0b);	/* cursor end */
+
+	write_hga_w(0x0000, 0x0c);	/* start address */
+	write_hga_w(0x0000, 0x0e);	/* cursor location */
+
+	hga_mode = HGA_GFX;
+	spin_unlock_irqrestore(&hga_reg_lock, flags);
+}
+
+static void hga_show_logo(struct fb_info *info)
+{
+/*
+	void __iomem *dest = hga_vram;
+	char *logo = linux_logo_bw;
+	int x, y;
+	
+	for (y = 134; y < 134 + 80 ; y++) * this needs some cleanup *
+		for (x = 0; x < 10 ; x++)
+			writeb(~*(logo++),(dest + HGA_ROWADDR(y) + x + 40));
+*/
+}
+
+static void hga_pan(unsigned int xoffset, unsigned int yoffset)
+{
+	unsigned int base;
+	unsigned long flags;
+	
+	base = (yoffset / 8) * 90 + xoffset;
+	spin_lock_irqsave(&hga_reg_lock, flags);
+	write_hga_w(base, 0x0c);	/* start address */
+	spin_unlock_irqrestore(&hga_reg_lock, flags);
+	DPRINTK("hga_pan: base:%d\n", base);
+}
+
+static void hga_blank(int blank_mode)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&hga_reg_lock, flags);
+	if (blank_mode) {
+		outb_p(0x00, HGA_MODE_PORT);	/* disable video */
+	} else {
+		outb_p(HGA_MODE_VIDEO_EN | HGA_MODE_GRAPHICS, HGA_MODE_PORT);
+	}
+	spin_unlock_irqrestore(&hga_reg_lock, flags);
+}
+
+static int __init hga_card_detect(void)
+{
+	int count=0;
+	void __iomem *p, *q;
+	unsigned short p_save, q_save;
+
+	hga_vram_len  = 0x08000;
+
+	hga_vram = ioremap(0xb0000, hga_vram_len);
+
+	if (request_region(0x3b0, 12, "hgafb"))
+		release_io_ports = 1;
+	if (request_region(0x3bf, 1, "hgafb"))
+		release_io_port = 1;
+
+	/* do a memory check */
+
+	p = hga_vram;
+	q = hga_vram + 0x01000;
+
+	p_save = readw(p); q_save = readw(q);
+
+	writew(0xaa55, p); if (readw(p) == 0xaa55) count++;
+	writew(0x55aa, p); if (readw(p) == 0x55aa) count++;
+	writew(p_save, p);
+
+	if (count != 2) {
+		return 0;
+	}
+
+	/* Ok, there is definitely a card registering at the correct
+	 * memory location, so now we do an I/O port test.
+	 */
+	
+	if (!test_hga_b(0x66, 0x0f)) {	    /* cursor low register */
+		return 0;
+	}
+	if (!test_hga_b(0x99, 0x0f)) {     /* cursor low register */
+		return 0;
+	}
+
+	/* See if the card is a Hercules, by checking whether the vsync
+	 * bit of the status register is changing.  This test lasts for
+	 * approximately 1/10th of a second.
+	 */
+	
+	p_save = q_save = inb_p(HGA_STATUS_PORT) & HGA_STATUS_VSYNC;
+
+	for (count=0; count < 50000 && p_save == q_save; count++) {
+		q_save = inb(HGA_STATUS_PORT) & HGA_STATUS_VSYNC;
+		udelay(2);
+	}
+
+	if (p_save == q_save) 
+		return 0;
+
+	switch (inb_p(HGA_STATUS_PORT) & 0x70) {
+		case 0x10:
+			hga_type = TYPE_HERCPLUS;
+			hga_type_name = "HerculesPlus";
+			break;
+		case 0x50:
+			hga_type = TYPE_HERCCOLOR;
+			hga_type_name = "HerculesColor";
+			break;
+		default:
+			hga_type = TYPE_HERC;
+			hga_type_name = "Hercules";
+			break;
+	}
+	return 1;
+}
+
+/**
+ *	hgafb_open - open the framebuffer device
+ *	@info:pointer to fb_info object containing info for current hga board
+ *	@int:open by console system or userland.
+ */
+
+static int hgafb_open(struct fb_info *info, int init)
+{
+	hga_gfx_mode();
+	hga_clear_screen();
+	if (!nologo) hga_show_logo(info);
+	return 0;
+}
+
+/**
+ *	hgafb_open - open the framebuffer device
+ *	@info:pointer to fb_info object containing info for current hga board
+ *	@int:open by console system or userland.
+ */
+
+static int hgafb_release(struct fb_info *info, int init)
+{
+	hga_txt_mode();
+	hga_clear_screen();
+	return 0;
+}
+
+/**
+ *	hgafb_setcolreg - set color registers
+ *	@regno:register index to set
+ *	@red:red value, unused
+ *	@green:green value, unused
+ *	@blue:blue value, unused
+ *	@transp:transparency value, unused
+ *	@info:unused
+ *
+ *	This callback function is used to set the color registers of a HGA
+ *	board. Since we have only two fixed colors only @regno is checked.
+ *	A zero is returned on success and 1 for failure.
+ */
+
+static int hgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			   u_int transp, struct fb_info *info)
+{
+	if (regno > 1)
+		return 1;
+	return 0;
+}
+
+/**
+ *	hga_pan_display - pan or wrap the display
+ *	@var:contains new xoffset, yoffset and vmode values
+ *	@info:pointer to fb_info object containing info for current hga board
+ *
+ *	This function looks only at xoffset, yoffset and the %FB_VMODE_YWRAP
+ *	flag in @var. If input parameters are correct it calls hga_pan() to 
+ *	program the hardware. @info->var is updated to the new values.
+ *	A zero is returned on success and %-EINVAL for failure.
+ */
+
+static int hgafb_pan_display(struct fb_var_screeninfo *var,
+			     struct fb_info *info)
+{
+	if (var->vmode & FB_VMODE_YWRAP) {
+		if (var->yoffset < 0 || 
+		    var->yoffset >= info->var.yres_virtual ||
+		    var->xoffset)
+			return -EINVAL;
+	} else {
+		if (var->xoffset + var->xres > info->var.xres_virtual
+		 || var->yoffset + var->yres > info->var.yres_virtual
+		 || var->yoffset % 8)
+			return -EINVAL;
+	}
+
+	hga_pan(var->xoffset, var->yoffset);
+	return 0;
+}
+
+/**
+ *	hgafb_blank - (un)blank the screen
+ *	@blank_mode:blanking method to use
+ *	@info:unused
+ *	
+ *	Blank the screen if blank_mode != 0, else unblank. 
+ *	Implements VESA suspend and powerdown modes on hardware that supports 
+ *	disabling hsync/vsync:
+ *		@blank_mode == 2 means suspend vsync,
+ *		@blank_mode == 3 means suspend hsync,
+ *		@blank_mode == 4 means powerdown.
+ */
+
+static int hgafb_blank(int blank_mode, struct fb_info *info)
+{
+	hga_blank(blank_mode);
+	return 0;
+}
+
+/*
+ * Accel functions
+ */
+#ifdef CONFIG_FB_HGA_ACCEL
+static void hgafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+	u_int rows, y;
+	u8 __iomem *dest;
+
+	y = rect->dy;
+
+	for (rows = rect->height; rows--; y++) {
+		dest = rowaddr(info, y) + (rect->dx >> 3);
+		switch (rect->rop) {
+		case ROP_COPY:
+			//fb_memset(dest, rect->color, (rect->width >> 3));
+			break;
+		case ROP_XOR:
+			fb_writeb(~(fb_readb(dest)), dest);
+			break;
+		}
+	}
+}
+
+static void hgafb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+	u_int rows, y1, y2;
+	u8 __iomem *src;
+	u8 __iomem *dest;
+
+	if (area->dy <= area->sy) {
+		y1 = area->sy;
+		y2 = area->dy;
+
+		for (rows = area->height; rows--; ) {
+			src = rowaddr(info, y1) + (area->sx >> 3);
+			dest = rowaddr(info, y2) + (area->dx >> 3);
+			//fb_memmove(dest, src, (area->width >> 3));
+			y1++;
+			y2++;
+		}
+	} else {
+		y1 = area->sy + area->height - 1;
+		y2 = area->dy + area->height - 1;
+
+		for (rows = area->height; rows--;) {
+			src = rowaddr(info, y1) + (area->sx >> 3);
+			dest = rowaddr(info, y2) + (area->dx >> 3);
+			//fb_memmove(dest, src, (area->width >> 3));
+			y1--;
+			y2--;
+		}
+	}
+}
+
+static void hgafb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	u8 __iomem *dest;
+	u8 *cdat = (u8 *) image->data;
+	u_int rows, y = image->dy;
+	u8 d;
+
+	for (rows = image->height; rows--; y++) {
+		d = *cdat++;
+		dest = rowaddr(info, y) + (image->dx >> 3);
+		fb_writeb(d, dest);
+	}
+}
+#else /* !CONFIG_FB_HGA_ACCEL */
+#define hgafb_fillrect cfb_fillrect
+#define hgafb_copyarea cfb_copyarea
+#define hgafb_imageblit cfb_imageblit
+#endif /* CONFIG_FB_HGA_ACCEL */
+
+
+static struct fb_ops hgafb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_open	= hgafb_open,
+	.fb_release	= hgafb_release,
+	.fb_setcolreg	= hgafb_setcolreg,
+	.fb_pan_display	= hgafb_pan_display,
+	.fb_blank	= hgafb_blank,
+	.fb_fillrect	= hgafb_fillrect,
+	.fb_copyarea	= hgafb_copyarea,
+	.fb_imageblit	= hgafb_imageblit,
+};
+		
+/* ------------------------------------------------------------------------- *
+ *
+ * Functions in fb_info
+ * 
+ * ------------------------------------------------------------------------- */
+
+/* ------------------------------------------------------------------------- */
+    
+	/*
+	 *  Initialization
+	 */
+
+static int __init hgafb_init(void)
+{
+	if (fb_get_options("hgafb", NULL))
+		return -ENODEV;
+
+	if (! hga_card_detect()) {
+		printk(KERN_INFO "hgafb: HGA card not detected.\n");
+		if (hga_vram)
+			iounmap(hga_vram);
+		return -EINVAL;
+	}
+
+	printk(KERN_INFO "hgafb: %s with %ldK of memory detected.\n",
+		hga_type_name, hga_vram_len/1024);
+
+	hga_fix.smem_start = (unsigned long)hga_vram;
+	hga_fix.smem_len = hga_vram_len;
+
+	fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+	fb_info.var = hga_default_var;
+	fb_info.fix = hga_fix;
+	fb_info.monspecs.hfmin = 0;
+	fb_info.monspecs.hfmax = 0;
+	fb_info.monspecs.vfmin = 10000;
+	fb_info.monspecs.vfmax = 10000;
+	fb_info.monspecs.dpms = 0;
+	fb_info.fbops = &hgafb_ops;
+	fb_info.screen_base = hga_vram;
+
+        if (register_framebuffer(&fb_info) < 0) {
+		iounmap(hga_vram);
+		return -EINVAL;
+	}
+
+        printk(KERN_INFO "fb%d: %s frame buffer device\n",
+               fb_info.node, fb_info.fix.id);
+	return 0;
+}
+
+#ifdef MODULE
+static void __exit hgafb_exit(void)
+{
+	hga_txt_mode();
+	hga_clear_screen();
+	unregister_framebuffer(&fb_info);
+	iounmap(hga_vram);
+	if (release_io_ports) release_region(0x3b0, 12);
+	if (release_io_port) release_region(0x3bf, 1);
+}
+#endif
+
+/* -------------------------------------------------------------------------
+ *
+ *  Modularization
+ *
+ * ------------------------------------------------------------------------- */
+
+MODULE_AUTHOR("Ferenc Bakonyi (fero@drama.obuda.kando.hu)");
+MODULE_DESCRIPTION("FBDev driver for Hercules Graphics Adaptor");
+MODULE_LICENSE("GPL");
+
+module_param(nologo, bool, 0);
+MODULE_PARM_DESC(nologo, "Disables startup logo if != 0 (default=0)");
+module_init(hgafb_init);
+
+#ifdef MODULE
+module_exit(hgafb_exit);
+#endif
diff --git a/drivers/video/hitfb.c b/drivers/video/hitfb.c
new file mode 100644
index 0000000..0d376ba
--- /dev/null
+++ b/drivers/video/hitfb.c
@@ -0,0 +1,350 @@
+/*
+ * linux/drivers/video/hitfb.c -- Hitachi LCD frame buffer device
+ *
+ * (C) 1999 Mihai Spatar
+ * (C) 2000 YAEGASHI Takeshi
+ * (C) 2003, 2004 Paul Mundt
+ * (C) 2003, 2004 Andriy Skulysh
+ *
+ *  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/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+
+#include <asm/machvec.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/hd64461/hd64461.h>
+
+#ifdef MACH_HP600
+#include <asm/cpu/dac.h>
+#include <asm/hp6xx/hp6xx.h>
+#endif
+
+#define	WIDTH 640
+
+static struct fb_var_screeninfo hitfb_var __initdata = {
+	.activate	= FB_ACTIVATE_NOW,
+	.height		= -1,
+	.width		= -1,
+	.vmode		= FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_fix_screeninfo hitfb_fix __initdata = {
+	.id		= "Hitachi HD64461",
+	.type		= FB_TYPE_PACKED_PIXELS,
+	.ypanstep	= 8,
+	.accel		= FB_ACCEL_NONE,
+};
+
+static u32 pseudo_palette[16];
+static struct fb_info fb_info;
+
+static inline void hitfb_accel_wait(void)
+{
+	while (fb_readw(HD64461_GRCFGR) & HD64461_GRCFGR_ACCSTATUS) ;
+}
+
+static inline void hitfb_accel_start(int truecolor)
+{
+	if (truecolor) {
+		fb_writew(6, HD64461_GRCFGR);
+	} else {
+		fb_writew(7, HD64461_GRCFGR);
+	}
+}
+
+static inline void hitfb_accel_set_dest(int truecolor, u16 dx, u16 dy,
+					u16 width, u16 height)
+{
+	u32 saddr = WIDTH * dy + dx;
+	if (truecolor)
+		saddr <<= 1;
+
+	fb_writew(width, HD64461_BBTDWR);
+	fb_writew(height, HD64461_BBTDHR);
+
+	fb_writew(saddr & 0xffff, HD64461_BBTDSARL);
+	fb_writew(saddr >> 16, HD64461_BBTDSARH);
+
+}
+
+static inline void hitfb_accel_solidfill(int truecolor, u16 dx, u16 dy,
+					 u16 width, u16 height, u16 color)
+{
+	hitfb_accel_set_dest(truecolor, dx, dy, width, height);
+
+	fb_writew(0x00f0, HD64461_BBTROPR);
+	fb_writew(16, HD64461_BBTMDR);
+	fb_writew(color, HD64461_GRSCR);
+
+	hitfb_accel_start(truecolor);
+}
+
+static inline void hitfb_accel_bitblt(int truecolor, u16 sx, u16 sy, u16 dx,
+				      u16 dy, u16 width, u16 height, u16 rop,
+				      u32 mask_addr)
+{
+	u32 saddr, daddr;
+	u32 maddr = 0;
+
+	fb_writew(rop, HD64461_BBTROPR);
+	if ((sy < dy) || ((sy == dy) && (sx <= dx))) {
+		saddr = WIDTH * (sy + height) + sx + width;
+		daddr = WIDTH * (dy + height) + dx + width;
+		if (mask_addr) {
+			if (truecolor)
+				maddr = ((width >> 3) + 1) * (height + 1) - 1;
+			else
+				maddr =
+				    (((width >> 4) + 1) * (height + 1) - 1) * 2;
+
+			fb_writew((1 << 5) | 1, HD64461_BBTMDR);
+		} else
+			fb_writew(1, HD64461_BBTMDR);
+	} else {
+		saddr = WIDTH * sy + sx;
+		daddr = WIDTH * dy + dx;
+		if (mask_addr) {
+			fb_writew((1 << 5), HD64461_BBTMDR);
+		} else {
+			fb_writew(0, HD64461_BBTMDR);
+		}
+	}
+	if (truecolor) {
+		saddr <<= 1;
+		daddr <<= 1;
+	}
+	fb_writew(width, HD64461_BBTDWR);
+	fb_writew(height, HD64461_BBTDHR);
+	fb_writew(saddr & 0xffff, HD64461_BBTSSARL);
+	fb_writew(saddr >> 16, HD64461_BBTSSARH);
+	fb_writew(daddr & 0xffff, HD64461_BBTDSARL);
+	fb_writew(daddr >> 16, HD64461_BBTDSARH);
+	if (mask_addr) {
+		maddr += mask_addr;
+		fb_writew(maddr & 0xffff, HD64461_BBTMARL);
+		fb_writew(maddr >> 16, HD64461_BBTMARH);
+	}
+	hitfb_accel_start(truecolor);
+}
+
+static void hitfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
+{
+	if (rect->rop != ROP_COPY)
+		cfb_fillrect(p, rect);
+	else {
+		fb_writew(0x00f0, HD64461_BBTROPR);
+		fb_writew(16, HD64461_BBTMDR);
+
+		if (p->var.bits_per_pixel == 16) {
+			fb_writew(((u32 *) (p->pseudo_palette))[rect->color],
+				  HD64461_GRSCR);
+			hitfb_accel_set_dest(1, rect->dx, rect->dy, rect->width,
+					     rect->height);
+			hitfb_accel_start(1);
+		} else {
+			fb_writew(rect->color, HD64461_GRSCR);
+			hitfb_accel_set_dest(0, rect->dx, rect->dy, rect->width,
+					     rect->height);
+			hitfb_accel_start(0);
+		}
+		hitfb_accel_wait();
+	}
+}
+
+static void hitfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
+{
+	hitfb_accel_bitblt(p->var.bits_per_pixel == 16, area->sx, area->sy,
+			   area->dx, area->dy, area->width, area->height,
+			   0x00cc, 0);
+	hitfb_accel_wait();
+}
+
+static int hitfb_pan_display(struct fb_var_screeninfo *var,
+			     struct fb_info *info)
+{
+	int xoffset = var->xoffset;
+	int yoffset = var->yoffset;
+
+	if (xoffset != 0)
+		return -EINVAL;
+
+	fb_writew(yoffset, HD64461_LCDCBAR);
+
+	return 0;
+}
+
+int hitfb_blank(int blank_mode, struct fb_info *info)
+{
+	unsigned short v;
+
+	if (blank_mode) {
+#ifdef MACH_HP600
+		sh_dac_disable(DAC_LCD_BRIGHTNESS);
+		v = fb_readw(HD64461_GPBDR);
+		v |= HD64461_GPBDR_LCDOFF;
+		fb_writew(v, HD64461_GPBDR);
+#endif
+		v = fb_readw(HD64461_LDR1);
+		v &= ~HD64461_LDR1_DON;
+		fb_writew(v, HD64461_LDR1);
+
+		v = fb_readw(HD64461_LCDCCR);
+		v |= HD64461_LCDCCR_MOFF;
+		fb_writew(v, HD64461_LCDCCR);
+
+		v = fb_readw(HD64461_STBCR);
+		v |= HD64461_STBCR_SLCDST;
+		fb_writew(v, HD64461_STBCR);
+	} else {
+		v = fb_readw(HD64461_STBCR);
+		v &= ~HD64461_STBCR_SLCDST;
+		fb_writew(v, HD64461_STBCR);
+#ifdef MACH_HP600
+		sh_dac_enable(DAC_LCD_BRIGHTNESS);
+		v = fb_readw(HD64461_GPBDR);
+		v &= ~HD64461_GPBDR_LCDOFF;
+		fb_writew(v, HD64461_GPBDR);
+#endif
+		v = fb_readw(HD64461_LDR1);
+		v |= HD64461_LDR1_DON;
+		fb_writew(v, HD64461_LDR1);
+
+		v = fb_readw(HD64461_LCDCCR);
+		v &= ~HD64461_LCDCCR_MOFF;
+		fb_writew(v, HD64461_LCDCCR);
+	}
+	return 0;
+}
+
+static int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp, struct fb_info *info)
+{
+	if (regno >= info->cmap.len)
+		return 1;
+
+	switch (info->var.bits_per_pixel) {
+	case 8:
+		fb_writew(regno << 8, HD64461_CPTWAR);
+		fb_writew(red >> 10, HD64461_CPTWDR);
+		fb_writew(green >> 10, HD64461_CPTWDR);
+		fb_writew(blue >> 10, HD64461_CPTWDR);
+		break;
+	case 16:
+		((u32 *) (info->pseudo_palette))[regno] =
+		    ((red & 0xf800)) |
+		    ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
+		break;
+	}
+	return 0;
+}
+
+static struct fb_ops hitfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_setcolreg	= hitfb_setcolreg,
+	.fb_blank	= hitfb_blank,
+	.fb_pan_display = hitfb_pan_display,
+	.fb_fillrect	= hitfb_fillrect,
+	.fb_copyarea	= hitfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+int __init hitfb_init(void)
+{
+	unsigned short lcdclor, ldr3, ldvndr;
+	int size;
+
+	if (fb_get_options("hitfb", NULL))
+		return -ENODEV;
+
+	hitfb_fix.smem_start = CONFIG_HD64461_IOBASE + 0x02000000;
+	hitfb_fix.smem_len = (MACH_HP690) ? 1024 * 1024 : 512 * 1024;
+
+	lcdclor = fb_readw(HD64461_LCDCLOR);
+	ldvndr = fb_readw(HD64461_LDVNDR);
+	ldr3 = fb_readw(HD64461_LDR3);
+
+	switch (ldr3 & 15) {
+	default:
+	case 4:
+		hitfb_var.bits_per_pixel = 8;
+		hitfb_var.xres = lcdclor;
+		break;
+	case 8:
+		hitfb_var.bits_per_pixel = 16;
+		hitfb_var.xres = lcdclor / 2;
+		break;
+	}
+	hitfb_fix.line_length = lcdclor;
+	hitfb_fix.visual = (hitfb_var.bits_per_pixel == 8) ?
+	    FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+	hitfb_var.yres = ldvndr + 1;
+	hitfb_var.xres_virtual = hitfb_var.xres;
+	hitfb_var.yres_virtual = hitfb_fix.smem_len / lcdclor;
+	switch (hitfb_var.bits_per_pixel) {
+	case 8:
+		hitfb_var.red.offset = 0;
+		hitfb_var.red.length = 8;
+		hitfb_var.green.offset = 0;
+		hitfb_var.green.length = 8;
+		hitfb_var.blue.offset = 0;
+		hitfb_var.blue.length = 8;
+		hitfb_var.transp.offset = 0;
+		hitfb_var.transp.length = 0;
+		break;
+	case 16:		/* RGB 565 */
+		hitfb_var.red.offset = 11;
+		hitfb_var.red.length = 5;
+		hitfb_var.green.offset = 5;
+		hitfb_var.green.length = 6;
+		hitfb_var.blue.offset = 0;
+		hitfb_var.blue.length = 5;
+		hitfb_var.transp.offset = 0;
+		hitfb_var.transp.length = 0;
+		break;
+	}
+
+	fb_info.fbops = &hitfb_ops;
+	fb_info.var = hitfb_var;
+	fb_info.fix = hitfb_fix;
+	fb_info.pseudo_palette = pseudo_palette;
+	fb_info.flags = FBINFO_DEFAULT;
+
+	fb_info.screen_base = (void *)hitfb_fix.smem_start;
+
+	size = (fb_info.var.bits_per_pixel == 8) ? 256 : 16;
+	fb_alloc_cmap(&fb_info.cmap, size, 0);
+
+	if (register_framebuffer(&fb_info) < 0)
+		return -EINVAL;
+
+	printk(KERN_INFO "fb%d: %s frame buffer device\n",
+	       fb_info.node, fb_info.fix.id);
+	return 0;
+}
+
+static void __exit hitfb_exit(void)
+{
+	unregister_framebuffer(&fb_info);
+}
+
+module_init(hitfb_init);
+module_exit(hitfb_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/hpfb.c b/drivers/video/hpfb.c
new file mode 100644
index 0000000..e97fe84
--- /dev/null
+++ b/drivers/video/hpfb.c
@@ -0,0 +1,416 @@
+/*
+ *	HP300 Topcat framebuffer support (derived from macfb of all things)
+ *	Phil Blundell <philb@gnu.org> 1998
+ *	DIO-II, colour map and Catseye support by
+ *	Kars de Jong <jongk@linux-m68k.org>, May 2004.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/dio.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+static struct fb_info fb_info = {
+	.fix = {
+		.id		= "HP300 ",
+		.type		= FB_TYPE_PACKED_PIXELS,
+		.visual		= FB_VISUAL_PSEUDOCOLOR,
+		.accel		= FB_ACCEL_NONE,
+	}
+};
+
+static unsigned long fb_regs;
+static unsigned char fb_bitmask;
+
+#define TC_NBLANK	0x4080
+#define TC_WEN		0x4088
+#define TC_REN		0x408c
+#define TC_FBEN		0x4090
+#define TC_PRR		0x40ea
+
+/* These defines match the X window system */
+#define RR_CLEAR	0x0
+#define RR_COPY		0x3
+#define RR_NOOP		0x5
+#define RR_XOR		0x6
+#define RR_INVERT	0xa
+#define RR_COPYINVERTED 0xc
+#define RR_SET		0xf
+
+/* blitter regs */
+#define BUSY		0x4044
+#define WMRR		0x40ef
+#define SOURCE_X	0x40f2
+#define SOURCE_Y	0x40f6
+#define DEST_X		0x40fa
+#define DEST_Y		0x40fe
+#define WHEIGHT		0x4106
+#define WWIDTH		0x4102
+#define WMOVE		0x409c
+
+static struct fb_var_screeninfo hpfb_defined = {
+	.red		= {
+		.length = 8,
+	},
+	.green		= {
+		.length = 8,
+	},
+	.blue		= {
+		.length = 8,
+	},
+	.activate	= FB_ACTIVATE_NOW,
+	.height		= -1,
+	.width		= -1,
+	.vmode		= FB_VMODE_NONINTERLACED,
+};
+
+static int hpfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			  unsigned blue, unsigned transp,
+			  struct fb_info *info)
+{
+	/* use MSBs */
+	unsigned char _red  =red>>8;
+	unsigned char _green=green>>8;
+	unsigned char _blue =blue>>8;
+	unsigned char _regno=regno;
+
+	/*
+	 *  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.
+	 */
+
+	if (regno >= info->cmap.len)
+		return 1;
+	
+	while (in_be16(fb_regs + 0x6002) & 0x4) udelay(1);
+
+	out_be16(fb_regs + 0x60ba, 0xff);
+
+	out_be16(fb_regs + 0x60b2, _red);
+	out_be16(fb_regs + 0x60b4, _green);
+	out_be16(fb_regs + 0x60b6, _blue);
+	out_be16(fb_regs + 0x60b8, ~_regno);
+	out_be16(fb_regs + 0x60f0, 0xff);
+
+	udelay(100);
+
+	while (in_be16(fb_regs + 0x6002) & 0x4) udelay(1);
+	out_be16(fb_regs + 0x60b2, 0);
+	out_be16(fb_regs + 0x60b4, 0);
+	out_be16(fb_regs + 0x60b6, 0);
+	out_be16(fb_regs + 0x60b8, 0);
+
+	return 0;
+}
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+
+static int hpfb_blank(int blank, struct fb_info *info)
+{
+	out_8(fb_regs + TC_NBLANK, (blank ? 0x00 : fb_bitmask));
+
+	return 0;
+}
+
+static void topcat_blit(int x0, int y0, int x1, int y1, int w, int h, int rr)
+{
+	if (rr >= 0) {
+		while (in_8(fb_regs + BUSY) & fb_bitmask)
+			;
+	}
+	out_8(fb_regs + TC_FBEN, fb_bitmask);
+	if (rr >= 0) {
+		out_8(fb_regs + TC_WEN, fb_bitmask);
+		out_8(fb_regs + WMRR, rr);
+	}
+	out_be16(fb_regs + SOURCE_X, x0);
+	out_be16(fb_regs + SOURCE_Y, y0);
+	out_be16(fb_regs + DEST_X, x1);
+	out_be16(fb_regs + DEST_Y, y1);
+	out_be16(fb_regs + WWIDTH, w);
+	out_be16(fb_regs + WHEIGHT, h);
+	out_8(fb_regs + WMOVE, fb_bitmask);
+}
+
+static void hpfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) 
+{
+	topcat_blit(area->sx, area->sy, area->dx, area->dy, area->width, area->height, RR_COPY);
+}
+
+static void hpfb_fillrect(struct fb_info *p, const struct fb_fillrect *region)
+{
+	u8 clr;
+
+	clr = region->color & 0xff;
+
+	while (in_8(fb_regs + BUSY) & fb_bitmask)
+		;
+
+	/* Foreground */
+	out_8(fb_regs + TC_WEN, fb_bitmask & clr);
+	out_8(fb_regs + WMRR, (region->rop == ROP_COPY ? RR_SET : RR_INVERT));
+
+	/* Background */
+	out_8(fb_regs + TC_WEN, fb_bitmask & ~clr);
+	out_8(fb_regs + WMRR, (region->rop == ROP_COPY ? RR_CLEAR : RR_NOOP));
+
+	topcat_blit(region->dx, region->dy, region->dx, region->dy, region->width, region->height, -1);
+}
+
+static int hpfb_sync(struct fb_info *info)
+{
+	/*
+	 * Since we also access the framebuffer directly, we have to wait
+	 * until the block mover is finished
+	 */
+	while (in_8(fb_regs + BUSY) & fb_bitmask)
+		;
+
+	out_8(fb_regs + TC_WEN, fb_bitmask);
+	out_8(fb_regs + TC_PRR, RR_COPY);
+	out_8(fb_regs + TC_FBEN, fb_bitmask);
+
+	return 0;
+}
+
+static struct fb_ops hpfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_setcolreg	= hpfb_setcolreg,
+	.fb_blank	= hpfb_blank,
+	.fb_fillrect	= hpfb_fillrect,
+	.fb_copyarea	= hpfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+	.fb_sync	= hpfb_sync,
+};
+
+/* Common to all HP framebuffers */
+#define HPFB_FBWMSB	0x05	/* Frame buffer width 		*/
+#define HPFB_FBWLSB	0x07
+#define HPFB_FBHMSB	0x09	/* Frame buffer height		*/
+#define HPFB_FBHLSB	0x0b
+#define HPFB_DWMSB	0x0d	/* Display width		*/
+#define HPFB_DWLSB	0x0f
+#define HPFB_DHMSB	0x11	/* Display height		*/
+#define HPFB_DHLSB	0x13
+#define HPFB_NUMPLANES	0x5b	/* Number of colour planes	*/
+#define HPFB_FBOMSB	0x5d	/* Frame buffer offset		*/
+#define HPFB_FBOLSB	0x5f
+
+static int __init hpfb_init_one(unsigned long phys_base, unsigned long virt_base)
+{
+	unsigned long fboff, fb_width, fb_height, fb_start;
+
+	fb_regs = virt_base;
+	fboff = (in_8(fb_regs + HPFB_FBOMSB) << 8) | in_8(fb_regs + HPFB_FBOLSB);
+
+	fb_info.fix.smem_start = (in_8(fb_regs + fboff) << 16);
+
+	if (phys_base >= DIOII_BASE) {
+		fb_info.fix.smem_start += phys_base;
+	}
+
+	if (DIO_SECID(fb_regs) != DIO_ID2_TOPCAT) {
+		/* This is the magic incantation the HP X server uses to make Catseye boards work. */
+		while (in_be16(fb_regs+0x4800) & 1)
+			;
+		out_be16(fb_regs+0x4800, 0);	/* Catseye status */
+		out_be16(fb_regs+0x4510, 0);	/* VB */
+		out_be16(fb_regs+0x4512, 0);	/* TCNTRL */
+		out_be16(fb_regs+0x4514, 0);	/* ACNTRL */
+		out_be16(fb_regs+0x4516, 0);	/* PNCNTRL */
+		out_be16(fb_regs+0x4206, 0x90);	/* RUG Command/Status */
+		out_be16(fb_regs+0x60a2, 0);	/* Overlay Mask */
+		out_be16(fb_regs+0x60bc, 0);	/* Ram Select */
+	}
+
+	/*
+	 *	Fill in the available video resolution
+	 */
+	fb_width = (in_8(fb_regs + HPFB_FBWMSB) << 8) | in_8(fb_regs + HPFB_FBWLSB);
+	fb_info.fix.line_length = fb_width;
+	fb_height = (in_8(fb_regs + HPFB_FBHMSB) << 8) | in_8(fb_regs + HPFB_FBHLSB);
+	fb_info.fix.smem_len = fb_width * fb_height;
+	fb_start = (unsigned long)ioremap_writethrough(fb_info.fix.smem_start,
+						       fb_info.fix.smem_len);
+	hpfb_defined.xres = (in_8(fb_regs + HPFB_DWMSB) << 8) | in_8(fb_regs + HPFB_DWLSB);
+	hpfb_defined.yres = (in_8(fb_regs + HPFB_DHMSB) << 8) | in_8(fb_regs + HPFB_DHLSB);
+	hpfb_defined.xres_virtual = hpfb_defined.xres;
+	hpfb_defined.yres_virtual = hpfb_defined.yres;
+	hpfb_defined.bits_per_pixel = in_8(fb_regs + HPFB_NUMPLANES);
+
+	printk(KERN_INFO "hpfb: framebuffer at 0x%lx, mapped to 0x%lx, size %dk\n",
+	       fb_info.fix.smem_start, fb_start, fb_info.fix.smem_len/1024);
+	printk(KERN_INFO "hpfb: mode is %dx%dx%d, linelength=%d\n",
+	       hpfb_defined.xres, hpfb_defined.yres, hpfb_defined.bits_per_pixel, fb_info.fix.line_length);
+
+	/*
+	 *	Give the hardware a bit of a prod and work out how many bits per
+	 *	pixel are supported.
+	 */
+	out_8(fb_regs + TC_WEN, 0xff);
+	out_8(fb_regs + TC_PRR, RR_COPY);
+	out_8(fb_regs + TC_FBEN, 0xff);
+	out_8(fb_start, 0xff);
+	fb_bitmask = in_8(fb_start);
+	out_8(fb_start, 0);
+
+	/*
+	 *	Enable reading/writing of all the planes.
+	 */
+	out_8(fb_regs + TC_WEN, fb_bitmask);
+	out_8(fb_regs + TC_PRR, RR_COPY);
+	out_8(fb_regs + TC_REN, fb_bitmask);
+	out_8(fb_regs + TC_FBEN, fb_bitmask);
+
+	/*
+	 *	Clear the screen.
+	 */
+	topcat_blit(0, 0, 0, 0, fb_width, fb_height, RR_CLEAR);
+
+	/*
+	 *	Let there be consoles..
+	 */
+	if (DIO_SECID(fb_regs) == DIO_ID2_TOPCAT)
+		strcat(fb_info.fix.id, "Topcat");
+	else
+		strcat(fb_info.fix.id, "Catseye");
+	fb_info.fbops = &hpfb_ops;
+	fb_info.flags = FBINFO_DEFAULT;
+	fb_info.var   = hpfb_defined;
+	fb_info.screen_base = (char *)fb_start;
+
+	fb_alloc_cmap(&fb_info.cmap, 1 << hpfb_defined.bits_per_pixel, 0);
+
+	if (register_framebuffer(&fb_info) < 0) {
+		fb_dealloc_cmap(&fb_info.cmap);
+		return 1;
+	}
+
+	printk(KERN_INFO "fb%d: %s frame buffer device\n",
+	       fb_info.node, fb_info.fix.id);
+
+	return 0;
+}
+
+/* 
+ * Check that the secondary ID indicates that we have some hope of working with this
+ * framebuffer.  The catseye boards are pretty much like topcats and we can muddle through.
+ */
+
+#define topcat_sid_ok(x)  (((x) == DIO_ID2_LRCATSEYE) || ((x) == DIO_ID2_HRCCATSEYE)    \
+			   || ((x) == DIO_ID2_HRMCATSEYE) || ((x) == DIO_ID2_TOPCAT))
+
+/* 
+ * Initialise the framebuffer
+ */
+static int __devinit hpfb_dio_probe(struct dio_dev * d, const struct dio_device_id * ent)
+{
+	unsigned long paddr, vaddr;
+
+	paddr = d->resource.start;
+	if (!request_mem_region(d->resource.start, d->resource.end - d->resource.start, d->name))
+                return -EBUSY;
+
+	if (d->scode >= DIOII_SCBASE) {
+		vaddr = (unsigned long)ioremap(paddr, d->resource.end - d->resource.start);
+	} else {
+		vaddr = paddr + DIO_VIRADDRBASE;
+	}
+	printk(KERN_INFO "Topcat found at DIO select code %d "
+	       "(secondary id %02x)\n", d->scode, (d->id >> 8) & 0xff);
+	if (hpfb_init_one(paddr, vaddr)) {
+		if (d->scode >= DIOII_SCBASE)
+			iounmap((void *)vaddr);
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static void __devexit hpfb_remove_one(struct dio_dev *d)
+{
+	unregister_framebuffer(&fb_info);
+	if (d->scode >= DIOII_SCBASE)
+		iounmap((void *)fb_regs);
+        release_mem_region(d->resource.start, d->resource.end - d->resource.start);
+}
+
+static struct dio_device_id hpfb_dio_tbl[] = {
+    { DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_LRCATSEYE) },
+    { DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_HRCCATSEYE) },
+    { DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_HRMCATSEYE) },
+    { DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_TOPCAT) },
+    { 0 }
+};
+
+static struct dio_driver hpfb_driver = {
+    .name      = "hpfb",
+    .id_table  = hpfb_dio_tbl,
+    .probe     = hpfb_dio_probe,
+    .remove    = __devexit_p(hpfb_remove_one),
+};
+
+int __init hpfb_init(void)
+{
+	unsigned int sid;
+	mm_segment_t fs;
+	unsigned char i;
+	int err;
+
+	/* Topcats can be on the internal IO bus or real DIO devices.
+	 * The internal variant sits at 0x560000; it has primary
+	 * and secondary ID registers just like the DIO version.
+	 * So we merge the two detection routines.
+	 *
+	 * Perhaps this #define should be in a global header file:
+	 * I believe it's common to all internal fbs, not just topcat.
+	 */
+#define INTFBVADDR 0xf0560000
+#define INTFBPADDR 0x560000
+
+	if (!MACH_IS_HP300)
+		return -ENXIO;
+
+	if (fb_get_options("hpfb", NULL))
+		return -ENODEV;
+
+	dio_module_init(&hpfb_driver);
+
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = get_user(i, (unsigned char *)INTFBVADDR + DIO_IDOFF);
+	set_fs(fs);
+
+	if (!err && (i == DIO_ID_FBUFFER) && topcat_sid_ok(sid = DIO_SECID(INTFBVADDR))) {
+		if (!request_mem_region(INTFBPADDR, DIO_DEVSIZE, "Internal Topcat"))
+			return -EBUSY;
+		printk(KERN_INFO "Internal Topcat found (secondary id %02x)\n", sid);
+		if (hpfb_init_one(INTFBPADDR, INTFBVADDR)) {
+			return -ENOMEM;
+		}
+	}
+	return 0;
+}
+
+void __exit hpfb_cleanup_module(void)
+{
+	dio_unregister_driver(&hpfb_driver);
+}
+
+module_init(hpfb_init);
+module_exit(hpfb_cleanup_module);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/i810/Makefile b/drivers/video/i810/Makefile
new file mode 100644
index 0000000..794ae76
--- /dev/null
+++ b/drivers/video/i810/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for the Intel 810/815 framebuffer driver
+#
+
+obj-$(CONFIG_FB_I810)		+= i810fb.o
+
+
+i810fb-objs                     := i810_main.o i810_accel.o
+
+ifdef CONFIG_FB_I810_GTF
+i810fb-objs                     += i810_gtf.o
+else
+i810fb-objs                     += i810_dvt.o
+endif
diff --git a/drivers/video/i810/i810.h b/drivers/video/i810/i810.h
new file mode 100644
index 0000000..fe3b757
--- /dev/null
+++ b/drivers/video/i810/i810.h
@@ -0,0 +1,285 @@
+/*-*- linux-c -*-
+ *  linux/drivers/video/i810.h -- Intel 810 General Definitions/Declarations
+ *
+ *      Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
+ *      All Rights Reserved      
+ *
+ *
+ *  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 __I810_H__
+#define __I810_H__
+
+#include <linux/list.h>
+#include <linux/agp_backend.h>
+#include <linux/fb.h>
+#include <video/vga.h>
+
+/* Fence */
+#define TILEWALK_X            (0 << 12)
+#define TILEWALK_Y            (1 << 12)
+
+/* Raster ops */
+#define COLOR_COPY_ROP        0xF0
+#define PAT_COPY_ROP          0xCC
+#define CLEAR_ROP             0x00
+#define WHITE_ROP             0xFF
+#define INVERT_ROP            0x55
+#define XOR_ROP               0x5A
+
+/* 2D Engine definitions */
+#define SOLIDPATTERN          0x80000000
+#define NONSOLID              0x00000000
+#define BPP8                  (0 << 24)
+#define BPP16                 (1 << 24)
+#define BPP24                 (2 << 24)
+
+#define PIXCONF8              (2 << 16)
+#define PIXCONF15             (4 << 16)
+#define PIXCONF16             (5 << 16)
+#define PIXCONF24             (6 << 16)
+#define PIXCONF32             (7 << 16)
+
+#define DYN_COLOR_EN          (1 << 26)
+#define DYN_COLOR_DIS         (0 << 26)
+#define INCREMENT             0x00000000
+#define DECREMENT             (0x01 << 30)
+#define ARB_ON                0x00000001
+#define ARB_OFF               0x00000000
+#define SYNC_FLIP             0x00000000
+#define ASYNC_FLIP            0x00000040
+#define OPTYPE_MASK           0xE0000000
+#define PARSER_MASK           0x001F8000 
+#define D2_MASK               0x001FC000         /* 2D mask */
+
+/* Instruction type */
+/* There are more but pertains to 3D */
+#define PARSER                0x00000000
+#define BLIT                  (0x02 << 29)
+#define RENDER                (0x03 << 29)
+            
+/* Parser */
+#define NOP                   0x00               /* No operation, padding */
+#define BP_INT                (0x01 << 23)         /* Breakpoint interrupt */
+#define USR_INT               (0x02 << 23)         /* User interrupt */
+#define WAIT_FOR_EVNT         (0x03 << 23)         /* Wait for event */
+#define FLUSH                 (0x04 << 23)              
+#define CONTEXT_SEL           (0x05 << 23)
+#define REPORT_HEAD           (0x07 << 23)
+#define ARB_ON_OFF            (0x08 << 23)
+#define OVERLAY_FLIP          (0x11 << 23)
+#define LOAD_SCAN_INC         (0x12 << 23)
+#define LOAD_SCAN_EX          (0x13 << 23)
+#define FRONT_BUFFER          (0x14 << 23)
+#define DEST_BUFFER           (0x15 << 23)
+#define Z_BUFFER              (0x16 << 23)       
+
+#define STORE_DWORD_IMM       (0x20 << 23)
+#define STORE_DWORD_IDX       (0x21 << 23)
+#define BATCH_BUFFER          (0x30 << 23)
+
+/* Blit */
+#define SETUP_BLIT                      0x00
+#define SETUP_MONO_PATTERN_SL_BLT       (0x10 << 22)
+#define PIXEL_BLT                       (0x20 << 22)
+#define SCANLINE_BLT                    (0x21 << 22)
+#define TEXT_BLT                        (0x22 << 22)
+#define TEXT_IMM_BLT                    (0x30 << 22)
+#define COLOR_BLT                       (0x40 << 22)
+#define MONO_PAT_BLIT                   (0x42 << 22)
+#define SOURCE_COPY_BLIT                (0x43 << 22)
+#define MONO_SOURCE_COPY_BLIT           (0x44 << 22)
+#define SOURCE_COPY_IMMEDIATE           (0x60 << 22)
+#define MONO_SOURCE_COPY_IMMEDIATE      (0x61 << 22)
+
+#define VERSION_MAJOR            0
+#define VERSION_MINOR            9
+#define VERSION_TEENIE           0
+#define BRANCH_VERSION           ""
+
+
+/* mvo: intel i815 */
+#ifndef PCI_DEVICE_ID_INTEL_82815_100
+  #define PCI_DEVICE_ID_INTEL_82815_100           0x1102
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_82815_NOAGP
+  #define PCI_DEVICE_ID_INTEL_82815_NOAGP         0x1112
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_82815_FULL_CTRL
+  #define PCI_DEVICE_ID_INTEL_82815_FULL_CTRL     0x1130
+#endif 
+
+/* General Defines */
+#define I810_PAGESIZE               4096
+#define MAX_DMA_SIZE                (1024 * 4096)
+#define SAREA_SIZE                  4096
+#define PCI_I810_MISCC              0x72
+#define MMIO_SIZE                   (512*1024)
+#define GTT_SIZE                    (16*1024) 
+#define RINGBUFFER_SIZE             (64*1024)
+#define CURSOR_SIZE                 4096 
+#define OFF                         0
+#define ON                          1
+#define MAX_KEY                     256
+#define WAIT_COUNT                  10000000
+#define IRING_PAD                   8
+#define FONTDATAMAX                 8192
+/* Masks (AND ops) and OR's */
+#define FB_START_MASK               (0x3f << (32 - 6))
+#define MMIO_ADDR_MASK              (0x1FFF << (32 - 13))
+#define FREQ_MASK                   0x1EF
+#define SCR_OFF                     0x20
+#define DRAM_ON                     0x08            
+#define DRAM_OFF                    0xE7
+#define PG_ENABLE_MASK              0x01
+#define RING_SIZE_MASK              (RINGBUFFER_SIZE - 1);
+
+/* defines for restoring registers partially */
+#define ADDR_MAP_MASK               (0x07 << 5)
+#define DISP_CTRL                   ~0
+#define PIXCONF_0                   (0x64 << 8)
+#define PIXCONF_2                   (0xF3 << 24)
+#define PIXCONF_1                   (0xF0 << 16)
+#define MN_MASK                     0x3FF03FF
+#define P_OR                        (0x7 << 4)                    
+#define DAC_BIT                     (1 << 16)
+#define INTERLACE_BIT               (1 << 7)
+#define IER_MASK                    (3 << 13)
+#define IMR_MASK                    (3 << 13)
+
+/* Power Management */
+#define DPMS_MASK                   0xF0000
+#define POWERON                     0x00000
+#define STANDBY                     0x20000
+#define SUSPEND                     0x80000
+#define POWERDOWN                   0xA0000
+#define EMR_MASK                    ~0x3F
+#define FW_BLC_MASK                 ~(0x3F|(7 << 8)|(0x3F << 12)|(7 << 20))
+
+/* Ringbuffer */
+#define RBUFFER_START_MASK          0xFFFFF000
+#define RBUFFER_SIZE_MASK           0x001FF000
+#define RBUFFER_HEAD_MASK           0x001FFFFC
+#define RBUFFER_TAIL_MASK           0x001FFFF8
+
+/* Video Timings */
+#define REF_FREQ                    24000000
+#define TARGET_N_MAX                30
+
+#define MAX_PIXELCLOCK              230000000
+#define MIN_PIXELCLOCK               15000000
+#define VFMAX                       60
+#define VFMIN                       60
+#define HFMAX                       30000
+#define HFMIN                       29000
+
+/* Cursor */
+#define CURSOR_ENABLE_MASK          0x1000             
+#define CURSOR_MODE_64_TRANS        4
+#define CURSOR_MODE_64_XOR	    5
+#define CURSOR_MODE_64_3C	    6	
+#define COORD_INACTIVE              0
+#define COORD_ACTIVE                (1 << 4)
+#define EXTENDED_PALETTE	    1
+  
+/* AGP Memory Types*/
+#define AGP_NORMAL_MEMORY           0
+#define AGP_DCACHE_MEMORY	    1
+#define AGP_PHYSICAL_MEMORY         2
+
+/* Allocated resource Flags */
+#define FRAMEBUFFER_REQ             1
+#define MMIO_REQ                    2
+#define PCI_DEVICE_ENABLED          4
+#define HAS_FONTCACHE               8 
+
+/* driver flags */
+#define HAS_MTRR                    1
+#define HAS_ACCELERATION            2
+#define ALWAYS_SYNC                 4
+#define LOCKUP                      8
+#define USE_HWCUR                  16
+
+struct gtt_data {
+	struct agp_memory *i810_fb_memory;
+	struct agp_memory *i810_cursor_memory;
+};
+
+struct mode_registers {
+	u32 pixclock, M, N, P;
+	u8 cr00, cr01, cr02, cr03;
+	u8 cr04, cr05, cr06, cr07;
+	u8 cr09, cr10, cr11, cr12;
+	u8 cr13, cr15, cr16, cr30;
+	u8 cr31, cr32, cr33, cr35, cr39;
+	u32 bpp8_100, bpp16_100;
+	u32 bpp24_100, bpp8_133;
+	u32 bpp16_133, bpp24_133;
+	u8 msr;
+};
+
+struct heap_data {
+        unsigned long physical;
+	__u8 __iomem *virtual;
+	u32 offset;
+	u32 size;
+};	
+
+struct state_registers {
+	u32 dclk_1d, dclk_2d, dclk_0ds;
+	u32 pixconf, fw_blc, pgtbl_ctl;
+	u32 fence0, hws_pga, dplystas;
+	u16 bltcntl, hwstam, ier, iir, imr;
+	u8 cr00, cr01, cr02, cr03, cr04;
+	u8 cr05, cr06, cr07, cr08, cr09;
+	u8 cr10, cr11, cr12, cr13, cr14;
+	u8 cr15, cr16, cr17, cr80, gr10;
+	u8 cr30, cr31, cr32, cr33, cr35;
+	u8 cr39, cr41, cr70, sr01, msr;
+};
+
+struct i810fb_par {
+	struct mode_registers    regs;
+	struct state_registers   hw_state;
+	struct gtt_data          i810_gtt;
+	struct fb_ops            i810fb_ops;
+	struct pci_dev           *dev;
+	struct heap_data         aperture;
+	struct heap_data         fb;
+	struct heap_data         iring;
+	struct heap_data         cursor_heap;
+	struct vgastate          state;
+	atomic_t                 use_count;
+	u32 pseudo_palette[17];
+	unsigned long mmio_start_phys;
+	u8 __iomem *mmio_start_virtual;
+	u32 pitch;
+	u32 pixconf;
+	u32 watermark;
+	u32 mem_freq;
+	u32 res_flags;
+	u32 dev_flags;
+	u32 cur_tail;
+	u32 depth;
+	u32 blit_bpp;
+	u32 ovract;
+	u32 cur_state;
+	int mtrr_reg;
+	u16 bltcntl;
+	u8 interlace;
+};
+
+/* 
+ * Register I/O
+ */
+#define i810_readb(where, mmio) readb(mmio + where)
+#define i810_readw(where, mmio) readw(mmio + where)
+#define i810_readl(where, mmio) readl(mmio + where)
+#define i810_writeb(where, mmio, val) writeb(val, mmio + where) 
+#define i810_writew(where, mmio, val) writew(val, mmio + where)
+#define i810_writel(where, mmio, val) writel(val, mmio + where)
+
+#endif /* __I810_H__ */
diff --git a/drivers/video/i810/i810_accel.c b/drivers/video/i810/i810_accel.c
new file mode 100644
index 0000000..64cd1c8
--- /dev/null
+++ b/drivers/video/i810/i810_accel.c
@@ -0,0 +1,449 @@
+/*-*- linux-c -*-
+ *  linux/drivers/video/i810_accel.c -- Hardware Acceleration
+ *
+ *      Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
+ *      All Rights Reserved      
+ *
+ *  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/kernel.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+
+#include "i810_regs.h"
+#include "i810.h"
+
+static u32 i810fb_rop[] = {
+	COLOR_COPY_ROP, /* ROP_COPY */
+	XOR_ROP         /* ROP_XOR  */
+};
+
+/* Macros */
+#define PUT_RING(n) {                                        \
+	i810_writel(par->cur_tail, par->iring.virtual, n);   \
+        par->cur_tail += 4;                                  \
+        par->cur_tail &= RING_SIZE_MASK;                     \
+}                                                                      
+
+extern void flush_cache(void);
+
+/************************************************************/
+
+/* BLT Engine Routines */
+static inline void i810_report_error(u8 __iomem *mmio)
+{
+	printk("IIR     : 0x%04x\n"
+	       "EIR     : 0x%04x\n"
+	       "PGTBL_ER: 0x%04x\n"
+	       "IPEIR   : 0x%04x\n"
+	       "IPEHR   : 0x%04x\n",
+	       i810_readw(IIR, mmio),
+	       i810_readb(EIR, mmio),
+	       i810_readl(PGTBL_ER, mmio),
+	       i810_readl(IPEIR, mmio), 
+	       i810_readl(IPEHR, mmio));
+}
+
+/**
+ * wait_for_space - check ring buffer free space
+ * @space: amount of ringbuffer space needed in bytes
+ * @par: pointer to i810fb_par structure
+ *
+ * DESCRIPTION:
+ * The function waits until a free space from the ringbuffer
+ * is available 
+ */	
+static inline int wait_for_space(struct fb_info *info, u32 space)
+{
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+	u32 head, count = WAIT_COUNT, tail;
+	u8 __iomem *mmio = par->mmio_start_virtual;
+
+	tail = par->cur_tail;
+	while (count--) {
+		head = i810_readl(IRING + 4, mmio) & RBUFFER_HEAD_MASK;	
+		if ((tail == head) || 
+		    (tail > head && 
+		     (par->iring.size - tail + head) >= space) || 
+		    (tail < head && (head - tail) >= space)) {
+			return 0;	
+		}
+	}
+	printk("ringbuffer lockup!!!\n");
+	i810_report_error(mmio); 
+	par->dev_flags |= LOCKUP;
+	info->pixmap.scan_align = 1;
+	return 1;
+}
+
+/** 
+ * wait_for_engine_idle - waits for all hardware engines to finish
+ * @par: pointer to i810fb_par structure
+ *
+ * DESCRIPTION:
+ * This waits for lring(0), iring(1), and batch(3), etc to finish and
+ * waits until ringbuffer is empty.
+ */
+static inline int wait_for_engine_idle(struct fb_info *info)
+{
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+	u8 __iomem *mmio = par->mmio_start_virtual;
+	int count = WAIT_COUNT;
+
+	if (wait_for_space(info, par->iring.size)) /* flush */
+		return 1;
+
+	while((i810_readw(INSTDONE, mmio) & 0x7B) != 0x7B && --count); 
+	if (count) return 0;
+
+	printk("accel engine lockup!!!\n");
+	printk("INSTDONE: 0x%04x\n", i810_readl(INSTDONE, mmio));
+	i810_report_error(mmio); 
+	par->dev_flags |= LOCKUP;
+	info->pixmap.scan_align = 1;
+	return 1;
+}
+
+/* begin_iring - prepares the ringbuffer 
+ * @space: length of sequence in dwords
+ * @par: pointer to i810fb_par structure
+ *
+ * DESCRIPTION:
+ * Checks/waits for sufficent space in ringbuffer of size
+ * space.  Returns the tail of the buffer
+ */ 
+static inline u32 begin_iring(struct fb_info *info, u32 space)
+{
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+
+	if (par->dev_flags & ALWAYS_SYNC) 
+		wait_for_engine_idle(info);
+	return wait_for_space(info, space);
+}
+
+/**
+ * end_iring - advances the buffer
+ * @par: pointer to i810fb_par structure
+ *
+ * DESCRIPTION:
+ * This advances the tail of the ringbuffer, effectively
+ * beginning the execution of the graphics instruction sequence.
+ */
+static inline void end_iring(struct i810fb_par *par)
+{
+	u8 __iomem *mmio = par->mmio_start_virtual;
+
+	i810_writel(IRING, mmio, par->cur_tail);
+}
+
+/**
+ * source_copy_blit - BLIT transfer operation
+ * @dwidth: width of rectangular graphics data
+ * @dheight: height of rectangular graphics data
+ * @dpitch: bytes per line of destination buffer
+ * @xdir: direction of copy (left to right or right to left)
+ * @src: address of first pixel to read from
+ * @dest: address of first pixel to write to
+ * @from: source address
+ * @where: destination address
+ * @rop: raster operation
+ * @blit_bpp: pixel format which can be different from the 
+ *            framebuffer's pixelformat
+ * @par: pointer to i810fb_par structure
+ *
+ * DESCRIPTION:
+ * This is a BLIT operation typically used when doing
+ * a 'Copy and Paste'
+ */
+static inline void source_copy_blit(int dwidth, int dheight, int dpitch, 
+				    int xdir, int src, int dest, int rop, 
+				    int blit_bpp, struct fb_info *info)
+{
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+
+	if (begin_iring(info, 24 + IRING_PAD)) return;
+
+	PUT_RING(BLIT | SOURCE_COPY_BLIT | 4);
+	PUT_RING(xdir | rop << 16 | dpitch | DYN_COLOR_EN | blit_bpp);
+	PUT_RING(dheight << 16 | dwidth);
+	PUT_RING(dest);
+	PUT_RING(dpitch);
+	PUT_RING(src);
+
+	end_iring(par);
+}	
+
+/**
+ * color_blit - solid color BLIT operation
+ * @width: width of destination
+ * @height: height of destination
+ * @pitch: pixels per line of the buffer
+ * @dest: address of first pixel to write to
+ * @where: destination
+ * @rop: raster operation
+ * @what: color to transfer
+ * @blit_bpp: pixel format which can be different from the 
+ *            framebuffer's pixelformat
+ * @par: pointer to i810fb_par structure
+ *
+ * DESCRIPTION:
+ * A BLIT operation which can be used for  color fill/rectangular fill
+ */
+static inline void color_blit(int width, int height, int pitch,  int dest, 
+			      int rop, int what, int blit_bpp, 
+			      struct fb_info *info)
+{
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+
+	if (begin_iring(info, 24 + IRING_PAD)) return;
+
+	PUT_RING(BLIT | COLOR_BLT | 3);
+	PUT_RING(rop << 16 | pitch | SOLIDPATTERN | DYN_COLOR_EN | blit_bpp);
+	PUT_RING(height << 16 | width);
+	PUT_RING(dest);
+	PUT_RING(what);
+	PUT_RING(NOP);
+
+	end_iring(par);
+}
+ 
+/**
+ * mono_src_copy_imm_blit - color expand from system memory to framebuffer
+ * @dwidth: width of destination
+ * @dheight: height of destination
+ * @dpitch: pixels per line of the buffer
+ * @dsize: size of bitmap in double words
+ * @dest: address of first byte of pixel;
+ * @rop: raster operation
+ * @blit_bpp: pixelformat to use which can be different from the 
+ *            framebuffer's pixelformat
+ * @src: address of image data
+ * @bg: backgound color
+ * @fg: forground color
+ * @par: pointer to i810fb_par structure
+ *
+ * DESCRIPTION:
+ * A color expand operation where the  source data is placed in the 
+ * ringbuffer itself. Useful for drawing text. 
+ *
+ * REQUIREMENT:
+ * The end of a scanline must be padded to the next word.
+ */
+static inline void mono_src_copy_imm_blit(int dwidth, int dheight, int dpitch,
+					  int dsize, int blit_bpp, int rop,
+					  int dest, const u32 *src, int bg,
+					  int fg, struct fb_info *info)
+{
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+
+	if (begin_iring(info, 24 + (dsize << 2) + IRING_PAD)) return;
+
+	PUT_RING(BLIT | MONO_SOURCE_COPY_IMMEDIATE | (4 + dsize));
+	PUT_RING(DYN_COLOR_EN | blit_bpp | rop << 16 | dpitch);
+	PUT_RING(dheight << 16 | dwidth);
+	PUT_RING(dest);
+	PUT_RING(bg);
+	PUT_RING(fg);
+	while (dsize--) 
+		PUT_RING(*src++);
+
+	end_iring(par);
+}
+
+static inline void load_front(int offset, struct fb_info *info)
+{
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+
+	if (begin_iring(info, 8 + IRING_PAD)) return;
+
+	PUT_RING(PARSER | FLUSH);
+	PUT_RING(NOP);
+
+	end_iring(par);
+
+	if (begin_iring(info, 8 + IRING_PAD)) return;
+
+	PUT_RING(PARSER | FRONT_BUFFER | ((par->pitch >> 3) << 8));
+	PUT_RING((par->fb.offset << 12) + offset);
+
+	end_iring(par);
+}
+
+/**
+ * i810fb_iring_enable - enables/disables the ringbuffer
+ * @mode: enable or disable
+ * @par: pointer to i810fb_par structure
+ *
+ * DESCRIPTION:
+ * Enables or disables the ringbuffer, effectively enabling or
+ * disabling the instruction/acceleration engine.
+ */
+static inline void i810fb_iring_enable(struct i810fb_par *par, u32 mode)
+{
+	u32 tmp;
+	u8 __iomem *mmio = par->mmio_start_virtual;
+
+	tmp = i810_readl(IRING + 12, mmio);
+	if (mode == OFF) 
+		tmp &= ~1;
+	else 
+		tmp |= 1;
+	flush_cache();
+	i810_writel(IRING + 12, mmio, tmp);
+}       
+
+void i810fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+	u32 dx, dy, width, height, dest, rop = 0, color = 0;
+
+	if (!info->var.accel_flags || par->dev_flags & LOCKUP ||
+	    par->depth == 4) 
+		return cfb_fillrect(info, rect);
+
+	if (par->depth == 1) 
+		color = rect->color;
+	else 
+		color = ((u32 *) (info->pseudo_palette))[rect->color];
+
+	rop = i810fb_rop[rect->rop];
+
+	dx = rect->dx * par->depth;
+	width = rect->width * par->depth;
+	dy = rect->dy;
+	height = rect->height;
+
+	dest = info->fix.smem_start + (dy * info->fix.line_length) + dx;
+	color_blit(width, height, info->fix.line_length, dest, rop, color, 
+		   par->blit_bpp, info);
+}
+	
+void i810fb_copyarea(struct fb_info *info, const struct fb_copyarea *region) 
+{
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+	u32 sx, sy, dx, dy, pitch, width, height, src, dest, xdir;
+
+	if (!info->var.accel_flags || par->dev_flags & LOCKUP ||
+	    par->depth == 4)
+		return cfb_copyarea(info, region);
+
+	dx = region->dx * par->depth;
+	sx = region->sx * par->depth;
+	width = region->width * par->depth;
+	sy = region->sy;
+	dy = region->dy;
+	height = region->height;
+
+	if (dx <= sx) {
+		xdir = INCREMENT;
+	}
+	else {
+		xdir = DECREMENT;
+		sx += width - 1;
+		dx += width - 1;
+	}
+	if (dy <= sy) {
+		pitch = info->fix.line_length;
+	}
+	else {
+		pitch = (-(info->fix.line_length)) & 0xFFFF;
+		sy += height - 1;
+		dy += height - 1;
+	}
+	src = info->fix.smem_start + (sy * info->fix.line_length) + sx;
+	dest = info->fix.smem_start + (dy * info->fix.line_length) + dx;
+
+	source_copy_blit(width, height, pitch, xdir, src, dest,
+			 PAT_COPY_ROP, par->blit_bpp, info);
+}
+
+void i810fb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+	u32 fg = 0, bg = 0, size, dst;
+	
+	if (!info->var.accel_flags || par->dev_flags & LOCKUP ||
+	    par->depth == 4 || image->depth != 1) 
+		return cfb_imageblit(info, image);
+
+	switch (info->var.bits_per_pixel) {
+	case 8:
+		fg = image->fg_color;
+		bg = image->bg_color;
+		break;
+	case 16:
+	case 24:
+		fg = ((u32 *)(info->pseudo_palette))[image->fg_color];
+		bg = ((u32 *)(info->pseudo_palette))[image->bg_color];
+		break;
+	}	
+	
+	dst = info->fix.smem_start + (image->dy * info->fix.line_length) + 
+		(image->dx * par->depth);
+
+	size = (image->width+7)/8 + 1;
+	size &= ~1;
+	size *= image->height;
+	size += 7;
+	size &= ~7;
+	mono_src_copy_imm_blit(image->width * par->depth, 
+			       image->height, info->fix.line_length, 
+			       size/4, par->blit_bpp,
+			       PAT_COPY_ROP, dst, (u32 *) image->data, 
+			       bg, fg, info);
+} 
+
+int i810fb_sync(struct fb_info *info)
+{
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+	
+	if (!info->var.accel_flags || par->dev_flags & LOCKUP)
+		return 0;
+
+	return wait_for_engine_idle(info);
+}
+
+void i810fb_load_front(u32 offset, struct fb_info *info)
+{
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+	u8 __iomem *mmio = par->mmio_start_virtual;
+
+	if (!info->var.accel_flags || par->dev_flags & LOCKUP)
+		i810_writel(DPLYBASE, mmio, par->fb.physical + offset);
+	else 
+		load_front(offset, info);
+}
+
+/**
+ * i810fb_init_ringbuffer - initialize the ringbuffer
+ * @par: pointer to i810fb_par structure
+ *
+ * DESCRIPTION:
+ * Initializes the ringbuffer by telling the device the
+ * size and location of the ringbuffer.  It also sets 
+ * the head and tail pointers = 0
+ */
+void i810fb_init_ringbuffer(struct fb_info *info)
+{
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+	u32 tmp1, tmp2;
+	u8 __iomem *mmio = par->mmio_start_virtual;
+	
+	wait_for_engine_idle(info);
+	i810fb_iring_enable(par, OFF);
+	i810_writel(IRING, mmio, 0);
+	i810_writel(IRING + 4, mmio, 0);
+	par->cur_tail = 0;
+
+	tmp2 = i810_readl(IRING + 8, mmio) & ~RBUFFER_START_MASK; 
+	tmp1 = par->iring.physical;
+	i810_writel(IRING + 8, mmio, tmp2 | tmp1);
+
+	tmp1 = i810_readl(IRING + 12, mmio);
+	tmp1 &= ~RBUFFER_SIZE_MASK;
+	tmp2 = (par->iring.size - I810_PAGESIZE) & RBUFFER_SIZE_MASK;
+	i810_writel(IRING + 12, mmio, tmp1 | tmp2);
+	i810fb_iring_enable(par, ON);
+}
diff --git a/drivers/video/i810/i810_dvt.c b/drivers/video/i810/i810_dvt.c
new file mode 100644
index 0000000..27fa703
--- /dev/null
+++ b/drivers/video/i810/i810_dvt.c
@@ -0,0 +1,307 @@
+/*-*- linux-c -*-
+ *  linux/drivers/video/i810_dvt.c -- Intel 810 Discrete Video Timings (Intel)
+ *
+ *      Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
+ *      All Rights Reserved      
+ *
+ *
+ *  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/kernel.h>
+
+#include "i810_regs.h"
+#include "i810.h"
+
+struct mode_registers std_modes[] = {
+	/* 640x480 @ 60Hz */
+	{ 25000, 0x0013, 0x0003, 0x40, 0x5F, 0x4F, 0x50, 0x82, 0x51, 0x9D,
+	  0x0B, 0x10, 0x40, 0xE9, 0x0B, 0xDF, 0x50, 0xE7, 0x04, 0x02,
+	  0x01, 0x01, 0x01, 0x00, 0x01, 0x22002000, 0x22004000, 0x22006000,
+	  0x22002000, 0x22004000, 0x22006000, 0xC0 }, 
+	  
+	/* 640x480 @ 70Hz */
+	{ 28000, 0x0053, 0x0010, 0x40, 0x61, 0x4F, 0x4F, 0x85, 0x52, 0x9A,
+	  0xF2, 0x10, 0x40, 0xE0, 0x03, 0xDF, 0x50, 0xDF, 0xF3, 0x01, 
+	  0x01, 0x01, 0x01, 0x00, 0x01, 0x22002000, 0x22004000, 0x22005000,
+          0x22002000, 0x22004000, 0x22005000, 0xC0 },
+          
+        /* 640x480 @ 72Hz */
+        { 31000, 0x0013, 0x0002, 0x40, 0x63, 0x4F, 0x4F, 0x87, 0x52, 0x97,
+          0x06, 0x0F, 0x40, 0xE8, 0x0B, 0xDF, 0x50, 0xDF, 0x07, 0x02, 
+          0x01, 0x01, 0x01, 0x00, 0x01, 0x22003000, 0x22005000, 0x22007000,
+          0x22003000, 0x22005000, 0x22007000, 0xC0 },
+          
+        /* 640x480 @ 75Hz */
+        { 31000, 0x0013, 0x0002, 0x40, 0x64, 0x4F, 0x4F, 0x88, 0x51, 0x99, 
+          0xF2, 0x10, 0x40, 0xE0, 0x03, 0xDF, 0x50, 0xDF, 0xF3, 0x01, 
+          0x01, 0x01, 0x01, 0x00, 0x01, 0x22003000, 0x22005000, 0x22007000, 
+          0x22003000, 0x22005000, 0x22007000, 0xC0 },
+          
+        /* 640x480 @ 85Hz */
+        { 36000, 0x0010, 0x0001, 0x40, 0x63, 0x4F, 0x4F, 0x87, 0x56, 0x9D,
+          0xFB, 0x10, 0x40, 0xE0, 0x03, 0xDF, 0x50, 0xDF, 0xFC, 0x01,
+          0x01, 0x01, 0x01, 0x00, 0x01, 0x22003000, 0x22005000, 0x22107000,
+          0x22003000, 0x22005000, 0x22107000, 0xC0 },
+          
+        /* 800x600 @ 56Hz */
+        { 36000, 0x0010, 0x0001, 0x40, 0x7B, 0x63, 0x63, 0x9F, 0x66, 0x8F,
+          0x6F, 0x10, 0x40, 0x58, 0x0A, 0x57, 0xC8, 0x57, 0x70, 0x02, 
+          0x02, 0x02, 0x02, 0x00, 0x01, 0x22003000, 0x22005000, 0x22107000,
+          0x22003000, 0x22005000, 0x22107000, 0x00 },
+          
+        /* 800x600 @ 60Hz */
+        { 40000, 0x0008, 0x0001, 0x30, 0x7F, 0x63, 0x63, 0x83, 0x68, 0x18, 
+          0x72, 0x10, 0x40, 0x58, 0x0C, 0x57, 0xC8, 0x57, 0x73, 0x02,
+          0x02, 0x02, 0x02, 0x00, 0x00, 0x22003000, 0x22006000, 0x22108000,
+          0x22003000, 0x22006000, 0x22108000, 0x00 },
+          
+        /* 800x600 @ 70Hz */
+        { 45000, 0x0054, 0x0015, 0x30, 0x7D, 0x63, 0x63, 0x81, 0x68, 0x12,
+          0x6f, 0x10, 0x40, 0x58, 0x0b, 0x57, 0x64, 0x57, 0x70, 0x02, 
+          0x02, 0x02, 0x02, 0x00, 0x00, 0x22004000, 0x22007000, 0x2210A000, 
+          0x22004000, 0x22007000, 0x2210A000, 0x00 },
+          
+        /* 800x600 @ 72Hz */
+        { 50000, 0x0017, 0x0004, 0x30, 0x7D, 0x63, 0x63, 0x81, 0x6A, 0x19,
+          0x98, 0x10, 0x40, 0x7C, 0x02, 0x57, 0xC8, 0x57, 0x99, 0x02, 
+          0x02, 0x02, 0x02, 0x00, 0x00, 0x22004000, 0x22007000, 0x2210A000,
+          0x22004000, 0x22007000, 0x2210A000, 0x00 }, 
+          
+        /* 800x600 @ 75Hz */
+        { 49000, 0x001F, 0x0006, 0x30, 0x7F, 0x63, 0x63, 0x83, 0x65, 0x0F,
+          0x6F, 0x10, 0x40, 0x58, 0x0B, 0x57, 0xC8, 0x57, 0x70, 0x02, 
+          0x02, 0x02, 0x02, 0x00, 0x00, 0x22004000, 0x22007000, 0x2210B000,
+          0x22004000, 0x22007000, 0x2210B000, 0x00 },
+          
+        /* 800x600 @ 85Hz */
+        { 56000, 0x0049, 0x000E, 0x30, 0x7E, 0x63, 0x63, 0x82, 0x67, 0x0F,
+          0x75, 0x10, 0x40, 0x58, 0x0B, 0x57, 0xC8, 0x57, 0x76, 0x02,
+          0x02, 0x02, 0x02, 0x00, 0x00, 0x22004000, 0x22108000, 0x2210b000, 
+          0x22004000, 0x22108000, 0x2210b000, 0x00 },
+          
+        /* 1024x768 @ 60Hz */
+        { 65000, 0x003F, 0x000A, 0x30, 0xA3, 0x7F, 0x7F, 0x87, 0x83, 0x94,
+          0x24, 0x10, 0x40, 0x02, 0x08, 0xFF, 0x80, 0xFF, 0x25, 0x03,
+          0x02, 0x03, 0x02, 0x00, 0x00, 0x22005000, 0x22109000, 0x2220D000,
+          0x22005000, 0x22109000, 0x2220D000, 0xC0 },
+          
+        /* 1024x768 @ 70Hz */
+	{ 75000, 0x0017, 0x0002, 0x30, 0xA1, 0x7F, 0x7F, 0x85, 0x82, 0x93,
+	  0x24, 0x10, 0x40, 0x02, 0x08, 0xFF, 0x80, 0xFF, 0x25, 0x03,
+	  0x02, 0x03, 0x02, 0x00, 0x00, 0x22005000, 0x2210A000, 0x2220F000,
+	  0x22005000, 0x2210A000, 0x2220F000, 0xC0 }, 
+	  
+	/* 1024x768 @ 75Hz */          
+	{ 78000, 0x0050, 0x0017, 0x20, 0x9F, 0x7F, 0x7F, 0x83, 0x81, 0x8D,
+	  0x1E, 0x10, 0x40, 0x00, 0x03, 0xFF, 0x80, 0xFF, 0x1F, 0x03,
+	  0x02, 0x03, 0x02, 0x00, 0x00, 0x22006000, 0x2210B000, 0x22210000,
+	  0x22006000, 0x2210B000, 0x22210000, 0x00 },
+	  
+	/* 1024x768 @ 85Hz */
+	{ 94000, 0x003D, 0x000E, 0x20, 0xA7, 0x7F, 0x7F, 0x8B, 0x85, 0x91,
+	  0x26, 0x10, 0x40, 0x00, 0x03, 0xFF, 0x80, 0xFF, 0x27, 0x03,
+	  0x02, 0x03, 0x02, 0x00, 0x00, 0x22007000, 0x2220E000, 0x22212000,
+	  0x22007000, 0x2220E000, 0x22212000, 0x00 },
+	  
+	/* 1152x864 @ 60Hz */ 
+	{ 80000, 0x0008, 0x0001, 0x20, 0xB3, 0x8F, 0x8F, 0x97, 0x93, 0x9f,
+	  0x87, 0x10, 0x40, 0x60, 0x03, 0x5F, 0x90, 0x5f, 0x88, 0x03,
+	  0x03, 0x03, 0x03, 0x00, 0x00, 0x2220C000, 0x22210000, 0x22415000,   
+	  0x2220C000, 0x22210000, 0x22415000, 0x00 },
+	  
+	/* 1152x864 @ 70Hz */
+	{ 96000, 0x000a, 0x0001, 0x20, 0xbb, 0x8F, 0x8F, 0x9f, 0x98, 0x87, 
+	  0x82, 0x10, 0x40, 0x60, 0x03, 0x5F, 0x90, 0x5F, 0x83, 0x03,
+	  0x03, 0x03, 0x03, 0x00, 0x00, 0x22107000, 0x22210000, 0x22415000,
+	  0x22107000, 0x22210000, 0x22415000, 0x00 },
+	  
+	/* 1152x864 @ 72Hz */
+	{ 99000, 0x001f, 0x0006, 0x20, 0xbb, 0x8F, 0x8F, 0x9f, 0x98, 0x87,
+	  0x83, 0x10, 0x40, 0x60, 0x03, 0x5F, 0x90, 0x5F, 0x84, 0x03,
+	  0x03, 0x03, 0x03, 0x00, 0x00, 0x22107000, 0x22210000, 0x22415000,
+	  0x22107000, 0x22210000, 0x22415000, 0x00 },
+	  
+	/* 1152x864 @ 75Hz */
+	{ 108000, 0x0010, 0x0002, 0x20, 0xC3, 0x8F, 0x8F, 0x87, 0x97, 0x07,
+	  0x82, 0x10, 0x40, 0x60, 0x03, 0x5F, 0x90, 0x5F, 0x83, 0x03, 
+	  0x03, 0x03, 0x03, 0x00, 0x01, 0x22107000, 0x22210000, 0x22415000,
+	  0x22107000, 0x22210000, 0x22415000, 0x00 },
+	  
+	/* 1152x864 @ 85Hz */
+	{ 121000, 0x006D, 0x0014, 0x20, 0xc0, 0x8F, 0x8F, 0x84, 0x97, 0x07,
+	  0x93, 0x10, 0x40, 0x60, 0x03, 0x5F, 0x90, 0x5F, 0x94, 0x03, 
+	  0x03, 0x03, 0x03, 0x00, 0x01, 0x2220C000, 0x22210000, 0x22415000,
+	  0x2220C000, 0x22210000, 0x22415000, 0x0 },
+	  
+	/* 1280x960 @ 60Hz */
+	{ 108000, 0x0010, 0x0002, 0x20, 0xDC, 0x9F, 0x9F, 0x80, 0xAB, 0x99,
+	  0xE6, 0x10, 0x40, 0xC0, 0x03, 0xBF, 0xA0, 0xBF, 0xE7, 0x03,
+	  0x03, 0x03, 0x03, 0x00, 0x01, 0x2210A000, 0x22210000, 0x22415000,
+	  0x2210A000, 0x22210000, 0x22415000, 0x00 },
+	  
+	/* 1280x960 @ 75Hz */
+	{ 129000, 0x0029, 0x0006, 0x20, 0xD3, 0x9F, 0x9F, 0x97, 0xaa, 0x1b,
+	  0xE8, 0x10, 0x40, 0xC0, 0x03, 0xBF, 0xA0, 0xBF, 0xE9, 0x03,
+	  0x03, 0x03, 0x03, 0x00, 0x01, 0x2210A000, 0x22210000, 0x2241B000,
+	  0x2210A000, 0x22210000, 0x2241B000, 0x00 },
+	  
+	/* 1280x960 @ 85Hz */
+	{ 148000, 0x0042, 0x0009, 0x20, 0xD3, 0x9F, 0x9F, 0x97, 0xA7, 0x1B,
+	  0xF1, 0x10, 0x40, 0xC0, 0x03, 0xBF, 0xA0, 0xBF, 0xF2, 0x03,
+	  0x03, 0x03, 0x03, 0x00, 0x01, 0x2210A000, 0x22220000, 0x2241D000,       
+	  0x2210A000, 0x22220000, 0x2241D000, 0x00 },
+	  
+	/* 1600x1200 @ 60Hz */
+	{ 162000, 0x0019, 0x0006, 0x10, 0x09, 0xC7, 0xC7, 0x8D, 0xcf, 0x07,
+	  0xE0, 0x10, 0x40, 0xB0, 0x03, 0xAF, 0xC8, 0xAF, 0xE1, 0x04, 
+	  0x04, 0x04, 0x04, 0x01, 0x00, 0x2210b000, 0x22416000, 0x44419000,
+	  0x2210b000, 0x22416000, 0x44419000, 0x00 },
+	  
+	/* 1600x1200 @ 65 Hz */
+	{ 175000, 0x005d, 0x0018, 0x10, 0x09, 0xC7, 0xC7, 0x8D, 0xcf, 0x07,
+	  0xE0, 0x10, 0x40, 0xB0, 0x03, 0xAF, 0xC8, 0xAF, 0xE1, 0x04, 
+	  0x04, 0x04, 0x04, 0x01, 0x00, 0x2210c000, 0x22416000, 0x44419000,
+	  0x2210c000, 0x22416000, 0x44419000, 0x00 },
+	  
+	/* 1600x1200 @ 70 Hz */
+	{ 189000, 0x003D, 0x000e, 0x10, 0x09, 0xC7, 0xC7, 0x8d, 0xcf, 0x07,
+	  0xE0, 0x10, 0x40, 0xb0, 0x03, 0xAF, 0xC8, 0xaf, 0xE1, 0x04, 
+	  0x04, 0x04, 0x04, 0x01, 0x00, 0x2220e000, 0x22416000, 0x44419000,
+	  0x2220e000, 0x22416000, 0x44419000, 0x00 },
+	  
+ 	/* 1600x1200 @ 72 Hz */
+ 	{ 195000, 0x003f, 0x000e, 0x10, 0x0b, 0xC7, 0xC7, 0x8f, 0xd5, 0x0b,
+ 	  0xE1, 0x10, 0x40, 0xb0, 0x03, 0xAF, 0xC8, 0xaf, 0xe2, 0x04, 0x04,
+ 	  0x04, 0x04, 0x01, 0x00, 0x2220e000, 0x22416000, 0x44419000,
+ 	  0x2220e000, 0x22416000, 0x44419000, 0x00 }, 
+ 	  
+ 	/* 1600x1200 @ 75 Hz */
+ 	{ 202000, 0x0024, 0x0007, 0x10, 0x09, 0xC7, 0xC7, 0x8d, 0xcf, 0x07,
+ 	  0xE0, 0x10, 0x40, 0xb0, 0x03, 0xAF, 0xC8, 0xaf, 0xE1, 0x04, 0x04,
+ 	  0x04, 0x04, 0x01, 0x00, 0x2220e000, 0x22416000, 0x44419000,      
+ 	  0x2220e000, 0x22416000, 0x44419000,  0x00 },
+ 	  
+ 	/* 1600x1200 @ 85 Hz */
+	{ 229000, 0x0029, 0x0007, 0x10, 0x09, 0xC7, 0xC7, 0x8d, 0xcf, 0x07,
+	  0xE0, 0x10, 0x40, 0xb0, 0x03, 0xAF, 0xC8, 0xaf, 0xE1, 0x04, 0x04,
+	  0x04, 0x04, 0x01, 0x00, 0x22210000, 0x22416000, 0x0,
+	  0x22210000, 0x22416000, 0x0, 0x00 },
+};	 
+
+void round_off_xres(u32 *xres) 
+{
+	if (*xres <= 640)
+		*xres = 640;
+	else if (*xres <= 800)
+		*xres = 800;
+	else if (*xres <= 1024)
+		*xres = 1024;
+	else if (*xres <= 1152)
+		*xres = 1152;
+	else if (*xres <= 1280)
+		*xres = 1280;
+	else
+		*xres = 1600;
+}
+
+inline void round_off_yres(u32 *xres, u32 *yres)
+{
+	*yres = (*xres * 3) >> 2;
+}
+
+void i810fb_encode_registers(const struct fb_var_screeninfo *var,
+			     struct i810fb_par *par, u32 xres, u32 yres)
+{ 
+	u32 diff = 0, diff_best = 0xFFFFFFFF, i = 0, i_best = 0; 
+	u8 hfl;
+
+	hfl = (u8) ((xres >> 3) - 1);
+	for (i = 0; i < ARRAY_SIZE(std_modes); i++) { 
+		if (std_modes[i].cr01 == hfl) { 
+			if (std_modes[i].pixclock <= par->regs.pixclock)
+				diff = par->regs.pixclock - 
+					std_modes[i].pixclock;
+			if (diff < diff_best) {	 
+		    		i_best = i;
+		    		diff_best = diff;
+			}
+		}
+	}
+	par->regs = std_modes[i_best];
+
+	/* overlay */
+	par->ovract = ((xres + var->right_margin + var->hsync_len + 
+			var->left_margin - 32) | ((xres - 32) << 16));
+}
+
+void i810fb_fill_var_timings(struct fb_var_screeninfo *var)
+{
+	struct i810fb_par par;
+	u32 total, xres, yres;
+
+	xres = var->xres;
+	yres = var->yres;
+	
+	par.regs.pixclock = 1000000000/var->pixclock;
+	i810fb_encode_registers(var, &par, xres, yres);
+	
+	total = ((par.regs.cr00 | (par.regs.cr35 & 1) << 8) + 3) << 3;
+	
+	var->pixclock = 1000000000/par.regs.pixclock;
+	var->right_margin = (par.regs.cr04 << 3) - xres;
+	var->hsync_len = ((par.regs.cr05 & 0x1F) - 
+			       (par.regs.cr04 & 0x1F)) << 3;
+	var->left_margin = (total - (xres + var->right_margin + 
+				     var->hsync_len));
+	var->sync = FB_SYNC_ON_GREEN;
+	if (~(par.regs.msr & (1 << 6)))
+		var->sync |= FB_SYNC_HOR_HIGH_ACT;
+	if (~(par.regs.msr & (1 << 7)))
+		var->sync |= FB_SYNC_VERT_HIGH_ACT;
+
+
+	total = ((par.regs.cr06 | (par.regs.cr30 & 0x0F)  << 8)) + 2;
+	var->lower_margin = (par.regs.cr10 | 
+			     (par.regs.cr32 & 0x0F) << 8) - yres;
+	var->vsync_len = (par.regs.cr11 & 0x0F) - (var->lower_margin & 0x0F);
+	var->upper_margin = total - (yres + var->lower_margin + 
+				     var->vsync_len);
+}
+
+u32 i810_get_watermark(struct fb_var_screeninfo *var,
+		       struct i810fb_par *par)
+{
+	struct mode_registers *params = &par->regs;
+	u32 wmark = 0;
+	
+	if (par->mem_freq == 100) {
+		switch (var->bits_per_pixel) {
+		case 8:
+			wmark = params->bpp8_100;
+			break;
+		case 16:
+			wmark = params->bpp16_100;
+			break;
+		case 24:
+		case 32:
+			wmark = params->bpp24_100;
+		}
+	} else {					
+		switch (var->bits_per_pixel) {
+		case 8:
+			wmark = params->bpp8_133;
+			break;
+		case 16:
+			wmark = params->bpp16_133;
+			break;
+		case 24:
+		case 32:
+			wmark = params->bpp24_133;
+		}
+	}
+	return wmark;
+}	
+
diff --git a/drivers/video/i810/i810_gtf.c b/drivers/video/i810/i810_gtf.c
new file mode 100644
index 0000000..64f087a
--- /dev/null
+++ b/drivers/video/i810/i810_gtf.c
@@ -0,0 +1,275 @@
+/*-*- linux-c -*-
+ *  linux/drivers/video/i810_main.h -- Intel 810 Non-discrete Video Timings 
+ *                                     (VESA GTF)
+ *
+ *      Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
+ *      All Rights Reserved      
+ *
+ *
+ *  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/kernel.h>
+
+#include "i810_regs.h"
+#include "i810.h"
+
+/*
+ * FIFO and Watermark tables - based almost wholly on i810_wmark.c in 
+ * XFree86 v4.03 by Precision Insight.  Slightly modified for integer 
+ * operation, instead of float
+ */
+
+struct wm_info {
+   u32 freq;
+   u32  wm;
+};
+
+static struct wm_info i810_wm_8_100[] = {
+	{ 15, 0x0070c000 },  { 19, 0x0070c000 },  { 25, 0x22003000 },
+	{ 28, 0x22003000 },  { 31, 0x22003000 },  { 36, 0x22007000 },
+	{ 40, 0x22007000 },  { 45, 0x22007000 },  { 49, 0x22008000 },
+	{ 50, 0x22008000 },  { 56, 0x22008000 },  { 65, 0x22008000 },
+	{ 75, 0x22008000 },  { 78, 0x22008000 },  { 80, 0x22008000 },
+	{ 94, 0x22008000 },  { 96, 0x22107000 },  { 99, 0x22107000 },
+	{ 108, 0x22107000 }, { 121, 0x22107000 }, { 128, 0x22107000 },
+	{ 132, 0x22109000 }, { 135, 0x22109000 }, { 157, 0x2210b000 },
+	{ 162, 0x2210b000 }, { 175, 0x2210b000 }, { 189, 0x2220e000 },
+	{ 195, 0x2220e000 }, { 202, 0x2220e000 }, { 204, 0x2220e000 },
+	{ 218, 0x2220f000 }, { 229, 0x22210000 }, { 234, 0x22210000 }, 
+};
+
+static struct wm_info i810_wm_16_100[] = {
+	{ 15, 0x0070c000 },  { 19, 0x0020c000 },  { 25, 0x22006000 },
+	{ 28, 0x22006000 },  { 31, 0x22007000 },  { 36, 0x22007000 },
+	{ 40, 0x22007000 },  { 45, 0x22007000 },  { 49, 0x22009000 },
+	{ 50, 0x22009000 },  { 56, 0x22108000 },  { 65, 0x2210e000 },
+	{ 75, 0x2210e000 },  { 78, 0x2210e000 },  { 80, 0x22210000 },
+	{ 94, 0x22210000 },  { 96, 0x22210000 },  { 99, 0x22210000 },
+	{ 108, 0x22210000 }, { 121, 0x22210000 }, { 128, 0x22210000 },
+	{ 132, 0x22314000 }, { 135, 0x22314000 }, { 157, 0x22415000 },
+	{ 162, 0x22416000 }, { 175, 0x22416000 }, { 189, 0x22416000 },
+	{ 195, 0x22416000 }, { 202, 0x22416000 }, { 204, 0x22416000 },
+	{ 218, 0x22416000 }, { 229, 0x22416000 },
+};
+
+static struct wm_info i810_wm_24_100[] = {
+	{ 15, 0x0020c000 },  { 19, 0x0040c000 },  { 25, 0x22009000 },
+	{ 28, 0x22009000 },  { 31, 0x2200a000 },  { 36, 0x2210c000 },
+	{ 40, 0x2210c000 },  { 45, 0x2210c000 },  { 49, 0x22111000 },
+	{ 50, 0x22111000 },  { 56, 0x22111000 },  { 65, 0x22214000 },
+	{ 75, 0x22214000 },  { 78, 0x22215000 },  { 80, 0x22216000 },
+	{ 94, 0x22218000 },  { 96, 0x22418000 },  { 99, 0x22418000 },
+	{ 108, 0x22418000 }, { 121, 0x22418000 }, { 128, 0x22419000 },
+	{ 132, 0x22519000 }, { 135, 0x4441d000 }, { 157, 0x44419000 },
+	{ 162, 0x44419000 }, { 175, 0x44419000 }, { 189, 0x44419000 },
+	{ 195, 0x44419000 }, { 202, 0x44419000 }, { 204, 0x44419000 },
+};
+
+static struct wm_info i810_wm_8_133[] = {
+	{ 15, 0x0070c000 },  { 19, 0x0070c000 },  { 25, 0x22003000 },
+	{ 28, 0x22003000 },  { 31, 0x22003000 },  { 36, 0x22007000 },
+	{ 40, 0x22007000 },  { 45, 0x22007000 },  { 49, 0x22008000 },
+	{ 50, 0x22008000 },  { 56, 0x22008000 },  { 65, 0x22008000 },
+	{ 75, 0x22008000 },  { 78, 0x22008000 },  { 80, 0x22008000 },
+	{ 94, 0x22008000 },  { 96, 0x22107000 },  { 99, 0x22107000 },
+	{ 108, 0x22107000 }, { 121, 0x22107000 }, { 128, 0x22107000 },
+	{ 132, 0x22109000 }, { 135, 0x22109000 }, { 157, 0x2210b000 },
+	{ 162, 0x2210b000 }, { 175, 0x2210b000 }, { 189, 0x2220e000 },
+	{ 195, 0x2220e000 }, { 202, 0x2220e000 }, { 204, 0x2220e000 },
+	{ 218, 0x2220f000 }, { 229, 0x22210000 }, { 234, 0x22210000 }, 
+};
+
+static struct wm_info i810_wm_16_133[] = {
+	{ 15, 0x0020c000 },  { 19, 0x0020c000 },  { 25, 0x22006000 },
+	{ 28, 0x22006000 },  { 31, 0x22007000 },  { 36, 0x22007000 },
+	{ 40, 0x22007000 },  { 45, 0x22007000 },  { 49, 0x22009000 },
+	{ 50, 0x22009000 },  { 56, 0x22108000 },  { 65, 0x2210e000 },
+	{ 75, 0x2210e000 },  { 78, 0x2210e000 },  { 80, 0x22210000 },
+	{ 94, 0x22210000 },  { 96, 0x22210000 },  { 99, 0x22210000 },
+	{ 108, 0x22210000 }, { 121, 0x22210000 }, { 128, 0x22210000 },
+	{ 132, 0x22314000 }, { 135, 0x22314000 }, { 157, 0x22415000 },
+	{ 162, 0x22416000 }, { 175, 0x22416000 }, { 189, 0x22416000 },
+	{ 195, 0x22416000 }, { 202, 0x22416000 }, { 204, 0x22416000 },
+	{ 218, 0x22416000 }, { 229, 0x22416000 },
+};
+
+static struct wm_info i810_wm_24_133[] = {
+	{ 15, 0x0020c000 },  { 19, 0x00408000 },  { 25, 0x22009000 },
+	{ 28, 0x22009000 },  { 31, 0x2200a000 },  { 36, 0x2210c000 },
+	{ 40, 0x2210c000 },  { 45, 0x2210c000 },  { 49, 0x22111000 },
+	{ 50, 0x22111000 },  { 56, 0x22111000 },  { 65, 0x22214000 },
+	{ 75, 0x22214000 },  { 78, 0x22215000 },  { 80, 0x22216000 },
+	{ 94, 0x22218000 },  { 96, 0x22418000 },  { 99, 0x22418000 },
+	{ 108, 0x22418000 }, { 121, 0x22418000 }, { 128, 0x22419000 },
+	{ 132, 0x22519000 }, { 135, 0x4441d000 }, { 157, 0x44419000 },
+	{ 162, 0x44419000 }, { 175, 0x44419000 }, { 189, 0x44419000 },
+	{ 195, 0x44419000 }, { 202, 0x44419000 }, { 204, 0x44419000 },
+};
+
+void round_off_xres(u32 *xres) { }
+void round_off_yres(u32 *xres, u32 *yres) { }
+
+/**
+ * i810fb_encode_registers - encode @var to hardware register values
+ * @var: pointer to var structure
+ * @par: pointer to hardware par structure
+ * 
+ * DESCRIPTION: 
+ * Timing values in @var will be converted to appropriate
+ * register values of @par.  
+ */
+void i810fb_encode_registers(const struct fb_var_screeninfo *var,
+			     struct i810fb_par *par, u32 xres, u32 yres)
+{
+	int n, blank_s, blank_e;
+	u8 __iomem *mmio = par->mmio_start_virtual;
+	u8 msr = 0;
+
+	/* Horizontal */
+	/* htotal */
+	n = ((xres + var->right_margin + var->hsync_len + 
+	      var->left_margin) >> 3) - 5;
+	par->regs.cr00 =  (u8) n;
+	par->regs.cr35 = (u8) ((n >> 8) & 1);
+	
+	/* xres */
+	par->regs.cr01 = (u8) ((xres >> 3) - 1);
+
+	/* hblank */
+	blank_e = (xres + var->right_margin + var->hsync_len + 
+		   var->left_margin) >> 3;
+	blank_e--;
+	blank_s = blank_e - 127;
+	if (blank_s < (xres >> 3))
+		blank_s = xres >> 3;
+	par->regs.cr02 = (u8) blank_s;
+	par->regs.cr03 = (u8) (blank_e & 0x1F);
+	par->regs.cr05 = (u8) ((blank_e & (1 << 5)) << 2);
+	par->regs.cr39 = (u8) ((blank_e >> 6) & 1);
+
+	/* hsync */
+	par->regs.cr04 = (u8) ((xres + var->right_margin) >> 3);
+	par->regs.cr05 |= (u8) (((xres + var->right_margin + 
+				  var->hsync_len) >> 3) & 0x1F);
+	
+       	/* Vertical */
+	/* vtotal */
+	n = yres + var->lower_margin + var->vsync_len + var->upper_margin - 2;
+	par->regs.cr06 = (u8) (n & 0xFF);
+	par->regs.cr30 = (u8) ((n >> 8) & 0x0F);
+
+	/* vsync */ 
+	n = yres + var->lower_margin;
+	par->regs.cr10 = (u8) (n & 0xFF);
+	par->regs.cr32 = (u8) ((n >> 8) & 0x0F);
+	par->regs.cr11 = i810_readb(CR11, mmio) & ~0x0F;
+	par->regs.cr11 |= (u8) ((yres + var->lower_margin + 
+				 var->vsync_len) & 0x0F);
+
+	/* yres */
+	n = yres - 1;
+	par->regs.cr12 = (u8) (n & 0xFF);
+	par->regs.cr31 = (u8) ((n >> 8) & 0x0F);
+	
+	/* vblank */
+	blank_e = yres + var->lower_margin + var->vsync_len + 
+		var->upper_margin;
+	blank_e--;
+	blank_s = blank_e - 127;
+	if (blank_s < yres)
+		blank_s = yres;
+	par->regs.cr15 = (u8) (blank_s & 0xFF);
+	par->regs.cr33 = (u8) ((blank_s >> 8) & 0x0F);
+	par->regs.cr16 = (u8) (blank_e & 0xFF);
+	par->regs.cr09 = 0;	
+
+	/* sync polarity */
+	if (!(var->sync & FB_SYNC_HOR_HIGH_ACT))
+		msr |= 1 << 6;
+	if (!(var->sync & FB_SYNC_VERT_HIGH_ACT))
+		msr |= 1 << 7;
+	par->regs.msr = msr;
+
+	/* interlace */
+	if (var->vmode & FB_VMODE_INTERLACED) 
+		par->interlace = (1 << 7) | ((u8) (var->yres >> 4));
+	else 
+		par->interlace = 0;
+
+	if (var->vmode & FB_VMODE_DOUBLE)
+		par->regs.cr09 |= 1 << 7;
+
+	/* overlay */
+	par->ovract = ((var->xres + var->right_margin + var->hsync_len + 
+			var->left_margin - 32) | ((var->xres - 32) << 16));
+}	
+
+void i810fb_fill_var_timings(struct fb_var_screeninfo *var) { }
+
+/**
+ * i810_get_watermark - gets watermark
+ * @var: pointer to fb_var_screeninfo
+ * @par: pointer to i810fb_par structure
+ *
+ * DESCRIPTION:
+ * Gets the required watermark based on 
+ * pixelclock and RAMBUS frequency.
+ * 
+ * RETURNS:
+ * watermark
+ */
+u32 i810_get_watermark(const struct fb_var_screeninfo *var,
+		       struct i810fb_par *par)
+{
+	struct wm_info *wmark = NULL;
+	u32 i, size = 0, pixclock, wm_best = 0, min, diff;
+
+	if (par->mem_freq == 100) {
+		switch (var->bits_per_pixel) { 
+		case 8:
+			wmark = i810_wm_8_100;
+			size = ARRAY_SIZE(i810_wm_8_100);
+			break;
+		case 16:
+			wmark = i810_wm_16_100;
+			size = ARRAY_SIZE(i810_wm_16_100);
+			break;
+		case 24:
+		case 32:
+			wmark = i810_wm_24_100;
+			size = ARRAY_SIZE(i810_wm_24_100);
+		}
+	} else {
+		switch(var->bits_per_pixel) {
+		case 8:
+			wmark = i810_wm_8_133;
+			size = ARRAY_SIZE(i810_wm_8_133);
+			break;
+		case 16:
+			wmark = i810_wm_16_133;
+			size = ARRAY_SIZE(i810_wm_16_133);
+			break;
+		case 24:
+		case 32:
+			wmark = i810_wm_24_133;
+			size = ARRAY_SIZE(i810_wm_24_133);
+		}
+	}
+
+	pixclock = 1000000/var->pixclock;
+	min = ~0;
+	for (i = 0; i < size; i++) {
+		if (pixclock <= wmark[i].freq) 
+			diff = wmark[i].freq - pixclock;
+		else 
+			diff = pixclock - wmark[i].freq;
+		if (diff < min) {
+			wm_best = wmark[i].wm;
+			min = diff;
+		}
+	}
+	return wm_best;		
+}	
+
diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c
new file mode 100644
index 0000000..9ec8781
--- /dev/null
+++ b/drivers/video/i810/i810_main.c
@@ -0,0 +1,2062 @@
+ /*-*- linux-c -*-
+ *  linux/drivers/video/i810_main.c -- Intel 810 frame buffer device
+ *
+ *      Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
+ *      All Rights Reserved      
+ *
+ *      Contributors:
+ *         Michael Vogt <mvogt@acm.org> - added support for Intel 815 chipsets
+ *                                        and enabling the power-on state of 
+ *                                        external VGA connectors for 
+ *                                        secondary displays
+ *
+ *         Fredrik Andersson <krueger@shell.linux.se> - alpha testing of
+ *                                        the VESA GTF
+ *
+ *         Brad Corrion <bcorrion@web-co.com> - alpha testing of customized
+ *                                        timings support
+ *
+ *	The code framework is a modification of vfb.c by Geert Uytterhoeven.
+ *      DotClock and PLL calculations are partly based on i810_driver.c 
+ *              in xfree86 v4.0.3 by Precision Insight.
+ *      Watermark calculation and tables are based on i810_wmark.c 
+ *              in xfre86 v4.0.3 by Precision Insight.  Slight modifications 
+ *              only to allow for integer operations instead of floating point.
+ *
+ *  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/module.h>
+#include <linux/config.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/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/resource.h>
+#include <linux/unistd.h>
+
+#include <asm/io.h>
+#include <asm/div64.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif 
+
+#include <asm/page.h>
+
+#include "i810_regs.h"
+#include "i810.h"
+#include "i810_main.h"
+
+/* PCI */
+static const char *i810_pci_list[] __devinitdata = {
+	"Intel(R) 810 Framebuffer Device"                                 ,
+	"Intel(R) 810-DC100 Framebuffer Device"                           ,
+	"Intel(R) 810E Framebuffer Device"                                ,
+	"Intel(R) 815 (Internal Graphics 100Mhz FSB) Framebuffer Device"  ,
+	"Intel(R) 815 (Internal Graphics only) Framebuffer Device"        ,
+	"Intel(R) 815 (Internal Graphics with AGP) Framebuffer Device"
+};
+
+static struct pci_device_id i810fb_pci_tbl[] = {
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG1,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG3,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1  },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810E_IG,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
+	/* mvo: added i815 PCI-ID */
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_100,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_NOAGP,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_CGC,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 },
+	{ 0 },
+};
+
+static struct pci_driver i810fb_driver = {
+	.name     =	"i810fb",
+	.id_table =	i810fb_pci_tbl,
+	.probe    =	i810fb_init_pci,
+	.remove   =	__exit_p(i810fb_remove_pci),
+	.suspend  =     i810fb_suspend,
+	.resume   =     i810fb_resume,
+};
+
+static int vram       __initdata = 4;
+static int bpp        __initdata = 8;
+static int mtrr       __initdata = 0;
+static int accel      __initdata = 0;
+static int hsync1     __initdata = 0;
+static int hsync2     __initdata = 0;
+static int vsync1     __initdata = 0;
+static int vsync2     __initdata = 0;
+static int xres       __initdata = 640;
+static int yres       __initdata = 480;
+static int vyres      __initdata = 0;
+static int sync       __initdata = 0;
+static int ext_vga    __initdata = 0;
+static int dcolor     __initdata = 0;
+
+/*------------------------------------------------------------*/
+
+/**************************************************************
+ *                Hardware Low Level Routines                 *
+ **************************************************************/
+
+/**
+ * i810_screen_off - turns off/on display
+ * @mmio: address of register space
+ * @mode: on or off
+ *
+ * DESCRIPTION:
+ * Blanks/unblanks the display
+ */
+static void i810_screen_off(u8 __iomem *mmio, u8 mode)
+{
+	u32 count = WAIT_COUNT;
+	u8 val;
+
+	i810_writeb(SR_INDEX, mmio, SR01);
+	val = i810_readb(SR_DATA, mmio);
+	val = (mode == OFF) ? val | SCR_OFF :
+		val & ~SCR_OFF;
+
+	while((i810_readw(DISP_SL, mmio) & 0xFFF) && count--);
+	i810_writeb(SR_INDEX, mmio, SR01);
+	i810_writeb(SR_DATA, mmio, val);
+}
+
+/**
+ * i810_dram_off - turns off/on dram refresh
+ * @mmio: address of register space
+ * @mode: on or off
+ *
+ * DESCRIPTION:
+ * Turns off DRAM refresh.  Must be off for only 2 vsyncs
+ * before data becomes corrupt
+ */
+static void i810_dram_off(u8 __iomem *mmio, u8 mode)
+{
+	u8 val;
+
+	val = i810_readb(DRAMCH, mmio);
+	val &= DRAM_OFF;
+	val = (mode == OFF) ? val : val | DRAM_ON;
+	i810_writeb(DRAMCH, mmio, val);
+}
+
+/**
+ * i810_protect_regs - allows rw/ro mode of certain VGA registers
+ * @mmio: address of register space
+ * @mode: protect/unprotect
+ *
+ * DESCRIPTION:
+ * The IBM VGA standard allows protection of certain VGA registers.  
+ * This will  protect or unprotect them. 
+ */
+static void i810_protect_regs(u8 __iomem *mmio, int mode)
+{
+	u8 reg;
+
+	i810_writeb(CR_INDEX_CGA, mmio, CR11);
+	reg = i810_readb(CR_DATA_CGA, mmio);
+	reg = (mode == OFF) ? reg & ~0x80 :
+		reg | 0x80;
+ 		
+	i810_writeb(CR_INDEX_CGA, mmio, CR11);
+	i810_writeb(CR_DATA_CGA, mmio, reg);
+}
+
+/**
+ * i810_load_pll - loads values for the hardware PLL clock
+ * @par: pointer to i810fb_par structure
+ *
+ * DESCRIPTION:
+ * Loads the P, M, and N registers.  
+ */
+static void i810_load_pll(struct i810fb_par *par)
+{
+	u32 tmp1, tmp2;
+	u8 __iomem *mmio = par->mmio_start_virtual;
+	
+	tmp1 = par->regs.M | par->regs.N << 16;
+	tmp2 = i810_readl(DCLK_2D, mmio);
+	tmp2 &= ~MN_MASK;
+	i810_writel(DCLK_2D, mmio, tmp1 | tmp2);
+	
+	tmp1 = par->regs.P;
+	tmp2 = i810_readl(DCLK_0DS, mmio);
+	tmp2 &= ~(P_OR << 16);
+	i810_writel(DCLK_0DS, mmio, (tmp1 << 16) | tmp2);
+
+	i810_writeb(MSR_WRITE, mmio, par->regs.msr | 0xC8 | 1);
+
+}
+
+/**
+ * i810_load_vga - load standard VGA registers
+ * @par: pointer to i810fb_par structure
+ *
+ * DESCRIPTION:
+ * Load values to VGA registers
+ */
+static void i810_load_vga(struct i810fb_par *par)
+{	
+	u8 __iomem *mmio = par->mmio_start_virtual;
+
+	/* interlace */
+	i810_writeb(CR_INDEX_CGA, mmio, CR70);
+	i810_writeb(CR_DATA_CGA, mmio, par->interlace);
+
+	i810_writeb(CR_INDEX_CGA, mmio, CR00);
+	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr00);
+	i810_writeb(CR_INDEX_CGA, mmio, CR01);
+	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr01);
+	i810_writeb(CR_INDEX_CGA, mmio, CR02);
+	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr02);
+	i810_writeb(CR_INDEX_CGA, mmio, CR03);
+	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr03);
+	i810_writeb(CR_INDEX_CGA, mmio, CR04);
+	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr04);
+	i810_writeb(CR_INDEX_CGA, mmio, CR05);
+	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr05);
+	i810_writeb(CR_INDEX_CGA, mmio, CR06);
+	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr06);
+	i810_writeb(CR_INDEX_CGA, mmio, CR09);
+	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr09);
+	i810_writeb(CR_INDEX_CGA, mmio, CR10);
+	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr10);
+	i810_writeb(CR_INDEX_CGA, mmio, CR11);
+	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr11);
+	i810_writeb(CR_INDEX_CGA, mmio, CR12);
+	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr12);
+	i810_writeb(CR_INDEX_CGA, mmio, CR15);
+	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr15);
+	i810_writeb(CR_INDEX_CGA, mmio, CR16);
+	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr16);
+}
+
+/**
+ * i810_load_vgax - load extended VGA registers
+ * @par: pointer to i810fb_par structure
+ *
+ * DESCRIPTION:
+ * Load values to extended VGA registers
+ */
+static void i810_load_vgax(struct i810fb_par *par)
+{
+	u8 __iomem *mmio = par->mmio_start_virtual;
+
+	i810_writeb(CR_INDEX_CGA, mmio, CR30);
+	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr30);
+	i810_writeb(CR_INDEX_CGA, mmio, CR31);
+	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr31);
+	i810_writeb(CR_INDEX_CGA, mmio, CR32);
+	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr32);
+	i810_writeb(CR_INDEX_CGA, mmio, CR33);
+	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr33);
+	i810_writeb(CR_INDEX_CGA, mmio, CR35);
+	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr35);
+	i810_writeb(CR_INDEX_CGA, mmio, CR39);
+	i810_writeb(CR_DATA_CGA, mmio, par->regs.cr39);
+}
+
+/**
+ * i810_load_2d - load grahics registers
+ * @par: pointer to i810fb_par structure
+ *
+ * DESCRIPTION:
+ * Load values to graphics registers
+ */
+static void i810_load_2d(struct i810fb_par *par)
+{
+	u32 tmp;
+	u8 tmp8;
+	u8 __iomem *mmio = par->mmio_start_virtual;
+
+  	i810_writel(FW_BLC, mmio, par->watermark); 
+	tmp = i810_readl(PIXCONF, mmio);
+	tmp |= 1 | 1 << 20;
+	i810_writel(PIXCONF, mmio, tmp);
+
+	i810_writel(OVRACT, mmio, par->ovract);
+
+	i810_writeb(GR_INDEX, mmio, GR10);
+	tmp8 = i810_readb(GR_DATA, mmio);
+	tmp8 |= 2;
+	i810_writeb(GR_INDEX, mmio, GR10);
+	i810_writeb(GR_DATA, mmio, tmp8);
+}	
+
+/**
+ * i810_hires - enables high resolution mode
+ * @mmio: address of register space
+ */
+static void i810_hires(u8 __iomem *mmio)
+{
+	u8 val;
+	
+	i810_writeb(CR_INDEX_CGA, mmio, CR80);
+	val = i810_readb(CR_DATA_CGA, mmio);
+	i810_writeb(CR_INDEX_CGA, mmio, CR80);
+	i810_writeb(CR_DATA_CGA, mmio, val | 1);
+}
+
+/**
+ * i810_load_pitch - loads the characters per line of the display
+ * @par: pointer to i810fb_par structure
+ *
+ * DESCRIPTION:
+ * Loads the characters per line
+ */	
+static void i810_load_pitch(struct i810fb_par *par)
+{
+	u32 tmp, pitch;
+	u8 val;
+	u8 __iomem *mmio = par->mmio_start_virtual;
+			
+	pitch = par->pitch >> 3;
+	i810_writeb(SR_INDEX, mmio, SR01);
+	val = i810_readb(SR_DATA, mmio);
+	val &= 0xE0;
+	val |= 1 | 1 << 2;
+	i810_writeb(SR_INDEX, mmio, SR01);
+	i810_writeb(SR_DATA, mmio, val);
+
+	tmp = pitch & 0xFF;
+	i810_writeb(CR_INDEX_CGA, mmio, CR13);
+	i810_writeb(CR_DATA_CGA, mmio, (u8) tmp);
+	
+	tmp = pitch >> 8;
+	i810_writeb(CR_INDEX_CGA, mmio, CR41);
+	val = i810_readb(CR_DATA_CGA, mmio) & ~0x0F;
+	i810_writeb(CR_INDEX_CGA, mmio, CR41);
+	i810_writeb(CR_DATA_CGA, mmio, (u8) tmp | val);
+}
+
+/**
+ * i810_load_color - loads the color depth of the display
+ * @par: pointer to i810fb_par structure
+ *
+ * DESCRIPTION:
+ * Loads the color depth of the display and the graphics engine
+ */
+static void i810_load_color(struct i810fb_par *par)
+{
+	u8 __iomem *mmio = par->mmio_start_virtual;
+	u32 reg1;
+	u16 reg2;
+
+	reg1 = i810_readl(PIXCONF, mmio) & ~(0xF0000 | 1 << 27);
+	reg2 = i810_readw(BLTCNTL, mmio) & ~0x30;
+
+	reg1 |= 0x8000 | par->pixconf;
+	reg2 |= par->bltcntl;
+	i810_writel(PIXCONF, mmio, reg1);
+	i810_writew(BLTCNTL, mmio, reg2);
+}
+
+/**
+ * i810_load_regs - loads all registers for the mode
+ * @par: pointer to i810fb_par structure
+ * 
+ * DESCRIPTION:
+ * Loads registers
+ */
+static void i810_load_regs(struct i810fb_par *par)
+{
+	u8 __iomem *mmio = par->mmio_start_virtual;
+
+	i810_screen_off(mmio, OFF);
+	i810_protect_regs(mmio, OFF);
+	i810_dram_off(mmio, OFF);
+	i810_load_pll(par);
+	i810_load_vga(par);
+	i810_load_vgax(par);
+	i810_dram_off(mmio, ON);	
+	i810_load_2d(par);
+	i810_hires(mmio);
+	i810_screen_off(mmio, ON);
+	i810_protect_regs(mmio, ON);
+	i810_load_color(par);
+	i810_load_pitch(par);
+}
+
+static void i810_write_dac(u8 regno, u8 red, u8 green, u8 blue,
+			  u8 __iomem *mmio)
+{
+	i810_writeb(CLUT_INDEX_WRITE, mmio, regno);
+	i810_writeb(CLUT_DATA, mmio, red);
+	i810_writeb(CLUT_DATA, mmio, green);
+	i810_writeb(CLUT_DATA, mmio, blue); 	
+}
+
+static void i810_read_dac(u8 regno, u8 *red, u8 *green, u8 *blue,
+			  u8 __iomem *mmio)
+{
+	i810_writeb(CLUT_INDEX_READ, mmio, regno);
+	*red = i810_readb(CLUT_DATA, mmio);
+	*green = i810_readb(CLUT_DATA, mmio);
+	*blue = i810_readb(CLUT_DATA, mmio);
+}
+
+/************************************************************
+ *                   VGA State Restore                      * 
+ ************************************************************/
+static void i810_restore_pll(struct i810fb_par *par)
+{
+	u32 tmp1, tmp2;
+	u8 __iomem *mmio = par->mmio_start_virtual;
+	
+	tmp1 = par->hw_state.dclk_2d;
+	tmp2 = i810_readl(DCLK_2D, mmio);
+	tmp1 &= ~MN_MASK;
+	tmp2 &= MN_MASK;
+	i810_writel(DCLK_2D, mmio, tmp1 | tmp2);
+
+	tmp1 = par->hw_state.dclk_1d;
+	tmp2 = i810_readl(DCLK_1D, mmio);
+	tmp1 &= ~MN_MASK;
+	tmp2 &= MN_MASK;
+	i810_writel(DCLK_1D, mmio, tmp1 | tmp2);
+
+	i810_writel(DCLK_0DS, mmio, par->hw_state.dclk_0ds);
+}
+
+static void i810_restore_dac(struct i810fb_par *par)
+{
+	u32 tmp1, tmp2;
+	u8 __iomem *mmio = par->mmio_start_virtual;
+
+	tmp1 = par->hw_state.pixconf;
+	tmp2 = i810_readl(PIXCONF, mmio);
+	tmp1 &= DAC_BIT;
+	tmp2 &= ~DAC_BIT;
+	i810_writel(PIXCONF, mmio, tmp1 | tmp2);
+}
+
+static void i810_restore_vgax(struct i810fb_par *par)
+{
+	u8 i, j;
+	u8 __iomem *mmio = par->mmio_start_virtual;
+	
+	for (i = 0; i < 4; i++) {
+		i810_writeb(CR_INDEX_CGA, mmio, CR30+i);
+		i810_writeb(CR_DATA_CGA, mmio, *(&(par->hw_state.cr30) + i));
+	}
+	i810_writeb(CR_INDEX_CGA, mmio, CR35);
+	i810_writeb(CR_DATA_CGA, mmio, par->hw_state.cr35);
+	i810_writeb(CR_INDEX_CGA, mmio, CR39);
+	i810_writeb(CR_DATA_CGA, mmio, par->hw_state.cr39);
+	i810_writeb(CR_INDEX_CGA, mmio, CR41);
+	i810_writeb(CR_DATA_CGA, mmio, par->hw_state.cr39);
+
+	/*restore interlace*/
+	i810_writeb(CR_INDEX_CGA, mmio, CR70);
+	i = par->hw_state.cr70;
+	i &= INTERLACE_BIT;
+	j = i810_readb(CR_DATA_CGA, mmio);
+	i810_writeb(CR_INDEX_CGA, mmio, CR70);
+	i810_writeb(CR_DATA_CGA, mmio, j | i);
+
+	i810_writeb(CR_INDEX_CGA, mmio, CR80);
+	i810_writeb(CR_DATA_CGA, mmio, par->hw_state.cr80);
+	i810_writeb(MSR_WRITE, mmio, par->hw_state.msr);
+	i810_writeb(SR_INDEX, mmio, SR01);
+	i = (par->hw_state.sr01) & ~0xE0 ;
+	j = i810_readb(SR_DATA, mmio) & 0xE0;
+	i810_writeb(SR_INDEX, mmio, SR01);
+	i810_writeb(SR_DATA, mmio, i | j);
+}
+
+static void i810_restore_vga(struct i810fb_par *par)
+{
+	u8 i;
+	u8 __iomem *mmio = par->mmio_start_virtual;
+	
+	for (i = 0; i < 10; i++) {
+		i810_writeb(CR_INDEX_CGA, mmio, CR00 + i);
+		i810_writeb(CR_DATA_CGA, mmio, *((&par->hw_state.cr00) + i));
+	}
+	for (i = 0; i < 8; i++) {
+		i810_writeb(CR_INDEX_CGA, mmio, CR10 + i);
+		i810_writeb(CR_DATA_CGA, mmio, *((&par->hw_state.cr10) + i));
+	}
+}
+
+static void i810_restore_addr_map(struct i810fb_par *par)
+{
+	u8 tmp;
+	u8 __iomem *mmio = par->mmio_start_virtual;
+
+	i810_writeb(GR_INDEX, mmio, GR10);
+	tmp = i810_readb(GR_DATA, mmio);
+	tmp &= ADDR_MAP_MASK;
+	tmp |= par->hw_state.gr10;
+	i810_writeb(GR_INDEX, mmio, GR10);
+	i810_writeb(GR_DATA, mmio, tmp);
+}
+
+static void i810_restore_2d(struct i810fb_par *par)
+{
+	u32 tmp_long;
+	u16 tmp_word;
+	u8 __iomem *mmio = par->mmio_start_virtual;
+
+	tmp_word = i810_readw(BLTCNTL, mmio);
+	tmp_word &= ~(3 << 4); 
+	tmp_word |= par->hw_state.bltcntl;
+	i810_writew(BLTCNTL, mmio, tmp_word);
+       
+	i810_dram_off(mmio, OFF);
+	i810_writel(PIXCONF, mmio, par->hw_state.pixconf);
+	i810_dram_off(mmio, ON);
+
+	tmp_word = i810_readw(HWSTAM, mmio);
+	tmp_word &= 3 << 13;
+	tmp_word |= par->hw_state.hwstam;
+	i810_writew(HWSTAM, mmio, tmp_word);
+
+	tmp_long = i810_readl(FW_BLC, mmio);
+	tmp_long &= FW_BLC_MASK;
+	tmp_long |= par->hw_state.fw_blc;
+	i810_writel(FW_BLC, mmio, tmp_long);
+
+	i810_writel(HWS_PGA, mmio, par->hw_state.hws_pga); 
+	i810_writew(IER, mmio, par->hw_state.ier);
+	i810_writew(IMR, mmio, par->hw_state.imr);
+	i810_writel(DPLYSTAS, mmio, par->hw_state.dplystas);
+}
+
+static void i810_restore_vga_state(struct i810fb_par *par)
+{
+	u8 __iomem *mmio = par->mmio_start_virtual;
+
+	i810_screen_off(mmio, OFF);
+	i810_protect_regs(mmio, OFF);
+	i810_dram_off(mmio, OFF);
+	i810_restore_pll(par);
+	i810_restore_dac(par);
+	i810_restore_vga(par);
+	i810_restore_vgax(par);
+	i810_restore_addr_map(par);
+	i810_dram_off(mmio, ON);
+	i810_restore_2d(par);
+	i810_screen_off(mmio, ON);
+	i810_protect_regs(mmio, ON);
+}
+
+/***********************************************************************
+ *                         VGA State Save                              *
+ ***********************************************************************/
+
+static void i810_save_vgax(struct i810fb_par *par)
+{
+	u8 i;
+	u8 __iomem *mmio = par->mmio_start_virtual;
+
+	for (i = 0; i < 4; i++) {
+		i810_writeb(CR_INDEX_CGA, mmio, CR30 + i);
+		*(&(par->hw_state.cr30) + i) = i810_readb(CR_DATA_CGA, mmio);
+	}
+	i810_writeb(CR_INDEX_CGA, mmio, CR35);
+	par->hw_state.cr35 = i810_readb(CR_DATA_CGA, mmio);
+	i810_writeb(CR_INDEX_CGA, mmio, CR39);
+	par->hw_state.cr39 = i810_readb(CR_DATA_CGA, mmio);
+	i810_writeb(CR_INDEX_CGA, mmio, CR41);
+	par->hw_state.cr41 = i810_readb(CR_DATA_CGA, mmio);
+	i810_writeb(CR_INDEX_CGA, mmio, CR70);
+	par->hw_state.cr70 = i810_readb(CR_DATA_CGA, mmio);	
+	par->hw_state.msr = i810_readb(MSR_READ, mmio);
+	i810_writeb(CR_INDEX_CGA, mmio, CR80);
+	par->hw_state.cr80 = i810_readb(CR_DATA_CGA, mmio);
+	i810_writeb(SR_INDEX, mmio, SR01);
+	par->hw_state.sr01 = i810_readb(SR_DATA, mmio);
+}
+
+static void i810_save_vga(struct i810fb_par *par)
+{
+	u8 i;
+	u8 __iomem *mmio = par->mmio_start_virtual;
+
+	for (i = 0; i < 10; i++) {
+		i810_writeb(CR_INDEX_CGA, mmio, CR00 + i);
+		*((&par->hw_state.cr00) + i) = i810_readb(CR_DATA_CGA, mmio);
+	}
+	for (i = 0; i < 8; i++) {
+		i810_writeb(CR_INDEX_CGA, mmio, CR10 + i);
+		*((&par->hw_state.cr10) + i) = i810_readb(CR_DATA_CGA, mmio);
+	}
+}
+
+static void i810_save_2d(struct i810fb_par *par)
+{
+	u8 __iomem *mmio = par->mmio_start_virtual;
+
+	par->hw_state.dclk_2d = i810_readl(DCLK_2D, mmio);
+	par->hw_state.dclk_1d = i810_readl(DCLK_1D, mmio);
+	par->hw_state.dclk_0ds = i810_readl(DCLK_0DS, mmio);
+	par->hw_state.pixconf = i810_readl(PIXCONF, mmio);
+	par->hw_state.fw_blc = i810_readl(FW_BLC, mmio);
+	par->hw_state.bltcntl = i810_readw(BLTCNTL, mmio);
+	par->hw_state.hwstam = i810_readw(HWSTAM, mmio); 
+	par->hw_state.hws_pga = i810_readl(HWS_PGA, mmio); 
+	par->hw_state.ier = i810_readw(IER, mmio);
+	par->hw_state.imr = i810_readw(IMR, mmio);
+	par->hw_state.dplystas = i810_readl(DPLYSTAS, mmio);
+}
+
+static void i810_save_vga_state(struct i810fb_par *par)
+{
+	i810_save_vga(par);
+	i810_save_vgax(par);
+	i810_save_2d(par);
+}
+
+/************************************************************
+ *                    Helpers                               * 
+ ************************************************************/
+/**
+ * get_line_length - calculates buffer pitch in bytes
+ * @par: pointer to i810fb_par structure
+ * @xres_virtual: virtual resolution of the frame
+ * @bpp: bits per pixel
+ *
+ * DESCRIPTION:
+ * Calculates buffer pitch in bytes.  
+ */
+static u32 get_line_length(struct i810fb_par *par, int xres_virtual, int bpp)
+{
+   	u32 length;
+	
+	length = xres_virtual*bpp;
+	length = (length+31)&-32;
+	length >>= 3;
+	return length;
+}
+
+/**
+ * i810_calc_dclk - calculates the P, M, and N values of a pixelclock value
+ * @freq: target pixelclock in picoseconds
+ * @m: where to write M register
+ * @n: where to write N register
+ * @p: where to write P register
+ *
+ * DESCRIPTION:
+ * Based on the formula Freq_actual = (4*M*Freq_ref)/(N^P)
+ * Repeatedly computes the Freq until the actual Freq is equal to
+ * the target Freq or until the loop count is zero.  In the latter
+ * case, the actual frequency nearest the target will be used.
+ */
+static void i810_calc_dclk(u32 freq, u32 *m, u32 *n, u32 *p)
+{
+	u32 m_reg, n_reg, p_divisor, n_target_max;
+	u32 m_target, n_target, p_target, n_best, m_best, mod;
+	u32 f_out, target_freq, diff = 0, mod_min, diff_min;
+
+	diff_min = mod_min = 0xFFFFFFFF;
+	n_best = m_best = m_target = f_out = 0;
+
+	target_freq =  freq;
+	n_target_max = 30;
+
+	/*
+	 * find P such that target freq is 16x reference freq (Hz). 
+	 */
+	p_divisor = 1;
+	p_target = 0;
+	while(!((1000000 * p_divisor)/(16 * 24 * target_freq)) && 
+	      p_divisor <= 32) {
+		p_divisor <<= 1;
+		p_target++;
+	}
+
+	n_reg = m_reg = n_target = 3;	
+	while (diff_min && mod_min && (n_target < n_target_max)) {
+		f_out = (p_divisor * n_reg * 1000000)/(4 * 24 * m_reg);
+		mod = (p_divisor * n_reg * 1000000) % (4 * 24 * m_reg);
+		m_target = m_reg;
+		n_target = n_reg;
+		if (f_out <= target_freq) {
+			n_reg++;
+			diff = target_freq - f_out;
+		} else {
+			m_reg++;
+			diff = f_out - target_freq;
+		}
+
+		if (diff_min > diff) {
+			diff_min = diff;
+			n_best = n_target;
+			m_best = m_target;
+		}		 
+
+		if (!diff && mod_min > mod) {
+			mod_min = mod;
+			n_best = n_target;
+			m_best = m_target;
+		}
+	} 
+	if (m) *m = (m_best - 2) & 0x3FF;
+	if (n) *n = (n_best - 2) & 0x3FF;
+	if (p) *p = (p_target << 4);
+}
+
+/*************************************************************
+ *                Hardware Cursor Routines                   *
+ *************************************************************/
+
+/**
+ * i810_enable_cursor - show or hide the hardware cursor
+ * @mmio: address of register space
+ * @mode: show (1) or hide (0)
+ *
+ * Description:
+ * Shows or hides the hardware cursor
+ */
+static void i810_enable_cursor(u8 __iomem *mmio, int mode)
+{
+	u32 temp;
+	
+	temp = i810_readl(PIXCONF, mmio);
+	temp = (mode == ON) ? temp | CURSOR_ENABLE_MASK :
+		temp & ~CURSOR_ENABLE_MASK;
+
+	i810_writel(PIXCONF, mmio, temp);
+}
+
+static void i810_reset_cursor_image(struct i810fb_par *par)
+{
+	u8 __iomem *addr = par->cursor_heap.virtual;
+	int i, j;
+
+	for (i = 64; i--; ) {
+		for (j = 0; j < 8; j++) {             
+			i810_writeb(j, addr, 0xff);   
+			i810_writeb(j+8, addr, 0x00); 
+		}	
+		addr +=16;
+	}
+}
+
+static void i810_load_cursor_image(int width, int height, u8 *data,
+				   struct i810fb_par *par)
+{
+	u8 __iomem *addr = par->cursor_heap.virtual;
+	int i, j, w = width/8;
+	int mod = width % 8, t_mask, d_mask;
+	
+	t_mask = 0xff >> mod;
+	d_mask = ~(0xff >> mod); 
+	for (i = height; i--; ) {
+		for (j = 0; j < w; j++) {
+			i810_writeb(j+0, addr, 0x00);
+			i810_writeb(j+8, addr, *data++);
+		}
+		if (mod) {
+			i810_writeb(j+0, addr, t_mask);
+			i810_writeb(j+8, addr, *data++ & d_mask);
+		}
+		addr += 16;
+	}
+}
+
+static void i810_load_cursor_colors(int fg, int bg, struct fb_info *info)
+{
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+	u8 __iomem *mmio = par->mmio_start_virtual;
+	u8 red, green, blue, trans, temp;
+
+	i810fb_getcolreg(bg, &red, &green, &blue, &trans, info);
+
+	temp = i810_readb(PIXCONF1, mmio);
+	i810_writeb(PIXCONF1, mmio, temp | EXTENDED_PALETTE);
+
+	i810_write_dac(4, red, green, blue, mmio);
+
+	i810_writeb(PIXCONF1, mmio, temp);
+
+	i810fb_getcolreg(fg, &red, &green, &blue, &trans, info);
+	temp = i810_readb(PIXCONF1, mmio);
+	i810_writeb(PIXCONF1, mmio, temp | EXTENDED_PALETTE);
+
+	i810_write_dac(5, red, green, blue, mmio);
+
+	i810_writeb(PIXCONF1, mmio, temp);
+}
+
+/**
+ * i810_init_cursor - initializes the cursor
+ * @par: pointer to i810fb_par structure
+ *
+ * DESCRIPTION:
+ * Initializes the cursor registers
+ */
+static void i810_init_cursor(struct i810fb_par *par)
+{
+	u8 __iomem *mmio = par->mmio_start_virtual;
+
+	i810_enable_cursor(mmio, OFF);
+	i810_writel(CURBASE, mmio, par->cursor_heap.physical);
+	i810_writew(CURCNTR, mmio, COORD_ACTIVE | CURSOR_MODE_64_XOR);
+}	
+
+/*********************************************************************
+ *                    Framebuffer hook helpers                       *
+ *********************************************************************/
+/**
+ * i810_round_off -  Round off values to capability of hardware
+ * @var: pointer to fb_var_screeninfo structure
+ *
+ * DESCRIPTION:
+ * @var contains user-defined information for the mode to be set.
+ * This will try modify those values to ones nearest the
+ * capability of the hardware
+ */
+static void i810_round_off(struct fb_var_screeninfo *var)
+{
+	u32 xres, yres, vxres, vyres;
+
+	/*
+	 *  Presently supports only these configurations 
+	 */
+
+	xres = var->xres;
+	yres = var->yres;
+	vxres = var->xres_virtual;
+	vyres = var->yres_virtual;
+
+	var->bits_per_pixel += 7;
+	var->bits_per_pixel &= ~7;
+	
+	if (var->bits_per_pixel < 8)
+		var->bits_per_pixel = 8;
+	if (var->bits_per_pixel > 32) 
+		var->bits_per_pixel = 32;
+
+	round_off_xres(&xres);
+	if (xres < 40)
+		xres = 40;
+	if (xres > 2048) 
+		xres = 2048;
+	xres = (xres + 7) & ~7;
+
+	if (vxres < xres) 
+		vxres = xres;
+
+	round_off_yres(&xres, &yres);
+	if (yres < 1)
+		yres = 1;
+	if (yres >= 2048)
+		yres = 2048;
+
+	if (vyres < yres) 
+		vyres = yres;
+
+	if (var->bits_per_pixel == 32)
+		var->accel_flags = 0;
+
+	/* round of horizontal timings to nearest 8 pixels */
+	var->left_margin = (var->left_margin + 4) & ~7;
+	var->right_margin = (var->right_margin + 4) & ~7;
+	var->hsync_len = (var->hsync_len + 4) & ~7;
+
+	if (var->vmode & FB_VMODE_INTERLACED) {
+		if (!((yres + var->upper_margin + var->vsync_len + 
+		       var->lower_margin) & 1))
+			var->upper_margin++;
+	}
+	
+	var->xres = xres;
+	var->yres = yres;
+	var->xres_virtual = vxres;
+	var->yres_virtual = vyres;
+}	
+
+/**
+ * set_color_bitfields - sets rgba fields
+ * @var: pointer to fb_var_screeninfo
+ *
+ * DESCRIPTION:
+ * The length, offset and ordering  for each color field 
+ * (red, green, blue)  will be set as specified 
+ * by the hardware
+ */  
+static void set_color_bitfields(struct fb_var_screeninfo *var)
+{
+	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:
+		var->green.length = (var->green.length == 5) ? 5 : 6;
+		var->red.length = 5;
+		var->blue.length = 5;
+		var->transp.length = 6 - var->green.length;
+		var->blue.offset = 0;
+		var->green.offset = 5;
+		var->red.offset = 5 + var->green.length;
+		var->transp.offset =  (5 + var->red.offset) & 15;
+		break;
+	case 24:	/* RGB 888   */
+	case 32:	/* RGBA 8888 */
+		var->red.offset = 16;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		var->transp.length = var->bits_per_pixel - 24;
+		var->transp.offset = (var->transp.length) ? 24 : 0;
+		break;
+	}
+	var->red.msb_right = 0;
+	var->green.msb_right = 0;
+	var->blue.msb_right = 0;
+	var->transp.msb_right = 0;
+}
+
+/**
+ * i810_check_params - check if contents in var are valid
+ * @var: pointer to fb_var_screeninfo
+ * @info: pointer to fb_info
+ *
+ * DESCRIPTION:
+ * This will check if the framebuffer size is sufficient 
+ * for the current mode and if the user's monitor has the 
+ * required specifications to display the current mode.
+ */
+static int i810_check_params(struct fb_var_screeninfo *var, 
+			     struct fb_info *info)
+{
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+	int line_length, vidmem;
+	u32 xres, yres, vxres, vyres;
+
+	xres = var->xres;
+	yres = var->yres;
+	vxres = var->xres_virtual;
+	vyres = var->yres_virtual;
+
+	/*
+	 *  Memory limit
+	 */
+	line_length = get_line_length(par, vxres, 
+				      var->bits_per_pixel);
+
+	vidmem = line_length*vyres;
+	if (vidmem > par->fb.size) {
+		vyres = par->fb.size/line_length;
+		if (vyres < yres) {
+			vyres = yres;
+			vxres = par->fb.size/vyres;
+			vxres /= var->bits_per_pixel >> 3;
+			line_length = get_line_length(par, vxres, 
+						      var->bits_per_pixel);
+			vidmem = line_length * yres;
+			if (vxres < xres) {
+				printk("i810fb: required video memory, "
+				       "%d bytes, for %dx%d-%d (virtual) "
+				       "is out of range\n", 
+				       vidmem, vxres, vyres, 
+				       var->bits_per_pixel);
+				return -ENOMEM;
+			}
+		}
+	}
+	/*
+	 * Monitor limit
+	 */
+	switch (var->bits_per_pixel) {
+	case 8:
+		info->monspecs.dclkmax = 234000000;
+		break;
+	case 16:
+		info->monspecs.dclkmax = 229000000;
+		break;
+	case 24:
+	case 32:
+		info->monspecs.dclkmax = 204000000;
+		break;
+	}
+	info->monspecs.dclkmin = 15000000;
+
+	if (fb_validate_mode(var, info)) {
+		if (fb_get_mode(FB_MAXTIMINGS, 0, var, info))
+			return -EINVAL;
+	}
+	
+	var->xres = xres;
+	var->yres = yres;
+	var->xres_virtual = vxres;
+	var->yres_virtual = vyres;
+	return 0;
+}	
+
+/**
+ * encode_fix - fill up fb_fix_screeninfo structure
+ * @fix: pointer to fb_fix_screeninfo
+ * @info: pointer to fb_info
+ *
+ * DESCRIPTION:
+ * This will set up parameters that are unmodifiable by the user.
+ */
+static int encode_fix(struct fb_fix_screeninfo *fix, struct fb_info *info)
+{
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+
+    	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+
+    	strcpy(fix->id, "I810");
+    	fix->smem_start = par->fb.physical;
+    	fix->smem_len = par->fb.size;
+    	fix->type = FB_TYPE_PACKED_PIXELS;
+    	fix->type_aux = 0;
+	fix->xpanstep = 8;
+	fix->ypanstep = 1;
+
+    	switch (info->var.bits_per_pixel) {
+	case 8:
+	    	fix->visual = FB_VISUAL_PSEUDOCOLOR;
+	    	break;
+	case 16:
+	case 24:
+	case 32:
+		if (info->var.nonstd)
+			fix->visual = FB_VISUAL_DIRECTCOLOR;
+		else
+			fix->visual = FB_VISUAL_TRUECOLOR;
+	    	break;
+	default:
+		return -EINVAL;
+	}
+    	fix->ywrapstep = 0;
+	fix->line_length = par->pitch;
+	fix->mmio_start = par->mmio_start_phys;
+	fix->mmio_len = MMIO_SIZE;
+	fix->accel = FB_ACCEL_I810;
+
+	return 0;
+}
+
+/**
+ * decode_var - modify par according to contents of var
+ * @var: pointer to fb_var_screeninfo
+ * @par: pointer to i810fb_par
+ *
+ * DESCRIPTION:
+ * Based on the contents of @var, @par will be dynamically filled up.
+ * @par contains all information necessary to modify the hardware. 
+*/
+static void decode_var(const struct fb_var_screeninfo *var, 
+		       struct i810fb_par *par)
+{
+	u32 xres, yres, vxres, vyres;
+
+	xres = var->xres;
+	yres = var->yres;
+	vxres = var->xres_virtual;
+	vyres = var->yres_virtual;
+
+	switch (var->bits_per_pixel) {
+	case 8:
+		par->pixconf = PIXCONF8;
+		par->bltcntl = 0;
+		par->depth = 1;
+		par->blit_bpp = BPP8;
+		break;
+	case 16:
+		if (var->green.length == 5)
+			par->pixconf = PIXCONF15;
+		else
+			par->pixconf = PIXCONF16;
+		par->bltcntl = 16;
+		par->depth = 2;
+		par->blit_bpp = BPP16;
+		break;
+	case 24:
+		par->pixconf = PIXCONF24;
+		par->bltcntl = 32;
+		par->depth = 3;
+		par->blit_bpp = BPP24;
+		break;
+	case 32:
+		par->pixconf = PIXCONF32;
+		par->bltcntl = 0;
+		par->depth = 4;
+		par->blit_bpp = 3 << 24;
+		break;
+	}
+	if (var->nonstd && var->bits_per_pixel != 8)
+		par->pixconf |= 1 << 27;
+
+	i810_calc_dclk(var->pixclock, &par->regs.M, 
+		       &par->regs.N, &par->regs.P);
+	i810fb_encode_registers(var, par, xres, yres);
+
+	par->watermark = i810_get_watermark(var, par);
+	par->pitch = get_line_length(par, vxres, var->bits_per_pixel);
+}	
+
+/**
+ * i810fb_getcolreg - gets red, green and blue values of the hardware DAC
+ * @regno: DAC index
+ * @red: red
+ * @green: green
+ * @blue: blue
+ * @transp: transparency (alpha)
+ * @info: pointer to fb_info
+ *
+ * DESCRIPTION:
+ * Gets the red, green and blue values of the hardware DAC as pointed by @regno
+ * and writes them to @red, @green and @blue respectively
+ */
+static int i810fb_getcolreg(u8 regno, u8 *red, u8 *green, u8 *blue, 
+			    u8 *transp, struct fb_info *info)
+{
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+	u8 __iomem *mmio = par->mmio_start_virtual;
+	u8 temp;
+
+	if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+		if ((info->var.green.length == 5 && regno > 31) ||
+		    (info->var.green.length == 6 && regno > 63))
+			return 1;
+	}
+
+	temp = i810_readb(PIXCONF1, mmio);
+	i810_writeb(PIXCONF1, mmio, temp & ~EXTENDED_PALETTE);
+
+	if (info->fix.visual == FB_VISUAL_DIRECTCOLOR && 
+	    info->var.green.length == 5) 
+		i810_read_dac(regno * 8, red, green, blue, mmio);
+
+	else if (info->fix.visual == FB_VISUAL_DIRECTCOLOR && 
+		 info->var.green.length == 6) {
+		u8 tmp;
+
+		i810_read_dac(regno * 8, red, &tmp, blue, mmio);
+		i810_read_dac(regno * 4, &tmp, green, &tmp, mmio);
+	}
+	else 
+		i810_read_dac(regno, red, green, blue, mmio);
+
+    	*transp = 0;
+	i810_writeb(PIXCONF1, mmio, temp);
+
+    	return 0;
+}
+
+/****************************************************************** 
+ *           Framebuffer device-specific hooks                    *
+ ******************************************************************/
+
+static int i810fb_open(struct fb_info *info, int user)
+{
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+	u32 count = atomic_read(&par->use_count);
+	
+	if (count == 0) {
+		memset(&par->state, 0, sizeof(struct vgastate));
+		par->state.flags = VGA_SAVE_CMAP;
+		par->state.vgabase = par->mmio_start_virtual;
+		save_vga(&par->state);
+
+		i810_save_vga_state(par);
+	}
+
+	atomic_inc(&par->use_count);
+	
+	return 0;
+}
+
+static int i810fb_release(struct fb_info *info, int user)
+{
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+	u32 count;
+	
+	count = atomic_read(&par->use_count);
+	if (count == 0)
+		return -EINVAL;
+
+	if (count == 1) {
+		i810_restore_vga_state(par);
+		restore_vga(&par->state);
+	}
+
+	atomic_dec(&par->use_count);
+	
+	return 0;
+}
+
+
+static int i810fb_setcolreg(unsigned regno, unsigned red, unsigned green, 
+			    unsigned blue, unsigned transp, 
+			    struct fb_info *info)
+{
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+	u8 __iomem *mmio = par->mmio_start_virtual;
+	u8 temp;
+	int i;
+
+ 	if (regno > 255) return 1;
+
+	if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+		if ((info->var.green.length == 5 && regno > 31) ||
+		    (info->var.green.length == 6 && regno > 63))
+			return 1;
+	}
+
+	if (info->var.grayscale)
+		red = green = blue = (19595 * red + 38470 * green +
+				      7471 * blue) >> 16;
+
+	temp = i810_readb(PIXCONF1, mmio);
+	i810_writeb(PIXCONF1, mmio, temp & ~EXTENDED_PALETTE);
+
+	if (info->fix.visual == FB_VISUAL_DIRECTCOLOR && 
+	    info->var.green.length == 5) {
+		for (i = 0; i < 8; i++) 
+			i810_write_dac((u8) (regno * 8) + i, (u8) red, 
+				       (u8) green, (u8) blue, mmio);
+	} else if (info->fix.visual == FB_VISUAL_DIRECTCOLOR && 
+		 info->var.green.length == 6) {
+		u8 r, g, b;
+
+		if (regno < 32) {
+			for (i = 0; i < 8; i++) 
+				i810_write_dac((u8) (regno * 8) + i,
+					       (u8) red, (u8) green, 
+					       (u8) blue, mmio);
+		}
+		i810_read_dac((u8) (regno*4), &r, &g, &b, mmio);
+		for (i = 0; i < 4; i++) 
+			i810_write_dac((u8) (regno*4) + i, r, (u8) green, 
+				       b, mmio);
+	} else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) {
+		i810_write_dac((u8) regno, (u8) red, (u8) green,
+			       (u8) blue, mmio);
+	}
+
+	i810_writeb(PIXCONF1, mmio, temp);
+
+	if (regno < 16) {
+		switch (info->var.bits_per_pixel) {
+		case 16:	
+			if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+				if (info->var.green.length == 5) 
+					((u32 *)info->pseudo_palette)[regno] = 
+						(regno << 10) | (regno << 5) |
+						regno;
+				else
+					((u32 *)info->pseudo_palette)[regno] = 
+						(regno << 11) | (regno << 5) |
+						regno;
+			} else {
+				if (info->var.green.length == 5) {
+					/* RGB 555 */
+					((u32 *)info->pseudo_palette)[regno] = 
+						((red & 0xf800) >> 1) |
+						((green & 0xf800) >> 6) |
+						((blue & 0xf800) >> 11);
+				} else {
+					/* RGB 565 */
+					((u32 *)info->pseudo_palette)[regno] =
+						(red & 0xf800) |
+						((green & 0xf800) >> 5) |
+						((blue & 0xf800) >> 11);
+				}
+			}
+			break;
+		case 24:	/* RGB 888 */
+		case 32:	/* RGBA 8888 */
+			if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) 
+				((u32 *)info->pseudo_palette)[regno] = 
+					(regno << 16) | (regno << 8) |
+					regno;
+			else 
+				((u32 *)info->pseudo_palette)[regno] = 
+					((red & 0xff00) << 8) |
+					(green & 0xff00) |
+					((blue & 0xff00) >> 8);
+			break;
+		}
+	}
+	return 0;
+}
+
+static int i810fb_pan_display(struct fb_var_screeninfo *var, 
+			      struct fb_info *info)
+{
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+	u32 total;
+	
+	total = var->xoffset * par->depth + 
+		var->yoffset * info->fix.line_length;
+	i810fb_load_front(total, info);
+
+	return 0;
+}
+
+static int i810fb_blank (int blank_mode, struct fb_info *info)
+{
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+	u8 __iomem *mmio = par->mmio_start_virtual;
+	int mode = 0, pwr, scr_off = 0;
+	
+	pwr = i810_readl(PWR_CLKC, mmio);
+
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANK:
+		mode = POWERON;
+		pwr |= 1;
+		scr_off = ON;
+		break;
+	case FB_BLANK_NORMAL:
+		mode = POWERON;
+		pwr |= 1;
+		scr_off = OFF;
+		break;
+	case FB_BLANK_VSYNC_SUSPEND:
+		mode = STANDBY;
+		pwr |= 1;
+		scr_off = OFF;
+		break;
+	case FB_BLANK_HSYNC_SUSPEND:
+		mode = SUSPEND;
+		pwr |= 1;
+		scr_off = OFF;
+		break;
+	case FB_BLANK_POWERDOWN:
+		mode = POWERDOWN;
+		pwr &= ~1;
+		scr_off = OFF;
+		break;
+	default:
+		return -EINVAL; 
+	}
+
+	i810_screen_off(mmio, scr_off);
+	i810_writel(HVSYNC, mmio, mode);
+	i810_writel(PWR_CLKC, mmio, pwr);
+
+	return 0;
+}
+
+static int i810fb_set_par(struct fb_info *info)
+{
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+
+	decode_var(&info->var, par);
+	i810_load_regs(par);
+	i810_init_cursor(par);
+
+	encode_fix(&info->fix, info);
+
+	if (info->var.accel_flags && !(par->dev_flags & LOCKUP)) {
+		info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN |
+		FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
+		FBINFO_HWACCEL_IMAGEBLIT;
+		info->pixmap.scan_align = 2;
+	} else {
+		info->pixmap.scan_align = 1;
+		info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+	}
+	return 0;
+}
+
+static int i810fb_check_var(struct fb_var_screeninfo *var, 
+			    struct fb_info *info)
+{
+	int err;
+
+	if (IS_DVT) {
+		var->vmode &= ~FB_VMODE_MASK;
+		var->vmode |= FB_VMODE_NONINTERLACED;
+	}
+	if (var->vmode & FB_VMODE_DOUBLE) {
+		var->vmode &= ~FB_VMODE_MASK;
+		var->vmode |= FB_VMODE_NONINTERLACED;
+	}
+
+	i810_round_off(var);
+	if ((err = i810_check_params(var, info)))
+		return err;
+
+	i810fb_fill_var_timings(var);
+	set_color_bitfields(var);
+	return 0;
+}
+
+static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+	struct i810fb_par *par = (struct i810fb_par *)info->par;
+	u8 __iomem *mmio = par->mmio_start_virtual;
+
+	if (!(par->dev_flags & USE_HWCUR) || !info->var.accel_flags ||
+	    par->dev_flags & LOCKUP)
+		return soft_cursor(info, cursor);
+
+	if (cursor->image.width > 64 || cursor->image.height > 64)
+		return -ENXIO;
+
+	if ((i810_readl(CURBASE, mmio) & 0xf) != par->cursor_heap.physical) {
+		i810_init_cursor(par);
+		cursor->set |= FB_CUR_SETALL;
+	}
+
+	i810_enable_cursor(mmio, OFF);
+
+	if (cursor->set & FB_CUR_SETPOS) {
+		u32 tmp;
+
+		tmp = (cursor->image.dx - info->var.xoffset) & 0xffff;
+		tmp |= (cursor->image.dy - info->var.yoffset) << 16;
+		i810_writel(CURPOS, mmio, tmp);
+	}
+
+	if (cursor->set & FB_CUR_SETSIZE)
+		i810_reset_cursor_image(par);
+
+	if (cursor->set & FB_CUR_SETCMAP)
+		i810_load_cursor_colors(cursor->image.fg_color,
+					cursor->image.bg_color,
+					info);
+
+	if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
+		int size = ((cursor->image.width + 7) >> 3) *
+			cursor->image.height;
+		int i;
+		u8 *data = kmalloc(64 * 8, GFP_KERNEL);
+
+		if (data == NULL)
+			return -ENOMEM;
+
+		switch (cursor->rop) {
+		case ROP_XOR:
+			for (i = 0; i < size; i++)
+				data[i] = cursor->image.data[i] ^ cursor->mask[i];
+			break;
+		case ROP_COPY:
+		default:
+			for (i = 0; i < size; i++)
+				data[i] = cursor->image.data[i] & cursor->mask[i];
+			break;
+		}
+
+		i810_load_cursor_image(cursor->image.width,
+				       cursor->image.height, data,
+				       par);
+		kfree(data);
+	}
+
+	if (cursor->enable)
+		i810_enable_cursor(mmio, ON);
+
+	return 0;
+}
+
+static struct fb_ops i810fb_ops __devinitdata = {
+	.owner =             THIS_MODULE,
+	.fb_open =           i810fb_open,
+	.fb_release =        i810fb_release,
+	.fb_check_var =      i810fb_check_var,
+	.fb_set_par =        i810fb_set_par,
+	.fb_setcolreg =      i810fb_setcolreg,
+	.fb_blank =          i810fb_blank,
+	.fb_pan_display =    i810fb_pan_display, 
+	.fb_fillrect =       i810fb_fillrect,
+	.fb_copyarea =       i810fb_copyarea,
+	.fb_imageblit =      i810fb_imageblit,
+	.fb_cursor =         i810fb_cursor,
+	.fb_sync =           i810fb_sync,
+};
+
+/***********************************************************************
+ *                         Power Management                            *
+ ***********************************************************************/
+static int i810fb_suspend(struct pci_dev *dev, pm_message_t state)
+{
+	struct fb_info *info = pci_get_drvdata(dev);
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+	int blank = 0, prev_state = par->cur_state;
+
+	if (state == prev_state)
+		return 0;
+
+	par->cur_state = state;
+
+	switch (state) {
+	case 1:
+		blank = VESA_VSYNC_SUSPEND;
+		break;
+	case 2:
+		blank = VESA_HSYNC_SUSPEND;
+		break;
+	case 3:
+		blank = VESA_POWERDOWN;
+		break;
+	default:
+		return -EINVAL;
+	}
+	info->fbops->fb_blank(blank, info);
+
+	if (!prev_state) { 
+		agp_unbind_memory(par->i810_gtt.i810_fb_memory);
+		agp_unbind_memory(par->i810_gtt.i810_cursor_memory);
+		pci_disable_device(dev);
+	}
+	pci_save_state(dev);
+	pci_set_power_state(dev, pci_choose_state(dev, state));
+
+	return 0;
+}
+
+static int i810fb_resume(struct pci_dev *dev) 
+{
+	struct fb_info *info = pci_get_drvdata(dev);
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+
+	if (par->cur_state == 0)
+		return 0;
+
+	pci_restore_state(dev);
+	pci_set_power_state(dev, PCI_D0);
+	pci_enable_device(dev);
+	agp_bind_memory(par->i810_gtt.i810_fb_memory,
+			par->fb.offset);
+	agp_bind_memory(par->i810_gtt.i810_cursor_memory,
+			par->cursor_heap.offset);
+
+	info->fbops->fb_blank(VESA_NO_BLANKING, info);
+
+	par->cur_state = 0;
+
+	return 0;
+}
+/***********************************************************************
+ *                  AGP resource allocation                            *
+ ***********************************************************************/
+  
+static void __devinit i810_fix_pointers(struct i810fb_par *par)
+{
+      	par->fb.physical = par->aperture.physical+(par->fb.offset << 12);
+	par->fb.virtual = par->aperture.virtual+(par->fb.offset << 12);
+	par->iring.physical = par->aperture.physical + 
+		(par->iring.offset << 12);
+	par->iring.virtual = par->aperture.virtual + 
+		(par->iring.offset << 12);
+	par->cursor_heap.virtual = par->aperture.virtual+
+		(par->cursor_heap.offset << 12);
+}
+
+static void __devinit i810_fix_offsets(struct i810fb_par *par)
+{
+	if (vram + 1 > par->aperture.size >> 20)
+		vram = (par->aperture.size >> 20) - 1;
+	if (v_offset_default > (par->aperture.size >> 20))
+		v_offset_default = (par->aperture.size >> 20);
+	if (vram + v_offset_default + 1 > par->aperture.size >> 20)
+		v_offset_default = (par->aperture.size >> 20) - (vram + 1);
+
+	par->fb.size = vram << 20;
+	par->fb.offset = v_offset_default << 20;
+	par->fb.offset >>= 12;
+
+	par->iring.offset = par->fb.offset + (par->fb.size >> 12);
+	par->iring.size = RINGBUFFER_SIZE;
+
+	par->cursor_heap.offset = par->iring.offset + (RINGBUFFER_SIZE >> 12);
+	par->cursor_heap.size = 4096;
+}
+
+static int __devinit i810_alloc_agp_mem(struct fb_info *info)
+{
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+	int size;
+	struct agp_bridge_data *bridge;
+	
+	i810_fix_offsets(par);
+	size = par->fb.size + par->iring.size;
+
+	if (!(bridge = agp_backend_acquire(par->dev))) {
+		printk("i810fb_alloc_fbmem: cannot acquire agpgart\n");
+		return -ENODEV;
+	}
+	if (!(par->i810_gtt.i810_fb_memory = 
+	      agp_allocate_memory(bridge, size >> 12, AGP_NORMAL_MEMORY))) {
+		printk("i810fb_alloc_fbmem: can't allocate framebuffer "
+		       "memory\n");
+		agp_backend_release(bridge);
+		return -ENOMEM;
+	}
+	if (agp_bind_memory(par->i810_gtt.i810_fb_memory,
+			    par->fb.offset)) {
+		printk("i810fb_alloc_fbmem: can't bind framebuffer memory\n");
+		agp_backend_release(bridge);
+		return -EBUSY;
+	}	
+	
+	if (!(par->i810_gtt.i810_cursor_memory = 
+	      agp_allocate_memory(bridge, par->cursor_heap.size >> 12,
+				  AGP_PHYSICAL_MEMORY))) {
+		printk("i810fb_alloc_cursormem:  can't allocate" 
+		       "cursor memory\n");
+		agp_backend_release(bridge);
+		return -ENOMEM;
+	}
+	if (agp_bind_memory(par->i810_gtt.i810_cursor_memory,
+			    par->cursor_heap.offset)) {
+		printk("i810fb_alloc_cursormem: cannot bind cursor memory\n");
+		agp_backend_release(bridge);
+		return -EBUSY;
+	}	
+
+	par->cursor_heap.physical = par->i810_gtt.i810_cursor_memory->physical;
+
+	i810_fix_pointers(par);
+
+	agp_backend_release(bridge);
+
+	return 0;
+}
+
+/*************************************************************** 
+ *                    Initialization                           * 
+ ***************************************************************/
+
+/**
+ * i810_init_monspecs
+ * @info: pointer to device specific info structure
+ *
+ * DESCRIPTION:
+ * Sets the the user monitor's horizontal and vertical
+ * frequency limits
+ */
+static void __devinit i810_init_monspecs(struct fb_info *info)
+{
+	if (!hsync1)
+		hsync1 = HFMIN;
+	if (!hsync2) 
+		hsync2 = HFMAX;
+	if (!info->monspecs.hfmax)
+		info->monspecs.hfmax = hsync2;
+	if (!info->monspecs.hfmin)
+		info->monspecs.hfmin = hsync1;
+	if (hsync2 < hsync1)
+		info->monspecs.hfmin = hsync2;
+
+	if (!vsync1)
+		vsync1 = VFMIN;
+	if (!vsync2) 
+		vsync2 = VFMAX;
+	if (IS_DVT && vsync1 < 60)
+		vsync1 = 60;
+	if (!info->monspecs.vfmax)
+		info->monspecs.vfmax = vsync2;
+	if (!info->monspecs.vfmin)
+		info->monspecs.vfmin = vsync1;
+	if (vsync2 < vsync1) 
+		info->monspecs.vfmin = vsync2;
+}
+
+/**
+ * i810_init_defaults - initializes default values to use
+ * @par: pointer to i810fb_par structure
+ * @info: pointer to current fb_info structure
+ */
+static void __devinit i810_init_defaults(struct i810fb_par *par, 
+				      struct fb_info *info)
+{
+	if (voffset) 
+		v_offset_default = voffset;
+	else if (par->aperture.size > 32 * 1024 * 1024)
+		v_offset_default = 16;
+	else
+		v_offset_default = 8;
+
+	if (!vram) 
+		vram = 1;
+
+	if (accel) 
+		par->dev_flags |= HAS_ACCELERATION;
+
+	if (sync) 
+		par->dev_flags |= ALWAYS_SYNC;
+
+	if (bpp < 8)
+		bpp = 8;
+	
+	if (!vyres) 
+		vyres = (vram << 20)/(xres*bpp >> 3);
+
+	par->i810fb_ops = i810fb_ops;
+	info->var.xres = xres;
+	info->var.yres = yres;
+	info->var.yres_virtual = vyres;
+	info->var.bits_per_pixel = bpp;
+
+	if (dcolor)
+		info->var.nonstd = 1;
+
+	if (par->dev_flags & HAS_ACCELERATION) 
+		info->var.accel_flags = 1;
+
+	i810_init_monspecs(info);
+}
+	
+/**
+ * i810_init_device - initialize device
+ * @par: pointer to i810fb_par structure
+ */
+static void __devinit i810_init_device(struct i810fb_par *par)
+{
+	u8 reg;
+	u8 __iomem *mmio = par->mmio_start_virtual;
+
+	if (mtrr) set_mtrr(par);
+
+	i810_init_cursor(par);
+
+	/* mvo: enable external vga-connector (for laptops) */
+	if (ext_vga) {
+		i810_writel(HVSYNC, mmio, 0);
+		i810_writel(PWR_CLKC, mmio, 3);
+	}
+
+	pci_read_config_byte(par->dev, 0x50, &reg);
+	reg &= FREQ_MASK;
+	par->mem_freq = (reg) ? 133 : 100;
+
+}
+
+static int __devinit 
+i810_allocate_pci_resource(struct i810fb_par *par, 
+			   const struct pci_device_id *entry)
+{
+	int err;
+
+	if ((err = pci_enable_device(par->dev))) { 
+		printk("i810fb_init: cannot enable device\n");
+		return err;		
+	}
+	par->res_flags |= PCI_DEVICE_ENABLED;
+
+	if (pci_resource_len(par->dev, 0) > 512 * 1024) {
+		par->aperture.physical = pci_resource_start(par->dev, 0);
+		par->aperture.size = pci_resource_len(par->dev, 0);
+		par->mmio_start_phys = pci_resource_start(par->dev, 1);
+	} else {
+		par->aperture.physical = pci_resource_start(par->dev, 1);
+		par->aperture.size = pci_resource_len(par->dev, 1);
+		par->mmio_start_phys = pci_resource_start(par->dev, 0);
+	}
+	if (!par->aperture.size) {
+		printk("i810fb_init: device is disabled\n");
+		return -ENOMEM;
+	}
+
+	if (!request_mem_region(par->aperture.physical, 
+				par->aperture.size, 
+				i810_pci_list[entry->driver_data])) {
+		printk("i810fb_init: cannot request framebuffer region\n");
+		return -ENODEV;
+	}
+	par->res_flags |= FRAMEBUFFER_REQ;
+
+	par->aperture.virtual = ioremap_nocache(par->aperture.physical, 
+					par->aperture.size);
+	if (!par->aperture.virtual) {
+		printk("i810fb_init: cannot remap framebuffer region\n");
+		return -ENODEV;
+	}
+  
+	if (!request_mem_region(par->mmio_start_phys, 
+				MMIO_SIZE, 
+				i810_pci_list[entry->driver_data])) {
+		printk("i810fb_init: cannot request mmio region\n");
+		return -ENODEV;
+	}
+	par->res_flags |= MMIO_REQ;
+
+	par->mmio_start_virtual = ioremap_nocache(par->mmio_start_phys, 
+						  MMIO_SIZE);
+	if (!par->mmio_start_virtual) {
+		printk("i810fb_init: cannot remap mmio region\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+#ifndef MODULE
+static int __init i810fb_setup(char *options)
+{
+	char *this_opt, *suffix = NULL;
+
+	if (!options || !*options)
+		return 0;
+	
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!strncmp(this_opt, "mtrr", 4))
+			mtrr = 1;
+		else if (!strncmp(this_opt, "accel", 5))
+			accel = 1;
+		else if (!strncmp(this_opt, "ext_vga", 7))
+			ext_vga = 1;
+		else if (!strncmp(this_opt, "sync", 4))
+			sync = 1;
+		else if (!strncmp(this_opt, "vram:", 5))
+			vram = (simple_strtoul(this_opt+5, NULL, 0));
+		else if (!strncmp(this_opt, "voffset:", 8))
+			voffset = (simple_strtoul(this_opt+8, NULL, 0));
+		else if (!strncmp(this_opt, "xres:", 5))
+			xres = simple_strtoul(this_opt+5, NULL, 0);
+		else if (!strncmp(this_opt, "yres:", 5))
+			yres = simple_strtoul(this_opt+5, NULL, 0);
+		else if (!strncmp(this_opt, "vyres:", 6))
+			vyres = simple_strtoul(this_opt+6, NULL, 0);
+		else if (!strncmp(this_opt, "bpp:", 4))
+			bpp = simple_strtoul(this_opt+4, NULL, 0);
+		else if (!strncmp(this_opt, "hsync1:", 7)) {
+			hsync1 = simple_strtoul(this_opt+7, &suffix, 0);
+			if (strncmp(suffix, "H", 1)) 
+				hsync1 *= 1000;
+		} else if (!strncmp(this_opt, "hsync2:", 7)) {
+			hsync2 = simple_strtoul(this_opt+7, &suffix, 0);
+			if (strncmp(suffix, "H", 1)) 
+				hsync2 *= 1000;
+		} else if (!strncmp(this_opt, "vsync1:", 7)) 
+			vsync1 = simple_strtoul(this_opt+7, NULL, 0);
+		else if (!strncmp(this_opt, "vsync2:", 7))
+			vsync2 = simple_strtoul(this_opt+7, NULL, 0);
+		else if (!strncmp(this_opt, "dcolor", 6))
+			dcolor = 1;
+	}
+	return 0;
+}
+#endif
+
+static int __devinit i810fb_init_pci (struct pci_dev *dev, 
+				   const struct pci_device_id *entry)
+{
+	struct fb_info    *info;
+	struct i810fb_par *par = NULL;
+	int i, err = -1, vfreq, hfreq, pixclock;
+
+	i = 0;
+
+	info = framebuffer_alloc(sizeof(struct i810fb_par), &dev->dev);
+	if (!info)
+		return -ENOMEM;
+
+	par = (struct i810fb_par *) info->par;
+	par->dev = dev;
+
+	if (!(info->pixmap.addr = kmalloc(8*1024, GFP_KERNEL))) {
+		i810fb_release_resource(info, par);
+		return -ENOMEM;
+	}
+	memset(info->pixmap.addr, 0, 8*1024);
+	info->pixmap.size = 8*1024;
+	info->pixmap.buf_align = 8;
+	info->pixmap.flags = FB_PIXMAP_SYSTEM;
+
+	if ((err = i810_allocate_pci_resource(par, entry))) {
+		i810fb_release_resource(info, par);
+		return err;
+	}
+
+	i810_init_defaults(par, info);
+
+	if ((err = i810_alloc_agp_mem(info))) {
+		i810fb_release_resource(info, par);
+		return err;
+	}
+
+	i810_init_device(par);        
+
+	info->screen_base = par->fb.virtual;
+	info->fbops = &par->i810fb_ops;
+	info->pseudo_palette = par->pseudo_palette;
+	fb_alloc_cmap(&info->cmap, 256, 0);
+
+	if ((err = info->fbops->fb_check_var(&info->var, info))) {
+		i810fb_release_resource(info, par);
+		return err;
+	}
+	encode_fix(&info->fix, info); 
+	 	    
+	i810fb_init_ringbuffer(info);
+	err = register_framebuffer(info);
+	if (err < 0) {
+    		i810fb_release_resource(info, par); 
+		printk("i810fb_init: cannot register framebuffer device\n");
+    		return err;  
+    	}   
+
+	pci_set_drvdata(dev, info);
+	pixclock = 1000000000/(info->var.pixclock);
+	pixclock *= 1000;
+	hfreq = pixclock/(info->var.xres + info->var.left_margin + 
+			  info->var.hsync_len + info->var.right_margin);
+	vfreq = hfreq/(info->var.yres + info->var.upper_margin +
+		       info->var.vsync_len + info->var.lower_margin);
+
+      	printk("I810FB: fb%d         : %s v%d.%d.%d%s\n"
+      	       "I810FB: Video RAM   : %dK\n" 
+	       "I810FB: Monitor     : H: %d-%d KHz V: %d-%d Hz\n"
+	       "I810FB: Mode        : %dx%d-%dbpp@%dHz\n",
+	       info->node,
+	       i810_pci_list[entry->driver_data],
+	       VERSION_MAJOR, VERSION_MINOR, VERSION_TEENIE, BRANCH_VERSION,
+	       (int) par->fb.size>>10, info->monspecs.hfmin/1000,
+	       info->monspecs.hfmax/1000, info->monspecs.vfmin,
+	       info->monspecs.vfmax, info->var.xres, 
+	       info->var.yres, info->var.bits_per_pixel, vfreq);
+	return 0;
+}
+
+/***************************************************************
+ *                     De-initialization                        *
+ ***************************************************************/
+
+static void i810fb_release_resource(struct fb_info *info, 
+				    struct i810fb_par *par)
+{
+	struct gtt_data *gtt = &par->i810_gtt;
+	unset_mtrr(par);
+
+	if (par->i810_gtt.i810_cursor_memory)
+		agp_free_memory(gtt->i810_cursor_memory);
+	if (par->i810_gtt.i810_fb_memory)
+		agp_free_memory(gtt->i810_fb_memory);
+
+	if (par->mmio_start_virtual)
+		iounmap(par->mmio_start_virtual);
+	if (par->aperture.virtual)
+		iounmap(par->aperture.virtual);
+
+	if (par->res_flags & FRAMEBUFFER_REQ)
+		release_mem_region(par->aperture.physical,
+				   par->aperture.size);
+	if (par->res_flags & MMIO_REQ)
+		release_mem_region(par->mmio_start_phys, MMIO_SIZE);
+
+	if (par->res_flags & PCI_DEVICE_ENABLED)
+		pci_disable_device(par->dev);
+
+	framebuffer_release(info);
+
+}
+
+static void __exit i810fb_remove_pci(struct pci_dev *dev)
+{
+	struct fb_info *info = pci_get_drvdata(dev);
+	struct i810fb_par *par = (struct i810fb_par *) info->par;
+
+	unregister_framebuffer(info);  
+	i810fb_release_resource(info, par);
+	pci_set_drvdata(dev, NULL);
+	printk("cleanup_module:  unloaded i810 framebuffer device\n");
+}                                                	
+
+#ifndef MODULE
+static int __init i810fb_init(void)
+{
+	char *option = NULL;
+
+	if (fb_get_options("i810fb", &option))
+		return -ENODEV;
+	i810fb_setup(option);
+
+	return pci_register_driver(&i810fb_driver);
+}
+#endif 
+
+/*********************************************************************
+ *                          Modularization                           *
+ *********************************************************************/
+
+#ifdef MODULE
+
+static int __init i810fb_init(void)
+{
+	hsync1 *= 1000;
+	hsync2 *= 1000;
+
+	return pci_register_driver(&i810fb_driver);
+}
+
+module_param(vram, int, 0);
+MODULE_PARM_DESC(vram, "System RAM to allocate to framebuffer in MiB" 
+		 " (default=4)");
+module_param(voffset, int, 0);
+MODULE_PARM_DESC(voffset, "at what offset to place start of framebuffer "
+                 "memory (0 to maximum aperture size), in MiB (default = 48)");
+module_param(bpp, int, 0);
+MODULE_PARM_DESC(bpp, "Color depth for display in bits per pixel"
+		 " (default = 8)");
+module_param(xres, int, 0);
+MODULE_PARM_DESC(xres, "Horizontal resolution in pixels (default = 640)");
+module_param(yres, int, 0);
+MODULE_PARM_DESC(yres, "Vertical resolution in scanlines (default = 480)");
+module_param(vyres,int, 0);
+MODULE_PARM_DESC(vyres, "Virtual vertical resolution in scanlines"
+		 " (default = 480)");
+module_param(hsync1, int, 0);
+MODULE_PARM_DESC(hsync1, "Minimum horizontal frequency of monitor in KHz"
+		 " (default = 31)");
+module_param(hsync2, int, 0);
+MODULE_PARM_DESC(hsync2, "Maximum horizontal frequency of monitor in KHz"
+		 " (default = 31)");
+module_param(vsync1, int, 0);
+MODULE_PARM_DESC(vsync1, "Minimum vertical frequency of monitor in Hz"
+		 " (default = 50)");
+module_param(vsync2, int, 0);
+MODULE_PARM_DESC(vsync2, "Maximum vertical frequency of monitor in Hz" 
+		 " (default = 60)");
+module_param(accel, bool, 0);
+MODULE_PARM_DESC(accel, "Use Acceleration (BLIT) engine (default = 0)");
+module_param(mtrr, bool, 0);
+MODULE_PARM_DESC(mtrr, "Use MTRR (default = 0)");
+module_param(ext_vga, bool, 0);
+MODULE_PARM_DESC(ext_vga, "Enable external VGA connector (default = 0)");
+module_param(sync, bool, 0);
+MODULE_PARM_DESC(sync, "wait for accel engine to finish drawing"
+		 " (default = 0)");
+module_param(dcolor, bool, 0);
+MODULE_PARM_DESC(dcolor, "use DirectColor visuals"
+		 " (default = 0 = TrueColor)");
+
+MODULE_AUTHOR("Tony A. Daplas");
+MODULE_DESCRIPTION("Framebuffer device for the Intel 810/815 and"
+		   " compatible cards");
+MODULE_LICENSE("GPL"); 
+
+static void __exit i810fb_exit(void)
+{
+	pci_unregister_driver(&i810fb_driver);
+}
+module_exit(i810fb_exit);
+
+#endif /* MODULE */
+
+module_init(i810fb_init);
diff --git a/drivers/video/i810/i810_main.h b/drivers/video/i810/i810_main.h
new file mode 100644
index 0000000..43b4297
--- /dev/null
+++ b/drivers/video/i810/i810_main.h
@@ -0,0 +1,127 @@
+/*-*- linux-c -*-
+ *  linux/drivers/video/i810fb_main.h -- Intel 810 frame buffer device 
+ *                                       main header file
+ *
+ *      Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
+ *      All Rights Reserved      
+ *
+ *
+ *  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 __I810_MAIN_H__
+#define __I810_MAIN_H__
+
+static int  __devinit i810fb_init_pci (struct pci_dev *dev, 
+				       const struct pci_device_id *entry);
+static void __exit i810fb_remove_pci(struct pci_dev *dev);
+static int i810fb_resume(struct pci_dev *dev);
+static int i810fb_suspend(struct pci_dev *dev, pm_message_t state);
+
+/*
+ * voffset - framebuffer offset in MiB from aperture start address.  In order for
+ * the driver to work with X, we must try to use memory holes left untouched by X. The 
+ * following table lists where X's different surfaces start at.  
+ * 
+ * ---------------------------------------------
+ * :                :  64 MiB     : 32 MiB      :
+ * ----------------------------------------------
+ * : FrontBuffer    :   0         :  0          :
+ * : DepthBuffer    :   48        :  16         :
+ * : BackBuffer     :   56        :  24         :
+ * ----------------------------------------------
+ *
+ * So for chipsets with 64 MiB Aperture sizes, 32 MiB for v_offset is okay, allowing up to
+ * 15 + 1 MiB of Framebuffer memory.  For 32 MiB Aperture sizes, a v_offset of 8 MiB should
+ * work, allowing 7 + 1 MiB of Framebuffer memory.
+ * Note, the size of the hole may change depending on how much memory you allocate to X,
+ * and how the memory is split up between these surfaces.  
+ *
+ * Note: Anytime the DepthBuffer or FrontBuffer is overlapped, X would still run but with
+ * DRI disabled.  But if the Frontbuffer is overlapped, X will fail to load.
+ * 
+ * Experiment with v_offset to find out which works best for you.
+ */
+static u32 v_offset_default __initdata; /* For 32 MiB Aper size, 8 should be the default */
+static u32 voffset          __initdata = 0;
+
+static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor);
+
+/* Chipset Specific Functions */
+static int i810fb_set_par    (struct fb_info *info);
+static int i810fb_getcolreg  (u8 regno, u8 *red, u8 *green, u8 *blue,
+			      u8 *transp, struct fb_info *info);
+static int i810fb_setcolreg  (unsigned regno, unsigned red, unsigned green, unsigned blue,
+			      unsigned transp, struct fb_info *info);
+static int i810fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
+static int i810fb_blank      (int blank_mode, struct fb_info *info);
+
+/* Initialization */
+static void i810fb_release_resource       (struct fb_info *info, struct i810fb_par *par);
+extern int __init agp_intel_init(void);
+
+
+/* Video Timings */
+extern void round_off_xres         (u32 *xres);
+extern void round_off_yres         (u32 *xres, u32 *yres);
+extern u32 i810_get_watermark      (const struct fb_var_screeninfo *var,
+			            struct i810fb_par *par);
+extern void i810fb_encode_registers(const struct fb_var_screeninfo *var,
+				    struct i810fb_par *par, u32 xres, u32 yres);
+extern void i810fb_fill_var_timings(struct fb_var_screeninfo *var);
+				    
+/* Accelerated Functions */
+extern void i810fb_fillrect (struct fb_info *p, 
+			     const struct fb_fillrect *rect);
+extern void i810fb_copyarea (struct fb_info *p, 
+			     const struct fb_copyarea *region);
+extern void i810fb_imageblit(struct fb_info *p, const struct fb_image *image);
+extern int  i810fb_sync     (struct fb_info *p);
+
+extern void i810fb_init_ringbuffer(struct fb_info *info);
+extern void i810fb_load_front     (u32 offset, struct fb_info *info);
+
+/* Conditionals */
+#ifdef CONFIG_X86
+inline void flush_cache(void)
+{
+	asm volatile ("wbinvd":::"memory");
+}
+#else
+#define flush_cache() do { } while(0)
+#endif 
+
+#ifdef CONFIG_MTRR
+#define KERNEL_HAS_MTRR 1
+static inline void __devinit set_mtrr(struct i810fb_par *par)
+{
+	par->mtrr_reg = mtrr_add((u32) par->aperture.physical, 
+		 par->aperture.size, MTRR_TYPE_WRCOMB, 1);
+	if (par->mtrr_reg < 0) {
+		printk(KERN_ERR "set_mtrr: unable to set MTRR\n");
+		return;
+	}
+	par->dev_flags |= HAS_MTRR;
+}
+static inline void unset_mtrr(struct i810fb_par *par)
+{
+  	if (par->dev_flags & HAS_MTRR) 
+  		mtrr_del(par->mtrr_reg, (u32) par->aperture.physical, 
+			 par->aperture.size); 
+}
+#else
+#define KERNEL_HAS_MTRR 0
+#define set_mtrr(x) printk("set_mtrr: MTRR is disabled in the kernel\n")
+
+#define unset_mtrr(x) do { } while (0)
+#endif /* CONFIG_MTRR */
+
+#ifdef CONFIG_FB_I810_GTF
+#define IS_DVT (0)
+#else
+#define IS_DVT (1)
+#endif
+
+#endif /* __I810_MAIN_H__ */
diff --git a/drivers/video/i810/i810_regs.h b/drivers/video/i810/i810_regs.h
new file mode 100644
index 0000000..6e4b9af
--- /dev/null
+++ b/drivers/video/i810/i810_regs.h
@@ -0,0 +1,274 @@
+/*-*- linux-c -*-
+ *  linux/drivers/video/i810_regs.h -- Intel 810/815 Register List
+ *
+ *      Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
+ *      All Rights Reserved      
+ *
+ *
+ *  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.
+ */
+
+
+/*
+ * Intel 810 Chipset Family PRM 15 3.1 
+ * GC Register Memory Address Map 
+ *
+ * Based on:
+ * Intel (R) 810 Chipset Family 
+ * Programmer s Reference Manual 
+ * November 1999 
+ * Revision 1.0 
+ * Order Number: 298026-001 R
+ *
+ * All GC registers are memory-mapped. In addition, the VGA and extended VGA registers 
+ * are I/O mapped. 
+ */
+ 
+#ifndef __I810_REGS_H__
+#define __I810_REGS_H__
+
+/*  Instruction and Interrupt Control Registers (01000h 02FFFh) */
+#define FENCE                 0x02000                
+#define PGTBL_CTL             0x02020 
+#define PGTBL_ER              0x02024               
+#define    LRING              0x02030
+#define    IRING              0x02040
+#define HWS_PGA               0x02080 
+#define IPEIR                 0x02088
+#define IPEHR                 0x0208C 
+#define INSTDONE              0x02090 
+#define NOPID                 0x02094
+#define HWSTAM                0x02098 
+#define IER                   0x020A0
+#define IIR                   0x020A4
+#define IMR                   0x020A8 
+#define ISR                   0x020AC 
+#define EIR                   0x020B0 
+#define EMR                   0x020B4 
+#define ESR                   0x020B8 
+#define INSTPM                0x020C0
+#define INSTPS                0x020C4 
+#define BBP_PTR               0x020C8 
+#define ABB_SRT               0x020CC
+#define ABB_END               0x020D0
+#define DMA_FADD              0x020D4 
+#define FW_BLC                0x020D8
+#define MEM_MODE              0x020DC        
+
+/*  Memory Control Registers (03000h 03FFFh) */
+#define DRT                   0x03000
+#define DRAMCL                0x03001
+#define DRAMCH                0x03002
+ 
+
+/* Span Cursor Registers (04000h 04FFFh) */
+#define UI_SC_CTL             0x04008 
+
+/* I/O Control Registers (05000h 05FFFh) */
+#define HVSYNC                0x05000 
+#define GPIOA                 0x05010
+#define GPIOB                 0x05014 
+
+/* Clock Control and Power Management Registers (06000h 06FFFh) */
+#define DCLK_0D               0x06000
+#define DCLK_1D               0x06004
+#define DCLK_2D               0x06008
+#define LCD_CLKD              0x0600C
+#define DCLK_0DS              0x06010
+#define PWR_CLKC              0x06014
+
+/* Graphics Translation Table Range Definition (10000h 1FFFFh) */
+#define GTT                   0x10000  
+
+/*  Overlay Registers (30000h 03FFFFh) */
+#define OVOADDR               0x30000
+#define DOVOSTA               0x30008
+#define GAMMA                 0x30010
+#define OBUF_0Y               0x30100
+#define OBUF_1Y               0x30104
+#define OBUF_0U               0x30108
+#define OBUF_0V               0x3010C
+#define OBUF_1U               0x30110
+#define OBUF_1V               0x30114 
+#define OVOSTRIDE             0x30118
+#define YRGB_VPH              0x3011C
+#define UV_VPH                0x30120
+#define HORZ_PH               0x30124
+#define INIT_PH               0x30128
+#define DWINPOS               0x3012C 
+#define DWINSZ                0x30130
+#define SWID                  0x30134
+#define SWIDQW                0x30138
+#define SHEIGHT               0x3013F
+#define YRGBSCALE             0x30140 
+#define UVSCALE               0x30144
+#define OVOCLRCO              0x30148
+#define OVOCLRC1              0x3014C
+#define DCLRKV                0x30150
+#define DLCRKM                0x30154
+#define SCLRKVH               0x30158
+#define SCLRKVL               0x3015C
+#define SCLRKM                0x30160
+#define OVOCONF               0x30164
+#define OVOCMD                0x30168
+#define AWINPOS               0x30170
+#define AWINZ                 0x30174
+
+/*  BLT Engine Status (40000h 4FFFFh) (Software Debug) */
+#define BR00                  0x40000
+#define BRO1                  0x40004
+#define BR02                  0x40008
+#define BR03                  0x4000C
+#define BR04                  0x40010
+#define BR05                  0x40014
+#define BR06                  0x40018
+#define BR07                  0x4001C
+#define BR08                  0x40020
+#define BR09                  0x40024
+#define BR10                  0x40028
+#define BR11                  0x4002C
+#define BR12                  0x40030
+#define BR13                  0x40034
+#define BR14                  0x40038
+#define BR15                  0x4003C
+#define BR16                  0x40040
+#define BR17                  0x40044
+#define BR18                  0x40048
+#define BR19                  0x4004C
+#define SSLADD                0x40074
+#define DSLH                  0x40078
+#define DSLRADD               0x4007C
+
+
+/* LCD/TV-Out and HW DVD Registers (60000h 6FFFFh) */
+/* LCD/TV-Out */
+#define HTOTAL                0x60000
+#define HBLANK                0x60004
+#define HSYNC                 0x60008
+#define VTOTAL                0x6000C
+#define VBLANK                0x60010
+#define VSYNC                 0x60014
+#define LCDTV_C               0x60018
+#define OVRACT                0x6001C
+#define BCLRPAT               0x60020
+
+/*  Display and Cursor Control Registers (70000h 7FFFFh) */
+#define DISP_SL               0x70000
+#define DISP_SLC              0x70004
+#define PIXCONF               0x70008
+#define PIXCONF1              0x70009
+#define BLTCNTL               0x7000C
+#define SWF                   0x70014
+#define DPLYBASE              0x70020
+#define DPLYSTAS              0x70024
+#define CURCNTR               0x70080
+#define CURBASE               0x70084
+#define CURPOS                0x70088
+
+
+/* VGA Registers */
+
+/* SMRAM Registers */
+#define SMRAM                 0x10
+
+/* Graphics Control Registers */
+#define GR_INDEX              0x3CE
+#define GR_DATA               0x3CF
+
+#define GR10                  0x10
+#define GR11                  0x11
+
+/* CRT Controller Registers */
+#define CR_INDEX_MDA          0x3B4
+#define CR_INDEX_CGA          0x3D4
+#define CR_DATA_MDA           0x3B5
+#define CR_DATA_CGA           0x3D5
+
+#define CR30                  0x30
+#define CR31                  0x31
+#define CR32                  0x32
+#define CR33                  0x33
+#define CR35                  0x35
+#define CR39                  0x39
+#define CR40                  0x40
+#define CR41                  0x41
+#define CR42                  0x42
+#define CR70                  0x70
+#define CR80                  0x80 
+#define CR81                  0x82
+
+/* Extended VGA Registers */
+
+/* General Control and Status Registers */
+#define ST00                  0x3C2
+#define ST01_MDA              0x3BA
+#define ST01_CGA              0x3DA
+#define FRC_READ              0x3CA
+#define FRC_WRITE_MDA         0x3BA
+#define FRC_WRITE_CGA         0x3DA
+#define MSR_READ              0x3CC
+#define MSR_WRITE             0x3C2
+
+/* Sequencer Registers */
+#define SR_INDEX              0x3C4
+#define SR_DATA               0x3C5
+
+#define SR01                  0x01
+#define SR02                  0x02
+#define SR03                  0x03
+#define SR04                  0x04
+#define SR07                  0x07
+
+/* Graphics Controller Registers */
+#define GR00                  0x00   
+#define GR01                  0x01
+#define GR02                  0x02
+#define GR03                  0x03
+#define GR04                  0x04
+#define GR05                  0x05
+#define GR06                  0x06
+#define GR07                  0x07
+#define GR08                  0x08  
+
+/* Attribute Controller Registers */
+#define ATTR_WRITE              0x3C0
+#define ATTR_READ               0x3C1
+
+/* VGA Color Palette Registers */
+
+/* CLUT */
+#define CLUT_DATA             0x3C9        /* DACDATA */
+#define CLUT_INDEX_READ       0x3C7        /* DACRX */
+#define CLUT_INDEX_WRITE      0x3C8        /* DACWX */
+#define DACMASK               0x3C6
+
+/* CRT Controller Registers */
+#define CR00                  0x00
+#define CR01                  0x01
+#define CR02                  0x02
+#define CR03                  0x03
+#define CR04                  0x04
+#define CR05                  0x05
+#define CR06                  0x06
+#define CR07                  0x07
+#define CR08                  0x08
+#define CR09                  0x09
+#define CR0A                  0x0A
+#define CR0B                  0x0B
+#define CR0C                  0x0C
+#define CR0D                  0x0D
+#define CR0E                  0x0E
+#define CR0F                  0x0F
+#define CR10                  0x10
+#define CR11                  0x11
+#define CR12                  0x12
+#define CR13                  0x13
+#define CR14                  0x14
+#define CR15                  0x15
+#define CR16                  0x16
+#define CR17                  0x17
+#define CR18                  0x18
+
+#endif /* __I810_REGS_H__ */
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
new file mode 100644
index 0000000..e326f44
--- /dev/null
+++ b/drivers/video/igafb.c
@@ -0,0 +1,579 @@
+/*
+ *  linux/drivers/video/igafb.c -- Frame buffer device for IGA 1682
+ *
+ *      Copyright (C) 1998  Vladimir Roganov and Gleb Raiko
+ *
+ *  This driver is partly based on the Frame buffer device for ATI Mach64
+ *  and partially on VESA-related code.
+ *
+ *      Copyright (C) 1997-1998  Geert Uytterhoeven
+ *      Copyright (C) 1998  Bernd Harries
+ *      Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
+ *
+ *  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.
+ */
+
+/******************************************************************************
+
+  TODO:
+       Despite of IGA Card has advanced graphic acceleration, 
+       initial version is almost dummy and does not support it.
+       Support for video modes and acceleration must be added
+       together with accelerated X-Windows driver implementation.
+
+       Most important thing at this moment is that we have working
+       JavaEngine1  console & X  with new console interface.
+
+******************************************************************************/
+
+#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 <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/nvram.h>
+
+#include <asm/io.h>
+
+#ifdef __sparc__
+#include <asm/pbm.h>
+#include <asm/pcic.h>
+#endif
+
+#include <video/iga.h>
+
+struct pci_mmap_map {
+    unsigned long voff;
+    unsigned long poff;
+    unsigned long size;
+    unsigned long prot_flag;
+    unsigned long prot_mask;
+};
+
+struct iga_par {
+	struct pci_mmap_map *mmap_map;
+	unsigned long frame_buffer_phys;
+	unsigned long io_base;
+};
+
+struct fb_info fb_info;
+
+struct fb_fix_screeninfo igafb_fix __initdata = {
+        .id		= "IGA 1682",
+	.type		= FB_TYPE_PACKED_PIXELS,
+	.mmio_len 	= 1000
+};
+
+struct fb_var_screeninfo default_var = {
+	/* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
+	.xres		= 640,
+	.yres		= 480,
+	.xres_virtual	= 640,
+	.yres_virtual	= 480,
+	.bits_per_pixel	= 8,
+	.red		= {0, 8, 0 },
+	.green		= {0, 8, 0 },
+	.blue		= {0, 8, 0 },
+	.height		= -1,
+	.width		= -1,
+	.accel_flags	= FB_ACCEL_NONE,
+	.pixclock	= 39722,
+	.left_margin	= 48,
+	.right_margin	= 16,
+	.upper_margin	= 33,
+	.lower_margin	= 10,
+	.hsync_len	= 96,
+	.vsync_len	= 2,
+	.vmode		= FB_VMODE_NONINTERLACED
+};
+
+#ifdef __sparc__
+struct fb_var_screeninfo default_var_1024x768 __initdata = {
+	/* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */
+	.xres		= 1024,
+	.yres		= 768,
+	.xres_virtual	= 1024,
+	.yres_virtual	= 768,
+	.bits_per_pixel	= 8,
+	.red		= {0, 8, 0 },
+	.green		= {0, 8, 0 },
+	.blue		= {0, 8, 0 },
+	.height		= -1,
+	.width		= -1,
+	.accel_flags	= FB_ACCEL_NONE,
+	.pixclock	= 12699,
+	.left_margin	= 176,
+	.right_margin	= 16,
+	.upper_margin	= 28,
+	.lower_margin	= 1,
+	.hsync_len	= 96,
+	.vsync_len	= 3,
+	.vmode		= FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+};
+
+struct fb_var_screeninfo default_var_1152x900 __initdata = {
+	/* 1152x900, 76 Hz, Non-Interlaced (110.0 MHz dotclock) */
+	.xres		= 1152,
+	.yres		= 900,
+	.xres_virtual	= 1152,
+	.yres_virtual	= 900,
+	.bits_per_pixel	= 8,
+	.red		= { 0, 8, 0 },
+	.green		= { 0, 8, 0 },
+	.blue		= { 0, 8, 0 },
+	.height		= -1,
+	.width		= -1,
+	.accel_flags	= FB_ACCEL_NONE,
+	.pixclock	= 9091,
+	.left_margin	= 234,
+	.right_margin	= 24,
+	.upper_margin	= 34,
+	.lower_margin	= 3,
+	.hsync_len	= 100,
+	.vsync_len	= 3,
+	.vmode		= FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+};
+
+struct fb_var_screeninfo default_var_1280x1024 __initdata = {
+	/* 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) */
+	.xres		= 1280,
+	.yres		= 1024,
+	.xres_virtual	= 1280,
+	.yres_virtual	= 1024,
+	.bits_per_pixel	= 8,
+	.red		= {0, 8, 0 }, 
+	.green		= {0, 8, 0 },
+	.blue		= {0, 8, 0 },
+	.height		= -1,
+	.width		= -1,
+	.accel_flags	= 0,
+	.pixclock	= 7408,
+	.left_margin	= 248,
+	.right_margin	= 16,
+	.upper_margin	= 38,
+	.lower_margin	= 1,
+	.hsync_len	= 144,
+	.vsync_len	= 3,
+	.vmode		= FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+};
+
+/*
+ *   Memory-mapped I/O functions for Sparc PCI
+ *
+ * On sparc we happen to access I/O with memory mapped functions too.
+ */ 
+#define pci_inb(par, reg)        readb(par->io_base+(reg))
+#define pci_outb(par, val, reg)  writeb(val, par->io_base+(reg))
+
+static inline unsigned int iga_inb(struct iga_par *par, unsigned int reg,
+				   unsigned int idx)
+{
+        pci_outb(par, idx, reg);
+        return pci_inb(par, reg + 1);
+}
+
+static inline void iga_outb(struct iga_par *par, unsigned char val,
+			    unsigned int reg, unsigned int idx )
+{
+        pci_outb(par, idx, reg);
+        pci_outb(par, val, reg+1);
+}
+
+#endif /* __sparc__ */
+
+/*
+ *  Very important functionality for the JavaEngine1 computer:
+ *  make screen border black (usign special IGA registers) 
+ */
+static void iga_blank_border(struct iga_par *par)
+{
+        int i;
+#if 0
+	/*
+	 * PROM does this for us, so keep this code as a reminder
+	 * about required read from 0x3DA and writing of 0x20 in the end.
+	 */
+	(void) pci_inb(par, 0x3DA);		/* required for every access */
+	pci_outb(par, IGA_IDX_VGA_OVERSCAN, IGA_ATTR_CTL);
+	(void) pci_inb(par, IGA_ATTR_CTL+1);
+	pci_outb(par, 0x38, IGA_ATTR_CTL);
+	pci_outb(par, 0x20, IGA_ATTR_CTL);	/* re-enable visual */
+#endif
+	/*
+	 * This does not work as it was designed because the overscan
+	 * color is looked up in the palette. Therefore, under X11
+	 * overscan changes color.
+	 */
+	for (i=0; i < 3; i++)
+		iga_outb(par, 0, IGA_EXT_CNTRL, IGA_IDX_OVERSCAN_COLOR + i);
+}
+
+#ifdef __sparc__
+static int igafb_mmap(struct fb_info *info, struct file *file,
+		      struct vm_area_struct *vma)
+{
+	struct iga_par *par = (struct iga_par *)info->par;
+	unsigned int size, page, map_size = 0;
+	unsigned long map_offset = 0;
+	int i;
+
+	if (!par->mmap_map)
+		return -ENXIO;
+
+	size = vma->vm_end - vma->vm_start;
+
+	/* To stop the swapper from even considering these pages. */
+	vma->vm_flags |= (VM_SHM | VM_LOCKED);
+
+	/* Each page, see which map applies */
+	for (page = 0; page < size; ) {
+		map_size = 0;
+		for (i = 0; par->mmap_map[i].size; i++) {
+			unsigned long start = par->mmap_map[i].voff;
+			unsigned long end = start + par->mmap_map[i].size;
+			unsigned long offset = (vma->vm_pgoff << PAGE_SHIFT) + page;
+
+			if (start > offset)
+				continue;
+			if (offset >= end)
+				continue;
+
+			map_size = par->mmap_map[i].size - (offset - start);
+			map_offset = par->mmap_map[i].poff + (offset - start);
+			break;
+		}
+		if (!map_size) {
+			page += PAGE_SIZE;
+			continue;
+		}
+		if (page + map_size > size)
+			map_size = size - page;
+
+		pgprot_val(vma->vm_page_prot) &= ~(par->mmap_map[i].prot_mask);
+		pgprot_val(vma->vm_page_prot) |= par->mmap_map[i].prot_flag;
+
+		if (remap_pfn_range(vma, vma->vm_start + page,
+			map_offset >> PAGE_SHIFT, map_size, vma->vm_page_prot))
+			return -EAGAIN;
+
+		page += map_size;
+	}
+
+	if (!map_size)
+		return -EINVAL;
+
+	vma->vm_flags |= VM_IO;
+	return 0;
+}
+#endif /* __sparc__ */
+
+static int igafb_setcolreg(unsigned regno, unsigned red, unsigned green,
+                           unsigned blue, unsigned transp,
+                           struct fb_info *info)
+{
+        /*
+         *  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.
+         */
+	struct iga_par *par = (struct iga_par *)info->par;
+
+        if (regno >= info->cmap.len)
+                return 1;
+
+	pci_outb(par, regno, DAC_W_INDEX);
+	pci_outb(par, red,   DAC_DATA);
+	pci_outb(par, green, DAC_DATA);
+	pci_outb(par, blue,  DAC_DATA);
+
+	if (regno < 16) {
+		switch (info->var.bits_per_pixel) {
+		case 16:
+			((u16*)(info->pseudo_palette))[regno] = 
+				(regno << 10) | (regno << 5) | regno;
+			break;
+		case 24:
+			((u32*)(info->pseudo_palette))[regno] = 
+				(regno << 16) | (regno << 8) | regno;
+		break;
+		case 32:
+			{ int i;
+			i = (regno << 8) | regno;
+			((u32*)(info->pseudo_palette))[regno] = (i << 16) | i;
+			}
+			break;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Framebuffer option structure
+ */
+static struct fb_ops igafb_ops = {
+	.owner 		= THIS_MODULE,
+	.fb_setcolreg 	= igafb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+#ifdef __sparc__
+	.fb_mmap 	= igafb_mmap,
+#endif
+};
+
+static int __init iga_init(struct fb_info *info, struct iga_par *par)
+{
+        char vramsz = iga_inb(par, IGA_EXT_CNTRL, IGA_IDX_EXT_BUS_CNTL) 
+		                                         & MEM_SIZE_ALIAS;
+	int video_cmap_len;
+
+        switch (vramsz) {
+        case MEM_SIZE_1M:
+                info->fix.smem_len = 0x100000;
+                break;
+        case MEM_SIZE_2M:
+                info->fix.smem_len = 0x200000;
+                break;
+        case MEM_SIZE_4M:
+        case MEM_SIZE_RESERVED:
+                info->fix.smem_len = 0x400000;
+                break;
+        }
+
+        if (info->var.bits_per_pixel > 8) 
+                video_cmap_len = 16;
+        else 
+                video_cmap_len = 256;
+
+	info->fbops = &igafb_ops;
+	info->flags = FBINFO_DEFAULT;
+
+	fb_alloc_cmap(&info->cmap, video_cmap_len, 0);
+
+	if (register_framebuffer(info) < 0)
+		return 0;
+
+	printk("fb%d: %s frame buffer device at 0x%08lx [%dMB VRAM]\n",
+	       info->node, info->fix.id, 
+	       par->frame_buffer_phys, info->fix.smem_len >> 20);
+
+	iga_blank_border(par); 
+	return 1;
+}
+
+int __init igafb_init(void)
+{
+        extern int con_is_present(void);
+        struct fb_info *info;
+        struct pci_dev *pdev;
+        struct iga_par *par;
+	unsigned long addr;
+	int size, iga2000 = 0;
+
+	if (fb_get_options("igafb", NULL))
+		return -ENODEV;
+
+        /* Do not attach when we have a serial console. */
+        if (!con_is_present())
+                return -ENXIO;
+
+        pdev = pci_find_device(PCI_VENDOR_ID_INTERG, 
+                               PCI_DEVICE_ID_INTERG_1682, 0);
+	if (pdev == NULL) {
+		/*
+		 * XXX We tried to use cyber2000fb.c for IGS 2000.
+		 * But it does not initialize the chip in JavaStation-E, alas.
+		 */
+        	pdev = pci_find_device(PCI_VENDOR_ID_INTERG, 0x2000, 0);
+        	if(pdev == NULL) {
+        	        return -ENXIO;
+		}
+		iga2000 = 1;
+	}
+	
+	size = sizeof(struct fb_info) + sizeof(struct iga_par) + sizeof(u32)*16;
+
+        info = kmalloc(size, GFP_ATOMIC);
+        if (!info) {
+                printk("igafb_init: can't alloc fb_info\n");
+                return -ENOMEM;
+        }
+        memset(info, 0, size);
+
+	par = (struct iga_par *) (info + 1);
+	
+
+	if ((addr = pdev->resource[0].start) == 0) {
+                printk("igafb_init: no memory start\n");
+		kfree(info);
+		return -ENXIO;
+	}
+
+	if ((info->screen_base = ioremap(addr, 1024*1024*2)) == 0) {
+                printk("igafb_init: can't remap %lx[2M]\n", addr);
+		kfree(info);
+		return -ENXIO;
+	}
+
+	par->frame_buffer_phys = addr & PCI_BASE_ADDRESS_MEM_MASK;
+
+#ifdef __sparc__
+	/*
+	 * The following is sparc specific and this is why:
+	 *
+	 * IGS2000 has its I/O memory mapped and we want
+	 * to generate memory cycles on PCI, e.g. do ioremap(),
+	 * then readb/writeb() as in Documentation/IO-mapping.txt.
+	 *
+	 * IGS1682 is more traditional, it responds to PCI I/O
+	 * cycles, so we want to access it with inb()/outb().
+	 *
+	 * On sparc, PCIC converts CPU memory access within
+	 * phys window 0x3000xxxx into PCI I/O cycles. Therefore
+	 * we may use readb/writeb to access them with IGS1682.
+	 *
+	 * We do not take io_base_phys from resource[n].start
+	 * on IGS1682 because that chip is BROKEN. It does not
+	 * have a base register for I/O. We just "know" what its
+	 * I/O addresses are.
+	 */
+	if (iga2000) {
+		igafb_fix.mmio_start = par->frame_buffer_phys | 0x00800000;
+	} else {
+		igafb_fix.mmio_start = 0x30000000;	/* XXX */
+	}
+	if ((par->io_base = (int) ioremap(igafb_fix.mmio_start, igafb_fix.smem_len)) == 0) {
+                printk("igafb_init: can't remap %lx[4K]\n", igafb_fix.mmio_start);
+		iounmap((void *)info->screen_base);
+		kfree(info);
+		return -ENXIO;
+	}
+
+	/*
+	 * Figure mmap addresses from PCI config space.
+	 * We need two regions: for video memory and for I/O ports.
+	 * Later one can add region for video coprocessor registers.
+	 * However, mmap routine loops until size != 0, so we put
+	 * one additional region with size == 0. 
+	 */
+
+	par->mmap_map = kmalloc(4 * sizeof(*par->mmap_map), GFP_ATOMIC);
+	if (!par->mmap_map) {
+		printk("igafb_init: can't alloc mmap_map\n");
+		iounmap((void *)par->io_base);
+		iounmap(info->screen_base);
+		kfree(info);
+		return -ENOMEM;
+	}
+
+	memset(par->mmap_map, 0, 4 * sizeof(*par->mmap_map));
+
+	/*
+	 * Set default vmode and cmode from PROM properties.
+	 */
+	{
+                struct pcidev_cookie *cookie = pdev->sysdata;
+                int node = cookie->prom_node;
+                int width = prom_getintdefault(node, "width", 1024);
+                int height = prom_getintdefault(node, "height", 768);
+                int depth = prom_getintdefault(node, "depth", 8);
+                switch (width) {
+                    case 1024:
+                        if (height == 768)
+                            default_var = default_var_1024x768;
+                        break;
+                    case 1152:
+                        if (height == 900)
+                            default_var = default_var_1152x900;
+                        break;
+                    case 1280:
+                        if (height == 1024)
+                            default_var = default_var_1280x1024;
+                        break;
+                    default:
+                        break;
+                }
+
+                switch (depth) {
+                    case 8:
+                        default_var.bits_per_pixel = 8;
+                        break;
+                    case 16:
+                        default_var.bits_per_pixel = 16;
+                        break;
+                    case 24:
+                        default_var.bits_per_pixel = 24;
+                        break;
+                    case 32:
+                        default_var.bits_per_pixel = 32;
+                        break;
+                    default:
+                        break;
+                }
+            }
+
+#endif
+	igafb_fix.smem_start = (unsigned long) info->screen_base;
+	igafb_fix.line_length = default_var.xres*(default_var.bits_per_pixel/8);
+	igafb_fix.visual = default_var.bits_per_pixel <= 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
+
+	info->var = default_var;
+	info->fix = igafb_fix;
+	info->pseudo_palette = (void *)(par + 1);
+	info->device = &pdev->dev;
+
+	if (!iga_init(info, par)) {
+		iounmap((void *)par->io_base);
+		iounmap(info->screen_base);
+		kfree(par->mmap_map);
+		kfree(info);
+        }
+
+#ifdef __sparc__
+	    /*
+	     * Add /dev/fb mmap values.
+	     */
+	    
+	    /* First region is for video memory */
+	    par->mmap_map[0].voff = 0x0;  
+	    par->mmap_map[0].poff = par->frame_buffer_phys & PAGE_MASK;
+	    par->mmap_map[0].size = info->fix.smem_len & PAGE_MASK;
+	    par->mmap_map[0].prot_mask = SRMMU_CACHE;
+	    par->mmap_map[0].prot_flag = SRMMU_WRITE;
+
+	    /* Second region is for I/O ports */
+	    par->mmap_map[1].voff = par->frame_buffer_phys & PAGE_MASK;
+	    par->mmap_map[1].poff = info->fix.smem_start & PAGE_MASK;
+	    par->mmap_map[1].size = PAGE_SIZE * 2; /* X wants 2 pages */
+	    par->mmap_map[1].prot_mask = SRMMU_CACHE;
+	    par->mmap_map[1].prot_flag = SRMMU_WRITE;
+#endif /* __sparc__ */
+
+	return 0;
+}
+
+int __init igafb_setup(char *options)
+{
+    char *this_opt;
+
+    if (!options || !*options)
+        return 0;
+
+    while ((this_opt = strsep(&options, ",")) != NULL) {
+    }
+    return 0;
+}
+
+module_init(igafb_init);
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c
new file mode 100644
index 0000000..5a72ca3
--- /dev/null
+++ b/drivers/video/imsttfb.c
@@ -0,0 +1,1626 @@
+/*
+ *  drivers/video/imsttfb.c -- frame buffer device for IMS TwinTurbo
+ *
+ *  This file is derived from the powermac console "imstt" driver:
+ *  Copyright (C) 1997 Sigurdur Asgeirsson
+ *  With additional hacking by Jeffrey Kuskin (jsk@mojave.stanford.edu)
+ *  Modified by Danilo Beuche 1998
+ *  Some register values added by Damien Doligez, INRIA Rocquencourt
+ *  Various cleanups by Paul Mundt (lethal@chaoticdreams.org)
+ *
+ *  This file was written by Ryan Nielsen (ran@krazynet.com)
+ *  Most of the frame buffer device stuff was copied from atyfb.c
+ *
+ *  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 <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#if defined(CONFIG_PPC)
+#include <linux/nvram.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include "macmodes.h"
+#endif
+
+#ifndef __powerpc__
+#define eieio()		/* Enforce In-order Execution of I/O */
+#endif
+
+/* TwinTurbo (Cosmo) registers */
+enum {
+	S1SA	=  0, /* 0x00 */
+	S2SA	=  1, /* 0x04 */
+	SP	=  2, /* 0x08 */
+	DSA	=  3, /* 0x0C */
+	CNT	=  4, /* 0x10 */
+	DP_OCTL	=  5, /* 0x14 */
+	CLR	=  6, /* 0x18 */
+	BI	=  8, /* 0x20 */
+	MBC	=  9, /* 0x24 */
+	BLTCTL	= 10, /* 0x28 */
+
+	/* Scan Timing Generator Registers */
+	HES	= 12, /* 0x30 */
+	HEB	= 13, /* 0x34 */
+	HSB	= 14, /* 0x38 */
+	HT	= 15, /* 0x3C */
+	VES	= 16, /* 0x40 */
+	VEB	= 17, /* 0x44 */
+	VSB	= 18, /* 0x48 */
+	VT	= 19, /* 0x4C */
+	HCIV	= 20, /* 0x50 */
+	VCIV	= 21, /* 0x54 */
+	TCDR	= 22, /* 0x58 */
+	VIL	= 23, /* 0x5C */
+	STGCTL	= 24, /* 0x60 */
+
+	/* Screen Refresh Generator Registers */
+	SSR	= 25, /* 0x64 */
+	HRIR	= 26, /* 0x68 */
+	SPR	= 27, /* 0x6C */
+	CMR	= 28, /* 0x70 */
+	SRGCTL	= 29, /* 0x74 */
+
+	/* RAM Refresh Generator Registers */
+	RRCIV	= 30, /* 0x78 */
+	RRSC	= 31, /* 0x7C */
+	RRCR	= 34, /* 0x88 */
+
+	/* System Registers */
+	GIOE	= 32, /* 0x80 */
+	GIO	= 33, /* 0x84 */
+	SCR	= 35, /* 0x8C */
+	SSTATUS	= 36, /* 0x90 */
+	PRC	= 37, /* 0x94 */
+
+#if 0	
+	/* PCI Registers */
+	DVID	= 0x00000000L,
+	SC	= 0x00000004L,
+	CCR	= 0x00000008L,
+	OG	= 0x0000000CL,
+	BARM	= 0x00000010L,
+	BARER	= 0x00000030L,
+#endif
+};
+
+/* IBM 624 RAMDAC Direct Registers */
+enum {
+	PADDRW	= 0x00,
+	PDATA	= 0x04,
+	PPMASK	= 0x08,
+	PADDRR	= 0x0c,
+	PIDXLO	= 0x10,	
+	PIDXHI	= 0x14,	
+	PIDXDATA= 0x18,
+	PIDXCTL	= 0x1c
+};
+
+/* IBM 624 RAMDAC Indirect Registers */
+enum {
+	CLKCTL		= 0x02,	/* (0x01) Miscellaneous Clock Control */
+	SYNCCTL		= 0x03,	/* (0x00) Sync Control */
+	HSYNCPOS	= 0x04,	/* (0x00) Horizontal Sync Position */
+	PWRMNGMT	= 0x05,	/* (0x00) Power Management */
+	DACOP		= 0x06,	/* (0x02) DAC Operation */
+	PALETCTL	= 0x07,	/* (0x00) Palette Control */
+	SYSCLKCTL	= 0x08,	/* (0x01) System Clock Control */
+	PIXFMT		= 0x0a,	/* () Pixel Format  [bpp >> 3 + 2] */
+	BPP8		= 0x0b,	/* () 8 Bits/Pixel Control */
+	BPP16		= 0x0c, /* () 16 Bits/Pixel Control  [bit 1=1 for 565] */
+	BPP24		= 0x0d,	/* () 24 Bits/Pixel Control */
+	BPP32		= 0x0e,	/* () 32 Bits/Pixel Control */
+	PIXCTL1		= 0x10, /* (0x05) Pixel PLL Control 1 */
+	PIXCTL2		= 0x11,	/* (0x00) Pixel PLL Control 2 */
+	SYSCLKN		= 0x15,	/* () System Clock N (System PLL Reference Divider) */
+	SYSCLKM		= 0x16,	/* () System Clock M (System PLL VCO Divider) */
+	SYSCLKP		= 0x17,	/* () System Clock P */
+	SYSCLKC		= 0x18,	/* () System Clock C */
+	/*
+	 * Dot clock rate is 20MHz * (m + 1) / ((n + 1) * (p ? 2 * p : 1)
+	 * c is charge pump bias which depends on the VCO frequency  
+	 */
+	PIXM0		= 0x20,	/* () Pixel M 0 */
+	PIXN0		= 0x21,	/* () Pixel N 0 */
+	PIXP0		= 0x22,	/* () Pixel P 0 */
+	PIXC0		= 0x23,	/* () Pixel C 0 */
+	CURSCTL		= 0x30,	/* (0x00) Cursor Control */
+	CURSXLO		= 0x31,	/* () Cursor X position, low 8 bits */
+	CURSXHI		= 0x32,	/* () Cursor X position, high 8 bits */
+	CURSYLO		= 0x33,	/* () Cursor Y position, low 8 bits */
+	CURSYHI		= 0x34,	/* () Cursor Y position, high 8 bits */
+	CURSHOTX	= 0x35,	/* () Cursor Hot Spot X */
+	CURSHOTY	= 0x36,	/* () Cursor Hot Spot Y */
+	CURSACCTL	= 0x37,	/* () Advanced Cursor Control Enable */
+	CURSACATTR	= 0x38,	/* () Advanced Cursor Attribute */
+	CURS1R		= 0x40,	/* () Cursor 1 Red */
+	CURS1G		= 0x41,	/* () Cursor 1 Green */
+	CURS1B		= 0x42,	/* () Cursor 1 Blue */
+	CURS2R		= 0x43,	/* () Cursor 2 Red */
+	CURS2G		= 0x44,	/* () Cursor 2 Green */
+	CURS2B		= 0x45,	/* () Cursor 2 Blue */
+	CURS3R		= 0x46,	/* () Cursor 3 Red */
+	CURS3G		= 0x47,	/* () Cursor 3 Green */
+	CURS3B		= 0x48,	/* () Cursor 3 Blue */
+	BORDR		= 0x60,	/* () Border Color Red */
+	BORDG		= 0x61,	/* () Border Color Green */
+	BORDB		= 0x62,	/* () Border Color Blue */
+	MISCTL1		= 0x70,	/* (0x00) Miscellaneous Control 1 */
+	MISCTL2		= 0x71,	/* (0x00) Miscellaneous Control 2 */
+	MISCTL3		= 0x72,	/* (0x00) Miscellaneous Control 3 */
+	KEYCTL		= 0x78	/* (0x00) Key Control/DB Operation */
+};
+
+/* TI TVP 3030 RAMDAC Direct Registers */
+enum {
+	TVPADDRW = 0x00,	/* 0  Palette/Cursor RAM Write Address/Index */
+	TVPPDATA = 0x04,	/* 1  Palette Data RAM Data */
+	TVPPMASK = 0x08,	/* 2  Pixel Read-Mask */
+	TVPPADRR = 0x0c,	/* 3  Palette/Cursor RAM Read Address */
+	TVPCADRW = 0x10,	/* 4  Cursor/Overscan Color Write Address */
+	TVPCDATA = 0x14,	/* 5  Cursor/Overscan Color Data */
+				/* 6  reserved */
+	TVPCADRR = 0x1c,	/* 7  Cursor/Overscan Color Read Address */
+				/* 8  reserved */
+	TVPDCCTL = 0x24,	/* 9  Direct Cursor Control */
+	TVPIDATA = 0x28,	/* 10 Index Data */
+	TVPCRDAT = 0x2c,	/* 11 Cursor RAM Data */
+	TVPCXPOL = 0x30,	/* 12 Cursor-Position X LSB */
+	TVPCXPOH = 0x34,	/* 13 Cursor-Position X MSB */
+	TVPCYPOL = 0x38,	/* 14 Cursor-Position Y LSB */
+	TVPCYPOH = 0x3c,	/* 15 Cursor-Position Y MSB */
+};
+
+/* TI TVP 3030 RAMDAC Indirect Registers */
+enum {
+	TVPIRREV = 0x01,	/* Silicon Revision [RO] */
+	TVPIRICC = 0x06,	/* Indirect Cursor Control 	(0x00) */
+	TVPIRBRC = 0x07,	/* Byte Router Control 	(0xe4) */
+	TVPIRLAC = 0x0f,	/* Latch Control 		(0x06) */
+	TVPIRTCC = 0x18,	/* True Color Control  	(0x80) */
+	TVPIRMXC = 0x19,	/* Multiplex Control		(0x98) */
+	TVPIRCLS = 0x1a,	/* Clock Selection		(0x07) */
+	TVPIRPPG = 0x1c,	/* Palette Page		(0x00) */
+	TVPIRGEC = 0x1d,	/* General Control 		(0x00) */
+	TVPIRMIC = 0x1e,	/* Miscellaneous Control	(0x00) */
+	TVPIRPLA = 0x2c,	/* PLL Address */
+	TVPIRPPD = 0x2d,	/* Pixel Clock PLL Data */
+	TVPIRMPD = 0x2e,	/* Memory Clock PLL Data */
+	TVPIRLPD = 0x2f,	/* Loop Clock PLL Data */
+	TVPIRCKL = 0x30,	/* Color-Key Overlay Low */
+	TVPIRCKH = 0x31,	/* Color-Key Overlay High */
+	TVPIRCRL = 0x32,	/* Color-Key Red Low */
+	TVPIRCRH = 0x33,	/* Color-Key Red High */
+	TVPIRCGL = 0x34,	/* Color-Key Green Low */
+	TVPIRCGH = 0x35,	/* Color-Key Green High */
+	TVPIRCBL = 0x36,	/* Color-Key Blue Low */
+	TVPIRCBH = 0x37,	/* Color-Key Blue High */
+	TVPIRCKC = 0x38,	/* Color-Key Control 		(0x00) */
+	TVPIRMLC = 0x39,	/* MCLK/Loop Clock Control	(0x18) */
+	TVPIRSEN = 0x3a,	/* Sense Test			(0x00) */
+	TVPIRTMD = 0x3b,	/* Test Mode Data */
+	TVPIRRML = 0x3c,	/* CRC Remainder LSB [RO] */
+	TVPIRRMM = 0x3d,	/* CRC Remainder MSB [RO] */
+	TVPIRRMS = 0x3e,	/* CRC  Bit Select [WO] */
+	TVPIRDID = 0x3f,	/* Device ID [RO] 		(0x30) */
+	TVPIRRES = 0xff		/* Software Reset [WO] */
+};
+
+struct initvalues {
+	__u8 addr, value;
+};
+
+static struct initvalues ibm_initregs[] __devinitdata = {
+	{ CLKCTL,	0x21 },
+	{ SYNCCTL,	0x00 },
+	{ HSYNCPOS,	0x00 },
+	{ PWRMNGMT,	0x00 },
+	{ DACOP,	0x02 },
+	{ PALETCTL,	0x00 },
+	{ SYSCLKCTL,	0x01 },
+
+	/*
+	 * Note that colors in X are correct only if all video data is
+	 * passed through the palette in the DAC.  That is, "indirect
+	 * color" must be configured.  This is the case for the IBM DAC
+	 * used in the 2MB and 4MB cards, at least.
+	 */
+	{ BPP8,		0x00 },
+	{ BPP16,	0x01 },
+	{ BPP24,	0x00 },
+	{ BPP32,	0x00 },
+
+	{ PIXCTL1,	0x05 },
+	{ PIXCTL2,	0x00 },
+	{ SYSCLKN,	0x08 },
+	{ SYSCLKM,	0x4f },
+	{ SYSCLKP,	0x00 },
+	{ SYSCLKC,	0x00 },
+	{ CURSCTL,	0x00 },
+	{ CURSACCTL,	0x01 },
+	{ CURSACATTR,	0xa8 },
+	{ CURS1R,	0xff },
+	{ CURS1G,	0xff },
+	{ CURS1B,	0xff },
+	{ CURS2R,	0xff },
+	{ CURS2G,	0xff },
+	{ CURS2B,	0xff },
+	{ CURS3R,	0xff },
+	{ CURS3G,	0xff },
+	{ CURS3B,	0xff },
+	{ BORDR,	0xff },
+	{ BORDG,	0xff },
+	{ BORDB,	0xff },
+	{ MISCTL1,	0x01 },
+	{ MISCTL2,	0x45 },
+	{ MISCTL3,	0x00 },
+	{ KEYCTL,	0x00 }
+};
+
+static struct initvalues tvp_initregs[] __devinitdata = {
+	{ TVPIRICC,	0x00 },
+	{ TVPIRBRC,	0xe4 },
+	{ TVPIRLAC,	0x06 },
+	{ TVPIRTCC,	0x80 },
+	{ TVPIRMXC,	0x4d },
+	{ TVPIRCLS,	0x05 },
+	{ TVPIRPPG,	0x00 },
+	{ TVPIRGEC,	0x00 },
+	{ TVPIRMIC,	0x08 },
+	{ TVPIRCKL,	0xff },
+	{ TVPIRCKH,	0xff },
+	{ TVPIRCRL,	0xff },
+	{ TVPIRCRH,	0xff },
+	{ TVPIRCGL,	0xff },
+	{ TVPIRCGH,	0xff },
+	{ TVPIRCBL,	0xff },
+	{ TVPIRCBH,	0xff },
+	{ TVPIRCKC,	0x00 },
+	{ TVPIRPLA,	0x00 },
+	{ TVPIRPPD,	0xc0 },
+	{ TVPIRPPD,	0xd5 },
+	{ TVPIRPPD,	0xea },
+	{ TVPIRPLA,	0x00 },
+	{ TVPIRMPD,	0xb9 },
+	{ TVPIRMPD,	0x3a },
+	{ TVPIRMPD,	0xb1 },
+	{ TVPIRPLA,	0x00 },
+	{ TVPIRLPD,	0xc1 },
+	{ TVPIRLPD,	0x3d },
+	{ TVPIRLPD,	0xf3 },
+};
+
+struct imstt_regvals {
+	__u32 pitch;
+	__u16 hes, heb, hsb, ht, ves, veb, vsb, vt, vil;
+	__u8 pclk_m, pclk_n, pclk_p;
+	/* Values of the tvp which change depending on colormode x resolution */
+	__u8 mlc[3];	/* Memory Loop Config 0x39 */
+	__u8 lckl_p[3];	/* P value of LCKL PLL */
+};
+
+struct imstt_par {
+	struct imstt_regvals init;
+	__u32 __iomem *dc_regs;
+	unsigned long cmap_regs_phys;
+	__u8 *cmap_regs;
+	__u32 ramdac;
+};
+ 
+enum {
+	IBM = 0,
+	TVP = 1
+};
+
+#define USE_NV_MODES		1
+#define INIT_BPP		8
+#define INIT_XRES		640
+#define INIT_YRES		480
+
+static int inverse = 0;
+static char fontname[40] __initdata = { 0 };
+#if defined(CONFIG_PPC)
+static signed char init_vmode __devinitdata = -1, init_cmode __devinitdata = -1;
+#endif
+
+static struct imstt_regvals tvp_reg_init_2 = {
+	512,
+	0x0002, 0x0006, 0x0026, 0x0028, 0x0003, 0x0016, 0x0196, 0x0197, 0x0196,
+	0xec, 0x2a, 0xf3,
+	{ 0x3c, 0x3b, 0x39 }, { 0xf3, 0xf3, 0xf3 }
+};
+
+static struct imstt_regvals tvp_reg_init_6 = {
+	640,
+	0x0004, 0x0009, 0x0031, 0x0036, 0x0003, 0x002a, 0x020a, 0x020d, 0x020a,
+	0xef, 0x2e, 0xb2,
+	{ 0x39, 0x39, 0x38 }, { 0xf3, 0xf3, 0xf3 }
+};
+
+static struct imstt_regvals tvp_reg_init_12 = {
+	800,
+	0x0005, 0x000e, 0x0040, 0x0042, 0x0003, 0x018, 0x270, 0x271, 0x270,
+	0xf6, 0x2e, 0xf2,
+	{ 0x3a, 0x39, 0x38 }, { 0xf3, 0xf3, 0xf3 }
+};
+
+static struct imstt_regvals tvp_reg_init_13 = {
+	832,
+	0x0004, 0x0011, 0x0045, 0x0048, 0x0003, 0x002a, 0x029a, 0x029b, 0x0000,
+	0xfe, 0x3e, 0xf1,
+	{ 0x39, 0x38, 0x38 }, { 0xf3, 0xf3, 0xf2 }
+};
+
+static struct imstt_regvals tvp_reg_init_17 = {
+	1024,
+	0x0006, 0x0210, 0x0250, 0x0053, 0x1003, 0x0021, 0x0321, 0x0324, 0x0000,
+	0xfc, 0x3a, 0xf1,
+	{ 0x39, 0x38, 0x38 }, { 0xf3, 0xf3, 0xf2 }
+};
+
+static struct imstt_regvals tvp_reg_init_18 = {
+	1152,
+  	0x0009, 0x0011, 0x059, 0x5b, 0x0003, 0x0031, 0x0397, 0x039a, 0x0000, 
+	0xfd, 0x3a, 0xf1,
+	{ 0x39, 0x38, 0x38 }, { 0xf3, 0xf3, 0xf2 }
+};
+
+static struct imstt_regvals tvp_reg_init_19 = {
+	1280,
+	0x0009, 0x0016, 0x0066, 0x0069, 0x0003, 0x0027, 0x03e7, 0x03e8, 0x03e7,
+	0xf7, 0x36, 0xf0,
+	{ 0x38, 0x38, 0x38 }, { 0xf3, 0xf2, 0xf1 }
+};
+
+static struct imstt_regvals tvp_reg_init_20 = {
+	1280,
+	0x0009, 0x0018, 0x0068, 0x006a, 0x0003, 0x0029, 0x0429, 0x042a, 0x0000,
+	0xf0, 0x2d, 0xf0,
+	{ 0x38, 0x38, 0x38 }, { 0xf3, 0xf2, 0xf1 }
+};
+
+/*
+ * PCI driver prototypes
+ */
+static int imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
+static void imsttfb_remove(struct pci_dev *pdev);
+
+/*
+ * Register access
+ */
+static inline u32 read_reg_le32(volatile u32 __iomem *base, int regindex)
+{
+#ifdef __powerpc__
+	return in_le32(base + regindex);
+#else
+	return readl(base + regindex);
+#endif
+}
+
+static inline void write_reg_le32(volatile u32 __iomem *base, int regindex, u32 val)
+{
+#ifdef __powerpc__
+	out_le32(base + regindex, val);
+#else
+	writel(val, base + regindex);
+#endif
+}
+
+static __u32
+getclkMHz(struct imstt_par *par)
+{
+	__u32 clk_m, clk_n, clk_p;
+
+	clk_m = par->init.pclk_m;
+	clk_n = par->init.pclk_n;
+	clk_p = par->init.pclk_p;
+
+	return 20 * (clk_m + 1) / ((clk_n + 1) * (clk_p ? 2 * clk_p : 1));
+}
+
+static void
+setclkMHz(struct imstt_par *par, __u32 MHz)
+{
+	__u32 clk_m, clk_n, clk_p, x, stage, spilled;
+
+	clk_m = clk_n = clk_p = 0;
+	stage = spilled = 0;
+	for (;;) {
+		switch (stage) {
+			case 0:
+				clk_m++;
+				break;
+			case 1:
+				clk_n++;
+				break;
+		}
+		x = 20 * (clk_m + 1) / ((clk_n + 1) * (clk_p ? 2 * clk_p : 1));
+		if (x == MHz)
+			break;
+		if (x > MHz) {
+			spilled = 1;
+			stage = 1;
+		} else if (spilled && x < MHz) {
+			stage = 0;
+		}
+	}
+
+	par->init.pclk_m = clk_m;
+	par->init.pclk_n = clk_n;
+	par->init.pclk_p = clk_p;
+}
+
+static struct imstt_regvals *
+compute_imstt_regvals_ibm(struct imstt_par *par, int xres, int yres)
+{
+	struct imstt_regvals *init = &par->init;
+	__u32 MHz, hes, heb, veb, htp, vtp;
+
+	switch (xres) {
+		case 640:
+			hes = 0x0008; heb = 0x0012; veb = 0x002a; htp = 10; vtp = 2;
+			MHz = 30 /* .25 */ ;
+			break;
+		case 832:
+			hes = 0x0005; heb = 0x0020; veb = 0x0028; htp = 8; vtp = 3;
+			MHz = 57 /* .27_ */ ;
+			break;
+		case 1024:
+			hes = 0x000a; heb = 0x001c; veb = 0x0020; htp = 8; vtp = 3;
+			MHz = 80;
+			break;
+		case 1152:
+			hes = 0x0012; heb = 0x0022; veb = 0x0031; htp = 4; vtp = 3;
+			MHz = 101 /* .6_ */ ;
+			break;
+		case 1280:
+			hes = 0x0012; heb = 0x002f; veb = 0x0029; htp = 4; vtp = 1;
+			MHz = yres == 960 ? 126 : 135;
+			break;
+		case 1600:
+			hes = 0x0018; heb = 0x0040; veb = 0x002a; htp = 4; vtp = 3;
+			MHz = 200;
+			break;
+		default:
+			return NULL;
+	}
+
+	setclkMHz(par, MHz);
+
+	init->hes = hes;
+	init->heb = heb;
+	init->hsb = init->heb + (xres >> 3);
+	init->ht = init->hsb + htp;
+	init->ves = 0x0003;
+	init->veb = veb;
+	init->vsb = init->veb + yres;
+	init->vt = init->vsb + vtp;
+	init->vil = init->vsb;
+
+	init->pitch = xres;
+	return init;
+}
+
+static struct imstt_regvals *
+compute_imstt_regvals_tvp(struct imstt_par *par, int xres, int yres)
+{
+	struct imstt_regvals *init;
+
+	switch (xres) {
+		case 512:
+			init = &tvp_reg_init_2;
+			break;
+		case 640:
+			init = &tvp_reg_init_6;
+			break;
+		case 800:
+			init = &tvp_reg_init_12;
+			break;
+		case 832:
+			init = &tvp_reg_init_13;
+			break;
+		case 1024:
+			init = &tvp_reg_init_17;
+			break;
+		case 1152:
+			init = &tvp_reg_init_18;
+			break;
+		case 1280:
+			init = yres == 960 ? &tvp_reg_init_19 : &tvp_reg_init_20;
+			break;
+		default:
+			return NULL;
+	}
+	par->init = *init;
+	return init;
+}
+
+static struct imstt_regvals *
+compute_imstt_regvals (struct imstt_par *par, u_int xres, u_int yres)
+{
+	if (par->ramdac == IBM)
+		return compute_imstt_regvals_ibm(par, xres, yres);
+	else
+		return compute_imstt_regvals_tvp(par, xres, yres);
+}
+
+static void
+set_imstt_regvals_ibm (struct imstt_par *par, u_int bpp)
+{
+	struct imstt_regvals *init = &par->init;
+	__u8 pformat = (bpp >> 3) + 2;
+
+	par->cmap_regs[PIDXHI] = 0;		eieio();
+	par->cmap_regs[PIDXLO] = PIXM0;		eieio();
+	par->cmap_regs[PIDXDATA] = init->pclk_m;eieio();
+	par->cmap_regs[PIDXLO] = PIXN0;		eieio();
+	par->cmap_regs[PIDXDATA] = init->pclk_n;eieio();
+	par->cmap_regs[PIDXLO] = PIXP0;		eieio();
+	par->cmap_regs[PIDXDATA] = init->pclk_p;eieio();
+	par->cmap_regs[PIDXLO] = PIXC0;		eieio();
+	par->cmap_regs[PIDXDATA] = 0x02;	eieio();
+
+	par->cmap_regs[PIDXLO] = PIXFMT;	eieio();
+	par->cmap_regs[PIDXDATA] = pformat;	eieio();
+}
+
+static void
+set_imstt_regvals_tvp (struct imstt_par *par, u_int bpp)
+{
+	struct imstt_regvals *init = &par->init;
+	__u8 tcc, mxc, lckl_n, mic;
+	__u8 mlc, lckl_p;
+
+	switch (bpp) {
+		default:
+		case 8:
+			tcc = 0x80;
+			mxc = 0x4d;
+			lckl_n = 0xc1;
+			mlc = init->mlc[0];
+			lckl_p = init->lckl_p[0];
+			break;
+		case 16:
+			tcc = 0x44;
+			mxc = 0x55;
+			lckl_n = 0xe1;
+			mlc = init->mlc[1];
+			lckl_p = init->lckl_p[1];
+			break;
+		case 24:
+			tcc = 0x5e;
+			mxc = 0x5d;
+			lckl_n = 0xf1;
+			mlc = init->mlc[2];
+			lckl_p = init->lckl_p[2];
+			break;
+		case 32:
+			tcc = 0x46;
+			mxc = 0x5d;
+			lckl_n = 0xf1;
+			mlc = init->mlc[2];
+			lckl_p = init->lckl_p[2];
+			break;
+	}
+	mic = 0x08;
+
+	par->cmap_regs[TVPADDRW] = TVPIRPLA;		eieio();
+	par->cmap_regs[TVPIDATA] = 0x00;		eieio();
+	par->cmap_regs[TVPADDRW] = TVPIRPPD;		eieio();
+	par->cmap_regs[TVPIDATA] = init->pclk_m;	eieio();
+	par->cmap_regs[TVPADDRW] = TVPIRPPD;		eieio();
+	par->cmap_regs[TVPIDATA] = init->pclk_n;	eieio();
+	par->cmap_regs[TVPADDRW] = TVPIRPPD;		eieio();
+	par->cmap_regs[TVPIDATA] = init->pclk_p;	eieio();
+
+	par->cmap_regs[TVPADDRW] = TVPIRTCC;		eieio();
+	par->cmap_regs[TVPIDATA] = tcc;			eieio();
+	par->cmap_regs[TVPADDRW] = TVPIRMXC;		eieio();
+	par->cmap_regs[TVPIDATA] = mxc;			eieio();
+	par->cmap_regs[TVPADDRW] = TVPIRMIC;		eieio();
+	par->cmap_regs[TVPIDATA] = mic;			eieio();
+
+	par->cmap_regs[TVPADDRW] = TVPIRPLA;		eieio();
+	par->cmap_regs[TVPIDATA] = 0x00;		eieio();
+	par->cmap_regs[TVPADDRW] = TVPIRLPD;		eieio();
+	par->cmap_regs[TVPIDATA] = lckl_n;		eieio();
+
+	par->cmap_regs[TVPADDRW] = TVPIRPLA;		eieio();
+	par->cmap_regs[TVPIDATA] = 0x15;		eieio();
+	par->cmap_regs[TVPADDRW] = TVPIRMLC;		eieio();
+	par->cmap_regs[TVPIDATA] = mlc;			eieio();
+
+	par->cmap_regs[TVPADDRW] = TVPIRPLA;		eieio();
+	par->cmap_regs[TVPIDATA] = 0x2a;		eieio();
+	par->cmap_regs[TVPADDRW] = TVPIRLPD;		eieio();
+	par->cmap_regs[TVPIDATA] = lckl_p;		eieio();
+}
+
+static void
+set_imstt_regvals (struct fb_info *info, u_int bpp)
+{
+	struct imstt_par *par = (struct imstt_par *) info->par;
+	struct imstt_regvals *init = &par->init;
+	__u32 ctl, pitch, byteswap, scr;
+
+	if (par->ramdac == IBM)
+		set_imstt_regvals_ibm(par, bpp);
+	else
+		set_imstt_regvals_tvp(par, bpp);
+
+  /*
+   * From what I (jsk) can gather poking around with MacsBug,
+   * bits 8 and 9 in the SCR register control endianness
+   * correction (byte swapping).  These bits must be set according
+   * to the color depth as follows:
+   *     Color depth    Bit 9   Bit 8
+   *     ==========     =====   =====
+   *        8bpp          0       0
+   *       16bpp          0       1
+   *       32bpp          1       1
+   */
+	switch (bpp) {
+		default:
+		case 8:
+			ctl = 0x17b1;
+			pitch = init->pitch >> 2;
+			byteswap = 0x000;
+			break;
+		case 16:
+			ctl = 0x17b3;
+			pitch = init->pitch >> 1;
+			byteswap = 0x100;
+			break;
+		case 24:
+			ctl = 0x17b9;
+			pitch = init->pitch - (init->pitch >> 2);
+			byteswap = 0x200;
+			break;
+		case 32:
+			ctl = 0x17b5;
+			pitch = init->pitch;
+			byteswap = 0x300;
+			break;
+	}
+	if (par->ramdac == TVP)
+		ctl -= 0x30;
+
+	write_reg_le32(par->dc_regs, HES, init->hes);
+	write_reg_le32(par->dc_regs, HEB, init->heb);
+	write_reg_le32(par->dc_regs, HSB, init->hsb);
+	write_reg_le32(par->dc_regs, HT, init->ht);
+	write_reg_le32(par->dc_regs, VES, init->ves);
+	write_reg_le32(par->dc_regs, VEB, init->veb);
+	write_reg_le32(par->dc_regs, VSB, init->vsb);
+	write_reg_le32(par->dc_regs, VT, init->vt);
+	write_reg_le32(par->dc_regs, VIL, init->vil);
+	write_reg_le32(par->dc_regs, HCIV, 1);
+	write_reg_le32(par->dc_regs, VCIV, 1);
+	write_reg_le32(par->dc_regs, TCDR, 4);
+	write_reg_le32(par->dc_regs, RRCIV, 1);
+	write_reg_le32(par->dc_regs, RRSC, 0x980);
+	write_reg_le32(par->dc_regs, RRCR, 0x11);
+
+	if (par->ramdac == IBM) {
+		write_reg_le32(par->dc_regs, HRIR, 0x0100);
+		write_reg_le32(par->dc_regs, CMR, 0x00ff);
+		write_reg_le32(par->dc_regs, SRGCTL, 0x0073);
+	} else {
+		write_reg_le32(par->dc_regs, HRIR, 0x0200);
+		write_reg_le32(par->dc_regs, CMR, 0x01ff);
+		write_reg_le32(par->dc_regs, SRGCTL, 0x0003);
+	}
+
+	switch (info->fix.smem_len) {
+		case 0x200000:
+			scr = 0x059d | byteswap;
+			break;
+		/* case 0x400000:
+		   case 0x800000: */
+		default:
+			pitch >>= 1;
+			scr = 0x150dd | byteswap;
+			break;
+	}
+
+	write_reg_le32(par->dc_regs, SCR, scr);
+	write_reg_le32(par->dc_regs, SPR, pitch);
+	write_reg_le32(par->dc_regs, STGCTL, ctl);
+}
+
+static inline void
+set_offset (struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct imstt_par *par = (struct imstt_par *) info->par;
+	__u32 off = var->yoffset * (info->fix.line_length >> 3)
+		    + ((var->xoffset * (var->bits_per_pixel >> 3)) >> 3);
+	write_reg_le32(par->dc_regs, SSR, off);
+}
+
+static inline void
+set_555 (struct imstt_par *par)
+{
+	if (par->ramdac == IBM) {
+		par->cmap_regs[PIDXHI] = 0;		eieio();
+		par->cmap_regs[PIDXLO] = BPP16;		eieio();
+		par->cmap_regs[PIDXDATA] = 0x01;	eieio();
+	} else {
+		par->cmap_regs[TVPADDRW] = TVPIRTCC;	eieio();
+		par->cmap_regs[TVPIDATA] = 0x44;	eieio();
+	}
+}
+
+static inline void
+set_565 (struct imstt_par *par)
+{
+	if (par->ramdac == IBM) {
+		par->cmap_regs[PIDXHI] = 0;		eieio();
+		par->cmap_regs[PIDXLO] = BPP16;		eieio();
+		par->cmap_regs[PIDXDATA] = 0x03;	eieio();
+	} else {
+		par->cmap_regs[TVPADDRW] = TVPIRTCC;	eieio();
+		par->cmap_regs[TVPIDATA] = 0x45;	eieio();
+	}
+}
+
+static int
+imsttfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	if ((var->bits_per_pixel != 8 && var->bits_per_pixel != 16
+	    && var->bits_per_pixel != 24 && var->bits_per_pixel != 32)
+	    || var->xres_virtual < var->xres || var->yres_virtual < var->yres
+	    || var->nonstd
+	    || (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+		return -EINVAL;
+
+	if ((var->xres * var->yres) * (var->bits_per_pixel >> 3) > info->fix.smem_len
+	    || (var->xres_virtual * var->yres_virtual) * (var->bits_per_pixel >> 3) > info->fix.smem_len)
+		return -EINVAL;
+
+	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:	/* RGB 555 or 565 */
+			if (var->green.length != 6)
+				var->red.offset = 10;
+			var->red.length = 5;
+			var->green.offset = 5;
+			if (var->green.length != 6)
+				var->green.length = 5;
+			var->blue.offset = 0;
+			var->blue.length = 5;
+			var->transp.offset = 0;
+			var->transp.length = 0;
+			break;
+		case 24:	/* RGB 888 */
+			var->red.offset = 16;
+			var->red.length = 8;
+			var->green.offset = 8;
+			var->green.length = 8;
+			var->blue.offset = 0;
+			var->blue.length = 8;
+			var->transp.offset = 0;
+			var->transp.length = 0;
+			break;
+		case 32:	/* RGBA 8888 */
+			var->red.offset = 16;
+			var->red.length = 8;
+			var->green.offset = 8;
+			var->green.length = 8;
+			var->blue.offset = 0;
+			var->blue.length = 8;
+			var->transp.offset = 24;
+			var->transp.length = 8;
+			break;
+	}
+
+	if (var->yres == var->yres_virtual) {
+		__u32 vram = (info->fix.smem_len - (PAGE_SIZE << 2));
+		var->yres_virtual = ((vram << 3) / var->bits_per_pixel) / var->xres_virtual;
+		if (var->yres_virtual < var->yres)
+			var->yres_virtual = var->yres;
+	}
+
+	var->red.msb_right = 0;
+	var->green.msb_right = 0;
+	var->blue.msb_right = 0;
+	var->transp.msb_right = 0;
+	var->height = -1;
+	var->width = -1;
+	var->vmode = FB_VMODE_NONINTERLACED;
+	var->left_margin = var->right_margin = 16;
+	var->upper_margin = var->lower_margin = 16;
+	var->hsync_len = var->vsync_len = 8;
+	return 0;
+}
+
+static int
+imsttfb_set_par(struct fb_info *info) 
+{
+	struct imstt_par *par = (struct imstt_par *) info->par;
+		
+	if (!compute_imstt_regvals(par, info->var.xres, info->var.yres))
+		return -EINVAL;
+
+	if (info->var.green.length == 6)
+		set_565(par);
+	else
+		set_555(par);
+	set_imstt_regvals(info, info->var.bits_per_pixel);
+	info->var.pixclock = 1000000 / getclkMHz(par);
+	return 0;
+}
+
+static int
+imsttfb_setcolreg (u_int regno, u_int red, u_int green, u_int blue,
+		   u_int transp, struct fb_info *info)
+{
+	struct imstt_par *par = (struct imstt_par *) info->par;
+	u_int bpp = info->var.bits_per_pixel;
+
+	if (regno > 255)
+		return 1;
+
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	/* PADDRW/PDATA are the same as TVPPADDRW/TVPPDATA */
+	if (0 && bpp == 16)	/* screws up X */
+		par->cmap_regs[PADDRW] = regno << 3;
+	else
+		par->cmap_regs[PADDRW] = regno;
+	eieio();
+
+	par->cmap_regs[PDATA] = red;	eieio();
+	par->cmap_regs[PDATA] = green;	eieio();
+	par->cmap_regs[PDATA] = blue;	eieio();
+
+	if (regno < 16)
+		switch (bpp) {
+			case 16:
+				((u16 *)info->pseudo_palette)[regno] = (regno << (info->var.green.length == 5 ? 10 : 11)) | (regno << 5) | regno;
+				break;
+			case 24:
+				((u32 *)info->pseudo_palette)[regno] = (regno << 16) | (regno << 8) | regno;
+				break;
+			case 32: {
+				int i = (regno << 8) | regno;
+				((u32 *)info->pseudo_palette)[regno] = (i << 16) | i;
+				break;
+			}
+		}
+	return 0;
+}
+
+static int
+imsttfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	if (var->xoffset + info->var.xres > info->var.xres_virtual
+	    || var->yoffset + info->var.yres > info->var.yres_virtual)
+		return -EINVAL;
+
+	info->var.xoffset = var->xoffset;
+	info->var.yoffset = var->yoffset;
+	set_offset(var, info);
+	return 0;
+}
+
+static int 
+imsttfb_blank(int blank, struct fb_info *info)
+{
+	struct imstt_par *par = (struct imstt_par *) info->par;
+	__u32 ctrl;
+
+	ctrl = read_reg_le32(par->dc_regs, STGCTL);
+	if (blank > 0) {
+		switch (blank) {
+		case FB_BLANK_NORMAL:
+		case FB_BLANK_POWERDOWN:
+			ctrl &= ~0x00000380;
+			if (par->ramdac == IBM) {
+				par->cmap_regs[PIDXHI] = 0;		eieio();
+				par->cmap_regs[PIDXLO] = MISCTL2;	eieio();
+				par->cmap_regs[PIDXDATA] = 0x55;	eieio();
+				par->cmap_regs[PIDXLO] = MISCTL1;	eieio();
+				par->cmap_regs[PIDXDATA] = 0x11;	eieio();
+				par->cmap_regs[PIDXLO] = SYNCCTL;	eieio();
+				par->cmap_regs[PIDXDATA] = 0x0f;	eieio();
+				par->cmap_regs[PIDXLO] = PWRMNGMT;	eieio();
+				par->cmap_regs[PIDXDATA] = 0x1f;	eieio();
+				par->cmap_regs[PIDXLO] = CLKCTL;	eieio();
+				par->cmap_regs[PIDXDATA] = 0xc0;
+			}
+			break;
+		case FB_BLANK_VSYNC_SUSPEND:
+			ctrl &= ~0x00000020;
+			break;
+		case FB_BLANK_HSYNC_SUSPEND:
+			ctrl &= ~0x00000010;
+			break;
+		}
+	} else {
+		if (par->ramdac == IBM) {
+			ctrl |= 0x000017b0;
+			par->cmap_regs[PIDXHI] = 0;		eieio();
+			par->cmap_regs[PIDXLO] = CLKCTL;	eieio();
+			par->cmap_regs[PIDXDATA] = 0x01;	eieio();
+			par->cmap_regs[PIDXLO] = PWRMNGMT;	eieio();
+			par->cmap_regs[PIDXDATA] = 0x00;	eieio();
+			par->cmap_regs[PIDXLO] = SYNCCTL;	eieio();
+			par->cmap_regs[PIDXDATA] = 0x00;	eieio();
+			par->cmap_regs[PIDXLO] = MISCTL1;	eieio();
+			par->cmap_regs[PIDXDATA] = 0x01;	eieio();
+			par->cmap_regs[PIDXLO] = MISCTL2;	eieio();
+			par->cmap_regs[PIDXDATA] = 0x45;	eieio();
+		} else
+			ctrl |= 0x00001780;
+	}
+	write_reg_le32(par->dc_regs, STGCTL, ctrl);
+	return 0;
+}
+
+static void
+imsttfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{ 
+	struct imstt_par *par = (struct imstt_par *) info->par;
+	__u32 Bpp, line_pitch, bgc, dx, dy, width, height;
+
+	bgc = rect->color;
+	bgc |= (bgc << 8);
+	bgc |= (bgc << 16);
+
+	Bpp = info->var.bits_per_pixel >> 3,
+	line_pitch = info->fix.line_length;
+
+	dy = rect->dy * line_pitch;
+	dx = rect->dx * Bpp;
+	height = rect->height;
+	height--;
+	width = rect->width * Bpp;
+	width--;
+
+	if (rect->rop == ROP_COPY) {
+		while(read_reg_le32(par->dc_regs, SSTATUS) & 0x80);
+		write_reg_le32(par->dc_regs, DSA, dy + dx);
+		write_reg_le32(par->dc_regs, CNT, (height << 16) | width);
+		write_reg_le32(par->dc_regs, DP_OCTL, line_pitch);
+		write_reg_le32(par->dc_regs, BI, 0xffffffff);
+		write_reg_le32(par->dc_regs, MBC, 0xffffffff);
+		write_reg_le32(par->dc_regs, CLR, bgc);
+		write_reg_le32(par->dc_regs, BLTCTL, 0x840); /* 0x200000 */
+		while(read_reg_le32(par->dc_regs, SSTATUS) & 0x80);
+		while(read_reg_le32(par->dc_regs, SSTATUS) & 0x40);
+	} else {
+		while(read_reg_le32(par->dc_regs, SSTATUS) & 0x80);
+		write_reg_le32(par->dc_regs, DSA, dy + dx);
+		write_reg_le32(par->dc_regs, S1SA, dy + dx);
+		write_reg_le32(par->dc_regs, CNT, (height << 16) | width);
+		write_reg_le32(par->dc_regs, DP_OCTL, line_pitch);
+		write_reg_le32(par->dc_regs, SP, line_pitch);
+		write_reg_le32(par->dc_regs, BLTCTL, 0x40005);
+		while(read_reg_le32(par->dc_regs, SSTATUS) & 0x80);
+		while(read_reg_le32(par->dc_regs, SSTATUS) & 0x40);
+	}
+}
+
+static void
+imsttfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+	struct imstt_par *par = (struct imstt_par *) info->par;
+	__u32 Bpp, line_pitch, fb_offset_old, fb_offset_new, sp, dp_octl;
+ 	__u32 cnt, bltctl, sx, sy, dx, dy, height, width;
+
+	Bpp = info->var.bits_per_pixel >> 3,
+
+	sx = area->sx * Bpp;
+	sy = area->sy;
+	dx = area->dx * Bpp;
+	dy = area->dy;
+	height = area->height;
+	height--;
+	width = area->width * Bpp;
+	width--;
+
+	line_pitch = info->fix.line_length;
+	bltctl = 0x05;
+	sp = line_pitch << 16;
+	cnt = height << 16;
+
+	if (sy < dy) {
+		sy += height;
+		dy += height;
+		sp |= -(line_pitch) & 0xffff;
+		dp_octl = -(line_pitch) & 0xffff;
+	} else {
+		sp |= line_pitch;
+		dp_octl = line_pitch;
+	}
+	if (sx < dx) {
+		sx += width;
+		dx += width;
+		bltctl |= 0x80;
+		cnt |= -(width) & 0xffff;
+	} else {
+		cnt |= width;
+	}
+	fb_offset_old = sy * line_pitch + sx;
+	fb_offset_new = dy * line_pitch + dx;
+
+	while(read_reg_le32(par->dc_regs, SSTATUS) & 0x80);
+	write_reg_le32(par->dc_regs, S1SA, fb_offset_old);
+	write_reg_le32(par->dc_regs, SP, sp);
+	write_reg_le32(par->dc_regs, DSA, fb_offset_new);
+	write_reg_le32(par->dc_regs, CNT, cnt);
+	write_reg_le32(par->dc_regs, DP_OCTL, dp_octl);
+	write_reg_le32(par->dc_regs, BLTCTL, bltctl);
+	while(read_reg_le32(par->dc_regs, SSTATUS) & 0x80);
+	while(read_reg_le32(par->dc_regs, SSTATUS) & 0x40);
+}
+
+#if 0
+static int
+imsttfb_load_cursor_image(struct imstt_par *par, int width, int height, __u8 fgc)
+{
+	u_int x, y;
+
+	if (width > 32 || height > 32)
+		return -EINVAL;
+
+	if (par->ramdac == IBM) {
+		par->cmap_regs[PIDXHI] = 1;	eieio();
+		for (x = 0; x < 0x100; x++) {
+			par->cmap_regs[PIDXLO] = x;		eieio();
+			par->cmap_regs[PIDXDATA] = 0x00;	eieio();
+		}
+		par->cmap_regs[PIDXHI] = 1;	eieio();
+		for (y = 0; y < height; y++)
+			for (x = 0; x < width >> 2; x++) {
+				par->cmap_regs[PIDXLO] = x + y * 8;	eieio();
+				par->cmap_regs[PIDXDATA] = 0xff;	eieio();
+			}
+		par->cmap_regs[PIDXHI] = 0;		eieio();
+		par->cmap_regs[PIDXLO] = CURS1R;	eieio();
+		par->cmap_regs[PIDXDATA] = fgc;		eieio();
+		par->cmap_regs[PIDXLO] = CURS1G;	eieio();
+		par->cmap_regs[PIDXDATA] = fgc;		eieio();
+		par->cmap_regs[PIDXLO] = CURS1B;	eieio();
+		par->cmap_regs[PIDXDATA] = fgc;		eieio();
+		par->cmap_regs[PIDXLO] = CURS2R;	eieio();
+		par->cmap_regs[PIDXDATA] = fgc;		eieio();
+		par->cmap_regs[PIDXLO] = CURS2G;	eieio();
+		par->cmap_regs[PIDXDATA] = fgc;		eieio();
+		par->cmap_regs[PIDXLO] = CURS2B;	eieio();
+		par->cmap_regs[PIDXDATA] = fgc;		eieio();
+		par->cmap_regs[PIDXLO] = CURS3R;	eieio();
+		par->cmap_regs[PIDXDATA] = fgc;		eieio();
+		par->cmap_regs[PIDXLO] = CURS3G;	eieio();
+		par->cmap_regs[PIDXDATA] = fgc;		eieio();
+		par->cmap_regs[PIDXLO] = CURS3B;	eieio();
+		par->cmap_regs[PIDXDATA] = fgc;		eieio();
+	} else {
+		par->cmap_regs[TVPADDRW] = TVPIRICC;	eieio();
+		par->cmap_regs[TVPIDATA] &= 0x03;	eieio();
+		par->cmap_regs[TVPADDRW] = 0;		eieio();
+		for (x = 0; x < 0x200; x++) {
+			par->cmap_regs[TVPCRDAT] = 0x00;	eieio();
+		}
+		for (x = 0; x < 0x200; x++) {
+			par->cmap_regs[TVPCRDAT] = 0xff;	eieio();
+		}
+		par->cmap_regs[TVPADDRW] = TVPIRICC;	eieio();
+		par->cmap_regs[TVPIDATA] &= 0x03;	eieio();
+		for (y = 0; y < height; y++)
+			for (x = 0; x < width >> 3; x++) {
+				par->cmap_regs[TVPADDRW] = x + y * 8;	eieio();
+				par->cmap_regs[TVPCRDAT] = 0xff;		eieio();
+			}
+		par->cmap_regs[TVPADDRW] = TVPIRICC;	eieio();
+		par->cmap_regs[TVPIDATA] |= 0x08;	eieio();
+		for (y = 0; y < height; y++)
+			for (x = 0; x < width >> 3; x++) {
+				par->cmap_regs[TVPADDRW] = x + y * 8;	eieio();
+				par->cmap_regs[TVPCRDAT] = 0xff;		eieio();
+			}
+		par->cmap_regs[TVPCADRW] = 0x00;	eieio();
+		for (x = 0; x < 12; x++)
+			par->cmap_regs[TVPCDATA] = fgc;	eieio();
+	}
+	return 1;
+}
+
+static void
+imstt_set_cursor(struct imstt_par *par, struct fb_image *d, int on)
+{
+	if (par->ramdac == IBM) {
+		par->cmap_regs[PIDXHI] = 0;	eieio();
+		if (!on) {
+			par->cmap_regs[PIDXLO] = CURSCTL;	eieio();
+			par->cmap_regs[PIDXDATA] = 0x00;	eieio();
+		} else {
+			par->cmap_regs[PIDXLO] = CURSXHI;	eieio();
+			par->cmap_regs[PIDXDATA] = d->dx >> 8;	eieio();
+			par->cmap_regs[PIDXLO] = CURSXLO;	eieio();
+			par->cmap_regs[PIDXDATA] = d->dx & 0xff;eieio();
+			par->cmap_regs[PIDXLO] = CURSYHI;	eieio();
+			par->cmap_regs[PIDXDATA] = d->dy >> 8;	eieio();
+			par->cmap_regs[PIDXLO] = CURSYLO;	eieio();
+			par->cmap_regs[PIDXDATA] = d->dy & 0xff;eieio();
+			par->cmap_regs[PIDXLO] = CURSCTL;	eieio();
+			par->cmap_regs[PIDXDATA] = 0x02;	eieio();
+		}
+	} else {
+		if (!on) {
+			par->cmap_regs[TVPADDRW] = TVPIRICC;	eieio();
+			par->cmap_regs[TVPIDATA] = 0x00;	eieio();
+		} else {
+			__u16 x = d->dx + 0x40, y = d->dy + 0x40;
+
+			par->cmap_regs[TVPCXPOH] = x >> 8;	eieio();
+			par->cmap_regs[TVPCXPOL] = x & 0xff;	eieio();
+			par->cmap_regs[TVPCYPOH] = y >> 8;	eieio();
+			par->cmap_regs[TVPCYPOL] = y & 0xff;	eieio();
+			par->cmap_regs[TVPADDRW] = TVPIRICC;	eieio();
+			par->cmap_regs[TVPIDATA] = 0x02;	eieio();
+		}
+	}
+}
+
+static int 
+imsttfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+	struct imstt_par *par = (struct imstt_par *) info->par;
+        u32 flags = cursor->set, fg, bg, xx, yy;
+
+	if (cursor->dest == NULL && cursor->rop == ROP_XOR)
+		return 1;
+	
+	imstt_set_cursor(info, cursor, 0);
+
+	if (flags & FB_CUR_SETPOS) {
+		xx = cursor->image.dx - info->var.xoffset;
+		yy = cursor->image.dy - info->var.yoffset;
+	}
+
+	if (flags & FB_CUR_SETSIZE) {
+        }
+
+        if (flags & (FB_CUR_SETSHAPE | FB_CUR_SETCMAP)) {
+                int fg_idx = cursor->image.fg_color;
+                int width = (cursor->image.width+7)/8;
+                u8 *dat = (u8 *) cursor->image.data;
+                u8 *dst = (u8 *) cursor->dest;
+                u8 *msk = (u8 *) cursor->mask;
+
+                switch (cursor->rop) {
+                case ROP_XOR:
+                        for (i = 0; i < cursor->image.height; i++) {
+                                for (j = 0; j < width; j++) {
+                                        d_idx = i * MAX_CURS/8  + j;
+                                        data[d_idx] =  byte_rev[dat[s_idx] ^
+                                                                dst[s_idx]];
+                                        mask[d_idx] = byte_rev[msk[s_idx]];
+                                        s_idx++;
+                                }
+                        }
+                        break;
+                case ROP_COPY:
+                default:
+                        for (i = 0; i < cursor->image.height; i++) {
+                                for (j = 0; j < width; j++) {
+                                        d_idx = i * MAX_CURS/8 + j;
+                                        data[d_idx] = byte_rev[dat[s_idx]];
+                                        mask[d_idx] = byte_rev[msk[s_idx]];
+                                        s_idx++;
+                                }
+			}
+			break;
+		}
+
+		fg = ((info->cmap.red[fg_idx] & 0xf8) << 7) |
+                     ((info->cmap.green[fg_idx] & 0xf8) << 2) |
+                     ((info->cmap.blue[fg_idx] & 0xf8) >> 3) | 1 << 15;
+
+		imsttfb_load_cursor_image(par, xx, yy, fgc);
+	}
+	if (cursor->enable)
+		imstt_set_cursor(info, cursor, 1);
+	return 0;
+}
+#endif
+
+#define FBIMSTT_SETREG		0x545401
+#define FBIMSTT_GETREG		0x545402
+#define FBIMSTT_SETCMAPREG	0x545403
+#define FBIMSTT_GETCMAPREG	0x545404
+#define FBIMSTT_SETIDXREG	0x545405
+#define FBIMSTT_GETIDXREG	0x545406
+
+static int
+imsttfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+	      u_long arg, struct fb_info *info)
+{
+	struct imstt_par *par = (struct imstt_par *) info->par;
+	void __user *argp = (void __user *)arg;
+	__u32 reg[2];
+	__u8 idx[2];
+
+	switch (cmd) {
+		case FBIMSTT_SETREG:
+			if (copy_from_user(reg, argp, 8) || reg[0] > (0x1000 - sizeof(reg[0])) / sizeof(reg[0]))
+				return -EFAULT;
+			write_reg_le32(par->dc_regs, reg[0], reg[1]);
+			return 0;
+		case FBIMSTT_GETREG:
+			if (copy_from_user(reg, argp, 4) || reg[0] > (0x1000 - sizeof(reg[0])) / sizeof(reg[0]))
+				return -EFAULT;
+			reg[1] = read_reg_le32(par->dc_regs, reg[0]);
+			if (copy_to_user((void __user *)(arg + 4), &reg[1], 4))
+				return -EFAULT;
+			return 0;
+		case FBIMSTT_SETCMAPREG:
+			if (copy_from_user(reg, argp, 8) || reg[0] > (0x1000 - sizeof(reg[0])) / sizeof(reg[0]))
+				return -EFAULT;
+			write_reg_le32(((u_int *)par->cmap_regs), reg[0], reg[1]);
+			return 0;
+		case FBIMSTT_GETCMAPREG:
+			if (copy_from_user(reg, argp, 4) || reg[0] > (0x1000 - sizeof(reg[0])) / sizeof(reg[0]))
+				return -EFAULT;
+			reg[1] = read_reg_le32(((u_int *)par->cmap_regs), reg[0]);
+			if (copy_to_user((void __user *)(arg + 4), &reg[1], 4))
+				return -EFAULT;
+			return 0;
+		case FBIMSTT_SETIDXREG:
+			if (copy_from_user(idx, argp, 2))
+				return -EFAULT;
+			par->cmap_regs[PIDXHI] = 0;		eieio();
+			par->cmap_regs[PIDXLO] = idx[0];	eieio();
+			par->cmap_regs[PIDXDATA] = idx[1];	eieio();
+			return 0;
+		case FBIMSTT_GETIDXREG:
+			if (copy_from_user(idx, argp, 1))
+				return -EFAULT;
+			par->cmap_regs[PIDXHI] = 0;		eieio();
+			par->cmap_regs[PIDXLO] = idx[0];	eieio();
+			idx[1] = par->cmap_regs[PIDXDATA];
+			if (copy_to_user((void __user *)(arg + 1), &idx[1], 1))
+				return -EFAULT;
+			return 0;
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+
+static struct pci_device_id imsttfb_pci_tbl[] = {
+	{ PCI_VENDOR_ID_IMS, PCI_DEVICE_ID_IMS_TT128,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, IBM },
+	{ PCI_VENDOR_ID_IMS, PCI_DEVICE_ID_IMS_TT3D,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, TVP },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, imsttfb_pci_tbl);
+
+static struct pci_driver imsttfb_pci_driver = {
+	.name =		"imsttfb",
+	.id_table =	imsttfb_pci_tbl,
+	.probe =	imsttfb_probe,
+	.remove =	__devexit_p(imsttfb_remove),
+};
+
+static struct fb_ops imsttfb_ops = {
+	.owner 		= THIS_MODULE,
+	.fb_check_var	= imsttfb_check_var,
+	.fb_set_par 	= imsttfb_set_par,
+	.fb_setcolreg 	= imsttfb_setcolreg,
+	.fb_pan_display = imsttfb_pan_display,
+	.fb_blank 	= imsttfb_blank,
+	.fb_fillrect	= imsttfb_fillrect,
+	.fb_copyarea	= imsttfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+	.fb_ioctl 	= imsttfb_ioctl,
+};
+
+static void __devinit
+init_imstt(struct fb_info *info)
+{
+	struct imstt_par *par = (struct imstt_par *) info->par;
+	__u32 i, tmp, *ip, *end;
+
+	tmp = read_reg_le32(par->dc_regs, PRC);
+	if (par->ramdac == IBM)
+		info->fix.smem_len = (tmp & 0x0004) ? 0x400000 : 0x200000;
+	else
+		info->fix.smem_len = 0x800000;
+
+	ip = (__u32 *)info->screen_base;
+	end = (__u32 *)(info->screen_base + info->fix.smem_len);
+	while (ip < end)
+		*ip++ = 0;
+
+	/* initialize the card */
+	tmp = read_reg_le32(par->dc_regs, STGCTL);
+	write_reg_le32(par->dc_regs, STGCTL, tmp & ~0x1);
+	write_reg_le32(par->dc_regs, SSR, 0);
+
+	/* set default values for DAC registers */ 
+	if (par->ramdac == IBM) {
+		par->cmap_regs[PPMASK] = 0xff;	eieio();
+		par->cmap_regs[PIDXHI] = 0;	eieio();
+		for (i = 0; i < sizeof(ibm_initregs) / sizeof(*ibm_initregs); i++) {
+			par->cmap_regs[PIDXLO] = ibm_initregs[i].addr;	eieio();
+			par->cmap_regs[PIDXDATA] = ibm_initregs[i].value;	eieio();
+		}
+	} else {
+		for (i = 0; i < sizeof(tvp_initregs) / sizeof(*tvp_initregs); i++) {
+			par->cmap_regs[TVPADDRW] = tvp_initregs[i].addr;	eieio();
+			par->cmap_regs[TVPIDATA] = tvp_initregs[i].value;	eieio();
+		}
+	}
+
+#if USE_NV_MODES && defined(CONFIG_PPC)
+	{
+		int vmode = init_vmode, cmode = init_cmode;
+
+		if (vmode == -1) {
+			vmode = nvram_read_byte(NV_VMODE);
+			if (vmode <= 0 || vmode > VMODE_MAX)
+				vmode = VMODE_640_480_67;
+		}
+		if (cmode == -1) {
+			cmode = nvram_read_byte(NV_CMODE);
+			if (cmode < CMODE_8 || cmode > CMODE_32)
+				cmode = CMODE_8;
+		}
+		if (mac_vmode_to_var(vmode, cmode, &info->var)) {
+			info->var.xres = info->var.xres_virtual = INIT_XRES;
+			info->var.yres = info->var.yres_virtual = INIT_YRES;
+			info->var.bits_per_pixel = INIT_BPP;
+		}
+	}
+#else
+	info->var.xres = info->var.xres_virtual = INIT_XRES;
+	info->var.yres = info->var.yres_virtual = INIT_YRES;
+	info->var.bits_per_pixel = INIT_BPP;
+#endif
+
+	if ((info->var.xres * info->var.yres) * (info->var.bits_per_pixel >> 3) > info->fix.smem_len
+	    || !(compute_imstt_regvals(par, info->var.xres, info->var.yres))) {
+		printk("imsttfb: %ux%ux%u not supported\n", info->var.xres, info->var.yres, info->var.bits_per_pixel);
+		kfree(info);
+		return;
+	}
+
+	sprintf(info->fix.id, "IMS TT (%s)", par->ramdac == IBM ? "IBM" : "TVP");
+	info->fix.mmio_len = 0x1000;
+	info->fix.accel = FB_ACCEL_IMS_TWINTURBO;
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.visual = info->var.bits_per_pixel == 8 ? FB_VISUAL_PSEUDOCOLOR
+							: FB_VISUAL_DIRECTCOLOR;
+	info->fix.line_length = info->var.xres * (info->var.bits_per_pixel >> 3);
+	info->fix.xpanstep = 8;
+	info->fix.ypanstep = 1;
+	info->fix.ywrapstep = 0;
+
+	info->var.accel_flags = FB_ACCELF_TEXT;
+
+//	if (par->ramdac == IBM)
+//		imstt_cursor_init(info);
+	if (info->var.green.length == 6)
+		set_565(par);
+	else
+		set_555(par);
+	set_imstt_regvals(info, info->var.bits_per_pixel);
+
+	info->var.pixclock = 1000000 / getclkMHz(par);
+
+	info->fbops = &imsttfb_ops;
+	info->flags = FBINFO_DEFAULT |
+                      FBINFO_HWACCEL_COPYAREA |
+	              FBINFO_HWACCEL_FILLRECT |
+	              FBINFO_HWACCEL_YPAN;
+
+	fb_alloc_cmap(&info->cmap, 0, 0);
+
+	if (register_framebuffer(info) < 0) {
+		kfree(info);
+		return;
+	}
+
+	tmp = (read_reg_le32(par->dc_regs, SSTATUS) & 0x0f00) >> 8;
+	printk("fb%u: %s frame buffer; %uMB vram; chip version %u\n",
+		info->node, info->fix.id, info->fix.smem_len >> 20, tmp);
+}
+
+static int __devinit
+imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	unsigned long addr, size;
+	struct imstt_par *par;
+	struct fb_info *info;
+#ifdef CONFIG_PPC_OF
+	struct device_node *dp;
+	
+	dp = pci_device_to_OF_node(pdev);
+	if(dp)
+		printk(KERN_INFO "%s: OF name %s\n",__FUNCTION__, dp->name);
+	else
+		printk(KERN_ERR "imsttfb: no OF node for pci device\n");
+#endif /* CONFIG_PPC_OF */
+
+	size = sizeof(struct fb_info) + sizeof(struct imstt_par) +
+		sizeof(u32) * 16;
+
+	info = kmalloc(size, GFP_KERNEL);
+
+	if (!info) {
+		printk(KERN_ERR "imsttfb: Can't allocate memory\n");
+		return -ENOMEM;
+	}
+
+	memset(info, 0, size);
+
+	par = (struct imstt_par *) (info + 1);
+
+	addr = pci_resource_start (pdev, 0);
+	size = pci_resource_len (pdev, 0);
+
+	if (!request_mem_region(addr, size, "imsttfb")) {
+		printk(KERN_ERR "imsttfb: Can't reserve memory region\n");
+		kfree(info);
+		return -ENODEV;
+	}
+
+	switch (pdev->device) {
+		case PCI_DEVICE_ID_IMS_TT128: /* IMS,tt128mbA */
+			par->ramdac = IBM;
+#ifdef CONFIG_PPC_OF
+			if (dp && ((strcmp(dp->name, "IMS,tt128mb8") == 0) ||
+				   (strcmp(dp->name, "IMS,tt128mb8A") == 0)))
+				par->ramdac = TVP;
+#endif /* CONFIG_PPC_OF */
+			break;
+		case PCI_DEVICE_ID_IMS_TT3D:  /* IMS,tt3d */
+			par->ramdac = TVP;
+			break;
+		default:
+			printk(KERN_INFO "imsttfb: Device 0x%x unknown, "
+					 "contact maintainer.\n", pdev->device);
+			return -ENODEV;
+	}
+
+	info->fix.smem_start = addr;
+	info->screen_base = (__u8 *)ioremap(addr, par->ramdac == IBM ? 0x400000 : 0x800000);
+	info->fix.mmio_start = addr + 0x800000;
+	par->dc_regs = ioremap(addr + 0x800000, 0x1000);
+	par->cmap_regs_phys = addr + 0x840000;
+	par->cmap_regs = (__u8 *)ioremap(addr + 0x840000, 0x1000);
+	info->par = par;
+	info->pseudo_palette = (void *) (par + 1);
+	info->device = &pdev->dev;
+	init_imstt(info);
+
+	pci_set_drvdata(pdev, info);
+	return 0;
+}
+
+static void __devexit
+imsttfb_remove(struct pci_dev *pdev)
+{
+	struct fb_info *info = pci_get_drvdata(pdev);
+	struct imstt_par *par = (struct imstt_par *) info->par;
+	int size = pci_resource_len(pdev, 0);
+
+	unregister_framebuffer(info);
+	iounmap(par->cmap_regs);
+	iounmap(par->dc_regs);
+	iounmap(info->screen_base);
+	release_mem_region(info->fix.smem_start, size);
+	kfree(info);
+}
+
+#ifndef MODULE
+static int __init
+imsttfb_setup(char *options)
+{
+	char *this_opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!strncmp(this_opt, "font:", 5)) {
+			char *p;
+			int i;
+
+			p = this_opt + 5;
+			for (i = 0; i < sizeof(fontname) - 1; i++)
+				if (!*p || *p == ' ' || *p == ',')
+					break;
+			memcpy(fontname, this_opt + 5, i);
+			fontname[i] = 0;
+		} else if (!strncmp(this_opt, "inverse", 7)) {
+			inverse = 1;
+			fb_invert_cmaps();
+		}
+#if defined(CONFIG_PPC)
+		else if (!strncmp(this_opt, "vmode:", 6)) {
+			int vmode = simple_strtoul(this_opt+6, NULL, 0);
+			if (vmode > 0 && vmode <= VMODE_MAX)
+				init_vmode = vmode;
+		} else if (!strncmp(this_opt, "cmode:", 6)) {
+			int cmode = simple_strtoul(this_opt+6, NULL, 0);
+			switch (cmode) {
+				case CMODE_8:
+				case 8:
+					init_cmode = CMODE_8;
+					break;
+				case CMODE_16:
+				case 15:
+				case 16:
+					init_cmode = CMODE_16;
+					break;
+				case CMODE_32:
+				case 24:
+				case 32:
+					init_cmode = CMODE_32;
+					break;
+			}
+		}
+#endif
+	}
+	return 0;
+}
+
+#endif /* MODULE */
+
+static int __init imsttfb_init(void)
+{
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("imsttfb", &option))
+		return -ENODEV;
+
+	imsttfb_setup(option);
+#endif
+	return pci_register_driver(&imsttfb_pci_driver);
+}
+ 
+static void __exit imsttfb_exit(void)
+{
+	pci_unregister_driver(&imsttfb_pci_driver);
+}
+
+MODULE_LICENSE("GPL");
+
+module_init(imsttfb_init);
+module_exit(imsttfb_exit);
+
diff --git a/drivers/video/intelfb/Makefile b/drivers/video/intelfb/Makefile
new file mode 100644
index 0000000..722d21d
--- /dev/null
+++ b/drivers/video/intelfb/Makefile
@@ -0,0 +1,8 @@
+obj-$(CONFIG_FB_INTEL) += intelfb.o
+
+intelfb-objs := intelfbdrv.o intelfbhw.o
+
+ifdef CONFIG_FB_INTEL_DEBUG
+#EXTRA_CFLAGS += -DDEBUG -DVERBOSE -DREGDUMP
+EXTRA_CFLAGS += -DDEBUG -DREGDUMP
+endif
diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h
new file mode 100644
index 0000000..6680ec9
--- /dev/null
+++ b/drivers/video/intelfb/intelfb.h
@@ -0,0 +1,280 @@
+#ifndef _INTELFB_H
+#define _INTELFB_H
+
+/* $DHD: intelfb/intelfb.h,v 1.40 2003/06/27 15:06:25 dawes Exp $ */
+
+#include <linux/agp_backend.h>
+#include <linux/fb.h>
+
+
+/*** Version/name ***/
+#define INTELFB_VERSION			"0.9.2"
+#define INTELFB_MODULE_NAME		"intelfb"
+#define SUPPORTED_CHIPSETS		"830M/845G/852GM/855GM/865G/915G"
+
+
+/*** Debug/feature defines ***/
+
+#ifndef DEBUG
+#define DEBUG				0
+#endif
+
+#ifndef VERBOSE
+#define VERBOSE				0
+#endif
+
+#ifndef REGDUMP
+#define REGDUMP				0
+#endif
+
+#ifndef DETECT_VGA_CLASS_ONLY
+#define DETECT_VGA_CLASS_ONLY		1
+#endif
+
+#ifndef ALLOCATE_FOR_PANNING
+#define ALLOCATE_FOR_PANNING		1
+#endif
+
+#ifndef PREFERRED_MODE
+#define PREFERRED_MODE			"1024x768-32@70"
+#endif
+
+/*** hw-related values ***/
+
+/* PCI ids for supported devices */
+#define PCI_DEVICE_ID_INTEL_830M	0x3577
+#define PCI_DEVICE_ID_INTEL_845G	0x2562
+#define PCI_DEVICE_ID_INTEL_85XGM	0x3582
+#define PCI_DEVICE_ID_INTEL_865G	0x2572
+#define PCI_DEVICE_ID_INTEL_915G	0x2582
+
+/* Size of MMIO region */
+#define INTEL_REG_SIZE			0x80000
+
+#define STRIDE_ALIGNMENT		16
+
+#define PALETTE_8_ENTRIES		256
+
+
+/*** Macros ***/
+
+/* basic arithmetic */
+#define KB(x)			((x) * 1024)
+#define MB(x)			((x) * 1024 * 1024)
+#define BtoKB(x)		((x) / 1024)
+#define BtoMB(x)		((x) / 1024 / 1024)
+
+#define GTT_PAGE_SIZE           KB(4)
+
+#define ROUND_UP_TO(x, y)	(((x) + (y) - 1) / (y) * (y))
+#define ROUND_DOWN_TO(x, y)	((x) / (y) * (y))
+#define ROUND_UP_TO_PAGE(x)	ROUND_UP_TO((x), GTT_PAGE_SIZE)
+#define ROUND_DOWN_TO_PAGE(x)	ROUND_DOWN_TO((x), GTT_PAGE_SIZE)
+
+/* messages */
+#define PFX			INTELFB_MODULE_NAME ": "
+
+#define ERR_MSG(fmt, args...)	printk(KERN_ERR PFX fmt, ## args)
+#define WRN_MSG(fmt, args...)	printk(KERN_WARNING PFX fmt, ## args)
+#define NOT_MSG(fmt, args...)	printk(KERN_NOTICE PFX fmt, ## args)
+#define INF_MSG(fmt, args...)	printk(KERN_INFO PFX fmt, ## args)
+#if DEBUG
+#define DBG_MSG(fmt, args...)	printk(KERN_DEBUG PFX fmt, ## args)
+#else
+#define DBG_MSG(fmt, args...)	while (0) printk(fmt, ## args)
+#endif
+
+/* get commonly used pointers */
+#define GET_DINFO(info)		(info)->par
+
+/* misc macros */
+#define ACCEL(d, i)                                                     \
+	((d)->accel && !(d)->ring_lockup &&                             \
+	 ((i)->var.accel_flags & FB_ACCELF_TEXT))
+
+/*#define NOACCEL_CHIPSET(d)						\
+	((d)->chipset != INTEL_865G)*/
+#define NOACCEL_CHIPSET(d)						\
+	(0)
+
+#define FIXED_MODE(d) ((d)->fixed_mode)
+
+/*** Driver paramters ***/
+
+#define RINGBUFFER_SIZE		KB(64)
+#define HW_CURSOR_SIZE		KB(4)
+
+/* Intel agpgart driver */
+#define AGP_PHYSICAL_MEMORY     2
+
+/*** Data Types ***/
+
+/* supported chipsets */
+enum intel_chips {
+	INTEL_830M,
+	INTEL_845G,
+	INTEL_85XGM,
+	INTEL_852GM,
+	INTEL_852GME,
+	INTEL_855GM,
+	INTEL_855GME,
+	INTEL_865G,
+	INTEL_915G
+};
+
+struct intelfb_hwstate {
+	u32 vga0_divisor;
+	u32 vga1_divisor;
+	u32 vga_pd;
+	u32 dpll_a;
+	u32 dpll_b;
+	u32 fpa0;
+	u32 fpa1;
+	u32 fpb0;
+	u32 fpb1;
+	u32 palette_a[PALETTE_8_ENTRIES];
+	u32 palette_b[PALETTE_8_ENTRIES];
+	u32 htotal_a;
+	u32 hblank_a;
+	u32 hsync_a;
+	u32 vtotal_a;
+	u32 vblank_a;
+	u32 vsync_a;
+	u32 src_size_a;
+	u32 bclrpat_a;
+	u32 htotal_b;
+	u32 hblank_b;
+	u32 hsync_b;
+	u32 vtotal_b;
+	u32 vblank_b;
+	u32 vsync_b;
+	u32 src_size_b;
+	u32 bclrpat_b;
+	u32 adpa;
+	u32 dvoa;
+	u32 dvob;
+	u32 dvoc;
+	u32 dvoa_srcdim;
+	u32 dvob_srcdim;
+	u32 dvoc_srcdim;
+	u32 lvds;
+	u32 pipe_a_conf;
+	u32 pipe_b_conf;
+	u32 disp_arb;
+	u32 cursor_a_control;
+	u32 cursor_b_control;
+	u32 cursor_a_base;
+	u32 cursor_b_base;
+	u32 cursor_size;
+	u32 disp_a_ctrl;
+	u32 disp_b_ctrl;
+	u32 disp_a_base;
+	u32 disp_b_base;
+	u32 cursor_a_palette[4];
+	u32 cursor_b_palette[4];
+	u32 disp_a_stride;
+	u32 disp_b_stride;
+	u32 vgacntrl;
+	u32 add_id;
+	u32 swf0x[7];
+	u32 swf1x[7];
+	u32 swf3x[3];
+	u32 fence[8];
+	u32 instpm;
+	u32 mem_mode;
+	u32 fw_blc_0;
+	u32 fw_blc_1;
+};
+
+struct intelfb_heap_data {
+	u32 physical;
+	u8 __iomem *virtual;
+	u32 offset;  // in GATT pages
+	u32 size;    // in bytes
+};
+
+struct intelfb_info {
+	struct fb_info *info;
+	struct fb_ops  *fbops;
+	struct pci_dev *pdev;
+
+	struct intelfb_hwstate save_state;
+
+	/* agpgart structs */
+	struct agp_memory *gtt_fb_mem;     // use all stolen memory or vram
+	struct agp_memory *gtt_ring_mem;   // ring buffer
+	struct agp_memory *gtt_cursor_mem; // hw cursor
+
+	/* use a gart reserved fb mem */
+	u8 fbmem_gart;
+
+	/* mtrr support */
+	u32 mtrr_reg;
+	u32 has_mtrr;
+
+	/* heap data */
+	struct intelfb_heap_data aperture;
+	struct intelfb_heap_data fb;
+	struct intelfb_heap_data ring;
+	struct intelfb_heap_data cursor;
+
+	/* mmio regs */
+	u32 mmio_base_phys;
+	u8 __iomem *mmio_base;
+
+	/* fb start offset (in bytes) */
+	u32 fb_start;
+
+	/* ring buffer */
+	u8 __iomem *ring_head;
+	u32 ring_tail;
+	u32 ring_tail_mask;
+	u32 ring_space;
+	u32 ring_lockup;
+
+	/* palette */
+	u32 pseudo_palette[17];
+	struct { u8 red, green, blue, pad; } palette[256];
+
+	/* chip info */
+	int pci_chipset;
+	int chipset;
+	const char *name;
+	int mobile;
+
+	/* current mode */
+	int bpp, depth;
+	u32 visual;
+	int xres, yres, pitch;
+	int pixclock;
+
+	/* current pipe */
+	int pipe;
+
+	/* some flags */
+	int accel;
+	int hwcursor;
+	int fixed_mode;
+	int ring_active;
+
+	/* hw cursor */
+	int cursor_on;
+	int cursor_blanked;
+	u8  cursor_src[64];
+
+	/* initial parameters */
+	int initial_vga;
+	struct fb_var_screeninfo initial_var;
+	u32 initial_fb_base;
+	u32 initial_video_ram;
+	u32 initial_pitch;
+
+	/* driver registered */
+	int registered;
+};
+
+/*** function prototypes ***/
+
+extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var);
+
+#endif /* _INTELFB_H */
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
new file mode 100644
index 0000000..6a05b70
--- /dev/null
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -0,0 +1,1570 @@
+/*
+ * intelfb
+ *
+ * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G
+ * integrated graphics chips.
+ *
+ * Copyright © 2002, 2003 David Dawes <dawes@xfree86.org>
+ *                   2004 Sylvain Meyer
+ *
+ * This driver consists of two parts.  The first part (intelfbdrv.c) provides
+ * the basic fbdev interfaces, is derived in part from the radeonfb and
+ * vesafb drivers, and is covered by the GPL.  The second part (intelfbhw.c)
+ * provides the code to program the hardware.  Most of it is derived from
+ * the i810/i830 XFree86 driver.  The HW-specific code is covered here
+ * under a dual license (GPL and MIT/XFree86 license).
+ *
+ * Author: David Dawes
+ *
+ */
+
+/* $DHD: intelfb/intelfbdrv.c,v 1.20 2003/06/27 15:17:40 dawes Exp $ */
+
+/*
+ * Changes:
+ *    01/2003 - Initial driver (0.1.0), no mode switching, no acceleration.
+ *		This initial version is a basic core that works a lot like
+ *		the vesafb driver.  It must be built-in to the kernel,
+ *		and the initial video mode must be set with vga=XXX at
+ *		boot time.  (David Dawes)
+ *
+ *    01/2003 - Version 0.2.0: Mode switching added, colormap support
+ *		implemented, Y panning, and soft screen blanking implemented.
+ *		No acceleration yet.  (David Dawes)
+ *
+ *    01/2003 - Version 0.3.0: fbcon acceleration support added.  Module
+ *		option handling added.  (David Dawes)
+ *
+ *    01/2003 - Version 0.4.0: fbcon HW cursor support added.  (David Dawes)
+ *
+ *    01/2003 - Version 0.4.1: Add auto-generation of built-in modes.
+ *		(David Dawes)
+ *
+ *    02/2003 - Version 0.4.2: Add check for active non-CRT devices, and
+ *		mode validation checks.  (David Dawes)
+ *
+ *    02/2003 - Version 0.4.3: Check when the VC is in graphics mode so that
+ *		acceleration is disabled while an XFree86 server is running.
+ *		(David Dawes)
+ *
+ *    02/2003 - Version 0.4.4: Monitor DPMS support.  (David Dawes)
+ *
+ *    02/2003 - Version 0.4.5: Basic XFree86 + fbdev working.  (David Dawes)
+ *
+ *    02/2003 - Version 0.5.0: Modify to work with the 2.5.32 kernel as well
+ *		as 2.4.x kernels.  (David Dawes)
+ *
+ *    02/2003 - Version 0.6.0: Split out HW-specifics into a separate file.
+ *		(David Dawes)
+ *
+ *    02/2003 - Version 0.7.0: Test on 852GM/855GM.  Acceleration and HW
+ *		cursor are disabled on this platform.  (David Dawes)
+ *
+ *    02/2003 - Version 0.7.1: Test on 845G.  Acceleration is disabled
+ *		on this platform.  (David Dawes)
+ *
+ *    02/2003 - Version 0.7.2: Test on 830M.  Acceleration and HW
+ *		cursor are disabled on this platform.  (David Dawes)
+ *
+ *    02/2003 - Version 0.7.3: Fix 8-bit modes for mobile platforms
+ *		(David Dawes)
+ *
+ *    02/2003 - Version 0.7.4: Add checks for FB and FBCON_HAS_CFB* configured
+ *		in the kernel, and add mode bpp verification and default
+ *		bpp selection based on which FBCON_HAS_CFB* are configured.
+ *		(David Dawes)
+ *
+ *    02/2003 - Version 0.7.5: Add basic package/install scripts based on the
+ *		DRI packaging scripts.  (David Dawes)
+ *
+ *    04/2003 - Version 0.7.6: Fix typo that affects builds with SMP-enabled
+ *		kernels.  (David Dawes, reported by Anupam).
+ *
+ *    06/2003 - Version 0.7.7:
+ *              Fix Makefile.kernel build problem (Tsutomu Yasuda).
+ *		Fix mis-placed #endif (2.4.21 kernel).
+ *
+ *    09/2004 - Version 0.9.0 - by Sylvain Meyer
+ *              Port to linux 2.6 kernel fbdev
+ *              Fix HW accel and HW cursor on i845G
+ *              Use of agpgart for fb memory reservation
+ *              Add mtrr support
+ *
+ *    10/2004 - Version 0.9.1
+ *              Use module_param instead of old MODULE_PARM
+ *              Some cleanup
+ *
+ *    11/2004 - Version 0.9.2
+ *              Add vram option to reserve more memory than stolen by BIOS
+ *              Fix intelfbhw_pan_display typo
+ *              Add __initdata annotations
+ *
+ * TODO:
+ *
+ *
+ * Wish List:
+ *
+ *
+ */
+
+#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/delay.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/selection.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/kd.h>
+#include <linux/vt_kern.h>
+#include <linux/pagemap.h>
+#include <linux/version.h>
+
+#include <asm/io.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include "intelfb.h"
+#include "intelfbdrv.h"
+#include "intelfbhw.h"
+
+/*
+ * Limiting the class to PCI_CLASS_DISPLAY_VGA prevents function 1 of the
+ * mobile chipsets from being registered.
+ */
+#if DETECT_VGA_CLASS_ONLY
+#define INTELFB_CLASS_MASK ~0 << 8
+#else
+#define INTELFB_CLASS_MASK 0
+#endif
+
+static struct pci_device_id intelfb_pci_table[] __devinitdata = {
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_830M, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_830M },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_845G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_845G },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_85XGM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_85XGM },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_865G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_865G },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915G },
+	{ 0, }
+};
+
+/* Global data */
+static int num_registered = 0;
+
+/* fb ops */
+static struct fb_ops intel_fb_ops = {
+	.owner =		THIS_MODULE,
+	.fb_check_var =         intelfb_check_var,
+	.fb_set_par =           intelfb_set_par,
+	.fb_setcolreg =		intelfb_setcolreg,
+	.fb_blank =		intelfb_blank,
+	.fb_pan_display =       intelfb_pan_display,
+	.fb_fillrect  =         intelfb_fillrect,
+	.fb_copyarea  =         intelfb_copyarea,
+	.fb_imageblit =         intelfb_imageblit,
+	.fb_cursor =            intelfb_cursor,
+	.fb_sync =              intelfb_sync,
+	.fb_ioctl =		intelfb_ioctl
+};
+
+/* PCI driver module table */
+static struct pci_driver intelfb_driver = {
+	.name =		"Intel(R) " SUPPORTED_CHIPSETS " Framebuffer Driver",
+	.id_table =	intelfb_pci_table,
+	.probe =	intelfb_pci_register,
+	.remove =	__devexit_p(intelfb_pci_unregister)
+};
+
+/* Module description/parameters */
+MODULE_AUTHOR("David Dawes <dawes@tungstengraphics.com>, "
+	      "Sylvain Meyer <sylvain.meyer@worldonline.fr>");
+MODULE_DESCRIPTION(
+	"Framebuffer driver for Intel(R) " SUPPORTED_CHIPSETS " chipsets");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DEVICE_TABLE(pci, intelfb_pci_table);
+
+static int accel        __initdata = 1;
+static int vram         __initdata = 4;
+static int hwcursor     __initdata = 1;
+static int mtrr         __initdata = 1;
+static int fixed        __initdata = 0;
+static int noinit       __initdata = 0;
+static int noregister   __initdata = 0;
+static int probeonly    __initdata = 0;
+static int idonly       __initdata = 0;
+static int bailearly    __initdata = 0;
+static char *mode       __initdata = NULL;
+
+module_param(accel, bool, S_IRUGO);
+MODULE_PARM_DESC(accel, "Enable console acceleration");
+module_param(vram, int, S_IRUGO);
+MODULE_PARM_DESC(vram, "System RAM to allocate to framebuffer in MiB");
+module_param(hwcursor, bool, S_IRUGO);
+MODULE_PARM_DESC(hwcursor, "Enable HW cursor");
+module_param(mtrr, bool, S_IRUGO);
+MODULE_PARM_DESC(mtrr, "Enable MTRR support");
+module_param(fixed, bool, S_IRUGO);
+MODULE_PARM_DESC(fixed, "Disable mode switching");
+module_param(noinit, bool, 0);
+MODULE_PARM_DESC(noinit, "Don't initialise graphics mode when loading");
+module_param(noregister, bool, 0);
+MODULE_PARM_DESC(noregister, "Don't register, just probe and exit (debug)");
+module_param(probeonly, bool, 0);
+MODULE_PARM_DESC(probeonly, "Do a minimal probe (debug)");
+module_param(idonly, bool, 0);
+MODULE_PARM_DESC(idonly, "Just identify without doing anything else (debug)");
+module_param(bailearly, bool, 0);
+MODULE_PARM_DESC(bailearly, "Bail out early, depending on value (debug)");
+module_param(mode, charp, S_IRUGO);
+MODULE_PARM_DESC(mode,
+		 "Initial video mode \"<xres>x<yres>[-<depth>][@<refresh>]\"");
+
+#ifndef MODULE
+#define OPT_EQUAL(opt, name) (!strncmp(opt, name, strlen(name)))
+#define OPT_INTVAL(opt, name) simple_strtoul(opt + strlen(name), NULL, 0)
+#define OPT_STRVAL(opt, name) (opt + strlen(name))
+
+static __inline__ char *
+get_opt_string(const char *this_opt, const char *name)
+{
+	const char *p;
+	int i;
+	char *ret;
+
+	p = OPT_STRVAL(this_opt, name);
+	i = 0;
+	while (p[i] && p[i] != ' ' && p[i] != ',')
+		i++;
+	ret = kmalloc(i + 1, GFP_KERNEL);
+	if (ret) {
+		strncpy(ret, p, i);
+		ret[i] = '\0';
+	}
+	return ret;
+}
+
+static __inline__ int
+get_opt_int(const char *this_opt, const char *name, int *ret)
+{
+	if (!ret)
+		return 0;
+
+	if (!OPT_EQUAL(this_opt, name))
+		return 0;
+
+	*ret = OPT_INTVAL(this_opt, name);
+	return 1;
+}
+
+static __inline__ int
+get_opt_bool(const char *this_opt, const char *name, int *ret)
+{
+	if (!ret)
+		return 0;
+
+	if (OPT_EQUAL(this_opt, name)) {
+		if (this_opt[strlen(name)] == '=')
+			*ret = simple_strtoul(this_opt + strlen(name) + 1,
+					      NULL, 0);
+		else
+			*ret = 1;
+	} else {
+		if (OPT_EQUAL(this_opt, "no") && OPT_EQUAL(this_opt + 2, name))
+			*ret = 0;
+		else
+			return 0;
+	}
+	return 1;
+}
+
+static int __init
+intelfb_setup(char *options)
+{
+	char *this_opt;
+
+	DBG_MSG("intelfb_setup\n");
+
+	if (!options || !*options) {
+		DBG_MSG("no options\n");
+		return 0;
+	} else
+		DBG_MSG("options: %s\n", options);
+
+	/*
+	 * These are the built-in options analogous to the module parameters
+	 * defined above.
+	 *
+	 * The syntax is:
+	 *
+	 *    video=intelfb:[mode][,<param>=<val>] ...
+	 *
+	 * e.g.,
+	 *
+	 *    video=intelfb:1024x768-16@75,accel=0
+	 */
+
+	while ((this_opt = strsep(&options, ","))) {
+		if (!*this_opt)
+			continue;
+		if (get_opt_bool(this_opt, "accel", &accel))
+			;
+ 		else if (get_opt_int(this_opt, "vram", &vram))
+			;
+		else if (get_opt_bool(this_opt, "hwcursor", &hwcursor))
+			;
+		else if (get_opt_bool(this_opt, "mtrr", &mtrr))
+			;
+		else if (get_opt_bool(this_opt, "fixed", &fixed))
+			;
+		else if (get_opt_bool(this_opt, "init", &noinit))
+			noinit = !noinit;
+		else if (OPT_EQUAL(this_opt, "mode="))
+			mode = get_opt_string(this_opt, "mode=");
+		else
+			mode = this_opt;
+	}
+
+	return 0;
+}
+
+#endif
+
+static int __init
+intelfb_init(void)
+{
+#ifndef MODULE
+	char *option = NULL;
+#endif
+
+	DBG_MSG("intelfb_init\n");
+
+	INF_MSG("Framebuffer driver for "
+		"Intel(R) " SUPPORTED_CHIPSETS " chipsets\n");
+	INF_MSG("Version " INTELFB_VERSION "\n");
+
+	if (idonly)
+		return -ENODEV;
+
+#ifndef MODULE
+	if (fb_get_options("intelfb", &option))
+		return -ENODEV;
+	intelfb_setup(option);
+#endif
+
+	return pci_register_driver(&intelfb_driver);
+}
+
+static void __exit
+intelfb_exit(void)
+{
+	DBG_MSG("intelfb_exit\n");
+	pci_unregister_driver(&intelfb_driver);
+}
+
+module_init(intelfb_init);
+module_exit(intelfb_exit);
+
+/***************************************************************
+ *                     mtrr support functions                  *
+ ***************************************************************/
+
+#ifdef CONFIG_MTRR
+static inline void __devinit set_mtrr(struct intelfb_info *dinfo)
+{
+	dinfo->mtrr_reg = mtrr_add(dinfo->aperture.physical,
+				   dinfo->aperture.size, MTRR_TYPE_WRCOMB, 1);
+	if (dinfo->mtrr_reg < 0) {
+		ERR_MSG("unable to set MTRR\n");
+		return;
+	}
+	dinfo->has_mtrr = 1;
+}
+static inline void unset_mtrr(struct intelfb_info *dinfo)
+{
+  	if (dinfo->has_mtrr)
+  		mtrr_del(dinfo->mtrr_reg, dinfo->aperture.physical,
+			 dinfo->aperture.size);
+}
+#else
+#define set_mtrr(x) WRN_MSG("MTRR is disabled in the kernel\n")
+
+#define unset_mtrr(x) do { } while (0)
+#endif /* CONFIG_MTRR */
+
+/***************************************************************
+ *                        driver init / cleanup                *
+ ***************************************************************/
+
+static void
+cleanup(struct intelfb_info *dinfo)
+{
+	DBG_MSG("cleanup\n");
+
+	if (!dinfo)
+		return;
+
+	fb_dealloc_cmap(&dinfo->info->cmap);
+	kfree(dinfo->info->pixmap.addr);
+
+	if (dinfo->registered)
+		unregister_framebuffer(dinfo->info);
+
+	unset_mtrr(dinfo);
+
+	if (dinfo->fbmem_gart && dinfo->gtt_fb_mem) {
+		agp_unbind_memory(dinfo->gtt_fb_mem);
+		agp_free_memory(dinfo->gtt_fb_mem);
+	}
+	if (dinfo->gtt_cursor_mem) {
+		agp_unbind_memory(dinfo->gtt_cursor_mem);
+		agp_free_memory(dinfo->gtt_cursor_mem);
+	}
+	if (dinfo->gtt_ring_mem) {
+		agp_unbind_memory(dinfo->gtt_ring_mem);
+		agp_free_memory(dinfo->gtt_ring_mem);
+	}
+
+	if (dinfo->mmio_base)
+		iounmap((void __iomem *)dinfo->mmio_base);
+	if (dinfo->aperture.virtual)
+		iounmap((void __iomem *)dinfo->aperture.virtual);
+
+	if (dinfo->mmio_base_phys)
+		release_mem_region(dinfo->mmio_base_phys, INTEL_REG_SIZE);
+	if (dinfo->aperture.physical)
+		release_mem_region(dinfo->aperture.physical,
+				   dinfo->aperture.size);
+	framebuffer_release(dinfo->info);
+}
+
+#define bailout(dinfo) do {						\
+	DBG_MSG("bailout\n");						\
+	cleanup(dinfo);							\
+	INF_MSG("Not going to register framebuffer, exiting...\n");	\
+	return -ENODEV;							\
+} while (0)
+
+
+static int __devinit
+intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	struct fb_info *info;
+	struct intelfb_info *dinfo;
+	int i, j, err, dvo;
+	int aperture_size, stolen_size;
+	struct agp_kern_info gtt_info;
+	int agp_memtype;
+	const char *s;
+	struct agp_bridge_data *bridge;
+ 	int aperture_bar = 0;
+ 	int mmio_bar = 1;
+
+	DBG_MSG("intelfb_pci_register\n");
+
+	num_registered++;
+	if (num_registered != 1) {
+		ERR_MSG("Attempted to register %d devices "
+			"(should be only 1).\n", num_registered);
+		return -ENODEV;
+	}
+
+	info = framebuffer_alloc(sizeof(struct intelfb_info), &pdev->dev);
+	if (!info) {
+		ERR_MSG("Could not allocate memory for intelfb_info.\n");
+		return -ENODEV;
+	}
+	if (fb_alloc_cmap(&info->cmap, 256, 1) < 0) {
+		ERR_MSG("Could not allocate cmap for intelfb_info.\n");
+		goto err_out_cmap;
+		return -ENODEV;
+	}
+
+	dinfo = info->par;
+	dinfo->info  = info;
+	dinfo->fbops = &intel_fb_ops;
+	dinfo->pdev  = pdev;
+
+	/* Reserve pixmap space. */
+	info->pixmap.addr = kmalloc(64 * 1024, GFP_KERNEL);
+	if (info->pixmap.addr == NULL) {
+		ERR_MSG("Cannot reserve pixmap memory.\n");
+		goto err_out_pixmap;
+	}
+	memset(info->pixmap.addr, 0, 64 * 1024);
+
+	/* set early this option because it could be changed by tv encoder
+	   driver */
+	dinfo->fixed_mode = fixed;
+
+	/* Enable device. */
+	if ((err = pci_enable_device(pdev))) {
+		ERR_MSG("Cannot enable device.\n");
+		cleanup(dinfo);
+		return -ENODEV;
+	}
+
+	/* Set base addresses. */
+	if (ent->device == PCI_DEVICE_ID_INTEL_915G) {
+		aperture_bar = 2;
+		mmio_bar = 0;
+		/* Disable HW cursor on 915G (not implemented yet) */
+		hwcursor = 0;
+	}
+	dinfo->aperture.physical = pci_resource_start(pdev, aperture_bar);
+	dinfo->aperture.size     = pci_resource_len(pdev, aperture_bar);
+	dinfo->mmio_base_phys    = pci_resource_start(pdev, mmio_bar);
+	DBG_MSG("fb aperture: 0x%llx/0x%llx, MMIO region: 0x%llx/0x%llx\n",
+		(unsigned long long)pci_resource_start(pdev, aperture_bar),
+		(unsigned long long)pci_resource_len(pdev, aperture_bar),
+		(unsigned long long)pci_resource_start(pdev, mmio_bar),
+		(unsigned long long)pci_resource_len(pdev, mmio_bar));
+
+	/* Reserve the fb and MMIO regions */
+	if (!request_mem_region(dinfo->aperture.physical, dinfo->aperture.size,
+				INTELFB_MODULE_NAME)) {
+		ERR_MSG("Cannot reserve FB region.\n");
+		cleanup(dinfo);
+		return -ENODEV;
+	}
+	if (!request_mem_region(dinfo->mmio_base_phys,
+				INTEL_REG_SIZE,
+				INTELFB_MODULE_NAME)) {
+		ERR_MSG("Cannot reserve MMIO region.\n");
+		cleanup(dinfo);
+		return -ENODEV;
+	}
+
+	/* Map the fb and MMIO regions */
+	dinfo->aperture.virtual = (u8 __iomem *)ioremap_nocache
+		(dinfo->aperture.physical, dinfo->aperture.size);
+	if (!dinfo->aperture.virtual) {
+		ERR_MSG("Cannot remap FB region.\n");
+		cleanup(dinfo);
+		return -ENODEV;
+	}
+	dinfo->mmio_base =
+		(u8 __iomem *)ioremap_nocache(dinfo->mmio_base_phys,
+					       INTEL_REG_SIZE);
+	if (!dinfo->mmio_base) {
+		ERR_MSG("Cannot remap MMIO region.\n");
+		cleanup(dinfo);
+		return -ENODEV;
+	}
+
+	/* Get the chipset info. */
+	dinfo->pci_chipset = pdev->device;
+
+	if (intelfbhw_get_chipset(pdev, &dinfo->name, &dinfo->chipset,
+				  &dinfo->mobile)) {
+		cleanup(dinfo);
+		return -ENODEV;
+	}
+
+	if (intelfbhw_get_memory(pdev, &aperture_size,&stolen_size)) {
+		cleanup(dinfo);
+		return -ENODEV;
+	}
+
+	INF_MSG("%02x:%02x.%d: %s, aperture size %dMB, "
+		"stolen memory %dkB\n",
+		pdev->bus->number, PCI_SLOT(pdev->devfn),
+		PCI_FUNC(pdev->devfn), dinfo->name,
+		BtoMB(aperture_size), BtoKB(stolen_size));
+
+	/* Set these from the options. */
+	dinfo->accel    = accel;
+	dinfo->hwcursor = hwcursor;
+
+	if (NOACCEL_CHIPSET(dinfo) && dinfo->accel == 1) {
+		INF_MSG("Acceleration is not supported for the %s chipset.\n",
+			dinfo->name);
+		dinfo->accel = 0;
+	}
+
+	/* Framebuffer parameters - Use all the stolen memory if >= vram */
+	if (ROUND_UP_TO_PAGE(stolen_size) >= MB(vram)) {
+		dinfo->fb.size = ROUND_UP_TO_PAGE(stolen_size);
+		dinfo->fbmem_gart = 0;
+	} else {
+		dinfo->fb.size =  MB(vram);
+		dinfo->fbmem_gart = 1;
+	}
+
+	/* Allocate space for the ring buffer and HW cursor if enabled. */
+	if (dinfo->accel) {
+		dinfo->ring.size = RINGBUFFER_SIZE;
+		dinfo->ring_tail_mask = dinfo->ring.size - 1;
+	}
+	if (dinfo->hwcursor) {
+		dinfo->cursor.size = HW_CURSOR_SIZE;
+	}
+
+	/* Use agpgart to manage the GATT */
+	if (!(bridge = agp_backend_acquire(pdev))) {
+		ERR_MSG("cannot acquire agp\n");
+		cleanup(dinfo);
+		return -ENODEV;
+	}
+
+	/* get the current gatt info */
+	if (agp_copy_info(bridge, &gtt_info)) {
+		ERR_MSG("cannot get agp info\n");
+		agp_backend_release(bridge);
+		cleanup(dinfo);
+		return -ENODEV;
+	}
+
+	/* set the mem offsets - set them after the already used pages */
+	if (dinfo->accel) {
+		dinfo->ring.offset = (stolen_size >> 12)
+			+ gtt_info.current_memory;
+	}
+	if (dinfo->hwcursor) {
+		dinfo->cursor.offset = (stolen_size >> 12) +
+			+ gtt_info.current_memory + (dinfo->ring.size >> 12);
+	}
+	if (dinfo->fbmem_gart) {
+		dinfo->fb.offset = (stolen_size >> 12) +
+			+ gtt_info.current_memory + (dinfo->ring.size >> 12)
+			+ (dinfo->cursor.size >> 12);
+	}
+
+	/* Allocate memories (which aren't stolen) */
+	if (dinfo->accel) {
+		if (!(dinfo->gtt_ring_mem =
+		      agp_allocate_memory(bridge, dinfo->ring.size >> 12,
+					  AGP_NORMAL_MEMORY))) {
+			ERR_MSG("cannot allocate ring buffer memory\n");
+			agp_backend_release(bridge);
+			cleanup(dinfo);
+			return -ENOMEM;
+		}
+		if (agp_bind_memory(dinfo->gtt_ring_mem,
+				    dinfo->ring.offset)) {
+			ERR_MSG("cannot bind ring buffer memory\n");
+			agp_backend_release(bridge);
+			cleanup(dinfo);
+			return -EBUSY;
+		}
+		dinfo->ring.physical = dinfo->aperture.physical
+			+ (dinfo->ring.offset << 12);
+		dinfo->ring.virtual  = dinfo->aperture.virtual
+			+ (dinfo->ring.offset << 12);
+		dinfo->ring_head = dinfo->ring.virtual;
+	}
+	if (dinfo->hwcursor) {
+		agp_memtype = dinfo->mobile ? AGP_PHYSICAL_MEMORY
+			: AGP_NORMAL_MEMORY;
+		if (!(dinfo->gtt_cursor_mem =
+		      agp_allocate_memory(bridge, dinfo->cursor.size >> 12,
+					  agp_memtype))) {
+			ERR_MSG("cannot allocate cursor memory\n");
+			agp_backend_release(bridge);
+			cleanup(dinfo);
+			return -ENOMEM;
+		}
+		if (agp_bind_memory(dinfo->gtt_cursor_mem,
+				    dinfo->cursor.offset)) {
+			ERR_MSG("cannot bind cursor memory\n");
+			agp_backend_release(bridge);
+			cleanup(dinfo);
+			return -EBUSY;
+		}
+		if (dinfo->mobile)
+			dinfo->cursor.physical
+				= dinfo->gtt_cursor_mem->physical;
+		else
+			dinfo->cursor.physical = dinfo->aperture.physical
+				+ (dinfo->cursor.offset << 12);
+		dinfo->cursor.virtual = dinfo->aperture.virtual
+			+ (dinfo->cursor.offset << 12);
+	}
+	if (dinfo->fbmem_gart) {
+		if (!(dinfo->gtt_fb_mem =
+		      agp_allocate_memory(bridge, dinfo->fb.size >> 12,
+					  AGP_NORMAL_MEMORY))) {
+			WRN_MSG("cannot allocate framebuffer memory - use "
+				"the stolen one\n");
+			dinfo->fbmem_gart = 0;
+		}
+		if (agp_bind_memory(dinfo->gtt_fb_mem,
+				    dinfo->fb.offset)) {
+			WRN_MSG("cannot bind framebuffer memory - use "
+				"the stolen one\n");
+			dinfo->fbmem_gart = 0;
+		}
+	}
+
+	/* update framebuffer memory parameters */
+	if (!dinfo->fbmem_gart)
+		dinfo->fb.offset = 0;   /* starts at offset 0 */
+	dinfo->fb.physical = dinfo->aperture.physical
+		+ (dinfo->fb.offset << 12);
+	dinfo->fb.virtual = dinfo->aperture.virtual + (dinfo->fb.offset << 12);
+	dinfo->fb_start = dinfo->fb.offset << 12;
+
+	/* release agpgart */
+	agp_backend_release(bridge);
+
+	if (mtrr)
+		set_mtrr(dinfo);
+
+	DBG_MSG("fb: 0x%x(+ 0x%x)/0x%x (0x%x)\n",
+		dinfo->fb.physical, dinfo->fb.offset, dinfo->fb.size,
+		(u32 __iomem ) dinfo->fb.virtual);
+	DBG_MSG("MMIO: 0x%x/0x%x (0x%x)\n",
+		dinfo->mmio_base_phys, INTEL_REG_SIZE,
+		(u32 __iomem) dinfo->mmio_base);
+	DBG_MSG("ring buffer: 0x%x/0x%x (0x%x)\n",
+		dinfo->ring.physical, dinfo->ring.size,
+		(u32 __iomem ) dinfo->ring.virtual);
+	DBG_MSG("HW cursor: 0x%x/0x%x (0x%x) (offset 0x%x) (phys 0x%x)\n",
+		dinfo->cursor.physical, dinfo->cursor.size,
+		(u32 __iomem ) dinfo->cursor.virtual, dinfo->cursor.offset,
+		dinfo->cursor.physical);
+
+	DBG_MSG("options: vram = %d, accel = %d, hwcursor = %d, fixed = %d, "
+		"noinit = %d\n", vram, accel, hwcursor, fixed, noinit);
+	DBG_MSG("options: mode = \"%s\"\n", mode ? mode : "");
+
+	if (probeonly)
+		bailout(dinfo);
+
+	/*
+	 * Check if the LVDS port or any DVO ports are enabled.  If so,
+	 * don't allow mode switching
+	 */
+	dvo = intelfbhw_check_non_crt(dinfo);
+	if (dvo) {
+		dinfo->fixed_mode = 1;
+		WRN_MSG("Non-CRT device is enabled ( ");
+		i = 0;
+		while (dvo) {
+			if (dvo & 1) {
+				s = intelfbhw_dvo_to_string(1 << i);
+				if (s)
+					printk("%s ", s);
+			}
+			dvo >>= 1;
+			++i;
+		}
+		printk(").  Disabling mode switching.\n");
+	}
+
+	if (bailearly == 1)
+		bailout(dinfo);
+
+	if (FIXED_MODE(dinfo) && ORIG_VIDEO_ISVGA != VIDEO_TYPE_VLFB) {
+		ERR_MSG("Video mode must be programmed at boot time.\n");
+		cleanup(dinfo);
+		return -ENODEV;
+	}
+
+	if (bailearly == 2)
+		bailout(dinfo);
+
+	/* Initialise dinfo and related data. */
+	/* If an initial mode was programmed at boot time, get its details. */
+	if (ORIG_VIDEO_ISVGA == VIDEO_TYPE_VLFB)
+		get_initial_mode(dinfo);
+
+	if (bailearly == 3)
+		bailout(dinfo);
+
+	if (FIXED_MODE(dinfo)) {
+		/* remap fb address */
+		update_dinfo(dinfo, &dinfo->initial_var);
+	}
+
+	if (bailearly == 4)
+		bailout(dinfo);
+
+
+	if (intelfb_set_fbinfo(dinfo)) {
+		cleanup(dinfo);
+		return -ENODEV;
+	}
+
+	if (bailearly == 5)
+		bailout(dinfo);
+
+	for (i = 0; i < 16; i++) {
+		j = color_table[i];
+		dinfo->palette[i].red = default_red[j];
+		dinfo->palette[i].green = default_grn[j];
+		dinfo->palette[i].blue = default_blu[j];
+	}
+
+	if (bailearly == 6)
+		bailout(dinfo);
+
+	pci_set_drvdata(pdev, dinfo);
+
+	/* Save the initial register state. */
+	i = intelfbhw_read_hw_state(dinfo, &dinfo->save_state,
+				    bailearly > 6 ? bailearly - 6 : 0);
+	if (i != 0) {
+		DBG_MSG("intelfbhw_read_hw_state returned %d\n", i);
+		bailout(dinfo);
+	}
+
+	intelfbhw_print_hw_state(dinfo, &dinfo->save_state);
+
+	if (bailearly == 18)
+		bailout(dinfo);
+
+	/* Cursor initialisation */
+	if (dinfo->hwcursor) {
+		intelfbhw_cursor_init(dinfo);
+		intelfbhw_cursor_reset(dinfo);
+	}
+
+	if (bailearly == 19)
+		bailout(dinfo);
+
+	/* 2d acceleration init */
+	if (dinfo->accel)
+		intelfbhw_2d_start(dinfo);
+
+	if (bailearly == 20)
+		bailout(dinfo);
+
+	if (noregister)
+		bailout(dinfo);
+
+	if (register_framebuffer(dinfo->info) < 0) {
+		ERR_MSG("Cannot register framebuffer.\n");
+		cleanup(dinfo);
+		return -ENODEV;
+	}
+
+	dinfo->registered = 1;
+
+	return 0;
+
+err_out_pixmap:
+	fb_dealloc_cmap(&info->cmap);
+err_out_cmap:
+	framebuffer_release(info);
+	return -ENODEV;
+}
+
+static void __devexit
+intelfb_pci_unregister(struct pci_dev *pdev)
+{
+	struct intelfb_info *dinfo = pci_get_drvdata(pdev);
+
+	DBG_MSG("intelfb_pci_unregister\n");
+
+	if (!dinfo)
+		return;
+
+	cleanup(dinfo);
+
+	pci_set_drvdata(pdev, NULL);
+}
+
+/***************************************************************
+ *                       helper functions                      *
+ ***************************************************************/
+
+int __inline__
+intelfb_var_to_depth(const struct fb_var_screeninfo *var)
+{
+	DBG_MSG("intelfb_var_to_depth: bpp: %d, green.length is %d\n",
+		var->bits_per_pixel, var->green.length);
+
+	switch (var->bits_per_pixel) {
+	case 16:
+		return (var->green.length == 6) ? 16 : 15;
+	case 32:
+		return 24;
+	default:
+		return var->bits_per_pixel;
+	}
+}
+
+
+static __inline__ int
+var_to_refresh(const struct fb_var_screeninfo *var)
+{
+	int xtot = var->xres + var->left_margin + var->right_margin +
+		   var->hsync_len;
+	int ytot = var->yres + var->upper_margin + var->lower_margin +
+		   var->vsync_len;
+
+	return (1000000000 / var->pixclock * 1000 + 500) / xtot / ytot;
+}
+
+/***************************************************************
+ *                Various intialisation functions              *
+ ***************************************************************/
+
+static void __devinit
+get_initial_mode(struct intelfb_info *dinfo)
+{
+	struct fb_var_screeninfo *var;
+	int xtot, ytot;
+
+	DBG_MSG("get_initial_mode\n");
+
+	dinfo->initial_vga = 1;
+	dinfo->initial_fb_base = screen_info.lfb_base;
+	dinfo->initial_video_ram = screen_info.lfb_size * KB(64);
+	dinfo->initial_pitch = screen_info.lfb_linelength;
+
+	var = &dinfo->initial_var;
+	memset(var, 0, sizeof(*var));
+	var->xres = screen_info.lfb_width;
+	var->yres = screen_info.lfb_height;
+	var->bits_per_pixel = screen_info.lfb_depth;
+	switch (screen_info.lfb_depth) {
+	case 15:
+		var->bits_per_pixel = 16;
+		break;
+	case 24:
+		var->bits_per_pixel = 32;
+		break;
+	}
+
+	DBG_MSG("Initial info: FB is 0x%x/0x%x (%d kByte)\n",
+		dinfo->initial_fb_base, dinfo->initial_video_ram,
+		BtoKB(dinfo->initial_video_ram));
+
+	DBG_MSG("Initial info: mode is %dx%d-%d (%d)\n",
+		var->xres, var->yres, var->bits_per_pixel,
+		dinfo->initial_pitch);
+
+	/* Dummy timing values (assume 60Hz) */
+	var->left_margin = (var->xres / 8) & 0xf8;
+	var->right_margin = 32;
+	var->upper_margin = 16;
+	var->lower_margin = 4;
+	var->hsync_len = (var->xres / 8) & 0xf8;
+	var->vsync_len = 4;
+
+	xtot = var->xres + var->left_margin +
+		var->right_margin + var->hsync_len;
+	ytot = var->yres + var->upper_margin +
+		var->lower_margin + var->vsync_len;
+	var->pixclock = 10000000 / xtot * 1000 / ytot * 100 / 60;
+
+	var->height = -1;
+	var->width = -1;
+
+	if (var->bits_per_pixel > 8) {
+		var->red.offset = screen_info.red_pos;
+		var->red.length = screen_info.red_size;
+		var->green.offset = screen_info.green_pos;
+		var->green.length = screen_info.green_size;
+		var->blue.offset = screen_info.blue_pos;
+		var->blue.length = screen_info.blue_size;
+		var->transp.offset = screen_info.rsvd_pos;
+		var->transp.length = screen_info.rsvd_size;
+	} else {
+		var->red.length = 8;
+		var->green.length = 8;
+		var->blue.length = 8;
+	}
+}
+
+static int __devinit
+intelfb_init_var(struct intelfb_info *dinfo)
+{
+	struct fb_var_screeninfo *var;
+	int msrc = 0;
+
+	DBG_MSG("intelfb_init_var\n");
+
+	var = &dinfo->info->var;
+	if (FIXED_MODE(dinfo)) {
+	        memcpy(var, &dinfo->initial_var,
+		       sizeof(struct fb_var_screeninfo));
+		msrc = 5;
+	} else {
+		if (mode) {
+			msrc = fb_find_mode(var, dinfo->info, mode,
+					    vesa_modes, VESA_MODEDB_SIZE,
+					    NULL, 0);
+			if (msrc)
+				msrc |= 8;
+		}
+		if (!msrc) {
+			msrc = fb_find_mode(var, dinfo->info, PREFERRED_MODE,
+					    vesa_modes, VESA_MODEDB_SIZE,
+					    NULL, 0);
+		}
+	}
+
+	if (!msrc) {
+		ERR_MSG("Cannot find a suitable video mode.\n");
+		return 1;
+	}
+
+	INF_MSG("Initial video mode is %dx%d-%d@%d.\n", var->xres, var->yres,
+		var->bits_per_pixel, var_to_refresh(var));
+
+	DBG_MSG("Initial video mode is from %d.\n", msrc);
+
+#if ALLOCATE_FOR_PANNING
+	/* Allow use of half of the video ram for panning */
+	var->xres_virtual = var->xres;
+	var->yres_virtual =
+		dinfo->fb.size / 2 / (var->bits_per_pixel * var->xres);
+	if (var->yres_virtual < var->yres)
+		var->yres_virtual = var->yres;
+#else
+	var->yres_virtual = var->yres;
+#endif
+
+	if (dinfo->accel)
+		var->accel_flags |= FB_ACCELF_TEXT;
+	else
+		var->accel_flags &= ~FB_ACCELF_TEXT;
+
+	return 0;
+}
+
+static int __devinit
+intelfb_set_fbinfo(struct intelfb_info *dinfo)
+{
+	struct fb_info *info = dinfo->info;
+
+	DBG_MSG("intelfb_set_fbinfo\n");
+
+	info->flags = FBINFO_FLAG_DEFAULT;
+	info->fbops = &intel_fb_ops;
+	info->pseudo_palette = dinfo->pseudo_palette;
+
+	info->pixmap.size = 64*1024;
+	info->pixmap.buf_align = 8;
+	info->pixmap.flags = FB_PIXMAP_SYSTEM;
+
+	if (intelfb_init_var(dinfo))
+		return 1;
+
+	info->pixmap.scan_align = 1;
+
+	update_dinfo(dinfo, &info->var);
+
+	return 0;
+}
+
+/* Update dinfo to match the active video mode. */
+static void
+update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var)
+{
+	DBG_MSG("update_dinfo\n");
+
+	dinfo->bpp = var->bits_per_pixel;
+	dinfo->depth = intelfb_var_to_depth(var);
+	dinfo->xres = var->xres;
+	dinfo->yres = var->xres;
+	dinfo->pixclock = var->pixclock;
+
+	intelfb_get_fix(&dinfo->info->fix, dinfo->info);
+
+	switch (dinfo->bpp) {
+	case 8:
+		dinfo->visual = FB_VISUAL_PSEUDOCOLOR;
+		dinfo->pitch = var->xres_virtual;
+		break;
+	case 16:
+		dinfo->visual = FB_VISUAL_TRUECOLOR;
+		dinfo->pitch = var->xres_virtual * 2;
+		break;
+	case 32:
+		dinfo->visual = FB_VISUAL_TRUECOLOR;
+		dinfo->pitch = var->xres_virtual * 4;
+		break;
+	}
+
+	/* Make sure the line length is a aligned correctly. */
+	dinfo->pitch = ROUND_UP_TO(dinfo->pitch, STRIDE_ALIGNMENT);
+
+	if (FIXED_MODE(dinfo))
+		dinfo->pitch = dinfo->initial_pitch;
+
+	dinfo->info->screen_base = (char __iomem *)dinfo->fb.virtual;
+	dinfo->info->fix.line_length = dinfo->pitch;
+	dinfo->info->fix.visual = dinfo->visual;
+}
+
+/* fbops functions */
+
+static int
+intelfb_get_fix(struct fb_fix_screeninfo *fix, struct fb_info *info)
+{
+	struct intelfb_info *dinfo = GET_DINFO(info);
+
+	DBG_MSG("intelfb_get_fix\n");
+
+	memset(fix, 0, sizeof(*fix));
+	strcpy(fix->id, dinfo->name);
+	fix->smem_start = dinfo->fb.physical;
+	fix->smem_len = dinfo->fb.size;
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->type_aux = 0;
+	fix->visual = dinfo->visual;
+	fix->xpanstep = 8;
+	fix->ypanstep = 1;
+	fix->ywrapstep = 0;
+	fix->line_length = dinfo->pitch;
+	fix->mmio_start = dinfo->mmio_base_phys;
+	fix->mmio_len = INTEL_REG_SIZE;
+	fix->accel = FB_ACCEL_I830;
+	return 0;
+}
+
+/***************************************************************
+ *                       fbdev interface                       *
+ ***************************************************************/
+
+static int
+intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	int change_var = 0;
+	struct fb_var_screeninfo v;
+	struct intelfb_info *dinfo;
+	static int first = 1;
+
+	DBG_MSG("intelfb_check_var: accel_flags is %d\n", var->accel_flags);
+
+	dinfo = GET_DINFO(info);
+
+	if (intelfbhw_validate_mode(dinfo, var) != 0)
+		return -EINVAL;
+
+	v = *var;
+
+	/* Check for a supported bpp. */
+	if (v.bits_per_pixel <= 8) {
+		v.bits_per_pixel = 8;
+	} else if (v.bits_per_pixel <= 16) {
+		if (v.bits_per_pixel == 16)
+			v.green.length = 6;
+		v.bits_per_pixel = 16;
+	} else if (v.bits_per_pixel <= 32) {
+		v.bits_per_pixel = 32;
+	} else
+		return -EINVAL;
+
+	change_var = ((info->var.xres != var->xres) ||
+		      (info->var.yres != var->yres) ||
+		      (info->var.xres_virtual != var->xres_virtual) ||
+		      (info->var.yres_virtual != var->yres_virtual) ||
+		      (info->var.bits_per_pixel != var->bits_per_pixel) ||
+		      memcmp(&info->var.red, &var->red, sizeof(var->red)) ||
+		      memcmp(&info->var.green, &var->green,
+			     sizeof(var->green)) ||
+		      memcmp(&info->var.blue, &var->blue, sizeof(var->blue)));
+
+	if (FIXED_MODE(dinfo) &&
+	    (change_var ||
+	     var->yres_virtual > dinfo->initial_var.yres_virtual ||
+	     var->yres_virtual < dinfo->initial_var.yres ||
+	     var->xoffset || var->nonstd)) {
+		if (first) {
+			ERR_MSG("Changing the video mode is not supported.\n");
+			first = 0;
+		}
+		return -EINVAL;
+	}
+
+	switch (intelfb_var_to_depth(&v)) {
+	case 8:
+		v.red.offset = v.green.offset = v.blue.offset = 0;
+		v.red.length = v.green.length = v.blue.length = 8;
+		v.transp.offset = v.transp.length = 0;
+		break;
+	case 15:
+		v.red.offset = 10;
+		v.green.offset = 5;
+		v.blue.offset = 0;
+		v.red.length = v.green.length = v.blue.length = 5;
+		v.transp.offset = v.transp.length = 0;
+		break;
+	case 16:
+		v.red.offset = 11;
+		v.green.offset = 5;
+		v.blue.offset = 0;
+		v.red.length = 5;
+		v.green.length = 6;
+		v.blue.length = 5;
+		v.transp.offset = v.transp.length = 0;
+		break;
+	case 24:
+		v.red.offset = 16;
+		v.green.offset = 8;
+		v.blue.offset = 0;
+		v.red.length = v.green.length = v.blue.length = 8;
+		v.transp.offset = v.transp.length = 0;
+		break;
+	case 32:
+		v.red.offset = 16;
+		v.green.offset = 8;
+		v.blue.offset = 0;
+		v.red.length = v.green.length = v.blue.length = 8;
+		v.transp.offset = 24;
+		v.transp.length = 8;
+		break;
+	}
+
+	if (v.xoffset < 0)
+		v.xoffset = 0;
+	if (v.yoffset < 0)
+		v.yoffset = 0;
+
+	if (v.xoffset > v.xres_virtual - v.xres)
+		v.xoffset = v.xres_virtual - v.xres;
+	if (v.yoffset > v.yres_virtual - v.yres)
+		v.yoffset = v.yres_virtual - v.yres;
+
+	v.red.msb_right = v.green.msb_right = v.blue.msb_right =
+			  v.transp.msb_right = 0;
+
+        *var = v;
+
+	return 0;
+}
+
+static int
+intelfb_set_par(struct fb_info *info)
+{
+ 	struct intelfb_hwstate *hw;
+        struct intelfb_info *dinfo = GET_DINFO(info);
+
+	if (FIXED_MODE(dinfo)) {
+		ERR_MSG("Changing the video mode is not supported.\n");
+		return -EINVAL;
+	}
+
+ 	hw = kmalloc(sizeof(*hw), GFP_ATOMIC);
+ 	if (!hw)
+ 		return -ENOMEM;
+
+	DBG_MSG("intelfb_set_par (%dx%d-%d)\n", info->var.xres,
+		info->var.yres, info->var.bits_per_pixel);
+
+	intelfb_blank(FB_BLANK_POWERDOWN, info);
+
+	if (dinfo->accel)
+		intelfbhw_2d_stop(dinfo);
+
+ 	memcpy(hw, &dinfo->save_state, sizeof(*hw));
+ 	if (intelfbhw_mode_to_hw(dinfo, hw, &info->var))
+ 		goto invalid_mode;
+ 	if (intelfbhw_program_mode(dinfo, hw, 0))
+ 		goto invalid_mode;
+
+#if REGDUMP > 0
+ 	intelfbhw_read_hw_state(dinfo, hw, 0);
+ 	intelfbhw_print_hw_state(dinfo, hw);
+#endif
+
+	update_dinfo(dinfo, &info->var);
+
+	if (dinfo->accel)
+		intelfbhw_2d_start(dinfo);
+
+	intelfb_pan_display(&info->var, info);
+
+	intelfb_blank(FB_BLANK_UNBLANK, info);
+
+	if (ACCEL(dinfo, info)) {
+		info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN |
+		FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
+		FBINFO_HWACCEL_IMAGEBLIT;
+	} else {
+		info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+	}
+	kfree(hw);
+	return 0;
+invalid_mode:
+	kfree(hw);
+	return -EINVAL;
+}
+
+static int
+intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+		  unsigned blue, unsigned transp, struct fb_info *info)
+{
+	struct intelfb_info *dinfo = GET_DINFO(info);
+
+#if VERBOSE > 0
+	DBG_MSG("intelfb_setcolreg: regno %d, depth %d\n", regno, dinfo->depth);
+#endif
+
+	if (regno > 255)
+		return 1;
+
+	switch (dinfo->depth) {
+	case 8:
+		{
+			red >>= 8;
+			green >>= 8;
+			blue >>= 8;
+
+			dinfo->palette[regno].red = red;
+			dinfo->palette[regno].green = green;
+			dinfo->palette[regno].blue = blue;
+
+			intelfbhw_setcolreg(dinfo, regno, red, green, blue,
+					    transp);
+		}
+		break;
+	case 15:
+		dinfo->pseudo_palette[regno] = ((red & 0xf800) >>  1) |
+					       ((green & 0xf800) >>  6) |
+					       ((blue & 0xf800) >> 11);
+		break;
+	case 16:
+		dinfo->pseudo_palette[regno] = (red & 0xf800) |
+					       ((green & 0xfc00) >>  5) |
+					       ((blue  & 0xf800) >> 11);
+		break;
+	case 24:
+		dinfo->pseudo_palette[regno] = ((red & 0xff00) << 8) |
+					       (green & 0xff00) |
+					       ((blue  & 0xff00) >> 8);
+		break;
+	}
+	return 0;
+}
+
+static int
+intelfb_blank(int blank, struct fb_info *info)
+{
+	intelfbhw_do_blank(blank, info);
+	return 0;
+}
+
+static int
+intelfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	intelfbhw_pan_display(var, info);
+	return 0;
+}
+
+/* When/if we have our own ioctls. */
+static int
+intelfb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	      unsigned long arg, struct fb_info *info)
+{
+	int retval = 0;
+
+	return retval;
+}
+
+static void
+intelfb_fillrect (struct fb_info *info, const struct fb_fillrect *rect)
+{
+        struct intelfb_info *dinfo = GET_DINFO(info);
+	u32 rop, color;
+
+#if VERBOSE > 0
+	DBG_MSG("intelfb_fillrect\n");
+#endif
+
+	if (!ACCEL(dinfo, info) || dinfo->depth == 4)
+		return cfb_fillrect(info, rect);
+
+	if (rect->rop == ROP_COPY)
+		rop = PAT_ROP_GXCOPY;
+	else // ROP_XOR
+		rop = PAT_ROP_GXXOR;
+
+	if (dinfo->depth != 8)
+		color = dinfo->pseudo_palette[rect->color];
+	else
+		color = rect->color;
+
+	intelfbhw_do_fillrect(dinfo, rect->dx, rect->dy,
+			      rect->width, rect->height, color,
+			      dinfo->pitch, info->var.bits_per_pixel,
+			      rop);
+}
+
+static void
+intelfb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
+{
+        struct intelfb_info *dinfo = GET_DINFO(info);
+
+#if VERBOSE > 0
+	DBG_MSG("intelfb_copyarea\n");
+#endif
+
+	if (!ACCEL(dinfo, info) || dinfo->depth == 4)
+		return cfb_copyarea(info, region);
+
+	intelfbhw_do_bitblt(dinfo, region->sx, region->sy, region->dx,
+			    region->dy, region->width, region->height,
+			    dinfo->pitch, info->var.bits_per_pixel);
+}
+
+static void
+intelfb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+        struct intelfb_info *dinfo = GET_DINFO(info);
+	u32 fgcolor, bgcolor;
+
+#if VERBOSE > 0
+	DBG_MSG("intelfb_imageblit\n");
+#endif
+
+	if (!ACCEL(dinfo, info) || dinfo->depth == 4
+	    || image->depth != 1)
+		return cfb_imageblit(info, image);
+
+	if (dinfo->depth != 8) {
+		fgcolor = dinfo->pseudo_palette[image->fg_color];
+		bgcolor = dinfo->pseudo_palette[image->bg_color];
+	} else {
+		fgcolor = image->fg_color;
+		bgcolor = image->bg_color;
+	}
+
+	if (!intelfbhw_do_drawglyph(dinfo, fgcolor, bgcolor, image->width,
+				    image->height, image->data,
+				    image->dx, image->dy,
+				    dinfo->pitch, info->var.bits_per_pixel))
+		return cfb_imageblit(info, image);
+}
+
+static int
+intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+        struct intelfb_info *dinfo = GET_DINFO(info);
+
+#if VERBOSE > 0
+	DBG_MSG("intelfb_cursor\n");
+#endif
+
+	if (!dinfo->hwcursor)
+		return soft_cursor(info, cursor);
+
+	intelfbhw_cursor_hide(dinfo);
+
+	/* If XFree killed the cursor - restore it */
+	if (INREG(CURSOR_A_BASEADDR) != dinfo->cursor.offset << 12) {
+		u32 fg, bg;
+
+		DBG_MSG("the cursor was killed - restore it !!\n");
+		DBG_MSG("size %d, %d   pos %d, %d\n",
+			cursor->image.width, cursor->image.height,
+			cursor->image.dx, cursor->image.dy);
+
+		intelfbhw_cursor_init(dinfo);
+		intelfbhw_cursor_reset(dinfo);
+		intelfbhw_cursor_setpos(dinfo, cursor->image.dx,
+					cursor->image.dy);
+
+		if (dinfo->depth != 8) {
+			fg =dinfo->pseudo_palette[cursor->image.fg_color];
+			bg =dinfo->pseudo_palette[cursor->image.bg_color];
+		} else {
+			fg = cursor->image.fg_color;
+			bg = cursor->image.bg_color;
+		}
+		intelfbhw_cursor_setcolor(dinfo, bg, fg);
+		intelfbhw_cursor_load(dinfo, cursor->image.width,
+				      cursor->image.height,
+				      dinfo->cursor_src);
+
+		if (cursor->enable)
+			intelfbhw_cursor_show(dinfo);
+		return 0;
+	}
+
+	if (cursor->set & FB_CUR_SETPOS) {
+		u32 dx, dy;
+
+		dx = cursor->image.dx - info->var.xoffset;
+		dy = cursor->image.dy - info->var.yoffset;
+
+		intelfbhw_cursor_setpos(dinfo, dx, dy);
+	}
+
+	if (cursor->set & FB_CUR_SETSIZE) {
+		if (cursor->image.width > 64 || cursor->image.height > 64)
+			return -ENXIO;
+
+		intelfbhw_cursor_reset(dinfo);
+	}
+
+	if (cursor->set & FB_CUR_SETCMAP) {
+		u32 fg, bg;
+
+		if (dinfo->depth != 8) {
+			fg = dinfo->pseudo_palette[cursor->image.fg_color];
+			bg = dinfo->pseudo_palette[cursor->image.bg_color];
+		} else {
+			fg = cursor->image.fg_color;
+			bg = cursor->image.bg_color;
+		}
+
+		intelfbhw_cursor_setcolor(dinfo, bg, fg);
+	}
+
+	if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
+		u32 s_pitch = (ROUND_UP_TO(cursor->image.width, 8) / 8);
+		u32 size = s_pitch * cursor->image.height;
+		u8 *dat = (u8 *) cursor->image.data;
+		u8 *msk = (u8 *) cursor->mask;
+		u8 src[64];
+		u32 i;
+
+		if (cursor->image.depth != 1)
+			return -ENXIO;
+
+		switch (cursor->rop) {
+		case ROP_XOR:
+			for (i = 0; i < size; i++)
+				src[i] = dat[i] ^ msk[i];
+			break;
+		case ROP_COPY:
+		default:
+			for (i = 0; i < size; i++)
+				src[i] = dat[i] & msk[i];
+			break;
+		}
+
+		/* save the bitmap to restore it when XFree will
+		   make the cursor dirty */
+		memcpy(dinfo->cursor_src, src, size);
+
+		intelfbhw_cursor_load(dinfo, cursor->image.width,
+				      cursor->image.height, src);
+	}
+
+	if (cursor->enable)
+		intelfbhw_cursor_show(dinfo);
+
+	return 0;
+}
+
+static int
+intelfb_sync(struct fb_info *info)
+{
+        struct intelfb_info *dinfo = GET_DINFO(info);
+
+#if VERBOSE > 0
+	DBG_MSG("intelfb_sync\n");
+#endif
+
+	if (dinfo->ring_lockup)
+		return 0;
+
+	intelfbhw_do_sync(dinfo);
+	return 0;
+}
+
diff --git a/drivers/video/intelfb/intelfbdrv.h b/drivers/video/intelfb/intelfbdrv.h
new file mode 100644
index 0000000..cc30581
--- /dev/null
+++ b/drivers/video/intelfb/intelfbdrv.h
@@ -0,0 +1,68 @@
+#ifndef _INTELFBDRV_H
+#define _INTELFBDRV_H
+
+/*
+ ******************************************************************************
+ * intelfb
+ *
+ * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G
+ * integrated graphics chips.
+ *
+ * Copyright © 2004 Sylvain Meyer
+ *
+ * Author: Sylvain Meyer
+ *
+ ******************************************************************************
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+static void __devinit get_initial_mode(struct intelfb_info *dinfo);
+static void update_dinfo(struct intelfb_info *dinfo,
+			 struct fb_var_screeninfo *var);
+static int intelfb_get_fix(struct fb_fix_screeninfo *fix,
+			   struct fb_info *info);
+
+static int intelfb_check_var(struct fb_var_screeninfo *var,
+			     struct fb_info *info);
+static int intelfb_set_par(struct fb_info *info);
+static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			     unsigned blue, unsigned transp,
+			     struct fb_info *info);
+
+static int intelfb_blank(int blank, struct fb_info *info);
+static int intelfb_pan_display(struct fb_var_screeninfo *var,
+			       struct fb_info *info);
+
+static void intelfb_fillrect(struct fb_info *info,
+			     const struct fb_fillrect *rect);
+static void intelfb_copyarea(struct fb_info *info,
+			     const struct fb_copyarea *region);
+static void intelfb_imageblit(struct fb_info *info,
+			      const struct fb_image *image);
+static int intelfb_cursor(struct fb_info *info,
+			   struct fb_cursor *cursor);
+
+static int intelfb_sync(struct fb_info *info);
+
+static int intelfb_ioctl(struct inode *inode, struct file *file,
+			 unsigned int cmd, unsigned long arg,
+			 struct fb_info *info);
+
+static int __devinit intelfb_pci_register(struct pci_dev *pdev,
+					  const struct pci_device_id *ent);
+static void __devexit intelfb_pci_unregister(struct pci_dev *pdev);
+static int __devinit intelfb_set_fbinfo(struct intelfb_info *dinfo);
+
+#endif
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
new file mode 100644
index 0000000..f5bed58
--- /dev/null
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -0,0 +1,1780 @@
+/*
+ * intelfb
+ *
+ * Linux framebuffer driver for Intel(R) 865G integrated graphics chips.
+ *
+ * Copyright © 2002, 2003 David Dawes <dawes@xfree86.org>
+ *                   2004 Sylvain Meyer
+ *
+ * This driver consists of two parts.  The first part (intelfbdrv.c) provides
+ * the basic fbdev interfaces, is derived in part from the radeonfb and
+ * vesafb drivers, and is covered by the GPL.  The second part (intelfbhw.c)
+ * provides the code to program the hardware.  Most of it is derived from
+ * the i810/i830 XFree86 driver.  The HW-specific code is covered here
+ * under a dual license (GPL and MIT/XFree86 license).
+ *
+ * Author: David Dawes
+ *
+ */
+
+/* $DHD: intelfb/intelfbhw.c,v 1.9 2003/06/27 15:06:25 dawes Exp $ */
+
+#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/delay.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/selection.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/kd.h>
+#include <linux/vt_kern.h>
+#include <linux/pagemap.h>
+#include <linux/version.h>
+
+#include <asm/io.h>
+
+#include "intelfb.h"
+#include "intelfbhw.h"
+
+int
+intelfbhw_get_chipset(struct pci_dev *pdev, const char **name, int *chipset,
+		      int *mobile)
+{
+	u32 tmp;
+
+	if (!pdev || !name || !chipset || !mobile)
+		return 1;
+
+	switch (pdev->device) {
+	case PCI_DEVICE_ID_INTEL_830M:
+		*name = "Intel(R) 830M";
+		*chipset = INTEL_830M;
+		*mobile = 1;
+		return 0;
+	case PCI_DEVICE_ID_INTEL_845G:
+		*name = "Intel(R) 845G";
+		*chipset = INTEL_845G;
+		*mobile = 0;
+		return 0;
+	case PCI_DEVICE_ID_INTEL_85XGM:
+		tmp = 0;
+		*mobile = 1;
+		pci_read_config_dword(pdev, INTEL_85X_CAPID, &tmp);
+		switch ((tmp >> INTEL_85X_VARIANT_SHIFT) &
+			INTEL_85X_VARIANT_MASK) {
+		case INTEL_VAR_855GME:
+			*name = "Intel(R) 855GME";
+			*chipset = INTEL_855GME;
+			return 0;
+		case INTEL_VAR_855GM:
+			*name = "Intel(R) 855GM";
+			*chipset = INTEL_855GM;
+			return 0;
+		case INTEL_VAR_852GME:
+			*name = "Intel(R) 852GME";
+			*chipset = INTEL_852GME;
+			return 0;
+		case INTEL_VAR_852GM:
+			*name = "Intel(R) 852GM";
+			*chipset = INTEL_852GM;
+			return 0;
+		default:
+			*name = "Intel(R) 852GM/855GM";
+			*chipset = INTEL_85XGM;
+			return 0;
+		}
+		break;
+	case PCI_DEVICE_ID_INTEL_865G:
+		*name = "Intel(R) 865G";
+		*chipset = INTEL_865G;
+		*mobile = 0;
+		return 0;
+	case PCI_DEVICE_ID_INTEL_915G:
+		*name = "Intel(R) 915G";
+		*chipset = INTEL_915G;
+		*mobile = 0;
+		return 0;
+	default:
+		return 1;
+	}
+}
+
+int
+intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
+		     int *stolen_size)
+{
+	struct pci_dev *bridge_dev;
+	u16 tmp;
+
+	if (!pdev || !aperture_size || !stolen_size)
+		return 1;
+
+	/* Find the bridge device.  It is always 0:0.0 */
+	if (!(bridge_dev = pci_find_slot(0, PCI_DEVFN(0, 0)))) {
+		ERR_MSG("cannot find bridge device\n");
+		return 1;
+	}
+
+	/* Get the fb aperture size and "stolen" memory amount. */
+	tmp = 0;
+	pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &tmp);
+	switch (pdev->device) {
+	case PCI_DEVICE_ID_INTEL_830M:
+	case PCI_DEVICE_ID_INTEL_845G:
+		if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M)
+			*aperture_size = MB(64);
+		else
+			*aperture_size = MB(128);
+		switch (tmp & INTEL_830_GMCH_GMS_MASK) {
+		case INTEL_830_GMCH_GMS_STOLEN_512:
+			*stolen_size = KB(512) - KB(132);
+			return 0;
+		case INTEL_830_GMCH_GMS_STOLEN_1024:
+			*stolen_size = MB(1) - KB(132);
+			return 0;
+		case INTEL_830_GMCH_GMS_STOLEN_8192:
+			*stolen_size = MB(8) - KB(132);
+			return 0;
+		case INTEL_830_GMCH_GMS_LOCAL:
+			ERR_MSG("only local memory found\n");
+			return 1;
+		case INTEL_830_GMCH_GMS_DISABLED:
+			ERR_MSG("video memory is disabled\n");
+			return 1;
+		default:
+			ERR_MSG("unexpected GMCH_GMS value: 0x%02x\n",
+				tmp & INTEL_830_GMCH_GMS_MASK);
+			return 1;
+		}
+		break;
+	default:
+		*aperture_size = MB(128);
+		switch (tmp & INTEL_855_GMCH_GMS_MASK) {
+		case INTEL_855_GMCH_GMS_STOLEN_1M:
+			*stolen_size = MB(1) - KB(132);
+			return 0;
+		case INTEL_855_GMCH_GMS_STOLEN_4M:
+			*stolen_size = MB(4) - KB(132);
+			return 0;
+		case INTEL_855_GMCH_GMS_STOLEN_8M:
+			*stolen_size = MB(8) - KB(132);
+			return 0;
+		case INTEL_855_GMCH_GMS_STOLEN_16M:
+			*stolen_size = MB(16) - KB(132);
+			return 0;
+		case INTEL_855_GMCH_GMS_STOLEN_32M:
+			*stolen_size = MB(32) - KB(132);
+			return 0;
+		case INTEL_915G_GMCH_GMS_STOLEN_48M:
+			*stolen_size = MB(48) - KB(132);
+			return 0;
+		case INTEL_915G_GMCH_GMS_STOLEN_64M:
+			*stolen_size = MB(64) - KB(132);
+			return 0;
+		case INTEL_855_GMCH_GMS_DISABLED:
+			ERR_MSG("video memory is disabled\n");
+			return 0;
+		default:
+			ERR_MSG("unexpected GMCH_GMS value: 0x%02x\n",
+				tmp & INTEL_855_GMCH_GMS_MASK);
+			return 1;
+		}
+	}
+}
+
+int
+intelfbhw_check_non_crt(struct intelfb_info *dinfo)
+{
+	int dvo = 0;
+
+	if (INREG(LVDS) & PORT_ENABLE)
+		dvo |= LVDS_PORT;
+	if (INREG(DVOA) & PORT_ENABLE)
+		dvo |= DVOA_PORT;
+	if (INREG(DVOB) & PORT_ENABLE)
+		dvo |= DVOB_PORT;
+	if (INREG(DVOC) & PORT_ENABLE)
+		dvo |= DVOC_PORT;
+
+	return dvo;
+}
+
+const char *
+intelfbhw_dvo_to_string(int dvo)
+{
+	if (dvo & DVOA_PORT)
+		return "DVO port A";
+	else if (dvo & DVOB_PORT)
+		return "DVO port B";
+	else if (dvo & DVOC_PORT)
+		return "DVO port C";
+	else if (dvo & LVDS_PORT)
+		return "LVDS port";
+	else
+		return NULL;
+}
+
+
+int
+intelfbhw_validate_mode(struct intelfb_info *dinfo,
+			struct fb_var_screeninfo *var)
+{
+	int bytes_per_pixel;
+	int tmp;
+
+#if VERBOSE > 0
+	DBG_MSG("intelfbhw_validate_mode\n");
+#endif
+
+	bytes_per_pixel = var->bits_per_pixel / 8;
+	if (bytes_per_pixel == 3)
+		bytes_per_pixel = 4;
+
+	/* Check if enough video memory. */
+	tmp = var->yres_virtual * var->xres_virtual * bytes_per_pixel;
+	if (tmp > dinfo->fb.size) {
+		WRN_MSG("Not enough video ram for mode "
+			"(%d KByte vs %d KByte).\n",
+			BtoKB(tmp), BtoKB(dinfo->fb.size));
+		return 1;
+	}
+
+	/* Check if x/y limits are OK. */
+	if (var->xres - 1 > HACTIVE_MASK) {
+		WRN_MSG("X resolution too large (%d vs %d).\n",
+			var->xres, HACTIVE_MASK + 1);
+		return 1;
+	}
+	if (var->yres - 1 > VACTIVE_MASK) {
+		WRN_MSG("Y resolution too large (%d vs %d).\n",
+			var->yres, VACTIVE_MASK + 1);
+		return 1;
+	}
+
+	/* Check for interlaced/doublescan modes. */
+	if (var->vmode & FB_VMODE_INTERLACED) {
+		WRN_MSG("Mode is interlaced.\n");
+		return 1;
+	}
+	if (var->vmode & FB_VMODE_DOUBLE) {
+		WRN_MSG("Mode is double-scan.\n");
+		return 1;
+	}
+
+	/* Check if clock is OK. */
+	tmp = 1000000000 / var->pixclock;
+	if (tmp < MIN_CLOCK) {
+		WRN_MSG("Pixel clock is too low (%d MHz vs %d MHz).\n",
+			(tmp + 500) / 1000, MIN_CLOCK / 1000);
+		return 1;
+	}
+	if (tmp > MAX_CLOCK) {
+		WRN_MSG("Pixel clock is too high (%d MHz vs %d MHz).\n",
+			(tmp + 500) / 1000, MAX_CLOCK / 1000);
+		return 1;
+	}
+
+	return 0;
+}
+
+int
+intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct intelfb_info *dinfo = GET_DINFO(info);
+	u32 offset, xoffset, yoffset;
+
+#if VERBOSE > 0
+	DBG_MSG("intelfbhw_pan_display\n");
+#endif
+
+	xoffset = ROUND_DOWN_TO(var->xoffset, 8);
+	yoffset = var->yoffset;
+
+	if ((xoffset + var->xres > var->xres_virtual) ||
+	    (yoffset + var->yres > var->yres_virtual))
+		return -EINVAL;
+
+	offset = (yoffset * dinfo->pitch) +
+		 (xoffset * var->bits_per_pixel) / 8;
+
+	offset += dinfo->fb.offset << 12;
+
+	OUTREG(DSPABASE, offset);
+
+	return 0;
+}
+
+/* Blank the screen. */
+void
+intelfbhw_do_blank(int blank, struct fb_info *info)
+{
+	struct intelfb_info *dinfo = GET_DINFO(info);
+	u32 tmp;
+
+#if VERBOSE > 0
+	DBG_MSG("intelfbhw_do_blank: blank is %d\n", blank);
+#endif
+
+	/* Turn plane A on or off */
+	tmp = INREG(DSPACNTR);
+	if (blank)
+		tmp &= ~DISPPLANE_PLANE_ENABLE;
+	else
+		tmp |= DISPPLANE_PLANE_ENABLE;
+	OUTREG(DSPACNTR, tmp);
+	/* Flush */
+	tmp = INREG(DSPABASE);
+	OUTREG(DSPABASE, tmp);
+
+	/* Turn off/on the HW cursor */
+#if VERBOSE > 0
+	DBG_MSG("cursor_on is %d\n", dinfo->cursor_on);
+#endif
+	if (dinfo->cursor_on) {
+		if (blank) {
+			intelfbhw_cursor_hide(dinfo);
+		} else {
+			intelfbhw_cursor_show(dinfo);
+		}
+		dinfo->cursor_on = 1;
+	}
+	dinfo->cursor_blanked = blank;
+
+	/* Set DPMS level */
+	tmp = INREG(ADPA) & ~ADPA_DPMS_CONTROL_MASK;
+	switch (blank) {
+	case FB_BLANK_UNBLANK:
+	case FB_BLANK_NORMAL:
+		tmp |= ADPA_DPMS_D0;
+		break;
+	case FB_BLANK_VSYNC_SUSPEND:
+		tmp |= ADPA_DPMS_D1;
+		break;
+	case FB_BLANK_HSYNC_SUSPEND:
+		tmp |= ADPA_DPMS_D2;
+		break;
+	case FB_BLANK_POWERDOWN:
+		tmp |= ADPA_DPMS_D3;
+		break;
+	}
+	OUTREG(ADPA, tmp);
+
+	return;
+}
+
+
+void
+intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno,
+		    unsigned red, unsigned green, unsigned blue,
+		    unsigned transp)
+{
+#if VERBOSE > 0
+	DBG_MSG("intelfbhw_setcolreg: %d: (%d, %d, %d)\n",
+		regno, red, green, blue);
+#endif
+
+	u32 palette_reg = (dinfo->pipe == PIPE_A) ?
+			  PALETTE_A : PALETTE_B;
+
+	OUTREG(palette_reg + (regno << 2),
+	       (red << PALETTE_8_RED_SHIFT) |
+	       (green << PALETTE_8_GREEN_SHIFT) |
+	       (blue << PALETTE_8_BLUE_SHIFT));
+}
+
+
+int
+intelfbhw_read_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
+			int flag)
+{
+	int i;
+
+#if VERBOSE > 0
+	DBG_MSG("intelfbhw_read_hw_state\n");
+#endif
+
+	if (!hw || !dinfo)
+		return -1;
+
+	/* Read in as much of the HW state as possible. */
+	hw->vga0_divisor = INREG(VGA0_DIVISOR);
+	hw->vga1_divisor = INREG(VGA1_DIVISOR);
+	hw->vga_pd = INREG(VGAPD);
+	hw->dpll_a = INREG(DPLL_A);
+	hw->dpll_b = INREG(DPLL_B);
+	hw->fpa0 = INREG(FPA0);
+	hw->fpa1 = INREG(FPA1);
+	hw->fpb0 = INREG(FPB0);
+	hw->fpb1 = INREG(FPB1);
+
+	if (flag == 1)
+		return flag;
+
+#if 0
+	/* This seems to be a problem with the 852GM/855GM */
+	for (i = 0; i < PALETTE_8_ENTRIES; i++) {
+		hw->palette_a[i] = INREG(PALETTE_A + (i << 2));
+		hw->palette_b[i] = INREG(PALETTE_B + (i << 2));
+	}
+#endif
+
+	if (flag == 2)
+		return flag;
+
+	hw->htotal_a = INREG(HTOTAL_A);
+	hw->hblank_a = INREG(HBLANK_A);
+	hw->hsync_a = INREG(HSYNC_A);
+	hw->vtotal_a = INREG(VTOTAL_A);
+	hw->vblank_a = INREG(VBLANK_A);
+	hw->vsync_a = INREG(VSYNC_A);
+	hw->src_size_a = INREG(SRC_SIZE_A);
+	hw->bclrpat_a = INREG(BCLRPAT_A);
+	hw->htotal_b = INREG(HTOTAL_B);
+	hw->hblank_b = INREG(HBLANK_B);
+	hw->hsync_b = INREG(HSYNC_B);
+	hw->vtotal_b = INREG(VTOTAL_B);
+	hw->vblank_b = INREG(VBLANK_B);
+	hw->vsync_b = INREG(VSYNC_B);
+	hw->src_size_b = INREG(SRC_SIZE_B);
+	hw->bclrpat_b = INREG(BCLRPAT_B);
+
+	if (flag == 3)
+		return flag;
+
+	hw->adpa = INREG(ADPA);
+	hw->dvoa = INREG(DVOA);
+	hw->dvob = INREG(DVOB);
+	hw->dvoc = INREG(DVOC);
+	hw->dvoa_srcdim = INREG(DVOA_SRCDIM);
+	hw->dvob_srcdim = INREG(DVOB_SRCDIM);
+	hw->dvoc_srcdim = INREG(DVOC_SRCDIM);
+	hw->lvds = INREG(LVDS);
+
+	if (flag == 4)
+		return flag;
+
+	hw->pipe_a_conf = INREG(PIPEACONF);
+	hw->pipe_b_conf = INREG(PIPEBCONF);
+	hw->disp_arb = INREG(DISPARB);
+
+	if (flag == 5)
+		return flag;
+
+	hw->cursor_a_control = INREG(CURSOR_A_CONTROL);
+	hw->cursor_b_control = INREG(CURSOR_B_CONTROL);
+	hw->cursor_a_base = INREG(CURSOR_A_BASEADDR);
+	hw->cursor_b_base = INREG(CURSOR_B_BASEADDR);
+
+	if (flag == 6)
+		return flag;
+
+	for (i = 0; i < 4; i++) {
+		hw->cursor_a_palette[i] = INREG(CURSOR_A_PALETTE0 + (i << 2));
+		hw->cursor_b_palette[i] = INREG(CURSOR_B_PALETTE0 + (i << 2));
+	}
+
+	if (flag == 7)
+		return flag;
+
+	hw->cursor_size = INREG(CURSOR_SIZE);
+
+	if (flag == 8)
+		return flag;
+
+	hw->disp_a_ctrl = INREG(DSPACNTR);
+	hw->disp_b_ctrl = INREG(DSPBCNTR);
+	hw->disp_a_base = INREG(DSPABASE);
+	hw->disp_b_base = INREG(DSPBBASE);
+	hw->disp_a_stride = INREG(DSPASTRIDE);
+	hw->disp_b_stride = INREG(DSPBSTRIDE);
+
+	if (flag == 9)
+		return flag;
+
+	hw->vgacntrl = INREG(VGACNTRL);
+
+	if (flag == 10)
+		return flag;
+
+	hw->add_id = INREG(ADD_ID);
+
+	if (flag == 11)
+		return flag;
+
+	for (i = 0; i < 7; i++) {
+		hw->swf0x[i] = INREG(SWF00 + (i << 2));
+		hw->swf1x[i] = INREG(SWF10 + (i << 2));
+		if (i < 3)
+			hw->swf3x[i] = INREG(SWF30 + (i << 2));
+	}
+
+	for (i = 0; i < 8; i++)
+		hw->fence[i] = INREG(FENCE + (i << 2));
+
+	hw->instpm = INREG(INSTPM);
+	hw->mem_mode = INREG(MEM_MODE);
+	hw->fw_blc_0 = INREG(FW_BLC_0);
+	hw->fw_blc_1 = INREG(FW_BLC_1);
+
+	return 0;
+}
+
+
+void
+intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
+{
+#if REGDUMP
+	int i, m1, m2, n, p1, p2;
+
+	DBG_MSG("intelfbhw_print_hw_state\n");
+
+	if (!hw || !dinfo)
+		return;
+	/* Read in as much of the HW state as possible. */
+	printk("hw state dump start\n");
+	printk("	VGA0_DIVISOR:		0x%08x\n", hw->vga0_divisor);
+	printk("	VGA1_DIVISOR:		0x%08x\n", hw->vga1_divisor);
+	printk("	VGAPD: 			0x%08x\n", hw->vga_pd);
+	n = (hw->vga0_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+	m1 = (hw->vga0_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+	m2 = (hw->vga0_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+	if (hw->vga_pd & VGAPD_0_P1_FORCE_DIV2)
+		p1 = 0;
+	else
+		p1 = (hw->vga_pd >> VGAPD_0_P1_SHIFT) & DPLL_P1_MASK;
+	p2 = (hw->vga_pd >> VGAPD_0_P2_SHIFT) & DPLL_P2_MASK;
+	printk("	VGA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
+		m1, m2, n, p1, p2);
+	printk("	VGA0: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
+
+	n = (hw->vga1_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+	m1 = (hw->vga1_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+	m2 = (hw->vga1_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+	if (hw->vga_pd & VGAPD_1_P1_FORCE_DIV2)
+		p1 = 0;
+	else
+		p1 = (hw->vga_pd >> VGAPD_1_P1_SHIFT) & DPLL_P1_MASK;
+	p2 = (hw->vga_pd >> VGAPD_1_P2_SHIFT) & DPLL_P2_MASK;
+	printk("	VGA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
+		m1, m2, n, p1, p2);
+	printk("	VGA1: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
+
+	printk("	DPLL_A:			0x%08x\n", hw->dpll_a);
+	printk("	DPLL_B:			0x%08x\n", hw->dpll_b);
+	printk("	FPA0:			0x%08x\n", hw->fpa0);
+	printk("	FPA1:			0x%08x\n", hw->fpa1);
+	printk("	FPB0:			0x%08x\n", hw->fpb0);
+	printk("	FPB1:			0x%08x\n", hw->fpb1);
+
+	n = (hw->fpa0 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+	m1 = (hw->fpa0 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+	m2 = (hw->fpa0 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+	if (hw->dpll_a & DPLL_P1_FORCE_DIV2)
+		p1 = 0;
+	else
+		p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
+	p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
+	printk("	PLLA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
+		m1, m2, n, p1, p2);
+	printk("	PLLA0: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
+
+	n = (hw->fpa1 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+	m1 = (hw->fpa1 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+	m2 = (hw->fpa1 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+	if (hw->dpll_a & DPLL_P1_FORCE_DIV2)
+		p1 = 0;
+	else
+		p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
+	p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
+	printk("	PLLA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
+		m1, m2, n, p1, p2);
+	printk("	PLLA1: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
+
+#if 0
+	printk("	PALETTE_A:\n");
+	for (i = 0; i < PALETTE_8_ENTRIES)
+		printk("	%3d:	0x%08x\n", i, hw->palette_a[i];
+	printk("	PALETTE_B:\n");
+	for (i = 0; i < PALETTE_8_ENTRIES)
+		printk("	%3d:	0x%08x\n", i, hw->palette_b[i];
+#endif
+
+	printk("	HTOTAL_A:		0x%08x\n", hw->htotal_a);
+	printk("	HBLANK_A:		0x%08x\n", hw->hblank_a);
+	printk("	HSYNC_A:		0x%08x\n", hw->hsync_a);
+	printk("	VTOTAL_A:		0x%08x\n", hw->vtotal_a);
+	printk("	VBLANK_A:		0x%08x\n", hw->vblank_a);
+	printk("	VSYNC_A:		0x%08x\n", hw->vsync_a);
+	printk("	SRC_SIZE_A:		0x%08x\n", hw->src_size_a);
+	printk("	BCLRPAT_A:		0x%08x\n", hw->bclrpat_a);
+	printk("	HTOTAL_B:		0x%08x\n", hw->htotal_b);
+	printk("	HBLANK_B:		0x%08x\n", hw->hblank_b);
+	printk("	HSYNC_B:		0x%08x\n", hw->hsync_b);
+	printk("	VTOTAL_B:		0x%08x\n", hw->vtotal_b);
+	printk("	VBLANK_B:		0x%08x\n", hw->vblank_b);
+	printk("	VSYNC_B:		0x%08x\n", hw->vsync_b);
+	printk("	SRC_SIZE_B:		0x%08x\n", hw->src_size_b);
+	printk("	BCLRPAT_B:		0x%08x\n", hw->bclrpat_b);
+
+	printk("	ADPA:			0x%08x\n", hw->adpa);
+	printk("	DVOA:			0x%08x\n", hw->dvoa);
+	printk("	DVOB:			0x%08x\n", hw->dvob);
+	printk("	DVOC:			0x%08x\n", hw->dvoc);
+	printk("	DVOA_SRCDIM:		0x%08x\n", hw->dvoa_srcdim);
+	printk("	DVOB_SRCDIM:		0x%08x\n", hw->dvob_srcdim);
+	printk("	DVOC_SRCDIM:		0x%08x\n", hw->dvoc_srcdim);
+	printk("	LVDS:			0x%08x\n", hw->lvds);
+
+	printk("	PIPEACONF:		0x%08x\n", hw->pipe_a_conf);
+	printk("	PIPEBCONF:		0x%08x\n", hw->pipe_b_conf);
+	printk("	DISPARB:		0x%08x\n", hw->disp_arb);
+
+	printk("	CURSOR_A_CONTROL:	0x%08x\n", hw->cursor_a_control);
+	printk("	CURSOR_B_CONTROL:	0x%08x\n", hw->cursor_b_control);
+	printk("	CURSOR_A_BASEADDR:	0x%08x\n", hw->cursor_a_base);
+	printk("	CURSOR_B_BASEADDR:	0x%08x\n", hw->cursor_b_base);
+
+	printk("	CURSOR_A_PALETTE:	");
+	for (i = 0; i < 4; i++) {
+		printk("0x%08x", hw->cursor_a_palette[i]);
+		if (i < 3)
+			printk(", ");
+	}
+	printk("\n");
+	printk("	CURSOR_B_PALETTE:	");
+	for (i = 0; i < 4; i++) {
+		printk("0x%08x", hw->cursor_b_palette[i]);
+		if (i < 3)
+			printk(", ");
+	}
+	printk("\n");
+
+	printk("	CURSOR_SIZE:		0x%08x\n", hw->cursor_size);
+
+	printk("	DSPACNTR:		0x%08x\n", hw->disp_a_ctrl);
+	printk("	DSPBCNTR:		0x%08x\n", hw->disp_b_ctrl);
+	printk("	DSPABASE:		0x%08x\n", hw->disp_a_base);
+	printk("	DSPBBASE:		0x%08x\n", hw->disp_b_base);
+	printk("	DSPASTRIDE:		0x%08x\n", hw->disp_a_stride);
+	printk("	DSPBSTRIDE:		0x%08x\n", hw->disp_b_stride);
+
+	printk("	VGACNTRL:		0x%08x\n", hw->vgacntrl);
+	printk("	ADD_ID:			0x%08x\n", hw->add_id);
+
+	for (i = 0; i < 7; i++) {
+		printk("	SWF0%d			0x%08x\n", i,
+			hw->swf0x[i]);
+	}
+	for (i = 0; i < 7; i++) {
+		printk("	SWF1%d			0x%08x\n", i,
+			hw->swf1x[i]);
+	}
+	for (i = 0; i < 3; i++) {
+		printk("	SWF3%d			0x%08x\n", i,
+			hw->swf3x[i]);
+	}
+	for (i = 0; i < 8; i++)
+		printk("	FENCE%d			0x%08x\n", i,
+			hw->fence[i]);
+
+	printk("	INSTPM			0x%08x\n", hw->instpm);
+	printk("	MEM_MODE		0x%08x\n", hw->mem_mode);
+	printk("	FW_BLC_0		0x%08x\n", hw->fw_blc_0);
+	printk("	FW_BLC_1		0x%08x\n", hw->fw_blc_1);
+
+	printk("hw state dump end\n");
+#endif
+}
+
+/* Split the M parameter into M1 and M2. */
+static int
+splitm(unsigned int m, unsigned int *retm1, unsigned int *retm2)
+{
+	int m1, m2;
+
+	m1 = (m - 2 - (MIN_M2 + MAX_M2) / 2) / 5 - 2;
+	if (m1 < MIN_M1)
+		m1 = MIN_M1;
+	if (m1 > MAX_M1)
+		m1 = MAX_M1;
+	m2 = m - 5 * (m1 + 2) - 2;
+	if (m2 < MIN_M2 || m2 > MAX_M2 || m2 >= m1) {
+		return 1;
+	} else {
+		*retm1 = (unsigned int)m1;
+		*retm2 = (unsigned int)m2;
+		return 0;
+	}
+}
+
+/* Split the P parameter into P1 and P2. */
+static int
+splitp(unsigned int p, unsigned int *retp1, unsigned int *retp2)
+{
+	int p1, p2;
+
+	if (p % 4 == 0)
+		p2 = 1;
+	else
+		p2 = 0;
+	p1 = (p / (1 << (p2 + 1))) - 2;
+	if (p % 4 == 0 && p1 < MIN_P1) {
+		p2 = 0;
+		p1 = (p / (1 << (p2 + 1))) - 2;
+	}
+	if (p1  < MIN_P1 || p1 > MAX_P1 || (p1 + 2) * (1 << (p2 + 1)) != p) {
+		return 1;
+	} else {
+		*retp1 = (unsigned int)p1;
+		*retp2 = (unsigned int)p2;
+		return 0;
+	}
+}
+
+static int
+calc_pll_params(int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1,
+		u32 *retp2, u32 *retclock)
+{
+	u32 m1, m2, n, p1, p2, n1;
+	u32 f_vco, p, p_best = 0, m, f_out;
+	u32 err_max, err_target, err_best = 10000000;
+	u32 n_best = 0, m_best = 0, f_best, f_err;
+	u32 p_min, p_max, p_inc, div_min, div_max;
+
+	/* Accept 0.5% difference, but aim for 0.1% */
+	err_max = 5 * clock / 1000;
+	err_target = clock / 1000;
+
+	DBG_MSG("Clock is %d\n", clock);
+
+	div_max = MAX_VCO_FREQ / clock;
+	div_min = ROUND_UP_TO(MIN_VCO_FREQ, clock) / clock;
+
+	if (clock <= P_TRANSITION_CLOCK)
+		p_inc = 4;
+	else
+		p_inc = 2;
+	p_min = ROUND_UP_TO(div_min, p_inc);
+	p_max = ROUND_DOWN_TO(div_max, p_inc);
+	if (p_min < MIN_P)
+		p_min = 4;
+	if (p_max > MAX_P)
+		p_max = 128;
+
+	DBG_MSG("p range is %d-%d (%d)\n", p_min, p_max, p_inc);
+
+	p = p_min;
+	do {
+		if (splitp(p, &p1, &p2)) {
+			WRN_MSG("cannot split p = %d\n", p);
+			p += p_inc;
+			continue;
+		}
+		n = MIN_N;
+		f_vco = clock * p;
+
+		do {
+			m = ROUND_UP_TO(f_vco * n, PLL_REFCLK) / PLL_REFCLK;
+			if (m < MIN_M)
+				m = MIN_M;
+			if (m > MAX_M)
+				m = MAX_M;
+			f_out = CALC_VCLOCK3(m, n, p);
+			if (splitm(m, &m1, &m2)) {
+				WRN_MSG("cannot split m = %d\n", m);
+				n++;
+				continue;
+			}
+			if (clock > f_out)
+				f_err = clock - f_out;
+			else
+				f_err = f_out - clock;
+
+			if (f_err < err_best) {
+				m_best = m;
+				n_best = n;
+				p_best = p;
+				f_best = f_out;
+				err_best = f_err;
+			}
+			n++;
+		} while ((n <= MAX_N) && (f_out >= clock));
+		p += p_inc;
+	} while ((p <= p_max));
+
+	if (!m_best) {
+		WRN_MSG("cannot find parameters for clock %d\n", clock);
+		return 1;
+	}
+	m = m_best;
+	n = n_best;
+	p = p_best;
+	splitm(m, &m1, &m2);
+	splitp(p, &p1, &p2);
+	n1 = n - 2;
+
+	DBG_MSG("m, n, p: %d (%d,%d), %d (%d), %d (%d,%d), "
+		"f: %d (%d), VCO: %d\n",
+		m, m1, m2, n, n1, p, p1, p2,
+		CALC_VCLOCK3(m, n, p), CALC_VCLOCK(m1, m2, n1, p1, p2),
+		CALC_VCLOCK3(m, n, p) * p);
+	*retm1 = m1;
+	*retm2 = m2;
+	*retn = n1;
+	*retp1 = p1;
+	*retp2 = p2;
+	*retclock = CALC_VCLOCK(m1, m2, n1, p1, p2);
+
+	return 0;
+}
+
+static __inline__ int
+check_overflow(u32 value, u32 limit, const char *description)
+{
+	if (value > limit) {
+		WRN_MSG("%s value %d exceeds limit %d\n",
+			description, value, limit);
+		return 1;
+	}
+	return 0;
+}
+
+/* It is assumed that hw is filled in with the initial state information. */
+int
+intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
+		     struct fb_var_screeninfo *var)
+{
+	int pipe = PIPE_A;
+	u32 *dpll, *fp0, *fp1;
+	u32 m1, m2, n, p1, p2, clock_target, clock;
+	u32 hsync_start, hsync_end, hblank_start, hblank_end, htotal, hactive;
+	u32 vsync_start, vsync_end, vblank_start, vblank_end, vtotal, vactive;
+	u32 vsync_pol, hsync_pol;
+	u32 *vs, *vb, *vt, *hs, *hb, *ht, *ss, *pipe_conf;
+
+	DBG_MSG("intelfbhw_mode_to_hw\n");
+
+	/* Disable VGA */
+	hw->vgacntrl |= VGA_DISABLE;
+
+	/* Check whether pipe A or pipe B is enabled. */
+	if (hw->pipe_a_conf & PIPECONF_ENABLE)
+		pipe = PIPE_A;
+	else if (hw->pipe_b_conf & PIPECONF_ENABLE)
+		pipe = PIPE_B;
+
+	/* Set which pipe's registers will be set. */
+	if (pipe == PIPE_B) {
+		dpll = &hw->dpll_b;
+		fp0 = &hw->fpb0;
+		fp1 = &hw->fpb1;
+		hs = &hw->hsync_b;
+		hb = &hw->hblank_b;
+		ht = &hw->htotal_b;
+		vs = &hw->vsync_b;
+		vb = &hw->vblank_b;
+		vt = &hw->vtotal_b;
+		ss = &hw->src_size_b;
+		pipe_conf = &hw->pipe_b_conf;
+	} else {
+		dpll = &hw->dpll_a;
+		fp0 = &hw->fpa0;
+		fp1 = &hw->fpa1;
+		hs = &hw->hsync_a;
+		hb = &hw->hblank_a;
+		ht = &hw->htotal_a;
+		vs = &hw->vsync_a;
+		vb = &hw->vblank_a;
+		vt = &hw->vtotal_a;
+		ss = &hw->src_size_a;
+		pipe_conf = &hw->pipe_a_conf;
+	}
+
+	/* Use ADPA register for sync control. */
+	hw->adpa &= ~ADPA_USE_VGA_HVPOLARITY;
+
+	/* sync polarity */
+	hsync_pol = (var->sync & FB_SYNC_HOR_HIGH_ACT) ?
+			ADPA_SYNC_ACTIVE_HIGH : ADPA_SYNC_ACTIVE_LOW;
+	vsync_pol = (var->sync & FB_SYNC_VERT_HIGH_ACT) ?
+			ADPA_SYNC_ACTIVE_HIGH : ADPA_SYNC_ACTIVE_LOW;
+	hw->adpa &= ~((ADPA_SYNC_ACTIVE_MASK << ADPA_VSYNC_ACTIVE_SHIFT) |
+		      (ADPA_SYNC_ACTIVE_MASK << ADPA_HSYNC_ACTIVE_SHIFT));
+	hw->adpa |= (hsync_pol << ADPA_HSYNC_ACTIVE_SHIFT) |
+		    (vsync_pol << ADPA_VSYNC_ACTIVE_SHIFT);
+
+	/* Connect correct pipe to the analog port DAC */
+	hw->adpa &= ~(PIPE_MASK << ADPA_PIPE_SELECT_SHIFT);
+	hw->adpa |= (pipe << ADPA_PIPE_SELECT_SHIFT);
+
+	/* Set DPMS state to D0 (on) */
+	hw->adpa &= ~ADPA_DPMS_CONTROL_MASK;
+	hw->adpa |= ADPA_DPMS_D0;
+
+	hw->adpa |= ADPA_DAC_ENABLE;
+
+	*dpll |= (DPLL_VCO_ENABLE | DPLL_VGA_MODE_DISABLE);
+	*dpll &= ~(DPLL_RATE_SELECT_MASK | DPLL_REFERENCE_SELECT_MASK);
+	*dpll |= (DPLL_REFERENCE_DEFAULT | DPLL_RATE_SELECT_FP0);
+
+	/* Desired clock in kHz */
+	clock_target = 1000000000 / var->pixclock;
+
+	if (calc_pll_params(clock_target, &m1, &m2, &n, &p1, &p2, &clock)) {
+		WRN_MSG("calc_pll_params failed\n");
+		return 1;
+	}
+
+	/* Check for overflow. */
+	if (check_overflow(p1, DPLL_P1_MASK, "PLL P1 parameter"))
+		return 1;
+	if (check_overflow(p2, DPLL_P2_MASK, "PLL P2 parameter"))
+		return 1;
+	if (check_overflow(m1, FP_DIVISOR_MASK, "PLL M1 parameter"))
+		return 1;
+	if (check_overflow(m2, FP_DIVISOR_MASK, "PLL M2 parameter"))
+		return 1;
+	if (check_overflow(n, FP_DIVISOR_MASK, "PLL N parameter"))
+		return 1;
+
+	*dpll &= ~DPLL_P1_FORCE_DIV2;
+	*dpll &= ~((DPLL_P2_MASK << DPLL_P2_SHIFT) |
+		   (DPLL_P1_MASK << DPLL_P1_SHIFT));
+	*dpll |= (p2 << DPLL_P2_SHIFT) | (p1 << DPLL_P1_SHIFT);
+	*fp0 = (n << FP_N_DIVISOR_SHIFT) |
+	       (m1 << FP_M1_DIVISOR_SHIFT) |
+	       (m2 << FP_M2_DIVISOR_SHIFT);
+	*fp1 = *fp0;
+
+	hw->dvob &= ~PORT_ENABLE;
+	hw->dvoc &= ~PORT_ENABLE;
+
+	/* Use display plane A. */
+	hw->disp_a_ctrl |= DISPPLANE_PLANE_ENABLE;
+	hw->disp_a_ctrl &= ~DISPPLANE_GAMMA_ENABLE;
+	hw->disp_a_ctrl &= ~DISPPLANE_PIXFORMAT_MASK;
+	switch (intelfb_var_to_depth(var)) {
+	case 8:
+		hw->disp_a_ctrl |= DISPPLANE_8BPP | DISPPLANE_GAMMA_ENABLE;
+		break;
+	case 15:
+		hw->disp_a_ctrl |= DISPPLANE_15_16BPP;
+		break;
+	case 16:
+		hw->disp_a_ctrl |= DISPPLANE_16BPP;
+		break;
+	case 24:
+		hw->disp_a_ctrl |= DISPPLANE_32BPP_NO_ALPHA;
+		break;
+	}
+	hw->disp_a_ctrl &= ~(PIPE_MASK << DISPPLANE_SEL_PIPE_SHIFT);
+	hw->disp_a_ctrl |= (pipe << DISPPLANE_SEL_PIPE_SHIFT);
+
+	/* Set CRTC registers. */
+	hactive = var->xres;
+	hsync_start = hactive + var->right_margin;
+	hsync_end = hsync_start + var->hsync_len;
+	htotal = hsync_end + var->left_margin;
+	hblank_start = hactive;
+	hblank_end = htotal;
+
+	DBG_MSG("H: act %d, ss %d, se %d, tot %d bs %d, be %d\n",
+		hactive, hsync_start, hsync_end, htotal, hblank_start,
+		hblank_end);
+
+	vactive = var->yres;
+	vsync_start = vactive + var->lower_margin;
+	vsync_end = vsync_start + var->vsync_len;
+	vtotal = vsync_end + var->upper_margin;
+	vblank_start = vactive;
+	vblank_end = vtotal;
+	vblank_end = vsync_end + 1;
+
+	DBG_MSG("V: act %d, ss %d, se %d, tot %d bs %d, be %d\n",
+		vactive, vsync_start, vsync_end, vtotal, vblank_start,
+		vblank_end);
+
+	/* Adjust for register values, and check for overflow. */
+	hactive--;
+	if (check_overflow(hactive, HACTIVE_MASK, "CRTC hactive"))
+		return 1;
+	hsync_start--;
+	if (check_overflow(hsync_start, HSYNCSTART_MASK, "CRTC hsync_start"))
+		return 1;
+	hsync_end--;
+	if (check_overflow(hsync_end, HSYNCEND_MASK, "CRTC hsync_end"))
+		return 1;
+	htotal--;
+	if (check_overflow(htotal, HTOTAL_MASK, "CRTC htotal"))
+		return 1;
+	hblank_start--;
+	if (check_overflow(hblank_start, HBLANKSTART_MASK, "CRTC hblank_start"))
+		return 1;
+	hblank_end--;
+	if (check_overflow(hblank_end, HBLANKEND_MASK, "CRTC hblank_end"))
+		return 1;
+
+	vactive--;
+	if (check_overflow(vactive, VACTIVE_MASK, "CRTC vactive"))
+		return 1;
+	vsync_start--;
+	if (check_overflow(vsync_start, VSYNCSTART_MASK, "CRTC vsync_start"))
+		return 1;
+	vsync_end--;
+	if (check_overflow(vsync_end, VSYNCEND_MASK, "CRTC vsync_end"))
+		return 1;
+	vtotal--;
+	if (check_overflow(vtotal, VTOTAL_MASK, "CRTC vtotal"))
+		return 1;
+	vblank_start--;
+	if (check_overflow(vblank_start, VBLANKSTART_MASK, "CRTC vblank_start"))
+		return 1;
+	vblank_end--;
+	if (check_overflow(vblank_end, VBLANKEND_MASK, "CRTC vblank_end"))
+		return 1;
+
+	*ht = (htotal << HTOTAL_SHIFT) | (hactive << HACTIVE_SHIFT);
+	*hb = (hblank_start << HBLANKSTART_SHIFT) |
+	      (hblank_end << HSYNCEND_SHIFT);
+	*hs = (hsync_start << HSYNCSTART_SHIFT) | (hsync_end << HSYNCEND_SHIFT);
+
+	*vt = (vtotal << VTOTAL_SHIFT) | (vactive << VACTIVE_SHIFT);
+	*vb = (vblank_start << VBLANKSTART_SHIFT) |
+	      (vblank_end << VSYNCEND_SHIFT);
+	*vs = (vsync_start << VSYNCSTART_SHIFT) | (vsync_end << VSYNCEND_SHIFT);
+	*ss = (hactive << SRC_SIZE_HORIZ_SHIFT) |
+	      (vactive << SRC_SIZE_VERT_SHIFT);
+
+	hw->disp_a_stride = var->xres_virtual * var->bits_per_pixel / 8;
+	DBG_MSG("pitch is %d\n", hw->disp_a_stride);
+
+	hw->disp_a_base = hw->disp_a_stride * var->yoffset +
+			  var->xoffset * var->bits_per_pixel / 8;
+
+	hw->disp_a_base += dinfo->fb.offset << 12;
+
+	/* Check stride alignment. */
+	if (hw->disp_a_stride % STRIDE_ALIGNMENT != 0) {
+		WRN_MSG("display stride %d has bad alignment %d\n",
+			hw->disp_a_stride, STRIDE_ALIGNMENT);
+		return 1;
+	}
+
+	/* Set the palette to 8-bit mode. */
+	*pipe_conf &= ~PIPECONF_GAMMA;
+	return 0;
+}
+
+/* Program a (non-VGA) video mode. */
+int
+intelfbhw_program_mode(struct intelfb_info *dinfo,
+		     const struct intelfb_hwstate *hw, int blank)
+{
+	int pipe = PIPE_A;
+	u32 tmp;
+	const u32 *dpll, *fp0, *fp1, *pipe_conf;
+	const u32 *hs, *ht, *hb, *vs, *vt, *vb, *ss;
+	u32 dpll_reg, fp0_reg, fp1_reg, pipe_conf_reg;
+	u32 hsync_reg, htotal_reg, hblank_reg;
+	u32 vsync_reg, vtotal_reg, vblank_reg;
+	u32 src_size_reg;
+
+	/* Assume single pipe, display plane A, analog CRT. */
+
+#if VERBOSE > 0
+	DBG_MSG("intelfbhw_program_mode\n");
+#endif
+
+	/* Disable VGA */
+	tmp = INREG(VGACNTRL);
+	tmp |= VGA_DISABLE;
+	OUTREG(VGACNTRL, tmp);
+
+	/* Check whether pipe A or pipe B is enabled. */
+	if (hw->pipe_a_conf & PIPECONF_ENABLE)
+		pipe = PIPE_A;
+	else if (hw->pipe_b_conf & PIPECONF_ENABLE)
+		pipe = PIPE_B;
+
+	dinfo->pipe = pipe;
+
+	if (pipe == PIPE_B) {
+		dpll = &hw->dpll_b;
+		fp0 = &hw->fpb0;
+		fp1 = &hw->fpb1;
+		pipe_conf = &hw->pipe_b_conf;
+		hs = &hw->hsync_b;
+		hb = &hw->hblank_b;
+		ht = &hw->htotal_b;
+		vs = &hw->vsync_b;
+		vb = &hw->vblank_b;
+		vt = &hw->vtotal_b;
+		ss = &hw->src_size_b;
+		dpll_reg = DPLL_B;
+		fp0_reg = FPB0;
+		fp1_reg = FPB1;
+		pipe_conf_reg = PIPEBCONF;
+		hsync_reg = HSYNC_B;
+		htotal_reg = HTOTAL_B;
+		hblank_reg = HBLANK_B;
+		vsync_reg = VSYNC_B;
+		vtotal_reg = VTOTAL_B;
+		vblank_reg = VBLANK_B;
+		src_size_reg = SRC_SIZE_B;
+	} else {
+		dpll = &hw->dpll_a;
+		fp0 = &hw->fpa0;
+		fp1 = &hw->fpa1;
+		pipe_conf = &hw->pipe_a_conf;
+		hs = &hw->hsync_a;
+		hb = &hw->hblank_a;
+		ht = &hw->htotal_a;
+		vs = &hw->vsync_a;
+		vb = &hw->vblank_a;
+		vt = &hw->vtotal_a;
+		ss = &hw->src_size_a;
+		dpll_reg = DPLL_A;
+		fp0_reg = FPA0;
+		fp1_reg = FPA1;
+		pipe_conf_reg = PIPEACONF;
+		hsync_reg = HSYNC_A;
+		htotal_reg = HTOTAL_A;
+		hblank_reg = HBLANK_A;
+		vsync_reg = VSYNC_A;
+		vtotal_reg = VTOTAL_A;
+		vblank_reg = VBLANK_A;
+		src_size_reg = SRC_SIZE_A;
+	}
+
+	/* Disable planes A and B. */
+	tmp = INREG(DSPACNTR);
+	tmp &= ~DISPPLANE_PLANE_ENABLE;
+	OUTREG(DSPACNTR, tmp);
+	tmp = INREG(DSPBCNTR);
+	tmp &= ~DISPPLANE_PLANE_ENABLE;
+	OUTREG(DSPBCNTR, tmp);
+
+	/* Wait for vblank.  For now, just wait for a 50Hz cycle (20ms)) */
+	mdelay(20);
+
+	/* Disable Sync */
+	tmp = INREG(ADPA);
+	tmp &= ~ADPA_DPMS_CONTROL_MASK;
+	tmp |= ADPA_DPMS_D3;
+	OUTREG(ADPA, tmp);
+
+	/* turn off pipe */
+	tmp = INREG(pipe_conf_reg);
+	tmp &= ~PIPECONF_ENABLE;
+	OUTREG(pipe_conf_reg, tmp);
+
+	/* turn off PLL */
+	tmp = INREG(dpll_reg);
+	dpll_reg &= ~DPLL_VCO_ENABLE;
+	OUTREG(dpll_reg, tmp);
+
+	/* Set PLL parameters */
+	OUTREG(dpll_reg, *dpll & ~DPLL_VCO_ENABLE);
+	OUTREG(fp0_reg, *fp0);
+	OUTREG(fp1_reg, *fp1);
+
+	/* Set pipe parameters */
+	OUTREG(hsync_reg, *hs);
+	OUTREG(hblank_reg, *hb);
+	OUTREG(htotal_reg, *ht);
+	OUTREG(vsync_reg, *vs);
+	OUTREG(vblank_reg, *vb);
+	OUTREG(vtotal_reg, *vt);
+	OUTREG(src_size_reg, *ss);
+
+	/* Set DVOs B/C */
+	OUTREG(DVOB, hw->dvob);
+	OUTREG(DVOC, hw->dvoc);
+
+	/* Set ADPA */
+	OUTREG(ADPA, (hw->adpa & ~(ADPA_DPMS_CONTROL_MASK)) | ADPA_DPMS_D3);
+
+	/* Enable PLL */
+	tmp = INREG(dpll_reg);
+	tmp |= DPLL_VCO_ENABLE;
+	OUTREG(dpll_reg, tmp);
+
+	/* Enable pipe */
+	OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE);
+
+	/* Enable sync */
+	tmp = INREG(ADPA);
+	tmp &= ~ADPA_DPMS_CONTROL_MASK;
+	tmp |= ADPA_DPMS_D0;
+	OUTREG(ADPA, tmp);
+
+	/* setup display plane */
+	if (dinfo->pdev->device == PCI_DEVICE_ID_INTEL_830M) {
+		/*
+		 *      i830M errata: the display plane must be enabled
+		 *      to allow writes to the other bits in the plane
+		 *      control register.
+		 */
+		tmp = INREG(DSPACNTR);
+		if ((tmp & DISPPLANE_PLANE_ENABLE) != DISPPLANE_PLANE_ENABLE) {
+			tmp |= DISPPLANE_PLANE_ENABLE;
+			OUTREG(DSPACNTR, tmp);
+			OUTREG(DSPACNTR,
+			       hw->disp_a_ctrl|DISPPLANE_PLANE_ENABLE);
+			mdelay(1);
+              }
+	}
+
+	OUTREG(DSPACNTR, hw->disp_a_ctrl & ~DISPPLANE_PLANE_ENABLE);
+	OUTREG(DSPASTRIDE, hw->disp_a_stride);
+	OUTREG(DSPABASE, hw->disp_a_base);
+
+	/* Enable plane */
+	if (!blank) {
+		tmp = INREG(DSPACNTR);
+		tmp |= DISPPLANE_PLANE_ENABLE;
+		OUTREG(DSPACNTR, tmp);
+		OUTREG(DSPABASE, hw->disp_a_base);
+	}
+
+	return 0;
+}
+
+/* forward declarations */
+static void refresh_ring(struct intelfb_info *dinfo);
+static void reset_state(struct intelfb_info *dinfo);
+static void do_flush(struct intelfb_info *dinfo);
+
+static int
+wait_ring(struct intelfb_info *dinfo, int n)
+{
+	int i = 0;
+	unsigned long end;
+	u32 last_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK;
+
+#if VERBOSE > 0
+	DBG_MSG("wait_ring: %d\n", n);
+#endif
+
+	end = jiffies + (HZ * 3);
+	while (dinfo->ring_space < n) {
+		dinfo->ring_head = (u8 __iomem *)(INREG(PRI_RING_HEAD) &
+						   RING_HEAD_MASK);
+		if (dinfo->ring_tail + RING_MIN_FREE <
+		    (u32 __iomem) dinfo->ring_head)
+			dinfo->ring_space = (u32 __iomem) dinfo->ring_head
+				- (dinfo->ring_tail + RING_MIN_FREE);
+		else
+			dinfo->ring_space = (dinfo->ring.size +
+					     (u32 __iomem) dinfo->ring_head)
+				- (dinfo->ring_tail + RING_MIN_FREE);
+		if ((u32 __iomem) dinfo->ring_head != last_head) {
+			end = jiffies + (HZ * 3);
+			last_head = (u32 __iomem) dinfo->ring_head;
+		}
+		i++;
+		if (time_before(end, jiffies)) {
+			if (!i) {
+				/* Try again */
+				reset_state(dinfo);
+				refresh_ring(dinfo);
+				do_flush(dinfo);
+				end = jiffies + (HZ * 3);
+				i = 1;
+			} else {
+				WRN_MSG("ring buffer : space: %d wanted %d\n",
+					dinfo->ring_space, n);
+				WRN_MSG("lockup - turning off hardware "
+					"acceleration\n");
+				dinfo->ring_lockup = 1;
+				break;
+			}
+		}
+		udelay(1);
+	}
+	return i;
+}
+
+static void
+do_flush(struct intelfb_info *dinfo) {
+	START_RING(2);
+	OUT_RING(MI_FLUSH | MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE);
+	OUT_RING(MI_NOOP);
+	ADVANCE_RING();
+}
+
+void
+intelfbhw_do_sync(struct intelfb_info *dinfo)
+{
+#if VERBOSE > 0
+	DBG_MSG("intelfbhw_do_sync\n");
+#endif
+
+	if (!dinfo->accel)
+		return;
+
+	/*
+	 * Send a flush, then wait until the ring is empty.  This is what
+	 * the XFree86 driver does, and actually it doesn't seem a lot worse
+	 * than the recommended method (both have problems).
+	 */
+	do_flush(dinfo);
+	wait_ring(dinfo, dinfo->ring.size - RING_MIN_FREE);
+	dinfo->ring_space = dinfo->ring.size - RING_MIN_FREE;
+}
+
+static void
+refresh_ring(struct intelfb_info *dinfo)
+{
+#if VERBOSE > 0
+	DBG_MSG("refresh_ring\n");
+#endif
+
+	dinfo->ring_head = (u8 __iomem *) (INREG(PRI_RING_HEAD) &
+					   RING_HEAD_MASK);
+	dinfo->ring_tail = INREG(PRI_RING_TAIL) & RING_TAIL_MASK;
+	if (dinfo->ring_tail + RING_MIN_FREE < (u32 __iomem)dinfo->ring_head)
+		dinfo->ring_space = (u32 __iomem) dinfo->ring_head
+			- (dinfo->ring_tail + RING_MIN_FREE);
+	else
+		dinfo->ring_space = (dinfo->ring.size +
+				     (u32 __iomem) dinfo->ring_head)
+			- (dinfo->ring_tail + RING_MIN_FREE);
+}
+
+static void
+reset_state(struct intelfb_info *dinfo)
+{
+	int i;
+	u32 tmp;
+
+#if VERBOSE > 0
+	DBG_MSG("reset_state\n");
+#endif
+
+	for (i = 0; i < FENCE_NUM; i++)
+		OUTREG(FENCE + (i << 2), 0);
+
+	/* Flush the ring buffer if it's enabled. */
+	tmp = INREG(PRI_RING_LENGTH);
+	if (tmp & RING_ENABLE) {
+#if VERBOSE > 0
+		DBG_MSG("reset_state: ring was enabled\n");
+#endif
+		refresh_ring(dinfo);
+		intelfbhw_do_sync(dinfo);
+		DO_RING_IDLE();
+	}
+
+	OUTREG(PRI_RING_LENGTH, 0);
+	OUTREG(PRI_RING_HEAD, 0);
+	OUTREG(PRI_RING_TAIL, 0);
+	OUTREG(PRI_RING_START, 0);
+}
+
+/* Stop the 2D engine, and turn off the ring buffer. */
+void
+intelfbhw_2d_stop(struct intelfb_info *dinfo)
+{
+#if VERBOSE > 0
+	DBG_MSG("intelfbhw_2d_stop: accel: %d, ring_active: %d\n", dinfo->accel,
+		dinfo->ring_active);
+#endif
+
+	if (!dinfo->accel)
+		return;
+
+	dinfo->ring_active = 0;
+	reset_state(dinfo);
+}
+
+/*
+ * Enable the ring buffer, and initialise the 2D engine.
+ * It is assumed that the graphics engine has been stopped by previously
+ * calling intelfb_2d_stop().
+ */
+void
+intelfbhw_2d_start(struct intelfb_info *dinfo)
+{
+#if VERBOSE > 0
+	DBG_MSG("intelfbhw_2d_start: accel: %d, ring_active: %d\n",
+		dinfo->accel, dinfo->ring_active);
+#endif
+
+	if (!dinfo->accel)
+		return;
+
+	/* Initialise the primary ring buffer. */
+	OUTREG(PRI_RING_LENGTH, 0);
+	OUTREG(PRI_RING_TAIL, 0);
+	OUTREG(PRI_RING_HEAD, 0);
+
+	OUTREG(PRI_RING_START, dinfo->ring.physical & RING_START_MASK);
+	OUTREG(PRI_RING_LENGTH,
+		((dinfo->ring.size - GTT_PAGE_SIZE) & RING_LENGTH_MASK) |
+		RING_NO_REPORT | RING_ENABLE);
+	refresh_ring(dinfo);
+	dinfo->ring_active = 1;
+}
+
+/* 2D fillrect (solid fill or invert) */
+void
+intelfbhw_do_fillrect(struct intelfb_info *dinfo, u32 x, u32 y, u32 w, u32 h,
+		      u32 color, u32 pitch, u32 bpp, u32 rop)
+{
+	u32 br00, br09, br13, br14, br16;
+
+#if VERBOSE > 0
+	DBG_MSG("intelfbhw_do_fillrect: (%d,%d) %dx%d, c 0x%06x, p %d bpp %d, "
+		"rop 0x%02x\n", x, y, w, h, color, pitch, bpp, rop);
+#endif
+
+	br00 = COLOR_BLT_CMD;
+	br09 = dinfo->fb_start + (y * pitch + x * (bpp / 8));
+	br13 = (rop << ROP_SHIFT) | pitch;
+	br14 = (h << HEIGHT_SHIFT) | ((w * (bpp / 8)) << WIDTH_SHIFT);
+	br16 = color;
+
+	switch (bpp) {
+	case 8:
+		br13 |= COLOR_DEPTH_8;
+		break;
+	case 16:
+		br13 |= COLOR_DEPTH_16;
+		break;
+	case 32:
+		br13 |= COLOR_DEPTH_32;
+		br00 |= WRITE_ALPHA | WRITE_RGB;
+		break;
+	}
+
+	START_RING(6);
+	OUT_RING(br00);
+	OUT_RING(br13);
+	OUT_RING(br14);
+	OUT_RING(br09);
+	OUT_RING(br16);
+	OUT_RING(MI_NOOP);
+	ADVANCE_RING();
+
+#if VERBOSE > 0
+	DBG_MSG("ring = 0x%08x, 0x%08x (%d)\n", dinfo->ring_head,
+		dinfo->ring_tail, dinfo->ring_space);
+#endif
+}
+
+void
+intelfbhw_do_bitblt(struct intelfb_info *dinfo, u32 curx, u32 cury,
+		    u32 dstx, u32 dsty, u32 w, u32 h, u32 pitch, u32 bpp)
+{
+	u32 br00, br09, br11, br12, br13, br22, br23, br26;
+
+#if VERBOSE > 0
+	DBG_MSG("intelfbhw_do_bitblt: (%d,%d)->(%d,%d) %dx%d, p %d bpp %d\n",
+		curx, cury, dstx, dsty, w, h, pitch, bpp);
+#endif
+
+	br00 = XY_SRC_COPY_BLT_CMD;
+	br09 = dinfo->fb_start;
+	br11 = (pitch << PITCH_SHIFT);
+	br12 = dinfo->fb_start;
+	br13 = (SRC_ROP_GXCOPY << ROP_SHIFT) | (pitch << PITCH_SHIFT);
+	br22 = (dstx << WIDTH_SHIFT) | (dsty << HEIGHT_SHIFT);
+	br23 = ((dstx + w) << WIDTH_SHIFT) |
+	       ((dsty + h) << HEIGHT_SHIFT);
+	br26 = (curx << WIDTH_SHIFT) | (cury << HEIGHT_SHIFT);
+
+	switch (bpp) {
+	case 8:
+		br13 |= COLOR_DEPTH_8;
+		break;
+	case 16:
+		br13 |= COLOR_DEPTH_16;
+		break;
+	case 32:
+		br13 |= COLOR_DEPTH_32;
+		br00 |= WRITE_ALPHA | WRITE_RGB;
+		break;
+	}
+
+	START_RING(8);
+	OUT_RING(br00);
+	OUT_RING(br13);
+	OUT_RING(br22);
+	OUT_RING(br23);
+	OUT_RING(br09);
+	OUT_RING(br26);
+	OUT_RING(br11);
+	OUT_RING(br12);
+	ADVANCE_RING();
+}
+
+int
+intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg, u32 w,
+		       u32 h, const u8* cdat, u32 x, u32 y, u32 pitch, u32 bpp)
+{
+	int nbytes, ndwords, pad, tmp;
+	u32 br00, br09, br13, br18, br19, br22, br23;
+	int dat, ix, iy, iw;
+	int i, j;
+
+#if VERBOSE > 0
+	DBG_MSG("intelfbhw_do_drawglyph: (%d,%d) %dx%d\n", x, y, w, h);
+#endif
+
+	/* size in bytes of a padded scanline */
+	nbytes = ROUND_UP_TO(w, 16) / 8;
+
+	/* Total bytes of padded scanline data to write out. */
+	nbytes = nbytes * h;
+
+	/*
+	 * Check if the glyph data exceeds the immediate mode limit.
+	 * It would take a large font (1K pixels) to hit this limit.
+	 */
+	if (nbytes > MAX_MONO_IMM_SIZE)
+		return 0;
+
+	/* Src data is packaged a dword (32-bit) at a time. */
+	ndwords = ROUND_UP_TO(nbytes, 4) / 4;
+
+	/*
+	 * Ring has to be padded to a quad word. But because the command starts
+	   with 7 bytes, pad only if there is an even number of ndwords
+	 */
+	pad = !(ndwords % 2);
+
+	tmp = (XY_MONO_SRC_IMM_BLT_CMD & DW_LENGTH_MASK) + ndwords;
+	br00 = (XY_MONO_SRC_IMM_BLT_CMD & ~DW_LENGTH_MASK) | tmp;
+	br09 = dinfo->fb_start;
+	br13 = (SRC_ROP_GXCOPY << ROP_SHIFT) | (pitch << PITCH_SHIFT);
+	br18 = bg;
+	br19 = fg;
+	br22 = (x << WIDTH_SHIFT) | (y << HEIGHT_SHIFT);
+	br23 = ((x + w) << WIDTH_SHIFT) | ((y + h) << HEIGHT_SHIFT);
+
+	switch (bpp) {
+	case 8:
+		br13 |= COLOR_DEPTH_8;
+		break;
+	case 16:
+		br13 |= COLOR_DEPTH_16;
+		break;
+	case 32:
+		br13 |= COLOR_DEPTH_32;
+		br00 |= WRITE_ALPHA | WRITE_RGB;
+		break;
+	}
+
+	START_RING(8 + ndwords);
+	OUT_RING(br00);
+	OUT_RING(br13);
+	OUT_RING(br22);
+	OUT_RING(br23);
+	OUT_RING(br09);
+	OUT_RING(br18);
+	OUT_RING(br19);
+	ix = iy = 0;
+	iw = ROUND_UP_TO(w, 8) / 8;
+	while (ndwords--) {
+		dat = 0;
+		for (j = 0; j < 2; ++j) {
+			for (i = 0; i < 2; ++i) {
+				if (ix != iw || i == 0)
+					dat |= cdat[iy*iw + ix++] << (i+j*2)*8;
+			}
+			if (ix == iw && iy != (h-1)) {
+				ix = 0;
+				++iy;
+			}
+		}
+		OUT_RING(dat);
+	}
+	if (pad)
+		OUT_RING(MI_NOOP);
+	ADVANCE_RING();
+
+	return 1;
+}
+
+/* HW cursor functions. */
+void
+intelfbhw_cursor_init(struct intelfb_info *dinfo)
+{
+	u32 tmp;
+
+#if VERBOSE > 0
+	DBG_MSG("intelfbhw_cursor_init\n");
+#endif
+
+	if (dinfo->mobile) {
+		if (!dinfo->cursor.physical)
+			return;
+		tmp = INREG(CURSOR_A_CONTROL);
+		tmp &= ~(CURSOR_MODE_MASK | CURSOR_MOBILE_GAMMA_ENABLE |
+			 CURSOR_MEM_TYPE_LOCAL |
+			 (1 << CURSOR_PIPE_SELECT_SHIFT));
+		tmp |= CURSOR_MODE_DISABLE;
+		OUTREG(CURSOR_A_CONTROL, tmp);
+		OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical);
+	} else {
+		tmp = INREG(CURSOR_CONTROL);
+		tmp &= ~(CURSOR_FORMAT_MASK | CURSOR_GAMMA_ENABLE |
+			 CURSOR_ENABLE | CURSOR_STRIDE_MASK);
+		tmp = CURSOR_FORMAT_3C;
+		OUTREG(CURSOR_CONTROL, tmp);
+		OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.offset << 12);
+		tmp = (64 << CURSOR_SIZE_H_SHIFT) |
+		      (64 << CURSOR_SIZE_V_SHIFT);
+		OUTREG(CURSOR_SIZE, tmp);
+	}
+}
+
+void
+intelfbhw_cursor_hide(struct intelfb_info *dinfo)
+{
+	u32 tmp;
+
+#if VERBOSE > 0
+	DBG_MSG("intelfbhw_cursor_hide\n");
+#endif
+
+	dinfo->cursor_on = 0;
+	if (dinfo->mobile) {
+		if (!dinfo->cursor.physical)
+			return;
+		tmp = INREG(CURSOR_A_CONTROL);
+		tmp &= ~CURSOR_MODE_MASK;
+		tmp |= CURSOR_MODE_DISABLE;
+		OUTREG(CURSOR_A_CONTROL, tmp);
+		/* Flush changes */
+		OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical);
+	} else {
+		tmp = INREG(CURSOR_CONTROL);
+		tmp &= ~CURSOR_ENABLE;
+		OUTREG(CURSOR_CONTROL, tmp);
+	}
+}
+
+void
+intelfbhw_cursor_show(struct intelfb_info *dinfo)
+{
+	u32 tmp;
+
+#if VERBOSE > 0
+	DBG_MSG("intelfbhw_cursor_show\n");
+#endif
+
+	dinfo->cursor_on = 1;
+
+	if (dinfo->cursor_blanked)
+		return;
+
+	if (dinfo->mobile) {
+		if (!dinfo->cursor.physical)
+			return;
+		tmp = INREG(CURSOR_A_CONTROL);
+		tmp &= ~CURSOR_MODE_MASK;
+		tmp |= CURSOR_MODE_64_4C_AX;
+		OUTREG(CURSOR_A_CONTROL, tmp);
+		/* Flush changes */
+		OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical);
+	} else {
+		tmp = INREG(CURSOR_CONTROL);
+		tmp |= CURSOR_ENABLE;
+		OUTREG(CURSOR_CONTROL, tmp);
+	}
+}
+
+void
+intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y)
+{
+	u32 tmp;
+
+#if VERBOSE > 0
+	DBG_MSG("intelfbhw_cursor_setpos: (%d, %d)\n", x, y);
+#endif
+
+	/*
+	 * Sets the position.  The coordinates are assumed to already
+	 * have any offset adjusted.  Assume that the cursor is never
+	 * completely off-screen, and that x, y are always >= 0.
+	 */
+
+	tmp = ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT) |
+	      ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
+	OUTREG(CURSOR_A_POSITION, tmp);
+}
+
+void
+intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, u32 fg)
+{
+#if VERBOSE > 0
+	DBG_MSG("intelfbhw_cursor_setcolor\n");
+#endif
+
+	OUTREG(CURSOR_A_PALETTE0, bg & CURSOR_PALETTE_MASK);
+	OUTREG(CURSOR_A_PALETTE1, fg & CURSOR_PALETTE_MASK);
+	OUTREG(CURSOR_A_PALETTE2, fg & CURSOR_PALETTE_MASK);
+	OUTREG(CURSOR_A_PALETTE3, bg & CURSOR_PALETTE_MASK);
+}
+
+void
+intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, int height,
+		      u8 *data)
+{
+	u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual;
+	int i, j, w = width / 8;
+	int mod = width % 8, t_mask, d_mask;
+
+#if VERBOSE > 0
+	DBG_MSG("intelfbhw_cursor_load\n");
+#endif
+
+	if (!dinfo->cursor.virtual)
+		return;
+
+	t_mask = 0xff >> mod;
+	d_mask = ~(0xff >> mod);
+	for (i = height; i--; ) {
+		for (j = 0; j < w; j++) {
+			writeb(0x00, addr + j);
+			writeb(*(data++), addr + j+8);
+		}
+		if (mod) {
+			writeb(t_mask, addr + j);
+			writeb(*(data++) & d_mask, addr + j+8);
+		}
+		addr += 16;
+	}
+}
+
+void
+intelfbhw_cursor_reset(struct intelfb_info *dinfo) {
+	u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual;
+	int i, j;
+
+#if VERBOSE > 0
+	DBG_MSG("intelfbhw_cursor_reset\n");
+#endif
+
+	if (!dinfo->cursor.virtual)
+		return;
+
+	for (i = 64; i--; ) {
+		for (j = 0; j < 8; j++) {
+			writeb(0xff, addr + j+0);
+			writeb(0x00, addr + j+8);
+		}
+		addr += 16;
+	}
+}
diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h
new file mode 100644
index 0000000..ba19201
--- /dev/null
+++ b/drivers/video/intelfb/intelfbhw.h
@@ -0,0 +1,570 @@
+#ifndef _INTELFBHW_H
+#define _INTELFBHW_H
+
+/* $DHD: intelfb/intelfbhw.h,v 1.5 2003/06/27 15:06:25 dawes Exp $ */
+
+
+/*** HW-specific data ***/
+
+/* Information about the 852GM/855GM variants */
+#define INTEL_85X_CAPID		0x44
+#define INTEL_85X_VARIANT_MASK		0x7
+#define INTEL_85X_VARIANT_SHIFT		5
+#define INTEL_VAR_855GME		0x0
+#define INTEL_VAR_855GM			0x4
+#define INTEL_VAR_852GME		0x2
+#define INTEL_VAR_852GM			0x5
+
+/* Information about DVO/LVDS Ports */
+#define DVOA_PORT  0x1
+#define DVOB_PORT  0x2
+#define DVOC_PORT  0x4
+#define LVDS_PORT  0x8
+
+/*
+ * The Bridge device's PCI config space has information about the
+ * fb aperture size and the amount of pre-reserved memory.
+ */
+#define INTEL_GMCH_CTRL		0x52
+#define INTEL_GMCH_ENABLED		0x4
+#define INTEL_GMCH_MEM_MASK		0x1
+#define INTEL_GMCH_MEM_64M		0x1
+#define INTEL_GMCH_MEM_128M		0
+
+#define INTEL_830_GMCH_GMS_MASK		(0x7 << 4)
+#define INTEL_830_GMCH_GMS_DISABLED	(0x0 << 4)
+#define INTEL_830_GMCH_GMS_LOCAL	(0x1 << 4)
+#define INTEL_830_GMCH_GMS_STOLEN_512	(0x2 << 4)
+#define INTEL_830_GMCH_GMS_STOLEN_1024	(0x3 << 4)
+#define INTEL_830_GMCH_GMS_STOLEN_8192	(0x4 << 4)
+
+#define INTEL_855_GMCH_GMS_MASK		(0x7 << 4)
+#define INTEL_855_GMCH_GMS_DISABLED	(0x0 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_1M	(0x1 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_4M	(0x2 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_8M	(0x3 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_16M	(0x4 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_32M	(0x5 << 4)
+
+#define INTEL_915G_GMCH_GMS_STOLEN_48M	(0x6 << 4)
+#define INTEL_915G_GMCH_GMS_STOLEN_64M	(0x7 << 4)
+
+/* HW registers */
+
+/* Fence registers */
+#define FENCE			0x2000
+#define FENCE_NUM			8
+
+/* Primary ring buffer */
+#define PRI_RING_TAIL		0x2030
+#define RING_TAIL_MASK			0x001ffff8
+#define RING_INUSE			0x1
+
+#define PRI_RING_HEAD		0x2034
+#define RING_HEAD_WRAP_MASK		0x7ff
+#define RING_HEAD_WRAP_SHIFT		21
+#define RING_HEAD_MASK			0x001ffffc
+
+#define PRI_RING_START		0x2038
+#define RING_START_MASK			0xfffff000
+
+#define PRI_RING_LENGTH		0x203c
+#define RING_LENGTH_MASK		0x001ff000
+#define RING_REPORT_MASK		(0x3 << 1)
+#define RING_NO_REPORT			(0x0 << 1)
+#define RING_REPORT_64K			(0x1 << 1)
+#define RING_REPORT_4K			(0x2 << 1)
+#define RING_REPORT_128K		(0x3 << 1)
+#define RING_ENABLE			0x1
+
+/*
+ * Tail can't wrap to any closer than RING_MIN_FREE bytes of the head,
+ * and the last RING_MIN_FREE bytes need to be padded with MI_NOOP
+ */
+#define RING_MIN_FREE			64
+
+#define IPEHR     		0x2088
+
+#define INSTDONE		0x2090
+#define PRI_RING_EMPTY			1
+
+#define INSTPM			0x20c0
+#define SYNC_FLUSH_ENABLE		(1 << 5)
+
+#define INSTPS			0x20c4
+
+#define MEM_MODE		0x20cc
+
+#define MASK_SHIFT			16
+
+#define FW_BLC_0		0x20d8
+#define FW_DISPA_WM_SHIFT		0
+#define FW_DISPA_WM_MASK		0x3f
+#define FW_DISPA_BL_SHIFT		8
+#define FW_DISPA_BL_MASK		0xf
+#define FW_DISPB_WM_SHIFT		16
+#define FW_DISPB_WM_MASK		0x1f
+#define FW_DISPB_BL_SHIFT		24
+#define FW_DISPB_BL_MASK		0x7
+
+#define FW_BLC_1		0x20dc
+#define FW_DISPC_WM_SHIFT		0
+#define FW_DISPC_WM_MASK		0x1f
+#define FW_DISPC_BL_SHIFT		8
+#define FW_DISPC_BL_MASK		0x7
+
+
+/* PLL registers */
+#define VGA0_DIVISOR		0x06000
+#define VGA1_DIVISOR		0x06004
+#define VGAPD			0x06010
+#define VGAPD_0_P1_SHIFT		0
+#define VGAPD_0_P1_FORCE_DIV2		(1 << 5)
+#define VGAPD_0_P2_SHIFT		7
+#define VGAPD_1_P1_SHIFT		8
+#define VGAPD_1_P1_FORCE_DIV2		(1 << 13)
+#define VGAPD_1_P2_SHIFT		15
+
+#define DPLL_A			0x06014
+#define DPLL_B			0x06018
+#define DPLL_VCO_ENABLE			(1 << 31)
+#define DPLL_2X_CLOCK_ENABLE		(1 << 30)
+#define DPLL_SYNCLOCK_ENABLE		(1 << 29)
+#define DPLL_VGA_MODE_DISABLE		(1 << 28)
+#define DPLL_P2_MASK			1
+#define DPLL_P2_SHIFT			23
+#define DPLL_P1_FORCE_DIV2		(1 << 21)
+#define DPLL_P1_MASK			0x1f
+#define DPLL_P1_SHIFT			16
+#define DPLL_REFERENCE_SELECT_MASK	(0x3 << 13)
+#define DPLL_REFERENCE_DEFAULT		(0x0 << 13)
+#define DPLL_REFERENCE_TVCLK		(0x2 << 13)
+#define DPLL_RATE_SELECT_MASK		(1 << 8)
+#define DPLL_RATE_SELECT_FP0		(0 << 8)
+#define DPLL_RATE_SELECT_FP1		(1 << 8)
+
+#define FPA0			0x06040
+#define FPA1			0x06044
+#define FPB0			0x06048
+#define FPB1			0x0604c
+#define FP_DIVISOR_MASK			0x3f
+#define FP_N_DIVISOR_SHIFT		16
+#define FP_M1_DIVISOR_SHIFT		8
+#define FP_M2_DIVISOR_SHIFT		0
+
+/* PLL parameters (these are for 852GM/855GM/865G, check earlier chips). */
+/* Clock values are in units of kHz */
+#define PLL_REFCLK		48000
+#define MIN_VCO_FREQ		930000
+#define MAX_VCO_FREQ		1400000
+#define MIN_CLOCK		25000
+#define MAX_CLOCK		350000
+#define P_TRANSITION_CLOCK	165000
+#define MIN_M			108
+#define MAX_M			140
+#define MIN_M1			18
+#define MAX_M1			26
+#define MIN_M2			6
+#define MAX_M2			16
+#define MIN_P			4
+#define MAX_P			128
+#define MIN_P1			0
+#define MAX_P1			31
+#define MIN_N			3
+#define MAX_N			16
+
+#define CALC_VCLOCK(m1, m2, n, p1, p2) \
+        ((PLL_REFCLK * (5 * ((m1) + 2) + ((m2) + 2)) / ((n) + 2)) / \
+        (((p1) + 2) * (1 << (p2 + 1))))
+
+#define CALC_VCLOCK3(m, n, p)	((PLL_REFCLK * (m) / (n)) / (p))
+
+/* Two pipes */
+#define PIPE_A			0
+#define PIPE_B			1
+#define PIPE_MASK		1
+
+/* palette registers */
+#define PALETTE_A		0x0a000
+#define PALETTE_B		0x0a800
+#ifndef PALETTE_8_ENTRIES
+#define PALETTE_8_ENTRIES		256
+#endif
+#define PALETTE_8_SIZE			(PALETTE_8_ENTRIES * 4)
+#define PALETTE_10_ENTRIES		128
+#define PALETTE_10_SIZE			(PALETTE_10_ENTRIES * 8)
+#define PALETTE_8_MASK			0xff
+#define PALETTE_8_RED_SHIFT		16
+#define PALETTE_8_GREEN_SHIFT		8
+#define PALETTE_8_BLUE_SHIFT		0
+
+/* CRTC registers */
+#define HTOTAL_A		0x60000
+#define HBLANK_A		0x60004
+#define HSYNC_A			0x60008
+#define VTOTAL_A		0x6000c
+#define VBLANK_A		0x60010
+#define VSYNC_A			0x60014
+#define SRC_SIZE_A		0x6001c
+#define BCLRPAT_A		0x60020
+
+#define HTOTAL_B		0x61000
+#define HBLANK_B		0x61004
+#define HSYNC_B			0x61008
+#define VTOTAL_B		0x6100c
+#define VBLANK_B		0x61010
+#define VSYNC_B			0x61014
+#define SRC_SIZE_B		0x6101c
+#define BCLRPAT_B		0x61020
+
+#define HTOTAL_MASK			0xfff
+#define HTOTAL_SHIFT			16
+#define HACTIVE_MASK			0x7ff
+#define HACTIVE_SHIFT			0
+#define HBLANKEND_MASK			0xfff
+#define HBLANKEND_SHIFT			16
+#define HBLANKSTART_MASK		0xfff
+#define HBLANKSTART_SHIFT		0
+#define HSYNCEND_MASK			0xfff
+#define HSYNCEND_SHIFT			16
+#define HSYNCSTART_MASK			0xfff
+#define HSYNCSTART_SHIFT		0
+#define VTOTAL_MASK			0xfff
+#define VTOTAL_SHIFT			16
+#define VACTIVE_MASK			0x7ff
+#define VACTIVE_SHIFT			0
+#define VBLANKEND_MASK			0xfff
+#define VBLANKEND_SHIFT			16
+#define VBLANKSTART_MASK		0xfff
+#define VBLANKSTART_SHIFT		0
+#define VSYNCEND_MASK			0xfff
+#define VSYNCEND_SHIFT			16
+#define VSYNCSTART_MASK			0xfff
+#define VSYNCSTART_SHIFT		0
+#define SRC_SIZE_HORIZ_MASK		0x7ff
+#define SRC_SIZE_HORIZ_SHIFT		16
+#define SRC_SIZE_VERT_MASK		0x7ff
+#define SRC_SIZE_VERT_SHIFT		0
+
+#define ADPA			0x61100
+#define ADPA_DAC_ENABLE			(1 << 31)
+#define ADPA_DAC_DISABLE		0
+#define ADPA_PIPE_SELECT_SHIFT		30
+#define ADPA_USE_VGA_HVPOLARITY		(1 << 15)
+#define ADPA_SETS_HVPOLARITY		0
+#define ADPA_DPMS_CONTROL_MASK		(0x3 << 10)
+#define ADPA_DPMS_D0			(0x0 << 10)
+#define ADPA_DPMS_D2			(0x1 << 10)
+#define ADPA_DPMS_D1			(0x2 << 10)
+#define ADPA_DPMS_D3			(0x3 << 10)
+#define ADPA_VSYNC_ACTIVE_SHIFT		4
+#define ADPA_HSYNC_ACTIVE_SHIFT		3
+#define ADPA_SYNC_ACTIVE_MASK		1
+#define ADPA_SYNC_ACTIVE_HIGH		1
+#define ADPA_SYNC_ACTIVE_LOW		0
+
+#define DVOA			0x61120
+#define DVOB			0x61140
+#define DVOC			0x61160
+#define LVDS			0x61180
+#define PORT_ENABLE		        (1 << 31)
+#define PORT_PIPE_SELECT_SHIFT	        30
+#define PORT_TV_FLAGS_MASK              0xFF
+#define PORT_TV_FLAGS                   0xC4  // ripped from my BIOS
+                                              // to understand and correct
+
+#define DVOA_SRCDIM		0x61124
+#define DVOB_SRCDIM		0x61144
+#define DVOC_SRCDIM		0x61164
+
+#define PIPEACONF		0x70008
+#define PIPEBCONF		0x71008
+#define PIPECONF_ENABLE			(1 << 31)
+#define PIPECONF_DISABLE		0
+#define PIPECONF_DOUBLE_WIDE		(1 << 30)
+#define PIPECONF_SINGLE_WIDE		0
+#define PIPECONF_LOCKED			(1 << 25)
+#define PIPECONF_UNLOCKED		0
+#define PIPECONF_GAMMA			(1 << 24)
+#define PIPECONF_PALETTE		0
+
+#define DISPARB			0x70030
+#define DISPARB_AEND_MASK		0x1ff
+#define DISPARB_AEND_SHIFT		0
+#define DISPARB_BEND_MASK		0x3ff
+#define DISPARB_BEND_SHIFT		9
+
+/* Desktop HW cursor */
+#define CURSOR_CONTROL		0x70080
+#define CURSOR_ENABLE			(1 << 31)
+#define CURSOR_GAMMA_ENABLE		(1 << 30)
+#define CURSOR_STRIDE_MASK		(0x3 << 28)
+#define CURSOR_STRIDE_256		(0x0 << 28)
+#define CURSOR_STRIDE_512		(0x1 << 28)
+#define CURSOR_STRIDE_1K		(0x2 << 28)
+#define CURSOR_STRIDE_2K		(0x3 << 28)
+#define CURSOR_FORMAT_MASK		(0x7 << 24)
+#define CURSOR_FORMAT_2C		(0x0 << 24)
+#define CURSOR_FORMAT_3C		(0x1 << 24)
+#define CURSOR_FORMAT_4C		(0x2 << 24)
+#define CURSOR_FORMAT_ARGB		(0x4 << 24)
+#define CURSOR_FORMAT_XRGB		(0x5 << 24)
+
+/* Mobile HW cursor (and i810) */
+#define CURSOR_A_CONTROL	CURSOR_CONTROL
+#define CURSOR_B_CONTROL	0x700c0
+#define CURSOR_MODE_MASK		0x27
+#define CURSOR_MODE_DISABLE		0
+#define CURSOR_MODE_64_3C		0x04
+#define CURSOR_MODE_64_4C_AX		0x05
+#define CURSOR_MODE_64_4C		0x06
+#define CURSOR_MODE_64_32B_AX		0x07
+#define CURSOR_MODE_64_ARGB_AX		0x27
+#define CURSOR_PIPE_SELECT_SHIFT	28
+#define CURSOR_MOBILE_GAMMA_ENABLE	(1 << 26)
+#define CURSOR_MEM_TYPE_LOCAL		(1 << 25)
+
+/* All platforms (desktop has no pipe B) */
+#define CURSOR_A_BASEADDR	0x70084
+#define CURSOR_B_BASEADDR	0x700c4
+#define CURSOR_BASE_MASK		0xffffff00
+
+#define CURSOR_A_POSITION	0x70088
+#define CURSOR_B_POSITION	0x700c8
+#define CURSOR_POS_SIGN			(1 << 15)
+#define CURSOR_POS_MASK			0x7ff
+#define CURSOR_X_SHIFT			0
+#define CURSOR_Y_SHIFT			16
+
+#define CURSOR_A_PALETTE0	0x70090
+#define CURSOR_A_PALETTE1	0x70094
+#define CURSOR_A_PALETTE2	0x70098
+#define CURSOR_A_PALETTE3	0x7009c
+#define CURSOR_B_PALETTE0	0x700d0
+#define CURSOR_B_PALETTE1	0x700d4
+#define CURSOR_B_PALETTE2	0x700d8
+#define CURSOR_B_PALETTE3	0x700dc
+#define CURSOR_COLOR_MASK			0xff
+#define CURSOR_RED_SHIFT			16
+#define CURSOR_GREEN_SHIFT			8
+#define CURSOR_BLUE_SHIFT			0
+#define CURSOR_PALETTE_MASK			0xffffff
+
+/* Desktop only */
+#define CURSOR_SIZE		0x700a0
+#define CURSOR_SIZE_MASK		0x3ff
+#define CURSOR_SIZE_H_SHIFT		0
+#define CURSOR_SIZE_V_SHIFT		12
+
+#define DSPACNTR		0x70180
+#define DSPBCNTR		0x71180
+#define DISPPLANE_PLANE_ENABLE		(1 << 31)
+#define DISPPLANE_PLANE_DISABLE		0
+#define DISPPLANE_GAMMA_ENABLE		(1<<30)
+#define DISPPLANE_GAMMA_DISABLE		0
+#define DISPPLANE_PIXFORMAT_MASK	(0xf<<26)
+#define DISPPLANE_8BPP			(0x2<<26)
+#define DISPPLANE_15_16BPP		(0x4<<26)
+#define DISPPLANE_16BPP			(0x5<<26)
+#define DISPPLANE_32BPP_NO_ALPHA 	(0x6<<26)
+#define DISPPLANE_32BPP			(0x7<<26)
+#define DISPPLANE_STEREO_ENABLE		(1<<25)
+#define DISPPLANE_STEREO_DISABLE	0
+#define DISPPLANE_SEL_PIPE_SHIFT	24
+#define DISPPLANE_SRC_KEY_ENABLE	(1<<22)
+#define DISPPLANE_SRC_KEY_DISABLE	0
+#define DISPPLANE_LINE_DOUBLE		(1<<20)
+#define DISPPLANE_NO_LINE_DOUBLE	0
+#define DISPPLANE_STEREO_POLARITY_FIRST	0
+#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18)
+/* plane B only */
+#define DISPPLANE_ALPHA_TRANS_ENABLE	(1<<15)
+#define DISPPLANE_ALPHA_TRANS_DISABLE	0
+#define DISPPLANE_SPRITE_ABOVE_DISPLAYA	0
+#define DISPPLANE_SPRITE_ABOVE_OVERLAY	1
+
+#define DSPABASE		0x70184
+#define DSPASTRIDE		0x70188
+
+#define DSPBBASE		0x71184
+#define DSPBSTRIDE		0x71188
+
+#define VGACNTRL		0x71400
+#define VGA_DISABLE			(1 << 31)
+#define VGA_ENABLE			0
+#define VGA_PIPE_SELECT_SHIFT		29
+#define VGA_PALETTE_READ_SELECT		23
+#define VGA_PALETTE_A_WRITE_DISABLE	(1 << 22)
+#define VGA_PALETTE_B_WRITE_DISABLE	(1 << 21)
+#define VGA_LEGACY_PALETTE		(1 << 20)
+#define VGA_6BIT_DAC			0
+#define VGA_8BIT_DAC			(1 << 20)
+
+#define ADD_ID			0x71408
+#define ADD_ID_MASK			0xff
+
+/* BIOS scratch area registers (830M and 845G). */
+#define SWF0			0x71410
+#define SWF1			0x71414
+#define SWF2			0x71418
+#define SWF3			0x7141c
+#define SWF4			0x71420
+#define SWF5			0x71424
+#define SWF6			0x71428
+
+/* BIOS scratch area registers (852GM, 855GM, 865G). */
+#define SWF00			0x70410
+#define SWF01			0x70414
+#define SWF02			0x70418
+#define SWF03			0x7041c
+#define SWF04			0x70420
+#define SWF05			0x70424
+#define SWF06			0x70428
+
+#define SWF10			SWF0
+#define SWF11			SWF1
+#define SWF12			SWF2
+#define SWF13			SWF3
+#define SWF14			SWF4
+#define SWF15			SWF5
+#define SWF16			SWF6
+
+#define SWF30			0x72414
+#define SWF31			0x72418
+#define SWF32			0x7241c
+
+/* Memory Commands */
+#define MI_NOOP			(0x00 << 23)
+#define MI_NOOP_WRITE_ID		(1 << 22)
+#define MI_NOOP_ID_MASK			((1 << 22) - 1)
+
+#define MI_FLUSH		(0x04 << 23)
+#define MI_WRITE_DIRTY_STATE		(1 << 4)
+#define MI_END_SCENE			(1 << 3)
+#define MI_INHIBIT_RENDER_CACHE_FLUSH	(1 << 2)
+#define MI_INVALIDATE_MAP_CACHE		(1 << 0)
+
+#define MI_STORE_DWORD_IMM	((0x20 << 23) | 1)
+
+/* 2D Commands */
+#define COLOR_BLT_CMD		((2 << 29) | (0x40 << 22) | 3)
+#define XY_COLOR_BLT_CMD	((2 << 29) | (0x50 << 22) | 4)
+#define XY_SETUP_CLIP_BLT_CMD	((2 << 29) | (0x03 << 22) | 1)
+#define XY_SRC_COPY_BLT_CMD	((2 << 29) | (0x53 << 22) | 6)
+#define SRC_COPY_BLT_CMD	((2 << 29) | (0x43 << 22) | 4)
+#define XY_MONO_PAT_BLT_CMD	((2 << 29) | (0x52 << 22) | 7)
+#define XY_MONO_SRC_BLT_CMD	((2 << 29) | (0x54 << 22) | 6)
+#define XY_MONO_SRC_IMM_BLT_CMD	((2 << 29) | (0x71 << 22) | 5)
+#define TXT_IMM_BLT_CMD	        ((2 << 29) | (0x30 << 22) | 2)
+#define SETUP_BLT_CMD	        ((2 << 29) | (0x00 << 22) | 6)
+
+#define DW_LENGTH_MASK			0xff
+
+#define WRITE_ALPHA			(1 << 21)
+#define WRITE_RGB			(1 << 20)
+#define VERT_SEED			(3 << 8)
+#define HORIZ_SEED			(3 << 12)
+
+#define COLOR_DEPTH_8			(0 << 24)
+#define COLOR_DEPTH_16			(1 << 24)
+#define COLOR_DEPTH_32			(3 << 24)
+
+#define SRC_ROP_GXCOPY			0xcc
+#define SRC_ROP_GXXOR			0x66
+
+#define PAT_ROP_GXCOPY                  0xf0
+#define PAT_ROP_GXXOR                   0x5a
+
+#define PITCH_SHIFT			0
+#define ROP_SHIFT			16
+#define WIDTH_SHIFT			0
+#define HEIGHT_SHIFT			16
+
+/* in bytes */
+#define MAX_MONO_IMM_SIZE		128
+
+
+/*** Macros ***/
+
+/* I/O macros */
+#define INREG8(addr)	      readb((u8 __iomem *)(dinfo->mmio_base + (addr)))
+#define INREG(addr)	      readl((u32 __iomem *)(dinfo->mmio_base + (addr)))
+#define OUTREG8(addr, val)    writeb((val),(u8 __iomem *)(dinfo->mmio_base + \
+							   (addr)))
+#define OUTREG(addr, val)     writel((val),(u32 __iomem *)(dinfo->mmio_base + \
+                                     (addr)))
+
+/* Ring buffer macros */
+#define OUT_RING(n)	do {						\
+	writel((n), (u32 __iomem *)(dinfo->ring.virtual + dinfo->ring_tail));\
+	dinfo->ring_tail += 4;						\
+	dinfo->ring_tail &= dinfo->ring_tail_mask;			\
+} while (0)
+
+#define START_RING(n)	do {						\
+	if (dinfo->ring_space < (n) * 4)				\
+		wait_ring(dinfo,(n) * 4);				\
+	dinfo->ring_space -= (n) * 4;					\
+} while (0)
+
+#define ADVANCE_RING()	do {						\
+	OUTREG(PRI_RING_TAIL, dinfo->ring_tail);                        \
+} while (0)
+
+#define DO_RING_IDLE()	do {						\
+	u32 head, tail;							\
+	do {								\
+		head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK;		\
+		tail = INREG(PRI_RING_TAIL) & RING_TAIL_MASK;		\
+		udelay(10);						\
+	} while (head != tail);						\
+} while (0)
+
+
+/* function protoypes */
+extern int intelfbhw_get_chipset(struct pci_dev *pdev, const char **name,
+				 int *chipset, int *mobile);
+extern int intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
+				int *stolen_size);
+extern int intelfbhw_check_non_crt(struct intelfb_info *dinfo);
+extern const char *intelfbhw_dvo_to_string(int dvo);
+extern int intelfbhw_validate_mode(struct intelfb_info *dinfo,
+				   struct fb_var_screeninfo *var);
+extern int intelfbhw_pan_display(struct fb_var_screeninfo *var,
+				 struct fb_info *info);
+extern void intelfbhw_do_blank(int blank, struct fb_info *info);
+extern void intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno,
+				unsigned red, unsigned green, unsigned blue,
+				unsigned transp);
+extern int intelfbhw_read_hw_state(struct intelfb_info *dinfo,
+				   struct intelfb_hwstate *hw, int flag);
+extern void intelfbhw_print_hw_state(struct intelfb_info *dinfo,
+				     struct intelfb_hwstate *hw);
+extern int intelfbhw_mode_to_hw(struct intelfb_info *dinfo,
+				struct intelfb_hwstate *hw,
+				struct fb_var_screeninfo *var);
+extern int intelfbhw_program_mode(struct intelfb_info *dinfo,
+				  const struct intelfb_hwstate *hw, int blank);
+extern void intelfbhw_do_sync(struct intelfb_info *dinfo);
+extern void intelfbhw_2d_stop(struct intelfb_info *dinfo);
+extern void intelfbhw_2d_start(struct intelfb_info *dinfo);
+extern void intelfbhw_do_fillrect(struct intelfb_info *dinfo, u32 x, u32 y,
+				  u32 w, u32 h, u32 color, u32 pitch, u32 bpp,
+				  u32 rop);
+extern void intelfbhw_do_bitblt(struct intelfb_info *dinfo, u32 curx, u32 cury,
+				u32 dstx, u32 dsty, u32 w, u32 h, u32 pitch,
+				u32 bpp);
+extern int intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg,
+				  u32 w, u32 h, const u8* cdat, u32 x, u32 y,
+				  u32 pitch, u32 bpp);
+extern void intelfbhw_cursor_init(struct intelfb_info *dinfo);
+extern void intelfbhw_cursor_hide(struct intelfb_info *dinfo);
+extern void intelfbhw_cursor_show(struct intelfb_info *dinfo);
+extern void intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y);
+extern void intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg,
+				      u32 fg);
+extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width,
+				  int height, u8 *data);
+extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo);
+
+#endif /* _INTELFBHW_H */
diff --git a/drivers/video/kyro/Makefile b/drivers/video/kyro/Makefile
new file mode 100644
index 0000000..2fd66f5
--- /dev/null
+++ b/drivers/video/kyro/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the Kyro framebuffer driver
+#
+
+obj-$(CONFIG_FB_KYRO)	+= kyrofb.o
+
+kyrofb-objs	:= STG4000Ramdac.o STG4000VTG.o STG4000OverlayDevice.o \
+		   STG4000InitDevice.o fbdev.o
diff --git a/drivers/video/kyro/STG4000InitDevice.c b/drivers/video/kyro/STG4000InitDevice.c
new file mode 100644
index 0000000..7e33cd30
--- /dev/null
+++ b/drivers/video/kyro/STG4000InitDevice.c
@@ -0,0 +1,326 @@
+/*
+ *  linux/drivers/video/kyro/STG4000InitDevice.c
+ *
+ *  Copyright (C) 2000 Imagination Technologies Ltd
+ *  Copyright (C) 2002 STMicroelectronics
+ *
+ * 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/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+
+#include "STG4000Reg.h"
+
+/* SDRAM fixed settings */
+#define SDRAM_CFG_0   0x49A1
+#define SDRAM_CFG_1   0xA732
+#define SDRAM_CFG_2   0x31
+#define SDRAM_ARB_CFG 0xA0
+#define SDRAM_REFRESH 0x20
+
+/* Reset values */
+#define PMX2_SOFTRESET_DAC_RST		0x0001
+#define PMX2_SOFTRESET_C1_RST		0x0004
+#define PMX2_SOFTRESET_C2_RST		0x0008
+#define PMX2_SOFTRESET_3D_RST		0x0010
+#define PMX2_SOFTRESET_VIDIN_RST	0x0020
+#define PMX2_SOFTRESET_TLB_RST		0x0040
+#define PMX2_SOFTRESET_SD_RST		0x0080
+#define PMX2_SOFTRESET_VGA_RST		0x0100
+#define PMX2_SOFTRESET_ROM_RST		0x0200	/* reserved bit, do not reset */
+#define PMX2_SOFTRESET_TA_RST		0x0400
+#define PMX2_SOFTRESET_REG_RST		0x4000
+#define PMX2_SOFTRESET_ALL		0x7fff
+
+/* Core clock freq */
+#define CORE_PLL_FREQ 1000000
+
+/* Reference Clock freq */
+#define REF_FREQ 14318
+
+/* PCI Registers */
+static u16 CorePllControl = 0x70;
+
+#define	PCI_CONFIG_SUBSYS_ID	0x2e
+
+/* Misc */
+#define CORE_PLL_MODE_REG_0_7      3
+#define CORE_PLL_MODE_REG_8_15     2
+#define CORE_PLL_MODE_CONFIG_REG   1
+#define DAC_PLL_CONFIG_REG         0
+
+#define STG_MAX_VCO 500000
+#define STG_MIN_VCO 100000
+
+/* PLL Clock */
+#define    STG4K3_PLL_SCALER      8	/* scale numbers by 2^8 for fixed point calc */
+#define    STG4K3_PLL_MIN_R       2	/* Minimum multiplier */
+#define    STG4K3_PLL_MAX_R       33	/* Max */
+#define    STG4K3_PLL_MIN_F       2	/* Minimum divisor */
+#define    STG4K3_PLL_MAX_F       513	/* Max */
+#define    STG4K3_PLL_MIN_OD      0	/* Min output divider (shift) */
+#define    STG4K3_PLL_MAX_OD      2	/* Max */
+#define    STG4K3_PLL_MIN_VCO_SC  (100000000 >> STG4K3_PLL_SCALER)	/* Min VCO rate */
+#define    STG4K3_PLL_MAX_VCO_SC  (500000000 >> STG4K3_PLL_SCALER)	/* Max VCO rate */
+#define    STG4K3_PLL_MINR_VCO_SC (100000000 >> STG4K3_PLL_SCALER)	/* Min VCO rate (restricted) */
+#define    STG4K3_PLL_MAXR_VCO_SC (500000000 >> STG4K3_PLL_SCALER)	/* Max VCO rate (restricted) */
+#define    STG4K3_PLL_MINR_VCO    100000000	/* Min VCO rate (restricted) */
+#define    STG4K3_PLL_MAX_VCO     500000000	/* Max VCO rate */
+#define    STG4K3_PLL_MAXR_VCO    500000000	/* Max VCO rate (restricted) */
+
+#define OS_DELAY(X) \
+{ \
+volatile u32 i,count=0; \
+    for(i=0;i<X;i++) count++; \
+}
+
+static u32 InitSDRAMRegisters(volatile STG4000REG __iomem *pSTGReg,
+			      u32 dwSubSysID, u32 dwRevID)
+{
+	u32 adwSDRAMArgCfg0[] = { 0xa0, 0x80, 0xa0, 0xa0, 0xa0 };
+	u32 adwSDRAMCfg1[] = { 0x8732, 0x8732, 0xa732, 0xa732, 0x8732 };
+	u32 adwSDRAMCfg2[] = { 0x87d2, 0x87d2, 0xa7d2, 0x87d2, 0xa7d2 };
+	u32 adwSDRAMRsh[] = { 36, 39, 40 };
+	u32 adwChipSpeed[] = { 110, 120, 125 };
+	u32 dwMemTypeIdx;
+	u32 dwChipSpeedIdx;
+
+	/* Get memory tpye and chip speed indexs from the SubSysDevID */
+	dwMemTypeIdx = (dwSubSysID & 0x70) >> 4;
+	dwChipSpeedIdx = (dwSubSysID & 0x180) >> 7;
+
+	if (dwMemTypeIdx > 4 || dwChipSpeedIdx > 2)
+		return 0;
+
+	/* Program SD-RAM interface */
+	STG_WRITE_REG(SDRAMArbiterConf, adwSDRAMArgCfg0[dwMemTypeIdx]);
+	if (dwRevID < 5) {
+		STG_WRITE_REG(SDRAMConf0, 0x49A1);
+		STG_WRITE_REG(SDRAMConf1, adwSDRAMCfg1[dwMemTypeIdx]);
+	} else {
+		STG_WRITE_REG(SDRAMConf0, 0x4DF1);
+		STG_WRITE_REG(SDRAMConf1, adwSDRAMCfg2[dwMemTypeIdx]);
+	}
+
+	STG_WRITE_REG(SDRAMConf2, 0x31);
+	STG_WRITE_REG(SDRAMRefresh, adwSDRAMRsh[dwChipSpeedIdx]);
+
+	return adwChipSpeed[dwChipSpeedIdx] * 10000;
+}
+
+u32 ProgramClock(u32 refClock,
+		   u32 coreClock,
+		   u32 * FOut, u32 * ROut, u32 * POut)
+{
+	u32 R = 0, F = 0, OD = 0, ODIndex = 0;
+	u32 ulBestR = 0, ulBestF = 0, ulBestOD = 0;
+	u32 ulBestVCO = 0, ulBestClk = 0, ulBestScore = 0;
+	u32 ulScore, ulPhaseScore, ulVcoScore;
+	u32 ulTmp = 0, ulVCO;
+	u32 ulScaleClockReq, ulMinClock, ulMaxClock;
+	u32 ODValues[] = { 1, 2, 0 };
+
+	/* Translate clock in Hz */
+	coreClock *= 100;	/* in Hz */
+	refClock *= 1000;	/* in Hz */
+
+	/* Work out acceptable clock
+	 * The method calculates ~ +- 0.4% (1/256)
+	 */
+	ulMinClock = coreClock - (coreClock >> 8);
+	ulMaxClock = coreClock + (coreClock >> 8);
+
+	/* Scale clock required for use in calculations */
+	ulScaleClockReq = coreClock >> STG4K3_PLL_SCALER;
+
+	/* Iterate through post divider values */
+	for (ODIndex = 0; ODIndex < 3; ODIndex++) {
+		OD = ODValues[ODIndex];
+		R = STG4K3_PLL_MIN_R;
+
+		/* loop for pre-divider from min to max  */
+		while (R <= STG4K3_PLL_MAX_R) {
+			/* estimate required feedback multiplier */
+			ulTmp = R * (ulScaleClockReq << OD);
+
+			/* F = ClkRequired * R * (2^OD) / Fref */
+			F = (u32)(ulTmp / (refClock >> STG4K3_PLL_SCALER));
+
+			/* compensate for accuracy */
+			if (F > STG4K3_PLL_MIN_F)
+				F--;
+
+
+			/*
+			 * We should be close to our target frequency (if it's
+			 * achievable with current OD & R) let's iterate
+			 * through F for best fit
+			 */
+			while ((F >= STG4K3_PLL_MIN_F) &&
+			       (F <= STG4K3_PLL_MAX_F)) {
+				/* Calc VCO at full accuracy */
+				ulVCO = refClock / R;
+				ulVCO = F * ulVCO;
+
+				/*
+				 * Check it's within restricted VCO range
+				 * unless of course the desired frequency is
+				 * above the restricted range, then test
+				 * against VCO limit
+				 */
+				if ((ulVCO >= STG4K3_PLL_MINR_VCO) &&
+				    ((ulVCO <= STG4K3_PLL_MAXR_VCO) ||
+				     ((coreClock > STG4K3_PLL_MAXR_VCO)
+				      && (ulVCO <= STG4K3_PLL_MAX_VCO)))) {
+					ulTmp = (ulVCO >> OD);	/* Clock = VCO / (2^OD) */
+
+					/* Is this clock good enough? */
+					if ((ulTmp >= ulMinClock)
+					    && (ulTmp <= ulMaxClock)) {
+						ulPhaseScore = (((refClock / R) - (refClock / STG4K3_PLL_MAX_R))) / ((refClock - (refClock / STG4K3_PLL_MAX_R)) >> 10);
+
+						ulVcoScore = ((ulVCO - STG4K3_PLL_MINR_VCO)) / ((STG4K3_PLL_MAXR_VCO - STG4K3_PLL_MINR_VCO) >> 10);
+						ulScore = ulPhaseScore + ulVcoScore;
+
+						if (!ulBestScore) {
+							ulBestVCO = ulVCO;
+							ulBestOD = OD;
+							ulBestF = F;
+							ulBestR = R;
+							ulBestClk = ulTmp;
+							ulBestScore =
+							    ulScore;
+						}
+						/* is this better, ( aim for highest Score) */
+			/*--------------------------------------------------------------------------
+                             Here we want to use a scoring system which will take account of both the
+                            value at the phase comparater and the VCO output
+                             to do this we will use a cumulative score between the two
+                          The way this ends up is that we choose the first value in the loop anyway
+                          but we shall keep this code in case new restrictions come into play
+                          --------------------------------------------------------------------------*/
+						if ((ulScore >= ulBestScore) && (OD > 0)) {
+							ulBestVCO = ulVCO;
+							ulBestOD = OD;
+							ulBestF = F;
+							ulBestR = R;
+							ulBestClk = ulTmp;
+							ulBestScore =
+							    ulScore;
+						}
+					}
+				}
+				F++;
+			}
+			R++;
+		}
+	}
+
+	/*
+	   did we find anything?
+	   Then return RFOD
+	 */
+	if (ulBestScore) {
+		*ROut = ulBestR;
+		*FOut = ulBestF;
+
+		if ((ulBestOD == 2) || (ulBestOD == 3)) {
+			*POut = 3;
+		} else
+			*POut = ulBestOD;
+
+	}
+
+	return (ulBestClk);
+}
+
+int SetCoreClockPLL(volatile STG4000REG __iomem *pSTGReg, struct pci_dev *pDev)
+{
+	u32 F, R, P;
+	u16 core_pll = 0, sub;
+	u32 ulCoreClock;
+	u32 tmp;
+	u32 ulChipSpeed;
+	u8 rev;
+
+	STG_WRITE_REG(IntMask, 0xFFFF);
+
+	/* Disable Primary Core Thread0 */
+	tmp = STG_READ_REG(Thread0Enable);
+	CLEAR_BIT(0);
+	STG_WRITE_REG(Thread0Enable, tmp);
+
+	/* Disable Primary Core Thread1 */
+	tmp = STG_READ_REG(Thread1Enable);
+	CLEAR_BIT(0);
+	STG_WRITE_REG(Thread1Enable, tmp);
+
+	STG_WRITE_REG(SoftwareReset,
+		      PMX2_SOFTRESET_REG_RST | PMX2_SOFTRESET_ROM_RST);
+	STG_WRITE_REG(SoftwareReset,
+		      PMX2_SOFTRESET_REG_RST | PMX2_SOFTRESET_TA_RST |
+		      PMX2_SOFTRESET_ROM_RST);
+
+	/* Need to play around to reset TA */
+	STG_WRITE_REG(TAConfiguration, 0);
+	STG_WRITE_REG(SoftwareReset,
+		      PMX2_SOFTRESET_REG_RST | PMX2_SOFTRESET_ROM_RST);
+	STG_WRITE_REG(SoftwareReset,
+		      PMX2_SOFTRESET_REG_RST | PMX2_SOFTRESET_TA_RST |
+		      PMX2_SOFTRESET_ROM_RST);
+
+	pci_read_config_word(pDev, PCI_CONFIG_SUBSYS_ID, &sub);
+	pci_read_config_byte(pDev, PCI_REVISION_ID, &rev);
+
+	ulChipSpeed = InitSDRAMRegisters(pSTGReg, (u32)sub, (u32)rev);
+
+	if (ulChipSpeed == 0)
+		return -EINVAL;
+
+	ulCoreClock = ProgramClock(REF_FREQ, CORE_PLL_FREQ, &F, &R, &P);
+
+	core_pll |= ((P) | ((F - 2) << 2) | ((R - 2) << 11));
+
+	/* Set Core PLL Control to Core PLL Mode  */
+
+	/* Send bits 0:7 of the Core PLL Mode register */
+	tmp = ((CORE_PLL_MODE_REG_0_7 << 8) | (core_pll & 0x00FF));
+	pci_write_config_word(pDev, CorePllControl, tmp);
+	/* Without some delay between the PCI config writes the clock does
+	   not reliably set when the code is compiled -O3
+	 */
+	OS_DELAY(1000000);
+
+	tmp |= SET_BIT(14);
+	pci_write_config_word(pDev, CorePllControl, tmp);
+	OS_DELAY(1000000);
+
+	/* Send bits 8:15 of the Core PLL Mode register */
+	tmp =
+	    ((CORE_PLL_MODE_REG_8_15 << 8) | ((core_pll & 0xFF00) >> 8));
+	pci_write_config_word(pDev, CorePllControl, tmp);
+	OS_DELAY(1000000);
+
+	tmp |= SET_BIT(14);
+	pci_write_config_word(pDev, CorePllControl, tmp);
+	OS_DELAY(1000000);
+
+	STG_WRITE_REG(SoftwareReset, PMX2_SOFTRESET_ALL);
+
+#if 0
+	/* Enable Primary Core Thread0 */
+	tmp = ((STG_READ_REG(Thread0Enable)) | SET_BIT(0));
+	STG_WRITE_REG(Thread0Enable, tmp);
+
+	/* Enable Primary Core Thread1 */
+	tmp = ((STG_READ_REG(Thread1Enable)) | SET_BIT(0));
+	STG_WRITE_REG(Thread1Enable, tmp);
+#endif
+
+	return 0;
+}
diff --git a/drivers/video/kyro/STG4000Interface.h b/drivers/video/kyro/STG4000Interface.h
new file mode 100644
index 0000000..e75b3b4
--- /dev/null
+++ b/drivers/video/kyro/STG4000Interface.h
@@ -0,0 +1,60 @@
+/*
+ *  linux/drivers/video/kyro/STG4000Interface.h
+ *
+ *  Copyright (C) 2002 STMicroelectronics
+ *
+ * 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 _STG4000INTERFACE_H
+#define _STG4000INTERFACE_H
+
+struct pci_dev;
+
+/*
+ * Ramdac Setup
+ */
+extern int InitialiseRamdac(volatile STG4000REG __iomem *pSTGReg, u32 displayDepth,
+			    u32 displayWidth, u32 displayHeight,
+			    s32 HSyncPolarity, s32 VSyncPolarity,
+			    u32 *pixelClock);
+
+extern void DisableRamdacOutput(volatile STG4000REG __iomem *pSTGReg);
+extern void EnableRamdacOutput(volatile STG4000REG __iomem *pSTGReg);
+
+/*
+ * Timing generator setup
+ */
+extern void DisableVGA(volatile STG4000REG __iomem *pSTGReg);
+extern void StopVTG(volatile STG4000REG __iomem *pSTGReg);
+extern void StartVTG(volatile STG4000REG __iomem *pSTGReg);
+extern void SetupVTG(volatile STG4000REG __iomem *pSTGReg,
+		     const struct kyrofb_info * pTiming);
+
+extern u32 ProgramClock(u32 refClock, u32 coreClock, u32 *FOut, u32 *ROut, u32 *POut);
+extern int SetCoreClockPLL(volatile STG4000REG __iomem *pSTGReg, struct pci_dev *pDev);
+
+/*
+ * Overlay setup
+ */
+extern void ResetOverlayRegisters(volatile STG4000REG __iomem *pSTGReg);
+
+extern int CreateOverlaySurface(volatile STG4000REG __iomem *pSTGReg,
+				u32 ulWidth, u32 ulHeight,
+				int bLinear,
+				u32 ulOverlayOffset,
+				u32 * retStride, u32 * retUVStride);
+
+extern int SetOverlayBlendMode(volatile STG4000REG __iomem *pSTGReg,
+			       OVRL_BLEND_MODE mode,
+			       u32 ulAlpha, u32 ulColorKey);
+
+extern int SetOverlayViewPort(volatile STG4000REG __iomem *pSTGReg,
+			      u32 left, u32 top,
+			      u32 right, u32 bottom);
+
+extern void EnableOverlayPlane(volatile STG4000REG __iomem *pSTGReg);
+
+#endif /* _STG4000INTERFACE_H */
diff --git a/drivers/video/kyro/STG4000OverlayDevice.c b/drivers/video/kyro/STG4000OverlayDevice.c
new file mode 100644
index 0000000..2ae9baf
--- /dev/null
+++ b/drivers/video/kyro/STG4000OverlayDevice.c
@@ -0,0 +1,600 @@
+/*
+ *  linux/drivers/video/kyro/STG4000OverlayDevice.c
+ *
+ *  Copyright (C) 2000 Imagination Technologies Ltd
+ *  Copyright (C) 2002 STMicroelectronics
+ *
+ * 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/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+
+#include "STG4000Reg.h"
+
+/* HW Defines */
+
+#define STG4000_NO_SCALING    0x800
+#define STG4000_NO_DECIMATION 0xFFFFFFFF
+
+/* Primary surface */
+#define STG4000_PRIM_NUM_PIX   5
+#define STG4000_PRIM_ALIGN     4
+#define STG4000_PRIM_ADDR_BITS 20
+
+#define STG4000_PRIM_MIN_WIDTH  640
+#define STG4000_PRIM_MAX_WIDTH  1600
+#define STG4000_PRIM_MIN_HEIGHT 480
+#define STG4000_PRIM_MAX_HEIGHT 1200
+
+/* Overlay surface */
+#define STG4000_OVRL_NUM_PIX   4
+#define STG4000_OVRL_ALIGN     2
+#define STG4000_OVRL_ADDR_BITS 20
+#define STG4000_OVRL_NUM_MODES 5
+
+#define STG4000_OVRL_MIN_WIDTH  0
+#define STG4000_OVRL_MAX_WIDTH  720
+#define STG4000_OVRL_MIN_HEIGHT 0
+#define STG4000_OVRL_MAX_HEIGHT 576
+
+/* Decimation and Scaling */
+static u32 adwDecim8[33] = {
+	    0xffffffff, 0xfffeffff, 0xffdffbff, 0xfefefeff, 0xfdf7efbf,
+	    0xfbdf7bdf, 0xf7bbddef, 0xeeeeeeef, 0xeeddbb77, 0xedb76db7,
+	    0xdb6db6db, 0xdb5b5b5b, 0xdab5ad6b, 0xd5ab55ab, 0xd555aaab,
+	    0xaaaaaaab, 0xaaaa5555, 0xaa952a55, 0xa94a5295, 0xa5252525,
+	    0xa4924925, 0x92491249, 0x91224489, 0x91111111, 0x90884211,
+	    0x88410821, 0x88102041, 0x81010101, 0x80800801, 0x80010001,
+	    0x80000001, 0x00000001, 0x00000000
+};
+
+typedef struct _OVRL_SRC_DEST {
+	/*clipped on-screen pixel position of overlay */
+	u32 ulDstX1;
+	u32 ulDstY1;
+	u32 ulDstX2;
+	u32 ulDstY2;
+
+	/*clipped pixel pos of source data within buffer thses need to be 128 bit word aligned */
+	u32 ulSrcX1;
+	u32 ulSrcY1;
+	u32 ulSrcX2;
+	u32 ulSrcY2;
+
+	/* on-screen pixel position of overlay */
+	s32 lDstX1;
+	s32 lDstY1;
+	s32 lDstX2;
+	s32 lDstY2;
+} OVRL_SRC_DEST;
+
+static u32 ovlWidth, ovlHeight, ovlStride;
+static int ovlLinear;
+
+void ResetOverlayRegisters(volatile STG4000REG __iomem *pSTGReg)
+{
+	u32 tmp;
+
+	/* Set Overlay address to default */
+	tmp = STG_READ_REG(DACOverlayAddr);
+	CLEAR_BITS_FRM_TO(0, 20);
+	CLEAR_BIT(31);
+	STG_WRITE_REG(DACOverlayAddr, tmp);
+
+	/* Set Overlay U address */
+	tmp = STG_READ_REG(DACOverlayUAddr);
+	CLEAR_BITS_FRM_TO(0, 20);
+	STG_WRITE_REG(DACOverlayUAddr, tmp);
+
+	/* Set Overlay V address */
+	tmp = STG_READ_REG(DACOverlayVAddr);
+	CLEAR_BITS_FRM_TO(0, 20);
+	STG_WRITE_REG(DACOverlayVAddr, tmp);
+
+	/* Set Overlay Size */
+	tmp = STG_READ_REG(DACOverlaySize);
+	CLEAR_BITS_FRM_TO(0, 10);
+	CLEAR_BITS_FRM_TO(12, 31);
+	STG_WRITE_REG(DACOverlaySize, tmp);
+
+	/* Set Overlay Vt Decimation */
+	tmp = STG4000_NO_DECIMATION;
+	STG_WRITE_REG(DACOverlayVtDec, tmp);
+
+	/* Set Overlay format to default value */
+	tmp = STG_READ_REG(DACPixelFormat);
+	CLEAR_BITS_FRM_TO(4, 7);
+	CLEAR_BITS_FRM_TO(16, 22);
+	STG_WRITE_REG(DACPixelFormat, tmp);
+
+	/* Set Vertical scaling to default */
+	tmp = STG_READ_REG(DACVerticalScal);
+	CLEAR_BITS_FRM_TO(0, 11);
+	CLEAR_BITS_FRM_TO(16, 22);
+	tmp |= STG4000_NO_SCALING;	/* Set to no scaling */
+	STG_WRITE_REG(DACVerticalScal, tmp);
+
+	/* Set Horizontal Scaling to default */
+	tmp = STG_READ_REG(DACHorizontalScal);
+	CLEAR_BITS_FRM_TO(0, 11);
+	CLEAR_BITS_FRM_TO(16, 17);
+	tmp |= STG4000_NO_SCALING;	/* Set to no scaling */
+	STG_WRITE_REG(DACHorizontalScal, tmp);
+
+	/* Set Blend mode to Alpha Blend */
+	/* ????? SG 08/11/2001 Surely this isn't the alpha blend mode,
+	   hopefully its overwrite
+	 */
+	tmp = STG_READ_REG(DACBlendCtrl);
+	CLEAR_BITS_FRM_TO(0, 30);
+	tmp = (GRAPHICS_MODE << 28);
+	STG_WRITE_REG(DACBlendCtrl, tmp);
+
+}
+
+int CreateOverlaySurface(volatile STG4000REG __iomem *pSTGReg,
+			 u32 inWidth,
+			 u32 inHeight,
+			 int bLinear,
+			 u32 ulOverlayOffset,
+			 u32 * retStride, u32 * retUVStride)
+{
+	u32 tmp;
+	u32 ulStride;
+
+	if (inWidth > STG4000_OVRL_MAX_WIDTH ||
+	    inHeight > STG4000_OVRL_MAX_HEIGHT) {
+		return -EINVAL;
+	}
+
+	/* Stride in 16 byte words - 16Bpp */
+	if (bLinear) {
+		/* Format is 16bits so num 16 byte words is width/8 */
+		if ((inWidth & 0x7) == 0) {	/* inWidth % 8 */
+			ulStride = (inWidth / 8);
+		} else {
+			/* Round up to next 16byte boundary */
+			ulStride = ((inWidth + 8) / 8);
+		}
+	} else {
+		/* Y component is 8bits so num 16 byte words is width/16 */
+		if ((inWidth & 0xf) == 0) {	/* inWidth % 16 */
+			ulStride = (inWidth / 16);
+		} else {
+			/* Round up to next 16byte boundary */
+			ulStride = ((inWidth + 16) / 16);
+		}
+	}
+
+
+	/* Set Overlay address and Format mode */
+	tmp = STG_READ_REG(DACOverlayAddr);
+	CLEAR_BITS_FRM_TO(0, 20);
+	if (bLinear) {
+		CLEAR_BIT(31);	/* Overlay format to Linear */
+	} else {
+		tmp |= SET_BIT(31);	/* Overlay format to Planer */
+	}
+
+	/* Only bits 24:4 of the Overlay address */
+	tmp |= (ulOverlayOffset >> 4);
+	STG_WRITE_REG(DACOverlayAddr, tmp);
+
+	if (!bLinear) {
+		u32 uvSize =
+		    (inWidth & 0x1) ? (inWidth + 1 / 2) : (inWidth / 2);
+		u32 uvStride;
+		u32 ulOffset;
+		/* Y component is 8bits so num 32 byte words is width/32 */
+		if ((uvSize & 0xf) == 0) {	/* inWidth % 16 */
+			uvStride = (uvSize / 16);
+		} else {
+			/* Round up to next 32byte boundary */
+			uvStride = ((uvSize + 16) / 16);
+		}
+
+		ulOffset = ulOverlayOffset + (inHeight * (ulStride * 16));
+		/* Align U,V data to 32byte boundary */
+		if ((ulOffset & 0x1f) != 0)
+			ulOffset = (ulOffset + 32L) & 0xffffffE0L;
+
+		tmp = STG_READ_REG(DACOverlayUAddr);
+		CLEAR_BITS_FRM_TO(0, 20);
+		tmp |= (ulOffset >> 4);
+		STG_WRITE_REG(DACOverlayUAddr, tmp);
+
+		ulOffset += (inHeight / 2) * (uvStride * 16);
+		/* Align U,V data to 32byte boundary */
+		if ((ulOffset & 0x1f) != 0)
+			ulOffset = (ulOffset + 32L) & 0xffffffE0L;
+
+		tmp = STG_READ_REG(DACOverlayVAddr);
+		CLEAR_BITS_FRM_TO(0, 20);
+		tmp |= (ulOffset >> 4);
+		STG_WRITE_REG(DACOverlayVAddr, tmp);
+
+		*retUVStride = uvStride * 16;
+	}
+
+
+	/* Set Overlay YUV pixel format
+	 * Make sure that LUT not used - ??????
+	 */
+	tmp = STG_READ_REG(DACPixelFormat);
+	/* Only support Planer or UYVY linear formats */
+	CLEAR_BITS_FRM_TO(4, 9);
+	STG_WRITE_REG(DACPixelFormat, tmp);
+
+	ovlWidth = inWidth;
+	ovlHeight = inHeight;
+	ovlStride = ulStride;
+	ovlLinear = bLinear;
+	*retStride = ulStride << 4;	/* In bytes */
+
+	return 0;
+}
+
+int SetOverlayBlendMode(volatile STG4000REG __iomem *pSTGReg,
+			OVRL_BLEND_MODE mode,
+			u32 ulAlpha, u32 ulColorKey)
+{
+	u32 tmp;
+
+	tmp = STG_READ_REG(DACBlendCtrl);
+	CLEAR_BITS_FRM_TO(28, 30);
+	tmp |= (mode << 28);
+
+	switch (mode) {
+	case COLOR_KEY:
+		CLEAR_BITS_FRM_TO(0, 23);
+		tmp |= (ulColorKey & 0x00FFFFFF);
+		break;
+
+	case GLOBAL_ALPHA:
+		CLEAR_BITS_FRM_TO(24, 27);
+		tmp |= ((ulAlpha & 0xF) << 24);
+		break;
+
+	case CK_PIXEL_ALPHA:
+		CLEAR_BITS_FRM_TO(0, 23);
+		tmp |= (ulColorKey & 0x00FFFFFF);
+		break;
+
+	case CK_GLOBAL_ALPHA:
+		CLEAR_BITS_FRM_TO(0, 23);
+		tmp |= (ulColorKey & 0x00FFFFFF);
+		CLEAR_BITS_FRM_TO(24, 27);
+		tmp |= ((ulAlpha & 0xF) << 24);
+		break;
+
+	case GRAPHICS_MODE:
+	case PER_PIXEL_ALPHA:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	STG_WRITE_REG(DACBlendCtrl, tmp);
+
+	return 0;
+}
+
+void EnableOverlayPlane(volatile STG4000REG __iomem *pSTGReg)
+{
+	u32 tmp;
+	/* Enable Overlay */
+	tmp = STG_READ_REG(DACPixelFormat);
+	tmp |= SET_BIT(7);
+	STG_WRITE_REG(DACPixelFormat, tmp);
+
+	/* Set video stream control */
+	tmp = STG_READ_REG(DACStreamCtrl);
+	tmp |= SET_BIT(1);	/* video stream */
+	STG_WRITE_REG(DACStreamCtrl, tmp);
+}
+
+static u32 Overlap(u32 ulBits, u32 ulPattern)
+{
+	u32 ulCount = 0;
+
+	while (ulBits) {
+		if (!(ulPattern & 1))
+			ulCount++;
+		ulBits--;
+		ulPattern = ulPattern >> 1;
+	}
+
+	return ulCount;
+
+}
+
+int SetOverlayViewPort(volatile STG4000REG __iomem *pSTGReg,
+		       u32 left, u32 top,
+		       u32 right, u32 bottom)
+{
+	OVRL_SRC_DEST srcDest;
+
+	u32 ulSrcTop, ulSrcBottom;
+	u32 ulSrc, ulDest;
+	u32 ulFxScale, ulFxOffset;
+	u32 ulHeight, ulWidth;
+	u32 ulPattern;
+	u32 ulDecimate, ulDecimated;
+	u32 ulApplied;
+	u32 ulDacXScale, ulDacYScale;
+	u32 ulScale;
+	u32 ulLeft, ulRight;
+	u32 ulSrcLeft, ulSrcRight;
+	u32 ulScaleLeft, ulScaleRight;
+	u32 ulhDecim;
+	u32 ulsVal;
+	u32 ulVertDecFactor;
+	int bResult;
+	u32 ulClipOff = 0;
+	u32 ulBits = 0;
+	u32 ulsAdd = 0;
+	u32 tmp, ulStride;
+	u32 ulExcessPixels, ulClip, ulExtraLines;
+
+
+	srcDest.ulSrcX1 = 0;
+	srcDest.ulSrcY1 = 0;
+	srcDest.ulSrcX2 = ovlWidth - 1;
+	srcDest.ulSrcY2 = ovlHeight - 1;
+
+	srcDest.ulDstX1 = left;
+	srcDest.ulDstY1 = top;
+	srcDest.ulDstX2 = right;
+	srcDest.ulDstY2 = bottom;
+
+	srcDest.lDstX1 = srcDest.ulDstX1;
+	srcDest.lDstY1 = srcDest.ulDstY1;
+	srcDest.lDstX2 = srcDest.ulDstX2;
+	srcDest.lDstY2 = srcDest.ulDstY2;
+
+    /************* Vertical decimation/scaling ******************/
+
+	/* Get Src Top and Bottom */
+	ulSrcTop = srcDest.ulSrcY1;
+	ulSrcBottom = srcDest.ulSrcY2;
+
+	ulSrc = ulSrcBottom - ulSrcTop;
+	ulDest = srcDest.lDstY2 - srcDest.lDstY1;	/* on-screen overlay */
+
+	if (ulSrc <= 1)
+		return -EINVAL;
+
+	/* First work out the position we are to display as offset from the
+	 * source of the buffer
+	 */
+	ulFxScale = (ulDest << 11) / ulSrc;	/* fixed point scale factor */
+	ulFxOffset = (srcDest.lDstY2 - srcDest.ulDstY2) << 11;
+
+	ulSrcBottom = ulSrcBottom - (ulFxOffset / ulFxScale);
+	ulSrc = ulSrcBottom - ulSrcTop;
+	ulHeight = ulSrc;
+
+	ulDest = srcDest.ulDstY2 - (srcDest.ulDstY1 - 1);
+	ulPattern = adwDecim8[ulBits];
+
+	/* At this point ulSrc represents the input decimator */
+	if (ulSrc > ulDest) {
+		ulDecimate = ulSrc - ulDest;
+		ulBits = 0;
+		ulApplied = ulSrc / 32;
+
+		while (((ulBits * ulApplied) +
+			Overlap((ulSrc % 32),
+				adwDecim8[ulBits])) < ulDecimate)
+			ulBits++;
+
+		ulPattern = adwDecim8[ulBits];
+		ulDecimated =
+		    (ulBits * ulApplied) + Overlap((ulSrc % 32),
+						   ulPattern);
+		ulSrc = ulSrc - ulDecimated;	/* the number number of lines that will go into the scaler */
+	}
+
+	if (ulBits && (ulBits != 32)) {
+		ulVertDecFactor = (63 - ulBits) / (32 - ulBits);	/* vertical decimation factor scaled up to nearest integer */
+	} else {
+		ulVertDecFactor = 1;
+	}
+
+	ulDacYScale = ((ulSrc - 1) * 2048) / (ulDest + 1);
+
+	tmp = STG_READ_REG(DACOverlayVtDec);	/* Decimation */
+	CLEAR_BITS_FRM_TO(0, 31);
+	tmp = ulPattern;
+	STG_WRITE_REG(DACOverlayVtDec, tmp);
+
+	/***************** Horizontal decimation/scaling ***************************/
+
+	/*
+	 * Now we handle the horizontal case, this is a simplified verison of
+	 * the vertical case in that we decimate by factors of 2.  as we are
+	 * working in words we should always be able to decimate by these
+	 * factors.  as we always have to have a buffer which is aligned to a
+	 * whole number of 128 bit words, we must align the left side to the
+	 * lowest to the next lowest 128 bit boundary, and the right hand edge
+	 * to the next largets boundary, (in a similar way to how we didi it in
+	 * PMX1) as the left and right hand edges are aligned to these
+	 * boundaries normally this only becomes an issue when we are chopping
+	 * of one of the sides We shall work out vertical stuff first
+	 */
+	ulSrc = srcDest.ulSrcX2 - srcDest.ulSrcX1;
+	ulDest = srcDest.lDstX2 - srcDest.lDstX1;
+#ifdef _OLDCODE
+	ulLeft = srcDest.ulDstX1;
+	ulRight = srcDest.ulDstX2;
+#else
+	if (srcDest.ulDstX1 > 2) {
+		ulLeft = srcDest.ulDstX1 + 2;
+		ulRight = srcDest.ulDstX2 + 1;
+	} else {
+		ulLeft = srcDest.ulDstX1;
+		ulRight = srcDest.ulDstX2 + 1;
+	}
+#endif
+	/* first work out the position we are to display as offset from the source of the buffer */
+	bResult = 1;
+
+	do {
+		if (ulDest == 0)
+			return -EINVAL;
+
+		/* source pixels per dest pixel <<11 */
+		ulFxScale = ((ulSrc - 1) << 11) / (ulDest);
+
+		/* then number of destination pixels out we are */
+		ulFxOffset = ulFxScale * ((srcDest.ulDstX1 - srcDest.lDstX1) + ulClipOff);
+		ulFxOffset >>= 11;
+
+		/* this replaces the code which was making a decision as to use either ulFxOffset or ulSrcX1 */
+		ulSrcLeft = srcDest.ulSrcX1 + ulFxOffset;
+
+		/* then number of destination pixels out we are */
+		ulFxOffset = ulFxScale * (srcDest.lDstX2 - srcDest.ulDstX2);
+		ulFxOffset >>= 11;
+
+		ulSrcRight = srcDest.ulSrcX2 - ulFxOffset;
+
+		/*
+		 * we must align these to our 128 bit boundaries. we shall
+		 * round down the pixel pos to the nearest 8 pixels.
+		 */
+		ulScaleLeft = ulSrcLeft;
+		ulScaleRight = ulSrcRight;
+
+		/* shift fxscale until it is in the range of the scaler */
+		ulhDecim = 0;
+		ulScale = (((ulSrcRight - ulSrcLeft) - 1) << (11 - ulhDecim)) / (ulRight - ulLeft + 2);
+
+		while (ulScale > 0x800) {
+			ulhDecim++;
+			ulScale = (((ulSrcRight - ulSrcLeft) - 1) << (11 - ulhDecim)) / (ulRight - ulLeft + 2);
+		}
+
+		/*
+		 * to try and get the best values We first try and use
+		 * src/dwdest for the scale factor, then we move onto src-1
+		 *
+		 * we want to check to see if we will need to clip data, if so
+		 * then we should clip our source so that we don't need to
+		 */
+		if (!ovlLinear) {
+			ulSrcLeft &= ~0x1f;
+
+			/*
+			 * we must align the right hand edge to the next 32
+			 * pixel` boundary, must be on a 256 boundary so u, and
+			 * v are 128 bit aligned
+			 */
+			ulSrcRight = (ulSrcRight + 0x1f) & ~0x1f;
+		} else {
+			ulSrcLeft &= ~0x7;
+
+			/*
+			 * we must align the right hand edge to the next
+			 * 8pixel` boundary
+			 */
+			ulSrcRight = (ulSrcRight + 0x7) & ~0x7;
+		}
+
+		/* this is the input size line store needs to cope with */
+		ulWidth = ulSrcRight - ulSrcLeft;
+
+		/*
+		 * use unclipped value to work out scale factror this is the
+		 * scale factor we want we shall now work out the horizonal
+		 * decimation and scaling
+		 */
+		ulsVal = ((ulWidth / 8) >> ulhDecim);
+
+		if ((ulWidth != (ulsVal << ulhDecim) * 8))
+			ulsAdd = 1;
+
+		/* input pixels to scaler; */
+		ulSrc = ulWidth >> ulhDecim;
+
+		if (ulSrc <= 2)
+			return -EINVAL;
+
+		ulExcessPixels = ((((ulScaleLeft - ulSrcLeft)) << (11 - ulhDecim)) / ulScale);
+
+		ulClip = (ulSrc << 11) / ulScale;
+		ulClip -= (ulRight - ulLeft);
+		ulClip += ulExcessPixels;
+
+		if (ulClip)
+			ulClip--;
+
+		/* We may need to do more here if we really have a HW rev < 5 */
+	} while (!bResult);
+
+	ulExtraLines = (1 << ulhDecim) * ulVertDecFactor;
+	ulExtraLines += 64;
+	ulHeight += ulExtraLines;
+
+	ulDacXScale = ulScale;
+
+
+	tmp = STG_READ_REG(DACVerticalScal);
+	CLEAR_BITS_FRM_TO(0, 11);
+	CLEAR_BITS_FRM_TO(16, 22);	/* Vertical Scaling */
+
+	/* Calculate new output line stride, this is always the number of 422
+	   words in the line buffer, so it doesn't matter if the
+	   mode is 420. Then set the vertical scale register.
+	 */
+	ulStride = (ulWidth >> (ulhDecim + 3)) + ulsAdd;
+	tmp |= ((ulStride << 16) | (ulDacYScale));	/* DAC_LS_CTRL = stride */
+	STG_WRITE_REG(DACVerticalScal, tmp);
+
+	/* Now set up the overlay size using the modified width and height
+	   from decimate and scaling calculations
+	 */
+	tmp = STG_READ_REG(DACOverlaySize);
+	CLEAR_BITS_FRM_TO(0, 10);
+	CLEAR_BITS_FRM_TO(12, 31);
+
+	if (ovlLinear) {
+		tmp |=
+		    (ovlStride | ((ulHeight + 1) << 12) |
+		     (((ulWidth / 8) - 1) << 23));
+	} else {
+		tmp |=
+		    (ovlStride | ((ulHeight + 1) << 12) |
+		     (((ulWidth / 32) - 1) << 23));
+	}
+
+	STG_WRITE_REG(DACOverlaySize, tmp);
+
+	/* Set Video Window Start */
+	tmp = ((ulLeft << 16)) | (srcDest.ulDstY1);
+	STG_WRITE_REG(DACVidWinStart, tmp);
+
+	/* Set Video Window End */
+	tmp = ((ulRight) << 16) | (srcDest.ulDstY2);
+	STG_WRITE_REG(DACVidWinEnd, tmp);
+
+	/* Finally set up the rest of the overlay regs in the order
+	   done in the IMG driver
+	 */
+	tmp = STG_READ_REG(DACPixelFormat);
+	tmp = ((ulExcessPixels << 16) | tmp) & 0x7fffffff;
+	STG_WRITE_REG(DACPixelFormat, tmp);
+
+	tmp = STG_READ_REG(DACHorizontalScal);
+	CLEAR_BITS_FRM_TO(0, 11);
+	CLEAR_BITS_FRM_TO(16, 17);
+	tmp |= ((ulhDecim << 16) | (ulDacXScale));
+	STG_WRITE_REG(DACHorizontalScal, tmp);
+
+	return 0;
+}
diff --git a/drivers/video/kyro/STG4000Ramdac.c b/drivers/video/kyro/STG4000Ramdac.c
new file mode 100644
index 0000000..e6ad037
--- /dev/null
+++ b/drivers/video/kyro/STG4000Ramdac.c
@@ -0,0 +1,163 @@
+/*
+ *  linux/drivers/video/kyro/STG4000Ramdac.c
+ *
+ *  Copyright (C) 2002 STMicroelectronics
+ *
+ * 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/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <video/kyro.h>
+
+#include "STG4000Reg.h"
+#include "STG4000Interface.h"
+
+static u32 STG_PIXEL_BUS_WIDTH = 128;	/* 128 bit bus width      */
+static u32 REF_CLOCK = 14318;
+
+int InitialiseRamdac(volatile STG4000REG __iomem * pSTGReg,
+		     u32 displayDepth,
+		     u32 displayWidth,
+		     u32 displayHeight,
+		     s32 HSyncPolarity,
+		     s32 VSyncPolarity, u32 * pixelClock)
+{
+	u32 tmp = 0;
+	u32 F = 0, R = 0, P = 0;
+	u32 stride = 0;
+	u32 ulPdiv = 0;
+	u32 physicalPixelDepth = 0;
+	/* Make sure DAC is in Reset */
+	tmp = STG_READ_REG(SoftwareReset);
+
+	if (tmp & 0x1) {
+		CLEAR_BIT(1);
+		STG_WRITE_REG(SoftwareReset, tmp);
+	}
+
+	/* Set Pixel Format */
+	tmp = STG_READ_REG(DACPixelFormat);
+	CLEAR_BITS_FRM_TO(0, 2);
+
+	/* Set LUT not used from 16bpp to 32 bpp ??? */
+	CLEAR_BITS_FRM_TO(8, 9);
+
+	switch (displayDepth) {
+	case 16:
+		{
+			physicalPixelDepth = 16;
+			tmp |= _16BPP;
+			break;
+		}
+	case 32:
+		{
+			/* Set for 32 bits per pixel */
+			physicalPixelDepth = 32;
+			tmp |= _32BPP;
+			break;
+		}
+	default:
+		return -EINVAL;
+	}
+
+	STG_WRITE_REG(DACPixelFormat, tmp);
+
+	/* Workout Bus transfer bandwidth according to pixel format */
+	ulPdiv = STG_PIXEL_BUS_WIDTH / physicalPixelDepth;
+
+	/* Get Screen Stride in pixels */
+	stride = displayWidth;
+
+	/* Set Primary size info */
+	tmp = STG_READ_REG(DACPrimSize);
+	CLEAR_BITS_FRM_TO(0, 10);
+	CLEAR_BITS_FRM_TO(12, 31);
+	tmp |=
+	    ((((displayHeight - 1) << 12) | (((displayWidth / ulPdiv) -
+					      1) << 23))
+	     | (stride / ulPdiv));
+	STG_WRITE_REG(DACPrimSize, tmp);
+
+
+	/* Set Pixel Clock */
+	*pixelClock = ProgramClock(REF_CLOCK, *pixelClock, &F, &R, &P);
+
+	/* Set DAC PLL Mode */
+	tmp = STG_READ_REG(DACPLLMode);
+	CLEAR_BITS_FRM_TO(0, 15);
+	/* tmp |= ((P-1) | ((F-2) << 2) | ((R-2) << 11)); */
+	tmp |= ((P) | ((F - 2) << 2) | ((R - 2) << 11));
+	STG_WRITE_REG(DACPLLMode, tmp);
+
+	/* Set Prim Address */
+	tmp = STG_READ_REG(DACPrimAddress);
+	CLEAR_BITS_FRM_TO(0, 20);
+	CLEAR_BITS_FRM_TO(20, 31);
+	STG_WRITE_REG(DACPrimAddress, tmp);
+
+	/* Set Cursor details with HW Cursor disabled */
+	tmp = STG_READ_REG(DACCursorCtrl);
+	tmp &= ~SET_BIT(31);
+	STG_WRITE_REG(DACCursorCtrl, tmp);
+
+	tmp = STG_READ_REG(DACCursorAddr);
+	CLEAR_BITS_FRM_TO(0, 20);
+	STG_WRITE_REG(DACCursorAddr, tmp);
+
+	/* Set Video Window */
+	tmp = STG_READ_REG(DACVidWinStart);
+	CLEAR_BITS_FRM_TO(0, 10);
+	CLEAR_BITS_FRM_TO(16, 26);
+	STG_WRITE_REG(DACVidWinStart, tmp);
+
+	tmp = STG_READ_REG(DACVidWinEnd);
+	CLEAR_BITS_FRM_TO(0, 10);
+	CLEAR_BITS_FRM_TO(16, 26);
+	STG_WRITE_REG(DACVidWinEnd, tmp);
+
+	/* Set DAC Border Color to default */
+	tmp = STG_READ_REG(DACBorderColor);
+	CLEAR_BITS_FRM_TO(0, 23);
+	STG_WRITE_REG(DACBorderColor, tmp);
+
+	/* Set Graphics and Overlay Burst Control */
+	STG_WRITE_REG(DACBurstCtrl, 0x0404);
+
+	/* Set CRC Trigger to default */
+	tmp = STG_READ_REG(DACCrcTrigger);
+	CLEAR_BIT(0);
+	STG_WRITE_REG(DACCrcTrigger, tmp);
+
+	/* Set Video Port Control to default */
+	tmp = STG_READ_REG(DigVidPortCtrl);
+	CLEAR_BIT(8);
+	CLEAR_BITS_FRM_TO(16, 27);
+	CLEAR_BITS_FRM_TO(1, 3);
+	CLEAR_BITS_FRM_TO(10, 11);
+	STG_WRITE_REG(DigVidPortCtrl, tmp);
+
+	return 0;
+}
+
+/* Ramdac control, turning output to the screen on and off */
+void DisableRamdacOutput(volatile STG4000REG __iomem * pSTGReg)
+{
+	u32 tmp;
+
+	/* Disable DAC for Graphics Stream Control */
+	tmp = (STG_READ_REG(DACStreamCtrl)) & ~SET_BIT(0);
+	STG_WRITE_REG(DACStreamCtrl, tmp);
+}
+
+void EnableRamdacOutput(volatile STG4000REG __iomem * pSTGReg)
+{
+	u32 tmp;
+
+	/* Enable DAC for Graphics Stream Control */
+	tmp = (STG_READ_REG(DACStreamCtrl)) | SET_BIT(0);
+	STG_WRITE_REG(DACStreamCtrl, tmp);
+}
diff --git a/drivers/video/kyro/STG4000Reg.h b/drivers/video/kyro/STG4000Reg.h
new file mode 100644
index 0000000..244549e
--- /dev/null
+++ b/drivers/video/kyro/STG4000Reg.h
@@ -0,0 +1,283 @@
+/*
+ *  linux/drivers/video/kyro/STG4000Reg.h
+ *
+ *  Copyright (C) 2002 STMicroelectronics
+ *
+ * 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 _STG4000REG_H
+#define _STG4000REG_H
+
+#define DWFILL unsigned long :32
+#define WFILL unsigned short :16
+
+/*
+ * Macros that access memory mapped card registers in PCI space
+ * Add an appropraite section for your OS or processor architecture.
+ */
+#if defined(__KERNEL__)
+#include <asm/page.h>
+#include <asm/io.h>
+#define STG_WRITE_REG(reg,data) (writel(data,&pSTGReg->reg))
+#define STG_READ_REG(reg)      (readl(&pSTGReg->reg))
+#else
+#define STG_WRITE_REG(reg,data) (pSTGReg->reg = data)
+#define STG_READ_REG(reg)      (pSTGReg->reg)
+#endif /* __KERNEL__ */
+
+#define SET_BIT(n) (1<<(n))
+#define CLEAR_BIT(n) (tmp &= ~(1<<n))
+#define CLEAR_BITS_FRM_TO(frm, to) \
+{\
+int i; \
+    for(i = frm; i<= to; i++) \
+	{ \
+	    tmp &= ~(1<<i); \
+	} \
+}
+
+#define CLEAR_BIT_2(n) (usTemp &= ~(1<<n))
+#define CLEAR_BITS_FRM_TO_2(frm, to) \
+{\
+int i; \
+    for(i = frm; i<= to; i++) \
+	{ \
+	    usTemp &= ~(1<<i); \
+	} \
+}
+
+/* LUT select */
+typedef enum _LUT_USES {
+	NO_LUT = 0, RESERVED, GRAPHICS, OVERLAY
+} LUT_USES;
+
+/* Primary surface pixel format select */
+typedef enum _PIXEL_FORMAT {
+	_8BPP = 0, _15BPP, _16BPP, _24BPP, _32BPP
+} PIXEL_FORMAT;
+
+/* Overlay blending mode select */
+typedef enum _BLEND_MODE {
+	GRAPHICS_MODE = 0, COLOR_KEY, PER_PIXEL_ALPHA, GLOBAL_ALPHA,
+	CK_PIXEL_ALPHA, CK_GLOBAL_ALPHA
+} OVRL_BLEND_MODE;
+
+/* Overlay Pixel format select */
+typedef enum _OVRL_PIX_FORMAT {
+	UYVY, VYUY, YUYV, YVYU
+} OVRL_PIX_FORMAT;
+
+/* Register Table */
+typedef struct {
+	/* 0h  */
+	volatile unsigned long Thread0Enable;	/* 0x0000 */
+	volatile unsigned long Thread1Enable;	/* 0x0004 */
+	volatile unsigned long Thread0Recover;	/* 0x0008 */
+	volatile unsigned long Thread1Recover;	/* 0x000C */
+	volatile unsigned long Thread0Step;	/* 0x0010 */
+	volatile unsigned long Thread1Step;	/* 0x0014 */
+	volatile unsigned long VideoInStatus;	/* 0x0018 */
+	volatile unsigned long Core2InSignStart;	/* 0x001C */
+	volatile unsigned long Core1ResetVector;	/* 0x0020 */
+	volatile unsigned long Core1ROMOffset;	/* 0x0024 */
+	volatile unsigned long Core1ArbiterPriority;	/* 0x0028 */
+	volatile unsigned long VideoInControl;	/* 0x002C */
+	volatile unsigned long VideoInReg0CtrlA;	/* 0x0030 */
+	volatile unsigned long VideoInReg0CtrlB;	/* 0x0034 */
+	volatile unsigned long VideoInReg1CtrlA;	/* 0x0038 */
+	volatile unsigned long VideoInReg1CtrlB;	/* 0x003C */
+	volatile unsigned long Thread0Kicker;	/* 0x0040 */
+	volatile unsigned long Core2InputSign;	/* 0x0044 */
+	volatile unsigned long Thread0ProgCtr;	/* 0x0048 */
+	volatile unsigned long Thread1ProgCtr;	/* 0x004C */
+	volatile unsigned long Thread1Kicker;	/* 0x0050 */
+	volatile unsigned long GPRegister1;	/* 0x0054 */
+	volatile unsigned long GPRegister2;	/* 0x0058 */
+	volatile unsigned long GPRegister3;	/* 0x005C */
+	volatile unsigned long GPRegister4;	/* 0x0060 */
+	volatile unsigned long SerialIntA;	/* 0x0064 */
+
+	volatile unsigned long Fill0[6];	/* GAP 0x0068 - 0x007C */
+
+	volatile unsigned long SoftwareReset;	/* 0x0080 */
+	volatile unsigned long SerialIntB;	/* 0x0084 */
+
+	volatile unsigned long Fill1[37];	/* GAP 0x0088 - 0x011C */
+
+	volatile unsigned long ROMELQV;	/* 0x011C */
+	volatile unsigned long WLWH;	/* 0x0120 */
+	volatile unsigned long ROMELWL;	/* 0x0124 */
+
+	volatile unsigned long dwFill_1;	/* GAP 0x0128 */
+
+	volatile unsigned long IntStatus;	/* 0x012C */
+	volatile unsigned long IntMask;	/* 0x0130 */
+	volatile unsigned long IntClear;	/* 0x0134 */
+
+	volatile unsigned long Fill2[6];	/* GAP 0x0138 - 0x014C */
+
+	volatile unsigned long ROMGPIOA;	/* 0x0150 */
+	volatile unsigned long ROMGPIOB;	/* 0x0154 */
+	volatile unsigned long ROMGPIOC;	/* 0x0158 */
+	volatile unsigned long ROMGPIOD;	/* 0x015C */
+
+	volatile unsigned long Fill3[2];	/* GAP 0x0160 - 0x0168 */
+
+	volatile unsigned long AGPIntID;	/* 0x0168 */
+	volatile unsigned long AGPIntClassCode;	/* 0x016C */
+	volatile unsigned long AGPIntBIST;	/* 0x0170 */
+	volatile unsigned long AGPIntSSID;	/* 0x0174 */
+	volatile unsigned long AGPIntPMCSR;	/* 0x0178 */
+	volatile unsigned long VGAFrameBufBase;	/* 0x017C */
+	volatile unsigned long VGANotify;	/* 0x0180 */
+	volatile unsigned long DACPLLMode;	/* 0x0184 */
+	volatile unsigned long Core1VideoClockDiv;	/* 0x0188 */
+	volatile unsigned long AGPIntStat;	/* 0x018C */
+
+	/*
+	   volatile unsigned long Fill4[0x0400/4 - 0x0190/4]; //GAP 0x0190 - 0x0400
+	   volatile unsigned long Fill5[0x05FC/4 - 0x0400/4]; //GAP 0x0400 - 0x05FC Fog Table
+	   volatile unsigned long Fill6[0x0604/4 - 0x0600/4]; //GAP 0x0600 - 0x0604
+	   volatile unsigned long Fill7[0x0680/4 - 0x0608/4]; //GAP 0x0608 - 0x0680
+	   volatile unsigned long Fill8[0x07FC/4 - 0x0684/4]; //GAP 0x0684 - 0x07FC
+	 */
+	volatile unsigned long Fill4[412];	/* 0x0190 - 0x07FC */
+
+	volatile unsigned long TACtrlStreamBase;	/* 0x0800 */
+	volatile unsigned long TAObjDataBase;	/* 0x0804 */
+	volatile unsigned long TAPtrDataBase;	/* 0x0808 */
+	volatile unsigned long TARegionDataBase;	/* 0x080C */
+	volatile unsigned long TATailPtrBase;	/* 0x0810 */
+	volatile unsigned long TAPtrRegionSize;	/* 0x0814 */
+	volatile unsigned long TAConfiguration;	/* 0x0818 */
+	volatile unsigned long TAObjDataStartAddr;	/* 0x081C */
+	volatile unsigned long TAObjDataEndAddr;	/* 0x0820 */
+	volatile unsigned long TAXScreenClip;	/* 0x0824 */
+	volatile unsigned long TAYScreenClip;	/* 0x0828 */
+	volatile unsigned long TARHWClamp;	/* 0x082C */
+	volatile unsigned long TARHWCompare;	/* 0x0830 */
+	volatile unsigned long TAStart;	/* 0x0834 */
+	volatile unsigned long TAObjReStart;	/* 0x0838 */
+	volatile unsigned long TAPtrReStart;	/* 0x083C */
+	volatile unsigned long TAStatus1;	/* 0x0840 */
+	volatile unsigned long TAStatus2;	/* 0x0844 */
+	volatile unsigned long TAIntStatus;	/* 0x0848 */
+	volatile unsigned long TAIntMask;	/* 0x084C */
+
+	volatile unsigned long Fill5[235];	/* GAP 0x0850 - 0x0BF8 */
+
+	volatile unsigned long TextureAddrThresh;	/* 0x0BFC */
+	volatile unsigned long Core1Translation;	/* 0x0C00 */
+	volatile unsigned long TextureAddrReMap;	/* 0x0C04 */
+	volatile unsigned long RenderOutAGPRemap;	/* 0x0C08 */
+	volatile unsigned long _3DRegionReadTrans;	/* 0x0C0C */
+	volatile unsigned long _3DPtrReadTrans;	/* 0x0C10 */
+	volatile unsigned long _3DParamReadTrans;	/* 0x0C14 */
+	volatile unsigned long _3DRegionReadThresh;	/* 0x0C18 */
+	volatile unsigned long _3DPtrReadThresh;	/* 0x0C1C */
+	volatile unsigned long _3DParamReadThresh;	/* 0x0C20 */
+	volatile unsigned long _3DRegionReadAGPRemap;	/* 0x0C24 */
+	volatile unsigned long _3DPtrReadAGPRemap;	/* 0x0C28 */
+	volatile unsigned long _3DParamReadAGPRemap;	/* 0x0C2C */
+	volatile unsigned long ZBufferAGPRemap;	/* 0x0C30 */
+	volatile unsigned long TAIndexAGPRemap;	/* 0x0C34 */
+	volatile unsigned long TAVertexAGPRemap;	/* 0x0C38 */
+	volatile unsigned long TAUVAddrTrans;	/* 0x0C3C */
+	volatile unsigned long TATailPtrCacheTrans;	/* 0x0C40 */
+	volatile unsigned long TAParamWriteTrans;	/* 0x0C44 */
+	volatile unsigned long TAPtrWriteTrans;	/* 0x0C48 */
+	volatile unsigned long TAParamWriteThresh;	/* 0x0C4C */
+	volatile unsigned long TAPtrWriteThresh;	/* 0x0C50 */
+	volatile unsigned long TATailPtrCacheAGPRe;	/* 0x0C54 */
+	volatile unsigned long TAParamWriteAGPRe;	/* 0x0C58 */
+	volatile unsigned long TAPtrWriteAGPRe;	/* 0x0C5C */
+	volatile unsigned long SDRAMArbiterConf;	/* 0x0C60 */
+	volatile unsigned long SDRAMConf0;	/* 0x0C64 */
+	volatile unsigned long SDRAMConf1;	/* 0x0C68 */
+	volatile unsigned long SDRAMConf2;	/* 0x0C6C */
+	volatile unsigned long SDRAMRefresh;	/* 0x0C70 */
+	volatile unsigned long SDRAMPowerStat;	/* 0x0C74 */
+
+	volatile unsigned long Fill6[2];	/* GAP 0x0C78 - 0x0C7C */
+
+	volatile unsigned long RAMBistData;	/* 0x0C80 */
+	volatile unsigned long RAMBistCtrl;	/* 0x0C84 */
+	volatile unsigned long FIFOBistKey;	/* 0x0C88 */
+	volatile unsigned long RAMBistResult;	/* 0x0C8C */
+	volatile unsigned long FIFOBistResult;	/* 0x0C90 */
+
+	/*
+	   volatile unsigned long Fill11[0x0CBC/4 - 0x0C94/4]; //GAP 0x0C94 - 0x0CBC
+	   volatile unsigned long Fill12[0x0CD0/4 - 0x0CC0/4]; //GAP 0x0CC0 - 0x0CD0 3DRegisters
+	 */
+
+	volatile unsigned long Fill7[16];	/* 0x0c94 - 0x0cd0 */
+
+	volatile unsigned long SDRAMAddrSign;	/* 0x0CD4 */
+	volatile unsigned long SDRAMDataSign;	/* 0x0CD8 */
+	volatile unsigned long SDRAMSignConf;	/* 0x0CDC */
+
+	/* DWFILL; //GAP 0x0CE0 */
+	volatile unsigned long dwFill_2;
+
+	volatile unsigned long ISPSignature;	/* 0x0CE4 */
+
+	volatile unsigned long Fill8[454];	/*GAP 0x0CE8 - 0x13FC */
+
+	volatile unsigned long DACPrimAddress;	/* 0x1400 */
+	volatile unsigned long DACPrimSize;	/* 0x1404 */
+	volatile unsigned long DACCursorAddr;	/* 0x1408 */
+	volatile unsigned long DACCursorCtrl;	/* 0x140C */
+	volatile unsigned long DACOverlayAddr;	/* 0x1410 */
+	volatile unsigned long DACOverlayUAddr;	/* 0x1414 */
+	volatile unsigned long DACOverlayVAddr;	/* 0x1418 */
+	volatile unsigned long DACOverlaySize;	/* 0x141C */
+	volatile unsigned long DACOverlayVtDec;	/* 0x1420 */
+
+	volatile unsigned long Fill9[9];	/* GAP 0x1424 - 0x1444 */
+
+	volatile unsigned long DACVerticalScal;	/* 0x1448 */
+	volatile unsigned long DACPixelFormat;	/* 0x144C */
+	volatile unsigned long DACHorizontalScal;	/* 0x1450 */
+	volatile unsigned long DACVidWinStart;	/* 0x1454 */
+	volatile unsigned long DACVidWinEnd;	/* 0x1458 */
+	volatile unsigned long DACBlendCtrl;	/* 0x145C */
+	volatile unsigned long DACHorTim1;	/* 0x1460 */
+	volatile unsigned long DACHorTim2;	/* 0x1464 */
+	volatile unsigned long DACHorTim3;	/* 0x1468 */
+	volatile unsigned long DACVerTim1;	/* 0x146C */
+	volatile unsigned long DACVerTim2;	/* 0x1470 */
+	volatile unsigned long DACVerTim3;	/* 0x1474 */
+	volatile unsigned long DACBorderColor;	/* 0x1478 */
+	volatile unsigned long DACSyncCtrl;	/* 0x147C */
+	volatile unsigned long DACStreamCtrl;	/* 0x1480 */
+	volatile unsigned long DACLUTAddress;	/* 0x1484 */
+	volatile unsigned long DACLUTData;	/* 0x1488 */
+	volatile unsigned long DACBurstCtrl;	/* 0x148C */
+	volatile unsigned long DACCrcTrigger;	/* 0x1490 */
+	volatile unsigned long DACCrcDone;	/* 0x1494 */
+	volatile unsigned long DACCrcResult1;	/* 0x1498 */
+	volatile unsigned long DACCrcResult2;	/* 0x149C */
+	volatile unsigned long DACLinecount;	/* 0x14A0 */
+
+	volatile unsigned long Fill10[151];	/*GAP 0x14A4 - 0x16FC */
+
+	volatile unsigned long DigVidPortCtrl;	/* 0x1700 */
+	volatile unsigned long DigVidPortStat;	/* 0x1704 */
+
+	/*
+	   volatile unsigned long Fill11[0x1FFC/4 - 0x1708/4]; //GAP 0x1708 - 0x1FFC
+	   volatile unsigned long Fill17[0x3000/4 - 0x2FFC/4]; //GAP 0x2000 - 0x2FFC ALUT
+	 */
+
+	volatile unsigned long Fill11[1598];
+
+	/* DWFILL; //GAP 0x3000          ALUT 256MB offset */
+	volatile unsigned long Fill_3;
+
+} STG4000REG;
+
+#endif /* _STG4000REG_H */
diff --git a/drivers/video/kyro/STG4000VTG.c b/drivers/video/kyro/STG4000VTG.c
new file mode 100644
index 0000000..3690b04
--- /dev/null
+++ b/drivers/video/kyro/STG4000VTG.c
@@ -0,0 +1,170 @@
+/*
+ *  linux/drivers/video/kyro/STG4000VTG.c
+ *
+ *  Copyright (C) 2002 STMicroelectronics
+ *
+ * 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/types.h>
+#include <video/kyro.h>
+
+#include "STG4000Reg.h"
+#include "STG4000Interface.h"
+
+void DisableVGA(volatile STG4000REG __iomem *pSTGReg)
+{
+	u32 tmp;
+	volatile u32 count, i;
+
+	/* Reset the VGA registers */
+	tmp = STG_READ_REG(SoftwareReset);
+	CLEAR_BIT(8);
+	STG_WRITE_REG(SoftwareReset, tmp);
+
+	/* Just for Delay */
+	for (i = 0; i < 1000; i++) {
+		count++;
+	}
+
+	/* Pull-out the VGA registers from reset */
+	tmp = STG_READ_REG(SoftwareReset);
+	tmp |= SET_BIT(8);
+	STG_WRITE_REG(SoftwareReset, tmp);
+}
+
+void StopVTG(volatile STG4000REG __iomem *pSTGReg)
+{
+	u32 tmp = 0;
+
+	/* Stop Ver and Hor Sync Generator */
+	tmp = (STG_READ_REG(DACSyncCtrl)) | SET_BIT(0) | SET_BIT(2);
+	CLEAR_BIT(31);
+	STG_WRITE_REG(DACSyncCtrl, tmp);
+}
+
+void StartVTG(volatile STG4000REG __iomem *pSTGReg)
+{
+	u32 tmp = 0;
+
+	/* Start Ver and Hor Sync Generator */
+	tmp = ((STG_READ_REG(DACSyncCtrl)) | SET_BIT(31));
+	CLEAR_BIT(0);
+	CLEAR_BIT(2);
+	STG_WRITE_REG(DACSyncCtrl, tmp);
+}
+
+void SetupVTG(volatile STG4000REG __iomem *pSTGReg,
+	      const struct kyrofb_info * pTiming)
+{
+	u32 tmp = 0;
+	u32 margins = 0;
+	u32 ulBorder;
+	u32 xRes = pTiming->XRES;
+	u32 yRes = pTiming->YRES;
+
+	/* Horizontal */
+	u32 HAddrTime, HRightBorder, HLeftBorder;
+	u32 HBackPorcStrt, HFrontPorchStrt, HTotal,
+	    HLeftBorderStrt, HRightBorderStrt, HDisplayStrt;
+
+	/* Vertical */
+	u32 VDisplayStrt, VBottomBorder, VTopBorder;
+	u32 VBackPorchStrt, VTotal, VTopBorderStrt,
+	    VFrontPorchStrt, VBottomBorderStrt, VAddrTime;
+
+	/* Need to calculate the right border */
+	if ((xRes == 640) && (yRes == 480)) {
+		if ((pTiming->VFREQ == 60) || (pTiming->VFREQ == 72)) {
+			margins = 8;
+		}
+	}
+
+	/* Work out the Border */
+	ulBorder =
+	    (pTiming->HTot -
+	     (pTiming->HST + (pTiming->HBP - margins) + xRes +
+	      (pTiming->HFP - margins))) >> 1;
+
+	/* Border the same for Vertical and Horizontal */
+	VBottomBorder = HLeftBorder = VTopBorder = HRightBorder = ulBorder;
+
+    /************ Get Timing values for Horizontal ******************/
+	HAddrTime = xRes;
+	HBackPorcStrt = pTiming->HST;
+	HTotal = pTiming->HTot;
+	HDisplayStrt =
+	    pTiming->HST + (pTiming->HBP - margins) + HLeftBorder;
+	HLeftBorderStrt = HDisplayStrt - HLeftBorder;
+	HFrontPorchStrt =
+	    pTiming->HST + (pTiming->HBP - margins) + HLeftBorder +
+	    HAddrTime + HRightBorder;
+	HRightBorderStrt = HFrontPorchStrt - HRightBorder;
+
+    /************ Get Timing values for Vertical ******************/
+	VAddrTime = yRes;
+	VBackPorchStrt = pTiming->VST;
+	VTotal = pTiming->VTot;
+	VDisplayStrt =
+	    pTiming->VST + (pTiming->VBP - margins) + VTopBorder;
+	VTopBorderStrt = VDisplayStrt - VTopBorder;
+	VFrontPorchStrt =
+	    pTiming->VST + (pTiming->VBP - margins) + VTopBorder +
+	    VAddrTime + VBottomBorder;
+	VBottomBorderStrt = VFrontPorchStrt - VBottomBorder;
+
+	/* Set Hor Timing 1, 2, 3 */
+	tmp = STG_READ_REG(DACHorTim1);
+	CLEAR_BITS_FRM_TO(0, 11);
+	CLEAR_BITS_FRM_TO(16, 27);
+	tmp |= (HTotal) | (HBackPorcStrt << 16);
+	STG_WRITE_REG(DACHorTim1, tmp);
+
+	tmp = STG_READ_REG(DACHorTim2);
+	CLEAR_BITS_FRM_TO(0, 11);
+	CLEAR_BITS_FRM_TO(16, 27);
+	tmp |= (HDisplayStrt << 16) | HLeftBorderStrt;
+	STG_WRITE_REG(DACHorTim2, tmp);
+
+	tmp = STG_READ_REG(DACHorTim3);
+	CLEAR_BITS_FRM_TO(0, 11);
+	CLEAR_BITS_FRM_TO(16, 27);
+	tmp |= (HFrontPorchStrt << 16) | HRightBorderStrt;
+	STG_WRITE_REG(DACHorTim3, tmp);
+
+	/* Set Ver Timing 1, 2, 3 */
+	tmp = STG_READ_REG(DACVerTim1);
+	CLEAR_BITS_FRM_TO(0, 11);
+	CLEAR_BITS_FRM_TO(16, 27);
+	tmp |= (VBackPorchStrt << 16) | (VTotal);
+	STG_WRITE_REG(DACVerTim1, tmp);
+
+	tmp = STG_READ_REG(DACVerTim2);
+	CLEAR_BITS_FRM_TO(0, 11);
+	CLEAR_BITS_FRM_TO(16, 27);
+	tmp |= (VDisplayStrt << 16) | VTopBorderStrt;
+	STG_WRITE_REG(DACVerTim2, tmp);
+
+	tmp = STG_READ_REG(DACVerTim3);
+	CLEAR_BITS_FRM_TO(0, 11);
+	CLEAR_BITS_FRM_TO(16, 27);
+	tmp |= (VFrontPorchStrt << 16) | VBottomBorderStrt;
+	STG_WRITE_REG(DACVerTim3, tmp);
+
+	/* Set Verical and Horizontal Polarity */
+	tmp = STG_READ_REG(DACSyncCtrl) | SET_BIT(3) | SET_BIT(1);
+
+	if ((pTiming->HSP > 0) && (pTiming->VSP < 0)) {	/* +hsync -vsync */
+		tmp &= ~0x8;
+	} else if ((pTiming->HSP < 0) && (pTiming->VSP > 0)) {	/* -hsync +vsync */
+		tmp &= ~0x2;
+	} else if ((pTiming->HSP < 0) && (pTiming->VSP < 0)) {	/* -hsync -vsync */
+		tmp &= ~0xA;
+	} else if ((pTiming->HSP > 0) && (pTiming->VSP > 0)) {	/* +hsync -vsync */
+		tmp &= ~0x0;
+	}
+
+	STG_WRITE_REG(DACSyncCtrl, tmp);
+}
diff --git a/drivers/video/kyro/fbdev.c b/drivers/video/kyro/fbdev.c
new file mode 100644
index 0000000..d8bac9e
--- /dev/null
+++ b/drivers/video/kyro/fbdev.c
@@ -0,0 +1,820 @@
+/*
+ *  linux/drivers/video/kyro/fbdev.c
+ *
+ *  Copyright (C) 2002 STMicroelectronics
+ *  Copyright (C) 2003, 2004 Paul Mundt
+ *
+ * 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/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/tty.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/ioctl.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include <video/kyro.h>
+
+#include "STG4000Reg.h"
+#include "STG4000Interface.h"
+
+/*
+ * PCI Definitions
+ */
+#define PCI_VENDOR_ID_ST	0x104a
+#define PCI_DEVICE_ID_STG4000	0x0010
+
+#define KHZ2PICOS(a) (1000000000UL/(a))
+
+/****************************************************************************/
+static struct fb_fix_screeninfo kyro_fix __devinitdata = {
+	.id		= "ST Kyro",
+	.type		= FB_TYPE_PACKED_PIXELS,
+	.visual		= FB_VISUAL_TRUECOLOR,
+	.accel		= FB_ACCEL_NONE,
+};
+
+static struct fb_var_screeninfo kyro_var __devinitdata = {
+	/* 640x480, 16bpp @ 60 Hz */
+	.xres		= 640,
+	.yres		= 480,
+	.xres_virtual	= 640,
+	.yres_virtual	= 480,
+	.bits_per_pixel	= 16,
+	.red		= { 11, 5, 0 },
+	.green		= {  5, 6, 0 },
+	.blue		= {  0, 5, 0 },
+	.activate	= FB_ACTIVATE_NOW,
+	.height		= -1,
+	.width		= -1,
+	.pixclock	= KHZ2PICOS(25175),
+	.left_margin	= 48,
+	.right_margin	= 16,
+	.upper_margin	= 33,
+	.lower_margin	= 10,
+	.hsync_len	= 96,
+	.vsync_len	= 2,
+	.vmode		= FB_VMODE_NONINTERLACED,
+};
+
+static struct kyrofb_info *currentpar;
+
+typedef struct {
+	STG4000REG __iomem *pSTGReg;	/* Virtual address of PCI register region */
+	u32 ulNextFreeVidMem;	/* Offset from start of vid mem to next free region */
+	u32 ulOverlayOffset;	/* Offset from start of vid mem to overlay */
+	u32 ulOverlayStride;	/* Interleaved YUV and 422 mode Y stride */
+	u32 ulOverlayUVStride;	/* 422 mode U & V stride */
+} device_info_t;
+
+/* global graphics card info structure (one per card) */
+static device_info_t deviceInfo;
+
+static char *mode_option __devinitdata = NULL;
+static int nopan __devinitdata = 0;
+static int nowrap __devinitdata = 1;
+#ifdef CONFIG_MTRR
+static int nomtrr __devinitdata = 0;
+#endif
+
+/* PCI driver prototypes */
+static int kyrofb_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
+static void kyrofb_remove(struct pci_dev *pdev);
+
+static struct fb_videomode kyro_modedb[] __devinitdata = {
+	{
+		/* 640x350 @ 85Hz */
+		NULL, 85, 640, 350, KHZ2PICOS(31500),
+		96, 32, 60, 32, 64, 3,
+		FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 640x400 @ 85Hz */
+		NULL, 85, 640, 400, KHZ2PICOS(31500),
+		96, 32, 41, 1, 64, 3,
+		FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 720x400 @ 85Hz */
+		NULL, 85, 720, 400, KHZ2PICOS(35500),
+		108, 36, 42, 1, 72, 3,
+		FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 640x480 @ 60Hz */
+		NULL, 60, 640, 480, KHZ2PICOS(25175),
+		48, 16, 33, 10, 96, 2,
+		0, FB_VMODE_NONINTERLACED
+	}, {
+		/* 640x480 @ 72Hz */
+		NULL, 72, 640, 480, KHZ2PICOS(31500),
+		128, 24, 28, 9, 40, 3,
+		0, FB_VMODE_NONINTERLACED
+	}, {
+		/* 640x480 @ 75Hz */
+		NULL, 75, 640, 480, KHZ2PICOS(31500),
+		120, 16, 16, 1, 64, 3,
+		0, FB_VMODE_NONINTERLACED
+	}, {
+		/* 640x480 @ 85Hz */
+		NULL, 85, 640, 480, KHZ2PICOS(36000),
+		80, 56, 25, 1, 56, 3,
+		0, FB_VMODE_NONINTERLACED
+	}, {
+		/* 800x600 @ 56Hz */
+		NULL, 56, 800, 600, KHZ2PICOS(36000),
+		128, 24, 22, 1, 72, 2,
+		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 800x600 @ 60Hz */
+		NULL, 60, 800, 600, KHZ2PICOS(40000),
+		88, 40, 23, 1, 128, 4,
+		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 800x600 @ 72Hz */
+		NULL, 72, 800, 600, KHZ2PICOS(50000),
+		64, 56, 23, 37, 120, 6,
+		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 800x600 @ 75Hz */
+		NULL, 75, 800, 600, KHZ2PICOS(49500),
+		160, 16, 21, 1, 80, 3,
+		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 800x600 @ 85Hz */
+		NULL, 85, 800, 600, KHZ2PICOS(56250),
+		152, 32, 27, 1, 64, 3,
+		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 1024x768 @ 60Hz */
+		NULL, 60, 1024, 768, KHZ2PICOS(65000),
+		160, 24, 29, 3, 136, 6,
+		0, FB_VMODE_NONINTERLACED
+	}, {
+		/* 1024x768 @ 70Hz */
+		NULL, 70, 1024, 768, KHZ2PICOS(75000),
+		144, 24, 29, 3, 136, 6,
+		0, FB_VMODE_NONINTERLACED
+	}, {
+		/* 1024x768 @ 75Hz */
+		NULL, 75, 1024, 768, KHZ2PICOS(78750),
+		176, 16, 28, 1, 96, 3,
+		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 1024x768 @ 85Hz */
+		NULL, 85, 1024, 768, KHZ2PICOS(94500),
+		208, 48, 36, 1, 96, 3,
+		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 1152x864 @ 75Hz */
+		NULL, 75, 1152, 864, KHZ2PICOS(108000),
+		256, 64, 32, 1, 128, 3,
+		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 1280x960 @ 60Hz */
+		NULL, 60, 1280, 960, KHZ2PICOS(108000),
+		312, 96, 36, 1, 112, 3,
+		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 1280x960 @ 85Hz */
+		NULL, 85, 1280, 960, KHZ2PICOS(148500),
+		224, 64, 47, 1, 160, 3,
+		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 1280x1024 @ 60Hz */
+		NULL, 60, 1280, 1024, KHZ2PICOS(108000),
+		248, 48, 38, 1, 112, 3,
+		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 1280x1024 @ 75Hz */
+		NULL, 75, 1280, 1024, KHZ2PICOS(135000),
+		248, 16, 38, 1, 144, 3,
+		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 1280x1024 @ 85Hz */
+		NULL, 85, 1280, 1024, KHZ2PICOS(157500),
+		224, 64, 44, 1, 160, 3,
+		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 1600x1200 @ 60Hz */
+		NULL, 60, 1600, 1200, KHZ2PICOS(162000),
+		304, 64, 46, 1, 192, 3,
+		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 1600x1200 @ 65Hz */
+		NULL, 65, 1600, 1200, KHZ2PICOS(175500),
+		304, 64, 46, 1, 192, 3,
+		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 1600x1200 @ 70Hz */
+		NULL, 70, 1600, 1200, KHZ2PICOS(189000),
+		304, 64, 46, 1, 192, 3,
+		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 1600x1200 @ 75Hz */
+		NULL, 75, 1600, 1200, KHZ2PICOS(202500),
+		304, 64, 46, 1, 192, 3,
+		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 1600x1200 @ 85Hz */
+		NULL, 85, 1600, 1200, KHZ2PICOS(229500),
+		304, 64, 46, 1, 192, 3,
+		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 1792x1344 @ 60Hz */
+		NULL, 60, 1792, 1344, KHZ2PICOS(204750),
+		328, 128, 46, 1, 200, 3,
+		FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 1792x1344 @ 75Hz */
+		NULL, 75, 1792, 1344, KHZ2PICOS(261000),
+		352, 96, 69, 1, 216, 3,
+		FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 1856x1392 @ 60Hz */
+		NULL, 60, 1856, 1392, KHZ2PICOS(218250),
+		352, 96, 43, 1, 224, 3,
+		FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 1856x1392 @ 75Hz */
+		NULL, 75, 1856, 1392, KHZ2PICOS(288000),
+		352, 128, 104, 1, 224, 3,
+		FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 1920x1440 @ 60Hz */
+		NULL, 60, 1920, 1440, KHZ2PICOS(234000),
+		344, 128, 56, 1, 208, 3,
+		FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}, {
+		/* 1920x1440 @ 75Hz */
+		NULL, 75, 1920, 1440, KHZ2PICOS(297000),
+		352, 144, 56, 1, 224, 3,
+		FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	},
+};
+#define NUM_TOTAL_MODES	ARRAY_SIZE(kyro_modedb)
+
+/*
+ * This needs to be kept ordered corresponding to kyro_modedb.
+ */
+enum {
+	VMODE_640_350_85,
+	VMODE_640_400_85,
+	VMODE_720_400_85,
+	VMODE_640_480_60,
+	VMODE_640_480_72,
+	VMODE_640_480_75,
+	VMODE_640_480_85,
+	VMODE_800_600_56,
+	VMODE_800_600_60,
+	VMODE_800_600_72,
+	VMODE_800_600_75,
+	VMODE_800_600_85,
+	VMODE_1024_768_60,
+	VMODE_1024_768_70,
+	VMODE_1024_768_75,
+	VMODE_1024_768_85,
+	VMODE_1152_864_75,
+	VMODE_1280_960_60,
+	VMODE_1280_960_85,
+	VMODE_1280_1024_60,
+	VMODE_1280_1024_75,
+	VMODE_1280_1024_85,
+	VMODE_1600_1200_60,
+	VMODE_1600_1200_65,
+	VMODE_1600_1200_70,
+	VMODE_1600_1200_75,
+	VMODE_1600_1200_85,
+	VMODE_1792_1344_60,
+	VMODE_1792_1344_75,
+	VMODE_1856_1392_60,
+	VMODE_1856_1392_75,
+	VMODE_1920_1440_60,
+	VMODE_1920_1440_75,
+};
+
+/* Accessors */
+static int kyro_dev_video_mode_set(struct fb_info *info)
+{
+	struct kyrofb_info *par = (struct kyrofb_info *)info->par;
+
+	/* Turn off display */
+	StopVTG(deviceInfo.pSTGReg);
+	DisableRamdacOutput(deviceInfo.pSTGReg);
+
+	/* Bring us out of VGA and into Hi-Res mode, if not already. */
+	DisableVGA(deviceInfo.pSTGReg);
+
+	if (InitialiseRamdac(deviceInfo.pSTGReg,
+			     info->var.bits_per_pixel,
+			     info->var.xres, info->var.yres,
+			     par->HSP, par->VSP, &par->PIXCLK) < 0)
+		return -EINVAL;
+
+	SetupVTG(deviceInfo.pSTGReg, par);
+
+	ResetOverlayRegisters(deviceInfo.pSTGReg);
+
+	/* Turn on display in new mode */
+	EnableRamdacOutput(deviceInfo.pSTGReg);
+	StartVTG(deviceInfo.pSTGReg);
+
+	deviceInfo.ulNextFreeVidMem = info->var.xres * info->var.yres *
+				      info->var.bits_per_pixel;
+	deviceInfo.ulOverlayOffset = 0;
+
+	return 0;
+}
+
+static int kyro_dev_overlay_create(u32 ulWidth,
+				   u32 ulHeight, int bLinear)
+{
+	u32 offset;
+	u32 stride, uvStride;
+
+	if (deviceInfo.ulOverlayOffset != 0)
+		/*
+		 * Can only create one overlay without resetting the card or
+		 * changing display mode
+		 */
+		return -EINVAL;
+
+	ResetOverlayRegisters(deviceInfo.pSTGReg);
+
+	/* Overlays are addressed in multiples of 16bytes or 32bytes, so make
+	 * sure the start offset is on an appropriate boundary.
+	 */
+	offset = deviceInfo.ulNextFreeVidMem;
+	if ((offset & 0x1f) != 0) {
+		offset = (offset + 32L) & 0xffffffE0L;
+	}
+
+	if (CreateOverlaySurface(deviceInfo.pSTGReg, ulWidth, ulHeight,
+				 bLinear, offset, &stride, &uvStride) < 0)
+		return -EINVAL;
+
+	deviceInfo.ulOverlayOffset = offset;
+	deviceInfo.ulOverlayStride = stride;
+	deviceInfo.ulOverlayUVStride = uvStride;
+	deviceInfo.ulNextFreeVidMem = offset + (ulHeight * stride) + (ulHeight * 2 * uvStride);
+
+	SetOverlayBlendMode(deviceInfo.pSTGReg, GLOBAL_ALPHA, 0xf, 0x0);
+
+	return 0;
+}
+
+static int kyro_dev_overlay_viewport_set(u32 x, u32 y, u32 ulWidth, u32 ulHeight)
+{
+	if (deviceInfo.ulOverlayOffset == 0)
+		/* probably haven't called CreateOverlay yet */
+		return -EINVAL;
+
+	/* Stop Ramdac Output */
+	DisableRamdacOutput(deviceInfo.pSTGReg);
+
+	SetOverlayViewPort(deviceInfo.pSTGReg,
+			   x, y, x + ulWidth - 1, y + ulHeight - 1);
+
+	EnableOverlayPlane(deviceInfo.pSTGReg);
+	/* Start Ramdac Output */
+	EnableRamdacOutput(deviceInfo.pSTGReg);
+
+	return 0;
+}
+
+static inline unsigned long get_line_length(int x, int bpp)
+{
+	return (unsigned long)((((x*bpp)+31)&~31) >> 3);
+}
+
+static int kyrofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct kyrofb_info *par = (struct kyrofb_info *)info->par;
+
+	if (var->bits_per_pixel != 16 && var->bits_per_pixel != 32) {
+		printk(KERN_WARNING "kyrofb: depth not supported: %u\n", var->bits_per_pixel);
+		return -EINVAL;
+	}
+
+	switch (var->bits_per_pixel) {
+	case 16:
+		var->red.offset = 11;
+		var->red.length = 5;
+		var->green.offset = 5;
+		var->green.length = 6;
+		var->blue.length = 5;
+		break;
+	case 32:
+		var->transp.offset = 24;
+		var->red.offset = 16;
+		var->green.offset = 8;
+		var->blue.offset = 0;
+
+		var->red.length = 8;
+		var->green.length = 8;
+		var->blue.length = 8;
+		var->transp.length = 8;
+		break;
+	}
+
+	/* Height/Width of picture in mm */
+	var->height = var->width = -1;
+
+	/* Timing information. All values are in picoseconds */
+
+	/* par->PIXCLK is in 100Hz units. Convert to picoseconds -
+	 * ensuring we do not exceed 32 bit precision
+	 */
+	/*
+	 * XXX: Enabling this really screws over the pixclock value when we
+	 * read it back with fbset. As such, leaving this commented out appears
+	 * to do the right thing (at least for now) .. bearing in mind that we
+	 * have infact already done the KHZ2PICOS conversion in both the modedb
+	 * and kyro_var. -- PFM.
+	 */
+//	var->pixclock = 1000000000 / (par->PIXCLK / 10);
+
+	/* the header file claims we should use picoseconds
+	 * - nobody else does though, the all use pixels and lines
+	 * of h and v sizes. Both options here.
+	 */
+
+	/*
+	 * If we're being called by __fb_try_mode(), then we don't want to
+	 * override any of the var settings that we've already parsed
+	 * from our modedb. -- PFM.
+	 */
+	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)
+		return 0;
+
+	var->left_margin = par->HBP;
+	var->hsync_len = par->HST;
+	var->right_margin = par->HFP;
+
+	var->upper_margin = par->VBP;
+	var->vsync_len = par->VST;
+	var->lower_margin = par->VFP;
+
+	if (par->HSP == 1)
+		var->sync |= FB_SYNC_HOR_HIGH_ACT;
+	if (par->VSP == 1)
+		var->sync |= FB_SYNC_VERT_HIGH_ACT;
+
+	return 0;
+}
+
+static int kyrofb_set_par(struct fb_info *info)
+{
+	struct kyrofb_info *par = (struct kyrofb_info *)info->par;
+	unsigned long lineclock;
+	unsigned long frameclock;
+
+	/* Actual resolution */
+	par->XRES = info->var.xres;
+	par->YRES = info->var.yres;
+
+	/* pixel depth */
+	par->PIXDEPTH = info->var.bits_per_pixel;
+
+	/* Refresh rate */
+	/* time for a line in ns */
+	lineclock = (info->var.pixclock * (info->var.xres +
+				    info->var.right_margin +
+				    info->var.hsync_len +
+				    info->var.left_margin)) / 1000;
+
+
+	/* time for a frame in ns (precision in 32bpp) */
+	frameclock = lineclock * (info->var.yres +
+				  info->var.lower_margin +
+				  info->var.vsync_len +
+				  info->var.upper_margin);
+
+	/* Calculate refresh rate and horrizontal clocks */
+	par->VFREQ = (1000000000 + (frameclock / 2)) / frameclock;
+	par->HCLK = (1000000000 + (lineclock / 2)) / lineclock;
+	par->PIXCLK = ((1000000000 + (info->var.pixclock / 2))
+					/ info->var.pixclock) * 10;
+
+	/* calculate horizontal timings */
+	par->HFP = info->var.right_margin;
+	par->HST = info->var.hsync_len;
+	par->HBP = info->var.left_margin;
+	par->HTot = par->XRES + par->HBP + par->HST + par->HFP;
+
+	/* calculate vertical timings */
+	par->VFP = info->var.lower_margin;
+	par->VST = info->var.vsync_len;
+	par->VBP = info->var.upper_margin;
+	par->VTot = par->YRES + par->VBP + par->VST + par->VFP;
+
+	par->HSP = (info->var.sync & FB_SYNC_HOR_HIGH_ACT) ? 1 : 0;
+	par->VSP = (info->var.sync & FB_SYNC_VERT_HIGH_ACT) ? 1 : 0;
+
+	kyro_dev_video_mode_set(info);
+
+	/* length of a line in bytes    */
+	info->fix.line_length = get_line_length(par->XRES, par->PIXDEPTH);
+	info->fix.visual = FB_VISUAL_TRUECOLOR;
+
+	return 0;
+}
+
+static int kyrofb_setcolreg(u_int regno, u_int red, u_int green,
+			    u_int blue, u_int transp, struct fb_info *info)
+{
+	if (regno > 255)
+		return 1;	/* Invalid register */
+
+	if (regno < 16) {
+		switch (info->var.bits_per_pixel) {
+		case 16:
+			((u16*)(info->pseudo_palette))[regno] =
+			     (red   & 0xf800) |
+			    ((green & 0xfc00) >> 5) |
+			    ((blue  & 0xf800) >> 11);
+			break;
+		case 32:
+			red >>= 8; green >>= 8; blue >>= 8; transp >>= 8;
+			((u32*)(info->pseudo_palette))[regno] =
+			    (transp << 24) | (red << 16) | (green << 8) | blue;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+#ifndef MODULE
+static int __init kyrofb_setup(char *options)
+{
+	char *this_opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ","))) {
+		if (!*this_opt)
+			continue;
+		if (strcmp(this_opt, "nopan") == 0) {
+			nopan = 1;
+		} else if (strcmp(this_opt, "nowrap") == 0) {
+			nowrap = 1;
+#ifdef CONFIG_MTRR
+		} else if (strcmp(this_opt, "nomtrr") == 0) {
+			nomtrr = 1;
+#endif
+		} else {
+			mode_option = this_opt;
+		}
+	}
+
+	return 0;
+}
+#endif
+
+static int kyrofb_ioctl(struct inode *inode, struct file *file,
+			unsigned int cmd, unsigned long arg,
+			struct fb_info *info)
+{
+	overlay_create ol_create;
+	overlay_viewport_set ol_viewport_set;
+	void __user *argp = (void __user *)arg;
+
+	switch (cmd) {
+	case KYRO_IOCTL_OVERLAY_CREATE:
+		if (copy_from_user(&ol_create, argp, sizeof(overlay_create)))
+			return -EFAULT;
+
+		if (kyro_dev_overlay_create(ol_create.ulWidth,
+					    ol_create.ulHeight, 0) < 0) {
+			printk(KERN_ERR "Kyro FB: failed to create overlay surface.\n");
+
+			return -EINVAL;
+		}
+		break;
+	case KYRO_IOCTL_OVERLAY_VIEWPORT_SET:
+		if (copy_from_user(&ol_viewport_set, argp,
+			       sizeof(overlay_viewport_set)))
+			return -EFAULT;
+
+		if (kyro_dev_overlay_viewport_set(ol_viewport_set.xOrgin,
+						  ol_viewport_set.yOrgin,
+						  ol_viewport_set.xSize,
+						  ol_viewport_set.ySize) != 0)
+		{
+			printk(KERN_ERR "Kyro FB: failed to create overlay viewport.\n");
+			return -EINVAL;
+		}
+		break;
+	case KYRO_IOCTL_SET_VIDEO_MODE:
+		{
+			printk(KERN_ERR "Kyro FB: KYRO_IOCTL_SET_VIDEO_MODE is"
+				"obsolete, use the appropriate fb_ioctl()"
+				"command instead.\n");
+			return -EINVAL;
+		}
+		break;
+	case KYRO_IOCTL_UVSTRIDE:
+		if (copy_to_user(argp, &deviceInfo.ulOverlayUVStride, sizeof(unsigned long)))
+			return -EFAULT;
+		break;
+	case KYRO_IOCTL_STRIDE:
+		if (copy_to_user(argp, &deviceInfo.ulOverlayStride, sizeof(unsigned long)))
+			return -EFAULT;
+		break;
+	case KYRO_IOCTL_OVERLAY_OFFSET:
+		if (copy_to_user(argp, &deviceInfo.ulOverlayOffset, sizeof(unsigned long)))
+			return -EFAULT;
+		break;
+	}
+
+	return 0;
+}
+
+static struct pci_device_id kyrofb_pci_tbl[] = {
+	{ PCI_VENDOR_ID_ST, PCI_DEVICE_ID_STG4000,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, kyrofb_pci_tbl);
+
+static struct pci_driver kyrofb_pci_driver = {
+	.name		= "kyrofb",
+	.id_table	= kyrofb_pci_tbl,
+	.probe		= kyrofb_probe,
+	.remove		= __devexit_p(kyrofb_remove),
+};
+
+static struct fb_ops kyrofb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= kyrofb_check_var,
+	.fb_set_par	= kyrofb_set_par,
+	.fb_setcolreg	= kyrofb_setcolreg,
+	.fb_ioctl	= kyrofb_ioctl,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+static int __devinit kyrofb_probe(struct pci_dev *pdev,
+				  const struct pci_device_id *ent)
+{
+	struct fb_info *info;
+	unsigned long size;
+	int err;
+
+	if ((err = pci_enable_device(pdev))) {
+		printk(KERN_WARNING "kyrofb: Can't enable pdev: %d\n", err);
+		return err;
+	}
+
+	size = sizeof(struct fb_info) + sizeof(struct kyrofb_info) + 16 * sizeof(u32);
+	info = kmalloc(size, GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	memset(info, 0, size);
+
+	currentpar = (struct kyrofb_info *)(info + 1);
+
+	kyro_fix.smem_start = pci_resource_start(pdev, 0);
+	kyro_fix.smem_len   = pci_resource_len(pdev, 0);
+	kyro_fix.mmio_start = pci_resource_start(pdev, 1);
+	kyro_fix.mmio_len   = pci_resource_len(pdev, 1);
+
+	currentpar->regbase = deviceInfo.pSTGReg =
+		ioremap_nocache(kyro_fix.mmio_start, kyro_fix.mmio_len);
+
+	info->screen_base = ioremap_nocache(kyro_fix.smem_start,
+					    kyro_fix.smem_len);
+
+#ifdef CONFIG_MTRR
+	if (!nomtrr)
+		currentpar->mtrr_handle =
+			mtrr_add(kyro_fix.smem_start,
+				 kyro_fix.smem_len,
+				 MTRR_TYPE_WRCOMB, 1);
+#endif
+
+	kyro_fix.ypanstep	= nopan ? 0 : 1;
+	kyro_fix.ywrapstep	= nowrap ? 0 : 1;
+
+	info->fbops		= &kyrofb_ops;
+	info->fix		= kyro_fix;
+	info->par		= currentpar;
+	info->pseudo_palette	= (void *)(currentpar + 1);
+	info->flags		= FBINFO_DEFAULT;
+
+	SetCoreClockPLL(deviceInfo.pSTGReg, pdev);
+
+	deviceInfo.ulNextFreeVidMem = 0;
+	deviceInfo.ulOverlayOffset = 0;
+
+	/* This should give a reasonable default video mode */
+	if (!fb_find_mode(&info->var, info, mode_option, kyro_modedb,
+			  NUM_TOTAL_MODES, &kyro_modedb[VMODE_1024_768_75], 32))
+		info->var = kyro_var;
+
+	fb_alloc_cmap(&info->cmap, 256, 0);
+
+	kyrofb_set_par(info);
+	kyrofb_check_var(&info->var, info);
+
+	size = get_line_length(info->var.xres_virtual,
+			       info->var.bits_per_pixel);
+	size *= info->var.yres_virtual;
+
+	fb_memset(info->screen_base, 0, size);
+
+	info->device = &pdev->dev;
+	if (register_framebuffer(info) < 0)
+		goto out_unmap;
+
+	printk("fb%d: %s frame buffer device, at %dx%d@%d using %ldk/%ldk of VRAM\n",
+	       info->node, info->fix.id, info->var.xres,
+	       info->var.yres, info->var.bits_per_pixel, size >> 10,
+	       (unsigned long)info->fix.smem_len >> 10);
+
+	pci_set_drvdata(pdev, info);
+
+	return 0;
+
+out_unmap:
+	iounmap(currentpar->regbase);
+	iounmap(info->screen_base);
+	kfree(info);
+
+	return -EINVAL;
+}
+
+static void __devexit kyrofb_remove(struct pci_dev *pdev)
+{
+	struct fb_info *info = pci_get_drvdata(pdev);
+	struct kyrofb_info *par = (struct kyrofb_info *)info->par;
+
+	/* Reset the board */
+	StopVTG(deviceInfo.pSTGReg);
+	DisableRamdacOutput(deviceInfo.pSTGReg);
+
+	/* Sync up the PLL */
+	SetCoreClockPLL(deviceInfo.pSTGReg, pdev);
+
+	deviceInfo.ulNextFreeVidMem = 0;
+	deviceInfo.ulOverlayOffset = 0;
+
+	iounmap(info->screen_base);
+	iounmap(par->regbase);
+
+#ifdef CONFIG_MTRR
+	if (par->mtrr_handle)
+		mtrr_del(par->mtrr_handle,
+			 info->fix.smem_start,
+			 info->fix.smem_len);
+#endif
+
+	unregister_framebuffer(info);
+	pci_set_drvdata(pdev, NULL);
+	kfree(info);
+}
+
+static int __init kyrofb_init(void)
+{
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("kyrofb", &option))
+		return -ENODEV;
+	kyrofb_setup(option);
+#endif
+	return pci_register_driver(&kyrofb_pci_driver);
+}
+
+static void __exit kyrofb_exit(void)
+{
+	pci_unregister_driver(&kyrofb_pci_driver);
+}
+
+module_init(kyrofb_init);
+
+#ifdef MODULE
+module_exit(kyrofb_exit);
+#endif
+
+MODULE_AUTHOR("STMicroelectronics; Paul Mundt <lethal@linux-sh.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/leo.c b/drivers/video/leo.c
new file mode 100644
index 0000000..7e1e7fb
--- /dev/null
+++ b/drivers/video/leo.c
@@ -0,0 +1,666 @@
+/* leo.c: LEO frame buffer driver
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996-1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1997 Michal Rehacek (Michal.Rehacek@st.mff.cuni.cz)
+ *
+ * Driver layout based loosely on tgafb.c, see that file for credits.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/mm.h>
+
+#include <asm/io.h>
+#include <asm/sbus.h>
+#include <asm/oplib.h>
+#include <asm/fbio.h>
+
+#include "sbuslib.h"
+
+/*
+ * Local functions.
+ */
+
+static int leo_setcolreg(unsigned, unsigned, unsigned, unsigned,
+			 unsigned, struct fb_info *);
+static int leo_blank(int, struct fb_info *);
+
+static int leo_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
+static int leo_ioctl(struct inode *, struct file *, unsigned int,
+		     unsigned long, struct fb_info *);
+static int leo_pan_display(struct fb_var_screeninfo *, struct fb_info *);
+
+/*
+ *  Frame buffer operations
+ */
+
+static struct fb_ops leo_ops = {
+	.owner			= THIS_MODULE,
+	.fb_setcolreg		= leo_setcolreg,
+	.fb_blank		= leo_blank,
+	.fb_pan_display		= leo_pan_display,
+	.fb_fillrect		= cfb_fillrect,
+	.fb_copyarea		= cfb_copyarea,
+	.fb_imageblit		= cfb_imageblit,
+	.fb_mmap		= leo_mmap,
+	.fb_ioctl		= leo_ioctl,
+	.fb_cursor		= soft_cursor,
+};
+
+#define LEO_OFF_LC_SS0_KRN	0x00200000UL
+#define LEO_OFF_LC_SS0_USR	0x00201000UL
+#define LEO_OFF_LC_SS1_KRN	0x01200000UL
+#define LEO_OFF_LC_SS1_USR	0x01201000UL
+#define LEO_OFF_LD_SS0		0x00400000UL
+#define LEO_OFF_LD_SS1		0x01400000UL
+#define LEO_OFF_LD_GBL		0x00401000UL
+#define LEO_OFF_LX_KRN		0x00600000UL
+#define LEO_OFF_LX_CURSOR	0x00601000UL
+#define LEO_OFF_SS0		0x00800000UL
+#define LEO_OFF_SS1		0x01800000UL
+#define LEO_OFF_UNK		0x00602000UL
+#define LEO_OFF_UNK2		0x00000000UL
+
+#define LEO_CUR_ENABLE		0x00000080
+#define LEO_CUR_UPDATE		0x00000030
+#define LEO_CUR_PROGRESS	0x00000006
+#define LEO_CUR_UPDATECMAP	0x00000003
+
+#define LEO_CUR_TYPE_MASK	0x00000000
+#define LEO_CUR_TYPE_IMAGE	0x00000020
+#define LEO_CUR_TYPE_CMAP	0x00000050
+
+struct leo_cursor {
+	u8		xxx0[16];
+	volatile u32	cur_type;
+	volatile u32	cur_misc;
+	volatile u32	cur_cursxy;
+	volatile u32	cur_data;
+};
+
+#define LEO_KRN_TYPE_CLUT0	0x00001000
+#define LEO_KRN_TYPE_CLUT1	0x00001001
+#define LEO_KRN_TYPE_CLUT2	0x00001002
+#define LEO_KRN_TYPE_WID	0x00001003
+#define LEO_KRN_TYPE_UNK	0x00001006
+#define LEO_KRN_TYPE_VIDEO	0x00002003
+#define LEO_KRN_TYPE_CLUTDATA	0x00004000
+#define LEO_KRN_CSR_ENABLE	0x00000008
+#define LEO_KRN_CSR_PROGRESS	0x00000004
+#define LEO_KRN_CSR_UNK		0x00000002
+#define LEO_KRN_CSR_UNK2	0x00000001
+
+struct leo_lx_krn {
+	volatile u32	krn_type;
+	volatile u32	krn_csr;
+	volatile u32	krn_value;
+};
+
+struct leo_lc_ss0_krn {
+	volatile u32 	misc;
+	u8		xxx0[0x800-4];
+	volatile u32	rev;
+};
+
+struct leo_lc_ss0_usr {
+	volatile u32	csr;
+	volatile u32	addrspace;
+	volatile u32 	fontmsk;
+	volatile u32	fontt;
+	volatile u32	extent;
+	volatile u32	src;
+	u32		dst;
+	volatile u32	copy;
+	volatile u32	fill;
+};
+
+struct leo_lc_ss1_krn {
+	u8	unknown;
+};
+
+struct leo_lc_ss1_usr {
+	u8	unknown;
+};
+
+struct leo_ld {
+	u8		xxx0[0xe00];
+	volatile u32	csr;
+	volatile u32	wid;
+	volatile u32	wmask;
+	volatile u32	widclip;
+	volatile u32	vclipmin;
+	volatile u32	vclipmax;
+	volatile u32	pickmin;	/* SS1 only */
+	volatile u32	pickmax;	/* SS1 only */
+	volatile u32	fg;
+	volatile u32	bg;
+	volatile u32	src;		/* Copy/Scroll (SS0 only) */
+	volatile u32	dst;		/* Copy/Scroll/Fill (SS0 only) */
+	volatile u32	extent;		/* Copy/Scroll/Fill size (SS0 only) */
+	u32		xxx1[3];
+	volatile u32	setsem;		/* SS1 only */
+	volatile u32	clrsem;		/* SS1 only */
+	volatile u32	clrpick;	/* SS1 only */
+	volatile u32	clrdat;		/* SS1 only */
+	volatile u32	alpha;		/* SS1 only */
+	u8		xxx2[0x2c];
+	volatile u32	winbg;
+	volatile u32	planemask;
+	volatile u32	rop;
+	volatile u32	z;
+	volatile u32	dczf;		/* SS1 only */
+	volatile u32	dczb;		/* SS1 only */
+	volatile u32	dcs;		/* SS1 only */
+	volatile u32	dczs;		/* SS1 only */
+	volatile u32	pickfb;		/* SS1 only */
+	volatile u32	pickbb;		/* SS1 only */
+	volatile u32	dcfc;		/* SS1 only */
+	volatile u32	forcecol;	/* SS1 only */
+	volatile u32	door[8];	/* SS1 only */
+	volatile u32	pick[5];	/* SS1 only */
+};
+
+#define LEO_SS1_MISC_ENABLE	0x00000001
+#define LEO_SS1_MISC_STEREO	0x00000002
+struct leo_ld_ss1 {
+	u8		xxx0[0xef4];
+	volatile u32	ss1_misc;
+};
+
+struct leo_ld_gbl {
+	u8	unknown;
+};
+
+struct leo_par {
+	spinlock_t		lock;
+	struct leo_lx_krn	__iomem *lx_krn;
+	struct leo_lc_ss0_usr	__iomem *lc_ss0_usr;
+	struct leo_ld_ss0	__iomem *ld_ss0;
+	struct leo_ld_ss1	__iomem *ld_ss1;
+	struct leo_cursor	__iomem *cursor;
+	u32			extent;
+	u32			clut_data[256];
+
+	u32			flags;
+#define LEO_FLAG_BLANKED	0x00000001
+
+	unsigned long		physbase;
+	unsigned long		fbsize;
+
+	struct sbus_dev		*sdev;
+	struct list_head	list;
+};
+
+static void leo_wait(struct leo_lx_krn __iomem *lx_krn)
+{
+	int i;
+	
+	for (i = 0;
+	     (sbus_readl(&lx_krn->krn_csr) & LEO_KRN_CSR_PROGRESS) && i < 300000;
+	     i++)
+		udelay (1); /* Busy wait at most 0.3 sec */
+	return;
+}
+
+/**
+ *      leo_setcolreg - Optional function. Sets a color register.
+ *      @regno: boolean, 0 copy local, 1 get_user() function
+ *      @red: frame buffer colormap structure
+ *      @green: The green value which can be up to 16 bits wide
+ *      @blue:  The blue value which can be up to 16 bits wide.
+ *      @transp: If supported the alpha value which can be up to 16 bits wide.
+ *      @info: frame buffer info structure
+ */
+static int leo_setcolreg(unsigned regno,
+			 unsigned red, unsigned green, unsigned blue,
+			 unsigned transp, struct fb_info *info)
+{
+	struct leo_par *par = (struct leo_par *) info->par;
+        struct leo_lx_krn __iomem *lx_krn = par->lx_krn;
+	unsigned long flags;
+	u32 val;
+	int i;
+
+	if (regno >= 256)
+		return 1;
+
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	par->clut_data[regno] = red | (green << 8) | (blue << 16);
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	leo_wait(lx_krn);
+
+	sbus_writel(LEO_KRN_TYPE_CLUTDATA, &lx_krn->krn_type);
+	for (i = 0; i < 256; i++)
+		sbus_writel(par->clut_data[i], &lx_krn->krn_value);
+	sbus_writel(LEO_KRN_TYPE_CLUT0, &lx_krn->krn_type);
+
+	val = sbus_readl(&lx_krn->krn_csr);
+	val |= (LEO_KRN_CSR_UNK | LEO_KRN_CSR_UNK2);
+	sbus_writel(val, &lx_krn->krn_csr);
+
+	spin_unlock_irqrestore(&par->lock, flags);
+
+	return 0;
+}
+
+/**
+ *      leo_blank - Optional function.  Blanks the display.
+ *      @blank_mode: the blank mode we want.
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int leo_blank(int blank, struct fb_info *info)
+{
+	struct leo_par *par = (struct leo_par *) info->par;
+	struct leo_lx_krn __iomem *lx_krn = par->lx_krn;
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	switch (blank) {
+	case FB_BLANK_UNBLANK: /* Unblanking */
+		val = sbus_readl(&lx_krn->krn_csr);
+		val |= LEO_KRN_CSR_ENABLE;
+		sbus_writel(val, &lx_krn->krn_csr);
+		par->flags &= ~LEO_FLAG_BLANKED;
+		break;
+
+	case FB_BLANK_NORMAL: /* Normal blanking */
+	case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
+	case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
+	case FB_BLANK_POWERDOWN: /* Poweroff */
+		val = sbus_readl(&lx_krn->krn_csr);
+		val &= ~LEO_KRN_CSR_ENABLE;
+		sbus_writel(val, &lx_krn->krn_csr);
+		par->flags |= LEO_FLAG_BLANKED;
+		break;
+	}
+
+	spin_unlock_irqrestore(&par->lock, flags);
+
+	return 0;
+}
+
+static struct sbus_mmap_map leo_mmap_map[] = {
+	{
+		.voff	= LEO_SS0_MAP,
+		.poff	= LEO_OFF_SS0,
+		.size	= 0x800000
+	},
+	{
+		.voff	= LEO_LC_SS0_USR_MAP,
+		.poff	= LEO_OFF_LC_SS0_USR,
+		.size	= 0x1000
+	},
+	{
+		.voff	= LEO_LD_SS0_MAP,
+		.poff	= LEO_OFF_LD_SS0,
+		.size	= 0x1000
+	},
+	{
+		.voff	= LEO_LX_CURSOR_MAP,
+		.poff	= LEO_OFF_LX_CURSOR,
+		.size	= 0x1000
+	},
+	{
+		.voff	= LEO_SS1_MAP,
+		.poff	= LEO_OFF_SS1,
+		.size	= 0x800000
+	},
+	{
+		.voff	= LEO_LC_SS1_USR_MAP,
+		.poff	= LEO_OFF_LC_SS1_USR,
+		.size	= 0x1000
+	},
+	{
+		.voff	= LEO_LD_SS1_MAP,
+		.poff	= LEO_OFF_LD_SS1,
+		.size	= 0x1000
+	},
+	{
+		.voff	= LEO_UNK_MAP,
+		.poff	= LEO_OFF_UNK,
+		.size	= 0x1000
+	},
+	{
+		.voff	= LEO_LX_KRN_MAP,
+		.poff	= LEO_OFF_LX_KRN,
+		.size	= 0x1000
+	},
+	{
+		.voff	= LEO_LC_SS0_KRN_MAP,
+		.poff	= LEO_OFF_LC_SS0_KRN,
+		.size	= 0x1000
+	},
+	{
+		.voff	= LEO_LC_SS1_KRN_MAP,
+		.poff	= LEO_OFF_LC_SS1_KRN,
+		.size	= 0x1000
+	},
+	{
+		.voff	= LEO_LD_GBL_MAP,
+		.poff	= LEO_OFF_LD_GBL,
+		.size	= 0x1000
+	},
+	{
+		.voff	= LEO_UNK2_MAP,
+		.poff	= LEO_OFF_UNK2,
+		.size	= 0x100000
+	},
+	{ .size = 0 }
+};
+
+static int leo_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+{
+	struct leo_par *par = (struct leo_par *)info->par;
+
+	return sbusfb_mmap_helper(leo_mmap_map,
+				  par->physbase, par->fbsize,
+				  par->sdev->reg_addrs[0].which_io,
+				  vma);
+}
+
+static int leo_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		     unsigned long arg, struct fb_info *info)
+{
+	struct leo_par *par = (struct leo_par *) info->par;
+
+	return sbusfb_ioctl_helper(cmd, arg, info,
+				   FBTYPE_SUNLEO, 32, par->fbsize);
+}
+
+/*
+ *  Initialisation
+ */
+
+static void
+leo_init_fix(struct fb_info *info)
+{
+	struct leo_par *par = (struct leo_par *)info->par;
+
+	strlcpy(info->fix.id, par->sdev->prom_name, sizeof(info->fix.id));
+
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.visual = FB_VISUAL_TRUECOLOR;
+
+	info->fix.line_length = 8192;
+
+	info->fix.accel = FB_ACCEL_SUN_LEO;
+}
+
+static void leo_wid_put(struct fb_info *info, struct fb_wid_list *wl)
+{
+	struct leo_par *par = (struct leo_par *) info->par;
+	struct leo_lx_krn __iomem *lx_krn = par->lx_krn;
+	struct fb_wid_item *wi;
+	unsigned long flags;
+	u32 val;
+	int i, j;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	leo_wait(lx_krn);
+
+	for (i = 0, wi = wl->wl_list; i < wl->wl_count; i++, wi++) {
+		switch(wi->wi_type) {
+		case FB_WID_DBL_8:
+			j = (wi->wi_index & 0xf) + 0x40;
+			break;
+
+		case FB_WID_DBL_24:
+			j = wi->wi_index & 0x3f;
+			break;
+
+		default:
+			continue;
+		};
+		sbus_writel(0x5800 + j, &lx_krn->krn_type);
+		sbus_writel(wi->wi_values[0], &lx_krn->krn_value);
+	}
+	sbus_writel(LEO_KRN_TYPE_WID, &lx_krn->krn_type);
+
+	val = sbus_readl(&lx_krn->krn_csr);
+	val |= (LEO_KRN_CSR_UNK | LEO_KRN_CSR_UNK2);
+	sbus_writel(val, &lx_krn->krn_csr);
+
+	spin_unlock_irqrestore(&par->lock, flags);
+}
+
+static void leo_init_wids(struct fb_info *info)
+{
+	struct fb_wid_item wi;
+	struct fb_wid_list wl;
+
+	wl.wl_count = 1;
+	wl.wl_list = &wi;
+	wi.wi_type = FB_WID_DBL_8;
+	wi.wi_index = 0;
+	wi.wi_values [0] = 0x2c0;
+	leo_wid_put(info, &wl);
+	wi.wi_index = 1;
+	wi.wi_values [0] = 0x30;
+	leo_wid_put(info, &wl);
+	wi.wi_index = 2;
+	wi.wi_values [0] = 0x20;
+	leo_wid_put(info, &wl);
+	wi.wi_type = FB_WID_DBL_24;
+	wi.wi_index = 1;
+	wi.wi_values [0] = 0x30;
+	leo_wid_put(info, &wl);
+
+}
+
+static void leo_switch_from_graph(struct fb_info *info)
+{
+	struct leo_par *par = (struct leo_par *) info->par;
+	struct leo_ld __iomem *ss = (struct leo_ld __iomem *) par->ld_ss0;
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	par->extent = ((info->var.xres - 1) |
+		       ((info->var.yres - 1) << 16));
+
+	sbus_writel(0xffffffff, &ss->wid);
+	sbus_writel(0xffff, &ss->wmask);
+	sbus_writel(0, &ss->vclipmin);
+	sbus_writel(par->extent, &ss->vclipmax);
+	sbus_writel(0, &ss->fg);
+	sbus_writel(0xff000000, &ss->planemask);
+	sbus_writel(0x310850, &ss->rop);
+	sbus_writel(0, &ss->widclip);
+	sbus_writel((info->var.xres-1) | ((info->var.yres-1) << 11),
+		    &par->lc_ss0_usr->extent);
+	sbus_writel(4, &par->lc_ss0_usr->addrspace);
+	sbus_writel(0x80000000, &par->lc_ss0_usr->fill);
+	sbus_writel(0, &par->lc_ss0_usr->fontt);
+	do {
+		val = sbus_readl(&par->lc_ss0_usr->csr);
+	} while (val & 0x20000000);
+
+	spin_unlock_irqrestore(&par->lock, flags);
+}
+
+static int leo_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	/* We just use this to catch switches out of
+	 * graphics mode.
+	 */
+	leo_switch_from_graph(info);
+
+	if (var->xoffset || var->yoffset || var->vmode)
+		return -EINVAL;
+	return 0;
+}
+
+static void leo_init_hw(struct fb_info *info)
+{
+	struct leo_par *par = (struct leo_par *) info->par;
+	u32 val;
+
+	val = sbus_readl(&par->ld_ss1->ss1_misc);
+	val |= LEO_SS1_MISC_ENABLE;
+	sbus_writel(val, &par->ld_ss1->ss1_misc);
+
+	leo_switch_from_graph(info);
+}
+
+static void leo_fixup_var_rgb(struct fb_var_screeninfo *var)
+{
+	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 = 0;
+	var->transp.length = 0;
+}
+
+struct all_info {
+	struct fb_info info;
+	struct leo_par par;
+	struct list_head list;
+};
+static LIST_HEAD(leo_list);
+
+static void leo_init_one(struct sbus_dev *sdev)
+{
+	struct all_info *all;
+	int linebytes;
+
+	all = kmalloc(sizeof(*all), GFP_KERNEL);
+	if (!all) {
+		printk(KERN_ERR "leo: Cannot allocate memory.\n");
+		return;
+	}
+	memset(all, 0, sizeof(*all));
+
+	INIT_LIST_HEAD(&all->list);
+
+	spin_lock_init(&all->par.lock);
+	all->par.sdev = sdev;
+
+	all->par.physbase = sdev->reg_addrs[0].phys_addr;
+
+	sbusfb_fill_var(&all->info.var, sdev->prom_node, 32);
+	leo_fixup_var_rgb(&all->info.var);
+
+	linebytes = prom_getintdefault(sdev->prom_node, "linebytes",
+				       all->info.var.xres);
+	all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
+
+#ifdef CONFIG_SPARC32
+	all->info.screen_base = (char __iomem *)
+		prom_getintdefault(sdev->prom_node, "address", 0);
+#endif
+	if (!all->info.screen_base)
+		all->info.screen_base = 
+			sbus_ioremap(&sdev->resource[0], LEO_OFF_SS0,
+				     0x800000, "leo ram");
+
+	all->par.lc_ss0_usr =
+		sbus_ioremap(&sdev->resource[0], LEO_OFF_LC_SS0_USR,
+			     0x1000, "leolc ss0usr");
+	all->par.ld_ss0 =
+		sbus_ioremap(&sdev->resource[0], LEO_OFF_LD_SS0,
+			     0x1000, "leold ss0");
+	all->par.ld_ss1 =
+		sbus_ioremap(&sdev->resource[0], LEO_OFF_LD_SS1,
+			     0x1000, "leold ss1");
+	all->par.lx_krn =
+		sbus_ioremap(&sdev->resource[0], LEO_OFF_LX_KRN,
+			     0x1000, "leolx krn");
+	all->par.cursor =
+		sbus_ioremap(&sdev->resource[0], LEO_OFF_LX_CURSOR,
+			     sizeof(struct leo_cursor), "leolx cursor");
+
+	all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+	all->info.fbops = &leo_ops;
+	all->info.par = &all->par;
+
+	leo_init_wids(&all->info);
+	leo_init_hw(&all->info);
+
+	leo_blank(0, &all->info);
+
+	if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
+		printk(KERN_ERR "leo: Could not allocate color map.\n");
+		kfree(all);
+		return;
+	}
+
+	leo_init_fix(&all->info);
+
+	if (register_framebuffer(&all->info) < 0) {
+		printk(KERN_ERR "leo: Could not register framebuffer.\n");
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+		return;
+	}
+
+	list_add(&all->list, &leo_list);
+
+	printk("leo: %s at %lx:%lx\n",
+	       sdev->prom_name,
+	       (long) sdev->reg_addrs[0].which_io,
+	       (long) sdev->reg_addrs[0].phys_addr);
+}
+
+int __init leo_init(void)
+{
+	struct sbus_bus *sbus;
+	struct sbus_dev *sdev;
+
+	if (fb_get_options("leofb", NULL))
+		return -ENODEV;
+
+	for_all_sbusdev(sdev, sbus) {
+		if (!strcmp(sdev->prom_name, "leo"))
+			leo_init_one(sdev);
+	}
+
+	return 0;
+}
+
+void __exit leo_exit(void)
+{
+	struct list_head *pos, *tmp;
+
+	list_for_each_safe(pos, tmp, &leo_list) {
+		struct all_info *all = list_entry(pos, typeof(*all), list);
+
+		unregister_framebuffer(&all->info);
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+	}
+}
+
+int __init
+leo_setup(char *arg)
+{
+	/* No cmdline options yet... */
+	return 0;
+}
+
+module_init(leo_init);
+#ifdef MODULE
+module_exit(leo_exit);
+#endif
+
+MODULE_DESCRIPTION("framebuffer driver for LEO chipsets");
+MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig
new file mode 100644
index 0000000..849b47b
--- /dev/null
+++ b/drivers/video/logo/Kconfig
@@ -0,0 +1,67 @@
+#
+# Logo configuration
+#
+
+menu "Logo configuration"
+
+config LOGO
+	bool "Bootup logo"
+	depends on FB || SGI_NEWPORT_CONSOLE
+
+config LOGO_LINUX_MONO
+	bool "Standard black and white Linux logo"
+	depends on LOGO
+	default y
+
+config LOGO_LINUX_VGA16
+	bool "Standard 16-color Linux logo"
+	depends on LOGO
+	default y
+
+config LOGO_LINUX_CLUT224
+	bool "Standard 224-color Linux logo"
+	depends on LOGO
+	default y
+
+config LOGO_DEC_CLUT224
+	bool "224-color Digital Equipment Corporation Linux logo"
+	depends on LOGO && (MACH_DECSTATION || ALPHA)
+	default y
+
+config LOGO_MAC_CLUT224
+	bool "224-color Macintosh Linux logo"
+	depends on LOGO && MAC
+	default y
+
+config LOGO_PARISC_CLUT224
+	bool "224-color PA-RISC Linux logo"
+	depends on LOGO && PARISC
+	default y
+
+config LOGO_SGI_CLUT224
+	bool "224-color SGI Linux logo"
+	depends on LOGO && (SGI_IP22 || SGI_IP27 || SGI_IP32 || X86_VISWS)
+	default y
+
+config LOGO_SUN_CLUT224
+	bool "224-color Sun Linux logo"
+	depends on LOGO && (SPARC || SPARC64)
+	default y
+
+config LOGO_SUPERH_MONO
+	bool "Black and white SuperH Linux logo"
+	depends on LOGO && SUPERH
+	default y
+
+config LOGO_SUPERH_VGA16
+	bool "16-color SuperH Linux logo"
+	depends on LOGO && SUPERH
+	default y
+
+config LOGO_SUPERH_CLUT224
+	bool "224-color SuperH Linux logo"
+	depends on LOGO && SUPERH
+	default y
+
+endmenu
+
diff --git a/drivers/video/logo/Makefile b/drivers/video/logo/Makefile
new file mode 100644
index 0000000..b0d9950
--- /dev/null
+++ b/drivers/video/logo/Makefile
@@ -0,0 +1,54 @@
+# Makefile for the Linux logos
+
+obj-$(CONFIG_LOGO)			+= logo.o
+obj-$(CONFIG_LOGO_LINUX_MONO)		+= logo_linux_mono.o
+obj-$(CONFIG_LOGO_LINUX_VGA16)		+= logo_linux_vga16.o
+obj-$(CONFIG_LOGO_LINUX_CLUT224)	+= logo_linux_clut224.o
+obj-$(CONFIG_LOGO_DEC_CLUT224)		+= logo_dec_clut224.o
+obj-$(CONFIG_LOGO_MAC_CLUT224)		+= logo_mac_clut224.o
+obj-$(CONFIG_LOGO_PARISC_CLUT224)	+= logo_parisc_clut224.o
+obj-$(CONFIG_LOGO_SGI_CLUT224)		+= logo_sgi_clut224.o
+obj-$(CONFIG_LOGO_SUN_CLUT224)		+= logo_sun_clut224.o
+obj-$(CONFIG_LOGO_SUPERH_MONO)		+= logo_superh_mono.o
+obj-$(CONFIG_LOGO_SUPERH_VGA16)		+= logo_superh_vga16.o
+obj-$(CONFIG_LOGO_SUPERH_CLUT224)	+= logo_superh_clut224.o
+
+# How to generate logo's
+
+# Use logo-cfiles to retreive list of .c files to be built
+logo-cfiles = $(notdir $(patsubst %.$(2), %.c, \
+              $(wildcard $(srctree)/$(src)/*$(1).$(2))))
+
+
+# Mono logos
+extra-y += $(call logo-cfiles,_mono,pbm)
+
+# VGA16 logos
+extra-y += $(call logo-cfiles,_vga16,ppm)
+
+# 224 Logos
+extra-y += $(call logo-cfiles,_clut224,ppm)
+
+# Gray 256
+extra-y += $(call logo-cfiles,_gray256,pgm)
+
+# Create commands like "pnmtologo -t mono -n logo_mac_mono -o ..."
+quiet_cmd_logo = LOGO	$@
+	cmd_logo = scripts/pnmtologo \
+			-t $(patsubst $*_%,%,$(notdir $(basename $<))) \
+			-n $(notdir $(basename $<)) -o $@ $<
+
+$(obj)/%_mono.c: $(src)/%_mono.pbm FORCE
+	$(call if_changed,logo)
+
+$(obj)/%_vga16.c: $(src)/%_vga16.ppm FORCE
+	$(call if_changed,logo)
+
+$(obj)/%_clut224.c: $(src)/%_clut224.ppm FORCE
+	$(call if_changed,logo)
+
+$(obj)/%_gray256.c: $(src)/%_gray256.pgm FORCE
+	$(call if_changed,logo)
+
+# Files generated that shall be removed upon make clean
+clean-files := *.o *_mono.c *_vga16.c *_clut224.c *_gray256.c
diff --git a/drivers/video/logo/clut_vga16.ppm b/drivers/video/logo/clut_vga16.ppm
new file mode 100644
index 0000000..aaf7c38
--- /dev/null
+++ b/drivers/video/logo/clut_vga16.ppm
@@ -0,0 +1,20 @@
+P3
+# Standard console colors
+16 1
+255
+  0   0   0
+  0   0 170
+  0 170   0
+  0 170 170
+170   0   0
+170   0 170
+170  85   0
+170 170 170
+ 85  85  85
+ 85  85 255
+ 85 255  85
+ 85 255 255
+255  85  85
+255  85 255
+255 255  85
+255 255 255
diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c
new file mode 100644
index 0000000..77b6220
--- /dev/null
+++ b/drivers/video/logo/logo.c
@@ -0,0 +1,103 @@
+
+/*
+ *  Linux logo to be displayed on boot
+ *
+ *  Copyright (C) 1996 Larry Ewing (lewing@isc.tamu.edu)
+ *  Copyright (C) 1996,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *  Copyright (C) 2001 Greg Banks <gnb@alphalink.com.au>
+ *  Copyright (C) 2001 Jan-Benedict Glaw <jbglaw@lug-owl.de>
+ *  Copyright (C) 2003 Geert Uytterhoeven <geert@linux-m68k.org>
+ */
+
+#include <linux/config.h>
+#include <linux/linux_logo.h>
+#include <linux/stddef.h>
+#include <linux/module.h>
+
+#ifdef CONFIG_M68K
+#include <asm/setup.h>
+#endif
+
+#ifdef CONFIG_MIPS
+#include <asm/bootinfo.h>
+#endif
+
+extern const struct linux_logo logo_linux_mono;
+extern const struct linux_logo logo_linux_vga16;
+extern const struct linux_logo logo_linux_clut224;
+extern const struct linux_logo logo_dec_clut224;
+extern const struct linux_logo logo_mac_clut224;
+extern const struct linux_logo logo_parisc_clut224;
+extern const struct linux_logo logo_sgi_clut224;
+extern const struct linux_logo logo_sun_clut224;
+extern const struct linux_logo logo_superh_mono;
+extern const struct linux_logo logo_superh_vga16;
+extern const struct linux_logo logo_superh_clut224;
+
+
+const struct linux_logo *fb_find_logo(int depth)
+{
+	const struct linux_logo *logo = NULL;
+
+	if (depth >= 1) {
+#ifdef CONFIG_LOGO_LINUX_MONO
+		/* Generic Linux logo */
+		logo = &logo_linux_mono;
+#endif
+#ifdef CONFIG_LOGO_SUPERH_MONO
+		/* SuperH Linux logo */
+		logo = &logo_superh_mono;
+#endif
+	}
+	
+	if (depth >= 4) {
+#ifdef CONFIG_LOGO_LINUX_VGA16
+		/* Generic Linux logo */
+		logo = &logo_linux_vga16;
+#endif
+#ifdef CONFIG_LOGO_SUPERH_VGA16
+		/* SuperH Linux logo */
+		logo = &logo_superh_vga16;
+#endif
+	}
+	
+	if (depth >= 8) {
+#ifdef CONFIG_LOGO_LINUX_CLUT224
+		/* Generic Linux logo */
+		logo = &logo_linux_clut224;
+#endif
+#ifdef CONFIG_LOGO_DEC_CLUT224
+		/* DEC Linux logo on MIPS/MIPS64 or ALPHA */
+#ifndef CONFIG_ALPHA
+		if (mips_machgroup == MACH_GROUP_DEC)
+#endif
+			logo = &logo_dec_clut224;
+#endif
+#ifdef CONFIG_LOGO_MAC_CLUT224
+		/* Macintosh Linux logo on m68k */
+		if (MACH_IS_MAC)
+			logo = &logo_mac_clut224;
+#endif
+#ifdef CONFIG_LOGO_PARISC_CLUT224
+		/* PA-RISC Linux logo */
+		logo = &logo_parisc_clut224;
+#endif
+#ifdef CONFIG_LOGO_SGI_CLUT224
+		/* SGI Linux logo on MIPS/MIPS64 and VISWS */
+#ifndef CONFIG_X86_VISWS
+		if (mips_machgroup == MACH_GROUP_SGI)
+#endif
+			logo = &logo_sgi_clut224;
+#endif
+#ifdef CONFIG_LOGO_SUN_CLUT224
+		/* Sun Linux logo */
+		logo = &logo_sun_clut224;
+#endif
+#ifdef CONFIG_LOGO_SUPERH_CLUT224
+		/* SuperH Linux logo */
+		logo = &logo_superh_clut224;
+#endif
+	}
+	return logo;
+}
+EXPORT_SYMBOL_GPL(fb_find_logo);
diff --git a/drivers/video/logo/logo_dec_clut224.ppm b/drivers/video/logo/logo_dec_clut224.ppm
new file mode 100644
index 0000000..fd921ad
--- /dev/null
+++ b/drivers/video/logo/logo_dec_clut224.ppm
@@ -0,0 +1,1604 @@
+P3
+# 224-color Digital Equipment Corporation Linux logo
+80 80
+255
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6   6   6   6  10  10  10  10  10  10
+ 10  10  10   6   6   6   6   6   6   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  10  10  10  14  14  14
+ 22  22  22  26  26  26  30  30  30  34  34  34
+ 30  30  30  30  30  30  26  26  26  18  18  18
+ 14  14  14  10  10  10   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  14  14  14  26  26  26  42  42  42
+ 54  54  54  66  66  66  78  78  78  78  78  78
+ 78  78  78  74  74  74  66  66  66  54  54  54
+ 42  42  42  26  26  26  18  18  18  10  10  10
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 22  22  22  42  42  42  66  66  66  86  86  86
+ 66  66  66  38  38  38  38  38  38  22  22  22
+ 26  26  26  34  34  34  54  54  54  66  66  66
+ 86  86  86  70  70  70  46  46  46  26  26  26
+ 14  14  14   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  10  10  10  26  26  26
+ 50  50  50  82  82  82  58  58  58   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  6   6   6  54  54  54  86  86  86  66  66  66
+ 38  38  38  18  18  18   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  22  22  22  50  50  50
+ 78  78  78  34  34  34   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   6   6   6  70  70  70
+ 78  78  78  46  46  46  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  18  18  18  42  42  42  82  82  82
+ 26  26  26   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  14  14  14
+ 46  46  46  34  34  34   6   6   6   2   2   6
+ 42  42  42  78  78  78  42  42  42  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   0   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 10  10  10  30  30  30  66  66  66  58  58  58
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  26  26  26
+ 86  86  86 101 101 101  46  46  46  10  10  10
+  2   2   6  58  58  58  70  70  70  34  34  34
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 14  14  14  42  42  42  86  86  86  10  10  10
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  30  30  30
+ 94  94  94  94  94  94  58  58  58  26  26  26
+  2   2   6   6   6   6  78  78  78  54  54  54
+ 22  22  22   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 22  22  22  62  62  62  62  62  62   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  26  26  26
+ 54  54  54  38  38  38  18  18  18  10  10  10
+  2   2   6   2   2   6  34  34  34  82  82  82
+ 38  38  38  14  14  14   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 30  30  30  78  78  78  30  30  30   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  10  10  10
+ 10  10  10   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  78  78  78
+ 50  50  50  18  18  18   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 38  38  38  86  86  86  14  14  14   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  54  54  54
+ 66  66  66  26  26  26   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 42  42  42  82  82  82   2   2   6   2   2   6
+  2   2   6   6   6   6  10  10  10   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   6   6   6
+ 14  14  14  10  10  10   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  18  18  18
+ 82  82  82  34  34  34  10  10  10   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 46  46  46  86  86  86   2   2   6   2   2   6
+  6   6   6   6   6   6  22  22  22  34  34  34
+  6   6   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  18  18  18  34  34  34
+ 10  10  10  50  50  50  22  22  22   2   2   6
+  2   2   6   2   2   6   2   2   6  10  10  10
+ 86  86  86  42  42  42  14  14  14   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 46  46  46  86  86  86   2   2   6   2   2   6
+ 38  38  38 116 116 116  94  94  94  22  22  22
+ 22  22  22   2   2   6   2   2   6   2   2   6
+ 14  14  14  86  86  86 138 138 138 162 162 162
+154 154 154  38  38  38  26  26  26   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 86  86  86  46  46  46  14  14  14   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 46  46  46  86  86  86   2   2   6  14  14  14
+134 134 134 198 198 198 195 195 195 116 116 116
+ 10  10  10   2   2   6   2   2   6   6   6   6
+101  98  89 187 187 187 210 210 210 218 218 218
+214 214 214 134 134 134  14  14  14   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 86  86  86  50  50  50  18  18  18   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   1   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 46  46  46  86  86  86   2   2   6  54  54  54
+218 218 218 195 195 195 226 226 226 246 246 246
+ 58  58  58   2   2   6   2   2   6  30  30  30
+210 210 210 253 253 253 174 174 174 123 123 123
+221 221 221 234 234 234  74  74  74   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 70  70  70  58  58  58  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 46  46  46  82  82  82   2   2   6 106 106 106
+170 170 170  26  26  26  86  86  86 226 226 226
+123 123 123  10  10  10  14  14  14  46  46  46
+231 231 231 190 190 190   6   6   6  70  70  70
+ 90  90  90 238 238 238 158 158 158   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 70  70  70  58  58  58  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   1   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 42  42  42  86  86  86   6   6   6 116 116 116
+106 106 106   6   6   6  70  70  70 149 149 149
+128 128 128  18  18  18  38  38  38  54  54  54
+221 221 221 106 106 106   2   2   6  14  14  14
+ 46  46  46 190 190 190 198 198 198   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 74  74  74  62  62  62  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   1   0   0   0
+  0   0   1   0   0   0   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 42  42  42  94  94  94  14  14  14 101 101 101
+128 128 128   2   2   6  18  18  18 116 116 116
+118  98  46 121  92   8 121  92   8  98  78  10
+162 162 162 106 106 106   2   2   6   2   2   6
+  2   2   6 195 195 195 195 195 195   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 74  74  74  62  62  62  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   1   0   0   1
+  0   0   1   0   0   0   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 38  38  38  90  90  90  14  14  14  58  58  58
+210 210 210  26  26  26  54  38   6 154 114  10
+226 170  11 236 186  11 225 175  15 184 144  12
+215 174  15 175 146  61  37  26   9   2   2   6
+ 70  70  70 246 246 246 138 138 138   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 70  70  70  66  66  66  26  26  26   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 38  38  38  86  86  86  14  14  14  10  10  10
+195 195 195 188 164 115 192 133   9 225 175  15
+239 182  13 234 190  10 232 195  16 232 200  30
+245 207  45 241 208  19 232 195  16 184 144  12
+218 194 134 211 206 186  42  42  42   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 50  50  50  74  74  74  30  30  30   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 34  34  34  86  86  86  14  14  14   2   2   6
+121  87  25 192 133   9 219 162  10 239 182  13
+236 186  11 232 195  16 241 208  19 244 214  54
+246 218  60 246 218  38 246 215  20 241 208  19
+241 208  19 226 184  13 121  87  25   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 50  50  50  82  82  82  34  34  34  10  10  10
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 34  34  34  82  82  82  30  30  30  61  42   6
+180 123   7 206 145  10 230 174  11 239 182  13
+234 190  10 238 202  15 241 208  19 246 218  74
+246 218  38 246 215  20 246 215  20 246 215  20
+226 184  13 215 174  15 184 144  12   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 26  26  26  94  94  94  42  42  42  14  14  14
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  78  78  78  50  50  50 104  69   6
+192 133   9 216 158  10 236 178  12 236 186  11
+232 195  16 241 208  19 244 214  54 245 215  43
+246 215  20 246 215  20 241 208  19 198 155  10
+200 144  11 216 158  10 156 118  10   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  6   6   6  90  90  90  54  54  54  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  78  78  78  46  46  46  22  22  22
+137  92   6 210 162  10 239 182  13 238 190  10
+238 202  15 241 208  19 246 215  20 246 215  20
+241 208  19 203 166  17 185 133  11 210 150  10
+216 158  10 210 150  10 102  78  10   2   2   6
+  6   6   6  54  54  54  14  14  14   2   2   6
+  2   2   6  62  62  62  74  74  74  30  30  30
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 34  34  34  78  78  78  50  50  50   6   6   6
+ 94  70  30 139 102  15 190 146  13 226 184  13
+232 200  30 232 195  16 215 174  15 190 146  13
+168 122  10 192 133   9 210 150  10 213 154  11
+202 150  34 182 157 106 101  98  89   2   2   6
+  2   2   6  78  78  78 116 116 116  58  58  58
+  2   2   6  22  22  22  90  90  90  46  46  46
+ 18  18  18   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 38  38  38  86  86  86  50  50  50   6   6   6
+128 128 128 174 154 114 156 107  11 168 122  10
+198 155  10 184 144  12 197 138  11 200 144  11
+206 145  10 206 145  10 197 138  11 188 164 115
+195 195 195 198 198 198 174 174 174  14  14  14
+  2   2   6  22  22  22 116 116 116 116 116 116
+ 22  22  22   2   2   6  74  74  74  70  70  70
+ 30  30  30  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 50  50  50 101 101 101  26  26  26  10  10  10
+138 138 138 190 190 190 174 154 114 156 107  11
+197 138  11 200 144  11 197 138  11 192 133   9
+180 123   7 190 142  34 190 178 144 187 187 187
+202 202 202 221 221 221 214 214 214  66  66  66
+  2   2   6   2   2   6  50  50  50  62  62  62
+  6   6   6   2   2   6  10  10  10  90  90  90
+ 50  50  50  18  18  18   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  10  10  10  34  34  34
+ 74  74  74  74  74  74   2   2   6   6   6   6
+144 144 144 198 198 198 190 190 190 178 166 146
+154 121  60 156 107  11 156 107  11 168 124  44
+174 154 114 187 187 187 190 190 190 210 210 210
+246 246 246 253 253 253 253 253 253 182 182 182
+  6   6   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  62  62  62
+ 74  74  74  34  34  34  14  14  14   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  10  10  10  22  22  22  54  54  54
+ 94  94  94  18  18  18   2   2   6  46  46  46
+234 234 234 221 221 221 190 190 190 190 190 190
+190 190 190 187 187 187 187 187 187 190 190 190
+190 190 190 195 195 195 214 214 214 242 242 242
+253 253 253 253 253 253 253 253 253 253 253 253
+ 82  82  82   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  14  14  14
+ 86  86  86  54  54  54  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  18  18  18  46  46  46  90  90  90
+ 46  46  46  18  18  18   6   6   6 182 182 182
+253 253 253 246 246 246 206 206 206 190 190 190
+190 190 190 190 190 190 190 190 190 190 190 190
+206 206 206 231 231 231 250 250 250 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+202 202 202  14  14  14   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 42  42  42  86  86  86  42  42  42  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 14  14  14  38  38  38  74  74  74  66  66  66
+  2   2   6   6   6   6  90  90  90 250 250 250
+253 253 253 253 253 253 238 238 238 198 198 198
+190 190 190 190 190 190 195 195 195 221 221 221
+246 246 246 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253  82  82  82   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  78  78  78  70  70  70  34  34  34
+ 14  14  14   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 34  34  34  66  66  66  78  78  78   6   6   6
+  2   2   6  18  18  18 218 218 218 253 253 253
+253 253 253 253 253 253 253 253 253 246 246 246
+226 226 226 231 231 231 246 246 246 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 178 178 178   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  18  18  18  90  90  90  62  62  62
+ 30  30  30  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  10  10  10  26  26  26
+ 58  58  58  90  90  90  18  18  18   2   2   6
+  2   2   6 110 110 110 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+250 250 250 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 231 231 231  18  18  18   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  18  18  18  94  94  94
+ 54  54  54  26  26  26  10  10  10   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  22  22  22  50  50  50
+ 90  90  90  26  26  26   2   2   6   2   2   6
+ 14  14  14 195 195 195 250 250 250 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+250 250 250 242 242 242  54  54  54   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  38  38  38
+ 86  86  86  50  50  50  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  14  14  14  38  38  38  82  82  82
+ 34  34  34   2   2   6   2   2   6   2   2   6
+ 42  42  42 195 195 195 246 246 246 253 253 253
+253 253 253 253 253 253 253 253 253 250 250 250
+242 242 242 242 242 242 250 250 250 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 250 250 250 246 246 246 238 238 238
+226 226 226 231 231 231 101 101 101   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 38  38  38  82  82  82  42  42  42  14  14  14
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 10  10  10  26  26  26  62  62  62  66  66  66
+  2   2   6   2   2   6   2   2   6   6   6   6
+ 70  70  70 170 170 170 206 206 206 234 234 234
+246 246 246 250 250 250 250 250 250 238 238 238
+226 226 226 231 231 231 238 238 238 250 250 250
+250 250 250 250 250 250 246 246 246 231 231 231
+214 214 214 206 206 206 202 202 202 202 202 202
+198 198 198 202 202 202 182 182 182  18  18  18
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  62  62  62  66  66  66  30  30  30
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 14  14  14  42  42  42  82  82  82  18  18  18
+  2   2   6   2   2   6   2   2   6  10  10  10
+ 94  94  94 182 182 182 218 218 218 242 242 242
+250 250 250 253 253 253 253 253 253 250 250 250
+234 234 234 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 246 246 246
+238 238 238 226 226 226 210 210 210 202 202 202
+195 195 195 195 195 195 210 210 210 158 158 158
+  6   6   6  14  14  14  50  50  50  14  14  14
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  86  86  86  46  46  46
+ 18  18  18   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 22  22  22  54  54  54  70  70  70   2   2   6
+  2   2   6  10  10  10   2   2   6  22  22  22
+166 166 166 231 231 231 250 250 250 253 253 253
+253 253 253 253 253 253 253 253 253 250 250 250
+242 242 242 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 246 246 246
+231 231 231 206 206 206 198 198 198 226 226 226
+ 94  94  94   2   2   6   6   6   6  38  38  38
+ 30  30  30   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  62  62  62  66  66  66
+ 26  26  26  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  74  74  74  50  50  50   2   2   6
+ 26  26  26  26  26  26   2   2   6 106 106 106
+238 238 238 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 246 246 246 218 218 218 202 202 202
+210 210 210  14  14  14   2   2   6   2   2   6
+ 30  30  30  22  22  22   2   2   6   2   2   6
+  2   2   6   2   2   6  18  18  18  86  86  86
+ 42  42  42  14  14  14   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 42  42  42  90  90  90  22  22  22   2   2   6
+ 42  42  42   2   2   6  18  18  18 218 218 218
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 250 250 250 221 221 221
+218 218 218 101 101 101   2   2   6  14  14  14
+ 18  18  18  38  38  38  10  10  10   2   2   6
+  2   2   6   2   2   6   2   2   6  78  78  78
+ 58  58  58  22  22  22   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 54  54  54  82  82  82   2   2   6  26  26  26
+ 22  22  22 175 118   6 175 118   6 175 118   6
+175 118   6 175 118   6 175 118   6 175 118   6
+175 118   6 175 118   6 175 118   6 253 253 253
+175 118   6 175 118   6 175 118   6 175 118   6
+175 118   6 175 118   6 175 118   6 253 253 253
+175 118   6 175 118   6 175 118   6 175 118   6
+175 118   6 175 118   6 175 118   6 175 118   6
+175 118   6 253 253 253   6   6   6  38  38  38
+ 58  58  58  26  26  26  38  38  38   2   2   6
+  2   2   6   2   2   6   2   2   6  46  46  46
+ 78  78  78  30  30  30  10  10  10   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  10  10  10  30  30  30
+ 74  74  74  58  58  58   2   2   6  42  42  42
+  2   2   6 175 118   6 175 118   6 175 118   6
+175 118   6 175 118   6 175 118   6 253 253 253
+253 253 253 253 253 253 175 118   6 253 253 253
+175 118   6 175 118   6 175 118   6 175 118   6
+175 118   6 175 118   6 175 118   6 253 253 253
+175 118   6 175 118   6 175 118   6 175 118   6
+175 118   6 175 118   6 175 118   6 175 118   6
+175 118   6 253 253 253  46  46  46  38  38  38
+ 42  42  42  14  14  14  38  38  38  14  14  14
+  2   2   6   2   2   6   2   2   6   6   6   6
+ 86  86  86  46  46  46  14  14  14   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  14  14  14  42  42  42
+ 90  90  90  18  18  18  18  18  18  26  26  26
+  2   2   6 175 118   6 175 118   6 175 118   6
+175 118   6 175 118   6 175 118   6 253 253 253
+253 253 253 253 253 253 175 118   6 253 253 253
+175 118   6 175 118   6 175 118   6 175 118   6
+175 118   6 175 118   6 175 118   6 253 253 253
+175 118   6 175 118   6 175 118   6 175 118   6
+175 118   6 175 118   6 175 118   6 175 118   6
+175 118   6 253 253 253  94  94  94   6   6   6
+  2   2   6   2   2   6  10  10  10  34  34  34
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 74  74  74  58  58  58  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  10  10  10  26  26  26  66  66  66
+ 82  82  82   2   2   6  38  38  38   6   6   6
+ 14  14  14 175 118   6 175 118   6 175 118   6
+253 253 253 253 253 253 175 118   6 253 253 253
+253 253 253 253 253 253 175 118   6 253 253 253
+175 118   6 253 253 253 253 253 253 253 253 253
+253 253 253 175 118   6 175 118   6 253 253 253
+175 118   6 175 118   6 175 118   6 253 253 253
+253 253 253 253 253 253 175 118   6 175 118   6
+175 118   6 253 253 253 144 144 144   2   2   6
+  2   2   6   2   2   6   2   2   6  46  46  46
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 42  42  42  74  74  74  30  30  30  10  10  10
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  14  14  14  42  42  42  90  90  90
+ 26  26  26   6   6   6  42  42  42   2   2   6
+ 74  74  74 175 118   6 175 118   6 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 175 118   6 253 253 253
+175 118   6 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 175 118   6 253 253 253
+175 118   6 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 175 118   6
+175 118   6 253 253 253 182 182 182   2   2   6
+  2   2   6   2   2   6   2   2   6  46  46  46
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 10  10  10  86  86  86  38  38  38  10  10  10
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 10  10  10  26  26  26  66  66  66  82  82  82
+  2   2   6  22  22  22  18  18  18   2   2   6
+149 149 149 175 118   6 175 118   6 253 253 253
+253 253 253 253 253 253 175 118   6 253 253 253
+253 253 253 253 253 253 175 118   6 253 253 253
+253 253 253 253 253 253 253 253 253 175 118   6
+253 253 253 253 253 253 253 253 253 253 253 253
+175 118   6 253 253 253 253 253 253 253 253 253
+175 118   6 253 253 253 253 253 253 253 253 253
+175 118   6 253 253 253 206 206 206   2   2   6
+  2   2   6   2   2   6   2   2   6  38  38  38
+  2   2   6   2   2   6   2   2   6   2   2   6
+  6   6   6  86  86  86  46  46  46  14  14  14
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 18  18  18  46  46  46  86  86  86  18  18  18
+  2   2   6  34  34  34  10  10  10   6   6   6
+210 210 210 175 118   6 175 118   6 253 253 253
+253 253 253 253 253 253 175 118   6 253 253 253
+253 253 253 253 253 253 175 118   6 253 253 253
+253 253 253 253 253 253 253 253 253 175 118   6
+253 253 253 253 253 253 253 253 253 253 253 253
+175 118   6 253 253 253 253 253 253 253 253 253
+175 118   6 253 253 253 253 253 253 253 253 253
+175 118   6 253 253 253 221 221 221   6   6   6
+  2   2   6   2   2   6   6   6   6  30  30  30
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  82  82  82  54  54  54  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 26  26  26  66  66  66  62  62  62   2   2   6
+  2   2   6  38  38  38  10  10  10  26  26  26
+238 238 238 175 118   6 175 118   6 253 253 253
+253 253 253 253 253 253 175 118   6 253 253 253
+253 253 253 253 253 253 175 118   6 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+175 118   6 253 253 253 253 253 253 253 253 253
+175 118   6 253 253 253 253 253 253 253 253 253
+175 118   6 253 253 253 231 231 231   6   6   6
+  2   2   6   2   2   6  10  10  10  30  30  30
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  66  66  66  58  58  58  22  22  22
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 38  38  38  78  78  78   6   6   6   2   2   6
+  2   2   6  46  46  46  14  14  14  42  42  42
+246 246 246 175 118   6 175 118   6 253 253 253
+253 253 253 253 253 253 175 118   6 253 253 253
+253 253 253 253 253 253 175 118   6 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+175 118   6 253 253 253 253 253 253 253 253 253
+175 118   6 175 118   6 175 118   6 175 118   6
+175 118   6 253 253 253 234 234 234  10  10  10
+  2   2   6   2   2   6  22  22  22  14  14  14
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  66  66  66  62  62  62  22  22  22
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 50  50  50  74  74  74   2   2   6   2   2   6
+ 14  14  14  70  70  70  34  34  34  62  62  62
+250 250 250 175 118   6 175 118   6 253 253 253
+253 253 253 253 253 253 175 118   6 253 253 253
+253 253 253 253 253 253 175 118   6 253 253 253
+253 253 253 253 253 253 253 253 253 175 118   6
+175 118   6 175 118   6 175 118   6 253 253 253
+175 118   6 253 253 253 253 253 253 253 253 253
+175 118   6 175 118   6 175 118   6 175 118   6
+175 118   6 253 253 253 234 234 234  14  14  14
+  2   2   6   2   2   6  30  30  30   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  66  66  66  62  62  62  22  22  22
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 54  54  54  62  62  62   2   2   6   2   2   6
+  2   2   6  30  30  30  46  46  46  70  70  70
+250 250 250 175 118   6 175 118   6 253 253 253
+253 253 253 253 253 253 175 118   6 253 253 253
+253 253 253 253 253 253 175 118   6 253 253 253
+253 253 253 253 253 253 253 253 253 175 118   6
+253 253 253 253 253 253 253 253 253 253 253 253
+175 118   6 253 253 253 253 253 253 253 253 253
+175 118   6 253 253 253 253 253 253 253 253 253
+175 118   6 253 253 253 226 226 226  10  10  10
+  2   2   6   6   6   6  30  30  30   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  66  66  66  58  58  58  22  22  22
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  22  22  22
+ 58  58  58  62  62  62   2   2   6   2   2   6
+  2   2   6   2   2   6  30  30  30  78  78  78
+250 250 250 175 118   6 175 118   6 253 253 253
+253 253 253 253 253 253 175 118   6 253 253 253
+253 253 253 253 253 253 175 118   6 253 253 253
+253 253 253 253 253 253 253 253 253 175 118   6
+253 253 253 253 253 253 253 253 253 253 253 253
+175 118   6 253 253 253 253 253 253 253 253 253
+175 118   6 253 253 253 253 253 253 253 253 253
+175 118   6 253 253 253 206 206 206   2   2   6
+ 22  22  22  34  34  34  18  14   6  22  22  22
+ 26  26  26  18  18  18   6   6   6   2   2   6
+  2   2   6  82  82  82  54  54  54  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  26  26  26
+ 62  62  62 106 106 106  74  54  14 185 133  11
+210 162  10 121  92   8   6   6   6  62  62  62
+238 238 238 175 118   6 175 118   6 253 253 253
+253 253 253 253 253 253 175 118   6 253 253 253
+253 253 253 253 253 253 175 118   6 253 253 253
+253 253 253 253 253 253 253 253 253 175 118   6
+253 253 253 253 253 253 253 253 253 253 253 253
+175 118   6 253 253 253 253 253 253 253 253 253
+175 118   6 253 253 253 253 253 253 253 253 253
+175 118   6 253 253 253 158 158 158  18  18  18
+ 14  14  14   2   2   6   2   2   6   2   2   6
+  6   6   6  18  18  18  66  66  66  38  38  38
+  6   6   6  94  94  94  50  50  50  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 10  10  10  10  10  10  18  18  18  38  38  38
+ 78  78  78 142 134 106 216 158  10 242 186  14
+246 190  14 246 190  14 156 118  10  10  10  10
+ 90  90  90 175 118   6 175 118   6 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 175 118   6 253 253 253
+175 118   6 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 175 118   6 253 253 253
+175 118   6 175 118   6 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 175 118   6
+175 118   6 253 253 253 181 142  44  37  26   9
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  38  38  38  46  46  46
+ 26  26  26 106 106 106  54  54  54  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  14  14  14  22  22  22
+ 30  30  30  38  38  38  50  50  50  70  70  70
+106 106 106 190 142  34 226 170  11 242 186  14
+246 190  14 246 190  14 246 190  14 154 114  10
+  6   6   6 175 118   6 175 118   6 175 118   6
+253 253 253 253 253 253 175 118   6 253 253 253
+253 253 253 253 253 253 175 118   6 253 253 253
+175 118   6 175 118   6 253 253 253 253 253 253
+253 253 253 253 253 253 175 118   6 253 253 253
+175 118   6 175 118   6 253 253 253 253 253 253
+253 253 253 253 253 253 175 118   6 175 118   6
+175 118   6 253 253 253 232 195  16  38  30  10
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  30  30  30  26  26  26
+203 166  17 154 142  90  66  66  66  26  26  26
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  18  18  18  38  38  38  58  58  58
+ 78  78  78  86  86  86 101 101 101 123 123 123
+175 146  61 210 150  10 234 174  13 246 186  14
+246 190  14 246 190  14 246 190  14 238 190  10
+102  78  10 175 118   6 175 118   6 175 118   6
+175 118   6 175 118   6 175 118   6 175 118   6
+175 118   6 175 118   6 175 118   6 253 253 253
+175 118   6 175 118   6 175 118   6 175 118   6
+175 118   6 175 118   6 175 118   6 253 253 253
+175 118   6 175 118   6 175 118   6 175 118   6
+175 118   6 175 118   6 175 118   6 175 118   6
+175 118   6 253 253 253 210 166  10  22  18   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   6   6   6 121  92   8
+238 202  15 232 195  16  82  82  82  34  34  34
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 14  14  14  38  38  38  70  70  70 154 122  46
+190 142  34 200 144  11 197 138  11 197 138  11
+213 154  11 226 170  11 242 186  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+225 175  15 175 118   6 175 118   6 175 118   6
+175 118   6 175 118   6 175 118   6 175 118   6
+175 118   6 175 118   6 175 118   6 253 253 253
+175 118   6 175 118   6 175 118   6 175 118   6
+175 118   6 175 118   6 175 118   6 253 253 253
+175 118   6 175 118   6 175 118   6 175 118   6
+175 118   6 175 118   6 175 118   6 175 118   6
+175 118   6 253 253 253 213 154  11  46  32   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  61  42   6 225 175  15
+238 190  10 236 186  11 112 100  78  42  42  42
+ 14  14  14   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 22  22  22  54  54  54 154 122  46 213 154  11
+226 170  11 230 174  11 226 170  11 226 170  11
+236 178  12 242 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+241 196  14 184 144  12  10  10  10   2   2   6
+  6   6   6 116 116 116 242 242 242 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 231 231 231 198 198 198 214 170  54
+236 178  12 236 178  12 210 150  10 137  92   6
+ 18  14   6   2   2   6   2   2   6   2   2   6
+  6   6   6  70  47   6 200 144  11 236 178  12
+239 182  13 239 182  13 124 112  88  58  58  58
+ 22  22  22   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  70  70  70 180 133  36 226 170  11
+239 182  13 242 186  14 242 186  14 246 186  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 232 195  16  98  70   6   2   2   6
+  2   2   6   2   2   6  66  66  66 221 221 221
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 206 206 206 198 198 198 214 166  58
+230 174  11 230 174  11 216 158  10 192 133   9
+163 110   8 116  81   8 102  78  10 116  81   8
+167 114   7 197 138  11 226 170  11 239 182  13
+242 186  14 242 186  14 162 146  94  78  78  78
+ 34  34  34  14  14  14   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 30  30  30  78  78  78 190 142  34 226 170  11
+239 182  13 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 241 196  14 203 166  17  22  18   6
+  2   2   6   2   2   6   2   2   6  38  38  38
+218 218 218 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+250 250 250 206 206 206 198 198 198 202 162  69
+226 170  11 236 178  12 224 166  10 210 150  10
+200 144  11 197 138  11 192 133   9 197 138  11
+210 150  10 226 170  11 242 186  14 246 190  14
+246 190  14 246 186  14 225 175  15 124 112  88
+ 62  62  62  30  30  30  14  14  14   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  78  78  78 174 135  50 224 166  10
+239 182  13 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 241 196  14 139 102  15
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 78  78  78 250 250 250 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+250 250 250 214 214 214 198 198 198 190 150  46
+219 162  10 236 178  12 234 174  13 224 166  10
+216 158  10 213 154  11 213 154  11 216 158  10
+226 170  11 239 182  13 246 190  14 246 190  14
+246 190  14 246 190  14 242 186  14 206 162  42
+101 101 101  58  58  58  30  30  30  14  14  14
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  74  74  74 174 135  50 216 158  10
+236 178  12 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 241 196  14 226 184  13
+ 61  42   6   2   2   6   2   2   6   2   2   6
+ 22  22  22 238 238 238 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 226 226 226 187 187 187 180 133  36
+216 158  10 236 178  12 239 182  13 236 178  12
+230 174  11 226 170  11 226 170  11 230 174  11
+236 178  12 242 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 186  14 239 182  13
+206 162  42 106 106 106  66  66  66  34  34  34
+ 14  14  14   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 26  26  26  70  70  70 163 133  67 213 154  11
+236 178  12 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 241 196  14
+190 146  13  18  14   6   2   2   6   2   2   6
+ 46  46  46 246 246 246 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 221 221 221  86  86  86 156 107  11
+216 158  10 236 178  12 242 186  14 246 186  14
+242 186  14 239 182  13 239 182  13 242 186  14
+242 186  14 246 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+242 186  14 225 175  15 142 122  72  66  66  66
+ 30  30  30  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 26  26  26  70  70  70 163 133  67 210 150  10
+236 178  12 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+232 195  16 121  92   8  34  34  34 106 106 106
+221 221 221 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+242 242 242  82  82  82  18  14   6 163 110   8
+216 158  10 236 178  12 242 186  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 242 186  14 163 133  67
+ 46  46  46  18  18  18   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  78  78  78 163 133  67 210 150  10
+236 178  12 246 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+241 196  14 215 174  15 190 178 144 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 218 218 218
+ 58  58  58   2   2   6  22  18   6 167 114   7
+216 158  10 236 178  12 246 186  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 186  14 242 186  14 190 150  46
+ 54  54  54  22  22  22   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 38  38  38  86  86  86 180 133  36 213 154  11
+236 178  12 246 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 232 195  16 190 146  13 214 214 214
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 250 250 250 170 170 170  26  26  26
+  2   2   6   2   2   6  37  26   9 163 110   8
+219 162  10 239 182  13 246 186  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 186  14 236 178  12 224 166  10 142 122  72
+ 46  46  46  18  18  18   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 50  50  50 109 106  95 192 133   9 224 166  10
+242 186  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+242 186  14 226 184  13 210 162  10 142 110  46
+226 226 226 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+198 198 198  66  66  66   2   2   6   2   2   6
+  2   2   6   2   2   6  50  34   6 156 107  11
+219 162  10 239 182  13 246 186  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 242 186  14
+234 174  13 213 154  11 154 122  46  66  66  66
+ 30  30  30  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  22  22  22
+ 58  58  58 154 121  60 206 145  10 234 174  13
+242 186  14 246 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 186  14 236 178  12 210 162  10 163 110   8
+ 61  42   6 138 138 138 218 218 218 250 250 250
+253 253 253 253 253 253 253 253 253 250 250 250
+242 242 242 210 210 210 144 144 144  66  66  66
+  6   6   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  61  42   6 163 110   8
+216 158  10 236 178  12 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 239 182  13 230 174  11 216 158  10
+190 142  34 124 112  88  70  70  70  38  38  38
+ 18  18  18   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  22  22  22
+ 62  62  62 168 124  44 206 145  10 224 166  10
+236 178  12 239 182  13 242 186  14 242 186  14
+246 186  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 236 178  12 216 158  10 175 118   6
+ 80  54   7   2   2   6   6   6   6  30  30  30
+ 54  54  54  62  62  62  50  50  50  38  38  38
+ 14  14  14   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  80  54   7 167 114   7
+213 154  11 236 178  12 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 242 186  14 239 182  13 239 182  13
+230 174  11 210 150  10 174 135  50 124 112  88
+ 82  82  82  54  54  54  34  34  34  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 50  50  50 158 118  36 192 133   9 200 144  11
+216 158  10 219 162  10 224 166  10 226 170  11
+230 174  11 236 178  12 239 182  13 239 182  13
+242 186  14 246 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 186  14 230 174  11 210 150  10 163 110   8
+104  69   6  10  10  10   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  91  60   6 167 114   7
+206 145  10 230 174  11 242 186  14 246 190  14
+246 190  14 246 190  14 246 186  14 242 186  14
+239 182  13 230 174  11 224 166  10 213 154  11
+180 133  36 124 112  88  86  86  86  58  58  58
+ 38  38  38  22  22  22  10  10  10   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 34  34  34  70  70  70 138 110  50 158 118  36
+167 114   7 180 123   7 192 133   9 197 138  11
+200 144  11 206 145  10 213 154  11 219 162  10
+224 166  10 230 174  11 239 182  13 242 186  14
+246 186  14 246 186  14 246 186  14 246 186  14
+239 182  13 216 158  10 185 133  11 152  99   6
+104  69   6  18  14   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  80  54   7 152  99   6
+192 133   9 219 162  10 236 178  12 239 182  13
+246 186  14 242 186  14 239 182  13 236 178  12
+224 166  10 206 145  10 192 133   9 154 121  60
+ 94  94  94  62  62  62  42  42  42  22  22  22
+ 14  14  14   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 18  18  18  34  34  34  58  58  58  78  78  78
+101  98  89 124 112  88 142 110  46 156 107  11
+163 110   8 167 114   7 175 118   6 180 123   7
+185 133  11 197 138  11 210 150  10 219 162  10
+226 170  11 236 178  12 236 178  12 234 174  13
+219 162  10 197 138  11 163 110   8 130  83   6
+ 91  60   6  10  10  10   2   2   6   2   2   6
+ 18  18  18  38  38  38  38  38  38  38  38  38
+ 38  38  38  38  38  38  38  38  38  38  38  38
+ 38  38  38  38  38  38  26  26  26   2   2   6
+  2   2   6   6   6   6  70  47   6 137  92   6
+175 118   6 200 144  11 219 162  10 230 174  11
+234 174  13 230 174  11 219 162  10 210 150  10
+192 133   9 163 110   8 124 112  88  82  82  82
+ 50  50  50  30  30  30  14  14  14   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  14  14  14  22  22  22  34  34  34
+ 42  42  42  58  58  58  74  74  74  86  86  86
+101  98  89 122 102  70 130  98  46 121  87  25
+137  92   6 152  99   6 163 110   8 180 123   7
+185 133  11 197 138  11 206 145  10 200 144  11
+180 123   7 156 107  11 130  83   6 104  69   6
+ 50  34   6  54  54  54 110 110 110 101  98  89
+ 86  86  86  82  82  82  78  78  78  78  78  78
+ 78  78  78  78  78  78  78  78  78  78  78  78
+ 78  78  78  82  82  82  86  86  86  94  94  94
+106 106 106 101 101 101  86  66  34 124  80   6
+156 107  11 180 123   7 192 133   9 200 144  11
+206 145  10 200 144  11 192 133   9 175 118   6
+139 102  15 109 106  95  70  70  70  42  42  42
+ 22  22  22  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  10  10  10
+ 14  14  14  22  22  22  30  30  30  38  38  38
+ 50  50  50  62  62  62  74  74  74  90  90  90
+101  98  89 112 100  78 121  87  25 124  80   6
+137  92   6 152  99   6 152  99   6 152  99   6
+138  86   6 124  80   6  98  70   6  86  66  30
+101  98  89  82  82  82  58  58  58  46  46  46
+ 38  38  38  34  34  34  34  34  34  34  34  34
+ 34  34  34  34  34  34  34  34  34  34  34  34
+ 34  34  34  34  34  34  38  38  38  42  42  42
+ 54  54  54  82  82  82  94  86  76  91  60   6
+134  86   6 156 107  11 167 114   7 175 118   6
+175 118   6 167 114   7 152  99   6 121  87  25
+101  98  89  62  62  62  34  34  34  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6   6   6   6  10  10  10
+ 18  18  18  22  22  22  30  30  30  42  42  42
+ 50  50  50  66  66  66  86  86  86 101  98  89
+106  86  58  98  70   6 104  69   6 104  69   6
+104  69   6  91  60   6  82  62  34  90  90  90
+ 62  62  62  38  38  38  22  22  22  14  14  14
+ 10  10  10  10  10  10  10  10  10  10  10  10
+ 10  10  10  10  10  10   6   6   6  10  10  10
+ 10  10  10  10  10  10  10  10  10  14  14  14
+ 22  22  22  42  42  42  70  70  70  89  81  66
+ 80  54   7 104  69   6 124  80   6 137  92   6
+134  86   6 116  81   8 100  82  52  86  86  86
+ 58  58  58  30  30  30  14  14  14   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  10  10  10  14  14  14
+ 18  18  18  26  26  26  38  38  38  54  54  54
+ 70  70  70  86  86  86  94  86  76  89  81  66
+ 89  81  66  86  86  86  74  74  74  50  50  50
+ 30  30  30  14  14  14   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  18  18  18  34  34  34  58  58  58
+ 82  82  82  89  81  66  89  81  66  89  81  66
+ 94  86  66  94  86  76  74  74  74  50  50  50
+ 26  26  26  14  14  14   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6   6   6   6  14  14  14  18  18  18
+ 30  30  30  38  38  38  46  46  46  54  54  54
+ 50  50  50  42  42  42  30  30  30  18  18  18
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  14  14  14  26  26  26
+ 38  38  38  50  50  50  58  58  58  58  58  58
+ 54  54  54  42  42  42  30  30  30  18  18  18
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+  6   6   6  10  10  10  14  14  14  18  18  18
+ 18  18  18  14  14  14  10  10  10   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 14  14  14  18  18  18  22  22  22  22  22  22
+ 18  18  18  14  14  14  10  10  10   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
diff --git a/drivers/video/logo/logo_linux_clut224.ppm b/drivers/video/logo/logo_linux_clut224.ppm
new file mode 100644
index 0000000..3c14e43
--- /dev/null
+++ b/drivers/video/logo/logo_linux_clut224.ppm
@@ -0,0 +1,1604 @@
+P3
+# Standard 224-color Linux logo
+80 80
+255
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6   6   6   6  10  10  10  10  10  10
+ 10  10  10   6   6   6   6   6   6   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  10  10  10  14  14  14
+ 22  22  22  26  26  26  30  30  30  34  34  34
+ 30  30  30  30  30  30  26  26  26  18  18  18
+ 14  14  14  10  10  10   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  14  14  14  26  26  26  42  42  42
+ 54  54  54  66  66  66  78  78  78  78  78  78
+ 78  78  78  74  74  74  66  66  66  54  54  54
+ 42  42  42  26  26  26  18  18  18  10  10  10
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 22  22  22  42  42  42  66  66  66  86  86  86
+ 66  66  66  38  38  38  38  38  38  22  22  22
+ 26  26  26  34  34  34  54  54  54  66  66  66
+ 86  86  86  70  70  70  46  46  46  26  26  26
+ 14  14  14   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  10  10  10  26  26  26
+ 50  50  50  82  82  82  58  58  58   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  6   6   6  54  54  54  86  86  86  66  66  66
+ 38  38  38  18  18  18   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  22  22  22  50  50  50
+ 78  78  78  34  34  34   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   6   6   6  70  70  70
+ 78  78  78  46  46  46  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  18  18  18  42  42  42  82  82  82
+ 26  26  26   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  14  14  14
+ 46  46  46  34  34  34   6   6   6   2   2   6
+ 42  42  42  78  78  78  42  42  42  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   0   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 10  10  10  30  30  30  66  66  66  58  58  58
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  26  26  26
+ 86  86  86 101 101 101  46  46  46  10  10  10
+  2   2   6  58  58  58  70  70  70  34  34  34
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 14  14  14  42  42  42  86  86  86  10  10  10
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  30  30  30
+ 94  94  94  94  94  94  58  58  58  26  26  26
+  2   2   6   6   6   6  78  78  78  54  54  54
+ 22  22  22   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 22  22  22  62  62  62  62  62  62   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  26  26  26
+ 54  54  54  38  38  38  18  18  18  10  10  10
+  2   2   6   2   2   6  34  34  34  82  82  82
+ 38  38  38  14  14  14   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 30  30  30  78  78  78  30  30  30   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  10  10  10
+ 10  10  10   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  78  78  78
+ 50  50  50  18  18  18   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 38  38  38  86  86  86  14  14  14   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  54  54  54
+ 66  66  66  26  26  26   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 42  42  42  82  82  82   2   2   6   2   2   6
+  2   2   6   6   6   6  10  10  10   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   6   6   6
+ 14  14  14  10  10  10   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  18  18  18
+ 82  82  82  34  34  34  10  10  10   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 46  46  46  86  86  86   2   2   6   2   2   6
+  6   6   6   6   6   6  22  22  22  34  34  34
+  6   6   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  18  18  18  34  34  34
+ 10  10  10  50  50  50  22  22  22   2   2   6
+  2   2   6   2   2   6   2   2   6  10  10  10
+ 86  86  86  42  42  42  14  14  14   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 46  46  46  86  86  86   2   2   6   2   2   6
+ 38  38  38 116 116 116  94  94  94  22  22  22
+ 22  22  22   2   2   6   2   2   6   2   2   6
+ 14  14  14  86  86  86 138 138 138 162 162 162
+154 154 154  38  38  38  26  26  26   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 86  86  86  46  46  46  14  14  14   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 46  46  46  86  86  86   2   2   6  14  14  14
+134 134 134 198 198 198 195 195 195 116 116 116
+ 10  10  10   2   2   6   2   2   6   6   6   6
+101  98  89 187 187 187 210 210 210 218 218 218
+214 214 214 134 134 134  14  14  14   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 86  86  86  50  50  50  18  18  18   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   1   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 46  46  46  86  86  86   2   2   6  54  54  54
+218 218 218 195 195 195 226 226 226 246 246 246
+ 58  58  58   2   2   6   2   2   6  30  30  30
+210 210 210 253 253 253 174 174 174 123 123 123
+221 221 221 234 234 234  74  74  74   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 70  70  70  58  58  58  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 46  46  46  82  82  82   2   2   6 106 106 106
+170 170 170  26  26  26  86  86  86 226 226 226
+123 123 123  10  10  10  14  14  14  46  46  46
+231 231 231 190 190 190   6   6   6  70  70  70
+ 90  90  90 238 238 238 158 158 158   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 70  70  70  58  58  58  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   1   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 42  42  42  86  86  86   6   6   6 116 116 116
+106 106 106   6   6   6  70  70  70 149 149 149
+128 128 128  18  18  18  38  38  38  54  54  54
+221 221 221 106 106 106   2   2   6  14  14  14
+ 46  46  46 190 190 190 198 198 198   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 74  74  74  62  62  62  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   1   0   0   0
+  0   0   1   0   0   0   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 42  42  42  94  94  94  14  14  14 101 101 101
+128 128 128   2   2   6  18  18  18 116 116 116
+118  98  46 121  92   8 121  92   8  98  78  10
+162 162 162 106 106 106   2   2   6   2   2   6
+  2   2   6 195 195 195 195 195 195   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 74  74  74  62  62  62  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   1   0   0   1
+  0   0   1   0   0   0   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 38  38  38  90  90  90  14  14  14  58  58  58
+210 210 210  26  26  26  54  38   6 154 114  10
+226 170  11 236 186  11 225 175  15 184 144  12
+215 174  15 175 146  61  37  26   9   2   2   6
+ 70  70  70 246 246 246 138 138 138   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 70  70  70  66  66  66  26  26  26   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 38  38  38  86  86  86  14  14  14  10  10  10
+195 195 195 188 164 115 192 133   9 225 175  15
+239 182  13 234 190  10 232 195  16 232 200  30
+245 207  45 241 208  19 232 195  16 184 144  12
+218 194 134 211 206 186  42  42  42   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 50  50  50  74  74  74  30  30  30   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 34  34  34  86  86  86  14  14  14   2   2   6
+121  87  25 192 133   9 219 162  10 239 182  13
+236 186  11 232 195  16 241 208  19 244 214  54
+246 218  60 246 218  38 246 215  20 241 208  19
+241 208  19 226 184  13 121  87  25   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 50  50  50  82  82  82  34  34  34  10  10  10
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 34  34  34  82  82  82  30  30  30  61  42   6
+180 123   7 206 145  10 230 174  11 239 182  13
+234 190  10 238 202  15 241 208  19 246 218  74
+246 218  38 246 215  20 246 215  20 246 215  20
+226 184  13 215 174  15 184 144  12   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 26  26  26  94  94  94  42  42  42  14  14  14
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  78  78  78  50  50  50 104  69   6
+192 133   9 216 158  10 236 178  12 236 186  11
+232 195  16 241 208  19 244 214  54 245 215  43
+246 215  20 246 215  20 241 208  19 198 155  10
+200 144  11 216 158  10 156 118  10   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  6   6   6  90  90  90  54  54  54  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  78  78  78  46  46  46  22  22  22
+137  92   6 210 162  10 239 182  13 238 190  10
+238 202  15 241 208  19 246 215  20 246 215  20
+241 208  19 203 166  17 185 133  11 210 150  10
+216 158  10 210 150  10 102  78  10   2   2   6
+  6   6   6  54  54  54  14  14  14   2   2   6
+  2   2   6  62  62  62  74  74  74  30  30  30
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 34  34  34  78  78  78  50  50  50   6   6   6
+ 94  70  30 139 102  15 190 146  13 226 184  13
+232 200  30 232 195  16 215 174  15 190 146  13
+168 122  10 192 133   9 210 150  10 213 154  11
+202 150  34 182 157 106 101  98  89   2   2   6
+  2   2   6  78  78  78 116 116 116  58  58  58
+  2   2   6  22  22  22  90  90  90  46  46  46
+ 18  18  18   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 38  38  38  86  86  86  50  50  50   6   6   6
+128 128 128 174 154 114 156 107  11 168 122  10
+198 155  10 184 144  12 197 138  11 200 144  11
+206 145  10 206 145  10 197 138  11 188 164 115
+195 195 195 198 198 198 174 174 174  14  14  14
+  2   2   6  22  22  22 116 116 116 116 116 116
+ 22  22  22   2   2   6  74  74  74  70  70  70
+ 30  30  30  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 50  50  50 101 101 101  26  26  26  10  10  10
+138 138 138 190 190 190 174 154 114 156 107  11
+197 138  11 200 144  11 197 138  11 192 133   9
+180 123   7 190 142  34 190 178 144 187 187 187
+202 202 202 221 221 221 214 214 214  66  66  66
+  2   2   6   2   2   6  50  50  50  62  62  62
+  6   6   6   2   2   6  10  10  10  90  90  90
+ 50  50  50  18  18  18   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  10  10  10  34  34  34
+ 74  74  74  74  74  74   2   2   6   6   6   6
+144 144 144 198 198 198 190 190 190 178 166 146
+154 121  60 156 107  11 156 107  11 168 124  44
+174 154 114 187 187 187 190 190 190 210 210 210
+246 246 246 253 253 253 253 253 253 182 182 182
+  6   6   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  62  62  62
+ 74  74  74  34  34  34  14  14  14   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  10  10  10  22  22  22  54  54  54
+ 94  94  94  18  18  18   2   2   6  46  46  46
+234 234 234 221 221 221 190 190 190 190 190 190
+190 190 190 187 187 187 187 187 187 190 190 190
+190 190 190 195 195 195 214 214 214 242 242 242
+253 253 253 253 253 253 253 253 253 253 253 253
+ 82  82  82   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  14  14  14
+ 86  86  86  54  54  54  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  18  18  18  46  46  46  90  90  90
+ 46  46  46  18  18  18   6   6   6 182 182 182
+253 253 253 246 246 246 206 206 206 190 190 190
+190 190 190 190 190 190 190 190 190 190 190 190
+206 206 206 231 231 231 250 250 250 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+202 202 202  14  14  14   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 42  42  42  86  86  86  42  42  42  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 14  14  14  38  38  38  74  74  74  66  66  66
+  2   2   6   6   6   6  90  90  90 250 250 250
+253 253 253 253 253 253 238 238 238 198 198 198
+190 190 190 190 190 190 195 195 195 221 221 221
+246 246 246 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253  82  82  82   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  78  78  78  70  70  70  34  34  34
+ 14  14  14   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 34  34  34  66  66  66  78  78  78   6   6   6
+  2   2   6  18  18  18 218 218 218 253 253 253
+253 253 253 253 253 253 253 253 253 246 246 246
+226 226 226 231 231 231 246 246 246 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 178 178 178   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  18  18  18  90  90  90  62  62  62
+ 30  30  30  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  10  10  10  26  26  26
+ 58  58  58  90  90  90  18  18  18   2   2   6
+  2   2   6 110 110 110 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+250 250 250 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 231 231 231  18  18  18   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  18  18  18  94  94  94
+ 54  54  54  26  26  26  10  10  10   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  22  22  22  50  50  50
+ 90  90  90  26  26  26   2   2   6   2   2   6
+ 14  14  14 195 195 195 250 250 250 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+250 250 250 242 242 242  54  54  54   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  38  38  38
+ 86  86  86  50  50  50  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  14  14  14  38  38  38  82  82  82
+ 34  34  34   2   2   6   2   2   6   2   2   6
+ 42  42  42 195 195 195 246 246 246 253 253 253
+253 253 253 253 253 253 253 253 253 250 250 250
+242 242 242 242 242 242 250 250 250 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 250 250 250 246 246 246 238 238 238
+226 226 226 231 231 231 101 101 101   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 38  38  38  82  82  82  42  42  42  14  14  14
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 10  10  10  26  26  26  62  62  62  66  66  66
+  2   2   6   2   2   6   2   2   6   6   6   6
+ 70  70  70 170 170 170 206 206 206 234 234 234
+246 246 246 250 250 250 250 250 250 238 238 238
+226 226 226 231 231 231 238 238 238 250 250 250
+250 250 250 250 250 250 246 246 246 231 231 231
+214 214 214 206 206 206 202 202 202 202 202 202
+198 198 198 202 202 202 182 182 182  18  18  18
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  62  62  62  66  66  66  30  30  30
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 14  14  14  42  42  42  82  82  82  18  18  18
+  2   2   6   2   2   6   2   2   6  10  10  10
+ 94  94  94 182 182 182 218 218 218 242 242 242
+250 250 250 253 253 253 253 253 253 250 250 250
+234 234 234 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 246 246 246
+238 238 238 226 226 226 210 210 210 202 202 202
+195 195 195 195 195 195 210 210 210 158 158 158
+  6   6   6  14  14  14  50  50  50  14  14  14
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  86  86  86  46  46  46
+ 18  18  18   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 22  22  22  54  54  54  70  70  70   2   2   6
+  2   2   6  10  10  10   2   2   6  22  22  22
+166 166 166 231 231 231 250 250 250 253 253 253
+253 253 253 253 253 253 253 253 253 250 250 250
+242 242 242 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 246 246 246
+231 231 231 206 206 206 198 198 198 226 226 226
+ 94  94  94   2   2   6   6   6   6  38  38  38
+ 30  30  30   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  62  62  62  66  66  66
+ 26  26  26  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  74  74  74  50  50  50   2   2   6
+ 26  26  26  26  26  26   2   2   6 106 106 106
+238 238 238 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 246 246 246 218 218 218 202 202 202
+210 210 210  14  14  14   2   2   6   2   2   6
+ 30  30  30  22  22  22   2   2   6   2   2   6
+  2   2   6   2   2   6  18  18  18  86  86  86
+ 42  42  42  14  14  14   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 42  42  42  90  90  90  22  22  22   2   2   6
+ 42  42  42   2   2   6  18  18  18 218 218 218
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 250 250 250 221 221 221
+218 218 218 101 101 101   2   2   6  14  14  14
+ 18  18  18  38  38  38  10  10  10   2   2   6
+  2   2   6   2   2   6   2   2   6  78  78  78
+ 58  58  58  22  22  22   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 54  54  54  82  82  82   2   2   6  26  26  26
+ 22  22  22   2   2   6 123 123 123 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 250 250 250
+238 238 238 198 198 198   6   6   6  38  38  38
+ 58  58  58  26  26  26  38  38  38   2   2   6
+  2   2   6   2   2   6   2   2   6  46  46  46
+ 78  78  78  30  30  30  10  10  10   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  10  10  10  30  30  30
+ 74  74  74  58  58  58   2   2   6  42  42  42
+  2   2   6  22  22  22 231 231 231 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 250 250 250
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 246 246 246  46  46  46  38  38  38
+ 42  42  42  14  14  14  38  38  38  14  14  14
+  2   2   6   2   2   6   2   2   6   6   6   6
+ 86  86  86  46  46  46  14  14  14   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  14  14  14  42  42  42
+ 90  90  90  18  18  18  18  18  18  26  26  26
+  2   2   6 116 116 116 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 250 250 250 238 238 238
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253  94  94  94   6   6   6
+  2   2   6   2   2   6  10  10  10  34  34  34
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 74  74  74  58  58  58  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  10  10  10  26  26  26  66  66  66
+ 82  82  82   2   2   6  38  38  38   6   6   6
+ 14  14  14 210 210 210 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 246 246 246 242 242 242
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 144 144 144   2   2   6
+  2   2   6   2   2   6   2   2   6  46  46  46
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 42  42  42  74  74  74  30  30  30  10  10  10
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  14  14  14  42  42  42  90  90  90
+ 26  26  26   6   6   6  42  42  42   2   2   6
+ 74  74  74 250 250 250 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 242 242 242 242 242 242
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 182 182 182   2   2   6
+  2   2   6   2   2   6   2   2   6  46  46  46
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 10  10  10  86  86  86  38  38  38  10  10  10
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 10  10  10  26  26  26  66  66  66  82  82  82
+  2   2   6  22  22  22  18  18  18   2   2   6
+149 149 149 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 234 234 234 242 242 242
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 206 206 206   2   2   6
+  2   2   6   2   2   6   2   2   6  38  38  38
+  2   2   6   2   2   6   2   2   6   2   2   6
+  6   6   6  86  86  86  46  46  46  14  14  14
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 18  18  18  46  46  46  86  86  86  18  18  18
+  2   2   6  34  34  34  10  10  10   6   6   6
+210 210 210 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 234 234 234 242 242 242
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 221 221 221   6   6   6
+  2   2   6   2   2   6   6   6   6  30  30  30
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  82  82  82  54  54  54  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 26  26  26  66  66  66  62  62  62   2   2   6
+  2   2   6  38  38  38  10  10  10  26  26  26
+238 238 238 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 231 231 231 238 238 238
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 231 231 231   6   6   6
+  2   2   6   2   2   6  10  10  10  30  30  30
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  66  66  66  58  58  58  22  22  22
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 38  38  38  78  78  78   6   6   6   2   2   6
+  2   2   6  46  46  46  14  14  14  42  42  42
+246 246 246 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 231 231 231 242 242 242
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 234 234 234  10  10  10
+  2   2   6   2   2   6  22  22  22  14  14  14
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  66  66  66  62  62  62  22  22  22
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 50  50  50  74  74  74   2   2   6   2   2   6
+ 14  14  14  70  70  70  34  34  34  62  62  62
+250 250 250 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 231 231 231 246 246 246
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 234 234 234  14  14  14
+  2   2   6   2   2   6  30  30  30   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  66  66  66  62  62  62  22  22  22
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 54  54  54  62  62  62   2   2   6   2   2   6
+  2   2   6  30  30  30  46  46  46  70  70  70
+250 250 250 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 231 231 231 246 246 246
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 226 226 226  10  10  10
+  2   2   6   6   6   6  30  30  30   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  66  66  66  58  58  58  22  22  22
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  22  22  22
+ 58  58  58  62  62  62   2   2   6   2   2   6
+  2   2   6   2   2   6  30  30  30  78  78  78
+250 250 250 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 231 231 231 246 246 246
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 206 206 206   2   2   6
+ 22  22  22  34  34  34  18  14   6  22  22  22
+ 26  26  26  18  18  18   6   6   6   2   2   6
+  2   2   6  82  82  82  54  54  54  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  26  26  26
+ 62  62  62 106 106 106  74  54  14 185 133  11
+210 162  10 121  92   8   6   6   6  62  62  62
+238 238 238 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 231 231 231 246 246 246
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 158 158 158  18  18  18
+ 14  14  14   2   2   6   2   2   6   2   2   6
+  6   6   6  18  18  18  66  66  66  38  38  38
+  6   6   6  94  94  94  50  50  50  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 10  10  10  10  10  10  18  18  18  38  38  38
+ 78  78  78 142 134 106 216 158  10 242 186  14
+246 190  14 246 190  14 156 118  10  10  10  10
+ 90  90  90 238 238 238 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 231 231 231 250 250 250
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 246 230 190
+238 204  91 238 204  91 181 142  44  37  26   9
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  38  38  38  46  46  46
+ 26  26  26 106 106 106  54  54  54  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  14  14  14  22  22  22
+ 30  30  30  38  38  38  50  50  50  70  70  70
+106 106 106 190 142  34 226 170  11 242 186  14
+246 190  14 246 190  14 246 190  14 154 114  10
+  6   6   6  74  74  74 226 226 226 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 231 231 231 250 250 250
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 228 184  62
+241 196  14 241 208  19 232 195  16  38  30  10
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  30  30  30  26  26  26
+203 166  17 154 142  90  66  66  66  26  26  26
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  18  18  18  38  38  38  58  58  58
+ 78  78  78  86  86  86 101 101 101 123 123 123
+175 146  61 210 150  10 234 174  13 246 186  14
+246 190  14 246 190  14 246 190  14 238 190  10
+102  78  10   2   2   6  46  46  46 198 198 198
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 234 234 234 242 242 242
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 224 178  62
+242 186  14 241 196  14 210 166  10  22  18   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   6   6   6 121  92   8
+238 202  15 232 195  16  82  82  82  34  34  34
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 14  14  14  38  38  38  70  70  70 154 122  46
+190 142  34 200 144  11 197 138  11 197 138  11
+213 154  11 226 170  11 242 186  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+225 175  15  46  32   6   2   2   6  22  22  22
+158 158 158 250 250 250 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 250 250 250 242 242 242 224 178  62
+239 182  13 236 186  11 213 154  11  46  32   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  61  42   6 225 175  15
+238 190  10 236 186  11 112 100  78  42  42  42
+ 14  14  14   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 22  22  22  54  54  54 154 122  46 213 154  11
+226 170  11 230 174  11 226 170  11 226 170  11
+236 178  12 242 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+241 196  14 184 144  12  10  10  10   2   2   6
+  6   6   6 116 116 116 242 242 242 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 231 231 231 198 198 198 214 170  54
+236 178  12 236 178  12 210 150  10 137  92   6
+ 18  14   6   2   2   6   2   2   6   2   2   6
+  6   6   6  70  47   6 200 144  11 236 178  12
+239 182  13 239 182  13 124 112  88  58  58  58
+ 22  22  22   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  70  70  70 180 133  36 226 170  11
+239 182  13 242 186  14 242 186  14 246 186  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 232 195  16  98  70   6   2   2   6
+  2   2   6   2   2   6  66  66  66 221 221 221
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 206 206 206 198 198 198 214 166  58
+230 174  11 230 174  11 216 158  10 192 133   9
+163 110   8 116  81   8 102  78  10 116  81   8
+167 114   7 197 138  11 226 170  11 239 182  13
+242 186  14 242 186  14 162 146  94  78  78  78
+ 34  34  34  14  14  14   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 30  30  30  78  78  78 190 142  34 226 170  11
+239 182  13 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 241 196  14 203 166  17  22  18   6
+  2   2   6   2   2   6   2   2   6  38  38  38
+218 218 218 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+250 250 250 206 206 206 198 198 198 202 162  69
+226 170  11 236 178  12 224 166  10 210 150  10
+200 144  11 197 138  11 192 133   9 197 138  11
+210 150  10 226 170  11 242 186  14 246 190  14
+246 190  14 246 186  14 225 175  15 124 112  88
+ 62  62  62  30  30  30  14  14  14   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  78  78  78 174 135  50 224 166  10
+239 182  13 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 241 196  14 139 102  15
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 78  78  78 250 250 250 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+250 250 250 214 214 214 198 198 198 190 150  46
+219 162  10 236 178  12 234 174  13 224 166  10
+216 158  10 213 154  11 213 154  11 216 158  10
+226 170  11 239 182  13 246 190  14 246 190  14
+246 190  14 246 190  14 242 186  14 206 162  42
+101 101 101  58  58  58  30  30  30  14  14  14
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  74  74  74 174 135  50 216 158  10
+236 178  12 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 241 196  14 226 184  13
+ 61  42   6   2   2   6   2   2   6   2   2   6
+ 22  22  22 238 238 238 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 226 226 226 187 187 187 180 133  36
+216 158  10 236 178  12 239 182  13 236 178  12
+230 174  11 226 170  11 226 170  11 230 174  11
+236 178  12 242 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 186  14 239 182  13
+206 162  42 106 106 106  66  66  66  34  34  34
+ 14  14  14   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 26  26  26  70  70  70 163 133  67 213 154  11
+236 178  12 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 241 196  14
+190 146  13  18  14   6   2   2   6   2   2   6
+ 46  46  46 246 246 246 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 221 221 221  86  86  86 156 107  11
+216 158  10 236 178  12 242 186  14 246 186  14
+242 186  14 239 182  13 239 182  13 242 186  14
+242 186  14 246 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+242 186  14 225 175  15 142 122  72  66  66  66
+ 30  30  30  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 26  26  26  70  70  70 163 133  67 210 150  10
+236 178  12 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+232 195  16 121  92   8  34  34  34 106 106 106
+221 221 221 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+242 242 242  82  82  82  18  14   6 163 110   8
+216 158  10 236 178  12 242 186  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 242 186  14 163 133  67
+ 46  46  46  18  18  18   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  78  78  78 163 133  67 210 150  10
+236 178  12 246 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+241 196  14 215 174  15 190 178 144 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 218 218 218
+ 58  58  58   2   2   6  22  18   6 167 114   7
+216 158  10 236 178  12 246 186  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 186  14 242 186  14 190 150  46
+ 54  54  54  22  22  22   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 38  38  38  86  86  86 180 133  36 213 154  11
+236 178  12 246 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 232 195  16 190 146  13 214 214 214
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 250 250 250 170 170 170  26  26  26
+  2   2   6   2   2   6  37  26   9 163 110   8
+219 162  10 239 182  13 246 186  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 186  14 236 178  12 224 166  10 142 122  72
+ 46  46  46  18  18  18   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 50  50  50 109 106  95 192 133   9 224 166  10
+242 186  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+242 186  14 226 184  13 210 162  10 142 110  46
+226 226 226 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+198 198 198  66  66  66   2   2   6   2   2   6
+  2   2   6   2   2   6  50  34   6 156 107  11
+219 162  10 239 182  13 246 186  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 242 186  14
+234 174  13 213 154  11 154 122  46  66  66  66
+ 30  30  30  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  22  22  22
+ 58  58  58 154 121  60 206 145  10 234 174  13
+242 186  14 246 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 186  14 236 178  12 210 162  10 163 110   8
+ 61  42   6 138 138 138 218 218 218 250 250 250
+253 253 253 253 253 253 253 253 253 250 250 250
+242 242 242 210 210 210 144 144 144  66  66  66
+  6   6   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  61  42   6 163 110   8
+216 158  10 236 178  12 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 239 182  13 230 174  11 216 158  10
+190 142  34 124 112  88  70  70  70  38  38  38
+ 18  18  18   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  22  22  22
+ 62  62  62 168 124  44 206 145  10 224 166  10
+236 178  12 239 182  13 242 186  14 242 186  14
+246 186  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 236 178  12 216 158  10 175 118   6
+ 80  54   7   2   2   6   6   6   6  30  30  30
+ 54  54  54  62  62  62  50  50  50  38  38  38
+ 14  14  14   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  80  54   7 167 114   7
+213 154  11 236 178  12 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 242 186  14 239 182  13 239 182  13
+230 174  11 210 150  10 174 135  50 124 112  88
+ 82  82  82  54  54  54  34  34  34  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 50  50  50 158 118  36 192 133   9 200 144  11
+216 158  10 219 162  10 224 166  10 226 170  11
+230 174  11 236 178  12 239 182  13 239 182  13
+242 186  14 246 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 186  14 230 174  11 210 150  10 163 110   8
+104  69   6  10  10  10   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  91  60   6 167 114   7
+206 145  10 230 174  11 242 186  14 246 190  14
+246 190  14 246 190  14 246 186  14 242 186  14
+239 182  13 230 174  11 224 166  10 213 154  11
+180 133  36 124 112  88  86  86  86  58  58  58
+ 38  38  38  22  22  22  10  10  10   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 34  34  34  70  70  70 138 110  50 158 118  36
+167 114   7 180 123   7 192 133   9 197 138  11
+200 144  11 206 145  10 213 154  11 219 162  10
+224 166  10 230 174  11 239 182  13 242 186  14
+246 186  14 246 186  14 246 186  14 246 186  14
+239 182  13 216 158  10 185 133  11 152  99   6
+104  69   6  18  14   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  80  54   7 152  99   6
+192 133   9 219 162  10 236 178  12 239 182  13
+246 186  14 242 186  14 239 182  13 236 178  12
+224 166  10 206 145  10 192 133   9 154 121  60
+ 94  94  94  62  62  62  42  42  42  22  22  22
+ 14  14  14   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 18  18  18  34  34  34  58  58  58  78  78  78
+101  98  89 124 112  88 142 110  46 156 107  11
+163 110   8 167 114   7 175 118   6 180 123   7
+185 133  11 197 138  11 210 150  10 219 162  10
+226 170  11 236 178  12 236 178  12 234 174  13
+219 162  10 197 138  11 163 110   8 130  83   6
+ 91  60   6  10  10  10   2   2   6   2   2   6
+ 18  18  18  38  38  38  38  38  38  38  38  38
+ 38  38  38  38  38  38  38  38  38  38  38  38
+ 38  38  38  38  38  38  26  26  26   2   2   6
+  2   2   6   6   6   6  70  47   6 137  92   6
+175 118   6 200 144  11 219 162  10 230 174  11
+234 174  13 230 174  11 219 162  10 210 150  10
+192 133   9 163 110   8 124 112  88  82  82  82
+ 50  50  50  30  30  30  14  14  14   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  14  14  14  22  22  22  34  34  34
+ 42  42  42  58  58  58  74  74  74  86  86  86
+101  98  89 122 102  70 130  98  46 121  87  25
+137  92   6 152  99   6 163 110   8 180 123   7
+185 133  11 197 138  11 206 145  10 200 144  11
+180 123   7 156 107  11 130  83   6 104  69   6
+ 50  34   6  54  54  54 110 110 110 101  98  89
+ 86  86  86  82  82  82  78  78  78  78  78  78
+ 78  78  78  78  78  78  78  78  78  78  78  78
+ 78  78  78  82  82  82  86  86  86  94  94  94
+106 106 106 101 101 101  86  66  34 124  80   6
+156 107  11 180 123   7 192 133   9 200 144  11
+206 145  10 200 144  11 192 133   9 175 118   6
+139 102  15 109 106  95  70  70  70  42  42  42
+ 22  22  22  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  10  10  10
+ 14  14  14  22  22  22  30  30  30  38  38  38
+ 50  50  50  62  62  62  74  74  74  90  90  90
+101  98  89 112 100  78 121  87  25 124  80   6
+137  92   6 152  99   6 152  99   6 152  99   6
+138  86   6 124  80   6  98  70   6  86  66  30
+101  98  89  82  82  82  58  58  58  46  46  46
+ 38  38  38  34  34  34  34  34  34  34  34  34
+ 34  34  34  34  34  34  34  34  34  34  34  34
+ 34  34  34  34  34  34  38  38  38  42  42  42
+ 54  54  54  82  82  82  94  86  76  91  60   6
+134  86   6 156 107  11 167 114   7 175 118   6
+175 118   6 167 114   7 152  99   6 121  87  25
+101  98  89  62  62  62  34  34  34  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6   6   6   6  10  10  10
+ 18  18  18  22  22  22  30  30  30  42  42  42
+ 50  50  50  66  66  66  86  86  86 101  98  89
+106  86  58  98  70   6 104  69   6 104  69   6
+104  69   6  91  60   6  82  62  34  90  90  90
+ 62  62  62  38  38  38  22  22  22  14  14  14
+ 10  10  10  10  10  10  10  10  10  10  10  10
+ 10  10  10  10  10  10   6   6   6  10  10  10
+ 10  10  10  10  10  10  10  10  10  14  14  14
+ 22  22  22  42  42  42  70  70  70  89  81  66
+ 80  54   7 104  69   6 124  80   6 137  92   6
+134  86   6 116  81   8 100  82  52  86  86  86
+ 58  58  58  30  30  30  14  14  14   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  10  10  10  14  14  14
+ 18  18  18  26  26  26  38  38  38  54  54  54
+ 70  70  70  86  86  86  94  86  76  89  81  66
+ 89  81  66  86  86  86  74  74  74  50  50  50
+ 30  30  30  14  14  14   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  18  18  18  34  34  34  58  58  58
+ 82  82  82  89  81  66  89  81  66  89  81  66
+ 94  86  66  94  86  76  74  74  74  50  50  50
+ 26  26  26  14  14  14   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6   6   6   6  14  14  14  18  18  18
+ 30  30  30  38  38  38  46  46  46  54  54  54
+ 50  50  50  42  42  42  30  30  30  18  18  18
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  14  14  14  26  26  26
+ 38  38  38  50  50  50  58  58  58  58  58  58
+ 54  54  54  42  42  42  30  30  30  18  18  18
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+  6   6   6  10  10  10  14  14  14  18  18  18
+ 18  18  18  14  14  14  10  10  10   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 14  14  14  18  18  18  22  22  22  22  22  22
+ 18  18  18  14  14  14  10  10  10   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
diff --git a/drivers/video/logo/logo_linux_mono.pbm b/drivers/video/logo/logo_linux_mono.pbm
new file mode 100644
index 0000000..2f14d9f
--- /dev/null
+++ b/drivers/video/logo/logo_linux_mono.pbm
@@ -0,0 +1,203 @@
+P1
+# Standard black and white Linux logo
+80 80
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 0 0 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1
+1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1
+1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1
+1 0 0 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 0 0 0 0 1 1 1 1 0 0 0 0 0 0 1 1
+1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1
+0 1 1 0 0 1 1 1 0 0 1 1 0 0 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0 1 1 1 0 1 1 1 1 0 0 1
+1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1
+1 1 1 1 0 1 1 1 0 1 1 1 1 0 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1
+1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1
+0 1 1 0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 0 0 0 1 0 0 1 0 0 0 0 0 1 1 1
+1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1
+1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1
+1 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 0 0 0 0 0 0 1 1 0 0 0 0 1 1
+1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1
+1 1 1 1 1 1 1 1 0 0 0 0 1 1 0 1 1 1 0 1 1 1 0 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 1
+1 1 1 0 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1
+0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 1 1 1 0 1 1 1 0 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0
+1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1
+0 0 0 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 0 1 1 1 1 1 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 1 1
+1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 1 1
+0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1
+1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1
+1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0
+0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1
+1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0
+0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1
+1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0
+0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1
+1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 1 0 1 1 1 1 1 1 0 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 0 0 1 1 1 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 1 0 0 0 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 1 1 1 1 1 0
+0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 1 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 1 1 0 0 0
+0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1
+1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1
+1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1
+1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0
+1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
+1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 0 0 0 0 0 0 0 0 0 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
diff --git a/drivers/video/logo/logo_linux_vga16.ppm b/drivers/video/logo/logo_linux_vga16.ppm
new file mode 100644
index 0000000..1850c15
--- /dev/null
+++ b/drivers/video/logo/logo_linux_vga16.ppm
@@ -0,0 +1,1604 @@
+P3
+# Standard 16-color Linux logo
+80 80
+255
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85  85  85  85  85  85  85  85  85  85
+ 85  85  85  85  85  85  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85  85  85  85
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+ 85  85  85  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85 170 170 170   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+170 170 170 170 170 170  85  85  85   0   0   0
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0  85  85  85 170 170 170   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0 170 170 170 170 170 170
+170 170 170   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+ 85  85  85 170 170 170 170 170 170 170 170 170
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0 170 170 170 255 255 255 255 255 255
+255 255 255 170 170 170   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0  85  85  85
+170 170 170 170 170 170 255 255 255 255 255 255
+  0   0   0   0   0   0   0   0   0   0   0   0
+170 170 170 255 255 255 170 170 170 170 170 170
+255 255 255 170 170 170   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0  85  85  85
+170 170 170   0   0   0   0   0   0 255 255 255
+ 85  85  85   0   0   0   0   0   0   0   0   0
+255 255 255 170 170 170   0   0   0  85  85  85
+170 170 170 255 255 255 170 170 170   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0  85  85  85
+ 85  85  85   0   0   0   0   0   0 170 170 170
+ 85  85  85   0   0   0   0   0   0   0   0   0
+255 255 255  85  85  85   0   0   0   0   0   0
+ 85  85  85 255 255 255 170 170 170   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0  85  85  85
+170 170 170   0   0   0   0   0   0 170 170 170
+ 85  85  85  85  85  85  85  85  85  85  85  85
+255 255 255  85  85  85   0   0   0   0   0   0
+ 85  85  85 255 255 255 170 170 170   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+255 255 255   0   0   0   0   0   0 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0   0   0   0   0   0   0
+ 85  85  85 255 255 255   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+170 170 170 170 170 170 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170 170 170 170 170 170   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85  85  85  85   0   0   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 170  85   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85  85  85  85   0   0   0
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 170  85   0
+170  85   0 170  85   0  85  85  85   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85  85  85  85   0   0   0
+ 85  85  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+170  85   0 170  85   0 170  85   0 170  85   0
+170  85   0 170  85   0  85  85  85   0   0   0
+  0   0   0  85  85  85 170 170 170  85  85  85
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85  85  85  85   0   0   0
+ 85  85  85 170  85   0 170  85   0 170  85   0
+170  85   0 170  85   0 170  85   0 170  85   0
+170  85   0 170  85   0 170  85   0 170  85   0
+170 170 170 170 170 170 170 170 170   0   0   0
+  0   0   0   0   0   0 170 170 170 170 170 170
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+ 85  85  85 170 170 170 170  85   0 170  85   0
+170  85   0 170  85   0 170  85   0 170  85   0
+170  85   0 170  85   0 170 170 170 170 170 170
+170 170 170 170 170 170 170 170 170  85  85  85
+  0   0   0   0   0   0  85  85  85  85  85  85
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+ 85  85  85 170 170 170 170 170 170 170  85   0
+170  85   0 170  85   0 170  85   0 170  85   0
+170 170 170 170 170 170 170 170 170 170 170 170
+255 255 255 255 255 255 255 255 255 170 170 170
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0  85  85  85
+255 255 255 255 255 255 170 170 170 170 170 170
+170 170 170 170 170 170 170 170 170 170 170 170
+170 170 170 170 170 170 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0 170 170 170
+255 255 255 255 255 255 170 170 170 170 170 170
+170 170 170 170 170 170 170 170 170 170 170 170
+170 170 170 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+170 170 170   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0  85  85  85 255 255 255
+255 255 255 255 255 255 255 255 255 170 170 170
+170 170 170 170 170 170 170 170 170 170 170 170
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0  85  85  85 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0  85  85  85 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0  85  85  85 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+ 85  85  85 170 170 170 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85 170 170 170 170 170 170 170 170 170
+255 255 255 255 255 255 255 255 255 170 170 170
+170 170 170 170 170 170 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+170 170 170 170 170 170 170 170 170 170 170 170
+170 170 170 170 170 170 170 170 170  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+170 170 170 170 170 170 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+170 170 170 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 170 170 170
+170 170 170 170 170 170 170 170 170  85  85  85
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+170 170 170 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170 170 170 170 170 170 170
+  0   0   0   0   0   0   0   0   0  85  85  85
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85   0   0   0
+ 85  85  85   0   0   0   0   0   0  85  85  85
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 170 170 170
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0 170 170 170
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+170 170 170  85  85  85   0   0   0   0   0   0
+  0   0   0  85  85  85  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0  85  85  85
+  0   0   0   0   0   0  85  85  85 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170   0   0   0  85  85  85
+ 85  85  85   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0  85  85  85
+  0   0   0  85  85  85 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170   0   0   0  85  85  85
+ 85  85  85   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0  85  85  85
+  0   0   0 170 170 170 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0  85  85  85   0   0   0
+  0   0   0 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0  85  85  85   0   0   0
+ 85  85  85 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0  85  85  85   0   0   0   0   0   0
+170 170 170 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0  85  85  85
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0  85  85  85
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85  85  85  85
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255   0   0   0
+ 85  85  85  85  85  85  85  85  85  85  85  85
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0 170  85   0
+255 255  85 170  85   0   0   0   0   0   0   0
+ 85  85  85 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85  85  85  85   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0   0   0   0
+  0   0   0  85  85  85 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255  85 170  85   0 255 255  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85  85  85  85
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+  0   0   0   0   0   0  85  85  85 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255  85
+170  85   0 255 255  85 170  85   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+170  85   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0   0   0   0   0   0   0  85  85  85
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 170  85   0
+255 255  85 170  85   0 255 255  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0 170  85   0
+255 255  85 170  85   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85   0   0   0   0   0   0   0   0   0
+ 85  85  85 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255  85
+170  85   0 255 255  85 170  85   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0 255 255  85
+170  85   0 255 255  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85   0   0   0   0   0   0
+  0   0   0  85  85  85 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0 255 255  85 170  85   0
+255 255  85 170  85   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85   0   0   0
+  0   0   0   0   0   0  85  85  85 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170 170 170 170 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170 170 170 170 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170 170 170 170 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0   0   0   0   0   0   0   0   0   0
+  0   0   0 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170 170 170 170 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85   0   0   0   0   0   0   0   0   0
+ 85  85  85 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170  85  85  85 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85  85  85  85  85  85  85
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+170 170 170  85  85  85  85  85  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 170 170 170
+ 85  85  85   0   0   0   0   0   0 170  85   0
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170  85  85  85
+  0   0   0   0   0   0   0   0   0 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+170 170 170 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+170 170 170  85  85  85  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0 170  85   0
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 170  85   0
+170  85   0 170 170 170 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170  85  85  85
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+170  85   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85 170  85   0
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 170  85   0 170  85   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 170  85   0
+170  85   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+170  85   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+170  85   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85 170  85   0
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 170  85   0 170  85   0 170  85   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0 170  85   0 170  85   0
+170  85   0 170  85   0 170  85   0 170  85   0
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 170  85   0
+170  85   0   0   0   0   0   0   0   0   0   0
+ 85  85  85  85  85  85  85  85  85  85  85  85
+ 85  85  85  85  85  85  85  85  85  85  85  85
+ 85  85  85  85  85  85  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0 170  85   0
+170  85   0 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+170  85   0 170  85   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0 170  85   0 170  85   0
+170  85   0 170  85   0 170  85   0 170  85   0
+170  85   0 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 170  85   0 170  85   0
+ 85  85  85  85  85  85  85  85  85  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+ 85  85  85  85  85  85  85  85  85 170  85   0
+170  85   0 170  85   0 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 170  85   0
+170  85   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0 170  85   0
+170  85   0 170  85   0 170  85   0 170  85   0
+170  85   0 170  85   0 170  85   0 170  85   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0 170  85   0
+170  85   0 170  85   0 170  85   0 170  85   0
+170  85   0 170  85   0 170  85   0 170  85   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0 170  85   0 170  85   0 170  85   0
+170  85   0 170  85   0 170  85   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+170  85   0 170  85   0 170  85   0 170  85   0
+170  85   0 170  85   0 170  85   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
diff --git a/drivers/video/logo/logo_mac_clut224.ppm b/drivers/video/logo/logo_mac_clut224.ppm
new file mode 100644
index 0000000..4dad34b
--- /dev/null
+++ b/drivers/video/logo/logo_mac_clut224.ppm
@@ -0,0 +1,1604 @@
+P3
+# 224-color Macintosh Linux logo
+80 80
+255
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6   6   6   6  10  10  10  10  10  10
+ 10  10  10   6   6   6   6   6   6   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  10  10  10  14  14  14
+ 22  22  22  26  26  26  30  30  30  34  34  34
+ 30  30  30  30  30  30  26  26  26  18  18  18
+ 14  14  14  10  10  10   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  14  14  14  26  26  26  42  42  42
+ 54  54  54  66  66  66  78  78  78  78  78  78
+ 78  78  78  74  74  74  66  66  66  54  54  54
+ 42  42  42  26  26  26  18  18  18  10  10  10
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 22  22  22  42  42  42  66  66  66  86  86  86
+ 66  66  66  38  38  38  38  38  38  22  22  22
+ 26  26  26  34  34  34  54  54  54  66  66  66
+ 86  86  86  70  70  70  46  46  46  26  26  26
+ 14  14  14   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  10  10  10  26  26  26
+ 50  50  50  82  82  82  58  58  58   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  6   6   6  54  54  54  86  86  86  66  66  66
+ 38  38  38  18  18  18   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  22  22  22  50  50  50
+ 78  78  78  34  34  34   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   6   6   6  70  70  70
+ 78  78  78  46  46  46  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0 250 250 250
+250 250 250 250 250 250 250 250 250 242 242 242
+250 250 250 250 250 250 246 246 246 250 250 250
+246 246 246 242 242 242 246 246 246 231 231 231
+ 46  46  46   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  14  14  14
+ 46  46  46  34  34  34   6   6   6   2   2   6
+ 82  82  82 242 242 242 242 242 242 246 246 246
+242 242 242 250 250 250 242 242 242 246 246 246
+242 242 242 250 250 250 242 242 242 250 250 250
+250 250 250 250 250 250 250 250 250 250 250 250
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   0   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0 242 242 242
+250 250 250 250 250 250 250 250 250 250 250 250
+242 242 242 246 246 246 250 250 250 250 250 250
+250 250 250 250 250 250 242 242 242 116 116 116
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  26  26  26
+ 86  86  86 101 101 101  46  46  46  10  10  10
+  2   2   6 123 123 123 242 242 242 250 250 250
+246 246 246 250 250 250 242 242 242 250 250 250
+246 246 246 250 250 250 242 242 242 250 250 250
+242 242 242 250 250 250 250 250 250 250 250 250
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0 123 123 123
+234 234 234 231 231 231 234 234 234 234 234 234
+234 234 234 221 221 221 234 234 234 231 231 231
+234 234 234 234 234 234 214 214 214  10  10  10
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  30  30  30
+ 94  94  94  94  94  94  58  58  58  26  26  26
+  2   2   6  10  10  10 190 190 190 242 242 242
+242 242 242 250 250 250 250 250 250 242 242 242
+246 246 246 250 250 250 250 250 250 242 242 242
+250 250 250 242 242 242 242 242 242 231 231 231
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  90  90  90
+234 234 234 226 226 226 226 226 226 218 218 218
+226 226 226 214 214 214 231 231 231 221 221 221
+231 231 231 221 221 221 116 116 116   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  26  26  26
+ 54  54  54  38  38  38  18  18  18  10  10  10
+  2   2   6   2   2   6  58  58  58 242 242 242
+242 242 242 242 242 242 242 242 242 242 242 242
+242 242 242 242 242 242 242 242 242 242 242 242
+242 242 242 242 242 242 250 250 250 226 226 226
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  82  82  82
+234 234 234 231 231 231 242 242 242 242 242 242
+234 234 234 234 234 234 238 238 238 234 234 234
+238 238 238 238 238 238  50  50  50   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  10  10  10
+ 10  10  10   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6 182 182 182
+242 242 242 250 250 250 250 250 250 250 250 250
+242 242 242 250 250 250 250 250 250 250 250 250
+242 242 242 242 242 242 250 250 250 206 206 206
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  50  50  50
+250 250 250 226 226 226 234 234 234  10  10  10
+ 78  78  78  66  66  66 101  98  89  90  90  90
+110 110 110 106 106 106  10  10  10   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6 101  98  89
+210 210 210 238 238 238 226 226 226 238 238 238
+210 210 210 242 242 242 226 226 226 242 242 242
+242 242 242 234 234 234 250 250 250 198 198 198
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  82  82  82
+234 234 234 234 234 234 231 231 231   2   2   6
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 42  42  42  82  82  82   2   2   6   2   2   6
+  2   2   6   6   6   6  10  10  10   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   6   6   6
+ 14  14  14  10  10  10   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  18  18  18
+ 82  82  82  34  34  34  10  10  10   0   0   0
+  6   6   6   0   0   0   0   0   0   0   0   0
+144 144 144 250 250 250 242 242 242 202 202 202
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  82  82  82
+226 226 226 231 231 231 234 234 234  90  90  90
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 46  46  46  86  86  86   2   2   6   2   2   6
+  6   6   6   6   6   6  22  22  22  34  34  34
+  6   6   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  18  18  18  34  34  34
+ 10  10  10  50  50  50  22  22  22   2   2   6
+  2   2   6   2   2   6   2   2   6  10  10  10
+ 86  86  86  42  42  42  14  14  14   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+158 158 158 242 242 242 234 234 234 187 187 187
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  66  66  66
+231 231 231 226 226 226 226 226 226 178 178 178
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 46  46  46  86  86  86   2   2   6   2   2   6
+ 38  38  38 116 116 116  94  94  94  22  22  22
+ 22  22  22   2   2   6   2   2   6   2   2   6
+ 14  14  14  86  86  86 138 138 138 162 162 162
+154 154 154  38  38  38  26  26  26   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 86  86  86  46  46  46  14  14  14   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+187 187 187 234 234 234 250 250 250 190 190 190
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  82  82  82
+226 226 226 218 218 218 234 234 234 218 218 218
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 46  46  46  86  86  86   2   2   6  14  14  14
+134 134 134 198 198 198 195 195 195 116 116 116
+ 10  10  10   2   2   6   2   2   6   6   6   6
+101  98  89 187 187 187 210 210 210 218 218 218
+214 214 214 134 134 134  14  14  14   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 86  86  86  50  50  50  18  18  18   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+214 214 214 226 226 226 242 242 242 187 187 187
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   1   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  74  74  74
+226 226 226 214 214 214 226 226 226 190 190 190
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 46  46  46  86  86  86   2   2   6  54  54  54
+218 218 218 195 195 195 226 226 226 246 246 246
+ 58  58  58   2   2   6   2   2   6  30  30  30
+210 210 210 253 253 253 174 174 174 123 123 123
+221 221 221 234 234 234  74  74  74   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 70  70  70  58  58  58  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+195 195 195 226 226 226 234 234 234 206 206 206
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  62  62  62
+226 226 226 218 218 218 234 234 234 226 226 226
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 46  46  46  82  82  82   2   2   6 106 106 106
+170 170 170  26  26  26  86  86  86 226 226 226
+123 123 123  10  10  10  14  14  14  46  46  46
+231 231 231 190 190 190   6   6   6  70  70  70
+ 90  90  90 238 238 238 158 158 158   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 70  70  70  58  58  58  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+182 182 182 234 234 234 242 242 242 158 158 158
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   1   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0 101  98  89
+214 214 214 214 214 214 226 226 226 242 242 242
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 42  42  42  86  86  86   6   6   6 116 116 116
+106 106 106   6   6   6  70  70  70 149 149 149
+128 128 128  18  18  18  38  38  38  54  54  54
+221 221 221 106 106 106   2   2   6  14  14  14
+ 46  46  46 190 190 190 198 198 198   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 74  74  74  62  62  62  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+190 190 190 226 226 226 226 226 226 178 178 178
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   1   0   0   0
+  0   0   1   0   0   0   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  66  66  66
+210 210 210 214 214 214 210 210 210 250 250 250
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 42  42  42  94  94  94  14  14  14 101 101 101
+128 128 128   2   2   6  18  18  18 116 116 116
+118  98  46 121  92   8 121  92   8  98  78  10
+162 162 162 106 106 106   2   2   6   2   2   6
+  2   2   6 195 195 195 195 195 195   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 74  74  74  62  62  62  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+214 214 214 226 226 226 231 231 231 149 149 149
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   1   0   0   1
+  0   0   1   0   0   0   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  42  42  42
+226 226 226 218 218 218 210 210 210 231 231 231
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 38  38  38  90  90  90  14  14  14  58  58  58
+210 210 210  26  26  26  54  38   6 154 114  10
+226 170  11 236 186  11 225 175  15 184 144  12
+215 174  15 175 146  61  37  26   9   2   2   6
+ 70  70  70 246 246 246 138 138 138   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 70  70  70  66  66  66  26  26  26   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+178 178 178 218 218 218 226 226 226 162 162 162
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  42  42  42
+214 214 214 198 198 198 210 210 210 242 242 242
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 38  38  38  86  86  86  14  14  14  10  10  10
+195 195 195 188 164 115 192 133   9 225 175  15
+239 182  13 234 190  10 232 195  16 232 200  30
+245 207  45 241 208  19 232 195  16 184 144  12
+218 194 134 211 206 186  42  42  42   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 50  50  50  74  74  74  30  30  30   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+187 187 187 231 231 231 226 226 226 182 182 182
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  66  66  66
+218 218 218 210 210 210 210 210 210 242 242 242
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 34  34  34  86  86  86  14  14  14   2   2   6
+121  87  25 192 133   9 219 162  10 239 182  13
+236 186  11 232 195  16 241 208  19 244 214  54
+246 218  60 246 218  38 246 215  20 241 208  19
+241 208  19 226 184  13 121  87  25   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 50  50  50  82  82  82  34  34  34  10  10  10
+  0   0   0   0   0   0   0   0   0   0   0   0
+162 162 162 226 226 226 226 226 226 162 162 162
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  62  62  62
+206 206 206 206 206 206 202 202 202 250 250 250
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 34  34  34  82  82  82  30  30  30  61  42   6
+180 123   7 206 145  10 230 174  11 239 182  13
+234 190  10 238 202  15 241 208  19 246 218  74
+246 218  38 246 215  20 246 215  20 246 215  20
+226 184  13 215 174  15 184 144  12   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 26  26  26  94  94  94  42  42  42  14  14  14
+  0   0   0   0   0   0   0   0   0   0   0   0
+166 166 166 226 226 226 214 214 214 170 170 170
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  66  66  66
+226 226 226 218 218 218 202 202 202 242 242 242
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  78  78  78  50  50  50 104  69   6
+192 133   9 216 158  10 236 178  12 236 186  11
+232 195  16 241 208  19 244 214  54 245 215  43
+246 215  20 246 215  20 241 208  19 198 155  10
+200 144  11 216 158  10 156 118  10   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  6   6   6  90  90  90  54  54  54  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+178 178 178 226 226 226 226 226 226 158 158 158
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  62  62  62
+214 214 214 198 198 198 202 202 202 242 242 242
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  78  78  78  46  46  46  22  22  22
+137  92   6 210 162  10 239 182  13 238 190  10
+238 202  15 241 208  19 246 215  20 246 215  20
+241 208  19 203 166  17 185 133  11 210 150  10
+216 158  10 210 150  10 102  78  10   2   2   6
+  6   6   6  54  54  54  14  14  14   2   2   6
+  2   2   6  62  62  62  74  74  74  30  30  30
+ 10  10  10   0   0   0   0   0   0   0   0   0
+190 190 190 214 214 214 242 242 242 158 158 158
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  66  66  66
+210 210 210 202 202 202 202 202 202 242 242 242
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 34  34  34  78  78  78  50  50  50   6   6   6
+ 94  70  30 139 102  15 190 146  13 226 184  13
+232 200  30 232 195  16 215 174  15 190 146  13
+168 122  10 192 133   9 210 150  10 213 154  11
+202 150  34 182 157 106 101  98  89   2   2   6
+  2   2   6  78  78  78 116 116 116  58  58  58
+  2   2   6  22  22  22  90  90  90  46  46  46
+ 18  18  18   6   6   6   0   0   0   0   0   0
+195 195 195 214 214 214 226 226 226 162 162 162
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  82  82  82
+198 198 198 190 190 190 187 187 187 242 242 242
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 38  38  38  86  86  86  50  50  50   6   6   6
+128 128 128 174 154 114 156 107  11 168 122  10
+198 155  10 184 144  12 197 138  11 200 144  11
+206 145  10 206 145  10 197 138  11 188 164 115
+195 195 195 198 198 198 174 174 174  14  14  14
+  2   2   6  22  22  22 116 116 116 116 116 116
+ 22  22  22   2   2   6  74  74  74  70  70  70
+ 30  30  30  10  10  10   0   0   0   0   0   0
+178 178 178 226 226 226 226 226 226 141 141 141
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  62  62  62
+195 195 195 195 195 195 195 195 195 250 250 250
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 50  50  50 101 101 101  26  26  26  10  10  10
+138 138 138 190 190 190 174 154 114 156 107  11
+197 138  11 200 144  11 197 138  11 192 133   9
+180 123   7 190 142  34 190 178 144 187 187 187
+202 202 202 221 221 221 214 214 214  66  66  66
+  2   2   6   2   2   6  50  50  50  62  62  62
+  6   6   6   2   2   6  10  10  10  90  90  90
+ 50  50  50  18  18  18   6   6   6   0   0   0
+190 190 190 226 226 226 250 250 250 202 202 202
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  42  42  42
+187 187 187 190 190 190 187 187 187 250 250 250
+  0   0   0   0   0   0  10  10  10  34  34  34
+ 74  74  74  74  74  74   2   2   6   6   6   6
+144 144 144 198 198 198 190 190 190 178 166 146
+154 121  60 156 107  11 156 107  11 168 124  44
+174 154 114 187 187 187 190 190 190 210 210 210
+246 246 246 253 253 253 253 253 253 182 182 182
+  6   6   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  62  62  62
+ 74  74  74  34  34  34  14  14  14   0   0   0
+174 174 174 206 206 206 242 242 242 158 158 158
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  42  42  42
+190 190 190 187 187 187 190 190 190 234 234 234
+  0   0   0  10  10  10  22  22  22  54  54  54
+ 94  94  94  18  18  18   2   2   6  46  46  46
+234 234 234 221 221 221 190 190 190 190 190 190
+190 190 190 187 187 187 187 187 187 190 190 190
+190 190 190 195 195 195 214 214 214 242 242 242
+253 253 253 253 253 253 253 253 253 253 253 253
+ 82  82  82   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  14  14  14
+ 86  86  86  54  54  54  22  22  22   6   6   6
+195 195 195 202 202 202 234 234 234 138 138 138
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  50  50  50
+182 182 182 187 187 187 178 178 178 242 242 242
+  6   6   6  18  18  18  46  46  46  90  90  90
+ 46  46  46  18  18  18   6   6   6 182 182 182
+253 253 253 246 246 246 206 206 206 190 190 190
+190 190 190 190 190 190 190 190 190 190 190 190
+206 206 206 231 231 231 250 250 250 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+202 202 202  14  14  14   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 42  42  42  86  86  86  42  42  42  18  18  18
+190 190 190 202 202 202 226 226 226 178 178 178
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  62  62  62
+195 195 195 182 182 182 187 187 187 250 250 250
+ 14  14  14  38  38  38  74  74  74  66  66  66
+  2   2   6   6   6   6  90  90  90 250 250 250
+253 253 253 253 253 253 238 238 238 198 198 198
+190 190 190 190 190 190 195 195 195 221 221 221
+246 246 246 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253  82  82  82   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  78  78  78  70  70  70  34  34  34
+202 202 202 182 182 182 242 242 242 158 158 158
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  26  26  26
+195 195 195 182 182 182 178 178 178 242 242 242
+ 34  34  34  66  66  66  78  78  78   6   6   6
+  2   2   6  18  18  18 218 218 218 253 253 253
+253 253 253 253 253 253 253 253 253 246 246 246
+226 226 226 231 231 231 246 246 246 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 178 178 178   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  18  18  18  90  90  90  62  62  62
+218 218 218 198 198 198 250 250 250 141 141 141
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  42  42  42
+182 182 182 178 178 178 174 174 174 250 250 250
+ 58  58  58  90  90  90  18  18  18   2   2   6
+  2   2   6 110 110 110 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+250 250 250 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 231 231 231  18  18  18   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  18  18  18  94  94  94
+206 206 206 198 198 198 242 242 242 162 162 162
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  42  42  42
+166 166 166 170 170 170 187 187 187 242 242 242
+ 90  90  90  26  26  26   2   2   6   2   2   6
+ 14  14  14 195 195 195 250 250 250 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+250 250 250 242 242 242  54  54  54   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  38  38  38
+187 187 187 214 214 214 231 231 231 134 134 134
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  50  50  50
+187 187 187 182 182 182 166 166 166 234 234 234
+ 34  34  34   2   2   6   2   2   6   2   2   6
+ 42  42  42 195 195 195 246 246 246 253 253 253
+253 253 253 253 253 253 253 253 253 250 250 250
+242 242 242 242 242 242 250 250 250 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 250 250 250 246 246 246 238 238 238
+226 226 226 231 231 231 101 101 101   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+206 206 206 174 174 174 250 250 250 128 128 128
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  34  34  34
+178 178 178 144 144 144 170 170 170 226 226 226
+  2   2   6   2   2   6   2   2   6   6   6   6
+ 70  70  70 170 170 170 206 206 206 234 234 234
+246 246 246 250 250 250 250 250 250 238 238 238
+226 226 226 231 231 231 238 238 238 250 250 250
+250 250 250 250 250 250 246 246 246 231 231 231
+214 214 214 206 206 206 202 202 202 202 202 202
+198 198 198 202 202 202 182 182 182  18  18  18
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+202 202 202 166 166 166 214 214 214 128 128 128
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  50  50  50
+178 178 178 158 158 158 134 134 134 242 242 242
+  2   2   6   2   2   6   2   2   6  10  10  10
+ 94  94  94 182 182 182 218 218 218 242 242 242
+250 250 250 253 253 253 253 253 253 250 250 250
+234 234 234 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 246 246 246
+238 238 238 226 226 226 210 210 210 202 202 202
+195 195 195 195 195 195 210 210 210 158 158 158
+  6   6   6  14  14  14  50  50  50  14  14  14
+  2   2   6   2   2   6   2   2   6   2   2   6
+198 198 198 187 187 187 246 246 246 116 116 116
+ 18  18  18   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  50  50  50
+195 195 195 154 154 154 154 154 154 250 250 250
+250 250 250 250 250 250 242 242 242 242 242 242
+242 242 242 250 250 250 250 250 250 250 250 250
+250 250 250 250 250 250 242 242 242 250 250 250
+250 250 250 250 250 250 242 242 242 250 250 250
+250 250 250 250 250 250 250 250 250 246 246 246
+234 234 234 250 250 250 242 242 242 242 242 242
+242 242 242 250 250 250 242 242 242 242 242 242
+242 242 242 250 250 250 242 242 242 242 242 242
+250 250 250 242 242 242 242 242 242 250 250 250
+182 182 182 190 190 190 206 206 206 141 141 141
+ 26  26  26  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  50  50  50
+170 170 170 166 166 166 128 128 128 250 250 250
+242 242 242 250 250 250 250 250 250 242 242 242
+250 250 250 242 242 242 242 242 242 250 250 250
+242 242 242 250 250 250 250 250 250 250 250 250
+250 250 250 250 250 250 242 242 242 250 250 250
+242 242 242 250 250 250 242 242 242 250 250 250
+250 250 250 242 242 242 250 250 250 250 250 250
+242 242 242 250 250 250 250 250 250 250 250 250
+242 242 242 242 242 242 250 250 250 234 234 234
+250 250 250 242 242 242 242 242 242 250 250 250
+195 195 195 195 195 195 206 206 206 128 128 128
+ 42  42  42  14  14  14   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  50  50  50
+178 178 178 174 174 174 158 158 158 170 170 170
+162 162 162 170 170 170 170 170 170 162 162 162
+166 166 166 170 170 170 154 154 154 154 154 154
+178 178 178 162 162 162 166 166 166 166 166 166
+166 166 166 158 158 158 178 178 178 162 162 162
+170 170 170 174 174 174 178 178 178 178 178 178
+170 170 170 178 178 178 170 170 170 166 166 166
+170 170 170 182 182 182 187 187 187 178 178 178
+195 195 195 195 195 195 195 195 195 195 195 195
+187 187 187 195 195 195 178 178 178 195 195 195
+206 206 206 195 195 195 210 210 210 116 116 116
+ 58  58  58  22  22  22   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  50  50  50
+162 162 162 162 162 162 170 170 170 158 158 158
+162 162 162 158 158 158 162 162 162 166 166 166
+158 158 158 174 174 174 162 162 162 158 158 158
+170 170 170 166 166 166 166 166 166 174 174 174
+166 166 166 174 174 174 174 174 174 174 174 174
+174 174 174 182 182 182 166 166 166 187 187 187
+182 182 182 187 187 187 174 174 174 166 166 166
+166 166 166 187 187 187 182 182 182 158 158 158
+174 174 174 174 174 174 174 174 174 182 182 182
+182 182 182 182 182 182 178 178 178 195 195 195
+178 178 178 182 182 182 174 174 174  30  30  30
+ 78  78  78  30  30  30  10  10  10   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  10  10  10  34  34  34
+154 154 154 158 158 158 154 154 154 158 158 158
+154 154 154 166 166 166 162 162 162 178 178 178
+178 178 178 166 166 166 170 170 170 158 158 158
+170 170 170 178 178 178 178 178 178 187 187 187
+195 195 195 178 178 178 178 178 178 178 178 178
+162 162 162 187 187 187 166 166 166 178 178 178
+174 174 174 178 178 178 170 170 170 170 170 170
+174 174 174 170 170 170 187 187 187 178 178 178
+178 178 178 202 202 202 170 170 170 187 187 187
+178 178 178 182 182 182 174 174 174 190 190 190
+182 182 182 166 166 166 149 149 149   6   6   6
+ 86  86  86  46  46  46  14  14  14   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  14  14  14  50  50  50
+166 166 166 162 162 162 149 149 149 162 162 162
+158 158 158 170 170 170 158 158 158 158 158 158
+166 166 166 170 170 170 149 149 149 170 170 170
+158 158 158 174 174 174 166 166 166 166 166 166
+166 166 166 166 166 166 182 182 182 158 158 158
+158 158 158 174 174 174 170 170 170 158 158 158
+178 178 178 166 166 166 158 158 158 174 174 174
+170 170 170 166 166 166 174 174 174 166 166 166
+174 174 174 182 182 182 174 174 174 182 182 182
+174 174 174 178 178 178 187 187 187 206 206 206
+187 187 187 178 178 178 128 128 128   2   2   6
+ 74  74  74  58  58  58  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  10  10  10  26  26  26  42  42  42
+158 158 158 144 144 144 149 149 149 162 162 162
+149 149 149 170 170 170 170 170 170 170 170 170
+174 174 174 170 170 170 158 158 158 162 162 162
+170 170 170 162 162 162 170 170 170 170 170 170
+162 162 162 162 162 162 170 170 170 170 170 170
+170 170 170 166 166 166 154 154 154 166 166 166
+154 154 154 162 162 162 170 170 170 149 149 149
+170 170 170 144 144 144 187 187 187 170 170 170
+170 170 170 195 195 195 187 187 187 202 202 202
+198 198 198 182 182 182 202 202 202 210 210 210
+187 187 187 178 178 178 106 106 106   2   2   6
+ 42  42  42  74  74  74  30  30  30  10  10  10
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  14  14  14  42  42  42  42  42  42
+158 158 158 141 141 141 162 162 162 149 149 149
+154 154 154 158 158 158 166 166 166 174 174 174
+162 162 162 158 158 158 162 162 162 158 158 158
+158 158 158 158 158 158 166 166 166 166 166 166
+158 158 158 158 158 158 158 158 158 166 166 166
+166 166 166 170 170 170 182 182 182 187 187 187
+166 166 166 174 174 174 166 166 166 154 154 154
+174 174 174 174 174 174 166 166 166 190 190 190
+ 34  34  34   2   2   6  18  18  18   2   2   6
+ 34  34  34   2   2   6  18  18  18  78  78  78
+182 182 182 178 178 178  78  78  78   2   2   6
+ 10  10  10  86  86  86  38  38  38  10  10  10
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 10  10  10  26  26  26  66  66  66  30  30  30
+138 138 138 144 144 144 154 154 154 149 149 149
+154 154 154 154 154 154 154 154 154 166 166 166
+162 162 162 158 158 158 162 162 162 154 154 154
+170 170 170 154 154 154 178 178 178 162 162 162
+162 162 162 170 170 170 162 162 162 154 154 154
+  2   2   6   2   2   6  34  34  34  42  42  42
+ 42  42  42  34  34  34  22  18   6  34  34  34
+ 42  42  42  42  42  42  66  66  66  34  34  34
+128 128 128  10  10  10  10  10  10  18  18  18
+ 18  18  18  10  10  10  26  26  26 174 174 174
+187 187 187 138 138 138  34  34  34   2   2   6
+  6   6   6  86  86  86  46  46  46  14  14  14
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 18  18  18  46  46  46  86  86  86   6   6   6
+110 110 110 162 162 162 149 149 149 144 144 144
+149 149 149 166 166 166 149 149 149 162 162 162
+149 149 149 162 162 162 149 149 149 158 158 158
+166 166 166 158 158 158 158 158 158 166 166 166
+166 166 166 149 149 149 158 158 158 166 166 166
+128 128 128  18  18  18   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  22  18   6  26  26  26
+ 18  18  18   6   6   6  18  18  18 166 166 166
+174 174 174 110 110 110  18  18  18   2   2   6
+  2   2   6  82  82  82  54  54  54  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 26  26  26  66  66  66  62  62  62   2   2   6
+ 46  46  46 141 141 141 166 166 166 144 144 144
+154 154 154 170 170 170 158 158 158 162 162 162
+149 149 149 162 162 162 154 154 154 154 154 154
+162 162 162 144 144 144 162 162 162 154 154 154
+170 170 170 144 144 144 154 154 154 170 170 170
+116 116 116 144 144 144 110 110 110 116 116 116
+110 110 110 144 144 144 116 116 116 128 128 128
+134 134 134 116 116 116 134 134 134 149 149 149
+158 158 158 231 231 231 234 234 234 214 214 214
+202 202 202 195 195 195 166 166 166 144 144 144
+144 144 144  34  34  34   2   2   6   2   2   6
+  2   2   6  66  66  66  58  58  58  22  22  22
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 38  38  38  78  78  78   6   6   6   2   2   6
+ 14  14  14 123 123 123 138 138 138  90  90  90
+110 110 110 128 128 128 154 154 154 149 149 149
+144 144 144 149 149 149 158 158 158 149 149 149
+166 166 166 158 158 158 158 158 158 166 166 166
+158 158 158 158 158 158 158 158 158 158 158 158
+144 144 144 170 170 170 162 162 162 170 170 170
+187 187 187 174 174 174 170 170 170 170 170 170
+162 162 162 170 170 170 170 170 170 178 178 178
+187 187 187 190 190 190 170 170 170 149 149 149
+149 149 149 138 138 138 170 170 170 116 116 116
+ 18  18  18   2   2   6   2   2   6   2   2   6
+  2   2   6  66  66  66  62  62  62  22  22  22
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 50  50  50  74  74  74   2   2   6   2   2   6
+ 14  14  14  94  94  94 134 134 134  74  74  74
+ 50  50  50 158 158 158 154 154 154 166 166 166
+162 162 162 170 170 170 162 162 162 178 178 178
+170 170 170 154 154 154 162 162 162 154 154 154
+154 154 154 154 154 154 170 170 170 141 141 141
+149 149 149 166 166 166 166 166 166 166 166 166
+178 178 178 174 174 174 158 158 158 174 174 174
+174 174 174 174 174 174 174 174 174 158 158 158
+166 166 166 166 166 166 170 170 170 170 170 170
+170 170 170 162 162 162  82  82  82  10  10  10
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  66  66  66  62  62  62  22  22  22
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 54  54  54  62  62  62   2   2   6   2   2   6
+  2   2   6  34  34  34 123 123 123  18  18  18
+ 22  18   6 128 128 128 149 149 149 154 154 154
+158 158 158 158 158 158 149 149 149 166 166 166
+166 166 166 158 158 158 158 158 158 182 182 182
+158 158 158 149 149 149 149 149 149 178 178 178
+162 162 162 170 170 170 170 170 170 170 170 170
+174 174 174 178 178 178 170 170 170 178 178 178
+170 170 170 178 178 178 178 178 178 162 162 162
+174 174 174 170 170 170 166 166 166 166 166 166
+141 141 141  50  50  50  30  30  30   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  66  66  66  58  58  58  22  22  22
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  22  22  22
+ 58  58  58  62  62  62   2   2   6   2   2   6
+  2   2   6   2   2   6  38  38  38 144 144 144
+178 178 178 162 162 162 134 134 134 154 154 154
+154 154 154 154 154 154 154 154 154 170 170 170
+154 154 154 154 154 154 162 162 162 170 170 170
+162 162 162 154 154 154 158 158 158 174 174 174
+149 149 149 166 166 166 174 174 174 178 178 178
+174 174 174 174 174 174 166 166 166 174 174 174
+166 166 166 166 166 166 166 166 166 166 166 166
+170 170 170 170 170 170 166 166 166 138 138 138
+ 42  42  42  34  34  34  18  14   6  22  22  22
+ 26  26  26  18  18  18   6   6   6   2   2   6
+  2   2   6  82  82  82  54  54  54  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  26  26  26
+ 62  62  62 106 106 106  74  54  14 185 133  11
+210 162  10 121  92   8   6   6   6  78  78  78
+154 154 154 149 149 149 141 141 141 149 149 149
+149 149 149 149 149 149 158 158 158 141 141 141
+149 149 149 141 141 141 158 158 158 149 149 149
+149 149 149 149 149 149 162 162 162 170 170 170
+154 154 154 170 170 170 162 162 162 166 166 166
+170 170 170 170 170 170 170 170 170 162 162 162
+162 162 162 170 170 170 170 170 170 170 170 170
+170 170 170 162 162 162 162 162 162  38  38  38
+ 14  14  14   2   2   6   2   2   6   2   2   6
+  6   6   6  18  18  18  66  66  66  38  38  38
+  6   6   6  94  94  94  50  50  50  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 10  10  10  10  10  10  18  18  18  38  38  38
+ 78  78  78 142 134 106 216 158  10 242 186  14
+246 190  14 246 190  14 156 118  10  10  10  10
+116 116 116 182 182 182 138 138 138 154 154 154
+154 154 154 138 138 138 162 162 162 170 170 170
+178 178 178 138 138 138 162 162 162 162 162 162
+162 162 162 158 158 158 149 149 149 174 174 174
+134 134 134 174 174 174 170 170 170 158 158 158
+158 158 158 174 174 174 141 141 141 174 174 174
+149 149 149 166 166 166 158 158 158 174 174 174
+141 141 141 178 178 178 175 146  61  37  26   9
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  38  38  38  46  46  46
+ 26  26  26 106 106 106  54  54  54  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  14  14  14  22  22  22
+ 30  30  30  38  38  38  50  50  50  70  70  70
+106 106 106 190 142  34 226 170  11 242 186  14
+246 190  14 246 190  14 246 190  14 154 114  10
+  6   6   6  74  74  74 226 226 226 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 231 231 231 250 250 250
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 228 184  62
+241 196  14 241 208  19 232 195  16  38  30  10
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  30  30  30  26  26  26
+203 166  17 154 142  90  66  66  66  26  26  26
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  18  18  18  38  38  38  58  58  58
+ 78  78  78  86  86  86 101 101 101 123 123 123
+175 146  61 210 150  10 234 174  13 246 186  14
+246 190  14 246 190  14 246 190  14 238 190  10
+102  78  10   2   2   6  46  46  46 198 198 198
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 234 234 234 242 242 242
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 224 178  62
+242 186  14 241 196  14 210 166  10  22  18   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   6   6   6 121  92   8
+238 202  15 232 195  16  82  82  82  34  34  34
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 14  14  14  38  38  38  70  70  70 154 122  46
+190 142  34 200 144  11 197 138  11 197 138  11
+213 154  11 226 170  11 242 186  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+225 175  15  46  32   6   2   2   6  22  22  22
+158 158 158 250 250 250 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 250 250 250 242 242 242 224 178  62
+239 182  13 236 186  11 213 154  11  46  32   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  61  42   6 225 175  15
+238 190  10 236 186  11 112 100  78  42  42  42
+ 14  14  14   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 22  22  22  54  54  54 154 122  46 213 154  11
+226 170  11 230 174  11 226 170  11 226 170  11
+236 178  12 242 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+241 196  14 184 144  12  10  10  10   2   2   6
+  6   6   6 116 116 116 242 242 242 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 231 231 231 198 198 198 214 170  54
+236 178  12 236 178  12 210 150  10 137  92   6
+ 18  14   6   2   2   6   2   2   6   2   2   6
+  6   6   6  70  47   6 200 144  11 236 178  12
+239 182  13 239 182  13 124 112  88  58  58  58
+ 22  22  22   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  70  70  70 180 133  36 226 170  11
+239 182  13 242 186  14 242 186  14 246 186  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 232 195  16  98  70   6   2   2   6
+  2   2   6   2   2   6  66  66  66 221 221 221
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 206 206 206 198 198 198 214 166  58
+230 174  11 230 174  11 216 158  10 192 133   9
+163 110   8 116  81   8 102  78  10 116  81   8
+167 114   7 197 138  11 226 170  11 239 182  13
+242 186  14 242 186  14 162 146  94  78  78  78
+ 34  34  34  14  14  14   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 30  30  30  78  78  78 190 142  34 226 170  11
+239 182  13 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 241 196  14 203 166  17  22  18   6
+  2   2   6   2   2   6   2   2   6  38  38  38
+218 218 218 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+250 250 250 206 206 206 198 198 198 202 162  69
+226 170  11 236 178  12 224 166  10 210 150  10
+200 144  11 197 138  11 192 133   9 197 138  11
+210 150  10 226 170  11 242 186  14 246 190  14
+246 190  14 246 186  14 225 175  15 124 112  88
+ 62  62  62  30  30  30  14  14  14   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  78  78  78 174 135  50 224 166  10
+239 182  13 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 241 196  14 139 102  15
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 78  78  78 250 250 250 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+250 250 250 214 214 214 198 198 198 190 150  46
+219 162  10 236 178  12 234 174  13 224 166  10
+216 158  10 213 154  11 213 154  11 216 158  10
+226 170  11 239 182  13 246 190  14 246 190  14
+246 190  14 246 190  14 242 186  14 206 162  42
+101 101 101  58  58  58  30  30  30  14  14  14
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  74  74  74 174 135  50 216 158  10
+236 178  12 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 241 196  14 226 184  13
+ 61  42   6   2   2   6   2   2   6   2   2   6
+ 22  22  22 238 238 238 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 226 226 226 187 187 187 180 133  36
+216 158  10 236 178  12 239 182  13 236 178  12
+230 174  11 226 170  11 226 170  11 230 174  11
+236 178  12 242 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 186  14 239 182  13
+206 162  42 106 106 106  66  66  66  34  34  34
+ 14  14  14   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 26  26  26  70  70  70 163 133  67 213 154  11
+236 178  12 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 241 196  14
+190 146  13  18  14   6   2   2   6   2   2   6
+ 46  46  46 246 246 246 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 221 221 221  86  86  86 156 107  11
+216 158  10 236 178  12 242 186  14 246 186  14
+242 186  14 239 182  13 239 182  13 242 186  14
+242 186  14 246 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+242 186  14 225 175  15 142 122  72  66  66  66
+ 30  30  30  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 26  26  26  70  70  70 163 133  67 210 150  10
+236 178  12 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+232 195  16 121  92   8  34  34  34 106 106 106
+221 221 221 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+242 242 242  82  82  82  18  14   6 163 110   8
+216 158  10 236 178  12 242 186  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 242 186  14 163 133  67
+ 46  46  46  18  18  18   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  78  78  78 163 133  67 210 150  10
+236 178  12 246 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+241 196  14 215 174  15 190 178 144 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 218 218 218
+ 58  58  58   2   2   6  22  18   6 167 114   7
+216 158  10 236 178  12 246 186  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 186  14 242 186  14 190 150  46
+ 54  54  54  22  22  22   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 38  38  38  86  86  86 180 133  36 213 154  11
+236 178  12 246 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 232 195  16 190 146  13 214 214 214
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 250 250 250 170 170 170  26  26  26
+  2   2   6   2   2   6  37  26   9 163 110   8
+219 162  10 239 182  13 246 186  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 186  14 236 178  12 224 166  10 142 122  72
+ 46  46  46  18  18  18   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 50  50  50 109 106  95 192 133   9 224 166  10
+242 186  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+242 186  14 226 184  13 210 162  10 142 110  46
+226 226 226 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+198 198 198  66  66  66   2   2   6   2   2   6
+  2   2   6   2   2   6  50  34   6 156 107  11
+219 162  10 239 182  13 246 186  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 242 186  14
+234 174  13 213 154  11 154 122  46  66  66  66
+ 30  30  30  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  22  22  22
+ 58  58  58 154 121  60 206 145  10 234 174  13
+242 186  14 246 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 186  14 236 178  12 210 162  10 163 110   8
+ 61  42   6 138 138 138 218 218 218 250 250 250
+253 253 253 253 253 253 253 253 253 250 250 250
+242 242 242 210 210 210 144 144 144  66  66  66
+  6   6   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  61  42   6 163 110   8
+216 158  10 236 178  12 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 239 182  13 230 174  11 216 158  10
+190 142  34 124 112  88  70  70  70  38  38  38
+ 18  18  18   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  22  22  22
+ 62  62  62 168 124  44 206 145  10 224 166  10
+236 178  12 239 182  13 242 186  14 242 186  14
+246 186  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 236 178  12 216 158  10 175 118   6
+ 80  54   7   2   2   6   6   6   6  30  30  30
+ 54  54  54  62  62  62  50  50  50  38  38  38
+ 14  14  14   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  80  54   7 167 114   7
+213 154  11 236 178  12 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 242 186  14 239 182  13 239 182  13
+230 174  11 210 150  10 174 135  50 124 112  88
+ 82  82  82  54  54  54  34  34  34  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 50  50  50 158 118  36 192 133   9 200 144  11
+216 158  10 219 162  10 224 166  10 226 170  11
+230 174  11 236 178  12 239 182  13 239 182  13
+242 186  14 246 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 186  14 230 174  11 210 150  10 163 110   8
+104  69   6  10  10  10   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  91  60   6 167 114   7
+206 145  10 230 174  11 242 186  14 246 190  14
+246 190  14 246 190  14 246 186  14 242 186  14
+239 182  13 230 174  11 224 166  10 213 154  11
+180 133  36 124 112  88  86  86  86  58  58  58
+ 38  38  38  22  22  22  10  10  10   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 34  34  34  70  70  70 138 110  50 158 118  36
+167 114   7 180 123   7 192 133   9 197 138  11
+200 144  11 206 145  10 213 154  11 219 162  10
+224 166  10 230 174  11 239 182  13 242 186  14
+246 186  14 246 186  14 246 186  14 246 186  14
+239 182  13 216 158  10 185 133  11 152  99   6
+104  69   6  18  14   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  80  54   7 152  99   6
+192 133   9 219 162  10 236 178  12 239 182  13
+246 186  14 242 186  14 239 182  13 236 178  12
+224 166  10 206 145  10 192 133   9 154 121  60
+ 94  94  94  62  62  62  42  42  42  22  22  22
+ 14  14  14   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 18  18  18  34  34  34  58  58  58  78  78  78
+101  98  89 124 112  88 142 110  46 156 107  11
+163 110   8 167 114   7 175 118   6 180 123   7
+185 133  11 197 138  11 210 150  10 219 162  10
+226 170  11 236 178  12 236 178  12 234 174  13
+219 162  10 197 138  11 163 110   8 130  83   6
+ 91  60   6  10  10  10   2   2   6   2   2   6
+ 18  18  18  38  38  38  38  38  38  38  38  38
+ 38  38  38  38  38  38  38  38  38  38  38  38
+ 38  38  38  38  38  38  26  26  26   2   2   6
+  2   2   6   6   6   6  70  47   6 137  92   6
+175 118   6 200 144  11 219 162  10 230 174  11
+234 174  13 230 174  11 219 162  10 210 150  10
+192 133   9 163 110   8 124 112  88  82  82  82
+ 50  50  50  30  30  30  14  14  14   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  14  14  14  22  22  22  34  34  34
+ 42  42  42  58  58  58  74  74  74  86  86  86
+101  98  89 122 102  70 130  98  46 121  87  25
+137  92   6 152  99   6 163 110   8 180 123   7
+185 133  11 197 138  11 206 145  10 200 144  11
+180 123   7 156 107  11 130  83   6 104  69   6
+ 50  34   6  54  54  54 110 110 110 101  98  89
+ 86  86  86  82  82  82  78  78  78  78  78  78
+ 78  78  78  78  78  78  78  78  78  78  78  78
+ 78  78  78  82  82  82  86  86  86  94  94  94
+106 106 106 101 101 101  86  66  34 124  80   6
+156 107  11 180 123   7 192 133   9 200 144  11
+206 145  10 200 144  11 192 133   9 175 118   6
+139 102  15 109 106  95  70  70  70  42  42  42
+ 22  22  22  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  10  10  10
+ 14  14  14  22  22  22  30  30  30  38  38  38
+ 50  50  50  62  62  62  74  74  74  90  90  90
+101  98  89 112 100  78 121  87  25 124  80   6
+137  92   6 152  99   6 152  99   6 152  99   6
+138  86   6 124  80   6  98  70   6  86  66  30
+101  98  89  82  82  82  58  58  58  46  46  46
+ 38  38  38  34  34  34  34  34  34  34  34  34
+ 34  34  34  34  34  34  34  34  34  34  34  34
+ 34  34  34  34  34  34  38  38  38  42  42  42
+ 54  54  54  82  82  82  94  86  76  91  60   6
+134  86   6 156 107  11 167 114   7 175 118   6
+175 118   6 167 114   7 152  99   6 121  87  25
+101  98  89  62  62  62  34  34  34  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6   6   6   6  10  10  10
+ 18  18  18  22  22  22  30  30  30  42  42  42
+ 50  50  50  66  66  66  86  86  86 101  98  89
+106  86  58  98  70   6 104  69   6 104  69   6
+104  69   6  91  60   6  82  62  34  90  90  90
+ 62  62  62  38  38  38  22  22  22  14  14  14
+ 10  10  10  10  10  10  10  10  10  10  10  10
+ 10  10  10  10  10  10   6   6   6  10  10  10
+ 10  10  10  10  10  10  10  10  10  14  14  14
+ 22  22  22  42  42  42  70  70  70  89  81  66
+ 80  54   7 104  69   6 124  80   6 137  92   6
+134  86   6 116  81   8 100  82  52  86  86  86
+ 58  58  58  30  30  30  14  14  14   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  10  10  10  14  14  14
+ 18  18  18  26  26  26  38  38  38  54  54  54
+ 70  70  70  86  86  86  94  86  76  89  81  66
+ 89  81  66  86  86  86  74  74  74  50  50  50
+ 30  30  30  14  14  14   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  18  18  18  34  34  34  58  58  58
+ 82  82  82  89  81  66  89  81  66  89  81  66
+ 94  86  66  94  86  76  74  74  74  50  50  50
+ 26  26  26  14  14  14   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6   6   6   6  14  14  14  18  18  18
+ 30  30  30  38  38  38  46  46  46  54  54  54
+ 50  50  50  42  42  42  30  30  30  18  18  18
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  14  14  14  26  26  26
+ 38  38  38  50  50  50  58  58  58  58  58  58
+ 54  54  54  42  42  42  30  30  30  18  18  18
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+  6   6   6  10  10  10  14  14  14  18  18  18
+ 18  18  18  14  14  14  10  10  10   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 14  14  14  18  18  18  22  22  22  22  22  22
+ 18  18  18  14  14  14  10  10  10   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
diff --git a/drivers/video/logo/logo_parisc_clut224.ppm b/drivers/video/logo/logo_parisc_clut224.ppm
new file mode 100644
index 0000000..9bf89ef
--- /dev/null
+++ b/drivers/video/logo/logo_parisc_clut224.ppm
@@ -0,0 +1,1604 @@
+P3
+# 224-color PA-RISC Linux logo
+80 80
+255
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   6   6   7   6   6   7
+   6   6   7   6   6   7   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   6   6   7  22  22  23
+  46  46  47  58  58  59  70  70  71  82  82  82
+  82  82  82  66  66  67  54  54  55  38  38  39
+  22  22  23   6   6   7   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   6   6   7  29  30  31  70  70  71 119 122 130
+ 166 166 167 191 191 190 198 198 200 206 206 206
+ 206 206 206 194 194 195 182 182 182 158 158 158
+ 119 119 118  70  70  71  29  30  31  10  10  11
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  14  14  15
+  54  54  55 126 126 127 191 191 190 226 226 226
+ 202 202 202 130 130 132 126 126 127 100 100 102
+ 100 100 102 119 122 130 163 162 161 202 202 202
+ 226 226 226 191 191 190 134 134 134  74  74  74
+  26  26  28   6   6   7   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2  18  18  18  74  74  74
+ 158 158 158 222 222 223 182 182 182  63  62  63
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+  63  62  63 166 166 167 230 230 231 191 191 190
+ 119 119 118  46  46  47  10  10  11   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2  10  10  11  66  66  67 166 166 167
+ 222 222 223 112 112 112   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2  46  46  47 194 194 195
+ 214 214 215 140 140 141  54  54  55  10  10  11
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2  38  38  39 140 140 141 226 226 226
+  90  90  90   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  10  10  11
+  33  34  35  22  22  23   2   2   2   6   6   7
+ 140 140 141 222 222 223 140 140 141  42  42  43
+   6   6   7   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+  14  14  15  86  86  86 202 202 202 146 146 146
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  26  26  28
+ 100 100 102 112 112 112  42  42  43   2   2   2
+   2   2   2 163 162 161 210 210 210 105 107 112
+  22  22  23   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+  33  34  35 146 146 146 226 226 226  33  34  35
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  29  30  31
+ 119 119 118 130 130 132  70  70  71  26  26  28
+   2   2   2  10  10  11 206 206 206 178 177 177
+  63  62  63   6   6   7   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   6   6   7
+  70  70  71 191 191 190 163 162 161   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  29  30  31
+  78  78  79  63  62  63  29  30  31  18  18  18
+   2   2   2   2   2   2  86  86  86 222 222 223
+ 119 119 118  22  22  23   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  14  14  15
+ 100 100 102 218 218 219  70  70  71   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  10  10  11
+  14  14  15   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   6   6   7 198 198 200
+ 171 170 167  54  54  55   6   6   7   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  22  22  23
+ 126 126 127 230 230 231  22  22  23   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2 112 112 112
+ 206 206 206  86  86  86  10  10  11   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  29  30  31
+ 146 146 146 210 210 210   6   6   7   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  38  38  39
+ 226 226 226 119 119 118  18  18  18   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  33  34  35
+ 150 150 151 202 202 202   2   2   2   2   2   2
+   2   2   2   2   2   2  22  22  23  26  26  28
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   6   6   7  54  54  55   6   6   7   2   2   2
+   2   2   2   2   2   2   2   2   2  18  18  18
+ 226 226 226 140 140 141  26  26  28   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  33  34  35
+ 150 150 151 202 202 202   2   2   2   2   2   2
+  10  10  11  78  78  79  54  54  55  14  14  15
+  18  18  18   2   2   2   2   2   2   2   2   2
+   2   2   2  54  54  55 130 130 132 171 170 167
+ 130 130 132  14  14  15  29  30  31   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+ 198 198 200 155 153 152  33  34  35   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  33  34  35
+ 150 150 151 202 202 202   2   2   2   2   2   2
+ 134 134 134 222 222 223 214 214 215  90  90  90
+   2   2   2   2   2   2   2   2   2   2   2   2
+  70  70  71 182 182 182 218 218 219 237 238 239
+ 241 242 244 140 140 141   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+ 202 202 202 166 166 167  42  42  43   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  33  34  35
+ 150 150 151 202 202 202   2   2   2  38  38  39
+ 234 234 235 254 254 254 254 254 254 254 254 254
+  29  30  31   2   2   2   2   2   2   2   2  10
+ 218 218 219 254 254 254 254 254 254 210 210 210
+ 254 254 254 249 250 251  54  54  55   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+ 140 140 141 178 177 177  54  54  55   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  33  34  35
+ 150 150 151 202 202 202   2   2   2 105 107 112
+ 237 238 239  29  30  31 105 107 112 254 254 254
+ 119 122 130   2   2   2   2   2   2  29  30  31
+ 254 254 254 249 250 251   6   6   7  58  58  59
+ 112 112 112 254 254 254 166 166 167   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+ 140 140 141 182 182 182  54  54  55   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  29  30  31
+ 146 146 146 198 198 200   2   2   2 126 126 127
+ 126 126 127   2   2   2  78  78  79 178 182 190
+ 150 150 151   2   2  10  26  26  28  42  42  43
+ 254 254 254 119 122 130   2   2   2   2   2  10
+  54  54  55 226 226 226 230 230 231   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+ 140 140 141 182 182 182  54  54  55   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  26  26  28
+ 134 134 134 234 234 235  22  22  23 119 119 118
+ 130 130 132   2   2   2   6  10  24 122 126 140
+  86  86  86  42  30   2  45  26   2  23  14   2
+ 184 186 195 100 100 102   2   2   2   2   2   2
+   2   2   2 210 210 210 234 234 235   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+ 140 140 141 187 187 186  58  58  59   6   6   7
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  18  18  18
+ 119 119 118 230 230 231  22  22  23  70  70  71
+ 222 222 223   2   2   2   2   2   2 138  98  18
+ 236 174   8 254 198   2 246 190  13 202 152   2
+ 214 170  26 162 138  86   2   2   2   2   2   2
+  12  14  26 254 254 254 183 186 190   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+ 146 146 146 194 194 195  70  70  71   6   6   7
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  18  18  18
+ 112 112 112 226 226 226  22  22  23   6   6   7
+ 249 250 251 167 155 134 186 124   4 234 170   6
+ 254 198   2 253 202   2 253 207   3 238 198  14
+ 254 212  22 254 216  14 218 173   2 118  90   6
+ 210 210 210 254 254 254  63  62  63   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+  82  82  82 206 206 206  82  82  82  10  10  11
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  18  18  18
+ 112 112 112 226 226 226  22  22  23   2   2   2
+ 122 106  82 207 143  12 234 170   6 254 194   2
+ 254 198   2 253 207   3 252 218   6 254 234  42
+ 254 234  66 254 234  42 254 233   7 254 226   4
+ 253 207   3 228 176  28  70  46   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+  82  82  82 214 214 215  94  94  95  10  10  11
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  18  18  18
+ 112 112 112 226 226 226  38  38  39  23  14   2
+ 186 124   4 221 154   6 248 183   3 254 198   2
+ 253 202   2 250 214   3 254 222   7 254 230  70
+ 254 234  66 254 233   7 254 233   7 254 236  14
+ 254 226   4 254 212  22 214 162   3   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+  54  54  55 226 226 226 119 119 118  22  22  23
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  10  10  11
+  94  94  95 214 214 215  86  86  86 100  63   4
+ 206 137   3 238 167   5 254 190  11 254 198   2
+ 253 207   3 252 218   6 254 226  46 254 232  58
+ 254 233   7 254 233   7 254 233   7 226 190   2
+ 202 152   2 231 166   7 175 127   3   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+  10  10  11 222 222 223 163 162 161  46  46  47
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  10  10  11
+  82  82  82 210 210 210  86  86  86  42  30   2
+ 174 119   4 248 183   3 254 194   2 253 202   2
+ 253 207   3 254 222   7 254 226  46 254 226   4
+ 254 222   7 238 202   2 190 145   2 207 143  12
+ 226 160   6 238 167   5 138  98  18   2   2   2
+   2   2   2  22  22  23   2   2   2   2   2   2
+   2   2   2 130 130 132 202 202 202  82  82  82
+  10  10  11   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  10  10  11
+  82  82  82 210 210 210  86  86  86   2   2   2
+  89  59   3 156 110   2 241 183   7 253 207   3
+ 253 224  28 254 222   7 250 214   3 218 173   2
+ 175 127   3 166 110  10 211 145   3 226 160   6
+ 221 154   6 204 154  50  63  62  63   2   2   2
+   2   2   2  94  94  95 100 100 102  33  34  35
+   2   2   2  50  50  51 230 230 231 140 140 141
+  33  34  35   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  14  14  15
+  94  94  95 214 214 215  86  86  86   2   2   2
+ 119 122 130 162 138  86 142  90   5 174 119   4
+ 190 145   2 175 127   3 170 112   4 186 124   4
+ 202 130   2 206 137   3 202 130   2 187 145  53
+ 194 186 174 204 208 219 178 177 177   2   2   2
+   2   2   2  18  18  18 140 140 141 130 130 132
+  14  14  15   2   2   2 178 177 177 198 198 200
+  86  86  86  14  14  15   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  33  34  35
+ 134 134 134 230 230 231  54  54  55   2   2   2
+ 146 146 146 202 202 202 164 124  56 156 101   3
+ 213 150   7 211 145   3 206 137   3 198 126   2
+ 180 114   4 182 118   3 182 158 114 188 190 198
+ 204 208 219 230 230 231 214 214 215  33  34  35
+   2   2   2   2   2   2  78  78  79  94  94  95
+   6   6   7   2   2   2  29  30  31 226 226 226
+ 150 150 151  42  42  43   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2  14  14  15  82  82  82
+ 194 194 195 187 187 186   6   6   7   2   2   2
+ 140 140 141 204 208 219 194 194 195 163 143 109
+ 148  89   3 148  89   3 148  89   3 148  89   3
+ 164 124  56 184 176 158 184 186 195 204 208 219
+ 254 254 254 254 254 254 254 254 254 158 158 158
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2 140 140 141
+ 206 206 206 100 100 102  18  18  18   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   6   6   7  54  54  55 158 158 158
+ 226 226 226  50  50  51   2   2   2   2   2   2
+ 234 234 235 230 234 235 198 198 200 190 194 210
+ 184 186 195 174 162 150 174 162 150 178 177 177
+ 183 186 190 188 190 198 204 208 219 245 246 248
+ 254 254 254 254 254 254 254 254 254 254 254 254
+  38  38  39   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  29  30  31
+ 218 218 219 171 170 167  58  58  59   6   6   7
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   6   6   7  38  38  39 134 134 134 222 222 223
+ 120 112 108   2   2   2   2   2   2 150 150 151
+ 254 254 254 254 254 254 210 210 210 188 190 198
+ 188 190 198 184 186 195 183 186 190 183 186 190
+ 194 194 195 222 222 223 249 250 251 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 194 194 195   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+ 100 100 102 222 222 223 119 122 130  29  30  31
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+  26  26  28 112 112 112 206 206 206 171 170 167
+   6   6   7   2   2   2  46  46  47 254 254 254
+ 254 254 254 254 254 254 241 242 244 188 190 198
+ 187 187 186 183 186 190 183 186 190 206 206 206
+ 241 242 244 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254  46  46  47   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   6   6   7 194 194 195 194 194 195  90  90  90
+  18  18  18   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  18  18  18
+  86  86  86 191 191 190 206 206 206  26  26  28
+   2   2   2   2   2   2 206 206 206 254 254 254
+ 254 254 254 254 254 254 254 254 254 245 246 248
+ 218 218 219 218 218 219 234 234 235 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 171 170 167   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2  46  46  47 226 226 226 178 177 177
+  74  74  74  14  14  15   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2  14  14  15  70  70  71
+ 171 170 167 226 226 226  46  46  47   2   2   2
+   2   2   2  74  74  74 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 249 250 251   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2  63  62  63 234 234 235
+ 163 162 161  66  66  67  14  14  15   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   6   6   7  54  54  55 155 153 152
+ 230 230 231  82  82  82   2   2   2   2   2   2
+   2   2   2 194 194 195 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254  26  26  28   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2 112 112 112
+ 230 230 231 155 153 152  58  58  59   6   6   7
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2  29  30  31 126 126 127 222 222 223
+ 112 112 112   2   2   2   2   2   2   2   2   2
+  14  14  15 218 218 219 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 249 250 251 249 250 251 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 250 254 254 254  90  90  90   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+ 112 112 112 222 222 223 134 134 134  38  38  39
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+  10  10  11  74  74  74 191 191 190 182 182 182
+   6   6   7   2   2   2   2   2   2   2   2   2
+  46  46  47 182 182 182 234 234 235 254 254 254
+ 254 254 254 254 254 254 254 254 254 234 234 235
+ 222 222 223 222 222 223 237 238 239 249 250 251
+ 249 250 251 249 250 251 249 250 251 230 230 231
+ 222 222 223 218 218 219 214 214 215 210 210 210
+ 210 210 210 222 222 223 163 162 161   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   6   6   7 163 162 161 202 202 202  90  90  90
+  14  14  15   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+  29  30  31 134 134 134 230 230 231  50  50  51
+   2   2   2   2   2   2   2   2   2   2   2   2
+  78  78  79 178 177 177 214 214 215 241 242 244
+ 254 254 254 254 254 254 254 254 254 254 254 250
+ 226 226 226 245 246 248 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 250 241 242 244
+ 222 222 223 206 206 206 198 198 200 194 194 195
+ 194 194 195 198 198 200 234 234 235 119 119 118
+   2   2   2   2   2   2  29  30  31   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2  26  26  28 222 222 223 150 150 151
+  38  38  39   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   6   6   7
+  58  58  59 178 177 177 171 170 167   2   2   2
+   2   2   2   2   2   2   2   2   2   6   6   7
+ 150 150 151 234 234 235 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 250
+ 237 238 239 254 254 254 254 254 250 254 254 250
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 237 238 239
+ 222 222 223 206 206 206 210 210 210 249 250 251
+  46  46  47   2   2   2   2   2   2  38  38  39
+  10  10  11   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2 150 150 151 198 198 200
+  82  82  82  10  10  11   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  10  10  11
+  86  86  86 210 210 210 112 112 112   2   2   2
+   2   2   2  18  18  18   2   2   2 112 112 112
+ 241 242 244 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 250 254 254 250 254 254 250 254 254 250
+ 254 254 250 254 254 250 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 234 234 235 226 226 226
+ 214 214 215   2   2   2   2   2   2   2   2   2
+  42  42  43  10  10  11   2   2   2   2   2   2
+   2   2   2   2   2   2  46  46  47 230 230 231
+ 134 134 134  29  30  31   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  26  26  28
+ 126 126 127 230 230 231  50  50  51   2   2   2
+  33  34  35   2   2   2  14  14  15 194 194 195
+ 254 254 254 254 254 254 245 246 248 254 254 254
+ 254 254 254 230 234 235 206 206 206 206 206 206
+ 206 206 206 206 206 206 154 206 206 154 206 206
+ 154 206 206 154 206 206 154 206 206 154 206 206
+ 154 206 206 102 154 154 102 154 154 166 174 186
+ 226 226 226 254 254 254 245 246 248 245 246 248
+ 245 246 248  70  70  71   2   2   2   2   2   2
+   2   2   2  38  38  39   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2 178 177 177
+ 178 177 177  58  58  59   6   6   7   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  50  50  51
+ 166 166 167 210 210 210   6   6   7   6   6   7
+  14  14  15   2   2   2 134 134 134 237 238 239
+ 249 250 251 254 254 254 254 254 254 254 254 254
+ 254 254 254 102 154 154   2 102 102   2 102 154
+   2 102 102   2 102 102   2 102 102   2 102 102
+   2 102 102   2 102 102   2 102 102   2 102 102
+   2 102 102   2 102 102   2 102 102  50 154 154
+ 234 234 235 254 254 254 254 254 254 254 254 254
+ 249 250 251 198 198 200   2   2   2  18  18  18
+  50  50  51  22  22  23  29  30  31   2   2   2
+   2   2   2   2   2   2   2   2   2 105 107 112
+ 214 214 215 100 100 102  14  14  15   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2  10  10  11  86  86  86
+ 206 206 206 126 126 127   2   2   2  38  38  39
+   2   2   2   6   6   7 230 230 231 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 102 154 154   2 102 102   2 102 102
+   2 154 154  50 154 154 102 206 206 154 206 206
+ 206 206 206 230 234 235 206 206 206 154 206 206
+ 102 154 154   2 102 154   2 102 102  50 154 154
+ 245 246 248 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254  14  14  15  29  30  31
+  50  50  51  10  10  11  42  42  43   2   2   2
+   2   2   2   2   2   2   2   2   2  10  10  11
+ 226 226 226 150 150 151  33  34  35   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2  29  30  31 134 134 134
+ 230 230 231  46  46  47   2   2   2  22  22  23
+   2   2   2  78  78  79 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254  50 154 154  50 154 154 154 206 206
+ 230 234 235 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 154 206 206   2 102 154   2 154 154
+ 241 242 244 254 254 254 249 250 251 254 254 254
+ 254 254 254 254 254 254  74  74  74   2   2   2
+   2   2   2   2   2   2  10  10  11  38  38  39
+   2   2   2   2   2   2   2   2   2   2   2   2
+ 166 166 167 191 191 190  66  66  67   6   6   7
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   6   6   7  66  66  67 182 182 182
+ 182 182 182   2   2   2  29  30  31   2   2   2
+   2   2   2 202 202 202 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 230 234 235
+ 102 154 154 154 206 206 230 234 235 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254  50 154 154   2 102 102
+ 206 206 206 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 140 140 141   2   2   2
+   2   2   2   2   2   2   2   2   2  46  46  47
+   2   2   2   2   2   2   2   2   2   2   2   2
+  90  90  90 214 214 215 100 100 102  14  14  15
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2  26  26  28 119 122 130 222 222 223
+  78  78  79   2   2   2  33  34  35   2   2   2
+  33  34  35 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 230 234 235 102 154 154
+ 206 206 206 254 254 254 254 254 254 254 254 254
+ 230 234 235 154 206 206 102 154 154  50 154 154
+  50 154 154  50 154 154  50 154 154 154 206 206
+ 230 234 235 254 254 254  50 154 154   2 102 102
+ 154 206 206 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 191 191 190   2   2   2
+   2   2   2   2   2   2   2   2   2  50  50  51
+   2   2   2   2   2   2   2   2   2   2   2   2
+  26  26  28 230 230 231 126 126 127  22  22  23
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+  10  10  11  74  74  74 187 187 186 194 194 195
+   6   6   7   2   2   2  10  10  11   2   2   2
+ 130 130 132 254 254 254 254 254 254 254 254 254
+ 254 254 254 230 234 235 154 206 206 230 234 235
+ 254 254 254 254 254 254 154 206 206  50 154 154
+   2 102 154   2 102 154  50 154 154  50 154 154
+  50 154 154  50 154 154   2 102 102   2 102 102
+  50 154 154 206 206 206  50 154 154   2 102 102
+ 102 206 206 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 226 226 226   2   2   2
+   2   2   2   2   2   2   2   2   2  42  42  43
+   2   2   2   2   2   2   2   2   2   2   2   2
+   6   6   7 214 214 215 150 150 151  33  34  35
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+  38  38  39 140 140 141 230 230 231  63  62  63
+   2   2   2  22  22  23   2   2   2   2   2   2
+ 210 210 210 254 254 254 254 254 254 254 254 254
+ 254 254 254 206 206 206 254 254 254 254 254 254
+ 154 206 206  50 154 154  50 154 154 102 154 206
+ 206 206 206 230 234 235 254 254 254 254 254 254
+ 254 254 254 230 234 235 206 206 206 102 154 154
+   2 102 102   2 102 154   2 102 154   2 102 102
+ 102 154 154 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 245 246 248   2   2   2
+   2   2   2   2   2   2   2   2   2  33  34  35
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2 194 194 195 171 170 167  46  46  47
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  14  14  15
+  90  90  90 202 202 202 150 150 151   2   2   2
+   2   2   2  29  30  31   2   2   2   2   2   2
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 230 234 235 102 154 154
+  50 154 154 154 206 206 230 234 235 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 102 154 206   2 102 102   2 102 154   2 102 102
+  50 154 154 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254   2   2   2
+   2   2   2   2   2   2   2   2   2  29  30  31
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2 134 134 134 187 187 186  58  58  59
+   6   6   7   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  29  30  31
+ 140 140 141 222 222 223  26  26  28   2   2   2
+   2   2   2  33  34  35   2   2   2  12  14  26
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 230 234 235 102 154 154 154 206 206
+ 254 254 254 254 254 254 230 234 235 254 254 254
+ 254 254 254 254 254 254 230 234 235 230 234 235
+ 230 234 235 254 254 254 254 254 254 254 254 254
+ 230 234 235   2 102 154   2 102 154   2 102 102
+  50 154 154 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254   2   2   2
+   2   2   2   2   2   2   6   6   7  18  18  18
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2 134 134 134 187 187 186  58  58  59
+   6   6   7   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  46  46  47
+ 171 170 167 194 194 195   2   2   2   2   2   2
+   2   2   2  58  58  59   6  10  24  33  34  35
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 230 234 235 102 154 206 230 234 235 254 254 254
+ 254 254 254 254 254 254 154 206 206 102 154 206
+  50 154 154  50 154 154   2 102 154   2 102 154
+   2 154 154  50 154 154 154 206 206 254 254 254
+ 230 234 235   2 154 154   2 102 154   2 102 154
+   2 154 154 230 234 235 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254   2   2   2
+   2   2   2   2   2   2  26  26  28   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2 134 134 134 187 187 186  58  58  59
+   6   6   7   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  58  58  59
+ 187 187 186 134 134 134   2   2   2   2   2   2
+   2   2   2  33  34  35  26  26  28  54  54  55
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 206 206 206 254 254 254 254 254 254 254 254 254
+ 154 206 206  50 154 154   2 102 154  50 154 154
+  50 154 154 102 154 154 102 154 154 102 154 154
+  50 154 154   2 102 102   2 102 102  50 154 154
+ 154 206 206   2 102 154   2 102 154   2 102 154
+   2 102 154 230 234 235 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254   2   2   2
+   2   2   2   2   2   2  26  26  28   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2 134 134 134 187 187 186  58  58  59
+   6   6   7   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   6   6   7  58  58  59
+ 187 187 186 134 134 134   2   2   2   2   2   2
+   2   2   2   2   2   2  12  14  26  54  54  55
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 154 206 206 102 154 154
+ 102 154 154 154 206 206 206 206 206 230 234 235
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 206 206 206  50 154 154   2 102 102
+   2 102 154   2 102 154   2 102 154   2 102 154
+   2 102 154 154 206 206 254 254 254 254 254 254
+ 254 254 254 254 254 254 237 238 239   2   2   2
+   2   2   2  26  26  28  14  14  15  14  14  15
+  12  14  26   2   2   2   2   2   2   2   2   2
+   2   2   2 163 162 161 182 182 182  54  54  55
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  54  54  55
+ 182 182 182 194 194 195  18   6   2 130  88   2
+ 162 122   2  55  34   3   2   2   2  62  66  80
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 230 234 235 102 154 154 102 154 154 230 234 235
+ 254 254 254 254 254 254 230 234 235 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254  50 154 154
+   2 102 102   2 102 102   2 102 102   2 102 102
+   2 102 102 102 206 206 254 254 254 254 254 254
+ 254 254 254 254 254 254 188 190 198   2   2   2
+   6   6   7   2   2   2   2   2   2   2   2   2
+   2   2  10  29  30  31  66  66  67  22  22  23
+   2   2   2 202 202 202 163 162 161  42  42  43
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   6   6   7
+  10  10  11  10  10  11  18  18  18  74  74  74
+ 194 194 195 222 222 223 226 162  16 254 212  22
+ 253 207   3 253 202   2  87  61  13   2   2   2
+ 130 130 132 254 254 254 254 254 254 230 234 235
+ 102 154 154 206 206 206 254 254 254 254 254 254
+ 254 254 254 254 254 254 230 234 235 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 206 206 206
+ 102 154 154 102 154 154 102 154 154  50 154 154
+  50 154 154 102 154 154 254 254 254 254 254 242
+ 254 230 154 254 234 162 150 126  70   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2  38  38  39  62  66  80
+  10  10  11 241 242 244 158 158 158  42  42  43
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2  10  10  11  29  30  31  63  62  63
+  86  86  86  94  94  95 100 100 102 158 158 158
+ 230 230 231 186 150  74 248 183   3 254 202  13
+ 253 207   3 253 207   3 254 198   2  89  59   3
+   2   2   2 105 107 112 254 254 254 154 206 206
+ 230 234 235 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 230 234 235 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 230 234 235 230 234 235 254 254 254 242 190  58
+ 253 207   3 254 226   4 250 214   3  23  14   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2  33  34  35  14  14  15
+ 170 142  50 218 218 219 194 194 195  78  78  79
+  10  10  11   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+  10  10  11  58  58  59 134 134 134 187 187 186
+ 210 210 210 214 214 215 218 218 219 234 234 235
+ 184 176 158 218 159   3 254 186   7 254 202  13
+ 253 207   3 253 202   2 253 202   2 246 190  13
+  38  22   2   2   2   2  62  66  80 245 246 248
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 230 230 231 241 242 244
+ 254 254 254 254 254 254 254 254 250 254 254 250
+ 254 254 250 254 254 250 254 254 250 254 254 250
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 228 176  28
+ 254 186   7 253 207   3 234 190   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2  10  87  61  13
+ 254 236  14 238 230  54 230 230 231 130 130 132
+  26  26  28   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+  42  42  43 146 146 146 226 226 226 184 176 158
+ 182 158 114 196 157  72 186 150  74 187 145  53
+ 213 150   7 236 174   8 254 194  14 254 202  13
+ 254 202  13 253 202   2 254 198   2 254 198   2
+ 214 162   3   2   2   2   2   2   2  12  14  26
+ 214 214 215 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 250
+ 254 254 250 254 254 250 254 254 250 254 254 250
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 226 174  56
+ 254 186   7 254 194   2 218 159   3   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   6   6   7 241 183   7
+ 254 222   7 254 222   7 194 194 195 155 153 152
+  33  34  35   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  10  10  11
+  86  86  86 206 206 206 179 164 133 234 170   6
+ 254 186   7 248 184  12 242 177   7 236 174   8
+ 248 184  12 254 190  11 254 198  13 254 198  13
+ 254 198  13 254 198   6 254 198   6 254 198   2
+ 253 207   3 142 102   2   2   2   2   2   2   2
+   2   2   2 166 166 167 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 250
+ 254 254 250 254 254 250 254 254 250 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 241 242 244 204 208 219 213 163  50
+ 248 183   3 254 186   7 221 154   6 100  63   4
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2 175 127   3 254 202  13
+ 254 212  22 254 212  22 194 194 195 166 166 167
+  42  42  43   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  18  18  18
+ 119 119 118 230 230 231 213 163  50 254 186   7
+ 254 202  13 254 202  13 254 198  13 254 194  14
+ 254 198  13 254 198  13 254 198  13 254 198  13
+ 254 198  13 254 198  13 254 198   6 254 194   9
+ 254 198   2 242 198   2  38  22   2   2   2   2
+   2   2   2   2   2   2 100 100 102 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 250
+ 254 254 250 254 254 250 254 254 250 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 204 208 219 190 194 210 213 163  50
+ 242 177   7 242 177   7 226 160   6 186 124   4
+ 118  76   2  55  34   3  45  26   2  55  34   3
+ 118  76   2 194 134  10 242 177   7 254 198  13
+ 254 206  18 254 206  18 191 191 190 198 198 200
+  86  86  86  18  18  18   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  18  18  18
+ 119 122 130 230 230 231 219 155  20 254 190  11
+ 254 202  13 254 206  18 254 202  13 254 202  13
+ 254 198  13 254 198  13 254 194  14 250 194  13
+ 250 194  13 254 194   9 254 194   9 254 198   6
+ 254 198   6 253 207   3 190 145   2   2   2   2
+   2   2   2   2   2   2   2   2   2  50  50  51
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 250
+ 254 254 250 254 254 250 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 204 208 219 190 198 214 204 154  50
+ 234 170   6 248 183   3 234 170   6 211 145   3
+ 206 137   3 194 131   6 194 131   6 194 134  10
+ 211 145   3 234 170   6 254 198  13 254 206  18
+ 254 206  18 254 206  18 222 182  66 222 222 223
+ 166 166 167  70  70  71  14  14  15   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  14  14  15
+ 105 107 112 222 222 223 196 157  72 248 183   3
+ 254 198  13 254 206  18 254 202  13 254 198  13
+ 254 194  14 250 194  13 250 194  13 250 194  13
+ 250 194  13 250 194  13 254 194   9 254 194   9
+ 254 198   6 254 198   6 253 207   3  82  58   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+  86  86  86 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 214 214 215 190 198 214 187 145  53
+ 226 160   6 241 183   7 241 183   7 231 166   7
+ 218 159   3 221 154   6 221 154   6 218 159   3
+ 236 174   8 250 190  11 254 202  13 254 202  13
+ 254 206  18 254 202  13 254 202  13 190 167 108
+ 230 230 231 163 162 161  74  74  74  22  22  23
+   6   6   7   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  10  10  11
+  90  90  90 214 214 215 188 154  82 240 174  22
+ 254 194  14 254 202  13 254 198  13 254 198  13
+ 250 194  13 250 194  13 246 190  13 246 190  13
+ 246 190  13 250 190  11 250 194  13 254 194   9
+ 254 198  13 254 198   6 253 202   2 218 173   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2 249 250 251 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 230 234 235 190 198 214 174 134  38
+ 221 154   6 248 183   3 250 190  11 241 183   7
+ 236 174   8 236 174   8 234 170   6 236 174   8
+ 241 183   7 254 194  14 254 198  13 254 198  13
+ 254 202  13 254 202  13 254 202  13 254 198  13
+ 190 167 108 234 234 235 182 182 182 112 112 112
+  50  50  51  10  10  11   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   6   6   7
+  74  74  74 202 202 202 179 164 133 231 166   7
+ 254 190  11 254 202  13 254 198  13 254 194  14
+ 250 194  13 246 190  13 246 190  13 246 190  13
+ 246 190  13 246 190  13 250 194  13 250 194  13
+ 254 194   9 254 198  13 254 198   6 253 207   3
+ 156 110   2   2   2   2   2   2   2   2   2   2
+   2   2   2 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 241 242 244 105 107 112 142  90   5
+ 221 154   6 241 183   7 254 194   9 254 190  11
+ 254 186   7 241 183   7 241 183   7 248 184  12
+ 250 190  11 254 194  14 254 198  13 254 198  13
+ 254 198  13 254 202  13 254 202  13 254 206  18
+ 254 206  18 218 182  78 214 214 215 214 214 215
+ 140 140 141  38  38  39   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   6   6   7
+  66  66  67 194 194 195 174 162 150 226 162  16
+ 250 190  11 254 198  13 254 198  13 250 194  13
+ 250 194  13 246 190  13 246 190  13 246 190  13
+ 246 190  13 246 190  13 250 190  11 250 194  13
+ 254 194   9 254 194   9 254 198   6 253 202   2
+ 253 202   2  62  39   2   2   2   2   6  10  24
+ 178 182 190 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 122 126 140   2   2   2 142  90   5
+ 218 159   3 248 183   3 254 194   9 254 198  13
+ 254 198  13 254 194   9 250 194  13 250 194  13
+ 250 194  13 250 194  13 254 194  14 254 198  13
+ 254 198  13 254 202  13 254 202  13 254 206  18
+ 254 212  22 254 216  14 254 206  18 194 178 146
+ 198 198 200  74  74  74   6   6   7   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  10  10  11
+  78  78  79 202 202 202 179 164 133 226 162  16
+ 250 190  11 254 198  13 254 198  13 250 194  13
+ 250 194  13 246 190  13 246 190  13 246 190  13
+ 246 190  13 246 190  13 246 190  13 250 194  13
+ 250 194  13 254 194   9 254 198   6 254 194   9
+ 253 207   3 214 162   3 171 170 167 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 100 100 102   2   2   2   2   2   2 156 101   3
+ 226 160   6 248 184  12 254 194   9 254 198  13
+ 254 194   9 250 194  13 250 194  13 250 194  13
+ 250 194  13 250 194  13 250 194  13 254 194  14
+ 254 198  13 254 202  13 254 202  13 254 206  18
+ 254 212  22 254 216  14 254 216  14 226 190  78
+ 214 214 215  90  90  90  10  10  11   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  18  18  18
+ 112 112 112 222 222 223 186 150  74 226 162  16
+ 254 194  14 254 198  13 254 198  13 254 194  14
+ 250 194  13 250 190  11 246 190  13 246 190  13
+ 246 190  13 246 190  13 246 190  13 250 194  13
+ 250 194  13 254 194   9 254 194   9 254 194   9
+ 254 198   2 242 198   2 182 138  22 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 241 242 244  46  46  47
+   2   2   2   2   2   2   2   2   2 156 101   3
+ 226 160   6 254 186   7 254 194   9 254 198  13
+ 254 194   9 250 194  13 250 194  13 250 194  13
+ 250 194  13 250 194  13 254 194  14 254 198  13
+ 254 198  13 254 202  13 254 206  18 254 206  18
+ 254 212  22 254 206  18 254 198  13 194 178 146
+ 206 206 206  82  82  82  10  10  11   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  42  42  43
+ 158 158 158 226 226 226 211 145   3 236 174   8
+ 254 198  13 254 202  13 254 198  13 254 198  13
+ 254 194  14 250 194  13 250 194  13 250 194  13
+ 250 194  13 250 190  11 250 194  13 250 194  13
+ 250 194  13 254 194   9 254 194   9 254 194   9
+ 254 194   9 242 198   2 214 162   3 146 122  78
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 130 130 132   2   2   2   2   2   2
+   2   2   2   2   2   2  18   6   2 156 101   3
+ 231 166   7 250 190  11 254 198  13 254 198  13
+ 254 194   9 250 194  13 250 194  13 250 194  13
+ 250 194  13 254 194  14 254 198  13 254 198  13
+ 254 202  13 254 202  13 254 206  18 254 206  18
+ 254 202  13 248 184  12 226 174  56 222 222 223
+ 158 158 158  50  50  51   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   6   6   7  70  70  71
+ 198 198 200 182 170 146 226 160   6 254 194   9
+ 254 206  18 254 202  13 254 202  13 254 198  13
+ 254 198  13 254 198  13 254 194  14 250 194  13
+ 250 194  13 250 194  13 250 194  13 250 194  13
+ 250 194  13 254 194   9 254 198  13 254 198   6
+ 254 198   6 241 183   7 231 166   7 142  90   5
+  63  62  63 214 214 215 254 254 254 254 254 254
+ 254 254 254 254 254 254 254 254 254 254 254 254
+ 254 254 254 254 254 254 230 230 231 134 134 134
+   6   6   7   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2  38  22   2 166 110  10
+ 231 166   7 250 190  11 254 198  13 254 198  13
+ 254 198  13 254 194  14 254 194  14 254 194  14
+ 254 198  13 254 198  13 254 198  13 254 202  13
+ 254 202  13 254 202  13 254 194  14 248 184  12
+ 240 174  22 179 164 133 234 234 235 178 177 177
+  82  82  82  14  14  15   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2  10  10  11  90  90  90
+ 214 214 215 196 157  72 231 166   7 254 190  11
+ 254 202  13 254 202  13 254 202  13 254 198  13
+ 254 198  13 254 198  13 254 198  13 254 198  13
+ 254 198  13 254 198  13 254 198  13 254 198  13
+ 254 198  13 254 194   9 254 198  13 254 198  13
+ 254 198   6 254 186   7 231 166   7 170 112   4
+  45  26   2   2   2   2  12  14  26  78  78  79
+ 119 119 118 126 126 127 112 112 112  94  94  95
+  54  54  55   6   6   7   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2  55  34   3 170 112   4
+ 231 166   7 254 190  11 254 202  13 254 202  13
+ 254 198  13 254 198  13 254 198  13 254 198  13
+ 254 198  13 254 198  13 254 194  14 254 198  13
+ 254 194  14 240 174  22 219 155  20 179 164 133
+ 214 214 215 210 210 210 150 150 151  74  74  74
+  18  18  18   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2  10  10  11  90  90  90
+ 210 210 210 196 157  72 221 154   6 234 170   6
+ 248 183   3 248 184  12 250 190  11 250 190  11
+ 254 190  11 254 194  14 254 198  13 254 198  13
+ 254 198  13 254 198  13 254 198  13 254 198  13
+ 254 198  13 254 198  13 254 202  13 254 202  13
+ 254 202  13 250 190  11 226 160   6 170 112   4
+  90  52   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2  82  51   7 182 118   3
+ 226 162  16 250 190  11 254 202  13 254 202  13
+ 254 202  13 254 202  13 254 198  13 254 198  13
+ 254 198  13 250 190  11 248 184  12 236 174   8
+ 213 150   7 167 155 134 226 226 226 210 210 210
+ 163 162 161 100 100 102  46  46  47  10  10  11
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   6   6   7  66  66  67
+ 187 187 186 202 202 202 198 146  54 194 131   6
+ 206 137   3 207 143  12 213 150   7 221 154   6
+ 226 162  16 231 166   7 236 174   8 241 183   7
+ 248 184  12 250 190  11 254 198  13 254 198  13
+ 254 202  13 254 202  13 254 202  13 254 202  13
+ 254 198  13 242 177   7 207 143  12 156 101   3
+ 100  63   4   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2  82  51   7 170 112   4
+ 213 150   7 242 177   7 254 198  13 254 198  13
+ 254 202  13 254 198  13 254 198  13 254 194  14
+ 241 183   7 231 166   7 221 154   6 187 145  53
+ 206 206 206 218 218 219 163 162 161 100 100 102
+  46  46  47  18  18  18   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  26  26  28
+ 105 107 112 187 187 186 226 226 226 226 226 226
+ 182 182 182 163 143 109 174 126  38 180 114   4
+ 186 124   4 186 124   4 194 131   6 194 134  10
+ 207 143  12 221 154   6 234 170   6 241 183   7
+ 254 190  11 254 194  14 254 198  13 254 194  14
+ 248 183   3 221 154   6 182 118   3 142  90   5
+  90  52   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2  70  46   2 156 101   3
+ 194 134  10 226 162  16 248 183   3 254 194  14
+ 254 194  14 254 194  14 248 183   3 234 170   6
+ 221 154   6 186 124   4 163 143 109 234 234 235
+ 187 187 186 119 119 118  54  54  55  14  14  15
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   6   6   7
+  26  26  28  74  74  74 112 112 112 150 150 151
+ 182 182 182 210 210 210 230 230 231 202 202 202
+ 171 170 167 146 122  78 146  98  22 142  90   5
+ 156 101   3 166 110  10 186 124   4 206 137   3
+ 211 145   3 218 159   3 231 166   7 226 162  16
+ 211 145   3 182 118   3 148  89   3 111  67   3
+  55  34   3  50  50  51 182 182 182 182 182 182
+ 202 202 202 237 238 239 234 234 235 234 234 235
+ 234 234 235 234 234 235 234 234 235 234 234 235
+ 234 234 235 234 234 235 218 218 219 182 182 182
+ 178 177 177 126 126 127  78  58  26 130  88   2
+ 182 118   3 206 137   3 221 154   6 231 166   7
+ 231 166   7 226 162  16 211 145   3 194 134  10
+ 166 110  10 174 162 150 226 226 226 163 162 161
+  78  78  79  26  26  28   6   6   7   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   6   6   7  18  18  18  33  34  35
+  58  58  59  90  90  90 130 130 132 163 162 161
+ 194 194 195 218 218 219 234 234 235 202 202 202
+ 167 155 134 130 114  86 118  76   2 142  90   5
+ 156 101   3 166 110  10 170 112   4 170 112   4
+ 156 101   3 134  82   2 111  67   3  89  59   3
+ 146 146 146 218 218 219 206 206 206 171 170 167
+ 155 153 152 140 140 141 130 130 132 126 126 127
+ 126 126 127 126 126 127 126 126 127 126 126 127
+ 126 126 127 134 134 134 150 150 151 166 166 167
+ 191 191 190 234 234 235 130 130 132 100  63   4
+ 156 101   3 182 118   3 186 124   4 194 131   6
+ 194 131   6 186 124   4 170 112   4 142  90   5
+ 171 170 167 218 218 219 146 146 146  63  62  63
+  14  14  15   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   6   6   7  10  10  11  26  26  28  42  42  43
+  66  66  67 100 100 102 134 134 134 166 166 167
+ 194 194 195 222 222 223 230 230 231 155 153 152
+ 110  86  42 111  67   3 111  67   3 118  76   2
+ 111  67   3 100  63   4  82  51   7 182 182 182
+ 218 218 219 158 158 158  94  94  95  50  50  51
+  33  34  35  26  26  28  22  22  23  22  22  23
+  22  22  23  22  22  23  22  22  23  22  22  23
+  22  22  23  26  26  28  33  34  35  42  42  43
+  78  78  79 166 166 167 226 226 226 120 112 108
+  89  59   3 134  82   2 148  89   3 156 101   3
+ 156 101   3 142  90   5 120  78  12 171 170 167
+ 218 218 219 134 134 134  50  50  51  10  10  11
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   6   6   7  14  14  15  26  26  28  46  46  47
+  70  70  71 112 112 112 155 153 152 198 198 200
+ 230 230 231 202 202 202 140 140 141 110  94  70
+ 110  94  70 155 153 152 218 218 219 202 202 202
+ 126 126 127  50  50  51  14  14  15   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+  14  14  15  74  74  74 163 162 161 222 222 223
+ 191 191 190 119 119 118 106  92  68 110  94  70
+ 118 106  86 150 150 151 226 226 226 202 202 202
+ 130 130 132  46  46  47   6   6   7   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   6   6   7  18  18  18  42  42  43  78  78  79
+ 126 126 127 171 170 167 198 198 200 214 214 215
+ 214 214 215 194 194 195 155 153 152 100 100 102
+  33  34  35   6   6   7   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2  14  14  15  58  58  59 126 126 127
+ 178 177 177 206 206 206 214 214 215 214 214 215
+ 210 210 210 194 194 195 150 150 151  90  90  90
+  38  38  39   6   6   7   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2  10  10  11
+  26  26  28  46  46  47  74  74  74  90  90  90
+  90  90  90  70  70  71  38  38  39  14  14  15
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   6   6   7  26  26  28
+  54  54  55  82  82  82  90  90  90  94  94  95
+  86  86  86  66  66  67  38  38  39  14  14  15
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
+   2   2   2   2   2   2   2   2   2   2   2   2
diff --git a/drivers/video/logo/logo_sgi_clut224.ppm b/drivers/video/logo/logo_sgi_clut224.ppm
new file mode 100644
index 0000000..6fe4697
--- /dev/null
+++ b/drivers/video/logo/logo_sgi_clut224.ppm
@@ -0,0 +1,1604 @@
+P3
+# 224-color SGI Linux logo
+80 80
+255
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6   6   6   6  10  10  10  10  10  10
+ 10  10  10   6   6   6   6   6   6   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  10  10  10  14  14  14
+ 22  22  22  26  26  26  30  30  30  34  34  34
+ 30  30  30  30  30  30  26  26  26  18  18  18
+ 14  14  14  10  10  10   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  14  14  14  26  26  26  42  42  42
+ 54  54  54  66  66  66  78  78  78  78  78  78
+ 78  78  78  74  74  74  66  66  66  54  54  54
+ 42  42  42  26  26  26  18  18  18  10  10  10
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 22  22  22  42  42  42  66  66  66  86  86  86
+ 66  66  66  38  38  38  38  38  38  22  22  22
+ 26  26  26  34  34  34  54  54  54  66  66  66
+ 86  86  86  70  70  70  46  46  46  26  26  26
+ 14  14  14   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  10  10  10  26  26  26
+ 50  50  50  82  82  82  58  58  58   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  6   6   6  54  54  54  86  86  86  66  66  66
+ 38  38  38  18  18  18   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  22  22  22  50  50  50
+ 78  78  78  34  34  34   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   6   6   6  70  70  70
+ 78  78  78  46  46  46  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  18  18  18  42  42  42  82  82  82
+ 26  26  26   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  14  14  14
+ 46  46  46  34  34  34   6   6   6   2   2   6
+ 42  42  42  78  78  78  42  42  42  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   0   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 10  10  10  30  30  30  66  66  66  58  58  58
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  26  26  26
+ 86  86  86 101 101 101  46  46  46  10  10  10
+  2   2   6  58  58  58  70  70  70  34  34  34
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 14  14  14  42  42  42  86  86  86  10  10  10
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  30  30  30
+ 94  94  94  94  94  94  58  58  58  26  26  26
+  2   2   6   6   6   6  78  78  78  54  54  54
+ 22  22  22   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 22  22  22  62  62  62  62  62  62   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  26  26  26
+ 54  54  54  38  38  38  18  18  18  10  10  10
+  2   2   6   2   2   6  34  34  34  82  82  82
+ 38  38  38  14  14  14   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 30  30  30  78  78  78  30  30  30   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  10  10  10
+ 10  10  10   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  78  78  78
+ 50  50  50  18  18  18   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 38  38  38  86  86  86  14  14  14   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  54  54  54
+ 66  66  66  26  26  26   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 42  42  42  82  82  82   2   2   6   2   2   6
+  2   2   6   6   6   6  10  10  10   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   6   6   6
+ 14  14  14  10  10  10   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  18  18  18
+ 82  82  82  34  34  34  10  10  10   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 46  46  46  86  86  86   2   2   6   2   2   6
+  6   6   6   6   6   6  22  22  22  34  34  34
+  6   6   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  18  18  18  34  34  34
+ 10  10  10  50  50  50  22  22  22   2   2   6
+  2   2   6   2   2   6   2   2   6  10  10  10
+ 86  86  86  42  42  42  14  14  14   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 46  46  46  86  86  86   2   2   6   2   2   6
+ 38  38  38 116 116 116  94  94  94  22  22  22
+ 22  22  22   2   2   6   2   2   6   2   2   6
+ 14  14  14  86  86  86 138 138 138 162 162 162
+154 154 154  38  38  38  26  26  26   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 86  86  86  46  46  46  14  14  14   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 46  46  46  86  86  86   2   2   6  14  14  14
+134 134 134 198 198 198 195 195 195 116 116 116
+ 10  10  10   2   2   6   2   2   6   6   6   6
+101  98  89 187 187 187 210 210 210 218 218 218
+214 214 214 134 134 134  14  14  14   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 86  86  86  50  50  50  18  18  18   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   1   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 46  46  46  86  86  86   2   2   6  54  54  54
+218 218 218 195 195 195 226 226 226 246 246 246
+ 58  58  58   2   2   6   2   2   6  30  30  30
+210 210 210 253 253 253 174 174 174 123 123 123
+221 221 221 234 234 234  74  74  74   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 70  70  70  58  58  58  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 46  46  46  82  82  82   2   2   6 106 106 106
+170 170 170  26  26  26  86  86  86 226 226 226
+123 123 123  10  10  10  14  14  14  46  46  46
+231 231 231 190 190 190   6   6   6  70  70  70
+ 90  90  90 238 238 238 158 158 158   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 70  70  70  58  58  58  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   1   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 42  42  42  86  86  86   6   6   6 116 116 116
+106 106 106   6   6   6  70  70  70 149 149 149
+128 128 128  18  18  18  38  38  38  54  54  54
+221 221 221 106 106 106   2   2   6  14  14  14
+ 46  46  46 190 190 190 198 198 198   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 74  74  74  62  62  62  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   1   0   0   0
+  0   0   1   0   0   0   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 42  42  42  94  94  94  14  14  14 101 101 101
+128 128 128   2   2   6  18  18  18 116 116 116
+118  98  46 121  92   8 121  92   8  98  78  10
+162 162 162 106 106 106   2   2   6   2   2   6
+  2   2   6 195 195 195 195 195 195   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 74  74  74  62  62  62  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   1   0   0   1
+  0   0   1   0   0   0   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 38  38  38  90  90  90  14  14  14  58  58  58
+210 210 210  26  26  26  54  38   6 154 114  10
+226 170  11 236 186  11 225 175  15 184 144  12
+215 174  15 175 146  61  37  26   9   2   2   6
+ 70  70  70 246 246 246 138 138 138   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 70  70  70  66  66  66  26  26  26   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 38  38  38  86  86  86  14  14  14  10  10  10
+195 195 195 188 164 115 192 133   9 225 175  15
+239 182  13 234 190  10 232 195  16 232 200  30
+245 207  45 241 208  19 232 195  16 184 144  12
+218 194 134 211 206 186  42  42  42   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 50  50  50  74  74  74  30  30  30   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 34  34  34  86  86  86  14  14  14   2   2   6
+121  87  25 192 133   9 219 162  10 239 182  13
+236 186  11 232 195  16 241 208  19 244 214  54
+246 218  60 246 218  38 246 215  20 241 208  19
+241 208  19 226 184  13 121  87  25   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 50  50  50  82  82  82  34  34  34  10  10  10
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 34  34  34  82  82  82  30  30  30  61  42   6
+180 123   7 206 145  10 230 174  11 239 182  13
+234 190  10 238 202  15 241 208  19 246 218  74
+246 218  38 246 215  20 246 215  20 246 215  20
+226 184  13 215 174  15 184 144  12   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 26  26  26  94  94  94  42  42  42  14  14  14
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  78  78  78  50  50  50 104  69   6
+192 133   9 216 158  10 236 178  12 236 186  11
+232 195  16 241 208  19 244 214  54 245 215  43
+246 215  20 246 215  20 241 208  19 198 155  10
+200 144  11 216 158  10 156 118  10   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  6   6   6  90  90  90  54  54  54  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  78  78  78  46  46  46  22  22  22
+137  92   6 210 162  10 239 182  13 238 190  10
+238 202  15 241 208  19 246 215  20 246 215  20
+241 208  19 203 166  17 185 133  11 210 150  10
+216 158  10 210 150  10 102  78  10   2   2   6
+  6   6   6  54  54  54  14  14  14   2   2   6
+  2   2   6  62  62  62  74  74  74  30  30  30
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 34  34  34  78  78  78  50  50  50   6   6   6
+ 94  70  30 139 102  15 190 146  13 226 184  13
+232 200  30 232 195  16 215 174  15 190 146  13
+168 122  10 192 133   9 210 150  10 213 154  11
+202 150  34 182 157 106 101  98  89   2   2   6
+  2   2   6  78  78  78 116 116 116  58  58  58
+  2   2   6  22  22  22  90  90  90  46  46  46
+ 18  18  18   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 38  38  38  86  86  86  50  50  50   6   6   6
+128 128 128 174 154 114 156 107  11 168 122  10
+198 155  10 184 144  12 197 138  11 200 144  11
+206 145  10 206 145  10 197 138  11 188 164 115
+195 195 195 198 198 198 174 174 174  14  14  14
+  2   2   6  22  22  22 116 116 116 116 116 116
+ 22  22  22   2   2   6  74  74  74  70  70  70
+ 30  30  30  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 50  50  50 101 101 101  26  26  26  10  10  10
+138 138 138 190 190 190 174 154 114 156 107  11
+197 138  11 200 144  11 197 138  11 192 133   9
+180 123   7 190 142  34 190 178 144 187 187 187
+202 202 202 221 221 221 214 214 214  66  66  66
+  2   2   6   2   2   6  50  50  50  62  62  62
+  6   6   6   2   2   6  10  10  10  90  90  90
+ 50  50  50  18  18  18   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  10  10  10  34  34  34
+ 74  74  74  74  74  74   2   2   6   6   6   6
+144 144 144 198 198 198 190 190 190 178 166 146
+154 121  60 156 107  11 156 107  11 168 124  44
+174 154 114 187 187 187 190 190 190 210 210 210
+246 246 246 253 253 253 253 253 253 182 182 182
+  6   6   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  62  62  62
+ 74  74  74  34  34  34  14  14  14   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  10  10  10  22  22  22  54  54  54
+ 94  94  94  18  18  18   2   2   6  46  46  46
+234 234 234 221 221 221 190 190 190 190 190 190
+190 190 190 187 187 187 187 187 187 190 190 190
+190 190 190 195 195 195 214 214 214 242 242 242
+253 253 253 253 253 253 253 253 253 253 253 253
+ 82  82  82   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  14  14  14
+ 86  86  86  54  54  54  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  18  18  18  46  46  46  90  90  90
+ 46  46  46  18  18  18   6   6   6 182 182 182
+253 253 253 246 246 246 206 206 206 190 190 190
+190 190 190 190 190 190 190 190 190 190 190 190
+206 206 206 231 231 231 250 250 250 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+202 202 202  14  14  14   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 42  42  42  86  86  86  42  42  42  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 14  14  14  38  38  38  74  74  74  66  66  66
+  2   2   6   6   6   6  90  90  90 250 250 250
+253 253 253 253 253 253 238 238 238 198 198 198
+190 190 190 190 190 190 195 195 195 221 221 221
+246 246 246 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253  82  82  82   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  78  78  78  70  70  70  34  34  34
+ 14  14  14   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 34  34  34  66  66  66  78  78  78   6   6   6
+  2   2   6  18  18  18 218 218 218 253 253 253
+253 253 253 253 253 253 253 253 253 246 246 246
+226 226 226 231 231 231 246 246 246 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 178 178 178   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  18  18  18  90  90  90  62  62  62
+ 30  30  30  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  10  10  10  26  26  26
+ 58  58  58  90  90  90  18  18  18   2   2   6
+  2   2   6 110 110 110 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+250 250 250 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 231 231 231  18  18  18   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  18  18  18  94  94  94
+ 54  54  54  26  26  26  10  10  10   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  22  22  22  50  50  50
+ 90  90  90  26  26  26   2   2   6   2   2   6
+ 14  14  14 195 195 195 250 250 250 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+250 250 250 242 242 242  54  54  54   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  38  38  38
+ 86  86  86  50  50  50  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  14  14  14  38  38  38  82  82  82
+ 34  34  34   2   2   6   2   2   6   2   2   6
+ 42  42  42 195 195 195 246 246 246 253 253 253
+253 253 253 253 253 253 253 253 253 250 250 250
+242 242 242 242 242 242 250 250 250 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 250 250 250 246 246 246 238 238 238
+226 226 226 231 231 231 101 101 101   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 38  38  38  82  82  82  42  42  42  14  14  14
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 10  10  10  26  26  26  62  62  62  66  66  66
+  2   2   6   2   2   6   2   2   6   6   6   6
+ 70  70  70 170 170 170 206 206 206 234 234 234
+246 246 246 250 250 250 250 250 250 238 238 238
+226 226 226 231 231 231 238 238 238 250 250 250
+250 250 250 250 250 250 246 246 246 231 231 231
+214 214 214 206 206 206 202 202 202 202 202 202
+198 198 198 202 202 202 182 182 182  18  18  18
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  62  62  62  66  66  66  30  30  30
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 14  14  14  42  42  42  82  82  82  18  18  18
+  2   2   6   2   2   6   2   2   6  10  10  10
+ 94  94  94 182 182 182 218 218 218 242 242 242
+250 250 250 253 253 253 253 253 253 250 250 250
+234 234 234 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 246 246 246
+238 238 238 226 226 226 210 210 210 202 202 202
+195 195 195 195 195 195 210 210 210 158 158 158
+  6   6   6  14  14  14  50  50  50  14  14  14
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  86  86  86  46  46  46
+ 18  18  18   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 22  22  22  54  54  54  70  70  70   2   2   6
+  2   2   6  10  10  10   2   2   6  22  22  22
+166 166 166 231 231 231 250 250 250 253 253 253
+253 253 253 253 253 253 253 253 253 250 250 250
+242 242 242 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 246 246 246
+231 231 231 206 206 206 198 198 198 226 226 226
+ 94  94  94   2   2   6   6   6   6  38  38  38
+ 30  30  30   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  62  62  62  66  66  66
+ 26  26  26  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  74  74  74  50  50  50   2   2   6
+ 26  26  26  26  26  26   2   2   6 106 106 106
+238 238 238 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 231 231 231
+134 134 134 106 106 106 174 174 174 253 253 253
+182 182 182  54  54  54 128 128 128 231 231 231
+250 250 250 253 253 253 253 253 253 253 253 253
+253 253 253 246 246 246 218 218 218 202 202 202
+210 210 210  14  14  14   2   2   6   2   2   6
+ 30  30  30  22  22  22   2   2   6   2   2   6
+  2   2   6   2   2   6  18  18  18  86  86  86
+ 42  42  42  14  14  14   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 42  42  42  90  90  90  22  22  22   2   2   6
+ 42  42  42   2   2   6  18  18  18 218 218 218
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 231 231 231 149 149 149  94  94  94
+154 154 154 182 182 182 101 101 101 250 250 250
+116 116 116  10  10  10  14  14  14  42  42  42
+128 128 128 231 231 231 253 253 253 253 253 253
+253 253 253 253 253 253 250 250 250 221 221 221
+218 218 218 101 101 101   2   2   6  14  14  14
+ 18  18  18  38  38  38  10  10  10   2   2   6
+  2   2   6   2   2   6   2   2   6  78  78  78
+ 58  58  58  22  22  22   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 54  54  54  82  82  82   2   2   6  26  26  26
+ 22  22  22   2   2   6 123 123 123 253 253 253
+253 253 253 253 253 253 253 253 253 238 238 238
+158 158 158 101 101 101 149 149 149 182 182 182
+128 128 128  94  94  94  94  94  94 246 246 246
+123 123 123  78  78  78  38  38  38  14  14  14
+ 18  18  18  62  62  62 158 158 158 238 238 238
+253 253 253 253 253 253 253 253 253 250 250 250
+238 238 238 198 198 198   6   6   6  38  38  38
+ 58  58  58  26  26  26  38  38  38   2   2   6
+  2   2   6   2   2   6   2   2   6  46  46  46
+ 78  78  78  30  30  30  10  10  10   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  10  10  10  30  30  30
+ 74  74  74  58  58  58   2   2   6  42  42  42
+  2   2   6  22  22  22 231 231 231 253 253 253
+253 253 253 250 250 250 128 128 128  62  62  62
+128 128 128 158 158 158 116 116 116 128 128 128
+116 116 116  90  90  90  90  90  90 246 246 246
+128 128 128 116 116 116 106 106 106 101 101 101
+ 38  38  38  10  10  10  22  22  22  54  54  54
+149 149 149 250 250 250 253 253 253 253 253 253
+253 253 253 246 246 246  46  46  46  38  38  38
+ 42  42  42  14  14  14  38  38  38  14  14  14
+  2   2   6   2   2   6   2   2   6   6   6   6
+ 86  86  86  46  46  46  14  14  14   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  14  14  14  42  42  42
+ 90  90  90  18  18  18  18  18  18  26  26  26
+  2   2   6 116 116 116 253 253 253 253 253 253
+253 253 253 231 231 231  30  30  30  14  14  14
+ 30  30  30  62  62  62 134 134 134 210 210 210
+174 174 174 101 101 101  86  86  86 250 250 250
+128 128 128 116 116 116 149 149 149 210 210 210
+134 134 134  38  38  38  46  46  46 154 154 154
+174 174 174 198 198 198 253 253 253 253 253 253
+253 253 253 253 253 253  94  94  94   6   6   6
+  2   2   6   2   2   6  10  10  10  34  34  34
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 74  74  74  58  58  58  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  10  10  10  26  26  26  66  66  66
+ 82  82  82   2   2   6  38  38  38   6   6   6
+ 14  14  14 210 210 210 253 253 253 253 253 253
+253 253 253 246 246 246 138 138 138  46  46  46
+  6   6   6  18  18  18  54  54  54 166 166 166
+174 174 174 101 101 101  74  74  74 238 238 238
+123 123 123 101 101 101 166 166 166 182 182 182
+ 90  90  90 116 116 116 202 202 202 149 149 149
+128 128 128 231 231 231 253 253 253 253 253 253
+253 253 253 253 253 253 144 144 144   2   2   6
+  2   2   6   2   2   6   2   2   6  46  46  46
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 42  42  42  74  74  74  30  30  30  10  10  10
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  14  14  14  42  42  42  90  90  90
+ 26  26  26   6   6   6  42  42  42   2   2   6
+ 74  74  74 250 250 250 253 253 253 253 253 253
+238 238 238 221 221 221 238 238 238 166 166 166
+ 90  90  90  38  38  38  10  10  10  18  18  18
+ 46  46  46  46  46  46  62  62  62 246 246 246
+101 101 101  42  42  42  62  62  62 116 116 116
+190 190 190 141 141 141 116 116 116 141 141 141
+221 221 221 250 250 250 253 253 253 253 253 253
+253 253 253 253 253 253 182 182 182   2   2   6
+  2   2   6   2   2   6   2   2   6  46  46  46
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 10  10  10  86  86  86  38  38  38  10  10  10
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 10  10  10  26  26  26  66  66  66  82  82  82
+  2   2   6  22  22  22  18  18  18   2   2   6
+149 149 149 253 253 253 253 253 253 214 214 214
+ 38  38  38  38  38  38 166 166 166 238 238 238
+214 214 214 116 116 116  70  70  70  26  26  26
+ 10  10  10  26  26  26  42  42  42 182 182 182
+ 62  62  62  86  86  86 187 187 187 174 174 174
+123 123 123 138 138 138 190 190 190 246 246 246
+210 210 210 110 110 110 138 138 138 221 221 221
+253 253 253 253 253 253 206 206 206   2   2   6
+  2   2   6   2   2   6   2   2   6  38  38  38
+  2   2   6   2   2   6   2   2   6   2   2   6
+  6   6   6  86  86  86  46  46  46  14  14  14
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 18  18  18  46  46  46  86  86  86  18  18  18
+  2   2   6  34  34  34  10  10  10   6   6   6
+210 210 210 253 253 253 253 253 253 190 190 190
+ 38  38  38  14  14  14  26  26  26  86  86  86
+198 198 198 238 238 238 174 174 174  90  90  90
+ 62  62  62  26  26  26  22  22  22  54  54  54
+166 166 166 187 187 187 134 134 134 128 128 128
+166 166 166 231 231 231 231 231 231 149 149 149
+123 123 123 166 166 166 174 174 174 190 190 190
+253 253 253 253 253 253 221 221 221   6   6   6
+  2   2   6   2   2   6   6   6   6  30  30  30
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  82  82  82  54  54  54  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 26  26  26  66  66  66  62  62  62   2   2   6
+  2   2   6  38  38  38  10  10  10  26  26  26
+238 238 238 253 253 253 253 253 253 214 214 214
+116 116 116  90  90  90  30  30  30  14  14  14
+ 38  38  38 110 110 110 214 214 214 195 195 195
+116 116 116  62  62  62  54  54  54  54  54  54
+138 138 138 116 116 116 128 128 128 221 221 221
+246 246 246 166 166 166 116 116 116 174 174 174
+166 166 166 141 141 141 138 138 138 206 206 206
+253 253 253 253 253 253 231 231 231   6   6   6
+  2   2   6   2   2   6  10  10  10  30  30  30
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  66  66  66  58  58  58  22  22  22
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 38  38  38  78  78  78   6   6   6   2   2   6
+  2   2   6  46  46  46  14  14  14  42  42  42
+246 246 246 253 253 253 253 253 253 210 210 210
+134 134 134 116 116 116 110 110 110  54  54  54
+ 14  14  14  26  26  26  62  62  62 106 106 106
+ 54  54  54  70  70  70  78  78  78 110 110 110
+ 82  82  82  74  74  74  86  86  86 166 166 166
+116 116 116 128 128 128 198 198 198 141 141 141
+141 141 141 134 134 134 128 128 128 210 210 210
+253 253 253 253 253 253 234 234 234  10  10  10
+  2   2   6   2   2   6  22  22  22  14  14  14
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  66  66  66  62  62  62  22  22  22
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 50  50  50  74  74  74   2   2   6   2   2   6
+ 14  14  14  70  70  70  34  34  34  62  62  62
+250 250 250 253 253 253 253 253 253 231 231 231
+134 134 134 106 106 106 128 128 128 166 166 166
+ 90  90  90  22  22  22  14  14  14  30  30  30
+ 46  46  46  66  66  66 138 138 138 221 221 221
+128 128 128  46  46  46  54  54  54 101 101 101
+182 182 182 166 166 166 134 134 134 166 166 166
+128 128 128 101 101 101 134 134 134 221 221 221
+253 253 253 253 253 253 234 234 234  14  14  14
+  2   2   6   2   2   6  30  30  30   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  66  66  66  62  62  62  22  22  22
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 54  54  54  62  62  62   2   2   6   2   2   6
+  2   2   6  30  30  30  46  46  46  70  70  70
+250 250 250 253 253 253 253 253 253 231 231 231
+128 128 128 116 116 116 158 158 158 158 158 158
+ 74  74  74 110 110 110  82  82  82  18  18  18
+ 18  18  18 101 101 101 182 182 182 214 214 214
+134 134 134  54  54  54 174 174 174 166 166 166
+138 138 138 134 134 134  78  78  78 211 206 186
+123 123 123 116 116 116 138 138 138 231 231 231
+253 253 253 253 253 253 226 226 226  10  10  10
+  2   2   6   6   6   6  30  30  30   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  66  66  66  58  58  58  22  22  22
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  22  22  22
+ 58  58  58  62  62  62   2   2   6   2   2   6
+  2   2   6   2   2   6  30  30  30  78  78  78
+250 250 250 253 253 253 253 253 253 246 246 246
+138 138 138 116 116 116  86  86  86 101 101 101
+174 174 174  94  94  94  94  94  94 116 116 116
+ 54  54  54  70  70  70  90  90  90  46  46  46
+ 54  54  54  30  30  30 101 101 101 141 141 141
+128 128 128  46  46  46  30  30  30  54  54  54
+ 78  78  78 110 110 110 138 138 138 238 238 238
+253 253 253 253 253 253 206 206 206   2   2   6
+ 22  22  22  34  34  34  18  14   6  22  22  22
+ 26  26  26  18  18  18   6   6   6   2   2   6
+  2   2   6  82  82  82  54  54  54  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  26  26  26
+ 62  62  62 106 106 106  74  54  14 185 133  11
+210 162  10 121  92   8   6   6   6  62  62  62
+238 238 238 253 253 253 253 253 253 246 246 246
+141 141 141 123 123 123 106 106 106 128 128 128
+101 101 101 141 141 141 214 214 214 166 166 166
+134 134 134 149 149 149 106 106 106  78  78  78
+ 90  90  90 138 138 138 154 154 154 195 195 195
+190 190 190  86  86  86  46  46  46  14  14  14
+ 42  42  42 116 116 116 149 149 149 246 246 246
+253 253 253 253 253 253 158 158 158  18  18  18
+ 14  14  14   2   2   6   2   2   6   2   2   6
+  6   6   6  18  18  18  66  66  66  38  38  38
+  6   6   6  94  94  94  50  50  50  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 10  10  10  10  10  10  18  18  18  38  38  38
+ 78  78  78 142 134 106 216 158  10 242 186  14
+246 190  14 246 190  14 156 118  10  10  10  10
+ 90  90  90 238 238 238 253 253 253 250 250 250
+138 138 138 116 116 116  86  86  86 149 149 149
+198 198 198 221 221 221 138 138 138  82  82  82
+134 134 134 128 128 128  82  82  82 106 106 106
+ 82  82  82 138 138 138 138 138 138 128 128 128
+187 187 187 221 221 221 166 166 166  70  70  70
+ 54  54  54 116 116 116 166 166 166 246 246 246
+238 204  91 238 204  91 181 142  44  37  26   9
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  38  38  38  46  46  46
+ 26  26  26 106 106 106  54  54  54  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  14  14  14  22  22  22
+ 30  30  30  38  38  38  50  50  50  70  70  70
+106 106 106 190 142  34 226 170  11 242 186  14
+246 190  14 246 190  14 246 190  14 154 114  10
+  6   6   6  74  74  74 226 226 226 253 253 253
+206 206 206 138 138 138 187 187 187 246 246 246
+187 187 187 110 110 110 101 101 101  62  62  62
+123 123 123 134 134 134 116 116 116 238 238 238
+ 94  94  94 134 134 134 134 134 134  54  54  54
+ 26  26  26 101 101 101 231 231 231 231 231 231
+128 128 128 128 128 128 214 214 214 228 184  62
+241 196  14 241 208  19 232 195  16  38  30  10
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  30  30  30  26  26  26
+203 166  17 154 142  90  66  66  66  26  26  26
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  18  18  18  38  38  38  58  58  58
+ 78  78  78  86  86  86 101 101 101 123 123 123
+175 146  61 210 150  10 234 174  13 246 186  14
+246 190  14 246 190  14 246 190  14 238 190  10
+102  78  10   2   2   6  46  46  46 198 198 198
+253 253 253 246 246 246 221 221 221 123 123 123
+110 110 110 128 128 128  86  86  86  90  90  90
+116 116 116 138 138 138 128 128 128 250 250 250
+106 106 106 138 138 138 128 128 128  62  62  62
+ 22  22  22  18  18  18  46  46  46 166 166 166
+246 246 246 246 246 246 253 253 253 224 178  62
+242 186  14 241 196  14 210 166  10  22  18   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   6   6   6 121  92   8
+238 202  15 232 195  16  82  82  82  34  34  34
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 14  14  14  38  38  38  70  70  70 154 122  46
+190 142  34 200 144  11 197 138  11 197 138  11
+213 154  11 226 170  11 242 186  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+225 175  15  46  32   6   2   2   6  22  22  22
+158 158 158 246 246 246 101 101 101  38  38  38
+ 46  46  46  74  74  74 182 182 182 198 198 198
+116 116 116 134 134 134 123 123 123 246 246 246
+110 110 110 134 134 134 149 149 149 195 195 195
+128 128 128  38  38  38  38  38  38 123 123 123
+211 206 186 250 250 250 242 242 242 224 178  62
+239 182  13 236 186  11 213 154  11  46  32   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  61  42   6 225 175  15
+238 190  10 236 186  11 112 100  78  42  42  42
+ 14  14  14   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 22  22  22  54  54  54 154 122  46 213 154  11
+226 170  11 230 174  11 226 170  11 226 170  11
+236 178  12 242 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+241 196  14 184 144  12  10  10  10   2   2   6
+  6   6   6 116 116 116 154 154 154  38  38  38
+ 10  10  10  18  18  18 116 116 116 218 218 218
+123 123 123 134 134 134 134 134 134 250 250 250
+110 110 110 134 134 134 166 166 166 221 221 221
+128 128 128  74  74  74 187 187 187 141 141 141
+202 202 202 231 231 231 198 198 198 214 170  54
+236 178  12 236 178  12 210 150  10 137  92   6
+ 18  14   6   2   2   6   2   2   6   2   2   6
+  6   6   6  70  47   6 200 144  11 236 178  12
+239 182  13 239 182  13 124 112  88  58  58  58
+ 22  22  22   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  70  70  70 180 133  36 226 170  11
+239 182  13 242 186  14 242 186  14 246 186  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 232 195  16  98  70   6   2   2   6
+  2   2   6   2   2   6  66  66  66 149 149 149
+ 70  70  70  14  14  14  30  30  30  66  66  66
+116 116 116 138 138 138 128 128 128 246 246 246
+101 101 101 138 138 138 138 138 138  94  94  94
+123 123 123 182 182 182 128 128 128 182 182 182
+246 246 246 206 206 206 198 198 198 214 166  58
+230 174  11 230 174  11 216 158  10 192 133   9
+163 110   8 116  81   8 102  78  10 116  81   8
+167 114   7 197 138  11 226 170  11 239 182  13
+242 186  14 242 186  14 162 146  94  78  78  78
+ 34  34  34  14  14  14   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 30  30  30  78  78  78 190 142  34 226 170  11
+239 182  13 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 241 196  14 203 166  17  22  18   6
+  2   2   6   2   2   6   2   2   6  38  38  38
+182 182 182 101 101 101  38  38  38  30  30  30
+110 110 110 134 134 134 141 141 141 250 250 250
+101 101 101 138 138 138 138 138 138 158 158 158
+158 158 158 154 154 154 221 221 221 253 253 253
+250 250 250 206 206 206 198 198 198 202 162  69
+226 170  11 236 178  12 224 166  10 210 150  10
+200 144  11 197 138  11 192 133   9 197 138  11
+210 150  10 226 170  11 242 186  14 246 190  14
+246 190  14 246 186  14 225 175  15 124 112  88
+ 62  62  62  30  30  30  14  14  14   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  78  78  78 174 135  50 224 166  10
+239 182  13 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 241 196  14 139 102  15
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 78  78  78 198 198 198 138 138 138  70  70  70
+106 106 106 134 134 134 141 141 141 246 246 246
+ 94  94  94 138 138 138 134 134 134 134 134 134
+182 182 182 238 238 238 253 253 253 253 253 253
+250 250 250 214 214 214 198 198 198 190 150  46
+219 162  10 236 178  12 234 174  13 224 166  10
+216 158  10 213 154  11 213 154  11 216 158  10
+226 170  11 239 182  13 246 190  14 246 190  14
+246 190  14 246 190  14 242 186  14 206 162  42
+101 101 101  58  58  58  30  30  30  14  14  14
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  74  74  74 174 135  50 216 158  10
+236 178  12 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 241 196  14 226 184  13
+ 61  42   6   2   2   6   2   2   6   2   2   6
+ 22  22  22 238 238 238 246 246 246 174 174 174
+116 116 116 128 128 128 182 182 182 246 246 246
+110 110 110 134 134 134 149 149 149 214 214 214
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 226 226 226 187 187 187 180 133  36
+216 158  10 236 178  12 239 182  13 236 178  12
+230 174  11 226 170  11 226 170  11 230 174  11
+236 178  12 242 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 186  14 239 182  13
+206 162  42 106 106 106  66  66  66  34  34  34
+ 14  14  14   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 26  26  26  70  70  70 163 133  67 213 154  11
+236 178  12 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 241 196  14
+190 146  13  18  14   6   2   2   6   2   2   6
+ 46  46  46 246 246 246 253 253 253 250 250 250
+206 206 206 198 198 198 246 246 246 253 253 253
+221 221 221 195 195 195 231 231 231 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 221 221 221  86  86  86 156 107  11
+216 158  10 236 178  12 242 186  14 246 186  14
+242 186  14 239 182  13 239 182  13 242 186  14
+242 186  14 246 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+242 186  14 225 175  15 142 122  72  66  66  66
+ 30  30  30  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 26  26  26  70  70  70 163 133  67 210 150  10
+236 178  12 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+232 195  16 121  92   8  34  34  34 106 106 106
+221 221 221 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+242 242 242  82  82  82  18  14   6 163 110   8
+216 158  10 236 178  12 242 186  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 242 186  14 163 133  67
+ 46  46  46  18  18  18   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  78  78  78 163 133  67 210 150  10
+236 178  12 246 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+241 196  14 215 174  15 190 178 144 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 218 218 218
+ 58  58  58   2   2   6  22  18   6 167 114   7
+216 158  10 236 178  12 246 186  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 186  14 242 186  14 190 150  46
+ 54  54  54  22  22  22   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 38  38  38  86  86  86 180 133  36 213 154  11
+236 178  12 246 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 232 195  16 190 146  13 214 214 214
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 250 250 250 170 170 170  26  26  26
+  2   2   6   2   2   6  37  26   9 163 110   8
+219 162  10 239 182  13 246 186  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 186  14 236 178  12 224 166  10 142 122  72
+ 46  46  46  18  18  18   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 50  50  50 109 106  95 192 133   9 224 166  10
+242 186  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+242 186  14 226 184  13 210 162  10 142 110  46
+226 226 226 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+198 198 198  66  66  66   2   2   6   2   2   6
+  2   2   6   2   2   6  50  34   6 156 107  11
+219 162  10 239 182  13 246 186  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 242 186  14
+234 174  13 213 154  11 154 122  46  66  66  66
+ 30  30  30  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  22  22  22
+ 58  58  58 154 121  60 206 145  10 234 174  13
+242 186  14 246 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 186  14 236 178  12 210 162  10 163 110   8
+ 61  42   6 138 138 138 218 218 218 250 250 250
+253 253 253 253 253 253 253 253 253 250 250 250
+242 242 242 210 210 210 144 144 144  66  66  66
+  6   6   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  61  42   6 163 110   8
+216 158  10 236 178  12 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 239 182  13 230 174  11 216 158  10
+190 142  34 124 112  88  70  70  70  38  38  38
+ 18  18  18   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  22  22  22
+ 62  62  62 168 124  44 206 145  10 224 166  10
+236 178  12 239 182  13 242 186  14 242 186  14
+246 186  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 236 178  12 216 158  10 175 118   6
+ 80  54   7   2   2   6   6   6   6  30  30  30
+ 54  54  54  62  62  62  50  50  50  38  38  38
+ 14  14  14   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  80  54   7 167 114   7
+213 154  11 236 178  12 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 242 186  14 239 182  13 239 182  13
+230 174  11 210 150  10 174 135  50 124 112  88
+ 82  82  82  54  54  54  34  34  34  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 50  50  50 158 118  36 192 133   9 200 144  11
+216 158  10 219 162  10 224 166  10 226 170  11
+230 174  11 236 178  12 239 182  13 239 182  13
+242 186  14 246 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 186  14 230 174  11 210 150  10 163 110   8
+104  69   6  10  10  10   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  91  60   6 167 114   7
+206 145  10 230 174  11 242 186  14 246 190  14
+246 190  14 246 190  14 246 186  14 242 186  14
+239 182  13 230 174  11 224 166  10 213 154  11
+180 133  36 124 112  88  86  86  86  58  58  58
+ 38  38  38  22  22  22  10  10  10   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 34  34  34  70  70  70 138 110  50 158 118  36
+167 114   7 180 123   7 192 133   9 197 138  11
+200 144  11 206 145  10 213 154  11 219 162  10
+224 166  10 230 174  11 239 182  13 242 186  14
+246 186  14 246 186  14 246 186  14 246 186  14
+239 182  13 216 158  10 185 133  11 152  99   6
+104  69   6  18  14   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  80  54   7 152  99   6
+192 133   9 219 162  10 236 178  12 239 182  13
+246 186  14 242 186  14 239 182  13 236 178  12
+224 166  10 206 145  10 192 133   9 154 121  60
+ 94  94  94  62  62  62  42  42  42  22  22  22
+ 14  14  14   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 18  18  18  34  34  34  58  58  58  78  78  78
+101  98  89 124 112  88 142 110  46 156 107  11
+163 110   8 167 114   7 175 118   6 180 123   7
+185 133  11 197 138  11 210 150  10 219 162  10
+226 170  11 236 178  12 236 178  12 234 174  13
+219 162  10 197 138  11 163 110   8 130  83   6
+ 91  60   6  10  10  10   2   2   6   2   2   6
+ 18  18  18  38  38  38  38  38  38  38  38  38
+ 38  38  38  38  38  38  38  38  38  38  38  38
+ 38  38  38  38  38  38  26  26  26   2   2   6
+  2   2   6   6   6   6  70  47   6 137  92   6
+175 118   6 200 144  11 219 162  10 230 174  11
+234 174  13 230 174  11 219 162  10 210 150  10
+192 133   9 163 110   8 124 112  88  82  82  82
+ 50  50  50  30  30  30  14  14  14   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  14  14  14  22  22  22  34  34  34
+ 42  42  42  58  58  58  74  74  74  86  86  86
+101  98  89 122 102  70 130  98  46 121  87  25
+137  92   6 152  99   6 163 110   8 180 123   7
+185 133  11 197 138  11 206 145  10 200 144  11
+180 123   7 156 107  11 130  83   6 104  69   6
+ 50  34   6  54  54  54 110 110 110 101  98  89
+ 86  86  86  82  82  82  78  78  78  78  78  78
+ 78  78  78  78  78  78  78  78  78  78  78  78
+ 78  78  78  82  82  82  86  86  86  94  94  94
+106 106 106 101 101 101  86  66  34 124  80   6
+156 107  11 180 123   7 192 133   9 200 144  11
+206 145  10 200 144  11 192 133   9 175 118   6
+139 102  15 109 106  95  70  70  70  42  42  42
+ 22  22  22  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  10  10  10
+ 14  14  14  22  22  22  30  30  30  38  38  38
+ 50  50  50  62  62  62  74  74  74  90  90  90
+101  98  89 112 100  78 121  87  25 124  80   6
+137  92   6 152  99   6 152  99   6 152  99   6
+138  86   6 124  80   6  98  70   6  86  66  30
+101  98  89  82  82  82  58  58  58  46  46  46
+ 38  38  38  34  34  34  34  34  34  34  34  34
+ 34  34  34  34  34  34  34  34  34  34  34  34
+ 34  34  34  34  34  34  38  38  38  42  42  42
+ 54  54  54  82  82  82  94  86  76  91  60   6
+134  86   6 156 107  11 167 114   7 175 118   6
+175 118   6 167 114   7 152  99   6 121  87  25
+101  98  89  62  62  62  34  34  34  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6   6   6   6  10  10  10
+ 18  18  18  22  22  22  30  30  30  42  42  42
+ 50  50  50  66  66  66  86  86  86 101  98  89
+106  86  58  98  70   6 104  69   6 104  69   6
+104  69   6  91  60   6  82  62  34  90  90  90
+ 62  62  62  38  38  38  22  22  22  14  14  14
+ 10  10  10  10  10  10  10  10  10  10  10  10
+ 10  10  10  10  10  10   6   6   6  10  10  10
+ 10  10  10  10  10  10  10  10  10  14  14  14
+ 22  22  22  42  42  42  70  70  70  89  81  66
+ 80  54   7 104  69   6 124  80   6 137  92   6
+134  86   6 116  81   8 100  82  52  86  86  86
+ 58  58  58  30  30  30  14  14  14   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  10  10  10  14  14  14
+ 18  18  18  26  26  26  38  38  38  54  54  54
+ 70  70  70  86  86  86  94  86  76  89  81  66
+ 89  81  66  86  86  86  74  74  74  50  50  50
+ 30  30  30  14  14  14   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  18  18  18  34  34  34  58  58  58
+ 82  82  82  89  81  66  89  81  66  89  81  66
+ 94  86  66  94  86  76  74  74  74  50  50  50
+ 26  26  26  14  14  14   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6   6   6   6  14  14  14  18  18  18
+ 30  30  30  38  38  38  46  46  46  54  54  54
+ 50  50  50  42  42  42  30  30  30  18  18  18
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  14  14  14  26  26  26
+ 38  38  38  50  50  50  58  58  58  58  58  58
+ 54  54  54  42  42  42  30  30  30  18  18  18
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+  6   6   6  10  10  10  14  14  14  18  18  18
+ 18  18  18  14  14  14  10  10  10   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 14  14  14  18  18  18  22  22  22  22  22  22
+ 18  18  18  14  14  14  10  10  10   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
diff --git a/drivers/video/logo/logo_sun_clut224.ppm b/drivers/video/logo/logo_sun_clut224.ppm
new file mode 100644
index 0000000..40e6339
--- /dev/null
+++ b/drivers/video/logo/logo_sun_clut224.ppm
@@ -0,0 +1,1604 @@
+P3
+# 224-color Sun Linux logo
+80 80
+255
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   6   6   6   6   6   6  10  10  10  10  10  10
+  10  10  10   6   6   6   6   6   6   6   6   6
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   6   6   6  10  10  10  14  14  14
+  22  22  22  26  26  26  30  30  30  34  34  34
+  30  30  30  30  30  30  26  26  26  18  18  18
+  14  14  14  10  10  10   6   6   6   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   1   0   0   1   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   6   6   6  14  14  14  26  26  26  42  42  42
+  54  54  54  66  66  66  78  78  78  78  78  78
+  78  78  78  74  74  74  66  66  66  54  54  54
+  42  42  42  26  26  26  18  18  18  10  10  10
+   6   6   6   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   1   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  10  10  10
+  22  22  22  42  42  42  66  66  66  86  86  86
+  66  66  66  38  38  38  38  38  38  22  22  22
+  26  26  26  34  34  34  54  54  54  66  66  66
+  86  86  86  70  70  70  46  46  46  26  26  26
+  14  14  14   6   6   6   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   1   0   0   1   0   0   1   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0  10  10  10  26  26  26
+  50  50  50  82  82  82  58  58  58   6   6   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   6   6   6  54  54  54  86  86  86  66  66  66
+  38  38  38  18  18  18   6   6   6   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   6   6   6  22  22  22  50  50  50
+  78  78  78  34  34  34   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   6   6   6  70  70  70
+  78  78  78  46  46  46  22  22  22   6   6   6
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   1   0   0   1   0   0   1   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   6   6   6  18  18  18  42  42  42  82  82  82
+  26  26  26   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6  14  14  14
+  46  46  46  34  34  34   6   6   6   2   2   6
+  42  42  42  78  78  78  42  42  42  18  18  18
+   6   6   6   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   1   0   0   0   0   0   1   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+  10  10  10  30  30  30  66  66  66  58  58  58
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6  26  26  26
+  86  86  86 101 101 101  46  46  46  10  10  10
+   2   2   6  58  58  58  70  70  70  34  34  34
+  10  10  10   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   1   0   0   1   0   0   1   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+  14  14  14  42  42  42  86  86  86  10  10  10
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6  30  30  30
+  94  94  94  94  94  94  58  58  58  26  26  26
+   2   2   6   6   6   6  78  78  78  54  54  54
+  22  22  22   6   6   6   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   6   6   6
+  22  22  22  62  62  62  62  62  62   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6  26  26  26
+  54  54  54  38  38  38  18  18  18  10  10  10
+   2   2   6   2   2   6  34  34  34  82  82  82
+  38  38  38  14  14  14   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   1   0   0   1   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   6   6   6
+  30  30  30  78  78  78  30  30  30   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6  10  10  10
+  10  10  10   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6  78  78  78
+  50  50  50  18  18  18   6   6   6   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   1   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  10  10  10
+  38  38  38  86  86  86  14  14  14   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6  54  54  54
+  66  66  66  26  26  26   6   6   6   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   1   0   0   1   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  14  14  14
+  42  42  42  82  82  82   2   2   6   2   2   6
+   2   2   6   6   6   6  10  10  10   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6   6   6   6
+  14  14  14  10  10  10   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6  18  18  18
+  82  82  82  34  34  34  10  10  10   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   1   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  14  14  14
+  46  46  46  86  86  86   2   2   6   2   2   6
+   6   6   6   6   6   6  22  22  22  34  34  34
+   6   6   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6  18  18  18  34  34  34
+  10  10  10  50  50  50  22  22  22   2   2   6
+   2   2   6   2   2   6   2   2   6  10  10  10
+  86  86  86  42  42  42  14  14  14   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   1   0   0   1   0   0   1   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  14  14  14
+  46  46  46  86  86  86   2   2   6   2   2   6
+  38  38  38 116 116 116  94  94  94  22  22  22
+  22  22  22   2   2   6   2   2   6   2   2   6
+  14  14  14  86  86  86 138 138 138 162 162 162
+ 154 154 154  38  38  38  26  26  26   6   6   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+  86  86  86  46  46  46  14  14  14   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  14  14  14
+  46  46  46  86  86  86   2   2   6  14  14  14
+ 134 134 134 198 198 198 195 195 195 116 116 116
+  10  10  10   2   2   6   2   2   6   6   6   6
+ 101  98  89 187 187 187 210 210 210 218 218 218
+ 214 214 214 134 134 134  14  14  14   6   6   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+  86  86  86  50  50  50  18  18  18   6   6   6
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   1   0   0   0
+   0   0   1   0   0   1   0   0   1   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  14  14  14
+  46  46  46  86  86  86   2   2   6  54  54  54
+ 218 218 218 195 195 195 226 226 226 246 246 246
+  58  58  58   2   2   6   2   2   6  30  30  30
+ 210 210 210 253 253 253 174 174 174 123 123 123
+ 221 221 221 234 234 234  74  74  74   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+  70  70  70  58  58  58  22  22  22   6   6   6
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  14  14  14
+  46  46  46  82  82  82   2   2   6 106 106 106
+ 170 170 170  26  26  26  86  86  86 226 226 226
+ 123 123 123  10  10  10  14  14  14  46  46  46
+ 231 231 231 190 190 190   6   6   6  70  70  70
+  90  90  90 238 238 238 158 158 158   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+  70  70  70  58  58  58  22  22  22   6   6   6
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   1   0   0   0
+   0   0   1   0   0   1   0   0   1   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  14  14  14
+  42  42  42  86  86  86   6   6   6 116 116 116
+ 106 106 106   6   6   6  70  70  70 149 149 149
+ 128 128 128  18  18  18  38  38  38  54  54  54
+ 221 221 221 106 106 106   2   2   6  14  14  14
+  46  46  46 190 190 190 198 198 198   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+  74  74  74  62  62  62  22  22  22   6   6   6
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   1   0   0   0
+   0   0   1   0   0   0   0   0   1   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  14  14  14
+  42  42  42  94  94  94  14  14  14 101 101 101
+ 128 128 128   2   2   6  18  18  18 116 116 116
+ 118  98  46 121  92   8 121  92   8  98  78  10
+ 162 162 162 106 106 106   2   2   6   2   2   6
+   2   2   6 195 195 195 195 195 195   6   6   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+  74  74  74  62  62  62  22  22  22   6   6   6
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   1   0   0   1
+   0   0   1   0   0   0   0   0   1   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  10  10  10
+  38  38  38  90  90  90  14  14  14  58  58  58
+ 210 210 210  26  26  26  54  38   6 154 114  10
+ 226 170  11 236 186  11 225 175  15 184 144  12
+ 215 174  15 175 146  61  37  26   9   2   2   6
+  70  70  70 246 246 246 138 138 138   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+  70  70  70  66  66  66  26  26  26   6   6   6
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  10  10  10
+  38  38  38  86  86  86  14  14  14  10  10  10
+ 195 195 195 188 164 115 192 133   9 225 175  15
+ 239 182  13 234 190  10 232 195  16 232 200  30
+ 245 207  45 241 208  19 232 195  16 184 144  12
+ 218 194 134 211 206 186  42  42  42   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+  50  50  50  74  74  74  30  30  30   6   6   6
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  10  10  10
+  34  34  34  86  86  86  14  14  14   2   2   6
+ 121  87  25 192 133   9 219 162  10 239 182  13
+ 236 186  11 232 195  16 241 208  19 244 214  54
+ 246 218  60 246 218  38 246 215  20 241 208  19
+ 241 208  19 226 184  13 121  87  25   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+  50  50  50  82  82  82  34  34  34  10  10  10
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  10  10  10
+  34  34  34  82  82  82  30  30  30  61  42   6
+ 180 123   7 206 145  10 230 174  11 239 182  13
+ 234 190  10 238 202  15 241 208  19 246 218  74
+ 246 218  38 246 215  20 246 215  20 246 215  20
+ 226 184  13 215 174  15 184 144  12   6   6   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+  26  26  26  94  94  94  42  42  42  14  14  14
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  10  10  10
+  30  30  30  78  78  78  50  50  50 104  69   6
+ 192 133   9 216 158  10 236 178  12 236 186  11
+ 232 195  16 241 208  19 244 214  54 245 215  43
+ 246 215  20 246 215  20 241 208  19 198 155  10
+ 200 144  11 216 158  10 156 118  10   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   6   6   6  90  90  90  54  54  54  18  18  18
+   6   6   6   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  10  10  10
+  30  30  30  78  78  78  46  46  46  22  22  22
+ 137  92   6 210 162  10 239 182  13 238 190  10
+ 238 202  15 241 208  19 246 215  20 246 215  20
+ 241 208  19 203 166  17 185 133  11 210 150  10
+ 216 158  10 210 150  10 102  78  10   2   2   6
+   6   6   6  54  54  54  14  14  14   2   2   6
+   2   2   6  62  62  62  74  74  74  30  30  30
+  10  10  10   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  10  10  10
+  34  34  34  78  78  78  50  50  50   6   6   6
+  94  70  30 139 102  15 190 146  13 226 184  13
+ 232 200  30 232 195  16 215 174  15 190 146  13
+ 168 122  10 192 133   9 210 150  10 213 154  11
+ 202 150  34 182 157 106 101  98  89   2   2   6
+   2   2   6  78  78  78 116 116 116  58  58  58
+   2   2   6  22  22  22  90  90  90  46  46  46
+  18  18  18   6   6   6   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  10  10  10
+  38  38  38  86  86  86  50  50  50   6   6   6
+ 128 128 128 174 154 114 156 107  11 168 122  10
+ 198 155  10 184 144  12 197 138  11 200 144  11
+ 206 145  10 206 145  10 197 138  11 188 164 115
+ 195 195 195 198 198 198 174 174 174  14  14  14
+   2   2   6  22  22  22 116 116 116 116 116 116
+  22  22  22   2   2   6  74  74  74  70  70  70
+  30  30  30  10  10  10   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   6   6   6  18  18  18
+  50  50  50 101 101 101  26  26  26  10  10  10
+ 138 138 138 190 190 190 174 154 114 156 107  11
+ 197 138  11 200 144  11 197 138  11 192 133   9
+ 180 123   7 190 142  34 190 178 144 187 187 187
+ 202 202 202 221 221 221 214 214 214  66  66  66
+   2   2   6   2   2   6  50  50  50  62  62  62
+   6   6   6   2   2   6  10  10  10  90  90  90
+  50  50  50  18  18  18   6   6   6   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0  10  10  10  34  34  34
+  74  74  74  74  74  74   2   2   6   6   6   6
+ 144 144 144 198 198 198 190 190 190 178 166 146
+ 154 121  60 156 107  11 156 107  11 168 124  44
+ 174 154 114 187 187 187 190 190 190 210 210 210
+ 246 246 246 253 253 253 253 253 253 182 182 182
+   6   6   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6  62  62  62
+  74  74  74  34  34  34  14  14  14   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0  10  10  10  22  22  22  54  54  54
+  94  94  94  18  18  18   2   2   6  46  46  46
+ 234 234 234 221 221 221 190 190 190 190 190 190
+ 190 190 190 187 187 187 187 187 187 190 190 190
+ 190 190 190 195 195 195 214 214 214 242 242 242
+ 253 253 253 253 253 253 253 253 253 253 253 253
+  82  82  82   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6  14  14  14
+  86  86  86  54  54  54  22  22  22   6   6   6
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   6   6   6  18  18  18  46  46  46  90  90  90
+  46  46  46  18  18  18   6   6   6 182 182 182
+ 253 253 253 246 246 246 206 206 206 190 190 190
+ 190 190 190 190 190 190 190 190 190 190 190 190
+ 206 206 206 231 231 231 250 250 250 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 202 202 202  14  14  14   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+  42  42  42  86  86  86  42  42  42  18  18  18
+   6   6   6   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   6   6   6
+  14  14  14  38  38  38  74  74  74  66  66  66
+   2   2   6   6   6   6  90  90  90 250 250 250
+ 253 253 253 253 253 253 238 238 238 198 198 198
+ 190 190 190 190 190 190 195 195 195 221 221 221
+ 246 246 246 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253  82  82  82   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6  78  78  78  70  70  70  34  34  34
+  14  14  14   6   6   6   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  14  14  14
+  34  34  34  66  66  66  78  78  78   6   6   6
+   2   2   6  18  18  18 218 218 218 253 253 253
+ 253 253 253 253 253 253 253 253 253 246 246 246
+ 226 226 226 231 231 231 246 246 246 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 178 178 178   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6  18  18  18  90  90  90  62  62  62
+  30  30  30  10  10  10   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0  10  10  10  26  26  26
+  58  58  58  90  90  90  18  18  18   2   2   6
+   2   2   6 110 110 110 253 253 253 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 250 250 250 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 231 231 231  18  18  18   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6  18  18  18  94  94  94
+  54  54  54  26  26  26  10  10  10   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   6   6   6  22  22  22  50  50  50
+  90  90  90  26  26  26   2   2   6   2   2   6
+  14  14  14 195 195 195 250 250 250 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 250 250 250 242 242 242  54  54  54   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6  38  38  38
+  86  86  86  50  50  50  22  22  22   6   6   6
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   6   6   6  14  14  14  38  38  38  82  82  82
+  34  34  34   2   2   6   2   2   6   2   2   6
+  42  42  42 195 195 195 246 246 246 253 253 253
+ 253 253 253 253 253 253 253 253 253 250 250 250
+ 242 242 242 242 242 242 250 250 250 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 250 250 250 246 246 246 238 238 238
+ 226 226 226 231 231 231 101 101 101   6   6   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+  38  38  38  82  82  82  42  42  42  14  14  14
+   6   6   6   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+  10  10  10  26  26  26  62  62  62  66  66  66
+   2   2   6   2   2   6   2   2   6   6   6   6
+  70  70  70 170 170 170 206 206 206 234 234 234
+ 246 246 246 250 250 250 250 250 250 238 238 238
+ 226 226 226 231 231 231 238 238 238 250 250 250
+ 250 250 250 250 250 250 246 246 246 231 231 231
+ 214 214 214 206 206 206 202 202 202 202 202 202
+ 198 198 198 202 202 202 182 182 182  18  18  18
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6  62  62  62  66  66  66  30  30  30
+  10  10  10   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+  14  14  14  42  42  42  82  82  82  18  18  18
+   2   2   6   2   2   6   2   2   6  10  10  10
+  94  94  94 182 182 182 218 218 218 242 242 242
+ 250 250 250 253 253 253 253 253 253 250 250 250
+ 234 234 234 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 253 253 253 246 246 246
+ 238 238 238 226 226 226 210 210 210 202 202 202
+ 195 195 195 195 195 195 210 210 210 158 158 158
+   6   6   6  14  14  14  50  50  50  14  14  14
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   6   6   6  86  86  86  46  46  46
+  18  18  18   6   6   6   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   6   6   6
+  22  22  22  54  54  54  70  70  70   2   2   6
+   2   2   6  10  10  10   2   2   6  22  22  22
+ 166 166 166 231 231 231 250 250 250 253 253 253
+ 253 253 253 253 253 253 253 253 253 250 250 250
+ 242 242 242 254 250 234 238 238 238 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 253 253 253 246 246 246
+ 231 231 231 206 206 206 198 198 198 226 226 226
+  94  94  94   2   2   6   6   6   6  38  38  38
+  30  30  30   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6  62  62  62  66  66  66
+  26  26  26  10  10  10   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  10  10  10
+  30  30  30  74  74  74  50  50  50   2   2   6
+  26  26  26  26  26  26   2   2   6 106 106 106
+ 238 238 238 253 253 253 253 253 253 253 253 253
+ 246 246 246 254 250 234 253 253 253 253 253 253
+ 253 253 253 246 234 182 236 215 124 254 246 218
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 246 246 246 218 218 218 202 202 202
+ 210 210 210  14  14  14   2   2   6   2   2   6
+  30  30  30  22  22  22   2   2   6   2   2   6
+   2   2   6   2   2   6  18  18  18  86  86  86
+  42  42  42  14  14  14   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  14  14  14
+  42  42  42  90  90  90  22  22  22   2   2   6
+  42  42  42   2   2   6  18  18  18 218 218 218
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 210 188 142 234 218 166 253 253 253 253 253 253
+ 254 250 234 245 222 135 242 218 102 254 250 234
+ 253 253 253 253 253 253 253 253 253 254 246 218
+ 242 230 182 246 246 246 253 253 253 253 253 253
+ 253 253 253 253 253 253 250 250 250 221 221 221
+ 218 218 218 101 101 101   2   2   6  14  14  14
+  18  18  18  38  38  38  10  10  10   2   2   6
+   2   2   6   2   2   6   2   2   6  78  78  78
+  58  58  58  22  22  22   6   6   6   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   6   6   6  18  18  18
+  54  54  54  82  82  82   2   2   6  26  26  26
+  22  22  22   2   2   6 123 123 123 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 233 202 129 236 215 124 253 253 253 253 253 253
+ 254 250 234 238 216 106 242 218 102 254 250 234
+ 253 253 253 253 253 253 246 234 198 236 215 124
+ 245 222 135 254 250 234 253 253 253 253 253 253
+ 253 253 253 253 253 253 253 253 253 250 250 250
+ 238 238 238 198 198 198   6   6   6  38  38  38
+  58  58  58  26  26  26  38  38  38   2   2   6
+   2   2   6   2   2   6   2   2   6  46  46  46
+  78  78  78  30  30  30  10  10  10   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0  10  10  10  30  30  30
+  74  74  74  58  58  58   2   2   6  42  42  42
+   2   2   6  22  22  22 231 231 231 253 253 253
+ 238 238 238 238 238 238 253 253 253 253 253 253
+ 242 224 154 238 204  91 246 234 182 253 253 253
+ 246 242 210 242 218 102 242 218 102 254 250 234
+ 253 253 253 254 246 218 238 216 106 242 218 102
+ 254 246 218 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 246 246 246  46  46  46  38  38  38
+  42  42  42  14  14  14  38  38  38  14  14  14
+   2   2   6   2   2   6   2   2   6   6   6   6
+  86  86  86  46  46  46  14  14  14   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   6   6   6  14  14  14  42  42  42
+  90  90  90  18  18  18  18  18  18  26  26  26
+   2   2   6 116 116 116 253 253 253 253 253 253
+ 218 206 182 212 178 106 253 253 253 253 253 253
+ 246 242 210 238 204  91 236 215 124 254 250 234
+ 254 246 218 238 216 106 238 216 106 254 246 218
+ 253 253 253 242 224 154 246 218  74 242 230 182
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 254 250 234 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253  94  94  94   6   6   6
+   2   2   6   2   2   6  10  10  10  34  34  34
+   2   2   6   2   2   6   2   2   6   2   2   6
+  74  74  74  58  58  58  22  22  22   6   6   6
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0  10  10  10  26  26  26  66  66  66
+  82  82  82   2   2   6  38  38  38   6   6   6
+  14  14  14 210 210 210 253 253 253 253 253 253
+ 250 238 202 202 162  69 242 214 146 254 250 234
+ 253 253 253 246 230 178 245 222 135 246 230 178
+ 242 224 154 238 216 106 238 216 106 246 230 178
+ 254 246 202 238 216 106 242 215  82 250 238 202
+ 253 253 253 253 253 253 246 234 182 245 222 135
+ 236 215 124 246 242 210 253 253 253 253 253 253
+ 253 253 253 253 253 253 144 144 144   2   2   6
+   2   2   6   2   2   6   2   2   6  46  46  46
+   2   2   6   2   2   6   2   2   6   2   2   6
+  42  42  42  74  74  74  30  30  30  10  10  10
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   6   6   6  14  14  14  42  42  42  90  90  90
+  26  26  26   6   6   6  42  42  42   2   2   6
+  74  74  74 250 250 250 253 253 253 253 253 253
+ 253 253 253 218 197 138 228 184  62 234 218 166
+ 254 246 218 242 230 182 242 215  82 246 218  74
+ 246 218  60 246 218  60 244 214  54 246 218  60
+ 238 216 106 242 215  82 242 224 154 253 253 253
+ 254 250 234 242 224 154 238 216 106 236 215 124
+ 246 234 198 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 182 182 182   2   2   6
+   2   2   6   2   2   6   2   2   6  46  46  46
+   2   2   6   2   2   6   2   2   6   2   2   6
+  10  10  10  86  86  86  38  38  38  10  10  10
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+  10  10  10  26  26  26  66  66  66  82  82  82
+   2   2   6  22  22  22  18  18  18   2   2   6
+ 149 149 149 253 253 253 253 253 253 253 253 253
+ 253 253 253 254 246 218 233 202 129 236 215 124
+ 245 222 135 242 218 102 244 214  54 244 214  54
+ 246 218  60 246 218  60 246 218  60 246 218  60
+ 246 218  60 246 218  74 245 222 135 246 234 182
+ 246 234 182 246 218  74 242 218 102 254 246 218
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 206 206 206   2   2   6
+   2   2   6   2   2   6   2   2   6  38  38  38
+   2   2   6   2   2   6   2   2   6   2   2   6
+   6   6   6  86  86  86  46  46  46  14  14  14
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   6   6   6
+  18  18  18  46  46  46  86  86  86  18  18  18
+   2   2   6  34  34  34  10  10  10   6   6   6
+ 210 210 210 253 253 253 221 221 221 254 246 218
+ 254 250 234 253 253 253 254 246 218 236 215 124
+ 246 198  46 244 214  54 244 214  54 242 215  82
+ 246 218  74 246 218  60 246 218  74 246 218  74
+ 244 214  54 246 218  60 246 218  74 242 215  82
+ 242 218 102 236 215 124 246 234 182 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 221 221 221   6   6   6
+   2   2   6   2   2   6   6   6   6  30  30  30
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6  82  82  82  54  54  54  18  18  18
+   6   6   6   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  10  10  10
+  26  26  26  66  66  66  62  62  62   2   2   6
+   2   2   6  38  38  38  10  10  10  26  26  26
+ 238 238 238 253 253 253 210 188 142 202 162  69
+ 218 197 138 246 230 178 246 234 198 238 204  91
+ 245 207  45 245 207  45 244 214  54 246 218  60
+ 246 218  60 246 218  60 246 218  60 246 218  60
+ 246 218  74 246 218  60 246 218  60 242 215  82
+ 242 218 102 254 246 202 253 253 253 254 250 234
+ 254 246 202 254 246 202 254 246 218 254 250 234
+ 253 253 253 253 253 253 231 231 231   6   6   6
+   2   2   6   2   2   6  10  10  10  30  30  30
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6  66  66  66  58  58  58  22  22  22
+   6   6   6   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  10  10  10
+  38  38  38  78  78  78   6   6   6   2   2   6
+   2   2   6  46  46  46  14  14  14  42  42  42
+ 246 246 246 253 253 253 254 246 218 218 197 138
+ 212 178 106 221 185 102 242 206 102 245 207  45
+ 244 214  54 244 214  54 246 218  60 246 218  60
+ 246 218  60 246 218  60 246 218  60 246 218  74
+ 246 218  60 246 218  60 242 218 102 246 218  60
+ 242 215  82 246 234 182 246 234 198 242 218 102
+ 242 218 102 238 216 106 242 214 146 246 230 178
+ 253 253 253 253 253 253 234 234 234  10  10  10
+   2   2   6   2   2   6  22  22  22  14  14  14
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6  66  66  66  62  62  62  22  22  22
+   6   6   6   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   6   6   6  18  18  18
+  50  50  50  74  74  74   2   2   6   2   2   6
+  14  14  14  70  70  70  34  34  34  62  62  62
+ 250 250 250 253 253 253 253 253 253 253 253 253
+ 250 238 202 250 238 202 242 206 102 246 198  46
+ 245 207  45 245 207  45 241 208  19 246 218  74
+ 246 218  60 242 215  82 246 218  60 242 215  82
+ 246 218  74 246 218  74 246 218  74 246 218  74
+ 246 218  74 245 222 135 238 222 174 238 216 106
+ 245 222 135 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 234 234 234  14  14  14
+   2   2   6   2   2   6  30  30  30   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6  66  66  66  62  62  62  22  22  22
+   6   6   6   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   6   6   6  18  18  18
+  54  54  54  62  62  62   2   2   6   2   2   6
+   2   2   6  30  30  30  46  46  46  70  70  70
+ 250 250 250 253 253 253 253 253 253 253 253 253
+ 253 253 253 254 250 234 238 204  91 245 207  45
+ 250 206  62 244 214  54 244 214  54 244 214  54
+ 242 215  82 246 218  60 244 214  54 246 218  60
+ 246 218  60 246 218  74 246 218  74 242 215  82
+ 242 215  82 245 222 135 254 250 234 254 250 234
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 226 226 226  10  10  10
+   2   2   6   6   6   6  30  30  30   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6  66  66  66  58  58  58  22  22  22
+   6   6   6   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   6   6   6  22  22  22
+  58  58  58  62  62  62   2   2   6   2   2   6
+   2   2   6   2   2   6  30  30  30  78  78  78
+ 250 250 250 253 253 253 253 253 253 250 238 202
+ 246 234 198 246 230 178 240 198  71 246 198  46
+ 246 198  46 245 207  45 244 214  54 244 214  54
+ 242 215  82 246 218  60 246 218  74 244 214  54
+ 246 218  74 246 218  60 246 218  74 246 218  74
+ 242 215  82 238 216 106 254 246 218 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 206 206 206   2   2   6
+  22  22  22  34  34  34  18  14   6  22  22  22
+  26  26  26  18  18  18   6   6   6   2   2   6
+   2   2   6  82  82  82  54  54  54  18  18  18
+   6   6   6   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   6   6   6  26  26  26
+  62  62  62 106 106 106  74  54  14 185 133  11
+ 210 162  10 121  92   8   6   6   6  62  62  62
+ 238 238 238 253 253 253 253 253 253 188 164 115
+ 202 162  69 214 174  82 242 190  54 242 190  54
+ 246 198  46 246 198  46 245 207  45 250 206  62
+ 244 214  54 244 214  54 244 214  54 246 218  74
+ 246 218  74 246 218  74 246 218  74 244 214  54
+ 246 218  74 238 216 106 246 234 182 242 224 154
+ 246 230 178 254 246 218 253 253 253 253 253 253
+ 253 253 253 253 253 253 158 158 158  18  18  18
+  14  14  14   2   2   6   2   2   6   2   2   6
+   6   6   6  18  18  18  66  66  66  38  38  38
+   6   6   6  94  94  94  50  50  50  18  18  18
+   6   6   6   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   6   6   6
+  10  10  10  10  10  10  18  18  18  38  38  38
+  78  78  78 142 134 106 216 158  10 242 186  14
+ 246 190  14 246 190  14 156 118  10  10  10  10
+  90  90  90 238 238 238 253 253 253 253 253 253
+ 250 238 202 246 234 198 233 202 129 240 198  71
+ 245 207  45 246 198  46 246 198  46 245 207  45
+ 245 207  45 244 214  54 244 214  54 246 218  60
+ 244 214  54 244 214  54 242 215  82 244 214  54
+ 246 218  74 242 224 154 242 224 154 242 215  82
+ 246 218  74 242 218 102 246 230 178 246 230 190
+ 238 204  91 238 204  91 181 142  44  37  26   9
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6  38  38  38  46  46  46
+  26  26  26 106 106 106  54  54  54  18  18  18
+   6   6   6   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   6   6   6  14  14  14  22  22  22
+  30  30  30  38  38  38  50  50  50  70  70  70
+ 106 106 106 190 142  34 226 170  11 242 186  14
+ 246 190  14 246 190  14 246 190  14 154 114  10
+   6   6   6  74  74  74 226 226 226 253 253 253
+ 253 253 253 253 253 253 250 238 202 239 182  13
+ 242 190  54 246 198  46 246 198  46 246 198  46
+ 245 207  45 246 215  20 244 214  54 244 214  54
+ 246 218  60 246 215  20 246 218  60 246 218  60
+ 242 218 102 246 234 182 254 250 234 254 246 202
+ 254 246 202 246 234 182 236 215 124 228 184  62
+ 241 196  14 241 208  19 232 195  16  38  30  10
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   6   6   6  30  30  30  26  26  26
+ 203 166  17 154 142  90  66  66  66  26  26  26
+   6   6   6   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   6   6   6  18  18  18  38  38  38  58  58  58
+  78  78  78  86  86  86 101 101 101 123 123 123
+ 175 146  61 210 150  10 234 174  13 246 186  14
+ 246 190  14 246 190  14 246 190  14 238 190  10
+ 102  78  10   2   2   6  46  46  46 198 198 198
+ 254 246 218 234 218 166 233 202 129 238 216 106
+ 246 198  46 246 198  46 246 198  46 246 198  46
+ 245 207  45 244 214  54 244 214  54 244 214  54
+ 244 214  54 246 215  20 246 218  60 246 215  20
+ 242 218 102 254 246 202 254 250 234 254 250 234
+ 253 253 253 253 253 253 253 253 253 224 178  62
+ 242 186  14 241 196  14 210 166  10  22  18   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   6   6   6 121  92   8
+ 238 202  15 232 195  16  82  82  82  34  34  34
+  10  10  10   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+  14  14  14  38  38  38  70  70  70 154 122  46
+ 190 142  34 200 144  11 197 138  11 197 138  11
+ 213 154  11 226 170  11 242 186  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 225 175  15  46  32   6   2   2   6  22  22  22
+ 210 198 158 202 162  69 212 178 106 246 234 198
+ 242 206 102 246 198  46 245 207  45 245 207  45
+ 245 207  45 246 215  20 244 214  54 244 214  54
+ 244 214  54 246 218  60 244 214  54 246 218  74
+ 236 215 124 238 216 106 236 215 124 250 238 202
+ 254 250 234 250 250 250 242 242 242 224 178  62
+ 239 182  13 236 186  11 213 154  11  46  32   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6  61  42   6 225 175  15
+ 238 190  10 236 186  11 112 100  78  42  42  42
+  14  14  14   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   6   6   6
+  22  22  22  54  54  54 154 122  46 213 154  11
+ 226 170  11 230 174  11 226 170  11 226 170  11
+ 236 178  12 242 186  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 241 196  14 184 144  12  10  10  10   2   2   6
+   6   6   6 116 116 116 242 242 242 253 253 253
+ 254 246 218 233 202 129 228 184  62 242 190  54
+ 246 198  46 245 207  45 245 207  45 250 206  62
+ 245 207  45 244 214  54 242 215  82 254 246 202
+ 254 246 202 242 224 154 242 215  82 236 215 124
+ 250 238 202 231 231 231 198 198 198 214 170  54
+ 236 178  12 236 178  12 210 150  10 137  92   6
+  18  14   6   2   2   6   2   2   6   2   2   6
+   6   6   6  70  47   6 200 144  11 236 178  12
+ 239 182  13 239 182  13 124 112  88  58  58  58
+  22  22  22   6   6   6   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  10  10  10
+  30  30  30  70  70  70 180 133  36 226 170  11
+ 239 182  13 242 186  14 242 186  14 246 186  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 232 195  16  98  70   6   2   2   6
+   2   2   6   2   2   6  66  66  66 221 221 221
+ 218 206 158 238 214 174 246 230 178 233 202 129
+ 240 198  71 240 198  71 240 198  71 240 198  71
+ 238 216 106 242 224 154 246 230 178 245 222 135
+ 254 246 218 254 250 234 254 246 218 236 215 124
+ 218 194 134 206 206 206 198 198 198 214 166  58
+ 230 174  11 230 174  11 216 158  10 192 133   9
+ 163 110   8 116  81   8 102  78  10 116  81   8
+ 167 114   7 197 138  11 226 170  11 239 182  13
+ 242 186  14 242 186  14 162 146  94  78  78  78
+  34  34  34  14  14  14   6   6   6   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   6   6   6
+  30  30  30  78  78  78 190 142  34 226 170  11
+ 239 182  13 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 241 196  14 203 166  17  22  18   6
+   2   2   6   2   2   6   2   2   6  38  38  38
+ 202 162  69 238 214 174 253 253 253 236 215 124
+ 242 214 146 250 238 202 250 238 202 246 230 178
+ 254 246 218 253 253 253 242 230 182 240 198  71
+ 238 216 106 254 246 218 253 253 253 254 250 234
+ 246 234 198 206 206 206 198 198 198 202 162  69
+ 226 170  11 236 178  12 224 166  10 210 150  10
+ 200 144  11 197 138  11 192 133   9 197 138  11
+ 210 150  10 226 170  11 242 186  14 246 190  14
+ 246 190  14 246 186  14 225 175  15 124 112  88
+  62  62  62  30  30  30  14  14  14   6   6   6
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  10  10  10
+  30  30  30  78  78  78 174 135  50 224 166  10
+ 239 182  13 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 241 196  14 139 102  15
+   2   2   6   2   2   6   2   2   6   2   2   6
+  78  78  78 250 250 250 253 253 253 221 185 102
+ 212 178 106 254 246 218 254 246 218 221 185 102
+ 233 202 129 254 250 234 253 253 253 242 230 182
+ 228 184  62 238 214 174 253 253 253 253 253 253
+ 250 250 250 214 214 214 198 198 198 190 150  46
+ 219 162  10 236 178  12 234 174  13 224 166  10
+ 216 158  10 213 154  11 213 154  11 216 158  10
+ 226 170  11 239 182  13 246 190  14 246 190  14
+ 246 190  14 246 190  14 242 186  14 206 162  42
+ 101 101 101  58  58  58  30  30  30  14  14  14
+   6   6   6   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  10  10  10
+  30  30  30  74  74  74 174 135  50 216 158  10
+ 236 178  12 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 241 196  14 226 184  13
+  61  42   6   2   2   6   2   2   6   2   2   6
+  22  22  22 238 238 238 253 253 253 210 188 142
+ 212 178 106 254 250 234 253 253 253 218 197 138
+ 212 178 106 254 246 218 253 253 253 254 250 234
+ 226 214 178 218 206 158 253 253 253 253 253 253
+ 253 253 253 226 226 226 187 187 187 180 133  36
+ 216 158  10 236 178  12 239 182  13 236 178  12
+ 230 174  11 226 170  11 226 170  11 230 174  11
+ 236 178  12 242 186  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 186  14 239 182  13
+ 206 162  42 106 106 106  66  66  66  34  34  34
+  14  14  14   6   6   6   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   6   6   6
+  26  26  26  70  70  70 163 133  67 213 154  11
+ 236 178  12 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 241 196  14
+ 190 146  13  18  14   6   2   2   6   2   2   6
+  46  46  46 246 246 246 253 253 253 231 231 231
+ 246 234 182 253 253 253 253 253 253 226 214 178
+ 190 178 144 254 250 234 253 253 253 254 250 234
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 221 221 221  86  86  86 156 107  11
+ 216 158  10 236 178  12 242 186  14 246 186  14
+ 242 186  14 239 182  13 239 182  13 242 186  14
+ 242 186  14 246 186  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 242 186  14 225 175  15 142 122  72  66  66  66
+  30  30  30  10  10  10   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   6   6   6
+  26  26  26  70  70  70 163 133  67 210 150  10
+ 236 178  12 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 232 195  16 121  92   8  34  34  34 106 106 106
+ 221 221 221 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 242 242 242  82  82  82  18  14   6 163 110   8
+ 216 158  10 236 178  12 242 186  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 242 186  14 163 133  67
+  46  46  46  18  18  18   6   6   6   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  10  10  10
+  30  30  30  78  78  78 163 133  67 210 150  10
+ 236 178  12 246 186  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 241 196  14 215 174  15 190 178 144 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 253 253 253 218 218 218
+  58  58  58   2   2   6  22  18   6 167 114   7
+ 216 158  10 236 178  12 246 186  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 186  14 242 186  14 190 150  46
+  54  54  54  22  22  22   6   6   6   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  14  14  14
+  38  38  38  86  86  86 180 133  36 213 154  11
+ 236 178  12 246 186  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 232 195  16 190 146  13 214 214 214
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 250 250 250 170 170 170  26  26  26
+   2   2   6   2   2   6  37  26   9 163 110   8
+ 219 162  10 239 182  13 246 186  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 186  14 236 178  12 224 166  10 142 122  72
+  46  46  46  18  18  18   6   6   6   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   6   6   6  18  18  18
+  50  50  50 109 106  95 192 133   9 224 166  10
+ 242 186  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 242 186  14 226 184  13 210 162  10 142 110  46
+ 226 226 226 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 253 253 253 253 253 253 253 253 253 253 253 253
+ 198 198 198  66  66  66   2   2   6   2   2   6
+   2   2   6   2   2   6  50  34   6 156 107  11
+ 219 162  10 239 182  13 246 186  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 242 186  14
+ 234 174  13 213 154  11 154 122  46  66  66  66
+  30  30  30  10  10  10   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   6   6   6  22  22  22
+  58  58  58 154 121  60 206 145  10 234 174  13
+ 242 186  14 246 186  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 186  14 236 178  12 210 162  10 163 110   8
+  61  42   6 138 138 138 218 218 218 250 250 250
+ 253 253 253 253 253 253 253 253 253 250 250 250
+ 242 242 242 210 210 210 144 144 144  66  66  66
+   6   6   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6  61  42   6 163 110   8
+ 216 158  10 236 178  12 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 239 182  13 230 174  11 216 158  10
+ 190 142  34 124 112  88  70  70  70  38  38  38
+  18  18  18   6   6   6   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   6   6   6  22  22  22
+  62  62  62 168 124  44 206 145  10 224 166  10
+ 236 178  12 239 182  13 242 186  14 242 186  14
+ 246 186  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 236 178  12 216 158  10 175 118   6
+  80  54   7   2   2   6   6   6   6  30  30  30
+  54  54  54  62  62  62  50  50  50  38  38  38
+  14  14  14   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   6   6   6  80  54   7 167 114   7
+ 213 154  11 236 178  12 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 190  14 242 186  14 239 182  13 239 182  13
+ 230 174  11 210 150  10 174 135  50 124 112  88
+  82  82  82  54  54  54  34  34  34  18  18  18
+   6   6   6   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   6   6   6  18  18  18
+  50  50  50 158 118  36 192 133   9 200 144  11
+ 216 158  10 219 162  10 224 166  10 226 170  11
+ 230 174  11 236 178  12 239 182  13 239 182  13
+ 242 186  14 246 186  14 246 190  14 246 190  14
+ 246 190  14 246 190  14 246 190  14 246 190  14
+ 246 186  14 230 174  11 210 150  10 163 110   8
+ 104  69   6  10  10  10   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   6   6   6  91  60   6 167 114   7
+ 206 145  10 230 174  11 242 186  14 246 190  14
+ 246 190  14 246 190  14 246 186  14 242 186  14
+ 239 182  13 230 174  11 224 166  10 213 154  11
+ 180 133  36 124 112  88  86  86  86  58  58  58
+  38  38  38  22  22  22  10  10  10   6   6   6
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0  14  14  14
+  34  34  34  70  70  70 138 110  50 158 118  36
+ 167 114   7 180 123   7 192 133   9 197 138  11
+ 200 144  11 206 145  10 213 154  11 219 162  10
+ 224 166  10 230 174  11 239 182  13 242 186  14
+ 246 186  14 246 186  14 246 186  14 246 186  14
+ 239 182  13 216 158  10 185 133  11 152  99   6
+ 104  69   6  18  14   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   2   2   6   2   2   6   2   2   6
+   2   2   6   6   6   6  80  54   7 152  99   6
+ 192 133   9 219 162  10 236 178  12 239 182  13
+ 246 186  14 242 186  14 239 182  13 236 178  12
+ 224 166  10 206 145  10 192 133   9 154 121  60
+  94  94  94  62  62  62  42  42  42  22  22  22
+  14  14  14   6   6   6   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   6   6   6
+  18  18  18  34  34  34  58  58  58  78  78  78
+ 101  98  89 124 112  88 142 110  46 156 107  11
+ 163 110   8 167 114   7 175 118   6 180 123   7
+ 185 133  11 197 138  11 210 150  10 219 162  10
+ 226 170  11 236 178  12 236 178  12 234 174  13
+ 219 162  10 197 138  11 163 110   8 130  83   6
+  91  60   6  10  10  10   2   2   6   2   2   6
+  18  18  18  38  38  38  38  38  38  38  38  38
+  38  38  38  38  38  38  38  38  38  38  38  38
+  38  38  38  38  38  38  26  26  26   2   2   6
+   2   2   6   6   6   6  70  47   6 137  92   6
+ 175 118   6 200 144  11 219 162  10 230 174  11
+ 234 174  13 230 174  11 219 162  10 210 150  10
+ 192 133   9 163 110   8 124 112  88  82  82  82
+  50  50  50  30  30  30  14  14  14   6   6   6
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   6   6   6  14  14  14  22  22  22  34  34  34
+  42  42  42  58  58  58  74  74  74  86  86  86
+ 101  98  89 122 102  70 130  98  46 121  87  25
+ 137  92   6 152  99   6 163 110   8 180 123   7
+ 185 133  11 197 138  11 206 145  10 200 144  11
+ 180 123   7 156 107  11 130  83   6 104  69   6
+  50  34   6  54  54  54 110 110 110 101  98  89
+  86  86  86  82  82  82  78  78  78  78  78  78
+  78  78  78  78  78  78  78  78  78  78  78  78
+  78  78  78  82  82  82  86  86  86  94  94  94
+ 106 106 106 101 101 101  86  66  34 124  80   6
+ 156 107  11 180 123   7 192 133   9 200 144  11
+ 206 145  10 200 144  11 192 133   9 175 118   6
+ 139 102  15 109 106  95  70  70  70  42  42  42
+  22  22  22  10  10  10   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   6   6   6  10  10  10
+  14  14  14  22  22  22  30  30  30  38  38  38
+  50  50  50  62  62  62  74  74  74  90  90  90
+ 101  98  89 112 100  78 121  87  25 124  80   6
+ 137  92   6 152  99   6 152  99   6 152  99   6
+ 138  86   6 124  80   6  98  70   6  86  66  30
+ 101  98  89  82  82  82  58  58  58  46  46  46
+  38  38  38  34  34  34  34  34  34  34  34  34
+  34  34  34  34  34  34  34  34  34  34  34  34
+  34  34  34  34  34  34  38  38  38  42  42  42
+  54  54  54  82  82  82  94  86  76  91  60   6
+ 134  86   6 156 107  11 167 114   7 175 118   6
+ 175 118   6 167 114   7 152  99   6 121  87  25
+ 101  98  89  62  62  62  34  34  34  18  18  18
+   6   6   6   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   6   6   6   6   6   6  10  10  10
+  18  18  18  22  22  22  30  30  30  42  42  42
+  50  50  50  66  66  66  86  86  86 101  98  89
+ 106  86  58  98  70   6 104  69   6 104  69   6
+ 104  69   6  91  60   6  82  62  34  90  90  90
+  62  62  62  38  38  38  22  22  22  14  14  14
+  10  10  10  10  10  10  10  10  10  10  10  10
+  10  10  10  10  10  10   6   6   6  10  10  10
+  10  10  10  10  10  10  10  10  10  14  14  14
+  22  22  22  42  42  42  70  70  70  89  81  66
+  80  54   7 104  69   6 124  80   6 137  92   6
+ 134  86   6 116  81   8 100  82  52  86  86  86
+  58  58  58  30  30  30  14  14  14   6   6   6
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   6   6   6  10  10  10  14  14  14
+  18  18  18  26  26  26  38  38  38  54  54  54
+  70  70  70  86  86  86  94  86  76  89  81  66
+  89  81  66  86  86  86  74  74  74  50  50  50
+  30  30  30  14  14  14   6   6   6   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   6   6   6  18  18  18  34  34  34  58  58  58
+  82  82  82  89  81  66  89  81  66  89  81  66
+  94  86  66  94  86  76  74  74  74  50  50  50
+  26  26  26  14  14  14   6   6   6   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   6   6   6   6   6   6  14  14  14  18  18  18
+  30  30  30  38  38  38  46  46  46  54  54  54
+  50  50  50  42  42  42  30  30  30  18  18  18
+  10  10  10   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   6   6   6  14  14  14  26  26  26
+  38  38  38  50  50  50  58  58  58  58  58  58
+  54  54  54  42  42  42  30  30  30  18  18  18
+  10  10  10   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   6   6   6
+   6   6   6  10  10  10  14  14  14  18  18  18
+  18  18  18  14  14  14  10  10  10   6   6   6
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   6   6   6
+  14  14  14  18  18  18  22  22  22  22  22  22
+  18  18  18  14  14  14  10  10  10   6   6   6
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
+   0   0   0   0   0   0   0   0   0   0   0   0
diff --git a/drivers/video/logo/logo_superh_clut224.ppm b/drivers/video/logo/logo_superh_clut224.ppm
new file mode 100644
index 0000000..0241aac
--- /dev/null
+++ b/drivers/video/logo/logo_superh_clut224.ppm
@@ -0,0 +1,1604 @@
+P3
+# 224-color SuperH Linux logo
+80 80
+255
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  6   6   6   6   6   6  10  10  10  10  10  10
+ 10  10  10   6   6   6   6   6   6   6   6   6
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   6   6   6  10  10  10  14  14  13
+ 22  22  22  26  26  26  30  30  30  34  34  34
+ 30  30  30  30  30  30  26  26  26  18  18  18
+ 14  14  13  10  10  10   6   6   6   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  6   6   6  14  14  13  26  26  26  42  42  43
+ 54  54  54  66  66  66  78  78  78  78  78  78
+ 78  78  78  74  74  74  66  66  66  54  54  54
+ 42  42  43  26  26  26  18  18  18  10  10  10
+  6   6   6   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2  10  10  10
+ 22  22  22  42  42  43  66  66  66  86  86  86
+ 66  66  66  38  38  38  38  38  38  22  22  22
+ 26  26  26  34  34  34  54  54  54  66  66  66
+ 86  86  86  70  70  70  46  46  46  26  26  26
+ 14  14  13   6   6   6   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2  10  10  10  26  26  26
+ 50  50  50  82  82  82  58  58  58   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  6   6   6  54  54  54  86  86  86  66  66  66
+ 38  38  38  18  18  18   6   6   6   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   6   6   6  22  22  22  50  50  50
+ 78  78  78  34  34  34   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   6   6   6  70  70  70
+ 78  78  78  46  46  46  22  22  22   6   6   6
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  6   6   6  18  18  18  42  42  43  82  82  82
+ 26  26  26   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  14  14  13
+ 46  46  46  34  34  34   6   6   6   2   2   6
+ 42  42  43  78  78  78  42  42  43  18  18  18
+  6   6   6   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+ 10  10  10  30  30  30  66  66  66  58  58  58
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  26  26  26
+ 86  86  86 102 102 102  46  46  46  10  10  10
+  2   2   6  58  58  58  70  70  70  34  34  34
+ 10  10  10   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+ 14  14  13  42  42  43  86  86  86  10  10  10
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  30  30  30
+ 94  94  93  94  94  93  58  58  58  26  26  26
+  2   2   6   6   6   6  78  78  78  54  54  54
+ 22  22  22   6   6   6   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   6   6   6
+ 22  22  22  62  62  62  62  62  62   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  26  26  26
+ 54  54  54  38  38  38  18  18  18  10  10  10
+  2   2   6   2   2   6  34  34  34  82  82  82
+ 38  38  38  14  14  13   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   6   6   6
+ 30  30  30  78  78  78  30  30  30   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  10  10  10
+ 10  10  10   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  78  78  78
+ 50  50  50  18  18  18   6   6   6   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2  10  10  10
+ 38  38  38  86  86  86  14  14  13   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  54  54  54
+ 66  66  66  26  26  26   6   6   6   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2  14  14  13
+ 42  42  43  82  82  82   2   2   6   2   2   6
+  2   2   6   6   6   6  10  10  10   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   6   6   6
+ 14  14  13  10  10  10   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  18  18  18
+ 82  82  82  34  34  34  10  10  10   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2  14  14  13
+ 46  46  46  86  86  86   2   2   6   2   2   6
+  6   6   6   6   6   6  22  22  22  34  34  34
+  6   6   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  18  18  18  34  34  34
+ 10  10  10  50  50  50  22  22  22   2   2   6
+  2   2   6   2   2   6   2   2   6  10  10  10
+ 86  86  86  42  42  43  14  14  13   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2  14  14  13
+ 46  46  46  86  86  86   2   2   6   2   2   6
+ 38  38  38 118 118 118  94  94  93  22  22  22
+ 22  22  22   2   2   6   2   2   6   2   2   6
+ 14  14  13  86  86  86 138 138 142 163 163 163
+154 154 154  38  38  38  26  26  26   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 86  86  86  46  46  46  14  14  13   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2  14  14  13
+ 46  46  46  86  86  86   2   2   6  14  14  13
+134 134 134 198 198 196 194 194 194 118 118 118
+ 10  10  10   2   2   6   2   2   6   6   6   6
+102  98  90 186 186 186 210 210 210 218 218 218
+214 214 214 134 134 134  14  14  13   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 86  86  86  50  50  50  18  18  18   6   6   6
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2  14  14  13
+ 46  46  46  86  86  86   2   2   6  54  54  54
+218 218 218 194 194 194 226 226 226 246 246 246
+ 58  58  58   2   2   6   2   2   6  30  30  30
+210 210 210 254 254 254 174 174 174 122 122 122
+223 222 222 234 234 234  74  74  74   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 70  70  70  58  58  58  22  22  22   6   6   6
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2  14  14  13
+ 46  46  46  82  82  82   2   2   6 106 106 105
+170 170 170  26  26  26  86  86  86 226 226 226
+122 122 122  10  10  10  14  14  13  46  46  46
+230 230 228 190 190 187   6   6   6  70  70  70
+ 89  90  90 238 238 238 158 158 158   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 70  70  70  58  58  58  22  22  22   6   6   6
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2  14  14  13
+ 42  42  43  86  86  86   6   6   6 118 118 118
+106 106 105   6   6   6  70  70  70 150 150 150
+130 130 130  18  18  18  38  38  38  54  54  54
+223 222 222 106 106 105   2   2   6  14  14  13
+ 46  46  46 190 190 187 198 198 196   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 74  74  74  62  62  62  22  22  22   6   6   6
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2  14  14  13
+ 42  42  43  94  94  93  14  14  13 102 102 102
+130 130 130   2   2   6  18  18  18 118 118 118
+122 100  66 122  94  10 122  94  10 104  78  10
+163 163 163 106 106 105   2   2   6   2   2   6
+  2   2   6 194 194 194 194 194 194   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 74  74  74  62  62  62  22  22  22   6   6   6
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2  10  10  10
+ 38  38  38  89  90  90  14  14  13  58  58  58
+210 210 210  26  26  26  60  40   9 154 114  10
+226 170  10 241 186  13 229 174  11 186 146  17
+214 174  14 178 147  70  38  26  10   2   2   6
+ 70  70  70 246 246 246 138 138 142   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 70  70  70  66  66  66  26  26  26   6   6   6
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2  10  10  10
+ 38  38  38  86  86  86  14  14  13  10  10  10
+194 194 194 190 166 114 195 134  10 229 174  11
+238 182  14 234 190  10 234 196  18 238 202  21
+246 206  46 244 212  20 234 196  18 186 146  17
+218 194 134 206 206 194  42  42  43   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 50  50  50  74  74  74  30  30  30   6   6   6
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2  10  10  10
+ 34  34  34  86  86  86  14  14  13   2   2   6
+122  86  26 195 134  10 220 162  10 238 182  14
+241 186  13 234 196  18 244 212  20 246 217  53
+246 217  53 246 217  39 244 212  20 244 212  20
+244 212  20 224 188  14 122  86  26   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 50  50  50  82  82  82  34  34  34  10  10  10
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2  10  10  10
+ 34  34  34  82  82  82  30  30  30  60  40   9
+181 122   9 204 146  11 229 174  11 238 182  14
+234 190  10 238 202  21 244 212  20 246 218  74
+246 217  39 244 212  20 244 212  20 244 212  20
+224 188  14 214 174  14 186 146  17   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 26  26  26  94  94  93  42  42  43  14  14  13
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2  10  10  10
+ 30  30  30  78  78  78  50  50  50 105  70   7
+195 134  10 219 158  11 238 178  14 241 186  13
+234 196  18 244 212  20 246 217  53 241 214  34
+244 212  20 244 212  20 244 212  20 197 151  13
+204 146  11 219 158  11 158 118  10   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  6   6   6  89  90  90  54  54  54  18  18  18
+  6   6   6   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2  10  10  10
+ 30  30  30  78  78  78  46  46  46  22  22  22
+138  94   6 210 162  12 238 182  14 238 190  10
+238 202  21 244 212  20 244 212  20 244 212  20
+244 212  20 202 164  20 186 134  10 211 150  11
+219 158  11 211 150  11 104  78  10   2   2   6
+  6   6   6  54  54  54  14  14  13   2   2   6
+  2   2   6  62  62  62  74  74  74  30  30  30
+ 10  10  10   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2  10  10  10
+ 34  34  34  78  78  78  50  50  50   6   6   6
+ 92  69  26 138 102  14 190 146  14 224 188  14
+238 202  21 234 196  18 214 174  14 190 146  14
+170 122  12 195 134  10 211 150  11 214 154  10
+202 147  31 182 158 106 102  98  90   2   2   6
+  2   2   6  78  78  78 118 118 118  58  58  58
+  2   2   6  22  22  22  89  90  90  46  46  46
+ 18  18  18   6   6   6   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2  10  10  10
+ 38  38  38  86  86  86  50  50  50   6   6   6
+130 130 130 173 154 115 158 106   9 170 122  12
+197 151  13 186 146  17 197 139  12 204 146  11
+204 146  11 204 146  11 197 139  12 190 166 114
+194 194 194 198 198 196 174 174 174  14  14  13
+  2   2   6  22  22  22 118 118 118 118 118 118
+ 22  22  22   2   2   6  74  74  74  70  70  70
+ 30  30  30  10  10  10   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   6   6   6  18  18  18
+ 50  50  50 102 102 102  26  26  26  10  10  10
+138 138 142 190 190 187 173 154 115 158 106   9
+197 139  12 204 146  11 197 139  12 195 134  10
+181 122   9 188 140  34 191 178 145 186 186 186
+201 202 203 223 222 222 214 214 214  66  66  66
+  2   2   6   2   2   6  50  50  50  62  62  62
+  6   6   6   2   2   6  10  10  10  89  90  90
+ 50  50  50  18  18  18   6   6   6   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2  10  10  10  34  34  34
+ 74  74  74  74  74  74   2   2   6   6   6   6
+146 146 146 198 198 196 190 190 187 178 166 146
+154 122  54 158 106   9 158 106   9 170 126  38
+173 154 115 186 186 186 190 190 187 210 210 210
+246 246 246 254 254 254 254 254 254 182 182 182
+  6   6   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  62  62  62
+ 74  74  74  34  34  34  14  14  13   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2  10  10  10  22  22  22  54  54  54
+ 94  94  93  18  18  18   2   2   6  46  46  46
+234 234 234 223 222 222 190 190 187 190 190 187
+190 190 187 186 186 186 186 186 186 190 190 187
+190 190 187 194 194 194 214 214 214 242 242 242
+254 254 254 254 254 254 254 254 254 254 254 254
+ 82  82  82   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  14  14  13
+ 86  86  86  54  54  54  22  22  22   6   6   6
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  6   6   6  18  18  18  46  46  46  89  90  90
+ 46  46  46  18  18  18   6   6   6 182 182 182
+254 254 254 246 246 246 206 206 206 190 190 187
+190 190 187 190 190 187 190 190 187 190 190 187
+206 206 206 230 230 228 250 250 250 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+201 202 203  14  14  13   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 42  42  43  86  86  86  42  42  43  18  18  18
+  6   6   6   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   6   6   6
+ 14  14  13  38  38  38  74  74  74  66  66  66
+  2   2   6   6   6   6  89  90  90 250 250 250
+254 254 254 254 254 254 238 238 238 198 198 196
+190 190 187 190 190 187 194 194 194 223 222 222
+246 246 246 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254  82  82  82   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  78  78  78  70  70  70  34  34  34
+ 14  14  13   6   6   6   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2  14  14  13
+ 34  34  34  66  66  66  78  78  78   6   6   6
+  2   2   6  18  18  18 218 218 218 254 254 254
+254 254 254 254 254 254 254 254 254 246 246 246
+226 226 226 230 230 228 246 246 246 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 174 174 174   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  18  18  18  89  90  90  62  62  62
+ 30  30  30  10  10  10   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2  10  10  10  26  26  26
+ 58  58  58  89  90  90  18  18  18   2   2   6
+  2   2   6 110 110 110 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+250 250 250 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 230 230 228  18  18  18   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  18  18  18  94  94  93
+ 54  54  54  26  26  26  10  10  10   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   6   6   6  22  22  22  50  50  50
+ 89  90  90  26  26  26   2   2   6   2   2   6
+ 14  14  13 194 194 194 250 250 250 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+250 250 250 242 242 242  54  54  54   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  38  38  38
+ 86  86  86  50  50  50  22  22  22   6   6   6
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  6   6   6  14  14  13  38  38  38  82  82  82
+ 34  34  34   2   2   6   2   2   6   2   2   6
+ 42  42  43 194 194 194 246 246 246 254 254 254
+254 254 254 254 254 254 254 254 254 250 250 250
+242 242 242 242 242 242 250 250 250 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 250 250 250 246 246 246 238 238 238
+226 226 226 230 230 228 102 102 102   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 38  38  38  82  82  82  42  42  43  14  14  13
+  6   6   6   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+ 10  10  10  26  26  26  62  62  62  66  66  66
+  2   2   6   2   2   6   2   2   6   6   6   6
+ 70  70  70 170 170 170 206 206 206 234 234 234
+246 246 246 250 250 250 250 250 250 238 238 238
+226 226 226 230 230 228 238 238 238 250 250 250
+250 250 250 250 250 250 246 246 246 230 230 228
+214 214 214 206 206 206 201 202 203 201 202 203
+198 198 196 201 202 203 182 182 182  18  18  18
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  62  62  62  66  66  66  30  30  30
+ 10  10  10   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+ 14  14  13  42  42  43  82  82  82  18  18  18
+  2   2   6   2   2   6   2   2   6  10  10  10
+ 94  94  93 182 182 182 218 218 218 242 242 242
+250 250 250 254 254 254 254 254 254 250 250 250
+234 234 234 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 246 246 246
+238 238 238 226 226 226 210 210 210 201 202 203
+194 194 194 194 194 194 210 210 210 158 158 158
+  6   6   6  14  14  13  50  50  50  14  14  13
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  86  86  86  46  46  46
+ 18  18  18   6   6   6   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   6   6   6
+ 22  22  22  54  54  54  70  70  70   2   2   6
+  2   2   6  10  10  10   2   2   6  22  22  22
+166 166 166 230 230 228 250 250 250 254 254 254
+254 254 254 254 254 254 254 254 254 250 250 250
+242 242 242 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 246 246 246
+230 230 228 206 206 206 198 198 196 226 226 226
+ 94  94  93   2   2   6   6   6   6  38  38  38
+ 30  30  30   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  62  62  62  66  66  66
+ 26  26  26  10  10  10   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2  10  10  10
+ 30  30  30  74  74  74  50  50  50   2   2   6
+ 26  26  26  26  26  26   2   2   6 106 106 105
+238 238 238 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 246 246 246 218 218 218 201 202 203
+210 210 210  14  14  13   2   2   6   2   2   6
+ 30  30  30  22  22  22   2   2   6   2   2   6
+  2   2   6   2   2   6  18  18  18  86  86  86
+ 42  42  43  14  14  13   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2  14  14  13
+ 42  42  43  89  90  90  22  22  22   2   2   6
+ 42  42  43   2   2   6  18  18  18 218 218 218
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 250 250 250 223 222 222
+218 218 218 102 102 102   2   2   6  14  14  13
+ 18  18  18  38  38  38  10  10  10   2   2   6
+  2   2   6   2   2   6   2   2   6  78  78  78
+ 58  58  58  22  22  22   6   6   6   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   6   6   6  18  18  18
+ 54  54  54  82  82  82   2   2   6  26  26  26
+ 22  22  22   2   2   6 122 122 122 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 250 250 250
+238 238 238 198 198 196   6   6   6  38  38  38
+ 58  58  58  26  26  26  38  38  38   2   2   6
+  2   2   6   2   2   6   2   2   6  46  46  46
+ 78  78  78  30  30  30  10  10  10   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2  10  10  10  30  30  30
+ 74  74  74  58  58  58   2   2   6  42  42  43
+  2   2   6  22  22  22 230 230 228 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 250 250 250
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 246 246 246  46  46  46  38  38  38
+ 42  42  43  14  14  13  38  38  38  14  14  13
+  2   2   6   2   2   6   2   2   6   6   6   6
+ 86  86  86  46  46  46  14  14  13   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   6   6   6  14  14  13  42  42  43
+ 89  90  90  18  18  18  18  18  18  26  26  26
+  2   2   6 118 118 118 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 250 250 250 238 238 238
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254  94  94  93   6   6   6
+  2   2   6   2   2   6  10  10  10  34  34  34
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 74  74  74  58  58  58  22  22  22   6   6   6
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2  10  10  10  26  26  26  66  66  66
+ 82  82  82   2   2   6  38  38  38   6   6   6
+ 14  14  13 210 210 210 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 246 246 246 242 242 242
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 146 146 146   2   2   6
+  2   2   6   2   2   6   2   2   6  46  46  46
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 42  42  43  74  74  74  30  30  30  10  10  10
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  6   6   6  14  14  13  42  42  43  89  90  90
+ 26  26  26   6   6   6  42  42  43   2   2   6
+ 74  74  74 250 250 250 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 242 242 242 242 242 242
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 182 182 182   2   2   6
+  2   2   6   2   2   6   2   2   6  46  46  46
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 10  10  10  86  86  86  38  38  38  10  10  10
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+ 10  10  10  26  26  26  66  66  66  82  82  82
+  2   2   6  22  22  22  18  18  18   2   2   6
+150 150 150 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 234 234 234 242 242 242
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 206 206 206   2   2   6
+  2   2   6   2   2   6   2   2   6  38  38  38
+  2   2   6   2   2   6   2   2   6   2   2   6
+  6   6   6  86  86  86  46  46  46  14  14  13
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   6   6   6
+ 18  18  18  46  46  46  86  86  86  18  18  18
+  2   2   6  34  34  34  10  10  10   6   6   6
+210 210 210 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 234 234 234 242 242 242
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 223 222 222   6   6   6
+  2   2   6   2   2   6   6   6   6  30  30  30
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  82  82  82  54  54  54  18  18  18
+  6   6   6   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2  10  10  10
+ 26  26  26  66  66  66  62  62  62   2   2   6
+  2   2   6  38  38  38  10  10  10  26  26  26
+238 238 238 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 230 230 228 238 238 238
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 230 230 228   6   6   6
+  2   2   6   2   2   6  10  10  10  30  30  30
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  66  66  66  58  58  58  22  22  22
+  6   6   6   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2  10  10  10
+ 38  38  38  78  78  78   6   6   6   2   2   6
+  2   2   6  46  46  46  14  14  13  42  42  43
+246 246 246 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 230 230 228 242 242 242
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 234 234 234  10  10  10
+  2   2   6   2   2   6  22  22  22  14  14  13
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  66  66  66  62  62  62  22  22  22
+  6   6   6   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   6   6   6  18  18  18
+ 50  50  50  74  74  74   2   2   6   2   2   6
+ 14  14  13  70  70  70  34  34  34  62  62  62
+250 250 250 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 230 230 228 246 246 246
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 234 234 234  14  14  13
+  2   2   6   2   2   6  30  30  30   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  66  66  66  62  62  62  22  22  22
+  6   6   6   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   6   6   6  18  18  18
+ 54  54  54  62  62  62   2   2   6   2   2   6
+  2   2   6  30  30  30  46  46  46  70  70  70
+250 250 250 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 230 230 228 246 246 246
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 226 226 226  10  10  10
+  2   2   6   6   6   6  30  30  30   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  66  66  66  58  58  58  22  22  22
+  6   6   6   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   6   6   6  22  22  22
+ 58  58  58  62  62  62   2   2   6   2   2   6
+  2   2   6   2   2   6  30  30  30  78  78  78
+250 250 250 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 230 230 228 246 246 246
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 206 206 206   2   2   6
+ 22  22  22  34  34  34  18  14   6  22  22  22
+ 26  26  26  18  18  18   6   6   6   2   2   6
+  2   2   6  82  82  82  54  54  54  18  18  18
+  6   6   6   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   6   6   6  26  26  26
+ 62  62  62 106 106 105  74  51  11 186 134  10
+210 162  12 122  94  10   6   6   6  62  62  62
+238 238 238 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 230 230 228 246 246 246
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 158 158 158  18  18  18
+ 14  14  13   2   2   6   2   2   6   2   2   6
+  6   6   6  18  18  18  66  66  66  38  38  38
+  6   6   6  94  94  93  50  50  50  18  18  18
+  6   6   6   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   6   6   6
+ 10  10  10  10  10  10  18  18  18  38  38  38
+ 78  78  78 142 134 106 219 158  11 241 186  13
+246 190  14 246 190  14 158 118  10  10  10  10
+ 89  90  90 238 238 238 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 230 230 228 250 250 250
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 246 230 190
+238 206  90 238 206  90 188 140  34  38  26  10
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  38  38  38  46  46  46
+ 26  26  26 106 106 105  54  54  54  18  18  18
+  6   6   6   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   6   6   6  14  14  13  22  22  22
+ 30  30  30  38  38  38  50  50  50  70  70  70
+106 106 105 188 140  34 226 170  10 241 186  13
+246 190  14 246 190  14 246 190  14 154 114  10
+  6   6   6  74  74  74 226 226 226 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 230 230 228 250 250 250
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 233 188  64
+240 198  14 244 212  20 234 196  18  38  30  10
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  30  30  30  26  26  26
+202 164  20 154 142  90  66  66  66  26  26  26
+  6   6   6   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  6   6   6  18  18  18  38  38  38  58  58  58
+ 78  78  78  86  86  86 102 102 102 122 122 122
+178 147  70 211 150  11 234 174  12 246 186  14
+246 190  14 246 190  14 246 190  14 238 190  10
+104  78  10   2   2   6  46  46  46 198 198 196
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 234 234 234 242 242 242
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 222 175  59
+241 186  13 240 198  14 210 162  12  18  18  18
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   6   6   6 122  94  10
+238 202  21 234 196  18  82  82  82  34  34  34
+ 10  10  10   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+ 14  14  13  38  38  38  70  70  70 154 122  54
+188 140  34 204 146  11 197 139  12 197 139  12
+214 154  10 226 170  10 241 186  13 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+229 174  11  49  35   6   2   2   6  22  22  22
+158 158 158 250 250 250 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 250 250 250 242 242 242 222 175  59
+238 182  14 241 186  13 214 154  10  49  35   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  60  40   9 229 174  11
+238 190  10 241 186  13 114 102  78  42  42  43
+ 14  14  13   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   6   6   6
+ 22  22  22  54  54  54 154 122  54 214 154  10
+226 170  10 229 174  11 226 170  10 226 170  10
+238 178  14 241 186  13 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+240 198  14 186 146  17  10  10  10   2   2   6
+  6   6   6 118 118 118 242 242 242 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 230 230 228 198 198 196 206 170  74
+238 178  14 238 178  14 211 150  11 138  94   6
+ 18  14   6   2   2   6   2   2   6   2   2   6
+  6   6   6  70  46   6 204 146  11 238 178  14
+238 182  14 238 182  14 126 114  90  58  58  58
+ 22  22  22   6   6   6   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2  10  10  10
+ 30  30  30  70  70  70 182 134  38 226 170  10
+238 182  14 241 186  13 241 186  13 246 186  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 234 196  18  98  70   6   2   2   6
+  2   2   6   2   2   6  66  66  66 223 222 222
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 206 206 206 198 198 196 207 165  68
+229 174  11 229 174  11 219 158  11 195 134  10
+163 110  10 118  82  10 104  78  10 118  82  10
+164 114   8 197 139  12 226 170  10 238 182  14
+241 186  13 241 186  13 162 146  94  78  78  78
+ 34  34  34  14  14  13   6   6   6   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   6   6   6
+ 30  30  30  78  78  78 188 140  34 226 170  10
+238 182  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 240 198  14 202 164  20  18  18  18
+  2   2   6   2   2   6   2   2   6  38  38  38
+218 218 218 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+250 250 250 206 206 206 198 198 196 207 165  68
+226 170  10 238 178  14 226 166  13 211 150  11
+204 146  11 197 139  12 195 134  10 197 139  12
+211 150  11 226 170  10 241 186  13 246 190  14
+246 190  14 246 186  14 229 174  11 126 114  90
+ 62  62  62  30  30  30  14  14  13   6   6   6
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2  10  10  10
+ 30  30  30  78  78  78 174 134  50 226 166  13
+238 182  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 240 198  14 138 102  14
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 78  78  78 250 250 250 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+250 250 250 214 214 214 198 198 196 192 148  44
+220 162  10 238 178  14 234 174  12 226 166  13
+219 158  11 214 154  10 214 154  10 219 158  11
+226 170  10 238 182  14 246 190  14 246 190  14
+246 190  14 246 190  14 241 186  13 206 160  36
+102 102 102  58  58  58  30  30  30  14  14  13
+  6   6   6   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2  10  10  10  86  86  86 150 150 150
+170 170 170 186 186 186 226 210 207 231 220 218
+246 230 190 246 230 190 246 230 190 246 230 190
+238 206  90 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 240 198  14 224 188  14
+ 60  40   9   2   2   6   6   6   6   2   2   6
+ 22  22  22 238 238 238 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 226 226 226 186 186 186 182 134  38
+219 158  11 238 178  14 238 182  14 238 178  14
+229 174  11 226 170  10 226 170  10 229 174  11
+238 178  14 241 186  13 246 190  14 246 190  14
+246 190  14 240 198  14 246 230 190 246 230 190
+226 210 207 186 186 186 110 110 110  38  38  38
+ 26  26  26 122 122 122 138 138 142 138 138 142
+138 138 142 102  98  90   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+ 14  14  13 154 154 154 246 246 246 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+246 230 190 238 206  90 240 198  14 240 198  14
+240 198  14 240 198  14 246 190  14 246 190  14
+246 190  14 240 198  14 240 198  14 238 202  21
+206 160  36  18  18  18  22  22  22  30  30  30
+ 70  70  70 246 246 246 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 254 254 254 254 254 254 254 254 254
+254 254 254 230 230 228 118 118 118 170 126  38
+220 162  10 238 178  14 241 186  13 246 190  14
+234 196  18 246 190  14 246 190  14 234 196  18
+246 190  14 246 206  46 238 206  90 246 206  46
+240 198  14 246 230 190 254 254 254 254 254 254
+254 254 254 252 251 251 205 195 190 110 110 110
+134 134 134 242 242 242 250 250 250 254 254 254
+250 250 250 138 138 142 102  98  90   2   2   2
+  2   2   2   2   2   2   3   3   3  18  14   6
+150 150 150 242 242 242 239 159 153 249 100  93
+249 100  93 249 100  93 249 100  93 249 100  93
+249 100  93 249 100  93 249 100  93 249 100  93
+239 159 153 246 218  74 246 246 246 246 246 246
+246 246 246 246 246 246 238 206  90 246 190  14
+246 230 190 246 246 246 246 246 246 246 246 246
+246 230 190 138 102  14 182 182 182 242 242 242
+252 251 251 252 251 251 252 251 251 252 251 251
+252 251 251 252 251 251 254 254 254 252 251 251
+252 251 251 252 251 251 246 246 246 252 251 251
+254 254 254 252 251 251 252 251 251 254 254 254
+254 254 254 252 251 251 242 242 242 238 238 238
+238 206  90 238 178  14 241 186  13 246 230 190
+246 246 246 246 246 246 246 246 246 246 230 190
+246 230 190 246 246 246 252 251 251 246 230 190
+246 230 190 246 230 190 249 100  93 249 100  93
+249 100  93 249 100  93 218 194 134 218 194 134
+234 234 234 212 132  53 249 100  93 249 100  93
+249 100  93 239 159 153 138 138 142 102  98  90
+  2   2   2   2   2   2  10  10  10 150 150 150
+242 242 242 249 100  93 254   3   3 254   3   3
+254   3   3 254   3   3 254   3   3 254   3   3
+254   3   3 254   3   3 254   3   3 254   3   3
+239 159 153 246 246 246 246 230 190 246 230 190
+246 230 190 246 230 190 246 230 190 246 230 190
+246 230 190 246 230 190 246 230 190 246 230 190
+246 230 190 246 230 190 238 238 238 246 230 190
+246 230 190 246 230 190 246 230 190 246 246 246
+231 220 218 218 194 134 218 194 134 226 210 207
+246 246 246 246 246 246 246 246 246 252 251 251
+246 246 246 226 210 207 218 194 134 218 194 134
+239 159 153 218 194 134 226 210 207 246 230 190
+246 246 246 238 206  90 246 230 190 246 230 190
+246 230 190 246 230 190 246 230 190 246 230 190
+246 246 246 226 210 207 239 159 153 226 210 207
+246 246 246 239 159 153 254   3   3 254   3   3
+254   3   3 254   3   3 218 194 134 246 246 246
+231 220 218 254  21  21 254   3   3 254   3   3
+254   3   3 212 132  53 250 250 250 122 122 122
+  2   2   2   2   2   2  89  90  90 246 246 246
+239 159 153 254   3   3 254   3   3 254   3   3
+254   3   3 254   3   3 254   3   3 254   3   3
+254   3   3 254   3   3 254   3   3 254  21  21
+226 210 207 226 210 207 254  21  21 254  21  21
+254  21  21 254  21  21 239 159 153 252 251 251
+249 100  93 254  21  21 254  21  21 254  21  21
+249 100  93 246 246 246 249 100  93 254  21  21
+254  21  21 254  21  21 249 100  93 249 100  93
+254  21  21 254   3   3 254   3   3 254  21  21
+212 132  53 246 246 246 252 251 251 226 210 207
+254  56  56 254  21  21 254   3   3 254   3   3
+254   3   3 254   3   3 254   3   3 254  21  21
+249 100  93 242 242 242 246 246 246 249 100  93
+254  21  21 254  21  21 254  21  21 249 100  93
+249 100  93 254   3   3 254   3   3 254  56  56
+246 246 246 249 100  93 254   3   3 254   3   3
+254   3   3 254  21  21 246 230 190 252 251 251
+239 159 153 254   3   3 254   3   3 254   3   3
+254   3   3 218 194 134 246 246 246  58  58  58
+  2   2   2   6   6   6 182 182 182 252 251 251
+254  56  56 254   3   3 254   3   3 254   3   3
+254   3   3 249 100  93 239 159 153 239 159 153
+239 159 153 212 132  53 249 100  93 249 100  93
+246 246 246 212 132  53 254   3   3 254   3   3
+254   3   3 254  21  21 238 238 238 246 230 190
+254  21  21 254   3   3 254   3   3 254   3   3
+239 159 153 246 230 190 254  21  21 254   3   3
+254   3   3 254   3   3 254  21  21 254   3   3
+254   3   3 254   3   3 254   3   3 254   3   3
+254  21  21 246 246 246 231 220 218 254  21  21
+254   3   3 254   3   3 254   3   3 254   3   3
+254  21  21 254  21  21 254   3   3 254   3   3
+254   3   3 239 159 153 246 230 190 254  21  21
+254   3   3 254   3   3 254   3   3 254  56  56
+254   3   3 254   3   3 254   3   3 212 132  53
+246 246 246 254  21  21 254   3   3 254   3   3
+254   3   3 249 100  93 246 246 246 246 246 246
+249 100  93 254   3   3 254   3   3 254   3   3
+254  21  21 242 242 242 214 214 214  14  14  13
+  2   2   2   6   6   6 210 210 210 252 251 251
+254  56  56 254   3   3 254   3   3 254   3   3
+254   3   3 249 100  93 239 159 153 239 159 153
+239 159 153 239 159 153 238 238 238 246 246 246
+246 246 246 254  56  56 254   3   3 254   3   3
+254   3   3 249 100  93 246 246 246 239 159 153
+254   3   3 254   3   3 254   3   3 254   3   3
+246 230 190 239 159 153 254   3   3 254   3   3
+254   3   3 254   3   3 254  21  21 254  21  21
+254   3   3 254   3   3 254   3   3 254   3   3
+254   3   3 246 246 246 249 100  93 254   3   3
+254   3   3 254   3   3 254  21  21 218 194 134
+242 242 242 239 159 153 254   3   3 254   3   3
+254   3   3 249 100  93 239 159 153 254   3   3
+254   3   3 254   3   3 254   3   3 254   3   3
+254   3   3 254   3   3 254   3   3 218 194 134
+226 210 207 254   3   3 254   3   3 254   3   3
+254   3   3 254  21  21 254  21  21 254  21  21
+254   3   3 254   3   3 254   3   3 254   3   3
+249 100  93 254 254 254 158 158 158   2   2   2
+  2   2   2  10  10  10 186 186 186 246 246 246
+254  56  56 254   3   3 254   3   3 254   3   3
+254   3   3 254   3   3 254   3   3 254   3   3
+254   3   3 254   3   3 254  56  56 252 251 251
+246 230 190 254  21  21 254   3   3 254   3   3
+254   3   3 239 159 153 252 251 251 249 100  93
+254   3   3 254   3   3 254   3   3 254  56  56
+252 251 251 249 100  93 254   3   3 254   3   3
+254   3   3 254  21  21 218 194 134 226 210 207
+254  56  56 254   3   3 254   3   3 254   3   3
+254  56  56 231 220 218 254  21  21 254   3   3
+254   3   3 254   3   3 254  21  21 254  56  56
+254  56  56 254  56  56 254   3   3 254   3   3
+254   3   3 239 159 153 249 100  93 254   3   3
+254   3   3 254   3   3 254   3   3 254   3   3
+254   3   3 254   3   3 254  21  21 246 246 246
+212 132  53 254   3   3 254   3   3 254   3   3
+254   3   3 254   3   3 254   3   3 254   3   3
+254   3   3 254   3   3 254   3   3 254   3   3
+239 159 153 252 251 251  89  90  90   2   2   2
+  2   2   2   6   6   6  50  50  50 206 206 206
+226 210 207 249 100  93 254  56  56 254  21  21
+254  21  21 254  21  21 254   3   3 254   3   3
+254   3   3 254   3   3 254   3   3 238 238 238
+239 159 153 254   3   3 254   3   3 254   3   3
+254  21  21 226 210 207 238 238 238 254  21  21
+254   3   3 254   3   3 254   3   3 212 132  53
+238 238 238 254  56  56 254   3   3 254   3   3
+254   3   3 239 159 153 246 246 246 246 246 246
+254  56  56 254   3   3 254   3   3 254   3   3
+249 100  93 239 159 153 254   3   3 254   3   3
+254   3   3 254   3   3 254   3   3 254   3   3
+254   3   3 254   3   3 254   3   3 254   3   3
+254  21  21 226 210 207 254  56  56 254   3   3
+254   3   3 254   3   3 254  21  21 249 100  93
+239 159 153 239 159 153 239 159 153 246 246 246
+254  56  56 254   3   3 254   3   3 254   3   3
+254   3   3 254  21  21 254  21  21 254   3   3
+254   3   3 254   3   3 254   3   3 254   3   3
+246 230 190 242 242 242  26  26  26   2   2   2
+  6   6   6  50  50  50 206 206 206 226 210 207
+231 220 218 231 220 218 231 220 218 246 230 190
+246 230 190 239 159 153 254   3   3 254   3   3
+254   3   3 254   3   3 254  21  21 246 246 246
+249 100  93 254   3   3 254   3   3 254   3   3
+254  21  21 231 220 218 239 159 153 254   3   3
+254   3   3 254   3   3 254   3   3 218 194 134
+218 194 134 254   3   3 254   3   3 254   3   3
+254   3   3 239 159 153 246 230 190 239 159 153
+254   3   3 254   3   3 254   3   3 254   3   3
+239 159 153 212 132  53 254   3   3 254   3   3
+254   3   3 254  21  21 218 194 134 231 220 218
+231 220 218 231 220 218 226 210 207 218 194 134
+226 210 207 231 220 218 254   3   3 254   3   3
+254   3   3 254   3   3 212 132  53 246 246 246
+252 251 251 252 251 251 242 242 242 231 220 218
+254  21  21 254   3   3 254   3   3 254   3   3
+249 100  93 242 242 242 238 238 238 254  56  56
+254   3   3 254   3   3 254   3   3 254  56  56
+246 246 246 194 194 194   6   6   6   2   2   2
+ 22  22  22 210 210 210 246 230 190 254  56  56
+254  21  21 254  21  21 254  21  21 254  21  21
+254  21  21 254  21  21 254   3   3 254   3   3
+254   3   3 254   3   3 249 100  93 246 246 246
+254  56  56 254   3   3 254   3   3 254   3   3
+254   3   3 254  21  21 254  21  21 254   3   3
+254   3   3 254   3   3 254  56  56 242 242 242
+212 132  53 254   3   3 254   3   3 254   3   3
+254   3   3 254  21  21 254  21  21 254   3   3
+254   3   3 254   3   3 254   3   3 254  56  56
+238 238 238 212 132  53 254   3   3 254   3   3
+254   3   3 254   3   3 254  56  56 249 100  93
+249 100  93 249 100  93 254  56  56 254  56  56
+246 246 246 239 159 153 254   3   3 254   3   3
+254   3   3 254  21  21 231 220 218 246 246 246
+206 170  74 182 158 106 246 246 246 239 159 153
+254   3   3 254   3   3 254   3   3 254   3   3
+218 194 134 242 242 242 246 230 190 254  21  21
+254   3   3 254   3   3 254   3   3 212 132  53
+252 251 251 131 126 116   6   6   6   2   2   2
+ 89  90  90 246 246 246 239 159 153 254   3   3
+254   3   3 254   3   3 254   3   3 254   3   3
+254   3   3 254   3   3 254   3   3 254   3   3
+254   3   3 254  21  21 226 210 207 246 246 246
+249 100  93 254   3   3 254   3   3 254   3   3
+254   3   3 254   3   3 254   3   3 254   3   3
+254   3   3 254  56  56 226 210 207 252 251 251
+254  56  56 254   3   3 254   3   3 254   3   3
+254  56  56 254  21  21 254   3   3 254   3   3
+254   3   3 254   3   3 254  21  21 218 194 134
+238 238 238 226 210 207 254  21  21 254   3   3
+254   3   3 254   3   3 254   3   3 254   3   3
+254   3   3 254   3   3 254   3   3 239 159 153
+252 251 251 249 100  93 254   3   3 254   3   3
+254   3   3 254  56  56 246 246 246 231 220 218
+138 102  14 198 198 196 252 251 251 249 100  93
+254   3   3 254   3   3 254   3   3 254  21  21
+246 230 190 252 251 251 239 159 153 254   3   3
+254   3   3 254   3   3 254   3   3 218 194 134
+242 242 242  62  62  62   6   6   6   2   2   2
+ 58  58  58 122 122 122 218 194 134 212 132  53
+249 100  93 249 100  93 254  56  56 254  56  56
+254  56  56 254  56  56 254  56  56 249 100  93
+212 132  53 246 230 190 214 214 214 146 146 146
+242 242 242 239 159 153 249 100  93 254  56  56
+254  56  56 254  56  56 254  56  56 249 100  93
+239 159 153 246 230 190 246 246 246 246 230 190
+254  21  21 254   3   3 254   3   3 254   3   3
+239 159 153 218 194 134 249 100  93 254  56  56
+254  56  56 249 100  93 226 210 207 230 230 228
+ 89  90  90 231 220 218 226 210 207 249 100  93
+249 100  93 254  56  56 254  56  56 254  56  56
+249 100  93 249 100  93 239 159 153 238 238 238
+218 194 134 239 159 153 212 132  53 249 100  93
+249 100  93 239 159 153 231 220 218 154 142  90
+102 102 102 146 146 146 170 170 170 239 159 153
+249 100  93 249 100  93 249 100  93 239 159 153
+218 218 218 130 130 130 239 159 153 249 100  93
+249 100  93 249 100  93 212 132  53 246 230 190
+118 118 118  18  14   6   6   6   6   2   2   2
+  2   2   2  58  58  58 118 118 118 242 242 242
+254 254 254 250 250 250 246 246 246 246 246 246
+246 246 246 246 246 246 246 246 246 252 251 251
+252 251 251 214 214 214  50  50  50  18  18  18
+138 138 142 246 246 246 252 251 251 246 246 246
+246 246 246 246 246 246 246 246 246 252 251 251
+252 251 251 231 220 218 252 251 251 239 159 153
+254   3   3 254   3   3 254   3   3 254  21  21
+231 220 218 238 238 238 252 251 251 242 242 242
+252 251 251 252 251 251 230 230 228  74  74  74
+ 18  18  18  62  62  62 226 226 226 254 254 254
+252 251 251 246 246 246 246 246 246 252 251 251
+252 251 251 252 251 251 250 250 250 150 150 150
+162 146  94 205 195 190 252 251 251 252 251 251
+252 251 251 226 210 207 142 134 106  86  86  86
+ 58  58  58  34  34  34 122 122 122 163 163 163
+252 251 251 254 254 254 250 250 250 223 222 222
+102  98  90  78  78  78 130 130 130 254 254 254
+254 254 254 254 254 254 246 246 246 118 118 118
+ 18  14   6   3   3   3   2   2   2   2   2   2
+  2   2   2   2   2   2  58  58  58 122 122 122
+150 150 150 170 170 170 182 182 182 190 190 187
+201 202 203 201 202 203 190 190 187 170 170 170
+118 118 118  30  30  30   6   6   6   6   6   6
+ 10  10  10  86  86  86 150 150 150 182 182 182
+201 202 203 201 202 203 190 190 187 174 174 174
+134 134 134 146 146 146 190 190 187 239 159 153
+249 100  93 249 100  93 249 100  93 249 100  93
+234 234 234 138 138 142 166 166 166 198 198 196
+190 190 187 138 138 142  42  42  43   6   6   6
+  3   3   3   6   6   6  50  50  50 138 138 142
+174 174 174 198 198 196 198 198 196 182 182 182
+163 163 163 138 138 142 102  98  90  70  70  70
+ 94  86  75 158 158 158 178 166 146 170 170 170
+174 174 174 138 138 142  74  74  74  50  50  50
+ 26  26  26  14  14  13  10  10  10 118 118 118
+130 130 130 130 130 130 130 130 130 102  98  90
+  6   6   6   3   3   3  78  78  78 130 130 130
+130 130 130 130 130 130 118 118 118  18  14   6
+  3   3   3   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   6   6   6   6   6   6
+ 10  10  10  10  10  10   6   6   6   2   2   2
+  2   2   2   2   2   2   2   2   2   6   6   6
+  6   6   6   6   6   6   6   6   6   6   6   6
+ 14  14  13  14  14  13  22  22  22  22  22  22
+ 34  34  34  42  42  43 122 122 122 174 174 174
+254 254 254 254 254 254 254 254 254 238 238 238
+138 138 142   6   6   6   6   6   6  10  10  10
+  6   6   6   2   2   2   2   2   2   6   6   6
+  6   6   6   6   6   6   6   6   6   2   2   2
+  6   6   6  10  10  10  10  10  10   6   6   6
+  2   2   2   6   6   6  14  14  13  30  30  30
+ 42  42  43  54  54  54  62  62  62  62  62  62
+ 54  54  54  42  42  43  30  30  30  18  18  18
+ 10  10  10   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  6   6   6   2   2   2   6   6   6   2   2   2
+  2   2   2   2   2   2   2   2   2  10  10  10
+ 10  10  10  10  10  10  14  14  13 106 106 105
+163 163 163 170 170 170 166 166 166 138 138 142
+  6   6   6   6   6   6   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  6   6   6   6   6   6   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   6   6   6
+ 18  18  18  22  22  22  22  22  22  22  22  22
+ 18  18  18  14  14  13  10  10  10   6   6   6
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
+  2   2   2   2   2   2   2   2   2   2   2   2
diff --git a/drivers/video/logo/logo_superh_mono.pbm b/drivers/video/logo/logo_superh_mono.pbm
new file mode 100644
index 0000000..6cd378e
--- /dev/null
+++ b/drivers/video/logo/logo_superh_mono.pbm
@@ -0,0 +1,203 @@
+P1
+# Black and white SuperH Linux logo
+80 80
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 0 0 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1
+1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1
+1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1
+1 0 0 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 0 0 0 0 1 1 1 1 0 0 0 0 0 0 1 1
+1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1
+0 1 1 0 0 1 1 1 0 0 1 1 0 0 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0 1 1 1 0 1 1 1 1 0 0 1
+1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1
+1 1 1 1 0 1 1 1 0 1 1 1 1 0 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1
+1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1
+0 1 1 0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 0 0 0 1 0 0 1 0 0 0 0 0 1 1 1
+1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1
+1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1
+1 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 0 0 0 0 0 0 1 1 0 0 0 0 1 1
+1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1
+1 1 1 1 1 1 1 1 0 0 0 0 1 1 0 1 1 1 0 1 1 1 0 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 1
+1 1 1 0 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1
+0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 1 1 1 0 1 1 1 0 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0
+1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1
+0 0 0 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 0 1 1 1 1 1 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 1 1
+1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 1 1
+0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1
+1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1
+1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0
+0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1
+1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0
+0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1
+1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0
+0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1
+1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 1 0 1 1 1 1 1 1 0 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 0 0 1 1 1 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 1 0 0 0 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 1 1 1 1 1 0
+0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 1 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 1 1 0 0 0
+0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1
+1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 1 1
+1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1
+1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 1 1 1 1 1 0 1
+1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 1 1 1 1 0 0 0 1 1 1 1 1 0 0 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1
+0 0 1 1 1 1 1 0 0 1 1 1 1 0 1 1 1 0 1 1 1 1 1 0 0 0 0 0 1 1 1 1
+1 1 1 0 0 0 0 1 1 1 0 0 1 1 1 1 0 1 1 1 1 1 0 0 0 1 1 1 1 0 0 1
+1 1 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 1 1 1 1 0 1 1
+1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1
+0 1 1 1 1 0 0 0 1 1 1 1 1 0 0 1 1 1 0 0 1 1 1 1 1 1 1 1 1 0 0 0
+0 1 1 1 1 1 0 0 0 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0
+0 1 1 1 1 0 0 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1
+1 1 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 0 0 1 1 1 1 0 1 1 1
+1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 0
+1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 0
+0 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1
+1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1
+1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 0 1 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1
+1 0 0 0 1 1 1 1 0 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0
+1 1 1 1 1 0 0 0 1 1 1 1 0 0 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0
+1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1
+1 1 1 1 0 0 1 1 1 1 0 0 0 1 0 0 1 1 1 1 0 0 0 1 1 1 1 1 0 0 1 1
+1 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1
+1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 0 1 0 0 1
+1 1 1 1 0 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0
+0 0 1 1 1 1 1 1 0 0 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 0 0 1 1 1 1 1
+1 1 0 0 0 1 1 1 1 0 0 1 1 0 0 1 1 1 1 1 0 0 0 1 1 1 1 0 0 1 1 1
+1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0
+0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0
+0 0 0 0 0 1 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1
+1 1 0 0 0 0 0 0 1 1 0 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0
+0 0 1 1 1 0 0 0 0 1 1 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0
+0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
diff --git a/drivers/video/logo/logo_superh_vga16.ppm b/drivers/video/logo/logo_superh_vga16.ppm
new file mode 100644
index 0000000..a8ffcd7
--- /dev/null
+++ b/drivers/video/logo/logo_superh_vga16.ppm
@@ -0,0 +1,1604 @@
+P3
+# 16-color SuperH Linux logo
+80 80
+255
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85  85  85  85  85  85  85  85  85  85
+ 85  85  85  85  85  85  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85  85  85  85
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+ 85  85  85  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85 170 170 170   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+170 170 170 170 170 170  85  85  85   0   0   0
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0  85  85  85 170 170 170   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0 170 170 170 170 170 170
+170 170 170   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+ 85  85  85 170 170 170 170 170 170 170 170 170
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0 170 170 170 255 255 255 255 255 255
+255 255 255 170 170 170   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0  85  85  85
+170 170 170 170 170 170 255 255 255 255 255 255
+  0   0   0   0   0   0   0   0   0   0   0   0
+170 170 170 255 255 255 170 170 170 170 170 170
+255 255 255 170 170 170   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0  85  85  85
+170 170 170   0   0   0   0   0   0 255 255 255
+ 85  85  85   0   0   0   0   0   0   0   0   0
+255 255 255 170 170 170   0   0   0  85  85  85
+170 170 170 255 255 255 170 170 170   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0  85  85  85
+ 85  85  85   0   0   0   0   0   0 170 170 170
+ 85  85  85   0   0   0   0   0   0   0   0   0
+255 255 255  85  85  85   0   0   0   0   0   0
+ 85  85  85 255 255 255 170 170 170   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0  85  85  85
+170 170 170   0   0   0   0   0   0 170 170 170
+ 85  85  85  85  85  85  85  85  85  85  85  85
+255 255 255  85  85  85   0   0   0   0   0   0
+ 85  85  85 255 255 255 170 170 170   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+255 255 255   0   0   0   0   0   0 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0   0   0   0   0   0   0
+ 85  85  85 255 255 255   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+170 170 170 170 170 170 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170 170 170 170 170 170   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85  85  85  85   0   0   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 170  85   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85  85  85  85   0   0   0
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 170  85   0
+170  85   0 170  85   0  85  85  85   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85  85  85  85   0   0   0
+ 85  85  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+170  85   0 170  85   0 170  85   0 170  85   0
+170  85   0 170  85   0  85  85  85   0   0   0
+  0   0   0  85  85  85 170 170 170  85  85  85
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85  85  85  85   0   0   0
+ 85  85  85 170  85   0 170  85   0 170  85   0
+170  85   0 170  85   0 170  85   0 170  85   0
+170  85   0 170  85   0 170  85   0 170  85   0
+170 170 170 170 170 170 170 170 170   0   0   0
+  0   0   0   0   0   0 170 170 170 170 170 170
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+ 85  85  85 170 170 170 170  85   0 170  85   0
+170  85   0 170  85   0 170  85   0 170  85   0
+170  85   0 170  85   0 170 170 170 170 170 170
+170 170 170 170 170 170 170 170 170  85  85  85
+  0   0   0   0   0   0  85  85  85  85  85  85
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+ 85  85  85 170 170 170 170 170 170 170  85   0
+170  85   0 170  85   0 170  85   0 170  85   0
+170 170 170 170 170 170 170 170 170 170 170 170
+255 255 255 255 255 255 255 255 255 170 170 170
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0  85  85  85
+255 255 255 255 255 255 170 170 170 170 170 170
+170 170 170 170 170 170 170 170 170 170 170 170
+170 170 170 170 170 170 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0 170 170 170
+255 255 255 255 255 255 170 170 170 170 170 170
+170 170 170 170 170 170 170 170 170 170 170 170
+170 170 170 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+170 170 170   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0  85  85  85 255 255 255
+255 255 255 255 255 255 255 255 255 170 170 170
+170 170 170 170 170 170 170 170 170 170 170 170
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0  85  85  85 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0  85  85  85 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0  85  85  85 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+ 85  85  85 170 170 170 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85 170 170 170 170 170 170 170 170 170
+255 255 255 255 255 255 255 255 255 170 170 170
+170 170 170 170 170 170 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+170 170 170 170 170 170 170 170 170 170 170 170
+170 170 170 170 170 170 170 170 170  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+170 170 170 170 170 170 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+170 170 170 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 170 170 170
+170 170 170 170 170 170 170 170 170  85  85  85
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+170 170 170 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170 170 170 170 170 170 170
+  0   0   0   0   0   0   0   0   0  85  85  85
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85   0   0   0
+ 85  85  85   0   0   0   0   0   0  85  85  85
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 170 170 170
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0 170 170 170
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+170 170 170  85  85  85   0   0   0   0   0   0
+  0   0   0  85  85  85  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0  85  85  85
+  0   0   0   0   0   0  85  85  85 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170   0   0   0  85  85  85
+ 85  85  85   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0  85  85  85
+  0   0   0  85  85  85 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170   0   0   0  85  85  85
+ 85  85  85   0   0   0  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0  85  85  85
+  0   0   0 170 170 170 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0  85  85  85   0   0   0
+  0   0   0 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0  85  85  85   0   0   0
+ 85  85  85 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0  85  85  85   0   0   0   0   0   0
+170 170 170 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0  85  85  85
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0  85  85  85
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85  85  85  85
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255   0   0   0
+ 85  85  85  85  85  85  85  85  85  85  85  85
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85   0   0   0 170  85   0
+255 255  85 170  85   0   0   0   0   0   0   0
+ 85  85  85 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255  85  85  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85  85  85  85   0   0   0
+  0   0   0  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0   0   0   0
+  0   0   0  85  85  85 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255  85 170  85   0 255 255  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85  85  85  85
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+  0   0   0   0   0   0  85  85  85 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255  85
+170  85   0 255 255  85 170  85   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+170  85   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0   0   0   0   0   0   0  85  85  85
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 170  85   0
+255 255  85 170  85   0 255 255  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0 170  85   0
+255 255  85 170  85   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85   0   0   0   0   0   0   0   0   0
+ 85  85  85 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255  85
+170  85   0 255 255  85 170  85   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0 255 255  85
+170  85   0 255 255  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85   0   0   0   0   0   0
+  0   0   0  85  85  85 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0 255 255  85 170  85   0
+255 255  85 170  85   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85   0   0   0
+  0   0   0   0   0   0  85  85  85 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170 170 170 170 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170 170 170 170 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170 170 170 170 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85 170 170 170
+170 170 170 170 170 170 170 170 170 255 255 255
+170 170 170 255 255 255 170 170 170 255 255  85
+170 170 170 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0   0   0   0   0   0   0   0   0   0
+  0   0   0 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170 170 170 170 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255 255 170 170 170
+255 255  85 170 170 170  85  85  85   0   0   0
+  0   0   0  85  85  85 170 170 170  85  85  85
+170 170 170  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0 170 170 170 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255  85 170 170 170 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85 170  85   0 255 255  85 170  85   0
+255 255  85   0   0   0   0   0   0   0   0   0
+ 85  85  85 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170 170 170 170 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170  85   0 255 255  85
+170  85   0 255 255  85 170 170 170 255 255  85
+170  85   0 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255  85  85  85  85  85  85
+ 85  85  85 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+170 170 170 255 255 255 170 170 170 255  85  85
+255  85  85 255  85  85 255  85  85 255  85  85
+255  85  85 255  85  85 255  85  85 255  85  85
+170 170 170 255 255  85 255 255 255 255 255 255
+255 255 255 255 255 255 170 170 170 255 255  85
+170 170 170 255 255 255 255 255 255 255 255 255
+170 170 170 255 255  85 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170  85   0 255 255  85 170 170 170
+255 255 255 255 255 255 255 255 255 170 170 170
+255 255  85 255 255 255 255 255 255 255 255 255
+255 255  85 255 255 255 255  85  85 255  85  85
+255  85  85 255  85  85 170 170 170 170 170 170
+255 255 255 170 170 170 255  85  85 255  85  85
+255  85  85 170 170 170 170 170 170  85  85  85
+  0   0   0   0   0   0   0   0   0 170 170 170
+255 255 255 255  85  85 170   0   0 170   0   0
+170   0   0 170   0   0 170   0   0 170   0   0
+170   0   0 170   0   0 170   0   0 170   0   0
+170 170 170 255 255 255 170 170 170 255 255 255
+255 255 255 170 170 170 255 255 255 170 170 170
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170 255 255 255 255 255 255
+255 255 255 170 170 170 255 255 255 255 255 255
+255 255 255 170 170 170 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170 170 170 170 170 170 170
+170 170 170 170 170 170 170 170 170 255 255 255
+255 255 255 255 255  85 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 170 170 170 170 170 170 170 170 170
+255 255 255 170 170 170 170   0   0 255  85  85
+170   0   0 255  85  85 170 170 170 255 255 255
+170 170 170 170   0   0 170   0   0 170   0   0
+170   0   0 255  85  85 255 255 255  85  85  85
+  0   0   0   0   0   0  85  85  85 255 255 255
+170 170 170 170   0   0 170   0   0 170   0   0
+170   0   0 170   0   0 170   0   0 170   0   0
+170   0   0 170   0   0 170   0   0 170   0   0
+170 170 170 255 255 255 170   0   0 170   0   0
+170   0   0 170   0   0 170 170 170 255 255 255
+255  85  85 170   0   0 170   0   0 170   0   0
+255  85  85 255 255 255 255  85  85 170   0   0
+170   0   0 170   0   0 255  85  85 255  85  85
+170   0   0 170   0   0 170   0   0 170   0   0
+255  85  85 255 255 255 255 255 255 170 170 170
+255  85  85 170   0   0 170   0   0 170   0   0
+170   0   0 170   0   0 170   0   0 170   0   0
+255  85  85 255 255 255 255 255 255 255  85  85
+170   0   0 170   0   0 170   0   0 255  85  85
+255  85  85 170   0   0 170   0   0 255  85  85
+255 255 255 255  85  85 170   0   0 170   0   0
+170   0   0 255  85  85 255 255 255 255 255 255
+170 170 170 170   0   0 170   0   0 170   0   0
+255  85  85 170 170 170 255 255 255  85  85  85
+  0   0   0   0   0   0 170 170 170 255 255 255
+255  85  85 170   0   0 170   0   0 170   0   0
+170   0   0 255  85  85 170 170 170 170 170 170
+170 170 170 255  85  85 255  85  85 170 170 170
+255 255 255 255  85  85 170   0   0 170   0   0
+170   0   0 255  85  85 255 255 255 170 170 170
+170   0   0 170   0   0 170   0   0 170   0   0
+170 170 170 255 255 255 170   0   0 170   0   0
+170   0   0 170   0   0 255  85  85 170   0   0
+170   0   0 170   0   0 170   0   0 170   0   0
+170   0   0 255 255 255 255 255 255 170   0   0
+170   0   0 170   0   0 170   0   0 170   0   0
+255  85  85 170   0   0 170   0   0 170   0   0
+170   0   0 170 170 170 255 255 255 170   0   0
+170   0   0 170   0   0 170   0   0 255  85  85
+170   0   0 170   0   0 170   0   0 255  85  85
+255 255 255 170   0   0 170   0   0 170   0   0
+170   0   0 255  85  85 255 255 255 255 255 255
+255  85  85 170   0   0 170   0   0 170   0   0
+170   0   0 255 255 255 255 255 255   0   0   0
+  0   0   0   0   0   0 170 170 170 255 255 255
+255  85  85 170   0   0 170   0   0 170   0   0
+170   0   0 255  85  85 255  85  85 170 170 170
+170 170 170 170 170 170 255 255 255 255 255 255
+255 255 255 255  85  85 170   0   0 170   0   0
+170   0   0 255  85  85 255 255 255 170 170 170
+170   0   0 170   0   0 170   0   0 170   0   0
+255 255 255 170 170 170 170   0   0 170   0   0
+170   0   0 170   0   0 170   0   0 170   0   0
+170   0   0 170   0   0 170   0   0 170   0   0
+170   0   0 255 255 255 255  85  85 170   0   0
+170   0   0 170   0   0 170   0   0 170 170 170
+255 255 255 170 170 170 170   0   0 170   0   0
+170   0   0 255  85  85 170 170 170 170   0   0
+170   0   0 170   0   0 170   0   0 170   0   0
+170   0   0 170   0   0 170   0   0 170 170 170
+255 255 255 170   0   0 170   0   0 170   0   0
+170   0   0 170   0   0 170   0   0 170   0   0
+170   0   0 170   0   0 170   0   0 170   0   0
+255  85  85 255 255 255 170 170 170   0   0   0
+  0   0   0   0   0   0 170 170 170 255 255 255
+255  85  85 170   0   0 170   0   0 170   0   0
+170   0   0 170   0   0 170   0   0 170   0   0
+170   0   0 170   0   0 255  85  85 255 255 255
+255 255 255 170   0   0 170   0   0 170   0   0
+170   0   0 255  85  85 255 255 255 255  85  85
+170   0   0 170   0   0 170   0   0 255  85  85
+255 255 255 255  85  85 170   0   0 170   0   0
+170   0   0 255  85  85 170 170 170 255 255 255
+170   0   0 170   0   0 170   0   0 170   0   0
+255  85  85 170 170 170 255  85  85 170   0   0
+170   0   0 170   0   0 255  85  85 255  85  85
+255  85  85 255  85  85 170   0   0 170   0   0
+170   0   0 170 170 170 255  85  85 170   0   0
+170   0   0 170   0   0 170   0   0 170   0   0
+170   0   0 170   0   0 255  85  85 255 255 255
+255  85  85 170   0   0 170   0   0 170   0   0
+170   0   0 170   0   0 170   0   0 170   0   0
+170   0   0 170   0   0 170   0   0 170   0   0
+170 170 170 255 255 255  85  85  85   0   0   0
+  0   0   0   0   0   0   0   0   0 255 255 255
+170 170 170 255  85  85 255  85  85 170   0   0
+255  85  85 170   0   0 170   0   0 170   0   0
+170   0   0 170   0   0 170   0   0 255 255 255
+170 170 170 170   0   0 170   0   0 170   0   0
+255  85  85 170 170 170 255 255 255 255  85  85
+170   0   0 170   0   0 170   0   0 255  85  85
+255 255 255 255  85  85 170   0   0 170   0   0
+170   0   0 255  85  85 255 255 255 255 255 255
+255  85  85 170   0   0 170   0   0 170   0   0
+255  85  85 170 170 170 170   0   0 170   0   0
+170   0   0 170   0   0 170   0   0 170   0   0
+170   0   0 170   0   0 170   0   0 170   0   0
+170   0   0 255 255 255 255  85  85 170   0   0
+170   0   0 170   0   0 170   0   0 255  85  85
+170 170 170 255  85  85 170 170 170 255 255 255
+255  85  85 170   0   0 170   0   0 170   0   0
+170   0   0 170   0   0 255  85  85 170   0   0
+170   0   0 170   0   0 170   0   0 170   0   0
+255 255 255 255 255 255   0   0   0   0   0   0
+  0   0   0  85  85  85 170 170 170 170 170 170
+255 255 255 255 255 255 170 170 170 255 255 255
+255 255 255 170 170 170 170   0   0 170   0   0
+170   0   0 170   0   0 170   0   0 255 255 255
+255  85  85 170   0   0 170   0   0 170   0   0
+170   0   0 255 255 255 170 170 170 170   0   0
+170   0   0 170   0   0 170   0   0 170 170 170
+170 170 170 170   0   0 170   0   0 170   0   0
+170   0   0 170 170 170 255 255 255 255  85  85
+170   0   0 170   0   0 170   0   0 170   0   0
+170 170 170 255  85  85 170   0   0 170   0   0
+170   0   0 170   0   0 255 255 255 170 170 170
+255 255 255 255 255 255 170 170 170 255 255 255
+170 170 170 255 255 255 170   0   0 170   0   0
+170   0   0 170   0   0 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 170 170 170
+170   0   0 170   0   0 170   0   0 170   0   0
+170 170 170 255 255 255 255 255 255 255  85  85
+170   0   0 170   0   0 170   0   0 255  85  85
+255 255 255 170 170 170   0   0   0   0   0   0
+  0   0   0 255 255 255 255 255 255 255  85  85
+170   0   0 170   0   0 170   0   0 170   0   0
+170   0   0 170   0   0 170   0   0 170   0   0
+170   0   0 170   0   0 255  85  85 255 255 255
+255  85  85 170   0   0 170   0   0 170   0   0
+170   0   0 170   0   0 170   0   0 170   0   0
+170   0   0 170   0   0 255  85  85 255 255 255
+255  85  85 170   0   0 170   0   0 170   0   0
+170   0   0 170   0   0 255  85  85 170   0   0
+170   0   0 170   0   0 170   0   0 255  85  85
+255 255 255 170 170 170 170   0   0 170   0   0
+170   0   0 170   0   0 255  85  85 255  85  85
+255  85  85 255  85  85 170   0   0 255  85  85
+255 255 255 170 170 170 170   0   0 170   0   0
+170   0   0 170   0   0 255 255 255 255 255 255
+255  85  85 170 170 170 255 255 255 170 170 170
+170   0   0 170   0   0 170   0   0 170   0   0
+170 170 170 170 170 170 255 255 255 170   0   0
+170   0   0 170   0   0 170   0   0 255  85  85
+255 255 255 170 170 170   0   0   0   0   0   0
+ 85  85  85 255 255 255 255  85  85 170   0   0
+170   0   0 170   0   0 170   0   0 170   0   0
+170   0   0 170   0   0 170   0   0 170   0   0
+170   0   0 255  85  85 170 170 170 255 255 255
+255  85  85 170   0   0 170   0   0 170   0   0
+170   0   0 170   0   0 170   0   0 170   0   0
+170   0   0 255  85  85 170 170 170 255 255 255
+255  85  85 170   0   0 170   0   0 170   0   0
+255  85  85 170   0   0 170   0   0 170   0   0
+170   0   0 170   0   0 170   0   0 170 170 170
+255 255 255 170 170 170 255  85  85 170   0   0
+170   0   0 170   0   0 170   0   0 170   0   0
+170   0   0 170   0   0 170   0   0 170 170 170
+255 255 255 255  85  85 170   0   0 170   0   0
+170   0   0 255  85  85 255 255 255 170 170 170
+170  85   0 170 170 170 255 255 255 255  85  85
+170   0   0 170   0   0 170   0   0 255  85  85
+255 255 255 255 255 255 170 170 170 170   0   0
+170   0   0 170   0   0 170   0   0 170 170 170
+255 255 255  85  85  85   0   0   0   0   0   0
+ 85  85  85 170 170 170 170 170 170 170 170 170
+255  85  85 255  85  85 255  85  85 255  85  85
+255  85  85 255  85  85 255  85  85 255  85  85
+255  85  85 255 255 255 170 170 170 170 170 170
+255 255 255 170 170 170 255  85  85 255  85  85
+255  85  85 255  85  85 255  85  85 255  85  85
+255  85  85 255 255 255 255 255 255 255 255 255
+170   0   0 170   0   0 170   0   0 170   0   0
+170 170 170 170 170 170 255  85  85 255  85  85
+255  85  85 255  85  85 170 170 170 255 255 255
+ 85  85  85 170 170 170 255 255 255 255  85  85
+255  85  85 255  85  85 255  85  85 255  85  85
+255  85  85 255  85  85 170 170 170 255 255 255
+170 170 170 255  85  85 170 170 170 255  85  85
+255  85  85 170 170 170 255 255  85 170 170 170
+  0   0   0  85  85  85 170 170 170 255  85  85
+170 170 170 255  85  85 255  85  85 255  85  85
+255 255 255 255  85  85 170 170 170 255  85  85
+170 170 170 255  85  85 170 170 170 255 255 255
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85 170  85   0 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255   0   0   0   0   0   0
+170 170 170 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255 255  85  85
+170   0   0 170   0   0 170   0   0 170   0   0
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255  85  85  85
+  0   0   0  85  85  85 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 255 255 255
+255 255 255 255 255 255 255 255 255  85  85  85
+170 170 170 255 255  85 255 255 255 255 255 255
+255 255 255 255 255 255 255  85  85   0   0   0
+  0   0   0   0   0   0 170 170 170 170 170 170
+255 255 255 255 255 255 255 255 255 255 255 255
+ 85  85  85  85  85  85 170 170 170 255 255 255
+255 255 255 255 255 255 255 255 255 170  85   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85  85  85  85
+170 170 170 170 170 170 170 170 170 170 170 170
+170 170 170 170 170 170 170 170 170 170 170 170
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0  85  85  85 170 170 170 170 170 170
+170 170 170 170 170 170 170 170 170 170 170 170
+ 85  85  85  85  85  85 170 170 170 170 170 170
+255  85  85 255  85  85 255  85  85 255  85  85
+255 255 255 170  85   0 170 170 170 170 170 170
+170 170 170 170 170 170   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0 170 170 170
+170 170 170 170 170 170 170 170 170 170 170 170
+170 170 170  85  85  85 170  85   0   0   0   0
+  0   0   0  85  85  85  85  85  85 170 170 170
+ 85  85  85  85  85  85   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+170 170 170  85  85  85 170 170 170  85  85  85
+  0   0   0   0   0   0  85  85  85  85  85  85
+170 170 170  85  85  85 170 170 170   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  85  85  85 170 170 170
+255 255 255 255 255 255 255 255 255 255 255 255
+ 85  85  85   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  85  85  85
+170 170 170 170 170 170 170 170 170 170 170 170
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
diff --git a/drivers/video/macfb.c b/drivers/video/macfb.c
new file mode 100644
index 0000000..4945a4c
--- /dev/null
+++ b/drivers/video/macfb.c
@@ -0,0 +1,970 @@
+/* macfb.c: Generic framebuffer for Macs whose colourmaps/modes we
+   don't know how to set */
+
+/* (c) 1999 David Huggins-Daines <dhd@debian.org>
+
+   Primarily based on vesafb.c, by Gerd Knorr
+   (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+
+   Also uses information and code from:
+   
+   The original macfb.c from Linux/mac68k 2.0, by Alan Cox, Juergen
+   Mellinger, Mikael Forselius, Michael Schmitz, and others.
+
+   valkyriefb.c, by Martin Costabel, Kevin Schoedel, Barry Nathan, Dan
+   Jacobowitz, Paul Mackerras, Fabio Riccardi, and Geert Uytterhoeven.
+   
+   This code is free software.  You may copy, modify, and distribute
+   it subject to the terms and conditions of the GNU General Public
+   License, version 2, or any later version, at your convenience. */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/nubus.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+
+#include <asm/setup.h>
+#include <asm/bootinfo.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/macintosh.h>
+#include <asm/io.h>
+#include <asm/machw.h>
+
+/* Common DAC base address for the LC, RBV, Valkyrie, and IIvx */
+#define DAC_BASE 0x50f24000
+
+/* Some addresses for the DAFB */
+#define DAFB_BASE 0xf9800200
+
+/* Address for the built-in Civic framebuffer in Quadra AVs */
+#define CIVIC_BASE 0x50f30800	/* Only tested on 660AV! */
+
+/* GSC (Gray Scale Controller) base address */
+#define GSC_BASE 0x50F20000
+
+/* CSC (Color Screen Controller) base address */
+#define CSC_BASE 0x50F20000
+
+static int (*macfb_setpalette) (unsigned int regno, unsigned int red,
+				unsigned int green, unsigned int blue,
+				struct fb_info *info) = NULL;
+static int valkyrie_setpalette (unsigned int regno, unsigned int red,
+				unsigned int green, unsigned int blue,
+				struct fb_info *info);
+static int dafb_setpalette (unsigned int regno, unsigned int red,
+			    unsigned int green, unsigned int blue,
+			    struct fb_info *fb_info);
+static int rbv_setpalette (unsigned int regno, unsigned int red,
+			   unsigned int green, unsigned int blue,
+			   struct fb_info *fb_info);
+static int mdc_setpalette (unsigned int regno, unsigned int red,
+			   unsigned int green, unsigned int blue,
+			   struct fb_info *fb_info);
+static int toby_setpalette (unsigned int regno, unsigned int red,
+			    unsigned int green, unsigned int blue,
+			    struct fb_info *fb_info);
+static int civic_setpalette (unsigned int regno, unsigned int red,
+			     unsigned int green, unsigned int blue,
+			     struct fb_info *fb_info);
+static int csc_setpalette (unsigned int regno, unsigned int red,
+			   unsigned int green, unsigned int blue,
+			   struct fb_info *fb_info);
+
+static volatile struct {
+	unsigned char addr;
+	/* Note: word-aligned */
+	char pad[3];
+	unsigned char lut;
+} *valkyrie_cmap_regs;
+
+static volatile struct {
+	unsigned char addr;
+	unsigned char lut;
+} *v8_brazil_cmap_regs;
+
+static volatile struct {
+	unsigned char addr;
+	char pad1[3]; /* word aligned */
+	unsigned char lut;
+	char pad2[3]; /* word aligned */
+	unsigned char cntl; /* a guess as to purpose */
+} *rbv_cmap_regs;
+
+static volatile struct {
+	unsigned long reset;
+	unsigned long pad1[3];
+	unsigned char pad2[3];
+	unsigned char lut;
+} *dafb_cmap_regs;
+
+static volatile struct {
+	unsigned char addr;	/* OFFSET: 0x00 */
+	unsigned char pad1[15];
+	unsigned char lut;	/* OFFSET: 0x10 */
+	unsigned char pad2[15];
+	unsigned char status;	/* OFFSET: 0x20 */
+	unsigned char pad3[7];
+	unsigned long vbl_addr;	/* OFFSET: 0x28 */
+	unsigned int  status2;	/* OFFSET: 0x2C */
+} *civic_cmap_regs;
+
+static volatile struct {
+	char    pad1[0x40];
+        unsigned char	clut_waddr;	/* 0x40 */
+        char    pad2;
+        unsigned char	clut_data;	/* 0x42 */
+        char	pad3[0x3];
+        unsigned char	clut_raddr;	/* 0x46 */
+} *csc_cmap_regs;
+
+/* We will leave these the way they are for the time being */
+struct mdc_cmap_regs {
+	char pad1[0x200200];
+	unsigned char addr;
+	char pad2[6];
+	unsigned char lut;
+};
+
+struct toby_cmap_regs {
+	char pad1[0x90018];
+	unsigned char lut; /* TFBClutWDataReg, offset 0x90018 */
+	char pad2[3];
+	unsigned char addr; /* TFBClutAddrReg, offset 0x9001C */
+};
+
+struct jet_cmap_regs {
+	char pad1[0xe0e000];
+	unsigned char addr;
+	unsigned char lut;
+};
+
+#define PIXEL_TO_MM(a)	(((a)*10)/28)	/* width in mm at 72 dpi */	
+
+/* mode */
+static int  video_slot = 0;
+
+static struct fb_var_screeninfo macfb_defined = {
+	.bits_per_pixel	= 8,	
+	.activate	= FB_ACTIVATE_NOW,
+	.width		= -1,
+	.height		= -1,
+	.right_margin	= 32,
+	.upper_margin	= 16,
+	.lower_margin	= 4,
+	.vsync_len	= 4,
+	.vmode		= FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_fix_screeninfo macfb_fix = {
+	.id	= "Macintosh ",
+	.type	= FB_TYPE_PACKED_PIXELS,
+	.accel	= FB_ACCEL_NONE,
+};
+
+static struct fb_info fb_info;
+static u32 pseudo_palette[17];
+static int inverse   = 0;
+static int vidtest   = 0;
+
+static int valkyrie_setpalette (unsigned int regno, unsigned int red,
+				unsigned int green, unsigned int blue,
+				struct fb_info *info)
+{
+	unsigned long flags;
+	
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	local_irq_save(flags);
+	
+	/* tell clut which address to fill */
+	nubus_writeb(regno, &valkyrie_cmap_regs->addr);
+	nop();
+
+	/* send one color channel at a time */
+	nubus_writeb(red, &valkyrie_cmap_regs->lut);
+	nop();
+	nubus_writeb(green, &valkyrie_cmap_regs->lut);
+	nop();
+	nubus_writeb(blue, &valkyrie_cmap_regs->lut);
+
+	local_irq_restore(flags);
+	return 0;
+}
+
+/* Unlike the Valkyrie, the DAFB cannot set individual colormap
+   registers.  Therefore, we do what the MacOS driver does (no
+   kidding!) and simply set them one by one until we hit the one we
+   want. */
+static int dafb_setpalette (unsigned int regno, unsigned int red,
+			    unsigned int green, unsigned int blue,
+			    struct fb_info *info)
+{
+	/* FIXME: really, really need to use ioremap() here,
+           phys_to_virt() doesn't work anymore */
+	static int lastreg = -1;
+	unsigned long flags;
+	
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	local_irq_save(flags);
+	
+	/* fbdev will set an entire colourmap, but X won't.  Hopefully
+	   this should accommodate both of them */
+	if (regno != lastreg+1) {
+		int i;
+		
+		/* Stab in the dark trying to reset the CLUT pointer */
+		nubus_writel(0, &dafb_cmap_regs->reset);
+		nop();
+		
+		/* Loop until we get to the register we want */
+		for (i = 0; i < regno; i++) {
+			nubus_writeb(info->cmap.red[i] >> 8, &dafb_cmap_regs->lut);
+			nop();
+			nubus_writeb(info->cmap.green[i] >> 8, &dafb_cmap_regs->lut);
+			nop();
+			nubus_writeb(info->cmap.blue[i] >> 8, &dafb_cmap_regs->lut);
+			nop();
+		}
+	}
+		
+	nubus_writeb(red, &dafb_cmap_regs->lut);
+	nop();
+	nubus_writeb(green, &dafb_cmap_regs->lut);
+	nop();
+	nubus_writeb(blue, &dafb_cmap_regs->lut);
+	
+	local_irq_restore(flags);
+	lastreg = regno;
+	return 0;
+}
+
+/* V8 and Brazil seem to use the same DAC.  Sonora does as well. */
+static int v8_brazil_setpalette (unsigned int regno, unsigned int red,
+				 unsigned int green, unsigned int blue,
+				 struct fb_info *info)	
+{
+	unsigned int bpp = info->var.bits_per_pixel;
+	unsigned char _red  =red>>8;
+	unsigned char _green=green>>8;
+	unsigned char _blue =blue>>8;
+	unsigned char _regno;
+	unsigned long flags;
+
+	if (bpp > 8) return 1; /* failsafe */
+
+	local_irq_save(flags);
+
+	/* On these chips, the CLUT register numbers are spread out
+	   across the register space.  Thus:
+
+	   In 8bpp, all regnos are valid.
+	   
+	   In 4bpp, the regnos are 0x0f, 0x1f, 0x2f, etc, etc
+	   
+	   In 2bpp, the regnos are 0x3f, 0x7f, 0xbf, 0xff */
+  	_regno = (regno << (8 - bpp)) | (0xFF >> bpp);
+	nubus_writeb(_regno, &v8_brazil_cmap_regs->addr); nop();
+
+	/* send one color channel at a time */
+	nubus_writeb(_red, &v8_brazil_cmap_regs->lut); nop();
+	nubus_writeb(_green, &v8_brazil_cmap_regs->lut); nop();
+	nubus_writeb(_blue, &v8_brazil_cmap_regs->lut);
+
+	local_irq_restore(flags);	
+	return 0;
+}
+
+static int rbv_setpalette (unsigned int regno, unsigned int red,
+			   unsigned int green, unsigned int blue,
+			   struct fb_info *info)
+{
+	/* use MSBs */
+	unsigned char _red  =red>>8;
+	unsigned char _green=green>>8;
+	unsigned char _blue =blue>>8;
+	unsigned char _regno;
+	unsigned long flags;
+
+	if (info->var.bits_per_pixel > 8) return 1; /* failsafe */
+
+	local_irq_save(flags);
+	
+	/* From the VideoToolbox driver.  Seems to be saying that
+	 * regno #254 and #255 are the important ones for 1-bit color,
+	 * regno #252-255 are the important ones for 2-bit color, etc.
+	 */
+	_regno = regno + (256-(1 << info->var.bits_per_pixel));
+
+	/* reset clut? (VideoToolbox sez "not necessary") */
+	nubus_writeb(0xFF, &rbv_cmap_regs->cntl); nop();
+	
+	/* tell clut which address to use. */
+	nubus_writeb(_regno, &rbv_cmap_regs->addr); nop();
+	
+	/* send one color channel at a time. */
+	nubus_writeb(_red,   &rbv_cmap_regs->lut); nop();
+	nubus_writeb(_green, &rbv_cmap_regs->lut); nop();
+	nubus_writeb(_blue,  &rbv_cmap_regs->lut);
+	
+	local_irq_restore(flags); /* done. */
+	return 0;
+}
+
+/* Macintosh Display Card (8x24) */
+static int mdc_setpalette(unsigned int regno, unsigned int red,
+			  unsigned int green, unsigned int blue,
+			  struct fb_info *info)
+{
+	volatile struct mdc_cmap_regs *cmap_regs =
+		nubus_slot_addr(video_slot);
+	/* use MSBs */
+	unsigned char _red  =red>>8;
+	unsigned char _green=green>>8;
+	unsigned char _blue =blue>>8;
+	unsigned char _regno=regno;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	
+	/* the nop's are there to order writes. */
+	nubus_writeb(_regno, &cmap_regs->addr); nop();
+	nubus_writeb(_red, &cmap_regs->lut);    nop();
+	nubus_writeb(_green, &cmap_regs->lut);  nop();
+	nubus_writeb(_blue, &cmap_regs->lut);
+
+	local_irq_restore(flags);
+	return 0;
+}
+
+/* Toby frame buffer */
+static int toby_setpalette(unsigned int regno, unsigned int red,
+			   unsigned int green, unsigned int blue,
+			   struct fb_info *info) 
+{
+	volatile struct toby_cmap_regs *cmap_regs =
+		nubus_slot_addr(video_slot);
+	unsigned int bpp = info->var.bits_per_pixel;
+	/* use MSBs */
+	unsigned char _red  =~(red>>8);
+	unsigned char _green=~(green>>8);
+	unsigned char _blue =~(blue>>8);
+	unsigned char _regno = (regno << (8 - bpp)) | (0xFF >> bpp);
+	unsigned long flags;
+
+	local_irq_save(flags);
+		
+	nubus_writeb(_regno, &cmap_regs->addr); nop();
+	nubus_writeb(_red, &cmap_regs->lut);    nop();
+	nubus_writeb(_green, &cmap_regs->lut);  nop();
+	nubus_writeb(_blue, &cmap_regs->lut);
+
+	local_irq_restore(flags);
+	return 0;
+}
+
+/* Jet frame buffer */
+static int jet_setpalette(unsigned int regno, unsigned int red,
+			  unsigned int green, unsigned int blue,
+			  struct fb_info *info)
+{
+	volatile struct jet_cmap_regs *cmap_regs =
+		nubus_slot_addr(video_slot);
+	/* use MSBs */
+	unsigned char _red   = (red>>8);
+	unsigned char _green = (green>>8);
+	unsigned char _blue  = (blue>>8);
+	unsigned long flags;
+
+	local_irq_save(flags);
+	
+	nubus_writeb(regno, &cmap_regs->addr); nop();
+	nubus_writeb(_red, &cmap_regs->lut); nop();
+	nubus_writeb(_green, &cmap_regs->lut); nop();
+	nubus_writeb(_blue, &cmap_regs->lut);
+
+	local_irq_restore(flags);
+	return 0;
+}
+
+/*
+ * Civic framebuffer -- Quadra AV built-in video.  A chip
+ * called Sebastian holds the actual color palettes, and
+ * apparently, there are two different banks of 512K RAM 
+ * which can act as separate framebuffers for doing video
+ * input and viewing the screen at the same time!  The 840AV
+ * Can add another 1MB RAM to give the two framebuffers 
+ * 1MB RAM apiece.
+ *
+ * FIXME: this doesn't seem to work anymore.
+ */
+static int civic_setpalette (unsigned int regno, unsigned int red,
+			     unsigned int green, unsigned int blue,
+			     struct fb_info *info)
+{
+	static int lastreg = -1;
+	unsigned long flags;
+	int clut_status;
+	
+	if (info->var.bits_per_pixel > 8) return 1; /* failsafe */
+
+	red   >>= 8;
+	green >>= 8;
+	blue  >>= 8;
+
+	local_irq_save(flags);
+	
+	/*
+	 * Set the register address
+	 */
+	nubus_writeb(regno, &civic_cmap_regs->addr); nop();
+
+	/*
+	 * Wait for VBL interrupt here;
+	 * They're usually not enabled from Penguin, so we won't check
+	 */
+#if 0
+	{
+#define CIVIC_VBL_OFFSET	0x120
+		volatile unsigned long *vbl = nubus_readl(civic_cmap_regs->vbl_addr + CIVIC_VBL_OFFSET);
+		/* do interrupt setup stuff here? */
+		*vbl = 0L; nop();	/* clear */
+		*vbl = 1L; nop();	/* set */
+		while (*vbl != 0L)	/* wait for next vbl */
+		{
+			usleep(10);	/* needed? */
+		}
+		/* do interrupt shutdown stuff here? */
+	}
+#endif
+
+	/*
+	 * Grab a status word and do some checking;
+	 * Then finally write the clut!
+	 */
+	clut_status =  nubus_readb(&civic_cmap_regs->status2);
+
+	if ((clut_status & 0x0008) == 0)
+	{
+#if 0
+		if ((clut_status & 0x000D) != 0)
+		{
+			nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
+			nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
+		}
+#endif
+
+		nubus_writeb(  red, &civic_cmap_regs->lut); nop();
+		nubus_writeb(green, &civic_cmap_regs->lut); nop();
+		nubus_writeb( blue, &civic_cmap_regs->lut); nop();
+		nubus_writeb( 0x00, &civic_cmap_regs->lut); nop();
+	}
+	else
+	{
+		unsigned char junk;
+
+		junk = nubus_readb(&civic_cmap_regs->lut); nop();
+		junk = nubus_readb(&civic_cmap_regs->lut); nop();
+		junk = nubus_readb(&civic_cmap_regs->lut); nop();
+		junk = nubus_readb(&civic_cmap_regs->lut); nop();
+
+		if ((clut_status & 0x000D) != 0)
+		{
+			nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
+			nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
+		}
+
+		nubus_writeb(  red, &civic_cmap_regs->lut); nop();
+		nubus_writeb(green, &civic_cmap_regs->lut); nop();
+		nubus_writeb( blue, &civic_cmap_regs->lut); nop();
+		nubus_writeb( junk, &civic_cmap_regs->lut); nop();
+	}
+
+	local_irq_restore(flags);
+	lastreg = regno;
+	return 0;
+}
+
+/*
+ * The CSC is the framebuffer on the PowerBook 190 series
+ * (and the 5300 too, but that's a PowerMac). This function
+ * brought to you in part by the ECSC driver for MkLinux.
+ */
+
+static int csc_setpalette (unsigned int regno, unsigned int red,
+			   unsigned int green, unsigned int blue,
+			   struct fb_info *info)
+{
+	mdelay(1);
+	csc_cmap_regs->clut_waddr = regno;
+	csc_cmap_regs->clut_data = red;
+	csc_cmap_regs->clut_data = green;
+	csc_cmap_regs->clut_data = blue;
+	return 0;
+}
+
+static int macfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp,
+			   struct fb_info *fb_info)
+{
+	/*
+	 *  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.
+	 */
+	
+	if (regno >= fb_info->cmap.len)
+		return 1;
+
+	switch (fb_info->var.bits_per_pixel) {
+	case 1:
+		/* We shouldn't get here */
+		break;
+	case 2:
+	case 4:
+	case 8:
+		if (macfb_setpalette)
+			macfb_setpalette(regno, red, green, blue, fb_info);
+		else
+			return 1;
+		break;
+	case 16:
+		if (fb_info->var.red.offset == 10) {
+			/* 1:5:5:5 */
+			((u32*) (fb_info->pseudo_palette))[regno] =
+					((red   & 0xf800) >>  1) |
+					((green & 0xf800) >>  6) |
+					((blue  & 0xf800) >> 11) |
+					((transp != 0) << 15);
+		} else {
+			/* 0:5:6:5 */
+			((u32*) (fb_info->pseudo_palette))[regno] =
+					((red   & 0xf800)      ) |
+					((green & 0xfc00) >>  5) |
+					((blue  & 0xf800) >> 11);
+		}
+		break;	
+		/* I'm pretty sure that one or the other of these
+		   doesn't exist on 68k Macs */
+	case 24:
+		red   >>= 8;
+		green >>= 8;
+		blue  >>= 8;
+		((u32 *)(fb_info->pseudo_palette))[regno] =
+			(red   << fb_info->var.red.offset)   |
+			(green << fb_info->var.green.offset) |
+			(blue  << fb_info->var.blue.offset);
+		break;
+	case 32:
+		red   >>= 8;
+		green >>= 8;
+		blue  >>= 8;
+		((u32 *)(fb_info->pseudo_palette))[regno] =
+			(red   << fb_info->var.red.offset)   |
+			(green << fb_info->var.green.offset) |
+			(blue  << fb_info->var.blue.offset);
+		break;
+    }
+    return 0;
+}
+
+static struct fb_ops macfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_setcolreg	= macfb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+void __init macfb_setup(char *options)
+{
+	char *this_opt;
+	
+	if (!options || !*options)
+		return;
+	
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt) continue;
+		
+		if (! strcmp(this_opt, "inverse"))
+			inverse=1;
+		/* This means "turn on experimental CLUT code" */
+		else if (!strcmp(this_opt, "vidtest"))
+			vidtest=1;
+	}
+}
+
+void __init macfb_init(void)
+{
+	int video_cmap_len, video_is_nubus = 0;
+	struct nubus_dev* ndev = NULL;
+	char *option = NULL;
+
+	if (fb_get_options("macfb", &option))
+		return -ENODEV;
+	macfb_setup(option);
+
+	if (!MACH_IS_MAC) 
+		return;
+
+	/* There can only be one internal video controller anyway so
+	   we're not too worried about this */
+	macfb_defined.xres = mac_bi_data.dimensions & 0xFFFF;
+	macfb_defined.yres = mac_bi_data.dimensions >> 16;
+	macfb_defined.bits_per_pixel = mac_bi_data.videodepth;
+	macfb_fix.line_length = mac_bi_data.videorow;
+	macfb_fix.smem_len = macfb_fix.line_length * macfb_defined.yres;
+	/* Note: physical address (since 2.1.127) */
+	macfb_fix.smem_start = mac_bi_data.videoaddr;
+	/* This is actually redundant with the initial mappings.
+	   However, there are some non-obvious aspects to the way
+	   those mappings are set up, so this is in fact the safest
+	   way to ensure that this driver will work on every possible
+	   Mac */
+	fb_info.screen_base = ioremap(mac_bi_data.videoaddr, macfb_fix.smem_len);
+	
+	printk("macfb: framebuffer at 0x%08lx, mapped to 0x%p, size %dk\n",
+	       macfb_fix.smem_start, fb_info.screen_base, macfb_fix.smem_len/1024);
+	printk("macfb: mode is %dx%dx%d, linelength=%d\n",
+	       macfb_defined.xres, macfb_defined.yres, macfb_defined.bits_per_pixel, macfb_fix.line_length);
+	
+	/*
+	 *	Fill in the available video resolution
+	 */
+	 
+	macfb_defined.xres_virtual   = macfb_defined.xres;
+	macfb_defined.yres_virtual   = macfb_defined.yres;
+	macfb_defined.height = PIXEL_TO_MM(macfb_defined.yres);
+	macfb_defined.width  = PIXEL_TO_MM(macfb_defined.xres);	 
+
+	printk("macfb: scrolling: redraw\n");
+	macfb_defined.yres_virtual = macfb_defined.yres;
+
+	/* some dummy values for timing to make fbset happy */
+	macfb_defined.pixclock     = 10000000 / macfb_defined.xres * 1000 / macfb_defined.yres;
+	macfb_defined.left_margin  = (macfb_defined.xres / 8) & 0xf8;
+	macfb_defined.hsync_len    = (macfb_defined.xres / 8) & 0xf8;
+
+	switch (macfb_defined.bits_per_pixel) {
+	case 1:
+		/* XXX: I think this will catch any program that tries
+		   to do FBIO_PUTCMAP when the visual is monochrome */
+		macfb_defined.red.length = macfb_defined.bits_per_pixel;
+		macfb_defined.green.length = macfb_defined.bits_per_pixel;
+		macfb_defined.blue.length = macfb_defined.bits_per_pixel;
+		video_cmap_len = 0;
+		macfb_fix.visual = FB_VISUAL_MONO01;
+		break;
+	case 2:
+	case 4:
+	case 8:
+		macfb_defined.red.length = macfb_defined.bits_per_pixel;
+		macfb_defined.green.length = macfb_defined.bits_per_pixel;
+		macfb_defined.blue.length = macfb_defined.bits_per_pixel;
+		video_cmap_len = 1 << macfb_defined.bits_per_pixel;
+		macfb_fix.visual = FB_VISUAL_PSEUDOCOLOR;
+		break;
+	case 16:
+		macfb_defined.transp.offset = 15;
+		macfb_defined.transp.length = 1;
+		macfb_defined.red.offset = 10;
+		macfb_defined.red.length = 5;
+		macfb_defined.green.offset = 5;
+		macfb_defined.green.length = 5;
+		macfb_defined.blue.offset = 0;
+		macfb_defined.blue.length = 5;
+		printk("macfb: directcolor: "
+		       "size=1:5:5:5, shift=15:10:5:0\n");
+		video_cmap_len = 16;
+		/* Should actually be FB_VISUAL_DIRECTCOLOR, but this
+		   works too */
+		macfb_fix.visual = FB_VISUAL_TRUECOLOR;
+		break;
+	case 24:
+	case 32:
+		/* XXX: have to test these... can any 68k Macs
+		   actually do this on internal video? */
+		macfb_defined.red.offset = 16;
+		macfb_defined.red.length = 8;
+		macfb_defined.green.offset = 8;
+		macfb_defined.green.length = 8;
+		macfb_defined.blue.offset = 0;
+		macfb_defined.blue.length = 8;
+		printk("macfb: truecolor: "
+		       "size=0:8:8:8, shift=0:16:8:0\n");
+		video_cmap_len = 16;
+		macfb_fix.visual = FB_VISUAL_TRUECOLOR;
+	default:
+		video_cmap_len = 0;
+		macfb_fix.visual = FB_VISUAL_MONO01;
+		printk("macfb: unknown or unsupported bit depth: %d\n", macfb_defined.bits_per_pixel);
+		break;
+	}
+	
+	/* Hardware dependent stuff */
+	/*  We take a wild guess that if the video physical address is
+	 *  in nubus slot space, that the nubus card is driving video.
+	 *  Penguin really ought to tell us whether we are using internal
+	 *  video or not.
+	 */
+	/* Hopefully we only find one of them.  Otherwise our NuBus
+           code is really broken :-) */
+
+	while ((ndev = nubus_find_type(NUBUS_CAT_DISPLAY, NUBUS_TYPE_VIDEO, ndev))
+		!= NULL)
+	{
+		if (!(mac_bi_data.videoaddr >= ndev->board->slot_addr
+		      && (mac_bi_data.videoaddr <
+			  (unsigned long)nubus_slot_addr(ndev->board->slot+1))))
+			continue;
+		video_is_nubus = 1;
+		/* We should probably just use the slot address... */
+		video_slot = ndev->board->slot;
+
+		switch(ndev->dr_hw) {
+		case NUBUS_DRHW_APPLE_MDC:
+			strcat( macfb_fix.id, "Display Card" );
+			macfb_setpalette = mdc_setpalette;
+			macfb_defined.activate = FB_ACTIVATE_NOW;
+			break;
+		case NUBUS_DRHW_APPLE_TFB:
+			strcat( macfb_fix.id, "Toby" );
+			macfb_setpalette = toby_setpalette;
+			macfb_defined.activate = FB_ACTIVATE_NOW;
+			break;
+		case NUBUS_DRHW_APPLE_JET:
+			strcat( macfb_fix.id, "Jet");
+			macfb_setpalette = jet_setpalette;
+			macfb_defined.activate = FB_ACTIVATE_NOW;
+			break;			
+		default:
+			strcat( macfb_fix.id, "Generic NuBus" );
+			break;
+		}
+	}
+
+	/* If it's not a NuBus card, it must be internal video */
+	/* FIXME: this function is getting way too big.  (this driver
+           is too...) */
+	if (!video_is_nubus)
+		switch( mac_bi_data.id )
+		{
+			/* These don't have onboard video.  Eventually, we may
+			   be able to write separate framebuffer drivers for
+			   them (tobyfb.c, hiresfb.c, etc, etc) */
+		case MAC_MODEL_II:
+		case MAC_MODEL_IIX:
+		case MAC_MODEL_IICX:
+		case MAC_MODEL_IIFX:
+			strcat( macfb_fix.id, "Generic NuBus" );
+			break;
+
+			/* Valkyrie Quadras */
+		case MAC_MODEL_Q630:
+			/* I'm not sure about this one */
+		case MAC_MODEL_P588:
+			strcat( macfb_fix.id, "Valkyrie built-in" );
+			macfb_setpalette = valkyrie_setpalette;
+			macfb_defined.activate = FB_ACTIVATE_NOW;
+			valkyrie_cmap_regs = ioremap(DAC_BASE, 0x1000);
+			break;
+
+			/* DAFB Quadras */
+			/* Note: these first four have the v7 DAFB, which is
+			   known to be rather unlike the ones used in the
+			   other models */
+		case MAC_MODEL_P475:
+		case MAC_MODEL_P475F:
+		case MAC_MODEL_P575:
+		case MAC_MODEL_Q605:
+	
+		case MAC_MODEL_Q800:
+		case MAC_MODEL_Q650:
+		case MAC_MODEL_Q610:
+		case MAC_MODEL_C650:
+		case MAC_MODEL_C610:
+		case MAC_MODEL_Q700:
+		case MAC_MODEL_Q900:
+		case MAC_MODEL_Q950:
+			strcat( macfb_fix.id, "DAFB built-in" );
+			macfb_setpalette = dafb_setpalette;
+			macfb_defined.activate = FB_ACTIVATE_NOW;
+			dafb_cmap_regs = ioremap(DAFB_BASE, 0x1000);
+			break;
+
+			/* LC II uses the V8 framebuffer */
+		case MAC_MODEL_LCII:
+			strcat( macfb_fix.id, "V8 built-in" );
+			macfb_setpalette = v8_brazil_setpalette;
+			macfb_defined.activate = FB_ACTIVATE_NOW;
+			v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
+			break;
+		
+			/* IIvi, IIvx use the "Brazil" framebuffer (which is
+			   very much like the V8, it seems, and probably uses
+			   the same DAC) */
+		case MAC_MODEL_IIVI:
+		case MAC_MODEL_IIVX:
+		case MAC_MODEL_P600:
+			strcat( macfb_fix.id, "Brazil built-in" );
+			macfb_setpalette = v8_brazil_setpalette;
+			macfb_defined.activate = FB_ACTIVATE_NOW;
+			v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
+			break;
+		
+			/* LC III (and friends) use the Sonora framebuffer */
+			/* Incidentally this is also used in the non-AV models
+			   of the x100 PowerMacs */
+			/* These do in fact seem to use the same DAC interface
+			   as the LC II. */
+		case MAC_MODEL_LCIII:
+		case MAC_MODEL_P520:
+		case MAC_MODEL_P550:
+		case MAC_MODEL_P460:
+			macfb_setpalette = v8_brazil_setpalette;
+			macfb_defined.activate = FB_ACTIVATE_NOW;
+			strcat( macfb_fix.id, "Sonora built-in" );
+			v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
+			break;
+
+			/* IIci and IIsi use the infamous RBV chip
+                           (the IIsi is just a rebadged and crippled
+                           IIci in a different case, BTW) */
+		case MAC_MODEL_IICI:
+		case MAC_MODEL_IISI:
+			macfb_setpalette = rbv_setpalette;
+			macfb_defined.activate = FB_ACTIVATE_NOW;
+			strcat( macfb_fix.id, "RBV built-in" );
+			rbv_cmap_regs = ioremap(DAC_BASE, 0x1000);
+			break;
+
+			/* AVs use the Civic framebuffer */
+		case MAC_MODEL_Q840:
+		case MAC_MODEL_C660:
+			macfb_setpalette = civic_setpalette;
+			macfb_defined.activate = FB_ACTIVATE_NOW;
+			strcat( macfb_fix.id, "Civic built-in" );
+			civic_cmap_regs = ioremap(CIVIC_BASE, 0x1000);
+			break;
+
+		
+			/* Write a setpalette function for your machine, then
+			   you can add something similar here.  These are
+			   grouped by classes of video chipsets.  Some of this
+			   information is from the VideoToolbox "Bugs" web
+			   page at
+			   http://rajsky.psych.nyu.edu/Tips/VideoBugs.html */
+
+			/* Assorted weirdos */
+			/* We think this may be like the LC II */
+		case MAC_MODEL_LC:
+			if (vidtest) {
+				macfb_setpalette = v8_brazil_setpalette;
+				macfb_defined.activate = FB_ACTIVATE_NOW;
+				v8_brazil_cmap_regs =
+					ioremap(DAC_BASE, 0x1000);
+			}
+			strcat( macfb_fix.id, "LC built-in" );
+			break;
+			/* We think this may be like the LC II */
+		case MAC_MODEL_CCL:
+			if (vidtest) {
+				macfb_setpalette = v8_brazil_setpalette;
+				macfb_defined.activate = FB_ACTIVATE_NOW;
+				v8_brazil_cmap_regs =
+					ioremap(DAC_BASE, 0x1000);
+			}
+			strcat( macfb_fix.id, "Color Classic built-in" );
+			break;
+
+			/* And we *do* mean "weirdos" */
+		case MAC_MODEL_TV:
+			strcat( macfb_fix.id, "Mac TV built-in" );
+			break;
+
+			/* These don't have colour, so no need to worry */
+		case MAC_MODEL_SE30:
+		case MAC_MODEL_CLII:
+			strcat( macfb_fix.id, "Monochrome built-in" );
+			break;
+
+			/* Powerbooks are particularly difficult.  Many of
+			   them have separate framebuffers for external and
+			   internal video, which is admittedly pretty cool,
+			   but will be a bit of a headache to support here.
+			   Also, many of them are grayscale, and we don't
+			   really support that. */
+
+		case MAC_MODEL_PB140:
+		case MAC_MODEL_PB145:
+		case MAC_MODEL_PB170:
+			strcat( macfb_fix.id, "DDC built-in" );
+			break;
+
+			/* Internal is GSC, External (if present) is ViSC */
+		case MAC_MODEL_PB150:	/* no external video */
+		case MAC_MODEL_PB160:
+		case MAC_MODEL_PB165:
+		case MAC_MODEL_PB180:
+		case MAC_MODEL_PB210:
+		case MAC_MODEL_PB230:
+			strcat( macfb_fix.id, "GSC built-in" );
+			break;
+
+			/* Internal is TIM, External is ViSC */
+		case MAC_MODEL_PB165C:
+		case MAC_MODEL_PB180C:
+			strcat( macfb_fix.id, "TIM built-in" );
+			break;
+
+			/* Internal is CSC, External is Keystone+Ariel. */
+		case MAC_MODEL_PB190:	/* external video is optional */
+		case MAC_MODEL_PB520:
+		case MAC_MODEL_PB250:
+		case MAC_MODEL_PB270C:
+		case MAC_MODEL_PB280:
+		case MAC_MODEL_PB280C:
+			macfb_setpalette = csc_setpalette;
+			macfb_defined.activate = FB_ACTIVATE_NOW;
+			strcat( macfb_fix.id, "CSC built-in" );
+			csc_cmap_regs = ioremap(CSC_BASE, 0x1000);
+			break;
+		
+		default:
+			strcat( macfb_fix.id, "Unknown/Unsupported built-in" );
+			break;
+		}
+
+	fb_info.fbops		= &macfb_ops;
+	fb_info.var		= macfb_defined;
+	fb_info.fix		= macfb_fix;
+	fb_info.pseudo_palette	= pseudo_palette;
+	fb_info.flags		= FBINFO_DEFAULT;
+
+	fb_alloc_cmap(&fb_info.cmap, video_cmap_len, 0);
+	
+	if (register_framebuffer(&fb_info) < 0)
+		return;
+
+	printk("fb%d: %s frame buffer device\n",
+	       fb_info.node, fb_info.fix.id);
+}
+
+module_init(macfb_init);
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/macmodes.c b/drivers/video/macmodes.c
new file mode 100644
index 0000000..de5a0f3
--- /dev/null
+++ b/drivers/video/macmodes.c
@@ -0,0 +1,389 @@
+/*
+ *  linux/drivers/video/macmodes.c -- Standard MacOS video modes
+ *
+ *	Copyright (C) 1998 Geert Uytterhoeven
+ *
+ *      2000 - Removal of OpenFirmware dependencies by:
+ *      - Ani Joshi
+ *      - Brad Douglas <brad@neruo.com>
+ *
+ *	2001 - Documented with DocBook
+ *	- Brad Douglas <brad@neruo.com>
+ *
+ *  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/errno.h>
+#include <linux/fb.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+#include "macmodes.h"
+
+    /*
+     *  MacOS video mode definitions
+     *
+     *  Order IS important! If you change these, don't forget to update
+     *  mac_modes[] below!
+     */
+
+#define DEFAULT_MODEDB_INDEX	0
+
+static const struct fb_videomode mac_modedb[] = {
+    {
+	/* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
+	"mac5", 60, 640, 480, 39722, 32, 32, 33, 10, 96, 2,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 640x480, 67Hz, Non-Interlaced (30.0 MHz dotclock) */
+	"mac6", 67, 640, 480, 33334, 80, 80, 39, 3, 64, 3,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 800x600, 56 Hz, Non-Interlaced (36.00 MHz dotclock) */
+	"mac9", 56, 800, 600, 27778, 112, 40, 22, 1, 72, 2,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }, {
+	/* 800x600, 60 Hz, Non-Interlaced (40.00 MHz dotclock) */
+	"mac10", 60, 800, 600, 25000, 72, 56, 23, 1, 128, 4,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }, {
+	/* 800x600, 72 Hz, Non-Interlaced (50.00 MHz dotclock) */
+	"mac11", 72, 800, 600, 20000, 48, 72, 23, 37, 120, 6,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }, {
+	/* 800x600, 75 Hz, Non-Interlaced (49.50 MHz dotclock) */
+	"mac12", 75, 800, 600, 20203, 144, 32, 21, 1, 80, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }, {
+	/* 832x624, 75Hz, Non-Interlaced (57.6 MHz dotclock) */
+	"mac13", 75, 832, 624, 17362, 208, 48, 39, 1, 64, 3,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1024x768, 60 Hz, Non-Interlaced (65.00 MHz dotclock) */
+	"mac14", 60, 1024, 768, 15385, 144, 40, 29, 3, 136, 6,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1024x768, 72 Hz, Non-Interlaced (75.00 MHz dotclock) */
+	"mac15", 72, 1024, 768, 13334, 128, 40, 29, 3, 136, 6,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */
+	"mac16", 75, 1024, 768, 12699, 176, 16, 28, 1, 96, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */
+	"mac17", 75, 1024, 768, 12699, 160, 32, 28, 1, 96, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1152x870, 75 Hz, Non-Interlaced (100.0 MHz dotclock) */
+	"mac18", 75, 1152, 870, 10000, 128, 48, 39, 3, 128, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1280x960, 75 Hz, Non-Interlaced (126.00 MHz dotclock) */
+	"mac19", 75, 1280, 960, 7937, 224, 32, 36, 1, 144, 3,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) */
+	"mac20", 75, 1280, 1024, 7408, 232, 64, 38, 1, 112, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1152x768, 60 Hz, Titanium PowerBook */
+	"mac21", 60, 1152, 768, 15386, 158, 26, 29, 3, 136, 6,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1600x1024, 60 Hz, Non-Interlaced (112.27 MHz dotclock) */
+	"mac22", 60, 1600, 1024, 8908, 88, 104, 1, 10, 16, 1,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }
+
+#if 0
+    /* Anyone who has timings for these? */
+    {
+	/* VMODE_512_384_60I: 512x384, 60Hz, Interlaced (NTSC) */
+	"mac1", 60, 512, 384, pixclock, left, right, upper, lower, hslen, vslen,
+	sync, FB_VMODE_INTERLACED
+    }, {
+	/* VMODE_512_384_60: 512x384, 60Hz, Non-Interlaced */
+    	"mac2", 60, 512, 384, pixclock, left, right, upper, lower, hslen, vslen,
+	sync, FB_VMODE_NONINTERLACED
+    }, {
+	/* VMODE_640_480_50I: 640x480, 50Hz, Interlaced (PAL) */
+	"mac3", 50, 640, 480, pixclock, left, right, upper, lower, hslen, vslen,
+	sync, FB_VMODE_INTERLACED
+    }, {
+	/* VMODE_640_480_60I: 640x480, 60Hz, Interlaced (NTSC) */
+	"mac4", 60, 640, 480, pixclock, left, right, upper, lower, hslen, vslen,
+	sync, FB_VMODE_INTERLACED
+    }, {
+	/* VMODE_640_870_75P: 640x870, 75Hz (portrait), Non-Interlaced */
+	"mac7", 75, 640, 870, pixclock, left, right, upper, lower, hslen, vslen,
+	sync, FB_VMODE_NONINTERLACED
+    }, {
+	/* VMODE_768_576_50I: 768x576, 50Hz (PAL full frame), Interlaced */
+	"mac8", 50, 768, 576, pixclock, left, right, upper, lower, hslen, vslen,
+	sync, FB_VMODE_INTERLACED
+    },
+#endif
+};
+
+
+    /*
+     *  Mapping between MacOS video mode numbers and video mode definitions
+     *
+     *  These MUST be ordered in
+     *    - increasing resolution
+     *    - decreasing refresh rate
+     */
+
+static const struct mode_map {
+    int vmode;
+    const struct fb_videomode *mode;
+} mac_modes[] = {
+    /* 640x480 */
+    { VMODE_640_480_67, &mac_modedb[1] },
+    { VMODE_640_480_60, &mac_modedb[0] },
+    /* 800x600 */
+    { VMODE_800_600_75, &mac_modedb[5] },
+    { VMODE_800_600_72, &mac_modedb[4] },
+    { VMODE_800_600_60, &mac_modedb[3] },
+    { VMODE_800_600_56, &mac_modedb[2] },
+    /* 832x624 */
+    { VMODE_832_624_75, &mac_modedb[6] },
+    /* 1024x768 */
+    { VMODE_1024_768_75, &mac_modedb[10] },
+    { VMODE_1024_768_75V, &mac_modedb[9] },
+    { VMODE_1024_768_70, &mac_modedb[8] },
+    { VMODE_1024_768_60, &mac_modedb[7] },
+    /* 1152x768 */
+    { VMODE_1152_768_60, &mac_modedb[14] },
+    /* 1152x870 */
+    { VMODE_1152_870_75, &mac_modedb[11] },
+    /* 1280x960 */
+    { VMODE_1280_960_75, &mac_modedb[12] },
+    /* 1280x1024 */
+    { VMODE_1280_1024_75, &mac_modedb[13] },
+    /* 1600x1024 */
+    { VMODE_1600_1024_60, &mac_modedb[15] },
+    { -1, NULL }
+};
+
+
+    /*
+     *  Mapping between monitor sense values and MacOS video mode numbers
+     */
+
+static const struct monitor_map {
+    int sense;
+    int vmode;
+} mac_monitors[] = {
+    { 0x000, VMODE_1280_1024_75 },	/* 21" RGB */
+    { 0x114, VMODE_640_870_75P },	/* Portrait Monochrome */
+    { 0x221, VMODE_512_384_60 },	/* 12" RGB*/
+    { 0x331, VMODE_1280_1024_75 },	/* 21" RGB (Radius) */
+    { 0x334, VMODE_1280_1024_75 },	/* 21" mono (Radius) */
+    { 0x335, VMODE_1280_1024_75 },	/* 21" mono */
+    { 0x40A, VMODE_640_480_60I },	/* NTSC */
+    { 0x51E, VMODE_640_870_75P },	/* Portrait RGB */
+    { 0x603, VMODE_832_624_75 },	/* 12"-16" multiscan */
+    { 0x60b, VMODE_1024_768_70 },	/* 13"-19" multiscan */
+    { 0x623, VMODE_1152_870_75 },	/* 13"-21" multiscan */
+    { 0x62b, VMODE_640_480_67 },	/* 13"/14" RGB */
+    { 0x700, VMODE_640_480_50I },	/* PAL */
+    { 0x714, VMODE_640_480_60I },	/* NTSC */
+    { 0x717, VMODE_800_600_75 },	/* VGA */
+    { 0x72d, VMODE_832_624_75 },	/* 16" RGB (Goldfish) */
+    { 0x730, VMODE_768_576_50I },	/* PAL (Alternate) */
+    { 0x73a, VMODE_1152_870_75 },	/* 3rd party 19" */
+    { 0x73f, VMODE_640_480_67 },	/* no sense lines connected at all */
+    { 0xBEEF, VMODE_1600_1024_60 },	/* 22" Apple Cinema Display */
+    { -1,    VMODE_640_480_60 },	/* catch-all, must be last */
+};
+
+/**
+ *	mac_vmode_to_var - converts vmode/cmode pair to var structure
+ *	@vmode: MacOS video mode
+ *	@cmode: MacOS color mode
+ *	@var: frame buffer video mode structure
+ *
+ *	Converts a MacOS vmode/cmode pair to a frame buffer video
+ *	mode structure.
+ *
+ *	Returns negative errno on error, or zero for success.
+ *
+ */
+
+int mac_vmode_to_var(int vmode, int cmode, struct fb_var_screeninfo *var)
+{
+    const struct fb_videomode *mode = NULL;
+    const struct mode_map *map;
+
+    for (map = mac_modes; map->vmode != -1; map++)
+	if (map->vmode == vmode) {
+	    mode = map->mode;
+	    break;
+	}
+    if (!mode)
+	return -EINVAL;
+
+    memset(var, 0, sizeof(struct fb_var_screeninfo));
+    switch (cmode) {
+	case CMODE_8:
+	    var->bits_per_pixel = 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;
+	    break;
+
+	case CMODE_16:
+	    var->bits_per_pixel = 16;
+	    var->red.offset = 10;
+	    var->red.length = 5;
+	    var->green.offset = 5;
+	    var->green.length = 5;
+	    var->blue.offset = 0;
+	    var->blue.length = 5;
+	    break;
+
+	case CMODE_32:
+	    var->bits_per_pixel = 32;
+	    var->red.offset = 16;
+	    var->red.length = 8;
+	    var->green.offset = 8;
+	    var->green.length = 8;
+	    var->blue.offset = 0;
+	    var->blue.length = 8;
+	    var->transp.offset = 24;
+	    var->transp.length = 8;
+	    break;
+
+	default:
+	    return -EINVAL;
+    }
+    var->xres = mode->xres;
+    var->yres = mode->yres;
+    var->xres_virtual = mode->xres;
+    var->yres_virtual = mode->yres;
+    var->height = -1;
+    var->width = -1;
+    var->pixclock = mode->pixclock;
+    var->left_margin = mode->left_margin;
+    var->right_margin = mode->right_margin;
+    var->upper_margin = mode->upper_margin;
+    var->lower_margin = mode->lower_margin;
+    var->hsync_len = mode->hsync_len;
+    var->vsync_len = mode->vsync_len;
+    var->sync = mode->sync;
+    var->vmode = mode->vmode;
+    return 0;
+}
+EXPORT_SYMBOL(mac_vmode_to_var);
+
+/**
+ *	mac_var_to_vmode - convert var structure to MacOS vmode/cmode pair
+ *	@var: frame buffer video mode structure
+ *	@vmode: MacOS video mode
+ *	@cmode: MacOS color mode
+ *
+ *	Converts a frame buffer video mode structure to a MacOS
+ *	vmode/cmode pair.
+ *
+ *	Returns negative errno on error, or zero for success.
+ *
+ */
+
+int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode,
+		     int *cmode)
+{
+    const struct fb_videomode *mode = NULL;
+    const struct mode_map *map;
+
+    if (var->bits_per_pixel <= 8)
+	*cmode = CMODE_8;
+    else if (var->bits_per_pixel <= 16)
+	*cmode = CMODE_16;
+    else if (var->bits_per_pixel <= 32)
+	*cmode = CMODE_32;
+    else
+	return -EINVAL;
+
+    for (map = mac_modes; map->vmode != -1; map++) {
+	mode = map->mode;
+	if (var->xres > mode->xres || var->yres > mode->yres)
+	    continue;
+	if (var->xres_virtual > mode->xres || var->yres_virtual > mode->yres)
+	    continue;
+	if (var->pixclock > mode->pixclock)
+	    continue;
+	if ((var->vmode & FB_VMODE_MASK) != mode->vmode)
+	    continue;
+	*vmode = map->vmode;
+	return 0;
+    }
+    return -EINVAL;
+}
+EXPORT_SYMBOL(mac_var_to_vmode);
+
+/**
+ *	mac_map_monitor_sense - Convert monitor sense to vmode
+ *	@sense: Macintosh monitor sense number
+ *
+ *	Converts a Macintosh monitor sense number to a MacOS
+ *	vmode number.
+ *
+ *	Returns MacOS vmode video mode number.
+ *
+ */
+
+int mac_map_monitor_sense(int sense)
+{
+    const struct monitor_map *map;
+
+    for (map = mac_monitors; map->sense != -1; map++)
+	if (map->sense == sense)
+	    break;
+    return map->vmode;
+}
+EXPORT_SYMBOL(mac_map_monitor_sense);
+
+/**
+ *	mac_find_mode - find a video mode
+ *	@var: frame buffer user defined part of display
+ *	@info: frame buffer info structure
+ *	@mode_option: video mode name (see mac_modedb[])
+ *	@default_bpp: default color depth in bits per pixel
+ *
+ *	Finds a suitable video mode.  Tries to set mode specified
+ *	by @mode_option.  If the name of the wanted mode begins with
+ *	'mac', the Mac video mode database will be used, otherwise it
+ *	will fall back to the standard video mode database.
+ *
+ *	Note: Function marked as __init and can only be used during
+ *	system boot.
+ *
+ *	Returns error code from fb_find_mode (see fb_find_mode
+ *	function).
+ *
+ */
+
+int __init mac_find_mode(struct fb_var_screeninfo *var, struct fb_info *info,
+			 const char *mode_option, unsigned int default_bpp)
+{
+    const struct fb_videomode *db = NULL;
+    unsigned int dbsize = 0;
+
+    if (mode_option && !strncmp(mode_option, "mac", 3)) {
+	mode_option += 3;
+	db = mac_modedb;
+	dbsize = sizeof(mac_modedb)/sizeof(*mac_modedb);
+    }
+    return fb_find_mode(var, info, mode_option, db, dbsize,
+			&mac_modedb[DEFAULT_MODEDB_INDEX], default_bpp);
+}
+EXPORT_SYMBOL(mac_find_mode);
+
diff --git a/drivers/video/macmodes.h b/drivers/video/macmodes.h
new file mode 100644
index 0000000..232f5a09
--- /dev/null
+++ b/drivers/video/macmodes.h
@@ -0,0 +1,70 @@
+/*
+ *  linux/drivers/video/macmodes.h -- Standard MacOS video modes
+ *
+ *	Copyright (C) 1998 Geert Uytterhoeven
+ *
+ *  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 _VIDEO_MACMODES_H
+#define _VIDEO_MACMODES_H
+
+    /*
+     *  Video mode values.
+     *  These are supposed to be the same as the values that Apple uses in
+     *  MacOS.
+     */
+
+#define VMODE_NVRAM		0
+#define VMODE_512_384_60I	1	/* 512x384, 60Hz interlaced (NTSC) */
+#define VMODE_512_384_60	2	/* 512x384, 60Hz */
+#define VMODE_640_480_50I	3	/* 640x480, 50Hz interlaced (PAL) */
+#define VMODE_640_480_60I	4	/* 640x480, 60Hz interlaced (NTSC) */
+#define VMODE_640_480_60	5	/* 640x480, 60Hz (VGA) */
+#define VMODE_640_480_67	6	/* 640x480, 67Hz */
+#define VMODE_640_870_75P	7	/* 640x870, 75Hz (portrait) */
+#define VMODE_768_576_50I	8	/* 768x576, 50Hz (PAL full frame) */
+#define VMODE_800_600_56	9	/* 800x600, 56Hz */
+#define VMODE_800_600_60	10	/* 800x600, 60Hz */
+#define VMODE_800_600_72	11	/* 800x600, 72Hz */
+#define VMODE_800_600_75	12	/* 800x600, 75Hz */
+#define VMODE_832_624_75	13	/* 832x624, 75Hz */
+#define VMODE_1024_768_60	14	/* 1024x768, 60Hz */
+#define VMODE_1024_768_70	15	/* 1024x768, 70Hz (or 72Hz?) */
+#define VMODE_1024_768_75V	16	/* 1024x768, 75Hz (VESA) */
+#define VMODE_1024_768_75	17	/* 1024x768, 75Hz */
+#define VMODE_1152_870_75	18	/* 1152x870, 75Hz */
+#define VMODE_1280_960_75	19	/* 1280x960, 75Hz */
+#define VMODE_1280_1024_75	20	/* 1280x1024, 75Hz */
+#define VMODE_1152_768_60	21	/* 1152x768, 60Hz     Titanium PowerBook */
+#define VMODE_1600_1024_60	22	/* 1600x1024, 60Hz 22" Cinema Display */
+#define VMODE_MAX		22
+#define VMODE_CHOOSE		99
+
+#define CMODE_NVRAM		-1
+#define CMODE_CHOOSE		-2
+#define CMODE_8			0	/* 8 bits/pixel */
+#define CMODE_16		1	/* 16 (actually 15) bits/pixel */
+#define CMODE_32		2	/* 32 (actually 24) bits/pixel */
+
+
+extern int mac_vmode_to_var(int vmode, int cmode,
+			    struct fb_var_screeninfo *var);
+extern int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode,
+			    int *cmode);
+extern int mac_map_monitor_sense(int sense);
+extern int __init mac_find_mode(struct fb_var_screeninfo *var,
+				struct fb_info *info, const char *mode_option,
+				unsigned int default_bpp);
+
+
+    /*
+     *  Addresses in NVRAM where video mode and pixel size are stored.
+     */
+
+#define NV_VMODE		0x140f
+#define NV_CMODE		0x1410
+
+#endif /* _VIDEO_MACMODES_H */
diff --git a/drivers/video/matrox/Makefile b/drivers/video/matrox/Makefile
new file mode 100644
index 0000000..f9c00eb
--- /dev/null
+++ b/drivers/video/matrox/Makefile
@@ -0,0 +1,11 @@
+# Makefile for the Linux video drivers.
+# 5 Aug 1999, James Simmons, <mailto:jsimmons@edgeglobal.com>
+# Rewritten to use lists instead of if-statements.
+
+# Each configuration option enables a list of files.
+
+my-obj-$(CONFIG_FB_MATROX_G)      += g450_pll.o matroxfb_g450.o matroxfb_crtc2.o
+
+obj-$(CONFIG_FB_MATROX)           += matroxfb_base.o matroxfb_accel.o matroxfb_DAC1064.o matroxfb_Ti3026.o matroxfb_misc.o $(my-obj-y)
+obj-$(CONFIG_FB_MATROX_I2C)       += i2c-matroxfb.o
+obj-$(CONFIG_FB_MATROX_MAVEN)     += matroxfb_maven.o matroxfb_crtc2.o
diff --git a/drivers/video/matrox/g450_pll.c b/drivers/video/matrox/g450_pll.c
new file mode 100644
index 0000000..8073a73
--- /dev/null
+++ b/drivers/video/matrox/g450_pll.c
@@ -0,0 +1,479 @@
+/*
+ *
+ * Hardware accelerated Matrox PCI cards - G450/G550 PLL control.
+ *
+ * (c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Portions Copyright (c) 2001 Matrox Graphics Inc.
+ *
+ * Version: 1.64 2002/06/10
+ *
+ * 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 "g450_pll.h"
+#include "matroxfb_DAC1064.h"
+
+static inline unsigned int g450_vco2f(unsigned char p, unsigned int fvco) {
+	return (p & 0x40) ? fvco : fvco >> ((p & 3) + 1);
+}
+
+static inline unsigned int g450_f2vco(unsigned char p, unsigned int fin) {
+	return (p & 0x40) ? fin : fin << ((p & 3) + 1);
+}
+
+static unsigned int g450_mnp2vco(CPMINFO unsigned int mnp) {
+	unsigned int m, n;
+
+	m = ((mnp >> 16) & 0x0FF) + 1;
+	n = ((mnp >>  7) & 0x1FE) + 4;
+	return (ACCESS_FBINFO(features).pll.ref_freq * n + (m >> 1)) / m;
+}
+
+unsigned int g450_mnp2f(CPMINFO unsigned int mnp) {
+	return g450_vco2f(mnp, g450_mnp2vco(PMINFO mnp));
+}
+
+static inline unsigned int pll_freq_delta(unsigned int f1, unsigned int f2) {
+	if (f2 < f1) {
+    		f2 = f1 - f2;
+	} else {
+		f2 = f2 - f1;
+	}
+	return f2;
+}
+
+#define NO_MORE_MNP	0x01FFFFFF
+#define G450_MNP_FREQBITS	(0xFFFFFF43)	/* do not mask high byte so we'll catch NO_MORE_MNP */
+
+static unsigned int g450_nextpll(CPMINFO const struct matrox_pll_limits* pi, unsigned int* fvco, unsigned int mnp) {
+	unsigned int m, n, p;
+	unsigned int tvco = *fvco;
+
+	m = (mnp >> 16) & 0xFF;
+	p = mnp & 0xFF;
+
+	do {
+		if (m == 0 || m == 0xFF) {
+			if (m == 0) {
+				if (p & 0x40) {
+					return NO_MORE_MNP;
+				}
+			        if (p & 3) {
+					p--;
+				} else {
+					p = 0x40;
+				}
+				tvco >>= 1;
+				if (tvco < pi->vcomin) {
+					return NO_MORE_MNP;
+				}
+				*fvco = tvco;
+			}
+
+			p &= 0x43;
+			if (tvco < 550000) {
+/*				p |= 0x00; */
+			} else if (tvco < 700000) {
+				p |= 0x08;
+			} else if (tvco < 1000000) {
+				p |= 0x10;
+			} else if (tvco < 1150000) {
+				p |= 0x18;
+			} else {
+				p |= 0x20;
+			}
+			m = 9;
+		} else {
+			m--;
+		}
+        	n = ((tvco * (m+1) + ACCESS_FBINFO(features).pll.ref_freq) / (ACCESS_FBINFO(features).pll.ref_freq * 2)) - 2;
+	} while (n < 0x03 || n > 0x7A);
+	return (m << 16) | (n << 8) | p;
+}
+
+static unsigned int g450_firstpll(CPMINFO const struct matrox_pll_limits* pi, unsigned int* vco, unsigned int fout) {
+	unsigned int p;
+	unsigned int vcomax;
+
+	vcomax = pi->vcomax;
+	if (fout > (vcomax / 2)) {
+		if (fout > vcomax) {
+			*vco = vcomax;
+		} else {
+			*vco = fout;
+		}
+		p = 0x40;
+	} else {
+		unsigned int tvco;
+
+		p = 3;
+		tvco = g450_f2vco(p, fout);
+		while (p && (tvco > vcomax)) {
+			p--;
+			tvco >>= 1;
+		}
+		if (tvco < pi->vcomin) {
+			tvco = pi->vcomin;
+		}
+		*vco = tvco;
+	}
+	return g450_nextpll(PMINFO pi, vco, 0xFF0000 | p);
+}
+
+static inline unsigned int g450_setpll(CPMINFO unsigned int mnp, unsigned int pll) {
+	switch (pll) {
+		case M_PIXEL_PLL_A:
+			matroxfb_DAC_out(PMINFO M1064_XPIXPLLAM, mnp >> 16);
+			matroxfb_DAC_out(PMINFO M1064_XPIXPLLAN, mnp >> 8);
+			matroxfb_DAC_out(PMINFO M1064_XPIXPLLAP, mnp);
+			return M1064_XPIXPLLSTAT;
+
+		case M_PIXEL_PLL_B:
+			matroxfb_DAC_out(PMINFO M1064_XPIXPLLBM, mnp >> 16);
+			matroxfb_DAC_out(PMINFO M1064_XPIXPLLBN, mnp >> 8);
+			matroxfb_DAC_out(PMINFO M1064_XPIXPLLBP, mnp);
+			return M1064_XPIXPLLSTAT;
+
+		case M_PIXEL_PLL_C:
+			matroxfb_DAC_out(PMINFO M1064_XPIXPLLCM, mnp >> 16);
+			matroxfb_DAC_out(PMINFO M1064_XPIXPLLCN, mnp >> 8);
+			matroxfb_DAC_out(PMINFO M1064_XPIXPLLCP, mnp);
+			return M1064_XPIXPLLSTAT;
+
+		case M_SYSTEM_PLL:
+			matroxfb_DAC_out(PMINFO DAC1064_XSYSPLLM, mnp >> 16);
+			matroxfb_DAC_out(PMINFO DAC1064_XSYSPLLN, mnp >> 8);
+			matroxfb_DAC_out(PMINFO DAC1064_XSYSPLLP, mnp);
+			return DAC1064_XSYSPLLSTAT;
+
+		case M_VIDEO_PLL:
+			matroxfb_DAC_out(PMINFO M1064_XVIDPLLM, mnp >> 16);
+			matroxfb_DAC_out(PMINFO M1064_XVIDPLLN, mnp >> 8);
+			matroxfb_DAC_out(PMINFO M1064_XVIDPLLP, mnp);
+			return M1064_XVIDPLLSTAT;
+	}
+	return 0;
+}
+
+static inline unsigned int g450_cmppll(CPMINFO unsigned int mnp, unsigned int pll) {
+	unsigned char m = mnp >> 16;
+	unsigned char n = mnp >> 8;
+	unsigned char p = mnp;
+
+	switch (pll) {
+		case M_PIXEL_PLL_A:
+			return (matroxfb_DAC_in(PMINFO M1064_XPIXPLLAM) != m ||
+				matroxfb_DAC_in(PMINFO M1064_XPIXPLLAN) != n ||
+				matroxfb_DAC_in(PMINFO M1064_XPIXPLLAP) != p);
+
+		case M_PIXEL_PLL_B:
+			return (matroxfb_DAC_in(PMINFO M1064_XPIXPLLBM) != m ||
+				matroxfb_DAC_in(PMINFO M1064_XPIXPLLBN) != n ||
+				matroxfb_DAC_in(PMINFO M1064_XPIXPLLBP) != p);
+
+		case M_PIXEL_PLL_C:
+			return (matroxfb_DAC_in(PMINFO M1064_XPIXPLLCM) != m ||
+				matroxfb_DAC_in(PMINFO M1064_XPIXPLLCN) != n ||
+				matroxfb_DAC_in(PMINFO M1064_XPIXPLLCP) != p);
+
+		case M_SYSTEM_PLL:
+			return (matroxfb_DAC_in(PMINFO DAC1064_XSYSPLLM) != m ||
+				matroxfb_DAC_in(PMINFO DAC1064_XSYSPLLN) != n ||
+				matroxfb_DAC_in(PMINFO DAC1064_XSYSPLLP) != p);
+
+		case M_VIDEO_PLL:
+			return (matroxfb_DAC_in(PMINFO M1064_XVIDPLLM) != m ||
+				matroxfb_DAC_in(PMINFO M1064_XVIDPLLN) != n ||
+				matroxfb_DAC_in(PMINFO M1064_XVIDPLLP) != p);
+	}
+	return 1;
+}
+
+static inline int g450_isplllocked(CPMINFO unsigned int regidx) {
+	unsigned int j;
+
+	for (j = 0; j < 1000; j++) {
+		if (matroxfb_DAC_in(PMINFO regidx) & 0x40) {
+			unsigned int r = 0;
+			int i;
+
+			for (i = 0; i < 100; i++) {
+				r += matroxfb_DAC_in(PMINFO regidx) & 0x40;
+			}
+			return r >= (90 * 0x40);
+		}
+		/* udelay(1)... but DAC_in is much slower... */
+	}
+	return 0;
+}
+
+static int g450_testpll(CPMINFO unsigned int mnp, unsigned int pll) {
+	return g450_isplllocked(PMINFO g450_setpll(PMINFO mnp, pll));
+}
+
+static void updatehwstate_clk(struct matrox_hw_state* hw, unsigned int mnp, unsigned int pll) {
+	switch (pll) {
+		case M_SYSTEM_PLL:
+			hw->DACclk[3] = mnp >> 16;
+			hw->DACclk[4] = mnp >> 8;
+			hw->DACclk[5] = mnp;
+			break;
+	}
+}
+
+void matroxfb_g450_setpll_cond(WPMINFO unsigned int mnp, unsigned int pll) {
+	if (g450_cmppll(PMINFO mnp, pll)) {
+		g450_setpll(PMINFO mnp, pll);
+	}
+}
+
+static inline unsigned int g450_findworkingpll(WPMINFO unsigned int pll, unsigned int* mnparray, unsigned int mnpcount) {
+	unsigned int found = 0;
+	unsigned int idx;
+	unsigned int mnpfound = mnparray[0];
+		
+	for (idx = 0; idx < mnpcount; idx++) {
+		unsigned int sarray[3];
+		unsigned int *sptr;
+		{
+			unsigned int mnp;
+		
+			sptr = sarray;
+			mnp = mnparray[idx];
+			if (mnp & 0x38) {
+				*sptr++ = mnp - 8;
+			}
+			if ((mnp & 0x38) != 0x38) {
+				*sptr++ = mnp + 8;
+			}
+			*sptr = mnp;
+		}
+		while (sptr >= sarray) {
+			unsigned int mnp = *sptr--;
+		
+			if (g450_testpll(PMINFO mnp - 0x0300, pll) &&
+			    g450_testpll(PMINFO mnp + 0x0300, pll) &&
+			    g450_testpll(PMINFO mnp - 0x0200, pll) &&
+			    g450_testpll(PMINFO mnp + 0x0200, pll) &&
+			    g450_testpll(PMINFO mnp - 0x0100, pll) &&
+			    g450_testpll(PMINFO mnp + 0x0100, pll)) {
+				if (g450_testpll(PMINFO mnp, pll)) {
+					return mnp;
+				}
+			} else if (!found && g450_testpll(PMINFO mnp, pll)) {
+				mnpfound = mnp;
+				found = 1;
+			}
+		}
+	}
+	g450_setpll(PMINFO mnpfound, pll);
+	return mnpfound;
+}
+
+static void g450_addcache(struct matrox_pll_cache* ci, unsigned int mnp_key, unsigned int mnp_value) {
+	if (++ci->valid > ARRAY_SIZE(ci->data)) {
+		ci->valid = ARRAY_SIZE(ci->data);
+	}
+	memmove(ci->data + 1, ci->data, (ci->valid - 1) * sizeof(*ci->data));
+	ci->data[0].mnp_key = mnp_key & G450_MNP_FREQBITS;
+	ci->data[0].mnp_value = mnp_value;
+}
+
+static int g450_checkcache(WPMINFO struct matrox_pll_cache* ci, unsigned int mnp_key) {
+	unsigned int i;
+	
+	mnp_key &= G450_MNP_FREQBITS;
+	for (i = 0; i < ci->valid; i++) {
+		if (ci->data[i].mnp_key == mnp_key) {
+			unsigned int mnp;
+			
+			mnp = ci->data[i].mnp_value;
+			if (i) {
+				memmove(ci->data + 1, ci->data, i * sizeof(*ci->data));
+				ci->data[0].mnp_key = mnp_key;
+				ci->data[0].mnp_value = mnp;
+			}
+			return mnp;
+		}
+	}
+	return NO_MORE_MNP;
+}
+
+static int __g450_setclk(WPMINFO unsigned int fout, unsigned int pll, 
+		unsigned int* mnparray, unsigned int* deltaarray) {
+	unsigned int mnpcount;
+	unsigned int pixel_vco;
+	const struct matrox_pll_limits* pi;
+	struct matrox_pll_cache* ci;
+
+	pixel_vco = 0;
+	switch (pll) {
+		case M_PIXEL_PLL_A:
+		case M_PIXEL_PLL_B:
+		case M_PIXEL_PLL_C:
+			{
+				u_int8_t tmp;
+				unsigned long flags;
+				
+				matroxfb_DAC_lock_irqsave(flags);
+				tmp = matroxfb_DAC_in(PMINFO M1064_XPIXCLKCTRL);
+				if (!(tmp & M1064_XPIXCLKCTRL_PLL_UP)) {
+					matroxfb_DAC_out(PMINFO M1064_XPIXCLKCTRL, tmp | M1064_XPIXCLKCTRL_PLL_UP);
+				}
+				matroxfb_DAC_unlock_irqrestore(flags);
+			}
+			{
+				u_int8_t misc;
+		
+				misc = mga_inb(M_MISC_REG_READ) & ~0x0C;
+				switch (pll) {
+					case M_PIXEL_PLL_A:
+						break;
+					case M_PIXEL_PLL_B:
+						misc |=  0x04;
+						break;
+					default:
+						misc |=  0x0C;
+						break;
+				}
+				mga_outb(M_MISC_REG, misc);
+			}
+			pi = &ACCESS_FBINFO(limits.pixel);
+			ci = &ACCESS_FBINFO(cache.pixel);
+			break;
+		case M_SYSTEM_PLL:
+			{
+				u_int32_t opt;
+
+				pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, &opt);
+				if (!(opt & 0x20)) {
+					pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, opt | 0x20);
+				}
+			}
+			pi = &ACCESS_FBINFO(limits.system);
+			ci = &ACCESS_FBINFO(cache.system);
+			break;
+		case M_VIDEO_PLL:
+			{
+				u_int8_t tmp;
+				unsigned int mnp;
+				unsigned long flags;
+				
+				matroxfb_DAC_lock_irqsave(flags);
+				tmp = matroxfb_DAC_in(PMINFO M1064_XPWRCTRL);
+				if (!(tmp & 2)) {
+					matroxfb_DAC_out(PMINFO M1064_XPWRCTRL, tmp | 2);
+				}
+				
+				mnp = matroxfb_DAC_in(PMINFO M1064_XPIXPLLCM) << 16;
+				mnp |= matroxfb_DAC_in(PMINFO M1064_XPIXPLLCN) << 8;
+				pixel_vco = g450_mnp2vco(PMINFO mnp);
+				matroxfb_DAC_unlock_irqrestore(flags);
+			}
+			pi = &ACCESS_FBINFO(limits.video);
+			ci = &ACCESS_FBINFO(cache.video);
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	mnpcount = 0;
+	{
+		unsigned int mnp;
+		unsigned int xvco;
+
+		for(mnp = g450_firstpll(PMINFO pi, &xvco, fout); mnp != NO_MORE_MNP; mnp = g450_nextpll(PMINFO pi, &xvco, mnp)) {
+			unsigned int idx;
+			unsigned int vco;
+			unsigned int delta;
+
+			vco = g450_mnp2vco(PMINFO mnp);
+#if 0			
+			if (pll == M_VIDEO_PLL) {
+				unsigned int big, small;
+
+				if (vco < pixel_vco) {
+					small = vco;
+					big = pixel_vco;
+				} else {
+					small = pixel_vco;
+					big = vco;
+				}
+				while (big > small) {
+					big >>= 1;
+				}
+				if (big == small) {
+					continue;
+				}
+			}
+#endif			
+			delta = pll_freq_delta(fout, g450_vco2f(mnp, vco));
+			for (idx = mnpcount; idx > 0; idx--) {
+				/* == is important; due to nextpll algorithm we get
+				   sorted equally good frequencies from lower VCO 
+				   frequency to higher - with <= lowest wins, while
+				   with < highest one wins */
+				if (delta <= deltaarray[idx-1]) {
+					mnparray[idx] = mnparray[idx-1];
+					deltaarray[idx] = deltaarray[idx-1];
+				} else {
+					break;
+				}
+			}
+			mnparray[idx] = mnp;
+			deltaarray[idx] = delta;
+			mnpcount++;
+		}
+	}
+	/* VideoPLL and PixelPLL matched: do nothing... In all other cases we should get at least one frequency */
+	if (!mnpcount) {
+		return -EBUSY;
+	}
+	{
+		unsigned long flags;
+		unsigned int mnp;
+		
+		matroxfb_DAC_lock_irqsave(flags);
+		mnp = g450_checkcache(PMINFO ci, mnparray[0]);
+		if (mnp != NO_MORE_MNP) {
+			matroxfb_g450_setpll_cond(PMINFO mnp, pll);
+		} else {
+			mnp = g450_findworkingpll(PMINFO pll, mnparray, mnpcount);
+			g450_addcache(ci, mnparray[0], mnp);
+		}
+		updatehwstate_clk(&ACCESS_FBINFO(hw), mnp, pll);
+		matroxfb_DAC_unlock_irqrestore(flags);
+		return mnp;
+	}
+}
+
+/* It must be greater than number of possible PLL values.
+ * Currently there is 5(p) * 10(m) = 50 possible values. */
+#define MNP_TABLE_SIZE  64
+
+int matroxfb_g450_setclk(WPMINFO unsigned int fout, unsigned int pll) {
+	unsigned int* arr;
+	
+	arr = kmalloc(sizeof(*arr) * MNP_TABLE_SIZE * 2, GFP_KERNEL);
+	if (arr) {
+		int r;
+
+		r = __g450_setclk(PMINFO fout, pll, arr, arr + MNP_TABLE_SIZE);
+		kfree(arr);
+		return r;
+	}
+	return -ENOMEM;
+}
+
+EXPORT_SYMBOL(matroxfb_g450_setclk);
+EXPORT_SYMBOL(g450_mnp2f);
+EXPORT_SYMBOL(matroxfb_g450_setpll_cond);
+
+MODULE_AUTHOR("(c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Matrox G450/G550 PLL driver");
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/matrox/g450_pll.h b/drivers/video/matrox/g450_pll.h
new file mode 100644
index 0000000..c17ed74
--- /dev/null
+++ b/drivers/video/matrox/g450_pll.h
@@ -0,0 +1,10 @@
+#ifndef __G450_PLL_H__
+#define __G450_PLL_H__
+
+#include "matroxfb_base.h"
+
+int matroxfb_g450_setclk(WPMINFO unsigned int fout, unsigned int pll);
+unsigned int g450_mnp2f(CPMINFO unsigned int mnp);
+void matroxfb_g450_setpll_cond(WPMINFO unsigned int mnp, unsigned int pll);
+
+#endif	/* __G450_PLL_H__ */
diff --git a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c
new file mode 100644
index 0000000..57abbae
--- /dev/null
+++ b/drivers/video/matrox/i2c-matroxfb.c
@@ -0,0 +1,223 @@
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
+ *
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Version: 1.64 2002/06/10
+ *
+ * See matroxfb_base.c for contributors.
+ *
+ */
+
+#include "matroxfb_base.h"
+#include "matroxfb_maven.h"
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+/* MGA-TVO I2C for G200, G400 */
+#define MAT_CLK		0x20
+#define MAT_DATA	0x10
+/* primary head DDC for Mystique(?), G100, G200, G400 */
+#define DDC1_CLK	0x08
+#define DDC1_DATA	0x02
+/* primary head DDC for Millennium, Millennium II */
+#define DDC1B_CLK	0x10
+#define DDC1B_DATA	0x04
+/* secondary head DDC for G400 */
+#define DDC2_CLK	0x04
+#define DDC2_DATA	0x01
+
+/******************************************************/
+
+struct matroxfb_dh_maven_info {
+	struct i2c_bit_adapter	maven;
+	struct i2c_bit_adapter	ddc1;
+	struct i2c_bit_adapter	ddc2;
+};
+
+static int matroxfb_read_gpio(struct matrox_fb_info* minfo) {
+	unsigned long flags;
+	int v;
+
+	matroxfb_DAC_lock_irqsave(flags);
+	v = matroxfb_DAC_in(PMINFO DAC_XGENIODATA);
+	matroxfb_DAC_unlock_irqrestore(flags);
+	return v;
+}
+
+static void matroxfb_set_gpio(struct matrox_fb_info* minfo, int mask, int val) {
+	unsigned long flags;
+	int v;
+
+	matroxfb_DAC_lock_irqsave(flags);
+	v = (matroxfb_DAC_in(PMINFO DAC_XGENIOCTRL) & mask) | val;
+	matroxfb_DAC_out(PMINFO DAC_XGENIOCTRL, v);
+	/* We must reset GENIODATA very often... XFree plays with this register */
+	matroxfb_DAC_out(PMINFO DAC_XGENIODATA, 0x00);
+	matroxfb_DAC_unlock_irqrestore(flags);
+}
+
+/* software I2C functions */
+static inline void matroxfb_i2c_set(struct matrox_fb_info* minfo, int mask, int state) {
+	if (state)
+		state = 0;
+	else
+		state = mask;
+	matroxfb_set_gpio(minfo, ~mask, state);
+}
+
+static void matroxfb_gpio_setsda(void* data, int state) {
+	struct i2c_bit_adapter* b = data;
+	matroxfb_i2c_set(b->minfo, b->mask.data, state);
+}
+
+static void matroxfb_gpio_setscl(void* data, int state) {
+	struct i2c_bit_adapter* b = data;
+	matroxfb_i2c_set(b->minfo, b->mask.clock, state);
+}
+
+static int matroxfb_gpio_getsda(void* data) {
+	struct i2c_bit_adapter* b = data;
+	return (matroxfb_read_gpio(b->minfo) & b->mask.data) ? 1 : 0;
+}
+
+static int matroxfb_gpio_getscl(void* data) {
+	struct i2c_bit_adapter* b = data;
+	return (matroxfb_read_gpio(b->minfo) & b->mask.clock) ? 1 : 0;
+}
+
+static struct i2c_adapter matrox_i2c_adapter_template =
+{
+	.owner =	THIS_MODULE,
+	.id =		I2C_HW_B_G400,
+};
+
+static struct i2c_algo_bit_data matrox_i2c_algo_template =
+{
+	NULL,
+	matroxfb_gpio_setsda,
+	matroxfb_gpio_setscl,
+	matroxfb_gpio_getsda,
+	matroxfb_gpio_getscl,
+	10, 10, 100,
+};
+
+static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo, 
+		unsigned int data, unsigned int clock, const char* name) {
+	int err;
+
+	b->minfo = minfo;
+	b->mask.data = data;
+	b->mask.clock = clock;
+	b->adapter = matrox_i2c_adapter_template;
+	snprintf(b->adapter.name, I2C_NAME_SIZE, name,
+		minfo->fbcon.node);
+	i2c_set_adapdata(&b->adapter, b);
+	b->adapter.algo_data = &b->bac;
+	b->bac = matrox_i2c_algo_template;
+	b->bac.data = b;
+	err = i2c_bit_add_bus(&b->adapter);
+	b->initialized = !err;
+	return err;
+}
+
+static void i2c_bit_bus_del(struct i2c_bit_adapter* b) {
+	if (b->initialized) {
+		i2c_bit_del_bus(&b->adapter);
+		b->initialized = 0;
+	}
+}
+
+static inline void i2c_maven_done(struct matroxfb_dh_maven_info* minfo2) {
+	i2c_bit_bus_del(&minfo2->maven);
+}
+
+static inline void i2c_ddc1_done(struct matroxfb_dh_maven_info* minfo2) {
+	i2c_bit_bus_del(&minfo2->ddc1);
+}
+
+static inline void i2c_ddc2_done(struct matroxfb_dh_maven_info* minfo2) {
+	i2c_bit_bus_del(&minfo2->ddc2);
+}
+
+static void* i2c_matroxfb_probe(struct matrox_fb_info* minfo) {
+	int err;
+	unsigned long flags;
+	struct matroxfb_dh_maven_info* m2info;
+
+	m2info = (struct matroxfb_dh_maven_info*)kmalloc(sizeof(*m2info), GFP_KERNEL);
+	if (!m2info)
+		return NULL;
+
+	matroxfb_DAC_lock_irqsave(flags);
+	matroxfb_DAC_out(PMINFO DAC_XGENIODATA, 0xFF);
+	matroxfb_DAC_out(PMINFO DAC_XGENIOCTRL, 0x00);
+	matroxfb_DAC_unlock_irqrestore(flags);
+
+	memset(m2info, 0, sizeof(*m2info));
+
+	switch (ACCESS_FBINFO(chip)) {
+		case MGA_2064:
+		case MGA_2164:
+			err = i2c_bus_reg(&m2info->ddc1, minfo, DDC1B_DATA, DDC1B_CLK, "DDC:fb%u #0");
+			break;
+		default:
+			err = i2c_bus_reg(&m2info->ddc1, minfo, DDC1_DATA, DDC1_CLK, "DDC:fb%u #0");
+			break;
+	}
+	if (err)
+		goto fail_ddc1;
+	if (ACCESS_FBINFO(devflags.dualhead)) {
+		err = i2c_bus_reg(&m2info->ddc2, minfo, DDC2_DATA, DDC2_CLK, "DDC:fb%u #1");
+		if (err == -ENODEV) {
+			printk(KERN_INFO "i2c-matroxfb: VGA->TV plug detected, DDC unavailable.\n");
+		} else if (err)
+			printk(KERN_INFO "i2c-matroxfb: Could not register secondary output i2c bus. Continuing anyway.\n");
+		/* Register maven bus even on G450/G550 */
+		err = i2c_bus_reg(&m2info->maven, minfo, MAT_DATA, MAT_CLK, "MAVEN:fb%u");
+		if (err)
+			printk(KERN_INFO "i2c-matroxfb: Could not register Maven i2c bus. Continuing anyway.\n");
+	}
+	return m2info;
+fail_ddc1:;
+	kfree(m2info);
+	printk(KERN_ERR "i2c-matroxfb: Could not register primary adapter DDC bus.\n");
+	return NULL;
+}
+
+static void i2c_matroxfb_remove(struct matrox_fb_info* minfo, void* data) {
+	struct matroxfb_dh_maven_info* m2info = data;
+
+	i2c_maven_done(m2info);
+	i2c_ddc2_done(m2info);
+	i2c_ddc1_done(m2info);
+	kfree(m2info);
+}
+
+static struct matroxfb_driver i2c_matroxfb = {
+	.node =		LIST_HEAD_INIT(i2c_matroxfb.node),
+	.name =		"i2c-matroxfb",
+	.probe = 	i2c_matroxfb_probe,
+	.remove =	i2c_matroxfb_remove,
+};
+
+static int __init i2c_matroxfb_init(void) {
+	if (matroxfb_register_driver(&i2c_matroxfb)) {
+		printk(KERN_ERR "i2c-matroxfb: failed to register driver\n");
+		return -ENXIO;
+	}
+	return 0;
+}
+
+static void __exit i2c_matroxfb_exit(void) {
+	matroxfb_unregister_driver(&i2c_matroxfb);
+}
+
+MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Support module providing I2C buses present on Matrox videocards");
+
+module_init(i2c_matroxfb_init);
+module_exit(i2c_matroxfb_exit);
+/* no __setup required */
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/matrox/matroxfb_DAC1064.c b/drivers/video/matrox/matroxfb_DAC1064.c
new file mode 100644
index 0000000..149680f
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_DAC1064.c
@@ -0,0 +1,1086 @@
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
+ *
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Portions Copyright (c) 2001 Matrox Graphics Inc.
+ *
+ * Version: 1.65 2002/08/14
+ *
+ * See matroxfb_base.c for contributors.
+ *
+ */
+
+/* make checkconfig does not walk through include tree :-( */
+#include <linux/config.h>
+
+#include "matroxfb_DAC1064.h"
+#include "matroxfb_misc.h"
+#include "matroxfb_accel.h"
+#include "g450_pll.h"
+#include <linux/matroxfb.h>
+
+#ifdef NEED_DAC1064
+#define outDAC1064 matroxfb_DAC_out
+#define inDAC1064 matroxfb_DAC_in
+
+#define DAC1064_OPT_SCLK_PCI	0x00
+#define DAC1064_OPT_SCLK_PLL	0x01
+#define DAC1064_OPT_SCLK_EXT	0x02
+#define DAC1064_OPT_SCLK_MASK	0x03
+#define DAC1064_OPT_GDIV1	0x04	/* maybe it is GDIV2 on G100 ?! */
+#define DAC1064_OPT_GDIV3	0x00
+#define DAC1064_OPT_MDIV1	0x08
+#define DAC1064_OPT_MDIV2	0x00
+#define DAC1064_OPT_RESERVED	0x10
+
+static void DAC1064_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsigned int* in, unsigned int* feed, unsigned int* post) {
+	unsigned int fvco;
+	unsigned int p;
+
+	DBG(__FUNCTION__)
+	
+	/* only for devices older than G450 */
+
+	fvco = PLL_calcclock(PMINFO freq, fmax, in, feed, &p);
+	
+	p = (1 << p) - 1;
+	if (fvco <= 100000)
+		;
+	else if (fvco <= 140000)
+		p |= 0x08;
+	else if (fvco <= 180000)
+		p |= 0x10;
+	else
+		p |= 0x18;
+	*post = p;
+}
+
+/* they must be in POS order */
+static const unsigned char MGA1064_DAC_regs[] = {
+		M1064_XCURADDL, M1064_XCURADDH, M1064_XCURCTRL,
+		M1064_XCURCOL0RED, M1064_XCURCOL0GREEN, M1064_XCURCOL0BLUE,
+		M1064_XCURCOL1RED, M1064_XCURCOL1GREEN, M1064_XCURCOL1BLUE,
+		M1064_XCURCOL2RED, M1064_XCURCOL2GREEN, M1064_XCURCOL2BLUE,
+		DAC1064_XVREFCTRL, M1064_XMULCTRL, M1064_XPIXCLKCTRL, M1064_XGENCTRL,
+		M1064_XMISCCTRL,
+		M1064_XGENIOCTRL, M1064_XGENIODATA, M1064_XZOOMCTRL, M1064_XSENSETEST,
+		M1064_XCRCBITSEL,
+		M1064_XCOLKEYMASKL, M1064_XCOLKEYMASKH, M1064_XCOLKEYL, M1064_XCOLKEYH };
+
+static const unsigned char MGA1064_DAC[] = {
+		0x00, 0x00, M1064_XCURCTRL_DIS,
+		0x00, 0x00, 0x00, 	/* black */
+		0xFF, 0xFF, 0xFF,	/* white */
+		0xFF, 0x00, 0x00,	/* red */
+		0x00, 0,
+		M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL,
+		M1064_XGENCTRL_VS_0 | M1064_XGENCTRL_ALPHA_DIS | M1064_XGENCTRL_BLACK_0IRE | M1064_XGENCTRL_NO_SYNC_ON_GREEN,
+		M1064_XMISCCTRL_DAC_8BIT,
+		0x00, 0x00, M1064_XZOOMCTRL_1, M1064_XSENSETEST_BCOMP | M1064_XSENSETEST_GCOMP | M1064_XSENSETEST_RCOMP | M1064_XSENSETEST_PDOWN,
+		0x00,
+		0x00, 0x00, 0xFF, 0xFF};
+
+static void DAC1064_setpclk(WPMINFO unsigned long fout) {
+	unsigned int m, n, p;
+
+	DBG(__FUNCTION__)
+
+	DAC1064_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
+	ACCESS_FBINFO(hw).DACclk[0] = m;
+	ACCESS_FBINFO(hw).DACclk[1] = n;
+	ACCESS_FBINFO(hw).DACclk[2] = p;
+}
+
+static void DAC1064_setmclk(WPMINFO int oscinfo, unsigned long fmem) {
+	u_int32_t mx;
+	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
+
+	DBG(__FUNCTION__)
+
+	if (ACCESS_FBINFO(devflags.noinit)) {
+		/* read MCLK and give up... */
+		hw->DACclk[3] = inDAC1064(PMINFO DAC1064_XSYSPLLM);
+		hw->DACclk[4] = inDAC1064(PMINFO DAC1064_XSYSPLLN);
+		hw->DACclk[5] = inDAC1064(PMINFO DAC1064_XSYSPLLP);
+		return;
+	}
+	mx = hw->MXoptionReg | 0x00000004;
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
+	mx &= ~0x000000BB;
+	if (oscinfo & DAC1064_OPT_GDIV1)
+		mx |= 0x00000008;
+	if (oscinfo & DAC1064_OPT_MDIV1)
+		mx |= 0x00000010;
+	if (oscinfo & DAC1064_OPT_RESERVED)
+		mx |= 0x00000080;
+	if ((oscinfo & DAC1064_OPT_SCLK_MASK) == DAC1064_OPT_SCLK_PLL) {
+		/* select PCI clock until we have setup oscilator... */
+		int clk;
+		unsigned int m, n, p;
+
+		/* powerup system PLL, select PCI clock */
+		mx |= 0x00000020;
+		pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
+		mx &= ~0x00000004;
+		pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
+
+		/* !!! you must not access device if MCLK is not running !!!
+		   Doing so cause immediate PCI lockup :-( Maybe they should
+		   generate ABORT or I/O (parity...) error and Linux should
+		   recover from this... (kill driver/process). But world is not
+		   perfect... */
+		/* (bit 2 of PCI_OPTION_REG must be 0... and bits 0,1 must not
+		   select PLL... because of PLL can be stopped at this time) */
+		DAC1064_calcclock(PMINFO fmem, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
+		outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3] = m);
+		outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4] = n);
+		outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5] = p);
+		for (clk = 65536; clk; --clk) {
+			if (inDAC1064(PMINFO DAC1064_XSYSPLLSTAT) & 0x40)
+				break;
+		}
+		if (!clk)
+			printk(KERN_ERR "matroxfb: aiee, SYSPLL not locked\n");
+		/* select PLL */
+		mx |= 0x00000005;
+	} else {
+		/* select specified system clock source */
+		mx |= oscinfo & DAC1064_OPT_SCLK_MASK;
+	}
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
+	mx &= ~0x00000004;
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
+	hw->MXoptionReg = mx;
+}
+
+#ifdef CONFIG_FB_MATROX_G
+static void g450_set_plls(WPMINFO2) {
+	u_int32_t c2_ctl;
+	unsigned int pxc;
+	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
+	int pixelmnp;
+	int videomnp;
+	
+	c2_ctl = hw->crtc2.ctl & ~0x4007;	/* Clear PLL + enable for CRTC2 */
+	c2_ctl |= 0x0001;			/* Enable CRTC2 */
+	hw->DACreg[POS1064_XPWRCTRL] &= ~0x02;	/* Stop VIDEO PLL */
+	pixelmnp = ACCESS_FBINFO(crtc1).mnp;
+	videomnp = ACCESS_FBINFO(crtc2).mnp;
+	if (videomnp < 0) {
+		c2_ctl &= ~0x0001;			/* Disable CRTC2 */
+		hw->DACreg[POS1064_XPWRCTRL] &= ~0x10;	/* Powerdown CRTC2 */
+	} else if (ACCESS_FBINFO(crtc2).pixclock == ACCESS_FBINFO(features).pll.ref_freq) {
+		c2_ctl |=  0x4002;	/* Use reference directly */
+	} else if (videomnp == pixelmnp) {
+		c2_ctl |=  0x0004;	/* Use pixel PLL */
+	} else {
+		if (0 == ((videomnp ^ pixelmnp) & 0xFFFFFF00)) {
+			/* PIXEL and VIDEO PLL must not use same frequency. We modify N
+			   of PIXEL PLL in such case because of VIDEO PLL may be source
+			   of TVO clocks, and chroma subcarrier is derived from its
+			   pixel clocks */
+			pixelmnp += 0x000100;
+		}
+		c2_ctl |=  0x0006;	/* Use video PLL */
+		hw->DACreg[POS1064_XPWRCTRL] |= 0x02;
+		
+		outDAC1064(PMINFO M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]);
+		matroxfb_g450_setpll_cond(PMINFO videomnp, M_VIDEO_PLL);
+	}
+
+	hw->DACreg[POS1064_XPIXCLKCTRL] &= ~M1064_XPIXCLKCTRL_PLL_UP;
+	if (pixelmnp >= 0) {
+		hw->DACreg[POS1064_XPIXCLKCTRL] |= M1064_XPIXCLKCTRL_PLL_UP;
+		
+		outDAC1064(PMINFO M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]);
+		matroxfb_g450_setpll_cond(PMINFO pixelmnp, M_PIXEL_PLL_C);
+	}
+	if (c2_ctl != hw->crtc2.ctl) {
+		hw->crtc2.ctl = c2_ctl;
+		mga_outl(0x3C10, c2_ctl);
+	}
+
+	pxc = ACCESS_FBINFO(crtc1).pixclock;
+	if (pxc == 0 || ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC2) {
+		pxc = ACCESS_FBINFO(crtc2).pixclock;
+	}
+	if (ACCESS_FBINFO(chip) == MGA_G550) {
+		if (pxc < 45000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x00;	/* 0-50 */
+		} else if (pxc < 55000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x08;	/* 34-62 */
+		} else if (pxc < 70000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x10;	/* 42-78 */
+		} else if (pxc < 85000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x18;	/* 62-92 */
+		} else if (pxc < 100000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x20;	/* 74-108 */
+		} else if (pxc < 115000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x28;	/* 94-122 */
+		} else if (pxc < 125000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x30;	/* 108-132 */
+		} else {
+			hw->DACreg[POS1064_XPANMODE] = 0x38;	/* 120-168 */
+		}
+	} else {
+		/* G450 */
+		if (pxc < 45000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x00;	/* 0-54 */
+		} else if (pxc < 65000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x08;	/* 38-70 */
+		} else if (pxc < 85000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x10;	/* 56-96 */
+		} else if (pxc < 105000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x18;	/* 80-114 */
+		} else if (pxc < 135000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x20;	/* 102-144 */
+		} else if (pxc < 160000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x28;	/* 132-166 */
+		} else if (pxc < 175000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x30;	/* 154-182 */
+		} else {
+			hw->DACreg[POS1064_XPANMODE] = 0x38;	/* 170-204 */
+		}
+	}
+}
+#endif
+
+void DAC1064_global_init(WPMINFO2) {
+	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
+
+	hw->DACreg[POS1064_XMISCCTRL] &= M1064_XMISCCTRL_DAC_WIDTHMASK;
+	hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_LUT_EN;
+	hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL;
+#ifdef CONFIG_FB_MATROX_G
+	if (ACCESS_FBINFO(devflags.g450dac)) {
+		hw->DACreg[POS1064_XPWRCTRL] = 0x1F;	/* powerup everything */
+		hw->DACreg[POS1064_XOUTPUTCONN] = 0x00;	/* disable outputs */
+		hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
+		switch (ACCESS_FBINFO(outputs[0]).src) {
+			case MATROXFB_SRC_CRTC1:
+			case MATROXFB_SRC_CRTC2:
+				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x01;	/* enable output; CRTC1/2 selection is in CRTC2 ctl */
+				break;
+			case MATROXFB_SRC_NONE:
+				hw->DACreg[POS1064_XMISCCTRL] &= ~M1064_XMISCCTRL_DAC_EN;
+				break;
+		}
+		switch (ACCESS_FBINFO(outputs[1]).src) {
+			case MATROXFB_SRC_CRTC1:
+				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x04;
+				break;
+			case MATROXFB_SRC_CRTC2:
+				if (ACCESS_FBINFO(outputs[1]).mode == MATROXFB_OUTPUT_MODE_MONITOR) {
+					hw->DACreg[POS1064_XOUTPUTCONN] |= 0x08;
+				} else {
+					hw->DACreg[POS1064_XOUTPUTCONN] |= 0x0C;
+				}
+				break;
+			case MATROXFB_SRC_NONE:
+				hw->DACreg[POS1064_XPWRCTRL] &= ~0x01;		/* Poweroff DAC2 */
+				break;
+		}
+		switch (ACCESS_FBINFO(outputs[2]).src) {
+			case MATROXFB_SRC_CRTC1:
+				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x20;
+				break;
+			case MATROXFB_SRC_CRTC2:
+				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x40;
+				break;
+			case MATROXFB_SRC_NONE:
+#if 0
+				/* HELP! If we boot without DFP connected to DVI, we can
+				   poweroff TMDS. But if we boot with DFP connected,
+				   TMDS generated clocks are used instead of ALL pixclocks
+				   available... If someone knows which register
+				   handles it, please reveal this secret to me... */			
+				hw->DACreg[POS1064_XPWRCTRL] &= ~0x04;		/* Poweroff TMDS */
+#endif				
+				break;
+		}
+		/* Now set timming related variables... */
+		g450_set_plls(PMINFO2);
+	} else
+#endif
+	{
+		if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC1) {
+			hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_EXT;
+			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_MAFC12;
+		} else if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC2) {
+			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_C2_MAFC12;
+		} else if (ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1)
+			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_PANELLINK | G400_XMISCCTRL_VDO_MAFC12;
+		else
+			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_DIS;
+
+		if (ACCESS_FBINFO(outputs[0]).src != MATROXFB_SRC_NONE)
+			hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
+	}
+}
+
+void DAC1064_global_restore(WPMINFO2) {
+	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
+
+	outDAC1064(PMINFO M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]);
+	outDAC1064(PMINFO M1064_XMISCCTRL, hw->DACreg[POS1064_XMISCCTRL]);
+	if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400) {
+		outDAC1064(PMINFO 0x20, 0x04);
+		outDAC1064(PMINFO 0x1F, ACCESS_FBINFO(devflags.dfp_type));
+		if (ACCESS_FBINFO(devflags.g450dac)) {
+			outDAC1064(PMINFO M1064_XSYNCCTRL, 0xCC);
+			outDAC1064(PMINFO M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]);
+			outDAC1064(PMINFO M1064_XPANMODE, hw->DACreg[POS1064_XPANMODE]);
+			outDAC1064(PMINFO M1064_XOUTPUTCONN, hw->DACreg[POS1064_XOUTPUTCONN]);
+		}
+	}
+}
+
+static int DAC1064_init_1(WPMINFO struct my_timming* m) {
+	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
+
+	DBG(__FUNCTION__)
+
+	memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs));
+	switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
+		/* case 4: not supported by MGA1064 DAC */
+		case 8:
+			hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+			break;
+		case 16:
+			if (ACCESS_FBINFO(fbcon).var.green.length == 5)
+				hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_15BPP_1BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+			else
+				hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_16BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+			break;
+		case 24:
+			hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_24BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+			break;
+		case 32:
+			hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_32BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+			break;
+		default:
+			return 1;	/* unsupported depth */
+	}
+	hw->DACreg[POS1064_XVREFCTRL] = ACCESS_FBINFO(features.DAC1064.xvrefctrl);
+	hw->DACreg[POS1064_XGENCTRL] &= ~M1064_XGENCTRL_SYNC_ON_GREEN_MASK;
+	hw->DACreg[POS1064_XGENCTRL] |= (m->sync & FB_SYNC_ON_GREEN)?M1064_XGENCTRL_SYNC_ON_GREEN:M1064_XGENCTRL_NO_SYNC_ON_GREEN;
+	hw->DACreg[POS1064_XCURADDL] = 0;
+	hw->DACreg[POS1064_XCURADDH] = 0;
+
+	DAC1064_global_init(PMINFO2);
+	return 0;
+}
+
+static int DAC1064_init_2(WPMINFO struct my_timming* m) {
+	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
+
+	DBG(__FUNCTION__)
+
+	if (ACCESS_FBINFO(fbcon).var.bits_per_pixel > 16) {	/* 256 entries */
+		int i;
+
+		for (i = 0; i < 256; i++) {
+			hw->DACpal[i * 3 + 0] = i;
+			hw->DACpal[i * 3 + 1] = i;
+			hw->DACpal[i * 3 + 2] = i;
+		}
+	} else if (ACCESS_FBINFO(fbcon).var.bits_per_pixel > 8) {
+		if (ACCESS_FBINFO(fbcon).var.green.length == 5) {	/* 0..31, 128..159 */
+			int i;
+
+			for (i = 0; i < 32; i++) {
+				/* with p15 == 0 */
+				hw->DACpal[i * 3 + 0] = i << 3;
+				hw->DACpal[i * 3 + 1] = i << 3;
+				hw->DACpal[i * 3 + 2] = i << 3;
+				/* with p15 == 1 */
+				hw->DACpal[(i + 128) * 3 + 0] = i << 3;
+				hw->DACpal[(i + 128) * 3 + 1] = i << 3;
+				hw->DACpal[(i + 128) * 3 + 2] = i << 3;
+			}
+		} else {
+			int i;
+
+			for (i = 0; i < 64; i++) {		/* 0..63 */
+				hw->DACpal[i * 3 + 0] = i << 3;
+				hw->DACpal[i * 3 + 1] = i << 2;
+				hw->DACpal[i * 3 + 2] = i << 3;
+			}
+		}
+	} else {
+		memset(hw->DACpal, 0, 768);
+	}
+	return 0;
+}
+
+static void DAC1064_restore_1(WPMINFO2) {
+	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
+
+	CRITFLAGS
+
+	DBG(__FUNCTION__)
+
+	CRITBEGIN
+
+	if ((inDAC1064(PMINFO DAC1064_XSYSPLLM) != hw->DACclk[3]) ||
+	    (inDAC1064(PMINFO DAC1064_XSYSPLLN) != hw->DACclk[4]) ||
+	    (inDAC1064(PMINFO DAC1064_XSYSPLLP) != hw->DACclk[5])) {
+		outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3]);
+		outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4]);
+		outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5]);
+	}
+	{
+		unsigned int i;
+
+		for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) {
+			if ((i != POS1064_XPIXCLKCTRL) && (i != POS1064_XMISCCTRL))
+				outDAC1064(PMINFO MGA1064_DAC_regs[i], hw->DACreg[i]);
+		}
+	}
+
+	DAC1064_global_restore(PMINFO2);
+
+	CRITEND
+};
+
+static void DAC1064_restore_2(WPMINFO2) {
+#ifdef DEBUG
+	unsigned int i;
+#endif
+
+	DBG(__FUNCTION__)
+
+#ifdef DEBUG
+	dprintk(KERN_DEBUG "DAC1064regs ");
+	for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) {
+		dprintk("R%02X=%02X ", MGA1064_DAC_regs[i], ACCESS_FBINFO(hw).DACreg[i]);
+		if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... ");
+	}
+	dprintk("\n" KERN_DEBUG "DAC1064clk ");
+	for (i = 0; i < 6; i++)
+		dprintk("C%02X=%02X ", i, ACCESS_FBINFO(hw).DACclk[i]);
+	dprintk("\n");
+#endif
+}
+
+static int m1064_compute(void* out, struct my_timming* m) {
+#define minfo ((struct matrox_fb_info*)out)
+	{
+		int i;
+		int tmout;
+		CRITFLAGS
+
+		DAC1064_setpclk(PMINFO m->pixclock);
+
+		CRITBEGIN
+
+		for (i = 0; i < 3; i++)
+			outDAC1064(PMINFO M1064_XPIXPLLCM + i, ACCESS_FBINFO(hw).DACclk[i]);
+		for (tmout = 500000; tmout; tmout--) {
+			if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40)
+				break;
+			udelay(10);
+		};
+
+		CRITEND
+
+		if (!tmout)
+			printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
+	}
+#undef minfo
+	return 0;
+}
+
+static struct matrox_altout m1064 = {
+	.name	 = "Primary output",
+	.compute = m1064_compute,
+};
+
+#ifdef CONFIG_FB_MATROX_G
+static int g450_compute(void* out, struct my_timming* m) {
+#define minfo ((struct matrox_fb_info*)out)
+	if (m->mnp < 0) {
+		m->mnp = matroxfb_g450_setclk(PMINFO m->pixclock, (m->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
+		if (m->mnp >= 0) {
+			m->pixclock = g450_mnp2f(PMINFO m->mnp);
+		}
+	}
+#undef minfo
+	return 0;
+}
+
+static struct matrox_altout g450out = {
+	.name	 = "Primary output",
+	.compute = g450_compute,
+};
+#endif
+
+#endif /* NEED_DAC1064 */
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static int MGA1064_init(WPMINFO struct my_timming* m) {
+	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
+
+	DBG(__FUNCTION__)
+
+	if (DAC1064_init_1(PMINFO m)) return 1;
+	if (matroxfb_vgaHWinit(PMINFO m)) return 1;
+
+	hw->MiscOutReg = 0xCB;
+	if (m->sync & FB_SYNC_HOR_HIGH_ACT)
+		hw->MiscOutReg &= ~0x40;
+	if (m->sync & FB_SYNC_VERT_HIGH_ACT)
+		hw->MiscOutReg &= ~0x80;
+	if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
+		hw->CRTCEXT[3] |= 0x40;
+
+	if (DAC1064_init_2(PMINFO m)) return 1;
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_G
+static int MGAG100_init(WPMINFO struct my_timming* m) {
+	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
+
+	DBG(__FUNCTION__)
+
+	if (DAC1064_init_1(PMINFO m)) return 1;
+	hw->MXoptionReg &= ~0x2000;
+	if (matroxfb_vgaHWinit(PMINFO m)) return 1;
+
+	hw->MiscOutReg = 0xEF;
+	if (m->sync & FB_SYNC_HOR_HIGH_ACT)
+		hw->MiscOutReg &= ~0x40;
+	if (m->sync & FB_SYNC_VERT_HIGH_ACT)
+		hw->MiscOutReg &= ~0x80;
+	if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
+		hw->CRTCEXT[3] |= 0x40;
+
+	if (DAC1064_init_2(PMINFO m)) return 1;
+	return 0;
+}
+#endif	/* G */
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static void MGA1064_ramdac_init(WPMINFO2) {
+
+	DBG(__FUNCTION__)
+
+	/* ACCESS_FBINFO(features.DAC1064.vco_freq_min) = 120000; */
+	ACCESS_FBINFO(features.pll.vco_freq_min) = 62000;
+	ACCESS_FBINFO(features.pll.ref_freq)	 = 14318;
+	ACCESS_FBINFO(features.pll.feed_div_min) = 100;
+	ACCESS_FBINFO(features.pll.feed_div_max) = 127;
+	ACCESS_FBINFO(features.pll.in_div_min)	 = 1;
+	ACCESS_FBINFO(features.pll.in_div_max)	 = 31;
+	ACCESS_FBINFO(features.pll.post_shift_max) = 3;
+	ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_EXTERNAL;
+	/* maybe cmdline MCLK= ?, doc says gclk=44MHz, mclk=66MHz... it was 55/83 with old values */
+	DAC1064_setmclk(PMINFO DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PLL, 133333);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_G
+/* BIOS environ */
+static int x7AF4 = 0x10;	/* flags, maybe 0x10 = SDRAM, 0x00 = SGRAM??? */
+				/* G100 wants 0x10, G200 SGRAM does not care... */
+#if 0
+static int def50 = 0;	/* reg50, & 0x0F, & 0x3000 (only 0x0000, 0x1000, 0x2000 (0x3000 disallowed and treated as 0) */
+#endif
+
+static void MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p) {
+	int reg;
+	int selClk;
+	int clk;
+
+	DBG(__FUNCTION__)
+
+	outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) | M1064_XPIXCLKCTRL_DIS |
+		   M1064_XPIXCLKCTRL_PLL_UP);
+	switch (flags & 3) {
+		case 0:		reg = M1064_XPIXPLLAM; break;
+		case 1:		reg = M1064_XPIXPLLBM; break;
+		default:	reg = M1064_XPIXPLLCM; break;
+	}
+	outDAC1064(PMINFO reg++, m);
+	outDAC1064(PMINFO reg++, n);
+	outDAC1064(PMINFO reg, p);
+	selClk = mga_inb(M_MISC_REG_READ) & ~0xC;
+	/* there should be flags & 0x03 & case 0/1/else */
+	/* and we should first select source and after that we should wait for PLL */
+	/* and we are waiting for PLL with oscilator disabled... Is it right? */
+	switch (flags & 0x03) {
+		case 0x00:	break;
+		case 0x01:	selClk |= 4; break;
+		default:	selClk |= 0x0C; break;
+	}
+	mga_outb(M_MISC_REG, selClk);
+	for (clk = 500000; clk; clk--) {
+		if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40)
+			break;
+		udelay(10);
+	};
+	if (!clk)
+		printk(KERN_ERR "matroxfb: Pixel PLL%c not locked after usual time\n", (reg-M1064_XPIXPLLAM-2)/4 + 'A');
+	selClk = inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_SRC_MASK;
+	switch (flags & 0x0C) {
+		case 0x00:	selClk |= M1064_XPIXCLKCTRL_SRC_PCI; break;
+		case 0x04:	selClk |= M1064_XPIXCLKCTRL_SRC_PLL; break;
+		default:	selClk |= M1064_XPIXCLKCTRL_SRC_EXT; break;
+	}
+	outDAC1064(PMINFO M1064_XPIXCLKCTRL, selClk);
+	outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_DIS);
+}
+
+static void MGAG100_setPixClock(CPMINFO int flags, int freq) {
+	unsigned int m, n, p;
+
+	DBG(__FUNCTION__)
+
+	DAC1064_calcclock(PMINFO freq, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
+	MGAG100_progPixClock(PMINFO flags, m, n, p);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static int MGA1064_preinit(WPMINFO2) {
+	static const int vxres_mystique[] = { 512,        640, 768,  800,  832,  960,
+					     1024, 1152, 1280,      1600, 1664, 1920,
+					     2048,    0};
+	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
+
+	DBG(__FUNCTION__)
+
+	/* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */
+	ACCESS_FBINFO(capable.text) = 1;
+	ACCESS_FBINFO(capable.vxres) = vxres_mystique;
+	ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
+
+	ACCESS_FBINFO(outputs[0]).output = &m1064;
+	ACCESS_FBINFO(outputs[0]).src = ACCESS_FBINFO(outputs[0]).default_src;
+	ACCESS_FBINFO(outputs[0]).data = MINFO;
+	ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+
+	if (ACCESS_FBINFO(devflags.noinit))
+		return 0;	/* do not modify settings */
+	hw->MXoptionReg &= 0xC0000100;
+	hw->MXoptionReg |= 0x00094E20;
+	if (ACCESS_FBINFO(devflags.novga))
+		hw->MXoptionReg &= ~0x00000100;
+	if (ACCESS_FBINFO(devflags.nobios))
+		hw->MXoptionReg &= ~0x40000000;
+	if (ACCESS_FBINFO(devflags.nopciretry))
+		hw->MXoptionReg |=  0x20000000;
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+	mga_setr(M_SEQ_INDEX, 0x01, 0x20);
+	mga_outl(M_CTLWTST, 0x00000000);
+	udelay(200);
+	mga_outl(M_MACCESS, 0x00008000);
+	udelay(100);
+	mga_outl(M_MACCESS, 0x0000C000);
+	return 0;
+}
+
+static void MGA1064_reset(WPMINFO2) {
+
+	DBG(__FUNCTION__);
+
+	MGA1064_ramdac_init(PMINFO2);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_G
+static void g450_mclk_init(WPMINFO2) {
+	/* switch all clocks to PCI source */
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg | 4);
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION3_REG, ACCESS_FBINFO(values).reg.opt3 & ~0x00300C03);
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg);
+	
+	if (((ACCESS_FBINFO(values).reg.opt3 & 0x000003) == 0x000003) ||
+	    ((ACCESS_FBINFO(values).reg.opt3 & 0x000C00) == 0x000C00) ||
+	    ((ACCESS_FBINFO(values).reg.opt3 & 0x300000) == 0x300000)) {
+		matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(values.pll.video), M_VIDEO_PLL);
+	} else {
+		unsigned long flags;
+		unsigned int pwr;
+		
+		matroxfb_DAC_lock_irqsave(flags);
+		pwr = inDAC1064(PMINFO M1064_XPWRCTRL) & ~0x02;
+		outDAC1064(PMINFO M1064_XPWRCTRL, pwr);
+		matroxfb_DAC_unlock_irqrestore(flags);
+	}
+	matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(values.pll.system), M_SYSTEM_PLL);
+	
+	/* switch clocks to their real PLL source(s) */
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg | 4);
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION3_REG, ACCESS_FBINFO(values).reg.opt3);
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg);
+
+}
+
+static void g450_memory_init(WPMINFO2) {
+	/* disable memory refresh */
+	ACCESS_FBINFO(hw).MXoptionReg &= ~0x001F8000;
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg);
+	
+	/* set memory interface parameters */
+	ACCESS_FBINFO(hw).MXoptionReg &= ~0x00207E00;
+	ACCESS_FBINFO(hw).MXoptionReg |= 0x00207E00 & ACCESS_FBINFO(values).reg.opt;
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg);
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, ACCESS_FBINFO(values).reg.opt2);
+	
+	mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst);
+	
+	/* first set up memory interface with disabled memory interface clocks */
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_MEMMISC_REG, ACCESS_FBINFO(values).reg.memmisc & ~0x80000000U);
+	mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk);
+	mga_outl(M_MACCESS, ACCESS_FBINFO(values).reg.maccess);
+	/* start memory clocks */
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_MEMMISC_REG, ACCESS_FBINFO(values).reg.memmisc | 0x80000000U);
+
+	udelay(200);
+	
+	if (ACCESS_FBINFO(values).memory.ddr && (!ACCESS_FBINFO(values).memory.emrswen || !ACCESS_FBINFO(values).memory.dll)) {
+		mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk & ~0x1000);
+	}
+	mga_outl(M_MACCESS, ACCESS_FBINFO(values).reg.maccess | 0x8000);
+	
+	udelay(200);
+	
+	ACCESS_FBINFO(hw).MXoptionReg |= 0x001F8000 & ACCESS_FBINFO(values).reg.opt;
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg);
+	
+	/* value is written to memory chips only if old != new */
+	mga_outl(M_PLNWT, 0);
+	mga_outl(M_PLNWT, ~0);
+	
+	if (ACCESS_FBINFO(values).reg.mctlwtst != ACCESS_FBINFO(values).reg.mctlwtst_core) {
+		mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst_core);
+	}
+	
+}
+
+static void g450_preinit(WPMINFO2) {
+	u_int32_t c2ctl;
+	u_int8_t curctl;
+	u_int8_t c1ctl;
+	
+	/* ACCESS_FBINFO(hw).MXoptionReg = minfo->values.reg.opt; */
+	ACCESS_FBINFO(hw).MXoptionReg &= 0xC0000100;
+	ACCESS_FBINFO(hw).MXoptionReg |= 0x00000020;
+	if (ACCESS_FBINFO(devflags.novga))
+		ACCESS_FBINFO(hw).MXoptionReg &= ~0x00000100;
+	if (ACCESS_FBINFO(devflags.nobios))
+		ACCESS_FBINFO(hw).MXoptionReg &= ~0x40000000;
+	if (ACCESS_FBINFO(devflags.nopciretry))
+		ACCESS_FBINFO(hw).MXoptionReg |=  0x20000000;
+	ACCESS_FBINFO(hw).MXoptionReg |= ACCESS_FBINFO(values).reg.opt & 0x03400040;
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg);
+
+	/* Init system clocks */
+		
+	/* stop crtc2 */
+	c2ctl = mga_inl(M_C2CTL);
+	mga_outl(M_C2CTL, c2ctl & ~1);
+	/* stop cursor */
+	curctl = inDAC1064(PMINFO M1064_XCURCTRL);
+	outDAC1064(PMINFO M1064_XCURCTRL, 0);
+	/* stop crtc1 */
+	c1ctl = mga_readr(M_SEQ_INDEX, 1);
+	mga_setr(M_SEQ_INDEX, 1, c1ctl | 0x20);
+
+	g450_mclk_init(PMINFO2);
+	g450_memory_init(PMINFO2);
+	
+	/* set legacy VGA clock sources for DOSEmu or VMware... */
+	matroxfb_g450_setclk(PMINFO 25175, M_PIXEL_PLL_A);
+	matroxfb_g450_setclk(PMINFO 28322, M_PIXEL_PLL_B);
+
+	/* restore crtc1 */
+	mga_setr(M_SEQ_INDEX, 1, c1ctl);
+	
+	/* restore cursor */
+	outDAC1064(PMINFO M1064_XCURCTRL, curctl);
+
+	/* restore crtc2 */
+	mga_outl(M_C2CTL, c2ctl);
+	
+	return;
+}
+
+static int MGAG100_preinit(WPMINFO2) {
+	static const int vxres_g100[] = {  512,        640, 768,  800,  832,  960,
+                                          1024, 1152, 1280,      1600, 1664, 1920,
+                                          2048, 0};
+	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
+
+        u_int32_t reg50;
+#if 0
+	u_int32_t q;
+#endif
+
+	DBG(__FUNCTION__)
+
+	/* there are some instabilities if in_div > 19 && vco < 61000 */
+	if (ACCESS_FBINFO(devflags.g450dac)) {
+		ACCESS_FBINFO(features.pll.vco_freq_min) = 130000;	/* my sample: >118 */
+	} else {
+		ACCESS_FBINFO(features.pll.vco_freq_min) = 62000;
+	}
+	if (!ACCESS_FBINFO(features.pll.ref_freq)) {
+		ACCESS_FBINFO(features.pll.ref_freq)	 = 27000;
+	}
+	ACCESS_FBINFO(features.pll.feed_div_min) = 7;
+	ACCESS_FBINFO(features.pll.feed_div_max) = 127;
+	ACCESS_FBINFO(features.pll.in_div_min)	 = 1;
+	ACCESS_FBINFO(features.pll.in_div_max)	 = 31;
+	ACCESS_FBINFO(features.pll.post_shift_max) = 3;
+	ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_G100_DEFAULT;
+	/* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */
+	ACCESS_FBINFO(capable.text) = 1;
+	ACCESS_FBINFO(capable.vxres) = vxres_g100;
+	ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
+	ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100
+			? ACCESS_FBINFO(devflags.sgram) : 1;
+
+#ifdef CONFIG_FB_MATROX_G
+	if (ACCESS_FBINFO(devflags.g450dac)) {
+		ACCESS_FBINFO(outputs[0]).output = &g450out;
+	} else
+#endif
+	{
+		ACCESS_FBINFO(outputs[0]).output = &m1064;
+	}
+	ACCESS_FBINFO(outputs[0]).src = ACCESS_FBINFO(outputs[0]).default_src;
+	ACCESS_FBINFO(outputs[0]).data = MINFO;
+	ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+
+	if (ACCESS_FBINFO(devflags.g450dac)) {
+		/* we must do this always, BIOS does not do it for us
+		   and accelerator dies without it */
+		mga_outl(0x1C0C, 0);
+	}
+	if (ACCESS_FBINFO(devflags.noinit))
+		return 0;
+	if (ACCESS_FBINFO(devflags.g450dac)) {
+		g450_preinit(PMINFO2);
+		return 0;
+	}
+	hw->MXoptionReg &= 0xC0000100;
+	hw->MXoptionReg |= 0x00000020;
+	if (ACCESS_FBINFO(devflags.novga))
+		hw->MXoptionReg &= ~0x00000100;
+	if (ACCESS_FBINFO(devflags.nobios))
+		hw->MXoptionReg &= ~0x40000000;
+	if (ACCESS_FBINFO(devflags.nopciretry))
+		hw->MXoptionReg |=  0x20000000;
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+	DAC1064_setmclk(PMINFO DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PCI, 133333);
+
+	if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100) {
+		pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, &reg50);
+		reg50 &= ~0x3000;
+		pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, reg50);
+
+		hw->MXoptionReg |= 0x1080;
+		pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+		mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst);
+		udelay(100);
+		mga_outb(0x1C05, 0x00);
+		mga_outb(0x1C05, 0x80);
+		udelay(100);
+		mga_outb(0x1C05, 0x40);
+		mga_outb(0x1C05, 0xC0);
+		udelay(100);
+		reg50 &= ~0xFF;
+		reg50 |=  0x07;
+		pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, reg50);
+		/* it should help with G100 */
+		mga_outb(M_GRAPHICS_INDEX, 6);
+		mga_outb(M_GRAPHICS_DATA, (mga_inb(M_GRAPHICS_DATA) & 3) | 4);
+		mga_setr(M_EXTVGA_INDEX, 0x03, 0x81);
+		mga_setr(M_EXTVGA_INDEX, 0x04, 0x00);
+		mga_writeb(ACCESS_FBINFO(video.vbase), 0x0000, 0xAA);
+		mga_writeb(ACCESS_FBINFO(video.vbase), 0x0800, 0x55);
+		mga_writeb(ACCESS_FBINFO(video.vbase), 0x4000, 0x55);
+#if 0
+		if (mga_readb(ACCESS_FBINFO(video.vbase), 0x0000) != 0xAA) {
+			hw->MXoptionReg &= ~0x1000;
+		}
+#endif
+		hw->MXoptionReg |= 0x00078020;
+	} else if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG200) {
+		pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, &reg50);
+		reg50 &= ~0x3000;
+		pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, reg50);
+
+		if (ACCESS_FBINFO(devflags.memtype) == -1)
+			hw->MXoptionReg |= ACCESS_FBINFO(values).reg.opt & 0x1C00;
+		else
+			hw->MXoptionReg |= (ACCESS_FBINFO(devflags.memtype) & 7) << 10;
+		if (ACCESS_FBINFO(devflags.sgram))
+			hw->MXoptionReg |= 0x4000;
+		mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst);
+		mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk);
+		udelay(200);
+		mga_outl(M_MACCESS, 0x00000000);
+		mga_outl(M_MACCESS, 0x00008000);
+		udelay(100);
+		mga_outw(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk);
+		hw->MXoptionReg |= 0x00078020;
+	} else {
+		pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, &reg50);
+		reg50 &= ~0x00000100;
+		reg50 |=  0x00000000;
+		pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, reg50);
+
+		if (ACCESS_FBINFO(devflags.memtype) == -1)
+			hw->MXoptionReg |= ACCESS_FBINFO(values).reg.opt & 0x1C00;
+		else
+			hw->MXoptionReg |= (ACCESS_FBINFO(devflags.memtype) & 7) << 10;
+		if (ACCESS_FBINFO(devflags.sgram))
+			hw->MXoptionReg |= 0x4000;
+		mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst);
+		mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk);
+		udelay(200);
+		mga_outl(M_MACCESS, 0x00000000);
+		mga_outl(M_MACCESS, 0x00008000);
+		udelay(100);
+		mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk);
+		hw->MXoptionReg |= 0x00040020;
+	}
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+	return 0;
+}
+
+static void MGAG100_reset(WPMINFO2) {
+	u_int8_t b;
+	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
+
+	DBG(__FUNCTION__)
+
+	{
+#ifdef G100_BROKEN_IBM_82351
+		u_int32_t d;
+
+		find 1014/22 (IBM/82351); /* if found and bridging Matrox, do some strange stuff */
+		pci_read_config_byte(ibm, PCI_SECONDARY_BUS, &b);
+		if (b == ACCESS_FBINFO(pcidev)->bus->number) {
+			pci_write_config_byte(ibm, PCI_COMMAND+1, 0);	/* disable back-to-back & SERR */
+			pci_write_config_byte(ibm, 0x41, 0xF4);		/* ??? */
+			pci_write_config_byte(ibm, PCI_IO_BASE, 0xF0);	/* ??? */
+			pci_write_config_byte(ibm, PCI_IO_LIMIT, 0x00);	/* ??? */
+		}
+#endif
+		if (!ACCESS_FBINFO(devflags.noinit)) {
+			if (x7AF4 & 8) {
+				hw->MXoptionReg |= 0x40;	/* FIXME... */
+				pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+			}
+			mga_setr(M_EXTVGA_INDEX, 0x06, 0x50);
+		}
+	}
+	if (ACCESS_FBINFO(devflags.g450dac)) {
+		/* either leave MCLK as is... or they were set in preinit */
+		hw->DACclk[3] = inDAC1064(PMINFO DAC1064_XSYSPLLM);
+		hw->DACclk[4] = inDAC1064(PMINFO DAC1064_XSYSPLLN);
+		hw->DACclk[5] = inDAC1064(PMINFO DAC1064_XSYSPLLP);
+	} else {
+		DAC1064_setmclk(PMINFO DAC1064_OPT_RESERVED | DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV1 | DAC1064_OPT_SCLK_PLL, 133333);
+	}
+	if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400) {
+		if (ACCESS_FBINFO(devflags.dfp_type) == -1) {
+			ACCESS_FBINFO(devflags.dfp_type) = inDAC1064(PMINFO 0x1F);
+		}
+	}
+	if (ACCESS_FBINFO(devflags.noinit))
+		return;
+	if (ACCESS_FBINFO(devflags.g450dac)) {
+	} else {
+		MGAG100_setPixClock(PMINFO 4, 25175);
+		MGAG100_setPixClock(PMINFO 5, 28322);
+		if (x7AF4 & 0x10) {
+			b = inDAC1064(PMINFO M1064_XGENIODATA) & ~1;
+			outDAC1064(PMINFO M1064_XGENIODATA, b);
+			b = inDAC1064(PMINFO M1064_XGENIOCTRL) | 1;
+			outDAC1064(PMINFO M1064_XGENIOCTRL, b);
+		}
+	}
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static void MGA1064_restore(WPMINFO2) {
+	int i;
+	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
+
+	CRITFLAGS
+
+	DBG(__FUNCTION__)
+
+	CRITBEGIN
+
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+	mga_outb(M_IEN, 0x00);
+	mga_outb(M_CACHEFLUSH, 0x00);
+
+	CRITEND
+
+	DAC1064_restore_1(PMINFO2);
+	matroxfb_vgaHWrestore(PMINFO2);
+	ACCESS_FBINFO(crtc1.panpos) = -1;
+	for (i = 0; i < 6; i++)
+		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
+	DAC1064_restore_2(PMINFO2);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_G
+static void MGAG100_restore(WPMINFO2) {
+	int i;
+	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
+
+	CRITFLAGS
+
+	DBG(__FUNCTION__)
+
+	CRITBEGIN
+
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+	CRITEND
+
+	DAC1064_restore_1(PMINFO2);
+	matroxfb_vgaHWrestore(PMINFO2);
+#ifdef CONFIG_FB_MATROX_32MB
+	if (ACCESS_FBINFO(devflags.support32MB))
+		mga_setr(M_EXTVGA_INDEX, 8, hw->CRTCEXT[8]);
+#endif
+	ACCESS_FBINFO(crtc1.panpos) = -1;
+	for (i = 0; i < 6; i++)
+		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
+	DAC1064_restore_2(PMINFO2);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+struct matrox_switch matrox_mystique = {
+	MGA1064_preinit, MGA1064_reset, MGA1064_init, MGA1064_restore,
+};
+EXPORT_SYMBOL(matrox_mystique);
+#endif
+
+#ifdef CONFIG_FB_MATROX_G
+struct matrox_switch matrox_G100 = {
+	MGAG100_preinit, MGAG100_reset, MGAG100_init, MGAG100_restore,
+};
+EXPORT_SYMBOL(matrox_G100);
+#endif
+
+#ifdef NEED_DAC1064
+EXPORT_SYMBOL(DAC1064_global_init);
+EXPORT_SYMBOL(DAC1064_global_restore);
+#endif
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/matrox/matroxfb_DAC1064.h b/drivers/video/matrox/matroxfb_DAC1064.h
new file mode 100644
index 0000000..a6a4701
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_DAC1064.h
@@ -0,0 +1,164 @@
+#ifndef __MATROXFB_DAC1064_H__
+#define __MATROXFB_DAC1064_H__
+
+/* make checkconfig does not walk through include tree */
+#include <linux/config.h>
+
+#include "matroxfb_base.h"
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+extern struct matrox_switch matrox_mystique;
+#endif
+#ifdef CONFIG_FB_MATROX_G
+extern struct matrox_switch matrox_G100;
+#endif
+#ifdef NEED_DAC1064
+void DAC1064_global_init(WPMINFO2);
+void DAC1064_global_restore(WPMINFO2);
+#endif
+
+#define M1064_INDEX	0x00
+#define M1064_PALWRADD	0x00
+#define M1064_PALDATA	0x01
+#define M1064_PIXRDMSK	0x02
+#define M1064_PALRDADD	0x03
+#define M1064_X_DATAREG	0x0A
+#define M1064_CURPOSXL	0x0C	/* can be accessed as DWORD */
+#define M1064_CURPOSXH	0x0D
+#define M1064_CURPOSYL	0x0E
+#define M1064_CURPOSYH	0x0F
+
+#define M1064_XCURADDL		0x04
+#define M1064_XCURADDH		0x05
+#define M1064_XCURCTRL		0x06
+#define     M1064_XCURCTRL_DIS		0x00	/* transparent, transparent, transparent, transparent */
+#define     M1064_XCURCTRL_3COLOR	0x01	/* transparent, 0, 1, 2 */
+#define     M1064_XCURCTRL_XGA		0x02	/* 0, 1, transparent, complement */
+#define     M1064_XCURCTRL_XWIN		0x03	/* transparent, transparent, 0, 1 */
+#define M1064_XCURCOL0RED	0x08
+#define M1064_XCURCOL0GREEN	0x09
+#define M1064_XCURCOL0BLUE	0x0A
+#define M1064_XCURCOL1RED	0x0C
+#define M1064_XCURCOL1GREEN	0x0D
+#define M1064_XCURCOL1BLUE	0x0E
+#define M1064_XCURCOL2RED	0x10
+#define M1064_XCURCOL2GREEN	0x11
+#define M1064_XCURCOL2BLUE	0x12
+#define DAC1064_XVREFCTRL	0x18
+#define      DAC1064_XVREFCTRL_INTERNAL		0x3F
+#define      DAC1064_XVREFCTRL_EXTERNAL		0x00
+#define      DAC1064_XVREFCTRL_G100_DEFAULT	0x03
+#define M1064_XMULCTRL		0x19
+#define      M1064_XMULCTRL_DEPTH_8BPP		0x00	/* 8 bpp paletized */
+#define      M1064_XMULCTRL_DEPTH_15BPP_1BPP	0x01	/* 15 bpp paletized + 1 bpp overlay */
+#define      M1064_XMULCTRL_DEPTH_16BPP		0x02	/* 16 bpp paletized */
+#define      M1064_XMULCTRL_DEPTH_24BPP		0x03	/* 24 bpp paletized */
+#define      M1064_XMULCTRL_DEPTH_24BPP_8BPP	0x04	/* 24 bpp direct + 8 bpp overlay paletized */
+#define      M1064_XMULCTRL_2G8V16		0x05	/* 15 bpp video direct, half xres, 8bpp paletized */
+#define      M1064_XMULCTRL_G16V16		0x06	/* 15 bpp video, 15bpp graphics, one of them paletized */
+#define      M1064_XMULCTRL_DEPTH_32BPP		0x07	/* 24 bpp paletized + 8 bpp unused */
+#define      M1064_XMULCTRL_GRAPHICS_PALETIZED	0x00
+#define      M1064_XMULCTRL_VIDEO_PALETIZED	0x08
+#define M1064_XPIXCLKCTRL	0x1A
+#define      M1064_XPIXCLKCTRL_SRC_PCI		0x00
+#define      M1064_XPIXCLKCTRL_SRC_PLL		0x01
+#define      M1064_XPIXCLKCTRL_SRC_EXT		0x02
+#define	     M1064_XPIXCLKCTRL_SRC_SYS		0x03	/* G200/G400 */
+#define      M1064_XPIXCLKCTRL_SRC_PLL2		0x03	/* G450 */
+#define      M1064_XPIXCLKCTRL_SRC_MASK		0x03
+#define      M1064_XPIXCLKCTRL_EN		0x00
+#define      M1064_XPIXCLKCTRL_DIS		0x04
+#define      M1064_XPIXCLKCTRL_PLL_DOWN		0x00
+#define      M1064_XPIXCLKCTRL_PLL_UP		0x08
+#define M1064_XGENCTRL		0x1D
+#define      M1064_XGENCTRL_VS_0		0x00
+#define      M1064_XGENCTRL_VS_1		0x01
+#define      M1064_XGENCTRL_ALPHA_DIS		0x00
+#define      M1064_XGENCTRL_ALPHA_EN		0x02
+#define      M1064_XGENCTRL_BLACK_0IRE		0x00
+#define      M1064_XGENCTRL_BLACK_75IRE		0x10
+#define      M1064_XGENCTRL_SYNC_ON_GREEN	0x00
+#define      M1064_XGENCTRL_NO_SYNC_ON_GREEN	0x20
+#define      M1064_XGENCTRL_SYNC_ON_GREEN_MASK	0x20
+#define M1064_XMISCCTRL		0x1E
+#define      M1064_XMISCCTRL_DAC_DIS		0x00
+#define      M1064_XMISCCTRL_DAC_EN		0x01
+#define      M1064_XMISCCTRL_MFC_VGA		0x00
+#define      M1064_XMISCCTRL_MFC_MAFC		0x02
+#define      M1064_XMISCCTRL_MFC_DIS		0x06
+#define      GX00_XMISCCTRL_MFC_MAFC		0x02
+#define      GX00_XMISCCTRL_MFC_PANELLINK	0x04
+#define      GX00_XMISCCTRL_MFC_DIS		0x06
+#define      GX00_XMISCCTRL_MFC_MASK		0x06
+#define      M1064_XMISCCTRL_DAC_6BIT		0x00
+#define      M1064_XMISCCTRL_DAC_8BIT		0x08
+#define      M1064_XMISCCTRL_DAC_WIDTHMASK	0x08
+#define      M1064_XMISCCTRL_LUT_DIS		0x00
+#define      M1064_XMISCCTRL_LUT_EN		0x10
+#define      G400_XMISCCTRL_VDO_MAFC12		0x00
+#define      G400_XMISCCTRL_VDO_BYPASS656	0x40
+#define      G400_XMISCCTRL_VDO_C2_MAFC12	0x80
+#define      G400_XMISCCTRL_VDO_C2_BYPASS656	0xC0
+#define      G400_XMISCCTRL_VDO_MASK		0xE0
+#define M1064_XGENIOCTRL	0x2A
+#define M1064_XGENIODATA	0x2B
+#define DAC1064_XSYSPLLM	0x2C
+#define DAC1064_XSYSPLLN	0x2D
+#define DAC1064_XSYSPLLP	0x2E
+#define DAC1064_XSYSPLLSTAT	0x2F
+#define M1064_XZOOMCTRL		0x38
+#define      M1064_XZOOMCTRL_1			0x00
+#define      M1064_XZOOMCTRL_2			0x01
+#define      M1064_XZOOMCTRL_4			0x03
+#define M1064_XSENSETEST	0x3A
+#define      M1064_XSENSETEST_BCOMP		0x01
+#define      M1064_XSENSETEST_GCOMP		0x02
+#define      M1064_XSENSETEST_RCOMP		0x04
+#define      M1064_XSENSETEST_PDOWN		0x00
+#define      M1064_XSENSETEST_PUP		0x80
+#define M1064_XCRCREML		0x3C
+#define M1064_XCRCREMH		0x3D
+#define M1064_XCRCBITSEL	0x3E
+#define M1064_XCOLKEYMASKL	0x40
+#define M1064_XCOLKEYMASKH	0x41
+#define M1064_XCOLKEYL		0x42
+#define M1064_XCOLKEYH		0x43
+#define M1064_XPIXPLLAM		0x44
+#define M1064_XPIXPLLAN		0x45
+#define M1064_XPIXPLLAP		0x46
+#define M1064_XPIXPLLBM		0x48
+#define M1064_XPIXPLLBN		0x49
+#define M1064_XPIXPLLBP		0x4A
+#define M1064_XPIXPLLCM		0x4C
+#define M1064_XPIXPLLCN		0x4D
+#define M1064_XPIXPLLCP		0x4E
+#define M1064_XPIXPLLSTAT	0x4F
+
+#define M1064_XTVO_IDX		0x87
+#define M1064_XTVO_DATA		0x88
+
+#define M1064_XOUTPUTCONN	0x8A
+#define M1064_XSYNCCTRL		0x8B
+#define M1064_XVIDPLLSTAT	0x8C
+#define M1064_XVIDPLLP		0x8D
+#define M1064_XVIDPLLM		0x8E
+#define M1064_XVIDPLLN		0x8F
+
+#define M1064_XPWRCTRL		0xA0
+
+#define M1064_XPANMODE		0xA2
+
+enum POS1064 {
+	POS1064_XCURADDL=0, POS1064_XCURADDH, POS1064_XCURCTRL,
+	POS1064_XCURCOL0RED, POS1064_XCURCOL0GREEN, POS1064_XCURCOL0BLUE,
+	POS1064_XCURCOL1RED, POS1064_XCURCOL1GREEN, POS1064_XCURCOL1BLUE,
+	POS1064_XCURCOL2RED, POS1064_XCURCOL2GREEN, POS1064_XCURCOL2BLUE,
+	POS1064_XVREFCTRL, POS1064_XMULCTRL, POS1064_XPIXCLKCTRL, POS1064_XGENCTRL,
+	POS1064_XMISCCTRL,
+	POS1064_XGENIOCTRL, POS1064_XGENIODATA, POS1064_XZOOMCTRL, POS1064_XSENSETEST,
+	POS1064_XCRCBITSEL,
+	POS1064_XCOLKEYMASKL, POS1064_XCOLKEYMASKH, POS1064_XCOLKEYL, POS1064_XCOLKEYH,
+	POS1064_XOUTPUTCONN, POS1064_XPANMODE, POS1064_XPWRCTRL };
+
+
+#endif	/* __MATROXFB_DAC1064_H__ */
diff --git a/drivers/video/matrox/matroxfb_Ti3026.c b/drivers/video/matrox/matroxfb_Ti3026.c
new file mode 100644
index 0000000..537ade5
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_Ti3026.c
@@ -0,0 +1,739 @@
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
+ *
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Portions Copyright (c) 2001 Matrox Graphics Inc.
+ *
+ * Version: 1.65 2002/08/14
+ *
+ * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
+ *
+ * Contributors: "menion?" <menion@mindless.com>
+ *                     Betatesting, fixes, ideas
+ *
+ *               "Kurt Garloff" <garloff@suse.de>
+ *                     Betatesting, fixes, ideas, videomodes, videomodes timmings
+ *
+ *               "Tom Rini" <trini@kernel.crashing.org>
+ *                     MTRR stuff, PPC cleanups, betatesting, fixes, ideas
+ *
+ *               "Bibek Sahu" <scorpio@dodds.net>
+ *                     Access device through readb|w|l and write b|w|l
+ *                     Extensive debugging stuff
+ *
+ *               "Daniel Haun" <haund@usa.net>
+ *                     Testing, hardware cursor fixes
+ *
+ *               "Scott Wood" <sawst46+@pitt.edu>
+ *                     Fixes
+ *
+ *               "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
+ *                     Betatesting
+ *
+ *               "Kelly French" <targon@hazmat.com>
+ *               "Fernando Herrera" <fherrera@eurielec.etsit.upm.es>
+ *                     Betatesting, bug reporting
+ *
+ *               "Pablo Bianucci" <pbian@pccp.com.ar>
+ *                     Fixes, ideas, betatesting
+ *
+ *               "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
+ *                     Fixes, enhandcements, ideas, betatesting
+ *
+ *               "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
+ *                     PPC betatesting, PPC support, backward compatibility
+ *
+ *               "Paul Womar" <Paul@pwomar.demon.co.uk>
+ *               "Owen Waller" <O.Waller@ee.qub.ac.uk>
+ *                     PPC betatesting
+ *
+ *               "Thomas Pornin" <pornin@bolet.ens.fr>
+ *                     Alpha betatesting
+ *
+ *               "Pieter van Leuven" <pvl@iae.nl>
+ *               "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de>
+ *                     G100 testing
+ *
+ *               "H. Peter Arvin" <hpa@transmeta.com>
+ *                     Ideas
+ *
+ *               "Cort Dougan" <cort@cs.nmt.edu>
+ *                     CHRP fixes and PReP cleanup
+ *
+ *               "Mark Vojkovich" <mvojkovi@ucsd.edu>
+ *                     G400 support
+ *
+ * (following author is not in any relation with this code, but his code
+ *  is included in this driver)
+ *
+ * Based on framebuffer driver for VBE 2.0 compliant graphic boards
+ *     (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ * (following author is not in any relation with this code, but his ideas
+ *  were used when writting this driver)
+ *
+ *		 FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
+ *
+ */
+
+/* make checkconfig does not verify included files... */
+#include <linux/config.h>
+
+#include "matroxfb_Ti3026.h"
+#include "matroxfb_misc.h"
+#include "matroxfb_accel.h"
+#include <linux/matroxfb.h>
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+#define outTi3026 matroxfb_DAC_out
+#define inTi3026 matroxfb_DAC_in
+
+#define TVP3026_INDEX		0x00
+#define TVP3026_PALWRADD	0x00
+#define TVP3026_PALDATA		0x01
+#define TVP3026_PIXRDMSK	0x02
+#define TVP3026_PALRDADD	0x03
+#define TVP3026_CURCOLWRADD	0x04
+#define     TVP3026_CLOVERSCAN		0x00
+#define     TVP3026_CLCOLOR0		0x01
+#define     TVP3026_CLCOLOR1		0x02
+#define     TVP3026_CLCOLOR2		0x03
+#define TVP3026_CURCOLDATA	0x05
+#define TVP3026_CURCOLRDADD	0x07
+#define TVP3026_CURCTRL		0x09
+#define TVP3026_X_DATAREG	0x0A
+#define TVP3026_CURRAMDATA	0x0B
+#define TVP3026_CURPOSXL	0x0C
+#define TVP3026_CURPOSXH	0x0D
+#define TVP3026_CURPOSYL	0x0E
+#define TVP3026_CURPOSYH	0x0F
+
+#define TVP3026_XSILICONREV	0x01
+#define TVP3026_XCURCTRL	0x06
+#define     TVP3026_XCURCTRL_DIS	0x00	/* transparent, transparent, transparent, transparent */
+#define     TVP3026_XCURCTRL_3COLOR	0x01	/* transparent, 0, 1, 2 */
+#define     TVP3026_XCURCTRL_XGA	0x02	/* 0, 1, transparent, complement */
+#define     TVP3026_XCURCTRL_XWIN	0x03	/* transparent, transparent, 0, 1 */
+#define     TVP3026_XCURCTRL_BLANK2048	0x00
+#define     TVP3026_XCURCTRL_BLANK4096	0x10
+#define     TVP3026_XCURCTRL_INTERLACED	0x20
+#define     TVP3026_XCURCTRL_ODD	0x00 /* ext.signal ODD/\EVEN */
+#define     TVP3026_XCURCTRL_EVEN	0x40 /* ext.signal EVEN/\ODD */
+#define     TVP3026_XCURCTRL_INDIRECT	0x00
+#define     TVP3026_XCURCTRL_DIRECT	0x80
+#define TVP3026_XLATCHCTRL	0x0F
+#define     TVP3026_XLATCHCTRL_1_1	0x06
+#define     TVP3026_XLATCHCTRL_2_1	0x07
+#define     TVP3026_XLATCHCTRL_4_1	0x06
+#define     TVP3026_XLATCHCTRL_8_1	0x06
+#define     TVP3026_XLATCHCTRL_16_1	0x06
+#define     TVP3026A_XLATCHCTRL_4_3	0x06	/* ??? do not understand... but it works... !!! */
+#define     TVP3026A_XLATCHCTRL_8_3	0x07
+#define     TVP3026B_XLATCHCTRL_4_3	0x08
+#define     TVP3026B_XLATCHCTRL_8_3	0x06	/* ??? do not understand... but it works... !!! */
+#define TVP3026_XTRUECOLORCTRL	0x18
+#define     TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_ACCEL	0x00
+#define     TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_TVP	0x20
+#define     TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR		0x80
+#define     TVP3026_XTRUECOLORCTRL_TRUECOLOR		0x40 /* paletized */
+#define     TVP3026_XTRUECOLORCTRL_DIRECTCOLOR		0x00
+#define     TVP3026_XTRUECOLORCTRL_24_ALTERNATE		0x08 /* 5:4/5:2 instead of 4:3/8:3 */
+#define     TVP3026_XTRUECOLORCTRL_RGB_888		0x16 /* 4:3/8:3 (or 5:4/5:2) */
+#define	    TVP3026_XTRUECOLORCTRL_BGR_888		0x17
+#define     TVP3026_XTRUECOLORCTRL_ORGB_8888		0x06
+#define     TVP3026_XTRUECOLORCTRL_BGRO_8888		0x07
+#define     TVP3026_XTRUECOLORCTRL_RGB_565		0x05
+#define     TVP3026_XTRUECOLORCTRL_ORGB_1555		0x04
+#define     TVP3026_XTRUECOLORCTRL_RGB_664		0x03
+#define     TVP3026_XTRUECOLORCTRL_RGBO_4444		0x01
+#define TVP3026_XMUXCTRL	0x19
+#define     TVP3026_XMUXCTRL_MEMORY_8BIT			0x01 /* - */
+#define     TVP3026_XMUXCTRL_MEMORY_16BIT			0x02 /* - */
+#define     TVP3026_XMUXCTRL_MEMORY_32BIT			0x03 /* 2MB RAM, 512K * 4 */
+#define     TVP3026_XMUXCTRL_MEMORY_64BIT			0x04 /* >2MB RAM, 512K * 8 & more */
+#define     TVP3026_XMUXCTRL_PIXEL_4BIT				0x40 /* L0,H0,L1,H1... */
+#define     TVP3026_XMUXCTRL_PIXEL_4BIT_SWAPPED			0x60 /* H0,L0,H1,L1... */
+#define     TVP3026_XMUXCTRL_PIXEL_8BIT				0x48
+#define     TVP3026_XMUXCTRL_PIXEL_16BIT			0x50
+#define     TVP3026_XMUXCTRL_PIXEL_32BIT			0x58
+#define     TVP3026_XMUXCTRL_VGA				0x98 /* VGA MEMORY, 8BIT PIXEL */
+#define TVP3026_XCLKCTRL	0x1A
+#define     TVP3026_XCLKCTRL_DIV1	0x00
+#define     TVP3026_XCLKCTRL_DIV2	0x10
+#define     TVP3026_XCLKCTRL_DIV4	0x20
+#define     TVP3026_XCLKCTRL_DIV8	0x30
+#define     TVP3026_XCLKCTRL_DIV16	0x40
+#define     TVP3026_XCLKCTRL_DIV32	0x50
+#define     TVP3026_XCLKCTRL_DIV64	0x60
+#define     TVP3026_XCLKCTRL_CLKSTOPPED	0x70
+#define     TVP3026_XCLKCTRL_SRC_CLK0	0x00
+#define     TVP3026_XCLKCTRL_SRC_CLK1   0x01
+#define     TVP3026_XCLKCTRL_SRC_CLK2	0x02	/* CLK2 is TTL source*/
+#define     TVP3026_XCLKCTRL_SRC_NCLK2	0x03	/* not CLK2 is TTL source */
+#define     TVP3026_XCLKCTRL_SRC_ECLK2	0x04	/* CLK2 and not CLK2 is ECL source */
+#define     TVP3026_XCLKCTRL_SRC_PLL	0x05
+#define     TVP3026_XCLKCTRL_SRC_DIS	0x06	/* disable & poweroff internal clock */
+#define     TVP3026_XCLKCTRL_SRC_CLK0VGA 0x07
+#define TVP3026_XPALETTEPAGE	0x1C
+#define TVP3026_XGENCTRL	0x1D
+#define     TVP3026_XGENCTRL_HSYNC_POS	0x00
+#define     TVP3026_XGENCTRL_HSYNC_NEG	0x01
+#define     TVP3026_XGENCTRL_VSYNC_POS	0x00
+#define     TVP3026_XGENCTRL_VSYNC_NEG	0x02
+#define     TVP3026_XGENCTRL_LITTLE_ENDIAN 0x00
+#define     TVP3026_XGENCTRL_BIG_ENDIAN    0x08
+#define     TVP3026_XGENCTRL_BLACK_0IRE		0x00
+#define     TVP3026_XGENCTRL_BLACK_75IRE	0x10
+#define     TVP3026_XGENCTRL_NO_SYNC_ON_GREEN	0x00
+#define     TVP3026_XGENCTRL_SYNC_ON_GREEN	0x20
+#define     TVP3026_XGENCTRL_OVERSCAN_DIS	0x00
+#define     TVP3026_XGENCTRL_OVERSCAN_EN	0x40
+#define TVP3026_XMISCCTRL	0x1E
+#define     TVP3026_XMISCCTRL_DAC_PUP	0x00
+#define     TVP3026_XMISCCTRL_DAC_PDOWN	0x01
+#define     TVP3026_XMISCCTRL_DAC_EXT	0x00 /* or 8, bit 3 is ignored */
+#define     TVP3026_XMISCCTRL_DAC_6BIT	0x04
+#define     TVP3026_XMISCCTRL_DAC_8BIT	0x0C
+#define     TVP3026_XMISCCTRL_PSEL_DIS	0x00
+#define     TVP3026_XMISCCTRL_PSEL_EN	0x10
+#define     TVP3026_XMISCCTRL_PSEL_LOW	0x00 /* PSEL high selects directcolor */
+#define     TVP3026_XMISCCTRL_PSEL_HIGH 0x20 /* PSEL high selects truecolor or pseudocolor */
+#define TVP3026_XGENIOCTRL	0x2A
+#define TVP3026_XGENIODATA	0x2B
+#define TVP3026_XPLLADDR	0x2C
+#define     TVP3026_XPLLADDR_X(LOOP,MCLK,PIX) (((LOOP)<<4) | ((MCLK)<<2) | (PIX))
+#define     TVP3026_XPLLDATA_N		0x00
+#define     TVP3026_XPLLDATA_M		0x01
+#define     TVP3026_XPLLDATA_P		0x02
+#define     TVP3026_XPLLDATA_STAT	0x03
+#define TVP3026_XPIXPLLDATA	0x2D
+#define TVP3026_XMEMPLLDATA	0x2E
+#define TVP3026_XLOOPPLLDATA	0x2F
+#define TVP3026_XCOLKEYOVRMIN	0x30
+#define TVP3026_XCOLKEYOVRMAX	0x31
+#define TVP3026_XCOLKEYREDMIN	0x32
+#define TVP3026_XCOLKEYREDMAX	0x33
+#define TVP3026_XCOLKEYGREENMIN	0x34
+#define TVP3026_XCOLKEYGREENMAX	0x35
+#define TVP3026_XCOLKEYBLUEMIN	0x36
+#define TVP3026_XCOLKEYBLUEMAX	0x37
+#define TVP3026_XCOLKEYCTRL	0x38
+#define     TVP3026_XCOLKEYCTRL_OVR_EN	0x01
+#define     TVP3026_XCOLKEYCTRL_RED_EN	0x02
+#define     TVP3026_XCOLKEYCTRL_GREEN_EN 0x04
+#define     TVP3026_XCOLKEYCTRL_BLUE_EN	0x08
+#define     TVP3026_XCOLKEYCTRL_NEGATE	0x10
+#define     TVP3026_XCOLKEYCTRL_ZOOM1	0x00
+#define     TVP3026_XCOLKEYCTRL_ZOOM2	0x20
+#define     TVP3026_XCOLKEYCTRL_ZOOM4	0x40
+#define     TVP3026_XCOLKEYCTRL_ZOOM8	0x60
+#define     TVP3026_XCOLKEYCTRL_ZOOM16	0x80
+#define     TVP3026_XCOLKEYCTRL_ZOOM32	0xA0
+#define TVP3026_XMEMPLLCTRL	0x39
+#define     TVP3026_XMEMPLLCTRL_DIV(X)	(((X)-1)>>1)	/* 2,4,6,8,10,12,14,16, division applied to LOOP PLL after divide by 2^P */
+#define     TVP3026_XMEMPLLCTRL_STROBEMKC4	0x08
+#define     TVP3026_XMEMPLLCTRL_MCLK_DOTCLOCK	0x00	/* MKC4 */
+#define     TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL	0x10	/* MKC4 */
+#define     TVP3026_XMEMPLLCTRL_RCLK_PIXPLL	0x00
+#define     TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL	0x20
+#define     TVP3026_XMEMPLLCTRL_RCLK_DOTDIVN	0x40	/* dot clock divided by loop pclk N prescaler */
+#define TVP3026_XSENSETEST	0x3A
+#define TVP3026_XTESTMODEDATA	0x3B
+#define TVP3026_XCRCREML	0x3C
+#define TVP3026_XCRCREMH	0x3D
+#define TVP3026_XCRCBITSEL	0x3E
+#define TVP3026_XID		0x3F
+
+static const unsigned char DACseq[] =
+{ TVP3026_XLATCHCTRL, TVP3026_XTRUECOLORCTRL,
+  TVP3026_XMUXCTRL, TVP3026_XCLKCTRL,
+  TVP3026_XPALETTEPAGE,
+  TVP3026_XGENCTRL,
+  TVP3026_XMISCCTRL,
+  TVP3026_XGENIOCTRL,
+  TVP3026_XGENIODATA,
+  TVP3026_XCOLKEYOVRMIN, TVP3026_XCOLKEYOVRMAX, TVP3026_XCOLKEYREDMIN, TVP3026_XCOLKEYREDMAX,
+  TVP3026_XCOLKEYGREENMIN, TVP3026_XCOLKEYGREENMAX, TVP3026_XCOLKEYBLUEMIN, TVP3026_XCOLKEYBLUEMAX,
+  TVP3026_XCOLKEYCTRL,
+  TVP3026_XMEMPLLCTRL, TVP3026_XSENSETEST, TVP3026_XCURCTRL };
+
+#define POS3026_XLATCHCTRL	0
+#define POS3026_XTRUECOLORCTRL	1
+#define POS3026_XMUXCTRL	2
+#define POS3026_XCLKCTRL	3
+#define POS3026_XGENCTRL	5
+#define POS3026_XMISCCTRL	6
+#define POS3026_XMEMPLLCTRL	18
+#define POS3026_XCURCTRL	20
+
+static const unsigned char MGADACbpp32[] =
+{ TVP3026_XLATCHCTRL_2_1, TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_8888,
+  0x00, TVP3026_XCLKCTRL_DIV1 | TVP3026_XCLKCTRL_SRC_PLL,
+  0x00,
+  TVP3026_XGENCTRL_HSYNC_POS | TVP3026_XGENCTRL_VSYNC_POS | TVP3026_XGENCTRL_LITTLE_ENDIAN | TVP3026_XGENCTRL_BLACK_0IRE | TVP3026_XGENCTRL_NO_SYNC_ON_GREEN | TVP3026_XGENCTRL_OVERSCAN_DIS,
+  TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_HIGH,
+  0x00,
+  0x1E,
+  0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF,
+  TVP3026_XCOLKEYCTRL_ZOOM1,
+  0x00, 0x00, TVP3026_XCURCTRL_DIS };
+
+static int Ti3026_calcclock(CPMINFO unsigned int freq, unsigned int fmax, int* in, int* feed, int* post) {
+	unsigned int fvco;
+	unsigned int lin, lfeed, lpost;
+
+	DBG(__FUNCTION__)
+
+	fvco = PLL_calcclock(PMINFO freq, fmax, &lin, &lfeed, &lpost);
+	fvco >>= (*post = lpost);
+	*in = 64 - lin;
+	*feed = 64 - lfeed;
+	return fvco;
+}
+
+static int Ti3026_setpclk(WPMINFO int clk) {
+	unsigned int f_pll;
+	unsigned int pixfeed, pixin, pixpost;
+	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
+
+	DBG(__FUNCTION__)
+
+	f_pll = Ti3026_calcclock(PMINFO clk, ACCESS_FBINFO(max_pixel_clock), &pixin, &pixfeed, &pixpost);
+
+	hw->DACclk[0] = pixin | 0xC0;
+	hw->DACclk[1] = pixfeed;
+	hw->DACclk[2] = pixpost | 0xB0;
+
+	{
+		unsigned int loopfeed, loopin, looppost, loopdiv, z;
+		unsigned int Bpp;
+
+		Bpp = ACCESS_FBINFO(curr.final_bppShift);
+
+		if (ACCESS_FBINFO(fbcon).var.bits_per_pixel == 24) {
+			loopfeed = 3;		/* set lm to any possible value */
+			loopin = 3 * 32 / Bpp;
+		} else {
+			loopfeed = 4;
+			loopin = 4 * 32 / Bpp;
+		}
+		z = (110000 * loopin) / (f_pll * loopfeed);
+		loopdiv = 0; /* div 2 */
+		if (z < 2)
+			looppost = 0;
+		else if (z < 4)
+			looppost = 1;
+		else if (z < 8)
+			looppost = 2;
+		else {
+			looppost = 3;
+			loopdiv = z/16;
+		}
+		if (ACCESS_FBINFO(fbcon).var.bits_per_pixel == 24) {
+			hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0;
+			hw->DACclk[4] = (65 - loopfeed) | 0x80;
+			if (ACCESS_FBINFO(accel.ramdac_rev) > 0x20) {
+				if (isInterleave(MINFO))
+					hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_8_3;
+				else {
+					hw->DACclk[4] &= ~0xC0;
+					hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_4_3;
+				}
+			} else {
+				if (isInterleave(MINFO))
+					;	/* default... */
+				else {
+					hw->DACclk[4] ^= 0xC0;	/* change from 0x80 to 0x40 */
+					hw->DACreg[POS3026_XLATCHCTRL] = TVP3026A_XLATCHCTRL_4_3;
+				}
+			}
+			hw->DACclk[5] = looppost | 0xF8;
+			if (ACCESS_FBINFO(devflags.mga_24bpp_fix))
+				hw->DACclk[5] ^= 0x40;
+		} else {
+			hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0;
+			hw->DACclk[4] = 65 - loopfeed;
+			hw->DACclk[5] = looppost | 0xF0;
+		}
+		hw->DACreg[POS3026_XMEMPLLCTRL] = loopdiv | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL;
+	}
+	return 0;
+}
+
+static int Ti3026_init(WPMINFO struct my_timming* m) {
+	u_int8_t muxctrl = isInterleave(MINFO) ? TVP3026_XMUXCTRL_MEMORY_64BIT : TVP3026_XMUXCTRL_MEMORY_32BIT;
+	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
+
+	DBG(__FUNCTION__)
+
+	memcpy(hw->DACreg, MGADACbpp32, sizeof(hw->DACreg));
+	switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
+		case 4:	hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_16_1;	/* or _8_1, they are same */
+			hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
+			hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_4BIT;
+			hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV8;
+			hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW;
+			break;
+		case 8: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_8_1;	/* or _4_1, they are same */
+			hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
+			hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_8BIT;
+			hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4;
+			hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW;
+			break;
+		case 16:
+			/* XLATCHCTRL should be _4_1 / _2_1... Why is not? (_2_1 is used everytime) */
+			hw->DACreg[POS3026_XTRUECOLORCTRL] = (ACCESS_FBINFO(fbcon).var.green.length == 5)? (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_1555 ) : (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_565);
+			hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_16BIT;
+			hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV2;
+			break;
+		case 24:
+			/* XLATCHCTRL is: for (A) use _4_3 (?_8_3 is same? TBD), for (B) it is set in setpclk */
+			hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_888;
+			hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT;
+			hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4;
+			break;
+		case 32:
+			/* XLATCHCTRL should be _2_1 / _1_1... Why is not? (_2_1 is used everytime) */
+			hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT;
+			break;
+		default:
+			return 1;	/* TODO: failed */
+	}
+	if (matroxfb_vgaHWinit(PMINFO m)) return 1;
+
+	/* set SYNC */
+	hw->MiscOutReg = 0xCB;
+	if (m->sync & FB_SYNC_HOR_HIGH_ACT)
+		hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_HSYNC_NEG;
+	if (m->sync & FB_SYNC_VERT_HIGH_ACT)
+		hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_VSYNC_NEG;
+	if (m->sync & FB_SYNC_ON_GREEN)
+		hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_SYNC_ON_GREEN;
+
+	/* set DELAY */
+	if (ACCESS_FBINFO(video.len) < 0x400000)
+		hw->CRTCEXT[3] |= 0x08;
+	else if (ACCESS_FBINFO(video.len) > 0x400000)
+		hw->CRTCEXT[3] |= 0x10;
+
+	/* set HWCURSOR */
+	if (m->interlaced) {
+		hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_INTERLACED;
+	}
+	if (m->HTotal >= 1536)
+		hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_BLANK4096;
+
+	/* set interleaving */
+	hw->MXoptionReg &= ~0x00001000;
+	if (isInterleave(MINFO)) hw->MXoptionReg |= 0x00001000;
+
+	/* set DAC */
+	Ti3026_setpclk(PMINFO m->pixclock);
+	return 0;
+}
+
+static void ti3026_setMCLK(WPMINFO int fout){
+	unsigned int f_pll;
+	unsigned int pclk_m, pclk_n, pclk_p;
+	unsigned int mclk_m, mclk_n, mclk_p;
+	unsigned int rfhcnt, mclk_ctl;
+	int tmout;
+
+	DBG(__FUNCTION__)
+
+	f_pll = Ti3026_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &mclk_n, &mclk_m, &mclk_p);
+
+	/* save pclk */
+	outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC);
+	pclk_n = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
+	outTi3026(PMINFO TVP3026_XPLLADDR, 0xFD);
+	pclk_m = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
+	outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE);
+	pclk_p = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
+
+	/* stop pclk */
+	outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE);
+	outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00);
+
+	/* set pclk to new mclk */
+	outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC);
+	outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_n | 0xC0);
+	outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_m);
+	outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_p | 0xB0);
+
+	/* wait for PLL to lock */
+	for (tmout = 500000; tmout; tmout--) {
+		if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40)
+			break;
+		udelay(10);
+	};
+	if (!tmout)
+		printk(KERN_ERR "matroxfb: Temporary pixel PLL not locked after 5 secs\n");
+
+	/* output pclk on mclk pin */
+	mclk_ctl = inTi3026(PMINFO TVP3026_XMEMPLLCTRL);
+	outTi3026(PMINFO TVP3026_XMEMPLLCTRL, mclk_ctl & 0xE7);
+	outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_STROBEMKC4);
+
+	/* stop MCLK */
+	outTi3026(PMINFO TVP3026_XPLLADDR, 0xFB);
+	outTi3026(PMINFO TVP3026_XMEMPLLDATA, 0x00);
+
+	/* set mclk to new freq */
+	outTi3026(PMINFO TVP3026_XPLLADDR, 0xF3);
+	outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_n | 0xC0);
+	outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_m);
+	outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_p | 0xB0);
+
+	/* wait for PLL to lock */
+	for (tmout = 500000; tmout; tmout--) {
+		if (inTi3026(PMINFO TVP3026_XMEMPLLDATA) & 0x40)
+			break;
+		udelay(10);
+	}
+	if (!tmout)
+		printk(KERN_ERR "matroxfb: Memory PLL not locked after 5 secs\n");
+
+	f_pll = f_pll * 333 / (10000 << mclk_p);
+	if (isMilleniumII(MINFO)) {
+		rfhcnt = (f_pll - 128) / 256;
+		if (rfhcnt > 15)
+			rfhcnt = 15;
+	} else {
+		rfhcnt = (f_pll - 64) / 128;
+		if (rfhcnt > 15)
+			rfhcnt = 0;
+	}
+	ACCESS_FBINFO(hw).MXoptionReg = (ACCESS_FBINFO(hw).MXoptionReg & ~0x000F0000) | (rfhcnt << 16);
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg);
+
+	/* output MCLK to MCLK pin */
+	outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL);
+	outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl       ) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_STROBEMKC4);
+
+	/* stop PCLK */
+	outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE);
+	outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00);
+
+	/* restore pclk */
+	outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC);
+	outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_n);
+	outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_m);
+	outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_p);
+
+	/* wait for PLL to lock */
+	for (tmout = 500000; tmout; tmout--) {
+		if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40)
+			break;
+		udelay(10);
+	}
+	if (!tmout)
+		printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
+}
+
+static void ti3026_ramdac_init(WPMINFO2) {
+
+	DBG(__FUNCTION__)
+
+	ACCESS_FBINFO(features.pll.vco_freq_min) = 110000;
+	ACCESS_FBINFO(features.pll.ref_freq)	 = 114545;
+	ACCESS_FBINFO(features.pll.feed_div_min) = 2;
+	ACCESS_FBINFO(features.pll.feed_div_max) = 24;
+	ACCESS_FBINFO(features.pll.in_div_min)	 = 2;
+	ACCESS_FBINFO(features.pll.in_div_max)	 = 63;
+	ACCESS_FBINFO(features.pll.post_shift_max) = 3;
+	if (ACCESS_FBINFO(devflags.noinit))
+		return;
+	ti3026_setMCLK(PMINFO 60000);
+}
+
+static void Ti3026_restore(WPMINFO2) {
+	int i;
+	unsigned char progdac[6];
+	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
+	CRITFLAGS
+
+	DBG(__FUNCTION__)
+
+#ifdef DEBUG
+	dprintk(KERN_INFO "EXTVGA regs: ");
+	for (i = 0; i < 6; i++)
+		dprintk("%02X:", hw->CRTCEXT[i]);
+	dprintk("\n");
+#endif
+
+	CRITBEGIN
+
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+
+	CRITEND
+
+	matroxfb_vgaHWrestore(PMINFO2);
+
+	CRITBEGIN
+
+	ACCESS_FBINFO(crtc1.panpos) = -1;
+	for (i = 0; i < 6; i++)
+		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
+
+	for (i = 0; i < 21; i++) {
+		outTi3026(PMINFO DACseq[i], hw->DACreg[i]);
+	}
+
+	outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
+	progdac[0] = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
+	progdac[3] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA);
+	outTi3026(PMINFO TVP3026_XPLLADDR, 0x15);
+	progdac[1] = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
+	progdac[4] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA);
+	outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
+	progdac[2] = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
+	progdac[5] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA);
+
+	CRITEND
+	if (memcmp(hw->DACclk, progdac, 6)) {
+		/* agrhh... setting up PLL is very slow on Millennium... */
+		/* Mystique PLL is locked in few ms, but Millennium PLL lock takes about 0.15 s... */
+		/* Maybe even we should call schedule() ? */
+
+		CRITBEGIN
+		outTi3026(PMINFO TVP3026_XCLKCTRL, hw->DACreg[POS3026_XCLKCTRL]);
+		outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
+		outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0);
+		outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0);
+
+		outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
+		for (i = 0; i < 3; i++)
+			outTi3026(PMINFO TVP3026_XPIXPLLDATA, hw->DACclk[i]);
+		/* wait for PLL only if PLL clock requested (always for PowerMode, never for VGA) */
+		if (hw->MiscOutReg & 0x08) {
+			int tmout;
+			outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F);
+			for (tmout = 500000; tmout; --tmout) {
+				if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40)
+					break;
+				udelay(10);
+			}
+
+			CRITEND
+
+			if (!tmout)
+				printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
+			else
+				dprintk(KERN_INFO "PixelPLL: %d\n", 500000-tmout);
+			CRITBEGIN
+		}
+		outTi3026(PMINFO TVP3026_XMEMPLLCTRL, hw->DACreg[POS3026_XMEMPLLCTRL]);
+		outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
+		for (i = 3; i < 6; i++)
+			outTi3026(PMINFO TVP3026_XLOOPPLLDATA, hw->DACclk[i]);
+		CRITEND
+		if ((hw->MiscOutReg & 0x08) && ((hw->DACclk[5] & 0x80) == 0x80)) {
+			int tmout;
+
+			CRITBEGIN
+			outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F);
+			for (tmout = 500000; tmout; --tmout) {
+				if (inTi3026(PMINFO TVP3026_XLOOPPLLDATA) & 0x40)
+					break;
+				udelay(10);
+			}
+			CRITEND
+			if (!tmout)
+				printk(KERN_ERR "matroxfb: Loop PLL not locked after 5 secs\n");
+			else
+				dprintk(KERN_INFO "LoopPLL: %d\n", 500000-tmout);
+		}
+	}
+
+#ifdef DEBUG
+	dprintk(KERN_DEBUG "3026DACregs ");
+	for (i = 0; i < 21; i++) {
+		dprintk("R%02X=%02X ", DACseq[i], hw->DACreg[i]);
+		if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... ");
+	}
+	dprintk("\n" KERN_DEBUG "DACclk ");
+	for (i = 0; i < 6; i++)
+		dprintk("C%02X=%02X ", i, hw->DACclk[i]);
+	dprintk("\n");
+#endif
+}
+
+static void Ti3026_reset(WPMINFO2) {
+
+	DBG(__FUNCTION__)
+
+	ti3026_ramdac_init(PMINFO2);
+}
+
+static struct matrox_altout ti3026_output = {
+	.name	 = "Primary output",
+};
+
+static int Ti3026_preinit(WPMINFO2) {
+	static const int vxres_mill2[] = { 512,        640, 768,  800,  832,  960,
+					  1024, 1152, 1280,      1600, 1664, 1920,
+					  2048, 0};
+	static const int vxres_mill1[] = {             640, 768,  800,        960,
+					  1024, 1152, 1280,      1600,       1920,
+					  2048, 0};
+	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
+
+	DBG(__FUNCTION__)
+
+	ACCESS_FBINFO(millenium) = 1;
+	ACCESS_FBINFO(milleniumII) = (ACCESS_FBINFO(pcidev)->device != PCI_DEVICE_ID_MATROX_MIL);
+	ACCESS_FBINFO(capable.cfb4) = 1;
+	ACCESS_FBINFO(capable.text) = 1; /* isMilleniumII(MINFO); */
+	ACCESS_FBINFO(capable.vxres) = isMilleniumII(MINFO)?vxres_mill2:vxres_mill1;
+
+	ACCESS_FBINFO(outputs[0]).data = MINFO;
+	ACCESS_FBINFO(outputs[0]).output = &ti3026_output;
+	ACCESS_FBINFO(outputs[0]).src = ACCESS_FBINFO(outputs[0]).default_src;
+	ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+
+	if (ACCESS_FBINFO(devflags.noinit))
+		return 0;
+	/* preserve VGA I/O, BIOS and PPC */
+	hw->MXoptionReg &= 0xC0000100;
+	hw->MXoptionReg |= 0x002C0000;
+	if (ACCESS_FBINFO(devflags.novga))
+		hw->MXoptionReg &= ~0x00000100;
+	if (ACCESS_FBINFO(devflags.nobios))
+		hw->MXoptionReg &= ~0x40000000;
+	if (ACCESS_FBINFO(devflags.nopciretry))
+		hw->MXoptionReg |=  0x20000000;
+	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+
+	ACCESS_FBINFO(accel.ramdac_rev) = inTi3026(PMINFO TVP3026_XSILICONREV);
+
+	outTi3026(PMINFO TVP3026_XCLKCTRL, TVP3026_XCLKCTRL_SRC_CLK0VGA | TVP3026_XCLKCTRL_CLKSTOPPED);
+	outTi3026(PMINFO TVP3026_XTRUECOLORCTRL, TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR);
+	outTi3026(PMINFO TVP3026_XMUXCTRL, TVP3026_XMUXCTRL_VGA);
+
+	outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
+	outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0x00);
+	outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00);
+
+	mga_outb(M_MISC_REG, 0x67);
+
+	outTi3026(PMINFO TVP3026_XMEMPLLCTRL, TVP3026_XMEMPLLCTRL_STROBEMKC4 | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL);
+
+	mga_outl(M_RESET, 1);
+	udelay(250);
+	mga_outl(M_RESET, 0);
+	udelay(250);
+	mga_outl(M_MACCESS, 0x00008000);
+	udelay(10);
+	return 0;
+}
+
+struct matrox_switch matrox_millennium = {
+	Ti3026_preinit, Ti3026_reset, Ti3026_init, Ti3026_restore
+};
+EXPORT_SYMBOL(matrox_millennium);
+#endif
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/matrox/matroxfb_Ti3026.h b/drivers/video/matrox/matroxfb_Ti3026.h
new file mode 100644
index 0000000..541933d
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_Ti3026.h
@@ -0,0 +1,13 @@
+#ifndef __MATROXFB_TI3026_H__
+#define __MATROXFB_TI3026_H__
+
+/* make checkconfig does not walk through whole include tree */
+#include <linux/config.h>
+
+#include "matroxfb_base.h"
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+extern struct matrox_switch matrox_millennium;
+#endif
+
+#endif	/* __MATROXFB_TI3026_H__ */
diff --git a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c
new file mode 100644
index 0000000..c7f3e13
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_accel.c
@@ -0,0 +1,497 @@
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
+ *
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Version: 1.65 2002/08/14
+ *
+ * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
+ *
+ * Contributors: "menion?" <menion@mindless.com>
+ *                     Betatesting, fixes, ideas
+ *
+ *               "Kurt Garloff" <garloff@suse.de>
+ *                     Betatesting, fixes, ideas, videomodes, videomodes timmings
+ *
+ *               "Tom Rini" <trini@kernel.crashing.org>
+ *                     MTRR stuff, PPC cleanups, betatesting, fixes, ideas
+ *
+ *               "Bibek Sahu" <scorpio@dodds.net>
+ *                     Access device through readb|w|l and write b|w|l
+ *                     Extensive debugging stuff
+ *
+ *               "Daniel Haun" <haund@usa.net>
+ *                     Testing, hardware cursor fixes
+ *
+ *               "Scott Wood" <sawst46+@pitt.edu>
+ *                     Fixes
+ *
+ *               "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
+ *                     Betatesting
+ *
+ *               "Kelly French" <targon@hazmat.com>
+ *               "Fernando Herrera" <fherrera@eurielec.etsit.upm.es>
+ *                     Betatesting, bug reporting
+ *
+ *               "Pablo Bianucci" <pbian@pccp.com.ar>
+ *                     Fixes, ideas, betatesting
+ *
+ *               "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
+ *                     Fixes, enhandcements, ideas, betatesting
+ *
+ *               "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
+ *                     PPC betatesting, PPC support, backward compatibility
+ *
+ *               "Paul Womar" <Paul@pwomar.demon.co.uk>
+ *               "Owen Waller" <O.Waller@ee.qub.ac.uk>
+ *                     PPC betatesting
+ *
+ *               "Thomas Pornin" <pornin@bolet.ens.fr>
+ *                     Alpha betatesting
+ *
+ *               "Pieter van Leuven" <pvl@iae.nl>
+ *               "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de>
+ *                     G100 testing
+ *
+ *               "H. Peter Arvin" <hpa@transmeta.com>
+ *                     Ideas
+ *
+ *               "Cort Dougan" <cort@cs.nmt.edu>
+ *                     CHRP fixes and PReP cleanup
+ *
+ *               "Mark Vojkovich" <mvojkovi@ucsd.edu>
+ *                     G400 support
+ *
+ * (following author is not in any relation with this code, but his code
+ *  is included in this driver)
+ *
+ * Based on framebuffer driver for VBE 2.0 compliant graphic boards
+ *     (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ * (following author is not in any relation with this code, but his ideas
+ *  were used when writting this driver)
+ *
+ *		 FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
+ *
+ */
+
+#include "matroxfb_accel.h"
+#include "matroxfb_DAC1064.h"
+#include "matroxfb_Ti3026.h"
+#include "matroxfb_misc.h"
+
+#define curr_ydstorg(x)	ACCESS_FBINFO2(x, curr.ydstorg.pixels)
+
+#define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l))
+
+static inline void matrox_cfb4_pal(u_int32_t* pal) {
+	unsigned int i;
+	
+	for (i = 0; i < 16; i++) {
+		pal[i] = i * 0x11111111U;
+	}
+	pal[i] = 0xFFFFFFFF;
+}
+
+static inline void matrox_cfb8_pal(u_int32_t* pal) {
+	unsigned int i;
+	
+	for (i = 0; i < 16; i++) {
+		pal[i] = i * 0x01010101U;
+	}
+	pal[i] = 0x0F0F0F0F;
+}
+
+static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area);
+static void matroxfb_fillrect(struct fb_info* info, const struct fb_fillrect* rect);
+static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* image);
+static void matroxfb_cfb4_fillrect(struct fb_info* info, const struct fb_fillrect* rect);
+static void matroxfb_cfb4_copyarea(struct fb_info* info, const struct fb_copyarea* area);
+
+void matrox_cfbX_init(WPMINFO2) {
+	u_int32_t maccess;
+	u_int32_t mpitch;
+	u_int32_t mopmode;
+	int accel;
+
+	DBG(__FUNCTION__)
+
+	mpitch = ACCESS_FBINFO(fbcon).var.xres_virtual;
+
+	ACCESS_FBINFO(fbops).fb_copyarea = cfb_copyarea;
+	ACCESS_FBINFO(fbops).fb_fillrect = cfb_fillrect;
+	ACCESS_FBINFO(fbops).fb_imageblit = cfb_imageblit;
+	ACCESS_FBINFO(fbops).fb_cursor = soft_cursor;
+
+	accel = (ACCESS_FBINFO(fbcon).var.accel_flags & FB_ACCELF_TEXT) == FB_ACCELF_TEXT;
+
+	switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
+		case 4:		maccess = 0x00000000;	/* accelerate as 8bpp video */
+				mpitch = (mpitch >> 1) | 0x8000; /* disable linearization */
+				mopmode = M_OPMODE_4BPP;
+				matrox_cfb4_pal(ACCESS_FBINFO(cmap));
+				if (accel && !(mpitch & 1)) {
+					ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_cfb4_copyarea;
+					ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_cfb4_fillrect;
+				}
+				break;
+		case 8:		maccess = 0x00000000;
+				mopmode = M_OPMODE_8BPP;
+				matrox_cfb8_pal(ACCESS_FBINFO(cmap));
+				if (accel) {
+					ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea;
+					ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect;
+					ACCESS_FBINFO(fbops).fb_imageblit = matroxfb_imageblit;
+				}
+				break;
+		case 16:	if (ACCESS_FBINFO(fbcon).var.green.length == 5) {
+					maccess = 0xC0000001;
+					ACCESS_FBINFO(cmap[16]) = 0x7FFF7FFF;
+				} else {
+					maccess = 0x40000001;
+					ACCESS_FBINFO(cmap[16]) = 0xFFFFFFFF;
+				}
+				mopmode = M_OPMODE_16BPP;
+				if (accel) {
+					ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea;
+					ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect;
+					ACCESS_FBINFO(fbops).fb_imageblit = matroxfb_imageblit;
+				}
+				break;
+		case 24:	maccess = 0x00000003;
+				mopmode = M_OPMODE_24BPP;
+				ACCESS_FBINFO(cmap[16]) = 0xFFFFFFFF;
+				if (accel) {
+					ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea;
+					ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect;
+					ACCESS_FBINFO(fbops).fb_imageblit = matroxfb_imageblit;
+				}
+				break;
+		case 32:	maccess = 0x00000002;
+				mopmode = M_OPMODE_32BPP;
+				ACCESS_FBINFO(cmap[16]) = 0xFFFFFFFF;
+				if (accel) {
+					ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea;
+					ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect;
+					ACCESS_FBINFO(fbops).fb_imageblit = matroxfb_imageblit;
+				}
+				break;
+		default:	maccess = 0x00000000;
+				mopmode = 0x00000000;
+				break;	/* turn off acceleration!!! */
+	}
+	mga_fifo(8);
+	mga_outl(M_PITCH, mpitch);
+	mga_outl(M_YDSTORG, curr_ydstorg(MINFO));
+	if (ACCESS_FBINFO(capable.plnwt))
+		mga_outl(M_PLNWT, -1);
+	if (ACCESS_FBINFO(capable.srcorg)) {
+		mga_outl(M_SRCORG, 0);
+		mga_outl(M_DSTORG, 0);
+	}
+	mga_outl(M_OPMODE, mopmode);
+	mga_outl(M_CXBNDRY, 0xFFFF0000);
+	mga_outl(M_YTOP, 0);
+	mga_outl(M_YBOT, 0x01FFFFFF);
+	mga_outl(M_MACCESS, maccess);
+	ACCESS_FBINFO(accel.m_dwg_rect) = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO;
+	if (isMilleniumII(MINFO)) ACCESS_FBINFO(accel.m_dwg_rect) |= M_DWG_TRANSC;
+	ACCESS_FBINFO(accel.m_opmode) = mopmode;
+}
+
+EXPORT_SYMBOL(matrox_cfbX_init);
+
+static void matrox_accel_bmove(WPMINFO int vxres, int sy, int sx, int dy, int dx, int height, int width) {
+	int start, end;
+	CRITFLAGS
+
+	DBG(__FUNCTION__)
+
+	CRITBEGIN
+
+	if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
+		mga_fifo(2);
+		mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
+			 M_DWG_BFCOL | M_DWG_REPLACE);
+		mga_outl(M_AR5, vxres);
+		width--;
+		start = sy*vxres+sx+curr_ydstorg(MINFO);
+		end = start+width;
+	} else {
+		mga_fifo(3);
+		mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
+		mga_outl(M_SGN, 5);
+		mga_outl(M_AR5, -vxres);
+		width--;
+		end = (sy+height-1)*vxres+sx+curr_ydstorg(MINFO);
+		start = end+width;
+		dy += height-1;
+	}
+	mga_fifo(4);
+	mga_outl(M_AR0, end);
+	mga_outl(M_AR3, start);
+	mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
+	mga_ydstlen(dy, height);
+	WaitTillIdle();
+
+	CRITEND
+}
+
+static void matrox_accel_bmove_lin(WPMINFO int vxres, int sy, int sx, int dy, int dx, int height, int width) {
+	int start, end;
+	CRITFLAGS
+
+	DBG(__FUNCTION__)
+
+	CRITBEGIN
+
+	if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
+		mga_fifo(2);
+		mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
+			M_DWG_BFCOL | M_DWG_REPLACE);
+		mga_outl(M_AR5, vxres);
+		width--;
+		start = sy*vxres+sx+curr_ydstorg(MINFO);
+		end = start+width;
+	} else {
+		mga_fifo(3);
+		mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
+		mga_outl(M_SGN, 5);
+		mga_outl(M_AR5, -vxres);
+		width--;
+		end = (sy+height-1)*vxres+sx+curr_ydstorg(MINFO);
+		start = end+width;
+		dy += height-1;
+	}
+	mga_fifo(5);
+	mga_outl(M_AR0, end);
+	mga_outl(M_AR3, start);
+	mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
+	mga_outl(M_YDST, dy*vxres >> 5);
+	mga_outl(M_LEN | M_EXEC, height);
+	WaitTillIdle();
+
+	CRITEND
+}
+
+static void matroxfb_cfb4_copyarea(struct fb_info* info, const struct fb_copyarea* area) {
+	MINFO_FROM_INFO(info);
+
+	if ((area->sx | area->dx | area->width) & 1)
+		cfb_copyarea(info, area);
+	else
+		matrox_accel_bmove_lin(PMINFO ACCESS_FBINFO(fbcon.var.xres_virtual) >> 1, area->sy, area->sx >> 1, area->dy, area->dx >> 1, area->height, area->width >> 1);
+}
+
+static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area) {
+	MINFO_FROM_INFO(info);
+
+	matrox_accel_bmove(PMINFO ACCESS_FBINFO(fbcon.var.xres_virtual), area->sy, area->sx, area->dy, area->dx, area->height, area->width);
+}
+
+static void matroxfb_accel_clear(WPMINFO u_int32_t color, int sy, int sx, int height,
+		int width) {
+	CRITFLAGS
+
+	DBG(__FUNCTION__)
+
+	CRITBEGIN
+
+	mga_fifo(5);
+	mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE);
+	mga_outl(M_FCOL, color);
+	mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
+	mga_ydstlen(sy, height);
+	WaitTillIdle();
+
+	CRITEND
+}
+
+static void matroxfb_fillrect(struct fb_info* info, const struct fb_fillrect* rect) {
+	MINFO_FROM_INFO(info);
+
+	switch (rect->rop) {
+		case ROP_COPY:
+			matroxfb_accel_clear(PMINFO ((u_int32_t*)info->pseudo_palette)[rect->color], rect->dy, rect->dx, rect->height, rect->width);
+			break;
+	}
+}
+
+static void matroxfb_cfb4_clear(WPMINFO u_int32_t bgx, int sy, int sx, int height, int width) {
+	int whattodo;
+	CRITFLAGS
+
+	DBG(__FUNCTION__)
+
+	CRITBEGIN
+
+	whattodo = 0;
+	if (sx & 1) {
+		sx ++;
+		if (!width) return;
+		width --;
+		whattodo = 1;
+	}
+	if (width & 1) {
+		whattodo |= 2;
+	}
+	width >>= 1;
+	sx >>= 1;
+	if (width) {
+		mga_fifo(5);
+		mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE2);
+		mga_outl(M_FCOL, bgx);
+		mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
+		mga_outl(M_YDST, sy * ACCESS_FBINFO(fbcon).var.xres_virtual >> 6);
+		mga_outl(M_LEN | M_EXEC, height);
+		WaitTillIdle();
+	}
+	if (whattodo) {
+		u_int32_t step = ACCESS_FBINFO(fbcon).var.xres_virtual >> 1;
+		vaddr_t vbase = ACCESS_FBINFO(video.vbase);
+		if (whattodo & 1) {
+			unsigned int uaddr = sy * step + sx - 1;
+			u_int32_t loop;
+			u_int8_t bgx2 = bgx & 0xF0;
+			for (loop = height; loop > 0; loop --) {
+				mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0x0F) | bgx2);
+				uaddr += step;
+			}
+		}
+		if (whattodo & 2) {
+			unsigned int uaddr = sy * step + sx + width;
+			u_int32_t loop;
+			u_int8_t bgx2 = bgx & 0x0F;
+			for (loop = height; loop > 0; loop --) {
+				mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0xF0) | bgx2);
+				uaddr += step;
+			}
+		}
+	}
+
+	CRITEND
+}
+
+static void matroxfb_cfb4_fillrect(struct fb_info* info, const struct fb_fillrect* rect) {
+	MINFO_FROM_INFO(info);
+
+	switch (rect->rop) {
+		case ROP_COPY:
+			matroxfb_cfb4_clear(PMINFO ((u_int32_t*)info->pseudo_palette)[rect->color], rect->dy, rect->dx, rect->height, rect->width);
+			break;
+	}
+}
+
+static void matroxfb_1bpp_imageblit(WPMINFO u_int32_t fgx, u_int32_t bgx,
+		const u_int8_t* chardata, int width, int height, int yy, int xx) {
+	u_int32_t step;
+	u_int32_t ydstlen;
+	u_int32_t xlen;
+	u_int32_t ar0;
+	u_int32_t charcell;
+	u_int32_t fxbndry;
+	vaddr_t mmio;
+	int easy;
+	CRITFLAGS
+
+	DBG_HEAVY(__FUNCTION__);
+
+	step = (width + 7) >> 3;
+	charcell = height * step;
+	xlen = (charcell + 3) & ~3;
+	ydstlen = (yy << 16) | height;
+	if (width == step << 3) {
+		ar0 = height * width - 1;
+		easy = 1;
+	} else {
+		ar0 = width - 1;
+		easy = 0;
+	}
+
+	CRITBEGIN
+
+	mga_fifo(3);
+	if (easy)
+		mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
+	else
+		mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_REPLACE);
+	mga_outl(M_FCOL, fgx);
+	mga_outl(M_BCOL, bgx);
+	fxbndry = ((xx + width - 1) << 16) | xx;
+	mmio = ACCESS_FBINFO(mmio.vbase);
+
+	mga_fifo(6);
+	mga_writel(mmio, M_FXBNDRY, fxbndry);
+	mga_writel(mmio, M_AR0, ar0);
+	mga_writel(mmio, M_AR3, 0);
+	if (easy) {
+		mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen);
+		mga_memcpy_toio(mmio, chardata, xlen);
+	} else {
+		mga_writel(mmio, M_AR5, 0);
+		mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen);
+		if ((step & 3) == 0) {
+			/* Great. Source has 32bit aligned lines, so we can feed them
+			   directly to the accelerator. */
+			mga_memcpy_toio(mmio, chardata, charcell);
+		} else if (step == 1) {
+			/* Special case for 1..8bit widths */
+			while (height--) {
+#if defined(__BIG_ENDIAN)
+				fb_writel((*chardata) << 24, mmio.vaddr);
+#else
+				fb_writel(*chardata, mmio.vaddr);
+#endif
+				chardata++;
+			}
+		} else if (step == 2) {
+			/* Special case for 9..15bit widths */
+			while (height--) {
+#if defined(__BIG_ENDIAN)
+				fb_writel((*(u_int16_t*)chardata) << 16, mmio.vaddr);
+#else
+				fb_writel(*(u_int16_t*)chardata, mmio.vaddr);
+#endif
+				chardata += 2;
+			}
+		} else {
+			/* Tell... well, why bother... */
+			while (height--) {
+				size_t i;
+				
+				for (i = 0; i < step; i += 4) {
+					/* Hope that there are at least three readable bytes beyond the end of bitmap */
+					fb_writel(get_unaligned((u_int32_t*)(chardata + i)),mmio.vaddr);
+				}
+				chardata += step;
+			}
+		}
+	}
+	WaitTillIdle();
+	CRITEND
+}
+
+
+static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* image) {
+	MINFO_FROM_INFO(info);
+
+	DBG_HEAVY(__FUNCTION__);
+
+	if (image->depth == 1) {
+		u_int32_t fgx, bgx;
+
+		fgx = ((u_int32_t*)info->pseudo_palette)[image->fg_color];
+		bgx = ((u_int32_t*)info->pseudo_palette)[image->bg_color];
+		matroxfb_1bpp_imageblit(PMINFO fgx, bgx, image->data, image->width, image->height, image->dy, image->dx);
+	} else {
+		/* Danger! image->depth is useless: logo painting code always
+		   passes framebuffer color depth here, although logo data are
+		   always 8bpp and info->pseudo_palette is changed to contain
+		   logo palette to be used (but only for true/direct-color... sic...).
+		   So do it completely in software... */
+		cfb_imageblit(info, image);
+	}
+}
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/matrox/matroxfb_accel.h b/drivers/video/matrox/matroxfb_accel.h
new file mode 100644
index 0000000..f40c314
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_accel.h
@@ -0,0 +1,8 @@
+#ifndef __MATROXFB_ACCEL_H__
+#define __MATROXFB_ACCEL_H__
+
+#include "matroxfb_base.h"
+
+void matrox_cfbX_init(WPMINFO2);
+
+#endif
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
new file mode 100644
index 0000000..98e00d8
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -0,0 +1,2589 @@
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
+ *
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Portions Copyright (c) 2001 Matrox Graphics Inc.
+ *
+ * Version: 1.65 2002/08/14
+ *
+ * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
+ *
+ * Contributors: "menion?" <menion@mindless.com>
+ *                     Betatesting, fixes, ideas
+ *
+ *               "Kurt Garloff" <garloff@suse.de>
+ *                     Betatesting, fixes, ideas, videomodes, videomodes timmings
+ *
+ *               "Tom Rini" <trini@kernel.crashing.org>
+ *                     MTRR stuff, PPC cleanups, betatesting, fixes, ideas
+ *
+ *               "Bibek Sahu" <scorpio@dodds.net>
+ *                     Access device through readb|w|l and write b|w|l
+ *                     Extensive debugging stuff
+ *
+ *               "Daniel Haun" <haund@usa.net>
+ *                     Testing, hardware cursor fixes
+ *
+ *               "Scott Wood" <sawst46+@pitt.edu>
+ *                     Fixes
+ *
+ *               "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
+ *                     Betatesting
+ *
+ *               "Kelly French" <targon@hazmat.com>
+ *               "Fernando Herrera" <fherrera@eurielec.etsit.upm.es>
+ *                     Betatesting, bug reporting
+ *
+ *               "Pablo Bianucci" <pbian@pccp.com.ar>
+ *                     Fixes, ideas, betatesting
+ *
+ *               "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
+ *                     Fixes, enhandcements, ideas, betatesting
+ *
+ *               "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
+ *                     PPC betatesting, PPC support, backward compatibility
+ *
+ *               "Paul Womar" <Paul@pwomar.demon.co.uk>
+ *               "Owen Waller" <O.Waller@ee.qub.ac.uk>
+ *                     PPC betatesting
+ *
+ *               "Thomas Pornin" <pornin@bolet.ens.fr>
+ *                     Alpha betatesting
+ *
+ *               "Pieter van Leuven" <pvl@iae.nl>
+ *               "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de>
+ *                     G100 testing
+ *
+ *               "H. Peter Arvin" <hpa@transmeta.com>
+ *                     Ideas
+ *
+ *               "Cort Dougan" <cort@cs.nmt.edu>
+ *                     CHRP fixes and PReP cleanup
+ *
+ *               "Mark Vojkovich" <mvojkovi@ucsd.edu>
+ *                     G400 support
+ *
+ *               "Samuel Hocevar" <sam@via.ecp.fr>
+ *                     Fixes
+ *
+ *               "Anton Altaparmakov" <AntonA@bigfoot.com>
+ *                     G400 MAX/non-MAX distinction
+ *
+ *               "Ken Aaker" <kdaaker@rchland.vnet.ibm.com>
+ *                     memtype extension (needed for GXT130P RS/6000 adapter)
+ *
+ *               "Uns Lider" <unslider@miranda.org>
+ *                     G100 PLNWT fixes
+ *
+ *               "Denis Zaitsev" <zzz@cd-club.ru>
+ *                     Fixes
+ *
+ *               "Mike Pieper" <mike@pieper-family.de>
+ *                     TVOut enhandcements, V4L2 control interface.
+ *
+ *               "Diego Biurrun" <diego@biurrun.de>
+ *                     DFP testing
+ *
+ * (following author is not in any relation with this code, but his code
+ *  is included in this driver)
+ *
+ * Based on framebuffer driver for VBE 2.0 compliant graphic boards
+ *     (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ * (following author is not in any relation with this code, but his ideas
+ *  were used when writting this driver)
+ *
+ *		 FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
+ *
+ */
+
+/* make checkconfig does not check included files... */
+#include <linux/config.h>
+#include <linux/version.h>
+
+#include "matroxfb_base.h"
+#include "matroxfb_misc.h"
+#include "matroxfb_accel.h"
+#include "matroxfb_DAC1064.h"
+#include "matroxfb_Ti3026.h"
+#include "matroxfb_maven.h"
+#include "matroxfb_crtc2.h"
+#include "matroxfb_g450.h"
+#include <linux/matroxfb.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_PPC_PMAC
+unsigned char nvram_read_byte(int);
+static int default_vmode = VMODE_NVRAM;
+static int default_cmode = CMODE_NVRAM;
+#endif
+
+static void matroxfb_unregister_device(struct matrox_fb_info* minfo);
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * card parameters
+ */
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_var_screeninfo vesafb_defined = {
+	640,480,640,480,/* W,H, W, H (virtual) load xres,xres_virtual*/
+	0,0,		/* virtual -> visible no offset */
+	8,		/* depth -> load bits_per_pixel */
+	0,		/* greyscale ? */
+	{0,0,0},	/* R */
+	{0,0,0},	/* G */
+	{0,0,0},	/* B */
+	{0,0,0},	/* transparency */
+	0,		/* standard pixel format */
+	FB_ACTIVATE_NOW,
+	-1,-1,
+	FB_ACCELF_TEXT,	/* accel flags */
+	39721L,48L,16L,33L,10L,
+	96L,2L,~0,	/* No sync info */
+	FB_VMODE_NONINTERLACED,
+	0, {0,0,0,0,0}
+};
+
+
+
+/* --------------------------------------------------------------------- */
+static void update_crtc2(WPMINFO unsigned int pos) {
+	struct matroxfb_dh_fb_info* info = ACCESS_FBINFO(crtc2.info);
+
+	/* Make sure that displays are compatible */
+	if (info && (info->fbcon.var.bits_per_pixel == ACCESS_FBINFO(fbcon).var.bits_per_pixel)
+	         && (info->fbcon.var.xres_virtual == ACCESS_FBINFO(fbcon).var.xres_virtual)
+	         && (info->fbcon.var.green.length == ACCESS_FBINFO(fbcon).var.green.length)
+	         ) {
+		switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
+			case 16:
+			case 32:
+				pos = pos * 8;
+				if (info->interlaced) {
+					mga_outl(0x3C2C, pos);
+					mga_outl(0x3C28, pos + ACCESS_FBINFO(fbcon).var.xres_virtual * ACCESS_FBINFO(fbcon).var.bits_per_pixel / 8);
+				} else {
+					mga_outl(0x3C28, pos);
+				}
+				break;
+		}
+	}
+}
+
+static void matroxfb_crtc1_panpos(WPMINFO2) {
+	if (ACCESS_FBINFO(crtc1.panpos) >= 0) {
+		unsigned long flags;
+		int panpos;
+
+		matroxfb_DAC_lock_irqsave(flags);
+		panpos = ACCESS_FBINFO(crtc1.panpos);
+		if (panpos >= 0) {
+			unsigned int extvga_reg;
+
+			ACCESS_FBINFO(crtc1.panpos) = -1; /* No update pending anymore */
+			extvga_reg = mga_inb(M_EXTVGA_INDEX);
+			mga_setr(M_EXTVGA_INDEX, 0x00, panpos);
+			if (extvga_reg != 0x00) {
+				mga_outb(M_EXTVGA_INDEX, extvga_reg);
+			}
+		}
+		matroxfb_DAC_unlock_irqrestore(flags);
+	}
+}
+
+static irqreturn_t matrox_irq(int irq, void *dev_id, struct pt_regs *fp)
+{
+	u_int32_t status;
+	int handled = 0;
+
+	MINFO_FROM(dev_id);
+
+	status = mga_inl(M_STATUS);
+
+	if (status & 0x20) {
+		mga_outl(M_ICLEAR, 0x20);
+		ACCESS_FBINFO(crtc1.vsync.cnt)++;
+		matroxfb_crtc1_panpos(PMINFO2);
+		wake_up_interruptible(&ACCESS_FBINFO(crtc1.vsync.wait));
+		handled = 1;
+	}
+	if (status & 0x200) {
+		mga_outl(M_ICLEAR, 0x200);
+		ACCESS_FBINFO(crtc2.vsync.cnt)++;
+		wake_up_interruptible(&ACCESS_FBINFO(crtc2.vsync.wait));
+		handled = 1;
+	}
+	return IRQ_RETVAL(handled);
+}
+
+int matroxfb_enable_irq(WPMINFO int reenable) {
+	u_int32_t bm;
+	
+	if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400)
+		bm = 0x220;
+	else
+		bm = 0x020;
+
+	if (!test_and_set_bit(0, &ACCESS_FBINFO(irq_flags))) {
+		if (request_irq(ACCESS_FBINFO(pcidev)->irq, matrox_irq,
+				SA_SHIRQ, "matroxfb", MINFO)) {
+			clear_bit(0, &ACCESS_FBINFO(irq_flags));
+			return -EINVAL;
+		}
+		/* Clear any pending field interrupts */
+		mga_outl(M_ICLEAR, bm);
+		mga_outl(M_IEN, mga_inl(M_IEN) | bm);
+	} else if (reenable) {
+		u_int32_t ien;
+		
+		ien = mga_inl(M_IEN);
+		if ((ien & bm) != bm) {
+			printk(KERN_DEBUG "matroxfb: someone disabled IRQ [%08X]\n", ien);
+			mga_outl(M_IEN, ien | bm);
+		}
+	}
+	return 0;
+}
+
+static void matroxfb_disable_irq(WPMINFO2) {
+	if (test_and_clear_bit(0, &ACCESS_FBINFO(irq_flags))) {
+		/* Flush pending pan-at-vbl request... */
+		matroxfb_crtc1_panpos(PMINFO2);
+		if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400)
+			mga_outl(M_IEN, mga_inl(M_IEN) & ~0x220);
+		else
+			mga_outl(M_IEN, mga_inl(M_IEN) & ~0x20);
+		free_irq(ACCESS_FBINFO(pcidev)->irq, MINFO);
+	}
+}
+
+int matroxfb_wait_for_sync(WPMINFO u_int32_t crtc) {
+	wait_queue_t __wait;
+	struct matrox_vsync *vs;
+	unsigned int cnt;
+	int ret;
+
+	switch (crtc) {
+		case 0:
+			vs = &ACCESS_FBINFO(crtc1.vsync);
+			break;
+		case 1:
+			if (ACCESS_FBINFO(devflags.accelerator) != FB_ACCEL_MATROX_MGAG400) {
+				return -ENODEV;
+			}
+			vs = &ACCESS_FBINFO(crtc2.vsync);
+			break;
+		default:
+			return -ENODEV;
+	}
+	ret = matroxfb_enable_irq(PMINFO 0);
+	if (ret) {
+		return ret;
+	}
+        init_waitqueue_entry(&__wait, current);
+
+	cnt = vs->cnt;
+	ret = wait_event_interruptible_timeout(vs->wait, cnt != vs->cnt, HZ/10);
+	if (ret < 0) {
+		return ret;
+	}
+	if (ret == 0) {
+		matroxfb_enable_irq(PMINFO 1);
+		return -ETIMEDOUT;
+	}
+	return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) {
+	unsigned int pos;
+	unsigned short p0, p1, p2;
+#ifdef CONFIG_FB_MATROX_32MB
+	unsigned int p3;
+#endif
+	int vbl;
+	unsigned long flags;
+
+	CRITFLAGS
+
+	DBG(__FUNCTION__)
+
+	if (ACCESS_FBINFO(dead))
+		return;
+
+	ACCESS_FBINFO(fbcon).var.xoffset = var->xoffset;
+	ACCESS_FBINFO(fbcon).var.yoffset = var->yoffset;
+	pos = (ACCESS_FBINFO(fbcon).var.yoffset * ACCESS_FBINFO(fbcon).var.xres_virtual + ACCESS_FBINFO(fbcon).var.xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32;
+	pos += ACCESS_FBINFO(curr.ydstorg.chunks);
+	p0 = ACCESS_FBINFO(hw).CRTC[0x0D] = pos & 0xFF;
+	p1 = ACCESS_FBINFO(hw).CRTC[0x0C] = (pos & 0xFF00) >> 8;
+	p2 = ACCESS_FBINFO(hw).CRTCEXT[0] = (ACCESS_FBINFO(hw).CRTCEXT[0] & 0xB0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
+#ifdef CONFIG_FB_MATROX_32MB
+	p3 = ACCESS_FBINFO(hw).CRTCEXT[8] = pos >> 21;
+#endif
+
+	/* FB_ACTIVATE_VBL and we can acquire interrupts? Honor FB_ACTIVATE_VBL then... */
+	vbl = (var->activate & FB_ACTIVATE_VBL) && (matroxfb_enable_irq(PMINFO 0) == 0);
+
+	CRITBEGIN
+
+	matroxfb_DAC_lock_irqsave(flags);
+	mga_setr(M_CRTC_INDEX, 0x0D, p0);
+	mga_setr(M_CRTC_INDEX, 0x0C, p1);
+#ifdef CONFIG_FB_MATROX_32MB
+	if (ACCESS_FBINFO(devflags.support32MB))
+		mga_setr(M_EXTVGA_INDEX, 0x08, p3);
+#endif
+	if (vbl) {
+		ACCESS_FBINFO(crtc1.panpos) = p2;
+	} else {
+		/* Abort any pending change */
+		ACCESS_FBINFO(crtc1.panpos) = -1;
+		mga_setr(M_EXTVGA_INDEX, 0x00, p2);
+	}
+	matroxfb_DAC_unlock_irqrestore(flags);
+	
+	update_crtc2(PMINFO pos);
+
+	CRITEND
+}
+
+static void matroxfb_remove(WPMINFO int dummy) {
+	/* Currently we are holding big kernel lock on all dead & usecount updates.
+	 * Destroy everything after all users release it. Especially do not unregister
+	 * framebuffer and iounmap memory, neither fbmem nor fbcon-cfb* does not check
+	 * for device unplugged when in use.
+	 * In future we should point mmio.vbase & video.vbase somewhere where we can
+	 * write data without causing too much damage...
+	 */
+
+	ACCESS_FBINFO(dead) = 1;
+	if (ACCESS_FBINFO(usecount)) {
+		/* destroy it later */
+		return;
+	}
+	matroxfb_unregister_device(MINFO);
+	unregister_framebuffer(&ACCESS_FBINFO(fbcon));
+	matroxfb_g450_shutdown(PMINFO2);
+#ifdef CONFIG_MTRR
+	if (ACCESS_FBINFO(mtrr.vram_valid))
+		mtrr_del(ACCESS_FBINFO(mtrr.vram), ACCESS_FBINFO(video.base), ACCESS_FBINFO(video.len));
+#endif
+	mga_iounmap(ACCESS_FBINFO(mmio.vbase));
+	mga_iounmap(ACCESS_FBINFO(video.vbase));
+	release_mem_region(ACCESS_FBINFO(video.base), ACCESS_FBINFO(video.len_maximum));
+	release_mem_region(ACCESS_FBINFO(mmio.base), 16384);
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+	kfree(minfo);
+#endif
+}
+
+	/*
+	 * Open/Release the frame buffer device
+	 */
+
+static int matroxfb_open(struct fb_info *info, int user)
+{
+	MINFO_FROM_INFO(info);
+	
+	DBG_LOOP(__FUNCTION__)
+
+	if (ACCESS_FBINFO(dead)) {
+		return -ENXIO;
+	}
+	ACCESS_FBINFO(usecount)++;
+	if (user) {
+		ACCESS_FBINFO(userusecount)++;
+	}
+	return(0);
+}
+
+static int matroxfb_release(struct fb_info *info, int user)
+{
+	MINFO_FROM_INFO(info);
+	
+	DBG_LOOP(__FUNCTION__)
+
+	if (user) {
+		if (0 == --ACCESS_FBINFO(userusecount)) {
+			matroxfb_disable_irq(PMINFO2);
+		}
+	}
+	if (!(--ACCESS_FBINFO(usecount)) && ACCESS_FBINFO(dead)) {
+		matroxfb_remove(PMINFO 0);
+	}
+	return(0);
+}
+
+static int matroxfb_pan_display(struct fb_var_screeninfo *var,
+		struct fb_info* info) {
+	MINFO_FROM_INFO(info);
+
+	DBG(__FUNCTION__)
+
+	matrox_pan_var(PMINFO var);
+	return 0;
+}
+
+static int matroxfb_get_final_bppShift(CPMINFO int bpp) {
+	int bppshft2;
+
+	DBG(__FUNCTION__)
+
+	bppshft2 = bpp;
+	if (!bppshft2) {
+		return 8;
+	}
+	if (isInterleave(MINFO))
+		bppshft2 >>= 1;
+	if (ACCESS_FBINFO(devflags.video64bits))
+		bppshft2 >>= 1;
+	return bppshft2;
+}
+
+static int matroxfb_test_and_set_rounding(CPMINFO int xres, int bpp) {
+	int over;
+	int rounding;
+
+	DBG(__FUNCTION__)
+
+	switch (bpp) {
+		case 0:		return xres;
+		case 4:		rounding = 128;
+				break;
+		case 8:		rounding = 64;	/* doc says 64; 32 is OK for G400 */
+				break;
+		case 16:	rounding = 32;
+				break;
+		case 24:	rounding = 64;	/* doc says 64; 32 is OK for G400 */
+				break;
+		default:	rounding = 16;
+				/* on G400, 16 really does not work */
+				if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400)
+					rounding = 32;
+				break;
+	}
+	if (isInterleave(MINFO)) {
+		rounding *= 2;
+	}
+	over = xres % rounding;
+	if (over)
+		xres += rounding-over;
+	return xres;
+}
+
+static int matroxfb_pitch_adjust(CPMINFO int xres, int bpp) {
+	const int* width;
+	int xres_new;
+
+	DBG(__FUNCTION__)
+
+	if (!bpp) return xres;
+
+	width = ACCESS_FBINFO(capable.vxres);
+
+	if (ACCESS_FBINFO(devflags.precise_width)) {
+		while (*width) {
+			if ((*width >= xres) && (matroxfb_test_and_set_rounding(PMINFO *width, bpp) == *width)) {
+				break;
+			}
+			width++;
+		}
+		xres_new = *width;
+	} else {
+		xres_new = matroxfb_test_and_set_rounding(PMINFO xres, bpp);
+	}
+	if (!xres_new) return 0;
+	if (xres != xres_new) {
+		printk(KERN_INFO "matroxfb: cannot set xres to %d, rounded up to %d\n", xres, xres_new);
+	}
+	return xres_new;
+}
+
+static int matroxfb_get_cmap_len(struct fb_var_screeninfo *var) {
+
+	DBG(__FUNCTION__)
+
+	switch (var->bits_per_pixel) {
+		case 4:
+			return 16;	/* pseudocolor... 16 entries HW palette */
+		case 8:
+			return 256;	/* pseudocolor... 256 entries HW palette */
+		case 16:
+			return 16;	/* directcolor... 16 entries SW palette */
+					/* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
+		case 24:
+			return 16;	/* directcolor... 16 entries SW palette */
+					/* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
+		case 32:
+			return 16;	/* directcolor... 16 entries SW palette */
+					/* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
+	}
+	return 16;	/* return something reasonable... or panic()? */
+}
+
+static int matroxfb_decode_var(CPMINFO struct fb_var_screeninfo *var, int *visual, int *video_cmap_len, unsigned int* ydstorg) {
+	struct RGBT {
+		unsigned char bpp;
+		struct {
+			unsigned char offset,
+				      length;
+		} red,
+		  green,
+		  blue,
+		  transp;
+		signed char visual;
+	};
+	static const struct RGBT table[]= {
+		{ 8,{ 0,8},{0,8},{0,8},{ 0,0},MX_VISUAL_PSEUDOCOLOR},
+		{15,{10,5},{5,5},{0,5},{15,1},MX_VISUAL_DIRECTCOLOR},
+		{16,{11,5},{5,6},{0,5},{ 0,0},MX_VISUAL_DIRECTCOLOR},
+		{24,{16,8},{8,8},{0,8},{ 0,0},MX_VISUAL_DIRECTCOLOR},
+		{32,{16,8},{8,8},{0,8},{24,8},MX_VISUAL_DIRECTCOLOR}
+	};
+	struct RGBT const *rgbt;
+	unsigned int bpp = var->bits_per_pixel;
+	unsigned int vramlen;
+	unsigned int memlen;
+
+	DBG(__FUNCTION__)
+
+	switch (bpp) {
+		case 4:	 if (!ACCESS_FBINFO(capable.cfb4)) return -EINVAL;
+			 break;
+		case 8:	 break;
+		case 16: break;
+		case 24: break;
+		case 32: break;
+		default: return -EINVAL;
+	}
+	*ydstorg = 0;
+	vramlen = ACCESS_FBINFO(video.len_usable);
+	if (var->yres_virtual < var->yres)
+		var->yres_virtual = var->yres;
+	if (var->xres_virtual < var->xres)
+		var->xres_virtual = var->xres;
+
+	var->xres_virtual = matroxfb_pitch_adjust(PMINFO var->xres_virtual, bpp);
+	memlen = var->xres_virtual * bpp * var->yres_virtual / 8;
+	if (memlen > vramlen) {
+		var->yres_virtual = vramlen * 8 / (var->xres_virtual * bpp);
+		memlen = var->xres_virtual * bpp * var->yres_virtual / 8;
+	}
+	/* There is hardware bug that no line can cross 4MB boundary */
+	/* give up for CFB24, it is impossible to easy workaround it */
+	/* for other try to do something */
+	if (!ACCESS_FBINFO(capable.cross4MB) && (memlen > 0x400000)) {
+		if (bpp == 24) {
+			/* sorry */
+		} else {
+			unsigned int linelen;
+			unsigned int m1 = linelen = var->xres_virtual * bpp / 8;
+			unsigned int m2 = PAGE_SIZE;	/* or 128 if you do not need PAGE ALIGNED address */
+			unsigned int max_yres;
+
+			while (m1) {
+				int t;
+
+				while (m2 >= m1) m2 -= m1;
+				t = m1;
+				m1 = m2;
+				m2 = t;
+			}
+			m2 = linelen * PAGE_SIZE / m2;
+			*ydstorg = m2 = 0x400000 % m2;
+			max_yres = (vramlen - m2) / linelen;
+			if (var->yres_virtual > max_yres)
+				var->yres_virtual = max_yres;
+		}
+	}
+	/* YDSTLEN contains only signed 16bit value */
+	if (var->yres_virtual > 32767)
+		var->yres_virtual = 32767;
+	/* we must round yres/xres down, we already rounded y/xres_virtual up
+	   if it was possible. We should return -EINVAL, but I disagree */
+	if (var->yres_virtual < var->yres)
+		var->yres = var->yres_virtual;
+	if (var->xres_virtual < var->xres)
+		var->xres = var->xres_virtual;
+	if (var->xoffset + var->xres > var->xres_virtual)
+		var->xoffset = var->xres_virtual - var->xres;
+	if (var->yoffset + var->yres > var->yres_virtual)
+		var->yoffset = var->yres_virtual - var->yres;
+
+	if (bpp == 16 && var->green.length == 5) {
+		bpp--; /* an artifical value - 15 */
+	}
+
+	for (rgbt = table; rgbt->bpp < bpp; rgbt++);
+#define	SETCLR(clr)\
+	var->clr.offset = rgbt->clr.offset;\
+	var->clr.length = rgbt->clr.length
+	SETCLR(red);
+	SETCLR(green);
+	SETCLR(blue);
+	SETCLR(transp);
+#undef	SETCLR
+	*visual = rgbt->visual;
+
+	if (bpp > 8)
+		dprintk("matroxfb: truecolor: "
+			"size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
+			var->transp.length, var->red.length, var->green.length, var->blue.length,
+			var->transp.offset, var->red.offset, var->green.offset, var->blue.offset);
+
+	*video_cmap_len = matroxfb_get_cmap_len(var);
+	dprintk(KERN_INFO "requested %d*%d/%dbpp (%d*%d)\n", var->xres, var->yres, var->bits_per_pixel,
+				var->xres_virtual, var->yres_virtual);
+	return 0;
+}
+
+static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			      unsigned blue, unsigned transp,
+			      struct fb_info *fb_info)
+{
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+	struct matrox_fb_info* minfo = container_of(fb_info, struct matrox_fb_info, fbcon);
+#endif
+
+	DBG(__FUNCTION__)
+
+	/*
+	 *  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.
+	 */
+
+	if (regno >= ACCESS_FBINFO(curr.cmap_len))
+		return 1;
+
+	if (ACCESS_FBINFO(fbcon).var.grayscale) {
+		/* gray = 0.30*R + 0.59*G + 0.11*B */
+		red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+	}
+
+	red = CNVT_TOHW(red, ACCESS_FBINFO(fbcon).var.red.length);
+	green = CNVT_TOHW(green, ACCESS_FBINFO(fbcon).var.green.length);
+	blue = CNVT_TOHW(blue, ACCESS_FBINFO(fbcon).var.blue.length);
+	transp = CNVT_TOHW(transp, ACCESS_FBINFO(fbcon).var.transp.length);
+
+	switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
+	case 4:
+	case 8:
+		mga_outb(M_DAC_REG, regno);
+		mga_outb(M_DAC_VAL, red);
+		mga_outb(M_DAC_VAL, green);
+		mga_outb(M_DAC_VAL, blue);
+		break;
+	case 16:
+		{
+			u_int16_t col =
+				(red << ACCESS_FBINFO(fbcon).var.red.offset)     |
+				(green << ACCESS_FBINFO(fbcon).var.green.offset) |
+				(blue << ACCESS_FBINFO(fbcon).var.blue.offset)   |
+				(transp << ACCESS_FBINFO(fbcon).var.transp.offset); /* for 1:5:5:5 */
+			ACCESS_FBINFO(cmap[regno]) = col | (col << 16);
+		}
+		break;
+	case 24:
+	case 32:
+		ACCESS_FBINFO(cmap[regno]) =
+			(red   << ACCESS_FBINFO(fbcon).var.red.offset)   |
+			(green << ACCESS_FBINFO(fbcon).var.green.offset) |
+			(blue  << ACCESS_FBINFO(fbcon).var.blue.offset)  |
+			(transp << ACCESS_FBINFO(fbcon).var.transp.offset);	/* 8:8:8:8 */
+		break;
+	}
+	return 0;
+}
+
+static void matroxfb_init_fix(WPMINFO2)
+{
+	struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix;
+	DBG(__FUNCTION__)
+
+	strcpy(fix->id,"MATROX");
+
+	fix->xpanstep = 8;	/* 8 for 8bpp, 4 for 16bpp, 2 for 32bpp */
+	fix->ypanstep = 1;
+	fix->ywrapstep = 0;
+	fix->mmio_start = ACCESS_FBINFO(mmio.base);
+	fix->mmio_len = ACCESS_FBINFO(mmio.len);
+	fix->accel = ACCESS_FBINFO(devflags.accelerator);
+}
+
+static void matroxfb_update_fix(WPMINFO2)
+{
+	struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix;
+	DBG(__FUNCTION__)
+
+	fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes);
+	fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes);
+}
+
+static int matroxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	int err;
+	int visual;
+	int cmap_len;
+	unsigned int ydstorg;
+	MINFO_FROM_INFO(info);
+
+	if (ACCESS_FBINFO(dead)) {
+		return -ENXIO;
+	}
+	if ((err = matroxfb_decode_var(PMINFO var, &visual, &cmap_len, &ydstorg)) != 0)
+		return err;
+	return 0;
+}
+
+static int matroxfb_set_par(struct fb_info *info)
+{
+	int err;
+	int visual;
+	int cmap_len;
+	unsigned int ydstorg;
+	struct fb_var_screeninfo *var;
+	MINFO_FROM_INFO(info);
+
+	DBG(__FUNCTION__)
+
+	if (ACCESS_FBINFO(dead)) {
+		return -ENXIO;
+	}
+
+	var = &info->var;
+	if ((err = matroxfb_decode_var(PMINFO var, &visual, &cmap_len, &ydstorg)) != 0)
+		return err;
+	ACCESS_FBINFO(fbcon.screen_base) = vaddr_va(ACCESS_FBINFO(video.vbase)) + ydstorg;
+	matroxfb_update_fix(PMINFO2);
+	ACCESS_FBINFO(fbcon).fix.visual = visual;
+	ACCESS_FBINFO(fbcon).fix.type = FB_TYPE_PACKED_PIXELS;
+	ACCESS_FBINFO(fbcon).fix.type_aux = 0;
+	ACCESS_FBINFO(fbcon).fix.line_length = (var->xres_virtual * var->bits_per_pixel) >> 3;
+	{
+		unsigned int pos;
+
+		ACCESS_FBINFO(curr.cmap_len) = cmap_len;
+		ydstorg += ACCESS_FBINFO(devflags.ydstorg);
+		ACCESS_FBINFO(curr.ydstorg.bytes) = ydstorg;
+		ACCESS_FBINFO(curr.ydstorg.chunks) = ydstorg >> (isInterleave(MINFO)?3:2);
+		if (var->bits_per_pixel == 4)
+			ACCESS_FBINFO(curr.ydstorg.pixels) = ydstorg;
+		else
+			ACCESS_FBINFO(curr.ydstorg.pixels) = (ydstorg * 8) / var->bits_per_pixel;
+		ACCESS_FBINFO(curr.final_bppShift) = matroxfb_get_final_bppShift(PMINFO var->bits_per_pixel);
+		{	struct my_timming mt;
+			struct matrox_hw_state* hw;
+			int out;
+
+			matroxfb_var2my(var, &mt);
+			mt.crtc = MATROXFB_SRC_CRTC1;
+			/* CRTC1 delays */
+			switch (var->bits_per_pixel) {
+				case  0:	mt.delay = 31 + 0; break;
+				case 16:	mt.delay = 21 + 8; break;
+				case 24:	mt.delay = 17 + 8; break;
+				case 32:	mt.delay = 16 + 8; break;
+				default:	mt.delay = 31 + 8; break;
+			}
+
+			hw = &ACCESS_FBINFO(hw);
+
+			down_read(&ACCESS_FBINFO(altout).lock);
+			for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+				if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 &&
+				    ACCESS_FBINFO(outputs[out]).output->compute) {
+					ACCESS_FBINFO(outputs[out]).output->compute(ACCESS_FBINFO(outputs[out]).data, &mt);
+				}
+			}
+			up_read(&ACCESS_FBINFO(altout).lock);
+			ACCESS_FBINFO(crtc1).pixclock = mt.pixclock;
+			ACCESS_FBINFO(crtc1).mnp = mt.mnp;
+			ACCESS_FBINFO(hw_switch->init(PMINFO &mt));
+			pos = (var->yoffset * var->xres_virtual + var->xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32;
+			pos += ACCESS_FBINFO(curr.ydstorg.chunks);
+
+			hw->CRTC[0x0D] = pos & 0xFF;
+			hw->CRTC[0x0C] = (pos & 0xFF00) >> 8;
+			hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
+			hw->CRTCEXT[8] = pos >> 21;
+			ACCESS_FBINFO(hw_switch->restore(PMINFO2));
+			update_crtc2(PMINFO pos);
+			down_read(&ACCESS_FBINFO(altout).lock);
+			for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+				if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 &&
+				    ACCESS_FBINFO(outputs[out]).output->program) {
+					ACCESS_FBINFO(outputs[out]).output->program(ACCESS_FBINFO(outputs[out]).data);
+				}
+			}
+			for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+				if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 &&
+				    ACCESS_FBINFO(outputs[out]).output->start) {
+					ACCESS_FBINFO(outputs[out]).output->start(ACCESS_FBINFO(outputs[out]).data);
+				}
+			}
+			up_read(&ACCESS_FBINFO(altout).lock);
+			matrox_cfbX_init(PMINFO2);
+		}
+	}
+	ACCESS_FBINFO(initialized) = 1;
+	return 0;
+}
+
+static int matroxfb_get_vblank(WPMINFO struct fb_vblank *vblank)
+{
+	unsigned int sts1;
+
+	matroxfb_enable_irq(PMINFO 0);
+	memset(vblank, 0, sizeof(*vblank));
+	vblank->flags = FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VSYNC |
+			FB_VBLANK_HAVE_VBLANK | FB_VBLANK_HAVE_HBLANK;
+	sts1 = mga_inb(M_INSTS1);
+	vblank->vcount = mga_inl(M_VCOUNT);
+	/* BTW, on my PIII/450 with G400, reading M_INSTS1
+	   byte makes this call about 12% slower (1.70 vs. 2.05 us
+	   per ioctl()) */
+	if (sts1 & 1)
+		vblank->flags |= FB_VBLANK_HBLANKING;
+	if (sts1 & 8)
+		vblank->flags |= FB_VBLANK_VSYNCING;
+	if (vblank->vcount >= ACCESS_FBINFO(fbcon).var.yres)
+		vblank->flags |= FB_VBLANK_VBLANKING;
+	if (test_bit(0, &ACCESS_FBINFO(irq_flags))) {
+		vblank->flags |= FB_VBLANK_HAVE_COUNT;
+		/* Only one writer, aligned int value... 
+		   it should work without lock and without atomic_t */
+		vblank->count = ACCESS_FBINFO(crtc1).vsync.cnt;
+	}
+	return 0;
+}
+
+static struct matrox_altout panellink_output = {
+	.name	 = "Panellink output",
+};
+
+static int matroxfb_ioctl(struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg,
+			  struct fb_info *info)
+{
+	void __user *argp = (void __user *)arg;
+	MINFO_FROM_INFO(info);
+	
+	DBG(__FUNCTION__)
+
+	if (ACCESS_FBINFO(dead)) {
+		return -ENXIO;
+	}
+
+	switch (cmd) {
+		case FBIOGET_VBLANK:
+			{
+				struct fb_vblank vblank;
+				int err;
+
+				err = matroxfb_get_vblank(PMINFO &vblank);
+				if (err)
+					return err;
+				if (copy_to_user(argp, &vblank, sizeof(vblank)))
+					return -EFAULT;
+				return 0;
+			}
+		case FBIO_WAITFORVSYNC:
+			{
+				u_int32_t crt;
+
+				if (get_user(crt, (u_int32_t __user *)arg))
+					return -EFAULT;
+
+				return matroxfb_wait_for_sync(PMINFO crt);
+			}
+		case MATROXFB_SET_OUTPUT_MODE:
+			{
+				struct matroxioc_output_mode mom;
+				struct matrox_altout *oproc;
+				int val;
+
+				if (copy_from_user(&mom, argp, sizeof(mom)))
+					return -EFAULT;
+				if (mom.output >= MATROXFB_MAX_OUTPUTS)
+					return -ENXIO;
+				down_read(&ACCESS_FBINFO(altout.lock));
+				oproc = ACCESS_FBINFO(outputs[mom.output]).output;
+				if (!oproc) {
+					val = -ENXIO;
+				} else if (!oproc->verifymode) {
+					if (mom.mode == MATROXFB_OUTPUT_MODE_MONITOR) {
+						val = 0;
+					} else {
+						val = -EINVAL;
+					}
+				} else {
+					val = oproc->verifymode(ACCESS_FBINFO(outputs[mom.output]).data, mom.mode);
+				}
+				if (!val) {
+					if (ACCESS_FBINFO(outputs[mom.output]).mode != mom.mode) {
+						ACCESS_FBINFO(outputs[mom.output]).mode = mom.mode;
+						val = 1;
+					}
+				}
+				up_read(&ACCESS_FBINFO(altout.lock));
+				if (val != 1)
+					return val;
+				switch (ACCESS_FBINFO(outputs[mom.output]).src) {
+					case MATROXFB_SRC_CRTC1:
+						matroxfb_set_par(info);
+						break;
+					case MATROXFB_SRC_CRTC2:
+						{
+							struct matroxfb_dh_fb_info* crtc2;
+
+							down_read(&ACCESS_FBINFO(crtc2.lock));
+							crtc2 = ACCESS_FBINFO(crtc2.info);
+							if (crtc2)
+								crtc2->fbcon.fbops->fb_set_par(&crtc2->fbcon);
+							up_read(&ACCESS_FBINFO(crtc2.lock));
+						}
+						break;
+				}
+				return 0;
+			}
+		case MATROXFB_GET_OUTPUT_MODE:
+			{
+				struct matroxioc_output_mode mom;
+				struct matrox_altout *oproc;
+				int val;
+
+				if (copy_from_user(&mom, argp, sizeof(mom)))
+					return -EFAULT;
+				if (mom.output >= MATROXFB_MAX_OUTPUTS)
+					return -ENXIO;
+				down_read(&ACCESS_FBINFO(altout.lock));
+				oproc = ACCESS_FBINFO(outputs[mom.output]).output;
+				if (!oproc) {
+					val = -ENXIO;
+				} else {
+					mom.mode = ACCESS_FBINFO(outputs[mom.output]).mode;
+					val = 0;
+				}
+				up_read(&ACCESS_FBINFO(altout.lock));
+				if (val)
+					return val;
+				if (copy_to_user(argp, &mom, sizeof(mom)))
+					return -EFAULT;
+				return 0;
+			}
+		case MATROXFB_SET_OUTPUT_CONNECTION:
+			{
+				u_int32_t tmp;
+				int i;
+				int changes;
+
+				if (copy_from_user(&tmp, argp, sizeof(tmp)))
+					return -EFAULT;
+				for (i = 0; i < 32; i++) {
+					if (tmp & (1 << i)) {
+						if (i >= MATROXFB_MAX_OUTPUTS)
+							return -ENXIO;
+						if (!ACCESS_FBINFO(outputs[i]).output)
+							return -ENXIO;
+						switch (ACCESS_FBINFO(outputs[i]).src) {
+							case MATROXFB_SRC_NONE:
+							case MATROXFB_SRC_CRTC1:
+								break;
+							default:
+								return -EBUSY;
+						}
+					}
+				}
+				if (ACCESS_FBINFO(devflags.panellink)) {
+					if (tmp & MATROXFB_OUTPUT_CONN_DFP) {
+						if (tmp & MATROXFB_OUTPUT_CONN_SECONDARY)
+							return -EINVAL;
+						for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+							if (ACCESS_FBINFO(outputs[i]).src == MATROXFB_SRC_CRTC2) {
+								return -EBUSY;
+							}
+						}
+					}
+				}
+				changes = 0;
+				for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+					if (tmp & (1 << i)) {
+						if (ACCESS_FBINFO(outputs[i]).src != MATROXFB_SRC_CRTC1) {
+							changes = 1;
+							ACCESS_FBINFO(outputs[i]).src = MATROXFB_SRC_CRTC1;
+						}
+					} else if (ACCESS_FBINFO(outputs[i]).src == MATROXFB_SRC_CRTC1) {
+						changes = 1;
+						ACCESS_FBINFO(outputs[i]).src = MATROXFB_SRC_NONE;
+					}
+				}
+				if (!changes)
+					return 0;
+				matroxfb_set_par(info);
+				return 0;
+			}
+		case MATROXFB_GET_OUTPUT_CONNECTION:
+			{
+				u_int32_t conn = 0;
+				int i;
+
+				for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+					if (ACCESS_FBINFO(outputs[i]).src == MATROXFB_SRC_CRTC1) {
+						conn |= 1 << i;
+					}
+				}
+				if (put_user(conn, (u_int32_t __user *)arg))
+					return -EFAULT;
+				return 0;
+			}
+		case MATROXFB_GET_AVAILABLE_OUTPUTS:
+			{
+				u_int32_t conn = 0;
+				int i;
+
+				for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+					if (ACCESS_FBINFO(outputs[i]).output) {
+						switch (ACCESS_FBINFO(outputs[i]).src) {
+							case MATROXFB_SRC_NONE:
+							case MATROXFB_SRC_CRTC1:
+								conn |= 1 << i;
+								break;
+						}
+					}
+				}
+				if (ACCESS_FBINFO(devflags.panellink)) {
+					if (conn & MATROXFB_OUTPUT_CONN_DFP)
+						conn &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
+					if (conn & MATROXFB_OUTPUT_CONN_SECONDARY)
+						conn &= ~MATROXFB_OUTPUT_CONN_DFP;
+				}
+				if (put_user(conn, (u_int32_t __user *)arg))
+					return -EFAULT;
+				return 0;
+			}
+		case MATROXFB_GET_ALL_OUTPUTS:
+			{
+				u_int32_t conn = 0;
+				int i;
+
+				for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+					if (ACCESS_FBINFO(outputs[i]).output) {
+						conn |= 1 << i;
+					}
+				}
+				if (put_user(conn, (u_int32_t __user *)arg))
+					return -EFAULT;
+				return 0;
+			}
+		case VIDIOC_QUERYCAP:
+			{
+				struct v4l2_capability r;
+				
+				memset(&r, 0, sizeof(r));
+				strcpy(r.driver, "matroxfb");
+				strcpy(r.card, "Matrox");
+				sprintf(r.bus_info, "PCI:%s", pci_name(ACCESS_FBINFO(pcidev)));
+				r.version = KERNEL_VERSION(1,0,0);
+				r.capabilities = V4L2_CAP_VIDEO_OUTPUT;
+				if (copy_to_user(argp, &r, sizeof(r)))
+					return -EFAULT;
+				return 0;
+				
+			}
+		case VIDIOC_QUERYCTRL:
+			{
+				struct v4l2_queryctrl qctrl;
+				int err;
+
+				if (copy_from_user(&qctrl, argp, sizeof(qctrl)))
+					return -EFAULT;
+
+				down_read(&ACCESS_FBINFO(altout).lock);
+				if (!ACCESS_FBINFO(outputs[1]).output) {
+					err = -ENXIO;
+				} else if (ACCESS_FBINFO(outputs[1]).output->getqueryctrl) {
+					err = ACCESS_FBINFO(outputs[1]).output->getqueryctrl(ACCESS_FBINFO(outputs[1]).data, &qctrl);
+				} else {
+					err = -EINVAL;
+				}
+				up_read(&ACCESS_FBINFO(altout).lock);
+				if (err >= 0 &&
+				    copy_to_user(argp, &qctrl, sizeof(qctrl)))
+					return -EFAULT;
+				return err;
+			}
+		case VIDIOC_G_CTRL:
+			{
+				struct v4l2_control ctrl;
+				int err;
+
+				if (copy_from_user(&ctrl, argp, sizeof(ctrl)))
+					return -EFAULT;
+
+				down_read(&ACCESS_FBINFO(altout).lock);
+				if (!ACCESS_FBINFO(outputs[1]).output) {
+					err = -ENXIO;
+				} else if (ACCESS_FBINFO(outputs[1]).output->getctrl) {
+					err = ACCESS_FBINFO(outputs[1]).output->getctrl(ACCESS_FBINFO(outputs[1]).data, &ctrl);
+				} else {
+					err = -EINVAL;
+				}
+				up_read(&ACCESS_FBINFO(altout).lock);
+				if (err >= 0 &&
+				    copy_to_user(argp, &ctrl, sizeof(ctrl)))
+					return -EFAULT;
+				return err;
+			}
+		case VIDIOC_S_CTRL_OLD:
+		case VIDIOC_S_CTRL:
+			{
+				struct v4l2_control ctrl;
+				int err;
+
+				if (copy_from_user(&ctrl, argp, sizeof(ctrl)))
+					return -EFAULT;
+
+				down_read(&ACCESS_FBINFO(altout).lock);
+				if (!ACCESS_FBINFO(outputs[1]).output) {
+					err = -ENXIO;
+				} else if (ACCESS_FBINFO(outputs[1]).output->setctrl) {
+					err = ACCESS_FBINFO(outputs[1]).output->setctrl(ACCESS_FBINFO(outputs[1]).data, &ctrl);
+				} else {
+					err = -EINVAL;
+				}
+				up_read(&ACCESS_FBINFO(altout).lock);
+				return err;
+			}
+	}
+	return -ENOTTY;
+}
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+
+static int matroxfb_blank(int blank, struct fb_info *info)
+{
+	int seq;
+	int crtc;
+	CRITFLAGS
+	MINFO_FROM_INFO(info);
+
+	DBG(__FUNCTION__)
+
+	if (ACCESS_FBINFO(dead))
+		return 1;
+
+	switch (blank) {
+	case FB_BLANK_NORMAL:  seq = 0x20; crtc = 0x00; break; /* works ??? */
+	case FB_BLANK_VSYNC_SUSPEND:  seq = 0x20; crtc = 0x10; break;
+	case FB_BLANK_HSYNC_SUSPEND:  seq = 0x20; crtc = 0x20; break;
+	case FB_BLANK_POWERDOWN:  seq = 0x20; crtc = 0x30; break;
+	default: seq = 0x00; crtc = 0x00; break;
+	}
+
+	CRITBEGIN
+
+	mga_outb(M_SEQ_INDEX, 1);
+	mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq);
+	mga_outb(M_EXTVGA_INDEX, 1);
+	mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc);
+
+	CRITEND
+	return 0;
+}
+
+static struct fb_ops matroxfb_ops = {
+	.owner =	THIS_MODULE,
+	.fb_open =	matroxfb_open,
+	.fb_release =	matroxfb_release,
+	.fb_check_var =	matroxfb_check_var,
+	.fb_set_par =	matroxfb_set_par,
+	.fb_setcolreg =	matroxfb_setcolreg,
+	.fb_pan_display =matroxfb_pan_display,
+	.fb_blank =	matroxfb_blank,
+	.fb_ioctl =	matroxfb_ioctl,
+/*	.fb_fillrect =	<set by matrox_cfbX_init>, */
+/*	.fb_copyarea =	<set by matrox_cfbX_init>, */
+/*	.fb_imageblit =	<set by matrox_cfbX_init>, */
+/*	.fb_cursor =	<set by matrox_cfbX_init>, */
+};
+
+#define RSDepth(X)	(((X) >> 8) & 0x0F)
+#define RS8bpp		0x1
+#define RS15bpp		0x2
+#define RS16bpp		0x3
+#define RS32bpp		0x4
+#define RS4bpp		0x5
+#define RS24bpp		0x6
+#define RSText		0x7
+#define RSText8		0x8
+/* 9-F */
+static struct { struct fb_bitfield red, green, blue, transp; int bits_per_pixel; } colors[] = {
+	{ {  0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, {  0, 0, 0},  8 },
+	{ { 10, 5, 0}, { 5, 5, 0}, { 0, 5, 0}, { 15, 1, 0}, 16 },
+	{ { 11, 5, 0}, { 5, 6, 0}, { 0, 5, 0}, {  0, 0, 0}, 16 },
+	{ { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 24, 8, 0}, 32 },
+	{ {  0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, {  0, 0, 0},  4 },
+	{ { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, {  0, 0, 0}, 24 },
+	{ {  0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, {  0, 0, 0},  0 },	/* textmode with (default) VGA8x16 */
+	{ {  0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, {  0, 0, 0},  0 },	/* textmode hardwired to VGA8x8 */
+};
+
+/* initialized by setup, see explanation at end of file (search for MODULE_PARM_DESC) */
+static unsigned int mem;		/* "matrox:mem:xxxxxM" */
+static int option_precise_width = 1;	/* cannot be changed, option_precise_width==0 must imply noaccel */
+static int inv24;			/* "matrox:inv24" */
+static int cross4MB = -1;		/* "matrox:cross4MB" */
+static int disabled;			/* "matrox:disabled" */
+static int noaccel;			/* "matrox:noaccel" */
+static int nopan;			/* "matrox:nopan" */
+static int no_pci_retry;		/* "matrox:nopciretry" */
+static int novga;			/* "matrox:novga" */
+static int nobios;			/* "matrox:nobios" */
+static int noinit = 1;			/* "matrox:init" */
+static int inverse;			/* "matrox:inverse" */
+static int sgram;			/* "matrox:sgram" */
+#ifdef CONFIG_MTRR
+static int mtrr = 1;			/* "matrox:nomtrr" */
+#endif
+static int grayscale;			/* "matrox:grayscale" */
+static int dev = -1;			/* "matrox:dev:xxxxx" */
+static unsigned int vesa = ~0;		/* "matrox:vesa:xxxxx" */
+static int depth = -1;			/* "matrox:depth:xxxxx" */
+static unsigned int xres;		/* "matrox:xres:xxxxx" */
+static unsigned int yres;		/* "matrox:yres:xxxxx" */
+static unsigned int upper = ~0;		/* "matrox:upper:xxxxx" */
+static unsigned int lower = ~0;		/* "matrox:lower:xxxxx" */
+static unsigned int vslen;		/* "matrox:vslen:xxxxx" */
+static unsigned int left = ~0;		/* "matrox:left:xxxxx" */
+static unsigned int right = ~0;		/* "matrox:right:xxxxx" */
+static unsigned int hslen;		/* "matrox:hslen:xxxxx" */
+static unsigned int pixclock;		/* "matrox:pixclock:xxxxx" */
+static int sync = -1;			/* "matrox:sync:xxxxx" */
+static unsigned int fv;			/* "matrox:fv:xxxxx" */
+static unsigned int fh;			/* "matrox:fh:xxxxxk" */
+static unsigned int maxclk;		/* "matrox:maxclk:xxxxM" */
+static int dfp;				/* "matrox:dfp */
+static int dfp_type = -1;		/* "matrox:dfp:xxx */
+static int memtype = -1;		/* "matrox:memtype:xxx" */
+static char outputs[8];			/* "matrox:outputs:xxx" */
+
+#ifndef MODULE
+static char videomode[64];		/* "matrox:mode:xxxxx" or "matrox:xxxxx" */
+#endif
+
+static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int *realSize){
+	vaddr_t vm;
+	unsigned int offs;
+	unsigned int offs2;
+	unsigned char store;
+	unsigned char bytes[32];
+	unsigned char* tmp;
+
+	DBG(__FUNCTION__)
+
+	vm = ACCESS_FBINFO(video.vbase);
+	maxSize &= ~0x1FFFFF;	/* must be X*2MB (really it must be 2 or X*4MB) */
+	/* at least 2MB */
+	if (maxSize < 0x0200000) return 0;
+	if (maxSize > 0x2000000) maxSize = 0x2000000;
+
+	mga_outb(M_EXTVGA_INDEX, 0x03);
+	mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) | 0x80);
+
+	store = mga_readb(vm, 0x1234);
+	tmp = bytes;
+	for (offs = 0x100000; offs < maxSize; offs += 0x200000)
+		*tmp++ = mga_readb(vm, offs);
+	for (offs = 0x100000; offs < maxSize; offs += 0x200000)
+		mga_writeb(vm, offs, 0x02);
+	if (ACCESS_FBINFO(features.accel.has_cacheflush))
+		mga_outb(M_CACHEFLUSH, 0x00);
+	else
+		mga_writeb(vm, 0x1234, 0x99);
+	for (offs = 0x100000; offs < maxSize; offs += 0x200000) {
+		if (mga_readb(vm, offs) != 0x02)
+			break;
+		mga_writeb(vm, offs, mga_readb(vm, offs) - 0x02);
+		if (mga_readb(vm, offs))
+			break;
+	}
+	tmp = bytes;
+	for (offs2 = 0x100000; offs2 < maxSize; offs2 += 0x200000)
+		mga_writeb(vm, offs2, *tmp++);
+	mga_writeb(vm, 0x1234, store);
+
+	mga_outb(M_EXTVGA_INDEX, 0x03);
+	mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) & ~0x80);
+
+	*realSize = offs - 0x100000;
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+	ACCESS_FBINFO(interleave) = !(!isMillenium(MINFO) || ((offs - 0x100000) & 0x3FFFFF));
+#endif
+	return 1;
+}
+
+struct video_board {
+	int maxvram;
+	int maxdisplayable;
+	int accelID;
+	struct matrox_switch* lowlevel;
+		 };
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+static struct video_board vbMillennium		= {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA2064W,	&matrox_millennium};
+static struct video_board vbMillennium2		= {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W,	&matrox_millennium};
+static struct video_board vbMillennium2A	= {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W_AGP,	&matrox_millennium};
+#endif	/* CONFIG_FB_MATROX_MILLENIUM */
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static struct video_board vbMystique		= {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA1064SG,	&matrox_mystique};
+#endif	/* CONFIG_FB_MATROX_MYSTIQUE */
+#ifdef CONFIG_FB_MATROX_G
+static struct video_board vbG100		= {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGAG100,	&matrox_G100};
+static struct video_board vbG200		= {0x1000000, 0x1000000, FB_ACCEL_MATROX_MGAG200,	&matrox_G100};
+#ifdef CONFIG_FB_MATROX_32MB
+/* from doc it looks like that accelerator can draw only to low 16MB :-( Direct accesses & displaying are OK for
+   whole 32MB */
+static struct video_board vbG400		= {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG400,	&matrox_G100};
+#else
+static struct video_board vbG400		= {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG400,	&matrox_G100};
+#endif
+#endif
+
+#define DEVF_VIDEO64BIT		0x0001
+#define	DEVF_SWAPS		0x0002
+#define DEVF_SRCORG		0x0004
+#define DEVF_DUALHEAD		0x0008
+#define DEVF_CROSS4MB		0x0010
+#define DEVF_TEXT4B		0x0020
+/* #define DEVF_recycled	0x0040	*/
+/* #define DEVF_recycled	0x0080	*/
+#define DEVF_SUPPORT32MB	0x0100
+#define DEVF_ANY_VXRES		0x0200
+#define DEVF_TEXT16B		0x0400
+#define DEVF_CRTC2		0x0800
+#define DEVF_MAVEN_CAPABLE	0x1000
+#define DEVF_PANELLINK_CAPABLE	0x2000
+#define DEVF_G450DAC		0x4000
+
+#define DEVF_GCORE	(DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB)
+#define DEVF_G2CORE	(DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE | DEVF_PANELLINK_CAPABLE | DEVF_SRCORG | DEVF_DUALHEAD)
+#define DEVF_G100	(DEVF_GCORE) /* no doc, no vxres... */
+#define DEVF_G200	(DEVF_G2CORE)
+#define DEVF_G400	(DEVF_G2CORE | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2)
+/* if you'll find how to drive DFP... */
+#define DEVF_G450	(DEVF_GCORE | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2 | DEVF_G450DAC | DEVF_SRCORG | DEVF_DUALHEAD)
+#define DEVF_G550	(DEVF_G450)
+
+static struct board {
+	unsigned short vendor, device, rev, svid, sid;
+	unsigned int flags;
+	unsigned int maxclk;
+	enum mga_chip chip;
+	struct video_board* base;
+	const char* name;
+		} dev_list[] = {
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MIL,	0xFF,
+		0,			0,
+		DEVF_TEXT4B,
+		230000,
+		MGA_2064,
+		&vbMillennium,
+		"Millennium (PCI)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MIL_2,	0xFF,
+		0,			0,
+		DEVF_SWAPS,
+		220000,
+		MGA_2164,
+		&vbMillennium2,
+		"Millennium II (PCI)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MIL_2_AGP,	0xFF,
+		0,			0,
+		DEVF_SWAPS,
+		250000,
+		MGA_2164,
+		&vbMillennium2A,
+		"Millennium II (AGP)"},
+#endif
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MYS,	0x02,
+		0,			0,
+		DEVF_VIDEO64BIT | DEVF_CROSS4MB,
+		180000,
+		MGA_1064,
+		&vbMystique,
+		"Mystique (PCI)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MYS,	0xFF,
+		0,			0,
+		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		220000,
+		MGA_1164,
+		&vbMystique,
+		"Mystique 220 (PCI)"},
+#endif
+#ifdef CONFIG_FB_MATROX_G
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_MM,	0xFF,
+		0,			0,
+		DEVF_G100,
+		230000,
+		MGA_G100,
+		&vbG100,
+		"MGA-G100 (PCI)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,	0xFF,
+		0,			0,
+		DEVF_G100,
+		230000,
+		MGA_G100,
+		&vbG100,
+		"MGA-G100 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_PCI,	0xFF,
+		0,			0,
+		DEVF_G200,
+		250000,
+		MGA_G200,
+		&vbG200,
+		"MGA-G200 (PCI)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
+		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_GENERIC,
+		DEVF_G200,
+		220000,
+		MGA_G200,
+		&vbG200,
+		"MGA-G200 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
+		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP,
+		DEVF_G200,
+		230000,
+		MGA_G200,
+		&vbG200,
+		"Mystique G200 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
+		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MILLENIUM_G200_AGP,
+		DEVF_G200,
+		250000,
+		MGA_G200,
+		&vbG200,
+		"Millennium G200 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
+		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MARVEL_G200_AGP,
+		DEVF_G200,
+		230000,
+		MGA_G200,
+		&vbG200,
+		"Marvel G200 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
+		PCI_SS_VENDOR_ID_SIEMENS_NIXDORF,	PCI_SS_ID_SIEMENS_MGA_G200_AGP,
+		DEVF_G200,
+		230000,
+		MGA_G200,
+		&vbG200,
+		"MGA-G200 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
+		0,			0,
+		DEVF_G200,
+		230000,
+		MGA_G200,
+		&vbG200,
+		"G200 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G400,	0x80,
+		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MILLENNIUM_G400_MAX_AGP,
+		DEVF_G400,
+		360000,
+		MGA_G400,
+		&vbG400,
+		"Millennium G400 MAX (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G400,	0x80,
+		0,			0,
+		DEVF_G400,
+		300000,
+		MGA_G400,
+		&vbG400,
+		"G400 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G400,	0xFF,
+		0,			0,
+		DEVF_G450,
+		360000,
+		MGA_G450,
+		&vbG400,
+		"G450"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G550,	0xFF,
+		0,			0,
+		DEVF_G550,
+		360000,
+		MGA_G550,
+		&vbG400,
+		"G550"},
+#endif
+	{0,			0,				0xFF,
+		0,			0,
+		0,
+		0,
+		0,
+		NULL,
+		NULL}};
+
+#ifndef MODULE
+static struct fb_videomode defaultmode = {
+	/* 640x480 @ 60Hz, 31.5 kHz */
+	NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2,
+	0, FB_VMODE_NONINTERLACED
+};
+#endif /* !MODULE */
+
+static int hotplug = 0;
+
+static void setDefaultOutputs(WPMINFO2) {
+	unsigned int i;
+	const char* ptr;
+
+	ACCESS_FBINFO(outputs[0]).default_src = MATROXFB_SRC_CRTC1;
+	if (ACCESS_FBINFO(devflags.g450dac)) {
+		ACCESS_FBINFO(outputs[1]).default_src = MATROXFB_SRC_CRTC1;
+		ACCESS_FBINFO(outputs[2]).default_src = MATROXFB_SRC_CRTC1;
+	} else if (dfp) {
+		ACCESS_FBINFO(outputs[2]).default_src = MATROXFB_SRC_CRTC1;
+	}
+	ptr = outputs;
+	for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+		char c = *ptr++;
+
+		if (c == 0) {
+			break;
+		}
+		if (c == '0') {
+			ACCESS_FBINFO(outputs[i]).default_src = MATROXFB_SRC_NONE;
+		} else if (c == '1') {
+			ACCESS_FBINFO(outputs[i]).default_src = MATROXFB_SRC_CRTC1;
+		} else if (c == '2' && ACCESS_FBINFO(devflags.crtc2)) {
+			ACCESS_FBINFO(outputs[i]).default_src = MATROXFB_SRC_CRTC2;
+		} else {
+			printk(KERN_ERR "matroxfb: Unknown outputs setting\n");
+			break;
+		}
+	}
+	/* Nullify this option for subsequent adapters */
+	outputs[0] = 0;
+}
+
+static int initMatrox2(WPMINFO struct board* b){
+	unsigned long ctrlptr_phys = 0;
+	unsigned long video_base_phys = 0;
+	unsigned int memsize;
+	int err;
+
+	static struct pci_device_id intel_82437[] = {
+		{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437) },
+		{ },
+	};
+
+	DBG(__FUNCTION__)
+
+	/* set default values... */
+	vesafb_defined.accel_flags = FB_ACCELF_TEXT;
+
+	ACCESS_FBINFO(hw_switch) = b->base->lowlevel;
+	ACCESS_FBINFO(devflags.accelerator) = b->base->accelID;
+	ACCESS_FBINFO(max_pixel_clock) = b->maxclk;
+
+	printk(KERN_INFO "matroxfb: Matrox %s detected\n", b->name);
+	ACCESS_FBINFO(capable.plnwt) = 1;
+	ACCESS_FBINFO(chip) = b->chip;
+	ACCESS_FBINFO(capable.srcorg) = b->flags & DEVF_SRCORG;
+	ACCESS_FBINFO(devflags.video64bits) = b->flags & DEVF_VIDEO64BIT;
+	if (b->flags & DEVF_TEXT4B) {
+		ACCESS_FBINFO(devflags.vgastep) = 4;
+		ACCESS_FBINFO(devflags.textmode) = 4;
+		ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP16;
+	} else if (b->flags & DEVF_TEXT16B) {
+		ACCESS_FBINFO(devflags.vgastep) = 16;
+		ACCESS_FBINFO(devflags.textmode) = 1;
+		ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP16;
+	} else {
+		ACCESS_FBINFO(devflags.vgastep) = 8;
+		ACCESS_FBINFO(devflags.textmode) = 1;
+		ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP8;
+	}
+#ifdef CONFIG_FB_MATROX_32MB
+	ACCESS_FBINFO(devflags.support32MB) = (b->flags & DEVF_SUPPORT32MB) != 0;
+#endif
+	ACCESS_FBINFO(devflags.precise_width) = !(b->flags & DEVF_ANY_VXRES);
+	ACCESS_FBINFO(devflags.crtc2) = (b->flags & DEVF_CRTC2) != 0;
+	ACCESS_FBINFO(devflags.maven_capable) = (b->flags & DEVF_MAVEN_CAPABLE) != 0;
+	ACCESS_FBINFO(devflags.dualhead) = (b->flags & DEVF_DUALHEAD) != 0;
+	ACCESS_FBINFO(devflags.dfp_type) = dfp_type;
+	ACCESS_FBINFO(devflags.g450dac) = (b->flags & DEVF_G450DAC) != 0;
+	ACCESS_FBINFO(devflags.textstep) = ACCESS_FBINFO(devflags.vgastep) * ACCESS_FBINFO(devflags.textmode);
+	ACCESS_FBINFO(devflags.textvram) = 65536 / ACCESS_FBINFO(devflags.textmode);
+	setDefaultOutputs(PMINFO2);
+	if (b->flags & DEVF_PANELLINK_CAPABLE) {
+		ACCESS_FBINFO(outputs[2]).data = MINFO;
+		ACCESS_FBINFO(outputs[2]).output = &panellink_output;
+		ACCESS_FBINFO(outputs[2]).src = ACCESS_FBINFO(outputs[2]).default_src;
+		ACCESS_FBINFO(outputs[2]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		ACCESS_FBINFO(devflags.panellink) = 1;
+	}
+
+	if (ACCESS_FBINFO(capable.cross4MB) < 0)
+		ACCESS_FBINFO(capable.cross4MB) = b->flags & DEVF_CROSS4MB;
+	if (b->flags & DEVF_SWAPS) {
+		ctrlptr_phys = pci_resource_start(ACCESS_FBINFO(pcidev), 1);
+		video_base_phys = pci_resource_start(ACCESS_FBINFO(pcidev), 0);
+		ACCESS_FBINFO(devflags.fbResource) = PCI_BASE_ADDRESS_0;
+	} else {
+		ctrlptr_phys = pci_resource_start(ACCESS_FBINFO(pcidev), 0);
+		video_base_phys = pci_resource_start(ACCESS_FBINFO(pcidev), 1);
+		ACCESS_FBINFO(devflags.fbResource) = PCI_BASE_ADDRESS_1;
+	}
+	err = -EINVAL;
+	if (!ctrlptr_phys) {
+		printk(KERN_ERR "matroxfb: control registers are not available, matroxfb disabled\n");
+		goto fail;
+	}
+	if (!video_base_phys) {
+		printk(KERN_ERR "matroxfb: video RAM is not available in PCI address space, matroxfb disabled\n");
+		goto fail;
+	}
+	memsize = b->base->maxvram;
+	if (!request_mem_region(ctrlptr_phys, 16384, "matroxfb MMIO")) {
+		goto fail;
+	}
+	if (!request_mem_region(video_base_phys, memsize, "matroxfb FB")) {
+		goto failCtrlMR;
+	}
+	ACCESS_FBINFO(video.len_maximum) = memsize;
+	/* convert mem (autodetect k, M) */
+	if (mem < 1024) mem *= 1024;
+	if (mem < 0x00100000) mem *= 1024;
+
+	if (mem && (mem < memsize))
+		memsize = mem;
+	err = -ENOMEM;
+	if (mga_ioremap(ctrlptr_phys, 16384, MGA_IOREMAP_MMIO, &ACCESS_FBINFO(mmio.vbase))) {
+		printk(KERN_ERR "matroxfb: cannot ioremap(%lX, 16384), matroxfb disabled\n", ctrlptr_phys);
+		goto failVideoMR;
+	}
+	ACCESS_FBINFO(mmio.base) = ctrlptr_phys;
+	ACCESS_FBINFO(mmio.len) = 16384;
+	ACCESS_FBINFO(video.base) = video_base_phys;
+	if (mga_ioremap(video_base_phys, memsize, MGA_IOREMAP_FB, &ACCESS_FBINFO(video.vbase))) {
+		printk(KERN_ERR "matroxfb: cannot ioremap(%lX, %d), matroxfb disabled\n",
+			video_base_phys, memsize);
+		goto failCtrlIO;
+	}
+	{
+		u_int32_t cmd;
+		u_int32_t mga_option;
+
+		pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, &mga_option);
+		pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, &cmd);
+		mga_option &= 0x7FFFFFFF; /* clear BIG_ENDIAN */
+		mga_option |= MX_OPTION_BSWAP;
+                /* disable palette snooping */
+                cmd &= ~PCI_COMMAND_VGA_PALETTE;
+		if (pci_dev_present(intel_82437)) {
+			if (!(mga_option & 0x20000000) && !ACCESS_FBINFO(devflags.nopciretry)) {
+				printk(KERN_WARNING "matroxfb: Disabling PCI retries due to i82437 present\n");
+			}
+			mga_option |= 0x20000000;
+			ACCESS_FBINFO(devflags.nopciretry) = 1;
+		}
+		pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, cmd);
+		pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mga_option);
+		ACCESS_FBINFO(hw).MXoptionReg = mga_option;
+
+		/* select non-DMA memory for PCI_MGA_DATA, otherwise dump of PCI cfg space can lock PCI bus */
+		/* maybe preinit() candidate, but it is same... for all devices... at this time... */
+		pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_MGA_INDEX, 0x00003C00);
+	}
+
+	err = -ENXIO;
+	matroxfb_read_pins(PMINFO2);
+	if (ACCESS_FBINFO(hw_switch)->preinit(PMINFO2)) {
+		goto failVideoIO;
+	}
+
+	err = -ENOMEM;
+	if (!matroxfb_getmemory(PMINFO memsize, &ACCESS_FBINFO(video.len)) || !ACCESS_FBINFO(video.len)) {
+		printk(KERN_ERR "matroxfb: cannot determine memory size\n");
+		goto failVideoIO;
+	}
+	ACCESS_FBINFO(devflags.ydstorg) = 0;
+
+	ACCESS_FBINFO(video.base) = video_base_phys;
+	ACCESS_FBINFO(video.len_usable) = ACCESS_FBINFO(video.len);
+	if (ACCESS_FBINFO(video.len_usable) > b->base->maxdisplayable)
+		ACCESS_FBINFO(video.len_usable) = b->base->maxdisplayable;
+#ifdef CONFIG_MTRR
+	if (mtrr) {
+		ACCESS_FBINFO(mtrr.vram) = mtrr_add(video_base_phys, ACCESS_FBINFO(video.len), MTRR_TYPE_WRCOMB, 1);
+		ACCESS_FBINFO(mtrr.vram_valid) = 1;
+		printk(KERN_INFO "matroxfb: MTRR's turned on\n");
+	}
+#endif	/* CONFIG_MTRR */
+
+	if (!ACCESS_FBINFO(devflags.novga))
+		request_region(0x3C0, 32, "matrox");
+	matroxfb_g450_connect(PMINFO2);
+	ACCESS_FBINFO(hw_switch->reset(PMINFO2));
+
+	ACCESS_FBINFO(fbcon.monspecs.hfmin) = 0;
+	ACCESS_FBINFO(fbcon.monspecs.hfmax) = fh;
+	ACCESS_FBINFO(fbcon.monspecs.vfmin) = 0;
+	ACCESS_FBINFO(fbcon.monspecs.vfmax) = fv;
+	ACCESS_FBINFO(fbcon.monspecs.dpms) = 0;	/* TBD */
+
+	/* static settings */
+	vesafb_defined.red = colors[depth-1].red;
+	vesafb_defined.green = colors[depth-1].green;
+	vesafb_defined.blue = colors[depth-1].blue;
+	vesafb_defined.bits_per_pixel = colors[depth-1].bits_per_pixel;
+	vesafb_defined.grayscale = grayscale;
+	vesafb_defined.vmode = 0;
+	if (noaccel)
+		vesafb_defined.accel_flags &= ~FB_ACCELF_TEXT;
+
+	ACCESS_FBINFO(fbops) = matroxfb_ops;
+	ACCESS_FBINFO(fbcon.fbops) = &ACCESS_FBINFO(fbops);
+	ACCESS_FBINFO(fbcon.pseudo_palette) = ACCESS_FBINFO(cmap);
+	/* after __init time we are like module... no logo */
+	ACCESS_FBINFO(fbcon.flags) = hotplug ? FBINFO_FLAG_MODULE : FBINFO_FLAG_DEFAULT;
+	ACCESS_FBINFO(fbcon.flags) |= FBINFO_PARTIAL_PAN_OK | 	 /* Prefer panning for scroll under MC viewer/edit */
+				      FBINFO_HWACCEL_COPYAREA |  /* We have hw-assisted bmove */
+				      FBINFO_HWACCEL_FILLRECT |  /* And fillrect */
+				      FBINFO_HWACCEL_IMAGEBLIT | /* And imageblit */
+				      FBINFO_HWACCEL_XPAN |      /* And we support both horizontal */
+				      FBINFO_HWACCEL_YPAN;       /* And vertical panning */
+	ACCESS_FBINFO(video.len_usable) &= PAGE_MASK;
+	fb_alloc_cmap(&ACCESS_FBINFO(fbcon.cmap), 256, 1);
+
+#ifndef MODULE
+	/* mode database is marked __init!!! */
+	if (!hotplug) {
+		fb_find_mode(&vesafb_defined, &ACCESS_FBINFO(fbcon), videomode[0]?videomode:NULL,
+			NULL, 0, &defaultmode, vesafb_defined.bits_per_pixel);
+	}
+#endif /* !MODULE */
+
+	/* mode modifiers */
+	if (hslen)
+		vesafb_defined.hsync_len = hslen;
+	if (vslen)
+		vesafb_defined.vsync_len = vslen;
+	if (left != ~0)
+		vesafb_defined.left_margin = left;
+	if (right != ~0)
+		vesafb_defined.right_margin = right;
+	if (upper != ~0)
+		vesafb_defined.upper_margin = upper;
+	if (lower != ~0)
+		vesafb_defined.lower_margin = lower;
+	if (xres)
+		vesafb_defined.xres = xres;
+	if (yres)
+		vesafb_defined.yres = yres;
+	if (sync != -1)
+		vesafb_defined.sync = sync;
+	else if (vesafb_defined.sync == ~0) {
+		vesafb_defined.sync = 0;
+		if (yres < 400)
+			vesafb_defined.sync |= FB_SYNC_HOR_HIGH_ACT;
+		else if (yres < 480)
+			vesafb_defined.sync |= FB_SYNC_VERT_HIGH_ACT;
+	}
+
+	/* fv, fh, maxclk limits was specified */
+	{
+		unsigned int tmp;
+
+		if (fv) {
+			tmp = fv * (vesafb_defined.upper_margin + vesafb_defined.yres
+			          + vesafb_defined.lower_margin + vesafb_defined.vsync_len);
+			if ((tmp < fh) || (fh == 0)) fh = tmp;
+		}
+		if (fh) {
+			tmp = fh * (vesafb_defined.left_margin + vesafb_defined.xres
+			          + vesafb_defined.right_margin + vesafb_defined.hsync_len);
+			if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp;
+		}
+		tmp = (maxclk + 499) / 500;
+		if (tmp) {
+			tmp = (2000000000 + tmp) / tmp;
+			if (tmp > pixclock) pixclock = tmp;
+		}
+	}
+	if (pixclock) {
+		if (pixclock < 2000)		/* > 500MHz */
+			pixclock = 4000;	/* 250MHz */
+		if (pixclock > 1000000)
+			pixclock = 1000000;	/* 1MHz */
+		vesafb_defined.pixclock = pixclock;
+	}
+
+	/* FIXME: Where to move this?! */
+#if defined(CONFIG_PPC_PMAC)
+#ifndef MODULE
+	if (_machine == _MACH_Pmac) {
+		struct fb_var_screeninfo var;
+		if (default_vmode <= 0 || default_vmode > VMODE_MAX)
+			default_vmode = VMODE_640_480_60;
+#ifdef CONFIG_NVRAM
+		if (default_cmode == CMODE_NVRAM)
+			default_cmode = nvram_read_byte(NV_CMODE);
+#endif
+		if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
+			default_cmode = CMODE_8;
+		if (!mac_vmode_to_var(default_vmode, default_cmode, &var)) {
+			var.accel_flags = vesafb_defined.accel_flags;
+			var.xoffset = var.yoffset = 0;
+			/* Note: mac_vmode_to_var() does not set all parameters */
+			vesafb_defined = var;
+		}
+	}
+#endif /* !MODULE */
+#endif /* CONFIG_PPC_PMAC */
+	vesafb_defined.xres_virtual = vesafb_defined.xres;
+	if (nopan) {
+		vesafb_defined.yres_virtual = vesafb_defined.yres;
+	} else {
+		vesafb_defined.yres_virtual = 65536; /* large enough to be INF, but small enough
+							to yres_virtual * xres_virtual < 2^32 */
+	}
+	matroxfb_init_fix(PMINFO2);
+	/* Normalize values (namely yres_virtual) */
+	matroxfb_check_var(&vesafb_defined, &ACCESS_FBINFO(fbcon));
+	/* And put it into "current" var. Do NOT program hardware yet, or we'll not take over
+	 * vgacon correctly. fbcon_startup will call fb_set_par for us, WITHOUT check_var,
+	 * and unfortunately it will do it BEFORE vgacon contents is saved, so it won't work
+	 * anyway. But we at least tried... */
+	ACCESS_FBINFO(fbcon.var) = vesafb_defined;
+	err = -EINVAL;
+
+	printk(KERN_INFO "matroxfb: %dx%dx%dbpp (virtual: %dx%d)\n",
+		vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel,
+		vesafb_defined.xres_virtual, vesafb_defined.yres_virtual);
+	printk(KERN_INFO "matroxfb: framebuffer at 0x%lX, mapped to 0x%p, size %d\n",
+		ACCESS_FBINFO(video.base), vaddr_va(ACCESS_FBINFO(video.vbase)), ACCESS_FBINFO(video.len));
+
+/* We do not have to set currcon to 0... register_framebuffer do it for us on first console
+ * and we do not want currcon == 0 for subsequent framebuffers */
+
+	ACCESS_FBINFO(fbcon).device = &ACCESS_FBINFO(pcidev)->dev;
+	if (register_framebuffer(&ACCESS_FBINFO(fbcon)) < 0) {
+		goto failVideoIO;
+	}
+	printk("fb%d: %s frame buffer device\n",
+	       ACCESS_FBINFO(fbcon.node), ACCESS_FBINFO(fbcon.fix.id));
+
+	/* there is no console on this fb... but we have to initialize hardware
+	 * until someone tells me what is proper thing to do */
+ 	if (!ACCESS_FBINFO(initialized)) {
+ 		printk(KERN_INFO "fb%d: initializing hardware\n",
+ 		       ACCESS_FBINFO(fbcon.node));
+ 		/* We have to use FB_ACTIVATE_FORCE, as we had to put vesafb_defined to the fbcon.var
+ 		 * already before, so register_framebuffer works correctly. */
+ 		vesafb_defined.activate |= FB_ACTIVATE_FORCE;
+ 		fb_set_var(&ACCESS_FBINFO(fbcon), &vesafb_defined);
+ 	}
+
+	return 0;
+failVideoIO:;
+	matroxfb_g450_shutdown(PMINFO2);
+	mga_iounmap(ACCESS_FBINFO(video.vbase));
+failCtrlIO:;
+	mga_iounmap(ACCESS_FBINFO(mmio.vbase));
+failVideoMR:;
+	release_mem_region(video_base_phys, ACCESS_FBINFO(video.len_maximum));
+failCtrlMR:;
+	release_mem_region(ctrlptr_phys, 16384);
+fail:;
+	return err;
+}
+
+static LIST_HEAD(matroxfb_list);
+static LIST_HEAD(matroxfb_driver_list);
+
+#define matroxfb_l(x) list_entry(x, struct matrox_fb_info, next_fb)
+#define matroxfb_driver_l(x) list_entry(x, struct matroxfb_driver, node)
+int matroxfb_register_driver(struct matroxfb_driver* drv) {
+	struct matrox_fb_info* minfo;
+
+	list_add(&drv->node, &matroxfb_driver_list);
+	for (minfo = matroxfb_l(matroxfb_list.next);
+	     minfo != matroxfb_l(&matroxfb_list);
+	     minfo = matroxfb_l(minfo->next_fb.next)) {
+		void* p;
+
+		if (minfo->drivers_count == MATROXFB_MAX_FB_DRIVERS)
+			continue;
+		p = drv->probe(minfo);
+		if (p) {
+			minfo->drivers_data[minfo->drivers_count] = p;
+			minfo->drivers[minfo->drivers_count++] = drv;
+		}
+	}
+	return 0;
+}
+
+void matroxfb_unregister_driver(struct matroxfb_driver* drv) {
+	struct matrox_fb_info* minfo;
+
+	list_del(&drv->node);
+	for (minfo = matroxfb_l(matroxfb_list.next);
+	     minfo != matroxfb_l(&matroxfb_list);
+	     minfo = matroxfb_l(minfo->next_fb.next)) {
+		int i;
+
+		for (i = 0; i < minfo->drivers_count; ) {
+			if (minfo->drivers[i] == drv) {
+				if (drv && drv->remove)
+					drv->remove(minfo, minfo->drivers_data[i]);
+				minfo->drivers[i] = minfo->drivers[--minfo->drivers_count];
+				minfo->drivers_data[i] = minfo->drivers_data[minfo->drivers_count];
+			} else
+				i++;
+		}
+	}
+}
+
+static void matroxfb_register_device(struct matrox_fb_info* minfo) {
+	struct matroxfb_driver* drv;
+	int i = 0;
+	list_add(&ACCESS_FBINFO(next_fb), &matroxfb_list);
+	for (drv = matroxfb_driver_l(matroxfb_driver_list.next);
+	     drv != matroxfb_driver_l(&matroxfb_driver_list);
+	     drv = matroxfb_driver_l(drv->node.next)) {
+		if (drv && drv->probe) {
+			void *p = drv->probe(minfo);
+			if (p) {
+				minfo->drivers_data[i] = p;
+				minfo->drivers[i++] = drv;
+				if (i == MATROXFB_MAX_FB_DRIVERS)
+					break;
+			}
+		}
+	}
+	minfo->drivers_count = i;
+}
+
+static void matroxfb_unregister_device(struct matrox_fb_info* minfo) {
+	int i;
+
+	list_del(&ACCESS_FBINFO(next_fb));
+	for (i = 0; i < minfo->drivers_count; i++) {
+		struct matroxfb_driver* drv = minfo->drivers[i];
+
+		if (drv && drv->remove)
+			drv->remove(minfo, minfo->drivers_data[i]);
+	}
+}
+
+static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dummy) {
+	struct board* b;
+	u_int8_t rev;
+	u_int16_t svid;
+	u_int16_t sid;
+	struct matrox_fb_info* minfo;
+	int err;
+	u_int32_t cmd;
+#ifndef CONFIG_FB_MATROX_MULTIHEAD
+	static int registered = 0;
+#endif
+	DBG(__FUNCTION__)
+
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
+	svid = pdev->subsystem_vendor;
+	sid = pdev->subsystem_device;
+	for (b = dev_list; b->vendor; b++) {
+		if ((b->vendor != pdev->vendor) || (b->device != pdev->device) || (b->rev < rev)) continue;
+		if (b->svid)
+			if ((b->svid != svid) || (b->sid != sid)) continue;
+		break;
+	}
+	/* not match... */
+	if (!b->vendor)
+		return -1;
+	if (dev > 0) {
+		/* not requested one... */
+		dev--;
+		return -1;
+	}
+	pci_read_config_dword(pdev, PCI_COMMAND, &cmd);
+	if (pci_enable_device(pdev)) {
+		return -1;
+	}
+
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+	minfo = (struct matrox_fb_info*)kmalloc(sizeof(*minfo), GFP_KERNEL);
+	if (!minfo)
+		return -1;
+#else
+	if (registered)	/* singlehead driver... */
+		return -1;
+	minfo = &matroxfb_global_mxinfo;
+#endif
+	memset(MINFO, 0, sizeof(*MINFO));
+
+	ACCESS_FBINFO(pcidev) = pdev;
+	ACCESS_FBINFO(dead) = 0;
+	ACCESS_FBINFO(usecount) = 0;
+	ACCESS_FBINFO(userusecount) = 0;
+
+	pci_set_drvdata(pdev, MINFO);
+	/* DEVFLAGS */
+	ACCESS_FBINFO(devflags.memtype) = memtype;
+	if (memtype != -1)
+		noinit = 0;
+	if (cmd & PCI_COMMAND_MEMORY) {
+		ACCESS_FBINFO(devflags.novga) = novga;
+		ACCESS_FBINFO(devflags.nobios) = nobios;
+		ACCESS_FBINFO(devflags.noinit) = noinit;
+		/* subsequent heads always needs initialization and must not enable BIOS */
+		novga = 1;
+		nobios = 1;
+		noinit = 0;
+	} else {
+		ACCESS_FBINFO(devflags.novga) = 1;
+		ACCESS_FBINFO(devflags.nobios) = 1;
+		ACCESS_FBINFO(devflags.noinit) = 0;
+	}
+
+	ACCESS_FBINFO(devflags.nopciretry) = no_pci_retry;
+	ACCESS_FBINFO(devflags.mga_24bpp_fix) = inv24;
+	ACCESS_FBINFO(devflags.precise_width) = option_precise_width;
+	ACCESS_FBINFO(devflags.sgram) = sgram;
+	ACCESS_FBINFO(capable.cross4MB) = cross4MB;
+
+	spin_lock_init(&ACCESS_FBINFO(lock.DAC));
+	spin_lock_init(&ACCESS_FBINFO(lock.accel));
+	init_rwsem(&ACCESS_FBINFO(crtc2.lock));
+	init_rwsem(&ACCESS_FBINFO(altout.lock));
+	ACCESS_FBINFO(irq_flags) = 0;
+	init_waitqueue_head(&ACCESS_FBINFO(crtc1.vsync.wait));
+	init_waitqueue_head(&ACCESS_FBINFO(crtc2.vsync.wait));
+	ACCESS_FBINFO(crtc1.panpos) = -1;
+
+	err = initMatrox2(PMINFO b);
+	if (!err) {
+#ifndef CONFIG_FB_MATROX_MULTIHEAD
+		registered = 1;
+#endif
+		matroxfb_register_device(MINFO);
+		return 0;
+	}
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+	kfree(minfo);
+#endif
+	return -1;
+}
+
+static void pci_remove_matrox(struct pci_dev* pdev) {
+	struct matrox_fb_info* minfo;
+
+	minfo = pci_get_drvdata(pdev);
+	matroxfb_remove(PMINFO 1);
+}
+
+static struct pci_device_id matroxfb_devices[] = {
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MIL,
+		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MIL_2,
+		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MIL_2_AGP,
+		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
+#endif
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MYS,
+		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
+#endif
+#ifdef CONFIG_FB_MATROX_G
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_MM,
+		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,
+		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_PCI,
+		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,
+		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G400,
+		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G550,
+		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
+#endif
+	{0,			0,
+		0,		0,		0, 0, 0}
+};
+
+MODULE_DEVICE_TABLE(pci, matroxfb_devices);
+
+
+static struct pci_driver matroxfb_driver = {
+	.name =		"matroxfb",
+	.id_table =	matroxfb_devices,
+	.probe =	matroxfb_probe,
+	.remove =	pci_remove_matrox,
+};
+
+/* **************************** init-time only **************************** */
+
+#define RSResolution(X)	((X) & 0x0F)
+#define RS640x400	1
+#define RS640x480	2
+#define RS800x600	3
+#define RS1024x768	4
+#define RS1280x1024	5
+#define RS1600x1200	6
+#define RS768x576	7
+#define RS960x720	8
+#define RS1152x864	9
+#define RS1408x1056	10
+#define RS640x350	11
+#define RS1056x344	12	/* 132 x 43 text */
+#define RS1056x400	13	/* 132 x 50 text */
+#define RS1056x480	14	/* 132 x 60 text */
+#define RSNoxNo		15
+/* 10-FF */
+static struct { int xres, yres, left, right, upper, lower, hslen, vslen, vfreq; } timmings[] __initdata = {
+	{  640,  400,  48, 16, 39,  8,  96, 2, 70 },
+	{  640,  480,  48, 16, 33, 10,  96, 2, 60 },
+	{  800,  600, 144, 24, 28,  8, 112, 6, 60 },
+	{ 1024,  768, 160, 32, 30,  4, 128, 4, 60 },
+	{ 1280, 1024, 224, 32, 32,  4, 136, 4, 60 },
+	{ 1600, 1200, 272, 48, 32,  5, 152, 5, 60 },
+	{  768,  576, 144, 16, 28,  6, 112, 4, 60 },
+	{  960,  720, 144, 24, 28,  8, 112, 4, 60 },
+	{ 1152,  864, 192, 32, 30,  4, 128, 4, 60 },
+	{ 1408, 1056, 256, 40, 32,  5, 144, 5, 60 },
+	{  640,  350,  48, 16, 39,  8,  96, 2, 70 },
+	{ 1056,  344,  96, 24, 59, 44, 160, 2, 70 },
+	{ 1056,  400,  96, 24, 39,  8, 160, 2, 70 },
+	{ 1056,  480,  96, 24, 36, 12, 160, 3, 60 },
+	{    0,    0,  ~0, ~0, ~0, ~0,   0, 0,  0 }
+};
+
+#define RSCreate(X,Y)	((X) | ((Y) << 8))
+static struct { unsigned int vesa; unsigned int info; } *RSptr, vesamap[] __initdata = {
+/* default must be first */
+	{    ~0, RSCreate(RSNoxNo,     RS8bpp ) },
+	{ 0x101, RSCreate(RS640x480,   RS8bpp ) },
+	{ 0x100, RSCreate(RS640x400,   RS8bpp ) },
+	{ 0x180, RSCreate(RS768x576,   RS8bpp ) },
+	{ 0x103, RSCreate(RS800x600,   RS8bpp ) },
+	{ 0x188, RSCreate(RS960x720,   RS8bpp ) },
+	{ 0x105, RSCreate(RS1024x768,  RS8bpp ) },
+	{ 0x190, RSCreate(RS1152x864,  RS8bpp ) },
+	{ 0x107, RSCreate(RS1280x1024, RS8bpp ) },
+	{ 0x198, RSCreate(RS1408x1056, RS8bpp ) },
+	{ 0x11C, RSCreate(RS1600x1200, RS8bpp ) },
+	{ 0x110, RSCreate(RS640x480,   RS15bpp) },
+	{ 0x181, RSCreate(RS768x576,   RS15bpp) },
+	{ 0x113, RSCreate(RS800x600,   RS15bpp) },
+	{ 0x189, RSCreate(RS960x720,   RS15bpp) },
+	{ 0x116, RSCreate(RS1024x768,  RS15bpp) },
+	{ 0x191, RSCreate(RS1152x864,  RS15bpp) },
+	{ 0x119, RSCreate(RS1280x1024, RS15bpp) },
+	{ 0x199, RSCreate(RS1408x1056, RS15bpp) },
+	{ 0x11D, RSCreate(RS1600x1200, RS15bpp) },
+	{ 0x111, RSCreate(RS640x480,   RS16bpp) },
+	{ 0x182, RSCreate(RS768x576,   RS16bpp) },
+	{ 0x114, RSCreate(RS800x600,   RS16bpp) },
+	{ 0x18A, RSCreate(RS960x720,   RS16bpp) },
+	{ 0x117, RSCreate(RS1024x768,  RS16bpp) },
+	{ 0x192, RSCreate(RS1152x864,  RS16bpp) },
+	{ 0x11A, RSCreate(RS1280x1024, RS16bpp) },
+	{ 0x19A, RSCreate(RS1408x1056, RS16bpp) },
+	{ 0x11E, RSCreate(RS1600x1200, RS16bpp) },
+	{ 0x1B2, RSCreate(RS640x480,   RS24bpp) },
+	{ 0x184, RSCreate(RS768x576,   RS24bpp) },
+	{ 0x1B5, RSCreate(RS800x600,   RS24bpp) },
+	{ 0x18C, RSCreate(RS960x720,   RS24bpp) },
+	{ 0x1B8, RSCreate(RS1024x768,  RS24bpp) },
+	{ 0x194, RSCreate(RS1152x864,  RS24bpp) },
+	{ 0x1BB, RSCreate(RS1280x1024, RS24bpp) },
+	{ 0x19C, RSCreate(RS1408x1056, RS24bpp) },
+	{ 0x1BF, RSCreate(RS1600x1200, RS24bpp) },
+	{ 0x112, RSCreate(RS640x480,   RS32bpp) },
+	{ 0x183, RSCreate(RS768x576,   RS32bpp) },
+	{ 0x115, RSCreate(RS800x600,   RS32bpp) },
+	{ 0x18B, RSCreate(RS960x720,   RS32bpp) },
+	{ 0x118, RSCreate(RS1024x768,  RS32bpp) },
+	{ 0x193, RSCreate(RS1152x864,  RS32bpp) },
+	{ 0x11B, RSCreate(RS1280x1024, RS32bpp) },
+	{ 0x19B, RSCreate(RS1408x1056, RS32bpp) },
+	{ 0x11F, RSCreate(RS1600x1200, RS32bpp) },
+	{ 0x010, RSCreate(RS640x350,   RS4bpp ) },
+	{ 0x012, RSCreate(RS640x480,   RS4bpp ) },
+	{ 0x102, RSCreate(RS800x600,   RS4bpp ) },
+	{ 0x104, RSCreate(RS1024x768,  RS4bpp ) },
+	{ 0x106, RSCreate(RS1280x1024, RS4bpp ) },
+	{     0, 0				}};
+
+static void __init matroxfb_init_params(void) {
+	/* fh from kHz to Hz */
+	if (fh < 1000)
+		fh *= 1000;	/* 1kHz minimum */
+	/* maxclk */
+	if (maxclk < 1000) maxclk *= 1000;	/* kHz -> Hz, MHz -> kHz */
+	if (maxclk < 1000000) maxclk *= 1000;	/* kHz -> Hz, 1MHz minimum */
+	/* fix VESA number */
+	if (vesa != ~0)
+		vesa &= 0x1DFF;		/* mask out clearscreen, acceleration and so on */
+
+	/* static settings */
+	for (RSptr = vesamap; RSptr->vesa; RSptr++) {
+		if (RSptr->vesa == vesa) break;
+	}
+	if (!RSptr->vesa) {
+		printk(KERN_ERR "Invalid vesa mode 0x%04X\n", vesa);
+		RSptr = vesamap;
+	}
+	{
+		int res = RSResolution(RSptr->info)-1;
+		if (left == ~0)
+			left = timmings[res].left;
+		if (!xres)
+			xres = timmings[res].xres;
+		if (right == ~0)
+			right = timmings[res].right;
+		if (!hslen)
+			hslen = timmings[res].hslen;
+		if (upper == ~0)
+			upper = timmings[res].upper;
+		if (!yres)
+			yres = timmings[res].yres;
+		if (lower == ~0)
+			lower = timmings[res].lower;
+		if (!vslen)
+			vslen = timmings[res].vslen;
+		if (!(fv||fh||maxclk||pixclock))
+			fv = timmings[res].vfreq;
+		if (depth == -1)
+			depth = RSDepth(RSptr->info);
+	}
+}
+
+static void __init matrox_init(void) {
+	matroxfb_init_params();
+	pci_register_driver(&matroxfb_driver);
+	dev = -1;	/* accept all new devices... */
+}
+
+/* **************************** exit-time only **************************** */
+
+static void __exit matrox_done(void) {
+	pci_unregister_driver(&matroxfb_driver);
+}
+
+#ifndef MODULE
+
+/* ************************* init in-kernel code ************************** */
+
+static int __init matroxfb_setup(char *options) {
+	char *this_opt;
+
+	DBG(__FUNCTION__)
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt) continue;
+
+		dprintk("matroxfb_setup: option %s\n", this_opt);
+
+		if (!strncmp(this_opt, "dev:", 4))
+			dev = simple_strtoul(this_opt+4, NULL, 0);
+		else if (!strncmp(this_opt, "depth:", 6)) {
+			switch (simple_strtoul(this_opt+6, NULL, 0)) {
+				case 0: depth = RSText; break;
+				case 4: depth = RS4bpp; break;
+				case 8: depth = RS8bpp; break;
+				case 15:depth = RS15bpp; break;
+				case 16:depth = RS16bpp; break;
+				case 24:depth = RS24bpp; break;
+				case 32:depth = RS32bpp; break;
+				default:
+					printk(KERN_ERR "matroxfb: unsupported color depth\n");
+			}
+		} else if (!strncmp(this_opt, "xres:", 5))
+			xres = simple_strtoul(this_opt+5, NULL, 0);
+		else if (!strncmp(this_opt, "yres:", 5))
+			yres = simple_strtoul(this_opt+5, NULL, 0);
+		else if (!strncmp(this_opt, "vslen:", 6))
+			vslen = simple_strtoul(this_opt+6, NULL, 0);
+		else if (!strncmp(this_opt, "hslen:", 6))
+			hslen = simple_strtoul(this_opt+6, NULL, 0);
+		else if (!strncmp(this_opt, "left:", 5))
+			left = simple_strtoul(this_opt+5, NULL, 0);
+		else if (!strncmp(this_opt, "right:", 6))
+			right = simple_strtoul(this_opt+6, NULL, 0);
+		else if (!strncmp(this_opt, "upper:", 6))
+			upper = simple_strtoul(this_opt+6, NULL, 0);
+		else if (!strncmp(this_opt, "lower:", 6))
+			lower = simple_strtoul(this_opt+6, NULL, 0);
+		else if (!strncmp(this_opt, "pixclock:", 9))
+			pixclock = simple_strtoul(this_opt+9, NULL, 0);
+		else if (!strncmp(this_opt, "sync:", 5))
+			sync = simple_strtoul(this_opt+5, NULL, 0);
+		else if (!strncmp(this_opt, "vesa:", 5))
+			vesa = simple_strtoul(this_opt+5, NULL, 0);
+		else if (!strncmp(this_opt, "maxclk:", 7))
+			maxclk = simple_strtoul(this_opt+7, NULL, 0);
+		else if (!strncmp(this_opt, "fh:", 3))
+			fh = simple_strtoul(this_opt+3, NULL, 0);
+		else if (!strncmp(this_opt, "fv:", 3))
+			fv = simple_strtoul(this_opt+3, NULL, 0);
+		else if (!strncmp(this_opt, "mem:", 4))
+			mem = simple_strtoul(this_opt+4, NULL, 0);
+		else if (!strncmp(this_opt, "mode:", 5))
+			strlcpy(videomode, this_opt+5, sizeof(videomode));
+		else if (!strncmp(this_opt, "outputs:", 8))
+			strlcpy(outputs, this_opt+8, sizeof(outputs));
+		else if (!strncmp(this_opt, "dfp:", 4)) {
+			dfp_type = simple_strtoul(this_opt+4, NULL, 0);
+			dfp = 1;
+		}	
+#ifdef CONFIG_PPC_PMAC
+		else if (!strncmp(this_opt, "vmode:", 6)) {
+			unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
+			if (vmode > 0 && vmode <= VMODE_MAX)
+				default_vmode = vmode;
+		} else if (!strncmp(this_opt, "cmode:", 6)) {
+			unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0);
+			switch (cmode) {
+				case 0:
+				case 8:
+					default_cmode = CMODE_8;
+					break;
+				case 15:
+				case 16:
+					default_cmode = CMODE_16;
+					break;
+				case 24:
+				case 32:
+					default_cmode = CMODE_32;
+					break;
+			}
+		}
+#endif
+		else if (!strcmp(this_opt, "disabled"))	/* nodisabled does not exist */
+			disabled = 1;
+		else if (!strcmp(this_opt, "enabled"))	/* noenabled does not exist */
+			disabled = 0;
+		else if (!strcmp(this_opt, "sgram"))	/* nosgram == sdram */
+			sgram = 1;
+		else if (!strcmp(this_opt, "sdram"))
+			sgram = 0;
+		else if (!strncmp(this_opt, "memtype:", 8))
+			memtype = simple_strtoul(this_opt+8, NULL, 0);
+		else {
+			int value = 1;
+
+			if (!strncmp(this_opt, "no", 2)) {
+				value = 0;
+				this_opt += 2;
+			}
+			if (! strcmp(this_opt, "inverse"))
+				inverse = value;
+			else if (!strcmp(this_opt, "accel"))
+				noaccel = !value;
+			else if (!strcmp(this_opt, "pan"))
+				nopan = !value;
+			else if (!strcmp(this_opt, "pciretry"))
+				no_pci_retry = !value;
+			else if (!strcmp(this_opt, "vga"))
+				novga = !value;
+			else if (!strcmp(this_opt, "bios"))
+				nobios = !value;
+			else if (!strcmp(this_opt, "init"))
+				noinit = !value;
+#ifdef CONFIG_MTRR
+			else if (!strcmp(this_opt, "mtrr"))
+				mtrr = value;
+#endif
+			else if (!strcmp(this_opt, "inv24"))
+				inv24 = value;
+			else if (!strcmp(this_opt, "cross4MB"))
+				cross4MB = value;
+			else if (!strcmp(this_opt, "grayscale"))
+				grayscale = value;
+			else if (!strcmp(this_opt, "dfp"))
+				dfp = value;
+			else {
+				strlcpy(videomode, this_opt, sizeof(videomode));
+			}
+		}
+	}
+	return 0;
+}
+
+static int __initdata initialized = 0;
+
+static int __init matroxfb_init(void)
+{
+	char *option = NULL;
+
+	DBG(__FUNCTION__)
+
+	if (fb_get_options("matroxfb", &option))
+		return -ENODEV;
+	matroxfb_setup(option);
+
+	if (disabled)
+		return -ENXIO;
+	if (!initialized) {
+		initialized = 1;
+		matrox_init();
+	}
+	hotplug = 1;
+	/* never return failure, user can hotplug matrox later... */
+	return 0;
+}
+
+module_init(matroxfb_init);
+
+#else
+
+/* *************************** init module code **************************** */
+
+MODULE_AUTHOR("(c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400/G450/G550");
+MODULE_LICENSE("GPL");
+
+module_param(mem, int, 0);
+MODULE_PARM_DESC(mem, "Size of available memory in MB, KB or B (2,4,8,12,16MB, default=autodetect)");
+module_param(disabled, int, 0);
+MODULE_PARM_DESC(disabled, "Disabled (0 or 1=disabled) (default=0)");
+module_param(noaccel, int, 0);
+MODULE_PARM_DESC(noaccel, "Do not use accelerating engine (0 or 1=disabled) (default=0)");
+module_param(nopan, int, 0);
+MODULE_PARM_DESC(nopan, "Disable pan on startup (0 or 1=disabled) (default=0)");
+module_param(no_pci_retry, int, 0);
+MODULE_PARM_DESC(no_pci_retry, "PCI retries enabled (0 or 1=disabled) (default=0)");
+module_param(novga, int, 0);
+MODULE_PARM_DESC(novga, "VGA I/O (0x3C0-0x3DF) disabled (0 or 1=disabled) (default=0)");
+module_param(nobios, int, 0);
+MODULE_PARM_DESC(nobios, "Disables ROM BIOS (0 or 1=disabled) (default=do not change BIOS state)");
+module_param(noinit, int, 0);
+MODULE_PARM_DESC(noinit, "Disables W/SG/SD-RAM and bus interface initialization (0 or 1=do not initialize) (default=0)");
+module_param(memtype, int, 0);
+MODULE_PARM_DESC(memtype, "Memory type for G200/G400 (see Documentation/fb/matroxfb.txt for explanation) (default=3 for G200, 0 for G400)");
+#ifdef CONFIG_MTRR
+module_param(mtrr, int, 0);
+MODULE_PARM_DESC(mtrr, "This speeds up video memory accesses (0=disabled or 1) (default=1)");
+#endif
+module_param(sgram, int, 0);
+MODULE_PARM_DESC(sgram, "Indicates that G100/G200/G400 has SGRAM memory (0=SDRAM, 1=SGRAM) (default=0)");
+module_param(inv24, int, 0);
+MODULE_PARM_DESC(inv24, "Inverts clock polarity for 24bpp and loop frequency > 100MHz (default=do not invert polarity)");
+module_param(inverse, int, 0);
+MODULE_PARM_DESC(inverse, "Inverse (0 or 1) (default=0)");
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+module_param(dev, int, 0);
+MODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=all working)");
+#else
+module_param(dev, int, 0);
+MODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=first working)");
+#endif
+module_param(vesa, int, 0);
+MODULE_PARM_DESC(vesa, "Startup videomode (0x000-0x1FF) (default=0x101)");
+module_param(xres, int, 0);
+MODULE_PARM_DESC(xres, "Horizontal resolution (px), overrides xres from vesa (default=vesa)");
+module_param(yres, int, 0);
+MODULE_PARM_DESC(yres, "Vertical resolution (scans), overrides yres from vesa (default=vesa)");
+module_param(upper, int, 0);
+MODULE_PARM_DESC(upper, "Upper blank space (scans), overrides upper from vesa (default=vesa)");
+module_param(lower, int, 0);
+MODULE_PARM_DESC(lower, "Lower blank space (scans), overrides lower from vesa (default=vesa)");
+module_param(vslen, int, 0);
+MODULE_PARM_DESC(vslen, "Vertical sync length (scans), overrides lower from vesa (default=vesa)");
+module_param(left, int, 0);
+MODULE_PARM_DESC(left, "Left blank space (px), overrides left from vesa (default=vesa)");
+module_param(right, int, 0);
+MODULE_PARM_DESC(right, "Right blank space (px), overrides right from vesa (default=vesa)");
+module_param(hslen, int, 0);
+MODULE_PARM_DESC(hslen, "Horizontal sync length (px), overrides hslen from vesa (default=vesa)");
+module_param(pixclock, int, 0);
+MODULE_PARM_DESC(pixclock, "Pixelclock (ns), overrides pixclock from vesa (default=vesa)");
+module_param(sync, int, 0);
+MODULE_PARM_DESC(sync, "Sync polarity, overrides sync from vesa (default=vesa)");
+module_param(depth, int, 0);
+MODULE_PARM_DESC(depth, "Color depth (0=text,8,15,16,24,32) (default=vesa)");
+module_param(maxclk, int, 0);
+MODULE_PARM_DESC(maxclk, "Startup maximal clock, 0-999MHz, 1000-999999kHz, 1000000-INF Hz");
+module_param(fh, int, 0);
+MODULE_PARM_DESC(fh, "Startup horizontal frequency, 0-999kHz, 1000-INF Hz");
+module_param(fv, int, 0);
+MODULE_PARM_DESC(fv, "Startup vertical frequency, 0-INF Hz\n"
+"You should specify \"fv:max_monitor_vsync,fh:max_monitor_hsync,maxclk:max_monitor_dotclock\"\n");
+module_param(grayscale, int, 0);
+MODULE_PARM_DESC(grayscale, "Sets display into grayscale. Works perfectly with paletized videomode (4, 8bpp), some limitations apply to 16, 24 and 32bpp videomodes (default=nograyscale)");
+module_param(cross4MB, int, 0);
+MODULE_PARM_DESC(cross4MB, "Specifies that 4MB boundary can be in middle of line. (default=autodetected)");
+module_param(dfp, int, 0);
+MODULE_PARM_DESC(dfp, "Specifies whether to use digital flat panel interface of G200/G400 (0 or 1) (default=0)");
+module_param(dfp_type, int, 0);
+MODULE_PARM_DESC(dfp_type, "Specifies DFP interface type (0 to 255) (default=read from hardware)");
+module_param_string(outputs, outputs, sizeof(outputs), 0);
+MODULE_PARM_DESC(outputs, "Specifies which CRTC is mapped to which output (string of up to three letters, consisting of 0 (disabled), 1 (CRTC1), 2 (CRTC2)) (default=111 for Gx50, 101 for G200/G400 with DFP, and 100 for all other devices)");
+#ifdef CONFIG_PPC_PMAC
+module_param_named(vmode, default_vmode, int, 0);
+MODULE_PARM_DESC(vmode, "Specify the vmode mode number that should be used (640x480 default)");
+module_param_named(cmode, default_cmode, int, 0);
+MODULE_PARM_DESC(cmode, "Specify the video depth that should be used (8bit default)");
+#endif
+
+int __init init_module(void){
+
+	DBG(__FUNCTION__)
+
+	if (disabled)
+		return -ENXIO;
+
+	if (depth == 0)
+		depth = RSText;
+	else if (depth == 4)
+		depth = RS4bpp;
+	else if (depth == 8)
+		depth = RS8bpp;
+	else if (depth == 15)
+		depth = RS15bpp;
+	else if (depth == 16)
+		depth = RS16bpp;
+	else if (depth == 24)
+		depth = RS24bpp;
+	else if (depth == 32)
+		depth = RS32bpp;
+	else if (depth != -1) {
+		printk(KERN_ERR "matroxfb: depth %d is not supported, using default\n", depth);
+		depth = -1;
+	}
+	matrox_init();
+	/* never return failure; user can hotplug matrox later... */
+	return 0;
+}
+#endif	/* MODULE */
+
+module_exit(matrox_done);
+EXPORT_SYMBOL(matroxfb_register_driver);
+EXPORT_SYMBOL(matroxfb_unregister_driver);
+EXPORT_SYMBOL(matroxfb_wait_for_sync);
+EXPORT_SYMBOL(matroxfb_enable_irq);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h
new file mode 100644
index 0000000..85a0b25
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_base.h
@@ -0,0 +1,781 @@
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450
+ *
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ */
+#ifndef __MATROXFB_H__
+#define __MATROXFB_H__
+
+/* general, but fairly heavy, debugging */
+#undef MATROXFB_DEBUG
+
+/* heavy debugging: */
+/* -- logs putc[s], so everytime a char is displayed, it's logged */
+#undef MATROXFB_DEBUG_HEAVY
+
+/* This one _could_ cause infinite loops */
+/* It _does_ cause lots and lots of messages during idle loops */
+#undef MATROXFB_DEBUG_LOOP
+
+/* Debug register calls, too? */
+#undef MATROXFB_DEBUG_REG
+
+/* Guard accelerator accesses with spin_lock_irqsave... */
+#undef MATROXFB_USE_SPINLOCKS
+
+#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/delay.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/selection.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/kd.h>
+
+#include <asm/io.h>
+#include <asm/unaligned.h>
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include "../console/fbcon.h"
+
+#if defined(CONFIG_PPC_PMAC)
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include "../macmodes.h"
+#endif
+
+/* always compile support for 32MB... It cost almost nothing */
+#define CONFIG_FB_MATROX_32MB
+
+#ifdef MATROXFB_DEBUG
+
+#define DEBUG
+#define DBG(x)		printk(KERN_DEBUG "matroxfb: %s\n", (x));
+
+#ifdef MATROXFB_DEBUG_HEAVY
+#define DBG_HEAVY(x)	DBG(x)
+#else /* MATROXFB_DEBUG_HEAVY */
+#define DBG_HEAVY(x)	/* DBG_HEAVY */
+#endif /* MATROXFB_DEBUG_HEAVY */
+
+#ifdef MATROXFB_DEBUG_LOOP
+#define DBG_LOOP(x)	DBG(x)
+#else /* MATROXFB_DEBUG_LOOP */
+#define DBG_LOOP(x)	/* DBG_LOOP */
+#endif /* MATROXFB_DEBUG_LOOP */
+
+#ifdef MATROXFB_DEBUG_REG
+#define DBG_REG(x)	DBG(x)
+#else /* MATROXFB_DEBUG_REG */
+#define DBG_REG(x)	/* DBG_REG */
+#endif /* MATROXFB_DEBUG_REG */
+
+#else /* MATROXFB_DEBUG */
+
+#define DBG(x)		/* DBG */
+#define DBG_HEAVY(x)	/* DBG_HEAVY */
+#define DBG_REG(x)	/* DBG_REG */
+#define DBG_LOOP(x)	/* DBG_LOOP */
+
+#endif /* MATROXFB_DEBUG */
+
+#ifdef DEBUG
+#define dprintk(X...)	printk(X)
+#else
+#define dprintk(X...)
+#endif
+
+#ifndef PCI_SS_VENDOR_ID_SIEMENS_NIXDORF
+#define PCI_SS_VENDOR_ID_SIEMENS_NIXDORF	0x110A
+#endif
+#ifndef PCI_SS_VENDOR_ID_MATROX
+#define PCI_SS_VENDOR_ID_MATROX		PCI_VENDOR_ID_MATROX
+#endif
+
+#ifndef PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP
+#define PCI_SS_ID_MATROX_GENERIC		0xFF00
+#define PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP	0xFF01
+#define PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP	0xFF02
+#define PCI_SS_ID_MATROX_MILLENIUM_G200_AGP	0xFF03
+#define PCI_SS_ID_MATROX_MARVEL_G200_AGP	0xFF04
+#define PCI_SS_ID_MATROX_MGA_G100_PCI		0xFF05
+#define PCI_SS_ID_MATROX_MGA_G100_AGP		0x1001
+#define PCI_SS_ID_MATROX_MILLENNIUM_G400_MAX_AGP	0x2179
+#define PCI_SS_ID_SIEMENS_MGA_G100_AGP		0x001E /* 30 */
+#define PCI_SS_ID_SIEMENS_MGA_G200_AGP		0x0032 /* 50 */
+#endif
+
+#define MX_VISUAL_TRUECOLOR	FB_VISUAL_DIRECTCOLOR
+#define MX_VISUAL_DIRECTCOLOR	FB_VISUAL_TRUECOLOR
+#define MX_VISUAL_PSEUDOCOLOR	FB_VISUAL_PSEUDOCOLOR
+
+#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+
+/* G-series and Mystique have (almost) same DAC */
+#undef NEED_DAC1064
+#if defined(CONFIG_FB_MATROX_MYSTIQUE) || defined(CONFIG_FB_MATROX_G)
+#define NEED_DAC1064 1
+#endif
+
+typedef struct {
+	void __iomem*	vaddr;
+} vaddr_t;
+
+static inline unsigned int mga_readb(vaddr_t va, unsigned int offs) {
+	return readb(va.vaddr + offs);
+}
+
+static inline void mga_writeb(vaddr_t va, unsigned int offs, u_int8_t value) {
+	writeb(value, va.vaddr + offs);
+}
+
+static inline void mga_writew(vaddr_t va, unsigned int offs, u_int16_t value) {
+	writew(value, va.vaddr + offs);
+}
+
+static inline u_int32_t mga_readl(vaddr_t va, unsigned int offs) {
+	return readl(va.vaddr + offs);
+}
+
+static inline void mga_writel(vaddr_t va, unsigned int offs, u_int32_t value) {
+	writel(value, va.vaddr + offs);
+}
+
+static inline void mga_memcpy_toio(vaddr_t va, const void* src, int len) {
+#if defined(__alpha__) || defined(__i386__) || defined(__x86_64__)
+	/*
+	 * memcpy_toio works for us if:
+	 *  (1) Copies data as 32bit quantities, not byte after byte,
+	 *  (2) Performs LE ordered stores, and
+	 *  (3) It copes with unaligned source (destination is guaranteed to be page
+	 *      aligned and length is guaranteed to be multiple of 4).
+	 */
+	memcpy_toio(va.vaddr, src, len);
+#else
+        u_int32_t __iomem* addr = va.vaddr;
+
+	if ((unsigned long)src & 3) {
+		while (len >= 4) {
+			fb_writel(get_unaligned((u32 *)src), addr);
+			addr++;
+			len -= 4;
+			src += 4;
+		}
+	} else {
+		while (len >= 4) {
+			fb_writel(*(u32 *)src, addr);
+			addr++;
+			len -= 4;
+			src += 4;
+		}
+	}
+#endif
+}
+
+static inline void vaddr_add(vaddr_t* va, unsigned long offs) {
+	va->vaddr += offs;
+}
+
+static inline void __iomem* vaddr_va(vaddr_t va) {
+	return va.vaddr;
+}
+
+#define MGA_IOREMAP_NORMAL	0
+#define MGA_IOREMAP_NOCACHE	1
+
+#define MGA_IOREMAP_FB		MGA_IOREMAP_NOCACHE
+#define MGA_IOREMAP_MMIO	MGA_IOREMAP_NOCACHE
+static inline int mga_ioremap(unsigned long phys, unsigned long size, int flags, vaddr_t* virt) {
+	if (flags & MGA_IOREMAP_NOCACHE)
+		virt->vaddr = ioremap_nocache(phys, size);
+	else
+		virt->vaddr = ioremap(phys, size);
+	return (virt->vaddr == 0); /* 0, !0... 0, error_code in future */
+}
+
+static inline void mga_iounmap(vaddr_t va) {
+	iounmap(va.vaddr);
+}
+
+struct my_timming {
+	unsigned int pixclock;
+	int mnp;
+	unsigned int crtc;
+	unsigned int HDisplay;
+	unsigned int HSyncStart;
+	unsigned int HSyncEnd;
+	unsigned int HTotal;
+	unsigned int VDisplay;
+	unsigned int VSyncStart;
+	unsigned int VSyncEnd;
+	unsigned int VTotal;
+	unsigned int sync;
+	int	     dblscan;
+	int	     interlaced;
+	unsigned int delay;	/* CRTC delay */
+};
+
+enum { M_SYSTEM_PLL, M_PIXEL_PLL_A, M_PIXEL_PLL_B, M_PIXEL_PLL_C, M_VIDEO_PLL };
+
+struct matrox_pll_cache {
+	unsigned int	valid;
+	struct {
+		unsigned int	mnp_key;
+		unsigned int	mnp_value;
+		      } data[4];
+};
+
+struct matrox_pll_limits {
+	unsigned int	vcomin;
+	unsigned int	vcomax;
+};
+
+struct matrox_pll_features {
+	unsigned int	vco_freq_min;
+	unsigned int	ref_freq;
+	unsigned int	feed_div_min;
+	unsigned int	feed_div_max;
+	unsigned int	in_div_min;
+	unsigned int	in_div_max;
+	unsigned int	post_shift_max;
+};
+
+struct matroxfb_par
+{
+	unsigned int	final_bppShift;
+	unsigned int	cmap_len;
+	struct {
+		unsigned int bytes;
+		unsigned int pixels;
+		unsigned int chunks;
+		      } ydstorg;
+};
+
+struct matrox_fb_info;
+
+struct matrox_DAC1064_features {
+	u_int8_t	xvrefctrl;
+	u_int8_t	xmiscctrl;
+};
+
+struct matrox_accel_features {
+	int		has_cacheflush;
+};
+
+/* current hardware status */
+struct mavenregs {
+	u_int8_t regs[256];
+	int	 mode;
+	int	 vlines;
+	int	 xtal;
+	int	 fv;
+
+	u_int16_t htotal;
+	u_int16_t hcorr;
+};
+
+struct matrox_crtc2 {
+	u_int32_t ctl;
+};
+
+struct matrox_hw_state {
+	u_int32_t	MXoptionReg;
+	unsigned char	DACclk[6];
+	unsigned char	DACreg[80];
+	unsigned char	MiscOutReg;
+	unsigned char	DACpal[768];
+	unsigned char	CRTC[25];
+	unsigned char	CRTCEXT[9];
+	unsigned char	SEQ[5];
+	/* unused for MGA mode, but who knows... */
+	unsigned char	GCTL[9];
+	/* unused for MGA mode, but who knows... */
+	unsigned char	ATTR[21];
+
+	/* TVOut only */
+	struct mavenregs	maven;
+
+	struct matrox_crtc2	crtc2;
+};
+
+struct matrox_accel_data {
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+	unsigned char	ramdac_rev;
+#endif
+	u_int32_t	m_dwg_rect;
+	u_int32_t	m_opmode;
+};
+
+struct v4l2_queryctrl;
+struct v4l2_control;
+
+struct matrox_altout {
+	const char	*name;
+	int		(*compute)(void* altout_dev, struct my_timming* input);
+	int		(*program)(void* altout_dev);
+	int		(*start)(void* altout_dev);
+	int		(*verifymode)(void* altout_dev, u_int32_t mode);
+	int		(*getqueryctrl)(void* altout_dev,
+					struct v4l2_queryctrl* ctrl);
+	int		(*getctrl)(void* altout_dev, 
+				   struct v4l2_control* ctrl);
+	int		(*setctrl)(void* altout_dev, 
+				   struct v4l2_control* ctrl);
+};
+
+#define MATROXFB_SRC_NONE	0
+#define MATROXFB_SRC_CRTC1	1
+#define MATROXFB_SRC_CRTC2	2
+
+enum mga_chip { MGA_2064, MGA_2164, MGA_1064, MGA_1164, MGA_G100, MGA_G200, MGA_G400, MGA_G450, MGA_G550 };
+
+struct matrox_bios {
+	unsigned int	bios_valid : 1;
+	unsigned int	pins_len;
+	unsigned char	pins[128];
+	struct {
+		unsigned char vMaj, vMin, vRev;
+		      } version;
+	struct {
+		unsigned char state, tvout;
+		      } output;
+};
+
+extern struct display fb_display[];
+
+struct matrox_switch;
+struct matroxfb_driver;
+struct matroxfb_dh_fb_info;
+
+struct matrox_vsync {
+	wait_queue_head_t	wait;
+	unsigned int		cnt;
+};
+
+struct matrox_fb_info {
+	struct fb_info		fbcon;
+
+	struct list_head	next_fb;
+
+	int			dead;
+	int                     initialized;
+	unsigned int		usecount;
+
+	unsigned int		userusecount;
+	unsigned long		irq_flags;
+
+	struct matroxfb_par	curr;
+	struct matrox_hw_state	hw;
+
+	struct matrox_accel_data accel;
+
+	struct pci_dev*		pcidev;
+
+	struct {
+		struct matrox_vsync	vsync;
+		unsigned int	pixclock;
+		int		mnp;
+		int		panpos;
+			      } crtc1;
+	struct {
+		struct matrox_vsync	vsync;
+		unsigned int 	pixclock;
+		int		mnp;
+	struct matroxfb_dh_fb_info*	info;
+	struct rw_semaphore	lock;
+			      } crtc2;
+	struct {
+	struct rw_semaphore	lock;
+	struct {
+		int brightness, contrast, saturation, hue, gamma;
+		int testout, deflicker;
+				} tvo_params;
+			      } altout;
+#define MATROXFB_MAX_OUTPUTS		3
+	struct {
+	unsigned int		src;
+	struct matrox_altout*	output;
+	void*			data;
+	unsigned int		mode;
+	unsigned int		default_src;
+			      } outputs[MATROXFB_MAX_OUTPUTS];
+
+#define MATROXFB_MAX_FB_DRIVERS		5
+	struct matroxfb_driver* (drivers[MATROXFB_MAX_FB_DRIVERS]);
+	void*			(drivers_data[MATROXFB_MAX_FB_DRIVERS]);
+	unsigned int		drivers_count;
+
+	struct {
+	unsigned long	base;	/* physical */
+	vaddr_t		vbase;	/* CPU view */
+	unsigned int	len;
+	unsigned int	len_usable;
+	unsigned int	len_maximum;
+		      } video;
+
+	struct {
+	unsigned long	base;	/* physical */
+	vaddr_t		vbase;	/* CPU view */
+	unsigned int	len;
+		      } mmio;
+
+	unsigned int	max_pixel_clock;
+
+	struct matrox_switch*	hw_switch;
+
+	struct {
+		struct matrox_pll_features pll;
+		struct matrox_DAC1064_features DAC1064;
+		struct matrox_accel_features accel;
+			      } features;
+	struct {
+		spinlock_t	DAC;
+		spinlock_t	accel;
+			      } lock;
+
+	enum mga_chip		chip;
+
+	int			interleave;
+	int			millenium;
+	int			milleniumII;
+	struct {
+		int		cfb4;
+		const int*	vxres;
+		int		cross4MB;
+		int		text;
+		int		plnwt;
+		int		srcorg;
+			      } capable;
+#ifdef CONFIG_MTRR
+	struct {
+		int		vram;
+		int		vram_valid;
+			      } mtrr;
+#endif
+	struct {
+		int		precise_width;
+		int		mga_24bpp_fix;
+		int		novga;
+		int		nobios;
+		int		nopciretry;
+		int		noinit;
+		int		sgram;
+#ifdef CONFIG_FB_MATROX_32MB
+		int		support32MB;
+#endif
+
+		int		accelerator;
+		int		text_type_aux;
+		int		video64bits;
+		int		crtc2;
+		int		maven_capable;
+		unsigned int	vgastep;
+		unsigned int	textmode;
+		unsigned int	textstep;
+		unsigned int	textvram;	/* character cells */
+		unsigned int	ydstorg;	/* offset in bytes from video start to usable memory */
+						/* 0 except for 6MB Millenium */
+		int		memtype;
+		int		g450dac;
+		int		dfp_type;
+		int		panellink;	/* G400 DFP possible (not G450/G550) */
+		int		dualhead;
+		unsigned int	fbResource;
+			      } devflags;
+	struct fb_ops		fbops;
+	struct matrox_bios	bios;
+	struct {
+		struct matrox_pll_limits	pixel;
+		struct matrox_pll_limits	system;
+		struct matrox_pll_limits	video;
+			      } limits;
+	struct {
+		struct matrox_pll_cache	pixel;
+		struct matrox_pll_cache	system;
+		struct matrox_pll_cache	video;
+				      } cache;
+	struct {
+		struct {
+			unsigned int	video;
+			unsigned int	system;
+				      } pll;
+		struct {
+			u_int32_t	opt;
+			u_int32_t	opt2;
+			u_int32_t	opt3;
+			u_int32_t	mctlwtst;
+			u_int32_t	mctlwtst_core;
+			u_int32_t	memmisc;
+			u_int32_t	memrdbk;
+			u_int32_t	maccess;
+				      } reg;
+		struct {
+			unsigned int	ddr:1,
+			                emrswen:1,
+					dll:1;
+				      } memory;
+			      } values;
+	u_int32_t cmap[17];
+};
+
+#define info2minfo(info) container_of(info, struct matrox_fb_info, fbcon)
+
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+#define ACCESS_FBINFO2(info, x) (info->x)
+#define ACCESS_FBINFO(x) ACCESS_FBINFO2(minfo,x)
+
+#define MINFO minfo
+
+#define WPMINFO2 struct matrox_fb_info* minfo
+#define WPMINFO  WPMINFO2 ,
+#define CPMINFO2 const struct matrox_fb_info* minfo
+#define CPMINFO	 CPMINFO2 ,
+#define PMINFO2  minfo
+#define PMINFO   PMINFO2 ,
+
+#define MINFO_FROM(x)	   struct matrox_fb_info* minfo = x
+#else
+
+extern struct matrox_fb_info matroxfb_global_mxinfo;
+
+#define ACCESS_FBINFO(x) (matroxfb_global_mxinfo.x)
+#define ACCESS_FBINFO2(info, x) (matroxfb_global_mxinfo.x)
+
+#define MINFO (&matroxfb_global_mxinfo)
+
+#define WPMINFO2 void
+#define WPMINFO
+#define CPMINFO2 void
+#define CPMINFO
+#define PMINFO2
+#define PMINFO
+
+#define MINFO_FROM(x)
+
+#endif
+
+#define MINFO_FROM_INFO(x) MINFO_FROM(info2minfo(x))
+
+struct matrox_switch {
+	int	(*preinit)(WPMINFO2);
+	void	(*reset)(WPMINFO2);
+	int	(*init)(WPMINFO struct my_timming*);
+	void	(*restore)(WPMINFO2);
+};
+
+struct matroxfb_driver {
+	struct list_head	node;
+	char*			name;
+	void*			(*probe)(struct matrox_fb_info* info);
+	void			(*remove)(struct matrox_fb_info* info, void* data);
+};
+
+int matroxfb_register_driver(struct matroxfb_driver* drv);
+void matroxfb_unregister_driver(struct matroxfb_driver* drv);
+
+#define PCI_OPTION_REG	0x40
+#define   PCI_OPTION_ENABLE_ROM		0x40000000
+
+#define PCI_MGA_INDEX	0x44
+#define PCI_MGA_DATA	0x48
+#define PCI_OPTION2_REG	0x50
+#define PCI_OPTION3_REG	0x54
+#define PCI_MEMMISC_REG	0x58
+
+#define M_DWGCTL	0x1C00
+#define M_MACCESS	0x1C04
+#define M_CTLWTST	0x1C08
+
+#define M_PLNWT		0x1C1C
+
+#define M_BCOL		0x1C20
+#define M_FCOL		0x1C24
+
+#define M_SGN		0x1C58
+#define M_LEN		0x1C5C
+#define M_AR0		0x1C60
+#define M_AR1		0x1C64
+#define M_AR2		0x1C68
+#define M_AR3		0x1C6C
+#define M_AR4		0x1C70
+#define M_AR5		0x1C74
+#define M_AR6		0x1C78
+
+#define M_CXBNDRY	0x1C80
+#define M_FXBNDRY	0x1C84
+#define M_YDSTLEN	0x1C88
+#define M_PITCH		0x1C8C
+#define M_YDST		0x1C90
+#define M_YDSTORG	0x1C94
+#define M_YTOP		0x1C98
+#define M_YBOT		0x1C9C
+
+/* mystique only */
+#define M_CACHEFLUSH	0x1FFF
+
+#define M_EXEC		0x0100
+
+#define M_DWG_TRAP	0x04
+#define M_DWG_BITBLT	0x08
+#define M_DWG_ILOAD	0x09
+
+#define M_DWG_LINEAR	0x0080
+#define M_DWG_SOLID	0x0800
+#define M_DWG_ARZERO	0x1000
+#define M_DWG_SGNZERO	0x2000
+#define M_DWG_SHIFTZERO	0x4000
+
+#define M_DWG_REPLACE	0x000C0000
+#define M_DWG_REPLACE2	(M_DWG_REPLACE | 0x40)
+#define M_DWG_XOR	0x00060010
+
+#define M_DWG_BFCOL	0x04000000
+#define M_DWG_BMONOWF	0x08000000
+
+#define M_DWG_TRANSC	0x40000000
+
+#define M_FIFOSTATUS	0x1E10
+#define M_STATUS	0x1E14
+#define M_ICLEAR	0x1E18
+#define M_IEN		0x1E1C
+
+#define M_VCOUNT	0x1E20
+
+#define M_RESET		0x1E40
+#define M_MEMRDBK	0x1E44
+
+#define M_AGP2PLL	0x1E4C
+
+#define M_OPMODE	0x1E54
+#define     M_OPMODE_DMA_GEN_WRITE	0x00
+#define     M_OPMODE_DMA_BLIT		0x04
+#define     M_OPMODE_DMA_VECTOR_WRITE	0x08
+#define     M_OPMODE_DMA_LE		0x0000		/* little endian - no transformation */
+#define     M_OPMODE_DMA_BE_8BPP	0x0000
+#define     M_OPMODE_DMA_BE_16BPP	0x0100
+#define     M_OPMODE_DMA_BE_32BPP	0x0200
+#define     M_OPMODE_DIR_LE		0x000000	/* little endian - no transformation */
+#define     M_OPMODE_DIR_BE_8BPP	0x000000
+#define     M_OPMODE_DIR_BE_16BPP	0x010000
+#define     M_OPMODE_DIR_BE_32BPP	0x020000
+
+#define M_ATTR_INDEX	0x1FC0
+#define M_ATTR_DATA	0x1FC1
+
+#define M_MISC_REG	0x1FC2
+#define M_3C2_RD	0x1FC2
+
+#define M_SEQ_INDEX	0x1FC4
+#define M_SEQ_DATA	0x1FC5
+
+#define M_MISC_REG_READ	0x1FCC
+
+#define M_GRAPHICS_INDEX 0x1FCE
+#define M_GRAPHICS_DATA	0x1FCF
+
+#define M_CRTC_INDEX	0x1FD4
+
+#define M_ATTR_RESET	0x1FDA
+#define M_3DA_WR	0x1FDA
+#define M_INSTS1	0x1FDA
+
+#define M_EXTVGA_INDEX	0x1FDE
+#define M_EXTVGA_DATA	0x1FDF
+
+/* G200 only */
+#define M_SRCORG	0x2CB4
+#define M_DSTORG	0x2CB8
+
+#define M_RAMDAC_BASE	0x3C00
+
+/* fortunately, same on TVP3026 and MGA1064 */
+#define M_DAC_REG	(M_RAMDAC_BASE+0)
+#define M_DAC_VAL	(M_RAMDAC_BASE+1)
+#define M_PALETTE_MASK	(M_RAMDAC_BASE+2)
+
+#define M_X_INDEX	0x00
+#define M_X_DATAREG	0x0A
+
+#define DAC_XGENIOCTRL		0x2A
+#define DAC_XGENIODATA		0x2B
+
+#define M_C2CTL		0x3C10
+
+#define MX_OPTION_BSWAP         0x00000000
+
+#ifdef __LITTLE_ENDIAN
+#define M_OPMODE_4BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_8BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_16BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_24BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_32BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#else
+#ifdef __BIG_ENDIAN
+#define M_OPMODE_4BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_LE       | M_OPMODE_DMA_BLIT)	/* TODO */
+#define M_OPMODE_8BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_BE_8BPP  | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_16BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_BE_16BPP | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_24BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_BE_8BPP  | M_OPMODE_DMA_BLIT)	/* TODO, ?32 */
+#define M_OPMODE_32BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_BE_32BPP | M_OPMODE_DMA_BLIT)
+#else
+#error "Byte ordering have to be defined. Cannot continue."
+#endif
+#endif
+
+#define mga_inb(addr)		mga_readb(ACCESS_FBINFO(mmio.vbase), (addr))
+#define mga_inl(addr)		mga_readl(ACCESS_FBINFO(mmio.vbase), (addr))
+#define mga_outb(addr,val)	mga_writeb(ACCESS_FBINFO(mmio.vbase), (addr), (val))
+#define mga_outw(addr,val)	mga_writew(ACCESS_FBINFO(mmio.vbase), (addr), (val))
+#define mga_outl(addr,val)	mga_writel(ACCESS_FBINFO(mmio.vbase), (addr), (val))
+#define mga_readr(port,idx)	(mga_outb((port),(idx)), mga_inb((port)+1))
+#define mga_setr(addr,port,val)	mga_outw(addr, ((val)<<8) | (port))
+
+#define mga_fifo(n)	do {} while ((mga_inl(M_FIFOSTATUS) & 0xFF) < (n))
+
+#define WaitTillIdle()	do {} while (mga_inl(M_STATUS) & 0x10000)
+
+/* code speedup */
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+#define isInterleave(x)	 (x->interleave)
+#define isMillenium(x)	 (x->millenium)
+#define isMilleniumII(x) (x->milleniumII)
+#else
+#define isInterleave(x)  (0)
+#define isMillenium(x)	 (0)
+#define isMilleniumII(x) (0)
+#endif
+
+#define matroxfb_DAC_lock()                   spin_lock(&ACCESS_FBINFO(lock.DAC))
+#define matroxfb_DAC_unlock()                 spin_unlock(&ACCESS_FBINFO(lock.DAC))
+#define matroxfb_DAC_lock_irqsave(flags)      spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC),flags)
+#define matroxfb_DAC_unlock_irqrestore(flags) spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC),flags)
+extern void matroxfb_DAC_out(CPMINFO int reg, int val);
+extern int matroxfb_DAC_in(CPMINFO int reg);
+extern void matroxfb_var2my(struct fb_var_screeninfo* fvsi, struct my_timming* mt);
+extern int matroxfb_wait_for_sync(WPMINFO u_int32_t crtc);
+extern int matroxfb_enable_irq(WPMINFO int reenable);
+
+#ifdef MATROXFB_USE_SPINLOCKS
+#define CRITBEGIN  spin_lock_irqsave(&ACCESS_FBINFO(lock.accel), critflags);
+#define CRITEND	   spin_unlock_irqrestore(&ACCESS_FBINFO(lock.accel), critflags);
+#define CRITFLAGS  unsigned long critflags;
+#else
+#define CRITBEGIN
+#define CRITEND
+#define CRITFLAGS
+#endif
+
+#endif	/* __MATROXFB_H__ */
diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c
new file mode 100644
index 0000000..429047a
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_crtc2.c
@@ -0,0 +1,741 @@
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
+ *
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Portions Copyright (c) 2001 Matrox Graphics Inc.
+ *
+ * Version: 1.65 2002/08/14
+ *
+ */
+
+#include "matroxfb_maven.h"
+#include "matroxfb_crtc2.h"
+#include "matroxfb_misc.h"
+#include "matroxfb_DAC1064.h"
+#include <linux/matroxfb.h>
+#include <asm/uaccess.h>
+
+/* **************************************************** */
+
+static int mem = 8192;
+
+module_param(mem, int, 0);
+MODULE_PARM_DESC(mem, "Memory size reserved for dualhead (default=8MB)");
+
+/* **************************************************** */
+
+static int matroxfb_dh_setcolreg(unsigned regno, unsigned red, unsigned green,
+		unsigned blue, unsigned transp, struct fb_info* info) {
+	u_int32_t col;
+#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
+
+	if (regno >= 16)
+		return 1;
+	if (m2info->fbcon.var.grayscale) {
+		/* gray = 0.30*R + 0.59*G + 0.11*B */
+		red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+	}
+	red = CNVT_TOHW(red, m2info->fbcon.var.red.length);
+	green = CNVT_TOHW(green, m2info->fbcon.var.green.length);
+	blue = CNVT_TOHW(blue, m2info->fbcon.var.blue.length);
+	transp = CNVT_TOHW(transp, m2info->fbcon.var.transp.length);
+
+	col = (red << m2info->fbcon.var.red.offset)     |
+	      (green << m2info->fbcon.var.green.offset) |
+	      (blue << m2info->fbcon.var.blue.offset)   |
+	      (transp << m2info->fbcon.var.transp.offset);
+
+	switch (m2info->fbcon.var.bits_per_pixel) {
+		case 16:
+			m2info->cmap[regno] = col | (col << 16);
+			break;
+		case 32:
+			m2info->cmap[regno] = col;
+			break;
+	}
+	return 0;
+#undef m2info
+}
+
+static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info,
+		struct my_timming* mt,
+		int mode,
+		unsigned int pos) {
+	u_int32_t tmp;
+	u_int32_t datactl;
+	MINFO_FROM(m2info->primary_dev);
+
+	switch (mode) {
+		case 15:
+			tmp = 0x00200000;
+			break;
+		case 16:
+			tmp = 0x00400000;
+			break;
+/*		case 32: */
+		default:
+			tmp = 0x00800000;
+			break;
+	}
+	tmp |= 0x00000001;	/* enable CRTC2 */
+	datactl = 0;
+	if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC2) {
+		if (ACCESS_FBINFO(devflags.g450dac)) {
+			tmp |= 0x00000006; /* source from secondary pixel PLL */
+			/* no vidrst when in monitor mode */
+			if (ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) {
+				tmp |=  0xC0001000; /* Enable H/V vidrst */
+			}
+		} else {
+			tmp |= 0x00000002; /* source from VDOCLK */
+			tmp |= 0xC0000000; /* enable vvidrst & hvidrst */
+			/* MGA TVO is our clock source */
+		}
+	} else if (ACCESS_FBINFO(outputs[0]).src == MATROXFB_SRC_CRTC2) {
+		tmp |= 0x00000004; /* source from pixclock */
+		/* PIXPLL is our clock source */
+	}
+	if (ACCESS_FBINFO(outputs[0]).src == MATROXFB_SRC_CRTC2) {
+		tmp |= 0x00100000;	/* connect CRTC2 to DAC */
+	}
+	if (mt->interlaced) {
+		tmp |= 0x02000000;	/* interlaced, second field is bigger, as G450 apparently ignores it */
+		mt->VDisplay >>= 1;
+		mt->VSyncStart >>= 1;
+		mt->VSyncEnd >>= 1;
+		mt->VTotal >>= 1;
+	}
+	if ((mt->HTotal & 7) == 2) {
+		datactl |= 0x00000010;
+		mt->HTotal &= ~7;
+	}
+	tmp |= 0x10000000;	/* 0x10000000 is VIDRST polarity */
+	mga_outl(0x3C14, ((mt->HDisplay - 8) << 16) | (mt->HTotal - 8));
+	mga_outl(0x3C18, ((mt->HSyncEnd - 8) << 16) | (mt->HSyncStart - 8));
+	mga_outl(0x3C1C, ((mt->VDisplay - 1) << 16) | (mt->VTotal - 1));
+	mga_outl(0x3C20, ((mt->VSyncEnd - 1) << 16) | (mt->VSyncStart - 1));
+	mga_outl(0x3C24, ((mt->VSyncStart) << 16) | (mt->HSyncStart));	/* preload */
+	{
+		u_int32_t linelen = m2info->fbcon.var.xres_virtual * (m2info->fbcon.var.bits_per_pixel >> 3);
+		if (tmp & 0x02000000) {
+			/* field #0 is smaller, so... */
+			mga_outl(0x3C2C, pos);			/* field #1 vmemory start */
+			mga_outl(0x3C28, pos + linelen);	/* field #0 vmemory start */
+			linelen <<= 1;
+			m2info->interlaced = 1;
+		} else {
+			mga_outl(0x3C28, pos);		/* vmemory start */
+			m2info->interlaced = 0;
+		}
+		mga_outl(0x3C40, linelen);
+	}
+	mga_outl(0x3C4C, datactl);	/* data control */
+	if (tmp & 0x02000000) {
+		int i;
+
+		mga_outl(0x3C10, tmp & ~0x02000000);
+		for (i = 0; i < 2; i++) {
+			unsigned int nl;
+			unsigned int lastl = 0;
+
+			while ((nl = mga_inl(0x3C48) & 0xFFF) >= lastl) {
+				lastl = nl;
+			}
+		}
+	}
+	mga_outl(0x3C10, tmp);
+	ACCESS_FBINFO(hw).crtc2.ctl = tmp;
+
+	tmp = mt->VDisplay << 16;	/* line compare */
+	if (mt->sync & FB_SYNC_HOR_HIGH_ACT)
+		tmp |= 0x00000100;
+	if (mt->sync & FB_SYNC_VERT_HIGH_ACT)
+		tmp |= 0x00000200;
+	mga_outl(0x3C44, tmp);
+}
+
+static void matroxfb_dh_disable(struct matroxfb_dh_fb_info* m2info) {
+	MINFO_FROM(m2info->primary_dev);
+
+	mga_outl(0x3C10, 0x00000004);	/* disable CRTC2, CRTC1->DAC1, PLL as clock source */
+	ACCESS_FBINFO(hw).crtc2.ctl = 0x00000004;
+}
+
+static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info) {
+	/* no acceleration for secondary head... */
+	m2info->cmap[16] = 0xFFFFFFFF;
+}
+
+static void matroxfb_dh_pan_var(struct matroxfb_dh_fb_info* m2info,
+		struct fb_var_screeninfo* var) {
+	unsigned int pos;
+	unsigned int linelen;
+	unsigned int pixelsize;
+	MINFO_FROM(m2info->primary_dev);
+
+	m2info->fbcon.var.xoffset = var->xoffset;
+	m2info->fbcon.var.yoffset = var->yoffset;
+	pixelsize = m2info->fbcon.var.bits_per_pixel >> 3;
+	linelen = m2info->fbcon.var.xres_virtual * pixelsize;
+	pos = m2info->fbcon.var.yoffset * linelen + m2info->fbcon.var.xoffset * pixelsize;
+	pos += m2info->video.offbase;
+	if (m2info->interlaced) {
+		mga_outl(0x3C2C, pos);
+		mga_outl(0x3C28, pos + linelen);
+	} else {
+		mga_outl(0x3C28, pos);
+	}
+}
+
+static int matroxfb_dh_decode_var(struct matroxfb_dh_fb_info* m2info,
+		struct fb_var_screeninfo* var,
+		int *visual,
+		int *video_cmap_len,
+		int *mode) {
+	unsigned int mask;
+	unsigned int memlen;
+	unsigned int vramlen;
+
+	switch (var->bits_per_pixel) {
+		case 16:	mask = 0x1F;
+				break;
+		case 32:	mask = 0x0F;
+				break;
+		default:	return -EINVAL;
+	}
+	vramlen = m2info->video.len_usable;
+	if (var->yres_virtual < var->yres)
+		var->yres_virtual = var->yres;
+	if (var->xres_virtual < var->xres)
+		var->xres_virtual = var->xres;
+	var->xres_virtual = (var->xres_virtual + mask) & ~mask;
+	if (var->yres_virtual > 32767)
+		return -EINVAL;
+	memlen = var->xres_virtual * var->yres_virtual * (var->bits_per_pixel >> 3);
+	if (memlen > vramlen)
+		return -EINVAL;
+	if (var->xoffset + var->xres > var->xres_virtual)
+		var->xoffset = var->xres_virtual - var->xres;
+	if (var->yoffset + var->yres > var->yres_virtual)
+		var->yoffset = var->yres_virtual - var->yres;
+
+	var->xres &= ~7;
+	var->left_margin &= ~7;
+	var->right_margin &= ~7;
+	var->hsync_len &= ~7;
+
+	*mode = var->bits_per_pixel;
+	if (var->bits_per_pixel == 16) {
+		if (var->green.length == 5) {
+			var->red.offset = 10;
+			var->red.length = 5;
+			var->green.offset = 5;
+			var->green.length = 5;
+			var->blue.offset = 0;
+			var->blue.length = 5;
+			var->transp.offset = 15;
+			var->transp.length = 1;
+			*mode = 15;
+		} else {
+			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;
+		}
+	} else {
+			var->red.offset = 16;
+			var->red.length = 8;
+			var->green.offset = 8;
+			var->green.length = 8;
+			var->blue.offset = 0;
+			var->blue.length = 8;
+			var->transp.offset = 24;
+			var->transp.length = 8;
+	}
+	*visual = FB_VISUAL_TRUECOLOR;
+	*video_cmap_len = 16;
+	return 0;
+}
+
+static int matroxfb_dh_open(struct fb_info* info, int user) {
+#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
+	MINFO_FROM(m2info->primary_dev);
+
+	if (MINFO) {
+		int err;
+
+		if (ACCESS_FBINFO(dead)) {
+			return -ENXIO;
+		}
+		err = ACCESS_FBINFO(fbops).fb_open(&ACCESS_FBINFO(fbcon), user);
+		if (err) {
+			return err;
+		}
+	}
+	return 0;
+#undef m2info
+}
+
+static int matroxfb_dh_release(struct fb_info* info, int user) {
+#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
+	int err = 0;
+	MINFO_FROM(m2info->primary_dev);
+
+	if (MINFO) {
+		err = ACCESS_FBINFO(fbops).fb_release(&ACCESS_FBINFO(fbcon), user);
+	}
+	return err;
+#undef m2info
+}
+
+static void matroxfb_dh_init_fix(struct matroxfb_dh_fb_info *m2info) {
+	struct fb_fix_screeninfo *fix = &m2info->fbcon.fix;
+
+	strcpy(fix->id, "MATROX DH");
+
+	fix->smem_start = m2info->video.base;
+	fix->smem_len = m2info->video.len_usable;
+	fix->ypanstep = 1;
+	fix->ywrapstep = 0;
+	fix->xpanstep = 8;	/* TBD */
+	fix->mmio_start = m2info->mmio.base;
+	fix->mmio_len = m2info->mmio.len;
+	fix->accel = 0;		/* no accel... */
+}
+
+static int matroxfb_dh_check_var(struct fb_var_screeninfo* var, struct fb_info* info) {
+#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
+	int visual;
+	int cmap_len;
+	int mode;
+
+	return matroxfb_dh_decode_var(m2info, var, &visual, &cmap_len, &mode);
+#undef m2info
+}
+
+static int matroxfb_dh_set_par(struct fb_info* info) {
+#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
+	int visual;
+	int cmap_len;
+	int mode;
+	int err;
+	struct fb_var_screeninfo* var = &info->var;
+	MINFO_FROM(m2info->primary_dev);
+
+	if ((err = matroxfb_dh_decode_var(m2info, var, &visual, &cmap_len, &mode)) != 0)
+		return err;
+	/* cmap */
+	{
+		m2info->fbcon.screen_base = vaddr_va(m2info->video.vbase);
+		m2info->fbcon.fix.visual = visual;
+		m2info->fbcon.fix.type = FB_TYPE_PACKED_PIXELS;
+		m2info->fbcon.fix.type_aux = 0;
+		m2info->fbcon.fix.line_length = (var->xres_virtual * var->bits_per_pixel) >> 3;
+	}
+	{
+		struct my_timming mt;
+		unsigned int pos;
+		int out;
+		int cnt;
+
+		matroxfb_var2my(&m2info->fbcon.var, &mt);
+		mt.crtc = MATROXFB_SRC_CRTC2;
+		/* CRTC2 delay */
+		mt.delay = 34;
+
+		pos = (m2info->fbcon.var.yoffset * m2info->fbcon.var.xres_virtual + m2info->fbcon.var.xoffset) * m2info->fbcon.var.bits_per_pixel >> 3;
+		pos += m2info->video.offbase;
+		cnt = 0;
+		down_read(&ACCESS_FBINFO(altout).lock);
+		for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+			if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) {
+				cnt++;
+				if (ACCESS_FBINFO(outputs[out]).output->compute) {
+					ACCESS_FBINFO(outputs[out]).output->compute(ACCESS_FBINFO(outputs[out]).data, &mt);
+				}
+			}
+		}
+		ACCESS_FBINFO(crtc2).pixclock = mt.pixclock;
+		ACCESS_FBINFO(crtc2).mnp = mt.mnp;
+		up_read(&ACCESS_FBINFO(altout).lock);
+		if (cnt) {
+			matroxfb_dh_restore(m2info, &mt, mode, pos);
+		} else {
+			matroxfb_dh_disable(m2info);
+		}
+		DAC1064_global_init(PMINFO2);
+		DAC1064_global_restore(PMINFO2);
+		down_read(&ACCESS_FBINFO(altout).lock);
+		for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+			if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2 &&
+			    ACCESS_FBINFO(outputs[out]).output->program) {
+				ACCESS_FBINFO(outputs[out]).output->program(ACCESS_FBINFO(outputs[out]).data);
+			}
+		}
+		for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+			if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2 &&
+			    ACCESS_FBINFO(outputs[out]).output->start) {
+				ACCESS_FBINFO(outputs[out]).output->start(ACCESS_FBINFO(outputs[out]).data);
+			}
+		}
+		up_read(&ACCESS_FBINFO(altout).lock);
+		matroxfb_dh_cfbX_init(m2info);
+	}
+	m2info->initialized = 1;
+	return 0;
+#undef m2info
+}
+
+static int matroxfb_dh_pan_display(struct fb_var_screeninfo* var, struct fb_info* info) {
+#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
+	matroxfb_dh_pan_var(m2info, var);
+	return 0;
+#undef m2info
+}
+
+static int matroxfb_dh_get_vblank(const struct matroxfb_dh_fb_info* m2info, struct fb_vblank* vblank) {
+	MINFO_FROM(m2info->primary_dev);
+
+	matroxfb_enable_irq(PMINFO 0);
+	memset(vblank, 0, sizeof(*vblank));
+	vblank->flags = FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VBLANK;
+	/* mask out reserved bits + field number (odd/even) */
+	vblank->vcount = mga_inl(0x3C48) & 0x000007FF;
+	/* compatibility stuff */
+	if (vblank->vcount >= m2info->fbcon.var.yres)
+		vblank->flags |= FB_VBLANK_VBLANKING;
+        if (test_bit(0, &ACCESS_FBINFO(irq_flags))) {
+                vblank->flags |= FB_VBLANK_HAVE_COUNT;
+                /* Only one writer, aligned int value...
+                   it should work without lock and without atomic_t */
+                vblank->count = ACCESS_FBINFO(crtc2).vsync.cnt;
+        }
+	return 0;
+}
+
+static int matroxfb_dh_ioctl(struct inode* inode,
+		struct file* file,
+		unsigned int cmd,
+		unsigned long arg,
+		struct fb_info* info) {
+#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
+	MINFO_FROM(m2info->primary_dev);
+
+	DBG(__FUNCTION__)
+
+	switch (cmd) {
+		case FBIOGET_VBLANK:
+			{
+				struct fb_vblank vblank;
+				int err;
+
+				err = matroxfb_dh_get_vblank(m2info, &vblank);
+				if (err)
+					return err;
+				if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank)))
+					return -EFAULT;
+				return 0;
+			}
+		case FBIO_WAITFORVSYNC:
+			{
+				u_int32_t crt;
+
+				if (get_user(crt, (u_int32_t __user *)arg))
+					return -EFAULT;
+
+				if (crt != 0)
+					return -ENODEV;
+				return matroxfb_wait_for_sync(PMINFO 1);
+			}
+		case MATROXFB_SET_OUTPUT_MODE:
+		case MATROXFB_GET_OUTPUT_MODE:
+		case MATROXFB_GET_ALL_OUTPUTS:
+			{
+				return ACCESS_FBINFO(fbcon.fbops)->fb_ioctl(inode, file, cmd, arg, &ACCESS_FBINFO(fbcon));
+			}
+		case MATROXFB_SET_OUTPUT_CONNECTION:
+			{
+				u_int32_t tmp;
+				int out;
+				int changes;
+
+				if (get_user(tmp, (u_int32_t __user *)arg))
+					return -EFAULT;
+				for (out = 0; out < 32; out++) {
+					if (tmp & (1 << out)) {
+						if (out >= MATROXFB_MAX_OUTPUTS)
+							return -ENXIO;
+						if (!ACCESS_FBINFO(outputs[out]).output)
+							return -ENXIO;
+						switch (ACCESS_FBINFO(outputs[out]).src) {
+							case MATROXFB_SRC_NONE:
+							case MATROXFB_SRC_CRTC2:
+								break;
+							default:
+								return -EBUSY;
+						}
+					}
+				}
+				if (ACCESS_FBINFO(devflags.panellink)) {
+					if (tmp & MATROXFB_OUTPUT_CONN_DFP)
+						return -EINVAL;
+					if ((ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1) && tmp)
+						return -EBUSY;
+				}
+				changes = 0;
+				for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+					if (tmp & (1 << out)) {
+						if (ACCESS_FBINFO(outputs[out]).src != MATROXFB_SRC_CRTC2) {
+							changes = 1;
+							ACCESS_FBINFO(outputs[out]).src = MATROXFB_SRC_CRTC2;
+						}
+					} else if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) {
+						changes = 1;
+						ACCESS_FBINFO(outputs[out]).src = MATROXFB_SRC_NONE;
+					}
+				}
+				if (!changes)
+					return 0;
+				matroxfb_dh_set_par(info);
+				return 0;
+			}
+		case MATROXFB_GET_OUTPUT_CONNECTION:
+			{
+				u_int32_t conn = 0;
+				int out;
+
+				for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+					if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) {
+						conn |= 1 << out;
+					}
+				}
+				if (put_user(conn, (u_int32_t __user *)arg))
+					return -EFAULT;
+				return 0;
+			}
+		case MATROXFB_GET_AVAILABLE_OUTPUTS:
+			{
+				u_int32_t tmp = 0;
+				int out;
+
+				for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+					if (ACCESS_FBINFO(outputs[out]).output) {
+						switch (ACCESS_FBINFO(outputs[out]).src) {
+							case MATROXFB_SRC_NONE:
+							case MATROXFB_SRC_CRTC2:
+								tmp |= 1 << out;
+								break;
+						}
+					}
+				}
+				if (ACCESS_FBINFO(devflags.panellink)) {
+					tmp &= ~MATROXFB_OUTPUT_CONN_DFP;
+					if (ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1) {
+						tmp = 0;
+					}
+				}
+				if (put_user(tmp, (u_int32_t __user *)arg))
+					return -EFAULT;
+				return 0;
+			}
+	}
+	return -ENOTTY;
+#undef m2info
+}
+
+static int matroxfb_dh_blank(int blank, struct fb_info* info) {
+#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
+	switch (blank) {
+		case 1:
+		case 2:
+		case 3:
+		case 4:
+		default:;
+	}
+	/* do something... */
+	return 0;
+#undef m2info
+}
+
+static struct fb_ops matroxfb_dh_ops = {
+	.owner =	THIS_MODULE,
+	.fb_open =	matroxfb_dh_open,
+	.fb_release =	matroxfb_dh_release,
+	.fb_check_var =	matroxfb_dh_check_var,
+	.fb_set_par =	matroxfb_dh_set_par,
+	.fb_setcolreg =	matroxfb_dh_setcolreg,
+	.fb_pan_display =matroxfb_dh_pan_display,
+	.fb_blank =	matroxfb_dh_blank,
+	.fb_ioctl =	matroxfb_dh_ioctl,
+	.fb_fillrect =	cfb_fillrect,
+	.fb_copyarea =	cfb_copyarea,
+	.fb_imageblit =	cfb_imageblit,
+	.fb_cursor =	soft_cursor,
+};
+
+static struct fb_var_screeninfo matroxfb_dh_defined = {
+		640,480,640,480,/* W,H, virtual W,H */
+		0,0,		/* offset */
+		32,		/* depth */
+		0,		/* gray */
+		{0,0,0},	/* R */
+		{0,0,0},	/* G */
+		{0,0,0},	/* B */
+		{0,0,0},	/* alpha */
+		0,		/* nonstd */
+		FB_ACTIVATE_NOW,
+		-1,-1,		/* display size */
+		0,		/* accel flags */
+		39721L,48L,16L,33L,10L,
+		96L,2,0,	/* no sync info */
+		FB_VMODE_NONINTERLACED,
+		0, {0,0,0,0,0}
+};
+
+static int matroxfb_dh_regit(CPMINFO struct matroxfb_dh_fb_info* m2info) {
+#define minfo (m2info->primary_dev)
+	void* oldcrtc2;
+
+	m2info->fbcon.fbops = &matroxfb_dh_ops;
+	m2info->fbcon.flags = FBINFO_FLAG_DEFAULT;
+	m2info->fbcon.flags |= FBINFO_HWACCEL_XPAN |
+			       FBINFO_HWACCEL_YPAN;
+	m2info->fbcon.pseudo_palette = m2info->cmap;
+	fb_alloc_cmap(&m2info->fbcon.cmap, 256, 1);
+
+	if (mem < 64)
+		mem *= 1024;
+	if (mem < 64*1024)
+		mem *= 1024;
+	mem &= ~0x00000FFF;	/* PAGE_MASK? */
+	if (ACCESS_FBINFO(video.len_usable) + mem <= ACCESS_FBINFO(video.len))
+		m2info->video.offbase = ACCESS_FBINFO(video.len) - mem;
+	else if (ACCESS_FBINFO(video.len) < mem) {
+		return -ENOMEM;
+	} else { /* check yres on first head... */
+		m2info->video.borrowed = mem;
+		ACCESS_FBINFO(video.len_usable) -= mem;
+		m2info->video.offbase = ACCESS_FBINFO(video.len_usable);
+	}
+	m2info->video.base = ACCESS_FBINFO(video.base) + m2info->video.offbase;
+	m2info->video.len = m2info->video.len_usable = m2info->video.len_maximum = mem;
+	m2info->video.vbase.vaddr = vaddr_va(ACCESS_FBINFO(video.vbase)) + m2info->video.offbase;
+	m2info->mmio.base = ACCESS_FBINFO(mmio.base);
+	m2info->mmio.vbase = ACCESS_FBINFO(mmio.vbase);
+	m2info->mmio.len = ACCESS_FBINFO(mmio.len);
+
+	matroxfb_dh_init_fix(m2info);
+	if (register_framebuffer(&m2info->fbcon)) {
+		return -ENXIO;
+	}
+	if (!m2info->initialized)
+		fb_set_var(&m2info->fbcon, &matroxfb_dh_defined);
+	down_write(&ACCESS_FBINFO(crtc2.lock));
+	oldcrtc2 = ACCESS_FBINFO(crtc2.info);
+	ACCESS_FBINFO(crtc2.info) = m2info;
+	up_write(&ACCESS_FBINFO(crtc2.lock));
+	if (oldcrtc2) {
+		printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 already present: %p\n",
+			oldcrtc2);
+	}
+	return 0;
+#undef minfo
+}
+
+/* ************************** */
+
+static int matroxfb_dh_registerfb(struct matroxfb_dh_fb_info* m2info) {
+#define minfo (m2info->primary_dev)
+	if (matroxfb_dh_regit(PMINFO m2info)) {
+		printk(KERN_ERR "matroxfb_crtc2: secondary head failed to register\n");
+		return -1;
+	}
+	printk(KERN_INFO "matroxfb_crtc2: secondary head of fb%u was registered as fb%u\n",
+		ACCESS_FBINFO(fbcon.node), m2info->fbcon.node);
+	m2info->fbcon_registered = 1;
+	return 0;
+#undef minfo
+}
+
+static void matroxfb_dh_deregisterfb(struct matroxfb_dh_fb_info* m2info) {
+#define minfo (m2info->primary_dev)
+	if (m2info->fbcon_registered) {
+		int id;
+		struct matroxfb_dh_fb_info* crtc2;
+
+		down_write(&ACCESS_FBINFO(crtc2.lock));
+		crtc2 = ACCESS_FBINFO(crtc2.info);
+		if (crtc2 == m2info)
+			ACCESS_FBINFO(crtc2.info) = NULL;
+		up_write(&ACCESS_FBINFO(crtc2.lock));
+		if (crtc2 != m2info) {
+			printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 mismatch at unload: %p != %p\n",
+				crtc2, m2info);
+			printk(KERN_ERR "matroxfb_crtc2: Expect kernel crash after module unload.\n");
+			return;
+		}
+		id = m2info->fbcon.node;
+		unregister_framebuffer(&m2info->fbcon);
+		/* return memory back to primary head */
+		ACCESS_FBINFO(video.len_usable) += m2info->video.borrowed;
+		printk(KERN_INFO "matroxfb_crtc2: fb%u unregistered\n", id);
+		m2info->fbcon_registered = 0;
+	}
+#undef minfo
+}
+
+static void* matroxfb_crtc2_probe(struct matrox_fb_info* minfo) {
+	struct matroxfb_dh_fb_info* m2info;
+
+	/* hardware is CRTC2 incapable... */
+	if (!ACCESS_FBINFO(devflags.crtc2))
+		return NULL;
+	m2info = (struct matroxfb_dh_fb_info*)kmalloc(sizeof(*m2info), GFP_KERNEL);
+	if (!m2info) {
+		printk(KERN_ERR "matroxfb_crtc2: Not enough memory for CRTC2 control structs\n");
+		return NULL;
+	}
+	memset(m2info, 0, sizeof(*m2info));
+	m2info->primary_dev = MINFO;
+	if (matroxfb_dh_registerfb(m2info)) {
+		kfree(m2info);
+		printk(KERN_ERR "matroxfb_crtc2: CRTC2 framebuffer failed to register\n");
+		return NULL;
+	}
+	return m2info;
+}
+
+static void matroxfb_crtc2_remove(struct matrox_fb_info* minfo, void* crtc2) {
+	matroxfb_dh_deregisterfb(crtc2);
+	kfree(crtc2);
+}
+
+static struct matroxfb_driver crtc2 = {
+		.name =		"Matrox G400 CRTC2",
+		.probe =	matroxfb_crtc2_probe,
+		.remove =	matroxfb_crtc2_remove };
+
+static int matroxfb_crtc2_init(void) {
+	if (fb_get_options("matrox_crtc2fb", NULL))
+		return -ENODEV;
+
+	matroxfb_register_driver(&crtc2);
+	return 0;
+}
+
+static void matroxfb_crtc2_exit(void) {
+	matroxfb_unregister_driver(&crtc2);
+}
+
+MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Matrox G400 CRTC2 driver");
+MODULE_LICENSE("GPL");
+module_init(matroxfb_crtc2_init);
+module_exit(matroxfb_crtc2_exit);
+/* we do not have __setup() yet */
diff --git a/drivers/video/matrox/matroxfb_crtc2.h b/drivers/video/matrox/matroxfb_crtc2.h
new file mode 100644
index 0000000..608e40b
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_crtc2.h
@@ -0,0 +1,36 @@
+#ifndef __MATROXFB_CRTC2_H__
+#define __MATROXFB_CRTC2_H__
+
+#include <linux/ioctl.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include "matroxfb_base.h"
+
+struct matroxfb_dh_fb_info {
+	struct fb_info		fbcon;
+	int			fbcon_registered;
+	int                     initialized;
+
+	struct matrox_fb_info*	primary_dev;
+
+	struct {
+		unsigned long	base;	/* physical */
+		vaddr_t		vbase;	/* virtual */
+		unsigned int	len;
+		unsigned int	len_usable;
+		unsigned int	len_maximum;
+		unsigned int 	offbase;
+		unsigned int	borrowed;
+			      } video;
+	struct {
+		unsigned long	base;
+		vaddr_t		vbase;
+		unsigned int	len;
+			      } mmio;
+
+	unsigned int		interlaced:1;
+
+	u_int32_t cmap[17];
+};
+
+#endif /* __MATROXFB_CRTC2_H__ */
diff --git a/drivers/video/matrox/matroxfb_g450.c b/drivers/video/matrox/matroxfb_g450.c
new file mode 100644
index 0000000..35008af
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_g450.c
@@ -0,0 +1,626 @@
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
+ *
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Portions Copyright (c) 2001 Matrox Graphics Inc.
+ *
+ * Version: 1.65 2002/08/14
+ *
+ * See matroxfb_base.c for contributors.
+ *
+ */
+
+#include "matroxfb_base.h"
+#include "matroxfb_misc.h"
+#include "matroxfb_DAC1064.h"
+#include "g450_pll.h"
+#include <linux/matroxfb.h>
+#include <asm/uaccess.h>
+#include <asm/div64.h>
+
+/* Definition of the various controls */
+struct mctl {
+	struct v4l2_queryctrl desc;
+	size_t control;
+};
+
+#define BLMIN	0xF3
+#define WLMAX	0x3FF
+
+static const struct mctl g450_controls[] =
+{	{ { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER, 
+	  "brightness",
+	  0, WLMAX-BLMIN, 1, 370-BLMIN, 
+	  0,
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.brightness) },
+	{ { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER, 
+	  "contrast",
+	  0, 1023, 1, 127, 
+	  0,
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.contrast) },
+	{ { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER,
+	  "saturation",
+	  0, 255, 1, 165, 
+	  0,
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.saturation) },
+	{ { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER,
+	  "hue",
+	  0, 255, 1, 0, 
+	  0,
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.hue) },
+	{ { MATROXFB_CID_TESTOUT, V4L2_CTRL_TYPE_BOOLEAN,
+	  "test output",
+	  0, 1, 1, 0, 
+	  0,
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.testout) },
+};
+
+#define G450CTRLS (sizeof(g450_controls)/sizeof(g450_controls[0]))
+
+/* Return: positive number: id found
+           -EINVAL:         id not found, return failure
+	   -ENOENT:         id not found, create fake disabled control */
+static int get_ctrl_id(__u32 v4l2_id) {
+	int i;
+
+	for (i = 0; i < G450CTRLS; i++) {
+		if (v4l2_id < g450_controls[i].desc.id) {
+			if (g450_controls[i].desc.id == 0x08000000) {
+				return -EINVAL;
+			}
+			return -ENOENT;
+		}
+		if (v4l2_id == g450_controls[i].desc.id) {
+			return i;
+		}
+	}
+	return -EINVAL;
+}
+
+static inline int* get_ctrl_ptr(WPMINFO unsigned int idx) {
+	return (int*)((char*)MINFO + g450_controls[idx].control);
+}
+
+static void tvo_fill_defaults(WPMINFO2) {
+	unsigned int i;
+	
+	for (i = 0; i < G450CTRLS; i++) {
+		*get_ctrl_ptr(PMINFO i) = g450_controls[i].desc.default_value;
+	}
+}
+
+static int cve2_get_reg(WPMINFO int reg) {
+	unsigned long flags;
+	int val;
+	
+	matroxfb_DAC_lock_irqsave(flags);
+	matroxfb_DAC_out(PMINFO 0x87, reg);
+	val = matroxfb_DAC_in(PMINFO 0x88);
+	matroxfb_DAC_unlock_irqrestore(flags);
+	return val;
+}
+
+static void cve2_set_reg(WPMINFO int reg, int val) {
+	unsigned long flags;
+
+	matroxfb_DAC_lock_irqsave(flags);
+	matroxfb_DAC_out(PMINFO 0x87, reg);
+	matroxfb_DAC_out(PMINFO 0x88, val);
+	matroxfb_DAC_unlock_irqrestore(flags);
+}
+
+static void cve2_set_reg10(WPMINFO int reg, int val) {
+	unsigned long flags;
+
+	matroxfb_DAC_lock_irqsave(flags);
+	matroxfb_DAC_out(PMINFO 0x87, reg);
+	matroxfb_DAC_out(PMINFO 0x88, val >> 2);
+	matroxfb_DAC_out(PMINFO 0x87, reg + 1);
+	matroxfb_DAC_out(PMINFO 0x88, val & 3);
+	matroxfb_DAC_unlock_irqrestore(flags);
+}
+
+static void g450_compute_bwlevel(CPMINFO int *bl, int *wl) {
+	const int b = ACCESS_FBINFO(altout.tvo_params.brightness) + BLMIN;
+	const int c = ACCESS_FBINFO(altout.tvo_params.contrast);
+
+	*bl = max(b - c, BLMIN);
+	*wl = min(b + c, WLMAX);
+}
+
+static int g450_query_ctrl(void* md, struct v4l2_queryctrl *p) {
+	int i;
+	
+	i = get_ctrl_id(p->id);
+	if (i >= 0) {
+		*p = g450_controls[i].desc;
+		return 0;
+	}
+	if (i == -ENOENT) {
+		static const struct v4l2_queryctrl disctrl = 
+			{ .flags = V4L2_CTRL_FLAG_DISABLED };
+			
+		i = p->id;
+		*p = disctrl;
+		p->id = i;
+		sprintf(p->name, "Ctrl #%08X", i);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int g450_set_ctrl(void* md, struct v4l2_control *p) {
+	int i;
+	MINFO_FROM(md);
+	
+	i = get_ctrl_id(p->id);
+	if (i < 0) return -EINVAL;
+
+	/*
+	 * Check if changed.
+	 */
+	if (p->value == *get_ctrl_ptr(PMINFO i)) return 0;
+
+	/*
+	 * Check limits.
+	 */
+	if (p->value > g450_controls[i].desc.maximum) return -EINVAL;
+	if (p->value < g450_controls[i].desc.minimum) return -EINVAL;
+
+	/*
+	 * Store new value.
+	 */
+	*get_ctrl_ptr(PMINFO i) = p->value;
+
+	switch (p->id) {
+		case V4L2_CID_BRIGHTNESS:
+		case V4L2_CID_CONTRAST:
+			{
+				int blacklevel, whitelevel;
+				g450_compute_bwlevel(PMINFO &blacklevel, &whitelevel);
+				cve2_set_reg10(PMINFO 0x0e, blacklevel);
+				cve2_set_reg10(PMINFO 0x1e, whitelevel);
+			}
+			break;
+		case V4L2_CID_SATURATION:
+			cve2_set_reg(PMINFO 0x20, p->value);
+			cve2_set_reg(PMINFO 0x22, p->value);
+			break;
+		case V4L2_CID_HUE:
+			cve2_set_reg(PMINFO 0x25, p->value);
+			break;
+		case MATROXFB_CID_TESTOUT:
+			{
+				unsigned char val = cve2_get_reg (PMINFO 0x05);
+				if (p->value) val |=  0x02;
+				else          val &= ~0x02;
+				cve2_set_reg(PMINFO 0x05, val);
+			}
+			break;
+	}
+	
+
+	return 0;
+}
+
+static int g450_get_ctrl(void* md, struct v4l2_control *p) {
+	int i;
+	MINFO_FROM(md);
+	
+	i = get_ctrl_id(p->id);
+	if (i < 0) return -EINVAL;
+	p->value = *get_ctrl_ptr(PMINFO i);
+	return 0;
+}
+
+struct output_desc {
+	unsigned int	h_vis;
+	unsigned int	h_f_porch;
+	unsigned int	h_sync;
+	unsigned int	h_b_porch;
+	unsigned long long int	chromasc;
+	unsigned int	burst;
+	unsigned int	v_total;
+};
+
+static void computeRegs(WPMINFO struct mavenregs* r, struct my_timming* mt, const struct output_desc* outd) {
+	u_int32_t chromasc;
+	u_int32_t hlen;
+	u_int32_t hsl;
+	u_int32_t hbp;
+	u_int32_t hfp;
+	u_int32_t hvis;
+	unsigned int pixclock;
+	unsigned long long piic;
+	int mnp;
+	int over;
+	
+	r->regs[0x80] = 0x03;	/* | 0x40 for SCART */
+
+	hvis = ((mt->HDisplay << 1) + 3) & ~3;
+	
+	if (hvis >= 2048) {
+		hvis = 2044;
+	}
+	
+	piic = 1000000000ULL * hvis;
+	do_div(piic, outd->h_vis);
+
+	dprintk(KERN_DEBUG "Want %u kHz pixclock\n", (unsigned int)piic);
+	
+	mnp = matroxfb_g450_setclk(PMINFO piic, M_VIDEO_PLL);
+	
+	mt->mnp = mnp;
+	mt->pixclock = g450_mnp2f(PMINFO mnp);
+
+	dprintk(KERN_DEBUG "MNP=%08X\n", mnp);
+
+	pixclock = 1000000000U / mt->pixclock;
+
+	dprintk(KERN_DEBUG "Got %u ps pixclock\n", pixclock);
+
+	piic = outd->chromasc;
+	do_div(piic, mt->pixclock);
+	chromasc = piic;
+	
+	dprintk(KERN_DEBUG "Chroma is %08X\n", chromasc);
+
+	r->regs[0] = piic >> 24;
+	r->regs[1] = piic >> 16;
+	r->regs[2] = piic >>  8;
+	r->regs[3] = piic >>  0;
+	hbp = (((outd->h_b_porch + pixclock) / pixclock)) & ~1;
+	hfp = (((outd->h_f_porch + pixclock) / pixclock)) & ~1;
+	hsl = (((outd->h_sync + pixclock) / pixclock)) & ~1;
+	hlen = hvis + hfp + hsl + hbp;
+	over = hlen & 0x0F;
+	
+	dprintk(KERN_DEBUG "WL: vis=%u, hf=%u, hs=%u, hb=%u, total=%u\n", hvis, hfp, hsl, hbp, hlen);
+
+	if (over) {
+		hfp -= over;
+		hlen -= over;
+		if (over <= 2) {
+		} else if (over < 10) {
+			hfp += 4;
+			hlen += 4;
+		} else {
+			hfp += 16;
+			hlen += 16;
+		}
+	}
+
+	/* maybe cve2 has requirement 800 < hlen < 1184 */
+	r->regs[0x08] = hsl;
+	r->regs[0x09] = (outd->burst + pixclock - 1) / pixclock;	/* burst length */
+	r->regs[0x0A] = hbp;
+	r->regs[0x2C] = hfp;
+	r->regs[0x31] = hvis / 8;
+	r->regs[0x32] = hvis & 7;
+	
+	dprintk(KERN_DEBUG "PG: vis=%04X, hf=%02X, hs=%02X, hb=%02X, total=%04X\n", hvis, hfp, hsl, hbp, hlen);
+
+	r->regs[0x84] = 1;	/* x sync point */
+	r->regs[0x85] = 0;
+	hvis = hvis >> 1;
+	hlen = hlen >> 1;
+	
+	dprintk(KERN_DEBUG "hlen=%u hvis=%u\n", hlen, hvis);
+
+	mt->interlaced = 1;
+
+	mt->HDisplay = hvis & ~7;
+	mt->HSyncStart = mt->HDisplay + 8;
+	mt->HSyncEnd = (hlen & ~7) - 8;
+	mt->HTotal = hlen;
+
+	{
+		int upper;
+		unsigned int vtotal;
+		unsigned int vsyncend;
+		unsigned int vdisplay;
+		
+		vtotal = mt->VTotal;
+		vsyncend = mt->VSyncEnd;
+		vdisplay = mt->VDisplay;
+		if (vtotal < outd->v_total) {
+			unsigned int yovr = outd->v_total - vtotal;
+			
+			vsyncend += yovr >> 1;
+		} else if (vtotal > outd->v_total) {
+			vdisplay = outd->v_total - 4;
+			vsyncend = outd->v_total;
+		}
+		upper = (outd->v_total - vsyncend) >> 1;	/* in field lines */
+		r->regs[0x17] = outd->v_total / 4;
+		r->regs[0x18] = outd->v_total & 3;
+		r->regs[0x33] = upper - 1;	/* upper blanking */
+		r->regs[0x82] = upper;		/* y sync point */
+		r->regs[0x83] = upper >> 8;
+		
+		mt->VDisplay = vdisplay;
+		mt->VSyncStart = outd->v_total - 2;
+		mt->VSyncEnd = outd->v_total;
+		mt->VTotal = outd->v_total;
+	}
+}
+
+static void cve2_init_TVdata(int norm, struct mavenregs* data, const struct output_desc** outd) {
+	static const struct output_desc paloutd = {
+		.h_vis	   = 52148148,	// ps
+		.h_f_porch =  1407407,	// ps
+		.h_sync    =  4666667,	// ps
+		.h_b_porch =  5777778,	// ps
+		.chromasc  = 19042247534182ULL,	// 4433618.750 Hz
+		.burst     =  2518518,	// ps
+		.v_total   =      625,
+	};
+	static const struct output_desc ntscoutd = {
+		.h_vis     = 52888889,	// ps
+		.h_f_porch =  1333333,	// ps
+		.h_sync    =  4666667,	// ps
+		.h_b_porch =  4666667,	// ps
+		.chromasc  = 15374030659475ULL,	// 3579545.454 Hz
+		.burst     =  2418418,	// ps
+		.v_total   =      525,	// lines
+	};
+
+	static const struct mavenregs palregs = { {
+		0x2A, 0x09, 0x8A, 0xCB,	/* 00: chroma subcarrier */
+		0x00,
+		0x00,	/* test */
+		0xF9,	/* modified by code (F9 written...) */
+		0x00,	/* ? not written */
+		0x7E,	/* 08 */
+		0x44,	/* 09 */
+		0x9C,	/* 0A */
+		0x2E,	/* 0B */
+		0x21,	/* 0C */
+		0x00,	/* ? not written */
+//		0x3F, 0x03, /* 0E-0F */
+		0x3C, 0x03,
+		0x3C, 0x03, /* 10-11 */
+		0x1A,	/* 12 */
+		0x2A,	/* 13 */
+		0x1C, 0x3D, 0x14, /* 14-16 */
+		0x9C, 0x01, /* 17-18 */
+		0x00,	/* 19 */
+		0xFE,	/* 1A */
+		0x7E,	/* 1B */
+		0x60,	/* 1C */
+		0x05,	/* 1D */
+//		0x89, 0x03, /* 1E-1F */
+		0xAD, 0x03,
+//		0x72,	/* 20 */
+		0xA5,
+		0x07,	/* 21 */
+//		0x72,	/* 22 */
+		0xA5,
+		0x00,	/* 23 */
+		0x00,	/* 24 */
+		0x00,	/* 25 */
+		0x08,	/* 26 */
+		0x04,	/* 27 */
+		0x00,	/* 28 */
+		0x1A,	/* 29 */
+		0x55, 0x01, /* 2A-2B */
+		0x26,	/* 2C */
+		0x07, 0x7E, /* 2D-2E */
+		0x02, 0x54, /* 2F-30 */
+		0xB0, 0x00, /* 31-32 */
+		0x14,	/* 33 */
+		0x49,	/* 34 */
+		0x00,	/* 35 written multiple times */
+		0x00,	/* 36 not written */
+		0xA3,	/* 37 */
+		0xC8,	/* 38 */
+		0x22,	/* 39 */
+		0x02,	/* 3A */
+		0x22,	/* 3B */
+		0x3F, 0x03, /* 3C-3D */
+		0x00,	/* 3E written multiple times */
+		0x00,	/* 3F not written */
+	} };
+	static struct mavenregs ntscregs = { {
+		0x21, 0xF0, 0x7C, 0x1F,	/* 00: chroma subcarrier */
+		0x00,
+		0x00,	/* test */
+		0xF9,	/* modified by code (F9 written...) */
+		0x00,	/* ? not written */
+		0x7E,	/* 08 */
+		0x43,	/* 09 */
+		0x7E,	/* 0A */
+		0x3D,	/* 0B */
+		0x00,	/* 0C */
+		0x00,	/* ? not written */
+		0x41, 0x00, /* 0E-0F */
+		0x3C, 0x00, /* 10-11 */
+		0x17,	/* 12 */
+		0x21,	/* 13 */
+		0x1B, 0x1B, 0x24, /* 14-16 */
+		0x83, 0x01, /* 17-18 */
+		0x00,	/* 19 */
+		0x0F,	/* 1A */
+		0x0F,	/* 1B */
+		0x60,	/* 1C */
+		0x05,	/* 1D */
+		//0x89, 0x02, /* 1E-1F */
+		0xC0, 0x02, /* 1E-1F */
+		//0x5F,	/* 20 */
+		0x9C,	/* 20 */
+		0x04,	/* 21 */
+		//0x5F,	/* 22 */
+		0x9C,	/* 22 */
+		0x01,	/* 23 */
+		0x02,	/* 24 */
+		0x00,	/* 25 */
+		0x0A,	/* 26 */
+		0x05,	/* 27 */
+		0x00,	/* 28 */
+		0x10,	/* 29 */
+		0xFF, 0x03, /* 2A-2B */
+		0x24,	/* 2C */
+		0x0F, 0x78, /* 2D-2E */
+		0x00, 0x00, /* 2F-30 */
+		0xB2, 0x04, /* 31-32 */
+		0x14,	/* 33 */
+		0x02,	/* 34 */
+		0x00,	/* 35 written multiple times */
+		0x00,	/* 36 not written */
+		0xA3,	/* 37 */
+		0xC8,	/* 38 */
+		0x15,	/* 39 */
+		0x05,	/* 3A */
+		0x3B,	/* 3B */
+		0x3C, 0x00, /* 3C-3D */
+		0x00,	/* 3E written multiple times */
+		0x00,	/* never written */
+	} };
+
+	if (norm == MATROXFB_OUTPUT_MODE_PAL) {
+		*data = palregs;
+		*outd = &paloutd;
+	} else {
+  		*data = ntscregs;
+		*outd = &ntscoutd;
+	}
+ 	return;
+}
+
+#define LR(x) cve2_set_reg(PMINFO (x), m->regs[(x)])
+static void cve2_init_TV(WPMINFO const struct mavenregs* m) {
+	int i;
+
+	LR(0x80);
+	LR(0x82); LR(0x83);
+	LR(0x84); LR(0x85);
+	
+	cve2_set_reg(PMINFO 0x3E, 0x01);
+	
+	for (i = 0; i < 0x3E; i++) {
+		LR(i);
+	}
+	cve2_set_reg(PMINFO 0x3E, 0x00);
+}
+
+static int matroxfb_g450_compute(void* md, struct my_timming* mt) {
+	MINFO_FROM(md);
+
+	dprintk(KERN_DEBUG "Computing, mode=%u\n", ACCESS_FBINFO(outputs[1]).mode);
+
+	if (mt->crtc == MATROXFB_SRC_CRTC2 &&
+	    ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) {
+		const struct output_desc* outd;
+
+		cve2_init_TVdata(ACCESS_FBINFO(outputs[1]).mode, &ACCESS_FBINFO(hw).maven, &outd);
+		{
+			int blacklevel, whitelevel;
+			g450_compute_bwlevel(PMINFO &blacklevel, &whitelevel);
+			ACCESS_FBINFO(hw).maven.regs[0x0E] = blacklevel >> 2;
+			ACCESS_FBINFO(hw).maven.regs[0x0F] = blacklevel & 3;
+			ACCESS_FBINFO(hw).maven.regs[0x1E] = whitelevel >> 2;
+			ACCESS_FBINFO(hw).maven.regs[0x1F] = whitelevel & 3;
+
+			ACCESS_FBINFO(hw).maven.regs[0x20] =
+			ACCESS_FBINFO(hw).maven.regs[0x22] = ACCESS_FBINFO(altout.tvo_params.saturation);
+
+			ACCESS_FBINFO(hw).maven.regs[0x25] = ACCESS_FBINFO(altout.tvo_params.hue);
+
+			if (ACCESS_FBINFO(altout.tvo_params.testout)) {
+				ACCESS_FBINFO(hw).maven.regs[0x05] |= 0x02;
+			}
+		}
+		computeRegs(PMINFO &ACCESS_FBINFO(hw).maven, mt, outd);
+	} else if (mt->mnp < 0) {
+		/* We must program clocks before CRTC2, otherwise interlaced mode
+		   startup may fail */
+		mt->mnp = matroxfb_g450_setclk(PMINFO mt->pixclock, (mt->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
+		mt->pixclock = g450_mnp2f(PMINFO mt->mnp);
+	}
+	dprintk(KERN_DEBUG "Pixclock = %u\n", mt->pixclock);
+	return 0;
+}
+
+static int matroxfb_g450_program(void* md) {
+	MINFO_FROM(md);
+	
+	if (ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) {
+		cve2_init_TV(PMINFO &ACCESS_FBINFO(hw).maven);
+	}
+	return 0;
+}
+
+static int matroxfb_g450_verify_mode(void* md, u_int32_t arg) {
+	switch (arg) {
+		case MATROXFB_OUTPUT_MODE_PAL:
+		case MATROXFB_OUTPUT_MODE_NTSC:
+		case MATROXFB_OUTPUT_MODE_MONITOR:
+			return 0;
+	}
+	return -EINVAL;
+}
+
+static int g450_dvi_compute(void* md, struct my_timming* mt) {
+	MINFO_FROM(md);
+
+	if (mt->mnp < 0) {
+		mt->mnp = matroxfb_g450_setclk(PMINFO mt->pixclock, (mt->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
+		mt->pixclock = g450_mnp2f(PMINFO mt->mnp);
+	}
+	return 0;
+}
+
+static struct matrox_altout matroxfb_g450_altout = {
+	.name		= "Secondary output",
+	.compute	= matroxfb_g450_compute,
+	.program	= matroxfb_g450_program,
+	.verifymode	= matroxfb_g450_verify_mode,
+	.getqueryctrl	= g450_query_ctrl,
+	.getctrl	= g450_get_ctrl,
+	.setctrl	= g450_set_ctrl,
+};
+
+static struct matrox_altout matroxfb_g450_dvi = {
+	.name		= "DVI output",
+	.compute	= g450_dvi_compute,
+};
+
+void matroxfb_g450_connect(WPMINFO2) {
+	if (ACCESS_FBINFO(devflags.g450dac)) {
+		down_write(&ACCESS_FBINFO(altout.lock));
+		tvo_fill_defaults(PMINFO2);
+		ACCESS_FBINFO(outputs[1]).src = ACCESS_FBINFO(outputs[1]).default_src;
+		ACCESS_FBINFO(outputs[1]).data = MINFO;
+		ACCESS_FBINFO(outputs[1]).output = &matroxfb_g450_altout;
+		ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		ACCESS_FBINFO(outputs[2]).src = ACCESS_FBINFO(outputs[2]).default_src;
+		ACCESS_FBINFO(outputs[2]).data = MINFO;
+		ACCESS_FBINFO(outputs[2]).output = &matroxfb_g450_dvi;
+		ACCESS_FBINFO(outputs[2]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		up_write(&ACCESS_FBINFO(altout.lock));
+	}
+}
+
+void matroxfb_g450_shutdown(WPMINFO2) {
+	if (ACCESS_FBINFO(devflags.g450dac)) {
+		down_write(&ACCESS_FBINFO(altout.lock));
+		ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE;
+		ACCESS_FBINFO(outputs[1]).output = NULL;
+		ACCESS_FBINFO(outputs[1]).data = NULL;
+		ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		ACCESS_FBINFO(outputs[2]).src = MATROXFB_SRC_NONE;
+		ACCESS_FBINFO(outputs[2]).output = NULL;
+		ACCESS_FBINFO(outputs[2]).data = NULL;
+		ACCESS_FBINFO(outputs[2]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		up_write(&ACCESS_FBINFO(altout.lock));
+	}
+}
+
+EXPORT_SYMBOL(matroxfb_g450_connect);
+EXPORT_SYMBOL(matroxfb_g450_shutdown);
+
+MODULE_AUTHOR("(c) 2000-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Matrox G450/G550 output driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/matrox/matroxfb_g450.h b/drivers/video/matrox/matroxfb_g450.h
new file mode 100644
index 0000000..a0822a6
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_g450.h
@@ -0,0 +1,14 @@
+#ifndef __MATROXFB_G450_H__
+#define __MATROXFB_G450_H__
+
+#include "matroxfb_base.h"
+
+#ifdef CONFIG_FB_MATROX_G
+void matroxfb_g450_connect(WPMINFO2);
+void matroxfb_g450_shutdown(WPMINFO2);
+#else
+static inline void matroxfb_g450_connect(WPMINFO2) { };
+static inline void matroxfb_g450_shutdown(WPMINFO2) { };
+#endif
+
+#endif /* __MATROXFB_G450_H__ */
diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c
new file mode 100644
index 0000000..e529841
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_maven.c
@@ -0,0 +1,1328 @@
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
+ *
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Portions Copyright (c) 2001 Matrox Graphics Inc.
+ *
+ * Version: 1.65 2002/08/14
+ *
+ * See matroxfb_base.c for contributors.
+ *
+ */
+
+#include "matroxfb_maven.h"
+#include "matroxfb_misc.h"
+#include "matroxfb_DAC1064.h"
+#include <linux/i2c.h>
+#include <linux/matroxfb.h>
+#include <asm/div64.h>
+#include <asm/uaccess.h>
+
+#define MAVEN_I2CID	(0x1B)
+
+#define MGATVO_B	1
+#define MGATVO_C	2
+
+static const struct maven_gamma {
+  unsigned char reg83;
+  unsigned char reg84;
+  unsigned char reg85;
+  unsigned char reg86;
+  unsigned char reg87;
+  unsigned char reg88;
+  unsigned char reg89;
+  unsigned char reg8a;
+  unsigned char reg8b;
+} maven_gamma[] = {
+  { 131, 57, 223, 15, 117, 212, 251, 91, 156},
+  { 133, 61, 128, 63, 180, 147, 195, 100, 180},
+  { 131, 19, 63, 31, 50, 66, 171, 64, 176},
+  { 0, 0, 0, 31, 16, 16, 16, 100, 200},
+  { 8, 23, 47, 73, 147, 244, 220, 80, 195},
+  { 22, 43, 64, 80, 147, 115, 58, 85, 168},
+  { 34, 60, 80, 214, 147, 212, 188, 85, 167},
+  { 45, 77, 96, 216, 147, 99, 91, 85, 159},
+  { 56, 76, 112, 107, 147, 212, 148, 64, 144},
+  { 65, 91, 128, 137, 147, 196, 17, 69, 148},
+  { 72, 104, 136, 138, 147, 180, 245, 73, 147},
+  { 87, 116, 143, 126, 16, 83, 229, 77, 144},
+  { 95, 119, 152, 254, 244, 83, 221, 77, 151},
+  { 100, 129, 159, 156, 244, 148, 197, 77, 160},
+  { 105, 141, 167, 247, 244, 132, 181, 84, 166},
+  { 105, 147, 168, 247, 244, 245, 181, 90, 170},
+  { 120, 153, 175, 248, 212, 229, 165, 90, 180},
+  { 119, 156, 176, 248, 244, 229, 84, 74, 160},
+  { 119, 158, 183, 248, 244, 229, 149, 78, 165}
+};
+
+/* Definition of the various controls */
+struct mctl {
+	struct v4l2_queryctrl desc;
+	size_t control;
+};
+
+#define BLMIN	0x0FF
+#define WLMAX	0x3FF
+
+static const struct mctl maven_controls[] =
+{	{ { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER,
+	  "brightness",
+	  0, WLMAX - BLMIN, 1, 379 - BLMIN, 
+	  0,
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.brightness) },
+	{ { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER,
+	  "contrast",
+	  0, 1023, 1, 127,
+	  0,
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.contrast) },
+	{ { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER,
+	  "saturation",
+	  0, 255, 1, 155,
+	  0,
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.saturation) },
+	{ { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER,
+	  "hue",
+	  0, 255, 1, 0,
+	  0,
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.hue) },
+	{ { V4L2_CID_GAMMA, V4L2_CTRL_TYPE_INTEGER,
+	  "gamma",
+	  0, sizeof(maven_gamma)/sizeof(maven_gamma[0])-1, 1, 3,
+	  0,
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.gamma) },
+	{ { MATROXFB_CID_TESTOUT, V4L2_CTRL_TYPE_BOOLEAN,
+	  "test output",
+	  0, 1, 1, 0, 
+	  0,
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.testout) },
+	{ { MATROXFB_CID_DEFLICKER, V4L2_CTRL_TYPE_INTEGER,
+	  "deflicker mode",
+	  0, 2, 1, 0,
+	  0,
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.deflicker) },
+
+};
+
+#define MAVCTRLS (sizeof(maven_controls)/sizeof(maven_controls[0]))
+
+/* Return: positive number: id found
+           -EINVAL:         id not found, return failure
+	   -ENOENT:         id not found, create fake disabled control */
+static int get_ctrl_id(__u32 v4l2_id) {
+	int i;
+
+	for (i = 0; i < MAVCTRLS; i++) {
+		if (v4l2_id < maven_controls[i].desc.id) {
+			if (maven_controls[i].desc.id == 0x08000000) {
+				return -EINVAL;
+			}
+			return -ENOENT;
+		}
+		if (v4l2_id == maven_controls[i].desc.id) {
+			return i;
+		}
+	}
+	return -EINVAL;
+}
+
+struct maven_data {
+	struct matrox_fb_info*		primary_head;
+	struct i2c_client*		client;
+	int				version;
+};
+
+static int* get_ctrl_ptr(struct maven_data* md, int idx) {
+	return (int*)((char*)(md->primary_head) + maven_controls[idx].control);
+}
+
+static int maven_get_reg(struct i2c_client* c, char reg) {
+	char dst;
+	struct i2c_msg msgs[] = {{ c->addr, I2C_M_REV_DIR_ADDR, sizeof(reg), &reg },
+				 { c->addr, I2C_M_RD | I2C_M_NOSTART, sizeof(dst), &dst }};
+	s32 err;
+
+	err = i2c_transfer(c->adapter, msgs, 2);
+	if (err < 0)
+		printk(KERN_INFO "ReadReg(%d) failed\n", reg);
+	return dst & 0xFF;
+}
+
+static int maven_set_reg(struct i2c_client* c, int reg, int val) {
+	s32 err;
+
+	err = i2c_smbus_write_byte_data(c, reg, val);
+	if (err)
+		printk(KERN_INFO "WriteReg(%d) failed\n", reg);
+	return err;
+}
+
+static int maven_set_reg_pair(struct i2c_client* c, int reg, int val) {
+	s32 err;
+
+	err = i2c_smbus_write_word_data(c, reg, val);
+	if (err)
+		printk(KERN_INFO "WriteRegPair(%d) failed\n", reg);
+	return err;
+}
+
+static const struct matrox_pll_features maven_pll = {
+	50000,
+	27000,
+	4, 127,
+	2, 31,
+	3
+};
+
+struct matrox_pll_features2 {
+	unsigned int	vco_freq_min;
+	unsigned int	vco_freq_max;
+	unsigned int	feed_div_min;
+	unsigned int	feed_div_max;
+	unsigned int	in_div_min;
+	unsigned int	in_div_max;
+	unsigned int	post_shift_max;
+};
+
+struct matrox_pll_ctl {
+	unsigned int	ref_freq;
+	unsigned int	den;
+};
+
+static const struct matrox_pll_features2 maven1000_pll = {
+	 50000000,
+	300000000,
+	 5, 128,
+	 3,  32,
+	 3
+};
+
+static const struct matrox_pll_ctl maven_PAL = {
+	540000,
+	    50
+};
+
+static const struct matrox_pll_ctl maven_NTSC = {
+	450450,	/* 27027000/60 == 27000000/59.94005994 */
+	    60
+};
+
+static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll,
+		const struct matrox_pll_ctl* ctl,
+		unsigned int htotal, unsigned int vtotal,
+		unsigned int* in, unsigned int* feed, unsigned int* post,
+		unsigned int* h2) {
+	unsigned int besth2 = 0;
+	unsigned int fxtal = ctl->ref_freq;
+	unsigned int fmin = pll->vco_freq_min / ctl->den;
+	unsigned int fwant;
+	unsigned int p;
+	unsigned int scrlen;
+	unsigned int fmax;
+
+	DBG(__FUNCTION__)
+
+	scrlen = htotal * (vtotal - 1);
+	fwant = htotal * vtotal;
+	fmax = pll->vco_freq_max / ctl->den;
+
+	dprintk(KERN_DEBUG "want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n",
+		fwant, fxtal, htotal, vtotal, fmax);
+	for (p = 1; p <= pll->post_shift_max; p++) {
+		if (fwant * 2 > fmax)
+			break;
+		fwant *= 2;
+	}
+	if (fwant > fmax)
+		return 0;
+	for (; p-- > 0; fwant >>= 1) {
+		unsigned int m;
+
+		if (fwant < fmin) break;
+		for (m = pll->in_div_min; m <= pll->in_div_max; m++) {
+			unsigned int n;
+			unsigned int dvd;
+			unsigned int ln;
+
+			n = (fwant * m) / fxtal;
+			if (n < pll->feed_div_min)
+				continue;
+			if (n > pll->feed_div_max)
+				break;
+
+			ln = fxtal * n;
+			dvd = m << p;
+
+			if (ln % dvd)
+				continue;
+			ln = ln / dvd;
+
+			if (ln < scrlen + 2)
+				continue;
+			ln = ln - scrlen;
+			if (ln > htotal)
+				continue;
+			dprintk(KERN_DEBUG "Match: %u / %u / %u / %u\n", n, m, p, ln);
+			if (ln > besth2) {
+				dprintk(KERN_DEBUG "Better...\n");
+				*h2 = besth2 = ln;
+				*post = p;
+				*in = m;
+				*feed = n;
+			}
+		}
+	}
+	if (besth2 < 2)
+		return 0;
+	dprintk(KERN_ERR "clk: %02X %02X %02X %d %d\n", *in, *feed, *post, fxtal, fwant);
+	return fxtal * (*feed) / (*in) * ctl->den;
+}
+
+static unsigned int matroxfb_mavenclock(const struct matrox_pll_ctl* ctl,
+		unsigned int htotal, unsigned int vtotal,
+		unsigned int* in, unsigned int* feed, unsigned int* post,
+		unsigned int* htotal2) {
+	unsigned int fvco;
+	unsigned int p;
+
+	fvco = matroxfb_PLL_mavenclock(&maven1000_pll, ctl, htotal, vtotal, in, feed, &p, htotal2);
+	if (!fvco)
+		return -EINVAL;
+	p = (1 << p) - 1;
+	if (fvco <= 100000000)
+		;
+	else if (fvco <= 140000000)
+		p |= 0x08;
+	else if (fvco <= 180000000)
+		p |= 0x10;
+	else
+		p |= 0x18;
+	*post = p;
+	return 0;
+}
+
+static void DAC1064_calcclock(unsigned int freq, unsigned int fmax,
+		unsigned int* in, unsigned int* feed, unsigned int* post) {
+	unsigned int fvco;
+	unsigned int p;
+
+	fvco = matroxfb_PLL_calcclock(&maven_pll, freq, fmax, in, feed, &p);
+	p = (1 << p) - 1;
+	if (fvco <= 100000)
+		;
+	else if (fvco <= 140000)
+		p |= 0x08;
+	else if (fvco <= 180000)
+		p |= 0x10;
+	else
+		p |= 0x18;
+	*post = p;
+	return;
+}
+
+static unsigned char maven_compute_deflicker (const struct maven_data* md) {
+	unsigned char df;
+	
+	df = (md->version == MGATVO_B?0x40:0x00);
+	switch (md->primary_head->altout.tvo_params.deflicker) {
+		case 0:
+/*			df |= 0x00; */
+			break;
+		case 1:
+			df |= 0xB1;
+			break;
+		case 2:
+			df |= 0xA2;
+			break;
+	}
+	return df;
+}
+
+static void maven_compute_bwlevel (const struct maven_data* md,
+				   int *bl, int *wl) {
+	const int b = md->primary_head->altout.tvo_params.brightness + BLMIN;
+	const int c = md->primary_head->altout.tvo_params.contrast;
+
+	*bl = max(b - c, BLMIN);
+	*wl = min(b + c, WLMAX);
+}
+
+static const struct maven_gamma* maven_compute_gamma (const struct maven_data* md) {
+ 	return maven_gamma + md->primary_head->altout.tvo_params.gamma;
+}
+
+
+static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* data) {
+	static struct mavenregs palregs = { {
+		0x2A, 0x09, 0x8A, 0xCB,	/* 00: chroma subcarrier */
+		0x00,
+		0x00,	/* ? not written */
+		0x00,	/* modified by code (F9 written...) */
+		0x00,	/* ? not written */
+		0x7E,	/* 08 */
+		0x44,	/* 09 */
+		0x9C,	/* 0A */
+		0x2E,	/* 0B */
+		0x21,	/* 0C */
+		0x00,	/* ? not written */
+		0x3F, 0x03, /* 0E-0F */
+		0x3F, 0x03, /* 10-11 */
+		0x1A,	/* 12 */
+		0x2A,	/* 13 */
+		0x1C, 0x3D, 0x14, /* 14-16 */
+		0x9C, 0x01, /* 17-18 */
+		0x00,	/* 19 */
+		0xFE,	/* 1A */
+		0x7E,	/* 1B */
+		0x60,	/* 1C */
+		0x05,	/* 1D */
+		0x89, 0x03, /* 1E-1F */
+		0x72,	/* 20 */
+		0x07,	/* 21 */
+		0x72,	/* 22 */
+		0x00,	/* 23 */
+		0x00,	/* 24 */
+		0x00,	/* 25 */
+		0x08,	/* 26 */
+		0x04,	/* 27 */
+		0x00,	/* 28 */
+		0x1A,	/* 29 */
+		0x55, 0x01, /* 2A-2B */
+		0x26,	/* 2C */
+		0x07, 0x7E, /* 2D-2E */
+		0x02, 0x54, /* 2F-30 */
+		0xB0, 0x00, /* 31-32 */
+		0x14,	/* 33 */
+		0x49,	/* 34 */
+		0x00,	/* 35 written multiple times */
+		0x00,	/* 36 not written */
+		0xA3,	/* 37 */
+		0xC8,	/* 38 */
+		0x22,	/* 39 */
+		0x02,	/* 3A */
+		0x22,	/* 3B */
+		0x3F, 0x03, /* 3C-3D */
+		0x00,	/* 3E written multiple times */
+		0x00,	/* 3F not written */
+	}, MATROXFB_OUTPUT_MODE_PAL, 625, 50 };
+	static struct mavenregs ntscregs = { {
+		0x21, 0xF0, 0x7C, 0x1F,	/* 00: chroma subcarrier */
+		0x00,
+		0x00,	/* ? not written */
+		0x00,	/* modified by code (F9 written...) */
+		0x00,	/* ? not written */
+		0x7E,	/* 08 */
+		0x43,	/* 09 */
+		0x7E,	/* 0A */
+		0x3D,	/* 0B */
+		0x00,	/* 0C */
+		0x00,	/* ? not written */
+		0x41, 0x00, /* 0E-0F */
+		0x3C, 0x00, /* 10-11 */
+		0x17,	/* 12 */
+		0x21,	/* 13 */
+		0x1B, 0x1B, 0x24, /* 14-16 */
+		0x83, 0x01, /* 17-18 */
+		0x00,	/* 19 */
+		0x0F,	/* 1A */
+		0x0F,	/* 1B */
+		0x60,	/* 1C */
+		0x05,	/* 1D */
+		0x89, 0x02, /* 1E-1F */
+		0x5F,	/* 20 */
+		0x04,	/* 21 */
+		0x5F,	/* 22 */
+		0x01,	/* 23 */
+		0x02,	/* 24 */
+		0x00,	/* 25 */
+		0x0A,	/* 26 */
+		0x05,	/* 27 */
+		0x00,	/* 28 */
+		0x10,	/* 29 */
+		0xFF, 0x03, /* 2A-2B */
+		0x24,	/* 2C */
+		0x0F, 0x78, /* 2D-2E */
+		0x00, 0x00, /* 2F-30 */
+		0xB2, 0x04, /* 31-32 */
+		0x14,	/* 33 */
+		0x02,	/* 34 */
+		0x00,	/* 35 written multiple times */
+		0x00,	/* 36 not written */
+		0xA3,	/* 37 */
+		0xC8,	/* 38 */
+		0x15,	/* 39 */
+		0x05,	/* 3A */
+		0x3B,	/* 3B */
+		0x3C, 0x00, /* 3C-3D */
+		0x00,	/* 3E written multiple times */
+		0x00,	/* never written */
+	}, MATROXFB_OUTPUT_MODE_NTSC, 525, 60 };
+	MINFO_FROM(md->primary_head);
+
+	if (ACCESS_FBINFO(outputs[1]).mode == MATROXFB_OUTPUT_MODE_PAL)
+		*data = palregs;
+	else
+		*data = ntscregs;
+
+	/* Set deflicker */
+	data->regs[0x93] = maven_compute_deflicker(md);
+ 
+	/* set gamma */
+	{
+		const struct maven_gamma* g;
+		g = maven_compute_gamma(md);
+		data->regs[0x83] = g->reg83;
+		data->regs[0x84] = g->reg84;
+		data->regs[0x85] = g->reg85;
+		data->regs[0x86] = g->reg86;
+		data->regs[0x87] = g->reg87;
+		data->regs[0x88] = g->reg88;
+		data->regs[0x89] = g->reg89;
+		data->regs[0x8A] = g->reg8a;
+		data->regs[0x8B] = g->reg8b;
+	}
+ 
+	/* Set contrast / brightness */
+	{
+		int bl, wl;
+		maven_compute_bwlevel (md, &bl, &wl);
+		data->regs[0x0e] = bl >> 2;
+		data->regs[0x0f] = bl & 3;
+		data->regs[0x1e] = wl >> 2;
+		data->regs[0x1f] = wl & 3;
+	}
+
+	/* Set saturation */
+	{
+		data->regs[0x20] =
+		data->regs[0x22] = ACCESS_FBINFO(altout.tvo_params.saturation);
+	}
+ 
+	/* Set HUE */
+	data->regs[0x25] = ACCESS_FBINFO(altout.tvo_params.hue);
+	return;
+}
+
+#define LR(x) maven_set_reg(c, (x), m->regs[(x)])
+#define LRP(x) maven_set_reg_pair(c, (x), m->regs[(x)] | (m->regs[(x)+1] << 8))
+static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) {
+	int val;
+
+
+	maven_set_reg(c, 0x3E, 0x01);
+	maven_get_reg(c, 0x82);	/* fetch oscillator state? */
+	maven_set_reg(c, 0x8C, 0x00);
+	maven_get_reg(c, 0x94);	/* get 0x82 */
+	maven_set_reg(c, 0x94, 0xA2);
+	/* xmiscctrl */
+
+	maven_set_reg_pair(c, 0x8E, 0x1EFF);
+	maven_set_reg(c, 0xC6, 0x01);
+
+	/* removed code... */
+
+	maven_get_reg(c, 0x06);
+	maven_set_reg(c, 0x06, 0xF9);	/* or read |= 0xF0 ? */
+
+	/* removed code here... */
+
+	/* real code begins here? */
+	/* chroma subcarrier */
+	LR(0x00); LR(0x01); LR(0x02); LR(0x03);
+
+	LR(0x04);
+
+	LR(0x2C);
+	LR(0x08);
+	LR(0x0A);
+	LR(0x09);
+	LR(0x29);
+	LRP(0x31);
+	LRP(0x17);
+	LR(0x0B);
+	LR(0x0C);
+	if (m->mode == MATROXFB_OUTPUT_MODE_PAL) {
+		maven_set_reg(c, 0x35, 0x10); /* ... */
+	} else {
+		maven_set_reg(c, 0x35, 0x0F); /* ... */
+	}
+
+	LRP(0x10);
+
+	LRP(0x0E);
+	LRP(0x1E);
+
+	LR(0x20);	/* saturation #1 */
+	LR(0x22);	/* saturation #2 */
+	LR(0x25);	/* hue */
+	LR(0x34);
+	LR(0x33);
+	LR(0x19);
+	LR(0x12);
+	LR(0x3B);
+	LR(0x13);
+	LR(0x39);
+	LR(0x1D);
+	LR(0x3A);
+	LR(0x24);
+	LR(0x14);
+	LR(0x15);
+	LR(0x16);
+	LRP(0x2D);
+	LRP(0x2F);
+	LR(0x1A);
+	LR(0x1B);
+	LR(0x1C);
+	LR(0x23);
+	LR(0x26);
+	LR(0x28);
+	LR(0x27);
+	LR(0x21);
+	LRP(0x2A);
+	if (m->mode == MATROXFB_OUTPUT_MODE_PAL)
+		maven_set_reg(c, 0x35, 0x1D);	/* ... */
+	else
+		maven_set_reg(c, 0x35, 0x1C);
+
+	LRP(0x3C);
+	LR(0x37);
+	LR(0x38);
+	maven_set_reg(c, 0xB3, 0x01);
+
+	maven_get_reg(c, 0xB0);	/* read 0x80 */
+	maven_set_reg(c, 0xB0, 0x08);	/* ugh... */
+	maven_get_reg(c, 0xB9);	/* read 0x7C */
+	maven_set_reg(c, 0xB9, 0x78);
+	maven_get_reg(c, 0xBF);	/* read 0x00 */
+	maven_set_reg(c, 0xBF, 0x02);
+	maven_get_reg(c, 0x94);	/* read 0x82 */
+	maven_set_reg(c, 0x94, 0xB3);
+
+	LR(0x80); /* 04 1A 91 or 05 21 91 */
+	LR(0x81);
+	LR(0x82);
+
+	maven_set_reg(c, 0x8C, 0x20);
+	maven_get_reg(c, 0x8D);
+	maven_set_reg(c, 0x8D, 0x10);
+
+	LR(0x90); /* 4D 50 52 or 4E 05 45 */
+	LR(0x91);
+	LR(0x92);
+
+	LRP(0x9A); /* 0049 or 004F */
+	LRP(0x9C); /* 0004 or 0004 */
+	LRP(0x9E); /* 0458 or 045E */
+	LRP(0xA0); /* 05DA or 051B */
+	LRP(0xA2); /* 00CC or 00CF */
+	LRP(0xA4); /* 007D or 007F */
+	LRP(0xA6); /* 007C or 007E */
+	LRP(0xA8); /* 03CB or 03CE */
+	LRP(0x98); /* 0000 or 0000 */
+	LRP(0xAE); /* 0044 or 003A */
+	LRP(0x96); /* 05DA or 051B */
+	LRP(0xAA); /* 04BC or 046A */
+	LRP(0xAC); /* 004D or 004E */
+
+	LR(0xBE);
+	LR(0xC2);
+
+	maven_get_reg(c, 0x8D);
+	maven_set_reg(c, 0x8D, 0x04);
+
+	LR(0x20);	/* saturation #1 */
+	LR(0x22);	/* saturation #2 */
+	LR(0x93);	/* whoops */
+	LR(0x20);	/* oh, saturation #1 again */
+	LR(0x22);	/* oh, saturation #2 again */
+	LR(0x25);	/* hue */
+	LRP(0x0E);
+	LRP(0x1E);
+	LRP(0x0E);	/* problems with memory? */
+	LRP(0x1E);	/* yes, matrox must have problems in memory area... */
+
+	/* load gamma correction stuff */
+	LR(0x83);
+	LR(0x84);
+	LR(0x85);
+	LR(0x86);
+	LR(0x87);
+	LR(0x88);
+	LR(0x89);
+	LR(0x8A);
+	LR(0x8B);
+
+	val = maven_get_reg(c, 0x8D);
+	val &= 0x14;			/* 0x10 or anything ored with it */
+	maven_set_reg(c, 0x8D, val);
+
+	LR(0x33);
+	LR(0x19);
+	LR(0x12);
+	LR(0x3B);
+	LR(0x13);
+	LR(0x39);
+	LR(0x1D);
+	LR(0x3A);
+	LR(0x24);
+	LR(0x14);
+	LR(0x15);
+	LR(0x16);
+	LRP(0x2D);
+	LRP(0x2F);
+	LR(0x1A);
+	LR(0x1B);
+	LR(0x1C);
+	LR(0x23);
+	LR(0x26);
+	LR(0x28);
+	LR(0x27);
+	LR(0x21);
+	LRP(0x2A);
+	if (m->mode == MATROXFB_OUTPUT_MODE_PAL)
+		maven_set_reg(c, 0x35, 0x1D);
+	else
+		maven_set_reg(c, 0x35, 0x1C);
+	LRP(0x3C);
+	LR(0x37);
+	LR(0x38);
+
+	maven_get_reg(c, 0xB0);
+	LR(0xB0);	/* output mode */
+	LR(0x90);
+	LR(0xBE);
+	LR(0xC2);
+
+	LRP(0x9A);
+	LRP(0xA2);
+	LRP(0x9E);
+	LRP(0xA6);
+	LRP(0xAA);
+	LRP(0xAC);
+	maven_set_reg(c, 0x3E, 0x00);
+	maven_set_reg(c, 0x95, 0x20);
+}
+
+static int maven_find_exact_clocks(unsigned int ht, unsigned int vt,
+		struct mavenregs* m) {
+	unsigned int x;
+	unsigned int err = ~0;
+
+	/* 1:1 */
+	m->regs[0x80] = 0x0F;
+	m->regs[0x81] = 0x07;
+	m->regs[0x82] = 0x81;
+
+	for (x = 0; x < 8; x++) {
+		unsigned int a, b, c, h2;
+		unsigned int h = ht + 2 + x;
+
+		if (!matroxfb_mavenclock((m->mode == MATROXFB_OUTPUT_MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) {
+			unsigned int diff = h - h2;
+
+			if (diff < err) {
+				err = diff;
+				m->regs[0x80] = a - 1;
+				m->regs[0x81] = b - 1;
+				m->regs[0x82] = c | 0x80;
+				m->hcorr = h2 - 2;
+				m->htotal = h - 2;
+			}
+		}
+	}
+	return err != ~0U;
+}
+
+static inline int maven_compute_timming(struct maven_data* md,
+		struct my_timming* mt,
+		struct mavenregs* m) {
+	unsigned int tmpi;
+	unsigned int a, bv, c;
+	MINFO_FROM(md->primary_head);
+
+	m->mode = ACCESS_FBINFO(outputs[1]).mode;
+	if (m->mode != MATROXFB_OUTPUT_MODE_MONITOR) {
+		unsigned int lmargin;
+		unsigned int umargin;
+		unsigned int vslen;
+		unsigned int hcrt;
+		unsigned int slen;
+
+		maven_init_TVdata(md, m);
+
+		if (maven_find_exact_clocks(mt->HTotal, mt->VTotal, m) == 0)
+			return -EINVAL;
+
+		lmargin = mt->HTotal - mt->HSyncEnd;
+		slen = mt->HSyncEnd - mt->HSyncStart;
+		hcrt = mt->HTotal - slen - mt->delay;
+		umargin = mt->VTotal - mt->VSyncEnd;
+		vslen = mt->VSyncEnd - mt->VSyncStart;
+
+		if (m->hcorr < mt->HTotal)
+			hcrt += m->hcorr;
+		if (hcrt > mt->HTotal)
+			hcrt -= mt->HTotal;
+		if (hcrt + 2 > mt->HTotal)
+			hcrt = 0;	/* or issue warning? */
+
+		/* last (first? middle?) line in picture can have different length */
+		/* hlen - 2 */
+		m->regs[0x96] = m->hcorr;
+		m->regs[0x97] = m->hcorr >> 8;
+		/* ... */
+		m->regs[0x98] = 0x00; m->regs[0x99] = 0x00;
+		/* hblanking end */
+		m->regs[0x9A] = lmargin;	/* 100% */
+		m->regs[0x9B] = lmargin >> 8;	/* 100% */
+		/* who knows */
+		m->regs[0x9C] = 0x04;
+		m->regs[0x9D] = 0x00;
+		/* htotal - 2 */
+		m->regs[0xA0] = m->htotal;
+		m->regs[0xA1] = m->htotal >> 8;
+		/* vblanking end */
+		m->regs[0xA2] = mt->VTotal - mt->VSyncStart - 1;	/* stop vblanking */
+		m->regs[0xA3] = (mt->VTotal - mt->VSyncStart - 1) >> 8;
+		/* something end... [A6]+1..[A8] */
+		if (md->version == MGATVO_B) {
+			m->regs[0xA4] = 0x04;
+			m->regs[0xA5] = 0x00;
+		} else {
+			m->regs[0xA4] = 0x01;
+			m->regs[0xA5] = 0x00;
+		}
+		/* something start... 0..[A4]-1 */
+		m->regs[0xA6] = 0x00;
+		m->regs[0xA7] = 0x00;
+		/* vertical line count - 1 */
+		m->regs[0xA8] = mt->VTotal - 1;
+		m->regs[0xA9] = (mt->VTotal - 1) >> 8;
+		/* horizontal vidrst pos */
+		m->regs[0xAA] = hcrt;		/* 0 <= hcrt <= htotal - 2 */
+		m->regs[0xAB] = hcrt >> 8;
+		/* vertical vidrst pos */
+		m->regs[0xAC] = mt->VTotal - 2;
+		m->regs[0xAD] = (mt->VTotal - 2) >> 8;
+		/* moves picture up/down and so on... */
+		m->regs[0xAE] = 0x01; /* Fix this... 0..VTotal */
+		m->regs[0xAF] = 0x00;
+		{
+			int hdec;
+			int hlen;
+			unsigned int ibmin = 4 + lmargin + mt->HDisplay;
+			unsigned int ib;
+			int i;
+
+			/* Verify! */
+			/* Where 94208 came from? */
+			if (mt->HTotal)
+				hdec = 94208 / (mt->HTotal);
+			else
+				hdec = 0x81;
+			if (hdec > 0x81)
+				hdec = 0x81;
+			if (hdec < 0x41)
+				hdec = 0x41;
+			hdec--;
+			hlen = 98304 - 128 - ((lmargin + mt->HDisplay - 8) * hdec);
+			if (hlen < 0)
+				hlen = 0;
+			hlen = hlen >> 8;
+			if (hlen > 0xFF)
+				hlen = 0xFF;
+			/* Now we have to compute input buffer length.
+			   If you want any picture, it must be between
+			     4 + lmargin + xres
+			   and
+			     94208 / hdec
+			   If you want perfect picture even on the top
+			   of screen, it must be also
+			     0x3C0000 * i / hdec + Q - R / hdec
+			   where
+			        R      Qmin   Qmax
+			     0x07000   0x5AE  0x5BF
+			     0x08000   0x5CF  0x5FF
+			     0x0C000   0x653  0x67F
+			     0x10000   0x6F8  0x6FF
+			 */
+			i = 1;
+			do {
+				ib = ((0x3C0000 * i - 0x8000)/ hdec + 0x05E7) >> 8;
+				i++;
+			} while (ib < ibmin);
+			if (ib >= m->htotal + 2) {
+				ib = ibmin;
+			}
+
+			m->regs[0x90] = hdec;	/* < 0x40 || > 0x80 is bad... 0x80 is questionable */
+			m->regs[0xC2] = hlen;
+			/* 'valid' input line length */
+			m->regs[0x9E] = ib;
+			m->regs[0x9F] = ib >> 8;
+		}
+		{
+			int vdec;
+			int vlen;
+
+#define MATROX_USE64BIT_DIVIDE
+			if (mt->VTotal) {
+#ifdef MATROX_USE64BIT_DIVIDE
+				u64 f1;
+				u32 a;
+				u32 b;
+
+				a = m->vlines * (m->htotal + 2);
+				b = (mt->VTotal - 1) * (m->htotal + 2) + m->hcorr + 2;
+
+				f1 = ((u64)a) << 15;	/* *32768 */
+				do_div(f1, b);
+				vdec = f1;
+#else
+				vdec = m->vlines * 32768 / mt->VTotal;
+#endif
+			} else
+				vdec = 0x8000;
+			if (vdec > 0x8000)
+				vdec = 0x8000;
+			vlen = (vslen + umargin + mt->VDisplay) * vdec;
+			vlen = (vlen >> 16) - 146; /* FIXME: 146?! */
+			if (vlen < 0)
+				vlen = 0;
+			if (vlen > 0xFF)
+				vlen = 0xFF;
+			vdec--;
+			m->regs[0x91] = vdec;
+			m->regs[0x92] = vdec >> 8;
+			m->regs[0xBE] = vlen;
+		}
+		m->regs[0xB0] = 0x08;	/* output: SVideo/Composite */
+		return 0;
+	}
+
+	DAC1064_calcclock(mt->pixclock, 450000, &a, &bv, &c);
+	m->regs[0x80] = a;
+	m->regs[0x81] = bv;
+	m->regs[0x82] = c | 0x80;
+
+	m->regs[0xB3] = 0x01;
+	m->regs[0x94] = 0xB2;
+
+	/* htotal... */
+	m->regs[0x96] = mt->HTotal;
+	m->regs[0x97] = mt->HTotal >> 8;
+	/* ?? */
+	m->regs[0x98] = 0x00;
+	m->regs[0x99] = 0x00;
+	/* hsync len */
+	tmpi = mt->HSyncEnd - mt->HSyncStart;
+	m->regs[0x9A] = tmpi;
+	m->regs[0x9B] = tmpi >> 8;
+	/* hblank end */
+	tmpi = mt->HTotal - mt->HSyncStart;
+	m->regs[0x9C] = tmpi;
+	m->regs[0x9D] = tmpi >> 8;
+	/* hblank start */
+	tmpi += mt->HDisplay;
+	m->regs[0x9E] = tmpi;
+	m->regs[0x9F] = tmpi >> 8;
+	/* htotal + 1 */
+	tmpi = mt->HTotal + 1;
+	m->regs[0xA0] = tmpi;
+	m->regs[0xA1] = tmpi >> 8;
+	/* vsync?! */
+	tmpi = mt->VSyncEnd - mt->VSyncStart - 1;
+	m->regs[0xA2] = tmpi;
+	m->regs[0xA3] = tmpi >> 8;
+	/* ignored? */
+	tmpi = mt->VTotal - mt->VSyncStart;
+	m->regs[0xA4] = tmpi;
+	m->regs[0xA5] = tmpi >> 8;
+	/* ignored? */
+	tmpi = mt->VTotal - 1;
+	m->regs[0xA6] = tmpi;
+	m->regs[0xA7] = tmpi >> 8;
+	/* vtotal - 1 */
+	m->regs[0xA8] = tmpi;
+	m->regs[0xA9] = tmpi >> 8;
+	/* hor vidrst */
+	tmpi = mt->HTotal - mt->delay;
+	m->regs[0xAA] = tmpi;
+	m->regs[0xAB] = tmpi >> 8;
+	/* vert vidrst */
+	tmpi = mt->VTotal - 2;
+	m->regs[0xAC] = tmpi;
+	m->regs[0xAD] = tmpi >> 8;
+	/* ignored? */
+	m->regs[0xAE] = 0x00;
+	m->regs[0xAF] = 0x00;
+
+	m->regs[0xB0] = 0x03;	/* output: monitor */
+	m->regs[0xB1] = 0xA0;	/* ??? */
+	m->regs[0x8C] = 0x20;	/* must be set... */
+	m->regs[0x8D] = 0x04;	/* defaults to 0x10: test signal */
+	m->regs[0xB9] = 0x1A;	/* defaults to 0x2C: too bright */
+	m->regs[0xBF] = 0x22;	/* makes picture stable */
+
+	return 0;
+}
+
+static inline int maven_program_timming(struct maven_data* md,
+		const struct mavenregs* m) {
+	struct i2c_client* c = md->client;
+
+	if (m->mode == MATROXFB_OUTPUT_MODE_MONITOR) {
+		LR(0x80);
+		LR(0x81);
+		LR(0x82);
+
+		LR(0xB3);
+		LR(0x94);
+
+		LRP(0x96);
+		LRP(0x98);
+		LRP(0x9A);
+		LRP(0x9C);
+		LRP(0x9E);
+		LRP(0xA0);
+		LRP(0xA2);
+		LRP(0xA4);
+		LRP(0xA6);
+		LRP(0xA8);
+		LRP(0xAA);
+		LRP(0xAC);
+		LRP(0xAE);
+
+		LR(0xB0);	/* output: monitor */
+		LR(0xB1);	/* ??? */
+		LR(0x8C);	/* must be set... */
+		LR(0x8D);	/* defaults to 0x10: test signal */
+		LR(0xB9);	/* defaults to 0x2C: too bright */
+		LR(0xBF);	/* makes picture stable */
+	} else {
+		maven_init_TV(c, m);
+	}
+	return 0;
+}
+
+static inline int maven_resync(struct maven_data* md) {
+	struct i2c_client* c = md->client;
+	maven_set_reg(c, 0x95, 0x20);	/* start whole thing */
+	return 0;
+}
+
+static int maven_get_queryctrl (struct maven_data* md, 
+				struct v4l2_queryctrl *p) {
+	int i;
+	
+	i = get_ctrl_id(p->id);
+	if (i >= 0) {
+		*p = maven_controls[i].desc;
+		return 0;
+	}
+	if (i == -ENOENT) {
+		static const struct v4l2_queryctrl disctrl = 
+			{ .flags = V4L2_CTRL_FLAG_DISABLED };
+			
+		i = p->id;
+		*p = disctrl;
+		p->id = i;
+		sprintf(p->name, "Ctrl #%08X", i);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int maven_set_control (struct maven_data* md, 
+			      struct v4l2_control *p) {
+	int i;
+	
+	i = get_ctrl_id(p->id);
+	if (i < 0) return -EINVAL;
+
+	/*
+	 * Check if changed.
+	 */
+	if (p->value == *get_ctrl_ptr(md, i)) return 0;
+
+	/*
+	 * Check limits.
+	 */
+	if (p->value > maven_controls[i].desc.maximum) return -EINVAL;
+	if (p->value < maven_controls[i].desc.minimum) return -EINVAL;
+
+	/*
+	 * Store new value.
+	 */
+	*get_ctrl_ptr(md, i) = p->value;
+
+	switch (p->id) {
+		case V4L2_CID_BRIGHTNESS:
+		case V4L2_CID_CONTRAST:
+		{
+		  int blacklevel, whitelevel;
+		  maven_compute_bwlevel(md, &blacklevel, &whitelevel);
+		  blacklevel = (blacklevel >> 2) | ((blacklevel & 3) << 8);
+		  whitelevel = (whitelevel >> 2) | ((whitelevel & 3) << 8);
+		  maven_set_reg_pair(md->client, 0x0e, blacklevel);
+		  maven_set_reg_pair(md->client, 0x1e, whitelevel);
+		}
+		break;
+		case V4L2_CID_SATURATION:
+		{
+		  maven_set_reg(md->client, 0x20, p->value);
+		  maven_set_reg(md->client, 0x22, p->value);
+		}
+		break;
+		case V4L2_CID_HUE:
+		{
+		  maven_set_reg(md->client, 0x25, p->value);
+		}
+		break;
+		case V4L2_CID_GAMMA:
+		{
+		  const struct maven_gamma* g;
+		  g = maven_compute_gamma(md);
+		  maven_set_reg(md->client, 0x83, g->reg83);
+		  maven_set_reg(md->client, 0x84, g->reg84);
+		  maven_set_reg(md->client, 0x85, g->reg85);
+		  maven_set_reg(md->client, 0x86, g->reg86);
+		  maven_set_reg(md->client, 0x87, g->reg87);
+		  maven_set_reg(md->client, 0x88, g->reg88);
+		  maven_set_reg(md->client, 0x89, g->reg89);
+		  maven_set_reg(md->client, 0x8a, g->reg8a);
+		  maven_set_reg(md->client, 0x8b, g->reg8b);
+		}
+		break;
+		case MATROXFB_CID_TESTOUT:
+		{
+			unsigned char val 
+			  = maven_get_reg (md->client,0x8d);
+			if (p->value) val |= 0x10;
+			else          val &= ~0x10;
+			maven_set_reg (md->client, 0x8d, val);
+		}
+		break;
+		case MATROXFB_CID_DEFLICKER:
+		{
+		  maven_set_reg(md->client, 0x93, maven_compute_deflicker(md));
+		}
+		break;
+	}
+	
+
+	return 0;
+}
+
+static int maven_get_control (struct maven_data* md, 
+			      struct v4l2_control *p) {
+	int i;
+	
+	i = get_ctrl_id(p->id);
+	if (i < 0) return -EINVAL;
+	p->value = *get_ctrl_ptr(md, i);
+	return 0;
+}
+
+/******************************************************/
+
+static int maven_out_compute(void* md, struct my_timming* mt) {
+#define mdinfo ((struct maven_data*)md)
+#define minfo (mdinfo->primary_head)
+	return maven_compute_timming(md, mt, &ACCESS_FBINFO(hw).maven);
+#undef minfo
+#undef mdinfo
+}
+
+static int maven_out_program(void* md) {
+#define mdinfo ((struct maven_data*)md)
+#define minfo (mdinfo->primary_head)
+	return maven_program_timming(md, &ACCESS_FBINFO(hw).maven);
+#undef minfo
+#undef mdinfo
+}
+
+static int maven_out_start(void* md) {
+	return maven_resync(md);
+}
+
+static int maven_out_verify_mode(void* md, u_int32_t arg) {
+	switch (arg) {
+		case MATROXFB_OUTPUT_MODE_PAL:
+		case MATROXFB_OUTPUT_MODE_NTSC:
+		case MATROXFB_OUTPUT_MODE_MONITOR:
+			return 0;
+	}
+	return -EINVAL;
+}
+
+static int maven_out_get_queryctrl(void* md, struct v4l2_queryctrl* p) {
+        return maven_get_queryctrl(md, p);
+}
+
+static int maven_out_get_ctrl(void* md, struct v4l2_control* p) {
+	return maven_get_control(md, p);
+}
+
+static int maven_out_set_ctrl(void* md, struct v4l2_control* p) {
+	return maven_set_control(md, p);
+}
+
+static struct matrox_altout maven_altout = {
+	.name		= "Secondary output",
+	.compute	= maven_out_compute,
+	.program	= maven_out_program,
+	.start		= maven_out_start,
+	.verifymode	= maven_out_verify_mode,
+	.getqueryctrl	= maven_out_get_queryctrl,
+	.getctrl	= maven_out_get_ctrl,
+	.setctrl	= maven_out_set_ctrl,
+};
+
+static int maven_init_client(struct i2c_client* clnt) {
+	struct maven_data* md = i2c_get_clientdata(clnt);
+	MINFO_FROM(container_of(clnt->adapter, struct i2c_bit_adapter, adapter)->minfo);
+
+	md->primary_head = MINFO;
+	md->client = clnt;
+	down_write(&ACCESS_FBINFO(altout.lock));
+	ACCESS_FBINFO(outputs[1]).output = &maven_altout;
+	ACCESS_FBINFO(outputs[1]).src = ACCESS_FBINFO(outputs[1]).default_src;
+	ACCESS_FBINFO(outputs[1]).data = md;
+	ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+	up_write(&ACCESS_FBINFO(altout.lock));
+	if (maven_get_reg(clnt, 0xB2) < 0x14) {
+		md->version = MGATVO_B;
+		/* Tweak some things for this old chip */
+	} else {
+		md->version = MGATVO_C;
+	}
+	/*
+	 * Set all parameters to its initial values.
+	 */
+	{
+		unsigned int i;
+
+		for (i = 0; i < MAVCTRLS; ++i) {
+			*get_ctrl_ptr(md, i) = maven_controls[i].desc.default_value;
+		}
+	}
+
+	return 0;
+}
+
+static int maven_shutdown_client(struct i2c_client* clnt) {
+	struct maven_data* md = i2c_get_clientdata(clnt);
+
+	if (md->primary_head) {
+		MINFO_FROM(md->primary_head);
+
+		down_write(&ACCESS_FBINFO(altout.lock));
+		ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE;
+		ACCESS_FBINFO(outputs[1]).output = NULL;
+		ACCESS_FBINFO(outputs[1]).data = NULL;
+		ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		up_write(&ACCESS_FBINFO(altout.lock));
+		md->primary_head = NULL;
+	}
+	return 0;
+}
+
+static unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END };
+static unsigned short normal_i2c_range[] = { MAVEN_I2CID, MAVEN_I2CID, I2C_CLIENT_END };
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver maven_driver;
+
+static int maven_detect_client(struct i2c_adapter* adapter, int address, int kind) {
+	int err = 0;
+	struct i2c_client* new_client;
+	struct maven_data* data;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_WORD_DATA |
+					      I2C_FUNC_SMBUS_BYTE_DATA |
+					      I2C_FUNC_PROTOCOL_MANGLING))
+		goto ERROR0;
+	if (!(new_client = (struct i2c_client*)kmalloc(sizeof(*new_client) + sizeof(*data),
+			GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto ERROR0;
+	}
+	memset(new_client, 0, sizeof(*new_client) + sizeof(*data));
+	data = (struct maven_data*)(new_client + 1);
+	i2c_set_clientdata(new_client, data);
+	new_client->addr = address;
+	new_client->adapter = adapter;
+	new_client->driver = &maven_driver;
+	new_client->flags = 0;
+	strcpy(new_client->name, "maven client");
+	if ((err = i2c_attach_client(new_client)))
+		goto ERROR3;
+	err = maven_init_client(new_client);
+	if (err)
+		goto ERROR4;
+	return 0;
+ERROR4:;
+	i2c_detach_client(new_client);
+ERROR3:;
+	kfree(new_client);
+ERROR0:;
+	return err;
+}
+
+static int maven_attach_adapter(struct i2c_adapter* adapter) {
+	if (adapter->id == (I2C_ALGO_BIT | I2C_HW_B_G400))
+		return i2c_probe(adapter, &addr_data, &maven_detect_client);
+	return 0;
+}
+
+static int maven_detach_client(struct i2c_client* client) {
+	int err;
+
+	if ((err = i2c_detach_client(client))) {
+		printk(KERN_ERR "maven: Cannot deregister client\n");
+		return err;
+	}
+	maven_shutdown_client(client);
+	kfree(client);
+	return 0;
+}
+
+static int maven_command(struct i2c_client* client, unsigned int cmd, void* arg) {
+	return -ENOIOCTLCMD;	/* or -EINVAL, depends on who will call this */
+}
+
+static struct i2c_driver maven_driver={
+	.owner		= THIS_MODULE,
+	.name		= "maven",
+	.id		= I2C_DRIVERID_MGATVO,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= maven_attach_adapter,
+	.detach_client	= maven_detach_client,
+	.command	= maven_command,
+};
+
+/* ************************** */
+
+static int matroxfb_maven_init(void) {
+	int err;
+
+	err = i2c_add_driver(&maven_driver);
+	if (err) {
+		printk(KERN_ERR "maven: Maven driver failed to register (%d).\n", err);
+		return err;
+	}
+	return 0;
+}
+
+static void matroxfb_maven_exit(void) {
+	i2c_del_driver(&maven_driver);
+}
+
+MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver");
+MODULE_LICENSE("GPL");
+module_init(matroxfb_maven_init);
+module_exit(matroxfb_maven_exit);
+/* we do not have __setup() yet */
diff --git a/drivers/video/matrox/matroxfb_maven.h b/drivers/video/matrox/matroxfb_maven.h
new file mode 100644
index 0000000..99eddec
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_maven.h
@@ -0,0 +1,20 @@
+#ifndef __MATROXFB_MAVEN_H__
+#define __MATROXFB_MAVEN_H__
+
+#include <linux/ioctl.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include "matroxfb_base.h"
+
+struct i2c_bit_adapter {
+	struct i2c_adapter		adapter;
+	int				initialized;
+	struct i2c_algo_bit_data	bac;
+	struct matrox_fb_info*		minfo;
+	struct {
+		unsigned int		data;
+		unsigned int		clock;
+				      } mask;
+};
+
+#endif /* __MATROXFB_MAVEN_H__ */
diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c
new file mode 100644
index 0000000..76fd3a5
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_misc.c
@@ -0,0 +1,777 @@
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
+ *
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Portions Copyright (c) 2001 Matrox Graphics Inc.
+ *
+ * Version: 1.65 2002/08/14
+ *
+ * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
+ *
+ * Contributors: "menion?" <menion@mindless.com>
+ *                     Betatesting, fixes, ideas
+ *
+ *               "Kurt Garloff" <garloff@suse.de>
+ *                     Betatesting, fixes, ideas, videomodes, videomodes timmings
+ *
+ *               "Tom Rini" <trini@kernel.crashing.org>
+ *                     MTRR stuff, PPC cleanups, betatesting, fixes, ideas
+ *
+ *               "Bibek Sahu" <scorpio@dodds.net>
+ *                     Access device through readb|w|l and write b|w|l
+ *                     Extensive debugging stuff
+ *
+ *               "Daniel Haun" <haund@usa.net>
+ *                     Testing, hardware cursor fixes
+ *
+ *               "Scott Wood" <sawst46+@pitt.edu>
+ *                     Fixes
+ *
+ *               "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
+ *                     Betatesting
+ *
+ *               "Kelly French" <targon@hazmat.com>
+ *               "Fernando Herrera" <fherrera@eurielec.etsit.upm.es>
+ *                     Betatesting, bug reporting
+ *
+ *               "Pablo Bianucci" <pbian@pccp.com.ar>
+ *                     Fixes, ideas, betatesting
+ *
+ *               "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
+ *                     Fixes, enhandcements, ideas, betatesting
+ *
+ *               "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
+ *                     PPC betatesting, PPC support, backward compatibility
+ *
+ *               "Paul Womar" <Paul@pwomar.demon.co.uk>
+ *               "Owen Waller" <O.Waller@ee.qub.ac.uk>
+ *                     PPC betatesting
+ *
+ *               "Thomas Pornin" <pornin@bolet.ens.fr>
+ *                     Alpha betatesting
+ *
+ *               "Pieter van Leuven" <pvl@iae.nl>
+ *               "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de>
+ *                     G100 testing
+ *
+ *               "H. Peter Arvin" <hpa@transmeta.com>
+ *                     Ideas
+ *
+ *               "Cort Dougan" <cort@cs.nmt.edu>
+ *                     CHRP fixes and PReP cleanup
+ *
+ *               "Mark Vojkovich" <mvojkovi@ucsd.edu>
+ *                     G400 support
+ *
+ *               "David C. Hansen" <haveblue@us.ibm.com>
+ *                     Fixes
+ *
+ * (following author is not in any relation with this code, but his code
+ *  is included in this driver)
+ *
+ * Based on framebuffer driver for VBE 2.0 compliant graphic boards
+ *     (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ * (following author is not in any relation with this code, but his ideas
+ *  were used when writting this driver)
+ *
+ *		 FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
+ *
+ */
+
+/* make checkconfig does not check includes for this... */
+#include <linux/config.h>
+
+#include "matroxfb_misc.h"
+#include <linux/interrupt.h>
+#include <linux/matroxfb.h>
+
+void matroxfb_DAC_out(CPMINFO int reg, int val) {
+	DBG_REG(__FUNCTION__)
+	mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg);
+	mga_outb(M_RAMDAC_BASE+M_X_DATAREG, val);
+}
+
+int matroxfb_DAC_in(CPMINFO int reg) {
+	DBG_REG(__FUNCTION__)
+	mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg);
+	return mga_inb(M_RAMDAC_BASE+M_X_DATAREG);
+}
+
+void matroxfb_var2my(struct fb_var_screeninfo* var, struct my_timming* mt) {
+	unsigned int pixclock = var->pixclock;
+
+	DBG(__FUNCTION__)
+
+	if (!pixclock) pixclock = 10000;	/* 10ns = 100MHz */
+	mt->pixclock = 1000000000 / pixclock;
+	if (mt->pixclock < 1) mt->pixclock = 1;
+	mt->mnp = -1;
+	mt->dblscan = var->vmode & FB_VMODE_DOUBLE;
+	mt->interlaced = var->vmode & FB_VMODE_INTERLACED;
+	mt->HDisplay = var->xres;
+	mt->HSyncStart = mt->HDisplay + var->right_margin;
+	mt->HSyncEnd = mt->HSyncStart + var->hsync_len;
+	mt->HTotal = mt->HSyncEnd + var->left_margin;
+	mt->VDisplay = var->yres;
+	mt->VSyncStart = mt->VDisplay + var->lower_margin;
+	mt->VSyncEnd = mt->VSyncStart + var->vsync_len;
+	mt->VTotal = mt->VSyncEnd + var->upper_margin;
+	mt->sync = var->sync;
+}
+
+int matroxfb_PLL_calcclock(const struct matrox_pll_features* pll, unsigned int freq, unsigned int fmax,
+		unsigned int* in, unsigned int* feed, unsigned int* post) {
+	unsigned int bestdiff = ~0;
+	unsigned int bestvco = 0;
+	unsigned int fxtal = pll->ref_freq;
+	unsigned int fwant;
+	unsigned int p;
+
+	DBG(__FUNCTION__)
+
+	fwant = freq;
+
+#ifdef DEBUG
+	printk(KERN_ERR "post_shift_max: %d\n", pll->post_shift_max);
+	printk(KERN_ERR "ref_freq: %d\n", pll->ref_freq);
+	printk(KERN_ERR "freq: %d\n", freq);
+	printk(KERN_ERR "vco_freq_min: %d\n", pll->vco_freq_min);
+	printk(KERN_ERR "in_div_min: %d\n", pll->in_div_min);
+	printk(KERN_ERR "in_div_max: %d\n", pll->in_div_max);
+	printk(KERN_ERR "feed_div_min: %d\n", pll->feed_div_min);
+	printk(KERN_ERR "feed_div_max: %d\n", pll->feed_div_max);
+	printk(KERN_ERR "fmax: %d\n", fmax);
+#endif
+	for (p = 1; p <= pll->post_shift_max; p++) {
+		if (fwant * 2 > fmax)
+			break;
+		fwant *= 2;
+	}
+	if (fwant < pll->vco_freq_min) fwant = pll->vco_freq_min;
+	if (fwant > fmax) fwant = fmax;
+	for (; p-- > 0; fwant >>= 1, bestdiff >>= 1) {
+		unsigned int m;
+
+		if (fwant < pll->vco_freq_min) break;
+		for (m = pll->in_div_min; m <= pll->in_div_max; m++) {
+			unsigned int diff, fvco;
+			unsigned int n;
+
+			n = (fwant * (m + 1) + (fxtal >> 1)) / fxtal - 1;
+			if (n > pll->feed_div_max)
+				break;
+			if (n < pll->feed_div_min)
+				n = pll->feed_div_min;
+			fvco = (fxtal * (n + 1)) / (m + 1);
+			if (fvco < fwant)
+				diff = fwant - fvco;
+			else
+				diff = fvco - fwant;
+			if (diff < bestdiff) {
+				bestdiff = diff;
+				*post = p;
+				*in = m;
+				*feed = n;
+				bestvco = fvco;
+			}
+		}
+	}
+	dprintk(KERN_ERR "clk: %02X %02X %02X %d %d %d\n", *in, *feed, *post, fxtal, bestvco, fwant);
+	return bestvco;
+}
+
+int matroxfb_vgaHWinit(WPMINFO struct my_timming* m) {
+	unsigned int hd, hs, he, hbe, ht;
+	unsigned int vd, vs, ve, vt, lc;
+	unsigned int wd;
+	unsigned int divider;
+	int i;
+	int fwidth;
+	struct matrox_hw_state * const hw = &ACCESS_FBINFO(hw);
+
+	fwidth = 8;
+
+	DBG(__FUNCTION__)
+
+	hw->SEQ[0] = 0x00;
+	if (fwidth == 9)
+		hw->SEQ[1] = 0x00;
+	else
+		hw->SEQ[1] = 0x01;	/* or 0x09 */
+	hw->SEQ[2] = 0x0F;	/* bitplanes */
+	hw->SEQ[3] = 0x00;
+	hw->SEQ[4] = 0x0E;
+	/* CRTC 0..7, 9, 16..19, 21, 22 are reprogrammed by Matrox Millennium code... Hope that by MGA1064 too */
+	if (m->dblscan) {
+		m->VTotal <<= 1;
+		m->VDisplay <<= 1;
+		m->VSyncStart <<= 1;
+		m->VSyncEnd <<= 1;
+	}
+	if (m->interlaced) {
+		m->VTotal >>= 1;
+		m->VDisplay >>= 1;
+		m->VSyncStart >>= 1;
+		m->VSyncEnd >>= 1;
+	}
+
+	/* GCTL is ignored when not using 0xA0000 aperture */
+	hw->GCTL[0] = 0x00;
+	hw->GCTL[1] = 0x00;
+	hw->GCTL[2] = 0x00;
+	hw->GCTL[3] = 0x00;
+	hw->GCTL[4] = 0x00;
+	hw->GCTL[5] = 0x40;
+	hw->GCTL[6] = 0x05;
+	hw->GCTL[7] = 0x0F;
+	hw->GCTL[8] = 0xFF;
+
+	/* Whole ATTR is ignored in PowerGraphics mode */
+	for (i = 0; i < 16; i++)
+		hw->ATTR[i] = i;
+	hw->ATTR[16] = 0x41;
+	hw->ATTR[17] = 0xFF;
+	hw->ATTR[18] = 0x0F;
+	if (fwidth == 9)
+		hw->ATTR[19] = 0x08;
+	else
+		hw->ATTR[19] = 0x00;
+	hw->ATTR[20] = 0x00;
+
+	hd = m->HDisplay >> 3;
+	hs = m->HSyncStart >> 3;
+	he = m->HSyncEnd >> 3;
+	ht = m->HTotal >> 3;
+	/* standard timmings are in 8pixels, but for interleaved we cannot */
+	/* do it for 4bpp (because of (4bpp >> 1(interleaved))/4 == 0) */
+	/* using 16 or more pixels per unit can save us */
+	divider = ACCESS_FBINFO(curr.final_bppShift);
+	while (divider & 3) {
+		hd >>= 1;
+		hs >>= 1;
+		he >>= 1;
+		ht >>= 1;
+		divider <<= 1;
+	}
+	divider = divider / 4;
+	/* divider can be from 1 to 8 */
+	while (divider > 8) {
+		hd <<= 1;
+		hs <<= 1;
+		he <<= 1;
+		ht <<= 1;
+		divider >>= 1;
+	}
+	hd = hd - 1;
+	hs = hs - 1;
+	he = he - 1;
+	ht = ht - 1;
+	vd = m->VDisplay - 1;
+	vs = m->VSyncStart - 1;
+	ve = m->VSyncEnd - 1;
+	vt = m->VTotal - 2;
+	lc = vd;
+	/* G200 cannot work with (ht & 7) == 6 */
+	if (((ht & 0x07) == 0x06) || ((ht & 0x0F) == 0x04))
+		ht++;
+	hbe = ht;
+	wd = ACCESS_FBINFO(fbcon).var.xres_virtual * ACCESS_FBINFO(curr.final_bppShift) / 64;
+
+	hw->CRTCEXT[0] = 0;
+	hw->CRTCEXT[5] = 0;
+	if (m->interlaced) {
+		hw->CRTCEXT[0] = 0x80;
+		hw->CRTCEXT[5] = (hs + he - ht) >> 1;
+		if (!m->dblscan)
+			wd <<= 1;
+		vt &= ~1;
+	}
+	hw->CRTCEXT[0] |=  (wd & 0x300) >> 4;
+	hw->CRTCEXT[1] = (((ht - 4) & 0x100) >> 8) |
+			  ((hd      & 0x100) >> 7) | /* blanking */
+			  ((hs      & 0x100) >> 6) | /* sync start */
+			   (hbe     & 0x040);	 /* end hor. blanking */
+	/* FIXME: Enable vidrst only on G400, and only if TV-out is used */
+	if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC1)
+		hw->CRTCEXT[1] |= 0x88;		/* enable horizontal and vertical vidrst */
+	hw->CRTCEXT[2] =  ((vt & 0xC00) >> 10) |
+			  ((vd & 0x400) >>  8) |	/* disp end */
+			  ((vd & 0xC00) >>  7) |	/* vblanking start */
+			  ((vs & 0xC00) >>  5) |
+			  ((lc & 0x400) >>  3);
+	hw->CRTCEXT[3] = (divider - 1) | 0x80;
+	hw->CRTCEXT[4] = 0;
+
+	hw->CRTC[0] = ht-4;
+	hw->CRTC[1] = hd;
+	hw->CRTC[2] = hd;
+	hw->CRTC[3] = (hbe & 0x1F) | 0x80;
+	hw->CRTC[4] = hs;
+	hw->CRTC[5] = ((hbe & 0x20) << 2) | (he & 0x1F);
+	hw->CRTC[6] = vt & 0xFF;
+	hw->CRTC[7] = ((vt & 0x100) >> 8) |
+		      ((vd & 0x100) >> 7) |
+		      ((vs & 0x100) >> 6) |
+		      ((vd & 0x100) >> 5) |
+		      ((lc & 0x100) >> 4) |
+		      ((vt & 0x200) >> 4) |
+		      ((vd & 0x200) >> 3) |
+		      ((vs & 0x200) >> 2);
+	hw->CRTC[8] = 0x00;
+	hw->CRTC[9] = ((vd & 0x200) >> 4) |
+		      ((lc & 0x200) >> 3);
+	if (m->dblscan && !m->interlaced)
+		hw->CRTC[9] |= 0x80;
+	for (i = 10; i < 16; i++)
+		hw->CRTC[i] = 0x00;
+	hw->CRTC[16] = vs /* & 0xFF */;
+	hw->CRTC[17] = (ve & 0x0F) | 0x20;
+	hw->CRTC[18] = vd /* & 0xFF */;
+	hw->CRTC[19] = wd /* & 0xFF */;
+	hw->CRTC[20] = 0x00;
+	hw->CRTC[21] = vd /* & 0xFF */;
+	hw->CRTC[22] = (vt + 1) /* & 0xFF */;
+	hw->CRTC[23] = 0xC3;
+	hw->CRTC[24] = lc;
+	return 0;
+};
+
+void matroxfb_vgaHWrestore(WPMINFO2) {
+	int i;
+	struct matrox_hw_state * const hw = &ACCESS_FBINFO(hw);
+	CRITFLAGS
+
+	DBG(__FUNCTION__)
+
+	dprintk(KERN_INFO "MiscOutReg: %02X\n", hw->MiscOutReg);
+	dprintk(KERN_INFO "SEQ regs:   ");
+	for (i = 0; i < 5; i++)
+		dprintk("%02X:", hw->SEQ[i]);
+	dprintk("\n");
+	dprintk(KERN_INFO "GDC regs:   ");
+	for (i = 0; i < 9; i++)
+		dprintk("%02X:", hw->GCTL[i]);
+	dprintk("\n");
+	dprintk(KERN_INFO "CRTC regs: ");
+	for (i = 0; i < 25; i++)
+		dprintk("%02X:", hw->CRTC[i]);
+	dprintk("\n");
+	dprintk(KERN_INFO "ATTR regs: ");
+	for (i = 0; i < 21; i++)
+		dprintk("%02X:", hw->ATTR[i]);
+	dprintk("\n");
+
+	CRITBEGIN
+
+	mga_inb(M_ATTR_RESET);
+	mga_outb(M_ATTR_INDEX, 0);
+	mga_outb(M_MISC_REG, hw->MiscOutReg);
+	for (i = 1; i < 5; i++)
+		mga_setr(M_SEQ_INDEX, i, hw->SEQ[i]);
+	mga_setr(M_CRTC_INDEX, 17, hw->CRTC[17] & 0x7F);
+	for (i = 0; i < 25; i++)
+		mga_setr(M_CRTC_INDEX, i, hw->CRTC[i]);
+	for (i = 0; i < 9; i++)
+		mga_setr(M_GRAPHICS_INDEX, i, hw->GCTL[i]);
+	for (i = 0; i < 21; i++) {
+		mga_inb(M_ATTR_RESET);
+		mga_outb(M_ATTR_INDEX, i);
+		mga_outb(M_ATTR_INDEX, hw->ATTR[i]);
+	}
+	mga_outb(M_PALETTE_MASK, 0xFF);
+	mga_outb(M_DAC_REG, 0x00);
+	for (i = 0; i < 768; i++)
+		mga_outb(M_DAC_VAL, hw->DACpal[i]);
+	mga_inb(M_ATTR_RESET);
+	mga_outb(M_ATTR_INDEX, 0x20);
+
+	CRITEND
+}
+
+static void get_pins(unsigned char __iomem* pins, struct matrox_bios* bd) {
+	unsigned int b0 = readb(pins);
+	
+	if (b0 == 0x2E && readb(pins+1) == 0x41) {
+		unsigned int pins_len = readb(pins+2);
+		unsigned int i;
+		unsigned char cksum;
+		unsigned char* dst = bd->pins;
+
+		if (pins_len < 3 || pins_len > 128) {
+			return;
+		}
+		*dst++ = 0x2E;
+		*dst++ = 0x41;
+		*dst++ = pins_len;
+		cksum = 0x2E + 0x41 + pins_len;
+		for (i = 3; i < pins_len; i++) {
+			cksum += *dst++ = readb(pins+i);
+		}
+		if (cksum) {
+			return;
+		}
+		bd->pins_len = pins_len;
+	} else if (b0 == 0x40 && readb(pins+1) == 0x00) {
+		unsigned int i;
+		unsigned char* dst = bd->pins;
+
+		*dst++ = 0x40;
+		*dst++ = 0;
+		for (i = 2; i < 0x40; i++) {
+			*dst++ = readb(pins+i);
+		}
+		bd->pins_len = 0x40;
+	}
+}
+
+static void get_bios_version(unsigned char __iomem * vbios, struct matrox_bios* bd) {
+	unsigned int pcir_offset;
+	
+	pcir_offset = readb(vbios + 24) | (readb(vbios + 25) << 8);
+	if (pcir_offset >= 26 && pcir_offset < 0xFFE0 &&
+	    readb(vbios + pcir_offset    ) == 'P' &&
+	    readb(vbios + pcir_offset + 1) == 'C' &&
+	    readb(vbios + pcir_offset + 2) == 'I' &&
+	    readb(vbios + pcir_offset + 3) == 'R') {
+		unsigned char h;
+
+		h = readb(vbios + pcir_offset + 0x12);
+		bd->version.vMaj = (h >> 4) & 0xF;
+		bd->version.vMin = h & 0xF;
+		bd->version.vRev = readb(vbios + pcir_offset + 0x13);
+	} else {
+		unsigned char h;
+
+		h = readb(vbios + 5);
+		bd->version.vMaj = (h >> 4) & 0xF;
+		bd->version.vMin = h & 0xF;
+		bd->version.vRev = 0;
+	}
+}
+
+static void get_bios_output(unsigned char __iomem* vbios, struct matrox_bios* bd) {
+	unsigned char b;
+	
+	b = readb(vbios + 0x7FF1);
+	if (b == 0xFF) {
+		b = 0;
+	}
+	bd->output.state = b;
+}
+
+static void get_bios_tvout(unsigned char __iomem* vbios, struct matrox_bios* bd) {
+	unsigned int i;
+	
+	/* Check for 'IBM .*(V....TVO' string - it means TVO BIOS */
+	bd->output.tvout = 0;
+	if (readb(vbios + 0x1D) != 'I' ||
+	    readb(vbios + 0x1E) != 'B' ||
+	    readb(vbios + 0x1F) != 'M' ||
+	    readb(vbios + 0x20) != ' ') {
+	    	return;
+	}
+	for (i = 0x2D; i < 0x2D + 128; i++) {
+		unsigned char b = readb(vbios + i);
+		
+		if (b == '(' && readb(vbios + i + 1) == 'V') {
+			if (readb(vbios + i + 6) == 'T' &&
+			    readb(vbios + i + 7) == 'V' &&
+			    readb(vbios + i + 8) == 'O') {
+				bd->output.tvout = 1;
+			}
+			return;
+		}
+		if (b == 0)
+			break;
+	}
+}
+
+static void parse_bios(unsigned char __iomem* vbios, struct matrox_bios* bd) {
+	unsigned int pins_offset;
+	
+	if (readb(vbios) != 0x55 || readb(vbios + 1) != 0xAA) {
+		return;
+	}
+	bd->bios_valid = 1;
+	get_bios_version(vbios, bd);
+	get_bios_output(vbios, bd);
+	get_bios_tvout(vbios, bd);
+	pins_offset = readb(vbios + 0x7FFC) | (readb(vbios + 0x7FFD) << 8);
+	if (pins_offset <= 0xFF80) {
+		get_pins(vbios + pins_offset, bd);
+	}
+}
+
+#define get_u16(x) (le16_to_cpu(get_unaligned((__u16*)(x))))
+#define get_u32(x) (le32_to_cpu(get_unaligned((__u32*)(x))))
+static int parse_pins1(WPMINFO const struct matrox_bios* bd) {
+	unsigned int maxdac;
+
+	switch (bd->pins[22]) {
+		case 0:		maxdac = 175000; break;
+		case 1:		maxdac = 220000; break;
+		default:	maxdac = 240000; break;
+	}
+	if (get_u16(bd->pins + 24)) {
+		maxdac = get_u16(bd->pins + 24) * 10;
+	}
+	MINFO->limits.pixel.vcomax = maxdac;
+	MINFO->values.pll.system = get_u16(bd->pins + 28) ? get_u16(bd->pins + 28) * 10 : 50000;
+	/* ignore 4MB, 8MB, module clocks */
+	MINFO->features.pll.ref_freq = 14318;
+	MINFO->values.reg.mctlwtst	= 0x00030101;
+	return 0;
+}
+
+static void default_pins1(WPMINFO2) {
+	/* Millennium */
+	MINFO->limits.pixel.vcomax	= 220000;
+	MINFO->values.pll.system	=  50000;
+	MINFO->features.pll.ref_freq	=  14318;
+	MINFO->values.reg.mctlwtst	= 0x00030101;
+}
+
+static int parse_pins2(WPMINFO const struct matrox_bios* bd) {
+	MINFO->limits.pixel.vcomax	=
+	MINFO->limits.system.vcomax	= (bd->pins[41] == 0xFF) ? 230000 : ((bd->pins[41] + 100) * 1000);
+	MINFO->values.reg.mctlwtst	= ((bd->pins[51] & 0x01) ? 0x00000001 : 0) |
+					  ((bd->pins[51] & 0x02) ? 0x00000100 : 0) |
+					  ((bd->pins[51] & 0x04) ? 0x00010000 : 0) |
+					  ((bd->pins[51] & 0x08) ? 0x00020000 : 0);
+	MINFO->values.pll.system	= (bd->pins[43] == 0xFF) ? 50000 : ((bd->pins[43] + 100) * 1000);
+	MINFO->features.pll.ref_freq	= 14318;
+	return 0;
+}
+
+static void default_pins2(WPMINFO2) {
+	/* Millennium II, Mystique */
+	MINFO->limits.pixel.vcomax	=
+	MINFO->limits.system.vcomax	= 230000;
+	MINFO->values.reg.mctlwtst	= 0x00030101;
+	MINFO->values.pll.system	=  50000;
+	MINFO->features.pll.ref_freq	=  14318;
+}
+
+static int parse_pins3(WPMINFO const struct matrox_bios* bd) {
+	MINFO->limits.pixel.vcomax	=
+	MINFO->limits.system.vcomax	= (bd->pins[36] == 0xFF) ? 230000			: ((bd->pins[36] + 100) * 1000);
+	MINFO->values.reg.mctlwtst	= get_u32(bd->pins + 48) == 0xFFFFFFFF ? 0x01250A21	: get_u32(bd->pins + 48);
+	/* memory config */
+	MINFO->values.reg.memrdbk	= ((bd->pins[57] << 21) & 0x1E000000) |
+					  ((bd->pins[57] << 22) & 0x00C00000) |
+					  ((bd->pins[56] <<  1) & 0x000001E0) |
+					  ( bd->pins[56]        & 0x0000000F);
+	MINFO->values.reg.opt		= (bd->pins[54] & 7) << 10;
+	MINFO->values.reg.opt2		= bd->pins[58] << 12;
+	MINFO->features.pll.ref_freq	= (bd->pins[52] & 0x20) ? 14318 : 27000;
+	return 0;
+}
+
+static void default_pins3(WPMINFO2) {
+	/* G100, G200 */
+	MINFO->limits.pixel.vcomax	=
+	MINFO->limits.system.vcomax	= 230000;
+	MINFO->values.reg.mctlwtst	= 0x01250A21;
+	MINFO->values.reg.memrdbk	= 0x00000000;
+	MINFO->values.reg.opt		= 0x00000C00;
+	MINFO->values.reg.opt2		= 0x00000000;
+	MINFO->features.pll.ref_freq	=  27000;
+}
+
+static int parse_pins4(WPMINFO const struct matrox_bios* bd) {
+	MINFO->limits.pixel.vcomax	= (bd->pins[ 39] == 0xFF) ? 230000			: bd->pins[ 39] * 4000;
+	MINFO->limits.system.vcomax	= (bd->pins[ 38] == 0xFF) ? MINFO->limits.pixel.vcomax	: bd->pins[ 38] * 4000;
+	MINFO->values.reg.mctlwtst	= get_u32(bd->pins + 71);
+	MINFO->values.reg.memrdbk	= ((bd->pins[87] << 21) & 0x1E000000) |
+					  ((bd->pins[87] << 22) & 0x00C00000) |
+					  ((bd->pins[86] <<  1) & 0x000001E0) |
+					  ( bd->pins[86]        & 0x0000000F);
+	MINFO->values.reg.opt		= ((bd->pins[53] << 15) & 0x00400000) |
+					  ((bd->pins[53] << 22) & 0x10000000) |
+					  ((bd->pins[53] <<  7) & 0x00001C00);
+	MINFO->values.reg.opt3		= get_u32(bd->pins + 67);
+	MINFO->values.pll.system	= (bd->pins[ 65] == 0xFF) ? 200000 			: bd->pins[ 65] * 4000;
+	MINFO->features.pll.ref_freq	= (bd->pins[ 92] & 0x01) ? 14318 : 27000;
+	return 0;
+}
+
+static void default_pins4(WPMINFO2) {
+	/* G400 */
+	MINFO->limits.pixel.vcomax	=
+	MINFO->limits.system.vcomax	= 252000;
+	MINFO->values.reg.mctlwtst	= 0x04A450A1;
+	MINFO->values.reg.memrdbk	= 0x000000E7;
+	MINFO->values.reg.opt		= 0x10000400;
+	MINFO->values.reg.opt3		= 0x0190A419;
+	MINFO->values.pll.system	= 200000;
+	MINFO->features.pll.ref_freq	= 27000;
+}
+
+static int parse_pins5(WPMINFO const struct matrox_bios* bd) {
+	unsigned int mult;
+	
+	mult = bd->pins[4]?8000:6000;
+	
+	MINFO->limits.pixel.vcomax	= (bd->pins[ 38] == 0xFF) ? 600000			: bd->pins[ 38] * mult;
+	MINFO->limits.system.vcomax	= (bd->pins[ 36] == 0xFF) ? MINFO->limits.pixel.vcomax	: bd->pins[ 36] * mult;
+	MINFO->limits.video.vcomax	= (bd->pins[ 37] == 0xFF) ? MINFO->limits.system.vcomax	: bd->pins[ 37] * mult;
+	MINFO->limits.pixel.vcomin	= (bd->pins[123] == 0xFF) ? 256000			: bd->pins[123] * mult;
+	MINFO->limits.system.vcomin	= (bd->pins[121] == 0xFF) ? MINFO->limits.pixel.vcomin	: bd->pins[121] * mult;
+	MINFO->limits.video.vcomin	= (bd->pins[122] == 0xFF) ? MINFO->limits.system.vcomin	: bd->pins[122] * mult;
+	MINFO->values.pll.system	=
+	MINFO->values.pll.video		= (bd->pins[ 92] == 0xFF) ? 284000			: bd->pins[ 92] * 4000;
+	MINFO->values.reg.opt		= get_u32(bd->pins+ 48);
+	MINFO->values.reg.opt2		= get_u32(bd->pins+ 52);
+	MINFO->values.reg.opt3		= get_u32(bd->pins+ 94);
+	MINFO->values.reg.mctlwtst	= get_u32(bd->pins+ 98);
+	MINFO->values.reg.memmisc	= get_u32(bd->pins+102);
+	MINFO->values.reg.memrdbk	= get_u32(bd->pins+106);
+	MINFO->features.pll.ref_freq	= (bd->pins[110] & 0x01) ? 14318 : 27000;
+	MINFO->values.memory.ddr	= (bd->pins[114] & 0x60) == 0x20;
+	MINFO->values.memory.dll	= (bd->pins[115] & 0x02) != 0;
+	MINFO->values.memory.emrswen	= (bd->pins[115] & 0x01) != 0;
+	MINFO->values.reg.maccess	= MINFO->values.memory.emrswen ? 0x00004000 : 0x00000000;
+	if (bd->pins[115] & 4) {
+		MINFO->values.reg.mctlwtst_core = MINFO->values.reg.mctlwtst;
+	} else {
+		u_int32_t wtst_xlat[] = { 0, 1, 5, 6, 7, 5, 2, 3 };
+		MINFO->values.reg.mctlwtst_core = (MINFO->values.reg.mctlwtst & ~7) |
+		                                  wtst_xlat[MINFO->values.reg.mctlwtst & 7];
+	}
+	return 0;
+}
+
+static void default_pins5(WPMINFO2) {
+	/* Mine 16MB G450 with SDRAM DDR */
+	MINFO->limits.pixel.vcomax	=
+	MINFO->limits.system.vcomax	=
+	MINFO->limits.video.vcomax	= 600000;
+	MINFO->limits.pixel.vcomin	=
+	MINFO->limits.system.vcomin	=
+	MINFO->limits.video.vcomin	= 256000;
+	MINFO->values.pll.system	=
+	MINFO->values.pll.video		= 284000;
+	MINFO->values.reg.opt		= 0x404A1160;
+	MINFO->values.reg.opt2		= 0x0000AC00;
+	MINFO->values.reg.opt3		= 0x0090A409;
+	MINFO->values.reg.mctlwtst_core	=
+	MINFO->values.reg.mctlwtst	= 0x0C81462B;
+	MINFO->values.reg.memmisc	= 0x80000004;
+	MINFO->values.reg.memrdbk	= 0x01001103;
+	MINFO->features.pll.ref_freq	= 27000;
+	MINFO->values.memory.ddr	= 1;
+	MINFO->values.memory.dll	= 1;
+	MINFO->values.memory.emrswen	= 1;
+	MINFO->values.reg.maccess	= 0x00004000;
+}
+
+static int matroxfb_set_limits(WPMINFO const struct matrox_bios* bd) {
+	unsigned int pins_version;
+	static const unsigned int pinslen[] = { 64, 64, 64, 128, 128 };
+
+	switch (ACCESS_FBINFO(chip)) {
+		case MGA_2064:	default_pins1(PMINFO2); break;
+		case MGA_2164:
+		case MGA_1064:
+		case MGA_1164:	default_pins2(PMINFO2); break;
+		case MGA_G100:
+		case MGA_G200:	default_pins3(PMINFO2); break;
+		case MGA_G400:	default_pins4(PMINFO2); break;
+		case MGA_G450:
+		case MGA_G550:	default_pins5(PMINFO2); break;
+	}
+	if (!bd->bios_valid) {
+		printk(KERN_INFO "matroxfb: Your Matrox device does not have BIOS\n");
+		return -1;
+	}
+	if (bd->pins_len < 64) {
+		printk(KERN_INFO "matroxfb: BIOS on your Matrox device does not contain powerup info\n");
+		return -1;
+	}
+	if (bd->pins[0] == 0x2E && bd->pins[1] == 0x41) {
+		pins_version = bd->pins[5];
+		if (pins_version < 2 || pins_version > 5) {
+			printk(KERN_INFO "matroxfb: Unknown version (%u) of powerup info\n", pins_version);
+			return -1;
+		}
+	} else {
+		pins_version = 1;
+	}
+	if (bd->pins_len != pinslen[pins_version - 1]) {
+		printk(KERN_INFO "matroxfb: Invalid powerup info\n");
+		return -1;
+	}
+	switch (pins_version) {
+		case 1:
+			return parse_pins1(PMINFO bd);
+		case 2:
+			return parse_pins2(PMINFO bd);
+		case 3:
+			return parse_pins3(PMINFO bd);
+		case 4:
+			return parse_pins4(PMINFO bd);
+		case 5:
+			return parse_pins5(PMINFO bd);
+		default:
+			printk(KERN_DEBUG "matroxfb: Powerup info version %u is not yet supported\n", pins_version);
+			return -1;
+	}
+}
+
+void matroxfb_read_pins(WPMINFO2) {
+	u32 opt;
+	u32 biosbase;
+	u32 fbbase;
+	struct pci_dev* pdev = ACCESS_FBINFO(pcidev);
+	
+	memset(&ACCESS_FBINFO(bios), 0, sizeof(ACCESS_FBINFO(bios)));
+	pci_read_config_dword(pdev, PCI_OPTION_REG, &opt);
+	pci_write_config_dword(pdev, PCI_OPTION_REG, opt | PCI_OPTION_ENABLE_ROM);
+	pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &biosbase);
+	pci_read_config_dword(pdev, ACCESS_FBINFO(devflags.fbResource), &fbbase);
+	pci_write_config_dword(pdev, PCI_ROM_ADDRESS, (fbbase & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
+	parse_bios(vaddr_va(ACCESS_FBINFO(video).vbase), &ACCESS_FBINFO(bios));
+	pci_write_config_dword(pdev, PCI_ROM_ADDRESS, biosbase);
+	pci_write_config_dword(pdev, PCI_OPTION_REG, opt);
+#ifdef CONFIG_X86
+	if (!ACCESS_FBINFO(bios).bios_valid) {
+		unsigned char __iomem* b;
+
+		b = ioremap(0x000C0000, 65536);
+		if (!b) {
+			printk(KERN_INFO "matroxfb: Unable to map legacy BIOS\n");
+		} else {
+			unsigned int ven = readb(b+0x64+0) | (readb(b+0x64+1) << 8);
+			unsigned int dev = readb(b+0x64+2) | (readb(b+0x64+3) << 8);
+			
+			if (ven != pdev->vendor || dev != pdev->device) {
+				printk(KERN_INFO "matroxfb: Legacy BIOS is for %04X:%04X, while this device is %04X:%04X\n",
+					ven, dev, pdev->vendor, pdev->device);
+			} else {
+				parse_bios(b, &ACCESS_FBINFO(bios));
+			}
+			iounmap(b);
+		}
+	}
+#endif
+	matroxfb_set_limits(PMINFO &ACCESS_FBINFO(bios));
+}
+
+EXPORT_SYMBOL(matroxfb_DAC_in);
+EXPORT_SYMBOL(matroxfb_DAC_out);
+EXPORT_SYMBOL(matroxfb_var2my);
+EXPORT_SYMBOL(matroxfb_PLL_calcclock);
+#ifndef CONFIG_FB_MATROX_MULTIHEAD
+struct matrox_fb_info matroxfb_global_mxinfo;
+EXPORT_SYMBOL(matroxfb_global_mxinfo);
+#endif
+EXPORT_SYMBOL(matroxfb_vgaHWinit);		/* DAC1064, Ti3026 */
+EXPORT_SYMBOL(matroxfb_vgaHWrestore);		/* DAC1064, Ti3026 */
+EXPORT_SYMBOL(matroxfb_read_pins);
+
+MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Miscellaneous support for Matrox video cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/matrox/matroxfb_misc.h b/drivers/video/matrox/matroxfb_misc.h
new file mode 100644
index 0000000..cb62cc0
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_misc.h
@@ -0,0 +1,18 @@
+#ifndef __MATROXFB_MISC_H__
+#define __MATROXFB_MISC_H__
+
+#include "matroxfb_base.h"
+
+/* also for modules */
+int matroxfb_PLL_calcclock(const struct matrox_pll_features* pll, unsigned int freq, unsigned int fmax,
+	unsigned int* in, unsigned int* feed, unsigned int* post);
+static inline int PLL_calcclock(CPMINFO unsigned int freq, unsigned int fmax,
+		unsigned int* in, unsigned int* feed, unsigned int* post) {
+	return matroxfb_PLL_calcclock(&ACCESS_FBINFO(features.pll), freq, fmax, in, feed, post);
+}
+
+int matroxfb_vgaHWinit(WPMINFO struct my_timming* m);
+void matroxfb_vgaHWrestore(WPMINFO2);
+void matroxfb_read_pins(WPMINFO2);
+
+#endif	/* __MATROXFB_MISC_H__ */
diff --git a/drivers/video/maxinefb.c b/drivers/video/maxinefb.c
new file mode 100644
index 0000000..f192d99
--- /dev/null
+++ b/drivers/video/maxinefb.c
@@ -0,0 +1,180 @@
+/*
+ *      linux/drivers/video/maxinefb.c
+ *
+ *	DECstation 5000/xx onboard framebuffer support ... derived from:
+ *	"HP300 Topcat framebuffer support (derived from macfb of all things)
+ *	Phil Blundell <philb@gnu.org> 1998", the original code can be
+ *      found in the file hpfb.c in the same directory.
+ *
+ *      DECstation related code Copyright (C) 1999,2000,2001 by
+ *      Michael Engel <engel@unix-ag.org> and
+ *      Karsten Merker <merker@linuxtag.org>.
+ *      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.
+ *
+ */
+
+/*
+ * Changes:
+ * 2001/01/27 removed debugging and testing code, fixed fb_ops
+ *            initialization which had caused a crash before,
+ *            general cleanup, first official release (KM)
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <video/maxinefb.h>
+
+/* bootinfo.h defines the machine type values, needed when checking */
+/* whether are really running on a maxine, KM                       */
+#include <asm/bootinfo.h>
+
+static struct fb_info fb_info;
+
+static struct fb_var_screeninfo maxinefb_defined = {
+	.xres =		1024,
+	.yres =		768,
+	.xres_virtual =	1024,
+	.yres_virtual =	768,
+	.bits_per_pixel =8,
+	.activate =	FB_ACTIVATE_NOW,
+	.height =	-1,
+	.width =	-1,
+	.vmode =	FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_fix_screeninfo maxinefb_fix = {
+	.id =		"Maxine onboard graphics 1024x768x8",
+	.smem_len =	(1024*768),
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_PSEUDOCOLOR,
+	.line_length =	1024,
+};
+
+/* Handle the funny Inmos RamDAC/video controller ... */
+
+void maxinefb_ims332_write_register(int regno, register unsigned int val)
+{
+	register unsigned char *regs = (char *) MAXINEFB_IMS332_ADDRESS;
+	unsigned char *wptr;
+
+	wptr = regs + 0xa0000 + (regno << 4);
+	*((volatile unsigned int *) (regs)) = (val >> 8) & 0xff00;
+	*((volatile unsigned short *) (wptr)) = val;
+}
+
+unsigned int maxinefb_ims332_read_register(int regno)
+{
+	register unsigned char *regs = (char *) MAXINEFB_IMS332_ADDRESS;
+	unsigned char *rptr;
+	register unsigned int j, k;
+
+	rptr = regs + 0x80000 + (regno << 4);
+	j = *((volatile unsigned short *) rptr);
+	k = *((volatile unsigned short *) regs);
+
+	return (j & 0xffff) | ((k & 0xff00) << 8);
+}
+
+/* Set the palette */
+static int maxinefb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			      unsigned blue, unsigned transp, struct fb_info *info)
+{
+	/* value to be written into the palette reg. */
+	unsigned long hw_colorvalue = 0;
+
+	red   >>= 8;    /* The cmap fields are 16 bits    */
+	green >>= 8;    /* wide, but the harware colormap */
+	blue  >>= 8;    /* registers are only 8 bits wide */
+
+	hw_colorvalue = (blue << 16) + (green << 8) + (red);
+
+	maxinefb_ims332_write_register(IMS332_REG_COLOR_PALETTE + regno,
+				       hw_colorvalue);
+	return 0;
+}
+
+static struct fb_ops maxinefb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_get_fix	= gen_get_fix,
+	.fb_get_var	= gen_get_var,
+	.fb_setcolreg	= maxinefb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+int __init maxinefb_init(void)
+{
+	unsigned long fboff;
+	unsigned long fb_start;
+	int i;
+
+	if (fb_get_options("maxinefb", NULL))
+		return -ENODEV;
+
+	/* Validate we're on the proper machine type */
+	if (mips_machtype != MACH_DS5000_XX) {
+		return -EINVAL;
+	}
+
+	printk(KERN_INFO "Maxinefb: Personal DECstation detected\n");
+	printk(KERN_INFO "Maxinefb: initializing onboard framebuffer\n");
+
+	/* Framebuffer display memory base address */
+	fb_start = DS5000_xx_ONBOARD_FBMEM_START;
+
+	/* Clear screen */
+	for (fboff = fb_start; fboff < fb_start + 0x1ffff; fboff++)
+		*(volatile unsigned char *)fboff = 0x0;
+
+	maxinefb_fix.smem_start = fb_start;
+	
+	/* erase hardware cursor */
+	for (i = 0; i < 512; i++) {
+		maxinefb_ims332_write_register(IMS332_REG_CURSOR_RAM + i,
+					       0);
+		/*
+		   if (i&0x8 == 0)
+		   maxinefb_ims332_write_register (IMS332_REG_CURSOR_RAM + i, 0x0f);
+		   else
+		   maxinefb_ims332_write_register (IMS332_REG_CURSOR_RAM + i, 0xf0);
+		 */
+	}
+
+	fb_info.fbops = &maxinefb_ops;
+	fb_info.screen_base = (char *)maxinefb_fix.smem_start;
+	fb_info.var = maxinefb_defined;
+	fb_info.fix = maxinefb_fix;
+	fb_info.flags = FBINFO_DEFAULT;
+
+	fb_alloc_cmap(&fb_info.cmap, 256, 0);
+
+	if (register_framebuffer(&fb_info) < 0)
+		return 1;
+	return 0;
+}
+
+static void __exit maxinefb_exit(void)
+{
+	unregister_framebuffer(&fb_info);
+}
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+#endif
+module_init(maxinefb_init);
+module_exit(maxinefb_exit);
+
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
new file mode 100644
index 0000000..fbf659b
--- /dev/null
+++ b/drivers/video/modedb.c
@@ -0,0 +1,892 @@
+/*
+ *  linux/drivers/video/modedb.c -- Standard video mode database management
+ *
+ *	Copyright (C) 1999 Geert Uytterhoeven
+ *
+ *	2001 - Documented with DocBook
+ *	- Brad Douglas <brad@neruo.com>
+ *
+ *  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/module.h>
+#include <linux/tty.h>
+#include <linux/fb.h>
+#include <linux/sched.h>
+
+#undef DEBUG
+
+#define name_matches(v, s, l) \
+    ((v).name && !strncmp((s), (v).name, (l)) && strlen((v).name) == (l))
+#define res_matches(v, x, y) \
+    ((v).xres == (x) && (v).yres == (y))
+
+#ifdef DEBUG
+#define DPRINTK(fmt, args...)	printk("modedb %s: " fmt, __FUNCTION__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+const char *global_mode_option;
+
+    /*
+     *  Standard video mode definitions (taken from XFree86)
+     */
+
+#define DEFAULT_MODEDB_INDEX	0
+
+static const struct fb_videomode modedb[] = {
+    {
+	/* 640x400 @ 70 Hz, 31.5 kHz hsync */
+	NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 640x480 @ 60 Hz, 31.5 kHz hsync */
+	NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 800x600 @ 56 Hz, 35.15 kHz hsync */
+	NULL, 56, 800, 600, 27777, 128, 24, 22, 1, 72, 2,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1024x768 @ 87 Hz interlaced, 35.5 kHz hsync */
+	NULL, 87, 1024, 768, 22271, 56, 24, 33, 8, 160, 8,
+	0, FB_VMODE_INTERLACED
+    }, {
+	/* 640x400 @ 85 Hz, 37.86 kHz hsync */
+	NULL, 85, 640, 400, 31746, 96, 32, 41, 1, 64, 3,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }, {
+	/* 640x480 @ 72 Hz, 36.5 kHz hsync */
+	NULL, 72, 640, 480, 31746, 144, 40, 30, 8, 40, 3,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 640x480 @ 75 Hz, 37.50 kHz hsync */
+	NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 800x600 @ 60 Hz, 37.8 kHz hsync */
+	NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }, {
+	/* 640x480 @ 85 Hz, 43.27 kHz hsync */
+	NULL, 85, 640, 480, 27777, 80, 56, 25, 1, 56, 3,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1152x864 @ 89 Hz interlaced, 44 kHz hsync */
+	NULL, 69, 1152, 864, 15384, 96, 16, 110, 1, 216, 10,
+	0, FB_VMODE_INTERLACED
+    }, {
+	/* 800x600 @ 72 Hz, 48.0 kHz hsync */
+	NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1024x768 @ 60 Hz, 48.4 kHz hsync */
+	NULL, 60, 1024, 768, 15384, 168, 8, 29, 3, 144, 6,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 640x480 @ 100 Hz, 53.01 kHz hsync */
+	NULL, 100, 640, 480, 21834, 96, 32, 36, 8, 96, 6,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1152x864 @ 60 Hz, 53.5 kHz hsync */
+	NULL, 60, 1152, 864, 11123, 208, 64, 16, 4, 256, 8,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 800x600 @ 85 Hz, 55.84 kHz hsync */
+	NULL, 85, 800, 600, 16460, 160, 64, 36, 16, 64, 5,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1024x768 @ 70 Hz, 56.5 kHz hsync */
+	NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1280x1024 @ 87 Hz interlaced, 51 kHz hsync */
+	NULL, 87, 1280, 1024, 12500, 56, 16, 128, 1, 216, 12,
+	0, FB_VMODE_INTERLACED
+    }, {
+	/* 800x600 @ 100 Hz, 64.02 kHz hsync */
+	NULL, 100, 800, 600, 14357, 160, 64, 30, 4, 64, 6,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1024x768 @ 76 Hz, 62.5 kHz hsync */
+	NULL, 76, 1024, 768, 11764, 208, 8, 36, 16, 120, 3,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1152x864 @ 70 Hz, 62.4 kHz hsync */
+	NULL, 70, 1152, 864, 10869, 106, 56, 20, 1, 160, 10,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1280x1024 @ 61 Hz, 64.2 kHz hsync */
+	NULL, 61, 1280, 1024, 9090, 200, 48, 26, 1, 184, 3,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1400x1050 @ 60Hz, 63.9 kHz hsync */
+	NULL, 68, 1400, 1050, 9259, 136, 40, 13, 1, 112, 3,
+	0, FB_VMODE_NONINTERLACED   	
+    }, {
+	/* 1400x1050 @ 75,107 Hz, 82,392 kHz +hsync +vsync*/
+	NULL, 75, 1400, 1050, 9271, 120, 56, 13, 0, 112, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1400x1050 @ 60 Hz, ? kHz +hsync +vsync*/
+        NULL, 60, 1400, 1050, 9259, 128, 40, 12, 0, 112, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1024x768 @ 85 Hz, 70.24 kHz hsync */
+	NULL, 85, 1024, 768, 10111, 192, 32, 34, 14, 160, 6,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1152x864 @ 78 Hz, 70.8 kHz hsync */
+	NULL, 78, 1152, 864, 9090, 228, 88, 32, 0, 84, 12,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1280x1024 @ 70 Hz, 74.59 kHz hsync */
+	NULL, 70, 1280, 1024, 7905, 224, 32, 28, 8, 160, 8,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1600x1200 @ 60Hz, 75.00 kHz hsync */
+	NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1152x864 @ 84 Hz, 76.0 kHz hsync */
+	NULL, 84, 1152, 864, 7407, 184, 312, 32, 0, 128, 12,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1280x1024 @ 74 Hz, 78.85 kHz hsync */
+	NULL, 74, 1280, 1024, 7407, 256, 32, 34, 3, 144, 3,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1024x768 @ 100Hz, 80.21 kHz hsync */
+	NULL, 100, 1024, 768, 8658, 192, 32, 21, 3, 192, 10,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1280x1024 @ 76 Hz, 81.13 kHz hsync */
+	NULL, 76, 1280, 1024, 7407, 248, 32, 34, 3, 104, 3,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1600x1200 @ 70 Hz, 87.50 kHz hsync */
+	NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1152x864 @ 100 Hz, 89.62 kHz hsync */
+	NULL, 100, 1152, 864, 7264, 224, 32, 17, 2, 128, 19,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1280x1024 @ 85 Hz, 91.15 kHz hsync */
+	NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1600x1200 @ 75 Hz, 93.75 kHz hsync */
+	NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1600x1200 @ 85 Hz, 105.77 kHz hsync */
+	NULL, 85, 1600, 1200, 4545, 272, 16, 37, 4, 192, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1280x1024 @ 100 Hz, 107.16 kHz hsync */
+	NULL, 100, 1280, 1024, 5502, 256, 32, 26, 7, 128, 15,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1800x1440 @ 64Hz, 96.15 kHz hsync  */
+	NULL, 64, 1800, 1440, 4347, 304, 96, 46, 1, 192, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1800x1440 @ 70Hz, 104.52 kHz hsync  */
+	NULL, 70, 1800, 1440, 4000, 304, 96, 46, 1, 192, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }, {
+	/* 512x384 @ 78 Hz, 31.50 kHz hsync */
+	NULL, 78, 512, 384, 49603, 48, 16, 16, 1, 64, 3,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 512x384 @ 85 Hz, 34.38 kHz hsync */
+	NULL, 85, 512, 384, 45454, 48, 16, 16, 1, 64, 3,
+	0, FB_VMODE_NONINTERLACED
+    }, {
+	/* 320x200 @ 70 Hz, 31.5 kHz hsync, 8:5 aspect ratio */
+	NULL, 70, 320, 200, 79440, 16, 16, 20, 4, 48, 1,
+	0, FB_VMODE_DOUBLE
+    }, {
+	/* 320x240 @ 60 Hz, 31.5 kHz hsync, 4:3 aspect ratio */
+	NULL, 60, 320, 240, 79440, 16, 16, 16, 5, 48, 1,
+	0, FB_VMODE_DOUBLE
+    }, {
+	/* 320x240 @ 72 Hz, 36.5 kHz hsync */
+	NULL, 72, 320, 240, 63492, 16, 16, 16, 4, 48, 2,
+	0, FB_VMODE_DOUBLE
+    }, {
+	/* 400x300 @ 56 Hz, 35.2 kHz hsync, 4:3 aspect ratio */
+	NULL, 56, 400, 300, 55555, 64, 16, 10, 1, 32, 1,
+	0, FB_VMODE_DOUBLE
+    }, {
+	/* 400x300 @ 60 Hz, 37.8 kHz hsync */
+	NULL, 60, 400, 300, 50000, 48, 16, 11, 1, 64, 2,
+	0, FB_VMODE_DOUBLE
+    }, {
+	/* 400x300 @ 72 Hz, 48.0 kHz hsync */
+	NULL, 72, 400, 300, 40000, 32, 24, 11, 19, 64, 3,
+	0, FB_VMODE_DOUBLE
+    }, {
+	/* 480x300 @ 56 Hz, 35.2 kHz hsync, 8:5 aspect ratio */
+	NULL, 56, 480, 300, 46176, 80, 16, 10, 1, 40, 1,
+	0, FB_VMODE_DOUBLE
+    }, {
+	/* 480x300 @ 60 Hz, 37.8 kHz hsync */
+	NULL, 60, 480, 300, 41858, 56, 16, 11, 1, 80, 2,
+	0, FB_VMODE_DOUBLE
+    }, {
+	/* 480x300 @ 63 Hz, 39.6 kHz hsync */
+	NULL, 63, 480, 300, 40000, 56, 16, 11, 1, 80, 2,
+	0, FB_VMODE_DOUBLE
+    }, {
+	/* 480x300 @ 72 Hz, 48.0 kHz hsync */
+	NULL, 72, 480, 300, 33386, 40, 24, 11, 19, 80, 3,
+	0, FB_VMODE_DOUBLE
+    },
+};
+
+#ifdef CONFIG_FB_MODE_HELPERS
+const struct fb_videomode vesa_modes[] = {
+	/* 0 640x350-85 VESA */
+	{ NULL, 85, 640, 350, 31746,  96, 32, 60, 32, 64, 3,
+	  FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA},
+	/* 1 640x400-85 VESA */
+	{ NULL, 85, 640, 400, 31746,  96, 32, 41, 01, 64, 3,
+	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 2 720x400-85 VESA */
+	{ NULL, 85, 721, 400, 28169, 108, 36, 42, 01, 72, 3,
+	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 3 640x480-60 VESA */
+	{ NULL, 60, 640, 480, 39682,  48, 16, 33, 10, 96, 2, 
+	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 4 640x480-72 VESA */
+	{ NULL, 72, 640, 480, 31746, 128, 24, 29, 9, 40, 2, 
+	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 5 640x480-75 VESA */
+	{ NULL, 75, 640, 480, 31746, 120, 16, 16, 01, 64, 3,
+	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 6 640x480-85 VESA */
+	{ NULL, 85, 640, 480, 27777, 80, 56, 25, 01, 56, 3,
+	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 7 800x600-56 VESA */
+	{ NULL, 56, 800, 600, 27777, 128, 24, 22, 01, 72, 2,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 8 800x600-60 VESA */
+	{ NULL, 60, 800, 600, 25000, 88, 40, 23, 01, 128, 4,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 9 800x600-72 VESA */
+	{ NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 10 800x600-75 VESA */
+	{ NULL, 75, 800, 600, 20202, 160, 16, 21, 01, 80, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 11 800x600-85 VESA */
+	{ NULL, 85, 800, 600, 17761, 152, 32, 27, 01, 64, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+        /* 12 1024x768i-43 VESA */
+	{ NULL, 53, 1024, 768, 22271, 56, 8, 41, 0, 176, 8,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_INTERLACED, FB_MODE_IS_VESA },
+	/* 13 1024x768-60 VESA */
+	{ NULL, 60, 1024, 768, 15384, 160, 24, 29, 3, 136, 6,
+	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 14 1024x768-70 VESA */
+	{ NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6,
+	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 15 1024x768-75 VESA */
+	{ NULL, 75, 1024, 768, 12690, 176, 16, 28, 1, 96, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 16 1024x768-85 VESA */
+	{ NULL, 85, 1024, 768, 10582, 208, 48, 36, 1, 96, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 17 1152x864-75 VESA */
+	{ NULL, 75, 1153, 864, 9259, 256, 64, 32, 1, 128, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 18 1280x960-60 VESA */
+	{ NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 19 1280x960-85 VESA */
+	{ NULL, 85, 1280, 960, 6734, 224, 64, 47, 1, 160, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 20 1280x1024-60 VESA */
+	{ NULL, 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 21 1280x1024-75 VESA */
+	{ NULL, 75, 1280, 1024, 7407, 248, 16, 38, 1, 144, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 22 1280x1024-85 VESA */
+	{ NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 23 1600x1200-60 VESA */
+	{ NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 24 1600x1200-65 VESA */
+	{ NULL, 65, 1600, 1200, 5698, 304,  64, 46, 1, 192, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 25 1600x1200-70 VESA */
+	{ NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 26 1600x1200-75 VESA */
+	{ NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, 
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 27 1600x1200-85 VESA */
+	{ NULL, 85, 1600, 1200, 4357, 304, 64, 46, 1, 192, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 28 1792x1344-60 VESA */
+	{ NULL, 60, 1792, 1344, 4882, 328, 128, 46, 1, 200, 3,
+	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 29 1792x1344-75 VESA */
+	{ NULL, 75, 1792, 1344, 3831, 352, 96, 69, 1, 216, 3,
+	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 30 1856x1392-60 VESA */
+	{ NULL, 60, 1856, 1392, 4580, 352, 96, 43, 1, 224, 3,
+	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 31 1856x1392-75 VESA */
+	{ NULL, 75, 1856, 1392, 3472, 352, 128, 104, 1, 224, 3,
+	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 32 1920x1440-60 VESA */
+	{ NULL, 60, 1920, 1440, 4273, 344, 128, 56, 1, 200, 3,
+	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+	/* 33 1920x1440-75 VESA */
+	{ NULL, 60, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3,
+	  FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+};
+EXPORT_SYMBOL(vesa_modes);
+#endif /* CONFIG_FB_MODE_HELPERS */
+
+static int my_atoi(const char *name)
+{
+    int val = 0;
+
+    for (;; name++) {
+	switch (*name) {
+	    case '0'...'9':
+		val = 10*val+(*name-'0');
+		break;
+	    default:
+		return val;
+	}
+    }
+}
+
+/**
+ *	fb_try_mode - test a video mode
+ *	@var: frame buffer user defined part of display
+ *	@info: frame buffer info structure
+ *	@mode: frame buffer video mode structure
+ *	@bpp: color depth in bits per pixel
+ *
+ *	Tries a video mode to test it's validity for device @info.
+ *
+ *	Returns 1 on success.
+ *
+ */
+
+static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info,
+		       const struct fb_videomode *mode, unsigned int bpp)
+{
+    int err = 0;
+
+    DPRINTK("Trying mode %s %dx%d-%d@%d\n", mode->name ? mode->name : "noname",
+	    mode->xres, mode->yres, bpp, mode->refresh);
+    var->xres = mode->xres;
+    var->yres = mode->yres;
+    var->xres_virtual = mode->xres;
+    var->yres_virtual = mode->yres;
+    var->xoffset = 0;
+    var->yoffset = 0;
+    var->bits_per_pixel = bpp;
+    var->activate |= FB_ACTIVATE_TEST;
+    var->pixclock = mode->pixclock;
+    var->left_margin = mode->left_margin;
+    var->right_margin = mode->right_margin;
+    var->upper_margin = mode->upper_margin;
+    var->lower_margin = mode->lower_margin;
+    var->hsync_len = mode->hsync_len;
+    var->vsync_len = mode->vsync_len;
+    var->sync = mode->sync;
+    var->vmode = mode->vmode;
+    if (info->fbops->fb_check_var)
+    	err = info->fbops->fb_check_var(var, info);
+    var->activate &= ~FB_ACTIVATE_TEST;
+    return err;
+}
+
+/**
+ *	fb_find_mode - finds a valid video mode
+ *	@var: frame buffer user defined part of display
+ *	@info: frame buffer info structure
+ *	@mode_option: string video mode to find
+ *	@db: video mode database
+ *	@dbsize: size of @db
+ *	@default_mode: default video mode to fall back to
+ *	@default_bpp: default color depth in bits per pixel
+ *
+ *	Finds a suitable video mode, starting with the specified mode
+ *	in @mode_option with fallback to @default_mode.  If
+ *	@default_mode fails, all modes in the video mode database will
+ *	be tried.
+ *
+ *	Valid mode specifiers for @mode_option:
+ *
+ *	<xres>x<yres>[-<bpp>][@<refresh>] or
+ *	<name>[-<bpp>][@<refresh>]
+ *
+ *	with <xres>, <yres>, <bpp> and <refresh> decimal numbers and
+ *	<name> a string.
+ *
+ *	NOTE: The passed struct @var is _not_ cleared!  This allows you
+ *	to supply values for e.g. the grayscale and accel_flags fields.
+ *
+ *	Returns zero for failure, 1 if using specified @mode_option,
+ *	2 if using specified @mode_option with an ignored refresh rate,
+ *	3 if default mode is used, 4 if fall back to any valid mode.
+ *
+ */
+
+int fb_find_mode(struct fb_var_screeninfo *var,
+		 struct fb_info *info, const char *mode_option,
+		 const struct fb_videomode *db, unsigned int dbsize,
+		 const struct fb_videomode *default_mode,
+		 unsigned int default_bpp)
+{
+    int i;
+
+    /* Set up defaults */
+    if (!db) {
+	db = modedb;
+	dbsize = sizeof(modedb)/sizeof(*modedb);
+    }
+    if (!default_mode)
+	default_mode = &modedb[DEFAULT_MODEDB_INDEX];
+    if (!default_bpp)
+	default_bpp = 8;
+
+    /* Did the user specify a video mode? */
+    if (mode_option || (mode_option = global_mode_option)) {
+	const char *name = mode_option;
+	unsigned int namelen = strlen(name);
+	int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
+	unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0;
+	int yres_specified = 0;
+	u32 best, diff;
+
+	for (i = namelen-1; i >= 0; i--) {
+	    switch (name[i]) {
+		case '@':
+		    namelen = i;
+		    if (!refresh_specified && !bpp_specified &&
+			!yres_specified) {
+			refresh = my_atoi(&name[i+1]);
+			refresh_specified = 1;
+		    } else
+			goto done;
+		    break;
+		case '-':
+		    namelen = i;
+		    if (!bpp_specified && !yres_specified) {
+			bpp = my_atoi(&name[i+1]);
+			bpp_specified = 1;
+		    } else
+			goto done;
+		    break;
+		case 'x':
+		    if (!yres_specified) {
+			yres = my_atoi(&name[i+1]);
+			yres_specified = 1;
+		    } else
+			goto done;
+		    break;
+		case '0'...'9':
+		    break;
+		default:
+		    goto done;
+	    }
+	}
+	if (i < 0 && yres_specified) {
+	    xres = my_atoi(name);
+	    res_specified = 1;
+	}
+done:
+	DPRINTK("Trying specified video mode%s %ix%i\n",
+	    refresh_specified ? "" : " (ignoring refresh rate)", xres, yres);
+
+	diff = refresh;
+	best = -1;
+	for (i = 0; i < dbsize; i++) {
+		if ((name_matches(db[i], name, namelen) &&
+			!fb_try_mode(var, info, &db[i], bpp)))
+			return 1;
+		if (res_specified && res_matches(db[i], xres, yres)) {
+			if(!fb_try_mode(var, info, &db[i], bpp)) {
+				if(!refresh_specified || db[i].refresh == refresh)
+					return 1;
+				else {
+					if(diff > abs(db[i].refresh - refresh)) {
+						diff = abs(db[i].refresh - refresh);
+						best = i;
+					}
+				}
+			}
+		}
+	}
+	if (best != -1) {
+		fb_try_mode(var, info, &db[best], bpp);
+		return 2;
+	}
+
+	diff = xres + yres;
+	best = -1;
+	DPRINTK("Trying best-fit modes\n");
+	for (i = 0; i < dbsize; i++) {
+	    if (xres <= db[i].xres && yres <= db[i].yres) {
+		DPRINTK("Trying %ix%i\n", db[i].xres, db[i].yres);
+		if (!fb_try_mode(var, info, &db[i], bpp)) {
+		    if (diff > (db[i].xres - xres) + (db[i].yres - yres)) {
+			diff = (db[i].xres - xres) + (db[i].yres - yres);
+			best = i;
+		    }
+		}
+	    }
+	}
+	if (best != -1) {
+	    fb_try_mode(var, info, &db[best], bpp);
+	    return 5;
+	}
+    }
+
+    DPRINTK("Trying default video mode\n");
+    if (!fb_try_mode(var, info, default_mode, default_bpp))
+	return 3;
+
+    DPRINTK("Trying all modes\n");
+    for (i = 0; i < dbsize; i++)
+	if (!fb_try_mode(var, info, &db[i], default_bpp))
+	    return 4;
+
+    DPRINTK("No valid mode found\n");
+    return 0;
+}
+
+/**
+ * fb_var_to_videomode - convert fb_var_screeninfo to fb_videomode
+ * @mode: pointer to struct fb_videomode
+ * @var: pointer to struct fb_var_screeninfo
+ */
+void fb_var_to_videomode(struct fb_videomode *mode,
+			 struct fb_var_screeninfo *var)
+{
+	u32 pixclock, hfreq, htotal, vtotal;
+
+	mode->name = NULL;
+	mode->xres = var->xres;
+	mode->yres = var->yres;
+	mode->pixclock = var->pixclock;
+	mode->hsync_len = var->hsync_len;
+	mode->vsync_len = var->vsync_len;
+	mode->left_margin = var->left_margin;
+	mode->right_margin = var->right_margin;
+	mode->upper_margin = var->upper_margin;
+	mode->lower_margin = var->lower_margin;
+	mode->sync = var->sync;
+	mode->vmode = var->vmode & FB_VMODE_MASK;
+	mode->flag = FB_MODE_IS_FROM_VAR;
+	if (!var->pixclock)
+		return;
+
+	pixclock = PICOS2KHZ(var->pixclock) * 1000;
+
+	htotal = var->xres + var->right_margin + var->hsync_len +
+		var->left_margin;
+	vtotal = var->yres + var->lower_margin + var->vsync_len +
+		var->upper_margin;
+
+	if (var->vmode & FB_VMODE_INTERLACED)
+		vtotal /= 2;
+	if (var->vmode & FB_VMODE_DOUBLE)
+		vtotal *= 2;
+
+	hfreq = pixclock/htotal;
+	mode->refresh = hfreq/vtotal;
+}
+
+/**
+ * fb_videomode_to_var - convert fb_videomode to fb_var_screeninfo
+ * @var: pointer to struct fb_var_screeninfo
+ * @mode: pointer to struct fb_videomode
+ */
+void fb_videomode_to_var(struct fb_var_screeninfo *var,
+			       struct fb_videomode *mode)
+{
+	var->xres = mode->xres;
+	var->yres = mode->yres;
+	var->pixclock = mode->pixclock;
+	var->left_margin = mode->left_margin;
+	var->hsync_len = mode->hsync_len;
+	var->vsync_len = mode->vsync_len;
+	var->right_margin = mode->right_margin;
+	var->upper_margin = mode->upper_margin;
+	var->lower_margin = mode->lower_margin;
+	var->sync = mode->sync;
+	var->vmode = mode->vmode & FB_VMODE_MASK;
+}
+
+/**
+ * fb_mode_is_equal - compare 2 videomodes
+ * @mode1: first videomode
+ * @mode2: second videomode
+ *
+ * RETURNS:
+ * 1 if equal, 0 if not
+ */
+int fb_mode_is_equal(struct fb_videomode *mode1,
+		     struct fb_videomode *mode2)
+{
+	return (mode1->xres         == mode2->xres &&
+		mode1->yres         == mode2->yres &&
+		mode1->pixclock     == mode2->pixclock &&
+		mode1->hsync_len    == mode2->hsync_len &&
+		mode1->vsync_len    == mode2->vsync_len &&
+		mode1->left_margin  == mode2->left_margin &&
+		mode1->right_margin == mode2->right_margin &&
+		mode1->upper_margin == mode2->upper_margin &&
+		mode1->lower_margin == mode2->lower_margin &&
+		mode1->sync         == mode2->sync &&
+		mode1->vmode        == mode2->vmode);
+}
+
+/**
+ * fb_find_best_mode - find best matching videomode
+ * @var: pointer to struct fb_var_screeninfo
+ * @head: pointer to struct list_head of modelist
+ *
+ * RETURNS:
+ * struct fb_videomode, NULL if none found
+ *
+ * IMPORTANT:
+ * This function assumes that all modelist entries in
+ * info->modelist are valid.
+ *
+ * NOTES:
+ * Finds best matching videomode which has an equal or greater dimension than
+ * var->xres and var->yres.  If more than 1 videomode is found, will return
+ * the videomode with the highest refresh rate
+ */
+struct fb_videomode *fb_find_best_mode(struct fb_var_screeninfo *var,
+				       struct list_head *head)
+{
+	struct list_head *pos;
+	struct fb_modelist *modelist;
+	struct fb_videomode *mode, *best = NULL;
+	u32 diff = -1;
+
+	list_for_each(pos, head) {
+		u32 d;
+
+		modelist = list_entry(pos, struct fb_modelist, list);
+		mode = &modelist->mode;
+
+		if (mode->xres >= var->xres && mode->yres >= var->yres) {
+			d = (mode->xres - var->xres) +
+				(mode->yres - var->yres);
+			if (diff > d) {
+				diff = d;
+				best = mode;
+			} else if (diff == d && mode->refresh > best->refresh)
+			    best = mode;
+		}
+	}
+	return best;
+}
+
+/**
+ * fb_find_nearest_mode - find mode closest video mode
+ *
+ * @var: pointer to struct fb_var_screeninfo
+ * @head: pointer to modelist
+ *
+ * Finds best matching videomode, smaller or greater in dimension.
+ * If more than 1 videomode is found, will return the videomode with
+ * the closest refresh rate
+ */
+struct fb_videomode *fb_find_nearest_mode(struct fb_var_screeninfo *var,
+					  struct list_head *head)
+{
+	struct list_head *pos;
+	struct fb_modelist *modelist;
+	struct fb_videomode *mode, *best = NULL;
+	u32 diff = -1, diff_refresh = -1;
+
+	list_for_each(pos, head) {
+		u32 d;
+
+		modelist = list_entry(pos, struct fb_modelist, list);
+		mode = &modelist->mode;
+
+		d = abs(mode->xres - var->xres) +
+			abs(mode->yres - var->yres);
+		if (diff > d) {
+			diff = d;
+			best = mode;
+		} else if (diff == d) {
+			d = abs(mode->refresh - best->refresh);
+			if (diff_refresh > d) {
+				diff_refresh = d;
+				best = mode;
+			}
+		}
+	}
+
+	return best;
+}
+
+/**
+ * fb_match_mode - find a videomode which exactly matches the timings in var
+ * @var: pointer to struct fb_var_screeninfo
+ * @head: pointer to struct list_head of modelist
+ *
+ * RETURNS:
+ * struct fb_videomode, NULL if none found
+ */
+struct fb_videomode *fb_match_mode(struct fb_var_screeninfo *var,
+				   struct list_head *head)
+{
+	struct list_head *pos;
+	struct fb_modelist *modelist;
+	struct fb_videomode *m, mode;
+
+	fb_var_to_videomode(&mode, var);
+	list_for_each(pos, head) {
+		modelist = list_entry(pos, struct fb_modelist, list);
+		m = &modelist->mode;
+		if (fb_mode_is_equal(m, &mode))
+			return m;
+	}
+	return NULL;
+}
+
+/**
+ * fb_add_videomode: adds videomode entry to modelist
+ * @mode: videomode to add
+ * @head: struct list_head of modelist
+ *
+ * NOTES:
+ * Will only add unmatched mode entries
+ */
+int fb_add_videomode(struct fb_videomode *mode, struct list_head *head)
+{
+	struct list_head *pos;
+	struct fb_modelist *modelist;
+	struct fb_videomode *m;
+	int found = 0;
+
+	list_for_each(pos, head) {
+		modelist = list_entry(pos, struct fb_modelist, list);
+		m = &modelist->mode;
+		if (fb_mode_is_equal(m, mode)) {
+			found = 1;
+			break;
+		}
+	}
+	if (!found) {
+		modelist = kmalloc(sizeof(struct fb_modelist),
+						  GFP_KERNEL);
+
+		if (!modelist)
+			return -ENOMEM;
+		modelist->mode = *mode;
+		list_add(&modelist->list, head);
+	}
+	return 0;
+}
+
+/**
+ * fb_delete_videomode: removed videomode entry from modelist
+ * @mode: videomode to remove
+ * @head: struct list_head of modelist
+ *
+ * NOTES:
+ * Will remove all matching mode entries
+ */
+void fb_delete_videomode(struct fb_videomode *mode, struct list_head *head)
+{
+	struct list_head *pos, *n;
+	struct fb_modelist *modelist;
+	struct fb_videomode *m;
+
+	list_for_each_safe(pos, n, head) {
+		modelist = list_entry(pos, struct fb_modelist, list);
+		m = &modelist->mode;
+		if (fb_mode_is_equal(m, mode)) {
+			list_del(pos);
+			kfree(pos);
+		}
+	}
+}
+
+/**
+ * fb_destroy_modelist: destroy modelist
+ * @head: struct list_head of modelist
+ */
+void fb_destroy_modelist(struct list_head *head)
+{
+	struct list_head *pos, *n;
+
+	list_for_each_safe(pos, n, head) {
+		list_del(pos);
+		kfree(pos);
+	}
+}
+
+/**
+ * fb_videomode_to_modelist: convert mode array to mode list
+ * @modedb: array of struct fb_videomode
+ * @num: number of entries in array
+ * @head: struct list_head of modelist
+ */
+void fb_videomode_to_modelist(struct fb_videomode *modedb, int num,
+			      struct list_head *head)
+{
+	int i;
+
+	INIT_LIST_HEAD(head);
+
+	for (i = 0; i < num; i++) {
+		if (fb_add_videomode(&modedb[i], head))
+			return;
+	}
+}
+
+EXPORT_SYMBOL(fb_videomode_to_var);
+EXPORT_SYMBOL(fb_var_to_videomode);
+EXPORT_SYMBOL(fb_mode_is_equal);
+EXPORT_SYMBOL(fb_add_videomode);
+EXPORT_SYMBOL(fb_delete_videomode);
+EXPORT_SYMBOL(fb_destroy_modelist);
+EXPORT_SYMBOL(fb_match_mode);
+EXPORT_SYMBOL(fb_find_best_mode);
+EXPORT_SYMBOL(fb_find_nearest_mode);
+EXPORT_SYMBOL(fb_videomode_to_modelist);
+EXPORT_SYMBOL(fb_find_mode);
diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c
new file mode 100644
index 0000000..5d424a3
--- /dev/null
+++ b/drivers/video/neofb.c
@@ -0,0 +1,2315 @@
+/*
+ * linux/drivers/video/neofb.c -- NeoMagic Framebuffer Driver
+ *
+ * Copyright (c) 2001-2002  Denis Oliver Kropp <dok@directfb.org>
+ *
+ *
+ * Card specific code is based on XFree86's neomagic driver.
+ * Framebuffer framework code is based on code of cyber2000fb.
+ *
+ * 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.
+ *
+ *
+ * 0.4.1
+ *  - Cosmetic changes (dok)
+ *
+ * 0.4
+ *  - Toshiba Libretto support, allow modes larger than LCD size if
+ *    LCD is disabled, keep BIOS settings if internal/external display
+ *    haven't been enabled explicitly
+ *                          (Thomas J. Moore <dark@mama.indstate.edu>)
+ *
+ * 0.3.3
+ *  - Porting over to new fbdev api. (jsimmons)
+ *  
+ * 0.3.2
+ *  - got rid of all floating point (dok) 
+ *
+ * 0.3.1
+ *  - added module license (dok)
+ *
+ * 0.3
+ *  - hardware accelerated clear and move for 2200 and above (dok)
+ *  - maximum allowed dotclock is handled now (dok)
+ *
+ * 0.2.1
+ *  - correct panning after X usage (dok)
+ *  - added module and kernel parameters (dok)
+ *  - no stretching if external display is enabled (dok)
+ *
+ * 0.2
+ *  - initial version (dok)
+ *
+ *
+ * TODO
+ * - ioctl for internal/external switching
+ * - blanking
+ * - 32bit depth support, maybe impossible
+ * - disable pan-on-sync, need specs
+ *
+ * BUGS
+ * - white margin on bootup like with tdfxfb (colormap problem?)
+ *
+ */
+
+#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/delay.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#ifdef CONFIG_TOSHIBA
+#include <linux/toshiba.h>
+extern int tosh_smm(SMMRegisters *regs);
+#endif
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include <video/vga.h>
+#include <video/neomagic.h>
+
+#define NEOFB_VERSION "0.4.2"
+
+/* --------------------------------------------------------------------- */
+
+static int internal;
+static int external;
+static int libretto;
+static int nostretch;
+static int nopciburst;
+static char *mode_option __devinitdata = NULL;
+
+#ifdef MODULE
+
+MODULE_AUTHOR("(c) 2001-2002  Denis Oliver Kropp <dok@convergence.de>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("FBDev driver for NeoMagic PCI Chips");
+module_param(internal, bool, 0);
+MODULE_PARM_DESC(internal, "Enable output on internal LCD Display.");
+module_param(external, bool, 0);
+MODULE_PARM_DESC(external, "Enable output on external CRT.");
+module_param(libretto, bool, 0);
+MODULE_PARM_DESC(libretto, "Force Libretto 100/110 800x480 LCD.");
+module_param(nostretch, bool, 0);
+MODULE_PARM_DESC(nostretch,
+		 "Disable stretching of modes smaller than LCD.");
+module_param(nopciburst, bool, 0);
+MODULE_PARM_DESC(nopciburst, "Disable PCI burst mode.");
+module_param(mode_option, charp, 0);
+MODULE_PARM_DESC(mode_option, "Preferred video mode ('640x480-8@60', etc)");
+
+#endif
+
+
+/* --------------------------------------------------------------------- */
+
+static biosMode bios8[] = {
+	{320, 240, 0x40},
+	{300, 400, 0x42},
+	{640, 400, 0x20},
+	{640, 480, 0x21},
+	{800, 600, 0x23},
+	{1024, 768, 0x25},
+};
+
+static biosMode bios16[] = {
+	{320, 200, 0x2e},
+	{320, 240, 0x41},
+	{300, 400, 0x43},
+	{640, 480, 0x31},
+	{800, 600, 0x34},
+	{1024, 768, 0x37},
+};
+
+static biosMode bios24[] = {
+	{640, 480, 0x32},
+	{800, 600, 0x35},
+	{1024, 768, 0x38}
+};
+
+#ifdef NO_32BIT_SUPPORT_YET
+/* FIXME: guessed values, wrong */
+static biosMode bios32[] = {
+	{640, 480, 0x33},
+	{800, 600, 0x36},
+	{1024, 768, 0x39}
+};
+#endif
+
+static inline void write_le32(int regindex, u32 val, const struct neofb_par *par)
+{
+	writel(val, par->neo2200 + par->cursorOff + regindex);
+}
+
+static int neoFindMode(int xres, int yres, int depth)
+{
+	int xres_s;
+	int i, size;
+	biosMode *mode;
+
+	switch (depth) {
+	case 8:
+		size = sizeof(bios8) / sizeof(biosMode);
+		mode = bios8;
+		break;
+	case 16:
+		size = sizeof(bios16) / sizeof(biosMode);
+		mode = bios16;
+		break;
+	case 24:
+		size = sizeof(bios24) / sizeof(biosMode);
+		mode = bios24;
+		break;
+#ifdef NO_32BIT_SUPPORT_YET
+	case 32:
+		size = sizeof(bios32) / sizeof(biosMode);
+		mode = bios32;
+		break;
+#endif
+	default:
+		return 0;
+	}
+
+	for (i = 0; i < size; i++) {
+		if (xres <= mode[i].x_res) {
+			xres_s = mode[i].x_res;
+			for (; i < size; i++) {
+				if (mode[i].x_res != xres_s)
+					return mode[i - 1].mode;
+				if (yres <= mode[i].y_res)
+					return mode[i].mode;
+			}
+		}
+	}
+	return mode[size - 1].mode;
+}
+
+/*
+ * neoCalcVCLK --
+ *
+ * Determine the closest clock frequency to the one requested.
+ */
+#define REF_FREQ 0xe517		/* 14.31818 in 20.12 fixed point */
+#define MAX_N 127
+#define MAX_D 31
+#define MAX_F 1
+
+static void neoCalcVCLK(const struct fb_info *info,
+			struct neofb_par *par, long freq)
+{
+	int n, d, f;
+	int n_best = 0, d_best = 0, f_best = 0;
+	long f_best_diff = (0x7ffff << 12);	/* 20.12 */
+	long f_target = (freq << 12) / 1000;	/* 20.12 */
+
+	for (f = 0; f <= MAX_F; f++)
+		for (n = 0; n <= MAX_N; n++)
+			for (d = 0; d <= MAX_D; d++) {
+				long f_out;	/* 20.12 */
+				long f_diff;	/* 20.12 */
+
+				f_out =
+				    ((((n + 1) << 12) / ((d +
+							  1) *
+							 (1 << f))) >> 12)
+				    * REF_FREQ;
+				f_diff = abs(f_out - f_target);
+				if (f_diff < f_best_diff) {
+					f_best_diff = f_diff;
+					n_best = n;
+					d_best = d;
+					f_best = f;
+				}
+			}
+
+	if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 ||
+	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 ||
+	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 ||
+	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) {
+		/* NOT_DONE:  We are trying the full range of the 2200 clock.
+		   We should be able to try n up to 2047 */
+		par->VCLK3NumeratorLow = n_best;
+		par->VCLK3NumeratorHigh = (f_best << 7);
+	} else
+		par->VCLK3NumeratorLow = n_best | (f_best << 7);
+
+	par->VCLK3Denominator = d_best;
+
+#ifdef NEOFB_DEBUG
+	printk("neoVCLK: f:%d NumLow=%d NumHi=%d Den=%d Df=%d\n",
+	       f_target >> 12,
+	       par->VCLK3NumeratorLow,
+	       par->VCLK3NumeratorHigh,
+	       par->VCLK3Denominator, f_best_diff >> 12);
+#endif
+}
+
+/*
+ * vgaHWInit --
+ *      Handle the initialization, etc. of a screen.
+ *      Return FALSE on failure.
+ */
+
+static int vgaHWInit(const struct fb_var_screeninfo *var,
+		     const struct fb_info *info,
+		     struct neofb_par *par, struct xtimings *timings)
+{
+	par->MiscOutReg = 0x23;
+
+	if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT))
+		par->MiscOutReg |= 0x40;
+
+	if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT))
+		par->MiscOutReg |= 0x80;
+
+	/*
+	 * Time Sequencer
+	 */
+	par->Sequencer[0] = 0x00;
+	par->Sequencer[1] = 0x01;
+	par->Sequencer[2] = 0x0F;
+	par->Sequencer[3] = 0x00;	/* Font select */
+	par->Sequencer[4] = 0x0E;	/* Misc */
+
+	/*
+	 * CRTC Controller
+	 */
+	par->CRTC[0] = (timings->HTotal >> 3) - 5;
+	par->CRTC[1] = (timings->HDisplay >> 3) - 1;
+	par->CRTC[2] = (timings->HDisplay >> 3) - 1;
+	par->CRTC[3] = (((timings->HTotal >> 3) - 1) & 0x1F) | 0x80;
+	par->CRTC[4] = (timings->HSyncStart >> 3);
+	par->CRTC[5] = ((((timings->HTotal >> 3) - 1) & 0x20) << 2)
+	    | (((timings->HSyncEnd >> 3)) & 0x1F);
+	par->CRTC[6] = (timings->VTotal - 2) & 0xFF;
+	par->CRTC[7] = (((timings->VTotal - 2) & 0x100) >> 8)
+	    | (((timings->VDisplay - 1) & 0x100) >> 7)
+	    | ((timings->VSyncStart & 0x100) >> 6)
+	    | (((timings->VDisplay - 1) & 0x100) >> 5)
+	    | 0x10 | (((timings->VTotal - 2) & 0x200) >> 4)
+	    | (((timings->VDisplay - 1) & 0x200) >> 3)
+	    | ((timings->VSyncStart & 0x200) >> 2);
+	par->CRTC[8] = 0x00;
+	par->CRTC[9] = (((timings->VDisplay - 1) & 0x200) >> 4) | 0x40;
+
+	if (timings->dblscan)
+		par->CRTC[9] |= 0x80;
+
+	par->CRTC[10] = 0x00;
+	par->CRTC[11] = 0x00;
+	par->CRTC[12] = 0x00;
+	par->CRTC[13] = 0x00;
+	par->CRTC[14] = 0x00;
+	par->CRTC[15] = 0x00;
+	par->CRTC[16] = timings->VSyncStart & 0xFF;
+	par->CRTC[17] = (timings->VSyncEnd & 0x0F) | 0x20;
+	par->CRTC[18] = (timings->VDisplay - 1) & 0xFF;
+	par->CRTC[19] = var->xres_virtual >> 4;
+	par->CRTC[20] = 0x00;
+	par->CRTC[21] = (timings->VDisplay - 1) & 0xFF;
+	par->CRTC[22] = (timings->VTotal - 1) & 0xFF;
+	par->CRTC[23] = 0xC3;
+	par->CRTC[24] = 0xFF;
+
+	/*
+	 * are these unnecessary?
+	 * vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO);
+	 * vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO);
+	 */
+
+	/*
+	 * Graphics Display Controller
+	 */
+	par->Graphics[0] = 0x00;
+	par->Graphics[1] = 0x00;
+	par->Graphics[2] = 0x00;
+	par->Graphics[3] = 0x00;
+	par->Graphics[4] = 0x00;
+	par->Graphics[5] = 0x40;
+	par->Graphics[6] = 0x05;	/* only map 64k VGA memory !!!! */
+	par->Graphics[7] = 0x0F;
+	par->Graphics[8] = 0xFF;
+
+
+	par->Attribute[0] = 0x00;	/* standard colormap translation */
+	par->Attribute[1] = 0x01;
+	par->Attribute[2] = 0x02;
+	par->Attribute[3] = 0x03;
+	par->Attribute[4] = 0x04;
+	par->Attribute[5] = 0x05;
+	par->Attribute[6] = 0x06;
+	par->Attribute[7] = 0x07;
+	par->Attribute[8] = 0x08;
+	par->Attribute[9] = 0x09;
+	par->Attribute[10] = 0x0A;
+	par->Attribute[11] = 0x0B;
+	par->Attribute[12] = 0x0C;
+	par->Attribute[13] = 0x0D;
+	par->Attribute[14] = 0x0E;
+	par->Attribute[15] = 0x0F;
+	par->Attribute[16] = 0x41;
+	par->Attribute[17] = 0xFF;
+	par->Attribute[18] = 0x0F;
+	par->Attribute[19] = 0x00;
+	par->Attribute[20] = 0x00;
+	return 0;
+}
+
+static void vgaHWLock(struct vgastate *state)
+{
+	/* Protect CRTC[0-7] */
+	vga_wcrt(state->vgabase, 0x11, vga_rcrt(state->vgabase, 0x11) | 0x80);
+}
+
+static void vgaHWUnlock(void)
+{
+	/* Unprotect CRTC[0-7] */
+	vga_wcrt(NULL, 0x11, vga_rcrt(NULL, 0x11) & ~0x80);
+}
+
+static void neoLock(struct vgastate *state)
+{
+	vga_wgfx(state->vgabase, 0x09, 0x00);
+	vgaHWLock(state);
+}
+
+static void neoUnlock(void)
+{
+	vgaHWUnlock();
+	vga_wgfx(NULL, 0x09, 0x26);
+}
+
+/*
+ * VGA Palette management
+ */
+static int paletteEnabled = 0;
+
+static inline void VGAenablePalette(void)
+{
+	vga_r(NULL, VGA_IS1_RC);
+	vga_w(NULL, VGA_ATT_W, 0x00);
+	paletteEnabled = 1;
+}
+
+static inline void VGAdisablePalette(void)
+{
+	vga_r(NULL, VGA_IS1_RC);
+	vga_w(NULL, VGA_ATT_W, 0x20);
+	paletteEnabled = 0;
+}
+
+static inline void VGAwATTR(u8 index, u8 value)
+{
+	if (paletteEnabled)
+		index &= ~0x20;
+	else
+		index |= 0x20;
+
+	vga_r(NULL, VGA_IS1_RC);
+	vga_wattr(NULL, index, value);
+}
+
+static void vgaHWProtect(int on)
+{
+	unsigned char tmp;
+
+	if (on) {
+		/*
+		 * Turn off screen and disable sequencer.
+		 */
+		tmp = vga_rseq(NULL, 0x01);
+		vga_wseq(NULL, 0x00, 0x01);		/* Synchronous Reset */
+		vga_wseq(NULL, 0x01, tmp | 0x20);	/* disable the display */
+
+		VGAenablePalette();
+	} else {
+		/*
+		 * Reenable sequencer, then turn on screen.
+		 */
+		tmp = vga_rseq(NULL, 0x01);
+		vga_wseq(NULL, 0x01, tmp & ~0x20);	/* reenable display */
+		vga_wseq(NULL, 0x00, 0x03);		/* clear synchronousreset */
+
+		VGAdisablePalette();
+	}
+}
+
+static void vgaHWRestore(const struct fb_info *info,
+			 const struct neofb_par *par)
+{
+	int i;
+
+	vga_w(NULL, VGA_MIS_W, par->MiscOutReg);
+
+	for (i = 1; i < 5; i++)
+		vga_wseq(NULL, i, par->Sequencer[i]);
+
+	/* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or CRTC[17] */
+	vga_wcrt(NULL, 17, par->CRTC[17] & ~0x80);
+
+	for (i = 0; i < 25; i++)
+		vga_wcrt(NULL, i, par->CRTC[i]);
+
+	for (i = 0; i < 9; i++)
+		vga_wgfx(NULL, i, par->Graphics[i]);
+
+	VGAenablePalette();
+
+	for (i = 0; i < 21; i++)
+		VGAwATTR(i, par->Attribute[i]);
+
+	VGAdisablePalette();
+}
+
+
+/* -------------------- Hardware specific routines ------------------------- */
+
+/*
+ * Hardware Acceleration for Neo2200+
+ */
+static inline int neo2200_sync(struct fb_info *info)
+{
+	struct neofb_par *par = (struct neofb_par *) info->par;
+	int waitcycles;
+
+	while (readl(&par->neo2200->bltStat) & 1)
+		waitcycles++;
+	return 0;
+}
+
+static inline void neo2200_wait_fifo(struct fb_info *info,
+				     int requested_fifo_space)
+{
+	//  ndev->neo.waitfifo_calls++;
+	//  ndev->neo.waitfifo_sum += requested_fifo_space;
+
+	/* FIXME: does not work
+	   if (neo_fifo_space < requested_fifo_space)
+	   {
+	   neo_fifo_waitcycles++;
+
+	   while (1)
+	   {
+	   neo_fifo_space = (neo2200->bltStat >> 8);
+	   if (neo_fifo_space >= requested_fifo_space)
+	   break;
+	   }
+	   }
+	   else
+	   {
+	   neo_fifo_cache_hits++;
+	   }
+
+	   neo_fifo_space -= requested_fifo_space;
+	 */
+
+	neo2200_sync(info);
+}
+
+static inline void neo2200_accel_init(struct fb_info *info,
+				      struct fb_var_screeninfo *var)
+{
+	struct neofb_par *par = (struct neofb_par *) info->par;
+	Neo2200 __iomem *neo2200 = par->neo2200;
+	u32 bltMod, pitch;
+
+	neo2200_sync(info);
+
+	switch (var->bits_per_pixel) {
+	case 8:
+		bltMod = NEO_MODE1_DEPTH8;
+		pitch = var->xres_virtual;
+		break;
+	case 15:
+	case 16:
+		bltMod = NEO_MODE1_DEPTH16;
+		pitch = var->xres_virtual * 2;
+		break;
+	case 24:
+		bltMod = NEO_MODE1_DEPTH24;
+		pitch = var->xres_virtual * 3;
+		break;
+	default:
+		printk(KERN_ERR
+		       "neofb: neo2200_accel_init: unexpected bits per pixel!\n");
+		return;
+	}
+
+	writel(bltMod << 16, &neo2200->bltStat);
+	writel((pitch << 16) | pitch, &neo2200->pitch);
+}
+
+/* --------------------------------------------------------------------- */
+
+static int
+neofb_open(struct fb_info *info, int user)
+{
+	struct neofb_par *par = (struct neofb_par *) info->par;
+	int cnt = atomic_read(&par->ref_count);
+
+	if (!cnt) {
+		memset(&par->state, 0, sizeof(struct vgastate));
+		par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS;
+		save_vga(&par->state);
+	}
+	atomic_inc(&par->ref_count);
+	return 0;
+}
+
+static int
+neofb_release(struct fb_info *info, int user)
+{
+	struct neofb_par *par = (struct neofb_par *) info->par;
+	int cnt = atomic_read(&par->ref_count);
+
+	if (!cnt)
+		return -EINVAL;
+	if (cnt == 1) {
+		restore_vga(&par->state);
+	}
+	atomic_dec(&par->ref_count);
+	return 0;
+}
+
+static int
+neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct neofb_par *par = (struct neofb_par *) info->par;
+	unsigned int pixclock = var->pixclock;
+	struct xtimings timings;
+	int memlen, vramlen;
+	int mode_ok = 0;
+
+	DBG("neofb_check_var");
+
+	if (!pixclock)
+		pixclock = 10000;	/* 10ns = 100MHz */
+	timings.pixclock = 1000000000 / pixclock;
+	if (timings.pixclock < 1)
+		timings.pixclock = 1;
+
+	if (timings.pixclock > par->maxClock)
+		return -EINVAL;
+
+	timings.dblscan = var->vmode & FB_VMODE_DOUBLE;
+	timings.interlaced = var->vmode & FB_VMODE_INTERLACED;
+	timings.HDisplay = var->xres;
+	timings.HSyncStart = timings.HDisplay + var->right_margin;
+	timings.HSyncEnd = timings.HSyncStart + var->hsync_len;
+	timings.HTotal = timings.HSyncEnd + var->left_margin;
+	timings.VDisplay = var->yres;
+	timings.VSyncStart = timings.VDisplay + var->lower_margin;
+	timings.VSyncEnd = timings.VSyncStart + var->vsync_len;
+	timings.VTotal = timings.VSyncEnd + var->upper_margin;
+	timings.sync = var->sync;
+
+	/* Is the mode larger than the LCD panel? */
+	if (par->internal_display &&
+            ((var->xres > par->NeoPanelWidth) ||
+	     (var->yres > par->NeoPanelHeight))) {
+		printk(KERN_INFO
+		       "Mode (%dx%d) larger than the LCD panel (%dx%d)\n",
+		       var->xres, var->yres, par->NeoPanelWidth,
+		       par->NeoPanelHeight);
+		return -EINVAL;
+	}
+
+	/* Is the mode one of the acceptable sizes? */
+	if (!par->internal_display)
+		mode_ok = 1;
+	else {
+		switch (var->xres) {
+		case 1280:
+			if (var->yres == 1024)
+				mode_ok = 1;
+			break;
+		case 1024:
+			if (var->yres == 768)
+				mode_ok = 1;
+			break;
+		case 800:
+			if (var->yres == (par->libretto ? 480 : 600))
+				mode_ok = 1;
+			break;
+		case 640:
+			if (var->yres == 480)
+				mode_ok = 1;
+			break;
+		}
+	}
+
+	if (!mode_ok) {
+		printk(KERN_INFO
+		       "Mode (%dx%d) won't display properly on LCD\n",
+		       var->xres, var->yres);
+		return -EINVAL;
+	}
+
+	var->red.msb_right = 0;
+	var->green.msb_right = 0;
+	var->blue.msb_right = 0;
+
+	switch (var->bits_per_pixel) {
+	case 8:		/* PSEUDOCOLOUR, 256 */
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		var->red.offset = 0;
+		var->red.length = 8;
+		var->green.offset = 0;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		break;
+
+	case 16:		/* DIRECTCOLOUR, 64k */
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		var->red.offset = 11;
+		var->red.length = 5;
+		var->green.offset = 5;
+		var->green.length = 6;
+		var->blue.offset = 0;
+		var->blue.length = 5;
+		break;
+
+	case 24:		/* TRUECOLOUR, 16m */
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		var->red.offset = 16;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		break;
+
+#ifdef NO_32BIT_SUPPORT_YET
+	case 32:		/* TRUECOLOUR, 16m */
+		var->transp.offset = 24;
+		var->transp.length = 8;
+		var->red.offset = 16;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		break;
+#endif
+	default:
+		printk(KERN_WARNING "neofb: no support for %dbpp\n",
+		       var->bits_per_pixel);
+		return -EINVAL;
+	}
+
+	vramlen = info->fix.smem_len;
+	if (vramlen > 4 * 1024 * 1024)
+		vramlen = 4 * 1024 * 1024;
+
+	if (var->yres_virtual < var->yres)
+		var->yres_virtual = var->yres;
+	if (var->xres_virtual < var->xres)
+		var->xres_virtual = var->xres;
+
+	memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual >> 3;
+
+	if (memlen > vramlen) {
+		var->yres_virtual =  vramlen * 8 / (var->xres_virtual *
+				   	var->bits_per_pixel);
+		memlen = var->xres_virtual * var->bits_per_pixel *
+				var->yres_virtual / 8;
+	}
+
+	/* we must round yres/xres down, we already rounded y/xres_virtual up
+	   if it was possible. We should return -EINVAL, but I disagree */
+	if (var->yres_virtual < var->yres)
+		var->yres = var->yres_virtual;
+	if (var->xres_virtual < var->xres)
+		var->xres = var->xres_virtual;
+	if (var->xoffset + var->xres > var->xres_virtual)
+		var->xoffset = var->xres_virtual - var->xres;
+	if (var->yoffset + var->yres > var->yres_virtual)
+		var->yoffset = var->yres_virtual - var->yres;
+
+	var->nonstd = 0;
+	var->height = -1;
+	var->width = -1;
+
+	if (var->bits_per_pixel >= 24 || !par->neo2200)
+		var->accel_flags &= ~FB_ACCELF_TEXT;
+	return 0;
+}
+
+static int neofb_set_par(struct fb_info *info)
+{
+	struct neofb_par *par = (struct neofb_par *) info->par;
+	struct xtimings timings;
+	unsigned char temp;
+	int i, clock_hi = 0;
+	int lcd_stretch;
+	int hoffset, voffset;
+
+	DBG("neofb_set_par");
+
+	neoUnlock();
+
+	vgaHWProtect(1);	/* Blank the screen */
+
+	timings.dblscan = info->var.vmode & FB_VMODE_DOUBLE;
+	timings.interlaced = info->var.vmode & FB_VMODE_INTERLACED;
+	timings.HDisplay = info->var.xres;
+	timings.HSyncStart = timings.HDisplay + info->var.right_margin;
+	timings.HSyncEnd = timings.HSyncStart + info->var.hsync_len;
+	timings.HTotal = timings.HSyncEnd + info->var.left_margin;
+	timings.VDisplay = info->var.yres;
+	timings.VSyncStart = timings.VDisplay + info->var.lower_margin;
+	timings.VSyncEnd = timings.VSyncStart + info->var.vsync_len;
+	timings.VTotal = timings.VSyncEnd + info->var.upper_margin;
+	timings.sync = info->var.sync;
+	timings.pixclock = PICOS2KHZ(info->var.pixclock);
+
+	if (timings.pixclock < 1)
+		timings.pixclock = 1;
+
+	/*
+	 * This will allocate the datastructure and initialize all of the
+	 * generic VGA registers.
+	 */
+
+	if (vgaHWInit(&info->var, info, par, &timings))
+		return -EINVAL;
+
+	/*
+	 * The default value assigned by vgaHW.c is 0x41, but this does
+	 * not work for NeoMagic.
+	 */
+	par->Attribute[16] = 0x01;
+
+	switch (info->var.bits_per_pixel) {
+	case 8:
+		par->CRTC[0x13] = info->var.xres_virtual >> 3;
+		par->ExtCRTOffset = info->var.xres_virtual >> 11;
+		par->ExtColorModeSelect = 0x11;
+		break;
+	case 16:
+		par->CRTC[0x13] = info->var.xres_virtual >> 2;
+		par->ExtCRTOffset = info->var.xres_virtual >> 10;
+		par->ExtColorModeSelect = 0x13;
+		break;
+	case 24:
+		par->CRTC[0x13] = (info->var.xres_virtual * 3) >> 3;
+		par->ExtCRTOffset = (info->var.xres_virtual * 3) >> 11;
+		par->ExtColorModeSelect = 0x14;
+		break;
+#ifdef NO_32BIT_SUPPORT_YET
+	case 32:		/* FIXME: guessed values */
+		par->CRTC[0x13] = info->var.xres_virtual >> 1;
+		par->ExtCRTOffset = info->var.xres_virtual >> 9;
+		par->ExtColorModeSelect = 0x15;
+		break;
+#endif
+	default:
+		break;
+	}
+
+	par->ExtCRTDispAddr = 0x10;
+
+	/* Vertical Extension */
+	par->VerticalExt = (((timings.VTotal - 2) & 0x400) >> 10)
+	    | (((timings.VDisplay - 1) & 0x400) >> 9)
+	    | (((timings.VSyncStart) & 0x400) >> 8)
+	    | (((timings.VSyncStart) & 0x400) >> 7);
+
+	/* Fast write bursts on unless disabled. */
+	if (par->pci_burst)
+		par->SysIfaceCntl1 = 0x30;
+	else
+		par->SysIfaceCntl1 = 0x00;
+
+	par->SysIfaceCntl2 = 0xc0;	/* VESA Bios sets this to 0x80! */
+
+	/* Enable any user specified display devices. */
+	par->PanelDispCntlReg1 = 0x00;
+	if (par->internal_display)
+		par->PanelDispCntlReg1 |= 0x02;
+	if (par->external_display)
+		par->PanelDispCntlReg1 |= 0x01;
+
+	/* If the user did not specify any display devices, then... */
+	if (par->PanelDispCntlReg1 == 0x00) {
+		/* Default to internal (i.e., LCD) only. */
+		par->PanelDispCntlReg1 |= 0x02;
+	}
+
+	/* If we are using a fixed mode, then tell the chip we are. */
+	switch (info->var.xres) {
+	case 1280:
+		par->PanelDispCntlReg1 |= 0x60;
+		break;
+	case 1024:
+		par->PanelDispCntlReg1 |= 0x40;
+		break;
+	case 800:
+		par->PanelDispCntlReg1 |= 0x20;
+		break;
+	case 640:
+	default:
+		break;
+	}
+
+	/* Setup shadow register locking. */
+	switch (par->PanelDispCntlReg1 & 0x03) {
+	case 0x01:		/* External CRT only mode: */
+		par->GeneralLockReg = 0x00;
+		/* We need to program the VCLK for external display only mode. */
+		par->ProgramVCLK = 1;
+		break;
+	case 0x02:		/* Internal LCD only mode: */
+	case 0x03:		/* Simultaneous internal/external (LCD/CRT) mode: */
+		par->GeneralLockReg = 0x01;
+		/* Don't program the VCLK when using the LCD. */
+		par->ProgramVCLK = 0;
+		break;
+	}
+
+	/*
+	 * If the screen is to be stretched, turn on stretching for the
+	 * various modes.
+	 *
+	 * OPTION_LCD_STRETCH means stretching should be turned off!
+	 */
+	par->PanelDispCntlReg2 = 0x00;
+	par->PanelDispCntlReg3 = 0x00;
+
+	if (par->lcd_stretch && (par->PanelDispCntlReg1 == 0x02) &&	/* LCD only */
+	    (info->var.xres != par->NeoPanelWidth)) {
+		switch (info->var.xres) {
+		case 320:	/* Needs testing.  KEM -- 24 May 98 */
+		case 400:	/* Needs testing.  KEM -- 24 May 98 */
+		case 640:
+		case 800:
+		case 1024:
+			lcd_stretch = 1;
+			par->PanelDispCntlReg2 |= 0xC6;
+			break;
+		default:
+			lcd_stretch = 0;
+			/* No stretching in these modes. */
+		}
+	} else
+		lcd_stretch = 0;
+
+	/*
+	 * If the screen is to be centerd, turn on the centering for the
+	 * various modes.
+	 */
+	par->PanelVertCenterReg1 = 0x00;
+	par->PanelVertCenterReg2 = 0x00;
+	par->PanelVertCenterReg3 = 0x00;
+	par->PanelVertCenterReg4 = 0x00;
+	par->PanelVertCenterReg5 = 0x00;
+	par->PanelHorizCenterReg1 = 0x00;
+	par->PanelHorizCenterReg2 = 0x00;
+	par->PanelHorizCenterReg3 = 0x00;
+	par->PanelHorizCenterReg4 = 0x00;
+	par->PanelHorizCenterReg5 = 0x00;
+
+
+	if (par->PanelDispCntlReg1 & 0x02) {
+		if (info->var.xres == par->NeoPanelWidth) {
+			/*
+			 * No centering required when the requested display width
+			 * equals the panel width.
+			 */
+		} else {
+			par->PanelDispCntlReg2 |= 0x01;
+			par->PanelDispCntlReg3 |= 0x10;
+
+			/* Calculate the horizontal and vertical offsets. */
+			if (!lcd_stretch) {
+				hoffset =
+				    ((par->NeoPanelWidth -
+				      info->var.xres) >> 4) - 1;
+				voffset =
+				    ((par->NeoPanelHeight -
+				      info->var.yres) >> 1) - 2;
+			} else {
+				/* Stretched modes cannot be centered. */
+				hoffset = 0;
+				voffset = 0;
+			}
+
+			switch (info->var.xres) {
+			case 320:	/* Needs testing.  KEM -- 24 May 98 */
+				par->PanelHorizCenterReg3 = hoffset;
+				par->PanelVertCenterReg2 = voffset;
+				break;
+			case 400:	/* Needs testing.  KEM -- 24 May 98 */
+				par->PanelHorizCenterReg4 = hoffset;
+				par->PanelVertCenterReg1 = voffset;
+				break;
+			case 640:
+				par->PanelHorizCenterReg1 = hoffset;
+				par->PanelVertCenterReg3 = voffset;
+				break;
+			case 800:
+				par->PanelHorizCenterReg2 = hoffset;
+				par->PanelVertCenterReg4 = voffset;
+				break;
+			case 1024:
+				par->PanelHorizCenterReg5 = hoffset;
+				par->PanelVertCenterReg5 = voffset;
+				break;
+			case 1280:
+			default:
+				/* No centering in these modes. */
+				break;
+			}
+		}
+	}
+
+	par->biosMode =
+	    neoFindMode(info->var.xres, info->var.yres,
+			info->var.bits_per_pixel);
+
+	/*
+	 * Calculate the VCLK that most closely matches the requested dot
+	 * clock.
+	 */
+	neoCalcVCLK(info, par, timings.pixclock);
+
+	/* Since we program the clocks ourselves, always use VCLK3. */
+	par->MiscOutReg |= 0x0C;
+
+	/* alread unlocked above */
+	/* BOGUS  vga_wgfx(NULL, 0x09, 0x26); */
+
+	/* don't know what this is, but it's 0 from bootup anyway */
+	vga_wgfx(NULL, 0x15, 0x00);
+
+	/* was set to 0x01 by my bios in text and vesa modes */
+	vga_wgfx(NULL, 0x0A, par->GeneralLockReg);
+
+	/*
+	 * The color mode needs to be set before calling vgaHWRestore
+	 * to ensure the DAC is initialized properly.
+	 *
+	 * NOTE: Make sure we don't change bits make sure we don't change
+	 * any reserved bits.
+	 */
+	temp = vga_rgfx(NULL, 0x90);
+	switch (info->fix.accel) {
+	case FB_ACCEL_NEOMAGIC_NM2070:
+		temp &= 0xF0;	/* Save bits 7:4 */
+		temp |= (par->ExtColorModeSelect & ~0xF0);
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2090:
+	case FB_ACCEL_NEOMAGIC_NM2093:
+	case FB_ACCEL_NEOMAGIC_NM2097:
+	case FB_ACCEL_NEOMAGIC_NM2160:
+	case FB_ACCEL_NEOMAGIC_NM2200:
+	case FB_ACCEL_NEOMAGIC_NM2230:
+	case FB_ACCEL_NEOMAGIC_NM2360:
+	case FB_ACCEL_NEOMAGIC_NM2380:
+		temp &= 0x70;	/* Save bits 6:4 */
+		temp |= (par->ExtColorModeSelect & ~0x70);
+		break;
+	}
+
+	vga_wgfx(NULL, 0x90, temp);
+
+	/*
+	 * In some rare cases a lockup might occur if we don't delay
+	 * here. (Reported by Miles Lane)
+	 */
+	//mdelay(200);
+
+	/*
+	 * Disable horizontal and vertical graphics and text expansions so
+	 * that vgaHWRestore works properly.
+	 */
+	temp = vga_rgfx(NULL, 0x25);
+	temp &= 0x39;
+	vga_wgfx(NULL, 0x25, temp);
+
+	/*
+	 * Sleep for 200ms to make sure that the two operations above have
+	 * had time to take effect.
+	 */
+	mdelay(200);
+
+	/*
+	 * This function handles restoring the generic VGA registers.  */
+	vgaHWRestore(info, par);
+
+	/* linear colormap for non palettized modes */
+	switch (info->var.bits_per_pixel) {
+	case 8:
+		/* PseudoColor, 256 */
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+		break;
+	case 16:
+		/* TrueColor, 64k */
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+
+		for (i = 0; i < 64; i++) {
+			outb(i, 0x3c8);
+
+			outb(i << 1, 0x3c9);
+			outb(i, 0x3c9);
+			outb(i << 1, 0x3c9);
+		}
+		break;
+	case 24:
+#ifdef NO_32BIT_SUPPORT_YET
+	case 32:
+#endif
+		/* TrueColor, 16m */
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+
+		for (i = 0; i < 256; i++) {
+			outb(i, 0x3c8);
+
+			outb(i, 0x3c9);
+			outb(i, 0x3c9);
+			outb(i, 0x3c9);
+		}
+		break;
+	}
+
+	vga_wgfx(NULL, 0x0E, par->ExtCRTDispAddr);
+	vga_wgfx(NULL, 0x0F, par->ExtCRTOffset);
+	temp = vga_rgfx(NULL, 0x10);
+	temp &= 0x0F;		/* Save bits 3:0 */
+	temp |= (par->SysIfaceCntl1 & ~0x0F);	/* VESA Bios sets bit 1! */
+	vga_wgfx(NULL, 0x10, temp);
+
+	vga_wgfx(NULL, 0x11, par->SysIfaceCntl2);
+	vga_wgfx(NULL, 0x15, 0 /*par->SingleAddrPage */ );
+	vga_wgfx(NULL, 0x16, 0 /*par->DualAddrPage */ );
+
+	temp = vga_rgfx(NULL, 0x20);
+	switch (info->fix.accel) {
+	case FB_ACCEL_NEOMAGIC_NM2070:
+		temp &= 0xFC;	/* Save bits 7:2 */
+		temp |= (par->PanelDispCntlReg1 & ~0xFC);
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2090:
+	case FB_ACCEL_NEOMAGIC_NM2093:
+	case FB_ACCEL_NEOMAGIC_NM2097:
+	case FB_ACCEL_NEOMAGIC_NM2160:
+		temp &= 0xDC;	/* Save bits 7:6,4:2 */
+		temp |= (par->PanelDispCntlReg1 & ~0xDC);
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2200:
+	case FB_ACCEL_NEOMAGIC_NM2230:
+	case FB_ACCEL_NEOMAGIC_NM2360:
+	case FB_ACCEL_NEOMAGIC_NM2380:
+		temp &= 0x98;	/* Save bits 7,4:3 */
+		temp |= (par->PanelDispCntlReg1 & ~0x98);
+		break;
+	}
+	vga_wgfx(NULL, 0x20, temp);
+
+	temp = vga_rgfx(NULL, 0x25);
+	temp &= 0x38;		/* Save bits 5:3 */
+	temp |= (par->PanelDispCntlReg2 & ~0x38);
+	vga_wgfx(NULL, 0x25, temp);
+
+	if (info->fix.accel != FB_ACCEL_NEOMAGIC_NM2070) {
+		temp = vga_rgfx(NULL, 0x30);
+		temp &= 0xEF;	/* Save bits 7:5 and bits 3:0 */
+		temp |= (par->PanelDispCntlReg3 & ~0xEF);
+		vga_wgfx(NULL, 0x30, temp);
+	}
+
+	vga_wgfx(NULL, 0x28, par->PanelVertCenterReg1);
+	vga_wgfx(NULL, 0x29, par->PanelVertCenterReg2);
+	vga_wgfx(NULL, 0x2a, par->PanelVertCenterReg3);
+
+	if (info->fix.accel != FB_ACCEL_NEOMAGIC_NM2070) {
+		vga_wgfx(NULL, 0x32, par->PanelVertCenterReg4);
+		vga_wgfx(NULL, 0x33, par->PanelHorizCenterReg1);
+		vga_wgfx(NULL, 0x34, par->PanelHorizCenterReg2);
+		vga_wgfx(NULL, 0x35, par->PanelHorizCenterReg3);
+	}
+
+	if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2160)
+		vga_wgfx(NULL, 0x36, par->PanelHorizCenterReg4);
+
+	if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 ||
+	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 ||
+	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 ||
+	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) {
+		vga_wgfx(NULL, 0x36, par->PanelHorizCenterReg4);
+		vga_wgfx(NULL, 0x37, par->PanelVertCenterReg5);
+		vga_wgfx(NULL, 0x38, par->PanelHorizCenterReg5);
+
+		clock_hi = 1;
+	}
+
+	/* Program VCLK3 if needed. */
+	if (par->ProgramVCLK && ((vga_rgfx(NULL, 0x9B) != par->VCLK3NumeratorLow)
+				 || (vga_rgfx(NULL, 0x9F) != par->VCLK3Denominator)
+				 || (clock_hi && ((vga_rgfx(NULL, 0x8F) & ~0x0f)
+						  != (par->VCLK3NumeratorHigh &
+						      ~0x0F))))) {
+		vga_wgfx(NULL, 0x9B, par->VCLK3NumeratorLow);
+		if (clock_hi) {
+			temp = vga_rgfx(NULL, 0x8F);
+			temp &= 0x0F;	/* Save bits 3:0 */
+			temp |= (par->VCLK3NumeratorHigh & ~0x0F);
+			vga_wgfx(NULL, 0x8F, temp);
+		}
+		vga_wgfx(NULL, 0x9F, par->VCLK3Denominator);
+	}
+
+	if (par->biosMode)
+		vga_wcrt(NULL, 0x23, par->biosMode);
+
+	vga_wgfx(NULL, 0x93, 0xc0);	/* Gives 5x faster framebuffer writes !!! */
+
+	/* Program vertical extension register */
+	if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 ||
+	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 ||
+	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 ||
+	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) {
+		vga_wcrt(NULL, 0x70, par->VerticalExt);
+	}
+
+	vgaHWProtect(0);	/* Turn on screen */
+
+	/* Calling this also locks offset registers required in update_start */
+	neoLock(&par->state);
+
+	info->fix.line_length =
+	    info->var.xres_virtual * (info->var.bits_per_pixel >> 3);
+
+	switch (info->fix.accel) {
+		case FB_ACCEL_NEOMAGIC_NM2200:
+		case FB_ACCEL_NEOMAGIC_NM2230: 
+		case FB_ACCEL_NEOMAGIC_NM2360: 
+		case FB_ACCEL_NEOMAGIC_NM2380: 
+			neo2200_accel_init(info, &info->var);
+			break;
+		default:
+			break;
+	}	
+	return 0;
+}
+
+static void neofb_update_start(struct fb_info *info,
+			       struct fb_var_screeninfo *var)
+{
+	struct neofb_par *par = (struct neofb_par *) info->par;
+	struct vgastate *state = &par->state;
+	int oldExtCRTDispAddr;
+	int Base;
+
+	DBG("neofb_update_start");
+
+	Base = (var->yoffset * var->xres_virtual + var->xoffset) >> 2;
+	Base *= (var->bits_per_pixel + 7) / 8;
+
+	neoUnlock();
+
+	/*
+	 * These are the generic starting address registers.
+	 */
+	vga_wcrt(state->vgabase, 0x0C, (Base & 0x00FF00) >> 8);
+	vga_wcrt(state->vgabase, 0x0D, (Base & 0x00FF));
+
+	/*
+	 * Make sure we don't clobber some other bits that might already
+	 * have been set. NOTE: NM2200 has a writable bit 3, but it shouldn't
+	 * be needed.
+	 */
+	oldExtCRTDispAddr = vga_rgfx(NULL, 0x0E);
+	vga_wgfx(state->vgabase, 0x0E, (((Base >> 16) & 0x0f) | (oldExtCRTDispAddr & 0xf0)));
+
+	neoLock(state);
+}
+
+/*
+ *    Pan or Wrap the Display
+ */
+static int neofb_pan_display(struct fb_var_screeninfo *var,
+			     struct fb_info *info)
+{
+	u_int y_bottom;
+
+	y_bottom = var->yoffset;
+
+	if (!(var->vmode & FB_VMODE_YWRAP))
+		y_bottom += var->yres;
+
+	if (var->xoffset > (var->xres_virtual - var->xres))
+		return -EINVAL;
+	if (y_bottom > info->var.yres_virtual)
+		return -EINVAL;
+
+	neofb_update_start(info, var);
+
+	info->var.xoffset = var->xoffset;
+	info->var.yoffset = var->yoffset;
+
+	if (var->vmode & FB_VMODE_YWRAP)
+		info->var.vmode |= FB_VMODE_YWRAP;
+	else
+		info->var.vmode &= ~FB_VMODE_YWRAP;
+	return 0;
+}
+
+static int neofb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			   u_int transp, struct fb_info *fb)
+{
+	if (regno >= fb->cmap.len || regno > 255)
+		return -EINVAL;
+
+	switch (fb->var.bits_per_pixel) {
+	case 8:
+		outb(regno, 0x3c8);
+
+		outb(red >> 10, 0x3c9);
+		outb(green >> 10, 0x3c9);
+		outb(blue >> 10, 0x3c9);
+		break;
+	case 16:
+		((u32 *) fb->pseudo_palette)[regno] =
+				((red & 0xf800)) | ((green & 0xfc00) >> 5) |
+				((blue & 0xf800) >> 11);
+		break;
+	case 24:
+		((u32 *) fb->pseudo_palette)[regno] =
+				((red & 0xff00) << 8) | ((green & 0xff00)) |
+				((blue & 0xff00) >> 8);
+		break;
+#ifdef NO_32BIT_SUPPORT_YET
+	case 32:
+		((u32 *) fb->pseudo_palette)[regno] =
+				((transp & 0xff00) << 16) | ((red & 0xff00) << 8) |
+				((green & 0xff00)) | ((blue & 0xff00) >> 8);
+		break;
+#endif
+	default:
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ *    (Un)Blank the display.
+ */
+static int neofb_blank(int blank_mode, struct fb_info *info)
+{
+	/*
+	 *  Blank the screen if blank_mode != 0, else unblank.
+	 *  Return 0 if blanking succeeded, != 0 if un-/blanking failed due to
+	 *  e.g. a video mode which doesn't support it. Implements VESA suspend
+	 *  and powerdown modes for monitors, and backlight control on LCDs.
+	 *    blank_mode == 0: unblanked (backlight on)
+	 *    blank_mode == 1: blank (backlight on)
+	 *    blank_mode == 2: suspend vsync (backlight off)
+	 *    blank_mode == 3: suspend hsync (backlight off)
+	 *    blank_mode == 4: powerdown (backlight off)
+	 *
+	 *  wms...Enable VESA DPMS compatible powerdown mode
+	 *  run "setterm -powersave powerdown" to take advantage
+	 */
+	struct neofb_par *par = (struct neofb_par *)info->par;
+	int seqflags, lcdflags, dpmsflags, reg;
+
+	switch (blank_mode) {
+	case FB_BLANK_POWERDOWN:	/* powerdown - both sync lines down */
+		seqflags = VGA_SR01_SCREEN_OFF; /* Disable sequencer */
+		lcdflags = 0;			/* LCD off */
+		dpmsflags = NEO_GR01_SUPPRESS_HSYNC |
+			    NEO_GR01_SUPPRESS_VSYNC;
+#ifdef CONFIG_TOSHIBA
+		/* Do we still need this ? */
+		/* attempt to turn off backlight on toshiba; also turns off external */
+		{
+			SMMRegisters regs;
+
+			regs.eax = 0xff00; /* HCI_SET */
+			regs.ebx = 0x0002; /* HCI_BACKLIGHT */
+			regs.ecx = 0x0000; /* HCI_DISABLE */
+			tosh_smm(&regs);
+		}
+#endif
+		break;
+	case FB_BLANK_HSYNC_SUSPEND:		/* hsync off */
+		seqflags = VGA_SR01_SCREEN_OFF;	/* Disable sequencer */
+		lcdflags = 0;			/* LCD off */
+		dpmsflags = NEO_GR01_SUPPRESS_HSYNC;
+		break;
+	case FB_BLANK_VSYNC_SUSPEND:		/* vsync off */
+		seqflags = VGA_SR01_SCREEN_OFF;	/* Disable sequencer */
+		lcdflags = 0;			/* LCD off */
+		dpmsflags = NEO_GR01_SUPPRESS_VSYNC;
+		break;
+	case FB_BLANK_NORMAL:		/* just blank screen (backlight stays on) */
+		seqflags = VGA_SR01_SCREEN_OFF;	/* Disable sequencer */
+		lcdflags = par->PanelDispCntlReg1 & 0x02; /* LCD normal */
+		dpmsflags = 0;			/* no hsync/vsync suppression */
+		break;
+	case FB_BLANK_UNBLANK:		/* unblank */
+		seqflags = 0;			/* Enable sequencer */
+		lcdflags = par->PanelDispCntlReg1 & 0x02; /* LCD normal */
+		dpmsflags = 0x00;	/* no hsync/vsync suppression */
+#ifdef CONFIG_TOSHIBA
+		/* Do we still need this ? */
+		/* attempt to re-enable backlight/external on toshiba */
+		{
+			SMMRegisters regs;
+
+			regs.eax = 0xff00; /* HCI_SET */
+			regs.ebx = 0x0002; /* HCI_BACKLIGHT */
+			regs.ecx = 0x0001; /* HCI_ENABLE */
+			tosh_smm(&regs);
+		}
+#endif
+		break;
+	default:	/* Anything else we don't understand; return 1 to tell
+			 * fb_blank we didn't aactually do anything */
+		return 1;
+	}
+
+	neoUnlock();
+	reg = (vga_rseq(NULL, 0x01) & ~0x20) | seqflags;
+	vga_wseq(NULL, 0x01, reg);
+	reg = (vga_rgfx(NULL, 0x20) & ~0x02) | lcdflags;
+	vga_wgfx(NULL, 0x20, reg);
+	reg = (vga_rgfx(NULL, 0x01) & ~0xF0) | 0x80 | dpmsflags;
+	vga_wgfx(NULL, 0x01, reg);
+	neoLock(&par->state);
+	return 0;
+}
+
+static void
+neo2200_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+	struct neofb_par *par = (struct neofb_par *) info->par;
+	u_long dst, rop;
+
+	dst = rect->dx + rect->dy * info->var.xres_virtual;
+	rop = rect->rop ? 0x060000 : 0x0c0000;
+
+	neo2200_wait_fifo(info, 4);
+
+	/* set blt control */
+	writel(NEO_BC3_FIFO_EN |
+	       NEO_BC0_SRC_IS_FG | NEO_BC3_SKIP_MAPPING |
+	       //               NEO_BC3_DST_XY_ADDR  |
+	       //               NEO_BC3_SRC_XY_ADDR  |
+	       rop, &par->neo2200->bltCntl);
+
+	switch (info->var.bits_per_pixel) {
+	case 8:
+		writel(rect->color, &par->neo2200->fgColor);
+		break;
+	case 16:
+	case 24:
+		writel(((u32 *) (info->pseudo_palette))[rect->color],
+		       &par->neo2200->fgColor);
+		break;
+	}
+
+	writel(dst * ((info->var.bits_per_pixel + 7) >> 3),
+	       &par->neo2200->dstStart);
+	writel((rect->height << 16) | (rect->width & 0xffff),
+	       &par->neo2200->xyExt);
+}
+
+static void
+neo2200_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+	u32 sx = area->sx, sy = area->sy, dx = area->dx, dy = area->dy;
+	struct neofb_par *par = (struct neofb_par *) info->par;
+	u_long src, dst, bltCntl;
+
+	bltCntl = NEO_BC3_FIFO_EN | NEO_BC3_SKIP_MAPPING | 0x0C0000;
+
+	if ((dy > sy) || ((dy == sy) && (dx > sx))) {
+		/* Start with the lower right corner */
+		sy += (area->height - 1);
+		dy += (area->height - 1);
+		sx += (area->width - 1);
+		dx += (area->width - 1);
+
+		bltCntl |= NEO_BC0_X_DEC | NEO_BC0_DST_Y_DEC | NEO_BC0_SRC_Y_DEC;
+	}
+
+	src = sx * (info->var.bits_per_pixel >> 3) + sy*info->fix.line_length;
+	dst = dx * (info->var.bits_per_pixel >> 3) + dy*info->fix.line_length;
+
+	neo2200_wait_fifo(info, 4);
+
+	/* set blt control */
+	writel(bltCntl, &par->neo2200->bltCntl);
+
+	writel(src, &par->neo2200->srcStart);
+	writel(dst, &par->neo2200->dstStart);
+	writel((area->height << 16) | (area->width & 0xffff),
+	       &par->neo2200->xyExt);
+}
+
+static void
+neo2200_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	struct neofb_par *par = (struct neofb_par *) info->par;
+	int s_pitch = (image->width * image->depth + 7) >> 3;
+	int scan_align = info->pixmap.scan_align - 1;
+	int buf_align = info->pixmap.buf_align - 1;
+	int bltCntl_flags, d_pitch, data_len;
+
+	// The data is padded for the hardware
+	d_pitch = (s_pitch + scan_align) & ~scan_align;
+	data_len = ((d_pitch * image->height) + buf_align) & ~buf_align;
+
+	neo2200_sync(info);
+
+	if (image->depth == 1) {
+		if (info->var.bits_per_pixel == 24 && image->width < 16) {
+			/* FIXME. There is a bug with accelerated color-expanded
+			 * transfers in 24 bit mode if the image being transferred
+			 * is less than 16 bits wide. This is due to insufficient
+			 * padding when writing the image. We need to adjust
+			 * struct fb_pixmap. Not yet done. */
+			return cfb_imageblit(info, image);
+		}
+		bltCntl_flags = NEO_BC0_SRC_MONO;
+	} else if (image->depth == info->var.bits_per_pixel) {
+		bltCntl_flags = 0;
+	} else {
+		/* We don't currently support hardware acceleration if image
+		 * depth is different from display */
+		return cfb_imageblit(info, image);
+	}
+
+	switch (info->var.bits_per_pixel) {
+	case 8:
+		writel(image->fg_color, &par->neo2200->fgColor);
+		writel(image->bg_color, &par->neo2200->bgColor);
+		break;
+	case 16:
+	case 24:
+		writel(((u32 *) (info->pseudo_palette))[image->fg_color],
+		       &par->neo2200->fgColor);
+		writel(((u32 *) (info->pseudo_palette))[image->bg_color],
+		       &par->neo2200->bgColor);
+		break;
+	}
+
+	writel(NEO_BC0_SYS_TO_VID |
+		NEO_BC3_SKIP_MAPPING | bltCntl_flags |
+		// NEO_BC3_DST_XY_ADDR |
+		0x0c0000, &par->neo2200->bltCntl);
+
+	writel(0, &par->neo2200->srcStart);
+//      par->neo2200->dstStart = (image->dy << 16) | (image->dx & 0xffff);
+	writel(((image->dx & 0xffff) * (info->var.bits_per_pixel >> 3) +
+		image->dy * info->fix.line_length), &par->neo2200->dstStart);
+	writel((image->height << 16) | (image->width & 0xffff),
+	       &par->neo2200->xyExt);
+
+	memcpy_toio(par->mmio_vbase + 0x100000, image->data, data_len);
+}
+
+static void
+neofb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+	switch (info->fix.accel) {
+		case FB_ACCEL_NEOMAGIC_NM2200:
+		case FB_ACCEL_NEOMAGIC_NM2230: 
+		case FB_ACCEL_NEOMAGIC_NM2360: 
+		case FB_ACCEL_NEOMAGIC_NM2380:
+			neo2200_fillrect(info, rect);
+			break;
+		default:
+			cfb_fillrect(info, rect);
+			break;
+	}	
+}
+
+static void
+neofb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+	switch (info->fix.accel) {
+		case FB_ACCEL_NEOMAGIC_NM2200:
+		case FB_ACCEL_NEOMAGIC_NM2230: 
+		case FB_ACCEL_NEOMAGIC_NM2360: 
+		case FB_ACCEL_NEOMAGIC_NM2380: 
+			neo2200_copyarea(info, area);
+			break;
+		default:
+			cfb_copyarea(info, area);
+			break;
+	}	
+}
+
+static void
+neofb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	switch (info->fix.accel) {
+		case FB_ACCEL_NEOMAGIC_NM2200:
+		case FB_ACCEL_NEOMAGIC_NM2230:
+		case FB_ACCEL_NEOMAGIC_NM2360:
+		case FB_ACCEL_NEOMAGIC_NM2380:
+			neo2200_imageblit(info, image);
+			break;
+		default:
+			cfb_imageblit(info, image);
+			break;
+	}
+}
+
+static int 
+neofb_sync(struct fb_info *info)
+{
+	switch (info->fix.accel) {
+		case FB_ACCEL_NEOMAGIC_NM2200:
+		case FB_ACCEL_NEOMAGIC_NM2230: 
+		case FB_ACCEL_NEOMAGIC_NM2360: 
+		case FB_ACCEL_NEOMAGIC_NM2380: 
+			neo2200_sync(info);
+			break;
+		default:
+			break;
+	}
+	return 0;		
+}
+
+/*
+static void
+neofb_draw_cursor(struct fb_info *info, u8 *dst, u8 *src, unsigned int width)
+{
+	//memset_io(info->sprite.addr, 0xff, 1);
+}
+
+static int
+neofb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+	struct neofb_par *par = (struct neofb_par *) info->par;
+
+	* Disable cursor *
+	write_le32(NEOREG_CURSCNTL, ~NEO_CURS_ENABLE, par);
+
+	if (cursor->set & FB_CUR_SETPOS) {
+		u32 x = cursor->image.dx;
+		u32 y = cursor->image.dy;
+
+		info->cursor.image.dx = x;
+		info->cursor.image.dy = y;
+		write_le32(NEOREG_CURSX, x, par);
+		write_le32(NEOREG_CURSY, y, par);
+	}
+
+	if (cursor->set & FB_CUR_SETSIZE) {
+		info->cursor.image.height = cursor->image.height;
+		info->cursor.image.width = cursor->image.width;
+	}
+
+	if (cursor->set & FB_CUR_SETHOT)
+		info->cursor.hot = cursor->hot;
+
+	if (cursor->set & FB_CUR_SETCMAP) {
+		if (cursor->image.depth == 1) {
+			u32 fg = cursor->image.fg_color;
+			u32 bg = cursor->image.bg_color;
+
+			info->cursor.image.fg_color = fg;
+			info->cursor.image.bg_color = bg;
+
+			fg = ((fg & 0xff0000) >> 16) | ((fg & 0xff) << 16) | (fg & 0xff00);
+			bg = ((bg & 0xff0000) >> 16) | ((bg & 0xff) << 16) | (bg & 0xff00);
+			write_le32(NEOREG_CURSFGCOLOR, fg, par);
+			write_le32(NEOREG_CURSBGCOLOR, bg, par);
+		}
+	}
+
+	if (cursor->set & FB_CUR_SETSHAPE)
+		fb_load_cursor_image(info);
+
+	if (info->cursor.enable)
+		write_le32(NEOREG_CURSCNTL, NEO_CURS_ENABLE, par);
+	return 0;
+}
+*/
+
+static struct fb_ops neofb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_open	= neofb_open,
+	.fb_release	= neofb_release,
+	.fb_check_var	= neofb_check_var,
+	.fb_set_par	= neofb_set_par,
+	.fb_setcolreg	= neofb_setcolreg,
+	.fb_pan_display	= neofb_pan_display,
+	.fb_blank	= neofb_blank,
+	.fb_sync	= neofb_sync,
+	.fb_fillrect	= neofb_fillrect,
+	.fb_copyarea	= neofb_copyarea,
+	.fb_imageblit	= neofb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_videomode __devinitdata mode800x480 = {
+	.xres           = 800,
+	.yres           = 480,
+	.pixclock       = 25000,
+	.left_margin    = 88,
+	.right_margin   = 40,
+	.upper_margin   = 23,
+	.lower_margin   = 1,
+	.hsync_len      = 128,
+	.vsync_len      = 4,
+	.sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	.vmode          = FB_VMODE_NONINTERLACED
+};
+
+static int __devinit neo_map_mmio(struct fb_info *info,
+				  struct pci_dev *dev)
+{
+	struct neofb_par *par = (struct neofb_par *) info->par;
+
+	DBG("neo_map_mmio");
+
+	switch (info->fix.accel) {
+		case FB_ACCEL_NEOMAGIC_NM2070:
+			info->fix.mmio_start = pci_resource_start(dev, 0)+
+				0x100000;
+			break;
+		case FB_ACCEL_NEOMAGIC_NM2090:
+		case FB_ACCEL_NEOMAGIC_NM2093:
+			info->fix.mmio_start = pci_resource_start(dev, 0)+
+				0x200000;
+			break;
+		case FB_ACCEL_NEOMAGIC_NM2160:
+		case FB_ACCEL_NEOMAGIC_NM2097:
+		case FB_ACCEL_NEOMAGIC_NM2200:
+		case FB_ACCEL_NEOMAGIC_NM2230:
+		case FB_ACCEL_NEOMAGIC_NM2360:
+		case FB_ACCEL_NEOMAGIC_NM2380:
+			info->fix.mmio_start = pci_resource_start(dev, 1);
+			break;
+		default:
+			info->fix.mmio_start = pci_resource_start(dev, 0);
+	}
+	info->fix.mmio_len = MMIO_SIZE;
+
+	if (!request_mem_region
+	    (info->fix.mmio_start, MMIO_SIZE, "memory mapped I/O")) {
+		printk("neofb: memory mapped IO in use\n");
+		return -EBUSY;
+	}
+
+	par->mmio_vbase = ioremap(info->fix.mmio_start, MMIO_SIZE);
+	if (!par->mmio_vbase) {
+		printk("neofb: unable to map memory mapped IO\n");
+		release_mem_region(info->fix.mmio_start,
+				   info->fix.mmio_len);
+		return -ENOMEM;
+	} else
+		printk(KERN_INFO "neofb: mapped io at %p\n",
+		       par->mmio_vbase);
+	return 0;
+}
+
+static void neo_unmap_mmio(struct fb_info *info)
+{
+	struct neofb_par *par = (struct neofb_par *) info->par;
+
+	DBG("neo_unmap_mmio");
+
+	iounmap(par->mmio_vbase);
+	par->mmio_vbase = NULL;
+
+	release_mem_region(info->fix.mmio_start,
+			   info->fix.mmio_len);
+}
+
+static int __devinit neo_map_video(struct fb_info *info,
+				   struct pci_dev *dev, int video_len)
+{
+	//unsigned long addr;
+
+	DBG("neo_map_video");
+
+	info->fix.smem_start = pci_resource_start(dev, 0);
+	info->fix.smem_len = video_len;
+
+	if (!request_mem_region(info->fix.smem_start, info->fix.smem_len,
+				"frame buffer")) {
+		printk("neofb: frame buffer in use\n");
+		return -EBUSY;
+	}
+
+	info->screen_base =
+	    ioremap(info->fix.smem_start, info->fix.smem_len);
+	if (!info->screen_base) {
+		printk("neofb: unable to map screen memory\n");
+		release_mem_region(info->fix.smem_start,
+				   info->fix.smem_len);
+		return -ENOMEM;
+	} else
+		printk(KERN_INFO "neofb: mapped framebuffer at %p\n",
+		       info->screen_base);
+
+#ifdef CONFIG_MTRR
+	((struct neofb_par *)(info->par))->mtrr =
+		mtrr_add(info->fix.smem_start, pci_resource_len(dev, 0),
+				MTRR_TYPE_WRCOMB, 1);
+#endif
+
+	/* Clear framebuffer, it's all white in memory after boot */
+	memset_io(info->screen_base, 0, info->fix.smem_len);
+
+	/* Allocate Cursor drawing pad.
+	info->fix.smem_len -= PAGE_SIZE;
+	addr = info->fix.smem_start + info->fix.smem_len;
+	write_le32(NEOREG_CURSMEMPOS, ((0x000f & (addr >> 10)) << 8) |
+					((0x0ff0 & (addr >> 10)) >> 4), par);
+	addr = (unsigned long) info->screen_base + info->fix.smem_len;
+	info->sprite.addr = (u8 *) addr; */
+	return 0;
+}
+
+static void neo_unmap_video(struct fb_info *info)
+{
+	DBG("neo_unmap_video");
+
+#ifdef CONFIG_MTRR
+	{
+		struct neofb_par *par = (struct neofb_par *) info->par;
+
+		mtrr_del(par->mtrr, info->fix.smem_start,
+			 info->fix.smem_len);
+	}
+#endif
+	iounmap(info->screen_base);
+	info->screen_base = NULL;
+
+	release_mem_region(info->fix.smem_start,
+			   info->fix.smem_len);
+}
+
+static int __devinit neo_scan_monitor(struct fb_info *info)
+{
+	struct neofb_par *par = (struct neofb_par *) info->par;
+	unsigned char type, display;
+	int w;
+
+	// Eventually we will have i2c support.
+	info->monspecs.modedb = kmalloc(sizeof(struct fb_videomode), GFP_KERNEL);
+	if (!info->monspecs.modedb)
+		return -ENOMEM;
+	info->monspecs.modedb_len = 1;
+
+	/* Determine the panel type */
+	vga_wgfx(NULL, 0x09, 0x26);
+	type = vga_rgfx(NULL, 0x21);
+	display = vga_rgfx(NULL, 0x20);
+	if (!par->internal_display && !par->external_display) {
+		par->internal_display = display & 2 || !(display & 3) ? 1 : 0;
+		par->external_display = display & 1;
+		printk (KERN_INFO "Autodetected %s display\n",
+			par->internal_display && par->external_display ? "simultaneous" :
+			par->internal_display ? "internal" : "external");
+	}
+
+	/* Determine panel width -- used in NeoValidMode. */
+	w = vga_rgfx(NULL, 0x20);
+	vga_wgfx(NULL, 0x09, 0x00);
+	switch ((w & 0x18) >> 3) {
+	case 0x00:
+		// 640x480@60
+		par->NeoPanelWidth = 640;
+		par->NeoPanelHeight = 480;
+		memcpy(info->monspecs.modedb, &vesa_modes[3], sizeof(struct fb_videomode));
+		break;
+	case 0x01:
+		par->NeoPanelWidth = 800;
+		if (par->libretto) {
+			par->NeoPanelHeight = 480;
+			memcpy(info->monspecs.modedb, &mode800x480, sizeof(struct fb_videomode));
+		} else {
+			// 800x600@60
+			par->NeoPanelHeight = 600;
+			memcpy(info->monspecs.modedb, &vesa_modes[8], sizeof(struct fb_videomode));
+		}
+		break;
+	case 0x02:
+		// 1024x768@60
+		par->NeoPanelWidth = 1024;
+		par->NeoPanelHeight = 768;
+		memcpy(info->monspecs.modedb, &vesa_modes[13], sizeof(struct fb_videomode));
+		break;
+	case 0x03:
+		/* 1280x1024@60 panel support needs to be added */
+#ifdef NOT_DONE
+		par->NeoPanelWidth = 1280;
+		par->NeoPanelHeight = 1024;
+		memcpy(info->monspecs.modedb, &vesa_modes[20], sizeof(struct fb_videomode));
+		break;
+#else
+		printk(KERN_ERR
+		       "neofb: Only 640x480, 800x600/480 and 1024x768 panels are currently supported\n");
+		return -1;
+#endif
+	default:
+		// 640x480@60
+		par->NeoPanelWidth = 640;
+		par->NeoPanelHeight = 480;
+		memcpy(info->monspecs.modedb, &vesa_modes[3], sizeof(struct fb_videomode));
+		break;
+	}
+
+	printk(KERN_INFO "Panel is a %dx%d %s %s display\n",
+	       par->NeoPanelWidth,
+	       par->NeoPanelHeight,
+	       (type & 0x02) ? "color" : "monochrome",
+	       (type & 0x10) ? "TFT" : "dual scan");
+	return 0;
+}
+
+static int __devinit neo_init_hw(struct fb_info *info)
+{
+	struct neofb_par *par = (struct neofb_par *) info->par;
+	int videoRam = 896;
+	int maxClock = 65000;
+	int CursorMem = 1024;
+	int CursorOff = 0x100;
+	int linearSize = 1024;
+	int maxWidth = 1024;
+	int maxHeight = 1024;
+
+	DBG("neo_init_hw");
+
+	neoUnlock();
+
+#if 0
+	printk(KERN_DEBUG "--- Neo extended register dump ---\n");
+	for (int w = 0; w < 0x85; w++)
+		printk(KERN_DEBUG "CR %p: %p\n", (void *) w,
+		       (void *) vga_rcrt(NULL, w);
+	for (int w = 0; w < 0xC7; w++)
+		printk(KERN_DEBUG "GR %p: %p\n", (void *) w,
+		       (void *) vga_rgfx(NULL, w));
+#endif
+	switch (info->fix.accel) {
+	case FB_ACCEL_NEOMAGIC_NM2070:
+		videoRam = 896;
+		maxClock = 65000;
+		CursorMem = 2048;
+		CursorOff = 0x100;
+		linearSize = 1024;
+		maxWidth = 1024;
+		maxHeight = 1024;
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2090:
+	case FB_ACCEL_NEOMAGIC_NM2093:
+		videoRam = 1152;
+		maxClock = 80000;
+		CursorMem = 2048;
+		CursorOff = 0x100;
+		linearSize = 2048;
+		maxWidth = 1024;
+		maxHeight = 1024;
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2097:
+		videoRam = 1152;
+		maxClock = 80000;
+		CursorMem = 1024;
+		CursorOff = 0x100;
+		linearSize = 2048;
+		maxWidth = 1024;
+		maxHeight = 1024;
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2160:
+		videoRam = 2048;
+		maxClock = 90000;
+		CursorMem = 1024;
+		CursorOff = 0x100;
+		linearSize = 2048;
+		maxWidth = 1024;
+		maxHeight = 1024;
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2200:
+		videoRam = 2560;
+		maxClock = 110000;
+		CursorMem = 1024;
+		CursorOff = 0x1000;
+		linearSize = 4096;
+		maxWidth = 1280;
+		maxHeight = 1024;	/* ???? */
+
+		par->neo2200 = (Neo2200 __iomem *) par->mmio_vbase;
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2230:
+		videoRam = 3008;
+		maxClock = 110000;
+		CursorMem = 1024;
+		CursorOff = 0x1000;
+		linearSize = 4096;
+		maxWidth = 1280;
+		maxHeight = 1024;	/* ???? */
+
+		par->neo2200 = (Neo2200 __iomem *) par->mmio_vbase;
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2360:
+		videoRam = 4096;
+		maxClock = 110000;
+		CursorMem = 1024;
+		CursorOff = 0x1000;
+		linearSize = 4096;
+		maxWidth = 1280;
+		maxHeight = 1024;	/* ???? */
+
+		par->neo2200 = (Neo2200 __iomem *) par->mmio_vbase;
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2380:
+		videoRam = 6144;
+		maxClock = 110000;
+		CursorMem = 1024;
+		CursorOff = 0x1000;
+		linearSize = 8192;
+		maxWidth = 1280;
+		maxHeight = 1024;	/* ???? */
+
+		par->neo2200 = (Neo2200 __iomem *) par->mmio_vbase;
+		break;
+	}
+/*
+	info->sprite.size = CursorMem;
+	info->sprite.scan_align = 1;
+	info->sprite.buf_align = 1;
+	info->sprite.flags = FB_PIXMAP_IO;
+	info->sprite.outbuf = neofb_draw_cursor;
+*/
+	par->maxClock = maxClock;
+	par->cursorOff = CursorOff;
+	return ((videoRam * 1024));
+}
+
+
+static struct fb_info *__devinit neo_alloc_fb_info(struct pci_dev *dev, const struct
+						   pci_device_id *id)
+{
+	struct fb_info *info;
+	struct neofb_par *par;
+
+	info = framebuffer_alloc(sizeof(struct neofb_par) + sizeof(u32) * 256, &dev->dev);
+
+	if (!info)
+		return NULL;
+
+	par = info->par;
+
+	info->fix.accel = id->driver_data;
+
+	par->pci_burst = !nopciburst;
+	par->lcd_stretch = !nostretch;
+	par->libretto = libretto;
+
+	par->internal_display = internal;
+	par->external_display = external;
+	info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+
+	switch (info->fix.accel) {
+	case FB_ACCEL_NEOMAGIC_NM2070:
+		sprintf(info->fix.id, "MagicGraph 128");
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2090:
+		sprintf(info->fix.id, "MagicGraph 128V");
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2093:
+		sprintf(info->fix.id, "MagicGraph 128ZV");
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2097:
+		sprintf(info->fix.id, "MagicGraph 128ZV+");
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2160:
+		sprintf(info->fix.id, "MagicGraph 128XD");
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2200:
+		sprintf(info->fix.id, "MagicGraph 256AV");
+		info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
+		               FBINFO_HWACCEL_COPYAREA |
+                	       FBINFO_HWACCEL_FILLRECT;
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2230:
+		sprintf(info->fix.id, "MagicGraph 256AV+");
+		info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
+		               FBINFO_HWACCEL_COPYAREA |
+                	       FBINFO_HWACCEL_FILLRECT;
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2360:
+		sprintf(info->fix.id, "MagicGraph 256ZX");
+		info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
+		               FBINFO_HWACCEL_COPYAREA |
+                	       FBINFO_HWACCEL_FILLRECT;
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2380:
+		sprintf(info->fix.id, "MagicGraph 256XL+");
+		info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
+		               FBINFO_HWACCEL_COPYAREA |
+                	       FBINFO_HWACCEL_FILLRECT;
+		break;
+	}
+
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.type_aux = 0;
+	info->fix.xpanstep = 0;
+	info->fix.ypanstep = 4;
+	info->fix.ywrapstep = 0;
+	info->fix.accel = id->driver_data;
+
+	info->fbops = &neofb_ops;
+	info->pseudo_palette = (void *) (par + 1);
+	return info;
+}
+
+static void neo_free_fb_info(struct fb_info *info)
+{
+	if (info) {
+		/*
+		 * Free the colourmap
+		 */
+		fb_dealloc_cmap(&info->cmap);
+		framebuffer_release(info);
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+static int __devinit neofb_probe(struct pci_dev *dev,
+				 const struct pci_device_id *id)
+{
+	struct fb_info *info;
+	u_int h_sync, v_sync;
+	int video_len, err;
+
+	DBG("neofb_probe");
+
+	err = pci_enable_device(dev);
+	if (err)
+		return err;
+
+	err = -ENOMEM;
+	info = neo_alloc_fb_info(dev, id);
+	if (!info)
+		return err;
+
+	err = neo_map_mmio(info, dev);
+	if (err)
+		goto err_map_mmio;
+
+	err = neo_scan_monitor(info);
+	if (err)
+		goto err_scan_monitor;
+
+	video_len = neo_init_hw(info);
+	if (video_len < 0) {
+		err = video_len;
+		goto err_init_hw;
+	}
+
+	err = neo_map_video(info, dev, video_len);
+	if (err)
+		goto err_init_hw;
+
+	if (!fb_find_mode(&info->var, info, mode_option, NULL, 0,
+			info->monspecs.modedb, 16)) {
+		printk(KERN_ERR "neofb: Unable to find usable video mode.\n");
+		goto err_map_video;
+	}
+
+	/*
+	 * Calculate the hsync and vsync frequencies.  Note that
+	 * we split the 1e12 constant up so that we can preserve
+	 * the precision and fit the results into 32-bit registers.
+	 *  (1953125000 * 512 = 1e12)
+	 */
+	h_sync = 1953125000 / info->var.pixclock;
+	h_sync =
+	    h_sync * 512 / (info->var.xres + info->var.left_margin +
+			    info->var.right_margin + info->var.hsync_len);
+	v_sync =
+	    h_sync / (info->var.yres + info->var.upper_margin +
+		      info->var.lower_margin + info->var.vsync_len);
+
+	printk(KERN_INFO "neofb v" NEOFB_VERSION
+	       ": %dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
+	       info->fix.smem_len >> 10, info->var.xres,
+	       info->var.yres, h_sync / 1000, h_sync % 1000, v_sync);
+
+	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
+		goto err_map_video;
+
+	err = register_framebuffer(info);
+	if (err < 0)
+		goto err_reg_fb;
+
+	printk(KERN_INFO "fb%d: %s frame buffer device\n",
+	       info->node, info->fix.id);
+
+	/*
+	 * Our driver data
+	 */
+	pci_set_drvdata(dev, info);
+	return 0;
+
+err_reg_fb:
+	fb_dealloc_cmap(&info->cmap);
+err_map_video:
+	neo_unmap_video(info);
+err_init_hw:
+	fb_destroy_modedb(info->monspecs.modedb);
+err_scan_monitor:
+	neo_unmap_mmio(info);
+err_map_mmio:
+	neo_free_fb_info(info);
+	return err;
+}
+
+static void __devexit neofb_remove(struct pci_dev *dev)
+{
+	struct fb_info *info = pci_get_drvdata(dev);
+
+	DBG("neofb_remove");
+
+	if (info) {
+		/*
+		 * If unregister_framebuffer fails, then
+		 * we will be leaving hooks that could cause
+		 * oopsen laying around.
+		 */
+		if (unregister_framebuffer(info))
+			printk(KERN_WARNING
+			       "neofb: danger danger!  Oopsen imminent!\n");
+
+		neo_unmap_video(info);
+		fb_destroy_modedb(info->monspecs.modedb);
+		neo_unmap_mmio(info);
+		neo_free_fb_info(info);
+
+		/*
+		 * Ensure that the driver data is no longer
+		 * valid.
+		 */
+		pci_set_drvdata(dev, NULL);
+	}
+}
+
+static struct pci_device_id neofb_devices[] = {
+	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2070,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2070},
+
+	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2090,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2090},
+
+	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2093,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2093},
+
+	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2097,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2097},
+
+	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2160,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2160},
+
+	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2200,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2200},
+
+	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2230,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2230},
+
+	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2360,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2360},
+
+	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2380,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2380},
+
+	{0, 0, 0, 0, 0, 0, 0}
+};
+
+MODULE_DEVICE_TABLE(pci, neofb_devices);
+
+static struct pci_driver neofb_driver = {
+	.name =		"neofb",
+	.id_table =	neofb_devices,
+	.probe =	neofb_probe,
+	.remove =	__devexit_p(neofb_remove)
+};
+
+/* ************************* init in-kernel code ************************** */
+
+#ifndef MODULE
+static int __init neofb_setup(char *options)
+{
+	char *this_opt;
+
+	DBG("neofb_setup");
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt)
+			continue;
+
+		if (!strncmp(this_opt, "internal", 8))
+			internal = 1;
+		else if (!strncmp(this_opt, "external", 8))
+			external = 1;
+		else if (!strncmp(this_opt, "nostretch", 9))
+			nostretch = 1;
+		else if (!strncmp(this_opt, "nopciburst", 10))
+			nopciburst = 1;
+		else if (!strncmp(this_opt, "libretto", 8))
+			libretto = 1;
+		else
+			mode_option = this_opt;
+	}
+	return 0;
+}
+#endif  /*  MODULE  */
+
+static int __init neofb_init(void)
+{
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("neofb", &option))
+		return -ENODEV;
+	neofb_setup(option);
+#endif
+	return pci_register_driver(&neofb_driver);
+}
+
+module_init(neofb_init);
+
+#ifdef MODULE
+static void __exit neofb_exit(void)
+{
+	pci_unregister_driver(&neofb_driver);
+}
+
+module_exit(neofb_exit);
+#endif				/* MODULE */
diff --git a/drivers/video/nvidia/Makefile b/drivers/video/nvidia/Makefile
new file mode 100644
index 0000000..690d37e
--- /dev/null
+++ b/drivers/video/nvidia/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for the nVidia framebuffer driver
+#
+
+obj-$(CONFIG_FB_NVIDIA)          += nvidiafb.o
+
+nvidiafb-y                       := nvidia.o nv_hw.o nv_setup.o \
+			            nv_accel.o
+nvidiafb-$(CONFIG_FB_NVIDIA_I2C) += nv_i2c.o
+nvidiafb-$(CONFIG_PPC_OF)	 += nv_of.o
+
+nvidiafb-objs                    := $(nvidiafb-y)
\ No newline at end of file
diff --git a/drivers/video/nvidia/nv_accel.c b/drivers/video/nvidia/nv_accel.c
new file mode 100644
index 0000000..f377a29
--- /dev/null
+++ b/drivers/video/nvidia/nv_accel.c
@@ -0,0 +1,419 @@
+ /***************************************************************************\
+|*                                                                           *|
+|*       Copyright 1993-2003 NVIDIA, Corporation.  All rights reserved.      *|
+|*                                                                           *|
+|*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
+|*     international laws.  Users and possessors of this source code are     *|
+|*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
+|*     use this code in individual and commercial software.                  *|
+|*                                                                           *|
+|*     Any use of this source code must include,  in the user documenta-     *|
+|*     tion and  internal comments to the code,  notices to the end user     *|
+|*     as follows:                                                           *|
+|*                                                                           *|
+|*       Copyright 1993-2003 NVIDIA, Corporation.  All rights reserved.      *|
+|*                                                                           *|
+|*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
+|*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
+|*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
+|*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
+|*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
+|*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
+|*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
+|*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
+|*     SULTING FROM LOSS OF USE,  DATA OR PROFITS,  WHETHER IN AN ACTION     *|
+|*     OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,  ARISING OUT OF     *|
+|*     OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.     *|
+|*                                                                           *|
+|*     U.S. Government  End  Users.   This source code  is a "commercial     *|
+|*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
+|*     consisting  of "commercial  computer  software"  and  "commercial     *|
+|*     computer  software  documentation,"  as such  terms  are  used in     *|
+|*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
+|*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
+|*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
+|*     all U.S. Government End Users  acquire the source code  with only     *|
+|*     those rights set forth herein.                                        *|
+|*                                                                           *|
+ \***************************************************************************/
+
+/*
+ * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/
+ * XFree86 'nv' driver, this source code is provided under MIT-style licensing
+ * where the source code is provided "as is" without warranty of any kind.
+ * The only usage restriction is for the copyright notices to be retained
+ * whenever code is used.
+ *
+ * Antonino Daplas <adaplas@pol.net> 2005-03-11
+ */
+
+#include <linux/fb.h>
+#include "nv_type.h"
+#include "nv_proto.h"
+#include "nv_dma.h"
+#include "nv_local.h"
+
+/* There is a HW race condition with videoram command buffers.
+   You can't jump to the location of your put offset.  We write put
+   at the jump offset + SKIPS dwords with noop padding in between
+   to solve this problem */
+#define SKIPS  8
+
+static const int NVCopyROP[16] = {
+	0xCC,			/* copy   */
+	0x55			/* invert */
+};
+
+static const int NVCopyROP_PM[16] = {
+	0xCA,			/* copy  */
+	0x5A,			/* invert */
+};
+
+static inline void NVFlush(struct nvidia_par *par)
+{
+	int count = 1000000000;
+
+	while (--count && READ_GET(par) != par->dmaPut) ;
+
+	if (!count) {
+		printk("nvidiafb: DMA Flush lockup\n");
+		par->lockup = 1;
+	}
+}
+
+static inline void NVSync(struct nvidia_par *par)
+{
+	int count = 1000000000;
+
+	while (--count && NV_RD32(par->PGRAPH, 0x0700)) ;
+
+	if (!count) {
+		printk("nvidiafb: DMA Sync lockup\n");
+		par->lockup = 1;
+	}
+}
+
+static void NVDmaKickoff(struct nvidia_par *par)
+{
+	if (par->dmaCurrent != par->dmaPut) {
+		par->dmaPut = par->dmaCurrent;
+		WRITE_PUT(par, par->dmaPut);
+	}
+}
+
+static void NVDmaWait(struct nvidia_par *par, int size)
+{
+	int dmaGet;
+	int count = 1000000000, cnt;
+	size++;
+
+	while (par->dmaFree < size && --count && !par->lockup) {
+		dmaGet = READ_GET(par);
+
+		if (par->dmaPut >= dmaGet) {
+			par->dmaFree = par->dmaMax - par->dmaCurrent;
+			if (par->dmaFree < size) {
+				NVDmaNext(par, 0x20000000);
+				if (dmaGet <= SKIPS) {
+					if (par->dmaPut <= SKIPS)
+						WRITE_PUT(par, SKIPS + 1);
+					cnt = 1000000000;
+					do {
+						dmaGet = READ_GET(par);
+					} while (--cnt && dmaGet <= SKIPS);
+					if (!cnt) {
+						printk("DMA Get lockup\n");
+						par->lockup = 1;
+					}
+				}
+				WRITE_PUT(par, SKIPS);
+				par->dmaCurrent = par->dmaPut = SKIPS;
+				par->dmaFree = dmaGet - (SKIPS + 1);
+			}
+		} else
+			par->dmaFree = dmaGet - par->dmaCurrent - 1;
+	}
+
+	if (!count) {
+		printk("DMA Wait Lockup\n");
+		par->lockup = 1;
+	}
+}
+
+static void NVSetPattern(struct nvidia_par *par, u32 clr0, u32 clr1,
+			 u32 pat0, u32 pat1)
+{
+	NVDmaStart(par, PATTERN_COLOR_0, 4);
+	NVDmaNext(par, clr0);
+	NVDmaNext(par, clr1);
+	NVDmaNext(par, pat0);
+	NVDmaNext(par, pat1);
+}
+
+static void NVSetRopSolid(struct nvidia_par *par, u32 rop, u32 planemask)
+{
+	if (planemask != ~0) {
+		NVSetPattern(par, 0, planemask, ~0, ~0);
+		if (par->currentRop != (rop + 32)) {
+			NVDmaStart(par, ROP_SET, 1);
+			NVDmaNext(par, NVCopyROP_PM[rop]);
+			par->currentRop = rop + 32;
+		}
+	} else if (par->currentRop != rop) {
+		if (par->currentRop >= 16)
+			NVSetPattern(par, ~0, ~0, ~0, ~0);
+		NVDmaStart(par, ROP_SET, 1);
+		NVDmaNext(par, NVCopyROP[rop]);
+		par->currentRop = rop;
+	}
+}
+
+static void NVSetClippingRectangle(struct fb_info *info, int x1, int y1,
+				   int x2, int y2)
+{
+	struct nvidia_par *par = info->par;
+	int h = y2 - y1 + 1;
+	int w = x2 - x1 + 1;
+
+	NVDmaStart(par, CLIP_POINT, 2);
+	NVDmaNext(par, (y1 << 16) | x1);
+	NVDmaNext(par, (h << 16) | w);
+}
+
+void NVResetGraphics(struct fb_info *info)
+{
+	struct nvidia_par *par = info->par;
+	u32 surfaceFormat, patternFormat, rectFormat, lineFormat;
+	int pitch, i;
+
+	pitch = info->fix.line_length;
+
+	par->dmaBase = (u32 __iomem *) (&par->FbStart[par->FbUsableSize]);
+
+	for (i = 0; i < SKIPS; i++)
+		NV_WR32(&par->dmaBase[i], 0, 0x00000000);
+
+	NV_WR32(&par->dmaBase[0x0 + SKIPS], 0, 0x00040000);
+	NV_WR32(&par->dmaBase[0x1 + SKIPS], 0, 0x80000010);
+	NV_WR32(&par->dmaBase[0x2 + SKIPS], 0, 0x00042000);
+	NV_WR32(&par->dmaBase[0x3 + SKIPS], 0, 0x80000011);
+	NV_WR32(&par->dmaBase[0x4 + SKIPS], 0, 0x00044000);
+	NV_WR32(&par->dmaBase[0x5 + SKIPS], 0, 0x80000012);
+	NV_WR32(&par->dmaBase[0x6 + SKIPS], 0, 0x00046000);
+	NV_WR32(&par->dmaBase[0x7 + SKIPS], 0, 0x80000013);
+	NV_WR32(&par->dmaBase[0x8 + SKIPS], 0, 0x00048000);
+	NV_WR32(&par->dmaBase[0x9 + SKIPS], 0, 0x80000014);
+	NV_WR32(&par->dmaBase[0xA + SKIPS], 0, 0x0004A000);
+	NV_WR32(&par->dmaBase[0xB + SKIPS], 0, 0x80000015);
+	NV_WR32(&par->dmaBase[0xC + SKIPS], 0, 0x0004C000);
+	NV_WR32(&par->dmaBase[0xD + SKIPS], 0, 0x80000016);
+	NV_WR32(&par->dmaBase[0xE + SKIPS], 0, 0x0004E000);
+	NV_WR32(&par->dmaBase[0xF + SKIPS], 0, 0x80000017);
+
+	par->dmaPut = 0;
+	par->dmaCurrent = 16 + SKIPS;
+	par->dmaMax = 8191;
+	par->dmaFree = par->dmaMax - par->dmaCurrent;
+
+	switch (info->var.bits_per_pixel) {
+	case 32:
+	case 24:
+		surfaceFormat = SURFACE_FORMAT_DEPTH24;
+		patternFormat = PATTERN_FORMAT_DEPTH24;
+		rectFormat = RECT_FORMAT_DEPTH24;
+		lineFormat = LINE_FORMAT_DEPTH24;
+		break;
+	case 16:
+		surfaceFormat = SURFACE_FORMAT_DEPTH16;
+		patternFormat = PATTERN_FORMAT_DEPTH16;
+		rectFormat = RECT_FORMAT_DEPTH16;
+		lineFormat = LINE_FORMAT_DEPTH16;
+		break;
+	default:
+		surfaceFormat = SURFACE_FORMAT_DEPTH8;
+		patternFormat = PATTERN_FORMAT_DEPTH8;
+		rectFormat = RECT_FORMAT_DEPTH8;
+		lineFormat = LINE_FORMAT_DEPTH8;
+		break;
+	}
+
+	NVDmaStart(par, SURFACE_FORMAT, 4);
+	NVDmaNext(par, surfaceFormat);
+	NVDmaNext(par, pitch | (pitch << 16));
+	NVDmaNext(par, 0);
+	NVDmaNext(par, 0);
+
+	NVDmaStart(par, PATTERN_FORMAT, 1);
+	NVDmaNext(par, patternFormat);
+
+	NVDmaStart(par, RECT_FORMAT, 1);
+	NVDmaNext(par, rectFormat);
+
+	NVDmaStart(par, LINE_FORMAT, 1);
+	NVDmaNext(par, lineFormat);
+
+	par->currentRop = ~0;	/* set to something invalid */
+	NVSetRopSolid(par, ROP_COPY, ~0);
+
+	NVSetClippingRectangle(info, 0, 0, info->var.xres_virtual,
+			       info->var.yres_virtual);
+
+	NVDmaKickoff(par);
+}
+
+u8 byte_rev[256] = {
+	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+};
+
+int nvidiafb_sync(struct fb_info *info)
+{
+	struct nvidia_par *par = info->par;
+
+	if (!par->lockup)
+		NVFlush(par);
+
+	if (!par->lockup)
+		NVSync(par);
+
+	return 0;
+}
+
+void nvidiafb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
+{
+	struct nvidia_par *par = info->par;
+
+	if (par->lockup)
+		return cfb_copyarea(info, region);
+
+	NVDmaStart(par, BLIT_POINT_SRC, 3);
+	NVDmaNext(par, (region->sy << 16) | region->sx);
+	NVDmaNext(par, (region->dy << 16) | region->dx);
+	NVDmaNext(par, (region->height << 16) | region->width);
+
+	NVDmaKickoff(par);
+}
+
+void nvidiafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+	struct nvidia_par *par = info->par;
+	u32 color;
+
+	if (par->lockup)
+		return cfb_fillrect(info, rect);
+
+	if (info->var.bits_per_pixel == 8)
+		color = rect->color;
+	else
+		color = ((u32 *) info->pseudo_palette)[rect->color];
+
+	if (rect->rop != ROP_COPY)
+		NVSetRopSolid(par, rect->rop, ~0);
+
+	NVDmaStart(par, RECT_SOLID_COLOR, 1);
+	NVDmaNext(par, color);
+
+	NVDmaStart(par, RECT_SOLID_RECTS(0), 2);
+	NVDmaNext(par, (rect->dx << 16) | rect->dy);
+	NVDmaNext(par, (rect->width << 16) | rect->height);
+
+	NVDmaKickoff(par);
+
+	if (rect->rop != ROP_COPY)
+		NVSetRopSolid(par, ROP_COPY, ~0);
+}
+
+static void nvidiafb_mono_color_expand(struct fb_info *info,
+				       const struct fb_image *image)
+{
+	struct nvidia_par *par = info->par;
+	u32 fg, bg, mask = ~(~0 >> (32 - info->var.bits_per_pixel));
+	u32 dsize, width, *data = (u32 *) image->data, tmp;
+	int j, k = 0;
+
+	width = (image->width + 31) & ~31;
+	dsize = (width * image->height) >> 5;
+
+	if (info->var.bits_per_pixel == 8) {
+		fg = image->fg_color | mask;
+		bg = image->bg_color | mask;
+	} else {
+		fg = ((u32 *) info->pseudo_palette)[image->fg_color] | mask;
+		bg = ((u32 *) info->pseudo_palette)[image->bg_color] | mask;
+	}
+
+	NVDmaStart(par, RECT_EXPAND_TWO_COLOR_CLIP, 7);
+	NVDmaNext(par, (image->dy << 16) | (image->dx & 0xffff));
+	NVDmaNext(par, ((image->dy + image->height) << 16) |
+		  ((image->dx + image->width) & 0xffff));
+	NVDmaNext(par, bg);
+	NVDmaNext(par, fg);
+	NVDmaNext(par, (image->height << 16) | width);
+	NVDmaNext(par, (image->height << 16) | width);
+	NVDmaNext(par, (image->dy << 16) | (image->dx & 0xffff));
+
+	while (dsize >= RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS) {
+		NVDmaStart(par, RECT_EXPAND_TWO_COLOR_DATA(0),
+			   RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS);
+
+		for (j = RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS; j--;) {
+			tmp = data[k++];
+			reverse_order(&tmp);
+			NVDmaNext(par, tmp);
+		}
+
+		dsize -= RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS;
+	}
+
+	if (dsize) {
+		NVDmaStart(par, RECT_EXPAND_TWO_COLOR_DATA(0), dsize);
+
+		for (j = dsize; j--;) {
+			tmp = data[k++];
+			reverse_order(&tmp);
+			NVDmaNext(par, tmp);
+		}
+	}
+
+	NVDmaKickoff(par);
+}
+
+void nvidiafb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	struct nvidia_par *par = info->par;
+
+	if (image->depth == 1 && !par->lockup)
+		nvidiafb_mono_color_expand(info, image);
+	else
+		cfb_imageblit(info, image);
+}
diff --git a/drivers/video/nvidia/nv_dma.h b/drivers/video/nvidia/nv_dma.h
new file mode 100644
index 0000000..a7ed1c0
--- /dev/null
+++ b/drivers/video/nvidia/nv_dma.h
@@ -0,0 +1,188 @@
+
+ /***************************************************************************\
+|*                                                                           *|
+|*       Copyright 2003 NVIDIA, Corporation.  All rights reserved.           *|
+|*                                                                           *|
+|*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
+|*     international laws.  Users and possessors of this source code are     *|
+|*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
+|*     use this code in individual and commercial software.                  *|
+|*                                                                           *|
+|*     Any use of this source code must include,  in the user documenta-     *|
+|*     tion and  internal comments to the code,  notices to the end user     *|
+|*     as follows:                                                           *|
+|*                                                                           *|
+|*       Copyright 2003 NVIDIA, Corporation.  All rights reserved.           *|
+|*                                                                           *|
+|*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
+|*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
+|*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
+|*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
+|*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
+|*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
+|*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
+|*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
+|*     SULTING FROM LOSS OF USE,  DATA OR PROFITS,  WHETHER IN AN ACTION     *|
+|*     OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,  ARISING OUT OF     *|
+|*     OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.     *|
+|*                                                                           *|
+|*     U.S. Government  End  Users.   This source code  is a "commercial     *|
+|*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
+|*     consisting  of "commercial  computer  software"  and  "commercial     *|
+|*     computer  software  documentation,"  as such  terms  are  used in     *|
+|*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
+|*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
+|*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
+|*     all U.S. Government End Users  acquire the source code  with only     *|
+|*     those rights set forth herein.                                        *|
+|*                                                                           *|
+ \***************************************************************************/
+
+/*
+ * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/
+ * XFree86 'nv' driver, this source code is provided under MIT-style licensing
+ * where the source code is provided "as is" without warranty of any kind.
+ * The only usage restriction is for the copyright notices to be retained
+ * whenever code is used.
+ *
+ * Antonino Daplas <adaplas@pol.net> 2005-03-11
+ */
+
+#define SURFACE_FORMAT                                              0x00000300
+#define SURFACE_FORMAT_DEPTH8                                       0x00000001
+#define SURFACE_FORMAT_DEPTH15                                      0x00000002
+#define SURFACE_FORMAT_DEPTH16                                      0x00000004
+#define SURFACE_FORMAT_DEPTH24                                      0x00000006
+#define SURFACE_PITCH                                               0x00000304
+#define SURFACE_PITCH_SRC                                           15:0
+#define SURFACE_PITCH_DST                                           31:16
+#define SURFACE_OFFSET_SRC                                          0x00000308
+#define SURFACE_OFFSET_DST                                          0x0000030C
+
+#define ROP_SET                                                     0x00002300
+
+#define PATTERN_FORMAT                                              0x00004300
+#define PATTERN_FORMAT_DEPTH8                                       0x00000003
+#define PATTERN_FORMAT_DEPTH16                                      0x00000001
+#define PATTERN_FORMAT_DEPTH24                                      0x00000003
+#define PATTERN_COLOR_0                                             0x00004310
+#define PATTERN_COLOR_1                                             0x00004314
+#define PATTERN_PATTERN_0                                           0x00004318
+#define PATTERN_PATTERN_1                                           0x0000431C
+
+#define CLIP_POINT                                                  0x00006300
+#define CLIP_POINT_X                                                15:0
+#define CLIP_POINT_Y                                                31:16
+#define CLIP_SIZE                                                   0x00006304
+#define CLIP_SIZE_WIDTH                                             15:0
+#define CLIP_SIZE_HEIGHT                                            31:16
+
+#define LINE_FORMAT                                                 0x00008300
+#define LINE_FORMAT_DEPTH8                                          0x00000003
+#define LINE_FORMAT_DEPTH16                                         0x00000001
+#define LINE_FORMAT_DEPTH24                                         0x00000003
+#define LINE_COLOR                                                  0x00008304
+#define LINE_MAX_LINES                                              16
+#define LINE_LINES(i)                                               0x00008400\
+                                                                    +(i)*8
+#define LINE_LINES_POINT0_X                                         15:0
+#define LINE_LINES_POINT0_Y                                         31:16
+#define LINE_LINES_POINT1_X                                         47:32
+#define LINE_LINES_POINT1_Y                                         63:48
+
+#define BLIT_POINT_SRC                                              0x0000A300
+#define BLIT_POINT_SRC_X                                            15:0
+#define BLIT_POINT_SRC_Y                                            31:16
+#define BLIT_POINT_DST                                              0x0000A304
+#define BLIT_POINT_DST_X                                            15:0
+#define BLIT_POINT_DST_Y                                            31:16
+#define BLIT_SIZE                                                   0x0000A308
+#define BLIT_SIZE_WIDTH                                             15:0
+#define BLIT_SIZE_HEIGHT                                            31:16
+
+#define RECT_FORMAT                                                 0x0000C300
+#define RECT_FORMAT_DEPTH8                                          0x00000003
+#define RECT_FORMAT_DEPTH16                                         0x00000001
+#define RECT_FORMAT_DEPTH24                                         0x00000003
+#define RECT_SOLID_COLOR                                            0x0000C3FC
+#define RECT_SOLID_RECTS_MAX_RECTS                                  32
+#define RECT_SOLID_RECTS(i)                                         0x0000C400\
+                                                                    +(i)*8
+#define RECT_SOLID_RECTS_Y                                          15:0
+#define RECT_SOLID_RECTS_X                                          31:16
+#define RECT_SOLID_RECTS_HEIGHT                                     47:32
+#define RECT_SOLID_RECTS_WIDTH                                      63:48
+
+#define RECT_EXPAND_ONE_COLOR_CLIP                                  0x0000C7EC
+#define RECT_EXPAND_ONE_COLOR_CLIP_POINT0_X                         15:0
+#define RECT_EXPAND_ONE_COLOR_CLIP_POINT0_Y                         31:16
+#define RECT_EXPAND_ONE_COLOR_CLIP_POINT1_X                         47:32
+#define RECT_EXPAND_ONE_COLOR_CLIP_POINT1_Y                         63:48
+#define RECT_EXPAND_ONE_COLOR_COLOR                                 0x0000C7F4
+#define RECT_EXPAND_ONE_COLOR_SIZE                                  0x0000C7F8
+#define RECT_EXPAND_ONE_COLOR_SIZE_WIDTH                            15:0
+#define RECT_EXPAND_ONE_COLOR_SIZE_HEIGHT                           31:16
+#define RECT_EXPAND_ONE_COLOR_POINT                                 0x0000C7FC
+#define RECT_EXPAND_ONE_COLOR_POINT_X                               15:0
+#define RECT_EXPAND_ONE_COLOR_POINT_Y                               31:16
+#define RECT_EXPAND_ONE_COLOR_DATA_MAX_DWORDS                       128
+#define RECT_EXPAND_ONE_COLOR_DATA(i)                               0x0000C800\
+                                                                    +(i)*4
+
+#define RECT_EXPAND_TWO_COLOR_CLIP                                  0x0000CBE4
+#define RECT_EXPAND_TWO_COLOR_CLIP_POINT0_X                         15:0
+#define RECT_EXPAND_TWO_COLOR_CLIP_POINT0_Y                         31:16
+#define RECT_EXPAND_TWO_COLOR_CLIP_POINT1_X                         47:32
+#define RECT_EXPAND_TWO_COLOR_CLIP_POINT1_Y                         63:48
+#define RECT_EXPAND_TWO_COLOR_COLOR_0                               0x0000CBEC
+#define RECT_EXPAND_TWO_COLOR_COLOR_1                               0x0000CBF0
+#define RECT_EXPAND_TWO_COLOR_SIZE_IN                               0x0000CBF4
+#define RECT_EXPAND_TWO_COLOR_SIZE_IN_WIDTH                         15:0
+#define RECT_EXPAND_TWO_COLOR_SIZE_IN_HEIGHT                        31:16
+#define RECT_EXPAND_TWO_COLOR_SIZE_OUT                              0x0000CBF8
+#define RECT_EXPAND_TWO_COLOR_SIZE_OUT_WIDTH                        15:0
+#define RECT_EXPAND_TWO_COLOR_SIZE_OUT_HEIGHT                       31:16
+#define RECT_EXPAND_TWO_COLOR_POINT                                 0x0000CBFC
+#define RECT_EXPAND_TWO_COLOR_POINT_X                               15:0
+#define RECT_EXPAND_TWO_COLOR_POINT_Y                               31:16
+#define RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS                       128
+#define RECT_EXPAND_TWO_COLOR_DATA(i)                               0x0000CC00\
+                                                                    +(i)*4
+
+#define STRETCH_BLIT_FORMAT                                         0x0000E300
+#define STRETCH_BLIT_FORMAT_DEPTH8                                  0x00000004
+#define STRETCH_BLIT_FORMAT_DEPTH16                                 0x00000007
+#define STRETCH_BLIT_FORMAT_DEPTH24                                 0x00000004
+#define STRETCH_BLIT_FORMAT_X8R8G8B8                                0x00000004
+#define STRETCH_BLIT_FORMAT_YUYV                                    0x00000005
+#define STRETCH_BLIT_FORMAT_UYVY                                    0x00000006
+#define STRETCH_BLIT_CLIP_POINT                                     0x0000E308
+#define STRETCH_BLIT_CLIP_POINT_X                                   15:0
+#define STRETCH_BLIT_CLIP_POINT_Y                                   31:16
+#define STRETCH_BLIT_CLIP_POINT                                     0x0000E308
+#define STRETCH_BLIT_CLIP_SIZE                                      0x0000E30C
+#define STRETCH_BLIT_CLIP_SIZE_WIDTH                                15:0
+#define STRETCH_BLIT_CLIP_SIZE_HEIGHT                               31:16
+#define STRETCH_BLIT_DST_POINT                                      0x0000E310
+#define STRETCH_BLIT_DST_POINT_X                                    15:0
+#define STRETCH_BLIT_DST_POINT_Y                                    31:16
+#define STRETCH_BLIT_DST_SIZE                                       0x0000E314
+#define STRETCH_BLIT_DST_SIZE_WIDTH                                 15:0
+#define STRETCH_BLIT_DST_SIZE_HEIGHT                                31:16
+#define STRETCH_BLIT_DU_DX                                          0x0000E318
+#define STRETCH_BLIT_DV_DY                                          0x0000E31C
+#define STRETCH_BLIT_SRC_SIZE                                       0x0000E400
+#define STRETCH_BLIT_SRC_SIZE_WIDTH                                 15:0
+#define STRETCH_BLIT_SRC_SIZE_HEIGHT                                31:16
+#define STRETCH_BLIT_SRC_FORMAT                                     0x0000E404
+#define STRETCH_BLIT_SRC_FORMAT_PITCH                               15:0
+#define STRETCH_BLIT_SRC_FORMAT_ORIGIN                              23:16
+#define STRETCH_BLIT_SRC_FORMAT_ORIGIN_CENTER                       0x00000001
+#define STRETCH_BLIT_SRC_FORMAT_ORIGIN_CORNER                       0x00000002
+#define STRETCH_BLIT_SRC_FORMAT_FILTER                              31:24
+#define STRETCH_BLIT_SRC_FORMAT_FILTER_POINT_SAMPLE                 0x00000000
+#define STRETCH_BLIT_SRC_FORMAT_FILTER_BILINEAR                     0x00000001
+#define STRETCH_BLIT_SRC_OFFSET                                     0x0000E408
+#define STRETCH_BLIT_SRC_POINT                                      0x0000E40C
+#define STRETCH_BLIT_SRC_POINT_U                                    15:0
+#define STRETCH_BLIT_SRC_POINT_V                                    31:16
diff --git a/drivers/video/nvidia/nv_hw.c b/drivers/video/nvidia/nv_hw.c
new file mode 100644
index 0000000..b989358
--- /dev/null
+++ b/drivers/video/nvidia/nv_hw.c
@@ -0,0 +1,1593 @@
+ /***************************************************************************\
+|*                                                                           *|
+|*       Copyright 1993-2003 NVIDIA, Corporation.  All rights reserved.      *|
+|*                                                                           *|
+|*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
+|*     international laws.  Users and possessors of this source code are     *|
+|*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
+|*     use this code in individual and commercial software.                  *|
+|*                                                                           *|
+|*     Any use of this source code must include,  in the user documenta-     *|
+|*     tion and  internal comments to the code,  notices to the end user     *|
+|*     as follows:                                                           *|
+|*                                                                           *|
+|*       Copyright 1993-2003 NVIDIA, Corporation.  All rights reserved.      *|
+|*                                                                           *|
+|*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
+|*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
+|*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
+|*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
+|*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
+|*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
+|*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
+|*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
+|*     SULTING FROM LOSS OF USE,  DATA OR PROFITS,  WHETHER IN AN ACTION     *|
+|*     OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,  ARISING OUT OF     *|
+|*     OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.     *|
+|*                                                                           *|
+|*     U.S. Government  End  Users.   This source code  is a "commercial     *|
+|*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
+|*     consisting  of "commercial  computer  software"  and  "commercial     *|
+|*     computer  software  documentation,"  as such  terms  are  used in     *|
+|*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
+|*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
+|*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
+|*     all U.S. Government End Users  acquire the source code  with only     *|
+|*     those rights set forth herein.                                        *|
+|*                                                                           *|
+ \***************************************************************************/
+
+/*
+ * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/
+ * XFree86 'nv' driver, this source code is provided under MIT-style licensing
+ * where the source code is provided "as is" without warranty of any kind.
+ * The only usage restriction is for the copyright notices to be retained
+ * whenever code is used.
+ *
+ * Antonino Daplas <adaplas@pol.net> 2005-03-11
+ */
+
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/nv_hw.c,v 1.4 2003/11/03 05:11:25 tsi Exp $ */
+
+#include <linux/pci.h>
+#include "nv_type.h"
+#include "nv_local.h"
+
+void NVLockUnlock(struct nvidia_par *par, int Lock)
+{
+	u8 cr11;
+
+	VGA_WR08(par->PCIO, 0x3D4, 0x1F);
+	VGA_WR08(par->PCIO, 0x3D5, Lock ? 0x99 : 0x57);
+
+	VGA_WR08(par->PCIO, 0x3D4, 0x11);
+	cr11 = VGA_RD08(par->PCIO, 0x3D5);
+	if (Lock)
+		cr11 |= 0x80;
+	else
+		cr11 &= ~0x80;
+	VGA_WR08(par->PCIO, 0x3D5, cr11);
+}
+
+int NVShowHideCursor(struct nvidia_par *par, int ShowHide)
+{
+	int cur = par->CurrentState->cursor1;
+
+	par->CurrentState->cursor1 = (par->CurrentState->cursor1 & 0xFE) |
+	    (ShowHide & 0x01);
+	VGA_WR08(par->PCIO, 0x3D4, 0x31);
+	VGA_WR08(par->PCIO, 0x3D5, par->CurrentState->cursor1);
+
+	if (par->Architecture == NV_ARCH_40)
+		NV_WR32(par->PRAMDAC, 0x0300, NV_RD32(par->PRAMDAC, 0x0300));
+
+	return (cur & 0x01);
+}
+
+/****************************************************************************\
+*                                                                            *
+* The video arbitration routines calculate some "magic" numbers.  Fixes      *
+* the snow seen when accessing the framebuffer without it.                   *
+* It just works (I hope).                                                    *
+*                                                                            *
+\****************************************************************************/
+
+typedef struct {
+	int graphics_lwm;
+	int video_lwm;
+	int graphics_burst_size;
+	int video_burst_size;
+	int valid;
+} nv4_fifo_info;
+
+typedef struct {
+	int pclk_khz;
+	int mclk_khz;
+	int nvclk_khz;
+	char mem_page_miss;
+	char mem_latency;
+	int memory_width;
+	char enable_video;
+	char gr_during_vid;
+	char pix_bpp;
+	char mem_aligned;
+	char enable_mp;
+} nv4_sim_state;
+
+typedef struct {
+	int graphics_lwm;
+	int video_lwm;
+	int graphics_burst_size;
+	int video_burst_size;
+	int valid;
+} nv10_fifo_info;
+
+typedef struct {
+	int pclk_khz;
+	int mclk_khz;
+	int nvclk_khz;
+	char mem_page_miss;
+	char mem_latency;
+	int memory_type;
+	int memory_width;
+	char enable_video;
+	char gr_during_vid;
+	char pix_bpp;
+	char mem_aligned;
+	char enable_mp;
+} nv10_sim_state;
+
+static void nvGetClocks(struct nvidia_par *par, unsigned int *MClk,
+			unsigned int *NVClk)
+{
+	unsigned int pll, N, M, MB, NB, P;
+
+	if (par->Architecture >= NV_ARCH_40) {
+		pll = NV_RD32(par->PMC, 0x4020);
+		P = (pll >> 16) & 0x03;
+		pll = NV_RD32(par->PMC, 0x4024);
+		M = pll & 0xFF;
+		N = (pll >> 8) & 0xFF;
+		MB = (pll >> 16) & 0xFF;
+		NB = (pll >> 24) & 0xFF;
+		*MClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P;
+
+		pll = NV_RD32(par->PMC, 0x4000);
+		P = (pll >> 16) & 0x03;
+		pll = NV_RD32(par->PMC, 0x4004);
+		M = pll & 0xFF;
+		N = (pll >> 8) & 0xFF;
+		MB = (pll >> 16) & 0xFF;
+		NB = (pll >> 24) & 0xFF;
+
+		*NVClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P;
+	} else if (par->twoStagePLL) {
+		pll = NV_RD32(par->PRAMDAC0, 0x0504);
+		M = pll & 0xFF;
+		N = (pll >> 8) & 0xFF;
+		P = (pll >> 16) & 0x0F;
+		pll = NV_RD32(par->PRAMDAC0, 0x0574);
+		if (pll & 0x80000000) {
+			MB = pll & 0xFF;
+			NB = (pll >> 8) & 0xFF;
+		} else {
+			MB = 1;
+			NB = 1;
+		}
+		*MClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P;
+
+		pll = NV_RD32(par->PRAMDAC0, 0x0500);
+		M = pll & 0xFF;
+		N = (pll >> 8) & 0xFF;
+		P = (pll >> 16) & 0x0F;
+		pll = NV_RD32(par->PRAMDAC0, 0x0570);
+		if (pll & 0x80000000) {
+			MB = pll & 0xFF;
+			NB = (pll >> 8) & 0xFF;
+		} else {
+			MB = 1;
+			NB = 1;
+		}
+		*NVClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P;
+	} else
+	    if (((par->Chipset & 0x0ff0) == 0x0300) ||
+		((par->Chipset & 0x0ff0) == 0x0330)) {
+		pll = NV_RD32(par->PRAMDAC0, 0x0504);
+		M = pll & 0x0F;
+		N = (pll >> 8) & 0xFF;
+		P = (pll >> 16) & 0x07;
+		if (pll & 0x00000080) {
+			MB = (pll >> 4) & 0x07;
+			NB = (pll >> 19) & 0x1f;
+		} else {
+			MB = 1;
+			NB = 1;
+		}
+		*MClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P;
+
+		pll = NV_RD32(par->PRAMDAC0, 0x0500);
+		M = pll & 0x0F;
+		N = (pll >> 8) & 0xFF;
+		P = (pll >> 16) & 0x07;
+		if (pll & 0x00000080) {
+			MB = (pll >> 4) & 0x07;
+			NB = (pll >> 19) & 0x1f;
+		} else {
+			MB = 1;
+			NB = 1;
+		}
+		*NVClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P;
+	} else {
+		pll = NV_RD32(par->PRAMDAC0, 0x0504);
+		M = pll & 0xFF;
+		N = (pll >> 8) & 0xFF;
+		P = (pll >> 16) & 0x0F;
+		*MClk = (N * par->CrystalFreqKHz / M) >> P;
+
+		pll = NV_RD32(par->PRAMDAC0, 0x0500);
+		M = pll & 0xFF;
+		N = (pll >> 8) & 0xFF;
+		P = (pll >> 16) & 0x0F;
+		*NVClk = (N * par->CrystalFreqKHz / M) >> P;
+	}
+}
+
+static void nv4CalcArbitration(nv4_fifo_info * fifo, nv4_sim_state * arb)
+{
+	int data, pagemiss, cas, width, video_enable, bpp;
+	int nvclks, mclks, pclks, vpagemiss, crtpagemiss, vbs;
+	int found, mclk_extra, mclk_loop, cbs, m1, p1;
+	int mclk_freq, pclk_freq, nvclk_freq, mp_enable;
+	int us_m, us_n, us_p, video_drain_rate, crtc_drain_rate;
+	int vpm_us, us_video, vlwm, video_fill_us, cpm_us, us_crt, clwm;
+
+	fifo->valid = 1;
+	pclk_freq = arb->pclk_khz;
+	mclk_freq = arb->mclk_khz;
+	nvclk_freq = arb->nvclk_khz;
+	pagemiss = arb->mem_page_miss;
+	cas = arb->mem_latency;
+	width = arb->memory_width >> 6;
+	video_enable = arb->enable_video;
+	bpp = arb->pix_bpp;
+	mp_enable = arb->enable_mp;
+	clwm = 0;
+	vlwm = 0;
+	cbs = 128;
+	pclks = 2;
+	nvclks = 2;
+	nvclks += 2;
+	nvclks += 1;
+	mclks = 5;
+	mclks += 3;
+	mclks += 1;
+	mclks += cas;
+	mclks += 1;
+	mclks += 1;
+	mclks += 1;
+	mclks += 1;
+	mclk_extra = 3;
+	nvclks += 2;
+	nvclks += 1;
+	nvclks += 1;
+	nvclks += 1;
+	if (mp_enable)
+		mclks += 4;
+	nvclks += 0;
+	pclks += 0;
+	found = 0;
+	vbs = 0;
+	while (found != 1) {
+		fifo->valid = 1;
+		found = 1;
+		mclk_loop = mclks + mclk_extra;
+		us_m = mclk_loop * 1000 * 1000 / mclk_freq;
+		us_n = nvclks * 1000 * 1000 / nvclk_freq;
+		us_p = nvclks * 1000 * 1000 / pclk_freq;
+		if (video_enable) {
+			video_drain_rate = pclk_freq * 2;
+			crtc_drain_rate = pclk_freq * bpp / 8;
+			vpagemiss = 2;
+			vpagemiss += 1;
+			crtpagemiss = 2;
+			vpm_us =
+			    (vpagemiss * pagemiss) * 1000 * 1000 / mclk_freq;
+			if (nvclk_freq * 2 > mclk_freq * width)
+				video_fill_us =
+				    cbs * 1000 * 1000 / 16 / nvclk_freq;
+			else
+				video_fill_us =
+				    cbs * 1000 * 1000 / (8 * width) /
+				    mclk_freq;
+			us_video = vpm_us + us_m + us_n + us_p + video_fill_us;
+			vlwm = us_video * video_drain_rate / (1000 * 1000);
+			vlwm++;
+			vbs = 128;
+			if (vlwm > 128)
+				vbs = 64;
+			if (vlwm > (256 - 64))
+				vbs = 32;
+			if (nvclk_freq * 2 > mclk_freq * width)
+				video_fill_us =
+				    vbs * 1000 * 1000 / 16 / nvclk_freq;
+			else
+				video_fill_us =
+				    vbs * 1000 * 1000 / (8 * width) /
+				    mclk_freq;
+			cpm_us =
+			    crtpagemiss * pagemiss * 1000 * 1000 / mclk_freq;
+			us_crt =
+			    us_video + video_fill_us + cpm_us + us_m + us_n +
+			    us_p;
+			clwm = us_crt * crtc_drain_rate / (1000 * 1000);
+			clwm++;
+		} else {
+			crtc_drain_rate = pclk_freq * bpp / 8;
+			crtpagemiss = 2;
+			crtpagemiss += 1;
+			cpm_us =
+			    crtpagemiss * pagemiss * 1000 * 1000 / mclk_freq;
+			us_crt = cpm_us + us_m + us_n + us_p;
+			clwm = us_crt * crtc_drain_rate / (1000 * 1000);
+			clwm++;
+		}
+		m1 = clwm + cbs - 512;
+		p1 = m1 * pclk_freq / mclk_freq;
+		p1 = p1 * bpp / 8;
+		if ((p1 < m1) && (m1 > 0)) {
+			fifo->valid = 0;
+			found = 0;
+			if (mclk_extra == 0)
+				found = 1;
+			mclk_extra--;
+		} else if (video_enable) {
+			if ((clwm > 511) || (vlwm > 255)) {
+				fifo->valid = 0;
+				found = 0;
+				if (mclk_extra == 0)
+					found = 1;
+				mclk_extra--;
+			}
+		} else {
+			if (clwm > 519) {
+				fifo->valid = 0;
+				found = 0;
+				if (mclk_extra == 0)
+					found = 1;
+				mclk_extra--;
+			}
+		}
+		if (clwm < 384)
+			clwm = 384;
+		if (vlwm < 128)
+			vlwm = 128;
+		data = (int)(clwm);
+		fifo->graphics_lwm = data;
+		fifo->graphics_burst_size = 128;
+		data = (int)((vlwm + 15));
+		fifo->video_lwm = data;
+		fifo->video_burst_size = vbs;
+	}
+}
+
+static void nv4UpdateArbitrationSettings(unsigned VClk,
+					 unsigned pixelDepth,
+					 unsigned *burst,
+					 unsigned *lwm, struct nvidia_par *par)
+{
+	nv4_fifo_info fifo_data;
+	nv4_sim_state sim_data;
+	unsigned int MClk, NVClk, cfg1;
+
+	nvGetClocks(par, &MClk, &NVClk);
+
+	cfg1 = NV_RD32(par->PFB, 0x00000204);
+	sim_data.pix_bpp = (char)pixelDepth;
+	sim_data.enable_video = 0;
+	sim_data.enable_mp = 0;
+	sim_data.memory_width = (NV_RD32(par->PEXTDEV, 0x0000) & 0x10) ?
+	    128 : 64;
+	sim_data.mem_latency = (char)cfg1 & 0x0F;
+	sim_data.mem_aligned = 1;
+	sim_data.mem_page_miss =
+	    (char)(((cfg1 >> 4) & 0x0F) + ((cfg1 >> 31) & 0x01));
+	sim_data.gr_during_vid = 0;
+	sim_data.pclk_khz = VClk;
+	sim_data.mclk_khz = MClk;
+	sim_data.nvclk_khz = NVClk;
+	nv4CalcArbitration(&fifo_data, &sim_data);
+	if (fifo_data.valid) {
+		int b = fifo_data.graphics_burst_size >> 4;
+		*burst = 0;
+		while (b >>= 1)
+			(*burst)++;
+		*lwm = fifo_data.graphics_lwm >> 3;
+	}
+}
+
+static void nv10CalcArbitration(nv10_fifo_info * fifo, nv10_sim_state * arb)
+{
+	int data, pagemiss, width, video_enable, bpp;
+	int nvclks, mclks, pclks, vpagemiss, crtpagemiss;
+	int nvclk_fill;
+	int found, mclk_extra, mclk_loop, cbs, m1;
+	int mclk_freq, pclk_freq, nvclk_freq, mp_enable;
+	int us_m, us_m_min, us_n, us_p, crtc_drain_rate;
+	int vus_m;
+	int vpm_us, us_video, cpm_us, us_crt, clwm;
+	int clwm_rnd_down;
+	int m2us, us_pipe_min, p1clk, p2;
+	int min_mclk_extra;
+	int us_min_mclk_extra;
+
+	fifo->valid = 1;
+	pclk_freq = arb->pclk_khz;	/* freq in KHz */
+	mclk_freq = arb->mclk_khz;
+	nvclk_freq = arb->nvclk_khz;
+	pagemiss = arb->mem_page_miss;
+	width = arb->memory_width / 64;
+	video_enable = arb->enable_video;
+	bpp = arb->pix_bpp;
+	mp_enable = arb->enable_mp;
+	clwm = 0;
+
+	cbs = 512;
+
+	pclks = 4;	/* lwm detect. */
+
+	nvclks = 3;	/* lwm -> sync. */
+	nvclks += 2;	/* fbi bus cycles (1 req + 1 busy) */
+	/* 2 edge sync.  may be very close to edge so just put one. */
+	mclks = 1;
+	mclks += 1;	/* arb_hp_req */
+	mclks += 5;	/* ap_hp_req   tiling pipeline */
+
+	mclks += 2;	/* tc_req     latency fifo */
+	mclks += 2;	/* fb_cas_n_  memory request to fbio block */
+	mclks += 7;	/* sm_d_rdv   data returned from fbio block */
+
+	/* fb.rd.d.Put_gc   need to accumulate 256 bits for read */
+	if (arb->memory_type == 0)
+		if (arb->memory_width == 64)	/* 64 bit bus */
+			mclks += 4;
+		else
+			mclks += 2;
+	else if (arb->memory_width == 64)	/* 64 bit bus */
+		mclks += 2;
+	else
+		mclks += 1;
+
+	if ((!video_enable) && (arb->memory_width == 128)) {
+		mclk_extra = (bpp == 32) ? 31 : 42;	/* Margin of error */
+		min_mclk_extra = 17;
+	} else {
+		mclk_extra = (bpp == 32) ? 8 : 4;	/* Margin of error */
+		/* mclk_extra = 4; *//* Margin of error */
+		min_mclk_extra = 18;
+	}
+
+	/* 2 edge sync.  may be very close to edge so just put one. */
+	nvclks += 1;
+	nvclks += 1;		/* fbi_d_rdv_n */
+	nvclks += 1;		/* Fbi_d_rdata */
+	nvclks += 1;		/* crtfifo load */
+
+	if (mp_enable)
+		mclks += 4;	/* Mp can get in with a burst of 8. */
+	/* Extra clocks determined by heuristics */
+
+	nvclks += 0;
+	pclks += 0;
+	found = 0;
+	while (found != 1) {
+		fifo->valid = 1;
+		found = 1;
+		mclk_loop = mclks + mclk_extra;
+		/* Mclk latency in us */
+		us_m = mclk_loop * 1000 * 1000 / mclk_freq;
+		/* Minimum Mclk latency in us */
+		us_m_min = mclks * 1000 * 1000 / mclk_freq;
+		us_min_mclk_extra = min_mclk_extra * 1000 * 1000 / mclk_freq;
+		/* nvclk latency in us */
+		us_n = nvclks * 1000 * 1000 / nvclk_freq;
+		/* nvclk latency in us */
+		us_p = pclks * 1000 * 1000 / pclk_freq;
+		us_pipe_min = us_m_min + us_n + us_p;
+
+		/* Mclk latency in us */
+		vus_m = mclk_loop * 1000 * 1000 / mclk_freq;
+
+		if (video_enable) {
+			crtc_drain_rate = pclk_freq * bpp / 8;	/* MB/s */
+
+			vpagemiss = 1;	/* self generating page miss */
+			vpagemiss += 1;	/* One higher priority before */
+
+			crtpagemiss = 2;	/* self generating page miss */
+			if (mp_enable)
+				crtpagemiss += 1;	/* if MA0 conflict */
+
+			vpm_us =
+			    (vpagemiss * pagemiss) * 1000 * 1000 / mclk_freq;
+
+			/* Video has separate read return path */
+			us_video = vpm_us + vus_m;
+
+			cpm_us =
+			    crtpagemiss * pagemiss * 1000 * 1000 / mclk_freq;
+			/* Wait for video */
+			us_crt = us_video
+			    + cpm_us	/* CRT Page miss */
+			    + us_m + us_n + us_p	/* other latency */
+			    ;
+
+			clwm = us_crt * crtc_drain_rate / (1000 * 1000);
+			/* fixed point <= float_point - 1.  Fixes that */
+			clwm++;
+		} else {
+		    /* bpp * pclk/8 */
+			crtc_drain_rate = pclk_freq * bpp / 8;
+
+			crtpagemiss = 1;	/* self generating page miss */
+			crtpagemiss += 1;	/* MA0 page miss */
+			if (mp_enable)
+				crtpagemiss += 1;	/* if MA0 conflict */
+			cpm_us =
+			    crtpagemiss * pagemiss * 1000 * 1000 / mclk_freq;
+			us_crt = cpm_us + us_m + us_n + us_p;
+			clwm = us_crt * crtc_drain_rate / (1000 * 1000);
+			/* fixed point <= float_point - 1.  Fixes that */
+			clwm++;
+
+			/* Finally, a heuristic check when width == 64 bits */
+			if (width == 1) {
+				nvclk_fill = nvclk_freq * 8;
+				if (crtc_drain_rate * 100 >= nvclk_fill * 102)
+					/*Large number to fail */
+					clwm = 0xfff;
+
+				else if (crtc_drain_rate * 100 >=
+					 nvclk_fill * 98) {
+					clwm = 1024;
+					cbs = 512;
+				}
+			}
+		}
+
+		/*
+		   Overfill check:
+		 */
+
+		clwm_rnd_down = ((int)clwm / 8) * 8;
+		if (clwm_rnd_down < clwm)
+			clwm += 8;
+
+		m1 = clwm + cbs - 1024;	/* Amount of overfill */
+		m2us = us_pipe_min + us_min_mclk_extra;
+
+		/* pclk cycles to drain */
+		p1clk = m2us * pclk_freq / (1000 * 1000);
+		p2 = p1clk * bpp / 8;	/* bytes drained. */
+
+		if ((p2 < m1) && (m1 > 0)) {
+			fifo->valid = 0;
+			found = 0;
+			if (min_mclk_extra == 0) {
+				if (cbs <= 32) {
+					/* Can't adjust anymore! */
+					found = 1;
+				} else {
+					/* reduce the burst size */
+					cbs = cbs / 2;
+				}
+			} else {
+				min_mclk_extra--;
+			}
+		} else {
+			if (clwm > 1023) {	/* Have some margin */
+				fifo->valid = 0;
+				found = 0;
+				if (min_mclk_extra == 0)
+					/* Can't adjust anymore! */
+					found = 1;
+				else
+					min_mclk_extra--;
+			}
+		}
+
+		if (clwm < (1024 - cbs + 8))
+			clwm = 1024 - cbs + 8;
+		data = (int)(clwm);
+		/*  printf("CRT LWM: %f bytes, prog: 0x%x, bs: 256\n",
+		    clwm, data ); */
+		fifo->graphics_lwm = data;
+		fifo->graphics_burst_size = cbs;
+
+		fifo->video_lwm = 1024;
+		fifo->video_burst_size = 512;
+	}
+}
+
+static void nv10UpdateArbitrationSettings(unsigned VClk,
+					  unsigned pixelDepth,
+					  unsigned *burst,
+					  unsigned *lwm,
+					  struct nvidia_par *par)
+{
+	nv10_fifo_info fifo_data;
+	nv10_sim_state sim_data;
+	unsigned int MClk, NVClk, cfg1;
+
+	nvGetClocks(par, &MClk, &NVClk);
+
+	cfg1 = NV_RD32(par->PFB, 0x0204);
+	sim_data.pix_bpp = (char)pixelDepth;
+	sim_data.enable_video = 1;
+	sim_data.enable_mp = 0;
+	sim_data.memory_type = (NV_RD32(par->PFB, 0x0200) & 0x01) ? 1 : 0;
+	sim_data.memory_width = (NV_RD32(par->PEXTDEV, 0x0000) & 0x10) ?
+	    128 : 64;
+	sim_data.mem_latency = (char)cfg1 & 0x0F;
+	sim_data.mem_aligned = 1;
+	sim_data.mem_page_miss =
+	    (char)(((cfg1 >> 4) & 0x0F) + ((cfg1 >> 31) & 0x01));
+	sim_data.gr_during_vid = 0;
+	sim_data.pclk_khz = VClk;
+	sim_data.mclk_khz = MClk;
+	sim_data.nvclk_khz = NVClk;
+	nv10CalcArbitration(&fifo_data, &sim_data);
+	if (fifo_data.valid) {
+		int b = fifo_data.graphics_burst_size >> 4;
+		*burst = 0;
+		while (b >>= 1)
+			(*burst)++;
+		*lwm = fifo_data.graphics_lwm >> 3;
+	}
+}
+
+static void nv30UpdateArbitrationSettings (
+    struct nvidia_par *par,
+    unsigned int      *burst,
+    unsigned int      *lwm
+)
+{
+    unsigned int MClk, NVClk;
+    unsigned int fifo_size, burst_size, graphics_lwm;
+
+    fifo_size = 2048;
+    burst_size = 512;
+    graphics_lwm = fifo_size - burst_size;
+
+    nvGetClocks(par, &MClk, &NVClk);
+
+    *burst = 0;
+    burst_size >>= 5;
+    while(burst_size >>= 1) (*burst)++;
+    *lwm = graphics_lwm >> 3;
+}
+
+static void nForceUpdateArbitrationSettings(unsigned VClk,
+					    unsigned pixelDepth,
+					    unsigned *burst,
+					    unsigned *lwm,
+					    struct nvidia_par *par)
+{
+	nv10_fifo_info fifo_data;
+	nv10_sim_state sim_data;
+	unsigned int M, N, P, pll, MClk, NVClk, memctrl;
+	struct pci_dev *dev;
+
+	if ((par->Chipset & 0x0FF0) == 0x01A0) {
+		unsigned int uMClkPostDiv;
+		dev = pci_find_slot(0, 3);
+		pci_read_config_dword(dev, 0x6C, &uMClkPostDiv);
+		uMClkPostDiv = (uMClkPostDiv >> 8) & 0xf;
+
+		if (!uMClkPostDiv)
+			uMClkPostDiv = 4;
+		MClk = 400000 / uMClkPostDiv;
+	} else {
+		dev = pci_find_slot(0, 5);
+		pci_read_config_dword(dev, 0x4c, &MClk);
+		MClk /= 1000;
+	}
+
+	pll = NV_RD32(par->PRAMDAC0, 0x0500);
+	M = (pll >> 0) & 0xFF;
+	N = (pll >> 8) & 0xFF;
+	P = (pll >> 16) & 0x0F;
+	NVClk = (N * par->CrystalFreqKHz / M) >> P;
+	sim_data.pix_bpp = (char)pixelDepth;
+	sim_data.enable_video = 0;
+	sim_data.enable_mp = 0;
+	pci_find_slot(0, 1);
+	pci_read_config_dword(dev, 0x7C, &sim_data.memory_type);
+	sim_data.memory_type = (sim_data.memory_type >> 12) & 1;
+	sim_data.memory_width = 64;
+
+	dev = pci_find_slot(0, 3);
+	pci_read_config_dword(dev, 0, &memctrl);
+	memctrl >>= 16;
+
+	if ((memctrl == 0x1A9) || (memctrl == 0x1AB) || (memctrl == 0x1ED)) {
+		int dimm[3];
+
+		pci_find_slot(0, 2);
+		pci_read_config_dword(dev, 0x40, &dimm[0]);
+		dimm[0] = (dimm[0] >> 8) & 0x4f;
+		pci_read_config_dword(dev, 0x44, &dimm[1]);
+		dimm[1] = (dimm[1] >> 8) & 0x4f;
+		pci_read_config_dword(dev, 0x48, &dimm[2]);
+		dimm[2] = (dimm[2] >> 8) & 0x4f;
+
+		if ((dimm[0] + dimm[1]) != dimm[2]) {
+			printk("nvidiafb: your nForce DIMMs are not arranged "
+			       "in optimal banks!\n");
+		}
+	}
+
+	sim_data.mem_latency = 3;
+	sim_data.mem_aligned = 1;
+	sim_data.mem_page_miss = 10;
+	sim_data.gr_during_vid = 0;
+	sim_data.pclk_khz = VClk;
+	sim_data.mclk_khz = MClk;
+	sim_data.nvclk_khz = NVClk;
+	nv10CalcArbitration(&fifo_data, &sim_data);
+	if (fifo_data.valid) {
+		int b = fifo_data.graphics_burst_size >> 4;
+		*burst = 0;
+		while (b >>= 1)
+			(*burst)++;
+		*lwm = fifo_data.graphics_lwm >> 3;
+	}
+}
+
+/****************************************************************************\
+*                                                                            *
+*                          RIVA Mode State Routines                          *
+*                                                                            *
+\****************************************************************************/
+
+/*
+ * Calculate the Video Clock parameters for the PLL.
+ */
+static void CalcVClock(int clockIn,
+		       int *clockOut, u32 * pllOut, struct nvidia_par *par)
+{
+	unsigned lowM, highM;
+	unsigned DeltaNew, DeltaOld;
+	unsigned VClk, Freq;
+	unsigned M, N, P;
+
+	DeltaOld = 0xFFFFFFFF;
+
+	VClk = (unsigned)clockIn;
+
+	if (par->CrystalFreqKHz == 13500) {
+		lowM = 7;
+		highM = 13;
+	} else {
+		lowM = 8;
+		highM = 14;
+	}
+
+	for (P = 0; P <= 4; P++) {
+		Freq = VClk << P;
+		if ((Freq >= 128000) && (Freq <= 350000)) {
+			for (M = lowM; M <= highM; M++) {
+				N = ((VClk << P) * M) / par->CrystalFreqKHz;
+				if (N <= 255) {
+					Freq =
+					    ((par->CrystalFreqKHz * N) /
+					     M) >> P;
+					if (Freq > VClk)
+						DeltaNew = Freq - VClk;
+					else
+						DeltaNew = VClk - Freq;
+					if (DeltaNew < DeltaOld) {
+						*pllOut =
+						    (P << 16) | (N << 8) | M;
+						*clockOut = Freq;
+						DeltaOld = DeltaNew;
+					}
+				}
+			}
+		}
+	}
+}
+
+static void CalcVClock2Stage(int clockIn,
+			     int *clockOut,
+			     u32 * pllOut,
+			     u32 * pllBOut, struct nvidia_par *par)
+{
+	unsigned DeltaNew, DeltaOld;
+	unsigned VClk, Freq;
+	unsigned M, N, P;
+
+	DeltaOld = 0xFFFFFFFF;
+
+	*pllBOut = 0x80000401;	/* fixed at x4 for now */
+
+	VClk = (unsigned)clockIn;
+
+	for (P = 0; P <= 6; P++) {
+		Freq = VClk << P;
+		if ((Freq >= 400000) && (Freq <= 1000000)) {
+			for (M = 1; M <= 13; M++) {
+				N = ((VClk << P) * M) /
+				    (par->CrystalFreqKHz << 2);
+				if ((N >= 5) && (N <= 255)) {
+					Freq =
+					    (((par->CrystalFreqKHz << 2) * N) /
+					     M) >> P;
+					if (Freq > VClk)
+						DeltaNew = Freq - VClk;
+					else
+						DeltaNew = VClk - Freq;
+					if (DeltaNew < DeltaOld) {
+						*pllOut =
+						    (P << 16) | (N << 8) | M;
+						*clockOut = Freq;
+						DeltaOld = DeltaNew;
+					}
+				}
+			}
+		}
+	}
+}
+
+/*
+ * Calculate extended mode parameters (SVGA) and save in a
+ * mode state structure.
+ */
+void NVCalcStateExt(struct nvidia_par *par,
+		    RIVA_HW_STATE * state,
+		    int bpp,
+		    int width,
+		    int hDisplaySize, int height, int dotClock, int flags)
+{
+	int pixelDepth, VClk;
+	/*
+	 * Save mode parameters.
+	 */
+	state->bpp = bpp;	/* this is not bitsPerPixel, it's 8,15,16,32 */
+	state->width = width;
+	state->height = height;
+	/*
+	 * Extended RIVA registers.
+	 */
+	pixelDepth = (bpp + 1) / 8;
+	if (par->twoStagePLL)
+		CalcVClock2Stage(dotClock, &VClk, &state->pll, &state->pllB,
+				 par);
+	else
+		CalcVClock(dotClock, &VClk, &state->pll, par);
+
+	switch (par->Architecture) {
+	case NV_ARCH_04:
+		nv4UpdateArbitrationSettings(VClk,
+					     pixelDepth * 8,
+					     &(state->arbitration0),
+					     &(state->arbitration1), par);
+		state->cursor0 = 0x00;
+		state->cursor1 = 0xbC;
+		if (flags & FB_VMODE_DOUBLE)
+			state->cursor1 |= 2;
+		state->cursor2 = 0x00000000;
+		state->pllsel = 0x10000700;
+		state->config = 0x00001114;
+		state->general = bpp == 16 ? 0x00101100 : 0x00100100;
+		state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00;
+		break;
+	case NV_ARCH_10:
+	case NV_ARCH_20:
+	case NV_ARCH_30:
+	default:
+		if (((par->Chipset & 0xffff) == 0x01A0) ||
+		    ((par->Chipset & 0xffff) == 0x01f0)) {
+			nForceUpdateArbitrationSettings(VClk,
+							pixelDepth * 8,
+							&(state->arbitration0),
+							&(state->arbitration1),
+							par);
+		} else if (par->Architecture < NV_ARCH_30) {
+			nv10UpdateArbitrationSettings(VClk,
+						      pixelDepth * 8,
+						      &(state->arbitration0),
+						      &(state->arbitration1),
+						      par);
+		} else {
+			nv30UpdateArbitrationSettings(par,
+						      &(state->arbitration0),
+						      &(state->arbitration1));
+		}
+
+		state->cursor0 = 0x80 | (par->CursorStart >> 17);
+		state->cursor1 = (par->CursorStart >> 11) << 2;
+		state->cursor2 = par->CursorStart >> 24;
+		if (flags & FB_VMODE_DOUBLE)
+			state->cursor1 |= 2;
+		state->pllsel = 0x10000700;
+		state->config = NV_RD32(par->PFB, 0x00000200);
+		state->general = bpp == 16 ? 0x00101100 : 0x00100100;
+		state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00;
+		break;
+	}
+
+	if (bpp != 8)		/* DirectColor */
+		state->general |= 0x00000030;
+
+	state->repaint0 = (((width / 8) * pixelDepth) & 0x700) >> 3;
+	state->pixel = (pixelDepth > 2) ? 3 : pixelDepth;
+}
+
+void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
+{
+	int i;
+
+	NV_WR32(par->PMC, 0x0140, 0x00000000);
+	NV_WR32(par->PMC, 0x0200, 0xFFFF00FF);
+	NV_WR32(par->PMC, 0x0200, 0xFFFFFFFF);
+
+	NV_WR32(par->PTIMER, 0x0200 * 4, 0x00000008);
+	NV_WR32(par->PTIMER, 0x0210 * 4, 0x00000003);
+	NV_WR32(par->PTIMER, 0x0140 * 4, 0x00000000);
+	NV_WR32(par->PTIMER, 0x0100 * 4, 0xFFFFFFFF);
+
+	if (par->Architecture == NV_ARCH_04) {
+		NV_WR32(par->PFB, 0x0200, state->config);
+	} else if ((par->Chipset & 0xfff0) == 0x0090) {
+		for (i = 0; i < 15; i++) {
+			NV_WR32(par->PFB, 0x0600 + (i * 0x10), 0);
+			NV_WR32(par->PFB, 0x0604 + (i * 0x10), par->FbMapSize - 1);
+		}
+	} else {
+		for (i = 0; i < 8; i++) {
+			NV_WR32(par->PFB, 0x0240 + (i * 0x10), 0);
+			NV_WR32(par->PFB, 0x0244 + (i * 0x10), par->FbMapSize - 1);
+		}
+	}
+
+	if (par->Architecture >= NV_ARCH_40) {
+		NV_WR32(par->PRAMIN, 0x0000 * 4, 0x80000010);
+		NV_WR32(par->PRAMIN, 0x0001 * 4, 0x00101202);
+		NV_WR32(par->PRAMIN, 0x0002 * 4, 0x80000011);
+		NV_WR32(par->PRAMIN, 0x0003 * 4, 0x00101204);
+		NV_WR32(par->PRAMIN, 0x0004 * 4, 0x80000012);
+		NV_WR32(par->PRAMIN, 0x0005 * 4, 0x00101206);
+		NV_WR32(par->PRAMIN, 0x0006 * 4, 0x80000013);
+		NV_WR32(par->PRAMIN, 0x0007 * 4, 0x00101208);
+		NV_WR32(par->PRAMIN, 0x0008 * 4, 0x80000014);
+		NV_WR32(par->PRAMIN, 0x0009 * 4, 0x0010120A);
+		NV_WR32(par->PRAMIN, 0x000A * 4, 0x80000015);
+		NV_WR32(par->PRAMIN, 0x000B * 4, 0x0010120C);
+		NV_WR32(par->PRAMIN, 0x000C * 4, 0x80000016);
+		NV_WR32(par->PRAMIN, 0x000D * 4, 0x0010120E);
+		NV_WR32(par->PRAMIN, 0x000E * 4, 0x80000017);
+		NV_WR32(par->PRAMIN, 0x000F * 4, 0x00101210);
+		NV_WR32(par->PRAMIN, 0x0800 * 4, 0x00003000);
+		NV_WR32(par->PRAMIN, 0x0801 * 4, par->FbMapSize - 1);
+		NV_WR32(par->PRAMIN, 0x0802 * 4, 0x00000002);
+		NV_WR32(par->PRAMIN, 0x0808 * 4, 0x02080062);
+		NV_WR32(par->PRAMIN, 0x0809 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x080A * 4, 0x00001200);
+		NV_WR32(par->PRAMIN, 0x080B * 4, 0x00001200);
+		NV_WR32(par->PRAMIN, 0x080C * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x080D * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0810 * 4, 0x02080043);
+		NV_WR32(par->PRAMIN, 0x0811 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0812 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0813 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0814 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0815 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0818 * 4, 0x02080044);
+		NV_WR32(par->PRAMIN, 0x0819 * 4, 0x02000000);
+		NV_WR32(par->PRAMIN, 0x081A * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x081B * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x081C * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x081D * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0820 * 4, 0x02080019);
+		NV_WR32(par->PRAMIN, 0x0821 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0822 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0823 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0824 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0825 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0828 * 4, 0x020A005C);
+		NV_WR32(par->PRAMIN, 0x0829 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x082A * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x082B * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x082C * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x082D * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0830 * 4, 0x0208009F);
+		NV_WR32(par->PRAMIN, 0x0831 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0832 * 4, 0x00001200);
+		NV_WR32(par->PRAMIN, 0x0833 * 4, 0x00001200);
+		NV_WR32(par->PRAMIN, 0x0834 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0835 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0838 * 4, 0x0208004A);
+		NV_WR32(par->PRAMIN, 0x0839 * 4, 0x02000000);
+		NV_WR32(par->PRAMIN, 0x083A * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x083B * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x083C * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x083D * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0840 * 4, 0x02080077);
+		NV_WR32(par->PRAMIN, 0x0841 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0842 * 4, 0x00001200);
+		NV_WR32(par->PRAMIN, 0x0843 * 4, 0x00001200);
+		NV_WR32(par->PRAMIN, 0x0844 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0845 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x084C * 4, 0x00003002);
+		NV_WR32(par->PRAMIN, 0x084D * 4, 0x00007FFF);
+		NV_WR32(par->PRAMIN, 0x084E * 4,
+			par->FbUsableSize | 0x00000002);
+
+#ifdef __BIG_ENDIAN
+		NV_WR32(par->PRAMIN, 0x080A * 4,
+			NV_RD32(par->PRAMIN, 0x080A * 4) | 0x01000000);
+		NV_WR32(par->PRAMIN, 0x0812 * 4,
+			NV_RD32(par->PRAMIN, 0x0812 * 4) | 0x01000000);
+		NV_WR32(par->PRAMIN, 0x081A * 4,
+			NV_RD32(par->PRAMIN, 0x081A * 4) | 0x01000000);
+		NV_WR32(par->PRAMIN, 0x0822 * 4,
+			NV_RD32(par->PRAMIN, 0x0822 * 4) | 0x01000000);
+		NV_WR32(par->PRAMIN, 0x082A * 4,
+			NV_RD32(par->PRAMIN, 0x082A * 4) | 0x01000000);
+		NV_WR32(par->PRAMIN, 0x0832 * 4,
+			NV_RD32(par->PRAMIN, 0x0832 * 4) | 0x01000000);
+		NV_WR32(par->PRAMIN, 0x083A * 4,
+			NV_RD32(par->PRAMIN, 0x083A * 4) | 0x01000000);
+		NV_WR32(par->PRAMIN, 0x0842 * 4,
+			NV_RD32(par->PRAMIN, 0x0842 * 4) | 0x01000000);
+		NV_WR32(par->PRAMIN, 0x0819 * 4, 0x01000000);
+		NV_WR32(par->PRAMIN, 0x0839 * 4, 0x01000000);
+#endif
+	} else {
+		NV_WR32(par->PRAMIN, 0x0000 * 4, 0x80000010);
+		NV_WR32(par->PRAMIN, 0x0001 * 4, 0x80011201);
+		NV_WR32(par->PRAMIN, 0x0002 * 4, 0x80000011);
+		NV_WR32(par->PRAMIN, 0x0003 * 4, 0x80011202);
+		NV_WR32(par->PRAMIN, 0x0004 * 4, 0x80000012);
+		NV_WR32(par->PRAMIN, 0x0005 * 4, 0x80011203);
+		NV_WR32(par->PRAMIN, 0x0006 * 4, 0x80000013);
+		NV_WR32(par->PRAMIN, 0x0007 * 4, 0x80011204);
+		NV_WR32(par->PRAMIN, 0x0008 * 4, 0x80000014);
+		NV_WR32(par->PRAMIN, 0x0009 * 4, 0x80011205);
+		NV_WR32(par->PRAMIN, 0x000A * 4, 0x80000015);
+		NV_WR32(par->PRAMIN, 0x000B * 4, 0x80011206);
+		NV_WR32(par->PRAMIN, 0x000C * 4, 0x80000016);
+		NV_WR32(par->PRAMIN, 0x000D * 4, 0x80011207);
+		NV_WR32(par->PRAMIN, 0x000E * 4, 0x80000017);
+		NV_WR32(par->PRAMIN, 0x000F * 4, 0x80011208);
+		NV_WR32(par->PRAMIN, 0x0800 * 4, 0x00003000);
+		NV_WR32(par->PRAMIN, 0x0801 * 4, par->FbMapSize - 1);
+		NV_WR32(par->PRAMIN, 0x0802 * 4, 0x00000002);
+		NV_WR32(par->PRAMIN, 0x0803 * 4, 0x00000002);
+		if (par->Architecture >= NV_ARCH_10)
+			NV_WR32(par->PRAMIN, 0x0804 * 4, 0x01008062);
+		else
+			NV_WR32(par->PRAMIN, 0x0804 * 4, 0x01008042);
+		NV_WR32(par->PRAMIN, 0x0805 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0806 * 4, 0x12001200);
+		NV_WR32(par->PRAMIN, 0x0807 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0808 * 4, 0x01008043);
+		NV_WR32(par->PRAMIN, 0x0809 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x080A * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x080B * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x080C * 4, 0x01008044);
+		NV_WR32(par->PRAMIN, 0x080D * 4, 0x00000002);
+		NV_WR32(par->PRAMIN, 0x080E * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x080F * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0810 * 4, 0x01008019);
+		NV_WR32(par->PRAMIN, 0x0811 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0812 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0813 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0814 * 4, 0x0100A05C);
+		NV_WR32(par->PRAMIN, 0x0815 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0816 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0817 * 4, 0x00000000);
+		if (par->WaitVSyncPossible)
+			NV_WR32(par->PRAMIN, 0x0818 * 4, 0x0100809F);
+		else
+			NV_WR32(par->PRAMIN, 0x0818 * 4, 0x0100805F);
+		NV_WR32(par->PRAMIN, 0x0819 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x081A * 4, 0x12001200);
+		NV_WR32(par->PRAMIN, 0x081B * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x081C * 4, 0x0100804A);
+		NV_WR32(par->PRAMIN, 0x081D * 4, 0x00000002);
+		NV_WR32(par->PRAMIN, 0x081E * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x081F * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0820 * 4, 0x01018077);
+		NV_WR32(par->PRAMIN, 0x0821 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0822 * 4, 0x12001200);
+		NV_WR32(par->PRAMIN, 0x0823 * 4, 0x00000000);
+		NV_WR32(par->PRAMIN, 0x0824 * 4, 0x00003002);
+		NV_WR32(par->PRAMIN, 0x0825 * 4, 0x00007FFF);
+		NV_WR32(par->PRAMIN, 0x0826 * 4,
+			par->FbUsableSize | 0x00000002);
+		NV_WR32(par->PRAMIN, 0x0827 * 4, 0x00000002);
+#ifdef __BIG_ENDIAN
+		NV_WR32(par->PRAMIN, 0x0804 * 4,
+			NV_RD32(par->PRAMIN, 0x0804 * 4) | 0x00080000);
+		NV_WR32(par->PRAMIN, 0x0808 * 4,
+			NV_RD32(par->PRAMIN, 0x0808 * 4) | 0x00080000);
+		NV_WR32(par->PRAMIN, 0x080C * 4,
+			NV_RD32(par->PRAMIN, 0x080C * 4) | 0x00080000);
+		NV_WR32(par->PRAMIN, 0x0810 * 4,
+			NV_RD32(par->PRAMIN, 0x0810 * 4) | 0x00080000);
+		NV_WR32(par->PRAMIN, 0x0814 * 4,
+			NV_RD32(par->PRAMIN, 0x0814 * 4) | 0x00080000);
+		NV_WR32(par->PRAMIN, 0x0818 * 4,
+			NV_RD32(par->PRAMIN, 0x0818 * 4) | 0x00080000);
+		NV_WR32(par->PRAMIN, 0x081C * 4,
+			NV_RD32(par->PRAMIN, 0x081C * 4) | 0x00080000);
+		NV_WR32(par->PRAMIN, 0x0820 * 4,
+			NV_RD32(par->PRAMIN, 0x0820 * 4) | 0x00080000);
+		NV_WR32(par->PRAMIN, 0x080D * 4, 0x00000001);
+		NV_WR32(par->PRAMIN, 0x081D * 4, 0x00000001);
+#endif
+	}
+	if (par->Architecture < NV_ARCH_10) {
+		if ((par->Chipset & 0x0fff) == 0x0020) {
+			NV_WR32(par->PRAMIN, 0x0824 * 4,
+				NV_RD32(par->PRAMIN, 0x0824 * 4) | 0x00020000);
+			NV_WR32(par->PRAMIN, 0x0826 * 4,
+				NV_RD32(par->PRAMIN,
+					0x0826 * 4) + par->FbAddress);
+		}
+		NV_WR32(par->PGRAPH, 0x0080, 0x000001FF);
+		NV_WR32(par->PGRAPH, 0x0080, 0x1230C000);
+		NV_WR32(par->PGRAPH, 0x0084, 0x72111101);
+		NV_WR32(par->PGRAPH, 0x0088, 0x11D5F071);
+		NV_WR32(par->PGRAPH, 0x008C, 0x0004FF31);
+		NV_WR32(par->PGRAPH, 0x008C, 0x4004FF31);
+		NV_WR32(par->PGRAPH, 0x0140, 0x00000000);
+		NV_WR32(par->PGRAPH, 0x0100, 0xFFFFFFFF);
+		NV_WR32(par->PGRAPH, 0x0170, 0x10010100);
+		NV_WR32(par->PGRAPH, 0x0710, 0xFFFFFFFF);
+		NV_WR32(par->PGRAPH, 0x0720, 0x00000001);
+		NV_WR32(par->PGRAPH, 0x0810, 0x00000000);
+		NV_WR32(par->PGRAPH, 0x0608, 0xFFFFFFFF);
+	} else {
+		NV_WR32(par->PGRAPH, 0x0080, 0xFFFFFFFF);
+		NV_WR32(par->PGRAPH, 0x0080, 0x00000000);
+
+		NV_WR32(par->PGRAPH, 0x0140, 0x00000000);
+		NV_WR32(par->PGRAPH, 0x0100, 0xFFFFFFFF);
+		NV_WR32(par->PGRAPH, 0x0144, 0x10010100);
+		NV_WR32(par->PGRAPH, 0x0714, 0xFFFFFFFF);
+		NV_WR32(par->PGRAPH, 0x0720, 0x00000001);
+		NV_WR32(par->PGRAPH, 0x0710,
+			NV_RD32(par->PGRAPH, 0x0710) & 0x0007ff00);
+		NV_WR32(par->PGRAPH, 0x0710,
+			NV_RD32(par->PGRAPH, 0x0710) | 0x00020100);
+
+		if (par->Architecture == NV_ARCH_10) {
+			NV_WR32(par->PGRAPH, 0x0084, 0x00118700);
+			NV_WR32(par->PGRAPH, 0x0088, 0x24E00810);
+			NV_WR32(par->PGRAPH, 0x008C, 0x55DE0030);
+
+			for (i = 0; i < 32; i++)
+				NV_WR32(&par->PGRAPH[(0x0B00 / 4) + i], 0,
+					NV_RD32(&par->PFB[(0x0240 / 4) + i],
+						0));
+
+			NV_WR32(par->PGRAPH, 0x640, 0);
+			NV_WR32(par->PGRAPH, 0x644, 0);
+			NV_WR32(par->PGRAPH, 0x684, par->FbMapSize - 1);
+			NV_WR32(par->PGRAPH, 0x688, par->FbMapSize - 1);
+
+			NV_WR32(par->PGRAPH, 0x0810, 0x00000000);
+			NV_WR32(par->PGRAPH, 0x0608, 0xFFFFFFFF);
+		} else {
+			if (par->Architecture >= NV_ARCH_40) {
+				NV_WR32(par->PGRAPH, 0x0084, 0x401287c0);
+				NV_WR32(par->PGRAPH, 0x008C, 0x60de8051);
+				NV_WR32(par->PGRAPH, 0x0090, 0x00008000);
+				NV_WR32(par->PGRAPH, 0x0610, 0x00be3c5f);
+
+				if ((par->Chipset & 0xfff0) == 0x0040) {
+					NV_WR32(par->PGRAPH, 0x09b0,
+						0x83280fff);
+					NV_WR32(par->PGRAPH, 0x09b4,
+						0x000000a0);
+				} else {
+					NV_WR32(par->PGRAPH, 0x0820,
+						0x83280eff);
+					NV_WR32(par->PGRAPH, 0x0824,
+						0x000000a0);
+				}
+
+				switch (par->Chipset & 0xfff0) {
+				case 0x0040:
+				case 0x0210:
+					NV_WR32(par->PGRAPH, 0x09b8,
+						0x0078e366);
+					NV_WR32(par->PGRAPH, 0x09bc,
+						0x0000014c);
+					NV_WR32(par->PFB, 0x033C,
+						NV_RD32(par->PFB, 0x33C) &
+						0xffff7fff);
+					break;
+				case 0x00C0:
+					NV_WR32(par->PGRAPH, 0x0828,
+						0x007596ff);
+					NV_WR32(par->PGRAPH, 0x082C,
+						0x00000108);
+					break;
+				case 0x0160:
+				case 0x01D0:
+					NV_WR32(par->PMC, 0x1700,
+						NV_RD32(par->PFB, 0x020C));
+					NV_WR32(par->PMC, 0x1704, 0);
+					NV_WR32(par->PMC, 0x1708, 0);
+					NV_WR32(par->PMC, 0x170C,
+						NV_RD32(par->PFB, 0x020C));
+					NV_WR32(par->PGRAPH, 0x0860, 0);
+					NV_WR32(par->PGRAPH, 0x0864, 0);
+					NV_WR32(par->PRAMDAC, 0x0608,
+						NV_RD32(par->PRAMDAC,
+							0x0608) | 0x00100000);
+					break;
+				case 0x0140:
+					NV_WR32(par->PGRAPH, 0x0828,
+						0x0072cb77);
+					NV_WR32(par->PGRAPH, 0x082C,
+						0x00000108);
+					break;
+				case 0x0220:
+				case 0x0230:
+					NV_WR32(par->PGRAPH, 0x0860, 0);
+					NV_WR32(par->PGRAPH, 0x0864, 0);
+					NV_WR32(par->PRAMDAC, 0x0608,
+						NV_RD32(par->PRAMDAC, 0x0608) |
+						0x00100000);
+					break;
+				case 0x0090:
+					NV_WR32(par->PRAMDAC, 0x0608,
+						NV_RD32(par->PRAMDAC, 0x0608) |
+						0x00100000);
+					NV_WR32(par->PGRAPH, 0x0828,
+						0x07830610);
+					NV_WR32(par->PGRAPH, 0x082C,
+						0x0000016A);
+					break;
+				default:
+					break;
+				};
+
+				NV_WR32(par->PGRAPH, 0x0b38, 0x2ffff800);
+				NV_WR32(par->PGRAPH, 0x0b3c, 0x00006000);
+				NV_WR32(par->PGRAPH, 0x032C, 0x01000000);
+				NV_WR32(par->PGRAPH, 0x0220, 0x00001200);
+			} else if (par->Architecture == NV_ARCH_30) {
+				NV_WR32(par->PGRAPH, 0x0084, 0x40108700);
+				NV_WR32(par->PGRAPH, 0x0890, 0x00140000);
+				NV_WR32(par->PGRAPH, 0x008C, 0xf00e0431);
+				NV_WR32(par->PGRAPH, 0x0090, 0x00008000);
+				NV_WR32(par->PGRAPH, 0x0610, 0xf04b1f36);
+				NV_WR32(par->PGRAPH, 0x0B80, 0x1002d888);
+				NV_WR32(par->PGRAPH, 0x0B88, 0x62ff007f);
+			} else {
+				NV_WR32(par->PGRAPH, 0x0084, 0x00118700);
+				NV_WR32(par->PGRAPH, 0x008C, 0xF20E0431);
+				NV_WR32(par->PGRAPH, 0x0090, 0x00000000);
+				NV_WR32(par->PGRAPH, 0x009C, 0x00000040);
+
+				if ((par->Chipset & 0x0ff0) >= 0x0250) {
+					NV_WR32(par->PGRAPH, 0x0890,
+						0x00080000);
+					NV_WR32(par->PGRAPH, 0x0610,
+						0x304B1FB6);
+					NV_WR32(par->PGRAPH, 0x0B80,
+						0x18B82880);
+					NV_WR32(par->PGRAPH, 0x0B84,
+						0x44000000);
+					NV_WR32(par->PGRAPH, 0x0098,
+						0x40000080);
+					NV_WR32(par->PGRAPH, 0x0B88,
+						0x000000ff);
+				} else {
+					NV_WR32(par->PGRAPH, 0x0880,
+						0x00080000);
+					NV_WR32(par->PGRAPH, 0x0094,
+						0x00000005);
+					NV_WR32(par->PGRAPH, 0x0B80,
+						0x45CAA208);
+					NV_WR32(par->PGRAPH, 0x0B84,
+						0x24000000);
+					NV_WR32(par->PGRAPH, 0x0098,
+						0x00000040);
+					NV_WR32(par->PGRAPH, 0x0750,
+						0x00E00038);
+					NV_WR32(par->PGRAPH, 0x0754,
+						0x00000030);
+					NV_WR32(par->PGRAPH, 0x0750,
+						0x00E10038);
+					NV_WR32(par->PGRAPH, 0x0754,
+						0x00000030);
+				}
+			}
+
+			if ((par->Chipset & 0xfff0) == 0x0090) {
+				for (i = 0; i < 60; i++)
+					NV_WR32(par->PGRAPH, 0x0D00 + i,
+						NV_RD32(par->PFB, 0x0600 + i));
+			} else {
+				for (i = 0; i < 32; i++)
+					NV_WR32(par->PGRAPH, 0x0900 + i,
+						NV_RD32(par->PFB, 0x0240 + i));
+			}
+
+			if (par->Architecture >= NV_ARCH_40) {
+				if ((par->Chipset & 0xfff0) == 0x0040) {
+					NV_WR32(par->PGRAPH, 0x09A4,
+						NV_RD32(par->PFB, 0x0200));
+					NV_WR32(par->PGRAPH, 0x09A8,
+						NV_RD32(par->PFB, 0x0204));
+					NV_WR32(par->PGRAPH, 0x69A4,
+						NV_RD32(par->PFB, 0x0200));
+					NV_WR32(par->PGRAPH, 0x69A8,
+						NV_RD32(par->PFB, 0x0204));
+
+					NV_WR32(par->PGRAPH, 0x0820, 0);
+					NV_WR32(par->PGRAPH, 0x0824, 0);
+					NV_WR32(par->PGRAPH, 0x0864,
+						par->FbMapSize - 1);
+					NV_WR32(par->PGRAPH, 0x0868,
+						par->FbMapSize - 1);
+				} else {
+					if((par->Chipset & 0xfff0) == 0x0090) {
+						NV_WR32(par->PGRAPH, 0x0DF0,
+							NV_RD32(par->PFB, 0x0200));
+						NV_WR32(par->PGRAPH, 0x0DF4,
+							NV_RD32(par->PFB, 0x0204));
+					} else {
+						NV_WR32(par->PGRAPH, 0x09F0,
+							NV_RD32(par->PFB, 0x0200));
+						NV_WR32(par->PGRAPH, 0x09F4,
+							NV_RD32(par->PFB, 0x0204));
+					}
+					NV_WR32(par->PGRAPH, 0x69F0,
+						NV_RD32(par->PFB, 0x0200));
+					NV_WR32(par->PGRAPH, 0x69F4,
+						NV_RD32(par->PFB, 0x0204));
+
+					NV_WR32(par->PGRAPH, 0x0840, 0);
+					NV_WR32(par->PGRAPH, 0x0844, 0);
+					NV_WR32(par->PGRAPH, 0x08a0,
+						par->FbMapSize - 1);
+					NV_WR32(par->PGRAPH, 0x08a4,
+						par->FbMapSize - 1);
+				}
+			} else {
+				NV_WR32(par->PGRAPH, 0x09A4,
+					NV_RD32(par->PFB, 0x0200));
+				NV_WR32(par->PGRAPH, 0x09A8,
+					NV_RD32(par->PFB, 0x0204));
+				NV_WR32(par->PGRAPH, 0x0750, 0x00EA0000);
+				NV_WR32(par->PGRAPH, 0x0754,
+					NV_RD32(par->PFB, 0x0200));
+				NV_WR32(par->PGRAPH, 0x0750, 0x00EA0004);
+				NV_WR32(par->PGRAPH, 0x0754,
+					NV_RD32(par->PFB, 0x0204));
+
+				NV_WR32(par->PGRAPH, 0x0820, 0);
+				NV_WR32(par->PGRAPH, 0x0824, 0);
+				NV_WR32(par->PGRAPH, 0x0864,
+					par->FbMapSize - 1);
+				NV_WR32(par->PGRAPH, 0x0868,
+					par->FbMapSize - 1);
+			}
+			NV_WR32(par->PGRAPH, 0x0B20, 0x00000000);
+			NV_WR32(par->PGRAPH, 0x0B04, 0xFFFFFFFF);
+		}
+	}
+	NV_WR32(par->PGRAPH, 0x053C, 0);
+	NV_WR32(par->PGRAPH, 0x0540, 0);
+	NV_WR32(par->PGRAPH, 0x0544, 0x00007FFF);
+	NV_WR32(par->PGRAPH, 0x0548, 0x00007FFF);
+
+	NV_WR32(par->PFIFO, 0x0140 * 4, 0x00000000);
+	NV_WR32(par->PFIFO, 0x0141 * 4, 0x00000001);
+	NV_WR32(par->PFIFO, 0x0480 * 4, 0x00000000);
+	NV_WR32(par->PFIFO, 0x0494 * 4, 0x00000000);
+	if (par->Architecture >= NV_ARCH_40)
+		NV_WR32(par->PFIFO, 0x0481 * 4, 0x00010000);
+	else
+		NV_WR32(par->PFIFO, 0x0481 * 4, 0x00000100);
+	NV_WR32(par->PFIFO, 0x0490 * 4, 0x00000000);
+	NV_WR32(par->PFIFO, 0x0491 * 4, 0x00000000);
+	if (par->Architecture >= NV_ARCH_40)
+		NV_WR32(par->PFIFO, 0x048B * 4, 0x00001213);
+	else
+		NV_WR32(par->PFIFO, 0x048B * 4, 0x00001209);
+	NV_WR32(par->PFIFO, 0x0400 * 4, 0x00000000);
+	NV_WR32(par->PFIFO, 0x0414 * 4, 0x00000000);
+	NV_WR32(par->PFIFO, 0x0084 * 4, 0x03000100);
+	NV_WR32(par->PFIFO, 0x0085 * 4, 0x00000110);
+	NV_WR32(par->PFIFO, 0x0086 * 4, 0x00000112);
+	NV_WR32(par->PFIFO, 0x0143 * 4, 0x0000FFFF);
+	NV_WR32(par->PFIFO, 0x0496 * 4, 0x0000FFFF);
+	NV_WR32(par->PFIFO, 0x0050 * 4, 0x00000000);
+	NV_WR32(par->PFIFO, 0x0040 * 4, 0xFFFFFFFF);
+	NV_WR32(par->PFIFO, 0x0415 * 4, 0x00000001);
+	NV_WR32(par->PFIFO, 0x048C * 4, 0x00000000);
+	NV_WR32(par->PFIFO, 0x04A0 * 4, 0x00000000);
+#ifdef __BIG_ENDIAN
+	NV_WR32(par->PFIFO, 0x0489 * 4, 0x800F0078);
+#else
+	NV_WR32(par->PFIFO, 0x0489 * 4, 0x000F0078);
+#endif
+	NV_WR32(par->PFIFO, 0x0488 * 4, 0x00000001);
+	NV_WR32(par->PFIFO, 0x0480 * 4, 0x00000001);
+	NV_WR32(par->PFIFO, 0x0494 * 4, 0x00000001);
+	NV_WR32(par->PFIFO, 0x0495 * 4, 0x00000001);
+	NV_WR32(par->PFIFO, 0x0140 * 4, 0x00000001);
+	if (par->Architecture >= NV_ARCH_10) {
+		if (par->twoHeads) {
+			NV_WR32(par->PCRTC0, 0x0860, state->head);
+			NV_WR32(par->PCRTC0, 0x2860, state->head2);
+		}
+		NV_WR32(par->PRAMDAC, 0x0404, NV_RD32(par->PRAMDAC, 0x0404) |
+			(1 << 25));
+
+		NV_WR32(par->PMC, 0x8704, 1);
+		NV_WR32(par->PMC, 0x8140, 0);
+		NV_WR32(par->PMC, 0x8920, 0);
+		NV_WR32(par->PMC, 0x8924, 0);
+		NV_WR32(par->PMC, 0x8908, par->FbMapSize - 1);
+		NV_WR32(par->PMC, 0x890C, par->FbMapSize - 1);
+		NV_WR32(par->PMC, 0x1588, 0);
+
+		NV_WR32(par->PCRTC, 0x0810, state->cursorConfig);
+		NV_WR32(par->PCRTC, 0x0830, state->displayV - 3);
+		NV_WR32(par->PCRTC, 0x0834, state->displayV - 1);
+
+		if (par->FlatPanel) {
+			if ((par->Chipset & 0x0ff0) == 0x0110) {
+				NV_WR32(par->PRAMDAC, 0x0528, state->dither);
+			} else if (par->twoHeads) {
+				NV_WR32(par->PRAMDAC, 0x083C, state->dither);
+			}
+
+			VGA_WR08(par->PCIO, 0x03D4, 0x53);
+			VGA_WR08(par->PCIO, 0x03D5, state->timingH);
+			VGA_WR08(par->PCIO, 0x03D4, 0x54);
+			VGA_WR08(par->PCIO, 0x03D5, state->timingV);
+			VGA_WR08(par->PCIO, 0x03D4, 0x21);
+			VGA_WR08(par->PCIO, 0x03D5, 0xfa);
+		}
+
+		VGA_WR08(par->PCIO, 0x03D4, 0x41);
+		VGA_WR08(par->PCIO, 0x03D5, state->extra);
+	}
+
+	VGA_WR08(par->PCIO, 0x03D4, 0x19);
+	VGA_WR08(par->PCIO, 0x03D5, state->repaint0);
+	VGA_WR08(par->PCIO, 0x03D4, 0x1A);
+	VGA_WR08(par->PCIO, 0x03D5, state->repaint1);
+	VGA_WR08(par->PCIO, 0x03D4, 0x25);
+	VGA_WR08(par->PCIO, 0x03D5, state->screen);
+	VGA_WR08(par->PCIO, 0x03D4, 0x28);
+	VGA_WR08(par->PCIO, 0x03D5, state->pixel);
+	VGA_WR08(par->PCIO, 0x03D4, 0x2D);
+	VGA_WR08(par->PCIO, 0x03D5, state->horiz);
+	VGA_WR08(par->PCIO, 0x03D4, 0x1C);
+	VGA_WR08(par->PCIO, 0x03D5, state->fifo);
+	VGA_WR08(par->PCIO, 0x03D4, 0x1B);
+	VGA_WR08(par->PCIO, 0x03D5, state->arbitration0);
+	VGA_WR08(par->PCIO, 0x03D4, 0x20);
+	VGA_WR08(par->PCIO, 0x03D5, state->arbitration1);
+
+	if(par->Architecture >= NV_ARCH_30) {
+		VGA_WR08(par->PCIO, 0x03D4, 0x47);
+		VGA_WR08(par->PCIO, 0x03D5, state->arbitration1 >> 8);
+	}
+
+	VGA_WR08(par->PCIO, 0x03D4, 0x30);
+	VGA_WR08(par->PCIO, 0x03D5, state->cursor0);
+	VGA_WR08(par->PCIO, 0x03D4, 0x31);
+	VGA_WR08(par->PCIO, 0x03D5, state->cursor1);
+	VGA_WR08(par->PCIO, 0x03D4, 0x2F);
+	VGA_WR08(par->PCIO, 0x03D5, state->cursor2);
+	VGA_WR08(par->PCIO, 0x03D4, 0x39);
+	VGA_WR08(par->PCIO, 0x03D5, state->interlace);
+
+	if (!par->FlatPanel) {
+		NV_WR32(par->PRAMDAC0, 0x050C, state->pllsel);
+		NV_WR32(par->PRAMDAC0, 0x0508, state->vpll);
+		if (par->twoHeads)
+			NV_WR32(par->PRAMDAC0, 0x0520, state->vpll2);
+		if (par->twoStagePLL) {
+			NV_WR32(par->PRAMDAC0, 0x0578, state->vpllB);
+			NV_WR32(par->PRAMDAC0, 0x057C, state->vpll2B);
+		}
+	} else {
+		NV_WR32(par->PRAMDAC, 0x0848, state->scale);
+		NV_WR32(par->PRAMDAC, 0x0828, state->crtcSync +
+			par->PanelTweak);
+	}
+
+	NV_WR32(par->PRAMDAC, 0x0600, state->general);
+
+	NV_WR32(par->PCRTC, 0x0140, 0);
+	NV_WR32(par->PCRTC, 0x0100, 1);
+
+	par->CurrentState = state;
+}
+
+void NVUnloadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) {
+	VGA_WR08(par->PCIO, 0x03D4, 0x19);
+	state->repaint0 = VGA_RD08(par->PCIO, 0x03D5);
+	VGA_WR08(par->PCIO, 0x03D4, 0x1A);
+	state->repaint1 = VGA_RD08(par->PCIO, 0x03D5);
+	VGA_WR08(par->PCIO, 0x03D4, 0x25);
+	state->screen = VGA_RD08(par->PCIO, 0x03D5);
+	VGA_WR08(par->PCIO, 0x03D4, 0x28);
+	state->pixel = VGA_RD08(par->PCIO, 0x03D5);
+	VGA_WR08(par->PCIO, 0x03D4, 0x2D);
+	state->horiz = VGA_RD08(par->PCIO, 0x03D5);
+	VGA_WR08(par->PCIO, 0x03D4, 0x1C);
+	state->fifo         = VGA_RD08(par->PCIO, 0x03D5);
+	VGA_WR08(par->PCIO, 0x03D4, 0x1B);
+	state->arbitration0 = VGA_RD08(par->PCIO, 0x03D5);
+	VGA_WR08(par->PCIO, 0x03D4, 0x20);
+	state->arbitration1 = VGA_RD08(par->PCIO, 0x03D5);
+
+	if(par->Architecture >= NV_ARCH_30) {
+		VGA_WR08(par->PCIO, 0x03D4, 0x47);
+		state->arbitration1 |= (VGA_RD08(par->PCIO, 0x03D5) & 1) << 8;
+	}
+
+	VGA_WR08(par->PCIO, 0x03D4, 0x30);
+	state->cursor0 = VGA_RD08(par->PCIO, 0x03D5);
+	VGA_WR08(par->PCIO, 0x03D4, 0x31);
+	state->cursor1 = VGA_RD08(par->PCIO, 0x03D5);
+	VGA_WR08(par->PCIO, 0x03D4, 0x2F);
+	state->cursor2 = VGA_RD08(par->PCIO, 0x03D5);
+	VGA_WR08(par->PCIO, 0x03D4, 0x39);
+	state->interlace = VGA_RD08(par->PCIO, 0x03D5);
+	state->vpll = NV_RD32(par->PRAMDAC0, 0x0508);
+	if (par->twoHeads)
+		state->vpll2 = NV_RD32(par->PRAMDAC0, 0x0520);
+	if (par->twoStagePLL) {
+		state->vpllB = NV_RD32(par->PRAMDAC0, 0x0578);
+		state->vpll2B = NV_RD32(par->PRAMDAC0, 0x057C);
+	}
+	state->pllsel = NV_RD32(par->PRAMDAC0, 0x050C);
+	state->general = NV_RD32(par->PRAMDAC, 0x0600);
+	state->scale = NV_RD32(par->PRAMDAC, 0x0848);
+	state->config = NV_RD32(par->PFB, 0x0200);
+
+	if (par->Architecture >= NV_ARCH_10) {
+		if (par->twoHeads) {
+			state->head = NV_RD32(par->PCRTC0, 0x0860);
+			state->head2 = NV_RD32(par->PCRTC0, 0x2860);
+			VGA_WR08(par->PCIO, 0x03D4, 0x44);
+			state->crtcOwner = VGA_RD08(par->PCIO, 0x03D5);
+		}
+		VGA_WR08(par->PCIO, 0x03D4, 0x41);
+		state->extra = VGA_RD08(par->PCIO, 0x03D5);
+		state->cursorConfig = NV_RD32(par->PCRTC, 0x0810);
+
+		if ((par->Chipset & 0x0ff0) == 0x0110) {
+			state->dither = NV_RD32(par->PRAMDAC, 0x0528);
+		} else if (par->twoHeads) {
+			state->dither = NV_RD32(par->PRAMDAC, 0x083C);
+		}
+
+		if (par->FlatPanel) {
+			VGA_WR08(par->PCIO, 0x03D4, 0x53);
+			state->timingH = VGA_RD08(par->PCIO, 0x03D5);
+			VGA_WR08(par->PCIO, 0x03D4, 0x54);
+			state->timingV = VGA_RD08(par->PCIO, 0x03D5);
+		}
+	}
+}
+
+void NVSetStartAddress(struct nvidia_par *par, u32 start)
+{
+	NV_WR32(par->PCRTC, 0x800, start);
+}
diff --git a/drivers/video/nvidia/nv_i2c.c b/drivers/video/nvidia/nv_i2c.c
new file mode 100644
index 0000000..3757c14
--- /dev/null
+++ b/drivers/video/nvidia/nv_i2c.c
@@ -0,0 +1,215 @@
+/*
+ * linux/drivers/video/nvidia/nvidia-i2c.c - nVidia i2c
+ *
+ * Copyright 2004 Antonino A. Daplas <adaplas @pol.net>
+ *
+ * Based on rivafb-i2c.c
+ *
+ * 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/sched.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/fb.h>
+
+#include <asm/io.h>
+
+#include "nv_type.h"
+#include "nv_local.h"
+#include "nv_proto.h"
+
+#include "../edid.h"
+
+static void nvidia_gpio_setscl(void *data, int state)
+{
+	struct nvidia_i2c_chan *chan = data;
+	struct nvidia_par *par = chan->par;
+	u32 val;
+
+	VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base + 1);
+	val = VGA_RD08(par->PCIO, 0x3d5) & 0xf0;
+
+	if (state)
+		val |= 0x20;
+	else
+		val &= ~0x20;
+
+	VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base + 1);
+	VGA_WR08(par->PCIO, 0x3d5, val | 0x1);
+}
+
+static void nvidia_gpio_setsda(void *data, int state)
+{
+	struct nvidia_i2c_chan *chan = (struct nvidia_i2c_chan *)data;
+	struct nvidia_par *par = chan->par;
+	u32 val;
+
+	VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base + 1);
+	val = VGA_RD08(par->PCIO, 0x3d5) & 0xf0;
+
+	if (state)
+		val |= 0x10;
+	else
+		val &= ~0x10;
+
+	VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base + 1);
+	VGA_WR08(par->PCIO, 0x3d5, val | 0x1);
+}
+
+static int nvidia_gpio_getscl(void *data)
+{
+	struct nvidia_i2c_chan *chan = (struct nvidia_i2c_chan *)data;
+	struct nvidia_par *par = chan->par;
+	u32 val = 0;
+
+	VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base);
+	if (VGA_RD08(par->PCIO, 0x3d5) & 0x04)
+		val = 1;
+
+	val = VGA_RD08(par->PCIO, 0x3d5);
+
+	return val;
+}
+
+static int nvidia_gpio_getsda(void *data)
+{
+	struct nvidia_i2c_chan *chan = (struct nvidia_i2c_chan *)data;
+	struct nvidia_par *par = chan->par;
+	u32 val = 0;
+
+	VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base);
+	if (VGA_RD08(par->PCIO, 0x3d5) & 0x08)
+		val = 1;
+
+	return val;
+}
+
+#define I2C_ALGO_NVIDIA   0x0e0000
+static int nvidia_setup_i2c_bus(struct nvidia_i2c_chan *chan, const char *name)
+{
+	int rc;
+
+	strcpy(chan->adapter.name, name);
+	chan->adapter.owner = THIS_MODULE;
+	chan->adapter.id = I2C_ALGO_NVIDIA;
+	chan->adapter.algo_data = &chan->algo;
+	chan->adapter.dev.parent = &chan->par->pci_dev->dev;
+	chan->algo.setsda = nvidia_gpio_setsda;
+	chan->algo.setscl = nvidia_gpio_setscl;
+	chan->algo.getsda = nvidia_gpio_getsda;
+	chan->algo.getscl = nvidia_gpio_getscl;
+	chan->algo.udelay = 40;
+	chan->algo.timeout = msecs_to_jiffies(2);
+	chan->algo.data = chan;
+
+	i2c_set_adapdata(&chan->adapter, chan);
+
+	/* Raise SCL and SDA */
+	nvidia_gpio_setsda(chan, 1);
+	nvidia_gpio_setscl(chan, 1);
+	udelay(20);
+
+	rc = i2c_bit_add_bus(&chan->adapter);
+	if (rc == 0)
+		dev_dbg(&chan->par->pci_dev->dev,
+			"I2C bus %s registered.\n", name);
+	else {
+		dev_warn(&chan->par->pci_dev->dev,
+			 "Failed to register I2C bus %s.\n", name);
+		chan->par = NULL;
+	}
+
+	return rc;
+}
+
+void nvidia_create_i2c_busses(struct nvidia_par *par)
+{
+	par->bus = 3;
+
+	par->chan[0].par = par;
+	par->chan[1].par = par;
+	par->chan[2].par = par;
+
+	par->chan[0].ddc_base = 0x3e;
+	nvidia_setup_i2c_bus(&par->chan[0], "BUS1");
+
+	par->chan[1].ddc_base = 0x36;
+	nvidia_setup_i2c_bus(&par->chan[1], "BUS2");
+
+	par->chan[2].ddc_base = 0x50;
+	nvidia_setup_i2c_bus(&par->chan[2], "BUS3");
+}
+
+void nvidia_delete_i2c_busses(struct nvidia_par *par)
+{
+	if (par->chan[0].par)
+		i2c_bit_del_bus(&par->chan[0].adapter);
+	par->chan[0].par = NULL;
+
+	if (par->chan[1].par)
+		i2c_bit_del_bus(&par->chan[1].adapter);
+	par->chan[1].par = NULL;
+
+	if (par->chan[2].par)
+		i2c_bit_del_bus(&par->chan[2].adapter);
+	par->chan[2].par = NULL;
+
+}
+
+static u8 *nvidia_do_probe_i2c_edid(struct nvidia_i2c_chan *chan)
+{
+	u8 start = 0x0;
+	struct i2c_msg msgs[] = {
+		{
+		 .addr = 0x50,
+		 .len = 1,
+		 .buf = &start,
+		 }, {
+		     .addr = 0x50,
+		     .flags = I2C_M_RD,
+		     .len = EDID_LENGTH,
+		     },
+	};
+	u8 *buf;
+
+	if (!chan->par)
+		return NULL;
+
+	buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
+	if (!buf) {
+		dev_warn(&chan->par->pci_dev->dev, "Out of memory!\n");
+		return NULL;
+	}
+	msgs[1].buf = buf;
+
+	if (i2c_transfer(&chan->adapter, msgs, 2) == 2)
+		return buf;
+	dev_dbg(&chan->par->pci_dev->dev, "Unable to read EDID block.\n");
+	kfree(buf);
+	return NULL;
+}
+
+int nvidia_probe_i2c_connector(struct nvidia_par *par, int conn, u8 **out_edid)
+{
+	u8 *edid = NULL;
+	int i;
+
+	for (i = 0; i < 3; i++) {
+		/* Do the real work */
+		edid = nvidia_do_probe_i2c_edid(&par->chan[conn - 1]);
+		if (edid)
+			break;
+	}
+	if (out_edid)
+		*out_edid = edid;
+	if (!edid)
+		return 1;
+
+	return 0;
+}
diff --git a/drivers/video/nvidia/nv_local.h b/drivers/video/nvidia/nv_local.h
new file mode 100644
index 0000000..9da3209
--- /dev/null
+++ b/drivers/video/nvidia/nv_local.h
@@ -0,0 +1,107 @@
+/***************************************************************************\
+|*                                                                           *|
+|*       Copyright 1993-2003 NVIDIA, Corporation.  All rights reserved.      *|
+|*                                                                           *|
+|*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
+|*     international laws.  Users and possessors of this source code are     *|
+|*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
+|*     use this code in individual and commercial software.                  *|
+|*                                                                           *|
+|*     Any use of this source code must include,  in the user documenta-     *|
+|*     tion and  internal comments to the code,  notices to the end user     *|
+|*     as follows:                                                           *|
+|*                                                                           *|
+|*       Copyright 1993-1999 NVIDIA, Corporation.  All rights reserved.      *|
+|*                                                                           *|
+|*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
+|*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
+|*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
+|*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
+|*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
+|*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
+|*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
+|*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
+|*     SULTING FROM LOSS OF USE,  DATA OR PROFITS,  WHETHER IN AN ACTION     *|
+|*     OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,  ARISING OUT OF     *|
+|*     OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.     *|
+|*                                                                           *|
+|*     U.S. Government  End  Users.   This source code  is a "commercial     *|
+|*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
+|*     consisting  of "commercial  computer  software"  and  "commercial     *|
+|*     computer  software  documentation,"  as such  terms  are  used in     *|
+|*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
+|*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
+|*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
+|*     all U.S. Government End Users  acquire the source code  with only     *|
+|*     those rights set forth herein.                                        *|
+|*                                                                           *|
+ \***************************************************************************/
+
+/*
+ * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/
+ * XFree86 'nv' driver, this source code is provided under MIT-style licensing
+ * where the source code is provided "as is" without warranty of any kind.
+ * The only usage restriction is for the copyright notices to be retained
+ * whenever code is used.
+ *
+ * Antonino Daplas <adaplas@pol.net> 2005-03-11
+ */
+
+#ifndef __NV_LOCAL_H__
+#define __NV_LOCAL_H__
+
+/*
+ * This file includes any environment or machine specific values to access the
+ * HW.  Put all affected includes, typdefs, etc. here so the riva_hw.* files
+ * can stay generic in nature.
+ */
+
+/*
+ * HW access macros.  These assume memory-mapped I/O, and not normal I/O space.
+ */
+#define NV_WR08(p,i,d)  (__raw_writeb((d), (void __iomem *)(p) + (i)))
+#define NV_RD08(p,i)    (__raw_readb((void __iomem *)(p) + (i)))
+#define NV_WR16(p,i,d)  (__raw_writew((d), (void __iomem *)(p) + (i)))
+#define NV_RD16(p,i)    (__raw_readw((void __iomem *)(p) + (i)))
+#define NV_WR32(p,i,d)  (__raw_writel((d), (void __iomem *)(p) + (i)))
+#define NV_RD32(p,i)    (__raw_readl((void __iomem *)(p) + (i)))
+
+/* VGA I/O is now always done through MMIO */
+#define VGA_WR08(p,i,d) (writeb((d), (void __iomem *)(p) + (i)))
+#define VGA_RD08(p,i)   (readb((void __iomem *)(p) + (i)))
+
+#define NVDmaNext(par, data) \
+     NV_WR32(&(par)->dmaBase[(par)->dmaCurrent++], 0, (data))
+
+#define NVDmaStart(par, tag, size) {          \
+     if((par)->dmaFree <= (size))             \
+        NVDmaWait(par, size);                 \
+     NVDmaNext(par, ((size) << 18) | (tag));  \
+     (par)->dmaFree -= ((size) + 1);          \
+}
+
+#if defined(__i386__)
+#define _NV_FENCE() outb(0, 0x3D0);
+#else
+#define _NV_FENCE() mb();
+#endif
+
+#define WRITE_PUT(par, data) {                   \
+  _NV_FENCE()                                    \
+  NV_RD08((par)->FbStart, 0);                    \
+  NV_WR32(&(par)->FIFO[0x0010], 0, (data) << 2); \
+  mb();                                          \
+}
+
+#define READ_GET(par) (NV_RD32(&(par)->FIFO[0x0011], 0) >> 2)
+
+#define reverse_order(l)        \
+do {                            \
+	u8 *a = (u8 *)(l);      \
+	*a = byte_rev[*a], a++; \
+	*a = byte_rev[*a], a++; \
+	*a = byte_rev[*a], a++; \
+	*a = byte_rev[*a];      \
+} while(0)
+
+#endif				/* __NV_LOCAL_H__ */
diff --git a/drivers/video/nvidia/nv_of.c b/drivers/video/nvidia/nv_of.c
new file mode 100644
index 0000000..7d12eb85
--- /dev/null
+++ b/drivers/video/nvidia/nv_of.c
@@ -0,0 +1,59 @@
+/*
+ * linux/drivers/video/nvidia/nv_of.c
+ *
+ * Copyright 2004 Antonino A. Daplas <adaplas @pol.net>
+ *
+ * Based on rivafb-i2c.c
+ *
+ * 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/sched.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/fb.h>
+
+#include <asm/io.h>
+
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+
+#include "nv_type.h"
+#include "nv_local.h"
+#include "nv_proto.h"
+
+void nvidia_create_i2c_busses(struct nvidia_par *par) {}
+void nvidia_delete_i2c_busses(struct nvidia_par *par) {}
+
+int nvidia_probe_i2c_connector(struct nvidia_par *par, int conn, u8 **out_edid)
+{
+	struct device_node *dp;
+	unsigned char *pedid = NULL;
+	unsigned char *disptype = NULL;
+	static char *propnames[] = {
+		"DFP,EDID", "LCD,EDID", "EDID", "EDID1", "EDID,B", "EDID,A", NULL };
+	int i;
+
+	dp = pci_device_to_OF_node(par->pci_dev);
+	for (; dp != NULL; dp = dp->child) {
+		disptype = (unsigned char *)get_property(dp, "display-type", NULL);
+		if (disptype == NULL)
+			continue;
+		if (strncmp(disptype, "LCD", 3) != 0)
+			continue;
+		for (i = 0; propnames[i] != NULL; ++i) {
+			pedid = (unsigned char *)
+				get_property(dp, propnames[i], NULL);
+			if (pedid != NULL) {
+				*out_edid = pedid;
+				return 0;
+			}
+		}
+	}
+	return 1;
+}
diff --git a/drivers/video/nvidia/nv_proto.h b/drivers/video/nvidia/nv_proto.h
new file mode 100644
index 0000000..42847ce
--- /dev/null
+++ b/drivers/video/nvidia/nv_proto.h
@@ -0,0 +1,58 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/nv_proto.h,v 1.10 2003/07/31 20:24:29 mvojkovi Exp $ */
+
+#ifndef __NV_PROTO_H__
+#define __NV_PROTO_H__
+
+/* in nv_setup.c */
+void NVCommonSetup(struct fb_info *info);
+void NVWriteCrtc(struct nvidia_par *par, u8 index, u8 value);
+u8 NVReadCrtc(struct nvidia_par *par, u8 index);
+void NVWriteGr(struct nvidia_par *par, u8 index, u8 value);
+u8 NVReadGr(struct nvidia_par *par, u8 index);
+void NVWriteSeq(struct nvidia_par *par, u8 index, u8 value);
+u8 NVReadSeq(struct nvidia_par *par, u8 index);
+void NVWriteAttr(struct nvidia_par *par, u8 index, u8 value);
+u8 NVReadAttr(struct nvidia_par *par, u8 index);
+void NVWriteMiscOut(struct nvidia_par *par, u8 value);
+u8 NVReadMiscOut(struct nvidia_par *par);
+void NVWriteDacMask(struct nvidia_par *par, u8 value);
+void NVWriteDacReadAddr(struct nvidia_par *par, u8 value);
+void NVWriteDacWriteAddr(struct nvidia_par *par, u8 value);
+void NVWriteDacData(struct nvidia_par *par, u8 value);
+u8 NVReadDacData(struct nvidia_par *par);
+
+/* in nv_hw.c */
+void NVCalcStateExt(struct nvidia_par *par, struct _riva_hw_state *,
+		    int, int, int, int, int, int);
+void NVLoadStateExt(struct nvidia_par *par, struct _riva_hw_state *);
+void NVUnloadStateExt(struct nvidia_par *par, struct _riva_hw_state *);
+void NVSetStartAddress(struct nvidia_par *par, u32);
+int NVShowHideCursor(struct nvidia_par *par, int);
+void NVLockUnlock(struct nvidia_par *par, int);
+
+/* in nvidia-i2c.c */
+#if defined(CONFIG_FB_NVIDIA_I2C) || defined (CONFIG_PPC_OF)
+void nvidia_create_i2c_busses(struct nvidia_par *par);
+void nvidia_delete_i2c_busses(struct nvidia_par *par);
+int nvidia_probe_i2c_connector(struct nvidia_par *par, int conn,
+			       u8 ** out_edid);
+#else
+#define nvidia_create_i2c_busses(...)
+#define nvidia_delete_i2c_busses(...)
+#define nvidia_probe_i2c_connector(p, c, edid) \
+do {                                           \
+	*(edid) = NULL;                        \
+} while(0)
+#endif
+
+/* in nv_accel.c */
+extern void NVResetGraphics(struct fb_info *info);
+extern void nvidiafb_copyarea(struct fb_info *info,
+			      const struct fb_copyarea *region);
+extern void nvidiafb_fillrect(struct fb_info *info,
+			      const struct fb_fillrect *rect);
+extern void nvidiafb_imageblit(struct fb_info *info,
+			       const struct fb_image *image);
+extern int nvidiafb_sync(struct fb_info *info);
+extern u8 byte_rev[256];
+#endif				/* __NV_PROTO_H__ */
diff --git a/drivers/video/nvidia/nv_setup.c b/drivers/video/nvidia/nv_setup.c
new file mode 100644
index 0000000..0bbdca2
--- /dev/null
+++ b/drivers/video/nvidia/nv_setup.c
@@ -0,0 +1,636 @@
+ /***************************************************************************\
+|*                                                                           *|
+|*       Copyright 2003 NVIDIA, Corporation.  All rights reserved.           *|
+|*                                                                           *|
+|*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
+|*     international laws.  Users and possessors of this source code are     *|
+|*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
+|*     use this code in individual and commercial software.                  *|
+|*                                                                           *|
+|*     Any use of this source code must include,  in the user documenta-     *|
+|*     tion and  internal comments to the code,  notices to the end user     *|
+|*     as follows:                                                           *|
+|*                                                                           *|
+|*       Copyright 2003 NVIDIA, Corporation.  All rights reserved.           *|
+|*                                                                           *|
+|*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
+|*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
+|*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
+|*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
+|*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
+|*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
+|*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
+|*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
+|*     SULTING FROM LOSS OF USE,  DATA OR PROFITS,  WHETHER IN AN ACTION     *|
+|*     OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,  ARISING OUT OF     *|
+|*     OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.     *|
+|*                                                                           *|
+|*     U.S. Government  End  Users.   This source code  is a "commercial     *|
+|*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
+|*     consisting  of "commercial  computer  software"  and  "commercial     *|
+|*     computer  software  documentation,"  as such  terms  are  used in     *|
+|*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
+|*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
+|*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
+|*     all U.S. Government End Users  acquire the source code  with only     *|
+|*     those rights set forth herein.                                        *|
+|*                                                                           *|
+ \***************************************************************************/
+
+/*
+ * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/
+ * XFree86 'nv' driver, this source code is provided under MIT-style licensing
+ * where the source code is provided "as is" without warranty of any kind.
+ * The only usage restriction is for the copyright notices to be retained
+ * whenever code is used.
+ *
+ * Antonino Daplas <adaplas@pol.net> 2005-03-11
+ */
+
+#include <video/vga.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include "nv_type.h"
+#include "nv_local.h"
+#include "nv_proto.h"
+/*
+ * Override VGA I/O routines.
+ */
+void NVWriteCrtc(struct nvidia_par *par, u8 index, u8 value)
+{
+	VGA_WR08(par->PCIO, par->IOBase + 0x04, index);
+	VGA_WR08(par->PCIO, par->IOBase + 0x05, value);
+}
+u8 NVReadCrtc(struct nvidia_par *par, u8 index)
+{
+	VGA_WR08(par->PCIO, par->IOBase + 0x04, index);
+	return (VGA_RD08(par->PCIO, par->IOBase + 0x05));
+}
+void NVWriteGr(struct nvidia_par *par, u8 index, u8 value)
+{
+	VGA_WR08(par->PVIO, VGA_GFX_I, index);
+	VGA_WR08(par->PVIO, VGA_GFX_D, value);
+}
+u8 NVReadGr(struct nvidia_par *par, u8 index)
+{
+	VGA_WR08(par->PVIO, VGA_GFX_I, index);
+	return (VGA_RD08(par->PVIO, VGA_GFX_D));
+}
+void NVWriteSeq(struct nvidia_par *par, u8 index, u8 value)
+{
+	VGA_WR08(par->PVIO, VGA_SEQ_I, index);
+	VGA_WR08(par->PVIO, VGA_SEQ_D, value);
+}
+u8 NVReadSeq(struct nvidia_par *par, u8 index)
+{
+	VGA_WR08(par->PVIO, VGA_SEQ_I, index);
+	return (VGA_RD08(par->PVIO, VGA_SEQ_D));
+}
+void NVWriteAttr(struct nvidia_par *par, u8 index, u8 value)
+{
+	volatile u8 tmp;
+
+	tmp = VGA_RD08(par->PCIO, par->IOBase + 0x0a);
+	if (par->paletteEnabled)
+		index &= ~0x20;
+	else
+		index |= 0x20;
+	VGA_WR08(par->PCIO, VGA_ATT_IW, index);
+	VGA_WR08(par->PCIO, VGA_ATT_W, value);
+}
+u8 NVReadAttr(struct nvidia_par *par, u8 index)
+{
+	volatile u8 tmp;
+
+	tmp = VGA_RD08(par->PCIO, par->IOBase + 0x0a);
+	if (par->paletteEnabled)
+		index &= ~0x20;
+	else
+		index |= 0x20;
+	VGA_WR08(par->PCIO, VGA_ATT_IW, index);
+	return (VGA_RD08(par->PCIO, VGA_ATT_R));
+}
+void NVWriteMiscOut(struct nvidia_par *par, u8 value)
+{
+	VGA_WR08(par->PVIO, VGA_MIS_W, value);
+}
+u8 NVReadMiscOut(struct nvidia_par *par)
+{
+	return (VGA_RD08(par->PVIO, VGA_MIS_R));
+}
+#if 0
+void NVEnablePalette(struct nvidia_par *par)
+{
+	volatile u8 tmp;
+
+	tmp = VGA_RD08(par->PCIO, par->IOBase + 0x0a);
+	VGA_WR08(par->PCIO, VGA_ATT_IW, 0x00);
+	par->paletteEnabled = 1;
+}
+void NVDisablePalette(struct nvidia_par *par)
+{
+	volatile u8 tmp;
+
+	tmp = VGA_RD08(par->PCIO, par->IOBase + 0x0a);
+	VGA_WR08(par->PCIO, VGA_ATT_IW, 0x20);
+	par->paletteEnabled = 0;
+}
+#endif  /*  0  */
+void NVWriteDacMask(struct nvidia_par *par, u8 value)
+{
+	VGA_WR08(par->PDIO, VGA_PEL_MSK, value);
+}
+#if 0
+u8 NVReadDacMask(struct nvidia_par *par)
+{
+	return (VGA_RD08(par->PDIO, VGA_PEL_MSK));
+}
+#endif  /*  0  */
+void NVWriteDacReadAddr(struct nvidia_par *par, u8 value)
+{
+	VGA_WR08(par->PDIO, VGA_PEL_IR, value);
+}
+void NVWriteDacWriteAddr(struct nvidia_par *par, u8 value)
+{
+	VGA_WR08(par->PDIO, VGA_PEL_IW, value);
+}
+void NVWriteDacData(struct nvidia_par *par, u8 value)
+{
+	VGA_WR08(par->PDIO, VGA_PEL_D, value);
+}
+u8 NVReadDacData(struct nvidia_par *par)
+{
+	return (VGA_RD08(par->PDIO, VGA_PEL_D));
+}
+
+static int NVIsConnected(struct nvidia_par *par, int output)
+{
+	volatile u32 __iomem *PRAMDAC = par->PRAMDAC0;
+	u32 reg52C, reg608;
+	int present;
+
+	if (output)
+		PRAMDAC += 0x800;
+
+	reg52C = NV_RD32(PRAMDAC, 0x052C);
+	reg608 = NV_RD32(PRAMDAC, 0x0608);
+
+	NV_WR32(PRAMDAC, 0x0608, reg608 & ~0x00010000);
+
+	NV_WR32(PRAMDAC, 0x052C, reg52C & 0x0000FEEE);
+	msleep(1);
+	NV_WR32(PRAMDAC, 0x052C, NV_RD32(PRAMDAC, 0x052C) | 1);
+
+	NV_WR32(par->PRAMDAC0, 0x0610, 0x94050140);
+	NV_WR32(par->PRAMDAC0, 0x0608, NV_RD32(par->PRAMDAC0, 0x0608) |
+		0x00001000);
+
+	msleep(1);
+
+	present = (NV_RD32(PRAMDAC, 0x0608) & (1 << 28)) ? 1 : 0;
+
+	if (present)
+		printk("nvidiafb: CRTC%i found\n", output);
+	else
+		printk("nvidiafb: CRTC%i not found\n", output);
+
+	NV_WR32(par->PRAMDAC0, 0x0608, NV_RD32(par->PRAMDAC0, 0x0608) &
+		0x0000EFFF);
+
+	NV_WR32(PRAMDAC, 0x052C, reg52C);
+	NV_WR32(PRAMDAC, 0x0608, reg608);
+
+	return present;
+}
+
+static void NVSelectHeadRegisters(struct nvidia_par *par, int head)
+{
+	if (head) {
+		par->PCIO = par->PCIO0 + 0x2000;
+		par->PCRTC = par->PCRTC0 + 0x800;
+		par->PRAMDAC = par->PRAMDAC0 + 0x800;
+		par->PDIO = par->PDIO0 + 0x2000;
+	} else {
+		par->PCIO = par->PCIO0;
+		par->PCRTC = par->PCRTC0;
+		par->PRAMDAC = par->PRAMDAC0;
+		par->PDIO = par->PDIO0;
+	}
+}
+
+static void nv4GetConfig(struct nvidia_par *par)
+{
+	if (NV_RD32(par->PFB, 0x0000) & 0x00000100) {
+		par->RamAmountKBytes =
+		    ((NV_RD32(par->PFB, 0x0000) >> 12) & 0x0F) * 1024 * 2 +
+		    1024 * 2;
+	} else {
+		switch (NV_RD32(par->PFB, 0x0000) & 0x00000003) {
+		case 0:
+			par->RamAmountKBytes = 1024 * 32;
+			break;
+		case 1:
+			par->RamAmountKBytes = 1024 * 4;
+			break;
+		case 2:
+			par->RamAmountKBytes = 1024 * 8;
+			break;
+		case 3:
+		default:
+			par->RamAmountKBytes = 1024 * 16;
+			break;
+		}
+	}
+	par->CrystalFreqKHz = (NV_RD32(par->PEXTDEV, 0x0000) & 0x00000040) ?
+	    14318 : 13500;
+	par->CURSOR = &par->PRAMIN[0x1E00];
+	par->MinVClockFreqKHz = 12000;
+	par->MaxVClockFreqKHz = 350000;
+}
+
+static void nv10GetConfig(struct nvidia_par *par)
+{
+	struct pci_dev *dev;
+	u32 implementation = par->Chipset & 0x0ff0;
+
+#ifdef __BIG_ENDIAN
+	/* turn on big endian register access */
+	if (!(NV_RD32(par->PMC, 0x0004) & 0x01000001)) {
+		NV_WR32(par->PMC, 0x0004, 0x01000001);
+		mb();
+	}
+#endif
+
+	dev = pci_find_slot(0, 1);
+	if ((par->Chipset && 0xffff) == 0x01a0) {
+		int amt = 0;
+
+		pci_read_config_dword(dev, 0x7c, &amt);
+		par->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024;
+	} else if ((par->Chipset & 0xffff) == 0x01f0) {
+		int amt = 0;
+
+		pci_read_config_dword(dev, 0x84, &amt);
+		par->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024;
+	} else {
+		par->RamAmountKBytes =
+		    (NV_RD32(par->PFB, 0x020C) & 0xFFF00000) >> 10;
+	}
+
+	par->CrystalFreqKHz = (NV_RD32(par->PEXTDEV, 0x0000) & (1 << 6)) ?
+	    14318 : 13500;
+
+	if (par->twoHeads && (implementation != 0x0110)) {
+		if (NV_RD32(par->PEXTDEV, 0x0000) & (1 << 22))
+			par->CrystalFreqKHz = 27000;
+	}
+
+	par->CursorStart = (par->RamAmountKBytes - 96) * 1024;
+	par->CURSOR = NULL;	/* can't set this here */
+	par->MinVClockFreqKHz = 12000;
+	par->MaxVClockFreqKHz = par->twoStagePLL ? 400000 : 350000;
+}
+
+void NVCommonSetup(struct fb_info *info)
+{
+	struct nvidia_par *par = info->par;
+	struct fb_var_screeninfo var;
+	u16 implementation = par->Chipset & 0x0ff0;
+	u8 *edidA = NULL, *edidB = NULL;
+	struct fb_monspecs monitorA, monitorB;
+	struct fb_monspecs *monA = NULL, *monB = NULL;
+	int mobile = 0;
+	int tvA = 0;
+	int tvB = 0;
+	int FlatPanel = -1;	/* really means the CRTC is slaved */
+	int Television = 0;
+
+	par->PRAMIN = par->REGS + (0x00710000 / 4);
+	par->PCRTC0 = par->REGS + (0x00600000 / 4);
+	par->PRAMDAC0 = par->REGS + (0x00680000 / 4);
+	par->PFB = par->REGS + (0x00100000 / 4);
+	par->PFIFO = par->REGS + (0x00002000 / 4);
+	par->PGRAPH = par->REGS + (0x00400000 / 4);
+	par->PEXTDEV = par->REGS + (0x00101000 / 4);
+	par->PTIMER = par->REGS + (0x00009000 / 4);
+	par->PMC = par->REGS + (0x00000000 / 4);
+	par->FIFO = par->REGS + (0x00800000 / 4);
+
+	/* 8 bit registers */
+	par->PCIO0 = (u8 __iomem *) par->REGS + 0x00601000;
+	par->PDIO0 = (u8 __iomem *) par->REGS + 0x00681000;
+	par->PVIO = (u8 __iomem *) par->REGS + 0x000C0000;
+
+	par->twoHeads = (par->Architecture >= NV_ARCH_10) &&
+	    (implementation != 0x0100) &&
+	    (implementation != 0x0150) &&
+	    (implementation != 0x01A0) && (implementation != 0x0200);
+
+	par->fpScaler = (par->FpScale && par->twoHeads &&
+			 (implementation != 0x0110));
+
+	par->twoStagePLL = (implementation == 0x0310) ||
+	    (implementation == 0x0340) || (par->Architecture >= NV_ARCH_40);
+
+	par->WaitVSyncPossible = (par->Architecture >= NV_ARCH_10) &&
+	    (implementation != 0x0100);
+
+	par->BlendingPossible = ((par->Chipset & 0xffff) != 0x0020);
+
+	/* look for known laptop chips */
+	switch (par->Chipset & 0xffff) {
+	case 0x0112:
+	case 0x0174:
+	case 0x0175:
+	case 0x0176:
+	case 0x0177:
+	case 0x0179:
+	case 0x017C:
+	case 0x017D:
+	case 0x0186:
+	case 0x0187:
+	case 0x018D:
+	case 0x0286:
+	case 0x028C:
+	case 0x0316:
+	case 0x0317:
+	case 0x031A:
+	case 0x031B:
+	case 0x031C:
+	case 0x031D:
+	case 0x031E:
+	case 0x031F:
+	case 0x0324:
+	case 0x0325:
+	case 0x0328:
+	case 0x0329:
+	case 0x032C:
+	case 0x032D:
+	case 0x0347:
+	case 0x0348:
+	case 0x0349:
+	case 0x034B:
+	case 0x034C:
+	case 0x0160:
+	case 0x0166:
+	case 0x00C8:
+	case 0x00CC:
+	case 0x0144:
+	case 0x0146:
+	case 0x0147:
+	case 0x0148:
+		mobile = 1;
+		break;
+	default:
+		break;
+	}
+
+	if (par->Architecture == NV_ARCH_04)
+		nv4GetConfig(par);
+	else
+		nv10GetConfig(par);
+
+	NVSelectHeadRegisters(par, 0);
+
+	NVLockUnlock(par, 0);
+
+	par->IOBase = (NVReadMiscOut(par) & 0x01) ? 0x3d0 : 0x3b0;
+
+	par->Television = 0;
+
+	nvidia_create_i2c_busses(par);
+	if (!par->twoHeads) {
+		par->CRTCnumber = 0;
+		nvidia_probe_i2c_connector(par, 1, &edidA);
+		if (edidA && !fb_parse_edid(edidA, &var)) {
+			printk("nvidiafb: EDID found from BUS1\n");
+			monA = &monitorA;
+			fb_edid_to_monspecs(edidA, monA);
+			FlatPanel = (monA->input & FB_DISP_DDI) ? 1 : 0;
+
+			/* NV4 doesn't support FlatPanels */
+			if ((par->Chipset & 0x0fff) <= 0x0020)
+				FlatPanel = 0;
+		} else {
+			VGA_WR08(par->PCIO, 0x03D4, 0x28);
+			if (VGA_RD08(par->PCIO, 0x03D5) & 0x80) {
+				VGA_WR08(par->PCIO, 0x03D4, 0x33);
+				if (!(VGA_RD08(par->PCIO, 0x03D5) & 0x01))
+					Television = 1;
+				FlatPanel = 1;
+			} else {
+				FlatPanel = 0;
+			}
+			printk("nvidiafb: HW is currently programmed for %s\n",
+			       FlatPanel ? (Television ? "TV" : "DFP") :
+			       "CRT");
+		}
+
+		if (par->FlatPanel == -1) {
+			par->FlatPanel = FlatPanel;
+			par->Television = Television;
+		} else {
+			printk("nvidiafb: Forcing display type to %s as "
+			       "specified\n", par->FlatPanel ? "DFP" : "CRT");
+		}
+	} else {
+		u8 outputAfromCRTC, outputBfromCRTC;
+		int CRTCnumber = -1;
+		u8 slaved_on_A, slaved_on_B;
+		int analog_on_A, analog_on_B;
+		u32 oldhead;
+		u8 cr44;
+
+		if (implementation != 0x0110) {
+			if (NV_RD32(par->PRAMDAC0, 0x0000052C) & 0x100)
+				outputAfromCRTC = 1;
+			else
+				outputAfromCRTC = 0;
+			if (NV_RD32(par->PRAMDAC0, 0x0000252C) & 0x100)
+				outputBfromCRTC = 1;
+			else
+				outputBfromCRTC = 0;
+			analog_on_A = NVIsConnected(par, 0);
+			analog_on_B = NVIsConnected(par, 1);
+		} else {
+			outputAfromCRTC = 0;
+			outputBfromCRTC = 1;
+			analog_on_A = 0;
+			analog_on_B = 0;
+		}
+
+		VGA_WR08(par->PCIO, 0x03D4, 0x44);
+		cr44 = VGA_RD08(par->PCIO, 0x03D5);
+
+		VGA_WR08(par->PCIO, 0x03D5, 3);
+		NVSelectHeadRegisters(par, 1);
+		NVLockUnlock(par, 0);
+
+		VGA_WR08(par->PCIO, 0x03D4, 0x28);
+		slaved_on_B = VGA_RD08(par->PCIO, 0x03D5) & 0x80;
+		if (slaved_on_B) {
+			VGA_WR08(par->PCIO, 0x03D4, 0x33);
+			tvB = !(VGA_RD08(par->PCIO, 0x03D5) & 0x01);
+		}
+
+		VGA_WR08(par->PCIO, 0x03D4, 0x44);
+		VGA_WR08(par->PCIO, 0x03D5, 0);
+		NVSelectHeadRegisters(par, 0);
+		NVLockUnlock(par, 0);
+
+		VGA_WR08(par->PCIO, 0x03D4, 0x28);
+		slaved_on_A = VGA_RD08(par->PCIO, 0x03D5) & 0x80;
+		if (slaved_on_A) {
+			VGA_WR08(par->PCIO, 0x03D4, 0x33);
+			tvA = !(VGA_RD08(par->PCIO, 0x03D5) & 0x01);
+		}
+
+		oldhead = NV_RD32(par->PCRTC0, 0x00000860);
+		NV_WR32(par->PCRTC0, 0x00000860, oldhead | 0x00000010);
+
+		nvidia_probe_i2c_connector(par, 1, &edidA);
+		if (edidA && !fb_parse_edid(edidA, &var)) {
+			printk("nvidiafb: EDID found from BUS1\n");
+			monA = &monitorA;
+			fb_edid_to_monspecs(edidA, monA);
+		}
+
+		nvidia_probe_i2c_connector(par, 2, &edidB);
+		if (edidB && !fb_parse_edid(edidB, &var)) {
+			printk("nvidiafb: EDID found from BUS2\n");
+			monB = &monitorB;
+			fb_edid_to_monspecs(edidB, monB);
+		}
+
+		if (slaved_on_A && !tvA) {
+			CRTCnumber = 0;
+			FlatPanel = 1;
+			printk("nvidiafb: CRTC 0 is currently programmed for "
+			       "DFP\n");
+		} else if (slaved_on_B && !tvB) {
+			CRTCnumber = 1;
+			FlatPanel = 1;
+			printk("nvidiafb: CRTC 1 is currently programmed "
+			       "for DFP\n");
+		} else if (analog_on_A) {
+			CRTCnumber = outputAfromCRTC;
+			FlatPanel = 0;
+			printk("nvidiafb: CRTC %i appears to have a "
+			       "CRT attached\n", CRTCnumber);
+		} else if (analog_on_B) {
+			CRTCnumber = outputBfromCRTC;
+			FlatPanel = 0;
+			printk("nvidiafb: CRTC %i"
+			       "appears to have a "
+			       "CRT attached\n", CRTCnumber);
+		} else if (slaved_on_A) {
+			CRTCnumber = 0;
+			FlatPanel = 1;
+			Television = 1;
+			printk("nvidiafb: CRTC 0 is currently programmed "
+			       "for TV\n");
+		} else if (slaved_on_B) {
+			CRTCnumber = 1;
+			FlatPanel = 1;
+			Television = 1;
+			printk("nvidiafb: CRTC 1 is currently programmed for "
+			       "TV\n");
+		} else if (monA) {
+			FlatPanel = (monA->input & FB_DISP_DDI) ? 1 : 0;
+		} else if (monB) {
+			FlatPanel = (monB->input & FB_DISP_DDI) ? 1 : 0;
+		}
+
+		if (par->FlatPanel == -1) {
+			if (FlatPanel != -1) {
+				par->FlatPanel = FlatPanel;
+				par->Television = Television;
+			} else {
+				printk("nvidiafb: Unable to detect display "
+				       "type...\n");
+				if (mobile) {
+					printk("...On a laptop, assuming "
+					       "DFP\n");
+					par->FlatPanel = 1;
+				} else {
+					printk("...Using default of CRT\n");
+					par->FlatPanel = 0;
+				}
+			}
+		} else {
+			printk("nvidiafb: Forcing display type to %s as "
+			       "specified\n", par->FlatPanel ? "DFP" : "CRT");
+		}
+
+		if (par->CRTCnumber == -1) {
+			if (CRTCnumber != -1)
+				par->CRTCnumber = CRTCnumber;
+			else {
+				printk("nvidiafb: Unable to detect which "
+				       "CRTCNumber...\n");
+				if (par->FlatPanel)
+					par->CRTCnumber = 1;
+				else
+					par->CRTCnumber = 0;
+				printk("...Defaulting to CRTCNumber %i\n",
+				       par->CRTCnumber);
+			}
+		} else {
+			printk("nvidiafb: Forcing CRTCNumber %i as "
+			       "specified\n", par->CRTCnumber);
+		}
+
+		if (monA) {
+			if (((monA->input & FB_DISP_DDI) &&
+			     par->FlatPanel) ||
+			    ((!(monA->input & FB_DISP_DDI)) &&
+			     !par->FlatPanel)) {
+				if (monB) {
+					fb_destroy_modedb(monB->modedb);
+					monB = NULL;
+				}
+			} else {
+				fb_destroy_modedb(monA->modedb);
+				monA = NULL;
+			}
+		}
+
+		if (monB) {
+			if (((monB->input & FB_DISP_DDI) &&
+			     !par->FlatPanel) ||
+			    ((!(monB->input & FB_DISP_DDI)) &&
+			     par->FlatPanel)) {
+				fb_destroy_modedb(monB->modedb);
+				monB = NULL;
+			} else
+				monA = monB;
+		}
+
+		if (implementation == 0x0110)
+			cr44 = par->CRTCnumber * 0x3;
+
+		NV_WR32(par->PCRTC0, 0x00000860, oldhead);
+
+		VGA_WR08(par->PCIO, 0x03D4, 0x44);
+		VGA_WR08(par->PCIO, 0x03D5, cr44);
+		NVSelectHeadRegisters(par, par->CRTCnumber);
+	}
+
+	printk("nvidiafb: Using %s on CRTC %i\n",
+	       par->FlatPanel ? (par->Television ? "TV" : "DFP") : "CRT",
+	       par->CRTCnumber);
+
+	if (par->FlatPanel && !par->Television) {
+		par->fpWidth = NV_RD32(par->PRAMDAC, 0x0820) + 1;
+		par->fpHeight = NV_RD32(par->PRAMDAC, 0x0800) + 1;
+		par->fpSyncs = NV_RD32(par->PRAMDAC, 0x0848) & 0x30000033;
+
+		printk("Panel size is %i x %i\n", par->fpWidth, par->fpHeight);
+	}
+
+	if (monA)
+		info->monspecs = *monA;
+
+	kfree(edidA);
+	kfree(edidB);
+}
diff --git a/drivers/video/nvidia/nv_type.h b/drivers/video/nvidia/nv_type.h
new file mode 100644
index 0000000..e4a5b1d
--- /dev/null
+++ b/drivers/video/nvidia/nv_type.h
@@ -0,0 +1,174 @@
+#ifndef __NV_TYPE_H__
+#define __NV_TYPE_H__
+
+#include <linux/fb.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/i2c-algo-bit.h>
+
+#define NV_ARCH_04  0x04
+#define NV_ARCH_10  0x10
+#define NV_ARCH_20  0x20
+#define NV_ARCH_30  0x30
+#define NV_ARCH_40  0x40
+
+#define BITMASK(t,b) (((unsigned)(1U << (((t)-(b)+1)))-1)  << (b))
+#define MASKEXPAND(mask) BITMASK(1?mask,0?mask)
+#define SetBF(mask,value) ((value) << (0?mask))
+#define GetBF(var,mask) (((unsigned)((var) & MASKEXPAND(mask))) >> (0?mask) )
+#define SetBitField(value,from,to) SetBF(to, GetBF(value,from))
+#define SetBit(n) (1<<(n))
+#define Set8Bits(value) ((value)&0xff)
+
+#define V_DBLSCAN  1
+
+typedef struct {
+	int bitsPerPixel;
+	int depth;
+	int displayWidth;
+	int weight;
+} NVFBLayout;
+
+#define NUM_SEQ_REGS		0x05
+#define NUM_CRT_REGS		0x41
+#define NUM_GRC_REGS		0x09
+#define NUM_ATC_REGS		0x15
+
+struct nvidia_par;
+
+struct nvidia_i2c_chan {
+	struct nvidia_par *par;
+	unsigned long ddc_base;
+	struct i2c_adapter adapter;
+	struct i2c_algo_bit_data algo;
+};
+
+typedef struct _riva_hw_state {
+	u8 attr[NUM_ATC_REGS];
+	u8 crtc[NUM_CRT_REGS];
+	u8 gra[NUM_GRC_REGS];
+	u8 seq[NUM_SEQ_REGS];
+	u8 misc_output;
+	u32 bpp;
+	u32 width;
+	u32 height;
+	u32 interlace;
+	u32 repaint0;
+	u32 repaint1;
+	u32 screen;
+	u32 scale;
+	u32 dither;
+	u32 extra;
+	u32 fifo;
+	u32 pixel;
+	u32 horiz;
+	u32 arbitration0;
+	u32 arbitration1;
+	u32 pll;
+	u32 pllB;
+	u32 vpll;
+	u32 vpll2;
+	u32 vpllB;
+	u32 vpll2B;
+	u32 pllsel;
+	u32 general;
+	u32 crtcOwner;
+	u32 head;
+	u32 head2;
+	u32 config;
+	u32 cursorConfig;
+	u32 cursor0;
+	u32 cursor1;
+	u32 cursor2;
+	u32 timingH;
+	u32 timingV;
+	u32 displayV;
+	u32 crtcSync;
+} RIVA_HW_STATE;
+
+struct riva_regs {
+	RIVA_HW_STATE ext;
+};
+
+struct nvidia_par {
+	RIVA_HW_STATE SavedReg;
+	RIVA_HW_STATE ModeReg;
+	RIVA_HW_STATE *CurrentState;
+	u32 pseudo_palette[16];
+	struct pci_dev *pci_dev;
+	u32 Architecture;
+	u32 CursorStart;
+	int Chipset;
+	int bus;
+	unsigned long FbAddress;
+	u8 __iomem *FbStart;
+	u32 FbMapSize;
+	u32 FbUsableSize;
+	u32 ScratchBufferSize;
+	u32 ScratchBufferStart;
+	int FpScale;
+	u32 MinVClockFreqKHz;
+	u32 MaxVClockFreqKHz;
+	u32 CrystalFreqKHz;
+	u32 RamAmountKBytes;
+	u32 IOBase;
+	NVFBLayout CurrentLayout;
+	int cursor_reset;
+	int lockup;
+	int videoKey;
+	int FlatPanel;
+	int FPDither;
+	int Television;
+	int CRTCnumber;
+	int alphaCursor;
+	int twoHeads;
+	int twoStagePLL;
+	int fpScaler;
+	int fpWidth;
+	int fpHeight;
+	int PanelTweak;
+	int paneltweak;
+	u32 crtcSync_read;
+	u32 fpSyncs;
+	u32 dmaPut;
+	u32 dmaCurrent;
+	u32 dmaFree;
+	u32 dmaMax;
+	u32 __iomem *dmaBase;
+	u32 currentRop;
+	int WaitVSyncPossible;
+	int BlendingPossible;
+	u32 paletteEnabled;
+	u32 forceCRTC;
+	u8 DDCBase;
+#ifdef CONFIG_MTRR
+	struct {
+		int vram;
+		int vram_valid;
+	} mtrr;
+#endif
+	struct nvidia_i2c_chan chan[3];
+
+	volatile u32 __iomem *REGS;
+	volatile u32 __iomem *PCRTC0;
+	volatile u32 __iomem *PCRTC;
+	volatile u32 __iomem *PRAMDAC0;
+	volatile u32 __iomem *PFB;
+	volatile u32 __iomem *PFIFO;
+	volatile u32 __iomem *PGRAPH;
+	volatile u32 __iomem *PEXTDEV;
+	volatile u32 __iomem *PTIMER;
+	volatile u32 __iomem *PMC;
+	volatile u32 __iomem *PRAMIN;
+	volatile u32 __iomem *FIFO;
+	volatile u32 __iomem *CURSOR;
+	volatile u8 __iomem *PCIO0;
+	volatile u8 __iomem *PCIO;
+	volatile u8 __iomem *PVIO;
+	volatile u8 __iomem *PDIO0;
+	volatile u8 __iomem *PDIO;
+	volatile u32 __iomem *PRAMDAC;
+};
+
+#endif				/* __NV_TYPE_H__ */
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
new file mode 100644
index 0000000..3a6555a
--- /dev/null
+++ b/drivers/video/nvidia/nvidia.c
@@ -0,0 +1,1729 @@
+/*
+ * linux/drivers/video/nvidia/nvidia.c - nVidia fb driver
+ *
+ * Copyright 2004 Antonino Daplas <adaplas@pol.net>
+ *
+ * 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/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+#ifdef CONFIG_PPC_OF
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#endif
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+
+#include "nv_local.h"
+#include "nv_type.h"
+#include "nv_proto.h"
+#include "nv_dma.h"
+
+#ifndef CONFIG_PCI		/* sanity check */
+#error This driver requires PCI support.
+#endif
+
+#undef CONFIG_FB_NVIDIA_DEBUG
+#ifdef CONFIG_FB_NVIDIA_DEBUG
+#define NVTRACE          printk
+#else
+#define NVTRACE          if (0) printk
+#endif
+
+#define NVTRACE_ENTER(...)  NVTRACE("%s START\n", __FUNCTION__)
+#define NVTRACE_LEAVE(...)  NVTRACE("%s END\n", __FUNCTION__)
+
+#ifdef CONFIG_FB_NVIDIA_DEBUG
+#define assert(expr) \
+	if (!(expr)) { \
+	printk( "Assertion failed! %s,%s,%s,line=%d\n",\
+	#expr,__FILE__,__FUNCTION__,__LINE__); \
+	BUG(); \
+	}
+#else
+#define assert(expr)
+#endif
+
+#define PFX "nvidiafb: "
+
+/* HW cursor parameters */
+#define MAX_CURS		32
+
+static struct pci_device_id nvidiafb_pci_tbl[] = {
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT2,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UTNT2,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT_UNKNOWN,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_VTNT2,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UVTNT2,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_ITNT2,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_SE,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_460_GO,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_200,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_410_GO_M16,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_8X,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440SE_8X,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420_8X,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_448_GO,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_488_GO,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_580_XGL,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_MAC,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_280_NVS,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_380_XGL,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_IGEFORCE2,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_1,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_2,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_DDC,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800_8X,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800SE,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_4200_GO,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_980_XGL,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_780_XGL,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_700_GOGL,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800_ULTRA,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_2000,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1000,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600_ULTRA,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600SE,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5600,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5650,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO700,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_ULTRA,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_1,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200SE,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5200,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250_32,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO_5200,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_NVS_280_PCI,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_500,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5300,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5100,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900_ULTRA,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900XT,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5950_ULTRA,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_3000,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700_ULTRA,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700LE,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700VE,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_1,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_2,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO1000,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1100,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5500,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5100,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_700,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900ZT,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_ULTRA,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_LE,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_GT,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_4000,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6600_GT,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6600,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6610_XL,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_540,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6200,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0252,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0313,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0316,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0317,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x031D,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x031E,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x031F,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0329,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x032F,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0345,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0349,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x034B,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x034F,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x00c0,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_6800A,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_6800A_LE,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_GO_6800,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_GO_6800_ULTRA,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_QUADRO_FX_GO1400,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x00cd,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_QUADRO_FX_1400,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0142,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0143,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0144,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0145,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0146,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0147,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0148,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0149,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x014b,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x14c,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x014d,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0160,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6200_TURBOCACHE,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0162,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0163,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0165,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200_1,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250_1,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0169,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x016b,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x016c,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x016d,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x016e,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0210,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_LE,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_GT,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x021d,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x021e,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0220,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0221,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0222,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_NVIDIA, 0x0228,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0,}			/* terminate list */
+};
+
+MODULE_DEVICE_TABLE(pci, nvidiafb_pci_tbl);
+
+/* command line data, set in nvidiafb_setup() */
+static int flatpanel __devinitdata = -1;	/* Autodetect later */
+static int forceCRTC __devinitdata = -1;
+static int hwcur __devinitdata = 0;
+static int noaccel __devinitdata = 0;
+static int noscale __devinitdata = 0;
+static int paneltweak __devinitdata = 0;
+#ifdef CONFIG_MTRR
+static int nomtrr __devinitdata = 0;
+#endif
+
+static char *mode_option __devinitdata = NULL;
+
+static struct fb_fix_screeninfo __devinitdata nvidiafb_fix = {
+	.type = FB_TYPE_PACKED_PIXELS,
+	.xpanstep = 8,
+	.ypanstep = 1,
+};
+
+static struct fb_var_screeninfo __devinitdata nvidiafb_default_var = {
+	.xres = 640,
+	.yres = 480,
+	.xres_virtual = 640,
+	.yres_virtual = 480,
+	.bits_per_pixel = 8,
+	.red = {0, 8, 0},
+	.green = {0, 8, 0},
+	.blue = {0, 8, 0},
+	.transp = {0, 0, 0},
+	.activate = FB_ACTIVATE_NOW,
+	.height = -1,
+	.width = -1,
+	.pixclock = 39721,
+	.left_margin = 40,
+	.right_margin = 24,
+	.upper_margin = 32,
+	.lower_margin = 11,
+	.hsync_len = 96,
+	.vsync_len = 2,
+	.vmode = FB_VMODE_NONINTERLACED
+};
+
+/*
+ * Backlight control
+ */
+#ifdef CONFIG_PMAC_BACKLIGHT
+
+static int nvidia_backlight_levels[] = {
+	0x158,
+	0x192,
+	0x1c6,
+	0x200,
+	0x234,
+	0x268,
+	0x2a2,
+	0x2d6,
+	0x310,
+	0x344,
+	0x378,
+	0x3b2,
+	0x3e6,
+	0x41a,
+	0x454,
+	0x534,
+};
+
+/* ------------------------------------------------------------------------- *
+ *
+ * Backlight operations
+ *
+ * ------------------------------------------------------------------------- */
+
+static int nvidia_set_backlight_enable(int on, int level, void *data)
+{
+	struct nvidia_par *par = (struct nvidia_par *)data;
+	u32 tmp_pcrt, tmp_pmc, fpcontrol;
+
+	tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF;
+	tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC;
+	fpcontrol = NV_RD32(par->PRAMDAC, 0x0848) & 0xCFFFFFCC;
+
+	if (on && (level > BACKLIGHT_OFF)) {
+		tmp_pcrt |= 0x1;
+		tmp_pmc |= (1 << 31);	// backlight bit
+		tmp_pmc |= nvidia_backlight_levels[level - 1] << 16;
+	}
+
+	if (on)
+		fpcontrol |= par->fpSyncs;
+	else
+		fpcontrol |= 0x20000022;
+
+	NV_WR32(par->PCRTC0, 0x081C, tmp_pcrt);
+	NV_WR32(par->PMC, 0x10F0, tmp_pmc);
+	NV_WR32(par->PRAMDAC, 0x848, fpcontrol);
+
+	return 0;
+}
+
+static int nvidia_set_backlight_level(int level, void *data)
+{
+	return nvidia_set_backlight_enable(1, level, data);
+}
+
+static struct backlight_controller nvidia_backlight_controller = {
+	nvidia_set_backlight_enable,
+	nvidia_set_backlight_level
+};
+
+#endif				/* CONFIG_PMAC_BACKLIGHT */
+
+static void nvidiafb_load_cursor_image(struct nvidia_par *par, u8 * data8,
+				       u16 bg, u16 fg, u32 w, u32 h)
+{
+	int i, j, k = 0;
+	u32 b, tmp;
+	u32 *data = (u32 *) data8;
+
+	w = (w + 1) & ~1;
+
+	for (i = 0; i < h; i++) {
+		b = *data++;
+		reverse_order(&b);
+
+		for (j = 0; j < w / 2; j++) {
+			tmp = 0;
+#if defined (__BIG_ENDIAN)
+			tmp = (b & (1 << 31)) ? fg << 16 : bg << 16;
+			b <<= 1;
+			tmp |= (b & (1 << 31)) ? fg : bg;
+			b <<= 1;
+#else
+			tmp = (b & 1) ? fg : bg;
+			b >>= 1;
+			tmp |= (b & 1) ? fg << 16 : bg << 16;
+			b >>= 1;
+#endif
+			NV_WR32(&par->CURSOR[k++], 0, tmp);
+		}
+		k += (MAX_CURS - w) / 2;
+	}
+}
+
+static void nvidia_write_clut(struct nvidia_par *par,
+			      u8 regnum, u8 red, u8 green, u8 blue)
+{
+	NVWriteDacMask(par, 0xff);
+	NVWriteDacWriteAddr(par, regnum);
+	NVWriteDacData(par, red);
+	NVWriteDacData(par, green);
+	NVWriteDacData(par, blue);
+}
+
+static void nvidia_read_clut(struct nvidia_par *par,
+			     u8 regnum, u8 * red, u8 * green, u8 * blue)
+{
+	NVWriteDacMask(par, 0xff);
+	NVWriteDacReadAddr(par, regnum);
+	*red = NVReadDacData(par);
+	*green = NVReadDacData(par);
+	*blue = NVReadDacData(par);
+}
+
+static int nvidia_panel_tweak(struct nvidia_par *par,
+			      struct _riva_hw_state *state)
+{
+	int tweak = 0;
+
+   if (par->paneltweak) {
+	   tweak = par->paneltweak;
+   } else {
+	   /* begin flat panel hacks */
+	   /* This is unfortunate, but some chips need this register
+	      tweaked or else you get artifacts where adjacent pixels are
+	      swapped.  There are no hard rules for what to set here so all
+	      we can do is experiment and apply hacks. */
+
+	   if(((par->Chipset & 0xffff) == 0x0328) && (state->bpp == 32)) {
+		   /* At least one NV34 laptop needs this workaround. */
+		   tweak = -1;
+	   }
+
+	   if((par->Chipset & 0xfff0) == 0x0310) {
+		   tweak = 1;
+	   }
+	   /* end flat panel hacks */
+   }
+
+   return tweak;
+}
+
+static void nvidia_save_vga(struct nvidia_par *par,
+			    struct _riva_hw_state *state)
+{
+	int i;
+
+	NVTRACE_ENTER();
+	NVLockUnlock(par, 0);
+
+	NVUnloadStateExt(par, state);
+
+	state->misc_output = NVReadMiscOut(par);
+
+	for (i = 0; i < NUM_CRT_REGS; i++)
+		state->crtc[i] = NVReadCrtc(par, i);
+
+	for (i = 0; i < NUM_ATC_REGS; i++)
+		state->attr[i] = NVReadAttr(par, i);
+
+	for (i = 0; i < NUM_GRC_REGS; i++)
+		state->gra[i] = NVReadGr(par, i);
+
+	for (i = 0; i < NUM_SEQ_REGS; i++)
+		state->seq[i] = NVReadSeq(par, i);
+	NVTRACE_LEAVE();
+}
+
+static void nvidia_write_regs(struct nvidia_par *par)
+{
+	struct _riva_hw_state *state = &par->ModeReg;
+	int i;
+
+	NVTRACE_ENTER();
+	NVWriteCrtc(par, 0x11, 0x00);
+
+	NVLockUnlock(par, 0);
+
+	NVLoadStateExt(par, state);
+
+	NVWriteMiscOut(par, state->misc_output);
+
+	for (i = 0; i < NUM_CRT_REGS; i++) {
+		switch (i) {
+		case 0x19:
+		case 0x20 ... 0x40:
+			break;
+		default:
+			NVWriteCrtc(par, i, state->crtc[i]);
+		}
+	}
+
+	for (i = 0; i < NUM_ATC_REGS; i++)
+		NVWriteAttr(par, i, state->attr[i]);
+
+	for (i = 0; i < NUM_GRC_REGS; i++)
+		NVWriteGr(par, i, state->gra[i]);
+
+	for (i = 0; i < NUM_SEQ_REGS; i++)
+		NVWriteSeq(par, i, state->seq[i]);
+	NVTRACE_LEAVE();
+}
+
+static int nvidia_calc_regs(struct fb_info *info)
+{
+	struct nvidia_par *par = info->par;
+	struct _riva_hw_state *state = &par->ModeReg;
+	int i, depth = fb_get_color_depth(&info->var);
+	int h_display = info->var.xres / 8 - 1;
+	int h_start = (info->var.xres + info->var.right_margin) / 8 - 1;
+	int h_end = (info->var.xres + info->var.right_margin +
+		     info->var.hsync_len) / 8 - 1;
+	int h_total = (info->var.xres + info->var.right_margin +
+		       info->var.hsync_len + info->var.left_margin) / 8 - 5;
+	int h_blank_s = h_display;
+	int h_blank_e = h_total + 4;
+	int v_display = info->var.yres - 1;
+	int v_start = info->var.yres + info->var.lower_margin - 1;
+	int v_end = (info->var.yres + info->var.lower_margin +
+		     info->var.vsync_len) - 1;
+	int v_total = (info->var.yres + info->var.lower_margin +
+		       info->var.vsync_len + info->var.upper_margin) - 2;
+	int v_blank_s = v_display;
+	int v_blank_e = v_total + 1;
+
+	/*
+	 * Set all CRTC values.
+	 */
+
+	if (info->var.vmode & FB_VMODE_INTERLACED)
+		v_total |= 1;
+
+	if (par->FlatPanel == 1) {
+		v_start = v_total - 3;
+		v_end = v_total - 2;
+		v_blank_s = v_start;
+		h_start = h_total - 5;
+		h_end = h_total - 2;
+		h_blank_e = h_total + 4;
+	}
+
+	state->crtc[0x0] = Set8Bits(h_total);
+	state->crtc[0x1] = Set8Bits(h_display);
+	state->crtc[0x2] = Set8Bits(h_blank_s);
+	state->crtc[0x3] = SetBitField(h_blank_e, 4: 0, 4:0)
+		| SetBit(7);
+	state->crtc[0x4] = Set8Bits(h_start);
+	state->crtc[0x5] = SetBitField(h_blank_e, 5: 5, 7:7)
+		| SetBitField(h_end, 4: 0, 4:0);
+	state->crtc[0x6] = SetBitField(v_total, 7: 0, 7:0);
+	state->crtc[0x7] = SetBitField(v_total, 8: 8, 0:0)
+		| SetBitField(v_display, 8: 8, 1:1)
+		| SetBitField(v_start, 8: 8, 2:2)
+		| SetBitField(v_blank_s, 8: 8, 3:3)
+		| SetBit(4)
+		| SetBitField(v_total, 9: 9, 5:5)
+		| SetBitField(v_display, 9: 9, 6:6)
+		| SetBitField(v_start, 9: 9, 7:7);
+	state->crtc[0x9] = SetBitField(v_blank_s, 9: 9, 5:5)
+		| SetBit(6)
+		| ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0x00);
+	state->crtc[0x10] = Set8Bits(v_start);
+	state->crtc[0x11] = SetBitField(v_end, 3: 0, 3:0) | SetBit(5);
+	state->crtc[0x12] = Set8Bits(v_display);
+	state->crtc[0x13] = ((info->var.xres_virtual / 8) *
+			     (info->var.bits_per_pixel / 8));
+	state->crtc[0x15] = Set8Bits(v_blank_s);
+	state->crtc[0x16] = Set8Bits(v_blank_e);
+
+	state->attr[0x10] = 0x01;
+
+	if (par->Television)
+		state->attr[0x11] = 0x00;
+
+	state->screen = SetBitField(h_blank_e, 6: 6, 4:4)
+		| SetBitField(v_blank_s, 10: 10, 3:3)
+		| SetBitField(v_start, 10: 10, 2:2)
+		| SetBitField(v_display, 10: 10, 1:1)
+		| SetBitField(v_total, 10: 10, 0:0);
+
+	state->horiz = SetBitField(h_total, 8: 8, 0:0)
+		| SetBitField(h_display, 8: 8, 1:1)
+		| SetBitField(h_blank_s, 8: 8, 2:2)
+		| SetBitField(h_start, 8: 8, 3:3);
+
+	state->extra = SetBitField(v_total, 11: 11, 0:0)
+		| SetBitField(v_display, 11: 11, 2:2)
+		| SetBitField(v_start, 11: 11, 4:4)
+		| SetBitField(v_blank_s, 11: 11, 6:6);
+
+	if (info->var.vmode & FB_VMODE_INTERLACED) {
+		h_total = (h_total >> 1) & ~1;
+		state->interlace = Set8Bits(h_total);
+		state->horiz |= SetBitField(h_total, 8: 8, 4:4);
+	} else {
+		state->interlace = 0xff;	/* interlace off */
+	}
+
+	/*
+	 * Calculate the extended registers.
+	 */
+
+	if (depth < 24)
+		i = depth;
+	else
+		i = 32;
+
+	if (par->Architecture >= NV_ARCH_10)
+		par->CURSOR = (volatile u32 __iomem *)(info->screen_base +
+						       par->CursorStart);
+
+	if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
+		state->misc_output &= ~0x40;
+	else
+		state->misc_output |= 0x40;
+	if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
+		state->misc_output &= ~0x80;
+	else
+		state->misc_output |= 0x80;
+
+	NVCalcStateExt(par, state, i, info->var.xres_virtual,
+		       info->var.xres, info->var.yres_virtual,
+		       1000000000 / info->var.pixclock, info->var.vmode);
+
+	state->scale = NV_RD32(par->PRAMDAC, 0x00000848) & 0xfff000ff;
+	if (par->FlatPanel == 1) {
+		state->pixel |= (1 << 7);
+
+		if (!par->fpScaler || (par->fpWidth <= info->var.xres)
+		    || (par->fpHeight <= info->var.yres)) {
+			state->scale |= (1 << 8);
+		}
+
+		if (!par->crtcSync_read) {
+			state->crtcSync = NV_RD32(par->PRAMDAC, 0x0828);
+			par->crtcSync_read = 1;
+		}
+
+		par->PanelTweak = nvidia_panel_tweak(par, state);
+	}
+
+	state->vpll = state->pll;
+	state->vpll2 = state->pll;
+	state->vpllB = state->pllB;
+	state->vpll2B = state->pllB;
+
+	VGA_WR08(par->PCIO, 0x03D4, 0x1C);
+	state->fifo = VGA_RD08(par->PCIO, 0x03D5) & ~(1<<5);
+
+	if (par->CRTCnumber) {
+		state->head = NV_RD32(par->PCRTC0, 0x00000860) & ~0x00001000;
+		state->head2 = NV_RD32(par->PCRTC0, 0x00002860) | 0x00001000;
+		state->crtcOwner = 3;
+		state->pllsel |= 0x20000800;
+		state->vpll = NV_RD32(par->PRAMDAC0, 0x00000508);
+		if (par->twoStagePLL)
+			state->vpllB = NV_RD32(par->PRAMDAC0, 0x00000578);
+	} else if (par->twoHeads) {
+		state->head = NV_RD32(par->PCRTC0, 0x00000860) | 0x00001000;
+		state->head2 = NV_RD32(par->PCRTC0, 0x00002860) & ~0x00001000;
+		state->crtcOwner = 0;
+		state->vpll2 = NV_RD32(par->PRAMDAC0, 0x0520);
+		if (par->twoStagePLL)
+			state->vpll2B = NV_RD32(par->PRAMDAC0, 0x057C);
+	}
+
+	state->cursorConfig = 0x00000100;
+
+	if (info->var.vmode & FB_VMODE_DOUBLE)
+		state->cursorConfig |= (1 << 4);
+
+	if (par->alphaCursor) {
+		if ((par->Chipset & 0x0ff0) != 0x0110)
+			state->cursorConfig |= 0x04011000;
+		else
+			state->cursorConfig |= 0x14011000;
+		state->general |= (1 << 29);
+	} else
+		state->cursorConfig |= 0x02000000;
+
+	if (par->twoHeads) {
+		if ((par->Chipset & 0x0ff0) == 0x0110) {
+			state->dither = NV_RD32(par->PRAMDAC, 0x0528) &
+			    ~0x00010000;
+			if (par->FPDither)
+				state->dither |= 0x00010000;
+		} else {
+			state->dither = NV_RD32(par->PRAMDAC, 0x083C) & ~1;
+			if (par->FPDither)
+				state->dither |= 1;
+		}
+	}
+
+	state->timingH = 0;
+	state->timingV = 0;
+	state->displayV = info->var.xres;
+
+	return 0;
+}
+
+static void nvidia_init_vga(struct fb_info *info)
+{
+	struct nvidia_par *par = info->par;
+	struct _riva_hw_state *state = &par->ModeReg;
+	int i;
+
+	for (i = 0; i < 0x10; i++)
+		state->attr[i] = i;
+	state->attr[0x10] = 0x41;
+	state->attr[0x11] = 0x01;
+	state->attr[0x12] = 0x0f;
+	state->attr[0x13] = 0x00;
+	state->attr[0x14] = 0x00;
+
+	memset(state->crtc, 0x00, NUM_CRT_REGS);
+	state->crtc[0x0a] = 0x20;
+	state->crtc[0x17] = 0xe3;
+	state->crtc[0x18] = 0xff;
+	state->crtc[0x28] = 0x40;
+
+	memset(state->gra, 0x00, NUM_GRC_REGS);
+	state->gra[0x05] = 0x40;
+	state->gra[0x06] = 0x05;
+	state->gra[0x07] = 0x0f;
+	state->gra[0x08] = 0xff;
+
+	state->seq[0x00] = 0x03;
+	state->seq[0x01] = 0x01;
+	state->seq[0x02] = 0x0f;
+	state->seq[0x03] = 0x00;
+	state->seq[0x04] = 0x0e;
+
+	state->misc_output = 0xeb;
+}
+
+static int nvidiafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+	struct nvidia_par *par = info->par;
+	u8 data[MAX_CURS * MAX_CURS / 8];
+	u16 fg, bg;
+	int i, set = cursor->set;
+
+	if (cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS)
+		return soft_cursor(info, cursor);
+
+	NVShowHideCursor(par, 0);
+
+	if (par->cursor_reset) {
+		set = FB_CUR_SETALL;
+		par->cursor_reset = 0;
+	}
+
+	if (set & FB_CUR_SETSIZE)
+		memset_io(par->CURSOR, 0, MAX_CURS * MAX_CURS * 2);
+
+	if (set & FB_CUR_SETPOS) {
+		u32 xx, yy, temp;
+
+		yy = cursor->image.dy - info->var.yoffset;
+		xx = cursor->image.dx - info->var.xoffset;
+		temp = xx & 0xFFFF;
+		temp |= yy << 16;
+
+		NV_WR32(par->PRAMDAC, 0x0000300, temp);
+	}
+
+	if (set & (FB_CUR_SETSHAPE | FB_CUR_SETCMAP | FB_CUR_SETIMAGE)) {
+		u32 bg_idx = cursor->image.bg_color;
+		u32 fg_idx = cursor->image.fg_color;
+		u32 s_pitch = (cursor->image.width + 7) >> 3;
+		u32 d_pitch = MAX_CURS / 8;
+		u8 *dat = (u8 *) cursor->image.data;
+		u8 *msk = (u8 *) cursor->mask;
+		u8 *src;
+
+		src = kmalloc(s_pitch * cursor->image.height, GFP_ATOMIC);
+
+		if (src) {
+			switch (cursor->rop) {
+			case ROP_XOR:
+				for (i = 0; i < s_pitch * cursor->image.height;
+				     i++)
+					src[i] = dat[i] ^ msk[i];
+				break;
+			case ROP_COPY:
+			default:
+				for (i = 0; i < s_pitch * cursor->image.height;
+				     i++)
+					src[i] = dat[i] & msk[i];
+				break;
+			}
+
+			fb_sysmove_buf_aligned(info, &info->pixmap, data,
+					       d_pitch, src, s_pitch,
+					       cursor->image.height);
+
+			bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) |
+			    ((info->cmap.green[bg_idx] & 0xf8) << 2) |
+			    ((info->cmap.blue[bg_idx] & 0xf8) >> 3) | 1 << 15;
+
+			fg = ((info->cmap.red[fg_idx] & 0xf8) << 7) |
+			    ((info->cmap.green[fg_idx] & 0xf8) << 2) |
+			    ((info->cmap.blue[fg_idx] & 0xf8) >> 3) | 1 << 15;
+
+			NVLockUnlock(par, 0);
+
+			nvidiafb_load_cursor_image(par, data, bg, fg,
+						   cursor->image.width,
+						   cursor->image.height);
+			kfree(src);
+		}
+	}
+
+	if (cursor->enable)
+		NVShowHideCursor(par, 1);
+
+	return 0;
+}
+
+static int nvidiafb_set_par(struct fb_info *info)
+{
+	struct nvidia_par *par = info->par;
+
+	NVTRACE_ENTER();
+
+	NVLockUnlock(par, 1);
+	if (!par->FlatPanel || (info->var.bits_per_pixel != 24) ||
+	    !par->twoHeads)
+		par->FPDither = 0;
+
+	nvidia_init_vga(info);
+	nvidia_calc_regs(info);
+	nvidia_write_regs(par);
+
+	NVLockUnlock(par, 0);
+	if (par->twoHeads) {
+		VGA_WR08(par->PCIO, 0x03D4, 0x44);
+		VGA_WR08(par->PCIO, 0x03D5, par->ModeReg.crtcOwner);
+		NVLockUnlock(par, 0);
+	}
+
+	NVWriteCrtc(par, 0x11, 0x00);
+	info->fix.line_length = (info->var.xres_virtual *
+				 info->var.bits_per_pixel) >> 3;
+	info->fix.visual = (info->var.bits_per_pixel == 8) ?
+	    FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
+
+	if (info->var.accel_flags) {
+		info->fbops->fb_imageblit = nvidiafb_imageblit;
+		info->fbops->fb_fillrect = nvidiafb_fillrect;
+		info->fbops->fb_copyarea = nvidiafb_copyarea;
+		info->fbops->fb_sync = nvidiafb_sync;
+		info->pixmap.scan_align = 4;
+		info->flags &= ~FBINFO_HWACCEL_DISABLED;
+		NVResetGraphics(info);
+	} else {
+		info->fbops->fb_imageblit = cfb_imageblit;
+		info->fbops->fb_fillrect = cfb_fillrect;
+		info->fbops->fb_copyarea = cfb_copyarea;
+		info->fbops->fb_sync = NULL;
+		info->pixmap.scan_align = 1;
+		info->flags |= FBINFO_HWACCEL_DISABLED;
+	}
+
+	par->cursor_reset = 1;
+
+	NVWriteCrtc(par, 0x11, 0xff);
+
+	NVTRACE_LEAVE();
+	return 0;
+}
+
+static int nvidiafb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			      unsigned blue, unsigned transp,
+			      struct fb_info *info)
+{
+	struct nvidia_par *par = info->par;
+	int i;
+
+	NVTRACE_ENTER();
+	if (regno >= (1 << info->var.green.length))
+		return -EINVAL;
+
+	if (info->var.grayscale) {
+		/* gray = 0.30*R + 0.59*G + 0.11*B */
+		red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+	}
+
+	if (regno < 16 && info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+		((u32 *) info->pseudo_palette)[regno] =
+		    (regno << info->var.red.offset) |
+		    (regno << info->var.green.offset) |
+		    (regno << info->var.blue.offset);
+	}
+
+	switch (info->var.bits_per_pixel) {
+	case 8:
+		/* "transparent" stuff is completely ignored. */
+		nvidia_write_clut(par, regno, red >> 8, green >> 8, blue >> 8);
+		break;
+	case 16:
+		if (info->var.green.length == 5) {
+			for (i = 0; i < 8; i++) {
+				nvidia_write_clut(par, regno * 8 + i, red >> 8,
+						  green >> 8, blue >> 8);
+			}
+		} else {
+			u8 r, g, b;
+
+			if (regno < 32) {
+				for (i = 0; i < 8; i++) {
+					nvidia_write_clut(par, regno * 8 + i,
+							  red >> 8, green >> 8,
+							  blue >> 8);
+				}
+			}
+
+			nvidia_read_clut(par, regno * 4, &r, &g, &b);
+
+			for (i = 0; i < 4; i++)
+				nvidia_write_clut(par, regno * 4 + i, r,
+						  green >> 8, b);
+		}
+		break;
+	case 32:
+		nvidia_write_clut(par, regno, red >> 8, green >> 8, blue >> 8);
+		break;
+	default:
+		/* do nothing */
+		break;
+	}
+
+	NVTRACE_LEAVE();
+	return 0;
+}
+
+static int nvidiafb_check_var(struct fb_var_screeninfo *var,
+			      struct fb_info *info)
+{
+	struct nvidia_par *par = info->par;
+	int memlen, vramlen, mode_valid = 0;
+	int pitch, err = 0;
+
+	NVTRACE_ENTER();
+
+	var->transp.offset = 0;
+	var->transp.length = 0;
+
+	var->xres &= ~7;
+
+	if (var->bits_per_pixel <= 8)
+		var->bits_per_pixel = 8;
+	else if (var->bits_per_pixel <= 16)
+		var->bits_per_pixel = 16;
+	else
+		var->bits_per_pixel = 32;
+
+	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:
+		var->green.length = (var->green.length < 6) ? 5 : 6;
+		var->red.length = 5;
+		var->blue.length = 5;
+		var->transp.length = 6 - var->green.length;
+		var->blue.offset = 0;
+		var->green.offset = 5;
+		var->red.offset = 5 + var->green.length;
+		var->transp.offset = (5 + var->red.offset) & 15;
+		break;
+	case 32:		/* RGBA 8888 */
+		var->red.offset = 16;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		var->transp.length = 8;
+		var->transp.offset = 24;
+		break;
+	}
+
+	var->red.msb_right = 0;
+	var->green.msb_right = 0;
+	var->blue.msb_right = 0;
+	var->transp.msb_right = 0;
+
+	if (!info->monspecs.hfmax || !info->monspecs.vfmax ||
+	    !info->monspecs.dclkmax || !fb_validate_mode(var, info))
+		mode_valid = 1;
+
+	/* calculate modeline if supported by monitor */
+	if (!mode_valid && info->monspecs.gtf) {
+		if (!fb_get_mode(FB_MAXTIMINGS, 0, var, info))
+			mode_valid = 1;
+	}
+
+	if (!mode_valid) {
+		struct fb_videomode *mode;
+
+		mode = fb_find_best_mode(var, &info->modelist);
+		if (mode) {
+			fb_videomode_to_var(var, mode);
+			mode_valid = 1;
+		}
+	}
+
+	if (!mode_valid && info->monspecs.modedb_len)
+		return -EINVAL;
+
+	if (par->fpWidth && par->fpHeight && (par->fpWidth < var->xres ||
+					      par->fpHeight < var->yres))
+		return -EINVAL;
+
+	if (var->yres_virtual < var->yres)
+		var->yres_virtual = var->yres;
+
+	if (var->xres_virtual < var->xres)
+		var->xres_virtual = var->xres;
+
+	var->xres_virtual = (var->xres_virtual + 63) & ~63;
+
+	vramlen = info->fix.smem_len;
+	pitch = ((var->xres_virtual * var->bits_per_pixel) + 7) / 8;
+	memlen = pitch * var->yres_virtual;
+
+	if (memlen > vramlen) {
+		var->yres_virtual = vramlen / pitch;
+
+		if (var->yres_virtual < var->yres) {
+			var->yres_virtual = var->yres;
+			var->xres_virtual = vramlen / var->yres_virtual;
+			var->xres_virtual /= var->bits_per_pixel / 8;
+			var->xres_virtual &= ~63;
+			pitch = (var->xres_virtual *
+				 var->bits_per_pixel + 7) / 8;
+			memlen = pitch * var->yres;
+
+			if (var->xres_virtual < var->xres) {
+				printk("nvidiafb: required video memory, "
+				       "%d bytes, for %dx%d-%d (virtual) "
+				       "is out of range\n",
+				       memlen, var->xres_virtual,
+				       var->yres_virtual, var->bits_per_pixel);
+				err = -ENOMEM;
+			}
+		}
+	}
+
+	if (var->accel_flags) {
+		if (var->yres_virtual > 0x7fff)
+			var->yres_virtual = 0x7fff;
+		if (var->xres_virtual > 0x7fff)
+			var->xres_virtual = 0x7fff;
+	}
+
+	var->xres_virtual &= ~63;
+
+	NVTRACE_LEAVE();
+
+	return err;
+}
+
+static int nvidiafb_pan_display(struct fb_var_screeninfo *var,
+				struct fb_info *info)
+{
+	struct nvidia_par *par = info->par;
+	u32 total;
+
+	total = info->var.yoffset * info->fix.line_length + info->var.xoffset;
+
+	NVSetStartAddress(par, total);
+
+	return 0;
+}
+
+static int nvidiafb_blank(int blank, struct fb_info *info)
+{
+	struct nvidia_par *par = info->par;
+	unsigned char tmp, vesa;
+
+	tmp = NVReadSeq(par, 0x01) & ~0x20;	/* screen on/off */
+	vesa = NVReadCrtc(par, 0x1a) & ~0xc0;	/* sync on/off */
+
+	NVTRACE_ENTER();
+
+	if (blank)
+		tmp |= 0x20;
+
+	switch (blank) {
+	case FB_BLANK_UNBLANK:
+	case FB_BLANK_NORMAL:
+		break;
+	case FB_BLANK_VSYNC_SUSPEND:
+		vesa |= 0x80;
+		break;
+	case FB_BLANK_HSYNC_SUSPEND:
+		vesa |= 0x40;
+		break;
+	case FB_BLANK_POWERDOWN:
+		vesa |= 0xc0;
+		break;
+	}
+
+	NVWriteSeq(par, 0x01, tmp);
+	NVWriteCrtc(par, 0x1a, vesa);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	if (par->FlatPanel && _machine == _MACH_Pmac) {
+		set_backlight_enable(!blank);
+	}
+#endif
+
+	NVTRACE_LEAVE();
+
+	return 0;
+}
+
+static struct fb_ops nvidia_fb_ops = {
+	.owner          = THIS_MODULE,
+	.fb_check_var   = nvidiafb_check_var,
+	.fb_set_par     = nvidiafb_set_par,
+	.fb_setcolreg   = nvidiafb_setcolreg,
+	.fb_pan_display = nvidiafb_pan_display,
+	.fb_blank       = nvidiafb_blank,
+	.fb_fillrect    = nvidiafb_fillrect,
+	.fb_copyarea    = nvidiafb_copyarea,
+	.fb_imageblit   = nvidiafb_imageblit,
+	.fb_cursor      = nvidiafb_cursor,
+	.fb_sync        = nvidiafb_sync,
+};
+
+static int __devinit nvidia_set_fbinfo(struct fb_info *info)
+{
+	struct fb_monspecs *specs = &info->monspecs;
+	struct fb_videomode modedb;
+	struct nvidia_par *par = info->par;
+	int lpitch;
+
+	NVTRACE_ENTER();
+	info->flags = FBINFO_DEFAULT
+	    | FBINFO_HWACCEL_IMAGEBLIT
+	    | FBINFO_HWACCEL_FILLRECT
+	    | FBINFO_HWACCEL_COPYAREA
+	    | FBINFO_HWACCEL_YPAN;
+
+	fb_videomode_to_modelist(info->monspecs.modedb,
+				 info->monspecs.modedb_len, &info->modelist);
+	fb_var_to_videomode(&modedb, &nvidiafb_default_var);
+
+	if (specs->modedb != NULL) {
+		/* get preferred timing */
+		if (specs->misc & FB_MISC_1ST_DETAIL) {
+			int i;
+
+			for (i = 0; i < specs->modedb_len; i++) {
+				if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {
+					modedb = specs->modedb[i];
+					break;
+				}
+			}
+		} else {
+			/* otherwise, get first mode in database */
+			modedb = specs->modedb[0];
+		}
+
+		fb_videomode_to_var(&nvidiafb_default_var, &modedb);
+		nvidiafb_default_var.bits_per_pixel = 8;
+	}
+
+	if (mode_option)
+		fb_find_mode(&nvidiafb_default_var, info, mode_option,
+			     specs->modedb, specs->modedb_len, &modedb, 8);
+
+	info->var = nvidiafb_default_var;
+	info->fix.visual = (info->var.bits_per_pixel == 8) ?
+		FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
+	info->pseudo_palette = par->pseudo_palette;
+	fb_alloc_cmap(&info->cmap, 256, 0);
+	fb_destroy_modedb(info->monspecs.modedb);
+	info->monspecs.modedb = NULL;
+
+	/* maximize virtual vertical length */
+	lpitch = info->var.xres_virtual *
+		((info->var.bits_per_pixel + 7) >> 3);
+	info->var.yres_virtual = info->fix.smem_len / lpitch;
+
+	info->pixmap.scan_align = 4;
+	info->pixmap.buf_align = 4;
+	info->pixmap.size = 8 * 1024;
+	info->pixmap.flags = FB_PIXMAP_SYSTEM;
+
+	if (!hwcur)
+		info->fbops->fb_cursor = soft_cursor;
+	info->var.accel_flags = (!noaccel);
+
+	switch (par->Architecture) {
+	case NV_ARCH_04:
+		info->fix.accel = FB_ACCEL_NV4;
+		break;
+	case NV_ARCH_10:
+		info->fix.accel = FB_ACCEL_NV_10;
+		break;
+	case NV_ARCH_20:
+		info->fix.accel = FB_ACCEL_NV_20;
+		break;
+	case NV_ARCH_30:
+		info->fix.accel = FB_ACCEL_NV_30;
+		break;
+	case NV_ARCH_40:
+		info->fix.accel = FB_ACCEL_NV_40;
+		break;
+	}
+
+	NVTRACE_LEAVE();
+
+	return nvidiafb_check_var(&info->var, info);
+}
+
+static u32 __devinit nvidia_get_arch(struct pci_dev *pd)
+{
+	u32 arch = 0;
+
+	switch (pd->device & 0x0ff0) {
+	case 0x0100:		/* GeForce 256 */
+	case 0x0110:		/* GeForce2 MX */
+	case 0x0150:		/* GeForce2 */
+	case 0x0170:		/* GeForce4 MX */
+	case 0x0180:		/* GeForce4 MX (8x AGP) */
+	case 0x01A0:		/* nForce */
+	case 0x01F0:		/* nForce2 */
+		arch = NV_ARCH_10;
+		break;
+	case 0x0200:		/* GeForce3 */
+	case 0x0250:		/* GeForce4 Ti */
+	case 0x0280:		/* GeForce4 Ti (8x AGP) */
+		arch = NV_ARCH_20;
+		break;
+	case 0x0300:		/* GeForceFX 5800 */
+	case 0x0310:		/* GeForceFX 5600 */
+	case 0x0320:		/* GeForceFX 5200 */
+	case 0x0330:		/* GeForceFX 5900 */
+	case 0x0340:		/* GeForceFX 5700 */
+		arch = NV_ARCH_30;
+		break;
+	case 0x0040:
+	case 0x00C0:
+	case 0x0120:
+	case 0x0130:
+	case 0x0140:
+	case 0x0160:
+	case 0x01D0:
+	case 0x0090:
+	case 0x0210:
+	case 0x0220:
+	case 0x0230:
+		arch = NV_ARCH_40;
+		break;
+	case 0x0020:		/* TNT, TNT2 */
+		arch = NV_ARCH_04;
+		break;
+	default:		/* unknown architecture */
+		break;
+	}
+
+	return arch;
+}
+
+static int __devinit nvidiafb_probe(struct pci_dev *pd,
+				    const struct pci_device_id *ent)
+{
+	struct nvidia_par *par;
+	struct fb_info *info;
+	unsigned short cmd;
+
+
+	NVTRACE_ENTER();
+	assert(pd != NULL);
+
+	info = framebuffer_alloc(sizeof(struct nvidia_par), &pd->dev);
+
+	if (!info)
+		goto err_out;
+
+	par = (struct nvidia_par *)info->par;
+	par->pci_dev = pd;
+
+	info->pixmap.addr = kmalloc(8 * 1024, GFP_KERNEL);
+
+	if (info->pixmap.addr == NULL)
+		goto err_out_kfree;
+
+	memset(info->pixmap.addr, 0, 8 * 1024);
+
+	if (pci_enable_device(pd)) {
+		printk(KERN_ERR PFX "cannot enable PCI device\n");
+		goto err_out_enable;
+	}
+
+	if (pci_request_regions(pd, "nvidiafb")) {
+		printk(KERN_ERR PFX "cannot request PCI regions\n");
+		goto err_out_request;
+	}
+
+	par->Architecture = nvidia_get_arch(pd);
+
+	par->Chipset = (pd->vendor << 16) | pd->device;
+	printk(KERN_INFO PFX "nVidia device/chipset %X\n", par->Chipset);
+
+#ifdef CONFIG_PCI_NAMES
+	printk(KERN_INFO PFX "%s\n", pd->pretty_name);
+#endif
+
+	if (par->Architecture == 0) {
+		printk(KERN_ERR PFX "unknown NV_ARCH\n");
+		goto err_out_free_base0;
+	}
+
+	sprintf(nvidiafb_fix.id, "NV%x", (pd->device & 0x0ff0) >> 4);
+
+	par->FlatPanel = flatpanel;
+
+	if (flatpanel == 1)
+		printk(KERN_INFO PFX "flatpanel support enabled\n");
+
+	par->CRTCnumber = forceCRTC;
+	par->FpScale = (!noscale);
+	par->paneltweak = paneltweak;
+
+	/* enable IO and mem if not already done */
+	pci_read_config_word(pd, PCI_COMMAND, &cmd);
+	cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+	pci_write_config_word(pd, PCI_COMMAND, cmd);
+
+	nvidiafb_fix.mmio_start = pci_resource_start(pd, 0);
+	nvidiafb_fix.smem_start = pci_resource_start(pd, 1);
+	nvidiafb_fix.mmio_len = pci_resource_len(pd, 0);
+
+	par->REGS = ioremap(nvidiafb_fix.mmio_start, nvidiafb_fix.mmio_len);
+
+	if (!par->REGS) {
+		printk(KERN_ERR PFX "cannot ioremap MMIO base\n");
+		goto err_out_free_base0;
+	}
+
+	NVCommonSetup(info);
+
+	par->FbAddress = nvidiafb_fix.smem_start;
+	par->FbMapSize = par->RamAmountKBytes * 1024;
+	par->FbUsableSize = par->FbMapSize - (128 * 1024);
+	par->ScratchBufferSize = (par->Architecture < NV_ARCH_10) ? 8 * 1024 :
+	    16 * 1024;
+	par->ScratchBufferStart = par->FbUsableSize - par->ScratchBufferSize;
+	info->screen_base = ioremap(nvidiafb_fix.smem_start, par->FbMapSize);
+	nvidiafb_fix.smem_len = par->FbUsableSize;
+
+	if (!info->screen_base) {
+		printk(KERN_ERR PFX "cannot ioremap FB base\n");
+		goto err_out_free_base1;
+	}
+
+	par->FbStart = info->screen_base;
+
+#ifdef CONFIG_MTRR
+	if (!nomtrr) {
+		par->mtrr.vram = mtrr_add(nvidiafb_fix.smem_start,
+					  par->FbMapSize, MTRR_TYPE_WRCOMB, 1);
+		if (par->mtrr.vram < 0) {
+			printk(KERN_ERR PFX "unable to setup MTRR\n");
+		} else {
+			par->mtrr.vram_valid = 1;
+			/* let there be speed */
+			printk(KERN_INFO PFX "MTRR set to ON\n");
+		}
+	}
+#endif				/* CONFIG_MTRR */
+
+	info->fbops = &nvidia_fb_ops;
+	info->fix = nvidiafb_fix;
+
+	if (nvidia_set_fbinfo(info) < 0) {
+		printk(KERN_ERR PFX "error setting initial video mode\n");
+		goto err_out_iounmap_fb;
+	}
+
+	nvidia_save_vga(par, &par->SavedReg);
+
+	if (register_framebuffer(info) < 0) {
+		printk(KERN_ERR PFX "error registering nVidia framebuffer\n");
+		goto err_out_iounmap_fb;
+	}
+
+	pci_set_drvdata(pd, info);
+
+	printk(KERN_INFO PFX
+	       "PCI nVidia %s framebuffer (%dMB @ 0x%lX)\n",
+	       info->fix.id,
+	       par->FbMapSize / (1024 * 1024), info->fix.smem_start);
+#ifdef CONFIG_PMAC_BACKLIGHT
+	if (par->FlatPanel && _machine == _MACH_Pmac)
+		register_backlight_controller(&nvidia_backlight_controller,
+					      par, "mnca");
+#endif
+	NVTRACE_LEAVE();
+	return 0;
+
+      err_out_iounmap_fb:
+	iounmap(info->screen_base);
+	fb_destroy_modedb(info->monspecs.modedb);
+	nvidia_delete_i2c_busses(par);
+      err_out_free_base1:
+	iounmap(par->REGS);
+      err_out_free_base0:
+	pci_release_regions(pd);
+      err_out_request:
+	pci_disable_device(pd);
+      err_out_enable:
+	kfree(info->pixmap.addr);
+      err_out_kfree:
+	framebuffer_release(info);
+      err_out:
+	return -ENODEV;
+}
+
+static void __exit nvidiafb_remove(struct pci_dev *pd)
+{
+	struct fb_info *info = pci_get_drvdata(pd);
+	struct nvidia_par *par = info->par;
+
+	NVTRACE_ENTER();
+	if (!info)
+		return;
+
+	unregister_framebuffer(info);
+#ifdef CONFIG_MTRR
+	if (par->mtrr.vram_valid)
+		mtrr_del(par->mtrr.vram, info->fix.smem_start,
+			 info->fix.smem_len);
+#endif				/* CONFIG_MTRR */
+
+	iounmap(info->screen_base);
+	fb_destroy_modedb(info->monspecs.modedb);
+	nvidia_delete_i2c_busses(par);
+	iounmap(par->REGS);
+	pci_release_regions(pd);
+	pci_disable_device(pd);
+	kfree(info->pixmap.addr);
+	framebuffer_release(info);
+	pci_set_drvdata(pd, NULL);
+	NVTRACE_LEAVE();
+}
+
+/* ------------------------------------------------------------------------- *
+ *
+ * initialization
+ *
+ * ------------------------------------------------------------------------- */
+
+#ifndef MODULE
+static int __devinit nvidiafb_setup(char *options)
+{
+	char *this_opt;
+
+	NVTRACE_ENTER();
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!strncmp(this_opt, "forceCRTC", 9)) {
+			char *p;
+
+			p = this_opt + 9;
+			if (!*p || !*(++p))
+				continue;
+			forceCRTC = *p - '0';
+			if (forceCRTC < 0 || forceCRTC > 1)
+				forceCRTC = -1;
+		} else if (!strncmp(this_opt, "flatpanel", 9)) {
+			flatpanel = 1;
+		} else if (!strncmp(this_opt, "hwcur", 5)) {
+			hwcur = 1;
+		} else if (!strncmp(this_opt, "noaccel", 6)) {
+			noaccel = 1;
+		} else if (!strncmp(this_opt, "noscale", 7)) {
+			noscale = 1;
+		} else if (!strncmp(this_opt, "paneltweak:", 11)) {
+			paneltweak = simple_strtoul(this_opt+11, NULL, 0);
+#ifdef CONFIG_MTRR
+		} else if (!strncmp(this_opt, "nomtrr", 6)) {
+			nomtrr = 1;
+#endif
+		} else
+			mode_option = this_opt;
+	}
+	NVTRACE_LEAVE();
+	return 0;
+}
+#endif				/* !MODULE */
+
+static struct pci_driver nvidiafb_driver = {
+	.name = "nvidiafb",
+	.id_table = nvidiafb_pci_tbl,
+	.probe = nvidiafb_probe,
+	.remove = __exit_p(nvidiafb_remove),
+};
+
+/* ------------------------------------------------------------------------- *
+ *
+ * modularization
+ *
+ * ------------------------------------------------------------------------- */
+
+static int __devinit nvidiafb_init(void)
+{
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("nvidiafb", &option))
+		return -ENODEV;
+	nvidiafb_setup(option);
+#endif
+	return pci_register_driver(&nvidiafb_driver);
+}
+
+module_init(nvidiafb_init);
+
+#ifdef MODULE
+static void __exit nvidiafb_exit(void)
+{
+	pci_unregister_driver(&nvidiafb_driver);
+}
+
+module_exit(nvidiafb_exit);
+
+module_param(flatpanel, int, 0);
+MODULE_PARM_DESC(flatpanel,
+		 "Enables experimental flat panel support for some chipsets. "
+		 "(0 or 1=enabled) (default=0)");
+module_param(hwcur, int, 0);
+MODULE_PARM_DESC(hwcur,
+		 "Enables hardware cursor implementation. (0 or 1=enabled) "
+		 "(default=0)");
+module_param(noaccel, int, 0);
+MODULE_PARM_DESC(noaccel,
+		 "Disables hardware acceleration. (0 or 1=disable) "
+		 "(default=0)");
+module_param(noscale, int, 0);
+MODULE_PARM_DESC(noscale,
+		 "Disables screen scaleing. (0 or 1=disable) "
+		 "(default=0, do scaling)");
+module_param(paneltweak, int, 0);
+MODULE_PARM_DESC(paneltweak,
+		 "Tweak display settings for flatpanels. "
+		 "(default=0, no tweaks)");
+module_param(forceCRTC, int, 0);
+MODULE_PARM_DESC(forceCRTC,
+		 "Forces usage of a particular CRTC in case autodetection "
+		 "fails. (0 or 1) (default=autodetect)");
+#ifdef CONFIG_MTRR
+module_param(nomtrr, bool, 0);
+MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) "
+		 "(default=0)");
+#endif
+
+MODULE_AUTHOR("Antonino Daplas");
+MODULE_DESCRIPTION("Framebuffer driver for nVidia graphics chipset");
+MODULE_LICENSE("GPL");
+#endif				/* MODULE */
+
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
new file mode 100644
index 0000000..42a6591
--- /dev/null
+++ b/drivers/video/offb.c
@@ -0,0 +1,538 @@
+/*
+ *  linux/drivers/video/offb.c -- Open Firmware based frame buffer device
+ *
+ *	Copyright (C) 1997 Geert Uytterhoeven
+ *
+ *  This driver is partly based on the PowerMac console driver:
+ *
+ *	Copyright (C) 1996 Paul Mackerras
+ *
+ *  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 <linux/fb.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+
+#ifdef CONFIG_PPC64
+#include <asm/pci-bridge.h>
+#endif
+
+#ifdef CONFIG_PPC32
+#include <asm/bootx.h>
+#endif
+
+#include "macmodes.h"
+
+/* Supported palette hacks */
+enum {
+	cmap_unknown,
+	cmap_m64,		/* ATI Mach64 */
+	cmap_r128,		/* ATI Rage128 */
+	cmap_M3A,		/* ATI Rage Mobility M3 Head A */
+	cmap_M3B,		/* ATI Rage Mobility M3 Head B */
+	cmap_radeon,		/* ATI Radeon */
+	cmap_gxt2000,		/* IBM GXT2000 */
+};
+
+struct offb_par {
+	volatile void __iomem *cmap_adr;
+	volatile void __iomem *cmap_data;
+	int cmap_type;
+	int blanked;
+};
+
+struct offb_par default_par;
+
+    /*
+     *  Interface used by the world
+     */
+
+int offb_init(void);
+
+static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			  u_int transp, struct fb_info *info);
+static int offb_blank(int blank, struct fb_info *info);
+
+#ifdef CONFIG_PPC32
+extern boot_infos_t *boot_infos;
+#endif
+
+static void offb_init_nodriver(struct device_node *);
+static void offb_init_fb(const char *name, const char *full_name,
+			 int width, int height, int depth, int pitch,
+			 unsigned long address, struct device_node *dp);
+
+static struct fb_ops offb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_setcolreg	= offb_setcolreg,
+	.fb_blank	= offb_blank,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+    /*
+     *  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 offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			  u_int transp, struct fb_info *info)
+{
+	struct offb_par *par = (struct offb_par *) info->par;
+
+	if (!par->cmap_adr || regno > 255)
+		return 1;
+
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	switch (par->cmap_type) {
+	case cmap_m64:
+		writeb(regno, par->cmap_adr);
+		writeb(red, par->cmap_data);
+		writeb(green, par->cmap_data);
+		writeb(blue, par->cmap_data);
+		break;
+	case cmap_M3A:
+		/* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */
+		out_le32(par->cmap_adr + 0x58,
+			 in_le32(par->cmap_adr + 0x58) & ~0x20);
+	case cmap_r128:
+		/* Set palette index & data */
+		out_8(par->cmap_adr + 0xb0, regno);
+		out_le32(par->cmap_adr + 0xb4,
+			 (red << 16 | green << 8 | blue));
+		break;
+	case cmap_M3B:
+		/* Set PALETTE_ACCESS_CNTL in DAC_CNTL */
+		out_le32(par->cmap_adr + 0x58,
+			 in_le32(par->cmap_adr + 0x58) | 0x20);
+		/* Set palette index & data */
+		out_8(par->cmap_adr + 0xb0, regno);
+		out_le32(par->cmap_adr + 0xb4, (red << 16 | green << 8 | blue));
+		break;
+	case cmap_radeon:
+		/* Set palette index & data (could be smarter) */
+		out_8(par->cmap_adr + 0xb0, regno);
+		out_le32(par->cmap_adr + 0xb4, (red << 16 | green << 8 | blue));
+		break;
+	case cmap_gxt2000:
+		out_le32((unsigned __iomem *) par->cmap_adr + regno,
+			 (red << 16 | green << 8 | blue));
+		break;
+	}
+
+	if (regno < 16)
+		switch (info->var.bits_per_pixel) {
+		case 16:
+			((u16 *) (info->pseudo_palette))[regno] =
+			    (regno << 10) | (regno << 5) | regno;
+			break;
+		case 32:
+			{
+				int i = (regno << 8) | regno;
+				((u32 *) (info->pseudo_palette))[regno] =
+				    (i << 16) | i;
+				break;
+			}
+		}
+	return 0;
+}
+
+    /*
+     *  Blank the display.
+     */
+
+static int offb_blank(int blank, struct fb_info *info)
+{
+	struct offb_par *par = (struct offb_par *) info->par;
+	int i, j;
+
+	if (!par->cmap_adr)
+		return 0;
+
+	if (!par->blanked)
+		if (!blank)
+			return 0;
+
+	par->blanked = blank;
+
+	if (blank)
+		for (i = 0; i < 256; i++) {
+			switch (par->cmap_type) {
+			case cmap_m64:
+				writeb(i, par->cmap_adr);
+				for (j = 0; j < 3; j++)
+					writeb(0, par->cmap_data);
+				break;
+			case cmap_M3A:
+				/* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */
+				out_le32(par->cmap_adr + 0x58,
+					 in_le32(par->cmap_adr + 0x58) & ~0x20);
+			case cmap_r128:
+				/* Set palette index & data */
+				out_8(par->cmap_adr + 0xb0, i);
+				out_le32(par->cmap_adr + 0xb4, 0);
+				break;
+			case cmap_M3B:
+				/* Set PALETTE_ACCESS_CNTL in DAC_CNTL */
+				out_le32(par->cmap_adr + 0x58,
+					 in_le32(par->cmap_adr + 0x58) | 0x20);
+				/* Set palette index & data */
+				out_8(par->cmap_adr + 0xb0, i);
+				out_le32(par->cmap_adr + 0xb4, 0);
+				break;
+			case cmap_radeon:
+				out_8(par->cmap_adr + 0xb0, i);
+				out_le32(par->cmap_adr + 0xb4, 0);
+				break;
+			case cmap_gxt2000:
+				out_le32((unsigned __iomem *) par->cmap_adr + i,
+					 0);
+				break;
+			}
+	} else
+		fb_set_cmap(&info->cmap, info);
+	return 0;
+}
+
+    /*
+     *  Initialisation
+     */
+
+int __init offb_init(void)
+{
+	struct device_node *dp = NULL, *boot_disp = NULL;
+#if defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32)
+	struct device_node *macos_display = NULL;
+#endif
+	if (fb_get_options("offb", NULL))
+		return -ENODEV;
+
+#if defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32)
+	/* If we're booted from BootX... */
+	if (boot_infos != 0) {
+		unsigned long addr =
+		    (unsigned long) boot_infos->dispDeviceBase;
+		/* find the device node corresponding to the macos display */
+		while ((dp = of_find_node_by_type(dp, "display"))) {
+			int i;
+			/*
+			 * Grrr...  It looks like the MacOS ATI driver
+			 * munges the assigned-addresses property (but
+			 * the AAPL,address value is OK).
+			 */
+			if (strncmp(dp->name, "ATY,", 4) == 0
+			    && dp->n_addrs == 1) {
+				unsigned int *ap =
+				    (unsigned int *) get_property(dp,
+								  "AAPL,address",
+								  NULL);
+				if (ap != NULL) {
+					dp->addrs[0].address = *ap;
+					dp->addrs[0].size = 0x01000000;
+				}
+			}
+
+			/*
+			 * The LTPro on the Lombard powerbook has no addresses
+			 * on the display nodes, they are on their parent.
+			 */
+			if (dp->n_addrs == 0
+			    && device_is_compatible(dp, "ATY,264LTPro")) {
+				int na;
+				unsigned int *ap = (unsigned int *)
+				    get_property(dp, "AAPL,address", &na);
+				if (ap != 0)
+					for (na /= sizeof(unsigned int);
+					     na > 0; --na, ++ap)
+						if (*ap <= addr
+						    && addr <
+						    *ap + 0x1000000)
+							goto foundit;
+			}
+
+			/*
+			 * See if the display address is in one of the address
+			 * ranges for this display.
+			 */
+			for (i = 0; i < dp->n_addrs; ++i) {
+				if (dp->addrs[i].address <= addr
+				    && addr <
+				    dp->addrs[i].address +
+				    dp->addrs[i].size)
+					break;
+			}
+			if (i < dp->n_addrs) {
+			      foundit:
+				printk(KERN_INFO "MacOS display is %s\n",
+				       dp->full_name);
+				macos_display = dp;
+				break;
+			}
+		}
+
+		/* initialize it */
+		offb_init_fb(macos_display ? macos_display->
+			     name : "MacOS display",
+			     macos_display ? macos_display->
+			     full_name : "MacOS display",
+			     boot_infos->dispDeviceRect[2],
+			     boot_infos->dispDeviceRect[3],
+			     boot_infos->dispDeviceDepth,
+			     boot_infos->dispDeviceRowBytes, addr, NULL);
+	}
+#endif /* defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32) */
+
+	for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) {
+		if (get_property(dp, "linux,opened", NULL) &&
+		    get_property(dp, "linux,boot-display", NULL)) {
+			boot_disp = dp;
+			offb_init_nodriver(dp);
+		}
+	}
+	for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) {
+		if (get_property(dp, "linux,opened", NULL) &&
+		    dp != boot_disp)
+			offb_init_nodriver(dp);
+	}
+
+	return 0;
+}
+
+
+static void __init offb_init_nodriver(struct device_node *dp)
+{
+	int *pp, i;
+	unsigned int len;
+	int width = 640, height = 480, depth = 8, pitch;
+	unsigned *up;
+	unsigned long address;
+
+	if ((pp = (int *) get_property(dp, "depth", &len)) != NULL
+	    && len == sizeof(int))
+		depth = *pp;
+	if ((pp = (int *) get_property(dp, "width", &len)) != NULL
+	    && len == sizeof(int))
+		width = *pp;
+	if ((pp = (int *) get_property(dp, "height", &len)) != NULL
+	    && len == sizeof(int))
+		height = *pp;
+	if ((pp = (int *) get_property(dp, "linebytes", &len)) != NULL
+	    && len == sizeof(int)) {
+		pitch = *pp;
+		if (pitch == 1)
+			pitch = 0x1000;
+	} else
+		pitch = width;
+	if ((up = (unsigned *) get_property(dp, "address", &len)) != NULL
+	    && len == sizeof(unsigned))
+		address = (u_long) * up;
+	else {
+		for (i = 0; i < dp->n_addrs; ++i)
+			if (dp->addrs[i].size >=
+			    pitch * height * depth / 8)
+				break;
+		if (i >= dp->n_addrs) {
+			printk(KERN_ERR
+			       "no framebuffer address found for %s\n",
+			       dp->full_name);
+			return;
+		}
+
+		address = (u_long) dp->addrs[i].address;
+
+#ifdef CONFIG_PPC64
+		address += dp->phb->pci_mem_offset;
+#endif
+
+		/* kludge for valkyrie */
+		if (strcmp(dp->name, "valkyrie") == 0)
+			address += 0x1000;
+	}
+	offb_init_fb(dp->name, dp->full_name, width, height, depth,
+		     pitch, address, dp);
+
+}
+
+static void __init offb_init_fb(const char *name, const char *full_name,
+				int width, int height, int depth,
+				int pitch, unsigned long address,
+				struct device_node *dp)
+{
+	unsigned long res_size = pitch * height * depth / 8;
+	struct offb_par *par = &default_par;
+	unsigned long res_start = address;
+	struct fb_fix_screeninfo *fix;
+	struct fb_var_screeninfo *var;
+	struct fb_info *info;
+	int size;
+
+	if (!request_mem_region(res_start, res_size, "offb"))
+		return;
+
+	printk(KERN_INFO
+	       "Using unsupported %dx%d %s at %lx, depth=%d, pitch=%d\n",
+	       width, height, name, address, depth, pitch);
+	if (depth != 8 && depth != 16 && depth != 32) {
+		printk(KERN_ERR "%s: can't use depth = %d\n", full_name,
+		       depth);
+		release_mem_region(res_start, res_size);
+		return;
+	}
+
+	size = sizeof(struct fb_info) + sizeof(u32) * 17;
+
+	info = kmalloc(size, GFP_ATOMIC);
+	
+	if (info == 0) {
+		release_mem_region(res_start, res_size);
+		return;
+	}
+	memset(info, 0, size);
+
+	fix = &info->fix;
+	var = &info->var;
+
+	strcpy(fix->id, "OFfb ");
+	strncat(fix->id, name, sizeof(fix->id) - sizeof("OFfb "));
+	fix->id[sizeof(fix->id) - 1] = '\0';
+
+	var->xres = var->xres_virtual = width;
+	var->yres = var->yres_virtual = height;
+	fix->line_length = pitch;
+
+	fix->smem_start = address;
+	fix->smem_len = pitch * height;
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->type_aux = 0;
+
+	par->cmap_type = cmap_unknown;
+	if (depth == 8) {
+		/* XXX kludge for ati */
+		if (dp && !strncmp(name, "ATY,Rage128", 11)) {
+			unsigned long regbase = dp->addrs[2].address;
+			par->cmap_adr = ioremap(regbase, 0x1FFF);
+			par->cmap_type = cmap_r128;
+		} else if (dp && (!strncmp(name, "ATY,RageM3pA", 12)
+				  || !strncmp(name, "ATY,RageM3p12A", 14))) {
+			unsigned long regbase =
+			    dp->parent->addrs[2].address;
+			par->cmap_adr = ioremap(regbase, 0x1FFF);
+			par->cmap_type = cmap_M3A;
+		} else if (dp && !strncmp(name, "ATY,RageM3pB", 12)) {
+			unsigned long regbase =
+			    dp->parent->addrs[2].address;
+			par->cmap_adr = ioremap(regbase, 0x1FFF);
+			par->cmap_type = cmap_M3B;
+		} else if (dp && !strncmp(name, "ATY,Rage6", 9)) {
+			unsigned long regbase = dp->addrs[1].address;
+			par->cmap_adr = ioremap(regbase, 0x1FFF);
+			par->cmap_type = cmap_radeon;
+		} else if (!strncmp(name, "ATY,", 4)) {
+			unsigned long base = address & 0xff000000UL;
+			par->cmap_adr =
+			    ioremap(base + 0x7ff000, 0x1000) + 0xcc0;
+			par->cmap_data = par->cmap_adr + 1;
+			par->cmap_type = cmap_m64;
+		} else if (device_is_compatible(dp, "pci1014,b7")) {
+			unsigned long regbase = dp->addrs[0].address;
+			par->cmap_adr = ioremap(regbase + 0x6000, 0x1000);
+			par->cmap_type = cmap_gxt2000;
+		}
+		fix->visual = par->cmap_adr ? FB_VISUAL_PSEUDOCOLOR
+		    : FB_VISUAL_STATIC_PSEUDOCOLOR;
+	} else
+		fix->visual =	/* par->cmap_adr ? FB_VISUAL_DIRECTCOLOR
+				   : */ FB_VISUAL_TRUECOLOR;
+
+	var->xoffset = var->yoffset = 0;
+	var->bits_per_pixel = depth;
+	switch (depth) {
+	case 8:
+		var->bits_per_pixel = 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:		/* RGB 555 */
+		var->bits_per_pixel = 16;
+		var->red.offset = 10;
+		var->red.length = 5;
+		var->green.offset = 5;
+		var->green.length = 5;
+		var->blue.offset = 0;
+		var->blue.length = 5;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		break;
+	case 32:		/* RGB 888 */
+		var->bits_per_pixel = 32;
+		var->red.offset = 16;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		var->transp.offset = 24;
+		var->transp.length = 8;
+		break;
+	}
+	var->red.msb_right = var->green.msb_right = var->blue.msb_right =
+	    var->transp.msb_right = 0;
+	var->grayscale = 0;
+	var->nonstd = 0;
+	var->activate = 0;
+	var->height = var->width = -1;
+	var->pixclock = 10000;
+	var->left_margin = var->right_margin = 16;
+	var->upper_margin = var->lower_margin = 16;
+	var->hsync_len = var->vsync_len = 8;
+	var->sync = 0;
+	var->vmode = FB_VMODE_NONINTERLACED;
+
+	info->fbops = &offb_ops;
+	info->screen_base = ioremap(address, fix->smem_len);
+	info->par = par;
+	info->pseudo_palette = (void *) (info + 1);
+	info->flags = FBINFO_DEFAULT;
+
+	fb_alloc_cmap(&info->cmap, 256, 0);
+
+	if (register_framebuffer(info) < 0) {
+		kfree(info);
+		release_mem_region(res_start, res_size);
+		return;
+	}
+
+	printk(KERN_INFO "fb%d: Open Firmware frame buffer device on %s\n",
+	       info->node, full_name);
+}
+
+module_init(offb_init);
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c
new file mode 100644
index 0000000..7808a01
--- /dev/null
+++ b/drivers/video/p9100.c
@@ -0,0 +1,379 @@
+/* p9100.c: P9100 frame buffer driver
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright 1999 Derrick J Brashear (shadow@dementia.org)
+ *
+ * Driver layout based loosely on tgafb.c, see that file for credits.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/mm.h>
+
+#include <asm/io.h>
+#include <asm/sbus.h>
+#include <asm/oplib.h>
+#include <asm/fbio.h>
+
+#include "sbuslib.h"
+
+/*
+ * Local functions.
+ */
+
+static int p9100_setcolreg(unsigned, unsigned, unsigned, unsigned,
+			   unsigned, struct fb_info *);
+static int p9100_blank(int, struct fb_info *);
+
+static int p9100_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
+static int p9100_ioctl(struct inode *, struct file *, unsigned int,
+		       unsigned long, struct fb_info *);
+
+/*
+ *  Frame buffer operations
+ */
+
+static struct fb_ops p9100_ops = {
+	.owner			= THIS_MODULE,
+	.fb_setcolreg		= p9100_setcolreg,
+	.fb_blank		= p9100_blank,
+	.fb_fillrect		= cfb_fillrect,
+	.fb_copyarea		= cfb_copyarea,
+	.fb_imageblit		= cfb_imageblit,
+	.fb_mmap		= p9100_mmap,
+	.fb_ioctl		= p9100_ioctl,
+	.fb_cursor		= soft_cursor,
+};
+
+/* P9100 control registers */
+#define P9100_SYSCTL_OFF	0x0UL
+#define P9100_VIDEOCTL_OFF	0x100UL
+#define P9100_VRAMCTL_OFF 	0x180UL
+#define P9100_RAMDAC_OFF 	0x200UL
+#define P9100_VIDEOCOPROC_OFF 	0x400UL
+
+/* P9100 command registers */
+#define P9100_CMD_OFF 0x0UL
+
+/* P9100 framebuffer memory */
+#define P9100_FB_OFF 0x0UL
+
+/* 3 bits: 2=8bpp 3=16bpp 5=32bpp 7=24bpp */
+#define SYS_CONFIG_PIXELSIZE_SHIFT 26 
+
+#define SCREENPAINT_TIMECTL1_ENABLE_VIDEO 0x20 /* 0 = off, 1 = on */
+
+struct p9100_regs {
+	/* Registers for the system control */
+	volatile u32 sys_base;
+	volatile u32 sys_config;
+	volatile u32 sys_intr;
+	volatile u32 sys_int_ena;
+	volatile u32 sys_alt_rd;
+	volatile u32 sys_alt_wr;
+	volatile u32 sys_xxx[58];
+
+	/* Registers for the video control */
+	volatile u32 vid_base;
+	volatile u32 vid_hcnt;
+	volatile u32 vid_htotal;
+	volatile u32 vid_hsync_rise;
+	volatile u32 vid_hblank_rise;
+	volatile u32 vid_hblank_fall;
+	volatile u32 vid_hcnt_preload;
+	volatile u32 vid_vcnt;
+	volatile u32 vid_vlen;
+	volatile u32 vid_vsync_rise;
+	volatile u32 vid_vblank_rise;
+	volatile u32 vid_vblank_fall;
+	volatile u32 vid_vcnt_preload;
+	volatile u32 vid_screenpaint_addr;
+	volatile u32 vid_screenpaint_timectl1;
+	volatile u32 vid_screenpaint_qsfcnt;
+	volatile u32 vid_screenpaint_timectl2;
+	volatile u32 vid_xxx[15];
+
+	/* Registers for the video control */
+	volatile u32 vram_base;
+	volatile u32 vram_memcfg;
+	volatile u32 vram_refresh_pd;
+	volatile u32 vram_refresh_cnt;
+	volatile u32 vram_raslo_max;
+	volatile u32 vram_raslo_cur;
+	volatile u32 pwrup_cfg;
+	volatile u32 vram_xxx[25];
+
+	/* Registers for IBM RGB528 Palette */
+	volatile u32 ramdac_cmap_wridx; 
+	volatile u32 ramdac_palette_data;
+	volatile u32 ramdac_pixel_mask;
+	volatile u32 ramdac_palette_rdaddr;
+	volatile u32 ramdac_idx_lo;
+	volatile u32 ramdac_idx_hi;
+	volatile u32 ramdac_idx_data;
+	volatile u32 ramdac_idx_ctl;
+	volatile u32 ramdac_xxx[1784];
+};
+
+struct p9100_cmd_parameng {
+	volatile u32 parameng_status;
+	volatile u32 parameng_bltcmd;
+	volatile u32 parameng_quadcmd;
+};
+
+struct p9100_par {
+	spinlock_t		lock;
+	struct p9100_regs	__iomem *regs;
+
+	u32			flags;
+#define P9100_FLAG_BLANKED	0x00000001
+
+	unsigned long		physbase;
+	unsigned long		fbsize;
+
+	struct sbus_dev		*sdev;
+	struct list_head	list;
+};
+
+/**
+ *      p9100_setcolreg - Optional function. Sets a color register.
+ *      @regno: boolean, 0 copy local, 1 get_user() function
+ *      @red: frame buffer colormap structure
+ *      @green: The green value which can be up to 16 bits wide
+ *      @blue:  The blue value which can be up to 16 bits wide.
+ *      @transp: If supported the alpha value which can be up to 16 bits wide.
+ *      @info: frame buffer info structure
+ */
+static int p9100_setcolreg(unsigned regno,
+			   unsigned red, unsigned green, unsigned blue,
+			   unsigned transp, struct fb_info *info)
+{
+	struct p9100_par *par = (struct p9100_par *) info->par;
+	struct p9100_regs __iomem *regs = par->regs;
+	unsigned long flags;
+
+	if (regno >= 256)
+		return 1;
+
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	sbus_writel((regno << 16), &regs->ramdac_cmap_wridx);
+	sbus_writel((red << 16), &regs->ramdac_palette_data);
+	sbus_writel((green << 16), &regs->ramdac_palette_data);
+	sbus_writel((blue << 16), &regs->ramdac_palette_data);
+
+	spin_unlock_irqrestore(&par->lock, flags);
+
+	return 0;
+}
+
+/**
+ *      p9100_blank - Optional function.  Blanks the display.
+ *      @blank_mode: the blank mode we want.
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+p9100_blank(int blank, struct fb_info *info)
+{
+	struct p9100_par *par = (struct p9100_par *) info->par;
+	struct p9100_regs __iomem *regs = par->regs;
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	switch (blank) {
+	case FB_BLANK_UNBLANK: /* Unblanking */
+		val = sbus_readl(&regs->vid_screenpaint_timectl1);
+		val |= SCREENPAINT_TIMECTL1_ENABLE_VIDEO;
+		sbus_writel(val, &regs->vid_screenpaint_timectl1);
+		par->flags &= ~P9100_FLAG_BLANKED;
+		break;
+
+	case FB_BLANK_NORMAL: /* Normal blanking */
+	case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
+	case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
+	case FB_BLANK_POWERDOWN: /* Poweroff */
+		val = sbus_readl(&regs->vid_screenpaint_timectl1);
+		val &= ~SCREENPAINT_TIMECTL1_ENABLE_VIDEO;
+		sbus_writel(val, &regs->vid_screenpaint_timectl1);
+		par->flags |= P9100_FLAG_BLANKED;
+		break;
+	}
+
+	spin_unlock_irqrestore(&par->lock, flags);
+
+	return 0;
+}
+
+static struct sbus_mmap_map p9100_mmap_map[] = {
+	{ CG3_MMAP_OFFSET,	0,		SBUS_MMAP_FBSIZE(1) },
+	{ 0,			0,		0		    }
+};
+
+static int p9100_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+{
+	struct p9100_par *par = (struct p9100_par *)info->par;
+
+	return sbusfb_mmap_helper(p9100_mmap_map,
+				  par->physbase, par->fbsize,
+				  par->sdev->reg_addrs[0].which_io,
+				  vma);
+}
+
+static int p9100_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		       unsigned long arg, struct fb_info *info)
+{
+	struct p9100_par *par = (struct p9100_par *) info->par;
+
+	/* Make it look like a cg3. */
+	return sbusfb_ioctl_helper(cmd, arg, info,
+				   FBTYPE_SUN3COLOR, 8, par->fbsize);
+}
+
+/*
+ *  Initialisation
+ */
+
+static void
+p9100_init_fix(struct fb_info *info, int linebytes)
+{
+	struct p9100_par *par = (struct p9100_par *)info->par;
+
+	strlcpy(info->fix.id, par->sdev->prom_name, sizeof(info->fix.id));
+
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+
+	info->fix.line_length = linebytes;
+
+	info->fix.accel = FB_ACCEL_SUN_CGTHREE;
+}
+
+struct all_info {
+	struct fb_info info;
+	struct p9100_par par;
+	struct list_head list;
+};
+static LIST_HEAD(p9100_list);
+
+static void p9100_init_one(struct sbus_dev *sdev)
+{
+	struct all_info *all;
+	int linebytes;
+
+	all = kmalloc(sizeof(*all), GFP_KERNEL);
+	if (!all) {
+		printk(KERN_ERR "p9100: Cannot allocate memory.\n");
+		return;
+	}
+	memset(all, 0, sizeof(*all));
+
+	INIT_LIST_HEAD(&all->list);
+
+	spin_lock_init(&all->par.lock);
+	all->par.sdev = sdev;
+
+	/* This is the framebuffer and the only resource apps can mmap.  */
+	all->par.physbase = sdev->reg_addrs[2].phys_addr;
+
+	sbusfb_fill_var(&all->info.var, sdev->prom_node, 8);
+
+	linebytes = prom_getintdefault(sdev->prom_node, "linebytes",
+				       all->info.var.xres);
+	all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
+
+	all->par.regs = sbus_ioremap(&sdev->resource[0], 0,
+			     sizeof(struct p9100_regs), "p9100 regs");
+
+	all->info.flags = FBINFO_DEFAULT;
+	all->info.fbops = &p9100_ops;
+#ifdef CONFIG_SPARC32
+	all->info.screen_base = (char __iomem *)
+		prom_getintdefault(sdev->prom_node, "address", 0);
+#endif
+	if (!all->info.screen_base)
+		all->info.screen_base = sbus_ioremap(&sdev->resource[2], 0,
+				     all->par.fbsize, "p9100 ram");
+	all->info.par = &all->par;
+
+	p9100_blank(0, &all->info);
+
+	if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
+		printk(KERN_ERR "p9100: Could not allocate color map.\n");
+		kfree(all);
+		return;
+	}
+
+	p9100_init_fix(&all->info, linebytes);
+
+	if (register_framebuffer(&all->info) < 0) {
+		printk(KERN_ERR "p9100: Could not register framebuffer.\n");
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+		return;
+	}
+
+	list_add(&all->list, &p9100_list);
+
+	printk("p9100: %s at %lx:%lx\n",
+	       sdev->prom_name,
+	       (long) sdev->reg_addrs[0].which_io,
+	       (long) sdev->reg_addrs[0].phys_addr);
+}
+
+int __init p9100_init(void)
+{
+	struct sbus_bus *sbus;
+	struct sbus_dev *sdev;
+
+	if (fb_get_options("p9100fb", NULL))
+		return -ENODEV;
+
+	for_all_sbusdev(sdev, sbus) {
+		if (!strcmp(sdev->prom_name, "p9100"))
+			p9100_init_one(sdev);
+	}
+
+	return 0;
+}
+
+void __exit p9100_exit(void)
+{
+	struct list_head *pos, *tmp;
+
+	list_for_each_safe(pos, tmp, &p9100_list) {
+		struct all_info *all = list_entry(pos, typeof(*all), list);
+
+		unregister_framebuffer(&all->info);
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+	}
+}
+
+int __init
+p9100_setup(char *arg)
+{
+	/* No cmdline options yet... */
+	return 0;
+}
+
+module_init(p9100_init);
+
+#ifdef MODULE
+module_exit(p9100_exit);
+#endif
+
+MODULE_DESCRIPTION("framebuffer driver for P9100 chipsets");
+MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c
new file mode 100644
index 0000000..3dd1de1
--- /dev/null
+++ b/drivers/video/platinumfb.c
@@ -0,0 +1,693 @@
+/*
+ *  platinumfb.c -- frame buffer device for the PowerMac 'platinum' display
+ *
+ *  Copyright (C) 1998 Franz Sirl
+ *
+ *  Frame buffer structure from:
+ *    drivers/video/controlfb.c -- frame buffer device for
+ *    Apple 'control' display chip.
+ *    Copyright (C) 1998 Dan Jacobowitz
+ *
+ *  Hardware information from:
+ *    platinum.c: Console support for PowerMac "platinum" display adaptor.
+ *    Copyright (C) 1996 Paul Mackerras and Mark Abene
+ *
+ *  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 <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/nvram.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pgtable.h>
+#include <asm/of_device.h>
+
+#include "macmodes.h"
+#include "platinumfb.h"
+
+static int default_vmode = VMODE_NVRAM;
+static int default_cmode = CMODE_NVRAM;
+
+struct fb_info_platinum {
+	struct fb_info			*info;
+
+	int				vmode, cmode;
+	int				xres, yres;
+	int				vxres, vyres;
+	int				xoffset, yoffset;
+
+	struct {
+		__u8 red, green, blue;
+	}				palette[256];
+	u32				pseudo_palette[17];
+	
+	volatile struct cmap_regs	__iomem *cmap_regs;
+	unsigned long			cmap_regs_phys;
+	
+	volatile struct platinum_regs	__iomem *platinum_regs;
+	unsigned long			platinum_regs_phys;
+	
+	__u8				__iomem *frame_buffer;
+	volatile __u8			__iomem *base_frame_buffer;
+	unsigned long			frame_buffer_phys;
+	
+	unsigned long			total_vram;
+	int				clktype;
+	int				dactype;
+};
+
+/*
+ * Frame buffer device API
+ */
+
+static int platinumfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+	u_int transp, struct fb_info *info);
+static int platinumfb_blank(int blank_mode, struct fb_info *info);
+static int platinumfb_set_par (struct fb_info *info);
+static int platinumfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info);
+
+/*
+ * internal functions
+ */
+
+static inline int platinum_vram_reqd(int video_mode, int color_mode);
+static int read_platinum_sense(struct fb_info_platinum *pinfo);
+static void set_platinum_clock(struct fb_info_platinum *pinfo);
+static void platinum_set_hardware(struct fb_info_platinum *pinfo);
+static int platinum_var_to_par(struct fb_var_screeninfo *var,
+			       struct fb_info_platinum *pinfo,
+			       int check_only);
+
+/*
+ * Interface used by the world
+ */
+
+int platinumfb_init(void);
+int platinumfb_setup(char*);
+
+static struct fb_ops platinumfb_ops = {
+	.owner =	THIS_MODULE,
+	.fb_check_var	= platinumfb_check_var,
+	.fb_set_par	= platinumfb_set_par,
+	.fb_setcolreg	= platinumfb_setcolreg,
+	.fb_blank	= platinumfb_blank,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+/*
+ * Checks a var structure
+ */
+static int platinumfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	return platinum_var_to_par(var, info->par, 1);
+}
+
+/*
+ * Applies current var to display
+ */
+static int platinumfb_set_par (struct fb_info *info)
+{
+	struct fb_info_platinum *pinfo = info->par;
+	struct platinum_regvals *init;
+	int err, offset = 0x20;
+
+	if((err = platinum_var_to_par(&info->var, pinfo, 0))) {
+		printk (KERN_ERR "platinumfb_set_par: error calling"
+				 " platinum_var_to_par: %d.\n", err);
+		return err;
+	}
+
+	platinum_set_hardware(pinfo);
+
+	init = platinum_reg_init[pinfo->vmode-1];
+	
+	if (pinfo->vmode == 13 && pinfo->cmode > 0)
+		offset = 0x10;
+	info->screen_base = pinfo->frame_buffer + init->fb_offset + offset;
+	info->fix.smem_start = (pinfo->frame_buffer_phys) + init->fb_offset + offset;
+	info->fix.visual = (pinfo->cmode == CMODE_8) ?
+		FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
+	info->fix.line_length = vmode_attrs[pinfo->vmode-1].hres * (1<<pinfo->cmode) + offset;
+	printk("line_length: %x\n", info->fix.line_length);
+	return 0;
+}
+
+static int platinumfb_blank(int blank,  struct fb_info *fb)
+{
+/*
+ *  Blank the screen if blank_mode != 0, else unblank. If blank == NULL
+ *  then the caller blanks by setting the CLUT (Color Look Up Table) to all
+ *  black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
+ *  to e.g. a video mode which doesn't support it. Implements VESA suspend
+ *  and powerdown modes on hardware that supports disabling hsync/vsync:
+ *    blank_mode == 2: suspend vsync
+ *    blank_mode == 3: suspend hsync
+ *    blank_mode == 4: powerdown
+ */
+/* [danj] I think there's something fishy about those constants... */
+/*
+	struct fb_info_platinum *info = (struct fb_info_platinum *) fb;
+	int	ctrl;
+
+	ctrl = ld_le32(&info->platinum_regs->ctrl.r) | 0x33;
+	if (blank)
+		--blank_mode;
+	if (blank & VESA_VSYNC_SUSPEND)
+		ctrl &= ~3;
+	if (blank & VESA_HSYNC_SUSPEND)
+		ctrl &= ~0x30;
+	out_le32(&info->platinum_regs->ctrl.r, ctrl);
+*/
+/* TODO: Figure out how the heck to powerdown this thing! */
+	return 0;
+}
+
+static int platinumfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			      u_int transp, struct fb_info *info)
+{
+	struct fb_info_platinum *pinfo = info->par;
+	volatile struct cmap_regs __iomem *cmap_regs = pinfo->cmap_regs;
+
+	if (regno > 255)
+		return 1;
+
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	pinfo->palette[regno].red = red;
+	pinfo->palette[regno].green = green;
+	pinfo->palette[regno].blue = blue;
+
+	out_8(&cmap_regs->addr, regno);		/* tell clut what addr to fill	*/
+	out_8(&cmap_regs->lut, red);		/* send one color channel at	*/
+	out_8(&cmap_regs->lut, green);		/* a time...			*/
+	out_8(&cmap_regs->lut, blue);
+
+	if (regno < 16) {
+		int i;
+		u32 *pal = info->pseudo_palette;
+		switch (pinfo->cmode) {
+		case CMODE_16:
+			pal[regno] = (regno << 10) | (regno << 5) | regno;
+			break;
+		case CMODE_32:
+			i = (regno << 8) | regno;
+			pal[regno] = (i << 16) | i;
+			break;
+		}
+	}
+	
+	return 0;
+}
+
+static inline int platinum_vram_reqd(int video_mode, int color_mode)
+{
+	return vmode_attrs[video_mode-1].vres *
+	       (vmode_attrs[video_mode-1].hres * (1<<color_mode) + 0x20) +0x1000;
+}
+
+#define STORE_D2(a, d) { \
+	out_8(&cmap_regs->addr, (a+32)); \
+	out_8(&cmap_regs->d2, (d)); \
+}
+
+static void set_platinum_clock(struct fb_info_platinum *pinfo)
+{
+	volatile struct cmap_regs __iomem *cmap_regs = pinfo->cmap_regs;
+	struct platinum_regvals	*init;
+
+	init = platinum_reg_init[pinfo->vmode-1];
+
+	STORE_D2(6, 0xc6);
+	out_8(&cmap_regs->addr,3+32);
+
+	if (in_8(&cmap_regs->d2) == 2) {
+		STORE_D2(7, init->clock_params[pinfo->clktype][0]);
+		STORE_D2(8, init->clock_params[pinfo->clktype][1]);
+		STORE_D2(3, 3);
+	} else {
+		STORE_D2(4, init->clock_params[pinfo->clktype][0]);
+		STORE_D2(5, init->clock_params[pinfo->clktype][1]);
+		STORE_D2(3, 2);
+	}
+
+	__delay(5000);
+	STORE_D2(9, 0xa6);
+}
+
+
+/* Now how about actually saying, Make it so! */
+/* Some things in here probably don't need to be done each time. */
+static void platinum_set_hardware(struct fb_info_platinum *pinfo)
+{
+	volatile struct platinum_regs	__iomem *platinum_regs = pinfo->platinum_regs;
+	volatile struct cmap_regs	__iomem *cmap_regs = pinfo->cmap_regs;
+	struct platinum_regvals		*init;
+	int				i;
+	int				vmode, cmode;
+	
+	vmode = pinfo->vmode;
+	cmode = pinfo->cmode;
+
+	init = platinum_reg_init[vmode - 1];
+
+	/* Initialize display timing registers */
+	out_be32(&platinum_regs->reg[24].r, 7);	/* turn display off */
+
+	for (i = 0; i < 26; ++i)
+		out_be32(&platinum_regs->reg[i+32].r, init->regs[i]);
+
+	out_be32(&platinum_regs->reg[26+32].r, (pinfo->total_vram == 0x100000 ?
+						init->offset[cmode] + 4 - cmode :
+						init->offset[cmode]));
+	out_be32(&platinum_regs->reg[16].r, (unsigned) pinfo->frame_buffer_phys+init->fb_offset+0x10);
+	out_be32(&platinum_regs->reg[18].r, init->pitch[cmode]);
+	out_be32(&platinum_regs->reg[19].r, (pinfo->total_vram == 0x100000 ?
+					     init->mode[cmode+1] :
+					     init->mode[cmode]));
+	out_be32(&platinum_regs->reg[20].r, (pinfo->total_vram == 0x100000 ? 0x11 : 0x1011));
+	out_be32(&platinum_regs->reg[21].r, 0x100);
+	out_be32(&platinum_regs->reg[22].r, 1);
+	out_be32(&platinum_regs->reg[23].r, 1);
+	out_be32(&platinum_regs->reg[26].r, 0xc00);
+	out_be32(&platinum_regs->reg[27].r, 0x235);
+	/* out_be32(&platinum_regs->reg[27].r, 0x2aa); */
+
+	STORE_D2(0, (pinfo->total_vram == 0x100000 ?
+		     init->dacula_ctrl[cmode] & 0xf :
+		     init->dacula_ctrl[cmode]));
+	STORE_D2(1, 4);
+	STORE_D2(2, 0);
+
+	set_platinum_clock(pinfo);
+
+	out_be32(&platinum_regs->reg[24].r, 0);	/* turn display on */
+}
+
+/*
+ * Set misc info vars for this driver
+ */
+static void __devinit platinum_init_info(struct fb_info *info, struct fb_info_platinum *pinfo)
+{
+	/* Fill fb_info */
+	info->fbops = &platinumfb_ops;
+	info->pseudo_palette = pinfo->pseudo_palette;
+        info->flags = FBINFO_DEFAULT;
+	info->screen_base = pinfo->frame_buffer + 0x20;
+
+	fb_alloc_cmap(&info->cmap, 256, 0);
+
+	/* Fill fix common fields */
+	strcpy(info->fix.id, "platinum");
+	info->fix.mmio_start = pinfo->platinum_regs_phys;
+	info->fix.mmio_len = 0x1000;
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.smem_start = pinfo->frame_buffer_phys + 0x20; /* will be updated later */
+	info->fix.smem_len = pinfo->total_vram - 0x20;
+        info->fix.ywrapstep = 0;
+	info->fix.xpanstep = 0;
+	info->fix.ypanstep = 0;
+        info->fix.type_aux = 0;
+        info->fix.accel = FB_ACCEL_NONE;
+}
+
+
+static int __devinit platinum_init_fb(struct fb_info *info)
+{
+	struct fb_info_platinum *pinfo = info->par;
+	struct fb_var_screeninfo var;
+	int sense, rc;
+
+	sense = read_platinum_sense(pinfo);
+	printk(KERN_INFO "platinumfb: Monitor sense value = 0x%x, ", sense);
+
+	if (default_vmode == VMODE_NVRAM) {
+		default_vmode = nvram_read_byte(NV_VMODE);
+		if (default_vmode <= 0 || default_vmode > VMODE_MAX ||
+		    !platinum_reg_init[default_vmode-1])
+			default_vmode = VMODE_CHOOSE;
+	}
+	if (default_vmode == VMODE_CHOOSE) {
+		default_vmode = mac_map_monitor_sense(sense);
+	}
+	if (default_vmode <= 0 || default_vmode > VMODE_MAX)
+		default_vmode = VMODE_640_480_60;
+	if (default_cmode == CMODE_NVRAM)
+		default_cmode = nvram_read_byte(NV_CMODE);
+	if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
+		default_cmode = CMODE_8;
+	/*
+	 * Reduce the pixel size if we don't have enough VRAM.
+	 */
+	while(default_cmode > CMODE_8 &&
+	      platinum_vram_reqd(default_vmode, default_cmode) > pinfo->total_vram)
+		default_cmode--;
+
+	printk("platinumfb:  Using video mode %d and color mode %d.\n", default_vmode, default_cmode);
+
+	/* Setup default var */
+	if (mac_vmode_to_var(default_vmode, default_cmode, &var) < 0) {
+		/* This shouldn't happen! */
+		printk("mac_vmode_to_var(%d, %d,) failed\n", default_vmode, default_cmode);
+try_again:
+		default_vmode = VMODE_640_480_60;
+		default_cmode = CMODE_8;
+		if (mac_vmode_to_var(default_vmode, default_cmode, &var) < 0) {
+			printk(KERN_ERR "platinumfb: mac_vmode_to_var() failed\n");
+			return -ENXIO;
+		}
+	}
+
+	/* Initialize info structure */
+	platinum_init_info(info, pinfo);
+
+	/* Apply default var */
+	info->var = var;
+	var.activate = FB_ACTIVATE_NOW;
+	rc = fb_set_var(info, &var);
+	if (rc && (default_vmode != VMODE_640_480_60 || default_cmode != CMODE_8))
+		goto try_again;
+
+	/* Register with fbdev layer */
+	rc = register_framebuffer(info);
+	if (rc < 0)
+		return rc;
+
+	printk(KERN_INFO "fb%d: Apple Platinum frame buffer device\n", info->node);
+
+	return 0;
+}
+
+/*
+ * Get the monitor sense value.
+ * Note that this can be called before calibrate_delay,
+ * so we can't use udelay.
+ */
+static int read_platinum_sense(struct fb_info_platinum *info)
+{
+	volatile struct platinum_regs __iomem *platinum_regs = info->platinum_regs;
+	int sense;
+
+	out_be32(&platinum_regs->reg[23].r, 7);	/* turn off drivers */
+	__delay(2000);
+	sense = (~in_be32(&platinum_regs->reg[23].r) & 7) << 8;
+
+	/* drive each sense line low in turn and collect the other 2 */
+	out_be32(&platinum_regs->reg[23].r, 3);	/* drive A low */
+	__delay(2000);
+	sense |= (~in_be32(&platinum_regs->reg[23].r) & 3) << 4;
+	out_be32(&platinum_regs->reg[23].r, 5);	/* drive B low */
+	__delay(2000);
+	sense |= (~in_be32(&platinum_regs->reg[23].r) & 4) << 1;
+	sense |= (~in_be32(&platinum_regs->reg[23].r) & 1) << 2;
+	out_be32(&platinum_regs->reg[23].r, 6);	/* drive C low */
+	__delay(2000);
+	sense |= (~in_be32(&platinum_regs->reg[23].r) & 6) >> 1;
+
+	out_be32(&platinum_regs->reg[23].r, 7);	/* turn off drivers */
+
+	return sense;
+}
+
+/*
+ * This routine takes a user-supplied var, and picks the best vmode/cmode from it.
+ * It also updates the var structure to the actual mode data obtained
+ */
+static int platinum_var_to_par(struct fb_var_screeninfo *var, 
+			       struct fb_info_platinum *pinfo,
+			       int check_only)
+{
+	int vmode, cmode;
+
+	if (mac_var_to_vmode(var, &vmode, &cmode) != 0) {
+		printk(KERN_ERR "platinum_var_to_par: mac_var_to_vmode unsuccessful.\n");
+		printk(KERN_ERR "platinum_var_to_par: var->xres = %d\n", var->xres);
+		printk(KERN_ERR "platinum_var_to_par: var->yres = %d\n", var->yres);
+		printk(KERN_ERR "platinum_var_to_par: var->xres_virtual = %d\n", var->xres_virtual);
+		printk(KERN_ERR "platinum_var_to_par: var->yres_virtual = %d\n", var->yres_virtual);
+		printk(KERN_ERR "platinum_var_to_par: var->bits_per_pixel = %d\n", var->bits_per_pixel);
+		printk(KERN_ERR "platinum_var_to_par: var->pixclock = %d\n", var->pixclock);
+		printk(KERN_ERR "platinum_var_to_par: var->vmode = %d\n", var->vmode);
+		return -EINVAL;
+	}
+
+	if (!platinum_reg_init[vmode-1]) {
+		printk(KERN_ERR "platinum_var_to_par, vmode %d not valid.\n", vmode);
+		return -EINVAL;
+	}
+
+	if (platinum_vram_reqd(vmode, cmode) > pinfo->total_vram) {
+		printk(KERN_ERR "platinum_var_to_par, not enough ram for vmode %d, cmode %d.\n", vmode, cmode);
+		return -EINVAL;
+	}
+
+	if (mac_vmode_to_var(vmode, cmode, var))
+		return -EINVAL;
+
+	if (check_only)
+		return 0;
+
+	pinfo->vmode = vmode;
+	pinfo->cmode = cmode;
+	pinfo->xres = vmode_attrs[vmode-1].hres;
+	pinfo->yres = vmode_attrs[vmode-1].vres;
+	pinfo->xoffset = 0;
+	pinfo->yoffset = 0;
+	pinfo->vxres = pinfo->xres;
+	pinfo->vyres = pinfo->yres;
+	
+	return 0;
+}
+
+
+/* 
+ * Parse user speficied options (`video=platinumfb:')
+ */
+int __init platinumfb_setup(char *options)
+{
+	char *this_opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!strncmp(this_opt, "vmode:", 6)) {
+	    		int vmode = simple_strtoul(this_opt+6, NULL, 0);
+			if (vmode > 0 && vmode <= VMODE_MAX)
+				default_vmode = vmode;
+		} else if (!strncmp(this_opt, "cmode:", 6)) {
+			int depth = simple_strtoul(this_opt+6, NULL, 0);
+			switch (depth) {
+			 case 0:
+			 case 8:
+			    default_cmode = CMODE_8;
+			    break;
+			 case 15:
+			 case 16:
+			    default_cmode = CMODE_16;
+			    break;
+			 case 24:
+			 case 32:
+			    default_cmode = CMODE_32;
+			    break;
+			}
+		}
+	}
+	return 0;
+}
+
+#ifdef __powerpc__
+#define invalidate_cache(addr) \
+	asm volatile("eieio; dcbf 0,%1" \
+	: "=m" (*(addr)) : "r" (addr) : "memory");
+#else
+#define invalidate_cache(addr)
+#endif
+
+static int __devinit platinumfb_probe(struct of_device* odev, const struct of_match *match)
+{
+	struct device_node	*dp = odev->node;
+	struct fb_info		*info;
+	struct fb_info_platinum	*pinfo;
+	unsigned long		addr, size;
+	volatile __u8		*fbuffer;
+	int			i, bank0, bank1, bank2, bank3, rc;
+
+	if (dp->n_addrs != 2) {
+		printk(KERN_ERR "expecting 2 address for platinum (got %d)", dp->n_addrs);
+		return -ENXIO;
+	}
+	printk(KERN_INFO "platinumfb: Found Apple Platinum video hardware\n");
+
+	info = framebuffer_alloc(sizeof(*pinfo), &odev->dev);
+	if (info == NULL)
+		return -ENOMEM;
+	pinfo = info->par;
+
+	/* Map in frame buffer and registers */
+	for (i = 0; i < dp->n_addrs; ++i) {
+		addr = dp->addrs[i].address;
+		size = dp->addrs[i].size;
+		/* Let's assume we can request either all or nothing */
+		if (!request_mem_region(addr, size, "platinumfb")) {
+			framebuffer_release(info);
+			return -ENXIO;
+		}
+		if (size >= 0x400000) {
+			/* frame buffer - map only 4MB */
+			pinfo->frame_buffer_phys = addr;
+			pinfo->frame_buffer = __ioremap(addr, 0x400000, _PAGE_WRITETHRU);
+			pinfo->base_frame_buffer = pinfo->frame_buffer;
+		} else {
+			/* registers */
+			pinfo->platinum_regs_phys = addr;
+			pinfo->platinum_regs = ioremap(addr, size);
+		}
+	}
+
+	pinfo->cmap_regs_phys = 0xf301b000;	/* XXX not in prom? */
+	request_mem_region(pinfo->cmap_regs_phys, 0x1000, "platinumfb cmap");
+	pinfo->cmap_regs = ioremap(pinfo->cmap_regs_phys, 0x1000);
+
+	/* Grok total video ram */
+	out_be32(&pinfo->platinum_regs->reg[16].r, (unsigned)pinfo->frame_buffer_phys);
+	out_be32(&pinfo->platinum_regs->reg[20].r, 0x1011);	/* select max vram */
+	out_be32(&pinfo->platinum_regs->reg[24].r, 0);	/* switch in vram */
+
+	fbuffer = pinfo->base_frame_buffer;
+	fbuffer[0x100000] = 0x34;
+	fbuffer[0x100008] = 0x0;
+	invalidate_cache(&fbuffer[0x100000]);
+	fbuffer[0x200000] = 0x56;
+	fbuffer[0x200008] = 0x0;
+	invalidate_cache(&fbuffer[0x200000]);
+	fbuffer[0x300000] = 0x78;
+	fbuffer[0x300008] = 0x0;
+	invalidate_cache(&fbuffer[0x300000]);
+	bank0 = 1; /* builtin 1MB vram, always there */
+	bank1 = fbuffer[0x100000] == 0x34;
+	bank2 = fbuffer[0x200000] == 0x56;
+	bank3 = fbuffer[0x300000] == 0x78;
+	pinfo->total_vram = (bank0 + bank1 + bank2 + bank3) * 0x100000;
+	printk(KERN_INFO "platinumfb: Total VRAM = %dMB (%d%d%d%d)\n", (int) (pinfo->total_vram / 1024 / 1024),
+	       bank3, bank2, bank1, bank0);
+
+	/*
+	 * Try to determine whether we have an old or a new DACula.
+	 */
+	out_8(&pinfo->cmap_regs->addr, 0x40);
+	pinfo->dactype = in_8(&pinfo->cmap_regs->d2);
+	switch (pinfo->dactype) {
+	case 0x3c:
+		pinfo->clktype = 1;
+		printk(KERN_INFO "platinumfb: DACula type 0x3c\n");
+		break;
+	case 0x84:
+		pinfo->clktype = 0;
+		printk(KERN_INFO "platinumfb: DACula type 0x84\n");
+		break;
+	default:
+		pinfo->clktype = 0;
+		printk(KERN_INFO "platinumfb: Unknown DACula type: %x\n", pinfo->dactype);
+		break;
+	}
+	dev_set_drvdata(&odev->dev, info);
+	
+	rc = platinum_init_fb(info);
+	if (rc != 0) {
+		dev_set_drvdata(&odev->dev, NULL);
+		framebuffer_release(info);
+	}
+
+	return rc;
+}
+
+static int __devexit platinumfb_remove(struct of_device* odev)
+{
+	struct fb_info		*info = dev_get_drvdata(&odev->dev);
+	struct fb_info_platinum	*pinfo = info->par;
+	struct device_node *dp = odev->node;
+	unsigned long addr, size;
+	int i;
+	
+        unregister_framebuffer (info);
+	
+	/* Unmap frame buffer and registers */
+	for (i = 0; i < dp->n_addrs; ++i) {
+		addr = dp->addrs[i].address;
+		size = dp->addrs[i].size;
+		release_mem_region(addr, size);
+	}
+	iounmap(pinfo->frame_buffer);
+	iounmap(pinfo->platinum_regs);
+	release_mem_region(pinfo->cmap_regs_phys, 0x1000);
+	iounmap(pinfo->cmap_regs);
+
+	framebuffer_release(info);
+
+	return 0;
+}
+
+static struct of_match platinumfb_match[] = 
+{
+	{
+	.name 		= "platinum",
+	.type		= OF_ANY_MATCH,
+	.compatible	= OF_ANY_MATCH,
+	},
+	{},
+};
+
+static struct of_platform_driver platinum_driver = 
+{
+	.name 		= "platinumfb",
+	.match_table	= platinumfb_match,
+	.probe		= platinumfb_probe,
+	.remove		= platinumfb_remove,
+};
+
+int __init platinumfb_init(void)
+{
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("platinumfb", &option))
+		return -ENODEV;
+	platinumfb_setup(option);
+#endif
+	of_register_driver(&platinum_driver);
+
+	return 0;
+}
+
+void __exit platinumfb_exit(void)
+{
+	of_unregister_driver(&platinum_driver);	
+}
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("framebuffer driver for Apple Platinum video");
+module_init(platinumfb_init);
+
+#ifdef MODULE
+module_exit(platinumfb_exit);
+#endif
diff --git a/drivers/video/platinumfb.h b/drivers/video/platinumfb.h
new file mode 100644
index 0000000..2834fc1
--- /dev/null
+++ b/drivers/video/platinumfb.h
@@ -0,0 +1,366 @@
+/*
+ * linux/drivers/video/platinumfb-hw.c -- Frame buffer device for the
+ * Platinum on-board video in PowerMac 7200s (and some clones based
+ * on the same motherboard.)
+ *
+ *  Created 09 Feb 1998 by Jon Howell <jonh@cs.dartmouth.edu>
+ *
+ * Copyright (C) 1998 Jon Howell
+ *
+ *  based on drivers/macintosh/platinum.c: Console support
+ * 	for PowerMac "platinum" display adaptor.
+ *  Copyright (C) 1996 Paul Mackerras and Mark Abene.
+ *
+ *  based on skeletonfb.c:
+ *  Created 28 Dec 1997 by Geert Uytterhoeven
+ *
+ * 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.
+ */
+
+/*
+ * Structure of the registers for the DACula colormap device.
+ */
+struct cmap_regs {
+	unsigned char addr;
+	char pad1[15];
+	unsigned char d1;
+	char pad2[15];
+	unsigned char d2;
+	char pad3[15];
+	unsigned char lut;
+	char pad4[15];
+};
+
+/*
+ * Structure of the registers for the "platinum" display adaptor".
+ */
+struct preg {			/* padded register */
+	unsigned r;			/* notice this is 32 bits. */
+	char pad[12];
+};
+
+struct platinum_regs {
+	struct preg reg[128];
+};
+
+/*
+ * Register initialization tables for the platinum display.
+ *
+ * It seems that there are two different types of platinum display
+ * out there.  Older ones use the values in clocksel[1], for which
+ * the formula for the clock frequency seems to be
+ *	F = 14.3MHz * c0 / (c1 & 0x1f) / (1 << (c1 >> 5))
+ * Newer ones use the values in clocksel[0], for which the formula
+ * seems to be
+ *	F = 15MHz * c0 / ((c1 & 0x1f) + 2) / (1 << (c1 >> 5))
+ */
+struct platinum_regvals {
+	int	fb_offset;
+	int	pitch[3];
+	unsigned regs[26];
+	unsigned char offset[3];
+	unsigned char mode[3];
+	unsigned char dacula_ctrl[3];
+	unsigned char clock_params[2][2];
+};
+
+#define DIV2	0x20
+#define DIV4	0x40
+#define DIV8	0x60
+#define DIV16	0x80
+
+/* 1280x1024, 75Hz (20) */
+static struct platinum_regvals platinum_reg_init_20 = {
+	0x5c00,
+	{ 1312, 2592, 2592 },
+	{ 0xffc, 4, 0, 0, 0, 0, 0x428, 0,
+	  0, 0xb3, 0xd3, 0x12, 0x1a5, 0x23, 0x28, 0x2d,
+	  0x5e, 0x19e, 0x1a4, 0x854, 0x852, 4, 9, 0x50,
+	  0x850, 0x851 }, { 0x58, 0x5d, 0x5d },
+	{ 0, 0xff, 0xff }, { 0x51, 0x55, 0x55 },
+	{{ 45, 3 }, { 66, 7 }}
+};
+
+/* 1280x960, 75Hz (19) */
+static struct platinum_regvals platinum_reg_init_19 = {
+	0x5c00,
+	{ 1312, 2592, 2592 },
+	{ 0xffc, 4, 0, 0, 0, 0, 0x428, 0,
+	  0, 0xb2, 0xd2, 0x12, 0x1a3, 0x23, 0x28, 0x2d,
+	  0x5c, 0x19c, 0x1a2, 0x7d0, 0x7ce, 4, 9, 0x4c,
+	  0x7cc, 0x7cd }, { 0x56, 0x5b, 0x5b },
+	{ 0, 0xff, 0xff }, { 0x51, 0x55, 0x55 },
+	{{ 42, 3 }, { 44, 5 }}
+};
+
+/* 1152x870, 75Hz (18) */
+static struct platinum_regvals platinum_reg_init_18 = {
+	0x11b0,
+	{ 1184, 2336, 4640 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x38f, 0,
+	  0, 0x294, 0x16c, 0x20, 0x2d7, 0x3f, 0x49, 0x53,
+	  0x82, 0x2c2, 0x2d6, 0x726, 0x724, 4, 9, 0x52,
+	  0x71e, 0x722 }, { 0x74, 0x7c, 0x81 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 26, 0 + DIV2 }, { 42, 6 }}
+};
+
+/* 1024x768, 75Hz (17) */
+static struct platinum_regvals platinum_reg_init_17 = {
+	0x10b0,
+	{ 1056, 2080, 4128 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x254, 0x14b, 0x18, 0x295, 0x2f, 0x32, 0x3b,
+	  0x80, 0x280, 0x296, 0x648, 0x646, 4, 9, 0x40,
+	  0x640, 0x644 }, { 0x72, 0x7a, 0x7f },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 54, 3 + DIV2 }, { 67, 12 }}
+};
+
+/* 1024x768, 75Hz (16) */
+static struct platinum_regvals platinum_reg_init_16 = {
+	0x10b0,
+	{ 1056, 2080, 4128 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x250, 0x147, 0x17, 0x28f, 0x2f, 0x35, 0x47,
+	  0x82, 0x282, 0x28e, 0x640, 0x63e, 4, 9, 0x3c,
+	  0x63c, 0x63d }, { 0x74, 0x7c, 0x81 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 20, 0 + DIV2 }, { 11, 2 }}
+};
+
+/* 1024x768, 70Hz (15) */
+static struct platinum_regvals platinum_reg_init_15 = {
+	0x10b0,
+	{ 1056, 2080, 4128 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x254, 0x14b, 0x22, 0x297, 0x43, 0x49, 0x5b,
+	  0x86, 0x286, 0x296, 0x64c, 0x64a, 0xa, 0xf, 0x44,
+	  0x644, 0x646 }, { 0x78, 0x80, 0x85 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 19, 0 + DIV2 }, { 110, 21 }}
+};
+
+/* 1024x768, 60Hz (14) */
+static struct platinum_regvals platinum_reg_init_14 = {
+	0x10b0,
+	{ 1056, 2080, 4128 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x25a, 0x14f, 0x22, 0x29f, 0x43, 0x49, 0x5b,
+	  0x8e, 0x28e, 0x29e, 0x64c, 0x64a, 0xa, 0xf, 0x44,
+	  0x644, 0x646 }, { 0x80, 0x88, 0x8d },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 71, 6 + DIV2 }, { 118, 13 + DIV2 }}
+};
+
+/* 832x624, 75Hz (13) */
+static struct platinum_regvals platinum_reg_init_13 = {
+	0x70,
+	{ 864, 1680, 3360 },	/* MacOS does 1680 instead of 1696 to fit 16bpp in 1MB */
+	{ 0xff0, 4, 0, 0, 0, 0, 0x299, 0,
+	  0, 0x21e, 0x120, 0x10, 0x23f, 0x1f, 0x25, 0x37,
+	  0x8a, 0x22a, 0x23e, 0x536, 0x534, 4, 9, 0x52,
+	  0x532, 0x533 }, { 0x7c, 0x84, 0x89 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 30, 0 + DIV4 }, { 56, 7 + DIV2 }}
+};
+
+/* 800x600, 75Hz (12) */
+static struct platinum_regvals platinum_reg_init_12 = {
+	0x1010,
+	{ 832, 1632, 3232 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x1ce, 0x108, 0x14, 0x20f, 0x27, 0x30, 0x39,
+	  0x72, 0x202, 0x20e, 0x4e2, 0x4e0, 4, 9, 0x2e,
+	  0x4de, 0x4df }, { 0x64, 0x6c, 0x71 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 122, 7 + DIV4 }, { 62, 9 + DIV2 }}
+};
+
+/* 800x600, 72Hz (11) */
+static struct platinum_regvals platinum_reg_init_11 = {
+	0x1010,
+	{ 832, 1632, 3232 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x1ca, 0x104, 0x1e, 0x207, 0x3b, 0x44, 0x4d,
+	  0x56, 0x1e6, 0x206, 0x534, 0x532, 0xa, 0xe, 0x38,
+	  0x4e8, 0x4ec }, { 0x48, 0x50, 0x55 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 26, 0 + DIV4 }, { 42, 6 + DIV2 }}
+};
+
+/* 800x600, 60Hz (10) */
+static struct platinum_regvals platinum_reg_init_10 = {
+	0x1010,
+	{ 832, 1632, 3232 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x1ce, 0x108, 0x20, 0x20f, 0x3f, 0x45, 0x5d,
+	  0x66, 0x1f6, 0x20e, 0x4e8, 0x4e6, 6, 0xa, 0x34,
+	  0x4e4, 0x4e5 }, { 0x58, 0x60, 0x65 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 54, 3 + DIV4 }, { 95, 1 + DIV8 }}
+};
+
+/* 800x600, 56Hz (9) --unsupported? copy of mode 10 for now... */
+static struct platinum_regvals platinum_reg_init_9 = {
+	0x1010,
+	{ 832, 1632, 3232 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x1ce, 0x108, 0x20, 0x20f, 0x3f, 0x45, 0x5d,
+	  0x66, 0x1f6, 0x20e, 0x4e8, 0x4e6, 6, 0xa, 0x34,
+	  0x4e4, 0x4e5 }, { 0x58, 0x60, 0x65 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 54, 3 + DIV4 }, { 88, 1 + DIV8 }}
+};
+
+/* 768x576, 50Hz Interlaced-PAL (8) */
+static struct platinum_regvals platinum_reg_init_8 = {
+	0x1010,
+	{ 800, 1568, 3104 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0xc8, 0xec, 0x11, 0x1d7, 0x22, 0x25, 0x36,
+	  0x47, 0x1c7, 0x1d6, 0x271, 0x270, 4, 9, 0x27,
+	  0x267, 0x26b }, { 0x39, 0x41, 0x46 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 31, 0 + DIV16 }, { 74, 9 + DIV8 }}
+};
+
+/* 640x870, 75Hz Portrait (7) */
+static struct platinum_regvals platinum_reg_init_7 = {
+	0xb10,
+	{ 672, 1312, 2592 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x176, 0xd0, 0x14, 0x19f, 0x27, 0x2d, 0x3f,
+	  0x4a, 0x18a, 0x19e, 0x72c, 0x72a, 4, 9, 0x58,
+	  0x724, 0x72a }, { 0x3c, 0x44, 0x49 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 30, 0 + DIV4 }, { 56, 7 + DIV2 }}
+};
+
+/* 640x480, 67Hz (6) */
+static struct platinum_regvals platinum_reg_init_6 = {
+	0x1010,
+	{ 672, 1312, 2592 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x209, 0,
+	  0, 0x18e, 0xd8, 0x10, 0x1af, 0x1f, 0x25, 0x37,
+	  0x4a, 0x18a, 0x1ae, 0x41a, 0x418, 4, 9, 0x52,
+	  0x412, 0x416 }, { 0x3c, 0x44, 0x49 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 99, 4 + DIV8 }, { 42, 5 + DIV4 }}
+};
+
+/* 640x480, 60Hz (5) */
+static struct platinum_regvals platinum_reg_init_5 = {
+	0x1010,
+	{ 672, 1312, 2592 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x15e, 0xc8, 0x18, 0x18f, 0x2f, 0x35, 0x3e,
+	  0x42, 0x182, 0x18e, 0x41a, 0x418, 2, 7, 0x44,
+	  0x404, 0x408 }, { 0x34, 0x3c, 0x41 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 26, 0 + DIV8 }, { 14, 2 + DIV4 }}
+};
+
+/* 640x480, 60Hz Interlaced-NTSC (4) */
+static struct platinum_regvals platinum_reg_init_4 = {
+	0x1010,
+	{ 672, 1312, 2592 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0xa5, 0xc3, 0xe, 0x185, 0x1c, 0x1f, 0x30,
+	  0x37, 0x177, 0x184, 0x20d, 0x20c, 5, 0xb, 0x23,
+	  0x203, 0x206 }, { 0x29, 0x31, 0x36 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 94, 5 + DIV16 }, { 48, 7 + DIV8 }}
+};
+
+/* 640x480, 50Hz Interlaced-PAL (3) */
+static struct platinum_regvals platinum_reg_init_3 = {
+	0x1010,
+	{ 672, 1312, 2592 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0xc8, 0xec, 0x11, 0x1d7, 0x22, 0x25, 0x36,
+	  0x67, 0x1a7, 0x1d6, 0x271, 0x270, 4, 9, 0x57,
+	  0x237, 0x26b }, { 0x59, 0x61, 0x66 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 31, 0 + DIV16 }, { 74, 9 + DIV8 }}
+};
+
+/* 512x384, 60Hz (2) */
+static struct platinum_regvals platinum_reg_init_2 = {
+	0x1010,
+	{ 544, 1056, 2080 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x25c, 0x140, 0x10, 0x27f, 0x1f, 0x2b, 0x4f,
+	  0x68, 0x268, 0x27e, 0x32e, 0x32c, 4, 9, 0x2a,
+	  0x32a, 0x32b }, { 0x5a, 0x62, 0x67 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 33, 2 + DIV8 }, { 79, 9 + DIV8 }}
+};
+
+/* 512x384, 60Hz Interlaced-NTSC (1) */
+static struct platinum_regvals platinum_reg_init_1 = {
+	0x1010,
+	{ 544, 1056, 2080 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0xa5, 0xc3, 0xe, 0x185, 0x1c, 0x1f, 0x30,
+	  0x57, 0x157, 0x184, 0x20d, 0x20c, 5, 0xb, 0x53,
+	  0x1d3, 0x206 }, { 0x49, 0x51, 0x56 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 94, 5 + DIV16 }, { 48, 7 + DIV8 }}
+};
+
+static struct platinum_regvals *platinum_reg_init[VMODE_MAX] = {
+	&platinum_reg_init_1,
+	&platinum_reg_init_2,
+	&platinum_reg_init_3,
+	&platinum_reg_init_4,
+	&platinum_reg_init_5,
+	&platinum_reg_init_6,
+	&platinum_reg_init_7,
+	&platinum_reg_init_8,
+	&platinum_reg_init_9,
+	&platinum_reg_init_10,
+	&platinum_reg_init_11,
+	&platinum_reg_init_12,
+	&platinum_reg_init_13,
+	&platinum_reg_init_14,
+	&platinum_reg_init_15,
+	&platinum_reg_init_16,
+	&platinum_reg_init_17,
+	&platinum_reg_init_18,
+	&platinum_reg_init_19,
+	&platinum_reg_init_20
+};
+
+struct vmode_attr {
+	int hres;
+	int vres;
+	int vfreq;
+	int interlaced;
+};
+
+struct vmode_attr vmode_attrs[VMODE_MAX] = {
+	{512, 384, 60, 1},
+	{512, 384, 60},
+	{640, 480, 50, 1},
+	{640, 480, 60, 1},
+	{640, 480, 60},
+	{640, 480, 67},
+	{640, 870, 75},
+	{768, 576, 50, 1},
+	{800, 600, 56},
+	{800, 600, 60},
+	{800, 600, 72},
+	{800, 600, 75},
+	{832, 624, 75},
+	{1024, 768, 60},
+	{1024, 768, 72},
+	{1024, 768, 75},
+	{1024, 768, 75},
+	{1152, 870, 75},
+	{1280, 960, 75},
+	{1280, 1024, 75}
+};
+
diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c
new file mode 100644
index 0000000..5dcedde
--- /dev/null
+++ b/drivers/video/pm2fb.c
@@ -0,0 +1,1314 @@
+/*
+ * Permedia2 framebuffer driver.
+ *
+ * 2.5/2.6 driver:
+ * Copyright (c) 2003 Jim Hague (jim.hague@acm.org)
+ *
+ * based on 2.4 driver:
+ * Copyright (c) 1998-2000 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
+ * Copyright (c) 1999 Jakub Jelinek (jakub@redhat.com)
+ *
+ * and additional input from James Simmon's port of Hannu Mallat's tdfx
+ * driver.
+ *
+ * I have a Creative Graphics Blaster Exxtreme card - pm2fb on x86.  I
+ * have no access to other pm2fb implementations. Sparc (and thus
+ * hopefully other big-endian) devices now work, thanks to a lot of
+ * testing work by Ron Murray. I have no access to CVision hardware,
+ * and therefore for now I am omitting the CVision code.
+ *
+ * Multiple boards support has been on the TODO list for ages.
+ * Don't expect this to change.
+ *
+ * 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/moduleparam.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/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <video/permedia2.h>
+#include <video/cvisionppc.h>
+
+#if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)
+#error	"The endianness of the target host has not been defined."
+#endif
+
+#if !defined(CONFIG_PCI)
+#error "Only generic PCI cards supported."
+#endif
+
+#undef PM2FB_MASTER_DEBUG
+#ifdef PM2FB_MASTER_DEBUG
+#define DPRINTK(a,b...)	printk(KERN_DEBUG "pm2fb: %s: " a, __FUNCTION__ , ## b)
+#else
+#define DPRINTK(a,b...)
+#endif
+
+/*
+ * Driver data 
+ */
+static char *mode __devinitdata = NULL;
+
+/*
+ * The XFree GLINT driver will (I think to implement hardware cursor
+ * support on TVP4010 and similar where there is no RAMDAC - see
+ * comment in set_video) always request +ve sync regardless of what
+ * the mode requires. This screws me because I have a Sun
+ * fixed-frequency monitor which absolutely has to have -ve sync. So
+ * these flags allow the user to specify that requests for +ve sync
+ * should be silently turned in -ve sync.
+ */
+static int lowhsync __devinitdata = 0;
+static int lowvsync __devinitdata = 0;
+
+/*
+ * The hardware state of the graphics card that isn't part of the
+ * screeninfo.
+ */
+struct pm2fb_par
+{
+	pm2type_t	type;		/* Board type */
+	u32		fb_size;	/* framebuffer memory size */
+	unsigned char	__iomem *v_fb;  /* virtual address of frame buffer */
+	unsigned char	__iomem *v_regs;/* virtual address of p_regs */
+	u32 	   	memclock;	/* memclock */
+	u32		video;		/* video flags before blanking */
+	u32		mem_config;	/* MemConfig reg at probe */
+	u32		mem_control;	/* MemControl reg at probe */
+	u32		boot_address;	/* BootAddress reg at probe */
+};
+
+/*
+ * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo
+ * if we don't use modedb.
+ */
+static struct fb_fix_screeninfo pm2fb_fix __devinitdata = {
+	.id =		"", 
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_PSEUDOCOLOR,
+	.xpanstep =	1,
+	.ypanstep =	1,
+	.ywrapstep =	0, 
+	.accel =	FB_ACCEL_NONE,
+};
+
+/*
+ * Default video mode. In case the modedb doesn't work.
+ */
+static struct fb_var_screeninfo pm2fb_var __devinitdata = {
+	/* "640x480, 8 bpp @ 60 Hz */
+	.xres =		640,
+	.yres =		480,
+	.xres_virtual =	640,
+	.yres_virtual =	480,
+	.bits_per_pixel =8,
+	.red =		{0, 8, 0},
+	.blue =		{0, 8, 0},
+	.green =	{0, 8, 0},
+	.activate =	FB_ACTIVATE_NOW,
+	.height =	-1,
+	.width =	-1,
+	.accel_flags =	0,
+	.pixclock =	39721,
+	.left_margin =	40,
+	.right_margin =	24,
+	.upper_margin =	32,
+	.lower_margin =	11,
+	.hsync_len =	96,
+	.vsync_len =	2,
+	.vmode =	FB_VMODE_NONINTERLACED
+};
+
+/*
+ * Utility functions
+ */
+
+inline static u32 RD32(unsigned char __iomem *base, s32 off)
+{
+	return fb_readl(base + off);
+}
+
+inline static void WR32(unsigned char __iomem *base, s32 off, u32 v)
+{
+	fb_writel(v, base + off);
+}
+
+inline static u32 pm2_RD(struct pm2fb_par* p, s32 off)
+{
+	return RD32(p->v_regs, off);
+}
+
+inline static void pm2_WR(struct pm2fb_par* p, s32 off, u32 v)
+{
+	WR32(p->v_regs, off, v);
+}
+
+inline static u32 pm2_RDAC_RD(struct pm2fb_par* p, s32 idx)
+{
+	int index = PM2R_RD_INDEXED_DATA;
+	switch (p->type) {
+	case PM2_TYPE_PERMEDIA2:
+		pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
+		break;
+	case PM2_TYPE_PERMEDIA2V:
+		pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
+		index = PM2VR_RD_INDEXED_DATA;
+		break;
+	}	
+	mb();
+	return pm2_RD(p, index);
+}
+
+inline static void pm2_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v)
+{
+	int index = PM2R_RD_INDEXED_DATA;
+	switch (p->type) {
+	case PM2_TYPE_PERMEDIA2:
+		pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
+		break;
+	case PM2_TYPE_PERMEDIA2V:
+		pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
+		index = PM2VR_RD_INDEXED_DATA;
+		break;
+	}	
+	mb();
+	pm2_WR(p, index, v);
+}
+
+inline static void pm2v_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v)
+{
+	pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
+	mb();
+	pm2_WR(p, PM2VR_RD_INDEXED_DATA, v);
+}
+
+#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
+#define WAIT_FIFO(p,a)
+#else
+inline static void WAIT_FIFO(struct pm2fb_par* p, u32 a)
+{
+	while( pm2_RD(p, PM2R_IN_FIFO_SPACE) < a );
+	mb();
+}
+#endif
+
+/*
+ * partial products for the supported horizontal resolutions.
+ */
+#define PACKPP(p0,p1,p2)	(((p2) << 6) | ((p1) << 3) | (p0))
+static const struct {
+	u16 width;
+	u16 pp;
+} pp_table[] = {
+	{ 32,	PACKPP(1, 0, 0) }, { 64,	PACKPP(1, 1, 0) },
+	{ 96,	PACKPP(1, 1, 1) }, { 128,	PACKPP(2, 1, 1) },
+	{ 160,	PACKPP(2, 2, 1) }, { 192,	PACKPP(2, 2, 2) },
+	{ 224,	PACKPP(3, 2, 1) }, { 256,	PACKPP(3, 2, 2) },
+	{ 288,	PACKPP(3, 3, 1) }, { 320,	PACKPP(3, 3, 2) },
+	{ 384,	PACKPP(3, 3, 3) }, { 416,	PACKPP(4, 3, 1) },
+	{ 448,	PACKPP(4, 3, 2) }, { 512,	PACKPP(4, 3, 3) },
+	{ 544,	PACKPP(4, 4, 1) }, { 576,	PACKPP(4, 4, 2) },
+	{ 640,	PACKPP(4, 4, 3) }, { 768,	PACKPP(4, 4, 4) },
+	{ 800,	PACKPP(5, 4, 1) }, { 832,	PACKPP(5, 4, 2) },
+	{ 896,	PACKPP(5, 4, 3) }, { 1024,	PACKPP(5, 4, 4) },
+	{ 1056,	PACKPP(5, 5, 1) }, { 1088,	PACKPP(5, 5, 2) },
+	{ 1152,	PACKPP(5, 5, 3) }, { 1280,	PACKPP(5, 5, 4) },
+	{ 1536,	PACKPP(5, 5, 5) }, { 1568,	PACKPP(6, 5, 1) },
+	{ 1600,	PACKPP(6, 5, 2) }, { 1664,	PACKPP(6, 5, 3) },
+	{ 1792,	PACKPP(6, 5, 4) }, { 2048,	PACKPP(6, 5, 5) },
+	{ 0,	0 } };
+
+static u32 partprod(u32 xres)
+{
+	int i;
+
+	for (i = 0; pp_table[i].width && pp_table[i].width != xres; i++)
+		;
+	if ( pp_table[i].width == 0 )
+		DPRINTK("invalid width %u\n", xres);
+	return pp_table[i].pp;
+}
+
+static u32 to3264(u32 timing, int bpp, int is64)
+{
+	switch (bpp) {
+	case 8:
+		timing >>= 2 + is64;
+		break;
+	case 16:
+		timing >>= 1 + is64;
+		break;
+	case 24:
+		timing = (timing * 3) >> (2 + is64);
+		break;
+	case 32:
+		if (is64)
+			timing >>= 1;
+		break;
+	}
+	return timing;
+}
+
+static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
+		    unsigned char* pp)
+{
+	unsigned char m;
+	unsigned char n;
+	unsigned char p;
+	u32 f;
+	s32 curr;
+	s32 delta = 100000;
+
+	*mm = *nn = *pp = 0;
+	for (n = 2; n < 15; n++) {
+		for (m = 2; m; m++) {
+			f = PM2_REFERENCE_CLOCK * m / n;
+			if (f >= 150000 && f <= 300000) {
+				for ( p = 0; p < 5; p++, f >>= 1) {
+					curr = ( clk > f ) ? clk - f : f - clk;
+					if ( curr < delta ) {
+						delta=curr;
+						*mm=m;
+						*nn=n;
+						*pp=p;
+					}
+				}
+			}
+		}
+	}
+}
+
+static void pm2v_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
+		     unsigned char* pp)
+{
+	unsigned char m;
+	unsigned char n;
+	unsigned char p;
+	u32 f;
+	s32 delta = 1000;
+
+	*mm = *nn = *pp = 0;
+	for (n = 1; n; n++) {
+		for ( m = 1; m; m++) {
+			for ( p = 0; p < 2; p++) {
+				f = PM2_REFERENCE_CLOCK * n / (m * (1 << (p + 1)));
+				if ( clk > f - delta && clk < f + delta ) {
+					delta = ( clk > f ) ? clk - f : f - clk;
+					*mm=m;
+					*nn=n;
+					*pp=p;
+				}
+			}
+		}
+	}
+}
+
+static void clear_palette(struct pm2fb_par* p) {
+	int i=256;
+
+	WAIT_FIFO(p, 1);
+	pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, 0);
+	wmb();
+	while (i--) {
+		WAIT_FIFO(p, 3);
+		pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
+		pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
+		pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
+	}
+}
+
+static void reset_card(struct pm2fb_par* p)
+{
+	if (p->type == PM2_TYPE_PERMEDIA2V)
+		pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0);
+	pm2_WR(p, PM2R_RESET_STATUS, 0);
+	mb();
+	while (pm2_RD(p, PM2R_RESET_STATUS) & PM2F_BEING_RESET)
+		;
+	mb();
+#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
+	DPRINTK("FIFO disconnect enabled\n");
+	pm2_WR(p, PM2R_FIFO_DISCON, 1);
+	mb();
+#endif
+
+	/* Restore stashed memory config information from probe */
+	WAIT_FIFO(p, 3);
+	pm2_WR(p, PM2R_MEM_CONTROL, p->mem_control);
+	pm2_WR(p, PM2R_BOOT_ADDRESS, p->boot_address);
+	wmb();
+	pm2_WR(p, PM2R_MEM_CONFIG, p->mem_config);
+}
+
+static void reset_config(struct pm2fb_par* p)
+{
+	WAIT_FIFO(p, 52);
+	pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG)&
+	       ~(PM2F_VGA_ENABLE|PM2F_VGA_FIXED));
+	pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L));
+	pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L));
+	pm2_WR(p, PM2R_FIFO_CONTROL, 0);
+	pm2_WR(p, PM2R_APERTURE_ONE, 0);
+	pm2_WR(p, PM2R_APERTURE_TWO, 0);
+	pm2_WR(p, PM2R_RASTERIZER_MODE, 0);
+	pm2_WR(p, PM2R_DELTA_MODE, PM2F_DELTA_ORDER_RGB);
+	pm2_WR(p, PM2R_LB_READ_FORMAT, 0);
+	pm2_WR(p, PM2R_LB_WRITE_FORMAT, 0); 
+	pm2_WR(p, PM2R_LB_READ_MODE, 0);
+	pm2_WR(p, PM2R_LB_SOURCE_OFFSET, 0);
+	pm2_WR(p, PM2R_FB_SOURCE_OFFSET, 0);
+	pm2_WR(p, PM2R_FB_PIXEL_OFFSET, 0);
+	pm2_WR(p, PM2R_FB_WINDOW_BASE, 0);
+	pm2_WR(p, PM2R_LB_WINDOW_BASE, 0);
+	pm2_WR(p, PM2R_FB_SOFT_WRITE_MASK, ~(0L));
+	pm2_WR(p, PM2R_FB_HARD_WRITE_MASK, ~(0L));
+	pm2_WR(p, PM2R_FB_READ_PIXEL, 0);
+	pm2_WR(p, PM2R_DITHER_MODE, 0);
+	pm2_WR(p, PM2R_AREA_STIPPLE_MODE, 0);
+	pm2_WR(p, PM2R_DEPTH_MODE, 0);
+	pm2_WR(p, PM2R_STENCIL_MODE, 0);
+	pm2_WR(p, PM2R_TEXTURE_ADDRESS_MODE, 0);
+	pm2_WR(p, PM2R_TEXTURE_READ_MODE, 0);
+	pm2_WR(p, PM2R_TEXEL_LUT_MODE, 0);
+	pm2_WR(p, PM2R_YUV_MODE, 0);
+	pm2_WR(p, PM2R_COLOR_DDA_MODE, 0);
+	pm2_WR(p, PM2R_TEXTURE_COLOR_MODE, 0);
+	pm2_WR(p, PM2R_FOG_MODE, 0);
+	pm2_WR(p, PM2R_ALPHA_BLEND_MODE, 0);
+	pm2_WR(p, PM2R_LOGICAL_OP_MODE, 0);
+	pm2_WR(p, PM2R_STATISTICS_MODE, 0);
+	pm2_WR(p, PM2R_SCISSOR_MODE, 0);
+	pm2_WR(p, PM2R_FILTER_MODE, PM2F_SYNCHRONIZATION);
+	switch (p->type) {
+	case PM2_TYPE_PERMEDIA2:
+		pm2_RDAC_WR(p, PM2I_RD_MODE_CONTROL, 0); /* no overlay */
+		pm2_RDAC_WR(p, PM2I_RD_CURSOR_CONTROL, 0);
+		pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, PM2F_RD_PALETTE_WIDTH_8);
+		break;
+	case PM2_TYPE_PERMEDIA2V:
+		pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1); /* 8bit */
+		break;
+	}
+	pm2_RDAC_WR(p, PM2I_RD_COLOR_KEY_CONTROL, 0);
+	pm2_RDAC_WR(p, PM2I_RD_OVERLAY_KEY, 0);
+	pm2_RDAC_WR(p, PM2I_RD_RED_KEY, 0);
+	pm2_RDAC_WR(p, PM2I_RD_GREEN_KEY, 0);
+	pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0);
+}
+
+static void set_aperture(struct pm2fb_par* p, u32 depth)
+{
+	/*
+	 * The hardware is little-endian. When used in big-endian
+	 * hosts, the on-chip aperture settings are used where
+	 * possible to translate from host to card byte order.
+	 */
+	WAIT_FIFO(p, 4);
+#ifdef __LITTLE_ENDIAN
+	pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_STANDARD);
+#else
+	switch (depth) {
+	case 24:	/* RGB->BGR */
+		/*
+		 * We can't use the aperture to translate host to
+		 * card byte order here, so we switch to BGR mode
+		 * in pm2fb_set_par().
+		 */
+	case 8:		/* B->B */
+		pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_STANDARD);
+		break;
+	case 16:	/* HL->LH */
+		pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_HALFWORDSWAP);
+		break;
+	case 32:	/* RGBA->ABGR */
+		pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_BYTESWAP);
+		break;
+	}
+#endif
+
+	// We don't use aperture two, so this may be superflous
+	pm2_WR(p, PM2R_APERTURE_TWO, PM2F_APERTURE_STANDARD);
+}
+
+static void set_color(struct pm2fb_par* p, unsigned char regno,
+		      unsigned char r, unsigned char g, unsigned char b)
+{
+	WAIT_FIFO(p, 4);
+	pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, regno);
+	wmb();
+	pm2_WR(p, PM2R_RD_PALETTE_DATA, r);
+	wmb();
+	pm2_WR(p, PM2R_RD_PALETTE_DATA, g);
+	wmb();
+	pm2_WR(p, PM2R_RD_PALETTE_DATA, b);
+}
+
+static void set_memclock(struct pm2fb_par* par, u32 clk)
+{
+	int i;
+	unsigned char m, n, p;
+
+	pm2_mnp(clk, &m, &n, &p);
+	WAIT_FIFO(par, 10);
+	pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 6);
+	wmb();
+	pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_1, m);
+	pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_2, n);
+	wmb();
+	pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 8|p);
+	wmb();
+	pm2_RDAC_RD(par, PM2I_RD_MEMORY_CLOCK_STATUS);
+	rmb();
+	for (i = 256;
+	     i && !(pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED);
+	     i--)
+		;
+}
+
+static void set_pixclock(struct pm2fb_par* par, u32 clk)
+{
+	int i;
+	unsigned char m, n, p;
+
+	switch (par->type) {
+	case PM2_TYPE_PERMEDIA2:
+		pm2_mnp(clk, &m, &n, &p);
+		WAIT_FIFO(par, 8);
+		pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 0);
+		wmb();
+		pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A1, m);
+		pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A2, n);
+		wmb();
+		pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 8|p);
+		wmb();
+		pm2_RDAC_RD(par, PM2I_RD_PIXEL_CLOCK_STATUS);
+		rmb();
+		for (i = 256;
+		     i && !(pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED);
+		     i--)
+			;
+		break;
+	case PM2_TYPE_PERMEDIA2V:
+		pm2v_mnp(clk/2, &m, &n, &p);
+		WAIT_FIFO(par, 8);
+		pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CLK0_PRESCALE >> 8);
+		pm2v_RDAC_WR(par, PM2VI_RD_CLK0_PRESCALE, m);
+		pm2v_RDAC_WR(par, PM2VI_RD_CLK0_FEEDBACK, n);
+		pm2v_RDAC_WR(par, PM2VI_RD_CLK0_POSTSCALE, p);
+		pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
+		break;
+	}
+}
+
+static void set_video(struct pm2fb_par* p, u32 video) {
+	u32 tmp;
+	u32 vsync;
+
+	vsync = video;
+
+	DPRINTK("video = 0x%x\n", video);
+	
+	/*
+	 * The hardware cursor needs +vsync to recognise vert retrace.
+	 * We may not be using the hardware cursor, but the X Glint
+	 * driver may well. So always set +hsync/+vsync and then set
+	 * the RAMDAC to invert the sync if necessary.
+	 */
+	vsync &= ~(PM2F_HSYNC_MASK|PM2F_VSYNC_MASK);
+	vsync |= PM2F_HSYNC_ACT_HIGH|PM2F_VSYNC_ACT_HIGH;
+
+	WAIT_FIFO(p, 5);
+	pm2_WR(p, PM2R_VIDEO_CONTROL, vsync);
+
+	switch (p->type) {
+	case PM2_TYPE_PERMEDIA2:
+		tmp = PM2F_RD_PALETTE_WIDTH_8;
+		if ((video & PM2F_HSYNC_MASK) == PM2F_HSYNC_ACT_LOW)
+			tmp |= 4; /* invert hsync */
+		if ((video & PM2F_VSYNC_MASK) == PM2F_VSYNC_ACT_LOW)
+			tmp |= 8; /* invert vsync */
+		pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, tmp);
+		break;
+	case PM2_TYPE_PERMEDIA2V:
+		tmp = 0;
+		if ((video & PM2F_HSYNC_MASK) == PM2F_HSYNC_ACT_LOW)
+			tmp |= 1; /* invert hsync */
+		if ((video & PM2F_VSYNC_MASK) == PM2F_VSYNC_ACT_LOW)
+			tmp |= 4; /* invert vsync */
+		pm2v_RDAC_WR(p, PM2VI_RD_SYNC_CONTROL, tmp);
+		pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1);
+		break;
+	}
+}
+
+/*
+ *
+ */
+
+/**
+ *      pm2fb_check_var - Optional function. Validates a var passed in. 
+ *      @var: frame buffer variable screen structure
+ *      @info: frame buffer structure that represents a single frame buffer 
+ *
+ *	Checks to see if the hardware supports the state requested by
+ *	var passed in.
+ *
+ *	Returns negative errno on error, or zero on success.
+ */
+static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	u32 lpitch;
+
+	if (var->bits_per_pixel != 8  && var->bits_per_pixel != 16 &&
+	    var->bits_per_pixel != 24 && var->bits_per_pixel != 32) {
+		DPRINTK("depth not supported: %u\n", var->bits_per_pixel);
+		return -EINVAL;
+	}
+
+	if (var->xres != var->xres_virtual) {
+		DPRINTK("virtual x resolution != physical x resolution not supported\n");
+		return -EINVAL;
+	}
+
+	if (var->yres > var->yres_virtual) {
+		DPRINTK("virtual y resolution < physical y resolution not possible\n");
+		return -EINVAL;
+	}
+
+	if (var->xoffset) {
+		DPRINTK("xoffset not supported\n");
+		return -EINVAL;
+	}
+
+	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+		DPRINTK("interlace not supported\n");
+		return -EINVAL;
+	}
+
+	var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */
+	lpitch = var->xres * ((var->bits_per_pixel + 7)>>3);
+  
+	if (var->xres < 320 || var->xres > 1600) {
+		DPRINTK("width not supported: %u\n", var->xres);
+		return -EINVAL;
+	}
+  
+	if (var->yres < 200 || var->yres > 1200) {
+		DPRINTK("height not supported: %u\n", var->yres);
+		return -EINVAL;
+	}
+  
+	if (lpitch * var->yres_virtual > info->fix.smem_len) {
+		DPRINTK("no memory for screen (%ux%ux%u)\n",
+			var->xres, var->yres_virtual, var->bits_per_pixel);
+		return -EINVAL;
+	}
+  
+	if (PICOS2KHZ(var->pixclock) > PM2_MAX_PIXCLOCK) {
+		DPRINTK("pixclock too high (%ldKHz)\n", PICOS2KHZ(var->pixclock));
+		return -EINVAL;
+	}
+
+	switch(var->bits_per_pixel) {
+	case 8:
+		var->red.length = var->green.length = var->blue.length = 8;
+		break;
+	case 16:
+		var->red.offset   = 11;
+		var->red.length   = 5;
+		var->green.offset = 5;
+		var->green.length = 6;
+		var->blue.offset  = 0;
+		var->blue.length  = 5;
+		break;
+	case 32:
+		var->transp.offset = 24;
+		var->transp.length = 8;
+		var->red.offset	  = 16;
+		var->green.offset = 8;
+		var->blue.offset  = 0;
+		var->red.length = var->green.length = var->blue.length = 8;
+		break;
+	case 24:
+#ifdef __BIG_ENDIAN
+		var->red.offset   = 0;
+		var->blue.offset  = 16;
+#else
+		var->red.offset   = 16;
+		var->blue.offset  = 0;
+#endif
+		var->green.offset = 8;
+		var->red.length = var->green.length = var->blue.length = 8;
+		break;
+	}
+	var->height = var->width = -1;
+  
+	var->accel_flags = 0;	/* Can't mmap if this is on */
+	
+	DPRINTK("Checking graphics mode at %dx%d depth %d\n",
+		var->xres, var->yres, var->bits_per_pixel);
+	return 0;
+}
+
+/**
+ *      pm2fb_set_par - Alters the hardware state.
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ *	Using the fb_var_screeninfo in fb_info we set the resolution of the
+ *	this particular framebuffer.
+ */
+static int pm2fb_set_par(struct fb_info *info)
+{
+	struct pm2fb_par *par = (struct pm2fb_par *) info->par;
+	u32 pixclock;
+	u32 width, height, depth;
+	u32 hsstart, hsend, hbend, htotal;
+	u32 vsstart, vsend, vbend, vtotal;
+	u32 stride;
+	u32 base;
+	u32 video = 0;
+	u32 clrmode = PM2F_RD_COLOR_MODE_RGB | PM2F_RD_GUI_ACTIVE;
+	u32 txtmap = 0;
+	u32 pixsize = 0;
+	u32 clrformat = 0;
+	u32 xres;
+	int data64;
+
+	reset_card(par);
+	reset_config(par);
+	clear_palette(par);
+	if ( par->memclock )
+		set_memclock(par, par->memclock);
+    
+	width = (info->var.xres_virtual + 7) & ~7;
+	height = info->var.yres_virtual;
+	depth = (info->var.bits_per_pixel + 7) & ~7;
+	depth = (depth > 32) ? 32 : depth;
+	data64 = depth > 8 || par->type == PM2_TYPE_PERMEDIA2V;
+
+	xres = (info->var.xres + 31) & ~31;
+	pixclock = PICOS2KHZ(info->var.pixclock);
+	if (pixclock > PM2_MAX_PIXCLOCK) {
+		DPRINTK("pixclock too high (%uKHz)\n", pixclock);
+		return -EINVAL;
+	}
+    
+	hsstart = to3264(info->var.right_margin, depth, data64);
+	hsend = hsstart + to3264(info->var.hsync_len, depth, data64);
+	hbend = hsend + to3264(info->var.left_margin, depth, data64);
+	htotal = to3264(xres, depth, data64) + hbend - 1;
+	vsstart = (info->var.lower_margin)
+		? info->var.lower_margin - 1
+		: 0;	/* FIXME! */
+	vsend = info->var.lower_margin + info->var.vsync_len - 1;
+	vbend = info->var.lower_margin + info->var.vsync_len + info->var.upper_margin;
+	vtotal = info->var.yres + vbend - 1;
+	stride = to3264(width, depth, 1);
+	base = to3264(info->var.yoffset * xres + info->var.xoffset, depth, 1);
+	if (data64)
+		video |= PM2F_DATA_64_ENABLE;
+    
+	if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) {
+		if (lowhsync) {
+			DPRINTK("ignoring +hsync, using -hsync.\n");
+			video |= PM2F_HSYNC_ACT_LOW;
+		} else
+			video |= PM2F_HSYNC_ACT_HIGH;
+	}
+	else
+		video |= PM2F_HSYNC_ACT_LOW;
+	if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) {
+		if (lowvsync) {
+			DPRINTK("ignoring +vsync, using -vsync.\n");
+			video |= PM2F_VSYNC_ACT_LOW;
+		} else
+			video |= PM2F_VSYNC_ACT_HIGH;
+	}
+	else
+		video |= PM2F_VSYNC_ACT_LOW;
+	if ((info->var.vmode & FB_VMODE_MASK)==FB_VMODE_INTERLACED) {
+		DPRINTK("interlaced not supported\n");
+		return -EINVAL;
+	}
+	if ((info->var.vmode & FB_VMODE_MASK)==FB_VMODE_DOUBLE)
+		video |= PM2F_LINE_DOUBLE;
+	if ((info->var.activate & FB_ACTIVATE_MASK)==FB_ACTIVATE_NOW)
+		video |= PM2F_VIDEO_ENABLE;
+	par->video = video;
+
+	info->fix.visual =
+		(depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+	info->fix.line_length = info->var.xres * depth / 8;
+	info->cmap.len = 256;
+
+	/*
+	 * Settings calculated. Now write them out.
+	 */
+	if (par->type == PM2_TYPE_PERMEDIA2V) {
+		WAIT_FIFO(par, 1);
+		pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
+	}
+    
+	set_aperture(par, depth);
+    
+	mb();
+	WAIT_FIFO(par, 19);
+	pm2_RDAC_WR(par, PM2I_RD_COLOR_KEY_CONTROL,
+		    ( depth == 8 ) ? 0 : PM2F_COLOR_KEY_TEST_OFF);
+	switch (depth) {
+	case 8:
+		pm2_WR(par, PM2R_FB_READ_PIXEL, 0);
+		clrformat = 0x0e;
+		break;
+	case 16:
+		pm2_WR(par, PM2R_FB_READ_PIXEL, 1);
+		clrmode |= PM2F_RD_TRUECOLOR | PM2F_RD_PIXELFORMAT_RGB565;
+		txtmap = PM2F_TEXTEL_SIZE_16;
+		pixsize = 1;
+		clrformat = 0x70;
+		break;
+	case 32:
+		pm2_WR(par, PM2R_FB_READ_PIXEL, 2);
+		clrmode |= PM2F_RD_TRUECOLOR | PM2F_RD_PIXELFORMAT_RGBA8888;
+		txtmap = PM2F_TEXTEL_SIZE_32;
+		pixsize = 2;
+		clrformat = 0x20;
+		break;
+	case 24:
+		pm2_WR(par, PM2R_FB_READ_PIXEL, 4);
+		clrmode |= PM2F_RD_TRUECOLOR | PM2F_RD_PIXELFORMAT_RGB888;
+		txtmap = PM2F_TEXTEL_SIZE_24;
+		pixsize = 4;
+		clrformat = 0x20;
+		break;
+	}
+	pm2_WR(par, PM2R_FB_WRITE_MODE, PM2F_FB_WRITE_ENABLE);
+	pm2_WR(par, PM2R_FB_READ_MODE, partprod(xres));
+	pm2_WR(par, PM2R_LB_READ_MODE, partprod(xres));
+	pm2_WR(par, PM2R_TEXTURE_MAP_FORMAT, txtmap | partprod(xres));
+	pm2_WR(par, PM2R_H_TOTAL, htotal);
+	pm2_WR(par, PM2R_HS_START, hsstart);
+	pm2_WR(par, PM2R_HS_END, hsend);
+	pm2_WR(par, PM2R_HG_END, hbend);
+	pm2_WR(par, PM2R_HB_END, hbend);
+	pm2_WR(par, PM2R_V_TOTAL, vtotal);
+	pm2_WR(par, PM2R_VS_START, vsstart);
+	pm2_WR(par, PM2R_VS_END, vsend);
+	pm2_WR(par, PM2R_VB_END, vbend);
+	pm2_WR(par, PM2R_SCREEN_STRIDE, stride);
+	wmb();
+	pm2_WR(par, PM2R_WINDOW_ORIGIN, 0);
+	pm2_WR(par, PM2R_SCREEN_SIZE, (height << 16) | width);
+	pm2_WR(par, PM2R_SCISSOR_MODE, PM2F_SCREEN_SCISSOR_ENABLE);
+	wmb();
+	pm2_WR(par, PM2R_SCREEN_BASE, base);
+	wmb();
+	set_video(par, video);
+	WAIT_FIFO(par, 4);
+	switch (par->type) {
+	case PM2_TYPE_PERMEDIA2:
+		pm2_RDAC_WR(par, PM2I_RD_COLOR_MODE, clrmode);
+		break;
+	case PM2_TYPE_PERMEDIA2V:
+		pm2v_RDAC_WR(par, PM2VI_RD_PIXEL_SIZE, pixsize);
+		pm2v_RDAC_WR(par, PM2VI_RD_COLOR_FORMAT, clrformat);
+		break;
+	}
+	set_pixclock(par, pixclock);
+	DPRINTK("Setting graphics mode at %dx%d depth %d\n",
+		info->var.xres, info->var.yres, info->var.bits_per_pixel);
+	return 0;	
+}
+
+/**
+ *  	pm2fb_setcolreg - Sets a color register.
+ *      @regno: boolean, 0 copy local, 1 get_user() function
+ *      @red: frame buffer colormap structure
+ *	@green: The green value which can be up to 16 bits wide 
+ *	@blue:  The blue value which can be up to 16 bits wide.
+ *	@transp: If supported the alpha value which can be up to 16 bits wide.	
+ *      @info: frame buffer info structure
+ * 
+ *  	Set a single color register. The values supplied have a 16 bit
+ *  	magnitude which needs to be scaled in this function for the hardware.
+ *	Pretty much a direct lift from tdfxfb.c.
+ * 
+ *	Returns negative errno on error, or zero on success.
+ */
+static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp,
+			   struct fb_info *info)
+{
+	struct pm2fb_par *par = (struct pm2fb_par *) info->par;
+
+	if (regno >= info->cmap.len)  /* no. of hw registers */
+		return 1;
+	/*
+	 * Program hardware... do anything you want with transp
+	 */
+
+	/* grayscale works only partially under directcolor */
+	if (info->var.grayscale) {
+		/* grayscale = 0.30*R + 0.59*G + 0.11*B */
+		red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+	}
+
+	/* Directcolor:
+	 *   var->{color}.offset contains start of bitfield
+	 *   var->{color}.length contains length of bitfield
+	 *   {hardwarespecific} contains width of DAC
+	 *   cmap[X] is programmed to
+	 *   (X << red.offset) | (X << green.offset) | (X << blue.offset)
+	 *   RAMDAC[X] is programmed to (red, green, blue)
+	 *
+	 * Pseudocolor:
+	 *    uses offset = 0 && length = DAC register width.
+	 *    var->{color}.offset is 0
+	 *    var->{color}.length contains widht of DAC
+	 *    cmap is not used
+	 *    DAC[X] is programmed to (red, green, blue)
+	 * Truecolor:
+	 *    does not use RAMDAC (usually has 3 of them).
+	 *    var->{color}.offset contains start of bitfield
+	 *    var->{color}.length contains length of bitfield
+	 *    cmap is programmed to
+	 *    (red << red.offset) | (green << green.offset) |
+	 *    (blue << blue.offset) | (transp << transp.offset)
+	 *    RAMDAC does not exist
+	 */
+#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+	switch (info->fix.visual) {
+	case FB_VISUAL_TRUECOLOR:
+	case FB_VISUAL_PSEUDOCOLOR:
+		red = CNVT_TOHW(red, info->var.red.length);
+		green = CNVT_TOHW(green, info->var.green.length);
+		blue = CNVT_TOHW(blue, info->var.blue.length);
+		transp = CNVT_TOHW(transp, info->var.transp.length);
+		break;
+	case FB_VISUAL_DIRECTCOLOR:
+		/* example here assumes 8 bit DAC. Might be different 
+		 * for your hardware */	
+		red = CNVT_TOHW(red, 8);       
+		green = CNVT_TOHW(green, 8);
+		blue = CNVT_TOHW(blue, 8);
+		/* hey, there is bug in transp handling... */
+		transp = CNVT_TOHW(transp, 8);
+		break;
+	}
+#undef CNVT_TOHW
+	/* Truecolor has hardware independent palette */
+	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+		u32 v;
+
+		if (regno >= 16)
+			return 1;
+
+		v = (red << info->var.red.offset) |
+			(green << info->var.green.offset) |
+			(blue << info->var.blue.offset) |
+			(transp << info->var.transp.offset);
+
+		switch (info->var.bits_per_pixel) {
+		case 8:
+			break;	
+   		case 16:
+		case 24:
+		case 32:	
+           		((u32*)(info->pseudo_palette))[regno] = v;
+			break;
+		}
+		return 0;
+	}
+	else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
+		set_color(par, regno, red, green, blue);
+
+	return 0;
+}
+
+/**
+ *      pm2fb_pan_display - Pans the display.
+ *      @var: frame buffer variable screen structure
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ *	Pan (or wrap, depending on the `vmode' field) the display using the
+ *  	`xoffset' and `yoffset' fields of the `var' structure.
+ *  	If the values don't fit, return -EINVAL.
+ *
+ *      Returns negative errno on error, or zero on success.
+ *
+ */
+static int pm2fb_pan_display(struct fb_var_screeninfo *var,
+			     struct fb_info *info)
+{
+	struct pm2fb_par *p = (struct pm2fb_par *) info->par;
+	u32 base;
+	u32 depth;
+	u32 xres;
+
+	xres = (var->xres + 31) & ~31;
+	depth = (var->bits_per_pixel + 7) & ~7;
+	depth = (depth > 32) ? 32 : depth;
+	base = to3264(var->yoffset * xres + var->xoffset, depth, 1);
+	WAIT_FIFO(p, 1);
+	pm2_WR(p, PM2R_SCREEN_BASE, base);    
+	return 0;
+}
+
+/**
+ *      pm2fb_blank - Blanks the display.
+ *      @blank_mode: the blank mode we want. 
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ *      Blank the screen if blank_mode != 0, else unblank. Return 0 if
+ *      blanking succeeded, != 0 if un-/blanking failed due to e.g. a 
+ *      video mode which doesn't support it. Implements VESA suspend
+ *      and powerdown modes on hardware that supports disabling hsync/vsync:
+ *      blank_mode == 2: suspend vsync
+ *      blank_mode == 3: suspend hsync
+ *      blank_mode == 4: powerdown
+ *
+ *      Returns negative errno on error, or zero on success.
+ *
+ */
+static int pm2fb_blank(int blank_mode, struct fb_info *info)
+{
+	struct pm2fb_par *par = (struct pm2fb_par *) info->par;
+	u32 video = par->video;
+
+	DPRINTK("blank_mode %d\n", blank_mode);
+
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANK:
+		/* Screen: On */
+		video |= PM2F_VIDEO_ENABLE;
+		break;
+	case FB_BLANK_NORMAL:
+		/* Screen: Off */
+		video &= ~PM2F_VIDEO_ENABLE;
+		break;
+	case FB_BLANK_VSYNC_SUSPEND:
+		/* VSync: Off */
+		video &= ~(PM2F_VSYNC_MASK | PM2F_BLANK_LOW );
+		break;
+	case FB_BLANK_HSYNC_SUSPEND:
+		/* HSync: Off */
+		video &= ~(PM2F_HSYNC_MASK | PM2F_BLANK_LOW );
+		break;
+	case FB_BLANK_POWERDOWN:
+		/* HSync: Off, VSync: Off */
+		video &= ~(PM2F_VSYNC_MASK | PM2F_HSYNC_MASK| PM2F_BLANK_LOW);
+		break;
+	}
+	set_video(par, video);
+	return 0;
+}
+
+/* ------------ Hardware Independent Functions ------------ */
+
+/*
+ *  Frame buffer operations
+ */
+
+static struct fb_ops pm2fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= pm2fb_check_var,
+	.fb_set_par	= pm2fb_set_par,
+	.fb_setcolreg	= pm2fb_setcolreg,
+	.fb_blank	= pm2fb_blank,
+	.fb_pan_display	= pm2fb_pan_display,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+/*
+ * PCI stuff
+ */
+
+
+/**
+ * Device initialisation
+ *
+ * Initialise and allocate resource for PCI device.
+ *
+ * @param	pdev	PCI device.
+ * @param	id	PCI device ID.
+ */
+static int __devinit pm2fb_probe(struct pci_dev *pdev,
+				 const struct pci_device_id *id)
+{
+	struct pm2fb_par *default_par;
+	struct fb_info *info;
+	int size, err;
+	int err_retval = -ENXIO;
+
+	err = pci_enable_device(pdev);
+	if ( err ) {
+		printk(KERN_WARNING "pm2fb: Can't enable pdev: %d\n", err);
+		return err;
+	}
+
+	size = sizeof(struct pm2fb_par) + 256 * sizeof(u32);
+	info = framebuffer_alloc(size, &pdev->dev);
+	if ( !info )
+		return -ENOMEM;
+	default_par = (struct pm2fb_par *) info->par;
+
+	switch (pdev->device) {
+	case  PCI_DEVICE_ID_TI_TVP4020:
+		strcpy(pm2fb_fix.id, "TVP4020");
+		default_par->type = PM2_TYPE_PERMEDIA2;
+		break;
+	case  PCI_DEVICE_ID_3DLABS_PERMEDIA2:
+		strcpy(pm2fb_fix.id, "Permedia2");
+		default_par->type = PM2_TYPE_PERMEDIA2;
+		break;
+	case  PCI_DEVICE_ID_3DLABS_PERMEDIA2V:
+		strcpy(pm2fb_fix.id, "Permedia2v");
+		default_par->type = PM2_TYPE_PERMEDIA2V;
+		break;
+	}
+
+	pm2fb_fix.mmio_start = pci_resource_start(pdev, 0);
+	pm2fb_fix.mmio_len = PM2_REGS_SIZE;
+
+#if defined(__BIG_ENDIAN)
+	/*
+	 * PM2 has a 64k register file, mapped twice in 128k. Lower
+	 * map is little-endian, upper map is big-endian.
+	 */
+	pm2fb_fix.mmio_start += PM2_REGS_SIZE;
+	DPRINTK("Adjusting register base for big-endian.\n");
+#endif
+	DPRINTK("Register base at 0x%lx\n", pm2fb_fix.mmio_start);
+    
+	/* Registers - request region and map it. */
+	if ( !request_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len,
+				 "pm2fb regbase") ) {
+		printk(KERN_WARNING "pm2fb: Can't reserve regbase.\n");
+		goto err_exit_neither;
+	}
+	default_par->v_regs =
+		ioremap_nocache(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len);
+	if ( !default_par->v_regs ) {
+		printk(KERN_WARNING "pm2fb: Can't remap %s register area.\n",
+		       pm2fb_fix.id);
+		release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len);
+		goto err_exit_neither;
+	}
+
+	/* Stash away memory register info for use when we reset the board */
+	default_par->mem_control = pm2_RD(default_par, PM2R_MEM_CONTROL);
+	default_par->boot_address = pm2_RD(default_par, PM2R_BOOT_ADDRESS);
+	default_par->mem_config = pm2_RD(default_par, PM2R_MEM_CONFIG);
+	DPRINTK("MemControl 0x%x BootAddress 0x%x MemConfig 0x%x\n",
+		default_par->mem_control, default_par->boot_address,
+		default_par->mem_config);
+
+	/* Now work out how big lfb is going to be. */
+	switch(default_par->mem_config & PM2F_MEM_CONFIG_RAM_MASK) {
+	case PM2F_MEM_BANKS_1:
+		default_par->fb_size=0x200000;
+		break;
+	case PM2F_MEM_BANKS_2:
+		default_par->fb_size=0x400000;
+		break;
+	case PM2F_MEM_BANKS_3:
+		default_par->fb_size=0x600000;
+		break;
+	case PM2F_MEM_BANKS_4:
+		default_par->fb_size=0x800000;
+		break;
+	}
+	default_par->memclock = CVPPC_MEMCLOCK;
+	pm2fb_fix.smem_start = pci_resource_start(pdev, 1);
+	pm2fb_fix.smem_len = default_par->fb_size;
+
+	/* Linear frame buffer - request region and map it. */
+	if ( !request_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len,
+				 "pm2fb smem") ) {
+		printk(KERN_WARNING "pm2fb: Can't reserve smem.\n");
+		goto err_exit_mmio;
+	}
+	info->screen_base = default_par->v_fb =
+		ioremap_nocache(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
+	if ( !default_par->v_fb ) {
+		printk(KERN_WARNING "pm2fb: Can't ioremap smem area.\n");
+		release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
+		goto err_exit_mmio;
+	}
+
+	info->fbops		= &pm2fb_ops;
+	info->fix		= pm2fb_fix; 	
+	info->pseudo_palette	= (void *)(default_par + 1); 
+	info->flags		= FBINFO_DEFAULT |
+                                  FBINFO_HWACCEL_YPAN;
+
+	if (!mode)
+		mode = "640x480@60";
+	 
+	err = fb_find_mode(&info->var, info, mode, NULL, 0, NULL, 8); 
+	if (!err || err == 4)
+		info->var = pm2fb_var;
+
+	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
+		goto err_exit_all;
+
+	if (register_framebuffer(info) < 0)
+		goto err_exit_both;
+
+	printk(KERN_INFO "fb%d: %s frame buffer device, memory = %dK.\n",
+	       info->node, info->fix.id, default_par->fb_size / 1024);
+
+	/*
+	 * Our driver data
+	 */
+	pci_set_drvdata(pdev, info);
+
+	return 0;
+
+ err_exit_all:
+	fb_dealloc_cmap(&info->cmap);	
+ err_exit_both:    
+	iounmap(info->screen_base);
+	release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
+ err_exit_mmio:
+	iounmap(default_par->v_regs);
+	release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len);
+ err_exit_neither:
+	framebuffer_release(info);
+	return err_retval;
+}
+
+/**
+ * Device removal.
+ *
+ * Release all device resources.
+ *
+ * @param	pdev	PCI device to clean up.
+ */
+static void __devexit pm2fb_remove(struct pci_dev *pdev)
+{
+	struct fb_info* info = pci_get_drvdata(pdev);
+	struct fb_fix_screeninfo* fix = &info->fix;
+	struct pm2fb_par *par = info->par;
+
+	unregister_framebuffer(info);
+    
+	iounmap(info->screen_base);
+	release_mem_region(fix->smem_start, fix->smem_len);
+	iounmap(par->v_regs);
+	release_mem_region(fix->mmio_start, fix->mmio_len);
+
+	pci_set_drvdata(pdev, NULL);
+	kfree(info);
+}
+
+static struct pci_device_id pm2fb_id_table[] = {
+	{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020,
+	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
+	  0xff0000, 0 },
+	{ PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2,
+	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
+	  0xff0000, 0 },
+	{ PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V,
+	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
+	  0xff0000, 0 },
+	{ 0, }
+};
+
+static struct pci_driver pm2fb_driver = {
+	.name		= "pm2fb",
+	.id_table 	= pm2fb_id_table,
+	.probe 		= pm2fb_probe,
+	.remove 	= __devexit_p(pm2fb_remove),
+};
+
+MODULE_DEVICE_TABLE(pci, pm2fb_id_table);
+
+
+#ifndef MODULE
+/**
+ * Parse user speficied options.
+ *
+ * This is, comma-separated options following `video=pm2fb:'.
+ */
+static int __init pm2fb_setup(char *options)
+{
+	char* this_opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {	
+		if (!*this_opt)
+			continue;
+		if(!strcmp(this_opt, "lowhsync")) {
+			lowhsync = 1;
+		} else if(!strcmp(this_opt, "lowvsync")) {
+			lowvsync = 1;
+		} else {
+			mode = this_opt;
+		}
+	}
+	return 0;
+}
+#endif
+
+
+static int __init pm2fb_init(void)
+{
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("pm2fb", &option))
+		return -ENODEV;
+	pm2fb_setup(option);
+#endif
+
+	return pci_register_driver(&pm2fb_driver);
+}
+
+module_init(pm2fb_init);
+
+#ifdef MODULE
+/*
+ *  Cleanup
+ */
+
+static void __exit pm2fb_exit(void)
+{
+	pci_unregister_driver(&pm2fb_driver);
+}
+#endif
+
+#ifdef MODULE
+module_exit(pm2fb_exit);
+
+module_param(mode, charp, 0);
+MODULE_PARM_DESC(mode, "Preferred video mode e.g. '648x480-8@60'");
+module_param(lowhsync, bool, 0);
+MODULE_PARM_DESC(lowhsync, "Force horizontal sync low regardless of mode");
+module_param(lowvsync, bool, 0);
+MODULE_PARM_DESC(lowvsync, "Force vertical sync low regardless of mode");
+
+MODULE_AUTHOR("Jim Hague <jim.hague@acm.org>");
+MODULE_DESCRIPTION("Permedia2 framebuffer device driver");
+MODULE_LICENSE("GPL");
+#endif
diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c
new file mode 100644
index 0000000..8e024aa
--- /dev/null
+++ b/drivers/video/pm3fb.c
@@ -0,0 +1,3646 @@
+/*
+ *  linux/drivers/video/pm3fb.c -- 3DLabs Permedia3 frame buffer device
+ *  
+ *  Copyright (C) 2001 Romain Dolbeau <dolbeau@irisa.fr>
+ *  Based on code written by:
+ *           Sven Luther, <luther@dpt-info.u-strasbg.fr>
+ *           Alan Hourihane, <alanh@fairlite.demon.co.uk>
+ *           Russel King, <rmk@arm.linux.org.uk>
+ *  Based on linux/drivers/video/skeletonfb.c:
+ *	Copyright (C) 1997 Geert Uytterhoeven
+ *  Based on linux/driver/video/pm2fb.c:
+ *      Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
+ *      Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com)
+ *
+ *  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.
+ *
+ *  $Header: /cvsroot/linux/drivers/video/pm3fb.c,v 1.1 2002/02/25 19:11:06 marcelo Exp $
+ *
+ *  CHANGELOG:
+ *  Mon Feb 11 10:35:48 MET 2002, v 1.4.11B: Cosmetic update.
+ *  Wed Jan 23 14:16:59 MET 2002, v 1.4.11: Preliminary 2.5.x support, patch for 2.5.2.
+ *  Wed Nov 28 11:08:29 MET 2001, v 1.4.10: potential bug fix for SDRAM-based board, patch for 2.4.16.
+ *  Thu Sep 20 10:24:42 MET DST 2001, v 1.4.9: sync bug fix, preliminary flatpanel support, better timings.
+ *  Tue Aug 28 10:13:01 MET DST 2001, v 1.4.8: memory timings check, minor bug fixes.
+ *  Wed Jul 18 19:06:14 CEST 2001, v 1.4.7: Mode fix (800x600-100, 1024x768-100 changed), using HW panning + accel bug fix.
+ *  Mon Jun 25 10:33:56 MET DST 2001, v 1.4.6: Depth 12 fix, chip reset ioctl, moved memory erase ioctl to DEBUG.
+ *  Wed Jun 20 11:13:08 MET DST 2001, v 1.4.5: Fixed missing blinking cursor in 8bpp, code cleaning, memory erase IOCTL.
+ *  Mon Jun 18 16:00:27 CEST 2001, v 1.4.4: Depth 12 (RGBA 4444) support, code cleaning.
+ *  Fri Jun 15 13:53:01 CEST 2001, v 1.4.3: Removed warnings, depth 15 support, add 'depth' option.
+ *  Thu Jun 14 10:13:52 MET DST 2001, v 1.4.2: Fixed depth switching bug, preliminary 15bpp (RGB5551) support.
+ *  Thu Apr 12 11:16:45 MET DST 2001, v 1.4.1B: Doc updates.
+ *  Fri Apr  6 11:12:53 MET DST 2001, v 1.4.1: Configure.help, minor cleanup
+ *  Thu Mar 29 10:56:50 MET DST 2001, v 1.4.0: Module & module options support (note: linux patch changed, 2.2.19 added).
+ *  Thu Mar 15 15:30:31 MET 2001, v 1.3.2: Fixed mirroring bug on little-endian.
+ *  Wed Mar 14 21:25:54 CET 2001, v 1.3.1: Fixed bug in BlockMove (_bmov).
+ *  Tue Mar 13 10:53:19 MET 2001, v 1.3.0: Character drawing hardware support (in all width between 1 and 16), fixes.
+ *  Thu Mar  8 10:20:16 MET 2001, v 1.2.2: Better J2000 support, "font:" option.
+ *  Tue Mar  6 21:25:04 CET 2001, v 1.2.1: Better acceleration support.
+ *  Mon Mar  5 21:54:17 CET 2001, v 1.2.0: Partial acceleration support (clear & bmove)
+ *  Mon Mar  5 12:52:15 CET 2001, v 1.1.3: Big pan_display fix.
+ *  Sun Mar  4 22:21:50 CET 2001, v 1.1.2: (numerous) bug fixes.
+ *  Fri Mar  2 15:54:07 CET 2001, v 1.1.1: Might have Appian J2000 support, resource mangement in 2.4
+ *  Wed Feb 28 18:21:35 CET 2001, v 1.1.0: Might have multiple boards support (added, but not yest tested)
+ *  Tue Feb 27 17:31:12 CET 2001, v 1.0.6: fixes boot-time mode select, add more default mode
+ *  Tue Feb 27 14:01:36 CET 2001, v 1.0.5: fixes (1.0.4 was broken for 2.2), cleaning up
+ *  Mon Feb 26 23:17:36 CET 2001, v 1.0.4: preliminary 2.4.x support, dropped (useless on pm3) partial product, more OF fix
+ *  Mon Feb 26 20:59:05 CET 2001, v 1.0.3: No more shadow register (and wasted memory), endianess fix, use OF-preset resolution by default
+ *  Wed Feb 21 22:09:30 CET 2001, v 1.0.2: Code cleaning for future multiboard support, better OF support, bugs fix
+ *  Wed Feb 21 19:58:56 CET 2001, v 1.0.1: OpenFirmware support, fixed memory detection, better debug support, code cleaning
+ *  Wed Feb 21 14:47:06 CET 2001, v 1.0.0: First working version
+ */
+
+#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 <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-mfb.h>
+#include <video/fbcon-cfb2.h>
+#include <video/fbcon-cfb4.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+#include <video/pm3fb.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_FB_OF
+#include <asm/prom.h>
+#endif
+
+/* ************************************* */
+/* ***** The various "global" data ***** */
+/* ************************************* */
+
+/* those will need a rework for multiple board support */
+/* Driver name */
+static const char permedia3_name[16] = "Permedia3";
+
+/* the fb_par struct, mandatory */
+struct pm3fb_par {
+	u32 pixclock;		/* pixclock in KHz */
+
+	u32 width;		/* width of virtual screen */
+	u32 height;		/* height of virtual screen */
+
+	u32 hsstart;		/* horiz. sync start */
+	u32 hsend;		/* horiz. sync end */
+	u32 hbend;		/* horiz. blank end (also gate end) */
+	u32 htotal;		/* total width (w/ sync & blank) */
+
+	u32 vsstart;		/* vert. sync start */
+	u32 vsend;		/* vert. sync end */
+	u32 vbend;		/* vert. blank end */
+	u32 vtotal;		/* total height (w/ sync & blank) */
+
+	u32 stride;		/* screen stride */
+	u32 base;		/* screen base (xoffset+yoffset) in 128 bits unit */
+	/* NOTE : unlike other pm3 stuff above, stored *after* shiftbpp. don't ask */
+	u32 depth;		/* screen depth (8, 12, 15, 16 or 32) */
+	u32 video;		/* video control (hsync,vsync) */
+};
+
+/* memory timings */
+struct pm3fb_timings
+{
+	unsigned long caps;
+	unsigned long timings;
+	unsigned long control;
+	unsigned long refresh;
+	unsigned long powerdown;
+};
+typedef enum pm3fb_timing_result { pm3fb_timing_ok, pm3fb_timing_problem, pm3fb_timing_retry } pm3fb_timing_result;
+#define PM3FB_UNKNOWN_TIMING_VALUE ((unsigned long)-1)
+#define PM3FB_UNKNOWN_TIMINGS { PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE }
+
+/* the fb_info struct, mandatory */
+struct pm3fb_info {
+	struct fb_info_gen gen;
+	unsigned long board_num; /* internal board number */
+	unsigned long use_current;
+	struct pm3fb_par *current_par;
+	struct pci_dev *dev;    /* PCI device */
+	unsigned long board_type; /* index in the cardbase */
+	unsigned char *fb_base;	/* framebuffer memory base */
+	u32 fb_size;		/* framebuffer memory size */
+	unsigned char *p_fb;	/* physical address of frame buffer */
+	unsigned char *v_fb;	/* virtual address of frame buffer */
+	unsigned char *pIOBase;	/* physical address of registers region, must be rg_base or rg_base+PM2_REGS_SIZE depending on the host endianness */
+	unsigned char *vIOBase;	/* address of registers after ioremap() */
+	struct {
+		u8 transp;
+		u8 red;
+		u8 green;
+		u8 blue;
+	} palette[256];
+	union {
+#ifdef FBCON_HAS_CFB16
+		u16 cmap12[16]; /* RGBA 4444 */
+		u16 cmap15[16]; /* RGBA 5551 */
+		u16 cmap16[16]; /* RGBA 5650 */
+#endif
+#ifdef FBCON_HAS_CFB32
+		u32 cmap32[16];
+#endif
+	} cmap;
+	struct pm3fb_timings memt;
+};
+
+/* regular resolution database*/
+static struct {
+	char name[16];
+	struct pm3fb_par user_mode;
+} mode_base[] __initdata = {
+	{
+		"default-800x600", {
+	49500, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625,
+			    800, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}}, {
+		"1024x768-74", {
+	78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38,
+			    806, 1024, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}}, {
+		"1024x768-74-32", {
+			78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38,
+			806, 1024, 0, 32,
+			PM3VideoControl_ENABLE |
+			PM3VideoControl_HSYNC_ACTIVE_HIGH
+			|
+			PM3VideoControl_VSYNC_ACTIVE_HIGH
+			| PM3VideoControl_PIXELSIZE_32BIT}},
+/* Generated mode : "1600x1024", for the SGI 1600SW flat panel*/
+	{
+		"SGI1600SW", {
+			108000, 1600, 1024, 16, 56, 104, 1704, 3, 6, 32,
+			1056, 1600, 0, 8,
+			PM3VideoControl_ENABLE|
+			PM3VideoControl_HSYNC_ACTIVE_LOW|PM3VideoControl_VSYNC_ACTIVE_LOW|
+			PM3VideoControl_PIXELSIZE_32BIT}}, 
+/* ##### auto-generated mode, by fbtimings2pm3 */
+/* Generated mode : "640x480-60" */
+	{
+		"640x480-60", {
+	25174, 640, 480, 16, 112, 160, 800, 10, 12, 45,
+			    525, 640, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "640x480-72" */
+	{
+		"640x480-72", {
+	31199, 640, 480, 24, 64, 192, 832, 9, 12, 40, 520,
+			    640, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "640x480-75" */
+	{
+		"640x480-75", {
+	31499, 640, 480, 16, 80, 200, 840, 1, 4, 20, 500,
+			    640, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "640x480-90" */
+	{
+		"640x480-90", {
+	39909, 640, 480, 32, 72, 192, 832, 25, 39, 53, 533,
+			    640, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "640x480-100" */
+	{
+		"640x480-100", {
+	44899, 640, 480, 32, 160, 208, 848, 22, 34, 51,
+			    531, 640, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "800x600-48-lace" */
+/* INTERLACED NOT SUPPORTED
+  {"800x600-48-lace", {35999, 800, 600, 80, 208, 264, 1064, 11, 23, 102, 702, 800, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
+   INTERLACED NOT SUPPORTED */
+/* Generated mode : "800x600-56" */
+	{
+		"800x600-56", {
+	35999, 800, 600, 24, 96, 224, 1024, 1, 3, 25, 625,
+			    800, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "800x600-60" */
+	{
+		"800x600-60", {
+	40000, 800, 600, 40, 168, 256, 1056, 1, 5, 28, 628,
+			    800, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "800x600-70" */
+	{
+		"800x600-70", {
+	44899, 800, 600, 24, 168, 208, 1008, 9, 21, 36,
+			    636, 800, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "800x600-72" */
+	{
+		"800x600-72", {
+	50000, 800, 600, 56, 176, 240, 1040, 37, 43, 66,
+			    666, 800, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "800x600-75" */
+	{
+		"800x600-75", {
+	49497, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625,
+			    800, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "800x600-90" */
+	{
+		"800x600-90", {
+	56637, 800, 600, 8, 72, 192, 992, 8, 19, 35, 635,
+			    800, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "800x600-100", from /etc/fb.modes */
+/* DISABLED, hsstart == 0
+	{
+		"800x600-100", {
+	67499, 800, 600, 0, 64, 280, 1080, 7, 11, 25, 625,
+			    800, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+*/
+/* Generated mode : "800x600-100", from ??? */
+	{
+		"800x600-100", {
+			69650, 800, 600, 64, 128, 288, 1088, 4, 10, 40, 640, 800, 0, 8,
+			PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW|
+			PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1024x768-43-lace" */
+/* INTERLACED NOT SUPPORTED
+  {"1024x768-43-lace", {44899, 1024, 768, 8, 184, 240, 1264, 1, 9, 49, 817, 1024, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
+   INTERLACED NOT SUPPORTED */
+/* Generated mode : "1024x768-60" */
+	{
+		"1024x768-60", {
+	64998, 1024, 768, 24, 160, 320, 1344, 3, 9, 38,
+			    806, 1024, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1024x768-70" */
+	{
+		"1024x768-70", {
+	74996, 1024, 768, 24, 160, 304, 1328, 3, 9, 38,
+			    806, 1024, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1024x768-72" */
+	{
+		"1024x768-72", {
+	74996, 10224, 768, 24, 160, 264, 10488, 3, 9, 38,
+			    806, 10224, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1024x768-75" */
+	{
+		"1024x768-75", {
+	78746, 1024, 768, 16, 112, 288, 1312, 1, 4, 32,
+			    800, 1024, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1024x768-90" */
+	{
+		"1024x768-90", {
+	100000, 1024, 768, 0, 96, 288, 1312, 21, 36, 77,
+			    845, 1024, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1024x768-100", from /etc/fb.modes */
+/* DISABLED, vsstart == 0
+	{
+		"1024x768-100", {
+	109998, 1024, 768, 0, 88, 368, 1392, 0, 8, 24, 792,
+			    1024, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+*/
+/* Generated mode : "1024x768-100", from ??? */
+	{
+		"1024x768-100", {
+			115500, 1024, 768, 32, 224, 416, 1440, 3, 13, 34, 802, 1024, 0, 8,
+			PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW|
+			PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1152x864-43-lace" */
+/* INTERLACED NOT SUPPORTED
+  {"1152x864-43-lace", {64998, 1152, 864, 72, 200, 264, 1416, 78, 87, 191, 1055, 1152, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
+   INTERLACED NOT SUPPORTED */
+/* Generated mode : "1152x864-47-lace" */
+/* INTERLACED NOT SUPPORTED
+  {"1152x864-47-lace", {64998, 1152, 864, 88, 216, 296, 1448, 30, 39, 83, 947, 1152, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
+   INTERLACED NOT SUPPORTED */
+/* Generated mode : "1152x864-60" */
+	{
+		"1152x864-60", {
+	80000, 1152, 864, 64, 176, 304, 1456, 6, 11, 52,
+			    916, 1152, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1152x864-70" */
+	{
+		"1152x864-70", {
+	100000, 1152, 864, 40, 192, 360, 1512, 13, 24, 81,
+			    945, 1152, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1152x864-75" */
+	{
+		"1152x864-75", {
+	109998, 1152, 864, 24, 168, 312, 1464, 45, 53, 138,
+			    1002, 1152, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1152x864-80" */
+	{
+		"1152x864-80", {
+	109998, 1152, 864, 16, 128, 288, 1440, 30, 37, 94,
+			    958, 1152, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1280x1024-43-lace" */
+/* INTERLACED NOT SUPPORTED
+  {"1280x1024-43-lace", {80000, 1024, 1024, 80, 160, 320, 1344, 50, 60, 125, 1149, 1024, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
+   INTERLACED NOT SUPPORTED */
+/* Generated mode : "1280x1024-47-lace" */
+/* INTERLACED NOT SUPPORTED
+  {"1280x1024-47-lace", {80000, 1280, 1024, 80, 160, 320, 1600, 1, 11, 29, 1053, 1280, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
+   INTERLACED NOT SUPPORTED */
+/* Generated mode : "1280x1024-60" */
+	{
+		"1280x1024-60", {
+	107991, 1280, 1024, 48, 160, 408, 1688, 1, 4, 42,
+			    1066, 1280, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1280x1024-70" */
+	{
+		"1280x1024-70", {
+	125992, 1280, 1024, 80, 192, 408, 1688, 1, 6, 42,
+			    1066, 1280, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1280x1024-74" */
+	{
+		"1280x1024-74", {
+	134989, 1280, 1024, 32, 176, 432, 1712, 0, 30, 40,
+			    1064, 1280, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1280x1024-75" */
+	{
+		"1280x1024-75", {
+	134989, 1280, 1024, 16, 160, 408, 1688, 1, 4, 42,
+			    1066, 1280, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_HIGH
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1600x1200-60" */
+	{
+		"1600x1200-60", {
+	155981, 1600, 1200, 32, 192, 448, 2048, 10, 18, 70,
+			    1270, 1600, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1600x1200-66" */
+	{
+		"1600x1200-66", {
+	171998, 1600, 1200, 40, 176, 480, 2080, 3, 6, 53,
+			    1253, 1600, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* Generated mode : "1600x1200-76" */
+	{
+		"1600x1200-76", {
+	197980, 1600, 1200, 40, 176, 480, 2080, 3, 8, 50,
+			    1250, 1600, 0, 8,
+			    PM3VideoControl_ENABLE |
+			    PM3VideoControl_HSYNC_ACTIVE_LOW
+			    |
+			    PM3VideoControl_VSYNC_ACTIVE_LOW
+			    | PM3VideoControl_PIXELSIZE_8BIT}},
+/* ##### end of auto-generated mode */
+	{
+	"\0",}
+};
+
+/* more mandatory stuff (see skeletonfb.c + framebuffer driver HOWTO */
+static struct pm3fb_info fb_info[PM3_MAX_BOARD];
+static struct pm3fb_par current_par[PM3_MAX_BOARD];
+static int current_par_valid[PM3_MAX_BOARD];
+/* to allow explicit filtering of board */
+short bus[PM3_MAX_BOARD];
+short slot[PM3_MAX_BOARD];
+short func[PM3_MAX_BOARD];
+short disable[PM3_MAX_BOARD];
+short noaccel[PM3_MAX_BOARD];
+char fontn[PM3_MAX_BOARD][PM3_FONTNAME_SIZE];
+short depth[PM3_MAX_BOARD];
+short flatpanel[PM3_MAX_BOARD];
+static struct display disp[PM3_MAX_BOARD];
+static char g_options[PM3_OPTIONS_SIZE] __initdata = "pm3fb,dummy";
+short printtimings = 0;
+short forcesize[PM3_MAX_BOARD];
+
+/* ********************* */
+/* ***** prototype ***** */
+/* ********************* */
+/* card-specific */
+static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info);
+/* permedia3-specific */
+static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info);
+static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info);
+static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info);
+static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info,
+					unsigned long r);
+static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock,	/* In kHz units */
+					  unsigned long refclock,	/* In kHz units */
+					  unsigned char *prescale,	/* ClkPreScale */
+					  unsigned char *feedback,	/* ClkFeedBackScale */
+					  unsigned char *postscale
+					  /* ClkPostScale */ );
+static void pm3fb_clear_memory(struct pm3fb_info *l_fb_info, u32 cc);
+static void pm3fb_clear_colormap(struct pm3fb_info *l_fb_info, unsigned char r, unsigned char g, unsigned char b);
+static void pm3fb_common_init(struct pm3fb_info *l_fb_info);
+static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info,
+			  unsigned long depth, int v);
+static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info,
+			    unsigned long depth, int v);
+static void pm3fb_mapIO(struct pm3fb_info *l_fb_info);
+static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info);
+#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2)
+static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info);
+#endif
+static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info);
+static void pm3fb_write_mode(struct pm3fb_info *l_fb_info);
+static void pm3fb_read_mode(struct pm3fb_info *l_fb_info,
+			    struct pm3fb_par *curpar);
+static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info);
+/* accelerated permedia3-specific */
+#ifdef PM3FB_USE_ACCEL
+static void pm3fb_wait_pm3(struct pm3fb_info *l_fb_info);
+static void pm3fb_init_engine(struct pm3fb_info *l_fb_info);
+#ifdef FBCON_HAS_CFB32
+static void pm3fb_cfb32_clear(struct vc_data *conp,
+			      struct display *p,
+			      int sy, int sx, int height, int width);
+static void pm3fb_cfb32_clear_margins(struct vc_data *conp,
+				      struct display *p, int bottom_only);
+#endif /* FBCON_HAS_CFB32 */
+#ifdef FBCON_HAS_CFB16
+static void pm3fb_cfb16_clear(struct vc_data *conp,
+			      struct display *p,
+			      int sy, int sx, int height, int width);
+static void pm3fb_cfb16_clear_margins(struct vc_data *conp,
+				      struct display *p, int bottom_only);
+#endif /* FBCON_HAS_CFB16 */
+#ifdef FBCON_HAS_CFB8
+static void pm3fb_cfb8_clear(struct vc_data *conp,
+			     struct display *p,
+			     int sy, int sx, int height, int width);
+static void pm3fb_cfb8_clear_margins(struct vc_data *conp,
+				     struct display *p, int bottom_only);
+#endif /* FBCON_HAS_CFB8 */
+#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32)
+static void pm3fb_cfbX_bmove(struct display *p,
+			     int sy, int sx,
+			     int dy, int dx, int height, int width);
+static void pm3fb_cfbX_putc(struct vc_data *conp, struct display *p,
+			    int c, int yy, int xx);
+static void pm3fb_cfbX_putcs(struct vc_data *conp, struct display *p,
+			     const unsigned short *s, int count, int yy,
+			     int xx);
+static void pm3fb_cfbX_revc(struct display *p, int xx, int yy);
+#endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */
+#endif /* PM3FB_USE_ACCEL */
+/* pre-init */
+static void pm3fb_mode_setup(char *mode, unsigned long board_num);
+static void pm3fb_pciid_setup(char *pciid, unsigned long board_num);
+static char *pm3fb_boardnum_setup(char *options, unsigned long *bn);
+static void pm3fb_real_setup(char *options);
+/* fbdev */
+static int pm3fb_encode_fix(struct fb_fix_screeninfo *fix,
+			    const void *par, struct fb_info_gen *info);
+static int pm3fb_decode_var(const struct fb_var_screeninfo *var,
+			    void *par, struct fb_info_gen *info);
+static void pm3fb_encode_depth(struct fb_var_screeninfo *var, long d);
+static int pm3fb_encode_var(struct fb_var_screeninfo *var,
+			    const void *par, struct fb_info_gen *info);
+static void pm3fb_get_par(void *par, struct fb_info_gen *info);
+static void pm3fb_set_par(const void *par, struct fb_info_gen *info);
+static void pm3fb_set_color(struct pm3fb_info *l_fb_info,
+			    unsigned char regno, unsigned char r,
+			    unsigned char g, unsigned char b);
+static int pm3fb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+			   unsigned *blue, unsigned *transp,
+			   struct fb_info *info);
+static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp,
+			   struct fb_info *info);
+static int pm3fb_blank(int blank_mode, struct fb_info_gen *info);
+static void pm3fb_set_disp(const void *par, struct display *disp,
+			   struct fb_info_gen *info);
+static void pm3fb_detect(void);
+static int pm3fb_pan_display(const struct fb_var_screeninfo *var,
+			     struct fb_info_gen *info);
+static int pm3fb_ioctl(struct inode *inode, struct file *file,
+                       u_int cmd, u_long arg, int con,
+		       struct fb_info *info);
+
+
+/* the struct that hold them together */
+struct fbgen_hwswitch pm3fb_switch = {
+	pm3fb_detect, pm3fb_encode_fix, pm3fb_decode_var, pm3fb_encode_var,
+	pm3fb_get_par, pm3fb_set_par, pm3fb_getcolreg, 
+	pm3fb_pan_display, pm3fb_blank, pm3fb_set_disp
+};
+
+static struct fb_ops pm3fb_ops = {
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	fbgen_get_fix,
+	.fb_get_var =	fbgen_get_var,
+	.fb_set_var =	fbgen_set_var,
+	.fb_get_cmap =	fbgen_get_cmap,
+	.fb_set_cmap =	fbgen_set_cmap,
+	.fb_setcolreg =	pm3fb_setcolreg,
+	.fb_pan_display =fbgen_pan_display,
+	.fb_blank =	fbgen_blank,
+	.fb_ioctl =	pm3fb_ioctl,
+};
+
+#ifdef PM3FB_USE_ACCEL
+#ifdef FBCON_HAS_CFB32
+static struct display_switch pm3fb_cfb32 = {
+	fbcon_cfb32_setup, pm3fb_cfbX_bmove, pm3fb_cfb32_clear,
+	pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc,
+	NULL /* cursor() */ , NULL /* set_font() */ ,
+	pm3fb_cfb32_clear_margins,
+	FONTWIDTHRANGE(1, 16)	/* true only if accelerated... */
+};
+#endif /* FBCON_HAS_CFB32 */
+#ifdef FBCON_HAS_CFB16
+static struct display_switch pm3fb_cfb16 = {
+	fbcon_cfb16_setup, pm3fb_cfbX_bmove, pm3fb_cfb16_clear,
+	pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc,
+	NULL /* cursor() */ , NULL /* set_font() */ ,
+	pm3fb_cfb16_clear_margins,
+	FONTWIDTHRANGE(1, 16)	/* true only if accelerated... */
+};
+#endif /* FBCON_HAS_CFB16 */
+#ifdef FBCON_HAS_CFB8
+static struct display_switch pm3fb_cfb8 = {
+	fbcon_cfb8_setup, pm3fb_cfbX_bmove, pm3fb_cfb8_clear,
+	pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc,
+	NULL /* cursor() */ , NULL /* set_font() */ ,
+	pm3fb_cfb8_clear_margins,
+	FONTWIDTHRANGE(1, 16)	/* true only if accelerated... */
+};
+#endif /* FBCON_HAS_CFB8 */
+#endif /* PM3FB_USE_ACCEL */
+
+/* ****************************** */
+/* ***** card-specific data ***** */
+/* ****************************** */
+struct pm3fb_card_timings {
+	unsigned long memsize; /* 0 for last value (i.e. default) */
+	struct pm3fb_timings memt;
+};
+
+static struct pm3fb_card_timings t_FormacProFormance3[] = {
+	{ 16, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} },
+	{ 0, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} } /* from 16 MB PF3 */
+};
+
+static struct pm3fb_card_timings t_AppianJeronimo2000[] = {
+	{ 32, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} },
+	{ 0, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} } /* from 32MB J2000 */
+};
+
+static struct pm3fb_card_timings t_3DLabsOxygenVX1[] = {
+	{ 32, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} },
+	{ 0, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} } /* from 32MB VX1 */
+};
+
+static struct {
+		char cardname[32]; /* recognized card name */
+		u16 subvendor; /* subvendor of the card */
+		u16 subdevice; /* subdevice of the card */
+		u8  func; /* function of the card to which the extra init apply */
+		void (*specific_setup)(struct pm3fb_info *l_fb_info); /* card/func specific setup, done before _any_ FB access */
+	struct pm3fb_card_timings *c_memt; /* defauls timings for the boards */
+} cardbase[] = {
+	{ "Unknown Permedia3 board", 0xFFFF, 0xFFFF, 0xFF, NULL, NULL },
+	{ "Appian Jeronimo 2000 head 1", 0x1097, 0x3d32, 1, NULL,
+	  t_AppianJeronimo2000
+	},
+	{ "Appian Jeronimo 2000 head 2", 0x1097, 0x3d32, 2, pm3fb_j2000_setup,
+	  t_AppianJeronimo2000
+	},
+	{ "Formac ProFormance 3", PCI_VENDOR_ID_3DLABS, 0x000a, 0, NULL, /* Formac use 3DLabs ID ?!? */
+	  t_FormacProFormance3
+	},
+	{ "3DLabs Permedia3 Create!", PCI_VENDOR_ID_3DLABS, 0x0127, 0, NULL, NULL },
+	{ "3DLabs Oxygen VX1 PCI", PCI_VENDOR_ID_3DLABS, 0x0121, 0, NULL,
+	  t_3DLabsOxygenVX1
+	},
+	{ "3DLabs Oxygen VX1 AGP", PCI_VENDOR_ID_3DLABS, 0x0125, 0, NULL, NULL },
+	{ "3DLabs Oxygen VX1-16 AGP", PCI_VENDOR_ID_3DLABS, 0x0140, 0, NULL, NULL },
+	{ "3DLabs Oxygen VX1-1600SW PCI", PCI_VENDOR_ID_3DLABS, 0x0800, 0, NULL, NULL },
+	{ "\0", 0x0, 0x0, 0, NULL, NULL }
+};
+
+/* ********************************** */
+/* ***** card-specific function ***** */
+/* ********************************** */
+static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info)
+{       /* the appian j2000 require more initialization of the second head */
+	/* l_fb_info must point to the _second_ head of the J2000 */
+	
+	DTRACE;
+
+	l_fb_info->memt = t_AppianJeronimo2000[0].memt; /* 32 MB, first and only j2000 ? */
+	
+	pm3fb_write_memory_timings(l_fb_info);
+}
+
+/* *************************************** */
+/* ***** permedia3-specific function ***** */
+/* *************************************** */
+static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info)
+{
+	l_fb_info->memt.caps = PM3_READ_REG(PM3LocalMemCaps);
+	l_fb_info->memt.timings = PM3_READ_REG(PM3LocalMemTimings);
+	l_fb_info->memt.control = PM3_READ_REG(PM3LocalMemControl);
+	l_fb_info->memt.refresh = PM3_READ_REG(PM3LocalMemRefresh);
+	l_fb_info->memt.powerdown = PM3_READ_REG(PM3LocalMemPowerDown);
+
+	if ((l_fb_info->memt.caps == PM3FB_UNKNOWN_TIMING_VALUE) ||
+	    (l_fb_info->memt.timings == PM3FB_UNKNOWN_TIMING_VALUE) ||
+	    (l_fb_info->memt.control == PM3FB_UNKNOWN_TIMING_VALUE) ||
+	    (l_fb_info->memt.refresh == PM3FB_UNKNOWN_TIMING_VALUE) ||
+	    (l_fb_info->memt.powerdown == PM3FB_UNKNOWN_TIMING_VALUE))
+	{
+		printk(KERN_ERR "pm3fb: invalid memory timings in permedia3 board #%ld\n", l_fb_info->board_num);
+		return(pm3fb_try_memory_timings(l_fb_info));
+	}
+	return(pm3fb_timing_ok);
+}
+
+static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info)
+{
+	if (cardbase[l_fb_info->board_type].c_memt)
+	{
+		int i = 0, done = 0;
+		while (!done)
+		{
+			if ((cardbase[l_fb_info->board_type].c_memt[i].memsize == l_fb_info->fb_size)
+			    || !(cardbase[l_fb_info->board_type].c_memt[i].memsize))
+			{ /* will use the 0-sized timings by default */
+				done = 1;
+				l_fb_info->memt = cardbase[l_fb_info->board_type].c_memt[i].memt;
+				printk(KERN_WARNING  "pm3fb: trying to use predefined memory timings for permedia3 board #%ld (%s, %ld MB)\n",
+				       l_fb_info->board_num,
+				       cardbase[l_fb_info->board_type].cardname,
+				       cardbase[l_fb_info->board_type].c_memt[i].memsize);
+				pm3fb_write_memory_timings(l_fb_info);
+				return(pm3fb_timing_retry);
+			}
+			i++;
+		}
+	} else
+		return(pm3fb_timing_problem);
+	return(pm3fb_timing_ok);
+}
+
+static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info)
+{
+	unsigned char m, n, p;
+	unsigned long clockused;
+	
+	PM3_SLOW_WRITE_REG(PM3LocalMemCaps, l_fb_info->memt.caps);
+	PM3_SLOW_WRITE_REG(PM3LocalMemTimings, l_fb_info->memt.timings);
+	PM3_SLOW_WRITE_REG(PM3LocalMemControl, l_fb_info->memt.control);
+	PM3_SLOW_WRITE_REG(PM3LocalMemRefresh, l_fb_info->memt.refresh);
+	PM3_SLOW_WRITE_REG(PM3LocalMemPowerDown, l_fb_info->memt.powerdown);
+
+	clockused =
+	    pm3fb_CalculateClock(l_fb_info, 2 * 105000, PM3_REF_CLOCK, &m,
+				 &n, &p);
+
+	PM3_WRITE_DAC_REG(PM3RD_KClkPreScale, m);
+	PM3_WRITE_DAC_REG(PM3RD_KClkFeedbackScale, n);
+	PM3_WRITE_DAC_REG(PM3RD_KClkPostScale, p);
+	PM3_WRITE_DAC_REG(PM3RD_KClkControl,
+			  PM3RD_KClkControl_STATE_RUN |
+			  PM3RD_KClkControl_SOURCE_PLL |
+			  PM3RD_KClkControl_ENABLE);
+	PM3_WRITE_DAC_REG(PM3RD_MClkControl,
+			  PM3RD_MClkControl_STATE_RUN |
+			  PM3RD_MClkControl_SOURCE_KCLK |
+			  PM3RD_MClkControl_ENABLE);
+	PM3_WRITE_DAC_REG(PM3RD_SClkControl,
+			  PM3RD_SClkControl_STATE_RUN |
+			  PM3RD_SClkControl_SOURCE_PCLK |
+			  PM3RD_SClkControl_ENABLE);
+}
+
+static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info,
+					unsigned long r)
+{
+	DASSERT((l_fb_info->vIOBase != (unsigned char *) (-1)),
+		"l_fb_info->vIOBase mapped in read dac reg\n");
+	PM3_SET_INDEX(r);
+	mb();
+	return (PM3_READ_REG(PM3RD_IndexedData));
+}
+
+/* Calculating various clock parameter */
+static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock,	/* In kHz units */
+					  unsigned long refclock,	/* In kHz units */
+					  unsigned char *prescale,	/* ClkPreScale */
+					  unsigned char *feedback,	/* ClkFeedBackScale */
+					  unsigned char *postscale
+					  /* ClkPostScale */ )
+{
+	int f, pre, post;
+	unsigned long freq;
+	long freqerr = 1000;
+	unsigned long actualclock = 0;
+
+	DTRACE;
+
+	for (f = 1; f < 256; f++) {
+		for (pre = 1; pre < 256; pre++) {
+			for (post = 0; post < 5; post++) {
+				freq =
+				    ((2 * refclock * f) /
+				     (pre * (1 << post)));
+				if ((reqclock > freq - freqerr)
+				    && (reqclock < freq + freqerr)) {
+					freqerr =
+					    (reqclock >
+					     freq) ? reqclock -
+					    freq : freq - reqclock;
+					*feedback = f;
+					*prescale = pre;
+					*postscale = post;
+					actualclock = freq;
+				}
+			}
+		}
+	}
+
+	return (actualclock);
+}
+
+static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info,
+			  unsigned long depth, int v)
+{
+	DTRACE;
+	
+	switch (depth) {
+	case 8:
+		return (v >> 4);
+	case 12:
+	case 15:
+	case 16:
+		return (v >> 3);
+	case 32:
+		return (v >> 2);
+	}
+	DPRINTK(1, "Unsupported depth %ld\n", depth);
+	return (0);
+}
+
+static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info,
+			    unsigned long depth, int v)
+{
+	DTRACE;
+
+	switch (depth) {
+	case 8:
+		return (v << 4);
+	case 12:	
+	case 15:
+	case 16:
+		return (v << 3);
+	case 32:
+		return (v << 2);
+	}
+	DPRINTK(1, "Unsupported depth %ld\n", depth);
+	return (0);
+}
+
+static void pm3fb_mapIO(struct pm3fb_info *l_fb_info)
+{
+	DTRACE;
+
+	l_fb_info->vIOBase =
+	    ioremap((unsigned long) l_fb_info->pIOBase, PM3_REGS_SIZE);
+	l_fb_info->v_fb =
+	    ioremap((unsigned long) l_fb_info->p_fb, l_fb_info->fb_size);
+	DPRINTK(2, "IO mapping : IOBase %lx / %lx, fb %lx / %lx\n",
+		(unsigned long) l_fb_info->pIOBase,
+		(unsigned long) l_fb_info->vIOBase,
+		(unsigned long) l_fb_info->p_fb,
+		(unsigned long) l_fb_info->v_fb);
+}
+
+static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info)
+{
+	DTRACE;
+
+	iounmap(l_fb_info->vIOBase);
+	iounmap(l_fb_info->v_fb);
+	l_fb_info->vIOBase = (unsigned char *) -1;
+	l_fb_info->v_fb = (unsigned char *) -1;
+}
+
+#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2)
+static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info)
+{
+	DPRINTK(2, "PM3Aperture0: 0x%08x\n", PM3_READ_REG(PM3Aperture0));
+	DPRINTK(2, "PM3Aperture1: 0x%08x\n", PM3_READ_REG(PM3Aperture1));
+	DPRINTK(2, "PM3ByAperture1Mode: 0x%08x\n",
+		PM3_READ_REG(PM3ByAperture1Mode));
+	DPRINTK(2, "PM3ByAperture2Mode: 0x%08x\n",
+		PM3_READ_REG(PM3ByAperture2Mode));
+	DPRINTK(2, "PM3ChipConfig: 0x%08x\n", PM3_READ_REG(PM3ChipConfig));
+	DPRINTK(2, "PM3FIFODis: 0x%08x\n", PM3_READ_REG(PM3FIFODis));
+	DPRINTK(2, "PM3HTotal: 0x%08x\n", PM3_READ_REG(PM3HTotal));
+	DPRINTK(2, "PM3HbEnd: 0x%08x\n", PM3_READ_REG(PM3HbEnd));
+	DPRINTK(2, "PM3HgEnd: 0x%08x\n", PM3_READ_REG(PM3HgEnd));
+	DPRINTK(2, "PM3HsEnd: 0x%08x\n", PM3_READ_REG(PM3HsEnd));
+	DPRINTK(2, "PM3HsStart: 0x%08x\n", PM3_READ_REG(PM3HsStart));
+	DPRINTK(2, "PM3MemBypassWriteMask: 0x%08x\n",
+		PM3_READ_REG(PM3MemBypassWriteMask));
+	DPRINTK(2, "PM3RD_IndexControl: 0x%08x\n",
+		PM3_READ_REG(PM3RD_IndexControl));
+	DPRINTK(2, "PM3ScreenBase: 0x%08x\n", PM3_READ_REG(PM3ScreenBase));
+	DPRINTK(2, "PM3ScreenStride: 0x%08x\n",
+		PM3_READ_REG(PM3ScreenStride));
+	DPRINTK(2, "PM3VClkCtl: 0x%08x\n", PM3_READ_REG(PM3VClkCtl));
+	DPRINTK(2, "PM3VTotal: 0x%08x\n", PM3_READ_REG(PM3VTotal));
+	DPRINTK(2, "PM3VbEnd: 0x%08x\n", PM3_READ_REG(PM3VbEnd));
+	DPRINTK(2, "PM3VideoControl: 0x%08x\n",
+		PM3_READ_REG(PM3VideoControl));
+	DPRINTK(2, "PM3VsEnd: 0x%08x\n", PM3_READ_REG(PM3VsEnd));
+	DPRINTK(2, "PM3VsStart: 0x%08x\n", PM3_READ_REG(PM3VsStart));
+
+	DPRINTK(2, "PM3RD_ColorFormat: %ld\n",
+		PM3_READ_DAC_REG(PM3RD_ColorFormat));
+	DPRINTK(2, "PM3RD_DACControl: %ld\n",
+		PM3_READ_DAC_REG(PM3RD_DACControl));
+	DPRINTK(2, "PM3RD_DClk0FeedbackScale: %ld\n",
+		PM3_READ_DAC_REG(PM3RD_DClk0FeedbackScale));
+	DPRINTK(2, "PM3RD_DClk0PostScale: %ld\n",
+		PM3_READ_DAC_REG(PM3RD_DClk0PostScale));
+	DPRINTK(2, "PM3RD_DClk0PreScale: %ld\n",
+		PM3_READ_DAC_REG(PM3RD_DClk0PreScale));
+	DPRINTK(2, "[not set] PM3RD_IndexControl: %ld\n",
+		PM3_READ_DAC_REG(PM3RD_IndexControl));
+	DPRINTK(2, "PM3RD_MiscControl: %ld\n",
+		PM3_READ_DAC_REG(PM3RD_MiscControl));
+	DPRINTK(2, "PM3RD_PixelSize: %ld\n",
+		PM3_READ_DAC_REG(PM3RD_PixelSize));
+	DPRINTK(2, "PM3RD_SyncControl: %ld\n",
+		PM3_READ_DAC_REG(PM3RD_SyncControl));
+}
+
+#endif /* defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2) */
+static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info)
+{
+	u16 subvendor, subdevice;
+
+	if ((!pci_read_config_word
+	     (l_fb_info->dev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor))
+	    &&
+	    (!pci_read_config_word
+	     (l_fb_info->dev, PCI_SUBSYSTEM_ID, &subdevice))) {
+		/* well, nothing... */
+	} else {
+		subvendor = subdevice = (u16)-1;
+	}
+
+	printk(KERN_INFO "pm3fb: memory timings for board #%ld (subvendor: 0x%hx, subdevice: 0x%hx)\n", l_fb_info->board_num, subvendor, subdevice);
+	printk(KERN_INFO " PM3LocalMemCaps: 0x%08x\n",
+	       PM3_READ_REG(PM3LocalMemCaps));
+	printk(KERN_INFO " PM3LocalMemTimings: 0x%08x\n",
+	       PM3_READ_REG(PM3LocalMemTimings));
+	printk(KERN_INFO " PM3LocalMemControl: 0x%08x\n",
+	       PM3_READ_REG(PM3LocalMemControl));
+	printk(KERN_INFO " PM3LocalMemRefresh: 0x%08x\n",
+	       PM3_READ_REG(PM3LocalMemRefresh));
+	printk(KERN_INFO " PM3LocalMemPowerDown: 0x%08x\n",
+	       PM3_READ_REG(PM3LocalMemPowerDown));
+}
+
+/* write the mode to registers */
+static void pm3fb_write_mode(struct pm3fb_info *l_fb_info)
+{
+	char tempsync = 0x00, tempmisc = 0x00;
+	DTRACE;
+
+	PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, 0xffffffff);
+	PM3_SLOW_WRITE_REG(PM3Aperture0, 0x00000000);
+	PM3_SLOW_WRITE_REG(PM3Aperture1, 0x00000000);
+	PM3_SLOW_WRITE_REG(PM3FIFODis, 0x00000007);
+
+	PM3_SLOW_WRITE_REG(PM3HTotal,
+			   pm3fb_Shiftbpp(l_fb_info,
+					  l_fb_info->current_par->depth,
+					  l_fb_info->current_par->htotal -
+					  1));
+	PM3_SLOW_WRITE_REG(PM3HsEnd,
+			   pm3fb_Shiftbpp(l_fb_info,
+					  l_fb_info->current_par->depth,
+					  l_fb_info->current_par->hsend));
+	PM3_SLOW_WRITE_REG(PM3HsStart,
+			   pm3fb_Shiftbpp(l_fb_info,
+					  l_fb_info->current_par->depth,
+					  l_fb_info->current_par->
+					  hsstart));
+	PM3_SLOW_WRITE_REG(PM3HbEnd,
+			   pm3fb_Shiftbpp(l_fb_info,
+					  l_fb_info->current_par->depth,
+					  l_fb_info->current_par->hbend));
+	PM3_SLOW_WRITE_REG(PM3HgEnd,
+			   pm3fb_Shiftbpp(l_fb_info,
+					  l_fb_info->current_par->depth,
+					  l_fb_info->current_par->hbend));
+	PM3_SLOW_WRITE_REG(PM3ScreenStride,
+			   pm3fb_Shiftbpp(l_fb_info,
+					  l_fb_info->current_par->depth,
+					  l_fb_info->current_par->stride));
+	PM3_SLOW_WRITE_REG(PM3VTotal, l_fb_info->current_par->vtotal - 1);
+	PM3_SLOW_WRITE_REG(PM3VsEnd, l_fb_info->current_par->vsend - 1);
+	PM3_SLOW_WRITE_REG(PM3VsStart,
+			   l_fb_info->current_par->vsstart - 1);
+	PM3_SLOW_WRITE_REG(PM3VbEnd, l_fb_info->current_par->vbend);
+
+	switch (l_fb_info->current_par->depth) {
+	case 8:
+		PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+				   PM3ByApertureMode_PIXELSIZE_8BIT);
+		PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+				   PM3ByApertureMode_PIXELSIZE_8BIT);
+		break;
+
+	case 12:
+	case 15:
+	case 16:
+#ifndef __BIG_ENDIAN
+		PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+				   PM3ByApertureMode_PIXELSIZE_16BIT);
+		PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+				   PM3ByApertureMode_PIXELSIZE_16BIT);
+#else
+		PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+				   PM3ByApertureMode_PIXELSIZE_16BIT |
+				   PM3ByApertureMode_BYTESWAP_BADC);
+		PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+				   PM3ByApertureMode_PIXELSIZE_16BIT |
+				   PM3ByApertureMode_BYTESWAP_BADC);
+#endif /* ! __BIG_ENDIAN */
+		break;
+
+	case 32:
+#ifndef __BIG_ENDIAN
+		PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+				   PM3ByApertureMode_PIXELSIZE_32BIT);
+		PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+				   PM3ByApertureMode_PIXELSIZE_32BIT);
+#else
+		PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+				   PM3ByApertureMode_PIXELSIZE_32BIT |
+				   PM3ByApertureMode_BYTESWAP_DCBA);
+		PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+				   PM3ByApertureMode_PIXELSIZE_32BIT |
+				   PM3ByApertureMode_BYTESWAP_DCBA);
+#endif /* ! __BIG_ENDIAN */
+		break;
+
+	default:
+		DPRINTK(1, "Unsupported depth %d\n",
+			l_fb_info->current_par->depth);
+		break;
+	}
+
+	/*
+	 * Oxygen VX1 - it appears that setting PM3VideoControl and
+	 * then PM3RD_SyncControl to the same SYNC settings undoes
+	 * any net change - they seem to xor together.  Only set the
+	 * sync options in PM3RD_SyncControl.  --rmk
+	 */
+	{
+		unsigned int video = l_fb_info->current_par->video;
+
+		video &= ~(PM3VideoControl_HSYNC_MASK |
+			   PM3VideoControl_VSYNC_MASK);
+		video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |
+			 PM3VideoControl_VSYNC_ACTIVE_HIGH;
+		PM3_SLOW_WRITE_REG(PM3VideoControl, video);
+	}
+	PM3_SLOW_WRITE_REG(PM3VClkCtl,
+			   (PM3_READ_REG(PM3VClkCtl) & 0xFFFFFFFC));
+	PM3_SLOW_WRITE_REG(PM3ScreenBase, l_fb_info->current_par->base);
+	PM3_SLOW_WRITE_REG(PM3ChipConfig,
+			   (PM3_READ_REG(PM3ChipConfig) & 0xFFFFFFFD));
+
+	{
+		unsigned char m;	/* ClkPreScale */
+		unsigned char n;	/* ClkFeedBackScale */
+		unsigned char p;	/* ClkPostScale */
+		(void)pm3fb_CalculateClock(l_fb_info, l_fb_info->current_par->pixclock, PM3_REF_CLOCK, &m, &n, &p);
+
+		DPRINTK(2,
+			"Pixclock: %d, Pre: %d, Feedback: %d, Post: %d\n",
+			l_fb_info->current_par->pixclock, (int) m, (int) n,
+			(int) p);
+
+		PM3_WRITE_DAC_REG(PM3RD_DClk0PreScale, m);
+		PM3_WRITE_DAC_REG(PM3RD_DClk0FeedbackScale, n);
+		PM3_WRITE_DAC_REG(PM3RD_DClk0PostScale, p);
+	}
+	/*
+	   PM3_WRITE_DAC_REG(PM3RD_IndexControl, 0x00);
+	 */
+	/*
+	   PM3_SLOW_WRITE_REG(PM3RD_IndexControl, 0x00);
+	 */
+	if ((l_fb_info->current_par->video & PM3VideoControl_HSYNC_MASK) ==
+	    PM3VideoControl_HSYNC_ACTIVE_HIGH)
+		tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH;
+	if ((l_fb_info->current_par->video & PM3VideoControl_VSYNC_MASK) ==
+	    PM3VideoControl_VSYNC_ACTIVE_HIGH)
+		tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH;
+	
+	PM3_WRITE_DAC_REG(PM3RD_SyncControl, tempsync);
+	DPRINTK(2, "PM3RD_SyncControl: %d\n", tempsync);
+	
+	if (flatpanel[l_fb_info->board_num])
+	{
+		PM3_WRITE_DAC_REG(PM3RD_DACControl, PM3RD_DACControl_BLANK_PEDESTAL_ENABLE);
+		PM3_WAIT(2);
+		PM3_WRITE_REG(PM3VSConfiguration, 0x06);
+		PM3_WRITE_REG(0x5a00, 1 << 14); /* black magic... */
+		tempmisc = PM3RD_MiscControl_VSB_OUTPUT_ENABLE;
+	}
+	else
+		PM3_WRITE_DAC_REG(PM3RD_DACControl, 0x00);
+
+	switch (l_fb_info->current_par->depth) {
+	case 8:
+		PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+				  PM3RD_PixelSize_8_BIT_PIXELS);
+		PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+				  PM3RD_ColorFormat_CI8_COLOR |
+				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW);
+		tempmisc |= PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
+		break;
+	case 12:
+		PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+				  PM3RD_PixelSize_16_BIT_PIXELS);
+		PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+				  PM3RD_ColorFormat_4444_COLOR |
+				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
+				  PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
+		tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
+			PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
+		break;		
+	case 15:
+		PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+				  PM3RD_PixelSize_16_BIT_PIXELS);
+		PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+				  PM3RD_ColorFormat_5551_FRONT_COLOR |
+				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
+				  PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
+		tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
+			PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
+		break;		
+	case 16:
+		PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+				  PM3RD_PixelSize_16_BIT_PIXELS);
+		PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+				  PM3RD_ColorFormat_565_FRONT_COLOR |
+				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
+				  PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
+		tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
+			PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
+		break;
+	case 32:
+		PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+				  PM3RD_PixelSize_32_BIT_PIXELS);
+		PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+				  PM3RD_ColorFormat_8888_COLOR |
+				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW);
+		tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
+			PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
+		break;
+	}
+	PM3_WRITE_DAC_REG(PM3RD_MiscControl, tempmisc);
+	
+	PM3_SHOW_CUR_MODE;
+}
+
+static void pm3fb_read_mode(struct pm3fb_info *l_fb_info,
+			    struct pm3fb_par *curpar)
+{
+	unsigned long pixsize1, pixsize2, clockused;
+	unsigned long pre, feedback, post;
+
+	DTRACE;
+
+	clockused = PM3_READ_REG(PM3VClkCtl);
+
+	switch (clockused) {
+	case 3:
+		pre = PM3_READ_DAC_REG(PM3RD_DClk3PreScale);
+		feedback = PM3_READ_DAC_REG(PM3RD_DClk3FeedbackScale);
+		post = PM3_READ_DAC_REG(PM3RD_DClk3PostScale);
+
+		DPRINTK(2,
+			"DClk3 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
+			pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
+								feedback,
+								post));
+		break;
+	case 2:
+		pre = PM3_READ_DAC_REG(PM3RD_DClk2PreScale);
+		feedback = PM3_READ_DAC_REG(PM3RD_DClk2FeedbackScale);
+		post = PM3_READ_DAC_REG(PM3RD_DClk2PostScale);
+
+		DPRINTK(2,
+			"DClk2 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
+			pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
+								feedback,
+								post));
+		break;
+	case 1:
+		pre = PM3_READ_DAC_REG(PM3RD_DClk1PreScale);
+		feedback = PM3_READ_DAC_REG(PM3RD_DClk1FeedbackScale);
+		post = PM3_READ_DAC_REG(PM3RD_DClk1PostScale);
+
+		DPRINTK(2,
+			"DClk1 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
+			pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
+								feedback,
+								post));
+		break;
+	case 0:
+		pre = PM3_READ_DAC_REG(PM3RD_DClk0PreScale);
+		feedback = PM3_READ_DAC_REG(PM3RD_DClk0FeedbackScale);
+		post = PM3_READ_DAC_REG(PM3RD_DClk0PostScale);
+
+		DPRINTK(2,
+			"DClk0 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
+			pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
+								feedback,
+								post));
+		break;
+	default:
+		pre = feedback = post = 0;
+		DPRINTK(1, "Unknowk D clock used : %ld\n", clockused);
+		break;
+	}
+
+	curpar->pixclock = PM3_SCALE_TO_CLOCK(pre, feedback, post);
+
+	pixsize1 =
+	    PM3ByApertureMode_PIXELSIZE_MASK &
+	    (PM3_READ_REG(PM3ByAperture1Mode));
+	pixsize2 =
+	    PM3ByApertureMode_PIXELSIZE_MASK &
+	    (PM3_READ_REG(PM3ByAperture2Mode));
+
+	DASSERT((pixsize1 == pixsize2),
+		"pixsize the same in both aperture\n");
+
+	if (pixsize1 & PM3ByApertureMode_PIXELSIZE_32BIT)
+		curpar->depth = 32;
+	else if (pixsize1 & PM3ByApertureMode_PIXELSIZE_16BIT)
+	{
+		curpar->depth = 16;
+	}
+	else
+		curpar->depth = 8;
+
+	/* not sure if I need to add one on the next ; it give better result with */
+	curpar->htotal =
+	    pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
+			     1 + PM3_READ_REG(PM3HTotal));
+	curpar->hsend =
+	    pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
+			     PM3_READ_REG(PM3HsEnd));
+	curpar->hsstart =
+	    pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
+			     PM3_READ_REG(PM3HsStart));
+	curpar->hbend =
+	    pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
+			     PM3_READ_REG(PM3HbEnd));
+
+	curpar->stride =
+	    pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
+			     PM3_READ_REG(PM3ScreenStride));
+
+	curpar->vtotal = 1 + PM3_READ_REG(PM3VTotal);
+	curpar->vsend = 1 + PM3_READ_REG(PM3VsEnd);
+	curpar->vsstart = 1 + PM3_READ_REG(PM3VsStart);
+	curpar->vbend = PM3_READ_REG(PM3VbEnd);
+
+	curpar->video = PM3_READ_REG(PM3VideoControl);
+
+	curpar->base = PM3_READ_REG(PM3ScreenBase);
+	curpar->width = curpar->htotal - curpar->hbend; /* make virtual == displayed resolution */
+	curpar->height = curpar->vtotal - curpar->vbend;
+
+	DPRINTK(2, "Found : %d * %d, %d Khz, stride is %08x\n",
+		curpar->width, curpar->height, curpar->pixclock,
+		curpar->stride);
+}
+
+static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info)
+{
+	unsigned long memsize = 0, tempBypass, i, temp1, temp2;
+	u16 subvendor, subdevice;
+	pm3fb_timing_result ptr;
+
+	DTRACE;
+
+	l_fb_info->fb_size = 64 * 1024 * 1024;	/* pm3 aperture always 64 MB */
+	pm3fb_mapIO(l_fb_info);	/* temporary map IO */
+
+	DASSERT((l_fb_info->vIOBase != NULL),
+		"IO successfully mapped before mem detect\n");
+	DASSERT((l_fb_info->v_fb != NULL),
+		"FB successfully mapped before mem detect\n");
+
+	/* card-specific stuff, *before* accessing *any* FB memory */
+	if ((!pci_read_config_word
+	     (l_fb_info->dev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor))
+	    &&
+	    (!pci_read_config_word
+	     (l_fb_info->dev, PCI_SUBSYSTEM_ID, &subdevice))) {
+		i = 0; l_fb_info->board_type = 0;
+		while ((cardbase[i].cardname[0]) && !(l_fb_info->board_type)) {
+			if ((cardbase[i].subvendor == subvendor) &&
+			    (cardbase[i].subdevice == subdevice) &&
+			    (cardbase[i].func == PCI_FUNC(l_fb_info->dev->devfn))) {
+				DPRINTK(2, "Card #%ld is an %s\n",
+					l_fb_info->board_num,
+					cardbase[i].cardname);
+				if (cardbase[i].specific_setup)
+					cardbase[i].specific_setup(l_fb_info);
+				l_fb_info->board_type = i;
+			}
+			i++;
+		}
+		if (!l_fb_info->board_type) {
+			DPRINTK(1, "Card #%ld is an unknown 0x%04x / 0x%04x\n",
+				l_fb_info->board_num, subvendor, subdevice);
+		}
+	} else {
+		printk(KERN_ERR "pm3fb: Error: pci_read_config_word failed, board #%ld\n",
+		       l_fb_info->board_num);
+	}
+
+	if (printtimings)
+		pm3fb_show_cur_timing(l_fb_info);
+	
+	/* card-specific setup is done, we preserve the final
+           memory timing for future reference */
+	if ((ptr = pm3fb_preserve_memory_timings(l_fb_info)) == pm3fb_timing_problem) { /* memory timings were wrong ! oops.... */
+		return(0);
+	}
+	
+	tempBypass = PM3_READ_REG(PM3MemBypassWriteMask);
+
+	DPRINTK(2, "PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass);
+
+	PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, 0xFFFFFFFF);
+
+	/* pm3 split up memory, replicates, and do a lot of nasty stuff IMHO ;-) */
+	for (i = 0; i < 32; i++) {
+		fb_writel(i * 0x00345678,
+			  (l_fb_info->v_fb + (i * 1048576)));
+		mb();
+		temp1 = fb_readl((l_fb_info->v_fb + (i * 1048576)));
+
+		/* Let's check for wrapover, write will fail at 16MB boundary */
+		if (temp1 == (i * 0x00345678))
+			memsize = i;
+		else
+			break;
+	}
+
+	DPRINTK(2, "First detect pass already got %ld MB\n", memsize + 1);
+
+	if (memsize == i) {
+		for (i = 0; i < 32; i++) {
+			/* Clear first 32MB ; 0 is 0, no need to byteswap */
+			writel(0x0000000,
+			       (l_fb_info->v_fb + (i * 1048576)));
+			mb();
+		}
+
+		for (i = 32; i < 64; i++) {
+			fb_writel(i * 0x00345678,
+				  (l_fb_info->v_fb + (i * 1048576)));
+			mb();
+			temp1 =
+			    fb_readl((l_fb_info->v_fb + (i * 1048576)));
+			temp2 =
+			    fb_readl((l_fb_info->v_fb +
+				      ((i - 32) * 1048576)));
+			if ((temp1 == (i * 0x00345678)) && (temp2 == 0))	/* different value, different RAM... */
+				memsize = i;
+			else
+				break;
+		}
+	}
+
+	DPRINTK(2, "Second detect pass got %ld MB\n", memsize + 1);
+
+	PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, tempBypass);
+
+	pm3fb_unmapIO(l_fb_info);
+	memsize = 1048576 * (memsize + 1);
+
+	DPRINTK(2, "Returning 0x%08lx bytes\n", memsize);
+
+	if (forcesize[l_fb_info->board_num] && ((forcesize[l_fb_info->board_num] * 1048576) != memsize))
+	{
+		printk(KERN_WARNING "pm3fb: mismatch between probed (%ld MB) and specified (%hd MB) memory size, using SPECIFIED !\n", memsize, forcesize[l_fb_info->board_num]);
+		memsize = 1048576 * forcesize[l_fb_info->board_num];
+	}
+	
+	l_fb_info->fb_size = memsize;
+	
+	if (ptr == pm3fb_timing_retry)
+	{
+		printk(KERN_WARNING "pm3fb: retrying memory timings check");
+		if (pm3fb_try_memory_timings(l_fb_info) == pm3fb_timing_problem)
+			return(0);
+	}
+	
+	return (memsize);
+}
+
+static void pm3fb_clear_memory(struct pm3fb_info *l_fb_info, u32 cc)
+{
+	int i;
+
+	DTRACE;
+
+	for (i = 0; i < (l_fb_info->fb_size / sizeof(u32)) ; i++) /* clear entire FB memory to black */
+	{
+		fb_writel(cc, (l_fb_info->v_fb + (i * sizeof(u32))));
+	}
+}
+
+static void pm3fb_clear_colormap(struct pm3fb_info *l_fb_info, unsigned char r, unsigned char g, unsigned char b)
+{
+	int i;
+
+	DTRACE;
+
+	for (i = 0; i < 256 ; i++) /* fill color map with white */
+		pm3fb_set_color(l_fb_info, i, r, g, b);
+
+}
+
+/* common initialisation */
+static void pm3fb_common_init(struct pm3fb_info *l_fb_info)
+{
+	DTRACE;
+
+	DPRINTK(2, "Initializing board #%ld @ %lx\n", l_fb_info->board_num,
+		(unsigned long) l_fb_info);
+
+	strcpy(l_fb_info->gen.info.modename, permedia3_name);
+	disp[l_fb_info->board_num].scrollmode = 0;	/* SCROLL_YNOMOVE; *//* 0 means "let fbcon choose" */
+	l_fb_info->gen.parsize = sizeof(struct pm3fb_par);
+	l_fb_info->gen.info.changevar = NULL;
+	l_fb_info->gen.info.fbops = &pm3fb_ops;
+	l_fb_info->gen.info.disp = &(disp[l_fb_info->board_num]);
+	if (fontn[l_fb_info->board_num][0])
+		strcpy(l_fb_info->gen.info.fontname,
+		       fontn[l_fb_info->board_num]);
+	l_fb_info->gen.info.switch_con = &fbgen_switch;
+	l_fb_info->gen.info.updatevar = &fbgen_update_var;	/* */
+	l_fb_info->gen.info.flags = FBINFO_FLAG_DEFAULT;
+
+	pm3fb_mapIO(l_fb_info);
+
+	pm3fb_clear_memory(l_fb_info, 0);
+	pm3fb_clear_colormap(l_fb_info, 0, 0, 0);
+
+	(void) fbgen_get_var(&(disp[l_fb_info->board_num]).var, -1,
+			     &l_fb_info->gen.info);
+
+	if (depth[l_fb_info->board_num]) /* override mode-defined depth */
+	{
+		pm3fb_encode_depth(&(disp[l_fb_info->board_num]).var, depth[l_fb_info->board_num]);
+		(disp[l_fb_info->board_num]).var.bits_per_pixel = depth2bpp(depth[l_fb_info->board_num]);
+	}
+
+	(void) fbgen_do_set_var(&(disp[l_fb_info->board_num]).var, 1,
+				&l_fb_info->gen);
+
+	fbgen_set_disp(-1, &l_fb_info->gen);
+
+	do_install_cmap(0, &l_fb_info->gen.info);
+
+	if (register_framebuffer(&l_fb_info->gen.info) < 0) {
+		DPRINTK(1, "Couldn't register framebuffer\n");
+		return;
+	}
+
+	PM3_WRITE_DAC_REG(PM3RD_CursorMode,
+			  PM3RD_CursorMode_CURSOR_DISABLE);
+	
+	PM3_SHOW_CUR_MODE;
+	
+	pm3fb_write_mode(l_fb_info);
+	
+	printk("fb%d: %s, using %uK of video memory (%s)\n",
+	       l_fb_info->gen.info.node,
+	       permedia3_name, (u32) (l_fb_info->fb_size >> 10),
+	       cardbase[l_fb_info->board_type].cardname);
+}
+
+/* **************************************************** */
+/* ***** accelerated permedia3-specific functions ***** */
+/* **************************************************** */
+#ifdef PM3FB_USE_ACCEL
+static void pm3fb_wait_pm3(struct pm3fb_info *l_fb_info)
+{
+	DTRACE;
+
+	PM3_SLOW_WRITE_REG(PM3FilterMode, PM3FilterModeSync);
+	PM3_SLOW_WRITE_REG(PM3Sync, 0);
+	mb();
+	do {
+		while ((PM3_READ_REG(PM3OutFIFOWords)) == 0);
+		rmb();
+	} while ((PM3_READ_REG(PM3OutputFifo)) != PM3Sync_Tag);
+}
+
+static void pm3fb_init_engine(struct pm3fb_info *l_fb_info)
+{
+	PM3_SLOW_WRITE_REG(PM3FilterMode, PM3FilterModeSync);
+	PM3_SLOW_WRITE_REG(PM3StatisticMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3DeltaMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3RasterizerMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3ScissorMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3LineStippleMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3AreaStippleMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3GIDMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3DepthMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3StencilMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3StencilData, 0x0);
+	PM3_SLOW_WRITE_REG(PM3ColorDDAMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3TextureCoordMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3TextureIndexMode0, 0x0);
+	PM3_SLOW_WRITE_REG(PM3TextureIndexMode1, 0x0);
+	PM3_SLOW_WRITE_REG(PM3TextureReadMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3LUTMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3TextureFilterMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3TextureCompositeMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3TextureApplicationMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3TextureCompositeColorMode1, 0x0);
+	PM3_SLOW_WRITE_REG(PM3TextureCompositeAlphaMode1, 0x0);
+	PM3_SLOW_WRITE_REG(PM3TextureCompositeColorMode0, 0x0);
+	PM3_SLOW_WRITE_REG(PM3TextureCompositeAlphaMode0, 0x0);
+	PM3_SLOW_WRITE_REG(PM3FogMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3ChromaTestMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3AlphaTestMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3AntialiasMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3YUVMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3AlphaBlendColorMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3AlphaBlendAlphaMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3DitherMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3LogicalOpMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3RouterMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3Window, 0x0);
+
+	PM3_SLOW_WRITE_REG(PM3Config2D, 0x0);
+
+	PM3_SLOW_WRITE_REG(PM3SpanColorMask, 0xffffffff);
+
+	PM3_SLOW_WRITE_REG(PM3XBias, 0x0);
+	PM3_SLOW_WRITE_REG(PM3YBias, 0x0);
+	PM3_SLOW_WRITE_REG(PM3DeltaControl, 0x0);
+
+	PM3_SLOW_WRITE_REG(PM3BitMaskPattern, 0xffffffff);
+
+	PM3_SLOW_WRITE_REG(PM3FBDestReadEnables,
+			   PM3FBDestReadEnables_E(0xff) |
+			   PM3FBDestReadEnables_R(0xff) |
+			   PM3FBDestReadEnables_ReferenceAlpha(0xff));
+	PM3_SLOW_WRITE_REG(PM3FBDestReadBufferAddr0, 0x0);
+	PM3_SLOW_WRITE_REG(PM3FBDestReadBufferOffset0, 0x0);
+	PM3_SLOW_WRITE_REG(PM3FBDestReadBufferWidth0,
+			   PM3FBDestReadBufferWidth_Width(l_fb_info->
+							  current_par->
+							  width));
+
+	PM3_SLOW_WRITE_REG(PM3FBDestReadMode,
+			   PM3FBDestReadMode_ReadEnable |
+			   PM3FBDestReadMode_Enable0);
+	PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferAddr, 0x0);
+	PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferOffset, 0x0);
+	PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferWidth,
+			   PM3FBSourceReadBufferWidth_Width(l_fb_info->
+							    current_par->
+							    width));
+	PM3_SLOW_WRITE_REG(PM3FBSourceReadMode,
+			   PM3FBSourceReadMode_Blocking |
+			   PM3FBSourceReadMode_ReadEnable);
+
+	{
+		unsigned long rm = 1;
+		switch (l_fb_info->current_par->depth) {
+		case 8:
+			PM3_SLOW_WRITE_REG(PM3PixelSize,
+					   PM3PixelSize_GLOBAL_8BIT);
+			break;
+		case 12:
+		case 15:
+		case 16:
+			PM3_SLOW_WRITE_REG(PM3PixelSize,
+					   PM3PixelSize_GLOBAL_16BIT);
+			break;
+		case 32:
+			PM3_SLOW_WRITE_REG(PM3PixelSize,
+					   PM3PixelSize_GLOBAL_32BIT);
+			break;
+		default:
+			DPRINTK(1, "Unsupported depth %d\n",
+				l_fb_info->current_par->depth);
+			break;
+		}
+		PM3_SLOW_WRITE_REG(PM3RasterizerMode, rm);
+	}
+
+	PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xffffffff);
+	PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xffffffff);
+	PM3_SLOW_WRITE_REG(PM3FBWriteMode,
+			   PM3FBWriteMode_WriteEnable |
+			   PM3FBWriteMode_OpaqueSpan |
+			   PM3FBWriteMode_Enable0);
+	PM3_SLOW_WRITE_REG(PM3FBWriteBufferAddr0, 0x0);
+	PM3_SLOW_WRITE_REG(PM3FBWriteBufferOffset0, 0x0);
+	PM3_SLOW_WRITE_REG(PM3FBWriteBufferWidth0,
+			   PM3FBWriteBufferWidth_Width(l_fb_info->
+						       current_par->
+						       width));
+
+	PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, 0x0);
+	{
+		unsigned long sofb = (8UL * l_fb_info->fb_size) /
+			((depth2bpp(l_fb_info->current_par->depth))
+			 * l_fb_info->current_par->width);	/* size in lines of FB */
+		if (sofb > 4095)
+			PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, 4095);
+		else
+			PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, sofb);
+		
+		switch (l_fb_info->current_par->depth) {
+		case 8:
+			PM3_SLOW_WRITE_REG(PM3DitherMode,
+					   (1 << 10) | (2 << 3));
+			break;
+		case 12:
+		case 15:
+		case 16:
+			PM3_SLOW_WRITE_REG(PM3DitherMode,
+					   (1 << 10) | (1 << 3));
+			break;
+		case 32:
+			PM3_SLOW_WRITE_REG(PM3DitherMode,
+					   (1 << 10) | (0 << 3));
+			break;
+		default:
+			DPRINTK(1, "Unsupported depth %d\n",
+				l_fb_info->current_par->depth);
+			break;
+		}
+	}
+
+	PM3_SLOW_WRITE_REG(PM3dXDom, 0x0);
+	PM3_SLOW_WRITE_REG(PM3dXSub, 0x0);
+	PM3_SLOW_WRITE_REG(PM3dY, (1 << 16));
+	PM3_SLOW_WRITE_REG(PM3StartXDom, 0x0);
+	PM3_SLOW_WRITE_REG(PM3StartXSub, 0x0);
+	PM3_SLOW_WRITE_REG(PM3StartY, 0x0);
+	PM3_SLOW_WRITE_REG(PM3Count, 0x0);
+	
+/* Disable LocalBuffer. better safe than sorry */
+	PM3_SLOW_WRITE_REG(PM3LBDestReadMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3LBDestReadEnables, 0x0);
+	PM3_SLOW_WRITE_REG(PM3LBSourceReadMode, 0x0);
+	PM3_SLOW_WRITE_REG(PM3LBWriteMode, 0x0);
+	
+	pm3fb_wait_pm3(l_fb_info);
+}
+
+#ifdef FBCON_HAS_CFB32
+static void pm3fb_cfb32_clear(struct vc_data *conp,
+			      struct display *p,
+			      int sy, int sx, int height, int width)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
+	u32 c;
+
+	DTRACE;
+
+	sx = sx * fontwidth(p);
+	width = width * fontwidth(p);
+	sy = sy * fontheight(p);
+	height = height * fontheight(p);
+	c = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
+
+	/* block fills in 32bpp are hard, but in low res (width <= 1600 :-)
+	   we can use 16bpp operations, but not if NoWriteMask is on (SDRAM)  */
+	if ((l_fb_info->current_par->width > 1600) ||
+	    (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)) {
+		PM3_WAIT(4);
+
+		PM3_WRITE_REG(PM3Config2D,
+					  PM3Config2D_UseConstantSource |
+					  PM3Config2D_ForegroundROPEnable |
+					  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+					  PM3Config2D_FBWriteEnable);
+
+		PM3_WRITE_REG(PM3ForegroundColor, c);
+
+		PM3_WRITE_REG(PM3RectanglePosition,
+			      (PM3RectanglePosition_XOffset(sx)) |
+			      (PM3RectanglePosition_YOffset(sy)));
+
+		PM3_WRITE_REG(PM3Render2D,
+			      PM3Render2D_XPositive |
+			      PM3Render2D_YPositive |
+			      PM3Render2D_Operation_Normal |
+			      PM3Render2D_SpanOperation |
+			      (PM3Render2D_Width(width)) |
+			      (PM3Render2D_Height(height)));
+	} else {
+		PM3_WAIT(8);
+
+		PM3_WRITE_REG(PM3FBBlockColor, c);
+
+		PM3_WRITE_REG(PM3PixelSize, PM3PixelSize_GLOBAL_16BIT);
+
+		PM3_WRITE_REG(PM3FBWriteBufferWidth0,
+			      PM3FBWriteBufferWidth_Width(l_fb_info->
+							  current_par->
+							  width << 1));
+
+		PM3_WRITE_REG(PM3Config2D,
+					  PM3Config2D_UseConstantSource |
+					  PM3Config2D_ForegroundROPEnable |
+					  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+					  PM3Config2D_FBWriteEnable);
+
+		PM3_WRITE_REG(PM3RectanglePosition,
+			      (PM3RectanglePosition_XOffset(sx << 1)) |
+			      (PM3RectanglePosition_YOffset(sy)));
+
+		PM3_WRITE_REG(PM3Render2D,
+			      PM3Render2D_XPositive |
+			      PM3Render2D_YPositive |
+			      PM3Render2D_Operation_Normal |
+			      (PM3Render2D_Width(width << 1)) |
+			      (PM3Render2D_Height(height)));
+
+		PM3_WRITE_REG(PM3FBWriteBufferWidth0,
+			      PM3FBWriteBufferWidth_Width(l_fb_info->
+							  current_par->
+							  width));
+
+		PM3_WRITE_REG(PM3PixelSize, PM3PixelSize_GLOBAL_32BIT);
+	}
+
+	pm3fb_wait_pm3(l_fb_info);
+}
+
+static void pm3fb_cfb32_clear_margins(struct vc_data *conp,
+				      struct display *p, int bottom_only)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
+	int sx, sy;
+	u32 c;
+
+	DTRACE;
+
+	sx = conp->vc_cols * fontwidth(p);	/* right margin */
+	sy = conp->vc_rows * fontheight(p);	/* bottom margin */
+	c = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
+
+	if (!bottom_only) {	/* right margin top->bottom */
+		PM3_WAIT(4);
+
+		PM3_WRITE_REG(PM3Config2D,
+					  PM3Config2D_UseConstantSource |
+					  PM3Config2D_ForegroundROPEnable |
+					  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+					  PM3Config2D_FBWriteEnable);
+
+		PM3_WRITE_REG(PM3ForegroundColor, c);
+
+		PM3_WRITE_REG(PM3RectanglePosition,
+			      (PM3RectanglePosition_XOffset
+			       (p->var.xoffset +
+				sx)) | (PM3RectanglePosition_YOffset(p->
+								     var.
+								     yoffset)));
+
+		PM3_WRITE_REG(PM3Render2D,
+			      PM3Render2D_XPositive |
+			      PM3Render2D_YPositive |
+			      PM3Render2D_Operation_Normal |
+			      PM3Render2D_SpanOperation |
+			      (PM3Render2D_Width(p->var.xres - sx)) |
+			      (PM3Render2D_Height(p->var.yres)));
+	}
+
+	/* bottom margin left -> right */
+	PM3_WAIT(4);
+
+	PM3_WRITE_REG(PM3Config2D,
+				  PM3Config2D_UseConstantSource |
+				  PM3Config2D_ForegroundROPEnable |
+				  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+				  PM3Config2D_FBWriteEnable);
+
+	PM3_WRITE_REG(PM3ForegroundColor, c);
+
+	PM3_WRITE_REG(PM3RectanglePosition,
+		      (PM3RectanglePosition_XOffset(p->var.xoffset)) |
+		      (PM3RectanglePosition_YOffset(p->var.yoffset + sy)));
+
+	PM3_WRITE_REG(PM3Render2D,
+		      PM3Render2D_XPositive |
+		      PM3Render2D_YPositive |
+		      PM3Render2D_Operation_Normal |
+		      PM3Render2D_SpanOperation |
+		      (PM3Render2D_Width(p->var.xres)) |
+		      (PM3Render2D_Height(p->var.yres - sy)));
+
+	pm3fb_wait_pm3(l_fb_info);
+}
+#endif /* FBCON_HAS_CFB32 */
+#ifdef FBCON_HAS_CFB16
+static void pm3fb_cfb16_clear(struct vc_data *conp,
+			      struct display *p,
+			      int sy, int sx, int height, int width)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
+	u32 c;
+
+	DTRACE;
+
+	sx = sx * fontwidth(p);
+	width = width * fontwidth(p);
+	sy = sy * fontheight(p);
+	height = height * fontheight(p);
+	c = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
+	c = c | (c << 16);
+
+	PM3_WAIT(4);
+
+	if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
+		PM3_WRITE_REG(PM3ForegroundColor, c);
+	else
+		PM3_WRITE_REG(PM3FBBlockColor, c);
+
+	PM3_WRITE_REG(PM3Config2D,
+				  PM3Config2D_UseConstantSource |
+				  PM3Config2D_ForegroundROPEnable |
+				  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+				  PM3Config2D_FBWriteEnable);
+
+	PM3_WRITE_REG(PM3RectanglePosition,
+		      (PM3RectanglePosition_XOffset(sx)) |
+		      (PM3RectanglePosition_YOffset(sy)));
+	
+	if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
+		PM3_WRITE_REG(PM3Render2D,
+			      PM3Render2D_XPositive |
+			      PM3Render2D_YPositive |
+			      PM3Render2D_Operation_Normal |
+			      PM3Render2D_SpanOperation |
+			      (PM3Render2D_Width(width)) |
+			      (PM3Render2D_Height(height)));
+	else
+		PM3_WRITE_REG(PM3Render2D,
+			      PM3Render2D_XPositive |
+			      PM3Render2D_YPositive |
+			      PM3Render2D_Operation_Normal |
+			      (PM3Render2D_Width(width)) |
+			      (PM3Render2D_Height(height)));
+	
+	pm3fb_wait_pm3(l_fb_info);
+}
+
+static void pm3fb_cfb16_clear_margins(struct vc_data *conp,
+				      struct display *p, int bottom_only)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
+	int sx, sy;
+	u32 c;
+
+	DTRACE;
+
+	sx = conp->vc_cols * fontwidth(p);	/* right margin */
+	sy = conp->vc_rows * fontheight(p);	/* bottom margin */
+	c = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
+	c = c | (c << 16);
+
+	if (!bottom_only) {	/* right margin top->bottom */
+		PM3_WAIT(4);
+
+		PM3_WRITE_REG(PM3Config2D,
+					  PM3Config2D_UseConstantSource |
+					  PM3Config2D_ForegroundROPEnable |
+					  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+					  PM3Config2D_FBWriteEnable);
+		
+		if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
+			PM3_WRITE_REG(PM3ForegroundColor, c);
+		else
+			PM3_WRITE_REG(PM3FBBlockColor, c);
+		
+		PM3_WRITE_REG(PM3RectanglePosition,
+			      (PM3RectanglePosition_XOffset
+			       (p->var.xoffset +
+				sx)) | (PM3RectanglePosition_YOffset(p->
+								     var.
+								     yoffset)));
+		if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
+			PM3_WRITE_REG(PM3Render2D,
+				      PM3Render2D_XPositive |
+				      PM3Render2D_YPositive |
+				      PM3Render2D_Operation_Normal |
+				      PM3Render2D_SpanOperation |
+				      (PM3Render2D_Width(p->var.xres - sx)) |
+				      (PM3Render2D_Height(p->var.yres)));
+		else
+			PM3_WRITE_REG(PM3Render2D,
+				      PM3Render2D_XPositive |
+				      PM3Render2D_YPositive |
+				      PM3Render2D_Operation_Normal |
+				      (PM3Render2D_Width(p->var.xres - sx)) |
+				      (PM3Render2D_Height(p->var.yres)));
+	}
+	
+	/* bottom margin left -> right */
+	PM3_WAIT(4);
+	
+	PM3_WRITE_REG(PM3Config2D,
+		      PM3Config2D_UseConstantSource |
+		      PM3Config2D_ForegroundROPEnable |
+		      (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+		      PM3Config2D_FBWriteEnable);
+	
+	if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
+		PM3_WRITE_REG(PM3ForegroundColor, c);
+	else
+		PM3_WRITE_REG(PM3FBBlockColor, c);
+	
+	
+	PM3_WRITE_REG(PM3RectanglePosition,
+		      (PM3RectanglePosition_XOffset(p->var.xoffset)) |
+		      (PM3RectanglePosition_YOffset(p->var.yoffset + sy)));
+	
+	if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
+		PM3_WRITE_REG(PM3Render2D,
+			      PM3Render2D_XPositive |
+			      PM3Render2D_YPositive |
+			      PM3Render2D_Operation_Normal |
+			      PM3Render2D_SpanOperation |
+			      (PM3Render2D_Width(p->var.xres)) |
+			      (PM3Render2D_Height(p->var.yres - sy)));
+	else
+		PM3_WRITE_REG(PM3Render2D,
+			      PM3Render2D_XPositive |
+			      PM3Render2D_YPositive |
+			      PM3Render2D_Operation_Normal |
+			      (PM3Render2D_Width(p->var.xres)) |
+			      (PM3Render2D_Height(p->var.yres - sy)));
+
+	pm3fb_wait_pm3(l_fb_info);
+}
+#endif /* FBCON_HAS_CFB16 */
+#ifdef FBCON_HAS_CFB8
+static void pm3fb_cfb8_clear(struct vc_data *conp,
+			     struct display *p,
+			     int sy, int sx, int height, int width)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
+	u32 c;
+
+	DTRACE;
+
+	sx = sx * fontwidth(p);
+	width = width * fontwidth(p);
+	sy = sy * fontheight(p);
+	height = height * fontheight(p);
+
+	c = attr_bgcol_ec(p, conp);
+	c |= c << 8;
+	c |= c << 16;
+
+	PM3_WAIT(4);
+
+	PM3_WRITE_REG(PM3Config2D,
+				  PM3Config2D_UseConstantSource |
+				  PM3Config2D_ForegroundROPEnable |
+				  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+				  PM3Config2D_FBWriteEnable);
+
+	PM3_WRITE_REG(PM3ForegroundColor, c);
+
+	PM3_WRITE_REG(PM3RectanglePosition,
+		      (PM3RectanglePosition_XOffset(sx)) |
+		      (PM3RectanglePosition_YOffset(sy)));
+
+	PM3_WRITE_REG(PM3Render2D,
+		      PM3Render2D_XPositive |
+		      PM3Render2D_YPositive |
+		      PM3Render2D_Operation_Normal |
+		      PM3Render2D_SpanOperation |
+		      (PM3Render2D_Width(width)) |
+		      (PM3Render2D_Height(height)));
+
+	pm3fb_wait_pm3(l_fb_info);
+}
+
+static void pm3fb_cfb8_clear_margins(struct vc_data *conp,
+				     struct display *p, int bottom_only)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
+	int sx, sy;
+	u32 c;
+
+	DTRACE;
+
+	sx = conp->vc_cols * fontwidth(p);	/* right margin */
+	sy = conp->vc_rows * fontheight(p);	/* bottom margin */
+	c = attr_bgcol_ec(p, conp);
+	c |= c << 8;
+	c |= c << 16;
+
+	if (!bottom_only) {	/* right margin top->bottom */
+		PM3_WAIT(4);
+
+		PM3_WRITE_REG(PM3Config2D,
+					  PM3Config2D_UseConstantSource |
+					  PM3Config2D_ForegroundROPEnable |
+					  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+					  PM3Config2D_FBWriteEnable);
+
+		PM3_WRITE_REG(PM3ForegroundColor, c);
+
+		PM3_WRITE_REG(PM3RectanglePosition,
+			      (PM3RectanglePosition_XOffset
+			       (p->var.xoffset +
+				sx)) | (PM3RectanglePosition_YOffset(p->
+								     var.
+								     yoffset)));
+
+		PM3_WRITE_REG(PM3Render2D,
+			      PM3Render2D_XPositive |
+			      PM3Render2D_YPositive |
+			      PM3Render2D_Operation_Normal |
+			      PM3Render2D_SpanOperation |
+			      (PM3Render2D_Width(p->var.xres - sx)) |
+			      (PM3Render2D_Height(p->var.yres)));
+	}
+
+	/* bottom margin left -> right */
+	PM3_WAIT(4);
+
+	PM3_WRITE_REG(PM3Config2D,
+				  PM3Config2D_UseConstantSource |
+				  PM3Config2D_ForegroundROPEnable |
+				  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+				  PM3Config2D_FBWriteEnable);
+
+	PM3_WRITE_REG(PM3ForegroundColor, c);
+
+	PM3_WRITE_REG(PM3RectanglePosition,
+		      (PM3RectanglePosition_XOffset(p->var.xoffset)) |
+		      (PM3RectanglePosition_YOffset(p->var.yoffset + sy)));
+
+	PM3_WRITE_REG(PM3Render2D,
+		      PM3Render2D_XPositive |
+		      PM3Render2D_YPositive |
+		      PM3Render2D_Operation_Normal |
+		      PM3Render2D_SpanOperation |
+		      (PM3Render2D_Width(p->var.xres)) |
+		      (PM3Render2D_Height(p->var.yres - sy)));
+
+	pm3fb_wait_pm3(l_fb_info);
+}
+#endif /* FBCON_HAS_CFB8 */
+#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32)
+static void pm3fb_cfbX_bmove(struct display *p,
+			     int sy, int sx,
+			     int dy, int dx, int height, int width)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
+	int x_align, o_x, o_y;
+
+	DTRACE;
+
+	sx = sx * fontwidth(p);
+	dx = dx * fontwidth(p);
+	width = width * fontwidth(p);
+	sy = sy * fontheight(p);
+	dy = dy * fontheight(p);
+	height = height * fontheight(p);
+
+	o_x = sx - dx;		/*(sx > dx ) ? (sx - dx) : (dx - sx); */
+	o_y = sy - dy;		/*(sy > dy ) ? (sy - dy) : (dy - sy); */
+
+	x_align = (sx & 0x1f);
+
+	PM3_WAIT(6);
+
+	PM3_WRITE_REG(PM3Config2D,
+				  PM3Config2D_UserScissorEnable |
+				  PM3Config2D_ForegroundROPEnable |
+				  PM3Config2D_Blocking |
+				  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+				  PM3Config2D_FBWriteEnable);
+
+	PM3_WRITE_REG(PM3ScissorMinXY,
+		      ((dy & 0x0fff) << 16) | (dx & 0x0fff));
+	PM3_WRITE_REG(PM3ScissorMaxXY,
+				  (((dy + height) & 0x0fff) << 16) |
+				  ((dx + width) & 0x0fff));
+
+	PM3_WRITE_REG(PM3FBSourceReadBufferOffset,
+		      PM3FBSourceReadBufferOffset_XOffset(o_x) |
+		      PM3FBSourceReadBufferOffset_YOffset(o_y));
+
+	PM3_WRITE_REG(PM3RectanglePosition,
+		      (PM3RectanglePosition_XOffset(dx - x_align)) |
+		      (PM3RectanglePosition_YOffset(dy)));
+
+	PM3_WRITE_REG(PM3Render2D,
+		      ((sx > dx) ? PM3Render2D_XPositive : 0) |
+		      ((sy > dy) ? PM3Render2D_YPositive : 0) |
+		      PM3Render2D_Operation_Normal |
+		      PM3Render2D_SpanOperation |
+		      PM3Render2D_FBSourceReadEnable |
+		      (PM3Render2D_Width(width + x_align)) |
+		      (PM3Render2D_Height(height)));
+
+	pm3fb_wait_pm3(l_fb_info);
+}
+
+static void pm3fb_cfbX_putc(struct vc_data *conp, struct display *p,
+			    int c, int yy, int xx)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
+	u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0;
+	u32 fgx, bgx, ldat;
+	int sx, sy, i;
+
+	DTRACE;
+
+	if (l_fb_info->current_par->depth == 8)
+		fgx = attr_fgcol(p, c);
+	else if (depth2bpp(l_fb_info->current_par->depth) == 16)
+		fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, c)];
+	else
+		fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, c)];
+
+	PM3_COLOR(fgx);
+
+	if (l_fb_info->current_par->depth == 8)
+		bgx = attr_bgcol(p, c);
+	else if (depth2bpp(l_fb_info->current_par->depth) == 16)
+		bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, c)];
+	else
+		bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, c)];
+
+	PM3_COLOR(bgx);
+
+	PM3_WAIT(4);
+
+	PM3_WRITE_REG(PM3Config2D,
+				  PM3Config2D_UseConstantSource |
+				  PM3Config2D_ForegroundROPEnable |
+				  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+				  PM3Config2D_FBWriteEnable | PM3Config2D_OpaqueSpan);
+
+	PM3_WRITE_REG(PM3ForegroundColor, fgx);
+	PM3_WRITE_REG(PM3FillBackgroundColor, bgx);
+
+	/* WARNING : address select X need to specify 8 bits for fontwidth <= 8 */
+	/* and 16 bits for fontwidth <= 16 */
+	/* same in _putcs, same for Y and fontheight */
+	if (fontwidth(p) <= 8)
+		asx = 2;
+	else if (fontwidth(p) <= 16)
+		asx = 3;	/* look OK */
+	if (fontheight(p) <= 8)
+		asy = 2;
+	else if (fontheight(p) <= 16)
+		asy = 3;	/* look OK */
+	else if (fontheight(p) <= 32)
+		asy = 4;	/* look OK */
+
+	sx = xx * fontwidth(p);
+	sy = yy * fontheight(p);
+
+	if (fontwidth(p) <= 8)
+		o_x = (8 - (sx & 0x7)) & 0x7;
+	else if (fontwidth(p) <= 16)
+		o_x = (16 - (sx & 0xF)) & 0xF;
+	if (fontheight(p) <= 8)
+		o_y = (8 - (sy & 0x7)) & 0x7;
+	else if (fontheight(p) <= 16)
+		o_y = (16 - (sy & 0xF)) & 0xF;
+	else if (fontheight(p) <= 32)
+		o_y = (32 - (sy & 0x1F)) & 0x1F;
+
+	PM3_WRITE_REG(PM3AreaStippleMode, (o_x << 7) | (o_y << 12) |	/* x_offset, y_offset in pattern */
+		      (1 << 18) |	/* BE */
+		      1 | (asx << 1) | (asy << 4) |	/* address select x/y */
+		      (1 << 20));	/* OpaqueSpan */
+
+	if (fontwidth(p) <= 8) {
+		cdat = p->fontdata + (c & p->charmask) * fontheight(p);
+	} else {
+		cdat =
+		    p->fontdata +
+		    ((c & p->charmask) * (fontheight(p) << 1));
+	}
+
+	PM3_WAIT(2 + fontheight(p));
+
+	for (i = 0; i < fontheight(p); i++) {	/* assume fontheight <= 32 */
+		if (fontwidth(p) <= 8) {
+			ldat = *cdat++;
+		} else {	/* assume fontwidth <= 16 ATM */
+
+			ldat = ((*cdat++) << 8);
+			ldat |= *cdat++;
+		}
+		PM3_WRITE_REG(AreaStipplePattern_indexed(i), ldat);
+	}
+
+	PM3_WRITE_REG(PM3RectanglePosition,
+		      (PM3RectanglePosition_XOffset(sx)) |
+		      (PM3RectanglePosition_YOffset(sy)));
+
+	PM3_WRITE_REG(PM3Render2D,
+		      PM3Render2D_AreaStippleEnable |
+		      PM3Render2D_XPositive |
+		      PM3Render2D_YPositive |
+		      PM3Render2D_Operation_Normal |
+		      PM3Render2D_SpanOperation |
+		      (PM3Render2D_Width(fontwidth(p))) |
+		      (PM3Render2D_Height(fontheight(p))));
+
+	pm3fb_wait_pm3(l_fb_info);
+}
+
+static void pm3fb_cfbX_putcs(struct vc_data *conp, struct display *p,
+			     const unsigned short *s, int count, int yy,
+			     int xx)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
+	u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0;
+	u32 fgx, bgx, ldat;
+	int sx, sy, i, j;
+	u16 sc;
+
+	DTRACE;
+
+	sc = scr_readw(s);
+	if (l_fb_info->current_par->depth == 8)
+		fgx = attr_fgcol(p, sc);
+	else if (depth2bpp(l_fb_info->current_par->depth) == 16)
+		fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, sc)];
+	else
+		fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, sc)];
+	
+	PM3_COLOR(fgx);
+	
+	if (l_fb_info->current_par->depth == 8)
+		bgx = attr_bgcol(p, sc);
+	else if (depth2bpp(l_fb_info->current_par->depth) == 16)
+		bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, sc)];
+	else
+		bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, sc)];
+	
+	PM3_COLOR(bgx);
+
+	PM3_WAIT(4);
+
+	PM3_WRITE_REG(PM3Config2D,
+				  PM3Config2D_UseConstantSource |
+				  PM3Config2D_ForegroundROPEnable |
+				  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+				  PM3Config2D_FBWriteEnable |
+				  PM3Config2D_OpaqueSpan);
+
+	PM3_WRITE_REG(PM3ForegroundColor, fgx);
+	PM3_WRITE_REG(PM3FillBackgroundColor, bgx);
+
+	/* WARNING : address select X need to specify 8 bits for fontwidth <= 8 */
+	/* and 16 bits for fontwidth <= 16 */
+	/* same in _putc, same for Y and fontheight */
+	if (fontwidth(p) <= 8)
+		asx = 2;
+	else if (fontwidth(p) <= 16)
+		asx = 3;	/* look OK */
+	if (fontheight(p) <= 8)
+		asy = 2;
+	else if (fontheight(p) <= 16)
+		asy = 3;	/* look OK */
+	else if (fontheight(p) <= 32)
+		asy = 4;	/* look OK */
+
+	sy = yy * fontheight(p);
+
+	if (fontheight(p) <= 8)
+		o_y = (8 - (sy & 0x7)) & 0x7;
+	else if (fontheight(p) <= 16)
+		o_y = (16 - (sy & 0xF)) & 0xF;
+	else if (fontheight(p) <= 32)
+		o_y = (32 - (sy & 0x1F)) & 0x1F;
+
+	for (j = 0; j < count; j++) {
+		sc = scr_readw(s + j);
+		if (fontwidth(p) <= 8)
+			cdat = p->fontdata +
+				(sc & p->charmask) * fontheight(p);
+		else
+			cdat = p->fontdata +
+				((sc & p->charmask) * fontheight(p) << 1);
+		
+		sx = (xx + j) * fontwidth(p);
+
+		if (fontwidth(p) <= 8)
+			o_x = (8 - (sx & 0x7)) & 0x7;
+		else if (fontwidth(p) <= 16)
+			o_x = (16 - (sx & 0xF)) & 0xF;
+
+		PM3_WAIT(3 + fontheight(p));
+
+		PM3_WRITE_REG(PM3AreaStippleMode, (o_x << 7) | (o_y << 12) | /* x_offset, y_offset in pattern */
+			      (1 << 18) | /* BE */
+			      1 | (asx << 1) | (asy << 4) | /* address select x/y */
+			      (1 << 20)); /* OpaqueSpan */
+
+		for (i = 0; i < fontheight(p); i++) { /* assume fontheight <= 32 */
+			if (fontwidth(p) <= 8) {
+				ldat = *cdat++;
+			} else { /* assume fontwidth <= 16 ATM */
+				ldat = ((*cdat++) << 8);
+				ldat |= *cdat++;
+			}
+			PM3_WRITE_REG(AreaStipplePattern_indexed(i), ldat);
+		}
+
+		PM3_WRITE_REG(PM3RectanglePosition,
+			      (PM3RectanglePosition_XOffset(sx)) |
+			      (PM3RectanglePosition_YOffset(sy)));
+
+		PM3_WRITE_REG(PM3Render2D,
+			      PM3Render2D_AreaStippleEnable |
+			      PM3Render2D_XPositive |
+			      PM3Render2D_YPositive |
+			      PM3Render2D_Operation_Normal |
+			      PM3Render2D_SpanOperation |
+			      (PM3Render2D_Width(fontwidth(p))) |
+			      (PM3Render2D_Height(fontheight(p))));
+	}
+	pm3fb_wait_pm3(l_fb_info);
+}
+
+static void pm3fb_cfbX_revc(struct display *p, int xx, int yy)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
+
+	xx = xx * fontwidth(p);
+	yy = yy * fontheight(p);
+
+	if (l_fb_info->current_par->depth == 8)
+	{
+		if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
+			PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0x0F0F0F0F);
+		else
+			PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0x0F0F0F0F);
+	}
+
+	PM3_WAIT(3);
+
+	PM3_WRITE_REG(PM3Config2D,
+				  PM3Config2D_UseConstantSource |
+				  PM3Config2D_ForegroundROPEnable |
+				  (PM3Config2D_ForegroundROP(0xa)) |	/* Oxa is GXinvert */
+				  PM3Config2D_FBDestReadEnable |
+				  PM3Config2D_FBWriteEnable);
+
+	PM3_WRITE_REG(PM3RectanglePosition,
+		      (PM3RectanglePosition_XOffset(xx)) |
+		      (PM3RectanglePosition_YOffset(yy)));
+
+	PM3_WRITE_REG(PM3Render2D,
+		      PM3Render2D_XPositive |
+		      PM3Render2D_YPositive |
+		      PM3Render2D_Operation_Normal |
+		      PM3Render2D_SpanOperation |
+		      (PM3Render2D_Width(fontwidth(p))) |
+		      (PM3Render2D_Height(fontheight(p))));
+
+	pm3fb_wait_pm3(l_fb_info);
+
+	if (l_fb_info->current_par->depth == 8)
+	{
+		if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
+			PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xFFFFFFFF);
+		else
+			PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xFFFFFFFF);
+	}
+}
+
+#endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */
+#endif /* PM3FB_USE_ACCEL */
+/* *********************************** */
+/* ***** pre-init board(s) setup ***** */
+/* *********************************** */
+
+static void pm3fb_mode_setup(char *mode, unsigned long board_num)
+{
+	struct pm3fb_info *l_fb_info = &(fb_info[board_num]);
+	struct pm3fb_par *l_fb_par = &(current_par[board_num]);
+	unsigned long i = 0;
+
+	current_par_valid[board_num] = 0;
+
+	if (!strncmp(mode, "current", 7)) {
+		l_fb_info->use_current = 1;	/* default w/ OpenFirmware */
+	} else {
+		while ((mode_base[i].name[0])
+		       && (!current_par_valid[board_num])) {
+			if (!
+			    (strncmp
+			     (mode, mode_base[i].name,
+			      strlen(mode_base[i].name)))) {
+				memcpy(l_fb_par, &(mode_base[i].user_mode),
+				       sizeof(struct pm3fb_par));
+				current_par_valid[board_num] = 1;
+				DPRINTK(2, "Mode set to %s\n",
+					mode_base[i].name);
+			}
+			i++;
+		}
+		DASSERT(current_par_valid[board_num],
+			"Valid mode on command line\n");
+	}
+}
+
+static void pm3fb_pciid_setup(char *pciid, unsigned long board_num)
+{
+	short l_bus = -1, l_slot = -1, l_func = -1;
+	char *next;
+
+	if (pciid) {
+		l_bus = simple_strtoul(pciid, &next, 10);
+		if (next && (next[0] == ':')) {
+			pciid = next + 1;
+			l_slot = simple_strtoul(pciid, &next, 10);
+			if (next && (next[0] == ':')) {
+				pciid = next + 1;
+				l_func =
+				    simple_strtoul(pciid, (char **) NULL,
+						   10);
+			}
+		}
+	} else
+		return;
+
+	if ((l_bus >= 0) && (l_slot >= 0) && (l_func >= 0)) {
+		bus[board_num] = l_bus;
+		slot[board_num] = l_slot;
+		func[board_num] = l_func;
+		DPRINTK(2, "Board #%ld will be PciId: %hd:%hd:%hd\n",
+			board_num, l_bus, l_slot, l_func);
+	} else {
+		DPRINTK(1, "Invalid PciId: %hd:%hd:%hd for board #%ld\n",
+			l_bus, l_slot, l_func, board_num);
+	}
+}
+
+static void pm3fb_font_setup(char *lf, unsigned long board_num)
+{
+	unsigned long lfs = strlen(lf);
+
+	if (lfs > (PM3_FONTNAME_SIZE - 1)) {
+		DPRINTK(1, "Fontname %s too long\n", lf);
+		return;
+	}
+	strlcpy(fontn[board_num], lf, lfs + 1);
+}
+
+static void pm3fb_bootdepth_setup(char *bds, unsigned long board_num)
+{
+	unsigned long bd = simple_strtoul(bds, (char **) NULL, 10);
+
+	if (!(depth_supported(bd))) {
+		printk(KERN_WARNING "pm3fb: ignoring invalid depth %s for board #%ld\n",
+		       bds, board_num);
+		return;
+	}
+	depth[board_num] = bd;
+}
+
+static void pm3fb_forcesize_setup(char *bds, unsigned long board_num)
+{
+	unsigned long bd = simple_strtoul(bds, (char **) NULL, 10);
+
+	if (bd > 64) {
+		printk(KERN_WARNING "pm3fb: ignoring invalid memory size %s for board #%ld\n",
+		       bds, board_num);
+		return;
+	}
+	forcesize[board_num] = bd;
+}
+
+static char *pm3fb_boardnum_setup(char *options, unsigned long *bn)
+{
+	char *next;
+
+	if (!(CHAR_IS_NUM(options[0]))) {
+		(*bn) = 0;
+		return (options);
+	}
+
+	(*bn) = simple_strtoul(options, &next, 10);
+
+	if (next && (next[0] == ':') && ((*bn) >= 0)
+	    && ((*bn) <= PM3_MAX_BOARD)) {
+		DPRINTK(2, "Board_num seen as %ld\n", (*bn));
+		return (next + 1);
+	} else {
+		(*bn) = 0;
+		DPRINTK(2, "Board_num default to %ld\n", (*bn));
+		return (options);
+	}
+}
+
+static void pm3fb_real_setup(char *options)
+{
+	char *next;
+	unsigned long i, bn;
+	struct pm3fb_info *l_fb_info;
+
+	DTRACE;
+
+	DPRINTK(2, "Options : %s\n", options);
+
+	for (i = 0; i < PM3_MAX_BOARD; i++) {
+		l_fb_info = &(fb_info[i]);
+		memset(l_fb_info, 0, sizeof(struct pm3fb_info));
+		l_fb_info->gen.fbhw = &pm3fb_switch;
+		l_fb_info->board_num = i;
+		current_par_valid[i] = 0;
+		slot[i] = -1;
+		func[i] = -1;
+		bus[i] = -1;
+		disable[i] = 0;
+		noaccel[i] = 0;
+		fontn[i][0] = '\0';
+		depth[i] = 0;
+		l_fb_info->current_par = &(current_par[i]);
+	}
+
+	/* eat up prefix pm3fb and whatever is used as separator i.e. :,= */
+	if (!strncmp(options, "pm3fb", 5)) {
+		options += 5;
+		while (((*options) == ',') || ((*options) == ':')
+		       || ((*options) == '='))
+			options++;
+	}
+
+	while (options) {
+		bn = 0;
+		if ((next = strchr(options, ','))) {
+			(*next) = '\0';
+			next++;
+		}
+
+		if (!strncmp(options, "mode:", 5)) {
+			options = pm3fb_boardnum_setup(options + 5, &bn);
+			DPRINTK(2, "Setting mode for board #%ld\n", bn);
+			pm3fb_mode_setup(options, bn);
+		} else if (!strncmp(options, "off:", 4)) {
+			options = pm3fb_boardnum_setup(options + 4, &bn);
+			DPRINTK(2, "Disabling board #%ld\n", bn);
+			disable[bn] = 1;
+		} else if (!strncmp(options, "off", 3)) {	/* disable everything */
+			for (i = 0; i < PM3_MAX_BOARD; i++)
+				disable[i] = 1;
+		} else if (!strncmp(options, "disable:", 8)) {
+			options = pm3fb_boardnum_setup(options + 8, &bn);
+			DPRINTK(2, "Disabling board #%ld\n", bn);
+			disable[bn] = 1;
+		} else if (!strncmp(options, "pciid:", 6)) {
+			options = pm3fb_boardnum_setup(options + 6, &bn);
+			DPRINTK(2, "Setting PciID for board #%ld\n", bn);
+			pm3fb_pciid_setup(options, bn);
+		} else if (!strncmp(options, "noaccel:", 8)) {
+			options = pm3fb_boardnum_setup(options + 8, &bn);
+			noaccel[bn] = 1;
+		} else if (!strncmp(options, "font:", 5)) {
+			options = pm3fb_boardnum_setup(options + 5, &bn);
+			pm3fb_font_setup(options, bn);
+		} else if (!strncmp(options, "depth:", 6)) {
+			options = pm3fb_boardnum_setup(options + 6, &bn);
+			pm3fb_bootdepth_setup(options, bn);
+		} else if (!strncmp(options, "printtimings", 12)) {
+			printtimings = 1;
+		} else if (!strncmp(options, "flatpanel:", 10)) {
+			options = pm3fb_boardnum_setup(options + 10, &bn);
+			flatpanel[bn] = 1;
+		} else if (!strncmp(options, "forcesize:", 10)) {
+			options = pm3fb_boardnum_setup(options + 10, &bn);
+			pm3fb_forcesize_setup(options, bn);
+		}
+		options = next;
+	}
+}
+
+/* ********************************************** */
+/* ***** framebuffer API standard functions ***** */
+/* ********************************************** */
+
+static int pm3fb_encode_fix(struct fb_fix_screeninfo *fix,
+			    const void *par, struct fb_info_gen *info)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+	struct pm3fb_par *p = (struct pm3fb_par *) par;
+
+	DTRACE;
+
+	strcpy(fix->id, permedia3_name);
+	fix->smem_start = (unsigned long)l_fb_info->p_fb;
+	fix->smem_len = l_fb_info->fb_size;
+	fix->mmio_start = (unsigned long)l_fb_info->pIOBase;
+	fix->mmio_len = PM3_REGS_SIZE;
+#ifdef PM3FB_USE_ACCEL
+	if (!(noaccel[l_fb_info->board_num]))
+		fix->accel = FB_ACCEL_3DLABS_PERMEDIA3;
+	else
+#endif /* PM3FB_USE_ACCEL */
+		fix->accel = FB_ACCEL_NONE;
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->visual =
+	    (p->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+	if (current_par_valid[l_fb_info->board_num])
+		fix->line_length =
+			l_fb_info->current_par->width *
+			depth2ByPP(l_fb_info->current_par->depth);
+	else
+		fix->line_length = 0;
+	fix->xpanstep = 64 / depth2bpp(p->depth);
+	fix->ypanstep = 1;
+	fix->ywrapstep = 0;
+	return (0);
+}
+
+static int pm3fb_decode_var(const struct fb_var_screeninfo *var,
+			    void *par, struct fb_info_gen *info)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+	struct pm3fb_par *p = (struct pm3fb_par *) par;
+	struct pm3fb_par temp_p;
+	u32 xres;
+
+	DTRACE;
+
+	DASSERT((var != NULL), "fb_var_screeninfo* not NULL");
+	DASSERT((p != NULL), "pm3fb_par* not NULL");
+	DASSERT((l_fb_info != NULL), "pm3fb_info* not NULL");
+
+	memset(&temp_p, 0, sizeof(struct pm3fb_par));
+	temp_p.width = (var->xres_virtual + 7) & ~7;
+	temp_p.height = var->yres_virtual;
+
+	if (!(depth_supported(var->bits_per_pixel))) /* round unsupported up to a multiple of 8 */
+		temp_p.depth = depth2bpp(var->bits_per_pixel);
+	else
+		temp_p.depth = var->bits_per_pixel;
+
+	temp_p.depth = (temp_p.depth > 32) ? 32 : temp_p.depth; /* max 32 */
+	temp_p.depth = (temp_p.depth == 24) ? 32 : temp_p.depth; /* 24 unsupported, round-up to 32 */
+
+	if ((temp_p.depth == 16) && (var->red.length == 5) && (var->green.length == 5) && (var->blue.length == 5))
+		temp_p.depth = 15; /* RGBA 5551 is stored as depth 15 */
+
+	if ((temp_p.depth == 16) && (var->red.length == 4) && (var->green.length == 4) && (var->blue.length == 4))
+		temp_p.depth = 12; /* RGBA 4444  is stored as depth 12 */
+
+
+	DPRINTK(2,
+		"xres: %d, yres: %d, vxres: %d, vyres: %d ; xoffset:%d, yoffset: %d\n",
+		var->xres, var->yres, var->xres_virtual, var->yres_virtual,
+		var->xoffset, var->yoffset);
+
+	xres = (var->xres + 31) & ~31;
+	if (temp_p.width < xres + var->xoffset)
+		temp_p.width = xres + var->xoffset;
+	if (temp_p.height < var->yres + var->yoffset)
+		temp_p.height = var->yres + var->yoffset;
+
+	if (temp_p.width > 2048) {
+		DPRINTK(1, "virtual width not supported: %u\n",
+			temp_p.width);
+		return (-EINVAL);
+	}
+	if (var->yres < 200) {
+		DPRINTK(1, "height not supported: %u\n", (u32) var->yres);
+		return (-EINVAL);
+	}
+	if (temp_p.height < 200 || temp_p.height > 4095) {
+		DPRINTK(1, "virtual height not supported: %u\n",
+			temp_p.height);
+		return (-EINVAL);
+	}
+	if (!(depth_supported(temp_p.depth))) {
+		DPRINTK(1, "depth not supported: %u\n", temp_p.depth);
+		return (-EINVAL);
+	}
+	if ((temp_p.width * temp_p.height * depth2ByPP(temp_p.depth)) >
+	    l_fb_info->fb_size) {
+		DPRINTK(1, "no memory for screen (%ux%ux%u)\n",
+			temp_p.width, temp_p.height, temp_p.depth);
+		return (-EINVAL);
+	}
+
+	if ((!var->pixclock) ||
+	    (!var->right_margin) ||
+	    (!var->hsync_len) ||
+	    (!var->left_margin) ||
+	    (!var->lower_margin) ||
+	    (!var->vsync_len) || (!var->upper_margin)
+	    ) {
+		unsigned long i = 0, done = 0;
+		printk(KERN_WARNING "pm3fb: refusing to use a likely wrong timing\n");
+
+		while ((mode_base[i].user_mode.width) && !done) {
+			if ((mode_base[i].user_mode.width == temp_p.width)
+			    && (mode_base[i].user_mode.height ==
+				temp_p.height)) {
+				printk(KERN_NOTICE "pm3fb: using close match %s\n",
+				       mode_base[i].name);
+				temp_p = mode_base[i].user_mode;
+				done = 1;
+			}
+			i++;
+		}
+		if (!done)
+			return (-EINVAL);
+	} else {
+		temp_p.pixclock = PICOS2KHZ(var->pixclock);
+		if (temp_p.pixclock > PM3_MAX_PIXCLOCK) {
+			DPRINTK(1, "pixclock too high (%uKHz)\n",
+				temp_p.pixclock);
+			return (-EINVAL);
+		}
+
+		temp_p.hsstart = var->right_margin;
+		temp_p.hsend = var->right_margin + var->hsync_len;
+		temp_p.hbend =
+		    var->right_margin + var->hsync_len + var->left_margin;
+		temp_p.htotal = xres + temp_p.hbend;
+
+		temp_p.vsstart = var->lower_margin;
+		temp_p.vsend = var->lower_margin + var->vsync_len;
+		temp_p.vbend =
+		    var->lower_margin + var->vsync_len + var->upper_margin;
+		temp_p.vtotal = var->yres + temp_p.vbend;
+
+		temp_p.stride = temp_p.width;
+
+		DPRINTK(2, "Using %d * %d, %d Khz, stride is %08x\n",
+			temp_p.width, temp_p.height, temp_p.pixclock,
+			temp_p.stride);
+
+		temp_p.base =
+		    pm3fb_Shiftbpp(l_fb_info, temp_p.depth,
+				   (var->yoffset * xres) + var->xoffset);
+
+		temp_p.video = 0;
+
+		if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+			temp_p.video |= PM3VideoControl_HSYNC_ACTIVE_HIGH;
+		else
+			temp_p.video |= PM3VideoControl_HSYNC_ACTIVE_LOW;
+
+		if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+			temp_p.video |= PM3VideoControl_VSYNC_ACTIVE_HIGH;
+		else
+			temp_p.video |= PM3VideoControl_VSYNC_ACTIVE_LOW;
+
+		if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+			DPRINTK(1, "Interlaced mode not supported\n\n");
+			return (-EINVAL);
+		}
+
+		if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
+			temp_p.video |= PM3VideoControl_LINE_DOUBLE_ON;
+		else
+			temp_p.video |= PM3VideoControl_LINE_DOUBLE_OFF;
+
+		if (var->activate == FB_ACTIVATE_NOW)
+			temp_p.video |= PM3VideoControl_ENABLE;
+		else {
+			temp_p.video |= PM3VideoControl_DISABLE;
+			DPRINTK(2, "PM3Video disabled\n");
+		}
+
+		switch (temp_p.depth) {
+		case 8:
+			temp_p.video |= PM3VideoControl_PIXELSIZE_8BIT;
+			break;
+		case 12:
+		case 15:
+		case 16:
+			temp_p.video |= PM3VideoControl_PIXELSIZE_16BIT;
+			break;
+		case 32:
+			temp_p.video |= PM3VideoControl_PIXELSIZE_32BIT;
+			break;
+		default:
+			DPRINTK(1, "Unsupported depth\n");
+			break;
+		}
+	}
+	(*p) = temp_p;
+
+#ifdef PM3FB_USE_ACCEL
+	if (var->accel_flags & FB_ACCELF_TEXT)
+		noaccel[l_fb_info->board_num] = 0;
+	else
+		noaccel[l_fb_info->board_num] = 1;
+#endif /* PM3FB_USE_ACCEL */
+
+	return (0);
+}
+
+static void pm3fb_encode_depth(struct fb_var_screeninfo *var, long d)
+{
+	switch (d) {
+	case 8:
+		var->red.length = var->green.length = var->blue.length = 8;
+		var->red.offset = var->green.offset = var->blue.offset = 0;
+		var->transp.offset = var->transp.length = 0;
+		break;
+
+	case 12:
+		var->red.offset = 8;
+		var->red.length = 4;
+		var->green.offset = 4;
+		var->green.length = 4;
+		var->blue.offset = 0;
+		var->blue.length = 4;
+		var->transp.offset = 12;
+		var->transp.length = 4;
+		break;
+
+	case 15:
+		var->red.offset = 10;
+		var->red.length = 5;
+		var->green.offset = 5;
+		var->green.length = 5;
+		var->blue.offset = 0;
+		var->blue.length = 5;
+		var->transp.offset = 15;
+		var->transp.length = 1;
+		break;
+
+	case 16:
+		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 = var->transp.length = 0;
+		break;
+
+	case 32:
+		var->transp.offset = 24;
+		var->red.offset = 16;
+		var->green.offset = 8;
+		var->blue.offset = 0;
+		var->red.length = var->green.length =
+			var->blue.length = var->transp.length = 8;
+		break;
+
+	default:
+		DPRINTK(1, "Unsupported depth %ld\n", d);
+		break;
+	}
+}
+
+static int pm3fb_encode_var(struct fb_var_screeninfo *var,
+			    const void *par, struct fb_info_gen *info)
+{
+	struct pm3fb_par *p = (struct pm3fb_par *) par;
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+
+	u32 base;
+
+	DTRACE;
+
+	DASSERT((var != NULL), "fb_var_screeninfo* not NULL");
+	DASSERT((p != NULL), "pm3fb_par* not NULL");
+	DASSERT((info != NULL), "fb_info_gen* not NULL");
+
+	memset(var, 0, sizeof(struct fb_var_screeninfo));
+
+#ifdef PM3FB_USE_ACCEL
+	if (!(noaccel[l_fb_info->board_num]))
+		var->accel_flags |= FB_ACCELF_TEXT;
+#endif /* PM3FB_USE_ACCEL */
+
+	var->xres_virtual = p->width;
+	var->yres_virtual = p->height;
+	var->xres = p->htotal - p->hbend;
+	var->yres = p->vtotal - p->vbend;
+
+	DPRINTK(2, "xres = %d, yres : %d\n", var->xres, var->yres);
+
+	var->right_margin = p->hsstart;
+	var->hsync_len = p->hsend - p->hsstart;
+	var->left_margin = p->hbend - p->hsend;
+	var->lower_margin = p->vsstart;
+	var->vsync_len = p->vsend - p->vsstart;
+	var->upper_margin = p->vbend - p->vsend;
+	var->bits_per_pixel = depth2bpp(p->depth);
+	
+	pm3fb_encode_depth(var, p->depth);
+
+	base = pm3fb_Unshiftbpp(l_fb_info, p->depth, p->base);
+
+	var->xoffset = base % var->xres;
+	var->yoffset = base / var->xres;
+
+	var->height = var->width = -1;
+
+	var->pixclock = KHZ2PICOS(p->pixclock);
+
+	if ((p->video & PM3VideoControl_HSYNC_MASK) ==
+	    PM3VideoControl_HSYNC_ACTIVE_HIGH)
+		var->sync |= FB_SYNC_HOR_HIGH_ACT;
+	if ((p->video & PM3VideoControl_VSYNC_MASK) ==
+	    PM3VideoControl_VSYNC_ACTIVE_HIGH)
+		var->sync |= FB_SYNC_VERT_HIGH_ACT;
+	if (p->video & PM3VideoControl_LINE_DOUBLE_ON)
+		var->vmode = FB_VMODE_DOUBLE;
+
+	return (0);
+}
+
+static void pm3fb_get_par(void *par, struct fb_info_gen *info)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+
+	DTRACE;
+
+	if (!current_par_valid[l_fb_info->board_num]) {
+		if (l_fb_info->use_current)
+			pm3fb_read_mode(l_fb_info, l_fb_info->current_par);
+		else
+			memcpy(l_fb_info->current_par,
+			       &(mode_base[0].user_mode),
+			       sizeof(struct pm3fb_par));
+		current_par_valid[l_fb_info->board_num] = 1;
+	}
+	*((struct pm3fb_par *) par) = *(l_fb_info->current_par);
+}
+
+static void pm3fb_set_par(const void *par, struct fb_info_gen *info)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+
+	DTRACE;
+
+	*(l_fb_info->current_par) = *((struct pm3fb_par *) par);
+	current_par_valid[l_fb_info->board_num] = 1;
+
+	pm3fb_write_mode(l_fb_info);
+
+#ifdef PM3FB_USE_ACCEL
+	pm3fb_init_engine(l_fb_info);
+#endif /* PM3FB_USE_ACCEL */
+}
+
+static void pm3fb_set_color(struct pm3fb_info *l_fb_info,
+			    unsigned char regno, unsigned char r,
+			    unsigned char g, unsigned char b)
+{
+	DTRACE;
+
+	PM3_SLOW_WRITE_REG(PM3RD_PaletteWriteAddress, regno);
+	PM3_SLOW_WRITE_REG(PM3RD_PaletteData, r);
+	PM3_SLOW_WRITE_REG(PM3RD_PaletteData, g);
+	PM3_SLOW_WRITE_REG(PM3RD_PaletteData, b);
+}
+
+static int pm3fb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+			   unsigned *blue, unsigned *transp,
+			   struct fb_info *info)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+
+	DTRACE;
+
+	if (regno < 256) {
+		*red =
+		    l_fb_info->palette[regno].red << 8 | l_fb_info->
+		    palette[regno].red;
+		*green =
+		    l_fb_info->palette[regno].green << 8 | l_fb_info->
+		    palette[regno].green;
+		*blue =
+		    l_fb_info->palette[regno].blue << 8 | l_fb_info->
+		    palette[regno].blue;
+		*transp =
+		    l_fb_info->palette[regno].transp << 8 | l_fb_info->
+		    palette[regno].transp;
+	}
+	return (regno > 255);
+}
+
+static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp,
+			   struct fb_info *info)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+
+	DTRACE;
+
+	if (regno < 16) {
+		switch (l_fb_info->current_par->depth) {
+#ifdef FBCON_HAS_CFB8
+		case 8:
+			break;
+#endif
+#ifdef FBCON_HAS_CFB16
+		case 12:
+			l_fb_info->cmap.cmap12[regno] =
+				(((u32) red & 0xf000) >> 4) |
+				(((u32) green & 0xf000) >> 8) |
+				(((u32) blue & 0xf000) >> 12);
+			break;
+
+		case 15:
+			l_fb_info->cmap.cmap15[regno] =
+				(((u32) red & 0xf800) >> 1) |
+				(((u32) green & 0xf800) >> 6) |
+				(((u32) blue & 0xf800) >> 11);
+			break;
+
+		case 16:
+			l_fb_info->cmap.cmap16[regno] =
+			    ((u32) red & 0xf800) |
+			    (((u32) green & 0xfc00) >> 5) |
+			    (((u32) blue & 0xf800) >> 11);
+			break;
+#endif
+#ifdef FBCON_HAS_CFB32
+		case 32:
+			l_fb_info->cmap.cmap32[regno] =
+			    (((u32) transp & 0xff00) << 16) |
+			    (((u32) red & 0xff00) << 8) |
+			    (((u32) green & 0xff00)) |
+			    (((u32) blue & 0xff00) >> 8);
+			break;
+#endif
+		default:
+			DPRINTK(1, "bad depth %u\n",
+				l_fb_info->current_par->depth);
+			break;
+		}
+	}
+	if (regno < 256) {
+		l_fb_info->palette[regno].red = red >> 8;
+		l_fb_info->palette[regno].green = green >> 8;
+		l_fb_info->palette[regno].blue = blue >> 8;
+		l_fb_info->palette[regno].transp = transp >> 8;
+		if (l_fb_info->current_par->depth == 8)
+			pm3fb_set_color(l_fb_info, regno, red >> 8,
+					green >> 8, blue >> 8);
+	}
+	return (regno > 255);
+}
+
+static int pm3fb_blank(int blank_mode, struct fb_info_gen *info)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+	u32 video;
+
+	DTRACE;
+
+	if (!current_par_valid[l_fb_info->board_num])
+		return (1);
+
+	video = l_fb_info->current_par->video;
+
+	/*
+	 * Oxygen VX1 - it appears that setting PM3VideoControl and
+	 * then PM3RD_SyncControl to the same SYNC settings undoes
+	 * any net change - they seem to xor together.  Only set the
+	 * sync options in PM3RD_SyncControl.  --rmk
+	 */
+	video &= ~(PM3VideoControl_HSYNC_MASK |
+		   PM3VideoControl_VSYNC_MASK);
+	video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |
+		 PM3VideoControl_VSYNC_ACTIVE_HIGH;
+
+	if (blank_mode > 0) {
+		switch (blank_mode - 1) {
+
+		case VESA_NO_BLANKING:	/* FIXME */
+			video = video & ~(PM3VideoControl_ENABLE);
+			break;
+
+		case VESA_HSYNC_SUSPEND:
+			video = video & ~(PM3VideoControl_HSYNC_MASK |
+					  PM3VideoControl_BLANK_ACTIVE_LOW);
+			break;
+		case VESA_VSYNC_SUSPEND:
+			video = video & ~(PM3VideoControl_VSYNC_MASK |
+					  PM3VideoControl_BLANK_ACTIVE_LOW);
+			break;
+		case VESA_POWERDOWN:
+			video = video & ~(PM3VideoControl_HSYNC_MASK |
+					  PM3VideoControl_VSYNC_MASK |
+					  PM3VideoControl_BLANK_ACTIVE_LOW);
+			break;
+		default:
+			DPRINTK(1, "Unsupported blanking %d\n",
+				blank_mode);
+			return (1);
+			break;
+		}
+	}
+
+	PM3_SLOW_WRITE_REG(PM3VideoControl, video);
+
+	return (0);
+}
+
+static void pm3fb_set_disp(const void *par, struct display *disp,
+			   struct fb_info_gen *info)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+	struct pm3fb_par *p = (struct pm3fb_par *) par;
+	u32 flags;
+
+	DTRACE;
+
+	local_irq_save(flags);
+	info->info.screen_base = l_fb_info->v_fb;
+	switch (p->depth) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+#ifdef PM3FB_USE_ACCEL
+		if (!(noaccel[l_fb_info->board_num]))
+			disp->dispsw = &pm3fb_cfb8;
+		else
+#endif /* PM3FB_USE_ACCEL */
+			disp->dispsw = &fbcon_cfb8;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 12:
+#ifdef PM3FB_USE_ACCEL
+		if (!(noaccel[l_fb_info->board_num]))
+			disp->dispsw = &pm3fb_cfb16;
+		else
+#endif /* PM3FB_USE_ACCEL */
+			disp->dispsw = &fbcon_cfb16;
+		disp->dispsw_data = l_fb_info->cmap.cmap12;
+		break;
+	case 15:
+#ifdef PM3FB_USE_ACCEL
+		if (!(noaccel[l_fb_info->board_num]))
+			disp->dispsw = &pm3fb_cfb16;
+		else
+#endif /* PM3FB_USE_ACCEL */
+			disp->dispsw = &fbcon_cfb16;
+		disp->dispsw_data = l_fb_info->cmap.cmap15;
+		break;
+	case 16:
+#ifdef PM3FB_USE_ACCEL
+		if (!(noaccel[l_fb_info->board_num]))
+			disp->dispsw = &pm3fb_cfb16;
+		else
+#endif /* PM3FB_USE_ACCEL */
+			disp->dispsw = &fbcon_cfb16;
+		disp->dispsw_data = l_fb_info->cmap.cmap16;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 32:
+#ifdef PM3FB_USE_ACCEL
+		if (!(noaccel[l_fb_info->board_num]))
+			disp->dispsw = &pm3fb_cfb32;
+		else
+#endif /* PM3FB_USE_ACCEL */
+			disp->dispsw = &fbcon_cfb32;
+		disp->dispsw_data = l_fb_info->cmap.cmap32;
+		break;
+#endif /* FBCON_HAS_CFB32 */
+	default:
+		disp->dispsw = &fbcon_dummy;
+		DPRINTK(1, "Invalid depth, using fbcon_dummy\n");
+		break;
+	}
+	local_irq_restore(flags);
+}
+
+/* */
+static void pm3fb_detect(void)
+{
+	struct pci_dev *dev_array[PM3_MAX_BOARD];
+	struct pci_dev *dev = NULL;
+	struct pm3fb_info *l_fb_info = &(fb_info[0]);
+	unsigned long i, j, done;
+
+	DTRACE;
+
+	for (i = 0; i < PM3_MAX_BOARD; i++) {
+		dev_array[i] = NULL;
+		fb_info[i].dev = NULL;
+	}
+
+	dev =
+	    pci_find_device(PCI_VENDOR_ID_3DLABS,
+			    PCI_DEVICE_ID_3DLABS_PERMEDIA3, dev);
+
+	for (i = 0; ((i < PM3_MAX_BOARD) && dev); i++) {
+		dev_array[i] = dev;
+		dev =
+		    pci_find_device(PCI_VENDOR_ID_3DLABS,
+				    PCI_DEVICE_ID_3DLABS_PERMEDIA3, dev);
+	}
+
+	if (dev) {		/* more than PM3_MAX_BOARD */
+		printk(KERN_WARNING "pm3fb: Warning: more than %d boards found\n",
+		       PM3_MAX_BOARD);
+	}
+
+	if (!dev_array[0]) {	/* not a single board, abort */
+		return;
+	}
+
+	/* allocate user-defined boards */
+	for (i = 0; i < PM3_MAX_BOARD; i++) {
+		if ((bus[i] >= 0) && (slot[i] >= 0) && (func[i] >= 0)) {
+			for (j = 0; j < PM3_MAX_BOARD; j++) {
+				if ((dev_array[j] != NULL) &&
+				    (dev_array[j]->bus->number == bus[i])
+				    && (PCI_SLOT(dev_array[j]->devfn) ==
+					slot[i])
+				    && (PCI_FUNC(dev_array[j]->devfn) ==
+					func[i])) {
+					fb_info[i].dev = dev_array[j];
+					dev_array[j] = NULL;
+				}
+			}
+		}
+	}
+	/* allocate remaining boards */
+	for (i = 0; i < PM3_MAX_BOARD; i++) {
+		if (fb_info[i].dev == NULL) {
+			done = 0;
+			for (j = 0; ((j < PM3_MAX_BOARD) && (!done)); j++) {
+				if (dev_array[j] != NULL) {
+					fb_info[i].dev = dev_array[j];
+					dev_array[j] = NULL;
+					done = 1;
+				}
+			}
+		}
+	}
+
+	/* at that point, all PCI Permedia3 are detected and allocated */
+	/* now, initialize... or not */
+	for (i = 0; i < PM3_MAX_BOARD; i++) {
+		l_fb_info = &(fb_info[i]);
+		if ((l_fb_info->dev) && (!disable[i])) {	/* PCI device was found and not disabled by user */
+			DPRINTK(2,
+				"found @%lx Vendor %lx Device %lx ; base @ : %lx - %lx - %lx - %lx - %lx - %lx, irq %ld\n",
+				(unsigned long) l_fb_info->dev,
+				(unsigned long) l_fb_info->dev->vendor,
+				(unsigned long) l_fb_info->dev->device,
+				(unsigned long)
+				pci_resource_start(l_fb_info->dev, 0),
+				(unsigned long)
+				pci_resource_start(l_fb_info->dev, 1),
+				(unsigned long)
+				pci_resource_start(l_fb_info->dev, 2),
+				(unsigned long)
+				pci_resource_start(l_fb_info->dev, 3),
+				(unsigned long)
+				pci_resource_start(l_fb_info->dev, 4),
+				(unsigned long)
+				pci_resource_start(l_fb_info->dev, 5),
+				(unsigned long) l_fb_info->dev->irq);
+
+			l_fb_info->pIOBase =
+			    (unsigned char *)
+			    pci_resource_start(l_fb_info->dev, 0);
+#ifdef __BIG_ENDIAN
+			l_fb_info->pIOBase += PM3_REGS_SIZE;
+#endif
+			l_fb_info->vIOBase = (unsigned char *) -1;
+			l_fb_info->p_fb =
+			    (unsigned char *)
+			    pci_resource_start(l_fb_info->dev, 1);
+			l_fb_info->v_fb = (unsigned char *) -1;
+
+				if (!request_mem_region
+			    ((unsigned long)l_fb_info->p_fb, 64 * 1024 * 1024, /* request full aperture size */
+			     "pm3fb")) {
+				printk
+				    (KERN_ERR "pm3fb: Error: couldn't request framebuffer memory, board #%ld\n",
+				     l_fb_info->board_num);
+				continue;
+			}
+			if (!request_mem_region
+			    ((unsigned long)l_fb_info->pIOBase, PM3_REGS_SIZE,
+			     "pm3fb I/O regs")) {
+				printk
+				    (KERN_ERR "pm3fb: Error: couldn't request IObase memory, board #%ld\n",
+				     l_fb_info->board_num);
+				continue;
+			}
+			if (forcesize[l_fb_info->board_num])
+				l_fb_info->fb_size = forcesize[l_fb_info->board_num];
+
+			l_fb_info->fb_size =
+			    pm3fb_size_memory(l_fb_info);
+				if (l_fb_info->fb_size) {
+				(void) pci_enable_device(l_fb_info->dev);
+				pm3fb_common_init(l_fb_info);
+			} else
+				printk(KERN_ERR "pm3fb: memory problem, not enabling board #%ld\n", l_fb_info->board_num);
+		}
+	}
+}
+
+static int pm3fb_pan_display(const struct fb_var_screeninfo *var,
+			     struct fb_info_gen *info)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+
+	DTRACE;
+
+	if (!current_par_valid[l_fb_info->board_num])
+		return -EINVAL;
+
+	l_fb_info->current_par->base =	/* in 128 bits chunk - i.e. AFTER Shiftbpp */
+	    pm3fb_Shiftbpp(l_fb_info,
+			   l_fb_info->current_par->depth,
+			   (var->yoffset * l_fb_info->current_par->width) +
+			   var->xoffset);
+	PM3_SLOW_WRITE_REG(PM3ScreenBase, l_fb_info->current_par->base);
+	return 0;
+}
+
+static int pm3fb_ioctl(struct inode *inode, struct file *file,
+                       u_int cmd, u_long arg, int con,
+		       struct fb_info *info)
+{
+	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+	u32 cm, i;
+#ifdef PM3FB_MASTER_DEBUG
+	char cc[3];
+#endif /* PM3FB_MASTER_DEBUG */
+
+	switch(cmd)
+	{
+#ifdef PM3FB_MASTER_DEBUG
+	case PM3FBIO_CLEARMEMORY:
+		if (copy_from_user(&cm, (void *)arg, sizeof(u32)))
+			return(-EFAULT);
+		pm3fb_clear_memory(l_fb_info, cm);
+		return(0);
+		break;
+
+	case PM3FBIO_CLEARCMAP:
+		if (copy_from_user(cc, (void*)arg, 3 * sizeof(char)))
+			return(-EFAULT);
+		pm3fb_clear_colormap(l_fb_info, cc[0], cc[1], cc[2]);
+		return(0);
+		break;
+#endif /* PM3FB_MASTER_DEBUG */
+
+	case PM3FBIO_RESETCHIP:
+		cm = 1;
+		PM3_SLOW_WRITE_REG(PM3ResetStatus, 1);
+		for (i = 0 ; (i < 10000) && cm ; i++)
+		{
+			PM3_DELAY(10);
+			cm = PM3_READ_REG(PM3ResetStatus);
+		}
+		if (cm)
+		{
+			printk(KERN_ERR "pm3fb: chip reset failed with status 0x%x\n", cm);
+			return(-EIO);
+		}
+		/* first thing first, reload memory timings */
+		pm3fb_write_memory_timings(l_fb_info);
+#ifdef PM3FB_USE_ACCEL
+		pm3fb_init_engine(l_fb_info);
+#endif /* PM3FB_USE_ACCEL */
+		pm3fb_write_mode(l_fb_info);
+		return(0);
+		break;
+
+	default:
+		DPRINTK(2, "unknown ioctl: %d (%x)\n", cmd, cmd);
+		return(-EINVAL);
+	}
+}
+
+/* ****************************************** */
+/* ***** standard FB API init functions ***** */
+/* ****************************************** */
+
+int __init pm3fb_setup(char *options)
+{
+	long opsi = strlen(options);
+
+	DTRACE;
+
+	memcpy(g_options, options,
+	       ((opsi + 1) >
+		PM3_OPTIONS_SIZE) ? PM3_OPTIONS_SIZE : (opsi + 1));
+	g_options[PM3_OPTIONS_SIZE - 1] = 0;
+
+	return (0);
+}
+
+int __init pm3fb_init(void)
+{
+	DTRACE;
+
+	DPRINTK(2, "This is pm3fb.c, CVS version: $Header: /cvsroot/linux/drivers/video/pm3fb.c,v 1.1 2002/02/25 19:11:06 marcelo Exp $");
+
+	pm3fb_real_setup(g_options);
+
+	pm3fb_detect();
+
+	if (!fb_info[0].dev) {	/* not even one board ??? */
+		DPRINTK(1, "No PCI Permedia3 board detected\n");
+	}
+	return (0);
+}
+
+/* ************************* */
+/* **** Module support ***** */
+/* ************************* */
+
+#ifdef MODULE
+MODULE_AUTHOR("Romain Dolbeau");
+MODULE_DESCRIPTION("Permedia3 framebuffer device driver");
+static char *mode[PM3_MAX_BOARD];
+MODULE_PARM(mode,PM3_MAX_BOARD_MODULE_ARRAY_STRING);
+MODULE_PARM_DESC(mode,"video mode");
+MODULE_PARM(disable,PM3_MAX_BOARD_MODULE_ARRAY_SHORT);
+MODULE_PARM_DESC(disable,"disable board");
+static short off[PM3_MAX_BOARD];
+MODULE_PARM(off,PM3_MAX_BOARD_MODULE_ARRAY_SHORT);
+MODULE_PARM_DESC(off,"disable board");
+static char *pciid[PM3_MAX_BOARD];
+MODULE_PARM(pciid,PM3_MAX_BOARD_MODULE_ARRAY_STRING);
+MODULE_PARM_DESC(pciid,"board PCI Id");
+MODULE_PARM(noaccel,PM3_MAX_BOARD_MODULE_ARRAY_SHORT);
+MODULE_PARM_DESC(noaccel,"disable accel");
+static char *font[PM3_MAX_BOARD];
+MODULE_PARM(font,PM3_MAX_BOARD_MODULE_ARRAY_STRING);
+MODULE_PARM_DESC(font,"choose font");
+MODULE_PARM(depth,PM3_MAX_BOARD_MODULE_ARRAY_SHORT);
+MODULE_PARM_DESC(depth,"boot-time depth");
+MODULE_PARM(printtimings, "h");
+MODULE_PARM_DESC(printtimings, "print the memory timings of the card(s)");
+MODULE_PARM(forcesize, PM3_MAX_BOARD_MODULE_ARRAY_SHORT);
+MODULE_PARM_DESC(forcesize, "force specified memory size");
+/*
+MODULE_SUPPORTED_DEVICE("Permedia3 PCI boards")
+MODULE_GENERIC_TABLE(gtype,name)
+MODULE_DEVICE_TABLE(type,name)
+*/
+
+void pm3fb_build_options(void)
+{
+	int i;
+	char ts[128];
+
+	strcpy(g_options, "pm3fb");
+	for (i = 0; i < PM3_MAX_BOARD ; i++)
+	{
+		if (mode[i])
+		{
+			sprintf(ts, ",mode:%d:%s", i, mode[i]);
+			strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
+		}
+		if (disable[i] || off[i])
+		{
+			sprintf(ts, ",disable:%d:", i);
+			strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
+		}
+		if (pciid[i])
+		{
+			sprintf(ts, ",pciid:%d:%s", i, pciid[i]);
+			strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
+		}
+		if (noaccel[i])
+		{
+			sprintf(ts, ",noaccel:%d:", i);
+			strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
+		}
+		if (font[i])
+		{
+			sprintf(ts, ",font:%d:%s", i, font[i]);
+			strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
+		}
+		if (depth[i])
+		{
+			sprintf(ts, ",depth:%d:%d", i, depth[i]);
+			strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
+		}
+	}
+	g_options[PM3_OPTIONS_SIZE - 1] = '\0';
+	DPRINTK(1, "pm3fb use options: %s\n", g_options);
+}
+
+int init_module(void)
+{
+	DTRACE;
+
+	pm3fb_build_options();
+
+	pm3fb_init();
+
+	return (0);
+}
+
+void cleanup_module(void)
+{
+	DTRACE;
+	{
+		unsigned long i;
+		struct pm3fb_info *l_fb_info;
+		for (i = 0; i < PM3_MAX_BOARD; i++) {
+			l_fb_info = &(fb_info[i]);
+			if ((l_fb_info->dev != NULL)
+			    && (!(disable[l_fb_info->board_num]))) {
+				if (l_fb_info->vIOBase !=
+				    (unsigned char *) -1) {
+					pm3fb_unmapIO(l_fb_info);
+					release_mem_region(l_fb_info->p_fb,
+							   l_fb_info->
+							   fb_size);
+					release_mem_region(l_fb_info->
+							   pIOBase,
+							   PM3_REGS_SIZE);
+				}
+				unregister_framebuffer(&l_fb_info->gen.
+						       info);
+			}
+		}
+	}
+	return;
+}
+#endif /* MODULE */
diff --git a/drivers/video/pmag-aa-fb.c b/drivers/video/pmag-aa-fb.c
new file mode 100644
index 0000000..3e00ad7
--- /dev/null
+++ b/drivers/video/pmag-aa-fb.c
@@ -0,0 +1,514 @@
+/*
+ *	linux/drivers/video/pmag-aa-fb.c
+ *	Copyright 2002 Karsten Merker <merker@debian.org>
+ *
+ *	PMAG-AA TurboChannel framebuffer card support ... derived from
+ *	pmag-ba-fb.c, which is Copyright (C) 1999, 2000, 2001 by
+ *	Michael Engel <engel@unix-ag.org>, Karsten Merker <merker@debian.org>
+ *	and Harald Koerfgen <hkoerfg@web.de>, which itself is derived from
+ *	"HP300 Topcat framebuffer support (derived from macfb of all things)
+ *	Phil Blundell <philb@gnu.org> 1998"
+ *
+ *	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.
+ *
+ *	2002-09-28  Karsten Merker <merker@linuxtag.org>
+ *		Version 0.01: First try to get a PMAG-AA running.
+ *
+ *	2003-02-24  Thiemo Seufer  <seufer@csv.ica.uni-stuttgart.de>
+ *		Version 0.02: Major code cleanup.
+ *
+ *	2003-09-21  Thiemo Seufer  <seufer@csv.ica.uni-stuttgart.de>
+ *		Hardware cursor support.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+
+#include <asm/bootinfo.h>
+#include <asm/dec/machtype.h>
+#include <asm/dec/tc.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+
+#include "bt455.h"
+#include "bt431.h"
+
+/* Version information */
+#define DRIVER_VERSION "0.02"
+#define DRIVER_AUTHOR "Karsten Merker <merker@linuxtag.org>"
+#define DRIVER_DESCRIPTION "PMAG-AA Framebuffer Driver"
+
+/* Prototypes */
+static int aafb_set_var(struct fb_var_screeninfo *var, int con,
+			struct fb_info *info);
+
+/*
+ * Bt455 RAM DAC register base offset (rel. to TC slot base address).
+ */
+#define PMAG_AA_BT455_OFFSET		0x100000
+
+/*
+ * Bt431 cursor generator offset (rel. to TC slot base address).
+ */
+#define PMAG_AA_BT431_OFFSET		0x180000
+
+/*
+ * Begin of PMAG-AA framebuffer memory relative to TC slot address,
+ * resolution is 1280x1024x1 (8 bits deep, but only LSB is used).
+ */
+#define PMAG_AA_ONBOARD_FBMEM_OFFSET	0x200000
+
+struct aafb_cursor {
+	struct timer_list timer;
+	int enable;
+	int on;
+	int vbl_cnt;
+	int blink_rate;
+	u16 x, y, width, height;
+};
+
+#define CURSOR_TIMER_FREQ	(HZ / 50)
+#define CURSOR_BLINK_RATE	(20)
+#define CURSOR_DRAW_DELAY	(2)
+
+struct aafb_info {
+	struct fb_info info;
+	struct display disp;
+	struct aafb_cursor cursor;
+	struct bt455_regs *bt455;
+	struct bt431_regs *bt431;
+	unsigned long fb_start;
+	unsigned long fb_size;
+	unsigned long fb_line_length;
+};
+
+/*
+ * Max 3 TURBOchannel slots -> max 3 PMAG-AA.
+ */
+static struct aafb_info my_fb_info[3];
+
+static struct aafb_par {
+} current_par;
+
+static int currcon = -1;
+
+static void aafb_set_cursor(struct aafb_info *info, int on)
+{
+	struct aafb_cursor *c = &info->cursor;
+
+	if (on) {
+		bt431_position_cursor(info->bt431, c->x, c->y);
+		bt431_enable_cursor(info->bt431);
+	} else
+		bt431_erase_cursor(info->bt431);
+}
+
+static void aafbcon_cursor(struct display *disp, int mode, int x, int y)
+{
+	struct aafb_info *info = (struct aafb_info *)disp->fb_info;
+	struct aafb_cursor *c = &info->cursor;
+
+	x *= fontwidth(disp);
+	y *= fontheight(disp);
+
+	if (c->x == x && c->y == y && (mode == CM_ERASE) == !c->enable)
+		return;
+
+	c->enable = 0;
+	if (c->on)
+		aafb_set_cursor(info, 0);
+	c->x = x - disp->var.xoffset;
+	c->y = y - disp->var.yoffset;
+
+	switch (mode) {
+		case CM_ERASE:
+			c->on = 0;
+			break;
+		case CM_DRAW:
+		case CM_MOVE:
+			if (c->on)
+				aafb_set_cursor(info, c->on);
+			else
+				c->vbl_cnt = CURSOR_DRAW_DELAY;
+			c->enable = 1;
+			break;
+	}
+}
+
+static int aafbcon_set_font(struct display *disp, int width, int height)
+{
+	struct aafb_info *info = (struct aafb_info *)disp->fb_info;
+	struct aafb_cursor *c = &info->cursor;
+	u8 fgc = ~attr_bgcol_ec(disp, disp->conp);
+
+	if (width > 64 || height > 64 || width < 0 || height < 0)
+		return -EINVAL;
+
+	c->height = height;
+	c->width = width;
+
+	bt431_set_font(info->bt431, fgc, width, height);
+
+	return 1;
+}
+
+static void aafb_cursor_timer_handler(unsigned long data)
+{
+	struct aafb_info *info = (struct aafb_info *)data;
+	struct aafb_cursor *c = &info->cursor;
+
+	if (!c->enable)
+		goto out;
+
+	if (c->vbl_cnt && --c->vbl_cnt == 0) {
+		c->on ^= 1;
+		aafb_set_cursor(info, c->on);
+		c->vbl_cnt = c->blink_rate;
+	}
+
+out:
+	c->timer.expires = jiffies + CURSOR_TIMER_FREQ;
+	add_timer(&c->timer);
+}
+
+static void __init aafb_cursor_init(struct aafb_info *info)
+{
+	struct aafb_cursor *c = &info->cursor;
+
+	c->enable = 1;
+	c->on = 1;
+	c->x = c->y = 0;
+	c->width = c->height = 0;
+	c->vbl_cnt = CURSOR_DRAW_DELAY;
+	c->blink_rate = CURSOR_BLINK_RATE;
+
+	init_timer(&c->timer);
+	c->timer.data = (unsigned long)info;
+	c->timer.function = aafb_cursor_timer_handler;
+	mod_timer(&c->timer, jiffies + CURSOR_TIMER_FREQ);
+}
+
+static void __exit aafb_cursor_exit(struct aafb_info *info)
+{
+	struct aafb_cursor *c = &info->cursor;
+
+	del_timer_sync(&c->timer);
+}
+
+static struct display_switch aafb_switch8 = {
+	.setup = fbcon_cfb8_setup,
+	.bmove = fbcon_cfb8_bmove,
+	.clear = fbcon_cfb8_clear,
+	.putc = fbcon_cfb8_putc,
+	.putcs = fbcon_cfb8_putcs,
+	.revc = fbcon_cfb8_revc,
+	.cursor = aafbcon_cursor,
+	.set_font = aafbcon_set_font,
+	.clear_margins = fbcon_cfb8_clear_margins,
+	.fontwidthmask = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+
+static void aafb_get_par(struct aafb_par *par)
+{
+	*par = current_par;
+}
+
+static int aafb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			struct fb_info *info)
+{
+	struct aafb_info *ip = (struct aafb_info *)info;
+
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+	strcpy(fix->id, "PMAG-AA");
+	fix->smem_start = ip->fb_start;
+	fix->smem_len = ip->fb_size;
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->ypanstep = 1;
+	fix->ywrapstep = 1;
+	fix->visual = FB_VISUAL_MONO10;
+	fix->line_length = 1280;
+	fix->accel = FB_ACCEL_NONE;
+
+	return 0;
+}
+
+static void aafb_set_disp(struct display *disp, int con,
+			  struct aafb_info *info)
+{
+	struct fb_fix_screeninfo fix;
+
+	disp->fb_info = &info->info;
+	aafb_set_var(&disp->var, con, &info->info);
+	if (disp->conp && disp->conp->vc_sw && disp->conp->vc_sw->con_cursor)
+		disp->conp->vc_sw->con_cursor(disp->conp, CM_ERASE);
+	disp->dispsw = &aafb_switch8;
+	disp->dispsw_data = 0;
+
+	aafb_get_fix(&fix, con, &info->info);
+	disp->screen_base = (u8 *) fix.smem_start;
+	disp->visual = fix.visual;
+	disp->type = fix.type;
+	disp->type_aux = fix.type_aux;
+	disp->ypanstep = fix.ypanstep;
+	disp->ywrapstep = fix.ywrapstep;
+	disp->line_length = fix.line_length;
+	disp->next_line = 2048;
+	disp->can_soft_blank = 1;
+	disp->inverse = 0;
+	disp->scrollmode = SCROLL_YREDRAW;
+
+	aafbcon_set_font(disp, fontwidth(disp), fontheight(disp));
+}
+
+static int aafb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			 struct fb_info *info)
+{
+	static u16 color[2] = {0x0000, 0x000f};
+	static struct fb_cmap aafb_cmap = {0, 2, color, color, color, NULL};
+
+	fb_copy_cmap(&aafb_cmap, cmap, kspc ? 0 : 2);
+	return 0;
+}
+
+static int aafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			 struct fb_info *info)
+{
+	u16 color[2] = {0x0000, 0x000f};
+
+	if (cmap->start == 0
+	    && cmap->len == 2
+	    && memcmp(cmap->red, color, sizeof(color)) == 0
+	    && memcmp(cmap->green, color, sizeof(color)) == 0
+	    && memcmp(cmap->blue, color, sizeof(color)) == 0
+	    && cmap->transp == NULL)
+		return 0;
+	else
+		return -EINVAL;
+}
+
+static int aafb_ioctl(struct inode *inode, struct file *file, u32 cmd,
+		      unsigned long arg, int con, struct fb_info *info)
+{
+	/* TODO: Not yet implemented */
+	return -ENOIOCTLCMD;
+}
+
+static int aafb_switch(int con, struct fb_info *info)
+{
+	struct aafb_info *ip = (struct aafb_info *)info;
+	struct display *old = (currcon < 0) ? &ip->disp : (fb_display + currcon);
+	struct display *new = (con < 0) ? &ip->disp : (fb_display + con);
+
+	if (old->conp && old->conp->vc_sw && old->conp->vc_sw->con_cursor)
+		old->conp->vc_sw->con_cursor(old->conp, CM_ERASE);
+
+	/* Set the current console. */
+	currcon = con;
+	aafb_set_disp(new, con, ip);
+
+	return 0;
+}
+
+static void aafb_encode_var(struct fb_var_screeninfo *var,
+			    struct aafb_par *par)
+{
+	var->xres = 1280;
+	var->yres = 1024;
+	var->xres_virtual = 2048;
+	var->yres_virtual = 1024;
+	var->xoffset = 0;
+	var->yoffset = 0;
+	var->bits_per_pixel = 8;
+	var->grayscale = 1;
+	var->red.offset = 0;
+	var->red.length = 0;
+	var->red.msb_right = 0;
+	var->green.offset = 0;
+	var->green.length = 1;
+	var->green.msb_right = 0;
+	var->blue.offset = 0;
+	var->blue.length = 0;
+	var->blue.msb_right = 0;
+	var->transp.offset = 0;
+	var->transp.length = 0;
+	var->transp.msb_right = 0;
+	var->nonstd = 0;
+	var->activate &= ~FB_ACTIVATE_MASK & FB_ACTIVATE_NOW;
+	var->accel_flags = 0;
+	var->sync = FB_SYNC_ON_GREEN;
+	var->vmode &= ~FB_VMODE_MASK & FB_VMODE_NONINTERLACED;
+}
+
+static int aafb_get_var(struct fb_var_screeninfo *var, int con,
+			struct fb_info *info)
+{
+	if (con < 0) {
+		struct aafb_par par;
+
+		memset(var, 0, sizeof(struct fb_var_screeninfo));
+		aafb_get_par(&par);
+		aafb_encode_var(var, &par);
+	} else
+		*var = info->var;
+
+	return 0;
+}
+
+static int aafb_set_var(struct fb_var_screeninfo *var, int con,
+			struct fb_info *info)
+{
+	struct aafb_par par;
+
+	aafb_get_par(&par);
+	aafb_encode_var(var, &par);
+	info->var = *var;
+
+	return 0;
+}
+
+static int aafb_update_var(int con, struct fb_info *info)
+{
+	struct aafb_info *ip = (struct aafb_info *)info;
+	struct display *disp = (con < 0) ? &ip->disp : (fb_display + con);
+
+	if (con == currcon)
+		aafbcon_cursor(disp, CM_ERASE, ip->cursor.x, ip->cursor.y);
+
+	return 0;
+}
+
+/* 0 unblanks, any other blanks. */
+
+static void aafb_blank(int blank, struct fb_info *info)
+{
+	struct aafb_info *ip = (struct aafb_info *)info;
+	u8 val = blank ? 0x00 : 0x0f;
+
+	bt455_write_cmap_entry(ip->bt455, 1, val, val, val);
+	aafbcon_cursor(&ip->disp, CM_ERASE, ip->cursor.x, ip->cursor.y);
+}
+
+static struct fb_ops aafb_ops = {
+	.owner = THIS_MODULE,
+	.fb_get_fix = aafb_get_fix,
+	.fb_get_var = aafb_get_var,
+	.fb_set_var = aafb_set_var,
+	.fb_get_cmap = aafb_get_cmap,
+	.fb_set_cmap = aafb_set_cmap,
+	.fb_ioctl = aafb_ioctl
+};
+
+static int __init init_one(int slot)
+{
+	unsigned long base_addr = get_tc_base_addr(slot);
+	struct aafb_info *ip = &my_fb_info[slot];
+
+	memset(ip, 0, sizeof(struct aafb_info));
+
+	/*
+	 * Framebuffer display memory base address and friends.
+	 */
+	ip->bt455 = (struct bt455_regs *) (base_addr + PMAG_AA_BT455_OFFSET);
+	ip->bt431 = (struct bt431_regs *) (base_addr + PMAG_AA_BT431_OFFSET);
+	ip->fb_start = base_addr + PMAG_AA_ONBOARD_FBMEM_OFFSET;
+	ip->fb_size = 2048 * 1024; /* fb_fix_screeninfo.smem_length
+				      seems to be physical */
+	ip->fb_line_length = 2048;
+
+	/*
+	 * Let there be consoles..
+	 */
+	strcpy(ip->info.modename, "PMAG-AA");
+	ip->info.node = -1;
+	ip->info.flags = FBINFO_FLAG_DEFAULT;
+	ip->info.fbops = &aafb_ops;
+	ip->info.disp = &ip->disp;
+	ip->info.changevar = NULL;
+	ip->info.switch_con = &aafb_switch;
+	ip->info.updatevar = &aafb_update_var;
+	ip->info.blank = &aafb_blank;
+
+	aafb_set_disp(&ip->disp, currcon, ip);
+
+	/*
+	 * Configure the RAM DACs.
+	 */
+	bt455_erase_cursor(ip->bt455);
+
+	/* Init colormap. */
+	bt455_write_cmap_entry(ip->bt455, 0, 0x00, 0x00, 0x00);
+	bt455_write_cmap_entry(ip->bt455, 1, 0x0f, 0x0f, 0x0f);
+
+	/* Init hardware cursor. */
+	bt431_init_cursor(ip->bt431);
+	aafb_cursor_init(ip);
+
+	/* Clear the screen. */
+	memset ((void *)ip->fb_start, 0, ip->fb_size);
+
+	if (register_framebuffer(&ip->info) < 0)
+		return -EINVAL;
+
+	printk(KERN_INFO "fb%d: %s frame buffer in TC slot %d\n",
+	       GET_FB_IDX(ip->info.node), ip->info.modename, slot);
+
+	return 0;
+}
+
+static int __exit exit_one(int slot)
+{
+	struct aafb_info *ip = &my_fb_info[slot];
+
+	if (unregister_framebuffer(&ip->info) < 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+/*
+ * Initialise the framebuffer.
+ */
+int __init pmagaafb_init(void)
+{
+	int sid;
+	int found = 0;
+
+	while ((sid = search_tc_card("PMAG-AA")) >= 0) {
+		found = 1;
+		claim_tc_card(sid);
+		init_one(sid);
+	}
+
+	return found ? 0 : -ENXIO;
+}
+
+static void __exit pmagaafb_exit(void)
+{
+	int sid;
+
+	while ((sid = search_tc_card("PMAG-AA")) >= 0) {
+		exit_one(sid);
+		release_tc_card(sid);
+	}
+}
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
+MODULE_LICENSE("GPL");
+#ifdef MODULE
+module_init(pmagaafb_init);
+module_exit(pmagaafb_exit);
+#endif
diff --git a/drivers/video/pmag-ba-fb.c b/drivers/video/pmag-ba-fb.c
new file mode 100644
index 0000000..f809558
--- /dev/null
+++ b/drivers/video/pmag-ba-fb.c
@@ -0,0 +1,182 @@
+/*
+ *      linux/drivers/video/pmag-ba-fb.c
+ *
+ *	PMAG-BA TurboChannel framebuffer card support ... derived from:
+ *	"HP300 Topcat framebuffer support (derived from macfb of all things)
+ *	Phil Blundell <philb@gnu.org> 1998", the original code can be
+ *      found in the file hpfb.c in the same directory.
+ *
+ *	Based on digital document:
+ * 	"PMAG-BA TURBOchannel Color Frame Buffer
+ *	 Functional Specification", Revision 1.2, August 27, 1990
+ *
+ *      DECstation related code Copyright (C) 1999, 2000, 2001 by
+ *      Michael Engel <engel@unix-ag.org>, 
+ *      Karsten Merker <merker@linuxtag.org> and
+ *	Harald Koerfgen.
+ *      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/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <asm/bootinfo.h>
+#include <asm/dec/machtype.h>
+#include <asm/dec/tc.h>
+#include <video/pmag-ba-fb.h>
+
+struct pmag_ba_ramdac_regs {
+	unsigned char addr_low;
+	unsigned char pad0[3];
+	unsigned char addr_hi;
+	unsigned char pad1[3];
+	unsigned char data;
+	unsigned char pad2[3];
+	unsigned char cmap;
+};
+
+/*
+ * Max 3 TURBOchannel slots -> max 3 PMAG-BA :)
+ */
+static struct fb_info pmagba_fb_info[3];
+
+static struct fb_var_screeninfo pmagbafb_defined = {
+	.xres		= 1024,
+	.yres		= 864,
+	.xres_virtual	= 1024,
+	.yres_virtual	= 864,
+	.bits_per_pixel	= 8,
+	.red.length	= 8,
+	.green.length	= 8,
+	.blue.length	= 8,
+	.activate	= FB_ACTIVATE_NOW,
+	.height		= 274,
+	.width		= 195,
+	.accel		= FB_ACCEL_NONE,
+	.vmode		= FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_fix_screeninfo pmagbafb_fix = {
+	.id		= "PMAG-BA",
+	.smem_len	= (1024 * 864),
+	.type		= FB_TYPE_PACKED_PIXELS,
+	.visual		= FB_VISUAL_PSEUDOCOLOR,
+	.line_length	= 1024,
+};
+
+/*
+ * Turn hardware cursor off
+ */
+void pmagbafb_erase_cursor(struct pmag_ba_ramdac_regs *bt459_regs)
+{
+	bt459_regs->addr_low = 0;
+	bt459_regs->addr_hi = 3;
+	bt459_regs->data = 0;
+}
+
+/*
+ * Set the palette. 
+ */
+static int pmagbafb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			      unsigned blue, unsigned transp,
+			      struct fb_info *info)
+{
+	struct pmag_ba_ramdac_regs *bt459_regs = (struct pmag_ba_ramdac_regs *) info->par;
+
+	if (regno >= info->cmap.len)
+		return 1;
+
+	red   >>= 8;	/* The cmap fields are 16 bits    */
+	green >>= 8;	/* wide, but the harware colormap */
+	blue  >>= 8;	/* registers are only 8 bits wide */
+
+	bt459_regs->addr_low = (__u8) regno;
+	bt459_regs->addr_hi = 0;
+	bt459_regs->cmap = red;
+	bt459_regs->cmap = green;
+	bt459_regs->cmap = blue;
+	return 0;
+}
+
+static struct fb_ops pmagbafb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_get_fix	= gen_get_fix,
+	.fb_get_var	= gen_get_var,
+	.fb_setcolreg	= pmagbafb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+int __init pmagbafb_init_one(int slot)
+{
+	unsigned long base_addr = get_tc_base_addr(slot);
+	struct fb_info *info = &pmagba_fb_info[slot]; 
+	struct display *disp = &pmagba_disp[slot];
+
+	printk("PMAG-BA framebuffer in slot %d\n", slot);
+	/*
+	 * Framebuffer display memory base address and friends
+	 */
+	pmagbafb_fix.smem_start = base_addr + PMAG_BA_ONBOARD_FBMEM_OFFSET;
+	info->par = (base_addr + PMAG_BA_BT459_OFFSET);
+
+	/*
+	 * Configure the Bt459 RAM DAC
+	 */
+	pmagbafb_erase_cursor((struct pmag_ba_ramdac_regs *) info->par);
+
+	/*
+	 *      Let there be consoles..
+	 */
+	info->fbops = &pmagbafb_ops;
+	info->var = pmagbafb_defined;
+	info->fix = pmagbafb_fix; 
+	info->screen_base = pmagbafb_fix.smem_start;
+	info->flags = FBINFO_DEFAULT;
+
+	fb_alloc_cmap(&fb_info.cmap, 256, 0);
+
+	if (register_framebuffer(info) < 0)
+		return 1;
+	return 0;
+}
+
+/* 
+ * Initialise the framebuffer
+ */
+
+int __init pmagbafb_init(void)
+{
+	int sid;
+	int found = 0;
+
+	if (fb_get_options("pmagbafb", NULL))
+		return -ENODEV;
+
+	if (TURBOCHANNEL) {
+		while ((sid = search_tc_card("PMAG-BA")) >= 0) {
+			found = 1;
+			claim_tc_card(sid);
+			pmagbafb_init_one(sid);
+		}
+		return found ? 0 : -ENODEV;
+	} else {
+		return -ENODEV;
+	}
+}
+
+module_init(pmagbafb_init);
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/pmagb-b-fb.c b/drivers/video/pmagb-b-fb.c
new file mode 100644
index 0000000..d14eaee
--- /dev/null
+++ b/drivers/video/pmagb-b-fb.c
@@ -0,0 +1,182 @@
+/*
+ *      linux/drivers/video/pmagb-b-fb.c
+ *
+ *	PMAGB-B TurboChannel framebuffer card support ... derived from:
+ *	"HP300 Topcat framebuffer support (derived from macfb of all things)
+ *	Phil Blundell <philb@gnu.org> 1998", the original code can be
+ *      found in the file hpfb.c in the same directory.
+ *
+ *      DECstation related code Copyright (C) 1999, 2000, 2001 by
+ *      Michael Engel <engel@unix-ag.org>,
+ *      Karsten Merker <merker@linuxtag.org> and 
+ *	Harald Koerfgen.
+ *      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.
+ *
+ */
+
+/*
+ *      We currently only support the PMAGB-B in high resolution mode
+ *      as I know of no way to detect low resolution mode set via jumper.
+ *      KM, 2001/01/07
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <asm/bootinfo.h>
+#include <asm/dec/machtype.h>
+#include <asm/dec/tc.h>
+#include <video/pmagb-b-fb.h>
+
+struct pmagb_b_ramdac_regs {
+	unsigned char addr_low;
+	unsigned char pad0[3];
+	unsigned char addr_hi;
+	unsigned char pad1[3];
+	unsigned char data;
+	unsigned char pad2[3];
+	unsigned char cmap;
+};
+
+/*
+ * Max 3 TURBOchannel slots -> max 3 PMAGB-B :)
+ */
+static struct fb_info pmagbb_fb_info[3];
+
+static struct fb_var_screeninfo pmagbbfb_defined = {
+	.xres		= 1280,
+	.yres		= 1024,
+	.xres_virtual	= 1280,
+	.yres_virtual	= 1024,
+	.bits_per_pixel	= 8,
+	.red.length	= 8,
+	.green.length	= 8,
+	.blue.length	= 8,
+	.activate	= FB_ACTIVATE_NOW,
+	.height		= 274,
+	.width		= 195,
+	.accel_flags	= FB_ACCEL_NONE,
+	.vmode		= FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_fix_screeninfo pmagbafb_fix = {
+	.id		= "PMAGB-BA",
+	.smem_len	= (1280 * 1024),
+	.type		= FB_TYPE_PACKED_PIXELS,
+	.visual		= FB_VISUAL_PSEUDOCOLOR,
+	.line_length	= 1280,
+}
+
+/*
+ * Turn hardware cursor off
+ */
+void pmagbbfb_erase_cursor(struct pmagb_b_ramdac_regs *bt459_regs)
+{
+	bt459_regs->addr_low = 0;
+	bt459_regs->addr_hi = 3;
+	bt459_regs->data = 0;
+}
+
+/*
+ * Set the palette. 
+ */
+static int pmagbbfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+                              unsigned blue, unsigned transp,
+                              struct fb_info *info)
+{
+	struct pmagb_b_ramdac_regs *bt459_regs = (struct pmagb_b_ramdac_regs *) info->par;
+	
+	if (regno >= info->cmap.len)
+		return 1;
+
+	red   >>= 8;	/* The cmap fields are 16 bits    */
+	green >>= 8;	/* wide, but the harware colormap */
+	blue  >>= 8;	/* registers are only 8 bits wide */
+
+	bt459_regs->addr_low = (__u8) regno;
+	bt459_regs->addr_hi = 0;
+	bt459_regs->cmap = red;
+	bt459_regs->cmap = green;
+	bt459_regs->cmap = blue;
+	return 0;
+}
+
+static struct fb_ops pmagbbfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_setcolreg	= pmagbbfb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+int __init pmagbbfb_init_one(int slot)
+{
+	unsigned long base_addr = get_tc_base_addr(slot);
+	struct fb_info *info = &pmagbb_fb_info[slot];
+
+	printk("PMAGB-BA framebuffer in slot %d\n", slot);
+	/*
+	 * Framebuffer display memory base address and friends
+	 */
+	pmagbbfb_fix.smem_start = base_addr + PMAGB_B_ONBOARD_FBMEM_OFFSET;
+	info->par = (base_addr + PMAGB_B_BT459_OFFSET); 
+	
+	/*
+	 * Configure the Bt459 RAM DAC
+	 */
+	pmagbbfb_erase_cursor((struct pmagb_b_ramdac_regs *) info->par);
+
+	/*
+	 *      Let there be consoles..
+	 */
+	info->fbops = &pmagbbfb_ops;
+	info->var = pmagbbfb_defined;
+	info->fix = pmagbbfb_fix;
+	info->screen_base = pmagbbfb_fix.smem_start; 
+	info->flags = FBINFO_DEFAULT;
+
+	fb_alloc_cmap(&fb_info.cmap, 256, 0);
+
+	if (register_framebuffer(info) < 0)
+		return 1;
+	return 0;
+}
+
+/* 
+ * Initialise the framebuffer
+ */
+
+int __init pmagbbfb_init(void)
+{
+	int sid;
+	int found = 0;
+
+	if (fb_get_options("pmagbbfb", NULL))
+		return -ENODEV;
+
+	if (TURBOCHANNEL) {
+		while ((sid = search_tc_card("PMAGB-BA")) >= 0) {
+			found = 1;
+			claim_tc_card(sid);
+			pmagbbfb_init_one(sid);
+		}
+		return found ? 0 : -ENODEV;
+	} else {
+		return -ENODEV;
+	}
+}
+
+module_init(pmagbbfb_init);
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c
new file mode 100644
index 0000000..31c547f
--- /dev/null
+++ b/drivers/video/pvr2fb.c
@@ -0,0 +1,1125 @@
+/* drivers/video/pvr2fb.c
+ *
+ * Frame buffer and fbcon support for the NEC PowerVR2 found within the Sega
+ * Dreamcast.
+ *
+ * Copyright (c) 2001 M. R. Brown <mrbrown@0xd6.org>
+ * Copyright (c) 2001, 2002, 2003, 2004, 2005 Paul Mundt <lethal@linux-sh.org>
+ *
+ * This file is part of the LinuxDC project (linuxdc.sourceforge.net).
+ *
+ */
+
+/*
+ * This driver is mostly based on the excellent amifb and vfb sources.  It uses
+ * an odd scheme for converting hardware values to/from framebuffer values,
+ * here are some hacked-up formulas:
+ *
+ *  The Dreamcast has screen offsets from each side of its four borders and
+ *  the start offsets of the display window.  I used these values to calculate
+ *  'pseudo' values (think of them as placeholders) for the fb video mode, so
+ *  that when it came time to convert these values back into their hardware
+ *  values, I could just add mode- specific offsets to get the correct mode
+ *  settings:
+ *
+ *      left_margin = diwstart_h - borderstart_h;
+ *      right_margin = borderstop_h - (diwstart_h + xres);
+ *      upper_margin = diwstart_v - borderstart_v;
+ *      lower_margin = borderstop_v - (diwstart_h + yres);
+ *
+ *      hsync_len = borderstart_h + (hsync_total - borderstop_h);
+ *      vsync_len = borderstart_v + (vsync_total - borderstop_v);
+ *
+ *  Then, when it's time to convert back to hardware settings, the only
+ *  constants are the borderstart_* offsets, all other values are derived from
+ *  the fb video mode:
+ *
+ *      // PAL
+ *      borderstart_h = 116;
+ *      borderstart_v = 44;
+ *      ...
+ *      borderstop_h = borderstart_h + hsync_total - hsync_len;
+ *      ...
+ *      diwstart_v = borderstart_v - upper_margin;
+ *
+ *  However, in the current implementation, the borderstart values haven't had
+ *  the benefit of being fully researched, so some modes may be broken.
+ */
+
+#undef DEBUG
+
+#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/delay.h>
+#include <linux/config.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#ifdef CONFIG_SH_DREAMCAST
+#include <asm/machvec.h>
+#include <asm/mach/sysasic.h>
+#endif
+
+#ifdef CONFIG_SH_DMA
+#include <linux/pagemap.h>
+#include <asm/mach/dma.h>
+#include <asm/dma.h>
+#endif
+
+#ifdef CONFIG_SH_STORE_QUEUES
+#include <asm/uaccess.h>
+#include <asm/cpu/sq.h>
+#endif
+
+#ifndef PCI_DEVICE_ID_NEC_NEON250
+#  define PCI_DEVICE_ID_NEC_NEON250	0x0067
+#endif
+
+/* 2D video registers */
+#define DISP_BASE	par->mmio_base
+#define DISP_BRDRCOLR (DISP_BASE + 0x40)
+#define DISP_DIWMODE (DISP_BASE + 0x44)
+#define DISP_DIWADDRL (DISP_BASE + 0x50)
+#define DISP_DIWADDRS (DISP_BASE + 0x54)
+#define DISP_DIWSIZE (DISP_BASE + 0x5c)
+#define DISP_SYNCCONF (DISP_BASE + 0xd0)
+#define DISP_BRDRHORZ (DISP_BASE + 0xd4)
+#define DISP_SYNCSIZE (DISP_BASE + 0xd8)
+#define DISP_BRDRVERT (DISP_BASE + 0xdc)
+#define DISP_DIWCONF (DISP_BASE + 0xe8)
+#define DISP_DIWHSTRT (DISP_BASE + 0xec)
+#define DISP_DIWVSTRT (DISP_BASE + 0xf0)
+
+/* Pixel clocks, one for TV output, doubled for VGA output */
+#define TV_CLK 74239
+#define VGA_CLK 37119
+
+/* This is for 60Hz - the VTOTAL is doubled for interlaced modes */
+#define PAL_HTOTAL 863
+#define PAL_VTOTAL 312
+#define NTSC_HTOTAL 857
+#define NTSC_VTOTAL 262
+
+/* Supported cable types */
+enum { CT_VGA, CT_NONE, CT_RGB, CT_COMPOSITE };
+
+/* Supported video output types */
+enum { VO_PAL, VO_NTSC, VO_VGA };
+
+/* Supported palette types */
+enum { PAL_ARGB1555, PAL_RGB565, PAL_ARGB4444, PAL_ARGB8888 };
+
+struct pvr2_params { unsigned int val; char *name; };
+static struct pvr2_params cables[] __initdata = {
+	{ CT_VGA, "VGA" }, { CT_RGB, "RGB" }, { CT_COMPOSITE, "COMPOSITE" },
+};
+
+static struct pvr2_params outputs[] __initdata = {
+	{ VO_PAL, "PAL" }, { VO_NTSC, "NTSC" }, { VO_VGA, "VGA" },
+};
+
+/*
+ * This describes the current video mode
+ */
+
+static struct pvr2fb_par {
+	unsigned int hsync_total;	/* Clocks/line */
+	unsigned int vsync_total;	/* Lines/field */
+	unsigned int borderstart_h;
+	unsigned int borderstop_h;
+	unsigned int borderstart_v;
+	unsigned int borderstop_v;
+	unsigned int diwstart_h;	/* Horizontal offset of the display field */
+	unsigned int diwstart_v;	/* Vertical offset of the display field, for
+				   interlaced modes, this is the long field */
+	unsigned long disp_start;	/* Address of image within VRAM */
+	unsigned char is_interlaced;	/* Is the display interlaced? */
+	unsigned char is_doublescan;	/* Are scanlines output twice? (doublescan) */
+	unsigned char is_lowres;	/* Is horizontal pixel-doubling enabled? */
+
+	unsigned long mmio_base;	/* MMIO base */
+} *currentpar;
+
+static struct fb_info *fb_info;
+
+static struct fb_fix_screeninfo pvr2_fix __initdata = {
+	.id =		"NEC PowerVR2",
+	.type = 	FB_TYPE_PACKED_PIXELS,
+	.visual = 	FB_VISUAL_TRUECOLOR,
+	.ypanstep =	1,
+	.ywrapstep =	1,
+	.accel = 	FB_ACCEL_NONE,
+};
+
+static struct fb_var_screeninfo pvr2_var __initdata = {
+	.xres =		640,
+	.yres =		480,
+	.xres_virtual =	640,
+	.yres_virtual = 480,
+	.bits_per_pixel	=16,
+	.red =		{ 11, 5, 0 },
+	.green =	{  5, 6, 0 },
+	.blue =		{  0, 5, 0 },
+	.activate =	FB_ACTIVATE_NOW,
+	.height =	-1,
+	.width =	-1,
+	.vmode =	FB_VMODE_NONINTERLACED,
+};
+
+static int cable_type = CT_VGA;
+static int video_output = VO_VGA;
+
+static int nopan = 0;
+static int nowrap = 1;
+
+/*
+ * We do all updating, blanking, etc. during the vertical retrace period
+ */
+static unsigned int do_vmode_full = 0;	/* Change the video mode */
+static unsigned int do_vmode_pan = 0;	/* Update the video mode */
+static short do_blank = 0;		/* (Un)Blank the screen */
+
+static unsigned int is_blanked = 0;		/* Is the screen blanked? */
+
+#ifdef CONFIG_SH_STORE_QUEUES
+static struct sq_mapping *pvr2fb_map;
+#endif
+
+#ifdef CONFIG_SH_DMA
+static unsigned int shdma = PVR2_CASCADE_CHAN;
+static unsigned int pvr2dma = ONCHIP_NR_DMA_CHANNELS;
+#endif
+
+/* Interface used by the world */
+
+int pvr2fb_setup(char*);
+
+static int pvr2fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, unsigned int blue,
+                            unsigned int transp, struct fb_info *info);
+static int pvr2fb_blank(int blank, struct fb_info *info);
+static unsigned long get_line_length(int xres_virtual, int bpp);
+static void set_color_bitfields(struct fb_var_screeninfo *var);
+static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info);
+static int pvr2fb_set_par(struct fb_info *info);
+static void pvr2_update_display(struct fb_info *info);
+static void pvr2_init_display(struct fb_info *info);
+static void pvr2_do_blank(void);
+static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id, struct pt_regs *fp);
+static int pvr2_init_cable(void);
+static int pvr2_get_param(const struct pvr2_params *p, const char *s,
+                            int val, int size);
+static ssize_t pvr2fb_write(struct file *file, const char *buf,
+			    size_t count, loff_t *ppos);
+
+static struct fb_ops pvr2fb_ops = {
+	.owner 		= THIS_MODULE,
+	.fb_setcolreg 	= pvr2fb_setcolreg,
+	.fb_blank 	= pvr2fb_blank,
+	.fb_check_var 	= pvr2fb_check_var,
+	.fb_set_par 	= pvr2fb_set_par,
+#ifdef CONFIG_SH_DMA
+	.fb_write	= pvr2fb_write,
+#endif
+	.fb_fillrect 	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+static struct fb_videomode pvr2_modedb[] __initdata = {
+    /*
+     * Broadcast video modes (PAL and NTSC).  I'm unfamiliar with
+     * PAL-M and PAL-N, but from what I've read both modes parallel PAL and
+     * NTSC, so it shouldn't be a problem (I hope).
+     */
+
+    {
+	/* 640x480 @ 60Hz interlaced (NTSC) */
+	"ntsc_640x480i", 60, 640, 480, TV_CLK, 38, 33, 0, 18, 146, 26,
+	FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+    }, {
+	/* 640x240 @ 60Hz (NTSC) */
+	/* XXX: Broken! Don't use... */
+	"ntsc_640x240", 60, 640, 240, TV_CLK, 38, 33, 0, 0, 146, 22,
+	FB_SYNC_BROADCAST, FB_VMODE_YWRAP
+    }, {
+	/* 640x480 @ 60hz (VGA) */
+	"vga_640x480", 60, 640, 480, VGA_CLK, 38, 33, 0, 18, 146, 26,
+	0, FB_VMODE_YWRAP
+    }, 
+};
+
+#define NUM_TOTAL_MODES  ARRAY_SIZE(pvr2_modedb)
+
+#define DEFMODE_NTSC	0
+#define DEFMODE_PAL	0
+#define DEFMODE_VGA	2
+
+static int defmode = DEFMODE_NTSC;
+static char *mode_option __initdata = NULL;
+
+static inline void pvr2fb_set_pal_type(unsigned int type)
+{
+	struct pvr2fb_par *par = (struct pvr2fb_par *)fb_info->par;
+
+	fb_writel(type, par->mmio_base + 0x108);
+}
+
+static inline void pvr2fb_set_pal_entry(struct pvr2fb_par *par,
+					unsigned int regno,
+					unsigned int val)
+{
+	fb_writel(val, par->mmio_base + 0x1000 + (4 * regno));
+}
+
+static int pvr2fb_blank(int blank, struct fb_info *info)
+{
+	do_blank = blank ? blank : -1;
+	return 0;
+}
+
+static inline unsigned long get_line_length(int xres_virtual, int bpp)
+{
+	return (unsigned long)((((xres_virtual*bpp)+31)&~31) >> 3);
+}
+
+static void set_color_bitfields(struct fb_var_screeninfo *var)
+{
+	switch (var->bits_per_pixel) {
+	    case 16:        /* RGB 565 */
+	    	pvr2fb_set_pal_type(PAL_RGB565);
+		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;
+	    case 24:        /* RGB 888 */
+		var->red.offset = 16;    var->red.length = 8;
+		var->green.offset = 8;   var->green.length = 8;
+		var->blue.offset = 0;    var->blue.length = 8;
+		var->transp.offset = 0;  var->transp.length = 0;
+		break;
+	    case 32:        /* ARGB 8888 */
+	    	pvr2fb_set_pal_type(PAL_ARGB8888);
+		var->red.offset = 16;    var->red.length = 8;
+		var->green.offset = 8;   var->green.length = 8;
+		var->blue.offset = 0;    var->blue.length = 8;
+		var->transp.offset = 24; var->transp.length = 8;
+		break;
+	}
+}
+
+static int pvr2fb_setcolreg(unsigned int regno, unsigned int red,
+			    unsigned int green, unsigned int blue,
+                            unsigned int transp, struct fb_info *info)
+{
+	struct pvr2fb_par *par = (struct pvr2fb_par *)info->par;
+	unsigned int tmp;
+
+	if (regno > info->cmap.len)
+		return 1;
+
+	/*
+	 * We only support the hardware palette for 16 and 32bpp. It's also
+	 * expected that the palette format has been set by the time we get
+	 * here, so we don't waste time setting it again.
+	 */
+	switch (info->var.bits_per_pixel) {
+	    case 16: /* RGB 565 */
+		tmp =  (red   & 0xf800)       |
+		      ((green & 0xfc00) >> 5) |
+		      ((blue  & 0xf800) >> 11);
+
+		pvr2fb_set_pal_entry(par, regno, tmp);
+		((u16*)(info->pseudo_palette))[regno] = tmp;
+		break;
+	    case 24: /* RGB 888 */
+		red >>= 8; green >>= 8; blue >>= 8;
+		((u32*)(info->pseudo_palette))[regno] = (red << 16) | (green << 8) | blue;
+		break;
+	    case 32: /* ARGB 8888 */
+		red >>= 8; green >>= 8; blue >>= 8;
+		tmp = (transp << 24) | (red << 16) | (green << 8) | blue;
+
+		pvr2fb_set_pal_entry(par, regno, tmp);
+		((u32*)(info->pseudo_palette))[regno] = tmp;
+		break;
+	    default:
+		pr_debug("Invalid bit depth %d?!?\n", info->var.bits_per_pixel);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int pvr2fb_set_par(struct fb_info *info)
+{
+	struct pvr2fb_par *par = (struct pvr2fb_par *)info->par;
+	struct fb_var_screeninfo *var = &info->var;
+	unsigned long line_length;
+	unsigned int vtotal;
+
+	/*
+	 * XXX: It's possible that a user could use a VGA box, change the cable
+	 * type in hardware (i.e. switch from VGA<->composite), then change
+	 * modes (i.e. switching to another VT).  If that happens we should
+	 * automagically change the output format to cope, but currently I
+	 * don't have a VGA box to make sure this works properly.
+	 */
+	cable_type = pvr2_init_cable();
+	if (cable_type == CT_VGA && video_output != VO_VGA)
+		video_output = VO_VGA;
+
+	var->vmode &= FB_VMODE_MASK;
+	if (var->vmode & FB_VMODE_INTERLACED && video_output != VO_VGA)
+		par->is_interlaced = 1;
+	/* 
+	 * XXX: Need to be more creative with this (i.e. allow doublecan for
+	 * PAL/NTSC output).
+	 */
+	if (var->vmode & FB_VMODE_DOUBLE && video_output == VO_VGA)
+		par->is_doublescan = 1;
+	
+	par->hsync_total = var->left_margin + var->xres + var->right_margin +
+	                   var->hsync_len;
+	par->vsync_total = var->upper_margin + var->yres + var->lower_margin +
+	                   var->vsync_len;
+
+	if (var->sync & FB_SYNC_BROADCAST) {
+		vtotal = par->vsync_total;
+		if (par->is_interlaced)
+			vtotal /= 2;
+		if (vtotal > (PAL_VTOTAL + NTSC_VTOTAL)/2) {
+			/* XXX: Check for start values here... */
+			/* XXX: Check hardware for PAL-compatibility */
+			par->borderstart_h = 116;
+			par->borderstart_v = 44;
+		} else {
+			/* NTSC video output */
+			par->borderstart_h = 126;
+			par->borderstart_v = 18;
+		}
+	} else {
+		/* VGA mode */
+		/* XXX: What else needs to be checked? */
+		/* 
+		 * XXX: We have a little freedom in VGA modes, what ranges
+		 * should be here (i.e. hsync/vsync totals, etc.)?
+		 */
+		par->borderstart_h = 126;
+		par->borderstart_v = 40;
+	}
+
+	/* Calculate the remainding offsets */
+	par->diwstart_h = par->borderstart_h + var->left_margin;
+	par->diwstart_v = par->borderstart_v + var->upper_margin;
+	par->borderstop_h = par->diwstart_h + var->xres + 
+			    var->right_margin;    
+	par->borderstop_v = par->diwstart_v + var->yres +
+			    var->lower_margin;
+
+	if (!par->is_interlaced)
+		par->borderstop_v /= 2;
+	if (info->var.xres < 640)
+		par->is_lowres = 1;
+
+	line_length = get_line_length(var->xres_virtual, var->bits_per_pixel);
+	par->disp_start = info->fix.smem_start + (line_length * var->yoffset) * line_length;
+	info->fix.line_length = line_length;
+	return 0;
+}
+
+static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct pvr2fb_par *par = (struct pvr2fb_par *)info->par;
+	unsigned int vtotal, hsync_total;
+	unsigned long line_length;
+
+	if (var->pixclock != TV_CLK && var->pixclock != VGA_CLK) {
+		pr_debug("Invalid pixclock value %d\n", var->pixclock);
+		return -EINVAL;
+	}
+
+	if (var->xres < 320)
+		var->xres = 320;
+	if (var->yres < 240)
+		var->yres = 240;
+	if (var->xres_virtual < var->xres)
+		var->xres_virtual = var->xres;
+	if (var->yres_virtual < var->yres)
+		var->yres_virtual = var->yres;
+
+	if (var->bits_per_pixel <= 16)
+		var->bits_per_pixel = 16;
+	else if (var->bits_per_pixel <= 24)
+		var->bits_per_pixel = 24;
+	else if (var->bits_per_pixel <= 32)
+		var->bits_per_pixel = 32;
+
+	set_color_bitfields(var);
+
+	if (var->vmode & FB_VMODE_YWRAP) {
+		if (var->xoffset || var->yoffset < 0 || 
+		    var->yoffset >= var->yres_virtual) {
+			var->xoffset = var->yoffset = 0;
+		} else {
+			if (var->xoffset > var->xres_virtual - var->xres ||
+		    	    var->yoffset > var->yres_virtual - var->yres || 
+			    var->xoffset < 0 || var->yoffset < 0)
+				var->xoffset = var->yoffset = 0;
+		}
+	} else {
+		var->xoffset = var->yoffset = 0;
+	}
+
+	/* 
+	 * XXX: Need to be more creative with this (i.e. allow doublecan for
+	 * PAL/NTSC output).
+	 */
+	if (var->yres < 480 && video_output == VO_VGA)
+		var->vmode |= FB_VMODE_DOUBLE;
+
+	if (video_output != VO_VGA) {
+		var->sync |= FB_SYNC_BROADCAST;
+		var->vmode |= FB_VMODE_INTERLACED;
+	} else {
+		var->sync &= ~FB_SYNC_BROADCAST;
+		var->vmode &= ~FB_VMODE_INTERLACED;
+		var->vmode |= pvr2_var.vmode;
+	}
+
+	if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_TEST) {
+		var->right_margin = par->borderstop_h -
+				   (par->diwstart_h + var->xres);
+		var->left_margin  = par->diwstart_h - par->borderstart_h;
+		var->hsync_len    = par->borderstart_h +
+		                   (par->hsync_total - par->borderstop_h);
+
+		var->upper_margin = par->diwstart_v - par->borderstart_v;
+		var->lower_margin = par->borderstop_v -
+				   (par->diwstart_v + var->yres);
+		var->vsync_len    = par->borderstop_v +
+				   (par->vsync_total - par->borderstop_v);
+	}
+		
+	hsync_total = var->left_margin + var->xres + var->right_margin +
+		      var->hsync_len;
+	vtotal = var->upper_margin + var->yres + var->lower_margin +
+		 var->vsync_len;
+
+	if (var->sync & FB_SYNC_BROADCAST) {
+		if (var->vmode & FB_VMODE_INTERLACED)
+			vtotal /= 2;
+		if (vtotal > (PAL_VTOTAL + NTSC_VTOTAL)/2) {
+			/* PAL video output */
+			/* XXX: Should be using a range here ... ? */
+			if (hsync_total != PAL_HTOTAL) {
+				pr_debug("invalid hsync total for PAL\n");
+				return -EINVAL;
+			}
+		} else {
+			/* NTSC video output */
+			if (hsync_total != NTSC_HTOTAL) {
+				pr_debug("invalid hsync total for NTSC\n");
+				return -EINVAL;
+			}
+		}
+	}
+	
+	/* Check memory sizes */
+	line_length = get_line_length(var->xres_virtual, var->bits_per_pixel);
+	if (line_length * var->yres_virtual > info->fix.smem_len)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void pvr2_update_display(struct fb_info *info)
+{
+	struct pvr2fb_par *par = (struct pvr2fb_par *) info->par;
+	struct fb_var_screeninfo *var = &info->var;
+
+	/* Update the start address of the display image */
+	fb_writel(par->disp_start, DISP_DIWADDRL);
+	fb_writel(par->disp_start +
+		  get_line_length(var->xoffset+var->xres, var->bits_per_pixel),
+	          DISP_DIWADDRS);
+}
+
+/* 
+ * Initialize the video mode.  Currently, the 16bpp and 24bpp modes aren't
+ * very stable.  It's probably due to the fact that a lot of the 2D video
+ * registers are still undocumented.
+ */
+
+static void pvr2_init_display(struct fb_info *info)
+{
+	struct pvr2fb_par *par = (struct pvr2fb_par *) info->par;
+	struct fb_var_screeninfo *var = &info->var;
+	unsigned int diw_height, diw_width, diw_modulo = 1;
+	unsigned int bytesperpixel = var->bits_per_pixel >> 3;
+
+	/* hsync and vsync totals */
+	fb_writel((par->vsync_total << 16) | par->hsync_total, DISP_SYNCSIZE);
+
+	/* column height, modulo, row width */
+	/* since we're "panning" within vram, we need to offset things based
+	 * on the offset from the virtual x start to our real gfx. */
+	if (video_output != VO_VGA && par->is_interlaced)
+		diw_modulo += info->fix.line_length / 4;
+	diw_height = (par->is_interlaced ? var->yres / 2 : var->yres);
+	diw_width = get_line_length(var->xres, var->bits_per_pixel) / 4;
+	fb_writel((diw_modulo << 20) | (--diw_height << 10) | --diw_width,
+	          DISP_DIWSIZE);
+
+	/* display address, long and short fields */
+	fb_writel(par->disp_start, DISP_DIWADDRL);
+	fb_writel(par->disp_start +
+	          get_line_length(var->xoffset+var->xres, var->bits_per_pixel),
+	          DISP_DIWADDRS);
+
+	/* border horizontal, border vertical, border color */
+	fb_writel((par->borderstart_h << 16) | par->borderstop_h, DISP_BRDRHORZ);
+	fb_writel((par->borderstart_v << 16) | par->borderstop_v, DISP_BRDRVERT);
+	fb_writel(0, DISP_BRDRCOLR);
+
+	/* display window start position */
+	fb_writel(par->diwstart_h, DISP_DIWHSTRT);
+	fb_writel((par->diwstart_v << 16) | par->diwstart_v, DISP_DIWVSTRT);
+	
+	/* misc. settings */
+	fb_writel((0x16 << 16) | par->is_lowres, DISP_DIWCONF);
+
+	/* clock doubler (for VGA), scan doubler, display enable */
+	fb_writel(((video_output == VO_VGA) << 23) | 
+	          (par->is_doublescan << 1) | 1, DISP_DIWMODE);
+
+	/* bits per pixel */
+	fb_writel(fb_readl(DISP_DIWMODE) | (--bytesperpixel << 2), DISP_DIWMODE);
+
+	/* video enable, color sync, interlace, 
+	 * hsync and vsync polarity (currently unused) */
+	fb_writel(0x100 | ((par->is_interlaced /*|4*/) << 4), DISP_SYNCCONF);
+}
+
+/* Simulate blanking by making the border cover the entire screen */
+
+#define BLANK_BIT (1<<3)
+
+static void pvr2_do_blank(void)
+{
+	struct pvr2fb_par *par = currentpar;
+	unsigned long diwconf;
+
+	diwconf = fb_readl(DISP_DIWCONF);
+	if (do_blank > 0)
+		fb_writel(diwconf | BLANK_BIT, DISP_DIWCONF);
+	else
+		fb_writel(diwconf & ~BLANK_BIT, DISP_DIWCONF);
+
+	is_blanked = do_blank > 0 ? do_blank : 0;
+}
+
+static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id, struct pt_regs *fp)
+{
+	struct fb_info *info = dev_id;
+
+	if (do_vmode_pan || do_vmode_full)
+		pvr2_update_display(info);
+	if (do_vmode_full)
+		pvr2_init_display(info);
+	if (do_vmode_pan)
+		do_vmode_pan = 0;
+	if (do_vmode_full)
+		do_vmode_full = 0;
+	if (do_blank) {
+		pvr2_do_blank();
+		do_blank = 0;
+	}
+	return IRQ_HANDLED;
+}
+
+/*
+ * Determine the cable type and initialize the cable output format.  Don't do
+ * anything if the cable type has been overidden (via "cable:XX").
+ */
+
+#define PCTRA 0xff80002c
+#define PDTRA 0xff800030
+#define VOUTC 0xa0702c00
+
+static int pvr2_init_cable(void)
+{
+	if (cable_type < 0) {
+		fb_writel((fb_readl(PCTRA) & 0xfff0ffff) | 0x000a0000, 
+	                  PCTRA);
+		cable_type = (fb_readw(PDTRA) >> 8) & 3;
+	}
+
+	/* Now select the output format (either composite or other) */
+	/* XXX: Save the previous val first, as this reg is also AICA
+	  related */
+	if (cable_type == CT_COMPOSITE)
+		fb_writel(3 << 8, VOUTC);
+	else
+		fb_writel(0, VOUTC);
+
+	return cable_type;
+}
+
+#ifdef CONFIG_SH_DMA
+static ssize_t pvr2fb_write(struct file *file, const char *buf,
+			    size_t count, loff_t *ppos)
+{
+	unsigned long dst, start, end, len;
+	unsigned int nr_pages;
+	struct page **pages;
+	int ret, i;
+
+	nr_pages = (count + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+	pages = kmalloc(nr_pages * sizeof(struct page *), GFP_KERNEL);
+	if (!pages)
+		return -ENOMEM;
+	
+	down_read(&current->mm->mmap_sem);
+	ret = get_user_pages(current, current->mm, (unsigned long)buf,
+			     nr_pages, WRITE, 0, pages, NULL);
+	up_read(&current->mm->mmap_sem);
+
+	if (ret < nr_pages) {
+		nr_pages = ret;
+		ret = -EINVAL;
+		goto out_unmap;
+	}
+
+	dma_configure_channel(shdma, 0x12c1);
+	
+	dst   = (unsigned long)fb_info->screen_base + *ppos;
+	start = (unsigned long)page_address(pages[0]);
+	end   = (unsigned long)page_address(pages[nr_pages]);
+	len   = nr_pages << PAGE_SHIFT;
+
+	/* Half-assed contig check */
+	if (start + len == end) {
+		/* As we do this in one shot, it's either all or nothing.. */
+		if ((*ppos + len) > fb_info->fix.smem_len) {
+			ret = -ENOSPC;
+			goto out_unmap;
+		}
+
+		dma_write(shdma, start, 0, len);
+		dma_write(pvr2dma, 0, dst, len);
+		dma_wait_for_completion(pvr2dma);
+
+		goto out;
+	}
+
+	/* Not contiguous, writeout per-page instead.. */
+	for (i = 0; i < nr_pages; i++, dst += PAGE_SIZE) {
+		if ((*ppos + (i << PAGE_SHIFT)) > fb_info->fix.smem_len) {
+			ret = -ENOSPC;
+			goto out_unmap;
+		}
+
+		dma_write_page(shdma, (unsigned long)page_address(pages[i]), 0);
+		dma_write_page(pvr2dma, 0, dst);
+		dma_wait_for_completion(pvr2dma);
+	}
+
+out:
+	*ppos += count;
+	ret = count;
+
+out_unmap:
+	for (i = 0; i < nr_pages; i++)
+		page_cache_release(pages[i]);
+
+	kfree(pages);
+
+	return ret;
+} 
+#endif /* CONFIG_SH_DMA */
+
+/**
+ * pvr2fb_common_init
+ *
+ * Common init code for the PVR2 chips.
+ *
+ * This mostly takes care of the common aspects of the fb setup and
+ * registration. It's expected that the board-specific init code has
+ * already setup pvr2_fix with something meaningful at this point.
+ *
+ * Device info reporting is also done here, as well as picking a sane
+ * default from the modedb. For board-specific modelines, simply define
+ * a per-board modedb.
+ *
+ * Also worth noting is that the cable and video output types are likely
+ * always going to be VGA for the PCI-based PVR2 boards, but we leave this
+ * in for flexibility anyways. Who knows, maybe someone has tv-out on a
+ * PCI-based version of these things ;-)
+ */
+static int __init pvr2fb_common_init(void)
+{
+	struct pvr2fb_par *par = currentpar;
+	unsigned long modememused, rev;
+
+	fb_info->screen_base = ioremap_nocache(pvr2_fix.smem_start,
+					       pvr2_fix.smem_len);
+	
+	if (!fb_info->screen_base) {
+		printk(KERN_ERR "pvr2fb: Failed to remap smem space\n");
+		goto out_err;
+	}
+
+	par->mmio_base = (unsigned long)ioremap_nocache(pvr2_fix.mmio_start,
+					 		pvr2_fix.mmio_len);
+	if (!par->mmio_base) {
+		printk(KERN_ERR "pvr2fb: Failed to remap mmio space\n");
+		goto out_err;
+	}
+
+	fb_memset((unsigned long)fb_info->screen_base, 0, pvr2_fix.smem_len);
+
+	pvr2_fix.ypanstep	= nopan  ? 0 : 1;
+	pvr2_fix.ywrapstep	= nowrap ? 0 : 1;
+
+	fb_info->fbops		= &pvr2fb_ops;
+	fb_info->fix		= pvr2_fix;
+	fb_info->par		= currentpar;
+	fb_info->pseudo_palette	= (void *)(fb_info->par + 1);
+	fb_info->flags		= FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+
+	if (video_output == VO_VGA)
+		defmode = DEFMODE_VGA;
+
+	if (!mode_option)
+		mode_option = "640x480@60";
+
+	if (!fb_find_mode(&fb_info->var, fb_info, mode_option, pvr2_modedb,
+	                  NUM_TOTAL_MODES, &pvr2_modedb[defmode], 16))
+		fb_info->var = pvr2_var;
+
+	fb_alloc_cmap(&fb_info->cmap, 256, 0);
+
+	if (register_framebuffer(fb_info) < 0)
+		goto out_err;
+
+	modememused = get_line_length(fb_info->var.xres_virtual,
+				      fb_info->var.bits_per_pixel);
+	modememused *= fb_info->var.yres_virtual;
+
+	rev = fb_readl(par->mmio_base + 0x04);
+
+	printk("fb%d: %s (rev %ld.%ld) frame buffer device, using %ldk/%ldk of video memory\n",
+	       fb_info->node, fb_info->fix.id, (rev >> 4) & 0x0f, rev & 0x0f,
+	       modememused >> 10, (unsigned long)(fb_info->fix.smem_len >> 10));
+	printk("fb%d: Mode %dx%d-%d pitch = %ld cable: %s video output: %s\n", 
+	       fb_info->node, fb_info->var.xres, fb_info->var.yres,
+	       fb_info->var.bits_per_pixel, 
+	       get_line_length(fb_info->var.xres, fb_info->var.bits_per_pixel),
+	       (char *)pvr2_get_param(cables, NULL, cable_type, 3),
+	       (char *)pvr2_get_param(outputs, NULL, video_output, 3));
+
+#ifdef CONFIG_SH_STORE_QUEUES
+	printk(KERN_NOTICE "fb%d: registering with SQ API\n", fb_info->node);
+
+	pvr2fb_map = sq_remap(fb_info->fix.smem_start, fb_info->fix.smem_len,
+			      fb_info->fix.id);
+
+	printk(KERN_NOTICE "fb%d: Mapped video memory to SQ addr 0x%lx\n",
+	       fb_info->node, pvr2fb_map->sq_addr);
+#endif
+
+	return 0;
+
+out_err:
+	if (fb_info->screen_base)
+		iounmap(fb_info->screen_base);
+	if (par->mmio_base)
+		iounmap((void *)par->mmio_base);
+
+	return -ENXIO;
+}
+
+#ifdef CONFIG_SH_DREAMCAST
+static int __init pvr2fb_dc_init(void)
+{
+	if (!mach_is_dreamcast())
+		return -ENXIO;
+
+	/* Make a guess at the monitor based on the attached cable */
+	if (pvr2_init_cable() == CT_VGA) {
+		fb_info->monspecs.hfmin = 30000;
+		fb_info->monspecs.hfmax = 70000;
+		fb_info->monspecs.vfmin = 60;
+		fb_info->monspecs.vfmax = 60;
+	} else {
+		/* Not VGA, using a TV (taken from acornfb) */
+		fb_info->monspecs.hfmin = 15469;
+		fb_info->monspecs.hfmax = 15781;
+		fb_info->monspecs.vfmin = 49;
+		fb_info->monspecs.vfmax = 51;
+	}
+
+	/*
+	 * XXX: This needs to pull default video output via BIOS or other means
+	 */
+	if (video_output < 0) {
+		if (cable_type == CT_VGA) {
+			video_output = VO_VGA;
+		} else {
+			video_output = VO_NTSC;
+		}
+	}
+	
+	/* 
+	 * Nothing exciting about the DC PVR2 .. only a measly 8MiB.
+	 */
+	pvr2_fix.smem_start	= 0xa5000000;	/* RAM starts here */
+	pvr2_fix.smem_len	= 8 << 20;
+
+	pvr2_fix.mmio_start	= 0xa05f8000;	/* registers start here */
+	pvr2_fix.mmio_len	= 0x2000;
+
+	if (request_irq(HW_EVENT_VSYNC, pvr2fb_interrupt, 0,
+	                "pvr2 VBL handler", fb_info)) {
+		return -EBUSY;
+	}
+
+#ifdef CONFIG_SH_DMA
+	if (request_dma(pvr2dma, "pvr2") != 0) {
+		free_irq(HW_EVENT_VSYNC, 0);
+		return -EBUSY;
+	}
+#endif
+
+	return pvr2fb_common_init();
+}
+
+static void pvr2fb_dc_exit(void)
+{
+	free_irq(HW_EVENT_VSYNC, 0);
+#ifdef CONFIG_SH_DMA
+	free_dma(pvr2dma);
+#endif
+}
+#endif /* CONFIG_SH_DREAMCAST */
+
+#ifdef CONFIG_PCI
+static int __devinit pvr2fb_pci_probe(struct pci_dev *pdev,
+				      const struct pci_device_id *ent)
+{
+	int ret;
+
+	ret = pci_enable_device(pdev);
+	if (ret) {
+		printk(KERN_ERR "pvr2fb: PCI enable failed\n");
+		return ret;
+	}
+
+	ret = pci_request_regions(pdev, "pvr2fb");
+	if (ret) {
+		printk(KERN_ERR "pvr2fb: PCI request regions failed\n");
+		return ret;
+	}
+
+	/*
+	 * Slightly more exciting than the DC PVR2 .. 16MiB!
+	 */
+	pvr2_fix.smem_start	= pci_resource_start(pdev, 0);
+	pvr2_fix.smem_len	= pci_resource_len(pdev, 0);
+
+	pvr2_fix.mmio_start	= pci_resource_start(pdev, 1);
+	pvr2_fix.mmio_len	= pci_resource_len(pdev, 1);
+
+	fb_info->device		= &pdev->dev;
+
+	return pvr2fb_common_init();
+}
+
+static void __devexit pvr2fb_pci_remove(struct pci_dev *pdev)
+{
+	pci_release_regions(pdev);
+}
+
+static struct pci_device_id pvr2fb_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NEON250,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, pvr2fb_pci_tbl);
+
+static struct pci_driver pvr2fb_pci_driver = {
+	.name		= "pvr2fb",
+	.id_table	= pvr2fb_pci_tbl,
+	.probe		= pvr2fb_pci_probe,
+	.remove		= __devexit_p(pvr2fb_pci_remove),
+};
+
+static int __init pvr2fb_pci_init(void)
+{
+	return pci_register_driver(&pvr2fb_pci_driver);
+}
+
+static void pvr2fb_pci_exit(void)
+{
+	pci_unregister_driver(&pvr2fb_pci_driver);
+}
+#endif /* CONFIG_PCI */
+
+static int __init pvr2_get_param(const struct pvr2_params *p, const char *s,
+                                   int val, int size)
+{
+	int i;
+
+	for (i = 0 ; i < size ; i++ ) {
+		if (s != NULL) {
+			if (!strnicmp(p[i].name, s, strlen(s)))
+				return p[i].val;
+		} else {
+			if (p[i].val == val)
+				return (int)p[i].name;
+		}
+	}
+	return -1;
+}
+
+/*
+ * Parse command arguments.  Supported arguments are:
+ *    inverse                             Use inverse color maps
+ *    cable:composite|rgb|vga             Override the video cable type
+ *    output:NTSC|PAL|VGA                 Override the video output format
+ *
+ *    <xres>x<yres>[-<bpp>][@<refresh>]   or,
+ *    <name>[-<bpp>][@<refresh>]          Startup using this video mode
+ */
+
+#ifndef MODULE
+int __init pvr2fb_setup(char *options)
+{
+	char *this_opt;
+	char cable_arg[80];
+	char output_arg[80];
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ","))) {
+		if (!*this_opt)
+			continue;
+		if (!strcmp(this_opt, "inverse")) {
+			fb_invert_cmaps();
+		} else if (!strncmp(this_opt, "cable:", 6)) {
+			strcpy(cable_arg, this_opt + 6);
+		} else if (!strncmp(this_opt, "output:", 7)) {
+			strcpy(output_arg, this_opt + 7);
+		} else if (!strncmp(this_opt, "nopan", 5)) {
+			nopan = 1;
+		} else if (!strncmp(this_opt, "nowrap", 6)) {
+			nowrap = 1;
+		} else {
+			mode_option = this_opt;
+		}
+	}
+
+	if (*cable_arg)
+		cable_type = pvr2_get_param(cables, cable_arg, 0, 3);
+	if (*output_arg)
+		video_output = pvr2_get_param(outputs, output_arg, 0, 3);
+
+	return 0;
+}
+#endif
+
+static struct pvr2_board {
+	int (*init)(void);
+	void (*exit)(void);
+	char name[16];
+} board_list[] = {
+#ifdef CONFIG_SH_DREAMCAST
+	{ pvr2fb_dc_init, pvr2fb_dc_exit, "Sega DC PVR2" },
+#endif
+#ifdef CONFIG_PCI
+	{ pvr2fb_pci_init, pvr2fb_pci_exit, "PCI PVR2" },
+#endif
+	{ 0, },
+};
+
+int __init pvr2fb_init(void)
+{
+	int i, ret = -ENODEV;
+	int size;
+
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("pvr2fb", &option))
+		return -ENODEV;
+	pvr2fb_setup(option);
+#endif
+	size = sizeof(struct fb_info) + sizeof(struct pvr2fb_par) + 16 * sizeof(u32);
+
+	fb_info = kmalloc(size, GFP_KERNEL);
+	if (!fb_info) {
+		printk(KERN_ERR "Failed to allocate memory for fb_info\n");
+		return -ENOMEM;
+	}
+
+	memset(fb_info, 0, size);
+
+	currentpar = (struct pvr2fb_par *)(fb_info + 1);
+
+	for (i = 0; i < ARRAY_SIZE(board_list); i++) {
+		struct pvr2_board *pvr_board = board_list + i;
+
+		if (!pvr_board->init)
+			continue;
+
+		ret = pvr_board->init();
+
+		if (ret != 0) {
+			printk(KERN_ERR "pvr2fb: Failed init of %s device\n",
+				pvr_board->name);
+			kfree(fb_info);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static void __exit pvr2fb_exit(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(board_list); i++) {
+		struct pvr2_board *pvr_board = board_list + i;
+
+		if (pvr_board->exit)
+			pvr_board->exit();
+	}
+		
+#ifdef CONFIG_SH_STORE_QUEUES
+	sq_unmap(pvr2fb_map);
+#endif
+
+	unregister_framebuffer(fb_info);
+	kfree(fb_info);
+}
+
+module_init(pvr2fb_init);
+module_exit(pvr2fb_exit);
+
+MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>");
+MODULE_DESCRIPTION("Framebuffer driver for NEC PowerVR 2 based graphics boards");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
new file mode 100644
index 0000000..483ad9b
--- /dev/null
+++ b/drivers/video/pxafb.c
@@ -0,0 +1,1390 @@
+/*
+ *  linux/drivers/video/pxafb.c
+ *
+ *  Copyright (C) 1999 Eric A. Thomas.
+ *  Copyright (C) 2004 Jean-Frederic Clere.
+ *  Copyright (C) 2004 Ian Campbell.
+ *  Copyright (C) 2004 Jeff Lackey.
+ *   Based on sa1100fb.c Copyright (C) 1999 Eric A. Thomas
+ *  which in turn is
+ *   Based on acornfb.c Copyright (C) Russell King.
+ *
+ * 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.
+ *
+ *	        Intel PXA250/210 LCD Controller Frame Buffer Driver
+ *
+ * Please direct your questions and comments on this driver to the following
+ * email address:
+ *
+ *	linux-arm-kernel@lists.arm.linux.org.uk
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/cpufreq.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/bitfield.h>
+#include <asm/arch/pxafb.h>
+
+/*
+ * Complain if VAR is out of range.
+ */
+#define DEBUG_VAR 1
+
+#include "pxafb.h"
+
+/* Bits which should not be set in machine configuration structures */
+#define LCCR0_INVALID_CONFIG_MASK (LCCR0_OUM|LCCR0_BM|LCCR0_QDM|LCCR0_DIS|LCCR0_EFM|LCCR0_IUM|LCCR0_SFM|LCCR0_LDM|LCCR0_ENB)
+#define LCCR3_INVALID_CONFIG_MASK (LCCR3_HSP|LCCR3_VSP|LCCR3_PCD|LCCR3_BPP)
+
+static void (*pxafb_backlight_power)(int);
+static void (*pxafb_lcd_power)(int);
+
+static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *);
+static void set_ctrlr_state(struct pxafb_info *fbi, u_int state);
+
+#ifdef CONFIG_FB_PXA_PARAMETERS
+#define PXAFB_OPTIONS_SIZE 256
+static char g_options[PXAFB_OPTIONS_SIZE] __initdata = "";
+#endif
+
+static inline void pxafb_schedule_work(struct pxafb_info *fbi, u_int state)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	/*
+	 * We need to handle two requests being made at the same time.
+	 * There are two important cases:
+	 *  1. When we are changing VT (C_REENABLE) while unblanking (C_ENABLE)
+	 *     We must perform the unblanking, which will do our REENABLE for us.
+	 *  2. When we are blanking, but immediately unblank before we have
+	 *     blanked.  We do the "REENABLE" thing here as well, just to be sure.
+	 */
+	if (fbi->task_state == C_ENABLE && state == C_REENABLE)
+		state = (u_int) -1;
+	if (fbi->task_state == C_DISABLE && state == C_ENABLE)
+		state = C_REENABLE;
+
+	if (state != (u_int)-1) {
+		fbi->task_state = state;
+		schedule_work(&fbi->task);
+	}
+	local_irq_restore(flags);
+}
+
+static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
+{
+	chan &= 0xffff;
+	chan >>= 16 - bf->length;
+	return chan << bf->offset;
+}
+
+static int
+pxafb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
+		       u_int trans, struct fb_info *info)
+{
+	struct pxafb_info *fbi = (struct pxafb_info *)info;
+	u_int val, ret = 1;
+
+	if (regno < fbi->palette_size) {
+		if (fbi->fb.var.grayscale) {
+			val = ((blue >> 8) & 0x00ff);
+		} else {
+			val  = ((red   >>  0) & 0xf800);
+			val |= ((green >>  5) & 0x07e0);
+			val |= ((blue  >> 11) & 0x001f);
+		}
+		fbi->palette_cpu[regno] = val;
+		ret = 0;
+	}
+	return ret;
+}
+
+static int
+pxafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+		   u_int trans, struct fb_info *info)
+{
+	struct pxafb_info *fbi = (struct pxafb_info *)info;
+	unsigned int val;
+	int ret = 1;
+
+	/*
+	 * If inverse mode was selected, invert all the colours
+	 * rather than the register number.  The register number
+	 * is what you poke into the framebuffer to produce the
+	 * colour you requested.
+	 */
+	if (fbi->cmap_inverse) {
+		red   = 0xffff - red;
+		green = 0xffff - green;
+		blue  = 0xffff - blue;
+	}
+
+	/*
+	 * If greyscale is true, then we convert the RGB value
+	 * to greyscale no matter what visual we are using.
+	 */
+	if (fbi->fb.var.grayscale)
+		red = green = blue = (19595 * red + 38470 * green +
+					7471 * blue) >> 16;
+
+	switch (fbi->fb.fix.visual) {
+	case FB_VISUAL_TRUECOLOR:
+		/*
+		 * 16-bit True Colour.  We encode the RGB value
+		 * according to the RGB bitfield information.
+		 */
+		if (regno < 16) {
+			u32 *pal = fbi->fb.pseudo_palette;
+
+			val  = chan_to_field(red, &fbi->fb.var.red);
+			val |= chan_to_field(green, &fbi->fb.var.green);
+			val |= chan_to_field(blue, &fbi->fb.var.blue);
+
+			pal[regno] = val;
+			ret = 0;
+		}
+		break;
+
+	case FB_VISUAL_STATIC_PSEUDOCOLOR:
+	case FB_VISUAL_PSEUDOCOLOR:
+		ret = pxafb_setpalettereg(regno, red, green, blue, trans, info);
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ *  pxafb_bpp_to_lccr3():
+ *    Convert a bits per pixel value to the correct bit pattern for LCCR3
+ */
+static int pxafb_bpp_to_lccr3(struct fb_var_screeninfo *var)
+{
+        int ret = 0;
+        switch (var->bits_per_pixel) {
+        case 1:  ret = LCCR3_1BPP; break;
+        case 2:  ret = LCCR3_2BPP; break;
+        case 4:  ret = LCCR3_4BPP; break;
+        case 8:  ret = LCCR3_8BPP; break;
+        case 16: ret = LCCR3_16BPP; break;
+        }
+        return ret;
+}
+
+#ifdef CONFIG_CPU_FREQ
+/*
+ *  pxafb_display_dma_period()
+ *    Calculate the minimum period (in picoseconds) between two DMA
+ *    requests for the LCD controller.  If we hit this, it means we're
+ *    doing nothing but LCD DMA.
+ */
+static unsigned int pxafb_display_dma_period(struct fb_var_screeninfo *var)
+{
+       /*
+        * Period = pixclock * bits_per_byte * bytes_per_transfer
+        *              / memory_bits_per_pixel;
+        */
+       return var->pixclock * 8 * 16 / var->bits_per_pixel;
+}
+
+extern unsigned int get_clk_frequency_khz(int info);
+#endif
+
+/*
+ *  pxafb_check_var():
+ *    Get the video params out of 'var'. If a value doesn't fit, round it up,
+ *    if it's too big, return -EINVAL.
+ *
+ *    Round up in the following order: bits_per_pixel, xres,
+ *    yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
+ *    bitfields, horizontal timing, vertical timing.
+ */
+static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct pxafb_info *fbi = (struct pxafb_info *)info;
+
+	if (var->xres < MIN_XRES)
+		var->xres = MIN_XRES;
+	if (var->yres < MIN_YRES)
+		var->yres = MIN_YRES;
+	if (var->xres > fbi->max_xres)
+		var->xres = fbi->max_xres;
+	if (var->yres > fbi->max_yres)
+		var->yres = fbi->max_yres;
+	var->xres_virtual =
+		max(var->xres_virtual, var->xres);
+	var->yres_virtual =
+		max(var->yres_virtual, var->yres);
+
+        /*
+	 * Setup the RGB parameters for this display.
+	 *
+	 * The pixel packing format is described on page 7-11 of the
+	 * PXA2XX Developer's Manual.
+         */
+	if (var->bits_per_pixel == 16) {
+		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 = var->transp.length = 0;
+	} else {
+		var->red.offset = var->green.offset = var->blue.offset = var->transp.offset = 0;
+		var->red.length   = 8;
+		var->green.length = 8;
+		var->blue.length  = 8;
+		var->transp.length = 0;
+	}
+
+#ifdef CONFIG_CPU_FREQ
+	DPRINTK("dma period = %d ps, clock = %d kHz\n",
+		pxafb_display_dma_period(var),
+		get_clk_frequency_khz(0));
+#endif
+
+	return 0;
+}
+
+static inline void pxafb_set_truecolor(u_int is_true_color)
+{
+	DPRINTK("true_color = %d\n", is_true_color);
+	// do your machine-specific setup if needed
+}
+
+/*
+ * pxafb_set_par():
+ *	Set the user defined part of the display for the specified console
+ */
+static int pxafb_set_par(struct fb_info *info)
+{
+	struct pxafb_info *fbi = (struct pxafb_info *)info;
+	struct fb_var_screeninfo *var = &info->var;
+	unsigned long palette_mem_size;
+
+	DPRINTK("set_par\n");
+
+	if (var->bits_per_pixel == 16)
+		fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+	else if (!fbi->cmap_static)
+		fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
+	else {
+		/*
+		 * Some people have weird ideas about wanting static
+		 * pseudocolor maps.  I suspect their user space
+		 * applications are broken.
+		 */
+		fbi->fb.fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
+	}
+
+	fbi->fb.fix.line_length = var->xres_virtual *
+				  var->bits_per_pixel / 8;
+	if (var->bits_per_pixel == 16)
+		fbi->palette_size = 0;
+	else
+		fbi->palette_size = var->bits_per_pixel == 1 ? 4 : 1 << var->bits_per_pixel;
+
+	palette_mem_size = fbi->palette_size * sizeof(u16);
+
+	DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size);
+
+	fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
+	fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
+
+	/*
+	 * Set (any) board control register to handle new color depth
+	 */
+	pxafb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR);
+
+	if (fbi->fb.var.bits_per_pixel == 16)
+		fb_dealloc_cmap(&fbi->fb.cmap);
+	else
+		fb_alloc_cmap(&fbi->fb.cmap, 1<<fbi->fb.var.bits_per_pixel, 0);
+
+	pxafb_activate_var(var, fbi);
+
+	return 0;
+}
+
+/*
+ * Formal definition of the VESA spec:
+ *  On
+ *  	This refers to the state of the display when it is in full operation
+ *  Stand-By
+ *  	This defines an optional operating state of minimal power reduction with
+ *  	the shortest recovery time
+ *  Suspend
+ *  	This refers to a level of power management in which substantial power
+ *  	reduction is achieved by the display.  The display can have a longer
+ *  	recovery time from this state than from the Stand-by state
+ *  Off
+ *  	This indicates that the display is consuming the lowest level of power
+ *  	and is non-operational. Recovery from this state may optionally require
+ *  	the user to manually power on the monitor
+ *
+ *  Now, the fbdev driver adds an additional state, (blank), where they
+ *  turn off the video (maybe by colormap tricks), but don't mess with the
+ *  video itself: think of it semantically between on and Stand-By.
+ *
+ *  So here's what we should do in our fbdev blank routine:
+ *
+ *  	VESA_NO_BLANKING (mode 0)	Video on,  front/back light on
+ *  	VESA_VSYNC_SUSPEND (mode 1)  	Video on,  front/back light off
+ *  	VESA_HSYNC_SUSPEND (mode 2)  	Video on,  front/back light off
+ *  	VESA_POWERDOWN (mode 3)		Video off, front/back light off
+ *
+ *  This will match the matrox implementation.
+ */
+
+/*
+ * pxafb_blank():
+ *	Blank the display by setting all palette values to zero.  Note, the
+ * 	16 bpp mode does not really use the palette, so this will not
+ *      blank the display in all modes.
+ */
+static int pxafb_blank(int blank, struct fb_info *info)
+{
+	struct pxafb_info *fbi = (struct pxafb_info *)info;
+	int i;
+
+	DPRINTK("pxafb_blank: blank=%d\n", blank);
+
+	switch (blank) {
+	case FB_BLANK_POWERDOWN:
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_NORMAL:
+		if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
+		    fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
+			for (i = 0; i < fbi->palette_size; i++)
+				pxafb_setpalettereg(i, 0, 0, 0, 0, info);
+
+		pxafb_schedule_work(fbi, C_DISABLE);
+		//TODO if (pxafb_blank_helper) pxafb_blank_helper(blank);
+		break;
+
+	case FB_BLANK_UNBLANK:
+		//TODO if (pxafb_blank_helper) pxafb_blank_helper(blank);
+		if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
+		    fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
+			fb_set_cmap(&fbi->fb.cmap, info);
+		pxafb_schedule_work(fbi, C_ENABLE);
+	}
+	return 0;
+}
+
+static int pxafb_mmap(struct fb_info *info, struct file *file,
+		      struct vm_area_struct *vma)
+{
+	struct pxafb_info *fbi = (struct pxafb_info *)info;
+	unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
+
+	if (off < info->fix.smem_len) {
+		vma->vm_pgoff += 1;
+		return dma_mmap_writecombine(fbi->dev, vma, fbi->map_cpu,
+					     fbi->map_dma, fbi->map_size);
+	}
+	return -EINVAL;
+}
+
+static struct fb_ops pxafb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= pxafb_check_var,
+	.fb_set_par	= pxafb_set_par,
+	.fb_setcolreg	= pxafb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_blank	= pxafb_blank,
+	.fb_cursor	= soft_cursor,
+	.fb_mmap	= pxafb_mmap,
+};
+
+/*
+ * Calculate the PCD value from the clock rate (in picoseconds).
+ * We take account of the PPCR clock setting.
+ * From PXA Developer's Manual:
+ *
+ *   PixelClock =      LCLK
+ *                -------------
+ *                2 ( PCD + 1 )
+ *
+ *   PCD =      LCLK
+ *         ------------- - 1
+ *         2(PixelClock)
+ *
+ * Where:
+ *   LCLK = LCD/Memory Clock
+ *   PCD = LCCR3[7:0]
+ *
+ * PixelClock here is in Hz while the pixclock argument given is the
+ * period in picoseconds. Hence PixelClock = 1 / ( pixclock * 10^-12 )
+ *
+ * The function get_lclk_frequency_10khz returns LCLK in units of
+ * 10khz. Calling the result of this function lclk gives us the
+ * following
+ *
+ *    PCD = (lclk * 10^4 ) * ( pixclock * 10^-12 )
+ *          -------------------------------------- - 1
+ *                          2
+ *
+ * Factoring the 10^4 and 10^-12 out gives 10^-8 == 1 / 100000000 as used below.
+ */
+static inline unsigned int get_pcd(unsigned int pixclock)
+{
+	unsigned long long pcd;
+
+	/* FIXME: Need to take into account Double Pixel Clock mode
+         * (DPC) bit? or perhaps set it based on the various clock
+         * speeds */
+
+	pcd = (unsigned long long)get_lcdclk_frequency_10khz() * pixclock;
+	pcd /= 100000000 * 2;
+	/* no need for this, since we should subtract 1 anyway. they cancel */
+	/* pcd += 1; */ /* make up for integer math truncations */
+	return (unsigned int)pcd;
+}
+
+/*
+ * pxafb_activate_var():
+ *	Configures LCD Controller based on entries in var parameter.  Settings are
+ *	only written to the controller if changes were made.
+ */
+static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *fbi)
+{
+	struct pxafb_lcd_reg new_regs;
+	u_long flags;
+	u_int lines_per_panel, pcd = get_pcd(var->pixclock);
+
+	DPRINTK("Configuring PXA LCD\n");
+
+	DPRINTK("var: xres=%d hslen=%d lm=%d rm=%d\n",
+		var->xres, var->hsync_len,
+		var->left_margin, var->right_margin);
+	DPRINTK("var: yres=%d vslen=%d um=%d bm=%d\n",
+		var->yres, var->vsync_len,
+		var->upper_margin, var->lower_margin);
+	DPRINTK("var: pixclock=%d pcd=%d\n", var->pixclock, pcd);
+
+#if DEBUG_VAR
+	if (var->xres < 16        || var->xres > 1024)
+		printk(KERN_ERR "%s: invalid xres %d\n",
+			fbi->fb.fix.id, var->xres);
+	switch(var->bits_per_pixel) {
+	case 1:
+	case 2:
+	case 4:
+	case 8:
+	case 16:
+		break;
+	default:
+		printk(KERN_ERR "%s: invalid bit depth %d\n",
+		       fbi->fb.fix.id, var->bits_per_pixel);
+		break;
+	}
+	if (var->hsync_len < 1    || var->hsync_len > 64)
+		printk(KERN_ERR "%s: invalid hsync_len %d\n",
+			fbi->fb.fix.id, var->hsync_len);
+	if (var->left_margin < 1  || var->left_margin > 255)
+		printk(KERN_ERR "%s: invalid left_margin %d\n",
+			fbi->fb.fix.id, var->left_margin);
+	if (var->right_margin < 1 || var->right_margin > 255)
+		printk(KERN_ERR "%s: invalid right_margin %d\n",
+			fbi->fb.fix.id, var->right_margin);
+	if (var->yres < 1         || var->yres > 1024)
+		printk(KERN_ERR "%s: invalid yres %d\n",
+			fbi->fb.fix.id, var->yres);
+	if (var->vsync_len < 1    || var->vsync_len > 64)
+		printk(KERN_ERR "%s: invalid vsync_len %d\n",
+			fbi->fb.fix.id, var->vsync_len);
+	if (var->upper_margin < 0 || var->upper_margin > 255)
+		printk(KERN_ERR "%s: invalid upper_margin %d\n",
+			fbi->fb.fix.id, var->upper_margin);
+	if (var->lower_margin < 0 || var->lower_margin > 255)
+		printk(KERN_ERR "%s: invalid lower_margin %d\n",
+			fbi->fb.fix.id, var->lower_margin);
+#endif
+
+	new_regs.lccr0 = fbi->lccr0 |
+		(LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM |
+                 LCCR0_QDM | LCCR0_BM  | LCCR0_OUM);
+
+	new_regs.lccr1 =
+		LCCR1_DisWdth(var->xres) +
+		LCCR1_HorSnchWdth(var->hsync_len) +
+		LCCR1_BegLnDel(var->left_margin) +
+		LCCR1_EndLnDel(var->right_margin);
+
+	/*
+	 * If we have a dual scan LCD, we need to halve
+	 * the YRES parameter.
+	 */
+	lines_per_panel = var->yres;
+	if ((fbi->lccr0 & LCCR0_SDS) == LCCR0_Dual)
+		lines_per_panel /= 2;
+
+	new_regs.lccr2 =
+		LCCR2_DisHght(lines_per_panel) +
+		LCCR2_VrtSnchWdth(var->vsync_len) +
+		LCCR2_BegFrmDel(var->upper_margin) +
+		LCCR2_EndFrmDel(var->lower_margin);
+
+	new_regs.lccr3 = fbi->lccr3 |
+		pxafb_bpp_to_lccr3(var) |
+		(var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
+		(var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
+
+	if (pcd)
+		new_regs.lccr3 |= LCCR3_PixClkDiv(pcd);
+
+	DPRINTK("nlccr0 = 0x%08x\n", new_regs.lccr0);
+	DPRINTK("nlccr1 = 0x%08x\n", new_regs.lccr1);
+	DPRINTK("nlccr2 = 0x%08x\n", new_regs.lccr2);
+	DPRINTK("nlccr3 = 0x%08x\n", new_regs.lccr3);
+
+	/* Update shadow copy atomically */
+	local_irq_save(flags);
+
+	/* setup dma descriptors */
+	fbi->dmadesc_fblow_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 3*16);
+	fbi->dmadesc_fbhigh_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 2*16);
+	fbi->dmadesc_palette_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 1*16);
+
+	fbi->dmadesc_fblow_dma = fbi->palette_dma - 3*16;
+	fbi->dmadesc_fbhigh_dma = fbi->palette_dma - 2*16;
+	fbi->dmadesc_palette_dma = fbi->palette_dma - 1*16;
+
+#define BYTES_PER_PANEL (lines_per_panel * fbi->fb.fix.line_length)
+
+	/* populate descriptors */
+	fbi->dmadesc_fblow_cpu->fdadr = fbi->dmadesc_fblow_dma;
+	fbi->dmadesc_fblow_cpu->fsadr = fbi->screen_dma + BYTES_PER_PANEL;
+	fbi->dmadesc_fblow_cpu->fidr  = 0;
+	fbi->dmadesc_fblow_cpu->ldcmd = BYTES_PER_PANEL;
+
+	fbi->fdadr1 = fbi->dmadesc_fblow_dma; /* only used in dual-panel mode */
+
+	fbi->dmadesc_fbhigh_cpu->fsadr = fbi->screen_dma;
+	fbi->dmadesc_fbhigh_cpu->fidr = 0;
+	fbi->dmadesc_fbhigh_cpu->ldcmd = BYTES_PER_PANEL;
+
+	fbi->dmadesc_palette_cpu->fsadr = fbi->palette_dma;
+	fbi->dmadesc_palette_cpu->fidr  = 0;
+	fbi->dmadesc_palette_cpu->ldcmd = (fbi->palette_size * 2) | LDCMD_PAL;
+
+	if (var->bits_per_pixel == 16) {
+		/* palette shouldn't be loaded in true-color mode */
+		fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_fbhigh_dma;
+		fbi->fdadr0 = fbi->dmadesc_fbhigh_dma; /* no pal just fbhigh */
+		/* init it to something, even though we won't be using it */
+		fbi->dmadesc_palette_cpu->fdadr = fbi->dmadesc_palette_dma;
+	} else {
+		fbi->dmadesc_palette_cpu->fdadr = fbi->dmadesc_fbhigh_dma;
+		fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_palette_dma;
+		fbi->fdadr0 = fbi->dmadesc_palette_dma; /* flips back and forth between pal and fbhigh */
+	}
+
+#if 0
+	DPRINTK("fbi->dmadesc_fblow_cpu = 0x%p\n", fbi->dmadesc_fblow_cpu);
+	DPRINTK("fbi->dmadesc_fbhigh_cpu = 0x%p\n", fbi->dmadesc_fbhigh_cpu);
+	DPRINTK("fbi->dmadesc_palette_cpu = 0x%p\n", fbi->dmadesc_palette_cpu);
+	DPRINTK("fbi->dmadesc_fblow_dma = 0x%x\n", fbi->dmadesc_fblow_dma);
+	DPRINTK("fbi->dmadesc_fbhigh_dma = 0x%x\n", fbi->dmadesc_fbhigh_dma);
+	DPRINTK("fbi->dmadesc_palette_dma = 0x%x\n", fbi->dmadesc_palette_dma);
+
+	DPRINTK("fbi->dmadesc_fblow_cpu->fdadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fdadr);
+	DPRINTK("fbi->dmadesc_fbhigh_cpu->fdadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fdadr);
+	DPRINTK("fbi->dmadesc_palette_cpu->fdadr = 0x%x\n", fbi->dmadesc_palette_cpu->fdadr);
+
+	DPRINTK("fbi->dmadesc_fblow_cpu->fsadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fsadr);
+	DPRINTK("fbi->dmadesc_fbhigh_cpu->fsadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fsadr);
+	DPRINTK("fbi->dmadesc_palette_cpu->fsadr = 0x%x\n", fbi->dmadesc_palette_cpu->fsadr);
+
+	DPRINTK("fbi->dmadesc_fblow_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fblow_cpu->ldcmd);
+	DPRINTK("fbi->dmadesc_fbhigh_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fbhigh_cpu->ldcmd);
+	DPRINTK("fbi->dmadesc_palette_cpu->ldcmd = 0x%x\n", fbi->dmadesc_palette_cpu->ldcmd);
+#endif
+
+	fbi->reg_lccr0 = new_regs.lccr0;
+	fbi->reg_lccr1 = new_regs.lccr1;
+	fbi->reg_lccr2 = new_regs.lccr2;
+	fbi->reg_lccr3 = new_regs.lccr3;
+	local_irq_restore(flags);
+
+	/*
+	 * Only update the registers if the controller is enabled
+	 * and something has changed.
+	 */
+	if ((LCCR0  != fbi->reg_lccr0) || (LCCR1  != fbi->reg_lccr1) ||
+	    (LCCR2  != fbi->reg_lccr2) || (LCCR3  != fbi->reg_lccr3) ||
+	    (FDADR0 != fbi->fdadr0)    || (FDADR1 != fbi->fdadr1))
+		pxafb_schedule_work(fbi, C_REENABLE);
+
+	return 0;
+}
+
+/*
+ * NOTE!  The following functions are purely helpers for set_ctrlr_state.
+ * Do not call them directly; set_ctrlr_state does the correct serialisation
+ * to ensure that things happen in the right way 100% of time time.
+ *	-- rmk
+ */
+static inline void __pxafb_backlight_power(struct pxafb_info *fbi, int on)
+{
+	DPRINTK("backlight o%s\n", on ? "n" : "ff");
+
+ 	if (pxafb_backlight_power)
+ 		pxafb_backlight_power(on);
+}
+
+static inline void __pxafb_lcd_power(struct pxafb_info *fbi, int on)
+{
+	DPRINTK("LCD power o%s\n", on ? "n" : "ff");
+
+	if (pxafb_lcd_power)
+		pxafb_lcd_power(on);
+}
+
+static void pxafb_setup_gpio(struct pxafb_info *fbi)
+{
+	int gpio, ldd_bits;
+        unsigned int lccr0 = fbi->lccr0;
+
+	/*
+	 * setup is based on type of panel supported
+        */
+
+	/* 4 bit interface */
+	if ((lccr0 & LCCR0_CMS) == LCCR0_Mono &&
+	    (lccr0 & LCCR0_SDS) == LCCR0_Sngl &&
+	    (lccr0 & LCCR0_DPD) == LCCR0_4PixMono)
+		ldd_bits = 4;
+
+	/* 8 bit interface */
+        else if (((lccr0 & LCCR0_CMS) == LCCR0_Mono &&
+		  ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_DPD) == LCCR0_8PixMono)) ||
+                 ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
+		  (lccr0 & LCCR0_PAS) == LCCR0_Pas && (lccr0 & LCCR0_SDS) == LCCR0_Sngl))
+		ldd_bits = 8;
+
+	/* 16 bit interface */
+	else if ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
+		 ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_PAS) == LCCR0_Act))
+		ldd_bits = 16;
+
+	else {
+	        printk(KERN_ERR "pxafb_setup_gpio: unable to determine bits per pixel\n");
+		return;
+        }
+
+	for (gpio = 58; ldd_bits; gpio++, ldd_bits--)
+		pxa_gpio_mode(gpio | GPIO_ALT_FN_2_OUT);
+	pxa_gpio_mode(GPIO74_LCD_FCLK_MD);
+	pxa_gpio_mode(GPIO75_LCD_LCLK_MD);
+	pxa_gpio_mode(GPIO76_LCD_PCLK_MD);
+	pxa_gpio_mode(GPIO77_LCD_ACBIAS_MD);
+}
+
+static void pxafb_enable_controller(struct pxafb_info *fbi)
+{
+	DPRINTK("Enabling LCD controller\n");
+	DPRINTK("fdadr0 0x%08x\n", (unsigned int) fbi->fdadr0);
+	DPRINTK("fdadr1 0x%08x\n", (unsigned int) fbi->fdadr1);
+	DPRINTK("reg_lccr0 0x%08x\n", (unsigned int) fbi->reg_lccr0);
+	DPRINTK("reg_lccr1 0x%08x\n", (unsigned int) fbi->reg_lccr1);
+	DPRINTK("reg_lccr2 0x%08x\n", (unsigned int) fbi->reg_lccr2);
+	DPRINTK("reg_lccr3 0x%08x\n", (unsigned int) fbi->reg_lccr3);
+
+	/* Sequence from 11.7.10 */
+	LCCR3 = fbi->reg_lccr3;
+	LCCR2 = fbi->reg_lccr2;
+	LCCR1 = fbi->reg_lccr1;
+	LCCR0 = fbi->reg_lccr0 & ~LCCR0_ENB;
+
+	FDADR0 = fbi->fdadr0;
+	FDADR1 = fbi->fdadr1;
+	LCCR0 |= LCCR0_ENB;
+
+	DPRINTK("FDADR0 0x%08x\n", (unsigned int) FDADR0);
+	DPRINTK("FDADR1 0x%08x\n", (unsigned int) FDADR1);
+	DPRINTK("LCCR0 0x%08x\n", (unsigned int) LCCR0);
+	DPRINTK("LCCR1 0x%08x\n", (unsigned int) LCCR1);
+	DPRINTK("LCCR2 0x%08x\n", (unsigned int) LCCR2);
+	DPRINTK("LCCR3 0x%08x\n", (unsigned int) LCCR3);
+}
+
+static void pxafb_disable_controller(struct pxafb_info *fbi)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	DPRINTK("Disabling LCD controller\n");
+
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	add_wait_queue(&fbi->ctrlr_wait, &wait);
+
+	LCSR = 0xffffffff;	/* Clear LCD Status Register */
+	LCCR0 &= ~LCCR0_LDM;	/* Enable LCD Disable Done Interrupt */
+	LCCR0 |= LCCR0_DIS;	/* Disable LCD Controller */
+
+	schedule_timeout(20 * HZ / 1000);
+	remove_wait_queue(&fbi->ctrlr_wait, &wait);
+}
+
+/*
+ *  pxafb_handle_irq: Handle 'LCD DONE' interrupts.
+ */
+static irqreturn_t pxafb_handle_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct pxafb_info *fbi = dev_id;
+	unsigned int lcsr = LCSR;
+
+	if (lcsr & LCSR_LDD) {
+		LCCR0 |= LCCR0_LDM;
+		wake_up(&fbi->ctrlr_wait);
+	}
+
+	LCSR = lcsr;
+	return IRQ_HANDLED;
+}
+
+/*
+ * This function must be called from task context only, since it will
+ * sleep when disabling the LCD controller, or if we get two contending
+ * processes trying to alter state.
+ */
+static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
+{
+	u_int old_state;
+
+	down(&fbi->ctrlr_sem);
+
+	old_state = fbi->state;
+
+	/*
+	 * Hack around fbcon initialisation.
+	 */
+	if (old_state == C_STARTUP && state == C_REENABLE)
+		state = C_ENABLE;
+
+	switch (state) {
+	case C_DISABLE_CLKCHANGE:
+		/*
+		 * Disable controller for clock change.  If the
+		 * controller is already disabled, then do nothing.
+		 */
+		if (old_state != C_DISABLE && old_state != C_DISABLE_PM) {
+			fbi->state = state;
+			//TODO __pxafb_lcd_power(fbi, 0);
+			pxafb_disable_controller(fbi);
+		}
+		break;
+
+	case C_DISABLE_PM:
+	case C_DISABLE:
+		/*
+		 * Disable controller
+		 */
+		if (old_state != C_DISABLE) {
+			fbi->state = state;
+			__pxafb_backlight_power(fbi, 0);
+			__pxafb_lcd_power(fbi, 0);
+			if (old_state != C_DISABLE_CLKCHANGE)
+				pxafb_disable_controller(fbi);
+		}
+		break;
+
+	case C_ENABLE_CLKCHANGE:
+		/*
+		 * Enable the controller after clock change.  Only
+		 * do this if we were disabled for the clock change.
+		 */
+		if (old_state == C_DISABLE_CLKCHANGE) {
+			fbi->state = C_ENABLE;
+			pxafb_enable_controller(fbi);
+			//TODO __pxafb_lcd_power(fbi, 1);
+		}
+		break;
+
+	case C_REENABLE:
+		/*
+		 * Re-enable the controller only if it was already
+		 * enabled.  This is so we reprogram the control
+		 * registers.
+		 */
+		if (old_state == C_ENABLE) {
+			pxafb_disable_controller(fbi);
+			pxafb_setup_gpio(fbi);
+			pxafb_enable_controller(fbi);
+		}
+		break;
+
+	case C_ENABLE_PM:
+		/*
+		 * Re-enable the controller after PM.  This is not
+		 * perfect - think about the case where we were doing
+		 * a clock change, and we suspended half-way through.
+		 */
+		if (old_state != C_DISABLE_PM)
+			break;
+		/* fall through */
+
+	case C_ENABLE:
+		/*
+		 * Power up the LCD screen, enable controller, and
+		 * turn on the backlight.
+		 */
+		if (old_state != C_ENABLE) {
+			fbi->state = C_ENABLE;
+			pxafb_setup_gpio(fbi);
+			pxafb_enable_controller(fbi);
+			__pxafb_lcd_power(fbi, 1);
+			__pxafb_backlight_power(fbi, 1);
+		}
+		break;
+	}
+	up(&fbi->ctrlr_sem);
+}
+
+/*
+ * Our LCD controller task (which is called when we blank or unblank)
+ * via keventd.
+ */
+static void pxafb_task(void *dummy)
+{
+	struct pxafb_info *fbi = dummy;
+	u_int state = xchg(&fbi->task_state, -1);
+
+	set_ctrlr_state(fbi, state);
+}
+
+#ifdef CONFIG_CPU_FREQ
+/*
+ * CPU clock speed change handler.  We need to adjust the LCD timing
+ * parameters when the CPU clock is adjusted by the power management
+ * subsystem.
+ *
+ * TODO: Determine why f->new != 10*get_lclk_frequency_10khz()
+ */
+static int
+pxafb_freq_transition(struct notifier_block *nb, unsigned long val, void *data)
+{
+	struct pxafb_info *fbi = TO_INF(nb, freq_transition);
+	//TODO struct cpufreq_freqs *f = data;
+	u_int pcd;
+
+	switch (val) {
+	case CPUFREQ_PRECHANGE:
+		set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
+		break;
+
+	case CPUFREQ_POSTCHANGE:
+		pcd = get_pcd(fbi->fb.var.pixclock);
+		fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
+		set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
+		break;
+	}
+	return 0;
+}
+
+static int
+pxafb_freq_policy(struct notifier_block *nb, unsigned long val, void *data)
+{
+	struct pxafb_info *fbi = TO_INF(nb, freq_policy);
+	struct fb_var_screeninfo *var = &fbi->fb.var;
+	struct cpufreq_policy *policy = data;
+
+	switch (val) {
+	case CPUFREQ_ADJUST:
+	case CPUFREQ_INCOMPATIBLE:
+		printk(KERN_DEBUG "min dma period: %d ps, "
+			"new clock %d kHz\n", pxafb_display_dma_period(var),
+			policy->max);
+		// TODO: fill in min/max values
+		break;
+#if 0
+	case CPUFREQ_NOTIFY:
+		printk(KERN_ERR "%s: got CPUFREQ_NOTIFY\n", __FUNCTION__);
+		do {} while(0);
+		/* todo: panic if min/max values aren't fulfilled
+		 * [can't really happen unless there's a bug in the
+		 * CPU policy verification process *
+		 */
+		break;
+#endif
+	}
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_PM
+/*
+ * Power management hooks.  Note that we won't be called from IRQ context,
+ * unlike the blank functions above, so we may sleep.
+ */
+static int pxafb_suspend(struct device *dev, u32 state, u32 level)
+{
+	struct pxafb_info *fbi = dev_get_drvdata(dev);
+
+	if (level == SUSPEND_DISABLE || level == SUSPEND_POWER_DOWN)
+		set_ctrlr_state(fbi, C_DISABLE_PM);
+	return 0;
+}
+
+static int pxafb_resume(struct device *dev, u32 level)
+{
+	struct pxafb_info *fbi = dev_get_drvdata(dev);
+
+	if (level == RESUME_ENABLE)
+		set_ctrlr_state(fbi, C_ENABLE_PM);
+	return 0;
+}
+#else
+#define pxafb_suspend	NULL
+#define pxafb_resume	NULL
+#endif
+
+/*
+ * pxafb_map_video_memory():
+ *      Allocates the DRAM memory for the frame buffer.  This buffer is
+ *	remapped into a non-cached, non-buffered, memory region to
+ *      allow palette and pixel writes to occur without flushing the
+ *      cache.  Once this area is remapped, all virtual memory
+ *      access to the video memory should occur at the new region.
+ */
+static int __init pxafb_map_video_memory(struct pxafb_info *fbi)
+{
+	u_long palette_mem_size;
+
+	/*
+	 * We reserve one page for the palette, plus the size
+	 * of the framebuffer.
+	 */
+	fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
+	fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size,
+					      &fbi->map_dma, GFP_KERNEL);
+
+	if (fbi->map_cpu) {
+		/* prevent initial garbage on screen */
+		memset(fbi->map_cpu, 0, fbi->map_size);
+		fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE;
+		fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
+		/*
+		 * FIXME: this is actually the wrong thing to place in
+		 * smem_start.  But fbdev suffers from the problem that
+		 * it needs an API which doesn't exist (in this case,
+		 * dma_writecombine_mmap)
+		 */
+		fbi->fb.fix.smem_start = fbi->screen_dma;
+
+		fbi->palette_size = fbi->fb.var.bits_per_pixel == 8 ? 256 : 16;
+
+		palette_mem_size = fbi->palette_size * sizeof(u16);
+		DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size);
+
+		fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
+		fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
+	}
+
+	return fbi->map_cpu ? 0 : -ENOMEM;
+}
+
+static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev)
+{
+	struct pxafb_info *fbi;
+	void *addr;
+	struct pxafb_mach_info *inf = dev->platform_data;
+
+	/* Alloc the pxafb_info and pseudo_palette in one step */
+	fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(u32) * 16, GFP_KERNEL);
+	if (!fbi)
+		return NULL;
+
+	memset(fbi, 0, sizeof(struct pxafb_info));
+	fbi->dev = dev;
+
+	strcpy(fbi->fb.fix.id, PXA_NAME);
+
+	fbi->fb.fix.type	= FB_TYPE_PACKED_PIXELS;
+	fbi->fb.fix.type_aux	= 0;
+	fbi->fb.fix.xpanstep	= 0;
+	fbi->fb.fix.ypanstep	= 0;
+	fbi->fb.fix.ywrapstep	= 0;
+	fbi->fb.fix.accel	= FB_ACCEL_NONE;
+
+	fbi->fb.var.nonstd	= 0;
+	fbi->fb.var.activate	= FB_ACTIVATE_NOW;
+	fbi->fb.var.height	= -1;
+	fbi->fb.var.width	= -1;
+	fbi->fb.var.accel_flags	= 0;
+	fbi->fb.var.vmode	= FB_VMODE_NONINTERLACED;
+
+	fbi->fb.fbops		= &pxafb_ops;
+	fbi->fb.flags		= FBINFO_DEFAULT;
+	fbi->fb.node		= -1;
+
+	addr = fbi;
+	addr = addr + sizeof(struct pxafb_info);
+	fbi->fb.pseudo_palette	= addr;
+
+	fbi->max_xres			= inf->xres;
+	fbi->fb.var.xres		= inf->xres;
+	fbi->fb.var.xres_virtual	= inf->xres;
+	fbi->max_yres			= inf->yres;
+	fbi->fb.var.yres		= inf->yres;
+	fbi->fb.var.yres_virtual	= inf->yres;
+	fbi->max_bpp			= inf->bpp;
+	fbi->fb.var.bits_per_pixel	= inf->bpp;
+	fbi->fb.var.pixclock		= inf->pixclock;
+	fbi->fb.var.hsync_len		= inf->hsync_len;
+	fbi->fb.var.left_margin		= inf->left_margin;
+	fbi->fb.var.right_margin	= inf->right_margin;
+	fbi->fb.var.vsync_len		= inf->vsync_len;
+	fbi->fb.var.upper_margin	= inf->upper_margin;
+	fbi->fb.var.lower_margin	= inf->lower_margin;
+	fbi->fb.var.sync		= inf->sync;
+	fbi->fb.var.grayscale		= inf->cmap_greyscale;
+	fbi->cmap_inverse		= inf->cmap_inverse;
+	fbi->cmap_static		= inf->cmap_static;
+	fbi->lccr0			= inf->lccr0;
+	fbi->lccr3			= inf->lccr3;
+	fbi->state			= C_STARTUP;
+	fbi->task_state			= (u_char)-1;
+	fbi->fb.fix.smem_len		= fbi->max_xres * fbi->max_yres *
+					  fbi->max_bpp / 8;
+
+	init_waitqueue_head(&fbi->ctrlr_wait);
+	INIT_WORK(&fbi->task, pxafb_task, fbi);
+	init_MUTEX(&fbi->ctrlr_sem);
+
+	return fbi;
+}
+
+#ifdef CONFIG_FB_PXA_PARAMETERS
+static int __init pxafb_parse_options(struct device *dev, char *options)
+{
+	struct pxafb_mach_info *inf = dev->platform_data;
+	char *this_opt;
+
+        if (!options || !*options)
+                return 0;
+
+	dev_dbg(dev, "options are \"%s\"\n", options ? options : "null");
+
+	/* could be made table driven or similar?... */
+        while ((this_opt = strsep(&options, ",")) != NULL) {
+                if (!strncmp(this_opt, "mode:", 5)) {
+			const char *name = this_opt+5;
+			unsigned int namelen = strlen(name);
+			int res_specified = 0, bpp_specified = 0;
+			unsigned int xres = 0, yres = 0, bpp = 0;
+			int yres_specified = 0;
+			int i;
+			for (i = namelen-1; i >= 0; i--) {
+				switch (name[i]) {
+				case '-':
+					namelen = i;
+					if (!bpp_specified && !yres_specified) {
+						bpp = simple_strtoul(&name[i+1], NULL, 0);
+						bpp_specified = 1;
+					} else
+						goto done;
+					break;
+				case 'x':
+					if (!yres_specified) {
+						yres = simple_strtoul(&name[i+1], NULL, 0);
+						yres_specified = 1;
+					} else
+						goto done;
+					break;
+				case '0'...'9':
+					break;
+				default:
+					goto done;
+				}
+			}
+			if (i < 0 && yres_specified) {
+				xres = simple_strtoul(name, NULL, 0);
+				res_specified = 1;
+			}
+		done:
+			if (res_specified) {
+				dev_info(dev, "overriding resolution: %dx%d\n", xres, yres);
+				inf->xres = xres; inf->yres = yres;
+			}
+			if (bpp_specified)
+				switch (bpp) {
+				case 1:
+				case 2:
+				case 4:
+				case 8:
+				case 16:
+					inf->bpp = bpp;
+					dev_info(dev, "overriding bit depth: %d\n", bpp);
+					break;
+				default:
+					dev_err(dev, "Depth %d is not valid\n", bpp);
+				}
+                } else if (!strncmp(this_opt, "pixclock:", 9)) {
+                        inf->pixclock = simple_strtoul(this_opt+9, NULL, 0);
+			dev_info(dev, "override pixclock: %ld\n", inf->pixclock);
+                } else if (!strncmp(this_opt, "left:", 5)) {
+                        inf->left_margin = simple_strtoul(this_opt+5, NULL, 0);
+			dev_info(dev, "override left: %u\n", inf->left_margin);
+                } else if (!strncmp(this_opt, "right:", 6)) {
+                        inf->right_margin = simple_strtoul(this_opt+6, NULL, 0);
+			dev_info(dev, "override right: %u\n", inf->right_margin);
+                } else if (!strncmp(this_opt, "upper:", 6)) {
+                        inf->upper_margin = simple_strtoul(this_opt+6, NULL, 0);
+			dev_info(dev, "override upper: %u\n", inf->upper_margin);
+                } else if (!strncmp(this_opt, "lower:", 6)) {
+                        inf->lower_margin = simple_strtoul(this_opt+6, NULL, 0);
+			dev_info(dev, "override lower: %u\n", inf->lower_margin);
+                } else if (!strncmp(this_opt, "hsynclen:", 9)) {
+                        inf->hsync_len = simple_strtoul(this_opt+9, NULL, 0);
+			dev_info(dev, "override hsynclen: %u\n", inf->hsync_len);
+                } else if (!strncmp(this_opt, "vsynclen:", 9)) {
+                        inf->vsync_len = simple_strtoul(this_opt+9, NULL, 0);
+			dev_info(dev, "override vsynclen: %u\n", inf->vsync_len);
+                } else if (!strncmp(this_opt, "hsync:", 6)) {
+                        if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
+				dev_info(dev, "override hsync: Active Low\n");
+				inf->sync &= ~FB_SYNC_HOR_HIGH_ACT;
+			} else {
+				dev_info(dev, "override hsync: Active High\n");
+				inf->sync |= FB_SYNC_HOR_HIGH_ACT;
+			}
+                } else if (!strncmp(this_opt, "vsync:", 6)) {
+                        if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
+				dev_info(dev, "override vsync: Active Low\n");
+				inf->sync &= ~FB_SYNC_VERT_HIGH_ACT;
+			} else {
+				dev_info(dev, "override vsync: Active High\n");
+				inf->sync |= FB_SYNC_VERT_HIGH_ACT;
+			}
+                } else if (!strncmp(this_opt, "dpc:", 4)) {
+                        if (simple_strtoul(this_opt+4, NULL, 0) == 0) {
+				dev_info(dev, "override double pixel clock: false\n");
+				inf->lccr3 &= ~LCCR3_DPC;
+			} else {
+				dev_info(dev, "override double pixel clock: true\n");
+				inf->lccr3 |= LCCR3_DPC;
+			}
+                } else if (!strncmp(this_opt, "outputen:", 9)) {
+                        if (simple_strtoul(this_opt+9, NULL, 0) == 0) {
+				dev_info(dev, "override output enable: active low\n");
+				inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnL;
+			} else {
+				dev_info(dev, "override output enable: active high\n");
+				inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnH;
+			}
+                } else if (!strncmp(this_opt, "pixclockpol:", 12)) {
+                        if (simple_strtoul(this_opt+12, NULL, 0) == 0) {
+				dev_info(dev, "override pixel clock polarity: falling edge\n");
+				inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixFlEdg;
+			} else {
+				dev_info(dev, "override pixel clock polarity: rising edge\n");
+				inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixRsEdg;
+			}
+                } else if (!strncmp(this_opt, "color", 5)) {
+			inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Color;
+                } else if (!strncmp(this_opt, "mono", 4)) {
+			inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Mono;
+                } else if (!strncmp(this_opt, "active", 6)) {
+			inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Act;
+                } else if (!strncmp(this_opt, "passive", 7)) {
+			inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Pas;
+                } else if (!strncmp(this_opt, "single", 6)) {
+			inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Sngl;
+                } else if (!strncmp(this_opt, "dual", 4)) {
+			inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Dual;
+                } else if (!strncmp(this_opt, "4pix", 4)) {
+			inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_4PixMono;
+                } else if (!strncmp(this_opt, "8pix", 4)) {
+			inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_8PixMono;
+		} else {
+			dev_err(dev, "unknown option: %s\n", this_opt);
+			return -EINVAL;
+		}
+        }
+        return 0;
+
+}
+#endif
+
+int __init pxafb_probe(struct device *dev)
+{
+	struct pxafb_info *fbi;
+	struct pxafb_mach_info *inf;
+	int ret;
+
+	dev_dbg(dev, "pxafb_probe\n");
+
+	inf = dev->platform_data;
+	ret = -ENOMEM;
+	fbi = NULL;
+	if (!inf)
+		goto failed;
+
+#ifdef CONFIG_FB_PXA_PARAMETERS
+	ret = pxafb_parse_options(dev, g_options);
+	if (ret < 0)
+		goto failed;
+#endif
+
+#ifdef DEBUG_VAR
+        /* Check for various illegal bit-combinations. Currently only
+	 * a warning is given. */
+
+        if (inf->lccr0 & LCCR0_INVALID_CONFIG_MASK)
+                dev_warn(dev, "machine LCCR0 setting contains illegal bits: %08x\n",
+                        inf->lccr0 & LCCR0_INVALID_CONFIG_MASK);
+        if (inf->lccr3 & LCCR3_INVALID_CONFIG_MASK)
+                dev_warn(dev, "machine LCCR3 setting contains illegal bits: %08x\n",
+                        inf->lccr3 & LCCR3_INVALID_CONFIG_MASK);
+        if (inf->lccr0 & LCCR0_DPD &&
+	    ((inf->lccr0 & LCCR0_PAS) != LCCR0_Pas ||
+	     (inf->lccr0 & LCCR0_SDS) != LCCR0_Sngl ||
+	     (inf->lccr0 & LCCR0_CMS) != LCCR0_Mono))
+                dev_warn(dev, "Double Pixel Data (DPD) mode is only valid in passive mono"
+			 " single panel mode\n");
+        if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Act &&
+	    (inf->lccr0 & LCCR0_SDS) == LCCR0_Dual)
+                dev_warn(dev, "Dual panel only valid in passive mode\n");
+        if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Pas &&
+             (inf->upper_margin || inf->lower_margin))
+                dev_warn(dev, "Upper and lower margins must be 0 in passive mode\n");
+#endif
+
+	dev_dbg(dev, "got a %dx%dx%d LCD\n",inf->xres, inf->yres, inf->bpp);
+	if (inf->xres == 0 || inf->yres == 0 || inf->bpp == 0) {
+		dev_err(dev, "Invalid resolution or bit depth\n");
+		ret = -EINVAL;
+		goto failed;
+	}
+	pxafb_backlight_power = inf->pxafb_backlight_power;
+	pxafb_lcd_power = inf->pxafb_lcd_power;
+	fbi = pxafb_init_fbinfo(dev);
+	if (!fbi) {
+		dev_err(dev, "Failed to initialize framebuffer device\n");
+		ret = -ENOMEM; // only reason for pxafb_init_fbinfo to fail is kmalloc
+		goto failed;
+	}
+
+	/* Initialize video memory */
+	ret = pxafb_map_video_memory(fbi);
+	if (ret) {
+		dev_err(dev, "Failed to allocate video RAM: %d\n", ret);
+		ret = -ENOMEM;
+		goto failed;
+	}
+	/* enable LCD controller clock */
+	pxa_set_cken(CKEN16_LCD, 1);
+
+	ret = request_irq(IRQ_LCD, pxafb_handle_irq, SA_INTERRUPT, "LCD", fbi);
+	if (ret) {
+		dev_err(dev, "request_irq failed: %d\n", ret);
+		ret = -EBUSY;
+		goto failed;
+	}
+
+	/*
+	 * This makes sure that our colour bitfield
+	 * descriptors are correctly initialised.
+	 */
+	pxafb_check_var(&fbi->fb.var, &fbi->fb);
+	pxafb_set_par(&fbi->fb);
+
+	dev_set_drvdata(dev, fbi);
+
+	ret = register_framebuffer(&fbi->fb);
+	if (ret < 0) {
+		dev_err(dev, "Failed to register framebuffer device: %d\n", ret);
+		goto failed;
+	}
+
+#ifdef CONFIG_PM
+	// TODO
+#endif
+
+#ifdef CONFIG_CPU_FREQ
+	fbi->freq_transition.notifier_call = pxafb_freq_transition;
+	fbi->freq_policy.notifier_call = pxafb_freq_policy;
+	cpufreq_register_notifier(&fbi->freq_transition, CPUFREQ_TRANSITION_NOTIFIER);
+	cpufreq_register_notifier(&fbi->freq_policy, CPUFREQ_POLICY_NOTIFIER);
+#endif
+
+	/*
+	 * Ok, now enable the LCD controller
+	 */
+	set_ctrlr_state(fbi, C_ENABLE);
+
+	return 0;
+
+failed:
+	dev_set_drvdata(dev, NULL);
+	kfree(fbi);
+	return ret;
+}
+
+static struct device_driver pxafb_driver = {
+	.name		= "pxa2xx-fb",
+	.bus		= &platform_bus_type,
+	.probe		= pxafb_probe,
+#ifdef CONFIG_PM
+	.suspend	= pxafb_suspend,
+	.resume		= pxafb_resume,
+#endif
+};
+
+#ifndef MODULE
+int __devinit pxafb_setup(char *options)
+{
+# ifdef CONFIG_FB_PXA_PARAMETERS
+	strlcpy(g_options, options, sizeof(g_options));
+# endif
+	return 0;
+}
+#else
+# ifdef CONFIG_FB_PXA_PARAMETERS
+module_param_string(options, g_options, sizeof(g_options), 0);
+MODULE_PARM_DESC(options, "LCD parameters (see Documentation/fb/pxafb.txt)");
+# endif
+#endif
+
+int __devinit pxafb_init(void)
+{
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("pxafb", &option))
+		return -ENODEV;
+	pxafb_setup(option);
+#endif
+	return driver_register(&pxafb_driver);
+}
+
+module_init(pxafb_init);
+
+MODULE_DESCRIPTION("loadable framebuffer driver for PXA");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/pxafb.h b/drivers/video/pxafb.h
new file mode 100644
index 0000000..de15fec
--- /dev/null
+++ b/drivers/video/pxafb.h
@@ -0,0 +1,129 @@
+#ifndef __PXAFB_H__
+#define __PXAFB_H__
+
+/*
+ * linux/drivers/video/pxafb.h
+ *    -- Intel PXA250/210 LCD Controller Frame Buffer Device
+ *
+ *  Copyright (C) 1999 Eric A. Thomas.
+ *  Copyright (C) 2004 Jean-Frederic Clere.
+ *  Copyright (C) 2004 Ian Campbell.
+ *  Copyright (C) 2004 Jeff Lackey.
+ *   Based on sa1100fb.c Copyright (C) 1999 Eric A. Thomas
+ *  which in turn is
+ *   Based on acornfb.c Copyright (C) Russell King.
+ *
+ *  2001-08-03: Cliff Brake <cbrake@acclent.com>
+ *	 - ported SA1100 code to PXA
+ *
+ * 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.
+ */
+
+/* Shadows for LCD controller registers */
+struct pxafb_lcd_reg {
+	unsigned int lccr0;
+	unsigned int lccr1;
+	unsigned int lccr2;
+	unsigned int lccr3;
+};
+
+/* PXA LCD DMA descriptor */
+struct pxafb_dma_descriptor {
+	unsigned int fdadr;
+	unsigned int fsadr;
+	unsigned int fidr;
+	unsigned int ldcmd;
+};
+
+struct pxafb_info {
+	struct fb_info		fb;
+	struct device		*dev;
+
+	u_int			max_bpp;
+	u_int			max_xres;
+	u_int			max_yres;
+
+	/*
+	 * These are the addresses we mapped
+	 * the framebuffer memory region to.
+	 */
+	/* raw memory addresses */
+	dma_addr_t		map_dma;	/* physical */
+	u_char *		map_cpu;	/* virtual */
+	u_int			map_size;
+
+	/* addresses of pieces placed in raw buffer */
+	u_char *		screen_cpu;	/* virtual address of frame buffer */
+	dma_addr_t		screen_dma;	/* physical address of frame buffer */
+	u16 *			palette_cpu;	/* virtual address of palette memory */
+	dma_addr_t		palette_dma;	/* physical address of palette memory */
+	u_int			palette_size;
+
+	/* DMA descriptors */
+	struct pxafb_dma_descriptor * 	dmadesc_fblow_cpu;
+	dma_addr_t		dmadesc_fblow_dma;
+	struct pxafb_dma_descriptor * 	dmadesc_fbhigh_cpu;
+	dma_addr_t		dmadesc_fbhigh_dma;
+	struct pxafb_dma_descriptor *	dmadesc_palette_cpu;
+	dma_addr_t		dmadesc_palette_dma;
+
+	dma_addr_t		fdadr0;
+	dma_addr_t		fdadr1;
+
+	u_int			lccr0;
+	u_int			lccr3;
+	u_int			cmap_inverse:1,
+				cmap_static:1,
+				unused:30;
+
+	u_int			reg_lccr0;
+	u_int			reg_lccr1;
+	u_int			reg_lccr2;
+	u_int			reg_lccr3;
+
+	volatile u_char		state;
+	volatile u_char		task_state;
+	struct semaphore	ctrlr_sem;
+	wait_queue_head_t	ctrlr_wait;
+	struct work_struct	task;
+
+#ifdef CONFIG_CPU_FREQ
+	struct notifier_block	freq_transition;
+	struct notifier_block	freq_policy;
+#endif
+};
+
+#define TO_INF(ptr,member) container_of(ptr,struct pxafb_info,member)
+
+/*
+ * These are the actions for set_ctrlr_state
+ */
+#define C_DISABLE		(0)
+#define C_ENABLE		(1)
+#define C_DISABLE_CLKCHANGE	(2)
+#define C_ENABLE_CLKCHANGE	(3)
+#define C_REENABLE		(4)
+#define C_DISABLE_PM		(5)
+#define C_ENABLE_PM		(6)
+#define C_STARTUP		(7)
+
+#define PXA_NAME	"PXA"
+
+/*
+ *  Debug macros
+ */
+#if DEBUG
+#  define DPRINTK(fmt, args...)	printk("%s: " fmt, __FUNCTION__ , ## args)
+#else
+#  define DPRINTK(fmt, args...)
+#endif
+
+/*
+ * Minimum X and Y resolutions
+ */
+#define MIN_XRES	64
+#define MIN_YRES	64
+
+#endif /* __PXAFB_H__ */
diff --git a/drivers/video/q40fb.c b/drivers/video/q40fb.c
new file mode 100644
index 0000000..71b69da
--- /dev/null
+++ b/drivers/video/q40fb.c
@@ -0,0 +1,160 @@
+/*
+ * linux/drivers/video/q40fb.c -- Q40 frame buffer device
+ *
+ * Copyright (C) 2001
+ *
+ *      Richard Zidlicky <rz@linux-m68k.org>
+ *
+ *  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/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+
+#include <asm/uaccess.h>
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/q40_master.h>
+#include <linux/fb.h>
+#include <linux/module.h>
+#include <asm/pgtable.h>
+
+#define Q40_PHYS_SCREEN_ADDR 0xFE800000
+
+static struct fb_fix_screeninfo q40fb_fix __initdata = {
+	.id		= "Q40",
+	.smem_len	= 1024*1024,
+	.type		= FB_TYPE_PACKED_PIXELS,
+	.visual		= FB_VISUAL_TRUECOLOR,
+	.line_length	= 1024*2,
+	.accel		= FB_ACCEL_NONE,
+};
+
+static struct fb_var_screeninfo q40fb_var __initdata = {
+	.xres		= 1024,
+	.yres		= 512,
+	.xres_virtual	= 1024,
+	.yres_virtual	= 512,
+	.bits_per_pixel	= 16,
+    	.red		= {6, 5, 0},
+	.green		= {11, 5, 0},
+	.blue		= {0, 6, 0},
+	.activate	= FB_ACTIVATE_NOW,
+	.height		= 230,
+	.width		= 300,
+	.vmode		= FB_VMODE_NONINTERLACED,
+};
+
+static int q40fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp,
+			   struct fb_info *info)
+{
+    /*
+     *  Set a single color register. The values supplied have a 16 bit
+     *  magnitude.
+     *  Return != 0 for invalid regno.
+     */
+
+    if (regno > 255)
+	    return 1;
+    red>>=11;
+    green>>=11;
+    blue>>=10;
+
+    if (regno < 16) {
+	((u32 *)info->pseudo_palette)[regno] = ((red & 31) <<6) |
+					       ((green & 31) << 11) |
+					       (blue & 63);
+    }
+    return 0;
+}
+
+static struct fb_ops q40fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_setcolreg	= q40fb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+static int __init q40fb_probe(struct device *device)
+{
+	struct platform_device *dev = to_platform_device(device);
+	struct fb_info *info;
+
+	if (!MACH_IS_Q40)
+		return -ENXIO;
+
+	/* mapped in q40/config.c */
+	q40fb_fix.smem_start = Q40_PHYS_SCREEN_ADDR;
+
+	info = framebuffer_alloc(sizeof(u32) * 256, &dev->dev);
+	if (!info)
+		return -ENOMEM;
+
+	info->var = q40fb_var;
+	info->fix = q40fb_fix;
+	info->fbops = &q40fb_ops;
+	info->flags = FBINFO_DEFAULT;  /* not as module for now */
+	info->pseudo_palette = info->par;
+	info->par = NULL;
+	info->screen_base = (char *) q40fb_fix.smem_start;
+
+	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+		framebuffer_release(info);
+		return -ENOMEM;
+	}
+
+	master_outb(3, DISPLAY_CONTROL_REG);
+
+	if (register_framebuffer(info) < 0) {
+		printk(KERN_ERR "Unable to register Q40 frame buffer\n");
+		fb_dealloc_cmap(&info->cmap);
+		framebuffer_release(info);
+		return -EINVAL;
+	}
+
+        printk(KERN_INFO "fb%d: Q40 frame buffer alive and kicking !\n",
+	       info->node);
+	return 0;
+}
+
+static struct device_driver q40fb_driver = {
+	.name	= "q40fb",
+	.bus	= &platform_bus_type,
+	.probe	= q40fb_probe,
+};
+
+static struct platform_device q40fb_device = {
+	.name	= "q40fb",
+};
+
+int __init q40fb_init(void)
+{
+	int ret = 0;
+
+	if (fb_get_options("q40fb", NULL))
+		return -ENODEV;
+
+	ret = driver_register(&q40fb_driver);
+
+	if (!ret) {
+		ret = platform_device_register(&q40fb_device);
+		if (ret)
+			driver_unregister(&q40fb_driver);
+	}
+	return ret;
+}
+
+module_init(q40fb_init);
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/radeonfb.c b/drivers/video/radeonfb.c
new file mode 100644
index 0000000..d9a084e
--- /dev/null
+++ b/drivers/video/radeonfb.c
@@ -0,0 +1,3168 @@
+/*
+ *	drivers/video/radeonfb.c
+ *	framebuffer driver for ATI Radeon chipset video boards
+ *
+ *	Copyright 2000	Ani Joshi <ajoshi@kernel.crashing.org>
+ *
+ *
+ *	ChangeLog:
+ *	2000-08-03	initial version 0.0.1
+ *	2000-09-10	more bug fixes, public release 0.0.5
+ *	2001-02-19	mode bug fixes, 0.0.7
+ *	2001-07-05	fixed scrolling issues, engine initialization,
+ *			and minor mode tweaking, 0.0.9
+ *	2001-09-07	Radeon VE support, Nick Kurshev
+ *			blanking, pan_display, and cmap fixes, 0.1.0
+ *	2001-10-10	Radeon 7500 and 8500 support, and experimental
+ *			flat panel support, 0.1.1
+ *	2001-11-17	Radeon M6 (ppc) support, Daniel Berlin, 0.1.2
+ *	2001-11-18	DFP fixes, Kevin Hendricks, 0.1.3
+ *	2001-11-29	more cmap, backlight fixes, Benjamin Herrenschmidt
+ *	2002-01-18	DFP panel detection via BIOS, Michael Clark, 0.1.4
+ *	2002-06-02	console switching, mode set fixes, accel fixes
+ *	2002-06-03	MTRR support, Peter Horton, 0.1.5
+ *	2002-09-21	rv250, r300, m9 initial support,
+ *			added mirror option, 0.1.6
+ *
+ *	Special thanks to ATI DevRel team for their hardware donations.
+ *
+ */
+
+
+#define RADEON_VERSION	"0.1.6"
+
+
+#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/delay.h>
+#include <linux/fb.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#if defined(__powerpc__)
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include "macmodes.h"
+
+#ifdef CONFIG_NVRAM
+#include <linux/nvram.h>
+#endif
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+
+#ifdef CONFIG_BOOTX_TEXT
+#include <asm/btext.h>
+#endif
+
+#ifdef CONFIG_ADB_PMU
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#endif
+
+#endif /* __powerpc__ */
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include <video/radeon.h>
+#include <linux/radeonfb.h>
+
+#define DEBUG	1
+
+#if DEBUG
+#define RTRACE		printk
+#else
+#define RTRACE		if(0) printk
+#endif
+
+// XXX
+#undef CONFIG_PMAC_PBOOK
+
+
+enum radeon_chips {
+	RADEON_QD,
+	RADEON_QE,
+	RADEON_QF,
+	RADEON_QG,
+	RADEON_QY,
+	RADEON_QZ,
+	RADEON_LW,
+	RADEON_LX,
+	RADEON_LY,
+	RADEON_LZ,
+	RADEON_QL,
+	RADEON_QN,
+	RADEON_QO,
+	RADEON_Ql,
+	RADEON_BB,
+	RADEON_QW,
+	RADEON_QX,
+	RADEON_Id,
+	RADEON_Ie,
+	RADEON_If,
+	RADEON_Ig,
+	RADEON_Ya,
+	RADEON_Yd,
+	RADEON_Ld,
+	RADEON_Le,
+	RADEON_Lf,
+	RADEON_Lg,
+	RADEON_ND,
+	RADEON_NE,
+	RADEON_NF,
+	RADEON_NG,
+	RADEON_QM
+};
+
+enum radeon_arch {
+	RADEON_R100,
+	RADEON_RV100,
+	RADEON_R200,
+	RADEON_RV200,
+	RADEON_RV250,
+	RADEON_R300,
+	RADEON_M6,
+	RADEON_M7,
+	RADEON_M9
+};
+
+static struct radeon_chip_info {
+	const char *name;
+	unsigned char arch;
+} radeon_chip_info[] __devinitdata = {
+	{ "QD", RADEON_R100 },
+	{ "QE", RADEON_R100 },
+	{ "QF", RADEON_R100 },
+	{ "QG", RADEON_R100 },
+	{ "VE QY", RADEON_RV100 },
+	{ "VE QZ", RADEON_RV100 },
+	{ "M7 LW", RADEON_M7 },
+	{ "M7 LX", RADEON_M7 },
+	{ "M6 LY", RADEON_M6 },
+	{ "M6 LZ", RADEON_M6 },
+	{ "8500 QL", RADEON_R200 },
+	{ "8500 QN", RADEON_R200 },
+	{ "8500 QO", RADEON_R200 },
+	{ "8500 Ql", RADEON_R200 },
+	{ "8500 BB", RADEON_R200 },
+	{ "7500 QW", RADEON_RV200 },
+	{ "7500 QX", RADEON_RV200 },
+	{ "9000 Id", RADEON_RV250 },
+	{ "9000 Ie", RADEON_RV250 },
+	{ "9000 If", RADEON_RV250 },
+	{ "9000 Ig", RADEON_RV250 },
+	{ "M9 Ld", RADEON_M9 },
+	{ "M9 Le", RADEON_M9 },
+	{ "M9 Lf", RADEON_M9 },
+	{ "M9 Lg", RADEON_M9 },
+	{ "9700 ND", RADEON_R300 },
+	{ "9700 NE", RADEON_R300 },
+	{ "9700 NF", RADEON_R300 },
+	{ "9700 NG", RADEON_R300 },
+	{ "9100 QM", RADEON_R200 }
+};
+
+
+enum radeon_montype
+{
+	MT_NONE,
+	MT_CRT,		/* CRT */
+	MT_LCD,		/* LCD */
+	MT_DFP,		/* DVI */
+	MT_CTV,		/* composite TV */
+	MT_STV		/* S-Video out */
+};
+
+
+static struct pci_device_id radeonfb_pci_table[] = {
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QD},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QE},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QF},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QG, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QG},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QY, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QY},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QZ, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QZ},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_LW, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_LW},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_LX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_LX},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_LY, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_LY},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_LZ, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_LZ},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QL, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QL},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QN, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QN},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QO},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Ql, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Ql},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_BB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_BB},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QW, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QW},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QX},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Id},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Ie, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Ie},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_If, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_If},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Ig, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Ig},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Ya, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Ya},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Yd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Yd},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Ld, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Ld},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Le, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Le},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Lf, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Lf},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Lg, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Lg},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_ND, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_ND},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_NE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_NE},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_NF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_NF},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_NG, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_NG},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QM},
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, radeonfb_pci_table);
+
+
+typedef struct {
+	u16 reg;
+	u32 val;
+} reg_val;
+
+
+/* these common regs are cleared before mode setting so they do not
+ * interfere with anything
+ */
+static reg_val common_regs[] = {
+	{ OVR_CLR, 0 },	
+	{ OVR_WID_LEFT_RIGHT, 0 },
+	{ OVR_WID_TOP_BOTTOM, 0 },
+	{ OV0_SCALE_CNTL, 0 },
+	{ SUBPIC_CNTL, 0 },
+	{ VIPH_CONTROL, 0 },
+	{ I2C_CNTL_1, 0 },
+	{ GEN_INT_CNTL, 0 },
+	{ CAP0_TRIG_CNTL, 0 },
+};
+
+static reg_val common_regs_m6[] = {
+	{ OVR_CLR,      0 },
+	{ OVR_WID_LEFT_RIGHT,   0 },
+	{ OVR_WID_TOP_BOTTOM,   0 },
+	{ OV0_SCALE_CNTL,   0 },
+	{ SUBPIC_CNTL,      0 },
+	{ GEN_INT_CNTL,     0 },
+	{ CAP0_TRIG_CNTL,   0 } 
+};
+
+typedef struct {
+        u8 clock_chip_type;
+        u8 struct_size;
+        u8 accelerator_entry;
+        u8 VGA_entry;
+        u16 VGA_table_offset;
+        u16 POST_table_offset;
+        u16 XCLK;
+        u16 MCLK;
+        u8 num_PLL_blocks;
+        u8 size_PLL_blocks;
+        u16 PCLK_ref_freq;
+        u16 PCLK_ref_divider;
+        u32 PCLK_min_freq;
+        u32 PCLK_max_freq;
+        u16 MCLK_ref_freq;
+        u16 MCLK_ref_divider;
+        u32 MCLK_min_freq;
+        u32 MCLK_max_freq;
+        u16 XCLK_ref_freq;
+        u16 XCLK_ref_divider;
+        u32 XCLK_min_freq;
+        u32 XCLK_max_freq;
+} __attribute__ ((packed)) PLL_BLOCK;
+
+
+struct pll_info {
+	int ppll_max;
+	int ppll_min;
+	int xclk;
+	int ref_div;
+	int ref_clk;
+};
+
+
+struct ram_info {
+	int ml;
+	int mb;
+	int trcd;
+	int trp;
+	int twr;
+	int cl;
+	int tr2w;
+	int loop_latency;
+	int rloop;
+};
+
+
+struct radeon_regs {
+	/* CRTC regs */
+	u32 crtc_h_total_disp;
+	u32 crtc_h_sync_strt_wid;
+	u32 crtc_v_total_disp;
+	u32 crtc_v_sync_strt_wid;
+	u32 crtc_pitch;
+	u32 crtc_gen_cntl;
+	u32 crtc_ext_cntl;
+	u32 dac_cntl;
+
+	u32 flags;
+	u32 pix_clock;
+	int xres, yres;
+
+	/* DDA regs */
+	u32 dda_config;
+	u32 dda_on_off;
+
+	/* PLL regs */
+	u32 ppll_div_3;
+	u32 ppll_ref_div;
+	u32 vclk_ecp_cntl;
+	
+	/* Flat panel regs */
+	u32 fp_crtc_h_total_disp;
+	u32 fp_crtc_v_total_disp;
+	u32 fp_gen_cntl;
+	u32 fp_h_sync_strt_wid;
+	u32 fp_horz_stretch;
+	u32 fp_panel_cntl;
+	u32 fp_v_sync_strt_wid;
+	u32 fp_vert_stretch;
+	u32 lvds_gen_cntl;
+	u32 lvds_pll_cntl;
+	u32 tmds_crc;
+	u32 tmds_transmitter_cntl;
+
+#if defined(__BIG_ENDIAN)
+	u32 surface_cntl;
+#endif
+};
+
+
+struct radeonfb_info {
+	struct fb_info info;
+
+	struct radeon_regs state;
+	struct radeon_regs init_state;
+
+	char name[32];
+	char ram_type[12];
+
+	unsigned long mmio_base_phys;
+	unsigned long fb_base_phys;
+
+	void __iomem *mmio_base;
+	void __iomem *fb_base;
+
+	struct pci_dev *pdev;
+
+	unsigned char *EDID;
+	unsigned char __iomem *bios_seg;
+
+	u32 pseudo_palette[17];
+	struct { u8 red, green, blue, pad; } palette[256];
+
+	int chipset;
+	unsigned char arch;
+	int video_ram;
+	u8 rev;
+	int pitch, bpp, depth;
+	int xres, yres, pixclock;
+	int xres_virtual, yres_virtual;
+	u32 accel_flags;
+
+	int use_default_var;
+	int got_dfpinfo;
+
+	int hasCRTC2;
+	int crtDisp_type;
+	int dviDisp_type;
+
+	int panel_xres, panel_yres;
+	int clock;
+	int hOver_plus, hSync_width, hblank;
+	int vOver_plus, vSync_width, vblank;
+	int hAct_high, vAct_high, interlaced;
+	int synct, misc;
+
+	u32 dp_gui_master_cntl;
+
+	struct pll_info pll;
+	int pll_output_freq, post_div, fb_div;
+
+	struct ram_info ram;
+
+	int mtrr_hdl;
+
+#ifdef CONFIG_PMAC_PBOOK
+	int pm_reg;
+	u32 save_regs[64];
+	u32 mdll, mdll2;
+#endif /* CONFIG_PMAC_PBOOK */
+	int asleep;
+	
+	struct radeonfb_info *next;
+};
+
+
+static struct fb_var_screeninfo radeonfb_default_var = {
+        640, 480, 640, 480, 0, 0, 8, 0,
+        {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
+        0, 0, -1, -1, 0, 39721, 40, 24, 32, 11, 96, 2,
+        0, FB_VMODE_NONINTERLACED
+};
+
+/*
+ * IO macros
+ */
+
+#define INREG8(addr)		readb((rinfo->mmio_base)+addr)
+#define OUTREG8(addr,val)	writeb(val, (rinfo->mmio_base)+addr)
+#define INREG(addr)		readl((rinfo->mmio_base)+addr)
+#define OUTREG(addr,val)	writel(val, (rinfo->mmio_base)+addr)
+
+#define OUTPLL(addr,val)	\
+	do {	\
+		OUTREG8(CLOCK_CNTL_INDEX, (addr & 0x0000003f) | 0x00000080); \
+		OUTREG(CLOCK_CNTL_DATA, val); \
+	} while(0)
+
+#define OUTPLLP(addr,val,mask)  					\
+	do {								\
+		unsigned int _tmp = INPLL(addr);			\
+		_tmp &= (mask);						\
+		_tmp |= (val);						\
+		OUTPLL(addr, _tmp);					\
+	} while (0)
+
+#define OUTREGP(addr,val,mask)  					\
+	do {								\
+		unsigned int _tmp = INREG(addr);			\
+		_tmp &= (mask);						\
+		_tmp |= (val);						\
+		OUTREG(addr, _tmp);					\
+	} while (0)
+
+
+static __inline__ u32 _INPLL(struct radeonfb_info *rinfo, u32 addr)
+{
+	OUTREG8(CLOCK_CNTL_INDEX, addr & 0x0000003f);
+	return (INREG(CLOCK_CNTL_DATA));
+}
+
+#define INPLL(addr)		_INPLL(rinfo, addr)
+
+#define PRIMARY_MONITOR(rinfo)	((rinfo->dviDisp_type != MT_NONE) &&	\
+				 (rinfo->dviDisp_type != MT_STV) &&	\
+				 (rinfo->dviDisp_type != MT_CTV) ?	\
+				 rinfo->dviDisp_type : rinfo->crtDisp_type)
+
+static char *GET_MON_NAME(int type)
+{
+	char *pret = NULL;
+
+	switch (type) {
+		case MT_NONE:
+			pret = "no";
+			break;
+		case MT_CRT:
+			pret = "CRT";
+			break;
+		case MT_DFP:
+			pret = "DFP";
+			break;
+		case MT_LCD:
+			pret = "LCD";
+			break;
+		case MT_CTV:
+			pret = "CTV";
+			break;
+		case MT_STV:
+			pret = "STV";
+			break;
+	}
+
+	return pret;
+}
+
+
+/*
+ * 2D engine routines
+ */
+
+static __inline__ void radeon_engine_flush (struct radeonfb_info *rinfo)
+{
+	int i;
+
+	/* initiate flush */
+	OUTREGP(RB2D_DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL,
+	        ~RB2D_DC_FLUSH_ALL);
+
+	for (i=0; i < 2000000; i++) {
+		if (!(INREG(RB2D_DSTCACHE_CTLSTAT) & RB2D_DC_BUSY))
+			break;
+	}
+}
+
+
+static __inline__ void _radeon_fifo_wait (struct radeonfb_info *rinfo, int entries)
+{
+	int i;
+
+	for (i=0; i<2000000; i++)
+		if ((INREG(RBBM_STATUS) & 0x7f) >= entries)
+			return;
+}
+
+
+static __inline__ void _radeon_engine_idle (struct radeonfb_info *rinfo)
+{
+	int i;
+
+	/* ensure FIFO is empty before waiting for idle */
+	_radeon_fifo_wait (rinfo, 64);
+
+	for (i=0; i<2000000; i++) {
+		if (((INREG(RBBM_STATUS) & GUI_ACTIVE)) == 0) {
+			radeon_engine_flush (rinfo);
+			return;
+		}
+	}
+}
+
+
+#define radeon_engine_idle()		_radeon_engine_idle(rinfo)
+#define radeon_fifo_wait(entries)	_radeon_fifo_wait(rinfo,entries)
+
+
+
+/*
+ * helper routines
+ */
+
+static __inline__ u32 radeon_get_dstbpp(u16 depth)
+{
+	switch (depth) {
+		case 8:
+			return DST_8BPP;
+		case 15:
+			return DST_15BPP;
+		case 16:
+			return DST_16BPP;
+		case 32:
+			return DST_32BPP;
+		default:
+			return 0;
+	}
+}
+
+
+static inline int var_to_depth(const struct fb_var_screeninfo *var)
+{
+	if (var->bits_per_pixel != 16)
+		return var->bits_per_pixel;
+	return (var->green.length == 6) ? 16 : 15;
+}
+
+
+static void _radeon_engine_reset(struct radeonfb_info *rinfo)
+{
+	u32 clock_cntl_index, mclk_cntl, rbbm_soft_reset;
+
+	radeon_engine_flush (rinfo);
+
+	clock_cntl_index = INREG(CLOCK_CNTL_INDEX);
+	mclk_cntl = INPLL(MCLK_CNTL);
+
+	OUTPLL(MCLK_CNTL, (mclk_cntl |
+			   FORCEON_MCLKA |
+			   FORCEON_MCLKB |
+			   FORCEON_YCLKA |
+			   FORCEON_YCLKB |
+			   FORCEON_MC |
+			   FORCEON_AIC));
+	rbbm_soft_reset = INREG(RBBM_SOFT_RESET);
+
+	OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset |
+				SOFT_RESET_CP |
+				SOFT_RESET_HI |
+				SOFT_RESET_SE |
+				SOFT_RESET_RE |
+				SOFT_RESET_PP |
+				SOFT_RESET_E2 |
+				SOFT_RESET_RB);
+	INREG(RBBM_SOFT_RESET);
+	OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset & (u32)
+				~(SOFT_RESET_CP |
+				  SOFT_RESET_HI |
+				  SOFT_RESET_SE |
+				  SOFT_RESET_RE |
+				  SOFT_RESET_PP |
+				  SOFT_RESET_E2 |
+				  SOFT_RESET_RB));
+	INREG(RBBM_SOFT_RESET);
+
+	OUTPLL(MCLK_CNTL, mclk_cntl);
+	OUTREG(CLOCK_CNTL_INDEX, clock_cntl_index);
+	OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset);
+
+	return;
+}
+
+#define radeon_engine_reset()		_radeon_engine_reset(rinfo)
+
+
+static __inline__ int round_div(int num, int den)
+{
+        return (num + (den / 2)) / den;
+}
+
+
+
+static __inline__ int min_bits_req(int val)
+{
+        int bits_req = 0;
+                
+        if (val == 0)
+                bits_req = 1;
+                        
+        while (val) {
+                val >>= 1;
+                bits_req++;
+        }       
+
+        return (bits_req);
+}
+
+
+static __inline__ int _max(int val1, int val2)
+{
+        if (val1 >= val2)
+                return val1;
+        else
+                return val2;
+}                       
+
+
+
+/*
+ * globals
+ */
+
+#ifndef MODULE
+static char *mode_option;
+#endif
+
+static char noaccel = 0;
+static char mirror = 0;
+static int panel_yres = 0;
+static char force_dfp = 0;
+static struct radeonfb_info *board_list = NULL;
+static char nomtrr = 0;
+
+/*
+ * prototypes
+ */
+
+static void radeon_save_state (struct radeonfb_info *rinfo,
+                               struct radeon_regs *save);
+static void radeon_engine_init (struct radeonfb_info *rinfo);
+static void radeon_write_mode (struct radeonfb_info *rinfo,
+                               struct radeon_regs *mode);
+static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo);
+static int __devinit radeon_init_disp (struct radeonfb_info *rinfo);
+static int radeon_init_disp_var (struct radeonfb_info *rinfo, struct fb_var_screeninfo *var);
+static void __iomem *radeon_find_rom(struct radeonfb_info *rinfo);
+static void radeon_get_pllinfo(struct radeonfb_info *rinfo, void __iomem *bios_seg);
+static void radeon_get_moninfo (struct radeonfb_info *rinfo);
+static int radeon_get_dfpinfo (struct radeonfb_info *rinfo);
+static int radeon_get_dfpinfo_BIOS(struct radeonfb_info *rinfo);
+static void radeon_get_EDID(struct radeonfb_info *rinfo);
+static int radeon_dfp_parse_EDID(struct radeonfb_info *rinfo);
+static void radeon_update_default_var(struct radeonfb_info *rinfo);
+
+#ifdef CONFIG_PPC_OF
+
+static int radeon_read_OF (struct radeonfb_info *rinfo);
+static int radeon_get_EDID_OF(struct radeonfb_info *rinfo);
+extern struct device_node *pci_device_to_OF_node(struct pci_dev *dev);
+
+#ifdef CONFIG_PMAC_PBOOK
+int radeon_sleep_notify(struct pmu_sleep_notifier *self, int when);
+static struct pmu_sleep_notifier radeon_sleep_notifier = {
+	radeon_sleep_notify, SLEEP_LEVEL_VIDEO,
+};
+#endif /* CONFIG_PMAC_PBOOK */
+#ifdef CONFIG_PMAC_BACKLIGHT
+static int radeon_set_backlight_enable(int on, int level, void *data);
+static int radeon_set_backlight_level(int level, void *data);
+static struct backlight_controller radeon_backlight_controller = {
+	radeon_set_backlight_enable,
+	radeon_set_backlight_level
+};
+#endif /* CONFIG_PMAC_BACKLIGHT */
+
+#endif /* CONFIG_PPC_OF */
+
+
+static void __iomem *radeon_find_rom(struct radeonfb_info *rinfo)
+{       
+#if defined(__i386__)
+        u32  segstart;
+        char __iomem *rom_base;
+        char __iomem *rom;
+        int  stage;
+        int  i,j;       
+        char aty_rom_sig[] = "761295520";
+        char *radeon_sig[] = {
+          "RG6",
+          "RADEON"
+        };
+                                                
+        for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
+                        
+                stage = 1;
+                
+                rom_base = ioremap(segstart, 0x1000);
+
+                if ((*rom_base == 0x55) && (((*(rom_base + 1)) & 0xff) == 0xaa))
+                        stage = 2;
+                
+                    
+                if (stage != 2) {
+                        iounmap(rom_base);
+                        continue;
+                }
+                                              
+                rom = rom_base;
+                     
+                for (i = 0; (i < 128 - strlen(aty_rom_sig)) && (stage != 3); i++) {
+                        if (aty_rom_sig[0] == *rom)
+                                if (strncmp(aty_rom_sig, rom,
+                                                strlen(aty_rom_sig)) == 0)
+                                        stage = 3;
+                        rom++;
+                }
+                if (stage != 3) {
+                        iounmap(rom_base);
+                        continue;
+                }
+                rom = rom_base;
+        
+                for (i = 0; (i < 512) && (stage != 4); i++) {
+                    for(j = 0;j < sizeof(radeon_sig)/sizeof(char *);j++) {
+                        if (radeon_sig[j][0] == *rom)
+                                if (strncmp(radeon_sig[j], rom,
+                                            strlen(radeon_sig[j])) == 0) {
+                                              stage = 4;
+                                              break;
+                                            }
+                    }                           
+                        rom++;
+                }       
+                if (stage != 4) {
+                        iounmap(rom_base);
+                        continue;
+                }       
+                
+                return rom_base;
+        }
+#endif          
+        return NULL;
+}
+
+
+
+
+static void radeon_get_pllinfo(struct radeonfb_info *rinfo, void __iomem *bios_seg)
+{
+        void __iomem *bios_header;
+        void __iomem *header_ptr;
+        u16 bios_header_offset, pll_info_offset;
+        PLL_BLOCK pll;
+
+	if (bios_seg) {
+	        bios_header = bios_seg + 0x48L;
+       		header_ptr  = bios_header;
+        
+        	bios_header_offset = readw(header_ptr);
+	        bios_header = bios_seg + bios_header_offset;
+        	bios_header += 0x30;
+        
+        	header_ptr = bios_header;
+        	pll_info_offset = readw(header_ptr);
+        	header_ptr = bios_seg + pll_info_offset;
+        
+        	memcpy_fromio(&pll, header_ptr, 50);
+        
+        	rinfo->pll.xclk = (u32)pll.XCLK;
+        	rinfo->pll.ref_clk = (u32)pll.PCLK_ref_freq;
+        	rinfo->pll.ref_div = (u32)pll.PCLK_ref_divider;
+        	rinfo->pll.ppll_min = pll.PCLK_min_freq;
+        	rinfo->pll.ppll_max = pll.PCLK_max_freq;
+
+		printk("radeonfb: ref_clk=%d, ref_div=%d, xclk=%d from BIOS\n",
+			rinfo->pll.ref_clk, rinfo->pll.ref_div, rinfo->pll.xclk);
+	} else {
+#ifdef CONFIG_PPC_OF
+		if (radeon_read_OF(rinfo)) {
+			unsigned int tmp, Nx, M, ref_div, xclk;
+
+			tmp = INPLL(M_SPLL_REF_FB_DIV);
+			ref_div = INPLL(PPLL_REF_DIV) & 0x3ff;
+
+			Nx = (tmp & 0xff00) >> 8;
+			M = (tmp & 0xff);
+			xclk = ((((2 * Nx * rinfo->pll.ref_clk) + (M)) /
+				(2 * M)));
+
+			rinfo->pll.xclk = xclk;
+			rinfo->pll.ref_div = ref_div;
+			rinfo->pll.ppll_min = 12000;
+			rinfo->pll.ppll_max = 35000;
+
+			printk("radeonfb: ref_clk=%d, ref_div=%d, xclk=%d from OF\n",
+				rinfo->pll.ref_clk, rinfo->pll.ref_div, rinfo->pll.xclk);
+
+			return;
+		}
+#endif
+		/* no BIOS or BIOS not found, use defaults */
+		switch (rinfo->chipset) {
+			case PCI_DEVICE_ID_ATI_RADEON_QW:
+			case PCI_DEVICE_ID_ATI_RADEON_QX:
+				rinfo->pll.ppll_max = 35000;
+				rinfo->pll.ppll_min = 12000;
+				rinfo->pll.xclk = 23000;
+				rinfo->pll.ref_div = 12;
+				rinfo->pll.ref_clk = 2700;
+				break;
+			case PCI_DEVICE_ID_ATI_RADEON_QL:
+			case PCI_DEVICE_ID_ATI_RADEON_QN:
+			case PCI_DEVICE_ID_ATI_RADEON_QO:
+			case PCI_DEVICE_ID_ATI_RADEON_Ql:
+			case PCI_DEVICE_ID_ATI_RADEON_BB:
+				rinfo->pll.ppll_max = 35000;
+				rinfo->pll.ppll_min = 12000;
+				rinfo->pll.xclk = 27500;
+				rinfo->pll.ref_div = 12;
+				rinfo->pll.ref_clk = 2700;
+				break;
+			case PCI_DEVICE_ID_ATI_RADEON_Id:
+			case PCI_DEVICE_ID_ATI_RADEON_Ie:
+			case PCI_DEVICE_ID_ATI_RADEON_If:
+			case PCI_DEVICE_ID_ATI_RADEON_Ig:
+				rinfo->pll.ppll_max = 35000;
+				rinfo->pll.ppll_min = 12000;
+				rinfo->pll.xclk = 25000;
+				rinfo->pll.ref_div = 12;
+				rinfo->pll.ref_clk = 2700;
+				break;
+			case PCI_DEVICE_ID_ATI_RADEON_ND:
+			case PCI_DEVICE_ID_ATI_RADEON_NE:
+			case PCI_DEVICE_ID_ATI_RADEON_NF:
+			case PCI_DEVICE_ID_ATI_RADEON_NG:
+				rinfo->pll.ppll_max = 40000;
+				rinfo->pll.ppll_min = 20000;
+				rinfo->pll.xclk = 27000;
+				rinfo->pll.ref_div = 12;
+				rinfo->pll.ref_clk = 2700;
+				break;
+			case PCI_DEVICE_ID_ATI_RADEON_QD:
+			case PCI_DEVICE_ID_ATI_RADEON_QE:
+			case PCI_DEVICE_ID_ATI_RADEON_QF:
+			case PCI_DEVICE_ID_ATI_RADEON_QG:
+			default:
+				rinfo->pll.ppll_max = 35000;
+				rinfo->pll.ppll_min = 12000;
+				rinfo->pll.xclk = 16600;
+				rinfo->pll.ref_div = 67;
+				rinfo->pll.ref_clk = 2700;
+				break;
+		}
+
+		printk("radeonfb: ref_clk=%d, ref_div=%d, xclk=%d defaults\n",
+			rinfo->pll.ref_clk, rinfo->pll.ref_div, rinfo->pll.xclk);
+	}
+}
+
+
+static void radeon_get_moninfo (struct radeonfb_info *rinfo)
+{
+	unsigned int tmp;
+
+	if (force_dfp) {
+		rinfo->dviDisp_type = MT_DFP;
+		return;
+	}
+
+	tmp = INREG(BIOS_4_SCRATCH);
+	printk(KERN_DEBUG "radeon_get_moninfo: bios 4 scratch = %x\n", tmp);
+	
+	if (rinfo->hasCRTC2) {
+		/* primary DVI port */
+		if (tmp & 0x08)
+			rinfo->dviDisp_type = MT_DFP;
+		else if (tmp & 0x4)
+			rinfo->dviDisp_type = MT_LCD;
+		else if (tmp & 0x200)
+			rinfo->dviDisp_type = MT_CRT;
+		else if (tmp & 0x10)
+			rinfo->dviDisp_type = MT_CTV;
+		else if (tmp & 0x20)
+			rinfo->dviDisp_type = MT_STV;
+
+		/* secondary CRT port */
+		if (tmp & 0x2)
+			rinfo->crtDisp_type = MT_CRT;
+		else if (tmp & 0x800)
+			rinfo->crtDisp_type = MT_DFP;
+		else if (tmp & 0x400)
+			rinfo->crtDisp_type = MT_LCD;
+		else if (tmp & 0x1000)
+			rinfo->crtDisp_type = MT_CTV;
+		else if (tmp & 0x2000)
+			rinfo->crtDisp_type = MT_STV;
+	} else {
+		rinfo->dviDisp_type = MT_NONE;
+
+		tmp = INREG(FP_GEN_CNTL);
+
+		if (tmp & FP_EN_TMDS)
+			rinfo->crtDisp_type = MT_DFP;
+		else
+			rinfo->crtDisp_type = MT_CRT;
+	}
+}
+
+
+
+static void radeon_get_EDID(struct radeonfb_info *rinfo)
+{
+#ifdef CONFIG_PPC_OF
+	if (!radeon_get_EDID_OF(rinfo))
+		RTRACE("radeonfb: could not retrieve EDID from OF\n");
+#else
+	/* XXX use other methods later */
+#endif
+}
+
+
+#ifdef CONFIG_PPC_OF
+static int radeon_get_EDID_OF(struct radeonfb_info *rinfo)
+{
+        struct device_node *dp;
+        unsigned char *pedid = NULL;
+        static char *propnames[] = { "DFP,EDID", "LCD,EDID", "EDID", "EDID1", NULL };
+        int i;  
+
+        dp = pci_device_to_OF_node(rinfo->pdev);
+        while (dp != NULL) {
+                for (i = 0; propnames[i] != NULL; ++i) {
+                        pedid = (unsigned char *)
+                                get_property(dp, propnames[i], NULL);
+                        if (pedid != NULL) {
+                                rinfo->EDID = pedid;
+                                return 1;
+                        }
+                }
+                dp = dp->child;
+        }
+        return 0;
+}
+#endif /* CONFIG_PPC_OF */
+
+
+static int radeon_dfp_parse_EDID(struct radeonfb_info *rinfo)
+{
+	unsigned char *block = rinfo->EDID;
+
+	if (!block)
+		return 0;
+
+	/* jump to the detailed timing block section */
+	block += 54;
+
+	rinfo->clock = (block[0] + (block[1] << 8));
+	rinfo->panel_xres = (block[2] + ((block[4] & 0xf0) << 4));
+	rinfo->hblank = (block[3] + ((block[4] & 0x0f) << 8));
+	rinfo->panel_yres = (block[5] + ((block[7] & 0xf0) << 4));
+	rinfo->vblank = (block[6] + ((block[7] & 0x0f) << 8));
+	rinfo->hOver_plus = (block[8] + ((block[11] & 0xc0) << 2));
+	rinfo->hSync_width = (block[9] + ((block[11] & 0x30) << 4));
+	rinfo->vOver_plus = ((block[10] >> 4) + ((block[11] & 0x0c) << 2));
+	rinfo->vSync_width = ((block[10] & 0x0f) + ((block[11] & 0x03) << 4));
+	rinfo->interlaced = ((block[17] & 0x80) >> 7);
+	rinfo->synct = ((block[17] & 0x18) >> 3);
+	rinfo->misc = ((block[17] & 0x06) >> 1);
+	rinfo->hAct_high = rinfo->vAct_high = 0;
+	if (rinfo->synct == 3) {
+		if (rinfo->misc & 2)
+			rinfo->hAct_high = 1;
+		if (rinfo->misc & 1)
+			rinfo->vAct_high = 1;
+	}
+
+	printk("radeonfb: detected DFP panel size from EDID: %dx%d\n",
+		rinfo->panel_xres, rinfo->panel_yres);
+
+	rinfo->got_dfpinfo = 1;
+
+	return 1;
+}
+
+
+static void radeon_update_default_var(struct radeonfb_info *rinfo)
+{
+	struct fb_var_screeninfo *var = &radeonfb_default_var;
+
+	var->xres = rinfo->panel_xres;
+	var->yres = rinfo->panel_yres;
+	var->xres_virtual = rinfo->panel_xres;
+	var->yres_virtual = rinfo->panel_yres;
+	var->xoffset = var->yoffset = 0;
+	var->bits_per_pixel = 8;
+	var->pixclock = 100000000 / rinfo->clock;
+	var->left_margin = (rinfo->hblank - rinfo->hOver_plus - rinfo->hSync_width);
+	var->right_margin = rinfo->hOver_plus;
+	var->upper_margin = (rinfo->vblank - rinfo->vOver_plus - rinfo->vSync_width);
+	var->lower_margin = rinfo->vOver_plus;
+	var->hsync_len = rinfo->hSync_width;
+	var->vsync_len = rinfo->vSync_width;
+	var->sync = 0;
+	if (rinfo->synct == 3) {
+		if (rinfo->hAct_high)
+			var->sync |= FB_SYNC_HOR_HIGH_ACT;
+		if (rinfo->vAct_high)
+			var->sync |= FB_SYNC_VERT_HIGH_ACT;
+	}
+
+	var->vmode = 0;
+	if (rinfo->interlaced)
+		var->vmode |= FB_VMODE_INTERLACED;
+
+	rinfo->use_default_var = 1;
+}
+
+
+static int radeon_get_dfpinfo_BIOS(struct radeonfb_info *rinfo)
+{
+	char __iomem *fpbiosstart, *tmp, *tmp0;
+	char stmp[30];
+	int i;
+
+	if (!rinfo->bios_seg)
+		return 0;
+
+	if (!(fpbiosstart = rinfo->bios_seg + readw(rinfo->bios_seg + 0x48))) {
+		printk("radeonfb: Failed to detect DFP panel info using BIOS\n");
+		return 0;
+	}
+
+	if (!(tmp = rinfo->bios_seg + readw(fpbiosstart + 0x40))) {
+		printk("radeonfb: Failed to detect DFP panel info using BIOS\n");
+		return 0;
+	}
+
+	for(i=0; i<24; i++)
+		stmp[i] = readb(tmp+i+1);
+	stmp[24] = 0;
+	printk("radeonfb: panel ID string: %s\n", stmp);
+	rinfo->panel_xres = readw(tmp + 25);
+	rinfo->panel_yres = readw(tmp + 27);
+	printk("radeonfb: detected DFP panel size from BIOS: %dx%d\n",
+		rinfo->panel_xres, rinfo->panel_yres);
+
+	for(i=0; i<32; i++) {
+		tmp0 = rinfo->bios_seg + readw(tmp+64+i*2);
+		if (tmp0 == 0)
+			break;
+		if ((readw(tmp0) == rinfo->panel_xres) &&
+		    (readw(tmp0+2) == rinfo->panel_yres)) {
+			rinfo->hblank = (readw(tmp0+17) - readw(tmp0+19)) * 8;
+			rinfo->hOver_plus = ((readw(tmp0+21) - readw(tmp0+19) -1) * 8) & 0x7fff;
+			rinfo->hSync_width = readb(tmp0+23) * 8;
+			rinfo->vblank = readw(tmp0+24) - readw(tmp0+26);
+			rinfo->vOver_plus = (readw(tmp0+28) & 0x7ff) - readw(tmp0+26);
+			rinfo->vSync_width = (readw(tmp0+28) & 0xf800) >> 11;
+			rinfo->clock = readw(tmp0+9);
+
+			rinfo->got_dfpinfo = 1;
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+
+
+static int radeon_get_dfpinfo (struct radeonfb_info *rinfo)
+{
+	unsigned int tmp;
+	unsigned short a, b;
+
+	if (radeon_get_dfpinfo_BIOS(rinfo))
+		radeon_update_default_var(rinfo);
+
+	if (radeon_dfp_parse_EDID(rinfo))
+		radeon_update_default_var(rinfo);
+
+	if (!rinfo->got_dfpinfo) {
+		/*
+		 * it seems all else has failed now and we
+		 * resort to probing registers for our DFP info
+	         */
+		if (panel_yres) {
+			rinfo->panel_yres = panel_yres;
+		} else {
+			tmp = INREG(FP_VERT_STRETCH);
+			tmp &= 0x00fff000;
+			rinfo->panel_yres = (unsigned short)(tmp >> 0x0c) + 1;
+		}
+
+		switch (rinfo->panel_yres) {
+			case 480:
+				rinfo->panel_xres = 640;
+				break;
+			case 600:
+				rinfo->panel_xres = 800;
+				break;
+			case 768:
+#if defined(__powerpc__)
+				if (rinfo->dviDisp_type == MT_LCD)
+					rinfo->panel_xres = 1152;
+				else
+#endif
+				rinfo->panel_xres = 1024;
+				break;
+			case 1024:
+				rinfo->panel_xres = 1280;
+				break;
+			case 1050:
+				rinfo->panel_xres = 1400;
+				break;
+			case 1200:
+				rinfo->panel_xres = 1600;
+				break;
+			default:
+				printk("radeonfb: Failed to detect DFP panel size\n");
+				return 0;
+		}
+
+		printk("radeonfb: detected DFP panel size from registers: %dx%d\n",
+			rinfo->panel_xres, rinfo->panel_yres);
+
+		tmp = INREG(FP_CRTC_H_TOTAL_DISP);
+		a = (tmp & FP_CRTC_H_TOTAL_MASK) + 4;
+		b = (tmp & 0x01ff0000) >> FP_CRTC_H_DISP_SHIFT;
+		rinfo->hblank = (a - b + 1) * 8;
+
+		tmp = INREG(FP_H_SYNC_STRT_WID);
+		rinfo->hOver_plus = (unsigned short) ((tmp & FP_H_SYNC_STRT_CHAR_MASK) >>
+					FP_H_SYNC_STRT_CHAR_SHIFT) - b - 1;
+		rinfo->hOver_plus *= 8;
+		rinfo->hSync_width = (unsigned short) ((tmp & FP_H_SYNC_WID_MASK) >>
+					FP_H_SYNC_WID_SHIFT);
+		rinfo->hSync_width *= 8;
+		tmp = INREG(FP_CRTC_V_TOTAL_DISP);
+		a = (tmp & FP_CRTC_V_TOTAL_MASK) + 1;
+		b = (tmp & FP_CRTC_V_DISP_MASK) >> FP_CRTC_V_DISP_SHIFT;
+		rinfo->vblank = a - b /* + 24 */ ;
+
+		tmp = INREG(FP_V_SYNC_STRT_WID);
+		rinfo->vOver_plus = (unsigned short) (tmp & FP_V_SYNC_STRT_MASK)
+					- b + 1;
+		rinfo->vSync_width = (unsigned short) ((tmp & FP_V_SYNC_WID_MASK) >>
+					FP_V_SYNC_WID_SHIFT);
+
+		return 1;
+	}
+
+	return 1;
+}
+
+
+#ifdef CONFIG_PPC_OF
+static int radeon_read_OF (struct radeonfb_info *rinfo)
+{
+	struct device_node *dp;
+	unsigned int *xtal;
+
+	dp = pci_device_to_OF_node(rinfo->pdev);
+
+	xtal = (unsigned int *) get_property(dp, "ATY,RefCLK", NULL);
+
+	rinfo->pll.ref_clk = *xtal / 10;
+
+	if (*xtal)
+		return 1;
+	else
+		return 0;
+}
+#endif	
+
+
+static void radeon_engine_init (struct radeonfb_info *rinfo)
+{
+	u32 temp;
+
+	/* disable 3D engine */
+	OUTREG(RB3D_CNTL, 0);
+
+	radeon_engine_reset ();
+
+	radeon_fifo_wait (1);
+	OUTREG(RB2D_DSTCACHE_MODE, 0);
+
+	radeon_fifo_wait (1);
+	temp = INREG(DEFAULT_PITCH_OFFSET);
+	OUTREG(DEFAULT_PITCH_OFFSET, ((temp & 0xc0000000) | 
+				      (rinfo->pitch << 0x16)));
+
+	radeon_fifo_wait (1);
+	OUTREGP(DP_DATATYPE, 0, ~HOST_BIG_ENDIAN_EN);
+
+	radeon_fifo_wait (1);
+	OUTREG(DEFAULT_SC_BOTTOM_RIGHT, (DEFAULT_SC_RIGHT_MAX |
+					 DEFAULT_SC_BOTTOM_MAX));
+
+	temp = radeon_get_dstbpp(rinfo->depth);
+	rinfo->dp_gui_master_cntl = ((temp << 8) | GMC_CLR_CMP_CNTL_DIS);
+	radeon_fifo_wait (1);
+	OUTREG(DP_GUI_MASTER_CNTL, (rinfo->dp_gui_master_cntl |
+				    GMC_BRUSH_SOLID_COLOR |
+				    GMC_SRC_DATATYPE_COLOR));
+
+	radeon_fifo_wait (7);
+
+	/* clear line drawing regs */
+	OUTREG(DST_LINE_START, 0);
+	OUTREG(DST_LINE_END, 0);
+
+	/* set brush color regs */
+	OUTREG(DP_BRUSH_FRGD_CLR, 0xffffffff);
+	OUTREG(DP_BRUSH_BKGD_CLR, 0x00000000);
+
+	/* set source color regs */
+	OUTREG(DP_SRC_FRGD_CLR, 0xffffffff);
+	OUTREG(DP_SRC_BKGD_CLR, 0x00000000);
+
+	/* default write mask */
+	OUTREG(DP_WRITE_MSK, 0xffffffff);
+
+	radeon_engine_idle ();
+}
+
+
+static int __devinit radeon_init_disp (struct radeonfb_info *rinfo)
+{
+        struct fb_info *info = &rinfo->info;
+	struct fb_var_screeninfo var;
+
+        var = radeonfb_default_var;
+        if ((radeon_init_disp_var(rinfo, &var)) < 0)
+                return -1;
+
+	rinfo->depth = var_to_depth(&var);
+	rinfo->bpp = var.bits_per_pixel;
+        
+	info->var = var;
+	fb_alloc_cmap(&info->cmap, 256, 0);
+
+	var.activate = FB_ACTIVATE_NOW;
+        return 0;
+}
+
+
+static int radeon_init_disp_var (struct radeonfb_info *rinfo,
+				 struct fb_var_screeninfo *var)
+{
+#ifndef MODULE
+        if (mode_option)
+                fb_find_mode (var, &rinfo->info, mode_option,
+                              NULL, 0, NULL, 8);
+        else
+#endif
+	if (rinfo->use_default_var)
+		/* We will use the modified default far */
+		*var = radeonfb_default_var;
+	else
+
+                fb_find_mode (var, &rinfo->info, "640x480-8@60",
+                              NULL, 0, NULL, 0);
+
+	if (noaccel)
+		var->accel_flags &= ~FB_ACCELF_TEXT;
+	else
+		var->accel_flags |= FB_ACCELF_TEXT;
+ 
+        return 0;
+}
+
+
+static int radeon_do_maximize(struct radeonfb_info *rinfo,
+                                struct fb_var_screeninfo *var,
+                                struct fb_var_screeninfo *v,
+                                int nom, int den)
+{
+        static struct {
+                int xres, yres;
+        } modes[] = {
+                {1600, 1280},
+                {1280, 1024},
+                {1024, 768},
+                {800, 600},
+                {640, 480},
+                {-1, -1}
+        };
+        int i;
+  
+        /* use highest possible virtual resolution */
+        if (v->xres_virtual == -1 && v->yres_virtual == -1) {
+                printk("radeonfb: using max available virtual resolution\n");
+                for (i=0; modes[i].xres != -1; i++) {
+                        if (modes[i].xres * nom / den * modes[i].yres <
+                            rinfo->video_ram / 2)
+                                break;
+                }
+                if (modes[i].xres == -1) {
+                        printk("radeonfb: could not find virtual resolution that fits into video memory!\n");
+                        return -EINVAL;
+                }
+                v->xres_virtual = modes[i].xres;  
+                v->yres_virtual = modes[i].yres;
+                
+                printk("radeonfb: virtual resolution set to max of %dx%d\n",
+                        v->xres_virtual, v->yres_virtual);
+        } else if (v->xres_virtual == -1) {
+                v->xres_virtual = (rinfo->video_ram * den /   
+                                (nom * v->yres_virtual * 2)) & ~15;
+        } else if (v->yres_virtual == -1) {
+                v->xres_virtual = (v->xres_virtual + 15) & ~15;
+                v->yres_virtual = rinfo->video_ram * den /
+                        (nom * v->xres_virtual *2);
+        } else {
+                if (v->xres_virtual * nom / den * v->yres_virtual >
+                        rinfo->video_ram) {
+                        return -EINVAL;
+                }
+        }
+                
+        if (v->xres_virtual * nom / den >= 8192) {
+                v->xres_virtual = 8192 * den / nom - 16;
+        }       
+        
+        if (v->xres_virtual < v->xres)
+                return -EINVAL;
+                
+        if (v->yres_virtual < v->yres)
+                return -EINVAL;
+                                
+        return 0;
+}
+
+
+static int radeonfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info)
+{
+        struct radeonfb_info *rinfo = (struct radeonfb_info *) info->par;
+        struct fb_var_screeninfo v;
+        int nom, den;
+
+        memcpy (&v, var, sizeof (v));
+
+        switch (v.bits_per_pixel) {
+		case 0 ... 8:
+			v.bits_per_pixel = 8;
+			break;
+		case 9 ... 16:
+			v.bits_per_pixel = 16;
+			break;
+		case 17 ... 24:
+#if 0 /* Doesn't seem to work */
+			v.bits_per_pixel = 24;
+			break;
+#endif			
+			return -EINVAL;
+		case 25 ... 32:
+			v.bits_per_pixel = 32;
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	switch (var_to_depth(&v)) {
+                case 8:
+                        nom = den = 1;
+                        v.red.offset = v.green.offset = v.blue.offset = 0;
+                        v.red.length = v.green.length = v.blue.length = 8;
+                        v.transp.offset = v.transp.length = 0;
+                        break;
+		case 15:
+			nom = 2;
+			den = 1;
+			v.red.offset = 10;
+			v.green.offset = 5;
+			v.blue.offset = 0;
+			v.red.length = v.green.length = v.blue.length = 5;
+			v.transp.offset = v.transp.length = 0;
+			break;
+                case 16:
+                        nom = 2;
+                        den = 1;
+                        v.red.offset = 11;
+                        v.green.offset = 5;
+                        v.blue.offset = 0;
+                        v.red.length = 5;
+                        v.green.length = 6;
+                        v.blue.length = 5;
+                        v.transp.offset = v.transp.length = 0;
+                        break;                          
+                case 24:
+                        nom = 4;
+                        den = 1;
+                        v.red.offset = 16;
+                        v.green.offset = 8;
+                        v.blue.offset = 0;
+                        v.red.length = v.blue.length = v.green.length = 8;
+                        v.transp.offset = v.transp.length = 0;
+                        break;
+                case 32:
+                        nom = 4;
+                        den = 1;
+                        v.red.offset = 16;
+                        v.green.offset = 8;
+                        v.blue.offset = 0;
+                        v.red.length = v.blue.length = v.green.length = 8;
+                        v.transp.offset = 24;
+                        v.transp.length = 8;
+                        break;
+                default:
+                        printk ("radeonfb: mode %dx%dx%d rejected, color depth invalid\n",
+                                var->xres, var->yres, var->bits_per_pixel);
+                        return -EINVAL;
+        }
+
+        if (radeon_do_maximize(rinfo, var, &v, nom, den) < 0)
+                return -EINVAL;  
+                
+        if (v.xoffset < 0)
+                v.xoffset = 0;
+        if (v.yoffset < 0)
+                v.yoffset = 0;
+         
+        if (v.xoffset > v.xres_virtual - v.xres)
+                v.xoffset = v.xres_virtual - v.xres - 1;
+                        
+        if (v.yoffset > v.yres_virtual - v.yres)
+                v.yoffset = v.yres_virtual - v.yres - 1;
+         
+        v.red.msb_right = v.green.msb_right = v.blue.msb_right =
+                          v.transp.offset = v.transp.length =
+                          v.transp.msb_right = 0;
+
+	if (noaccel)
+		v.accel_flags = 0;
+			
+        memcpy(var, &v, sizeof(v));
+        
+        return 0;
+}
+
+
+static int radeonfb_pan_display (struct fb_var_screeninfo *var,
+                                 struct fb_info *info)
+{
+        struct radeonfb_info *rinfo = (struct radeonfb_info *) info;
+
+        if ((var->xoffset + var->xres > var->xres_virtual)
+	    || (var->yoffset + var->yres > var->yres_virtual))
+               return -EINVAL;
+                
+        if (rinfo->asleep)
+        	return 0;
+
+        OUTREG(CRTC_OFFSET, ((var->yoffset * var->xres_virtual + var->xoffset)
+			     * var->bits_per_pixel / 8) & ~7);
+        return 0;
+}
+
+
+static int radeonfb_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
+                           unsigned long arg, struct fb_info *info)
+{
+        struct radeonfb_info *rinfo = (struct radeonfb_info *) info;
+	unsigned int tmp;
+	u32 value = 0;
+	int rc;
+
+	switch (cmd) {
+		/*
+		 * TODO:  set mirror accordingly for non-Mobility chipsets with 2 CRTC's
+		 */
+		case FBIO_RADEON_SET_MIRROR:
+			switch (rinfo->arch) {
+				case RADEON_R100:
+				case RADEON_RV100:
+				case RADEON_R200:
+				case RADEON_RV200:
+				case RADEON_RV250:
+				case RADEON_R300:
+					return -EINVAL;
+				default:
+					/* RADEON M6, RADEON_M7, RADEON_M9 */
+					break;
+			}
+
+			rc = get_user(value, (__u32 __user *)arg);
+
+			if (rc)
+				return rc;
+
+			if (value & 0x01) {
+				tmp = INREG(LVDS_GEN_CNTL);
+
+				tmp |= (LVDS_ON | LVDS_BLON);
+			} else {
+				tmp = INREG(LVDS_GEN_CNTL);
+
+				tmp &= ~(LVDS_ON | LVDS_BLON);
+			}
+
+			OUTREG(LVDS_GEN_CNTL, tmp);
+
+			if (value & 0x02) {
+				tmp = INREG(CRTC_EXT_CNTL);
+				tmp |= CRTC_CRT_ON;
+
+				mirror = 1;
+			} else {
+				tmp = INREG(CRTC_EXT_CNTL);
+				tmp &= ~CRTC_CRT_ON;
+
+				mirror = 0;
+			}
+
+			OUTREG(CRTC_EXT_CNTL, tmp);
+
+			break;
+		case FBIO_RADEON_GET_MIRROR:
+			switch (rinfo->arch) {
+				case RADEON_R100:
+				case RADEON_RV100:
+				case RADEON_R200:
+				case RADEON_RV200:
+				case RADEON_RV250:
+				case RADEON_R300:
+					return -EINVAL;
+				default:
+					/* RADEON M6, RADEON_M7, RADEON_M9 */
+					break;
+			}
+
+			tmp = INREG(LVDS_GEN_CNTL);
+			if ((LVDS_ON | LVDS_BLON) & tmp)
+				value |= 0x01;
+
+			tmp = INREG(CRTC_EXT_CNTL);
+			if (CRTC_CRT_ON & tmp)
+				value |= 0x02;
+
+			return put_user(value, (__u32 __user *)arg);
+		default:
+			return -EINVAL;
+	}
+
+	return -EINVAL;
+}
+
+
+static int radeonfb_blank (int blank, struct fb_info *info)
+{
+        struct radeonfb_info *rinfo = (struct radeonfb_info *) info;
+        u32 val = INREG(CRTC_EXT_CNTL);
+	u32 val2 = INREG(LVDS_GEN_CNTL);
+
+	if (rinfo->asleep)
+		return 0;
+		
+#ifdef CONFIG_PMAC_BACKLIGHT
+	if (rinfo->dviDisp_type == MT_LCD && _machine == _MACH_Pmac) {
+		set_backlight_enable(!blank);
+		return 0;
+	}
+#endif
+                        
+        /* reset it */
+        val &= ~(CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS |
+                 CRTC_VSYNC_DIS);
+	val2 &= ~(LVDS_DISPLAY_DIS);
+
+        switch (blank) {
+	        case FB_BLANK_UNBLANK:
+	        case FB_BLANK_NORMAL:
+                        break;
+                case FB_BLANK_VSYNC_SUSPEND:
+                        val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS);
+                        break;
+                case FB_BLANK_HSYNC_SUSPEND:
+                        val |= (CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS);
+                        break;
+                case FB_BLANK_POWERDOWN:
+                        val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS | 
+                                CRTC_HSYNC_DIS);
+			val2 |= (LVDS_DISPLAY_DIS);
+                        break;
+        }
+
+	switch (rinfo->dviDisp_type) {
+		case MT_LCD:
+			OUTREG(LVDS_GEN_CNTL, val2);
+			break;
+		case MT_CRT:
+		default:
+		        OUTREG(CRTC_EXT_CNTL, val);
+			break;
+	}
+
+	/* let fbcon do a soft blank for us */
+	return (blank == FB_BLANK_NORMAL) ? 1 : 0;
+}
+
+
+static int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green,
+                             unsigned blue, unsigned transp, struct fb_info *info)
+{
+        struct radeonfb_info *rinfo = (struct radeonfb_info *) info;
+	u32 pindex, vclk_cntl;
+	unsigned int i;
+	
+	if (regno > 255)
+		return 1;
+
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+	rinfo->palette[regno].red = red;
+	rinfo->palette[regno].green = green;
+	rinfo->palette[regno].blue = blue;
+
+        /* default */
+        pindex = regno;
+
+        if (!rinfo->asleep) {
+		vclk_cntl = INPLL(VCLK_ECP_CNTL);
+		OUTPLL(VCLK_ECP_CNTL, vclk_cntl & ~PIXCLK_DAC_ALWAYS_ONb);
+
+		if (rinfo->bpp == 16) {
+			pindex = regno * 8;
+
+			if (rinfo->depth == 16 && regno > 63)
+				return 1;
+			if (rinfo->depth == 15 && regno > 31)
+				return 1;
+
+			/* For 565, the green component is mixed one order below */
+			if (rinfo->depth == 16) {
+		                OUTREG(PALETTE_INDEX, pindex>>1);
+	       	         	OUTREG(PALETTE_DATA, (rinfo->palette[regno>>1].red << 16) |
+	                        	(green << 8) | (rinfo->palette[regno>>1].blue));
+	                	green = rinfo->palette[regno<<1].green;
+	        	}
+		}
+
+		if (rinfo->depth != 16 || regno < 32) {
+			OUTREG(PALETTE_INDEX, pindex);
+			OUTREG(PALETTE_DATA, (red << 16) | (green << 8) | blue);
+		}
+
+		OUTPLL(VCLK_ECP_CNTL, vclk_cntl);
+	}
+ 	if (regno < 16) {
+        	switch (rinfo->depth) {
+		case 15:
+			((u16 *) (info->pseudo_palette))[regno] =
+			    (regno << 10) | (regno << 5) | regno;
+			break;
+		case 16:
+			((u16 *) (info->pseudo_palette))[regno] =
+			    (regno << 11) | (regno << 6) | regno;
+			break;
+		case 24:
+			((u32 *) (info->pseudo_palette))[regno] =
+			    (regno << 16) | (regno << 8) | regno;
+			break;
+		case 32:
+			i = (regno << 8) | regno;
+			((u32 *) (info->pseudo_palette))[regno] =
+			    (i << 16) | i;
+			break;
+		}
+        }
+	return 0;
+}
+
+
+
+static void radeon_save_state (struct radeonfb_info *rinfo,
+                               struct radeon_regs *save)
+{
+	/* CRTC regs */
+	save->crtc_gen_cntl = INREG(CRTC_GEN_CNTL);
+	save->crtc_ext_cntl = INREG(CRTC_EXT_CNTL);
+	save->dac_cntl = INREG(DAC_CNTL);
+        save->crtc_h_total_disp = INREG(CRTC_H_TOTAL_DISP);
+        save->crtc_h_sync_strt_wid = INREG(CRTC_H_SYNC_STRT_WID);
+        save->crtc_v_total_disp = INREG(CRTC_V_TOTAL_DISP);
+        save->crtc_v_sync_strt_wid = INREG(CRTC_V_SYNC_STRT_WID);
+	save->crtc_pitch = INREG(CRTC_PITCH);
+#if defined(__BIG_ENDIAN)
+	save->surface_cntl = INREG(SURFACE_CNTL);
+#endif
+
+	/* FP regs */
+	save->fp_crtc_h_total_disp = INREG(FP_CRTC_H_TOTAL_DISP);
+	save->fp_crtc_v_total_disp = INREG(FP_CRTC_V_TOTAL_DISP);
+	save->fp_gen_cntl = INREG(FP_GEN_CNTL);
+	save->fp_h_sync_strt_wid = INREG(FP_H_SYNC_STRT_WID);
+	save->fp_horz_stretch = INREG(FP_HORZ_STRETCH);
+	save->fp_v_sync_strt_wid = INREG(FP_V_SYNC_STRT_WID);
+	save->fp_vert_stretch = INREG(FP_VERT_STRETCH);
+	save->lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
+	save->lvds_pll_cntl = INREG(LVDS_PLL_CNTL);
+	save->tmds_crc = INREG(TMDS_CRC);
+	save->tmds_transmitter_cntl = INREG(TMDS_TRANSMITTER_CNTL);
+	save->vclk_ecp_cntl = INPLL(VCLK_ECP_CNTL);
+}
+
+
+
+static int radeonfb_set_par (struct fb_info *info)
+{
+	struct radeonfb_info *rinfo = (struct radeonfb_info *)info->par;
+	struct fb_var_screeninfo *mode = &info->var;
+	struct radeon_regs newmode;
+	int hTotal, vTotal, hSyncStart, hSyncEnd,
+	    hSyncPol, vSyncStart, vSyncEnd, vSyncPol, cSync;
+	u8 hsync_adj_tab[] = {0, 0x12, 9, 9, 6, 5};
+	u8 hsync_fudge_fp[] = {2, 2, 0, 0, 5, 5};
+	u32 dotClock = 1000000000 / mode->pixclock,
+	    sync, h_sync_pol, v_sync_pol;
+	int freq = dotClock / 10;  /* x 100 */
+        int xclk_freq, vclk_freq, xclk_per_trans, xclk_per_trans_precise;
+        int useable_precision, roff, ron;
+        int min_bits, format = 0;
+	int hsync_start, hsync_fudge, bytpp, hsync_wid, vsync_wid;
+	int primary_mon = PRIMARY_MONITOR(rinfo);
+	int depth = var_to_depth(mode);
+        int accel = (mode->accel_flags & FB_ACCELF_TEXT) != 0;
+
+	rinfo->xres = mode->xres;
+	rinfo->yres = mode->yres;
+	rinfo->xres_virtual = mode->xres_virtual;
+	rinfo->yres_virtual = mode->yres_virtual;
+	rinfo->pixclock = mode->pixclock;
+
+	hSyncStart = mode->xres + mode->right_margin;
+	hSyncEnd = hSyncStart + mode->hsync_len;
+	hTotal = hSyncEnd + mode->left_margin;
+
+	vSyncStart = mode->yres + mode->lower_margin;
+	vSyncEnd = vSyncStart + mode->vsync_len;
+	vTotal = vSyncEnd + mode->upper_margin;
+
+	if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {
+		if (rinfo->panel_xres < mode->xres)
+			rinfo->xres = mode->xres = rinfo->panel_xres;
+		if (rinfo->panel_yres < mode->yres)
+			rinfo->yres = mode->yres = rinfo->panel_yres;
+
+		hTotal = mode->xres + rinfo->hblank;
+		hSyncStart = mode->xres + rinfo->hOver_plus;
+		hSyncEnd = hSyncStart + rinfo->hSync_width;
+
+		vTotal = mode->yres + rinfo->vblank;
+		vSyncStart = mode->yres + rinfo->vOver_plus;
+		vSyncEnd = vSyncStart + rinfo->vSync_width;
+	}
+
+	sync = mode->sync;
+	h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
+	v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;
+
+	RTRACE("hStart = %d, hEnd = %d, hTotal = %d\n",
+		hSyncStart, hSyncEnd, hTotal);
+	RTRACE("vStart = %d, vEnd = %d, vTotal = %d\n",
+		vSyncStart, vSyncEnd, vTotal);
+
+	hsync_wid = (hSyncEnd - hSyncStart) / 8;
+	vsync_wid = vSyncEnd - vSyncStart;
+	if (hsync_wid == 0)
+		hsync_wid = 1;
+	else if (hsync_wid > 0x3f)	/* max */
+		hsync_wid = 0x3f;
+
+	if (vsync_wid == 0)
+		vsync_wid = 1;
+	else if (vsync_wid > 0x1f)	/* max */
+		vsync_wid = 0x1f;
+
+	hSyncPol = mode->sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
+	vSyncPol = mode->sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;
+
+	cSync = mode->sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0;
+
+	format = radeon_get_dstbpp(depth);
+	bytpp = mode->bits_per_pixel >> 3;
+
+	if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD))
+		hsync_fudge = hsync_fudge_fp[format-1];
+	else
+		hsync_fudge = hsync_adj_tab[format-1];
+
+	hsync_start = hSyncStart - 8 + hsync_fudge;
+
+	newmode.crtc_gen_cntl = CRTC_EXT_DISP_EN | CRTC_EN |
+				(format << 8);
+
+	if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {
+		newmode.crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN;
+		if (mirror)
+			newmode.crtc_ext_cntl |= CRTC_CRT_ON;
+
+		newmode.crtc_gen_cntl &= ~(CRTC_DBL_SCAN_EN |
+					   CRTC_INTERLACE_EN);
+	} else {
+		newmode.crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN |
+					CRTC_CRT_ON;
+	}
+
+	newmode.dac_cntl = /* INREG(DAC_CNTL) | */ DAC_MASK_ALL | DAC_VGA_ADR_EN |
+			   DAC_8BIT_EN;
+
+	newmode.crtc_h_total_disp = ((((hTotal / 8) - 1) & 0x3ff) |
+				     (((mode->xres / 8) - 1) << 16));
+
+	newmode.crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) |
+					(hsync_wid << 16) | (h_sync_pol << 23));
+
+	newmode.crtc_v_total_disp = ((vTotal - 1) & 0xffff) |
+				    ((mode->yres - 1) << 16);
+
+	newmode.crtc_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff) |
+					 (vsync_wid << 16) | (v_sync_pol  << 23));
+
+	if (accel) {
+		/* We first calculate the engine pitch */
+		rinfo->pitch = ((mode->xres_virtual * ((mode->bits_per_pixel + 1) / 8) + 0x3f)
+ 				& ~(0x3f)) >> 6;
+
+		/* Then, re-multiply it to get the CRTC pitch */
+		newmode.crtc_pitch = (rinfo->pitch << 3) / ((mode->bits_per_pixel + 1) / 8);
+	} else
+		newmode.crtc_pitch = (mode->xres_virtual >> 3);
+	newmode.crtc_pitch |= (newmode.crtc_pitch << 16);
+
+#if defined(__BIG_ENDIAN)
+	/*
+	 * It looks like recent chips have a problem with SURFACE_CNTL,
+	 * setting SURF_TRANSLATION_DIS completely disables the
+	 * swapper as well, so we leave it unset now.
+	 */
+	newmode.surface_cntl = 0;
+
+	/* Setup swapping on both apertures, though we currently
+	 * only use aperture 0, enabling swapper on aperture 1
+	 * won't harm
+	 */
+	switch (mode->bits_per_pixel) {
+		case 16:
+			newmode.surface_cntl |= NONSURF_AP0_SWP_16BPP;
+			newmode.surface_cntl |= NONSURF_AP1_SWP_16BPP;
+			break;
+		case 24:	
+		case 32:
+			newmode.surface_cntl |= NONSURF_AP0_SWP_32BPP;
+			newmode.surface_cntl |= NONSURF_AP1_SWP_32BPP;
+			break;
+	}
+#endif
+
+	rinfo->pitch = ((mode->xres_virtual * ((mode->bits_per_pixel + 1) / 8) + 0x3f)
+ 			& ~(0x3f)) / 64;
+
+	RTRACE("h_total_disp = 0x%x\t   hsync_strt_wid = 0x%x\n",
+		newmode.crtc_h_total_disp, newmode.crtc_h_sync_strt_wid);
+	RTRACE("v_total_disp = 0x%x\t   vsync_strt_wid = 0x%x\n",
+		newmode.crtc_v_total_disp, newmode.crtc_v_sync_strt_wid);
+
+	newmode.xres = mode->xres;
+	newmode.yres = mode->yres;
+
+	rinfo->bpp = mode->bits_per_pixel;
+	rinfo->depth = depth;
+
+	if (freq > rinfo->pll.ppll_max)
+		freq = rinfo->pll.ppll_max;
+	if (freq*12 < rinfo->pll.ppll_min)
+		freq = rinfo->pll.ppll_min / 12;
+
+	{
+		struct {
+			int divider;
+			int bitvalue;
+		} *post_div,
+		  post_divs[] = {
+			{ 1,  0 },
+			{ 2,  1 },
+			{ 4,  2 },
+			{ 8,  3 },
+			{ 3,  4 },
+			{ 16, 5 },
+			{ 6,  6 },
+			{ 12, 7 },
+			{ 0,  0 },
+		};
+
+		for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
+			rinfo->pll_output_freq = post_div->divider * freq;
+			if (rinfo->pll_output_freq >= rinfo->pll.ppll_min  &&
+			    rinfo->pll_output_freq <= rinfo->pll.ppll_max)
+				break;
+		}
+
+		rinfo->post_div = post_div->divider;
+		rinfo->fb_div = round_div(rinfo->pll.ref_div*rinfo->pll_output_freq,
+					  rinfo->pll.ref_clk);
+		newmode.ppll_ref_div = rinfo->pll.ref_div;
+		newmode.ppll_div_3 = rinfo->fb_div | (post_div->bitvalue << 16);
+	}
+	newmode.vclk_ecp_cntl = rinfo->init_state.vclk_ecp_cntl;
+
+#ifdef CONFIG_PPC_OF
+	/* Gross hack for iBook with M7 until I find out a proper fix */
+	if (machine_is_compatible("PowerBook4,3") && rinfo->arch == RADEON_M7)
+		newmode.ppll_div_3 = 0x000600ad;
+#endif /* CONFIG_PPC_OF */	
+
+	RTRACE("post div = 0x%x\n", rinfo->post_div);
+	RTRACE("fb_div = 0x%x\n", rinfo->fb_div);
+	RTRACE("ppll_div_3 = 0x%x\n", newmode.ppll_div_3);
+
+	/* DDA */
+	vclk_freq = round_div(rinfo->pll.ref_clk * rinfo->fb_div,
+			      rinfo->pll.ref_div * rinfo->post_div);
+	xclk_freq = rinfo->pll.xclk;
+
+	xclk_per_trans = round_div(xclk_freq * 128, vclk_freq * mode->bits_per_pixel);
+
+	min_bits = min_bits_req(xclk_per_trans);
+	useable_precision = min_bits + 1;
+
+	xclk_per_trans_precise = round_div((xclk_freq * 128) << (11 - useable_precision),
+					   vclk_freq * mode->bits_per_pixel);
+
+	ron = (4 * rinfo->ram.mb + 3 * _max(rinfo->ram.trcd - 2, 0) +
+	       2 * rinfo->ram.trp + rinfo->ram.twr + rinfo->ram.cl + rinfo->ram.tr2w +
+	       xclk_per_trans) << (11 - useable_precision);
+	roff = xclk_per_trans_precise * (32 - 4);
+
+	RTRACE("ron = %d, roff = %d\n", ron, roff);
+	RTRACE("vclk_freq = %d, per = %d\n", vclk_freq, xclk_per_trans_precise);
+
+	if ((ron + rinfo->ram.rloop) >= roff) {
+		printk("radeonfb: error ron out of range\n");
+		return -EINVAL;
+	}
+
+	newmode.dda_config = (xclk_per_trans_precise |
+			      (useable_precision << 16) |
+			      (rinfo->ram.rloop << 20));
+	newmode.dda_on_off = (ron << 16) | roff;
+
+	if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {
+		unsigned int hRatio, vRatio;
+
+		/* We force the pixel clock to be always enabled. Allowing it
+		 * to be power managed during blanking would save power, but has
+		 * nasty interactions with the 2D engine & sleep code that haven't
+		 * been solved yet. --BenH
+		 */
+		newmode.vclk_ecp_cntl &= ~PIXCLK_DAC_ALWAYS_ONb;
+		
+		if (mode->xres > rinfo->panel_xres)
+			mode->xres = rinfo->panel_xres;
+		if (mode->yres > rinfo->panel_yres)
+			mode->yres = rinfo->panel_yres;
+
+		newmode.fp_horz_stretch = (((rinfo->panel_xres / 8) - 1)
+					   << HORZ_PANEL_SHIFT);
+		newmode.fp_vert_stretch = ((rinfo->panel_yres - 1)
+					   << VERT_PANEL_SHIFT);
+
+		if (mode->xres != rinfo->panel_xres) {
+			hRatio = round_div(mode->xres * HORZ_STRETCH_RATIO_MAX,
+					   rinfo->panel_xres);
+			newmode.fp_horz_stretch = (((((unsigned long)hRatio) & HORZ_STRETCH_RATIO_MASK)) |
+						   (newmode.fp_horz_stretch &
+						    (HORZ_PANEL_SIZE | HORZ_FP_LOOP_STRETCH |
+						     HORZ_AUTO_RATIO_INC)));
+			newmode.fp_horz_stretch |= (HORZ_STRETCH_BLEND |
+						    HORZ_STRETCH_ENABLE);
+		}
+		newmode.fp_horz_stretch &= ~HORZ_AUTO_RATIO;
+
+		if (mode->yres != rinfo->panel_yres) {
+			vRatio = round_div(mode->yres * VERT_STRETCH_RATIO_MAX,
+					   rinfo->panel_yres);
+			newmode.fp_vert_stretch = (((((unsigned long)vRatio) & VERT_STRETCH_RATIO_MASK)) |
+						   (newmode.fp_vert_stretch &
+						   (VERT_PANEL_SIZE | VERT_STRETCH_RESERVED)));
+			newmode.fp_vert_stretch |= (VERT_STRETCH_BLEND |
+						    VERT_STRETCH_ENABLE);
+		}
+		newmode.fp_vert_stretch &= ~VERT_AUTO_RATIO_EN;
+
+		newmode.fp_gen_cntl = (rinfo->init_state.fp_gen_cntl & (u32)
+				       ~(FP_SEL_CRTC2 |
+					 FP_RMX_HVSYNC_CONTROL_EN |
+					 FP_DFP_SYNC_SEL |
+					 FP_CRT_SYNC_SEL |
+					 FP_CRTC_LOCK_8DOT |
+					 FP_USE_SHADOW_EN |
+					 FP_CRTC_USE_SHADOW_VEND |
+					 FP_CRT_SYNC_ALT));
+
+		newmode.fp_gen_cntl |= (FP_CRTC_DONT_SHADOW_VPAR |
+					FP_CRTC_DONT_SHADOW_HEND);
+
+		newmode.lvds_gen_cntl = rinfo->init_state.lvds_gen_cntl;
+		newmode.lvds_pll_cntl = rinfo->init_state.lvds_pll_cntl;
+		newmode.tmds_crc = rinfo->init_state.tmds_crc;
+		newmode.tmds_transmitter_cntl = rinfo->init_state.tmds_transmitter_cntl;
+
+		if (primary_mon == MT_LCD) {
+			newmode.lvds_gen_cntl |= (LVDS_ON | LVDS_BLON);
+			newmode.fp_gen_cntl &= ~(FP_FPON | FP_TMDS_EN);
+		} else {
+			/* DFP */
+			newmode.fp_gen_cntl |= (FP_FPON | FP_TMDS_EN);
+			newmode.tmds_transmitter_cntl = (TMDS_RAN_PAT_RST |
+							 TMDS_ICHCSEL | TMDS_PLL_EN) &
+							 ~(TMDS_PLLRST);
+			newmode.crtc_ext_cntl &= ~CRTC_CRT_ON;
+		}
+
+		newmode.fp_crtc_h_total_disp = (((rinfo->hblank / 8) & 0x3ff) |
+				(((mode->xres / 8) - 1) << 16));
+		newmode.fp_crtc_v_total_disp = (rinfo->vblank & 0xffff) |
+				((mode->yres - 1) << 16);
+		newmode.fp_h_sync_strt_wid = ((rinfo->hOver_plus & 0x1fff) |
+				(hsync_wid << 16) | (h_sync_pol << 23));
+		newmode.fp_v_sync_strt_wid = ((rinfo->vOver_plus & 0xfff) |
+				(vsync_wid << 16) | (v_sync_pol  << 23));
+	}
+
+	/* do it! */
+	if (!rinfo->asleep) {
+		radeon_write_mode (rinfo, &newmode);
+		/* (re)initialize the engine */
+		if (noaccel)
+			radeon_engine_init (rinfo);
+	
+	}
+	/* Update fix */
+	if (accel)
+        	info->fix.line_length = rinfo->pitch*64;
+        else
+		info->fix.line_length = mode->xres_virtual * ((mode->bits_per_pixel + 1) / 8);
+        info->fix.visual = rinfo->depth == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
+
+#ifdef CONFIG_BOOTX_TEXT
+	/* Update debug text engine */
+	btext_update_display(rinfo->fb_base_phys, mode->xres, mode->yres,
+			     rinfo->depth, info->fix.line_length);
+#endif
+
+	return 0;
+}
+
+
+static void radeon_write_mode (struct radeonfb_info *rinfo,
+                               struct radeon_regs *mode)
+{
+	int i;
+	int primary_mon = PRIMARY_MONITOR(rinfo);
+
+	radeonfb_blank(VESA_POWERDOWN, (struct fb_info *)rinfo);
+
+
+	if (rinfo->arch == RADEON_M6) {
+		for (i=0; i<8; i++)
+			OUTREG(common_regs_m6[i].reg, common_regs_m6[i].val);
+	} else {
+		for (i=0; i<9; i++)
+			OUTREG(common_regs[i].reg, common_regs[i].val);
+	}
+
+	OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl);
+	OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl,
+		CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS);
+	OUTREGP(DAC_CNTL, mode->dac_cntl, DAC_RANGE_CNTL | DAC_BLANKING);
+	OUTREG(CRTC_H_TOTAL_DISP, mode->crtc_h_total_disp);
+	OUTREG(CRTC_H_SYNC_STRT_WID, mode->crtc_h_sync_strt_wid);
+	OUTREG(CRTC_V_TOTAL_DISP, mode->crtc_v_total_disp);
+	OUTREG(CRTC_V_SYNC_STRT_WID, mode->crtc_v_sync_strt_wid);
+	OUTREG(CRTC_OFFSET, 0);
+	OUTREG(CRTC_OFFSET_CNTL, 0);
+	OUTREG(CRTC_PITCH, mode->crtc_pitch);
+
+#if defined(__BIG_ENDIAN)
+	OUTREG(SURFACE_CNTL, mode->surface_cntl);
+#endif
+
+	while ((INREG(CLOCK_CNTL_INDEX) & PPLL_DIV_SEL_MASK) !=
+	       PPLL_DIV_SEL_MASK) {
+		OUTREGP(CLOCK_CNTL_INDEX, PPLL_DIV_SEL_MASK, 0xffff);
+	}
+
+	OUTPLLP(PPLL_CNTL, PPLL_RESET, 0xffff);
+
+	while ((INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK) !=
+	       (mode->ppll_ref_div & PPLL_REF_DIV_MASK)) {
+		OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, ~PPLL_REF_DIV_MASK);
+	}
+
+	while ((INPLL(PPLL_DIV_3) & PPLL_FB3_DIV_MASK) !=
+	       (mode->ppll_div_3 & PPLL_FB3_DIV_MASK)) {
+		OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_FB3_DIV_MASK);
+	}
+
+	while ((INPLL(PPLL_DIV_3) & PPLL_POST3_DIV_MASK) !=
+	       (mode->ppll_div_3 & PPLL_POST3_DIV_MASK)) {
+		OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_POST3_DIV_MASK);
+	}
+
+	OUTPLL(HTOTAL_CNTL, 0);
+
+	OUTPLLP(PPLL_CNTL, 0, ~PPLL_RESET);
+
+//	OUTREG(DDA_CONFIG, mode->dda_config);
+//	OUTREG(DDA_ON_OFF, mode->dda_on_off);
+
+	if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {
+		OUTREG(FP_CRTC_H_TOTAL_DISP, mode->fp_crtc_h_total_disp);
+		OUTREG(FP_CRTC_V_TOTAL_DISP, mode->fp_crtc_v_total_disp);
+		OUTREG(FP_H_SYNC_STRT_WID, mode->fp_h_sync_strt_wid);
+		OUTREG(FP_V_SYNC_STRT_WID, mode->fp_v_sync_strt_wid);
+		OUTREG(FP_HORZ_STRETCH, mode->fp_horz_stretch);
+		OUTREG(FP_VERT_STRETCH, mode->fp_vert_stretch);
+		OUTREG(FP_GEN_CNTL, mode->fp_gen_cntl);
+		OUTREG(TMDS_CRC, mode->tmds_crc);
+		OUTREG(TMDS_TRANSMITTER_CNTL, mode->tmds_transmitter_cntl);
+
+		if (primary_mon == MT_LCD) {
+			unsigned int tmp = INREG(LVDS_GEN_CNTL);
+
+			mode->lvds_gen_cntl &= ~LVDS_STATE_MASK;
+			mode->lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_STATE_MASK);
+
+			if ((tmp & (LVDS_ON | LVDS_BLON)) ==
+			    (mode->lvds_gen_cntl & (LVDS_ON | LVDS_BLON))) {
+				OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl);
+			} else {
+				if (mode->lvds_gen_cntl & (LVDS_ON | LVDS_BLON)) {
+					udelay(1000);
+					OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl);
+				} else {
+					OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl |
+					       LVDS_BLON);
+					udelay(1000);
+					OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl);
+				}
+			}
+		}
+	}
+
+	radeonfb_blank(VESA_NO_BLANKING, (struct fb_info *)rinfo);
+
+	OUTPLL(VCLK_ECP_CNTL, mode->vclk_ecp_cntl);
+	
+	return;
+}
+
+static struct fb_ops radeonfb_ops = {
+	.owner			= THIS_MODULE,
+	.fb_check_var		= radeonfb_check_var,
+	.fb_set_par		= radeonfb_set_par,
+	.fb_setcolreg		= radeonfb_setcolreg,
+	.fb_pan_display 	= radeonfb_pan_display,
+	.fb_blank		= radeonfb_blank,
+	.fb_ioctl		= radeonfb_ioctl,
+#if 0
+	.fb_fillrect	= radeonfb_fillrect,
+	.fb_copyarea	= radeonfb_copyarea,
+	.fb_imageblit	= radeonfb_imageblit,
+	.fb_rasterimg	= radeonfb_rasterimg,
+#else
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+#endif
+	.fb_cursor	= soft_cursor,
+};
+
+
+static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo)
+{
+	struct fb_info *info;
+
+	info = &rinfo->info;
+
+	info->par = rinfo;
+	info->pseudo_palette = rinfo->pseudo_palette;
+        info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+        info->fbops = &radeonfb_ops;
+        info->screen_base = rinfo->fb_base;
+
+	/* Fill fix common fields */
+	strlcpy(info->fix.id, rinfo->name, sizeof(info->fix.id));
+        info->fix.smem_start = rinfo->fb_base_phys;
+        info->fix.smem_len = rinfo->video_ram;
+        info->fix.type = FB_TYPE_PACKED_PIXELS;
+        info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+        info->fix.xpanstep = 8;
+        info->fix.ypanstep = 1;
+        info->fix.ywrapstep = 0;
+        info->fix.type_aux = 0;
+        info->fix.mmio_start = rinfo->mmio_base_phys;
+        info->fix.mmio_len = RADEON_REGSIZE;
+	if (noaccel)
+	        info->fix.accel = FB_ACCEL_NONE;
+	else
+		info->fix.accel = FB_ACCEL_ATI_RADEON;
+
+        if (radeon_init_disp (rinfo) < 0)
+                return -1;   
+
+        return 0;
+}
+
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+
+/* TODO: Dbl check these tables, we don't go up to full ON backlight
+ * in these, possibly because we noticed MacOS doesn't, but I'd prefer
+ * having some more official numbers from ATI
+ */
+static int backlight_conv_m6[] = {
+	0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e,
+	0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
+};
+static int backlight_conv_m7[] = {
+	0x00, 0x3f, 0x4a, 0x55, 0x60, 0x6b, 0x76, 0x81,
+	0x8c, 0x97, 0xa2, 0xad, 0xb8, 0xc3, 0xce, 0xd9
+};
+
+#define BACKLIGHT_LVDS_OFF
+#undef BACKLIGHT_DAC_OFF
+
+/* We turn off the LCD completely instead of just dimming the backlight.
+ * This provides some greater power saving and the display is useless
+ * without backlight anyway.
+ */
+
+static int radeon_set_backlight_enable(int on, int level, void *data)
+{
+	struct radeonfb_info *rinfo = (struct radeonfb_info *)data;
+	unsigned int lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
+	int* conv_table;
+
+	/* Pardon me for that hack... maybe some day we can figure
+	 * out in what direction backlight should work on a given
+	 * panel ?
+	 */
+	if ((rinfo->arch == RADEON_M7 || rinfo->arch == RADEON_M9)
+		&& !machine_is_compatible("PowerBook4,3"))
+		conv_table = backlight_conv_m7;
+	else
+		conv_table = backlight_conv_m6;
+
+	lvds_gen_cntl |= (LVDS_BL_MOD_EN | LVDS_BLON);
+	if (on && (level > BACKLIGHT_OFF)) {
+		lvds_gen_cntl |= LVDS_DIGON;
+		if (!(lvds_gen_cntl & LVDS_ON)) {
+			lvds_gen_cntl &= ~LVDS_BLON;
+			OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+			(void)INREG(LVDS_GEN_CNTL);
+			mdelay(10);
+			lvds_gen_cntl |= LVDS_BLON;
+			OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+		}
+		lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
+		lvds_gen_cntl |= (conv_table[level] <<
+				  LVDS_BL_MOD_LEVEL_SHIFT);
+		lvds_gen_cntl |= (LVDS_ON | LVDS_EN);
+		lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
+	} else {
+		lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
+		lvds_gen_cntl |= (conv_table[0] <<
+				  LVDS_BL_MOD_LEVEL_SHIFT);
+		lvds_gen_cntl |= LVDS_DISPLAY_DIS;
+		OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+		udelay(10);
+		lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGON);
+	}
+
+	OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+	rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
+	rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK);
+
+	return 0;
+}
+
+static int radeon_set_backlight_level(int level, void *data)
+{
+	return radeon_set_backlight_enable(1, level, data);
+}
+#endif /* CONFIG_PMAC_BACKLIGHT */
+
+
+#ifdef CONFIG_PMAC_PBOOK
+
+static u32 dbg_clk;
+
+/*
+ * Radeon M6 Power Management code. This code currently only supports
+ * the mobile chips, it's based from some informations provided by ATI
+ * along with hours of tracing of MacOS drivers
+ */
+ 
+static void radeon_pm_save_regs(struct radeonfb_info *rinfo)
+{
+	rinfo->save_regs[0] = INPLL(PLL_PWRMGT_CNTL);
+	rinfo->save_regs[1] = INPLL(CLK_PWRMGT_CNTL);
+	rinfo->save_regs[2] = INPLL(MCLK_CNTL);
+	rinfo->save_regs[3] = INPLL(SCLK_CNTL);
+	rinfo->save_regs[4] = INPLL(CLK_PIN_CNTL);
+	rinfo->save_regs[5] = INPLL(VCLK_ECP_CNTL);
+	rinfo->save_regs[6] = INPLL(PIXCLKS_CNTL);
+	rinfo->save_regs[7] = INPLL(MCLK_MISC);
+	rinfo->save_regs[8] = INPLL(P2PLL_CNTL);
+	
+	rinfo->save_regs[9] = INREG(DISP_MISC_CNTL);
+	rinfo->save_regs[10] = INREG(DISP_PWR_MAN);
+	rinfo->save_regs[11] = INREG(LVDS_GEN_CNTL);
+	rinfo->save_regs[12] = INREG(LVDS_PLL_CNTL);
+	rinfo->save_regs[13] = INREG(TV_DAC_CNTL);
+	rinfo->save_regs[14] = INREG(BUS_CNTL1);
+	rinfo->save_regs[15] = INREG(CRTC_OFFSET_CNTL);
+	rinfo->save_regs[16] = INREG(AGP_CNTL);
+	rinfo->save_regs[17] = (INREG(CRTC_GEN_CNTL) & 0xfdffffff) | 0x04000000;
+	rinfo->save_regs[18] = (INREG(CRTC2_GEN_CNTL) & 0xfdffffff) | 0x04000000;
+	rinfo->save_regs[19] = INREG(GPIOPAD_A);
+	rinfo->save_regs[20] = INREG(GPIOPAD_EN);
+	rinfo->save_regs[21] = INREG(GPIOPAD_MASK);
+	rinfo->save_regs[22] = INREG(ZV_LCDPAD_A);
+	rinfo->save_regs[23] = INREG(ZV_LCDPAD_EN);
+	rinfo->save_regs[24] = INREG(ZV_LCDPAD_MASK);
+	rinfo->save_regs[25] = INREG(GPIO_VGA_DDC);
+	rinfo->save_regs[26] = INREG(GPIO_DVI_DDC);
+	rinfo->save_regs[27] = INREG(GPIO_MONID);
+	rinfo->save_regs[28] = INREG(GPIO_CRT2_DDC);
+
+	rinfo->save_regs[29] = INREG(SURFACE_CNTL);
+	rinfo->save_regs[30] = INREG(MC_FB_LOCATION);
+	rinfo->save_regs[31] = INREG(DISPLAY_BASE_ADDR);
+	rinfo->save_regs[32] = INREG(MC_AGP_LOCATION);
+	rinfo->save_regs[33] = INREG(CRTC2_DISPLAY_BASE_ADDR);
+}
+
+static void radeon_pm_restore_regs(struct radeonfb_info *rinfo)
+{
+	OUTPLL(P2PLL_CNTL, rinfo->save_regs[8] & 0xFFFFFFFE); /* First */
+	
+	OUTPLL(PLL_PWRMGT_CNTL, rinfo->save_regs[0]);
+	OUTPLL(CLK_PWRMGT_CNTL, rinfo->save_regs[1]);
+	OUTPLL(MCLK_CNTL, rinfo->save_regs[2]);
+	OUTPLL(SCLK_CNTL, rinfo->save_regs[3]);
+	OUTPLL(CLK_PIN_CNTL, rinfo->save_regs[4]);
+	OUTPLL(VCLK_ECP_CNTL, rinfo->save_regs[5]);
+	OUTPLL(PIXCLKS_CNTL, rinfo->save_regs[6]);
+	OUTPLL(MCLK_MISC, rinfo->save_regs[7]);
+	
+	OUTREG(DISP_MISC_CNTL, rinfo->save_regs[9]);
+	OUTREG(DISP_PWR_MAN, rinfo->save_regs[10]);
+	OUTREG(LVDS_GEN_CNTL, rinfo->save_regs[11]);
+	OUTREG(LVDS_PLL_CNTL,rinfo->save_regs[12]);
+	OUTREG(TV_DAC_CNTL, rinfo->save_regs[13]);
+	OUTREG(BUS_CNTL1, rinfo->save_regs[14]);
+	OUTREG(CRTC_OFFSET_CNTL, rinfo->save_regs[15]);
+	OUTREG(AGP_CNTL, rinfo->save_regs[16]);
+	OUTREG(CRTC_GEN_CNTL, rinfo->save_regs[17]);
+	OUTREG(CRTC2_GEN_CNTL, rinfo->save_regs[18]);
+
+	// wait VBL before that one  ?
+	OUTPLL(P2PLL_CNTL, rinfo->save_regs[8]);
+	
+	OUTREG(GPIOPAD_A, rinfo->save_regs[19]);
+	OUTREG(GPIOPAD_EN, rinfo->save_regs[20]);
+	OUTREG(GPIOPAD_MASK, rinfo->save_regs[21]);
+	OUTREG(ZV_LCDPAD_A, rinfo->save_regs[22]);
+	OUTREG(ZV_LCDPAD_EN, rinfo->save_regs[23]);
+	OUTREG(ZV_LCDPAD_MASK, rinfo->save_regs[24]);
+	OUTREG(GPIO_VGA_DDC, rinfo->save_regs[25]);
+	OUTREG(GPIO_DVI_DDC, rinfo->save_regs[26]);
+	OUTREG(GPIO_MONID, rinfo->save_regs[27]);
+	OUTREG(GPIO_CRT2_DDC, rinfo->save_regs[28]);
+}
+
+static void radeon_pm_disable_iopad(struct radeonfb_info *rinfo)
+{		
+	OUTREG(GPIOPAD_MASK, 0x0001ffff);
+	OUTREG(GPIOPAD_EN, 0x00000400);
+	OUTREG(GPIOPAD_A, 0x00000000);		
+        OUTREG(ZV_LCDPAD_MASK, 0x00000000);
+        OUTREG(ZV_LCDPAD_EN, 0x00000000);
+      	OUTREG(ZV_LCDPAD_A, 0x00000000); 	
+	OUTREG(GPIO_VGA_DDC, 0x00030000);
+	OUTREG(GPIO_DVI_DDC, 0x00000000);
+	OUTREG(GPIO_MONID, 0x00030000);
+	OUTREG(GPIO_CRT2_DDC, 0x00000000);
+}
+
+static void radeon_pm_program_v2clk(struct radeonfb_info *rinfo)
+{
+//
+//	u32 reg;
+//
+//	OUTPLL(P2PLL_REF_DIV, 0x0c);
+//
+//      .../... figure out what macos does here
+}
+
+static void radeon_pm_low_current(struct radeonfb_info *rinfo)
+{
+	u32 reg;
+
+	reg  = INREG(BUS_CNTL1);
+	reg &= ~BUS_CNTL1_MOBILE_PLATFORM_SEL_MASK;
+	reg |= BUS_CNTL1_AGPCLK_VALID | (1<<BUS_CNTL1_MOBILE_PLATFORM_SEL_SHIFT);
+	OUTREG(BUS_CNTL1, reg);
+	
+	reg  = INPLL(PLL_PWRMGT_CNTL);
+	reg |= PLL_PWRMGT_CNTL_SPLL_TURNOFF | PLL_PWRMGT_CNTL_PPLL_TURNOFF |
+		PLL_PWRMGT_CNTL_P2PLL_TURNOFF | PLL_PWRMGT_CNTL_TVPLL_TURNOFF;
+	reg &= ~PLL_PWRMGT_CNTL_SU_MCLK_USE_BCLK;
+	reg &= ~PLL_PWRMGT_CNTL_MOBILE_SU;
+	OUTPLL(PLL_PWRMGT_CNTL, reg);
+
+//	reg  = INPLL(TV_PLL_CNTL1);
+//	reg |= TV_PLL_CNTL1__TVPLL_RESET | TV_PLL_CNTL1__TVPLL_SLEEP;
+//	OUTPLL(TV_PLL_CNTL1, reg);
+	
+	reg  = INREG(TV_DAC_CNTL);
+	reg &= ~(TV_DAC_CNTL_BGADJ_MASK |TV_DAC_CNTL_DACADJ_MASK);
+	reg |=TV_DAC_CNTL_BGSLEEP | TV_DAC_CNTL_RDACPD | TV_DAC_CNTL_GDACPD |
+		TV_DAC_CNTL_BDACPD |
+		(8<<TV_DAC_CNTL_BGADJ__SHIFT) | (8<<TV_DAC_CNTL_DACADJ__SHIFT);
+	OUTREG(TV_DAC_CNTL, reg);
+	
+	reg  = INREG(TMDS_TRANSMITTER_CNTL);
+	reg &= ~(TMDS_PLL_EN |TMDS_PLLRST);
+	OUTREG(TMDS_TRANSMITTER_CNTL, reg);
+
+//	lvds_pll_cntl  = regr32(g, LVDS_PLL_CNTL);
+//	lvds_pll_cntl &= ~LVDS_PLL_CNTL__LVDS_PLL_EN;											
+//	lvds_pll_cntl |=  LVDS_PLL_CNTL__LVDS_PLL_RESET;	
+//	regw32(g, LVDS_PLL_CNTL, lvds_pll_cntl);
+
+	reg = INREG(DAC_CNTL);
+	reg &= ~DAC_CMP_EN;
+	OUTREG(DAC_CNTL, reg);
+
+	reg = INREG(DAC_CNTL2);
+	reg &= ~DAC2_CMP_EN;
+	OUTREG(DAC_CNTL2, reg);
+	
+	reg  = INREG(TV_DAC_CNTL);
+	reg &= ~TV_DAC_CNTL_DETECT;
+	OUTREG(TV_DAC_CNTL, reg);
+}
+
+static void radeon_pm_setup_for_suspend(struct radeonfb_info *rinfo)
+{
+	/* This code is disabled. It does what is in the pm_init
+	 * function of the MacOS driver code ATI sent me. However,
+	 * it doesn't fix my sleep problem, and is causing other issues
+	 * on wakeup (bascially the machine dying when switching consoles
+	 * I haven't had time to investigate this yet
+	 */
+#if 0
+	u32 disp_misc_cntl;
+	u32 disp_pwr_man;
+	u32 temp;
+
+	// set SPLL, MPLL, PPLL, P2PLL, TVPLL, SCLK, MCLK, PCLK, P2CLK,
+	// TCLK and TEST_MODE to 0
+	temp = INPLL(CLK_PWRMGT_CNTL);
+	OUTPLL(CLK_PWRMGT_CNTL , temp & ~0xc00002ff);
+
+	// Turn on Power Management
+	temp = INPLL(CLK_PWRMGT_CNTL);
+	OUTPLL(CLK_PWRMGT_CNTL , temp | 0x00000400);
+
+	// Turn off display clock if using mobile chips
+	temp = INPLL(CLK_PWRMGT_CNTL);
+	OUTREG(CLK_PWRMGT_CNTL , temp | 0x00100000);
+
+	// Force PIXCLK_ALWAYS_ON and PIXCLK_DAC_ALWAYS_ON
+	temp = INPLL(VCLK_ECP_CNTL);
+	OUTPLL(VCLK_ECP_CNTL, temp & ~0x000000c0);
+
+	// Force ECP_FORCE_ON to 1
+	temp = INPLL(VCLK_ECP_CNTL);
+	OUTPLL(VCLK_ECP_CNTL, temp | 0x00040000);
+
+	// Force PIXCLK_BLEND_ALWAYS_ON and PIXCLK_GV_ALWAYS_ON
+	temp = INPLL(PIXCLKS_CNTL);
+       	OUTPLL(PIXCLKS_CNTL, temp & ~0x00001800);
+
+	// Forcing SCLK_CNTL to ON
+	OUTPLL(SCLK_CNTL, (INPLL(SCLK_CNTL)& 0x00000007) | 0xffff8000 );
+
+	// Set PM control over XTALIN pad
+	temp = INPLL(CLK_PIN_CNTL);
+	OUTPLL(CLK_PIN_CNTL, temp | 0x00080000);
+
+	// Force MCLK and YCLK and MC as dynamic
+    	temp = INPLL(MCLK_CNTL);
+	OUTPLL(MCLK_CNTL, temp & 0xffeaffff);
+
+	// PLL_TURNOFF
+	temp = INPLL(PLL_PWRMGT_CNTL);
+	OUTPLL(PLL_PWRMGT_CNTL, temp | 0x0000001f);
+ 
+	// set MOBILE_SU to 1 if M6 or DDR64 is detected
+	temp = INPLL(PLL_PWRMGT_CNTL);
+	OUTPLL(PLL_PWRMGT_CNTL, temp | 0x00010000);
+
+	// select PM access mode (PM_MODE_SEL) (use ACPI mode)
+//      temp = INPLL(PLL_PWRMGT_CNTL);
+//      OUTPLL(PLL_PWRMGT_CNTL, temp | 0x00002000);
+	temp = INPLL(PLL_PWRMGT_CNTL);
+        OUTPLL(PLL_PWRMGT_CNTL, temp & ~0x00002000);
+
+	// set DISP_MISC_CNTL register
+	disp_misc_cntl = INREG(DISP_MISC_CNTL);
+	disp_misc_cntl &= ~(	DISP_MISC_CNTL_SOFT_RESET_GRPH_PP |
+				DISP_MISC_CNTL_SOFT_RESET_SUBPIC_PP |
+				DISP_MISC_CNTL_SOFT_RESET_OV0_PP |
+				DISP_MISC_CNTL_SOFT_RESET_GRPH_SCLK |
+				DISP_MISC_CNTL_SOFT_RESET_SUBPIC_SCLK |
+				DISP_MISC_CNTL_SOFT_RESET_OV0_SCLK |
+				DISP_MISC_CNTL_SOFT_RESET_GRPH2_PP |
+				DISP_MISC_CNTL_SOFT_RESET_GRPH2_SCLK |
+				DISP_MISC_CNTL_SOFT_RESET_LVDS |
+				DISP_MISC_CNTL_SOFT_RESET_TMDS |
+				DISP_MISC_CNTL_SOFT_RESET_DIG_TMDS |
+				DISP_MISC_CNTL_SOFT_RESET_TV);
+	OUTREG(DISP_MISC_CNTL, disp_misc_cntl);
+
+	// set DISP_PWR_MAN register
+	disp_pwr_man = INREG(DISP_PWR_MAN);
+	// clau - 9.29.2000 - changes made to bit23:18 to set to 1 as requested by George
+	disp_pwr_man |= (DISP_PWR_MAN_DIG_TMDS_ENABLE_RST |
+                    DISP_PWR_MAN_TV_ENABLE_RST |
+ //                 DISP_PWR_MAN_AUTO_PWRUP_EN |
+                    DISP_PWR_MAN_DISP_D3_GRPH_RST |
+                    DISP_PWR_MAN_DISP_D3_SUBPIC_RST |
+                    DISP_PWR_MAN_DISP_D3_OV0_RST |
+                    DISP_PWR_MAN_DISP_D1D2_GRPH_RST |
+                    DISP_PWR_MAN_DISP_D1D2_SUBPIC_RST |
+                    DISP_PWR_MAN_DISP_D1D2_OV0_RST);
+	disp_pwr_man &= ~(DISP_PWR_MAN_DISP_PWR_MAN_D3_CRTC_EN |
+                    DISP_PWR_MAN_DISP2_PWR_MAN_D3_CRTC2_EN|
+                    DISP_PWR_MAN_DISP_D3_RST |
+                    DISP_PWR_MAN_DISP_D3_REG_RST);
+	OUTREG(DISP_PWR_MAN, disp_pwr_man);
+
+	// clau - 10.24.2000
+	// - add in setting for BUS_CNTL1 b27:26 = 0x01 and b31 = 0x1
+	// - add in setting for AGP_CNTL  b7:0 = 0x20
+	// - add in setting for DVI_DDC_DATA_OUT_EN b17:16 = 0x0
+
+	// the following settings (two lines) are applied at a later part of this function, only on mobile platform
+	// requres -mobile flag
+	OUTREG(BUS_CNTL1, (INREG(BUS_CNTL1) & 0xf3ffffff) | 0x04000000);
+	OUTREG(BUS_CNTL1,  INREG(BUS_CNTL1) | 0x80000000);
+	OUTREG(AGP_CNTL, (INREG(AGP_CNTL) & 0xffffff00) | 0x20);
+	OUTREG(GPIO_DVI_DDC, INREG(GPIO_DVI_DDC) & 0xfffcffff);
+
+	// yulee - 12.12.2000
+	// A12 only
+	// EN_MCLK_TRISTATE_IN_SUSPEND@MCLK_MISC = 1
+	// ACCESS_REGS_IN_SUSPEND@CLK_PIN_CNTL = 0
+	// only on mobile platform
+        OUTPLL(MCLK_MISC, INPLL(MCLK_MISC) | 0x00040000 );
+    	
+	// yulee -12.12.2000
+	// AGPCLK_VALID@BUS_CNTL1 = 1
+	// MOBILE_PLATFORM_SEL@BUS_CNTL1 = 01
+	// CRTC_STEREO_SYNC_OUT_EN@CRTC_OFFSET_CNTL = 0
+	// CG_CLK_TO_OUTPIN@CLK_PIN_CNTL = 0
+	// only on mobile platform
+        OUTPLL(CLK_PIN_CNTL, INPLL(CLK_PIN_CNTL ) & 0xFFFFF7FF );
+        OUTREG(BUS_CNTL1, (INREG(BUS_CNTL1 ) & 0xF3FFFFFF) | 0x84000000 );
+        OUTREG(CRTC_OFFSET_CNTL, INREG(CRTC_OFFSET_CNTL ) & 0xFFEFFFFF );
+
+        mdelay(100);
+#endif
+
+	/* Disable CRTCs */
+	OUTREG(CRTC_GEN_CNTL, (INREG(CRTC_GEN_CNTL) & ~CRTC_EN) | CRTC_DISP_REQ_EN_B);
+	OUTREG(CRTC2_GEN_CNTL, (INREG(CRTC2_GEN_CNTL) & ~CRTC2_EN) | CRTC2_DISP_REQ_EN_B);
+	(void)INREG(CRTC2_GEN_CNTL);
+	mdelay(17);
+}
+
+static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend)
+{
+	u16 pwr_cmd;
+
+	if (!rinfo->pm_reg)
+		return;
+
+	/* Set the chip into appropriate suspend mode (we use D2,
+	 * D3 would require a compete re-initialization of the chip,
+	 * including PCI config registers, clocks, AGP conf, ...)
+	 */
+	if (suspend) {
+		/* According to ATI, we should program V2CLK here, I have
+		 * to verify what's up exactly
+		 */
+		/* Save some registers */
+		radeon_pm_save_regs(rinfo);
+
+		/* Check that on M7 too, might work might not. M7 may also
+		 * need explicit enabling of PM
+		 */
+		if (rinfo->arch == RADEON_M6) {
+			/* Program V2CLK */
+			radeon_pm_program_v2clk(rinfo);
+		
+			/* Disable IO PADs */
+			radeon_pm_disable_iopad(rinfo);
+
+			/* Set low current */
+			radeon_pm_low_current(rinfo);
+
+			/* Prepare chip for power management */
+			radeon_pm_setup_for_suspend(rinfo);
+
+			/* Reset the MDLL */
+			OUTPLL(MDLL_CKO, INPLL(MDLL_CKO) | MCKOA_RESET);
+			(void)INPLL(MDLL_RDCKA);
+			OUTPLL(MDLL_CKO, INPLL(MDLL_CKO) & ~MCKOA_RESET);
+			(void)INPLL(MDLL_RDCKA);
+		}
+
+		/* Switch PCI power managment to D2. */
+		for (;;) {
+			pci_read_config_word(
+				rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL,
+				&pwr_cmd);
+			if (pwr_cmd & 2)
+				break;			
+			pci_write_config_word(
+				rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL,
+				(pwr_cmd & ~PCI_PM_CTRL_STATE_MASK) | 2);
+			mdelay(500);
+		}
+	} else {
+		/* Switch back PCI powermanagment to D0 */
+		mdelay(200);
+		pci_write_config_word(rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL, 0);
+		mdelay(500);
+
+		dbg_clk = INPLL(1);
+
+		/* Do we need that on M7 ? */
+		if (rinfo->arch == RADEON_M6) {
+			/* Restore the MDLL */
+			OUTPLL(MDLL_CKO, INPLL(MDLL_CKO) & ~MCKOA_RESET);
+			(void)INPLL(MDLL_CKO);			
+		}
+		
+		/* Restore some registers */
+		radeon_pm_restore_regs(rinfo);
+	}
+}
+
+/*
+ * Save the contents of the framebuffer when we go to sleep,
+ * and restore it when we wake up again.
+ */
+
+int radeon_sleep_notify(struct pmu_sleep_notifier *self, int when)
+{
+	struct radeonfb_info *rinfo;
+
+	for (rinfo = board_list; rinfo != NULL; rinfo = rinfo->next) {
+		struct fb_fix_screeninfo fix;
+		int nb;
+	        struct display *disp;  
+
+        	disp = (rinfo->currcon < 0) ? rinfo->info.disp : &fb_display[rinfo->currcon];
+
+		switch (rinfo->arch) {
+			case RADEON_M6:
+			case RADEON_M7:
+			case RADEON_M9:
+				break;
+			default:
+				return PBOOK_SLEEP_REFUSE;
+		}
+
+		radeonfb_get_fix(&fix, fg_console, (struct fb_info *)rinfo);
+		nb = fb_display[fg_console].var.yres * fix.line_length;
+
+		switch (when) {
+			case PBOOK_SLEEP_NOW:
+				acquire_console_sem();
+				disp->dispsw = &fbcon_dummy;
+
+				if (!noaccel) {
+					/* Make sure engine is reset */
+					radeon_engine_reset();
+					radeon_engine_idle();
+				}
+
+				/* Blank display and LCD */
+				radeonfb_blank(VESA_POWERDOWN+1,
+					       (struct fb_info *)rinfo);
+
+				/* Sleep */
+				rinfo->asleep = 1;
+				radeon_set_suspend(rinfo, 1);
+				release_console_sem();
+				
+				break;
+			case PBOOK_WAKE:
+				acquire_console_sem();
+				/* Wakeup */
+				radeon_set_suspend(rinfo, 0);
+
+				if (!noaccel)
+					radeon_engine_init(rinfo);
+				rinfo->asleep = 0;
+				radeon_set_dispsw(rinfo, disp);
+				radeon_load_video_mode(rinfo, &disp->var);
+				do_install_cmap(rinfo->currcon < 0 ? 0 : rinfo->currcon,
+						(struct fb_info *)rinfo);
+
+				radeonfb_blank(0, (struct fb_info *)rinfo);
+				release_console_sem();
+				printk("CLK_PIN_CNTL on wakeup was: %08x\n", dbg_clk);
+				break;
+		}
+	}
+
+	return PBOOK_SLEEP_OK;
+}
+
+#endif /* CONFIG_PMAC_PBOOK */
+
+static int radeonfb_pci_register (struct pci_dev *pdev,
+				  const struct pci_device_id *ent)
+{
+	struct radeonfb_info *rinfo;
+	struct radeon_chip_info *rci = &radeon_chip_info[ent->driver_data];
+	u32 tmp;
+
+	RTRACE("radeonfb_pci_register BEGIN\n");
+
+	/* Enable device in PCI config */
+	if (pci_enable_device(pdev) != 0) {
+		printk(KERN_ERR "radeonfb: Cannot enable PCI device\n");
+		return -ENODEV;
+	}
+
+	rinfo = kmalloc (sizeof (struct radeonfb_info), GFP_KERNEL);
+	if (!rinfo) {
+		printk ("radeonfb: could not allocate memory\n");
+		return -ENODEV;
+	}
+
+	memset (rinfo, 0, sizeof (struct radeonfb_info));
+	//info = &rinfo->info;
+	rinfo->pdev = pdev;
+	strcpy(rinfo->name, rci->name);
+	rinfo->arch = rci->arch;
+
+	/* Set base addrs */
+	rinfo->fb_base_phys = pci_resource_start (pdev, 0);
+	rinfo->mmio_base_phys = pci_resource_start (pdev, 2);
+
+	/* request the mem regions */
+	if (!request_mem_region (rinfo->fb_base_phys,
+				 pci_resource_len(pdev, 0), "radeonfb")) {
+		printk ("radeonfb: cannot reserve FB region\n");
+		kfree (rinfo);
+		return -ENODEV;
+	}
+
+	if (!request_mem_region (rinfo->mmio_base_phys,
+				 pci_resource_len(pdev, 2), "radeonfb")) {
+		printk ("radeonfb: cannot reserve MMIO region\n");
+		release_mem_region (rinfo->fb_base_phys,
+				    pci_resource_len(pdev, 0));
+		kfree (rinfo);
+		return -ENODEV;
+	}
+
+	/* map the regions */
+	rinfo->mmio_base = ioremap (rinfo->mmio_base_phys, RADEON_REGSIZE);
+	if (!rinfo->mmio_base) {
+		printk ("radeonfb: cannot map MMIO\n");
+		release_mem_region (rinfo->mmio_base_phys,
+				    pci_resource_len(pdev, 2));
+		release_mem_region (rinfo->fb_base_phys,
+				    pci_resource_len(pdev, 0));
+		kfree (rinfo);
+		return -ENODEV;
+	}
+
+	rinfo->chipset = pdev->device;
+
+	switch (rinfo->arch) {
+		case RADEON_R100:
+			rinfo->hasCRTC2 = 0;
+			break;
+		default:
+			/* all the rest have it */
+			rinfo->hasCRTC2 = 1;
+			break;
+	}
+#if 0
+	if (rinfo->arch == RADEON_M7) {
+		/*
+		 * Noticed some errors in accel with M7, will have to work these out...
+		 */
+		noaccel = 1;
+	}
+#endif
+	if (mirror)
+		printk("radeonfb: mirroring display to CRT\n");
+
+	/* framebuffer size */
+	tmp = INREG(CONFIG_MEMSIZE);
+
+	/* mem size is bits [28:0], mask off the rest */
+	rinfo->video_ram = tmp & CONFIG_MEMSIZE_MASK;
+
+	/* ram type */
+	tmp = INREG(MEM_SDRAM_MODE_REG);
+	switch ((MEM_CFG_TYPE & tmp) >> 30) {
+		case 0:
+			/* SDR SGRAM (2:1) */
+			strcpy(rinfo->ram_type, "SDR SGRAM");
+			rinfo->ram.ml = 4;
+			rinfo->ram.mb = 4;
+			rinfo->ram.trcd = 1;
+			rinfo->ram.trp = 2;
+			rinfo->ram.twr = 1;
+			rinfo->ram.cl = 2;
+			rinfo->ram.loop_latency = 16;
+			rinfo->ram.rloop = 16;
+	
+			break;
+		case 1:
+			/* DDR SGRAM */
+			strcpy(rinfo->ram_type, "DDR SGRAM");
+			rinfo->ram.ml = 4;
+			rinfo->ram.mb = 4;
+			rinfo->ram.trcd = 3;
+			rinfo->ram.trp = 3;
+			rinfo->ram.twr = 2;
+			rinfo->ram.cl = 3;
+			rinfo->ram.tr2w = 1;
+			rinfo->ram.loop_latency = 16;
+			rinfo->ram.rloop = 16;
+
+			break;
+		default:
+			/* 64-bit SDR SGRAM */
+			strcpy(rinfo->ram_type, "SDR SGRAM 64");
+			rinfo->ram.ml = 4;
+			rinfo->ram.mb = 8;
+			rinfo->ram.trcd = 3;
+			rinfo->ram.trp = 3;
+			rinfo->ram.twr = 1;
+			rinfo->ram.cl = 3;
+			rinfo->ram.tr2w = 1;
+			rinfo->ram.loop_latency = 17;
+			rinfo->ram.rloop = 17;
+
+			break;
+	}
+
+	rinfo->bios_seg = radeon_find_rom(rinfo);
+	radeon_get_pllinfo(rinfo, rinfo->bios_seg);
+
+	/*
+	 * Hack to get around some busted production M6's
+	 * reporting no ram
+	 */
+	if (rinfo->video_ram == 0) {
+		switch (pdev->device) {
+			case PCI_DEVICE_ID_ATI_RADEON_LY:
+			case PCI_DEVICE_ID_ATI_RADEON_LZ:
+				rinfo->video_ram = 8192 * 1024;
+				break;
+			default:
+				break;
+		}
+	}
+
+
+	RTRACE("radeonfb: probed %s %dk videoram\n", (rinfo->ram_type), (rinfo->video_ram/1024));
+
+#if !defined(__powerpc__)
+	radeon_get_moninfo(rinfo);
+#else
+	switch (pdev->device) {
+		case PCI_DEVICE_ID_ATI_RADEON_LW:
+		case PCI_DEVICE_ID_ATI_RADEON_LX:
+		case PCI_DEVICE_ID_ATI_RADEON_LY:
+		case PCI_DEVICE_ID_ATI_RADEON_LZ:
+			rinfo->dviDisp_type = MT_LCD;
+			break;
+		default:
+			radeon_get_moninfo(rinfo);
+			break;
+	}
+#endif
+
+	radeon_get_EDID(rinfo);
+
+	if ((rinfo->dviDisp_type == MT_DFP) || (rinfo->dviDisp_type == MT_LCD) ||
+	    (rinfo->crtDisp_type == MT_DFP)) {
+		if (!radeon_get_dfpinfo(rinfo)) {
+			iounmap(rinfo->mmio_base);
+			release_mem_region (rinfo->mmio_base_phys,
+					    pci_resource_len(pdev, 2));
+			release_mem_region (rinfo->fb_base_phys,
+					    pci_resource_len(pdev, 0));
+			kfree (rinfo);
+			return -ENODEV;
+		}
+	}
+
+	rinfo->fb_base = ioremap (rinfo->fb_base_phys, rinfo->video_ram);
+	if (!rinfo->fb_base) {
+		printk ("radeonfb: cannot map FB\n");
+		iounmap(rinfo->mmio_base);
+		release_mem_region (rinfo->mmio_base_phys,
+				    pci_resource_len(pdev, 2));
+		release_mem_region (rinfo->fb_base_phys,
+				    pci_resource_len(pdev, 0));
+		kfree (rinfo);
+		return -ENODEV;
+	}
+
+	/* I SHOULD FIX THAT CRAP ! I should probably mimmic XFree DRI
+	 * driver setup here.
+	 * 
+	 * On PPC, OF based cards setup the internal memory
+	 * mapping in strange ways. We change it so that the
+	 * framebuffer is mapped at 0 and given half of the card's
+	 * address space (2Gb). AGP is mapped high (0xe0000000) and
+	 * can use up to 512Mb. Once DRI is fully implemented, we
+	 * will have to setup the PCI remapper to remap the agp_special_page
+	 * memory page somewhere between those regions so that the card
+	 * use a normal PCI bus master cycle to access the ring read ptr.
+	 * --BenH.
+	 */
+#ifdef CONFIG_ALL_PPC
+	if (rinfo->hasCRTC2)
+		OUTREG(CRTC2_GEN_CNTL,
+			(INREG(CRTC2_GEN_CNTL) & ~CRTC2_EN) | CRTC2_DISP_REQ_EN_B);
+	OUTREG(CRTC_EXT_CNTL, INREG(CRTC_EXT_CNTL) | CRTC_DISPLAY_DIS);
+	OUTREG(MC_FB_LOCATION, 0x7fff0000);
+	OUTREG(MC_AGP_LOCATION, 0xffffe000);
+	OUTREG(DISPLAY_BASE_ADDR, 0x00000000);
+	if (rinfo->hasCRTC2)
+		OUTREG(CRTC2_DISPLAY_BASE_ADDR, 0x00000000);
+	OUTREG(SRC_OFFSET, 0x00000000);
+	OUTREG(DST_OFFSET, 0x00000000);
+	mdelay(10);
+	OUTREG(CRTC_EXT_CNTL, INREG(CRTC_EXT_CNTL) & ~CRTC_DISPLAY_DIS);
+#endif /* CONFIG_ALL_PPC */
+
+	/* save current mode regs before we switch into the new one
+	 * so we can restore this upon __exit
+	 */
+	radeon_save_state (rinfo, &rinfo->init_state);
+
+	/* set all the vital stuff */
+	radeon_set_fbinfo (rinfo);
+
+	pci_set_drvdata(pdev, rinfo);
+	rinfo->next = board_list;
+	board_list = rinfo;
+	((struct fb_info *) rinfo)->device = &pdev->dev;
+	if (register_framebuffer ((struct fb_info *) rinfo) < 0) {
+		printk ("radeonfb: could not register framebuffer\n");
+		iounmap(rinfo->fb_base);
+		iounmap(rinfo->mmio_base);
+		release_mem_region (rinfo->mmio_base_phys,
+				    pci_resource_len(pdev, 2));
+		release_mem_region (rinfo->fb_base_phys,
+				    pci_resource_len(pdev, 0));
+		kfree (rinfo);
+		return -ENODEV;
+	}
+
+#ifdef CONFIG_MTRR
+	rinfo->mtrr_hdl = nomtrr ? -1 : mtrr_add(rinfo->fb_base_phys,
+						 rinfo->video_ram,
+						 MTRR_TYPE_WRCOMB, 1);
+#endif
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	if (rinfo->dviDisp_type == MT_LCD)
+		register_backlight_controller(&radeon_backlight_controller,
+					      rinfo, "ati");
+#endif
+
+#ifdef CONFIG_PMAC_PBOOK
+	if (rinfo->dviDisp_type == MT_LCD) {
+		rinfo->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM);
+		pmu_register_sleep_notifier(&radeon_sleep_notifier);
+	}
+#endif
+
+	printk ("radeonfb: ATI Radeon %s %s %d MB\n", rinfo->name, rinfo->ram_type,
+		(rinfo->video_ram/(1024*1024)));
+
+	if (rinfo->hasCRTC2) {
+		printk("radeonfb: DVI port %s monitor connected\n",
+			GET_MON_NAME(rinfo->dviDisp_type));
+		printk("radeonfb: CRT port %s monitor connected\n",
+			GET_MON_NAME(rinfo->crtDisp_type));
+	} else {
+		printk("radeonfb: CRT port %s monitor connected\n",
+			GET_MON_NAME(rinfo->crtDisp_type));
+	}
+
+	RTRACE("radeonfb_pci_register END\n");
+
+	return 0;
+}
+
+
+
+static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev)
+{
+        struct radeonfb_info *rinfo = pci_get_drvdata(pdev);
+ 
+        if (!rinfo)
+                return;
+ 
+	/* restore original state
+	 * 
+	 * Doesn't quite work yet, possibly because of the PPC hacking
+	 * I do on startup, disable for now. --BenH
+	 */
+        radeon_write_mode (rinfo, &rinfo->init_state);
+ 
+#ifdef CONFIG_MTRR
+	if (rinfo->mtrr_hdl >= 0)
+		mtrr_del(rinfo->mtrr_hdl, 0, 0);
+#endif
+
+        unregister_framebuffer ((struct fb_info *) rinfo);
+                
+        iounmap(rinfo->mmio_base);
+        iounmap(rinfo->fb_base);
+ 
+	release_mem_region (rinfo->mmio_base_phys,
+			    pci_resource_len(pdev, 2));
+	release_mem_region (rinfo->fb_base_phys,
+			    pci_resource_len(pdev, 0));
+        
+        kfree (rinfo);
+}
+
+
+static struct pci_driver radeonfb_driver = {
+	.name		= "radeonfb",
+	.id_table	= radeonfb_pci_table,
+	.probe		= radeonfb_pci_register,
+	.remove		= __devexit_p(radeonfb_pci_unregister),
+};
+
+#ifndef MODULE
+static int __init radeonfb_old_setup (char *options)
+{
+        char *this_opt;
+
+        if (!options || !*options)
+                return 0;
+ 
+	while ((this_opt = strsep (&options, ",")) != NULL) {
+		if (!*this_opt)
+			continue;
+                if (!strncmp(this_opt, "noaccel", 7)) {
+			noaccel = 1;
+                } else if (!strncmp(this_opt, "mirror", 6)) {
+			mirror = 1;
+		} else if (!strncmp(this_opt, "dfp", 3)) {
+			force_dfp = 1;
+		} else if (!strncmp(this_opt, "panel_yres:", 11)) {
+			panel_yres = simple_strtoul((this_opt+11), NULL, 0);
+		} else if (!strncmp(this_opt, "nomtrr", 6)) {
+			nomtrr = 1;
+                } else
+			mode_option = this_opt;
+        }
+
+	return 0;
+}
+#endif  /*  MODULE  */
+
+static int __init radeonfb_old_init (void)
+{
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("radeonfb_old", &option))
+		return -ENODEV;
+	radeonfb_old_setup(option);
+#endif
+	return pci_register_driver (&radeonfb_driver);
+}
+
+
+static void __exit radeonfb_old_exit (void)
+{
+	pci_unregister_driver (&radeonfb_driver);
+}
+
+module_init(radeonfb_old_init);
+module_exit(radeonfb_old_exit);
+
+
+MODULE_AUTHOR("Ani Joshi");
+MODULE_DESCRIPTION("framebuffer driver for ATI Radeon chipset");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/retz3fb.c b/drivers/video/retz3fb.c
new file mode 100644
index 0000000..5e2c64f
--- /dev/null
+++ b/drivers/video/retz3fb.c
@@ -0,0 +1,1587 @@
+/*
+ * Linux/drivers/video/retz3fb.c -- RetinaZ3 frame buffer device
+ *
+ *    Copyright (C) 1997 Jes Sorensen
+ *
+ * This file is based on the CyberVision64 frame buffer device and
+ * the generic Cirrus Logic driver.
+ *
+ * cyberfb.c: Copyright (C) 1996 Martin Apel,
+ *                               Geert Uytterhoeven
+ * clgen.c:   Copyright (C) 1996 Frank Neumann
+ *
+ * History:
+ *   - 22 Jan 97: Initial work
+ *   - 14 Feb 97: Screen initialization works somewhat, still only
+ *                8-bit packed pixel is supported.
+ *
+ * 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/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/delay.h>
+#include <linux/fb.h>
+#include <linux/zorro.h>
+#include <linux/init.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+
+#include "retz3fb.h"
+
+/* #define DEBUG if(1) */
+#define DEBUG if(0)
+
+/*
+ * Reserve space for one pattern line.
+ *
+ * For the time being we only support 4MB boards!
+ */
+
+#define PAT_MEM_SIZE 16*3
+#define PAT_MEM_OFF  (4*1024*1024 - PAT_MEM_SIZE)
+
+struct retz3fb_par {
+	int xres;
+	int yres;
+	int xres_vir;
+	int yres_vir;
+	int xoffset;
+	int yoffset;
+	int bpp;
+
+	struct fb_bitfield red;
+	struct fb_bitfield green;
+	struct fb_bitfield blue;
+	struct fb_bitfield transp;
+
+	int pixclock;
+	int left_margin;	/* time from sync to picture	*/
+	int right_margin;	/* time from picture to sync	*/
+	int upper_margin;	/* time from sync to picture	*/
+	int lower_margin;
+	int hsync_len;	/* length of horizontal sync	*/
+	int vsync_len;	/* length of vertical sync	*/
+	int vmode;
+
+	int accel;
+};
+
+struct display_data {
+	long h_total;		/* Horizontal Total */
+	long h_sstart;		/* Horizontal Sync Start */
+	long h_sstop;		/* Horizontal Sync Stop */
+	long h_bstart;		/* Horizontal Blank Start */
+	long h_bstop;		/* Horizontal Blank Stop */
+	long h_dispend;		/* Horizontal Display End */
+	long v_total;		/* Vertical Total */
+	long v_sstart;		/* Vertical Sync Start */
+	long v_sstop;		/* Vertical Sync Stop */
+	long v_bstart;		/* Vertical Blank Start */
+	long v_bstop;		/* Vertical Blank Stop */
+	long v_dispend;		/* Horizontal Display End */
+};
+
+struct retz3_fb_info {
+	struct fb_info info;
+	unsigned char *base;
+	unsigned char *fbmem;
+	unsigned long fbsize;
+	volatile unsigned char *regs;
+	unsigned long physfbmem;
+	unsigned long physregs;
+	int current_par_valid; /* set to 0 by memset */
+	int blitbusy;
+	struct display disp;
+	struct retz3fb_par current_par;
+	unsigned char color_table [256][3];
+};
+
+
+static char fontname[40] __initdata = { 0 };
+
+#define retz3info(info) ((struct retz3_fb_info *)(info))
+#define fbinfo(info) ((struct fb_info *)(info))
+
+
+/*
+ *    Frame Buffer Name
+ */
+
+static char retz3fb_name[16] = "RetinaZ3";
+
+
+/*
+ * A small info on how to convert XFree86 timing values into fb
+ * timings - by Frank Neumann:
+ *
+An XFree86 mode line consists of the following fields:
+ "800x600"     50      800  856  976 1040    600  637  643  666
+ < name >     DCF       HR  SH1  SH2  HFL     VR  SV1  SV2  VFL
+
+The fields in the fb_var_screeninfo structure are:
+        unsigned long pixclock;         * pixel clock in ps (pico seconds) *
+        unsigned long left_margin;      * time from sync to picture    *
+        unsigned long right_margin;     * time from picture to sync    *
+        unsigned long upper_margin;     * time from sync to picture    *
+        unsigned long lower_margin;
+        unsigned long hsync_len;        * length of horizontal sync    *
+        unsigned long vsync_len;        * length of vertical sync      *
+
+1) Pixelclock:
+   xfree: in MHz
+   fb: In Picoseconds (ps)
+
+   pixclock = 1000000 / DCF
+
+2) horizontal timings:
+   left_margin = HFL - SH2
+   right_margin = SH1 - HR
+   hsync_len = SH2 - SH1
+
+3) vertical timings:
+   upper_margin = VFL - SV2
+   lower_margin = SV1 - VR
+   vsync_len = SV2 - SV1
+
+Good examples for VESA timings can be found in the XFree86 source tree,
+under "programs/Xserver/hw/xfree86/doc/modeDB.txt".
+*/
+
+/*
+ *    Predefined Video Modes
+ */
+
+static struct {
+    const char *name;
+    struct fb_var_screeninfo var;
+} retz3fb_predefined[] __initdata = {
+    /*
+     * NB: it is very important to adjust the pixel-clock to the color-depth.
+     */
+
+    {
+	"640x480", {		/* 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, FB_ACCEL_NONE, 39722, 48, 16, 33, 10, 96, 2,
+	    FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
+	}
+    },
+    /*
+     ModeLine "800x600" 36 800 824 896 1024 600 601 603 625
+	      < name > DCF HR  SH1 SH2  HFL VR  SV1 SV2 VFL
+     */
+    {
+	"800x600", {		/* 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, FB_ACCELF_TEXT, 27778, 64, 24, 22, 1, 120, 2,
+	    FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}
+    },
+    {
+	"800x600-60", {		/* 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, FB_ACCELF_TEXT, 25000, 88, 40, 23, 1, 128, 4,
+	    FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}
+    },
+    {
+	"800x600-70", {		/* 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, FB_ACCELF_TEXT, 22272, 40, 24, 15, 9, 144, 12,
+	    FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED
+	}
+    },
+    /*
+      ModeLine "1024x768i" 45 1024 1064 1224 1264 768 777 785 817 interlace
+	       < name >   DCF HR  SH1  SH2  HFL  VR  SV1 SV2 VFL
+     */
+    {
+	"1024x768i", {		/* 1024x768, 8 bpp, interlaced */
+	    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, 22222, 40, 40, 32, 9, 160, 8,
+	    FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED
+	}
+    },
+    {
+	"1024x768", {
+	    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_ACCEL_NONE, 12500, 92, 112, 31, 2, 204, 4,
+	    FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	 }
+    },
+    {
+	"640x480-16", {		/* 640x480, 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, 0, 38461/2, 28, 32, 12, 10, 96, 2,
+	    FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
+	}
+    },
+    {
+	"640x480-24", {		/* 640x480, 24 bpp */
+	    640, 480, 640, 480, 0, 0, 24, 0,
+	    {8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0},
+	    0, 0, -1, -1, 0, 38461/3, 28, 32, 12, 10, 96, 2,
+	    FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
+	}
+    },
+};
+
+
+#define NUM_TOTAL_MODES    ARRAY_SIZE(retz3fb_predefined)
+
+static struct fb_var_screeninfo retz3fb_default;
+
+static int z3fb_inverse = 0;
+static int z3fb_mode __initdata = 0;
+
+
+/*
+ *    Interface used by the world
+ */
+
+int retz3fb_setup(char *options);
+
+static int retz3fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			   struct fb_info *info);
+static int retz3fb_get_var(struct fb_var_screeninfo *var, int con,
+			   struct fb_info *info);
+static int retz3fb_set_var(struct fb_var_screeninfo *var, int con,
+			   struct fb_info *info);
+static int retz3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			    struct fb_info *info);
+static int retz3fb_setcolreg(unsigned int regno, unsigned int red,
+			     unsigned int green, unsigned int blue,
+			     unsigned int transp, struct fb_info *info);
+static int retz3fb_blank(int blank, struct fb_info *info);
+
+
+/*
+ *    Interface to the low level console driver
+ */
+
+int retz3fb_init(void);
+static int z3fb_switch(int con, struct fb_info *info);
+static int z3fb_updatevar(int con, struct fb_info *info);
+
+
+/*
+ *    Text console acceleration
+ */
+
+#ifdef FBCON_HAS_CFB8
+static struct display_switch fbcon_retz3_8;
+#endif
+
+
+/*
+ *    Accelerated Functions used by the low level console driver
+ */
+
+static void retz3_bitblt(struct display *p,
+			 unsigned short curx, unsigned short cury, unsigned
+			 short destx, unsigned short desty, unsigned short
+			 width, unsigned short height, unsigned short cmd,
+			 unsigned short mask);
+
+/*
+ *   Hardware Specific Routines
+ */
+
+static int retz3_encode_fix(struct fb_info *info,
+			    struct fb_fix_screeninfo *fix,
+			    struct retz3fb_par *par);
+static int retz3_decode_var(struct fb_var_screeninfo *var,
+			    struct retz3fb_par *par);
+static int retz3_encode_var(struct fb_var_screeninfo *var,
+			    struct retz3fb_par *par);
+static int retz3_getcolreg(unsigned int regno, unsigned int *red,
+			   unsigned int *green, unsigned int *blue,
+			   unsigned int *transp, struct fb_info *info);
+
+/*
+ *    Internal routines
+ */
+
+static void retz3fb_get_par(struct fb_info *info, struct retz3fb_par *par);
+static void retz3fb_set_par(struct fb_info *info, struct retz3fb_par *par);
+static int do_fb_set_var(struct fb_info *info,
+			 struct fb_var_screeninfo *var, int isactive);
+static void retz3fb_set_disp(int con, struct fb_info *info);
+static int get_video_mode(const char *name);
+
+
+/* -------------------- Hardware specific routines ------------------------- */
+
+static unsigned short find_fq(unsigned int freq)
+{
+	unsigned long f;
+	long tmp;
+	long prev = 0x7fffffff;
+	long n2, n1 = 3;
+	unsigned long m;
+	unsigned short res = 0;
+
+	if (freq <= 31250000)
+		n2 = 3;
+	else if (freq <= 62500000)
+		n2 = 2;
+	else if (freq <= 125000000)
+		n2 = 1;
+	else if (freq <= 250000000)
+		n2 = 0;
+	else
+		return 0;
+
+
+	do {
+		f = freq >> (10 - n2);
+
+		m = (f * n1) / (14318180/1024);
+
+		if (m > 129)
+			break;
+
+		tmp =  (((m * 14318180) >> n2) / n1) - freq;
+		if (tmp < 0)
+			tmp = -tmp;
+
+		if (tmp < prev) {
+			prev = tmp;
+			res = (((n2 << 5) | (n1-2)) << 8) | (m-2);
+		}
+
+	} while ( (++n1) <= 21);
+
+	return res;
+}
+
+
+static int retz3_set_video(struct fb_info *info,
+			   struct fb_var_screeninfo *var,
+			   struct retz3fb_par *par)
+{
+	volatile unsigned char *regs = retz3info(info)->regs;
+	unsigned int freq;
+
+	int xres, hfront, hsync, hback;
+	int yres, vfront, vsync, vback;
+	unsigned char tmp;
+	unsigned short best_freq;
+	struct display_data data;
+
+	short clocksel = 0; /* Apparantly this is always zero */
+
+	int bpp = var->bits_per_pixel;
+
+	/*
+	 * XXX
+	 */
+	if (bpp == 24)
+		return 0;
+
+	if ((bpp != 8) && (bpp != 16) && (bpp != 24))
+		return -EFAULT;
+
+	par->xoffset = 0;
+	par->yoffset = 0;
+
+	xres   = var->xres * bpp / 4;
+	hfront = var->right_margin * bpp / 4;
+	hsync  = var->hsync_len * bpp / 4;
+	hback  = var->left_margin * bpp / 4;
+
+	if (var->vmode & FB_VMODE_DOUBLE)
+	{
+		yres = var->yres * 2;
+		vfront = var->lower_margin * 2;
+		vsync  = var->vsync_len * 2;
+		vback  = var->upper_margin * 2;
+	}
+	else if (var->vmode & FB_VMODE_INTERLACED)
+	{
+		yres   = (var->yres + 1) / 2;
+		vfront = (var->lower_margin + 1) / 2;
+		vsync  = (var->vsync_len + 1) / 2;
+		vback  = (var->upper_margin + 1) / 2;
+	}
+	else
+	{
+		yres   = var->yres; /* -1 ? */
+		vfront = var->lower_margin;
+		vsync  = var->vsync_len;
+		vback  = var->upper_margin;
+	}
+
+	data.h_total	= (hback / 8) + (xres / 8)
+			+ (hfront / 8) + (hsync / 8) - 1 /* + 1 */;
+	data.h_dispend	= ((xres + bpp - 1)/ 8) - 1;
+	data.h_bstart	= xres / 8 - 1 /* + 1 */;
+
+	data.h_bstop	= data.h_total+1 + 2 + 1;
+	data.h_sstart	= (xres / 8) + (hfront / 8) + 1;
+	data.h_sstop	= (xres / 8) + (hfront / 8) + (hsync / 8) + 1;
+
+	data.v_total	= yres + vfront + vsync + vback - 1;
+
+	data.v_dispend	= yres - 1;
+	data.v_bstart	= yres - 1;
+
+	data.v_bstop	= data.v_total;
+	data.v_sstart	= yres + vfront - 1 - 2;
+	data.v_sstop	= yres + vfront + vsync - 1;
+
+#if 0 /* testing */
+
+	printk("HBS: %i\n", data.h_bstart);
+	printk("HSS: %i\n", data.h_sstart);
+	printk("HSE: %i\n", data.h_sstop);
+	printk("HBE: %i\n", data.h_bstop);
+	printk("HT: %i\n", data.h_total);
+
+	printk("hsync: %i\n", hsync);
+	printk("hfront: %i\n", hfront);
+	printk("hback: %i\n", hback);
+
+	printk("VBS: %i\n", data.v_bstart);
+	printk("VSS: %i\n", data.v_sstart);
+	printk("VSE: %i\n", data.v_sstop);
+	printk("VBE: %i\n", data.v_bstop);
+	printk("VT: %i\n", data.v_total);
+
+	printk("vsync: %i\n", vsync);
+	printk("vfront: %i\n", vfront);
+	printk("vback: %i\n", vback);
+#endif
+
+	if (data.v_total >= 1024)
+		printk(KERN_ERR "MAYDAY: v_total >= 1024; bailing out!\n");
+
+	reg_w(regs, GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04));
+	reg_w(regs, GREG_FEATURE_CONTROL_W, 0x00);
+
+	seq_w(regs, SEQ_RESET, 0x00);
+	seq_w(regs, SEQ_RESET, 0x03);	/* reset sequencer logic */
+
+	/*
+	 * CLOCKING_MODE bits:
+	 * 2: This one is only set for certain text-modes, wonder if
+	 *    it may be for EGA-lines? (it was referred to as CLKDIV2)
+	 * (The CL drivers sets it to 0x21 with the comment:
+	 *  FullBandwidth (video off) and 8/9 dot clock)
+	 */
+	seq_w(regs, SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */);
+
+	seq_w(regs, SEQ_MAP_MASK, 0x0f);        /* enable writing to plane 0-3 */
+	seq_w(regs, SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */
+	seq_w(regs, SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/
+	seq_w(regs, SEQ_RESET, 0x01);
+	seq_w(regs, SEQ_RESET, 0x03);
+
+	seq_w(regs, SEQ_EXTENDED_ENABLE, 0x05);
+
+	seq_w(regs, SEQ_CURSOR_CONTROL, 0x00);	/* disable cursor */
+	seq_w(regs, SEQ_PRIM_HOST_OFF_HI, 0x00);
+	seq_w(regs, SEQ_PRIM_HOST_OFF_HI, 0x00);
+	seq_w(regs, SEQ_LINEAR_0, 0x4a);
+	seq_w(regs, SEQ_LINEAR_1, 0x00);
+
+	seq_w(regs, SEQ_SEC_HOST_OFF_HI, 0x00);
+	seq_w(regs, SEQ_SEC_HOST_OFF_LO, 0x00);
+	seq_w(regs, SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40);
+
+	/*
+	 * The lower 4 bits (0-3) are used to set the font-width for
+	 * text-mode - DON'T try to set this for gfx-mode.
+	 */
+	seq_w(regs, SEQ_EXT_CLOCK_MODE, 0x10);
+	seq_w(regs, SEQ_EXT_VIDEO_ADDR, 0x03);
+
+	/*
+	 * Extended Pixel Control:
+	 * bit 0:   text-mode=0, gfx-mode=1 (Graphics Byte ?)
+	 * bit 1: (Packed/Nibble Pixel Format ?)
+	 * bit 4-5: depth, 0=1-8bpp, 1=9-16bpp, 2=17-24bpp
+	 */
+	seq_w(regs, SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4));
+
+	seq_w(regs, SEQ_BUS_WIDTH_FEEDB, 0x04);
+	seq_w(regs, SEQ_COLOR_EXP_WFG, 0x01);
+	seq_w(regs, SEQ_COLOR_EXP_WBG, 0x00);
+	seq_w(regs, SEQ_EXT_RW_CONTROL, 0x00);
+	seq_w(regs, SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8)));
+	seq_w(regs, SEQ_COLOR_KEY_CNTL, 0x40);
+	seq_w(regs, SEQ_COLOR_KEY_MATCH0, 0x00);
+	seq_w(regs, SEQ_COLOR_KEY_MATCH1, 0x00);
+	seq_w(regs, SEQ_COLOR_KEY_MATCH2, 0x00);
+	seq_w(regs, SEQ_CRC_CONTROL, 0x00);
+	seq_w(regs, SEQ_PERF_SELECT, 0x10);
+	seq_w(regs, SEQ_ACM_APERTURE_1, 0x00);
+	seq_w(regs, SEQ_ACM_APERTURE_2, 0x30);
+	seq_w(regs, SEQ_ACM_APERTURE_3, 0x00);
+	seq_w(regs, SEQ_MEMORY_MAP_CNTL, 0x03);
+
+
+	/* unlock register CRT0..CRT7 */
+	crt_w(regs, CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20);
+
+	/* Zuerst zu schreibende Werte nur per printk ausgeben */
+	DEBUG printk("CRT_HOR_TOTAL: %ld\n", data.h_total);
+	crt_w(regs, CRT_HOR_TOTAL, data.h_total & 0xff);
+
+	DEBUG printk("CRT_HOR_DISP_ENA_END: %ld\n", data.h_dispend);
+	crt_w(regs, CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff);
+
+	DEBUG printk("CRT_START_HOR_BLANK: %ld\n", data.h_bstart);
+	crt_w(regs, CRT_START_HOR_BLANK, data.h_bstart & 0xff);
+
+	DEBUG printk("CRT_END_HOR_BLANK: 128+%ld\n", data.h_bstop % 32);
+	crt_w(regs, CRT_END_HOR_BLANK,  0x80 | (data.h_bstop & 0x1f));
+
+	DEBUG printk("CRT_START_HOR_RETR: %ld\n", data.h_sstart);
+	crt_w(regs, CRT_START_HOR_RETR, data.h_sstart & 0xff);
+
+	tmp = (data.h_sstop & 0x1f);
+	if (data.h_bstop & 0x20)
+		tmp |= 0x80;
+	DEBUG printk("CRT_END_HOR_RETR: %d\n", tmp);
+	crt_w(regs, CRT_END_HOR_RETR, tmp);
+
+	DEBUG printk("CRT_VER_TOTAL: %ld\n", data.v_total & 0xff);
+	crt_w(regs, CRT_VER_TOTAL, (data.v_total & 0xff));
+
+	tmp = 0x10;  /* LineCompare bit #9 */
+	if (data.v_total & 256)
+		tmp |= 0x01;
+	if (data.v_dispend & 256)
+		tmp |= 0x02;
+	if (data.v_sstart & 256)
+		tmp |= 0x04;
+	if (data.v_bstart & 256)
+		tmp |= 0x08;
+	if (data.v_total & 512)
+		tmp |= 0x20;
+	if (data.v_dispend & 512)
+		tmp |= 0x40;
+	if (data.v_sstart & 512)
+		tmp |= 0x80;
+	DEBUG printk("CRT_OVERFLOW: %d\n", tmp);
+	crt_w(regs, CRT_OVERFLOW, tmp);
+
+	crt_w(regs, CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */
+
+	tmp = 0x40; /* LineCompare bit #8 */
+	if (data.v_bstart & 512)
+		tmp |= 0x20;
+	if (var->vmode & FB_VMODE_DOUBLE)
+		tmp |= 0x80;
+ 	DEBUG printk("CRT_MAX_SCAN_LINE: %d\n", tmp);
+	crt_w(regs, CRT_MAX_SCAN_LINE, tmp);
+
+	crt_w(regs, CRT_CURSOR_START, 0x00);
+	crt_w(regs, CRT_CURSOR_END, 8 & 0x1f); /* font height */
+
+	crt_w(regs, CRT_START_ADDR_HIGH, 0x00);
+	crt_w(regs, CRT_START_ADDR_LOW, 0x00);
+
+	crt_w(regs, CRT_CURSOR_LOC_HIGH, 0x00);
+	crt_w(regs, CRT_CURSOR_LOC_LOW, 0x00);
+
+ 	DEBUG printk("CRT_START_VER_RETR: %ld\n", data.v_sstart & 0xff);
+	crt_w(regs, CRT_START_VER_RETR, (data.v_sstart & 0xff));
+
+#if 1
+	/* 5 refresh cycles per scanline */
+	DEBUG printk("CRT_END_VER_RETR: 64+32+%ld\n", data.v_sstop % 16);
+	crt_w(regs, CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20));
+#else
+	DEBUG printk("CRT_END_VER_RETR: 128+32+%ld\n", data.v_sstop % 16);
+	crt_w(regs, CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32));
+#endif
+	DEBUG printk("CRT_VER_DISP_ENA_END: %ld\n", data.v_dispend & 0xff);
+	crt_w(regs, CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff));
+
+	DEBUG printk("CRT_START_VER_BLANK: %ld\n", data.v_bstart & 0xff);
+	crt_w(regs, CRT_START_VER_BLANK, (data.v_bstart & 0xff));
+
+	DEBUG printk("CRT_END_VER_BLANK: %ld\n", data.v_bstop & 0xff);
+	crt_w(regs, CRT_END_VER_BLANK, (data.v_bstop & 0xff));
+
+	DEBUG printk("CRT_MODE_CONTROL: 0xe3\n");
+	crt_w(regs, CRT_MODE_CONTROL, 0xe3);
+
+	DEBUG printk("CRT_LINE_COMPARE: 0xff\n");
+	crt_w(regs, CRT_LINE_COMPARE, 0xff);
+
+	tmp = (var->xres_virtual / 8) * (bpp / 8);
+	crt_w(regs, CRT_OFFSET, tmp);
+
+	crt_w(regs, CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */
+
+	tmp = 0x20;			/* Enable extended end bits */
+	if (data.h_total & 0x100)
+		tmp |= 0x01;
+	if ((data.h_dispend) & 0x100)
+		tmp |= 0x02;
+	if (data.h_bstart & 0x100)
+		tmp |= 0x04;
+	if (data.h_sstart & 0x100)
+		tmp |= 0x08;
+	if (var->vmode & FB_VMODE_INTERLACED)
+		tmp |= 0x10;
+ 	DEBUG printk("CRT_EXT_HOR_TIMING1: %d\n", tmp);
+	crt_w(regs, CRT_EXT_HOR_TIMING1, tmp);
+
+	tmp = 0x00;
+	if (((var->xres_virtual / 8) * (bpp / 8)) & 0x100)
+		tmp |= 0x10;
+	crt_w(regs, CRT_EXT_START_ADDR, tmp);
+
+	tmp = 0x00;
+	if (data.h_total & 0x200)
+		tmp |= 0x01;
+	if ((data.h_dispend) & 0x200)
+		tmp |= 0x02;
+	if (data.h_bstart & 0x200)
+		tmp |= 0x04;
+	if (data.h_sstart & 0x200)
+		tmp |= 0x08;
+	tmp |= ((data.h_bstop & 0xc0) >> 2);
+	tmp |= ((data.h_sstop & 0x60) << 1);
+	crt_w(regs, CRT_EXT_HOR_TIMING2, tmp);
+ 	DEBUG printk("CRT_EXT_HOR_TIMING2: %d\n", tmp);
+
+	tmp = 0x10;			/* Line compare bit 10 */
+	if (data.v_total & 0x400)
+		tmp |= 0x01;
+	if ((data.v_dispend) & 0x400)
+		tmp |= 0x02;
+	if (data.v_bstart & 0x400)
+		tmp |= 0x04;
+	if (data.v_sstart & 0x400)
+		tmp |= 0x08;
+	tmp |= ((data.v_bstop & 0x300) >> 3);
+	if (data.v_sstop & 0x10)
+		tmp |= 0x80;
+	crt_w(regs, CRT_EXT_VER_TIMING, tmp);
+ 	DEBUG printk("CRT_EXT_VER_TIMING: %d\n", tmp);
+
+	crt_w(regs, CRT_MONITOR_POWER, 0x00);
+
+	/*
+	 * Convert from ps to Hz.
+	 */
+	freq = 2000000000 / var->pixclock;
+	freq = freq * 500;
+
+	best_freq = find_fq(freq);
+	pll_w(regs, 0x02, best_freq);
+	best_freq = find_fq(61000000);
+	pll_w(regs, 0x0a, best_freq);
+	pll_w(regs, 0x0e, 0x22);
+
+	gfx_w(regs, GFX_SET_RESET, 0x00);
+	gfx_w(regs, GFX_ENABLE_SET_RESET, 0x00);
+	gfx_w(regs, GFX_COLOR_COMPARE, 0x00);
+	gfx_w(regs, GFX_DATA_ROTATE, 0x00);
+	gfx_w(regs, GFX_READ_MAP_SELECT, 0x00);
+	gfx_w(regs, GFX_GRAPHICS_MODE, 0x00);
+	gfx_w(regs, GFX_MISC, 0x05);
+	gfx_w(regs, GFX_COLOR_XCARE, 0x0f);
+	gfx_w(regs, GFX_BITMASK, 0xff);
+
+	reg_r(regs, ACT_ADDRESS_RESET);
+	attr_w(regs, ACT_PALETTE0 , 0x00);
+	attr_w(regs, ACT_PALETTE1 , 0x01);
+	attr_w(regs, ACT_PALETTE2 , 0x02);
+	attr_w(regs, ACT_PALETTE3 , 0x03);
+	attr_w(regs, ACT_PALETTE4 , 0x04);
+	attr_w(regs, ACT_PALETTE5 , 0x05);
+	attr_w(regs, ACT_PALETTE6 , 0x06);
+	attr_w(regs, ACT_PALETTE7 , 0x07);
+	attr_w(regs, ACT_PALETTE8 , 0x08);
+	attr_w(regs, ACT_PALETTE9 , 0x09);
+	attr_w(regs, ACT_PALETTE10, 0x0a);
+	attr_w(regs, ACT_PALETTE11, 0x0b);
+	attr_w(regs, ACT_PALETTE12, 0x0c);
+	attr_w(regs, ACT_PALETTE13, 0x0d);
+	attr_w(regs, ACT_PALETTE14, 0x0e);
+	attr_w(regs, ACT_PALETTE15, 0x0f);
+	reg_r(regs, ACT_ADDRESS_RESET);
+
+	attr_w(regs, ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */
+
+	attr_w(regs, ACT_OVERSCAN_COLOR, 0x00);
+	attr_w(regs, ACT_COLOR_PLANE_ENA, 0x0f);
+	attr_w(regs, ACT_HOR_PEL_PANNING, 0x00);
+	attr_w(regs, ACT_COLOR_SELECT, 0x00);
+
+	reg_r(regs, ACT_ADDRESS_RESET);
+	reg_w(regs, ACT_DATA, 0x20);
+
+	reg_w(regs, VDAC_MASK, 0xff);
+
+	/*
+	 * Extended palette addressing ???
+	 */
+	switch (bpp){
+	case 8:
+		reg_w(regs, 0x83c6, 0x00);
+		break;
+	case 16:
+		reg_w(regs, 0x83c6, 0x60);
+		break;
+	case 24:
+		reg_w(regs, 0x83c6, 0xe0);
+		break;
+	default:
+		printk(KERN_INFO "Illegal color-depth: %i\n", bpp);
+	}
+
+	reg_w(regs, VDAC_ADDRESS, 0x00);
+
+	seq_w(regs, SEQ_MAP_MASK, 0x0f );
+
+	return 0;
+}
+
+
+/*
+ *    This function should fill in the `fix' structure based on the
+ *    values in the `par' structure.
+ */
+
+static int retz3_encode_fix(struct fb_info *info,
+			    struct fb_fix_screeninfo *fix,
+			    struct retz3fb_par *par)
+{
+	struct retz3_fb_info *zinfo = retz3info(info);
+
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+	strcpy(fix->id, retz3fb_name);
+	fix->smem_start = zinfo->physfbmem;
+	fix->smem_len = zinfo->fbsize;
+	fix->mmio_start = zinfo->physregs;
+	fix->mmio_len = 0x00c00000;
+
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->type_aux = 0;
+	if (par->bpp == 8)
+		fix->visual = FB_VISUAL_PSEUDOCOLOR;
+	else
+		fix->visual = FB_VISUAL_TRUECOLOR;
+
+	fix->xpanstep = 0;
+	fix->ypanstep = 0;
+	fix->ywrapstep = 0;
+	fix->line_length = 0;
+
+	fix->accel = FB_ACCEL_NCR_77C32BLT;
+
+	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.
+ */
+
+static int retz3_decode_var(struct fb_var_screeninfo *var,
+			    struct retz3fb_par *par)
+{
+	par->xres = var->xres;
+	par->yres = var->yres;
+	par->xres_vir = var->xres_virtual;
+	par->yres_vir = var->yres_virtual;
+	par->bpp = var->bits_per_pixel;
+	par->pixclock = var->pixclock;
+	par->vmode = var->vmode;
+
+	par->red = var->red;
+	par->green = var->green;
+	par->blue = var->blue;
+	par->transp = var->transp;
+
+	par->left_margin = var->left_margin;
+	par->right_margin = var->right_margin;
+	par->upper_margin = var->upper_margin;
+	par->lower_margin = var->lower_margin;
+	par->hsync_len = var->hsync_len;
+	par->vsync_len = var->vsync_len;
+
+	if (var->accel_flags & FB_ACCELF_TEXT)
+	    par->accel = FB_ACCELF_TEXT;
+	else
+	    par->accel = 0;
+
+	return 0;
+}
+
+
+/*
+ *    Fill the `var' structure based on the values in `par' and maybe
+ *    other values read out of the hardware.
+ */
+
+static int retz3_encode_var(struct fb_var_screeninfo *var,
+			    struct retz3fb_par *par)
+{
+	memset(var, 0, sizeof(struct fb_var_screeninfo));
+	var->xres = par->xres;
+	var->yres = par->yres;
+	var->xres_virtual = par->xres_vir;
+	var->yres_virtual = par->yres_vir;
+	var->xoffset = 0;
+	var->yoffset = 0;
+
+	var->bits_per_pixel = par->bpp;
+	var->grayscale = 0;
+
+	var->red = par->red;
+	var->green = par->green;
+	var->blue = par->blue;
+	var->transp = par->transp;
+
+	var->nonstd = 0;
+	var->activate = 0;
+
+	var->height = -1;
+	var->width = -1;
+
+	var->accel_flags = (par->accel && par->bpp == 8) ? FB_ACCELF_TEXT : 0;
+
+	var->pixclock = par->pixclock;
+
+	var->sync = 0;				/* ??? */
+	var->left_margin = par->left_margin;
+	var->right_margin = par->right_margin;
+	var->upper_margin = par->upper_margin;
+	var->lower_margin = par->lower_margin;
+	var->hsync_len = par->hsync_len;
+	var->vsync_len = par->vsync_len;
+
+	var->vmode = par->vmode;
+	return 0;
+}
+
+
+/*
+ *    Set a single color register. Return != 0 for invalid regno.
+ */
+
+static int retz3fb_setcolreg(unsigned int regno, unsigned int red,
+			     unsigned int green, unsigned int blue,
+			     unsigned int transp, struct fb_info *info)
+{
+	struct retz3_fb_info *zinfo = retz3info(info);
+	volatile unsigned char *regs = zinfo->regs;
+
+	/* We'll get to this */
+
+	if (regno > 255)
+		return 1;
+
+	red >>= 10;
+	green >>= 10;
+	blue >>= 10;
+
+	zinfo->color_table[regno][0] = red;
+	zinfo->color_table[regno][1] = green;
+	zinfo->color_table[regno][2] = blue;
+
+	reg_w(regs, VDAC_ADDRESS_W, regno);
+	reg_w(regs, VDAC_DATA, red);
+	reg_w(regs, VDAC_DATA, green);
+	reg_w(regs, VDAC_DATA, blue);
+
+	return 0;
+}
+
+
+/*
+ *    Read a single color register and split it into
+ *    colors/transparent. Return != 0 for invalid regno.
+ */
+
+static int retz3_getcolreg(unsigned int regno, unsigned int *red,
+			   unsigned int *green, unsigned int *blue,
+			   unsigned int *transp, struct fb_info *info)
+{
+	struct retz3_fb_info *zinfo = retz3info(info);
+	int t;
+
+	if (regno > 255)
+		return 1;
+	t       = zinfo->color_table[regno][0];
+	*red    = (t<<10) | (t<<4) | (t>>2);
+	t       = zinfo->color_table[regno][1];
+	*green  = (t<<10) | (t<<4) | (t>>2);
+	t       = zinfo->color_table[regno][2];
+	*blue   = (t<<10) | (t<<4) | (t>>2);
+	*transp = 0;
+	return 0;
+}
+
+
+static inline void retz3_busy(struct display *p)
+{
+	struct retz3_fb_info *zinfo = retz3info(p->fb_info);
+	volatile unsigned char *acm = zinfo->base + ACM_OFFSET;
+	unsigned char blt_status;
+
+	if (zinfo->blitbusy) {
+		do{
+			blt_status = *((acm) + (ACM_START_STATUS + 2));
+		}while ((blt_status & 1) == 0);
+		zinfo->blitbusy = 0;
+	}
+}
+
+
+static void retz3_bitblt (struct display *p,
+			  unsigned short srcx, unsigned short srcy,
+			  unsigned short destx, unsigned short desty,
+			  unsigned short width, unsigned short height,
+			  unsigned short cmd, unsigned short mask)
+{
+	struct fb_var_screeninfo *var = &p->var;
+	struct retz3_fb_info *zinfo = retz3info(p->fb_info);
+	volatile unsigned long *acm = (unsigned long *)(zinfo->base + ACM_OFFSET);
+	unsigned long *pattern = (unsigned long *)(zinfo->fbmem + PAT_MEM_OFF);
+
+	unsigned short mod;
+	unsigned long tmp;
+	unsigned long pat, src, dst;
+
+	int i, xres_virtual = var->xres_virtual;
+	short bpp = (var->bits_per_pixel & 0xff);
+
+	if (bpp < 8)
+		bpp = 8;
+
+	tmp = mask | (mask << 16);
+
+	retz3_busy(p);
+
+	i = 0;
+	do{
+		*pattern++ = tmp;
+	}while(i++ < bpp/4);
+
+	tmp = cmd << 8;
+	*(acm + ACM_RASTEROP_ROTATION/4) = tmp;
+
+	mod = 0xc0c2;
+
+	pat = 8 * PAT_MEM_OFF;
+	dst = bpp * (destx + desty * xres_virtual);
+
+	/*
+	 * Source is not set for clear.
+	 */
+	if ((cmd != Z3BLTclear) && (cmd != Z3BLTset)) {
+		src = bpp * (srcx + srcy * xres_virtual);
+
+		if (destx > srcx) {
+			mod &= ~0x8000;
+			src += bpp * (width - 1);
+			dst += bpp * (width - 1);
+			pat += bpp * 2;
+		}
+		if (desty > srcy) {
+			mod &= ~0x4000;
+			src += bpp * (height - 1) * xres_virtual;
+			dst += bpp * (height - 1) * xres_virtual;
+			pat += bpp * 4;
+		}
+
+		*(acm + ACM_SOURCE/4) = cpu_to_le32(src);
+	}
+
+	*(acm + ACM_PATTERN/4) = cpu_to_le32(pat);
+
+	*(acm + ACM_DESTINATION/4) = cpu_to_le32(dst);
+
+	tmp = mod << 16;
+	*(acm + ACM_CONTROL/4) = tmp;
+
+	tmp  = width | (height << 16);
+
+	*(acm + ACM_BITMAP_DIMENSION/4) = cpu_to_le32(tmp);
+
+	*(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x00;
+	*(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x01;
+	zinfo->blitbusy = 1;
+}
+
+#if 0
+/*
+ * Move cursor to x, y
+ */
+static void retz3_MoveCursor (unsigned short x, unsigned short y)
+{
+	/* Guess we gotta deal with the cursor at some point */
+}
+#endif
+
+
+/*
+ *    Fill the hardware's `par' structure.
+ */
+
+static void retz3fb_get_par(struct fb_info *info, struct retz3fb_par *par)
+{
+	struct retz3_fb_info *zinfo = retz3info(info);
+
+	if (zinfo->current_par_valid)
+		*par = zinfo->current_par;
+	else
+		retz3_decode_var(&retz3fb_default, par);
+}
+
+
+static void retz3fb_set_par(struct fb_info *info, struct retz3fb_par *par)
+{
+	struct retz3_fb_info *zinfo = retz3info(info);
+
+	zinfo->current_par = *par;
+	zinfo->current_par_valid = 1;
+}
+
+
+static int do_fb_set_var(struct fb_info *info,
+			 struct fb_var_screeninfo *var, int isactive)
+{
+	int err, activate;
+	struct retz3fb_par par;
+	struct retz3_fb_info *zinfo = retz3info(info);
+
+	if ((err = retz3_decode_var(var, &par)))
+		return err;
+	activate = var->activate;
+
+	/* XXX ... what to do about isactive ? */
+
+	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
+		retz3fb_set_par(info, &par);
+	retz3_encode_var(var, &par);
+	var->activate = activate;
+
+	retz3_set_video(info, var, &zinfo->current_par);
+
+	return 0;
+}
+
+/*
+ *    Get the Fixed Part of the Display
+ */
+
+static int retz3fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			   struct fb_info *info)
+{
+	struct retz3fb_par par;
+	int error = 0;
+
+	if (con == -1)
+		retz3fb_get_par(info, &par);
+	else
+		error = retz3_decode_var(&fb_display[con].var, &par);
+	return(error ? error : retz3_encode_fix(info, fix, &par));
+}
+
+
+/*
+ *    Get the User Defined Part of the Display
+ */
+
+static int retz3fb_get_var(struct fb_var_screeninfo *var, int con,
+			   struct fb_info *info)
+{
+	struct retz3fb_par par;
+	int error = 0;
+
+	if (con == -1) {
+		retz3fb_get_par(info, &par);
+		error = retz3_encode_var(var, &par);
+	} else
+		*var = fb_display[con].var;
+	return error;
+}
+
+
+static void retz3fb_set_disp(int con, struct fb_info *info)
+{
+	struct fb_fix_screeninfo fix;
+	struct display *display;
+	struct retz3_fb_info *zinfo = retz3info(info);
+
+	if (con >= 0)
+		display = &fb_display[con];
+	else
+		display = &zinfo->disp;	/* used during initialization */
+
+	retz3fb_get_fix(&fix, con, info);
+
+	if (con == -1)
+		con = 0;
+
+	display->visual = fix.visual;
+	display->type = fix.type;
+	display->type_aux = fix.type_aux;
+	display->ypanstep = fix.ypanstep;
+	display->ywrapstep = fix.ywrapstep;
+	display->can_soft_blank = 1;
+	display->inverse = z3fb_inverse;
+
+	/*
+	 * This seems to be about 20% faster.
+	 */
+	display->scrollmode = SCROLL_YREDRAW;
+
+	switch (display->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		if (display->var.accel_flags & FB_ACCELF_TEXT) {
+		    display->dispsw = &fbcon_retz3_8;
+		    retz3_set_video(info, &display->var, &zinfo->current_par);
+		} else
+		    display->dispsw = &fbcon_cfb8;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		display->dispsw = &fbcon_cfb16;
+		break;
+#endif
+	default:
+		display->dispsw = &fbcon_dummy;
+		break;
+	}
+}
+
+
+/*
+ *    Set the User Defined Part of the Display
+ */
+
+static int retz3fb_set_var(struct fb_var_screeninfo *var, int con,
+			   struct fb_info *info)
+{
+	int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel;
+	struct display *display;
+	struct retz3_fb_info *zinfo = retz3info(info);
+
+	if (con >= 0)
+		display = &fb_display[con];
+	else
+		display = &zinfo->disp;	/* used during initialization */
+
+	if ((err = do_fb_set_var(info, var, con == info->currcon)))
+		return err;
+	if ((var->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;
+		oldaccel = display->var.accel_flags;
+		display->var = *var;
+
+		if (oldxres != var->xres || oldyres != var->yres ||
+		    oldvxres != var->xres_virtual ||
+		    oldvyres != var->yres_virtual ||
+		    oldbpp != var->bits_per_pixel ||
+		    oldaccel != var->accel_flags) {
+
+			struct fb_fix_screeninfo fix;
+			retz3fb_get_fix(&fix, con, info);
+
+			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 = z3fb_inverse;
+			switch (display->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
+			case 8:
+				if (var->accel_flags & FB_ACCELF_TEXT) {
+					display->dispsw = &fbcon_retz3_8;
+				} else
+					display->dispsw = &fbcon_cfb8;
+				break;
+#endif
+#ifdef FBCON_HAS_CFB16
+			case 16:
+				display->dispsw = &fbcon_cfb16;
+				break;
+#endif
+			default:
+				display->dispsw = &fbcon_dummy;
+				break;
+			}
+			/*
+			 * We still need to find a way to tell the X
+			 * server that the video mem has been fiddled with
+			 * so it redraws the entire screen when switching
+			 * between X and a text console.
+			 */
+			retz3_set_video(info, var, &zinfo->current_par);
+
+			if (info->changevar)
+				(*info->changevar)(con);
+		}
+
+		if (oldbpp != var->bits_per_pixel) {
+			if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
+				return err;
+			do_install_cmap(con, info);
+		}
+	}
+	return 0;
+}
+
+
+/*
+ *    Get the Colormap
+ */
+
+static int retz3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			    struct fb_info *info)
+{
+	if (con == info->currcon) /* current console? */
+		return(fb_get_cmap(cmap, kspc, retz3_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;
+}
+
+/*
+ *    Blank the display.
+ */
+
+static int retz3fb_blank(int blank, struct fb_info *info)
+{
+	struct retz3_fb_info *zinfo = retz3info(info);
+	volatile unsigned char *regs = retz3info(info)->regs;
+	short i;
+
+	if (blank)
+		for (i = 0; i < 256; i++){
+			reg_w(regs, VDAC_ADDRESS_W, i);
+			reg_w(regs, VDAC_DATA, 0);
+			reg_w(regs, VDAC_DATA, 0);
+			reg_w(regs, VDAC_DATA, 0);
+		}
+	else
+		for (i = 0; i < 256; i++){
+			reg_w(regs, VDAC_ADDRESS_W, i);
+			reg_w(regs, VDAC_DATA, zinfo->color_table[i][0]);
+			reg_w(regs, VDAC_DATA, zinfo->color_table[i][1]);
+			reg_w(regs, VDAC_DATA, zinfo->color_table[i][2]);
+		}
+	return 0;
+}
+
+static struct fb_ops retz3fb_ops = {
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	retz3fb_get_fix,
+	.fb_get_var =	retz3fb_get_var,
+	.fb_set_var =	retz3fb_set_var,
+	.fb_get_cmap =	retz3fb_get_cmap,
+	.fb_set_cmap =	gen_set_cmap,
+	.fb_setcolreg =	retz3fb_setcolreg,
+	.fb_blank =	retz3fb_blank,
+};
+
+int __init retz3fb_setup(char *options)
+{
+	char *this_opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt)
+			continue;
+		if (!strcmp(this_opt, "inverse")) {
+			z3fb_inverse = 1;
+			fb_invert_cmaps();
+		} else if (!strncmp(this_opt, "font:", 5)) {
+			strlcpy(fontname, this_opt+5, sizeof(fontname));
+		} else
+			z3fb_mode = get_video_mode(this_opt);
+	}
+	return 0;
+}
+
+
+/*
+ *    Initialization
+ */
+
+int __init retz3fb_init(void)
+{
+	unsigned long board_addr, board_size;
+	struct zorro_dev *z = NULL;
+	volatile unsigned char *regs;
+	struct retz3fb_par par;
+	struct retz3_fb_info *zinfo;
+	struct fb_info *fb_info;
+	short i;
+	int res = -ENXIO;
+
+	while ((z = zorro_find_device(ZORRO_PROD_MACROSYSTEMS_RETINA_Z3, z))) {
+		board_addr = z->resource.start;
+		board_size = z->resource.end-z->resource.start+1;
+		if (!request_mem_region(board_addr, 0x0c00000,
+			    		"ncr77c32blt")) {
+			continue;
+		if (!request_mem_region(board_addr+VIDEO_MEM_OFFSET,
+			    		0x00400000, "RAM"))
+			release_mem_region(board_addr, 0x00c00000);
+			continue;
+		}
+		if (!(zinfo = kmalloc(sizeof(struct retz3_fb_info),
+				      GFP_KERNEL)))
+			return -ENOMEM;
+		memset(zinfo, 0, sizeof(struct retz3_fb_info));
+
+		zinfo->base = ioremap(board_addr, board_size);
+		zinfo->regs = zinfo->base;
+		zinfo->fbmem = zinfo->base + VIDEO_MEM_OFFSET;
+		/* Get memory size - for now we asume it's a 4MB board */
+		zinfo->fbsize = 0x00400000; /* 4 MB */
+		zinfo->physregs = board_addr;
+		zinfo->physfbmem = board_addr + VIDEO_MEM_OFFSET;
+
+		fb_info = fbinfo(zinfo);
+
+		for (i = 0; i < 256; i++){
+			for (i = 0; i < 256; i++){
+				zinfo->color_table[i][0] = i;
+				zinfo->color_table[i][1] = i;
+				zinfo->color_table[i][2] = i;
+			}
+		}
+
+		regs = zinfo->regs;
+		/* Disable hardware cursor */
+		seq_w(regs, SEQ_CURSOR_Y_INDEX, 0x00);
+
+		retz3fb_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, fb_info);
+		retz3fb_setcolreg (254, 0, 0, 0, 0, fb_info);
+
+		strcpy(fb_info->modename, retz3fb_name);
+		fb_info->changevar = NULL;
+		fb_info->fbops = &retz3fb_ops;
+		fb_info->screen_base = zinfo->fbmem;
+		fb_info->disp = &zinfo->disp;
+		fb_info->currcon = -1;
+		fb_info->switch_con = &z3fb_switch;
+		fb_info->updatevar = &z3fb_updatevar;
+		fb_info->flags = FBINFO_FLAG_DEFAULT;
+		strlcpy(fb_info->fontname, fontname, sizeof(fb_info->fontname));
+
+		if (z3fb_mode == -1)
+			retz3fb_default = retz3fb_predefined[0].var;
+
+		retz3_decode_var(&retz3fb_default, &par);
+		retz3_encode_var(&retz3fb_default, &par);
+
+		do_fb_set_var(fb_info, &retz3fb_default, 0);
+		retz3fb_get_var(&zinfo->disp.var, -1, fb_info);
+
+		retz3fb_set_disp(-1, fb_info);
+
+		do_install_cmap(0, fb_info);
+
+		if (register_framebuffer(fb_info) < 0)
+			return -EINVAL;
+
+		printk(KERN_INFO "fb%d: %s frame buffer device, using %ldK of "
+		       "video memory\n", fb_info->node,
+		       fb_info->modename, zinfo->fbsize>>10);
+
+		/* FIXME: This driver cannot be unloaded yet */
+		res = 0;
+	}
+	return res;
+}
+
+
+static int z3fb_switch(int con, struct fb_info *info)
+{
+	/* Do we have to save the colormap? */
+	if (fb_display[info->currcon].cmap.len)
+		fb_get_cmap(&fb_display[info->currcon].cmap, 1,
+			    retz3_getcolreg, info);
+
+	do_fb_set_var(info, &fb_display[con].var, 1);
+	info->currcon = con;
+	/* Install new colormap */
+	do_install_cmap(con, info);
+	return 0;
+}
+
+
+/*
+ *    Update the `var' structure (called by fbcon.c)
+ *
+ *    This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
+ *    Since it's called by a kernel driver, no range checking is done.
+ */
+
+static int z3fb_updatevar(int con, struct fb_info *info)
+{
+	return 0;
+}
+
+/*
+ *    Get a Video Mode
+ */
+
+static int __init get_video_mode(const char *name)
+{
+	short i;
+
+	for (i = 0; i < NUM_TOTAL_MODES; i++)
+		if (!strcmp(name, retz3fb_predefined[i].name)){
+			retz3fb_default = retz3fb_predefined[i].var;
+			return i;
+		}
+	return -1;
+}
+
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+
+int init_module(void)
+{
+	return retz3fb_init();
+}
+#endif
+
+
+/*
+ *  Text console acceleration
+ */
+
+#ifdef FBCON_HAS_CFB8
+static void retz3_8_bmove(struct display *p, int sy, int sx,
+			  int dy, int dx, int height, int width)
+{
+	int fontwidth = fontwidth(p);
+
+	sx *= fontwidth;
+	dx *= fontwidth;
+	width *= fontwidth;
+
+	retz3_bitblt(p,
+		     (unsigned short)sx,
+		     (unsigned short)(sy*fontheight(p)),
+		     (unsigned short)dx,
+		     (unsigned short)(dy*fontheight(p)),
+		     (unsigned short)width,
+		     (unsigned short)(height*fontheight(p)),
+		     Z3BLTcopy,
+		     0xffff);
+}
+
+static void retz3_8_clear(struct vc_data *conp, struct display *p,
+			  int sy, int sx, int height, int width)
+{
+	unsigned short col;
+	int fontwidth = fontwidth(p);
+
+	sx *= fontwidth;
+	width *= fontwidth;
+
+	col = attr_bgcol_ec(p, conp);
+	col &= 0xff;
+	col |= (col << 8);
+
+	retz3_bitblt(p,
+		     (unsigned short)sx,
+		     (unsigned short)(sy*fontheight(p)),
+		     (unsigned short)sx,
+		     (unsigned short)(sy*fontheight(p)),
+		     (unsigned short)width,
+		     (unsigned short)(height*fontheight(p)),
+		     Z3BLTset,
+		     col);
+}
+
+
+static void retz3_putc(struct vc_data *conp, struct display *p, int c,
+		       int yy, int xx)
+{
+	retz3_busy(p);
+	fbcon_cfb8_putc(conp, p, c, yy, xx);
+}
+
+
+static void retz3_putcs(struct vc_data *conp, struct display *p,
+			const unsigned short *s, int count,
+			int yy, int xx)
+{
+	retz3_busy(p);
+	fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
+}
+
+
+static void retz3_revc(struct display *p, int xx, int yy)
+{
+	retz3_busy(p);
+	fbcon_cfb8_revc(p, xx, yy);
+}
+
+
+static void retz3_clear_margins(struct vc_data* conp, struct display* p,
+				int bottom_only)
+{
+	retz3_busy(p);
+	fbcon_cfb8_clear_margins(conp, p, bottom_only);
+}
+
+
+static struct display_switch fbcon_retz3_8 = {
+	.setup		= fbcon_cfb8_setup,
+	.bmove		= retz3_8_bmove,
+	.clear		= retz3_8_clear,
+	.putc		= retz3_putc,
+	.putcs		= retz3_putcs,
+	.revc		= retz3_revc,
+	.clear_margins	= retz3_clear_margins,
+	.fontwidthmask	= FONTWIDTH(8)
+};
+#endif
diff --git a/drivers/video/retz3fb.h b/drivers/video/retz3fb.h
new file mode 100644
index 0000000..5cc7510
--- /dev/null
+++ b/drivers/video/retz3fb.h
@@ -0,0 +1,286 @@
+/*
+ * linux/drivers/video/retz3fb.h -- Defines and macros for the RetinaZ3 frame
+ *				    buffer device
+ *
+ *    Copyright (C) 1997 Jes Sorensen
+ *
+ * History:
+ *   - 22 Jan 97: Initial work
+ *
+ *
+ * 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.
+ */
+
+/*
+ * Macros to read and write to registers.
+ */
+#define reg_w(regs, reg,dat) (*(regs + reg) = dat)
+#define reg_r(regs, reg) (*(regs + reg))
+
+/*
+ * Macro to access the sequencer.
+ */
+#define seq_w(regs, sreg, sdat) \
+	do{ reg_w(regs, SEQ_IDX, sreg); reg_w(regs, SEQ_DATA, sdat); } while(0)
+
+/*
+ * Macro to access the CRT controller.
+ */
+#define crt_w(regs, creg, cdat) \
+	do{ reg_w(regs, CRT_IDX, creg); reg_w(regs, CRT_DATA, cdat); } while(0)
+
+/*
+ * Macro to access the graphics controller.
+ */
+#define gfx_w(regs, greg, gdat) \
+	do{ reg_w(regs, GFX_IDX, greg); reg_w(regs, GFX_DATA, gdat); } while(0)
+
+/*
+ * Macro to access the attribute controller.
+ */
+#define attr_w(regs, areg, adat) \
+	do{ reg_w(regs, ACT_IDX, areg); reg_w(regs, ACT_DATA, adat); } while(0)
+
+/*
+ * Macro to access the pll.
+ */
+#define pll_w(regs, preg, pdat) \
+	do{ reg_w(regs, PLL_IDX, preg); \
+	    reg_w(regs, PLL_DATA, (pdat & 0xff)); \
+	    reg_w(regs, PLL_DATA, (pdat >> 8));\
+	} while(0)
+
+/*
+ * Offsets
+ */
+#define VIDEO_MEM_OFFSET	0x00c00000
+#define ACM_OFFSET		0x00b00000
+
+/*
+ * Accelerator Control Menu
+ */
+#define ACM_PRIMARY_OFFSET	0x00
+#define ACM_SECONDARY_OFFSET	0x04
+#define ACM_MODE_CONTROL	0x08
+#define ACM_CURSOR_POSITION	0x0c
+#define ACM_START_STATUS	0x30
+#define ACM_CONTROL		0x34
+#define ACM_RASTEROP_ROTATION	0x38
+#define ACM_BITMAP_DIMENSION	0x3c
+#define ACM_DESTINATION		0x40
+#define ACM_SOURCE		0x44
+#define ACM_PATTERN		0x48
+#define ACM_FOREGROUND		0x4c
+#define ACM_BACKGROUND		0x50
+
+/*
+ * Video DAC addresses
+ */
+#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
+
+/*
+ * Sequencer
+ */
+#define SEQ_IDX			0x03c4	/* Sequencer Index */
+#define SEQ_DATA		0x03c5
+#define SEQ_RESET		0x00
+#define SEQ_CLOCKING_MODE	0x01
+#define SEQ_MAP_MASK		0x02
+#define SEQ_CHAR_MAP_SELECT	0x03
+#define SEQ_MEMORY_MODE		0x04
+#define SEQ_EXTENDED_ENABLE	0x05	/* NCR extensions */
+#define SEQ_UNKNOWN1         	0x06
+#define SEQ_UNKNOWN2         	0x07
+#define SEQ_CHIP_ID		0x08
+#define SEQ_UNKNOWN3         	0x09
+#define SEQ_CURSOR_COLOR1	0x0a
+#define SEQ_CURSOR_COLOR0	0x0b
+#define SEQ_CURSOR_CONTROL	0x0c
+#define SEQ_CURSOR_X_LOC_HI	0x0d
+#define SEQ_CURSOR_X_LOC_LO	0x0e
+#define SEQ_CURSOR_Y_LOC_HI	0x0f
+#define SEQ_CURSOR_Y_LOC_LO	0x10
+#define SEQ_CURSOR_X_INDEX	0x11
+#define SEQ_CURSOR_Y_INDEX	0x12
+#define SEQ_CURSOR_STORE_HI	0x13
+#define SEQ_CURSOR_STORE_LO	0x14
+#define SEQ_CURSOR_ST_OFF_HI	0x15
+#define SEQ_CURSOR_ST_OFF_LO	0x16
+#define SEQ_CURSOR_PIXELMASK	0x17
+#define SEQ_PRIM_HOST_OFF_HI	0x18
+#define SEQ_PRIM_HOST_OFF_LO	0x19
+#define SEQ_LINEAR_0		0x1a
+#define SEQ_LINEAR_1		0x1b
+#define SEQ_SEC_HOST_OFF_HI	0x1c
+#define SEQ_SEC_HOST_OFF_LO	0x1d
+#define SEQ_EXTENDED_MEM_ENA	0x1e
+#define SEQ_EXT_CLOCK_MODE	0x1f
+#define SEQ_EXT_VIDEO_ADDR	0x20
+#define SEQ_EXT_PIXEL_CNTL	0x21
+#define SEQ_BUS_WIDTH_FEEDB	0x22
+#define SEQ_PERF_SELECT		0x23
+#define SEQ_COLOR_EXP_WFG	0x24
+#define SEQ_COLOR_EXP_WBG	0x25
+#define SEQ_EXT_RW_CONTROL	0x26
+#define SEQ_MISC_FEATURE_SEL	0x27
+#define SEQ_COLOR_KEY_CNTL	0x28
+#define SEQ_COLOR_KEY_MATCH0	0x29
+#define SEQ_COLOR_KEY_MATCH1 	0x2a
+#define SEQ_COLOR_KEY_MATCH2 	0x2b
+#define SEQ_UNKNOWN6         	0x2c
+#define SEQ_CRC_CONTROL		0x2d
+#define SEQ_CRC_DATA_LOW	0x2e
+#define SEQ_CRC_DATA_HIGH	0x2f
+#define SEQ_MEMORY_MAP_CNTL	0x30
+#define SEQ_ACM_APERTURE_1	0x31
+#define SEQ_ACM_APERTURE_2	0x32
+#define SEQ_ACM_APERTURE_3	0x33
+#define SEQ_BIOS_UTILITY_0	0x3e
+#define SEQ_BIOS_UTILITY_1	0x3f
+
+/*
+ * Graphics Controller
+ */
+#define GFX_IDX			0x03ce
+#define GFX_DATA		0x03cf
+#define GFX_SET_RESET		0x00
+#define GFX_ENABLE_SET_RESET	0x01
+#define GFX_COLOR_COMPARE	0x02
+#define GFX_DATA_ROTATE		0x03
+#define GFX_READ_MAP_SELECT	0x04
+#define GFX_GRAPHICS_MODE	0x05
+#define GFX_MISC		0x06
+#define GFX_COLOR_XCARE		0x07
+#define GFX_BITMASK		0x08
+
+/*
+ * CRT Controller
+ */
+#define CRT_IDX			0x03d4
+#define CRT_DATA		0x03d5
+#define CRT_HOR_TOTAL		0x00
+#define CRT_HOR_DISP_ENA_END	0x01
+#define CRT_START_HOR_BLANK	0x02
+#define CRT_END_HOR_BLANK	0x03
+#define CRT_START_HOR_RETR	0x04
+#define CRT_END_HOR_RETR	0x05
+#define CRT_VER_TOTAL		0x06
+#define CRT_OVERFLOW		0x07
+#define CRT_PRESET_ROW_SCAN	0x08
+#define CRT_MAX_SCAN_LINE	0x09
+#define CRT_CURSOR_START	0x0a
+#define CRT_CURSOR_END		0x0b
+#define CRT_START_ADDR_HIGH	0x0c
+#define CRT_START_ADDR_LOW	0x0d
+#define CRT_CURSOR_LOC_HIGH	0x0e
+#define CRT_CURSOR_LOC_LOW	0x0f
+#define CRT_START_VER_RETR	0x10
+#define CRT_END_VER_RETR	0x11
+#define CRT_VER_DISP_ENA_END	0x12
+#define CRT_OFFSET		0x13
+#define CRT_UNDERLINE_LOC	0x14
+#define CRT_START_VER_BLANK	0x15
+#define CRT_END_VER_BLANK	0x16
+#define CRT_MODE_CONTROL	0x17
+#define CRT_LINE_COMPARE	0x18
+#define CRT_UNKNOWN1         	0x19
+#define CRT_UNKNOWN2         	0x1a
+#define CRT_UNKNOWN3         	0x1b
+#define CRT_UNKNOWN4         	0x1c
+#define CRT_UNKNOWN5         	0x1d
+#define CRT_UNKNOWN6         	0x1e
+#define CRT_UNKNOWN7         	0x1f
+#define CRT_UNKNOWN8         	0x20
+#define CRT_UNKNOWN9		0x21
+#define CRT_UNKNOWN10		0x22
+#define CRT_UNKNOWN11      	0x23
+#define CRT_UNKNOWN12      	0x24
+#define CRT_UNKNOWN13      	0x25
+#define CRT_UNKNOWN14      	0x26
+#define CRT_UNKNOWN15      	0x27
+#define CRT_UNKNOWN16      	0x28
+#define CRT_UNKNOWN17      	0x29
+#define CRT_UNKNOWN18      	0x2a
+#define CRT_UNKNOWN19      	0x2b
+#define CRT_UNKNOWN20      	0x2c
+#define CRT_UNKNOWN21      	0x2d
+#define CRT_UNKNOWN22      	0x2e
+#define CRT_UNKNOWN23      	0x2f
+#define CRT_EXT_HOR_TIMING1	0x30	/* NCR crt extensions */
+#define CRT_EXT_START_ADDR	0x31
+#define CRT_EXT_HOR_TIMING2	0x32
+#define CRT_EXT_VER_TIMING	0x33
+#define CRT_MONITOR_POWER	0x34
+
+/*
+ * General Registers
+ */
+#define GREG_STATUS0_R		0x03c2
+#define GREG_STATUS1_R		0x03da
+#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_POS		0x0102
+
+/*
+ * Attribute Controller
+ */
+#define ACT_IDX			0x03C0
+#define ACT_ADDRESS_R		0x03C0
+#define ACT_DATA		0x03C0
+#define ACT_ADDRESS_RESET	0x03DA
+#define ACT_PALETTE0		0x00
+#define ACT_PALETTE1		0x01
+#define ACT_PALETTE2		0x02
+#define ACT_PALETTE3		0x03
+#define ACT_PALETTE4		0x04
+#define ACT_PALETTE5		0x05
+#define ACT_PALETTE6		0x06
+#define ACT_PALETTE7		0x07
+#define ACT_PALETTE8		0x08
+#define ACT_PALETTE9		0x09
+#define ACT_PALETTE10		0x0A
+#define ACT_PALETTE11		0x0B
+#define ACT_PALETTE12		0x0C
+#define ACT_PALETTE13		0x0D
+#define ACT_PALETTE14		0x0E
+#define ACT_PALETTE15		0x0F
+#define ACT_ATTR_MODE_CNTL	0x10
+#define ACT_OVERSCAN_COLOR	0x11
+#define ACT_COLOR_PLANE_ENA	0x12
+#define ACT_HOR_PEL_PANNING	0x13
+#define ACT_COLOR_SELECT	0x14
+
+/*
+ * PLL
+ */
+#define PLL_IDX			0x83c8
+#define PLL_DATA		0x83c9
+
+/*
+ * Blitter operations
+ */
+#define	Z3BLTclear		0x00	/* 0 */
+#define Z3BLTand		0x80	/* src AND dst */
+#define Z3BLTandReverse		0x40	/* src AND NOT dst */
+#define Z3BLTcopy		0xc0	/* src */
+#define Z3BLTandInverted	0x20	/* NOT src AND dst */
+#define	Z3BLTnoop		0xa0	/* dst */
+#define Z3BLTxor		0x60	/* src XOR dst */
+#define Z3BLTor			0xe0	/* src OR dst */
+#define Z3BLTnor		0x10	/* NOT src AND NOT dst */
+#define Z3BLTequiv		0x90	/* NOT src XOR dst */
+#define Z3BLTinvert		0x50	/* NOT dst */
+#define Z3BLTorReverse		0xd0	/* src OR NOT dst */
+#define Z3BLTcopyInverted	0x30	/* NOT src */
+#define Z3BLTorInverted		0xb0	/* NOT src OR dst */
+#define Z3BLTnand		0x70	/* NOT src OR NOT dst */
+#define Z3BLTset		0xf0	/* 1 */
diff --git a/drivers/video/riva/Makefile b/drivers/video/riva/Makefile
new file mode 100644
index 0000000..8898c99
--- /dev/null
+++ b/drivers/video/riva/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the Riva framebuffer driver
+#
+
+obj-$(CONFIG_FB_RIVA)     += rivafb.o
+
+rivafb-objs               := fbdev.o riva_hw.o nv_driver.o
+
+ifdef CONFIG_FB_RIVA_I2C
+	rivafb-objs       += rivafb-i2c.o
+endif
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
new file mode 100644
index 0000000..b0c886d
--- /dev/null
+++ b/drivers/video/riva/fbdev.c
@@ -0,0 +1,2229 @@
+/*
+ * linux/drivers/video/riva/fbdev.c - nVidia RIVA 128/TNT/TNT2 fb driver
+ *
+ * Maintained by Ani Joshi <ajoshi@shell.unixbox.com>
+ *
+ * Copyright 1999-2000 Jeff Garzik
+ *
+ * Contributors:
+ *
+ *	Ani Joshi:  Lots of debugging and cleanup work, really helped
+ *	get the driver going
+ *
+ *	Ferenc Bakonyi:  Bug fixes, cleanup, modularization
+ *
+ *	Jindrich Makovicka:  Accel code help, hw cursor, mtrr
+ *
+ *	Paul Richards:  Bug fixes, updates
+ *
+ * Initial template from skeletonfb.c, created 28 Dec 1997 by Geert Uytterhoeven
+ * Includes riva_hw.c from nVidia, see copyright below.
+ * KGI code provided the basis for state storage, init, and mode switching.
+ *
+ * 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.
+ *
+ * Known bugs and issues:
+ *	restoring text mode fails
+ *	doublescan modes are broken
+ */
+
+#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/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+#ifdef CONFIG_PPC_OF
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#endif
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+
+#include "rivafb.h"
+#include "nvreg.h"
+
+#ifndef CONFIG_PCI		/* sanity check */
+#error This driver requires PCI support.
+#endif
+
+/* version number of this driver */
+#define RIVAFB_VERSION "0.9.5b"
+
+/* ------------------------------------------------------------------------- *
+ *
+ * various helpful macros and constants
+ *
+ * ------------------------------------------------------------------------- */
+#ifdef CONFIG_FB_RIVA_DEBUG
+#define NVTRACE          printk
+#else
+#define NVTRACE          if(0) printk
+#endif
+
+#define NVTRACE_ENTER(...)  NVTRACE("%s START\n", __FUNCTION__)
+#define NVTRACE_LEAVE(...)  NVTRACE("%s END\n", __FUNCTION__)
+
+#ifdef CONFIG_FB_RIVA_DEBUG
+#define assert(expr) \
+	if(!(expr)) { \
+	printk( "Assertion failed! %s,%s,%s,line=%d\n",\
+	#expr,__FILE__,__FUNCTION__,__LINE__); \
+	BUG(); \
+	}
+#else
+#define assert(expr)
+#endif
+
+#define PFX "rivafb: "
+
+/* macro that allows you to set overflow bits */
+#define SetBitField(value,from,to) SetBF(to,GetBF(value,from))
+#define SetBit(n)		(1<<(n))
+#define Set8Bits(value)		((value)&0xff)
+
+/* HW cursor parameters */
+#define MAX_CURS		32
+
+/* ------------------------------------------------------------------------- *
+ *
+ * prototypes
+ *
+ * ------------------------------------------------------------------------- */
+
+static int rivafb_blank(int blank, struct fb_info *info);
+
+/* ------------------------------------------------------------------------- *
+ *
+ * card identification
+ *
+ * ------------------------------------------------------------------------- */
+
+static struct pci_device_id rivafb_pci_tbl[] = {
+	{ PCI_VENDOR_ID_NVIDIA_SGS, PCI_DEVICE_ID_NVIDIA_SGS_RIVA128,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT2,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UTNT2,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_VTNT2,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UVTNT2,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_ITNT2,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	// NF2/IGP version, GeForce 4 MX, NV18
+	{ PCI_VENDOR_ID_NVIDIA, 0x01f0,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_200,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_IGEFORCE2,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_1,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_2,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_DDC,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO_5200,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0, } /* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, rivafb_pci_tbl);
+
+/* ------------------------------------------------------------------------- *
+ *
+ * global variables
+ *
+ * ------------------------------------------------------------------------- */
+
+/* command line data, set in rivafb_setup() */
+static int flatpanel __devinitdata = -1; /* Autodetect later */
+static int forceCRTC __devinitdata = -1;
+static int noaccel   __devinitdata = 0;
+#ifdef CONFIG_MTRR
+static int nomtrr __devinitdata = 0;
+#endif
+
+static char *mode_option __devinitdata = NULL;
+static int  strictmode       = 0;
+
+static struct fb_fix_screeninfo __devinitdata rivafb_fix = {
+	.type		= FB_TYPE_PACKED_PIXELS,
+	.xpanstep	= 1,
+	.ypanstep	= 1,
+};
+
+static struct fb_var_screeninfo __devinitdata rivafb_default_var = {
+	.xres		= 640,
+	.yres		= 480,
+	.xres_virtual	= 640,
+	.yres_virtual	= 480,
+	.bits_per_pixel	= 8,
+	.red		= {0, 8, 0},
+	.green		= {0, 8, 0},
+	.blue		= {0, 8, 0},
+	.transp		= {0, 0, 0},
+	.activate	= FB_ACTIVATE_NOW,
+	.height		= -1,
+	.width		= -1,
+	.pixclock	= 39721,
+	.left_margin	= 40,
+	.right_margin	= 24,
+	.upper_margin	= 32,
+	.lower_margin	= 11,
+	.hsync_len	= 96,
+	.vsync_len	= 2,
+	.vmode		= FB_VMODE_NONINTERLACED
+};
+
+/* from GGI */
+static const struct riva_regs reg_template = {
+	{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,	/* ATTR */
+	 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	 0x41, 0x01, 0x0F, 0x00, 0x00},
+	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* CRT  */
+	 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
+	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3,	/* 0x10 */
+	 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 0x20 */
+	 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 0x30 */
+	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	 0x00,							/* 0x40 */
+	 },
+	{0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,	/* GRA  */
+	 0xFF},
+	{0x03, 0x01, 0x0F, 0x00, 0x0E},				/* SEQ  */
+	0xEB							/* MISC */
+};
+
+/*
+ * Backlight control
+ */
+#ifdef CONFIG_PMAC_BACKLIGHT
+
+static int riva_backlight_levels[] = {
+    0x158,
+    0x192,
+    0x1c6,
+    0x200,
+    0x234,
+    0x268,
+    0x2a2,
+    0x2d6,
+    0x310,
+    0x344,
+    0x378,
+    0x3b2,
+    0x3e6,
+    0x41a,
+    0x454,
+    0x534,
+};
+
+static int riva_set_backlight_enable(int on, int level, void *data);
+static int riva_set_backlight_level(int level, void *data);
+static struct backlight_controller riva_backlight_controller = {
+	riva_set_backlight_enable,
+	riva_set_backlight_level
+};
+#endif /* CONFIG_PMAC_BACKLIGHT */
+
+/* ------------------------------------------------------------------------- *
+ *
+ * MMIO access macros
+ *
+ * ------------------------------------------------------------------------- */
+
+static inline void CRTCout(struct riva_par *par, unsigned char index,
+			   unsigned char val)
+{
+	VGA_WR08(par->riva.PCIO, 0x3d4, index);
+	VGA_WR08(par->riva.PCIO, 0x3d5, val);
+}
+
+static inline unsigned char CRTCin(struct riva_par *par,
+				   unsigned char index)
+{
+	VGA_WR08(par->riva.PCIO, 0x3d4, index);
+	return (VGA_RD08(par->riva.PCIO, 0x3d5));
+}
+
+static inline void GRAout(struct riva_par *par, unsigned char index,
+			  unsigned char val)
+{
+	VGA_WR08(par->riva.PVIO, 0x3ce, index);
+	VGA_WR08(par->riva.PVIO, 0x3cf, val);
+}
+
+static inline unsigned char GRAin(struct riva_par *par,
+				  unsigned char index)
+{
+	VGA_WR08(par->riva.PVIO, 0x3ce, index);
+	return (VGA_RD08(par->riva.PVIO, 0x3cf));
+}
+
+static inline void SEQout(struct riva_par *par, unsigned char index,
+			  unsigned char val)
+{
+	VGA_WR08(par->riva.PVIO, 0x3c4, index);
+	VGA_WR08(par->riva.PVIO, 0x3c5, val);
+}
+
+static inline unsigned char SEQin(struct riva_par *par,
+				  unsigned char index)
+{
+	VGA_WR08(par->riva.PVIO, 0x3c4, index);
+	return (VGA_RD08(par->riva.PVIO, 0x3c5));
+}
+
+static inline void ATTRout(struct riva_par *par, unsigned char index,
+			   unsigned char val)
+{
+	VGA_WR08(par->riva.PCIO, 0x3c0, index);
+	VGA_WR08(par->riva.PCIO, 0x3c0, val);
+}
+
+static inline unsigned char ATTRin(struct riva_par *par,
+				   unsigned char index)
+{
+	VGA_WR08(par->riva.PCIO, 0x3c0, index);
+	return (VGA_RD08(par->riva.PCIO, 0x3c1));
+}
+
+static inline void MISCout(struct riva_par *par, unsigned char val)
+{
+	VGA_WR08(par->riva.PVIO, 0x3c2, val);
+}
+
+static inline unsigned char MISCin(struct riva_par *par)
+{
+	return (VGA_RD08(par->riva.PVIO, 0x3cc));
+}
+
+static u8 byte_rev[256] = {
+	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+};
+
+static inline void reverse_order(u32 *l)
+{
+	u8 *a = (u8 *)l;
+	*a = byte_rev[*a], a++;
+	*a = byte_rev[*a], a++;
+	*a = byte_rev[*a], a++;
+	*a = byte_rev[*a];
+}
+
+/* ------------------------------------------------------------------------- *
+ *
+ * cursor stuff
+ *
+ * ------------------------------------------------------------------------- */
+
+/**
+ * rivafb_load_cursor_image - load cursor image to hardware
+ * @data: address to monochrome bitmap (1 = foreground color, 0 = background)
+ * @par:  pointer to private data
+ * @w:    width of cursor image in pixels
+ * @h:    height of cursor image in scanlines
+ * @bg:   background color (ARGB1555) - alpha bit determines opacity
+ * @fg:   foreground color (ARGB1555)
+ *
+ * DESCRIPTiON:
+ * Loads cursor image based on a monochrome source and mask bitmap.  The
+ * image bits determines the color of the pixel, 0 for background, 1 for
+ * foreground.  Only the affected region (as determined by @w and @h 
+ * parameters) will be updated.
+ *
+ * CALLED FROM:
+ * rivafb_cursor()
+ */
+static void rivafb_load_cursor_image(struct riva_par *par, u8 *data8,
+				     u16 bg, u16 fg, u32 w, u32 h)
+{
+	int i, j, k = 0;
+	u32 b, tmp;
+	u32 *data = (u32 *)data8;
+	bg = le16_to_cpu(bg);
+	fg = le16_to_cpu(fg);
+
+	w = (w + 1) & ~1;
+
+	for (i = 0; i < h; i++) {
+		b = *data++;
+		reverse_order(&b);
+		
+		for (j = 0; j < w/2; j++) {
+			tmp = 0;
+#if defined (__BIG_ENDIAN)
+			tmp = (b & (1 << 31)) ? fg << 16 : bg << 16;
+			b <<= 1;
+			tmp |= (b & (1 << 31)) ? fg : bg;
+			b <<= 1;
+#else
+			tmp = (b & 1) ? fg : bg;
+			b >>= 1;
+			tmp |= (b & 1) ? fg << 16 : bg << 16;
+			b >>= 1;
+#endif
+			writel(tmp, &par->riva.CURSOR[k++]);
+		}
+		k += (MAX_CURS - w)/2;
+	}
+}
+
+/* ------------------------------------------------------------------------- *
+ *
+ * general utility functions
+ *
+ * ------------------------------------------------------------------------- */
+
+/**
+ * riva_wclut - set CLUT entry
+ * @chip: pointer to RIVA_HW_INST object
+ * @regnum: register number
+ * @red: red component
+ * @green: green component
+ * @blue: blue component
+ *
+ * DESCRIPTION:
+ * Sets color register @regnum.
+ *
+ * CALLED FROM:
+ * rivafb_setcolreg()
+ */
+static void riva_wclut(RIVA_HW_INST *chip,
+		       unsigned char regnum, unsigned char red,
+		       unsigned char green, unsigned char blue)
+{
+	VGA_WR08(chip->PDIO, 0x3c8, regnum);
+	VGA_WR08(chip->PDIO, 0x3c9, red);
+	VGA_WR08(chip->PDIO, 0x3c9, green);
+	VGA_WR08(chip->PDIO, 0x3c9, blue);
+}
+
+/**
+ * riva_rclut - read fromCLUT register
+ * @chip: pointer to RIVA_HW_INST object
+ * @regnum: register number
+ * @red: red component
+ * @green: green component
+ * @blue: blue component
+ *
+ * DESCRIPTION:
+ * Reads red, green, and blue from color register @regnum.
+ *
+ * CALLED FROM:
+ * rivafb_setcolreg()
+ */
+static void riva_rclut(RIVA_HW_INST *chip,
+		       unsigned char regnum, unsigned char *red,
+		       unsigned char *green, unsigned char *blue)
+{
+	
+	VGA_WR08(chip->PDIO, 0x3c7, regnum);
+	*red = VGA_RD08(chip->PDIO, 0x3c9);
+	*green = VGA_RD08(chip->PDIO, 0x3c9);
+	*blue = VGA_RD08(chip->PDIO, 0x3c9);
+}
+
+/**
+ * riva_save_state - saves current chip state
+ * @par: pointer to riva_par object containing info for current riva board
+ * @regs: pointer to riva_regs object
+ *
+ * DESCRIPTION:
+ * Saves current chip state to @regs.
+ *
+ * CALLED FROM:
+ * rivafb_probe()
+ */
+/* from GGI */
+static void riva_save_state(struct riva_par *par, struct riva_regs *regs)
+{
+	int i;
+
+	NVTRACE_ENTER();
+	par->riva.LockUnlock(&par->riva, 0);
+
+	par->riva.UnloadStateExt(&par->riva, &regs->ext);
+
+	regs->misc_output = MISCin(par);
+
+	for (i = 0; i < NUM_CRT_REGS; i++)
+		regs->crtc[i] = CRTCin(par, i);
+
+	for (i = 0; i < NUM_ATC_REGS; i++)
+		regs->attr[i] = ATTRin(par, i);
+
+	for (i = 0; i < NUM_GRC_REGS; i++)
+		regs->gra[i] = GRAin(par, i);
+
+	for (i = 0; i < NUM_SEQ_REGS; i++)
+		regs->seq[i] = SEQin(par, i);
+	NVTRACE_LEAVE();
+}
+
+/**
+ * riva_load_state - loads current chip state
+ * @par: pointer to riva_par object containing info for current riva board
+ * @regs: pointer to riva_regs object
+ *
+ * DESCRIPTION:
+ * Loads chip state from @regs.
+ *
+ * CALLED FROM:
+ * riva_load_video_mode()
+ * rivafb_probe()
+ * rivafb_remove()
+ */
+/* from GGI */
+static void riva_load_state(struct riva_par *par, struct riva_regs *regs)
+{
+	RIVA_HW_STATE *state = &regs->ext;
+	int i;
+
+	NVTRACE_ENTER();
+	CRTCout(par, 0x11, 0x00);
+
+	par->riva.LockUnlock(&par->riva, 0);
+
+	par->riva.LoadStateExt(&par->riva, state);
+
+	MISCout(par, regs->misc_output);
+
+	for (i = 0; i < NUM_CRT_REGS; i++) {
+		switch (i) {
+		case 0x19:
+		case 0x20 ... 0x40:
+			break;
+		default:
+			CRTCout(par, i, regs->crtc[i]);
+		}
+	}
+
+	for (i = 0; i < NUM_ATC_REGS; i++)
+		ATTRout(par, i, regs->attr[i]);
+
+	for (i = 0; i < NUM_GRC_REGS; i++)
+		GRAout(par, i, regs->gra[i]);
+
+	for (i = 0; i < NUM_SEQ_REGS; i++)
+		SEQout(par, i, regs->seq[i]);
+	NVTRACE_LEAVE();
+}
+
+/**
+ * riva_load_video_mode - calculate timings
+ * @info: pointer to fb_info object containing info for current riva board
+ *
+ * DESCRIPTION:
+ * Calculate some timings and then send em off to riva_load_state().
+ *
+ * CALLED FROM:
+ * rivafb_set_par()
+ */
+static void riva_load_video_mode(struct fb_info *info)
+{
+	int bpp, width, hDisplaySize, hDisplay, hStart,
+	    hEnd, hTotal, height, vDisplay, vStart, vEnd, vTotal, dotClock;
+	int hBlankStart, hBlankEnd, vBlankStart, vBlankEnd;
+	struct riva_par *par = (struct riva_par *) info->par;
+	struct riva_regs newmode;
+	
+	NVTRACE_ENTER();
+	/* time to calculate */
+	rivafb_blank(1, info);
+
+	bpp = info->var.bits_per_pixel;
+	if (bpp == 16 && info->var.green.length == 5)
+		bpp = 15;
+	width = info->var.xres_virtual;
+	hDisplaySize = info->var.xres;
+	hDisplay = (hDisplaySize / 8) - 1;
+	hStart = (hDisplaySize + info->var.right_margin) / 8 - 1;
+	hEnd = (hDisplaySize + info->var.right_margin +
+		info->var.hsync_len) / 8 - 1;
+	hTotal = (hDisplaySize + info->var.right_margin +
+		  info->var.hsync_len + info->var.left_margin) / 8 - 5;
+	hBlankStart = hDisplay;
+	hBlankEnd = hTotal + 4;
+
+	height = info->var.yres_virtual;
+	vDisplay = info->var.yres - 1;
+	vStart = info->var.yres + info->var.lower_margin - 1;
+	vEnd = info->var.yres + info->var.lower_margin +
+	       info->var.vsync_len - 1;
+	vTotal = info->var.yres + info->var.lower_margin +
+		 info->var.vsync_len + info->var.upper_margin + 2;
+	vBlankStart = vDisplay;
+	vBlankEnd = vTotal + 1;
+	dotClock = 1000000000 / info->var.pixclock;
+
+	memcpy(&newmode, &reg_template, sizeof(struct riva_regs));
+
+	if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
+		vTotal |= 1;
+
+	if (par->FlatPanel) {
+		vStart = vTotal - 3;
+		vEnd = vTotal - 2;
+		vBlankStart = vStart;
+		hStart = hTotal - 3;
+		hEnd = hTotal - 2;
+		hBlankEnd = hTotal + 4;
+	}
+
+	newmode.crtc[0x0] = Set8Bits (hTotal); 
+	newmode.crtc[0x1] = Set8Bits (hDisplay);
+	newmode.crtc[0x2] = Set8Bits (hBlankStart);
+	newmode.crtc[0x3] = SetBitField (hBlankEnd, 4: 0, 4:0) | SetBit (7);
+	newmode.crtc[0x4] = Set8Bits (hStart);
+	newmode.crtc[0x5] = SetBitField (hBlankEnd, 5: 5, 7:7)
+		| SetBitField (hEnd, 4: 0, 4:0);
+	newmode.crtc[0x6] = SetBitField (vTotal, 7: 0, 7:0);
+	newmode.crtc[0x7] = SetBitField (vTotal, 8: 8, 0:0)
+		| SetBitField (vDisplay, 8: 8, 1:1)
+		| SetBitField (vStart, 8: 8, 2:2)
+		| SetBitField (vBlankStart, 8: 8, 3:3)
+		| SetBit (4)
+		| SetBitField (vTotal, 9: 9, 5:5)
+		| SetBitField (vDisplay, 9: 9, 6:6)
+		| SetBitField (vStart, 9: 9, 7:7);
+	newmode.crtc[0x9] = SetBitField (vBlankStart, 9: 9, 5:5)
+		| SetBit (6);
+	newmode.crtc[0x10] = Set8Bits (vStart);
+	newmode.crtc[0x11] = SetBitField (vEnd, 3: 0, 3:0)
+		| SetBit (5);
+	newmode.crtc[0x12] = Set8Bits (vDisplay);
+	newmode.crtc[0x13] = (width / 8) * ((bpp + 1) / 8);
+	newmode.crtc[0x15] = Set8Bits (vBlankStart);
+	newmode.crtc[0x16] = Set8Bits (vBlankEnd);
+
+	newmode.ext.screen = SetBitField(hBlankEnd,6:6,4:4)
+		| SetBitField(vBlankStart,10:10,3:3)
+		| SetBitField(vStart,10:10,2:2)
+		| SetBitField(vDisplay,10:10,1:1)
+		| SetBitField(vTotal,10:10,0:0);
+	newmode.ext.horiz  = SetBitField(hTotal,8:8,0:0) 
+		| SetBitField(hDisplay,8:8,1:1)
+		| SetBitField(hBlankStart,8:8,2:2)
+		| SetBitField(hStart,8:8,3:3);
+	newmode.ext.extra  = SetBitField(vTotal,11:11,0:0)
+		| SetBitField(vDisplay,11:11,2:2)
+		| SetBitField(vStart,11:11,4:4)
+		| SetBitField(vBlankStart,11:11,6:6); 
+
+	if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+		int tmp = (hTotal >> 1) & ~1;
+		newmode.ext.interlace = Set8Bits(tmp);
+		newmode.ext.horiz |= SetBitField(tmp, 8:8,4:4);
+	} else 
+		newmode.ext.interlace = 0xff; /* interlace off */
+
+	if (par->riva.Architecture >= NV_ARCH_10)
+		par->riva.CURSOR = (U032 __iomem *)(info->screen_base + par->riva.CursorStart);
+
+	if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
+		newmode.misc_output &= ~0x40;
+	else
+		newmode.misc_output |= 0x40;
+	if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
+		newmode.misc_output &= ~0x80;
+	else
+		newmode.misc_output |= 0x80;	
+
+	par->riva.CalcStateExt(&par->riva, &newmode.ext, bpp, width,
+				  hDisplaySize, height, dotClock);
+
+	newmode.ext.scale = NV_RD32(par->riva.PRAMDAC, 0x00000848) &
+		0xfff000ff;
+	if (par->FlatPanel == 1) {
+		newmode.ext.pixel |= (1 << 7);
+		newmode.ext.scale |= (1 << 8);
+	}
+	if (par->SecondCRTC) {
+		newmode.ext.head  = NV_RD32(par->riva.PCRTC0, 0x00000860) &
+			~0x00001000;
+		newmode.ext.head2 = NV_RD32(par->riva.PCRTC0, 0x00002860) |
+			0x00001000;
+		newmode.ext.crtcOwner = 3;
+		newmode.ext.pllsel |= 0x20000800;
+		newmode.ext.vpll2 = newmode.ext.vpll;
+	} else if (par->riva.twoHeads) {
+		newmode.ext.head  =  NV_RD32(par->riva.PCRTC0, 0x00000860) |
+			0x00001000;
+		newmode.ext.head2 =  NV_RD32(par->riva.PCRTC0, 0x00002860) &
+			~0x00001000;
+		newmode.ext.crtcOwner = 0;
+		newmode.ext.vpll2 = NV_RD32(par->riva.PRAMDAC0, 0x00000520);
+	}
+	if (par->FlatPanel == 1) {
+		newmode.ext.pixel |= (1 << 7);
+		newmode.ext.scale |= (1 << 8);
+	}
+	newmode.ext.cursorConfig = 0x02000100;
+	par->current_state = newmode;
+	riva_load_state(par, &par->current_state);
+	par->riva.LockUnlock(&par->riva, 0); /* important for HW cursor */
+	rivafb_blank(0, info);
+	NVTRACE_LEAVE();
+}
+
+static void riva_update_var(struct fb_var_screeninfo *var, struct fb_videomode *modedb)
+{
+	NVTRACE_ENTER();
+	var->xres = var->xres_virtual = modedb->xres;
+	var->yres = modedb->yres;
+        if (var->yres_virtual < var->yres)
+	    var->yres_virtual = var->yres;
+        var->xoffset = var->yoffset = 0;
+        var->pixclock = modedb->pixclock;
+        var->left_margin = modedb->left_margin;
+        var->right_margin = modedb->right_margin;
+        var->upper_margin = modedb->upper_margin;
+        var->lower_margin = modedb->lower_margin;
+        var->hsync_len = modedb->hsync_len;
+        var->vsync_len = modedb->vsync_len;
+        var->sync = modedb->sync;
+        var->vmode = modedb->vmode;
+	NVTRACE_LEAVE();
+}
+
+/**
+ * rivafb_do_maximize - 
+ * @info: pointer to fb_info object containing info for current riva board
+ * @var:
+ * @nom:
+ * @den:
+ *
+ * DESCRIPTION:
+ * .
+ *
+ * RETURNS:
+ * -EINVAL on failure, 0 on success
+ * 
+ *
+ * CALLED FROM:
+ * rivafb_check_var()
+ */
+static int rivafb_do_maximize(struct fb_info *info,
+			      struct fb_var_screeninfo *var,
+			      int nom, int den)
+{
+	static struct {
+		int xres, yres;
+	} modes[] = {
+		{1600, 1280},
+		{1280, 1024},
+		{1024, 768},
+		{800, 600},
+		{640, 480},
+		{-1, -1}
+	};
+	int i;
+
+	NVTRACE_ENTER();
+	/* use highest possible virtual resolution */
+	if (var->xres_virtual == -1 && var->yres_virtual == -1) {
+		printk(KERN_WARNING PFX
+		       "using maximum available virtual resolution\n");
+		for (i = 0; modes[i].xres != -1; i++) {
+			if (modes[i].xres * nom / den * modes[i].yres <
+			    info->fix.smem_len)
+				break;
+		}
+		if (modes[i].xres == -1) {
+			printk(KERN_ERR PFX
+			       "could not find a virtual resolution that fits into video memory!!\n");
+			NVTRACE("EXIT - EINVAL error\n");
+			return -EINVAL;
+		}
+		var->xres_virtual = modes[i].xres;
+		var->yres_virtual = modes[i].yres;
+
+		printk(KERN_INFO PFX
+		       "virtual resolution set to maximum of %dx%d\n",
+		       var->xres_virtual, var->yres_virtual);
+	} else if (var->xres_virtual == -1) {
+		var->xres_virtual = (info->fix.smem_len * den /
+			(nom * var->yres_virtual)) & ~15;
+		printk(KERN_WARNING PFX
+		       "setting virtual X resolution to %d\n", var->xres_virtual);
+	} else if (var->yres_virtual == -1) {
+		var->xres_virtual = (var->xres_virtual + 15) & ~15;
+		var->yres_virtual = info->fix.smem_len * den /
+			(nom * var->xres_virtual);
+		printk(KERN_WARNING PFX
+		       "setting virtual Y resolution to %d\n", var->yres_virtual);
+	} else {
+		var->xres_virtual = (var->xres_virtual + 15) & ~15;
+		if (var->xres_virtual * nom / den * var->yres_virtual > info->fix.smem_len) {
+			printk(KERN_ERR PFX
+			       "mode %dx%dx%d rejected...resolution too high to fit into video memory!\n",
+			       var->xres, var->yres, var->bits_per_pixel);
+			NVTRACE("EXIT - EINVAL error\n");
+			return -EINVAL;
+		}
+	}
+	
+	if (var->xres_virtual * nom / den >= 8192) {
+		printk(KERN_WARNING PFX
+		       "virtual X resolution (%d) is too high, lowering to %d\n",
+		       var->xres_virtual, 8192 * den / nom - 16);
+		var->xres_virtual = 8192 * den / nom - 16;
+	}
+	
+	if (var->xres_virtual < var->xres) {
+		printk(KERN_ERR PFX
+		       "virtual X resolution (%d) is smaller than real\n", var->xres_virtual);
+		return -EINVAL;
+	}
+
+	if (var->yres_virtual < var->yres) {
+		printk(KERN_ERR PFX
+		       "virtual Y resolution (%d) is smaller than real\n", var->yres_virtual);
+		return -EINVAL;
+	}
+	if (var->yres_virtual > 0x7fff/nom)
+		var->yres_virtual = 0x7fff/nom;
+	if (var->xres_virtual > 0x7fff/nom)
+		var->xres_virtual = 0x7fff/nom;
+	NVTRACE_LEAVE();
+	return 0;
+}
+
+static void
+riva_set_pattern(struct riva_par *par, int clr0, int clr1, int pat0, int pat1)
+{
+	RIVA_FIFO_FREE(par->riva, Patt, 4);
+	NV_WR32(&par->riva.Patt->Color0, 0, clr0);
+	NV_WR32(&par->riva.Patt->Color1, 0, clr1);
+	NV_WR32(par->riva.Patt->Monochrome, 0, pat0);
+	NV_WR32(par->riva.Patt->Monochrome, 4, pat1);
+}
+
+/* acceleration routines */
+static inline void wait_for_idle(struct riva_par *par)
+{
+	while (par->riva.Busy(&par->riva));
+}
+
+/*
+ * Set ROP.  Translate X rop into ROP3.  Internal routine.
+ */
+static void
+riva_set_rop_solid(struct riva_par *par, int rop)
+{
+	riva_set_pattern(par, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
+        RIVA_FIFO_FREE(par->riva, Rop, 1);
+        NV_WR32(&par->riva.Rop->Rop3, 0, rop);
+
+}
+
+static void riva_setup_accel(struct fb_info *info)
+{
+	struct riva_par *par = (struct riva_par *) info->par;
+
+	RIVA_FIFO_FREE(par->riva, Clip, 2);
+	NV_WR32(&par->riva.Clip->TopLeft, 0, 0x0);
+	NV_WR32(&par->riva.Clip->WidthHeight, 0,
+		(info->var.xres_virtual & 0xffff) |
+		(info->var.yres_virtual << 16));
+	riva_set_rop_solid(par, 0xcc);
+	wait_for_idle(par);
+}
+
+/**
+ * riva_get_cmap_len - query current color map length
+ * @var: standard kernel fb changeable data
+ *
+ * DESCRIPTION:
+ * Get current color map length.
+ *
+ * RETURNS:
+ * Length of color map
+ *
+ * CALLED FROM:
+ * rivafb_setcolreg()
+ */
+static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
+{
+	int rc = 256;		/* reasonable default */
+
+	switch (var->green.length) {
+	case 8:
+		rc = 256;	/* 256 entries (2^8), 8 bpp and RGB8888 */
+		break;
+	case 5:
+		rc = 32;	/* 32 entries (2^5), 16 bpp, RGB555 */
+		break;
+	case 6:
+		rc = 64;	/* 64 entries (2^6), 16 bpp, RGB565 */
+		break;		
+	default:
+		/* should not occur */
+		break;
+	}
+	return rc;
+}
+
+/* ------------------------------------------------------------------------- *
+ *
+ * Backlight operations
+ *
+ * ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+static int riva_set_backlight_enable(int on, int level, void *data)
+{
+	struct riva_par *par = (struct riva_par *)data;
+	U032 tmp_pcrt, tmp_pmc;
+
+	tmp_pmc = par->riva.PMC[0x10F0/4] & 0x0000FFFF;
+	tmp_pcrt = par->riva.PCRTC0[0x081C/4] & 0xFFFFFFFC;
+	if(on && (level > BACKLIGHT_OFF)) {
+		tmp_pcrt |= 0x1;
+		tmp_pmc |= (1 << 31); // backlight bit
+		tmp_pmc |= riva_backlight_levels[level-1] << 16; // level
+	}
+	par->riva.PCRTC0[0x081C/4] = tmp_pcrt;
+	par->riva.PMC[0x10F0/4] = tmp_pmc;
+	return 0;
+}
+
+static int riva_set_backlight_level(int level, void *data)
+{
+	return riva_set_backlight_enable(1, level, data);
+}
+#endif /* CONFIG_PMAC_BACKLIGHT */
+
+/* ------------------------------------------------------------------------- *
+ *
+ * framebuffer operations
+ *
+ * ------------------------------------------------------------------------- */
+
+static int rivafb_open(struct fb_info *info, int user)
+{
+	struct riva_par *par = (struct riva_par *) info->par;
+	int cnt = atomic_read(&par->ref_count);
+
+	NVTRACE_ENTER();
+	if (!cnt) {
+#ifdef CONFIG_X86
+		memset(&par->state, 0, sizeof(struct vgastate));
+		par->state.flags = VGA_SAVE_MODE  | VGA_SAVE_FONTS;
+		/* save the DAC for Riva128 */
+		if (par->riva.Architecture == NV_ARCH_03)
+			par->state.flags |= VGA_SAVE_CMAP;
+		save_vga(&par->state);
+#endif
+		/* vgaHWunlock() + riva unlock (0x7F) */
+		CRTCout(par, 0x11, 0xFF);
+		par->riva.LockUnlock(&par->riva, 0);
+	
+		riva_save_state(par, &par->initial_state);
+	}
+	atomic_inc(&par->ref_count);
+	NVTRACE_LEAVE();
+	return 0;
+}
+
+static int rivafb_release(struct fb_info *info, int user)
+{
+	struct riva_par *par = (struct riva_par *) info->par;
+	int cnt = atomic_read(&par->ref_count);
+
+	NVTRACE_ENTER();
+	if (!cnt)
+		return -EINVAL;
+	if (cnt == 1) {
+		par->riva.LockUnlock(&par->riva, 0);
+		par->riva.LoadStateExt(&par->riva, &par->initial_state.ext);
+		riva_load_state(par, &par->initial_state);
+#ifdef CONFIG_X86
+		restore_vga(&par->state);
+#endif
+		par->riva.LockUnlock(&par->riva, 1);
+	}
+	atomic_dec(&par->ref_count);
+	NVTRACE_LEAVE();
+	return 0;
+}
+
+static int rivafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct fb_videomode *mode;
+	struct riva_par *par = (struct riva_par *) info->par;
+	int nom, den;		/* translating from pixels->bytes */
+	int mode_valid = 0;
+	
+	NVTRACE_ENTER();
+	switch (var->bits_per_pixel) {
+	case 1 ... 8:
+		var->red.offset = var->green.offset = var->blue.offset = 0;
+		var->red.length = var->green.length = var->blue.length = 8;
+		var->bits_per_pixel = 8;
+		nom = den = 1;
+		break;
+	case 9 ... 15:
+		var->green.length = 5;
+		/* fall through */
+	case 16:
+		var->bits_per_pixel = 16;
+		/* The Riva128 supports RGB555 only */
+		if (par->riva.Architecture == NV_ARCH_03)
+			var->green.length = 5;
+		if (var->green.length == 5) {
+			/* 0rrrrrgg gggbbbbb */
+			var->red.offset = 10;
+			var->green.offset = 5;
+			var->blue.offset = 0;
+			var->red.length = 5;
+			var->green.length = 5;
+			var->blue.length = 5;
+		} else {
+			/* rrrrrggg gggbbbbb */
+			var->red.offset = 11;
+			var->green.offset = 5;
+			var->blue.offset = 0;
+			var->red.length = 5;
+			var->green.length = 6;
+			var->blue.length = 5;
+		}
+		nom = 2;
+		den = 1;
+		break;
+	case 17 ... 32:
+		var->red.length = var->green.length = var->blue.length = 8;
+		var->bits_per_pixel = 32;
+		var->red.offset = 16;
+		var->green.offset = 8;
+		var->blue.offset = 0;
+		nom = 4;
+		den = 1;
+		break;
+	default:
+		printk(KERN_ERR PFX
+		       "mode %dx%dx%d rejected...color depth not supported.\n",
+		       var->xres, var->yres, var->bits_per_pixel);
+		NVTRACE("EXIT, returning -EINVAL\n");
+		return -EINVAL;
+	}
+
+	if (!strictmode) {
+		if (!info->monspecs.vfmax || !info->monspecs.hfmax ||
+		    !info->monspecs.dclkmax || !fb_validate_mode(var, info))
+			mode_valid = 1;
+	}
+
+	/* calculate modeline if supported by monitor */
+	if (!mode_valid && info->monspecs.gtf) {
+		if (!fb_get_mode(FB_MAXTIMINGS, 0, var, info))
+			mode_valid = 1;
+	}
+
+	if (!mode_valid) {
+		mode = fb_find_best_mode(var, &info->modelist);
+		if (mode) {
+			riva_update_var(var, mode);
+			mode_valid = 1;
+		}
+	}
+
+	if (!mode_valid && info->monspecs.modedb_len)
+		return -EINVAL;
+
+	if (var->xres_virtual < var->xres)
+		var->xres_virtual = var->xres;
+	if (var->yres_virtual <= var->yres)
+		var->yres_virtual = -1;
+	if (rivafb_do_maximize(info, var, nom, den) < 0)
+		return -EINVAL;
+
+	if (var->xoffset < 0)
+		var->xoffset = 0;
+	if (var->yoffset < 0)
+		var->yoffset = 0;
+
+	/* truncate xoffset and yoffset to maximum if too high */
+	if (var->xoffset > var->xres_virtual - var->xres)
+		var->xoffset = var->xres_virtual - var->xres - 1;
+
+	if (var->yoffset > var->yres_virtual - var->yres)
+		var->yoffset = var->yres_virtual - var->yres - 1;
+
+	var->red.msb_right = 
+	    var->green.msb_right =
+	    var->blue.msb_right =
+	    var->transp.offset = var->transp.length = var->transp.msb_right = 0;
+	NVTRACE_LEAVE();
+	return 0;
+}
+
+static int rivafb_set_par(struct fb_info *info)
+{
+	struct riva_par *par = (struct riva_par *) info->par;
+
+	NVTRACE_ENTER();
+	/* vgaHWunlock() + riva unlock (0x7F) */
+	CRTCout(par, 0x11, 0xFF);
+	par->riva.LockUnlock(&par->riva, 0);
+	riva_load_video_mode(info);
+	if(!(info->flags & FBINFO_HWACCEL_DISABLED))
+		riva_setup_accel(info);
+	
+	par->cursor_reset = 1;
+	info->fix.line_length = (info->var.xres_virtual * (info->var.bits_per_pixel >> 3));
+	info->fix.visual = (info->var.bits_per_pixel == 8) ?
+				FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
+
+	if (info->flags & FBINFO_HWACCEL_DISABLED)
+		info->pixmap.scan_align = 1;
+	else
+		info->pixmap.scan_align = 4;
+	NVTRACE_LEAVE();
+	return 0;
+}
+
+/**
+ * rivafb_pan_display
+ * @var: standard kernel fb changeable data
+ * @con: TODO
+ * @info: pointer to fb_info object containing info for current riva board
+ *
+ * DESCRIPTION:
+ * Pan (or wrap, depending on the `vmode' field) the display using the
+ * `xoffset' and `yoffset' fields of the `var' structure.
+ * If the values don't fit, return -EINVAL.
+ *
+ * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
+ */
+static int rivafb_pan_display(struct fb_var_screeninfo *var,
+			      struct fb_info *info)
+{
+	struct riva_par *par = (struct riva_par *)info->par;
+	unsigned int base;
+
+	NVTRACE_ENTER();
+	if (var->xoffset > (var->xres_virtual - var->xres))
+		return -EINVAL;
+	if (var->yoffset > (var->yres_virtual - var->yres))
+		return -EINVAL;
+
+	if (var->vmode & FB_VMODE_YWRAP) {
+		if (var->yoffset < 0
+		    || var->yoffset >= info->var.yres_virtual
+		    || var->xoffset) return -EINVAL;
+	} else {
+		if (var->xoffset + info->var.xres > info->var.xres_virtual ||
+		    var->yoffset + info->var.yres > info->var.yres_virtual)
+			return -EINVAL;
+	}
+
+	base = var->yoffset * info->fix.line_length + var->xoffset;
+
+	par->riva.SetStartAddress(&par->riva, base);
+
+	info->var.xoffset = var->xoffset;
+	info->var.yoffset = var->yoffset;
+
+	if (var->vmode & FB_VMODE_YWRAP)
+		info->var.vmode |= FB_VMODE_YWRAP;
+	else
+		info->var.vmode &= ~FB_VMODE_YWRAP;
+	NVTRACE_LEAVE();
+	return 0;
+}
+
+static int rivafb_blank(int blank, struct fb_info *info)
+{
+	struct riva_par *par= (struct riva_par *)info->par;
+	unsigned char tmp, vesa;
+
+	tmp = SEQin(par, 0x01) & ~0x20;	/* screen on/off */
+	vesa = CRTCin(par, 0x1a) & ~0xc0;	/* sync on/off */
+
+	NVTRACE_ENTER();
+
+	if (blank)
+		tmp |= 0x20;
+
+	switch (blank) {
+	case FB_BLANK_UNBLANK:
+	case FB_BLANK_NORMAL:
+		break;
+	case FB_BLANK_VSYNC_SUSPEND:
+		vesa |= 0x80;
+		break;
+	case FB_BLANK_HSYNC_SUSPEND:
+		vesa |= 0x40;
+		break;
+	case FB_BLANK_POWERDOWN:
+		vesa |= 0xc0;
+		break;
+	}
+
+	SEQout(par, 0x01, tmp);
+	CRTCout(par, 0x1a, vesa);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	if ( par->FlatPanel && _machine == _MACH_Pmac) {
+		set_backlight_enable(!blank);
+	}
+#endif
+
+	NVTRACE_LEAVE();
+
+	return 0;
+}
+
+/**
+ * rivafb_setcolreg
+ * @regno: register index
+ * @red: red component
+ * @green: green component
+ * @blue: blue component
+ * @transp: transparency
+ * @info: pointer to fb_info object containing info for current riva board
+ *
+ * DESCRIPTION:
+ * Set a single color register. The values supplied have a 16 bit
+ * magnitude.
+ *
+ * RETURNS:
+ * Return != 0 for invalid regno.
+ *
+ * CALLED FROM:
+ * fbcmap.c:fb_set_cmap()
+ */
+static int rivafb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			  unsigned blue, unsigned transp,
+			  struct fb_info *info)
+{
+	struct riva_par *par = (struct riva_par *)info->par;
+	RIVA_HW_INST *chip = &par->riva;
+	int i;
+
+	if (regno >= riva_get_cmap_len(&info->var))
+			return -EINVAL;
+
+	if (info->var.grayscale) {
+		/* gray = 0.30*R + 0.59*G + 0.11*B */
+		red = green = blue =
+		    (red * 77 + green * 151 + blue * 28) >> 8;
+	}
+
+	if (regno < 16 && info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+		((u32 *) info->pseudo_palette)[regno] =
+			(regno << info->var.red.offset) |
+			(regno << info->var.green.offset) |
+			(regno << info->var.blue.offset);
+		/*
+		 * The Riva128 2D engine requires color information in
+		 * TrueColor format even if framebuffer is in DirectColor
+		 */
+		if (par->riva.Architecture == NV_ARCH_03) {
+			switch (info->var.bits_per_pixel) {
+			case 16:
+				par->palette[regno] = ((red & 0xf800) >> 1) |
+					((green & 0xf800) >> 6) |
+					((blue & 0xf800) >> 11);
+				break;
+			case 32:
+				par->palette[regno] = ((red & 0xff00) << 8) |
+					((green & 0xff00)) |
+					((blue & 0xff00) >> 8);
+				break;
+			}
+		}
+	}
+
+	switch (info->var.bits_per_pixel) {
+	case 8:
+		/* "transparent" stuff is completely ignored. */
+		riva_wclut(chip, regno, red >> 8, green >> 8, blue >> 8);
+		break;
+	case 16:
+		if (info->var.green.length == 5) {
+			for (i = 0; i < 8; i++) {
+				riva_wclut(chip, regno*8+i, red >> 8,
+					   green >> 8, blue >> 8);
+			}
+		} else {
+			u8 r, g, b;
+
+			if (regno < 32) {
+				for (i = 0; i < 8; i++) {
+					riva_wclut(chip, regno*8+i,
+						   red >> 8, green >> 8,
+						   blue >> 8);
+				}
+			}
+			riva_rclut(chip, regno*4, &r, &g, &b);
+			for (i = 0; i < 4; i++)
+				riva_wclut(chip, regno*4+i, r,
+					   green >> 8, b);
+		}
+		break;
+	case 32:
+		riva_wclut(chip, regno, red >> 8, green >> 8, blue >> 8);
+		break;
+	default:
+		/* do nothing */
+		break;
+	}
+	return 0;
+}
+
+/**
+ * rivafb_fillrect - hardware accelerated color fill function
+ * @info: pointer to fb_info structure
+ * @rect: pointer to fb_fillrect structure
+ *
+ * DESCRIPTION:
+ * This function fills up a region of framebuffer memory with a solid
+ * color with a choice of two different ROP's, copy or invert.
+ *
+ * CALLED FROM:
+ * framebuffer hook
+ */
+static void rivafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+	struct riva_par *par = (struct riva_par *) info->par;
+	u_int color, rop = 0;
+
+	if ((info->flags & FBINFO_HWACCEL_DISABLED)) {
+		cfb_fillrect(info, rect);
+		return;
+	}
+
+	if (info->var.bits_per_pixel == 8)
+		color = rect->color;
+	else {
+		if (par->riva.Architecture != NV_ARCH_03)
+			color = ((u32 *)info->pseudo_palette)[rect->color];
+		else
+			color = par->palette[rect->color];
+	}
+
+	switch (rect->rop) {
+	case ROP_XOR:
+		rop = 0x66;
+		break;
+	case ROP_COPY:
+	default:
+		rop = 0xCC;
+		break;
+	}
+
+	riva_set_rop_solid(par, rop);
+
+	RIVA_FIFO_FREE(par->riva, Bitmap, 1);
+	NV_WR32(&par->riva.Bitmap->Color1A, 0, color);
+
+	RIVA_FIFO_FREE(par->riva, Bitmap, 2);
+	NV_WR32(&par->riva.Bitmap->UnclippedRectangle[0].TopLeft, 0,
+		(rect->dx << 16) | rect->dy);
+	mb();
+	NV_WR32(&par->riva.Bitmap->UnclippedRectangle[0].WidthHeight, 0,
+		(rect->width << 16) | rect->height);
+	mb();
+	riva_set_rop_solid(par, 0xcc);
+
+}
+
+/**
+ * rivafb_copyarea - hardware accelerated blit function
+ * @info: pointer to fb_info structure
+ * @region: pointer to fb_copyarea structure
+ *
+ * DESCRIPTION:
+ * This copies an area of pixels from one location to another
+ *
+ * CALLED FROM:
+ * framebuffer hook
+ */
+static void rivafb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
+{
+	struct riva_par *par = (struct riva_par *) info->par;
+
+	if ((info->flags & FBINFO_HWACCEL_DISABLED)) {
+		cfb_copyarea(info, region);
+		return;
+	}
+
+	RIVA_FIFO_FREE(par->riva, Blt, 3);
+	NV_WR32(&par->riva.Blt->TopLeftSrc, 0,
+		(region->sy << 16) | region->sx);
+	NV_WR32(&par->riva.Blt->TopLeftDst, 0,
+		(region->dy << 16) | region->dx);
+	mb();
+	NV_WR32(&par->riva.Blt->WidthHeight, 0,
+		(region->height << 16) | region->width);
+	mb();
+}
+
+static inline void convert_bgcolor_16(u32 *col)
+{
+	*col = ((*col & 0x0000F800) << 8)
+		| ((*col & 0x00007E0) << 5)
+		| ((*col & 0x0000001F) << 3)
+		|	   0xFF000000;
+	mb();
+}
+
+/**
+ * rivafb_imageblit: hardware accelerated color expand function
+ * @info: pointer to fb_info structure
+ * @image: pointer to fb_image structure
+ *
+ * DESCRIPTION:
+ * If the source is a monochrome bitmap, the function fills up a a region
+ * of framebuffer memory with pixels whose color is determined by the bit
+ * setting of the bitmap, 1 - foreground, 0 - background.
+ *
+ * If the source is not a monochrome bitmap, color expansion is not done.
+ * In this case, it is channeled to a software function.
+ *
+ * CALLED FROM:
+ * framebuffer hook
+ */
+static void rivafb_imageblit(struct fb_info *info, 
+			     const struct fb_image *image)
+{
+	struct riva_par *par = (struct riva_par *) info->par;
+	u32 fgx = 0, bgx = 0, width, tmp;
+	u8 *cdat = (u8 *) image->data;
+	volatile u32 __iomem *d;
+	int i, size;
+
+	if ((info->flags & FBINFO_HWACCEL_DISABLED) || image->depth != 1) {
+		cfb_imageblit(info, image);
+		return;
+	}
+
+	switch (info->var.bits_per_pixel) {
+	case 8:
+		fgx = image->fg_color;
+		bgx = image->bg_color;
+		break;
+	case 16:
+	case 32:
+		if (par->riva.Architecture != NV_ARCH_03) {
+			fgx = ((u32 *)info->pseudo_palette)[image->fg_color];
+			bgx = ((u32 *)info->pseudo_palette)[image->bg_color];
+		} else {
+			fgx = par->palette[image->fg_color];
+			bgx = par->palette[image->bg_color];
+		}
+		if (info->var.green.length == 6)
+			convert_bgcolor_16(&bgx);	
+		break;
+	}
+
+	RIVA_FIFO_FREE(par->riva, Bitmap, 7);
+	NV_WR32(&par->riva.Bitmap->ClipE.TopLeft, 0,
+		(image->dy << 16) | (image->dx & 0xFFFF));
+	NV_WR32(&par->riva.Bitmap->ClipE.BottomRight, 0,
+		(((image->dy + image->height) << 16) |
+		 ((image->dx + image->width) & 0xffff)));
+	NV_WR32(&par->riva.Bitmap->Color0E, 0, bgx);
+	NV_WR32(&par->riva.Bitmap->Color1E, 0, fgx);
+	NV_WR32(&par->riva.Bitmap->WidthHeightInE, 0,
+		(image->height << 16) | ((image->width + 31) & ~31));
+	NV_WR32(&par->riva.Bitmap->WidthHeightOutE, 0,
+		(image->height << 16) | ((image->width + 31) & ~31));
+	NV_WR32(&par->riva.Bitmap->PointE, 0,
+		(image->dy << 16) | (image->dx & 0xFFFF));
+
+	d = &par->riva.Bitmap->MonochromeData01E;
+
+	width = (image->width + 31)/32;
+	size = width * image->height;
+	while (size >= 16) {
+		RIVA_FIFO_FREE(par->riva, Bitmap, 16);
+		for (i = 0; i < 16; i++) {
+			tmp = *((u32 *)cdat);
+			cdat = (u8 *)((u32 *)cdat + 1);
+			reverse_order(&tmp);
+			NV_WR32(d, i*4, tmp);
+		}
+		size -= 16;
+	}
+	if (size) {
+		RIVA_FIFO_FREE(par->riva, Bitmap, size);
+		for (i = 0; i < size; i++) {
+			tmp = *((u32 *) cdat);
+			cdat = (u8 *)((u32 *)cdat + 1);
+			reverse_order(&tmp);
+			NV_WR32(d, i*4, tmp);
+		}
+	}
+}
+
+/**
+ * rivafb_cursor - hardware cursor function
+ * @info: pointer to info structure
+ * @cursor: pointer to fbcursor structure
+ *
+ * DESCRIPTION:
+ * A cursor function that supports displaying a cursor image via hardware.
+ * Within the kernel, copy and invert rops are supported.  If exported
+ * to user space, only the copy rop will be supported.
+ *
+ * CALLED FROM
+ * framebuffer hook
+ */
+static int rivafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+	struct riva_par *par = (struct riva_par *) info->par;
+	u8 data[MAX_CURS * MAX_CURS/8];
+	u16 fg, bg;
+	int i, set = cursor->set;
+
+	if (cursor->image.width > MAX_CURS ||
+	    cursor->image.height > MAX_CURS)
+		return soft_cursor(info, cursor);
+
+	par->riva.ShowHideCursor(&par->riva, 0);
+
+	if (par->cursor_reset) {
+		set = FB_CUR_SETALL;
+		par->cursor_reset = 0;
+	}
+
+	if (set & FB_CUR_SETSIZE)
+		memset_io(par->riva.CURSOR, 0, MAX_CURS * MAX_CURS * 2);
+
+	if (set & FB_CUR_SETPOS) {
+		u32 xx, yy, temp;
+
+		yy = cursor->image.dy - info->var.yoffset;
+		xx = cursor->image.dx - info->var.xoffset;
+		temp = xx & 0xFFFF;
+		temp |= yy << 16;
+
+		NV_WR32(par->riva.PRAMDAC, 0x0000300, temp);
+	}
+
+
+	if (set & (FB_CUR_SETSHAPE | FB_CUR_SETCMAP | FB_CUR_SETIMAGE)) {
+		u32 bg_idx = cursor->image.bg_color;
+		u32 fg_idx = cursor->image.fg_color;
+		u32 s_pitch = (cursor->image.width+7) >> 3;
+		u32 d_pitch = MAX_CURS/8;
+		u8 *dat = (u8 *) cursor->image.data;
+		u8 *msk = (u8 *) cursor->mask;
+		u8 *src;
+		
+		src = kmalloc(s_pitch * cursor->image.height, GFP_ATOMIC);
+
+		if (src) {
+			switch (cursor->rop) {
+			case ROP_XOR:
+				for (i = 0; i < s_pitch * cursor->image.height;
+				     i++)
+					src[i] = dat[i] ^ msk[i];
+				break;
+			case ROP_COPY:
+			default:
+				for (i = 0; i < s_pitch * cursor->image.height;
+				     i++)
+					src[i] = dat[i] & msk[i];
+				break;
+			}
+
+			fb_sysmove_buf_aligned(info, &info->pixmap, data,
+					       d_pitch, src, s_pitch,
+					       cursor->image.height);
+
+			bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) |
+				((info->cmap.green[bg_idx] & 0xf8) << 2) |
+				((info->cmap.blue[bg_idx] & 0xf8) >> 3) |
+				1 << 15;
+
+			fg = ((info->cmap.red[fg_idx] & 0xf8) << 7) |
+				((info->cmap.green[fg_idx] & 0xf8) << 2) |
+				((info->cmap.blue[fg_idx] & 0xf8) >> 3) |
+				1 << 15;
+
+			par->riva.LockUnlock(&par->riva, 0);
+
+			rivafb_load_cursor_image(par, data, bg, fg,
+						 cursor->image.width,
+						 cursor->image.height);
+			kfree(src);
+		}
+	}
+
+	if (cursor->enable)
+		par->riva.ShowHideCursor(&par->riva, 1);
+
+	return 0;
+}
+
+static int rivafb_sync(struct fb_info *info)
+{
+	struct riva_par *par = (struct riva_par *)info->par;
+
+	wait_for_idle(par);
+	return 0;
+}
+
+/* ------------------------------------------------------------------------- *
+ *
+ * initialization helper functions
+ *
+ * ------------------------------------------------------------------------- */
+
+/* kernel interface */
+static struct fb_ops riva_fb_ops = {
+	.owner 		= THIS_MODULE,
+	.fb_open	= rivafb_open,
+	.fb_release	= rivafb_release,
+	.fb_check_var 	= rivafb_check_var,
+	.fb_set_par 	= rivafb_set_par,
+	.fb_setcolreg 	= rivafb_setcolreg,
+	.fb_pan_display	= rivafb_pan_display,
+	.fb_blank 	= rivafb_blank,
+	.fb_fillrect 	= rivafb_fillrect,
+	.fb_copyarea 	= rivafb_copyarea,
+	.fb_imageblit 	= rivafb_imageblit,
+	.fb_cursor	= rivafb_cursor,	
+	.fb_sync 	= rivafb_sync,
+};
+
+static int __devinit riva_set_fbinfo(struct fb_info *info)
+{
+	unsigned int cmap_len;
+	struct riva_par *par = (struct riva_par *) info->par;
+
+	NVTRACE_ENTER();
+	info->flags = FBINFO_DEFAULT
+		    | FBINFO_HWACCEL_XPAN
+		    | FBINFO_HWACCEL_YPAN
+		    | FBINFO_HWACCEL_COPYAREA
+		    | FBINFO_HWACCEL_FILLRECT
+	            | FBINFO_HWACCEL_IMAGEBLIT;
+
+	/* Accel seems to not work properly on NV30 yet...*/
+	if ((par->riva.Architecture == NV_ARCH_30) || noaccel) {
+	    	printk(KERN_DEBUG PFX "disabling acceleration\n");
+  		info->flags |= FBINFO_HWACCEL_DISABLED;
+	}
+
+	info->var = rivafb_default_var;
+	info->fix.visual = (info->var.bits_per_pixel == 8) ?
+				FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
+
+	info->pseudo_palette = par->pseudo_palette;
+
+	cmap_len = riva_get_cmap_len(&info->var);
+	fb_alloc_cmap(&info->cmap, cmap_len, 0);	
+
+	info->pixmap.size = 8 * 1024;
+	info->pixmap.buf_align = 4;
+	info->pixmap.flags = FB_PIXMAP_SYSTEM;
+	info->var.yres_virtual = -1;
+	NVTRACE_LEAVE();
+	return (rivafb_check_var(&info->var, info));
+}
+
+#ifdef CONFIG_PPC_OF
+static int __devinit riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd)
+{
+	struct riva_par *par = (struct riva_par *) info->par;
+	struct device_node *dp;
+	unsigned char *pedid = NULL;
+	unsigned char *disptype = NULL;
+	static char *propnames[] = {
+		"DFP,EDID", "LCD,EDID", "EDID", "EDID1", "EDID,B", "EDID,A", NULL };
+	int i;
+
+	NVTRACE_ENTER();
+	dp = pci_device_to_OF_node(pd);
+	for (; dp != NULL; dp = dp->child) {
+		disptype = (unsigned char *)get_property(dp, "display-type", NULL);
+		if (disptype == NULL)
+			continue;
+		if (strncmp(disptype, "LCD", 3) != 0)
+			continue;
+		for (i = 0; propnames[i] != NULL; ++i) {
+			pedid = (unsigned char *)
+				get_property(dp, propnames[i], NULL);
+			if (pedid != NULL) {
+				par->EDID = pedid;
+				NVTRACE("LCD found.\n");
+				return 1;
+			}
+		}
+	}
+	NVTRACE_LEAVE();
+	return 0;
+}
+#endif /* CONFIG_PPC_OF */
+
+#if defined(CONFIG_FB_RIVA_I2C) && !defined(CONFIG_PPC_OF)
+static int __devinit riva_get_EDID_i2c(struct fb_info *info)
+{
+	struct riva_par *par = (struct riva_par *) info->par;
+	struct fb_var_screeninfo var;
+	int i;
+
+	NVTRACE_ENTER();
+	riva_create_i2c_busses(par);
+	for (i = 0; i < par->bus; i++) {
+		riva_probe_i2c_connector(par, i+1, &par->EDID);
+		if (par->EDID && !fb_parse_edid(par->EDID, &var)) {
+			printk(PFX "Found EDID Block from BUS %i\n", i);
+			break;
+		}
+	}
+
+	NVTRACE_LEAVE();
+	return (par->EDID) ? 1 : 0;
+}
+#endif /* CONFIG_FB_RIVA_I2C */
+
+static void __devinit riva_update_default_var(struct fb_var_screeninfo *var,
+					      struct fb_info *info)
+{
+	struct fb_monspecs *specs = &info->monspecs;
+	struct fb_videomode modedb;
+
+	NVTRACE_ENTER();
+	/* respect mode options */
+	if (mode_option) {
+		fb_find_mode(var, info, mode_option,
+			     specs->modedb, specs->modedb_len,
+			     NULL, 8);
+	} else if (specs->modedb != NULL) {
+		/* get preferred timing */
+		if (info->monspecs.misc & FB_MISC_1ST_DETAIL) {
+			int i;
+
+			for (i = 0; i < specs->modedb_len; i++) {
+				if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {
+					modedb = specs->modedb[i];
+					break;
+				}
+			}
+		} else {
+			/* otherwise, get first mode in database */
+			modedb = specs->modedb[0];
+		}
+		var->bits_per_pixel = 8;
+		riva_update_var(var, &modedb);
+	}
+	NVTRACE_LEAVE();
+}
+
+
+static void __devinit riva_get_EDID(struct fb_info *info, struct pci_dev *pdev)
+{
+	NVTRACE_ENTER();
+#ifdef CONFIG_PPC_OF
+	if (!riva_get_EDID_OF(info, pdev))
+		printk(PFX "could not retrieve EDID from OF\n");
+#elif CONFIG_FB_RIVA_I2C
+	if (!riva_get_EDID_i2c(info))
+		printk(PFX "could not retrieve EDID from DDC/I2C\n");
+#endif
+	NVTRACE_LEAVE();
+}
+
+
+static void __devinit riva_get_edidinfo(struct fb_info *info)
+{
+	struct fb_var_screeninfo *var = &rivafb_default_var;
+	struct riva_par *par = (struct riva_par *) info->par;
+
+	fb_edid_to_monspecs(par->EDID, &info->monspecs);
+	fb_videomode_to_modelist(info->monspecs.modedb, info->monspecs.modedb_len,
+				 &info->modelist);
+	riva_update_default_var(var, info);
+
+	/* if user specified flatpanel, we respect that */
+	if (info->monspecs.input & FB_DISP_DDI)
+		par->FlatPanel = 1;
+}
+
+/* ------------------------------------------------------------------------- *
+ *
+ * PCI bus
+ *
+ * ------------------------------------------------------------------------- */
+
+static u32 __devinit riva_get_arch(struct pci_dev *pd)
+{
+    	u32 arch = 0;
+
+	switch (pd->device & 0x0ff0) {
+		case 0x0100:   /* GeForce 256 */
+		case 0x0110:   /* GeForce2 MX */
+		case 0x0150:   /* GeForce2 */
+		case 0x0170:   /* GeForce4 MX */
+		case 0x0180:   /* GeForce4 MX (8x AGP) */
+		case 0x01A0:   /* nForce */
+		case 0x01F0:   /* nForce2 */
+		     arch =  NV_ARCH_10;
+		     break;
+		case 0x0200:   /* GeForce3 */
+		case 0x0250:   /* GeForce4 Ti */
+		case 0x0280:   /* GeForce4 Ti (8x AGP) */
+		     arch =  NV_ARCH_20;
+		     break;
+		case 0x0300:   /* GeForceFX 5800 */
+		case 0x0310:   /* GeForceFX 5600 */
+		case 0x0320:   /* GeForceFX 5200 */
+		case 0x0330:   /* GeForceFX 5900 */
+		case 0x0340:   /* GeForceFX 5700 */
+		     arch =  NV_ARCH_30;
+		     break;
+		case 0x0020:   /* TNT, TNT2 */
+		     arch =  NV_ARCH_04;
+		     break;
+		case 0x0010:   /* Riva128 */
+		     arch =  NV_ARCH_03;
+		     break;
+		default:   /* unknown architecture */
+		     break;
+	}
+	return arch;
+}
+
+static int __devinit rivafb_probe(struct pci_dev *pd,
+			     	const struct pci_device_id *ent)
+{
+	struct riva_par *default_par;
+	struct fb_info *info;
+	int ret;
+
+	NVTRACE_ENTER();
+	assert(pd != NULL);
+
+	info = framebuffer_alloc(sizeof(struct riva_par), &pd->dev);
+	if (!info) {
+		printk (KERN_ERR PFX "could not allocate memory\n");
+		ret = -ENOMEM;
+		goto err_ret;
+	}
+	default_par = (struct riva_par *) info->par;
+	default_par->pdev = pd;
+
+	info->pixmap.addr = kmalloc(8 * 1024, GFP_KERNEL);
+	if (info->pixmap.addr == NULL) {
+	    	ret = -ENOMEM;
+		goto err_framebuffer_release;
+	}
+	memset(info->pixmap.addr, 0, 8 * 1024);
+
+	ret = pci_enable_device(pd);
+	if (ret < 0) {
+		printk(KERN_ERR PFX "cannot enable PCI device\n");
+		goto err_free_pixmap;
+	}
+
+	ret = pci_request_regions(pd, "rivafb");
+	if (ret < 0) {
+		printk(KERN_ERR PFX "cannot request PCI regions\n");
+		goto err_disable_device;
+	}
+
+	default_par->riva.Architecture = riva_get_arch(pd);
+
+	default_par->Chipset = (pd->vendor << 16) | pd->device;
+	printk(KERN_INFO PFX "nVidia device/chipset %X\n",default_par->Chipset);
+	
+#ifdef CONFIG_PCI_NAMES
+	printk(KERN_INFO PFX "%s\n", pd->pretty_name);
+#endif
+
+	if(default_par->riva.Architecture == 0) {
+		printk(KERN_ERR PFX "unknown NV_ARCH\n");
+		ret=-ENODEV;
+		goto err_release_region;
+	}
+	if(default_par->riva.Architecture == NV_ARCH_10 ||
+	   default_par->riva.Architecture == NV_ARCH_20 ||
+	   default_par->riva.Architecture == NV_ARCH_30) {
+		sprintf(rivafb_fix.id, "NV%x", (pd->device & 0x0ff0) >> 4);
+	} else {
+		sprintf(rivafb_fix.id, "NV%x", default_par->riva.Architecture);
+	}
+
+	default_par->FlatPanel = flatpanel;
+	if (flatpanel == 1)
+		printk(KERN_INFO PFX "flatpanel support enabled\n");
+	default_par->forceCRTC = forceCRTC;
+	
+	rivafb_fix.mmio_len = pci_resource_len(pd, 0);
+	rivafb_fix.smem_len = pci_resource_len(pd, 1);
+
+	{
+		/* enable IO and mem if not already done */
+		unsigned short cmd;
+
+		pci_read_config_word(pd, PCI_COMMAND, &cmd);
+		cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+		pci_write_config_word(pd, PCI_COMMAND, cmd);
+	}
+	
+	rivafb_fix.mmio_start = pci_resource_start(pd, 0);
+	rivafb_fix.smem_start = pci_resource_start(pd, 1);
+
+	default_par->ctrl_base = ioremap(rivafb_fix.mmio_start,
+					 rivafb_fix.mmio_len);
+	if (!default_par->ctrl_base) {
+		printk(KERN_ERR PFX "cannot ioremap MMIO base\n");
+		ret = -EIO;
+		goto err_release_region;
+	}
+
+	switch (default_par->riva.Architecture) {
+	case NV_ARCH_03:
+		/* Riva128's PRAMIN is in the "framebuffer" space
+		 * Since these cards were never made with more than 8 megabytes
+		 * we can safely allocate this separately.
+		 */
+		default_par->riva.PRAMIN = ioremap(rivafb_fix.smem_start + 0x00C00000, 0x00008000);
+		if (!default_par->riva.PRAMIN) {
+			printk(KERN_ERR PFX "cannot ioremap PRAMIN region\n");
+			ret = -EIO;
+			goto err_iounmap_ctrl_base;
+		}
+		break;
+	case NV_ARCH_04:
+	case NV_ARCH_10:
+	case NV_ARCH_20:
+	case NV_ARCH_30:
+		default_par->riva.PCRTC0 =
+			(u32 __iomem *)(default_par->ctrl_base + 0x00600000);
+		default_par->riva.PRAMIN =
+			(u32 __iomem *)(default_par->ctrl_base + 0x00710000);
+		break;
+	}
+	riva_common_setup(default_par);
+
+	if (default_par->riva.Architecture == NV_ARCH_03) {
+		default_par->riva.PCRTC = default_par->riva.PCRTC0
+		                        = default_par->riva.PGRAPH;
+	}
+
+	rivafb_fix.smem_len = riva_get_memlen(default_par) * 1024;
+	default_par->dclk_max = riva_get_maxdclk(default_par) * 1000;
+	info->screen_base = ioremap(rivafb_fix.smem_start,
+				    rivafb_fix.smem_len);
+	if (!info->screen_base) {
+		printk(KERN_ERR PFX "cannot ioremap FB base\n");
+		ret = -EIO;
+		goto err_iounmap_pramin;
+	}
+
+#ifdef CONFIG_MTRR
+	if (!nomtrr) {
+		default_par->mtrr.vram = mtrr_add(rivafb_fix.smem_start,
+					   	  rivafb_fix.smem_len,
+					    	  MTRR_TYPE_WRCOMB, 1);
+		if (default_par->mtrr.vram < 0) {
+			printk(KERN_ERR PFX "unable to setup MTRR\n");
+		} else {
+			default_par->mtrr.vram_valid = 1;
+			/* let there be speed */
+			printk(KERN_INFO PFX "RIVA MTRR set to ON\n");
+		}
+	}
+#endif /* CONFIG_MTRR */
+
+	info->fbops = &riva_fb_ops;
+	info->fix = rivafb_fix;
+	riva_get_EDID(info, pd);
+	riva_get_edidinfo(info);
+
+	ret=riva_set_fbinfo(info);
+	if (ret < 0) {
+		printk(KERN_ERR PFX "error setting initial video mode\n");
+		goto err_iounmap_screen_base;
+	}
+
+	fb_destroy_modedb(info->monspecs.modedb);
+	info->monspecs.modedb = NULL;
+	ret = register_framebuffer(info);
+	if (ret < 0) {
+		printk(KERN_ERR PFX
+			"error registering riva framebuffer\n");
+		goto err_iounmap_screen_base;
+	}
+
+	pci_set_drvdata(pd, info);
+
+	printk(KERN_INFO PFX
+		"PCI nVidia %s framebuffer ver %s (%dMB @ 0x%lX)\n",
+		info->fix.id,
+		RIVAFB_VERSION,
+		info->fix.smem_len / (1024 * 1024),
+		info->fix.smem_start);
+#ifdef CONFIG_PMAC_BACKLIGHT
+	if (default_par->FlatPanel && _machine == _MACH_Pmac)
+	register_backlight_controller(&riva_backlight_controller,
+						default_par, "mnca");
+#endif
+	NVTRACE_LEAVE();
+	return 0;
+
+err_iounmap_screen_base:
+#ifdef CONFIG_FB_RIVA_I2C
+	riva_delete_i2c_busses((struct riva_par *) info->par);
+#endif
+	iounmap(info->screen_base);
+err_iounmap_pramin:
+	if (default_par->riva.Architecture == NV_ARCH_03) 
+		iounmap(default_par->riva.PRAMIN);
+err_iounmap_ctrl_base:
+	iounmap(default_par->ctrl_base);
+err_release_region:
+	pci_release_regions(pd);
+err_disable_device:
+	pci_disable_device(pd);
+err_free_pixmap:
+	kfree(info->pixmap.addr);
+err_framebuffer_release:
+	framebuffer_release(info);
+err_ret:
+	return ret;
+}
+
+static void __exit rivafb_remove(struct pci_dev *pd)
+{
+	struct fb_info *info = pci_get_drvdata(pd);
+	struct riva_par *par = (struct riva_par *) info->par;
+	
+	NVTRACE_ENTER();
+	if (!info)
+		return;
+
+#ifdef CONFIG_FB_RIVA_I2C
+	riva_delete_i2c_busses(par);
+	kfree(par->EDID);
+#endif
+
+	unregister_framebuffer(info);
+#ifdef CONFIG_MTRR
+	if (par->mtrr.vram_valid)
+		mtrr_del(par->mtrr.vram, info->fix.smem_start,
+			 info->fix.smem_len);
+#endif /* CONFIG_MTRR */
+
+	iounmap(par->ctrl_base);
+	iounmap(info->screen_base);
+	if (par->riva.Architecture == NV_ARCH_03)
+		iounmap(par->riva.PRAMIN);
+	pci_release_regions(pd);
+	pci_disable_device(pd);
+	kfree(info->pixmap.addr);
+	framebuffer_release(info);
+	pci_set_drvdata(pd, NULL);
+	NVTRACE_LEAVE();
+}
+
+/* ------------------------------------------------------------------------- *
+ *
+ * initialization
+ *
+ * ------------------------------------------------------------------------- */
+
+#ifndef MODULE
+static int __init rivafb_setup(char *options)
+{
+	char *this_opt;
+
+	NVTRACE_ENTER();
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!strncmp(this_opt, "forceCRTC", 9)) {
+			char *p;
+			
+			p = this_opt + 9;
+			if (!*p || !*(++p)) continue; 
+			forceCRTC = *p - '0';
+			if (forceCRTC < 0 || forceCRTC > 1) 
+				forceCRTC = -1;
+		} else if (!strncmp(this_opt, "flatpanel", 9)) {
+			flatpanel = 1;
+#ifdef CONFIG_MTRR
+		} else if (!strncmp(this_opt, "nomtrr", 6)) {
+			nomtrr = 1;
+#endif
+		} else if (!strncmp(this_opt, "strictmode", 10)) {
+			strictmode = 1;
+		} else if (!strncmp(this_opt, "noaccel", 7)) {
+			noaccel = 1;
+		} else
+			mode_option = this_opt;
+	}
+	NVTRACE_LEAVE();
+	return 0;
+}
+#endif /* !MODULE */
+
+static struct pci_driver rivafb_driver = {
+	.name		= "rivafb",
+	.id_table	= rivafb_pci_tbl,
+	.probe		= rivafb_probe,
+	.remove		= __exit_p(rivafb_remove),
+};
+
+
+
+/* ------------------------------------------------------------------------- *
+ *
+ * modularization
+ *
+ * ------------------------------------------------------------------------- */
+
+static int __devinit rivafb_init(void)
+{
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("rivafb", &option))
+		return -ENODEV;
+	rivafb_setup(option);
+#endif
+	return pci_register_driver(&rivafb_driver);
+}
+
+
+module_init(rivafb_init);
+
+#ifdef MODULE
+static void __exit rivafb_exit(void)
+{
+	pci_unregister_driver(&rivafb_driver);
+}
+
+module_exit(rivafb_exit);
+#endif /* MODULE */
+
+module_param(noaccel, bool, 0);
+MODULE_PARM_DESC(noaccel, "bool: disable acceleration");
+module_param(flatpanel, int, 0);
+MODULE_PARM_DESC(flatpanel, "Enables experimental flat panel support for some chipsets. (0 or 1=enabled) (default=0)");
+module_param(forceCRTC, int, 0);
+MODULE_PARM_DESC(forceCRTC, "Forces usage of a particular CRTC in case autodetection fails. (0 or 1) (default=autodetect)");
+#ifdef CONFIG_MTRR
+module_param(nomtrr, bool, 0);
+MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) (default=0)");
+#endif
+module_param(strictmode, bool, 0);
+MODULE_PARM_DESC(strictmode, "Only use video modes from EDID");
+
+MODULE_AUTHOR("Ani Joshi, maintainer");
+MODULE_DESCRIPTION("Framebuffer driver for nVidia Riva 128, TNT, TNT2, and the GeForce series");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/riva/nv4ref.h b/drivers/video/riva/nv4ref.h
new file mode 100644
index 0000000..3b5f911
--- /dev/null
+++ b/drivers/video/riva/nv4ref.h
@@ -0,0 +1,2445 @@
+ /***************************************************************************\
+|*                                                                           *|
+|*       Copyright 1993-1998 NVIDIA, Corporation.  All rights reserved.      *|
+|*                                                                           *|
+|*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
+|*     international laws.  Users and possessors of this source code are     *|
+|*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
+|*     use this code in individual and commercial software.                  *|
+|*                                                                           *|
+|*     Any use of this source code must include,  in the user documenta-     *|
+|*     tion and  internal comments to the code,  notices to the end user     *|
+|*     as follows:                                                           *|
+|*                                                                           *|
+|*       Copyright 1993-1998 NVIDIA, Corporation.  All rights reserved.      *|
+|*                                                                           *|
+|*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
+|*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
+|*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
+|*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
+|*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
+|*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
+|*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
+|*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
+|*     SULTING FROM LOSS OF USE,  DATA OR PROFITS,  WHETHER IN AN ACTION     *|
+|*     OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,  ARISING OUT OF     *|
+|*     OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.     *|
+|*                                                                           *|
+|*     U.S. Government  End  Users.   This source code  is a "commercial     *|
+|*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
+|*     consisting  of "commercial  computer  software"  and  "commercial     *|
+|*     computer  software  documentation,"  as such  terms  are  used in     *|
+|*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
+|*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
+|*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
+|*     all U.S. Government End Users  acquire the source code  with only     *|
+|*     those rights set forth herein.                                        *|
+|*                                                                           *|
+ \***************************************************************************/
+
+/*
+ * GPL licensing note -- nVidia is allowing a liberal interpretation of
+ * the documentation restriction above, to merely say that this nVidia's
+ * copyright and disclaimer should be included with all code derived
+ * from this source.  -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 
+ */
+
+ /***************************************************************************\
+|*            Modified 1999 by Fredrik Reite (fredrik@reite.com)             *|
+ \***************************************************************************/
+
+
+#ifndef __NV4REF_H__
+#define __NV4REF_H__
+
+/* Magic values to lock/unlock extended regs */
+#define NV_CIO_SR_LOCK_INDEX				     0x0000001F /*       */
+#define NV_CIO_SR_UNLOCK_RW_VALUE                            0x00000057 /*       */
+#define NV_CIO_SR_UNLOCK_RO_VALUE                            0x00000075 /*       */
+#define NV_CIO_SR_LOCK_VALUE                                 0x00000099 /*       */
+
+#define UNLOCK_EXT_MAGIC 0x57
+#define LOCK_EXT_MAGIC 0x99 /* Any value other than 0x57 will do */
+
+#define LOCK_EXT_INDEX 0x6
+
+#define NV_PCRTC_HORIZ_TOTAL                                 0x00
+#define NV_PCRTC_HORIZ_DISPLAY_END                           0x01
+#define NV_PCRTC_HORIZ_BLANK_START                           0x02
+
+#define NV_PCRTC_HORIZ_BLANK_END                             0x03
+#define NV_PCRTC_HORIZ_BLANK_END_EVRA                        7:7
+#define NV_PCRTC_HORIZ_BLANK_END_DISPLAY_END_SKEW            6:5
+#define NV_PCRTC_HORIZ_BLANK_END_HORIZ_BLANK_END             4:0
+
+#define NV_PCRTC_HORIZ_RETRACE_START                         0x04
+
+#define NV_PCRTC_HORIZ_RETRACE_END                           0x05
+#define NV_PCRTC_HORIZ_RETRACE_END_HORIZ_BLANK_END_5         7:7
+#define NV_PCRTC_HORIZ_RETRACE_END_HORIZ_RETRACE_SKEW        6:5
+#define NV_PCRTC_HORIZ_RETRACE_END_HORIZ_RETRACE_END         4:0
+
+#define NV_PCRTC_VERT_TOTAL                                  0x06
+
+#define NV_PCRTC_OVERFLOW                                    0x07
+#define NV_PCRTC_OVERFLOW_VERT_RETRACE_START_9               7:7
+#define NV_PCRTC_OVERFLOW_VERT_DISPLAY_END_9                 6:6
+#define NV_PCRTC_OVERFLOW_VERT_TOTAL_9                       5:5
+#define NV_PCRTC_OVERFLOW_LINE_COMPARE_8                     4:4
+#define NV_PCRTC_OVERFLOW_VERT_BLANK_START_8                 3:3
+#define NV_PCRTC_OVERFLOW_VERT_RETRACE_START_8               2:2
+#define NV_PCRTC_OVERFLOW_VERT_DISPLAY_END_8                 1:1
+#define NV_PCRTC_OVERFLOW_VERT_TOTAL_8                       0:0
+
+#define NV_PCRTC_PRESET_ROW_SCAN                             0x08
+
+#define NV_PCRTC_MAX_SCAN_LINE                               0x09
+#define NV_PCRTC_MAX_SCAN_LINE_DOUBLE_SCAN                   7:7
+#define NV_PCRTC_MAX_SCAN_LINE_LINE_COMPARE_9                6:6
+#define NV_PCRTC_MAX_SCAN_LINE_VERT_BLANK_START_9            5:5
+#define NV_PCRTC_MAX_SCAN_LINE_MAX_SCAN_LINE                 4:0
+
+#define NV_PCRTC_CURSOR_START                                0x0A
+#define NV_PCRTC_CURSOR_END                                  0x0B
+#define NV_PCRTC_START_ADDR_HIGH                             0x0C
+#define NV_PCRTC_START_ADDR_LOW                              0x0D
+#define NV_PCRTC_CURSOR_LOCATION_HIGH                        0x0E
+#define NV_PCRTC_CURSOR_LOCATION_LOW                         0x0F
+
+#define NV_PCRTC_VERT_RETRACE_START                          0x10
+#define NV_PCRTC_VERT_RETRACE_END                            0x11
+#define NV_PCRTC_VERT_DISPLAY_END                            0x12
+#define NV_PCRTC_OFFSET                                      0x13
+#define NV_PCRTC_UNDERLINE_LOCATION                          0x14
+#define NV_PCRTC_VERT_BLANK_START                            0x15
+#define NV_PCRTC_VERT_BLANK_END                              0x16
+#define NV_PCRTC_MODE_CONTROL                                0x17
+#define NV_PCRTC_LINE_COMPARE                                0x18
+
+/* Extended offset and start address */
+#define NV_PCRTC_REPAINT0                                    0x19
+#define NV_PCRTC_REPAINT0_OFFSET_10_8                        7:5 
+#define NV_PCRTC_REPAINT0_START_ADDR_20_16                   4:0
+
+/* Horizonal extended bits */
+#define NV_PCRTC_HORIZ_EXTRA                                 0x2d
+#define NV_PCRTC_HORIZ_EXTRA_INTER_HALF_START_8              4:4
+#define NV_PCRTC_HORIZ_EXTRA_HORIZ_RETRACE_START_8           3:3
+#define NV_PCRTC_HORIZ_EXTRA_HORIZ_BLANK_START_8             2:2
+#define NV_PCRTC_HORIZ_EXTRA_DISPLAY_END_8                   1:1
+#define NV_PCRTC_HORIZ_EXTRA_DISPLAY_TOTAL_8                 0:0
+
+/* Assorted extra bits */
+#define NV_PCRTC_EXTRA                                       0x25
+#define NV_PCRTC_EXTRA_OFFSET_11                             5:5
+#define NV_PCRTC_EXTRA_HORIZ_BLANK_END_6                     4:4
+#define NV_PCRTC_EXTRA_VERT_BLANK_START_10                   3:3
+#define NV_PCRTC_EXTRA_VERT_RETRACE_START_10                 2:2
+#define NV_PCRTC_EXTRA_VERT_DISPLAY_END_10                   1:1
+#define NV_PCRTC_EXTRA_VERT_TOTAL_10                         0:0
+
+/* Controls how much data the refresh fifo requests */
+#define NV_PCRTC_FIFO_CONTROL                                0x1b
+#define NV_PCRTC_FIFO_CONTROL_UNDERFLOW_WARN                 7:7
+#define NV_PCRTC_FIFO_CONTROL_BURST_LENGTH                   2:0
+#define NV_PCRTC_FIFO_CONTROL_BURST_LENGTH_8                 0x0
+#define NV_PCRTC_FIFO_CONTROL_BURST_LENGTH_32                0x1
+#define NV_PCRTC_FIFO_CONTROL_BURST_LENGTH_64                0x2
+#define NV_PCRTC_FIFO_CONTROL_BURST_LENGTH_128               0x3
+#define NV_PCRTC_FIFO_CONTROL_BURST_LENGTH_256               0x4
+
+/* When the fifo occupancy falls below *twice* the watermark,
+ * the refresh fifo will start to be refilled. If this value is 
+ * too low, you will get junk on the screen. Too high, and performance
+ * will suffer. Watermark in units of 8 bytes
+ */
+#define NV_PCRTC_FIFO                                        0x20
+#define NV_PCRTC_FIFO_RESET                                  7:7
+#define NV_PCRTC_FIFO_WATERMARK                              5:0
+
+/* Various flags */
+#define NV_PCRTC_REPAINT1                                    0x1a
+#define NV_PCRTC_REPAINT1_HSYNC                              7:7
+#define NV_PCRTC_REPAINT1_HYSNC_DISABLE                      0x01
+#define NV_PCRTC_REPAINT1_HYSNC_ENABLE                       0x00
+#define NV_PCRTC_REPAINT1_VSYNC                              6:6
+#define NV_PCRTC_REPAINT1_VYSNC_DISABLE                      0x01
+#define NV_PCRTC_REPAINT1_VYSNC_ENABLE                       0x00
+#define NV_PCRTC_REPAINT1_COMPATIBLE_TEXT                    4:4
+#define NV_PCRTC_REPAINT1_COMPATIBLE_TEXT_ENABLE             0x01
+#define NV_PCRTC_REPAINT1_COMPATIBLE_TEXT_DISABLE            0x00
+#define NV_PCRTC_REPAINT1_LARGE_SCREEN                       2:2 
+#define NV_PCRTC_REPAINT1_LARGE_SCREEN_DISABLE               0x01
+#define NV_PCRTC_REPAINT1_LARGE_SCREEN_ENABLE                0x00 /* >=1280 */
+#define NV_PCRTC_REPAINT1_PALETTE_WIDTH                      1:1
+#define NV_PCRTC_REPAINT1_PALETTE_WIDTH_8BITS                0x00
+#define NV_PCRTC_REPAINT1_PALETTE_WIDTH_6BITS                0x01
+
+#define NV_PCRTC_GRCURSOR0                                   0x30
+#define NV_PCRTC_GRCURSOR0_START_ADDR_21_16                  5:0
+
+#define NV_PCRTC_GRCURSOR1                                   0x31
+#define NV_PCRTC_GRCURSOR1_START_ADDR_15_11                  7:3
+#define NV_PCRTC_GRCURSOR1_SCAN_DBL                          1:1
+#define NV_PCRTC_GRCURSOR1_SCAN_DBL_DISABLE                  0
+#define NV_PCRTC_GRCURSOR1_SCAN_DBL_ENABLE                   1
+#define NV_PCRTC_GRCURSOR1_CURSOR                            0:0
+#define NV_PCRTC_GRCURSOR1_CURSOR_DISABLE                    0 
+#define NV_PCRTC_GRCURSOR1_CURSOR_ENABLE                     1
+
+/* Controls what the format of the framebuffer is */
+#define NV_PCRTC_PIXEL                       0x28
+#define NV_PCRTC_PIXEL_MODE                  7:7
+#define NV_PCRTC_PIXEL_MODE_TV               0x01
+#define NV_PCRTC_PIXEL_MODE_VGA              0x00
+#define NV_PCRTC_PIXEL_TV_MODE               6:6
+#define NV_PCRTC_PIXEL_TV_MODE_NTSC          0x00
+#define NV_PCRTC_PIXEL_TV_MODE_PAL           0x01
+#define NV_PCRTC_PIXEL_TV_HORIZ_ADJUST       5:3
+#define NV_PCRTC_PIXEL_FORMAT                1:0
+#define NV_PCRTC_PIXEL_FORMAT_VGA            0x00
+#define NV_PCRTC_PIXEL_FORMAT_8BPP           0x01
+#define NV_PCRTC_PIXEL_FORMAT_16BPP          0x02
+#define NV_PCRTC_PIXEL_FORMAT_32BPP          0x03
+
+/* RAMDAC registers and fields */
+#define NV_PRAMDAC                            0x00680FFF:0x00680000 /* RW--D */
+#define NV_PRAMDAC_GRCURSOR_START_POS                    0x00680300 /* RW-4R */
+#define NV_PRAMDAC_GRCURSOR_START_POS_X                        11:0 /* RWXSF */
+#define NV_PRAMDAC_GRCURSOR_START_POS_Y                       27:16 /* RWXSF */
+#define NV_PRAMDAC_NVPLL_COEFF                           0x00680500 /* RW-4R */
+#define NV_PRAMDAC_NVPLL_COEFF_MDIV                             7:0 /* RWIUF */
+#define NV_PRAMDAC_NVPLL_COEFF_NDIV                            15:8 /* RWIUF */
+#define NV_PRAMDAC_NVPLL_COEFF_PDIV                           18:16 /* RWIVF */
+#define NV_PRAMDAC_MPLL_COEFF                            0x00680504 /* RW-4R */
+#define NV_PRAMDAC_MPLL_COEFF_MDIV                              7:0 /* RWIUF */
+#define NV_PRAMDAC_MPLL_COEFF_NDIV                             15:8 /* RWIUF */
+#define NV_PRAMDAC_MPLL_COEFF_PDIV                            18:16 /* RWIVF */
+#define NV_PRAMDAC_VPLL_COEFF                            0x00680508 /* RW-4R */
+#define NV_PRAMDAC_VPLL_COEFF_MDIV                              7:0 /* RWIUF */
+#define NV_PRAMDAC_VPLL_COEFF_NDIV                             15:8 /* RWIUF */
+#define NV_PRAMDAC_VPLL_COEFF_PDIV                            18:16 /* RWIVF */
+#define NV_PRAMDAC_PLL_COEFF_SELECT                      0x0068050C /* RW-4R */
+#define NV_PRAMDAC_PLL_COEFF_SELECT_DLL_BYPASS                  4:4 /* RWIVF */
+#define NV_PRAMDAC_PLL_COEFF_SELECT_DLL_BYPASS_FALSE     0x00000000 /* RWI-V */
+#define NV_PRAMDAC_PLL_COEFF_SELECT_DLL_BYPASS_TRUE      0x00000001 /* RW--V */
+#define NV_PRAMDAC_PLL_COEFF_SELECT_MPLL_SOURCE                 8:8 /* RWIVF */
+#define NV_PRAMDAC_PLL_COEFF_SELECT_MPLL_SOURCE_DEFAULT  0x00000000 /* RWI-V */
+#define NV_PRAMDAC_PLL_COEFF_SELECT_MPLL_SOURCE_PROG     0x00000001 /* RW--V */
+#define NV_PRAMDAC_PLL_COEFF_SELECT_MPLL_BYPASS               12:12 /* RWIVF */
+#define NV_PRAMDAC_PLL_COEFF_SELECT_MPLL_BYPASS_FALSE    0x00000000 /* RWI-V */
+#define NV_PRAMDAC_PLL_COEFF_SELECT_MPLL_BYPASS_TRUE     0x00000001 /* RW--V */
+#define NV_PRAMDAC_PLL_COEFF_SELECT_VPLL_SOURCE               16:16 /* RWIVF */
+#define NV_PRAMDAC_PLL_COEFF_SELECT_VPLL_SOURCE_DEFAULT  0x00000000 /* RWI-V */
+#define NV_PRAMDAC_PLL_COEFF_SELECT_VPLL_SOURCE_PROG     0x00000001 /* RW--V */
+#define NV_PRAMDAC_PLL_COEFF_SELECT_VPLL_BYPASS               20:20 /* RWIVF */
+#define NV_PRAMDAC_PLL_COEFF_SELECT_VPLL_BYPASS_FALSE    0x00000000 /* RWI-V */
+#define NV_PRAMDAC_PLL_COEFF_SELECT_VPLL_BYPASS_TRUE     0x00000001 /* RW--V */
+#define NV_PRAMDAC_PLL_COEFF_SELECT_PCLK_SOURCE               25:24 /* RWIVF */
+#define NV_PRAMDAC_PLL_COEFF_SELECT_PCLK_SOURCE_VPLL     0x00000000 /* RWI-V */
+#define NV_PRAMDAC_PLL_COEFF_SELECT_PCLK_SOURCE_VIP      0x00000001 /* RW--V */
+#define NV_PRAMDAC_PLL_COEFF_SELECT_PCLK_SOURCE_XTALOSC  0x00000002 /* RW--V */
+#define NV_PRAMDAC_PLL_COEFF_SELECT_VCLK_RATIO                28:28 /* RWIVF */
+#define NV_PRAMDAC_PLL_COEFF_SELECT_VCLK_RATIO_DB1       0x00000000 /* RWI-V */
+#define NV_PRAMDAC_PLL_COEFF_SELECT_VCLK_RATIO_DB2       0x00000001 /* RW--V */
+#define NV_PRAMDAC_GENERAL_CONTROL                       0x00680600 /* RW-4R */
+#define NV_PRAMDAC_GENERAL_CONTROL_FF_COEFF                     1:0 /* RWIVF */
+#define NV_PRAMDAC_GENERAL_CONTROL_FF_COEFF_DEF          0x00000000 /* RWI-V */
+#define NV_PRAMDAC_GENERAL_CONTROL_IDC_MODE                     4:4 /* RWIVF */
+#define NV_PRAMDAC_GENERAL_CONTROL_IDC_MODE_GAMMA        0x00000000 /* RWI-V */
+#define NV_PRAMDAC_GENERAL_CONTROL_IDC_MODE_INDEX        0x00000001 /* RW--V */
+#define NV_PRAMDAC_GENERAL_CONTROL_VGA_STATE                    8:8 /* RWIVF */
+#define NV_PRAMDAC_GENERAL_CONTROL_VGA_STATE_NOTSE       0x00000000 /* RWI-V */
+#define NV_PRAMDAC_GENERAL_CONTROL_VGA_STATE_SEL         0x00000001 /* RW--V */
+#define NV_PRAMDAC_GENERAL_CONTROL_565_MODE                   12:12 /* RWIVF */
+#define NV_PRAMDAC_GENERAL_CONTROL_565_MODE_NOTSEL       0x00000000 /* RWI-V */
+#define NV_PRAMDAC_GENERAL_CONTROL_565_MODE_SEL          0x00000001 /* RW--V */
+#define NV_PRAMDAC_GENERAL_CONTROL_BLK_PEDSTL                 16:16 /* RWIVF */
+#define NV_PRAMDAC_GENERAL_CONTROL_BLK_PEDSTL_OFF        0x00000000 /* RWI-V */
+#define NV_PRAMDAC_GENERAL_CONTROL_BLK_PEDSTL_ON         0x00000001 /* RW--V */
+#define NV_PRAMDAC_GENERAL_CONTROL_TERMINATION                17:17 /* RWIVF */
+#define NV_PRAMDAC_GENERAL_CONTROL_TERMINATION_37OHM     0x00000000 /* RWI-V */
+#define NV_PRAMDAC_GENERAL_CONTROL_TERMINATION_75OHM     0x00000001 /* RW--V */
+#define NV_PRAMDAC_GENERAL_CONTROL_BPC                        20:20 /* RWIVF */
+#define NV_PRAMDAC_GENERAL_CONTROL_BPC_6BITS             0x00000000 /* RWI-V */
+#define NV_PRAMDAC_GENERAL_CONTROL_BPC_8BITS             0x00000001 /* RW--V */
+#define NV_PRAMDAC_GENERAL_CONTROL_DAC_SLEEP                  24:24 /* RWIVF */
+#define NV_PRAMDAC_GENERAL_CONTROL_DAC_SLEEP_DIS         0x00000000 /* RWI-V */
+#define NV_PRAMDAC_GENERAL_CONTROL_DAC_SLEEP_EN          0x00000001 /* RW--V */
+#define NV_PRAMDAC_GENERAL_CONTROL_PALETTE_CLK                28:28 /* RWIVF */
+#define NV_PRAMDAC_GENERAL_CONTROL_PALETTE_CLK_EN        0x00000000 /* RWI-V */
+#define NV_PRAMDAC_GENERAL_CONTROL_PALETTE_CLK_DIS       0x00000001 /* RW--V */
+
+/* Master Control */
+#define NV_PMC                                0x00000FFF:0x00000000 /* RW--D */
+#define NV_PMC_BOOT_0                                    0x00000000 /* R--4R */
+#define NV_PMC_BOOT_0_MINOR_REVISION                            3:0 /* C--VF */
+#define NV_PMC_BOOT_0_MINOR_REVISION_0                   0x00000000 /* C---V */
+#define NV_PMC_BOOT_0_MAJOR_REVISION                            7:4 /* C--VF */
+#define NV_PMC_BOOT_0_MAJOR_REVISION_A                   0x00000000 /* C---V */
+#define NV_PMC_BOOT_0_MAJOR_REVISION_B                   0x00000001 /* ----V */
+#define NV_PMC_BOOT_0_IMPLEMENTATION                           11:8 /* C--VF */
+#define NV_PMC_BOOT_0_IMPLEMENTATION_NV4_0               0x00000000 /* C---V */
+#define NV_PMC_BOOT_0_ARCHITECTURE                            15:12 /* C--VF */
+#define NV_PMC_BOOT_0_ARCHITECTURE_NV0                   0x00000000 /* ----V */
+#define NV_PMC_BOOT_0_ARCHITECTURE_NV1                   0x00000001 /* ----V */
+#define NV_PMC_BOOT_0_ARCHITECTURE_NV2                   0x00000002 /* ----V */
+#define NV_PMC_BOOT_0_ARCHITECTURE_NV3                   0x00000003 /* ----V */
+#define NV_PMC_BOOT_0_ARCHITECTURE_NV4                   0x00000004 /* C---V */
+#define NV_PMC_BOOT_0_FIB_REVISION                            19:16 /* C--VF */
+#define NV_PMC_BOOT_0_FIB_REVISION_0                     0x00000000 /* C---V */
+#define NV_PMC_BOOT_0_MASK_REVISION                           23:20 /* C--VF */
+#define NV_PMC_BOOT_0_MASK_REVISION_A                    0x00000000 /* C---V */
+#define NV_PMC_BOOT_0_MASK_REVISION_B                    0x00000001 /* ----V */
+#define NV_PMC_BOOT_0_MANUFACTURER                            27:24 /* C--UF */
+#define NV_PMC_BOOT_0_MANUFACTURER_NVIDIA                0x00000000 /* C---V */
+#define NV_PMC_BOOT_0_FOUNDRY                                 31:28 /* C--VF */
+#define NV_PMC_BOOT_0_FOUNDRY_SGS                        0x00000000 /* ----V */
+#define NV_PMC_BOOT_0_FOUNDRY_HELIOS                     0x00000001 /* ----V */
+#define NV_PMC_BOOT_0_FOUNDRY_TSMC                       0x00000002 /* C---V */
+#define NV_PMC_INTR_0                                    0x00000100 /* RW-4R */
+#define NV_PMC_INTR_0_PMEDIA                                    4:4 /* R--VF */
+#define NV_PMC_INTR_0_PMEDIA_NOT_PENDING                 0x00000000 /* R---V */
+#define NV_PMC_INTR_0_PMEDIA_PENDING                     0x00000001 /* R---V */
+#define NV_PMC_INTR_0_PFIFO                                     8:8 /* R--VF */
+#define NV_PMC_INTR_0_PFIFO_NOT_PENDING                  0x00000000 /* R---V */
+#define NV_PMC_INTR_0_PFIFO_PENDING                      0x00000001 /* R---V */
+#define NV_PMC_INTR_0_PGRAPH                                  12:12 /* R--VF */
+#define NV_PMC_INTR_0_PGRAPH_NOT_PENDING                 0x00000000 /* R---V */
+#define NV_PMC_INTR_0_PGRAPH_PENDING                     0x00000001 /* R---V */
+#define NV_PMC_INTR_0_PVIDEO                                  16:16 /* R--VF */
+#define NV_PMC_INTR_0_PVIDEO_NOT_PENDING                 0x00000000 /* R---V */
+#define NV_PMC_INTR_0_PVIDEO_PENDING                     0x00000001 /* R---V */
+#define NV_PMC_INTR_0_PTIMER                                  20:20 /* R--VF */
+#define NV_PMC_INTR_0_PTIMER_NOT_PENDING                 0x00000000 /* R---V */
+#define NV_PMC_INTR_0_PTIMER_PENDING                     0x00000001 /* R---V */
+#define NV_PMC_INTR_0_PCRTC                                   24:24 /* R--VF */
+#define NV_PMC_INTR_0_PCRTC_NOT_PENDING                  0x00000000 /* R---V */
+#define NV_PMC_INTR_0_PCRTC_PENDING                      0x00000001 /* R---V */
+#define NV_PMC_INTR_0_PBUS                                    28:28 /* R--VF */
+#define NV_PMC_INTR_0_PBUS_NOT_PENDING                   0x00000000 /* R---V */
+#define NV_PMC_INTR_0_PBUS_PENDING                       0x00000001 /* R---V */
+#define NV_PMC_INTR_0_SOFTWARE                                31:31 /* RWIVF */
+#define NV_PMC_INTR_0_SOFTWARE_NOT_PENDING               0x00000000 /* RWI-V */
+#define NV_PMC_INTR_0_SOFTWARE_PENDING                   0x00000001 /* RW--V */
+#define NV_PMC_INTR_EN_0                                 0x00000140 /* RW-4R */
+#define NV_PMC_INTR_EN_0_INTA                                   1:0 /* RWIVF */
+#define NV_PMC_INTR_EN_0_INTA_DISABLED                   0x00000000 /* RWI-V */
+#define NV_PMC_INTR_EN_0_INTA_HARDWARE                   0x00000001 /* RW--V */
+#define NV_PMC_INTR_EN_0_INTA_SOFTWARE                   0x00000002 /* RW--V */
+#define NV_PMC_INTR_READ_0                               0x00000160 /* R--4R */
+#define NV_PMC_INTR_READ_0_INTA                                 0:0 /* R--VF */
+#define NV_PMC_INTR_READ_0_INTA_LOW                      0x00000000 /* R---V */
+#define NV_PMC_INTR_READ_0_INTA_HIGH                     0x00000001 /* R---V */
+#define NV_PMC_ENABLE                                    0x00000200 /* RW-4R */
+#define NV_PMC_ENABLE_PMEDIA                                    4:4 /* RWIVF */
+#define NV_PMC_ENABLE_PMEDIA_DISABLED                    0x00000000 /* RWI-V */
+#define NV_PMC_ENABLE_PMEDIA_ENABLED                     0x00000001 /* RW--V */
+#define NV_PMC_ENABLE_PFIFO                                     8:8 /* RWIVF */
+#define NV_PMC_ENABLE_PFIFO_DISABLED                     0x00000000 /* RWI-V */
+#define NV_PMC_ENABLE_PFIFO_ENABLED                      0x00000001 /* RW--V */
+#define NV_PMC_ENABLE_PGRAPH                                  12:12 /* RWIVF */
+#define NV_PMC_ENABLE_PGRAPH_DISABLED                    0x00000000 /* RWI-V */
+#define NV_PMC_ENABLE_PGRAPH_ENABLED                     0x00000001 /* RW--V */
+#define NV_PMC_ENABLE_PPMI                                    16:16 /* RWIVF */
+#define NV_PMC_ENABLE_PPMI_DISABLED                      0x00000000 /* RWI-V */
+#define NV_PMC_ENABLE_PPMI_ENABLED                       0x00000001 /* RW--V */
+#define NV_PMC_ENABLE_PFB                                     20:20 /* RWIVF */
+#define NV_PMC_ENABLE_PFB_DISABLED                       0x00000000 /* RW--V */
+#define NV_PMC_ENABLE_PFB_ENABLED                        0x00000001 /* RWI-V */
+#define NV_PMC_ENABLE_PCRTC                                   24:24 /* RWIVF */
+#define NV_PMC_ENABLE_PCRTC_DISABLED                     0x00000000 /* RW--V */
+#define NV_PMC_ENABLE_PCRTC_ENABLED                      0x00000001 /* RWI-V */
+#define NV_PMC_ENABLE_PVIDEO                                  28:28 /* RWIVF */
+#define NV_PMC_ENABLE_PVIDEO_DISABLED                    0x00000000 /* RWI-V */
+#define NV_PMC_ENABLE_PVIDEO_ENABLED                     0x00000001 /* RW--V */
+
+/* dev_timer.ref */
+#define NV_PTIMER                             0x00009FFF:0x00009000 /* RW--D */
+#define NV_PTIMER_INTR_0                                 0x00009100 /* RW-4R */
+#define NV_PTIMER_INTR_0_ALARM                                  0:0 /* RWXVF */
+#define NV_PTIMER_INTR_0_ALARM_NOT_PENDING               0x00000000 /* R---V */
+#define NV_PTIMER_INTR_0_ALARM_PENDING                   0x00000001 /* R---V */
+#define NV_PTIMER_INTR_0_ALARM_RESET                     0x00000001 /* -W--V */
+#define NV_PTIMER_INTR_EN_0                              0x00009140 /* RW-4R */
+#define NV_PTIMER_INTR_EN_0_ALARM                               0:0 /* RWIVF */
+#define NV_PTIMER_INTR_EN_0_ALARM_DISABLED               0x00000000 /* RWI-V */
+#define NV_PTIMER_INTR_EN_0_ALARM_ENABLED                0x00000001 /* RW--V */
+#define NV_PTIMER_NUMERATOR                              0x00009200 /* RW-4R */
+#define NV_PTIMER_NUMERATOR_VALUE                              15:0 /* RWIUF */
+#define NV_PTIMER_NUMERATOR_VALUE_0                      0x00000000 /* RWI-V */
+#define NV_PTIMER_DENOMINATOR                            0x00009210 /* RW-4R */
+#define NV_PTIMER_DENOMINATOR_VALUE                            15:0 /* RWIUF */
+#define NV_PTIMER_DENOMINATOR_VALUE_0                    0x00000000 /* RWI-V */
+#define NV_PTIMER_TIME_0                                 0x00009400 /* RW-4R */
+#define NV_PTIMER_TIME_0_NSEC                                  31:5 /* RWXUF */
+#define NV_PTIMER_TIME_1                                 0x00009410 /* RW-4R */
+#define NV_PTIMER_TIME_1_NSEC                                  28:0 /* RWXUF */
+#define NV_PTIMER_ALARM_0                                0x00009420 /* RW-4R */
+#define NV_PTIMER_ALARM_0_NSEC                                 31:5 /* RWXUF */
+
+/* dev_fifo.ref */
+#define NV_PFIFO                              0x00003FFF:0x00002000 /* RW--D */
+#define NV_PFIFO_DELAY_0                                 0x00002040 /* RW-4R */
+#define NV_PFIFO_DELAY_0_WAIT_RETRY                             9:0 /* RWIUF */
+#define NV_PFIFO_DELAY_0_WAIT_RETRY_0                    0x00000000 /* RWI-V */
+#define NV_PFIFO_DMA_TIMESLICE                           0x00002044 /* RW-4R */
+#define NV_PFIFO_DMA_TIMESLICE_SELECT                          16:0 /* RWIUF */
+#define NV_PFIFO_DMA_TIMESLICE_SELECT_1                  0x00000000 /* RWI-V */
+#define NV_PFIFO_DMA_TIMESLICE_SELECT_16K                0x00003fff /* RW--V */
+#define NV_PFIFO_DMA_TIMESLICE_SELECT_32K                0x00007fff /* RW--V */
+#define NV_PFIFO_DMA_TIMESLICE_SELECT_64K                0x0000ffff /* RW--V */
+#define NV_PFIFO_DMA_TIMESLICE_SELECT_128K               0x0001ffff /* RW--V */
+#define NV_PFIFO_DMA_TIMESLICE_TIMEOUT                        24:24 /* RWIUF */
+#define NV_PFIFO_DMA_TIMESLICE_TIMEOUT_DISABLED          0x00000000 /* RW--V */
+#define NV_PFIFO_DMA_TIMESLICE_TIMEOUT_ENABLED           0x00000001 /* RWI-V */
+#define NV_PFIFO_PIO_TIMESLICE                           0x00002048 /* RW-4R */
+#define NV_PFIFO_PIO_TIMESLICE_SELECT                          16:0 /* RWIUF */
+#define NV_PFIFO_PIO_TIMESLICE_SELECT_1                  0x00000000 /* RWI-V */
+#define NV_PFIFO_PIO_TIMESLICE_SELECT_16K                0x00003fff /* RW--V */
+#define NV_PFIFO_PIO_TIMESLICE_SELECT_32K                0x00007fff /* RW--V */
+#define NV_PFIFO_PIO_TIMESLICE_SELECT_64K                0x0000ffff /* RW--V */
+#define NV_PFIFO_PIO_TIMESLICE_SELECT_128K               0x0001ffff /* RW--V */
+#define NV_PFIFO_PIO_TIMESLICE_TIMEOUT                        24:24 /* RWIUF */
+#define NV_PFIFO_PIO_TIMESLICE_TIMEOUT_DISABLED          0x00000000 /* RW--V */
+#define NV_PFIFO_PIO_TIMESLICE_TIMEOUT_ENABLED           0x00000001 /* RWI-V */
+#define NV_PFIFO_TIMESLICE                               0x0000204C /* RW-4R */
+#define NV_PFIFO_TIMESLICE_TIMER                               17:0 /* RWIUF */
+#define NV_PFIFO_TIMESLICE_TIMER_EXPIRED                 0x0003FFFF /* RWI-V */
+#define NV_PFIFO_NEXT_CHANNEL                            0x00002050 /* RW-4R */
+#define NV_PFIFO_NEXT_CHANNEL_CHID                              3:0 /* RWXUF */
+#define NV_PFIFO_NEXT_CHANNEL_MODE                              8:8 /* RWXVF */
+#define NV_PFIFO_NEXT_CHANNEL_MODE_PIO                   0x00000000 /* RW--V */
+#define NV_PFIFO_NEXT_CHANNEL_MODE_DMA                   0x00000001 /* RW--V */
+#define NV_PFIFO_NEXT_CHANNEL_SWITCH                          12:12 /* RWIVF */
+#define NV_PFIFO_NEXT_CHANNEL_SWITCH_NOT_PENDING         0x00000000 /* RWI-V */
+#define NV_PFIFO_NEXT_CHANNEL_SWITCH_PENDING             0x00000001 /* RW--V */
+#define NV_PFIFO_DEBUG_0                                 0x00002080 /* R--4R */
+#define NV_PFIFO_DEBUG_0_CACHE_ERROR0                           0:0 /* R-XVF */
+#define NV_PFIFO_DEBUG_0_CACHE_ERROR0_NOT_PENDING        0x00000000 /* R---V */
+#define NV_PFIFO_DEBUG_0_CACHE_ERROR0_PENDING            0x00000001 /* R---V */
+#define NV_PFIFO_DEBUG_0_CACHE_ERROR1                           4:4 /* R-XVF */
+#define NV_PFIFO_DEBUG_0_CACHE_ERROR1_NOT_PENDING        0x00000000 /* R---V */
+#define NV_PFIFO_DEBUG_0_CACHE_ERROR1_PENDING            0x00000001 /* R---V */
+#define NV_PFIFO_INTR_0                                  0x00002100 /* RW-4R */
+#define NV_PFIFO_INTR_0_CACHE_ERROR                             0:0 /* RWXVF */
+#define NV_PFIFO_INTR_0_CACHE_ERROR_NOT_PENDING          0x00000000 /* R---V */
+#define NV_PFIFO_INTR_0_CACHE_ERROR_PENDING              0x00000001 /* R---V */
+#define NV_PFIFO_INTR_0_CACHE_ERROR_RESET                0x00000001 /* -W--V */
+#define NV_PFIFO_INTR_0_RUNOUT                                  4:4 /* RWXVF */
+#define NV_PFIFO_INTR_0_RUNOUT_NOT_PENDING               0x00000000 /* R---V */
+#define NV_PFIFO_INTR_0_RUNOUT_PENDING                   0x00000001 /* R---V */
+#define NV_PFIFO_INTR_0_RUNOUT_RESET                     0x00000001 /* -W--V */
+#define NV_PFIFO_INTR_0_RUNOUT_OVERFLOW                         8:8 /* RWXVF */
+#define NV_PFIFO_INTR_0_RUNOUT_OVERFLOW_NOT_PENDING      0x00000000 /* R---V */
+#define NV_PFIFO_INTR_0_RUNOUT_OVERFLOW_PENDING          0x00000001 /* R---V */
+#define NV_PFIFO_INTR_0_RUNOUT_OVERFLOW_RESET            0x00000001 /* -W--V */
+#define NV_PFIFO_INTR_0_DMA_PUSHER                            12:12 /* RWXVF */
+#define NV_PFIFO_INTR_0_DMA_PUSHER_NOT_PENDING           0x00000000 /* R---V */
+#define NV_PFIFO_INTR_0_DMA_PUSHER_PENDING               0x00000001 /* R---V */
+#define NV_PFIFO_INTR_0_DMA_PUSHER_RESET                 0x00000001 /* -W--V */
+#define NV_PFIFO_INTR_0_DMA_PT                                16:16 /* RWXVF */
+#define NV_PFIFO_INTR_0_DMA_PT_NOT_PENDING               0x00000000 /* R---V */
+#define NV_PFIFO_INTR_0_DMA_PT_PENDING                   0x00000001 /* R---V */
+#define NV_PFIFO_INTR_0_DMA_PT_RESET                     0x00000001 /* -W--V */
+#define NV_PFIFO_INTR_EN_0                               0x00002140 /* RW-4R */
+#define NV_PFIFO_INTR_EN_0_CACHE_ERROR                          0:0 /* RWIVF */
+#define NV_PFIFO_INTR_EN_0_CACHE_ERROR_DISABLED          0x00000000 /* RWI-V */
+#define NV_PFIFO_INTR_EN_0_CACHE_ERROR_ENABLED           0x00000001 /* RW--V */
+#define NV_PFIFO_INTR_EN_0_RUNOUT                               4:4 /* RWIVF */
+#define NV_PFIFO_INTR_EN_0_RUNOUT_DISABLED               0x00000000 /* RWI-V */
+#define NV_PFIFO_INTR_EN_0_RUNOUT_ENABLED                0x00000001 /* RW--V */
+#define NV_PFIFO_INTR_EN_0_RUNOUT_OVERFLOW                      8:8 /* RWIVF */
+#define NV_PFIFO_INTR_EN_0_RUNOUT_OVERFLOW_DISABLED      0x00000000 /* RWI-V */
+#define NV_PFIFO_INTR_EN_0_RUNOUT_OVERFLOW_ENABLED       0x00000001 /* RW--V */
+#define NV_PFIFO_INTR_EN_0_DMA_PUSHER                         12:12 /* RWIVF */
+#define NV_PFIFO_INTR_EN_0_DMA_PUSHER_DISABLED           0x00000000 /* RWI-V */
+#define NV_PFIFO_INTR_EN_0_DMA_PUSHER_ENABLED            0x00000001 /* RW--V */
+#define NV_PFIFO_INTR_EN_0_DMA_PT                             16:16 /* RWIVF */
+#define NV_PFIFO_INTR_EN_0_DMA_PT_DISABLED               0x00000000 /* RWI-V */
+#define NV_PFIFO_INTR_EN_0_DMA_PT_ENABLED                0x00000001 /* RW--V */
+#define NV_PFIFO_RAMHT                                   0x00002210 /* RW-4R */
+#define NV_PFIFO_RAMHT_BASE_ADDRESS                             8:4 /* RWIUF */
+#define NV_PFIFO_RAMHT_BASE_ADDRESS_10000                0x00000010 /* RWI-V */
+#define NV_PFIFO_RAMHT_SIZE                                   17:16 /* RWIUF */
+#define NV_PFIFO_RAMHT_SIZE_4K                           0x00000000 /* RWI-V */
+#define NV_PFIFO_RAMHT_SIZE_8K                           0x00000001 /* RW--V */
+#define NV_PFIFO_RAMHT_SIZE_16K                          0x00000002 /* RW--V */
+#define NV_PFIFO_RAMHT_SIZE_32K                          0x00000003 /* RW--V */
+#define NV_PFIFO_RAMHT_SEARCH                                 25:24 /* RWIUF */
+#define NV_PFIFO_RAMHT_SEARCH_16                         0x00000000 /* RWI-V */
+#define NV_PFIFO_RAMHT_SEARCH_32                         0x00000001 /* RW--V */
+#define NV_PFIFO_RAMHT_SEARCH_64                         0x00000002 /* RW--V */
+#define NV_PFIFO_RAMHT_SEARCH_128                        0x00000003 /* RW--V */
+#define NV_PFIFO_RAMFC                                   0x00002214 /* RW-4R */
+#define NV_PFIFO_RAMFC_BASE_ADDRESS                             8:1 /* RWIUF */
+#define NV_PFIFO_RAMFC_BASE_ADDRESS_11000                0x00000088 /* RWI-V */
+#define NV_PFIFO_RAMRO                                   0x00002218 /* RW-4R */
+#define NV_PFIFO_RAMRO_BASE_ADDRESS                             8:1 /* RWIUF */
+#define NV_PFIFO_RAMRO_BASE_ADDRESS_11200                0x00000089 /* RWI-V */
+#define NV_PFIFO_RAMRO_BASE_ADDRESS_12000                0x00000090 /* RW--V */
+#define NV_PFIFO_RAMRO_SIZE                                   16:16 /* RWIVF */
+#define NV_PFIFO_RAMRO_SIZE_512                          0x00000000 /* RWI-V */
+#define NV_PFIFO_RAMRO_SIZE_8K                           0x00000001 /* RW--V */
+#define NV_PFIFO_CACHES                                  0x00002500 /* RW-4R */
+#define NV_PFIFO_CACHES_REASSIGN                                0:0 /* RWIVF */
+#define NV_PFIFO_CACHES_REASSIGN_DISABLED                0x00000000 /* RWI-V */
+#define NV_PFIFO_CACHES_REASSIGN_ENABLED                 0x00000001 /* RW--V */
+#define NV_PFIFO_CACHES_DMA_SUSPEND                             4:4 /* R--VF */
+#define NV_PFIFO_CACHES_DMA_SUSPEND_IDLE                 0x00000000 /* R---V */
+#define NV_PFIFO_CACHES_DMA_SUSPEND_BUSY                 0x00000001 /* R---V */
+#define NV_PFIFO_MODE                                    0x00002504 /* RW-4R */
+#define NV_PFIFO_MODE_CHANNEL_0                                 0:0 /* RWIVF */
+#define NV_PFIFO_MODE_CHANNEL_0_PIO                      0x00000000 /* RWI-V */
+#define NV_PFIFO_MODE_CHANNEL_0_DMA                      0x00000001 /* RW--V */
+#define NV_PFIFO_MODE_CHANNEL_1                                 1:1 /* RWIVF */
+#define NV_PFIFO_MODE_CHANNEL_1_PIO                      0x00000000 /* RWI-V */
+#define NV_PFIFO_MODE_CHANNEL_1_DMA                      0x00000001 /* RW--V */
+#define NV_PFIFO_MODE_CHANNEL_2                                 2:2 /* RWIVF */
+#define NV_PFIFO_MODE_CHANNEL_2_PIO                      0x00000000 /* RWI-V */
+#define NV_PFIFO_MODE_CHANNEL_2_DMA                      0x00000001 /* RW--V */
+#define NV_PFIFO_MODE_CHANNEL_3                                 3:3 /* RWIVF */
+#define NV_PFIFO_MODE_CHANNEL_3_PIO                      0x00000000 /* RWI-V */
+#define NV_PFIFO_MODE_CHANNEL_3_DMA                      0x00000001 /* RW--V */
+#define NV_PFIFO_MODE_CHANNEL_4                                 4:4 /* RWIVF */
+#define NV_PFIFO_MODE_CHANNEL_4_PIO                      0x00000000 /* RWI-V */
+#define NV_PFIFO_MODE_CHANNEL_4_DMA                      0x00000001 /* RW--V */
+#define NV_PFIFO_MODE_CHANNEL_5                                 5:5 /* RWIVF */
+#define NV_PFIFO_MODE_CHANNEL_5_PIO                      0x00000000 /* RWI-V */
+#define NV_PFIFO_MODE_CHANNEL_5_DMA                      0x00000001 /* RW--V */
+#define NV_PFIFO_MODE_CHANNEL_6                                 6:6 /* RWIVF */
+#define NV_PFIFO_MODE_CHANNEL_6_PIO                      0x00000000 /* RWI-V */
+#define NV_PFIFO_MODE_CHANNEL_6_DMA                      0x00000001 /* RW--V */
+#define NV_PFIFO_MODE_CHANNEL_7                                 7:7 /* RWIVF */
+#define NV_PFIFO_MODE_CHANNEL_7_PIO                      0x00000000 /* RWI-V */
+#define NV_PFIFO_MODE_CHANNEL_7_DMA                      0x00000001 /* RW--V */
+#define NV_PFIFO_MODE_CHANNEL_8                                 8:8 /* RWIVF */
+#define NV_PFIFO_MODE_CHANNEL_8_PIO                      0x00000000 /* RWI-V */
+#define NV_PFIFO_MODE_CHANNEL_8_DMA                      0x00000001 /* RW--V */
+#define NV_PFIFO_MODE_CHANNEL_9                                 9:9 /* RWIVF */
+#define NV_PFIFO_MODE_CHANNEL_9_PIO                      0x00000000 /* RWI-V */
+#define NV_PFIFO_MODE_CHANNEL_9_DMA                      0x00000001 /* RW--V */
+#define NV_PFIFO_MODE_CHANNEL_10                              10:10 /* RWIVF */
+#define NV_PFIFO_MODE_CHANNEL_10_PIO                     0x00000000 /* RWI-V */
+#define NV_PFIFO_MODE_CHANNEL_10_DMA                     0x00000001 /* RW--V */
+#define NV_PFIFO_MODE_CHANNEL_11                              11:11 /* RWIVF */
+#define NV_PFIFO_MODE_CHANNEL_11_PIO                     0x00000000 /* RWI-V */
+#define NV_PFIFO_MODE_CHANNEL_11_DMA                     0x00000001 /* RW--V */
+#define NV_PFIFO_MODE_CHANNEL_12                              12:12 /* RWIVF */
+#define NV_PFIFO_MODE_CHANNEL_12_PIO                     0x00000000 /* RWI-V */
+#define NV_PFIFO_MODE_CHANNEL_12_DMA                     0x00000001 /* RW--V */
+#define NV_PFIFO_MODE_CHANNEL_13                              13:13 /* RWIVF */
+#define NV_PFIFO_MODE_CHANNEL_13_PIO                     0x00000000 /* RWI-V */
+#define NV_PFIFO_MODE_CHANNEL_13_DMA                     0x00000001 /* RW--V */
+#define NV_PFIFO_MODE_CHANNEL_14                              14:14 /* RWIVF */
+#define NV_PFIFO_MODE_CHANNEL_14_PIO                     0x00000000 /* RWI-V */
+#define NV_PFIFO_MODE_CHANNEL_14_DMA                     0x00000001 /* RW--V */
+#define NV_PFIFO_MODE_CHANNEL_15                              15:15 /* RWIVF */
+#define NV_PFIFO_MODE_CHANNEL_15_PIO                     0x00000000 /* RWI-V */
+#define NV_PFIFO_MODE_CHANNEL_15_DMA                     0x00000001 /* RW--V */
+#define NV_PFIFO_DMA                                     0x00002508 /* RW-4R */
+#define NV_PFIFO_DMA_CHANNEL_0                                  0:0 /* RWIVF */
+#define NV_PFIFO_DMA_CHANNEL_0_NOT_PENDING               0x00000000 /* RWI-V */
+#define NV_PFIFO_DMA_CHANNEL_0_PENDING                   0x00000001 /* RW--V */
+#define NV_PFIFO_DMA_CHANNEL_1                                  1:1 /* RWIVF */
+#define NV_PFIFO_DMA_CHANNEL_1_NOT_PENDING               0x00000000 /* RWI-V */
+#define NV_PFIFO_DMA_CHANNEL_1_PENDING                   0x00000001 /* RW--V */
+#define NV_PFIFO_DMA_CHANNEL_2                                  2:2 /* RWIVF */
+#define NV_PFIFO_DMA_CHANNEL_2_NOT_PENDING               0x00000000 /* RWI-V */
+#define NV_PFIFO_DMA_CHANNEL_2_PENDING                   0x00000001 /* RW--V */
+#define NV_PFIFO_DMA_CHANNEL_3                                  3:3 /* RWIVF */
+#define NV_PFIFO_DMA_CHANNEL_3_NOT_PENDING               0x00000000 /* RWI-V */
+#define NV_PFIFO_DMA_CHANNEL_3_PENDING                   0x00000001 /* RW--V */
+#define NV_PFIFO_DMA_CHANNEL_4                                  4:4 /* RWIVF */
+#define NV_PFIFO_DMA_CHANNEL_4_NOT_PENDING               0x00000000 /* RWI-V */
+#define NV_PFIFO_DMA_CHANNEL_4_PENDING                   0x00000001 /* RW--V */
+#define NV_PFIFO_DMA_CHANNEL_5                                  5:5 /* RWIVF */
+#define NV_PFIFO_DMA_CHANNEL_5_NOT_PENDING               0x00000000 /* RWI-V */
+#define NV_PFIFO_DMA_CHANNEL_5_PENDING                   0x00000001 /* RW--V */
+#define NV_PFIFO_DMA_CHANNEL_6                                  6:6 /* RWIVF */
+#define NV_PFIFO_DMA_CHANNEL_6_NOT_PENDING               0x00000000 /* RWI-V */
+#define NV_PFIFO_DMA_CHANNEL_6_PENDING                   0x00000001 /* RW--V */
+#define NV_PFIFO_DMA_CHANNEL_7                                  7:7 /* RWIVF */
+#define NV_PFIFO_DMA_CHANNEL_7_NOT_PENDING               0x00000000 /* RWI-V */
+#define NV_PFIFO_DMA_CHANNEL_7_PENDING                   0x00000001 /* RW--V */
+#define NV_PFIFO_DMA_CHANNEL_8                                  8:8 /* RWIVF */
+#define NV_PFIFO_DMA_CHANNEL_8_NOT_PENDING               0x00000000 /* RWI-V */
+#define NV_PFIFO_DMA_CHANNEL_8_PENDING                   0x00000001 /* RW--V */
+#define NV_PFIFO_DMA_CHANNEL_9                                  9:9 /* RWIVF */
+#define NV_PFIFO_DMA_CHANNEL_9_NOT_PENDING               0x00000000 /* RWI-V */
+#define NV_PFIFO_DMA_CHANNEL_9_PENDING                   0x00000001 /* RW--V */
+#define NV_PFIFO_DMA_CHANNEL_10                               10:10 /* RWIVF */
+#define NV_PFIFO_DMA_CHANNEL_10_NOT_PENDING              0x00000000 /* RWI-V */
+#define NV_PFIFO_DMA_CHANNEL_10_PENDING                  0x00000001 /* RW--V */
+#define NV_PFIFO_DMA_CHANNEL_11                               11:11 /* RWIVF */
+#define NV_PFIFO_DMA_CHANNEL_11_NOT_PENDING              0x00000000 /* RWI-V */
+#define NV_PFIFO_DMA_CHANNEL_11_PENDING                  0x00000001 /* RW--V */
+#define NV_PFIFO_DMA_CHANNEL_12                               12:12 /* RWIVF */
+#define NV_PFIFO_DMA_CHANNEL_12_NOT_PENDING              0x00000000 /* RWI-V */
+#define NV_PFIFO_DMA_CHANNEL_12_PENDING                  0x00000001 /* RW--V */
+#define NV_PFIFO_DMA_CHANNEL_13                               13:13 /* RWIVF */
+#define NV_PFIFO_DMA_CHANNEL_13_NOT_PENDING              0x00000000 /* RWI-V */
+#define NV_PFIFO_DMA_CHANNEL_13_PENDING                  0x00000001 /* RW--V */
+#define NV_PFIFO_DMA_CHANNEL_14                               14:14 /* RWIVF */
+#define NV_PFIFO_DMA_CHANNEL_14_NOT_PENDING              0x00000000 /* RWI-V */
+#define NV_PFIFO_DMA_CHANNEL_14_PENDING                  0x00000001 /* RW--V */
+#define NV_PFIFO_DMA_CHANNEL_15                               15:15 /* RWIVF */
+#define NV_PFIFO_DMA_CHANNEL_15_NOT_PENDING              0x00000000 /* RWI-V */
+#define NV_PFIFO_DMA_CHANNEL_15_PENDING                  0x00000001 /* RW--V */
+#define NV_PFIFO_SIZE                                    0x0000250C /* RW-4R */
+#define NV_PFIFO_SIZE_CHANNEL_0                                 0:0 /* RWIVF */
+#define NV_PFIFO_SIZE_CHANNEL_0_124_BYTES                0x00000000 /* RWI-V */
+#define NV_PFIFO_SIZE_CHANNEL_0_512_BYTES                0x00000001 /* RW--V */
+#define NV_PFIFO_SIZE_CHANNEL_1                                 1:1 /* RWIVF */
+#define NV_PFIFO_SIZE_CHANNEL_1_124_BYTES                0x00000000 /* RWI-V */
+#define NV_PFIFO_SIZE_CHANNEL_1_512_BYTES                0x00000001 /* RW--V */
+#define NV_PFIFO_SIZE_CHANNEL_2                                 2:2 /* RWIVF */
+#define NV_PFIFO_SIZE_CHANNEL_2_124_BYTES                0x00000000 /* RWI-V */
+#define NV_PFIFO_SIZE_CHANNEL_2_512_BYTES                0x00000001 /* RW--V */
+#define NV_PFIFO_SIZE_CHANNEL_3                                 3:3 /* RWIVF */
+#define NV_PFIFO_SIZE_CHANNEL_3_124_BYTES                0x00000000 /* RWI-V */
+#define NV_PFIFO_SIZE_CHANNEL_3_512_BYTES                0x00000001 /* RW--V */
+#define NV_PFIFO_SIZE_CHANNEL_4                                 4:4 /* RWIVF */
+#define NV_PFIFO_SIZE_CHANNEL_4_124_BYTES                0x00000000 /* RWI-V */
+#define NV_PFIFO_SIZE_CHANNEL_4_512_BYTES                0x00000001 /* RW--V */
+#define NV_PFIFO_SIZE_CHANNEL_5                                 5:5 /* RWIVF */
+#define NV_PFIFO_SIZE_CHANNEL_5_124_BYTES                0x00000000 /* RWI-V */
+#define NV_PFIFO_SIZE_CHANNEL_5_512_BYTES                0x00000001 /* RW--V */
+#define NV_PFIFO_SIZE_CHANNEL_6                                 6:6 /* RWIVF */
+#define NV_PFIFO_SIZE_CHANNEL_6_124_BYTES                0x00000000 /* RWI-V */
+#define NV_PFIFO_SIZE_CHANNEL_6_512_BYTES                0x00000001 /* RW--V */
+#define NV_PFIFO_SIZE_CHANNEL_7                                 7:7 /* RWIVF */
+#define NV_PFIFO_SIZE_CHANNEL_7_124_BYTES                0x00000000 /* RWI-V */
+#define NV_PFIFO_SIZE_CHANNEL_7_512_BYTES                0x00000001 /* RW--V */
+#define NV_PFIFO_SIZE_CHANNEL_8                                 8:8 /* RWIVF */
+#define NV_PFIFO_SIZE_CHANNEL_8_124_BYTES                0x00000000 /* RWI-V */
+#define NV_PFIFO_SIZE_CHANNEL_8_512_BYTES                0x00000001 /* RW--V */
+#define NV_PFIFO_SIZE_CHANNEL_9                                 9:9 /* RWIVF */
+#define NV_PFIFO_SIZE_CHANNEL_9_124_BYTES                0x00000000 /* RWI-V */
+#define NV_PFIFO_SIZE_CHANNEL_9_512_BYTES                0x00000001 /* RW--V */
+#define NV_PFIFO_SIZE_CHANNEL_10                              10:10 /* RWIVF */
+#define NV_PFIFO_SIZE_CHANNEL_10_124_BYTES               0x00000000 /* RWI-V */
+#define NV_PFIFO_SIZE_CHANNEL_10_512_BYTES               0x00000001 /* RW--V */
+#define NV_PFIFO_SIZE_CHANNEL_11                              11:11 /* RWIVF */
+#define NV_PFIFO_SIZE_CHANNEL_11_124_BYTES               0x00000000 /* RWI-V */
+#define NV_PFIFO_SIZE_CHANNEL_11_512_BYTES               0x00000001 /* RW--V */
+#define NV_PFIFO_SIZE_CHANNEL_12                              12:12 /* RWIVF */
+#define NV_PFIFO_SIZE_CHANNEL_12_124_BYTES               0x00000000 /* RWI-V */
+#define NV_PFIFO_SIZE_CHANNEL_12_512_BYTES               0x00000001 /* RW--V */
+#define NV_PFIFO_SIZE_CHANNEL_13                              13:13 /* RWIVF */
+#define NV_PFIFO_SIZE_CHANNEL_13_124_BYTES               0x00000000 /* RWI-V */
+#define NV_PFIFO_SIZE_CHANNEL_13_512_BYTES               0x00000001 /* RW--V */
+#define NV_PFIFO_SIZE_CHANNEL_14                              14:14 /* RWIVF */
+#define NV_PFIFO_SIZE_CHANNEL_14_124_BYTES               0x00000000 /* RWI-V */
+#define NV_PFIFO_SIZE_CHANNEL_14_512_BYTES               0x00000001 /* RW--V */
+#define NV_PFIFO_SIZE_CHANNEL_15                              15:15 /* RWIVF */
+#define NV_PFIFO_SIZE_CHANNEL_15_124_BYTES               0x00000000 /* RWI-V */
+#define NV_PFIFO_SIZE_CHANNEL_15_512_BYTES               0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE0_PUSH0                            0x00003000 /* RW-4R */
+#define NV_PFIFO_CACHE0_PUSH0_ACCESS                            0:0 /* RWIVF */
+#define NV_PFIFO_CACHE0_PUSH0_ACCESS_DISABLED            0x00000000 /* RWI-V */
+#define NV_PFIFO_CACHE0_PUSH0_ACCESS_ENABLED             0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE1_PUSH0                            0x00003200 /* RW-4R */
+#define NV_PFIFO_CACHE1_PUSH0_ACCESS                            0:0 /* RWIVF */
+#define NV_PFIFO_CACHE1_PUSH0_ACCESS_DISABLED            0x00000000 /* RWI-V */
+#define NV_PFIFO_CACHE1_PUSH0_ACCESS_ENABLED             0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE0_PUSH1                            0x00003004 /* RW-4R */
+#define NV_PFIFO_CACHE0_PUSH1_CHID                              3:0 /* RWXUF */
+#define NV_PFIFO_CACHE1_PUSH1                            0x00003204 /* RW-4R */
+#define NV_PFIFO_CACHE1_PUSH1_CHID                              3:0 /* RWXUF */
+#define NV_PFIFO_CACHE1_PUSH1_MODE                              8:8 /* RWIVF */
+#define NV_PFIFO_CACHE1_PUSH1_MODE_PIO                   0x00000000 /* RWI-V */
+#define NV_PFIFO_CACHE1_PUSH1_MODE_DMA                   0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_PUSH                         0x00003220 /* RW-4R */
+#define NV_PFIFO_CACHE1_DMA_PUSH_ACCESS                         0:0 /* RWIVF */
+#define NV_PFIFO_CACHE1_DMA_PUSH_ACCESS_DISABLED         0x00000000 /* RWI-V */
+#define NV_PFIFO_CACHE1_DMA_PUSH_ACCESS_ENABLED          0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_PUSH_STATE                          4:4 /* R--VF */
+#define NV_PFIFO_CACHE1_DMA_PUSH_STATE_IDLE              0x00000000 /* R---V */
+#define NV_PFIFO_CACHE1_DMA_PUSH_STATE_BUSY              0x00000001 /* R---V */
+#define NV_PFIFO_CACHE1_DMA_PUSH_BUFFER                         8:8 /* R--VF */
+#define NV_PFIFO_CACHE1_DMA_PUSH_BUFFER_NOT_EMPTY        0x00000000 /* R---V */
+#define NV_PFIFO_CACHE1_DMA_PUSH_BUFFER_EMPTY            0x00000001 /* R---V */
+#define NV_PFIFO_CACHE1_DMA_PUSH_STATUS                       12:12 /* RWIVF */
+#define NV_PFIFO_CACHE1_DMA_PUSH_STATUS_RUNNING          0x00000000 /* RWI-V */
+#define NV_PFIFO_CACHE1_DMA_PUSH_STATUS_SUSPENDED        0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH                        0x00003224 /* RW-4R */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG                          7:3 /* RWIUF */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_8_BYTES           0x00000000 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_16_BYTES          0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_24_BYTES          0x00000002 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_32_BYTES          0x00000003 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_40_BYTES          0x00000004 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_48_BYTES          0x00000005 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_56_BYTES          0x00000006 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_64_BYTES          0x00000007 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_72_BYTES          0x00000008 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_80_BYTES          0x00000009 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_88_BYTES          0x0000000A /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_96_BYTES          0x0000000B /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_104_BYTES         0x0000000C /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES         0x0000000D /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_120_BYTES         0x0000000E /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES         0x0000000F /* RWI-V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_136_BYTES         0x00000010 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_144_BYTES         0x00000011 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_152_BYTES         0x00000012 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_160_BYTES         0x00000013 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_168_BYTES         0x00000014 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_176_BYTES         0x00000015 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_184_BYTES         0x00000016 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_192_BYTES         0x00000017 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_200_BYTES         0x00000018 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_208_BYTES         0x00000019 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_216_BYTES         0x0000001A /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_224_BYTES         0x0000001B /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_232_BYTES         0x0000001C /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_240_BYTES         0x0000001D /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_248_BYTES         0x0000001E /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_256_BYTES         0x0000001F /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE                        15:13 /* RWIUF */
+#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_32_BYTES          0x00000000 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_64_BYTES          0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_96_BYTES          0x00000002 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES         0x00000003 /* RWI-V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_160_BYTES         0x00000004 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_192_BYTES         0x00000005 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_224_BYTES         0x00000006 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_256_BYTES         0x00000007 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS                    19:16 /* RWIUF */
+#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_0             0x00000000 /* RWI-V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_1             0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_2             0x00000002 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_3             0x00000003 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_4             0x00000004 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_5             0x00000005 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_6             0x00000006 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_7             0x00000007 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8             0x00000008 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_9             0x00000009 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_10            0x0000000A /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_11            0x0000000B /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_12            0x0000000C /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_13            0x0000000D /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_14            0x0000000E /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_15            0x0000000F /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_PUT                          0x00003240 /* RW-4R */
+#define NV_PFIFO_CACHE1_DMA_PUT_OFFSET                         28:2 /* RWXUF */
+#define NV_PFIFO_CACHE1_DMA_GET                          0x00003244 /* RW-4R */
+#define NV_PFIFO_CACHE1_DMA_GET_OFFSET                         28:2 /* RWXUF */
+#define NV_PFIFO_CACHE1_DMA_STATE                        0x00003228 /* RW-4R */
+#define NV_PFIFO_CACHE1_DMA_STATE_METHOD                       12:2 /* RWXUF */
+#define NV_PFIFO_CACHE1_DMA_STATE_SUBCHANNEL                  15:13 /* RWXUF */
+#define NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT                28:18 /* RWIUF */
+#define NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT_0         0x00000000 /* RWI-V */
+#define NV_PFIFO_CACHE1_DMA_STATE_ERROR                       31:30 /* RWXUF */
+#define NV_PFIFO_CACHE1_DMA_STATE_ERROR_NONE             0x00000000 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_STATE_ERROR_NON_CACHE        0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_STATE_ERROR_RESERVED_CMD     0x00000002 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_STATE_ERROR_PROTECTION       0x00000003 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_INSTANCE                     0x0000322C /* RW-4R */
+#define NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS                   15:0 /* RWXUF */
+#define NV_PFIFO_CACHE1_DMA_CTL                          0x00003230 /* RW-4R */
+#define NV_PFIFO_CACHE1_DMA_CTL_ADJUST                         11:2 /* RWXUF */
+#define NV_PFIFO_CACHE1_DMA_CTL_PAGE_TABLE                    12:12 /* RWXUF */
+#define NV_PFIFO_CACHE1_DMA_CTL_PAGE_TABLE_NOT_PRESENT   0x00000000 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_CTL_PAGE_TABLE_PRESENT       0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_CTL_PAGE_ENTRY                    13:13 /* RWXUF */
+#define NV_PFIFO_CACHE1_DMA_CTL_PAGE_ENTRY_NOT_LINEAR    0x00000000 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_CTL_PAGE_ENTRY_LINEAR        0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_CTL_TARGET_NODE                   17:16 /* RWXUF */
+#define NV_PFIFO_CACHE1_DMA_CTL_TARGET_NODE_PCI          0x00000002 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_CTL_TARGET_NODE_AGP          0x00000003 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_CTL_AT_INFO                       31:31 /* RWIUF */
+#define NV_PFIFO_CACHE1_DMA_CTL_AT_INFO_INVALID          0x00000000 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_CTL_AT_INFO_VALID            0x00000001 /* RWI-V */
+#define NV_PFIFO_CACHE1_DMA_LIMIT                        0x00003234 /* RW-4R */
+#define NV_PFIFO_CACHE1_DMA_LIMIT_OFFSET                       28:2 /* RWXUF */
+#define NV_PFIFO_CACHE1_DMA_TLB_TAG                      0x00003238 /* RW-4R */
+#define NV_PFIFO_CACHE1_DMA_TLB_TAG_ADDRESS                   28:12 /* RWXUF */
+#define NV_PFIFO_CACHE1_DMA_TLB_TAG_STATE                       0:0 /* RWIUF */
+#define NV_PFIFO_CACHE1_DMA_TLB_TAG_STATE_INVALID        0x00000000 /* RWI-V */
+#define NV_PFIFO_CACHE1_DMA_TLB_TAG_STATE_VALID          0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE1_DMA_TLB_PTE                      0x0000323C /* RW-4R */
+#define NV_PFIFO_CACHE1_DMA_TLB_PTE_FRAME_ADDRESS             31:12 /* RWXUF */
+#define NV_PFIFO_CACHE0_PULL0                            0x00003050 /* RW-4R */
+#define NV_PFIFO_CACHE0_PULL0_ACCESS                            0:0 /* RWIVF */
+#define NV_PFIFO_CACHE0_PULL0_ACCESS_DISABLED            0x00000000 /* RWI-V */
+#define NV_PFIFO_CACHE0_PULL0_ACCESS_ENABLED             0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE0_PULL0_HASH                              4:4 /* R-XVF */
+#define NV_PFIFO_CACHE0_PULL0_HASH_SUCCEEDED             0x00000000 /* R---V */
+#define NV_PFIFO_CACHE0_PULL0_HASH_FAILED                0x00000001 /* R---V */
+#define NV_PFIFO_CACHE0_PULL0_DEVICE                            8:8 /* R-XVF */
+#define NV_PFIFO_CACHE0_PULL0_DEVICE_HARDWARE            0x00000000 /* R---V */
+#define NV_PFIFO_CACHE0_PULL0_DEVICE_SOFTWARE            0x00000001 /* R---V */
+#define NV_PFIFO_CACHE0_PULL0_HASH_STATE                      12:12 /* R-XVF */
+#define NV_PFIFO_CACHE0_PULL0_HASH_STATE_IDLE            0x00000000 /* R---V */
+#define NV_PFIFO_CACHE0_PULL0_HASH_STATE_BUSY            0x00000001 /* R---V */
+#define NV_PFIFO_CACHE1_PULL0                            0x00003250 /* RW-4R */
+#define NV_PFIFO_CACHE1_PULL0_ACCESS                            0:0 /* RWIVF */
+#define NV_PFIFO_CACHE1_PULL0_ACCESS_DISABLED            0x00000000 /* RWI-V */
+#define NV_PFIFO_CACHE1_PULL0_ACCESS_ENABLED             0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE1_PULL0_HASH                              4:4 /* R-XVF */
+#define NV_PFIFO_CACHE1_PULL0_HASH_SUCCEEDED             0x00000000 /* R---V */
+#define NV_PFIFO_CACHE1_PULL0_HASH_FAILED                0x00000001 /* R---V */
+#define NV_PFIFO_CACHE1_PULL0_DEVICE                            8:8 /* R-XVF */
+#define NV_PFIFO_CACHE1_PULL0_DEVICE_HARDWARE            0x00000000 /* R---V */
+#define NV_PFIFO_CACHE1_PULL0_DEVICE_SOFTWARE            0x00000001 /* R---V */
+#define NV_PFIFO_CACHE1_PULL0_HASH_STATE                      12:12 /* R-XVF */
+#define NV_PFIFO_CACHE1_PULL0_HASH_STATE_IDLE            0x00000000 /* R---V */
+#define NV_PFIFO_CACHE1_PULL0_HASH_STATE_BUSY            0x00000001 /* R---V */
+#define NV_PFIFO_CACHE0_PULL1                            0x00003054 /* RW-4R */
+#define NV_PFIFO_CACHE0_PULL1_ENGINE                            1:0 /* RWXUF */
+#define NV_PFIFO_CACHE0_PULL1_ENGINE_SW                  0x00000000 /* RW--V */
+#define NV_PFIFO_CACHE0_PULL1_ENGINE_GRAPHICS            0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE0_PULL1_ENGINE_DVD                 0x00000002 /* RW--V */
+#define NV_PFIFO_CACHE1_PULL1                            0x00003254 /* RW-4R */
+#define NV_PFIFO_CACHE1_PULL1_ENGINE                            1:0 /* RWXUF */
+#define NV_PFIFO_CACHE1_PULL1_ENGINE_SW                  0x00000000 /* RW--V */
+#define NV_PFIFO_CACHE1_PULL1_ENGINE_GRAPHICS            0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE1_PULL1_ENGINE_DVD                 0x00000002 /* RW--V */
+#define NV_PFIFO_CACHE0_HASH                             0x00003058 /* RW-4R */
+#define NV_PFIFO_CACHE0_HASH_INSTANCE                          15:0 /* RWXUF */
+#define NV_PFIFO_CACHE0_HASH_VALID                            16:16 /* RWXVF */
+#define NV_PFIFO_CACHE1_HASH                             0x00003258 /* RW-4R */
+#define NV_PFIFO_CACHE1_HASH_INSTANCE                          15:0 /* RWXUF */
+#define NV_PFIFO_CACHE1_HASH_VALID                            16:16 /* RWXVF */
+#define NV_PFIFO_CACHE0_STATUS                           0x00003014 /* R--4R */
+#define NV_PFIFO_CACHE0_STATUS_LOW_MARK                         4:4 /* R--VF */
+#define NV_PFIFO_CACHE0_STATUS_LOW_MARK_NOT_EMPTY        0x00000000 /* R---V */
+#define NV_PFIFO_CACHE0_STATUS_LOW_MARK_EMPTY            0x00000001 /* R---V */
+#define NV_PFIFO_CACHE0_STATUS_HIGH_MARK                        8:8 /* R--VF */
+#define NV_PFIFO_CACHE0_STATUS_HIGH_MARK_NOT_FULL        0x00000000 /* R---V */
+#define NV_PFIFO_CACHE0_STATUS_HIGH_MARK_FULL            0x00000001 /* R---V */
+#define NV_PFIFO_CACHE1_STATUS                           0x00003214 /* R--4R */
+#define NV_PFIFO_CACHE1_STATUS_LOW_MARK                         4:4 /* R--VF */
+#define NV_PFIFO_CACHE1_STATUS_LOW_MARK_NOT_EMPTY        0x00000000 /* R---V */
+#define NV_PFIFO_CACHE1_STATUS_LOW_MARK_EMPTY            0x00000001 /* R---V */
+#define NV_PFIFO_CACHE1_STATUS_HIGH_MARK                        8:8 /* R--VF */
+#define NV_PFIFO_CACHE1_STATUS_HIGH_MARK_NOT_FULL        0x00000000 /* R---V */
+#define NV_PFIFO_CACHE1_STATUS_HIGH_MARK_FULL            0x00000001 /* R---V */
+#define NV_PFIFO_CACHE1_STATUS1                          0x00003218 /* R--4R */
+#define NV_PFIFO_CACHE1_STATUS1_RANOUT                          0:0 /* R-XVF */
+#define NV_PFIFO_CACHE1_STATUS1_RANOUT_FALSE             0x00000000 /* R---V */
+#define NV_PFIFO_CACHE1_STATUS1_RANOUT_TRUE              0x00000001 /* R---V */
+#define NV_PFIFO_CACHE0_PUT                              0x00003010 /* RW-4R */
+#define NV_PFIFO_CACHE0_PUT_ADDRESS                             2:2 /* RWXUF */
+#define NV_PFIFO_CACHE1_PUT                              0x00003210 /* RW-4R */
+#define NV_PFIFO_CACHE1_PUT_ADDRESS                             9:2 /* RWXUF */
+#define NV_PFIFO_CACHE0_GET                              0x00003070 /* RW-4R */
+#define NV_PFIFO_CACHE0_GET_ADDRESS                             2:2 /* RWXUF */
+#define NV_PFIFO_CACHE1_GET                              0x00003270 /* RW-4R */
+#define NV_PFIFO_CACHE1_GET_ADDRESS                             9:2 /* RWXUF */
+#define NV_PFIFO_CACHE0_ENGINE                           0x00003080 /* RW-4R */
+#define NV_PFIFO_CACHE0_ENGINE_0                                1:0 /* RWXUF */
+#define NV_PFIFO_CACHE0_ENGINE_0_SW                      0x00000000 /* RW--V */
+#define NV_PFIFO_CACHE0_ENGINE_0_GRAPHICS                0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE0_ENGINE_0_DVD                     0x00000002 /* RW--V */
+#define NV_PFIFO_CACHE0_ENGINE_1                                5:4 /* RWXUF */
+#define NV_PFIFO_CACHE0_ENGINE_1_SW                      0x00000000 /* RW--V */
+#define NV_PFIFO_CACHE0_ENGINE_1_GRAPHICS                0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE0_ENGINE_1_DVD                     0x00000002 /* RW--V */
+#define NV_PFIFO_CACHE0_ENGINE_2                                9:8 /* RWXUF */
+#define NV_PFIFO_CACHE0_ENGINE_2_SW                      0x00000000 /* RW--V */
+#define NV_PFIFO_CACHE0_ENGINE_2_GRAPHICS                0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE0_ENGINE_2_DVD                     0x00000002 /* RW--V */
+#define NV_PFIFO_CACHE0_ENGINE_3                              13:12 /* RWXUF */
+#define NV_PFIFO_CACHE0_ENGINE_3_SW                      0x00000000 /* RW--V */
+#define NV_PFIFO_CACHE0_ENGINE_3_GRAPHICS                0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE0_ENGINE_3_DVD                     0x00000002 /* RW--V */
+#define NV_PFIFO_CACHE0_ENGINE_4                              17:16 /* RWXUF */
+#define NV_PFIFO_CACHE0_ENGINE_4_SW                      0x00000000 /* RW--V */
+#define NV_PFIFO_CACHE0_ENGINE_4_GRAPHICS                0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE0_ENGINE_4_DVD                     0x00000002 /* RW--V */
+#define NV_PFIFO_CACHE0_ENGINE_5                              21:20 /* RWXUF */
+#define NV_PFIFO_CACHE0_ENGINE_5_SW                      0x00000000 /* RW--V */
+#define NV_PFIFO_CACHE0_ENGINE_5_GRAPHICS                0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE0_ENGINE_5_DVD                     0x00000002 /* RW--V */
+#define NV_PFIFO_CACHE0_ENGINE_6                              25:24 /* RWXUF */
+#define NV_PFIFO_CACHE0_ENGINE_6_SW                      0x00000000 /* RW--V */
+#define NV_PFIFO_CACHE0_ENGINE_6_GRAPHICS                0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE0_ENGINE_6_DVD                     0x00000002 /* RW--V */
+#define NV_PFIFO_CACHE0_ENGINE_7                              29:28 /* RWXUF */
+#define NV_PFIFO_CACHE0_ENGINE_7_SW                      0x00000000 /* RW--V */
+#define NV_PFIFO_CACHE0_ENGINE_7_GRAPHICS                0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE0_ENGINE_7_DVD                     0x00000002 /* RW--V */
+#define NV_PFIFO_CACHE1_ENGINE                           0x00003280 /* RW-4R */
+#define NV_PFIFO_CACHE1_ENGINE_0                                1:0 /* RWXUF */
+#define NV_PFIFO_CACHE1_ENGINE_0_SW                      0x00000000 /* RW--V */
+#define NV_PFIFO_CACHE1_ENGINE_0_GRAPHICS                0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE1_ENGINE_0_DVD                     0x00000002 /* RW--V */
+#define NV_PFIFO_CACHE1_ENGINE_1                                5:4 /* RWXUF */
+#define NV_PFIFO_CACHE1_ENGINE_1_SW                      0x00000000 /* RW--V */
+#define NV_PFIFO_CACHE1_ENGINE_1_GRAPHICS                0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE1_ENGINE_1_DVD                     0x00000002 /* RW--V */
+#define NV_PFIFO_CACHE1_ENGINE_2                                9:8 /* RWXUF */
+#define NV_PFIFO_CACHE1_ENGINE_2_SW                      0x00000000 /* RW--V */
+#define NV_PFIFO_CACHE1_ENGINE_2_GRAPHICS                0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE1_ENGINE_2_DVD                     0x00000002 /* RW--V */
+#define NV_PFIFO_CACHE1_ENGINE_3                              13:12 /* RWXUF */
+#define NV_PFIFO_CACHE1_ENGINE_3_SW                      0x00000000 /* RW--V */
+#define NV_PFIFO_CACHE1_ENGINE_3_GRAPHICS                0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE1_ENGINE_3_DVD                     0x00000002 /* RW--V */
+#define NV_PFIFO_CACHE1_ENGINE_4                              17:16 /* RWXUF */
+#define NV_PFIFO_CACHE1_ENGINE_4_SW                      0x00000000 /* RW--V */
+#define NV_PFIFO_CACHE1_ENGINE_4_GRAPHICS                0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE1_ENGINE_4_DVD                     0x00000002 /* RW--V */
+#define NV_PFIFO_CACHE1_ENGINE_5                              21:20 /* RWXUF */
+#define NV_PFIFO_CACHE1_ENGINE_5_SW                      0x00000000 /* RW--V */
+#define NV_PFIFO_CACHE1_ENGINE_5_GRAPHICS                0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE1_ENGINE_5_DVD                     0x00000002 /* RW--V */
+#define NV_PFIFO_CACHE1_ENGINE_6                              25:24 /* RWXUF */
+#define NV_PFIFO_CACHE1_ENGINE_6_SW                      0x00000000 /* RW--V */
+#define NV_PFIFO_CACHE1_ENGINE_6_GRAPHICS                0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE1_ENGINE_6_DVD                     0x00000002 /* RW--V */
+#define NV_PFIFO_CACHE1_ENGINE_7                              29:28 /* RWXUF */
+#define NV_PFIFO_CACHE1_ENGINE_7_SW                      0x00000000 /* RW--V */
+#define NV_PFIFO_CACHE1_ENGINE_7_GRAPHICS                0x00000001 /* RW--V */
+#define NV_PFIFO_CACHE1_ENGINE_7_DVD                     0x00000002 /* RW--V */
+#define NV_PFIFO_CACHE0_METHOD(i)                (0x00003100+(i)*8) /* RW-4A */
+#define NV_PFIFO_CACHE0_METHOD__SIZE_1                            1 /*       */
+#define NV_PFIFO_CACHE0_METHOD_ADDRESS                         12:2 /* RWXUF */
+#define NV_PFIFO_CACHE0_METHOD_SUBCHANNEL                     15:13 /* RWXUF */
+#define NV_PFIFO_CACHE1_METHOD(i)                (0x00003800+(i)*8) /* RW-4A */
+#define NV_PFIFO_CACHE1_METHOD__SIZE_1                          128 /*       */
+#define NV_PFIFO_CACHE1_METHOD_ADDRESS                         12:2 /* RWXUF */
+#define NV_PFIFO_CACHE1_METHOD_SUBCHANNEL                     15:13 /* RWXUF */
+#define NV_PFIFO_CACHE1_METHOD_ALIAS(i)          (0x00003C00+(i)*8) /* RW-4A */
+#define NV_PFIFO_CACHE1_METHOD_ALIAS__SIZE_1                    128 /*       */
+#define NV_PFIFO_CACHE0_DATA(i)                  (0x00003104+(i)*8) /* RW-4A */
+#define NV_PFIFO_CACHE0_DATA__SIZE_1                              1 /*       */
+#define NV_PFIFO_CACHE0_DATA_VALUE                             31:0 /* RWXVF */
+#define NV_PFIFO_CACHE1_DATA(i)                  (0x00003804+(i)*8) /* RW-4A */
+#define NV_PFIFO_CACHE1_DATA__SIZE_1                            128 /*       */
+#define NV_PFIFO_CACHE1_DATA_VALUE                             31:0 /* RWXVF */
+#define NV_PFIFO_CACHE1_DATA_ALIAS(i)            (0x00003C04+(i)*8) /* RW-4A */
+#define NV_PFIFO_CACHE1_DATA_ALIAS__SIZE_1                      128 /*       */
+#define NV_PFIFO_DEVICE(i)                       (0x00002800+(i)*4) /* R--4A */
+#define NV_PFIFO_DEVICE__SIZE_1                                 128 /*       */
+#define NV_PFIFO_DEVICE_CHID                                    3:0 /* R--UF */
+#define NV_PFIFO_DEVICE_SWITCH                                24:24 /* R--VF */
+#define NV_PFIFO_DEVICE_SWITCH_UNAVAILABLE               0x00000000 /* R---V */
+#define NV_PFIFO_DEVICE_SWITCH_AVAILABLE                 0x00000001 /* R---V */
+#define NV_PFIFO_RUNOUT_STATUS                           0x00002400 /* R--4R */
+#define NV_PFIFO_RUNOUT_STATUS_RANOUT                           0:0 /* R--VF */
+#define NV_PFIFO_RUNOUT_STATUS_RANOUT_FALSE              0x00000000 /* R---V */
+#define NV_PFIFO_RUNOUT_STATUS_RANOUT_TRUE               0x00000001 /* R---V */
+#define NV_PFIFO_RUNOUT_STATUS_LOW_MARK                         4:4 /* R--VF */
+#define NV_PFIFO_RUNOUT_STATUS_LOW_MARK_NOT_EMPTY        0x00000000 /* R---V */
+#define NV_PFIFO_RUNOUT_STATUS_LOW_MARK_EMPTY            0x00000001 /* R---V */
+#define NV_PFIFO_RUNOUT_STATUS_HIGH_MARK                        8:8 /* R--VF */
+#define NV_PFIFO_RUNOUT_STATUS_HIGH_MARK_NOT_FULL        0x00000000 /* R---V */
+#define NV_PFIFO_RUNOUT_STATUS_HIGH_MARK_FULL            0x00000001 /* R---V */
+#define NV_PFIFO_RUNOUT_PUT                              0x00002410 /* RW-4R */
+#define NV_PFIFO_RUNOUT_PUT_ADDRESS                            12:3 /* RWXUF */
+#define NV_PFIFO_RUNOUT_PUT_ADDRESS__SIZE_0                     8:3 /* RWXUF */
+#define NV_PFIFO_RUNOUT_PUT_ADDRESS__SIZE_1                    12:3 /* RWXUF */
+#define NV_PFIFO_RUNOUT_GET                              0x00002420 /* RW-4R */
+#define NV_PFIFO_RUNOUT_GET_ADDRESS                            13:3 /* RWXUF */
+/* dev_graphics.ref */
+#define NV_PGRAPH                             0x00401FFF:0x00400000 /* RW--D */
+#define NV_PGRAPH_DEBUG_0                                0x00400080 /* RW-4R */
+#define NV_PGRAPH_DEBUG_1                                0x00400084 /* RW-4R */
+#define NV_PGRAPH_DEBUG_2                                0x00400088 /* RW-4R */
+#define NV_PGRAPH_DEBUG_3                                0x0040008C /* RW-4R */
+#define NV_PGRAPH_INTR                                   0x00400100 /* RW-4R */
+#define NV_PGRAPH_INTR_NOTIFY                                   0:0 /* RWIVF */
+#define NV_PGRAPH_INTR_NOTIFY_NOT_PENDING                0x00000000 /* R-I-V */
+#define NV_PGRAPH_INTR_NOTIFY_PENDING                    0x00000001 /* R---V */
+#define NV_PGRAPH_INTR_NOTIFY_RESET                      0x00000001 /* -W--C */
+#define NV_PGRAPH_INTR_MISSING_HW                               4:4 /* RWIVF */
+#define NV_PGRAPH_INTR_MISSING_HW_NOT_PENDING            0x00000000 /* R-I-V */
+#define NV_PGRAPH_INTR_MISSING_HW_PENDING                0x00000001 /* R---V */
+#define NV_PGRAPH_INTR_MISSING_HW_RESET                  0x00000001 /* -W--C */
+#define NV_PGRAPH_INTR_TLB_PRESENT_A                            8:8 /* RWIVF */
+#define NV_PGRAPH_INTR_TLB_PRESENT_A_NOT_PENDING         0x00000000 /* R-I-V */
+#define NV_PGRAPH_INTR_TLB_PRESENT_A_PENDING             0x00000001 /* R---V */
+#define NV_PGRAPH_INTR_TLB_PRESENT_A_RESET               0x00000001 /* -W--C */
+#define NV_PGRAPH_INTR_TLB_PRESENT_B                            9:9 /* RWIVF */
+#define NV_PGRAPH_INTR_TLB_PRESENT_B_NOT_PENDING         0x00000000 /* R-I-V */
+#define NV_PGRAPH_INTR_TLB_PRESENT_B_PENDING             0x00000001 /* R---V */
+#define NV_PGRAPH_INTR_TLB_PRESENT_B_RESET               0x00000001 /* -W--C */
+#define NV_PGRAPH_INTR_CONTEXT_SWITCH                         12:12 /* RWIVF */
+#define NV_PGRAPH_INTR_CONTEXT_SWITCH_NOT_PENDING        0x00000000 /* R-I-V */
+#define NV_PGRAPH_INTR_CONTEXT_SWITCH_PENDING            0x00000001 /* R---V */
+#define NV_PGRAPH_INTR_CONTEXT_SWITCH_RESET              0x00000001 /* -W--C */
+#define NV_PGRAPH_INTR_BUFFER_NOTIFY                          16:16 /* RWIVF */
+#define NV_PGRAPH_INTR_BUFFER_NOTIFY_NOT_PENDING         0x00000000 /* R-I-V */
+#define NV_PGRAPH_INTR_BUFFER_NOTIFY_PENDING             0x00000001 /* R---V */
+#define NV_PGRAPH_INTR_BUFFER_NOTIFY_RESET               0x00000001 /* -W--C */
+#define NV_PGRAPH_NSTATUS                                0x00400104 /* RW-4R */
+#define NV_PGRAPH_NSTATUS_STATE_IN_USE                        11:11 /* RWIVF */
+#define NV_PGRAPH_NSTATUS_STATE_IN_USE_NOT_PENDING       0x00000000 /* RWI-V */
+#define NV_PGRAPH_NSTATUS_STATE_IN_USE_PENDING           0x00000001 /* RW--V */
+#define NV_PGRAPH_NSTATUS_INVALID_STATE                       12:12 /* RWIVF */
+#define NV_PGRAPH_NSTATUS_INVALID_STATE_NOT_PENDING      0x00000000 /* RWI-V */
+#define NV_PGRAPH_NSTATUS_INVALID_STATE_PENDING          0x00000001 /* RW--V */
+#define NV_PGRAPH_NSTATUS_BAD_ARGUMENT                        13:13 /* RWIVF */
+#define NV_PGRAPH_NSTATUS_BAD_ARGUMENT_NOT_PENDING       0x00000000 /* RWI-V */
+#define NV_PGRAPH_NSTATUS_BAD_ARGUMENT_PENDING           0x00000001 /* RW--V */
+#define NV_PGRAPH_NSTATUS_PROTECTION_FAULT                    14:14 /* RWIVF */
+#define NV_PGRAPH_NSTATUS_PROTECTION_FAULT_NOT_PENDING   0x00000000 /* RWI-V */
+#define NV_PGRAPH_NSTATUS_PROTECTION_FAULT_PENDING       0x00000001 /* RW--V */
+#define NV_PGRAPH_NSOURCE                                0x00400108 /* R--4R */
+#define NV_PGRAPH_NSOURCE_NOTIFICATION                          0:0 /* R-IVF */
+#define NV_PGRAPH_NSOURCE_NOTIFICATION_NOT_PENDING       0x00000000 /* R-I-V */
+#define NV_PGRAPH_NSOURCE_NOTIFICATION_PENDING           0x00000001 /* R---V */
+#define NV_PGRAPH_NSOURCE_DATA_ERROR                            1:1 /* R-IVF */
+#define NV_PGRAPH_NSOURCE_DATA_ERROR_NOT_PENDING         0x00000000 /* R-I-V */
+#define NV_PGRAPH_NSOURCE_DATA_ERROR_PENDING             0x00000001 /* R---V */
+#define NV_PGRAPH_NSOURCE_PROTECTION_ERROR                      2:2 /* R-IVF */
+#define NV_PGRAPH_NSOURCE_PROTECTION_ERROR_NOT_PENDING   0x00000000 /* R-I-V */
+#define NV_PGRAPH_NSOURCE_PROTECTION_ERROR_PENDING       0x00000001 /* R---V */
+#define NV_PGRAPH_NSOURCE_RANGE_EXCEPTION                       3:3 /* R-IVF */
+#define NV_PGRAPH_NSOURCE_RANGE_EXCEPTION_NOT_PENDING    0x00000000 /* R-I-V */
+#define NV_PGRAPH_NSOURCE_RANGE_EXCEPTION_PENDING        0x00000001 /* R---V */
+#define NV_PGRAPH_NSOURCE_LIMIT_COLOR                           4:4 /* R-IVF */
+#define NV_PGRAPH_NSOURCE_LIMIT_COLOR_NOT_PENDING        0x00000000 /* R-I-V */
+#define NV_PGRAPH_NSOURCE_LIMIT_COLOR_PENDING            0x00000001 /* R---V */
+#define NV_PGRAPH_NSOURCE_LIMIT_ZETA_                           5:5 /* R-IVF */
+#define NV_PGRAPH_NSOURCE_LIMIT_ZETA_NOT_PENDING         0x00000000 /* R-I-V */
+#define NV_PGRAPH_NSOURCE_LIMIT_ZETA_PENDING             0x00000001 /* R---V */
+#define NV_PGRAPH_NSOURCE_ILLEGAL_MTHD                          6:6 /* R-IVF */
+#define NV_PGRAPH_NSOURCE_ILLEGAL_MTHD_NOT_PENDING       0x00000000 /* R-I-V */
+#define NV_PGRAPH_NSOURCE_ILLEGAL_MTHD_PENDING           0x00000001 /* R---V */
+#define NV_PGRAPH_NSOURCE_DMA_R_PROTECTION                      7:7 /* R-IVF */
+#define NV_PGRAPH_NSOURCE_DMA_R_PROTECTION_NOT_PENDING   0x00000000 /* R-I-V */
+#define NV_PGRAPH_NSOURCE_DMA_R_PROTECTION_PENDING       0x00000001 /* R---V */
+#define NV_PGRAPH_NSOURCE_DMA_W_PROTECTION                      8:8 /* R-IVF */
+#define NV_PGRAPH_NSOURCE_DMA_W_PROTECTION_NOT_PENDING   0x00000000 /* R-I-V */
+#define NV_PGRAPH_NSOURCE_DMA_W_PROTECTION_PENDING       0x00000001 /* R---V */
+#define NV_PGRAPH_NSOURCE_FORMAT_EXCEPTION                      9:9 /* R-IVF */
+#define NV_PGRAPH_NSOURCE_FORMAT_EXCEPTION_NOT_PENDING   0x00000000 /* R-I-V */
+#define NV_PGRAPH_NSOURCE_FORMAT_EXCEPTION_PENDING       0x00000001 /* R---V */
+#define NV_PGRAPH_NSOURCE_PATCH_EXCEPTION                     10:10 /* R-IVF */
+#define NV_PGRAPH_NSOURCE_PATCH_EXCEPTION_NOT_PENDING    0x00000000 /* R-I-V */
+#define NV_PGRAPH_NSOURCE_PATCH_EXCEPTION_PENDING        0x00000001 /* R---V */
+#define NV_PGRAPH_NSOURCE_STATE_INVALID                       11:11 /* R-IVF */
+#define NV_PGRAPH_NSOURCE_STATE_INVALID_NOT_PENDING      0x00000000 /* R-I-V */
+#define NV_PGRAPH_NSOURCE_STATE_INVALID_PENDING          0x00000001 /* R---V */
+#define NV_PGRAPH_NSOURCE_DOUBLE_NOTIFY                       12:12 /* R-IVF */
+#define NV_PGRAPH_NSOURCE_DOUBLE_NOTIFY_NOT_PENDING      0x00000000 /* R-I-V */
+#define NV_PGRAPH_NSOURCE_DOUBLE_NOTIFY_PENDING          0x00000001 /* R---V */
+#define NV_PGRAPH_NSOURCE_NOTIFY_IN_USE                       13:13 /* R-IVF */
+#define NV_PGRAPH_NSOURCE_NOTIFY_IN_USE_NOT_PENDING      0x00000000 /* R-I-V */
+#define NV_PGRAPH_NSOURCE_NOTIFY_IN_USE_PENDING          0x00000001 /* R---V */
+#define NV_PGRAPH_NSOURCE_METHOD_CNT                          14:14 /* R-IVF */
+#define NV_PGRAPH_NSOURCE_METHOD_CNT_NOT_PENDING         0x00000000 /* R-I-V */
+#define NV_PGRAPH_NSOURCE_METHOD_CNT_PENDING             0x00000001 /* R---V */
+#define NV_PGRAPH_NSOURCE_BFR_NOTIFICATION                    15:15 /* R-IVF */
+#define NV_PGRAPH_NSOURCE_BFR_NOTIFICATION_NOT_PENDING   0x00000000 /* R-I-V */
+#define NV_PGRAPH_NSOURCE_BFR_NOTIFICATION_PENDING       0x00000001 /* R---V */
+#define NV_PGRAPH_INTR_EN                                0x00400140 /* RW-4R */
+#define NV_PGRAPH_INTR_EN_NOTIFY                                0:0 /* RWIVF */
+#define NV_PGRAPH_INTR_EN_NOTIFY_DISABLED                0x00000000 /* RWI-V */
+#define NV_PGRAPH_INTR_EN_NOTIFY_ENABLED                 0x00000001 /* RW--V */
+#define NV_PGRAPH_INTR_EN_MISSING_HW                            4:4 /* RWIVF */
+#define NV_PGRAPH_INTR_EN_MISSING_HW_DISABLED            0x00000000 /* RWI-V */
+#define NV_PGRAPH_INTR_EN_MISSING_HW_ENABLED             0x00000001 /* RW--V */
+#define NV_PGRAPH_INTR_EN_TLB_PRESENT_A                         8:8 /* RWIVF */
+#define NV_PGRAPH_INTR_EN_TLB_PRESENT_A_DISABLED         0x00000000 /* RWI-V */
+#define NV_PGRAPH_INTR_EN_TLB_PRESENT_A_ENABLED          0x00000001 /* RW--V */
+#define NV_PGRAPH_INTR_EN_TLB_PRESENT_B                         9:9 /* RWIVF */
+#define NV_PGRAPH_INTR_EN_TLB_PRESENT_B_DISABLED         0x00000000 /* RWI-V */
+#define NV_PGRAPH_INTR_EN_TLB_PRESENT_B_ENABLED          0x00000001 /* RW--V */
+#define NV_PGRAPH_INTR_EN_CONTEXT_SWITCH                      12:12 /* RWIVF */
+#define NV_PGRAPH_INTR_EN_CONTEXT_SWITCH_DISABLED        0x00000000 /* RWI-V */
+#define NV_PGRAPH_INTR_EN_CONTEXT_SWITCH_ENABLED         0x00000001 /* RW--V */
+#define NV_PGRAPH_INTR_EN_BUFFER_NOTIFY                       16:16 /* RWIVF */
+#define NV_PGRAPH_INTR_EN_BUFFER_NOTIFY_DISABLED         0x00000000 /* RWI-V */
+#define NV_PGRAPH_INTR_EN_BUFFER_NOTIFY_ENABLED          0x00000001 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH1                            0x00400160 /* RW-4R */
+#define NV_PGRAPH_CTX_SWITCH1_GRCLASS                           7:0 /* RWXVF */
+#define NV_PGRAPH_CTX_SWITCH1_CHROMA_KEY                      12:12 /* RWXUF */
+#define NV_PGRAPH_CTX_SWITCH1_CHROMA_KEY_DISABLE         0x00000000 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH1_CHROMA_KEY_ENABLE          0x00000001 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH1_USER_CLIP                       13:13 /* RWXUF */
+#define NV_PGRAPH_CTX_SWITCH1_USER_CLIP_DISABLE          0x00000000 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH1_USER_CLIP_ENABLE           0x00000001 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH1_SWIZZLE                         14:14 /* RWXUF */
+#define NV_PGRAPH_CTX_SWITCH1_SWIZZLE_DISABLE            0x00000000 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH1_SWIZZLE_ENABLE             0x00000001 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG                    17:15 /* RWXUF */
+#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_SRCCOPY_AND   0x00000000 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_ROP_AND       0x00000001 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_BLEND_AND     0x00000002 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_SRCCOPY       0x00000003 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_SRCCOPY_PRE   0x00000004 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_BLEND_PRE     0x00000005 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH1_PATCH_STATUS                    24:24 /* RWXUF */
+#define NV_PGRAPH_CTX_SWITCH1_PATCH_STATUS_INVALID       0x00000000 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH1_PATCH_STATUS_VALID         0x00000001 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH1_CONTEXT_SURFACE                 25:25 /* RWXUF */
+#define NV_PGRAPH_CTX_SWITCH1_CONTEXT_SURFACE_INVALID    0x00000000 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH1_CONTEXT_SURFACE_VALID      0x00000001 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH1_VOLATILE_RESET                  31:31 /* CWIVF */
+#define NV_PGRAPH_CTX_SWITCH1_VOLATILE_RESET_IGNORE      0x00000000 /* CWI-V */
+#define NV_PGRAPH_CTX_SWITCH1_VOLATILE_RESET_ENABLED     0x00000001 /* -W--T */
+#define NV_PGRAPH_CTX_SWITCH2                            0x00400164 /* RW-4R */
+#define NV_PGRAPH_CTX_SWITCH2_MONO_FORMAT                       1:0 /* RWXUF */
+#define NV_PGRAPH_CTX_SWITCH2_MONO_FORMAT_INVALID              0x00 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH2_MONO_FORMAT_CGA6_M1              0x01 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH2_MONO_FORMAT_LE_M1                0x02 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT                     13:8 /* RWXUF */
+#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_INVALID             0x00 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_Y8               0x01 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X16A8Y8          0x02 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X24Y8            0x03 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_A1R5G5B5         0x06 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X1R5G5B5         0x07 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X16A1R5G5B5      0x08 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X17R5G5B5        0x09 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_R5G6B5           0x0A /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_A16R5G6B5        0x0B /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X16R5G6B5        0x0C /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_A8R8G8B8         0x0D /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X8R8G8B8         0x0E /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_Y16              0x0F /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_A16Y16           0x10 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X16Y16           0x11 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_V8YB8U8YA8       0x12 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_YB8V8YA8U8       0x13 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_Y32              0x14 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH2_NOTIFY_INSTANCE                 31:16 /* RWXUF */
+#define NV_PGRAPH_CTX_SWITCH2_NOTIFY_INSTANCE_INVALID        0x0000 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH3                            0x00400168 /* RW-4R */
+#define NV_PGRAPH_CTX_SWITCH3_DMA_INSTANCE_0                   15:0 /* RWXUF */
+#define NV_PGRAPH_CTX_SWITCH3_DMA_INSTANCE_0_INVALID         0x0000 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH3_DMA_INSTANCE_1                  31:16 /* RWXUF */
+#define NV_PGRAPH_CTX_SWITCH3_DMA_INSTANCE_1_INVALID         0x0000 /* RW--V */
+#define NV_PGRAPH_CTX_SWITCH4                            0x0040016C /* RW-4R */
+#define NV_PGRAPH_CTX_SWITCH4_USER_INSTANCE                    15:0 /* RWXUF */
+#define NV_PGRAPH_CTX_SWITCH4_USER_INSTANCE_INVALID          0x0000 /* RW--V */
+#define NV_PGRAPH_CTX_CACHE1(i)                  (0x00400180+(i)*4) /* RW-4A */
+#define NV_PGRAPH_CTX_CACHE1__SIZE_1                              8 /*       */
+#define NV_PGRAPH_CTX_CACHE1_GRCLASS                            7:0 /* RWXVF */
+#define NV_PGRAPH_CTX_CACHE1_CHROMA_KEY                       12:12 /* RWXVF */
+#define NV_PGRAPH_CTX_CACHE1_USER_CLIP                        13:13 /* RWXVF */
+#define NV_PGRAPH_CTX_CACHE1_SWIZZLE                          14:14 /* RWXVF */
+#define NV_PGRAPH_CTX_CACHE1_PATCH_CONFIG                     19:15 /* RWXVF */
+#define NV_PGRAPH_CTX_CACHE1_SPARE1                           20:20 /* RWXVF */
+#define NV_PGRAPH_CTX_CACHE1_PATCH_STATUS                     24:24 /* RWXVF */
+#define NV_PGRAPH_CTX_CACHE1_CONTEXT_SURFACE                  25:25 /* RWXVF */
+#define NV_PGRAPH_CTX_CACHE2(i)                  (0x004001a0+(i)*4) /* RW-4A */
+#define NV_PGRAPH_CTX_CACHE2__SIZE_1                              8 /*       */
+#define NV_PGRAPH_CTX_CACHE2_MONO_FORMAT                        1:0 /* RWXVF */
+#define NV_PGRAPH_CTX_CACHE2_COLOR_FORMAT                      13:8 /* RWXVF */
+#define NV_PGRAPH_CTX_CACHE2_NOTIFY_INSTANCE                  31:16 /* RWXVF */
+#define NV_PGRAPH_CTX_CACHE3(i)                  (0x004001c0+(i)*4) /* RW-4A */
+#define NV_PGRAPH_CTX_CACHE3__SIZE_1                              8 /*       */
+#define NV_PGRAPH_CTX_CACHE3_DMA_INSTANCE_0                    15:0 /* RWXVF */
+#define NV_PGRAPH_CTX_CACHE3_DMA_INSTANCE_1                   31:16 /* RWXVF */
+#define NV_PGRAPH_CTX_CACHE4(i)                  (0x004001e0+(i)*4) /* RW-4A */
+#define NV_PGRAPH_CTX_CACHE4__SIZE_1                              8 /*       */
+#define NV_PGRAPH_CTX_CACHE4_USER_INSTANCE                     15:0 /* RWXVF */
+#define NV_PGRAPH_CTX_CONTROL                            0x00400170 /* RW-4R */
+#define NV_PGRAPH_CTX_CONTROL_MINIMUM_TIME                      1:0 /* RWIVF */
+#define NV_PGRAPH_CTX_CONTROL_MINIMUM_TIME_33US          0x00000000 /* RWI-V */
+#define NV_PGRAPH_CTX_CONTROL_MINIMUM_TIME_262US         0x00000001 /* RW--V */
+#define NV_PGRAPH_CTX_CONTROL_MINIMUM_TIME_2MS           0x00000002 /* RW--V */
+#define NV_PGRAPH_CTX_CONTROL_MINIMUM_TIME_17MS          0x00000003 /* RW--V */
+#define NV_PGRAPH_CTX_CONTROL_TIME                              8:8 /* RWIVF */
+#define NV_PGRAPH_CTX_CONTROL_TIME_EXPIRED               0x00000000 /* RWI-V */
+#define NV_PGRAPH_CTX_CONTROL_TIME_NOT_EXPIRED           0x00000001 /* RW--V */
+#define NV_PGRAPH_CTX_CONTROL_CHID                            16:16 /* RWIVF */
+#define NV_PGRAPH_CTX_CONTROL_CHID_INVALID               0x00000000 /* RWI-V */
+#define NV_PGRAPH_CTX_CONTROL_CHID_VALID                 0x00000001 /* RW--V */
+#define NV_PGRAPH_CTX_CONTROL_CHANGE                          20:20 /* R--VF */
+#define NV_PGRAPH_CTX_CONTROL_CHANGE_UNAVAILABLE         0x00000000 /* R---V */
+#define NV_PGRAPH_CTX_CONTROL_CHANGE_AVAILABLE           0x00000001 /* R---V */
+#define NV_PGRAPH_CTX_CONTROL_SWITCHING                       24:24 /* RWIVF */
+#define NV_PGRAPH_CTX_CONTROL_SWITCHING_IDLE             0x00000000 /* RWI-V */
+#define NV_PGRAPH_CTX_CONTROL_SWITCHING_BUSY             0x00000001 /* RW--V */
+#define NV_PGRAPH_CTX_CONTROL_DEVICE                          28:28 /* RWIVF */
+#define NV_PGRAPH_CTX_CONTROL_DEVICE_DISABLED            0x00000000 /* RWI-V */
+#define NV_PGRAPH_CTX_CONTROL_DEVICE_ENABLED             0x00000001 /* RW--V */
+#define NV_PGRAPH_CTX_USER                               0x00400174 /* RW-4R */
+#define NV_PGRAPH_CTX_USER_SUBCH                              15:13 /* RWIVF */
+#define NV_PGRAPH_CTX_USER_SUBCH_0                       0x00000000 /* RWI-V */
+#define NV_PGRAPH_CTX_USER_CHID                               27:24 /* RWIVF */
+#define NV_PGRAPH_CTX_USER_CHID_0                        0x00000000 /* RWI-V */
+#define NV_PGRAPH_FIFO                                   0x00400720 /* RW-4R */
+#define NV_PGRAPH_FIFO_ACCESS                                   0:0 /* RWIVF */
+#define NV_PGRAPH_FIFO_ACCESS_DISABLED                   0x00000000 /* RW--V */
+#define NV_PGRAPH_FIFO_ACCESS_ENABLED                    0x00000001 /* RWI-V */
+#define NV_PGRAPH_FFINTFC_FIFO_0(i)              (0x00400730+(i)*4) /* RW-4A */
+#define NV_PGRAPH_FFINTFC_FIFO_0__SIZE_1                          4 /*       */
+#define NV_PGRAPH_FFINTFC_FIFO_0_TAG                            0:0 /* RWXVF */
+#define NV_PGRAPH_FFINTFC_FIFO_0_TAG_MTHD                0x00000000 /* RW--V */
+#define NV_PGRAPH_FFINTFC_FIFO_0_TAG_CHSW                0x00000001 /* RW--V */
+#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH                          3:1 /* RWXVF */
+#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_0                 0x00000000 /* RW--V */
+#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_1                 0x00000001 /* RW--V */
+#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_2                 0x00000002 /* RW--V */
+#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_3                 0x00000003 /* RW--V */
+#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_4                 0x00000004 /* RW--V */
+#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_5                 0x00000005 /* RW--V */
+#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_6                 0x00000006 /* RW--V */
+#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_7                 0x00000007 /* RW--V */
+#define NV_PGRAPH_FFINTFC_FIFO_0_MTHD                          14:4 /* RWXVF */
+#define NV_PGRAPH_FFINTFC_FIFO_0_MTHD_CTX_SWITCH         0x00000000 /* RW--V */
+#define NV_PGRAPH_FFINTFC_FIFO_1(i)              (0x00400740+(i)*4) /* RW-4A */
+#define NV_PGRAPH_FFINTFC_FIFO_1__SIZE_1                          4 /*       */
+#define NV_PGRAPH_FFINTFC_FIFO_1_ARGUMENT                      31:0 /* RWXVF */
+#define NV_PGRAPH_FFINTFC_FIFO_PTR                       0x00400750 /* RW-4R */
+#define NV_PGRAPH_FFINTFC_FIFO_PTR_WRITE                        2:0 /* RWIVF */
+#define NV_PGRAPH_FFINTFC_FIFO_PTR_WRITE_0               0x00000000 /* RWI-V */
+#define NV_PGRAPH_FFINTFC_FIFO_PTR_READ                         6:4 /* RWIVF */
+#define NV_PGRAPH_FFINTFC_FIFO_PTR_READ_0                0x00000000 /* RWI-V */
+#define NV_PGRAPH_FFINTFC_ST2                            0x00400754 /* RW-4R */
+#define NV_PGRAPH_FFINTFC_ST2_STATUS                            0:0 /* RWIVF */
+#define NV_PGRAPH_FFINTFC_ST2_STATUS_INVALID             0x00000000 /* RWI-V */
+#define NV_PGRAPH_FFINTFC_ST2_STATUS_VALID               0x00000001 /* RW--V */
+#define NV_PGRAPH_FFINTFC_ST2_MTHD                             11:1 /* RWIVF */
+#define NV_PGRAPH_FFINTFC_ST2_MTHD_CTX_SWITCH            0x00000000 /* RWI-V */
+#define NV_PGRAPH_FFINTFC_ST2_SUBCH                           14:12 /* RWIVF */
+#define NV_PGRAPH_FFINTFC_ST2_SUBCH_0                    0x00000000 /* RWI-V */
+#define NV_PGRAPH_FFINTFC_ST2_SUBCH_1                    0x00000001 /* RW--V */
+#define NV_PGRAPH_FFINTFC_ST2_SUBCH_2                    0x00000002 /* RW--V */
+#define NV_PGRAPH_FFINTFC_ST2_SUBCH_3                    0x00000003 /* RW--V */
+#define NV_PGRAPH_FFINTFC_ST2_SUBCH_4                    0x00000004 /* RW--V */
+#define NV_PGRAPH_FFINTFC_ST2_SUBCH_5                    0x00000005 /* RW--V */
+#define NV_PGRAPH_FFINTFC_ST2_SUBCH_6                    0x00000006 /* RW--V */
+#define NV_PGRAPH_FFINTFC_ST2_SUBCH_7                    0x00000007 /* RW--V */
+#define NV_PGRAPH_FFINTFC_ST2_CHID                            18:15 /* RWIVF */
+#define NV_PGRAPH_FFINTFC_ST2_CHID_0                     0x00000000 /* RWI-V */
+#define NV_PGRAPH_FFINTFC_ST2_CHID_1                     0x00000001 /* RW--V */
+#define NV_PGRAPH_FFINTFC_ST2_CHID_2                     0x00000002 /* RW--V */
+#define NV_PGRAPH_FFINTFC_ST2_CHID_3                     0x00000003 /* RW--V */
+#define NV_PGRAPH_FFINTFC_ST2_CHID_4                     0x00000004 /* RW--V */
+#define NV_PGRAPH_FFINTFC_ST2_CHID_5                     0x00000005 /* RW--V */
+#define NV_PGRAPH_FFINTFC_ST2_CHID_6                     0x00000006 /* RW--V */
+#define NV_PGRAPH_FFINTFC_ST2_CHID_7                     0x00000007 /* RW--V */
+#define NV_PGRAPH_FFINTFC_ST2_CHID_8                     0x00000008 /* RW--V */
+#define NV_PGRAPH_FFINTFC_ST2_CHID_9                     0x00000009 /* RW--V */
+#define NV_PGRAPH_FFINTFC_ST2_CHID_10                    0x0000000A /* RW--V */
+#define NV_PGRAPH_FFINTFC_ST2_CHID_11                    0x0000000B /* RW--V */
+#define NV_PGRAPH_FFINTFC_ST2_CHID_12                    0x0000000C /* RW--V */
+#define NV_PGRAPH_FFINTFC_ST2_CHID_13                    0x0000000D /* RW--V */
+#define NV_PGRAPH_FFINTFC_ST2_CHID_14                    0x0000000E /* RW--V */
+#define NV_PGRAPH_FFINTFC_ST2_CHID_15                    0x0000000F /* RW--V */
+#define NV_PGRAPH_FFINTFC_ST2_CHID_STATUS                     19:19 /* RWIVF */
+#define NV_PGRAPH_FFINTFC_ST2_CHID_STATUS_INVALID        0x00000000 /* RWI-V */
+#define NV_PGRAPH_FFINTFC_ST2_CHID_STATUS_VALID          0x00000001 /* RW--V */
+#define NV_PGRAPH_FFINTFC_ST2_D                          0x00400758 /* RW-4R */
+#define NV_PGRAPH_FFINTFC_ST2_D_ARGUMENT                       31:0 /* RWIVF */
+#define NV_PGRAPH_FFINTFC_ST2_D_ARGUMENT_0               0x00000000 /* RWI-V */
+#define NV_PGRAPH_STATUS                                 0x00400700 /* R--4R */
+#define NV_PGRAPH_STATUS_STATE                                  0:0 /* R-IVF */
+#define NV_PGRAPH_STATUS_STATE_IDLE                      0x00000000 /* R-I-V */
+#define NV_PGRAPH_STATUS_STATE_BUSY                      0x00000001 /* R---V */
+#define NV_PGRAPH_STATUS_XY_LOGIC                               4:4 /* R-IVF */
+#define NV_PGRAPH_STATUS_XY_LOGIC_IDLE                   0x00000000 /* R-I-V */
+#define NV_PGRAPH_STATUS_XY_LOGIC_BUSY                   0x00000001 /* R---V */
+#define NV_PGRAPH_STATUS_FE                                     5:5 /* R-IVF */
+#define NV_PGRAPH_STATUS_FE_IDLE                         0x00000000 /* R-I-V */
+#define NV_PGRAPH_STATUS_FE_BUSY                         0x00000001 /* R---V */
+#define NV_PGRAPH_STATUS_RASTERIZER                             6:6 /* R-IVF */
+#define NV_PGRAPH_STATUS_RASTERIZER_IDLE                 0x00000000 /* R-I-V */
+#define NV_PGRAPH_STATUS_RASTERIZER_BUSY                 0x00000001 /* R---V */
+#define NV_PGRAPH_STATUS_PORT_NOTIFY                            8:8 /* R-IVF */
+#define NV_PGRAPH_STATUS_PORT_NOTIFY_IDLE                0x00000000 /* R-I-V */
+#define NV_PGRAPH_STATUS_PORT_NOTIFY_BUSY                0x00000001 /* R---V */
+#define NV_PGRAPH_STATUS_PORT_REGISTER                        12:12 /* R-IVF */
+#define NV_PGRAPH_STATUS_PORT_REGISTER_IDLE              0x00000000 /* R-I-V */
+#define NV_PGRAPH_STATUS_PORT_REGISTER_BUSY              0x00000001 /* R---V */
+#define NV_PGRAPH_STATUS_PORT_DMA                             16:16 /* R-IVF */
+#define NV_PGRAPH_STATUS_PORT_DMA_IDLE                   0x00000000 /* R-I-V */
+#define NV_PGRAPH_STATUS_PORT_DMA_BUSY                   0x00000001 /* R---V */
+#define NV_PGRAPH_STATUS_DMA_ENGINE                           17:17 /* R-IVF */
+#define NV_PGRAPH_STATUS_DMA_ENGINE_IDLE                 0x00000000 /* R-I-V */
+#define NV_PGRAPH_STATUS_DMA_ENGINE_BUSY                 0x00000001 /* R---V */
+#define NV_PGRAPH_STATUS_DMA_NOTIFY                           20:20 /* R-IVF */
+#define NV_PGRAPH_STATUS_DMA_NOTIFY_IDLE                 0x00000000 /* R-I-V */
+#define NV_PGRAPH_STATUS_DMA_NOTIFY_BUSY                 0x00000001 /* R---V */
+#define NV_PGRAPH_STATUS_DMA_BUFFER_NOTIFY                    21:21 /* R-IVF */
+#define NV_PGRAPH_STATUS_DMA_BUFFER_NOTIFY_IDLE          0x00000000 /* R-I-V */
+#define NV_PGRAPH_STATUS_DMA_BUFFER_NOTIFY_BUSY          0x00000001 /* R---V */
+#define NV_PGRAPH_STATUS_D3D                                  24:24 /* R-IVF */
+#define NV_PGRAPH_STATUS_D3D_IDLE                        0x00000000 /* R-I-V */
+#define NV_PGRAPH_STATUS_D3D_BUSY                        0x00000001 /* R---V */
+#define NV_PGRAPH_STATUS_CACHE                                25:25 /* R-IVF */
+#define NV_PGRAPH_STATUS_CACHE_IDLE                      0x00000000 /* R-I-V */
+#define NV_PGRAPH_STATUS_CACHE_BUSY                      0x00000001 /* R---V */
+#define NV_PGRAPH_STATUS_LIGHTING                             26:26 /* R-IVF */
+#define NV_PGRAPH_STATUS_LIGHTING_IDLE                   0x00000000 /* R-I-V */
+#define NV_PGRAPH_STATUS_LIGHTING_BUSY                   0x00000001 /* R---V */
+#define NV_PGRAPH_STATUS_PREROP                               27:27 /* R-IVF */
+#define NV_PGRAPH_STATUS_PREROP_IDLE                     0x00000000 /* R-I-V */
+#define NV_PGRAPH_STATUS_PREROP_BUSY                     0x00000001 /* R---V */
+#define NV_PGRAPH_STATUS_ROP                                  28:28 /* R-IVF */
+#define NV_PGRAPH_STATUS_ROP_IDLE                        0x00000000 /* R-I-V */
+#define NV_PGRAPH_STATUS_ROP_BUSY                        0x00000001 /* R---V */
+#define NV_PGRAPH_STATUS_PORT_USER                            29:29 /* R-IVF */
+#define NV_PGRAPH_STATUS_PORT_USER_IDLE                  0x00000000 /* R-I-V */
+#define NV_PGRAPH_STATUS_PORT_USER_BUSY                  0x00000001 /* R---V */
+#define NV_PGRAPH_TRAPPED_ADDR                           0x00400704 /* R--4R */
+#define NV_PGRAPH_TRAPPED_ADDR_MTHD                            12:2 /* R-XUF */
+#define NV_PGRAPH_TRAPPED_ADDR_SUBCH                          15:13 /* R-XUF */
+#define NV_PGRAPH_TRAPPED_ADDR_CHID                           27:24 /* R-XUF */
+#define NV_PGRAPH_TRAPPED_DATA                           0x00400708 /* R--4R */
+#define NV_PGRAPH_TRAPPED_DATA_VALUE                           31:0 /* R-XVF */
+#define NV_PGRAPH_SURFACE                                0x0040070C /* RW-4R */
+#define NV_PGRAPH_SURFACE_TYPE                                  1:0 /* RWIVF */
+#define NV_PGRAPH_SURFACE_TYPE_INVALID                   0x00000000 /* RWI-V */
+#define NV_PGRAPH_SURFACE_TYPE_NON_SWIZZLE               0x00000001 /* RW--V */
+#define NV_PGRAPH_SURFACE_TYPE_SWIZZLE                   0x00000002 /* RW--V */
+#define NV_PGRAPH_NOTIFY                                 0x00400714 /* RW-4R */
+#define NV_PGRAPH_NOTIFY_BUFFER_REQ                             0:0 /* RWIVF */
+#define NV_PGRAPH_NOTIFY_BUFFER_REQ_NOT_PENDING          0x00000000 /* RWI-V */
+#define NV_PGRAPH_NOTIFY_BUFFER_REQ_PENDING              0x00000001 /* RW--V */
+#define NV_PGRAPH_NOTIFY_BUFFER_STYLE                           8:8 /* RWIVF */
+#define NV_PGRAPH_NOTIFY_BUFFER_STYLE_WRITE_ONLY         0x00000000 /* RWI-V */
+#define NV_PGRAPH_NOTIFY_BUFFER_STYLE_WRITE_THEN_AWAKEN  0x00000001 /* RW--V */
+#define NV_PGRAPH_NOTIFY_REQ                                  16:16 /* RWIVF */
+#define NV_PGRAPH_NOTIFY_REQ_NOT_PENDING                 0x00000000 /* RWI-V */
+#define NV_PGRAPH_NOTIFY_REQ_PENDING                     0x00000001 /* RW--V */
+#define NV_PGRAPH_NOTIFY_STYLE                                20:20 /* RWIVF */
+#define NV_PGRAPH_NOTIFY_STYLE_WRITE_ONLY                0x00000000 /* RWI-V */
+#define NV_PGRAPH_NOTIFY_STYLE_WRITE_THEN_AWAKEN         0x00000001 /* RW--V */
+#define NV_PGRAPH_BOFFSET(i)                     (0x00400640+(i)*4) /* RW-4A */
+#define NV_PGRAPH_BOFFSET__SIZE_1                                 6 /*       */
+#define NV_PGRAPH_BOFFSET_LINADRS                              23:0 /* RWIUF */
+#define NV_PGRAPH_BOFFSET_LINADRS_0                      0x00000000 /* RWI-V */
+#define NV_PGRAPH_BOFFSET0                               0x00400640 /* RW-4R */
+#define NV_PGRAPH_BOFFSET0__ALIAS_1            NV_PGRAPH_BOFFSET(0) /*       */
+#define NV_PGRAPH_BOFFSET0_LINADRS                             23:0 /* RWIUF */
+#define NV_PGRAPH_BOFFSET0_LINADRS_0                     0x00000000 /* RWI-V */
+#define NV_PGRAPH_BOFFSET1                               0x00400644 /* RW-4R */
+#define NV_PGRAPH_BOFFSET1__ALIAS_1            NV_PGRAPH_BOFFSET(1) /*       */
+#define NV_PGRAPH_BOFFSET1_LINADRS                             23:0 /* RWIUF */
+#define NV_PGRAPH_BOFFSET1_LINADRS_0                     0x00000000 /* RWI-V */
+#define NV_PGRAPH_BOFFSET2                               0x00400648 /* RW-4R */
+#define NV_PGRAPH_BOFFSET2__ALIAS_1            NV_PGRAPH_BOFFSET(2) /*       */
+#define NV_PGRAPH_BOFFSET2_LINADRS                             23:0 /* RWIUF */
+#define NV_PGRAPH_BOFFSET2_LINADRS_0                     0x00000000 /* RWI-V */
+#define NV_PGRAPH_BOFFSET3                               0x0040064C /* RW-4R */
+#define NV_PGRAPH_BOFFSET3__ALIAS_1            NV_PGRAPH_BOFFSET(3) /*       */
+#define NV_PGRAPH_BOFFSET3_LINADRS                             23:0 /* RWIUF */
+#define NV_PGRAPH_BOFFSET3_LINADRS_0                     0x00000000 /* RWI-V */
+#define NV_PGRAPH_BOFFSET4                               0x00400650 /* RW-4R */
+#define NV_PGRAPH_BOFFSET4__ALIAS_1            NV_PGRAPH_BOFFSET(4) /*       */
+#define NV_PGRAPH_BOFFSET4_LINADRS                             23:0 /* RWIUF */
+#define NV_PGRAPH_BOFFSET4_LINADRS_0                     0x00000000 /* RWI-V */
+#define NV_PGRAPH_BOFFSET5                               0x00400654 /* RW-4R */
+#define NV_PGRAPH_BOFFSET5__ALIAS_1            NV_PGRAPH_BOFFSET(5) /*       */
+#define NV_PGRAPH_BOFFSET5_LINADRS                             23:0 /* RWIUF */
+#define NV_PGRAPH_BOFFSET5_LINADRS_0                     0x00000000 /* RWI-V */
+#define NV_PGRAPH_BBASE(i)                       (0x00400658+(i)*4) /* RW-4A */
+#define NV_PGRAPH_BBASE__SIZE_1                                   6 /*       */
+#define NV_PGRAPH_BBASE_LINADRS                                23:0 /* RWIUF */
+#define NV_PGRAPH_BBASE_LINADRS_0                        0x00000000 /* RWI-V */
+#define NV_PGRAPH_BBASE0                                 0x00400658 /* RW-4R */
+#define NV_PGRAPH_BBASE0__ALIAS_1                NV_PGRAPH_BBASE(0) /*       */
+#define NV_PGRAPH_BBASE0_LINADRS                               23:0 /* RWIUF */
+#define NV_PGRAPH_BBASE0_LINADRS_0                       0x00000000 /* RWI-V */
+#define NV_PGRAPH_BBASE1                                 0x0040065c /* RW-4R */
+#define NV_PGRAPH_BBASE1__ALIAS_1                NV_PGRAPH_BBASE(1) /*       */
+#define NV_PGRAPH_BBASE1_LINADRS                               23:0 /* RWIUF */
+#define NV_PGRAPH_BBASE1_LINADRS_0                       0x00000000 /* RWI-V */
+#define NV_PGRAPH_BBASE2                                 0x00400660 /* RW-4R */
+#define NV_PGRAPH_BBASE2__ALIAS_1                NV_PGRAPH_BBASE(2) /*       */
+#define NV_PGRAPH_BBASE2_LINADRS                               23:0 /* RWIUF */
+#define NV_PGRAPH_BBASE2_LINADRS_0                       0x00000000 /* RWI-V */
+#define NV_PGRAPH_BBASE3                                 0x00400664 /* RW-4R */
+#define NV_PGRAPH_BBASE3__ALIAS_1                NV_PGRAPH_BBASE(3) /*       */
+#define NV_PGRAPH_BBASE3_LINADRS                               23:0 /* RWIUF */
+#define NV_PGRAPH_BBASE3_LINADRS_0                       0x00000000 /* RWI-V */
+#define NV_PGRAPH_BBASE4                                 0x00400668 /* RW-4R */
+#define NV_PGRAPH_BBASE4__ALIAS_1                NV_PGRAPH_BBASE(4) /*       */
+#define NV_PGRAPH_BBASE4_LINADRS                               23:0 /* RWIUF */
+#define NV_PGRAPH_BBASE4_LINADRS_0                       0x00000000 /* RWI-V */
+#define NV_PGRAPH_BBASE5                                 0x0040066C /* RW-4R */
+#define NV_PGRAPH_BBASE5__ALIAS_1                NV_PGRAPH_BBASE(5) /*       */
+#define NV_PGRAPH_BBASE5_LINADRS                               23:0 /* RWIUF */
+#define NV_PGRAPH_BBASE5_LINADRS_0                       0x00000000 /* RWI-V */
+#define NV_PGRAPH_BPITCH(i)                      (0x00400670+(i)*4) /* RW-4A */
+#define NV_PGRAPH_BPITCH__SIZE_1                                  5 /*       */
+#define NV_PGRAPH_BPITCH_VALUE                                 12:0 /* RWIUF */
+#define NV_PGRAPH_BPITCH_VALUE_0                         0x00000000 /* RWI-V */
+#define NV_PGRAPH_BPITCH0                                0x00400670 /* RW-4R */
+#define NV_PGRAPH_BPITCH0__ALIAS_1              NV_PGRAPH_BPITCH(0) /*       */
+#define NV_PGRAPH_BPITCH0_VALUE                                12:0 /* RWIUF */
+#define NV_PGRAPH_BPITCH0_VALUE_0                        0x00000000 /* RWI-V */
+#define NV_PGRAPH_BPITCH1                                0x00400674 /* RW-4R */
+#define NV_PGRAPH_BPITCH1__ALIAS_1              NV_PGRAPH_BPITCH(1) /*       */
+#define NV_PGRAPH_BPITCH1_VALUE                                12:0 /* RWIUF */
+#define NV_PGRAPH_BPITCH1_VALUE_0                        0x00000000 /* RWI-V */
+#define NV_PGRAPH_BPITCH2                                0x00400678 /* RW-4R */
+#define NV_PGRAPH_BPITCH2__ALIAS_1              NV_PGRAPH_BPITCH(2) /*       */
+#define NV_PGRAPH_BPITCH2_VALUE                                12:0 /* RWIUF */
+#define NV_PGRAPH_BPITCH2_VALUE_0                        0x00000000 /* RWI-V */
+#define NV_PGRAPH_BPITCH3                                0x0040067C /* RW-4R */
+#define NV_PGRAPH_BPITCH3__ALIAS_1              NV_PGRAPH_BPITCH(3) /*       */
+#define NV_PGRAPH_BPITCH3_VALUE                                12:0 /* RWIUF */
+#define NV_PGRAPH_BPITCH3_VALUE_0                        0x00000000 /* RWI-V */
+#define NV_PGRAPH_BPITCH4                                0x00400680 /* RW-4R */
+#define NV_PGRAPH_BPITCH4__ALIAS_1              NV_PGRAPH_BPITCH(4) /*       */
+#define NV_PGRAPH_BPITCH4_VALUE                                12:0 /* RWIUF */
+#define NV_PGRAPH_BPITCH4_VALUE_0                        0x00000000 /* RWI-V */
+#define NV_PGRAPH_BLIMIT(i)                      (0x00400684+(i)*4) /* RW-4A */
+#define NV_PGRAPH_BLIMIT__SIZE_1                                  6 /*       */
+#define NV_PGRAPH_BLIMIT_VALUE                                 23:0 /* RWXUF */
+#define NV_PGRAPH_BLIMIT_TYPE                                 31:31 /* RWIVF */
+#define NV_PGRAPH_BLIMIT_TYPE_IN_MEMORY                  0x00000000 /* RW--V */
+#define NV_PGRAPH_BLIMIT_TYPE_NULL                       0x00000001 /* RWI-V */
+#define NV_PGRAPH_BLIMIT0                                0x00400684 /* RW-4R */
+#define NV_PGRAPH_BLIMIT0__ALIAS_1              NV_PGRAPH_BLIMIT(0) /*       */
+#define NV_PGRAPH_BLIMIT0_VALUE                                23:0 /* RWXUF */
+#define NV_PGRAPH_BLIMIT0_TYPE                                31:31 /* RWIVF */
+#define NV_PGRAPH_BLIMIT0_TYPE_IN_MEMORY                 0x00000000 /* RW--V */
+#define NV_PGRAPH_BLIMIT0_TYPE_NULL                      0x00000001 /* RWI-V */
+#define NV_PGRAPH_BLIMIT1                                0x00400688 /* RW-4R */
+#define NV_PGRAPH_BLIMIT1__ALIAS_1              NV_PGRAPH_BLIMIT(1) /*       */
+#define NV_PGRAPH_BLIMIT1_VALUE                                23:0 /* RWXUF */
+#define NV_PGRAPH_BLIMIT1_TYPE                                31:31 /* RWIVF */
+#define NV_PGRAPH_BLIMIT1_TYPE_IN_MEMORY                 0x00000000 /* RW--V */
+#define NV_PGRAPH_BLIMIT1_TYPE_NULL                      0x00000001 /* RWI-V */
+#define NV_PGRAPH_BLIMIT2                                0x0040068c /* RW-4R */
+#define NV_PGRAPH_BLIMIT2__ALIAS_1              NV_PGRAPH_BLIMIT(2) /*       */
+#define NV_PGRAPH_BLIMIT2_VALUE                                23:0 /* RWXUF */
+#define NV_PGRAPH_BLIMIT2_TYPE                                31:31 /* RWIVF */
+#define NV_PGRAPH_BLIMIT2_TYPE_IN_MEMORY                 0x00000000 /* RW--V */
+#define NV_PGRAPH_BLIMIT2_TYPE_NULL                      0x00000001 /* RWI-V */
+#define NV_PGRAPH_BLIMIT3                                0x00400690 /* RW-4R */
+#define NV_PGRAPH_BLIMIT3__ALIAS_1              NV_PGRAPH_BLIMIT(3) /*       */
+#define NV_PGRAPH_BLIMIT3_VALUE                                23:0 /* RWXUF */
+#define NV_PGRAPH_BLIMIT3_TYPE                                31:31 /* RWIVF */
+#define NV_PGRAPH_BLIMIT3_TYPE_IN_MEMORY                 0x00000000 /* RW--V */
+#define NV_PGRAPH_BLIMIT3_TYPE_NULL                      0x00000001 /* RWI-V */
+#define NV_PGRAPH_BLIMIT4                                0x00400694 /* RW-4R */
+#define NV_PGRAPH_BLIMIT4__ALIAS_1              NV_PGRAPH_BLIMIT(4) /*       */
+#define NV_PGRAPH_BLIMIT4_VALUE                                23:0 /* RWXUF */
+#define NV_PGRAPH_BLIMIT4_TYPE                                31:31 /* RWIVF */
+#define NV_PGRAPH_BLIMIT4_TYPE_IN_MEMORY                 0x00000000 /* RW--V */
+#define NV_PGRAPH_BLIMIT4_TYPE_NULL                      0x00000001 /* RWI-V */
+#define NV_PGRAPH_BLIMIT5                                0x00400698 /* RW-4R */
+#define NV_PGRAPH_BLIMIT5__ALIAS_1              NV_PGRAPH_BLIMIT(5) /*       */
+#define NV_PGRAPH_BLIMIT5_VALUE                                23:0 /* RWXUF */
+#define NV_PGRAPH_BLIMIT5_TYPE                                31:31 /* RWIVF */
+#define NV_PGRAPH_BLIMIT5_TYPE_IN_MEMORY                 0x00000000 /* RW--V */
+#define NV_PGRAPH_BLIMIT5_TYPE_NULL                      0x00000001 /* RWI-V */
+#define NV_PGRAPH_BSWIZZLE2                              0x0040069c /* RW-4R */
+#define NV_PGRAPH_BSWIZZLE2_WIDTH                             19:16 /* RWIUF */
+#define NV_PGRAPH_BSWIZZLE2_WIDTH_0                      0x00000000 /* RWI-V */
+#define NV_PGRAPH_BSWIZZLE2_HEIGHT                            27:24 /* RWIUF */
+#define NV_PGRAPH_BSWIZZLE2_HEIGHT_0                     0x00000000 /* RWI-V */
+#define NV_PGRAPH_BSWIZZLE5                              0x004006a0 /* RW-4R */
+#define NV_PGRAPH_BSWIZZLE5_WIDTH                             19:16 /* RWIUF */
+#define NV_PGRAPH_BSWIZZLE5_WIDTH_0                      0x00000000 /* RWI-V */
+#define NV_PGRAPH_BSWIZZLE5_HEIGHT                            27:24 /* RWIUF */
+#define NV_PGRAPH_BSWIZZLE5_HEIGHT_0                     0x00000000 /* RWI-V */
+#define NV_PGRAPH_BPIXEL                                 0x00400724 /* RW-4R */
+#define NV_PGRAPH_BPIXEL_DEPTH0                                 3:0 /* RWIVF */
+#define NV_PGRAPH_BPIXEL_DEPTH0_INVALID                  0x00000000 /* RWI-V */
+#define NV_PGRAPH_BPIXEL_DEPTH0_Y8                       0x00000001 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH0_X1R5G5B5_Z1R5G5B5        0x00000002 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH0_X1R5G5B5_O1R5G5B5        0x00000003 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH0_A1R5G5B5                 0x00000004 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH0_R5G6B5                   0x00000005 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH0_Y16                      0x00000006 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH0_X8R8G8B8_Z8R8G8B8        0x00000007 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH0_X8R8G8B8_O1Z7R8G8B8      0x00000008 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH0_X1A7R8G8B8_Z1A7R8G8B8    0x00000009 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH0_X1A7R8G8B8_O1A7R8G8B8    0x0000000a /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH0_X8R8G8B8_O8R8G8B8        0x0000000b /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH0_A8R8G8B8                 0x0000000c /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH0_Y32                      0x0000000d /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH0_V8YB8U8YA8               0x0000000e /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH0_YB8V8YA8U8               0x0000000f /* RW--V */ 
+#define NV_PGRAPH_BPIXEL_DEPTH1                                 7:4 /* RWIVF */
+#define NV_PGRAPH_BPIXEL_DEPTH1_INVALID                  0x00000000 /* RWI-V */
+#define NV_PGRAPH_BPIXEL_DEPTH1_Y8                       0x00000001 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH1_X1R5G5B5_Z1R5G5B5        0x00000002 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH1_X1R5G5B5_O1R5G5B5        0x00000003 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH1_A1R5G5B5                 0x00000004 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH1_R5G6B5                   0x00000005 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH1_Y16                      0x00000006 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH1_X8R8G8B8_Z8R8G8B8        0x00000007 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH1_X8R8G8B8_O1Z7R8G8B8      0x00000008 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH1_X1A7R8G8B8_Z1A7R8G8B8    0x00000009 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH1_X1A7R8G8B8_O1A7R8G8B8    0x0000000a /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH1_X8R8G8B8_O8R8G8B8        0x0000000b /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH1_A8R8G8B8                 0x0000000c /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH1_Y32                      0x0000000d /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH1_V8YB8U8YA8               0x0000000e /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH1_YB8V8YA8U8               0x0000000f /* RW--V */ 
+#define NV_PGRAPH_BPIXEL_DEPTH2                                11:8 /* RWIVF */
+#define NV_PGRAPH_BPIXEL_DEPTH2_INVALID                  0x00000000 /* RWI-V */
+#define NV_PGRAPH_BPIXEL_DEPTH2_Y8                       0x00000001 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH2_X1R5G5B5_Z1R5G5B5        0x00000002 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH2_X1R5G5B5_O1R5G5B5        0x00000003 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH2_A1R5G5B5                 0x00000004 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH2_R5G6B5                   0x00000005 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH2_Y16                      0x00000006 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH2_X8R8G8B8_Z8R8G8B8        0x00000007 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH2_X8R8G8B8_O1Z7R8G8B8      0x00000008 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH2_X1A7R8G8B8_Z1A7R8G8B8    0x00000009 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH2_X1A7R8G8B8_O1A7R8G8B8    0x0000000a /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH2_X8R8G8B8_O8R8G8B8        0x0000000b /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH2_A8R8G8B8                 0x0000000c /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH2_Y32                      0x0000000d /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH2_V8YB8U8YA8               0x0000000e /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH2_YB8V8YA8U8               0x0000000f /* RW--V */ 
+#define NV_PGRAPH_BPIXEL_DEPTH3                               15:12 /* RWIVF */
+#define NV_PGRAPH_BPIXEL_DEPTH3_INVALID                  0x00000000 /* RWI-V */
+#define NV_PGRAPH_BPIXEL_DEPTH3_Y8                       0x00000001 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH3_X1R5G5B5_Z1R5G5B5        0x00000002 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH3_X1R5G5B5_O1R5G5B5        0x00000003 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH3_A1R5G5B5                 0x00000004 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH3_R5G6B5                   0x00000005 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH3_Y16                      0x00000006 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH3_X8R8G8B8_Z8R8G8B8        0x00000007 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH3_X8R8G8B8_O1Z7R8G8B8      0x00000008 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH3_X1A7R8G8B8_Z1A7R8G8B8    0x00000009 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH3_X1A7R8G8B8_O1A7R8G8B8    0x0000000a /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH3_X8R8G8B8_O8R8G8B8        0x0000000b /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH3_A8R8G8B8                 0x0000000c /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH3_Y32                      0x0000000d /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH3_V8YB8U8YA8               0x0000000e /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH3_YB8V8YA8U8               0x0000000f /* RW--V */ 
+#define NV_PGRAPH_BPIXEL_DEPTH4                               19:16 /* RWIVF */
+#define NV_PGRAPH_BPIXEL_DEPTH4_INVALID                  0x00000000 /* RWI-V */
+#define NV_PGRAPH_BPIXEL_DEPTH4_Y8                       0x00000001 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH4_X1R5G5B5_Z1R5G5B5        0x00000002 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH4_X1R5G5B5_O1R5G5B5        0x00000003 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH4_A1R5G5B5                 0x00000004 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH4_R5G6B5                   0x00000005 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH4_Y16                      0x00000006 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH4_X8R8G8B8_Z8R8G8B8        0x00000007 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH4_X8R8G8B8_O1Z7R8G8B8      0x00000008 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH4_X1A7R8G8B8_Z1A7R8G8B8    0x00000009 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH4_X1A7R8G8B8_O1A7R8G8B8    0x0000000a /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH4_X8R8G8B8_O8R8G8B8        0x0000000b /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH4_A8R8G8B8                 0x0000000c /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH4_Y32                      0x0000000d /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH4_V8YB8U8YA8               0x0000000e /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH4_YB8V8YA8U8               0x0000000f /* RW--V */ 
+#define NV_PGRAPH_BPIXEL_DEPTH5                               23:20 /* RWIVF */
+#define NV_PGRAPH_BPIXEL_DEPTH5_INVALID                  0x00000000 /* RWI-V */
+#define NV_PGRAPH_BPIXEL_DEPTH5_Y8                       0x00000001 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH5_X1R5G5B5_Z1R5G5B5        0x00000002 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH5_X1R5G5B5_O1R5G5B5        0x00000003 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH5_A1R5G5B5                 0x00000004 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH5_R5G6B5                   0x00000005 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH5_Y16                      0x00000006 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH5_X8R8G8B8_Z8R8G8B8        0x00000007 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH5_X8R8G8B8_O1Z7R8G8B8      0x00000008 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH5_X1A7R8G8B8_Z1A7R8G8B8    0x00000009 /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH5_X1A7R8G8B8_O1A7R8G8B8    0x0000000a /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH5_X8R8G8B8_O8R8G8B8        0x0000000b /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH5_A8R8G8B8                 0x0000000c /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH5_Y32                      0x0000000d /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH5_V8YB8U8YA8               0x0000000e /* RW--V */
+#define NV_PGRAPH_BPIXEL_DEPTH5_YB8V8YA8U8               0x0000000f /* RW--V */ 
+#define NV_PGRAPH_LIMIT_VIOL_PIX                         0x00400610 /* RW-4R */
+#define NV_PGRAPH_LIMIT_VIOL_PIX_ADRS                          23:0 /* RWIVF */
+#define NV_PGRAPH_LIMIT_VIOL_PIX_ADRS_0                  0x00000000 /* RWI-V */
+#define NV_PGRAPH_LIMIT_VIOL_PIX_BLIT                         29:29 /* RWIVF */
+#define NV_PGRAPH_LIMIT_VIOL_PIX_BLIT_NO_VIOL            0x00000000 /* RWI-V */
+#define NV_PGRAPH_LIMIT_VIOL_PIX_BLIT_VIOL               0x00000001 /* RW--V */
+#define NV_PGRAPH_LIMIT_VIOL_PIX_LIMIT                        30:30 /* RWIVF */
+#define NV_PGRAPH_LIMIT_VIOL_PIX_LIMIT_NO_VIOL           0x00000000 /* RWI-V */
+#define NV_PGRAPH_LIMIT_VIOL_PIX_LIMIT_VIOL              0x00000001 /* RW--V */
+#define NV_PGRAPH_LIMIT_VIOL_PIX_OVRFLW                       31:31 /* RWIVF */
+#define NV_PGRAPH_LIMIT_VIOL_PIX_OVRFLW_NO_VIOL          0x00000000 /* RWI-V */
+#define NV_PGRAPH_LIMIT_VIOL_PIX_OVRFLW_VIOL             0x00000001 /* RW--V */
+#define NV_PGRAPH_LIMIT_VIOL_Z                           0x00400614 /* RW-4R */
+#define NV_PGRAPH_LIMIT_VIOL_Z_ADRS                            23:0 /* RWIVF */
+#define NV_PGRAPH_LIMIT_VIOL_Z_ADRS_0                    0x00000000 /* RWI-V */
+#define NV_PGRAPH_LIMIT_VIOL_Z_LIMIT                          30:30 /* RWIVF */
+#define NV_PGRAPH_LIMIT_VIOL_Z_LIMIT_NO_VIOL             0x00000000 /* RWI-V */
+#define NV_PGRAPH_LIMIT_VIOL_Z_LIMIT_VIOL                0x00000001 /* RW--V */
+#define NV_PGRAPH_LIMIT_VIOL_Z_OVRFLW                         31:31 /* RWIVF */
+#define NV_PGRAPH_LIMIT_VIOL_Z_OVRFLW_NO_VIOL            0x00000000 /* RWI-V */
+#define NV_PGRAPH_LIMIT_VIOL_Z_OVRFLW_VIOL               0x00000001 /* RW--V */
+#define NV_PGRAPH_STATE                                  0x00400710 /* RW-4R */
+#define NV_PGRAPH_STATE_BUFFER_0                                0:0 /* RWIVF */
+#define NV_PGRAPH_STATE_BUFFER_0_INVALID                 0x00000000 /* RWI-V */
+#define NV_PGRAPH_STATE_BUFFER_0_VALID                   0x00000001 /* RW--V */
+#define NV_PGRAPH_STATE_BUFFER_1                                1:1 /* RWIVF */
+#define NV_PGRAPH_STATE_BUFFER_1_INVALID                 0x00000000 /* RWI-V */
+#define NV_PGRAPH_STATE_BUFFER_1_VALID                   0x00000001 /* RW--V */
+#define NV_PGRAPH_STATE_BUFFER_2                                2:2 /* RWIVF */
+#define NV_PGRAPH_STATE_BUFFER_2_INVALID                 0x00000000 /* RWI-V */
+#define NV_PGRAPH_STATE_BUFFER_2_VALID                   0x00000001 /* RW--V */
+#define NV_PGRAPH_STATE_BUFFER_3                                3:3 /* RWIVF */
+#define NV_PGRAPH_STATE_BUFFER_3_INVALID                 0x00000000 /* RWI-V */
+#define NV_PGRAPH_STATE_BUFFER_3_VALID                   0x00000001 /* RW--V */
+#define NV_PGRAPH_STATE_BUFFER_4                                4:4 /* RWIVF */
+#define NV_PGRAPH_STATE_BUFFER_4_INVALID                 0x00000000 /* RWI-V */
+#define NV_PGRAPH_STATE_BUFFER_4_VALID                   0x00000001 /* RW--V */
+#define NV_PGRAPH_STATE_BUFFER_5                                5:5 /* RWIVF */
+#define NV_PGRAPH_STATE_BUFFER_5_INVALID                 0x00000000 /* RWI-V */
+#define NV_PGRAPH_STATE_BUFFER_5_VALID                   0x00000001 /* RW--V */
+#define NV_PGRAPH_STATE_PITCH_0                                 8:8 /* RWIVF */
+#define NV_PGRAPH_STATE_PITCH_0_INVALID                  0x00000000 /* RWI-V */
+#define NV_PGRAPH_STATE_PITCH_0_VALID                    0x00000001 /* RW--V */
+#define NV_PGRAPH_STATE_PITCH_1                                 9:9 /* RWIVF */
+#define NV_PGRAPH_STATE_PITCH_1_INVALID                  0x00000000 /* RWI-V */
+#define NV_PGRAPH_STATE_PITCH_1_VALID                    0x00000001 /* RW--V */
+#define NV_PGRAPH_STATE_PITCH_2                               10:10 /* RWIVF */
+#define NV_PGRAPH_STATE_PITCH_2_INVALID                  0x00000000 /* RWI-V */
+#define NV_PGRAPH_STATE_PITCH_2_VALID                    0x00000001 /* RW--V */
+#define NV_PGRAPH_STATE_PITCH_3                               11:11 /* RWIVF */
+#define NV_PGRAPH_STATE_PITCH_3_INVALID                  0x00000000 /* RWI-V */
+#define NV_PGRAPH_STATE_PITCH_3_VALID                    0x00000001 /* RW--V */
+#define NV_PGRAPH_STATE_PITCH_4                               12:12 /* RWIVF */
+#define NV_PGRAPH_STATE_PITCH_4_INVALID                  0x00000000 /* RWI-V */
+#define NV_PGRAPH_STATE_PITCH_4_VALID                    0x00000001 /* RW--V */
+#define NV_PGRAPH_STATE_CHROMA_COLOR                          16:16 /* RWIVF */
+#define NV_PGRAPH_STATE_CHROMA_COLOR_INVALID             0x00000000 /* RWI-V */
+#define NV_PGRAPH_STATE_CHROMA_COLOR_VALID               0x00000001 /* RW--V */
+#define NV_PGRAPH_STATE_CHROMA_COLORFMT                       17:17 /* RWIVF */
+#define NV_PGRAPH_STATE_CHROMA_COLORFMT_INVALID          0x00000000 /* RWI-V */
+#define NV_PGRAPH_STATE_CHROMA_COLORFMT_VALID            0x00000001 /* RW--V */
+#define NV_PGRAPH_STATE_CPATTERN_COLORFMT                     20:20 /* RWIVF */
+#define NV_PGRAPH_STATE_CPATTERN_COLORFMT_INVALID        0x00000000 /* RWI-V */
+#define NV_PGRAPH_STATE_CPATTERN_COLORFMT_VALID          0x00000001 /* RW--V */
+#define NV_PGRAPH_STATE_CPATTERN_MONOFMT                      21:21 /* RWIVF */
+#define NV_PGRAPH_STATE_CPATTERN_MONOFMT_INVALID         0x00000000 /* RWI-V */
+#define NV_PGRAPH_STATE_CPATTERN_MONOFMT_VALID           0x00000001 /* RW--V */
+#define NV_PGRAPH_STATE_CPATTERN_SELECT                       22:22 /* RWIVF */
+#define NV_PGRAPH_STATE_CPATTERN_SELECT_INVALID          0x00000000 /* RWI-V */
+#define NV_PGRAPH_STATE_CPATTERN_SELECT_VALID            0x00000001 /* RW--V */
+#define NV_PGRAPH_STATE_PATTERN_COLOR0                        24:24 /* RWIVF */
+#define NV_PGRAPH_STATE_PATTERN_COLOR0_INVALID           0x00000000 /* RWI-V */
+#define NV_PGRAPH_STATE_PATTERN_COLOR0_VALID             0x00000001 /* RW--V */
+#define NV_PGRAPH_STATE_PATTERN_COLOR1                        25:25 /* RWIVF */
+#define NV_PGRAPH_STATE_PATTERN_COLOR1_INVALID           0x00000000 /* RWI-V */
+#define NV_PGRAPH_STATE_PATTERN_COLOR1_VALID             0x00000001 /* RW--V */
+#define NV_PGRAPH_STATE_PATTERN_PATT0                         26:26 /* RWIVF */
+#define NV_PGRAPH_STATE_PATTERN_PATT0_INVALID            0x00000000 /* RWI-V */
+#define NV_PGRAPH_STATE_PATTERN_PATT0_VALID              0x00000001 /* RW--V */
+#define NV_PGRAPH_STATE_PATTERN_PATT1                         27:27 /* RWIVF */
+#define NV_PGRAPH_STATE_PATTERN_PATT1_INVALID            0x00000000 /* RWI-V */
+#define NV_PGRAPH_STATE_PATTERN_PATT1_VALID              0x00000001 /* RW--V */
+#define NV_PGRAPH_CACHE_INDEX                            0x00400728 /* RW-4R */
+#define NV_PGRAPH_CACHE_INDEX_BANK                              2:2 /* RWXVF */
+#define NV_PGRAPH_CACHE_INDEX_BANK_10                    0x00000000 /* RW--V */
+#define NV_PGRAPH_CACHE_INDEX_BANK_32                    0x00000001 /* RW--V */
+#define NV_PGRAPH_CACHE_INDEX_ADRS                             12:3 /* RWXVF */
+#define NV_PGRAPH_CACHE_INDEX_ADRS_0                     0x00000000 /* RW--V */
+#define NV_PGRAPH_CACHE_INDEX_ADRS_1024                  0x00000400 /* RW--V */
+#define NV_PGRAPH_CACHE_INDEX_OP                              14:13 /* RWXVF */
+#define NV_PGRAPH_CACHE_INDEX_OP_WR_CACHE                0x00000000 /* RW--V */
+#define NV_PGRAPH_CACHE_INDEX_OP_RD_CACHE                0x00000001 /* RW--V */
+#define NV_PGRAPH_CACHE_INDEX_OP_RD_INDEX                0x00000002 /* RW--V */
+#define NV_PGRAPH_CACHE_RAM                              0x0040072c /* RW-4R */
+#define NV_PGRAPH_CACHE_RAM_VALUE                              31:0 /* RWXVF */
+#define NV_PGRAPH_DMA_PITCH                              0x00400760 /* RW-4R */
+#define NV_PGRAPH_DMA_PITCH_S0                                 15:0 /* RWXSF */
+#define NV_PGRAPH_DMA_PITCH_S1                                31:16 /* RWXSF */
+#define NV_PGRAPH_DVD_COLORFMT                           0x00400764 /* RW-4R */
+#define NV_PGRAPH_DVD_COLORFMT_IMAGE                            5:0 /* RWNVF */
+#define NV_PGRAPH_DVD_COLORFMT_IMAGE_FORMAT_INVALID            0x00 /* RWN-V */
+#define NV_PGRAPH_DVD_COLORFMT_IMAGE_FORMAT_LE_V8YB8U8YA8      0x12 /* RW--V */
+#define NV_PGRAPH_DVD_COLORFMT_IMAGE_FORMAT_LE_YB8V8YA8U8      0x13 /* RW--V */
+#define NV_PGRAPH_DVD_COLORFMT_OVLY                             9:8 /* RWNVF */
+#define NV_PGRAPH_DVD_COLORFMT_OVLY_FORMAT_INVALID             0x00 /* RWN-V */
+#define NV_PGRAPH_DVD_COLORFMT_OVLY_FORMAT_LE_A8Y8U8V8         0x01 /* RW--V */
+#define NV_PGRAPH_DVD_COLORFMT_OVLY_FORMAT_LE_A4V6YB6A4U6YA6   0x02 /* RW--V */
+#define NV_PGRAPH_DVD_COLORFMT_OVLY_FORMAT_TRANSPARENT         0x03 /* RW--V */
+#define NV_PGRAPH_SCALED_FORMAT                          0x00400768 /* RW-4R */
+#define NV_PGRAPH_SCALED_FORMAT_ORIGIN                        17:16 /* RWIVF */
+#define NV_PGRAPH_SCALED_FORMAT_ORIGIN_INVALID           0x00000000 /* RWI-V */
+#define NV_PGRAPH_SCALED_FORMAT_ORIGIN_CENTER            0x00000001 /* RW--V */
+#define NV_PGRAPH_SCALED_FORMAT_ORIGIN_CORNER            0x00000002 /* RW--V */
+#define NV_PGRAPH_SCALED_FORMAT_INTERPOLATOR                  24:24 /* RWIVF */
+#define NV_PGRAPH_SCALED_FORMAT_INTERPOLATOR_ZOH         0x00000000 /* RWI-V */
+#define NV_PGRAPH_SCALED_FORMAT_INTERPOLATOR_FOH         0x00000001 /* RW--V */
+#define NV_PGRAPH_PATT_COLOR0                            0x00400800 /* RW-4R */
+#define NV_PGRAPH_PATT_COLOR0_VALUE                            31:0 /* RWXUF */
+#define NV_PGRAPH_PATT_COLOR1                            0x00400804 /* RW-4R */
+#define NV_PGRAPH_PATT_COLOR1_VALUE                            31:0 /* RWXUF */
+#define NV_PGRAPH_PATT_COLORRAM(i)               (0x00400900+(i)*4) /* R--4A */
+#define NV_PGRAPH_PATT_COLORRAM__SIZE_1                          64 /*       */
+#define NV_PGRAPH_PATT_COLORRAM_VALUE                          23:0 /* R--UF */
+#define NV_PGRAPH_PATTERN(i)                     (0x00400808+(i)*4) /* RW-4A */
+#define NV_PGRAPH_PATTERN__SIZE_1                                 2 /*       */
+#define NV_PGRAPH_PATTERN_BITMAP                               31:0 /* RWXVF */
+#define NV_PGRAPH_PATTERN_SHAPE                          0x00400810 /* RW-4R */
+#define NV_PGRAPH_PATTERN_SHAPE_VALUE                           1:0 /* RWXVF */
+#define NV_PGRAPH_PATTERN_SHAPE_VALUE_8X_8Y              0x00000000 /* RW--V */
+#define NV_PGRAPH_PATTERN_SHAPE_VALUE_64X_1Y             0x00000001 /* RW--V */
+#define NV_PGRAPH_PATTERN_SHAPE_VALUE_1X_64Y             0x00000002 /* RW--V */
+#define NV_PGRAPH_PATTERN_SHAPE_SELECT                          4:4 /* RWXVF */
+#define NV_PGRAPH_PATTERN_SHAPE_SELECT_2COLOR            0x00000000 /* RW--V */
+#define NV_PGRAPH_PATTERN_SHAPE_SELECT_FULLCOLOR         0x00000001 /* RW--V */
+#define NV_PGRAPH_MONO_COLOR0                            0x00400600 /* RW-4R */
+#define NV_PGRAPH_MONO_COLOR0_VALUE                            31:0 /* RWXUF */
+#define NV_PGRAPH_ROP3                                   0x00400604 /* RW-4R */
+#define NV_PGRAPH_ROP3_VALUE                                    7:0 /* RWXVF */
+#define NV_PGRAPH_CHROMA                                 0x00400814 /* RW-4R */
+#define NV_PGRAPH_CHROMA_VALUE                                 31:0 /* RWXUF */
+#define NV_PGRAPH_BETA_AND                               0x00400608 /* RW-4R */
+#define NV_PGRAPH_BETA_AND_VALUE_FRACTION                     30:23 /* RWXUF */
+#define NV_PGRAPH_BETA_PREMULT                           0x0040060c /* RW-4R */
+#define NV_PGRAPH_BETA_PREMULT_VALUE                           31:0 /* RWXUF */
+#define NV_PGRAPH_CONTROL0                               0x00400818 /* RW-4R */
+#define NV_PGRAPH_CONTROL1                               0x0040081c /* RW-4R */
+#define NV_PGRAPH_CONTROL2                               0x00400820 /* RW-4R */
+#define NV_PGRAPH_BLEND                                  0x00400824 /* RW-4R */
+#define NV_PGRAPH_DPRAM_INDEX                            0x00400828 /* RW-4R */
+#define NV_PGRAPH_DPRAM_INDEX_ADRS                              6:0 /* RWIVF */
+#define NV_PGRAPH_DPRAM_INDEX_ADRS_0                     0x00000000 /* RWI-V */
+#define NV_PGRAPH_DPRAM_INDEX_SELECT                           10:8 /* RWIVF */
+#define NV_PGRAPH_DPRAM_INDEX_SELECT_ADRS_0              0x00000000 /* RWI-V */
+#define NV_PGRAPH_DPRAM_INDEX_SELECT_ADRS_1              0x00000001 /* RW--V */
+#define NV_PGRAPH_DPRAM_INDEX_SELECT_DATA_0              0x00000002 /* RW--V */
+#define NV_PGRAPH_DPRAM_INDEX_SELECT_DATA_1              0x00000003 /* RW--V */
+#define NV_PGRAPH_DPRAM_INDEX_SELECT_WE_0                0x00000004 /* RW--V */
+#define NV_PGRAPH_DPRAM_INDEX_SELECT_WE_1                0x00000005 /* RW--V */
+#define NV_PGRAPH_DPRAM_INDEX_SELECT_ALPHA_0             0x00000006 /* RW--V */
+#define NV_PGRAPH_DPRAM_INDEX_SELECT_ALPHA_1             0x00000007 /* RW--V */
+#define NV_PGRAPH_DPRAM_DATA                             0x0040082c /* RW-4R */
+#define NV_PGRAPH_DPRAM_DATA_VALUE                             31:0 /* RWXVF */
+#define NV_PGRAPH_DPRAM_ADRS_0                           0x0040082c /* RW-4R */
+#define NV_PGRAPH_DPRAM_ADRS_0__ALIAS_1        NV_PGRAPH_DPRAM_DATA /*       */
+#define NV_PGRAPH_DPRAM_ADRS_0_VALUE                           19:0 /* RWXVF */
+#define NV_PGRAPH_DPRAM_ADRS_1                           0x0040082c /* RW-4R */
+#define NV_PGRAPH_DPRAM_ADRS_1__ALIAS_1        NV_PGRAPH_DPRAM_DATA /*       */
+#define NV_PGRAPH_DPRAM_ADRS_1_VALUE                           19:0 /* RWXVF */
+#define NV_PGRAPH_DPRAM_DATA_0                           0x0040082c /* RW-4R */
+#define NV_PGRAPH_DPRAM_DATA_0__ALIAS_1        NV_PGRAPH_DPRAM_DATA /*       */
+#define NV_PGRAPH_DPRAM_DATA_0_VALUE                           31:0 /* RWXVF */
+#define NV_PGRAPH_DPRAM_DATA_1                           0x0040082c /* RW-4R */
+#define NV_PGRAPH_DPRAM_DATA_1__ALIAS_1        NV_PGRAPH_DPRAM_DATA /*       */
+#define NV_PGRAPH_DPRAM_DATA_1_VALUE                           31:0 /* RWXVF */
+#define NV_PGRAPH_DPRAM_WE_0                             0x0040082c /* RW-4R */
+#define NV_PGRAPH_DPRAM_WE_0__ALIAS_1          NV_PGRAPH_DPRAM_DATA /*       */
+#define NV_PGRAPH_DPRAM_WE_0_VALUE                             23:0 /* RWXVF */
+#define NV_PGRAPH_DPRAM_WE_1                             0x0040082c /* RW-4R */
+#define NV_PGRAPH_DPRAM_WE_1__ALIAS_1          NV_PGRAPH_DPRAM_DATA /*       */
+#define NV_PGRAPH_DPRAM_WE_1_VALUE                             23:0 /* RWXVF */
+#define NV_PGRAPH_DPRAM_ALPHA_0                          0x0040082c /* RW-4R */
+#define NV_PGRAPH_DPRAM_ALPHA_0__ALIAS_1       NV_PGRAPH_DPRAM_DATA /*       */
+#define NV_PGRAPH_DPRAM_ALPHA_0_VALUE                          31:0 /* RWXVF */
+#define NV_PGRAPH_DPRAM_ALPHA_1                          0x0040082c /* RW-4R */
+#define NV_PGRAPH_DPRAM_ALPHA_1__ALIAS_1       NV_PGRAPH_DPRAM_DATA /*       */
+#define NV_PGRAPH_DPRAM_ALPHA_1_VALUE                          31:0 /* RWXVF */
+#define NV_PGRAPH_STORED_FMT                             0x00400830 /* RW-4R */
+#define NV_PGRAPH_STORED_FMT_MONO0                              5:0 /* RWXVF */
+#define NV_PGRAPH_STORED_FMT_PATT0                             13:8 /* RWXVF */
+#define NV_PGRAPH_STORED_FMT_PATT1                            21:16 /* RWXVF */
+#define NV_PGRAPH_STORED_FMT_CHROMA                           29:24 /* RWXVF */
+#define NV_PGRAPH_FORMATS                                0x00400618 /* RW-4R */
+#define NV_PGRAPH_FORMATS_ROP                                   2:0 /* R-XVF */
+#define NV_PGRAPH_FORMATS_ROP_Y8                         0x00000000 /* -W--V */
+#define NV_PGRAPH_FORMATS_ROP_RGB15                      0x00000001 /* -W--V */
+#define NV_PGRAPH_FORMATS_ROP_RGB16                      0x00000002 /* -W--V */
+#define NV_PGRAPH_FORMATS_ROP_Y16                        0x00000003 /* -W--V */
+#define NV_PGRAPH_FORMATS_ROP_INVALID                    0x00000004 /* -W--V */
+#define NV_PGRAPH_FORMATS_ROP_RGB24                      0x00000005 /* -W--V */
+#define NV_PGRAPH_FORMATS_ROP_RGB30                      0x00000006 /* -W--V */
+#define NV_PGRAPH_FORMATS_ROP_Y32                        0x00000007 /* -W--V */
+#define NV_PGRAPH_FORMATS_SRC                                   9:4 /* R-XVF */
+#define NV_PGRAPH_FORMATS_SRC_INVALID                    0x00000000 /* RW--V */
+#define NV_PGRAPH_FORMATS_SRC_LE_Y8                      0x00000001 /* RW--V */
+#define NV_PGRAPH_FORMATS_SRC_LE_X16A8Y8                 0x00000002 /* RW--V */
+#define NV_PGRAPH_FORMATS_SRC_LE_X24Y8                   0x00000003 /* RW--V */
+#define NV_PGRAPH_FORMATS_SRC_LE_A1R5G5B5                0x00000006 /* RW--V */
+#define NV_PGRAPH_FORMATS_SRC_LE_X1R5G5B5                0x00000007 /* RW--V */
+#define NV_PGRAPH_FORMATS_SRC_LE_X16A1R5G5B5             0x00000008 /* RW--V */
+#define NV_PGRAPH_FORMATS_SRC_LE_X17R5G5B5               0x00000009 /* RW--V */
+#define NV_PGRAPH_FORMATS_SRC_LE_R5G6B5                  0x0000000A /* RW--V */
+#define NV_PGRAPH_FORMATS_SRC_LE_A16R5G6B5               0x0000000B /* RW--V */
+#define NV_PGRAPH_FORMATS_SRC_LE_X16R5G6B5               0x0000000C /* RW--V */
+#define NV_PGRAPH_FORMATS_SRC_LE_A8R8G8B8                0x0000000D /* RW--V */
+#define NV_PGRAPH_FORMATS_SRC_LE_X8R8G8B8                0x0000000E /* RW--V */
+#define NV_PGRAPH_FORMATS_SRC_LE_Y16                     0x0000000F /* RW--V */
+#define NV_PGRAPH_FORMATS_SRC_LE_A16Y16                  0x00000010 /* RW--V */
+#define NV_PGRAPH_FORMATS_SRC_LE_X16Y16                  0x00000011 /* RW--V */
+#define NV_PGRAPH_FORMATS_SRC_LE_V8YB8U8YA8              0x00000012 /* RW--V */
+#define NV_PGRAPH_FORMATS_SRC_LE_YB8V8YA8U8              0x00000013 /* RW--V */
+#define NV_PGRAPH_FORMATS_SRC_LE_Y32                     0x00000014 /* RW--V */
+#define NV_PGRAPH_FORMATS_FB                                  15:12 /* R-XVF */
+#define NV_PGRAPH_FORMATS_FB_INVALID                     0x00000000 /* RWI-V */
+#define NV_PGRAPH_FORMATS_FB_Y8                          0x00000001 /* RW--V */
+#define NV_PGRAPH_FORMATS_FB_X1R5G5B5_Z1R5G5B5           0x00000002 /* RW--V */
+#define NV_PGRAPH_FORMATS_FB_X1R5G5B5_O1R5G5B5           0x00000003 /* RW--V */
+#define NV_PGRAPH_FORMATS_FB_A1R5G5B5                    0x00000004 /* RW--V */
+#define NV_PGRAPH_FORMATS_FB_R5G6B5                      0x00000005 /* RW--V */
+#define NV_PGRAPH_FORMATS_FB_Y16                         0x00000006 /* RW--V */
+#define NV_PGRAPH_FORMATS_FB_X8R8G8B8_Z8R8G8B8           0x00000007 /* RW--V */
+#define NV_PGRAPH_FORMATS_FB_X8R8G8B8_O1Z7R8G8B8         0x00000008 /* RW--V */
+#define NV_PGRAPH_FORMATS_FB_X1A7R8G8B8_Z1A7R8G8B8       0x00000009 /* RW--V */
+#define NV_PGRAPH_FORMATS_FB_X1A7R8G8B8_O1A7R8G8B8       0x0000000a /* RW--V */
+#define NV_PGRAPH_FORMATS_FB_X8R8G8B8_O8R8G8B8           0x0000000b /* RW--V */
+#define NV_PGRAPH_FORMATS_FB_A8R8G8B8                    0x0000000c /* RW--V */
+#define NV_PGRAPH_FORMATS_FB_Y32                         0x0000000d /* RW--V */
+#define NV_PGRAPH_FORMATS_FB_V8YB8U8YA8                  0x0000000e /* RW--V */
+#define NV_PGRAPH_FORMATS_FB_YB8V8YA8U8                  0x0000000f /* RW--V */ 
+#define NV_PGRAPH_ABS_X_RAM(i)                   (0x00400400+(i)*4) /* RW-4A */
+#define NV_PGRAPH_ABS_X_RAM__SIZE_1                              32 /*       */
+#define NV_PGRAPH_ABS_X_RAM_VALUE                              31:0 /* RWXUF */
+#define NV_PGRAPH_X_RAM_BPORT(i)                 (0x00400c00+(i)*4) /* R--4A */
+#define NV_PGRAPH_X_RAM_BPORT__SIZE_1                            32 /*       */
+#define NV_PGRAPH_X_RAM_BPORT_VALUE                            31:0 /* R--UF */
+#define NV_PGRAPH_ABS_Y_RAM(i)                   (0x00400480+(i)*4) /* RW-4A */
+#define NV_PGRAPH_ABS_Y_RAM__SIZE_1                              32 /*       */
+#define NV_PGRAPH_ABS_Y_RAM_VALUE                              31:0 /* RWXUF */
+#define NV_PGRAPH_Y_RAM_BPORT(i)                 (0x00400c80+(i)*4) /* R--4A */
+#define NV_PGRAPH_Y_RAM_BPORT__SIZE_1                            32 /*       */
+#define NV_PGRAPH_Y_RAM_BPORT_VALUE                            31:0 /* R--UF */
+#define NV_PGRAPH_XY_LOGIC_MISC0                         0x00400514 /* RW-4R */
+#define NV_PGRAPH_XY_LOGIC_MISC0_COUNTER                       17:0 /* RWBUF */
+#define NV_PGRAPH_XY_LOGIC_MISC0_COUNTER_0               0x00000000 /* RWB-V */
+#define NV_PGRAPH_XY_LOGIC_MISC0_DIMENSION                    20:20 /* RWVVF */
+#define NV_PGRAPH_XY_LOGIC_MISC0_DIMENSION_NONZERO       0x00000000 /* RWV-V */
+#define NV_PGRAPH_XY_LOGIC_MISC0_DIMENSION_ZERO          0x00000001 /* RW--V */
+#define NV_PGRAPH_XY_LOGIC_MISC0_INDEX                        31:28 /* RWBUF */
+#define NV_PGRAPH_XY_LOGIC_MISC0_INDEX_0                 0x00000000 /* RWB-V */
+#define NV_PGRAPH_XY_LOGIC_MISC1                         0x00400518 /* RW-4R */
+#define NV_PGRAPH_XY_LOGIC_MISC1_INITIAL                        0:0 /* RWNVF */
+#define NV_PGRAPH_XY_LOGIC_MISC1_INITIAL_NEEDED          0x00000000 /* RWN-V */
+#define NV_PGRAPH_XY_LOGIC_MISC1_INITIAL_DONE            0x00000001 /* RW--V */
+#define NV_PGRAPH_XY_LOGIC_MISC1_XTRACLIPX                      4:4 /* RWIVF */
+#define NV_PGRAPH_XY_LOGIC_MISC1_XTRACLIPX_NOTNULL       0x00000000 /* RWI-V */
+#define NV_PGRAPH_XY_LOGIC_MISC1_XTRACLIPX_NULL          0x00000001 /* RW--V */
+#define NV_PGRAPH_XY_LOGIC_MISC1_XTRACLIPY                      5:5 /* RWIVF */
+#define NV_PGRAPH_XY_LOGIC_MISC1_XTRACLIPY_NOTNULL       0x00000000 /* RWI-V */
+#define NV_PGRAPH_XY_LOGIC_MISC1_XTRACLIPY_NULL          0x00000001 /* RW--V */
+#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_XIMAX                    12:12 /* RWIVF */
+#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_XIMAX_UUMAX         0x00000000 /* RWI-V */
+#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_XIMAX_IMAGEMAX      0x00000001 /* RW--V */
+#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_YIMAX                    16:16 /* RWIVF */
+#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_YIMAX_UUMAX         0x00000000 /* RWI-V */
+#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_YIMAX_IMAGEMAX      0x00000001 /* RW--V */
+#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_XXTRA                    20:20 /* RWIVF */
+#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_XXTRA_CLIPMAX       0x00000000 /* RWI-V */
+#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_XXTRA_IMAGEMAX      0x00000001 /* RW--V */
+#define NV_PGRAPH_XY_LOGIC_MISC2                         0x0040051C /* RW-4R */
+#define NV_PGRAPH_XY_LOGIC_MISC2_HANDOFF                        0:0 /* RWIVF */
+#define NV_PGRAPH_XY_LOGIC_MISC2_HANDOFF_DISABLE         0x00000000 /* RWI-V */
+#define NV_PGRAPH_XY_LOGIC_MISC2_HANDOFF_ENABLE          0x00000001 /* RW--V */
+#define NV_PGRAPH_XY_LOGIC_MISC2_XTRACLIPX                      4:4 /* RWIVF */
+#define NV_PGRAPH_XY_LOGIC_MISC2_XTRACLIPX_NOTNULL       0x00000000 /* RWI-V */
+#define NV_PGRAPH_XY_LOGIC_MISC2_XTRACLIPX_NULL          0x00000001 /* RW--V */
+#define NV_PGRAPH_XY_LOGIC_MISC2_XTRACLIPY                      5:5 /* RWIVF */
+#define NV_PGRAPH_XY_LOGIC_MISC2_XTRACLIPY_NOTNULL       0x00000000 /* RWI-V */
+#define NV_PGRAPH_XY_LOGIC_MISC2_XTRACLIPY_NULL          0x00000001 /* RW--V */
+#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_XIMAX                    12:12 /* RWIVF */
+#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_XIMAX_UCMAX         0x00000000 /* RWI-V */
+#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_XIMAX_IMAGEMAX      0x00000001 /* RW--V */
+#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_YIMAX                    16:16 /* RWIVF */
+#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_YIMAX_UCMAX         0x00000000 /* RWI-V */
+#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_YIMAX_IMAGEMAX      0x00000001 /* RW--V */
+#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_XXTRA                    20:20 /* RWIVF */
+#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_XXTRA_CLIPMAX       0x00000000 /* RWI-V */
+#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_XXTRA_IMAGEMAX      0x00000001 /* RW--V */
+#define NV_PGRAPH_XY_LOGIC_MISC3                         0x00400520 /* RW-4R */
+#define NV_PGRAPH_XY_LOGIC_MISC3_WDIMY_EQ_0                     0:0 /* RWXVF */
+#define NV_PGRAPH_XY_LOGIC_MISC3_WDIMY_EQ_0_NULL         0x00000000 /* RW--V */
+#define NV_PGRAPH_XY_LOGIC_MISC3_WDIMY_EQ_0_TRUE         0x00000001 /* RW--V */
+#define NV_PGRAPH_XY_LOGIC_MISC3_RELOAD_WDIMY                   4:4 /* RWXVF */
+#define NV_PGRAPH_XY_LOGIC_MISC3_RELOAD_WDIMY_NULL       0x00000000 /* RW--V */
+#define NV_PGRAPH_XY_LOGIC_MISC3_RELOAD_WDIMY_TRUE       0x00000001 /* RW--V */
+#define NV_PGRAPH_XY_LOGIC_MISC3_RELOAD_WX                      8:8 /* RWIVF */
+#define NV_PGRAPH_XY_LOGIC_MISC3_RELOAD_WX_NULL          0x00000000 /* RWI-V */
+#define NV_PGRAPH_XY_LOGIC_MISC3_RELOAD_WX_TRUE          0x00000001 /* RW--V */
+#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_ALG                     12:12 /* RWIVF */
+#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_ALG_NULL           0x00000000 /* RWI-V */
+#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_ALG_TRUE           0x00000001 /* RW--V */
+#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_DIMX                    22:16 /* RWXUF */
+#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_DIMX_0             0x00000000 /* RW--V */
+#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_WDIMX                   30:24 /* RWXUF */
+#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_WDIMX_0            0x00000000 /* RW--V */
+#define NV_PGRAPH_X_MISC                                 0x00400500 /* RW-4R */
+#define NV_PGRAPH_X_MISC_BIT33_0                                0:0 /* RWNVF */
+#define NV_PGRAPH_X_MISC_BIT33_0_0                       0x00000000 /* RWN-V */
+#define NV_PGRAPH_X_MISC_BIT33_1                                1:1 /* RWNVF */
+#define NV_PGRAPH_X_MISC_BIT33_1_0                       0x00000000 /* RWN-V */
+#define NV_PGRAPH_X_MISC_BIT33_2                                2:2 /* RWNVF */
+#define NV_PGRAPH_X_MISC_BIT33_2_0                       0x00000000 /* RWN-V */
+#define NV_PGRAPH_X_MISC_BIT33_3                                3:3 /* RWNVF */
+#define NV_PGRAPH_X_MISC_BIT33_3_0                       0x00000000 /* RWN-V */
+#define NV_PGRAPH_X_MISC_RANGE_0                                4:4 /* RWNVF */
+#define NV_PGRAPH_X_MISC_RANGE_0_0                       0x00000000 /* RWN-V */
+#define NV_PGRAPH_X_MISC_RANGE_1                                5:5 /* RWNVF */
+#define NV_PGRAPH_X_MISC_RANGE_1_0                       0x00000000 /* RWN-V */
+#define NV_PGRAPH_X_MISC_RANGE_2                                6:6 /* RWNVF */
+#define NV_PGRAPH_X_MISC_RANGE_2_0                       0x00000000 /* RWN-V */
+#define NV_PGRAPH_X_MISC_RANGE_3                                7:7 /* RWNVF */
+#define NV_PGRAPH_X_MISC_RANGE_3_0                       0x00000000 /* RWN-V */
+#define NV_PGRAPH_X_MISC_ADDER_OUTPUT                         29:28 /* RWXVF */
+#define NV_PGRAPH_X_MISC_ADDER_OUTPUT_EQ_0               0x00000000 /* RW--V */
+#define NV_PGRAPH_X_MISC_ADDER_OUTPUT_LT_0               0x00000001 /* RW--V */
+#define NV_PGRAPH_X_MISC_ADDER_OUTPUT_GT_0               0x00000002 /* RW--V */
+#define NV_PGRAPH_Y_MISC                                 0x00400504 /* RW-4R */
+#define NV_PGRAPH_Y_MISC_BIT33_0                                0:0 /* RWNVF */
+#define NV_PGRAPH_Y_MISC_BIT33_0_0                       0x00000000 /* RWN-V */
+#define NV_PGRAPH_Y_MISC_BIT33_1                                1:1 /* RWNVF */
+#define NV_PGRAPH_Y_MISC_BIT33_1_0                       0x00000000 /* RWN-V */
+#define NV_PGRAPH_Y_MISC_BIT33_2                                2:2 /* RWNVF */
+#define NV_PGRAPH_Y_MISC_BIT33_2_0                       0x00000000 /* RWN-V */
+#define NV_PGRAPH_Y_MISC_BIT33_3                                3:3 /* RWNVF */
+#define NV_PGRAPH_Y_MISC_BIT33_3_0                       0x00000000 /* RWN-V */
+#define NV_PGRAPH_Y_MISC_RANGE_0                                4:4 /* RWNVF */
+#define NV_PGRAPH_Y_MISC_RANGE_0_0                       0x00000000 /* RWN-V */
+#define NV_PGRAPH_Y_MISC_RANGE_1                                5:5 /* RWNVF */
+#define NV_PGRAPH_Y_MISC_RANGE_1_0                       0x00000000 /* RWN-V */
+#define NV_PGRAPH_Y_MISC_RANGE_2                                6:6 /* RWNVF */
+#define NV_PGRAPH_Y_MISC_RANGE_2_0                       0x00000000 /* RWN-V */
+#define NV_PGRAPH_Y_MISC_RANGE_3                                7:7 /* RWNVF */
+#define NV_PGRAPH_Y_MISC_RANGE_3_0                       0x00000000 /* RWN-V */
+#define NV_PGRAPH_Y_MISC_ADDER_OUTPUT                         29:28 /* RWXVF */
+#define NV_PGRAPH_Y_MISC_ADDER_OUTPUT_EQ_0               0x00000000 /* RW--V */
+#define NV_PGRAPH_Y_MISC_ADDER_OUTPUT_LT_0               0x00000001 /* RW--V */
+#define NV_PGRAPH_Y_MISC_ADDER_OUTPUT_GT_0               0x00000002 /* RW--V */
+#define NV_PGRAPH_ABS_UCLIP_XMIN                         0x0040053C /* RW-4R */
+#define NV_PGRAPH_ABS_UCLIP_XMIN_VALUE                         15:0 /* RWXSF */
+#define NV_PGRAPH_ABS_UCLIP_XMAX                         0x00400544 /* RW-4R */
+#define NV_PGRAPH_ABS_UCLIP_XMAX_VALUE                         17:0 /* RWXSF */
+#define NV_PGRAPH_ABS_UCLIP_YMIN                         0x00400540 /* RW-4R */
+#define NV_PGRAPH_ABS_UCLIP_YMIN_VALUE                         15:0 /* RWXSF */
+#define NV_PGRAPH_ABS_UCLIP_YMAX                         0x00400548 /* RW-4R */
+#define NV_PGRAPH_ABS_UCLIP_YMAX_VALUE                         17:0 /* RWXSF */
+#define NV_PGRAPH_ABS_UCLIPA_XMIN                        0x00400560 /* RW-4R */
+#define NV_PGRAPH_ABS_UCLIPA_XMIN_VALUE                        15:0 /* RWXSF */
+#define NV_PGRAPH_ABS_UCLIPA_XMAX                        0x00400568 /* RW-4R */
+#define NV_PGRAPH_ABS_UCLIPA_XMAX_VALUE                        17:0 /* RWXSF */
+#define NV_PGRAPH_ABS_UCLIPA_YMIN                        0x00400564 /* RW-4R */
+#define NV_PGRAPH_ABS_UCLIPA_YMIN_VALUE                        15:0 /* RWXSF */
+#define NV_PGRAPH_ABS_UCLIPA_YMAX                        0x0040056C /* RW-4R */
+#define NV_PGRAPH_ABS_UCLIPA_YMAX_VALUE                        17:0 /* RWXSF */
+#define NV_PGRAPH_SOURCE_COLOR                           0x0040050C /* RW-4R */
+#define NV_PGRAPH_SOURCE_COLOR_VALUE                           31:0 /* RWNVF */
+#define NV_PGRAPH_SOURCE_COLOR_VALUE_0                   0x00000000 /* RWN-V */
+#define NV_PGRAPH_VALID1                                 0x00400508 /* RW-4R */
+#define NV_PGRAPH_VALID1_VLD                                   22:0 /* RWNVF */
+#define NV_PGRAPH_VALID1_VLD_0                           0x00000000 /* RWN-V */
+#define NV_PGRAPH_VALID1_CLIP_MIN                             28:28 /* RWIVF */
+#define NV_PGRAPH_VALID1_CLIP_MIN_NO_ERROR               0x00000000 /* RWI-V */
+#define NV_PGRAPH_VALID1_CLIP_MIN_ONLY                   0x00000001 /* RW--V */
+#define NV_PGRAPH_VALID1_CLIPA_MIN                            29:29 /* RWIVF */
+#define NV_PGRAPH_VALID1_CLIPA_MIN_NO_ERROR              0x00000000 /* RWI-V */
+#define NV_PGRAPH_VALID1_CLIPA_MIN_ONLY                  0x00000001 /* RW--V */
+#define NV_PGRAPH_VALID1_CLIP_MAX                             30:30 /* RWIVF */
+#define NV_PGRAPH_VALID1_CLIP_MAX_NO_ERROR               0x00000000 /* RWI-V */
+#define NV_PGRAPH_VALID1_CLIP_MAX_ONLY                   0x00000001 /* RW--V */
+#define NV_PGRAPH_VALID1_CLIPA_MAX                            31:31 /* RWIVF */
+#define NV_PGRAPH_VALID1_CLIPA_MAX_NO_ERROR              0x00000000 /* RWI-V */
+#define NV_PGRAPH_VALID1_CLIPA_MAX_ONLY                  0x00000001 /* RW--V */
+#define NV_PGRAPH_VALID2                                 0x00400578 /* RW-4R */
+#define NV_PGRAPH_VALID2_VLD2                                  28:0 /* RWNVF */
+#define NV_PGRAPH_VALID2_VLD2_0                          0x00000000 /* RWN-V */
+#define NV_PGRAPH_ABS_ICLIP_XMAX                         0x00400534 /* RW-4R */
+#define NV_PGRAPH_ABS_ICLIP_XMAX_VALUE                         17:0 /* RWXSF */
+#define NV_PGRAPH_ABS_ICLIP_YMAX                         0x00400538 /* RW-4R */
+#define NV_PGRAPH_ABS_ICLIP_YMAX_VALUE                         17:0 /* RWXSF */
+#define NV_PGRAPH_CLIPX_0                                0x00400524 /* RW-4R */
+#define NV_PGRAPH_CLIPX_0_CLIP0_MIN                             1:0 /* RWNVF */
+#define NV_PGRAPH_CLIPX_0_CLIP0_MIN_GT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP0_MIN_LT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_0_CLIP0_MIN_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP0_MAX                             3:2 /* RWNVF */
+#define NV_PGRAPH_CLIPX_0_CLIP0_MAX_LT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP0_MAX_GT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_0_CLIP0_MAX_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP1_MIN                             5:4 /* RWNVF */
+#define NV_PGRAPH_CLIPX_0_CLIP1_MIN_GT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP1_MIN_LT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_0_CLIP1_MIN_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP1_MAX                             7:6 /* RWNVF */
+#define NV_PGRAPH_CLIPX_0_CLIP1_MAX_LT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP1_MAX_GT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_0_CLIP1_MAX_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP2_MIN                             9:8 /* RWNVF */
+#define NV_PGRAPH_CLIPX_0_CLIP2_MIN_GT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP2_MIN_LT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_0_CLIP2_MIN_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP2_MAX                           11:10 /* RWNVF */
+#define NV_PGRAPH_CLIPX_0_CLIP2_MAX_LT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP2_MAX_GT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_0_CLIP2_MAX_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP3_MIN                           13:12 /* RWNVF */
+#define NV_PGRAPH_CLIPX_0_CLIP3_MIN_GT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP3_MIN_LT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_0_CLIP3_MIN_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP3_MAX                           15:14 /* RWNVF */
+#define NV_PGRAPH_CLIPX_0_CLIP3_MAX_LT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP3_MAX_GT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_0_CLIP3_MAX_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP4_MIN                           17:16 /* RWNVF */
+#define NV_PGRAPH_CLIPX_0_CLIP4_MIN_GT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP4_MIN_LT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_0_CLIP4_MIN_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP4_MAX                           19:18 /* RWNVF */
+#define NV_PGRAPH_CLIPX_0_CLIP4_MAX_LT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP4_MAX_GT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_0_CLIP4_MAX_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP5_MIN                           21:20 /* RWNVF */
+#define NV_PGRAPH_CLIPX_0_CLIP5_MIN_GT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP5_MIN_LT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_0_CLIP5_MIN_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP5_MAX                           23:22 /* RWNVF */
+#define NV_PGRAPH_CLIPX_0_CLIP5_MAX_LT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP5_MAX_GT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_0_CLIP5_MAX_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP6_MIN                           25:24 /* RWNVF */
+#define NV_PGRAPH_CLIPX_0_CLIP6_MIN_GT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP6_MIN_LT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_0_CLIP6_MIN_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP6_MAX                           27:26 /* RWNVF */
+#define NV_PGRAPH_CLIPX_0_CLIP6_MAX_LT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP6_MAX_GT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_0_CLIP6_MAX_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP7_MIN                           29:28 /* RWNVF */
+#define NV_PGRAPH_CLIPX_0_CLIP7_MIN_GT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP7_MIN_LT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_0_CLIP7_MIN_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP7_MAX                           31:30 /* RWNVF */
+#define NV_PGRAPH_CLIPX_0_CLIP7_MAX_LT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_0_CLIP7_MAX_GT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_0_CLIP7_MAX_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_1                                0x00400528 /* RW-4R */
+#define NV_PGRAPH_CLIPX_1_CLIP8_MIN                             1:0 /* RWNVF */
+#define NV_PGRAPH_CLIPX_1_CLIP8_MIN_GT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP8_MIN_LT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_1_CLIP8_MIN_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP8_MAX                             3:2 /* RWNVF */
+#define NV_PGRAPH_CLIPX_1_CLIP8_MAX_LT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP8_MAX_GT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_1_CLIP8_MAX_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP9_MIN                             5:4 /* RWNVF */
+#define NV_PGRAPH_CLIPX_1_CLIP9_MIN_GT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP9_MIN_LT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_1_CLIP9_MIN_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP9_MAX                             7:6 /* RWNVF */
+#define NV_PGRAPH_CLIPX_1_CLIP9_MAX_LT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP9_MAX_GT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_1_CLIP9_MAX_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP10_MIN                            9:8 /* RWNVF */
+#define NV_PGRAPH_CLIPX_1_CLIP10_MIN_GT                  0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP10_MIN_LT                  0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_1_CLIP10_MIN_EQ                  0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP10_MAX                          11:10 /* RWNVF */
+#define NV_PGRAPH_CLIPX_1_CLIP10_MAX_LT                  0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP10_MAX_GT                  0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_1_CLIP10_MAX_EQ                  0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP11_MIN                          13:12 /* RWNVF */
+#define NV_PGRAPH_CLIPX_1_CLIP11_MIN_GT                  0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP11_MIN_LT                  0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_1_CLIP11MIN_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP11_MAX                          15:14 /* RWNVF */
+#define NV_PGRAPH_CLIPX_1_CLIP11_MAX_LT                  0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP11_MAX_GT                  0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_1_CLIP11_MAX_EQ                  0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP12_MIN                          17:16 /* RWNVF */
+#define NV_PGRAPH_CLIPX_1_CLIP12_MIN_GT                  0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP12_MIN_LT                  0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_1_CLIP12_MIN_EQ                  0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP12_MAX                          19:18 /* RWNVF */
+#define NV_PGRAPH_CLIPX_1_CLIP12_MAX_LT                  0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP12_MAX_GT                  0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_1_CLIP12_MAX_EQ                  0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP13_MIN                          21:20 /* RWNVF */
+#define NV_PGRAPH_CLIPX_1_CLIP13_MIN_GT                  0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP13_MIN_LT                  0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_1_CLIP13_MIN_EQ                  0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP13_MAX                          23:22 /* RWNVF */
+#define NV_PGRAPH_CLIPX_1_CLIP13_MAX_LT                  0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP13_MAX_GT                  0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_1_CLIP13_MAX_EQ                  0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP14_MIN                          25:24 /* RWNVF */
+#define NV_PGRAPH_CLIPX_1_CLIP14_MIN_GT                  0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP14_MIN_LT                  0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_1_CLIP14_MIN_EQ                  0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP14_MAX                          27:26 /* RWNVF */
+#define NV_PGRAPH_CLIPX_1_CLIP14_MAX_LT                  0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP14_MAX_GT                  0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_1_CLIP14_MAX_EQ                  0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP15_MIN                          29:28 /* RWNVF */
+#define NV_PGRAPH_CLIPX_1_CLIP15_MIN_GT                  0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP15_MIN_LT                  0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_1_CLIP15_MIN_EQ                  0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP15_MAX                          31:30 /* RWNVF */
+#define NV_PGRAPH_CLIPX_1_CLIP15_MAX_LT                  0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPX_1_CLIP15_MAX_GT                  0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPX_1_CLIP15_MAX_EQ                  0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_0                                0x0040052c /* RW-4R */
+#define NV_PGRAPH_CLIPY_0_CLIP0_MIN                             1:0 /* RWNVF */
+#define NV_PGRAPH_CLIPY_0_CLIP0_MIN_GT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP0_MIN_LT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_0_CLIP0_MIN_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP0_MAX                             3:2 /* RWNVF */
+#define NV_PGRAPH_CLIPY_0_CLIP0_MAX_LT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP0_MAX_GT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_0_CLIP0_MAX_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP1_MIN                             5:4 /* RWNVF */
+#define NV_PGRAPH_CLIPY_0_CLIP1_MIN_GT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP1_MIN_LT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_0_CLIP1_MIN_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP1_MAX                             7:6 /* RWNVF */
+#define NV_PGRAPH_CLIPY_0_CLIP1_MAX_LT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP1_MAX_GT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_0_CLIP1_MAX_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP2_MIN                             9:8 /* RWNVF */
+#define NV_PGRAPH_CLIPY_0_CLIP2_MIN_GT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP2_MIN_LT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_0_CLIP2_MIN_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP2_MAX                           11:10 /* RWNVF */
+#define NV_PGRAPH_CLIPY_0_CLIP2_MAX_LT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP2_MAX_GT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_0_CLIP2_MAX_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP3_MIN                           13:12 /* RWNVF */
+#define NV_PGRAPH_CLIPY_0_CLIP3_MIN_GT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP3_MIN_LT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_0_CLIP3_MIN_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP3_MAX                           15:14 /* RWNVF */
+#define NV_PGRAPH_CLIPY_0_CLIP3_MAX_LT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP3_MAX_GT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_0_CLIP3_MAX_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP4_MIN                           17:16 /* RWNVF */
+#define NV_PGRAPH_CLIPY_0_CLIP4_MIN_GT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP4_MIN_LT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_0_CLIP4_MIN_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP4_MAX                           19:18 /* RWNVF */
+#define NV_PGRAPH_CLIPY_0_CLIP4_MAX_LT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP4_MAX_GT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_0_CLIP4_MAX_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP5_MIN                           21:20 /* RWNVF */
+#define NV_PGRAPH_CLIPY_0_CLIP5_MIN_GT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP5_MIN_LT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_0_CLIP5_MIN_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP5_MAX                           23:22 /* RWNVF */
+#define NV_PGRAPH_CLIPY_0_CLIP5_MAX_LT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP5_MAX_GT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_0_CLIP5_MAX_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP6_MIN                           25:24 /* RWNVF */
+#define NV_PGRAPH_CLIPY_0_CLIP6_MIN_GT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP6_MIN_LT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_0_CLIP6_MIN_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP6_MAX                           27:26 /* RWNVF */
+#define NV_PGRAPH_CLIPY_0_CLIP6_MAX_LT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP6_MAX_GT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_0_CLIP6_MAX_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP7_MIN                           29:28 /* RWNVF */
+#define NV_PGRAPH_CLIPY_0_CLIP7_MIN_GT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP7_MIN_LT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_0_CLIP7_MIN_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP7_MAX                           31:30 /* RWNVF */
+#define NV_PGRAPH_CLIPY_0_CLIP7_MAX_LT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_0_CLIP7_MAX_GT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_0_CLIP7_MAX_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_1                                0x00400530 /* RW-4R */
+#define NV_PGRAPH_CLIPY_1_CLIP8_MIN                             1:0 /* RWNVF */
+#define NV_PGRAPH_CLIPY_1_CLIP8_MIN_GT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP8_MIN_LT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_1_CLIP8_MIN_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP8_MAX                             3:2 /* RWNVF */
+#define NV_PGRAPH_CLIPY_1_CLIP8_MAX_LT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP8_MAX_GT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_1_CLIP8_MAX_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP9_MIN                             5:4 /* RWNVF */
+#define NV_PGRAPH_CLIPY_1_CLIP9_MIN_GT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP9_MIN_LT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_1_CLIP9_MIN_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP9_MAX                             7:6 /* RWNVF */
+#define NV_PGRAPH_CLIPY_1_CLIP9_MAX_LT                   0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP9_MAX_GT                   0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_1_CLIP9_MAX_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP10_MIN                            9:8 /* RWNVF */
+#define NV_PGRAPH_CLIPY_1_CLIP10_MIN_GT                  0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP10_MIN_LT                  0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_1_CLIP10_MIN_EQ                  0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP10_MAX                          11:10 /* RWNVF */
+#define NV_PGRAPH_CLIPY_1_CLIP10_MAX_LT                  0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP10_MAX_GT                  0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_1_CLIP10_MAX_EQ                  0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP11_MIN                          13:12 /* RWNVF */
+#define NV_PGRAPH_CLIPY_1_CLIP11_MIN_GT                  0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP11_MIN_LT                  0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_1_CLIP11MIN_EQ                   0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP11_MAX                          15:14 /* RWNVF */
+#define NV_PGRAPH_CLIPY_1_CLIP11_MAX_LT                  0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP11_MAX_GT                  0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_1_CLIP11_MAX_EQ                  0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP12_MIN                          17:16 /* RWNVF */
+#define NV_PGRAPH_CLIPY_1_CLIP12_MIN_GT                  0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP12_MIN_LT                  0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_1_CLIP12_MIN_EQ                  0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP12_MAX                          19:18 /* RWNVF */
+#define NV_PGRAPH_CLIPY_1_CLIP12_MAX_LT                  0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP12_MAX_GT                  0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_1_CLIP12_MAX_EQ                  0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP13_MIN                          21:20 /* RWNVF */
+#define NV_PGRAPH_CLIPY_1_CLIP13_MIN_GT                  0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP13_MIN_LT                  0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_1_CLIP13_MIN_EQ                  0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP13_MAX                          23:22 /* RWNVF */
+#define NV_PGRAPH_CLIPY_1_CLIP13_MAX_LT                  0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP13_MAX_GT                  0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_1_CLIP13_MAX_EQ                  0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP14_MIN                          25:24 /* RWNVF */
+#define NV_PGRAPH_CLIPY_1_CLIP14_MIN_GT                  0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP14_MIN_LT                  0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_1_CLIP14_MIN_EQ                  0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP14_MAX                          27:26 /* RWNVF */
+#define NV_PGRAPH_CLIPY_1_CLIP14_MAX_LT                  0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP14_MAX_GT                  0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_1_CLIP14_MAX_EQ                  0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP15_MIN                          29:28 /* RWNVF */
+#define NV_PGRAPH_CLIPY_1_CLIP15_MIN_GT                  0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP15_MIN_LT                  0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_1_CLIP15_MIN_EQ                  0x00000002 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP15_MAX                          31:30 /* RWNVF */
+#define NV_PGRAPH_CLIPY_1_CLIP15_MAX_LT                  0x00000000 /* RW--V */
+#define NV_PGRAPH_CLIPY_1_CLIP15_MAX_GT                  0x00000001 /* RWN-V */
+#define NV_PGRAPH_CLIPY_1_CLIP15_MAX_EQ                  0x00000002 /* RW--V */
+#define NV_PGRAPH_MISC24_0                               0x00400510 /* RW-4R */
+#define NV_PGRAPH_MISC24_0_VALUE                               23:0 /* RWXUF */
+#define NV_PGRAPH_MISC24_1                               0x00400570 /* RW-4R */
+#define NV_PGRAPH_MISC24_1_VALUE                               23:0 /* RWXUF */
+#define NV_PGRAPH_MISC24_2                               0x00400574 /* RW-4R */
+#define NV_PGRAPH_MISC24_2_VALUE                               23:0 /* RWXUF */
+#define NV_PGRAPH_PASSTHRU_0                             0x0040057C /* RW-4R */
+#define NV_PGRAPH_PASSTHRU_0_VALUE                             31:0 /* RWXUF */
+#define NV_PGRAPH_PASSTHRU_1                             0x00400580 /* RW-4R */
+#define NV_PGRAPH_PASSTHRU_1_VALUE                             31:0 /* RWXUF */
+#define NV_PGRAPH_PASSTHRU_2                             0x00400584 /* RW-4R */
+#define NV_PGRAPH_PASSTHRU_2_VALUE                             31:0 /* RWXUF */
+#define NV_PGRAPH_U_RAM(i)                       (0x00400d00+(i)*4) /* RW-4A */
+#define NV_PGRAPH_U_RAM__SIZE_1                                  16 /*       */
+#define NV_PGRAPH_U_RAM_VALUE                                  31:6 /* RWXFF */
+#define NV_PGRAPH_V_RAM(i)                       (0x00400d40+(i)*4) /* RW-4A */
+#define NV_PGRAPH_V_RAM__SIZE_1                                  16 /*       */
+#define NV_PGRAPH_V_RAM_VALUE                                  31:6 /* RWXFF */
+#define NV_PGRAPH_M_RAM(i)                       (0x00400d80+(i)*4) /* RW-4A */
+#define NV_PGRAPH_M_RAM__SIZE_1                                  16 /*       */
+#define NV_PGRAPH_M_RAM_VALUE                                  31:6 /* RWXFF */
+#define NV_PGRAPH_DMA_START_0                            0x00401000 /* RW-4R */
+#define NV_PGRAPH_DMA_START_0_VALUE                            31:0 /* RWXUF */
+#define NV_PGRAPH_DMA_START_1                            0x00401004 /* RW-4R */
+#define NV_PGRAPH_DMA_START_1_VALUE                            31:0 /* RWXUF */
+#define NV_PGRAPH_DMA_LENGTH                             0x00401008 /* RW-4R */
+#define NV_PGRAPH_DMA_LENGTH_VALUE                             21:0 /* RWXUF */
+#define NV_PGRAPH_DMA_MISC                               0x0040100C /* RW-4R */
+#define NV_PGRAPH_DMA_MISC_COUNT                               15:0 /* RWXUF */
+#define NV_PGRAPH_DMA_MISC_FMT_SRC                            18:16 /* RWXVF */
+#define NV_PGRAPH_DMA_MISC_FMT_DST                            22:20 /* RWXVF */
+#define NV_PGRAPH_DMA_DATA_0                             0x00401020 /* RW-4R */
+#define NV_PGRAPH_DMA_DATA_0_VALUE                             31:0 /* RWXUF */
+#define NV_PGRAPH_DMA_DATA_1                             0x00401024 /* RW-4R */
+#define NV_PGRAPH_DMA_DATA_1_VALUE                             31:0 /* RWXUF */
+#define NV_PGRAPH_DMA_RM                                 0x00401030 /* RW-4R */
+#define NV_PGRAPH_DMA_RM_ASSIST_A                               0:0 /* RWIVF */
+#define NV_PGRAPH_DMA_RM_ASSIST_A_NOT_PENDING            0x00000000 /* R-I-V */
+#define NV_PGRAPH_DMA_RM_ASSIST_A_PENDING                0x00000001 /* R---V */
+#define NV_PGRAPH_DMA_RM_ASSIST_A_RESET                  0x00000001 /* -W--C */
+#define NV_PGRAPH_DMA_RM_ASSIST_B                               1:1 /* RWIVF */
+#define NV_PGRAPH_DMA_RM_ASSIST_B_NOT_PENDING            0x00000000 /* R-I-V */
+#define NV_PGRAPH_DMA_RM_ASSIST_B_PENDING                0x00000001 /* R---V */
+#define NV_PGRAPH_DMA_RM_ASSIST_B_RESET                  0x00000001 /* -W--C */
+#define NV_PGRAPH_DMA_RM_WRITE_REQ                              4:4 /* CWIVF */
+#define NV_PGRAPH_DMA_RM_WRITE_REQ_NOT_PENDING           0x00000000 /* CWI-V */
+#define NV_PGRAPH_DMA_RM_WRITE_REQ_PENDING               0x00000001 /* -W--T */
+#define NV_PGRAPH_DMA_A_XLATE_INST                       0x00401040 /* RW-4R */
+#define NV_PGRAPH_DMA_A_XLATE_INST_VALUE                       15:0 /* RWXUF */
+#define NV_PGRAPH_DMA_A_CONTROL                          0x00401044 /* RW-4R */
+#define NV_PGRAPH_DMA_A_CONTROL_PAGE_TABLE                    12:12 /* RWIVF */
+#define NV_PGRAPH_DMA_A_CONTROL_PAGE_TABLE_NOT_PRESENT   0x00000000 /* RWI-V */
+#define NV_PGRAPH_DMA_A_CONTROL_PAGE_TABLE_PRESENT       0x00000001 /* RW--V */
+#define NV_PGRAPH_DMA_A_CONTROL_PAGE_ENTRY                    13:13 /* RWXVF */
+#define NV_PGRAPH_DMA_A_CONTROL_PAGE_ENTRY_NOT_LINEAR    0x00000000 /* RW--V */
+#define NV_PGRAPH_DMA_A_CONTROL_PAGE_ENTRY_LINEAR        0x00000001 /* RW--V */
+#define NV_PGRAPH_DMA_A_CONTROL_TARGET_NODE                   17:16 /* RWXUF */
+#define NV_PGRAPH_DMA_A_CONTROL_TARGET_NODE_NVM          0x00000000 /* RW--V */
+#define NV_PGRAPH_DMA_A_CONTROL_TARGET_NODE_PCI          0x00000002 /* RW--V */
+#define NV_PGRAPH_DMA_A_CONTROL_TARGET_NODE_AGP          0x00000003 /* RW--V */
+#define NV_PGRAPH_DMA_A_CONTROL_ADJUST                        31:20 /* RWXUF */
+#define NV_PGRAPH_DMA_A_LIMIT                            0x00401048 /* RW-4R */
+#define NV_PGRAPH_DMA_A_LIMIT_OFFSET                           31:0 /* RWXUF */
+#define NV_PGRAPH_DMA_A_TLB_PTE                          0x0040104C /* RW-4R */
+#define NV_PGRAPH_DMA_A_TLB_PTE_ACCESS                          1:1 /* RWXVF */
+#define NV_PGRAPH_DMA_A_TLB_PTE_ACCESS_READ_ONLY         0x00000000 /* RW--V */
+#define NV_PGRAPH_DMA_A_TLB_PTE_ACCESS_READ_WRITE        0x00000001 /* RW--V */
+#define NV_PGRAPH_DMA_A_TLB_PTE_FRAME_ADDRESS                 31:12 /* RWXUF */
+#define NV_PGRAPH_DMA_A_TLB_TAG                          0x00401050 /* RW-4R */
+#define NV_PGRAPH_DMA_A_TLB_TAG_ADDRESS                       31:12 /* RWXUF */
+#define NV_PGRAPH_DMA_A_ADJ_OFFSET                       0x00401054 /* RW-4R */
+#define NV_PGRAPH_DMA_A_ADJ_OFFSET_VALUE                       31:0 /* RWXUF */
+#define NV_PGRAPH_DMA_A_OFFSET                           0x00401058 /* RW-4R */
+#define NV_PGRAPH_DMA_A_OFFSET_VALUE                           31:0 /* RWXUF */
+#define NV_PGRAPH_DMA_A_SIZE                             0x0040105C /* RW-4R */
+#define NV_PGRAPH_DMA_A_SIZE_VALUE                             24:0 /* RWXUF */
+#define NV_PGRAPH_DMA_A_Y_SIZE                           0x00401060 /* RW-4R */
+#define NV_PGRAPH_DMA_A_Y_SIZE_VALUE                           10:0 /* RWXUF */
+#define NV_PGRAPH_DMA_B_XLATE_INST                       0x00401080 /* RW-4R */
+#define NV_PGRAPH_DMA_B_XLATE_INST_VALUE                       15:0 /* RWXUF */
+#define NV_PGRAPH_DMA_B_CONTROL                          0x00401084 /* RW-4R */
+#define NV_PGRAPH_DMA_B_CONTROL_PAGE_TABLE                    12:12 /* RWIVF */
+#define NV_PGRAPH_DMA_B_CONTROL_PAGE_TABLE_NOT_PRESENT   0x00000000 /* RWI-V */
+#define NV_PGRAPH_DMA_B_CONTROL_PAGE_TABLE_PRESENT       0x00000001 /* RW--V */
+#define NV_PGRAPH_DMA_B_CONTROL_PAGE_ENTRY                    13:13 /* RWXVF */
+#define NV_PGRAPH_DMA_B_CONTROL_PAGE_ENTRY_NOT_LINEAR    0x00000000 /* RW--V */
+#define NV_PGRAPH_DMA_B_CONTROL_PAGE_ENTRY_LINEAR        0x00000001 /* RW--V */
+#define NV_PGRAPH_DMA_B_CONTROL_TARGET_NODE                   17:16 /* RWXUF */
+#define NV_PGRAPH_DMA_B_CONTROL_TARGET_NODE_NVM          0x00000000 /* RW--V */
+#define NV_PGRAPH_DMA_B_CONTROL_TARGET_NODE_PCI          0x00000002 /* RW--V */
+#define NV_PGRAPH_DMA_B_CONTROL_TARGET_NODE_AGP          0x00000003 /* RW--V */
+#define NV_PGRAPH_DMA_B_CONTROL_ADJUST                        31:20 /* RWXUF */
+#define NV_PGRAPH_DMA_B_LIMIT                            0x00401088 /* RW-4R */
+#define NV_PGRAPH_DMA_B_LIMIT_OFFSET                           31:0 /* RWXUF */
+#define NV_PGRAPH_DMA_B_TLB_PTE                          0x0040108C /* RW-4R */
+#define NV_PGRAPH_DMA_B_TLB_PTE_ACCESS                          1:1 /* RWXVF */
+#define NV_PGRAPH_DMA_B_TLB_PTE_ACCESS_READ_ONLY         0x00000000 /* RW--V */
+#define NV_PGRAPH_DMA_B_TLB_PTE_ACCESS_READ_WRITE        0x00000001 /* RW--V */
+#define NV_PGRAPH_DMA_B_TLB_PTE_FRAME_ADDRESS                 31:12 /* RWXUF */
+#define NV_PGRAPH_DMA_B_TLB_TAG                          0x00401090 /* RW-4R */
+#define NV_PGRAPH_DMA_B_TLB_TAG_ADDRESS                       31:12 /* RWXUF */
+#define NV_PGRAPH_DMA_B_ADJ_OFFSET                       0x00401094 /* RW-4R */
+#define NV_PGRAPH_DMA_B_ADJ_OFFSET_VALUE                       31:0 /* RWXUF */
+#define NV_PGRAPH_DMA_B_OFFSET                           0x00401098 /* RW-4R */
+#define NV_PGRAPH_DMA_B_OFFSET_VALUE                           31:0 /* RWXUF */
+#define NV_PGRAPH_DMA_B_SIZE                             0x0040109C /* RW-4R */
+#define NV_PGRAPH_DMA_B_SIZE_VALUE                             24:0 /* RWXUF */
+#define NV_PGRAPH_DMA_B_Y_SIZE                           0x004010A0 /* RW-4R */
+#define NV_PGRAPH_DMA_B_Y_SIZE_VALUE                           10:0 /* RWXUF */
+
+/* Framebuffer registers */
+#define NV_PFB                                0x00100FFF:0x00100000 /* RW--D */
+#define NV_PFB_BOOT_0                                    0x00100000 /* RW-4R */
+#define NV_PFB_BOOT_0_RAM_AMOUNT                                1:0 /* RW-VF */
+#define NV_PFB_BOOT_0_RAM_AMOUNT_32MB                    0x00000000 /* RW--V */
+#define NV_PFB_BOOT_0_RAM_AMOUNT_4MB                     0x00000001 /* RW--V */
+#define NV_PFB_BOOT_0_RAM_AMOUNT_8MB                     0x00000002 /* RW--V */
+#define NV_PFB_BOOT_0_RAM_AMOUNT_16MB                    0x00000003 /* RW--V */
+#define NV_PFB_BOOT_0_RAM_WIDTH_128                             2:2 /* RW-VF */
+#define NV_PFB_BOOT_0_RAM_WIDTH_128_OFF                  0x00000000 /* RW--V */
+#define NV_PFB_BOOT_0_RAM_WIDTH_128_ON                   0x00000001 /* RW--V */
+#define NV_PFB_BOOT_0_RAM_TYPE                                  4:3 /* RW-VF */
+#define NV_PFB_BOOT_0_RAM_TYPE_256K                      0x00000000 /* RW--V */
+#define NV_PFB_BOOT_0_RAM_TYPE_512K_2BANK                0x00000001 /* RW--V */
+#define NV_PFB_BOOT_0_RAM_TYPE_512K_4BANK                0x00000002 /* RW--V */
+#define NV_PFB_BOOT_0_RAM_TYPE_1024K_2BANK               0x00000003 /* RW--V */
+#define NV_PFB_CONFIG_0                                  0x00100200 /* RW-4R */
+#define NV_PFB_CONFIG_0_TYPE                                   14:0 /* RWIVF */
+#define NV_PFB_CONFIG_0_TYPE_OLD1024_FIXED_8BPP          0x00000120 /* RW--V */
+#define NV_PFB_CONFIG_0_TYPE_OLD1024_FIXED_16BPP         0x00000220 /* RW--V */
+#define NV_PFB_CONFIG_0_TYPE_OLD1024_FIXED_32BPP         0x00000320 /* RW--V */
+#define NV_PFB_CONFIG_0_TYPE_OLD1024_VAR_8BPP            0x00004120 /* RW--V */
+#define NV_PFB_CONFIG_0_TYPE_OLD1024_VAR_16BPP           0x00004220 /* RW--V */
+#define NV_PFB_CONFIG_0_TYPE_OLD1024_VAR_32BPP           0x00004320 /* RW--V */
+#define NV_PFB_CONFIG_0_TYPE_TETRIS                      0x00002000 /* RW--V */
+#define NV_PFB_CONFIG_0_TYPE_NOTILING                    0x00001114 /* RWI-V */
+#define NV_PFB_CONFIG_0_TETRIS_MODE                           17:15 /* RWI-F */
+#define NV_PFB_CONFIG_0_TETRIS_MODE_PASS                 0x00000000 /* RWI-V */
+#define NV_PFB_CONFIG_0_TETRIS_MODE_1                    0x00000001 /* RW--V */
+#define NV_PFB_CONFIG_0_TETRIS_MODE_2                    0x00000002 /* RW--V */
+#define NV_PFB_CONFIG_0_TETRIS_MODE_3                    0x00000003 /* RW--V */
+#define NV_PFB_CONFIG_0_TETRIS_MODE_4                    0x00000004 /* RW--V */
+#define NV_PFB_CONFIG_0_TETRIS_MODE_5                    0x00000005 /* RW--V */
+#define NV_PFB_CONFIG_0_TETRIS_MODE_6                    0x00000006 /* RW--V */
+#define NV_PFB_CONFIG_0_TETRIS_MODE_7                    0x00000007 /* RW--V */
+#define NV_PFB_CONFIG_0_TETRIS_SHIFT                          19:18 /* RWI-F */
+#define NV_PFB_CONFIG_0_TETRIS_SHIFT_0                   0x00000000 /* RWI-V */
+#define NV_PFB_CONFIG_0_TETRIS_SHIFT_1                   0x00000001 /* RW--V */
+#define NV_PFB_CONFIG_0_TETRIS_SHIFT_2                   0x00000002 /* RW--V */
+#define NV_PFB_CONFIG_0_BANK_SWAP                             22:20 /* RWI-F */
+#define NV_PFB_CONFIG_0_BANK_SWAP_OFF                    0x00000000 /* RWI-V */
+#define NV_PFB_CONFIG_0_BANK_SWAP_1M                     0x00000001 /* RW--V */
+#define NV_PFB_CONFIG_0_BANK_SWAP_2M                     0x00000005 /* RW--V */
+#define NV_PFB_CONFIG_0_BANK_SWAP_4M                     0x00000007 /* RW--V */
+#define NV_PFB_CONFIG_0_UNUSED                                23:23 /* RW-VF */
+#define NV_PFB_CONFIG_0_SCRAMBLE_EN                           29:29 /* RWIVF */
+#define NV_PFB_CONFIG_0_SCRAMBLE_EN_INIT                 0x00000000 /* RW--V */
+#define NV_PFB_CONFIG_0_SCRAMBLE_ACTIVE                  0x00000001 /* RW--V */
+#define NV_PFB_CONFIG_0_PRAMIN_WR                             28:28 /* RWIVF */
+#define NV_PFB_CONFIG_0_PRAMIN_WR_INIT                   0x00000000 /* RW--V */
+#define NV_PFB_CONFIG_0_PRAMIN_WR_DISABLED               0x00000001 /* RW--V */
+#define NV_PFB_CONFIG_0_PRAMIN_WR_MASK                        27:24 /* RWIVF */
+#define NV_PFB_CONFIG_0_PRAMIN_WR_MASK_INIT              0x00000000 /* RWI-V */
+#define NV_PFB_CONFIG_0_PRAMIN_WR_MASK_CLEAR             0x0000000f /* RWI-V */
+#define NV_PFB_CONFIG_1                                  0x00100204 /* RW-4R */
+#define NV_PFB_RTL                                       0x00100300 /* RW-4R */
+#define NV_PFB_RTL_H                                            0:0 /* RWIUF */
+#define NV_PFB_RTL_H_DEFAULT                             0x00000000 /* RWI-V */
+#define NV_PFB_RTL_MC                                           1:1 /* RWIUF */
+#define NV_PFB_RTL_MC_DEFAULT                            0x00000000 /* RWI-V */
+#define NV_PFB_RTL_V                                            2:2 /* RWIUF */
+#define NV_PFB_RTL_V_DEFAULT                             0x00000000 /* RWI-V */
+#define NV_PFB_RTL_G                                            3:3 /* RWIUF */
+#define NV_PFB_RTL_G_DEFAULT                             0x00000000 /* RWI-V */
+#define NV_PFB_RTL_GB                                           4:4 /* RWIUF */
+#define NV_PFB_RTL_GB_DEFAULT                            0x00000000 /* RWI-V */
+#define NV_PFB_CONFIG_0_RESOLUTION                              5:0 /* RWIVF */
+#define NV_PFB_CONFIG_0_RESOLUTION_320_PIXELS            0x0000000a /* RW--V */
+#define NV_PFB_CONFIG_0_RESOLUTION_400_PIXELS            0x0000000d /* RW--V */
+#define NV_PFB_CONFIG_0_RESOLUTION_480_PIXELS            0x0000000f /* RW--V */
+#define NV_PFB_CONFIG_0_RESOLUTION_512_PIXELS            0x00000010 /* RW--V */
+#define NV_PFB_CONFIG_0_RESOLUTION_640_PIXELS            0x00000014 /* RW--V */
+#define NV_PFB_CONFIG_0_RESOLUTION_800_PIXELS            0x00000019 /* RW--V */
+#define NV_PFB_CONFIG_0_RESOLUTION_960_PIXELS            0x0000001e /* RW--V */
+#define NV_PFB_CONFIG_0_RESOLUTION_1024_PIXELS           0x00000020 /* RW--V */
+#define NV_PFB_CONFIG_0_RESOLUTION_1152_PIXELS           0x00000024 /* RW--V */
+#define NV_PFB_CONFIG_0_RESOLUTION_1280_PIXELS           0x00000028 /* RW--V */
+#define NV_PFB_CONFIG_0_RESOLUTION_1600_PIXELS           0x00000032 /* RW--V */
+#define NV_PFB_CONFIG_0_RESOLUTION_DEFAULT               0x00000014 /* RWI-V */
+#define NV_PFB_CONFIG_0_PIXEL_DEPTH                             9:8 /* RWIVF */
+#define NV_PFB_CONFIG_0_PIXEL_DEPTH_8_BITS               0x00000001 /* RW--V */
+#define NV_PFB_CONFIG_0_PIXEL_DEPTH_16_BITS              0x00000002 /* RW--V */
+#define NV_PFB_CONFIG_0_PIXEL_DEPTH_32_BITS              0x00000003 /* RW--V */
+#define NV_PFB_CONFIG_0_PIXEL_DEPTH_DEFAULT              0x00000001 /* RWI-V */
+#define NV_PFB_CONFIG_0_TILING                                12:12 /* RWIVF */
+#define NV_PFB_CONFIG_0_TILING_ENABLED                   0x00000000 /* RW--V */
+#define NV_PFB_CONFIG_0_TILING_DISABLED                  0x00000001 /* RWI-V */
+#define NV_PFB_CONFIG_1_SGRAM100                                3:3 /* RWIVF */
+#define NV_PFB_CONFIG_1_SGRAM100_ENABLED                 0x00000000 /* RWI-V */
+#define NV_PFB_CONFIG_1_SGRAM100_DISABLED                0x00000001 /* RW--V */
+#define NV_PFB_DEBUG_0_CKE_ALWAYSON                           29:29 /* RWIVF */
+#define NV_PFB_DEBUG_0_CKE_ALWAYSON_OFF                  0x00000000 /* RW--V */
+#define NV_PFB_DEBUG_0_CKE_ALWAYSON_ON                   0x00000001 /* RWI-V */
+
+#define NV_PEXTDEV                            0x00101FFF:0x00101000 /* RW--D */
+#define NV_PEXTDEV_BOOT_0                                0x00101000 /* R--4R */
+#define NV_PEXTDEV_BOOT_0_STRAP_BUS_SPEED                       0:0 /* R-XVF */
+#define NV_PEXTDEV_BOOT_0_STRAP_BUS_SPEED_33MHZ          0x00000000 /* R---V */
+#define NV_PEXTDEV_BOOT_0_STRAP_BUS_SPEED_66MHZ          0x00000001 /* R---V */
+#define NV_PEXTDEV_BOOT_0_STRAP_SUB_VENDOR                      1:1 /* R-XVF */
+#define NV_PEXTDEV_BOOT_0_STRAP_SUB_VENDOR_NO_BIOS       0x00000000 /* R---V */
+#define NV_PEXTDEV_BOOT_0_STRAP_SUB_VENDOR_BIOS          0x00000001 /* R---V */
+#define NV_PEXTDEV_BOOT_0_STRAP_RAM_TYPE                        3:2 /* R-XVF */
+#define NV_PEXTDEV_BOOT_0_STRAP_RAM_TYPE_SGRAM_256K      0x00000000 /* R---V */
+#define NV_PEXTDEV_BOOT_0_STRAP_RAM_TYPE_SGRAM_512K_2BANK 0x00000001 /* R---V */
+#define NV_PEXTDEV_BOOT_0_STRAP_RAM_TYPE_SGRAM_512K_4BANK 0x00000002 /* R---V */
+#define NV_PEXTDEV_BOOT_0_STRAP_RAM_TYPE_1024K_2BANK     0x00000003 /* R---V */
+#define NV_PEXTDEV_BOOT_0_STRAP_RAM_WIDTH                       4:4 /* R-XVF */
+#define NV_PEXTDEV_BOOT_0_STRAP_RAM_WIDTH_64             0x00000000 /* R---V */
+#define NV_PEXTDEV_BOOT_0_STRAP_RAM_WIDTH_128            0x00000001 /* R---V */
+#define NV_PEXTDEV_BOOT_0_STRAP_BUS_TYPE                        5:5 /* R-XVF */
+#define NV_PEXTDEV_BOOT_0_STRAP_BUS_TYPE_PCI             0x00000000 /* R---V */
+#define NV_PEXTDEV_BOOT_0_STRAP_BUS_TYPE_AGP             0x00000001 /* R---V */
+#define NV_PEXTDEV_BOOT_0_STRAP_CRYSTAL                         6:6 /* R-XVF */
+#define NV_PEXTDEV_BOOT_0_STRAP_CRYSTAL_13500K           0x00000000 /* R---V */
+#define NV_PEXTDEV_BOOT_0_STRAP_CRYSTAL_14318180         0x00000001 /* R---V */
+#define NV_PEXTDEV_BOOT_0_STRAP_TVMODE                          8:7 /* R-XVF */
+#define NV_PEXTDEV_BOOT_0_STRAP_TVMODE_SECAM             0x00000000 /* R---V */
+#define NV_PEXTDEV_BOOT_0_STRAP_TVMODE_NTSC              0x00000001 /* R---V */
+#define NV_PEXTDEV_BOOT_0_STRAP_TVMODE_PAL               0x00000002 /* R---V */
+#define NV_PEXTDEV_BOOT_0_STRAP_TVMODE_DISABLED          0x00000003 /* R---V */
+#define NV_PEXTDEV_BOOT_0_STRAP_OVERWRITE                     11:11 /* RWIVF */
+#define NV_PEXTDEV_BOOT_0_STRAP_OVERWRITE_DISABLED       0x00000000 /* RWI-V */
+#define NV_PEXTDEV_BOOT_0_STRAP_OVERWRITE_ENABLED        0x00000001 /* RW--V */
+
+/* Extras */
+#define NV_PRAMIN                             0x007FFFFF:0x00700000 /* RW--M */
+/*#define NV_PRAMIN                             0x00FFFFFF:0x00C00000*/
+#define NV_PNVM                               0x01FFFFFF:0x01000000 /* RW--M */
+/*#define NV_PNVM                               0x00BFFFFF:0x00800000*/
+#define NV_CHAN0                              0x0080ffff:0x00800000
+
+/* FIFO subchannels */
+#define NV_UROP                               0x43
+#define NV_UCHROMA                            0x57
+#define NV_UCLIP                              0x19
+#define NV_UPATT                              0x18
+#define NV_ULIN                               0x5C
+#define NV_UTRI                               0x5D
+#define NV_URECT                              0x5E
+#define NV_UBLIT                              0x5F
+#define NV_UGLYPH                             0x4B
+
+#endif /*__NV4REF_H__*/
+
diff --git a/drivers/video/riva/nv_driver.c b/drivers/video/riva/nv_driver.c
new file mode 100644
index 0000000..be630a0
--- /dev/null
+++ b/drivers/video/riva/nv_driver.c
@@ -0,0 +1,425 @@
+/* $XConsortium: nv_driver.c /main/3 1996/10/28 05:13:37 kaleb $ */
+/*
+ * Copyright 1996-1997  David J. McKay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * DAVID J. MCKAY BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * GPL licensing note -- nVidia is allowing a liberal interpretation of
+ * the documentation restriction above, to merely say that this nVidia's
+ * copyright and disclaimer should be included with all code derived
+ * from this source.  -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 
+ */
+
+/* Hacked together from mga driver and 3.3.4 NVIDIA driver by Jarno Paananen
+   <jpaana@s2.org> */
+
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/nv_setup.c,v 1.18 2002/08/0
+5 20:47:06 mvojkovi Exp $ */
+
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include "nv_type.h"
+#include "rivafb.h"
+#include "nvreg.h"
+
+
+#ifndef CONFIG_PCI		/* sanity check */
+#error This driver requires PCI support.
+#endif
+
+#define PFX "rivafb: "
+
+static inline unsigned char MISCin(struct riva_par *par)
+{
+	return (VGA_RD08(par->riva.PVIO, 0x3cc));
+}
+
+static Bool 
+riva_is_connected(struct riva_par *par, Bool second)
+{
+	volatile U032 __iomem *PRAMDAC = par->riva.PRAMDAC0;
+	U032 reg52C, reg608;
+	Bool present;
+
+	if(second) PRAMDAC += 0x800;
+
+	reg52C = NV_RD32(PRAMDAC, 0x052C);
+	reg608 = NV_RD32(PRAMDAC, 0x0608);
+
+	NV_WR32(PRAMDAC, 0x0608, reg608 & ~0x00010000);
+
+	NV_WR32(PRAMDAC, 0x052C, reg52C & 0x0000FEEE);
+	mdelay(1); 
+	NV_WR32(PRAMDAC, 0x052C, NV_RD32(PRAMDAC, 0x052C) | 1);
+
+	NV_WR32(par->riva.PRAMDAC0, 0x0610, 0x94050140);
+	NV_WR32(par->riva.PRAMDAC0, 0x0608, 0x00001000);
+
+	mdelay(1);
+
+	present = (NV_RD32(PRAMDAC, 0x0608) & (1 << 28)) ? TRUE : FALSE;
+
+	NV_WR32(par->riva.PRAMDAC0, 0x0608,
+		NV_RD32(par->riva.PRAMDAC0, 0x0608) & 0x0000EFFF);
+
+	NV_WR32(PRAMDAC, 0x052C, reg52C);
+	NV_WR32(PRAMDAC, 0x0608, reg608);
+
+	return present;
+}
+
+static void
+riva_override_CRTC(struct riva_par *par)
+{
+	printk(KERN_INFO PFX
+		"Detected CRTC controller %i being used\n",
+		par->SecondCRTC ? 1 : 0);
+
+	if(par->forceCRTC != -1) {
+		printk(KERN_INFO PFX
+			"Forcing usage of CRTC %i\n", par->forceCRTC);
+		par->SecondCRTC = par->forceCRTC;
+	}
+}
+
+static void
+riva_is_second(struct riva_par *par)
+{
+	if (par->FlatPanel == 1) {
+		switch(par->Chipset & 0xffff) {
+		case 0x0174:
+		case 0x0175:
+		case 0x0176:
+		case 0x0177:
+		case 0x0179:
+		case 0x017C:
+		case 0x017D:
+		case 0x0186:
+		case 0x0187:
+		/* this might not be a good default for the chips below */
+		case 0x0286:
+		case 0x028C:
+		case 0x0316:
+		case 0x0317:
+		case 0x031A:
+		case 0x031B:
+		case 0x031C:
+		case 0x031D:
+		case 0x031E:
+		case 0x031F:
+		case 0x0324:
+		case 0x0325:
+		case 0x0328:
+		case 0x0329:
+		case 0x032C:
+		case 0x032D:
+			par->SecondCRTC = TRUE;
+			break;
+		default:
+			par->SecondCRTC = FALSE;
+			break;
+		}
+	} else {
+		if(riva_is_connected(par, 0)) {
+
+			if (NV_RD32(par->riva.PRAMDAC0, 0x0000052C) & 0x100)
+				par->SecondCRTC = TRUE;
+			else
+				par->SecondCRTC = FALSE;
+		} else 
+		if (riva_is_connected(par, 1)) {
+			if(NV_RD32(par->riva.PRAMDAC0, 0x0000252C) & 0x100)
+				par->SecondCRTC = TRUE;
+			else
+				par->SecondCRTC = FALSE;
+		} else /* default */
+			par->SecondCRTC = FALSE;
+	}
+	riva_override_CRTC(par);
+}
+
+unsigned long riva_get_memlen(struct riva_par *par)
+{
+	RIVA_HW_INST *chip = &par->riva;
+	unsigned long memlen = 0;
+	unsigned int chipset = par->Chipset;
+	struct pci_dev* dev;
+	int amt;
+
+	switch (chip->Architecture) {
+	case NV_ARCH_03:
+		if (NV_RD32(chip->PFB, 0x00000000) & 0x00000020) {
+			if (((NV_RD32(chip->PMC, 0x00000000) & 0xF0) == 0x20)
+			    && ((NV_RD32(chip->PMC, 0x00000000)&0x0F)>=0x02)) {
+				/*
+				 * SDRAM 128 ZX.
+				 */
+				switch (NV_RD32(chip->PFB,0x00000000) & 0x03) {
+				case 2:
+					memlen = 1024 * 4;
+					break;
+				case 1:
+					memlen = 1024 * 2;
+					break;
+				default:
+					memlen = 1024 * 8;
+					break;
+				}
+			} else {
+				memlen = 1024 * 8;
+			}            
+		} else 	{
+			/*
+			 * SGRAM 128.
+			 */
+			switch (NV_RD32(chip->PFB, 0x00000000) & 0x00000003) {
+			case 0:
+				memlen = 1024 * 8;
+				break;
+			case 2:
+				memlen = 1024 * 4;
+				break;
+			default:
+				memlen = 1024 * 2;
+				break;
+			}
+		}        
+		break;
+	case NV_ARCH_04:
+		if (NV_RD32(chip->PFB, 0x00000000) & 0x00000100) {
+			memlen = ((NV_RD32(chip->PFB, 0x00000000)>>12)&0x0F) *
+				1024 * 2 + 1024 * 2;
+		} else {
+			switch (NV_RD32(chip->PFB, 0x00000000) & 0x00000003) {
+			case 0:
+				memlen = 1024 * 32;
+				break;
+			case 1:
+				memlen = 1024 * 4;
+				break;
+			case 2:
+				memlen = 1024 * 8;
+				break;
+			case 3:
+			default:
+				memlen = 1024 * 16;
+				break;
+			}
+		}
+		break;
+	case NV_ARCH_10:
+	case NV_ARCH_20:
+	case NV_ARCH_30:
+		if(chipset == NV_CHIP_IGEFORCE2) {
+
+			dev = pci_find_slot(0, 1);
+			pci_read_config_dword(dev, 0x7C, &amt);
+			memlen = (((amt >> 6) & 31) + 1) * 1024;
+		} else if (chipset == NV_CHIP_0x01F0) {
+			dev = pci_find_slot(0, 1);
+			pci_read_config_dword(dev, 0x84, &amt);
+			memlen = (((amt >> 4) & 127) + 1) * 1024;
+		} else {
+			switch ((NV_RD32(chip->PFB, 0x0000020C) >> 20) &
+				0x000000FF){
+			case 0x02:
+				memlen = 1024 * 2;
+				break;
+			case 0x04:
+				memlen = 1024 * 4;
+				break;
+			case 0x08:
+				memlen = 1024 * 8;
+				break;
+			case 0x10:
+				memlen = 1024 * 16;
+				break;
+			case 0x20:
+				memlen = 1024 * 32;
+				break;
+			case 0x40:
+				memlen = 1024 * 64;
+				break;
+			case 0x80:
+				memlen = 1024 * 128;
+				break;
+			default:
+				memlen = 1024 * 16;
+				break;
+			}
+		}
+		break;
+	}
+	return memlen;
+}
+
+unsigned long riva_get_maxdclk(struct riva_par *par)
+{
+	RIVA_HW_INST *chip = &par->riva;
+	unsigned long dclk = 0;
+
+	switch (chip->Architecture) {
+	case NV_ARCH_03:
+		if (NV_RD32(chip->PFB, 0x00000000) & 0x00000020) {
+			if (((NV_RD32(chip->PMC, 0x00000000) & 0xF0) == 0x20)
+			    && ((NV_RD32(chip->PMC,0x00000000)&0x0F) >= 0x02)) {
+				/*
+				 * SDRAM 128 ZX.
+				 */
+				dclk = 800000;
+			} else {
+				dclk = 1000000;
+			}            
+		} else {
+			/*
+			 * SGRAM 128.
+			 */
+			dclk = 1000000;
+		} 
+		break;
+	case NV_ARCH_04:
+	case NV_ARCH_10:
+	case NV_ARCH_20:
+	case NV_ARCH_30:
+		switch ((NV_RD32(chip->PFB, 0x00000000) >> 3) & 0x00000003) {
+		case 3:
+			dclk = 800000;
+			break;
+		default:
+			dclk = 1000000;
+			break;
+		}
+		break;
+	}
+	return dclk;
+}
+
+void
+riva_common_setup(struct riva_par *par)
+{
+	par->riva.EnableIRQ = 0;
+	par->riva.PRAMDAC0 =
+		(volatile U032 __iomem *)(par->ctrl_base + 0x00680000);
+	par->riva.PFB =
+		(volatile U032 __iomem *)(par->ctrl_base + 0x00100000);
+	par->riva.PFIFO =
+		(volatile U032 __iomem *)(par->ctrl_base + 0x00002000);
+	par->riva.PGRAPH =
+		(volatile U032 __iomem *)(par->ctrl_base + 0x00400000);
+	par->riva.PEXTDEV =
+		(volatile U032 __iomem *)(par->ctrl_base + 0x00101000);
+	par->riva.PTIMER =
+		(volatile U032 __iomem *)(par->ctrl_base + 0x00009000);
+	par->riva.PMC =
+		(volatile U032 __iomem *)(par->ctrl_base + 0x00000000);
+	par->riva.FIFO =
+		(volatile U032 __iomem *)(par->ctrl_base + 0x00800000);
+	par->riva.PCIO0 = par->ctrl_base + 0x00601000;
+	par->riva.PDIO0 = par->ctrl_base + 0x00681000;
+	par->riva.PVIO = par->ctrl_base + 0x000C0000;
+
+	par->riva.IO = (MISCin(par) & 0x01) ? 0x3D0 : 0x3B0;
+	
+	if (par->FlatPanel == -1) {
+		switch (par->Chipset & 0xffff) {
+		case 0x0112:   /* known laptop chips */
+		case 0x0174:
+		case 0x0175:
+		case 0x0176:
+		case 0x0177:
+		case 0x0179:
+		case 0x017C:
+		case 0x017D:
+		case 0x0186:
+		case 0x0187:
+		case 0x0286:
+		case 0x028C:
+		case 0x0316:
+		case 0x0317:
+		case 0x031A:
+		case 0x031B:
+		case 0x031C:
+		case 0x031D:
+		case 0x031E:
+		case 0x031F:
+		case 0x0324:
+		case 0x0325:
+		case 0x0328:
+		case 0x0329:
+		case 0x032C:
+		case 0x032D:
+			printk(KERN_INFO PFX 
+				"On a laptop.  Assuming Digital Flat Panel\n");
+			par->FlatPanel = 1;
+			break;
+		default:
+			break;
+		}
+	}
+	
+	switch (par->Chipset & 0x0ff0) {
+	case 0x0110:
+		if (par->Chipset == NV_CHIP_GEFORCE2_GO)
+			par->SecondCRTC = TRUE; 
+#if defined(__powerpc__)
+		if (par->FlatPanel == 1)
+			par->SecondCRTC = TRUE;
+#endif
+		riva_override_CRTC(par);
+		break;
+	case 0x0170:
+	case 0x0180:
+	case 0x01F0:
+	case 0x0250:
+	case 0x0280:
+	case 0x0300:
+	case 0x0310:
+	case 0x0320:
+	case 0x0330:
+	case 0x0340:
+		riva_is_second(par);
+		break;
+	default:
+		break;
+	}
+
+	if (par->SecondCRTC) {
+		par->riva.PCIO = par->riva.PCIO0 + 0x2000;
+		par->riva.PCRTC = par->riva.PCRTC0 + 0x800;
+		par->riva.PRAMDAC = par->riva.PRAMDAC0 + 0x800;
+		par->riva.PDIO = par->riva.PDIO0 + 0x2000;
+	} else {
+		par->riva.PCIO = par->riva.PCIO0;
+		par->riva.PCRTC = par->riva.PCRTC0;
+		par->riva.PRAMDAC = par->riva.PRAMDAC0;
+		par->riva.PDIO = par->riva.PDIO0;
+	}
+
+	if (par->FlatPanel == -1) {
+		/* Fix me, need x86 DDC code */
+		par->FlatPanel = 0;
+	}
+	par->riva.flatPanel = (par->FlatPanel > 0) ? TRUE : FALSE;
+
+	RivaGetConfig(&par->riva, par->Chipset);
+}
+
diff --git a/drivers/video/riva/nv_type.h b/drivers/video/riva/nv_type.h
new file mode 100644
index 0000000..a69480c
--- /dev/null
+++ b/drivers/video/riva/nv_type.h
@@ -0,0 +1,58 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/nv_type.h,v 1.35 2002/08/05 20:47:06 mvojkovi Exp $ */
+
+#ifndef __NV_STRUCT_H__
+#define __NV_STRUCT_H__
+
+#define NV_CHIP_RIVA_128            ((PCI_VENDOR_ID_NVIDIA_SGS << 16)| PCI_DEVICE_ID_NVIDIA_RIVA128)
+#define NV_CHIP_TNT                 ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_TNT)
+#define NV_CHIP_TNT2                ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_TNT2)
+#define NV_CHIP_UTNT2               ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_UTNT2)
+#define NV_CHIP_VTNT2               ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_VTNT2)
+#define NV_CHIP_UVTNT2              ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_UVTNT2)
+#define NV_CHIP_ITNT2               ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_ITNT2)
+#define NV_CHIP_GEFORCE_256         ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_GEFORCE_256)
+#define NV_CHIP_GEFORCE_DDR         ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR)
+#define NV_CHIP_QUADRO              ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_QUADRO)
+#define NV_CHIP_GEFORCE2_MX         ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX)
+#define NV_CHIP_GEFORCE2_MX_100     ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX_100)
+#define NV_CHIP_QUADRO2_MXR         ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR)
+#define NV_CHIP_GEFORCE2_GO         ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO)
+#define NV_CHIP_GEFORCE2_GTS        ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS)
+#define NV_CHIP_GEFORCE2_TI         ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE2_TI)
+#define NV_CHIP_GEFORCE2_ULTRA      ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA)
+#define NV_CHIP_QUADRO2_PRO         ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO)
+#define NV_CHIP_GEFORCE4_MX_460     ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460)
+#define NV_CHIP_GEFORCE4_MX_440     ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440)
+#define NV_CHIP_GEFORCE4_MX_420     ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420)
+#define NV_CHIP_GEFORCE4_440_GO     ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO)
+#define NV_CHIP_GEFORCE4_420_GO     ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO)
+#define NV_CHIP_GEFORCE4_420_GO_M32 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32)
+#define NV_CHIP_QUADRO4_500XGL      ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL)
+#define NV_CHIP_GEFORCE4_440_GO_M64 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64)
+#define NV_CHIP_QUADRO4_200         ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_200)
+#define NV_CHIP_QUADRO4_550XGL      ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL)
+#define NV_CHIP_QUADRO4_500_GOGL    ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL)
+#define NV_CHIP_0x0180              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0180)
+#define NV_CHIP_0x0181              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0181)
+#define NV_CHIP_0x0182              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0182)
+#define NV_CHIP_0x0188              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0188)
+#define NV_CHIP_0x018A              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x018A)
+#define NV_CHIP_0x018B              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x018B)
+#define NV_CHIP_IGEFORCE2           ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_IGEFORCE2)
+#define NV_CHIP_0x01F0              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x01F0)
+#define NV_CHIP_GEFORCE3            ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE3)
+#define NV_CHIP_GEFORCE3_TI_200     ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE3_TI_200)
+#define NV_CHIP_GEFORCE3_TI_500     ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE3_TI_500)
+#define NV_CHIP_QUADRO_DCC          ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO_DCC)
+#define NV_CHIP_GEFORCE4_TI_4600    ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600)
+#define NV_CHIP_GEFORCE4_TI_4400    ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400)
+#define NV_CHIP_GEFORCE4_TI_4200    ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200)
+#define NV_CHIP_QUADRO4_900XGL      ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL)
+#define NV_CHIP_QUADRO4_750XGL      ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL)
+#define NV_CHIP_QUADRO4_700XGL      ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL)
+#define NV_CHIP_0x0280              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0280)
+#define NV_CHIP_0x0281              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0281)
+#define NV_CHIP_0x0288              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0288)
+#define NV_CHIP_0x0289              ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0289)
+
+#endif /* __NV_STRUCT_H__ */
diff --git a/drivers/video/riva/nvreg.h b/drivers/video/riva/nvreg.h
new file mode 100644
index 0000000..abfc167
--- /dev/null
+++ b/drivers/video/riva/nvreg.h
@@ -0,0 +1,188 @@
+/* $XConsortium: nvreg.h /main/2 1996/10/28 05:13:41 kaleb $ */
+/*
+ * Copyright 1996-1997  David J. McKay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * DAVID J. MCKAY BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/nv/nvreg.h,v 3.2.2.1 1998/01/18 10:35:36 hohndel Exp $ */
+
+#ifndef __NVREG_H_
+#define __NVREG_H_
+
+/* Little macro to construct bitmask for contiguous ranges of bits */
+#define BITMASK(t,b) (((unsigned)(1U << (((t)-(b)+1)))-1)  << (b))
+#define MASKEXPAND(mask) BITMASK(1?mask,0?mask)
+
+/* Macro to set specific bitfields (mask has to be a macro x:y) ! */
+#define SetBF(mask,value) ((value) << (0?mask))
+#define GetBF(var,mask) (((unsigned)((var) & MASKEXPAND(mask))) >> (0?mask) )
+
+#define MaskAndSetBF(var,mask,value) (var)=(((var)&(~MASKEXPAND(mask)) \
+                                             | SetBF(mask,value)))
+
+#define DEVICE_BASE(device) (0?NV##_##device)
+#define DEVICE_SIZE(device) ((1?NV##_##device) - DEVICE_BASE(device)+1)
+
+/* This is where we will have to have conditional compilation */
+#define DEVICE_ACCESS(device,reg) \
+  nvCONTROL[(NV_##device##_##reg)/4]
+
+#define DEVICE_WRITE(device,reg,value) DEVICE_ACCESS(device,reg)=(value)
+#define DEVICE_READ(device,reg)        DEVICE_ACCESS(device,reg)
+#define DEVICE_PRINT(device,reg) \
+  ErrorF("NV_"#device"_"#reg"=#%08lx\n",DEVICE_ACCESS(device,reg))
+#define DEVICE_DEF(device,mask,value) \
+  SetBF(NV_##device##_##mask,NV_##device##_##mask##_##value)
+#define DEVICE_VALUE(device,mask,value) SetBF(NV_##device##_##mask,value)
+#define DEVICE_MASK(device,mask) MASKEXPAND(NV_##device##_##mask)
+
+#define PDAC_Write(reg,value)           DEVICE_WRITE(PDAC,reg,value)
+#define PDAC_Read(reg)                  DEVICE_READ(PDAC,reg)
+#define PDAC_Print(reg)                 DEVICE_PRINT(PDAC,reg)
+#define PDAC_Def(mask,value)            DEVICE_DEF(PDAC,mask,value)
+#define PDAC_Val(mask,value)            DEVICE_VALUE(PDAC,mask,value)
+#define PDAC_Mask(mask)                 DEVICE_MASK(PDAC,mask)
+
+#define PFB_Write(reg,value)            DEVICE_WRITE(PFB,reg,value)
+#define PFB_Read(reg)                   DEVICE_READ(PFB,reg)
+#define PFB_Print(reg)                  DEVICE_PRINT(PFB,reg)
+#define PFB_Def(mask,value)             DEVICE_DEF(PFB,mask,value)
+#define PFB_Val(mask,value)             DEVICE_VALUE(PFB,mask,value)
+#define PFB_Mask(mask)                  DEVICE_MASK(PFB,mask)
+
+#define PRM_Write(reg,value)            DEVICE_WRITE(PRM,reg,value)
+#define PRM_Read(reg)                   DEVICE_READ(PRM,reg)
+#define PRM_Print(reg)                  DEVICE_PRINT(PRM,reg)
+#define PRM_Def(mask,value)             DEVICE_DEF(PRM,mask,value)
+#define PRM_Val(mask,value)             DEVICE_VALUE(PRM,mask,value)
+#define PRM_Mask(mask)                  DEVICE_MASK(PRM,mask)
+
+#define PGRAPH_Write(reg,value)         DEVICE_WRITE(PGRAPH,reg,value)
+#define PGRAPH_Read(reg)                DEVICE_READ(PGRAPH,reg)
+#define PGRAPH_Print(reg)               DEVICE_PRINT(PGRAPH,reg)
+#define PGRAPH_Def(mask,value)          DEVICE_DEF(PGRAPH,mask,value)
+#define PGRAPH_Val(mask,value)          DEVICE_VALUE(PGRAPH,mask,value)
+#define PGRAPH_Mask(mask)               DEVICE_MASK(PGRAPH,mask)
+
+#define PDMA_Write(reg,value)           DEVICE_WRITE(PDMA,reg,value)
+#define PDMA_Read(reg)                  DEVICE_READ(PDMA,reg)
+#define PDMA_Print(reg)                 DEVICE_PRINT(PDMA,reg)
+#define PDMA_Def(mask,value)            DEVICE_DEF(PDMA,mask,value)
+#define PDMA_Val(mask,value)            DEVICE_VALUE(PDMA,mask,value)
+#define PDMA_Mask(mask)                 DEVICE_MASK(PDMA,mask)
+
+#define PTIMER_Write(reg,value)         DEVICE_WRITE(PTIMER,reg,value)
+#define PTIMER_Read(reg)                DEVICE_READ(PTIMER,reg)
+#define PTIMER_Print(reg)               DEVICE_PRINT(PTIMER,reg)
+#define PTIMER_Def(mask,value)          DEVICE_DEF(PTIMER,mask,value)
+#define PTIMER_Val(mask,value)          DEVICE_VALUE(PTIEMR,mask,value)
+#define PTIMER_Mask(mask)               DEVICE_MASK(PTIMER,mask)
+
+#define PEXTDEV_Write(reg,value)         DEVICE_WRITE(PEXTDEV,reg,value)
+#define PEXTDEV_Read(reg)                DEVICE_READ(PEXTDEV,reg)
+#define PEXTDEV_Print(reg)               DEVICE_PRINT(PEXTDEV,reg)
+#define PEXTDEV_Def(mask,value)          DEVICE_DEF(PEXTDEV,mask,value)
+#define PEXTDEV_Val(mask,value)          DEVICE_VALUE(PEXTDEV,mask,value)
+#define PEXTDEV_Mask(mask)               DEVICE_MASK(PEXTDEV,mask)
+
+#define PFIFO_Write(reg,value)          DEVICE_WRITE(PFIFO,reg,value)
+#define PFIFO_Read(reg)                 DEVICE_READ(PFIFO,reg)
+#define PFIFO_Print(reg)                DEVICE_PRINT(PFIFO,reg)
+#define PFIFO_Def(mask,value)           DEVICE_DEF(PFIFO,mask,value)
+#define PFIFO_Val(mask,value)           DEVICE_VALUE(PFIFO,mask,value)
+#define PFIFO_Mask(mask)                DEVICE_MASK(PFIFO,mask)
+
+#define PRAM_Write(reg,value)           DEVICE_WRITE(PRAM,reg,value)
+#define PRAM_Read(reg)                  DEVICE_READ(PRAM,reg)
+#define PRAM_Print(reg)                 DEVICE_PRINT(PRAM,reg)
+#define PRAM_Def(mask,value)            DEVICE_DEF(PRAM,mask,value)
+#define PRAM_Val(mask,value)            DEVICE_VALUE(PRAM,mask,value)
+#define PRAM_Mask(mask)                 DEVICE_MASK(PRAM,mask)
+
+#define PRAMFC_Write(reg,value)         DEVICE_WRITE(PRAMFC,reg,value)
+#define PRAMFC_Read(reg)                DEVICE_READ(PRAMFC,reg)
+#define PRAMFC_Print(reg)               DEVICE_PRINT(PRAMFC,reg)
+#define PRAMFC_Def(mask,value)          DEVICE_DEF(PRAMFC,mask,value)
+#define PRAMFC_Val(mask,value)          DEVICE_VALUE(PRAMFC,mask,value)
+#define PRAMFC_Mask(mask)               DEVICE_MASK(PRAMFC,mask)
+
+#define PMC_Write(reg,value)            DEVICE_WRITE(PMC,reg,value)
+#define PMC_Read(reg)                   DEVICE_READ(PMC,reg)
+#define PMC_Print(reg)                  DEVICE_PRINT(PMC,reg)
+#define PMC_Def(mask,value)             DEVICE_DEF(PMC,mask,value)
+#define PMC_Val(mask,value)             DEVICE_VALUE(PMC,mask,value)
+#define PMC_Mask(mask)                  DEVICE_MASK(PMC,mask)
+
+#define PMC_Write(reg,value)            DEVICE_WRITE(PMC,reg,value)
+#define PMC_Read(reg)                   DEVICE_READ(PMC,reg)
+#define PMC_Print(reg)                  DEVICE_PRINT(PMC,reg)
+#define PMC_Def(mask,value)             DEVICE_DEF(PMC,mask,value)
+#define PMC_Val(mask,value)             DEVICE_VALUE(PMC,mask,value)
+#define PMC_Mask(mask)                  DEVICE_MASK(PMC,mask)
+
+
+#define PBUS_Write(reg,value)         DEVICE_WRITE(PBUS,reg,value)
+#define PBUS_Read(reg)                DEVICE_READ(PBUS,reg)
+#define PBUS_Print(reg)               DEVICE_PRINT(PBUS,reg)
+#define PBUS_Def(mask,value)          DEVICE_DEF(PBUS,mask,value)
+#define PBUS_Val(mask,value)          DEVICE_VALUE(PBUS,mask,value)
+#define PBUS_Mask(mask)               DEVICE_MASK(PBUS,mask)
+
+
+#define PRAMDAC_Write(reg,value)         DEVICE_WRITE(PRAMDAC,reg,value)
+#define PRAMDAC_Read(reg)                DEVICE_READ(PRAMDAC,reg)
+#define PRAMDAC_Print(reg)               DEVICE_PRINT(PRAMDAC,reg)
+#define PRAMDAC_Def(mask,value)          DEVICE_DEF(PRAMDAC,mask,value)
+#define PRAMDAC_Val(mask,value)          DEVICE_VALUE(PRAMDAC,mask,value)
+#define PRAMDAC_Mask(mask)               DEVICE_MASK(PRAMDAC,mask)
+
+
+#define PDAC_ReadExt(reg) \
+  ((PDAC_Write(INDEX_LO,(NV_PDAC_EXT_##reg) & 0xff)),\
+  (PDAC_Write(INDEX_HI,((NV_PDAC_EXT_##reg) >> 8) & 0xff)),\
+  (PDAC_Read(INDEX_DATA)))
+
+#define PDAC_WriteExt(reg,value)\
+  ((PDAC_Write(INDEX_LO,(NV_PDAC_EXT_##reg) & 0xff)),\
+  (PDAC_Write(INDEX_HI,((NV_PDAC_EXT_##reg) >> 8) & 0xff)),\
+  (PDAC_Write(INDEX_DATA,(value))))
+
+#define CRTC_Write(index,value) outb((index), 0x3d4); outb(value, 0x3d5)
+#define CRTC_Read(index) (outb(index, 0x3d4),inb(0x3d5))
+
+#define PCRTC_Write(index,value) CRTC_Write(NV_PCRTC_##index,value)
+#define PCRTC_Read(index) CRTC_Read(NV_PCRTC_##index)
+
+#define PCRTC_Def(mask,value)          DEVICE_DEF(PCRTC,mask,value)
+#define PCRTC_Val(mask,value)          DEVICE_VALUE(PCRTC,mask,value)
+#define PCRTC_Mask(mask)               DEVICE_MASK(PCRTC,mask)
+
+#define SR_Write(index,value) outb(0x3c4,(index));outb(0x3c5,value)
+#define SR_Read(index) (outb(0x3c4,index),inb(0x3c5))
+
+extern volatile unsigned  *nvCONTROL;
+
+typedef enum {NV1,NV3,NV4,NumNVChips} NVChipType;
+
+NVChipType GetChipType(void);
+
+#endif
+
+
diff --git a/drivers/video/riva/riva_hw.c b/drivers/video/riva/riva_hw.c
new file mode 100644
index 0000000..b6f8690
--- /dev/null
+++ b/drivers/video/riva/riva_hw.c
@@ -0,0 +1,2259 @@
+ /***************************************************************************\
+|*                                                                           *|
+|*       Copyright 1993-1999 NVIDIA, Corporation.  All rights reserved.      *|
+|*                                                                           *|
+|*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
+|*     international laws.  Users and possessors of this source code are     *|
+|*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
+|*     use this code in individual and commercial software.                  *|
+|*                                                                           *|
+|*     Any use of this source code must include,  in the user documenta-     *|
+|*     tion and  internal comments to the code,  notices to the end user     *|
+|*     as follows:                                                           *|
+|*                                                                           *|
+|*       Copyright 1993-1999 NVIDIA, Corporation.  All rights reserved.      *|
+|*                                                                           *|
+|*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
+|*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
+|*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
+|*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
+|*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
+|*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
+|*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
+|*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
+|*     SULTING FROM LOSS OF USE,  DATA OR PROFITS,  WHETHER IN AN ACTION     *|
+|*     OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,  ARISING OUT OF     *|
+|*     OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.     *|
+|*                                                                           *|
+|*     U.S. Government  End  Users.   This source code  is a "commercial     *|
+|*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
+|*     consisting  of "commercial  computer  software"  and  "commercial     *|
+|*     computer  software  documentation,"  as such  terms  are  used in     *|
+|*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
+|*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
+|*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
+|*     all U.S. Government End Users  acquire the source code  with only     *|
+|*     those rights set forth herein.                                        *|
+|*                                                                           *|
+ \***************************************************************************/
+
+/*
+ * GPL licensing note -- nVidia is allowing a liberal interpretation of
+ * the documentation restriction above, to merely say that this nVidia's
+ * copyright and disclaimer should be included with all code derived
+ * from this source.  -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 
+ */
+
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/riva_hw.c,v 1.33 2002/08/05 20:47:06 mvojkovi Exp $ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include "riva_hw.h"
+#include "riva_tbl.h"
+#include "nv_type.h"
+
+/*
+ * This file is an OS-agnostic file used to make RIVA 128 and RIVA TNT
+ * operate identically (except TNT has more memory and better 3D quality.
+ */
+static int nv3Busy
+(
+    RIVA_HW_INST *chip
+)
+{
+    return ((NV_RD32(&chip->Rop->FifoFree, 0) < chip->FifoEmptyCount) ||
+	    NV_RD32(&chip->PGRAPH[0x000006B0/4], 0) & 0x01);
+}
+static int nv4Busy
+(
+    RIVA_HW_INST *chip
+)
+{
+    return ((NV_RD32(&chip->Rop->FifoFree, 0) < chip->FifoEmptyCount) ||
+	    NV_RD32(&chip->PGRAPH[0x00000700/4], 0) & 0x01);
+}
+static int nv10Busy
+(
+    RIVA_HW_INST *chip
+)
+{
+    return ((NV_RD32(&chip->Rop->FifoFree, 0) < chip->FifoEmptyCount) ||
+	    NV_RD32(&chip->PGRAPH[0x00000700/4], 0) & 0x01);
+}
+
+static void vgaLockUnlock
+(
+    RIVA_HW_INST *chip,
+    int           Lock
+)
+{
+    U008 cr11;
+    VGA_WR08(chip->PCIO, 0x3D4, 0x11);
+    cr11 = VGA_RD08(chip->PCIO, 0x3D5);
+    if(Lock) cr11 |= 0x80;
+    else cr11 &= ~0x80;
+    VGA_WR08(chip->PCIO, 0x3D5, cr11);
+}
+static void nv3LockUnlock
+(
+    RIVA_HW_INST *chip,
+    int           Lock
+)
+{
+    VGA_WR08(chip->PVIO, 0x3C4, 0x06);
+    VGA_WR08(chip->PVIO, 0x3C5, Lock ? 0x99 : 0x57);
+    vgaLockUnlock(chip, Lock);
+}
+static void nv4LockUnlock
+(
+    RIVA_HW_INST *chip,
+    int           Lock
+)
+{
+    VGA_WR08(chip->PCIO, 0x3D4, 0x1F);
+    VGA_WR08(chip->PCIO, 0x3D5, Lock ? 0x99 : 0x57);
+    vgaLockUnlock(chip, Lock);
+}
+
+static int ShowHideCursor
+(
+    RIVA_HW_INST *chip,
+    int           ShowHide
+)
+{
+    int cursor;
+    cursor                      =  chip->CurrentState->cursor1;
+    chip->CurrentState->cursor1 = (chip->CurrentState->cursor1 & 0xFE) |
+                                  (ShowHide & 0x01);
+    VGA_WR08(chip->PCIO, 0x3D4, 0x31);
+    VGA_WR08(chip->PCIO, 0x3D5, chip->CurrentState->cursor1);
+    return (cursor & 0x01);
+}
+
+/****************************************************************************\
+*                                                                            *
+* The video arbitration routines calculate some "magic" numbers.  Fixes      *
+* the snow seen when accessing the framebuffer without it.                   *
+* It just works (I hope).                                                    *
+*                                                                            *
+\****************************************************************************/
+
+#define DEFAULT_GR_LWM 100
+#define DEFAULT_VID_LWM 100
+#define DEFAULT_GR_BURST_SIZE 256
+#define DEFAULT_VID_BURST_SIZE 128
+#define VIDEO		0
+#define GRAPHICS	1
+#define MPORT		2
+#define ENGINE		3
+#define GFIFO_SIZE	320
+#define GFIFO_SIZE_128	256
+#define MFIFO_SIZE	120
+#define VFIFO_SIZE	256
+
+typedef struct {
+  int gdrain_rate;
+  int vdrain_rate;
+  int mdrain_rate;
+  int gburst_size;
+  int vburst_size;
+  char vid_en;
+  char gr_en;
+  int wcmocc, wcgocc, wcvocc, wcvlwm, wcglwm;
+  int by_gfacc;
+  char vid_only_once;
+  char gr_only_once;
+  char first_vacc;
+  char first_gacc;
+  char first_macc;
+  int vocc;
+  int gocc;
+  int mocc;
+  char cur;
+  char engine_en;
+  char converged;
+  int priority;
+} nv3_arb_info;
+typedef struct {
+  int graphics_lwm;
+  int video_lwm;
+  int graphics_burst_size;
+  int video_burst_size;
+  int graphics_hi_priority;
+  int media_hi_priority;
+  int rtl_values;
+  int valid;
+} nv3_fifo_info;
+typedef struct {
+  char pix_bpp;
+  char enable_video;
+  char gr_during_vid;
+  char enable_mp;
+  int memory_width;
+  int video_scale;
+  int pclk_khz;
+  int mclk_khz;
+  int mem_page_miss;
+  int mem_latency;
+  char mem_aligned;
+} nv3_sim_state;
+typedef struct {
+  int graphics_lwm;
+  int video_lwm;
+  int graphics_burst_size;
+  int video_burst_size;
+  int valid;
+} nv4_fifo_info;
+typedef struct {
+  int pclk_khz;
+  int mclk_khz;
+  int nvclk_khz;
+  char mem_page_miss;
+  char mem_latency;
+  int memory_width;
+  char enable_video;
+  char gr_during_vid;
+  char pix_bpp;
+  char mem_aligned;
+  char enable_mp;
+} nv4_sim_state;
+typedef struct {
+  int graphics_lwm;
+  int video_lwm;
+  int graphics_burst_size;
+  int video_burst_size;
+  int valid;
+} nv10_fifo_info;
+typedef struct {
+  int pclk_khz;
+  int mclk_khz;
+  int nvclk_khz;
+  char mem_page_miss;
+  char mem_latency;
+  int memory_type;
+  int memory_width;
+  char enable_video;
+  char gr_during_vid;
+  char pix_bpp;
+  char mem_aligned;
+  char enable_mp;
+} nv10_sim_state;
+static int nv3_iterate(nv3_fifo_info *res_info, nv3_sim_state * state, nv3_arb_info *ainfo)
+{
+    int iter = 0;
+    int tmp;
+    int vfsize, mfsize, gfsize;
+    int mburst_size = 32;
+    int mmisses, gmisses, vmisses;
+    int misses;
+    int vlwm, glwm, mlwm;
+    int last, next, cur;
+    int max_gfsize ;
+    long ns;
+
+    vlwm = 0;
+    glwm = 0;
+    mlwm = 0;
+    vfsize = 0;
+    gfsize = 0;
+    cur = ainfo->cur;
+    mmisses = 2;
+    gmisses = 2;
+    vmisses = 2;
+    if (ainfo->gburst_size == 128) max_gfsize = GFIFO_SIZE_128;
+    else  max_gfsize = GFIFO_SIZE;
+    max_gfsize = GFIFO_SIZE;
+    while (1)
+    {
+        if (ainfo->vid_en)
+        {
+            if (ainfo->wcvocc > ainfo->vocc) ainfo->wcvocc = ainfo->vocc;
+            if (ainfo->wcvlwm > vlwm) ainfo->wcvlwm = vlwm ;
+            ns = 1000000 * ainfo->vburst_size/(state->memory_width/8)/state->mclk_khz;
+            vfsize = ns * ainfo->vdrain_rate / 1000000;
+            vfsize =  ainfo->wcvlwm - ainfo->vburst_size + vfsize;
+        }
+        if (state->enable_mp)
+        {
+            if (ainfo->wcmocc > ainfo->mocc) ainfo->wcmocc = ainfo->mocc;
+        }
+        if (ainfo->gr_en)
+        {
+            if (ainfo->wcglwm > glwm) ainfo->wcglwm = glwm ;
+            if (ainfo->wcgocc > ainfo->gocc) ainfo->wcgocc = ainfo->gocc;
+            ns = 1000000 * (ainfo->gburst_size/(state->memory_width/8))/state->mclk_khz;
+            gfsize = (ns * (long) ainfo->gdrain_rate)/1000000;
+            gfsize = ainfo->wcglwm - ainfo->gburst_size + gfsize;
+        }
+        mfsize = 0;
+        if (!state->gr_during_vid && ainfo->vid_en)
+            if (ainfo->vid_en && (ainfo->vocc < 0) && !ainfo->vid_only_once)
+                next = VIDEO;
+            else if (ainfo->mocc < 0)
+                next = MPORT;
+            else if (ainfo->gocc< ainfo->by_gfacc)
+                next = GRAPHICS;
+            else return (0);
+        else switch (ainfo->priority)
+            {
+                case VIDEO:
+                    if (ainfo->vid_en && ainfo->vocc<0 && !ainfo->vid_only_once)
+                        next = VIDEO;
+                    else if (ainfo->gr_en && ainfo->gocc<0 && !ainfo->gr_only_once)
+                        next = GRAPHICS;
+                    else if (ainfo->mocc<0)
+                        next = MPORT;
+                    else    return (0);
+                    break;
+                case GRAPHICS:
+                    if (ainfo->gr_en && ainfo->gocc<0 && !ainfo->gr_only_once)
+                        next = GRAPHICS;
+                    else if (ainfo->vid_en && ainfo->vocc<0 && !ainfo->vid_only_once)
+                        next = VIDEO;
+                    else if (ainfo->mocc<0)
+                        next = MPORT;
+                    else    return (0);
+                    break;
+                default:
+                    if (ainfo->mocc<0)
+                        next = MPORT;
+                    else if (ainfo->gr_en && ainfo->gocc<0 && !ainfo->gr_only_once)
+                        next = GRAPHICS;
+                    else if (ainfo->vid_en && ainfo->vocc<0 && !ainfo->vid_only_once)
+                        next = VIDEO;
+                    else    return (0);
+                    break;
+            }
+        last = cur;
+        cur = next;
+        iter++;
+        switch (cur)
+        {
+            case VIDEO:
+                if (last==cur)    misses = 0;
+                else if (ainfo->first_vacc)   misses = vmisses;
+                else    misses = 1;
+                ainfo->first_vacc = 0;
+                if (last!=cur)
+                {
+                    ns =  1000000 * (vmisses*state->mem_page_miss + state->mem_latency)/state->mclk_khz; 
+                    vlwm = ns * ainfo->vdrain_rate/ 1000000;
+                    vlwm = ainfo->vocc - vlwm;
+                }
+                ns = 1000000*(misses*state->mem_page_miss + ainfo->vburst_size)/(state->memory_width/8)/state->mclk_khz;
+                ainfo->vocc = ainfo->vocc + ainfo->vburst_size - ns*ainfo->vdrain_rate/1000000;
+                ainfo->gocc = ainfo->gocc - ns*ainfo->gdrain_rate/1000000;
+                ainfo->mocc = ainfo->mocc - ns*ainfo->mdrain_rate/1000000;
+                break;
+            case GRAPHICS:
+                if (last==cur)    misses = 0;
+                else if (ainfo->first_gacc)   misses = gmisses;
+                else    misses = 1;
+                ainfo->first_gacc = 0;
+                if (last!=cur)
+                {
+                    ns = 1000000*(gmisses*state->mem_page_miss + state->mem_latency)/state->mclk_khz ;
+                    glwm = ns * ainfo->gdrain_rate/1000000;
+                    glwm = ainfo->gocc - glwm;
+                }
+                ns = 1000000*(misses*state->mem_page_miss + ainfo->gburst_size/(state->memory_width/8))/state->mclk_khz;
+                ainfo->vocc = ainfo->vocc + 0 - ns*ainfo->vdrain_rate/1000000;
+                ainfo->gocc = ainfo->gocc + ainfo->gburst_size - ns*ainfo->gdrain_rate/1000000;
+                ainfo->mocc = ainfo->mocc + 0 - ns*ainfo->mdrain_rate/1000000;
+                break;
+            default:
+                if (last==cur)    misses = 0;
+                else if (ainfo->first_macc)   misses = mmisses;
+                else    misses = 1;
+                ainfo->first_macc = 0;
+                ns = 1000000*(misses*state->mem_page_miss + mburst_size/(state->memory_width/8))/state->mclk_khz;
+                ainfo->vocc = ainfo->vocc + 0 - ns*ainfo->vdrain_rate/1000000;
+                ainfo->gocc = ainfo->gocc + 0 - ns*ainfo->gdrain_rate/1000000;
+                ainfo->mocc = ainfo->mocc + mburst_size - ns*ainfo->mdrain_rate/1000000;
+                break;
+        }
+        if (iter>100)
+        {
+            ainfo->converged = 0;
+            return (1);
+        }
+        ns = 1000000*ainfo->gburst_size/(state->memory_width/8)/state->mclk_khz;
+        tmp = ns * ainfo->gdrain_rate/1000000;
+        if (abs(ainfo->gburst_size) + ((abs(ainfo->wcglwm) + 16 ) & ~0x7) - tmp > max_gfsize)
+        {
+            ainfo->converged = 0;
+            return (1);
+        }
+        ns = 1000000*ainfo->vburst_size/(state->memory_width/8)/state->mclk_khz;
+        tmp = ns * ainfo->vdrain_rate/1000000;
+        if (abs(ainfo->vburst_size) + (abs(ainfo->wcvlwm + 32) & ~0xf)  - tmp> VFIFO_SIZE)
+        {
+            ainfo->converged = 0;
+            return (1);
+        }
+        if (abs(ainfo->gocc) > max_gfsize)
+        {
+            ainfo->converged = 0;
+            return (1);
+        }
+        if (abs(ainfo->vocc) > VFIFO_SIZE)
+        {
+            ainfo->converged = 0;
+            return (1);
+        }
+        if (abs(ainfo->mocc) > MFIFO_SIZE)
+        {
+            ainfo->converged = 0;
+            return (1);
+        }
+        if (abs(vfsize) > VFIFO_SIZE)
+        {
+            ainfo->converged = 0;
+            return (1);
+        }
+        if (abs(gfsize) > max_gfsize)
+        {
+            ainfo->converged = 0;
+            return (1);
+        }
+        if (abs(mfsize) > MFIFO_SIZE)
+        {
+            ainfo->converged = 0;
+            return (1);
+        }
+    }
+}
+static char nv3_arb(nv3_fifo_info * res_info, nv3_sim_state * state,  nv3_arb_info *ainfo) 
+{
+    long ens, vns, mns, gns;
+    int mmisses, gmisses, vmisses, eburst_size, mburst_size;
+    int refresh_cycle;
+
+    refresh_cycle = 0;
+    refresh_cycle = 2*(state->mclk_khz/state->pclk_khz) + 5;
+    mmisses = 2;
+    if (state->mem_aligned) gmisses = 2;
+    else    gmisses = 3;
+    vmisses = 2;
+    eburst_size = state->memory_width * 1;
+    mburst_size = 32;
+    gns = 1000000 * (gmisses*state->mem_page_miss + state->mem_latency)/state->mclk_khz;
+    ainfo->by_gfacc = gns*ainfo->gdrain_rate/1000000;
+    ainfo->wcmocc = 0;
+    ainfo->wcgocc = 0;
+    ainfo->wcvocc = 0;
+    ainfo->wcvlwm = 0;
+    ainfo->wcglwm = 0;
+    ainfo->engine_en = 1;
+    ainfo->converged = 1;
+    if (ainfo->engine_en)
+    {
+        ens =  1000000*(state->mem_page_miss + eburst_size/(state->memory_width/8) +refresh_cycle)/state->mclk_khz;
+        ainfo->mocc = state->enable_mp ? 0-ens*ainfo->mdrain_rate/1000000 : 0;
+        ainfo->vocc = ainfo->vid_en ? 0-ens*ainfo->vdrain_rate/1000000 : 0;
+        ainfo->gocc = ainfo->gr_en ? 0-ens*ainfo->gdrain_rate/1000000 : 0;
+        ainfo->cur = ENGINE;
+        ainfo->first_vacc = 1;
+        ainfo->first_gacc = 1;
+        ainfo->first_macc = 1;
+        nv3_iterate(res_info, state,ainfo);
+    }
+    if (state->enable_mp)
+    {
+        mns = 1000000 * (mmisses*state->mem_page_miss + mburst_size/(state->memory_width/8) + refresh_cycle)/state->mclk_khz;
+        ainfo->mocc = state->enable_mp ? 0 : mburst_size - mns*ainfo->mdrain_rate/1000000;
+        ainfo->vocc = ainfo->vid_en ? 0 : 0- mns*ainfo->vdrain_rate/1000000;
+        ainfo->gocc = ainfo->gr_en ? 0: 0- mns*ainfo->gdrain_rate/1000000;
+        ainfo->cur = MPORT;
+        ainfo->first_vacc = 1;
+        ainfo->first_gacc = 1;
+        ainfo->first_macc = 0;
+        nv3_iterate(res_info, state,ainfo);
+    }
+    if (ainfo->gr_en)
+    {
+        ainfo->first_vacc = 1;
+        ainfo->first_gacc = 0;
+        ainfo->first_macc = 1;
+        gns = 1000000*(gmisses*state->mem_page_miss + ainfo->gburst_size/(state->memory_width/8) + refresh_cycle)/state->mclk_khz;
+        ainfo->gocc = ainfo->gburst_size - gns*ainfo->gdrain_rate/1000000;
+        ainfo->vocc = ainfo->vid_en? 0-gns*ainfo->vdrain_rate/1000000 : 0;
+        ainfo->mocc = state->enable_mp ?  0-gns*ainfo->mdrain_rate/1000000: 0;
+        ainfo->cur = GRAPHICS;
+        nv3_iterate(res_info, state,ainfo);
+    }
+    if (ainfo->vid_en)
+    {
+        ainfo->first_vacc = 0;
+        ainfo->first_gacc = 1;
+        ainfo->first_macc = 1;
+        vns = 1000000*(vmisses*state->mem_page_miss + ainfo->vburst_size/(state->memory_width/8) + refresh_cycle)/state->mclk_khz;
+        ainfo->vocc = ainfo->vburst_size - vns*ainfo->vdrain_rate/1000000;
+        ainfo->gocc = ainfo->gr_en? (0-vns*ainfo->gdrain_rate/1000000) : 0;
+        ainfo->mocc = state->enable_mp? 0-vns*ainfo->mdrain_rate/1000000 :0 ;
+        ainfo->cur = VIDEO;
+        nv3_iterate(res_info, state, ainfo);
+    }
+    if (ainfo->converged)
+    {
+        res_info->graphics_lwm = (int)abs(ainfo->wcglwm) + 16;
+        res_info->video_lwm = (int)abs(ainfo->wcvlwm) + 32;
+        res_info->graphics_burst_size = ainfo->gburst_size;
+        res_info->video_burst_size = ainfo->vburst_size;
+        res_info->graphics_hi_priority = (ainfo->priority == GRAPHICS);
+        res_info->media_hi_priority = (ainfo->priority == MPORT);
+        if (res_info->video_lwm > 160)
+        {
+            res_info->graphics_lwm = 256;
+            res_info->video_lwm = 128;
+            res_info->graphics_burst_size = 64;
+            res_info->video_burst_size = 64;
+            res_info->graphics_hi_priority = 0;
+            res_info->media_hi_priority = 0;
+            ainfo->converged = 0;
+            return (0);
+        }
+        if (res_info->video_lwm > 128)
+        {
+            res_info->video_lwm = 128;
+        }
+        return (1);
+    }
+    else
+    {
+        res_info->graphics_lwm = 256;
+        res_info->video_lwm = 128;
+        res_info->graphics_burst_size = 64;
+        res_info->video_burst_size = 64;
+        res_info->graphics_hi_priority = 0;
+        res_info->media_hi_priority = 0;
+        return (0);
+    }
+}
+static char nv3_get_param(nv3_fifo_info *res_info, nv3_sim_state * state, nv3_arb_info *ainfo)
+{
+    int done, g,v, p;
+    
+    done = 0;
+    for (p=0; p < 2; p++)
+    {
+        for (g=128 ; g > 32; g= g>> 1)
+        {
+            for (v=128; v >=32; v = v>> 1)
+            {
+                ainfo->priority = p;
+                ainfo->gburst_size = g;     
+                ainfo->vburst_size = v;
+                done = nv3_arb(res_info, state,ainfo);
+                if (done && (g==128))
+                    if ((res_info->graphics_lwm + g) > 256)
+                        done = 0;
+                if (done)
+                    goto Done;
+            }
+        }
+    }
+
+ Done:
+    return done;
+}
+static void nv3CalcArbitration 
+(
+    nv3_fifo_info * res_info,
+    nv3_sim_state * state
+)
+{
+    nv3_fifo_info save_info;
+    nv3_arb_info ainfo;
+    char   res_gr, res_vid;
+
+    ainfo.gr_en = 1;
+    ainfo.vid_en = state->enable_video;
+    ainfo.vid_only_once = 0;
+    ainfo.gr_only_once = 0;
+    ainfo.gdrain_rate = (int) state->pclk_khz * (state->pix_bpp/8);
+    ainfo.vdrain_rate = (int) state->pclk_khz * 2;
+    if (state->video_scale != 0)
+        ainfo.vdrain_rate = ainfo.vdrain_rate/state->video_scale;
+    ainfo.mdrain_rate = 33000;
+    res_info->rtl_values = 0;
+    if (!state->gr_during_vid && state->enable_video)
+    {
+        ainfo.gr_only_once = 1;
+        ainfo.gr_en = 1;
+        ainfo.gdrain_rate = 0;
+        res_vid = nv3_get_param(res_info, state,  &ainfo);
+        res_vid = ainfo.converged;
+        save_info.video_lwm = res_info->video_lwm;
+        save_info.video_burst_size = res_info->video_burst_size;
+        ainfo.vid_en = 1;
+        ainfo.vid_only_once = 1;
+        ainfo.gr_en = 1;
+        ainfo.gdrain_rate = (int) state->pclk_khz * (state->pix_bpp/8);
+        ainfo.vdrain_rate = 0;
+        res_gr = nv3_get_param(res_info, state,  &ainfo);
+        res_gr = ainfo.converged;
+        res_info->video_lwm = save_info.video_lwm;
+        res_info->video_burst_size = save_info.video_burst_size;
+        res_info->valid = res_gr & res_vid;
+    }
+    else
+    {
+        if (!ainfo.gr_en) ainfo.gdrain_rate = 0;
+        if (!ainfo.vid_en) ainfo.vdrain_rate = 0;
+        res_gr = nv3_get_param(res_info, state,  &ainfo);
+        res_info->valid = ainfo.converged;
+    }
+}
+static void nv3UpdateArbitrationSettings
+(
+    unsigned      VClk, 
+    unsigned      pixelDepth, 
+    unsigned     *burst,
+    unsigned     *lwm,
+    RIVA_HW_INST *chip
+)
+{
+    nv3_fifo_info fifo_data;
+    nv3_sim_state sim_data;
+    unsigned int M, N, P, pll, MClk;
+    
+    pll = NV_RD32(&chip->PRAMDAC0[0x00000504/4], 0);
+    M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; P = (pll >> 16) & 0x0F;
+    MClk = (N * chip->CrystalFreqKHz / M) >> P;
+    sim_data.pix_bpp        = (char)pixelDepth;
+    sim_data.enable_video   = 0;
+    sim_data.enable_mp      = 0;
+    sim_data.video_scale    = 1;
+    sim_data.memory_width   = (NV_RD32(&chip->PEXTDEV[0x00000000/4], 0) & 0x10) ?
+	128 : 64;
+    sim_data.memory_width   = 128;
+
+    sim_data.mem_latency    = 9;
+    sim_data.mem_aligned    = 1;
+    sim_data.mem_page_miss  = 11;
+    sim_data.gr_during_vid  = 0;
+    sim_data.pclk_khz       = VClk;
+    sim_data.mclk_khz       = MClk;
+    nv3CalcArbitration(&fifo_data, &sim_data);
+    if (fifo_data.valid)
+    {
+        int  b = fifo_data.graphics_burst_size >> 4;
+        *burst = 0;
+        while (b >>= 1)
+	    (*burst)++;
+        *lwm   = fifo_data.graphics_lwm >> 3;
+    }
+    else
+    {
+        *lwm   = 0x24;
+        *burst = 0x2;
+    }
+}
+static void nv4CalcArbitration 
+(
+    nv4_fifo_info *fifo,
+    nv4_sim_state *arb
+)
+{
+    int data, pagemiss, cas,width, video_enable, color_key_enable, bpp, align;
+    int nvclks, mclks, pclks, vpagemiss, crtpagemiss, vbs;
+    int found, mclk_extra, mclk_loop, cbs, m1, p1;
+    int mclk_freq, pclk_freq, nvclk_freq, mp_enable;
+    int us_m, us_n, us_p, video_drain_rate, crtc_drain_rate;
+    int vpm_us, us_video, vlwm, video_fill_us, cpm_us, us_crt,clwm;
+    int craw, vraw;
+
+    fifo->valid = 1;
+    pclk_freq = arb->pclk_khz;
+    mclk_freq = arb->mclk_khz;
+    nvclk_freq = arb->nvclk_khz;
+    pagemiss = arb->mem_page_miss;
+    cas = arb->mem_latency;
+    width = arb->memory_width >> 6;
+    video_enable = arb->enable_video;
+    color_key_enable = arb->gr_during_vid;
+    bpp = arb->pix_bpp;
+    align = arb->mem_aligned;
+    mp_enable = arb->enable_mp;
+    clwm = 0;
+    vlwm = 0;
+    cbs = 128;
+    pclks = 2;
+    nvclks = 2;
+    nvclks += 2;
+    nvclks += 1;
+    mclks = 5;
+    mclks += 3;
+    mclks += 1;
+    mclks += cas;
+    mclks += 1;
+    mclks += 1;
+    mclks += 1;
+    mclks += 1;
+    mclk_extra = 3;
+    nvclks += 2;
+    nvclks += 1;
+    nvclks += 1;
+    nvclks += 1;
+    if (mp_enable)
+        mclks+=4;
+    nvclks += 0;
+    pclks += 0;
+    found = 0;
+    vbs = 0;
+    while (found != 1)
+    {
+        fifo->valid = 1;
+        found = 1;
+        mclk_loop = mclks+mclk_extra;
+        us_m = mclk_loop *1000*1000 / mclk_freq;
+        us_n = nvclks*1000*1000 / nvclk_freq;
+        us_p = nvclks*1000*1000 / pclk_freq;
+        if (video_enable)
+        {
+            video_drain_rate = pclk_freq * 2;
+            crtc_drain_rate = pclk_freq * bpp/8;
+            vpagemiss = 2;
+            vpagemiss += 1;
+            crtpagemiss = 2;
+            vpm_us = (vpagemiss * pagemiss)*1000*1000/mclk_freq;
+            if (nvclk_freq * 2 > mclk_freq * width)
+                video_fill_us = cbs*1000*1000 / 16 / nvclk_freq ;
+            else
+                video_fill_us = cbs*1000*1000 / (8 * width) / mclk_freq;
+            us_video = vpm_us + us_m + us_n + us_p + video_fill_us;
+            vlwm = us_video * video_drain_rate/(1000*1000);
+            vlwm++;
+            vbs = 128;
+            if (vlwm > 128) vbs = 64;
+            if (vlwm > (256-64)) vbs = 32;
+            if (nvclk_freq * 2 > mclk_freq * width)
+                video_fill_us = vbs *1000*1000/ 16 / nvclk_freq ;
+            else
+                video_fill_us = vbs*1000*1000 / (8 * width) / mclk_freq;
+            cpm_us = crtpagemiss  * pagemiss *1000*1000/ mclk_freq;
+            us_crt =
+            us_video
+            +video_fill_us
+            +cpm_us
+            +us_m + us_n +us_p
+            ;
+            clwm = us_crt * crtc_drain_rate/(1000*1000);
+            clwm++;
+        }
+        else
+        {
+            crtc_drain_rate = pclk_freq * bpp/8;
+            crtpagemiss = 2;
+            crtpagemiss += 1;
+            cpm_us = crtpagemiss  * pagemiss *1000*1000/ mclk_freq;
+            us_crt =  cpm_us + us_m + us_n + us_p ;
+            clwm = us_crt * crtc_drain_rate/(1000*1000);
+            clwm++;
+        }
+        m1 = clwm + cbs - 512;
+        p1 = m1 * pclk_freq / mclk_freq;
+        p1 = p1 * bpp / 8;
+        if ((p1 < m1) && (m1 > 0))
+        {
+            fifo->valid = 0;
+            found = 0;
+            if (mclk_extra ==0)   found = 1;
+            mclk_extra--;
+        }
+        else if (video_enable)
+        {
+            if ((clwm > 511) || (vlwm > 255))
+            {
+                fifo->valid = 0;
+                found = 0;
+                if (mclk_extra ==0)   found = 1;
+                mclk_extra--;
+            }
+        }
+        else
+        {
+            if (clwm > 519)
+            {
+                fifo->valid = 0;
+                found = 0;
+                if (mclk_extra ==0)   found = 1;
+                mclk_extra--;
+            }
+        }
+        craw = clwm;
+        vraw = vlwm;
+        if (clwm < 384) clwm = 384;
+        if (vlwm < 128) vlwm = 128;
+        data = (int)(clwm);
+        fifo->graphics_lwm = data;
+        fifo->graphics_burst_size = 128;
+        data = (int)((vlwm+15));
+        fifo->video_lwm = data;
+        fifo->video_burst_size = vbs;
+    }
+}
+static void nv4UpdateArbitrationSettings
+(
+    unsigned      VClk, 
+    unsigned      pixelDepth, 
+    unsigned     *burst,
+    unsigned     *lwm,
+    RIVA_HW_INST *chip
+)
+{
+    nv4_fifo_info fifo_data;
+    nv4_sim_state sim_data;
+    unsigned int M, N, P, pll, MClk, NVClk, cfg1;
+
+    pll = NV_RD32(&chip->PRAMDAC0[0x00000504/4], 0);
+    M = (pll >> 0)  & 0xFF; N = (pll >> 8)  & 0xFF; P = (pll >> 16) & 0x0F;
+    MClk  = (N * chip->CrystalFreqKHz / M) >> P;
+    pll = NV_RD32(&chip->PRAMDAC0[0x00000500/4], 0);
+    M = (pll >> 0)  & 0xFF; N = (pll >> 8)  & 0xFF; P = (pll >> 16) & 0x0F;
+    NVClk  = (N * chip->CrystalFreqKHz / M) >> P;
+    cfg1 = NV_RD32(&chip->PFB[0x00000204/4], 0);
+    sim_data.pix_bpp        = (char)pixelDepth;
+    sim_data.enable_video   = 0;
+    sim_data.enable_mp      = 0;
+    sim_data.memory_width   = (NV_RD32(&chip->PEXTDEV[0x00000000/4], 0) & 0x10) ?
+	128 : 64;
+    sim_data.mem_latency    = (char)cfg1 & 0x0F;
+    sim_data.mem_aligned    = 1;
+    sim_data.mem_page_miss  = (char)(((cfg1 >> 4) &0x0F) + ((cfg1 >> 31) & 0x01));
+    sim_data.gr_during_vid  = 0;
+    sim_data.pclk_khz       = VClk;
+    sim_data.mclk_khz       = MClk;
+    sim_data.nvclk_khz      = NVClk;
+    nv4CalcArbitration(&fifo_data, &sim_data);
+    if (fifo_data.valid)
+    {
+        int  b = fifo_data.graphics_burst_size >> 4;
+        *burst = 0;
+        while (b >>= 1)
+	    (*burst)++;
+        *lwm   = fifo_data.graphics_lwm >> 3;
+    }
+}
+static void nv10CalcArbitration 
+(
+    nv10_fifo_info *fifo,
+    nv10_sim_state *arb
+)
+{
+    int data, pagemiss, cas,width, video_enable, color_key_enable, bpp, align;
+    int nvclks, mclks, pclks, vpagemiss, crtpagemiss, vbs;
+    int nvclk_fill, us_extra;
+    int found, mclk_extra, mclk_loop, cbs, m1;
+    int mclk_freq, pclk_freq, nvclk_freq, mp_enable;
+    int us_m, us_m_min, us_n, us_p, video_drain_rate, crtc_drain_rate;
+    int vus_m, vus_n, vus_p;
+    int vpm_us, us_video, vlwm, cpm_us, us_crt,clwm;
+    int clwm_rnd_down;
+    int craw, m2us, us_pipe, us_pipe_min, vus_pipe, p1clk, p2;
+    int pclks_2_top_fifo, min_mclk_extra;
+    int us_min_mclk_extra;
+
+    fifo->valid = 1;
+    pclk_freq = arb->pclk_khz; /* freq in KHz */
+    mclk_freq = arb->mclk_khz;
+    nvclk_freq = arb->nvclk_khz;
+    pagemiss = arb->mem_page_miss;
+    cas = arb->mem_latency;
+    width = arb->memory_width/64;
+    video_enable = arb->enable_video;
+    color_key_enable = arb->gr_during_vid;
+    bpp = arb->pix_bpp;
+    align = arb->mem_aligned;
+    mp_enable = arb->enable_mp;
+    clwm = 0;
+    vlwm = 1024;
+
+    cbs = 512;
+    vbs = 512;
+
+    pclks = 4; /* lwm detect. */
+
+    nvclks = 3; /* lwm -> sync. */
+    nvclks += 2; /* fbi bus cycles (1 req + 1 busy) */
+
+    mclks  = 1;   /* 2 edge sync.  may be very close to edge so just put one. */
+
+    mclks += 1;   /* arb_hp_req */
+    mclks += 5;   /* ap_hp_req   tiling pipeline */
+
+    mclks += 2;    /* tc_req     latency fifo */
+    mclks += 2;    /* fb_cas_n_  memory request to fbio block */
+    mclks += 7;    /* sm_d_rdv   data returned from fbio block */
+
+    /* fb.rd.d.Put_gc   need to accumulate 256 bits for read */
+    if (arb->memory_type == 0)
+      if (arb->memory_width == 64) /* 64 bit bus */
+        mclks += 4;
+      else
+        mclks += 2;
+    else
+      if (arb->memory_width == 64) /* 64 bit bus */
+        mclks += 2;
+      else
+        mclks += 1;
+
+    if ((!video_enable) && (arb->memory_width == 128))
+    {  
+      mclk_extra = (bpp == 32) ? 31 : 42; /* Margin of error */
+      min_mclk_extra = 17;
+    }
+    else
+    {
+      mclk_extra = (bpp == 32) ? 8 : 4; /* Margin of error */
+      /* mclk_extra = 4; */ /* Margin of error */
+      min_mclk_extra = 18;
+    }
+
+    nvclks += 1; /* 2 edge sync.  may be very close to edge so just put one. */
+    nvclks += 1; /* fbi_d_rdv_n */
+    nvclks += 1; /* Fbi_d_rdata */
+    nvclks += 1; /* crtfifo load */
+
+    if(mp_enable)
+      mclks+=4; /* Mp can get in with a burst of 8. */
+    /* Extra clocks determined by heuristics */
+
+    nvclks += 0;
+    pclks += 0;
+    found = 0;
+    while(found != 1) {
+      fifo->valid = 1;
+      found = 1;
+      mclk_loop = mclks+mclk_extra;
+      us_m = mclk_loop *1000*1000 / mclk_freq; /* Mclk latency in us */
+      us_m_min = mclks * 1000*1000 / mclk_freq; /* Minimum Mclk latency in us */
+      us_min_mclk_extra = min_mclk_extra *1000*1000 / mclk_freq;
+      us_n = nvclks*1000*1000 / nvclk_freq;/* nvclk latency in us */
+      us_p = pclks*1000*1000 / pclk_freq;/* nvclk latency in us */
+      us_pipe = us_m + us_n + us_p;
+      us_pipe_min = us_m_min + us_n + us_p;
+      us_extra = 0;
+
+      vus_m = mclk_loop *1000*1000 / mclk_freq; /* Mclk latency in us */
+      vus_n = (4)*1000*1000 / nvclk_freq;/* nvclk latency in us */
+      vus_p = 0*1000*1000 / pclk_freq;/* pclk latency in us */
+      vus_pipe = vus_m + vus_n + vus_p;
+
+      if(video_enable) {
+        video_drain_rate = pclk_freq * 4; /* MB/s */
+        crtc_drain_rate = pclk_freq * bpp/8; /* MB/s */
+
+        vpagemiss = 1; /* self generating page miss */
+        vpagemiss += 1; /* One higher priority before */
+
+        crtpagemiss = 2; /* self generating page miss */
+        if(mp_enable)
+            crtpagemiss += 1; /* if MA0 conflict */
+
+        vpm_us = (vpagemiss * pagemiss)*1000*1000/mclk_freq;
+
+        us_video = vpm_us + vus_m; /* Video has separate read return path */
+
+        cpm_us = crtpagemiss  * pagemiss *1000*1000/ mclk_freq;
+        us_crt =
+          us_video  /* Wait for video */
+          +cpm_us /* CRT Page miss */
+          +us_m + us_n +us_p /* other latency */
+          ;
+
+        clwm = us_crt * crtc_drain_rate/(1000*1000);
+        clwm++; /* fixed point <= float_point - 1.  Fixes that */
+      } else {
+        crtc_drain_rate = pclk_freq * bpp/8; /* bpp * pclk/8 */
+
+        crtpagemiss = 1; /* self generating page miss */
+        crtpagemiss += 1; /* MA0 page miss */
+        if(mp_enable)
+            crtpagemiss += 1; /* if MA0 conflict */
+        cpm_us = crtpagemiss  * pagemiss *1000*1000/ mclk_freq;
+        us_crt =  cpm_us + us_m + us_n + us_p ;
+        clwm = us_crt * crtc_drain_rate/(1000*1000);
+        clwm++; /* fixed point <= float_point - 1.  Fixes that */
+
+  /*
+          //
+          // Another concern, only for high pclks so don't do this
+          // with video:
+          // What happens if the latency to fetch the cbs is so large that
+          // fifo empties.  In that case we need to have an alternate clwm value
+          // based off the total burst fetch
+          //
+          us_crt = (cbs * 1000 * 1000)/ (8*width)/mclk_freq ;
+          us_crt = us_crt + us_m + us_n + us_p + (4 * 1000 * 1000)/mclk_freq;
+          clwm_mt = us_crt * crtc_drain_rate/(1000*1000);
+          clwm_mt ++;
+          if(clwm_mt > clwm)
+              clwm = clwm_mt;
+  */
+          /* Finally, a heuristic check when width == 64 bits */
+          if(width == 1){
+              nvclk_fill = nvclk_freq * 8;
+              if(crtc_drain_rate * 100 >= nvclk_fill * 102)
+                      clwm = 0xfff; /*Large number to fail */
+
+              else if(crtc_drain_rate * 100  >= nvclk_fill * 98) {
+                  clwm = 1024;
+                  cbs = 512;
+                  us_extra = (cbs * 1000 * 1000)/ (8*width)/mclk_freq ;
+              }
+          }
+      }
+
+
+      /*
+        Overfill check:
+
+        */
+
+      clwm_rnd_down = ((int)clwm/8)*8;
+      if (clwm_rnd_down < clwm)
+          clwm += 8;
+
+      m1 = clwm + cbs -  1024; /* Amount of overfill */
+      m2us = us_pipe_min + us_min_mclk_extra;
+      pclks_2_top_fifo = (1024-clwm)/(8*width);
+
+      /* pclk cycles to drain */
+      p1clk = m2us * pclk_freq/(1000*1000); 
+      p2 = p1clk * bpp / 8; /* bytes drained. */
+
+      if((p2 < m1) && (m1 > 0)) {
+          fifo->valid = 0;
+          found = 0;
+          if(min_mclk_extra == 0)   {
+            if(cbs <= 32) {
+              found = 1; /* Can't adjust anymore! */
+            } else {
+              cbs = cbs/2;  /* reduce the burst size */
+            }
+          } else {
+            min_mclk_extra--;
+          }
+      } else {
+        if (clwm > 1023){ /* Have some margin */
+          fifo->valid = 0;
+          found = 0;
+          if(min_mclk_extra == 0)   
+              found = 1; /* Can't adjust anymore! */
+          else 
+              min_mclk_extra--;
+        }
+      }
+      craw = clwm;
+
+      if(clwm < (1024-cbs+8)) clwm = 1024-cbs+8;
+      data = (int)(clwm);
+      /*  printf("CRT LWM: %f bytes, prog: 0x%x, bs: 256\n", clwm, data ); */
+      fifo->graphics_lwm = data;   fifo->graphics_burst_size = cbs;
+
+      /*  printf("VID LWM: %f bytes, prog: 0x%x, bs: %d\n, ", vlwm, data, vbs ); */
+      fifo->video_lwm = 1024;  fifo->video_burst_size = 512;
+    }
+}
+static void nv10UpdateArbitrationSettings
+(
+    unsigned      VClk, 
+    unsigned      pixelDepth, 
+    unsigned     *burst,
+    unsigned     *lwm,
+    RIVA_HW_INST *chip
+)
+{
+    nv10_fifo_info fifo_data;
+    nv10_sim_state sim_data;
+    unsigned int M, N, P, pll, MClk, NVClk, cfg1;
+
+    pll = NV_RD32(&chip->PRAMDAC0[0x00000504/4], 0);
+    M = (pll >> 0)  & 0xFF; N = (pll >> 8)  & 0xFF; P = (pll >> 16) & 0x0F;
+    MClk  = (N * chip->CrystalFreqKHz / M) >> P;
+    pll = NV_RD32(&chip->PRAMDAC0[0x00000500/4], 0);
+    M = (pll >> 0)  & 0xFF; N = (pll >> 8)  & 0xFF; P = (pll >> 16) & 0x0F;
+    NVClk  = (N * chip->CrystalFreqKHz / M) >> P;
+    cfg1 = NV_RD32(&chip->PFB[0x00000204/4], 0);
+    sim_data.pix_bpp        = (char)pixelDepth;
+    sim_data.enable_video   = 0;
+    sim_data.enable_mp      = 0;
+    sim_data.memory_type    = (NV_RD32(&chip->PFB[0x00000200/4], 0) & 0x01) ?
+	1 : 0;
+    sim_data.memory_width   = (NV_RD32(&chip->PEXTDEV[0x00000000/4], 0) & 0x10) ?
+	128 : 64;
+    sim_data.mem_latency    = (char)cfg1 & 0x0F;
+    sim_data.mem_aligned    = 1;
+    sim_data.mem_page_miss  = (char)(((cfg1 >> 4) &0x0F) + ((cfg1 >> 31) & 0x01));
+    sim_data.gr_during_vid  = 0;
+    sim_data.pclk_khz       = VClk;
+    sim_data.mclk_khz       = MClk;
+    sim_data.nvclk_khz      = NVClk;
+    nv10CalcArbitration(&fifo_data, &sim_data);
+    if (fifo_data.valid)
+    {
+        int  b = fifo_data.graphics_burst_size >> 4;
+        *burst = 0;
+        while (b >>= 1)
+	    (*burst)++;
+        *lwm   = fifo_data.graphics_lwm >> 3;
+    }
+}
+
+static void nForceUpdateArbitrationSettings
+(
+    unsigned      VClk,
+    unsigned      pixelDepth,
+    unsigned     *burst,
+    unsigned     *lwm,
+    RIVA_HW_INST *chip
+)
+{
+    nv10_fifo_info fifo_data;
+    nv10_sim_state sim_data;
+    unsigned int M, N, P, pll, MClk, NVClk;
+    unsigned int uMClkPostDiv;
+    struct pci_dev *dev;
+
+    dev = pci_find_slot(0, 3);
+    pci_read_config_dword(dev, 0x6C, &uMClkPostDiv);
+    uMClkPostDiv = (uMClkPostDiv >> 8) & 0xf;
+
+    if(!uMClkPostDiv) uMClkPostDiv = 4;
+    MClk = 400000 / uMClkPostDiv;
+
+    pll = NV_RD32(&chip->PRAMDAC0[0x00000500/4], 0);
+    M = (pll >> 0)  & 0xFF; N = (pll >> 8)  & 0xFF; P = (pll >> 16) & 0x0F;
+    NVClk  = (N * chip->CrystalFreqKHz / M) >> P;
+    sim_data.pix_bpp        = (char)pixelDepth;
+    sim_data.enable_video   = 0;
+    sim_data.enable_mp      = 0;
+
+    dev = pci_find_slot(0, 1);
+    pci_read_config_dword(dev, 0x7C, &sim_data.memory_type);
+    sim_data.memory_type    = (sim_data.memory_type >> 12) & 1;
+
+    sim_data.memory_width   = 64;
+    sim_data.mem_latency    = 3;
+    sim_data.mem_aligned    = 1;
+    sim_data.mem_page_miss  = 10;
+    sim_data.gr_during_vid  = 0;
+    sim_data.pclk_khz       = VClk;
+    sim_data.mclk_khz       = MClk;
+    sim_data.nvclk_khz      = NVClk;
+    nv10CalcArbitration(&fifo_data, &sim_data);
+    if (fifo_data.valid)
+    {
+        int  b = fifo_data.graphics_burst_size >> 4;
+        *burst = 0;
+        while (b >>= 1)
+	    (*burst)++;
+        *lwm   = fifo_data.graphics_lwm >> 3;
+    }
+}
+
+/****************************************************************************\
+*                                                                            *
+*                          RIVA Mode State Routines                          *
+*                                                                            *
+\****************************************************************************/
+
+/*
+ * Calculate the Video Clock parameters for the PLL.
+ */
+static int CalcVClock
+(
+    int           clockIn,
+    int          *clockOut,
+    int          *mOut,
+    int          *nOut,
+    int          *pOut,
+    RIVA_HW_INST *chip
+)
+{
+    unsigned lowM, highM, highP;
+    unsigned DeltaNew, DeltaOld;
+    unsigned VClk, Freq;
+    unsigned M, N, P;
+    
+    DeltaOld = 0xFFFFFFFF;
+
+    VClk     = (unsigned)clockIn;
+    
+    if (chip->CrystalFreqKHz == 13500)
+    {
+        lowM  = 7;
+        highM = 13 - (chip->Architecture == NV_ARCH_03);
+    }
+    else
+    {
+        lowM  = 8;
+        highM = 14 - (chip->Architecture == NV_ARCH_03);
+    }                      
+
+    highP = 4 - (chip->Architecture == NV_ARCH_03);
+    for (P = 0; P <= highP; P ++)
+    {
+        Freq = VClk << P;
+        if ((Freq >= 128000) && (Freq <= chip->MaxVClockFreqKHz))
+        {
+            for (M = lowM; M <= highM; M++)
+            {
+                N    = (VClk << P) * M / chip->CrystalFreqKHz;
+                if(N <= 255) {
+                Freq = (chip->CrystalFreqKHz * N / M) >> P;
+                if (Freq > VClk)
+                    DeltaNew = Freq - VClk;
+                else
+                    DeltaNew = VClk - Freq;
+                if (DeltaNew < DeltaOld)
+                {
+                    *mOut     = M;
+                    *nOut     = N;
+                    *pOut     = P;
+                    *clockOut = Freq;
+                    DeltaOld  = DeltaNew;
+                }
+            }
+        }
+    }
+    }
+    return (DeltaOld != 0xFFFFFFFF);
+}
+/*
+ * Calculate extended mode parameters (SVGA) and save in a 
+ * mode state structure.
+ */
+static void CalcStateExt
+(
+    RIVA_HW_INST  *chip,
+    RIVA_HW_STATE *state,
+    int            bpp,
+    int            width,
+    int            hDisplaySize,
+    int            height,
+    int            dotClock
+)
+{
+    int pixelDepth, VClk, m, n, p;
+    /*
+     * Save mode parameters.
+     */
+    state->bpp    = bpp;    /* this is not bitsPerPixel, it's 8,15,16,32 */
+    state->width  = width;
+    state->height = height;
+    /*
+     * Extended RIVA registers.
+     */
+    pixelDepth = (bpp + 1)/8;
+    CalcVClock(dotClock, &VClk, &m, &n, &p, chip);
+
+    switch (chip->Architecture)
+    {
+        case NV_ARCH_03:
+            nv3UpdateArbitrationSettings(VClk, 
+                                         pixelDepth * 8, 
+                                        &(state->arbitration0),
+                                        &(state->arbitration1),
+                                         chip);
+            state->cursor0  = 0x00;
+            state->cursor1  = 0x78;
+            state->cursor2  = 0x00000000;
+            state->pllsel   = 0x10010100;
+            state->config   = ((width + 31)/32)
+                            | (((pixelDepth > 2) ? 3 : pixelDepth) << 8)
+                            | 0x1000;
+            state->general  = 0x00100100;
+            state->repaint1 = hDisplaySize < 1280 ? 0x06 : 0x02;
+            break;
+        case NV_ARCH_04:
+            nv4UpdateArbitrationSettings(VClk, 
+                                         pixelDepth * 8, 
+                                        &(state->arbitration0),
+                                        &(state->arbitration1),
+                                         chip);
+            state->cursor0  = 0x00;
+            state->cursor1  = 0xFC;
+            state->cursor2  = 0x00000000;
+            state->pllsel   = 0x10000700;
+            state->config   = 0x00001114;
+            state->general  = bpp == 16 ? 0x00101100 : 0x00100100;
+            state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00;
+            break;
+        case NV_ARCH_10:
+        case NV_ARCH_20:
+        case NV_ARCH_30:
+            if((chip->Chipset == NV_CHIP_IGEFORCE2) ||
+               (chip->Chipset == NV_CHIP_0x01F0))
+            {
+                nForceUpdateArbitrationSettings(VClk,
+                                          pixelDepth * 8,
+                                         &(state->arbitration0),
+                                         &(state->arbitration1),
+                                          chip);
+            } else {
+                nv10UpdateArbitrationSettings(VClk, 
+                                          pixelDepth * 8, 
+                                         &(state->arbitration0),
+                                         &(state->arbitration1),
+                                          chip);
+            }
+            state->cursor0  = 0x80 | (chip->CursorStart >> 17);
+            state->cursor1  = (chip->CursorStart >> 11) << 2;
+            state->cursor2  = chip->CursorStart >> 24;
+            state->pllsel   = 0x10000700;
+            state->config   = NV_RD32(&chip->PFB[0x00000200/4], 0);
+            state->general  = bpp == 16 ? 0x00101100 : 0x00100100;
+            state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00;
+            break;
+    }
+
+     /* Paul Richards: below if block borks things in kernel for some reason */
+     /* Tony: Below is needed to set hardware in DirectColor */
+    if((bpp != 8) && (chip->Architecture != NV_ARCH_03))
+	    state->general |= 0x00000030;
+
+    state->vpll     = (p << 16) | (n << 8) | m;
+    state->repaint0 = (((width/8)*pixelDepth) & 0x700) >> 3;
+    state->pixel    = pixelDepth > 2   ? 3    : pixelDepth;
+    state->offset0  =
+    state->offset1  =
+    state->offset2  =
+    state->offset3  = 0;
+    state->pitch0   =
+    state->pitch1   =
+    state->pitch2   =
+    state->pitch3   = pixelDepth * width;
+}
+/*
+ * Load fixed function state and pre-calculated/stored state.
+ */
+#if 0
+#define LOAD_FIXED_STATE(tbl,dev)                                       \
+    for (i = 0; i < sizeof(tbl##Table##dev)/8; i++)                 \
+        chip->dev[tbl##Table##dev[i][0]] = tbl##Table##dev[i][1]
+#define LOAD_FIXED_STATE_8BPP(tbl,dev)                                  \
+    for (i = 0; i < sizeof(tbl##Table##dev##_8BPP)/8; i++)            \
+        chip->dev[tbl##Table##dev##_8BPP[i][0]] = tbl##Table##dev##_8BPP[i][1]
+#define LOAD_FIXED_STATE_15BPP(tbl,dev)                                 \
+    for (i = 0; i < sizeof(tbl##Table##dev##_15BPP)/8; i++)           \
+        chip->dev[tbl##Table##dev##_15BPP[i][0]] = tbl##Table##dev##_15BPP[i][1]
+#define LOAD_FIXED_STATE_16BPP(tbl,dev)                                 \
+    for (i = 0; i < sizeof(tbl##Table##dev##_16BPP)/8; i++)           \
+        chip->dev[tbl##Table##dev##_16BPP[i][0]] = tbl##Table##dev##_16BPP[i][1]
+#define LOAD_FIXED_STATE_32BPP(tbl,dev)                                 \
+    for (i = 0; i < sizeof(tbl##Table##dev##_32BPP)/8; i++)           \
+        chip->dev[tbl##Table##dev##_32BPP[i][0]] = tbl##Table##dev##_32BPP[i][1]
+#endif
+
+#define LOAD_FIXED_STATE(tbl,dev)                                       \
+    for (i = 0; i < sizeof(tbl##Table##dev)/8; i++)                 \
+        NV_WR32(&chip->dev[tbl##Table##dev[i][0]], 0, tbl##Table##dev[i][1])
+#define LOAD_FIXED_STATE_8BPP(tbl,dev)                                  \
+    for (i = 0; i < sizeof(tbl##Table##dev##_8BPP)/8; i++)            \
+        NV_WR32(&chip->dev[tbl##Table##dev##_8BPP[i][0]], 0, tbl##Table##dev##_8BPP[i][1])
+#define LOAD_FIXED_STATE_15BPP(tbl,dev)                                 \
+    for (i = 0; i < sizeof(tbl##Table##dev##_15BPP)/8; i++)           \
+        NV_WR32(&chip->dev[tbl##Table##dev##_15BPP[i][0]], 0, tbl##Table##dev##_15BPP[i][1])
+#define LOAD_FIXED_STATE_16BPP(tbl,dev)                                 \
+    for (i = 0; i < sizeof(tbl##Table##dev##_16BPP)/8; i++)           \
+        NV_WR32(&chip->dev[tbl##Table##dev##_16BPP[i][0]], 0, tbl##Table##dev##_16BPP[i][1])
+#define LOAD_FIXED_STATE_32BPP(tbl,dev)                                 \
+    for (i = 0; i < sizeof(tbl##Table##dev##_32BPP)/8; i++)           \
+        NV_WR32(&chip->dev[tbl##Table##dev##_32BPP[i][0]], 0, tbl##Table##dev##_32BPP[i][1])
+
+static void UpdateFifoState
+(
+    RIVA_HW_INST  *chip
+)
+{
+    int i;
+
+    switch (chip->Architecture)
+    {
+        case NV_ARCH_04:
+            LOAD_FIXED_STATE(nv4,FIFO);
+            chip->Tri03 = NULL;
+            chip->Tri05 = (RivaTexturedTriangle05 __iomem *)&(chip->FIFO[0x0000E000/4]);
+            break;
+        case NV_ARCH_10:
+        case NV_ARCH_20:
+        case NV_ARCH_30:
+            /*
+             * Initialize state for the RivaTriangle3D05 routines.
+             */
+            LOAD_FIXED_STATE(nv10tri05,PGRAPH);
+            LOAD_FIXED_STATE(nv10,FIFO);
+            chip->Tri03 = NULL;
+            chip->Tri05 = (RivaTexturedTriangle05 __iomem *)&(chip->FIFO[0x0000E000/4]);
+            break;
+    }
+}
+static void LoadStateExt
+(
+    RIVA_HW_INST  *chip,
+    RIVA_HW_STATE *state
+)
+{
+    int i;
+
+    /*
+     * Load HW fixed function state.
+     */
+    LOAD_FIXED_STATE(Riva,PMC);
+    LOAD_FIXED_STATE(Riva,PTIMER);
+    switch (chip->Architecture)
+    {
+        case NV_ARCH_03:
+            /*
+             * Make sure frame buffer config gets set before loading PRAMIN.
+             */
+            NV_WR32(chip->PFB, 0x00000200, state->config);
+            LOAD_FIXED_STATE(nv3,PFIFO);
+            LOAD_FIXED_STATE(nv3,PRAMIN);
+            LOAD_FIXED_STATE(nv3,PGRAPH);
+            switch (state->bpp)
+            {
+                case 15:
+                case 16:
+                    LOAD_FIXED_STATE_15BPP(nv3,PRAMIN);
+                    LOAD_FIXED_STATE_15BPP(nv3,PGRAPH);
+                    chip->Tri03 = (RivaTexturedTriangle03  __iomem *)&(chip->FIFO[0x0000E000/4]);
+                    break;
+                case 24:
+                case 32:
+                    LOAD_FIXED_STATE_32BPP(nv3,PRAMIN);
+                    LOAD_FIXED_STATE_32BPP(nv3,PGRAPH);
+                    chip->Tri03 = NULL;
+                    break;
+                case 8:
+                default:
+                    LOAD_FIXED_STATE_8BPP(nv3,PRAMIN);
+                    LOAD_FIXED_STATE_8BPP(nv3,PGRAPH);
+                    chip->Tri03 = NULL;
+                    break;
+            }
+            for (i = 0x00000; i < 0x00800; i++)
+                NV_WR32(&chip->PRAMIN[0x00000502 + i], 0, (i << 12) | 0x03);
+            NV_WR32(chip->PGRAPH, 0x00000630, state->offset0);
+            NV_WR32(chip->PGRAPH, 0x00000634, state->offset1);
+            NV_WR32(chip->PGRAPH, 0x00000638, state->offset2);
+            NV_WR32(chip->PGRAPH, 0x0000063C, state->offset3);
+            NV_WR32(chip->PGRAPH, 0x00000650, state->pitch0);
+            NV_WR32(chip->PGRAPH, 0x00000654, state->pitch1);
+            NV_WR32(chip->PGRAPH, 0x00000658, state->pitch2);
+            NV_WR32(chip->PGRAPH, 0x0000065C, state->pitch3);
+            break;
+        case NV_ARCH_04:
+            /*
+             * Make sure frame buffer config gets set before loading PRAMIN.
+             */
+            NV_WR32(chip->PFB, 0x00000200, state->config);
+            LOAD_FIXED_STATE(nv4,PFIFO);
+            LOAD_FIXED_STATE(nv4,PRAMIN);
+            LOAD_FIXED_STATE(nv4,PGRAPH);
+            switch (state->bpp)
+            {
+                case 15:
+                    LOAD_FIXED_STATE_15BPP(nv4,PRAMIN);
+                    LOAD_FIXED_STATE_15BPP(nv4,PGRAPH);
+                    chip->Tri03 = (RivaTexturedTriangle03  __iomem *)&(chip->FIFO[0x0000E000/4]);
+                    break;
+                case 16:
+                    LOAD_FIXED_STATE_16BPP(nv4,PRAMIN);
+                    LOAD_FIXED_STATE_16BPP(nv4,PGRAPH);
+                    chip->Tri03 = (RivaTexturedTriangle03  __iomem *)&(chip->FIFO[0x0000E000/4]);
+                    break;
+                case 24:
+                case 32:
+                    LOAD_FIXED_STATE_32BPP(nv4,PRAMIN);
+                    LOAD_FIXED_STATE_32BPP(nv4,PGRAPH);
+                    chip->Tri03 = NULL;
+                    break;
+                case 8:
+                default:
+                    LOAD_FIXED_STATE_8BPP(nv4,PRAMIN);
+                    LOAD_FIXED_STATE_8BPP(nv4,PGRAPH);
+                    chip->Tri03 = NULL;
+                    break;
+            }
+            NV_WR32(chip->PGRAPH, 0x00000640, state->offset0);
+            NV_WR32(chip->PGRAPH, 0x00000644, state->offset1);
+            NV_WR32(chip->PGRAPH, 0x00000648, state->offset2);
+            NV_WR32(chip->PGRAPH, 0x0000064C, state->offset3);
+            NV_WR32(chip->PGRAPH, 0x00000670, state->pitch0);
+            NV_WR32(chip->PGRAPH, 0x00000674, state->pitch1);
+            NV_WR32(chip->PGRAPH, 0x00000678, state->pitch2);
+            NV_WR32(chip->PGRAPH, 0x0000067C, state->pitch3);
+            break;
+        case NV_ARCH_10:
+        case NV_ARCH_20:
+        case NV_ARCH_30:
+            if(chip->twoHeads) {
+               VGA_WR08(chip->PCIO, 0x03D4, 0x44);
+               VGA_WR08(chip->PCIO, 0x03D5, state->crtcOwner);
+               chip->LockUnlock(chip, 0);
+            }
+
+            LOAD_FIXED_STATE(nv10,PFIFO);
+            LOAD_FIXED_STATE(nv10,PRAMIN);
+            LOAD_FIXED_STATE(nv10,PGRAPH);
+            switch (state->bpp)
+            {
+                case 15:
+                    LOAD_FIXED_STATE_15BPP(nv10,PRAMIN);
+                    LOAD_FIXED_STATE_15BPP(nv10,PGRAPH);
+                    chip->Tri03 = (RivaTexturedTriangle03  __iomem *)&(chip->FIFO[0x0000E000/4]);
+                    break;
+                case 16:
+                    LOAD_FIXED_STATE_16BPP(nv10,PRAMIN);
+                    LOAD_FIXED_STATE_16BPP(nv10,PGRAPH);
+                    chip->Tri03 = (RivaTexturedTriangle03  __iomem *)&(chip->FIFO[0x0000E000/4]);
+                    break;
+                case 24:
+                case 32:
+                    LOAD_FIXED_STATE_32BPP(nv10,PRAMIN);
+                    LOAD_FIXED_STATE_32BPP(nv10,PGRAPH);
+                    chip->Tri03 = NULL;
+                    break;
+                case 8:
+                default:
+                    LOAD_FIXED_STATE_8BPP(nv10,PRAMIN);
+                    LOAD_FIXED_STATE_8BPP(nv10,PGRAPH);
+                    chip->Tri03 = NULL;
+                    break;
+            }
+
+            if(chip->Architecture == NV_ARCH_10) {
+                NV_WR32(chip->PGRAPH, 0x00000640, state->offset0);
+                NV_WR32(chip->PGRAPH, 0x00000644, state->offset1);
+                NV_WR32(chip->PGRAPH, 0x00000648, state->offset2);
+                NV_WR32(chip->PGRAPH, 0x0000064C, state->offset3);
+                NV_WR32(chip->PGRAPH, 0x00000670, state->pitch0);
+                NV_WR32(chip->PGRAPH, 0x00000674, state->pitch1);
+                NV_WR32(chip->PGRAPH, 0x00000678, state->pitch2);
+                NV_WR32(chip->PGRAPH, 0x0000067C, state->pitch3);
+                NV_WR32(chip->PGRAPH, 0x00000680, state->pitch3);
+        } else {
+        NV_WR32(chip->PGRAPH, 0x00000820, state->offset0);
+        NV_WR32(chip->PGRAPH, 0x00000824, state->offset1);
+        NV_WR32(chip->PGRAPH, 0x00000828, state->offset2);
+        NV_WR32(chip->PGRAPH, 0x0000082C, state->offset3);
+        NV_WR32(chip->PGRAPH, 0x00000850, state->pitch0);
+        NV_WR32(chip->PGRAPH, 0x00000854, state->pitch1);
+        NV_WR32(chip->PGRAPH, 0x00000858, state->pitch2);
+        NV_WR32(chip->PGRAPH, 0x0000085C, state->pitch3);
+        NV_WR32(chip->PGRAPH, 0x00000860, state->pitch3);
+        NV_WR32(chip->PGRAPH, 0x00000864, state->pitch3);
+        NV_WR32(chip->PGRAPH, 0x000009A4, NV_RD32(chip->PFB, 0x00000200));
+        NV_WR32(chip->PGRAPH, 0x000009A8, NV_RD32(chip->PFB, 0x00000204));
+        }
+            if(chip->twoHeads) {
+               NV_WR32(chip->PCRTC0, 0x00000860, state->head);
+               NV_WR32(chip->PCRTC0, 0x00002860, state->head2);
+            }
+            NV_WR32(chip->PRAMDAC, 0x00000404, NV_RD32(chip->PRAMDAC, 0x00000404) | (1 << 25));
+
+            NV_WR32(chip->PMC, 0x00008704, 1);
+            NV_WR32(chip->PMC, 0x00008140, 0);
+            NV_WR32(chip->PMC, 0x00008920, 0);
+            NV_WR32(chip->PMC, 0x00008924, 0);
+            NV_WR32(chip->PMC, 0x00008908, 0x01ffffff);
+            NV_WR32(chip->PMC, 0x0000890C, 0x01ffffff);
+            NV_WR32(chip->PMC, 0x00001588, 0);
+
+            NV_WR32(chip->PFB, 0x00000240, 0);
+            NV_WR32(chip->PFB, 0x00000250, 0);
+            NV_WR32(chip->PFB, 0x00000260, 0);
+            NV_WR32(chip->PFB, 0x00000270, 0);
+            NV_WR32(chip->PFB, 0x00000280, 0);
+            NV_WR32(chip->PFB, 0x00000290, 0);
+            NV_WR32(chip->PFB, 0x000002A0, 0);
+            NV_WR32(chip->PFB, 0x000002B0, 0);
+
+            NV_WR32(chip->PGRAPH, 0x00000B00, NV_RD32(chip->PFB, 0x00000240));
+            NV_WR32(chip->PGRAPH, 0x00000B04, NV_RD32(chip->PFB, 0x00000244));
+            NV_WR32(chip->PGRAPH, 0x00000B08, NV_RD32(chip->PFB, 0x00000248));
+            NV_WR32(chip->PGRAPH, 0x00000B0C, NV_RD32(chip->PFB, 0x0000024C));
+            NV_WR32(chip->PGRAPH, 0x00000B10, NV_RD32(chip->PFB, 0x00000250));
+            NV_WR32(chip->PGRAPH, 0x00000B14, NV_RD32(chip->PFB, 0x00000254));
+            NV_WR32(chip->PGRAPH, 0x00000B18, NV_RD32(chip->PFB, 0x00000258));
+            NV_WR32(chip->PGRAPH, 0x00000B1C, NV_RD32(chip->PFB, 0x0000025C));
+            NV_WR32(chip->PGRAPH, 0x00000B20, NV_RD32(chip->PFB, 0x00000260));
+            NV_WR32(chip->PGRAPH, 0x00000B24, NV_RD32(chip->PFB, 0x00000264));
+            NV_WR32(chip->PGRAPH, 0x00000B28, NV_RD32(chip->PFB, 0x00000268));
+            NV_WR32(chip->PGRAPH, 0x00000B2C, NV_RD32(chip->PFB, 0x0000026C));
+            NV_WR32(chip->PGRAPH, 0x00000B30, NV_RD32(chip->PFB, 0x00000270));
+            NV_WR32(chip->PGRAPH, 0x00000B34, NV_RD32(chip->PFB, 0x00000274));
+            NV_WR32(chip->PGRAPH, 0x00000B38, NV_RD32(chip->PFB, 0x00000278));
+            NV_WR32(chip->PGRAPH, 0x00000B3C, NV_RD32(chip->PFB, 0x0000027C));
+            NV_WR32(chip->PGRAPH, 0x00000B40, NV_RD32(chip->PFB, 0x00000280));
+            NV_WR32(chip->PGRAPH, 0x00000B44, NV_RD32(chip->PFB, 0x00000284));
+            NV_WR32(chip->PGRAPH, 0x00000B48, NV_RD32(chip->PFB, 0x00000288));
+            NV_WR32(chip->PGRAPH, 0x00000B4C, NV_RD32(chip->PFB, 0x0000028C));
+            NV_WR32(chip->PGRAPH, 0x00000B50, NV_RD32(chip->PFB, 0x00000290));
+            NV_WR32(chip->PGRAPH, 0x00000B54, NV_RD32(chip->PFB, 0x00000294));
+            NV_WR32(chip->PGRAPH, 0x00000B58, NV_RD32(chip->PFB, 0x00000298));
+            NV_WR32(chip->PGRAPH, 0x00000B5C, NV_RD32(chip->PFB, 0x0000029C));
+            NV_WR32(chip->PGRAPH, 0x00000B60, NV_RD32(chip->PFB, 0x000002A0));
+            NV_WR32(chip->PGRAPH, 0x00000B64, NV_RD32(chip->PFB, 0x000002A4));
+            NV_WR32(chip->PGRAPH, 0x00000B68, NV_RD32(chip->PFB, 0x000002A8));
+            NV_WR32(chip->PGRAPH, 0x00000B6C, NV_RD32(chip->PFB, 0x000002AC));
+            NV_WR32(chip->PGRAPH, 0x00000B70, NV_RD32(chip->PFB, 0x000002B0));
+            NV_WR32(chip->PGRAPH, 0x00000B74, NV_RD32(chip->PFB, 0x000002B4));
+            NV_WR32(chip->PGRAPH, 0x00000B78, NV_RD32(chip->PFB, 0x000002B8));
+            NV_WR32(chip->PGRAPH, 0x00000B7C, NV_RD32(chip->PFB, 0x000002BC));
+            NV_WR32(chip->PGRAPH, 0x00000F40, 0x10000000);
+            NV_WR32(chip->PGRAPH, 0x00000F44, 0x00000000);
+            NV_WR32(chip->PGRAPH, 0x00000F50, 0x00000040);
+            NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000008);
+            NV_WR32(chip->PGRAPH, 0x00000F50, 0x00000200);
+            for (i = 0; i < (3*16); i++)
+                NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000000);
+            NV_WR32(chip->PGRAPH, 0x00000F50, 0x00000040);
+            NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000000);
+            NV_WR32(chip->PGRAPH, 0x00000F50, 0x00000800);
+            for (i = 0; i < (16*16); i++)
+                NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000000);
+            NV_WR32(chip->PGRAPH, 0x00000F40, 0x30000000);
+            NV_WR32(chip->PGRAPH, 0x00000F44, 0x00000004);
+            NV_WR32(chip->PGRAPH, 0x00000F50, 0x00006400);
+            for (i = 0; i < (59*4); i++)
+                NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000000);
+            NV_WR32(chip->PGRAPH, 0x00000F50, 0x00006800);
+            for (i = 0; i < (47*4); i++)
+                NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000000);
+            NV_WR32(chip->PGRAPH, 0x00000F50, 0x00006C00);
+            for (i = 0; i < (3*4); i++)
+                NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000000);
+            NV_WR32(chip->PGRAPH, 0x00000F50, 0x00007000);
+            for (i = 0; i < (19*4); i++)
+                NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000000);
+            NV_WR32(chip->PGRAPH, 0x00000F50, 0x00007400);
+            for (i = 0; i < (12*4); i++)
+                NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000000);
+            NV_WR32(chip->PGRAPH, 0x00000F50, 0x00007800);
+            for (i = 0; i < (12*4); i++)
+                NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000000);
+            NV_WR32(chip->PGRAPH, 0x00000F50, 0x00004400);
+            for (i = 0; i < (8*4); i++)
+                NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000000);
+            NV_WR32(chip->PGRAPH, 0x00000F50, 0x00000000);
+            for (i = 0; i < 16; i++)
+                NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000000);
+            NV_WR32(chip->PGRAPH, 0x00000F50, 0x00000040);
+            for (i = 0; i < 4; i++)
+                NV_WR32(chip->PGRAPH, 0x00000F54, 0x00000000);
+
+            NV_WR32(chip->PCRTC, 0x00000810, state->cursorConfig);
+
+            if(chip->flatPanel) {
+               if((chip->Chipset & 0x0ff0) == 0x0110) {
+                   NV_WR32(chip->PRAMDAC, 0x0528, state->dither);
+               } else 
+               if((chip->Chipset & 0x0ff0) >= 0x0170) {
+                   NV_WR32(chip->PRAMDAC, 0x083C, state->dither);
+               }
+            
+               VGA_WR08(chip->PCIO, 0x03D4, 0x53);
+               VGA_WR08(chip->PCIO, 0x03D5, 0);
+               VGA_WR08(chip->PCIO, 0x03D4, 0x54);
+               VGA_WR08(chip->PCIO, 0x03D5, 0);
+               VGA_WR08(chip->PCIO, 0x03D4, 0x21);
+               VGA_WR08(chip->PCIO, 0x03D5, 0xfa);
+            }
+
+            VGA_WR08(chip->PCIO, 0x03D4, 0x41);
+            VGA_WR08(chip->PCIO, 0x03D5, state->extra);
+    }
+    LOAD_FIXED_STATE(Riva,FIFO);
+    UpdateFifoState(chip);
+    /*
+     * Load HW mode state.
+     */
+    VGA_WR08(chip->PCIO, 0x03D4, 0x19);
+    VGA_WR08(chip->PCIO, 0x03D5, state->repaint0);
+    VGA_WR08(chip->PCIO, 0x03D4, 0x1A);
+    VGA_WR08(chip->PCIO, 0x03D5, state->repaint1);
+    VGA_WR08(chip->PCIO, 0x03D4, 0x25);
+    VGA_WR08(chip->PCIO, 0x03D5, state->screen);
+    VGA_WR08(chip->PCIO, 0x03D4, 0x28);
+    VGA_WR08(chip->PCIO, 0x03D5, state->pixel);
+    VGA_WR08(chip->PCIO, 0x03D4, 0x2D);
+    VGA_WR08(chip->PCIO, 0x03D5, state->horiz);
+    VGA_WR08(chip->PCIO, 0x03D4, 0x1B);
+    VGA_WR08(chip->PCIO, 0x03D5, state->arbitration0);
+    VGA_WR08(chip->PCIO, 0x03D4, 0x20);
+    VGA_WR08(chip->PCIO, 0x03D5, state->arbitration1);
+    VGA_WR08(chip->PCIO, 0x03D4, 0x30);
+    VGA_WR08(chip->PCIO, 0x03D5, state->cursor0);
+    VGA_WR08(chip->PCIO, 0x03D4, 0x31);
+    VGA_WR08(chip->PCIO, 0x03D5, state->cursor1);
+    VGA_WR08(chip->PCIO, 0x03D4, 0x2F);
+    VGA_WR08(chip->PCIO, 0x03D5, state->cursor2);
+    VGA_WR08(chip->PCIO, 0x03D4, 0x39);
+    VGA_WR08(chip->PCIO, 0x03D5, state->interlace);
+
+    if(!chip->flatPanel) {
+       NV_WR32(chip->PRAMDAC0, 0x00000508, state->vpll);
+       NV_WR32(chip->PRAMDAC0, 0x0000050C, state->pllsel);
+       if(chip->twoHeads)
+          NV_WR32(chip->PRAMDAC0, 0x00000520, state->vpll2);
+    }  else {
+       NV_WR32(chip->PRAMDAC, 0x00000848 , state->scale);
+    }  
+    NV_WR32(chip->PRAMDAC, 0x00000600 , state->general);
+
+    /*
+     * Turn off VBlank enable and reset.
+     */
+    NV_WR32(chip->PCRTC, 0x00000140, 0);
+    NV_WR32(chip->PCRTC, 0x00000100, chip->VBlankBit);
+    /*
+     * Set interrupt enable.
+     */    
+    NV_WR32(chip->PMC, 0x00000140, chip->EnableIRQ & 0x01);
+    /*
+     * Set current state pointer.
+     */
+    chip->CurrentState = state;
+    /*
+     * Reset FIFO free and empty counts.
+     */
+    chip->FifoFreeCount  = 0;
+    /* Free count from first subchannel */
+    chip->FifoEmptyCount = NV_RD32(&chip->Rop->FifoFree, 0);
+}
+static void UnloadStateExt
+(
+    RIVA_HW_INST  *chip,
+    RIVA_HW_STATE *state
+)
+{
+    /*
+     * Save current HW state.
+     */
+    VGA_WR08(chip->PCIO, 0x03D4, 0x19);
+    state->repaint0     = VGA_RD08(chip->PCIO, 0x03D5);
+    VGA_WR08(chip->PCIO, 0x03D4, 0x1A);
+    state->repaint1     = VGA_RD08(chip->PCIO, 0x03D5);
+    VGA_WR08(chip->PCIO, 0x03D4, 0x25);
+    state->screen       = VGA_RD08(chip->PCIO, 0x03D5);
+    VGA_WR08(chip->PCIO, 0x03D4, 0x28);
+    state->pixel        = VGA_RD08(chip->PCIO, 0x03D5);
+    VGA_WR08(chip->PCIO, 0x03D4, 0x2D);
+    state->horiz        = VGA_RD08(chip->PCIO, 0x03D5);
+    VGA_WR08(chip->PCIO, 0x03D4, 0x1B);
+    state->arbitration0 = VGA_RD08(chip->PCIO, 0x03D5);
+    VGA_WR08(chip->PCIO, 0x03D4, 0x20);
+    state->arbitration1 = VGA_RD08(chip->PCIO, 0x03D5);
+    VGA_WR08(chip->PCIO, 0x03D4, 0x30);
+    state->cursor0      = VGA_RD08(chip->PCIO, 0x03D5);
+    VGA_WR08(chip->PCIO, 0x03D4, 0x31);
+    state->cursor1      = VGA_RD08(chip->PCIO, 0x03D5);
+    VGA_WR08(chip->PCIO, 0x03D4, 0x2F);
+    state->cursor2      = VGA_RD08(chip->PCIO, 0x03D5);
+    VGA_WR08(chip->PCIO, 0x03D4, 0x39);
+    state->interlace    = VGA_RD08(chip->PCIO, 0x03D5);
+    state->vpll         = NV_RD32(chip->PRAMDAC0, 0x00000508);
+    state->vpll2        = NV_RD32(chip->PRAMDAC0, 0x00000520);
+    state->pllsel       = NV_RD32(chip->PRAMDAC0, 0x0000050C);
+    state->general      = NV_RD32(chip->PRAMDAC, 0x00000600);
+    state->scale        = NV_RD32(chip->PRAMDAC, 0x00000848);
+    state->config       = NV_RD32(chip->PFB, 0x00000200);
+    switch (chip->Architecture)
+    {
+        case NV_ARCH_03:
+            state->offset0  = NV_RD32(chip->PGRAPH, 0x00000630);
+            state->offset1  = NV_RD32(chip->PGRAPH, 0x00000634);
+            state->offset2  = NV_RD32(chip->PGRAPH, 0x00000638);
+            state->offset3  = NV_RD32(chip->PGRAPH, 0x0000063C);
+            state->pitch0   = NV_RD32(chip->PGRAPH, 0x00000650);
+            state->pitch1   = NV_RD32(chip->PGRAPH, 0x00000654);
+            state->pitch2   = NV_RD32(chip->PGRAPH, 0x00000658);
+            state->pitch3   = NV_RD32(chip->PGRAPH, 0x0000065C);
+            break;
+        case NV_ARCH_04:
+            state->offset0  = NV_RD32(chip->PGRAPH, 0x00000640);
+            state->offset1  = NV_RD32(chip->PGRAPH, 0x00000644);
+            state->offset2  = NV_RD32(chip->PGRAPH, 0x00000648);
+            state->offset3  = NV_RD32(chip->PGRAPH, 0x0000064C);
+            state->pitch0   = NV_RD32(chip->PGRAPH, 0x00000670);
+            state->pitch1   = NV_RD32(chip->PGRAPH, 0x00000674);
+            state->pitch2   = NV_RD32(chip->PGRAPH, 0x00000678);
+            state->pitch3   = NV_RD32(chip->PGRAPH, 0x0000067C);
+            break;
+        case NV_ARCH_10:
+        case NV_ARCH_20:
+        case NV_ARCH_30:
+            state->offset0  = NV_RD32(chip->PGRAPH, 0x00000640);
+            state->offset1  = NV_RD32(chip->PGRAPH, 0x00000644);
+            state->offset2  = NV_RD32(chip->PGRAPH, 0x00000648);
+            state->offset3  = NV_RD32(chip->PGRAPH, 0x0000064C);
+            state->pitch0   = NV_RD32(chip->PGRAPH, 0x00000670);
+            state->pitch1   = NV_RD32(chip->PGRAPH, 0x00000674);
+            state->pitch2   = NV_RD32(chip->PGRAPH, 0x00000678);
+            state->pitch3   = NV_RD32(chip->PGRAPH, 0x0000067C);
+            if(chip->twoHeads) {
+               state->head     = NV_RD32(chip->PCRTC0, 0x00000860);
+               state->head2    = NV_RD32(chip->PCRTC0, 0x00002860);
+               VGA_WR08(chip->PCIO, 0x03D4, 0x44);
+               state->crtcOwner = VGA_RD08(chip->PCIO, 0x03D5);
+            }
+            VGA_WR08(chip->PCIO, 0x03D4, 0x41);
+            state->extra = VGA_RD08(chip->PCIO, 0x03D5);
+            state->cursorConfig = NV_RD32(chip->PCRTC, 0x00000810);
+
+            if((chip->Chipset & 0x0ff0) == 0x0110) {
+                state->dither = NV_RD32(chip->PRAMDAC, 0x0528);
+            } else 
+            if((chip->Chipset & 0x0ff0) >= 0x0170) {
+                state->dither = NV_RD32(chip->PRAMDAC, 0x083C);
+            }
+            break;
+    }
+}
+static void SetStartAddress
+(
+    RIVA_HW_INST *chip,
+    unsigned      start
+)
+{
+    NV_WR32(chip->PCRTC, 0x800, start);
+}
+
+static void SetStartAddress3
+(
+    RIVA_HW_INST *chip,
+    unsigned      start
+)
+{
+    int offset = start >> 2;
+    int pan    = (start & 3) << 1;
+    unsigned char tmp;
+
+    /*
+     * Unlock extended registers.
+     */
+    chip->LockUnlock(chip, 0);
+    /*
+     * Set start address.
+     */
+    VGA_WR08(chip->PCIO, 0x3D4, 0x0D); VGA_WR08(chip->PCIO, 0x3D5, offset);
+    offset >>= 8;
+    VGA_WR08(chip->PCIO, 0x3D4, 0x0C); VGA_WR08(chip->PCIO, 0x3D5, offset);
+    offset >>= 8;
+    VGA_WR08(chip->PCIO, 0x3D4, 0x19); tmp = VGA_RD08(chip->PCIO, 0x3D5);
+    VGA_WR08(chip->PCIO, 0x3D5, (offset & 0x01F) | (tmp & ~0x1F));
+    VGA_WR08(chip->PCIO, 0x3D4, 0x2D); tmp = VGA_RD08(chip->PCIO, 0x3D5);
+    VGA_WR08(chip->PCIO, 0x3D5, (offset & 0x60) | (tmp & ~0x60));
+    /*
+     * 4 pixel pan register.
+     */
+    offset = VGA_RD08(chip->PCIO, chip->IO + 0x0A);
+    VGA_WR08(chip->PCIO, 0x3C0, 0x13);
+    VGA_WR08(chip->PCIO, 0x3C0, pan);
+}
+static void nv3SetSurfaces2D
+(
+    RIVA_HW_INST *chip,
+    unsigned     surf0,
+    unsigned     surf1
+)
+{
+    RivaSurface __iomem *Surface =
+	(RivaSurface __iomem *)&(chip->FIFO[0x0000E000/4]);
+
+    RIVA_FIFO_FREE(*chip,Tri03,5);
+    NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000003);
+    NV_WR32(&Surface->Offset, 0, surf0);
+    NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000004);
+    NV_WR32(&Surface->Offset, 0, surf1);
+    NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000013);
+}
+static void nv4SetSurfaces2D
+(
+    RIVA_HW_INST *chip,
+    unsigned     surf0,
+    unsigned     surf1
+)
+{
+    RivaSurface __iomem *Surface =
+	(RivaSurface __iomem *)&(chip->FIFO[0x0000E000/4]);
+
+    NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000003);
+    NV_WR32(&Surface->Offset, 0, surf0);
+    NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000004);
+    NV_WR32(&Surface->Offset, 0, surf1);
+    NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000014);
+}
+static void nv10SetSurfaces2D
+(
+    RIVA_HW_INST *chip,
+    unsigned     surf0,
+    unsigned     surf1
+)
+{
+    RivaSurface __iomem *Surface =
+	(RivaSurface __iomem *)&(chip->FIFO[0x0000E000/4]);
+
+    NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000003);
+    NV_WR32(&Surface->Offset, 0, surf0);
+    NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000004);
+    NV_WR32(&Surface->Offset, 0, surf1);
+    NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000014);
+}
+static void nv3SetSurfaces3D
+(
+    RIVA_HW_INST *chip,
+    unsigned     surf0,
+    unsigned     surf1
+)
+{
+    RivaSurface __iomem *Surface =
+	(RivaSurface __iomem *)&(chip->FIFO[0x0000E000/4]);
+
+    RIVA_FIFO_FREE(*chip,Tri03,5);
+    NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000005);
+    NV_WR32(&Surface->Offset, 0, surf0);
+    NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000006);
+    NV_WR32(&Surface->Offset, 0, surf1);
+    NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000013);
+}
+static void nv4SetSurfaces3D
+(
+    RIVA_HW_INST *chip,
+    unsigned     surf0,
+    unsigned     surf1
+)
+{
+    RivaSurface __iomem *Surface =
+	(RivaSurface __iomem *)&(chip->FIFO[0x0000E000/4]);
+
+    NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000005);
+    NV_WR32(&Surface->Offset, 0, surf0);
+    NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000006);
+    NV_WR32(&Surface->Offset, 0, surf1);
+    NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000014);
+}
+static void nv10SetSurfaces3D
+(
+    RIVA_HW_INST *chip,
+    unsigned     surf0,
+    unsigned     surf1
+)
+{
+    RivaSurface3D __iomem *Surfaces3D =
+	(RivaSurface3D __iomem *)&(chip->FIFO[0x0000E000/4]);
+
+    RIVA_FIFO_FREE(*chip,Tri03,4);
+    NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000007);
+    NV_WR32(&Surfaces3D->RenderBufferOffset, 0, surf0);
+    NV_WR32(&Surfaces3D->ZBufferOffset, 0, surf1);
+    NV_WR32(&chip->FIFO[0x00003800], 0, 0x80000014);
+}
+
+/****************************************************************************\
+*                                                                            *
+*                      Probe RIVA Chip Configuration                         *
+*                                                                            *
+\****************************************************************************/
+
+static void nv3GetConfig
+(
+    RIVA_HW_INST *chip
+)
+{
+    /*
+     * Fill in chip configuration.
+     */
+    if (NV_RD32(&chip->PFB[0x00000000/4], 0) & 0x00000020)
+    {
+        if (((NV_RD32(chip->PMC, 0x00000000) & 0xF0) == 0x20)
+         && ((NV_RD32(chip->PMC, 0x00000000) & 0x0F) >= 0x02))
+        {        
+            /*
+             * SDRAM 128 ZX.
+             */
+            chip->RamBandwidthKBytesPerSec = 800000;
+            switch (NV_RD32(chip->PFB, 0x00000000) & 0x03)
+            {
+                case 2:
+                    chip->RamAmountKBytes = 1024 * 4;
+                    break;
+                case 1:
+                    chip->RamAmountKBytes = 1024 * 2;
+                    break;
+                default:
+                    chip->RamAmountKBytes = 1024 * 8;
+                    break;
+            }
+        }            
+        else            
+        {
+            chip->RamBandwidthKBytesPerSec = 1000000;
+            chip->RamAmountKBytes          = 1024 * 8;
+        }            
+    }
+    else
+    {
+        /*
+         * SGRAM 128.
+         */
+        chip->RamBandwidthKBytesPerSec = 1000000;
+        switch (NV_RD32(chip->PFB, 0x00000000) & 0x00000003)
+        {
+            case 0:
+                chip->RamAmountKBytes = 1024 * 8;
+                break;
+            case 2:
+                chip->RamAmountKBytes = 1024 * 4;
+                break;
+            default:
+                chip->RamAmountKBytes = 1024 * 2;
+                break;
+        }
+    }        
+    chip->CrystalFreqKHz   = (NV_RD32(chip->PEXTDEV, 0x00000000) & 0x00000040) ? 14318 : 13500;
+    chip->CURSOR           = &(chip->PRAMIN[0x00008000/4 - 0x0800/4]);
+    chip->VBlankBit        = 0x00000100;
+    chip->MaxVClockFreqKHz = 256000;
+    /*
+     * Set chip functions.
+     */
+    chip->Busy            = nv3Busy;
+    chip->ShowHideCursor  = ShowHideCursor;
+    chip->CalcStateExt    = CalcStateExt;
+    chip->LoadStateExt    = LoadStateExt;
+    chip->UnloadStateExt  = UnloadStateExt;
+    chip->SetStartAddress = SetStartAddress3;
+    chip->SetSurfaces2D   = nv3SetSurfaces2D;
+    chip->SetSurfaces3D   = nv3SetSurfaces3D;
+    chip->LockUnlock      = nv3LockUnlock;
+}
+static void nv4GetConfig
+(
+    RIVA_HW_INST *chip
+)
+{
+    /*
+     * Fill in chip configuration.
+     */
+    if (NV_RD32(chip->PFB, 0x00000000) & 0x00000100)
+    {
+        chip->RamAmountKBytes = ((NV_RD32(chip->PFB, 0x00000000) >> 12) & 0x0F) * 1024 * 2
+                              + 1024 * 2;
+    }
+    else
+    {
+        switch (NV_RD32(chip->PFB, 0x00000000) & 0x00000003)
+        {
+            case 0:
+                chip->RamAmountKBytes = 1024 * 32;
+                break;
+            case 1:
+                chip->RamAmountKBytes = 1024 * 4;
+                break;
+            case 2:
+                chip->RamAmountKBytes = 1024 * 8;
+                break;
+            case 3:
+            default:
+                chip->RamAmountKBytes = 1024 * 16;
+                break;
+        }
+    }
+    switch ((NV_RD32(chip->PFB, 0x00000000) >> 3) & 0x00000003)
+    {
+        case 3:
+            chip->RamBandwidthKBytesPerSec = 800000;
+            break;
+        default:
+            chip->RamBandwidthKBytesPerSec = 1000000;
+            break;
+    }
+    chip->CrystalFreqKHz   = (NV_RD32(chip->PEXTDEV, 0x00000000) & 0x00000040) ? 14318 : 13500;
+    chip->CURSOR           = &(chip->PRAMIN[0x00010000/4 - 0x0800/4]);
+    chip->VBlankBit        = 0x00000001;
+    chip->MaxVClockFreqKHz = 350000;
+    /*
+     * Set chip functions.
+     */
+    chip->Busy            = nv4Busy;
+    chip->ShowHideCursor  = ShowHideCursor;
+    chip->CalcStateExt    = CalcStateExt;
+    chip->LoadStateExt    = LoadStateExt;
+    chip->UnloadStateExt  = UnloadStateExt;
+    chip->SetStartAddress = SetStartAddress;
+    chip->SetSurfaces2D   = nv4SetSurfaces2D;
+    chip->SetSurfaces3D   = nv4SetSurfaces3D;
+    chip->LockUnlock      = nv4LockUnlock;
+}
+static void nv10GetConfig
+(
+    RIVA_HW_INST *chip,
+    unsigned int chipset
+)
+{
+    struct pci_dev* dev;
+    int amt;
+
+#ifdef __BIG_ENDIAN
+    /* turn on big endian register access */
+    if(!(NV_RD32(chip->PMC, 0x00000004) & 0x01000001))
+    	NV_WR32(chip->PMC, 0x00000004, 0x01000001);
+#endif
+
+    /*
+     * Fill in chip configuration.
+     */
+    if(chipset == NV_CHIP_IGEFORCE2) {
+        dev = pci_find_slot(0, 1);
+        pci_read_config_dword(dev, 0x7C, &amt);
+        chip->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024;
+    } else if(chipset == NV_CHIP_0x01F0) {
+        dev = pci_find_slot(0, 1);
+        pci_read_config_dword(dev, 0x84, &amt);
+        chip->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024;
+    } else {
+        switch ((NV_RD32(chip->PFB, 0x0000020C) >> 20) & 0x000000FF)
+        {
+            case 0x02:
+                chip->RamAmountKBytes = 1024 * 2;
+                break;
+            case 0x04:
+                chip->RamAmountKBytes = 1024 * 4;
+                break;
+            case 0x08:
+                chip->RamAmountKBytes = 1024 * 8;
+                break;
+            case 0x10:
+                chip->RamAmountKBytes = 1024 * 16;
+                break;
+            case 0x20:
+                chip->RamAmountKBytes = 1024 * 32;
+                break;
+            case 0x40:
+                chip->RamAmountKBytes = 1024 * 64;
+                break;
+            case 0x80:
+                chip->RamAmountKBytes = 1024 * 128;
+                break;
+            default:
+                chip->RamAmountKBytes = 1024 * 16;
+                break;
+        }
+    }
+    switch ((NV_RD32(chip->PFB, 0x00000000) >> 3) & 0x00000003)
+    {
+        case 3:
+            chip->RamBandwidthKBytesPerSec = 800000;
+            break;
+        default:
+            chip->RamBandwidthKBytesPerSec = 1000000;
+            break;
+    }
+    chip->CrystalFreqKHz = (NV_RD32(chip->PEXTDEV, 0x0000) & (1 << 6)) ?
+	14318 : 13500;
+
+    switch (chipset & 0x0ff0) {
+    case 0x0170:
+    case 0x0180:
+    case 0x01F0:
+    case 0x0250:
+    case 0x0280:
+    case 0x0300:
+    case 0x0310:
+    case 0x0320:
+    case 0x0330:
+    case 0x0340:
+       if(NV_RD32(chip->PEXTDEV, 0x0000) & (1 << 22))
+           chip->CrystalFreqKHz = 27000;
+       break;
+    default:
+       break;
+    }
+
+    chip->CursorStart      = (chip->RamAmountKBytes - 128) * 1024;
+    chip->CURSOR           = NULL;  /* can't set this here */
+    chip->VBlankBit        = 0x00000001;
+    chip->MaxVClockFreqKHz = 350000;
+    /*
+     * Set chip functions.
+     */
+    chip->Busy            = nv10Busy;
+    chip->ShowHideCursor  = ShowHideCursor;
+    chip->CalcStateExt    = CalcStateExt;
+    chip->LoadStateExt    = LoadStateExt;
+    chip->UnloadStateExt  = UnloadStateExt;
+    chip->SetStartAddress = SetStartAddress;
+    chip->SetSurfaces2D   = nv10SetSurfaces2D;
+    chip->SetSurfaces3D   = nv10SetSurfaces3D;
+    chip->LockUnlock      = nv4LockUnlock;
+
+    switch(chipset & 0x0ff0) {
+    case 0x0110:
+    case 0x0170:
+    case 0x0180:
+    case 0x01F0:
+    case 0x0250:
+    case 0x0280:
+    case 0x0300:
+    case 0x0310:
+    case 0x0320:
+    case 0x0330:
+    case 0x0340:
+        chip->twoHeads = TRUE;
+        break;
+    default:
+        chip->twoHeads = FALSE;
+        break;
+    }
+}
+int RivaGetConfig
+(
+    RIVA_HW_INST *chip,
+    unsigned int chipset
+)
+{
+    /*
+     * Save this so future SW know whats it's dealing with.
+     */
+    chip->Version = RIVA_SW_VERSION;
+    /*
+     * Chip specific configuration.
+     */
+    switch (chip->Architecture)
+    {
+        case NV_ARCH_03:
+            nv3GetConfig(chip);
+            break;
+        case NV_ARCH_04:
+            nv4GetConfig(chip);
+            break;
+        case NV_ARCH_10:
+        case NV_ARCH_20:
+        case NV_ARCH_30:
+            nv10GetConfig(chip, chipset);
+            break;
+        default:
+            return (-1);
+    }
+    chip->Chipset = chipset;
+    /*
+     * Fill in FIFO pointers.
+     */
+    chip->Rop    = (RivaRop __iomem         *)&(chip->FIFO[0x00000000/4]);
+    chip->Clip   = (RivaClip __iomem        *)&(chip->FIFO[0x00002000/4]);
+    chip->Patt   = (RivaPattern __iomem     *)&(chip->FIFO[0x00004000/4]);
+    chip->Pixmap = (RivaPixmap __iomem      *)&(chip->FIFO[0x00006000/4]);
+    chip->Blt    = (RivaScreenBlt __iomem   *)&(chip->FIFO[0x00008000/4]);
+    chip->Bitmap = (RivaBitmap __iomem      *)&(chip->FIFO[0x0000A000/4]);
+    chip->Line   = (RivaLine __iomem        *)&(chip->FIFO[0x0000C000/4]);
+    chip->Tri03  = (RivaTexturedTriangle03 __iomem *)&(chip->FIFO[0x0000E000/4]);
+    return (0);
+}
+
diff --git a/drivers/video/riva/riva_hw.h b/drivers/video/riva/riva_hw.h
new file mode 100644
index 0000000..a1e71a6
--- /dev/null
+++ b/drivers/video/riva/riva_hw.h
@@ -0,0 +1,548 @@
+/***************************************************************************\
+|*                                                                           *|
+|*       Copyright 1993-1999 NVIDIA, Corporation.  All rights reserved.      *|
+|*                                                                           *|
+|*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
+|*     international laws.  Users and possessors of this source code are     *|
+|*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
+|*     use this code in individual and commercial software.                  *|
+|*                                                                           *|
+|*     Any use of this source code must include,  in the user documenta-     *|
+|*     tion and  internal comments to the code,  notices to the end user     *|
+|*     as follows:                                                           *|
+|*                                                                           *|
+|*       Copyright 1993-1999 NVIDIA, Corporation.  All rights reserved.      *|
+|*                                                                           *|
+|*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
+|*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
+|*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
+|*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
+|*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
+|*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
+|*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
+|*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
+|*     SULTING FROM LOSS OF USE,  DATA OR PROFITS,  WHETHER IN AN ACTION     *|
+|*     OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,  ARISING OUT OF     *|
+|*     OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.     *|
+|*                                                                           *|
+|*     U.S. Government  End  Users.   This source code  is a "commercial     *|
+|*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
+|*     consisting  of "commercial  computer  software"  and  "commercial     *|
+|*     computer  software  documentation,"  as such  terms  are  used in     *|
+|*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
+|*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
+|*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
+|*     all U.S. Government End Users  acquire the source code  with only     *|
+|*     those rights set forth herein.                                        *|
+|*                                                                           *|
+\***************************************************************************/
+
+/*
+ * GPL licensing note -- nVidia is allowing a liberal interpretation of
+ * the documentation restriction above, to merely say that this nVidia's
+ * copyright and disclaimer should be included with all code derived
+ * from this source.  -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 
+ */
+
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/riva_hw.h,v 1.21 2002/10/14 18:22:46 mvojkovi Exp $ */
+#ifndef __RIVA_HW_H__
+#define __RIVA_HW_H__
+#define RIVA_SW_VERSION 0x00010003
+
+#ifndef Bool
+typedef int Bool;
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef NULL
+#define NULL 0
+#endif
+
+/*
+ * Typedefs to force certain sized values.
+ */
+typedef unsigned char  U008;
+typedef unsigned short U016;
+typedef unsigned int   U032;
+
+/*
+ * HW access macros.
+ */
+#include <asm/io.h>
+
+#define NV_WR08(p,i,d)  (__raw_writeb((d), (void __iomem *)(p) + (i)))
+#define NV_RD08(p,i)    (__raw_readb((void __iomem *)(p) + (i)))
+#define NV_WR16(p,i,d)  (__raw_writew((d), (void __iomem *)(p) + (i)))
+#define NV_RD16(p,i)    (__raw_readw((void __iomem *)(p) + (i)))
+#define NV_WR32(p,i,d)  (__raw_writel((d), (void __iomem *)(p) + (i)))
+#define NV_RD32(p,i)    (__raw_readl((void __iomem *)(p) + (i)))
+
+#define VGA_WR08(p,i,d) (writeb((d), (void __iomem *)(p) + (i)))
+#define VGA_RD08(p,i)   (readb((void __iomem *)(p) + (i)))
+
+/*
+ * Define different architectures.
+ */
+#define NV_ARCH_03  0x03
+#define NV_ARCH_04  0x04
+#define NV_ARCH_10  0x10
+#define NV_ARCH_20  0x20
+#define NV_ARCH_30  0x30
+#define NV_ARCH_40  0x40
+
+/***************************************************************************\
+*                                                                           *
+*                             FIFO registers.                               *
+*                                                                           *
+\***************************************************************************/
+
+/*
+ * Raster OPeration. Windows style ROP3.
+ */
+typedef volatile struct
+{
+    U032 reserved00[4];
+#ifdef __BIG_ENDIAN
+    U032 FifoFree;
+#else
+    U016 FifoFree;
+    U016 Nop;
+#endif
+    U032 reserved01[0x0BB];
+    U032 Rop3;
+} RivaRop;
+/*
+ * 8X8 Monochrome pattern.
+ */
+typedef volatile struct
+{
+    U032 reserved00[4];
+#ifdef __BIG_ENDIAN
+    U032 FifoFree;
+#else
+    U016 FifoFree;
+    U016 Nop;
+#endif
+    U032 reserved01[0x0BD];
+    U032 Shape;
+    U032 reserved03[0x001];
+    U032 Color0;
+    U032 Color1;
+    U032 Monochrome[2];
+} RivaPattern;
+/*
+ * Scissor clip rectangle.
+ */
+typedef volatile struct
+{
+    U032 reserved00[4];
+#ifdef __BIG_ENDIAN
+    U032 FifoFree;
+#else
+    U016 FifoFree;
+    U016 Nop;
+#endif
+    U032 reserved01[0x0BB];
+    U032 TopLeft;
+    U032 WidthHeight;
+} RivaClip;
+/*
+ * 2D filled rectangle.
+ */
+typedef volatile struct
+{
+    U032 reserved00[4];
+#ifdef __BIG_ENDIAN
+    U032 FifoFree;
+#else
+    U016 FifoFree;
+    U016 Nop[1];
+#endif
+    U032 reserved01[0x0BC];
+    U032 Color;
+    U032 reserved03[0x03E];
+    U032 TopLeft;
+    U032 WidthHeight;
+} RivaRectangle;
+/*
+ * 2D screen-screen BLT.
+ */
+typedef volatile struct
+{
+    U032 reserved00[4];
+#ifdef __BIG_ENDIAN
+    U032 FifoFree;
+#else
+    U016 FifoFree;
+    U016 Nop;
+#endif
+    U032 reserved01[0x0BB];
+    U032 TopLeftSrc;
+    U032 TopLeftDst;
+    U032 WidthHeight;
+} RivaScreenBlt;
+/*
+ * 2D pixel BLT.
+ */
+typedef volatile struct
+{
+    U032 reserved00[4];
+#ifdef __BIG_ENDIAN
+    U032 FifoFree;
+#else
+    U016 FifoFree;
+    U016 Nop[1];
+#endif
+    U032 reserved01[0x0BC];
+    U032 TopLeft;
+    U032 WidthHeight;
+    U032 WidthHeightIn;
+    U032 reserved02[0x03C];
+    U032 Pixels;
+} RivaPixmap;
+/*
+ * Filled rectangle combined with monochrome expand.  Useful for glyphs.
+ */
+typedef volatile struct
+{
+    U032 reserved00[4];
+#ifdef __BIG_ENDIAN
+    U032 FifoFree;
+#else
+    U016 FifoFree;
+    U016 Nop;
+#endif
+    U032 reserved01[0x0BB];
+    U032 reserved03[(0x040)-1];
+    U032 Color1A;
+    struct
+    {
+        U032 TopLeft;
+        U032 WidthHeight;
+    } UnclippedRectangle[64];
+    U032 reserved04[(0x080)-3];
+    struct
+    {
+        U032 TopLeft;
+        U032 BottomRight;
+    } ClipB;
+    U032 Color1B;
+    struct
+    {
+        U032 TopLeft;
+        U032 BottomRight;
+    } ClippedRectangle[64];
+    U032 reserved05[(0x080)-5];
+    struct
+    {
+        U032 TopLeft;
+        U032 BottomRight;
+    } ClipC;
+    U032 Color1C;
+    U032 WidthHeightC;
+    U032 PointC;
+    U032 MonochromeData1C;
+    U032 reserved06[(0x080)+121];
+    struct
+    {
+        U032 TopLeft;
+        U032 BottomRight;
+    } ClipD;
+    U032 Color1D;
+    U032 WidthHeightInD;
+    U032 WidthHeightOutD;
+    U032 PointD;
+    U032 MonochromeData1D;
+    U032 reserved07[(0x080)+120];
+    struct
+    {
+        U032 TopLeft;
+        U032 BottomRight;
+    } ClipE;
+    U032 Color0E;
+    U032 Color1E;
+    U032 WidthHeightInE;
+    U032 WidthHeightOutE;
+    U032 PointE;
+    U032 MonochromeData01E;
+} RivaBitmap;
+/*
+ * 3D textured, Z buffered triangle.
+ */
+typedef volatile struct
+{
+    U032 reserved00[4];
+#ifdef __BIG_ENDIAN
+    U032 FifoFree;
+#else
+    U016 FifoFree;
+    U016 Nop;
+#endif
+    U032 reserved01[0x0BC];
+    U032 TextureOffset;
+    U032 TextureFormat;
+    U032 TextureFilter;
+    U032 FogColor;
+/* This is a problem on LynxOS */
+#ifdef Control
+#undef Control
+#endif
+    U032 Control;
+    U032 AlphaTest;
+    U032 reserved02[0x339];
+    U032 FogAndIndex;
+    U032 Color;
+    float ScreenX;
+    float ScreenY;
+    float ScreenZ;
+    float EyeM;
+    float TextureS;
+    float TextureT;
+} RivaTexturedTriangle03;
+typedef volatile struct
+{
+    U032 reserved00[4];
+#ifdef __BIG_ENDIAN
+    U032 FifoFree;
+#else
+    U016 FifoFree;
+    U016 Nop;
+#endif
+    U032 reserved01[0x0BB];
+    U032 ColorKey;
+    U032 TextureOffset;
+    U032 TextureFormat;
+    U032 TextureFilter;
+    U032 Blend;
+/* This is a problem on LynxOS */
+#ifdef Control
+#undef Control
+#endif
+    U032 Control;
+    U032 FogColor;
+    U032 reserved02[0x39];
+    struct
+    {
+        float ScreenX;
+        float ScreenY;
+        float ScreenZ;
+        float EyeM;
+        U032 Color;
+        U032 Specular;
+        float TextureS;
+        float TextureT;
+    } Vertex[16];
+    U032 DrawTriangle3D;
+} RivaTexturedTriangle05;
+/*
+ * 2D line.
+ */
+typedef volatile struct
+{
+    U032 reserved00[4];
+#ifdef __BIG_ENDIAN
+    U032 FifoFree;
+#else
+    U016 FifoFree;
+    U016 Nop[1];
+#endif
+    U032 reserved01[0x0BC];
+    U032 Color;             /* source color               0304-0307*/
+    U032 Reserved02[0x03e];
+    struct {                /* start aliased methods in array   0400-    */
+        U032 point0;        /* y_x S16_S16 in pixels            0-   3*/
+        U032 point1;        /* y_x S16_S16 in pixels            4-   7*/
+    } Lin[16];              /* end of aliased methods in array      -047f*/
+    struct {                /* start aliased methods in array   0480-    */
+        U032 point0X;       /* in pixels, 0 at left                0-   3*/
+        U032 point0Y;       /* in pixels, 0 at top                 4-   7*/
+        U032 point1X;       /* in pixels, 0 at left                8-   b*/
+        U032 point1Y;       /* in pixels, 0 at top                 c-   f*/
+    } Lin32[8];             /* end of aliased methods in array      -04ff*/
+    U032 PolyLin[32];       /* y_x S16_S16 in pixels         0500-057f*/
+    struct {                /* start aliased methods in array   0580-    */
+        U032 x;             /* in pixels, 0 at left                0-   3*/
+        U032 y;             /* in pixels, 0 at top                 4-   7*/
+    } PolyLin32[16];        /* end of aliased methods in array      -05ff*/
+    struct {                /* start aliased methods in array   0600-    */
+        U032 color;         /* source color                     0-   3*/
+        U032 point;         /* y_x S16_S16 in pixels            4-   7*/
+    } ColorPolyLin[16];     /* end of aliased methods in array      -067f*/
+} RivaLine;
+/*
+ * 2D/3D surfaces
+ */
+typedef volatile struct
+{
+    U032 reserved00[4];
+#ifdef __BIG_ENDIAN
+    U032 FifoFree;
+#else
+    U016 FifoFree;
+    U016 Nop;
+#endif
+    U032 reserved01[0x0BE];
+    U032 Offset;
+} RivaSurface;
+typedef volatile struct
+{
+    U032 reserved00[4];
+#ifdef __BIG_ENDIAN
+    U032 FifoFree;
+#else
+    U016 FifoFree;
+    U016 Nop;
+#endif
+    U032 reserved01[0x0BD];
+    U032 Pitch;
+    U032 RenderBufferOffset;
+    U032 ZBufferOffset;
+} RivaSurface3D;
+    
+/***************************************************************************\
+*                                                                           *
+*                        Virtualized RIVA H/W interface.                    *
+*                                                                           *
+\***************************************************************************/
+
+#define FP_ENABLE  1
+#define FP_DITHER  2
+
+struct _riva_hw_inst;
+struct _riva_hw_state;
+/*
+ * Virtialized chip interface. Makes RIVA 128 and TNT look alike.
+ */
+typedef struct _riva_hw_inst
+{
+    /*
+     * Chip specific settings.
+     */
+    U032 Architecture;
+    U032 Version;
+    U032 Chipset;
+    U032 CrystalFreqKHz;
+    U032 RamAmountKBytes;
+    U032 MaxVClockFreqKHz;
+    U032 RamBandwidthKBytesPerSec;
+    U032 EnableIRQ;
+    U032 IO;
+    U032 VBlankBit;
+    U032 FifoFreeCount;
+    U032 FifoEmptyCount;
+    U032 CursorStart;
+    U032 flatPanel;
+    Bool twoHeads;
+    /*
+     * Non-FIFO registers.
+     */
+    volatile U032 __iomem *PCRTC0;
+    volatile U032 __iomem *PCRTC;
+    volatile U032 __iomem *PRAMDAC0;
+    volatile U032 __iomem *PFB;
+    volatile U032 __iomem *PFIFO;
+    volatile U032 __iomem *PGRAPH;
+    volatile U032 __iomem *PEXTDEV;
+    volatile U032 __iomem *PTIMER;
+    volatile U032 __iomem *PMC;
+    volatile U032 __iomem *PRAMIN;
+    volatile U032 __iomem *FIFO;
+    volatile U032 __iomem *CURSOR;
+    volatile U008 __iomem *PCIO0;
+    volatile U008 __iomem *PCIO;
+    volatile U008 __iomem *PVIO;
+    volatile U008 __iomem *PDIO0;
+    volatile U008 __iomem *PDIO;
+    volatile U032 __iomem *PRAMDAC;
+    /*
+     * Common chip functions.
+     */
+    int  (*Busy)(struct _riva_hw_inst *);
+    void (*CalcStateExt)(struct _riva_hw_inst *,struct _riva_hw_state *,int,int,int,int,int);
+    void (*LoadStateExt)(struct _riva_hw_inst *,struct _riva_hw_state *);
+    void (*UnloadStateExt)(struct _riva_hw_inst *,struct _riva_hw_state *);
+    void (*SetStartAddress)(struct _riva_hw_inst *,U032);
+    void (*SetSurfaces2D)(struct _riva_hw_inst *,U032,U032);
+    void (*SetSurfaces3D)(struct _riva_hw_inst *,U032,U032);
+    int  (*ShowHideCursor)(struct _riva_hw_inst *,int);
+    void (*LockUnlock)(struct _riva_hw_inst *, int);
+    /*
+     * Current extended mode settings.
+     */
+    struct _riva_hw_state *CurrentState;
+    /*
+     * FIFO registers.
+     */
+    RivaRop                 __iomem *Rop;
+    RivaPattern             __iomem *Patt;
+    RivaClip                __iomem *Clip;
+    RivaPixmap              __iomem *Pixmap;
+    RivaScreenBlt           __iomem *Blt;
+    RivaBitmap              __iomem *Bitmap;
+    RivaLine                __iomem *Line;
+    RivaTexturedTriangle03  __iomem *Tri03;
+    RivaTexturedTriangle05  __iomem *Tri05;
+} RIVA_HW_INST;
+/*
+ * Extended mode state information.
+ */
+typedef struct _riva_hw_state
+{
+    U032 bpp;
+    U032 width;
+    U032 height;
+    U032 interlace;
+    U032 repaint0;
+    U032 repaint1;
+    U032 screen;
+    U032 scale;
+    U032 dither;
+    U032 extra;
+    U032 pixel;
+    U032 horiz;
+    U032 arbitration0;
+    U032 arbitration1;
+    U032 vpll;
+    U032 vpll2;
+    U032 pllsel;
+    U032 general;
+    U032 crtcOwner;
+    U032 head; 
+    U032 head2; 
+    U032 config;
+    U032 cursorConfig;	
+    U032 cursor0;
+    U032 cursor1;
+    U032 cursor2;
+    U032 offset0;
+    U032 offset1;
+    U032 offset2;
+    U032 offset3;
+    U032 pitch0;
+    U032 pitch1;
+    U032 pitch2;
+    U032 pitch3;
+} RIVA_HW_STATE;
+/*
+ * External routines.
+ */
+int RivaGetConfig(RIVA_HW_INST *, unsigned int);
+/*
+ * FIFO Free Count. Should attempt to yield processor if RIVA is busy.
+ */
+
+#define RIVA_FIFO_FREE(hwinst,hwptr,cnt)                            \
+{                                                                   \
+    while ((hwinst).FifoFreeCount < (cnt)) {                        \
+	mb();mb();						    \
+        (hwinst).FifoFreeCount = NV_RD32(&(hwinst).hwptr->FifoFree, 0) >> 2;     \
+    }								    \
+    (hwinst).FifoFreeCount -= (cnt);                                \
+}
+#endif /* __RIVA_HW_H__ */
+
diff --git a/drivers/video/riva/riva_tbl.h b/drivers/video/riva/riva_tbl.h
new file mode 100644
index 0000000..7ee7d72
--- /dev/null
+++ b/drivers/video/riva/riva_tbl.h
@@ -0,0 +1,1008 @@
+ /***************************************************************************\
+|*                                                                           *|
+|*       Copyright 1993-1999 NVIDIA, Corporation.  All rights reserved.      *|
+|*                                                                           *|
+|*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
+|*     international laws.  Users and possessors of this source code are     *|
+|*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
+|*     use this code in individual and commercial software.                  *|
+|*                                                                           *|
+|*     Any use of this source code must include,  in the user documenta-     *|
+|*     tion and  internal comments to the code,  notices to the end user     *|
+|*     as follows:                                                           *|
+|*                                                                           *|
+|*       Copyright 1993-1999 NVIDIA, Corporation.  All rights reserved.      *|
+|*                                                                           *|
+|*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
+|*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
+|*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
+|*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
+|*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
+|*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
+|*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
+|*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
+|*     SULTING FROM LOSS OF USE,  DATA OR PROFITS,  WHETHER IN AN ACTION     *|
+|*     OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,  ARISING OUT OF     *|
+|*     OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.     *|
+|*                                                                           *|
+|*     U.S. Government  End  Users.   This source code  is a "commercial     *|
+|*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
+|*     consisting  of "commercial  computer  software"  and  "commercial     *|
+|*     computer  software  documentation,"  as such  terms  are  used in     *|
+|*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
+|*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
+|*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
+|*     all U.S. Government End Users  acquire the source code  with only     *|
+|*     those rights set forth herein.                                        *|
+|*                                                                           *|
+ \***************************************************************************/
+
+/*
+ * GPL licensing note -- nVidia is allowing a liberal interpretation of
+ * the documentation restriction above, to merely say that this nVidia's
+ * copyright and disclaimer should be included with all code derived
+ * from this source.  -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 
+ */
+
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/riva_tbl.h,v 1.9 2002/01/30 01:35:03 mvojkovi Exp $ */
+
+
+/*
+ * RIVA Fixed Functionality Init Tables.
+ */
+static unsigned RivaTablePMC[][2] =
+{
+    {0x00000050, 0x00000000},
+    {0x00000080, 0xFFFF00FF},
+    {0x00000080, 0xFFFFFFFF}
+};
+static unsigned RivaTablePTIMER[][2] =
+{
+    {0x00000080, 0x00000008},
+    {0x00000084, 0x00000003},
+    {0x00000050, 0x00000000},
+    {0x00000040, 0xFFFFFFFF}
+};
+static unsigned RivaTableFIFO[][2] =
+{
+    {0x00000000, 0x80000000},
+    {0x00000800, 0x80000001},
+    {0x00001000, 0x80000002},
+    {0x00001800, 0x80000010},
+    {0x00002000, 0x80000011},
+    {0x00002800, 0x80000012},
+    {0x00003000, 0x80000016},
+    {0x00003800, 0x80000013}
+};
+static unsigned nv3TablePFIFO[][2] =
+{
+    {0x00000140, 0x00000000},
+    {0x00000480, 0x00000000},
+    {0x00000490, 0x00000000},
+    {0x00000494, 0x00000000},
+    {0x00000481, 0x00000000},
+    {0x00000084, 0x00000000},
+    {0x00000086, 0x00002000},
+    {0x00000085, 0x00002200},
+    {0x00000484, 0x00000000},
+    {0x0000049C, 0x00000000},
+    {0x00000104, 0x00000000},
+    {0x00000108, 0x00000000},
+    {0x00000100, 0x00000000},
+    {0x000004A0, 0x00000000},
+    {0x000004A4, 0x00000000},
+    {0x000004A8, 0x00000000},
+    {0x000004AC, 0x00000000},
+    {0x000004B0, 0x00000000},
+    {0x000004B4, 0x00000000},
+    {0x000004B8, 0x00000000},
+    {0x000004BC, 0x00000000},
+    {0x00000050, 0x00000000},
+    {0x00000040, 0xFFFFFFFF},
+    {0x00000480, 0x00000001},
+    {0x00000490, 0x00000001},
+    {0x00000140, 0x00000001}
+};
+static unsigned nv3TablePGRAPH[][2] =
+{
+    {0x00000020, 0x1230001F},
+    {0x00000021, 0x10113000},
+    {0x00000022, 0x1131F101},
+    {0x00000023, 0x0100F531},
+    {0x00000060, 0x00000000},
+    {0x00000065, 0x00000000},
+    {0x00000068, 0x00000000},
+    {0x00000069, 0x00000000},
+    {0x0000006A, 0x00000000},
+    {0x0000006B, 0x00000000},
+    {0x0000006C, 0x00000000},
+    {0x0000006D, 0x00000000},
+    {0x0000006E, 0x00000000},
+    {0x0000006F, 0x00000000},
+    {0x000001A8, 0x00000000},
+    {0x00000440, 0xFFFFFFFF},
+    {0x00000480, 0x00000001},
+    {0x000001A0, 0x00000000},
+    {0x000001A2, 0x00000000},
+    {0x0000018A, 0xFFFFFFFF},
+    {0x00000190, 0x00000000},
+    {0x00000142, 0x00000000},
+    {0x00000154, 0x00000000},
+    {0x00000155, 0xFFFFFFFF},
+    {0x00000156, 0x00000000},
+    {0x00000157, 0xFFFFFFFF},
+    {0x00000064, 0x10010002},
+    {0x00000050, 0x00000000},
+    {0x00000051, 0x00000000},
+    {0x00000040, 0xFFFFFFFF},
+    {0x00000041, 0xFFFFFFFF},
+    {0x00000440, 0xFFFFFFFF},
+    {0x000001A9, 0x00000001}
+};
+static unsigned nv3TablePGRAPH_8BPP[][2] =
+{
+    {0x000001AA, 0x00001111}
+};
+static unsigned nv3TablePGRAPH_15BPP[][2] =
+{
+    {0x000001AA, 0x00002222}
+};
+static unsigned nv3TablePGRAPH_32BPP[][2] =
+{
+    {0x000001AA, 0x00003333}
+};
+static unsigned nv3TablePRAMIN[][2] =
+{
+    {0x00000500, 0x00010000},
+    {0x00000501, 0x007FFFFF},
+    {0x00000200, 0x80000000},
+    {0x00000201, 0x00C20341},
+    {0x00000204, 0x80000001},
+    {0x00000205, 0x00C50342},
+    {0x00000208, 0x80000002},
+    {0x00000209, 0x00C60343},
+    {0x0000020C, 0x80000003},
+    {0x0000020D, 0x00DC0348},
+    {0x00000210, 0x80000004},
+    {0x00000211, 0x00DC0349},
+    {0x00000214, 0x80000005},
+    {0x00000215, 0x00DC034A},
+    {0x00000218, 0x80000006},
+    {0x00000219, 0x00DC034B},
+    {0x00000240, 0x80000010},
+    {0x00000241, 0x00D10344},
+    {0x00000244, 0x80000011},
+    {0x00000245, 0x00D00345},
+    {0x00000248, 0x80000012},
+    {0x00000249, 0x00CC0346},
+    {0x0000024C, 0x80000013},
+    {0x0000024D, 0x00D70347},
+    {0x00000258, 0x80000016},
+    {0x00000259, 0x00CA034C},
+    {0x00000D05, 0x00000000},
+    {0x00000D06, 0x00000000},
+    {0x00000D07, 0x00000000},
+    {0x00000D09, 0x00000000},
+    {0x00000D0A, 0x00000000},
+    {0x00000D0B, 0x00000000},
+    {0x00000D0D, 0x00000000},
+    {0x00000D0E, 0x00000000},
+    {0x00000D0F, 0x00000000},
+    {0x00000D11, 0x00000000},
+    {0x00000D12, 0x00000000},
+    {0x00000D13, 0x00000000},
+    {0x00000D15, 0x00000000},
+    {0x00000D16, 0x00000000},
+    {0x00000D17, 0x00000000},
+    {0x00000D19, 0x00000000},
+    {0x00000D1A, 0x00000000},
+    {0x00000D1B, 0x00000000},
+    {0x00000D1D, 0x00000140},
+    {0x00000D1E, 0x00000000},
+    {0x00000D1F, 0x00000000},
+    {0x00000D20, 0x10100200},
+    {0x00000D21, 0x00000000},
+    {0x00000D22, 0x00000000},
+    {0x00000D23, 0x00000000},
+    {0x00000D24, 0x10210200},
+    {0x00000D25, 0x00000000},
+    {0x00000D26, 0x00000000},
+    {0x00000D27, 0x00000000},
+    {0x00000D28, 0x10420200},
+    {0x00000D29, 0x00000000},
+    {0x00000D2A, 0x00000000},
+    {0x00000D2B, 0x00000000},
+    {0x00000D2C, 0x10830200},
+    {0x00000D2D, 0x00000000},
+    {0x00000D2E, 0x00000000},
+    {0x00000D2F, 0x00000000},
+    {0x00000D31, 0x00000000},
+    {0x00000D32, 0x00000000},
+    {0x00000D33, 0x00000000}
+};
+static unsigned nv3TablePRAMIN_8BPP[][2] =
+{
+    /*           0xXXXXX3XX For  MSB mono format */
+    /*           0xXXXXX2XX For  LSB mono format */
+    {0x00000D04, 0x10110203},
+    {0x00000D08, 0x10110203},
+    {0x00000D0C, 0x1011020B},
+    {0x00000D10, 0x10118203},
+    {0x00000D14, 0x10110203},
+    {0x00000D18, 0x10110203},
+    {0x00000D1C, 0x10419208},
+    {0x00000D30, 0x10118203}
+};
+static unsigned nv3TablePRAMIN_15BPP[][2] =
+{
+    /*           0xXXXXX2XX For  MSB mono format */
+    /*           0xXXXXX3XX For  LSB mono format */
+    {0x00000D04, 0x10110200},
+    {0x00000D08, 0x10110200},
+    {0x00000D0C, 0x10110208},
+    {0x00000D10, 0x10118200},
+    {0x00000D14, 0x10110200},
+    {0x00000D18, 0x10110200},
+    {0x00000D1C, 0x10419208},
+    {0x00000D30, 0x10118200}
+};
+static unsigned nv3TablePRAMIN_32BPP[][2] =
+{
+    /*           0xXXXXX3XX For  MSB mono format */
+    /*           0xXXXXX2XX For  LSB mono format */
+    {0x00000D04, 0x10110201},
+    {0x00000D08, 0x10110201},
+    {0x00000D0C, 0x10110209},
+    {0x00000D10, 0x10118201},
+    {0x00000D14, 0x10110201},
+    {0x00000D18, 0x10110201},
+    {0x00000D1C, 0x10419208},
+    {0x00000D30, 0x10118201}
+};
+static unsigned nv4TableFIFO[][2] =
+{
+    {0x00003800, 0x80000014}
+};
+static unsigned nv4TablePFIFO[][2] =
+{
+    {0x00000140, 0x00000000},
+    {0x00000480, 0x00000000},
+    {0x00000494, 0x00000000},
+    {0x00000481, 0x00000000},
+    {0x0000048B, 0x00000000},
+    {0x00000400, 0x00000000},
+    {0x00000414, 0x00000000},
+    {0x00000084, 0x03000100},  
+    {0x00000085, 0x00000110},
+    {0x00000086, 0x00000112},  
+    {0x00000143, 0x0000FFFF},
+    {0x00000496, 0x0000FFFF},
+    {0x00000050, 0x00000000},
+    {0x00000040, 0xFFFFFFFF},
+    {0x00000415, 0x00000001},
+    {0x00000480, 0x00000001},
+    {0x00000494, 0x00000001},
+    {0x00000495, 0x00000001},
+    {0x00000140, 0x00000001}
+};
+static unsigned nv4TablePGRAPH[][2] =
+{
+    {0x00000020, 0x1231C001},
+    {0x00000021, 0x72111101},
+    {0x00000022, 0x11D5F071},
+    {0x00000023, 0x10D4FF31},
+    {0x00000060, 0x00000000},
+    {0x00000068, 0x00000000},
+    {0x00000070, 0x00000000},
+    {0x00000078, 0x00000000},
+    {0x00000061, 0x00000000},
+    {0x00000069, 0x00000000},
+    {0x00000071, 0x00000000},
+    {0x00000079, 0x00000000},
+    {0x00000062, 0x00000000},
+    {0x0000006A, 0x00000000},
+    {0x00000072, 0x00000000},
+    {0x0000007A, 0x00000000},
+    {0x00000063, 0x00000000},
+    {0x0000006B, 0x00000000},
+    {0x00000073, 0x00000000},
+    {0x0000007B, 0x00000000},
+    {0x00000064, 0x00000000},
+    {0x0000006C, 0x00000000},
+    {0x00000074, 0x00000000},
+    {0x0000007C, 0x00000000},
+    {0x00000065, 0x00000000},
+    {0x0000006D, 0x00000000},
+    {0x00000075, 0x00000000},
+    {0x0000007D, 0x00000000},
+    {0x00000066, 0x00000000},
+    {0x0000006E, 0x00000000},
+    {0x00000076, 0x00000000},
+    {0x0000007E, 0x00000000},
+    {0x00000067, 0x00000000},
+    {0x0000006F, 0x00000000},
+    {0x00000077, 0x00000000},
+    {0x0000007F, 0x00000000},
+    {0x00000058, 0x00000000},
+    {0x00000059, 0x00000000},
+    {0x0000005A, 0x00000000},
+    {0x0000005B, 0x00000000},
+    {0x00000196, 0x00000000},
+    {0x000001A1, 0x01FFFFFF},
+    {0x00000197, 0x00000000},
+    {0x000001A2, 0x01FFFFFF},
+    {0x00000198, 0x00000000},
+    {0x000001A3, 0x01FFFFFF},
+    {0x00000199, 0x00000000},
+    {0x000001A4, 0x01FFFFFF},
+    {0x00000050, 0x00000000},
+    {0x00000040, 0xFFFFFFFF},
+    {0x0000005C, 0x10010100},
+    {0x000001C4, 0xFFFFFFFF},
+    {0x000001C8, 0x00000001},
+    {0x00000204, 0x00000000},
+    {0x000001C3, 0x00000001}
+};
+static unsigned nv4TablePGRAPH_8BPP[][2] =
+{
+    {0x000001C9, 0x00111111},
+    {0x00000186, 0x00001010},
+    {0x0000020C, 0x03020202}
+};
+static unsigned nv4TablePGRAPH_15BPP[][2] =
+{
+    {0x000001C9, 0x00226222},
+    {0x00000186, 0x00002071},
+    {0x0000020C, 0x09080808}
+};
+static unsigned nv4TablePGRAPH_16BPP[][2] =
+{
+    {0x000001C9, 0x00556555},
+    {0x00000186, 0x000050C2},
+    {0x0000020C, 0x0C0B0B0B}
+};
+static unsigned nv4TablePGRAPH_32BPP[][2] =
+{
+    {0x000001C9, 0x0077D777},
+    {0x00000186, 0x000070E5},
+    {0x0000020C, 0x0E0D0D0D}
+};
+static unsigned nv4TablePRAMIN[][2] =
+{
+    {0x00000000, 0x80000010},
+    {0x00000001, 0x80011145},
+    {0x00000002, 0x80000011},
+    {0x00000003, 0x80011146},
+    {0x00000004, 0x80000012},
+    {0x00000005, 0x80011147},
+    {0x00000006, 0x80000013},
+    {0x00000007, 0x80011148},
+    {0x00000008, 0x80000014},
+    {0x00000009, 0x80011149},
+    {0x0000000A, 0x80000015},
+    {0x0000000B, 0x8001114A},
+    {0x0000000C, 0x80000016},
+    {0x0000000D, 0x8001114F},
+    {0x00000020, 0x80000000},
+    {0x00000021, 0x80011142},
+    {0x00000022, 0x80000001},
+    {0x00000023, 0x80011143},
+    {0x00000024, 0x80000002},
+    {0x00000025, 0x80011144}, 
+    {0x00000026, 0x80000003},
+    {0x00000027, 0x8001114B},
+    {0x00000028, 0x80000004},
+    {0x00000029, 0x8001114C},
+    {0x0000002A, 0x80000005},
+    {0x0000002B, 0x8001114D},
+    {0x0000002C, 0x80000006},
+    {0x0000002D, 0x8001114E},
+    {0x00000500, 0x00003000},
+    {0x00000501, 0x01FFFFFF},
+    {0x00000502, 0x00000002},
+    {0x00000503, 0x00000002},
+    {0x00000508, 0x01008043},
+    {0x0000050A, 0x00000000},
+    {0x0000050B, 0x00000000},
+    {0x0000050C, 0x01008019},
+    {0x0000050E, 0x00000000},
+    {0x0000050F, 0x00000000},
+#if 1
+    {0x00000510, 0x01008018},
+#else
+    {0x00000510, 0x01008044},
+#endif
+    {0x00000512, 0x00000000},
+    {0x00000513, 0x00000000},
+    {0x00000514, 0x01008021},
+    {0x00000516, 0x00000000},
+    {0x00000517, 0x00000000},
+    {0x00000518, 0x0100805F},
+    {0x0000051A, 0x00000000},
+    {0x0000051B, 0x00000000},
+#if 1
+    {0x0000051C, 0x0100804B},
+#else
+    {0x0000051C, 0x0100804A},
+#endif
+    {0x0000051E, 0x00000000},
+    {0x0000051F, 0x00000000},
+    {0x00000520, 0x0100A048},
+    {0x00000521, 0x00000D01},
+    {0x00000522, 0x11401140},
+    {0x00000523, 0x00000000},
+    {0x00000524, 0x0300A054},
+    {0x00000525, 0x00000D01},
+    {0x00000526, 0x11401140},
+    {0x00000527, 0x00000000},
+    {0x00000528, 0x0300A055},
+    {0x00000529, 0x00000D01},
+    {0x0000052A, 0x11401140},
+    {0x0000052B, 0x00000000},
+    {0x0000052C, 0x00000058},
+    {0x0000052E, 0x11401140},
+    {0x0000052F, 0x00000000},
+    {0x00000530, 0x00000059},
+    {0x00000532, 0x11401140},
+    {0x00000533, 0x00000000},
+    {0x00000534, 0x0000005A},
+    {0x00000536, 0x11401140},
+    {0x00000537, 0x00000000},
+    {0x00000538, 0x0000005B},
+    {0x0000053A, 0x11401140},
+    {0x0000053B, 0x00000000},
+    {0x0000053C, 0x0300A01C},
+    {0x0000053E, 0x11401140},
+    {0x0000053F, 0x00000000}
+};
+static unsigned nv4TablePRAMIN_8BPP[][2] =
+{
+    /*           0xXXXXXX01 For  MSB mono format */
+    /*           0xXXXXXX02 For  LSB mono format */
+    {0x00000509, 0x00000302},
+    {0x0000050D, 0x00000302},
+    {0x00000511, 0x00000202},
+    {0x00000515, 0x00000302},
+    {0x00000519, 0x00000302},
+    {0x0000051D, 0x00000302},
+    {0x0000052D, 0x00000302},
+    {0x0000052E, 0x00000302},
+    {0x00000535, 0x00000000},
+    {0x00000539, 0x00000000},
+    {0x0000053D, 0x00000302}
+};
+static unsigned nv4TablePRAMIN_15BPP[][2] =
+{
+    /*           0xXXXXXX01 For  MSB mono format */
+    /*           0xXXXXXX02 For  LSB mono format */
+    {0x00000509, 0x00000902},
+    {0x0000050D, 0x00000902},
+    {0x00000511, 0x00000802},
+    {0x00000515, 0x00000902},
+    {0x00000519, 0x00000902},
+    {0x0000051D, 0x00000902},
+    {0x0000052D, 0x00000902},
+    {0x0000052E, 0x00000902},
+    {0x00000535, 0x00000702},
+    {0x00000539, 0x00000702},
+    {0x0000053D, 0x00000902}
+};
+static unsigned nv4TablePRAMIN_16BPP[][2] =
+{
+    /*           0xXXXXXX01 For  MSB mono format */
+    /*           0xXXXXXX02 For  LSB mono format */
+    {0x00000509, 0x00000C02},
+    {0x0000050D, 0x00000C02},
+    {0x00000511, 0x00000B02},
+    {0x00000515, 0x00000C02},
+    {0x00000519, 0x00000C02},
+    {0x0000051D, 0x00000C02},
+    {0x0000052D, 0x00000C02},
+    {0x0000052E, 0x00000C02},
+    {0x00000535, 0x00000702},
+    {0x00000539, 0x00000702},
+    {0x0000053D, 0x00000C02}
+};
+static unsigned nv4TablePRAMIN_32BPP[][2] =
+{
+    /*           0xXXXXXX01 For  MSB mono format */
+    /*           0xXXXXXX02 For  LSB mono format */
+    {0x00000509, 0x00000E02},
+    {0x0000050D, 0x00000E02},
+    {0x00000511, 0x00000D02},
+    {0x00000515, 0x00000E02},
+    {0x00000519, 0x00000E02},
+    {0x0000051D, 0x00000E02},
+    {0x0000052D, 0x00000E02},
+    {0x0000052E, 0x00000E02},
+    {0x00000535, 0x00000E02},
+    {0x00000539, 0x00000E02},
+    {0x0000053D, 0x00000E02}
+};
+static unsigned nv10TableFIFO[][2] =
+{
+    {0x00003800, 0x80000014}
+};
+static unsigned nv10TablePFIFO[][2] =
+{
+    {0x00000140, 0x00000000},
+    {0x00000480, 0x00000000},
+    {0x00000494, 0x00000000},
+    {0x00000481, 0x00000000},
+    {0x0000048B, 0x00000000},
+    {0x00000400, 0x00000000},
+    {0x00000414, 0x00000000},
+    {0x00000084, 0x03000100},
+    {0x00000085, 0x00000110},
+    {0x00000086, 0x00000112},
+    {0x00000143, 0x0000FFFF},
+    {0x00000496, 0x0000FFFF},
+    {0x00000050, 0x00000000},
+    {0x00000040, 0xFFFFFFFF},
+    {0x00000415, 0x00000001},
+    {0x00000480, 0x00000001},
+    {0x00000494, 0x00000001},
+    {0x00000495, 0x00000001},
+    {0x00000140, 0x00000001}
+};
+static unsigned nv10TablePGRAPH[][2] =
+{
+    {0x00000020, 0x0003FFFF},
+    {0x00000021, 0x00118701},
+    {0x00000022, 0x24F82AD9},
+    {0x00000023, 0x55DE0030},
+    {0x00000020, 0x00000000},
+    {0x00000024, 0x00000000},
+    {0x00000058, 0x00000000},
+    {0x00000060, 0x00000000},
+    {0x00000068, 0x00000000},
+    {0x00000070, 0x00000000},
+    {0x00000078, 0x00000000},
+    {0x00000059, 0x00000000},
+    {0x00000061, 0x00000000},
+    {0x00000069, 0x00000000},
+    {0x00000071, 0x00000000},
+    {0x00000079, 0x00000000},
+    {0x0000005A, 0x00000000},
+    {0x00000062, 0x00000000},
+    {0x0000006A, 0x00000000},
+    {0x00000072, 0x00000000},
+    {0x0000007A, 0x00000000},
+    {0x0000005B, 0x00000000},
+    {0x00000063, 0x00000000},
+    {0x0000006B, 0x00000000},
+    {0x00000073, 0x00000000},
+    {0x0000007B, 0x00000000},
+    {0x0000005C, 0x00000000},
+    {0x00000064, 0x00000000},
+    {0x0000006C, 0x00000000},
+    {0x00000074, 0x00000000},
+    {0x0000007C, 0x00000000},
+    {0x0000005D, 0x00000000},
+    {0x00000065, 0x00000000},
+    {0x0000006D, 0x00000000},
+    {0x00000075, 0x00000000},
+    {0x0000007D, 0x00000000},
+    {0x0000005E, 0x00000000},
+    {0x00000066, 0x00000000},
+    {0x0000006E, 0x00000000},
+    {0x00000076, 0x00000000},
+    {0x0000007E, 0x00000000},
+    {0x0000005F, 0x00000000},
+    {0x00000067, 0x00000000},
+    {0x0000006F, 0x00000000},
+    {0x00000077, 0x00000000},
+    {0x0000007F, 0x00000000},
+    {0x00000053, 0x00000000},
+    {0x00000054, 0x00000000},
+    {0x00000055, 0x00000000},
+    {0x00000056, 0x00000000},
+    {0x00000057, 0x00000000},
+    {0x00000196, 0x00000000},
+    {0x000001A1, 0x01FFFFFF},
+    {0x00000197, 0x00000000},
+    {0x000001A2, 0x01FFFFFF},
+    {0x00000198, 0x00000000},
+    {0x000001A3, 0x01FFFFFF},
+    {0x00000199, 0x00000000},
+    {0x000001A4, 0x01FFFFFF},
+    {0x0000019A, 0x00000000},
+    {0x000001A5, 0x01FFFFFF},
+    {0x0000019B, 0x00000000},
+    {0x000001A6, 0x01FFFFFF},
+    {0x00000050, 0x01111111},
+    {0x00000040, 0xFFFFFFFF},
+    {0x00000051, 0x10010100},
+    {0x000001C5, 0xFFFFFFFF},
+    {0x000001C8, 0x00000001},
+    {0x00000204, 0x00000000},
+    {0x000001C4, 0x00000001}
+};
+static unsigned nv10TablePGRAPH_8BPP[][2] =
+{
+    {0x000001C9, 0x00111111},
+    {0x00000186, 0x00001010},
+    {0x0000020C, 0x03020202}
+};
+static unsigned nv10TablePGRAPH_15BPP[][2] =
+{
+    {0x000001C9, 0x00226222},
+    {0x00000186, 0x00002071},
+    {0x0000020C, 0x09080808}
+};
+static unsigned nv10TablePGRAPH_16BPP[][2] =
+{
+    {0x000001C9, 0x00556555},
+    {0x00000186, 0x000050C2},
+    {0x0000020C, 0x000B0B0C}
+};
+static unsigned nv10TablePGRAPH_32BPP[][2] =
+{
+    {0x000001C9, 0x0077D777},
+    {0x00000186, 0x000070E5},
+    {0x0000020C, 0x0E0D0D0D}
+};
+static unsigned nv10tri05TablePGRAPH[][2] =
+{
+    {(0x00000E00/4), 0x00000000},
+    {(0x00000E04/4), 0x00000000},
+    {(0x00000E08/4), 0x00000000},
+    {(0x00000E0C/4), 0x00000000},
+    {(0x00000E10/4), 0x00001000},
+    {(0x00000E14/4), 0x00001000},
+    {(0x00000E18/4), 0x4003ff80},
+    {(0x00000E1C/4), 0x00000000},
+    {(0x00000E20/4), 0x00000000},
+    {(0x00000E24/4), 0x00000000},
+    {(0x00000E28/4), 0x00000000},
+    {(0x00000E2C/4), 0x00000000},
+    {(0x00000E30/4), 0x00080008},
+    {(0x00000E34/4), 0x00080008},
+    {(0x00000E38/4), 0x00000000},
+    {(0x00000E3C/4), 0x00000000},
+    {(0x00000E40/4), 0x00000000},
+    {(0x00000E44/4), 0x00000000},
+    {(0x00000E48/4), 0x00000000},
+    {(0x00000E4C/4), 0x00000000},
+    {(0x00000E50/4), 0x00000000},
+    {(0x00000E54/4), 0x00000000},
+    {(0x00000E58/4), 0x00000000},
+    {(0x00000E5C/4), 0x00000000},
+    {(0x00000E60/4), 0x00000000},
+    {(0x00000E64/4), 0x10000000},
+    {(0x00000E68/4), 0x00000000},
+    {(0x00000E6C/4), 0x00000000},
+    {(0x00000E70/4), 0x00000000},
+    {(0x00000E74/4), 0x00000000},
+    {(0x00000E78/4), 0x00000000},
+    {(0x00000E7C/4), 0x00000000},
+    {(0x00000E80/4), 0x00000000},
+    {(0x00000E84/4), 0x00000000},
+    {(0x00000E88/4), 0x08000000},
+    {(0x00000E8C/4), 0x00000000},
+    {(0x00000E90/4), 0x00000000},
+    {(0x00000E94/4), 0x00000000},
+    {(0x00000E98/4), 0x00000000},
+    {(0x00000E9C/4), 0x4B7FFFFF},
+    {(0x00000EA0/4), 0x00000000},
+    {(0x00000EA4/4), 0x00000000},
+    {(0x00000EA8/4), 0x00000000},
+    {(0x00000F00/4), 0x07FF0800},
+    {(0x00000F04/4), 0x07FF0800},
+    {(0x00000F08/4), 0x07FF0800},
+    {(0x00000F0C/4), 0x07FF0800},
+    {(0x00000F10/4), 0x07FF0800},
+    {(0x00000F14/4), 0x07FF0800},
+    {(0x00000F18/4), 0x07FF0800},
+    {(0x00000F1C/4), 0x07FF0800},
+    {(0x00000F20/4), 0x07FF0800},
+    {(0x00000F24/4), 0x07FF0800},
+    {(0x00000F28/4), 0x07FF0800},
+    {(0x00000F2C/4), 0x07FF0800},
+    {(0x00000F30/4), 0x07FF0800},
+    {(0x00000F34/4), 0x07FF0800},
+    {(0x00000F38/4), 0x07FF0800},
+    {(0x00000F3C/4), 0x07FF0800},
+    {(0x00000F40/4), 0x10000000},
+    {(0x00000F44/4), 0x00000000},
+    {(0x00000F50/4), 0x00006740},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x3F800000},
+    {(0x00000F50/4), 0x00006750},
+    {(0x00000F54/4), 0x40000000},
+    {(0x00000F54/4), 0x40000000},
+    {(0x00000F54/4), 0x40000000},
+    {(0x00000F54/4), 0x40000000},
+    {(0x00000F50/4), 0x00006760},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x3F800000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F50/4), 0x00006770},
+    {(0x00000F54/4), 0xC5000000},
+    {(0x00000F54/4), 0xC5000000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F50/4), 0x00006780},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x3F800000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F50/4), 0x000067A0},
+    {(0x00000F54/4), 0x3F800000},
+    {(0x00000F54/4), 0x3F800000},
+    {(0x00000F54/4), 0x3F800000},
+    {(0x00000F54/4), 0x3F800000},
+    {(0x00000F50/4), 0x00006AB0},
+    {(0x00000F54/4), 0x3F800000},
+    {(0x00000F54/4), 0x3F800000},
+    {(0x00000F54/4), 0x3F800000},
+    {(0x00000F50/4), 0x00006AC0},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F50/4), 0x00006C10},
+    {(0x00000F54/4), 0xBF800000},
+    {(0x00000F50/4), 0x00007030},
+    {(0x00000F54/4), 0x7149F2CA},
+    {(0x00000F50/4), 0x00007040},
+    {(0x00000F54/4), 0x7149F2CA},
+    {(0x00000F50/4), 0x00007050},
+    {(0x00000F54/4), 0x7149F2CA},
+    {(0x00000F50/4), 0x00007060},
+    {(0x00000F54/4), 0x7149F2CA},
+    {(0x00000F50/4), 0x00007070},
+    {(0x00000F54/4), 0x7149F2CA},
+    {(0x00000F50/4), 0x00007080},
+    {(0x00000F54/4), 0x7149F2CA},
+    {(0x00000F50/4), 0x00007090},
+    {(0x00000F54/4), 0x7149F2CA},
+    {(0x00000F50/4), 0x000070A0},
+    {(0x00000F54/4), 0x7149F2CA},
+    {(0x00000F50/4), 0x00006A80},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x3F800000},
+    {(0x00000F50/4), 0x00006AA0},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F50/4), 0x00000040},
+    {(0x00000F54/4), 0x00000005},
+    {(0x00000F50/4), 0x00006400},
+    {(0x00000F54/4), 0x3F800000},
+    {(0x00000F54/4), 0x3F800000},
+    {(0x00000F54/4), 0x4B7FFFFF},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F50/4), 0x00006410},
+    {(0x00000F54/4), 0xC5000000},
+    {(0x00000F54/4), 0xC5000000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F50/4), 0x00006420},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F50/4), 0x00006430},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F50/4), 0x000064C0},
+    {(0x00000F54/4), 0x3F800000},
+    {(0x00000F54/4), 0x3F800000},
+    {(0x00000F54/4), 0x477FFFFF},
+    {(0x00000F54/4), 0x3F800000},
+    {(0x00000F50/4), 0x000064D0},
+    {(0x00000F54/4), 0xC5000000},
+    {(0x00000F54/4), 0xC5000000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F50/4), 0x000064E0},
+    {(0x00000F54/4), 0xC4FFF000},
+    {(0x00000F54/4), 0xC4FFF000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F50/4), 0x000064F0},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F54/4), 0x00000000},
+    {(0x00000F40/4), 0x30000000},
+    {(0x00000F44/4), 0x00000004},
+    {(0x00000F48/4), 0x10000000},
+    {(0x00000F4C/4), 0x00000000}
+};
+static unsigned nv10TablePRAMIN[][2] =
+{
+    {0x00000000, 0x80000010},
+    {0x00000001, 0x80011145},
+    {0x00000002, 0x80000011},
+    {0x00000003, 0x80011146},
+    {0x00000004, 0x80000012},
+    {0x00000005, 0x80011147},
+    {0x00000006, 0x80000013},
+    {0x00000007, 0x80011148},
+    {0x00000008, 0x80000014},
+    {0x00000009, 0x80011149},
+    {0x0000000A, 0x80000015},
+    {0x0000000B, 0x8001114A},
+    {0x0000000C, 0x80000016},
+    {0x0000000D, 0x80011150},
+    {0x00000020, 0x80000000},
+    {0x00000021, 0x80011142},
+    {0x00000022, 0x80000001},
+    {0x00000023, 0x80011143},
+    {0x00000024, 0x80000002},
+    {0x00000025, 0x80011144},
+    {0x00000026, 0x80000003},
+    {0x00000027, 0x8001114B},
+    {0x00000028, 0x80000004},
+    {0x00000029, 0x8001114C},
+    {0x0000002A, 0x80000005},
+    {0x0000002B, 0x8001114D},
+    {0x0000002C, 0x80000006},
+    {0x0000002D, 0x8001114E},
+    {0x0000002E, 0x80000007},
+    {0x0000002F, 0x8001114F},
+    {0x00000500, 0x00003000},
+    {0x00000501, 0x01FFFFFF},
+    {0x00000502, 0x00000002},
+    {0x00000503, 0x00000002},
+#ifdef __BIG_ENDIAN
+    {0x00000508, 0x01088043}, 
+#else
+    {0x00000508, 0x01008043},
+#endif
+    {0x0000050A, 0x00000000},
+    {0x0000050B, 0x00000000},
+#ifdef __BIG_ENDIAN
+    {0x0000050C, 0x01088019},
+#else
+    {0x0000050C, 0x01008019},
+#endif
+    {0x0000050E, 0x00000000},
+    {0x0000050F, 0x00000000},
+#ifdef __BIG_ENDIAN
+    {0x00000510, 0x01088018},
+#else
+    {0x00000510, 0x01008018},
+#endif
+    {0x00000512, 0x00000000},
+    {0x00000513, 0x00000000},
+#ifdef __BIG_ENDIAN
+    {0x00000514, 0x01088021},
+#else
+    {0x00000514, 0x01008021},
+#endif
+    {0x00000516, 0x00000000},
+    {0x00000517, 0x00000000},
+#ifdef __BIG_ENDIAN
+    {0x00000518, 0x0108805F},
+#else
+    {0x00000518, 0x0100805F},
+#endif
+    {0x0000051A, 0x00000000},
+    {0x0000051B, 0x00000000},
+#ifdef __BIG_ENDIAN
+    {0x0000051C, 0x0108804B},
+#else
+    {0x0000051C, 0x0100804B},
+#endif
+    {0x0000051E, 0x00000000},
+    {0x0000051F, 0x00000000},
+    {0x00000520, 0x0100A048},
+    {0x00000521, 0x00000D01},
+    {0x00000522, 0x11401140},
+    {0x00000523, 0x00000000},
+    {0x00000524, 0x0300A094},
+    {0x00000525, 0x00000D01},
+    {0x00000526, 0x11401140},
+    {0x00000527, 0x00000000},
+    {0x00000528, 0x0300A095},
+    {0x00000529, 0x00000D01},
+    {0x0000052A, 0x11401140},
+    {0x0000052B, 0x00000000},
+#ifdef __BIG_ENDIAN
+    {0x0000052C, 0x00080058},
+#else
+    {0x0000052C, 0x00000058},
+#endif
+    {0x0000052E, 0x11401140},
+    {0x0000052F, 0x00000000},
+#ifdef __BIG_ENDIAN
+    {0x00000530, 0x00080059},
+#else
+    {0x00000530, 0x00000059},
+#endif
+    {0x00000532, 0x11401140},
+    {0x00000533, 0x00000000},
+    {0x00000534, 0x0000005A},
+    {0x00000536, 0x11401140},
+    {0x00000537, 0x00000000},
+    {0x00000538, 0x0000005B},
+    {0x0000053A, 0x11401140},
+    {0x0000053B, 0x00000000},
+    {0x0000053C, 0x00000093},
+    {0x0000053E, 0x11401140},
+    {0x0000053F, 0x00000000},
+#ifdef __BIG_ENDIAN
+    {0x00000540, 0x0308A01C},
+#else
+    {0x00000540, 0x0300A01C},
+#endif
+    {0x00000542, 0x11401140},
+    {0x00000543, 0x00000000}
+};
+static unsigned nv10TablePRAMIN_8BPP[][2] =
+{
+    /*           0xXXXXXX01 For  MSB mono format */
+    /*           0xXXXXXX02 For  LSB mono format */
+    {0x00000509, 0x00000302},
+    {0x0000050D, 0x00000302},
+    {0x00000511, 0x00000202},
+    {0x00000515, 0x00000302},
+    {0x00000519, 0x00000302},
+    {0x0000051D, 0x00000302},
+    {0x0000052D, 0x00000302},
+    {0x0000052E, 0x00000302},
+    {0x00000535, 0x00000000},
+    {0x00000539, 0x00000000},
+    {0x0000053D, 0x00000000},
+    {0x00000541, 0x00000302}
+};
+static unsigned nv10TablePRAMIN_15BPP[][2] =
+{
+    /*           0xXXXXXX01 For  MSB mono format */
+    /*           0xXXXXXX02 For  LSB mono format */
+    {0x00000509, 0x00000902},
+    {0x0000050D, 0x00000902},
+    {0x00000511, 0x00000802},
+    {0x00000515, 0x00000902},
+    {0x00000519, 0x00000902},
+    {0x0000051D, 0x00000902},
+    {0x0000052D, 0x00000902},
+    {0x0000052E, 0x00000902},
+    {0x00000535, 0x00000902},
+    {0x00000539, 0x00000902}, 
+    {0x0000053D, 0x00000902},
+    {0x00000541, 0x00000902}
+};
+static unsigned nv10TablePRAMIN_16BPP[][2] =
+{
+    /*           0xXXXXXX01 For  MSB mono format */
+    /*           0xXXXXXX02 For  LSB mono format */
+    {0x00000509, 0x00000C02},
+    {0x0000050D, 0x00000C02},
+    {0x00000511, 0x00000B02},
+    {0x00000515, 0x00000C02},
+    {0x00000519, 0x00000C02},
+    {0x0000051D, 0x00000C02},
+    {0x0000052D, 0x00000C02},
+    {0x0000052E, 0x00000C02},
+    {0x00000535, 0x00000C02},
+    {0x00000539, 0x00000C02},
+    {0x0000053D, 0x00000C02},
+    {0x00000541, 0x00000C02}
+};
+static unsigned nv10TablePRAMIN_32BPP[][2] =
+{
+    /*           0xXXXXXX01 For  MSB mono format */
+    /*           0xXXXXXX02 For  LSB mono format */
+    {0x00000509, 0x00000E02},
+    {0x0000050D, 0x00000E02},
+    {0x00000511, 0x00000D02},
+    {0x00000515, 0x00000E02},
+    {0x00000519, 0x00000E02},
+    {0x0000051D, 0x00000E02},
+    {0x0000052D, 0x00000E02},
+    {0x0000052E, 0x00000E02},
+    {0x00000535, 0x00000E02},
+    {0x00000539, 0x00000E02},
+    {0x0000053D, 0x00000E02},
+    {0x00000541, 0x00000E02}
+};
+
diff --git a/drivers/video/riva/rivafb-i2c.c b/drivers/video/riva/rivafb-i2c.c
new file mode 100644
index 0000000..da1334d
--- /dev/null
+++ b/drivers/video/riva/rivafb-i2c.c
@@ -0,0 +1,214 @@
+/*
+ * linux/drivers/video/riva/fbdev-i2c.c - nVidia i2c
+ *
+ * Maintained by Ani Joshi <ajoshi@shell.unixbox.com>
+ *
+ * Copyright 2004 Antonino A. Daplas <adaplas @pol.net>
+ *
+ * Based on radeonfb-i2c.c
+ *
+ * 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/sched.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/fb.h>
+#include <linux/jiffies.h>
+
+#include <asm/io.h>
+
+#include "rivafb.h"
+#include "../edid.h"
+
+#define RIVA_DDC 	0x50
+
+static void riva_gpio_setscl(void* data, int state)
+{
+	struct riva_i2c_chan 	*chan = (struct riva_i2c_chan *)data;
+	struct riva_par 	*par = chan->par;
+	u32			val;
+
+	VGA_WR08(par->riva.PCIO, 0x3d4, chan->ddc_base + 1);
+	val = VGA_RD08(par->riva.PCIO, 0x3d5) & 0xf0;
+
+	if (state)
+		val |= 0x20;
+	else
+		val &= ~0x20;
+
+	VGA_WR08(par->riva.PCIO, 0x3d4, chan->ddc_base + 1);
+	VGA_WR08(par->riva.PCIO, 0x3d5, val | 0x1);
+}
+
+static void riva_gpio_setsda(void* data, int state)
+{
+	struct riva_i2c_chan 	*chan = (struct riva_i2c_chan *)data;
+	struct riva_par 	*par = chan->par;
+	u32			val;
+
+	VGA_WR08(par->riva.PCIO, 0x3d4, chan->ddc_base + 1);
+	val = VGA_RD08(par->riva.PCIO, 0x3d5) & 0xf0;
+
+	if (state)
+		val |= 0x10;
+	else
+		val &= ~0x10;
+
+	VGA_WR08(par->riva.PCIO, 0x3d4, chan->ddc_base + 1);
+	VGA_WR08(par->riva.PCIO, 0x3d5, val | 0x1);
+}
+
+static int riva_gpio_getscl(void* data)
+{
+	struct riva_i2c_chan 	*chan = (struct riva_i2c_chan *)data;
+	struct riva_par 	*par = chan->par;
+	u32			val = 0;
+
+	VGA_WR08(par->riva.PCIO, 0x3d4, chan->ddc_base);
+	if (VGA_RD08(par->riva.PCIO, 0x3d5) & 0x04)
+		val = 1;
+
+	val = VGA_RD08(par->riva.PCIO, 0x3d5);
+
+	return val;
+}
+
+static int riva_gpio_getsda(void* data)
+{
+	struct riva_i2c_chan 	*chan = (struct riva_i2c_chan *)data;
+	struct riva_par 	*par = chan->par;
+	u32			val = 0;
+
+	VGA_WR08(par->riva.PCIO, 0x3d4, chan->ddc_base);
+	if (VGA_RD08(par->riva.PCIO, 0x3d5) & 0x08)
+		val = 1;
+
+	return val;
+}
+
+#define I2C_ALGO_RIVA   0x0e0000
+static int riva_setup_i2c_bus(struct riva_i2c_chan *chan, const char *name)
+{
+	int rc;
+
+	strcpy(chan->adapter.name, name);
+	chan->adapter.owner		= THIS_MODULE;
+	chan->adapter.id		= I2C_ALGO_RIVA;
+	chan->adapter.algo_data		= &chan->algo;
+	chan->adapter.dev.parent	= &chan->par->pdev->dev;
+	chan->algo.setsda		= riva_gpio_setsda;
+	chan->algo.setscl		= riva_gpio_setscl;
+	chan->algo.getsda		= riva_gpio_getsda;
+	chan->algo.getscl		= riva_gpio_getscl;
+	chan->algo.udelay		= 40;
+	chan->algo.timeout		= msecs_to_jiffies(2);
+	chan->algo.data 		= chan;
+
+	i2c_set_adapdata(&chan->adapter, chan);
+
+	/* Raise SCL and SDA */
+	riva_gpio_setsda(chan, 1);
+	riva_gpio_setscl(chan, 1);
+	udelay(20);
+
+	rc = i2c_bit_add_bus(&chan->adapter);
+	if (rc == 0)
+		dev_dbg(&chan->par->pdev->dev, "I2C bus %s registered.\n", name);
+	else {
+		dev_warn(&chan->par->pdev->dev,
+			 "Failed to register I2C bus %s.\n", name);
+		chan->par = NULL;
+	}
+
+	return rc;
+}
+
+void riva_create_i2c_busses(struct riva_par *par)
+{
+	par->bus = 3;
+
+	par->chan[0].par	= par;
+	par->chan[1].par	= par;
+	par->chan[2].par        = par;
+
+	par->chan[0].ddc_base = 0x3e;
+	par->chan[1].ddc_base = 0x36;
+	par->chan[2].ddc_base = 0x50;
+	riva_setup_i2c_bus(&par->chan[0], "BUS1");
+	riva_setup_i2c_bus(&par->chan[1], "BUS2");
+	riva_setup_i2c_bus(&par->chan[2], "BUS3");
+}
+
+void riva_delete_i2c_busses(struct riva_par *par)
+{
+	if (par->chan[0].par)
+		i2c_bit_del_bus(&par->chan[0].adapter);
+	par->chan[0].par = NULL;
+
+	if (par->chan[1].par)
+		i2c_bit_del_bus(&par->chan[1].adapter);
+	par->chan[1].par = NULL;
+
+	if (par->chan[2].par)
+		i2c_bit_del_bus(&par->chan[2].adapter);
+	par->chan[2].par = NULL;
+}
+
+static u8 *riva_do_probe_i2c_edid(struct riva_i2c_chan *chan)
+{
+	u8 start = 0x0;
+	struct i2c_msg msgs[] = {
+		{
+			.addr	= RIVA_DDC,
+			.len	= 1,
+			.buf	= &start,
+		}, {
+			.addr	= RIVA_DDC,
+			.flags	= I2C_M_RD,
+			.len	= EDID_LENGTH,
+		},
+	};
+	u8 *buf;
+
+	if (!chan->par)
+		return NULL;
+
+	buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
+	if (!buf) {
+		dev_warn(&chan->par->pdev->dev, "Out of memory!\n");
+		return NULL;
+	}
+	msgs[1].buf = buf;
+
+	if (i2c_transfer(&chan->adapter, msgs, 2) == 2)
+		return buf;
+	dev_dbg(&chan->par->pdev->dev, "Unable to read EDID block.\n");
+	kfree(buf);
+	return NULL;
+}
+
+int riva_probe_i2c_connector(struct riva_par *par, int conn, u8 **out_edid)
+{
+	u8 *edid = NULL;
+	int i;
+
+	for (i = 0; i < 3; i++) {
+		/* Do the real work */
+		edid = riva_do_probe_i2c_edid(&par->chan[conn-1]);
+		if (edid)
+			break;
+	}
+	if (out_edid)
+		*out_edid = edid;
+	if (!edid)
+		return 1;
+
+	return 0;
+}
+
diff --git a/drivers/video/riva/rivafb.h b/drivers/video/riva/rivafb.h
new file mode 100644
index 0000000..440ff44
--- /dev/null
+++ b/drivers/video/riva/rivafb.h
@@ -0,0 +1,79 @@
+#ifndef __RIVAFB_H
+#define __RIVAFB_H
+
+#include <linux/config.h>
+#include <linux/fb.h>
+#include <video/vga.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/i2c-algo-bit.h>
+
+#include "riva_hw.h"
+
+/* GGI compatibility macros */
+#define NUM_SEQ_REGS		0x05
+#define NUM_CRT_REGS		0x41
+#define NUM_GRC_REGS		0x09
+#define NUM_ATC_REGS		0x15
+
+/* I2C */
+#define DDC_SCL_READ_MASK       (1 << 2)
+#define DDC_SCL_WRITE_MASK      (1 << 5)
+#define DDC_SDA_READ_MASK       (1 << 3)
+#define DDC_SDA_WRITE_MASK      (1 << 4)
+
+/* holds the state of the VGA core and extended Riva hw state from riva_hw.c.
+ * From KGI originally. */
+struct riva_regs {
+	u8 attr[NUM_ATC_REGS];
+	u8 crtc[NUM_CRT_REGS];
+	u8 gra[NUM_GRC_REGS];
+	u8 seq[NUM_SEQ_REGS];
+	u8 misc_output;
+	RIVA_HW_STATE ext;
+};
+
+struct riva_par;
+
+struct riva_i2c_chan {
+	struct riva_par *par;
+	unsigned long   ddc_base;
+	struct i2c_adapter adapter;
+	struct i2c_algo_bit_data algo;
+};
+
+struct riva_par {
+	RIVA_HW_INST riva;	/* interface to riva_hw.c */
+	u32 pseudo_palette[16]; /* default palette */
+	u32 palette[16];        /* for Riva128 */
+	u8 __iomem *ctrl_base;	/* virtual control register base addr */
+	unsigned dclk_max;	/* max DCLK */
+
+	struct riva_regs initial_state;	/* initial startup video mode */
+	struct riva_regs current_state;
+#ifdef CONFIG_X86
+	struct vgastate state;
+#endif
+	atomic_t ref_count;
+	unsigned char *EDID;
+	unsigned int Chipset;
+	int forceCRTC;
+	Bool SecondCRTC;
+	int FlatPanel;
+	struct pci_dev *pdev;
+	int bus;
+	int cursor_reset;
+#ifdef CONFIG_MTRR
+	struct { int vram; int vram_valid; } mtrr;
+#endif
+	struct riva_i2c_chan chan[3];
+};
+
+void riva_common_setup(struct riva_par *);
+unsigned long riva_get_memlen(struct riva_par *);
+unsigned long riva_get_maxdclk(struct riva_par *);
+void riva_delete_i2c_busses(struct riva_par *par);
+void riva_create_i2c_busses(struct riva_par *par);
+int riva_probe_i2c_connector(struct riva_par *par, int conn, u8 **out_edid);
+
+#endif /* __RIVAFB_H */
diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c
new file mode 100644
index 0000000..b637c38
--- /dev/null
+++ b/drivers/video/s1d13xxxfb.c
@@ -0,0 +1,772 @@
+/* drivers/video/s1d13xxxfb.c
+ *
+ * (c) 2004 Simtec Electronics
+ * (c) 2005 Thibaut VARENE <varenet@parisc-linux.org>
+ *
+ * Driver for Epson S1D13xxx series framebuffer chips
+ *
+ * Adapted from
+ *  linux/drivers/video/skeletonfb.c
+ *  linux/drivers/video/epson1355fb.c
+ *  linux/drivers/video/epson/s1d13xxxfb.c (2.4 driver by Epson)
+ *
+ * Note, currently only tested on S1D13806 with 16bit CRT.
+ * As such, this driver might still contain some hardcoded bits relating to
+ * S1D13806.
+ * Making it work on other S1D13XXX chips should merely be a matter of adding
+ * a few switch()s, some missing glue here and there maybe, and split header
+ * files.
+ *
+ * TODO: - handle dual screen display (CRT and LCD at the same time).
+ *	 - check_var(), mode change, etc.
+ *	 - PM untested.
+ *	 - Accelerated interfaces.
+ *	 - Probably not SMP safe :)
+ *
+ * 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/device.h>
+#include <linux/delay.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/fb.h>
+
+#include <asm/io.h>
+
+#include <video/s1d13xxxfb.h>
+
+#define PFX "s1d13xxxfb: "
+
+#if 0
+#define dbg(fmt, args...) do { printk(KERN_INFO fmt, ## args); } while(0)
+#else
+#define dbg(fmt, args...) do { } while (0)
+#endif
+
+/*
+ * Here we define the default struct fb_fix_screeninfo
+ */
+static struct fb_fix_screeninfo __devinitdata s1d13xxxfb_fix = {
+	.id		= S1D_FBID,
+	.type		= FB_TYPE_PACKED_PIXELS,
+	.visual		= FB_VISUAL_PSEUDOCOLOR,
+	.xpanstep	= 0,
+	.ypanstep	= 1,
+	.ywrapstep	= 0,
+	.accel		= FB_ACCEL_NONE,
+};
+
+static inline u8
+s1d13xxxfb_readreg(struct s1d13xxxfb_par *par, u16 regno)
+{
+	return readb(par->regs + regno);
+}
+
+static inline void
+s1d13xxxfb_writereg(struct s1d13xxxfb_par *par, u16 regno, u8 value)
+{
+	writeb(value, par->regs + regno);
+}
+
+static inline void
+s1d13xxxfb_runinit(struct s1d13xxxfb_par *par,
+			const struct s1d13xxxfb_regval *initregs,
+			const unsigned int size)
+{
+	int i;
+
+	for (i = 0; i < size; i++) {
+        	if ((initregs[i].addr == S1DREG_DELAYOFF) ||
+				(initregs[i].addr == S1DREG_DELAYON))
+			mdelay((int)initregs[i].value);
+        	else {
+			s1d13xxxfb_writereg(par, initregs[i].addr, initregs[i].value);
+		}
+        }
+
+	/* make sure the hardware can cope with us */
+	mdelay(1);
+}
+
+static inline void
+lcd_enable(struct s1d13xxxfb_par *par, int enable)
+{
+	u8 mode = s1d13xxxfb_readreg(par, S1DREG_COM_DISP_MODE);
+
+	if (enable)
+		mode |= 0x01;
+	else
+		mode &= ~0x01;
+
+	s1d13xxxfb_writereg(par, S1DREG_COM_DISP_MODE, mode);
+}
+
+static inline void
+crt_enable(struct s1d13xxxfb_par *par, int enable)
+{
+	u8 mode = s1d13xxxfb_readreg(par, S1DREG_COM_DISP_MODE);
+
+	if (enable)
+		mode |= 0x02;
+	else
+		mode &= ~0x02;
+
+	s1d13xxxfb_writereg(par, S1DREG_COM_DISP_MODE, mode);
+}
+
+/* framebuffer control routines */
+
+static inline void
+s1d13xxxfb_setup_pseudocolour(struct fb_info *info)
+{
+	info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+
+	info->var.red.length = 4;
+	info->var.green.length = 4;
+	info->var.blue.length = 4;
+}
+
+static inline void
+s1d13xxxfb_setup_truecolour(struct fb_info *info)
+{
+	info->fix.visual = FB_VISUAL_TRUECOLOR;
+	info->var.bits_per_pixel = 16;
+
+	info->var.red.length = 5;
+	info->var.red.offset = 11;
+
+	info->var.green.length = 6;
+	info->var.green.offset = 5;
+
+	info->var.blue.length = 5;
+	info->var.blue.offset = 0;
+}
+
+/**
+ *      s1d13xxxfb_set_par - Alters the hardware state.
+ *      @info: frame buffer structure
+ *
+ *	Using the fb_var_screeninfo in fb_info we set the depth of the
+ *	framebuffer. This function alters the par AND the
+ *	fb_fix_screeninfo stored in fb_info. It doesn't not alter var in
+ *	fb_info since we are using that data. This means we depend on the
+ *	data in var inside fb_info to be supported by the hardware.
+ *	xxxfb_check_var is always called before xxxfb_set_par to ensure this.
+ *
+ *	XXX TODO: write proper s1d13xxxfb_check_var(), without which that
+ *	function is quite useless.
+ */
+static int
+s1d13xxxfb_set_par(struct fb_info *info)
+{
+	struct s1d13xxxfb_par *s1dfb = info->par;
+	unsigned int val;
+
+	dbg("s1d13xxxfb_set_par: bpp=%d\n", info->var.bits_per_pixel);
+
+	if ((s1dfb->display & 0x01))	/* LCD */
+		val = s1d13xxxfb_readreg(s1dfb, S1DREG_LCD_DISP_MODE);   /* read colour control */
+	else	/* CRT */
+		val = s1d13xxxfb_readreg(s1dfb, S1DREG_CRT_DISP_MODE);   /* read colour control */
+
+	val &= ~0x07;
+
+	switch (info->var.bits_per_pixel) {
+		case 4:
+			dbg("pseudo colour 4\n");
+			s1d13xxxfb_setup_pseudocolour(info);
+			val |= 2;
+			break;
+		case 8:
+			dbg("pseudo colour 8\n");
+			s1d13xxxfb_setup_pseudocolour(info);
+			val |= 3;
+			break;
+		case 16:
+			dbg("true colour\n");
+			s1d13xxxfb_setup_truecolour(info);
+			val |= 5;
+			break;
+
+		default:
+			dbg("bpp not supported!\n");
+			return -EINVAL;
+	}
+
+	dbg("writing %02x to display mode register\n", val);
+
+	if ((s1dfb->display & 0x01))	/* LCD */
+		s1d13xxxfb_writereg(s1dfb, S1DREG_LCD_DISP_MODE, val);
+	else	/* CRT */
+		s1d13xxxfb_writereg(s1dfb, S1DREG_CRT_DISP_MODE, val);
+
+	info->fix.line_length  = info->var.xres * info->var.bits_per_pixel;
+	info->fix.line_length /= 8;
+
+	dbg("setting line_length to %d\n", info->fix.line_length);
+
+	dbg("done setup\n");
+
+	return 0;
+}
+
+/**
+ *  	s1d13xxxfb_setcolreg - sets a color register.
+ *      @regno: Which register in the CLUT we are programming
+ *      @red: The red value which can be up to 16 bits wide
+ *	@green: The green value which can be up to 16 bits wide
+ *	@blue:  The blue value which can be up to 16 bits wide.
+ *	@transp: If supported the alpha value which can be up to 16 bits wide.
+ *      @info: frame buffer info structure
+ *
+ *	Returns negative errno on error, or zero on success.
+ */
+static int
+s1d13xxxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			u_int transp, struct fb_info *info)
+{
+	struct s1d13xxxfb_par *s1dfb = info->par;
+	unsigned int pseudo_val;
+
+	if (regno >= S1D_PALETTE_SIZE)
+		return -EINVAL;
+
+	dbg("s1d13xxxfb_setcolreg: %d: rgb=%d,%d,%d, tr=%d\n",
+		    regno, red, green, blue, transp);
+
+	if (info->var.grayscale)
+		red = green = blue = (19595*red + 38470*green + 7471*blue) >> 16;
+
+	switch (info->fix.visual) {
+		case FB_VISUAL_TRUECOLOR:
+			if (regno >= 16)
+				return -EINVAL;
+
+			/* deal with creating pseudo-palette entries */
+
+			pseudo_val  = (red   >> 11) << info->var.red.offset;
+			pseudo_val |= (green >> 10) << info->var.green.offset;
+			pseudo_val |= (blue  >> 11) << info->var.blue.offset;
+
+			dbg("s1d13xxxfb_setcolreg: pseudo %d, val %08x\n",
+				    regno, pseudo_val);
+
+			((u32 *)info->pseudo_palette)[regno] = pseudo_val;
+
+			break;
+		case FB_VISUAL_PSEUDOCOLOR:
+			s1d13xxxfb_writereg(s1dfb, S1DREG_LKUP_ADDR, regno);
+			s1d13xxxfb_writereg(s1dfb, S1DREG_LKUP_DATA, red);
+			s1d13xxxfb_writereg(s1dfb, S1DREG_LKUP_DATA, green);
+			s1d13xxxfb_writereg(s1dfb, S1DREG_LKUP_DATA, blue);
+
+			break;
+		default:
+			return -ENOSYS;
+	}
+
+	dbg("s1d13xxxfb_setcolreg: done\n");
+
+	return 0;
+}
+
+/**
+ *      s1d13xxxfb_blank - blanks the display.
+ *      @blank_mode: the blank mode we want.
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ *      Blank the screen if blank_mode != 0, else unblank. Return 0 if
+ *      blanking succeeded, != 0 if un-/blanking failed due to e.g. a
+ *      video mode which doesn't support it. Implements VESA suspend
+ *      and powerdown modes on hardware that supports disabling hsync/vsync:
+ *      blank_mode == 2: suspend vsync
+ *      blank_mode == 3: suspend hsync
+ *      blank_mode == 4: powerdown
+ *
+ *      Returns negative errno on error, or zero on success.
+ */
+static int
+s1d13xxxfb_blank(int blank_mode, struct fb_info *info)
+{
+	struct s1d13xxxfb_par *par = info->par;
+
+	dbg("s1d13xxxfb_blank: blank=%d, info=%p\n", blank_mode, info);
+
+	switch (blank_mode) {
+		case FB_BLANK_UNBLANK:
+		case FB_BLANK_NORMAL:
+			if ((par->display & 0x01) != 0)
+				lcd_enable(par, 1);
+			if ((par->display & 0x02) != 0)
+				crt_enable(par, 1);
+			break;
+		case FB_BLANK_VSYNC_SUSPEND:
+		case FB_BLANK_HSYNC_SUSPEND:
+			break;
+		case FB_BLANK_POWERDOWN:
+			lcd_enable(par, 0);
+			crt_enable(par, 0);
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	/* let fbcon do a soft blank for us */
+	return ((blank_mode == FB_BLANK_NORMAL) ? 1 : 0);
+}
+
+/**
+ *      s1d13xxxfb_pan_display - Pans the display.
+ *      @var: frame buffer variable screen structure
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ *	Pan (or wrap, depending on the `vmode' field) the display using the
+ *  	`yoffset' field of the `var' structure (`xoffset'  not yet supported).
+ *  	If the values don't fit, return -EINVAL.
+ *
+ *      Returns negative errno on error, or zero on success.
+ */
+static int
+s1d13xxxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct s1d13xxxfb_par *par = info->par;
+	u32 start;
+
+	if (var->xoffset != 0)	/* not yet ... */
+		return -EINVAL;
+
+	if (var->yoffset + info->var.yres > info->var.yres_virtual)
+		return -EINVAL;
+
+	start = (info->fix.line_length >> 1) * var->yoffset;
+
+	if ((par->display & 0x01)) {
+		/* LCD */
+		s1d13xxxfb_writereg(par, S1DREG_LCD_DISP_START0, (start & 0xff));
+		s1d13xxxfb_writereg(par, S1DREG_LCD_DISP_START1, ((start >> 8) & 0xff));
+		s1d13xxxfb_writereg(par, S1DREG_LCD_DISP_START2, ((start >> 16) & 0x0f));
+	} else {
+		/* CRT */
+		s1d13xxxfb_writereg(par, S1DREG_CRT_DISP_START0, (start & 0xff));
+		s1d13xxxfb_writereg(par, S1DREG_CRT_DISP_START1, ((start >> 8) & 0xff));
+		s1d13xxxfb_writereg(par, S1DREG_CRT_DISP_START2, ((start >> 16) & 0x0f));
+	}
+
+	return 0;
+}
+
+
+/* framebuffer information structures */
+
+static struct fb_ops s1d13xxxfb_fbops = {
+	.owner		= THIS_MODULE,
+	.fb_set_par	= s1d13xxxfb_set_par,
+	.fb_setcolreg	= s1d13xxxfb_setcolreg,
+	.fb_blank	= s1d13xxxfb_blank,
+
+	.fb_pan_display	= s1d13xxxfb_pan_display,
+
+	/* to be replaced by any acceleration we can */
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor
+};
+
+static int s1d13xxxfb_width_tab[2][4] __devinitdata = {
+	{4, 8, 16, -1},
+	{9, 12, 18, -1},
+};
+
+/**
+ *      s1d13xxxfb_fetch_hw_state - Configure the framebuffer according to
+ *	hardware setup.
+ *      @info: frame buffer structure
+ *
+ *	We setup the framebuffer structures according to the current
+ *	hardware setup. On some machines, the BIOS will have filled
+ *	the chip registers with such info, on others, these values will
+ *	have been written in some init procedure. In any case, the
+ *	software values needs to match the hardware ones. This is what
+ *	this function ensures.
+ *
+ *	Note: some of the hardcoded values here might need some love to
+ *	work on various chips, and might need to no longer be hardcoded.
+ */
+static void __devinit
+s1d13xxxfb_fetch_hw_state(struct fb_info *info)
+{
+	struct fb_var_screeninfo *var = &info->var;
+	struct fb_fix_screeninfo *fix = &info->fix;
+	struct s1d13xxxfb_par *par = info->par;
+	u8 panel, display;
+	u16 offset;
+	u32 xres, yres;
+	u32 xres_virtual, yres_virtual;
+	int bpp, lcd_bpp;
+	int is_color, is_dual, is_tft;
+	int lcd_enabled, crt_enabled;
+
+	fix->type = FB_TYPE_PACKED_PIXELS;
+
+	/* general info */
+	par->display = s1d13xxxfb_readreg(par, S1DREG_COM_DISP_MODE);
+	crt_enabled = (par->display & 0x02) != 0;
+	lcd_enabled = (par->display & 0x01) != 0;
+
+	if (lcd_enabled && crt_enabled)
+		printk(KERN_WARNING PFX "Warning: LCD and CRT detected, using LCD\n");
+
+	if (lcd_enabled)
+		display = s1d13xxxfb_readreg(par, S1DREG_LCD_DISP_MODE);
+	else	/* CRT */
+		display = s1d13xxxfb_readreg(par, S1DREG_CRT_DISP_MODE);
+
+	bpp = display & 0x07;
+
+	switch (bpp) {
+		case 2:	/* 4 bpp */
+		case 3:	/* 8 bpp */
+			var->bits_per_pixel = 8;
+			var->red.offset = var->green.offset = var->blue.offset = 0;
+			var->red.length = var->green.length = var->blue.length = 8;
+			break;
+		case 5:	/* 16 bpp */
+			s1d13xxxfb_setup_truecolour(info);
+			break;
+		default:
+			dbg("bpp: %i\n", bpp);
+	}
+	fb_alloc_cmap(&info->cmap, 256, 0);
+
+	/* LCD info */
+	panel = s1d13xxxfb_readreg(par, S1DREG_PANEL_TYPE);
+	is_color = (panel & 0x04) != 0;
+	is_dual = (panel & 0x02) != 0;
+	is_tft = (panel & 0x01) != 0;
+	lcd_bpp = s1d13xxxfb_width_tab[is_tft][(panel >> 4) & 3];
+
+	if (lcd_enabled) {
+		xres = (s1d13xxxfb_readreg(par, S1DREG_LCD_DISP_HWIDTH) + 1) * 8;
+		yres = (s1d13xxxfb_readreg(par, S1DREG_LCD_DISP_VHEIGHT0) +
+			((s1d13xxxfb_readreg(par, S1DREG_LCD_DISP_VHEIGHT1) & 0x03) << 8) + 1);
+
+		offset = (s1d13xxxfb_readreg(par, S1DREG_LCD_MEM_OFF0) +
+			((s1d13xxxfb_readreg(par, S1DREG_LCD_MEM_OFF1) & 0x7) << 8));
+	} else { /* crt */
+		xres = (s1d13xxxfb_readreg(par, S1DREG_CRT_DISP_HWIDTH) + 1) * 8;
+		yres = (s1d13xxxfb_readreg(par, S1DREG_CRT_DISP_VHEIGHT0) +
+			((s1d13xxxfb_readreg(par, S1DREG_CRT_DISP_VHEIGHT1) & 0x03) << 8) + 1);
+
+		offset = (s1d13xxxfb_readreg(par, S1DREG_CRT_MEM_OFF0) +
+			((s1d13xxxfb_readreg(par, S1DREG_CRT_MEM_OFF1) & 0x7) << 8));
+	}
+	xres_virtual = offset * 16 / var->bits_per_pixel;
+	yres_virtual = fix->smem_len / (offset * 2);
+
+	var->xres		= xres;
+	var->yres		= yres;
+	var->xres_virtual	= xres_virtual;
+	var->yres_virtual	= yres_virtual;
+	var->xoffset		= var->yoffset = 0;
+
+	fix->line_length	= offset * 2;
+
+	var->grayscale		= !is_color;
+
+	var->activate		= FB_ACTIVATE_NOW;
+
+	dbg(PFX "bpp=%d, lcd_bpp=%d, "
+		"crt_enabled=%d, lcd_enabled=%d\n",
+		var->bits_per_pixel, lcd_bpp, crt_enabled, lcd_enabled);
+	dbg(PFX "xres=%d, yres=%d, vxres=%d, vyres=%d "
+		"is_color=%d, is_dual=%d, is_tft=%d\n",
+		xres, yres, xres_virtual, yres_virtual, is_color, is_dual, is_tft);
+}
+
+
+static int __devexit
+s1d13xxxfb_remove(struct device *dev)
+{
+	struct fb_info *info = dev_get_drvdata(dev);
+	struct platform_device *pdev = to_platform_device(dev);
+	struct s1d13xxxfb_par *par = NULL;
+
+	if (info) {
+		par = info->par;
+		if (par && par->regs) {
+			/* disable output & enable powersave */
+			s1d13xxxfb_writereg(par, S1DREG_COM_DISP_MODE, 0x00);
+			s1d13xxxfb_writereg(par, S1DREG_PS_CNF, 0x11);
+			iounmap(par->regs);
+		}
+
+		fb_dealloc_cmap(&info->cmap);
+
+		if (info->screen_base)
+			iounmap(info->screen_base);
+
+		framebuffer_release(info);
+	}
+
+	release_mem_region(pdev->resource[0].start,
+			pdev->resource[0].end - pdev->resource[0].start +1);
+	release_mem_region(pdev->resource[1].start,
+			pdev->resource[1].end - pdev->resource[1].start +1);
+	return 0;
+}
+
+static int __devinit
+s1d13xxxfb_probe(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct s1d13xxxfb_par *default_par;
+	struct fb_info *info;
+	struct s1d13xxxfb_pdata *pdata = NULL;
+	int ret = 0;
+	u8 revision;
+
+	dbg("probe called: device is %p\n", dev);
+
+	printk(KERN_INFO "Epson S1D13XXX FB Driver\n");
+
+	/* enable platform-dependent hardware glue, if any */
+	if (dev->platform_data)
+		pdata = dev->platform_data;
+
+	if (pdata && pdata->platform_init_video)
+		pdata->platform_init_video();
+
+
+	if (pdev->num_resources != 2) {
+		dev_err(&pdev->dev, "invalid num_resources: %i\n",
+		       pdev->num_resources);
+		ret = -ENODEV;
+		goto bail;
+	}
+
+	/* resource[0] is VRAM, resource[1] is registers */
+	if (pdev->resource[0].flags != IORESOURCE_MEM
+			|| pdev->resource[1].flags != IORESOURCE_MEM) {
+		dev_err(&pdev->dev, "invalid resource type\n");
+		ret = -ENODEV;
+		goto bail;
+	}
+
+	if (!request_mem_region(pdev->resource[0].start,
+		pdev->resource[0].end - pdev->resource[0].start +1, "s1d13xxxfb mem")) {
+		dev_dbg(dev, "request_mem_region failed\n");
+		ret = -EBUSY;
+		goto bail;
+	}
+
+	if (!request_mem_region(pdev->resource[1].start,
+		pdev->resource[1].end - pdev->resource[1].start +1, "s1d13xxxfb regs")) {
+		dev_dbg(dev, "request_mem_region failed\n");
+		ret = -EBUSY;
+		goto bail;
+	}
+
+	info = framebuffer_alloc(sizeof(struct s1d13xxxfb_par) + sizeof(u32) * 256, &pdev->dev);
+	if (!info) {
+		ret = -ENOMEM;
+		goto bail;
+	}
+
+	default_par = info->par;
+	default_par->regs = ioremap_nocache(pdev->resource[1].start,
+			pdev->resource[1].end - pdev->resource[1].start +1);
+	if (!default_par->regs) {
+		printk(KERN_ERR PFX "unable to map registers\n");
+		ret = -ENOMEM;
+		goto bail;
+	}
+	info->pseudo_palette = default_par->pseudo_palette;
+
+	info->screen_base = ioremap_nocache(pdev->resource[0].start,
+			pdev->resource[0].end - pdev->resource[0].start +1);
+
+	if (!info->screen_base) {
+		printk(KERN_ERR PFX "unable to map framebuffer\n");
+		ret = -ENOMEM;
+		goto bail;
+	}
+
+	revision = s1d13xxxfb_readreg(default_par, S1DREG_REV_CODE);
+	if ((revision >> 2) != S1D_CHIP_REV) {
+		printk(KERN_INFO PFX "chip not found: %i\n", (revision >> 2));
+		ret = -ENODEV;
+		goto bail;
+	}
+
+	info->fix = s1d13xxxfb_fix;
+	info->fix.mmio_start = pdev->resource[1].start;
+	info->fix.mmio_len = pdev->resource[1].end - pdev->resource[1].start +1;
+	info->fix.smem_start = pdev->resource[0].start;
+	info->fix.smem_len = pdev->resource[0].end - pdev->resource[0].start +1;
+
+	printk(KERN_INFO PFX "regs mapped at 0x%p, fb %d KiB mapped at 0x%p\n",
+	       default_par->regs, info->fix.smem_len / 1024, info->screen_base);
+
+	info->par = default_par;
+	info->fbops = &s1d13xxxfb_fbops;
+	info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+
+	/* perform "manual" chip initialization, if needed */
+	if (pdata && pdata->initregs)
+		s1d13xxxfb_runinit(info->par, pdata->initregs, pdata->initregssize);
+
+	s1d13xxxfb_fetch_hw_state(info);
+
+	if (register_framebuffer(info) < 0) {
+		ret = -EINVAL;
+		goto bail;
+	}
+
+	dev_set_drvdata(&pdev->dev, info);
+
+	printk(KERN_INFO "fb%d: %s frame buffer device\n",
+	       info->node, info->fix.id);
+
+	return 0;
+
+bail:
+	s1d13xxxfb_remove(dev);
+	return ret;
+
+}
+
+#ifdef CONFIG_PM
+static int s1d13xxxfb_suspend(struct device *dev, u32 state, u32 level)
+{
+	struct fb_info *info = dev_get_drvdata(dev);
+	struct s1d13xxxfb_par *s1dfb = info->par;
+	struct s1d13xxxfb_pdata *pdata = NULL;
+
+	/* disable display */
+	lcd_enable(s1dfb, 0);
+	crt_enable(s1dfb, 0);
+
+	if (dev->platform_data)
+		pdata = dev->platform_data;
+
+#if 0
+	if (!s1dfb->disp_save)
+		s1dfb->disp_save = kmalloc(info->fix.smem_len, GFP_KERNEL);
+
+	if (!s1dfb->disp_save) {
+		printk(KERN_ERR PFX "no memory to save screen");
+		return -ENOMEM;
+	}
+
+	memcpy_fromio(s1dfb->disp_save, info->screen_base, info->fix.smem_len);
+#else
+	s1dfb->disp_save = NULL;
+#endif
+
+	if (!s1dfb->regs_save)
+		s1dfb->regs_save = kmalloc(info->fix.mmio_len, GFP_KERNEL);
+
+	if (!s1dfb->regs_save) {
+		printk(KERN_ERR PFX "no memory to save registers");
+		return -ENOMEM;
+	}
+
+	/* backup all registers */
+	memcpy_fromio(s1dfb->regs_save, s1dfb->regs, info->fix.mmio_len);
+
+	/* now activate power save mode */
+	s1d13xxxfb_writereg(s1dfb, S1DREG_PS_CNF, 0x11);
+
+	if (pdata && pdata->platform_suspend_video)
+		return pdata->platform_suspend_video();
+	else
+		return 0;
+}
+
+static int s1d13xxxfb_resume(struct device *dev, u32 level)
+{
+	struct fb_info *info = dev_get_drvdata(dev);
+	struct s1d13xxxfb_par *s1dfb = info->par;
+	struct s1d13xxxfb_pdata *pdata = NULL;
+
+	if (level != RESUME_ENABLE)
+		return 0;
+
+	/* awaken the chip */
+	s1d13xxxfb_writereg(s1dfb, S1DREG_PS_CNF, 0x10);
+
+	/* do not let go until SDRAM "wakes up" */
+	while ((s1d13xxxfb_readreg(s1dfb, S1DREG_PS_STATUS) & 0x01))
+		udelay(10);
+
+	if (dev->platform_data)
+		pdata = dev->platform_data;
+
+	if (s1dfb->regs_save) {
+		/* will write RO regs, *should* get away with it :) */
+		memcpy_toio(s1dfb->regs, s1dfb->regs_save, info->fix.mmio_len);
+		kfree(s1dfb->regs_save);
+	}
+
+	if (s1dfb->disp_save) {
+		memcpy_toio(info->screen_base, s1dfb->disp_save,
+				info->fix.smem_len);
+		kfree(s1dfb->disp_save);	/* XXX kmalloc()'d when? */
+	}
+
+	if ((s1dfb->display & 0x01) != 0)
+		lcd_enable(s1dfb, 1);
+	if ((s1dfb->display & 0x02) != 0)
+		crt_enable(s1dfb, 1);
+
+	if (pdata && pdata->platform_resume_video)
+		return pdata->platform_resume_video();
+	else
+		return 0;
+}
+#endif /* CONFIG_PM */
+
+static struct device_driver s1d13xxxfb_driver = {
+	.name		= S1D_DEVICENAME,
+	.bus		= &platform_bus_type,
+	.probe		= s1d13xxxfb_probe,
+	.remove		= s1d13xxxfb_remove,
+#ifdef CONFIG_PM
+	.suspend	= s1d13xxxfb_suspend,
+	.resume		= s1d13xxxfb_resume
+#endif
+};
+
+
+static int __init
+s1d13xxxfb_init(void)
+{
+	if (fb_get_options("s1d13xxxfb", NULL))
+		return -ENODEV;
+
+	return driver_register(&s1d13xxxfb_driver);
+}
+
+
+static void __exit
+s1d13xxxfb_exit(void)
+{
+	driver_unregister(&s1d13xxxfb_driver);
+}
+
+module_init(s1d13xxxfb_init);
+module_exit(s1d13xxxfb_exit);
+
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Framebuffer driver for S1D13xxx devices");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>, Thibaut VARENE <varenet@parisc-linux.org>");
diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
new file mode 100644
index 0000000..4f8043a
--- /dev/null
+++ b/drivers/video/sa1100fb.c
@@ -0,0 +1,1574 @@
+/*
+ *  linux/drivers/video/sa1100fb.c
+ *
+ *  Copyright (C) 1999 Eric A. Thomas
+ *   Based on acornfb.c Copyright (C) Russell King.
+ *
+ * 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.
+ *
+ *	        StrongARM 1100 LCD Controller Frame Buffer Driver
+ *
+ * Please direct your questions and comments on this driver to the following
+ * email address:
+ *
+ *	linux-arm-kernel@lists.arm.linux.org.uk
+ *
+ * Clean patches should be sent to the ARM Linux Patch System.  Please see the
+ * following web page for more information:
+ *
+ *	http://www.arm.linux.org.uk/developer/patches/info.shtml
+ *
+ * Thank you.
+ *
+ * Known problems:
+ *	- With the Neponset plugged into an Assabet, LCD powerdown
+ *	  doesn't work (LCD stays powered up).  Therefore we shouldn't
+ *	  blank the screen.
+ *	- We don't limit the CPU clock rate nor the mode selection
+ *	  according to the available SDRAM bandwidth.
+ *
+ * Other notes:
+ *	- Linear grayscale palettes and the kernel.
+ *	  Such code does not belong in the kernel.  The kernel frame buffer
+ *	  drivers do not expect a linear colourmap, but a colourmap based on
+ *	  the VT100 standard mapping.
+ *
+ *	  If your _userspace_ requires a linear colourmap, then the setup of
+ *	  such a colourmap belongs _in userspace_, not in the kernel.  Code
+ *	  to set the colourmap correctly from user space has been sent to
+ *	  David Neuer.  It's around 8 lines of C code, plus another 4 to
+ *	  detect if we are using grayscale.
+ *
+ *	- The following must never be specified in a panel definition:
+ *	     LCCR0_LtlEnd, LCCR3_PixClkDiv, LCCR3_VrtSnchL, LCCR3_HorSnchL
+ *
+ *	- The following should be specified:
+ *	     either LCCR0_Color or LCCR0_Mono
+ *	     either LCCR0_Sngl or LCCR0_Dual
+ *	     either LCCR0_Act or LCCR0_Pas
+ *	     either LCCR3_OutEnH or LCCD3_OutEnL
+ *	     either LCCR3_PixRsEdg or LCCR3_PixFlEdg
+ *	     either LCCR3_ACBsDiv or LCCR3_ACBsCntOff
+ *
+ * Code Status:
+ * 1999/04/01:
+ *	- Driver appears to be working for Brutus 320x200x8bpp mode.  Other
+ *	  resolutions are working, but only the 8bpp mode is supported.
+ *	  Changes need to be made to the palette encode and decode routines
+ *	  to support 4 and 16 bpp modes.  
+ *	  Driver is not designed to be a module.  The FrameBuffer is statically
+ *	  allocated since dynamic allocation of a 300k buffer cannot be 
+ *	  guaranteed. 
+ *
+ * 1999/06/17:
+ *	- FrameBuffer memory is now allocated at run-time when the
+ *	  driver is initialized.    
+ *
+ * 2000/04/10: Nicolas Pitre <nico@cam.org>
+ *	- Big cleanup for dynamic selection of machine type at run time.
+ *
+ * 2000/07/19: Jamey Hicks <jamey@crl.dec.com>
+ *	- Support for Bitsy aka Compaq iPAQ H3600 added.
+ *
+ * 2000/08/07: Tak-Shing Chan <tchan.rd@idthk.com>
+ *	       Jeff Sutherland <jsutherland@accelent.com>
+ *	- Resolved an issue caused by a change made to the Assabet's PLD 
+ *	  earlier this year which broke the framebuffer driver for newer 
+ *	  Phase 4 Assabets.  Some other parameters were changed to optimize
+ *	  for the Sharp display.
+ *
+ * 2000/08/09: Kunihiko IMAI <imai@vasara.co.jp>
+ *	- XP860 support added
+ *
+ * 2000/08/19: Mark Huang <mhuang@livetoy.com>
+ *	- Allows standard options to be passed on the kernel command line
+ *	  for most common passive displays.
+ *
+ * 2000/08/29:
+ *	- s/save_flags_cli/local_irq_save/
+ *	- remove unneeded extra save_flags_cli in sa1100fb_enable_lcd_controller
+ *
+ * 2000/10/10: Erik Mouw <J.A.K.Mouw@its.tudelft.nl>
+ *	- Updated LART stuff. Fixed some minor bugs.
+ *
+ * 2000/10/30: Murphy Chen <murphy@mail.dialogue.com.tw>
+ *	- Pangolin support added
+ *
+ * 2000/10/31: Roman Jordan <jor@hoeft-wessel.de>
+ *	- Huw Webpanel support added
+ *
+ * 2000/11/23: Eric Peng <ericpeng@coventive.com>
+ *	- Freebird add
+ *
+ * 2001/02/07: Jamey Hicks <jamey.hicks@compaq.com> 
+ *	       Cliff Brake <cbrake@accelent.com>
+ *	- Added PM callback
+ *
+ * 2001/05/26: <rmk@arm.linux.org.uk>
+ *	- Fix 16bpp so that (a) we use the right colours rather than some
+ *	  totally random colour depending on what was in page 0, and (b)
+ *	  we don't de-reference a NULL pointer.
+ *	- remove duplicated implementation of consistent_alloc()
+ *	- convert dma address types to dma_addr_t
+ *	- remove unused 'montype' stuff
+ *	- remove redundant zero inits of init_var after the initial
+ *	  memzero.
+ *	- remove allow_modeset (acornfb idea does not belong here)
+ *
+ * 2001/05/28: <rmk@arm.linux.org.uk>
+ *	- massive cleanup - move machine dependent data into structures
+ *	- I've left various #warnings in - if you see one, and know
+ *	  the hardware concerned, please get in contact with me.
+ *
+ * 2001/05/31: <rmk@arm.linux.org.uk>
+ *	- Fix LCCR1 HSW value, fix all machine type specifications to
+ *	  keep values in line.  (Please check your machine type specs)
+ *
+ * 2001/06/10: <rmk@arm.linux.org.uk>
+ *	- Fiddle with the LCD controller from task context only; mainly
+ *	  so that we can run with interrupts on, and sleep.
+ *	- Convert #warnings into #errors.  No pain, no gain. ;)
+ *
+ * 2001/06/14: <rmk@arm.linux.org.uk>
+ *	- Make the palette BPS value for 12bpp come out correctly.
+ *	- Take notice of "greyscale" on any colour depth.
+ *	- Make truecolor visuals use the RGB channel encoding information.
+ *
+ * 2001/07/02: <rmk@arm.linux.org.uk>
+ *	- Fix colourmap problems.
+ *
+ * 2001/07/13: <abraham@2d3d.co.za>
+ *	- Added support for the ICP LCD-Kit01 on LART. This LCD is
+ *	  manufactured by Prime View, model no V16C6448AB
+ *
+ * 2001/07/23: <rmk@arm.linux.org.uk>
+ *	- Hand merge version from handhelds.org CVS tree.  See patch
+ *	  notes for 595/1 for more information.
+ *	- Drop 12bpp (it's 16bpp with different colour register mappings).
+ *	- This hardware can not do direct colour.  Therefore we don't
+ *	  support it.
+ *
+ * 2001/07/27: <rmk@arm.linux.org.uk>
+ *	- Halve YRES on dual scan LCDs.
+ *
+ * 2001/08/22: <rmk@arm.linux.org.uk>
+ *	- Add b/w iPAQ pixclock value.
+ *
+ * 2001/10/12: <rmk@arm.linux.org.uk>
+ *	- Add patch 681/1 and clean up stork definitions.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/cpufreq.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+#include <asm/uaccess.h>
+#include <asm/arch/assabet.h>
+#include <asm/arch/shannon.h>
+
+/*
+ * debugging?
+ */
+#define DEBUG 0
+/*
+ * Complain if VAR is out of range.
+ */
+#define DEBUG_VAR 1
+
+#undef ASSABET_PAL_VIDEO
+
+#include "sa1100fb.h"
+
+extern void (*sa1100fb_backlight_power)(int on);
+extern void (*sa1100fb_lcd_power)(int on);
+
+/*
+ * IMHO this looks wrong.  In 8BPP, length should be 8.
+ */
+static struct sa1100fb_rgb rgb_8 = {
+	.red	= { .offset = 0,  .length = 4, },
+	.green	= { .offset = 0,  .length = 4, },
+	.blue	= { .offset = 0,  .length = 4, },
+	.transp	= { .offset = 0,  .length = 0, },
+};
+
+static struct sa1100fb_rgb def_rgb_16 = {
+	.red	= { .offset = 11, .length = 5, },
+	.green	= { .offset = 5,  .length = 6, },
+	.blue	= { .offset = 0,  .length = 5, },
+	.transp	= { .offset = 0,  .length = 0, },
+};
+
+#ifdef CONFIG_SA1100_ASSABET
+#ifndef ASSABET_PAL_VIDEO
+/*
+ * The assabet uses a sharp LQ039Q2DS54 LCD module.  It is actually
+ * takes an RGB666 signal, but we provide it with an RGB565 signal
+ * instead (def_rgb_16).
+ */
+static struct sa1100fb_mach_info lq039q2ds54_info __initdata = {
+	.pixclock	= 171521,	.bpp		= 16,
+	.xres		= 320,		.yres		= 240,
+
+	.hsync_len	= 5,		.vsync_len	= 1,
+	.left_margin	= 61,		.upper_margin	= 3,
+	.right_margin	= 9,		.lower_margin	= 0,
+
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+};
+#else
+static struct sa1100fb_mach_info pal_info __initdata = {
+	.pixclock	= 67797,	.bpp		= 16,
+	.xres		= 640,		.yres		= 512,
+
+	.hsync_len	= 64,		.vsync_len	= 6,
+	.left_margin	= 125,		.upper_margin	= 70,
+	.right_margin	= 115,		.lower_margin	= 36,
+
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
+};
+#endif
+#endif
+
+#ifdef CONFIG_SA1100_H3800
+static struct sa1100fb_mach_info h3800_info __initdata = {
+	.pixclock	= 174757, 	.bpp		= 16,
+	.xres		= 320,		.yres		= 240,
+
+	.hsync_len	= 3,		.vsync_len	= 3,
+	.left_margin	= 12,		.upper_margin	= 10,
+	.right_margin	= 17,		.lower_margin	= 1,
+
+	.cmap_static	= 1,
+
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+};
+#endif
+
+#ifdef CONFIG_SA1100_H3600
+static struct sa1100fb_mach_info h3600_info __initdata = {
+	.pixclock	= 174757, 	.bpp		= 16,
+	.xres		= 320,		.yres		= 240,
+
+	.hsync_len	= 3,		.vsync_len	= 3,
+	.left_margin	= 12,		.upper_margin	= 10,
+	.right_margin	= 17,		.lower_margin	= 1,
+
+	.cmap_static	= 1,
+
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+};
+
+static struct sa1100fb_rgb h3600_rgb_16 = {
+	.red	= { .offset = 12, .length = 4, },
+	.green	= { .offset = 7,  .length = 4, },
+	.blue	= { .offset = 1,  .length = 4, },
+	.transp	= { .offset = 0,  .length = 0, },
+};
+#endif
+
+#ifdef CONFIG_SA1100_H3100
+static struct sa1100fb_mach_info h3100_info __initdata = {
+	.pixclock	= 406977, 	.bpp		= 4,
+	.xres		= 320,		.yres		= 240,
+
+	.hsync_len	= 26,		.vsync_len	= 41,
+	.left_margin	= 4,		.upper_margin	= 0,
+	.right_margin	= 4,		.lower_margin	= 0,
+
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	.cmap_greyscale	= 1,
+	.cmap_inverse	= 1,
+
+	.lccr0		= LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+};
+#endif
+
+#ifdef CONFIG_SA1100_COLLIE
+static struct sa1100fb_mach_info collie_info __initdata = {
+	.pixclock	= 171521,	.bpp		= 16,
+	.xres		= 320,		.yres		= 240,
+
+	.hsync_len	= 5,		.vsync_len	= 1,
+	.left_margin	= 11,		.upper_margin	= 2,
+	.right_margin	= 30,		.lower_margin	= 0,
+
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+};
+#endif
+
+#ifdef LART_GREY_LCD
+static struct sa1100fb_mach_info lart_grey_info __initdata = {
+	.pixclock	= 150000,	.bpp		= 4,
+	.xres		= 320,		.yres		= 240,
+
+	.hsync_len	= 1,		.vsync_len	= 1,
+	.left_margin	= 4,		.upper_margin	= 0,
+	.right_margin	= 2,		.lower_margin	= 0,
+
+	.cmap_greyscale	= 1,
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+	.lccr0		= LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_4PixMono,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
+};
+#endif
+#ifdef LART_COLOR_LCD
+static struct sa1100fb_mach_info lart_color_info __initdata = {
+	.pixclock	= 150000,	.bpp		= 16,
+	.xres		= 320,		.yres		= 240,
+
+	.hsync_len	= 2,		.vsync_len	= 3,
+	.left_margin	= 69,		.upper_margin	= 14,
+	.right_margin	= 8,		.lower_margin	= 4,
+
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
+};
+#endif
+#ifdef LART_VIDEO_OUT
+static struct sa1100fb_mach_info lart_video_info __initdata = {
+	.pixclock	= 39721,	.bpp		= 16,
+	.xres		= 640,		.yres		= 480,
+
+	.hsync_len	= 95,		.vsync_len	= 2,
+	.left_margin	= 40,		.upper_margin	= 32,
+	.right_margin	= 24,		.lower_margin	= 11,
+
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnL | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
+};
+#endif
+
+#ifdef LART_KIT01_LCD
+static struct sa1100fb_mach_info lart_kit01_info __initdata = {
+	.pixclock	= 63291,	.bpp		= 16,
+	.xres		= 640,		.yres		= 480,
+
+	.hsync_len	= 64,		.vsync_len	= 3,
+	.left_margin	= 122,		.upper_margin	= 45,
+	.right_margin	= 10,		.lower_margin	= 10,
+
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixFlEdg
+};
+#endif
+
+#ifdef CONFIG_SA1100_SHANNON
+static struct sa1100fb_mach_info shannon_info __initdata = {
+	.pixclock	= 152500,	.bpp		= 8,
+	.xres		= 640,		.yres		= 480,
+
+	.hsync_len	= 4,		.vsync_len	= 3,
+	.left_margin	= 2,		.upper_margin	= 0,
+	.right_margin	= 1,		.lower_margin	= 0,
+
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+	.lccr0		= LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
+	.lccr3		= LCCR3_ACBsDiv(512),
+};
+#endif
+
+
+
+static struct sa1100fb_mach_info * __init
+sa1100fb_get_machine_info(struct sa1100fb_info *fbi)
+{
+	struct sa1100fb_mach_info *inf = NULL;
+
+	/*
+	 *            R        G       B       T
+	 * default  {11,5}, { 5,6}, { 0,5}, { 0,0}
+	 * h3600    {12,4}, { 7,4}, { 1,4}, { 0,0}
+	 * freebird { 8,4}, { 4,4}, { 0,4}, {12,4}
+	 */
+#ifdef CONFIG_SA1100_ASSABET
+	if (machine_is_assabet()) {
+#ifndef ASSABET_PAL_VIDEO
+		inf = &lq039q2ds54_info;
+#else
+		inf = &pal_info;
+#endif
+	}
+#endif
+#ifdef CONFIG_SA1100_H3100
+	if (machine_is_h3100()) {
+		inf = &h3100_info;
+	}
+#endif
+#ifdef CONFIG_SA1100_H3600
+	if (machine_is_h3600()) {
+		inf = &h3600_info;
+		fbi->rgb[RGB_16] = &h3600_rgb_16;
+	}
+#endif
+#ifdef CONFIG_SA1100_H3800
+	if (machine_is_h3800()) {
+		inf = &h3800_info;
+	}
+#endif
+#ifdef CONFIG_SA1100_COLLIE
+	if (machine_is_collie()) {
+		inf = &collie_info;
+	}
+#endif
+#ifdef CONFIG_SA1100_LART
+	if (machine_is_lart()) {
+#ifdef LART_GREY_LCD
+		inf = &lart_grey_info;
+#endif
+#ifdef LART_COLOR_LCD
+		inf = &lart_color_info;
+#endif
+#ifdef LART_VIDEO_OUT
+		inf = &lart_video_info;
+#endif
+#ifdef LART_KIT01_LCD
+		inf = &lart_kit01_info;
+#endif
+	}
+#endif
+#ifdef CONFIG_SA1100_SHANNON
+	if (machine_is_shannon()) {
+		inf = &shannon_info;
+	}
+#endif
+	return inf;
+}
+
+static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *);
+static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state);
+
+static inline void sa1100fb_schedule_work(struct sa1100fb_info *fbi, u_int state)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	/*
+	 * We need to handle two requests being made at the same time.
+	 * There are two important cases:
+	 *  1. When we are changing VT (C_REENABLE) while unblanking (C_ENABLE)
+	 *     We must perform the unblanking, which will do our REENABLE for us.
+	 *  2. When we are blanking, but immediately unblank before we have
+	 *     blanked.  We do the "REENABLE" thing here as well, just to be sure.
+	 */
+	if (fbi->task_state == C_ENABLE && state == C_REENABLE)
+		state = (u_int) -1;
+	if (fbi->task_state == C_DISABLE && state == C_ENABLE)
+		state = C_REENABLE;
+
+	if (state != (u_int)-1) {
+		fbi->task_state = state;
+		schedule_work(&fbi->task);
+	}
+	local_irq_restore(flags);
+}
+
+static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
+{
+	chan &= 0xffff;
+	chan >>= 16 - bf->length;
+	return chan << bf->offset;
+}
+
+/*
+ * Convert bits-per-pixel to a hardware palette PBS value.
+ */
+static inline u_int palette_pbs(struct fb_var_screeninfo *var)
+{
+	int ret = 0;
+	switch (var->bits_per_pixel) {
+	case 4:  ret = 0 << 12;	break;
+	case 8:  ret = 1 << 12; break;
+	case 16: ret = 2 << 12; break;
+	}
+	return ret;
+}
+
+static int
+sa1100fb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
+		       u_int trans, struct fb_info *info)
+{
+	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+	u_int val, ret = 1;
+
+	if (regno < fbi->palette_size) {
+		val = ((red >> 4) & 0xf00);
+		val |= ((green >> 8) & 0x0f0);
+		val |= ((blue >> 12) & 0x00f);
+
+		if (regno == 0)
+			val |= palette_pbs(&fbi->fb.var);
+
+		fbi->palette_cpu[regno] = val;
+		ret = 0;
+	}
+	return ret;
+}
+
+static int
+sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+		   u_int trans, struct fb_info *info)
+{
+	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+	unsigned int val;
+	int ret = 1;
+
+	/*
+	 * If inverse mode was selected, invert all the colours
+	 * rather than the register number.  The register number
+	 * is what you poke into the framebuffer to produce the
+	 * colour you requested.
+	 */
+	if (fbi->cmap_inverse) {
+		red   = 0xffff - red;
+		green = 0xffff - green;
+		blue  = 0xffff - blue;
+	}
+
+	/*
+	 * If greyscale is true, then we convert the RGB value
+	 * to greyscale no mater what visual we are using.
+	 */
+	if (fbi->fb.var.grayscale)
+		red = green = blue = (19595 * red + 38470 * green +
+					7471 * blue) >> 16;
+
+	switch (fbi->fb.fix.visual) {
+	case FB_VISUAL_TRUECOLOR:
+		/*
+		 * 12 or 16-bit True Colour.  We encode the RGB value
+		 * according to the RGB bitfield information.
+		 */
+		if (regno < 16) {
+			u32 *pal = fbi->fb.pseudo_palette;
+
+			val  = chan_to_field(red, &fbi->fb.var.red);
+			val |= chan_to_field(green, &fbi->fb.var.green);
+			val |= chan_to_field(blue, &fbi->fb.var.blue);
+
+			pal[regno] = val;
+			ret = 0;
+		}
+		break;
+
+	case FB_VISUAL_STATIC_PSEUDOCOLOR:
+	case FB_VISUAL_PSEUDOCOLOR:
+		ret = sa1100fb_setpalettereg(regno, red, green, blue, trans, info);
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ *  sa1100fb_display_dma_period()
+ *    Calculate the minimum period (in picoseconds) between two DMA
+ *    requests for the LCD controller.  If we hit this, it means we're
+ *    doing nothing but LCD DMA.
+ */
+static unsigned int sa1100fb_display_dma_period(struct fb_var_screeninfo *var)
+{
+	/*
+	 * Period = pixclock * bits_per_byte * bytes_per_transfer
+	 *		/ memory_bits_per_pixel;
+	 */
+	return var->pixclock * 8 * 16 / var->bits_per_pixel;
+}
+
+/*
+ *  sa1100fb_check_var():
+ *    Round up in the following order: bits_per_pixel, xres,
+ *    yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
+ *    bitfields, horizontal timing, vertical timing.
+ */
+static int
+sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+	int rgbidx;
+
+	if (var->xres < MIN_XRES)
+		var->xres = MIN_XRES;
+	if (var->yres < MIN_YRES)
+		var->yres = MIN_YRES;
+	if (var->xres > fbi->max_xres)
+		var->xres = fbi->max_xres;
+	if (var->yres > fbi->max_yres)
+		var->yres = fbi->max_yres;
+	var->xres_virtual = max(var->xres_virtual, var->xres);
+	var->yres_virtual = max(var->yres_virtual, var->yres);
+
+	DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel);
+	switch (var->bits_per_pixel) {
+	case 4:
+		rgbidx = RGB_8;
+		break;
+	case 8:
+		rgbidx = RGB_8;
+		break;
+	case 16:
+		rgbidx = RGB_16;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/*
+	 * Copy the RGB parameters for this display
+	 * from the machine specific parameters.
+	 */
+	var->red    = fbi->rgb[rgbidx]->red;
+	var->green  = fbi->rgb[rgbidx]->green;
+	var->blue   = fbi->rgb[rgbidx]->blue;
+	var->transp = fbi->rgb[rgbidx]->transp;
+
+	DPRINTK("RGBT length = %d:%d:%d:%d\n",
+		var->red.length, var->green.length, var->blue.length,
+		var->transp.length);
+
+	DPRINTK("RGBT offset = %d:%d:%d:%d\n",
+		var->red.offset, var->green.offset, var->blue.offset,
+		var->transp.offset);
+
+#ifdef CONFIG_CPU_FREQ
+	printk(KERN_DEBUG "dma period = %d ps, clock = %d kHz\n",
+		sa1100fb_display_dma_period(var),
+		cpufreq_get(smp_processor_id()));
+#endif
+
+	return 0;
+}
+
+static inline void sa1100fb_set_truecolor(u_int is_true_color)
+{
+	if (machine_is_assabet()) {
+#if 1		// phase 4 or newer Assabet's
+		if (is_true_color)
+			ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
+		else
+			ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
+#else
+		// older Assabet's
+		if (is_true_color)
+			ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
+		else
+			ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
+#endif
+	}
+}
+
+/*
+ * sa1100fb_set_par():
+ *	Set the user defined part of the display for the specified console
+ */
+static int sa1100fb_set_par(struct fb_info *info)
+{
+	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+	struct fb_var_screeninfo *var = &info->var;
+	unsigned long palette_mem_size;
+
+	DPRINTK("set_par\n");
+
+	if (var->bits_per_pixel == 16)
+		fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+	else if (!fbi->cmap_static)
+		fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
+	else {
+		/*
+		 * Some people have weird ideas about wanting static
+		 * pseudocolor maps.  I suspect their user space
+		 * applications are broken.
+		 */
+		fbi->fb.fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
+	}
+
+	fbi->fb.fix.line_length = var->xres_virtual *
+				  var->bits_per_pixel / 8;
+	fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16;
+
+	palette_mem_size = fbi->palette_size * sizeof(u16);
+
+	DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size);
+
+	fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
+	fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
+
+	/*
+	 * Set (any) board control register to handle new color depth
+	 */
+	sa1100fb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR);
+	sa1100fb_activate_var(var, fbi);
+
+	return 0;
+}
+
+#if 0
+static int
+sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+		  struct fb_info *info)
+{
+	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+
+	/*
+	 * Make sure the user isn't doing something stupid.
+	 */
+	if (!kspc && (fbi->fb.var.bits_per_pixel == 16 || fbi->cmap_static))
+		return -EINVAL;
+
+	return gen_set_cmap(cmap, kspc, con, info);
+}
+#endif
+
+/*
+ * Formal definition of the VESA spec:
+ *  On
+ *  	This refers to the state of the display when it is in full operation
+ *  Stand-By
+ *  	This defines an optional operating state of minimal power reduction with
+ *  	the shortest recovery time
+ *  Suspend
+ *  	This refers to a level of power management in which substantial power
+ *  	reduction is achieved by the display.  The display can have a longer 
+ *  	recovery time from this state than from the Stand-by state
+ *  Off
+ *  	This indicates that the display is consuming the lowest level of power
+ *  	and is non-operational. Recovery from this state may optionally require
+ *  	the user to manually power on the monitor
+ *
+ *  Now, the fbdev driver adds an additional state, (blank), where they
+ *  turn off the video (maybe by colormap tricks), but don't mess with the
+ *  video itself: think of it semantically between on and Stand-By.
+ *
+ *  So here's what we should do in our fbdev blank routine:
+ *
+ *  	VESA_NO_BLANKING (mode 0)	Video on,  front/back light on
+ *  	VESA_VSYNC_SUSPEND (mode 1)  	Video on,  front/back light off
+ *  	VESA_HSYNC_SUSPEND (mode 2)  	Video on,  front/back light off
+ *  	VESA_POWERDOWN (mode 3)		Video off, front/back light off
+ *
+ *  This will match the matrox implementation.
+ */
+/*
+ * sa1100fb_blank():
+ *	Blank the display by setting all palette values to zero.  Note, the 
+ * 	12 and 16 bpp modes don't really use the palette, so this will not
+ *      blank the display in all modes.  
+ */
+static int sa1100fb_blank(int blank, struct fb_info *info)
+{
+	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+	int i;
+
+	DPRINTK("sa1100fb_blank: blank=%d\n", blank);
+
+	switch (blank) {
+	case FB_BLANK_POWERDOWN:
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_NORMAL:
+		if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
+		    fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
+			for (i = 0; i < fbi->palette_size; i++)
+				sa1100fb_setpalettereg(i, 0, 0, 0, 0, info);
+		sa1100fb_schedule_work(fbi, C_DISABLE);
+		break;
+
+	case FB_BLANK_UNBLANK:
+		if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
+		    fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
+			fb_set_cmap(&fbi->fb.cmap, info);
+		sa1100fb_schedule_work(fbi, C_ENABLE);
+	}
+	return 0;
+}
+
+static int sa1100fb_mmap(struct fb_info *info, struct file *file,
+			 struct vm_area_struct *vma)
+{
+	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+	unsigned long start, len, off = vma->vm_pgoff << PAGE_SHIFT;
+
+	if (off < info->fix.smem_len) {
+		vma->vm_pgoff += 1; /* skip over the palette */
+		return dma_mmap_writecombine(fbi->dev, vma, fbi->map_cpu,
+					     fbi->map_dma, fbi->map_size);
+	}
+
+	start = info->fix.mmio_start;
+	len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
+
+	if ((vma->vm_end - vma->vm_start + off) > len)
+		return -EINVAL;
+
+	off += start & PAGE_MASK;
+	vma->vm_pgoff = off >> PAGE_SHIFT;
+	vma->vm_flags |= VM_IO;
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	return io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+				   vma->vm_end - vma->vm_start,
+				   vma->vm_page_prot);
+}
+
+static struct fb_ops sa1100fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= sa1100fb_check_var,
+	.fb_set_par	= sa1100fb_set_par,
+//	.fb_set_cmap	= sa1100fb_set_cmap,
+	.fb_setcolreg	= sa1100fb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_blank	= sa1100fb_blank,
+	.fb_cursor	= soft_cursor,
+	.fb_mmap	= sa1100fb_mmap,
+};
+
+/*
+ * Calculate the PCD value from the clock rate (in picoseconds).
+ * We take account of the PPCR clock setting.
+ */
+static inline unsigned int get_pcd(unsigned int pixclock, unsigned int cpuclock)
+{
+	unsigned int pcd = cpuclock / 100;
+
+	pcd *= pixclock;
+	pcd /= 10000000;
+
+	return pcd + 1;	/* make up for integer math truncations */
+}
+
+/*
+ * sa1100fb_activate_var():
+ *	Configures LCD Controller based on entries in var parameter.  Settings are      
+ *	only written to the controller if changes were made.  
+ */
+static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi)
+{
+	struct sa1100fb_lcd_reg new_regs;
+	u_int half_screen_size, yres, pcd;
+	u_long flags;
+
+	DPRINTK("Configuring SA1100 LCD\n");
+
+	DPRINTK("var: xres=%d hslen=%d lm=%d rm=%d\n",
+		var->xres, var->hsync_len,
+		var->left_margin, var->right_margin);
+	DPRINTK("var: yres=%d vslen=%d um=%d bm=%d\n",
+		var->yres, var->vsync_len,
+		var->upper_margin, var->lower_margin);
+
+#if DEBUG_VAR
+	if (var->xres < 16        || var->xres > 1024)
+		printk(KERN_ERR "%s: invalid xres %d\n",
+			fbi->fb.fix.id, var->xres);
+	if (var->hsync_len < 1    || var->hsync_len > 64)
+		printk(KERN_ERR "%s: invalid hsync_len %d\n",
+			fbi->fb.fix.id, var->hsync_len);
+	if (var->left_margin < 1  || var->left_margin > 255)
+		printk(KERN_ERR "%s: invalid left_margin %d\n",
+			fbi->fb.fix.id, var->left_margin);
+	if (var->right_margin < 1 || var->right_margin > 255)
+		printk(KERN_ERR "%s: invalid right_margin %d\n",
+			fbi->fb.fix.id, var->right_margin);
+	if (var->yres < 1         || var->yres > 1024)
+		printk(KERN_ERR "%s: invalid yres %d\n",
+			fbi->fb.fix.id, var->yres);
+	if (var->vsync_len < 1    || var->vsync_len > 64)
+		printk(KERN_ERR "%s: invalid vsync_len %d\n",
+			fbi->fb.fix.id, var->vsync_len);
+	if (var->upper_margin < 0 || var->upper_margin > 255)
+		printk(KERN_ERR "%s: invalid upper_margin %d\n",
+			fbi->fb.fix.id, var->upper_margin);
+	if (var->lower_margin < 0 || var->lower_margin > 255)
+		printk(KERN_ERR "%s: invalid lower_margin %d\n",
+			fbi->fb.fix.id, var->lower_margin);
+#endif
+
+	new_regs.lccr0 = fbi->lccr0 |
+		LCCR0_LEN | LCCR0_LDM | LCCR0_BAM |
+		LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0);
+
+	new_regs.lccr1 =
+		LCCR1_DisWdth(var->xres) +
+		LCCR1_HorSnchWdth(var->hsync_len) +
+		LCCR1_BegLnDel(var->left_margin) +
+		LCCR1_EndLnDel(var->right_margin);
+
+	/*
+	 * If we have a dual scan LCD, then we need to halve
+	 * the YRES parameter.
+	 */
+	yres = var->yres;
+	if (fbi->lccr0 & LCCR0_Dual)
+		yres /= 2;
+
+	new_regs.lccr2 =
+		LCCR2_DisHght(yres) +
+		LCCR2_VrtSnchWdth(var->vsync_len) +
+		LCCR2_BegFrmDel(var->upper_margin) +
+		LCCR2_EndFrmDel(var->lower_margin);
+
+	pcd = get_pcd(var->pixclock, cpufreq_get(0));
+	new_regs.lccr3 = LCCR3_PixClkDiv(pcd) | fbi->lccr3 |
+		(var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
+		(var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
+
+	DPRINTK("nlccr0 = 0x%08lx\n", new_regs.lccr0);
+	DPRINTK("nlccr1 = 0x%08lx\n", new_regs.lccr1);
+	DPRINTK("nlccr2 = 0x%08lx\n", new_regs.lccr2);
+	DPRINTK("nlccr3 = 0x%08lx\n", new_regs.lccr3);
+
+	half_screen_size = var->bits_per_pixel;
+	half_screen_size = half_screen_size * var->xres * var->yres / 16;
+
+	/* Update shadow copy atomically */
+	local_irq_save(flags);
+	fbi->dbar1 = fbi->palette_dma;
+	fbi->dbar2 = fbi->screen_dma + half_screen_size;
+
+	fbi->reg_lccr0 = new_regs.lccr0;
+	fbi->reg_lccr1 = new_regs.lccr1;
+	fbi->reg_lccr2 = new_regs.lccr2;
+	fbi->reg_lccr3 = new_regs.lccr3;
+	local_irq_restore(flags);
+
+	/*
+	 * Only update the registers if the controller is enabled
+	 * and something has changed.
+	 */
+	if ((LCCR0 != fbi->reg_lccr0)       || (LCCR1 != fbi->reg_lccr1) ||
+	    (LCCR2 != fbi->reg_lccr2)       || (LCCR3 != fbi->reg_lccr3) ||
+	    (DBAR1 != fbi->dbar1) || (DBAR2 != fbi->dbar2))
+		sa1100fb_schedule_work(fbi, C_REENABLE);
+
+	return 0;
+}
+
+/*
+ * NOTE!  The following functions are purely helpers for set_ctrlr_state.
+ * Do not call them directly; set_ctrlr_state does the correct serialisation
+ * to ensure that things happen in the right way 100% of time time.
+ *	-- rmk
+ */
+static inline void __sa1100fb_backlight_power(struct sa1100fb_info *fbi, int on)
+{
+	DPRINTK("backlight o%s\n", on ? "n" : "ff");
+
+	if (sa1100fb_backlight_power)
+		sa1100fb_backlight_power(on);
+}
+
+static inline void __sa1100fb_lcd_power(struct sa1100fb_info *fbi, int on)
+{
+	DPRINTK("LCD power o%s\n", on ? "n" : "ff");
+
+	if (sa1100fb_lcd_power)
+		sa1100fb_lcd_power(on);
+}
+
+static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi)
+{
+	u_int mask = 0;
+
+	/*
+	 * Enable GPIO<9:2> for LCD use if:
+	 *  1. Active display, or
+	 *  2. Color Dual Passive display
+	 *
+	 * see table 11.8 on page 11-27 in the SA1100 manual
+	 *   -- Erik.
+	 *
+	 * SA1110 spec update nr. 25 says we can and should
+	 * clear LDD15 to 12 for 4 or 8bpp modes with active
+	 * panels.  
+	 */
+	if ((fbi->reg_lccr0 & LCCR0_CMS) == LCCR0_Color &&
+	    (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) != 0) {
+		mask = GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9  | GPIO_LDD8;
+
+		if (fbi->fb.var.bits_per_pixel > 8 ||
+		    (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) == LCCR0_Dual)
+			mask |= GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12;
+
+	}
+
+	if (mask) {
+		GPDR |= mask;
+		GAFR |= mask;
+	}
+}
+
+static void sa1100fb_enable_controller(struct sa1100fb_info *fbi)
+{
+	DPRINTK("Enabling LCD controller\n");
+
+	/*
+	 * Make sure the mode bits are present in the first palette entry
+	 */
+	fbi->palette_cpu[0] &= 0xcfff;
+	fbi->palette_cpu[0] |= palette_pbs(&fbi->fb.var);
+
+	/* Sequence from 11.7.10 */
+	LCCR3 = fbi->reg_lccr3;
+	LCCR2 = fbi->reg_lccr2;
+	LCCR1 = fbi->reg_lccr1;
+	LCCR0 = fbi->reg_lccr0 & ~LCCR0_LEN;
+	DBAR1 = fbi->dbar1;
+	DBAR2 = fbi->dbar2;
+	LCCR0 |= LCCR0_LEN;
+
+	if (machine_is_shannon()) {
+		GPDR |= SHANNON_GPIO_DISP_EN;
+		GPSR |= SHANNON_GPIO_DISP_EN;
+	}
+
+	DPRINTK("DBAR1 = 0x%08x\n", DBAR1);
+	DPRINTK("DBAR2 = 0x%08x\n", DBAR2);
+	DPRINTK("LCCR0 = 0x%08x\n", LCCR0);
+	DPRINTK("LCCR1 = 0x%08x\n", LCCR1);
+	DPRINTK("LCCR2 = 0x%08x\n", LCCR2);
+	DPRINTK("LCCR3 = 0x%08x\n", LCCR3);
+}
+
+static void sa1100fb_disable_controller(struct sa1100fb_info *fbi)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	DPRINTK("Disabling LCD controller\n");
+
+	if (machine_is_shannon()) {
+		GPCR |= SHANNON_GPIO_DISP_EN;
+	}	
+
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	add_wait_queue(&fbi->ctrlr_wait, &wait);
+
+	LCSR = 0xffffffff;	/* Clear LCD Status Register */
+	LCCR0 &= ~LCCR0_LDM;	/* Enable LCD Disable Done Interrupt */
+	LCCR0 &= ~LCCR0_LEN;	/* Disable LCD Controller */
+
+	schedule_timeout(20 * HZ / 1000);
+	remove_wait_queue(&fbi->ctrlr_wait, &wait);
+}
+
+/*
+ *  sa1100fb_handle_irq: Handle 'LCD DONE' interrupts.
+ */
+static irqreturn_t sa1100fb_handle_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct sa1100fb_info *fbi = dev_id;
+	unsigned int lcsr = LCSR;
+
+	if (lcsr & LCSR_LDD) {
+		LCCR0 |= LCCR0_LDM;
+		wake_up(&fbi->ctrlr_wait);
+	}
+
+	LCSR = lcsr;
+	return IRQ_HANDLED;
+}
+
+/*
+ * This function must be called from task context only, since it will
+ * sleep when disabling the LCD controller, or if we get two contending
+ * processes trying to alter state.
+ */
+static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state)
+{
+	u_int old_state;
+
+	down(&fbi->ctrlr_sem);
+
+	old_state = fbi->state;
+
+	/*
+	 * Hack around fbcon initialisation.
+	 */
+	if (old_state == C_STARTUP && state == C_REENABLE)
+		state = C_ENABLE;
+
+	switch (state) {
+	case C_DISABLE_CLKCHANGE:
+		/*
+		 * Disable controller for clock change.  If the
+		 * controller is already disabled, then do nothing.
+		 */
+		if (old_state != C_DISABLE && old_state != C_DISABLE_PM) {
+			fbi->state = state;
+			sa1100fb_disable_controller(fbi);
+		}
+		break;
+
+	case C_DISABLE_PM:
+	case C_DISABLE:
+		/*
+		 * Disable controller
+		 */
+		if (old_state != C_DISABLE) {
+			fbi->state = state;
+
+			__sa1100fb_backlight_power(fbi, 0);
+			if (old_state != C_DISABLE_CLKCHANGE)
+				sa1100fb_disable_controller(fbi);
+			__sa1100fb_lcd_power(fbi, 0);
+		}
+		break;
+
+	case C_ENABLE_CLKCHANGE:
+		/*
+		 * Enable the controller after clock change.  Only
+		 * do this if we were disabled for the clock change.
+		 */
+		if (old_state == C_DISABLE_CLKCHANGE) {
+			fbi->state = C_ENABLE;
+			sa1100fb_enable_controller(fbi);
+		}
+		break;
+
+	case C_REENABLE:
+		/*
+		 * Re-enable the controller only if it was already
+		 * enabled.  This is so we reprogram the control
+		 * registers.
+		 */
+		if (old_state == C_ENABLE) {
+			sa1100fb_disable_controller(fbi);
+			sa1100fb_setup_gpio(fbi);
+			sa1100fb_enable_controller(fbi);
+		}
+		break;
+
+	case C_ENABLE_PM:
+		/*
+		 * Re-enable the controller after PM.  This is not
+		 * perfect - think about the case where we were doing
+		 * a clock change, and we suspended half-way through.
+		 */
+		if (old_state != C_DISABLE_PM)
+			break;
+		/* fall through */
+
+	case C_ENABLE:
+		/*
+		 * Power up the LCD screen, enable controller, and
+		 * turn on the backlight.
+		 */
+		if (old_state != C_ENABLE) {
+			fbi->state = C_ENABLE;
+			sa1100fb_setup_gpio(fbi);
+			__sa1100fb_lcd_power(fbi, 1);
+			sa1100fb_enable_controller(fbi);
+			__sa1100fb_backlight_power(fbi, 1);
+		}
+		break;
+	}
+	up(&fbi->ctrlr_sem);
+}
+
+/*
+ * Our LCD controller task (which is called when we blank or unblank)
+ * via keventd.
+ */
+static void sa1100fb_task(void *dummy)
+{
+	struct sa1100fb_info *fbi = dummy;
+	u_int state = xchg(&fbi->task_state, -1);
+
+	set_ctrlr_state(fbi, state);
+}
+
+#ifdef CONFIG_CPU_FREQ
+/*
+ * Calculate the minimum DMA period over all displays that we own.
+ * This, together with the SDRAM bandwidth defines the slowest CPU
+ * frequency that can be selected.
+ */
+static unsigned int sa1100fb_min_dma_period(struct sa1100fb_info *fbi)
+{
+#if 0
+	unsigned int min_period = (unsigned int)-1;
+	int i;
+
+	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+		struct display *disp = &fb_display[i];
+		unsigned int period;
+
+		/*
+		 * Do we own this display?
+		 */
+		if (disp->fb_info != &fbi->fb)
+			continue;
+
+		/*
+		 * Ok, calculate its DMA period
+		 */
+		period = sa1100fb_display_dma_period(&disp->var);
+		if (period < min_period)
+			min_period = period;
+	}
+
+	return min_period;
+#else
+	/*
+	 * FIXME: we need to verify _all_ consoles.
+	 */
+	return sa1100fb_display_dma_period(&fbi->fb.var);
+#endif
+}
+
+/*
+ * CPU clock speed change handler.  We need to adjust the LCD timing
+ * parameters when the CPU clock is adjusted by the power management
+ * subsystem.
+ */
+static int
+sa1100fb_freq_transition(struct notifier_block *nb, unsigned long val,
+			 void *data)
+{
+	struct sa1100fb_info *fbi = TO_INF(nb, freq_transition);
+	struct cpufreq_freqs *f = data;
+	u_int pcd;
+
+	switch (val) {
+	case CPUFREQ_PRECHANGE:
+		set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
+		break;
+
+	case CPUFREQ_POSTCHANGE:
+		pcd = get_pcd(fbi->fb.var.pixclock, f->new);
+		fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
+		set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
+		break;
+	}
+	return 0;
+}
+
+static int
+sa1100fb_freq_policy(struct notifier_block *nb, unsigned long val,
+		     void *data)
+{
+	struct sa1100fb_info *fbi = TO_INF(nb, freq_policy);
+	struct cpufreq_policy *policy = data;
+
+	switch (val) {
+	case CPUFREQ_ADJUST:
+	case CPUFREQ_INCOMPATIBLE:
+		printk(KERN_DEBUG "min dma period: %d ps, "
+			"new clock %d kHz\n", sa1100fb_min_dma_period(fbi),
+			policy->max);
+		/* todo: fill in min/max values */
+		break;
+	case CPUFREQ_NOTIFY:
+		do {} while(0);
+		/* todo: panic if min/max values aren't fulfilled 
+		 * [can't really happen unless there's a bug in the
+		 * CPU policy verififcation process *
+		 */
+		break;
+	}
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_PM
+/*
+ * Power management hooks.  Note that we won't be called from IRQ context,
+ * unlike the blank functions above, so we may sleep.
+ */
+static int sa1100fb_suspend(struct device *dev, u32 state, u32 level)
+{
+	struct sa1100fb_info *fbi = dev_get_drvdata(dev);
+
+	if (level == SUSPEND_DISABLE || level == SUSPEND_POWER_DOWN)
+		set_ctrlr_state(fbi, C_DISABLE_PM);
+	return 0;
+}
+
+static int sa1100fb_resume(struct device *dev, u32 level)
+{
+	struct sa1100fb_info *fbi = dev_get_drvdata(dev);
+
+	if (level == RESUME_ENABLE)
+		set_ctrlr_state(fbi, C_ENABLE_PM);
+	return 0;
+}
+#else
+#define sa1100fb_suspend	NULL
+#define sa1100fb_resume		NULL
+#endif
+
+/*
+ * sa1100fb_map_video_memory():
+ *      Allocates the DRAM memory for the frame buffer.  This buffer is  
+ *	remapped into a non-cached, non-buffered, memory region to  
+ *      allow palette and pixel writes to occur without flushing the 
+ *      cache.  Once this area is remapped, all virtual memory
+ *      access to the video memory should occur at the new region.
+ */
+static int __init sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
+{
+	/*
+	 * We reserve one page for the palette, plus the size
+	 * of the framebuffer.
+	 */
+	fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
+	fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size,
+					      &fbi->map_dma, GFP_KERNEL);
+
+	if (fbi->map_cpu) {
+		fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE;
+		fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
+		/*
+		 * FIXME: this is actually the wrong thing to place in
+		 * smem_start.  But fbdev suffers from the problem that
+		 * it needs an API which doesn't exist (in this case,
+		 * dma_writecombine_mmap)
+		 */
+		fbi->fb.fix.smem_start = fbi->screen_dma;
+	}
+
+	return fbi->map_cpu ? 0 : -ENOMEM;
+}
+
+/* Fake monspecs to fill in fbinfo structure */
+static struct fb_monspecs monspecs __initdata = {
+	.hfmin	= 30000,
+	.hfmax	= 70000,
+	.vfmin	= 50,
+	.vfmax	= 65,
+};
+
+
+static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev)
+{
+	struct sa1100fb_mach_info *inf;
+	struct sa1100fb_info *fbi;
+
+	fbi = kmalloc(sizeof(struct sa1100fb_info) + sizeof(u32) * 16,
+		      GFP_KERNEL);
+	if (!fbi)
+		return NULL;
+
+	memset(fbi, 0, sizeof(struct sa1100fb_info));
+	fbi->dev = dev;
+
+	strcpy(fbi->fb.fix.id, SA1100_NAME);
+
+	fbi->fb.fix.type	= FB_TYPE_PACKED_PIXELS;
+	fbi->fb.fix.type_aux	= 0;
+	fbi->fb.fix.xpanstep	= 0;
+	fbi->fb.fix.ypanstep	= 0;
+	fbi->fb.fix.ywrapstep	= 0;
+	fbi->fb.fix.accel	= FB_ACCEL_NONE;
+
+	fbi->fb.var.nonstd	= 0;
+	fbi->fb.var.activate	= FB_ACTIVATE_NOW;
+	fbi->fb.var.height	= -1;
+	fbi->fb.var.width	= -1;
+	fbi->fb.var.accel_flags	= 0;
+	fbi->fb.var.vmode	= FB_VMODE_NONINTERLACED;
+
+	fbi->fb.fbops		= &sa1100fb_ops;
+	fbi->fb.flags		= FBINFO_DEFAULT;
+	fbi->fb.monspecs	= monspecs;
+	fbi->fb.pseudo_palette	= (fbi + 1);
+
+	fbi->rgb[RGB_8]		= &rgb_8;
+	fbi->rgb[RGB_16]	= &def_rgb_16;
+
+	inf = sa1100fb_get_machine_info(fbi);
+
+	/*
+	 * People just don't seem to get this.  We don't support
+	 * anything but correct entries now, so panic if someone
+	 * does something stupid.
+	 */
+	if (inf->lccr3 & (LCCR3_VrtSnchL|LCCR3_HorSnchL|0xff) ||
+	    inf->pixclock == 0)
+		panic("sa1100fb error: invalid LCCR3 fields set or zero "
+			"pixclock.");
+
+	fbi->max_xres			= inf->xres;
+	fbi->fb.var.xres		= inf->xres;
+	fbi->fb.var.xres_virtual	= inf->xres;
+	fbi->max_yres			= inf->yres;
+	fbi->fb.var.yres		= inf->yres;
+	fbi->fb.var.yres_virtual	= inf->yres;
+	fbi->max_bpp			= inf->bpp;
+	fbi->fb.var.bits_per_pixel	= inf->bpp;
+	fbi->fb.var.pixclock		= inf->pixclock;
+	fbi->fb.var.hsync_len		= inf->hsync_len;
+	fbi->fb.var.left_margin		= inf->left_margin;
+	fbi->fb.var.right_margin	= inf->right_margin;
+	fbi->fb.var.vsync_len		= inf->vsync_len;
+	fbi->fb.var.upper_margin	= inf->upper_margin;
+	fbi->fb.var.lower_margin	= inf->lower_margin;
+	fbi->fb.var.sync		= inf->sync;
+	fbi->fb.var.grayscale		= inf->cmap_greyscale;
+	fbi->cmap_inverse		= inf->cmap_inverse;
+	fbi->cmap_static		= inf->cmap_static;
+	fbi->lccr0			= inf->lccr0;
+	fbi->lccr3			= inf->lccr3;
+	fbi->state			= C_STARTUP;
+	fbi->task_state			= (u_char)-1;
+	fbi->fb.fix.smem_len		= fbi->max_xres * fbi->max_yres *
+					  fbi->max_bpp / 8;
+
+	init_waitqueue_head(&fbi->ctrlr_wait);
+	INIT_WORK(&fbi->task, sa1100fb_task, fbi);
+	init_MUTEX(&fbi->ctrlr_sem);
+
+	return fbi;
+}
+
+static int __init sa1100fb_probe(struct device *dev)
+{
+	struct sa1100fb_info *fbi;
+	int ret;
+
+	if (!request_mem_region(0xb0100000, 0x10000, "LCD"))
+		return -EBUSY;
+
+	fbi = sa1100fb_init_fbinfo(dev);
+	ret = -ENOMEM;
+	if (!fbi)
+		goto failed;
+
+	/* Initialize video memory */
+	ret = sa1100fb_map_video_memory(fbi);
+	if (ret)
+		goto failed;
+
+	ret = request_irq(IRQ_LCD, sa1100fb_handle_irq, SA_INTERRUPT,
+			  "LCD", fbi);
+	if (ret) {
+		printk(KERN_ERR "sa1100fb: request_irq failed: %d\n", ret);
+		goto failed;
+	}
+
+#ifdef ASSABET_PAL_VIDEO
+	if (machine_is_assabet())
+		ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
+#endif
+
+	/*
+	 * This makes sure that our colour bitfield
+	 * descriptors are correctly initialised.
+	 */
+	sa1100fb_check_var(&fbi->fb.var, &fbi->fb);
+
+	dev_set_drvdata(dev, fbi);
+
+	ret = register_framebuffer(&fbi->fb);
+	if (ret < 0)
+		goto failed;
+
+#ifdef CONFIG_CPU_FREQ
+	fbi->freq_transition.notifier_call = sa1100fb_freq_transition;
+	fbi->freq_policy.notifier_call = sa1100fb_freq_policy;
+	cpufreq_register_notifier(&fbi->freq_transition, CPUFREQ_TRANSITION_NOTIFIER);
+	cpufreq_register_notifier(&fbi->freq_policy, CPUFREQ_POLICY_NOTIFIER);
+#endif
+
+	/* This driver cannot be unloaded at the moment */
+	return 0;
+
+failed:
+	dev_set_drvdata(dev, NULL);
+	kfree(fbi);
+	release_mem_region(0xb0100000, 0x10000);
+	return ret;
+}
+
+static struct device_driver sa1100fb_driver = {
+	.name		= "sa11x0-fb",
+	.bus		= &platform_bus_type,
+	.probe		= sa1100fb_probe,
+	.suspend	= sa1100fb_suspend,
+	.resume		= sa1100fb_resume,
+};
+
+int __init sa1100fb_init(void)
+{
+	if (fb_get_options("sa1100fb", NULL))
+		return -ENODEV;
+
+	return driver_register(&sa1100fb_driver);
+}
+
+int __init sa1100fb_setup(char *options)
+{
+#if 0
+	char *this_opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+
+		if (!strncmp(this_opt, "bpp:", 4))
+			current_par.max_bpp =
+			    simple_strtoul(this_opt + 4, NULL, 0);
+
+		if (!strncmp(this_opt, "lccr0:", 6))
+			lcd_shadow.lccr0 =
+			    simple_strtoul(this_opt + 6, NULL, 0);
+		if (!strncmp(this_opt, "lccr1:", 6)) {
+			lcd_shadow.lccr1 =
+			    simple_strtoul(this_opt + 6, NULL, 0);
+			current_par.max_xres =
+			    (lcd_shadow.lccr1 & 0x3ff) + 16;
+		}
+		if (!strncmp(this_opt, "lccr2:", 6)) {
+			lcd_shadow.lccr2 =
+			    simple_strtoul(this_opt + 6, NULL, 0);
+			current_par.max_yres =
+			    (lcd_shadow.
+			     lccr0 & LCCR0_SDS) ? ((lcd_shadow.
+						    lccr2 & 0x3ff) +
+						   1) *
+			    2 : ((lcd_shadow.lccr2 & 0x3ff) + 1);
+		}
+		if (!strncmp(this_opt, "lccr3:", 6))
+			lcd_shadow.lccr3 =
+			    simple_strtoul(this_opt + 6, NULL, 0);
+	}
+#endif
+	return 0;
+}
+
+module_init(sa1100fb_init);
+MODULE_DESCRIPTION("StrongARM-1100/1110 framebuffer driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/sa1100fb.h b/drivers/video/sa1100fb.h
new file mode 100644
index 0000000..0b07f6a
--- /dev/null
+++ b/drivers/video/sa1100fb.h
@@ -0,0 +1,147 @@
+/*
+ * linux/drivers/video/sa1100fb.h
+ *    -- StrongARM 1100 LCD Controller Frame Buffer Device
+ *
+ *  Copyright (C) 1999 Eric A. Thomas
+ *   Based on acornfb.c Copyright (C) Russell King.
+ *  
+ * 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.
+ */
+
+/*
+ * These are the bitfields for each
+ * display depth that we support.
+ */
+struct sa1100fb_rgb {
+	struct fb_bitfield	red;
+	struct fb_bitfield	green;
+	struct fb_bitfield	blue;
+	struct fb_bitfield	transp;
+};
+
+/*
+ * This structure describes the machine which we are running on.
+ */
+struct sa1100fb_mach_info {
+	u_long		pixclock;
+
+	u_short		xres;
+	u_short		yres;
+
+	u_char		bpp;
+	u_char		hsync_len;
+	u_char		left_margin;
+	u_char		right_margin;
+
+	u_char		vsync_len;
+	u_char		upper_margin;
+	u_char		lower_margin;
+	u_char		sync;
+
+	u_int		cmap_greyscale:1,
+			cmap_inverse:1,
+			cmap_static:1,
+			unused:29;
+
+	u_int		lccr0;
+	u_int		lccr3;
+};
+
+/* Shadows for LCD controller registers */
+struct sa1100fb_lcd_reg {
+	unsigned long lccr0;
+	unsigned long lccr1;
+	unsigned long lccr2;
+	unsigned long lccr3;
+};
+
+#define RGB_8	(0)
+#define RGB_16	(1)
+#define NR_RGB	2
+
+struct sa1100fb_info {
+	struct fb_info		fb;
+	struct device		*dev;
+	struct sa1100fb_rgb	*rgb[NR_RGB];
+
+	u_int			max_bpp;
+	u_int			max_xres;
+	u_int			max_yres;
+
+	/*
+	 * These are the addresses we mapped
+	 * the framebuffer memory region to.
+	 */
+	dma_addr_t		map_dma;
+	u_char *		map_cpu;
+	u_int			map_size;
+
+	u_char *		screen_cpu;
+	dma_addr_t		screen_dma;
+	u16 *			palette_cpu;
+	dma_addr_t		palette_dma;
+	u_int			palette_size;
+
+	dma_addr_t		dbar1;
+	dma_addr_t		dbar2;
+
+	u_int			lccr0;
+	u_int			lccr3;
+	u_int			cmap_inverse:1,
+				cmap_static:1,
+				unused:30;
+
+	u_int			reg_lccr0;
+	u_int			reg_lccr1;
+	u_int			reg_lccr2;
+	u_int			reg_lccr3;
+
+	volatile u_char		state;
+	volatile u_char		task_state;
+	struct semaphore	ctrlr_sem;
+	wait_queue_head_t	ctrlr_wait;
+	struct work_struct	task;
+
+#ifdef CONFIG_CPU_FREQ
+	struct notifier_block	freq_transition;
+	struct notifier_block	freq_policy;
+#endif
+};
+
+#define __type_entry(ptr,type,member) ((type *)((char *)(ptr)-offsetof(type,member)))
+
+#define TO_INF(ptr,member)	__type_entry(ptr,struct sa1100fb_info,member)
+
+#define SA1100_PALETTE_MODE_VAL(bpp)    (((bpp) & 0x018) << 9)
+
+/*
+ * These are the actions for set_ctrlr_state
+ */
+#define C_DISABLE		(0)
+#define C_ENABLE		(1)
+#define C_DISABLE_CLKCHANGE	(2)
+#define C_ENABLE_CLKCHANGE	(3)
+#define C_REENABLE		(4)
+#define C_DISABLE_PM		(5)
+#define C_ENABLE_PM		(6)
+#define C_STARTUP		(7)
+
+#define SA1100_NAME	"SA1100"
+
+/*
+ *  Debug macros 
+ */
+#if DEBUG
+#  define DPRINTK(fmt, args...)	printk("%s: " fmt, __FUNCTION__ , ## args)
+#else
+#  define DPRINTK(fmt, args...)
+#endif
+
+/*
+ * Minimum X and Y resolutions
+ */
+#define MIN_XRES	64
+#define MIN_YRES	64
+
diff --git a/drivers/video/savage/Makefile b/drivers/video/savage/Makefile
new file mode 100644
index 0000000..e09770f
--- /dev/null
+++ b/drivers/video/savage/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the S3 Savage framebuffer driver
+#
+
+obj-$(CONFIG_FB_SAVAGE)			+= savagefb.o
+
+savagefb-y				+= savagefb_driver.o
+savagefb-$(CONFIG_FB_SAVAGE_I2C)	+= savagefb-i2c.o
+savagefb-$(CONFIG_FB_SAVAGE_ACCEL)	+= savagefb_accel.o
diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c
new file mode 100644
index 0000000..024a0ce
--- /dev/null
+++ b/drivers/video/savage/savagefb-i2c.c
@@ -0,0 +1,282 @@
+/*
+ * linux/drivers/video/savage/savagefb-i2c.c - S3 Savage DDC2
+ *
+ * Copyright 2004 Antonino A. Daplas <adaplas @pol.net>
+ *
+ * Based partly on rivafb-i2c.c
+ *
+ * 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/sched.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/fb.h>
+
+#include <asm/io.h>
+#include "savagefb.h"
+
+#define SAVAGE_DDC 	0x50
+
+#define VGA_CR_IX	0x3d4
+#define VGA_CR_DATA	0x3d5
+
+#define CR_SERIAL1	0xa0	/* I2C serial communications interface */
+#define MM_SERIAL1	0xff20
+#define CR_SERIAL2	0xb1	/* DDC2 monitor communications interface */
+
+/* based on vt8365 documentation */
+#define PROSAVAGE_I2C_ENAB	0x10
+#define PROSAVAGE_I2C_SCL_OUT	0x01
+#define PROSAVAGE_I2C_SDA_OUT	0x02
+#define PROSAVAGE_I2C_SCL_IN	0x04
+#define PROSAVAGE_I2C_SDA_IN	0x08
+
+#define SAVAGE4_I2C_ENAB	0x00000020
+#define SAVAGE4_I2C_SCL_OUT	0x00000001
+#define SAVAGE4_I2C_SDA_OUT	0x00000002
+#define SAVAGE4_I2C_SCL_IN	0x00000008
+#define SAVAGE4_I2C_SDA_IN	0x00000010
+
+#define SET_CR_IX(base, val)	writeb((val), base + 0x8000 + VGA_CR_IX)
+#define SET_CR_DATA(base, val)	writeb((val), base + 0x8000 + VGA_CR_DATA)
+#define GET_CR_DATA(base)	readb(base + 0x8000 + VGA_CR_DATA)
+
+static void savage4_gpio_setscl(void *data, int val)
+{
+	struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data;
+	unsigned int r;
+
+	r = readl(chan->ioaddr + chan->reg);
+	if(val)
+		r |= SAVAGE4_I2C_SCL_OUT;
+	else
+		r &= ~SAVAGE4_I2C_SCL_OUT;
+	writel(r, chan->ioaddr + chan->reg);
+	readl(chan->ioaddr + chan->reg);	/* flush posted write */
+}
+
+static void savage4_gpio_setsda(void *data, int val)
+{
+	struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data;
+
+	unsigned int r;
+	r = readl(chan->ioaddr + chan->reg);
+	if(val)
+		r |= SAVAGE4_I2C_SDA_OUT;
+	else
+		r &= ~SAVAGE4_I2C_SDA_OUT;
+	writel(r, chan->ioaddr + chan->reg);
+	readl(chan->ioaddr + chan->reg);	/* flush posted write */
+}
+
+static int savage4_gpio_getscl(void *data)
+{
+	struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data;
+
+	return (0 != (readl(chan->ioaddr + chan->reg) & SAVAGE4_I2C_SCL_IN));
+}
+
+static int savage4_gpio_getsda(void *data)
+{
+	struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data;
+
+	return (0 != (readl(chan->ioaddr + chan->reg) & SAVAGE4_I2C_SDA_IN));
+}
+
+static void prosavage_gpio_setscl(void* data, int val)
+{
+	struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data;
+	u32			  r;
+
+	SET_CR_IX(chan->ioaddr, chan->reg);
+	r = GET_CR_DATA(chan->ioaddr);
+	r |= PROSAVAGE_I2C_ENAB;
+	if (val) {
+		r |= PROSAVAGE_I2C_SCL_OUT;
+	} else {
+		r &= ~PROSAVAGE_I2C_SCL_OUT;
+	}
+	SET_CR_DATA(chan->ioaddr, r);
+}
+
+static void prosavage_gpio_setsda(void* data, int val)
+{
+	struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data;
+	unsigned int r;
+
+	SET_CR_IX(chan->ioaddr, chan->reg);
+	r = GET_CR_DATA(chan->ioaddr);
+	r |= PROSAVAGE_I2C_ENAB;
+	if (val) {
+		r |= PROSAVAGE_I2C_SDA_OUT;
+	} else {
+		r &= ~PROSAVAGE_I2C_SDA_OUT;
+	}
+	SET_CR_DATA(chan->ioaddr, r);
+}
+
+static int prosavage_gpio_getscl(void* data)
+{
+	struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data;
+
+	SET_CR_IX(chan->ioaddr, chan->reg);
+	return (0 != (GET_CR_DATA(chan->ioaddr) & PROSAVAGE_I2C_SCL_IN));
+}
+
+static int prosavage_gpio_getsda(void* data)
+{
+	struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data;
+
+	SET_CR_IX(chan->ioaddr, chan->reg);
+	return (0 != (GET_CR_DATA(chan->ioaddr) & PROSAVAGE_I2C_SDA_IN));
+}
+
+#define I2C_ALGO_SAVAGE   0x0f0000
+static int savage_setup_i2c_bus(struct savagefb_i2c_chan *chan,
+				const char *name)
+{
+	int (*add_bus)(struct i2c_adapter *) = symbol_get(i2c_bit_add_bus);
+	int rc = 0;
+
+	if (add_bus && chan->par) {
+		strcpy(chan->adapter.name, name);
+		chan->adapter.owner		= THIS_MODULE;
+		chan->adapter.id		= I2C_ALGO_SAVAGE;
+		chan->adapter.algo_data		= &chan->algo;
+		chan->adapter.dev.parent	= &chan->par->pcidev->dev;
+		chan->algo.udelay		= 40;
+		chan->algo.mdelay               = 5;
+		chan->algo.timeout		= 20;
+		chan->algo.data 		= chan;
+
+		i2c_set_adapdata(&chan->adapter, chan);
+
+		/* Raise SCL and SDA */
+		chan->algo.setsda(chan, 1);
+		chan->algo.setscl(chan, 1);
+		udelay(20);
+
+		rc = add_bus(&chan->adapter);
+
+		if (rc == 0)
+			dev_dbg(&chan->par->pcidev->dev,
+				"I2C bus %s registered.\n", name);
+		else
+			dev_warn(&chan->par->pcidev->dev,
+				 "Failed to register I2C bus %s.\n", name);
+
+		symbol_put(i2c_bit_add_bus);
+	} else
+		chan->par = NULL;
+
+	return rc;
+}
+
+void savagefb_create_i2c_busses(struct fb_info *info)
+{
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+	par->chan.par	= par;
+
+	switch(info->fix.accel) {
+	case FB_ACCEL_PROSAVAGE_DDRK:
+	case FB_ACCEL_PROSAVAGE_PM:
+		par->chan.reg         = CR_SERIAL2;
+		par->chan.ioaddr      = par->mmio.vbase;
+		par->chan.algo.setsda = prosavage_gpio_setsda;
+		par->chan.algo.setscl = prosavage_gpio_setscl;
+		par->chan.algo.getsda = prosavage_gpio_getsda;
+		par->chan.algo.getscl = prosavage_gpio_getscl;
+		break;
+	case FB_ACCEL_SAVAGE4:
+		par->chan.reg         = 0xff20;
+		par->chan.ioaddr      = par->mmio.vbase;
+		par->chan.algo.setsda = savage4_gpio_setsda;
+		par->chan.algo.setscl = savage4_gpio_setscl;
+		par->chan.algo.getsda = savage4_gpio_getsda;
+		par->chan.algo.getscl = savage4_gpio_getscl;
+		break;
+	default:
+		par->chan.par = NULL;
+	}
+
+	savage_setup_i2c_bus(&par->chan, "SAVAGE DDC2");
+}
+
+void savagefb_delete_i2c_busses(struct fb_info *info)
+{
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+	int (*del_bus)(struct i2c_adapter *) =
+		symbol_get(i2c_bit_del_bus);
+
+	if (del_bus && par->chan.par) {
+		del_bus(&par->chan.adapter);
+		symbol_put(i2c_bit_del_bus);
+	}
+
+	par->chan.par = NULL;
+}
+
+static u8 *savage_do_probe_i2c_edid(struct savagefb_i2c_chan *chan)
+{
+	u8 start = 0x0;
+	int (*transfer)(struct i2c_adapter *, struct i2c_msg *, int) =
+		symbol_get(i2c_transfer);
+	struct i2c_msg msgs[] = {
+		{
+			.addr	= SAVAGE_DDC,
+			.len	= 1,
+			.buf	= &start,
+		}, {
+			.addr	= SAVAGE_DDC,
+			.flags	= I2C_M_RD,
+			.len	= EDID_LENGTH,
+		},
+	};
+	u8 *buf = NULL;
+
+	if (transfer && chan->par) {
+		buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
+
+		if (buf) {
+			msgs[1].buf = buf;
+
+			if (transfer(&chan->adapter, msgs, 2) != 2) {
+				dev_dbg(&chan->par->pcidev->dev,
+					"Unable to read EDID block.\n");
+				kfree(buf);
+				buf = NULL;
+			}
+		}
+
+		symbol_put(i2c_transfer);
+	}
+
+	return buf;
+}
+
+int savagefb_probe_i2c_connector(struct savagefb_par *par, u8 **out_edid)
+{
+	u8 *edid = NULL;
+	int i;
+
+	for (i = 0; i < 3; i++) {
+		/* Do the real work */
+		edid = savage_do_probe_i2c_edid(&par->chan);
+		if (edid)
+			break;
+	}
+	if (out_edid)
+		*out_edid = edid;
+	if (!edid)
+		return 1;
+
+	return 0;
+}
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/savage/savagefb.h b/drivers/video/savage/savagefb.h
new file mode 100644
index 0000000..8594b1e
--- /dev/null
+++ b/drivers/video/savage/savagefb.h
@@ -0,0 +1,354 @@
+/*
+ * linux/drivers/video/savagefb.h -- S3 Savage Framebuffer Driver
+ *
+ * Copyright (c) 2001  Denis Oliver Kropp <dok@convergence.de>
+ *
+ * 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 __SAVAGEFB_H__
+#define __SAVAGEFB_H__
+
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/i2c-algo-bit.h>
+#include "../edid.h"
+
+#ifdef SAVAGEFB_DEBUG
+# define DBG(x)		printk (KERN_DEBUG "savagefb: %s\n", (x));
+#else
+# define DBG(x)
+# define SavagePrintRegs(...)
+#endif
+
+
+#define PCI_CHIP_SAVAGE4      0x8a22
+#define PCI_CHIP_SAVAGE3D     0x8a20
+#define PCI_CHIP_SAVAGE3D_MV  0x8a21
+#define PCI_CHIP_SAVAGE2000   0x9102
+#define PCI_CHIP_SAVAGE_MX_MV 0x8c10
+#define PCI_CHIP_SAVAGE_MX    0x8c11
+#define PCI_CHIP_SAVAGE_IX_MV 0x8c12
+#define PCI_CHIP_SAVAGE_IX    0x8c13
+#define PCI_CHIP_PROSAVAGE_PM 0x8a25
+#define PCI_CHIP_PROSAVAGE_KM 0x8a26
+ /* Twister is a code name; hope I get the real name soon. */
+#define PCI_CHIP_S3TWISTER_P  0x8d01
+#define PCI_CHIP_S3TWISTER_K  0x8d02
+#define PCI_CHIP_PROSAVAGE_DDR          0x8d03
+#define PCI_CHIP_PROSAVAGE_DDRK         0x8d04
+#define PCI_CHIP_SUPSAV_MX128		0x8c22
+#define PCI_CHIP_SUPSAV_MX64		0x8c24
+#define PCI_CHIP_SUPSAV_MX64C		0x8c26
+#define PCI_CHIP_SUPSAV_IX128SDR	0x8c2a
+#define PCI_CHIP_SUPSAV_IX128DDR	0x8c2b
+#define PCI_CHIP_SUPSAV_IX64SDR		0x8c2c
+#define PCI_CHIP_SUPSAV_IX64DDR		0x8c2d
+#define PCI_CHIP_SUPSAV_IXCSDR		0x8c2e
+#define PCI_CHIP_SUPSAV_IXCDDR		0x8c2f
+
+
+
+#define S3_SAVAGE3D_SERIES(chip)  ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE_MX))
+
+#define S3_SAVAGE4_SERIES(chip)   ((chip==S3_SAVAGE4) || (chip==S3_PROSAVAGE))
+
+#define S3_SAVAGE_MOBILE_SERIES(chip)  ((chip==S3_SAVAGE_MX) || (chip==S3_SUPERSAVAGE))
+
+#define S3_SAVAGE_SERIES(chip)    ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE2000))
+
+
+/* Chip tags.  These are used to group the adapters into
+ * related families.
+ */
+
+typedef enum {
+  S3_UNKNOWN = 0,
+  S3_SAVAGE3D,
+  S3_SAVAGE_MX,
+  S3_SAVAGE4,
+  S3_PROSAVAGE,
+  S3_SUPERSAVAGE,
+  S3_SAVAGE2000,
+  S3_LAST
+} savage_chipset;
+
+#define BIOS_BSIZE		     1024
+#define BIOS_BASE		     0xc0000
+
+#define SAVAGE_NEWMMIO_REGBASE_S3    0x1000000  /* 16MB */
+#define SAVAGE_NEWMMIO_REGBASE_S4    0x0000000
+#define SAVAGE_NEWMMIO_REGSIZE	     0x0080000  /* 512kb */
+#define SAVAGE_NEWMMIO_VGABASE	     0x8000
+
+#define BASE_FREQ		     14318
+#define HALF_BASE_FREQ               7159
+
+#define FIFO_CONTROL_REG	     0x8200
+#define MIU_CONTROL_REG		     0x8204
+#define STREAMS_TIMEOUT_REG	     0x8208
+#define MISC_TIMEOUT_REG	     0x820c
+
+#define MONO_PAT_0                   0xa4e8
+#define MONO_PAT_1                   0xa4ec
+
+#define MAXFIFO                      0x7f00
+
+#define BCI_CMD_NOP                  0x40000000
+#define BCI_CMD_SETREG               0x96000000
+#define BCI_CMD_RECT                 0x48000000
+#define BCI_CMD_RECT_XP              0x01000000
+#define BCI_CMD_RECT_YP              0x02000000
+#define BCI_CMD_SEND_COLOR           0x00008000
+#define BCI_CMD_DEST_GBD             0x00000000
+#define BCI_CMD_SRC_GBD              0x00000020
+#define BCI_CMD_SRC_SOLID            0x00000000
+#define BCI_CMD_SRC_MONO             0x00000060
+#define BCI_CMD_CLIP_NEW             0x00006000
+#define BCI_CMD_CLIP_LR              0x00004000
+
+#define BCI_CLIP_LR(l, r)            ((((r) << 16) | (l)) & 0x0FFF0FFF)
+#define BCI_CLIP_TL(t, l)            ((((t) << 16) | (l)) & 0x0FFF0FFF)
+#define BCI_CLIP_BR(b, r)            ((((b) << 16) | (r)) & 0x0FFF0FFF)
+#define BCI_W_H(w, h)                (((h) << 16) | ((w) & 0xFFF))
+#define BCI_X_Y(x, y)                (((y) << 16) | ((x) & 0xFFF))
+
+#define BCI_GBD1                     0xE0
+#define BCI_GBD2                     0xE1
+
+#define BCI_BUFFER_OFFSET            0x10000
+#define BCI_SIZE                     0x4000
+
+#define BCI_SEND(dw)                 writel(dw, par->bci_base + par->bci_ptr++)
+
+#define BCI_CMD_GET_ROP(cmd)         (((cmd) >> 16) & 0xFF)
+#define BCI_CMD_SET_ROP(cmd, rop)    ((cmd) |= ((rop & 0xFF) << 16))
+#define BCI_CMD_SEND_COLOR           0x00008000
+
+struct xtimings {
+	unsigned int Clock;
+	unsigned int HDisplay;
+	unsigned int HSyncStart;
+	unsigned int HSyncEnd;
+	unsigned int HTotal;
+	unsigned int HAdjusted;
+	unsigned int VDisplay;
+	unsigned int VSyncStart;
+	unsigned int VSyncEnd;
+	unsigned int VTotal;
+	unsigned int sync;
+	int	       dblscan;
+	int	       interlaced;
+};
+
+
+/* --------------------------------------------------------------------- */
+
+#define NR_PALETTE	256
+
+
+struct savagefb_par;
+
+struct savagefb_i2c_chan {
+	struct savagefb_par *par;
+	struct i2c_adapter adapter;
+	struct i2c_algo_bit_data algo;
+	volatile u8 __iomem *ioaddr;
+	u32   reg;
+};
+
+struct savagefb_par {
+	struct pci_dev *pcidev;
+	savage_chipset  chip;
+	struct savagefb_i2c_chan chan;
+	unsigned char   *edid;
+	u32 pseudo_palette[16];
+	int dacSpeedBpp;
+	int maxClock;
+	int minClock;
+	int numClocks;
+	int clock[4];
+	struct {
+		u8   __iomem *vbase;
+		u32    pbase;
+		u32    len;
+#ifdef CONFIG_MTRR
+		int    mtrr;
+#endif
+	} video;
+
+	struct {
+		volatile u8  __iomem *vbase;
+		u32           pbase;
+		u32           len;
+	} mmio;
+
+	volatile u32  __iomem *bci_base;
+	unsigned int  bci_ptr;
+
+	u32           cob_offset;
+	u32           cob_size;
+	int           cob_index;
+
+	void (*SavageWaitIdle) (struct savagefb_par *par);
+	void (*SavageWaitFifo) (struct savagefb_par *par, int space);
+
+	int MCLK, REFCLK, LCDclk;
+	int HorizScaleFactor;
+
+	/* Panels size */
+	int SavagePanelWidth;
+	int SavagePanelHeight;
+
+	struct {
+		u16 red, green, blue, transp;
+	} palette[NR_PALETTE];
+
+	int depth;
+	int vwidth;
+
+	unsigned char MiscOutReg;     /* Misc */
+	unsigned char CRTC[25];       /* Crtc Controller */
+	unsigned char Sequencer[5];   /* Video Sequencer */
+	unsigned char Graphics[9];    /* Video Graphics */
+	unsigned char Attribute[21];  /* Video Atribute */
+
+	unsigned int mode, refresh;
+	unsigned char SR08, SR0E, SR0F;
+	unsigned char SR10, SR11, SR12, SR13, SR15, SR18, SR29, SR30;
+	unsigned char SR54[8];
+	unsigned char Clock;
+	unsigned char CR31, CR32, CR33, CR34, CR36, CR3A, CR3B, CR3C;
+	unsigned char CR40, CR41, CR42, CR43, CR45;
+	unsigned char CR50, CR51, CR53, CR55, CR58, CR5B, CR5D, CR5E;
+	unsigned char CR60, CR63, CR65, CR66, CR67, CR68, CR69, CR6D, CR6F;
+	unsigned char CR86, CR88;
+	unsigned char CR90, CR91, CRB0;
+	unsigned int  STREAMS[22];	/* yuck, streams regs */
+	unsigned int  MMPR0, MMPR1, MMPR2, MMPR3;
+};
+
+#define BCI_BD_BW_DISABLE            0x10000000
+#define BCI_BD_SET_BPP(bd, bpp)      ((bd) |= (((bpp) & 0xFF) << 16))
+#define BCI_BD_SET_STRIDE(bd, st)    ((bd) |= ((st) & 0xFFFF))
+
+
+/* IO functions */
+
+#define  vga_in8(addr)         (inb (addr))
+#define vga_in16(addr)         (inw (addr))
+#define vga_in32(addr)         (inl (addr))
+
+#define  vga_out8(addr,val)    (outb ((val), (addr)))
+#define vga_out16(addr,val)    (outw ((val), (addr)))
+#define vga_out32(addr,val)    (outl ((val), (addr)))
+
+#define savage_in16(addr)      readw(par->mmio.vbase + (addr))
+#define savage_in32(addr)      readl(par->mmio.vbase + (addr))
+
+#define savage_out16(addr,val) writew((val), par->mmio.vbase + (addr))
+#define savage_out32(addr,val) writel((val), par->mmio.vbase + (addr))
+
+static inline u8 VGArCR (u8 index)
+{
+  outb (index, 0x3d4);
+  return inb (0x3d5);
+}
+
+static inline u8 VGArGR (u8 index)
+{
+  outb (index, 0x3ce);
+  return inb (0x3cf);
+}
+
+static inline u8 VGArSEQ (u8 index)
+{
+  outb (index, 0x3c4);
+  return inb (0x3c5);
+}
+
+#define VGAwCR(index, val) \
+do {                       \
+  vga_out8 (0x3d4, index); \
+  vga_out8 (0x3d5, val);   \
+} while (0)
+
+#define VGAwGR(index, val) \
+do {                       \
+  vga_out8 (0x3ce, index); \
+  vga_out8 (0x3cf, val);   \
+} while (0)
+
+#define VGAwSEQ(index, val) \
+do {                        \
+  vga_out8 (0x3c4, index);  \
+  vga_out8 (0x3c5, val);    \
+} while (0)
+
+#define VGAenablePalette() \
+do {                       \
+  u8 tmp;                  \
+                           \
+  tmp = vga_in8 (0x3da);   \
+  vga_out8 (0x3c0, 0x00);  \
+  paletteEnabled = 1;      \
+} while (0)
+
+#define VGAdisablePalette() \
+do {                        \
+  u8 tmp;                   \
+                            \
+  tmp = vga_in8 (0x3da);    \
+  vga_out8 (0x3c0, 0x20);   \
+  paletteEnabled = 0;       \
+} while (0)
+
+#define VGAwATTR(index, value) \
+do {                           \
+  u8 tmp;                      \
+                               \
+  if (paletteEnabled)          \
+    index &= ~0x20;            \
+  else                         \
+    index |= 0x20;             \
+                               \
+  tmp = vga_in8 (0x3da);       \
+  vga_out8 (0x3c0, index);     \
+  vga_out8 (0x3c0, value);     \
+} while (0)
+
+#define VGAwMISC(value)    \
+do {                       \
+  vga_out8 (0x3c2, value); \
+} while (0)
+
+#ifndef CONFIG_FB_SAVAGE_ACCEL
+#define savagefb_set_clip(x)
+#endif
+
+#define VerticalRetraceWait() \
+{ \
+	vga_out8 (0x3d4, 0x17); \
+	if (vga_in8 (0x3d5) & 0x80) { \
+		while ((vga_in8(0x3da) & 0x08) == 0x08) ; \
+		while ((vga_in8(0x3da) & 0x08) == 0x00) ; \
+	} \
+}
+
+extern int savagefb_probe_i2c_connector(struct savagefb_par *par,
+					u8 **out_edid);
+extern void savagefb_create_i2c_busses(struct fb_info *info);
+extern void savagefb_delete_i2c_busses(struct fb_info *info);
+extern int  savagefb_sync(struct fb_info *info);
+extern void savagefb_copyarea(struct fb_info *info,
+			      const struct fb_copyarea *region);
+extern void savagefb_fillrect(struct fb_info *info,
+			      const struct fb_fillrect *rect);
+extern void savagefb_imageblit(struct fb_info *info,
+			       const struct fb_image *image);
+
+
+#endif /* __SAVAGEFB_H__ */
diff --git a/drivers/video/savage/savagefb_accel.c b/drivers/video/savage/savagefb_accel.c
new file mode 100644
index 0000000..bac8ea3
--- /dev/null
+++ b/drivers/video/savage/savagefb_accel.c
@@ -0,0 +1,136 @@
+/*-*- linux-c -*-
+ *  linux/drivers/video/savage/savage_accel.c -- Hardware Acceleration
+ *
+ *      Copyright (C) 2004 Antonino Daplas<adaplas@pol.net>
+ *      All Rights Reserved
+ *
+ *  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/kernel.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+
+#include "savagefb.h"
+
+static u32 savagefb_rop[] = {
+	0xCC, /* ROP_COPY */
+	0x5A  /* ROP_XOR  */
+};
+
+int savagefb_sync(struct fb_info *info)
+{
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+
+	par->SavageWaitIdle(par);
+	return 0;
+}
+
+void savagefb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
+{
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+	int sx = region->sx, dx = region->dx;
+	int sy = region->sy, dy = region->dy;
+	int cmd;
+
+	if (!region->width || !region->height)
+		return;
+	par->bci_ptr = 0;
+	cmd = BCI_CMD_RECT | BCI_CMD_DEST_GBD | BCI_CMD_SRC_GBD;
+	BCI_CMD_SET_ROP(cmd, savagefb_rop[0]);
+
+	if (dx <= sx) {
+		cmd |= BCI_CMD_RECT_XP;
+	} else {
+		sx += region->width - 1;
+		dx += region->width - 1;
+	}
+
+	if (dy <= sy) {
+		cmd |= BCI_CMD_RECT_YP;
+	} else {
+		sy += region->height - 1;
+		dy += region->height - 1;
+	}
+
+	par->SavageWaitFifo(par,4);
+	BCI_SEND(cmd);
+	BCI_SEND(BCI_X_Y(sx, sy));
+	BCI_SEND(BCI_X_Y(dx, dy));
+	BCI_SEND(BCI_W_H(region->width, region->height));
+}
+
+void savagefb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+	int cmd, color;
+
+	if (!rect->width || !rect->height)
+		return;
+
+	if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
+		color = rect->color;
+	else
+		color = ((u32 *)info->pseudo_palette)[rect->color];
+
+	cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP |
+	      BCI_CMD_DEST_GBD | BCI_CMD_SRC_SOLID |
+	      BCI_CMD_SEND_COLOR;
+
+	par->bci_ptr = 0;
+	BCI_CMD_SET_ROP(cmd, savagefb_rop[rect->rop]);
+
+	par->SavageWaitFifo(par,4);
+	BCI_SEND(cmd);
+	BCI_SEND(color);
+	BCI_SEND( BCI_X_Y(rect->dx, rect->dy) );
+	BCI_SEND( BCI_W_H(rect->width, rect->height) );
+}
+
+void savagefb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+	int fg, bg, size, i, width;
+	int cmd;
+	u32 *src = (u32 *) image->data;
+
+	if (!image->width || !image->height)
+		return;
+
+	if (image->depth != 1) {
+		cfb_imageblit(info, image);
+		return;
+	}
+
+	if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) {
+		fg = image->fg_color;
+		bg = image->bg_color;
+	} else {
+		fg = ((u32 *)info->pseudo_palette)[image->fg_color];
+		bg = ((u32 *)info->pseudo_palette)[image->bg_color];
+	}
+
+	cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP |
+	      BCI_CMD_CLIP_LR | BCI_CMD_DEST_GBD | BCI_CMD_SRC_MONO |
+	      BCI_CMD_SEND_COLOR;
+
+	par->bci_ptr = 0;
+	BCI_CMD_SET_ROP(cmd, savagefb_rop[0]);
+
+	width = (image->width + 31) & ~31;
+	size = (width * image->height)/8;
+	size >>= 2;
+
+	par->SavageWaitFifo(par, size + 5);
+	BCI_SEND(cmd);
+	BCI_SEND(BCI_CLIP_LR(image->dx, image->dx + image->width - 1));
+	BCI_SEND(fg);
+	BCI_SEND(bg);
+	BCI_SEND(BCI_X_Y(image->dx, image->dy));
+	BCI_SEND(BCI_W_H(width, image->height));
+	for (i = 0; i < size; i++)
+		BCI_SEND(src[i]);
+}
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c
new file mode 100644
index 0000000..e1c9c94
--- /dev/null
+++ b/drivers/video/savage/savagefb_driver.c
@@ -0,0 +1,2279 @@
+/*
+ * linux/drivers/video/savagefb.c -- S3 Savage Framebuffer Driver
+ *
+ * Copyright (c) 2001-2002  Denis Oliver Kropp <dok@directfb.org>
+ *                          Sven Neumann <neo@directfb.org>
+ *
+ *
+ * Card specific code is based on XFree86's savage driver.
+ * Framebuffer framework code is based on code of cyber2000fb and tdfxfb.
+ *
+ * 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.
+ *
+ * 0.4.0 (neo)
+ *  - hardware accelerated clear and move
+ *
+ * 0.3.2 (dok)
+ *  - wait for vertical retrace before writing to cr67
+ *    at the beginning of savagefb_set_par
+ *  - use synchronization registers cr23 and cr26
+ *
+ * 0.3.1 (dok)
+ *  - reset 3D engine
+ *  - don't return alpha bits for 32bit format
+ *
+ * 0.3.0 (dok)
+ *  - added WaitIdle functions for all Savage types
+ *  - do WaitIdle before mode switching
+ *  - code cleanup
+ *
+ * 0.2.0 (dok)
+ *  - first working version
+ *
+ *
+ * TODO
+ * - clock validations in decode_var
+ *
+ * BUGS
+ * - white margin on bootup
+ *
+ */
+
+#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/delay.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/console.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include "savagefb.h"
+
+
+#define SAVAGEFB_VERSION "0.4.0_2.6"
+
+/* --------------------------------------------------------------------- */
+
+
+static char *mode_option __initdata = NULL;
+static int   paletteEnabled = 0;
+
+#ifdef MODULE
+
+MODULE_AUTHOR("(c) 2001-2002  Denis Oliver Kropp <dok@directfb.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("FBDev driver for S3 Savage PCI/AGP Chips");
+
+#endif
+
+
+/* --------------------------------------------------------------------- */
+
+static void vgaHWSeqReset (struct savagefb_par *par, int start)
+{
+	if (start)
+		VGAwSEQ (0x00, 0x01);		/* Synchronous Reset */
+	else
+		VGAwSEQ (0x00, 0x03);		/* End Reset */
+}
+
+static void vgaHWProtect (struct savagefb_par *par, int on)
+{
+	unsigned char tmp;
+
+	if (on) {
+		/*
+		 * Turn off screen and disable sequencer.
+		 */
+		tmp = VGArSEQ (0x01);
+
+		vgaHWSeqReset (par, 1);	        /* start synchronous reset */
+		VGAwSEQ (0x01, tmp | 0x20);	/* disable the display */
+
+		VGAenablePalette();
+	} else {
+		/*
+		 * Reenable sequencer, then turn on screen.
+		 */
+
+		tmp = VGArSEQ (0x01);
+
+		VGAwSEQ (0x01, tmp & ~0x20);	/* reenable display */
+		vgaHWSeqReset (par, 0);	        /* clear synchronous reset */
+
+		VGAdisablePalette();
+	}
+}
+
+static void vgaHWRestore (struct savagefb_par  *par)
+{
+	int i;
+
+	VGAwMISC (par->MiscOutReg);
+
+	for (i = 1; i < 5; i++)
+		VGAwSEQ (i, par->Sequencer[i]);
+
+	/* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or
+	   CRTC[17] */
+	VGAwCR (17, par->CRTC[17] & ~0x80);
+
+	for (i = 0; i < 25; i++)
+		VGAwCR (i, par->CRTC[i]);
+
+	for (i = 0; i < 9; i++)
+		VGAwGR (i, par->Graphics[i]);
+
+	VGAenablePalette();
+
+	for (i = 0; i < 21; i++)
+		VGAwATTR (i, par->Attribute[i]);
+
+	VGAdisablePalette();
+}
+
+static void vgaHWInit (struct fb_var_screeninfo *var,
+		       struct savagefb_par            *par,
+		       struct xtimings                *timings)
+{
+	par->MiscOutReg = 0x23;
+
+	if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT))
+		par->MiscOutReg |= 0x40;
+
+	if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT))
+		par->MiscOutReg |= 0x80;
+
+	/*
+	 * Time Sequencer
+	 */
+	par->Sequencer[0x00] = 0x00;
+	par->Sequencer[0x01] = 0x01;
+	par->Sequencer[0x02] = 0x0F;
+	par->Sequencer[0x03] = 0x00;          /* Font select */
+	par->Sequencer[0x04] = 0x0E;          /* Misc */
+
+	/*
+	 * CRTC Controller
+	 */
+	par->CRTC[0x00] = (timings->HTotal >> 3) - 5;
+	par->CRTC[0x01] = (timings->HDisplay >> 3) - 1;
+	par->CRTC[0x02] = (timings->HSyncStart >> 3) - 1;
+	par->CRTC[0x03] = (((timings->HSyncEnd >> 3)  - 1) & 0x1f) | 0x80;
+	par->CRTC[0x04] = (timings->HSyncStart >> 3);
+	par->CRTC[0x05] = ((((timings->HSyncEnd >> 3) - 1) & 0x20) << 2) |
+		(((timings->HSyncEnd >> 3)) & 0x1f);
+	par->CRTC[0x06] = (timings->VTotal - 2) & 0xFF;
+	par->CRTC[0x07] = (((timings->VTotal - 2) & 0x100) >> 8) |
+		(((timings->VDisplay - 1) & 0x100) >> 7) |
+		((timings->VSyncStart & 0x100) >> 6) |
+		(((timings->VSyncStart - 1) & 0x100) >> 5) |
+		0x10 |
+		(((timings->VTotal - 2) & 0x200) >> 4) |
+		(((timings->VDisplay - 1) & 0x200) >> 3) |
+		((timings->VSyncStart & 0x200) >> 2);
+	par->CRTC[0x08] = 0x00;
+	par->CRTC[0x09] = (((timings->VSyncStart - 1) & 0x200) >> 4) | 0x40;
+
+	if (timings->dblscan)
+		par->CRTC[0x09] |= 0x80;
+
+	par->CRTC[0x0a] = 0x00;
+	par->CRTC[0x0b] = 0x00;
+	par->CRTC[0x0c] = 0x00;
+	par->CRTC[0x0d] = 0x00;
+	par->CRTC[0x0e] = 0x00;
+	par->CRTC[0x0f] = 0x00;
+	par->CRTC[0x10] = timings->VSyncStart & 0xff;
+	par->CRTC[0x11] = (timings->VSyncEnd & 0x0f) | 0x20;
+	par->CRTC[0x12] = (timings->VDisplay - 1) & 0xff;
+	par->CRTC[0x13] = var->xres_virtual >> 4;
+	par->CRTC[0x14] = 0x00;
+	par->CRTC[0x15] = (timings->VSyncStart - 1) & 0xff;
+	par->CRTC[0x16] = (timings->VSyncEnd - 1) & 0xff;
+	par->CRTC[0x17] = 0xc3;
+	par->CRTC[0x18] = 0xff;
+
+	/*
+	 * are these unnecessary?
+	 * vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN|KGA_ENABLE_ON_ZERO);
+	 * vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN|KGA_ENABLE_ON_ZERO);
+	 */
+
+	/*
+	 * Graphics Display Controller
+	 */
+	par->Graphics[0x00] = 0x00;
+	par->Graphics[0x01] = 0x00;
+	par->Graphics[0x02] = 0x00;
+	par->Graphics[0x03] = 0x00;
+	par->Graphics[0x04] = 0x00;
+	par->Graphics[0x05] = 0x40;
+	par->Graphics[0x06] = 0x05;   /* only map 64k VGA memory !!!! */
+	par->Graphics[0x07] = 0x0F;
+	par->Graphics[0x08] = 0xFF;
+
+
+	par->Attribute[0x00]  = 0x00; /* standard colormap translation */
+	par->Attribute[0x01]  = 0x01;
+	par->Attribute[0x02]  = 0x02;
+	par->Attribute[0x03]  = 0x03;
+	par->Attribute[0x04]  = 0x04;
+	par->Attribute[0x05]  = 0x05;
+	par->Attribute[0x06]  = 0x06;
+	par->Attribute[0x07]  = 0x07;
+	par->Attribute[0x08]  = 0x08;
+	par->Attribute[0x09]  = 0x09;
+	par->Attribute[0x0a] = 0x0A;
+	par->Attribute[0x0b] = 0x0B;
+	par->Attribute[0x0c] = 0x0C;
+	par->Attribute[0x0d] = 0x0D;
+	par->Attribute[0x0e] = 0x0E;
+	par->Attribute[0x0f] = 0x0F;
+	par->Attribute[0x10] = 0x41;
+	par->Attribute[0x11] = 0xFF;
+	par->Attribute[0x12] = 0x0F;
+	par->Attribute[0x13] = 0x00;
+	par->Attribute[0x14] = 0x00;
+}
+
+/* -------------------- Hardware specific routines ------------------------- */
+
+/*
+ * Hardware Acceleration for SavageFB
+ */
+
+/* Wait for fifo space */
+static void
+savage3D_waitfifo(struct savagefb_par *par, int space)
+{
+	int slots = MAXFIFO - space;
+
+	while ((savage_in32(0x48C00) & 0x0000ffff) > slots);
+}
+
+static void
+savage4_waitfifo(struct savagefb_par *par, int space)
+{
+	int slots = MAXFIFO - space;
+
+	while ((savage_in32(0x48C60) & 0x001fffff) > slots);
+}
+
+static void
+savage2000_waitfifo(struct savagefb_par *par, int space)
+{
+	int slots = MAXFIFO - space;
+
+	while ((savage_in32(0x48C60) & 0x0000ffff) > slots);
+}
+
+/* Wait for idle accelerator */
+static void
+savage3D_waitidle(struct savagefb_par *par)
+{
+	while ((savage_in32(0x48C00) & 0x0008ffff) != 0x80000);
+}
+
+static void
+savage4_waitidle(struct savagefb_par *par)
+{
+	while ((savage_in32(0x48C60) & 0x00a00000) != 0x00a00000);
+}
+
+static void
+savage2000_waitidle(struct savagefb_par *par)
+{
+	while ((savage_in32(0x48C60) & 0x009fffff));
+}
+
+
+static void
+SavageSetup2DEngine (struct savagefb_par  *par)
+{
+	unsigned long GlobalBitmapDescriptor;
+
+	GlobalBitmapDescriptor = 1 | 8 | BCI_BD_BW_DISABLE;
+	BCI_BD_SET_BPP (GlobalBitmapDescriptor, par->depth);
+	BCI_BD_SET_STRIDE (GlobalBitmapDescriptor, par->vwidth);
+
+	switch(par->chip) {
+	case S3_SAVAGE3D:
+	case S3_SAVAGE_MX:
+		/* Disable BCI */
+		savage_out32(0x48C18, savage_in32(0x48C18) & 0x3FF0);
+		/* Setup BCI command overflow buffer */
+		savage_out32(0x48C14, (par->cob_offset >> 11) | (par->cob_index << 29));
+		/* Program shadow status update. */
+		savage_out32(0x48C10, 0x78207220);
+		savage_out32(0x48C0C, 0);
+		/* Enable BCI and command overflow buffer */
+		savage_out32(0x48C18, savage_in32(0x48C18) | 0x0C);
+		break;
+	case S3_SAVAGE4:
+	case S3_PROSAVAGE:
+	case S3_SUPERSAVAGE:
+		/* Disable BCI */
+		savage_out32(0x48C18, savage_in32(0x48C18) & 0x3FF0);
+		/* Program shadow status update */
+		savage_out32(0x48C10, 0x00700040);
+		savage_out32(0x48C0C, 0);
+		/* Enable BCI without the COB */
+		savage_out32(0x48C18, savage_in32(0x48C18) | 0x08);
+		break;
+	case S3_SAVAGE2000:
+		/* Disable BCI */
+		savage_out32(0x48C18, 0);
+		/* Setup BCI command overflow buffer */
+		savage_out32(0x48C18, (par->cob_offset >> 7) | (par->cob_index));
+		/* Disable shadow status update */
+		savage_out32(0x48A30, 0);
+		/* Enable BCI and command overflow buffer */
+		savage_out32(0x48C18, savage_in32(0x48C18) | 0x00280000 );
+		break;
+	    default:
+		break;
+	}
+	/* Turn on 16-bit register access. */
+	vga_out8(0x3d4, 0x31);
+	vga_out8(0x3d5, 0x0c);
+
+	/* Set stride to use GBD. */
+	vga_out8 (0x3d4, 0x50);
+	vga_out8 (0x3d5, vga_in8 (0x3d5 ) | 0xC1);
+
+	/* Enable 2D engine. */
+	vga_out8 (0x3d4, 0x40 );
+	vga_out8 (0x3d5, 0x01 );
+
+	savage_out32 (MONO_PAT_0, ~0);
+	savage_out32 (MONO_PAT_1, ~0);
+
+	/* Setup plane masks */
+	savage_out32 (0x8128, ~0 ); /* enable all write planes */
+	savage_out32 (0x812C, ~0 ); /* enable all read planes */
+	savage_out16 (0x8134, 0x27 );
+	savage_out16 (0x8136, 0x07 );
+
+	/* Now set the GBD */
+	par->bci_ptr = 0;
+	par->SavageWaitFifo (par, 4);
+
+	BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_GBD1 );
+	BCI_SEND( 0 );
+	BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_GBD2 );
+	BCI_SEND( GlobalBitmapDescriptor );
+}
+
+
+static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1,
+			    int min_n2, int max_n2, long freq_min,
+			    long freq_max, unsigned int *mdiv,
+			    unsigned int *ndiv, unsigned int *r)
+{
+	long diff, best_diff;
+	unsigned int m;
+	unsigned char n1, n2, best_n1=16+2, best_n2=2, best_m=125+2;
+
+	if (freq < freq_min / (1 << max_n2)) {
+		printk (KERN_ERR "invalid frequency %ld Khz\n", freq);
+		freq = freq_min / (1 << max_n2);
+	}
+	if (freq > freq_max / (1 << min_n2)) {
+		printk (KERN_ERR "invalid frequency %ld Khz\n", freq);
+		freq = freq_max / (1 << min_n2);
+	}
+
+	/* work out suitable timings */
+	best_diff = freq;
+
+	for (n2=min_n2; n2<=max_n2; n2++) {
+		for (n1=min_n1+2; n1<=max_n1+2; n1++) {
+			m = (freq * n1 * (1 << n2) + HALF_BASE_FREQ) /
+				BASE_FREQ;
+			if (m < min_m+2 || m > 127+2)
+				continue;
+			if ((m * BASE_FREQ >= freq_min * n1) &&
+			    (m * BASE_FREQ <= freq_max * n1)) {
+				diff = freq * (1 << n2) * n1 - BASE_FREQ * m;
+				if (diff < 0)
+					diff = -diff;
+				if (diff < best_diff) {
+					best_diff = diff;
+					best_m = m;
+					best_n1 = n1;
+					best_n2 = n2;
+				}
+			}
+		}
+	}
+
+	*ndiv = best_n1 - 2;
+	*r = best_n2;
+	*mdiv = best_m - 2;
+}
+
+static int common_calc_clock(long freq, int min_m, int min_n1, int max_n1,
+			     int min_n2, int max_n2, long freq_min,
+			     long freq_max, unsigned char *mdiv,
+			     unsigned char *ndiv)
+{
+	long diff, best_diff;
+	unsigned int m;
+	unsigned char n1, n2;
+	unsigned char best_n1 = 16+2, best_n2 = 2, best_m = 125+2;
+
+	best_diff = freq;
+
+	for (n2 = min_n2; n2 <= max_n2; n2++) {
+		for (n1 = min_n1+2; n1 <= max_n1+2; n1++) {
+			m = (freq * n1 * (1 << n2) + HALF_BASE_FREQ) /
+				BASE_FREQ;
+			if (m < min_m + 2 || m > 127+2)
+				continue;
+			if((m * BASE_FREQ >= freq_min * n1) &&
+			   (m * BASE_FREQ <= freq_max * n1)) {
+				diff = freq * (1 << n2) * n1 - BASE_FREQ * m;
+				if(diff < 0)
+					diff = -diff;
+				if(diff < best_diff) {
+					best_diff = diff;
+					best_m = m;
+					best_n1 = n1;
+					best_n2 = n2;
+				}
+			}
+		}
+	}
+
+	if(max_n1 == 63)
+		*ndiv = (best_n1 - 2) | (best_n2 << 6);
+	else
+		*ndiv = (best_n1 - 2) | (best_n2 << 5);
+
+	*mdiv = best_m - 2;
+
+	return 0;
+}
+
+#ifdef SAVAGEFB_DEBUG
+/* This function is used to debug, it prints out the contents of s3 regs */
+
+static void SavagePrintRegs(void)
+{
+	unsigned char i;
+	int vgaCRIndex = 0x3d4;
+	int vgaCRReg = 0x3d5;
+
+	printk(KERN_DEBUG "SR    x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE "
+	       "xF" );
+
+	for( i = 0; i < 0x70; i++ ) {
+		if( !(i % 16) )
+			printk(KERN_DEBUG "\nSR%xx ", i >> 4 );
+		vga_out8( 0x3c4, i );
+		printk(KERN_DEBUG " %02x", vga_in8(0x3c5) );
+	}
+
+	printk(KERN_DEBUG "\n\nCR    x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC "
+	       "xD xE xF" );
+
+	for( i = 0; i < 0xB7; i++ ) {
+		if( !(i % 16) )
+			printk(KERN_DEBUG "\nCR%xx ", i >> 4 );
+		vga_out8( vgaCRIndex, i );
+		printk(KERN_DEBUG " %02x", vga_in8(vgaCRReg) );
+	}
+
+	printk(KERN_DEBUG "\n\n");
+}
+#endif
+
+/* --------------------------------------------------------------------- */
+
+static void savage_get_default_par(struct savagefb_par *par)
+{
+	unsigned char cr3a, cr53, cr66;
+
+	vga_out16 (0x3d4, 0x4838);
+	vga_out16 (0x3d4, 0xa039);
+	vga_out16 (0x3c4, 0x0608);
+
+	vga_out8 (0x3d4, 0x66);
+	cr66 = vga_in8 (0x3d5);
+	vga_out8 (0x3d5, cr66 | 0x80);
+	vga_out8 (0x3d4, 0x3a);
+	cr3a = vga_in8 (0x3d5);
+	vga_out8 (0x3d5, cr3a | 0x80);
+	vga_out8 (0x3d4, 0x53);
+	cr53 = vga_in8 (0x3d5);
+	vga_out8 (0x3d5, cr53 & 0x7f);
+
+	vga_out8 (0x3d4, 0x66);
+	vga_out8 (0x3d5, cr66);
+	vga_out8 (0x3d4, 0x3a);
+	vga_out8 (0x3d5, cr3a);
+
+	vga_out8 (0x3d4, 0x66);
+	vga_out8 (0x3d5, cr66);
+	vga_out8 (0x3d4, 0x3a);
+	vga_out8 (0x3d5, cr3a);
+
+	/* unlock extended seq regs */
+	vga_out8 (0x3c4, 0x08);
+	par->SR08 = vga_in8 (0x3c5);
+	vga_out8 (0x3c5, 0x06);
+
+	/* now save all the extended regs we need */
+	vga_out8 (0x3d4, 0x31);
+	par->CR31 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x32);
+	par->CR32 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x34);
+	par->CR34 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x36);
+	par->CR36 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x3a);
+	par->CR3A = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x40);
+	par->CR40 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x42);
+	par->CR42 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x45);
+	par->CR45 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x50);
+	par->CR50 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x51);
+	par->CR51 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x53);
+	par->CR53 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x58);
+	par->CR58 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x60);
+	par->CR60 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x66);
+	par->CR66 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x67);
+	par->CR67 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x68);
+	par->CR68 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x69);
+	par->CR69 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x6f);
+	par->CR6F = vga_in8 (0x3d5);
+
+	vga_out8 (0x3d4, 0x33);
+	par->CR33 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x86);
+	par->CR86 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x88);
+	par->CR88 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x90);
+	par->CR90 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x91);
+	par->CR91 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0xb0);
+	par->CRB0 = vga_in8 (0x3d5) | 0x80;
+
+	/* extended mode timing regs */
+	vga_out8 (0x3d4, 0x3b);
+	par->CR3B = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x3c);
+	par->CR3C = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x43);
+	par->CR43 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x5d);
+	par->CR5D = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x5e);
+	par->CR5E = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x65);
+	par->CR65 = vga_in8 (0x3d5);
+
+	/* save seq extended regs for DCLK PLL programming */
+	vga_out8 (0x3c4, 0x0e);
+	par->SR0E = vga_in8 (0x3c5);
+	vga_out8 (0x3c4, 0x0f);
+	par->SR0F = vga_in8 (0x3c5);
+	vga_out8 (0x3c4, 0x10);
+	par->SR10 = vga_in8 (0x3c5);
+	vga_out8 (0x3c4, 0x11);
+	par->SR11 = vga_in8 (0x3c5);
+	vga_out8 (0x3c4, 0x12);
+	par->SR12 = vga_in8 (0x3c5);
+	vga_out8 (0x3c4, 0x13);
+	par->SR13 = vga_in8 (0x3c5);
+	vga_out8 (0x3c4, 0x29);
+	par->SR29 = vga_in8 (0x3c5);
+
+	vga_out8 (0x3c4, 0x15);
+	par->SR15 = vga_in8 (0x3c5);
+	vga_out8 (0x3c4, 0x30);
+	par->SR30 = vga_in8 (0x3c5);
+	vga_out8 (0x3c4, 0x18);
+	par->SR18 = vga_in8 (0x3c5);
+
+	/* Save flat panel expansion regsters. */
+	if (par->chip == S3_SAVAGE_MX) {
+		int i;
+
+		for (i = 0; i < 8; i++) {
+			vga_out8 (0x3c4, 0x54+i);
+			par->SR54[i] = vga_in8 (0x3c5);
+		}
+	}
+
+	vga_out8 (0x3d4, 0x66);
+	cr66 = vga_in8 (0x3d5);
+	vga_out8 (0x3d5, cr66 | 0x80);
+	vga_out8 (0x3d4, 0x3a);
+	cr3a = vga_in8 (0x3d5);
+	vga_out8 (0x3d5, cr3a | 0x80);
+
+	/* now save MIU regs */
+	if (par->chip != S3_SAVAGE_MX) {
+		par->MMPR0 = savage_in32(FIFO_CONTROL_REG);
+		par->MMPR1 = savage_in32(MIU_CONTROL_REG);
+		par->MMPR2 = savage_in32(STREAMS_TIMEOUT_REG);
+		par->MMPR3 = savage_in32(MISC_TIMEOUT_REG);
+	}
+
+	vga_out8 (0x3d4, 0x3a);
+	vga_out8 (0x3d5, cr3a);
+	vga_out8 (0x3d4, 0x66);
+	vga_out8 (0x3d5, cr66);
+}
+
+static void savage_update_var(struct fb_var_screeninfo *var, struct fb_videomode *modedb)
+{
+	var->xres = var->xres_virtual = modedb->xres;
+	var->yres = modedb->yres;
+        if (var->yres_virtual < var->yres)
+	    var->yres_virtual = var->yres;
+        var->xoffset = var->yoffset = 0;
+        var->pixclock = modedb->pixclock;
+        var->left_margin = modedb->left_margin;
+        var->right_margin = modedb->right_margin;
+        var->upper_margin = modedb->upper_margin;
+        var->lower_margin = modedb->lower_margin;
+        var->hsync_len = modedb->hsync_len;
+        var->vsync_len = modedb->vsync_len;
+        var->sync = modedb->sync;
+        var->vmode = modedb->vmode;
+}
+
+static int savagefb_check_var (struct fb_var_screeninfo   *var,
+			       struct fb_info *info)
+{
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+	int memlen, vramlen, mode_valid = 0;
+
+	DBG("savagefb_check_var");
+
+	var->transp.offset = 0;
+	var->transp.length = 0;
+	switch (var->bits_per_pixel) {
+	case 8:
+		var->red.offset = var->green.offset =
+			var->blue.offset = 0;
+		var->red.length = var->green.length =
+			var->blue.length = var->bits_per_pixel;
+		break;
+	case 16:
+		var->red.offset = 11;
+		var->red.length = 5;
+		var->green.offset = 5;
+		var->green.length = 6;
+		var->blue.offset = 0;
+		var->blue.length = 5;
+		break;
+	case 32:
+		var->transp.offset = 24;
+		var->transp.length = 8;
+		var->red.offset = 16;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (!info->monspecs.hfmax || !info->monspecs.vfmax ||
+	    !info->monspecs.dclkmax || !fb_validate_mode(var, info))
+		mode_valid = 1;
+
+	/* calculate modeline if supported by monitor */
+	if (!mode_valid && info->monspecs.gtf) {
+		if (!fb_get_mode(FB_MAXTIMINGS, 0, var, info))
+			mode_valid = 1;
+	}
+
+	if (!mode_valid) {
+		struct fb_videomode *mode;
+
+		mode = fb_find_best_mode(var, &info->modelist);
+		if (mode) {
+			savage_update_var(var, mode);
+			mode_valid = 1;
+		}
+	}
+
+	if (!mode_valid && info->monspecs.modedb_len)
+		return -EINVAL;
+
+	/* Is the mode larger than the LCD panel? */
+	if (par->SavagePanelWidth &&
+	    (var->xres > par->SavagePanelWidth ||
+	     var->yres > par->SavagePanelHeight)) {
+		printk (KERN_INFO "Mode (%dx%d) larger than the LCD panel "
+			"(%dx%d)\n", var->xres,  var->yres,
+			par->SavagePanelWidth,
+			par->SavagePanelHeight);
+		return -1;
+	}
+
+	if (var->yres_virtual < var->yres)
+		var->yres_virtual = var->yres;
+	if (var->xres_virtual < var->xres)
+		var->xres_virtual = var->xres;
+
+	vramlen = info->fix.smem_len;
+
+	memlen = var->xres_virtual * var->bits_per_pixel *
+		var->yres_virtual / 8;
+	if (memlen > vramlen) {
+		var->yres_virtual = vramlen * 8 /
+			(var->xres_virtual * var->bits_per_pixel);
+		memlen = var->xres_virtual * var->bits_per_pixel *
+			var->yres_virtual / 8;
+	}
+
+	/* we must round yres/xres down, we already rounded y/xres_virtual up
+	   if it was possible. We should return -EINVAL, but I disagree */
+	if (var->yres_virtual < var->yres)
+		var->yres = var->yres_virtual;
+	if (var->xres_virtual < var->xres)
+		var->xres = var->xres_virtual;
+	if (var->xoffset + var->xres > var->xres_virtual)
+		var->xoffset = var->xres_virtual - var->xres;
+	if (var->yoffset + var->yres > var->yres_virtual)
+		var->yoffset = var->yres_virtual - var->yres;
+
+	return 0;
+}
+
+
+static int savagefb_decode_var (struct fb_var_screeninfo   *var,
+				struct savagefb_par        *par)
+{
+	struct xtimings timings;
+	int width, dclk, i, j; /*, refresh; */
+	unsigned int m, n, r;
+	unsigned char tmp = 0;
+	unsigned int pixclock = var->pixclock;
+
+	DBG("savagefb_decode_var");
+
+	memset (&timings, 0, sizeof(timings));
+
+	if (!pixclock) pixclock = 10000;	/* 10ns = 100MHz */
+	timings.Clock = 1000000000 / pixclock;
+	if (timings.Clock < 1) timings.Clock = 1;
+	timings.dblscan = var->vmode & FB_VMODE_DOUBLE;
+	timings.interlaced = var->vmode & FB_VMODE_INTERLACED;
+	timings.HDisplay = var->xres;
+	timings.HSyncStart = timings.HDisplay + var->right_margin;
+	timings.HSyncEnd = timings.HSyncStart + var->hsync_len;
+	timings.HTotal = timings.HSyncEnd + var->left_margin;
+	timings.VDisplay = var->yres;
+	timings.VSyncStart = timings.VDisplay + var->lower_margin;
+	timings.VSyncEnd = timings.VSyncStart + var->vsync_len;
+	timings.VTotal = timings.VSyncEnd + var->upper_margin;
+	timings.sync = var->sync;
+
+
+	par->depth  = var->bits_per_pixel;
+	par->vwidth = var->xres_virtual;
+
+	if (var->bits_per_pixel == 16  &&  par->chip == S3_SAVAGE3D) {
+		timings.HDisplay *= 2;
+		timings.HSyncStart *= 2;
+		timings.HSyncEnd *= 2;
+		timings.HTotal *= 2;
+	}
+
+	/*
+	 * This will allocate the datastructure and initialize all of the
+	 * generic VGA registers.
+	 */
+	vgaHWInit (var, par, &timings);
+
+	/* We need to set CR67 whether or not we use the BIOS. */
+
+	dclk = timings.Clock;
+	par->CR67 = 0x00;
+
+	switch( var->bits_per_pixel ) {
+	case 8:
+		if( (par->chip == S3_SAVAGE2000) && (dclk >= 230000) )
+			par->CR67 = 0x10;	/* 8bpp, 2 pixels/clock */
+		else
+			par->CR67 = 0x00;	/* 8bpp, 1 pixel/clock */
+		break;
+	case 15:
+		if ( S3_SAVAGE_MOBILE_SERIES(par->chip) ||
+		     ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)) )
+			par->CR67 = 0x30;	/* 15bpp, 2 pixel/clock */
+		else
+			par->CR67 = 0x20;	/* 15bpp, 1 pixels/clock */
+		break;
+	case 16:
+		if( S3_SAVAGE_MOBILE_SERIES(par->chip) ||
+		    ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)) )
+			par->CR67 = 0x50;	/* 16bpp, 2 pixel/clock */
+		else
+			par->CR67 = 0x40;	/* 16bpp, 1 pixels/clock */
+		break;
+	case 24:
+		par->CR67 = 0x70;
+		break;
+	case 32:
+		par->CR67 = 0xd0;
+		break;
+	}
+
+	/*
+	 * Either BIOS use is disabled, or we failed to find a suitable
+	 * match.  Fall back to traditional register-crunching.
+	 */
+
+	vga_out8 (0x3d4, 0x3a);
+	tmp = vga_in8 (0x3d5);
+	if (1 /*FIXME:psav->pci_burst*/)
+		par->CR3A = (tmp & 0x7f) | 0x15;
+	else
+		par->CR3A = tmp | 0x95;
+
+	par->CR53 = 0x00;
+	par->CR31 = 0x8c;
+	par->CR66 = 0x89;
+
+	vga_out8 (0x3d4, 0x58);
+	par->CR58 = vga_in8 (0x3d5) & 0x80;
+	par->CR58 |= 0x13;
+
+	par->SR15 = 0x03 | 0x80;
+	par->SR18 = 0x00;
+	par->CR43 = par->CR45 = par->CR65 = 0x00;
+
+	vga_out8 (0x3d4, 0x40);
+	par->CR40 = vga_in8 (0x3d5) & ~0x01;
+
+	par->MMPR0 = 0x010400;
+	par->MMPR1 = 0x00;
+	par->MMPR2 = 0x0808;
+	par->MMPR3 = 0x08080810;
+
+	SavageCalcClock (dclk, 1, 1, 127, 0, 4, 180000, 360000, &m, &n, &r);
+	/* m = 107; n = 4; r = 2; */
+
+	if (par->MCLK <= 0) {
+		par->SR10 = 255;
+		par->SR11 = 255;
+	} else {
+		common_calc_clock (par->MCLK, 1, 1, 31, 0, 3, 135000, 270000,
+				   &par->SR11, &par->SR10);
+		/*      par->SR10 = 80; // MCLK == 286000 */
+		/*      par->SR11 = 125; */
+	}
+
+	par->SR12 = (r << 6) | (n & 0x3f);
+	par->SR13 = m & 0xff;
+	par->SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2;
+
+	if (var->bits_per_pixel < 24)
+		par->MMPR0 -= 0x8000;
+	else
+		par->MMPR0 -= 0x4000;
+
+	if (timings.interlaced)
+		par->CR42 = 0x20;
+	else
+		par->CR42 = 0x00;
+
+	par->CR34 = 0x10; /* display fifo */
+
+	i = ((((timings.HTotal >> 3) - 5) & 0x100) >> 8) |
+		((((timings.HDisplay >> 3) - 1) & 0x100) >> 7) |
+		((((timings.HSyncStart >> 3) - 1) & 0x100) >> 6) |
+		((timings.HSyncStart & 0x800) >> 7);
+
+	if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 64)
+		i |= 0x08;
+	if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 32)
+		i |= 0x20;
+
+	j = (par->CRTC[0] + ((i & 0x01) << 8) +
+	     par->CRTC[4] + ((i & 0x10) << 4) + 1) / 2;
+
+	if (j - (par->CRTC[4] + ((i & 0x10) << 4)) < 4) {
+		if (par->CRTC[4] + ((i & 0x10) << 4) + 4 <=
+		    par->CRTC[0] + ((i & 0x01) << 8))
+			j = par->CRTC[4] + ((i & 0x10) << 4) + 4;
+		else
+			j = par->CRTC[0] + ((i & 0x01) << 8) + 1;
+	}
+
+	par->CR3B = j & 0xff;
+	i |= (j & 0x100) >> 2;
+	par->CR3C = (par->CRTC[0] + ((i & 0x01) << 8)) / 2;
+	par->CR5D = i;
+	par->CR5E = (((timings.VTotal - 2) & 0x400) >> 10) |
+		(((timings.VDisplay - 1) & 0x400) >> 9) |
+		(((timings.VSyncStart) & 0x400) >> 8) |
+		(((timings.VSyncStart) & 0x400) >> 6) | 0x40;
+	width = (var->xres_virtual * ((var->bits_per_pixel+7) / 8)) >> 3;
+	par->CR91 = par->CRTC[19] = 0xff & width;
+	par->CR51 = (0x300 & width) >> 4;
+	par->CR90 = 0x80 | (width >> 8);
+	par->MiscOutReg |= 0x0c;
+
+	/* Set frame buffer description. */
+
+	if (var->bits_per_pixel <= 8)
+		par->CR50 = 0;
+	else if (var->bits_per_pixel <= 16)
+		par->CR50 = 0x10;
+	else
+		par->CR50 = 0x30;
+
+	if (var->xres_virtual <= 640)
+		par->CR50 |= 0x40;
+	else if (var->xres_virtual == 800)
+		par->CR50 |= 0x80;
+	else if (var->xres_virtual == 1024)
+		par->CR50 |= 0x00;
+	else if (var->xres_virtual == 1152)
+		par->CR50 |= 0x01;
+	else if (var->xres_virtual == 1280)
+		par->CR50 |= 0xc0;
+	else if (var->xres_virtual == 1600)
+		par->CR50 |= 0x81;
+	else
+		par->CR50 |= 0xc1;	/* Use GBD */
+
+	if( par->chip == S3_SAVAGE2000 )
+		par->CR33 = 0x08;
+	else
+		par->CR33 = 0x20;
+
+	par->CRTC[0x17] = 0xeb;
+
+	par->CR67 |= 1;
+
+	vga_out8(0x3d4, 0x36);
+	par->CR36 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x68);
+	par->CR68 = vga_in8 (0x3d5);
+	par->CR69 = 0;
+	vga_out8 (0x3d4, 0x6f);
+	par->CR6F = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x86);
+	par->CR86 = vga_in8 (0x3d5);
+	vga_out8 (0x3d4, 0x88);
+	par->CR88 = vga_in8 (0x3d5) | 0x08;
+	vga_out8 (0x3d4, 0xb0);
+	par->CRB0 = vga_in8 (0x3d5) | 0x80;
+
+	return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ *    Set a single color register. Return != 0 for invalid regno.
+ */
+static int savagefb_setcolreg(unsigned        regno,
+			      unsigned        red,
+			      unsigned        green,
+			      unsigned        blue,
+			      unsigned        transp,
+			      struct fb_info *info)
+{
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+
+	if (regno >= NR_PALETTE)
+		return -EINVAL;
+
+	par->palette[regno].red    = red;
+	par->palette[regno].green  = green;
+	par->palette[regno].blue   = blue;
+	par->palette[regno].transp = transp;
+
+	switch (info->var.bits_per_pixel) {
+	case 8:
+		vga_out8 (0x3c8, regno);
+
+		vga_out8 (0x3c9, red   >> 10);
+		vga_out8 (0x3c9, green >> 10);
+		vga_out8 (0x3c9, blue  >> 10);
+		break;
+
+	case 16:
+		if (regno < 16)
+			((u32 *)info->pseudo_palette)[regno] =
+				((red   & 0xf800)      ) |
+				((green & 0xfc00) >>  5) |
+				((blue  & 0xf800) >> 11);
+		break;
+
+	case 24:
+		if (regno < 16)
+			((u32 *)info->pseudo_palette)[regno] =
+				((red    & 0xff00) <<  8) |
+				((green  & 0xff00)      ) |
+				((blue   & 0xff00) >>  8);
+		break;
+	case 32:
+		if (regno < 16)
+			((u32 *)info->pseudo_palette)[regno] =
+				((transp & 0xff00) << 16) |
+				((red    & 0xff00) <<  8) |
+				((green  & 0xff00)      ) |
+				((blue   & 0xff00) >>  8);
+		break;
+
+	default:
+		return 1;
+	}
+
+	return 0;
+}
+
+static void savagefb_set_par_int (struct savagefb_par  *par)
+{
+	unsigned char tmp, cr3a, cr66, cr67;
+
+	DBG ("savagefb_set_par_int");
+
+	par->SavageWaitIdle (par);
+
+	vga_out8 (0x3c2, 0x23);
+
+	vga_out16 (0x3d4, 0x4838);
+	vga_out16 (0x3d4, 0xa539);
+	vga_out16 (0x3c4, 0x0608);
+
+	vgaHWProtect (par, 1);
+
+	/*
+	 * Some Savage/MX and /IX systems go nuts when trying to exit the
+	 * server after WindowMaker has displayed a gradient background.  I
+	 * haven't been able to find what causes it, but a non-destructive
+	 * switch to mode 3 here seems to eliminate the issue.
+	 */
+
+	VerticalRetraceWait();
+	vga_out8 (0x3d4, 0x67);
+	cr67 = vga_in8 (0x3d5);
+	vga_out8 (0x3d5, cr67/*par->CR67*/ & ~0x0c); /* no STREAMS yet */
+
+	vga_out8 (0x3d4, 0x23);
+	vga_out8 (0x3d5, 0x00);
+	vga_out8 (0x3d4, 0x26);
+	vga_out8 (0x3d5, 0x00);
+
+	/* restore extended regs */
+	vga_out8 (0x3d4, 0x66);
+	vga_out8 (0x3d5, par->CR66);
+	vga_out8 (0x3d4, 0x3a);
+	vga_out8 (0x3d5, par->CR3A);
+	vga_out8 (0x3d4, 0x31);
+	vga_out8 (0x3d5, par->CR31);
+	vga_out8 (0x3d4, 0x32);
+	vga_out8 (0x3d5, par->CR32);
+	vga_out8 (0x3d4, 0x58);
+	vga_out8 (0x3d5, par->CR58);
+	vga_out8 (0x3d4, 0x53);
+	vga_out8 (0x3d5, par->CR53 & 0x7f);
+
+	vga_out16 (0x3c4, 0x0608);
+
+	/* Restore DCLK registers. */
+
+	vga_out8 (0x3c4, 0x0e);
+	vga_out8 (0x3c5, par->SR0E);
+	vga_out8 (0x3c4, 0x0f);
+	vga_out8 (0x3c5, par->SR0F);
+	vga_out8 (0x3c4, 0x29);
+	vga_out8 (0x3c5, par->SR29);
+	vga_out8 (0x3c4, 0x15);
+	vga_out8 (0x3c5, par->SR15);
+
+	/* Restore flat panel expansion regsters. */
+	if( par->chip == S3_SAVAGE_MX ) {
+		int i;
+
+		for( i = 0; i < 8; i++ ) {
+			vga_out8 (0x3c4, 0x54+i);
+			vga_out8 (0x3c5, par->SR54[i]);
+		}
+	}
+
+	vgaHWRestore (par);
+
+	/* extended mode timing registers */
+	vga_out8 (0x3d4, 0x53);
+	vga_out8 (0x3d5, par->CR53);
+	vga_out8 (0x3d4, 0x5d);
+	vga_out8 (0x3d5, par->CR5D);
+	vga_out8 (0x3d4, 0x5e);
+	vga_out8 (0x3d5, par->CR5E);
+	vga_out8 (0x3d4, 0x3b);
+	vga_out8 (0x3d5, par->CR3B);
+	vga_out8 (0x3d4, 0x3c);
+	vga_out8 (0x3d5, par->CR3C);
+	vga_out8 (0x3d4, 0x43);
+	vga_out8 (0x3d5, par->CR43);
+	vga_out8 (0x3d4, 0x65);
+	vga_out8 (0x3d5, par->CR65);
+
+	/* restore the desired video mode with cr67 */
+	vga_out8 (0x3d4, 0x67);
+	/* following part not present in X11 driver */
+	cr67 = vga_in8 (0x3d5) & 0xf;
+	vga_out8 (0x3d5, 0x50 | cr67);
+	udelay (10000);
+	vga_out8 (0x3d4, 0x67);
+	/* end of part */
+	vga_out8 (0x3d5, par->CR67 & ~0x0c);
+
+	/* other mode timing and extended regs */
+	vga_out8 (0x3d4, 0x34);
+	vga_out8 (0x3d5, par->CR34);
+	vga_out8 (0x3d4, 0x40);
+	vga_out8 (0x3d5, par->CR40);
+	vga_out8 (0x3d4, 0x42);
+	vga_out8 (0x3d5, par->CR42);
+	vga_out8 (0x3d4, 0x45);
+	vga_out8 (0x3d5, par->CR45);
+	vga_out8 (0x3d4, 0x50);
+	vga_out8 (0x3d5, par->CR50);
+	vga_out8 (0x3d4, 0x51);
+	vga_out8 (0x3d5, par->CR51);
+
+	/* memory timings */
+	vga_out8 (0x3d4, 0x36);
+	vga_out8 (0x3d5, par->CR36);
+	vga_out8 (0x3d4, 0x60);
+	vga_out8 (0x3d5, par->CR60);
+	vga_out8 (0x3d4, 0x68);
+	vga_out8 (0x3d5, par->CR68);
+	vga_out8 (0x3d4, 0x69);
+	vga_out8 (0x3d5, par->CR69);
+	vga_out8 (0x3d4, 0x6f);
+	vga_out8 (0x3d5, par->CR6F);
+
+	vga_out8 (0x3d4, 0x33);
+	vga_out8 (0x3d5, par->CR33);
+	vga_out8 (0x3d4, 0x86);
+	vga_out8 (0x3d5, par->CR86);
+	vga_out8 (0x3d4, 0x88);
+	vga_out8 (0x3d5, par->CR88);
+	vga_out8 (0x3d4, 0x90);
+	vga_out8 (0x3d5, par->CR90);
+	vga_out8 (0x3d4, 0x91);
+	vga_out8 (0x3d5, par->CR91);
+
+	if (par->chip == S3_SAVAGE4) {
+		vga_out8 (0x3d4, 0xb0);
+		vga_out8 (0x3d5, par->CRB0);
+	}
+
+	vga_out8 (0x3d4, 0x32);
+	vga_out8 (0x3d5, par->CR32);
+
+	/* unlock extended seq regs */
+	vga_out8 (0x3c4, 0x08);
+	vga_out8 (0x3c5, 0x06);
+
+	/* Restore extended sequencer regs for MCLK. SR10 == 255 indicates
+	 * that we should leave the default SR10 and SR11 values there.
+	 */
+	if (par->SR10 != 255) {
+		vga_out8 (0x3c4, 0x10);
+		vga_out8 (0x3c5, par->SR10);
+		vga_out8 (0x3c4, 0x11);
+		vga_out8 (0x3c5, par->SR11);
+	}
+
+	/* restore extended seq regs for dclk */
+	vga_out8 (0x3c4, 0x0e);
+	vga_out8 (0x3c5, par->SR0E);
+	vga_out8 (0x3c4, 0x0f);
+	vga_out8 (0x3c5, par->SR0F);
+	vga_out8 (0x3c4, 0x12);
+	vga_out8 (0x3c5, par->SR12);
+	vga_out8 (0x3c4, 0x13);
+	vga_out8 (0x3c5, par->SR13);
+	vga_out8 (0x3c4, 0x29);
+	vga_out8 (0x3c5, par->SR29);
+
+	vga_out8 (0x3c4, 0x18);
+	vga_out8 (0x3c5, par->SR18);
+
+	/* load new m, n pll values for dclk & mclk */
+	vga_out8 (0x3c4, 0x15);
+	tmp = vga_in8 (0x3c5) & ~0x21;
+
+	vga_out8 (0x3c5, tmp | 0x03);
+	vga_out8 (0x3c5, tmp | 0x23);
+	vga_out8 (0x3c5, tmp | 0x03);
+	vga_out8 (0x3c5, par->SR15);
+	udelay (100);
+
+	vga_out8 (0x3c4, 0x30);
+	vga_out8 (0x3c5, par->SR30);
+	vga_out8 (0x3c4, 0x08);
+	vga_out8 (0x3c5, par->SR08);
+
+	/* now write out cr67 in full, possibly starting STREAMS */
+	VerticalRetraceWait();
+	vga_out8 (0x3d4, 0x67);
+	vga_out8 (0x3d5, par->CR67);
+
+	vga_out8 (0x3d4, 0x66);
+	cr66 = vga_in8 (0x3d5);
+	vga_out8 (0x3d5, cr66 | 0x80);
+	vga_out8 (0x3d4, 0x3a);
+	cr3a = vga_in8 (0x3d5);
+	vga_out8 (0x3d5, cr3a | 0x80);
+
+	if (par->chip != S3_SAVAGE_MX) {
+		VerticalRetraceWait();
+		savage_out32 (FIFO_CONTROL_REG, par->MMPR0);
+		par->SavageWaitIdle (par);
+		savage_out32 (MIU_CONTROL_REG, par->MMPR1);
+		par->SavageWaitIdle (par);
+		savage_out32 (STREAMS_TIMEOUT_REG, par->MMPR2);
+		par->SavageWaitIdle (par);
+		savage_out32 (MISC_TIMEOUT_REG, par->MMPR3);
+	}
+
+	vga_out8 (0x3d4, 0x66);
+	vga_out8 (0x3d5, cr66);
+	vga_out8 (0x3d4, 0x3a);
+	vga_out8 (0x3d5, cr3a);
+
+	SavageSetup2DEngine (par);
+	vgaHWProtect (par, 0);
+}
+
+static void savagefb_update_start (struct savagefb_par      *par,
+				   struct fb_var_screeninfo *var)
+{
+	int base;
+
+	base = ((var->yoffset * var->xres_virtual + (var->xoffset & ~1))
+		* ((var->bits_per_pixel+7) / 8)) >> 2;
+
+	/* now program the start address registers */
+	vga_out16(0x3d4, (base & 0x00ff00) | 0x0c);
+	vga_out16(0x3d4, ((base & 0x00ff) << 8) | 0x0d);
+	vga_out8 (0x3d4, 0x69);
+	vga_out8 (0x3d5, (base & 0x7f0000) >> 16);
+}
+
+
+static void savagefb_set_fix(struct fb_info *info)
+{
+	info->fix.line_length = info->var.xres_virtual *
+		info->var.bits_per_pixel / 8;
+
+	if (info->var.bits_per_pixel == 8)
+		info->fix.visual      = FB_VISUAL_PSEUDOCOLOR;
+	else
+		info->fix.visual      = FB_VISUAL_TRUECOLOR;
+}
+
+#if defined(CONFIG_FB_SAVAGE_ACCEL)
+static void savagefb_set_clip(struct fb_info *info)
+{
+    struct savagefb_par *par = (struct savagefb_par *)info->par;
+    int cmd;
+
+    cmd = BCI_CMD_NOP | BCI_CMD_CLIP_NEW;
+    par->bci_ptr = 0;
+    par->SavageWaitFifo(par,3);
+    BCI_SEND(cmd);
+    BCI_SEND(BCI_CLIP_TL(0, 0));
+    BCI_SEND(BCI_CLIP_BR(0xfff, 0xfff));
+}
+#endif
+
+static int savagefb_set_par (struct fb_info *info)
+{
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+	struct fb_var_screeninfo *var = &info->var;
+	int err;
+
+	DBG("savagefb_set_par");
+	err = savagefb_decode_var (var, par);
+	if (err)
+		return err;
+
+	if (par->dacSpeedBpp <= 0) {
+		if (var->bits_per_pixel > 24)
+			par->dacSpeedBpp = par->clock[3];
+		else if (var->bits_per_pixel >= 24)
+			par->dacSpeedBpp = par->clock[2];
+		else if ((var->bits_per_pixel > 8) && (var->bits_per_pixel < 24))
+			par->dacSpeedBpp = par->clock[1];
+		else if (var->bits_per_pixel <= 8)
+			par->dacSpeedBpp = par->clock[0];
+	}
+
+	/* Set ramdac limits */
+	par->maxClock = par->dacSpeedBpp;
+	par->minClock = 10000;
+
+	savagefb_set_par_int (par);
+	savagefb_update_start (par, var);
+	fb_set_cmap (&info->cmap, info);
+	savagefb_set_fix(info);
+	savagefb_set_clip(info);
+
+	SavagePrintRegs();
+	return 0;
+}
+
+/*
+ *    Pan or Wrap the Display
+ */
+static int savagefb_pan_display (struct fb_var_screeninfo *var,
+				 struct fb_info           *info)
+{
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+	u_int y_bottom;
+
+	y_bottom = var->yoffset;
+
+	if (!(var->vmode & FB_VMODE_YWRAP))
+		y_bottom += var->yres;
+
+	if (var->xoffset > (var->xres_virtual - var->xres))
+		return -EINVAL;
+	if (y_bottom > info->var.yres_virtual)
+		return -EINVAL;
+
+	savagefb_update_start (par, var);
+
+	info->var.xoffset = var->xoffset;
+	info->var.yoffset = var->yoffset;
+
+	if (var->vmode & FB_VMODE_YWRAP)
+		info->var.vmode |= FB_VMODE_YWRAP;
+	else
+		info->var.vmode &= ~FB_VMODE_YWRAP;
+
+	return 0;
+}
+
+
+static struct fb_ops savagefb_ops = {
+	.owner          = THIS_MODULE,
+	.fb_check_var   = savagefb_check_var,
+	.fb_set_par     = savagefb_set_par,
+	.fb_setcolreg   = savagefb_setcolreg,
+	.fb_pan_display = savagefb_pan_display,
+#if defined(CONFIG_FB_SAVAGE_ACCEL)
+	.fb_fillrect    = savagefb_fillrect,
+	.fb_copyarea    = savagefb_copyarea,
+	.fb_imageblit   = savagefb_imageblit,
+	.fb_sync        = savagefb_sync,
+#else
+	.fb_fillrect    = cfb_fillrect,
+	.fb_copyarea    = cfb_copyarea,
+	.fb_imageblit   = cfb_imageblit,
+#endif
+	.fb_cursor      = soft_cursor,
+};
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_var_screeninfo __devinitdata savagefb_var800x600x8 = {
+	.accel_flags =	FB_ACCELF_TEXT,
+	.xres =		800,
+	.yres =		600,
+	.xres_virtual =  800,
+	.yres_virtual =  600,
+	.bits_per_pixel = 8,
+	.pixclock =	25000,
+	.left_margin =	88,
+	.right_margin =	40,
+	.upper_margin =	23,
+	.lower_margin =	1,
+	.hsync_len =	128,
+	.vsync_len =	4,
+	.sync =		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	.vmode =	FB_VMODE_NONINTERLACED
+};
+
+static void savage_enable_mmio (struct savagefb_par *par)
+{
+	unsigned char val;
+
+	DBG ("savage_enable_mmio\n");
+
+	val = vga_in8 (0x3c3);
+	vga_out8 (0x3c3, val | 0x01);
+	val = vga_in8 (0x3cc);
+	vga_out8 (0x3c2, val | 0x01);
+
+	if (par->chip >= S3_SAVAGE4) {
+		vga_out8 (0x3d4, 0x40);
+		val = vga_in8 (0x3d5);
+		vga_out8 (0x3d5, val | 1);
+	}
+}
+
+
+static void savage_disable_mmio (struct savagefb_par *par)
+{
+	unsigned char val;
+
+	DBG ("savage_disable_mmio\n");
+
+	if(par->chip >= S3_SAVAGE4 ) {
+		vga_out8 (0x3d4, 0x40);
+		val = vga_in8 (0x3d5);
+		vga_out8 (0x3d5, val | 1);
+	}
+}
+
+
+static int __devinit savage_map_mmio (struct fb_info *info)
+{
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+	DBG ("savage_map_mmio");
+
+	if (S3_SAVAGE3D_SERIES (par->chip))
+		par->mmio.pbase = pci_resource_start (par->pcidev, 0) +
+			SAVAGE_NEWMMIO_REGBASE_S3;
+	else
+		par->mmio.pbase = pci_resource_start (par->pcidev, 0) +
+			SAVAGE_NEWMMIO_REGBASE_S4;
+
+	par->mmio.len = SAVAGE_NEWMMIO_REGSIZE;
+
+	par->mmio.vbase = ioremap (par->mmio.pbase, par->mmio.len);
+	if (!par->mmio.vbase) {
+		printk ("savagefb: unable to map memory mapped IO\n");
+		return -ENOMEM;
+	} else
+		printk (KERN_INFO "savagefb: mapped io at %p\n",
+			par->mmio.vbase);
+
+	info->fix.mmio_start = par->mmio.pbase;
+	info->fix.mmio_len   = par->mmio.len;
+
+	par->bci_base = (u32*)(par->mmio.vbase + BCI_BUFFER_OFFSET);
+	par->bci_ptr  = 0;
+
+	savage_enable_mmio (par);
+
+	return 0;
+}
+
+static void __devinit savage_unmap_mmio (struct fb_info *info)
+{
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+	DBG ("savage_unmap_mmio");
+
+	savage_disable_mmio(par);
+
+	if (par->mmio.vbase) {
+		iounmap ((void *)par->mmio.vbase);
+		par->mmio.vbase = NULL;
+	}
+}
+
+static int __devinit savage_map_video (struct fb_info *info,
+				       int video_len)
+{
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+	int resource;
+
+	DBG("savage_map_video");
+
+	if (S3_SAVAGE3D_SERIES (par->chip))
+		resource = 0;
+	else
+		resource = 1;
+
+	par->video.pbase = pci_resource_start (par->pcidev, resource);
+	par->video.len   = video_len;
+	par->video.vbase = ioremap (par->video.pbase, par->video.len);
+
+	if (!par->video.vbase) {
+		printk ("savagefb: unable to map screen memory\n");
+		return -ENOMEM;
+	} else
+		printk (KERN_INFO "savagefb: mapped framebuffer at %p, "
+			"pbase == %x\n", par->video.vbase, par->video.pbase);
+
+	info->fix.smem_start = par->video.pbase;
+	info->fix.smem_len   = par->video.len - par->cob_size;
+	info->screen_base    = par->video.vbase;
+
+#ifdef CONFIG_MTRR
+	par->video.mtrr = mtrr_add (par->video.pbase, video_len,
+				     MTRR_TYPE_WRCOMB, 1);
+#endif
+
+	/* Clear framebuffer, it's all white in memory after boot */
+	memset (par->video.vbase, 0, par->video.len);
+
+	return 0;
+}
+
+static void __devinit savage_unmap_video (struct fb_info *info)
+{
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+
+	DBG("savage_unmap_video");
+
+	if (par->video.vbase) {
+#ifdef CONFIG_MTRR
+		mtrr_del (par->video.mtrr, par->video.pbase, par->video.len);
+#endif
+
+		iounmap (par->video.vbase);
+		par->video.vbase = NULL;
+		info->screen_base = NULL;
+	}
+}
+
+static int __devinit savage_init_hw (struct savagefb_par *par)
+{
+	unsigned char config1, m, n, n1, n2, sr8, cr3f, cr66 = 0, tmp;
+
+	static unsigned char RamSavage3D[] = { 8, 4, 4, 2 };
+	static unsigned char RamSavage4[] =  { 2, 4, 8, 12, 16, 32, 64, 32 };
+	static unsigned char RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 };
+	static unsigned char RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 2, 2 };
+
+	int videoRam, videoRambytes;
+
+	DBG("savage_init_hw");
+
+	/* unprotect CRTC[0-7] */
+	vga_out8(0x3d4, 0x11);
+	tmp = vga_in8(0x3d5);
+	vga_out8(0x3d5, tmp & 0x7f);
+
+	/* unlock extended regs */
+	vga_out16(0x3d4, 0x4838);
+	vga_out16(0x3d4, 0xa039);
+	vga_out16(0x3c4, 0x0608);
+
+	vga_out8(0x3d4, 0x40);
+	tmp = vga_in8(0x3d5);
+	vga_out8(0x3d5, tmp & ~0x01);
+
+	/* unlock sys regs */
+	vga_out8(0x3d4, 0x38);
+	vga_out8(0x3d5, 0x48);
+
+	/* Unlock system registers. */
+	vga_out16(0x3d4, 0x4838);
+
+	/* Next go on to detect amount of installed ram */
+
+	vga_out8(0x3d4, 0x36);            /* for register CR36 (CONFG_REG1), */
+	config1 = vga_in8(0x3d5);           /* get amount of vram installed */
+
+	/* Compute the amount of video memory and offscreen memory. */
+
+	switch  (par->chip) {
+	case S3_SAVAGE3D:
+		videoRam = RamSavage3D[ (config1 & 0xC0) >> 6 ] * 1024;
+		break;
+
+	case S3_SAVAGE4:
+		/*
+		 * The Savage4 has one ugly special case to consider.  On
+		 * systems with 4 banks of 2Mx32 SDRAM, the BIOS says 4MB
+		 * when it really means 8MB.  Why do it the same when you
+		 * can do it different...
+		 */
+		vga_out8(0x3d4, 0x68);	/* memory control 1 */
+		if( (vga_in8(0x3d5) & 0xC0) == (0x01 << 6) )
+			RamSavage4[1] = 8;
+
+		/*FALLTHROUGH*/
+
+	case S3_SAVAGE2000:
+		videoRam = RamSavage4[ (config1 & 0xE0) >> 5 ] * 1024;
+		break;
+
+	case S3_SAVAGE_MX:
+	case S3_SUPERSAVAGE:
+		videoRam = RamSavageMX[ (config1 & 0x0E) >> 1 ] * 1024;
+		break;
+
+	case S3_PROSAVAGE:
+		videoRam = RamSavageNB[ (config1 & 0xE0) >> 5 ] * 1024;
+		break;
+
+	default:
+		/* How did we get here? */
+		videoRam = 0;
+		break;
+	}
+
+	videoRambytes = videoRam * 1024;
+
+	printk (KERN_INFO "savagefb: probed videoram:  %dk\n", videoRam);
+
+	/* reset graphics engine to avoid memory corruption */
+	vga_out8 (0x3d4, 0x66);
+	cr66 = vga_in8 (0x3d5);
+	vga_out8 (0x3d5, cr66 | 0x02);
+	udelay (10000);
+
+	vga_out8 (0x3d4, 0x66);
+	vga_out8 (0x3d5, cr66 & ~0x02);	/* clear reset flag */
+	udelay (10000);
+
+
+	/*
+	 * reset memory interface, 3D engine, AGP master, PCI master,
+	 * master engine unit, motion compensation/LPB
+	 */
+	vga_out8 (0x3d4, 0x3f);
+	cr3f = vga_in8 (0x3d5);
+	vga_out8 (0x3d5, cr3f | 0x08);
+	udelay (10000);
+
+	vga_out8 (0x3d4, 0x3f);
+	vga_out8 (0x3d5, cr3f & ~0x08);	/* clear reset flags */
+	udelay (10000);
+
+	/* Savage ramdac speeds */
+	par->numClocks = 4;
+	par->clock[0] = 250000;
+	par->clock[1] = 250000;
+	par->clock[2] = 220000;
+	par->clock[3] = 220000;
+
+	/* detect current mclk */
+	vga_out8(0x3c4, 0x08);
+	sr8 = vga_in8(0x3c5);
+	vga_out8(0x3c5, 0x06);
+	vga_out8(0x3c4, 0x10);
+	n = vga_in8(0x3c5);
+	vga_out8(0x3c4, 0x11);
+	m = vga_in8(0x3c5);
+	vga_out8(0x3c4, 0x08);
+	vga_out8(0x3c5, sr8);
+	m &= 0x7f;
+	n1 = n & 0x1f;
+	n2 = (n >> 5) & 0x03;
+	par->MCLK = ((1431818 * (m+2)) / (n1+2) / (1 << n2) + 50) / 100;
+	printk (KERN_INFO "savagefb: Detected current MCLK value of %d kHz\n",
+		par->MCLK);
+
+	/* Check LCD panel parrmation */
+
+	if (par->chip == S3_SAVAGE_MX) {
+		unsigned char cr6b = VGArCR( 0x6b );
+
+		int panelX = (VGArSEQ (0x61) +
+			      ((VGArSEQ (0x66) & 0x02) << 7) + 1) * 8;
+		int panelY = (VGArSEQ (0x69) +
+			      ((VGArSEQ (0x6e) & 0x70) << 4) + 1);
+
+		char * sTechnology = "Unknown";
+
+		/* OK, I admit it.  I don't know how to limit the max dot clock
+		 * for LCD panels of various sizes.  I thought I copied the
+		 * formula from the BIOS, but many users have parrmed me of
+		 * my folly.
+		 *
+		 * Instead, I'll abandon any attempt to automatically limit the
+		 * clock, and add an LCDClock option to XF86Config.  Some day,
+		 * I should come back to this.
+		 */
+
+		enum ACTIVE_DISPLAYS { /* These are the bits in CR6B */
+			ActiveCRT = 0x01,
+			ActiveLCD = 0x02,
+			ActiveTV = 0x04,
+			ActiveCRT2 = 0x20,
+			ActiveDUO = 0x80
+		};
+
+		if ((VGArSEQ (0x39) & 0x03) == 0) {
+			sTechnology = "TFT";
+		} else if ((VGArSEQ (0x30) & 0x01) == 0) {
+			sTechnology = "DSTN";
+		} else 	{
+			sTechnology = "STN";
+		}
+
+		printk (KERN_INFO "savagefb: %dx%d %s LCD panel detected %s\n",
+			panelX, panelY, sTechnology,
+			cr6b & ActiveLCD ? "and active" : "but not active");
+
+		if( cr6b & ActiveLCD ) 	{
+			/*
+			 * If the LCD is active and panel expansion is enabled,
+			 * we probably want to kill the HW cursor.
+			 */
+
+			printk (KERN_INFO "savagefb: Limiting video mode to "
+				"%dx%d\n", panelX, panelY );
+
+			par->SavagePanelWidth = panelX;
+			par->SavagePanelHeight = panelY;
+
+		}
+	}
+
+	savage_get_default_par (par);
+
+	if( S3_SAVAGE4_SERIES(par->chip) ) {
+		/*
+		 * The Savage4 and ProSavage have COB coherency bugs which
+		 * render the buffer useless.  We disable it.
+		 */
+		par->cob_index = 2;
+		par->cob_size = 0x8000 << par->cob_index;
+		par->cob_offset = videoRambytes;
+	} else {
+		/* We use 128kB for the COB on all chips. */
+
+		par->cob_index  = 7;
+		par->cob_size   = 0x400 << par->cob_index;
+		par->cob_offset = videoRambytes - par->cob_size;
+	}
+
+	return videoRambytes;
+}
+
+static int __devinit savage_init_fb_info (struct fb_info *info,
+					  struct pci_dev *dev,
+					  const struct pci_device_id *id)
+{
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+	int err = 0;
+
+	par->pcidev  = dev;
+
+	info->fix.type	   = FB_TYPE_PACKED_PIXELS;
+	info->fix.type_aux	   = 0;
+	info->fix.xpanstep	   = 2;
+	info->fix.ypanstep	   = 1;
+	info->fix.ywrapstep   = 0;
+	info->fix.accel       = id->driver_data;
+
+	switch (info->fix.accel) {
+	case FB_ACCEL_SUPERSAVAGE:
+		par->chip = S3_SUPERSAVAGE;
+		snprintf (info->fix.id, 16, "SuperSavage");
+		break;
+	case FB_ACCEL_SAVAGE4:
+		par->chip = S3_SAVAGE4;
+		snprintf (info->fix.id, 16, "Savage4");
+		break;
+	case FB_ACCEL_SAVAGE3D:
+		par->chip = S3_SAVAGE3D;
+		snprintf (info->fix.id, 16, "Savage3D");
+		break;
+	case FB_ACCEL_SAVAGE3D_MV:
+		par->chip = S3_SAVAGE3D;
+		snprintf (info->fix.id, 16, "Savage3D-MV");
+		break;
+	case FB_ACCEL_SAVAGE2000:
+		par->chip = S3_SAVAGE2000;
+		snprintf (info->fix.id, 16, "Savage2000");
+		break;
+	case FB_ACCEL_SAVAGE_MX_MV:
+		par->chip = S3_SAVAGE_MX;
+		snprintf (info->fix.id, 16, "Savage/MX-MV");
+		break;
+	case FB_ACCEL_SAVAGE_MX:
+		par->chip = S3_SAVAGE_MX;
+		snprintf (info->fix.id, 16, "Savage/MX");
+		break;
+	case FB_ACCEL_SAVAGE_IX_MV:
+		par->chip = S3_SAVAGE_MX;
+		snprintf (info->fix.id, 16, "Savage/IX-MV");
+		break;
+	case FB_ACCEL_SAVAGE_IX:
+		par->chip = S3_SAVAGE_MX;
+		snprintf (info->fix.id, 16, "Savage/IX");
+		break;
+	case FB_ACCEL_PROSAVAGE_PM:
+		par->chip = S3_PROSAVAGE;
+		snprintf (info->fix.id, 16, "ProSavagePM");
+		break;
+	case FB_ACCEL_PROSAVAGE_KM:
+		par->chip = S3_PROSAVAGE;
+		snprintf (info->fix.id, 16, "ProSavageKM");
+		break;
+	case FB_ACCEL_S3TWISTER_P:
+		par->chip = S3_PROSAVAGE;
+		snprintf (info->fix.id, 16, "TwisterP");
+		break;
+	case FB_ACCEL_S3TWISTER_K:
+		par->chip = S3_PROSAVAGE;
+		snprintf (info->fix.id, 16, "TwisterK");
+		break;
+	case FB_ACCEL_PROSAVAGE_DDR:
+		par->chip = S3_PROSAVAGE;
+		snprintf (info->fix.id, 16, "ProSavageDDR");
+		break;
+	case FB_ACCEL_PROSAVAGE_DDRK:
+		par->chip = S3_PROSAVAGE;
+		snprintf (info->fix.id, 16, "ProSavage8");
+		break;
+	}
+
+	if (S3_SAVAGE3D_SERIES(par->chip)) {
+		par->SavageWaitIdle = savage3D_waitidle;
+		par->SavageWaitFifo = savage3D_waitfifo;
+	} else if (S3_SAVAGE4_SERIES(par->chip) ||
+		   S3_SUPERSAVAGE == par->chip) {
+		par->SavageWaitIdle = savage4_waitidle;
+		par->SavageWaitFifo = savage4_waitfifo;
+	} else {
+		par->SavageWaitIdle = savage2000_waitidle;
+		par->SavageWaitFifo = savage2000_waitfifo;
+	}
+
+	info->var.nonstd      = 0;
+	info->var.activate    = FB_ACTIVATE_NOW;
+	info->var.width       = -1;
+	info->var.height      = -1;
+	info->var.accel_flags = 0;
+
+	info->fbops          = &savagefb_ops;
+	info->flags          = FBINFO_DEFAULT |
+		               FBINFO_HWACCEL_YPAN |
+		               FBINFO_HWACCEL_XPAN;
+
+	info->pseudo_palette = par->pseudo_palette;
+
+#if defined(CONFIG_FB_SAVAGE_ACCEL)
+	/* FIFO size + padding for commands */
+	info->pixmap.addr = kmalloc(8*1024, GFP_KERNEL);
+
+	err = -ENOMEM;
+	if (info->pixmap.addr) {
+		memset(info->pixmap.addr, 0, 8*1024);
+		info->pixmap.size = 8*1024;
+		info->pixmap.scan_align = 4;
+		info->pixmap.buf_align = 4;
+		info->pixmap.access_align = 4;
+
+		fb_alloc_cmap (&info->cmap, NR_PALETTE, 0);
+		info->flags |= FBINFO_HWACCEL_COPYAREA |
+	                       FBINFO_HWACCEL_FILLRECT |
+		               FBINFO_HWACCEL_IMAGEBLIT;
+
+		err = 0;
+	}
+#endif
+	return err;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int __devinit savagefb_probe (struct pci_dev* dev,
+				     const struct pci_device_id* id)
+{
+	struct fb_info *info;
+	struct savagefb_par *par;
+	u_int h_sync, v_sync;
+	int err, lpitch;
+	int video_len;
+
+	DBG("savagefb_probe");
+	SavagePrintRegs();
+
+	info = framebuffer_alloc(sizeof(struct savagefb_par), &dev->dev);
+	if (!info)
+		return -ENOMEM;
+	par = info->par;
+	err = pci_enable_device(dev);
+	if (err)
+		goto failed_enable;
+
+	if (pci_request_regions(dev, "savagefb")) {
+		printk(KERN_ERR "cannot request PCI regions\n");
+		goto failed_enable;
+	}
+
+	err = -ENOMEM;
+
+	if (savage_init_fb_info(info, dev, id))
+		goto failed_init;
+
+	err = savage_map_mmio(info);
+	if (err)
+		goto failed_mmio;
+
+	video_len = savage_init_hw(par);
+	if (video_len < 0) {
+		err = video_len;
+		goto failed_mmio;
+	}
+
+	err = savage_map_video(info, video_len);
+	if (err)
+		goto failed_video;
+
+	INIT_LIST_HEAD(&info->modelist);
+#if defined(CONFIG_FB_SAVAGE_I2C)
+	savagefb_create_i2c_busses(info);
+	savagefb_probe_i2c_connector(par, &par->edid);
+	fb_edid_to_monspecs(par->edid, &info->monspecs);
+	fb_videomode_to_modelist(info->monspecs.modedb,
+				 info->monspecs.modedb_len,
+				 &info->modelist);
+#endif
+	info->var = savagefb_var800x600x8;
+
+	if (mode_option) {
+		fb_find_mode(&info->var, info, mode_option,
+			     info->monspecs.modedb, info->monspecs.modedb_len,
+			     NULL, 8);
+	} else if (info->monspecs.modedb != NULL) {
+		struct fb_monspecs *specs = &info->monspecs;
+		struct fb_videomode modedb;
+
+		if (info->monspecs.misc & FB_MISC_1ST_DETAIL) {
+			int i;
+
+			for (i = 0; i < specs->modedb_len; i++) {
+				if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {
+					modedb = specs->modedb[i];
+					break;
+				}
+			}
+		} else {
+			/* otherwise, get first mode in database */
+			modedb = specs->modedb[0];
+		}
+
+		savage_update_var(&info->var, &modedb);
+	}
+
+	/* maximize virtual vertical length */
+	lpitch = info->var.xres_virtual*((info->var.bits_per_pixel + 7) >> 3);
+	info->var.yres_virtual = info->fix.smem_len/lpitch;
+
+	if (info->var.yres_virtual < info->var.yres)
+		goto failed;
+
+#if defined(CONFIG_FB_SAVAGE_ACCEL)
+	/*
+	 * The clipping coordinates are masked with 0xFFF, so limit our
+	 * virtual resolutions to these sizes.
+	 */
+	if (info->var.yres_virtual > 0x1000)
+		info->var.yres_virtual = 0x1000;
+
+	if (info->var.xres_virtual > 0x1000)
+		info->var.xres_virtual = 0x1000;
+#endif
+	savagefb_check_var(&info->var, info);
+	savagefb_set_fix(info);
+
+	/*
+	 * Calculate the hsync and vsync frequencies.  Note that
+	 * we split the 1e12 constant up so that we can preserve
+	 * the precision and fit the results into 32-bit registers.
+	 *  (1953125000 * 512 = 1e12)
+	 */
+	h_sync = 1953125000 / info->var.pixclock;
+	h_sync = h_sync * 512 / (info->var.xres + info->var.left_margin +
+				 info->var.right_margin +
+				 info->var.hsync_len);
+	v_sync = h_sync / (info->var.yres + info->var.upper_margin +
+			   info->var.lower_margin + info->var.vsync_len);
+
+	printk(KERN_INFO "savagefb v" SAVAGEFB_VERSION ": "
+	       "%dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
+	       info->fix.smem_len >> 10,
+	       info->var.xres, info->var.yres,
+	       h_sync / 1000, h_sync % 1000, v_sync);
+
+
+	fb_destroy_modedb(info->monspecs.modedb);
+	info->monspecs.modedb = NULL;
+
+	err = register_framebuffer (info);
+	if (err < 0)
+		goto failed;
+
+	printk (KERN_INFO "fb: S3 %s frame buffer device\n",
+		info->fix.id);
+
+	/*
+	 * Our driver data
+	 */
+	pci_set_drvdata(dev, info);
+
+	return 0;
+
+ failed:
+#ifdef CONFIG_FB_SAVAGE_I2C
+	savagefb_delete_i2c_busses(info);
+#endif
+	fb_alloc_cmap (&info->cmap, 0, 0);
+	savage_unmap_video(info);
+ failed_video:
+	savage_unmap_mmio (info);
+ failed_mmio:
+	kfree(info->pixmap.addr);
+ failed_init:
+	pci_release_regions(dev);
+ failed_enable:
+	framebuffer_release(info);
+
+	return err;
+}
+
+static void __devexit savagefb_remove (struct pci_dev *dev)
+{
+	struct fb_info *info =
+		(struct fb_info *)pci_get_drvdata(dev);
+
+	DBG("savagefb_remove");
+
+	if (info) {
+		/*
+		 * If unregister_framebuffer fails, then
+		 * we will be leaving hooks that could cause
+		 * oopsen laying around.
+		 */
+		if (unregister_framebuffer (info))
+			printk (KERN_WARNING "savagefb: danger danger! "
+				"Oopsen imminent!\n");
+
+#ifdef CONFIG_FB_SAVAGE_I2C
+		savagefb_delete_i2c_busses(info);
+#endif
+		fb_alloc_cmap (&info->cmap, 0, 0);
+		savage_unmap_video (info);
+		savage_unmap_mmio (info);
+		kfree(info->pixmap.addr);
+		pci_release_regions(dev);
+		framebuffer_release(info);
+
+		/*
+		 * Ensure that the driver data is no longer
+		 * valid.
+		 */
+		pci_set_drvdata(dev, NULL);
+	}
+}
+
+static int savagefb_suspend (struct pci_dev* dev, u32 state)
+{
+	struct fb_info *info =
+		(struct fb_info *)pci_get_drvdata(dev);
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+
+	DBG("savagefb_suspend");
+	printk(KERN_DEBUG "state: %u\n", state);
+
+	acquire_console_sem();
+	fb_set_suspend(info, state);
+	savage_disable_mmio(par);
+	release_console_sem();
+
+	pci_disable_device(dev);
+	pci_set_power_state(dev, state);
+
+	return 0;
+}
+
+static int savagefb_resume (struct pci_dev* dev)
+{
+	struct fb_info *info =
+		(struct fb_info *)pci_get_drvdata(dev);
+	struct savagefb_par *par = (struct savagefb_par *)info->par;
+
+	DBG("savage_resume");
+
+	pci_set_power_state(dev, 0);
+	pci_restore_state(dev);
+	if(pci_enable_device(dev))
+		DBG("err");
+
+	SavagePrintRegs();
+
+	acquire_console_sem();
+
+	savage_enable_mmio(par);
+	savage_init_hw(par);
+	savagefb_set_par (info);
+
+	fb_set_suspend (info, 0);
+	release_console_sem();
+
+	return 0;
+}
+
+
+static struct pci_device_id savagefb_devices[] __devinitdata = {
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX128,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX64,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX64C,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX128SDR,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX128DDR,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX64SDR,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX64DDR,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IXCSDR,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IXCDDR,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE4,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE4},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE3D,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE3D},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE3D_MV,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE3D_MV},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE2000,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE2000},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_MX_MV,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_MX_MV},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_MX,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_MX},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_IX_MV,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_IX_MV},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_IX,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_IX},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_PM,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_PM},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_KM,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_KM},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_S3TWISTER_P,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_S3TWISTER_P},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_S3TWISTER_K,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_S3TWISTER_K},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_DDR,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_DDR},
+
+	{PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_DDRK,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_DDRK},
+
+	{0, 0, 0, 0, 0, 0, 0}
+};
+
+MODULE_DEVICE_TABLE(pci, savagefb_devices);
+
+static struct pci_driver savagefb_driver = {
+	.name =     "savagefb",
+	.id_table = savagefb_devices,
+	.probe =    savagefb_probe,
+	.suspend =  savagefb_suspend,
+	.resume =   savagefb_resume,
+	.remove =   __devexit_p(savagefb_remove)
+};
+
+/* **************************** exit-time only **************************** */
+
+static void __exit savage_done (void)
+{
+	DBG("savage_done");
+	pci_unregister_driver (&savagefb_driver);
+}
+
+
+/* ************************* init in-kernel code ************************** */
+
+static int __init savagefb_setup(char *options)
+{
+#ifndef MODULE
+	char *this_opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		mode_option = this_opt;
+	}
+#endif /* !MODULE */
+	return 0;
+}
+
+static int __init savagefb_init(void)
+{
+	char *option;
+
+	DBG("savagefb_init");
+
+	if (fb_get_options("savagefb", &option))
+		return -ENODEV;
+
+	savagefb_setup(option);
+	return pci_register_driver (&savagefb_driver);
+
+}
+
+module_init(savagefb_init);
+module_exit(savage_done);
diff --git a/drivers/video/sbuslib.c b/drivers/video/sbuslib.c
new file mode 100644
index 0000000..34f72ed
--- /dev/null
+++ b/drivers/video/sbuslib.c
@@ -0,0 +1,184 @@
+/* sbuslib.c: Helper library for SBUS framebuffer drivers.
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <linux/mm.h>
+
+#include <asm/oplib.h>
+#include <asm/fbio.h>
+
+#include "sbuslib.h"
+
+void sbusfb_fill_var(struct fb_var_screeninfo *var, int prom_node, int bpp)
+{
+	memset(var, 0, sizeof(*var));
+
+	var->xres = prom_getintdefault(prom_node, "width", 1152);
+	var->yres = prom_getintdefault(prom_node, "height", 900);
+	var->xres_virtual = var->xres;
+	var->yres_virtual = var->yres;
+	var->bits_per_pixel = bpp;
+}
+
+EXPORT_SYMBOL(sbusfb_fill_var);
+
+static unsigned long sbusfb_mmapsize(long size, unsigned long fbsize)
+{
+	if (size == SBUS_MMAP_EMPTY) return 0;
+	if (size >= 0) return size;
+	return fbsize * (-size);
+}
+
+int sbusfb_mmap_helper(struct sbus_mmap_map *map,
+		       unsigned long physbase,
+		       unsigned long fbsize,
+		       unsigned long iospace,
+		       struct vm_area_struct *vma)
+{
+	unsigned int size, page, r, map_size;
+	unsigned long map_offset = 0;
+	unsigned long off;
+	int i;
+                                        
+	size = vma->vm_end - vma->vm_start;
+	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+		return -EINVAL;
+
+	off = vma->vm_pgoff << PAGE_SHIFT;
+
+	/* To stop the swapper from even considering these pages */
+	vma->vm_flags |= (VM_IO | VM_RESERVED);
+	
+	/* Each page, see which map applies */
+	for (page = 0; page < size; ){
+		map_size = 0;
+		for (i = 0; map[i].size; i++)
+			if (map[i].voff == off+page) {
+				map_size = sbusfb_mmapsize(map[i].size, fbsize);
+#ifdef __sparc_v9__
+#define POFF_MASK	(PAGE_MASK|0x1UL)
+#else
+#define POFF_MASK	(PAGE_MASK)
+#endif				
+				map_offset = (physbase + map[i].poff) & POFF_MASK;
+				break;
+			}
+		if (!map_size){
+			page += PAGE_SIZE;
+			continue;
+		}
+		if (page + map_size > size)
+			map_size = size - page;
+		r = io_remap_pfn_range(vma,
+					vma->vm_start + page,
+					MK_IOSPACE_PFN(iospace,
+						map_offset >> PAGE_SHIFT),
+					map_size,
+					vma->vm_page_prot);
+		if (r)
+			return -EAGAIN;
+		page += map_size;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(sbusfb_mmap_helper);
+
+int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg,
+			struct fb_info *info,
+			int type, int fb_depth, unsigned long fb_size)
+{
+	switch(cmd) {
+	case FBIOGTYPE: {
+		struct fbtype __user *f = (struct fbtype __user *) arg;
+
+		if (put_user(type, &f->fb_type) ||
+		    __put_user(info->var.yres, &f->fb_height) ||
+		    __put_user(info->var.xres, &f->fb_width) ||
+		    __put_user(fb_depth, &f->fb_depth) ||
+		    __put_user(0, &f->fb_cmsize) ||
+		    __put_user(fb_size, &f->fb_cmsize))
+			return -EFAULT;
+		return 0;
+	}
+	case FBIOPUTCMAP_SPARC: {
+		struct fbcmap __user *c = (struct fbcmap __user *) arg;
+		struct fb_cmap cmap;
+		u16 red, green, blue;
+		u8 red8, green8, blue8;
+		unsigned char __user *ured;
+		unsigned char __user *ugreen;
+		unsigned char __user *ublue;
+		int index, count, i;
+
+		if (get_user(index, &c->index) ||
+		    __get_user(count, &c->count) ||
+		    __get_user(ured, &c->red) ||
+		    __get_user(ugreen, &c->green) ||
+		    __get_user(ublue, &c->blue))
+			return -EFAULT;
+
+		cmap.len = 1;
+		cmap.red = &red;
+		cmap.green = &green;
+		cmap.blue = &blue;
+		cmap.transp = NULL;
+		for (i = 0; i < count; i++) {
+			int err;
+
+			if (get_user(red8, &ured[i]) ||
+			    get_user(green8, &ugreen[i]) ||
+			    get_user(blue8, &ublue[i]))
+				return -EFAULT;
+
+			red = red8 << 8;
+			green = green8 << 8;
+			blue = blue8 << 8;
+
+			cmap.start = index + i;
+			err = fb_set_cmap(&cmap, info);
+			if (err)
+				return err;
+		}
+		return 0;
+	}
+	case FBIOGETCMAP_SPARC: {
+		struct fbcmap __user *c = (struct fbcmap __user *) arg;
+		unsigned char __user *ured;
+		unsigned char __user *ugreen;
+		unsigned char __user *ublue;
+		struct fb_cmap *cmap = &info->cmap;
+		int index, count, i;
+		u8 red, green, blue;
+
+		if (get_user(index, &c->index) ||
+		    __get_user(count, &c->count) ||
+		    __get_user(ured, &c->red) ||
+		    __get_user(ugreen, &c->green) ||
+		    __get_user(ublue, &c->blue))
+			return -EFAULT;
+
+		if (index + count > cmap->len)
+			return -EINVAL;
+
+		for (i = 0; i < count; i++) {
+			red = cmap->red[index + i] >> 8;
+			green = cmap->green[index + i] >> 8;
+			blue = cmap->blue[index + i] >> 8;
+			if (put_user(red, &ured[i]) ||
+			    put_user(green, &ugreen[i]) ||
+			    put_user(blue, &ublue[i]))
+				return -EFAULT;
+		}
+		return 0;
+	}
+	default:
+		return -EINVAL;
+	};
+}
+EXPORT_SYMBOL(sbusfb_ioctl_helper);
diff --git a/drivers/video/sbuslib.h b/drivers/video/sbuslib.h
new file mode 100644
index 0000000..a6aa33b
--- /dev/null
+++ b/drivers/video/sbuslib.h
@@ -0,0 +1,24 @@
+/* sbuslib.h: SBUS fb helper library interfaces */
+#ifndef _SBUSLIB_H
+#define _SBUSLIB_H
+
+struct sbus_mmap_map {
+	unsigned long voff;
+	unsigned long poff;
+	unsigned long size;
+};
+
+#define SBUS_MMAP_FBSIZE(n) (-n)
+#define SBUS_MMAP_EMPTY	0x80000000
+
+extern void sbusfb_fill_var(struct fb_var_screeninfo *var, int prom_node, int bpp);
+struct vm_area_struct;
+extern int sbusfb_mmap_helper(struct sbus_mmap_map *map,
+			      unsigned long physbase, unsigned long fbsize,
+			      unsigned long iospace,
+			      struct vm_area_struct *vma);
+int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg,
+			struct fb_info *info,
+			int type, int fb_depth, unsigned long fb_size);
+
+#endif /* _SBUSLIB_H */
diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c
new file mode 100644
index 0000000..8413907
--- /dev/null
+++ b/drivers/video/sgivwfb.c
@@ -0,0 +1,901 @@
+/*
+ *  linux/drivers/video/sgivwfb.c -- SGI DBE frame buffer device
+ *
+ *	Copyright (C) 1999 Silicon Graphics, Inc.
+ *      Jeffrey Newquist, newquist@engr.sgi.som
+ *
+ *  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/mm.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/mtrr.h>
+
+#define INCLUDE_TIMING_TABLE_DATA
+#define DBE_REG_BASE par->regs
+#include <video/sgivw.h>
+
+struct sgivw_par {
+	struct asregs *regs;
+	u32 cmap_fifo;
+	u_long timing_num;
+};
+
+#define FLATPANEL_SGI_1600SW	5
+
+/*
+ *  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
+ */
+
+/* set by arch/i386/kernel/setup.c */
+extern unsigned long sgivwfb_mem_phys;
+extern unsigned long sgivwfb_mem_size;
+
+static int ypan = 0;
+static int ywrap = 0;
+
+static int flatpanel_id = -1;
+
+static struct fb_fix_screeninfo sgivwfb_fix __initdata = {
+	.id		= "SGI Vis WS FB",
+	.type		= FB_TYPE_PACKED_PIXELS,
+        .visual		= FB_VISUAL_PSEUDOCOLOR,
+	.mmio_start	= DBE_REG_PHYS,
+	.mmio_len	= DBE_REG_SIZE,
+        .accel		= FB_ACCEL_NONE,
+	.line_length	= 640,
+};
+
+static struct fb_var_screeninfo sgivwfb_var __initdata = {
+	/* 640x480, 8 bpp */
+	.xres		= 640,
+	.yres		= 480,
+	.xres_virtual	= 640,
+	.yres_virtual	= 480,
+	.bits_per_pixel	= 8,
+	.red		= { 0, 8, 0 },
+	.green		= { 0, 8, 0 },
+	.blue		= { 0, 8, 0 },
+	.height		= -1,
+	.width		= -1,
+	.pixclock	= 20000,
+	.left_margin	= 64,
+	.right_margin	= 64,
+	.upper_margin	= 32,
+	.lower_margin	= 32,
+	.hsync_len	= 64,
+	.vsync_len	= 2,
+	.vmode		= FB_VMODE_NONINTERLACED
+};
+
+static struct fb_var_screeninfo sgivwfb_var1600sw __initdata = {
+	/* 1600x1024, 8 bpp */
+	.xres		= 1600,
+	.yres		= 1024,
+	.xres_virtual	= 1600,
+	.yres_virtual	= 1024,
+	.bits_per_pixel	= 8,
+	.red		= { 0, 8, 0 },
+	.green		= { 0, 8, 0 },
+	.blue		= { 0, 8, 0 },
+	.height		= -1,
+	.width		= -1,
+	.pixclock	= 9353,
+	.left_margin	= 20,
+	.right_margin	= 30,
+	.upper_margin	= 37,
+	.lower_margin	= 3,
+	.hsync_len	= 20,
+	.vsync_len	= 3,
+	.vmode		= FB_VMODE_NONINTERLACED
+};
+
+/*
+ *  Interface used by the world
+ */
+int sgivwfb_init(void);
+
+static int sgivwfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info);
+static int sgivwfb_set_par(struct fb_info *info);
+static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green,
+			     u_int blue, u_int transp,
+			     struct fb_info *info);
+static int sgivwfb_mmap(struct fb_info *info, struct file *file,
+			struct vm_area_struct *vma);
+
+static struct fb_ops sgivwfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= sgivwfb_check_var,
+	.fb_set_par	= sgivwfb_set_par,
+	.fb_setcolreg	= sgivwfb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+	.fb_mmap	= sgivwfb_mmap,
+};
+
+/*
+ *  Internal routines
+ */
+static unsigned long bytes_per_pixel(int bpp)
+{
+	switch (bpp) {
+		case 8:
+			return 1;
+		case 16:
+			return 2;
+		case 32:
+			return 4;
+		default:
+			printk(KERN_INFO "sgivwfb: unsupported bpp %d\n", bpp);
+			return 0;
+	}
+}
+
+static unsigned long get_line_length(int xres_virtual, int bpp)
+{
+	return (xres_virtual * bytes_per_pixel(bpp));
+}
+
+/*
+ * Function:	dbe_TurnOffDma
+ * Parameters:	(None)
+ * Description:	This should turn off the monitor and dbe.  This is used
+ *              when switching between the serial console and the graphics
+ *              console.
+ */
+
+static void dbe_TurnOffDma(struct sgivw_par *par)
+{
+	unsigned int readVal;
+	int i;
+
+	// Check to see if things are already turned off:
+	// 1) Check to see if dbe is not using the internal dotclock.
+	// 2) Check to see if the xy counter in dbe is already off.
+
+	DBE_GETREG(ctrlstat, readVal);
+	if (GET_DBE_FIELD(CTRLSTAT, PCLKSEL, readVal) < 2)
+		return;
+
+	DBE_GETREG(vt_xy, readVal);
+	if (GET_DBE_FIELD(VT_XY, VT_FREEZE, readVal) == 1)
+		return;
+
+	// Otherwise, turn off dbe
+
+	DBE_GETREG(ovr_control, readVal);
+	SET_DBE_FIELD(OVR_CONTROL, OVR_DMA_ENABLE, readVal, 0);
+	DBE_SETREG(ovr_control, readVal);
+	udelay(1000);
+	DBE_GETREG(frm_control, readVal);
+	SET_DBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, readVal, 0);
+	DBE_SETREG(frm_control, readVal);
+	udelay(1000);
+	DBE_GETREG(did_control, readVal);
+	SET_DBE_FIELD(DID_CONTROL, DID_DMA_ENABLE, readVal, 0);
+	DBE_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.
+
+	for (i = 0; i < 10000; i++) {
+		DBE_GETREG(frm_inhwctrl, readVal);
+		if (GET_DBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, readVal) ==
+		    0)
+			udelay(10);
+		else {
+			DBE_GETREG(ovr_inhwctrl, readVal);
+			if (GET_DBE_FIELD
+			    (OVR_INHWCTRL, OVR_DMA_ENABLE, readVal) == 0)
+				udelay(10);
+			else {
+				DBE_GETREG(did_inhwctrl, readVal);
+				if (GET_DBE_FIELD
+				    (DID_INHWCTRL, DID_DMA_ENABLE,
+				     readVal) == 0)
+					udelay(10);
+				else
+					break;
+			}
+		}
+	}
+}
+
+/*
+ *  Set the User Defined Part of the Display. Again if par use it to get
+ *  real video mode.
+ */
+static int sgivwfb_check_var(struct fb_var_screeninfo *var, 
+			     struct fb_info *info)
+{
+	struct sgivw_par *par = (struct sgivw_par *)info->par;
+	struct dbe_timing_info *timing;
+	u_long line_length;
+	u_long min_mode;
+	int req_dot;
+	int test_mode;
+
+	/*
+	 *  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 = info->var.xoffset;
+		var->yoffset = info->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;
+
+	var->grayscale = 0;	/* No grayscale for now */
+
+	/* determine valid resolution and timing */
+	for (min_mode = 0; min_mode < DBE_VT_SIZE; min_mode++) {
+		if (dbeVTimings[min_mode].width >= var->xres &&
+		    dbeVTimings[min_mode].height >= var->yres)
+			break;
+	}
+
+	if (min_mode == DBE_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 = PICOS2KHZ(var->pixclock);
+	printk(KERN_INFO "sgivwfb: requested pixclock=%d ps (%d KHz)\n",
+	       var->pixclock, req_dot);
+	test_mode = min_mode;
+	while (dbeVTimings[min_mode].width == dbeVTimings[test_mode].width) {
+		if (dbeVTimings[test_mode].cfreq + 3000 > req_dot)
+			break;
+		test_mode++;
+	}
+	if (dbeVTimings[min_mode].width != dbeVTimings[test_mode].width)
+		test_mode--;
+	min_mode = test_mode;
+	timing = &dbeVTimings[min_mode];
+	printk(KERN_INFO "sgivwfb: 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 > sgivwfb_mem_size)
+		return -ENOMEM;	/* Virtual resolution to high */
+
+	info->fix.line_length = line_length;
+
+	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 = KHZ2PICOS(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;
+
+	/* Ouch. This breaks the rules but timing_num is only important if you
+	* change a video mode */
+	par->timing_num = min_mode;
+
+	printk(KERN_INFO "sgivwfb: 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);
+	return 0;
+}
+
+/*
+ *  Setup flatpanel related registers.
+ */
+static void sgivwfb_setup_flatpanel(struct sgivw_par *par, struct dbe_timing_info *currentTiming)
+{
+	int fp_wid, fp_hgt, fp_vbs, fp_vbe;
+	u32 outputVal = 0;
+
+	SET_DBE_FIELD(VT_FLAGS, HDRV_INVERT, outputVal, 
+		(currentTiming->flags & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1);
+	SET_DBE_FIELD(VT_FLAGS, VDRV_INVERT, outputVal, 
+		(currentTiming->flags & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1);
+	DBE_SETREG(vt_flags, outputVal);
+
+	/* Turn on the flat panel */
+	switch (flatpanel_id) {
+		case FLATPANEL_SGI_1600SW:
+			fp_wid = 1600;
+			fp_hgt = 1024;
+			fp_vbs = 0;
+			fp_vbe = 1600;
+			currentTiming->pll_m = 4;
+			currentTiming->pll_n = 1;
+			currentTiming->pll_p = 0;
+			break;
+		default:
+      			fp_wid = fp_hgt = fp_vbs = fp_vbe = 0xfff;
+  	}
+
+	outputVal = 0;
+	SET_DBE_FIELD(FP_DE, FP_DE_ON, outputVal, fp_vbs);
+	SET_DBE_FIELD(FP_DE, FP_DE_OFF, outputVal, fp_vbe);
+	DBE_SETREG(fp_de, outputVal);
+	outputVal = 0;
+	SET_DBE_FIELD(FP_HDRV, FP_HDRV_OFF, outputVal, fp_wid);
+	DBE_SETREG(fp_hdrv, outputVal);
+	outputVal = 0;
+	SET_DBE_FIELD(FP_VDRV, FP_VDRV_ON, outputVal, 1);
+	SET_DBE_FIELD(FP_VDRV, FP_VDRV_OFF, outputVal, fp_hgt + 1);
+	DBE_SETREG(fp_vdrv, outputVal);
+}
+
+/*
+ *  Set the hardware according to 'par'.
+ */
+static int sgivwfb_set_par(struct fb_info *info)
+{
+	struct sgivw_par *par = info->par;
+	int i, j, htmp, temp;
+	u32 readVal, outputVal;
+	int wholeTilesX, maxPixelsPerTileX;
+	int frmWrite1, frmWrite2, frmWrite3b;
+	struct dbe_timing_info *currentTiming; /* Current Video Timing */
+	int xpmax, ypmax;	// Monitor resolution
+	int bytesPerPixel;	// Bytes per pixel
+
+	currentTiming = &dbeVTimings[par->timing_num];
+	bytesPerPixel = bytes_per_pixel(info->var.bits_per_pixel);
+	xpmax = currentTiming->width;
+	ypmax = currentTiming->height;
+
+	/* dbe_InitGraphicsBase(); */
+	/* Turn on dotclock PLL */
+	DBE_SETREG(ctrlstat, 0x20000000);
+
+	dbe_TurnOffDma(par);
+
+	/* dbe_CalculateScreenParams(); */
+	maxPixelsPerTileX = 512 / bytesPerPixel;
+	wholeTilesX = xpmax / maxPixelsPerTileX;
+	if (wholeTilesX * maxPixelsPerTileX < xpmax)
+		wholeTilesX++;
+
+	printk(KERN_DEBUG "sgivwfb: pixPerTile=%d wholeTilesX=%d\n",
+	       maxPixelsPerTileX, wholeTilesX);
+
+	/* dbe_InitGammaMap(); */
+	udelay(10);
+
+	for (i = 0; i < 256; i++) {
+		DBE_ISETREG(gmap, i, (i << 24) | (i << 16) | (i << 8));
+	}
+
+	/* dbe_TurnOn(); */
+	DBE_GETREG(vt_xy, readVal);
+	if (GET_DBE_FIELD(VT_XY, VT_FREEZE, readVal) == 1) {
+		DBE_SETREG(vt_xy, 0x00000000);
+		udelay(1);
+	} else
+		dbe_TurnOffDma(par);
+
+	/* dbe_Initdbe(); */
+	for (i = 0; i < 256; i++) {
+		for (j = 0; j < 100; j++) {
+			DBE_GETREG(cm_fifo, readVal);
+			if (readVal != 0x00000000)
+				break;
+			else
+				udelay(10);
+		}
+
+		// DBE_ISETREG(cmap, i, 0x00000000);
+		DBE_ISETREG(cmap, i, (i << 8) | (i << 16) | (i << 24));
+	}
+
+	/* dbe_InitFramebuffer(); */
+	frmWrite1 = 0;
+	SET_DBE_FIELD(FRM_SIZE_TILE, FRM_WIDTH_TILE, frmWrite1,
+		      wholeTilesX);
+	SET_DBE_FIELD(FRM_SIZE_TILE, FRM_RHS, frmWrite1, 0);
+
+	switch (bytesPerPixel) {
+	case 1:
+		SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1,
+			      DBE_FRM_DEPTH_8);
+		break;
+	case 2:
+		SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1,
+			      DBE_FRM_DEPTH_16);
+		break;
+	case 4:
+		SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1,
+			      DBE_FRM_DEPTH_32);
+		break;
+	}
+
+	frmWrite2 = 0;
+	SET_DBE_FIELD(FRM_SIZE_PIXEL, FB_HEIGHT_PIX, frmWrite2, ypmax);
+
+	// Tell dbe about the framebuffer location and type
+	// XXX What format is the FRM_TILE_PTR??  64K aligned address?
+	frmWrite3b = 0;
+	SET_DBE_FIELD(FRM_CONTROL, FRM_TILE_PTR, frmWrite3b,
+		      sgivwfb_mem_phys >> 9);
+	SET_DBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, frmWrite3b, 1);
+	SET_DBE_FIELD(FRM_CONTROL, FRM_LINEAR, frmWrite3b, 1);
+
+	/* Initialize DIDs */
+
+	outputVal = 0;
+	switch (bytesPerPixel) {
+	case 1:
+		SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_I8);
+		break;
+	case 2:
+		SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_RGBA5);
+		break;
+	case 4:
+		SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_RGB8);
+		break;
+	}
+	SET_DBE_FIELD(WID, BUF, outputVal, DBE_BMODE_BOTH);
+
+	for (i = 0; i < 32; i++) {
+		DBE_ISETREG(mode_regs, i, outputVal);
+	}
+
+	/* dbe_InitTiming(); */
+	DBE_SETREG(vt_intr01, 0xffffffff);
+	DBE_SETREG(vt_intr23, 0xffffffff);
+
+	DBE_GETREG(dotclock, readVal);
+	DBE_SETREG(dotclock, readVal & 0xffff);
+
+	DBE_SETREG(vt_xymax, 0x00000000);
+	outputVal = 0;
+	SET_DBE_FIELD(VT_VSYNC, VT_VSYNC_ON, outputVal,
+		      currentTiming->vsync_start);
+	SET_DBE_FIELD(VT_VSYNC, VT_VSYNC_OFF, outputVal,
+		      currentTiming->vsync_end);
+	DBE_SETREG(vt_vsync, outputVal);
+	outputVal = 0;
+	SET_DBE_FIELD(VT_HSYNC, VT_HSYNC_ON, outputVal,
+		      currentTiming->hsync_start);
+	SET_DBE_FIELD(VT_HSYNC, VT_HSYNC_OFF, outputVal,
+		      currentTiming->hsync_end);
+	DBE_SETREG(vt_hsync, outputVal);
+	outputVal = 0;
+	SET_DBE_FIELD(VT_VBLANK, VT_VBLANK_ON, outputVal,
+		      currentTiming->vblank_start);
+	SET_DBE_FIELD(VT_VBLANK, VT_VBLANK_OFF, outputVal,
+		      currentTiming->vblank_end);
+	DBE_SETREG(vt_vblank, outputVal);
+	outputVal = 0;
+	SET_DBE_FIELD(VT_HBLANK, VT_HBLANK_ON, outputVal,
+		      currentTiming->hblank_start);
+	SET_DBE_FIELD(VT_HBLANK, VT_HBLANK_OFF, outputVal,
+		      currentTiming->hblank_end - 3);
+	DBE_SETREG(vt_hblank, outputVal);
+	outputVal = 0;
+	SET_DBE_FIELD(VT_VCMAP, VT_VCMAP_ON, outputVal,
+		      currentTiming->vblank_start);
+	SET_DBE_FIELD(VT_VCMAP, VT_VCMAP_OFF, outputVal,
+		      currentTiming->vblank_end);
+	DBE_SETREG(vt_vcmap, outputVal);
+	outputVal = 0;
+	SET_DBE_FIELD(VT_HCMAP, VT_HCMAP_ON, outputVal,
+		      currentTiming->hblank_start);
+	SET_DBE_FIELD(VT_HCMAP, VT_HCMAP_OFF, outputVal,
+		      currentTiming->hblank_end - 3);
+	DBE_SETREG(vt_hcmap, outputVal);
+
+	if (flatpanel_id != -1)
+		sgivwfb_setup_flatpanel(par, currentTiming);
+
+	outputVal = 0;
+	temp = currentTiming->vblank_start - currentTiming->vblank_end - 1;
+	if (temp > 0)
+		temp = -temp;
+
+	SET_DBE_FIELD(DID_START_XY, DID_STARTY, outputVal, (u32) temp);
+	if (currentTiming->hblank_end >= 20)
+		SET_DBE_FIELD(DID_START_XY, DID_STARTX, outputVal,
+			      currentTiming->hblank_end - 20);
+	else
+		SET_DBE_FIELD(DID_START_XY, DID_STARTX, outputVal,
+			      currentTiming->htotal - (20 -
+						       currentTiming->
+						       hblank_end));
+	DBE_SETREG(did_start_xy, outputVal);
+
+	outputVal = 0;
+	SET_DBE_FIELD(CRS_START_XY, CRS_STARTY, outputVal,
+		      (u32) (temp + 1));
+	if (currentTiming->hblank_end >= DBE_CRS_MAGIC)
+		SET_DBE_FIELD(CRS_START_XY, CRS_STARTX, outputVal,
+			      currentTiming->hblank_end - DBE_CRS_MAGIC);
+	else
+		SET_DBE_FIELD(CRS_START_XY, CRS_STARTX, outputVal,
+			      currentTiming->htotal - (DBE_CRS_MAGIC -
+						       currentTiming->
+						       hblank_end));
+	DBE_SETREG(crs_start_xy, outputVal);
+
+	outputVal = 0;
+	SET_DBE_FIELD(VC_START_XY, VC_STARTY, outputVal, (u32) temp);
+	SET_DBE_FIELD(VC_START_XY, VC_STARTX, outputVal,
+		      currentTiming->hblank_end - 4);
+	DBE_SETREG(vc_start_xy, outputVal);
+
+	DBE_SETREG(frm_size_tile, frmWrite1);
+	DBE_SETREG(frm_size_pixel, frmWrite2);
+
+	outputVal = 0;
+	SET_DBE_FIELD(DOTCLK, M, outputVal, currentTiming->pll_m - 1);
+	SET_DBE_FIELD(DOTCLK, N, outputVal, currentTiming->pll_n - 1);
+	SET_DBE_FIELD(DOTCLK, P, outputVal, currentTiming->pll_p);
+	SET_DBE_FIELD(DOTCLK, RUN, outputVal, 1);
+	DBE_SETREG(dotclock, outputVal);
+
+	udelay(11 * 1000);
+
+	DBE_SETREG(vt_vpixen, 0xffffff);
+	DBE_SETREG(vt_hpixen, 0xffffff);
+
+	outputVal = 0;
+	SET_DBE_FIELD(VT_XYMAX, VT_MAXX, outputVal, currentTiming->htotal);
+	SET_DBE_FIELD(VT_XYMAX, VT_MAXY, outputVal, currentTiming->vtotal);
+	DBE_SETREG(vt_xymax, outputVal);
+
+	outputVal = frmWrite1;
+	SET_DBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, outputVal, 1);
+	DBE_SETREG(frm_size_tile, outputVal);
+	DBE_SETREG(frm_size_tile, frmWrite1);
+
+	outputVal = 0;
+	SET_DBE_FIELD(OVR_WIDTH_TILE, OVR_FIFO_RESET, outputVal, 1);
+	DBE_SETREG(ovr_width_tile, outputVal);
+	DBE_SETREG(ovr_width_tile, 0);
+
+	DBE_SETREG(frm_control, frmWrite3b);
+	DBE_SETREG(did_control, 0);
+
+	// Wait for dbe to take frame settings
+	for (i = 0; i < 100000; i++) {
+		DBE_GETREG(frm_inhwctrl, readVal);
+		if (GET_DBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, readVal) !=
+		    0)
+			break;
+		else
+			udelay(1);
+	}
+
+	if (i == 100000)
+		printk(KERN_INFO
+		       "sgivwfb: 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_DBE_FIELD(VT_HPIXEN, VT_HPIXEN_ON, outputVal, htmp);
+	SET_DBE_FIELD(VT_HPIXEN, VT_HPIXEN_OFF, outputVal,
+		      ((htmp + currentTiming->width -
+			2) % currentTiming->htotal));
+	DBE_SETREG(vt_hpixen, outputVal);
+
+	outputVal = 0;
+	SET_DBE_FIELD(VT_VPIXEN, VT_VPIXEN_OFF, outputVal,
+		      currentTiming->vblank_start);
+	SET_DBE_FIELD(VT_VPIXEN, VT_VPIXEN_ON, outputVal,
+		      currentTiming->vblank_end);
+	DBE_SETREG(vt_vpixen, outputVal);
+
+	// Turn off mouse cursor
+	par->regs->crs_ctl = 0;
+
+	// XXX What's this section for??
+	DBE_GETREG(ctrlstat, readVal);
+	readVal &= 0x02000000;
+
+	if (readVal != 0) {
+		DBE_SETREG(ctrlstat, 0x30000000);
+	}
+	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 sgivwfb_setcolreg(u_int regno, u_int red, u_int green,
+			     u_int blue, u_int transp,
+			     struct fb_info *info)
+{
+	struct sgivw_par *par = (struct sgivw_par *) info->par;
+
+	if (regno > 255)
+		return 1;
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	/* wait for the color map FIFO to have a free entry */
+	while (par->cmap_fifo == 0)
+		par->cmap_fifo = par->regs->cm_fifo;
+
+	par->regs->cmap[regno] = (red << 24) | (green << 16) | (blue << 8);
+	par->cmap_fifo--;	/* assume FIFO is filling up */
+	return 0;
+}
+
+static int sgivwfb_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 > sgivwfb_mem_size)
+		return -EINVAL;
+	offset += sgivwfb_mem_phys;
+	pgprot_val(vma->vm_page_prot) =
+	    pgprot_val(vma->vm_page_prot) | _PAGE_PCD;
+	vma->vm_flags |= VM_IO;
+	if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT,
+						size, vma->vm_page_prot))
+		return -EAGAIN;
+	vma->vm_file = file;
+	printk(KERN_DEBUG "sgivwfb: mmap framebuffer P(%lx)->V(%lx)\n",
+	       offset, vma->vm_start);
+	return 0;
+}
+
+int __init sgivwfb_setup(char *options)
+{
+	char *this_opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!strncmp(this_opt, "monitor:", 8)) {
+			if (!strncmp(this_opt + 8, "crt", 3))
+				flatpanel_id = -1;
+			else if (!strncmp(this_opt + 8, "1600sw", 6))
+				flatpanel_id = FLATPANEL_SGI_1600SW;
+		}
+	}
+	return 0;
+}
+
+/*
+ *  Initialisation
+ */
+static void sgivwfb_release(struct device *device)
+{
+}
+
+static int __init sgivwfb_probe(struct device *device)
+{
+	struct platform_device *dev = to_platform_device(device);
+	struct sgivw_par *par;
+	struct fb_info *info;
+	char *monitor;
+
+	info = framebuffer_alloc(sizeof(struct sgivw_par) + sizeof(u32) * 256, &dev->dev);
+	if (!info)
+		return -ENOMEM;
+	par = info->par;
+
+	if (!request_mem_region(DBE_REG_PHYS, DBE_REG_SIZE, "sgivwfb")) {
+		printk(KERN_ERR "sgivwfb: couldn't reserve mmio region\n");
+		framebuffer_release(info);
+		return -EBUSY;
+	}
+
+	par->regs = (struct asregs *) ioremap_nocache(DBE_REG_PHYS, DBE_REG_SIZE);
+	if (!par->regs) {
+		printk(KERN_ERR "sgivwfb: couldn't ioremap registers\n");
+		goto fail_ioremap_regs;
+	}
+
+	mtrr_add(sgivwfb_mem_phys, sgivwfb_mem_size, MTRR_TYPE_WRCOMB, 1);
+
+	sgivwfb_fix.smem_start = sgivwfb_mem_phys;
+	sgivwfb_fix.smem_len = sgivwfb_mem_size;
+	sgivwfb_fix.ywrapstep = ywrap;
+	sgivwfb_fix.ypanstep = ypan;
+
+	info->fix = sgivwfb_fix;
+
+	switch (flatpanel_id) {
+		case FLATPANEL_SGI_1600SW:
+			info->var = sgivwfb_var1600sw;
+			monitor = "SGI 1600SW flatpanel";
+			break;
+		default:
+			info->var = sgivwfb_var;
+			monitor = "CRT";
+	}
+
+	printk(KERN_INFO "sgivwfb: %s monitor selected\n", monitor);
+
+	info->fbops = &sgivwfb_ops;
+	info->pseudo_palette = (void *) (par + 1);
+	info->flags = FBINFO_DEFAULT;
+
+	info->screen_base = ioremap_nocache((unsigned long) sgivwfb_mem_phys, sgivwfb_mem_size);
+	if (!info->screen_base) {
+		printk(KERN_ERR "sgivwfb: couldn't ioremap screen_base\n");
+		goto fail_ioremap_fbmem;
+	}
+
+	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
+		goto fail_color_map;
+
+	if (register_framebuffer(info) < 0) {
+		printk(KERN_ERR "sgivwfb: couldn't register framebuffer\n");
+		goto fail_register_framebuffer;
+	}
+
+	dev_set_drvdata(&dev->dev, info);
+
+	printk(KERN_INFO "fb%d: SGI DBE frame buffer device, using %ldK of video memory at %#lx\n",      
+		info->node, sgivwfb_mem_size >> 10, sgivwfb_mem_phys);
+	return 0;
+
+fail_register_framebuffer:
+	fb_dealloc_cmap(&info->cmap);
+fail_color_map:
+	iounmap((char *) info->screen_base);
+fail_ioremap_fbmem:
+	iounmap(par->regs);
+fail_ioremap_regs:
+	release_mem_region(DBE_REG_PHYS, DBE_REG_SIZE);
+	framebuffer_release(info);
+	return -ENXIO;
+}
+
+static int sgivwfb_remove(struct device *device)
+{
+	struct fb_info *info = dev_get_drvdata(device);
+
+	if (info) {
+		struct sgivw_par *par = info->par;
+
+		unregister_framebuffer(info);
+		dbe_TurnOffDma(par);
+		iounmap(par->regs);
+		iounmap(info->screen_base);
+		release_mem_region(DBE_REG_PHYS, DBE_REG_SIZE);
+	}
+	return 0;
+}
+
+static struct device_driver sgivwfb_driver = {
+	.name	= "sgivwfb",
+	.bus	= &platform_bus_type,
+	.probe	= sgivwfb_probe,
+	.remove	= sgivwfb_remove,
+};
+
+static struct platform_device sgivwfb_device = {
+	.name	= "sgivwfb",
+	.id	= 0,
+	.dev	= {
+		.release = sgivwfb_release,
+	}
+};
+
+int __init sgivwfb_init(void)
+{
+	int ret;
+
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("sgivwfb", &option))
+		return -ENODEV;
+	sgivwfb_setup(option);
+#endif
+	ret = driver_register(&sgivwfb_driver);
+	if (!ret) {
+		ret = platform_device_register(&sgivwfb_device);
+		if (ret)
+			driver_unregister(&sgivwfb_driver);
+	}
+	return ret;
+}
+
+module_init(sgivwfb_init);
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+
+static void __exit sgivwfb_exit(void)
+{
+	platform_device_unregister(&sgivwfb_device);
+	driver_unregister(&sgivwfb_driver);
+}
+
+module_exit(sgivwfb_exit);
+
+#endif				/* MODULE */
diff --git a/drivers/video/sis/300vtbl.h b/drivers/video/sis/300vtbl.h
new file mode 100644
index 0000000..b6d5c71
--- /dev/null
+++ b/drivers/video/sis/300vtbl.h
@@ -0,0 +1,1965 @@
+/* $XFree86$ */
+/* $XdotOrg$ */
+/*
+ * Register settings for SiS 300 series
+ *
+ * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, the following license terms
+ * apply:
+ *
+ * * This program is free software; you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License as published by
+ * * the Free Software Foundation; either version 2 of the named License,
+ * * or any later version.
+ * *
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details.
+ * *
+ * * You should have received a copy of the GNU General Public License
+ * * along with this program; if not, write to the Free Software
+ * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * * Redistribution and use in source and binary forms, with or without
+ * * modification, are permitted provided that the following conditions
+ * * are met:
+ * * 1) Redistributions of source code must retain the above copyright
+ * *    notice, this list of conditions and the following disclaimer.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * *    notice, this list of conditions and the following disclaimer in the
+ * *    documentation and/or other materials provided with the distribution.
+ * * 3) The name of the author may not be used to endorse or promote products
+ * *    derived from this software without specific prior written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ */
+
+static const SiS_StStruct  SiS300_SModeIDTable[] =
+{
+	{0x01,0x9208,0x01,0x00,0x00,0x00,0x00,0x00, 0},
+	{0x01,0x1210,0x14,0x01,0x01,0x00,0x00,0x00, 0},
+	{0x01,0x1010,0x17,0x02,0x02,0x00,0x00,0x00, 0},
+	{0x03,0x8208,0x03,0x00,0x00,0x00,0x00,0x00, 0},
+	{0x03,0x0210,0x16,0x01,0x01,0x00,0x00,0x00, 0},
+	{0x03,0x0010,0x18,0x02,0x02,0x00,0x00,0x00, 0},
+	{0x05,0x9209,0x05,0x00,0x00,0x00,0x00,0x00, 0},
+	{0x06,0x8209,0x06,0x00,0x00,0x00,0x00,0x00, 0},
+	{0x07,0x0000,0x07,0x03,0x03,0x00,0x00,0x00, 0},
+	{0x07,0x0000,0x19,0x02,0x02,0x00,0x00,0x00, 0},
+	{0x0d,0x920a,0x0d,0x00,0x00,0x00,0x00,0x00, 0},
+	{0x0e,0x820a,0x0e,0x00,0x00,0x00,0x00,0x00, 0},
+	{0x0f,0x0202,0x11,0x01,0x01,0x00,0x00,0x00, 0},
+	{0x10,0x0212,0x12,0x01,0x01,0x00,0x00,0x00, 0},
+	{0x11,0x0212,0x1a,0x04,0x04,0x00,0x00,0x00, 0},
+	{0x12,0x0212,0x1b,0x04,0x04,0x00,0x00,0x00, 0},
+	{0x13,0x021b,0x1c,0x00,0x00,0x00,0x00,0x00, 0},
+	{0x12,0x0010,0x18,0x02,0x02,0x00,0x00,0x00, 0},
+	{0x12,0x0210,0x18,0x01,0x01,0x00,0x00,0x00, 0},
+	{0xff,     0,   0,   0,   0,   0,   0,   0, 0}
+};
+
+static const SiS_ExtStruct  SiS300_EModeIDTable[] =
+{
+	{0x6a,0x2212,0x0102,SIS_RI_800x600,  0x00,0x00,0x00,0x00,0x00,-1},  /* 800x600x? */
+	{0x2e,0x0a1b,0x0101,SIS_RI_640x480,  0x00,0x00,0x00,0x00,0x08,-1},
+	{0x2f,0x021b,0x0100,SIS_RI_640x400,  0x00,0x00,0x00,0x00,0x10,-1},  /* 640x400x8 */
+	{0x30,0x2a1b,0x0103,SIS_RI_800x600,  0x00,0x00,0x00,0x00,0x00,-1},
+	{0x31,0x4a1b,0x0000,SIS_RI_720x480,  0x00,0x00,0x00,0x00,0x11,-1},  /* 720x480x8 */
+	{0x32,0x6a1b,0x0000,SIS_RI_720x576,  0x00,0x00,0x00,0x00,0x12,-1},  /* 720x576x8 */
+	{0x33,0x4a1d,0x0000,SIS_RI_720x480,  0x00,0x00,0x00,0x00,0x11,-1},  /* 720x480x16 */
+	{0x34,0x6a1d,0x0000,SIS_RI_720x576,  0x00,0x00,0x00,0x00,0x12,-1},  /* 720x576x16 */
+	{0x35,0x4a1f,0x0000,SIS_RI_720x480,  0x00,0x00,0x00,0x00,0x11,-1},  /* 720x480x32 */
+	{0x36,0x6a1f,0x0000,SIS_RI_720x576,  0x00,0x00,0x00,0x00,0x12,-1},  /* 720x576x32 */
+	{0x37,0x0212,0x0104,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13,-1},  /* 1024x768x? */
+	{0x38,0x0a1b,0x0105,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13,-1},  /* 1024x768x8 */
+	{0x3a,0x0e3b,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a,-1},  /* 1280x1024x8 */
+	{0x3c,0x063b,0x0130,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e,-1},
+	{0x3d,0x067d,0x0131,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e,-1},
+	{0x40,0x921c,0x010d,SIS_RI_320x200,  0x00,0x00,0x00,0x00,0x23,-1},  /* 320x200x15 */
+	{0x41,0x921d,0x010e,SIS_RI_320x200,  0x00,0x00,0x00,0x00,0x23,-1},  /* 320x200x16 */
+	{0x43,0x0a1c,0x0110,SIS_RI_640x480,  0x00,0x00,0x00,0x00,0x08,-1},
+	{0x44,0x0a1d,0x0111,SIS_RI_640x480,  0x00,0x00,0x00,0x00,0x08,-1},
+	{0x46,0x2a1c,0x0113,SIS_RI_800x600,  0x00,0x00,0x00,0x00,0x00,-1},  /* 800x600x15 */
+	{0x47,0x2a1d,0x0114,SIS_RI_800x600,  0x00,0x00,0x00,0x00,0x00,-1},  /* 800x600x16 */
+	{0x49,0x0a3c,0x0116,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13,-1},
+	{0x4a,0x0a3d,0x0117,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13,-1},
+	{0x4c,0x0e7c,0x0119,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a,-1},
+	{0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a,-1},
+	{0x50,0x921b,0x0132,SIS_RI_320x240,  0x00,0x00,0x00,0x00,0x24,-1},  /* 320x240x8  */
+	{0x51,0xb21b,0x0133,SIS_RI_400x300,  0x00,0x00,0x00,0x00,0x25,-1},  /* 400x300x8  */
+	{0x52,0x921b,0x0134,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x26,-1},  /* 512x384x8  */
+	{0x56,0x921d,0x0135,SIS_RI_320x240,  0x00,0x00,0x00,0x00,0x24,-1},  /* 320x240x16 */
+	{0x57,0xb21d,0x0136,SIS_RI_400x300,  0x00,0x00,0x00,0x00,0x25,-1},  /* 400x300x16 */
+	{0x58,0x921d,0x0137,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x26,-1},  /* 512x384x16 */
+	{0x59,0x921b,0x0138,SIS_RI_320x200,  0x00,0x00,0x00,0x00,0x23,-1},  /* 320x200x8  */
+	{0x5c,0x921f,0x0000,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x26,-1},  /* 512x384x32 */
+	{0x5d,0x021d,0x0139,SIS_RI_640x400,  0x00,0x00,0x00,0x00,0x10,-1},  /* 640x400x16 */
+ 	{0x5e,0x021f,0x0000,SIS_RI_640x400,  0x00,0x00,0x00,0x00,0x10,-1},  /* 640x400x32 */
+	{0x62,0x0a3f,0x013a,SIS_RI_640x480,  0x00,0x00,0x00,0x00,0x08,-1},
+	{0x63,0x2a3f,0x013b,SIS_RI_800x600,  0x00,0x00,0x00,0x00,0x00,-1},  /* 800x600x32 */
+	{0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13,-1},
+	{0x65,0x0eff,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a,-1},
+	{0x66,0x06ff,0x013e,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e,-1},
+	{0x68,0x067b,0x013f,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x27,-1},
+	{0x69,0x06fd,0x0140,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x27,-1},
+	{0x6b,0x07ff,0x0000,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x27,-1},
+	{0x6c,0x067b,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x28,-1},  /* 2048x1536x8 - not in BIOS! */
+	{0x6d,0x06fd,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x28,-1},  /* 2048x1536x16 - not in BIOS! */
+	{0x70,0x6a1b,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x00,0x2d,-1},  /* 800x480x8 */
+	{0x71,0x4a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x30,-1},  /* 1024x576x8 */
+	{0x74,0x4a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x30,-1},  /* 1024x576x16 */
+	{0x75,0x0e3d,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x33,-1},  /* 1280x720x16 */
+	{0x76,0x6a1f,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x00,0x2d,-1},  /* 800x480x32 */
+	{0x77,0x4a3f,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x30,-1},  /* 1024x576x32 */
+	{0x78,0x0eff,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x33,-1},  /* 1280x720x32 */
+	{0x79,0x0e3b,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x33,-1},  /* 1280x720x8 */
+	{0x7a,0x6a1d,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x00,0x2d,-1},  /* 800x480x16 */
+	{0x7c,0x0a3b,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x29,-1},  /* 1280x960x8 */
+	{0x7d,0x0a7d,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x29,-1},  /* 1280x960x16 */
+	{0x7e,0x0aff,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x29,-1},  /* 1280x960x32 */
+	{0x20,0x4a1b,0x0000,SIS_RI_1024x600, 0x00,0x00,0x00,0x00,0x2b,-1},  /* 1024x600 */
+	{0x21,0x4a3d,0x0000,SIS_RI_1024x600, 0x00,0x00,0x00,0x00,0x2b,-1},
+	{0x22,0x4a7f,0x0000,SIS_RI_1024x600, 0x00,0x00,0x00,0x00,0x2b,-1},
+	{0x23,0x4a1b,0x0000,SIS_RI_1152x768, 0x00,0x00,0x00,0x00,0x2c,-1},  /* 1152x768 */
+	{0x24,0x4a3d,0x0000,SIS_RI_1152x768, 0x00,0x00,0x00,0x00,0x2c,-1},
+	{0x25,0x4a7f,0x0000,SIS_RI_1152x768, 0x00,0x00,0x00,0x00,0x2c,-1},
+	{0x29,0x4e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x36,-1},  /* 1152x864 */
+	{0x2a,0x4e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x36,-1},
+	{0x2b,0x4e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x36,-1},
+	{0x39,0x6a1b,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x39,-1},  /* 848x480 */
+	{0x3b,0x6a3d,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x39,-1},
+	{0x3e,0x6a7f,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x39,-1},
+	{0x3f,0x6a1b,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x3b,-1},  /* 856x480 */
+	{0x42,0x6a3d,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x3b,-1},
+	{0x45,0x6a7f,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x3b,-1},
+	{0x48,0x6a3b,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x3d,-1},  /* 1360x768 */
+	{0x4b,0x6a7d,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x3d,-1},
+	{0x4e,0x6aff,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x3d,-1},
+	{0x4f,0x921f,0x0000,SIS_RI_320x200,  0x00,0x00,0x00,0x00,0x23,-1},  /* 320x200x32 */
+	{0x53,0x921f,0x0000,SIS_RI_320x240,  0x00,0x00,0x00,0x00,0x24,-1},  /* 320x240x32 */
+	{0x54,0xb21f,0x0000,SIS_RI_400x300,  0x00,0x00,0x00,0x00,0x25,-1},  /* 400x300x32 */
+	{0x55,0x2e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x3e,-1},  /* 1280x768   */
+	{0x5a,0x2e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x3e,-1},
+	{0x5b,0x2eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x3e,-1},
+	{0x5f,0x6a1b,0x0000,SIS_RI_768x576,  0x00,0x00,0x00,0x00,0x3f,-1},  /* 768x576x8 */
+	{0x60,0x6a1d,0x0000,SIS_RI_768x576,  0x00,0x00,0x00,0x00,0x3f,-1},  /* 768x576x16 */
+	{0x61,0x6a1f,0x0000,SIS_RI_768x576,  0x00,0x00,0x00,0x00,0x3f,-1},  /* 768x576x32 */
+	{0x67,0x6e3b,0x0000,SIS_RI_1360x1024,0x00,0x00,0x00,0x00,0x40,-1},  /* 1360x1024x8 (BARCO) */
+	{0x6f,0x6e7d,0x0000,SIS_RI_1360x1024,0x00,0x00,0x00,0x00,0x40,-1},  /* 1360x1024x16 (BARCO) */
+	{0x72,0x6eff,0x0000,SIS_RI_1360x1024,0x00,0x00,0x00,0x00,0x40,-1},  /* 1360x1024x32 (BARCO) */
+	{0xff,0x0000,0xffff,0,               0x00,0x00,0x00,0x00,0x00}
+};
+
+static const SiS_Ext2Struct  SiS300_RefIndex[] =
+{
+	{0x085f,0x0d,0x03,0x05,0x05,0x6a, 800, 600, 0}, /* 00 */
+	{0x0467,0x0e,0x44,0x05,0x05,0x6a, 800, 600, 0}, /* 01 */
+	{0x0067,0x0f,0x07,0x48,0x05,0x6a, 800, 600, 0}, /* 02 - CRT1CRTC was 0x4f */
+	{0x0067,0x10,0x06,0x8b,0x05,0x6a, 800, 600, 0}, /* 03 */
+	{0x0147,0x11,0x08,0x00,0x05,0x6a, 800, 600, 0}, /* 04 */
+	{0x0147,0x12,0x0c,0x00,0x05,0x6a, 800, 600, 0}, /* 05 */
+	{0x0047,0x11,0x4e,0x00,0x05,0x6a, 800, 600, 0}, /* 06 - CRT1CRTC was 0x51 */
+	{0x0047,0x11,0x13,0x00,0x05,0x6a, 800, 600, 0}, /* 07 */
+	{0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0}, /* 08 */
+	{0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0}, /* 09 */
+	{0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0}, /* 0a */
+	{0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0}, /* 0b */
+	{0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0}, /* 0c */
+	{0xc047,0x0a,0x08,0x00,0x04,0x2e, 640, 480, 0}, /* 0d */
+	{0xc047,0x0b,0x0a,0x00,0x04,0x2e, 640, 480, 0}, /* 0e */
+	{0xc047,0x0c,0x10,0x00,0x04,0x2e, 640, 480, 0}, /* 0f */
+	{0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0}, /* 10 */
+	{0xc06f,0x31,0x01,0x06,0x13,0x31, 720, 480, 0}, /* 11 */
+	{0x006f,0x32,0x03,0x06,0x14,0x32, 720, 576, 0}, /* 12 */
+	{0x0187,0x15,0x05,0x00,0x06,0x37,1024, 768, 0}, /* 13 */
+        {0xc877,0x16,0x09,0x06,0x06,0x37,1024, 768, 0}, /* 14 */
+	{0xc067,0x17,0x0b,0x49,0x06,0x37,1024, 768, 0}, /* 15 - CRT1CRTC was 0x97 */
+	{0x0267,0x18,0x0d,0x00,0x06,0x37,1024, 768, 0}, /* 16 */
+	{0x0047,0x19,0x11,0x8c,0x06,0x37,1024, 768, 0}, /* 17 - CRT1CRTC was 0x59 */
+	{0x0047,0x1a,0x52,0x00,0x06,0x37,1024, 768, 0}, /* 18 */
+	{0x0007,0x1b,0x16,0x00,0x06,0x37,1024, 768, 0}, /* 19 - CRT1CRTC was 0x5b */
+	{0x0387,0x1c,0x4d,0x00,0x07,0x3a,1280,1024, 0}, /* 1a - CRT1CRTC was 0x5c */
+	{0x0077,0x1d,0x14,0x07,0x07,0x3a,1280,1024, 0}, /* 1b */
+	{0x0047,0x1e,0x17,0x00,0x07,0x3a,1280,1024, 0}, /* 1c */
+	{0x0007,0x1f,0x98,0x00,0x07,0x3a,1280,1024, 0}, /* 1d */
+	{0x0007,0x20,0x59,0x00,0x00,0x3c,1600,1200, 0}, /* 1e - CRT1CRTC was 0x60 */
+	{0x0007,0x21,0x5a,0x00,0x00,0x3c,1600,1200, 0}, /* 1f */
+	{0x0007,0x22,0x1b,0x00,0x00,0x3c,1600,1200, 0}, /* 20 */
+	{0x0007,0x23,0x1d,0x00,0x00,0x3c,1600,1200, 0}, /* 21 - CRT1CRTC was 0x63 */
+	{0x0007,0x24,0x1e,0x00,0x00,0x3c,1600,1200, 0}, /* 22 */
+	{0x407f,0x00,0x00,0x00,0x00,0x40, 320, 200, 0}, /* 23 */
+	{0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0}, /* 24 */
+	{0x0077,0x02,0x04,0x05,0x05,0x51, 400, 300, 0}, /* 25 */
+	{0xc877,0x03,0x09,0x06,0x06,0x52, 512, 384, 0}, /* 26 */  /* was c077 */
+	{0x8207,0x25,0x1f,0x00,0x00,0x68,1920,1440, 0}, /* 27 */
+	{0x0007,0x26,0x20,0x00,0x00,0x6c,2048,1536, 0}, /* 28 */
+	{0x0067,0x27,0x14,0x08,0x0a,0x6e,1280, 960, 0}, /* 29 - 1280x960-60 */
+	{0x0027,0x45,0x3c,0x08,0x0a,0x6e,1280, 960, 0}, /* 2a - 1280x960-85 */
+	{0xc077,0x33,0x09,0x06,0x00,0x20,1024, 600, 0}, /* 2b */
+	{0xc077,0x34,0x0b,0x06,0x00,0x23,1152, 768, 0}, /* 2c */	/* VCLK 0x09 */
+	{0x0077,0x35,0x27,0x08,0x18,0x70, 800, 480, 0}, /* 2d */
+	{0x0047,0x36,0x37,0x08,0x18,0x70, 800, 480, 0}, /* 2e */
+	{0x0047,0x37,0x08,0x08,0x18,0x70, 800, 480, 0}, /* 2f */
+	{0x0077,0x38,0x09,0x09,0x19,0x71,1024, 576, 0}, /* 30 */
+	{0x0047,0x39,0x38,0x09,0x19,0x71,1024, 576, 0}, /* 31 */
+	{0x0047,0x3a,0x11,0x09,0x19,0x71,1024, 576, 0}, /* 32 */
+	{0x0077,0x3b,0x39,0x0a,0x0c,0x75,1280, 720, 0}, /* 33 */
+	{0x0047,0x3c,0x3a,0x0a,0x0c,0x75,1280, 720, 0}, /* 34 */
+	{0x0007,0x3d,0x3b,0x0a,0x0c,0x75,1280, 720, 0}, /* 35 */
+	{0x0067,0x49,0x35,0x06,0x1a,0x29,1152, 864, 0}, /* 36 1152x864-60Hz  */
+	{0x0067,0x3e,0x34,0x06,0x1a,0x29,1152, 864, 0}, /* 37 1152x864-75Hz */
+	{0x0047,0x44,0x3a,0x06,0x1a,0x29,1152, 864, 0}, /* 38 1152x864-85Hz */
+	{0x00c7,0x3f,0x28,0x00,0x16,0x39, 848, 480, 0}, /* 39 848x480-38Hzi */
+	{0xc067,0x40,0x3d,0x0b,0x16,0x39, 848, 480, 0}, /* 3a 848x480-60Hz  */
+	{0x00c7,0x41,0x28,0x00,0x17,0x3f, 856, 480, 0}, /* 3b 856x480-38Hzi */
+	{0xc047,0x42,0x28,0x00,0x17,0x3f, 856, 480, 0}, /* 3c 856x480-60Hz  */
+	{0x0067,0x43,0x3e,0x0c,0x1b,0x48,1360, 768, 0}, /* 3d 1360x768-60Hz */
+	{0x0077,0x46,0x3f,0x08,0x08,0x55,1280, 768, 0}, /* 3e 1280x768-60Hz */
+	{0x006f,0x47,0x03,0x06,0x15,0x5f, 768, 576, 0}, /* 3f 768x576 */
+	{0x0027,0x48,0x13,0x08,0x00,0x67,1360,1024, 0}, /* 40 1360x1024-59Hz (BARCO1366 only) */
+	{0xffff,   0,   0,   0,   0,   0,   0,   0, 0}
+};
+
+static const SiS_VBModeStruct SiS300_VBModeIDTable[] =
+{
+	{0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+	{0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01},
+	{0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x02},
+	{0x03,0x00,0x00,0x00,0x02,0x00,0x02,0x00},
+	{0x03,0x00,0x00,0x00,0x02,0x00,0x02,0x01},
+	{0x03,0x00,0x00,0x00,0x03,0x00,0x03,0x02},
+	{0x05,0x00,0x00,0x01,0x04,0x00,0x00,0x00},
+	{0x06,0x00,0x00,0x01,0x05,0x00,0x02,0x00},
+	{0x07,0x00,0x00,0x00,0x03,0x00,0x03,0x01},
+	{0x07,0x00,0x00,0x00,0x03,0x00,0x03,0x02},
+	{0x0d,0x00,0x00,0x01,0x04,0x00,0x00,0x00},
+	{0x0e,0x00,0x00,0x01,0x05,0x00,0x02,0x00},
+	{0x0f,0x00,0x00,0x01,0x05,0x00,0x02,0x01},
+	{0x10,0x00,0x00,0x01,0x05,0x00,0x02,0x01},
+	{0x11,0x00,0x00,0x01,0x05,0x00,0x02,0x03},
+	{0x12,0x00,0x00,0x01,0x05,0x00,0x02,0x03},
+	{0x13,0x00,0x00,0x01,0x04,0x00,0x04,0x00},
+	{0x6a,0x00,0x00,0x01,0x07,0x00,0x08,0x0a},
+	{0x2e,0x00,0x00,0x01,0x05,0x00,0x06,0x08},
+	{0x2f,0x00,0x00,0x01,0x05,0x00,0x06,0x06},
+	{0x30,0x00,0x00,0x01,0x07,0x00,0x08,0x0a},
+	{0x31,0x00,0x00,0x01,0x06,0x00,0x00,0x00},
+	{0x32,0x00,0x00,0x01,0x06,0x00,0x00,0x00},
+	{0x33,0x00,0x00,0x01,0x06,0x00,0x00,0x00},
+	{0x34,0x00,0x00,0x01,0x06,0x00,0x00,0x00},
+	{0x35,0x00,0x00,0x01,0x06,0x00,0x00,0x00},
+	{0x36,0x00,0x00,0x01,0x06,0x00,0x00,0x00},
+	{0x37,0x00,0x00,0x01,0x00,0x00,0x0a,0x0c},
+	{0x38,0x00,0x00,0x01,0x00,0x00,0x0a,0x0c},
+	{0x3a,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d},
+	{0x40,0x00,0x00,0x01,0x04,0x00,0x05,0x05},
+	{0x41,0x00,0x00,0x01,0x04,0x00,0x05,0x05},
+	{0x43,0x00,0x00,0x01,0x05,0x00,0x06,0x08},
+	{0x44,0x00,0x00,0x01,0x05,0x00,0x06,0x08},
+	{0x46,0x00,0x00,0x01,0x07,0x00,0x08,0x0a},
+	{0x47,0x00,0x00,0x01,0x07,0x00,0x08,0x0a},
+	{0x49,0x00,0x00,0x01,0x00,0x00,0x0a,0x0c},
+	{0x4a,0x00,0x00,0x01,0x00,0x00,0x0a,0x0c},
+	{0x4c,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d},
+	{0x4d,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d},
+	{0x4f,0x00,0x00,0x01,0x04,0x00,0x05,0x05},
+	{0x50,0x00,0x00,0x01,0x04,0x00,0x05,0x07},
+	{0x51,0x00,0x00,0x01,0x07,0x00,0x07,0x09},
+	{0x52,0x00,0x00,0x01,0x00,0x00,0x09,0x0b},
+	{0x53,0x00,0x00,0x01,0x04,0x00,0x05,0x07},
+	{0x54,0x00,0x00,0x01,0x07,0x00,0x07,0x09},
+	{0x56,0x00,0x00,0x01,0x04,0x00,0x05,0x07},
+	{0x57,0x00,0x00,0x01,0x07,0x00,0x07,0x09},
+	{0x58,0x00,0x00,0x01,0x00,0x00,0x09,0x0b},
+	{0x59,0x00,0x00,0x01,0x04,0x00,0x05,0x05},
+	{0x5c,0x00,0x00,0x01,0x00,0x00,0x09,0x0b},
+	{0x5d,0x00,0x00,0x01,0x05,0x00,0x06,0x06},
+	{0x5e,0x00,0x00,0x01,0x05,0x00,0x06,0x06},
+	{0x5f,0x00,0x00,0x01,0x06,0x00,0x00,0x00},
+	{0x60,0x00,0x00,0x01,0x06,0x00,0x00,0x00},
+	{0x61,0x00,0x00,0x01,0x06,0x00,0x00,0x00},
+	{0x62,0x00,0x00,0x01,0x05,0x00,0x06,0x08},
+	{0x63,0x00,0x00,0x01,0x07,0x00,0x08,0x0a},
+	{0x64,0x00,0x00,0x01,0x00,0x00,0x0a,0x0c},
+	{0x65,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d},
+	{0x6c,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d},
+	{0x6d,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d},
+	{0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
+};
+
+static const SiS_CRT1TableStruct  SiS300_CRT1Table[] =
+{
+#if 1
+ {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,    /* 0x00 - 320x200 */
+  0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00,     /* HRE [4],[15] is invalid - but correcting it does not work */
+  0x00}},
+#endif
+#if 0
+ {{0x2d,0x27,0x27,0x91,0x2c,0x92,0xbf,0x1f,    /* 0x00 - corrected 320x200-72 - does not work */
+  0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x04,
+  0x00}},
+#endif
+ {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,    /* 0x01 */
+  0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,     /* HRE [4],[15] is invalid - but correcting it does not work */
+  0x00}},
+#if 0
+ {{0x2d,0x27,0x27,0x91,0x2c,0x92,0x0b,0x3e,    /* 0x01 - corrected 320x240-60 - does not work */
+  0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x04,
+  0x00}},
+#endif
+ {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0,    /* 0x02 */
+  0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05,
+  0x01}},
+#if 0
+ {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0,    /* 0x02 - corrected 400x300-60 */
+  0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05,
+  0x01}},
+#endif
+ {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+  0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01,
+  0x01}},
+ {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+  0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05,
+  0x00}},
+#if 0  
+ {{0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e,    /* 0x05 */
+  0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
+  0x00}},
+#endif
+ {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,    /* 0x05 - corrected 640x480-60 */
+  0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
+  0x00}},
+#if 0
+ {{0x63,0x4f,0x50,0x86,0x56,0x9b,0x06,0x3e,    /* 0x06 */
+  0xe8,0x8b,0xdf,0xe7,0xff,0x10,0x00,0x01,
+  0x00}},
+#endif  
+ {{0x63,0x4f,0x4f,0x87,0x56,0x9b,0x06,0x3e,    /* 0x06 - corrected 640x480-72 */
+  0xe8,0x8a,0xdf,0xe7,0x07,0x00,0x00,0x01,
+  0x00}},
+ {{0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f,
+  0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01,
+  0x00}},
+ {{0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f,
+  0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
+  0x00}},
+#if 0  
+ {{0x66,0x4f,0x4f,0x86,0x56,0x9e,0x03,0x3e,    /* 0x09 */
+  0xe4,0x87,0xdf,0xdf,0x04,0x00,0x00,0x01,
+  0x00}},
+#endif
+ {{0x67,0x4f,0x4f,0x8b,0x57,0x83,0x10,0x3e,    /* 0x09 - corrected 640x480-100 */
+  0xe7,0x8d,0xdf,0xe6,0x11,0x00,0x00,0x05,
+  0x00}},
+#if 0  
+ {{0x6c,0x4f,0x4f,0x83,0x59,0x9e,0x00,0x3e,    /* 0x0a */
+  0xe5,0x8d,0xdf,0xdf,0x01,0x00,0x00,0x01,
+  0x00}},
+#endif    
+ {{0x67,0x4f,0x4f,0x8b,0x57,0x83,0x10,0x3e,    /* 0x0a - corrected 640x480-120 */
+  0xe7,0x8d,0xdf,0xe6,0x11,0x00,0x00,0x05,
+  0x00}},
+ {{0x63,0x4f,0x4f,0x87,0x56,0x9d,0xfb,0x1f,
+  0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x01,
+  0x00}},
+ {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f,
+  0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01,    /* Corrected VDE, VBE */
+  0x00}},
+ {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0,
+  0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05,
+  0x01}},
+ {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0,
+  0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06,
+  0x01}},
+ {{0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0,
+  0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06,
+  0x01}},
+ {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0,
+  0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06,
+  0x01}},
+ {{0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0,
+  0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06,
+  0x01}},
+ {{0x8c,0x63,0x63,0x87,0x72,0x16,0x7e,0xf0,
+  0x59,0x8d,0x57,0x57,0x7f,0x00,0x00,0x06,
+  0x01}},
+ {{0x7e,0x63,0x63,0x82,0x6c,0x14,0x75,0xe0,
+  0x58,0x0b,0x57,0x57,0x76,0x20,0x00,0x06,
+  0x01}},
+ {{0x7e,0x63,0x63,0x82,0x6c,0x14,0x75,0xe0,   /* 0x14 */
+  0x58,0x0b,0x57,0x57,0x76,0x20,0x00,0x06,
+  0x01}},
+ {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f,
+  0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02,
+  0x00}},
+ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
+  0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
+  0x01}},
+ {{0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5,
+  0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
+  0x01}},
+ {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5,
+  0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02,
+  0x01}},
+ {{0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5,
+  0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02,
+  0x01}},
+ {{0x9f,0x7f,0x7f,0x83,0x83,0x93,0x1e,0xf5,  /* 0x1a */
+  0x00,0x84,0xff,0xff,0x1f,0x10,0x00,0x02,
+  0x01}},
+ {{0xa2,0x7f,0x7f,0x86,0x84,0x94,0x37,0xf5,
+  0x0b,0x82,0xff,0xff,0x38,0x10,0x00,0x02,
+  0x01}},
+ {{0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba,
+  0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03,
+  0x00}},
+ {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a,
+  0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
+  0x01}},
+ {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a,  /* 0x1e */
+  0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
+  0x01}},
+ {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a,
+  0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07,
+  0x01}},
+ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
+  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+  0x00}},
+ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
+  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+  0x00}},
+ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
+  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+  0x00}},
+ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
+  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+  0x00}},
+ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,  /* 36: 1600x1200x85Hz */
+  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+  0x00}},
+ {{0x3f,0xef,0xef,0x83,0xfd,0x1a,0xda,0x1f,  /* 37: 1920x1440x60Hz */
+  0xa0,0x84,0x9f,0x9f,0xdb,0x1f,0x01,0x01,
+  0x00}},
+ {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba,
+  0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05,
+  0x00}},
+#if 0  
+ {{0xdc,0x9f,0x9f,0x00,0xab,0x19,0xe6,0xef,  /* 0x27: 1280x960-70 - invalid! */
+  0xc0,0xc3,0xbf,0xbf,0xe7,0x10,0x00,0x07,
+  0x01}},
+#endif  
+ {{0xdc,0x9f,0x9f,0x80,0xaf,0x9d,0xe6,0xff,  /* 0x27: 1280x960-60 - correct */
+  0xc0,0x83,0xbf,0xbf,0xe7,0x10,0x00,0x07,
+  0x01}},
+ {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba,  /* 0x28 */
+  0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06,
+  0x01}},
+ {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba,
+  0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06,
+  0x01}},
+ {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba,
+  0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06,
+  0x01}},
+ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1,
+  0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02,
+  0x01}},
+ {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1,
+  0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02,
+  0x01}},
+ {{0xa7,0x7f,0x7f,0x88,0x89,0x15,0x26,0xf1,
+  0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02,
+  0x01}},
+ {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4,
+  0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
+  0x01}},
+ {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4,
+  0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
+  0x01}},
+ {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4,
+  0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07,
+  0x01}},
+ {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e,
+  0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
+  0x00}},
+ {{0x7b,0x59,0x63,0x9f,0x6a,0x93,0x6f,0xf0,  /* 0x32 */
+  0x58,0x8a,0x3f,0x57,0x70,0x20,0x00,0x05,
+  0x01}},
+ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1,  /* 0x33 - 1024x600 */
+  0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02,
+  0x01}},
+ {{0xa3,0x8f,0x8f,0x97,0x96,0x97,0x24,0xf5,  /* 0x34 - 1152x768 - corrected */
+  0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
+  0x01}},
+ {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba,  /* 0x35 */
+   0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06,
+   0x01}}, /* 0x35 */
+ {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba,
+   0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06,
+   0x01}}, /* 0x36 */
+ {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba,
+   0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06,
+   0x01}}, /* 0x37 */
+ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1,
+   0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02,
+   0x01}}, /* 0x38 */
+ {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1,
+   0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02,
+   0x01}}, /* 0x39 */
+ {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1,  /* 95 was 15 - illegal HBE! */
+   0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02,
+   0x01}}, /* 0x3a */
+ {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4,
+   0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
+   0x01}}, /* 0x3b */
+ {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4,
+   0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
+   0x01}}, /* 0x3c */
+ {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4,
+   0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07,
+   0x01}}, /* 0x3d */
+ {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef,  /* 1152x864-75 */
+   0x60,0x83,0x5f,0x5f,0x83,0x10,0x00,0x07,
+   0x01}},  /* 0x3e */
+ {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15,  /* 848x480-38i */
+   0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
+   0x00}}, /* 0x3f */
+ {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E,  /* 848x480-60  */
+   0xE5,0x8d,0xDF,0xe4,0x04,0x00,0x00,0x06,
+   0x00}}, /* 0x40 */
+ {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15,  /* 856x480-38i */
+   0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
+   0x00}}, /* 0x41 */
+ {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E,  /* 856x480-60  */
+   0xEB,0x8E,0xDF,0xDF,0x10,0x00,0x00,0x02,
+   0x00}}, /* 0x42 */
+ {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd,  /* 1360x768-60 */
+   0x01,0x8d,0xff,0x00,0x27,0x10,0x00,0x03,
+   0x01}}, /* 0x43 */
+ {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff,  /* 1152x864-84 */
+   0x60,0x8b,0x5f,0x5f,0x8b,0x10,0x00,0x03,
+   0x01}}, /* 0x44 */
+ {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff,  /* 1280x960-85 */
+   0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07,
+   0x01}}, /* 0x45 */
+ {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x20,0xf5,  /* 1280x768-60 */
+   0x03,0x88,0xff,0xff,0x21,0x10,0x00,0x07,
+   0x01}}, /* 0x46 */
+ {{0x7b,0x5f,0x63,0x9f,0x6a,0x93,0x6f,0xf0,  /* 768x576 */
+   0x58,0x8a,0x3f,0x57,0x70,0x20,0x00,0x05,
+   0x01}}, /* 0x47 */
+ {{0xce,0xa9,0xa9,0x92,0xb1,0x07,0x28,0x52,  /* 1360x1024 (Barco iQ Pro R300) */
+   0x02,0x8e,0xff,0x00,0x29,0x0d,0x00,0x03,
+   0x00}}, /* 0x48 */
+ {{0xcd,0x8f,0x8f,0x91,0x9b,0x1b,0x7a,0xff,  /* 1152x864-60 */
+   0x64,0x8c,0x5f,0x62,0x7b,0x10,0x00,0x07,
+   0x41}}  /* 0x49 */
+};
+
+static const SiS_MCLKDataStruct  SiS300_MCLKData_630[] =
+{
+	{ 0x5a,0x64,0x80, 66},
+	{ 0xb3,0x45,0x80, 83},
+	{ 0x37,0x61,0x80,100},
+	{ 0x37,0x22,0x80,133},
+	{ 0x37,0x61,0x80,100},
+	{ 0x37,0x61,0x80,100},
+	{ 0x37,0x61,0x80,100},
+	{ 0x37,0x61,0x80,100}
+};
+
+static const SiS_MCLKDataStruct  SiS300_MCLKData_300[] =
+{
+	{ 0x68,0x43,0x80,125},
+	{ 0x68,0x43,0x80,125},
+	{ 0x68,0x43,0x80,125},
+	{ 0x37,0x61,0x80,100},
+	{ 0x37,0x61,0x80,100},
+	{ 0x37,0x61,0x80,100},
+	{ 0x37,0x61,0x80,100},
+	{ 0x37,0x61,0x80,100}
+};
+
+static SiS_VCLKDataStruct SiS300_VCLKData[] =
+{
+	{ 0x1b,0xe1, 25}, /* 0x00 */
+	{ 0x4e,0xe4, 28}, /* 0x01 */
+	{ 0x57,0xe4, 32}, /* 0x02 */
+	{ 0xc3,0xc8, 36}, /* 0x03 */
+	{ 0x42,0xc3, 40}, /* 0x04 */
+	{ 0x5d,0xc4, 45}, /* 0x05 */
+	{ 0x52,0x65, 50}, /* 0x06 */
+	{ 0x53,0x65, 50}, /* 0x07 */
+	{ 0x6d,0x66, 56}, /* 0x08 */
+	{ 0x5a,0x64, 65}, /* 0x09 */
+	{ 0x46,0x44, 68}, /* 0x0a */
+	{ 0x3e,0x43, 75}, /* 0x0b */
+	{ 0x6d,0x46, 76}, /* 0x0c */  /* 800x600 | LVDS_2(CH), MITAC(CH);  - 730, A901(301B): 0xb1,0x46, 76 */
+	{ 0x41,0x43, 79}, /* 0x0d */
+	{ 0x31,0x42, 79}, /* 0x0e */
+	{ 0x46,0x25, 85}, /* 0x0f */
+	{ 0x78,0x29, 87}, /* 0x10 */
+	{ 0x62,0x44, 95}, /* 0x11 */
+	{ 0x2b,0x22,105}, /* 0x12 */
+	{ 0x49,0x24,106}, /* 0x13 */
+	{ 0xc3,0x28,108}, /* 0x14 */
+	{ 0x3c,0x23,109}, /* 0x15 */
+	{ 0xf7,0x2c,132}, /* 0x16 */
+	{ 0xd4,0x28,136}, /* 0x17 */
+	{ 0x41,0x05,158}, /* 0x18 */
+	{ 0x43,0x05,162}, /* 0x19 */
+	{ 0xe1,0x0f,175}, /* 0x1a */
+	{ 0xfc,0x12,189}, /* 0x1b */
+	{ 0xde,0x26,194}, /* 0x1c */
+	{ 0x54,0x05,203}, /* 0x1d */
+	{ 0x3f,0x03,230}, /* 0x1e */
+	{ 0x30,0x02,234}, /* 0x1f */
+	{ 0x24,0x01,266}, /* 0x20 */
+	{ 0x52,0x2a, 54}, /* 0x21 */  /* 301 TV */
+	{ 0x52,0x6a, 27}, /* 0x22 */  /* 301 TV */
+	{ 0x62,0x24, 70}, /* 0x23 */  /* 301 TV */
+	{ 0x62,0x64, 70}, /* 0x24 */  /* 301 TV */
+	{ 0xa8,0x4c, 30}, /* 0x25 */  /* 301 TV */
+	{ 0x20,0x26, 33}, /* 0x26 */  /* 301 TV */
+	{ 0x31,0xc2, 39}, /* 0x27 */
+	{ 0xbf,0xc8, 35}, /* 0x28 */  /* 856x480 */
+	{ 0x60,0x36, 30}, /* 0x29 */  /* CH/UNTSC TEXT | LVDS_2(CH) - 730, A901(301B), Mitac(CH): 0xe0, 0xb6, 30 */
+	{ 0x40,0x4a, 28}, /* 0x2a */  /* CH-TV */
+	{ 0x9f,0x46, 44}, /* 0x2b */  /* CH-TV */
+	{ 0x97,0x2c, 26}, /* 0x2c */  /* CH-TV */
+	{ 0x44,0xe4, 25}, /* 0x2d */  /* CH-TV */
+	{ 0x7e,0x32, 47}, /* 0x2e */  /* CH-TV */
+	{ 0x8a,0x24, 31}, /* 0x2f */  /* CH/PAL TEXT | LVDS_2(CH), Mitac(CH) -  730, A901(301B): 0x57, 0xe4, 31 */
+	{ 0x97,0x2c, 26}, /* 0x30 */  /* CH-TV */
+	{ 0xce,0x3c, 39}, /* 0x31 */  /* CH-TV */
+	{ 0x52,0x4a, 36}, /* 0x32 */  /* CH/PAL 800x600 5/6 */
+	{ 0x34,0x61, 95}, /* 0x33 */
+	{ 0x78,0x27,108}, /* 0x34 */  /* Replacement for index 0x14 for 630 (?) */
+	{ 0x70,0x28, 90}, /* 0x35 */  /* 1152x864@60 */
+	{ 0x45,0x6b, 21}, /* 0x36 */  /* Chrontel SuperOverscan */
+	{ 0x52,0xe2, 49}, /* 0x37 */  /* 16:9 modes  */
+	{ 0x2b,0x61, 78}, /* 0x38 */  /* 16:9 modes  */
+	{ 0x70,0x44,108}, /* 0x39 */  /* 16:9 modes  */
+	{ 0x54,0x42,135}, /* 0x3a */  /* 16:9 modes  */
+	{ 0x41,0x22,157}, /* 0x3b */  /* 16:9 modes  */
+	{ 0x52,0x07,149}, /* 0x3c */  /* 1280x960-85 */
+	{ 0x62,0xc6, 34}, /* 0x3d */  /* 848x480-60  */
+	{ 0x30,0x23, 88}, /* 0x3e */  /* 1360x768-60 */
+        { 0x70,0x29, 81}, /* 0x3f */  /* 1280x768-60 */
+	{ 0x72,0x2a, 76}, /* 0x40 */  /* test for SiS730 --- LIMIT for table (&0x3f) */
+	{ 0x15,0x21, 79}, /* 0x41 */  /* test for SiS730 */
+	{ 0xa1,0x42,108}, /* 0x42 */  /* 1280x960 LCD */
+	{ 0x37,0x61,100}, /* 0x43 */  /* 1280x960 LCD */
+	{ 0xe3,0x9a,106}, /* 0x44 */  /* 1360x1024 - special for Barco iQ R300 */
+	{ 0xe2,0x46,135}, /* 0x45 */  /* 1280x1024-75, better clock for VGA2 */
+	{ 0x70,0x29, 81}, /* 0x46 */  /* unused */
+	{    0,   0,  0}, /* 0x47 custom (will be filled out) */
+	{ 0xce,0x25,189}  /* 0x48 */  /* Replacement for index 0x1b for 730 (and 540?) */
+};
+
+#ifdef LINUX_KERNEL
+static UCHAR SiS300_SR07 = 0x10;
+#endif
+
+static const DRAM4Type SiS300_SR15[8] =
+{
+	{0x01,0x09,0xa3,0x00},
+	{0x43,0x43,0x43,0x00},
+	{0x1e,0x1e,0x1e,0x00},
+	{0x2a,0x2a,0x2a,0x00},
+	{0x06,0x06,0x06,0x00},
+	{0x00,0x00,0x00,0x00},
+	{0x00,0x00,0x00,0x00},
+	{0x00,0x00,0x00,0x00}
+};
+
+#ifdef LINUX_KERNEL
+static UCHAR SiS300_SR1F = 0x00;
+static UCHAR SiS300_SR21 = 0x16;
+static UCHAR SiS300_SR22 = 0xb2;
+static UCHAR SiS300_SR23 = 0xf6;
+static UCHAR SiS300_SR24 = 0x0d;
+static UCHAR SiS300_SR25[] = {0x0,0x0};
+static UCHAR SiS300_SR31 = 0x00;
+static UCHAR SiS300_SR32 = 0x11;
+static UCHAR SiS300_SR33 = 0x00;
+static UCHAR SiS300_CRT2Data_1_2 = 0x40;
+static UCHAR SiS300_CRT2Data_4_D = 0x00;
+static UCHAR SiS300_CRT2Data_4_E = 0x00;
+static UCHAR SiS300_CRT2Data_4_10 = 0x80;
+
+static const USHORT SiS300_RGBSenseData = 0xd1;
+static const USHORT SiS300_VideoSenseData = 0xb3;
+static const USHORT SiS300_YCSenseData = 0xb9;
+static const USHORT SiS300_RGBSenseData2 = 0x0190;
+static const USHORT SiS300_VideoSenseData2 = 0x0174;
+static const USHORT SiS300_YCSenseData2 = 0x016b;
+
+static const DRAM4Type SiS300_CR40[5];
+
+static UCHAR SiS300_CR49[2];
+#endif
+
+static const SiS_PanelDelayTblStruct  SiS300_PanelDelayTbl[] =
+{
+	{{0x05,0xaa}},
+	{{0x05,0x14}},
+	{{0x05,0x36}},
+	{{0x05,0x14}},
+	{{0x05,0x14}},
+	{{0x05,0x14}},
+	{{0x05,0x90}},
+	{{0x05,0x90}},
+	{{0x05,0x14}},
+	{{0x05,0x14}},
+	{{0x05,0x14}},
+	{{0x05,0x14}},
+	{{0x20,0x80}},
+	{{0x05,0x14}},
+	{{0x05,0x40}},
+	{{0x05,0x60}}
+};
+
+#if 0
+static const SiS_PanelDelayTblStruct  SiS300_PanelDelayTblLVDS[] =
+{
+	{{0x05,0xaa}},
+	{{0x05,0x14}},
+	{{0x05,0x36}},
+	{{0x05,0x14}},
+	{{0x05,0x14}},
+	{{0x05,0x14}},
+	{{0x05,0x90}},
+	{{0x05,0x90}},
+	{{0x05,0x14}},
+	{{0x05,0x14}},
+	{{0x05,0x14}},
+	{{0x05,0x14}},  /* 2.07a (JVC): 14,96 */
+	{{0x05,0x28}},  /* 2.04.5c: 20, 80 - Clevo (2.04.2c): 05, 28 */
+	{{0x05,0x14}},
+	{{0x05,0x14}},  /* Some BIOSes: 05, 40 */
+	{{0x05,0x60}}
+};
+#endif
+
+/**************************************************************/
+/* SIS VIDEO BRIDGE ----------------------------------------- */
+/**************************************************************/
+
+static const SiS_LCDDataStruct  SiS300_St2LCD1024x768Data[] =
+{
+	{   62,  25, 800, 546,1344, 806},
+	{   32,  15, 930, 546,1344, 806},
+	{   32,  15, 930, 546,1344, 806},
+	{  104,  45, 945, 496,1344, 806},
+	{   62,  25, 800, 546,1344, 806},
+	{   31,  18,1008, 624,1344, 806},
+	{    1,   1,1344, 806,1344, 806}
+};
+
+static const SiS_LCDDataStruct  SiS300_ExtLCD1024x768Data[] =
+{
+	{   12,   5, 896, 512,1344, 806},
+	{   12,   5, 896, 510,1344, 806},
+	{   32,  15,1008, 505,1344, 806},
+	{   32,  15,1008, 514,1344, 806},
+	{   12,   5, 896, 500,1344, 806},
+	{   42,  25,1024, 625,1344, 806},
+	{    1,   1,1344, 806,1344, 806},
+	{   12,   5, 896, 500,1344, 806},
+	{   42,  25,1024, 625,1344, 806},
+	{    1,   1,1344, 806,1344, 806},
+	{   12,   5, 896, 500,1344, 806},
+	{   42,  25,1024, 625,1344, 806},
+	{    1,   1,1344, 806,1344, 806}
+};
+
+static const SiS_LCDDataStruct  SiS300_St2LCD1280x1024Data[] =
+{
+	{   22,   5, 800, 510,1650,1088},
+	{   22,   5, 800, 510,1650,1088},
+	{  176,  45, 900, 510,1650,1088},
+	{  176,  45, 900, 510,1650,1088},
+	{   22,   5, 800, 510,1650,1088},
+	{   13,   5,1024, 675,1560,1152},
+	{   16,   9,1266, 804,1688,1072},
+	{    1,   1,1688,1066,1688,1066}
+};
+
+static const SiS_LCDDataStruct  SiS300_ExtLCD1280x1024Data[] =
+{
+	{  211,  60,1024, 501,1688,1066},
+	{  211,  60,1024, 508,1688,1066},
+	{  211,  60,1024, 501,1688,1066},
+	{  211,  60,1024, 508,1688,1066},
+	{  211,  60,1024, 500,1688,1066},
+	{  211,  75,1024, 625,1688,1066},
+	{  211, 120,1280, 798,1688,1066},
+	{    1,   1,1688,1066,1688,1066}
+};
+
+static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1024x768_1[] =
+{ /* VESA Timing */
+  {{0x21,0x12,0xbf,0xe4,0xc0,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}},
+  {{0x2c,0x12,0x9a,0xae,0x88,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}},
+  {{0x21,0x12,0xbf,0xe4,0xc0,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}},
+  {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+  {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}},
+  {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}},
+  {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}}
+};
+
+static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1024x768_2[] =
+{  /* Non-VESA */
+ {{0x28,0x12,0xa3,0xd0,0xaa,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}},
+ {{0x2c,0x12,0x9a,0xae,0x88,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}},
+ {{0x28,0x12,0xa3,0xd0,0xaa,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}},
+ {{0x2c,0x12,0x9a,0xae,0x88,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}},
+ {{0x28,0x13,0xe7,0x0b,0xe8,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}},
+ {{0x38,0x18,0x16,0x00,0x00,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}},
+ {{0x36,0x13,0x13,0x25,0xff,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}
+};
+
+static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1024x768_3[] =
+{
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
+};
+
+static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1280x1024_1[] =
+{
+  {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
+};
+
+static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1280x1024_2[] =
+{
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
+};
+
+static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1280x1024_3[] =
+{
+  {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
+};
+
+/**************************************************************/
+/* LVDS/Chrontel -------------------------------------------- */
+/**************************************************************/
+
+static const SiS_LVDSDataStruct  SiS300_CHTVUPALData[] =
+{
+	{1008, 625,1008, 625},
+	{1008, 625,1008, 625},
+	{1008, 625,1008, 625},
+	{1008, 625,1008, 625},
+	{ 840, 750, 840, 750},
+	{ 936, 836, 936, 836}
+};
+
+static const SiS_LVDSDataStruct  SiS300_CHTVOPALData[] =
+{
+	{1008, 625,1008, 625},
+	{1008, 625,1008, 625},
+	{1008, 625,1008, 625},
+	{1008, 625,1008, 625},
+	{ 840, 625, 840, 625},
+	{ 960, 750, 960, 750}
+};
+
+static const SiS_LVDSDataStruct  SiS300_CHTVSOPALData[] =
+{
+	{1008, 625,1008, 625},
+	{1008, 625,1008, 625},
+	{1008, 625,1008, 625},
+	{1008, 625,1008, 625},
+	{ 840, 500, 840, 500},
+	{ 944, 625, 944, 625}
+};
+
+
+static const SiS_LVDSDesStruct  SiS300_PanelType00_1[] =
+{
+	{ 1059, 626 },   /* 2.08 */
+	{ 1059, 624 },
+	{ 1059, 626 },
+	{ 1059, 624 },
+	{ 1059, 624 },
+	{    0, 627 },
+	{    0, 627 },
+	{    0,   0 },
+	{    0,   0 }
+#if 0
+	{0, 626},
+	{0, 624},
+	{0, 626},
+	{0, 624},
+	{0, 624},
+	{0, 627},
+	{0, 627},
+	{0,   0},
+	{0,   0}
+#endif
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType01_1[] =
+{
+	{   0,   0 },  /* 2.08 */
+	{   0,   0 },
+	{   0,   0 },
+	{   0,   0 },
+	{   0,   0 },
+	{   0,   0 },
+	{   0,   0 },
+	{   0,   0 },
+	{   0,   0 }
+#if 0
+	{1343, 798},
+	{1343, 794},
+	{1343, 798},
+	{1343, 794},
+	{1343,   0},
+	{1343,   0},
+	{   0, 805},
+	{   0, 794},
+	{   0,   0}
+#endif
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType02_1[] =
+{
+	{ 1059, 626 },  /* 2.08 */
+	{ 1059, 624 },
+	{ 1059, 626 },
+	{ 1059, 624 },
+	{ 1059, 624 },
+	{    0, 627 },
+	{    0, 627 },
+	{    0,   0 },
+	{    0,   0 }
+#if 0
+	{0, 626},
+	{0, 624},
+	{0, 626},
+	{0, 624},
+	{0, 624},
+	{0, 627},
+	{0, 627},
+	{0,   0},
+	{0,   0}
+#endif
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType03_1[] =
+{
+	{   8, 436},
+	{   8, 440},
+	{   8, 436},
+	{   8, 440},
+	{   8, 512},
+	{1343, 798},
+	{1343, 794},
+	{1343, 798},
+	{1343, 794}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType04_1[] =	/* 1280x1024 */
+{
+	{1343, 798},
+	{1343, 794},
+	{1343, 798},
+	{1343, 794},
+	{1343,   0},
+	{1343,   0},
+	{   0, 805},
+	{   0, 794},
+	{   0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType05_1[] =
+{
+	{1343, 798},
+	{1343, 794},
+	{1343, 798},
+	{1343, 794},
+	{1343,   0},
+	{1343,   0},
+	{   0, 805},
+	{   0, 794},
+	{   0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType06_1[] =	/* Clevo Trumpion 1024x768 */
+{
+	{1343, 798},
+	{1343, 794},
+	{1343, 798},
+	{1343, 794},
+	{1343,   0},
+	{1343,   0},
+	{   0, 805},
+	{   0, 794},
+	{   0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType07_1[] =
+{
+	{1343, 798},
+	{1343, 794},
+	{1343, 798},
+	{1343, 794},
+	{1343,   0},
+	{1343,   0},
+	{   0, 805},
+	{   0, 794},
+	{   0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType08_1[] =
+{
+	{1059, 626},
+	{1059, 624},
+	{1059, 626},
+	{1059, 624},
+	{1059, 624},
+	{   0, 627},
+	{   0, 627},
+	{   0,   0},
+	{   0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType09_1[] =
+{
+	{1343, 798},
+	{1343, 794},
+	{1343, 798},
+	{1343, 794},
+	{1343,   0},
+	{1343,   0},
+	{   0, 805},
+	{   0, 794},
+	{   0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType0a_1[] =
+{
+	{1059, 626},
+	{1059, 624},
+	{1059, 626},
+	{1059, 624},
+	{1059, 624},
+	{   0, 627},
+	{   0, 627},
+	{   0,   0},
+	{   0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType0b_1[] =
+{
+	{1343,   0},
+	{1343,   0},
+	{1343,   0},
+	{1343,   0},
+	{1343,   0},
+	{1343,   0},
+	{   0, 799},
+	{   0,   0},
+	{   0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType0c_1[] =
+{
+	{1343, 798},
+	{1343, 794},
+	{1343, 798},
+	{1343, 794},
+	{1343,   0},
+	{1343,   0},
+	{   0, 805},
+	{   0, 794},
+	{   0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType0d_1[] =
+{
+	{1343, 798},
+	{1343, 794},
+	{1343, 798},
+	{1343, 794},
+	{1343,   0},
+	{1343,   0},
+	{   0, 805},
+	{   0, 794},
+	{   0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType0e_1[] =
+{
+	{1343, 798},
+	{1343, 794},
+	{1343, 798},
+	{1343, 794},
+	{1343,   0},    /* 640x480 */
+	{1343,   0},    /* 800x600 */
+	{   0, 805},    /* 1024x768 */
+	{   0, 794},    /* 1280x1024 */
+	{   0,   0}     /* 1280x960 - not applicable */
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType0f_1[] =
+{
+	{1343, 798},
+	{1343, 794},
+	{1343, 798},
+	{1343, 794},
+	{1343,   0},
+	{1343,   0},
+	{   0, 805},
+	{   0, 794},
+	{   0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType00_2[] =
+{
+	{976, 527},
+	{976, 502},
+	{976, 527},
+	{976, 502},
+	{976, 567},
+	{  0, 627},
+	{  0, 627},
+	{  0,   0},
+	{  0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType01_2[] =
+{
+	{1152, 622},
+	{1152, 597},
+	{1152, 622},
+	{1152, 597},
+	{1152, 662},
+	{1232, 722},
+	{   0, 805},
+	{   0, 794},
+	{   0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType02_2[] =
+{
+	{976, 527},
+	{976, 502},
+	{976, 527},
+	{976, 502},
+	{976, 567},
+	{  0, 627},
+	{  0, 627},
+	{  0,   0},
+	{  0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType03_2[] =
+{
+	{1152, 622},
+	{1152, 597},
+	{1152, 622},
+	{1152, 597},
+	{1152, 662},
+	{1232, 722},
+	{   0, 805},
+	{1152, 622},
+	{1152, 597}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType04_2[] =
+{
+	{1152, 622},
+	{1152, 597},
+	{1152, 622},
+	{1152, 597},
+	{1152, 662},
+	{1232, 722},
+	{   0, 805},
+	{   0, 794},
+	{   0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType05_2[] =
+{
+	{1152, 622},
+	{1152, 597},
+	{1152, 622},
+	{1152, 597},
+	{1152, 662},
+	{1232, 722},
+	{   0, 805},
+	{   0, 794},
+	{   0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType06_2[] =
+{
+	{1152, 622},
+	{1152, 597},
+	{1152, 622},
+	{1152, 597},
+	{1152, 662},
+	{1232, 722},
+	{   0, 805},
+	{   0, 794},
+	{   0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType07_2[] =
+{
+ 	{1152, 622},
+ 	{1152, 597},
+ 	{1152, 622},
+ 	{1152, 597},
+ 	{1152, 662},
+ 	{1232, 722},
+	{   0, 805},
+	{   0, 794},
+	{   0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType08_2[] =
+{
+ 	{976, 527},
+ 	{976, 502},
+ 	{976, 527},
+ 	{976, 502},
+ 	{976, 567},
+ 	{  0, 627},
+ 	{  0, 627},
+ 	{  0,   0},
+ 	{  0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType09_2[] =
+{
+ 	{1152, 622},
+ 	{1152, 597},
+ 	{1152, 622},
+ 	{1152, 597},
+ 	{1152, 662},
+ 	{1232, 722},
+ 	{   0, 805},
+ 	{   0, 794},
+ 	{   0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType0a_2[] =
+{
+ 	{976, 527},
+ 	{976, 502},
+ 	{976, 527},
+ 	{976, 502},
+ 	{976, 567},
+ 	{  0, 627},
+ 	{  0, 627},
+ 	{  0,   0},
+ 	{  0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType0b_2[] =
+{
+ 	{ 1152, 700},
+ 	{ 1152, 675},
+ 	{ 1152, 700},
+ 	{ 1152, 675},
+ 	{ 1152, 740},
+ 	{ 1232, 799},
+ 	{    0, 799},
+ 	{    0,   0},
+ 	{    0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType0c_2[] =
+{
+ 	{1152, 622},
+ 	{1152, 597},
+ 	{1152, 622},
+ 	{1152, 597},
+ 	{1152, 662},
+ 	{1232, 722},
+ 	{   0, 805},
+ 	{   0, 794},
+ 	{   0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType0d_2[] =
+{
+ 	{1152, 622},
+ 	{1152, 597},
+ 	{1152, 622},
+ 	{1152, 597},
+ 	{1152, 662},
+ 	{1232, 722},
+ 	{   0, 805},
+ 	{   0, 794},
+ 	{   0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType0e_2[] =
+{
+ 	{1152, 622},
+ 	{1152, 597},
+ 	{1152, 622},
+ 	{1152, 597},
+ 	{1152, 662},
+ 	{1232, 722},
+ 	{   0, 805},
+ 	{   0, 794},
+ 	{   0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType0f_2[] =
+{
+ 	{1152, 622},
+ 	{1152, 597},
+ 	{1152, 622},
+ 	{1152, 597},
+ 	{1152, 662},
+ 	{1232, 722},
+ 	{   0, 805},
+ 	{   0, 794},
+ 	{   0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelTypeNS_1[]=
+{
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0, 805},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelTypeNS_2[] =
+{
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
+};
+
+/* Custom data for Barco iQ R200/300/400 (BIOS 2.00.07) */
+static const SiS_LVDSDesStruct  SiS300_PanelType04_1a[] =	/* 1280x1024 (1366x1024) */
+{
+	{1330, 798},  /* 320x200 */
+	{1330, 794},
+	{1330, 798},
+	{1330, 794},
+	{1330,   0},  /* 640x480 / 320x240  */
+	{1343,   0},  /* 800x600 / 400x300  */
+	{   0, 805},  /* 1024x768 / 512x384 */
+	{1688,1066},  /* 1280x1024          */
+	{   0,   0}   /* 1360x1024          */
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType04_2a[] =
+{
+	{1152, 622},
+	{1152, 597},
+	{1152, 622},
+	{1152, 597},
+	{1152, 662},
+	{1232, 722},
+	{   0, 805},
+	{1688,1066},
+	{   0,   0}
+};
+
+/* Custom data for Barco iQ G200/300/400 (BIOS 2.00.07) */
+static const SiS_LVDSDesStruct  SiS300_PanelType04_1b[] =	/* 1024x768 */
+{
+	{1330, 798},  /* 320x200 */
+	{1330, 794},
+	{1330, 798},
+	{1330, 794},
+	{1330,   0},  /* 640x480 / 320x240  */
+	{1343,   0},  /* 800x600 / 400x300  */
+	{   0, 805}   /* 1024x768 / 512x384 */
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelType04_2b[] =
+{
+	{1152, 622},
+	{1152, 597},
+	{1152, 622},
+	{1152, 597},
+	{1152, 662},
+	{1232, 722},
+	{   0, 805}
+};
+
+/* CRT1 CRTC for slave modes */
+
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_1[] =
+{
+	{{0x65,0x4f,0x89,0x56,0x83,0xaf,0x1f,
+	  0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
+	  0x00 }},
+	{{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f,
+	  0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
+	  0x00 }},
+	{{0x65,0x4f,0x89,0x56,0x83,0xaf,0x1f,
+	  0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
+	  0x00 }},
+	{{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f,
+	  0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
+	  0x00 }},
+	{{0x65,0x4f,0x89,0x56,0x83,0x04,0x3e,
+	  0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05,
+	  0x00 }},
+	{{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
+	  0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
+	  0x01 }}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_1_H[] =
+{
+	{{0x30,0x27,0x94,0x2c,0x92,0xaf,0x1f,
+	  0x90,0x85,0x8f,0xab,0x30,0x00,0x04,
+	  0x00 }},
+	{{0x30,0x27,0x94,0x2c,0x92,0x83,0x1f,
+	  0x5e,0x83,0x5d,0x79,0x10,0x00,0x04,
+	  0x00 }},
+	{{0x30,0x27,0x94,0x2c,0x92,0xaf,0x1f,
+	  0x90,0x85,0x8f,0xab,0x30,0x00,0x04,
+	  0x00 }},
+	{{0x30,0x27,0x94,0x2c,0x92,0x83,0x1f,
+	  0x5e,0x83,0x5d,0x79,0x10,0x00,0x04,
+	  0x00 }},
+	{{0x30,0x27,0x94,0x2c,0x92,0x04,0x3e,
+	  0xe0,0x85,0xdf,0xfb,0x10,0x00,0x04,
+	  0x00 }},
+	{{0x3d,0x31,0x81,0x37,0x1f,0x72,0xf0,
+	  0x58,0x8c,0x57,0x73,0x20,0x00,0x05,
+	  0x01 }}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_1[] =
+{
+	{{0x64,0x4f,0x88,0x54,0x9f,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+	  0x00}},
+	{{0x64,0x4f,0x88,0x54,0x9f,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
+	  0x00}},
+	{{0x64,0x4f,0x88,0x54,0x9f,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+	  0x00}},
+	{{0x64,0x4f,0x88,0x54,0x9f,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
+	  0x00}},
+	{{0x64,0x4f,0x88,0x54,0x9f,0x04,0x3e,
+	  0xe2,0x89,0xdf,0x05,0x00,0x00,0x01,
+	  0x00}},
+	{{0x7e,0x63,0x82,0x68,0x15,0x7c,0xf0,
+	  0x5a,0x8f,0x57,0x7d,0x20,0x00,0x26,
+	  0x01}},
+	{{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+	  0x01}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_1_H[] =
+{
+	{{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+	  0x00 }},
+	{{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f,
+	  0x60,0x87,0x5D,0x83,0x10,0x00,0x44,
+	  0x00}},
+	{{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+	  0x00}},
+	{{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f,
+	  0x60,0x87,0x5D,0x83,0x10,0x00,0x44,
+	  0x00}},
+	{{0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e,
+	  0xE2,0x89,0xdf,0x05,0x00,0x00,0x44,
+	  0x00}},
+	{{0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0,
+	  0x5A,0x8F,0x57,0x7D,0x20,0x00,0x55,
+	  0x01}},
+	{{0x4f,0x3F,0x93,0x45,0x0D,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+	  0x01 }}
+
+#if 0
+	{{0x37,0x27,0x9B,0x2b,0x94,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+	  0x00 }},
+	{{0x37,0x27,0x9B,0x2b,0x94,0x97,0x1f,
+	  0x60,0x87,0x5D,0x83,0x01,0x00,0x44,
+	  0x00}},
+	{{0x37,0x27,0x9B,0x2b,0x94,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+	  0x00}},
+	{{0x37,0x27,0x9B,0x2b,0x94,0x97,0x1f,
+	  0x60,0x87,0x5D,0x83,0x01,0x00,0x44,
+	  0x00}},
+	{{0x37,0x27,0x9B,0x2b,0x94,0x04,0x3e,
+	  0xE2,0x89,0xDf,0x05,0x00,0x00,0x44,
+	  0x00}},
+	{{0x41,0x31,0x85,0x35,0x1d,0x7c,0xf0,
+	  0x5A,0x8F,0x57,0x7D,0x20,0x00,0x55,
+	  0x01}},
+	{{0x4f,0x3F,0x93,0x45,0x0D,0x24,0xf5,
+	  0x02,0x88,0xFf,0x25,0x10,0x00,0x01,
+	  0x01 }}
+#endif
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_1[] =
+{
+	{{0x63,0x4f,0x87,0x54,0x9f,0xb4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+	  0x00 }},
+	{{0x63,0x4f,0x87,0x54,0x9f,0x82,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
+	  0x00 }},
+	{{0x63,0x4f,0x87,0x54,0x9f,0xb4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+	  0x00 }},
+	{{0x63,0x4f,0x87,0x54,0x9f,0x82,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
+	  0x00 }},
+	{{0x63,0x4f,0x87,0x54,0x9f,0x04,0x3e,
+	  0xe2,0x89,0xdf,0x05,0x00,0x00,0x01,
+	  0x00 }},
+	{{0x7e,0x63,0x82,0x68,0x15,0x7c,0xf0,
+	  0x5a,0x8f,0x57,0x7d,0x20,0x00,0x26,
+	  0x01 }},
+	{{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+	  0x01 }}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_1_H[] =
+{
+	{{0x2f,0x27,0x93,0x2b,0x90,0xb4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x04,
+	  0x00 }},
+	{{0x2f,0x27,0x93,0x2b,0x90,0x82,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x04,
+	  0x00 }},
+	{{0x2f,0x27,0x93,0x2b,0x90,0xb4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x04,
+	  0x00 }},
+	{{0x2f,0x27,0x93,0x2b,0x90,0x82,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x04,
+	  0x00 }},
+	{{0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e,
+	  0xe2,0x89,0xdf,0x05,0x00,0x00,0x04,
+	  0x00 }},
+	{{0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0,
+	  0x5a,0x8f,0x57,0x7d,0x20,0x00,0x55,
+	  0x01 }},
+	{{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+	  0x01 }}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_2[] =
+{
+	{{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
+	  0xf4,0x88,0x8f,0x73,0x20,0x00,0x06,
+	  0x00 }},
+	{{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
+	  0xdb,0x8f,0x5d,0x73,0x20,0x00,0x06,
+	  0x00 }},
+	{{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
+	  0xf4,0x88,0x8f,0x73,0x20,0x00,0x06,
+	  0x00 }},
+	{{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
+	  0xdb,0x8f,0x5d,0x73,0x20,0x00,0x06,
+	  0x00 }},
+	{{0x7f,0x4f,0x83,0x62,0x12,0x72,0xba,
+	  0x1c,0x80,0xdf,0x73,0x00,0x00,0x06,
+	  0x00 }},
+	{{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
+	  0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
+	  0x01 }}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_2_H[] =
+{
+	{{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
+	  0xf4,0x88,0x8f,0x73,0x20,0x00,0x05,
+	  0x00 }},
+	{{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
+	  0xdb,0x8f,0x5d,0x73,0x20,0x00,0x05,
+	  0x00 }},
+	{{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
+	  0xf4,0x88,0x8f,0x73,0x20,0x00,0x05,
+	  0x00 }},
+	{{0x3d,0x27,0x81,0x3a,0x1a,0x72,0x3e,
+	  0xdb,0x8f,0x5d,0x73,0x20,0x00,0x05,
+	  0x00 }},
+	{{0x3d,0x27,0x81,0x32,0x1a,0x72,0xba,
+	  0x1c,0x80,0xdf,0x73,0x00,0x00,0x05,
+	  0x00 }},
+	{{0x3d,0x31,0x81,0x37,0x1f,0x72,0xf0,
+	  0x58,0x8c,0x57,0x73,0x20,0x00,0x05,
+	  0x01 }}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_2[] =
+{
+	{{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+	  0x00 }},
+	{{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+	  0x00 }},
+	{{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+	  0x00 }},
+	{{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+	  0x00 }},
+	{{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x72,0x88,0xdf,0x25,0x30,0x00,0x06,
+	  0x00 }},
+	{{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1,
+	  0xae,0x84,0x57,0x25,0x30,0x00,0x02,
+	  0x01 }},
+	{{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+	  0x01 }}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_2_H[] =
+{
+	{{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+	  0x00 }},
+	{{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+	  0x00 }},
+	{{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+	  0x00 }},
+	{{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+	  0x00 }},
+	{{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x72,0x88,0xdf,0x25,0x30,0x00,0x01,
+	  0x00 }},
+	{{0x4f,0x31,0x93,0x3e,0x06,0x24,0xf1,
+	  0xae,0x84,0x57,0x25,0x30,0x00,0x01,
+	  0x01 }},
+	{{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+	  0x01 }}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_2[] =
+{
+	{{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+	  0x00 }},
+	{{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+	  0x00 }},
+	{{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+	  0x00 }},
+	{{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+	  0x00 }},
+	{{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x72,0x88,0xdf,0x25,0x30,0x00,0x06,
+	  0x00 }},
+	{{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1,
+	  0xae,0x84,0x57,0x25,0x30,0x00,0x02,
+	  0x01 }},
+	{{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+	  0x01 }}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_2_H[] =
+{
+	{{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+	  0x00 }},
+	{{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+	  0x00 }},
+	{{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+	  0x00 }},
+	{{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+	  0x00 }},
+	{{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
+	  0x72,0x88,0xdf,0x25,0x30,0x00,0x01,
+	  0x00 }},
+	{{0x4f,0x31,0x93,0x3e,0x86,0x24,0xf1,
+	  0xae,0x84,0x57,0x25,0x30,0x00,0x01,
+	  0x01 }},
+	{{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+	  0x01}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT1XXXxXXX_1[] =
+{
+ {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
+   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x05,
+   0x00}},
+ {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
+   0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
+   0x01}},
+ {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
+   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+   0x01}},
+ {{0xce,0x9f,0x92,0xa8,0x14,0x28,0x5a,
+   0x00,0x84,0xff,0x29,0x09,0x00,0x07,
+   0x01}},
+ {{0xce,0x9f,0x92,0xa9,0x17,0x24,0xf5,
+   0x02,0x88,0xff,0x25,0x10,0x00,0x07,
+   0x01}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT1XXXxXXX_1_H[] =
+{
+ {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
+   0x00}},
+ {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
+   0x00}},
+ {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
+   0x00}},
+ {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
+   0x00}},
+ {{0x38,0x27,0x9c,0x2c,0x80,0x0b,0x3e,
+   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00,
+   0x00}},
+ {{0x4d,0x31,0x91,0x3b,0x03,0x72,0xf0,
+   0x58,0x8c,0x57,0x73,0x20,0x00,0x01,
+   0x01}},
+ {{0x63,0x3f,0x87,0x4a,0x92,0x24,0xf5,
+   0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+   0x01}}
+};
+
+
+static const SiS_LVDSCRT1DataStruct  SiS300_CHTVCRT1UNTSC[] =
+{
+	{{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
+	  0xe8,0x84,0x8f,0x57,0x20,0x00,0x01,
+	  0x00 }},
+	{{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
+	  0xd0,0x82,0x5d,0x57,0x00,0x00,0x01,
+	  0x00 }},
+	{{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
+	  0xe8,0x84,0x8f,0x57,0x20,0x00,0x01,
+	  0x00 }},
+	{{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
+	  0xd0,0x82,0x5d,0x57,0x00,0x00,0x01,
+	  0x00 }},
+	{{0x5d,0x4f,0x81,0x53,0x9c,0x56,0xba,
+	  0x18,0x84,0xdf,0x57,0x00,0x00,0x01,
+	  0x00 }},
+	{{0x80,0x63,0x84,0x6c,0x17,0xec,0xf0,
+	  0x90,0x8c,0x57,0xed,0x20,0x00,0x06,
+	  0x01 }}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS300_CHTVCRT1ONTSC[] =
+{
+	{{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
+	  0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01,
+	  0x00 }},
+	{{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
+	  0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01,
+	  0x00 }},
+	{{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
+	  0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01,
+	  0x00 }},
+	{{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
+	  0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01,
+	  0x00 }},
+	{{0x5d,0x4f,0x81,0x56,0x9c,0x0b,0x3e,
+	  0xe8,0x84,0xdf,0x0c,0x00,0x00,0x01,
+	  0x00 }},
+	{{0x7d,0x63,0x81,0x6a,0x16,0xba,0xf0,
+	  0x7f,0x86,0x57,0xbb,0x00,0x00,0x06,
+	  0x01 }}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS300_CHTVCRT1UPAL[] =
+{
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xf8,0x83,0x8f,0x70,0x20,0x00,0x05,
+	  0x00 }},
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
+	  0x00 }},
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xf8,0x83,0x8f,0x70,0x20,0x00,0x05,
+	  0x00 }},
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
+	  0x00 }},
+	{{0x64,0x4f,0x88,0x55,0x80,0xec,0xba,
+	  0x50,0x84,0xdf,0xed,0x00,0x00,0x05,
+	  0x00 }},
+	{{0x70,0x63,0x94,0x68,0x8d,0x42,0xf1,
+	  0xc8,0x8c,0x57,0xe9,0x20,0x00,0x05,
+	  0x01 }}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS300_CHTVCRT1OPAL[] =
+{
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,
+	  0x00 }},
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
+	  0x00 }},
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,
+	  0x00 }},
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
+	  0x00 }},
+	{{0x64,0x4f,0x88,0x55,0x80,0x6f,0xba,
+	  0x20,0x83,0xdf,0x70,0x00,0x00,0x05,
+	  0x00 }},
+	{{0x73,0x63,0x97,0x69,0x8e,0xec,0xf0,
+	  0x90,0x8c,0x57,0xed,0x20,0x00,0x05,
+	  0x01 }}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS300_CHTVCRT1SOPAL[] =
+{
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,
+	  0x00 }},
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
+	  0x00 }},
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,
+	  0x00 }},
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
+	  0x00 }},
+	{{0x64,0x4f,0x88,0x55,0x80,0x6f,0xba,  /* TODO */
+	  0x20,0x83,0xdf,0x70,0x00,0x00,0x05,
+	  0x00 }},
+	{{0x73,0x63,0x97,0x69,0x8e,0xec,0xf0,  /* TODO */
+	  0x90,0x8c,0x57,0xed,0x20,0x00,0x05,
+	  0x01 }}
+};
+
+static const SiS_CHTVRegDataStruct SiS300_CHTVReg_UNTSC[] =
+{
+	{{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x6a,0x6a,0x00,0x2d,0xfa,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 17: 640x480 NTSC 7/8  */
+	{{0x8d,0xc4,0x00,0x3b,0xfb,0,0,0,0,0,0,0,0,0,0,0}}  /* Mode 24: 800x600 NTSC 7/10 */
+};
+
+static const SiS_CHTVRegDataStruct SiS300_CHTVReg_ONTSC[] =
+{
+	{{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x69,0x6a,0x00,0x1e,0xfd,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 16: 640x480 NTSC 1/1 */
+	{{0x8c,0xb4,0x00,0x32,0xf9,0,0,0,0,0,0,0,0,0,0,0}}  /* Mode 23: 800x600 NTSC 3/4 */
+};
+
+static const SiS_CHTVRegDataStruct SiS300_CHTVReg_UPAL[] =
+{
+	{{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x63,0x94,0x01,0x50,0x30,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 15: 640x480 PAL 5/6 */
+	{{0x84,0x64,0x01,0x4e,0x2f,0,0,0,0,0,0,0,0,0,0,0}}  /* Mode 21: 800x600 PAL 3/4 */
+
+};
+
+static const SiS_CHTVRegDataStruct SiS300_CHTVReg_OPAL[] =
+{
+	{{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 9: 640x400 PAL 1/1 */
+	{{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x61,0x94,0x01,0x36,0x30,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 14: 640x480 PAL 1/1 */
+	{{0x83,0x76,0x01,0x40,0x31,0,0,0,0,0,0,0,0,0,0,0}}  /* Mode 20: 800x600 PAL 5/6 */
+
+};
+
+static const SiS_CHTVRegDataStruct SiS300_CHTVReg_SOPAL[] =
+{
+	{{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 9: 640x400 PAL 1/1 */
+	{{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x60,0x30,0x00,0x10,0x00,0,0,0,0,0,0,0,0,0,0,0}}, /* TW: Mode 13: 640x480 PAL 5/4 */
+	{{0x81,0x50,0x00,0x1b,0x00,0,0,0,0,0,0,0,0,0,0,0}}  /* TW: Mode 19: 800x600 PAL 1/1 */
+};
+
+static const UCHAR SiS300_CHTVVCLKUNTSC[]  = {0x29,0x29,0x29,0x29,0x2a,0x2e};
+
+static const UCHAR SiS300_CHTVVCLKONTSC[]  = {0x2c,0x2c,0x2c,0x2c,0x2d,0x2b};
+
+static const UCHAR SiS300_CHTVVCLKSONTSC[] = {0x2c,0x2c,0x2c,0x2c,0x2d,0x2b};
+
+static const UCHAR SiS300_CHTVVCLKUPAL[]   = {0x2f,0x2f,0x2f,0x2f,0x2f,0x31};
+
+static const UCHAR SiS300_CHTVVCLKOPAL[]   = {0x2f,0x2f,0x2f,0x2f,0x30,0x32};
+
+static const UCHAR SiS300_CHTVVCLKSOPAL[]  = {0x2f,0x2f,0x2f,0x2f,0x36,0x29};
+
+
diff --git a/drivers/video/sis/310vtbl.h b/drivers/video/sis/310vtbl.h
new file mode 100644
index 0000000..2c71d04
--- /dev/null
+++ b/drivers/video/sis/310vtbl.h
@@ -0,0 +1,2754 @@
+/* $XFree86$ */
+/* $XdotOrg$ */
+/*
+ * Register settings for SiS 315/330 series
+ *
+ * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, the following license terms
+ * apply:
+ *
+ * * This program is free software; you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License as published by
+ * * the Free Software Foundation; either version 2 of the named License,
+ * * or any later version.
+ * *
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details.
+ * *
+ * * You should have received a copy of the GNU General Public License
+ * * along with this program; if not, write to the Free Software
+ * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * * Redistribution and use in source and binary forms, with or without
+ * * modification, are permitted provided that the following conditions
+ * * are met:
+ * * 1) Redistributions of source code must retain the above copyright
+ * *    notice, this list of conditions and the following disclaimer.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * *    notice, this list of conditions and the following disclaimer in the
+ * *    documentation and/or other materials provided with the distribution.
+ * * 3) The name of the author may not be used to endorse or promote products
+ * *    derived from this software without specific prior written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ */
+
+static const SiS_StStruct SiS310_SModeIDTable[]=
+{
+	{0x01,0x9208,0x01,0x00,0x00,0x00,0x01,0x00, 0x40},
+	{0x01,0x1210,0x14,0x01,0x01,0x00,0x01,0x00, 0x40},
+	{0x01,0x1010,0x17,0x02,0x02,0x00,0x01,0x01, 0x40},
+	{0x03,0x8208,0x03,0x00,0x00,0x00,0x01,0x02, 0x40},
+	{0x03,0x0210,0x16,0x01,0x01,0x00,0x01,0x02, 0x40},
+	{0x03,0x0010,0x18,0x02,0x02,0x00,0x01,0x03, 0x40},
+	{0x05,0x9209,0x05,0x00,0x00,0x00,0x00,0x04, 0x40},
+	{0x06,0x8209,0x06,0x00,0x00,0x00,0x00,0x05, 0x40},
+	{0x07,0x0000,0x07,0x03,0x03,0x00,0x01,0x03, 0x40},
+	{0x07,0x0000,0x19,0x02,0x02,0x00,0x01,0x03, 0x40},
+	{0x0d,0x920a,0x0d,0x00,0x00,0x00,0x00,0x04, 0x40},
+	{0x0e,0x820a,0x0e,0x00,0x00,0x00,0x00,0x05, 0x40},
+	{0x0f,0x0202,0x11,0x01,0x01,0x00,0x00,0x05, 0x40},
+	{0x10,0x0212,0x12,0x01,0x01,0x00,0x00,0x05, 0x40},
+	{0x11,0x0212,0x1a,0x04,0x04,0x00,0x00,0x05, 0x40},
+	{0x12,0x0212,0x1b,0x04,0x04,0x00,0x00,0x05, 0x40},
+	{0x13,0x021b,0x1c,0x00,0x00,0x00,0x00,0x04, 0x40},
+	{0x12,0x0010,0x18,0x02,0x02,0x00,0x00,0x05, 0x40},
+	{0x12,0x0210,0x18,0x01,0x01,0x00,0x00,0x05, 0x40},
+	{0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00, 0x40}
+};
+
+static const SiS_ExtStruct  SiS310_EModeIDTable[]=
+{
+	{0x6a,0x2212,0x0102,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x? */
+	{0x2e,0x0a1b,0x0101,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x8 */
+        {0x2f,0x0a1b,0x0100,SIS_RI_640x400,  0x00,0x00,0x05,0x05,0x10, 0}, /* 640x400x8 */
+	{0x30,0x2a1b,0x0103,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x8 */
+        {0x31,0x4a1b,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x8 */
+	{0x32,0x4a1b,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x8 */
+	{0x33,0x4a1d,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x16 */
+	{0x34,0x6a1d,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x16 */
+	{0x35,0x4a1f,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x32 */
+	{0x36,0x6a1f,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x32 */
+	{0x37,0x0212,0x0104,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x? */
+	{0x38,0x0a1b,0x0105,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x8 */
+	{0x3a,0x0e3b,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a, 8}, /* 1280x1024x8 */
+	{0x3c,0x0e3b,0x0130,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e,10}, /* 1600x1200x8 */
+	{0x3d,0x0e7d,0x0131,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e,10}, /* 1600x1200x16 */
+	{0x40,0x9a1c,0x010d,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x25, 0}, /* 320x200x15 */
+	{0x41,0x9a1d,0x010e,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x25, 0}, /* 320x200x16 */
+	{0x43,0x0a1c,0x0110,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08, 2},
+	{0x44,0x0a1d,0x0111,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x16 */
+	{0x46,0x2a1c,0x0113,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00, 3},
+	{0x47,0x2a1d,0x0114,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x16 */
+	{0x49,0x0a3c,0x0116,SIS_RI_1024x768, 0x00,0x00,0x00,0x07,0x13, 4},
+	{0x4a,0x0a3d,0x0117,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x16 */
+	{0x4c,0x0e7c,0x0119,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a, 8},
+	{0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a, 8}, /* 1280x1024x16 */
+	{0x50,0x9a1b,0x0132,SIS_RI_320x240,  0x00,0x00,0x04,0x04,0x26, 2}, /* 320x240x8  */
+	{0x51,0xba1b,0x0133,SIS_RI_400x300,  0x00,0x00,0x07,0x07,0x27, 3}, /* 400x300x8  */
+  	{0x52,0xba1b,0x0134,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x28, 4}, /* 512x384x8  */
+	{0x56,0x9a1d,0x0135,SIS_RI_320x240,  0x00,0x00,0x04,0x04,0x26, 2}, /* 320x240x16 */
+	{0x57,0xba1d,0x0136,SIS_RI_400x300,  0x00,0x00,0x07,0x07,0x27, 3}, /* 400x300x16 */
+ 	{0x58,0xba1d,0x0137,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x28, 4}, /* 512x384x16 */
+	{0x59,0x9a1b,0x0138,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x25, 0}, /* 320x200x8  */
+	{0x5a,0x021b,0x0138,SIS_RI_320x240,  0x00,0x00,0x00,0x00,0x3f, 2}, /* 320x240x8  fstn */
+	{0x5b,0x0a1d,0x0135,SIS_RI_320x240,  0x00,0x00,0x00,0x00,0x3f, 2}, /* 320x240x16 fstn */
+	{0x5c,0xba1f,0x0000,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x28, 4}, /* 512x384x32 */
+	{0x5d,0x0a1d,0x0139,SIS_RI_640x400,  0x00,0x00,0x05,0x07,0x10, 0},
+	{0x5e,0x0a1f,0x0000,SIS_RI_640x400,  0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x32 */
+	{0x62,0x0a3f,0x013a,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x32 */
+	{0x63,0x2a3f,0x013b,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x32 */
+	{0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x32 */
+	{0x65,0x0eff,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a, 8}, /* 1280x1024x32 */
+	{0x66,0x0eff,0x013e,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e,10}, /* 1600x1200x32 */
+	{0x68,0x067b,0x013f,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x29,-1}, /* 1920x1440x8 */
+	{0x69,0x06fd,0x0140,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x29,-1}, /* 1920x1440x16 */
+	{0x6b,0x07ff,0x0141,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x29,-1}, /* 1920x1440x32 */
+	{0x6c,0x067b,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x2f,-1}, /* 2048x1536x8 */
+	{0x6d,0x06fd,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x2f,-1}, /* 2048x1536x16 */
+	{0x6e,0x07ff,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x2f,-1}, /* 2048x1536x32 */
+	{0x70,0x6a1b,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x07,0x34,-1}, /* 800x480x8 */
+	{0x71,0x4a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x37,-1}, /* 1024x576x8 */
+	{0x74,0x4a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x37,-1}, /* 1024x576x16 */
+	{0x75,0x0a3d,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x3a, 5}, /* 1280x720x16 */
+	{0x76,0x6a1f,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x07,0x34,-1}, /* 800x480x32 */
+	{0x77,0x4a1f,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x37,-1}, /* 1024x576x32 */
+	{0x78,0x0a3f,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x3a, 5}, /* 1280x720x32 */
+	{0x79,0x0a3b,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x3a, 5}, /* 1280x720x8 */
+	{0x7a,0x6a1d,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x07,0x34,-1}, /* 800x480x16 */
+	{0x7c,0x0e3b,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x3d,-1}, /* 1280x960x8 */
+	{0x7d,0x0e7d,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x3d,-1}, /* 1280x960x16 */
+	{0x7e,0x0eff,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x3d,-1}, /* 1280x960x32 */
+	{0x23,0x0e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x40, 6}, /* 1280x768x8 */
+	{0x24,0x0e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x40, 6}, /* 1280x768x16 */
+	{0x25,0x0eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x40, 6}, /* 1280x768x32 */
+	{0x26,0x0e3b,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x41, 9}, /* 1400x1050x8 */
+	{0x27,0x0e7d,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x41, 9}, /* 1400x1050x16 */
+	{0x28,0x0eff,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x41, 9}, /* 1400x1050x32*/
+	{0x29,0x4e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x43,-1}, /* 1152x864 */
+	{0x2a,0x4e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x43,-1},
+	{0x2b,0x4e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x43,-1},
+	{0x39,0x6a1b,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x46,-1}, /* 848x480 */
+	{0x3b,0x6a3d,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x46,-1},
+	{0x3e,0x6a7f,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x46,-1},
+	{0x3f,0x6a1b,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x48,-1}, /* 856x480 */
+	{0x42,0x6a3d,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x48,-1},
+	{0x45,0x6a7f,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x48,-1},
+	{0x48,0x6a3b,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x4a,-1}, /* 1360x768 */
+	{0x4b,0x6a7d,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x4a,-1},
+	{0x4e,0x6aff,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x4a,-1},
+	{0x4f,0x9a1f,0x0000,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x25, 0}, /* 320x200x32 */
+	{0x53,0x9a1f,0x0000,SIS_RI_320x240,  0x00,0x00,0x04,0x04,0x26, 2}, /* 320x240x32 */
+	{0x54,0xba1f,0x0000,SIS_RI_400x300,  0x00,0x00,0x07,0x07,0x27, 3}, /* 400x300x32 */
+	{0x5f,0x6a1b,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x06,0x4b,-1}, /* 768x576 */
+	{0x60,0x6a1d,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x06,0x4b,-1},
+	{0x61,0x6a3f,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x06,0x4b,-1},
+	{0x14,0x0e3b,0x0000,SIS_RI_1280x800, 0x00,0x00,0x00,0x00,0x4c, 7}, /* 1280x800 */
+	{0x15,0x0e7d,0x0000,SIS_RI_1280x800, 0x00,0x00,0x00,0x00,0x4c, 7},
+	{0x16,0x0eff,0x0000,SIS_RI_1280x800, 0x00,0x00,0x00,0x00,0x4c, 7},
+	{0x17,0x0e3b,0x0000,SIS_RI_1680x1050,0x00,0x00,0x00,0x00,0x4d, 9}, /* 1680x1050 */
+	{0x18,0x0e7d,0x0000,SIS_RI_1680x1050,0x00,0x00,0x00,0x00,0x4d, 9},
+	{0x19,0x0eff,0x0000,SIS_RI_1680x1050,0x00,0x00,0x00,0x00,0x4d, 9},
+	{0x2c,0x267b,0x0000,SIS_RI_1920x1080,0x00,0x00,0x00,0x00,0x4e,-1}, /* 1920x1080(i) */
+	{0x2d,0x26fd,0x0000,SIS_RI_1920x1080,0x00,0x00,0x00,0x00,0x4e,-1},
+	{0x73,0x27ff,0x0000,SIS_RI_1920x1080,0x00,0x00,0x00,0x00,0x4e,-1},
+	{0x1d,0x6a1b,0x0000,SIS_RI_960x540,  0x00,0x00,0x00,0x00,0x4f,-1}, /* 960x540 */
+	{0x1e,0x6a3d,0x0000,SIS_RI_960x540,  0x00,0x00,0x00,0x00,0x4f,-1},
+	{0x1f,0x6a7f,0x0000,SIS_RI_960x540,  0x00,0x00,0x00,0x00,0x4f,-1},
+	{0x20,0x6a1b,0x0000,SIS_RI_960x600,  0x00,0x00,0x00,0x00,0x50,-1}, /* 960x600 */
+	{0x21,0x6a3d,0x0000,SIS_RI_960x600,  0x00,0x00,0x00,0x00,0x50,-1},
+	{0x22,0x6a7f,0x0000,SIS_RI_960x600,  0x00,0x00,0x00,0x00,0x50,-1},
+	{0xff,0x0000,0x0000,0,               0x00,0x00,0x00,0x00,0x00,-1}
+};
+
+static const SiS_Ext2Struct SiS310_RefIndex[]=
+{
+	{0x085f,0x0d,0x03,0x05,0x05,0x6a, 800, 600, 0x40}, /* 0x0 */
+	{0x0067,0x0e,0x04,0x05,0x05,0x6a, 800, 600, 0x40}, /* 0x1 */
+	{0x0067,0x0f,0x08,0x48,0x05,0x6a, 800, 600, 0x40}, /* 0x2 */
+	{0x0067,0x10,0x07,0x8b,0x05,0x6a, 800, 600, 0x40}, /* 0x3 */
+	{0x0047,0x11,0x0a,0x00,0x05,0x6a, 800, 600, 0x40}, /* 0x4 */
+	{0x0047,0x12,0x0d,0x00,0x05,0x6a, 800, 600, 0x40}, /* 0x5 */
+	{0x0047,0x13,0x13,0x00,0x05,0x6a, 800, 600, 0x20}, /* 0x6 */
+	{0x0107,0x14,0x1c,0x00,0x05,0x6a, 800, 600, 0x20}, /* 0x7 */
+	{0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0x40}, /* 0x8 */
+	{0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0x40}, /* 0x9 */
+	{0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0x40}, /* 0xa */
+	{0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0x40}, /* 0xb */
+	{0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0x40}, /* 0xc */
+	{0xc047,0x0a,0x09,0x00,0x04,0x2e, 640, 480, 0x40}, /* 0xd */
+	{0xc047,0x0b,0x0e,0x00,0x04,0x2e, 640, 480, 0x40}, /* 0xe */
+	{0xc047,0x0c,0x15,0x00,0x04,0x2e, 640, 480, 0x40}, /* 0xf */
+	{0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0x30}, /* 0x10 */
+	{0xc06f,0x3c,0x01,0x06,0x13,0x31, 720, 480, 0x30}, /* 0x11 */
+	{0x006f,0x3d,0x03,0x06,0x14,0x32, 720, 576, 0x30}, /* 0x12 */
+	{0x0087,0x15,0x06,0x00,0x06,0x37,1024, 768, 0x30}, /* 0x13 */
+	{0xc877,0x16,0x0b,0x06,0x06,0x37,1024, 768, 0x20}, /* 0x14 */
+	{0xc067,0x17,0x0f,0x49,0x06,0x37,1024, 768, 0x20}, /* 0x15 */
+	{0x0067,0x18,0x11,0x00,0x06,0x37,1024, 768, 0x20}, /* 0x16 */
+	{0x0047,0x19,0x16,0x8c,0x06,0x37,1024, 768, 0x20}, /* 0x17 */
+	{0x0107,0x1a,0x1b,0x00,0x06,0x37,1024, 768, 0x10}, /* 0x18 */
+	{0x0107,0x1b,0x1f,0x00,0x06,0x37,1024, 768, 0x10}, /* 0x19 */
+	{0x0087,0x1c,0x11,0x00,0x07,0x3a,1280,1024, 0x30}, /* 0x1a */
+	{0x0137,0x1d,0x19,0x07,0x07,0x3a,1280,1024, 0x00}, /* 0x1b */
+	{0x0107,0x1e,0x1e,0x00,0x07,0x3a,1280,1024, 0x00}, /* 0x1c */
+	{0x0207,0x1f,0x20,0x00,0x07,0x3a,1280,1024, 0x00}, /* 0x1d */
+	{0x0227,0x20,0x21,0x09,0x09,0x3c,1600,1200, 0x00}, /* 0x1e */
+	{0x0407,0x21,0x22,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x1f */
+	{0x0407,0x22,0x23,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x20 */
+	{0x0407,0x23,0x25,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x21 */
+	{0x0007,0x24,0x26,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x22 */
+	{0x0007,0x25,0x2c,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x23 */
+	{0x0007,0x26,0x34,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x24 */
+	{0x407f,0x00,0x00,0x00,0x00,0x40, 320, 200, 0x30}, /* 0x25 */
+	{0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0x30}, /* 0x26 */
+	{0x007f,0x02,0x04,0x05,0x05,0x51, 400, 300, 0x30}, /* 0x27 */
+	{0xc077,0x03,0x0b,0x06,0x06,0x52, 512, 384, 0x30}, /* 0x28 */
+	{0x8007,0x27,0x27,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x29 */
+	{0x4007,0x28,0x29,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x2a */
+	{0x4007,0x29,0x2e,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x2b */
+	{0x4007,0x2a,0x30,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x2c */
+	{0x4007,0x2b,0x35,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x2d */
+	{0x4005,0x2c,0x39,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x2e */
+	{0x4007,0x2d,0x2b,0x00,0x00,0x6c,2048,1536, 0x00}, /* 0x2f */
+	{0x4007,0x2e,0x31,0x00,0x00,0x6c,2048,1536, 0x00}, /* 0x30 */
+	{0x4007,0x2f,0x33,0x00,0x00,0x6c,2048,1536, 0x00}, /* 0x31 */
+	{0x4007,0x30,0x37,0x00,0x00,0x6c,2048,1536, 0x00}, /* 0x32 */
+	{0x4005,0x31,0x38,0x00,0x00,0x6c,2048,1536, 0x00}, /* 0x33 */
+	{0x0077,0x32,0x40,0x08,0x18,0x70, 800, 480, 0x30}, /* 0x34 */
+	{0x0047,0x33,0x07,0x08,0x18,0x70, 800, 480, 0x30}, /* 0x35 */
+	{0x0047,0x34,0x0a,0x08,0x18,0x70, 800, 480, 0x30}, /* 0x36 */
+	{0x0077,0x35,0x0b,0x09,0x19,0x71,1024, 576, 0x30}, /* 0x37 */
+	{0x0047,0x36,0x11,0x09,0x19,0x71,1024, 576, 0x30}, /* 0x38 */
+	{0x0047,0x37,0x16,0x09,0x19,0x71,1024, 576, 0x30}, /* 0x39 */
+	{0x1137,0x38,0x19,0x0a,0x0c,0x75,1280, 720, 0x30}, /* 0x3a */
+	{0x1107,0x39,0x1e,0x0a,0x0c,0x75,1280, 720, 0x30}, /* 0x3b */
+	{0x1307,0x3a,0x20,0x0a,0x0c,0x75,1280, 720, 0x30}, /* 0x3c */
+	{0x0127,0x3b,0x19,0x08,0x0a,0x7c,1280, 960, 0x30}, /* 0x3d */
+	{0x0227,0x4c,0x59,0x08,0x0a,0x7c,1280, 960, 0x20}, /* 0x3e */
+	{0xc07f,0x4e,0x00,0x06,0x04,0x5a, 320, 240, 0x30}, /* 0x3f */    /* FSTN 320x240 */
+        {0x0077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30}, /* 0x40 */    /* 0x5b was 0x12 */
+	{0x0127,0x43,0x4d,0x08,0x0b,0x26,1400,1050, 0x30}, /* 0x41 */
+	{0x0207,0x4b,0x5a,0x08,0x0b,0x26,1400,1050, 0x30}, /* 0x42 1400x1050-75Hz */
+	{0x0127,0x54,0x6d,0x00,0x1a,0x29,1152, 864, 0x30}, /* 0x43 1152x864-60Hz  */
+	{0x0127,0x44,0x19,0x00,0x1a,0x29,1152, 864, 0x30}, /* 0x44 1152x864-75Hz  */
+	{0x0127,0x4a,0x1e,0x00,0x1a,0x29,1152, 864, 0x30}, /* 0x45 1152x864-85Hz  */
+	{0x0087,0x45,0x57,0x00,0x16,0x39, 848, 480, 0x30}, /* 0x46 848x480-38Hzi  */
+	{0xc067,0x46,0x55,0x0b,0x16,0x39, 848, 480, 0x30}, /* 0x47 848x480-60Hz   */
+	{0x0087,0x47,0x57,0x00,0x17,0x3f, 856, 480, 0x30}, /* 0x48 856x480-38Hzi  */
+	{0xc067,0x48,0x57,0x00,0x17,0x3f, 856, 480, 0x30}, /* 0x49 856x480-60Hz   */
+	{0x0067,0x49,0x58,0x0c,0x1b,0x48,1360, 768, 0x30}, /* 0x4a 1360x768-60Hz  */
+	{0x006f,0x4d,0x03,0x06,0x15,0x5f, 768, 576, 0x30}, /* 0x4b 768x576-56Hz   */
+	{0x0067,0x4f,0x5c,0x08,0x0d,0x14,1280, 800, 0x30}, /* 0x4c 1280x800-60Hz  */
+	{0x0067,0x50,0x5d,0x0c,0x0e,0x17,1680,1050, 0x30}, /* 0x4d 1680x1050-60Hz */
+	{0x0087,0x51,0x69,0x00,0x00,0x2c,1920,1080, 0x30}, /* 0x4e 1920x1080 60Hzi */
+	{0x0067,0x52,0x6a,0x00,0x1c,0x1d, 960, 540, 0x30}, /* 0x4f 960x540 60Hz */
+	{0x0077,0x53,0x6b,0x0b,0x1d,0x20, 960, 600, 0x30}, /* 0x50 960x600 60Hz */
+	{0xffff,0x00,0x00,0x00,0x00,0x00,   0,   0,    0}
+};
+
+#ifdef LINUX_XF86
+static const struct {
+	UCHAR  Ext_ModeID;     /* ModeID in new ROM */
+	UCHAR  Ext_MyModeID;   /* corresponding ModeID in my tables (0 = identical) */
+	USHORT Ext_VESAID;     /* corresponding VESA ID in new ROM */
+} SiS_EModeIDTable661[] = {
+        { 0x6a, 0x00, 0x0102 },
+	{ 0x1d, 0x20, 0x0000 },
+	{ 0x1e, 0x21, 0x0000 },
+	{ 0x1f, 0x22, 0x0000 },
+	{ 0x20, 0x29, 0x0000 },
+	{ 0x21, 0x2a, 0x0000 },
+	{ 0x22, 0x2b, 0x0000 },
+	{ 0x23, 0x00, 0x011c },
+	{ 0x24, 0x00, 0x011d },
+	{ 0x25, 0x00, 0x011e },
+	{ 0x26, 0x00, 0x011f },
+	{ 0x27, 0x00, 0x0120 },
+	{ 0x28, 0x00, 0x0121 },
+	{ 0x2a, 0x14, 0x013d },
+	{ 0x2b, 0x15, 0x013e },
+	{ 0x2c, 0x16, 0x013f },
+	{ 0x2e, 0x00, 0x0101 },
+	{ 0x2f, 0x00, 0x0100 },
+	{ 0x30, 0x00, 0x0103 },
+	{ 0x37, 0x00, 0x0104 },
+	{ 0x38, 0x00, 0x0105 },
+	{ 0x3a, 0x00, 0x0107 },
+	{ 0x3c, 0x00, 0x0125 },
+	{ 0x3d, 0x00, 0x0126 },
+	{ 0x40, 0x00, 0x010d },
+	{ 0x41, 0x00, 0x010e },
+	{ 0x43, 0x00, 0x0110 },
+	{ 0x44, 0x00, 0x0111 },
+	{ 0x46, 0x00, 0x0113 },
+	{ 0x47, 0x00, 0x0114 },
+	{ 0x49, 0x00, 0x0116 },
+	{ 0x4a, 0x00, 0x0117 },
+	{ 0x4c, 0x00, 0x0119 },
+	{ 0x4d, 0x00, 0x011a },
+	{ 0x50, 0x00, 0x0127 },
+	{ 0x51, 0x00, 0x0128 },
+	{ 0x52, 0x00, 0x0129 },
+	{ 0x56, 0x00, 0x012a },
+	{ 0x57, 0x00, 0x012b },
+	{ 0x58, 0x00, 0x012c },
+	{ 0x59, 0x00, 0x012d },
+	{ 0x5a, 0x17, 0x012e },
+	{ 0x5b, 0x18, 0x012f },
+	{ 0x5c, 0x19, 0x0130 },
+	{ 0x5d, 0x00, 0x0131 },
+	{ 0x62, 0x00, 0x0112 },
+	{ 0x63, 0x00, 0x0115 },
+	{ 0x64, 0x00, 0x0118 },
+	{ 0x65, 0x00, 0x011b },
+	{ 0x66, 0x00, 0x0132 },
+	{ 0x75, 0x00, 0x013a },
+	{ 0x78, 0x00, 0x013b },
+	{ 0x79, 0x00, 0x013c },
+	{ 0x7b, 0x7c, 0x0136 },
+	{ 0x7c, 0x7d, 0x0137 },
+	{ 0x7d, 0x7e, 0x0138 },
+	{ 0xff, 0xff, 0xffff }
+};
+#endif
+
+static const SiS_CRT1TableStruct SiS310_CRT1Table[]=
+{
+ {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00,
+   0x00}}, /* 0x0 */
+ {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
+   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
+   0x00}}, /* 0x1 */
+ {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0,
+   0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05,
+   0x01}}, /* 0x2 */
+ {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01,
+   0x01}}, /* 0x3 */
+ {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05,
+   0x00}}, /* 0x4 */
+#if 0
+ {{0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e,
+   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
+   0x00}}, /* 0x5 */
+#endif
+ {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,    /* 0x05 - corrected 640x480-60 */
+   0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
+   0x00}},
+#if 0   
+ {{0x63,0x4f,0x50,0x86,0x56,0x9b,0x06,0x3e,
+   0xe8,0x8b,0xdf,0xe7,0xff,0x10,0x00,0x01,
+   0x00}}, /* 0x6 */
+#endif
+ {{0x63,0x4f,0x4f,0x87,0x56,0x9b,0x06,0x3e,    /* 0x06 - corrected 640x480-72 */
+   0xe8,0x8a,0xdf,0xe7,0x07,0x00,0x00,0x01,
+   0x00}},
+ {{0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f,
+   0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01,
+   0x00}}, /* 0x7 */
+ {{0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f,
+   0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
+   0x00}}, /* 0x8 */
+ {{0x65,0x4f,0x4f,0x89,0x58,0x80,0xfb,0x1f,
+   0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,  /* Corrected VBE */
+   0x61}}, /* 0x9 */
+ {{0x65,0x4f,0x4f,0x89,0x58,0x80,0x01,0x3e,
+   0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05,
+   0x61}}, /* 0xa */
+ {{0x67,0x4f,0x4f,0x8b,0x58,0x81,0x0d,0x3e,
+   0xe0,0x83,0xdf,0xdf,0x0e,0x00,0x00,0x05,  /* Corrected VBE */
+   0x61}}, /* 0xb */
+ {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f,
+   0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01,  /* Corrected VDE, VBE */
+   0x00}}, /* 0xc */
+ {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0,
+   0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05,
+   0x01}}, /* 0xd */
+ {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0,
+   0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06,
+   0x01}}, /* 0xe */
+ {{0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0,
+   0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06,
+   0x01}}, /* 0xf */
+ {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0,
+   0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06,
+   0x01}}, /* 0x10 */
+ {{0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0,
+   0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06,
+   0x01}}, /* 0x11 */
+ {{0x81,0x63,0x63,0x85,0x6d,0x18,0x7a,0xf0,
+   0x58,0x8b,0x57,0x57,0x7b,0x20,0x00,0x06,
+   0x61}}, /* 0x12 */
+ {{0x83,0x63,0x63,0x87,0x6e,0x19,0x81,0xf0,
+   0x58,0x8b,0x57,0x57,0x82,0x20,0x00,0x06,
+   0x61}}, /* 0x13 */
+ {{0x85,0x63,0x63,0x89,0x6f,0x1a,0x91,0xf0,
+   0x58,0x8b,0x57,0x57,0x92,0x20,0x00,0x06,
+   0x61}}, /* 0x14 */
+ {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f,
+   0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02,
+   0x00}}, /* 0x15 */
+ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
+   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
+   0x01}}, /* 0x16 */
+ {{0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5,
+   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
+   0x01}}, /* 0x17 */
+ {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5,
+   0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02,
+   0x01}}, /* 0x18 */
+ {{0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5,
+   0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02,
+   0x01}}, /* 0x19 */
+ {{0xa9,0x7f,0x7f,0x8d,0x8c,0x9a,0x2c,0xf5,
+   0x00,0x83,0xff,0xff,0x2d,0x14,0x00,0x02,
+   0x62}}, /* 0x1a */
+ {{0xab,0x7f,0x7f,0x8f,0x8d,0x9b,0x35,0xf5,
+   0x00,0x83,0xff,0xff,0x36,0x14,0x00,0x02,
+   0x62}}, /* 0x1b */
+ {{0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba,
+   0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03,
+   0x00}}, /* 0x1c */
+ {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a,
+   0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
+   0x01}}, /* 0x1d */
+ {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a,
+   0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
+   0x01}}, /* 0x1e */
+ {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a,
+   0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07,
+   0x01}}, /* 0x1f */
+ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x20 */
+ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x21 @ 4084 */
+ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x22 */
+ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x23 */
+ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x24 */
+ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x25 */
+ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x26 */
+ {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
+   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
+   0x00}}, /* 0x27 */
+ {{0x43,0xef,0xef,0x87,0x06,0x00,0xd4,0x1f,
+   0xa0,0x83,0x9f,0x9f,0xd5,0x1f,0x41,0x05,
+   0x63}}, /* 0x28 */
+ {{0x45,0xef,0xef,0x89,0x07,0x01,0xd9,0x1f,
+   0xa0,0x83,0x9f,0x9f,0xda,0x1f,0x41,0x05,
+   0x63}}, /* 0x29 */
+ {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
+   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
+   0x00}}, /* 0x2a */
+ {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
+   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
+   0x00}}, /* 0x2b */
+ {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
+   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
+   0x00}}, /* 0x2c */
+ {{0x59,0xff,0xff,0x9d,0x17,0x13,0x33,0xba,
+   0x00,0x83,0xff,0xff,0x34,0x0f,0x41,0x05,
+   0x44}}, /* 0x2d */
+ {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x38,0xba,
+   0x00,0x83,0xff,0xff,0x39,0x0f,0x41,0x05,
+   0x44}}, /* 0x2e */
+ {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x3d,0xba,
+   0x00,0x83,0xff,0xff,0x3e,0x0f,0x41,0x05,
+   0x44}}, /* 0x2f */
+ {{0x5d,0xff,0xff,0x81,0x19,0x95,0x41,0xba,
+   0x00,0x84,0xff,0xff,0x42,0x0f,0x41,0x05,
+   0x44}}, /* 0x30 */
+ {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba,
+   0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05,
+   0x00}}, /* 0x31 */
+ {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba,
+   0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06,
+   0x01}}, /* 0x32 */
+ {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba,
+   0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06,
+   0x01}}, /* 0x33 */
+ {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba,
+   0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06,
+   0x01}}, /* 0x34 */
+ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1,
+   0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02,
+   0x01}}, /* 0x35 */
+ {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1,
+   0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02,
+   0x01}}, /* 0x36 */
+ {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1,   /* 95 was 15 - illegal HBE! */
+   0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02,
+   0x01}}, /* 0x37 */
+ {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4,
+   0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
+   0x01}}, /* 0x38 */
+ {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4,
+   0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
+   0x01}}, /* 0x39 */
+ {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4,
+   0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07,
+   0x01}}, /* 0x3a */
+#if 0   
+ {{0xdc,0x9f,0x9f,0x00,0xab,0x19,0xe6,0xef,	/* 1280x960 - invalid */
+   0xc0,0xc3,0xbf,0xbf,0xe7,0x10,0x00,0x07,
+   0x01}}, /* 0x3b */
+#endif  
+ {{0xdc,0x9f,0x9f,0x80,0xaf,0x9d,0xe6,0xff,	/* 1280x960-60 - corrected */
+   0xc0,0x83,0xbf,0xbf,0xe7,0x10,0x00,0x07,
+   0x01}}, /* 0x3b */ 
+ {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e,
+   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
+   0x00}}, /* 0x3c */
+ {{0x7b,0x59,0x63,0x9f,0x6a,0x93,0x6f,0xf0,
+   0x58,0x8a,0x3f,0x57,0x70,0x20,0x00,0x05,
+   0x01}}, /* 0x3d */
+ {{0x86,0x6a,0x6a,0x8a,0x74,0x06,0x8c,0x15,
+   0x4f,0x83,0xef,0xef,0x8d,0x30,0x00,0x02,
+   0x00}}, /* 0x3e */
+ {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e,
+   0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02,
+   0x00}}, /* 0x3f */
+ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1,
+   0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02,
+   0x01}},  /* 0x40 */
+ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
+   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
+   0x01}},  /* 0x41 */
+ {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x20,0xf5,
+   0x03,0x88,0xff,0xff,0x21,0x10,0x00,0x07,
+   0x01}},  /* 0x42 */
+ {{0xe6,0xae,0xae,0x8a,0xbd,0x90,0x3d,0x10,
+   0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x00,0x03,
+   0x00}},  /* 0x43 */
+ {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef, /* 1152x864-75 */
+   0x60,0x83,0x5f,0x5f,0x83,0x10,0x00,0x07,
+   0x01}},  /* 0x44 */
+ {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15, /* 848x480-38i */
+   0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
+   0x00}},  /* 0x45 */
+ {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E, /* 848x480-60 */
+   0xE5,0x8d,0xDF,0xe4,0x04,0x00,0x00,0x06,
+   0x00}},  /* 0x46 */
+ {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15, /* 856x480-38i */
+   0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
+   0x00}},  /* 0x47 */
+ {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E, /* 856x480-60 */
+   0xEB,0x8E,0xDF,0xDF,0x10,0x00,0x00,0x02,
+   0x00}},  /* 0x48 */
+ {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd, /* 1360x768-60 */
+   0x01,0x8d,0xff,0x00,0x27,0x10,0x00,0x03,
+   0x01}},  /* 0x49 */
+ {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff, /* 1152x864-84  */
+   0x60,0x8b,0x5f,0x5f,0x8b,0x10,0x00,0x03,
+   0x01}},  /* 0x4a */
+ {{0xea,0xae,0xae,0x8e,0xba,0x82,0x40,0x10, /* 1400x1050-75  */
+   0x1b,0x87,0x19,0x1a,0x41,0x0f,0x00,0x03,
+   0x00}},  /* 0x4b */
+ {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff, /* 1280x960-85 */
+   0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07,
+   0x01}},  /* 0x4c */
+ {{0x7b,0x5f,0x63,0x9f,0x6a,0x93,0x6f,0xf0, /* 768x576 */
+   0x58,0x8a,0x3f,0x57,0x70,0x20,0x00,0x05,
+   0x01}},  /* 0x4d */
+ {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e, /* FSTN 320x480, TEMP - possibly invalid */
+   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
+   0x00}},  /* 0x4e */
+ {{0xcd,0x9f,0x9f,0x91,0xab,0x1c,0x3a,0xff, /* 1280x800-60 */
+   0x20,0x83,0x1f,0x1f,0x3b,0x10,0x00,0x07,
+   0x21}},  /* 0x4f */
+ {{0x15,0xd1,0xd1,0x99,0xe2,0x19,0x3d,0x10, /* 1680x1050-60 */
+   0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x01,0x0c,
+   0x20}},  /* 0x50 */
+ {{0x0e,0xef,0xef,0x92,0xfe,0x03,0x30,0xf0, /* 1920x1080-60i */
+   0x1e,0x83,0x1b,0x1c,0x31,0x00,0x01,0x00,
+   0x61}},  /* 0x51 */
+ {{0x85,0x77,0x77,0x89,0x7d,0x01,0x31,0xf0, /* 960x540-60 */
+   0x1e,0x84,0x1b,0x1c,0x32,0x00,0x00,0x02,
+   0x41}},  /* 0x52 */
+ {{0x87,0x77,0x77,0x8b,0x81,0x0b,0x68,0xf0, /* 960x600-60 */
+   0x5a,0x80,0x57,0x57,0x69,0x00,0x00,0x02,
+   0x01}},  /* 0x53 */
+ {{0xcd,0x8f,0x8f,0x91,0x9b,0x1b,0x7a,0xff, /* 1152x864-60 */
+   0x64,0x8c,0x5f,0x62,0x7b,0x10,0x00,0x07,
+   0x41}}   /* 0x54 */
+};
+
+static const SiS_MCLKDataStruct SiS310_MCLKData_0_315[] =
+{
+	{ 0x3b,0x22,0x01,143},
+	{ 0x5c,0x23,0x01,166},
+	{ 0x5c,0x23,0x01,166},
+	{ 0x5c,0x23,0x01,166},
+	{ 0x5c,0x23,0x01,166},
+	{ 0x5c,0x23,0x01,166},
+	{ 0x5c,0x23,0x01,166},
+	{ 0x5c,0x23,0x01,166}
+};
+
+static const SiS_MCLKDataStruct SiS310_MCLKData_0_650[] =
+{
+	{ 0x5a,0x64,0x82, 66},
+	{ 0xb3,0x45,0x82, 83},
+	{ 0x37,0x61,0x82,100},
+	{ 0x37,0x22,0x82,133},
+	{ 0x37,0x61,0x82,100},
+	{ 0x37,0x22,0x82,133},
+	{ 0x37,0x22,0x82,133},
+	{ 0x37,0x22,0x82,133}
+};
+
+static const SiS_MCLKDataStruct SiS310_MCLKData_0_330[] =
+{
+	{ 0x5c,0x23,0x01,166},
+	{ 0x5c,0x23,0x01,166},
+	{ 0x7c,0x08,0x01,200},
+	{ 0x79,0x06,0x01,250},
+	{ 0x7c,0x08,0x01,200},
+	{ 0x7c,0x08,0x01,200},
+	{ 0x7c,0x08,0x01,200},
+	{ 0x79,0x06,0x01,250}
+};
+
+static const SiS_MCLKDataStruct SiS310_MCLKData_0_660[] =
+{
+	{ 0x5c,0x23,0x82,166},
+	{ 0x5c,0x23,0x82,166},
+	{ 0x37,0x21,0x82,200},
+	{ 0x37,0x22,0x82,133},
+	{ 0x29,0x21,0x82,150},
+	{ 0x5c,0x23,0x82,166},
+	{ 0x65,0x23,0x82,183},
+	{ 0x37,0x21,0x82,200}
+};
+
+static const SiS_MCLKDataStruct SiS310_MCLKData_0_760[] =
+{
+	{ 0x37,0x22,0x82,133},
+	{ 0x5c,0x23,0x82,166},
+	{ 0x65,0x23,0x82,183},
+	{ 0x7c,0x08,0x82,200},
+	{ 0x29,0x21,0x82,150},
+	{ 0x5c,0x23,0x82,166},
+	{ 0x65,0x23,0x82,183},
+	{ 0x37,0x21,0x82,200}
+};
+
+static const SiS_MCLKDataStruct SiS310_MCLKData_0_761[] =
+{
+	{ 0x37,0x22,0x82,133},  /* Preliminary */
+	{ 0x5c,0x23,0x82,166},
+	{ 0x65,0x23,0x82,183},
+	{ 0x7c,0x08,0x82,200},
+	{ 0x29,0x21,0x82,150},
+	{ 0x5c,0x23,0x82,166},
+	{ 0x65,0x23,0x82,183},
+	{ 0x37,0x21,0x82,200}
+};
+
+static const SiS_MCLKDataStruct SiS310_MCLKData_0_340[] =
+{
+	{ 0x79,0x06,0x01,250},
+	{ 0x7c,0x08,0x01,200},
+	{ 0x7c,0x08,0x80,200},
+	{ 0x79,0x06,0x80,250},
+	{ 0x29,0x01,0x81,300},
+	{ 0x29,0x01,0x81,300},
+	{ 0x29,0x01,0x81,300},
+	{ 0x29,0x01,0x81,300}
+};
+
+static const SiS_MCLKDataStruct SiS310_MCLKData_1[] = /* ECLK */
+{
+        { 0x29,0x21,0x82,150},
+	{ 0x5c,0x23,0x82,166},
+	{ 0x65,0x23,0x82,183},
+	{ 0x37,0x21,0x82,200},
+	{ 0x37,0x22,0x82,133},
+	{ 0x37,0x22,0x82,133},
+	{ 0x37,0x22,0x82,133},
+	{ 0x37,0x22,0x82,133}
+};
+
+static const SiS_MCLKDataStruct SiS310_MCLKData_1_340[] =
+{
+	{ 0x7c,0x08,0x01,200},
+	{ 0x7c,0x08,0x01,200},
+	{ 0x7c,0x08,0x80,200},
+	{ 0x79,0x06,0x80,250},
+	{ 0x29,0x01,0x81,300},
+	{ 0x29,0x01,0x81,300},
+	{ 0x29,0x01,0x81,300},
+	{ 0x29,0x01,0x81,300}
+};
+
+static SiS_VCLKDataStruct SiS310_VCLKData[]=
+{
+	{ 0x1b,0xe1, 25}, /* 0x00 */
+	{ 0x4e,0xe4, 28}, /* 0x01 */
+	{ 0x57,0xe4, 31}, /* 0x02 */
+	{ 0xc3,0xc8, 36}, /* 0x03 */
+	{ 0x42,0xe2, 40}, /* 0x04 */
+	{ 0xfe,0xcd, 43}, /* 0x05 */
+	{ 0x5d,0xc4, 44}, /* 0x06 */
+	{ 0x52,0xe2, 49}, /* 0x07 */
+	{ 0x53,0xe2, 50}, /* 0x08 */
+	{ 0x74,0x67, 52}, /* 0x09 */
+	{ 0x6d,0x66, 56}, /* 0x0a */
+	{ 0x5a,0x64, 65}, /* 0x0b */  /* was 6c c3 - WRONG */
+	{ 0x46,0x44, 67}, /* 0x0c */
+	{ 0xb1,0x46, 68}, /* 0x0d */
+	{ 0xd3,0x4a, 72}, /* 0x0e */
+	{ 0x29,0x61, 75}, /* 0x0f */
+	{ 0x6e,0x46, 76}, /* 0x10 */
+	{ 0x2b,0x61, 78}, /* 0x11 */
+	{ 0x31,0x42, 79}, /* 0x12 */
+	{ 0xab,0x44, 83}, /* 0x13 */
+	{ 0x46,0x25, 84}, /* 0x14 */
+	{ 0x78,0x29, 86}, /* 0x15 */
+	{ 0x62,0x44, 94}, /* 0x16 */
+	{ 0x2b,0x41,104}, /* 0x17 */
+	{ 0x3a,0x23,105}, /* 0x18 */
+	{ 0x70,0x44,108}, /* 0x19 */
+	{ 0x3c,0x23,109}, /* 0x1a */
+	{ 0x5e,0x43,113}, /* 0x1b */
+	{ 0xbc,0x44,116}, /* 0x1c */
+	{ 0xe0,0x46,132}, /* 0x1d */
+	{ 0x54,0x42,135}, /* 0x1e */
+	{ 0xea,0x2a,139}, /* 0x1f */
+	{ 0x41,0x22,157}, /* 0x20 */
+	{ 0x70,0x24,162}, /* 0x21 */
+	{ 0x30,0x21,175}, /* 0x22 */
+	{ 0x4e,0x22,189}, /* 0x23 */
+	{ 0xde,0x26,194}, /* 0x24 */
+	{ 0x62,0x06,202}, /* 0x25 */
+	{ 0x3f,0x03,229}, /* 0x26 */
+	{ 0xb8,0x06,234}, /* 0x27 */
+	{ 0x34,0x02,253}, /* 0x28 */
+	{ 0x58,0x04,255}, /* 0x29 */
+	{ 0x24,0x01,265}, /* 0x2a */
+	{ 0x9b,0x02,267}, /* 0x2b */
+	{ 0x70,0x05,270}, /* 0x2c */
+	{ 0x25,0x01,272}, /* 0x2d */
+	{ 0x9c,0x02,277}, /* 0x2e */
+	{ 0x27,0x01,286}, /* 0x2f */
+	{ 0x3c,0x02,291}, /* 0x30 */
+	{ 0xef,0x0a,292}, /* 0x31 */
+	{ 0xf6,0x0a,310}, /* 0x32 */
+	{ 0x95,0x01,315}, /* 0x33 */
+	{ 0xf0,0x09,324}, /* 0x34 */
+	{ 0xfe,0x0a,331}, /* 0x35 */
+	{ 0xf3,0x09,332}, /* 0x36 */
+	{ 0xea,0x08,340}, /* 0x37 */
+	{ 0xe8,0x07,376}, /* 0x38 */
+	{ 0xde,0x06,389}, /* 0x39 */
+	{ 0x52,0x2a, 54}, /* 0x3a 301 TV */
+	{ 0x52,0x6a, 27}, /* 0x3b 301 TV */
+	{ 0x62,0x24, 70}, /* 0x3c 301 TV */
+	{ 0x62,0x64, 70}, /* 0x3d 301 TV */
+	{ 0xa8,0x4c, 30}, /* 0x3e 301 TV */
+	{ 0x20,0x26, 33}, /* 0x3f 301 TV */
+	{ 0x31,0xc2, 39}, /* 0x40 */
+	{ 0x60,0x36, 30}, /* 0x41 Chrontel */
+	{ 0x40,0x4a, 28}, /* 0x42 Chrontel */
+	{ 0x9f,0x46, 44}, /* 0x43 Chrontel */
+	{ 0x97,0x2c, 26}, /* 0x44 */
+	{ 0x44,0xe4, 25}, /* 0x45 Chrontel */
+	{ 0x7e,0x32, 47}, /* 0x46 Chrontel */
+	{ 0x8a,0x24, 31}, /* 0x47 Chrontel */
+	{ 0x97,0x2c, 26}, /* 0x48 Chrontel */
+	{ 0xce,0x3c, 39}, /* 0x49 */
+	{ 0x52,0x4a, 36}, /* 0x4a Chrontel */
+	{ 0x34,0x61, 95}, /* 0x4b */
+	{ 0x78,0x27,108}, /* 0x4c - was 102 */
+	{ 0x66,0x43,123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */
+	{ 0x41,0x4e, 21}, /* 0x4e */
+	{ 0xa1,0x4a, 29}, /* 0x4f Chrontel */
+	{ 0x19,0x42, 42}, /* 0x50 */
+	{ 0x54,0x46, 58}, /* 0x51 Chrontel */
+	{ 0x25,0x42, 61}, /* 0x52 */
+	{ 0x44,0x44, 66}, /* 0x53 Chrontel */
+	{ 0x3a,0x62, 70}, /* 0x54 Chrontel */
+	{ 0x62,0xc6, 34}, /* 0x55 848x480-60 */
+	{ 0x6a,0xc6, 37}, /* 0x56 848x480-75 - TEMP */
+	{ 0xbf,0xc8, 35}, /* 0x57 856x480-38i,60 */
+	{ 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */
+	{ 0x52,0x07,149}, /* 0x59 1280x960-85 */
+	{ 0x56,0x07,156}, /* 0x5a 1400x1050-75 */
+   	{ 0x70,0x29, 81}, /* 0x5b 1280x768 LCD */
+	{ 0x45,0x25, 83}, /* 0x5c 1280x800  */
+	{ 0x70,0x0a,147}, /* 0x5d 1680x1050 */
+	{ 0x70,0x24,162}, /* 0x5e 1600x1200 */
+	{ 0x5a,0x64, 65}, /* 0x5f 1280x720 - temp */
+	{ 0x63,0x46, 68}, /* 0x60 1280x768_2 */
+	{ 0x31,0x42, 79}, /* 0x61 1280x768_3 - temp */
+	{    0,   0,  0}, /* 0x62 - custom (will be filled out at run-time) */
+	{ 0x5a,0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */
+	{ 0x70,0x28, 90}, /* 0x64 1152x864@60 */
+	{ 0x41,0xc4, 32}, /* 0x65 848x480@60 */
+	{ 0x5c,0xc6, 32}, /* 0x66 856x480@60 */
+	{ 0x76,0xe7, 27}, /* 0x67 720x480@60 */
+	{ 0x5f,0xc6, 33}, /* 0x68 720/768x576@60 */
+	{ 0x52,0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */
+	{ 0x7c,0x6b, 38}, /* 0x6a 960x540@60 */
+	{ 0xe3,0x56, 41}, /* 0x6b 960x600@60 */
+	{ 0x45,0x25, 83}, /* 0x6c 1280x800 */
+	{ 0x70,0x28, 90}  /* 0x6d 1152x864@60 */
+};
+
+static SiS_VBVCLKDataStruct SiS310_VBVCLKData[]=
+{
+	{ 0x1b,0xe1, 25}, /* 0x00 */
+	{ 0x4e,0xe4, 28}, /* 0x01 */
+	{ 0x57,0xe4, 31}, /* 0x02 */
+	{ 0xc3,0xc8, 36}, /* 0x03 */
+	{ 0x42,0x47, 40}, /* 0x04 */
+	{ 0xfe,0xcd, 43}, /* 0x05 */
+	{ 0x5d,0xc4, 44}, /* 0x06 */
+	{ 0x52,0x47, 49}, /* 0x07 */
+	{ 0x53,0x47, 50}, /* 0x08 */
+	{ 0x74,0x67, 52}, /* 0x09 */
+	{ 0x6d,0x66, 56}, /* 0x0a */
+	{ 0x35,0x62, 65}, /* 0x0b */  /* Was 0x5a,0x64 - 650/LVDS+301: 35,62  */
+	{ 0x46,0x44, 67}, /* 0x0c */
+	{ 0xb1,0x46, 68}, /* 0x0d */
+	{ 0xd3,0x4a, 72}, /* 0x0e */
+	{ 0x29,0x61, 75}, /* 0x0f */
+	{ 0x6d,0x46, 75}, /* 0x10 */
+	{ 0x41,0x43, 78}, /* 0x11 */
+	{ 0x31,0x42, 79}, /* 0x12 */
+	{ 0xab,0x44, 83}, /* 0x13 */
+	{ 0x46,0x25, 84}, /* 0x14 */
+	{ 0x78,0x29, 86}, /* 0x15 */
+	{ 0x62,0x44, 94}, /* 0x16 */
+	{ 0x2b,0x22,104}, /* 0x17 */
+	{ 0x49,0x24,105}, /* 0x18 */
+	{ 0xf8,0x2f,108}, /* 0x19 */  /* 1400x1050 LCD */
+	{ 0x3c,0x23,109}, /* 0x1a */
+	{ 0x5e,0x43,113}, /* 0x1b */
+	{ 0xbc,0x44,116}, /* 0x1c */
+	{ 0xe0,0x46,132}, /* 0x1d */
+#if 0
+	{ 0xd4,0x28,135}, /* 0x1e */
+	{ 0xea,0x2a,139}, /* 0x1f */
+	{ 0x41,0x22,157}, /* 0x20 */
+	{ 0x70,0x24,162}, /* 0x21 */
+#endif
+	{ 0xe2,0x46,135}, /* 0x1e */  /* 1280x1024-75, better clock for VGA2 */
+	{ 0xe5,0x46,139}, /* 0x1f */  /* 1024x768-120, better clock for VGA2 */
+	{ 0x15,0x01,157}, /* 0x20 */  /* 1280x1024-85, better clock for VGA2 */
+	{ 0x70,0x09,162}, /* 0x21 */  /* 1600x1200-60, better clock for VGA2 */
+	{ 0x30,0x21,175}, /* 0x22 */
+	{ 0x4e,0x22,189}, /* 0x23 */
+	{ 0xde,0x26,194}, /* 0x24 */
+	{ 0x70,0x07,202}, /* 0x25 */
+	{ 0x3f,0x03,229}, /* 0x26 */
+	{ 0xb8,0x06,234}, /* 0x27 */
+	{ 0x34,0x02,253}, /* 0x28 */
+	{ 0x58,0x04,255}, /* 0x29 */
+	{ 0x24,0x01,265}, /* 0x2a */
+	{ 0x9b,0x02,267}, /* 0x2b */
+	{ 0x70,0x05,270}, /* 0x2c */
+	{ 0x25,0x01,272}, /* 0x2d */
+	{ 0x9c,0x02,277}, /* 0x2e */
+	{ 0x27,0x01,286}, /* 0x2f */
+	{ 0x3c,0x02,291}, /* 0x30 */
+	{ 0xef,0x0a,292}, /* 0x31 */
+	{ 0xf6,0x0a,310}, /* 0x32 */
+	{ 0x95,0x01,315}, /* 0x33 */
+	{ 0xf0,0x09,324}, /* 0x34 */
+	{ 0xfe,0x0a,331}, /* 0x35 */
+	{ 0xf3,0x09,332}, /* 0x36 */
+	{ 0xea,0x08,340}, /* 0x37 */
+	{ 0xe8,0x07,376}, /* 0x38 */
+	{ 0xde,0x06,389}, /* 0x39 */
+	{ 0x52,0x2a, 54}, /* 0x3a 301 TV - start */
+	{ 0x52,0x6a, 27}, /* 0x3b 301 TV */
+	{ 0x62,0x24, 70}, /* 0x3c 301 TV */
+	{ 0x62,0x64, 70}, /* 0x3d 301 TV */
+	{ 0xa8,0x4c, 30}, /* 0x3e 301 TV */
+	{ 0x20,0x26, 33}, /* 0x3f 301 TV */
+	{ 0x31,0xc2, 39}, /* 0x40 */
+	{ 0x2e,0x48, 25}, /* 0x41 Replacement for LCD on 315 for index 0 */
+	{ 0x24,0x46, 25}, /* 0x42 Replacement for LCD on 315 for modes 0x01, 0x03, 0x0f, 0x10, 0x12 */
+	{ 0x26,0x64, 28}, /* 0x43 Replacement for LCD on 315 for index 1 */
+	{ 0x37,0x64, 40}, /* 0x44 Replacement for LCD on 315 for index 4 */
+	{ 0xa1,0x42,108}, /* 0x45 1280x960 LCD */
+	{ 0x37,0x61,100}, /* 0x46 1280x960 LCD */
+	{ 0x78,0x27,108}, /* 0x47 */
+	{ 0x97,0x2c, 26}, /* 0x48 UNUSED */
+	{ 0xce,0x3c, 39}, /* 0x49 UNUSED */
+	{ 0x52,0x4a, 36}, /* 0x4a UNUSED */
+	{ 0x34,0x61, 95}, /* 0x4b UNUSED */
+	{ 0x78,0x27,108}, /* 0x4c UNUSED */
+	{ 0x66,0x43,123}, /* 0x4d 1400x1050-60 */
+	{ 0x41,0x4e, 21}, /* 0x4e UNUSED */
+	{ 0xa1,0x4a, 29}, /* 0x4f UNUSED */
+	{ 0x19,0x42, 42}, /* 0x50 UNUSED */
+	{ 0x54,0x46, 58}, /* 0x51 UNUSED */
+	{ 0x25,0x42, 61}, /* 0x52 UNUSED */
+	{ 0x44,0x44, 66}, /* 0x53 UNUSED */
+	{ 0x3a,0x62, 70}, /* 0x54 UNUSED */
+	{ 0x62,0xc6, 34}, /* 0x55 848x480-60 */
+	{ 0x6a,0xc6, 37}, /* 0x56 848x480-75 - TEMP, UNUSED */
+	{ 0xbf,0xc8, 35}, /* 0x57 856x480-38i,60  */
+	{ 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) TEMP, UNUSED */
+	{ 0x52,0x07,149}, /* 0x59 1280x960-85  */
+	{ 0x56,0x07,156}, /* 0x5a 1400x1050-75 */
+   	{ 0x70,0x29, 81}, /* 0x5b 1280x768 LCD (TMDS) */
+	{ 0xce,0x1e, 73}, /* 0x5c 1280x800_2 LCD (SiS LVDS) - (CRT1: 45 25 83) */
+	{ 0xbe,0x44,121}, /* 0x5d 1680x1050 LCD */
+	{ 0x70,0x24,162}, /* 0x5e 1600x1200 LCD */
+	{ 0x52,0x27, 75}, /* 0x5f 1280x720 (TMDS + HDTV) (correct) */
+	{ 0xc8,0x48, 77}, /* 0x60 1280x768_2 (SiS LVDS) */
+	{ 0x31,0x42, 79}, /* 0x61 1280x768_3 (SiS LVDS) - temp */
+	{    0,   0,  0}, /* 0x62 - custom (will be filled out at run-time) */
+	{ 0x9c,0x62, 69}, /* 0x63 1280x720 (SiS LVDS) */
+	{ 0x70,0x28, 90}, /* 0x64 1152x864@60 */
+	{ 0x41,0xc4, 32}, /* 0x65 848x480@60 */
+	{ 0x5c,0xc6, 32}, /* 0x66 856x480@60 */
+	{ 0x76,0xe7, 27}, /* 0x67 720x480@60 */
+	{ 0x5f,0xc6, 33}, /* 0x68 720/768x576@60 */
+	{ 0x52,0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced (UNUSED) */
+	{ 0x7c,0x6b, 38}, /* 0x6a 960x540@60 */
+	{ 0xe3,0x56, 41}, /* 0x6b 960x600@60 */
+	{ 0x9c,0x62, 69}, /* 0x6c 1280x800 (SiS TMDS) (special) */
+	{ 0x70,0x28, 90}  /* 0x6d 1152x864@60 */
+};
+
+static const DRAM4Type SiS310_SR15[8] = {
+	{0x00,0x04,0x60,0x60},
+	{0x0f,0x0f,0x0f,0x0f},
+	{0xba,0xba,0xba,0xba},
+	{0xa9,0xa9,0xac,0xac},
+	{0xa0,0xa0,0xa0,0xa8},
+	{0x00,0x00,0x02,0x02},
+ 	{0x30,0x30,0x40,0x40},
+	{0x00,0xa5,0xfb,0xf6}
+};
+
+#ifdef LINUX_KERNEL
+
+static UCHAR SiS310_SR07 = 0x18;
+
+static const DRAM4Type SiS310_CR40[5] = {
+	{0x77,0x77,0x33,0x33},
+	{0x77,0x77,0x33,0x33},
+	{0x00,0x00,0x00,0x00},
+	{0x5b,0x5b,0x03,0x03},
+	{0x00,0x00,0xf0,0xf8}
+};
+
+static UCHAR SiS310_CR49[] = {0xaa,0x88};
+static UCHAR SiS310_SR1F = 0x00;
+static UCHAR SiS310_SR21 = 0xa5;
+static UCHAR SiS310_SR22 = 0xfb;
+static UCHAR SiS310_SR23 = 0xf6;
+static UCHAR SiS310_SR24 = 0x0d;
+static UCHAR SiS310_SR25[] = {0x33,0x3};
+static UCHAR SiS310_SR31 = 0x00;
+static UCHAR SiS310_SR32 = 0x11;
+static UCHAR SiS310_SR33 = 0x00;
+static UCHAR SiS310_CRT2Data_1_2  = 0x00;
+static UCHAR SiS310_CRT2Data_4_D  = 0x00;
+static UCHAR SiS310_CRT2Data_4_E  = 0x00;
+static UCHAR SiS310_CRT2Data_4_10 = 0x80;
+static const USHORT SiS310_RGBSenseData    = 0xd1;
+static const USHORT SiS310_VideoSenseData  = 0xb9;
+static const USHORT SiS310_YCSenseData     = 0xb3;
+static const USHORT SiS310_RGBSenseData2   = 0x0190; 
+static const USHORT SiS310_VideoSenseData2 = 0x0174;
+static const USHORT SiS310_YCSenseData2    = 0x016b;
+#endif
+
+static const SiS_PanelDelayTblStruct SiS310_PanelDelayTbl[]=
+{
+        {{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}}
+};
+
+static const SiS_PanelDelayTblStruct SiS310_PanelDelayTblLVDS[]=
+{
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}}
+};
+
+/**************************************************************/
+/* SIS VIDEO BRIDGE ----------------------------------------- */
+/**************************************************************/
+
+static const SiS_LCDDataStruct  SiS310_St2LCD1024x768Data[] =
+{
+	{   62,  25, 800, 546,1344, 806},
+	{   32,  15, 930, 546,1344, 806},
+        {   62,  25, 800, 546,1344, 806},
+	{  104,  45, 945, 496,1344, 806},
+	{   62,  25, 800, 546,1344, 806},
+	{   31,  18,1008, 624,1344, 806},
+	{    1,   1,1344, 806,1344, 806}
+};
+
+static const SiS_LCDDataStruct  SiS310_ExtLCD1024x768Data[] =
+{
+	{   42,  25,1536, 419,1344, 806},
+	{   48,  25,1536, 369,1344, 806},
+	{   42,  25,1536, 419,1344, 806},
+	{   48,  25,1536, 369,1344, 806},
+	{   12,   5, 896, 500,1344, 806},
+	{   42,  25,1024, 625,1344, 806},
+	{    1,   1,1344, 806,1344, 806}
+};
+
+static const SiS_LCDDataStruct  SiS310_St2LCD1280x1024Data[] =
+{
+	{   22,   5, 800, 510,1650,1088},
+	{   22,   5, 800, 510,1650,1088},
+	{  176,  45, 900, 510,1650,1088},
+	{  176,  45, 900, 510,1650,1088},
+	{   22,   5, 800, 510,1650,1088},
+	{   13,   5,1024, 675,1560,1152},
+	{   16,   9,1266, 804,1688,1072},
+	{    1,   1,1688,1066,1688,1066}
+};
+
+static const SiS_LCDDataStruct  SiS310_ExtLCD1280x1024Data[] =
+{
+	{  211,  60,1024, 501,1688,1066},
+	{  211,  60,1024, 508,1688,1066},
+	{  211,  60,1024, 501,1688,1066},
+	{  211,  60,1024, 508,1688,1066},
+	{  211,  60,1024, 500,1688,1066},
+	{  211,  75,1024, 625,1688,1066},
+	{  211, 120,1280, 798,1688,1066},
+	{    1,   1,1688,1066,1688,1066}
+};
+
+static const SiS_Part2PortTblStruct SiS310_CRT2Part2_1024x768_1[] =
+{
+ {{0x25,0x12,0xc9,0xdc,0xb6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x2c,0x12,0x9a,0xae,0x88,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x25,0x12,0xc9,0xdc,0xb6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x38,0x13,0x16,0x0c,0xe6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x38,0x18,0x16,0x00,0x00,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}
+};
+
+/* *** LCDA *** */
+
+#if 0
+static const SiS_LVDSDataStruct  SiS_LCDA1600x1200Data_1[]=
+{ /* Clevo, 651+301C */
+	{1200, 450, 2048,1250},
+	{1200, 400, 2048,1250},
+	{1280, 450, 2048,1250},
+	{1280, 400, 2048,1250},
+	{1200, 530, 2048,1250},
+	{1360, 650, 2048,1250},
+	{1584, 818, 2048,1250},
+	{1688,1066, 2048,1250},
+	{1688,1066, 2048,1250},
+#if 0
+	{2048,1250, 2048,1250}   /* this should be correct */
+#endif
+#if 1
+	{2160,1250, 2048,1250}   /* ? */
+#endif
+};
+#endif
+
+/**************************************************************/
+/* LVDS, CHRONTEL ------------------------------------------- */
+/**************************************************************/
+
+static const SiS_LVDSDataStruct  SiS310_CHTVUPALData[]=
+{
+	{1008, 625,1008, 625},
+	{1008, 625,1008, 625},
+	{1008, 625,1008, 625},
+	{1008, 625,1008, 625},
+	{ 840, 625, 840, 625},
+	{ 960, 750, 960, 750},
+	{1400,1000,1400,1000}
+};
+
+static const SiS_LVDSDataStruct  SiS310_CHTVOPALData[]=
+{
+	{1008, 625,1008, 625},
+	{1008, 625,1008, 625},
+	{1008, 625,1008, 625},
+	{1008, 625,1008, 625},
+	{ 840, 625, 840, 625},
+	{ 944, 625, 944, 625},
+        {1400, 875,1400, 875}
+};
+
+static const SiS_LVDSDataStruct  SiS310_CHTVUPALMData[]=
+{
+	{ 840, 600, 840, 600},
+	{ 840, 600, 840, 600},
+	{ 840, 600, 840, 600},
+	{ 840, 600, 840, 600},
+	{ 784, 600, 784, 600},
+	{1064, 750,1064, 750},
+        {1160, 945,1160, 945}
+};
+
+static const SiS_LVDSDataStruct  SiS310_CHTVOPALMData[]=
+{
+	{ 840, 525, 840, 525},
+	{ 840, 525, 840, 525},
+	{ 840, 525, 840, 525},
+	{ 840, 525, 840, 525},
+	{ 784, 525, 784, 525},
+	{1040, 700,1040, 700},
+        {1160, 840,1160, 840}
+};
+
+static const SiS_LVDSDataStruct  SiS310_CHTVUPALNData[]=
+{
+	{1008, 625,1008, 625},
+	{1008, 625,1008, 625},
+	{1008, 625,1008, 625},
+	{1008, 625,1008, 625},
+	{ 840, 625, 840, 625},
+	{ 960, 750, 960, 750},
+	{1400,1000,1400,1000}
+};
+
+static const SiS_LVDSDataStruct  SiS310_CHTVOPALNData[]=
+{
+	{1008, 625,1008, 625},
+	{1008, 625,1008, 625},
+	{1008, 625,1008, 625},
+	{1008, 625,1008, 625},
+	{ 840, 625, 840, 625},
+	{ 944, 625, 944, 625},
+        {1400, 875,1400, 875}
+};
+
+static const SiS_LVDSDataStruct  SiS310_CHTVSOPALData[]=   /* (super overscan - no effect on 7019) */
+{
+	{1008, 625,1008, 625},
+	{1008, 625,1008, 625},
+	{1008, 625,1008, 625},
+	{1008, 625,1008, 625},
+	{ 840, 625, 840, 625},
+	{ 944, 625, 944, 625},
+        {1400, 875,1400, 875}
+};
+
+
+static const SiS_LVDSDesStruct  SiS310_PanelType00_1[]=  /* 800x600 */
+{
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType01_1[]=  /* 1024x768 */
+{
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 805},
+	{ 0, 0},
+	{ 0, 0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType02_1[]=  /* 1280x1024 */
+{
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 1065},
+	{ 0, 0},
+	{ 0, 0}
+};
+
+
+static const SiS_LVDSDesStruct  SiS310_PanelType03_1[]=
+{
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType04_1[]=
+{
+	{1343, 798},
+	{1343, 794},
+	{1343, 798},
+	{1343, 794},
+	{1343,   0},
+	{1343,   0},
+	{ 0, 805},
+	{ 0, 794},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType05_1[]=
+{
+	{1343, 798},
+	{1343, 794},
+	{1343, 798},
+	{1343, 794},
+	{1343,   0},
+	{1343,   0},
+	{ 0, 805},
+	{ 0, 794},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType06_1[]=
+{
+	{1343, 798},
+	{1343, 794},
+	{1343, 798},
+	{1343, 794},
+	{1343,   0},
+	{1343,   0},
+	{ 0, 805},
+	{ 0, 794},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType07_1[]=
+{
+	{1343, 798},
+	{1343, 794},
+	{1343, 798},
+	{1343, 794},
+	{1343,   0},
+	{1343,   0},
+	{ 0, 805},
+	{ 0, 794},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType08_1[]=   /* 1400x1050 */
+{
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType09_1[]=   /* 1280x768 */
+{
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType0a_1[]=  /* 1600x1200 */
+{
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType0b_1[]=  /* 640x480_2 */
+{
+	{ 0, 524},
+	{ 0, 524},
+	{ 0, 524},
+	{ 0, 524},
+	{ 0, 524},
+	{ 0, 524},
+	{ 8, 524},
+	{ 0, 524}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType0c_1[]=  /* 640x480_3 */
+{
+	{ 0, 524},
+	{ 0, 524},
+	{ 0, 524},
+	{ 0, 524},
+	{ 0, 524},
+	{ 0, 524},
+	{ 8, 524},
+	{ 0, 524}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType0d_1[]=
+{
+	{1343, 798},
+	{1343, 794},
+	{1343, 798},
+	{1343, 794},
+	{1343,   0},
+	{1343,   0},
+	{ 0, 805},
+	{ 0, 794},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType0e_1[]=
+{
+	{1343, 798},
+	{1343, 794},
+	{1343, 798},
+	{1343, 794},
+	{1343,   0},
+	{1343,   0},
+	{ 0, 805},
+	{ 0, 794},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType0f_1[]=
+{
+	{1343, 798},
+	{1343, 794},
+	{1343, 798},
+	{1343, 794},
+	{1343,   0},
+	{1343,   0},
+	{ 0, 805},
+	{ 0, 794},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType00_2[]=
+{
+	{980, 528},
+	{980, 503},
+	{980, 528},
+	{980, 503},
+	{980, 568},
+	{ 0, 628},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType01_2[]=
+{
+	{1152, 622},
+	{1152, 597},
+	{1152, 622},
+	{1152, 597},
+	{1152, 662},
+	{1232, 722},
+	{ 0, 806},
+	{ 0,   0},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType02_2[]=
+{
+	{1368, 754},
+	{1368, 729},
+	{1368, 754},
+	{1368, 729},
+	{1368, 794},
+	{1448, 854},
+	{1560, 938},
+	{   0,1066},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType03_2[]=
+{
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType04_2[]=
+{
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType05_2[]=
+{
+	{1152, 622},
+	{1152, 597},
+	{1152, 622},
+	{1152, 597},
+	{1152, 662},
+	{1232, 722},
+	{ 0, 805},
+	{ 0, 794},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType06_2[]=
+{
+	{1152, 622},
+	{1152, 597},
+	{1152, 622},
+	{1152, 597},
+	{1152, 662},
+	{1232, 722},
+	{ 0, 805},
+	{ 0, 794},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType07_2[]=
+{
+	{1152, 622},
+	{1152, 597},
+	{1152, 622},
+	{1152, 597},
+	{1152, 662},
+	{1232, 722},
+	{ 0, 805},
+	{ 0, 794},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType08_2[]=  /* 1400x1050 */
+{
+	{1308, 741},
+	{1308, 716},
+	{1308, 741},
+	{1308, 716},
+	{1308, 781},
+	{1388, 841},
+	{1500, 925},
+	{1628,1053},
+	{   0,1065},
+	{   0,   0},
+	{   0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType09_2[]= /* 1280x768 */
+{
+	{1083, 622},
+	{1083, 597},
+	{1083, 622},
+	{1083, 597},
+	{1083, 662},
+	{1163, 722},
+	{1286, 805},
+	{   0, 794},
+	{   0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType0a_2[]=  /* 1600x1200 */
+{
+	{1568, 920},
+	{1568, 895},
+	{1568, 920},
+	{1568, 895},
+	{1568, 960},
+	{1648,1020},
+	{1760,1104},
+	{1888,1232},
+	{1948,1245},
+	{   0,   0}
+#if 0
+	{1568, 850},
+	{1568, 825},
+	{1568, 850},
+	{1568, 825},
+	{1568, 890},
+	{1648, 950},
+	{1760,1034},
+	{1888,1162},
+	{1948,1175},
+	{   0,   0}
+#endif
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType0b_2[]=  /* 640x480_2 */
+{
+	{1152, 622},
+	{1152, 597},
+	{1152, 622},
+	{1152, 597},
+	{1152, 662},
+	{1232, 722},
+	{ 0, 805},
+	{ 0, 794},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType0c_2[]=  /* 640x480_3 */
+{
+	{1152, 622},
+	{1152, 597},
+	{1152, 622},
+	{1152, 597},
+	{1152, 662},
+	{1232, 722},
+	{ 0, 805},
+	{ 0, 794},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType0d_2[]=
+{
+	{1152, 622},
+	{1152, 597},
+	{1152, 622},
+	{1152, 597},
+	{1152, 662},
+	{1232, 722},
+	{ 0, 805},
+	{ 0, 794},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType0e_2[]=
+{
+	{1152, 622},
+	{1152, 597},
+	{1152, 622},
+	{1152, 597},
+	{1152, 662},
+	{1232, 722},
+	{ 0, 805},
+	{ 0, 794},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelType0f_2[] =
+{
+	{1152, 622},
+	{1152, 597},
+	{1152, 622},
+	{1152, 597},
+	{1152, 662},
+	{1232, 722},
+	{ 0, 805},
+	{ 0, 794},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelTypeNS_1[]=
+{
+	{ 8,   0},
+	{ 8,   0},
+	{ 8,   0},
+	{ 8,   0},
+	{ 8,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0, 806},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS310_PanelTypeNS_2[] =
+{
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
+};
+
+/* CRT1 CRTC for SlaveModes and LCDA */
+
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_1[] =
+{
+ {{0x6b,0x4f,0x8f,0x55,0x85,0xaa,0x1f,
+   0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
+   0x00 }},
+ {{0x6b,0x4f,0x8f,0x55,0x85,0x78,0x1f,
+   0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
+   0x00 }},
+ {{0x6b,0x4f,0x8f,0x55,0x85,0xaa,0x1f,
+   0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
+   0x00 }},
+ {{0x6b,0x4f,0x8f,0x55,0x85,0x78,0x1f,
+   0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
+   0x00 }},
+ {{0x6b,0x4f,0x8f,0x55,0x85,0xfa,0x1f,
+   0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05,
+   0x00 }},
+ {{0x7f,0x63,0x83,0x69,0x19,0x72,0xf0,
+   0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
+   0x01 }}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_1_H[] =
+{
+ {{0x43,0x27,0x87,0x2d,0x1d,0xaa,0x1f,
+   0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
+   0x00 }},
+ {{0x43,0x27,0x87,0x2d,0x1d,0x78,0x1f,
+   0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
+   0x00 }},
+ {{0x43,0x27,0x87,0x2d,0x1d,0xfa,0x1f,
+   0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05,
+   0x00 }},
+ {{0x43,0x27,0x87,0x2d,0x1d,0x78,0x1f,
+   0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
+   0x00 }},
+ {{0x43,0x27,0x87,0x2d,0x1d,0xfa,0x1f,
+   0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05,
+   0x00 }},
+ {{0x4d,0x31,0x91,0x37,0x07,0x72,0xf0,
+   0x58,0x8d,0x57,0x73,0x20,0x00,0x01,
+   0x01 }}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_2[]=
+{
+ {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
+   0xff,0x84,0x8f,0x73,0x00,0x00,0x06,
+   0x00 }},
+ {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
+   0xe6,0x8b,0x5d,0x73,0x00,0x00,0x06,
+   0x00 }},
+ {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
+   0xff,0x84,0x8f,0x73,0x00,0x00,0x06,
+   0x00 }},
+ {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
+   0xe6,0x8b,0x5d,0x73,0x00,0x00,0x06,
+   0x00 }},
+ {{0x7f,0x4f,0x83,0x62,0x12,0x72,0xba,
+   0x27,0x8c,0xdf,0x73,0x00,0x00,0x06,
+   0x00 }},
+ {{0x7f,0x63,0x83,0x69,0x19,0x72,0xf0,
+   0x58,0x8d,0x57,0x73,0x20,0x00,0x06,
+   0x01 }}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_2_H[] =
+{
+ {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0x3e,
+   0xff,0x84,0x8f,0x73,0x00,0x00,0x01,
+   0x00 }},
+ {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0x3e,
+   0xd6,0x8b,0x5d,0x73,0x00,0x00,0x01,
+   0x00 }},
+ {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0x3e,
+   0xff,0x84,0x8f,0x73,0x00,0x00,0x01,
+   0x00 }},
+ {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0x3e,
+   0xd6,0x8b,0x5d,0x73,0x00,0x00,0x01,
+   0x00 }},
+ {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0xba,
+   0x27,0x8c,0xdf,0x73,0x00,0x00,0x01,
+   0x00 }},
+ {{0x4d,0x31,0x91,0x3a,0x0a,0x72,0xf0,
+   0x63,0x88,0x57,0x73,0x00,0x00,0x01,
+   0x01 }}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_1[] =
+{
+ {{0x73,0x4f,0x97,0x53,0x84,0xb4,0x1f,
+   0x92,0x89,0x8f,0xb5,0x30,0x00,0x05,
+   0x00}},
+ {{0x73,0x4f,0x97,0x53,0x84,0x82,0x1f,
+   0x60,0x87,0x5d,0x83,0x10,0x00,0x05,
+   0x00}},
+ {{0x73,0x4f,0x97,0x53,0x84,0xb4,0x1f,
+   0x92,0x89,0x8f,0xb5,0x30,0x00,0x05,
+   0x00}},
+ {{0x73,0x4f,0x97,0x53,0x84,0x82,0x1f,
+   0x60,0x87,0x5d,0x83,0x10,0x00,0x05,
+   0x00}},
+ {{0x73,0x4f,0x97,0x53,0x84,0x04,0x3e,
+   0xE2,0x89,0xDf,0x05,0x00,0x00,0x05,
+   0x00}},
+ {{0x87,0x63,0x8B,0x67,0x18,0x7c,0xf0,
+   0x5A,0x81,0x57,0x7D,0x00,0x00,0x06,
+   0x01}},
+ {{0xA3,0x7f,0x87,0x83,0x94,0x24,0xf5,
+   0x02,0x89,0xFf,0x25,0x10,0x00,0x02,
+   0x01}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_1_H[] =
+{
+ {{0x4b,0x27,0x8f,0x2b,0x1c,0xb4,0x1f,
+   0x92,0x89,0x8f,0xb5,0x30,0x00,0x05,
+   0x00 }},
+ {{0x4b,0x27,0x8f,0x2b,0x1c,0x82,0x1f,
+   0x60,0x87,0x5D,0x83,0x01,0x00,0x05,
+   0x00}},
+ {{0x4b,0x27,0x8f,0x2b,0x1c,0xb4,0x1f,
+   0x92,0x89,0x8f,0xb5,0x30,0x00,0x05,
+   0x00}},
+ {{0x4b,0x27,0x8f,0x2b,0x1c,0x82,0x1f,
+   0x60,0x87,0x5D,0x83,0x01,0x00,0x05,
+   0x00}},
+ {{0x4b,0x27,0x8f,0x2b,0x1c,0x04,0x3e,
+   0xE2,0x89,0xDf,0x05,0x00,0x00,0x05,
+   0x00}},
+ {{0x55,0x31,0x99,0x35,0x06,0x7c,0xf0,
+   0x5A,0x81,0x57,0x7D,0x00,0x00,0x01,
+   0x01}},
+ {{0x63,0x3F,0x87,0x43,0x94,0x24,0xf5,
+   0x02,0x89,0xFf,0x25,0x10,0x00,0x01,
+   0x01 }}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_2[] =
+{
+ {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x57,0x8e,0x8f,0x25,0x30,0x00,0x06,
+   0x00 }},
+ {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x3e,0x85,0x5d,0x25,0x10,0x00,0x06,
+   0x00 }},
+ {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x57,0x8e,0x8f,0x25,0x30,0x00,0x06,
+   0x00 }},
+ {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x3e,0x85,0x5d,0x25,0x10,0x00,0x06,
+   0x01 }},
+ {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x7f,0x86,0xdf,0x25,0x10,0x00,0x06,
+   0x00 }},
+ {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1,
+   0xbb,0x82,0x57,0x25,0x10,0x00,0x02,
+   0x01 }},
+ {{0xa3,0x7f,0x87,0x83,0x94,0x24,0xf5,
+   0x02,0x89,0xff,0x25,0x10,0x00,0x02,
+   0x01 }}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_2_H[] =
+{
+ {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb,
+   0x57,0x8e,0x8f,0x25,0x30,0x00,0x01,
+   0x00 }},
+ {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb,
+   0x3e,0x85,0x5d,0x25,0x10,0x00,0x01,
+   0x00 }},
+ {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb,
+   0x57,0x8e,0x8f,0x25,0x30,0x00,0x01,
+   0x00 }},
+ {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb,
+   0x3e,0x85,0x5d,0x25,0x10,0x00,0x01,
+   0x00 }},
+ {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb,
+   0x7f,0x86,0xdf,0x25,0x10,0x00,0x01,
+   0x00 }},
+ {{0x71,0x31,0x95,0x46,0x97,0x24,0xf1,
+   0xbb,0x82,0x57,0x25,0x10,0x00,0x01,
+   0x01 }},
+ {{0x63,0x3f,0x87,0x46,0x97,0x24,0xf5,
+   0x0f,0x86,0xff,0x25,0x30,0x00,0x01,
+   0x01 }}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_1[] =
+{
+ {{0x7e,0x4f,0x82,0x58,0x04,0xb8,0x1f,
+   0x90,0x84,0x8f,0xb9,0x30,0x00,0x06,
+   0x00}},
+ {{0x7e,0x4f,0x82,0x58,0x04,0x86,0x1f,
+   0x5e,0x82,0x5d,0x87,0x10,0x00,0x06,
+   0x00}},
+ {{0x7e,0x4f,0x82,0x58,0x04,0xb8,0x1f,
+   0x90,0x84,0x8f,0xb9,0x30,0x00,0x06,
+   0x00}},
+ {{0x7e,0x4f,0x82,0x58,0x04,0x86,0x1f,
+   0x5e,0x82,0x5d,0x87,0x10,0x00,0x06,
+   0x00}},
+ {{0x7e,0x4f,0x82,0x58,0x04,0x08,0x3e,
+   0xe0,0x84,0xdf,0x09,0x00,0x00,0x06,
+   0x00}},
+ {{0x92,0x63,0x96,0x6c,0x18,0x80,0xf0,
+   0x58,0x8c,0x57,0x81,0x20,0x00,0x06,
+   0x01}},
+ {{0xae,0x7f,0x92,0x88,0x94,0x28,0xf5,
+   0x00,0x84,0xff,0x29,0x10,0x00,0x02,
+   0x01}},
+ {{0xce,0x9f,0x92,0xa8,0x14,0x28,0x5a,
+   0x00,0x84,0xff,0x29,0x09,0x00,0x07,
+   0x01}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_1_H[] =
+{
+ {{0x56,0x27,0x9a,0x31,0x1c,0xb8,0x1f,
+   0x90,0x84,0x8f,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x56,0x27,0x9a,0x31,0x1c,0x86,0x1f,
+   0x5e,0x82,0x5d,0x87,0x10,0x00,0x05,
+   0x00}},
+ {{0x56,0x27,0x9a,0x31,0x1c,0xb8,0x1f,
+   0x90,0x84,0x8f,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x56,0x27,0x9a,0x31,0x1c,0x86,0x1f,
+   0x5e,0x82,0x5d,0x87,0x10,0x00,0x05,
+   0x01}},
+ {{0x56,0x27,0x9a,0x31,0x1c,0x08,0x3e,
+   0xe0,0x84,0xdf,0x09,0x00,0x00,0x05,
+   0x00}},
+ {{0x60,0x31,0x84,0x3a,0x86,0x80,0xf0,
+   0x58,0x8c,0x57,0x81,0x20,0x00,0x01,
+   0x01}},
+ {{0x6e,0x3f,0x92,0x48,0x94,0x28,0xf5,
+   0x00,0x84,0xff,0x29,0x10,0x00,0x01,
+   0x01}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_2[] =
+{
+ {{0xce,0x72,0x91,0x81,0x8f,0x28,0x92,
+   0xc8,0x8c,0x5d,0x5c,0x01,0x00,0x02,
+   0x01}},
+ {{0xce,0x72,0x91,0x81,0x8f,0x28,0x92,
+   0xaf,0x83,0x44,0x43,0x21,0x00,0x02,
+   0x01}},
+ {{0xce,0x72,0x91,0x81,0x8f,0x28,0x92,
+   0xc8,0x8c,0x5d,0x5c,0x01,0x00,0x02,
+   0x01}},
+ {{0xce,0x72,0x91,0x81,0x8f,0x28,0x92,
+   0xaf,0x83,0x44,0x43,0x21,0x00,0x02,
+   0x01}},
+ {{0xce,0x72,0x91,0x81,0x8f,0x28,0x92,
+   0xf0,0x84,0x85,0x84,0x11,0x00,0x02,
+   0x01}},
+ {{0xce,0x63,0x92,0x8b,0x19,0x28,0xd4,
+   0x3f,0x83,0x57,0x29,0x01,0x00,0x03,
+   0x01}},
+ {{0xce,0x7f,0x92,0x99,0x07,0x28,0xd4,
+   0x93,0x87,0xff,0x29,0x21,0x00,0x07,
+   0x01}},
+ {{0xce,0x9f,0x92,0xa8,0x14,0x28,0x5a,
+   0x00,0x84,0xff,0x29,0x09,0x00,0x07,
+   0x01}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_2_H[] =
+{
+ {{0xa6,0x4a,0x89,0x59,0x07,0x28,0x92,
+   0xc8,0x8c,0x5d,0x5c,0x01,0x00,0x06,
+   0x01}},
+ {{0xa6,0x4a,0x89,0x59,0x07,0x28,0x92,
+   0xaf,0x83,0x44,0x43,0x21,0x00,0x06,
+   0x01}},
+ {{0xa6,0x4a,0x89,0x59,0x07,0x28,0x92,
+   0xc8,0x8c,0x5d,0x5c,0x01,0x00,0x06,
+   0x01}},
+ {{0xa6,0x4a,0x89,0x59,0x07,0x28,0x92,
+   0xfa,0x83,0x44,0x43,0x31,0x00,0x06,
+   0x01}},
+ {{0xa6,0x4a,0x89,0x59,0x07,0x28,0x92,
+   0xf0,0x84,0x85,0x84,0x11,0x00,0x06,
+   0x01}},
+ {{0x9c,0x31,0x80,0x59,0x87,0x28,0xd4,
+   0x3f,0x83,0x57,0x29,0x01,0x00,0x06,
+   0x01}},
+ {{0x8e,0x3f,0x92,0x59,0x07,0x28,0xd4,
+   0x93,0x87,0xff,0x29,0x21,0x00,0x06,
+   0x01}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11400x1050_1[] =
+{
+  {{0x6f,0x4f,0x93,0x54,0x82,0x9e,0x1f,
+    0x8f,0x81,0x8f,0x9f,0x30,0x00,0x05,
+    0x00}},
+  {{0x6f,0x4f,0x93,0x54,0x82,0x6c,0x1f,
+    0x5e,0x81,0x5d,0x6d,0x10,0x00,0x05,
+    0x00}},
+  {{0x6f,0x4f,0x93,0x54,0x82,0x9e,0x1f,
+    0x90,0x83,0x8f,0x9f,0x30,0x00,0x05,
+    0x00}},
+  {{0x6f,0x4f,0x93,0x54,0x82,0x6c,0x1f,
+    0x60,0x84,0x5d,0x6d,0x10,0x00,0x05,
+    0x00}},
+  {{0x6f,0x4f,0x93,0x54,0x82,0xee,0x1f,
+    0xdf,0x82,0xdf,0xef,0x10,0x00,0x05,
+    0x00}},
+  {{0x83,0x63,0x87,0x68,0x16,0x66,0xf0,
+    0x57,0x8e,0x57,0x67,0x20,0x00,0x06,
+    0x01}},
+  {{0x9f,0x7f,0x83,0x84,0x92,0x0e,0xf1,
+    0xff,0x86,0xff,0x0f,0x10,0x00,0x02,
+    0x01,}},
+  {{0xbf,0x9f,0x83,0xa4,0x12,0x0e,0xde,
+    0xff,0x86,0xff,0x0f,0x01,0x00,0x07,
+    0x01}},
+  {{0xce,0xae,0x92,0xb3,0x01,0x28,0x10,
+    0x19,0x80,0x19,0x29,0x0f,0x00,0x03,
+    0x00}}
+#if 0
+ {{0x6f,0x4f,0x93,0x54,0x82,0x9e,0x1f,
+   0x93,0x86,0x8f,0x9f,0x30,0x00,0x05,
+   0x00}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0x6c,0x1f,
+   0x60,0x84,0x5d,0x6d,0x10,0x00,0x05,
+   0x00}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0x9e,0x1f,
+   0x93,0x86,0x8f,0x9f,0x30,0x00,0x05,
+   0x00}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0x6c,0x1f,
+   0x60,0x84,0x5d,0x6d,0x10,0x00,0x05,
+   0x00}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0xee,0x1f,
+   0xe2,0x86,0xdf,0xef,0x10,0x00,0x05,
+   0x00}},
+ {{0x83,0x63,0x87,0x68,0x16,0x66,0xf0,
+   0x5a,0x8e,0x57,0x67,0x20,0x00,0x06,
+   0x01}},
+ {{0x9f,0x7f,0x83,0x84,0x92,0x0e,0xf5,
+   0x02,0x86,0xff,0x0f,0x10,0x00,0x02,
+   0x01}},
+ {{0xbf,0x9f,0x83,0xa4,0x12,0x0e,0x5a,
+   0x02,0x86,0xff,0x0f,0x09,0x00,0x07,
+   0x01}},
+ {{0xce,0xae,0x92,0xb3,0x01,0x28,0x10,
+   0x1a,0x80,0x19,0x29,0x0f,0x00,0x03,
+   0x00}}
+#endif   
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11400x1050_1_H[] =
+{
+ {{0x47,0x27,0x8b,0x2c,0x1a,0x9e,0x1f,
+   0x8f,0x81,0x8f,0x9f,0x30,0x00,0x05,
+  0x00}},
+ {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f,
+   0x60,0x84,0x5d,0x6d,0x10,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x30,0x1e,0x9e,0x1f,
+   0x90,0x83,0x8f,0x9f,0x30,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f,
+   0x60,0x84,0x5d,0x6d,0x10,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x2c,0x1a,0xee,0x1f,
+   0xdf,0x86,0xdf,0xef,0x10,0x00,0x05,
+   0x00}},
+ {{0x51,0x31,0x95,0x36,0x04,0x66,0xf0,
+   0x57,0x8e,0x57,0x67,0x20,0x00,0x01,
+   0x01}},
+ {{0x5f,0x3f,0x83,0x44,0x92,0x0e,0xf1,
+   0xff,0x86,0xff,0x0f,0x10,0x00,0x01,
+   0x01}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0x0e,0x5a,
+   0x02,0x86,0xff,0x0f,0x09,0x00,0x05,
+   0x01}},
+ {{0x76,0x56,0x9a,0x5b,0x89,0x28,0x10,
+   0x1c,0x80,0x19,0x29,0x0b,0x00,0x05,
+   0x00}}
+#if 0
+ {{0x47,0x27,0x8b,0x2c,0x1a,0x9e,0x1f,
+   0x93,0x86,0x8f,0x9f,0x30,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f,
+   0x60,0x84,0x5d,0x6d,0x10,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x30,0x1e,0x9e,0x1f,
+   0x92,0x86,0x8f,0x9f,0x30,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f,
+   0x60,0x84,0x5d,0x6d,0x10,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x2c,0x1a,0xee,0x1f,
+   0xe2,0x86,0xdf,0xef,0x10,0x00,0x05,
+   0x00}},
+ {{0x51,0x31,0x95,0x36,0x04,0x66,0xf0,
+   0x5a,0x8e,0x57,0x67,0x20,0x00,0x01,
+   0x01}},
+ {{0x5f,0x3f,0x83,0x44,0x92,0x0e,0xf5,
+   0x02,0x86,0xff,0x0f,0x10,0x00,0x01,
+   0x01}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0x0e,0x5a,
+   0x02,0x86,0xff,0x0f,0x09,0x00,0x05,
+   0x01}},
+ {{0x76,0x56,0x9a,0x5b,0x89,0x28,0x10,
+   0x1c,0x80,0x19,0x29,0x0b,0x00,0x05,
+   0x00}}
+#endif   
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11400x1050_2[] =
+{
+ {{0xce,0x72,0x91,0x84,0x92,0x28,0x92,
+   0xd7,0x8b,0x5d,0x5c,0x21,0x00,0x02,
+   0x01}},
+ {{0xce,0x72,0x91,0x84,0x92,0x28,0x92,
+   0xbe,0x82,0x44,0x43,0x01,0x00,0x02,
+   0x01}},
+ {{0xce,0x72,0x91,0x84,0x92,0x28,0x92,
+   0xd7,0x8b,0x5d,0x5c,0x21,0x00,0x02,
+   0x01}},
+ {{0xce,0x72,0x91,0x84,0x92,0x28,0x92,
+   0xbe,0x82,0x44,0x43,0x01,0x00,0x02,
+   0x01}},
+ {{0xce,0x72,0x91,0x84,0x92,0x28,0x92,
+   0xff,0x83,0x85,0x84,0x11,0x00,0x02,
+   0x01}},
+ {{0xce,0x63,0x92,0x8e,0x1c,0x28,0xd4,
+   0x3f,0x83,0x57,0x29,0x01,0x00,0x03,
+   0x01}},
+ {{0xce,0x7f,0x92,0x9c,0x0a,0x28,0xd4,
+   0x93,0x87,0xff,0x29,0x21,0x00,0x07,
+   0x01}},
+ {{0xce,0x9f,0x92,0xac,0x1a,0x28,0x5a,
+   0x13,0x87,0xff,0x29,0x29,0x00,0x07,
+   0x01}},
+ {{0xce,0xae,0x92,0xbc,0x0a,0x28,0x10,
+   0x20,0x84,0x19,0x29,0x0f,0x00,0x03,
+   0x00}}
+#if 0
+ {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x03,
+   0x00}},
+ {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x03,
+   0x01}},
+ {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x03,
+   0x00}},
+ {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x03,
+   0x00}},
+ {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9e,
+   0x03,0x87,0xdf,0x29,0x01,0x00,0x03,
+   0x00}},
+ {{0xce,0x63,0x92,0x96,0x04,0x28,0xd4,
+   0x3f,0x83,0x57,0x29,0x01,0x00,0x07,
+   0x01}},
+ {{0xce,0x7f,0x92,0xa4,0x12,0x28,0xd4,
+   0x93,0x87,0xff,0x29,0x21,0x00,0x07,
+   0x01}},
+ {{0xce,0x9f,0x92,0xb4,0x02,0x28,0x5a,
+   0x13,0x87,0xff,0x29,0x29,0x00,0x03,
+   0x01}},
+ {{0xce,0xae,0x92,0xbc,0x0a,0x28,0x10,
+   0x20,0x84,0x19,0x29,0x0f,0x00,0x03,
+   0x00}}
+#endif   
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11400x1050_2_H[] =
+{
+ {{0xa6,0x4a,0x89,0x5c,0x0a,0x28,0x92,
+   0xd7,0x8b,0x5d,0x5c,0x21,0x00,0x06,
+   0x01}},
+ {{0xa6,0x4a,0x89,0x5c,0x0a,0x28,0x92,
+   0xbe,0x82,0x44,0x43,0x01,0x00,0x06,
+   0x01}},
+ {{0xa6,0x4a,0x89,0x5c,0x0a,0x28,0x92,
+   0xd7,0x8b,0x5d,0x5c,0x21,0x00,0x06,
+   0x01}},
+ {{0xa6,0x4a,0x89,0x5c,0x0a,0x28,0x92,
+   0xbe,0x82,0x44,0x43,0x01,0x00,0x06,
+   0x01}},
+ {{0xa6,0x4a,0x89,0x5c,0x0a,0x28,0x92,
+   0xff,0x83,0x85,0x84,0x11,0x00,0x06,
+   0x01}},
+ {{0x9c,0x31,0x80,0x5c,0x8a,0x28,0xd4,
+   0x3f,0x83,0x57,0x29,0x01,0x00,0x06,
+   0x01}},
+ {{0x8e,0x3f,0x92,0x5c,0x0a,0x28,0xd4,
+   0x93,0x87,0xff,0x29,0x21,0x00,0x06,
+   0x01}},
+ {{0x7e,0x4f,0x82,0x5c,0x0a,0x28,0x5a,
+   0x13,0x87,0xff,0x29,0x29,0x00,0x06,
+   0x01}},
+ {{0x76,0x56,0x9a,0x64,0x92,0x28,0x10,
+   0x20,0x84,0x19,0x29,0x0f,0x00,0x05,
+   0x00}}
+#if 0
+ {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9e,
+   0x03,0x87,0xdf,0x29,0x01,0x00,0x06,
+   0x00}},
+ {{0x9c,0x31,0x80,0x64,0x92,0x28,0xd4,
+   0x3f,0x83,0x57,0x29,0x01,0x00,0x06,
+   0x01}},
+ {{0x8e,0x3f,0x92,0x64,0x12,0x28,0xd4,
+   0x93,0x87,0xff,0x29,0x21,0x00,0x06,
+   0x01}},
+ {{0x7e,0x4f,0x82,0x64,0x12,0x28,0x5a,
+   0x13,0x87,0xff,0x29,0x29,0x00,0x06,
+   0x01}},
+ {{0x76,0x56,0x9a,0x64,0x92,0x28,0x10,
+   0x20,0x84,0x19,0x29,0x0f,0x00,0x05,
+   0x00}}
+#endif   
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11600x1200_1[] =
+{
+ {{0x83,0x4F,0x87,0x5B,0x13,0x06,0x3E,
+   0xB3,0x86,0x8F,0x07,0x20,0x00,0x06,
+   0x00}},
+ {{0x83,0x4F,0x87,0x5B,0x13,0xD4,0x1F,
+   0x81,0x84,0x5D,0xD5,0x10,0x00,0x06,
+   0x00}},
+ {{0x83,0x4F,0x87,0x5B,0x13,0x06,0x3E,
+   0xB3,0x86,0x8F,0x07,0x20,0x00,0x06,
+   0x00}},
+ {{0x83,0x4F,0x87,0x5B,0x13,0xD4,0x1F,
+   0x81,0x84,0x5D,0xD5,0x10,0x00,0x06,
+   0x00}},
+ {{0x83,0x4F,0x87,0x5B,0x13,0x56,0xBA,
+   0x03,0x86,0xDF,0x57,0x00,0x00,0x06,
+   0x00}},
+ {{0x97,0x63,0x9B,0x6F,0x07,0xCE,0xF0,
+   0x7B,0x8E,0x57,0xCF,0x20,0x00,0x02,
+   0x01}},
+ {{0xB3,0x7F,0x97,0x8B,0x83,0x76,0xF5,
+   0x23,0x86,0xFF,0x77,0x10,0x00,0x06,
+   0x01}},
+ {{0xD3,0x9F,0x97,0xAB,0x03,0x76,0x5A,
+   0x23,0x86,0xFF,0x77,0x09,0x00,0x03,
+   0x01}},
+ {{0xE2,0xAE,0x86,0xBA,0x92,0x90,0x10,
+   0x3D,0x80,0x19,0x91,0x0F,0x00,0x03,
+   0x00}},
+ {{0xFB,0xC7,0x9F,0xD3,0x8B,0x26,0x11,
+   0xD3,0x86,0xAF,0x27,0x3F,0x00,0x07,
+   0x00}}
+#if 0
+ {{0x83,0x4f,0x87,0x51,0x09,0xc0,0x1f,
+   0x90,0x84,0x8f,0xc1,0x30,0x00,0x06,
+   0x00}},
+ {{0x83,0x4f,0x87,0x51,0x09,0x8e,0x1f,
+   0x5e,0x82,0x5d,0x8f,0x10,0x00,0x06,
+   0x00}},
+ {{0x83,0x4f,0x87,0x51,0x09,0xc0,0x1f,
+   0x90,0x84,0x8f,0xc1,0x30,0x00,0x06,
+   0x00}},
+ {{0x83,0x4f,0x87,0x51,0x09,0x8e,0x1f,
+   0x5e,0x82,0x5d,0x8f,0x10,0x00,0x06,
+   0x00}},
+ {{0x83,0x4f,0x87,0x51,0x09,0x10,0x3e,
+   0xe0,0x84,0xdf,0x11,0x00,0x00,0x06,
+   0x00}},
+ {{0x97,0x63,0x9b,0x65,0x1d,0x88,0xf0,
+   0x58,0x8c,0x57,0x89,0x20,0x00,0x06,
+   0x01}},
+ {{0xb3,0x7f,0x97,0x81,0x99,0x30,0xf5,
+   0x00,0x84,0xff,0x31,0x10,0x00,0x02,
+   0x01}},
+ {{0xd3,0x9f,0x97,0xa1,0x19,0x30,0x5a,
+   0x00,0x84,0xff,0x31,0x09,0x00,0x07,
+   0x01}},
+ {{0xe2,0xae,0x86,0xb0,0x88,0x4a,0x10,
+   0x1a,0x8e,0x19,0x4b,0x2f,0x00,0x03,
+   0x00}},
+ {{0xfb,0xc7,0x9f,0xc9,0x81,0xe0,0x10,
+   0xb0,0x84,0xaf,0xe1,0x2f,0x00,0x07,
+   0x00}}
+#endif
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11600x1200_1_H[] =
+{
+ {{0x5B,0x27,0x9F,0x33,0x0B,0x06,0x2E,
+   0xB3,0x86,0x8F,0x07,0x20,0x00,0x01,
+   0x00}},
+ {{0x5B,0x27,0x9F,0x29,0x01,0x8E,0x1F,
+   0x81,0x84,0x5D,0xD5,0x10,0x00,0x06,
+   0x00}},
+ {{0x5B,0x27,0x9F,0x33,0x0B,0x06,0x2E,
+   0xB3,0x86,0x8F,0x07,0x20,0x00,0x01,
+   0x00}},
+ {{0x83,0x4F,0x87,0x5B,0x13,0xD4,0x1F,
+   0x81,0x84,0x5D,0xD5,0x10,0x00,0x06,
+   0x00}},
+ {{0x5B,0x27,0x9F,0x33,0x0B,0x56,0xBA,
+   0x03,0x86,0xDF,0x57,0x00,0x00,0x01,
+   0x00}},
+ {{0x65,0x31,0x89,0x3D,0x95,0xCE,0xF0,
+   0x7B,0x8E,0x57,0xCF,0x20,0x00,0x01,
+   0x01}},
+ {{0x73,0x3F,0x97,0x4B,0x83,0x76,0xF5,
+   0x23,0x86,0xFF,0x77,0x10,0x00,0x05,
+   0x01}},
+ {{0xD3,0x9F,0x97,0xAB,0x03,0x76,0x5A,
+   0x23,0x86,0xFF,0x77,0x09,0x00,0x03,
+   0x01}},
+ {{0xE2,0xAE,0x86,0xBA,0x92,0x90,0x10,
+   0x3D,0x80,0x19,0x91,0x0F,0x00,0x03,
+   0x00}},
+ {{0x97,0x63,0x9B,0x6F,0x07,0xE0,0x10,
+   0xB0,0x84,0xAF,0xE1,0x2F,0x00,0x06,
+   0x00}}
+#if 0
+ {{0x5b,0x27,0x9f,0x29,0x01,0xc0,0x1f,
+   0x90,0x84,0x8f,0xc1,0x30,0x00,0x01,
+   0x00}},
+ {{0x5b,0x27,0x9f,0x29,0x01,0x8e,0x1f,
+   0x5e,0x82,0x5d,0x8f,0x10,0x00,0x01,
+   0x00}},
+ {{0x5b,0x27,0x9f,0x29,0x01,0xc0,0x1f,
+   0x90,0x84,0x8f,0xc1,0x30,0x00,0x01,
+   0x00}},
+ {{0x5b,0x27,0x9f,0x29,0x01,0x8e,0x1f,
+   0x5e,0x82,0x5d,0x8f,0x10,0x00,0x01,
+   0x00}},
+ {{0x5b,0x27,0x9f,0x29,0x01,0x10,0x3e,
+   0xe0,0x84,0xdf,0x11,0x00,0x00,0x01,
+   0x00}},
+ {{0x65,0x31,0x89,0x33,0x8b,0x88,0xf0,
+   0x58,0x8c,0x57,0x89,0x20,0x00,0x01,
+   0x01}},
+ {{0x73,0x3f,0x97,0x41,0x99,0x30,0xf5,
+   0x00,0x84,0xff,0x31,0x10,0x00,0x01,
+   0x01}},
+ {{0x83,0x4f,0x87,0x51,0x09,0x30,0x5a,
+   0x00,0x84,0xff,0x31,0x09,0x00,0x06,
+   0x01}},
+ {{0x8a,0x56,0x8e,0x58,0x10,0x4a,0x10,
+   0x1a,0x8e,0x19,0x4b,0x2f,0x00,0x06,
+   0x00}},
+ {{0x97,0x63,0x9b,0x65,0x1d,0xe0,0x10,
+   0xb0,0x84,0xaf,0xe1,0x2f,0x00,0x06,
+   0x00}}
+#endif
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11600x1200_2[] =
+{
+ {{0xFB,0x87,0x86,0x97,0x0F,0x26,0x97,
+   0x43,0x86,0xDB,0xDA,0x11,0x00,0x07,
+   0x01}},
+ {{0xFB,0x87,0x86,0x97,0x0F,0x26,0x97,
+   0x2A,0x8D,0xC2,0xC1,0x11,0x00,0x07,
+   0x01}},
+ {{0xFB,0x87,0x86,0x97,0x0F,0x26,0x97,
+   0x43,0x86,0xDB,0xDA,0x11,0x00,0x07,
+   0x01}},
+ {{0xFB,0x87,0x86,0x97,0x0F,0x26,0x97,
+   0x2A,0x8D,0xC2,0xC1,0x11,0x00,0x07,
+   0x01}},
+ {{0xFB,0x87,0x86,0x97,0x0F,0x26,0x9F,
+   0x6B,0x8E,0x03,0x02,0x01,0x00,0x07,
+   0x01}},
+ {{0xFB,0x63,0x9F,0xA1,0x99,0x26,0xD5,
+   0xA7,0x8A,0xBF,0xBE,0x01,0x00,0x07,
+   0x01}},
+ {{0xFB,0x7F,0x9F,0xAF,0x87,0x26,0xDD,
+   0xFB,0x8E,0x13,0x12,0x31,0x00,0x03,
+   0x01}},
+ {{0xFB,0x9F,0x9F,0xBF,0x97,0x26,0x5B,
+   0x7B,0x8E,0xFF,0x27,0x39,0x00,0x03,
+   0x01}},
+ {{0xFB,0xAE,0x9F,0xC6,0x9E,0x26,0x11,
+   0x88,0x8B,0x19,0x27,0x1F,0x00,0x03,
+   0x00}},
+ {{0xFB,0xC7,0x9F,0xD3,0x8B,0x26,0x11,
+   0xD3,0x86,0xAF,0x27,0x3F,0x00,0x07,
+   0x00}}
+#if 0
+ {{0xfb,0x88,0x87,0x90,0x08,0xe0,0x96,
+   0x20,0x84,0xb9,0xb8,0x01,0x00,0x07,
+   0x01}},
+ {{0xfb,0x88,0x87,0x90,0x08,0xe0,0x96,
+   0x07,0x8b,0xa0,0x9f,0x01,0x00,0x07,
+   0x01}},
+ {{0xfb,0x88,0x87,0x90,0x08,0xe0,0x96,
+   0x20,0x84,0xb9,0xb8,0x01,0x00,0x07,
+   0x01}},
+ {{0xfb,0x88,0x87,0x90,0x08,0xe0,0x96,
+   0x07,0x8b,0xa0,0x9f,0x01,0x00,0x07,
+   0x01}},
+ {{0xfb,0x88,0x87,0x90,0x08,0xe0,0x96,
+   0x48,0x8c,0xe1,0xe0,0x11,0x00,0x07,
+   0x01}},
+ {{0xfb,0x63,0x9f,0x9a,0x92,0xe0,0xd4,
+   0x9b,0x8f,0x9d,0x9c,0x21,0x00,0x07,
+   0x01}},
+ {{0xfb,0x7f,0x9f,0xa8,0x80,0xe0,0xd4,
+   0xef,0x83,0xff,0xe1,0x21,0x00,0x03,
+   0x01}},
+ {{0xfb,0x9f,0x9f,0xb8,0x90,0xe0,0x5a,
+   0x6f,0x83,0xff,0xe1,0x29,0x00,0x03,
+   0x01}},
+ {{0xfb,0xae,0x9f,0xbf,0x97,0xe0,0x10,
+   0x7c,0x80,0x19,0xe1,0x0f,0x00,0x03,
+   0x00}},
+ {{0xfb,0xc7,0x9f,0xc9,0x84,0xe0,0x10,
+   0xc7,0x8b,0xaf,0xe1,0x0f,0x00,0x07,
+   0x00}}
+#endif
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11600x1200_2_H[] =
+{
+ {{0xD3,0x5F,0x9E,0x6F,0x07,0x26,0x97,
+   0x43,0x86,0xDB,0xDA,0x11,0x00,0x02,
+   0x01}},
+ {{0xD3,0x27,0x97,0x6F,0x07,0x26,0x97,
+   0x6B,0x8E,0x83,0x82,0x01,0x00,0x03,
+   0x01}},
+ {{0xD3,0x5F,0x9E,0x6F,0x07,0x26,0x97,
+   0x43,0x86,0xDB,0xDA,0x11,0x00,0x02,
+   0x01}},
+ {{0xD3,0x27,0x97,0x6F,0x07,0x26,0x97,
+   0x07,0x8B,0xA0,0x9F,0x01,0x00,0x02,
+   0x01}},
+ {{0xD3,0x27,0x97,0x6F,0x07,0x26,0x97,
+   0x6B,0x8E,0x83,0x82,0x01,0x00,0x03,
+   0x01}},
+ {{0xC9,0x31,0x8D,0x6F,0x07,0x26,0xD5,
+   0xA7,0x8A,0xBF,0xBE,0x01,0x00,0x03,
+   0x01}},
+ {{0xBB,0x3F,0x9F,0x6F,0x87,0x26,0xDD,
+   0xFB,0x8E,0x13,0x12,0x31,0x00,0x02,
+   0x01}},
+ {{0xAB,0x4F,0x8F,0x68,0x80,0xE0,0x5A,
+   0x6F,0x83,0xFF,0xE1,0x29,0x00,0x02,
+   0x01}},
+ {{0xA3,0x56,0x87,0x67,0x9F,0xE0,0x10,
+   0x7C,0x80,0x19,0xE1,0x0F,0x00,0x06,
+   0x00}},
+ {{0x97,0x63,0x9B,0x68,0x00,0xE0,0x10,
+   0xC7,0x8B,0xAF,0xE1,0x0F,0x00,0x02,
+   0x00}}
+#if 0
+ {{0xd3,0x60,0x9f,0x68,0x00,0xe0,0x96,
+   0x20,0x84,0xb9,0xb8,0x01,0x00,0x02,
+   0x01}},
+ {{0xd3,0x60,0x9f,0x68,0x00,0xe0,0x96,
+   0x07,0x8b,0xa0,0x9f,0x01,0x00,0x02,
+   0x01}},
+ {{0xd3,0x60,0x9f,0x68,0x00,0xe0,0x96,
+   0x20,0x84,0xb9,0xb8,0x01,0x00,0x02,
+   0x01}},
+ {{0xd3,0x60,0x9f,0x68,0x00,0xe0,0x96,
+   0x07,0x8b,0xa0,0x9f,0x01,0x00,0x02,
+   0x01}},
+ {{0xd3,0x60,0x9f,0x68,0x00,0xe0,0x96,
+   0x48,0x8c,0xe1,0xe0,0x11,0x00,0x02,
+   0x01}},
+ {{0xc9,0x31,0x8d,0x68,0x00,0xe0,0xd4,
+   0x9b,0x8f,0x9d,0x9c,0x21,0x00,0x03,
+   0x01}},
+ {{0xbb,0x3f,0x9f,0x68,0x80,0xe0,0xd4,
+   0xef,0x83,0xff,0xe1,0x21,0x00,0x02,
+   0x01}},
+ {{0xab,0x4f,0x8f,0x68,0x80,0xe0,0x5a,
+   0x6f,0x83,0xff,0xe1,0x29,0x00,0x02,
+   0x01}},
+ {{0xa3,0x56,0x87,0x67,0x9f,0xe0,0x10,
+   0x7c,0x80,0x19,0xe1,0x0f,0x00,0x06,
+   0x00}},
+ {{0x97,0x63,0x9b,0x68,0x00,0xe0,0x10,
+   0xc7,0x8b,0xaf,0xe1,0x0f,0x00,0x02,
+   0x00}}
+#endif
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT1XXXxXXX_1[] =
+{
+ {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
+   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x05,
+   0x00}},
+ {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
+   0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
+   0x01}},
+ {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
+   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+   0x01}},
+ {{0xce,0x9f,0x92,0xa8,0x14,0x28,0x5a,
+   0x00,0x84,0xff,0x29,0x09,0x00,0x07,
+   0x01}},
+ {{0xce,0x9f,0x92,0xa9,0x17,0x24,0xf5,
+   0x02,0x88,0xff,0x25,0x10,0x00,0x07,
+   0x01}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT1XXXxXXX_1_H[] =
+{
+ {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
+   0x00}},
+ {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
+   0x00}},
+ {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
+   0x00}},
+ {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
+   0x00}},
+ {{0x38,0x27,0x9c,0x2c,0x80,0x0b,0x3e,
+   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00,
+   0x00}},
+ {{0x4d,0x31,0x91,0x3b,0x03,0x72,0xf0,
+   0x58,0x8c,0x57,0x73,0x20,0x00,0x01,
+   0x01}},
+ {{0x63,0x3f,0x87,0x4a,0x92,0x24,0xf5,
+   0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+   0x01}}
+};
+
+
+/* CRT1 CRTC for Chrontel TV slave modes */
+
+static const SiS_LVDSCRT1DataStruct  SiS310_CHTVCRT1UNTSC[] =
+{ 
+ {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
+   0xe8,0x84,0x8f,0x57,0x20,0x00,0x01,
+   0x00 }},
+ {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
+   0xd0,0x82,0x5d,0x57,0x00,0x00,0x01,
+   0x00 }},
+ {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
+   0xe8,0x84,0x8f,0x57,0x20,0x00,0x01,
+   0x00 }},
+ {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
+   0xd0,0x82,0x5d,0x57,0x00,0x00,0x01,
+   0x00 }},
+ {{0x5d,0x4f,0x81,0x56,0x99,0x56,0xba,
+   0x0a,0x84,0xdf,0x57,0x00,0x00,0x01,
+   0x00 }},
+ {{0x80,0x63,0x84,0x6d,0x0f,0xec,0xf0,
+   0x7a,0x8f,0x57,0xed,0x20,0x00,0x06,
+   0x01 }},
+ {{0x8c,0x7f,0x90,0x86,0x09,0xaf,0xf5,
+   0x36,0x88,0xff,0xb0,0x10,0x00,0x02,
+   0x01}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS310_CHTVCRT1ONTSC[] =
+{
+ {{0x63,0x4f,0x87,0x5a,0x9f,0x0b,0x3e,
+   0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01,
+   0x00 }},
+ {{0x63,0x4f,0x87,0x5a,0x9f,0x0b,0x3e,
+   0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01,
+   0x00 }},
+ {{0x63,0x4f,0x87,0x5a,0x9f,0x0b,0x3e,
+   0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01,
+   0x00 }},
+ {{0x63,0x4f,0x87,0x5a,0x9f,0x0b,0x3e,
+   0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01,
+   0x00 }},
+ {{0x5d,0x4f,0x81,0x58,0x9d,0x0b,0x3e,
+   0xe8,0x84,0xdf,0x0c,0x00,0x00,0x01,
+   0x00 }},
+ {{0x7d,0x63,0x81,0x68,0x0e,0xba,0xf0,
+   0x78,0x8a,0x57,0xbb,0x20,0x00,0x06,
+   0x01 }},
+ {{0x8c,0x7f,0x90,0x82,0x06,0x46,0xf5,
+   0x15,0x88,0xff,0x47,0x70,0x00,0x02,
+   0x01 }}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS310_CHTVCRT1UPAL[] =
+{ 
+ {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+   0xf8,0x83,0x8f,0x70,0x20,0x00,0x05,
+   0x00 }},
+ {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+   0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
+   0x00 }},
+ {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+   0xf8,0x83,0x8f,0x70,0x20,0x00,0x05,
+   0x00 }},
+ {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+   0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
+   0x00 }},
+ {{0x64,0x4f,0x88,0x5a,0x9f,0x6f,0xba,
+   0x15,0x83,0xdf,0x70,0x00,0x00,0x01,
+   0x00 }},
+ {{0x73,0x63,0x97,0x69,0x8b,0xec,0xf0,
+   0x90,0x8c,0x57,0xed,0x20,0x00,0x05,
+   0x01 }},
+ {{0xaa,0x7f,0x8e,0x8e,0x96,0xe6,0xf5,
+   0x50,0x88,0xff,0xe7,0x10,0x00,0x02,
+   0x01}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS310_CHTVCRT1OPAL[] =
+{
+ {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+   0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,
+   0x00 }},
+ {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+   0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
+   0x00 }},
+ {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+   0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,
+   0x00 }},
+ {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+   0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
+   0x00 }},
+ {{0x64,0x4f,0x88,0x58,0x9d,0x6f,0xba,
+   0x15,0x83,0xdf,0x70,0x00,0x00,0x01,
+   0x00 }},
+ {{0x71,0x63,0x95,0x69,0x8c,0x6f,0xf0,
+   0x5a,0x8b,0x57,0x70,0x20,0x00,0x05,
+   0x01 }},
+ {{0xaa,0x7f,0x8e,0x8f,0x96,0x69,0xf5,
+   0x28,0x88,0xff,0x6a,0x10,0x00,0x02,
+   0x01 }}
+};
+
+
+static const SiS_CHTVRegDataStruct SiS310_CHTVReg_UNTSC[] =
+{
+ {{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+ {{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+ {{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+ {{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+ {{0x6a,0x77,0xbb,0x6e,0x84,0x2e,0x02,0x5a,0x04,0x00,0x80,0x20,0x7e,0x80,0x98,0x00}},
+ {{0xcf,0x77,0xb7,0xc8,0x84,0x3b,0x02,0x5a,0x04,0x00,0x80,0x19,0x88,0x30,0x7f,0x00}},
+ {{0xee,0x77,0xbb,0x66,0x87,0x32,0x01,0x5a,0x04,0x00,0x80,0x1b,0xd3,0xf2,0x36,0x00}}
+}; /* WRONG: 0x02: should be 0xfx, because if CIVEnable is clear, this should be set;
+             0x07: Blacklevel: NTSC/PAL-M: Should be 131 (0x83), and not 0x50/0x5a
+	                       PAL/PAL-N:  110 (0x6e)
+			       NTSC-J:     102 (0x66)
+	     0x0c-0x0f: CIV is not default as in datasheet
+      MISSING: 0x21: Should set D1 to ZERO (for NTSC, PAL-M) or ONE (PAL, NTSC-J)
+      Most of this is wrong in all NTSC and PAL register arrays. But I won't correct
+      it as long as it works. For NTSC-J, the blacklevel is corrected in init301.c;
+      for PAL-M and PAL-N all above is corrected.
+    */
+
+static const SiS_CHTVRegDataStruct SiS310_CHTVReg_ONTSC[] =
+{
+ {{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+ {{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+ {{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+ {{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+ {{0x69,0x77,0xbb,0x6e,0x84,0x1e,0x00,0x5a,0x04,0x00,0x80,0x25,0x1a,0x43,0x04,0x00}},
+ {{0xce,0x77,0xb7,0xb6,0x83,0x2c,0x02,0x5a,0x04,0x00,0x80,0x1c,0x00,0x82,0x97,0x00}},
+ {{0xed,0x77,0xbb,0x66,0x8c,0x21,0x02,0x5a,0x04,0x00,0x80,0x1f,0x9f,0xc1,0x0c,0x00}}
+};
+
+static const SiS_CHTVRegDataStruct SiS310_CHTVReg_UPAL[] =
+{
+ {{0x41,0x7f,0xb7,0x34,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+ {{0x41,0x7f,0xb7,0x80,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+ {{0x41,0x7f,0xb7,0x34,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+ {{0x41,0x7f,0xb7,0x12,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+ {{0x61,0x7f,0xb7,0x99,0x84,0x35,0x04,0x5a,0x05,0x00,0x80,0x26,0x2a,0x55,0x5d,0x00}},
+ {{0xc3,0x7f,0xb7,0x7a,0x84,0x40,0x02,0x5a,0x05,0x00,0x80,0x1f,0x84,0x3d,0x28,0x00}},
+ {{0xe5,0x7f,0xb7,0x1d,0xa7,0x3e,0x04,0x5a,0x05,0x00,0x80,0x20,0x3e,0xe4,0x22,0x00}}
+};
+
+static const SiS_CHTVRegDataStruct SiS310_CHTVReg_OPAL[] =
+{
+ {{0x41,0x7f,0xb7,0x36,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+ {{0x41,0x7f,0xb7,0x86,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+ {{0x41,0x7f,0xb7,0x36,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+ {{0x41,0x7f,0xb7,0x86,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+ {{0x61,0x7f,0xb7,0x99,0x84,0x35,0x04,0x5a,0x05,0x00,0x80,0x26,0x2a,0x55,0x5d,0x00}},
+ {{0xc1,0x7f,0xb7,0x4d,0x8c,0x1e,0x31,0x5a,0x05,0x00,0x80,0x26,0x78,0x19,0x34,0x00}},
+ {{0xe4,0x7f,0xb7,0x1e,0xaf,0x29,0x37,0x5a,0x05,0x00,0x80,0x25,0x8c,0xb2,0x2a,0x00}}
+};
+
+static const SiS_CHTVRegDataStruct SiS310_CHTVReg_UPALM[] =
+{
+ {{0x52,0x77,0xbb,0x94,0x84,0x48,0xfe,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+ {{0x52,0x77,0xbb,0x94,0x84,0x48,0xfe,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+ {{0x52,0x77,0xbb,0x94,0x84,0x48,0xfe,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+ {{0x52,0x77,0xbb,0x94,0x84,0x48,0xfe,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+ {{0x72,0x77,0xfb,0x6e,0x84,0x2e,0x02,0x83,0x04,0x00,0x80,0x20,0x76,0xdb,0x6e,0x00}},
+ {{0xd7,0x77,0xf7,0xc8,0x84,0x3b,0x02,0x83,0x04,0x00,0x80,0x19,0x84,0x0a,0xc7,0x00}},
+ {{0xf6,0x77,0xfb,0x66,0x87,0x32,0x01,0x83,0x04,0x00,0x80,0x1b,0xdc,0xb0,0x8d,0x00}}
+#if 0 /* Correct blacklevel and CFRB */
+ {{0x72,0x77,0xbb,0x6e,0x84,0x2e,0x02,0x5a,0x04,0x00,0x80,0x20,0x76,0xdb,0x6e,0x00}},
+ {{0xd7,0x77,0xb7,0xc8,0x84,0x3b,0x02,0x5a,0x04,0x00,0x80,0x19,0x84,0x0a,0xc7,0x00}},
+ {{0xf6,0x77,0xbb,0x66,0x87,0x32,0x01,0x5a,0x04,0x00,0x80,0x1b,0xdc,0xb0,0x8d,0x00}}
+#endif
+};
+
+static const SiS_CHTVRegDataStruct SiS310_CHTVReg_OPALM[] =
+{
+ {{0x51,0x77,0xbb,0x7b,0x84,0x34,0x00,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+ {{0x51,0x77,0xbb,0x7b,0x84,0x34,0x00,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+ {{0x51,0x77,0xbb,0x7b,0x84,0x34,0x00,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+ {{0x51,0x77,0xbb,0x7b,0x84,0x34,0x00,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+ {{0x71,0x77,0xfb,0x6e,0x84,0x1e,0x00,0x83,0x04,0x00,0x80,0x25,0x1a,0x1f,0x59,0x00}},
+ {{0xd6,0x77,0xf7,0xb6,0x83,0x2c,0x02,0x83,0x04,0x00,0x80,0x1b,0xf8,0x1f,0x82,0x00}},
+ {{0xf5,0x77,0xfb,0x66,0x8c,0x21,0x02,0x83,0x04,0x00,0x80,0x1f,0x58,0x46,0x9f,0x00}}
+#if 0 /* Correct blacklevel and CFRB */
+ {{0x71,0x77,0xbb,0x6e,0x84,0x1e,0x00,0x5a,0x04,0x00,0x80,0x25,0x1a,0x1f,0x59,0x00}},
+ {{0xd6,0x77,0xb7,0xb6,0x83,0x2c,0x02,0x5a,0x04,0x00,0x80,0x1b,0xf8,0x1f,0x82,0x00}},
+ {{0xf5,0x77,0xbb,0x66,0x8c,0x21,0x02,0x5a,0x04,0x00,0x80,0x1f,0x58,0x46,0x9f,0x00}}
+#endif
+};
+
+static const SiS_CHTVRegDataStruct SiS310_CHTVReg_UPALN[] =
+{
+ {{0x41,0x7f,0xb7,0x34,0xad,0x50,0x34,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}},
+ {{0x41,0x7f,0xb7,0x80,0x85,0x50,0x00,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}},
+ {{0x41,0x7f,0xb7,0x34,0xad,0x50,0x34,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}},
+ {{0x41,0x7f,0xb7,0x12,0x85,0x50,0x00,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}},
+ {{0x61,0x7f,0xb7,0x99,0x84,0x35,0x04,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}},
+ {{0xc3,0x7f,0xb7,0x7a,0x84,0x40,0x02,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}},
+ {{0xe5,0x7f,0xb7,0x1d,0xa7,0x3e,0x04,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}
+#if 0 /* Correct blacklevel, CIV and CFRB */
+ {{0x61,0x7f,0xb7,0x99,0x84,0x35,0x04,0x5a,0x05,0x00,0x80,0x1f,0x0d,0x54,0x5e,0x00}},
+ {{0xc3,0x7f,0xb7,0x7a,0x84,0x40,0x02,0x5a,0x05,0x00,0x80,0x19,0x78,0xef,0x35,0x00}},
+ {{0xe5,0x7f,0xb7,0x1d,0xa7,0x3e,0x04,0x5a,0x05,0x00,0x80,0x1a,0x33,0x3f,0x2f,0x00}}
+#endif
+};
+
+static const SiS_CHTVRegDataStruct SiS310_CHTVReg_OPALN[] =
+{
+ {{0x41,0x7f,0xb7,0x36,0xad,0x50,0x34,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}},
+ {{0x41,0x7f,0xb7,0x86,0x85,0x50,0x00,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}},
+ {{0x41,0x7f,0xb7,0x36,0xad,0x50,0x34,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}},
+ {{0x41,0x7f,0xb7,0x86,0x85,0x50,0x00,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}},
+ {{0x61,0x7f,0xb7,0x99,0x84,0x35,0x04,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}},
+ {{0xc1,0x7f,0xb7,0x4d,0x8c,0x1e,0x31,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}},
+ {{0xe4,0x7f,0xb7,0x1e,0xaf,0x29,0x37,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}
+#if 0 /* Correct blacklevel, CIV and CFRB */
+ {{0x61,0x7f,0xb7,0x99,0x84,0x35,0x04,0x5a,0x05,0x00,0x80,0x1f,0x0d,0x54,0x5e,0x00}},
+ {{0xc1,0x7f,0xb7,0x4d,0x8c,0x1e,0x31,0x5a,0x05,0x00,0x80,0x1f,0x15,0xc0,0x1e,0x00}},
+ {{0xe4,0x7f,0xb7,0x1e,0xaf,0x29,0x37,0x5a,0x05,0x00,0x80,0x1d,0xf1,0x6c,0xcb,0x00}}
+#endif
+};
+
+static const UCHAR SiS310_CHTVVCLKUNTSC[] = {0x41,0x41,0x41,0x41,0x42,0x46,0x53};
+static const UCHAR SiS310_CHTVVCLKONTSC[] = {0x48,0x48,0x48,0x48,0x45,0x43,0x51};
+
+static const UCHAR SiS310_CHTVVCLKUPAL[]  = {0x47,0x47,0x47,0x47,0x48,0x4a,0x54};
+static const UCHAR SiS310_CHTVVCLKOPAL[]  = {0x47,0x47,0x47,0x47,0x48,0x4f,0x52};
+
+static const UCHAR SiS310_CHTVVCLKUPALM[] = {0x41,0x41,0x41,0x41,0x42,0x46,0x53};
+static const UCHAR SiS310_CHTVVCLKOPALM[] = {0x48,0x48,0x48,0x48,0x45,0x43,0x51};
+
+static const UCHAR SiS310_CHTVVCLKUPALN[] = {0x47,0x47,0x47,0x47,0x48,0x4a,0x54};
+static const UCHAR SiS310_CHTVVCLKOPALN[] = {0x47,0x47,0x47,0x47,0x48,0x4f,0x52};
+
+
diff --git a/drivers/video/sis/Makefile b/drivers/video/sis/Makefile
new file mode 100644
index 0000000..aaed8c2
--- /dev/null
+++ b/drivers/video/sis/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the SiS framebuffer device driver
+#
+
+obj-$(CONFIG_FB_SIS) += sisfb.o
+
+sisfb-objs := sis_main.o sis_accel.o init.o init301.o
diff --git a/drivers/video/sis/init.c b/drivers/video/sis/init.c
new file mode 100644
index 0000000..1994054
--- /dev/null
+++ b/drivers/video/sis/init.c
@@ -0,0 +1,5318 @@
+/* $XFree86$ */
+/* $XdotOrg$ */
+/*
+ * Mode initializing code (CRT1 section) for
+ * for SiS 300/305/540/630/730 and
+ *     SiS 315/550/650/M650/651/661FX/M661FX/740/741(GX)/M741/330/660/M660/760/M760
+ * (Universal module for Linux kernel framebuffer and XFree86 4.x)
+ *
+ * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, the following license terms
+ * apply:
+ *
+ * * This program is free software; you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License as published by
+ * * the Free Software Foundation; either version 2 of the named License,
+ * * or any later version.
+ * *
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details.
+ * *
+ * * You should have received a copy of the GNU General Public License
+ * * along with this program; if not, write to the Free Software
+ * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * * Redistribution and use in source and binary forms, with or without
+ * * modification, are permitted provided that the following conditions
+ * * are met:
+ * * 1) Redistributions of source code must retain the above copyright
+ * *    notice, this list of conditions and the following disclaimer.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * *    notice, this list of conditions and the following disclaimer in the
+ * *    documentation and/or other materials provided with the distribution.
+ * * 3) The name of the author may not be used to endorse or promote products
+ * *    derived from this software without specific prior written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ * Formerly based on non-functional code-fragements for 300 series by SiS, Inc.
+ * Used by permission.
+ *
+ * TW says: This code looks awful, I know. But please don't do anything about
+ * this otherwise debugging will be hell.
+ * The code is extremely fragile as regards the different chipsets, different
+ * video bridges and combinations thereof. If anything is changed, extreme
+ * care has to be taken that that change doesn't break it for other chipsets,
+ * bridges or combinations thereof.
+ * All comments in this file are by me, regardless if they are marked TW or not.
+ *
+ */
+ 
+#include "init.h"
+
+#ifdef SIS300
+#include "300vtbl.h"
+#endif
+
+#ifdef SIS315H
+#include "310vtbl.h"
+#endif
+
+#if defined(ALLOC_PRAGMA)
+#pragma alloc_text(PAGE,SiSSetMode)
+#endif
+
+/*********************************************/
+/*         POINTER INITIALIZATION            */
+/*********************************************/
+
+#if defined(SIS300) || defined(SIS315H)
+static void
+InitCommonPointer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+   SiS_Pr->SiS_StResInfo     = SiS_StResInfo;
+   SiS_Pr->SiS_ModeResInfo   = SiS_ModeResInfo;
+   SiS_Pr->SiS_StandTable    = SiS_StandTable;
+
+   SiS_Pr->SiS_NTSCPhase     = SiS_NTSCPhase;
+   SiS_Pr->SiS_PALPhase      = SiS_PALPhase;
+   SiS_Pr->SiS_NTSCPhase2    = SiS_NTSCPhase2;
+   SiS_Pr->SiS_PALPhase2     = SiS_PALPhase2;
+   SiS_Pr->SiS_PALMPhase     = SiS_PALMPhase;
+   SiS_Pr->SiS_PALNPhase     = SiS_PALNPhase;
+   SiS_Pr->SiS_PALMPhase2    = SiS_PALMPhase2;
+   SiS_Pr->SiS_PALNPhase2    = SiS_PALNPhase2;
+   SiS_Pr->SiS_SpecialPhase  = SiS_SpecialPhase;
+   SiS_Pr->SiS_SpecialPhaseM = SiS_SpecialPhaseM;
+   SiS_Pr->SiS_SpecialPhaseJ = SiS_SpecialPhaseJ;
+
+   SiS_Pr->SiS_NTSCTiming     = SiS_NTSCTiming;
+   SiS_Pr->SiS_PALTiming      = SiS_PALTiming;
+   SiS_Pr->SiS_HiTVSt1Timing  = SiS_HiTVSt1Timing;
+   SiS_Pr->SiS_HiTVSt2Timing  = SiS_HiTVSt2Timing;
+
+   SiS_Pr->SiS_HiTVExtTiming  = SiS_HiTVExtTiming;
+   SiS_Pr->SiS_HiTVGroup3Data = SiS_HiTVGroup3Data;
+   SiS_Pr->SiS_HiTVGroup3Simu = SiS_HiTVGroup3Simu;
+#if 0
+   SiS_Pr->SiS_HiTVTextTiming = SiS_HiTVTextTiming;
+   SiS_Pr->SiS_HiTVGroup3Text = SiS_HiTVGroup3Text;
+#endif
+
+   SiS_Pr->SiS_StPALData   = SiS_StPALData;
+   SiS_Pr->SiS_ExtPALData  = SiS_ExtPALData;
+   SiS_Pr->SiS_StNTSCData  = SiS_StNTSCData;
+   SiS_Pr->SiS_ExtNTSCData = SiS_ExtNTSCData;
+   SiS_Pr->SiS_St1HiTVData = SiS_StHiTVData;
+   SiS_Pr->SiS_St2HiTVData = SiS_St2HiTVData;
+   SiS_Pr->SiS_ExtHiTVData = SiS_ExtHiTVData;
+   SiS_Pr->SiS_St525iData  = SiS_StNTSCData;
+   SiS_Pr->SiS_St525pData  = SiS_St525pData;
+   SiS_Pr->SiS_St750pData  = SiS_St750pData;
+   SiS_Pr->SiS_Ext525iData = SiS_ExtNTSCData;
+   SiS_Pr->SiS_Ext525pData = SiS_ExtNTSCData;
+   SiS_Pr->SiS_Ext750pData = SiS_Ext750pData;
+
+   SiS_Pr->pSiS_OutputSelect = &SiS_OutputSelect;
+   SiS_Pr->pSiS_SoftSetting  = &SiS_SoftSetting;
+
+   SiS_Pr->SiS_LCD1280x720Data      = SiS_LCD1280x720Data;
+   SiS_Pr->SiS_StLCD1280x768_2Data  = SiS_StLCD1280x768_2Data;
+   SiS_Pr->SiS_ExtLCD1280x768_2Data = SiS_ExtLCD1280x768_2Data;
+   SiS_Pr->SiS_LCD1280x800Data      = SiS_LCD1280x800Data;
+   SiS_Pr->SiS_LCD1280x800_2Data    = SiS_LCD1280x800_2Data;
+   SiS_Pr->SiS_LCD1280x960Data      = SiS_LCD1280x960Data;
+   SiS_Pr->SiS_StLCD1400x1050Data   = SiS_StLCD1400x1050Data;
+   SiS_Pr->SiS_ExtLCD1400x1050Data  = SiS_ExtLCD1400x1050Data;
+   SiS_Pr->SiS_LCD1680x1050Data     = SiS_LCD1680x1050Data;
+   SiS_Pr->SiS_StLCD1600x1200Data   = SiS_StLCD1600x1200Data;
+   SiS_Pr->SiS_ExtLCD1600x1200Data  = SiS_ExtLCD1600x1200Data;
+   SiS_Pr->SiS_NoScaleData          = SiS_NoScaleData;
+
+   SiS_Pr->SiS_LVDS320x480Data_1   = SiS_LVDS320x480Data_1;
+   SiS_Pr->SiS_LVDS800x600Data_1   = SiS_LVDS800x600Data_1;
+   SiS_Pr->SiS_LVDS800x600Data_2   = SiS_LVDS800x600Data_2;
+   SiS_Pr->SiS_LVDS1024x768Data_1  = SiS_LVDS1024x768Data_1;
+   SiS_Pr->SiS_LVDS1024x768Data_2  = SiS_LVDS1024x768Data_2;
+   SiS_Pr->SiS_LVDS1280x1024Data_1 = SiS_LVDS1280x1024Data_1;
+   SiS_Pr->SiS_LVDS1280x1024Data_2 = SiS_LVDS1280x1024Data_2;
+   SiS_Pr->SiS_LVDS1400x1050Data_1 = SiS_LVDS1400x1050Data_1;
+   SiS_Pr->SiS_LVDS1400x1050Data_2 = SiS_LVDS1400x1050Data_2;
+   SiS_Pr->SiS_LVDS1600x1200Data_1 = SiS_LVDS1600x1200Data_1;
+   SiS_Pr->SiS_LVDS1600x1200Data_2 = SiS_LVDS1600x1200Data_2;
+   SiS_Pr->SiS_LVDS1280x768Data_1  = SiS_LVDS1280x768Data_1;
+   SiS_Pr->SiS_LVDS1280x768Data_2  = SiS_LVDS1280x768Data_2;
+   SiS_Pr->SiS_LVDS1024x600Data_1  = SiS_LVDS1024x600Data_1;
+   SiS_Pr->SiS_LVDS1024x600Data_2  = SiS_LVDS1024x600Data_2;
+   SiS_Pr->SiS_LVDS1152x768Data_1  = SiS_LVDS1152x768Data_1;
+   SiS_Pr->SiS_LVDS1152x768Data_2  = SiS_LVDS1152x768Data_2;
+   SiS_Pr->SiS_LVDSXXXxXXXData_1   = SiS_LVDSXXXxXXXData_1;
+   SiS_Pr->SiS_LVDS1280x960Data_1  = SiS_LVDS1280x960Data_1;
+   SiS_Pr->SiS_LVDS1280x960Data_2  = SiS_LVDS1280x960Data_2;
+   SiS_Pr->SiS_LVDS640x480Data_1   = SiS_LVDS640x480Data_1;
+   SiS_Pr->SiS_LVDS1280x960Data_1  = SiS_LVDS1280x1024Data_1;
+   SiS_Pr->SiS_LVDS1280x960Data_2  = SiS_LVDS1280x1024Data_2;
+   SiS_Pr->SiS_LVDS640x480Data_1   = SiS_LVDS640x480Data_1;
+   SiS_Pr->SiS_LVDS640x480Data_2   = SiS_LVDS640x480Data_2;
+
+   SiS_Pr->SiS_LVDS848x480Data_1   = SiS_LVDS848x480Data_1;
+   SiS_Pr->SiS_LVDS848x480Data_2   = SiS_LVDS848x480Data_2;
+   SiS_Pr->SiS_LVDSBARCO1024Data_1 = SiS_LVDSBARCO1024Data_1;
+   SiS_Pr->SiS_LVDSBARCO1024Data_2 = SiS_LVDSBARCO1024Data_2;
+   SiS_Pr->SiS_LVDSBARCO1366Data_1 = SiS_LVDSBARCO1366Data_1;
+   SiS_Pr->SiS_LVDSBARCO1366Data_2 = SiS_LVDSBARCO1366Data_2;
+
+   SiS_Pr->SiS_LVDSCRT11280x768_1    = SiS_LVDSCRT11280x768_1;
+   SiS_Pr->SiS_LVDSCRT11024x600_1    = SiS_LVDSCRT11024x600_1;
+   SiS_Pr->SiS_LVDSCRT11152x768_1    = SiS_LVDSCRT11152x768_1;
+   SiS_Pr->SiS_LVDSCRT11280x768_1_H  = SiS_LVDSCRT11280x768_1_H;
+   SiS_Pr->SiS_LVDSCRT11024x600_1_H  = SiS_LVDSCRT11024x600_1_H;
+   SiS_Pr->SiS_LVDSCRT11152x768_1_H  = SiS_LVDSCRT11152x768_1_H;
+   SiS_Pr->SiS_LVDSCRT11280x768_2    = SiS_LVDSCRT11280x768_2;
+   SiS_Pr->SiS_LVDSCRT11024x600_2    = SiS_LVDSCRT11024x600_2;
+   SiS_Pr->SiS_LVDSCRT11152x768_2    = SiS_LVDSCRT11152x768_2;
+   SiS_Pr->SiS_LVDSCRT11280x768_2_H  = SiS_LVDSCRT11280x768_2_H;
+   SiS_Pr->SiS_LVDSCRT11024x600_2_H  = SiS_LVDSCRT11024x600_2_H;
+   SiS_Pr->SiS_LVDSCRT11152x768_2_H  = SiS_LVDSCRT11152x768_2_H;
+   SiS_Pr->SiS_LVDSCRT1320x480_1     = SiS_LVDSCRT1320x480_1;
+   SiS_Pr->SiS_LVDSCRT1640x480_1     = SiS_LVDSCRT1640x480_1;
+   SiS_Pr->SiS_LVDSCRT1640x480_1_H   = SiS_LVDSCRT1640x480_1_H;
+   SiS_Pr->SiS_LVDSCRT1640x480_2     = SiS_LVDSCRT1640x480_2;
+   SiS_Pr->SiS_LVDSCRT1640x480_2_H   = SiS_LVDSCRT1640x480_2_H;
+   SiS_Pr->SiS_LVDSCRT1640x480_3     = SiS_LVDSCRT1640x480_3;
+   SiS_Pr->SiS_LVDSCRT1640x480_3_H   = SiS_LVDSCRT1640x480_3_H;
+
+   SiS_Pr->SiS_CHTVUNTSCData = SiS_CHTVUNTSCData;
+   SiS_Pr->SiS_CHTVONTSCData = SiS_CHTVONTSCData;
+
+   SiS_Pr->SiS_CHTVUNTSCDesData = SiS_CHTVUNTSCDesData;
+   SiS_Pr->SiS_CHTVONTSCDesData = SiS_CHTVONTSCDesData;
+   SiS_Pr->SiS_CHTVUPALDesData  = SiS_CHTVUPALDesData;
+   SiS_Pr->SiS_CHTVOPALDesData  = SiS_CHTVOPALDesData;
+
+   SiS_Pr->SiS_PanelMinLVDS   = Panel_800x600;    /* lowest value LVDS/LCDA */
+   SiS_Pr->SiS_PanelMin301    = Panel_1024x768;   /* lowest value 301 */
+}
+#endif
+
+#ifdef SIS300
+static void
+InitTo300Pointer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+   InitCommonPointer(SiS_Pr, HwInfo);
+
+   SiS_Pr->SiS_SModeIDTable  = SiS300_SModeIDTable;
+   SiS_Pr->SiS_VBModeIDTable = SiS300_VBModeIDTable;
+   SiS_Pr->SiS_EModeIDTable  = SiS300_EModeIDTable;
+   SiS_Pr->SiS_RefIndex      = SiS300_RefIndex;
+   SiS_Pr->SiS_CRT1Table     = SiS300_CRT1Table;
+   if(HwInfo->jChipType == SIS_300) {
+      SiS_Pr->SiS_MCLKData_0    = SiS300_MCLKData_300; /* 300 */
+   } else {
+      SiS_Pr->SiS_MCLKData_0    = SiS300_MCLKData_630; /* 630, 730 */
+   }
+   SiS_Pr->SiS_VCLKData      = SiS300_VCLKData;
+   SiS_Pr->SiS_VBVCLKData    = (SiS_VBVCLKDataStruct *)SiS300_VCLKData;
+
+   SiS_Pr->SiS_SR15  = SiS300_SR15;
+
+#ifdef LINUX_KERNEL
+   SiS_Pr->pSiS_SR07 = &SiS300_SR07;
+   SiS_Pr->SiS_CR40  = SiS300_CR40;
+   SiS_Pr->SiS_CR49  = SiS300_CR49;
+   SiS_Pr->pSiS_SR1F = &SiS300_SR1F;
+   SiS_Pr->pSiS_SR21 = &SiS300_SR21;
+   SiS_Pr->pSiS_SR22 = &SiS300_SR22;
+   SiS_Pr->pSiS_SR23 = &SiS300_SR23;
+   SiS_Pr->pSiS_SR24 = &SiS300_SR24;
+   SiS_Pr->SiS_SR25  = SiS300_SR25;
+   SiS_Pr->pSiS_SR31 = &SiS300_SR31;
+   SiS_Pr->pSiS_SR32 = &SiS300_SR32;
+   SiS_Pr->pSiS_SR33 = &SiS300_SR33;
+   SiS_Pr->pSiS_CRT2Data_1_2  = &SiS300_CRT2Data_1_2;
+   SiS_Pr->pSiS_CRT2Data_4_D  = &SiS300_CRT2Data_4_D;
+   SiS_Pr->pSiS_CRT2Data_4_E  = &SiS300_CRT2Data_4_E;
+   SiS_Pr->pSiS_CRT2Data_4_10 = &SiS300_CRT2Data_4_10;
+   SiS_Pr->pSiS_RGBSenseData    = &SiS300_RGBSenseData;
+   SiS_Pr->pSiS_VideoSenseData  = &SiS300_VideoSenseData;
+   SiS_Pr->pSiS_YCSenseData     = &SiS300_YCSenseData;
+   SiS_Pr->pSiS_RGBSenseData2   = &SiS300_RGBSenseData2;
+   SiS_Pr->pSiS_VideoSenseData2 = &SiS300_VideoSenseData2;
+   SiS_Pr->pSiS_YCSenseData2    = &SiS300_YCSenseData2;
+#endif
+
+   SiS_Pr->SiS_PanelDelayTbl     = SiS300_PanelDelayTbl;
+   SiS_Pr->SiS_PanelDelayTblLVDS = SiS300_PanelDelayTbl;
+
+   SiS_Pr->SiS_ExtLCD1024x768Data   = SiS300_ExtLCD1024x768Data;
+   SiS_Pr->SiS_St2LCD1024x768Data   = SiS300_St2LCD1024x768Data;
+   SiS_Pr->SiS_ExtLCD1280x1024Data  = SiS300_ExtLCD1280x1024Data;
+   SiS_Pr->SiS_St2LCD1280x1024Data  = SiS300_St2LCD1280x1024Data;
+
+   SiS_Pr->SiS_CRT2Part2_1024x768_1  = SiS300_CRT2Part2_1024x768_1;
+   SiS_Pr->SiS_CRT2Part2_1280x1024_1 = SiS300_CRT2Part2_1280x1024_1;
+   SiS_Pr->SiS_CRT2Part2_1024x768_2  = SiS300_CRT2Part2_1024x768_2;
+   SiS_Pr->SiS_CRT2Part2_1280x1024_2 = SiS300_CRT2Part2_1280x1024_2;
+   SiS_Pr->SiS_CRT2Part2_1024x768_3  = SiS300_CRT2Part2_1024x768_3;
+   SiS_Pr->SiS_CRT2Part2_1280x1024_3 = SiS300_CRT2Part2_1280x1024_3;
+
+   SiS_Pr->SiS_CHTVUPALData  = SiS300_CHTVUPALData;
+   SiS_Pr->SiS_CHTVOPALData  = SiS300_CHTVOPALData;
+   SiS_Pr->SiS_CHTVUPALMData = SiS_CHTVUNTSCData;    /* not supported on 300 series */
+   SiS_Pr->SiS_CHTVOPALMData = SiS_CHTVONTSCData;    /* not supported on 300 series */
+   SiS_Pr->SiS_CHTVUPALNData = SiS300_CHTVUPALData;  /* not supported on 300 series */
+   SiS_Pr->SiS_CHTVOPALNData = SiS300_CHTVOPALData;  /* not supported on 300 series */
+   SiS_Pr->SiS_CHTVSOPALData = SiS300_CHTVSOPALData;
+
+   SiS_Pr->SiS_PanelType00_1 = SiS300_PanelType00_1;
+   SiS_Pr->SiS_PanelType01_1 = SiS300_PanelType01_1;
+   SiS_Pr->SiS_PanelType02_1 = SiS300_PanelType02_1;
+   SiS_Pr->SiS_PanelType03_1 = SiS300_PanelType03_1;
+   SiS_Pr->SiS_PanelType04_1 = SiS300_PanelType04_1;
+   SiS_Pr->SiS_PanelType05_1 = SiS300_PanelType05_1;
+   SiS_Pr->SiS_PanelType06_1 = SiS300_PanelType06_1;
+   SiS_Pr->SiS_PanelType07_1 = SiS300_PanelType07_1;
+   SiS_Pr->SiS_PanelType08_1 = SiS300_PanelType08_1;
+   SiS_Pr->SiS_PanelType09_1 = SiS300_PanelType09_1;
+   SiS_Pr->SiS_PanelType0a_1 = SiS300_PanelType0a_1;
+   SiS_Pr->SiS_PanelType0b_1 = SiS300_PanelType0b_1;
+   SiS_Pr->SiS_PanelType0c_1 = SiS300_PanelType0c_1;
+   SiS_Pr->SiS_PanelType0d_1 = SiS300_PanelType0d_1;
+   SiS_Pr->SiS_PanelType0e_1 = SiS300_PanelType0e_1;
+   SiS_Pr->SiS_PanelType0f_1 = SiS300_PanelType0f_1;
+   SiS_Pr->SiS_PanelType00_2 = SiS300_PanelType00_2;
+   SiS_Pr->SiS_PanelType01_2 = SiS300_PanelType01_2;
+   SiS_Pr->SiS_PanelType02_2 = SiS300_PanelType02_2;
+   SiS_Pr->SiS_PanelType03_2 = SiS300_PanelType03_2;
+   SiS_Pr->SiS_PanelType04_2 = SiS300_PanelType04_2;
+   SiS_Pr->SiS_PanelType05_2 = SiS300_PanelType05_2;
+   SiS_Pr->SiS_PanelType06_2 = SiS300_PanelType06_2;
+   SiS_Pr->SiS_PanelType07_2 = SiS300_PanelType07_2;
+   SiS_Pr->SiS_PanelType08_2 = SiS300_PanelType08_2;
+   SiS_Pr->SiS_PanelType09_2 = SiS300_PanelType09_2;
+   SiS_Pr->SiS_PanelType0a_2 = SiS300_PanelType0a_2;
+   SiS_Pr->SiS_PanelType0b_2 = SiS300_PanelType0b_2;
+   SiS_Pr->SiS_PanelType0c_2 = SiS300_PanelType0c_2;
+   SiS_Pr->SiS_PanelType0d_2 = SiS300_PanelType0d_2;
+   SiS_Pr->SiS_PanelType0e_2 = SiS300_PanelType0e_2;
+   SiS_Pr->SiS_PanelType0f_2 = SiS300_PanelType0f_2;
+   SiS_Pr->SiS_PanelTypeNS_1 = SiS300_PanelTypeNS_1;
+   SiS_Pr->SiS_PanelTypeNS_2 = SiS300_PanelTypeNS_2;
+
+   if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) {
+      SiS_Pr->SiS_PanelType04_1 = SiS300_PanelType04_1a;
+      SiS_Pr->SiS_PanelType04_2 = SiS300_PanelType04_2a;
+   }
+   if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) {
+      SiS_Pr->SiS_PanelType04_1 = SiS300_PanelType04_1b;
+      SiS_Pr->SiS_PanelType04_2 = SiS300_PanelType04_2b;
+   }
+
+   SiS_Pr->SiS_LVDSCRT1800x600_1     = SiS300_LVDSCRT1800x600_1;
+   SiS_Pr->SiS_LVDSCRT1800x600_1_H   = SiS300_LVDSCRT1800x600_1_H;
+   SiS_Pr->SiS_LVDSCRT1800x600_2     = SiS300_LVDSCRT1800x600_2;
+   SiS_Pr->SiS_LVDSCRT1800x600_2_H   = SiS300_LVDSCRT1800x600_2_H;
+   SiS_Pr->SiS_LVDSCRT11024x768_1    = SiS300_LVDSCRT11024x768_1;
+   SiS_Pr->SiS_LVDSCRT11024x768_1_H  = SiS300_LVDSCRT11024x768_1_H;
+   SiS_Pr->SiS_LVDSCRT11024x768_2    = SiS300_LVDSCRT11024x768_2;
+   SiS_Pr->SiS_LVDSCRT11024x768_2_H  = SiS300_LVDSCRT11024x768_2_H;
+   SiS_Pr->SiS_LVDSCRT11280x1024_1   = SiS300_LVDSCRT11280x1024_1;
+   SiS_Pr->SiS_LVDSCRT11280x1024_1_H = SiS300_LVDSCRT11280x1024_1_H;
+   SiS_Pr->SiS_LVDSCRT11280x1024_2   = SiS300_LVDSCRT11280x1024_2;
+   SiS_Pr->SiS_LVDSCRT11280x1024_2_H = SiS300_LVDSCRT11280x1024_2_H;
+   SiS_Pr->SiS_LVDSCRT1XXXxXXX_1     = SiS300_LVDSCRT1XXXxXXX_1;
+   SiS_Pr->SiS_LVDSCRT1XXXxXXX_1_H   = SiS300_LVDSCRT1XXXxXXX_1_H;
+
+   SiS_Pr->SiS_CHTVCRT1UNTSC = SiS300_CHTVCRT1UNTSC;
+   SiS_Pr->SiS_CHTVCRT1ONTSC = SiS300_CHTVCRT1ONTSC;
+   SiS_Pr->SiS_CHTVCRT1UPAL  = SiS300_CHTVCRT1UPAL;
+   SiS_Pr->SiS_CHTVCRT1OPAL  = SiS300_CHTVCRT1OPAL;
+   SiS_Pr->SiS_CHTVCRT1SOPAL = SiS300_CHTVCRT1SOPAL;
+   SiS_Pr->SiS_CHTVReg_UNTSC = SiS300_CHTVReg_UNTSC;
+   SiS_Pr->SiS_CHTVReg_ONTSC = SiS300_CHTVReg_ONTSC;
+   SiS_Pr->SiS_CHTVReg_UPAL  = SiS300_CHTVReg_UPAL;
+   SiS_Pr->SiS_CHTVReg_OPAL  = SiS300_CHTVReg_OPAL;
+   SiS_Pr->SiS_CHTVReg_UPALM = SiS300_CHTVReg_UNTSC;  /* not supported on 300 series */
+   SiS_Pr->SiS_CHTVReg_OPALM = SiS300_CHTVReg_ONTSC;  /* not supported on 300 series */
+   SiS_Pr->SiS_CHTVReg_UPALN = SiS300_CHTVReg_UPAL;   /* not supported on 300 series */
+   SiS_Pr->SiS_CHTVReg_OPALN = SiS300_CHTVReg_OPAL;   /* not supported on 300 series */
+   SiS_Pr->SiS_CHTVReg_SOPAL = SiS300_CHTVReg_SOPAL;
+   SiS_Pr->SiS_CHTVVCLKUNTSC = SiS300_CHTVVCLKUNTSC;
+   SiS_Pr->SiS_CHTVVCLKONTSC = SiS300_CHTVVCLKONTSC;
+   SiS_Pr->SiS_CHTVVCLKUPAL  = SiS300_CHTVVCLKUPAL;
+   SiS_Pr->SiS_CHTVVCLKOPAL  = SiS300_CHTVVCLKOPAL;
+   SiS_Pr->SiS_CHTVVCLKUPALM = SiS300_CHTVVCLKUNTSC;  /* not supported on 300 series */
+   SiS_Pr->SiS_CHTVVCLKOPALM = SiS300_CHTVVCLKONTSC;  /* not supported on 300 series */
+   SiS_Pr->SiS_CHTVVCLKUPALN = SiS300_CHTVVCLKUPAL;   /* not supported on 300 series */
+   SiS_Pr->SiS_CHTVVCLKOPALN = SiS300_CHTVVCLKOPAL;   /* not supported on 300 series */
+   SiS_Pr->SiS_CHTVVCLKSOPAL = SiS300_CHTVVCLKSOPAL;
+}
+#endif
+
+#ifdef SIS315H
+static void
+InitTo310Pointer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+   InitCommonPointer(SiS_Pr, HwInfo);
+
+   SiS_Pr->SiS_SModeIDTable  = SiS310_SModeIDTable;
+   SiS_Pr->SiS_EModeIDTable  = SiS310_EModeIDTable;
+   SiS_Pr->SiS_RefIndex      = (SiS_Ext2Struct *)SiS310_RefIndex;
+   SiS_Pr->SiS_CRT1Table     = SiS310_CRT1Table;
+   if(HwInfo->jChipType >= SIS_340) {
+      SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_340;  /* 340 */
+   } else if(HwInfo->jChipType >= SIS_761) {
+      SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_761;  /* 761 - preliminary */
+   } else if(HwInfo->jChipType >= SIS_760) {
+      SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_760;  /* 760 */
+   } else if(HwInfo->jChipType >= SIS_661) {
+      SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_660;  /* 661/741 */
+   } else if(HwInfo->jChipType == SIS_330) {
+      SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_330;  /* 330 */
+   } else if(HwInfo->jChipType > SIS_315PRO) {
+      SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_650;  /* 550, 650, 740 */
+   } else {
+      SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_315;  /* 315 */
+   }
+   if(HwInfo->jChipType >= SIS_340) {
+      SiS_Pr->SiS_MCLKData_1    = SiS310_MCLKData_1_340;
+   } else {
+      SiS_Pr->SiS_MCLKData_1    = SiS310_MCLKData_1;
+   }
+   SiS_Pr->SiS_VCLKData      = SiS310_VCLKData;
+   SiS_Pr->SiS_VBVCLKData    = SiS310_VBVCLKData;
+
+   SiS_Pr->SiS_SR15  = SiS310_SR15;
+
+#ifdef LINUX_KERNEL
+   SiS_Pr->pSiS_SR07 = &SiS310_SR07;
+   SiS_Pr->SiS_CR40  = SiS310_CR40;
+   SiS_Pr->SiS_CR49  = SiS310_CR49;
+   SiS_Pr->pSiS_SR1F = &SiS310_SR1F;
+   SiS_Pr->pSiS_SR21 = &SiS310_SR21;
+   SiS_Pr->pSiS_SR22 = &SiS310_SR22;
+   SiS_Pr->pSiS_SR23 = &SiS310_SR23;
+   SiS_Pr->pSiS_SR24 = &SiS310_SR24;
+   SiS_Pr->SiS_SR25  = SiS310_SR25;
+   SiS_Pr->pSiS_SR31 = &SiS310_SR31;
+   SiS_Pr->pSiS_SR32 = &SiS310_SR32;
+   SiS_Pr->pSiS_SR33 = &SiS310_SR33;
+   SiS_Pr->pSiS_CRT2Data_1_2  = &SiS310_CRT2Data_1_2;
+   SiS_Pr->pSiS_CRT2Data_4_D  = &SiS310_CRT2Data_4_D;
+   SiS_Pr->pSiS_CRT2Data_4_E  = &SiS310_CRT2Data_4_E;
+   SiS_Pr->pSiS_CRT2Data_4_10 = &SiS310_CRT2Data_4_10;
+   SiS_Pr->pSiS_RGBSenseData    = &SiS310_RGBSenseData;
+   SiS_Pr->pSiS_VideoSenseData  = &SiS310_VideoSenseData;
+   SiS_Pr->pSiS_YCSenseData     = &SiS310_YCSenseData;
+   SiS_Pr->pSiS_RGBSenseData2   = &SiS310_RGBSenseData2;
+   SiS_Pr->pSiS_VideoSenseData2 = &SiS310_VideoSenseData2;
+   SiS_Pr->pSiS_YCSenseData2    = &SiS310_YCSenseData2;
+#endif
+
+   SiS_Pr->SiS_PanelDelayTbl     = SiS310_PanelDelayTbl;
+   SiS_Pr->SiS_PanelDelayTblLVDS = SiS310_PanelDelayTblLVDS;
+
+   SiS_Pr->SiS_St2LCD1024x768Data   = SiS310_St2LCD1024x768Data;
+   SiS_Pr->SiS_ExtLCD1024x768Data   = SiS310_ExtLCD1024x768Data;
+   SiS_Pr->SiS_St2LCD1280x1024Data  = SiS310_St2LCD1280x1024Data;
+   SiS_Pr->SiS_ExtLCD1280x1024Data  = SiS310_ExtLCD1280x1024Data;
+
+   SiS_Pr->SiS_CRT2Part2_1024x768_1  = SiS310_CRT2Part2_1024x768_1;
+
+   SiS_Pr->SiS_PanelType00_1 = SiS310_PanelType00_1;
+   SiS_Pr->SiS_PanelType01_1 = SiS310_PanelType01_1;
+   SiS_Pr->SiS_PanelType02_1 = SiS310_PanelType02_1;
+   SiS_Pr->SiS_PanelType03_1 = SiS310_PanelType03_1;
+   SiS_Pr->SiS_PanelType04_1 = SiS310_PanelType04_1;
+   SiS_Pr->SiS_PanelType05_1 = SiS310_PanelType05_1;
+   SiS_Pr->SiS_PanelType06_1 = SiS310_PanelType06_1;
+   SiS_Pr->SiS_PanelType07_1 = SiS310_PanelType07_1;
+   SiS_Pr->SiS_PanelType08_1 = SiS310_PanelType08_1;
+   SiS_Pr->SiS_PanelType09_1 = SiS310_PanelType09_1;
+   SiS_Pr->SiS_PanelType0a_1 = SiS310_PanelType0a_1;
+   SiS_Pr->SiS_PanelType0b_1 = SiS310_PanelType0b_1;
+   SiS_Pr->SiS_PanelType0c_1 = SiS310_PanelType0c_1;
+   SiS_Pr->SiS_PanelType0d_1 = SiS310_PanelType0d_1;
+   SiS_Pr->SiS_PanelType0e_1 = SiS310_PanelType0e_1;
+   SiS_Pr->SiS_PanelType0f_1 = SiS310_PanelType0f_1;
+   SiS_Pr->SiS_PanelType00_2 = SiS310_PanelType00_2;
+   SiS_Pr->SiS_PanelType01_2 = SiS310_PanelType01_2;
+   SiS_Pr->SiS_PanelType02_2 = SiS310_PanelType02_2;
+   SiS_Pr->SiS_PanelType03_2 = SiS310_PanelType03_2;
+   SiS_Pr->SiS_PanelType04_2 = SiS310_PanelType04_2;
+   SiS_Pr->SiS_PanelType05_2 = SiS310_PanelType05_2;
+   SiS_Pr->SiS_PanelType06_2 = SiS310_PanelType06_2;
+   SiS_Pr->SiS_PanelType07_2 = SiS310_PanelType07_2;
+   SiS_Pr->SiS_PanelType08_2 = SiS310_PanelType08_2;
+   SiS_Pr->SiS_PanelType09_2 = SiS310_PanelType09_2;
+   SiS_Pr->SiS_PanelType0a_2 = SiS310_PanelType0a_2;
+   SiS_Pr->SiS_PanelType0b_2 = SiS310_PanelType0b_2;
+   SiS_Pr->SiS_PanelType0c_2 = SiS310_PanelType0c_2;
+   SiS_Pr->SiS_PanelType0d_2 = SiS310_PanelType0d_2;
+   SiS_Pr->SiS_PanelType0e_2 = SiS310_PanelType0e_2;
+   SiS_Pr->SiS_PanelType0f_2 = SiS310_PanelType0f_2;
+   SiS_Pr->SiS_PanelTypeNS_1 = SiS310_PanelTypeNS_1;
+   SiS_Pr->SiS_PanelTypeNS_2 = SiS310_PanelTypeNS_2;
+
+   SiS_Pr->SiS_CHTVUPALData  = SiS310_CHTVUPALData;
+   SiS_Pr->SiS_CHTVOPALData  = SiS310_CHTVOPALData;
+   SiS_Pr->SiS_CHTVUPALMData = SiS310_CHTVUPALMData;
+   SiS_Pr->SiS_CHTVOPALMData = SiS310_CHTVOPALMData;
+   SiS_Pr->SiS_CHTVUPALNData = SiS310_CHTVUPALNData;
+   SiS_Pr->SiS_CHTVOPALNData = SiS310_CHTVOPALNData;
+   SiS_Pr->SiS_CHTVSOPALData = SiS310_CHTVSOPALData;
+
+   SiS_Pr->SiS_LVDSCRT1800x600_1     = SiS310_LVDSCRT1800x600_1;
+   SiS_Pr->SiS_LVDSCRT11024x768_1    = SiS310_LVDSCRT11024x768_1;
+   SiS_Pr->SiS_LVDSCRT11280x1024_1   = SiS310_LVDSCRT11280x1024_1;
+   SiS_Pr->SiS_LVDSCRT11400x1050_1   = SiS310_LVDSCRT11400x1050_1;
+   SiS_Pr->SiS_LVDSCRT11600x1200_1   = SiS310_LVDSCRT11600x1200_1;
+   SiS_Pr->SiS_LVDSCRT1800x600_1_H   = SiS310_LVDSCRT1800x600_1_H;
+   SiS_Pr->SiS_LVDSCRT11024x768_1_H  = SiS310_LVDSCRT11024x768_1_H;
+   SiS_Pr->SiS_LVDSCRT11280x1024_1_H = SiS310_LVDSCRT11280x1024_1_H;
+   SiS_Pr->SiS_LVDSCRT11400x1050_1_H = SiS310_LVDSCRT11400x1050_1_H;
+   SiS_Pr->SiS_LVDSCRT11600x1200_1_H = SiS310_LVDSCRT11600x1200_1_H;
+   SiS_Pr->SiS_LVDSCRT1800x600_2     = SiS310_LVDSCRT1800x600_2;
+   SiS_Pr->SiS_LVDSCRT11024x768_2    = SiS310_LVDSCRT11024x768_2;
+   SiS_Pr->SiS_LVDSCRT11280x1024_2   = SiS310_LVDSCRT11280x1024_2;
+   SiS_Pr->SiS_LVDSCRT11400x1050_2   = SiS310_LVDSCRT11400x1050_2;
+   SiS_Pr->SiS_LVDSCRT11600x1200_2   = SiS310_LVDSCRT11600x1200_2;
+   SiS_Pr->SiS_LVDSCRT1800x600_2_H   = SiS310_LVDSCRT1800x600_2_H;
+   SiS_Pr->SiS_LVDSCRT11024x768_2_H  = SiS310_LVDSCRT11024x768_2_H;
+   SiS_Pr->SiS_LVDSCRT11280x1024_2_H = SiS310_LVDSCRT11280x1024_2_H;
+   SiS_Pr->SiS_LVDSCRT11400x1050_2_H = SiS310_LVDSCRT11400x1050_2_H;
+   SiS_Pr->SiS_LVDSCRT11600x1200_2_H = SiS310_LVDSCRT11600x1200_2_H;
+   SiS_Pr->SiS_LVDSCRT1XXXxXXX_1     = SiS310_LVDSCRT1XXXxXXX_1;
+   SiS_Pr->SiS_LVDSCRT1XXXxXXX_1_H   = SiS310_LVDSCRT1XXXxXXX_1_H;
+   SiS_Pr->SiS_CHTVCRT1UNTSC         = SiS310_CHTVCRT1UNTSC;
+   SiS_Pr->SiS_CHTVCRT1ONTSC         = SiS310_CHTVCRT1ONTSC;
+   SiS_Pr->SiS_CHTVCRT1UPAL          = SiS310_CHTVCRT1UPAL;
+   SiS_Pr->SiS_CHTVCRT1OPAL          = SiS310_CHTVCRT1OPAL;
+   SiS_Pr->SiS_CHTVCRT1SOPAL         = SiS310_CHTVCRT1OPAL;
+
+   SiS_Pr->SiS_CHTVReg_UNTSC = SiS310_CHTVReg_UNTSC;
+   SiS_Pr->SiS_CHTVReg_ONTSC = SiS310_CHTVReg_ONTSC;
+   SiS_Pr->SiS_CHTVReg_UPAL  = SiS310_CHTVReg_UPAL;
+   SiS_Pr->SiS_CHTVReg_OPAL  = SiS310_CHTVReg_OPAL;
+   SiS_Pr->SiS_CHTVReg_UPALM = SiS310_CHTVReg_UPALM;
+   SiS_Pr->SiS_CHTVReg_OPALM = SiS310_CHTVReg_OPALM;
+   SiS_Pr->SiS_CHTVReg_UPALN = SiS310_CHTVReg_UPALN;
+   SiS_Pr->SiS_CHTVReg_OPALN = SiS310_CHTVReg_OPALN;
+   SiS_Pr->SiS_CHTVReg_SOPAL = SiS310_CHTVReg_OPAL;
+
+   SiS_Pr->SiS_CHTVVCLKUNTSC = SiS310_CHTVVCLKUNTSC;
+   SiS_Pr->SiS_CHTVVCLKONTSC = SiS310_CHTVVCLKONTSC;
+   SiS_Pr->SiS_CHTVVCLKUPAL  = SiS310_CHTVVCLKUPAL;
+   SiS_Pr->SiS_CHTVVCLKOPAL  = SiS310_CHTVVCLKOPAL;
+   SiS_Pr->SiS_CHTVVCLKUPALM = SiS310_CHTVVCLKUPALM;
+   SiS_Pr->SiS_CHTVVCLKOPALM = SiS310_CHTVVCLKOPALM;
+   SiS_Pr->SiS_CHTVVCLKUPALN = SiS310_CHTVVCLKUPALN;
+   SiS_Pr->SiS_CHTVVCLKOPALN = SiS310_CHTVVCLKOPALN;
+   SiS_Pr->SiS_CHTVVCLKSOPAL = SiS310_CHTVVCLKOPAL;
+}
+#endif
+
+static void
+SiSInitPtr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+   switch(HwInfo->jChipType) {
+#ifdef SIS315H
+   case SIS_315H:
+   case SIS_315:
+   case SIS_315PRO:
+   case SIS_550:
+   case SIS_650:
+   case SIS_740:
+   case SIS_330:
+   case SIS_661:
+   case SIS_741:
+   case SIS_660:
+   case SIS_760:
+   case SIS_761:
+   case SIS_340:
+      InitTo310Pointer(SiS_Pr, HwInfo);
+      break;
+#endif
+#ifdef SIS300
+   case SIS_300:
+   case SIS_540:
+   case SIS_630:
+   case SIS_730:
+      InitTo300Pointer(SiS_Pr, HwInfo);
+      break;
+#endif
+   default:
+      break;
+   }
+}
+
+/*********************************************/
+/*            HELPER: Get ModeID             */
+/*********************************************/
+
+#ifdef LINUX_XF86
+USHORT
+SiS_GetModeID(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay,
+              int Depth, BOOLEAN FSTN, int LCDwidth, int LCDheight)
+{
+   USHORT ModeIndex = 0;
+
+   switch(HDisplay)
+   {
+     case 320:
+     	  if(VDisplay == 200)     ModeIndex = ModeIndex_320x200[Depth];
+	  else if(VDisplay == 240) {
+	     if(FSTN) ModeIndex = ModeIndex_320x240_FSTN[Depth];
+	     else     ModeIndex = ModeIndex_320x240[Depth];
+          }
+          break;
+     case 400:
+          if((!(VBFlags & CRT1_LCDA)) || ((LCDwidth >= 800) && (LCDwidth >= 600))) {
+             if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth];
+	  }
+          break;
+     case 512:
+          if((!(VBFlags & CRT1_LCDA)) || ((LCDwidth >= 1024) && (LCDwidth >= 768))) {
+             if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth];
+	  }
+          break;
+     case 640:
+          if(VDisplay == 480)      ModeIndex = ModeIndex_640x480[Depth];
+	  else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth];
+          break;
+     case 720:
+          if(VDisplay == 480)      ModeIndex = ModeIndex_720x480[Depth];
+          else if(VDisplay == 576) ModeIndex = ModeIndex_720x576[Depth];
+          break;
+     case 768:
+          if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth];
+	  break;
+     case 800:
+	  if(VDisplay == 600)      ModeIndex = ModeIndex_800x600[Depth];
+	  else if(VDisplay == 480) ModeIndex = ModeIndex_800x480[Depth];
+          break;
+     case 848:
+	  if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth];
+	  break;
+     case 856:
+	  if(VDisplay == 480) ModeIndex = ModeIndex_856x480[Depth];
+	  break;
+     case 960:
+	  if(VGAEngine == SIS_315_VGA) {
+	     if(VDisplay == 540)      ModeIndex = ModeIndex_960x540[Depth];
+	     else if(VDisplay == 600) ModeIndex = ModeIndex_960x600[Depth];
+	  }
+	  break;
+     case 1024:
+          if(VDisplay == 576)      ModeIndex = ModeIndex_1024x576[Depth];
+          else if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth];
+	  else if(VGAEngine == SIS_300_VGA) {
+	     if(VDisplay == 600)   ModeIndex = ModeIndex_1024x600[Depth];
+	  }
+          break;
+     case 1152:
+          if(VDisplay == 864) ModeIndex = ModeIndex_1152x864[Depth];
+          if(VGAEngine == SIS_300_VGA) {
+	     if(VDisplay == 768) ModeIndex = ModeIndex_1152x768[Depth];
+	  }
+	  break;
+     case 1280:
+          switch(VDisplay) {
+	  case 720:
+	     ModeIndex = ModeIndex_1280x720[Depth];
+	     break;
+	  case 768:
+	     if(VGAEngine == SIS_300_VGA) {
+	        ModeIndex = ModeIndex_300_1280x768[Depth];
+	     } else {
+	        ModeIndex = ModeIndex_310_1280x768[Depth];
+	     }
+	     break;
+	  case 800:
+	     if(VGAEngine == SIS_315_VGA) {
+	        ModeIndex = ModeIndex_1280x800[Depth];
+	     }
+	     break;
+	  case 960:
+	     ModeIndex = ModeIndex_1280x960[Depth];
+	     break;
+	  case 1024:
+	     ModeIndex = ModeIndex_1280x1024[Depth];
+	     break;
+	  }
+          break;
+     case 1360:
+          if(VDisplay == 768) ModeIndex = ModeIndex_1360x768[Depth];
+	  if(VGAEngine == SIS_300_VGA) {
+	     if(VDisplay == 1024) ModeIndex = ModeIndex_300_1360x1024[Depth];
+          }
+          break;
+     case 1400:
+          if(VGAEngine == SIS_315_VGA) {
+	     if(VDisplay == 1050) {
+	        ModeIndex = ModeIndex_1400x1050[Depth];
+	     }
+	  }
+          break;
+     case 1600:
+          if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth];
+          break;
+     case 1680:
+          if(VGAEngine == SIS_315_VGA) {
+             if(VDisplay == 1050) ModeIndex = ModeIndex_1680x1050[Depth];
+	  }
+          break;
+     case 1920:
+          if(VDisplay == 1440)    ModeIndex = ModeIndex_1920x1440[Depth];
+	  else if(VGAEngine == SIS_315_VGA) {
+	     if(VDisplay == 1080) ModeIndex = ModeIndex_1920x1080[Depth];
+	  }
+          break;
+     case 2048:
+          if(VDisplay == 1536) {
+             if(VGAEngine == SIS_300_VGA) {
+	         ModeIndex = ModeIndex_300_2048x1536[Depth];
+  	     } else {
+	         ModeIndex = ModeIndex_310_2048x1536[Depth];
+             }
+	  }
+          break;
+   }
+
+   return(ModeIndex);
+}
+#endif
+
+USHORT
+SiS_GetModeID_LCD(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay,
+                  int Depth, BOOLEAN FSTN, USHORT CustomT, int LCDwidth, int LCDheight)
+{
+   USHORT ModeIndex = 0;
+
+   if(VBFlags & (VB_LVDS | VB_30xBDH)) {
+
+      switch(HDisplay)
+      {
+	case 320:
+	     if(CustomT != CUT_PANEL848) {
+     	  	if(VDisplay == 200) ModeIndex = ModeIndex_320x200[Depth];
+	  	else if(VDisplay == 240) {
+		   if(!FSTN) ModeIndex = ModeIndex_320x240[Depth];
+          	   else if(VGAEngine == SIS_315_VGA) {
+                      ModeIndex = ModeIndex_320x240_FSTN[Depth];
+		   }
+		}
+	     }
+             break;
+     	case 400:
+	     if(CustomT != CUT_PANEL848) {
+	        if(!((VGAEngine == SIS_300_VGA) && (VBFlags & VB_TRUMPION))) {
+          	   if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth];
+		}
+	     }
+             break;
+	case 512:
+	     if(CustomT != CUT_PANEL848) {
+	        if(!((VGAEngine == SIS_300_VGA) && (VBFlags & VB_TRUMPION))) {
+		   if(LCDwidth >= 1024 && LCDwidth != 1152 && LCDheight >= 768) {
+		      if(VDisplay == 384) {
+		         ModeIndex = ModeIndex_512x384[Depth];
+		      }
+		   }
+		}
+	     }
+	     break;
+	case 640:
+	     if(VDisplay == 480)            ModeIndex = ModeIndex_640x480[Depth];
+	     else if(VDisplay == 400) {
+	        if(CustomT != CUT_PANEL848) ModeIndex = ModeIndex_640x400[Depth];
+	     }
+	     break;
+	case 800:
+	     if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth];
+	     break;
+	case 848:
+	     if(CustomT == CUT_PANEL848) {
+	        if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth];
+	     }
+	     break;
+	case 1024:
+	     if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth];
+	     else if(VGAEngine == SIS_300_VGA) {
+		if((VDisplay == 600) && (LCDheight == 600)) {
+		   ModeIndex = ModeIndex_1024x600[Depth];
+		}
+	     }
+	     break;
+	case 1152:
+	     if(VGAEngine == SIS_300_VGA) {
+	        if((VDisplay == 768) && (LCDheight == 768)) {
+		   ModeIndex = ModeIndex_1152x768[Depth];
+		}
+	     }
+	     break;
+        case 1280:
+	     if(VDisplay == 1024) ModeIndex = ModeIndex_1280x1024[Depth];
+	     else if(VGAEngine == SIS_315_VGA) {
+	        if((VDisplay == 768) && (LCDheight == 768)) {
+		   ModeIndex = ModeIndex_310_1280x768[Depth];
+		}
+	     }
+	     break;
+	case 1360:
+	     if(VGAEngine == SIS_300_VGA) {
+	        if(CustomT == CUT_BARCO1366) {
+		   if(VDisplay == 1024) ModeIndex = ModeIndex_300_1360x1024[Depth];
+		}
+	     }
+	     if(CustomT == CUT_PANEL848) {
+	        if(VDisplay == 768) ModeIndex = ModeIndex_1360x768[Depth];
+	     }
+	     break;
+	case 1400:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 1050) ModeIndex = ModeIndex_1400x1050[Depth];
+	     }
+	     break;
+	case 1600:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth];
+	     }
+	     break;
+      }
+
+   } else if(VBFlags & VB_SISBRIDGE) {
+
+      switch(HDisplay)
+      {
+	case 320:
+     	     if(VDisplay == 200)      ModeIndex = ModeIndex_320x200[Depth];
+	     else if(VDisplay == 240) ModeIndex = ModeIndex_320x240[Depth];
+             break;
+     	case 400:
+	     if(LCDwidth >= 800 && LCDheight >= 600) {
+                if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth];
+	     }
+             break;
+	case 512:
+	     if(LCDwidth >= 1024 && LCDheight >= 768 && LCDwidth != 1152) {
+	        if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth];
+	     }
+	     break;
+	case 640:
+	     if(VDisplay == 480)      ModeIndex = ModeIndex_640x480[Depth];
+	     else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth];
+	     break;
+	case 720:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 480)      ModeIndex = ModeIndex_720x480[Depth];
+		else if(VDisplay == 576) ModeIndex = ModeIndex_720x576[Depth];
+	     }
+	     break;
+	case 768:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth];
+	     }
+	     break;
+	case 800:
+	     if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth];
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 480) ModeIndex = ModeIndex_800x480[Depth];
+	     }
+	     break;
+	case 848:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth];
+	     }
+	     break;
+	case 856:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 480) ModeIndex = ModeIndex_856x480[Depth];
+	     }
+	     break;
+	case 960:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 540)      ModeIndex = ModeIndex_960x540[Depth];
+		else if(VDisplay == 600) ModeIndex = ModeIndex_960x600[Depth];
+	     }
+	     break;
+	case 1024:
+	     if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth];
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 576) ModeIndex = ModeIndex_1024x576[Depth];
+	     }
+	     break;
+	case 1152:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 864) ModeIndex = ModeIndex_1152x864[Depth];
+	     }
+	     break;
+	case 1280:
+	     switch(VDisplay) {
+	     case 720:
+	        ModeIndex = ModeIndex_1280x720[Depth];
+	     case 768:
+	        if(VGAEngine == SIS_300_VGA) {
+		   ModeIndex = ModeIndex_300_1280x768[Depth];
+		} else {
+		   ModeIndex = ModeIndex_310_1280x768[Depth];
+		}
+		break;
+	     case 800:
+	        if(VGAEngine == SIS_315_VGA) {
+		   ModeIndex = ModeIndex_1280x800[Depth];
+		}
+		break;
+	     case 960:
+	        ModeIndex = ModeIndex_1280x960[Depth];
+		break;
+	     case 1024:
+	        ModeIndex = ModeIndex_1280x1024[Depth];
+		break;
+	     }
+	     break;
+	case 1360:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 768) ModeIndex = ModeIndex_1360x768[Depth];
+	     }
+	     break;
+	case 1400:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VBFlags & (VB_301C | VB_302LV | VB_302ELV)) {
+		   if(VDisplay == 1050) ModeIndex = ModeIndex_1400x1050[Depth];
+		}
+	     }
+	     break;
+	case 1600:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VBFlags & (VB_301C | VB_302LV | VB_302ELV)) {
+	           if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth];
+		}
+	     }
+	     break;
+#ifndef VB_FORBID_CRT2LCD_OVER_1600
+	case 1680:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VBFlags & (VB_301C | VB_302LV | VB_302ELV)) {
+	           if(VDisplay == 1050) ModeIndex = ModeIndex_1680x1050[Depth];
+		}
+	     }
+	     break;
+#endif
+      }
+   }
+
+   return ModeIndex;
+}
+
+USHORT
+SiS_GetModeID_TV(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth)
+{
+   USHORT ModeIndex = 0;
+
+   if(VBFlags & VB_CHRONTEL) {
+
+      switch(HDisplay)
+      {
+      	case 512:
+	     if(VGAEngine == SIS_315_VGA) {
+		if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth];
+	     }
+	     break;
+	case 640:
+	     if(VDisplay == 480)      ModeIndex = ModeIndex_640x480[Depth];
+	     else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth];
+	     break;
+	case 800:
+	     if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth];
+	     break;
+	case 1024:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth];
+	     }
+	     break;
+      }
+
+   } else if(VBFlags & VB_SISTVBRIDGE) {
+
+      switch(HDisplay)
+      {
+	case 320:
+     	     if(VDisplay == 200)      ModeIndex = ModeIndex_320x200[Depth];
+	     else if(VDisplay == 240) ModeIndex = ModeIndex_320x240[Depth];
+             break;
+        case 400:
+             if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth];
+             break;
+      	case 512:
+	     if( ((VBFlags & TV_YPBPR) && (VBFlags & (TV_YPBPR750P | TV_YPBPR1080I))) ||
+	         (VBFlags & TV_HIVISION) 					      ||
+	         ((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL)) ) {
+	        if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth];
+	     }
+	     break;
+	case 640:
+	     if(VDisplay == 480)      ModeIndex = ModeIndex_640x480[Depth];
+	     else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth];
+	     break;
+	case 720:
+	     if((!(VBFlags & TV_HIVISION)) && (!((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I)))) {
+                if(VDisplay == 480) {
+                   ModeIndex = ModeIndex_720x480[Depth];
+                } else if(VDisplay == 576) {
+		   if( ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR750P)) ||
+		       ((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL)) )
+                      ModeIndex = ModeIndex_720x576[Depth];
+                }
+	     }
+             break;
+	case 768:
+	     if((!(VBFlags & TV_HIVISION)) && (!((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I)))) {
+	        if( ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR750P)) ||
+		    ((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL)) ) {
+          	   if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth];
+		}
+             }
+	     break;
+	case 800:
+	     if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth];
+	     else if(VDisplay == 480) {
+	        if((VBFlags & TV_HIVISION) || ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I))) {
+		   ModeIndex = ModeIndex_800x480[Depth];
+		}
+	     }
+	     break;
+	case 960:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 600) {
+		   if((VBFlags & TV_HIVISION) || ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I))) {
+		      ModeIndex = ModeIndex_960x600[Depth];
+		   }
+		}
+	     }
+	     break;
+	case 1024:
+	     if(VDisplay == 768) {
+		if(VBFlags & (VB_301B|VB_301C|VB_302B|VB_301LV|VB_302LV|VB_302ELV)) {
+		   ModeIndex = ModeIndex_1024x768[Depth];
+		}
+	     } else if(VDisplay == 576) {
+	        if((VBFlags & TV_HIVISION) || ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I))) {
+		   ModeIndex = ModeIndex_1024x576[Depth];
+		}
+	     }
+	     break;
+	case 1280:
+	     if(VDisplay == 720) {
+	        if((VBFlags & TV_HIVISION) ||
+		   ((VBFlags & TV_YPBPR) && (VBFlags & (TV_YPBPR1080I | TV_YPBPR750P)))) {
+	           ModeIndex = ModeIndex_1280x720[Depth];
+		}
+	     } else if(VDisplay == 1024) {
+	        if((VBFlags & TV_HIVISION) ||
+		   ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I))) {
+	           ModeIndex = ModeIndex_1280x1024[Depth];
+		}
+	     }
+	     break;
+      }
+   }
+   return ModeIndex;
+}
+
+USHORT
+SiS_GetModeID_VGA2(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth)
+{
+   USHORT ModeIndex = 0;
+
+   if(!(VBFlags & (VB_301|VB_301B|VB_301C|VB_302B))) return 0;
+
+   switch(HDisplay)
+   {
+	case 320:
+     	  	if(VDisplay == 200)      ModeIndex = ModeIndex_320x200[Depth];
+	  	else if(VDisplay == 240) ModeIndex = ModeIndex_320x240[Depth];
+          	break;
+     	case 400:
+          	if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth];
+          	break;
+  	case 512:
+		if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth];
+		break;
+	case 640:
+		if(VDisplay == 480)      ModeIndex = ModeIndex_640x480[Depth];
+		else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth];
+		break;
+	case 720:
+		if(VDisplay == 480)      ModeIndex = ModeIndex_720x480[Depth];
+		else if(VDisplay == 576) ModeIndex = ModeIndex_720x576[Depth];
+		break;
+	case 768:
+          	if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth];
+	  	break;
+	case 800:
+		if(VDisplay == 600)      ModeIndex = ModeIndex_800x600[Depth];
+   	        else if(VDisplay == 480) ModeIndex = ModeIndex_800x480[Depth];
+		break;
+	case 848:
+		if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth];
+		break;
+	case 856:
+		if(VDisplay == 480) ModeIndex = ModeIndex_856x480[Depth];
+		break;
+	case 960:
+		if(VGAEngine == SIS_315_VGA) {
+		   if(VDisplay == 540)      ModeIndex = ModeIndex_960x540[Depth];
+		   else if(VDisplay == 600) ModeIndex = ModeIndex_960x600[Depth];
+		}
+		break;
+	case 1024:
+		if(VDisplay == 768)      ModeIndex = ModeIndex_1024x768[Depth];
+		else if(VDisplay == 576) ModeIndex = ModeIndex_1024x576[Depth];
+		break;
+	case 1152:
+	        if(VDisplay == 864)    ModeIndex = ModeIndex_1152x864[Depth];
+		else if(VGAEngine == SIS_300_VGA) {
+		   if(VDisplay == 768) ModeIndex = ModeIndex_1152x768[Depth];
+		}
+		break;
+	case 1280:
+	        if(VDisplay == 768) {
+		   if(VGAEngine == SIS_300_VGA) {
+		      ModeIndex = ModeIndex_300_1280x768[Depth];
+		   } else {
+		      ModeIndex = ModeIndex_310_1280x768[Depth];
+		   }
+		} else if(VDisplay == 1024) ModeIndex = ModeIndex_1280x1024[Depth];
+		else if(VDisplay == 720)    ModeIndex = ModeIndex_1280x720[Depth];
+		else if(VDisplay == 800)    ModeIndex = ModeIndex_1280x800[Depth];
+		else if(VDisplay == 960)    ModeIndex = ModeIndex_1280x960[Depth];
+		break;
+        case 1360:
+	        if(VDisplay == 768) ModeIndex = ModeIndex_1360x768[Depth];
+                break;
+        case 1400:
+		if(VGAEngine == SIS_315_VGA) {
+	           if(VDisplay == 1050) ModeIndex = ModeIndex_1400x1050[Depth];
+		}
+		break;
+	case 1600:
+		if(VGAEngine == SIS_315_VGA) {
+		   if(VBFlags & (VB_301B|VB_301C|VB_302B)) {
+	              if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth];
+		   }
+		}
+		break;
+	case 1680:
+		if(VGAEngine == SIS_315_VGA) {
+		   if(VBFlags & (VB_301B|VB_301C|VB_302B)) {
+	              if(VDisplay == 1050) ModeIndex = ModeIndex_1680x1050[Depth];
+		   }
+		}
+		break;
+   }
+
+   return ModeIndex;
+}
+
+
+/*********************************************/
+/*          HELPER: SetReg, GetReg           */
+/*********************************************/
+
+void
+SiS_SetReg(SISIOADDRESS port, USHORT index, USHORT data)
+{
+   OutPortByte(port,index);
+   OutPortByte(port + 1,data);
+}
+
+void
+SiS_SetRegByte(SISIOADDRESS port, USHORT data)
+{
+   OutPortByte(port,data);
+}
+
+void
+SiS_SetRegShort(SISIOADDRESS port, USHORT data)
+{
+   OutPortWord(port,data);
+}
+
+void
+SiS_SetRegLong(SISIOADDRESS port, ULONG data)
+{
+   OutPortLong(port,data);
+}
+
+UCHAR
+SiS_GetReg(SISIOADDRESS port, USHORT index)
+{
+   OutPortByte(port,index);
+   return(InPortByte(port + 1));
+}
+
+UCHAR
+SiS_GetRegByte(SISIOADDRESS port)
+{
+   return(InPortByte(port));
+}
+
+USHORT
+SiS_GetRegShort(SISIOADDRESS port)
+{
+   return(InPortWord(port));
+}
+
+ULONG
+SiS_GetRegLong(SISIOADDRESS port)
+{
+   return(InPortLong(port));
+}
+
+void
+SiS_SetRegANDOR(SISIOADDRESS Port,USHORT Index,USHORT DataAND,USHORT DataOR)
+{
+  USHORT temp;
+
+  temp = SiS_GetReg(Port,Index);
+  temp = (temp & (DataAND)) | DataOR;
+  SiS_SetReg(Port,Index,temp);
+}
+
+void
+SiS_SetRegAND(SISIOADDRESS Port,USHORT Index,USHORT DataAND)
+{
+  USHORT temp;
+
+  temp = SiS_GetReg(Port,Index);
+  temp &= DataAND;
+  SiS_SetReg(Port,Index,temp);
+}
+
+void
+SiS_SetRegOR(SISIOADDRESS Port,USHORT Index,USHORT DataOR)
+{
+  USHORT temp;
+
+  temp = SiS_GetReg(Port,Index);
+  temp |= DataOR;
+  SiS_SetReg(Port,Index,temp);
+}
+
+/*********************************************/
+/*      HELPER: DisplayOn, DisplayOff        */
+/*********************************************/
+
+void
+SiS_DisplayOn(SiS_Private *SiS_Pr)
+{
+   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x01,0xDF);
+}
+
+void
+SiS_DisplayOff(SiS_Private *SiS_Pr)
+{
+   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x01,0x20);
+}
+
+
+/*********************************************/
+/*        HELPER: Init Port Addresses        */
+/*********************************************/
+
+void
+SiSRegInit(SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr)
+{
+   SiS_Pr->SiS_P3c4 = BaseAddr + 0x14;
+   SiS_Pr->SiS_P3d4 = BaseAddr + 0x24;
+   SiS_Pr->SiS_P3c0 = BaseAddr + 0x10;
+   SiS_Pr->SiS_P3ce = BaseAddr + 0x1e;
+   SiS_Pr->SiS_P3c2 = BaseAddr + 0x12;
+   SiS_Pr->SiS_P3ca = BaseAddr + 0x1a;
+   SiS_Pr->SiS_P3c6 = BaseAddr + 0x16;
+   SiS_Pr->SiS_P3c7 = BaseAddr + 0x17;
+   SiS_Pr->SiS_P3c8 = BaseAddr + 0x18;
+   SiS_Pr->SiS_P3c9 = BaseAddr + 0x19;
+   SiS_Pr->SiS_P3cb = BaseAddr + 0x1b;
+   SiS_Pr->SiS_P3cd = BaseAddr + 0x1d;
+   SiS_Pr->SiS_P3da = BaseAddr + 0x2a;
+   SiS_Pr->SiS_Part1Port = BaseAddr + SIS_CRT2_PORT_04;     /* Digital video interface registers (LCD) */
+   SiS_Pr->SiS_Part2Port = BaseAddr + SIS_CRT2_PORT_10;     /* 301 TV Encoder registers */
+   SiS_Pr->SiS_Part3Port = BaseAddr + SIS_CRT2_PORT_12;     /* 301 Macrovision registers */
+   SiS_Pr->SiS_Part4Port = BaseAddr + SIS_CRT2_PORT_14;     /* 301 VGA2 (and LCD) registers */
+   SiS_Pr->SiS_Part5Port = BaseAddr + SIS_CRT2_PORT_14 + 2; /* 301 palette address port registers */
+   SiS_Pr->SiS_DDC_Port = BaseAddr + 0x14;                  /* DDC Port ( = P3C4, SR11/0A) */
+   SiS_Pr->SiS_VidCapt = BaseAddr + SIS_VIDEO_CAPTURE;
+   SiS_Pr->SiS_VidPlay = BaseAddr + SIS_VIDEO_PLAYBACK;
+}
+
+/*********************************************/
+/*             HELPER: GetSysFlags           */
+/*********************************************/
+
+static void
+SiS_GetSysFlags(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+   unsigned char cr5f, temp1, temp2;
+
+   /* 661 and newer: NEVER write non-zero to SR11[7:4] */
+   /* (SR11 is used for DDC and in enable/disablebridge) */
+   SiS_Pr->SiS_SensibleSR11 = FALSE;
+   SiS_Pr->SiS_MyCR63 = 0x63;
+   if(HwInfo->jChipType >= SIS_330) {
+      SiS_Pr->SiS_MyCR63 = 0x53;
+      if(HwInfo->jChipType >= SIS_661) {
+         SiS_Pr->SiS_SensibleSR11 = TRUE;
+      }
+   }
+
+   /* You should use the macros, not these flags directly */
+
+   SiS_Pr->SiS_SysFlags = 0;
+   if(HwInfo->jChipType == SIS_650) {
+      cr5f = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0xf0;
+      SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x5c,0x07);
+      temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5c) & 0xf8;
+      SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x5c,0xf8);
+      temp2 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5c) & 0xf8;
+      if((!temp1) || (temp2)) {
+         switch(cr5f) {
+	    case 0x80:
+	    case 0x90:
+	    case 0xc0:
+	       SiS_Pr->SiS_SysFlags |= SF_IsM650;  break;
+	    case 0xa0:
+	    case 0xb0:
+	    case 0xe0:
+	       SiS_Pr->SiS_SysFlags |= SF_Is651;   break;
+	 }
+      } else {
+         switch(cr5f) {
+	    case 0x90:
+	       temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5c) & 0xf8;
+	       switch(temp1) {
+	          case 0x00: SiS_Pr->SiS_SysFlags |= SF_IsM652; break;
+		  case 0x40: SiS_Pr->SiS_SysFlags |= SF_IsM653; break;
+		  default:   SiS_Pr->SiS_SysFlags |= SF_IsM650; break;
+	       }
+	       break;
+	    case 0xb0:
+	       SiS_Pr->SiS_SysFlags |= SF_Is652;  break;
+	    default:
+	       SiS_Pr->SiS_SysFlags |= SF_IsM650; break;
+	 }
+      }
+   }
+   if(HwInfo->jChipType == SIS_760) {
+      temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x78);
+      if(temp1 & 0x30) SiS_Pr->SiS_SysFlags |= SF_760LFB;
+   }
+}
+
+/*********************************************/
+/*         HELPER: Init PCI & Engines        */
+/*********************************************/
+
+static void
+SiSInitPCIetc(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+   switch(HwInfo->jChipType) {
+   case SIS_300:
+   case SIS_540:
+   case SIS_630:
+   case SIS_730:
+      /* Set - PCI LINEAR ADDRESSING ENABLE (0x80)
+       *     - RELOCATED VGA IO  (0x20)
+       *     - MMIO ENABLE (0x1)
+       */
+      SiS_SetReg(SiS_Pr->SiS_P3c4,0x20,0xa1);
+      /*  - Enable 2D (0x40)
+       *  - Enable 3D (0x02)
+       *  - Enable 3D Vertex command fetch (0x10) ?
+       *  - Enable 3D command parser (0x08) ?
+       */
+      SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x5A);
+      break;
+   case SIS_315H:
+   case SIS_315:
+   case SIS_315PRO:
+   case SIS_650:
+   case SIS_740:
+   case SIS_330:
+   case SIS_661:
+   case SIS_741:
+   case SIS_660:
+   case SIS_760:
+   case SIS_761:
+   case SIS_340:
+      SiS_SetReg(SiS_Pr->SiS_P3c4,0x20,0xa1);
+      /*  - Enable 2D (0x40)
+       *  - Enable 3D (0x02)
+       *  - Enable 3D vertex command fetch (0x10)
+       *  - Enable 3D command parser (0x08)
+       *  - Enable 3D G/L transformation engine (0x80)
+       */
+      SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0xDA);
+      break;
+   case SIS_550:
+      SiS_SetReg(SiS_Pr->SiS_P3c4,0x20,0xa1);
+      /* No 3D engine ! */
+      /*  - Enable 2D (0x40)
+       */
+      SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x40);
+   }
+}
+
+/*********************************************/
+/*             HELPER: SetLVDSetc            */
+/*********************************************/
+
+void
+SiSSetLVDSetc(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+   USHORT temp;
+
+   SiS_Pr->SiS_IF_DEF_LVDS = 0;
+   SiS_Pr->SiS_IF_DEF_TRUMPION = 0;
+   SiS_Pr->SiS_IF_DEF_CH70xx = 0;
+   SiS_Pr->SiS_IF_DEF_DSTN = 0;
+   SiS_Pr->SiS_IF_DEF_FSTN = 0;
+   SiS_Pr->SiS_IF_DEF_CONEX = 0;
+
+   SiS_Pr->SiS_ChrontelInit = 0;
+
+   /* Check for SiS30x first */
+   temp = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00);
+   if((temp == 1) || (temp == 2)) return;
+
+   switch(HwInfo->jChipType) {
+#ifdef SIS300
+   case SIS_540:
+   case SIS_630:
+   case SIS_730:
+      	temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37);
+      	temp = (temp & 0x0E) >> 1;
+      	if((temp >= 2) && (temp <= 5)) 	SiS_Pr->SiS_IF_DEF_LVDS = 1;
+      	if(temp == 3)   		SiS_Pr->SiS_IF_DEF_TRUMPION = 1;
+      	if((temp == 4) || (temp == 5)) {
+		/* Save power status (and error check) - UNUSED */
+		SiS_Pr->SiS_Backup70xx = SiS_GetCH700x(SiS_Pr, 0x0e);
+		SiS_Pr->SiS_IF_DEF_CH70xx = 1;
+        }
+	break;
+#endif
+#ifdef SIS315H
+   case SIS_550:
+   case SIS_650:
+   case SIS_740:
+   case SIS_330:
+        temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37);
+      	temp = (temp & 0x0E) >> 1;
+      	if((temp >= 2) && (temp <= 3)) 	SiS_Pr->SiS_IF_DEF_LVDS = 1;
+      	if(temp == 3)  			SiS_Pr->SiS_IF_DEF_CH70xx = 2;
+        break;
+   case SIS_661:
+   case SIS_741:
+   case SIS_660:
+   case SIS_760:
+   case SIS_761:
+   case SIS_340:
+        temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
+      	temp = (temp & 0xe0) >> 5;
+      	if((temp >= 2) && (temp <= 3)) 	SiS_Pr->SiS_IF_DEF_LVDS = 1;
+      	if(temp == 3)  			SiS_Pr->SiS_IF_DEF_CH70xx = 2;
+	if(temp == 4)  			SiS_Pr->SiS_IF_DEF_CONEX = 1;  /* Not yet supported */
+        break;
+#endif
+   default:
+        break;
+   }
+}
+
+/*********************************************/
+/*          HELPER: Enable DSTN/FSTN         */
+/*********************************************/
+
+void
+SiS_SetEnableDstn(SiS_Private *SiS_Pr, int enable)
+{
+   SiS_Pr->SiS_IF_DEF_DSTN = enable ? 1 : 0;
+}
+
+void
+SiS_SetEnableFstn(SiS_Private *SiS_Pr, int enable)
+{
+   SiS_Pr->SiS_IF_DEF_FSTN = enable ? 1 : 0;
+}
+
+/*********************************************/
+/*        HELPER: Determine ROM usage        */
+/*********************************************/
+
+BOOLEAN
+SiSDetermineROMLayout661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+   UCHAR  *ROMAddr  = HwInfo->pjVirtualRomBase;
+   USHORT romversoffs, romvmaj = 1, romvmin = 0;
+
+   if(HwInfo->jChipType >= SIS_761) {
+      /* I very much assume 761 and 340 will use new layout */
+      return TRUE;
+   } else if(HwInfo->jChipType >= SIS_661) {
+      if((ROMAddr[0x1a] == 'N') &&
+         (ROMAddr[0x1b] == 'e') &&
+         (ROMAddr[0x1c] == 'w') &&
+         (ROMAddr[0x1d] == 'V')) {
+	 return TRUE;
+      }
+      romversoffs = ROMAddr[0x16] | (ROMAddr[0x17] << 8);
+      if(romversoffs) {
+	 if((ROMAddr[romversoffs+1] == '.') || (ROMAddr[romversoffs+4] == '.')) {
+	    romvmaj = ROMAddr[romversoffs] - '0';
+	    romvmin = ((ROMAddr[romversoffs+2] -'0') * 10) + (ROMAddr[romversoffs+3] - '0');
+	 }
+      }
+      if((romvmaj != 0) || (romvmin >= 92)) {
+	 return TRUE;
+      }
+   } else if(IS_SIS650740) {
+      if((ROMAddr[0x1a] == 'N') &&
+         (ROMAddr[0x1b] == 'e') &&
+         (ROMAddr[0x1c] == 'w') &&
+         (ROMAddr[0x1d] == 'V')) {
+	 return TRUE;
+      }
+   }
+   return FALSE;
+}
+
+static void
+SiSDetermineROMUsage(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+   UCHAR  *ROMAddr  = HwInfo->pjVirtualRomBase;
+   USHORT romptr = 0;
+
+   SiS_Pr->SiS_UseROM = FALSE;
+   SiS_Pr->SiS_ROMNew = FALSE;
+
+   if((ROMAddr) && (HwInfo->UseROM)) {
+      if(HwInfo->jChipType == SIS_300) {
+         /* 300: We check if the code starts below 0x220 by
+	  * checking the jmp instruction at the beginning
+	  * of the BIOS image.
+	  */
+	 if((ROMAddr[3] == 0xe9) && ((ROMAddr[5] << 8) | ROMAddr[4]) > 0x21a)
+	    SiS_Pr->SiS_UseROM = TRUE;
+      } else if(HwInfo->jChipType < SIS_315H) {
+	 /* Sony's VAIO BIOS 1.09 follows the standard, so perhaps
+	  * the others do as well
+	  */
+	 SiS_Pr->SiS_UseROM = TRUE;
+      } else {
+         /* 315/330 series stick to the standard(s) */
+	 SiS_Pr->SiS_UseROM = TRUE;
+	 if((SiS_Pr->SiS_ROMNew = SiSDetermineROMLayout661(SiS_Pr, HwInfo))) {
+	    SiS_Pr->SiS_EMIOffset = 14;
+	    SiS_Pr->SiS661LCD2TableSize = 36;
+	    /* Find out about LCD data table entry size */
+	    if((romptr = SISGETROMW(0x0102))) {
+	       if(ROMAddr[romptr + (32 * 16)] == 0xff)
+	          SiS_Pr->SiS661LCD2TableSize = 32;
+	       else if(ROMAddr[romptr + (34 * 16)] == 0xff)
+	          SiS_Pr->SiS661LCD2TableSize = 34;
+	       else if(ROMAddr[romptr + (36 * 16)] == 0xff)	   /* 0.94 */
+	          SiS_Pr->SiS661LCD2TableSize = 36;
+	       else if( (ROMAddr[romptr + (38 * 16)] == 0xff) ||   /* 2.00.00 - 2.02.00 */
+	       	 	(ROMAddr[0x6F] & 0x01) ) {		   /* 2.03.00+ */
+		  SiS_Pr->SiS661LCD2TableSize = 38;
+		  SiS_Pr->SiS_EMIOffset = 16;
+	       }
+	    }
+	 }
+      }
+   }
+}
+
+/*********************************************/
+/*        HELPER: SET SEGMENT REGISTERS      */
+/*********************************************/
+
+static void
+SiS_SetSegRegLower(SiS_Private *SiS_Pr, USHORT value)
+{
+   USHORT temp;
+
+   value &= 0x00ff;
+   temp = SiS_GetRegByte(SiS_Pr->SiS_P3cb) & 0xf0;
+   temp |= (value >> 4);
+   SiS_SetRegByte(SiS_Pr->SiS_P3cb, temp);
+   temp = SiS_GetRegByte(SiS_Pr->SiS_P3cd) & 0xf0;
+   temp |= (value & 0x0f);
+   SiS_SetRegByte(SiS_Pr->SiS_P3cd, temp);
+}
+
+static void
+SiS_SetSegRegUpper(SiS_Private *SiS_Pr, USHORT value)
+{
+   USHORT temp;
+
+   value &= 0x00ff;
+   temp = SiS_GetRegByte(SiS_Pr->SiS_P3cb) & 0x0f;
+   temp |= (value & 0xf0);
+   SiS_SetRegByte(SiS_Pr->SiS_P3cb, temp);
+   temp = SiS_GetRegByte(SiS_Pr->SiS_P3cd) & 0x0f;
+   temp |= (value << 4);
+   SiS_SetRegByte(SiS_Pr->SiS_P3cd, temp);
+}
+
+static void
+SiS_SetSegmentReg(SiS_Private *SiS_Pr, USHORT value)
+{
+   SiS_SetSegRegLower(SiS_Pr, value);
+   SiS_SetSegRegUpper(SiS_Pr, value);
+}
+
+static void
+SiS_ResetSegmentReg(SiS_Private *SiS_Pr)
+{
+   SiS_SetSegmentReg(SiS_Pr, 0);
+}
+
+static void
+SiS_SetSegmentRegOver(SiS_Private *SiS_Pr, USHORT value)
+{
+   USHORT temp = value >> 8;
+
+   temp &= 0x07;
+   temp |= (temp << 4);
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x1d,temp);
+   SiS_SetSegmentReg(SiS_Pr, value);
+}
+
+static void
+SiS_ResetSegmentRegOver(SiS_Private *SiS_Pr)
+{
+   SiS_SetSegmentRegOver(SiS_Pr, 0);
+}
+
+static void
+SiS_ResetSegmentRegisters(SiS_Private *SiS_Pr,PSIS_HW_INFO HwInfo)
+{
+   if((IS_SIS65x) || (HwInfo->jChipType >= SIS_661)) {
+      SiS_ResetSegmentReg(SiS_Pr);
+      SiS_ResetSegmentRegOver(SiS_Pr);
+   }
+}
+
+/*********************************************/
+/*             HELPER: GetVBType             */
+/*********************************************/
+
+void
+SiS_GetVBType(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  USHORT flag=0, rev=0, nolcd=0, p4_0f, p4_25, p4_27;
+
+  SiS_Pr->SiS_VBType = 0;
+
+  if((SiS_Pr->SiS_IF_DEF_LVDS) || (SiS_Pr->SiS_IF_DEF_CONEX))
+     return;
+
+  flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00);
+
+  if(flag > 3) return;
+
+  rev = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01);
+
+  if(flag >= 2) {
+     SiS_Pr->SiS_VBType = VB_SIS302B;
+  } else if(flag == 1) {
+     if(rev >= 0xC0) {
+       	SiS_Pr->SiS_VBType = VB_SIS301C;
+     } else if(rev >= 0xB0) {
+       	SiS_Pr->SiS_VBType = VB_SIS301B;
+	/* Check if 30xB DH version (no LCD support, use Panel Link instead) */
+    	nolcd = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x23);
+        if(!(nolcd & 0x02)) SiS_Pr->SiS_VBType |= VB_NoLCD;
+     } else {
+        SiS_Pr->SiS_VBType = VB_SIS301;
+     }
+  }
+  if(SiS_Pr->SiS_VBType & (VB_SIS301B | VB_SIS301C | VB_SIS302B)) {
+     if(rev >= 0xE0) {
+	flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x39);
+	if(flag == 0xff) SiS_Pr->SiS_VBType = VB_SIS302LV;
+	else 	 	 SiS_Pr->SiS_VBType = VB_SIS301C;  /* VB_SIS302ELV; */
+     } else if(rev >= 0xD0) {
+	SiS_Pr->SiS_VBType = VB_SIS301LV;
+     }
+  }
+  if(SiS_Pr->SiS_VBType & (VB_301C | VB_301LV | VB_302LV | VB_302ELV)) {
+     p4_0f = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x0f);
+     p4_25 = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x25);
+     p4_27 = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x27);
+     SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x0f,0x7f);
+     SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x25,0x08);
+     SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x27,0xfd);
+     if(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x26) & 0x08) {
+        SiS_Pr->SiS_VBType |= VB_UMC;
+     }
+     SiS_SetReg(SiS_Pr->SiS_Part4Port,0x27,p4_27);
+     SiS_SetReg(SiS_Pr->SiS_Part4Port,0x25,p4_25);
+     SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0f,p4_0f);
+  }
+}
+
+/*********************************************/
+/*           HELPER: Check RAM size          */
+/*********************************************/
+
+#ifdef LINUX_KERNEL
+static BOOLEAN
+SiS_CheckMemorySize(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+                    USHORT ModeNo, USHORT ModeIdIndex)
+{
+  USHORT AdapterMemSize = HwInfo->ulVideoMemorySize / (1024*1024);
+  USHORT memorysize,modeflag;
+
+  if(SiS_Pr->UseCustomMode) {
+     modeflag = SiS_Pr->CModeFlag;
+  } else {
+     if(ModeNo <= 0x13) {
+        modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+     } else {
+        modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+     }
+  }
+
+  memorysize = modeflag & MemoryInfoFlag;
+  memorysize >>= MemorySizeShift;		/* Get required memory size */
+  memorysize++;
+
+  if(AdapterMemSize < memorysize) return FALSE;
+  return TRUE;
+}
+#endif
+
+/*********************************************/
+/*           HELPER: Get DRAM type           */
+/*********************************************/
+
+#ifdef SIS315H
+static UCHAR
+SiS_Get310DRAMType(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+   UCHAR data, temp;
+
+   if((*SiS_Pr->pSiS_SoftSetting) & SoftDRAMType) {
+     data = (*SiS_Pr->pSiS_SoftSetting) & 0x03;
+   } else {
+     if(HwInfo->jChipType >= SIS_340) {
+        /* TODO */
+	data = 0;
+     } if(HwInfo->jChipType >= SIS_661) {
+        data = SiS_GetReg(SiS_Pr->SiS_P3d4,0x78) & 0x07;
+	if(SiS_Pr->SiS_ROMNew) {
+	   data = ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x78) & 0xc0) >> 6);
+	}
+     } else if(IS_SIS550650740) {
+        data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x07;
+     } else {	/* 315, 330 */
+        data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x3a) & 0x03;
+        if(HwInfo->jChipType == SIS_330) {
+	   if(data > 1) {
+	      temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0x30;
+	      switch(temp) {
+	      case 0x00: data = 1; break;
+	      case 0x10: data = 3; break;
+	      case 0x20: data = 3; break;
+	      case 0x30: data = 2; break;
+	      }
+	   } else {
+	      data = 0;
+	   }
+	}
+     }
+   }
+
+   return data;
+}
+
+static USHORT
+SiS_GetMCLK(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+  USHORT index;
+
+  index = SiS_Get310DRAMType(SiS_Pr, HwInfo);
+  if(HwInfo->jChipType >= SIS_661) {
+     if(SiS_Pr->SiS_ROMNew) {
+        return((USHORT)(SISGETROMW((0x90 + (index * 5) + 3))));
+     }
+     return(SiS_Pr->SiS_MCLKData_0[index].CLOCK);
+  } else if(index >= 4) {
+     index -= 4;
+     return(SiS_Pr->SiS_MCLKData_1[index].CLOCK);
+  } else {
+     return(SiS_Pr->SiS_MCLKData_0[index].CLOCK);
+  }
+}
+#endif
+
+/*********************************************/
+/*           HELPER: ClearBuffer             */
+/*********************************************/
+
+#ifdef LINUX_KERNEL
+static void
+SiS_ClearBuffer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo)
+{
+  UCHAR SISIOMEMTYPE *VideoMemoryAddress = HwInfo->pjVideoMemoryAddress;
+  ULONG  AdapterMemorySize = HwInfo->ulVideoMemorySize;
+  USHORT SISIOMEMTYPE *pBuffer;
+  int i;
+
+  if(SiS_Pr->SiS_ModeType >= ModeEGA) {
+     if(ModeNo > 0x13) {
+        SiS_SetMemory(VideoMemoryAddress, AdapterMemorySize, 0);
+     } else {
+        pBuffer = (USHORT SISIOMEMTYPE *)VideoMemoryAddress;
+        for(i=0; i<0x4000; i++) writew(0x0000, &pBuffer[i]);
+     }
+  } else {
+     if(SiS_Pr->SiS_ModeType < ModeCGA) {
+        pBuffer = (USHORT SISIOMEMTYPE *)VideoMemoryAddress;
+        for(i=0; i<0x4000; i++) writew(0x0720, &pBuffer[i]);
+     } else {
+        SiS_SetMemory(VideoMemoryAddress, 0x8000, 0);
+     }
+  }
+}
+#endif
+
+/*********************************************/
+/*           HELPER: SearchModeID            */
+/*********************************************/
+
+BOOLEAN
+SiS_SearchModeID(SiS_Private *SiS_Pr, USHORT *ModeNo, USHORT *ModeIdIndex)
+{
+   UCHAR VGAINFO = SiS_Pr->SiS_VGAINFO;
+
+   if(*ModeNo <= 0x13) {
+
+      if((*ModeNo) <= 0x05) (*ModeNo) |= 0x01;
+
+      for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) {
+         if(SiS_Pr->SiS_SModeIDTable[*ModeIdIndex].St_ModeID == (*ModeNo)) break;
+         if(SiS_Pr->SiS_SModeIDTable[*ModeIdIndex].St_ModeID == 0xFF)   return FALSE;
+      }
+
+      if(*ModeNo == 0x07) {
+          if(VGAINFO & 0x10) (*ModeIdIndex)++;   /* 400 lines */
+          /* else 350 lines */
+      }
+      if(*ModeNo <= 0x03) {
+         if(!(VGAINFO & 0x80)) (*ModeIdIndex)++;
+         if(VGAINFO & 0x10)    (*ModeIdIndex)++; /* 400 lines  */
+         /* else 350 lines  */
+      }
+      /* else 200 lines  */
+
+   } else {
+
+      for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) {
+         if(SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo)) break;
+         if(SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF)      return FALSE;
+      }
+
+   }
+   return TRUE;
+}
+
+/*********************************************/
+/*            HELPER: GetModePtr             */
+/*********************************************/
+
+UCHAR
+SiS_GetModePtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex)
+{
+   UCHAR index;
+
+   if(ModeNo <= 0x13) {
+      index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_StTableIndex;
+   } else {
+      if(SiS_Pr->SiS_ModeType <= ModeEGA) index = 0x1B;
+      else index = 0x0F;
+   }
+   return index;
+}
+
+/*********************************************/
+/*           HELPER: LowModeTests            */
+/*********************************************/
+
+static BOOLEAN
+SiS_DoLowModeTest(SiS_Private *SiS_Pr, USHORT ModeNo, PSIS_HW_INFO HwInfo)
+{
+    USHORT temp,temp1,temp2;
+
+    if((ModeNo != 0x03) && (ModeNo != 0x10) && (ModeNo != 0x12))
+       return(TRUE);
+    temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x11);
+    SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x11,0x80);
+    temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x00);
+    SiS_SetReg(SiS_Pr->SiS_P3d4,0x00,0x55);
+    temp2 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x00);
+    SiS_SetReg(SiS_Pr->SiS_P3d4,0x00,temp1);
+    SiS_SetReg(SiS_Pr->SiS_P3d4,0x11,temp);
+    if((HwInfo->jChipType >= SIS_315H) ||
+       (HwInfo->jChipType == SIS_300)) {
+       if(temp2 == 0x55) return(FALSE);
+       else return(TRUE);
+    } else {
+       if(temp2 != 0x55) return(TRUE);
+       else {
+          SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01);
+          return(FALSE);
+       }
+    }
+}
+
+static void
+SiS_SetLowModeTest(SiS_Private *SiS_Pr, USHORT ModeNo, PSIS_HW_INFO HwInfo)
+{
+    if(SiS_DoLowModeTest(SiS_Pr, ModeNo, HwInfo)) {
+       SiS_Pr->SiS_SetFlag |= LowModeTests;
+    }
+}
+
+/*********************************************/
+/*            HELPER: ENABLE CRT1            */
+/*********************************************/
+
+static void
+SiS_SetupCR5x(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+    if(IS_SIS650) {
+       if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+	  SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f);
+	  if(IS_SIS651) SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x51,0x20);
+	  SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7);
+       }
+    } else if(IS_SIS661741660760) {
+       SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x61,0xf7);
+       SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f);
+       SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7);
+       if(!SiS_Pr->SiS_ROMNew) {
+	  SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x3a,0xef);
+       }
+    }
+}
+
+static void
+SiS_HandleCRT1(SiS_Private *SiS_Pr)
+{
+  /* Enable CRT1 gating */
+  SiS_SetRegAND(SiS_Pr->SiS_P3d4,SiS_Pr->SiS_MyCR63,0xbf);
+#if 0
+  if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x15) & 0x01)) {
+     if((SiS_GetReg(SiS_Pr->SiS_P3c4,0x15) & 0x0a) ||
+        (SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x01)) {
+        SiS_SetRegOR(SiS_Pr->SiS_P3d4,SiS_Pr->SiS_MyCR63,0x40);
+     }
+  }
+#endif
+}
+
+/*********************************************/
+/*           HELPER: GetColorDepth           */
+/*********************************************/
+
+USHORT
+SiS_GetColorDepth(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex)
+{
+  USHORT ColorDepth[6] = { 1, 2, 4, 4, 6, 8};
+  SHORT  index;
+  USHORT modeflag;
+
+  /* Do NOT check UseCustomMode, will skrew up FIFO */
+  if(ModeNo == 0xfe) {
+     modeflag = SiS_Pr->CModeFlag;
+  } else {
+     if(ModeNo <= 0x13)
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+     else
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+  }
+
+  index = (modeflag & ModeTypeMask) - ModeEGA;
+  if(index < 0) index = 0;
+  return(ColorDepth[index]);
+}
+
+/*********************************************/
+/*             HELPER: GetOffset             */
+/*********************************************/
+
+USHORT
+SiS_GetOffset(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex,
+              USHORT RefreshRateTableIndex,PSIS_HW_INFO HwInfo)
+{
+  USHORT xres, temp, colordepth, infoflag;
+
+  if(SiS_Pr->UseCustomMode) {
+     infoflag = SiS_Pr->CInfoFlag;
+     xres = SiS_Pr->CHDisplay;
+  } else {
+     infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+     xres = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].XRes;
+  }
+
+  colordepth = SiS_GetColorDepth(SiS_Pr,ModeNo,ModeIdIndex);
+
+  temp = xres / 16;
+  if(infoflag & InterlaceMode) temp <<= 1;
+  temp *= colordepth;
+  if(xres % 16) {
+     colordepth >>= 1;
+     temp += colordepth;
+  }
+
+  return(temp);
+}
+
+/*********************************************/
+/*                   SEQ                     */
+/*********************************************/
+
+static void
+SiS_SetSeqRegs(SiS_Private *SiS_Pr, USHORT StandTableIndex, PSIS_HW_INFO HwInfo)
+{
+   UCHAR SRdata;
+   USHORT i;
+
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x00,0x03);           	/* Set SR0  */
+
+   SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0];
+
+   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+         SRdata |= 0x01;
+      }
+      if(HwInfo->jChipType >= SIS_661) {
+         if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToTV)) {
+	    if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+               SRdata |= 0x01;          		/* 8 dot clock  */
+            }
+	 }
+      } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+         if(SiS_Pr->SiS_VBType & VB_NoLCD) {
+	    if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+               SRdata |= 0x01;          		/* 8 dot clock  */
+            }
+	 }
+      }
+   }
+
+   if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+      if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+         if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+            if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+               SRdata |= 0x01;        			/* 8 dot clock  */
+            }
+         }
+      }
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+         if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+            SRdata |= 0x01;          			/* 8 dot clock  */
+         }
+      }
+   }
+
+   SRdata |= 0x20;                			/* screen off  */
+
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x01,SRdata);
+
+   for(i = 2; i <= 4; i++) {
+      SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i-1];
+      SiS_SetReg(SiS_Pr->SiS_P3c4,i,SRdata);
+   }
+}
+
+/*********************************************/
+/*                  MISC                     */
+/*********************************************/
+
+static void
+SiS_SetMiscRegs(SiS_Private *SiS_Pr, USHORT StandTableIndex, PSIS_HW_INFO HwInfo)
+{
+   UCHAR Miscdata;
+
+   Miscdata = SiS_Pr->SiS_StandTable[StandTableIndex].MISC;
+
+   if(HwInfo->jChipType < SIS_661) {
+      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+         if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+            Miscdata |= 0x0C;
+         }
+      }
+   }
+
+   SiS_SetRegByte(SiS_Pr->SiS_P3c2,Miscdata);
+}
+
+/*********************************************/
+/*                  CRTC                     */
+/*********************************************/
+
+static void
+SiS_SetCRTCRegs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+                USHORT StandTableIndex)
+{
+  UCHAR CRTCdata;
+  USHORT i;
+
+  SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f);                       /* Unlock CRTC */
+
+  for(i = 0; i <= 0x18; i++) {
+     CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i];
+     SiS_SetReg(SiS_Pr->SiS_P3d4,i,CRTCdata);                     /* Set CRTC(3d4) */
+  }
+  if(HwInfo->jChipType >= SIS_661) {
+     SiS_SetupCR5x(SiS_Pr, HwInfo);
+     for(i = 0x13; i <= 0x14; i++) {
+        CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i];
+        SiS_SetReg(SiS_Pr->SiS_P3d4,i,CRTCdata);
+     }
+  } else if( ( (HwInfo->jChipType == SIS_630) ||
+               (HwInfo->jChipType == SIS_730) )  &&
+             (HwInfo->jChipRevision >= 0x30) ) {       	   /* for 630S0 */
+     if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+        if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToTV)) {
+           SiS_SetReg(SiS_Pr->SiS_P3d4,0x18,0xFE);
+        }
+     }
+  }
+}
+
+/*********************************************/
+/*                   ATT                     */
+/*********************************************/
+
+static void
+SiS_SetATTRegs(SiS_Private *SiS_Pr, USHORT StandTableIndex,
+               PSIS_HW_INFO HwInfo)
+{
+   UCHAR ARdata;
+   USHORT i;
+
+   for(i = 0; i <= 0x13; i++) {
+      ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i];
+#if 0
+      if((i <= 0x0f) || (i == 0x11)) {
+         if(ds:489 & 0x08) {
+	    continue;
+         }
+      }
+#endif
+      if(i == 0x13) {
+         /* Pixel shift. If screen on LCD or TV is shifted left or right,
+          * this might be the cause.
+          */
+         if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+            if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)  ARdata=0;
+         }
+         if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+            if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+               if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+                  if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata=0;
+               }
+            }
+         }
+	 if(HwInfo->jChipType >= SIS_661) {
+	    if(SiS_Pr->SiS_VBInfo & (SetCRT2ToTV | SetCRT2ToLCD)) {
+	       if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata=0;
+	    }
+	 } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+            if(HwInfo->jChipType >= SIS_315H) {
+	       if(IS_SIS550650740660) {
+	          /* 315, 330 don't do this */
+	          if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
+	             if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata=0;
+	          } else {
+	             ARdata = 0;
+	          }
+	       }
+	    } else {
+               if(SiS_Pr->SiS_VBInfo & SetInSlaveMode)  ARdata=0;
+	    }
+         }
+      }
+      SiS_GetRegByte(SiS_Pr->SiS_P3da);                         /* reset 3da  */
+      SiS_SetRegByte(SiS_Pr->SiS_P3c0,i);                       /* set index  */
+      SiS_SetRegByte(SiS_Pr->SiS_P3c0,ARdata);                  /* set data   */
+   }
+   SiS_GetRegByte(SiS_Pr->SiS_P3da);                            /* reset 3da  */
+   SiS_SetRegByte(SiS_Pr->SiS_P3c0,0x14);                       /* set index  */
+   SiS_SetRegByte(SiS_Pr->SiS_P3c0,0x00);                       /* set data   */
+
+   SiS_GetRegByte(SiS_Pr->SiS_P3da);
+   SiS_SetRegByte(SiS_Pr->SiS_P3c0,0x20);			/* Enable Attribute  */
+   SiS_GetRegByte(SiS_Pr->SiS_P3da);
+}
+
+/*********************************************/
+/*                   GRC                     */
+/*********************************************/
+
+static void
+SiS_SetGRCRegs(SiS_Private *SiS_Pr, USHORT StandTableIndex)
+{
+   UCHAR GRdata;
+   USHORT i;
+
+   for(i = 0; i <= 0x08; i++) {
+      GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i];
+      SiS_SetReg(SiS_Pr->SiS_P3ce,i,GRdata);
+   }
+
+   if(SiS_Pr->SiS_ModeType > ModeVGA) {
+      /* 256 color disable */
+      SiS_SetRegAND(SiS_Pr->SiS_P3ce,0x05,0xBF);
+   }
+}
+
+/*********************************************/
+/*          CLEAR EXTENDED REGISTERS         */
+/*********************************************/
+
+static void
+SiS_ClearExt1Regs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo)
+{
+  USHORT i;
+
+  for(i = 0x0A; i <= 0x0E; i++) {
+     SiS_SetReg(SiS_Pr->SiS_P3c4,i,0x00);
+  }
+
+  if(HwInfo->jChipType >= SIS_315H) {
+     SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x37,0xFE);
+     if(ModeNo <= 0x13) {
+        if(ModeNo == 0x06 || ModeNo >= 0x0e) {
+	   SiS_SetReg(SiS_Pr->SiS_P3c4,0x0e,0x20);
+	}
+     }
+  }
+}
+
+/*********************************************/
+/*                 RESET VCLK                */
+/*********************************************/
+
+static void
+SiS_ResetCRT1VCLK(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+   if(HwInfo->jChipType >= SIS_315H) {
+      if(HwInfo->jChipType < SIS_661) {
+         if(SiS_Pr->SiS_IF_DEF_LVDS == 0) return;
+      }
+   } else {
+      if((SiS_Pr->SiS_IF_DEF_LVDS == 0) &&
+         (!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) ) {
+	 return;
+      }
+   }
+
+   if(HwInfo->jChipType >= SIS_315H) {
+      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x31,0xCF,0x20);
+   } else {
+      SiS_SetReg(SiS_Pr->SiS_P3c4,0x31,0x20);
+   }
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x2B,SiS_Pr->SiS_VCLKData[1].SR2B);
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x2C,SiS_Pr->SiS_VCLKData[1].SR2C);
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x80);
+   if(HwInfo->jChipType >= SIS_315H) {
+      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x31,0xcf,0x10);
+   } else {
+      SiS_SetReg(SiS_Pr->SiS_P3c4,0x31,0x10);
+   }
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x2B,SiS_Pr->SiS_VCLKData[0].SR2B);
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x2C,SiS_Pr->SiS_VCLKData[0].SR2C);
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x80);
+}
+
+/*********************************************/
+/*                  SYNC                     */
+/*********************************************/
+
+static void
+SiS_SetCRT1Sync(SiS_Private *SiS_Pr, USHORT RefreshRateTableIndex)
+{
+  USHORT sync;
+
+  if(SiS_Pr->UseCustomMode) {
+     sync = SiS_Pr->CInfoFlag >> 8;
+  } else {
+     sync = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag >> 8;
+  }
+
+  sync &= 0xC0;
+  sync |= 0x2f;
+  SiS_SetRegByte(SiS_Pr->SiS_P3c2,sync);
+}
+
+/*********************************************/
+/*                  CRTC/2                   */
+/*********************************************/
+
+static void
+SiS_SetCRT1CRTC(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+                USHORT RefreshRateTableIndex,
+		PSIS_HW_INFO HwInfo)
+{
+  UCHAR  index;
+  USHORT temp,i,j,modeflag;
+
+  SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f);		/* unlock cr0-7 */
+
+  if(SiS_Pr->UseCustomMode) {
+
+     modeflag = SiS_Pr->CModeFlag;
+
+     for(i=0,j=0;i<=7;i++,j++) {
+        SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]);
+     }
+     for(j=0x10;i<=10;i++,j++) {
+        SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]);
+     }
+     for(j=0x15;i<=12;i++,j++) {
+        SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]);
+     }
+     for(j=0x0A;i<=15;i++,j++) {
+        SiS_SetReg(SiS_Pr->SiS_P3c4,j,SiS_Pr->CCRT1CRTC[i]);
+     }
+
+     temp = SiS_Pr->CCRT1CRTC[16] & 0xE0;
+     SiS_SetReg(SiS_Pr->SiS_P3c4,0x0E,temp);
+
+     temp = (SiS_Pr->CCRT1CRTC[16] & 0x01) << 5;
+     if(modeflag & DoubleScanMode) temp |= 0x80;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0x5F,temp);
+
+  } else {
+
+     if(ModeNo <= 0x13) {
+        modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+     } else {
+        modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+     }
+
+     index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+
+     for(i=0,j=0;i<=7;i++,j++) {
+        SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]);
+     }
+     for(j=0x10;i<=10;i++,j++) {
+        SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]);
+     }
+     for(j=0x15;i<=12;i++,j++) {
+        SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]);
+     }
+     for(j=0x0A;i<=15;i++,j++) {
+        SiS_SetReg(SiS_Pr->SiS_P3c4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]);
+     }
+
+     temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0;
+     SiS_SetReg(SiS_Pr->SiS_P3c4,0x0E,temp);
+
+     temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5;
+     if(modeflag & DoubleScanMode)  temp |= 0x80;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0x5F,temp);
+
+  }
+
+  if(SiS_Pr->SiS_ModeType > ModeVGA) SiS_SetReg(SiS_Pr->SiS_P3d4,0x14,0x4F);
+}
+
+/*********************************************/
+/*               OFFSET & PITCH              */
+/*********************************************/
+/*  (partly overruled by SetPitch() in XF86) */
+/*********************************************/
+
+static void
+SiS_SetCRT1Offset(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+                  USHORT RefreshRateTableIndex,
+		  PSIS_HW_INFO HwInfo)
+{
+   USHORT temp, DisplayUnit, infoflag;
+
+   if(SiS_Pr->UseCustomMode) {
+      infoflag = SiS_Pr->CInfoFlag;
+   } else {
+      infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+   }
+
+   DisplayUnit = SiS_GetOffset(SiS_Pr,ModeNo,ModeIdIndex,
+                     	       RefreshRateTableIndex,HwInfo);
+
+   temp = (DisplayUnit >> 8) & 0x0f;
+   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0xF0,temp);
+
+   temp = DisplayUnit & 0xFF;
+   SiS_SetReg(SiS_Pr->SiS_P3d4,0x13,temp);
+
+   if(infoflag & InterlaceMode) DisplayUnit >>= 1;
+
+   DisplayUnit <<= 5;
+   temp = (DisplayUnit & 0xff00) >> 8;
+   if(DisplayUnit & 0xff) temp++;
+   temp++;
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x10,temp);
+}
+
+/*********************************************/
+/*                  VCLK                     */
+/*********************************************/
+
+static void
+SiS_SetCRT1VCLK(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+                PSIS_HW_INFO HwInfo, USHORT RefreshRateTableIndex)
+{
+  USHORT  index=0, clka, clkb;
+
+  if(SiS_Pr->UseCustomMode) {
+     clka = SiS_Pr->CSR2B;
+     clkb = SiS_Pr->CSR2C;
+  } else {
+     index = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
+     if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+        clka = SiS_Pr->SiS_VBVCLKData[index].Part4_A;
+	clkb = SiS_Pr->SiS_VBVCLKData[index].Part4_B;
+     } else {
+        clka = SiS_Pr->SiS_VCLKData[index].SR2B;
+	clkb = SiS_Pr->SiS_VCLKData[index].SR2C;
+     }
+  }
+
+  if(HwInfo->jChipType >= SIS_315H) {
+     SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x31,0xCF);
+  } else {
+     SiS_SetReg(SiS_Pr->SiS_P3c4,0x31,0x00);
+  }
+
+  SiS_SetReg(SiS_Pr->SiS_P3c4,0x2B,clka);
+  SiS_SetReg(SiS_Pr->SiS_P3c4,0x2C,clkb);
+
+  if(HwInfo->jChipType >= SIS_315H) {
+     SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x01);
+  } else {
+     SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x80);
+  }
+}
+
+/*********************************************/
+/*                  FIFO                     */
+/*********************************************/
+
+#ifdef SIS300
+static USHORT
+SiS_DoCalcDelay(SiS_Private *SiS_Pr, USHORT MCLK, USHORT VCLK, USHORT colordepth, USHORT key)
+{
+  const UCHAR ThLowA[]   = { 61, 3,52, 5,68, 7,100,11,
+                             43, 3,42, 5,54, 7, 78,11,
+                             34, 3,37, 5,47, 7, 67,11 };
+
+  const UCHAR ThLowB[]   = { 81, 4,72, 6,88, 8,120,12,
+                             55, 4,54, 6,66, 8, 90,12,
+                             42, 4,45, 6,55, 8, 75,12 };
+
+  const UCHAR ThTiming[] = {  1, 2, 2, 3, 0, 1,  1, 2 };
+
+  USHORT tempah, tempal, tempcl, tempbx, temp;
+  ULONG  longtemp;
+
+  tempah = SiS_GetReg(SiS_Pr->SiS_P3c4,0x18);
+  tempah &= 0x62;
+  tempah >>= 1;
+  tempal = tempah;
+  tempah >>= 3;
+  tempal |= tempah;
+  tempal &= 0x07;
+  tempcl = ThTiming[tempal];
+  tempbx = SiS_GetReg(SiS_Pr->SiS_P3c4,0x16);
+  tempbx >>= 6;
+  tempah = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14);
+  tempah >>= 4;
+  tempah &= 0x0c;
+  tempbx |= tempah;
+  tempbx <<= 1;
+  if(key == 0) {
+     tempal = ThLowA[tempbx + 1];
+     tempal *= tempcl;
+     tempal += ThLowA[tempbx];
+  } else {
+     tempal = ThLowB[tempbx + 1];
+     tempal *= tempcl;
+     tempal += ThLowB[tempbx];
+  }
+  longtemp = tempal * VCLK * colordepth;
+  temp = longtemp % (MCLK * 16);
+  longtemp /= (MCLK * 16);
+  if(temp) longtemp++;
+  return((USHORT)longtemp);
+}
+
+static USHORT
+SiS_CalcDelay(SiS_Private *SiS_Pr, USHORT VCLK, USHORT colordepth, USHORT MCLK)
+{
+  USHORT tempax, tempbx;
+
+  tempbx = SiS_DoCalcDelay(SiS_Pr, MCLK, VCLK, colordepth, 0);
+  tempax = SiS_DoCalcDelay(SiS_Pr, MCLK, VCLK, colordepth, 1);
+  if(tempax < 4) tempax = 4;
+  tempax -= 4;
+  if(tempbx < tempax) tempbx = tempax;
+  return(tempbx);
+}
+
+static void
+SiS_SetCRT1FIFO_300(SiS_Private *SiS_Pr, USHORT ModeNo, PSIS_HW_INFO HwInfo,
+                    USHORT RefreshRateTableIndex)
+{
+  USHORT  ThresholdLow = 0;
+  USHORT  index, VCLK, MCLK, colorth=0;
+  USHORT  tempah, temp;
+
+  if(ModeNo > 0x13) {
+
+     if(SiS_Pr->UseCustomMode) {
+        VCLK = SiS_Pr->CSRClock;
+     } else {
+        index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+        index &= 0x3F;
+        VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;             /* Get VCLK  */
+     }
+
+     switch (SiS_Pr->SiS_ModeType - ModeEGA) {     /* Get half colordepth */
+        case 0 : colorth = 1; break;
+        case 1 : colorth = 1; break;
+        case 2 : colorth = 2; break;
+        case 3 : colorth = 2; break;
+        case 4 : colorth = 3; break;
+        case 5 : colorth = 4; break;
+     }
+
+     index = SiS_GetReg(SiS_Pr->SiS_P3c4,0x3A);
+     index &= 0x07;
+     MCLK = SiS_Pr->SiS_MCLKData_0[index].CLOCK;           /* Get MCLK  */
+
+     tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
+     tempah &= 0xc3;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x16,0x3c,tempah);
+
+     do {
+        ThresholdLow = SiS_CalcDelay(SiS_Pr, VCLK, colorth, MCLK);
+        ThresholdLow++;
+        if(ThresholdLow < 0x13) break;
+        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x16,0xfc);
+        ThresholdLow = 0x13;
+        tempah = SiS_GetReg(SiS_Pr->SiS_P3c4,0x16);
+        tempah >>= 6;
+        if(!(tempah)) break;
+        tempah--;
+        tempah <<= 6;
+        SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x16,0x3f,tempah);
+     } while(0);
+
+  } else ThresholdLow = 2;
+
+  /* Write CRT/CPU threshold low, CRT/Engine threshold high */
+  temp = (ThresholdLow << 4) | 0x0f;
+  SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,temp);
+
+  temp = (ThresholdLow & 0x10) << 1;
+  if(ModeNo > 0x13) temp |= 0x40;
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0f,0x9f,temp);
+
+  /* What is this? */
+  SiS_SetReg(SiS_Pr->SiS_P3c4,0x3B,0x09);
+
+  /* Write CRT/CPU threshold high */
+  temp = ThresholdLow + 3;
+  if(temp > 0x0f) temp = 0x0f;
+  SiS_SetReg(SiS_Pr->SiS_P3c4,0x09,temp);
+}
+
+static USHORT
+SiS_CalcDelay2(SiS_Private *SiS_Pr, UCHAR key, PSIS_HW_INFO HwInfo)
+{
+  USHORT data,index;
+  const UCHAR  LatencyFactor[] = {
+   	97, 88, 86, 79, 77, 00,       /*; 64  bit    BQ=2   */
+        00, 87, 85, 78, 76, 54,       /*; 64  bit    BQ=1   */
+        97, 88, 86, 79, 77, 00,       /*; 128 bit    BQ=2   */
+        00, 79, 77, 70, 68, 48,       /*; 128 bit    BQ=1   */
+        80, 72, 69, 63, 61, 00,       /*; 64  bit    BQ=2   */
+        00, 70, 68, 61, 59, 37,       /*; 64  bit    BQ=1   */
+        86, 77, 75, 68, 66, 00,       /*; 128 bit    BQ=2   */
+        00, 68, 66, 59, 57, 37        /*; 128 bit    BQ=1   */
+  };
+  const UCHAR  LatencyFactor730[] = {
+         69, 63, 61,
+	 86, 79, 77,
+	103, 96, 94,
+	120,113,111,
+	137,130,128,    /* --- Table ends with this entry, data below */
+	137,130,128,	/* to avoid using illegal values              */
+	137,130,128,
+	137,130,128,
+	137,130,128,
+	137,130,128,
+	137,130,128,
+	137,130,128,
+	137,130,128,
+	137,130,128,
+	137,130,128,
+	137,130,128,
+  };
+
+  if(HwInfo->jChipType == SIS_730) {
+     index = ((key & 0x0f) * 3) + ((key & 0xC0) >> 6);
+     data = LatencyFactor730[index];
+  } else {
+     index = (key & 0xE0) >> 5;
+     if(key & 0x10) index +=6;
+     if(!(key & 0x01)) index += 24;
+     data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14);
+     if(data & 0x0080) index += 12;
+     data = LatencyFactor[index];
+  }
+  return(data);
+}
+
+static void
+SiS_SetCRT1FIFO_630(SiS_Private *SiS_Pr, USHORT ModeNo,
+ 		    PSIS_HW_INFO HwInfo,
+                    USHORT RefreshRateTableIndex)
+{
+  USHORT  i,index,data,VCLK,MCLK,colorth=0;
+  ULONG   B,eax,bl,data2;
+  USHORT  ThresholdLow=0;
+  UCHAR   FQBQData[]= {
+  	0x01,0x21,0x41,0x61,0x81,
+        0x31,0x51,0x71,0x91,0xb1,
+        0x00,0x20,0x40,0x60,0x80,
+        0x30,0x50,0x70,0x90,0xb0,
+	0xFF
+  };
+  UCHAR   FQBQData730[]= {
+        0x34,0x74,0xb4,
+	0x23,0x63,0xa3,
+	0x12,0x52,0x92,
+	0x01,0x41,0x81,
+	0x00,0x40,0x80,
+	0xff
+  };
+
+  i=0;
+  if(ModeNo > 0x13) {
+    if(SiS_Pr->UseCustomMode) {
+       VCLK = SiS_Pr->CSRClock;
+    } else {
+       index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+       index &= 0x3F;
+       VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;          /* Get VCLK  */
+    }
+
+    index = SiS_GetReg(SiS_Pr->SiS_P3c4,0x1A);
+    index &= 0x07;
+    MCLK = SiS_Pr->SiS_MCLKData_0[index].CLOCK;           /* Get MCLK  */
+
+    data2 = SiS_Pr->SiS_ModeType - ModeEGA;	  /* Get half colordepth */
+    switch (data2) {
+        case 0 : colorth = 1; break;
+        case 1 : colorth = 1; break;
+        case 2 : colorth = 2; break;
+        case 3 : colorth = 2; break;
+        case 4 : colorth = 3; break;
+        case 5 : colorth = 4; break;
+    }
+
+    if(HwInfo->jChipType == SIS_730) {
+
+       do {
+          B = SiS_CalcDelay2(SiS_Pr, FQBQData730[i], HwInfo) * VCLK * colorth;
+	  bl = B / (MCLK * 16);
+
+          if(B == bl * 16 * MCLK) {
+             bl = bl + 1;
+          } else {
+             bl = bl + 2;
+          }
+
+          if(bl > 0x13) {
+             if(FQBQData730[i+1] == 0xFF) {
+                ThresholdLow = 0x13;
+                break;
+             }
+             i++;
+          } else {
+             ThresholdLow = bl;
+             break;
+          }
+       } while(FQBQData730[i] != 0xFF);
+
+    } else {
+
+       do {
+          B = SiS_CalcDelay2(SiS_Pr, FQBQData[i], HwInfo) * VCLK * colorth;
+          bl = B / (MCLK * 16);
+
+          if(B == bl * 16 * MCLK) {
+             bl = bl + 1;
+          } else {
+             bl = bl + 2;
+          }
+
+          if(bl > 0x13) {
+             if(FQBQData[i+1] == 0xFF) {
+                ThresholdLow = 0x13;
+                break;
+             }
+             i++;
+          } else {
+             ThresholdLow = bl;
+             break;
+          }
+       } while(FQBQData[i] != 0xFF);
+    }
+  }
+  else {
+    if(HwInfo->jChipType == SIS_730) {
+    } else {
+      i = 9;
+    }
+    ThresholdLow = 0x02;
+  }
+
+  /* Write foreground and background queue */
+  if(HwInfo->jChipType == SIS_730) {
+
+     data2 = FQBQData730[i];
+     data2 = (data2 & 0xC0) >> 5;
+     data2 <<= 8;
+
+#ifdef LINUX_KERNEL
+     SiS_SetRegLong(0xcf8,0x80000050);
+     eax = SiS_GetRegLong(0xcfc);
+     eax &= 0xfffff9ff;
+     eax |= data2;
+     SiS_SetRegLong(0xcfc,eax);
+#else
+     /* We use pci functions X offers. We use pcitag 0, because
+      * we want to read/write to the host bridge (which is always
+      * 00:00.0 on 630, 730 and 540), not the VGA device.
+      */
+     eax = pciReadLong(0x00000000, 0x50);
+     eax &= 0xfffff9ff;
+     eax |= data2;
+     pciWriteLong(0x00000000, 0x50, eax);
+#endif
+
+     /* Write GUI grant timer (PCI config 0xA3) */
+     data2 = FQBQData730[i] << 8;
+     data2 = (data2 & 0x0f00) | ((data2 & 0x3000) >> 8);
+     data2 <<= 20;
+
+#ifdef LINUX_KERNEL
+     SiS_SetRegLong(0xcf8,0x800000A0);
+     eax = SiS_GetRegLong(0xcfc);
+     eax &= 0x00ffffff;
+     eax |= data2;
+     SiS_SetRegLong(0xcfc,eax);
+#else
+     eax = pciReadLong(0x00000000, 0xA0);
+     eax &= 0x00ffffff;
+     eax |= data2;
+     pciWriteLong(0x00000000, 0xA0, eax);
+#endif
+
+  } else {
+
+     data2 = FQBQData[i];
+     data2 = (data2 & 0xf0) >> 4;
+     data2 <<= 24;
+
+#ifdef LINUX_KERNEL
+     SiS_SetRegLong(0xcf8,0x80000050);
+     eax = SiS_GetRegLong(0xcfc);
+     eax &= 0xf0ffffff;
+     eax |= data2;
+     SiS_SetRegLong(0xcfc,eax);
+#else
+     eax = pciReadLong(0x00000000, 0x50);
+     eax &= 0xf0ffffff;
+     eax |= data2;
+     pciWriteLong(0x00000000, 0x50, eax);
+#endif
+
+     /* Write GUI grant timer (PCI config 0xA3) */
+     data2 = FQBQData[i];
+     data2 &= 0x0f;
+     data2 <<= 24;
+
+#ifdef LINUX_KERNEL
+     SiS_SetRegLong(0xcf8,0x800000A0);
+     eax = SiS_GetRegLong(0xcfc);
+     eax &= 0xf0ffffff;
+     eax |= data2;
+     SiS_SetRegLong(0xcfc,eax);
+#else
+     eax = pciReadLong(0x00000000, 0xA0);
+     eax &= 0xf0ffffff;
+     eax |= data2;
+     pciWriteLong(0x00000000, 0xA0, eax);
+#endif
+
+  }
+
+  /* Write CRT/CPU threshold low, CRT/Engine threshold high */
+  data = ((ThresholdLow & 0x0f) << 4) | 0x0f;
+  SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,data);
+
+  data = (ThresholdLow & 0x10) << 1;
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xDF,data);
+
+  /* What is this? */
+  SiS_SetReg(SiS_Pr->SiS_P3c4,0x3B,0x09);
+
+  /* Write CRT/CPU threshold high (gap = 3) */
+  data = ThresholdLow + 3;
+  if(data > 0x0f) data = 0x0f;
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x09,0x80,data);
+}
+#endif
+
+#ifdef SIS315H
+static void
+SiS_SetCRT1FIFO_310(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+                    PSIS_HW_INFO HwInfo)
+{
+  USHORT modeflag;
+
+  /* disable auto-threshold */
+  SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x3D,0xFE);
+
+  if(SiS_Pr->UseCustomMode) {
+     modeflag = SiS_Pr->CModeFlag;
+  } else {
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+  }
+
+  SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0xAE);
+  SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0);
+  if(ModeNo > 0x13) {
+     if(HwInfo->jChipType >= SIS_661) {
+        if(!(modeflag & HalfDCLK)) {
+	   SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0x34);
+	   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01);
+	}
+     } else {
+        if((!(modeflag & DoubleScanMode)) || (!(modeflag & HalfDCLK))) {
+           SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0x34);
+           SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01);
+	}
+     }
+  }
+}
+#endif
+
+/*********************************************/
+/*              MODE REGISTERS               */
+/*********************************************/
+
+static void
+SiS_SetVCLKState(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+                 USHORT ModeNo, USHORT RefreshRateTableIndex,
+                 USHORT ModeIdIndex)
+{
+  USHORT data=0, VCLK=0, index=0;
+
+  if(ModeNo > 0x13) {
+     if(SiS_Pr->UseCustomMode) {
+        VCLK = SiS_Pr->CSRClock;
+     } else {
+        index = SiS_GetVCLK2Ptr(SiS_Pr,ModeNo,ModeIdIndex,
+	                      RefreshRateTableIndex,HwInfo);
+        VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;
+     }
+  }
+
+  if(HwInfo->jChipType < SIS_315H) {
+
+     if(VCLK > 150) data |= 0x80;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0x7B,data);
+
+     data = 0x00;
+     if(VCLK >= 150) data |= 0x08;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xF7,data);
+
+  } else {
+
+     if(VCLK >= 166) data |= 0x0c;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xf3,data);
+
+     if(VCLK >= 166) {
+        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1f,0xe7);
+     }
+  }
+
+  /* DAC speed */
+  if(HwInfo->jChipType >= SIS_661) {
+
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xE8,0x10);
+
+  } else {
+
+     data = 0x03;
+     if((VCLK >= 135) && (VCLK < 160))      data = 0x02;
+     else if((VCLK >= 160) && (VCLK < 260)) data = 0x01;
+     else if(VCLK >= 260)                   data = 0x00;
+
+     if(HwInfo->jChipType == SIS_540) {
+        if((VCLK == 203) || (VCLK < 234))   data = 0x02;
+     }
+
+     if(HwInfo->jChipType < SIS_315H) {
+        SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xFC,data);
+     } else {
+        if(HwInfo->jChipType > SIS_315PRO) {
+           if(ModeNo > 0x13) data &= 0xfc;
+        }
+        SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xF8,data);
+     }
+
+  }
+}
+
+static void
+SiS_SetCRT1ModeRegs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+                    USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex)
+{
+  USHORT data,infoflag=0,modeflag;
+  USHORT resindex,xres;
+#ifdef SIS315H
+  USHORT data2,data3;
+  ULONG  longdata;
+  UCHAR  *ROMAddr  = HwInfo->pjVirtualRomBase;
+#endif
+
+  if(SiS_Pr->UseCustomMode) {
+     modeflag = SiS_Pr->CModeFlag;
+     infoflag = SiS_Pr->CInfoFlag;
+     xres = SiS_Pr->CHDisplay;
+  } else {
+     resindex = SiS_GetResInfo(SiS_Pr,ModeNo,ModeIdIndex);
+     if(ModeNo > 0x13) {
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+    	infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+	xres = SiS_Pr->SiS_ModeResInfo[resindex].HTotal;
+     } else {
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+	xres = SiS_Pr->SiS_StResInfo[resindex].HTotal;
+     }
+  }
+
+  /* Disable DPMS */
+  SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1F,0x3F);
+
+  data = 0;
+  if(ModeNo > 0x13) {
+     if(SiS_Pr->SiS_ModeType > ModeEGA) {
+        data |= 0x02;
+        data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2);
+     }
+     if(infoflag & InterlaceMode) data |= 0x20;
+  }
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x06,0xC0,data);
+
+  if(HwInfo->jChipType != SIS_300) {
+     data = 0;
+     if(infoflag & InterlaceMode) {
+        if(xres <= 800)       data = 0x0020;
+        else if(xres <= 1024) data = 0x0035;
+        else                  data = 0x0048;
+     }
+     SiS_SetReg(SiS_Pr->SiS_P3d4,0x19,(data & 0xFF));
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x1a,0xFC,(data >> 8));
+  }
+
+  if(modeflag & HalfDCLK) {
+     SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x01,0x08);
+  }
+
+  data = 0;
+  if(modeflag & LineCompareOff) data = 0x08;
+  if(HwInfo->jChipType == SIS_300) {
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xF7,data);
+  } else {
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xB7,data);
+     if(SiS_Pr->SiS_ModeType == ModeEGA) {
+        if(ModeNo > 0x13) {
+  	   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x0F,0x40);
+        }
+     }
+  }
+
+  if(HwInfo->jChipType >= SIS_661) {
+     SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x31,0xfb);
+  }
+
+#ifdef SIS315H
+  if(HwInfo->jChipType == SIS_315PRO) {
+
+     data = SiS_Get310DRAMType(SiS_Pr, HwInfo);
+     data = SiS_Pr->SiS_SR15[2][data];
+     if(SiS_Pr->SiS_ModeType == ModeText) {
+        data &= 0xc7;
+     } else {
+        data2 = SiS_GetOffset(SiS_Pr,ModeNo,ModeIdIndex,
+                              RefreshRateTableIndex,HwInfo);
+	data2 >>= 1;
+	if(infoflag & InterlaceMode) data2 >>= 1;
+	data3 = SiS_GetColorDepth(SiS_Pr,ModeNo,ModeIdIndex) >> 1;
+	if(!data3) data3++;
+	data2 /= data3;
+	if(data2 >= 0x50) {
+	   data &= 0x0f;
+	   data |= 0x50;
+	}
+     }
+     SiS_SetReg(SiS_Pr->SiS_P3c4,0x17,data);
+
+  } else if( (HwInfo->jChipType == SIS_330) ||
+             ((HwInfo->jChipType == SIS_760) && (SiS_Pr->SiS_SysFlags & SF_760LFB))) {
+
+     data = SiS_Get310DRAMType(SiS_Pr, HwInfo);
+     if(HwInfo->jChipType == SIS_330) {
+        data = SiS_Pr->SiS_SR15[2][data];
+     } else {
+        if(SiS_Pr->SiS_ROMNew) 	    data = ROMAddr[0xf6];
+        else if(SiS_Pr->SiS_UseROM) data = ROMAddr[0x100 + data];
+	else                        data = 0xba;
+     }
+     if(SiS_Pr->SiS_ModeType <= ModeEGA) {
+        data &= 0xc7;
+     } else {
+        if(SiS_Pr->UseCustomMode) {
+	   data2 = SiS_Pr->CSRClock;
+	} else {
+           data2 = SiS_GetVCLK2Ptr(SiS_Pr,ModeNo,ModeIdIndex,
+                                   RefreshRateTableIndex,HwInfo);
+           data2 = SiS_Pr->SiS_VCLKData[data2].CLOCK;
+	}
+
+	data3 = SiS_GetColorDepth(SiS_Pr,ModeNo,ModeIdIndex) >> 1;
+	if(data3) data2 *= data3;
+
+	longdata = SiS_GetMCLK(SiS_Pr, HwInfo) * 1024;
+
+	data2 = longdata / data2;
+
+	if(HwInfo->jChipType == SIS_330) {
+	   if(SiS_Pr->SiS_ModeType != Mode16Bpp) {
+              if     (data2 >= 0x19c) data = 0xba;
+	      else if(data2 >= 0x140) data = 0x7a;
+	      else if(data2 >= 0x101) data = 0x3a;
+	      else if(data2 >= 0xf5)  data = 0x32;
+	      else if(data2 >= 0xe2)  data = 0x2a;
+	      else if(data2 >= 0xc4)  data = 0x22;
+	      else if(data2 >= 0xac)  data = 0x1a;
+	      else if(data2 >= 0x9e)  data = 0x12;
+	      else if(data2 >= 0x8e)  data = 0x0a;
+	      else                    data = 0x02;
+	   } else {
+	      if(data2 >= 0x127)      data = 0xba;
+	      else                    data = 0x7a;
+	   }
+	} else {  /* 760+LFB */
+	   if     (data2 >= 0x190) data = 0xba;
+	   else if(data2 >= 0xff)  data = 0x7a;
+	   else if(data2 >= 0xd3)  data = 0x3a;
+	   else if(data2 >= 0xa9)  data = 0x1a;
+	   else if(data2 >= 0x93)  data = 0x0a;
+	   else                    data = 0x02;
+	}
+     }
+     SiS_SetReg(SiS_Pr->SiS_P3c4,0x17,data);
+  } else if(HwInfo->jChipType == SIS_340) {
+     /* TODO */
+  }
+#endif
+
+  data = 0x60;
+  if(SiS_Pr->SiS_ModeType != ModeText) {
+     data ^= 0x60;
+     if(SiS_Pr->SiS_ModeType != ModeEGA) {
+        data ^= 0xA0;
+     }
+  }
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x21,0x1F,data);
+
+  SiS_SetVCLKState(SiS_Pr, HwInfo, ModeNo, RefreshRateTableIndex, ModeIdIndex);
+
+#ifdef SIS315H
+  if(HwInfo->jChipType >= SIS_315H) {
+     if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & 0x40) {
+        SiS_SetReg(SiS_Pr->SiS_P3d4,0x52,0x2c);
+     } else {
+        SiS_SetReg(SiS_Pr->SiS_P3d4,0x52,0x6c);
+     }
+  }
+#endif
+}
+
+/*********************************************/
+/*                 LOAD DAC                  */
+/*********************************************/
+
+#if 0
+static void
+SiS_ClearDAC(SiS_Private *SiS_Pr, ULONG port)
+{
+   int i;
+
+   OutPortByte(port, 0);
+   port++;
+   for (i=0; i < (256 * 3); i++) {
+      OutPortByte(port, 0);
+   }
+}
+#endif
+
+static void
+SiS_WriteDAC(SiS_Private *SiS_Pr, SISIOADDRESS DACData, USHORT shiftflag,
+             USHORT dl, USHORT ah, USHORT al, USHORT dh)
+{
+  USHORT temp,bh,bl;
+
+  bh = ah;
+  bl = al;
+  if(dl != 0) {
+     temp = bh;
+     bh = dh;
+     dh = temp;
+     if(dl == 1) {
+        temp = bl;
+        bl = dh;
+        dh = temp;
+     } else {
+        temp = bl;
+        bl = bh;
+        bh = temp;
+     }
+  }
+  if(shiftflag) {
+     dh <<= 2;
+     bh <<= 2;
+     bl <<= 2;
+  }
+  SiS_SetRegByte(DACData,(USHORT)dh);
+  SiS_SetRegByte(DACData,(USHORT)bh);
+  SiS_SetRegByte(DACData,(USHORT)bl);
+}
+
+void
+SiS_LoadDAC(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+            USHORT ModeNo, USHORT ModeIdIndex)
+{
+   USHORT data,data2;
+   USHORT time,i,j,k,m,n,o;
+   USHORT si,di,bx,dl,al,ah,dh;
+   USHORT shiftflag;
+   SISIOADDRESS DACAddr, DACData;
+   const USHORT *table = NULL;
+
+   if(ModeNo <= 0x13) {
+      data = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+   } else {
+      if(SiS_Pr->UseCustomMode) {
+	 data = SiS_Pr->CModeFlag;
+      } else {
+         data = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+      }
+   }
+
+   data &= DACInfoFlag;
+   time = 64;
+   if(data == 0x00) table = SiS_MDA_DAC;
+   if(data == 0x08) table = SiS_CGA_DAC;
+   if(data == 0x10) table = SiS_EGA_DAC;
+   if(data == 0x18) {
+      time = 256;
+      table = SiS_VGA_DAC;
+   }
+   if(time == 256) j = 16;
+   else            j = time;
+
+   if( ( (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) &&        /* 301B-DH LCD */
+         (SiS_Pr->SiS_VBType & VB_NoLCD) )        ||
+       (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)       ||   /* LCDA */
+       (!(SiS_Pr->SiS_SetFlag & ProgrammingCRT2)) ) {  /* Programming CRT1 */
+      DACAddr = SiS_Pr->SiS_P3c8;
+      DACData = SiS_Pr->SiS_P3c9;
+      shiftflag = 0;
+      SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF);
+   } else {
+      shiftflag = 1;
+      DACAddr = SiS_Pr->SiS_Part5Port;
+      DACData = SiS_Pr->SiS_Part5Port + 1;
+   }
+
+   SiS_SetRegByte(DACAddr,0x00);
+
+   for(i=0; i<j; i++) {
+      data = table[i];
+      for(k=0; k<3; k++) {
+	data2 = 0;
+	if(data & 0x01) data2 = 0x2A;
+	if(data & 0x02) data2 += 0x15;
+	if(shiftflag) data2 <<= 2;
+	SiS_SetRegByte(DACData, data2);
+	data >>= 2;
+      }
+   }
+
+   if(time == 256) {
+      for(i = 16; i < 32; i++) {
+   	 data = table[i];
+	 if(shiftflag) data <<= 2;
+	 for(k = 0; k < 3; k++) SiS_SetRegByte(DACData, data);
+      }
+      si = 32;
+      for(m = 0; m < 9; m++) {
+         di = si;
+         bx = si + 4;
+         dl = 0;
+         for(n = 0; n < 3; n++) {
+  	    for(o = 0; o < 5; o++) {
+	       dh = table[si];
+	       ah = table[di];
+	       al = table[bx];
+	       si++;
+	       SiS_WriteDAC(SiS_Pr, DACData, shiftflag, dl, ah, al, dh);
+	    }
+	    si -= 2;
+	    for(o = 0; o < 3; o++) {
+	       dh = table[bx];
+	       ah = table[di];
+	       al = table[si];
+	       si--;
+	       SiS_WriteDAC(SiS_Pr, DACData, shiftflag, dl, ah, al, dh);
+	    }
+	    dl++;
+	 }            /* for n < 3 */
+	 si += 5;
+      }               /* for m < 9 */
+   }
+}
+
+/*********************************************/
+/*         SET CRT1 REGISTER GROUP           */
+/*********************************************/
+
+static void
+SiS_SetCRT1Group(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+                 USHORT ModeNo, USHORT ModeIdIndex)
+{
+  USHORT  StandTableIndex,RefreshRateTableIndex;
+
+  SiS_Pr->SiS_CRT1Mode = ModeNo;
+  StandTableIndex = SiS_GetModePtr(SiS_Pr, ModeNo, ModeIdIndex);
+  if(SiS_Pr->SiS_SetFlag & LowModeTests) {
+     if(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchCRT2)) {
+        SiS_DisableBridge(SiS_Pr, HwInfo);
+     }
+  }
+
+  SiS_ResetSegmentRegisters(SiS_Pr, HwInfo);
+
+  SiS_SetSeqRegs(SiS_Pr, StandTableIndex, HwInfo);
+  SiS_SetMiscRegs(SiS_Pr, StandTableIndex, HwInfo);
+  SiS_SetCRTCRegs(SiS_Pr, HwInfo, StandTableIndex);
+  SiS_SetATTRegs(SiS_Pr, StandTableIndex, HwInfo);
+  SiS_SetGRCRegs(SiS_Pr, StandTableIndex);
+  SiS_ClearExt1Regs(SiS_Pr, HwInfo, ModeNo);
+  SiS_ResetCRT1VCLK(SiS_Pr, HwInfo);
+
+  SiS_Pr->SiS_SelectCRT2Rate = 0;
+  SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2);
+
+#ifdef LINUX_XF86
+  xf86DrvMsgVerb(0, X_PROBED, 4, "(init: VBType=0x%04x, VBInfo=0x%04x)\n",
+                    SiS_Pr->SiS_VBType, SiS_Pr->SiS_VBInfo);
+#endif
+
+  if(SiS_Pr->SiS_VBInfo & SetSimuScanMode) {
+     if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+        SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
+     }
+  }
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+     SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
+  }
+
+  RefreshRateTableIndex = SiS_GetRatePtr(SiS_Pr, ModeNo, ModeIdIndex, HwInfo);
+
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+     SiS_Pr->SiS_SetFlag &= ~ProgrammingCRT2;
+  }
+
+  if(RefreshRateTableIndex != 0xFFFF) {
+     SiS_SetCRT1Sync(SiS_Pr, RefreshRateTableIndex);
+     SiS_SetCRT1CRTC(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
+     SiS_SetCRT1Offset(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
+     SiS_SetCRT1VCLK(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex);
+  }
+
+#ifdef SIS300
+  if(HwInfo->jChipType == SIS_300) {
+     SiS_SetCRT1FIFO_300(SiS_Pr, ModeNo,HwInfo,RefreshRateTableIndex);
+  } else if((HwInfo->jChipType == SIS_630) ||
+            (HwInfo->jChipType == SIS_730) ||
+            (HwInfo->jChipType == SIS_540)) {
+     SiS_SetCRT1FIFO_630(SiS_Pr, ModeNo, HwInfo, RefreshRateTableIndex);
+  }
+#endif
+#ifdef SIS315H
+  if(HwInfo->jChipType >= SIS_315H) {
+     SiS_SetCRT1FIFO_310(SiS_Pr, ModeNo, ModeIdIndex, HwInfo);
+  }
+#endif
+
+  SiS_SetCRT1ModeRegs(SiS_Pr, HwInfo, ModeNo, ModeIdIndex, RefreshRateTableIndex);
+
+  SiS_LoadDAC(SiS_Pr, HwInfo, ModeNo, ModeIdIndex);
+
+#ifdef LINUX_KERNEL
+  if(SiS_Pr->SiS_flag_clearbuffer) {
+     SiS_ClearBuffer(SiS_Pr,HwInfo,ModeNo);
+  }
+#endif
+
+  if(!(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchCRT2 | SetCRT2ToLCDA))) {
+     SiS_WaitRetrace1(SiS_Pr);
+     SiS_DisplayOn(SiS_Pr);
+  }
+}
+
+/*********************************************/
+/*       HELPER: VIDEO BRIDGE PROG CLK       */
+/*********************************************/
+
+static void
+SiS_ResetVB(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+   UCHAR  *ROMAddr  = HwInfo->pjVirtualRomBase;
+   USHORT temp;
+
+   /* VB programming clock */
+   if(SiS_Pr->SiS_UseROM) {
+      if(HwInfo->jChipType < SIS_330) {
+         temp = ROMAddr[VB310Data_1_2_Offset] | 0x40;
+	 if(SiS_Pr->SiS_ROMNew) temp = ROMAddr[0x80] | 0x40;
+	 SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp);
+      } else if(HwInfo->jChipType >= SIS_661) {
+         temp = ROMAddr[0x7e] | 0x40;
+         if(SiS_Pr->SiS_ROMNew) temp = ROMAddr[0x80] | 0x40;
+	 SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp);
+      }
+   }
+}
+
+/*********************************************/
+/*         HELPER: SET VIDEO REGISTERS       */
+/*********************************************/
+
+static void
+SiS_StrangeStuff(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+   if((IS_SIS651) || (IS_SISM650)) {
+      SiS_SetReg(SiS_Pr->SiS_VidCapt, 0x3f, 0x00);   /* Fiddle with capture regs */
+      SiS_SetReg(SiS_Pr->SiS_VidCapt, 0x00, 0x00);
+      SiS_SetReg(SiS_Pr->SiS_VidPlay, 0x00, 0x86);   /* (BIOS does NOT unlock) */
+      SiS_SetRegAND(SiS_Pr->SiS_VidPlay, 0x30, 0xfe); /* Fiddle with video regs */
+      SiS_SetRegAND(SiS_Pr->SiS_VidPlay, 0x3f, 0xef);
+   }
+   /* !!! This does not support modes < 0x13 !!! */
+}
+
+/*********************************************/
+/*         XFree86: SET SCREEN PITCH         */
+/*********************************************/
+
+#ifdef LINUX_XF86
+static void
+SiS_SetPitchCRT1(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn)
+{
+   SISPtr pSiS = SISPTR(pScrn);
+   UShort HDisplay = pSiS->scrnPitch >> 3;
+
+   SiS_SetReg(SiS_Pr->SiS_P3d4,0x13,(HDisplay & 0xFF));
+   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0xF0,(HDisplay>>8));
+}
+
+static void
+SiS_SetPitchCRT2(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn)
+{
+   SISPtr pSiS = SISPTR(pScrn);
+   UShort HDisplay = pSiS->scrnPitch2 >> 3;
+
+    /* Unlock CRT2 */
+   if(pSiS->VGAEngine == SIS_315_VGA)
+     SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2F, 0x01);
+   else
+     SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x24, 0x01);
+
+   SiS_SetReg(SiS_Pr->SiS_Part1Port,0x07,(HDisplay & 0xFF));
+   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0xF0,(HDisplay >> 8));
+}
+
+static void
+SiS_SetPitch(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn)
+{
+   SISPtr pSiS = SISPTR(pScrn);
+   BOOLEAN isslavemode = FALSE;
+
+   if( (pSiS->VBFlags & VB_VIDEOBRIDGE) &&
+       ( ((pSiS->VGAEngine == SIS_300_VGA) &&
+          (SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0xa0) == 0x20) ||
+         ((pSiS->VGAEngine == SIS_315_VGA) &&
+	  (SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x50) == 0x10) ) ) {
+      isslavemode = TRUE;
+   }
+
+   /* We need to set pitch for CRT1 if bridge is in slave mode, too */
+   if((pSiS->VBFlags & DISPTYPE_DISP1) || (isslavemode)) {
+      SiS_SetPitchCRT1(SiS_Pr, pScrn);
+   }
+   /* We must not set the pitch for CRT2 if bridge is in slave mode */
+   if((pSiS->VBFlags & DISPTYPE_DISP2) && (!isslavemode)) {
+      SiS_SetPitchCRT2(SiS_Pr, pScrn);
+   }
+}
+#endif
+
+/*********************************************/
+/*                 SiSSetMode()              */
+/*********************************************/
+
+#ifdef LINUX_XF86
+/* We need pScrn for setting the pitch correctly */
+BOOLEAN
+SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,ScrnInfoPtr pScrn,USHORT ModeNo, BOOLEAN dosetpitch)
+#else
+BOOLEAN
+SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,USHORT ModeNo)
+#endif
+{
+   USHORT  ModeIdIndex;
+   SISIOADDRESS BaseAddr = HwInfo->ulIOAddress;
+   unsigned char backupreg=0;
+#ifdef LINUX_KERNEL
+   USHORT  KeepLockReg;
+   ULONG   temp;
+
+   SiS_Pr->UseCustomMode = FALSE;
+   SiS_Pr->CRT1UsesCustomMode = FALSE;
+#endif
+
+   if(SiS_Pr->UseCustomMode) {
+      ModeNo = 0xfe;
+   }
+
+   SiSInitPtr(SiS_Pr, HwInfo);
+   SiSRegInit(SiS_Pr, BaseAddr);
+   SiS_GetSysFlags(SiS_Pr, HwInfo);
+
+#if defined(LINUX_XF86) && (defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__))
+   if(pScrn) SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff);
+   else
+#endif
+         SiS_Pr->SiS_VGAINFO = 0x11;
+
+   SiSInitPCIetc(SiS_Pr, HwInfo);
+   SiSSetLVDSetc(SiS_Pr, HwInfo);
+   SiSDetermineROMUsage(SiS_Pr, HwInfo);
+
+   SiS_Pr->SiS_flag_clearbuffer = 0;
+
+   if(!SiS_Pr->UseCustomMode) {
+#ifdef LINUX_KERNEL
+      if(!(ModeNo & 0x80)) SiS_Pr->SiS_flag_clearbuffer = 1;
+#endif
+      ModeNo &= 0x7f;
+   }
+
+#ifdef LINUX_KERNEL
+   KeepLockReg = SiS_GetReg(SiS_Pr->SiS_P3c4,0x05);
+#endif
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86);
+
+   SiS_UnLockCRT2(SiS_Pr, HwInfo);
+
+   if(!SiS_Pr->UseCustomMode) {
+      if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return FALSE;
+   } else {
+      ModeIdIndex = 0;
+   }
+
+   SiS_GetVBType(SiS_Pr, HwInfo);
+
+   /* Init/restore some VB registers */
+
+   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+      if(HwInfo->jChipType >= SIS_315H) {
+         SiS_ResetVB(SiS_Pr, HwInfo);
+	 SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x32,0x10);
+	 SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x00,0x0c);
+         backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
+      } else {
+         backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
+      }
+   }
+
+   /* Get VB information (connectors, connected devices) */
+   SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, (SiS_Pr->UseCustomMode) ? 0 : 1);
+   SiS_SetYPbPr(SiS_Pr, HwInfo);
+   SiS_SetTVMode(SiS_Pr, ModeNo, ModeIdIndex, HwInfo);
+   SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo);
+   SiS_SetLowModeTest(SiS_Pr, ModeNo, HwInfo);
+
+#ifdef LINUX_KERNEL
+   /* 3. Check memory size (Kernel framebuffer driver only) */
+   temp = SiS_CheckMemorySize(SiS_Pr, HwInfo, ModeNo, ModeIdIndex);
+   if(!temp) return(0);
+#endif
+
+   if(HwInfo->jChipType >= SIS_315H) {
+      SiS_SetupCR5x(SiS_Pr, HwInfo);
+   }
+
+   if(SiS_Pr->UseCustomMode) {
+      SiS_Pr->CRT1UsesCustomMode = TRUE;
+      SiS_Pr->CSRClock_CRT1 = SiS_Pr->CSRClock;
+      SiS_Pr->CModeFlag_CRT1 = SiS_Pr->CModeFlag;
+   } else {
+      SiS_Pr->CRT1UsesCustomMode = FALSE;
+   }
+
+   /* Set mode on CRT1 */
+   if( (SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SetCRT2ToLCDA)) ||
+       (!(SiS_Pr->SiS_VBInfo & SwitchCRT2)) ) {
+      SiS_SetCRT1Group(SiS_Pr, HwInfo, ModeNo, ModeIdIndex);
+   }
+
+   /* Set mode on CRT2 */
+   if(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchCRT2 | SetCRT2ToLCDA)) {
+      if( (SiS_Pr->SiS_VBType & VB_SISVB)    ||
+          (SiS_Pr->SiS_IF_DEF_LVDS     == 1) ||
+          (SiS_Pr->SiS_IF_DEF_CH70xx   != 0) ||
+          (SiS_Pr->SiS_IF_DEF_TRUMPION != 0) ) {
+         SiS_SetCRT2Group(SiS_Pr, HwInfo, ModeNo);
+      }
+   }
+
+   SiS_HandleCRT1(SiS_Pr);
+
+   SiS_StrangeStuff(SiS_Pr, HwInfo);
+
+   SiS_DisplayOn(SiS_Pr);
+   SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF);
+
+   if(HwInfo->jChipType >= SIS_315H) {
+      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+         if(!(SiS_IsDualEdge(SiS_Pr, HwInfo))) {
+	    SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb);
+	 }
+      }
+   }
+
+   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+      if(HwInfo->jChipType >= SIS_315H) {
+         if(!SiS_Pr->SiS_ROMNew) {
+	    if(SiS_IsVAMode(SiS_Pr,HwInfo)) {
+	       SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01);
+	    } else {
+	       SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x35,0xFE);
+	    }
+	 }
+
+	 SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupreg);
+
+	 if((IS_SIS650) && (SiS_GetReg(SiS_Pr->SiS_P3d4,0x30) & 0xfc)) {
+	    if((ModeNo == 0x03) || (ModeNo == 0x10)) {
+	       SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x51,0x80);
+	       SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x56,0x08);
+            }
+	 }
+
+	 if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x30) & SetCRT2ToLCD) {
+	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xfc);
+	 }
+      } else if((HwInfo->jChipType == SIS_630) ||
+                (HwInfo->jChipType == SIS_730)) {
+         SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupreg);
+      }
+   }
+
+#ifdef LINUX_XF86
+   if(pScrn) {
+      /* SetPitch: Adapt to virtual size & position */
+      if((ModeNo > 0x13) && (dosetpitch)) {
+         SiS_SetPitch(SiS_Pr, pScrn);
+      }
+
+      /* Backup/Set ModeNo in BIOS scratch area */
+      SiS_GetSetModeID(pScrn, ModeNo);
+   }
+#endif
+
+#ifdef LINUX_KERNEL  /* We never lock registers in XF86 */
+   if(KeepLockReg == 0xA1) SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86);
+   else SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x00);
+#endif
+
+   return TRUE;
+}
+
+/*********************************************/
+/*          XFree86: SiSBIOSSetMode()        */
+/*           for non-Dual-Head mode          */
+/*********************************************/
+
+#ifdef LINUX_XF86
+BOOLEAN
+SiSBIOSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn,
+               DisplayModePtr mode, BOOLEAN IsCustom)
+{
+   SISPtr pSiS = SISPTR(pScrn);
+   UShort ModeNo = 0;
+
+   SiS_Pr->UseCustomMode = FALSE;
+
+   if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) {
+
+      xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting custom mode %dx%d\n",
+	 	SiS_Pr->CHDisplay,
+		(mode->Flags & V_INTERLACE ? SiS_Pr->CVDisplay * 2 :
+		   (mode->Flags & V_DBLSCAN ? SiS_Pr->CVDisplay / 2 :
+		      SiS_Pr->CVDisplay)));
+
+   } else {
+
+      /* Don't need vbflags here; checks done earlier */
+      ModeNo = SiS_GetModeNumber(pScrn, mode, 0);
+      if(!ModeNo) return FALSE;
+
+      xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting standard mode 0x%x\n", ModeNo);
+
+   }
+
+   return(SiSSetMode(SiS_Pr, HwInfo, pScrn, ModeNo, TRUE));
+}
+
+/*********************************************/
+/*       XFree86: SiSBIOSSetModeCRT2()       */
+/*           for Dual-Head modes             */
+/*********************************************/
+BOOLEAN
+SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn,
+               DisplayModePtr mode, BOOLEAN IsCustom)
+{
+   USHORT  ModeIdIndex;
+   SISIOADDRESS BaseAddr = HwInfo->ulIOAddress;
+   UShort  ModeNo   = 0;
+   unsigned char backupreg=0;
+   SISPtr  pSiS     = SISPTR(pScrn);
+#ifdef SISDUALHEAD
+   SISEntPtr pSiSEnt = pSiS->entityPrivate;
+#endif
+
+   SiS_Pr->UseCustomMode = FALSE;
+
+   /* Remember: Custom modes for CRT2 are ONLY supported
+    *     -) on the 30x/B/C, and
+    *     -) if CRT2 is LCD or VGA, or CRT1 is LCDA
+    */
+
+   if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) {
+
+	 ModeNo = 0xfe;
+
+   } else {
+
+         ModeNo = SiS_GetModeNumber(pScrn, mode, 0);
+         if(!ModeNo) return FALSE;
+
+   }
+
+   SiSRegInit(SiS_Pr, BaseAddr);
+   SiSInitPtr(SiS_Pr, HwInfo);
+   SiS_GetSysFlags(SiS_Pr, HwInfo);
+#if (defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__))
+   SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff);
+#else
+   SiS_Pr->SiS_VGAINFO = 0x11;
+#endif
+   SiSInitPCIetc(SiS_Pr, HwInfo);
+   SiSSetLVDSetc(SiS_Pr, HwInfo);
+   SiSDetermineROMUsage(SiS_Pr, HwInfo);
+
+   /* Save mode info so we can set it from within SetMode for CRT1 */
+#ifdef SISDUALHEAD
+   if(pSiS->DualHeadMode) {
+      pSiSEnt->CRT2ModeNo = ModeNo;
+      pSiSEnt->CRT2DMode = mode;
+      pSiSEnt->CRT2IsCustom = IsCustom;
+      pSiSEnt->CRT2CR30 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
+      pSiSEnt->CRT2CR31 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31);
+      pSiSEnt->CRT2CR35 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
+      pSiSEnt->CRT2CR38 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
+#if 0
+      /* We can't set CRT2 mode before CRT1 mode is set */
+      if(pSiSEnt->CRT1ModeNo == -1) {
+    	 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
+		"Setting CRT2 mode delayed until after setting CRT1 mode\n");
+   	 return TRUE;
+      }
+#endif
+      pSiSEnt->CRT2ModeSet = TRUE;
+   }
+#endif
+
+   /* We don't clear the buffer in X */
+   SiS_Pr->SiS_flag_clearbuffer=0;
+
+   if(SiS_Pr->UseCustomMode) {
+
+      USHORT temptemp = SiS_Pr->CVDisplay;
+
+      if(SiS_Pr->CModeFlag & DoubleScanMode)     temptemp >>= 1;
+      else if(SiS_Pr->CInfoFlag & InterlaceMode) temptemp <<= 1;
+
+      xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
+	  "Setting custom mode %dx%d on CRT2\n",
+	  SiS_Pr->CHDisplay, temptemp);
+
+   } else {
+
+      xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
+   	  "Setting standard mode 0x%x on CRT2\n", ModeNo);
+
+   }
+
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86);
+
+   SiS_UnLockCRT2(SiS_Pr, HwInfo);
+
+   if(!SiS_Pr->UseCustomMode) {
+      if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return FALSE;
+   } else {
+      ModeIdIndex = 0;
+   }
+
+   SiS_GetVBType(SiS_Pr, HwInfo);
+
+   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+      if(HwInfo->jChipType >= SIS_315H) {
+	 SiS_ResetVB(SiS_Pr, HwInfo);
+	 SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x32,0x10);
+	 SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x00,0x0c);
+         backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
+      } else {
+         backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
+      }
+   }
+
+   /* Get VB information (connectors, connected devices) */
+   if(!SiS_Pr->UseCustomMode) {
+      SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, 1);
+   } else {
+      /* If this is a custom mode, we don't check the modeflag for CRT2Mode */
+      SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, 0);
+   }
+   SiS_SetYPbPr(SiS_Pr, HwInfo);
+   SiS_SetTVMode(SiS_Pr, ModeNo, ModeIdIndex, HwInfo);
+   SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo);
+   SiS_SetLowModeTest(SiS_Pr, ModeNo, HwInfo);
+
+   /* Set mode on CRT2 */
+   if( (SiS_Pr->SiS_VBType & VB_SISVB)    ||
+       (SiS_Pr->SiS_IF_DEF_LVDS     == 1) ||
+       (SiS_Pr->SiS_IF_DEF_CH70xx   != 0) ||
+       (SiS_Pr->SiS_IF_DEF_TRUMPION != 0) ) {
+      SiS_SetCRT2Group(SiS_Pr, HwInfo, ModeNo);
+   }
+
+   SiS_StrangeStuff(SiS_Pr, HwInfo);
+
+   SiS_DisplayOn(SiS_Pr);
+   SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF);
+
+   if(HwInfo->jChipType >= SIS_315H) {
+      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+         if(!(SiS_IsDualEdge(SiS_Pr, HwInfo))) {
+	    SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb);
+	 }
+      }
+   }
+
+   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+      if(HwInfo->jChipType >= SIS_315H) {
+         if(!SiS_Pr->SiS_ROMNew) {
+	    if(SiS_IsVAMode(SiS_Pr,HwInfo)) {
+	       SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01);
+	    } else {
+	       SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x35,0xFE);
+	    }
+	 }
+
+	 SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupreg);
+
+	 if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x30) & SetCRT2ToLCD) {
+	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xfc);
+	 }
+      } else if((HwInfo->jChipType == SIS_630) ||
+                (HwInfo->jChipType == SIS_730)) {
+         SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupreg);
+      }
+   }
+
+   /* SetPitch: Adapt to virtual size & position */
+   SiS_SetPitchCRT2(SiS_Pr, pScrn);
+
+   return TRUE;
+}
+
+/*********************************************/
+/*       XFree86: SiSBIOSSetModeCRT1()       */
+/*           for Dual-Head modes             */
+/*********************************************/
+
+BOOLEAN
+SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn,
+                   DisplayModePtr mode, BOOLEAN IsCustom)
+{
+   SISPtr  pSiS = SISPTR(pScrn);
+   SISIOADDRESS BaseAddr = HwInfo->ulIOAddress;
+   USHORT  ModeIdIndex, ModeNo=0;
+   UCHAR backupreg=0;
+#ifdef SISDUALHEAD
+   SISEntPtr pSiSEnt = pSiS->entityPrivate;
+   UCHAR backupcr30, backupcr31, backupcr38, backupcr35, backupp40d=0;
+   BOOLEAN backupcustom;
+#endif
+
+   SiS_Pr->UseCustomMode = FALSE;
+
+   if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) {
+
+         USHORT temptemp = SiS_Pr->CVDisplay;
+
+         if(SiS_Pr->CModeFlag & DoubleScanMode)     temptemp >>= 1;
+         else if(SiS_Pr->CInfoFlag & InterlaceMode) temptemp <<= 1;
+
+         xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
+	 	"Setting custom mode %dx%d on CRT1\n",
+	 	SiS_Pr->CHDisplay, temptemp);
+	 ModeNo = 0xfe;
+
+   } else {
+
+         ModeNo = SiS_GetModeNumber(pScrn, mode, 0);
+         if(!ModeNo) return FALSE;
+
+         xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
+	 	"Setting standard mode 0x%x on CRT1\n", ModeNo);
+   }
+
+   SiSInitPtr(SiS_Pr, HwInfo);
+   SiSRegInit(SiS_Pr, BaseAddr);
+   SiS_GetSysFlags(SiS_Pr, HwInfo);
+#if (defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__))
+   SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff);
+#else
+   SiS_Pr->SiS_VGAINFO = 0x11;
+#endif
+   SiSInitPCIetc(SiS_Pr, HwInfo);
+   SiSSetLVDSetc(SiS_Pr, HwInfo);
+   SiSDetermineROMUsage(SiS_Pr, HwInfo);
+
+   /* We don't clear the buffer in X */
+   SiS_Pr->SiS_flag_clearbuffer = 0;
+
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86);
+
+   SiS_UnLockCRT2(SiS_Pr, HwInfo);
+
+   if(!SiS_Pr->UseCustomMode) {
+      if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return FALSE;
+   } else {
+      ModeIdIndex = 0;
+   }
+
+   /* Determine VBType */
+   SiS_GetVBType(SiS_Pr, HwInfo);
+
+   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+      if(HwInfo->jChipType >= SIS_315H) {
+         backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
+      } else {
+         backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
+      }
+   }
+
+   /* Get VB information (connectors, connected devices) */
+   /* (We don't care if the current mode is a CRT2 mode) */
+   SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, 0);
+   SiS_SetYPbPr(SiS_Pr, HwInfo);
+   SiS_SetTVMode(SiS_Pr, ModeNo, ModeIdIndex, HwInfo);
+   SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo);
+   SiS_SetLowModeTest(SiS_Pr, ModeNo, HwInfo);
+
+   if(HwInfo->jChipType >= SIS_315H) {
+      SiS_SetupCR5x(SiS_Pr, HwInfo);
+   }
+
+   /* Set mode on CRT1 */
+   SiS_SetCRT1Group(SiS_Pr, HwInfo, ModeNo, ModeIdIndex);
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+      SiS_SetCRT2Group(SiS_Pr, HwInfo, ModeNo);
+   }
+
+   /* SetPitch: Adapt to virtual size & position */
+   SiS_SetPitchCRT1(SiS_Pr, pScrn);
+
+#ifdef SISDUALHEAD
+   if(pSiS->DualHeadMode) {
+      pSiSEnt->CRT1ModeNo = ModeNo;
+      pSiSEnt->CRT1DMode = mode;
+   }
+#endif
+
+   if(SiS_Pr->UseCustomMode) {
+      SiS_Pr->CRT1UsesCustomMode = TRUE;
+      SiS_Pr->CSRClock_CRT1 = SiS_Pr->CSRClock;
+      SiS_Pr->CModeFlag_CRT1 = SiS_Pr->CModeFlag;
+   } else {
+      SiS_Pr->CRT1UsesCustomMode = FALSE;
+   }
+
+   /* Reset CRT2 if changing mode on CRT1 */
+#ifdef SISDUALHEAD
+   if(pSiS->DualHeadMode) {
+      if(pSiSEnt->CRT2ModeNo != -1) {
+         xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
+				"(Re-)Setting mode for CRT2\n");
+	 backupcustom = SiS_Pr->UseCustomMode;
+	 backupcr30 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
+	 backupcr31 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31);
+	 backupcr35 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
+	 backupcr38 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
+	 if(SiS_Pr->SiS_VBType & VB_SISVB) {
+	    /* Backup LUT-enable */
+	    if(pSiSEnt->CRT2ModeSet) {
+	       backupp40d = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x0d) & 0x08;
+	    }
+	 }
+	 if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+	    SiS_SetReg(SiS_Pr->SiS_P3d4,0x30,pSiSEnt->CRT2CR30);
+	    SiS_SetReg(SiS_Pr->SiS_P3d4,0x31,pSiSEnt->CRT2CR31);
+	    SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,pSiSEnt->CRT2CR35);
+	    SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,pSiSEnt->CRT2CR38);
+	 }
+	 SiSBIOSSetModeCRT2(SiS_Pr, HwInfo, pSiSEnt->pScrn_1,
+			    pSiSEnt->CRT2DMode, pSiSEnt->CRT2IsCustom);
+         SiS_SetReg(SiS_Pr->SiS_P3d4,0x30,backupcr30);
+	 SiS_SetReg(SiS_Pr->SiS_P3d4,0x31,backupcr31);
+	 SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupcr35);
+	 SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupcr38);
+	 if(SiS_Pr->SiS_VBType & VB_SISVB) {
+	    SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0d, ~0x08, backupp40d);
+	 }
+	 SiS_Pr->UseCustomMode = backupcustom;
+      }
+   }
+#endif
+
+   /* Warning: From here, the custom mode entries in SiS_Pr are
+    * possibly overwritten
+    */
+
+   SiS_HandleCRT1(SiS_Pr);
+
+   SiS_StrangeStuff(SiS_Pr, HwInfo);
+
+   SiS_DisplayOn(SiS_Pr);
+   SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF);
+
+   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+      if(HwInfo->jChipType >= SIS_315H) {
+	 SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupreg);
+      } else if((HwInfo->jChipType == SIS_630) ||
+                (HwInfo->jChipType == SIS_730)) {
+         SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupreg);
+      }
+   }
+
+   /* Backup/Set ModeNo in BIOS scratch area */
+   SiS_GetSetModeID(pScrn,ModeNo);
+
+   return TRUE;
+}
+#endif /* Linux_XF86 */
+
+
+#ifdef LINUX_XF86
+BOOLEAN
+SiS_GetPanelID(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  const USHORT PanelTypeTable300[16] = {
+      0xc101, 0xc117, 0x0121, 0xc135, 0xc142, 0xc152, 0xc162, 0xc072,
+      0xc181, 0xc192, 0xc1a1, 0xc1b6, 0xc1c2, 0xc0d2, 0xc1e2, 0xc1f2
+  };
+  const USHORT PanelTypeTable31030x[16] = {
+      0xc102, 0xc112, 0x0122, 0xc132, 0xc142, 0xc152, 0xc169, 0xc179,
+      0x0189, 0xc192, 0xc1a2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+  };
+  const USHORT PanelTypeTable310LVDS[16] = {
+      0xc111, 0xc122, 0xc133, 0xc144, 0xc155, 0xc166, 0xc177, 0xc188,
+      0xc199, 0xc0aa, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+  };
+  USHORT tempax,tempbx,temp;
+
+  if(HwInfo->jChipType < SIS_315H) {
+
+     tempax = SiS_GetReg(SiS_Pr->SiS_P3c4,0x18);
+     tempbx = tempax & 0x0F;
+     if(!(tempax & 0x10)){
+        if(SiS_Pr->SiS_IF_DEF_LVDS == 1){
+           tempbx = 0;
+           temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x38);
+           if(temp & 0x40) tempbx |= 0x08;
+           if(temp & 0x20) tempbx |= 0x02;
+           if(temp & 0x01) tempbx |= 0x01;
+           temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x39);
+           if(temp & 0x80) tempbx |= 0x04;
+        } else {
+           return 0;
+        }
+     }
+     tempbx = PanelTypeTable300[tempbx];
+     tempbx |= LCDSync;
+     temp = tempbx & 0x00FF;
+     SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,temp);
+     temp = (tempbx & 0xFF00) >> 8;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,~(LCDSyncBit|LCDRGB18Bit),temp);
+
+  } else {
+
+     if(HwInfo->jChipType >= SIS_661) return 0;
+
+     tempax = SiS_GetReg(SiS_Pr->SiS_P3c4,0x1a);
+     tempax &= 0x1e;
+     tempax >>= 1;
+     if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+        if(tempax == 0) {
+           /* TODO: Include HUGE detection routine
+	            (Probably not worth bothering)
+	    */
+           return 0;
+        }
+        temp = tempax & 0xff;
+        tempax--;
+        tempbx = PanelTypeTable310LVDS[tempax];
+     } else {
+        tempbx = PanelTypeTable31030x[tempax];
+        temp = tempbx & 0xff;
+     }
+     SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,temp);
+     tempbx = (tempbx & 0xff00) >> 8;
+     temp = tempbx & 0xc1;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,~(LCDSyncBit|LCDRGB18Bit),temp);
+     if(SiS_Pr->SiS_VBType & VB_SISVB) {
+        temp = tempbx & 0x04;
+        SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x39,0xfb,temp);
+     }
+
+  }
+  return 1;
+}
+#endif
+
+#ifndef GETBITSTR
+#define BITMASK(h,l)    	(((unsigned)(1U << ((h)-(l)+1))-1)<<(l))
+#define GENMASK(mask)   	BITMASK(1?mask,0?mask)
+#define GETBITS(var,mask)   	(((var) & GENMASK(mask)) >> (0?mask))
+#define GETBITSTR(val,from,to)  ((GETBITS(val,from)) << (0?to))
+#endif
+
+static void
+SiS_CalcCRRegisters(SiS_Private *SiS_Pr, int depth)
+{
+   SiS_Pr->CCRT1CRTC[0]  =  ((SiS_Pr->CHTotal >> 3) - 5) & 0xff;		/* CR0 */
+   SiS_Pr->CCRT1CRTC[1]  =  (SiS_Pr->CHDisplay >> 3) - 1;			/* CR1 */
+   SiS_Pr->CCRT1CRTC[2]  =  (SiS_Pr->CHBlankStart >> 3) - 1;			/* CR2 */
+   SiS_Pr->CCRT1CRTC[3]  =  (((SiS_Pr->CHBlankEnd >> 3) - 1) & 0x1F) | 0x80;	/* CR3 */
+   SiS_Pr->CCRT1CRTC[4]  =  (SiS_Pr->CHSyncStart >> 3) + 3;			/* CR4 */
+   SiS_Pr->CCRT1CRTC[5]  =  ((((SiS_Pr->CHBlankEnd >> 3) - 1) & 0x20) << 2) |	/* CR5 */
+       			    (((SiS_Pr->CHSyncEnd >> 3) + 3) & 0x1F);
+
+   SiS_Pr->CCRT1CRTC[6]  =  (SiS_Pr->CVTotal - 2) & 0xFF;			/* CR6 */
+   SiS_Pr->CCRT1CRTC[7]  =  (((SiS_Pr->CVTotal - 2) & 0x100) >> 8)		/* CR7 */
+ 	 		  | (((SiS_Pr->CVDisplay - 1) & 0x100) >> 7)
+	 		  | ((SiS_Pr->CVSyncStart & 0x100) >> 6)
+	 	  	  | (((SiS_Pr->CVBlankStart - 1) & 0x100) >> 5)
+			  | 0x10
+	 		  | (((SiS_Pr->CVTotal - 2) & 0x200)   >> 4)
+	 		  | (((SiS_Pr->CVDisplay - 1) & 0x200) >> 3)
+	 		  | ((SiS_Pr->CVSyncStart & 0x200) >> 2);
+
+   SiS_Pr->CCRT1CRTC[16] = ((((SiS_Pr->CVBlankStart - 1) & 0x200) >> 4) >> 5); 	/* CR9 */
+
+   if(depth != 8) {
+      if(SiS_Pr->CHDisplay >= 1600)      SiS_Pr->CCRT1CRTC[16] |= 0x60;		/* SRE */
+      else if(SiS_Pr->CHDisplay >= 640)  SiS_Pr->CCRT1CRTC[16] |= 0x40;
+   }
+
+#if 0
+   if (mode->VScan >= 32)
+	regp->CRTC[9] |= 0x1F;
+   else if (mode->VScan > 1)
+	regp->CRTC[9] |= mode->VScan - 1;
+#endif
+
+   SiS_Pr->CCRT1CRTC[8] =  (SiS_Pr->CVSyncStart     ) & 0xFF;			/* CR10 */
+   SiS_Pr->CCRT1CRTC[9] =  ((SiS_Pr->CVSyncEnd      ) & 0x0F) | 0x80;		/* CR11 */
+   SiS_Pr->CCRT1CRTC[10] = (SiS_Pr->CVDisplay    - 1) & 0xFF;			/* CR12 */
+   SiS_Pr->CCRT1CRTC[11] = (SiS_Pr->CVBlankStart - 1) & 0xFF;			/* CR15 */
+   SiS_Pr->CCRT1CRTC[12] = (SiS_Pr->CVBlankEnd   - 1) & 0xFF;			/* CR16 */
+
+   SiS_Pr->CCRT1CRTC[13] =							/* SRA */
+                        GETBITSTR((SiS_Pr->CVTotal     -2), 10:10, 0:0) |
+                        GETBITSTR((SiS_Pr->CVDisplay   -1), 10:10, 1:1) |
+                        GETBITSTR((SiS_Pr->CVBlankStart-1), 10:10, 2:2) |
+                        GETBITSTR((SiS_Pr->CVSyncStart   ), 10:10, 3:3) |
+                        GETBITSTR((SiS_Pr->CVBlankEnd  -1),   8:8, 4:4) |
+                        GETBITSTR((SiS_Pr->CVSyncEnd     ),   4:4, 5:5) ;
+
+   SiS_Pr->CCRT1CRTC[14] =							/* SRB */
+                        GETBITSTR((SiS_Pr->CHTotal      >> 3) - 5, 9:8, 1:0) |
+                        GETBITSTR((SiS_Pr->CHDisplay    >> 3) - 1, 9:8, 3:2) |
+                        GETBITSTR((SiS_Pr->CHBlankStart >> 3) - 1, 9:8, 5:4) |
+                        GETBITSTR((SiS_Pr->CHSyncStart  >> 3) + 3, 9:8, 7:6) ;
+
+
+   SiS_Pr->CCRT1CRTC[15] =							/* SRC */
+                        GETBITSTR((SiS_Pr->CHBlankEnd >> 3) - 1, 7:6, 1:0) |
+                        GETBITSTR((SiS_Pr->CHSyncEnd  >> 3) + 3, 5:5, 2:2) ;
+}
+
+void
+SiS_CalcLCDACRT1Timing(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex)
+{
+   USHORT modeflag, tempax, tempbx, VGAHDE = SiS_Pr->SiS_VGAHDE;
+   int i,j;
+
+   /* 1:1 data: use data set by setcrt1crtc() */
+   if(SiS_Pr->SiS_LCDInfo & LCDPass11) return;
+
+   if(ModeNo <= 0x13) {
+     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+   } else if(SiS_Pr->UseCustomMode) {
+     modeflag = SiS_Pr->CModeFlag;
+   } else {
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+   }
+
+   if(modeflag & HalfDCLK) VGAHDE >>= 1;
+
+   SiS_Pr->CHDisplay = VGAHDE;
+   SiS_Pr->CHBlankStart = VGAHDE;
+
+   SiS_Pr->CVDisplay = SiS_Pr->SiS_VGAVDE;
+   SiS_Pr->CVBlankStart = SiS_Pr->SiS_VGAVDE;
+
+   tempbx = SiS_Pr->PanelHT - SiS_Pr->PanelXRes;
+   tempax = SiS_Pr->SiS_VGAHDE;  /* not /2 ! */
+   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+      tempax = SiS_Pr->PanelXRes;
+   }
+   tempbx += tempax;
+   if(modeflag & HalfDCLK) tempbx -= VGAHDE;
+   SiS_Pr->CHTotal = SiS_Pr->CHBlankEnd = tempbx;
+
+   tempax = VGAHDE;
+   tempbx = SiS_Pr->CHTotal;
+   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+      tempbx = SiS_Pr->PanelXRes;
+      if(modeflag & HalfDCLK) tempbx >>= 1;
+      tempax += ((tempbx - tempax) >> 1);
+   }
+
+   tempax += SiS_Pr->PanelHRS;
+   SiS_Pr->CHSyncStart = tempax;
+   tempax += SiS_Pr->PanelHRE;
+   SiS_Pr->CHSyncEnd = tempax;
+
+   tempbx = SiS_Pr->PanelVT - SiS_Pr->PanelYRes;
+   tempax = SiS_Pr->SiS_VGAVDE;
+   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+      tempax = SiS_Pr->PanelYRes;
+   }
+   SiS_Pr->CVTotal = SiS_Pr->CVBlankEnd = tempbx + tempax;
+
+   tempax = SiS_Pr->SiS_VGAVDE;
+   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+      tempax += (SiS_Pr->PanelYRes - tempax) >> 1;
+   }
+   tempax += SiS_Pr->PanelVRS;
+   SiS_Pr->CVSyncStart = tempax;
+   tempax += SiS_Pr->PanelVRE;
+   SiS_Pr->CVSyncEnd = tempax;
+
+   SiS_CalcCRRegisters(SiS_Pr, 8);
+   SiS_Pr->CCRT1CRTC[16] &= ~0xE0;
+
+   SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f);
+
+   for(i=0,j=0;i<=7;i++,j++) {
+      SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]);
+   }
+   for(j=0x10;i<=10;i++,j++) {
+      SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]);
+   }
+   for(j=0x15;i<=12;i++,j++) {
+      SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]);
+   }
+   for(j=0x0A;i<=15;i++,j++) {
+      SiS_SetReg(SiS_Pr->SiS_P3c4,j,SiS_Pr->CCRT1CRTC[i]);
+   }
+
+   tempax = SiS_Pr->CCRT1CRTC[16] & 0xE0;
+   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0x1F,tempax);
+
+   tempax = (SiS_Pr->CCRT1CRTC[16] & 0x01) << 5;
+   if(modeflag & DoubleScanMode) tempax |= 0x80;
+   SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0x5F,tempax);
+
+#ifdef TWDEBUG
+   xf86DrvMsg(0, X_INFO, "%d %d %d %d  %d %d %d %d  (%d %d %d %d)\n",
+       	SiS_Pr->CHDisplay, SiS_Pr->CHSyncStart, SiS_Pr->CHSyncEnd, SiS_Pr->CHTotal,
+	SiS_Pr->CVDisplay, SiS_Pr->CVSyncStart, SiS_Pr->CVSyncEnd, SiS_Pr->CVTotal,
+	SiS_Pr->CHBlankStart, SiS_Pr->CHBlankEnd, SiS_Pr->CVBlankStart, SiS_Pr->CVBlankEnd);
+
+   xf86DrvMsg(0, X_INFO, " {{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n",
+   	SiS_Pr->CCRT1CRTC[0], SiS_Pr->CCRT1CRTC[1],
+	SiS_Pr->CCRT1CRTC[2], SiS_Pr->CCRT1CRTC[3],
+	SiS_Pr->CCRT1CRTC[4], SiS_Pr->CCRT1CRTC[5],
+	SiS_Pr->CCRT1CRTC[6], SiS_Pr->CCRT1CRTC[7]);
+   xf86DrvMsg(0, X_INFO, "   0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n",
+   	SiS_Pr->CCRT1CRTC[8], SiS_Pr->CCRT1CRTC[9],
+	SiS_Pr->CCRT1CRTC[10], SiS_Pr->CCRT1CRTC[11],
+	SiS_Pr->CCRT1CRTC[12], SiS_Pr->CCRT1CRTC[13],
+	SiS_Pr->CCRT1CRTC[14], SiS_Pr->CCRT1CRTC[15]);
+   xf86DrvMsg(0, X_INFO, "   0x%02x}},\n", SiS_Pr->CCRT1CRTC[16]);
+#endif
+}
+
+#ifdef LINUX_XF86
+
+void
+SiS_MakeClockRegs(ScrnInfoPtr pScrn, int clock, UCHAR *p2b, UCHAR *p2c)
+{
+   int          out_n, out_dn, out_div, out_sbit, out_scale;
+   unsigned int vclk[5];
+
+#define Midx         0
+#define Nidx         1
+#define VLDidx       2
+#define Pidx         3
+#define PSNidx       4
+
+   if(SiS_compute_vclk(clock, &out_n, &out_dn, &out_div, &out_sbit, &out_scale)) {
+      (*p2b) = (out_div == 2) ? 0x80 : 0x00;
+      (*p2b) |= ((out_n - 1) & 0x7f);
+      (*p2c) = (out_dn - 1) & 0x1f;
+      (*p2c) |= (((out_scale - 1) & 3) << 5);
+      (*p2c) |= ((out_sbit & 0x01) << 7);
+#ifdef TWDEBUG
+      xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Clock %d: n %d dn %d div %d sb %d sc %d\n",
+        	 clock, out_n, out_dn, out_div, out_sbit, out_scale);
+#endif
+   } else {
+      SiSCalcClock(pScrn, clock, 2, vclk);
+      (*p2b) = (vclk[VLDidx] == 2) ? 0x80 : 0x00;
+      (*p2b) |= (vclk[Midx] - 1) & 0x7f;
+      (*p2c) = (vclk[Nidx] - 1) & 0x1f;
+      if(vclk[Pidx] <= 4) {
+         /* postscale 1,2,3,4 */
+         (*p2c) |= ((vclk[Pidx] - 1) & 3) << 5;
+      } else {
+         /* postscale 6,8 */
+         (*p2c) |= (((vclk[Pidx] / 2) - 1) & 3) << 5;
+	 (*p2c) |= 0x80;
+      }
+#ifdef TWDEBUG
+      xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Clock %d: n %d dn %d div %d sc %d\n",
+        	 clock, vclk[Midx], vclk[Nidx], vclk[VLDidx], vclk[Pidx]);
+#endif
+   }
+}
+
+#endif
+
+/* ================ XFREE86/X.ORG ================= */
+
+/* Helper functions */
+
+#ifdef LINUX_XF86
+
+USHORT
+SiS_CheckBuildCustomMode(ScrnInfoPtr pScrn, DisplayModePtr mode, int VBFlags)
+{
+   SISPtr pSiS = SISPTR(pScrn);
+   int    depth = pSiS->CurrentLayout.bitsPerPixel;
+
+   pSiS->SiS_Pr->CModeFlag = 0;
+   
+   pSiS->SiS_Pr->CDClock = mode->Clock;
+
+   pSiS->SiS_Pr->CHDisplay = mode->HDisplay;
+   pSiS->SiS_Pr->CHSyncStart = mode->HSyncStart;
+   pSiS->SiS_Pr->CHSyncEnd = mode->HSyncEnd;
+   pSiS->SiS_Pr->CHTotal = mode->HTotal;
+
+   pSiS->SiS_Pr->CVDisplay = mode->VDisplay;
+   pSiS->SiS_Pr->CVSyncStart = mode->VSyncStart;
+   pSiS->SiS_Pr->CVSyncEnd = mode->VSyncEnd;
+   pSiS->SiS_Pr->CVTotal = mode->VTotal;
+
+   pSiS->SiS_Pr->CFlags = mode->Flags;
+
+   if(pSiS->SiS_Pr->CFlags & V_INTERLACE) {
+      pSiS->SiS_Pr->CVDisplay >>= 1;
+      pSiS->SiS_Pr->CVSyncStart >>= 1;
+      pSiS->SiS_Pr->CVSyncEnd >>= 1;
+      pSiS->SiS_Pr->CVTotal >>= 1;
+   }
+   if(pSiS->SiS_Pr->CFlags & V_DBLSCAN) {
+      /* pSiS->SiS_Pr->CDClock <<= 1; */
+      pSiS->SiS_Pr->CVDisplay <<= 1;
+      pSiS->SiS_Pr->CVSyncStart <<= 1;
+      pSiS->SiS_Pr->CVSyncEnd <<= 1;
+      pSiS->SiS_Pr->CVTotal <<= 1;
+   }
+
+   pSiS->SiS_Pr->CHBlankStart = pSiS->SiS_Pr->CHDisplay;
+   pSiS->SiS_Pr->CHBlankEnd = pSiS->SiS_Pr->CHTotal;
+   pSiS->SiS_Pr->CVBlankStart = pSiS->SiS_Pr->CVSyncStart - 1;
+   pSiS->SiS_Pr->CVBlankEnd = pSiS->SiS_Pr->CVTotal;
+
+   SiS_MakeClockRegs(pScrn, pSiS->SiS_Pr->CDClock, &pSiS->SiS_Pr->CSR2B, &pSiS->SiS_Pr->CSR2C);
+
+   pSiS->SiS_Pr->CSRClock = (pSiS->SiS_Pr->CDClock / 1000) + 1;
+
+   SiS_CalcCRRegisters(pSiS->SiS_Pr, depth);
+
+   switch(depth) {
+   case 8:  pSiS->SiS_Pr->CModeFlag |= 0x223b; break;
+   case 16: pSiS->SiS_Pr->CModeFlag |= 0x227d; break;
+   case 32: pSiS->SiS_Pr->CModeFlag |= 0x22ff; break;
+   default: return 0;
+   }
+
+   if(pSiS->SiS_Pr->CFlags & V_DBLSCAN)
+      pSiS->SiS_Pr->CModeFlag |= DoubleScanMode;
+
+   if((pSiS->SiS_Pr->CVDisplay >= 1024)	||
+      (pSiS->SiS_Pr->CVTotal >= 1024)   ||
+      (pSiS->SiS_Pr->CHDisplay >= 1024))
+      pSiS->SiS_Pr->CModeFlag |= LineCompareOff;
+
+   if(pSiS->SiS_Pr->CFlags & V_CLKDIV2)
+      pSiS->SiS_Pr->CModeFlag |= HalfDCLK;
+
+   pSiS->SiS_Pr->CInfoFlag = 0x0007;
+
+   if(pSiS->SiS_Pr->CFlags & V_NHSYNC)
+      pSiS->SiS_Pr->CInfoFlag |= 0x4000;
+
+   if(pSiS->SiS_Pr->CFlags & V_NVSYNC)
+      pSiS->SiS_Pr->CInfoFlag |= 0x8000;
+
+   if(pSiS->SiS_Pr->CFlags & V_INTERLACE)
+      pSiS->SiS_Pr->CInfoFlag |= InterlaceMode;
+
+   pSiS->SiS_Pr->UseCustomMode = TRUE;
+#ifdef TWDEBUG
+   xf86DrvMsg(0, X_INFO, "Custom mode %dx%d:\n",
+   	pSiS->SiS_Pr->CHDisplay,pSiS->SiS_Pr->CVDisplay);
+   xf86DrvMsg(0, X_INFO, "Modeflag %04x, Infoflag %04x\n",
+   	pSiS->SiS_Pr->CModeFlag, pSiS->SiS_Pr->CInfoFlag);
+   xf86DrvMsg(0, X_INFO, " {{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n",
+   	pSiS->SiS_Pr->CCRT1CRTC[0], pSiS->SiS_Pr->CCRT1CRTC[1],
+	pSiS->SiS_Pr->CCRT1CRTC[2], pSiS->SiS_Pr->CCRT1CRTC[3],
+	pSiS->SiS_Pr->CCRT1CRTC[4], pSiS->SiS_Pr->CCRT1CRTC[5],
+	pSiS->SiS_Pr->CCRT1CRTC[6], pSiS->SiS_Pr->CCRT1CRTC[7]);
+   xf86DrvMsg(0, X_INFO, "  0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n",
+   	pSiS->SiS_Pr->CCRT1CRTC[8], pSiS->SiS_Pr->CCRT1CRTC[9],
+	pSiS->SiS_Pr->CCRT1CRTC[10], pSiS->SiS_Pr->CCRT1CRTC[11],
+	pSiS->SiS_Pr->CCRT1CRTC[12], pSiS->SiS_Pr->CCRT1CRTC[13],
+	pSiS->SiS_Pr->CCRT1CRTC[14], pSiS->SiS_Pr->CCRT1CRTC[15]);
+   xf86DrvMsg(0, X_INFO, "  0x%02x}},\n", pSiS->SiS_Pr->CCRT1CRTC[16]);
+   xf86DrvMsg(0, X_INFO, "Clock: 0x%02x, 0x%02x, %d\n",
+   	pSiS->SiS_Pr->CSR2B, pSiS->SiS_Pr->CSR2C, pSiS->SiS_Pr->CSRClock);
+#endif
+   return 1;
+}
+
+int
+SiS_FindPanelFromDB(SISPtr pSiS, USHORT panelvendor, USHORT panelproduct, int *maxx, int *maxy, int *prefx, int *prefy)
+{
+   int i, j;
+   BOOLEAN done = FALSE;
+
+   i = 0;
+   while((!done) && (SiS_PlasmaTable[i].vendor) && panelvendor) {
+      if(SiS_PlasmaTable[i].vendor == panelvendor) {
+         for(j=0; j<SiS_PlasmaTable[i].productnum; j++) {
+	    if(SiS_PlasmaTable[i].product[j] == panelproduct) {
+	       if(SiS_PlasmaTable[i].maxx && SiS_PlasmaTable[i].maxy) {
+	          (*maxx) = (int)SiS_PlasmaTable[i].maxx;
+		  (*maxy) = (int)SiS_PlasmaTable[i].maxy;
+		  (*prefx) = (int)SiS_PlasmaTable[i].prefx;
+		  (*prefy) = (int)SiS_PlasmaTable[i].prefy;
+		  done = TRUE;
+		  xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
+	       	        "Identified %s, correcting max X res %d, max Y res %d\n",
+			 SiS_PlasmaTable[i].plasmaname,
+		         SiS_PlasmaTable[i].maxx, SiS_PlasmaTable[i].maxy);
+	          break;
+	       }
+ 	    }
+	 }
+      }
+      i++;
+   }
+   return (done) ? 1 : 0;
+}
+
+/* Build a list of supported modes:
+ * Built-in modes for which we have all data are M_T_DEFAULT,
+ * modes derived from DDC or database data are M_T_BUILTIN
+ */
+DisplayModePtr
+SiSBuildBuiltInModeList(ScrnInfoPtr pScrn, BOOLEAN includelcdmodes, BOOLEAN isfordvi)
+{
+   SISPtr         pSiS = SISPTR(pScrn);
+   unsigned short VRE, VBE, VRS, VBS, VDE, VT;
+   unsigned short HRE, HBE, HRS, HBS, HDE, HT;
+   unsigned char  sr_data, cr_data, cr_data2, cr_data3;
+   unsigned char  sr2b, sr2c;
+   float          num, denum, postscalar, divider;
+   int            A, B, C, D, E, F, temp, i, j, k, l, index, vclkindex;
+   DisplayModePtr new = NULL, current = NULL, first = NULL;
+   BOOLEAN        done = FALSE;
+#if 0
+   DisplayModePtr backup = NULL;
+#endif
+
+   pSiS->backupmodelist = NULL;
+   pSiS->AddedPlasmaModes = FALSE;
+
+   /* Initialize our pointers */
+   if(pSiS->VGAEngine == SIS_300_VGA) {
+#ifdef SIS300
+      InitTo300Pointer(pSiS->SiS_Pr, &pSiS->sishw_ext);
+#else
+      return NULL;
+#endif
+   } else if(pSiS->VGAEngine == SIS_315_VGA) {
+#ifdef SIS315H
+      InitTo310Pointer(pSiS->SiS_Pr, &pSiS->sishw_ext);
+#else
+      return NULL;
+#endif
+   } else return NULL;
+
+   i = 0;
+   while(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_InfoFlag != 0xFFFF) {
+
+      index = pSiS->SiS_Pr->SiS_RefIndex[i].Ext_CRT1CRTC;
+
+      /* 0x5a (320x240) is a pure FTSN mode, not DSTN! */
+      if((!pSiS->FSTN) &&
+	 (pSiS->SiS_Pr->SiS_RefIndex[i].ModeID == 0x5a))  {
+           i++;
+      	   continue;
+      }
+      if((pSiS->FSTN) &&
+         (pSiS->SiS_Pr->SiS_RefIndex[i].XRes == 320) &&
+	 (pSiS->SiS_Pr->SiS_RefIndex[i].YRes == 240) &&
+	 (pSiS->SiS_Pr->SiS_RefIndex[i].ModeID != 0x5a)) {
+	   i++;
+	   continue;
+      }
+
+      if(!(new = xalloc(sizeof(DisplayModeRec)))) return first;
+      memset(new, 0, sizeof(DisplayModeRec));
+      if(!(new->name = xalloc(10))) {
+      		xfree(new);
+		return first;
+      }
+      if(!first) first = new;
+      if(current) {
+         current->next = new;
+	 new->prev = current;
+      }
+
+      current = new;
+
+      sprintf(current->name, "%dx%d", pSiS->SiS_Pr->SiS_RefIndex[i].XRes,
+                                      pSiS->SiS_Pr->SiS_RefIndex[i].YRes);
+
+      current->status = MODE_OK;
+
+      current->type = M_T_DEFAULT;
+
+      vclkindex = pSiS->SiS_Pr->SiS_RefIndex[i].Ext_CRTVCLK;
+      if(pSiS->VGAEngine == SIS_300_VGA) vclkindex &= 0x3F;
+
+      sr2b = pSiS->SiS_Pr->SiS_VCLKData[vclkindex].SR2B;
+      sr2c = pSiS->SiS_Pr->SiS_VCLKData[vclkindex].SR2C;
+
+      divider = (sr2b & 0x80) ? 2.0 : 1.0;
+      postscalar = (sr2c & 0x80) ?
+              ( (((sr2c >> 5) & 0x03) == 0x02) ? 6.0 : 8.0) : (((sr2c >> 5) & 0x03) + 1.0);
+      num = (sr2b & 0x7f) + 1.0;
+      denum = (sr2c & 0x1f) + 1.0;
+
+#ifdef TWDEBUG
+      xf86DrvMsg(0, X_INFO, "------------\n");
+      xf86DrvMsg(0, X_INFO, "sr2b: %x sr2c %x div %f ps %f num %f denum %f\n",
+         sr2b, sr2c, divider, postscalar, num, denum);
+#endif
+
+      current->Clock = (int)(14318 * (divider / postscalar) * (num / denum));
+
+      sr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[14];
+	/* inSISIDXREG(SISSR, 0x0b, sr_data); */
+
+      cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[0];
+	/* inSISIDXREG(SISCR, 0x00, cr_data); */
+
+      /* Horizontal total */
+      HT = (cr_data & 0xff) |
+           ((unsigned short) (sr_data & 0x03) << 8);
+      A = HT + 5;
+
+      cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[1];
+	/* inSISIDXREG(SISCR, 0x01, cr_data); */
+
+      /* Horizontal display enable end */
+      HDE = (cr_data & 0xff) |
+            ((unsigned short) (sr_data & 0x0C) << 6);
+      E = HDE + 1;  /* 0x80 0x64 */
+
+      cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[4];
+	/* inSISIDXREG(SISCR, 0x04, cr_data); */
+
+      /* Horizontal retrace (=sync) start */
+      HRS = (cr_data & 0xff) |
+            ((unsigned short) (sr_data & 0xC0) << 2);
+      F = HRS - E - 3;  /* 0x06 0x06 */
+
+      cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[2];
+	/* inSISIDXREG(SISCR, 0x02, cr_data); */
+
+      /* Horizontal blank start */
+      HBS = (cr_data & 0xff) |
+            ((unsigned short) (sr_data & 0x30) << 4);
+
+      sr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[15];
+	/* inSISIDXREG(SISSR, 0x0c, sr_data); */
+
+      cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[3];
+	/* inSISIDXREG(SISCR, 0x03, cr_data);  */
+
+      cr_data2 = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[5];
+	/* inSISIDXREG(SISCR, 0x05, cr_data2); */
+
+      /* Horizontal blank end */
+      HBE = (cr_data & 0x1f) |
+            ((unsigned short) (cr_data2 & 0x80) >> 2) |
+	    ((unsigned short) (sr_data & 0x03) << 6);
+
+      /* Horizontal retrace (=sync) end */
+      HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3);
+
+      temp = HBE - ((E - 1) & 255);
+      B = (temp > 0) ? temp : (temp + 256);
+
+      temp = HRE - ((E + F + 3) & 63);
+      C = (temp > 0) ? temp : (temp + 64); /* 0x0b 0x0b */
+
+      D = B - F - C;
+
+      if((pSiS->SiS_Pr->SiS_RefIndex[i].XRes == 320) &&
+	 ((pSiS->SiS_Pr->SiS_RefIndex[i].YRes == 200) ||
+	  (pSiS->SiS_Pr->SiS_RefIndex[i].YRes == 240))) {
+
+	 /* Terrible hack, but correct CRTC data for
+	  * these modes only produces a black screen...
+	  * (HRE is 0, leading into a too large C and
+	  * a negative D. The CRT controller does not
+	  * seem to like correcting HRE to 50
+	  */
+	 current->HDisplay   = 320;
+         current->HSyncStart = 328;
+         current->HSyncEnd   = 376;
+         current->HTotal     = 400;
+
+      } else {
+
+         current->HDisplay   = (E * 8);
+         current->HSyncStart = (E * 8) + (F * 8);
+         current->HSyncEnd   = (E * 8) + (F * 8) + (C * 8);
+         current->HTotal     = (E * 8) + (F * 8) + (C * 8) + (D * 8);
+
+      }
+
+#ifdef TWDEBUG
+      xf86DrvMsg(0, X_INFO,
+        "H: A %d B %d C %d D %d E %d F %d  HT %d HDE %d HRS %d HBS %d HBE %d HRE %d\n",
+      	A, B, C, D, E, F, HT, HDE, HRS, HBS, HBE, HRE);
+#endif
+
+      sr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[13];
+	/* inSISIDXREG(SISSR, 0x0A, sr_data); */
+
+      cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[6];
+        /* inSISIDXREG(SISCR, 0x06, cr_data); */
+
+      cr_data2 = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[7];
+        /* inSISIDXREG(SISCR, 0x07, cr_data2);  */
+
+      /* Vertical total */
+      VT = (cr_data & 0xFF) |
+           ((unsigned short) (cr_data2 & 0x01) << 8) |
+	   ((unsigned short)(cr_data2 & 0x20) << 4) |
+	   ((unsigned short) (sr_data & 0x01) << 10);
+      A = VT + 2;
+
+      cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[10];
+	/* inSISIDXREG(SISCR, 0x12, cr_data);  */
+
+      /* Vertical display enable end */
+      VDE = (cr_data & 0xff) |
+            ((unsigned short) (cr_data2 & 0x02) << 7) |
+	    ((unsigned short) (cr_data2 & 0x40) << 3) |
+	    ((unsigned short) (sr_data & 0x02) << 9);
+      E = VDE + 1;
+
+      cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[8];
+	/* inSISIDXREG(SISCR, 0x10, cr_data); */
+
+      /* Vertical retrace (=sync) start */
+      VRS = (cr_data & 0xff) |
+            ((unsigned short) (cr_data2 & 0x04) << 6) |
+	    ((unsigned short) (cr_data2 & 0x80) << 2) |
+	    ((unsigned short) (sr_data & 0x08) << 7);
+      F = VRS + 1 - E;
+
+      cr_data =  pSiS->SiS_Pr->SiS_CRT1Table[index].CR[11];
+	/* inSISIDXREG(SISCR, 0x15, cr_data);  */
+
+      cr_data3 = (pSiS->SiS_Pr->SiS_CRT1Table[index].CR[16] & 0x01) << 5;
+	/* inSISIDXREG(SISCR, 0x09, cr_data3);  */
+
+      /* Vertical blank start */
+      VBS = (cr_data & 0xff) |
+            ((unsigned short) (cr_data2 & 0x08) << 5) |
+	    ((unsigned short) (cr_data3 & 0x20) << 4) |
+	    ((unsigned short) (sr_data & 0x04) << 8);
+
+      cr_data =  pSiS->SiS_Pr->SiS_CRT1Table[index].CR[12];
+	/* inSISIDXREG(SISCR, 0x16, cr_data); */
+
+      /* Vertical blank end */
+      VBE = (cr_data & 0xff) |
+            ((unsigned short) (sr_data & 0x10) << 4);
+      temp = VBE - ((E - 1) & 511);
+      B = (temp > 0) ? temp : (temp + 512);
+
+      cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[9];
+	/* inSISIDXREG(SISCR, 0x11, cr_data); */
+
+      /* Vertical retrace (=sync) end */
+      VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1);
+      temp = VRE - ((E + F - 1) & 31);
+      C = (temp > 0) ? temp : (temp + 32);
+
+      D = B - F - C;
+
+      current->VDisplay   = VDE + 1;
+      current->VSyncStart = VRS + 1;
+      current->VSyncEnd   = ((VRS & ~0x1f) | VRE) + 1;
+      if(VRE <= (VRS & 0x1f)) current->VSyncEnd += 32;
+      current->VTotal     = E + D + C + F;
+
+#if 0
+      current->VDisplay   = E;
+      current->VSyncStart = E + D;
+      current->VSyncEnd   = E + D + C;
+      current->VTotal     = E + D + C + F;
+#endif
+
+#ifdef TWDEBUG
+      xf86DrvMsg(0, X_INFO,
+        "V: A %d B %d C %d D %d E %d F %d  VT %d VDE %d VRS %d VBS %d VBE %d VRE %d\n",
+      	A, B, C, D, E, F, VT, VDE, VRS, VBS, VBE, VRE);
+#endif
+
+      if(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_InfoFlag & 0x4000)
+          current->Flags |= V_NHSYNC;
+      else
+          current->Flags |= V_PHSYNC;
+
+      if(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_InfoFlag & 0x8000)
+      	  current->Flags |= V_NVSYNC;
+      else
+          current->Flags |= V_PVSYNC;
+
+      if(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_InfoFlag & 0x0080)
+          current->Flags |= V_INTERLACE;
+
+      j = 0;
+      while(pSiS->SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID != 0xff) {
+          if(pSiS->SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID ==
+	                  pSiS->SiS_Pr->SiS_RefIndex[i].ModeID) {
+              if(pSiS->SiS_Pr->SiS_EModeIDTable[j].Ext_ModeFlag & DoubleScanMode) {
+	      	  current->Flags |= V_DBLSCAN;
+              }
+	      break;
+          }
+	  j++;
+      }
+
+      if(current->Flags & V_INTERLACE) {
+         current->VDisplay <<= 1;
+	 current->VSyncStart <<= 1;
+	 current->VSyncEnd <<= 1;
+	 current->VTotal <<= 1;
+	 current->VTotal |= 1;
+      }
+      if(current->Flags & V_DBLSCAN) {
+         current->Clock >>= 1;
+	 current->VDisplay >>= 1;
+	 current->VSyncStart >>= 1;
+	 current->VSyncEnd >>= 1;
+	 current->VTotal >>= 1;
+      }
+
+#ifdef TWDEBUG
+      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+      	"Built-in: %s %.2f %d %d %d %d %d %d %d %d\n",
+	current->name, (float)current->Clock / 1000,
+	current->HDisplay, current->HSyncStart, current->HSyncEnd, current->HTotal,
+	current->VDisplay, current->VSyncStart, current->VSyncEnd, current->VTotal);
+#else
+        (void)VBS;  (void)HBS;  (void)A;
+#endif
+
+      i++;
+   }
+
+   /* Add non-standard LCD modes for panel's detailed timings */
+
+   if(!includelcdmodes) return first;
+
+   if(pSiS->SiS_Pr->CP_Vendor) {
+      xf86DrvMsg(0, X_INFO, "Checking database for vendor %x, product %x\n",
+         pSiS->SiS_Pr->CP_Vendor, pSiS->SiS_Pr->CP_Product);
+   }
+
+   i = 0;
+   while((!done) && (SiS_PlasmaTable[i].vendor) && (pSiS->SiS_Pr->CP_Vendor)) {
+
+     if(SiS_PlasmaTable[i].vendor == pSiS->SiS_Pr->CP_Vendor) {
+
+        for(j=0; j<SiS_PlasmaTable[i].productnum; j++) {
+
+	    if(SiS_PlasmaTable[i].product[j] == pSiS->SiS_Pr->CP_Product) {
+
+	       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+	       	  "Identified %s panel, adding specific modes\n",
+		  SiS_PlasmaTable[i].plasmaname);
+
+	       for(k=0; k<SiS_PlasmaTable[i].modenum; k++) {
+
+	          if(isfordvi) {
+		     if(!(SiS_PlasmaTable[i].plasmamodes[k] & 0x80)) continue;
+		  } else {
+		     if(!(SiS_PlasmaTable[i].plasmamodes[k] & 0x40)) continue;
+		  }
+
+		  l = SiS_PlasmaTable[i].plasmamodes[k] & 0x3f;
+
+		  if(pSiS->VBFlags & (VB_301|VB_301B|VB_302B|VB_301LV)) {
+		     if(isfordvi) {
+		        if(SiS_PlasmaMode[l].VDisplay > 1024) continue;
+		     }
+		  }
+
+	          if(!(new = xalloc(sizeof(DisplayModeRec)))) return first;
+
+                  memset(new, 0, sizeof(DisplayModeRec));
+                  if(!(new->name = xalloc(12))) {
+      		     xfree(new);
+		     return first;
+                  }
+                  if(!first) first = new;
+                  if(current) {
+                     current->next = new;
+	             new->prev = current;
+                  }
+
+                  current = new;
+
+		  pSiS->AddedPlasmaModes = TRUE;
+
+		  strcpy(current->name, SiS_PlasmaMode[l].name);
+	          /* sprintf(current->name, "%dx%d", SiS_PlasmaMode[l].HDisplay,
+                                                  SiS_PlasmaMode[l].VDisplay); */
+
+                  current->status = MODE_OK;
+
+                  current->type = M_T_BUILTIN;
+
+		  current->Clock = SiS_PlasmaMode[l].clock;
+            	  current->SynthClock = current->Clock;
+
+                  current->HDisplay   = SiS_PlasmaMode[l].HDisplay;
+                  current->HSyncStart = current->HDisplay + SiS_PlasmaMode[l].HFrontPorch;
+                  current->HSyncEnd   = current->HSyncStart + SiS_PlasmaMode[l].HSyncWidth;
+                  current->HTotal     = SiS_PlasmaMode[l].HTotal;
+
+		  current->VDisplay   = SiS_PlasmaMode[l].VDisplay;
+                  current->VSyncStart = current->VDisplay + SiS_PlasmaMode[l].VFrontPorch;
+                  current->VSyncEnd   = current->VSyncStart + SiS_PlasmaMode[l].VSyncWidth;
+                  current->VTotal     = SiS_PlasmaMode[l].VTotal;
+
+                  current->CrtcHDisplay = current->HDisplay;
+                  current->CrtcHBlankStart = current->HSyncStart;
+                  current->CrtcHSyncStart = current->HSyncStart;
+                  current->CrtcHSyncEnd = current->HSyncEnd;
+                  current->CrtcHBlankEnd = current->HSyncEnd;
+                  current->CrtcHTotal = current->HTotal;
+
+                  current->CrtcVDisplay = current->VDisplay;
+                  current->CrtcVBlankStart = current->VSyncStart;
+                  current->CrtcVSyncStart = current->VSyncStart;
+                  current->CrtcVSyncEnd = current->VSyncEnd;
+                  current->CrtcVBlankEnd = current->VSyncEnd;
+                  current->CrtcVTotal = current->VTotal;
+
+                  if(SiS_PlasmaMode[l].SyncFlags & SIS_PL_HSYNCP)
+                     current->Flags |= V_PHSYNC;
+                  else
+                     current->Flags |= V_NHSYNC;
+
+                  if(SiS_PlasmaMode[l].SyncFlags & SIS_PL_VSYNCP)
+                     current->Flags |= V_PVSYNC;
+                  else
+                     current->Flags |= V_NVSYNC;
+
+		  if(current->HDisplay > pSiS->LCDwidth)
+		     pSiS->LCDwidth = pSiS->SiS_Pr->CP_MaxX = current->HDisplay;
+	          if(current->VDisplay > pSiS->LCDheight)
+		     pSiS->LCDheight = pSiS->SiS_Pr->CP_MaxY = current->VDisplay;
+
+		  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+		  	"\tAdding \"%s\" to list of built-in modes\n", current->name);
+
+               }
+	       done = TRUE;
+	       break;
+	    }
+	}
+     }
+
+     i++;
+
+   }
+
+   if(pSiS->SiS_Pr->CP_HaveCustomData) {
+
+      for(i=0; i<7; i++) {
+
+         if(pSiS->SiS_Pr->CP_DataValid[i]) {
+
+            if(!(new = xalloc(sizeof(DisplayModeRec)))) return first;
+
+            memset(new, 0, sizeof(DisplayModeRec));
+            if(!(new->name = xalloc(10))) {
+      		xfree(new);
+		return first;
+            }
+            if(!first) first = new;
+            if(current) {
+               current->next = new;
+	       new->prev = current;
+            }
+
+            current = new;
+
+            sprintf(current->name, "%dx%d", pSiS->SiS_Pr->CP_HDisplay[i],
+                                            pSiS->SiS_Pr->CP_VDisplay[i]);
+
+            current->status = MODE_OK;
+
+            current->type = M_T_BUILTIN;
+
+            current->Clock = pSiS->SiS_Pr->CP_Clock[i];
+            current->SynthClock = current->Clock;
+
+            current->HDisplay   = pSiS->SiS_Pr->CP_HDisplay[i];
+            current->HSyncStart = pSiS->SiS_Pr->CP_HSyncStart[i];
+            current->HSyncEnd   = pSiS->SiS_Pr->CP_HSyncEnd[i];
+            current->HTotal     = pSiS->SiS_Pr->CP_HTotal[i];
+
+            current->VDisplay   = pSiS->SiS_Pr->CP_VDisplay[i];
+            current->VSyncStart = pSiS->SiS_Pr->CP_VSyncStart[i];
+            current->VSyncEnd   = pSiS->SiS_Pr->CP_VSyncEnd[i];
+            current->VTotal     = pSiS->SiS_Pr->CP_VTotal[i];
+
+            current->CrtcHDisplay = current->HDisplay;
+            current->CrtcHBlankStart = pSiS->SiS_Pr->CP_HBlankStart[i];
+            current->CrtcHSyncStart = current->HSyncStart;
+            current->CrtcHSyncEnd = current->HSyncEnd;
+            current->CrtcHBlankEnd = pSiS->SiS_Pr->CP_HBlankEnd[i];
+            current->CrtcHTotal = current->HTotal;
+
+            current->CrtcVDisplay = current->VDisplay;
+            current->CrtcVBlankStart = pSiS->SiS_Pr->CP_VBlankStart[i];
+            current->CrtcVSyncStart = current->VSyncStart;
+            current->CrtcVSyncEnd = current->VSyncEnd;
+            current->CrtcVBlankEnd = pSiS->SiS_Pr->CP_VBlankEnd[i];
+            current->CrtcVTotal = current->VTotal;
+
+	    if(pSiS->SiS_Pr->CP_SyncValid[i]) {
+               if(pSiS->SiS_Pr->CP_HSync_P[i])
+                  current->Flags |= V_PHSYNC;
+               else
+                  current->Flags |= V_NHSYNC;
+
+               if(pSiS->SiS_Pr->CP_VSync_P[i])
+                  current->Flags |= V_PVSYNC;
+               else
+                  current->Flags |= V_NVSYNC;
+	    } else {
+	       /* No sync data? Use positive sync... */
+	       current->Flags |= V_PHSYNC;
+	       current->Flags |= V_PVSYNC;
+	    }
+         }
+      }
+   }
+
+   return first;
+
+}
+
+/* Translate a mode number into the VESA pendant */
+int
+SiSTranslateToVESA(ScrnInfoPtr pScrn, int modenumber)
+{
+   SISPtr pSiS = SISPTR(pScrn);
+   int    i = 0;
+
+   /* Initialize our pointers */
+   if(pSiS->VGAEngine == SIS_300_VGA) {
+#ifdef SIS300
+	InitTo300Pointer(pSiS->SiS_Pr, &pSiS->sishw_ext);
+#else
+	return -1;
+#endif
+   } else if(pSiS->VGAEngine == SIS_315_VGA) {
+#ifdef SIS315H
+       	InitTo310Pointer(pSiS->SiS_Pr, &pSiS->sishw_ext);
+#else
+	return -1;
+#endif
+   } else return -1;
+
+   if(modenumber <= 0x13) return modenumber;
+
+#ifdef SIS315H
+   if(pSiS->ROM661New) {
+      while(SiS_EModeIDTable661[i].Ext_ModeID != 0xff) {
+         if(SiS_EModeIDTable661[i].Ext_ModeID == modenumber) {
+            return (int)SiS_EModeIDTable661[i].Ext_VESAID;
+         }
+         i++;
+      }
+   } else {
+#endif
+      while(pSiS->SiS_Pr->SiS_EModeIDTable[i].Ext_ModeID != 0xff) {
+         if(pSiS->SiS_Pr->SiS_EModeIDTable[i].Ext_ModeID == modenumber) {
+            return (int)pSiS->SiS_Pr->SiS_EModeIDTable[i].Ext_VESAID;
+         }
+         i++;
+      }
+#ifdef SIS315H
+   }
+#endif
+   return -1;
+}
+
+/* Translate a new BIOS mode number into the driver's pendant */
+int
+SiSTranslateToOldMode(int modenumber)
+{
+#ifdef SIS315H
+   int    i = 0;
+
+   while(SiS_EModeIDTable661[i].Ext_ModeID != 0xff) {
+      if(SiS_EModeIDTable661[i].Ext_ModeID == modenumber) {
+         if(SiS_EModeIDTable661[i].Ext_MyModeID)
+            return (int)SiS_EModeIDTable661[i].Ext_MyModeID;
+	 else
+	    return modenumber;
+      }
+      i++;
+   }
+#endif
+   return modenumber;
+}
+
+#endif  /* Xfree86 */
+
+#ifdef LINUX_KERNEL
+int
+sisfb_mode_rate_to_dclock(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+			  unsigned char modeno, unsigned char rateindex)
+{
+    USHORT ModeNo = modeno;
+    USHORT ModeIdIndex = 0, ClockIndex = 0;
+    USHORT RefreshRateTableIndex = 0;
+    int    Clock;
+
+    if(HwInfo->jChipType < SIS_315H) {
+#ifdef SIS300
+       InitTo300Pointer(SiS_Pr, HwInfo);
+#else
+       return 65 * 1000;
+#endif
+    } else {
+#ifdef SIS315H
+       InitTo310Pointer(SiS_Pr, HwInfo);
+#else
+       return 65 * 1000;
+#endif
+    }
+
+    if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) {;
+    	printk(KERN_ERR "Could not find mode %x\n", ModeNo);
+    	return 65 * 1000;
+    }
+
+    RefreshRateTableIndex = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
+    RefreshRateTableIndex += (rateindex - 1);
+    ClockIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+    if(HwInfo->jChipType < SIS_315H) {
+       ClockIndex &= 0x3F;
+    }
+    Clock = SiS_Pr->SiS_VCLKData[ClockIndex].CLOCK * 1000;
+    
+    return(Clock);
+}
+
+BOOLEAN
+sisfb_gettotalfrommode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+		       unsigned char modeno, int *htotal, int *vtotal, unsigned char rateindex)
+{
+    USHORT ModeNo = modeno;
+    USHORT ModeIdIndex = 0, CRT1Index = 0;
+    USHORT RefreshRateTableIndex = 0;
+    unsigned char  sr_data, cr_data, cr_data2;
+
+    if(HwInfo->jChipType < SIS_315H) {
+#ifdef SIS300
+       InitTo300Pointer(SiS_Pr, HwInfo);
+#else
+       return FALSE;
+#endif
+    } else {
+#ifdef SIS315H
+       InitTo310Pointer(SiS_Pr, HwInfo);
+#else
+       return FALSE;
+#endif
+    }
+
+    if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return FALSE;
+
+    RefreshRateTableIndex = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
+    RefreshRateTableIndex += (rateindex - 1);
+    CRT1Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+
+    sr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14];
+    cr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[0];
+    *htotal = (((cr_data & 0xff) | ((unsigned short) (sr_data & 0x03) << 8)) + 5) * 8;
+
+    sr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[13];
+    cr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[6];
+    cr_data2 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[7];
+    *vtotal = ((cr_data & 0xFF) |
+               ((unsigned short)(cr_data2 & 0x01) <<  8) |
+	       ((unsigned short)(cr_data2 & 0x20) <<  4) |
+	       ((unsigned short)(sr_data  & 0x01) << 10)) + 2;
+
+    if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag & InterlaceMode)
+       *vtotal *= 2;
+
+    return TRUE;
+}
+
+int
+sisfb_mode_rate_to_ddata(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+			 unsigned char modeno, unsigned char rateindex,
+			 struct fb_var_screeninfo *var)
+{
+    USHORT ModeNo = modeno;
+    USHORT ModeIdIndex = 0, index = 0;
+    USHORT RefreshRateTableIndex = 0;
+    unsigned short VRE, VBE, VRS, VBS, VDE, VT;
+    unsigned short HRE, HBE, HRS, HBS, HDE, HT;
+    unsigned char  sr_data, cr_data, cr_data2, cr_data3;
+    int            A, B, C, D, E, F, temp, j;
+   
+    if(HwInfo->jChipType < SIS_315H) {
+#ifdef SIS300
+       InitTo300Pointer(SiS_Pr, HwInfo);
+#else
+       return 0;
+#endif
+    } else {
+#ifdef SIS315H
+       InitTo310Pointer(SiS_Pr, HwInfo);
+#else
+       return 0;
+#endif
+    }
+
+    if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return 0;
+
+    RefreshRateTableIndex = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
+    RefreshRateTableIndex += (rateindex - 1);
+    index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+
+    sr_data = SiS_Pr->SiS_CRT1Table[index].CR[14];
+
+    cr_data = SiS_Pr->SiS_CRT1Table[index].CR[0];
+
+    /* Horizontal total */
+    HT = (cr_data & 0xff) |
+         ((unsigned short) (sr_data & 0x03) << 8);
+    A = HT + 5;
+
+    cr_data = SiS_Pr->SiS_CRT1Table[index].CR[1];
+	
+    /* Horizontal display enable end */
+    HDE = (cr_data & 0xff) |
+          ((unsigned short) (sr_data & 0x0C) << 6);
+    E = HDE + 1;
+
+    cr_data = SiS_Pr->SiS_CRT1Table[index].CR[4];
+	
+    /* Horizontal retrace (=sync) start */
+    HRS = (cr_data & 0xff) |
+          ((unsigned short) (sr_data & 0xC0) << 2);
+    F = HRS - E - 3;
+
+    cr_data = SiS_Pr->SiS_CRT1Table[index].CR[2];
+	
+    /* Horizontal blank start */
+    HBS = (cr_data & 0xff) |
+          ((unsigned short) (sr_data & 0x30) << 4);
+
+    sr_data = SiS_Pr->SiS_CRT1Table[index].CR[15];
+	
+    cr_data = SiS_Pr->SiS_CRT1Table[index].CR[3];
+
+    cr_data2 = SiS_Pr->SiS_CRT1Table[index].CR[5];
+	
+    /* Horizontal blank end */
+    HBE = (cr_data & 0x1f) |
+          ((unsigned short) (cr_data2 & 0x80) >> 2) |
+	  ((unsigned short) (sr_data & 0x03) << 6);
+
+    /* Horizontal retrace (=sync) end */
+    HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3);
+
+    temp = HBE - ((E - 1) & 255);
+    B = (temp > 0) ? temp : (temp + 256);
+
+    temp = HRE - ((E + F + 3) & 63);
+    C = (temp > 0) ? temp : (temp + 64);
+
+    D = B - F - C;
+
+    if((SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].XRes == 320) &&
+       ((SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].YRes == 200) ||
+	(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].YRes == 240))) {
+
+	 /* Terrible hack, but the correct CRTC data for
+	  * these modes only produces a black screen...
+	  */
+       var->left_margin = (400 - 376);
+       var->right_margin = (328 - 320);
+       var->hsync_len = (376 - 328);
+
+    } else {
+
+       var->left_margin = D * 8;
+       var->right_margin = F * 8;
+       var->hsync_len = C * 8;
+
+    }
+
+    sr_data = SiS_Pr->SiS_CRT1Table[index].CR[13];
+
+    cr_data = SiS_Pr->SiS_CRT1Table[index].CR[6];
+
+    cr_data2 = SiS_Pr->SiS_CRT1Table[index].CR[7];
+
+    /* Vertical total */
+    VT = (cr_data & 0xFF) |
+         ((unsigned short) (cr_data2 & 0x01) << 8) |
+	 ((unsigned short)(cr_data2 & 0x20) << 4) |
+	 ((unsigned short) (sr_data & 0x01) << 10);
+    A = VT + 2;
+
+    cr_data = SiS_Pr->SiS_CRT1Table[index].CR[10];
+	
+    /* Vertical display enable end */
+    VDE = (cr_data & 0xff) |
+          ((unsigned short) (cr_data2 & 0x02) << 7) |
+	  ((unsigned short) (cr_data2 & 0x40) << 3) |
+	  ((unsigned short) (sr_data & 0x02) << 9);
+    E = VDE + 1;
+
+    cr_data = SiS_Pr->SiS_CRT1Table[index].CR[8];
+
+    /* Vertical retrace (=sync) start */
+    VRS = (cr_data & 0xff) |
+          ((unsigned short) (cr_data2 & 0x04) << 6) |
+	  ((unsigned short) (cr_data2 & 0x80) << 2) |
+	  ((unsigned short) (sr_data & 0x08) << 7);
+    F = VRS + 1 - E;
+
+    cr_data =  SiS_Pr->SiS_CRT1Table[index].CR[11];
+
+    cr_data3 = (SiS_Pr->SiS_CRT1Table[index].CR[16] & 0x01) << 5;
+
+    /* Vertical blank start */
+    VBS = (cr_data & 0xff) |
+          ((unsigned short) (cr_data2 & 0x08) << 5) |
+	  ((unsigned short) (cr_data3 & 0x20) << 4) |
+	  ((unsigned short) (sr_data & 0x04) << 8);
+
+    cr_data =  SiS_Pr->SiS_CRT1Table[index].CR[12];
+
+    /* Vertical blank end */
+    VBE = (cr_data & 0xff) |
+          ((unsigned short) (sr_data & 0x10) << 4);
+    temp = VBE - ((E - 1) & 511);
+    B = (temp > 0) ? temp : (temp + 512);
+
+    cr_data = SiS_Pr->SiS_CRT1Table[index].CR[9];
+
+    /* Vertical retrace (=sync) end */
+    VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1);
+    temp = VRE - ((E + F - 1) & 31);
+    C = (temp > 0) ? temp : (temp + 32);
+
+    D = B - F - C;
+      
+    var->upper_margin = D;
+    var->lower_margin = F;
+    var->vsync_len = C;
+
+    if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag & 0x8000)
+       var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
+    else
+       var->sync |= FB_SYNC_VERT_HIGH_ACT;
+
+    if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag & 0x4000)       
+       var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
+    else
+       var->sync |= FB_SYNC_HOR_HIGH_ACT;
+		
+    var->vmode = FB_VMODE_NONINTERLACED;
+    if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag & 0x0080)
+       var->vmode = FB_VMODE_INTERLACED;
+    else {
+       j = 0;
+       while(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID != 0xff) {
+          if(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID ==
+	                  SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].ModeID) {
+              if(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeFlag & DoubleScanMode) {
+	      	  var->vmode = FB_VMODE_DOUBLE;
+              }
+	      break;
+          }
+	  j++;
+       }
+    }       
+
+    if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+#if 0  /* Do this? */
+       var->upper_margin <<= 1;
+       var->lower_margin <<= 1;
+       var->vsync_len <<= 1;
+#endif
+    } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+       var->upper_margin >>= 1;
+       var->lower_margin >>= 1;
+       var->vsync_len >>= 1;
+    }
+
+    return 1;       
+}			  
+
+#endif
+
diff --git a/drivers/video/sis/init.h b/drivers/video/sis/init.h
new file mode 100644
index 0000000..35030d3
--- /dev/null
+++ b/drivers/video/sis/init.h
@@ -0,0 +1,2472 @@
+/* $XFree86$ */
+/* $XdotOrg$ */
+/*
+ * Data and prototypes for init.c
+ *
+ * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, the following license terms
+ * apply:
+ *
+ * * This program is free software; you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License as published by
+ * * the Free Software Foundation; either version 2 of the named License,
+ * * or any later version.
+ * *
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details.
+ * *
+ * * You should have received a copy of the GNU General Public License
+ * * along with this program; if not, write to the Free Software
+ * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * * Redistribution and use in source and binary forms, with or without
+ * * modification, are permitted provided that the following conditions
+ * * are met:
+ * * 1) Redistributions of source code must retain the above copyright
+ * *    notice, this list of conditions and the following disclaimer.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * *    notice, this list of conditions and the following disclaimer in the
+ * *    documentation and/or other materials provided with the distribution.
+ * * 3) The name of the author may not be used to endorse or promote products
+ * *    derived from this software without specific prior written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ */
+
+#ifndef _INIT_
+#define _INIT_
+
+#include "osdef.h"
+#include "initdef.h"
+
+#ifdef LINUX_XF86
+#include "sis.h"
+#include "sis_regs.h"
+#endif
+
+#ifdef LINUX_KERNEL
+#include "vgatypes.h"
+#include "vstruct.h"
+#ifdef SIS_CP
+#undef SIS_CP
+#endif
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <linux/fb.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#include <linux/sisfb.h>
+#else
+#include <video/sisfb.h>
+#endif
+#endif
+
+/* Mode numbers */
+static const USHORT ModeIndex_320x200[]      = {0x59, 0x41, 0x00, 0x4f};
+static const USHORT ModeIndex_320x240[]      = {0x50, 0x56, 0x00, 0x53};
+static const USHORT ModeIndex_320x240_FSTN[] = {0x5a, 0x5b, 0x00, 0x00};  /* FSTN */
+static const USHORT ModeIndex_400x300[]      = {0x51, 0x57, 0x00, 0x54};
+static const USHORT ModeIndex_512x384[]      = {0x52, 0x58, 0x00, 0x5c};
+static const USHORT ModeIndex_640x400[]      = {0x2f, 0x5d, 0x00, 0x5e};
+static const USHORT ModeIndex_640x480[]      = {0x2e, 0x44, 0x00, 0x62};
+static const USHORT ModeIndex_720x480[]      = {0x31, 0x33, 0x00, 0x35};
+static const USHORT ModeIndex_720x576[]      = {0x32, 0x34, 0x00, 0x36};
+static const USHORT ModeIndex_768x576[]      = {0x5f, 0x60, 0x00, 0x61};
+static const USHORT ModeIndex_800x480[]      = {0x70, 0x7a, 0x00, 0x76};
+static const USHORT ModeIndex_800x600[]      = {0x30, 0x47, 0x00, 0x63};
+static const USHORT ModeIndex_848x480[]      = {0x39, 0x3b, 0x00, 0x3e};
+static const USHORT ModeIndex_856x480[]      = {0x3f, 0x42, 0x00, 0x45};
+static const USHORT ModeIndex_960x540[]      = {0x1d, 0x1e, 0x00, 0x1f};  /* 315 series only */
+static const USHORT ModeIndex_960x600[]      = {0x20, 0x21, 0x00, 0x22};  /* 315 series only */
+static const USHORT ModeIndex_1024x768[]     = {0x38, 0x4a, 0x00, 0x64};
+static const USHORT ModeIndex_1024x576[]     = {0x71, 0x74, 0x00, 0x77};
+static const USHORT ModeIndex_1024x600[]     = {0x20, 0x21, 0x00, 0x22};  /* 300 series only */
+static const USHORT ModeIndex_1280x1024[]    = {0x3a, 0x4d, 0x00, 0x65};
+static const USHORT ModeIndex_1280x960[]     = {0x7c, 0x7d, 0x00, 0x7e};
+static const USHORT ModeIndex_1152x768[]     = {0x23, 0x24, 0x00, 0x25};  /* 300 series only */
+static const USHORT ModeIndex_1152x864[]     = {0x29, 0x2a, 0x00, 0x2b};
+static const USHORT ModeIndex_300_1280x768[] = {0x55, 0x5a, 0x00, 0x5b};
+static const USHORT ModeIndex_310_1280x768[] = {0x23, 0x24, 0x00, 0x25};
+static const USHORT ModeIndex_1280x720[]     = {0x79, 0x75, 0x00, 0x78};
+static const USHORT ModeIndex_1280x800[]     = {0x14, 0x15, 0x00, 0x16};
+static const USHORT ModeIndex_1360x768[]     = {0x48, 0x4b, 0x00, 0x4e};
+static const USHORT ModeIndex_300_1360x1024[]= {0x67, 0x6f, 0x00, 0x72};  /* 300 series, BARCO only */
+static const USHORT ModeIndex_1400x1050[]    = {0x26, 0x27, 0x00, 0x28};  /* 315 series only */
+static const USHORT ModeIndex_1680x1050[]    = {0x17, 0x18, 0x00, 0x19};  /* 315 series only */
+static const USHORT ModeIndex_1600x1200[]    = {0x3c, 0x3d, 0x00, 0x66};
+static const USHORT ModeIndex_1920x1080[]    = {0x2c, 0x2d, 0x00, 0x73};  /* 315 series only */
+static const USHORT ModeIndex_1920x1440[]    = {0x68, 0x69, 0x00, 0x6b};
+static const USHORT ModeIndex_300_2048x1536[]= {0x6c, 0x6d, 0x00, 0x00};
+static const USHORT ModeIndex_310_2048x1536[]= {0x6c, 0x6d, 0x00, 0x6e};
+
+static const USHORT SiS_DRAMType[17][5]={
+	{0x0C,0x0A,0x02,0x40,0x39},
+	{0x0D,0x0A,0x01,0x40,0x48},
+	{0x0C,0x09,0x02,0x20,0x35},
+	{0x0D,0x09,0x01,0x20,0x44},
+	{0x0C,0x08,0x02,0x10,0x31},
+	{0x0D,0x08,0x01,0x10,0x40},
+	{0x0C,0x0A,0x01,0x20,0x34},
+	{0x0C,0x09,0x01,0x08,0x32},
+	{0x0B,0x08,0x02,0x08,0x21},
+	{0x0C,0x08,0x01,0x08,0x30},
+	{0x0A,0x08,0x02,0x04,0x11},
+	{0x0B,0x0A,0x01,0x10,0x28},
+	{0x09,0x08,0x02,0x02,0x01},
+	{0x0B,0x09,0x01,0x08,0x24},
+	{0x0B,0x08,0x01,0x04,0x20},
+	{0x0A,0x08,0x01,0x02,0x10},
+	{0x09,0x08,0x01,0x01,0x00}
+};
+
+static const USHORT SiS_SDRDRAM_TYPE[13][5] =
+{
+	{ 2,12, 9,64,0x35},
+	{ 1,13, 9,64,0x44},
+	{ 2,12, 8,32,0x31},
+	{ 2,11, 9,32,0x25},
+	{ 1,12, 9,32,0x34},
+	{ 1,13, 8,32,0x40},
+	{ 2,11, 8,16,0x21},
+	{ 1,12, 8,16,0x30},
+	{ 1,11, 9,16,0x24},
+	{ 1,11, 8, 8,0x20},
+	{ 2, 9, 8, 4,0x01},
+	{ 1,10, 8, 4,0x10},
+	{ 1, 9, 8, 2,0x00}
+};
+
+static const USHORT SiS_DDRDRAM_TYPE[4][5] =
+{
+	{ 2,12, 9,64,0x35},
+	{ 2,12, 8,32,0x31},
+	{ 2,11, 8,16,0x21},
+	{ 2, 9, 8, 4,0x01}
+};
+
+static const USHORT SiS_MDA_DAC[] =
+{
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+        0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
+        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+        0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F
+};
+
+static const USHORT SiS_CGA_DAC[] =
+{
+        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
+        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
+        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
+        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F
+};
+
+static const USHORT SiS_EGA_DAC[] =
+{
+        0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15,
+        0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35,
+        0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D,
+        0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D,
+        0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17,
+        0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37,
+        0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F,
+        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F
+};
+
+static const USHORT SiS_VGA_DAC[] =
+{
+	0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+	0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
+	0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18,
+	0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F,
+	0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F,
+	0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00,
+	0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18,
+	0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04,
+	0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10,
+	0x0B,0x0C,0x0D,0x0F,0x10
+};
+
+static const SiS_StResInfoStruct SiS_StResInfo[]=
+{
+	{ 640,400},
+	{ 640,350},
+	{ 720,400},
+	{ 720,350},
+	{ 640,480}
+};
+
+static const SiS_ModeResInfoStruct SiS_ModeResInfo[] =
+{
+	{  320, 200, 8, 8},   /* 0x00 */
+	{  320, 240, 8, 8},   /* 0x01 */
+	{  320, 400, 8, 8},   /* 0x02 */
+	{  400, 300, 8, 8},   /* 0x03 */
+	{  512, 384, 8, 8},   /* 0x04 */
+	{  640, 400, 8,16},   /* 0x05 */
+	{  640, 480, 8,16},   /* 0x06 */
+	{  800, 600, 8,16},   /* 0x07 */
+	{ 1024, 768, 8,16},   /* 0x08 */
+	{ 1280,1024, 8,16},   /* 0x09 */
+	{ 1600,1200, 8,16},   /* 0x0a */
+	{ 1920,1440, 8,16},   /* 0x0b */
+	{ 2048,1536, 8,16},   /* 0x0c */
+	{  720, 480, 8,16},   /* 0x0d */
+	{  720, 576, 8,16},   /* 0x0e */
+	{ 1280, 960, 8,16},   /* 0x0f */
+	{  800, 480, 8,16},   /* 0x10 */
+	{ 1024, 576, 8,16},   /* 0x11 */
+	{ 1280, 720, 8,16},   /* 0x12 */
+	{  856, 480, 8,16},   /* 0x13 */
+	{ 1280, 768, 8,16},   /* 0x14 */
+	{ 1400,1050, 8,16},   /* 0x15 */
+	{ 1152, 864, 8,16},   /* 0x16 */
+	{  848, 480, 8,16},   /* 0x17 */
+	{ 1360, 768, 8,16},   /* 0x18 */
+	{ 1024, 600, 8,16},   /* 0x19 */
+	{ 1152, 768, 8,16},   /* 0x1a */
+	{  768, 576, 8,16},   /* 0x1b */
+	{ 1360,1024, 8,16},   /* 0x1c */
+	{ 1680,1050, 8,16},   /* 0x1d */
+	{ 1280, 800, 8,16},   /* 0x1e */
+	{ 1920,1080, 8,16},   /* 0x1f */
+	{  960, 540, 8,16},   /* 0x20 */
+	{  960, 600, 8,16}    /* 0x21 */
+};
+
+#if defined(SIS300) || defined(SIS315H)
+static const SiS_StandTableStruct SiS_StandTable[]=
+{
+/* 0x00: MD_0_200 */
+ {
+  0x28,0x18,0x08,0x0800,
+  {0x09,0x03,0x00,0x02},
+  0x63,
+  {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
+   0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
+   0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3,
+   0xff},
+  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+   0x08,0x00,0x0f,0x00},
+  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+   0xff}
+ },
+/* 0x01: MD_1_200 */
+ {
+  0x28,0x18,0x08,0x0800,
+  {0x09,0x03,0x00,0x02},
+  0x63,
+  {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
+   0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
+   0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3,
+   0xff},
+  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+   0x08,0x00,0x0f,0x00},
+  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+   0xff}
+ },
+/* 0x02: MD_2_200 */
+ {
+  0x50,0x18,0x08,0x1000,
+  {0x01,0x03,0x00,0x02},
+  0x63,
+  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+   0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
+   0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
+   0xff},
+  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+   0x08,0x00,0x0f,0x00},
+  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+   0xff}
+ },
+/* 0x03: MD_3_200 - mode 0x03 - 0 */
+ {
+  0x50,0x18,0x08,0x1000,
+  {0x01,0x03,0x00,0x02},
+  0x63,
+  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+   0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
+   0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
+   0xff},
+  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+   0x08,0x00,0x0f,0x00},
+  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+   0xff}
+ },
+/* 0x04: MD_4 */
+ {
+  0x28,0x18,0x08,0x4000,
+  {0x09,0x03,0x00,0x02},
+  0x63,
+  {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,   /* 0x2c is 2b for 300 */
+   0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xa2,
+   0xff},
+  {0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07,
+   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+   0x01,0x00,0x03,0x00},
+  {0x00,0x00,0x00,0x00,0x00,0x30,0x0f,0x00,
+   0xff}
+ },
+/* 0x05: MD_5 */
+ {
+  0x28,0x18,0x08,0x4000,
+  {0x09,0x03,0x00,0x02},
+  0x63,
+  {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,   /* 0x2c is 2b for 300 */
+   0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xa2,
+   0xff},
+  {0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07,
+   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+   0x01,0x00,0x03,0x00},
+  {0x00,0x00,0x00,0x00,0x00,0x30,0x0f,0x00,
+   0xff}
+ },
+/* 0x06: MD_6 */
+ {
+  0x50,0x18,0x08,0x4000,
+  {0x01,0x01,0x00,0x06},
+  0x63,
+  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,   /* 55,81 is 54,80 for 300 */
+   0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xc2,
+   0xff},
+  {0x00,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
+   0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
+   0x01,0x00,0x01,0x00},
+  {0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x00,
+   0xff}
+ },
+/* 0x07: MD_7 */
+ {
+  0x50,0x18,0x0e,0x1000,
+  {0x00,0x03,0x00,0x03},
+  0xa6,
+  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
+   0x83,0x85,0x5d,0x28,0x0d,0x63,0xba,0xa3,
+   0xff},
+  {0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+   0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+   0x0e,0x00,0x0f,0x08},
+  {0x00,0x00,0x00,0x00,0x00,0x10,0x0a,0x00,
+   0xff}
+ },
+/* 0x08: MDA_DAC */
+ {
+  0x00,0x00,0x00,0x0000,
+  {0x00,0x00,0x00,0x15},
+  0x15,
+  {0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+   0x15,0x15,0x15,0x15,0x15,0x15,0x3f,0x3f,
+   0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x00,0x00,
+   0x00},
+  {0x00,0x00,0x00,0x00,0x00,0x15,0x15,0x15,
+   0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+   0x15,0x15,0x15,0x15},
+  {0x15,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,
+   0x3f}
+ },
+/* 0x09: CGA_DAC */
+ {
+  0x00,0x10,0x04,0x0114,
+  {0x11,0x09,0x15,0x00},
+  0x10,
+  {0x04,0x14,0x01,0x11,0x09,0x15,0x2a,0x3a,
+   0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x2a,0x3a,
+   0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x00,0x10,
+   0x04},
+  {0x14,0x01,0x11,0x09,0x15,0x00,0x10,0x04,
+   0x14,0x01,0x11,0x09,0x15,0x2a,0x3a,0x2e,
+   0x3e,0x2b,0x3b,0x2f},
+  {0x3f,0x2a,0x3a,0x2e,0x3e,0x2b,0x3b,0x2f,
+   0x3f}
+ },
+/* 0x0a: EGA_DAC */
+ {
+  0x00,0x10,0x04,0x0114,
+  {0x11,0x05,0x15,0x20},
+  0x30,
+  {0x24,0x34,0x21,0x31,0x25,0x35,0x08,0x18,
+   0x0c,0x1c,0x09,0x19,0x0d,0x1d,0x28,0x38,
+   0x2c,0x3c,0x29,0x39,0x2d,0x3d,0x02,0x12,
+   0x06},
+  {0x16,0x03,0x13,0x07,0x17,0x22,0x32,0x26,
+   0x36,0x23,0x33,0x27,0x37,0x0a,0x1a,0x0e,
+   0x1e,0x0b,0x1b,0x0f},
+  {0x1f,0x2a,0x3a,0x2e,0x3e,0x2b,0x3b,0x2f,
+   0x3f}
+ },
+/* 0x0b: VGA_DAC */
+ {
+  0x00,0x10,0x04,0x0114,
+  {0x11,0x09,0x15,0x2a},
+  0x3a,
+  {0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x00,0x05,
+   0x08,0x0b,0x0e,0x11,0x14,0x18,0x1c,0x20,
+   0x24,0x28,0x2d,0x32,0x38,0x3f,0x00,0x10,
+   0x1f},
+  {0x2f,0x3f,0x1f,0x27,0x2f,0x37,0x3f,0x2d,
+   0x31,0x36,0x3a,0x3f,0x00,0x07,0x0e,0x15,
+   0x1c,0x0e,0x11,0x15},
+  {0x18,0x1c,0x14,0x16,0x18,0x1a,0x1c,0x00,
+   0x04}
+ },
+/* 0x0c */
+ {
+  0x08,0x0c,0x10,0x0a08,
+  {0x0c,0x0e,0x10,0x0b},
+  0x0c,
+  {0x0d,0x0f,0x10,0x10,0x01,0x08,0x00,0x00,
+   0x00,0x00,0x01,0x00,0x02,0x02,0x01,0x00,
+   0x04,0x04,0x01,0x00,0x05,0x02,0x05,0x00,
+   0x06},
+  {0x01,0x06,0x05,0x06,0x00,0x08,0x01,0x08,
+   0x00,0x07,0x02,0x07,0x06,0x07,0x00,0x00,
+   0x00,0x00,0x00,0x00},
+  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}
+ },
+/* 0x0d: MD_D */
+ {
+  0x28,0x18,0x08,0x2000,
+  {0x09,0x0f,0x00,0x06},
+  0x63,
+  {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,     /* 2c is 2b for 300 */
+   0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xe3,
+   0xff},
+  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+   0x01,0x00,0x0f,0x00},
+  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
+   0xff}
+ },
+/* 0x0e: MD_E */
+ {
+  0x50,0x18,0x08,0x4000,
+  {0x01,0x0f,0x00,0x06},
+  0x63,
+  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,     /* 55,81 is 54,80 for 300 */
+   0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xe3,
+   0xff},
+  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+   0x01,0x00,0x0f,0x00},
+  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
+   0xff}
+ },
+/* 0x0f: ExtVGATable - modes > 0x13 */
+ {
+  0x00,0x00,0x00,0x0000,
+  {0x01,0x0f,0x00,0x0e},
+  0x23,
+  {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
+   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+   0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
+   0xff},
+  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+   0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+   0x01,0x00,0x00,0x00},
+  {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
+   0xff}
+ },
+/* 0x10: ROM_SAVEPTR - totally different for 300 */
+ {
+  0x9f,0x3b,0x00,0x00c0,
+  {0x00,0x00,0x00,0x00},
+  0x00,
+  {0x00,0x00,0x00,0x00,0x00,0x00,0xbb,0x3f,
+   0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x1a,0x00,0xac,0x3e,0x00,0xc0,
+   0x00},
+  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00},
+  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}
+ },
+/* 0x11: MD_F */
+ {
+  0x50,0x18,0x0e,0x8000,
+  {0x01,0x0f,0x00,0x06},
+  0xa2,
+  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,    /* 55,81 is 54,80 on 300 */
+   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x82,0x84,0x5d,0x28,0x0f,0x63,0xba,0xe3,    /* 82,84 is 83,85 on 300 */
+   0xff},
+  {0x00,0x08,0x00,0x00,0x18,0x18,0x00,0x00,
+   0x00,0x08,0x00,0x00,0x00,0x18,0x00,0x00,
+   0x0b,0x00,0x05,0x00},
+  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x05,
+   0xff}
+ },
+/* 0x12: MD_10 */
+ {
+  0x50,0x18,0x0e,0x8000,
+  {0x01,0x0f,0x00,0x06},
+  0xa3,
+  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,    /* 55,81 is 54,80 on 300 */
+   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x82,0x84,0x5d,0x28,0x0f,0x63,0xba,0xe3,    /* 82,84 is 83,85 on 300 */
+   0xff},
+  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+   0x01,0x00,0x0f,0x00},
+  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
+   0xff}
+ },
+/* 0x13: MD_0_350 */
+ {
+  0x28,0x18,0x0e,0x0800,
+  {0x09,0x03,0x00,0x02},
+  0xa3,
+  {0x2d,0x27,0x28,0x90,0x2b,0xb1,0xbf,0x1f,    /* b1 is a0 on 300 */
+   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
+   0x83,0x85,0x5d,0x14,0x1f,0x63,0xba,0xa3,
+   0xff},
+  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+   0x08,0x00,0x0f,0x00},
+  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+   0xff}
+ },
+/* 0x14: MD_1_350 */
+ {
+  0x28,0x18,0x0e,0x0800,
+  {0x09,0x03,0x00,0x02},
+  0xa3,
+  {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
+   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
+   0x83,0x85,0x5d,0x14,0x1f,0x63,0xba,0xa3,
+   0xff},
+  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+   0x08,0x00,0x0f,0x00},
+  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+   0xff}
+ },
+/* 0x15: MD_2_350 */
+ {
+  0x50,0x18,0x0e,0x1000,
+  {0x01,0x03,0x00,0x02},
+  0xa3,
+  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
+   0x83,0x85,0x5d,0x28,0x1f,0x63,0xba,0xa3,
+   0xff},
+  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+   0x08,0x00,0x0f,0x00},
+  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+   0xff}
+ },
+/* 0x16: MD_3_350 - mode 0x03 - 1 */
+ {
+  0x50,0x18,0x0e,0x1000,
+  {0x01,0x03,0x00,0x02},
+  0xa3,
+  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
+   0x83,0x85,0x5d,0x28,0x1f,0x63,0xba,0xa3,
+   0xff},
+  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+   0x08,0x00,0x0f,0x00},
+  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+   0xff}
+ },
+/* 0x17: MD_0_1_400 */
+ {
+  0x28,0x18,0x10,0x0800,
+  {0x08,0x03,0x00,0x02},
+  0x67,
+  {0x2d,0x27,0x28,0x90,0x2b,0xb1,0xbf,0x1f,    /* b1 is a0 on 300 */
+   0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
+   0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3,
+   0xff},
+  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+   0x0c,0x00,0x0f,0x08},
+  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+   0xff}
+ },
+/* 0x18: MD_2_3_400 - mode 0x03 - 2 */
+ {
+  0x50,0x18,0x10,0x1000,
+  {0x00,0x03,0x00,0x02},
+  0x67,
+  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+   0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
+   0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
+   0xff},
+  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+   0x0c,0x00,0x0f,0x08},
+  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+   0xff}
+ },
+/* 0x19: MD_7_400 */
+ {
+  0x50,0x18,0x10,0x1000,
+  {0x00,0x03,0x00,0x02},
+  0x66,
+  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+   0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
+   0x9c,0x8e,0x8f,0x28,0x0f,0x96,0xb9,0xa3,
+   0xff},
+  {0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+   0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+   0x0e,0x00,0x0f,0x08},
+  {0x00,0x00,0x00,0x00,0x00,0x10,0x0a,0x00,
+   0xff}
+ },
+/* 0x1a: MD_11 */
+ {
+  0x50,0x1d,0x10,0xa000,
+  {0x01,0x0f,0x00,0x06},
+  0xe3,
+  {0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e,    /* 55,81 is 54,80 on 300 */
+   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+   0xe9,0x8b,0xdf,0x28,0x00,0xe7,0x04,0xc3,    /* e9,8b is ea,8c on 300 */
+   0xff},
+  {0x00,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,
+   0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,
+   0x01,0x00,0x0f,0x00},
+  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x01,
+   0xff}
+ },
+/* 0x1b: ExtEGATable - Modes <= 0x02 */
+ {
+  0x50,0x1d,0x10,0xa000,
+  {0x01,0x0f,0x00,0x06},
+  0xe3,
+  {0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e,    /* 55,81 is 54,80 on 300 */
+   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+   0xe9,0x8b,0xdf,0x28,0x00,0xe7,0x04,0xe3,    /* e9,8b is ea,8c on 300 */
+   0xff},
+  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+   0x01,0x00,0x0f,0x00},
+  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
+   0xff}
+ },
+/* 0x1c: MD_13 */
+ {
+  0x28,0x18,0x08,0x2000,
+  {0x01,0x0f,0x00,0x0e},
+  0x63,
+  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,    /* 55,81 is 54,80 on 300 */
+   0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x9c,0x8e,0x8f,0x28,0x40,0x96,0xb9,0xa3,
+   0xff},
+  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+   0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+   0x41,0x00,0x0f,0x00},
+  {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
+   0xff}
+ }
+};
+#endif
+
+/**************************************************************/
+/* SIS VIDEO BRIDGE ----------------------------------------- */
+/**************************************************************/
+
+static const UCHAR SiS_SoftSetting  = 0x30;   /* RAM setting */
+
+static const UCHAR SiS_OutputSelect = 0x40;
+
+static const UCHAR SiS_NTSCTiming[] = {
+	0x17,0x1d,0x03,0x09,0x05,0x06,0x0c,0x0c,
+	0x94,0x49,0x01,0x0a,0x06,0x0d,0x04,0x0a,
+	0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x1b,
+	0x0c,0x50,0x00,0x97,0x00,0xda,0x4a,0x17,
+	0x7d,0x05,0x4b,0x00,0x00,0xe2,0x00,0x02,
+	0x03,0x0a,0x65,0x9d,0x08,0x92,0x8f,0x40,
+	0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x50,
+	0x00,0x40,0x44,0x00,0xdb,0x02,0x3b,0x00
+};
+
+static const UCHAR SiS_PALTiming[] = {
+	0x19,0x52,0x35,0x6e,0x04,0x38,0x3d,0x70,
+	0x94,0x49,0x01,0x12,0x06,0x3e,0x35,0x6d,
+	0x06,0x14,0x3e,0x35,0x6d,0x00,0x45,0x2b,
+	0x70,0x50,0x00,0x9b,0x00,0xd9,0x5d,0x17,
+	0x7d,0x05,0x45,0x00,0x00,0xe8,0x00,0x02,
+	0x0d,0x00,0x68,0xb0,0x0b,0x92,0x8f,0x40,
+	0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x63,
+	0x00,0x40,0x3e,0x00,0xe1,0x02,0x28,0x00
+};
+
+static const UCHAR SiS_HiTVExtTiming[] = {
+        0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x64,
+	0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d,
+	0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f,
+	0x64,0x90,0x33,0x8c,0x18,0x36,0x3e,0x13,
+	0x2a,0xde,0x2a,0x44,0x40,0x2a,0x44,0x40,
+	0x8e,0x8e,0x82,0x07,0x0b,0x92,0x0f,0x40,
+	0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x3d,
+	0x63,0x4f,0x27,0x00,0xfc,0xff,0x6a,0x00
+};
+
+static const UCHAR SiS_HiTVSt1Timing[] = {
+        0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x65,
+	0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d,
+	0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f,
+	0x65,0x90,0x7b,0xa8,0x03,0xf0,0x87,0x03,
+	0x11,0x15,0x11,0xcf,0x10,0x11,0xcf,0x10,
+	0x35,0x35,0x3b,0x69,0x1d,0x92,0x0f,0x40,
+	0x60,0x80,0x14,0x90,0x8c,0x60,0x04,0x86,
+	0xaf,0x5d,0x0e,0x00,0xfc,0xff,0x2d,0x00
+};
+
+static const UCHAR SiS_HiTVSt2Timing[] = {
+        0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x64,
+	0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d,
+	0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f,
+	0x64,0x90,0x33,0x8c,0x18,0x36,0x3e,0x13,
+	0x2a,0xde,0x2a,0x44,0x40,0x2a,0x44,0x40,
+	0x8e,0x8e,0x82,0x07,0x0b,0x92,0x0f,0x40,
+	0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x3d,
+	0x63,0x4f,0x27,0x00,0xfc,0xff,0x6a,0x00
+};
+
+#if 0
+static const UCHAR SiS_HiTVTextTiming[] = {
+        0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x65,
+	0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d,
+	0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f,
+	0x65,0x90,0xe7,0xbc,0x03,0x0c,0x97,0x03,
+	0x14,0x78,0x14,0x08,0x20,0x14,0x08,0x20,
+	0xc8,0xc8,0x3b,0xd2,0x26,0x92,0x0f,0x40,
+        0x60,0x80,0x14,0x90,0x8c,0x60,0x04,0x96,
+	0x72,0x5c,0x11,0x00,0xfc,0xff,0x32,0x00
+};
+#endif
+
+static const UCHAR SiS_HiTVGroup3Data[] = {
+        0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0x5f,
+	0x05,0x21,0xb2,0xb2,0x55,0x77,0x2a,0xa6,
+	0x25,0x2f,0x47,0xfa,0xc8,0xff,0x8e,0x20,
+	0x8c,0x6e,0x60,0x2e,0x58,0x48,0x72,0x44,
+	0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80,
+	0x4f,0x7f,0x03,0xa8,0x7d,0x20,0x1a,0xa9,
+	0x14,0x05,0x03,0x7e,0x64,0x31,0x14,0x75,
+	0x18,0x05,0x18,0x05,0x4c,0xa8,0x01
+};
+
+static const UCHAR SiS_HiTVGroup3Simu[] = {
+        0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0x95,
+	0xdb,0x20,0xb8,0xb8,0x55,0x47,0x2a,0xa6,
+	0x25,0x2f,0x47,0xfa,0xc8,0xff,0x8e,0x20,
+	0x8c,0x6e,0x60,0x15,0x26,0xd3,0xe4,0x11,
+	0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80,
+	0x67,0x36,0x01,0x47,0x0e,0x10,0xbe,0xb4,
+	0x01,0x05,0x03,0x7e,0x65,0x31,0x14,0x75,
+	0x18,0x05,0x18,0x05,0x4c,0xa8,0x01
+};
+
+#if 0
+static const UCHAR SiS_HiTVGroup3Text[] = {
+        0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0xa7,
+	0xf5,0x20,0xce,0xce,0x55,0x47,0x2a,0xa6,
+	0x25,0x2f,0x47,0xfa,0xc8,0xff,0x8e,0x20,
+	0x8c,0x6e,0x60,0x18,0x2c,0x0c,0x20,0x22,
+	0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80,
+	0x93,0x3c,0x01,0x50,0x2f,0x10,0xf4,0xca,
+	0x01,0x05,0x03,0x7e,0x65,0x31,0x14,0x75,
+	0x18,0x05,0x18,0x05,0x4c,0xa8,0x01
+};
+#endif
+
+static const UCHAR SiS_NTSCPhase[]    = {0x21,0xed,0xba,0x08};
+static const UCHAR SiS_PALPhase[]     = {0x2a,0x05,0xe3,0x00};
+static const UCHAR SiS_PALMPhase[]    = {0x21,0xE4,0x2E,0x9B};
+static const UCHAR SiS_PALNPhase[]    = {0x21,0xF4,0x3E,0xBA};
+static const UCHAR SiS_NTSCPhase2[]   = {0x21,0xF0,0x7B,0xD6};
+static const UCHAR SiS_PALPhase2[]    = {0x2a,0x09,0x86,0xe9};
+static const UCHAR SiS_PALMPhase2[]   = {0x21,0xE6,0xEF,0xA4};
+static const UCHAR SiS_PALNPhase2[]   = {0x21,0xF6,0x94,0x46};
+static const UCHAR SiS_SpecialPhase[] = {0x1e,0x8c,0x5c,0x7a};
+static const UCHAR SiS_SpecialPhaseM[]= {0x1e,0x83,0x0a,0xe0};
+static const UCHAR SiS_SpecialPhaseJ[]= {0x25,0xd4,0xfd,0x5e};
+
+static const SiS_TVDataStruct  SiS_StPALData[] =
+{
+ {    1,   1, 864, 525,1270, 400, 100,   0, 760,0xf4,0xff,0x1c,0x22},
+ {    1,   1, 864, 525,1270, 350, 100,   0, 760,0xf4,0xff,0x1c,0x22},
+ {    1,   1, 864, 525,1270, 400,   0,   0, 720,0xf1,0x04,0x1f,0x18},
+ {    1,   1, 864, 525,1270, 350,   0,   0, 720,0xf4,0x0b,0x1c,0x0a},
+ {    1,   1, 864, 525,1270, 480,  50,   0, 760,0xf4,0xff,0x1c,0x22},
+ {    1,   1, 864, 525,1270, 600,  50,   0,   0,0xf4,0xff,0x1c,0x22}
+};
+
+static const SiS_TVDataStruct  SiS_ExtPALData[] =
+{
+ {   27,  10, 848, 448,1270, 530,  50,   0,  50,0xf4,0xff,0x1c,0x22},  /* 640x400, 320x200 */
+ {  108,  35, 848, 398,1270, 530,  50,   0,  50,0xf4,0xff,0x1c,0x22},
+ {   12,   5, 954, 448,1270, 530,  50,   0,  50,0xf1,0x04,0x1f,0x18},
+ {    9,   4, 960, 463,1644, 438,  50,   0,  50,0xf4,0x0b,0x1c,0x0a},
+ {    9,   4, 848, 528,1270, 530,   0,   0,  50,0xf5,0xfb,0x1b,0x2a},  /* 640x480, 320x240 */
+/*{  36,  25,1060, 648,1316, 530, 438,   0, 438,0xeb,0x05,0x25,0x16},*//* 800x600, 400x300 */
+ {   36,  25,1060, 648,1270, 530, 438,   0, 438,0xeb,0x05,0x25,0x16},  /* 800x600, 400x300 - better */
+ {    3,   2,1080, 619,1270, 540, 438,   0, 438,0xf3,0x00,0x1d,0x20},  /* 720x576 */
+ {    1,   1,1170, 821,1270, 520, 686,   0, 686,0xF3,0x00,0x1D,0x20},  /* 1024x768 */
+ {    1,   1,1170, 821,1270, 520, 686,   0, 686,0xF3,0x00,0x1D,0x20},  /* 1024x768 (for NTSC equ) */
+ {    9,   4, 848, 528,1270, 530,   0,   0,  50,0xf5,0xfb,0x1b,0x2a}   /* 720x480 test */
+};
+
+static const SiS_TVDataStruct  SiS_StNTSCData[] =
+{
+ {    1,   1, 858, 525,1270, 400,  50,   0, 760,0xf1,0x04,0x1f,0x18},
+ {    1,   1, 858, 525,1270, 350,  50,   0, 640,0xf1,0x04,0x1f,0x18},
+ {    1,   1, 858, 525,1270, 400,   0,   0, 720,0xf1,0x04,0x1f,0x18},
+ {    1,   1, 858, 525,1270, 350,   0,   0, 720,0xf4,0x0b,0x1c,0x0a},
+ {    1,   1, 858, 525,1270, 480,   0,   0, 760,0xf1,0x04,0x1f,0x18}
+};
+
+static const SiS_TVDataStruct  SiS_ExtNTSCData[] =
+{
+ {  143,  65, 858, 443,1270, 440, 171,   0, 171,0xf1,0x04,0x1f,0x18},    /* 640x400, 320x200 */
+ {   88,  35, 858, 393,1270, 440, 171,   0, 171,0xf1,0x04,0x1f,0x18},
+ {  143,  70, 924, 443,1270, 440,  92,   0,  92,0xf1,0x04,0x1f,0x18},
+ {  143,  70, 924, 393,1270, 440,  92,   0,  92,0xf4,0x0b,0x1c,0x0a},
+ {  143,  76, 836, 523,1270, 440, 224,   0,   0,0xf1,0x05,0x1f,0x16},    /* 640x480, 320x240 */
+ {  143, 120,1056, 643,1270, 440,   0, 128,   0,0xf4,0x10,0x1c,0x00},    /* 800x600, 400x300  */
+/*{   2,   1, 858, 503,1270, 480,   0, 128,   0,0xee,0x0c,0x22,0x08},*/  /* 720x480  (old, from 650) */
+ {  143,  76, 836, 523,1270, 440,   0, 128,   0,0xee,0x0c,0x22,0x08},    /* 720x480 - BETTER (from 300 series) */
+/*{  65,  64,1056, 791,1270, 480, 638,   0,   0,0xEE,0x0C,0x22,0x08} */  /* 1024x768 (525i) */
+ {    1,   1,1100, 811,1412, 440,   0, 128,   0,0xee,0x0c,0x22,0x08},    /* 1024x768 (525i) CORRECTED */
+ {   65,  64,1056, 791,1270, 480, 455,   0,   0,0x00,0x00,0x00,0x00}     /* 1024x768 (525p) */
+};
+
+static const SiS_TVDataStruct  SiS_StHiTVData[] =  /* Slave + TVSimu */
+{
+ {    1,   1, 0x37c,0x233,0x2b2,0x320,    0,  0, 0, 0x00,0x00,0x00,0x00},
+ {    1,   1, 0x37c,0x233,0x2b2,0x2bc,    0,  0, 0, 0x00,0x00,0x00,0x00},
+ {    1,   1, 0x37c,0x233,0x2b2,0x320,    0,  0, 0, 0x00,0x00,0x00,0x00},
+ {    1,   1, 0x37c,0x233,0x2b2,0x2bc,    0,  0, 0, 0x00,0x00,0x00,0x00},
+ {    1,   1, 0x37c,0x233,0x2b2,0x3c0,    0,  0, 0, 0x00,0x00,0x00,0x00},
+ {    8,   5, 0x41a,0x2ab,0x670,0x3c0,0x150,128, 0, 0x00,0x00,0x00,0x00}
+};
+
+static const SiS_TVDataStruct  SiS_St2HiTVData[] = /* Slave */
+{
+ {    3,   1, 0x348,0x1e3,0x670,0x3c0,0x032,  0, 0, 0x00,0x00,0x00,0x00},
+ {    1,   1, 0x37c,0x233,0x2b2,0x2bc, 	  0,  0, 0, 0x00,0x00,0x00,0x00},
+ {    3,   1, 0x348,0x1e3,0x670,0x3c0,0x032,  0, 0, 0x00,0x00,0x00,0x00},
+ {    1,   1, 0x37c,0x233,0x2b2,0x2bc,    0,  0, 0, 0x00,0x00,0x00,0x00},
+ {    5,   2, 0x348,0x233,0x670,0x3c0,0x08d,128, 0, 0x00,0x00,0x00,0x00},
+ {    8,   5, 0x41a,0x2ab,0x670,0x3c0,0x17c,128, 0, 0x00,0x00,0x00,0x00}
+};
+
+static const SiS_TVDataStruct  SiS_ExtHiTVData[] =
+{
+ {    6,   1, 0x348,0x233,0x660,0x3c0,    0,  0, 0, 0x00,0x00,0x00,0x00},
+ {    3,   1, 0x3c0,0x233,0x660,0x3c0,    0,  0, 0, 0x00,0x00,0x00,0x00},
+ {    6,   1, 0x348,0x233,0x660,0x3c0,    0,  0, 0, 0x00,0x00,0x00,0x00},
+ {    3,   1, 0x3c0,0x233,0x660,0x3c0,    0,  0, 0, 0x00,0x00,0x00,0x00},
+ {    5,   1, 0x348,0x233,0x670,0x3c0,0x166,128, 0, 0x00,0x00,0x00,0x00},  /* 640x480   */
+ {   16,   5, 0x41a,0x2ab,0x670,0x3c0,0x143,128, 0, 0x00,0x00,0x00,0x00},  /* 800x600   */
+ {   25,  12, 0x4ec,0x353,0x670,0x3c0,0x032,  0, 0, 0x00,0x00,0x00,0x00},  /* 1024x768  */
+ {    5,   4, 0x627,0x464,0x670,0x3c0,0x128,  0, 0, 0x00,0x00,0x00,0x00},  /* 1280x1024 */
+ {    4,   1, 0x41a,0x233,0x60c,0x3c0,0x143,128, 0, 0x00,0x00,0x00,0x00},  /* 800x480   */
+ {    5,   2, 0x578,0x293,0x670,0x3c0,0x032,  0, 0, 0x00,0x00,0x00,0x00},  /* 1024x576  */
+ {    8,   5, 0x6d6,0x323,0x670,0x3c0,0x128,  0, 0, 0x00,0x00,0x00,0x00},  /* 1280x720  */
+ {  137,  32, 0x3d4,0x233,0x663,0x3bf,0x143,  0, 0, 0x00,0x00,0x00,0x00}   /* 960x600  */
+};
+
+static const SiS_TVDataStruct  SiS_St525pData[] =
+{
+ {    1,   1, 0x6b4,0x20d,0x4f6,0x190,   50,  0, 0x2f8, 0x00,0x00,0x00,0x00},
+ {    1,   1, 0x6b4,0x20d,0x4f6,0x15e,   50,  0, 0x280, 0x00,0x00,0x00,0x00},
+ {    1,   1, 0x6b4,0x20d,0x4f6,0x190,   50,  0, 0x2f8, 0x00,0x00,0x00,0x00},
+ {    1,   1, 0x6b4,0x20d,0x4f6,0x15e,   50,  0, 0x280, 0x00,0x00,0x00,0x00},
+ {    1,   1, 0x6b4,0x20d,0x4f6,0x1e0,    0,  0, 0x2f8, 0x00,0x00,0x00,0x00}
+};
+
+static const SiS_TVDataStruct  SiS_St750pData[] =
+{
+ {    1,   1, 0x672,0x2ee,0x500,0x190,   50,  0, 0x2f8, 0x00,0x00,0x00,0x00},
+ {    1,   1, 0x672,0x2ee,0x500,0x15e,   50,  0, 0x280, 0x00,0x00,0x00,0x00},
+ {    1,   1, 0x672,0x2ee,0x500,0x190,    0,  0, 0x2d0, 0x00,0x00,0x00,0x00},
+ {    1,   1, 0x672,0x2ee,0x500,0x15e,    0,  0, 0x2d0, 0x00,0x00,0x00,0x00},
+ {    1,   1, 0x672,0x2ee,0x500,0x1e0,    0,  0, 0x2f8, 0x00,0x00,0x00,0x00}
+};
+
+static const SiS_TVDataStruct  SiS_Ext750pData[] =
+{
+ {  143,  65, 0x35a,0x1bb,0x4f6,0x1b8,0x0ab,  0, 0x0ab, 0x00,0x00,0x00,0x00},
+ {   88,  35, 0x35a,0x189,0x4f6,0x1b8,0x0ab,  0, 0x0ab, 0x00,0x00,0x00,0x00},
+ {   18,   5, 0x339,0x1ae,0x500,0x2d0,0x05c,  0, 0x05c, 0x00,0x00,0x00,0x00},
+ {  143,  70, 0x39c,0x189,0x4f6,0x1b8,0x05c,  0, 0x05c, 0x00,0x00,0x00,0x00},
+ {   99,  32, 0x320,0x1fe,0x500,0x2d0,   50,  0,     0, 0x00,0x00,0x00,0x00},  /* 640x480  */
+ {    5,   4, 0x5d8,0x29e,0x500,0x2a8,   50,  0,     0, 0x00,0x00,0x00,0x00},  /* 800x600  */
+ {   99,  32, 0x320,0x1fe,0x500,0x2d0,   50,  0,     0, 0x00,0x00,0x00,0x00},  /* 720x480 test WORKS */
+ {   68,  64, 0x55f,0x346,0x500,0x2a8,0x27e,  0,     0, 0x00,0x00,0x00,0x00},  /* 1024x768 */
+ {    5,   2, 0x3a7,0x226,0x500,0x2a8,    0,128,     0, 0x00,0x00,0x00,0x00},  /* 720x576  */
+ {   25,  24, 0x5d8,0x2f3,0x460,0x2a8,   50,  0,     0, 0x00,0x00,0x00,0x00}   /* 1280x720 WORKS */
+};
+
+static const SiS_LCDDataStruct  SiS_LCD1280x720Data[] =  /* 2.03.00 */
+{
+	{  44,   15,  864,  430, 1408,  806 }, /* 640x400 */
+	{ 128,   35,  792,  385, 1408,  806 },
+	{  44,   15,  864,  430, 1408,  806 },
+	{ 128,   35,  792,  385, 1408,  806 },
+	{  22,    9,  864,  516, 1408,  806 }, /* 640x480 */
+	{   8,    5, 1056,  655, 1408,  806 }, /* 800x600 */
+	{   0,    0,    0,    0,    0,    0 }, /* 1024x768 */
+	{   0,    0,    0,    0,    0,    0 }, /* 1280x1024 */
+	{   0,    0,    0,    0,    0,    0 },
+	{   0,    0,    0,    0,    0,    0 },
+	{   1,    1, 1408,  806, 1408,  806 }  /* 1280x720 */
+};
+
+/* About 1280x768: For TMDS, Panel_1280x768 will only be set if
+ * the panel is a Fujitsu 7911 (VL-17WDX8) (with clock 81, 1688x802)
+ * Other TMDS panels of this resolution will be treated as custom.
+ * For LVDS, we know another type (_2).
+ * (Note: 1280x768_3 is now special for SiS301/NetVista
+ */
+
+static const SiS_LCDDataStruct  SiS_StLCD1280x768_2Data[] = /* 2.03.00 */
+{
+	{  64,   21,  858,  434, 1408,  806 }, /* 640x400 */
+	{  32,    9,  858,  372, 1408,  806 },
+	{  64,   21,  858,  434, 1408,  806 },
+	{  32,    9,  858,  372, 1408,  806 },
+	{ 143,   68, 1024,  527, 1408,  806 }, /* 640x480 */
+	{  64,   51, 1364,  663, 1408,  806 }, /* 800x600 */
+	{  88,   81, 1296,  806, 1408,  806 }, /* 1024x768 */
+	{   0,    0,    0,    0,    0,    0 },
+	{   1,    1, 1408,  806, 1408,  806 }, /* 1280x768 */
+	{   0,    0,    0,    0,    0,    0 },
+	{  16,   15, 1600,  750, 1600,  806 }  /* 1280x720 - from Ext */
+};
+
+static const SiS_LCDDataStruct  SiS_ExtLCD1280x768_2Data[] = /* 2.03.00 */
+{
+	{  16,    5,  960,  410, 1600,  806 }, /* 640x400 */
+	{  64,   21, 1152,  364, 1600,  806 },
+	{  16,    5,  960,  410, 1600,  806 },
+	{  64,   21, 1152,  364, 1600,  806 },
+	{  32,   13, 1040,  493, 1600,  806 }, /* 640x480 */
+	{  16,    9, 1152,  618, 1600,  806 }, /* 800x600 */
+	{  25,   21, 1344,  796, 1600,  806 }, /* 1024x768 */
+	{   0,    0,    0,    0,    0,    0 },
+	{   1,    1, 1600,  806, 1600,  806 }, /* 1280x768 */
+	{   0,    0,    0,    0,    0,    0 },
+	{  16,   15, 1600,  750, 1600,  806 }  /* 1280x720 */
+};
+
+#if 0  /* Not used; _3 now reserved for NetVista (SiS301) */
+static const SiS_LCDDataStruct  SiS_LCD1280x768_3Data[] =
+{
+	{  64,   25, 1056,  422, 1664,  798 },			/* 640x400 */
+	{ 128,   39,  884,  396, 1408,  806 }, /* ,640 */
+	{  64,   25, 1056,  422, 1664,  798 },			/* 640x400 */
+	{ 128,   39,  884,  396, 1408,  806 }, /* ,640 */
+	{  32,   15, 1056,  513, 1408,  806 }, /* ,664 */	/* 640x480 */
+	{ 176,  125, 1280,  640, 1408,  806 }, /* ,768 */	/* 800x600 */
+	{  64,   61, 1342,  806, 1408,  806 },			/* 1024x768 */
+	{   0,    0,    0,    0,    0,    0 },
+	{   1,    1, 1408,  806, 1408,  806 },			/* 1280x768 */
+	{   0,    0,    0,    0,    0,    0 },
+	{  16,   15, 1600,  750, 1600,  806 }  /* 1280x720  from above */
+};
+#endif
+
+static const SiS_LCDDataStruct  SiS_LCD1280x800Data[] = /* 0.93.12a (TMDS) */
+{
+	{ 128,   51, 1122,  412, 1408,  816 },  /* 640x400 */
+	{ 128,   49, 1232,  361, 1408,  816 },
+	{ 128,   51, 1122,  412, 1408,  816 },
+	{ 128,   49, 1232,  361, 1408,  816 },
+	{   8,    3,  880,  491, 1408,  816 },  /* 640x480 */
+	{  11,    6, 1024,  612, 1408,  816 },  /* 800x600 */
+	{  22,   21, 1400,  784, 1408,  816 },  /* 1024x768 */
+	{   0,    0,    0,    0,    0,    0 },  /* 1280x1024 */
+	{   1,    1, 1408,  816, 1408,  816 },  /* 1280x800 */
+	{   0,    0,    0,    0,    0,    0 },  /* 1280x768 (patch index) */
+	{   0,    0,    0,    0,    0,    0 }   /* 1280x720 */
+};
+
+static const SiS_LCDDataStruct  SiS_LCD1280x800_2Data[] = /* 2.03.00 (LVDS) */
+{
+	{  97,   42, 1344,  409, 1552,  812 }, /* 640x400 */
+	{  97,   35, 1280,  358, 1552,  812 },
+	{  97,   42, 1344,  409, 1552,  812 },
+	{  97,   35, 1280,  358, 1552,  812 },
+	{  97,   39, 1040,  488, 1552,  812 }, /* 640x480 */
+	{ 194,  105, 1120,  608, 1552,  812 }, /* 800x600 */
+	{  97,   84, 1400,  780, 1552,  812 }, /* 1024x768 */
+	{   0,    0,    0,    0,    0,    0 }, /* 1280x1024 */
+	{   1,    1, 1552,  812, 1552,  812 }, /* 1280x800 */
+	{  97,   96, 1600,  780, 1552,  812 }, /* 1280x768 - patch index */
+	{  97,   90, 1600,  730, 1552,  812 }  /* 1280x720 */
+};
+
+static const SiS_LCDDataStruct  SiS_LCD1280x960Data[] =
+{
+	{    9,   2,  800,  500, 1800, 1000 },
+	{    9,   2,  800,  500, 1800, 1000 },
+	{    4,   1,  900,  500, 1800, 1000 },
+	{    4,   1,  900,  500, 1800, 1000 },
+	{    9,   2,  800,  500, 1800, 1000 },
+	{   30,  11, 1056,  625, 1800, 1000 },
+	{    5,   3, 1350,  800, 1800, 1000 },
+	{    1,   1, 1576, 1050, 1576, 1050 },
+	{    1,   1, 1800, 1000, 1800, 1000 }
+};
+
+static const SiS_LCDDataStruct  SiS_StLCD1400x1050Data[] =
+{
+	{ 211,  100, 2100,  408, 1688, 1066 },
+	{ 211,   64, 1536,  358, 1688, 1066 },
+	{ 211,  100, 2100,  408, 1688, 1066 },
+	{ 211,   64, 1536,  358, 1688, 1066 },
+	{ 211,   48,  840,  488, 1688, 1066 },
+	{ 211,   72, 1008,  609, 1688, 1066 },
+	{ 211,  128, 1400,  776, 1688, 1066 },
+	{ 211,  205, 1680, 1041, 1688, 1066 },
+	{   1,    1, 1688, 1066, 1688, 1066 }
+};
+
+static const SiS_LCDDataStruct  SiS_ExtLCD1400x1050Data[] =
+{
+/*	{ 211,   60, 1260,  410, 1688, 1066 },    640x400 (6330) */
+	{ 211,  100, 2100,  408, 1688, 1066 }, /* 640x400 (6325) WORKS */
+	{ 211,   64, 1536,  358, 1688, 1066 },
+	{ 211,  100, 2100,  408, 1688, 1066 },
+	{ 211,   64, 1536,  358, 1688, 1066 },
+/*	{ 211,   80, 1400,  490, 1688, 1066 },    640x480 (6330) */
+	{ 211,   48,  840,  488, 1688, 1066 }, /* 640x480 (6325) WORKS */
+/*	{ 211,  117, 1638,  613, 1688, 1066 },    800x600 (6330) */
+	{ 211,   72, 1008,  609, 1688, 1066 }, /* 800x600 (6325) WORKS */
+	{ 211,  128, 1400,  776, 1688, 1066 }, /* 1024x768 */
+	{ 211,  205, 1680, 1041, 1688, 1066 }, /* 1280x1024 - not used (always unscaled) */
+	{   1,    1, 1688, 1066, 1688, 1066 }, /* 1400x1050 */
+	{   0,    0,    0,    0,    0,    0 }, /* kludge */
+	{ 211,  120, 1400,  730, 1688, 1066 }  /* 1280x720 */
+};
+
+static const SiS_LCDDataStruct  SiS_LCD1680x1050Data[] =
+{
+	{  95,   24, 1260,  410, 1900, 1066 }, /*  0 640x400 */
+	{  10,    3, 1710,  362, 1900, 1066 },
+	{  95,   24, 1260,  410, 1900, 1066 },
+	{  10,    3, 1710,  362, 1900, 1066 },
+	{  95,   32, 1400,  490, 1900, 1066 }, /*  4 640x480 */
+	{  95,   42, 1470,  610, 1900, 1066 }, /*  5 800x600 */
+	{  95,   64, 1750,  784, 1900, 1066 }, /*  6 1024x768 */
+	{  95,   94, 1900, 1055, 1900, 1066 }, /*  7 1280x1024 */
+	{  41,   31, 1900,  806, 1900, 1066 }, /*  8 1280x768 */
+	{  95,   69, 1800,  817, 1900, 1066 }, /*  9 1280x800 patch index */
+	{  13,    9, 1900,  739, 1900, 1066 }, /* 10 1280x720 */
+	{  95,   94, 1880, 1066, 1900, 1066 }, /* 11 1400x1050 patch index */
+	{   1,    1, 1900, 1066, 1900, 1066 }  /* 12 1680x1050 */
+};
+
+static const SiS_LCDDataStruct  SiS_StLCD1600x1200Data[] =
+{
+	{27,  4, 800, 500, 2160, 1250 },
+	{27,  4, 800, 500, 2160, 1250 },
+	{ 6,  1, 900, 500, 2160, 1250 },
+	{ 6,  1, 900, 500, 2160, 1250 },
+	{27,  1, 800, 500, 2160, 1250 },
+	{ 4,  1,1080, 625, 2160, 1250 },
+	{ 5,  2,1350, 800, 2160, 1250 },
+	{135,88,1600,1100, 2160, 1250 },
+	{72, 49,1680,1092, 2160, 1250 },
+	{ 1,  1,2160,1250, 2160, 1250 }
+};
+
+static const SiS_LCDDataStruct  SiS_ExtLCD1600x1200Data[] =
+{
+	{72,11, 990, 422, 2160, 1250 }, /* 640x400 (6330) WORKS */
+/*	{27, 4, 800, 500, 2160, 1250 },    640x400 (6235) */
+	{27, 4, 800, 500, 2160, 1250 },
+	{ 6, 1, 900, 500, 2160, 1250 },
+	{ 6, 1, 900, 500, 2160, 1250 },
+	{45, 8, 960, 505, 2160, 1250 }, /* 640x480 (6330) WORKS */
+/*	{27, 1, 800, 500, 2160, 1250 },    640x480 (6325) */
+	{ 4, 1,1080, 625, 2160, 1250 },
+	{ 5, 2,1350, 800, 2160, 1250 },
+	{27,16,1500,1064, 2160, 1250 }, /* 1280x1024 */
+	{72,49,1680,1092, 2160, 1250 }, /* 1400x1050 (6330, was not supported on 6325) */
+	{ 1, 1,2160,1250, 2160, 1250 }
+};
+
+static const SiS_LCDDataStruct  SiS_NoScaleData[] =
+{
+	{ 1, 1, 800, 449, 800, 449 },  /* 0x00: 320x200, 640x400 */
+	{ 1, 1, 800, 449, 800, 449 },
+	{ 1, 1, 900, 449, 900, 449 },
+	{ 1, 1, 900, 449, 900, 449 },
+	{ 1, 1, 800, 525, 800, 525 },  /* 0x04: 320x240, 640x480  */
+	{ 1, 1,1056, 628,1056, 628 },  /* 0x05: 400x300, 800x600  */
+	{ 1, 1,1344, 806,1344, 806 },  /* 0x06: 512x384, 1024x768 */
+	{ 1, 1,1688,1066,1688,1066 },  /* 0x07: 1280x1024 */
+        { 1, 1,1688, 802,1688, 802 },  /* 0x08: 1280x768: Fujitsu, TMDS only */
+        { 1, 1,2160,1250,2160,1250 },  /* 0x09: 1600x1200 */
+	{ 1, 1,1800,1000,1800,1000 },  /* 0x0a: 1280x960  */
+	{ 1, 1,1688,1066,1688,1066 },  /* 0x0b: 1400x1050 */
+	{ 1, 1,1650, 750,1650, 750 },  /* 0x0c: 1280x720 (TMDS, projector)  */
+	{ 1, 1,1552, 812,1552, 812 },  /* 0x0d: 1280x800_2 (LVDS) (was: 1408,816/ 1656,841) */
+	{ 1, 1,1900,1066,1900,1066 },  /* 0x0e: 1680x1050 (LVDS) */
+	{ 1, 1,1660, 806,1660, 806 },  /* 0x0f: 1280x768_2 (LVDS) */
+	{ 1, 1,1664, 798,1664, 798 },  /* 0x10: 1280x768_3 (NetVista SiS 301) - TODO */
+	{ 1, 1,1688, 802,1688, 802 },  /* 0x11: 1280x768   (TMDS Fujitsu) */
+	{ 1, 1,1408, 806,1408, 806 },  /* 0x12: 1280x720 (LVDS) */
+	{ 1, 1, 896, 497, 896, 497 },  /* 0x13: 720x480 */
+	{ 1, 1, 912, 597, 912, 597 },  /* 0x14: 720x576 */
+	{ 1, 1, 912, 597, 912, 597 },  /* 0x15: 768x576 */
+	{ 1, 1,1056, 497,1056, 497 },  /* 0x16: 848x480 */
+	{ 1, 1,1064, 497,1064, 497 },  /* 0x17: 856x480 */
+	{ 1, 1,1056, 497,1056, 497 },  /* 0x18: 800x480 */
+	{ 1, 1,1328, 739,1328, 739 },  /* 0x19: 1024x576 */
+	{ 1, 1,1680, 892,1680, 892 },  /* 0x1a: 1152x864 */
+	{ 1, 1,1808, 808,1808, 808 },  /* 0x1b: 1360x768 */
+	{ 1, 1,1104, 563,1104, 563 },  /* 0x1c: 960x540 */
+	{ 1, 1,1120, 618,1120, 618 },  /* 0x1d: 960x600 */
+	{ 1, 1,1408, 816,1408, 816 }   /* 0x1f: 1280x800 (TMDS special) */
+};
+
+/**************************************************************/
+/* LVDS ----------------------------------------------------- */
+/**************************************************************/
+
+static const SiS_LVDSDataStruct  SiS_LVDS320x480Data_1[]=
+{
+	{ 848, 433, 400, 525},
+	{ 848, 389, 400, 525},
+	{ 848, 433, 400, 525},
+	{ 848, 389, 400, 525},
+	{ 848, 518, 400, 525},
+	{1056, 628, 400, 525},
+	{ 400, 525, 400, 525},
+	{ 800, 449,1000, 644},
+	{ 800, 525,1000, 635}
+};
+
+static const SiS_LVDSDataStruct  SiS_LVDS640x480Data_1[]=
+{
+	{ 800, 445, 800, 525},   /* 800, 449, 800, 449 */
+	{ 800, 395, 800, 525},
+	{ 800, 445, 800, 525},
+	{ 800, 395, 800, 525},
+	{ 800, 525, 800, 525},
+	{ 800, 525, 800, 525},   /* pseudo */
+	{ 800, 525, 800, 525}    /* pseudo */
+};
+
+/* FSTN 320x240 */
+static const SiS_LVDSDataStruct  SiS_LVDS640x480Data_2[]=
+{
+	{ 800, 445, 800, 525},
+	{ 800, 395, 800, 525},
+	{ 800, 445, 800, 525},
+	{ 800, 395, 800, 525},
+	{ 800, 525, 800, 525},
+        { 800, 525, 800, 525},   /* pseudo */
+	{ 800, 525, 800, 525}    /* pseudo */
+};
+
+static const SiS_LVDSDataStruct  SiS_LVDS800x600Data_1[]=
+{
+	{ 848, 433,1060, 629},
+	{ 848, 389,1060, 629},
+	{ 848, 433,1060, 629},
+	{ 848, 389,1060, 629},
+	{ 848, 518,1060, 629},
+	{1056, 628,1056, 628},
+	{1056, 628,1056, 628}
+};
+
+static const SiS_LVDSDataStruct  SiS_LVDS800x600Data_2[]=
+{
+	{1056, 628,1056, 628}
+};
+
+static const SiS_LVDSDataStruct  SiS_LVDS1024x768Data_1[]=
+{
+	{ 840, 438,1344, 806},
+	{ 840, 409,1344, 806},
+	{ 840, 438,1344, 806},
+	{ 840, 409,1344, 806},
+	{ 840, 518,1344, 806},   /* 640x480 */
+	{1050, 638,1344, 806},   /* 800x600 */
+	{1344, 806,1344, 806},   /* 1024x768 */
+};
+
+static const SiS_LVDSDataStruct  SiS_LVDS1024x768Data_2[]=
+{
+	{1344, 806,1344, 806}
+};
+
+static const SiS_LVDSDataStruct  SiS_LVDS1280x1024Data_1[]=
+{
+	{1048, 442,1688,1066},
+	{1048, 392,1688,1066},
+	{1048, 442,1688,1066},
+	{1048, 392,1688,1066},
+	{1048, 522,1688,1066},
+	{1208, 642,1688,1066},
+	{1432, 810,1688,1066},
+	{1688,1066,1688,1066}
+};
+
+static const SiS_LVDSDataStruct  SiS_LVDS1280x1024Data_2[]=
+{
+	{1688,1066,1688,1066}
+};
+
+static const SiS_LVDSDataStruct  SiS_LVDS1400x1050Data_1[]=
+{
+        { 928, 416, 1688,1066},
+	{ 928, 366, 1688,1066},
+	{ 928, 416, 1688,1066},
+	{ 928, 366, 1688,1066},
+	{ 928, 496, 1688,1066},
+	{1088, 616, 1688,1066},
+	{1312, 784, 1688,1066},
+	{1568,1040, 1688,1066},
+	{1688,1066, 1688,1066}
+};
+
+static const SiS_LVDSDataStruct  SiS_LVDS1400x1050Data_2[]=
+{
+        {1688,1066, 1688,1066}
+};
+
+static const SiS_LVDSDataStruct  SiS_LVDS1600x1200Data_1[]=
+{
+   	{1088, 520, 2048,1320},
+	{1088, 470, 2048,1320},
+	{1088, 520, 2048,1320},
+	{1088, 470, 2048,1320},
+	{1088, 600, 2048,1320},
+	{1248, 720, 2048,1320},
+	{1472, 888, 2048,1320},
+	{1728,1144, 2048,1320},
+	{1848,1170, 2048,1320},
+	{2048,1320, 2048,1320}
+};
+
+static const SiS_LVDSDataStruct  SiS_LVDS1600x1200Data_2[]=
+{
+        {2048,1320, 2048,1320}
+};
+
+static const SiS_LVDSDataStruct  SiS_LVDS1280x960Data_1[]=
+{
+	{ 840, 438,1344, 806},
+	{ 840, 409,1344, 806},
+	{ 840, 438,1344, 806},
+	{ 840, 409,1344, 806},
+	{ 840, 518,1344, 806},
+	{1050, 638,1344, 806},
+	{1344, 806,1344, 806},
+	{ 800, 449,1280, 801},
+	{ 800, 525,1280, 813}
+};
+
+static const SiS_LVDSDataStruct  SiS_LVDS1280x960Data_2[]=
+{
+	{1344, 806,1344, 806}
+};
+
+static const SiS_LVDSDataStruct  SiS_LVDS1280x768Data_1[]=
+{
+	{ 768, 438, 1408, 806},
+	{ 768, 388, 1408, 806},
+	{ 768, 438, 1408, 806},
+	{ 768, 388, 1408, 806},
+	{ 768, 518, 1408, 806},
+	{ 928, 638, 1408, 806},
+	{1152, 806, 1408, 806},
+	{1408, 806, 1408, 806},
+	{1408, 806, 1408, 806}
+};
+
+static const SiS_LVDSDataStruct  SiS_LVDS1280x768Data_2[]=
+{
+	{1408, 806, 1408, 806}
+};
+
+static const SiS_LVDSDataStruct  SiS_LVDS1024x600Data_1[] =
+{
+	{ 840, 604,1344, 800},
+	{ 840, 560,1344, 800},
+	{ 840, 604,1344, 800},
+	{ 840, 560,1344, 800},
+	{ 840, 689,1344, 800},
+	{1050, 800,1344, 800},
+	{1344, 800,1344, 800}
+};
+
+static const SiS_LVDSDataStruct  SiS_LVDS1024x600Data_2[] =
+{
+	{1344, 800,1344, 800}
+};
+
+static const SiS_LVDSDataStruct  SiS_LVDS1152x768Data_1[] =
+{
+	{ 840, 438,1344, 806},
+	{ 840, 409,1344, 806},
+	{ 840, 438,1344, 806},
+	{ 840, 409,1344, 806},
+	{ 840, 518,1344, 806},
+	{1050, 638,1344, 806},
+	{1344, 806,1344, 806}
+};
+
+static const SiS_LVDSDataStruct  SiS_LVDS1152x768Data_2[] =
+{
+	{1344, 806,1344, 806}
+};
+
+/* Pass 1:1 data */
+static const SiS_LVDSDataStruct  SiS_LVDSXXXxXXXData_1[]=
+{
+        { 800, 449,  800, 449},
+	{ 800, 449,  800, 449},
+	{ 900, 449,  900, 449},
+	{ 900, 449,  900, 449},
+	{ 800, 525,  800, 525},  /*  640x480  */
+	{1056, 628, 1056, 628},  /*  800x600  */
+	{1344, 806, 1344, 806},  /* 1024x768  */
+	{1688,1066, 1688,1066},  /* 1280x1024 */  /* INSERTED */
+ 	{1688, 806, 1688, 806},  /* 1280x768  */
+};
+
+/* Custom data for Barco iQ R series */
+static const SiS_LVDSDataStruct  SiS_LVDSBARCO1366Data_1[]=
+{
+	{ 832, 438,1331, 806},
+	{ 832, 388,1331, 806},
+	{ 832, 438,1331, 806},
+	{ 832, 388,1331, 806},
+	{ 832, 518,1331, 806},
+	{1050, 638,1344, 806},
+	{1344, 806,1344, 806},
+	{1688,1066,1688,1066},
+	{1688,1066,1688,1066}   /* 1360x1024 */
+};
+
+/* Custom data for Barco iQ R series */
+static const SiS_LVDSDataStruct  SiS_LVDSBARCO1366Data_2[]=
+{
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1688,1066,1688,1066},
+	{1688,1066,1688,1066}   /* 1360x1024 */
+};
+
+/* Custom data for Barco iQ G series */
+static const SiS_LVDSDataStruct  SiS_LVDSBARCO1024Data_1[]=
+{
+	{ 832, 438,1331, 806},
+	{ 832, 409,1331, 806},
+	{ 832, 438,1331, 806},
+	{ 832, 409,1331, 806},
+	{ 832, 518,1331, 806},   /* 640x480 */
+	{1050, 638,1344, 806},   /* 800x600 */
+	{1344, 806,1344, 806},   /* 1024x768 */
+};
+
+/* Custom data for Barco iQ G series */
+static const SiS_LVDSDataStruct  SiS_LVDSBARCO1024Data_2[]=
+{
+	{1344, 806,1344, 806}
+};
+
+/* Custom data for 848x480 parallel panel */
+static const SiS_LVDSDataStruct  SiS_LVDS848x480Data_1[]=
+{
+	{   0,   0,   0,   0},
+	{   0,   0,   0,   0},
+	{   0,   0,   0,   0},
+	{   0,   0,   0,   0},
+	{1088, 525,1088, 525},  /* 640x480 TODO */
+	{1088, 525,1088, 525},  /* 800x600 TODO */
+	{1088, 525,1088, 525},  /* 1024x768 TODO */
+	{   0,   0,   0,   0},
+	{   0,   0,   0,   0},
+	{   0,   0,   0,   0},
+	{   0,   0,   0,   0},
+	{1088, 525,1088, 525},  /* 848x480 */
+	{1088, 525,1088, 525}   /* 1360x768 TODO */
+};
+
+/* Custom data for 848x480 parallel panel */
+static const SiS_LVDSDataStruct  SiS_LVDS848x480Data_2[]=
+{
+	{   0,   0,   0,   0},
+	{   0,   0,   0,   0},
+	{   0,   0,   0,   0},
+	{   0,   0,   0,   0},
+	{1088, 525,1088, 525},  /*  640x480 */
+	{1088, 525,1088, 525},  /*  800x600 */
+	{1088, 525,1088, 525},  /* 1024x768 */
+	{   0,   0,   0,   0},
+	{   0,   0,   0,   0},
+	{   0,   0,   0,   0},
+	{   0,   0,   0,   0},
+	{1088, 525,1088, 525},  /* 848x480 */
+	{1088, 525,1088, 525}	/* 1360x768 TODO */
+};
+
+static const SiS_LVDSDataStruct  SiS_CHTVUNTSCData[]=
+{
+	{ 840, 600, 840, 600},
+	{ 840, 600, 840, 600},
+	{ 840, 600, 840, 600},
+	{ 840, 600, 840, 600},
+	{ 784, 600, 784, 600},
+	{1064, 750,1064, 750},
+        {1160, 945,1160, 945}
+};
+
+static const SiS_LVDSDataStruct  SiS_CHTVONTSCData[]=
+{
+	{ 840, 525, 840, 525},
+	{ 840, 525, 840, 525},
+	{ 840, 525, 840, 525},
+	{ 840, 525, 840, 525},
+	{ 784, 525, 784, 525},
+	{1040, 700,1040, 700},
+        {1160, 840,1160, 840}
+};
+
+/* Chrontel TV Skew */
+
+static const SiS_LVDSDesStruct  SiS_CHTVUNTSCDesData[]=
+{
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS_CHTVONTSCDesData[]=
+{
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS_CHTVUPALDesData[]=
+{
+	{256,  0},
+	{256,  0},
+	{256,  0},
+	{256,  0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS_CHTVOPALDesData[]=
+{
+	{256,  0},
+	{256,  0},
+	{256,  0},
+	{256,  0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0}
+};
+
+/* CRT1 CRTC data for slave modes */
+
+static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT1320x480_1[] =
+{
+ {{0x65,0x4f,0x89,0x56,0x83,0xaa,0x1f,
+   0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
+   0x00 }},
+ {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f,
+   0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
+   0x00 }},
+ {{0x65,0x4f,0x89,0x54,0x9f,0xc4,0x1f,
+   0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+   0x00 }},
+ {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f,
+   0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
+   0x00 }},
+ {{0x65,0x4f,0x89,0x56,0x83,0x04,0x3e,
+   0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05,
+   0x00 }},
+ {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
+   0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
+   0x01 }},
+ {{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e,
+   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00,
+   0x00 }}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT1640x480_1[] =
+{
+ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
+   0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
+   0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
+   0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
+   0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
+   0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05,
+   0x00}},
+ {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
+   0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
+   0x01}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT1640x480_1_H[] =
+{
+ {{0x2d,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x00,0x00,0x00,
+   0x00}},
+ {{0x2d,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
+   0x83,0x85,0x63,0xba,0x00,0x00,0x00,
+   0x00}},
+ {{0x2d,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x00,0x00,0x00,
+   0x00}},
+ {{0x2d,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
+   0x83,0x85,0x63,0xba,0x00,0x00,0x00,
+   0x00}},
+ {{0x2d,0x28,0x90,0x2c,0x80,0x0b,0x3e,
+   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00,
+   0x00}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT1640x480_2[] =
+{
+ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
+   0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
+   0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
+   0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
+   0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
+   0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05,
+   0x00}},
+ {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
+   0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
+   0x01}},
+ {{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e,
+   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00,
+   0x00}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT1640x480_2_H[] =
+{
+ {{0x65,0x4f,0x89,0x56,0x83,0xaa,0x1f,
+   0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
+   0x00}},
+ {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f,
+   0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
+   0x00}},
+ {{0x65,0x4f,0x89,0x54,0x9f,0xc4,0x1f,
+   0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+   0x00}},
+ {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f,
+   0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
+   0x00}},
+ {{0x65,0x4f,0x89,0x56,0x83,0x04,0x3e,
+   0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05,
+   0x00}},
+ {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
+   0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
+   0x01}},
+ {{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e,
+   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00,
+   0x00}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT1640x480_3[] =
+{
+ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
+   0xe9,0x8b,0xdf,0x04,0x00,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
+   0xe9,0x8b,0xdf,0x04,0x00,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
+   0xe9,0x8b,0xdf,0x04,0x00,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
+   0xe9,0x8b,0xdf,0x04,0x00,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
+   0xe9,0x8b,0xdf,0x04,0x00,0x00,0x05,
+   0x00}},
+ {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
+   0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
+   0x01}},
+ {{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e,
+   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00,
+   0x00}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT1640x480_3_H[] =
+{
+ {{0x65,0x4f,0x89,0x56,0x83,0xaa,0x1f,
+   0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
+   0x00}},
+ {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f,
+   0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
+   0x00}},
+ {{0x65,0x4f,0x89,0x54,0x9f,0xc4,0x1f,
+   0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+   0x00}},
+ {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f,
+   0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
+   0x00}},
+ {{0x65,0x4f,0x89,0x56,0x83,0x04,0x3e,
+   0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05,
+   0x00}},
+ {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
+   0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
+   0x01}},
+ {{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e,
+   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00,
+   0x00}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT11024x600_1[] =
+{
+ {{0x64,0x4f,0x88,0x54,0x9f,0x5a,0x3e,
+   0xe8,0x8f,0x8f,0x5b,0x00,0x00,0x01,
+   0x00}},
+ {{0x64,0x4f,0x88,0x54,0x9f,0x2e,0x3e,
+   0xb9,0x80,0x5d,0x2f,0x00,0x00,0x01,
+   0x00}},
+ {{0x64,0x4f,0x88,0x54,0x9f,0x5a,0x3e,
+   0xe8,0x8f,0x8f,0x5b,0x00,0x00,0x01,
+   0x00}},
+ {{0x64,0x4f,0x88,0x54,0x9f,0x2e,0x3e,
+   0xb9,0x80,0x5d,0x2f,0x00,0x00,0x01,
+   0x00}},
+ {{0x64,0x4f,0x88,0x54,0x9f,0xaf,0xba,
+   0x3b,0x82,0xdf,0xb0,0x00,0x00,0x01,
+   0x00}},
+ {{0x7e,0x63,0x82,0x68,0x15,0x1e,0xf1,
+   0xae,0x85,0x57,0x1f,0x30,0x00,0x26,
+   0x01}},
+ {{0xa3,0x7f,0x87,0x86,0x97,0x1e,0xf1,
+   0xae,0x85,0x57,0x1f,0x30,0x00,0x02,
+   0x01}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT11024x600_1_H[] =
+{
+ {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f,
+   0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+   0x00}},
+ {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f,
+   0x60,0x87,0x5d,0x83,0x10,0x00,0x44,
+   0x00}},
+ {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f,
+   0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+   0x00}},
+ {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f,
+   0x60,0x87,0x5d,0x83,0x10,0x00,0x44,
+   0x00}},
+ {{0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e,
+   0xe2,0x89,0xdf,0x05,0x00,0x00,0x44,
+   0x00}},
+ {{0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0,
+   0x5a,0x8f,0x57,0x7d,0x20,0x00,0x55,
+   0x01}},
+ {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+   0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+   0x01}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT11024x600_2[] =
+{
+ {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+   0x00}},
+ {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+   0x00}},
+ {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+   0x00}},
+ {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+   0x00}},
+ {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x72,0x88,0xdf,0x25,0x30,0x00,0x06,
+   0x00}},
+ {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1,
+   0xae,0x84,0x57,0x25,0x30,0x00,0x02,
+   0x01}},
+ {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
+   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+   0x01}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT11024x600_2_H[] =
+{
+ {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+   0x00}},
+ {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+   0x00}},
+ {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+   0x00}},
+ {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+   0x00}},
+ {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+   0x72,0x88,0xdf,0x25,0x30,0x00,0x01,
+   0x00}},
+ {{0x4f,0x31,0x93,0x3e,0x06,0x24,0xf1,
+   0xae,0x84,0x57,0x25,0x30,0x00,0x01,
+   0x01}},
+ {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+   0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+   0x01}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT11152x768_1[] =
+{
+ {{0x64,0x4f,0x88,0x54,0x9f,0xc4,0x1f,
+   0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+   0x00}},
+ {{0x64,0x4f,0x88,0x54,0x9f,0x97,0x1f,
+   0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
+   0x00}},
+ {{0x64,0x4f,0x88,0x54,0x9f,0xc4,0x1f,
+   0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+   0x00}},
+ {{0x64,0x4f,0x88,0x54,0x9f,0x97,0x1f,
+   0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
+   0x00}},
+ {{0x64,0x4f,0x88,0x54,0x9f,0x04,0x3e,
+   0xe2,0x89,0xdf,0x05,0x00,0x00,0x01,
+   0x00}},
+ {{0x7e,0x63,0x82,0x68,0x15,0x7c,0xf0,
+   0x5a,0x8f,0x57,0x7d,0x20,0x00,0x26,
+   0x01}},
+ {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
+   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+   0x01}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT11152x768_1_H[] =
+{
+ {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f,
+   0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+   0x00}},
+ {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f,
+   0x60,0x87,0x5d,0x83,0x10,0x00,0x44,
+   0x00}},
+ {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f,
+   0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+   0x00}},
+ {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f,
+   0x60,0x87,0x5d,0x83,0x10,0x00,0x44,
+   0x00}},
+ {{0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e,
+   0xe2,0x89,0xdf,0x05,0x00,0x00,0x44,
+   0x00}},
+ {{0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0,
+   0x5a,0x8f,0x57,0x7d,0x20,0x00,0x55,
+   0x01}},
+ {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+   0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+   0x01}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT11152x768_2[] =
+{
+ {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+   0x00}},
+ {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+   0x00}},
+ {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+   0x00}},
+ {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+   0x00}},
+ {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x72,0x88,0xdf,0x25,0x30,0x00,0x06,
+   0x00}},
+ {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1,
+   0xae,0x84,0x57,0x25,0x30,0x00,0x02,
+   0x01}},
+ {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
+   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+   0x01}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT11152x768_2_H[] =
+{
+ {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+   0x00}},
+ {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+   0x00}},
+ {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+   0x00}},
+ {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+   0x00}},
+ {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+   0x72,0x88,0xdf,0x25,0x30,0x00,0x01,
+   0x00}},
+ {{0x4f,0x31,0x93,0x3e,0x06,0x24,0xf1,
+   0xae,0x84,0x57,0x25,0x30,0x00,0x01,
+   0x01}},
+ {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+   0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+   0x01}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT11280x768_1[] =
+{
+ {{0x5b,0x4f,0x9f,0x55,0x19,0xb4,0x1f,
+   0x9c,0x8e,0x8f,0xb5,0x10,0x00,0x01,
+   0x00}},
+ {{0x5b,0x4f,0x9f,0x55,0x19,0x82,0x1f,
+   0x6a,0x8c,0x5d,0x83,0x30,0x00,0x01,
+   0x00}},
+ {{0x5b,0x4f,0x9f,0x55,0x19,0xb4,0x1f,
+   0x9c,0x8e,0x8f,0xb5,0x10,0x00,0x01,
+   0x00}},
+ {{0x5b,0x4f,0x9f,0x55,0x19,0x82,0x1f,
+   0x6a,0x8c,0x5d,0x83,0x30,0x00,0x01,
+   0x00}},
+ {{0x5b,0x4f,0x9f,0x55,0x19,0x04,0x3e,
+   0xec,0x8e,0xdf,0x05,0x20,0x00,0x01,
+   0x00}},
+ {{0x6f,0x63,0x93,0x69,0x8d,0x7c,0xf0,
+   0x64,0x86,0x57,0x7d,0x20,0x00,0x05,
+   0x01}},
+ {{0x8b,0x7f,0x8f,0x85,0x09,0x24,0xf5,
+   0x0c,0x8e,0xff,0x25,0x30,0x00,0x02,
+   0x01}},
+ {{0xab,0x9f,0x8f,0xa5,0x89,0x24,0xf5,
+   0x0c,0x8e,0xff,0x25,0x30,0x00,0x06,
+   0x01}},
+ {{0xab,0x9f,0x8f,0xa5,0x89,0x24,0xf5,
+   0x0c,0x8e,0xff,0x25,0x30,0x00,0x06,
+   0x01}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT11280x768_1_H[] =
+{
+ {{0x47,0x27,0x8b,0x2c,0x1a,0x9e,0x1f,
+   0x93,0x86,0x8f,0x9f,0x30,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f,
+   0x60,0x84,0x5d,0x6d,0x10,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x30,0x1e,0x9e,0x1f,
+   0x92,0x86,0x8f,0x9f,0x30,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f,
+   0x60,0x84,0x5d,0x6d,0x10,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x2c,0x1a,0xee,0x1f,
+   0xe2,0x86,0xdf,0xef,0x10,0x00,0x05,
+   0x00}},
+ {{0x51,0x31,0x95,0x36,0x04,0x66,0xf0,
+   0x5a,0x8e,0x57,0x67,0x20,0x00,0x01,
+   0x01}},
+ {{0x5f,0x3f,0x83,0x44,0x92,0x0e,0xf5,
+   0x02,0x86,0xff,0x0f,0x10,0x00,0x01,
+   0x01}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0x0e,0x5a,
+   0x02,0x86,0xff,0x0f,0x09,0x00,0x05,
+   0x01}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0x0e,0x5a,
+   0x02,0x86,0xff,0x0f,0x09,0x00,0x05,
+   0x01}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT11280x768_2[] =
+{
+ {{0xab,0x60,0x9f,0x80,0x04,0x24,0xbb,
+   0x54,0x86,0xdb,0xda,0x00,0x00,0x02,
+   0x00}},
+ {{0xab,0x60,0x9f,0x80,0x04,0x24,0xbb,
+   0x3b,0x8d,0xc2,0xc1,0x00,0x00,0x02,
+   0x00}},
+ {{0xab,0x60,0x9f,0x80,0x04,0x24,0xbb,
+   0x54,0x86,0xdb,0xda,0x00,0x00,0x02,
+   0x00}},
+ {{0xab,0x60,0x9f,0x80,0x04,0x24,0xbb,
+   0x3b,0x8d,0xc2,0xc1,0x00,0x00,0x02,
+   0x00}},
+ {{0xab,0x60,0x9f,0x80,0x04,0x24,0xb3,
+   0x7c,0x8e,0x03,0x02,0x10,0x00,0x02,
+   0x01}},
+ {{0xab,0x63,0x8f,0x8a,0x8e,0x24,0xf1,
+   0xb6,0x88,0x57,0x25,0x10,0x00,0x02,
+   0x01}},
+ {{0xab,0x7f,0x8f,0x98,0x9c,0x24,0xf5,
+   0x0a,0x8c,0xff,0x25,0x30,0x00,0x02,
+   0x01}},
+ {{0xab,0x9f,0x8f,0xa8,0x8c,0x24,0xf5,
+   0x0a,0x8c,0xff,0x25,0x30,0x00,0x06,
+   0x01}},
+ {{0xab,0x9f,0x8f,0xa8,0x8c,0x24,0xf5,
+   0x0a,0x8c,0xff,0x25,0x30,0x00,0x06,
+   0x01}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT11280x768_2_H[] =
+{
+ {{0x83,0x38,0x97,0x58,0x9c,0x24,0xbb,
+   0x54,0x86,0xdb,0xda,0x00,0x00,0x01,
+   0x00}},
+ {{0x83,0x38,0x97,0x58,0x9c,0x24,0xbb,
+   0x3b,0x8d,0xc2,0xc1,0x00,0x00,0x01,
+   0x00}},
+ {{0x83,0x38,0x97,0x58,0x9c,0x24,0xbb,
+   0x54,0x86,0xdb,0xda,0x00,0x00,0x01,
+   0x00}},
+ {{0x83,0x38,0x97,0x58,0x9c,0x24,0xbb,
+   0x3b,0x8d,0xc2,0xc1,0x00,0x00,0x01,
+   0x00}},
+ {{0x83,0x38,0x97,0x58,0x9c,0x24,0xb3,
+   0x7c,0x8e,0x03,0x02,0x10,0x00,0x01,
+   0x01}},
+ {{0x79,0x31,0x9d,0x58,0x9c,0x24,0xf1,
+   0xb6,0x88,0x57,0x25,0x10,0x00,0x01,
+   0x01}},
+ {{0x6b,0x3f,0x8f,0x58,0x9c,0x24,0xf5,
+   0x0a,0x8c,0xff,0x25,0x30,0x00,0x01,
+   0x01}},
+ {{0xab,0x9f,0x8f,0xa8,0x8c,0x24,0xf5,
+   0x0a,0x8c,0xff,0x25,0x30,0x00,0x06,
+   0x01}},
+ {{0xab,0x9f,0x8f,0xa8,0x8c,0x24,0xf5,
+   0x0a,0x8c,0xff,0x25,0x30,0x00,0x06,
+   0x01}}
+};
+
+/**************************************************************/
+/* COMMON --------------------------------------------------- */
+/**************************************************************/
+
+#ifdef LINUX_XF86
+
+#define SIS_PL_HSYNCP 0x01
+#define SIS_PL_HSYNCN 0x02
+#define SIS_PL_VSYNCP 0x04
+#define SIS_PL_VSYNCN 0x08
+#define SIS_PL_DVI    0x80
+
+typedef struct _SiS_PlasmaModes
+{
+  const char *name;
+  ULONG  clock;
+  USHORT HDisplay, HTotal, HFrontPorch, HSyncWidth;
+  USHORT VDisplay, VTotal, VFrontPorch, VSyncWidth;
+  UCHAR  SyncFlags;
+} SiS_PlasmaModes;
+
+typedef struct _SiS_PlasmaTables
+{
+   USHORT vendor;
+   UCHAR  productnum;
+   USHORT product[5];
+   const char *DDCnames[5];
+   const char *plasmaname;
+   USHORT maxx,maxy;
+   USHORT prefx, prefy;
+   UCHAR  modenum;
+   UCHAR  plasmamodes[20];  /* | 0x80 = DVI-capable, | 0x40 = analog */
+} SiS_PlasmaTables;
+
+static const SiS_PlasmaModes SiS_PlasmaMode[] = {
+   {  "640x400",		/* 00: IBM 400@70 */
+      25175,
+       640,  800, 17,  64,
+       400,  449, 13,   2,
+      SIS_PL_HSYNCN | SIS_PL_VSYNCN },
+   {  "640x480",		/* 01: VESA 480@72 */
+      31500,
+       640,  832, 24,  40,
+       480,  520,  9,   3,
+      SIS_PL_HSYNCN | SIS_PL_VSYNCN },
+   {  "800x600",		/* 02: VESA 600@72 */
+      50000,
+       800, 1040, 56, 120,
+       600,  666, 37,   6,
+      SIS_PL_HSYNCP | SIS_PL_VSYNCP },
+   {  "864x480",		/* 03: Cereb wide 1 */
+      42526,
+       864, 1134, 22,  86,
+       480,  500,  1,   3,
+      SIS_PL_HSYNCP | SIS_PL_VSYNCN },
+   {  "848x480",		/* 04: VESA wide (NEC1) */
+      33750,
+       848, 1088, 16, 112,
+       480,  517,  6,   8,
+      SIS_PL_HSYNCP | SIS_PL_VSYNCP },
+   {  "1024x576",		/* 05: VESA wide (NEC2) */
+      47250,
+      1024, 1320, 16, 144,
+       576,  596,  2,   4,
+      SIS_PL_HSYNCP | SIS_PL_VSYNCP },
+   {  "1280x720",		/* 06: VESA wide (NEC3) */
+      76500,
+      1280, 1696, 48, 176,
+       720,  750,  4,   8,
+      SIS_PL_HSYNCP | SIS_PL_VSYNCP },
+   {  "1360x765",		/* 07: VESA wide (NEC4) */
+      85500,
+      1360, 1792, 64, 176,
+       765,  795,  4,   8,
+      SIS_PL_HSYNCP | SIS_PL_VSYNCP },
+   {  "1024x600",		/* 08: CEREB wide 2 */
+      51200,
+      1024, 1352, 51, 164,
+       600,  628,  1,   4,
+      SIS_PL_HSYNCN | SIS_PL_VSYNCP },
+   {  "1024x768",		/* 09: VESA 768@75 */
+      78750,
+      1024, 1312,  16, 96,
+       768,  800,   1,  3,
+      SIS_PL_HSYNCP | SIS_PL_VSYNCP },
+   {  "1152x864",		/* 10: VESA 1152x864@75 */
+      108000,
+      1152, 1600, 64, 128,
+       864,  900,  1,   3,
+      SIS_PL_HSYNCP | SIS_PL_VSYNCP },
+   {  "1280x1024",		/* 11: VESA 1024@60 */
+      108000,
+      1280, 1688, 48, 112,
+      1024, 1066,  1,   3,
+      SIS_PL_HSYNCP | SIS_PL_VSYNCP },
+   {  "1280x768",		/* 12: W_XGA */
+      81000,
+      1280, 1688, 48, 112,
+       768,  802,  3,   6,
+      SIS_PL_HSYNCP | SIS_PL_VSYNCN },
+   {  "1280x768",		/* 13: I/O Data W_XGA@56Hz */
+      76064,
+      1280, 1688, 48, 112,
+       768,  802,  2,   3,
+      SIS_PL_HSYNCP | SIS_PL_VSYNCP },
+   {  "1376x768",		/* 14: I/O Wide XGA */
+      87340,
+      1376, 1808, 32, 128,
+       768,  806,  3,   6,
+      SIS_PL_HSYNCN | SIS_PL_VSYNCP },
+   {  "1280x960",		/* 15: VESA 960@60 */
+      108000,
+      1280, 1800, 96, 112,
+       960, 1000,  1,   3,
+      SIS_PL_HSYNCP | SIS_PL_VSYNCP },
+   {  "1400x1050",		/* 16: VESA 1050@60Hz */
+      108000,
+      1400, 1688, 48, 112,
+      1050, 1066,  1,   3,
+      SIS_PL_HSYNCN | SIS_PL_VSYNCN },
+   {  "1360x768",		/* 17: VESA wide (NEC4/2) */
+      85500,
+      1360, 1792, 64, 112,
+       765,  795,  3,   6,
+      SIS_PL_HSYNCP | SIS_PL_VSYNCP },
+   {  "800x600",		/* 18: VESA 600@56 */
+      36000,
+       800, 1024, 24,   2,
+       600,  625,  1,   2,
+      SIS_PL_HSYNCP | SIS_PL_VSYNCP },
+   {  "1072x600",		/* 19: Panasonic 1072x600 (sync?) */
+      54100,
+       1072, 1424, 48, 176,
+        600,  628, 16,   1,
+      SIS_PL_HSYNCP | SIS_PL_VSYNCP },
+   {  "848x480",		/* 20: Panasonic 848x480 (sync?) */
+      33070,			/* is 852x480, but we can't use 852 */
+        848, 1068, 20,  40,	/* differs from DDC data, better centered */
+        480,  516,  3,   5,	/* won't work assumingly, because data is % 8 */
+      SIS_PL_HSYNCN | SIS_PL_VSYNCN },
+   {  "1280x720",		/* 21: WIDE720(60) (aka "750p") (Panasonic) */
+      74300,
+      1280, 1650,110,  40,
+       720,  750,  5,   5,
+      SIS_PL_HSYNCP | SIS_PL_VSYNCP },
+   {  "1280x768",		/* 22: 1280x768@56.5 (Panasonic) */
+      76200,			/* (According to manual not supported for HDMI; but works) */
+      1280, 1680, 16,  24,
+       768,  802,  2,   5,
+      SIS_PL_HSYNCP | SIS_PL_VSYNCP },
+   {  "1280x720@50",		/* 23: WIDE720(50) (aka "750p") (Panasonic) */
+      74300,			/* Panasonic states 45.0kHz. Not possible. This one works (with some overscan) */
+      1280, 1980,400,  80,
+       720,  750,  1,   2,
+      SIS_PL_HSYNCP | SIS_PL_VSYNCP },
+   {  "720x480",		/* 24: 720x480 (aka "525p" and "480p") (Panasonic) */
+      27000,
+       720,  856, 40,  32,
+       480,  525,  1,   3,
+      SIS_PL_HSYNCP | SIS_PL_VSYNCP },
+   {  "720x576",		/* 25: 720x576 (aka "625p"and "576p") (Panasonic) */
+      27500,
+       720,  864, 16,  64,
+       576,  625,  5,   6,
+      SIS_PL_HSYNCP | SIS_PL_VSYNCP },
+   {  "1280x720@50",		/* 26: WIDE720(50) (aka "750p") (Generic) */
+      74300,
+      1280, 1980,400,  80,
+       720,  750,  5,   5,
+      SIS_PL_HSYNCP | SIS_PL_VSYNCP },
+};
+
+/*
+27.00  720 755 791 858  480 480 484 525
+27.50  720 732 795 864  576 581 587 625
+*/
+
+static const SiS_PlasmaTables SiS_PlasmaTable[] = {
+#if 0  /* Product IDs missing */
+   { 0x38a3, 4,
+     { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "", "", "", "", "" },
+     "NEC PlasmaSync 42VP4/42VP4D/42VP4G/42VP4DG",
+     0, 0,
+     0, 0,
+     11,   /* All DVI, except 0, 7, 13 */
+     { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 7|0x40, 9|0xc0,10|0xc0,11|0xc0,13|0x40,14|0xc0,
+      17|0xc0, 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0       }
+   },
+#endif
+#if 0  /* Product IDs missing */
+   { 0x38a3, 3,
+     { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "", "", "", "", "" },
+     "NEC PlasmaSync 42PD1/50PD1/50PD2",
+     0, 0,
+     0, 0,
+     5,   /* DVI entirely unknown */
+     { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 9|0xc0, 0     , 0     , 0     , 0     , 0     ,
+       0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0       }
+   },
+   { 0x38a3, 1,
+     { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "", "", "", "", "" },
+     "NEC PlasmaSync 42PD3",
+     0, 0,
+     0, 0,
+     10,   /* DVI entirely unknown */
+     { 0|0x40, 1|0xc0, 2|0xc0, 3|0xc0, 4|0xc0, 5|0xc0, 6|0xc0, 7|0x40, 8|0xc0, 9|0xc0,
+       0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0       }
+   },
+   { 0x38a3, 2,
+     { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "", "", "", "", "" },
+     "NEC PlasmaSync 42VM3/61XM1",
+     0, 0,
+     0, 0,
+     11,  /* DVI entirely unknown */
+     { 0|0x40, 1|0xc0, 2|0xc0, 3|0xc0, 4|0xc0, 5|0xc0, 6|0xc0, 8|0xc0, 9|0xc0,11|0xc0,
+      17|0xc0, 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0       }
+   },
+   { 0x38a3, 2,
+     { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "", "", "", "", "" },
+     "NEC PlasmaSync 42MP1/42MP2",
+     0, 0,
+     0, 0,
+     6,   /* DVI entirely unknown */
+     { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 9|0xc0,11|0xc0, 0     , 0     , 0     , 0     ,
+       0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0       }
+   },
+   { 0x38a3, 1,
+     { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "", "", "", "", "" },
+     "NEC PlasmaSync 50MP1",
+     0, 0,
+     0, 0,
+     10,   /* DVI entirely unknown */
+     { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 7|0x40, 9|0xc0,10|0xc0,11|0xc0,13|0x40,14|0xc0,
+       0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0       }
+   },
+#endif
+   { 0x38a3, 4,
+     { 0xa482, 0xa483, 0x0000, 0x0000, 0x0000 },
+     { "PX-42VM", "", "", "", "" },
+     "NEC PlasmaSync 42MP3/42MP4/50MP2/61MP1",
+     0, 0,
+     0, 0,
+     11,   /* All DVI except 0, 7, 13, 17 */
+     { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 7|0x40, 9|0xc0,10|0xc0,11|0xc0,13|0x40,14|0xc0,
+      17|0x40, 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0       }
+   },
+#if 0  /* Product IDs missing */
+   { 0x38a3, 1,
+     { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "", "", "", "", "" },
+     "NEC PlasmaSync 3300W",
+     0, 0,
+     0, 0,
+     3,
+     { 0|0x40, 1|0xc0,18|0xc0, 0     , 0     , 0     , 0     , 0     , 0     , 0     ,
+       0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0       }
+   },
+   { 0x38a3, 1,
+     { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "", "", "", "", "" },
+     "NEC PlasmaSync 4200W",
+     4,   /* DVI entirely unknown */
+     { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 0     , 0     , 0     , 0     , 0     , 0     ,
+       0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0       }
+   },
+   { 0x38a3, 1,
+     { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "", "", "", "", "" },
+     "NEC PlasmaSync 4210W",
+     0, 0,
+     0, 0,
+     6,   /* DVI entirely unknown */
+     { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 9|0xc0,11|0xc0, 0     , 0     , 0     , 0     ,
+       0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0       }
+   },
+   { 0x38a3, 1,
+     { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "", "", "", "", "" },
+     "NEC PlasmaSync 5000W",
+     0, 0,
+     0, 0,
+     7,   /* DVI entirely unknown */
+     { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 7|0x40, 9|0xc0,11|0xc0, 0     , 0     , 0     ,
+       0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0       }
+   },
+#endif
+   { 0x412f, 2,
+     { 0x000c, 0x000b, 0x0000, 0x0000, 0x0000 },
+     { "", "", "", "", "" },
+     "Pioneer 503CMX/PDA-5002",
+     0, 0,
+     0, 0,
+     6,   /* DVI unknown */
+     { 1|0xc0, 2|0xc0, 9|0xc0,11|0xc0,12|0xc0,15|0xc0, 0     , 0     , 0     , 0     ,
+       0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0       }
+   },
+   { 0x34a9, 1,
+     { 0xa00e, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "", "", "", "", "" },
+     "Panasonic TH-42",
+     0, 0,
+     0, 0,
+     5,   /* No DVI output */
+     { 1|0x40, 2|0x40, 4|0x40, 9|0x40,15|0x40, 0     , 0     , 0     , 0     , 0     ,
+       0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0       }
+   },
+   { 0x34a9, 1,
+     { 0xa005, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "TH-42PW*4", "", "", "", "" },
+     "Panasonic TH-42PW5",
+     0, 0,
+     0, 0,
+     1,   /* No special modes otherwise; no DVI. */
+     {20|0x40,19|0x40, 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     ,
+       0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0       }
+   },
+   { 0x4c2e, 1,
+     { 0x9b05, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "PLV-Z2", "", "", "", "" },
+     "Sanyo PLV-Z2 (non HDCP-mode)", 	/* HDCP mode would be id 9b06, but not needed */
+     1280, 768,				/* as it then advertises correct size */
+     1280, 720,
+     1,   /* 1280x720, no special modes otherwise */
+     {21|0xc0, 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     ,
+       0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0       }
+   },
+   { 0x34a9, 1,
+     { 0xd034, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "AE500U (DVI-D)", "", "", "", "" },
+     "Panasonic AE500U",
+     1280, 768,
+     1280, 720,
+     1,   /* 1280x720, no special modes otherwise */
+     {21|0xc0, 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     ,
+       0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0       }
+   },
+   { 0x34a9, 1,
+     { 0xd043, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "AE700U (HDMI)", "", "", "", "" },
+     "Panasonic AE700U",
+     1360, 768,
+     1280, 720,
+     6,   /* 1280x720/60, 1280x720/50, 1280x768@56(digital/analog), 720x480, 720x576 */
+     {21|0xc0,23|0xc0,22|0x80,13|0x40,24|0x80,25|0x80, 0     , 0     , 0     , 0     ,
+       0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0       }
+   },
+   { 0x0000 }
+};
+#endif
+
+#ifdef LINUX_XF86
+USHORT  SiS_GetModeID(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay,
+			  int Depth, BOOLEAN FSTN, int LCDwith, int LCDheight);
+#endif
+USHORT  SiS_GetModeID_LCD(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth, BOOLEAN FSTN,
+                          USHORT CustomT, int LCDwith, int LCDheight);
+USHORT  SiS_GetModeID_TV(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth);
+USHORT  SiS_GetModeID_VGA2(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth);
+
+void 	SiS_SetReg(SISIOADDRESS port, USHORT index, USHORT data);
+void 	SiS_SetRegByte(SISIOADDRESS port, USHORT data);
+void  	SiS_SetRegShort(SISIOADDRESS port, USHORT data);
+void	SiS_SetRegLong(SISIOADDRESS port, ULONG data);
+UCHAR	SiS_GetReg(SISIOADDRESS port, USHORT index);
+UCHAR 	SiS_GetRegByte(SISIOADDRESS port);
+USHORT	SiS_GetRegShort(SISIOADDRESS port);
+ULONG	SiS_GetRegLong(SISIOADDRESS port);
+void	SiS_SetRegANDOR(SISIOADDRESS Port, USHORT Index, USHORT DataAND, USHORT DataOR);
+void 	SiS_SetRegAND(SISIOADDRESS Port,USHORT Index, USHORT DataAND);
+void	SiS_SetRegOR(SISIOADDRESS Port,USHORT Index, USHORT DataOR);
+void	SiS_DisplayOn(SiS_Private *SiS_Pr);
+void	SiS_DisplayOff(SiS_Private *SiS_Pr);
+void	SiSRegInit(SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr);
+void	SiSSetLVDSetc(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
+BOOLEAN SiSDetermineROMLayout661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
+void	SiS_SetEnableDstn(SiS_Private *SiS_Pr, int enable);
+void	SiS_SetEnableFstn(SiS_Private *SiS_Pr, int enable);
+void	SiS_GetVBType(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
+BOOLEAN	SiS_SearchModeID(SiS_Private *SiS_Pr, USHORT *ModeNo, USHORT *ModeIdIndex);
+UCHAR	SiS_GetModePtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex);
+USHORT	SiS_GetColorDepth(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex);
+USHORT	SiS_GetOffset(SiS_Private *SiS_Pr,USHORT ModeNo, USHORT ModeIdIndex,
+              USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo);
+void	SiS_LoadDAC(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo, USHORT ModeIdIndex);
+void	SiS_CalcLCDACRT1Timing(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex);
+
+#ifdef LINUX_XF86
+BOOLEAN	SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,ScrnInfoPtr pScrn,USHORT ModeNo, BOOLEAN dosetpitch);
+BOOLEAN	SiSBIOSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn,
+               DisplayModePtr mode, BOOLEAN IsCustom);
+BOOLEAN	SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn,
+               DisplayModePtr mode, BOOLEAN IsCustom);
+BOOLEAN	SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn,
+               DisplayModePtr mode, BOOLEAN IsCustom);
+int	SiSTranslateToVESA(ScrnInfoPtr pScrn, int modenumber);
+int	SiSTranslateToOldMode(int modenumber);
+BOOLEAN	SiS_GetPanelID(SiS_Private *SiS_Pr, PSIS_HW_INFO);
+USHORT 	SiS_CheckBuildCustomMode(ScrnInfoPtr pScrn, DisplayModePtr mode, int VBFlags);
+DisplayModePtr SiSBuildBuiltInModeList(ScrnInfoPtr pScrn, BOOLEAN includelcdmodes, BOOLEAN isfordvi);
+int 	SiS_FindPanelFromDB(SISPtr pSiS, USHORT panelvendor, USHORT panelproduct, int *maxx, int *maxy, int *prefx, int *prefy);
+void    SiS_MakeClockRegs(ScrnInfoPtr pScrn, int clock, UCHAR *p2b, UCHAR *p2c);
+#else
+BOOLEAN	SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,USHORT ModeNo);
+#endif
+
+#ifdef LINUX_KERNEL
+int    	sisfb_mode_rate_to_dclock(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+			      UCHAR modeno, UCHAR rateindex);
+int    	sisfb_mode_rate_to_ddata(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+			UCHAR modeno, UCHAR rateindex,
+			struct fb_var_screeninfo *var);
+BOOLEAN sisfb_gettotalfrommode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+		       	UCHAR modeno, int *htotal, int *vtotal, UCHAR rateindex);
+#endif
+
+/* init301.c: */
+extern void     SiS_GetVBInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+			       	PSIS_HW_INFO HwInfo, int chkcrt2mode);
+extern void     SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+			       	PSIS_HW_INFO HwInfo);
+extern void     SiS_SetYPbPr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
+extern void 	SiS_SetTVMode(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, PSIS_HW_INFO HwInfo);
+extern void     SiS_UnLockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
+extern void     SiS_LockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
+extern void     SiS_DisableBridge(SiS_Private *, PSIS_HW_INFO);
+extern BOOLEAN  SiS_SetCRT2Group(SiS_Private *, PSIS_HW_INFO, USHORT);
+extern USHORT   SiS_GetRatePtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+                               	PSIS_HW_INFO HwInfo);
+extern void     SiS_WaitRetrace1(SiS_Private *SiS_Pr);
+extern USHORT   SiS_GetResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex);
+extern USHORT   SiS_GetCH700x(SiS_Private *SiS_Pr, USHORT tempax);
+extern USHORT   SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+                               	USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo);
+extern BOOLEAN  SiS_IsVAMode(SiS_Private *, PSIS_HW_INFO);
+extern BOOLEAN  SiS_IsDualEdge(SiS_Private *, PSIS_HW_INFO);
+
+#ifdef LINUX_XF86
+/* From other sis driver modules: */
+extern int      SiS_compute_vclk(int Clock, int *out_n, int *out_dn, int *out_div,
+	     	 	 	int *out_sbit, int *out_scale);
+extern void 	SiSCalcClock(ScrnInfoPtr pScrn, int clock, int max_VLD, unsigned int *vclk);
+
+extern UCHAR   	SiS_GetSetBIOSScratch(ScrnInfoPtr pScrn, USHORT offset, UCHAR value);
+extern UCHAR   	SiS_GetSetModeID(ScrnInfoPtr pScrn, UCHAR id);
+extern USHORT 	SiS_GetModeNumber(ScrnInfoPtr pScrn, DisplayModePtr mode, ULONG VBFlags);
+#endif
+
+#endif
+
diff --git a/drivers/video/sis/init301.c b/drivers/video/sis/init301.c
new file mode 100644
index 0000000..2bc5b80
--- /dev/null
+++ b/drivers/video/sis/init301.c
@@ -0,0 +1,12239 @@
+/* $XFree86$ */
+/* $XdotOrg$ */
+/*
+ * Mode initializing code (CRT2 section)
+ * for SiS 300/305/540/630/730 and
+ *     SiS 315/550/650/M650/651/661FX/M661xX/740/741(GX)/M741/330/660/M660/760/M760
+ * (Universal module for Linux kernel framebuffer and XFree86/X.org 4.x)
+ *
+ * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, the following license terms
+ * apply:
+ *
+ * * This program is free software; you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License as published by
+ * * the Free Software Foundation; either version 2 of the named License,
+ * * or any later version.
+ * *
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details.
+ * *
+ * * You should have received a copy of the GNU General Public License
+ * * along with this program; if not, write to the Free Software
+ * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * * Redistribution and use in source and binary forms, with or without
+ * * modification, are permitted provided that the following conditions
+ * * are met:
+ * * 1) Redistributions of source code must retain the above copyright
+ * *    notice, this list of conditions and the following disclaimer.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * *    notice, this list of conditions and the following disclaimer in the
+ * *    documentation and/or other materials provided with the distribution.
+ * * 3) The name of the author may not be used to endorse or promote products
+ * *    derived from this software without specific prior written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
+ * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ * Formerly based on non-functional code-fragements for 300 series by SiS, Inc.
+ * Used by permission.
+ *
+ * TW says: This code looks awful, I know. But please don't do anything about
+ * this otherwise debugging will be hell.
+ * The code is extremely fragile as regards the different chipsets, different
+ * video bridges and combinations thereof. If anything is changed, extreme
+ * care has to be taken that that change doesn't break it for other chipsets,
+ * bridges or combinations thereof.
+ * All comments in this file are by me, regardless if marked TW or not.
+ *
+ */
+
+#if 1
+#define SET_EMI		/* 302LV/ELV: Set EMI values */
+#endif
+
+#define COMPAL_HACK	/* Needed for Compal 1400x1050 (EMI) */
+#define COMPAQ_HACK	/* Needed for Inventec/Compaq 1280x1024 (EMI) */
+#define ASUS_HACK	/* Needed for Asus A2H 1024x768 (EMI) */
+
+#include "init301.h"
+
+#ifdef SIS300
+#include "oem300.h"
+#endif
+
+#ifdef SIS315H
+#include "oem310.h"
+#endif
+
+#define SiS_I2CDELAY      1000
+#define SiS_I2CDELAYSHORT  150
+
+static USHORT SiS_GetBIOSLCDResInfo(SiS_Private *SiS_Pr);
+
+/*********************************************/
+/*         HELPER: Lock/Unlock CRT2          */
+/*********************************************/
+
+void
+SiS_UnLockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+   if(HwInfo->jChipType >= SIS_315H)
+      SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2f,0x01);
+   else
+      SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x24,0x01);
+}
+
+void
+SiS_LockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+   if(HwInfo->jChipType >= SIS_315H)
+      SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2F,0xFE);
+   else
+      SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x24,0xFE);
+}
+
+/*********************************************/
+/*            HELPER: Write SR11             */
+/*********************************************/
+
+static void
+SiS_SetRegSR11ANDOR(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT DataAND, USHORT DataOR)
+{
+   if(HwInfo->jChipType >= SIS_661) {
+      DataAND &= 0x0f;
+      DataOR  &= 0x0f;
+   }
+   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,DataAND,DataOR);
+}
+
+/*********************************************/
+/*    HELPER: Get Pointer to LCD structure   */
+/*********************************************/
+
+#ifdef SIS315H
+static UCHAR *
+GetLCDStructPtr661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+   UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+   UCHAR  *myptr = NULL;
+   USHORT romindex = 0, reg = 0, idx = 0;
+
+   /* Use the BIOS tables only for LVDS panels; TMDS is unreliable
+    * due to the variaty of panels the BIOS doesn't know about.
+    * Exception: If the BIOS has better knowledge (such as in case
+    * of machines with a 301C and a panel that does not support DDC)
+    * use the BIOS data as well.
+    */
+
+   if((SiS_Pr->SiS_ROMNew) &&
+      ((SiS_Pr->SiS_VBType & VB_SIS301LV302LV) || (!SiS_Pr->PanelSelfDetected))) {
+
+      if(HwInfo->jChipType < SIS_661) reg = 0x3c;
+      else                            reg = 0x7d;
+
+      idx = (SiS_GetReg(SiS_Pr->SiS_P3d4,reg) & 0x1f) * 26;
+
+      if(idx < (8*26)) {
+         myptr = (UCHAR *)&SiS_LCDStruct661[idx];
+      }
+      romindex = SISGETROMW(0x100);
+      if(romindex) {
+         romindex += idx;
+         myptr = &ROMAddr[romindex];
+      }
+   }
+   return myptr;
+}
+
+static USHORT
+GetLCDStructPtr661_2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+   UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+   USHORT romptr = 0;
+
+   /* Use the BIOS tables only for LVDS panels; TMDS is unreliable
+    * due to the variaty of panels the BIOS doesn't know about.
+    * Exception: If the BIOS has better knowledge (such as in case
+    * of machines with a 301C and a panel that does not support DDC)
+    * use the BIOS data as well.
+    */
+
+   if((SiS_Pr->SiS_ROMNew) &&
+      ((SiS_Pr->SiS_VBType & VB_SIS301LV302LV) || (!SiS_Pr->PanelSelfDetected))) {
+      romptr = SISGETROMW(0x102);
+      romptr += ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4) * SiS_Pr->SiS661LCD2TableSize);
+   }
+
+   return(romptr);
+}
+#endif
+
+/*********************************************/
+/*           Adjust Rate for CRT2            */
+/*********************************************/
+
+static BOOLEAN
+SiS_AdjustCRT2Rate(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+                   USHORT RRTI, USHORT *i, PSIS_HW_INFO HwInfo)
+{
+  USHORT checkmask=0,modeid,infoflag;
+
+  modeid = SiS_Pr->SiS_RefIndex[RRTI + (*i)].ModeID;
+
+  if(SiS_Pr->SiS_VBType & VB_SISVB) {
+
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) {
+
+      	checkmask |= SupportRAMDAC2;
+	if(HwInfo->jChipType >= SIS_315H) {
+	   checkmask |= SupportRAMDAC2_135;
+	   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+	      checkmask |= SupportRAMDAC2_162;
+	      if(SiS_Pr->SiS_VBType & VB_SIS301C) {
+		 checkmask |= SupportRAMDAC2_202;
+	      }
+	   }
+	}
+
+     } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+
+     	checkmask |= SupportLCD;
+	if(HwInfo->jChipType >= SIS_315H) {
+	   if(SiS_Pr->SiS_VBType & VB_SISVB) {
+	      if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (SiS_Pr->SiS_LCDInfo & LCDPass11)) {
+	         if(modeid == 0x2e) checkmask |= Support64048060Hz;
+	      }
+	   }
+	}
+
+     } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+
+      	checkmask |= SupportHiVision;
+
+     } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToYPbPr525750|SetCRT2ToAVIDEO|SetCRT2ToSVIDEO|SetCRT2ToSCART)) {
+
+        checkmask |= SupportTV;
+	if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+	   checkmask |= SupportTV1024;
+	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) {
+	      if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) {
+	         checkmask |= SupportYPbPr750p;
+	      }
+	   }
+	}
+
+     }
+
+  } else {	/* LVDS */
+
+     if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+     	if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+           checkmask |= SupportCHTV;
+      	}
+     }
+
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+     	checkmask |= SupportLCD;
+     }
+
+  }
+
+  /* Look backwards in table for matching CRT2 mode */
+  for(; SiS_Pr->SiS_RefIndex[RRTI + (*i)].ModeID == modeid; (*i)--) {
+     infoflag = SiS_Pr->SiS_RefIndex[RRTI + (*i)].Ext_InfoFlag;
+     if(infoflag & checkmask) return TRUE;
+     if((*i) == 0) break;
+  }
+
+  /* Look through the whole mode-section of the table from the beginning
+   * for a matching CRT2 mode if no mode was found yet.
+   */
+  for((*i) = 0; ; (*i)++) {
+     if(SiS_Pr->SiS_RefIndex[RRTI + (*i)].ModeID != modeid) break;
+     infoflag = SiS_Pr->SiS_RefIndex[RRTI + (*i)].Ext_InfoFlag;
+     if(infoflag & checkmask) return TRUE;
+  }
+  return FALSE;
+}
+
+/*********************************************/
+/*              Get rate index               */
+/*********************************************/
+
+USHORT
+SiS_GetRatePtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+               PSIS_HW_INFO HwInfo)
+{
+  SHORT  LCDRefreshIndex[] = { 0x00, 0x00, 0x01, 0x01,
+                               0x01, 0x01, 0x01, 0x01,
+			       0x01, 0x01, 0x01, 0x01,
+			       0x01, 0x01, 0x01, 0x01,
+			       0x00, 0x00, 0x00, 0x00 };
+  USHORT RRTI,i,backup_i;
+  USHORT modeflag,index,temp,backupindex;
+
+  /* Do NOT check for UseCustomMode here, will skrew up FIFO */
+  if(ModeNo == 0xfe) return 0;
+
+  if(ModeNo <= 0x13) {
+     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  } else {
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+  }
+
+  if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+     	if(modeflag & HalfDCLK) return 0;
+     }
+  }
+
+  if(ModeNo < 0x14) return 0xFFFF;
+
+  index = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x33) >> SiS_Pr->SiS_SelectCRT2Rate) & 0x0F;
+  backupindex = index;
+
+  if(index > 0) index--;
+
+  if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) {
+     if(SiS_Pr->SiS_VBType & VB_SISVB) {
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+	   if(SiS_Pr->SiS_VBType & VB_NoLCD)		index = 0;
+	   else if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) index = backupindex = 0;
+	}
+	if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+	   if(!(SiS_Pr->SiS_VBType & VB_NoLCD)) {
+              temp = LCDRefreshIndex[SiS_GetBIOSLCDResInfo(SiS_Pr)];
+              if(index > temp) index = temp;
+	   }
+	}
+     } else {
+        if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) index = 0;
+	if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+           if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) index = 0;
+        }
+     }
+  }
+
+  RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
+  ModeNo = SiS_Pr->SiS_RefIndex[RRTI].ModeID;
+
+  if(HwInfo->jChipType >= SIS_315H) {
+     if(!(SiS_Pr->SiS_VBInfo & DriverMode)) {
+        if( (SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_VESAID == 0x105) ||
+            (SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_VESAID == 0x107) ) {
+           if(backupindex <= 1) RRTI++;
+        }
+     }
+  }
+
+  i = 0;
+  do {
+     if(SiS_Pr->SiS_RefIndex[RRTI + i].ModeID != ModeNo) break;
+     temp = SiS_Pr->SiS_RefIndex[RRTI + i].Ext_InfoFlag;
+     temp &= ModeTypeMask;
+     if(temp < SiS_Pr->SiS_ModeType) break;
+     i++;
+     index--;
+  } while(index != 0xFFFF);
+
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) {
+     if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+      	temp = SiS_Pr->SiS_RefIndex[RRTI + i - 1].Ext_InfoFlag;
+      	if(temp & InterlaceMode) i++;
+     }
+  }
+
+  i--;
+
+  if((SiS_Pr->SiS_SetFlag & ProgrammingCRT2) && (!(SiS_Pr->SiS_VBInfo & DisableCRT2Display))) {
+     backup_i = i;
+     if(!(SiS_AdjustCRT2Rate(SiS_Pr, ModeNo, ModeIdIndex, RRTI, &i, HwInfo))) {
+	i = backup_i;
+     }
+  }
+
+  return(RRTI + i);
+}
+
+/*********************************************/
+/*            STORE CRT2 INFO in CR34        */
+/*********************************************/
+
+static void
+SiS_SaveCRT2Info(SiS_Private *SiS_Pr, USHORT ModeNo)
+{
+  USHORT temp1,temp2;
+
+  /* Store CRT1 ModeNo in CR34 */
+  SiS_SetReg(SiS_Pr->SiS_P3d4,0x34,ModeNo);
+  temp1 = (SiS_Pr->SiS_VBInfo & SetInSlaveMode) >> 8;
+  temp2 = ~(SetInSlaveMode >> 8);
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x31,temp2,temp1);
+}
+
+/*********************************************/
+/*    HELPER: GET SOME DATA FROM BIOS ROM    */
+/*********************************************/
+
+#ifdef SIS300
+static BOOLEAN
+SiS_CR36BIOSWord23b(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+  USHORT temp,temp1;
+
+  if(SiS_Pr->SiS_UseROM) {
+     if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) {
+        temp = 1 << ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4) & 0x0f);
+        temp1 = SISGETROMW(0x23b);
+        if(temp1 & temp) return TRUE;
+     }
+  }
+  return FALSE;
+}
+
+static BOOLEAN
+SiS_CR36BIOSWord23d(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+  USHORT temp,temp1;
+
+  if(SiS_Pr->SiS_UseROM) {
+     if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) {
+        temp = 1 << ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4) & 0x0f);
+        temp1 = SISGETROMW(0x23d);
+        if(temp1 & temp) return TRUE;
+     }
+  }
+  return FALSE;
+}
+#endif
+
+/*********************************************/
+/*          HELPER: DELAY FUNCTIONS          */
+/*********************************************/
+
+void
+SiS_DDC2Delay(SiS_Private *SiS_Pr, USHORT delaytime)
+{
+  USHORT i, j;
+
+  for(i=0; i<delaytime; i++) {
+     j += SiS_GetReg(SiS_Pr->SiS_P3c4,0x05);
+  }
+}
+
+#if defined(SIS300) || defined(SIS315H)
+static void
+SiS_GenericDelay(SiS_Private *SiS_Pr, USHORT delay)
+{
+  USHORT temp,flag;
+
+  flag = SiS_GetRegByte(0x61) & 0x10;
+
+  while(delay) {
+     temp = SiS_GetRegByte(0x61) & 0x10;
+     if(temp == flag) continue;
+     flag = temp;
+     delay--;
+  }
+}
+#endif
+
+#ifdef SIS315H
+static void
+SiS_LongDelay(SiS_Private *SiS_Pr, USHORT delay)
+{
+  while(delay--) {
+     SiS_GenericDelay(SiS_Pr,0x19df);
+  }
+}
+#endif
+
+#if defined(SIS300) || defined(SIS315H)
+static void
+SiS_ShortDelay(SiS_Private *SiS_Pr, USHORT delay)
+{
+  while(delay--) {
+     SiS_GenericDelay(SiS_Pr,0x42);
+  }
+}
+#endif
+
+static void
+SiS_PanelDelay(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT DelayTime)
+{
+#if defined(SIS300) || defined(SIS315H)
+  UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+  USHORT PanelID, DelayIndex, Delay=0;
+#endif
+
+  if(HwInfo->jChipType < SIS_315H) {
+
+#ifdef SIS300
+
+      PanelID = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36);
+      if(SiS_Pr->SiS_VBType & VB_SISVB) {
+         if(SiS_Pr->SiS_VBType & VB_SIS301) PanelID &= 0xf7;
+         if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x18) & 0x10)) PanelID = 0x12;
+      }
+      DelayIndex = PanelID >> 4;
+      if((DelayTime >= 2) && ((PanelID & 0x0f) == 1))  {
+         Delay = 3;
+      } else {
+         if(DelayTime >= 2) DelayTime -= 2;
+         if(!(DelayTime & 0x01)) {
+       	    Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[0];
+         } else {
+       	    Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[1];
+         }
+	 if(SiS_Pr->SiS_UseROM) {
+            if(ROMAddr[0x220] & 0x40) {
+               if(!(DelayTime & 0x01)) Delay = (USHORT)ROMAddr[0x225];
+               else 	    	       Delay = (USHORT)ROMAddr[0x226];
+            }
+         }
+      }
+      SiS_ShortDelay(SiS_Pr, Delay);
+
+#endif  /* SIS300 */
+
+   } else {
+
+#ifdef SIS315H
+
+      if((HwInfo->jChipType >= SIS_661)    ||
+         (HwInfo->jChipType <= SIS_315PRO) ||
+	 (HwInfo->jChipType == SIS_330)    ||
+	 (SiS_Pr->SiS_ROMNew)) {
+
+         if(!(DelayTime & 0x01)) {
+	    SiS_DDC2Delay(SiS_Pr, 0x1000);
+         } else {
+	    SiS_DDC2Delay(SiS_Pr, 0x4000);
+         }
+
+      } else if((SiS_Pr->SiS_IF_DEF_LVDS == 1) /* ||
+         (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) ||
+	 (SiS_Pr->SiS_CustomT == CUT_CLEVO1400) */ ) {			/* 315 series, LVDS; Special */
+
+         if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) {
+            PanelID = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36);
+	    if(SiS_Pr->SiS_CustomT == CUT_CLEVO1400) {
+	       if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x1b) & 0x10)) PanelID = 0x12;
+	    }
+	    if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
+	       DelayIndex = PanelID & 0x0f;
+	    } else {
+	       DelayIndex = PanelID >> 4;
+	    }
+	    if((DelayTime >= 2) && ((PanelID & 0x0f) == 1))  {
+               Delay = 3;
+            } else {
+               if(DelayTime >= 2) DelayTime -= 2;
+               if(!(DelayTime & 0x01)) {
+       		  Delay = SiS_Pr->SiS_PanelDelayTblLVDS[DelayIndex].timer[0];
+               } else {
+       		  Delay = SiS_Pr->SiS_PanelDelayTblLVDS[DelayIndex].timer[1];
+               }
+	       if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) {
+                  if(ROMAddr[0x13c] & 0x40) {
+                     if(!(DelayTime & 0x01)) {
+	    	        Delay = (USHORT)ROMAddr[0x17e];
+                     } else {
+	    	        Delay = (USHORT)ROMAddr[0x17f];
+                     }
+                  }
+               }
+            }
+	    SiS_ShortDelay(SiS_Pr, Delay);
+	 }
+
+      } else if(SiS_Pr->SiS_VBType & VB_SISVB) {			/* 315 series, all bridges */
+
+	 DelayIndex = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4;
+         if(!(DelayTime & 0x01)) {
+       	    Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[0];
+         } else {
+       	    Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[1];
+         }
+	 Delay <<= 8;
+	 SiS_DDC2Delay(SiS_Pr, Delay);
+
+      }
+
+#endif /* SIS315H */
+
+   }
+}
+
+#ifdef SIS315H
+static void
+SiS_PanelDelayLoop(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+                      USHORT DelayTime, USHORT DelayLoop)
+{
+   int i;
+   for(i=0; i<DelayLoop; i++) {
+      SiS_PanelDelay(SiS_Pr, HwInfo, DelayTime);
+   }
+}
+#endif
+
+/*********************************************/
+/*    HELPER: WAIT-FOR-RETRACE FUNCTIONS     */
+/*********************************************/
+
+void
+SiS_WaitRetrace1(SiS_Private *SiS_Pr)
+{
+  USHORT watchdog;
+
+  if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x1f) & 0xc0) return;
+  if(!(SiS_GetReg(SiS_Pr->SiS_P3d4,0x17) & 0x80)) return;
+
+  watchdog = 65535;
+  while((SiS_GetRegByte(SiS_Pr->SiS_P3da) & 0x08) && --watchdog);
+  watchdog = 65535;
+  while((!(SiS_GetRegByte(SiS_Pr->SiS_P3da) & 0x08)) && --watchdog);
+}
+
+#if defined(SIS300) || defined(SIS315H)
+static void
+SiS_WaitRetrace2(SiS_Private *SiS_Pr, USHORT reg)
+{
+  USHORT watchdog;
+
+  watchdog = 65535;
+  while((SiS_GetReg(SiS_Pr->SiS_Part1Port,reg) & 0x02) && --watchdog);
+  watchdog = 65535;
+  while((!(SiS_GetReg(SiS_Pr->SiS_Part1Port,reg) & 0x02)) && --watchdog);
+}
+#endif
+
+static void
+SiS_WaitVBRetrace(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  if(HwInfo->jChipType < SIS_315H) {
+#ifdef SIS300
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+        if(!(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x20)) return;
+     }
+     if(!(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x80)) {
+        SiS_WaitRetrace1(SiS_Pr);
+     } else {
+        SiS_WaitRetrace2(SiS_Pr, 0x25);
+     }
+#endif
+  } else {
+#ifdef SIS315H
+     if(!(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x40)) {
+        SiS_WaitRetrace1(SiS_Pr);
+     } else {
+        SiS_WaitRetrace2(SiS_Pr, 0x30);
+     }
+#endif
+  }
+}
+
+static void
+SiS_VBWait(SiS_Private *SiS_Pr)
+{
+  USHORT tempal,temp,i,j;
+
+  temp = 0;
+  for(i=0; i<3; i++) {
+    for(j=0; j<100; j++) {
+       tempal = SiS_GetRegByte(SiS_Pr->SiS_P3da);
+       if(temp & 0x01) {
+          if((tempal & 0x08))  continue;
+          else break;
+       } else {
+          if(!(tempal & 0x08)) continue;
+          else break;
+       }
+    }
+    temp ^= 0x01;
+  }
+}
+
+static void
+SiS_VBLongWait(SiS_Private *SiS_Pr)
+{
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+     SiS_VBWait(SiS_Pr);
+  } else {
+     SiS_WaitRetrace1(SiS_Pr);
+  }
+}
+
+/*********************************************/
+/*               HELPER: MISC                */
+/*********************************************/
+
+#ifdef SIS300
+static BOOLEAN
+SiS_Is301B(SiS_Private *SiS_Pr)
+{
+  if(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01) >= 0xb0) return TRUE;
+  return FALSE;
+}
+#endif
+
+static BOOLEAN
+SiS_CRT2IsLCD(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  USHORT flag;
+
+  if(HwInfo->jChipType == SIS_730) {
+     flag = SiS_GetReg(SiS_Pr->SiS_P3c4,0x13);
+     if(flag & 0x20) return TRUE;
+  }
+  flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
+  if(flag & 0x20) return TRUE;
+  return FALSE;
+}
+
+BOOLEAN
+SiS_IsDualEdge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+#ifdef SIS315H
+  USHORT flag;
+
+  if(HwInfo->jChipType >= SIS_315H) {
+     if((HwInfo->jChipType != SIS_650) || (SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0xf0)) {
+        flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
+        if(flag & EnableDualEdge) return TRUE;
+     }
+  }
+#endif
+  return FALSE;
+}
+
+BOOLEAN
+SiS_IsVAMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+#ifdef SIS315H
+  USHORT flag;
+
+  if(HwInfo->jChipType >= SIS_315H) {
+     flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
+     if((flag & EnableDualEdge) && (flag & SetToLCDA)) return TRUE;
+  }
+#endif
+  return FALSE;
+}
+
+#ifdef SIS315H
+static BOOLEAN
+SiS_IsVAorLCD(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  if(SiS_IsVAMode(SiS_Pr,HwInfo))   return TRUE;
+  if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) return TRUE;
+  return FALSE;
+}
+#endif
+
+static BOOLEAN
+SiS_IsDualLink(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+#ifdef SIS315H
+  if(HwInfo->jChipType >= SIS_315H) {
+     if((SiS_CRT2IsLCD(SiS_Pr, HwInfo)) ||
+        (SiS_IsVAMode(SiS_Pr, HwInfo))) {
+        if(SiS_Pr->SiS_LCDInfo & LCDDualLink) return TRUE;
+     }
+  }
+#endif
+  return FALSE;
+}
+
+#ifdef SIS315H
+static BOOLEAN
+SiS_TVEnabled(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  if((SiS_GetReg(SiS_Pr->SiS_Part2Port,0x00) & 0x0f) != 0x0c) return TRUE;
+  if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS301LV302LV)) {
+     if(SiS_GetReg(SiS_Pr->SiS_Part2Port,0x4d) & 0x10) return TRUE;
+  }
+  return FALSE;
+}
+#endif
+
+#ifdef SIS315H
+static BOOLEAN
+SiS_LCDAEnabled(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x13) & 0x04) return TRUE;
+  return FALSE;
+}
+#endif
+
+#ifdef SIS315H
+static BOOLEAN
+SiS_WeHaveBacklightCtrl(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  if((HwInfo->jChipType >= SIS_315H) && (HwInfo->jChipType < SIS_661)) {
+     if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x79) & 0x10) return TRUE;
+  }
+  return FALSE;
+}
+#endif
+
+#ifdef SIS315H
+static BOOLEAN
+SiS_IsNotM650orLater(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  USHORT flag;
+
+  if(HwInfo->jChipType == SIS_650) {
+     flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f);
+     flag &= 0xF0;
+     /* Check for revision != A0 only */
+     if((flag == 0xe0) || (flag == 0xc0) ||
+        (flag == 0xb0) || (flag == 0x90)) return FALSE;
+  } else if(HwInfo->jChipType >= SIS_661) return FALSE;
+  return TRUE;
+}
+#endif
+
+#ifdef SIS315H
+static BOOLEAN
+SiS_IsYPbPr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  USHORT flag;
+
+  if(HwInfo->jChipType >= SIS_315H) {
+     flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
+     if(flag & EnableCHYPbPr) return TRUE;  /* = YPrPb = 0x08 */
+  }
+  return FALSE;
+}
+#endif
+
+#ifdef SIS315H
+static BOOLEAN
+SiS_IsChScart(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  USHORT flag;
+
+  if(HwInfo->jChipType >= SIS_315H) {
+     flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
+     if(flag & EnableCHScart) return TRUE;  /* = Scart = 0x04 */
+  }
+  return FALSE;
+}
+#endif
+
+#ifdef SIS315H
+static BOOLEAN
+SiS_IsTVOrYPbPrOrScart(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  USHORT flag;
+
+  if(HwInfo->jChipType >= SIS_315H) {
+     flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
+     if(flag & SetCRT2ToTV)        return TRUE;
+     flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
+     if(flag & EnableCHYPbPr)      return TRUE;  /* = YPrPb = 0x08 */
+     if(flag & EnableCHScart)      return TRUE;  /* = Scart = 0x04 - TW */
+  } else {
+     flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
+     if(flag & SetCRT2ToTV)        return TRUE;
+  }
+  return FALSE;
+}
+#endif
+
+#ifdef SIS315H
+static BOOLEAN
+SiS_IsLCDOrLCDA(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  USHORT flag;
+
+  if(HwInfo->jChipType >= SIS_315H) {
+     flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
+     if(flag & SetCRT2ToLCD) return TRUE;
+     flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
+     if(flag & SetToLCDA)    return TRUE;
+  } else {
+     flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
+     if(flag & SetCRT2ToLCD) return TRUE;
+  }
+  return FALSE;
+}
+#endif
+
+static BOOLEAN
+SiS_BridgeIsOn(SiS_Private *SiS_Pr)
+{
+  USHORT flag;
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+     return TRUE;
+  } else if(SiS_Pr->SiS_VBType & VB_SISVB) {
+     flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00);
+     if((flag == 1) || (flag == 2)) return TRUE;
+  }
+  return FALSE;
+}
+
+static BOOLEAN
+SiS_BridgeIsEnabled(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  USHORT flag;
+
+  if(SiS_BridgeIsOn(SiS_Pr)) {
+     flag = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00);
+     if(HwInfo->jChipType < SIS_315H) {
+       flag &= 0xa0;
+       if((flag == 0x80) || (flag == 0x20)) return TRUE;
+     } else {
+       flag &= 0x50;
+       if((flag == 0x40) || (flag == 0x10)) return TRUE;
+     }
+  }
+  return FALSE;
+}
+
+static BOOLEAN
+SiS_BridgeInSlavemode(SiS_Private *SiS_Pr)
+{
+  USHORT flag1;
+
+  flag1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31);
+  if(flag1 & (SetInSlaveMode >> 8)) return TRUE;
+  return FALSE;
+}
+
+/*********************************************/
+/*       GET VIDEO BRIDGE CONFIG INFO        */
+/*********************************************/
+
+/* Setup general purpose IO for Chrontel communication */
+void
+SiS_SetChrontelGPIO(SiS_Private *SiS_Pr, USHORT myvbinfo)
+{
+   unsigned long  acpibase;
+   unsigned short temp;
+
+   if(!(SiS_Pr->SiS_ChSW)) return;
+
+#ifdef LINUX_KERNEL
+   SiS_SetRegLong(0xcf8,0x80000874);		       /* get ACPI base */
+   acpibase = SiS_GetRegLong(0xcfc);
+#else
+   acpibase = pciReadLong(0x00000800, 0x74);
+#endif
+   acpibase &= 0xFFFF;
+   temp = SiS_GetRegShort((USHORT)(acpibase + 0x3c));  /* ACPI register 0x3c: GP Event 1 I/O mode select */
+   temp &= 0xFEFF;
+   SiS_SetRegShort((USHORT)(acpibase + 0x3c), temp);
+   temp = SiS_GetRegShort((USHORT)(acpibase + 0x3c));
+   temp = SiS_GetRegShort((USHORT)(acpibase + 0x3a));  /* ACPI register 0x3a: GP Pin Level (low/high) */
+   temp &= 0xFEFF;
+   if(!(myvbinfo & SetCRT2ToTV)) temp |= 0x0100;
+   SiS_SetRegShort((USHORT)(acpibase + 0x3a), temp);
+   temp = SiS_GetRegShort((USHORT)(acpibase + 0x3a));
+}
+
+void
+SiS_GetVBInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+              PSIS_HW_INFO HwInfo, int checkcrt2mode)
+{
+  USHORT tempax,tempbx,temp;
+  USHORT modeflag, resinfo=0;
+
+  if(ModeNo <= 0x13) {
+     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  } else if(SiS_Pr->UseCustomMode) {
+     modeflag = SiS_Pr->CModeFlag;
+  } else {
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+     resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+  }
+
+  SiS_Pr->SiS_SetFlag = 0;
+
+  SiS_Pr->SiS_ModeType = modeflag & ModeTypeMask;
+
+  tempbx = 0;
+  if(SiS_BridgeIsOn(SiS_Pr)) {
+    	temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
+#if 0
+   	if(HwInfo->jChipType < SIS_661) {
+	   /* NO - YPbPr not set yet ! */
+	   if(SiS_Pr->SiS_YPbPr & <all ypbpr except 525i>) {
+	      temp &= (SetCRT2ToHiVision | SwitchCRT2 | SetSimuScanMode); 	/* 0x83 */
+	      temp |= SetCRT2ToHiVision;   					/* 0x80 */
+   	   }
+	   if(SiS_Pr->SiS_YPbPr & <ypbpr525i>) {
+	      temp &= (SetCRT2ToHiVision | SwitchCRT2 | SetSimuScanMode); 	/* 0x83 */
+	      temp |= SetCRT2ToSVIDEO;  					/* 0x08 */
+	   }
+	}
+#endif
+    	tempbx |= temp;
+    	tempax = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) << 8;
+        tempax &= (DriverMode | LoadDACFlag | SetNotSimuMode | SetPALTV);
+    	tempbx |= tempax;
+
+#ifdef SIS315H
+	if(HwInfo->jChipType >= SIS_315H) {
+    	   if(SiS_Pr->SiS_VBType & VB_SISLCDA) {
+	      if(ModeNo == 0x03) {
+	         /* Mode 0x03 is never in driver mode */
+		 SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x31,0xbf);
+	      }
+	      if(!(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & (DriverMode >> 8))) {
+	         /* Reset LCDA setting if not driver mode */
+		 SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xfc);
+	      }
+	      if(IS_SIS650) {
+	         if(SiS_Pr->SiS_UseLCDA) {
+		    if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0xF0) {
+		       if((ModeNo <= 0x13) || (!(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & (DriverMode >> 8)))) {
+		          SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x38,(EnableDualEdge | SetToLCDA));
+		       }
+		    }
+		 }
+	      }
+	      temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
+       	      if((temp & (EnableDualEdge | SetToLCDA)) == (EnableDualEdge | SetToLCDA)) {
+          	 tempbx |= SetCRT2ToLCDA;
+	      }
+	   }
+
+	   if(SiS_Pr->SiS_VBType & (VB_SIS301LV|VB_SIS302LV|VB_SIS302ELV)) {
+	      tempbx &= ~(SetCRT2ToRAMDAC);
+	   }
+
+	   if(HwInfo->jChipType >= SIS_661) {
+	      tempbx &= ~(SetCRT2ToYPbPr525750 | SetCRT2ToHiVision);
+	      temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
+	      if(SiS_Pr->SiS_VBType & VB_SISYPBPR) {
+	         if(temp & 0x04) {
+		    temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35) & 0xe0;
+		    if(temp == 0x60) tempbx |= SetCRT2ToHiVision;
+		    else             tempbx |= SetCRT2ToYPbPr525750;
+		 }
+	      } else if(SiS_Pr->SiS_VBType & VB_SISHIVISION) {
+	         if(temp & 0x04) {
+		    temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35) & 0xe0;
+		    if(temp == 0x60) tempbx |= SetCRT2ToHiVision;
+		 }
+	      }
+  	   }
+
+	   if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+	      temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
+	      if(temp & SetToLCDA) {
+		 tempbx |= SetCRT2ToLCDA;
+	      }
+	      if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+	         if(temp & EnableCHYPbPr) {
+		    tempbx |= SetCRT2ToCHYPbPr;
+		 }
+	      }
+	   }
+	}
+
+#endif  /* SIS315H */
+
+    	if(SiS_Pr->SiS_VBType & VB_SISVB) {
+	   temp = SetCRT2ToSVIDEO   |
+	          SetCRT2ToAVIDEO   |
+	          SetCRT2ToSCART    |
+	          SetCRT2ToLCDA     |
+	          SetCRT2ToLCD      |
+	          SetCRT2ToRAMDAC   |
+                  SetCRT2ToHiVision |
+		  SetCRT2ToYPbPr525750;
+    	} else {
+           if(HwInfo->jChipType >= SIS_315H) {
+              if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+        	 temp = SetCRT2ToAVIDEO |
+		        SetCRT2ToSVIDEO |
+		        SetCRT2ToSCART  |
+		        SetCRT2ToLCDA   |
+		        SetCRT2ToLCD    |
+		        SetCRT2ToCHYPbPr;
+      	      } else {
+        	 temp = SetCRT2ToLCDA   |
+		        SetCRT2ToLCD;
+	      }
+	   } else {
+      	      if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+          	 temp = SetCRT2ToTV | SetCRT2ToLCD;
+              } else {
+        	 temp = SetCRT2ToLCD;
+	      }
+	   }
+    	}
+
+    	if(!(tempbx & temp)) {
+      	   tempax = DisableCRT2Display;
+      	   tempbx = 0;
+    	}
+
+   	if(SiS_Pr->SiS_VBType & VB_SISVB) {
+	   USHORT clearmask = ( DriverMode 	   |
+				DisableCRT2Display |
+				LoadDACFlag 	   |
+				SetNotSimuMode 	   |
+				SetInSlaveMode 	   |
+				SetPALTV 	   |
+				SwitchCRT2	   |
+				SetSimuScanMode );
+      	   if(tempbx & SetCRT2ToLCDA)        tempbx &= (clearmask | SetCRT2ToLCDA);
+	   if(tempbx & SetCRT2ToRAMDAC)      tempbx &= (clearmask | SetCRT2ToRAMDAC);
+	   if(tempbx & SetCRT2ToLCD)         tempbx &= (clearmask | SetCRT2ToLCD);
+	   if(tempbx & SetCRT2ToSCART)       tempbx &= (clearmask | SetCRT2ToSCART);
+	   if(tempbx & SetCRT2ToHiVision)    tempbx &= (clearmask | SetCRT2ToHiVision);
+	   if(tempbx & SetCRT2ToYPbPr525750) tempbx &= (clearmask | SetCRT2ToYPbPr525750);
+   	} else {
+	   if(HwInfo->jChipType >= SIS_315H) {
+	      if(tempbx & SetCRT2ToLCDA) {
+	         tempbx &= (0xFF00|SwitchCRT2|SetSimuScanMode);
+	      }
+	   }
+      	   if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+              if(tempbx & SetCRT2ToTV) {
+          	 tempbx &= (0xFF00|SetCRT2ToTV|SwitchCRT2|SetSimuScanMode);
+	      }
+      	   }
+      	   if(tempbx & SetCRT2ToLCD) {
+              tempbx &= (0xFF00|SetCRT2ToLCD|SwitchCRT2|SetSimuScanMode);
+	   }
+	   if(HwInfo->jChipType >= SIS_315H) {
+	      if(tempbx & SetCRT2ToLCDA) {
+	         tempbx |= SetCRT2ToLCD;
+	      }
+	   }
+	}
+
+    	if(tempax & DisableCRT2Display) {
+      	   if(!(tempbx & (SwitchCRT2 | SetSimuScanMode))) {
+              tempbx = SetSimuScanMode | DisableCRT2Display;
+      	   }
+    	}
+
+    	if(!(tempbx & DriverMode)) tempbx |= SetSimuScanMode;
+
+	/* LVDS/CHRONTEL (LCD/TV) and 301BDH (LCD) can only be slave in 8bpp modes */
+	if(SiS_Pr->SiS_ModeType <= ModeVGA) {
+	   if( (SiS_Pr->SiS_IF_DEF_LVDS == 1) ||
+	       ((SiS_Pr->SiS_VBType & VB_NoLCD) && (tempbx & SetCRT2ToLCD)) ) {
+	       modeflag &= (~CRT2Mode);
+	   }
+	}
+
+    	if(!(tempbx & SetSimuScanMode)) {
+      	   if(tempbx & SwitchCRT2) {
+              if((!(modeflag & CRT2Mode)) && (checkcrt2mode)) {
+		 if( (HwInfo->jChipType >= SIS_315H) &&
+		     (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) ) {
+		    if(resinfo != SIS_RI_1600x1200) {
+                       tempbx |= SetSimuScanMode;
+		    }
+		 } else {
+            	    tempbx |= SetSimuScanMode;
+	         }
+              }
+      	   } else {
+              if(SiS_BridgeIsEnabled(SiS_Pr,HwInfo)) {
+          	 if(!(tempbx & DriverMode)) {
+            	    if(SiS_BridgeInSlavemode(SiS_Pr)) {
+		       tempbx |= SetSimuScanMode;
+            	    }
+                 }
+              }
+      	   }
+    	}
+
+    	if(!(tempbx & DisableCRT2Display)) {
+           if(tempbx & DriverMode) {
+              if(tempbx & SetSimuScanMode) {
+          	 if((!(modeflag & CRT2Mode)) && (checkcrt2mode)) {
+	            if( (HwInfo->jChipType >= SIS_315H) &&
+		        (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) ) {
+		       if(resinfo != SIS_RI_1600x1200) {
+		          tempbx |= SetInSlaveMode;
+		       }
+		    } else {
+            	       tempbx |= SetInSlaveMode;
+                    }
+	         }
+              }
+           } else {
+              tempbx |= SetInSlaveMode;
+      	   }
+    	}
+
+  }
+
+  SiS_Pr->SiS_VBInfo = tempbx;
+
+  if(HwInfo->jChipType == SIS_630) {
+     SiS_SetChrontelGPIO(SiS_Pr, SiS_Pr->SiS_VBInfo);
+  }
+
+#ifdef TWDEBUG
+#ifdef LINUX_KERNEL
+  printk(KERN_DEBUG "sisfb: (VBInfo= 0x%04x, SetFlag=0x%04x)\n",
+      SiS_Pr->SiS_VBInfo, SiS_Pr->SiS_SetFlag);
+#endif
+#ifdef LINUX_XF86
+  xf86DrvMsgVerb(0, X_PROBED, 3, "(init301: VBInfo=0x%04x, SetFlag=0x%04x)\n",
+      SiS_Pr->SiS_VBInfo, SiS_Pr->SiS_SetFlag);
+#endif
+#endif
+}
+
+/*********************************************/
+/*           DETERMINE YPbPr MODE            */
+/*********************************************/
+
+void
+SiS_SetYPbPr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+
+  UCHAR temp;
+
+  /* Note: This variable is only used on 30xLV systems.
+   * CR38 has a different meaning on LVDS/CH7019 systems.
+   * On 661 and later, these bits moved to CR35.
+   *
+   * On 301, 301B, only HiVision 1080i is supported.
+   * On 30xLV, 301C, only YPbPr 1080i is supported.
+   */
+
+  SiS_Pr->SiS_YPbPr = 0;
+  if(HwInfo->jChipType >= SIS_661) return;
+
+  if(SiS_Pr->SiS_VBType) {
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+	SiS_Pr->SiS_YPbPr = YPbPrHiVision;
+     }
+  }
+
+  if(HwInfo->jChipType >= SIS_315H) {
+     if(SiS_Pr->SiS_VBType & (VB_SIS301LV302LV | VB_SIS301C)) {
+        temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
+	if(temp & 0x08) {
+	   switch((temp >> 4)) {
+	   case 0x00: SiS_Pr->SiS_YPbPr = YPbPr525i;     break;
+	   case 0x01: SiS_Pr->SiS_YPbPr = YPbPr525p;     break;
+	   case 0x02: SiS_Pr->SiS_YPbPr = YPbPr750p;     break;
+	   case 0x03: SiS_Pr->SiS_YPbPr = YPbPrHiVision; break;
+	   }
+	}
+     }
+  }
+
+}
+
+/*********************************************/
+/*           DETERMINE TVMode flag           */
+/*********************************************/
+
+void
+SiS_SetTVMode(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, PSIS_HW_INFO HwInfo)
+{
+  UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+  USHORT temp, temp1, resinfo = 0, romindex = 0;
+  UCHAR  OutputSelect = *SiS_Pr->pSiS_OutputSelect;
+
+  SiS_Pr->SiS_TVMode = 0;
+
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) return;
+  if(SiS_Pr->UseCustomMode) return;
+
+  if(ModeNo > 0x13) {
+     resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+  }
+
+  if(HwInfo->jChipType < SIS_661) {
+
+     if(SiS_Pr->SiS_VBInfo & SetPALTV) SiS_Pr->SiS_TVMode |= TVSetPAL;
+
+     if(SiS_Pr->SiS_VBType & VB_SISVB) {
+        temp = 0;
+        if((HwInfo->jChipType == SIS_630) ||
+           (HwInfo->jChipType == SIS_730)) {
+           temp = 0x35;
+	   romindex = 0xfe;
+        } else if(HwInfo->jChipType >= SIS_315H) {
+           temp = 0x38;
+	   romindex = 0xf3;
+	   if(HwInfo->jChipType >= SIS_330) romindex = 0x11b;
+        }
+        if(temp) {
+           if(romindex && SiS_Pr->SiS_UseROM && (!(SiS_Pr->SiS_ROMNew))) {
+	      OutputSelect = ROMAddr[romindex];
+	      if(!(OutputSelect & EnablePALMN)) {
+                 SiS_SetRegAND(SiS_Pr->SiS_P3d4,temp,0x3F);
+	      }
+	   }
+	   temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,temp);
+	   if(SiS_Pr->SiS_TVMode & TVSetPAL) {
+              if(temp1 & EnablePALM) {		/* 0x40 */
+                 SiS_Pr->SiS_TVMode |= TVSetPALM;
+	         SiS_Pr->SiS_TVMode &= ~TVSetPAL;
+	      } else if(temp1 & EnablePALN) {	/* 0x80 */
+	         SiS_Pr->SiS_TVMode |= TVSetPALN;
+              }
+	   } else {
+              if(temp1 & EnableNTSCJ) {		/* 0x40 */
+	         SiS_Pr->SiS_TVMode |= TVSetNTSCJ;
+  	      }
+	   }
+        }
+	/* Translate HiVision/YPbPr to our new flags */
+	if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+	   if(SiS_Pr->SiS_YPbPr == YPbPr750p)          SiS_Pr->SiS_TVMode |= TVSetYPbPr750p;
+	   else if(SiS_Pr->SiS_YPbPr == YPbPr525p)     SiS_Pr->SiS_TVMode |= TVSetYPbPr525p;
+	   else	if(SiS_Pr->SiS_YPbPr == YPbPrHiVision) SiS_Pr->SiS_TVMode |= TVSetHiVision;
+	   else					       SiS_Pr->SiS_TVMode |= TVSetYPbPr525i;
+	   if(SiS_Pr->SiS_TVMode & (TVSetYPbPr750p | TVSetYPbPr525p | TVSetYPbPr525i)) {
+	      SiS_Pr->SiS_VBInfo &= ~SetCRT2ToHiVision;
+	      SiS_Pr->SiS_VBInfo |= SetCRT2ToYPbPr525750;
+	   } else if(SiS_Pr->SiS_TVMode & TVSetHiVision) {
+	      SiS_Pr->SiS_TVMode |= TVSetPAL;
+	   }
+	}
+     } else if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+        if(SiS_Pr->SiS_CHOverScan) {
+           if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
+              temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
+              if((temp & TVOverScan) || (SiS_Pr->SiS_CHOverScan == 1)) {
+	         SiS_Pr->SiS_TVMode |= TVSetCHOverScan;
+              }
+           } else if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+      	      temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x79);
+      	      if((temp & 0x80) || (SiS_Pr->SiS_CHOverScan == 1)) {
+	         SiS_Pr->SiS_TVMode |= TVSetCHOverScan;
+ 	      }
+	   }
+           if(SiS_Pr->SiS_CHSOverScan) {
+              SiS_Pr->SiS_TVMode |= TVSetCHOverScan;
+           }
+        }
+        if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+	   temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
+     	   if(SiS_Pr->SiS_TVMode & TVSetPAL) {
+              if(temp & EnablePALM)      SiS_Pr->SiS_TVMode |= TVSetPALM;
+	      else if(temp & EnablePALN) SiS_Pr->SiS_TVMode |= TVSetPALN;
+           } else {
+	      if(temp & EnableNTSCJ) {
+	         SiS_Pr->SiS_TVMode |= TVSetNTSCJ;
+  	      }
+	   }
+	}
+     }
+
+  } else {  /* 661 and later */
+
+     temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
+     if(temp1 & 0x01) {
+        SiS_Pr->SiS_TVMode |= TVSetPAL;
+	if(temp1 & 0x08) {
+	   SiS_Pr->SiS_TVMode |= TVSetPALN;
+	} else if(temp1 & 0x04) {
+	   if(SiS_Pr->SiS_VBType & VB_SISVB) {
+	      SiS_Pr->SiS_TVMode &= ~TVSetPAL;
+	   }
+	   SiS_Pr->SiS_TVMode |= TVSetPALM;
+	}
+     } else {
+        if(temp1 & 0x02) {
+	   SiS_Pr->SiS_TVMode |= TVSetNTSCJ;
+	}
+     }
+     if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+        if(SiS_Pr->SiS_CHOverScan) {
+           if((temp1 & 0x10) || (SiS_Pr->SiS_CHOverScan == 1)) {
+	      SiS_Pr->SiS_TVMode |= TVSetCHOverScan;
+	   }
+	}
+     }
+     if(SiS_Pr->SiS_VBType & VB_SISVB) {
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) {
+	   temp1 &= 0xe0;
+	   if(temp1 == 0x00)      SiS_Pr->SiS_TVMode |= TVSetYPbPr525i;
+	   else if(temp1 == 0x20) SiS_Pr->SiS_TVMode |= TVSetYPbPr525p;
+	   else if(temp1 == 0x40) SiS_Pr->SiS_TVMode |= TVSetYPbPr750p;
+	} else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+	   SiS_Pr->SiS_TVMode |= (TVSetHiVision | TVSetPAL);
+	}
+	if(SiS_Pr->SiS_VBInfo & (SetCRT2ToYPbPr525750 | SetCRT2ToHiVision)) {
+	   if(resinfo == SIS_RI_800x480 || resinfo == SIS_RI_1024x576 || resinfo == SIS_RI_1280x720) {
+	      SiS_Pr->SiS_TVMode |= TVAspect169;
+	   } else {
+	      temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x39);
+	      if(temp1 & 0x02) {
+		 if(SiS_Pr->SiS_TVMode & (TVSetYPbPr750p | TVSetHiVision)) {
+		    SiS_Pr->SiS_TVMode |= TVAspect169;
+		 } else {
+		    SiS_Pr->SiS_TVMode |= TVAspect43LB;
+		 }
+	      } else {
+		 SiS_Pr->SiS_TVMode |= TVAspect43;
+	      }
+	   }
+	}
+     }
+  }
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToSCART) SiS_Pr->SiS_TVMode |= TVSetPAL;
+
+  if(SiS_Pr->SiS_VBType & VB_SISVB) {
+
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+        SiS_Pr->SiS_TVMode |= TVSetPAL;
+	SiS_Pr->SiS_TVMode &= ~(TVSetPALM | TVSetPALN | TVSetNTSCJ);
+     } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) {
+        if(SiS_Pr->SiS_TVMode & (TVSetYPbPr525i | TVSetYPbPr525p | TVSetYPbPr750p)) {
+	   SiS_Pr->SiS_TVMode &= ~(TVSetPAL | TVSetNTSCJ | TVSetPALM | TVSetPALN);
+	}
+     }
+
+     if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+        if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) {
+           SiS_Pr->SiS_TVMode |= TVSetTVSimuMode;
+        }
+     }
+
+     if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) {
+        /* BIOS sets TVNTSC1024 without checking 525p here. Wrong? */
+        if(!(SiS_Pr->SiS_TVMode & (TVSetHiVision | TVSetYPbPr525p | TVSetYPbPr750p))) {
+           if(resinfo == SIS_RI_1024x768) {
+              SiS_Pr->SiS_TVMode |= TVSetNTSC1024;
+	   }
+        }
+     }
+
+     SiS_Pr->SiS_TVMode |= TVRPLLDIV2XO;
+     if((SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) &&
+        (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+	SiS_Pr->SiS_TVMode &= ~TVRPLLDIV2XO;
+     } else if(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p | TVSetYPbPr750p)) {
+        SiS_Pr->SiS_TVMode &= ~TVRPLLDIV2XO;
+     } else if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) {
+        if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) {
+           SiS_Pr->SiS_TVMode &= ~TVRPLLDIV2XO;
+        }
+     }
+
+  }
+
+  SiS_Pr->SiS_VBInfo &= ~SetPALTV;
+
+#ifdef TWDEBUG
+  xf86DrvMsg(0, X_INFO, "(init301: TVMode %x, VBInfo %x)\n", SiS_Pr->SiS_TVMode, SiS_Pr->SiS_VBInfo);
+#endif
+}
+
+/*********************************************/
+/*               GET LCD INFO                */
+/*********************************************/
+
+static USHORT
+SiS_GetBIOSLCDResInfo(SiS_Private *SiS_Pr)
+{
+   USHORT temp = SiS_Pr->SiS_LCDResInfo;
+   /* Translate my LCDResInfo to BIOS value */
+   if(temp == Panel_1280x768_2)  temp = Panel_1280x768;
+   if(temp == Panel_1280x800_2)  temp = Panel_1280x800;
+   return temp;
+}
+
+static void
+SiS_GetLCDInfoBIOS(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+#ifdef SIS315H
+   UCHAR  *ROMAddr;
+   USHORT temp;
+
+#ifdef TWDEBUG
+   xf86DrvMsg(0, X_INFO, "Paneldata driver: [%d %d] [H %d %d] [V %d %d] [C %d 0x%02x 0x%02x]\n",
+      	SiS_Pr->PanelHT, SiS_Pr->PanelVT,
+	SiS_Pr->PanelHRS, SiS_Pr->PanelHRE,
+	SiS_Pr->PanelVRS, SiS_Pr->PanelVRE,
+	SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].CLOCK,
+	SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_A,
+	SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_B);
+#endif
+
+   if((ROMAddr = GetLCDStructPtr661(SiS_Pr, HwInfo))) {
+      if((temp = SISGETROMW(6)) != SiS_Pr->PanelHT) {
+         SiS_Pr->SiS_NeedRomModeData = TRUE;
+	 SiS_Pr->PanelHT  = temp;
+      }
+      if((temp = SISGETROMW(8)) != SiS_Pr->PanelVT) {
+         SiS_Pr->SiS_NeedRomModeData = TRUE;
+         SiS_Pr->PanelVT  = temp;
+      }
+      SiS_Pr->PanelHRS = SISGETROMW(10);
+      SiS_Pr->PanelHRE = SISGETROMW(12);
+      SiS_Pr->PanelVRS = SISGETROMW(14);
+      SiS_Pr->PanelVRE = SISGETROMW(16);
+      SiS_Pr->PanelVCLKIdx315 = VCLK_CUSTOM_315;
+      SiS_Pr->SiS_VCLKData[VCLK_CUSTOM_315].CLOCK =
+	 SiS_Pr->SiS_VBVCLKData[VCLK_CUSTOM_315].CLOCK = (USHORT)((UCHAR)ROMAddr[18]);
+      SiS_Pr->SiS_VCLKData[VCLK_CUSTOM_315].SR2B =
+	 SiS_Pr->SiS_VBVCLKData[VCLK_CUSTOM_315].Part4_A = ROMAddr[19];
+      SiS_Pr->SiS_VCLKData[VCLK_CUSTOM_315].SR2C =
+	 SiS_Pr->SiS_VBVCLKData[VCLK_CUSTOM_315].Part4_B = ROMAddr[20];
+
+#ifdef TWDEBUG
+      xf86DrvMsg(0, X_INFO, "Paneldata BIOS:  [%d %d] [H %d %d] [V %d %d] [C %d 0x%02x 0x%02x]\n",
+      	SiS_Pr->PanelHT, SiS_Pr->PanelVT,
+	SiS_Pr->PanelHRS, SiS_Pr->PanelHRE,
+	SiS_Pr->PanelVRS, SiS_Pr->PanelVRE,
+	SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].CLOCK,
+	SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_A,
+	SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_B);
+#endif
+
+   }
+#endif
+}
+
+static void
+SiS_CheckScaling(SiS_Private *SiS_Pr, USHORT resinfo, const UCHAR *nonscalingmodes)
+{
+    int i = 0;
+    while(nonscalingmodes[i] != 0xff) {
+        if(nonscalingmodes[i++] == resinfo) {
+	   if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) ||
+	      (SiS_Pr->UsePanelScaler == -1)) {
+	      SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
+	   }
+	   break;
+	}
+    }
+}
+
+void
+SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+		  PSIS_HW_INFO HwInfo)
+{
+#ifdef SIS300
+  UCHAR *ROMAddr = HwInfo->pjVirtualRomBase;
+  const unsigned char SiS300SeriesLCDRes[] =
+          { 0,  1,  2,  3,  7,  4,  5,  8,
+	    0,  0, 10,  0,  0,  0,  0, 15 };
+#endif
+#ifdef SIS315H
+  UCHAR   *myptr = NULL;
+#endif
+  USHORT  temp,modeflag,resinfo=0,modexres=0,modeyres=0;
+  BOOLEAN panelcanscale = FALSE;
+
+  SiS_Pr->SiS_LCDResInfo  = 0;
+  SiS_Pr->SiS_LCDTypeInfo = 0;
+  SiS_Pr->SiS_LCDInfo     = 0;
+  SiS_Pr->PanelHRS        = 999; /* HSync start */
+  SiS_Pr->PanelHRE        = 999; /* HSync end */
+  SiS_Pr->PanelVRS        = 999; /* VSync start */
+  SiS_Pr->PanelVRE        = 999; /* VSync end */
+  SiS_Pr->SiS_NeedRomModeData = FALSE;
+
+  if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA))) return;
+
+  if(ModeNo <= 0x13) {
+     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  } else if(SiS_Pr->UseCustomMode) {
+     modeflag = SiS_Pr->CModeFlag;
+  } else {
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+     resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+     modexres = SiS_Pr->SiS_ModeResInfo[resinfo].HTotal;
+     modeyres = SiS_Pr->SiS_ModeResInfo[resinfo].VTotal;
+  }
+
+  temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36);
+
+  /* For broken BIOSes: Assume 1024x768 */
+  if(temp == 0) temp = 0x02;
+
+  if((HwInfo->jChipType >= SIS_661) || (SiS_Pr->SiS_ROMNew)) {
+     SiS_Pr->SiS_LCDTypeInfo = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x39) & 0x7c) >> 2;
+  } else if((HwInfo->jChipType < SIS_315H) || (HwInfo->jChipType >= SIS_661)) {
+     SiS_Pr->SiS_LCDTypeInfo = temp >> 4;
+  } else {
+     SiS_Pr->SiS_LCDTypeInfo = (temp & 0x0F) - 1;
+  }
+  temp &= 0x0f;
+#ifdef SIS300
+  if(HwInfo->jChipType < SIS_315H) {
+     /* Very old BIOSes only know 7 sizes (NetVista 2179, 1.01g) */
+     if(SiS_Pr->SiS_VBType & VB_SIS301) {
+        if(temp < 0x0f) temp &= 0x07;
+     }
+     /* Translate 300 series LCDRes to 315 series for unified usage */
+     temp = SiS300SeriesLCDRes[temp];
+  }
+#endif
+
+  /* Translate to our internal types */
+  if(HwInfo->jChipType == SIS_550) {
+     if(temp == Panel310_640x480_2) temp = Panel_640x480_2;
+     if(temp == Panel310_640x480_3) temp = Panel_640x480_3;
+  }
+
+  if(SiS_Pr->SiS_VBType & VB_SISLVDS) {	/* SiS LVDS */
+     if(temp == Panel310_1280x768) {
+        temp = Panel_1280x768_2;
+     }
+     if(SiS_Pr->SiS_ROMNew) {
+        if(temp == Panel661_1280x800) {
+	   temp = Panel_1280x800_2;
+	}
+     }
+  }
+
+  SiS_Pr->SiS_LCDResInfo = temp;
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+     if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) {
+        SiS_Pr->SiS_LCDResInfo = Panel_Barco1366;
+     } else if(SiS_Pr->SiS_CustomT == CUT_PANEL848) {
+        SiS_Pr->SiS_LCDResInfo = Panel_848x480;
+     }
+  }
+
+  if(SiS_Pr->SiS_VBType & VB_SISVB) {
+     if(SiS_Pr->SiS_LCDResInfo < SiS_Pr->SiS_PanelMin301)
+	SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_PanelMin301;
+  } else {
+     if(SiS_Pr->SiS_LCDResInfo < SiS_Pr->SiS_PanelMinLVDS)
+	SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_PanelMinLVDS;
+  }
+
+  temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37);
+  SiS_Pr->SiS_LCDInfo = temp & ~0x000e;
+  /* Need temp below! */
+
+  /* These can't scale no matter what */
+  switch(SiS_Pr->SiS_LCDResInfo) {
+  case Panel_1280x960:
+      SiS_Pr->SiS_LCDInfo &= ~DontExpandLCD;
+  }
+
+  panelcanscale = (SiS_Pr->SiS_LCDInfo & DontExpandLCD) ? TRUE : FALSE;
+
+  if(!SiS_Pr->UsePanelScaler)          SiS_Pr->SiS_LCDInfo &= ~DontExpandLCD;
+  else if(SiS_Pr->UsePanelScaler == 1) SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
+
+  /* Dual link, Pass 1:1 BIOS default, etc. */
+#ifdef SIS315H
+  if(HwInfo->jChipType >= SIS_661) {
+     if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+        if(temp & 0x08) SiS_Pr->SiS_LCDInfo |= LCDPass11;
+     }
+     if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
+        if(SiS_Pr->SiS_ROMNew) {
+	   if(temp & 0x02) SiS_Pr->SiS_LCDInfo |= LCDDualLink;
+	} else if((myptr = GetLCDStructPtr661(SiS_Pr, HwInfo))) {
+           if(myptr[2] & 0x01) SiS_Pr->SiS_LCDInfo |= LCDDualLink;
+	}
+     }
+  } else if(HwInfo->jChipType >= SIS_315H) {
+     if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+        if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x39) & 0x01) SiS_Pr->SiS_LCDInfo |= LCDPass11;
+     }
+     if((SiS_Pr->SiS_ROMNew) && (!(SiS_Pr->PanelSelfDetected))) {
+        SiS_Pr->SiS_LCDInfo &= ~(LCDRGB18Bit);
+	temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
+        if(temp & 0x01) SiS_Pr->SiS_LCDInfo |= LCDRGB18Bit;
+	if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
+	   if(temp & 0x02) SiS_Pr->SiS_LCDInfo |= LCDDualLink;
+	}
+     } else if(!(SiS_Pr->SiS_ROMNew)) {
+        if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
+           if((SiS_Pr->SiS_CustomT == CUT_CLEVO1024) &&
+	      (SiS_Pr->SiS_LCDResInfo == Panel_1024x768)) {
+	      SiS_Pr->SiS_LCDInfo |= LCDDualLink;
+	   }
+           if((SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) ||
+	      (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) ||
+              (SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) ||
+	      (SiS_Pr->SiS_LCDResInfo == Panel_1680x1050)) {
+	      SiS_Pr->SiS_LCDInfo |= LCDDualLink;
+	   }
+        }
+     }
+  }
+#endif
+
+  /* Pass 1:1 */
+  if((SiS_Pr->SiS_IF_DEF_LVDS == 1) || (SiS_Pr->SiS_VBType & VB_NoLCD)) {
+     /* Always center screen on LVDS (if scaling is disabled) */
+     SiS_Pr->SiS_LCDInfo &= ~LCDPass11;
+  } else if(SiS_Pr->SiS_VBType & VB_SISVB) {
+     if(SiS_Pr->SiS_VBType & VB_SISLVDS) {
+        /* Always center screen on SiS LVDS (if scaling is disabled) */
+        SiS_Pr->SiS_LCDInfo &= ~LCDPass11;
+     } else {
+        /* By default, pass 1:1 on SiS TMDS (if scaling is supported) */
+        if(panelcanscale)             SiS_Pr->SiS_LCDInfo |= LCDPass11;
+        if(SiS_Pr->CenterScreen == 1) SiS_Pr->SiS_LCDInfo &= ~LCDPass11;
+     }
+  }
+
+  SiS_Pr->PanelVCLKIdx300 = VCLK65_300;
+  SiS_Pr->PanelVCLKIdx315 = VCLK108_2_315;
+
+  switch(SiS_Pr->SiS_LCDResInfo) {
+     case Panel_320x480:    SiS_Pr->PanelXRes =  320; SiS_Pr->PanelYRes =  480;
+     			    SiS_Pr->PanelHT   =  400; SiS_Pr->PanelVT   =  525;
+			    SiS_Pr->PanelVCLKIdx300 = VCLK28;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK28;
+			    break;
+     case Panel_640x480_2:
+     case Panel_640x480_3:  SiS_Pr->PanelXRes =  640; SiS_Pr->PanelYRes =  480;
+     			    SiS_Pr->PanelVRS  =   24; SiS_Pr->PanelVRE  =    3;
+			    SiS_Pr->PanelVCLKIdx300 = VCLK28;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK28;
+			    break;
+     case Panel_640x480:    SiS_Pr->PanelXRes =  640; SiS_Pr->PanelYRes =  480;
+     			    			      SiS_Pr->PanelVRE  =    3;
+			    SiS_Pr->PanelVCLKIdx300 = VCLK28;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK28;
+			    break;
+     case Panel_800x600:    SiS_Pr->PanelXRes =  800; SiS_Pr->PanelYRes =  600;
+     			    SiS_Pr->PanelHT   = 1056; SiS_Pr->PanelVT   =  628;
+			    SiS_Pr->PanelHRS  =   40; SiS_Pr->PanelHRE  =  128;
+			    SiS_Pr->PanelVRS  =    1; SiS_Pr->PanelVRE  =    4;
+			    SiS_Pr->PanelVCLKIdx300 = VCLK40;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK40;
+			    break;
+     case Panel_1024x600:   SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes =  600;
+     			    SiS_Pr->PanelHT   = 1344; SiS_Pr->PanelVT   =  800;
+			    SiS_Pr->PanelHRS  =   24; SiS_Pr->PanelHRE  =  136;
+			    SiS_Pr->PanelVRS  =    2 /* 88 */ ; SiS_Pr->PanelVRE  =    6;
+     			    SiS_Pr->PanelVCLKIdx300 = VCLK65_300;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK65_315;
+     			    break;
+     case Panel_1024x768:   SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes =  768;
+     			    SiS_Pr->PanelHT   = 1344; SiS_Pr->PanelVT   =  806;
+			    SiS_Pr->PanelHRS  =   24; SiS_Pr->PanelHRE  =  136;
+			    SiS_Pr->PanelVRS  =    3; SiS_Pr->PanelVRE  =    6;
+			    if(HwInfo->jChipType < SIS_315H) {
+			       SiS_Pr->PanelHRS = 23;
+			       			      SiS_Pr->PanelVRE  =    5;
+			    }
+			    SiS_Pr->PanelVCLKIdx300 = VCLK65_300;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK65_315;
+			    SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo);
+			    break;
+     case Panel_1152x768:   SiS_Pr->PanelXRes = 1152; SiS_Pr->PanelYRes =  768;
+     			    SiS_Pr->PanelHT   = 1344; SiS_Pr->PanelVT   =  806;
+			    SiS_Pr->PanelHRS  =   24;
+			    SiS_Pr->PanelVRS  =    3; SiS_Pr->PanelVRE  =    6;
+			    if(HwInfo->jChipType < SIS_315H) {
+			       SiS_Pr->PanelHRS = 23;
+			       			      SiS_Pr->PanelVRE  =    5;
+			    }
+     			    SiS_Pr->PanelVCLKIdx300 = VCLK65_300;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK65_315;
+     			    break;
+     case Panel_1152x864:   SiS_Pr->PanelXRes = 1152; SiS_Pr->PanelYRes =  864;
+     			    break;
+     case Panel_1280x720:   SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes =  720;
+     			    SiS_Pr->PanelHT   = 1650; SiS_Pr->PanelVT   =  750;
+			    SiS_Pr->PanelHRS  =  110; SiS_Pr->PanelHRE  =   40;
+			    SiS_Pr->PanelVRS  =    5; SiS_Pr->PanelVRE  =    5;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK_1280x720;
+			    /* Data above for TMDS (projector); get from BIOS for LVDS */
+			    SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo);
+			    break;
+     case Panel_1280x768:   SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes =  768;
+     			    if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+			       SiS_Pr->PanelHT   = 1408; SiS_Pr->PanelVT   =  806;
+			       SiS_Pr->PanelVCLKIdx300 = VCLK81_300; /* ? */
+			       SiS_Pr->PanelVCLKIdx315 = VCLK81_315; /* ? */
+			    } else {
+     			       SiS_Pr->PanelHT   = 1688; SiS_Pr->PanelVT   =  802;
+			       SiS_Pr->PanelHRS  =   48; SiS_Pr->PanelHRS  =  112;
+			       SiS_Pr->PanelVRS  =    3; SiS_Pr->PanelVRE  =    6;
+			       SiS_Pr->PanelVCLKIdx300 = VCLK81_300;
+			       SiS_Pr->PanelVCLKIdx315 = VCLK81_315;
+			    }
+			    break;
+     case Panel_1280x768_2: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes =  768;
+     			    SiS_Pr->PanelHT   = 1660; SiS_Pr->PanelVT   =  806;
+			    SiS_Pr->PanelHRS  =   48; SiS_Pr->PanelHRE  =  112;
+			    SiS_Pr->PanelVRS  =    3; SiS_Pr->PanelVRE  =    6;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK_1280x768_2;
+			    SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo);
+			    break;
+     case Panel_1280x800:   SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes =  800;
+     			    SiS_Pr->PanelHT   = 1408; SiS_Pr->PanelVT   =  816;
+			    SiS_Pr->PanelHRS   =  21; SiS_Pr->PanelHRE  =   24;
+			    SiS_Pr->PanelVRS   =   4; SiS_Pr->PanelVRE  =    3;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK_1280x800_315;
+			    SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo);
+			    break;
+     case Panel_1280x800_2: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes =  800;
+     			    SiS_Pr->PanelHT   = 1552; SiS_Pr->PanelVT   =  812;
+			    SiS_Pr->PanelHRS   =  48; SiS_Pr->PanelHRE  =  112;
+			    SiS_Pr->PanelVRS   =   4; SiS_Pr->PanelVRE  =    3;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK_1280x800_315_2;
+			    SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo);
+			    break;
+     case Panel_1280x960:   SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes =  960;
+     			    SiS_Pr->PanelHT   = 1800; SiS_Pr->PanelVT   = 1000;
+			    SiS_Pr->PanelVCLKIdx300 = VCLK108_3_300;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK108_3_315;
+		 	    if(resinfo == SIS_RI_1280x1024) {
+			       SiS_Pr->PanelVCLKIdx300 = VCLK100_300;
+			       SiS_Pr->PanelVCLKIdx315 = VCLK100_315;
+			    }
+			    break;
+     case Panel_1280x1024:  SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 1024;
+     			    SiS_Pr->PanelHT   = 1688; SiS_Pr->PanelVT   = 1066;
+			    SiS_Pr->PanelHRS  =   48; SiS_Pr->PanelHRE  =  112;
+			    SiS_Pr->PanelVRS  =    1; SiS_Pr->PanelVRE  =    3;
+			    SiS_Pr->PanelVCLKIdx300 = VCLK108_3_300;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK108_2_315;
+			    SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo);
+			    break;
+     case Panel_1400x1050:  SiS_Pr->PanelXRes = 1400; SiS_Pr->PanelYRes = 1050;
+     			    SiS_Pr->PanelHT   = 1688; SiS_Pr->PanelVT   = 1066;
+			    SiS_Pr->PanelHRS  =   48; SiS_Pr->PanelHRE  =  112; /* HRE OK for LVDS, not for LCDA */
+			    SiS_Pr->PanelVRS  =    1; SiS_Pr->PanelVRE  =    3;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK108_2_315;
+			    SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo);
+			    break;
+     case Panel_1600x1200:  SiS_Pr->PanelXRes = 1600; SiS_Pr->PanelYRes = 1200;
+     			    SiS_Pr->PanelHT   = 2160; SiS_Pr->PanelVT   = 1250;
+			    SiS_Pr->PanelHRS  =   64; SiS_Pr->PanelHRE  =  192;
+			    SiS_Pr->PanelVRS  =    1; SiS_Pr->PanelVRE  =    3;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK162_315;
+			    SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo);
+			    break;
+     case Panel_1680x1050:  SiS_Pr->PanelXRes = 1680; SiS_Pr->PanelYRes = 1050;
+     			    SiS_Pr->PanelHT   = 1900; SiS_Pr->PanelVT   = 1066;
+			    SiS_Pr->PanelHRS  =   26; SiS_Pr->PanelHRE  =   76;
+			    SiS_Pr->PanelVRS  =    3; SiS_Pr->PanelVRE  =    6;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK121_315;
+			    SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo);
+			    break;
+     case Panel_Barco1366:  SiS_Pr->PanelXRes = 1360; SiS_Pr->PanelYRes = 1024;
+     			    SiS_Pr->PanelHT   = 1688; SiS_Pr->PanelVT   = 1066;
+     			    break;
+     case Panel_848x480:    SiS_Pr->PanelXRes =  848; SiS_Pr->PanelYRes =  480;
+     			    SiS_Pr->PanelHT   = 1088; SiS_Pr->PanelVT   =  525;
+     			    break;
+     case Panel_Custom:     SiS_Pr->PanelXRes = SiS_Pr->CP_MaxX;
+    			    SiS_Pr->PanelYRes = SiS_Pr->CP_MaxY;
+			    SiS_Pr->PanelHT   = SiS_Pr->CHTotal;
+			    SiS_Pr->PanelVT   = SiS_Pr->CVTotal;
+			    if(SiS_Pr->CP_PreferredIndex != -1) {
+			       SiS_Pr->PanelXRes = SiS_Pr->CP_HDisplay[SiS_Pr->CP_PreferredIndex];
+    			       SiS_Pr->PanelYRes = SiS_Pr->CP_VDisplay[SiS_Pr->CP_PreferredIndex];
+			       SiS_Pr->PanelHT   = SiS_Pr->CP_HTotal[SiS_Pr->CP_PreferredIndex];
+			       SiS_Pr->PanelVT   = SiS_Pr->CP_VTotal[SiS_Pr->CP_PreferredIndex];
+			       SiS_Pr->PanelHRS  = SiS_Pr->CP_HSyncStart[SiS_Pr->CP_PreferredIndex];
+			       SiS_Pr->PanelHRE  = SiS_Pr->CP_HSyncEnd[SiS_Pr->CP_PreferredIndex];
+			       SiS_Pr->PanelVRS  = SiS_Pr->CP_VSyncStart[SiS_Pr->CP_PreferredIndex];
+			       SiS_Pr->PanelVRE  = SiS_Pr->CP_VSyncEnd[SiS_Pr->CP_PreferredIndex];
+			       SiS_Pr->PanelHRS -= SiS_Pr->PanelXRes;
+			       SiS_Pr->PanelHRE -= SiS_Pr->PanelHRS;
+			       SiS_Pr->PanelVRS -= SiS_Pr->PanelYRes;
+			       SiS_Pr->PanelVRE -= SiS_Pr->PanelVRS;
+			       if(SiS_Pr->CP_PrefClock) {
+			          int idx;
+			          SiS_Pr->PanelVCLKIdx315 = VCLK_CUSTOM_315;
+				  SiS_Pr->PanelVCLKIdx300 = VCLK_CUSTOM_300;
+				  if(HwInfo->jChipType < SIS_315H) idx = VCLK_CUSTOM_300;
+				  else				   idx = VCLK_CUSTOM_315;
+      			          SiS_Pr->SiS_VCLKData[idx].CLOCK =
+	 		             SiS_Pr->SiS_VBVCLKData[idx].CLOCK = SiS_Pr->CP_PrefClock;
+      			          SiS_Pr->SiS_VCLKData[idx].SR2B =
+  	 			     SiS_Pr->SiS_VBVCLKData[idx].Part4_A = SiS_Pr->CP_PrefSR2B;
+      			          SiS_Pr->SiS_VCLKData[idx].SR2C =
+	 			     SiS_Pr->SiS_VBVCLKData[idx].Part4_B = SiS_Pr->CP_PrefSR2C;
+			       }
+			    }
+			    break;
+     default:		    SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes =  768;
+     			    SiS_Pr->PanelHT   = 1344; SiS_Pr->PanelVT   =  806;
+			    break;
+  }
+
+  /* Special cases */
+  if( (SiS_Pr->SiS_IF_DEF_FSTN)              ||
+      (SiS_Pr->SiS_IF_DEF_DSTN)              ||
+      (SiS_Pr->SiS_CustomT == CUT_BARCO1366) ||
+      (SiS_Pr->SiS_CustomT == CUT_BARCO1024) ||
+      (SiS_Pr->SiS_CustomT == CUT_PANEL848) ) {
+     SiS_Pr->PanelHRS = 999;
+     SiS_Pr->PanelHRE = 999;
+  }
+
+  if( (SiS_Pr->SiS_CustomT == CUT_BARCO1366) ||
+      (SiS_Pr->SiS_CustomT == CUT_BARCO1024) ||
+      (SiS_Pr->SiS_CustomT == CUT_PANEL848) ) {
+     SiS_Pr->PanelVRS = 999;
+     SiS_Pr->PanelVRE = 999;
+  }
+
+  /* DontExpand overrule */
+  if((SiS_Pr->SiS_VBType & VB_SISVB) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) {
+
+     if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (modeflag & NoSupportLCDScale)) {
+	/* No scaling for this mode on any panel (LCD=CRT2)*/
+	SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
+     }
+
+     switch(SiS_Pr->SiS_LCDResInfo) {
+
+     case Panel_Custom:
+     case Panel_1152x864:
+     case Panel_1280x768:	/* TMDS only */
+        SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
+	break;
+
+     case Panel_800x600: {
+        static const UCHAR nonscalingmodes[] = {
+	   SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, 0xff
+	};
+	SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes);
+	break;
+     }
+     case Panel_1024x768: {
+        static const UCHAR nonscalingmodes[] = {
+	   SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480,
+	   SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600,
+	   0xff
+	};
+	SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes);
+	break;
+     }
+     case Panel_1280x720: {
+        static const UCHAR nonscalingmodes[] = {
+	   SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480,
+	   SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600,
+	   0xff
+	};
+	SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes);
+	if(SiS_Pr->PanelHT == 1650) {
+	   SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
+	}
+	break;
+     }
+     case Panel_1280x768_2: {  /* LVDS only */
+        static const UCHAR nonscalingmodes[] = {
+	   SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480,
+	   SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600,
+	   SIS_RI_1152x768,0xff
+	};
+	SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes);
+	switch(resinfo) {
+	case SIS_RI_1280x720:  if(SiS_Pr->UsePanelScaler == -1) {
+	      			  SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
+	   		       }
+	   		       break;
+	}
+        break;
+     }
+     case Panel_1280x800: {  	/* SiS TMDS special (Averatec 6200 series) */
+        static const UCHAR nonscalingmodes[] = {
+	   SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480,
+	   SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600,
+	   SIS_RI_1152x768,SIS_RI_1280x720,SIS_RI_1280x768,0xff
+	};
+	SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes);
+        break;
+     }
+     case Panel_1280x800_2:  { 	/* SiS LVDS */
+        static const UCHAR nonscalingmodes[] = {
+	   SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480,
+	   SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600,
+	   SIS_RI_1152x768,0xff
+	};
+	SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes);
+	switch(resinfo) {
+	case SIS_RI_1280x720:
+	case SIS_RI_1280x768:  if(SiS_Pr->UsePanelScaler == -1) {
+	      			  SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
+	   		       }
+	   		       break;
+	}
+        break;
+     }
+     case Panel_1280x960: {
+        static const UCHAR nonscalingmodes[] = {
+	   SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480,
+	   SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600,
+	   SIS_RI_1152x768,SIS_RI_1152x864,SIS_RI_1280x720,SIS_RI_1280x768,SIS_RI_1280x800,
+	   0xff
+	};
+	SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes);
+        break;
+     }
+     case Panel_1280x1024: {
+        static const UCHAR nonscalingmodes[] = {
+	   SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480,
+	   SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600,
+	   SIS_RI_1152x768,SIS_RI_1152x864,SIS_RI_1280x720,SIS_RI_1280x768,SIS_RI_1280x800,
+	   SIS_RI_1280x960,0xff
+	};
+	SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes);
+	break;
+     }
+     case Panel_1400x1050: {
+        static const UCHAR nonscalingmodes[] = {
+	     SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480,
+	     SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600,
+	     SIS_RI_1152x768,SIS_RI_1152x864,SIS_RI_1280x768,SIS_RI_1280x800,SIS_RI_1280x960,
+	     0xff
+	};
+	SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes);
+        switch(resinfo) {
+	case SIS_RI_1280x720:  if(SiS_Pr->UsePanelScaler == -1) {
+	      			  SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
+	   		       }
+	   		       break;
+	case SIS_RI_1280x1024: SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
+	      		       break;
+	}
+	break;
+     }
+     case Panel_1600x1200: {
+        static const UCHAR nonscalingmodes[] = {
+	     SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480,
+	     SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600,
+	     SIS_RI_1152x768,SIS_RI_1152x864,SIS_RI_1280x720,SIS_RI_1280x768,SIS_RI_1280x800,
+	     SIS_RI_1280x960,SIS_RI_1360x768,SIS_RI_1360x1024,0xff
+	};
+	SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes);
+        break;
+     }
+     case Panel_1680x1050: {
+        static const UCHAR nonscalingmodes[] = {
+	     SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480,
+	     SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600,
+	     SIS_RI_1152x768,SIS_RI_1152x864,SIS_RI_1280x960,SIS_RI_1360x768,SIS_RI_1360x1024,
+	     0xff
+	};
+	SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes);
+	break;
+     }
+     }
+  }
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+     if(SiS_Pr->SiS_CustomT == CUT_PANEL848) {
+        SiS_Pr->SiS_LCDInfo = 0x80 | 0x40 | 0x20;   /* neg h/v sync, RGB24(D0 = 0) */
+     }
+  }
+
+#ifdef SIS300
+  if(HwInfo->jChipType < SIS_315H) {
+     if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+        if(SiS_Pr->SiS_UseROM) {
+	   if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) {
+              if(!(ROMAddr[0x235] & 0x02)) {
+	         SiS_Pr->SiS_LCDInfo &= (~DontExpandLCD);
+ 	      }
+	   }
+        }
+     } else if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+	if((SiS_Pr->SiS_SetFlag & SetDOSMode) && ((ModeNo == 0x03) || (ModeNo == 0x10))) {
+           SiS_Pr->SiS_LCDInfo &= (~DontExpandLCD);
+	}
+     }
+  }
+#endif
+
+  /* Special cases */
+
+  if(modexres == SiS_Pr->PanelXRes && modeyres == SiS_Pr->PanelYRes) {
+     SiS_Pr->SiS_LCDInfo &= ~LCDPass11;
+  }
+
+  if(SiS_Pr->SiS_IF_DEF_TRUMPION) {
+     SiS_Pr->SiS_LCDInfo |= (DontExpandLCD | LCDPass11);
+  }
+
+  switch(SiS_Pr->SiS_LCDResInfo) {
+  case Panel_640x480:
+     SiS_Pr->SiS_LCDInfo |= LCDPass11;
+     break;
+  case Panel_1280x800:
+     /* Don't pass 1:1 by default (TMDS special) */
+     if(SiS_Pr->CenterScreen == -1) SiS_Pr->SiS_LCDInfo &= ~LCDPass11;
+     break;
+  case Panel_1280x960:
+     SiS_Pr->SiS_LCDInfo &= ~LCDPass11;
+     break;
+  case Panel_Custom:
+     if((!SiS_Pr->CP_PrefClock) ||
+        (modexres > SiS_Pr->PanelXRes) || (modeyres > SiS_Pr->PanelYRes)) {
+        SiS_Pr->SiS_LCDInfo |= LCDPass11;
+     }
+     break;
+  }
+
+  if(SiS_Pr->UseCustomMode) {
+     SiS_Pr->SiS_LCDInfo |= (DontExpandLCD | LCDPass11);
+  }
+
+  /* (In)validate LCDPass11 flag */
+  if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
+     SiS_Pr->SiS_LCDInfo &= ~LCDPass11;
+  }
+
+  /* LVDS DDA */
+  if(!((HwInfo->jChipType < SIS_315H) && (SiS_Pr->SiS_SetFlag & SetDOSMode))) {
+
+     if((SiS_Pr->SiS_IF_DEF_LVDS == 1) || (SiS_Pr->SiS_VBType & VB_NoLCD)) {
+	if(SiS_Pr->SiS_IF_DEF_TRUMPION == 0) {
+	   if(ModeNo == 0x12) {
+	      if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
+	         SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+	      }
+	   } else if(ModeNo > 0x13) {
+	      if(SiS_Pr->SiS_LCDResInfo == Panel_1024x600) {
+	         if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
+	            if((resinfo == SIS_RI_800x600) || (resinfo == SIS_RI_400x300)) {
+                       SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+		    }
+		 }
+	      }
+	   }
+	}
+     }
+
+     if(modeflag & HalfDCLK) {
+        if(SiS_Pr->SiS_IF_DEF_TRUMPION == 1) {
+	   SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+        } else if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+	   SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+	} else if(SiS_Pr->SiS_LCDResInfo == Panel_640x480) {
+	   SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+	} else if(ModeNo > 0x13) {
+           if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+              if(resinfo == SIS_RI_512x384) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+           } else if(SiS_Pr->SiS_LCDResInfo == Panel_800x600) {
+              if(resinfo == SIS_RI_400x300) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+           }
+	}
+     }
+
+  }
+
+  /* VESA timing */
+  if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+     if(SiS_Pr->SiS_VBInfo & SetNotSimuMode) {
+     	SiS_Pr->SiS_SetFlag |= LCDVESATiming;
+     }
+  } else {
+     SiS_Pr->SiS_SetFlag |= LCDVESATiming;
+  }
+
+#ifdef LINUX_KERNEL
+#ifdef TWDEBUG
+  printk(KERN_DEBUG "sisfb: (LCDInfo=0x%04x LCDResInfo=0x%02x LCDTypeInfo=0x%02x)\n",
+	SiS_Pr->SiS_LCDInfo, SiS_Pr->SiS_LCDResInfo, SiS_Pr->SiS_LCDTypeInfo);
+#endif
+#endif
+#ifdef LINUX_XF86
+  xf86DrvMsgVerb(0, X_PROBED, 4,
+  	"(init301: LCDInfo=0x%04x LCDResInfo=0x%02x LCDTypeInfo=0x%02x SetFlag=0x%04x)\n",
+	SiS_Pr->SiS_LCDInfo, SiS_Pr->SiS_LCDResInfo, SiS_Pr->SiS_LCDTypeInfo, SiS_Pr->SiS_SetFlag);
+#endif
+}
+
+/*********************************************/
+/*                 GET VCLK                  */
+/*********************************************/
+
+USHORT
+SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+                USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo)
+{
+  USHORT CRT2Index,VCLKIndex=0,VCLKIndexGEN=0;
+  USHORT modeflag,resinfo,tempbx;
+  const UCHAR *CHTVVCLKPtr = NULL;
+
+  if(ModeNo <= 0x13) {
+     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+     resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+     CRT2Index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+     VCLKIndexGEN = (SiS_GetRegByte((SiS_Pr->SiS_P3ca+0x02)) >> 2) & 0x03;
+  } else {
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+     resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+     CRT2Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+     VCLKIndexGEN = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+     if(HwInfo->jChipType < SIS_315H) VCLKIndexGEN &= 0x3f;
+  }
+
+  if(SiS_Pr->SiS_VBType & VB_SISVB) {    /* 30x/B/LV */
+
+     if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) {
+
+        CRT2Index >>= 6;
+        if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {      	/*  LCD */
+
+           if(HwInfo->jChipType < SIS_315H) {
+	      VCLKIndex = SiS_Pr->PanelVCLKIdx300;
+	      if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (SiS_Pr->SiS_LCDInfo & LCDPass11)) {
+	         VCLKIndex = VCLKIndexGEN;
+	      }
+	   } else {
+	      VCLKIndex = SiS_Pr->PanelVCLKIdx315;
+	      if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (SiS_Pr->SiS_LCDInfo & LCDPass11)) {
+		 switch(resinfo) {
+		 /* Only those whose IndexGEN doesn't match VBVCLK array */
+		 case SIS_RI_1280x720: VCLKIndex = VCLK_1280x720; break;
+		 case SIS_RI_720x480:  VCLKIndex = VCLK_720x480;  break;
+		 case SIS_RI_720x576:  VCLKIndex = VCLK_720x576;  break;
+		 case SIS_RI_768x576:  VCLKIndex = VCLK_768x576;  break;
+		 case SIS_RI_848x480:  VCLKIndex = VCLK_848x480;  break;
+		 case SIS_RI_856x480:  VCLKIndex = VCLK_856x480;  break;
+		 case SIS_RI_800x480:  VCLKIndex = VCLK_800x480;  break;
+		 case SIS_RI_1024x576: VCLKIndex = VCLK_1024x576; break;
+		 case SIS_RI_1152x864: VCLKIndex = VCLK_1152x864; break;
+		 case SIS_RI_1360x768: VCLKIndex = VCLK_1360x768; break;
+		 default:              VCLKIndex = VCLKIndexGEN;
+		 }
+
+		 if(ModeNo <= 0x13) {
+		    if(HwInfo->jChipType <= SIS_315PRO) {
+		       if(SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC == 1) VCLKIndex = 0x42;
+	            } else {
+		       if(SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC == 1) VCLKIndex = 0x00;
+		    }
+		 }
+		 if(HwInfo->jChipType <= SIS_315PRO) {
+		    if(VCLKIndex == 0) VCLKIndex = 0x41;
+		    if(VCLKIndex == 1) VCLKIndex = 0x43;
+		    if(VCLKIndex == 4) VCLKIndex = 0x44;
+		 }
+	      }
+	   }
+
+        } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {                 	/*  TV */
+
+	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+              if(SiS_Pr->SiS_TVMode & TVRPLLDIV2XO) 		VCLKIndex = HiTVVCLKDIV2;
+     	      else                                  		VCLKIndex = HiTVVCLK;
+              if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) {
+            	 if(modeflag & Charx8Dot) 	    		VCLKIndex = HiTVSimuVCLK;
+            	 else 			  	    		VCLKIndex = HiTVTextVCLK;
+              }
+           } else if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) 	VCLKIndex = YPbPr750pVCLK;
+	   else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p)   	VCLKIndex = TVVCLKDIV2;
+	   else if(SiS_Pr->SiS_TVMode & TVRPLLDIV2XO)     	VCLKIndex = TVVCLKDIV2;
+           else         		            	  	VCLKIndex = TVVCLK;
+
+	   if(HwInfo->jChipType < SIS_315H) VCLKIndex += TVCLKBASE_300;
+  	   else 	                    VCLKIndex += TVCLKBASE_315;
+
+        } else {         						/* VGA2 */
+
+	   VCLKIndex = VCLKIndexGEN;
+	   if(HwInfo->jChipType < SIS_315H) {
+              if(ModeNo > 0x13) {
+		 if( (HwInfo->jChipType == SIS_630) &&
+		     (HwInfo->jChipRevision >= 0x30)) {
+		    if(VCLKIndex == 0x14) VCLKIndex = 0x34;
+		 }
+		 /* Better VGA2 clock for 1280x1024@75 */
+		 if(VCLKIndex == 0x17) VCLKIndex = 0x45;
+	      }
+           }
+        }
+
+     } else {   /* If not programming CRT2 */
+
+        VCLKIndex = VCLKIndexGEN;
+	if(HwInfo->jChipType < SIS_315H) {
+           if(ModeNo > 0x13) {
+	      if( (HwInfo->jChipType != SIS_630) &&
+		  (HwInfo->jChipType != SIS_300) ) {
+		 if(VCLKIndex == 0x1b) VCLKIndex = 0x48;
+	      }
+	   }
+        }
+     }
+
+  } else {       /*   LVDS  */
+
+     VCLKIndex = CRT2Index;
+
+     if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) {
+
+        if( (SiS_Pr->SiS_IF_DEF_CH70xx != 0) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) ) {
+
+	   VCLKIndex &= 0x1f;
+           tempbx = 0;
+	   if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1;
+           if(SiS_Pr->SiS_TVMode & TVSetPAL) {
+	      tempbx += 2;
+	      if(SiS_Pr->SiS_ModeType > ModeVGA) {
+		 if(SiS_Pr->SiS_CHSOverScan) tempbx = 8;
+	      }
+	      if(SiS_Pr->SiS_TVMode & TVSetPALM) {
+		 tempbx = 4;
+		 if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1;
+	      } else if(SiS_Pr->SiS_TVMode & TVSetPALN) {
+		 tempbx = 6;
+		 if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1;
+	      }
+	   }
+       	   switch(tempbx) {
+             case  0: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKUNTSC;  break;
+             case  1: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKONTSC;  break;
+             case  2: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKUPAL;   break;
+             case  3: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKOPAL;   break;
+	     case  4: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKUPALM;  break;
+             case  5: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKOPALM;  break;
+             case  6: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKUPALN;  break;
+             case  7: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKOPALN;  break;
+	     case  8: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKSOPAL;  break;
+	     default: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKOPAL;   break;
+           }
+           VCLKIndex = CHTVVCLKPtr[VCLKIndex];
+
+        } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+
+	   if(HwInfo->jChipType < SIS_315H) {
+	      VCLKIndex = SiS_Pr->PanelVCLKIdx300;
+	   } else {
+	      VCLKIndex = SiS_Pr->PanelVCLKIdx315;
+	   }
+
+	   /* Special Timing: Barco iQ Pro R series */
+	   if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) VCLKIndex = 0x44;
+
+	   /* Special Timing: 848x480 parallel lvds */
+	   if(SiS_Pr->SiS_CustomT == CUT_PANEL848) {
+	      if(HwInfo->jChipType < SIS_315H) {
+		 VCLKIndex = VCLK34_300;
+	         /* if(resinfo == SIS_RI_1360x768) VCLKIndex = ?; */
+	      } else {
+		 VCLKIndex = VCLK34_315;
+		 /* if(resinfo == SIS_RI_1360x768) VCLKIndex = ?; */
+	      }
+	   }
+
+        } else {
+
+	   VCLKIndex = VCLKIndexGEN;
+	   if(HwInfo->jChipType < SIS_315H) {
+              if(ModeNo > 0x13) {
+		 if( (HwInfo->jChipType == SIS_630) &&
+                     (HwInfo->jChipRevision >= 0x30) ) {
+		    if(VCLKIndex == 0x14) VCLKIndex = 0x2e;
+	         }
+              }
+	   }
+        }
+
+     } else {  /* if not programming CRT2 */
+
+        VCLKIndex = VCLKIndexGEN;
+	if(HwInfo->jChipType < SIS_315H) {
+           if(ModeNo > 0x13) {
+	      if( (HwInfo->jChipType != SIS_630) &&
+	          (HwInfo->jChipType != SIS_300) ) {
+		 if(VCLKIndex == 0x1b) VCLKIndex = 0x48;
+	      }
+#if 0
+	      if(HwInfo->jChipType == SIS_730) {
+		 if(VCLKIndex == 0x0b) VCLKIndex = 0x40;   /* 1024x768-70 */
+		 if(VCLKIndex == 0x0d) VCLKIndex = 0x41;   /* 1024x768-75 */
+	      }
+#endif
+	   }
+        }
+
+     }
+
+  }
+
+#ifdef TWDEBUG
+  xf86DrvMsg(0, X_INFO, "VCLKIndex %d (0x%x)\n", VCLKIndex, VCLKIndex);
+#endif
+
+  return(VCLKIndex);
+}
+
+/*********************************************/
+/*        SET CRT2 MODE TYPE REGISTERS       */
+/*********************************************/
+
+static void
+SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+                    PSIS_HW_INFO HwInfo)
+{
+  USHORT i,j,modeflag;
+  USHORT tempcl,tempah=0;
+#if defined(SIS300) || defined(SIS315H)
+  USHORT tempbl;
+#endif
+#ifdef SIS315H
+  UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+  USHORT tempah2, tempbl2;
+#endif
+
+  if(ModeNo <= 0x13) {
+     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  } else if(SiS_Pr->UseCustomMode) {
+     modeflag = SiS_Pr->CModeFlag;
+  } else {
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+  }
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x00,0xAF,0x40);
+     SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2E,0xF7);
+
+  } else {
+
+     for(i=0,j=4; i<3; i++,j++) SiS_SetReg(SiS_Pr->SiS_Part1Port,j,0);
+     if(HwInfo->jChipType >= SIS_315H) {
+        SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0x7F);
+     }
+
+     tempcl = SiS_Pr->SiS_ModeType;
+
+     if(HwInfo->jChipType < SIS_315H) {
+
+#ifdef SIS300    /* ---- 300 series ---- */
+
+        /* For 301BDH: (with LCD via LVDS) */
+        if(SiS_Pr->SiS_VBType & VB_NoLCD) {
+	   tempbl = SiS_GetReg(SiS_Pr->SiS_P3c4,0x32);
+	   tempbl &= 0xef;
+	   tempbl |= 0x02;
+	   if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) || (SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) {
+	      tempbl |= 0x10;
+	      tempbl &= 0xfd;
+	   }
+	   SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,tempbl);
+        }
+
+        if(ModeNo > 0x13) {
+           tempcl -= ModeVGA;
+           if((tempcl > 0) || (tempcl == 0)) {      /* tempcl is USHORT -> always true! */
+              tempah = ((0x10 >> tempcl) | 0x80);
+           }
+        } else tempah = 0x80;
+
+        if(SiS_Pr->SiS_VBInfo & SetInSlaveMode)  tempah ^= 0xA0;
+
+#endif  /* SIS300 */
+
+     } else {
+
+#ifdef SIS315H    /* ------- 315/330 series ------ */
+
+        if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+           if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) {
+	      SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x08);
+           }
+        }
+
+        if(ModeNo > 0x13) {
+           tempcl -= ModeVGA;
+           if((tempcl > 0) || (tempcl == 0)) {  /* tempcl is USHORT -> always true! */
+              tempah = (0x08 >> tempcl);
+              if (tempah == 0) tempah = 1;
+              tempah |= 0x40;
+           }
+        } else tempah = 0x40;
+
+        if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) tempah ^= 0x50;
+
+#endif  /* SIS315H */
+
+     }
+
+     if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 0;
+
+     if(HwInfo->jChipType < SIS_315H) {
+        SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,tempah);
+     } else {
+        if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+           SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x00,0xa0,tempah);
+        } else if(SiS_Pr->SiS_VBType & VB_SISVB) {
+           if(IS_SIS740) {
+	      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,tempah);
+	   } else {
+              SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x00,0xa0,tempah);
+	   }
+        }
+     }
+
+     if(SiS_Pr->SiS_VBType & VB_SISVB) {
+
+        tempah = 0x01;
+        if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+      	   tempah |= 0x02;
+        }
+        if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) {
+      	   tempah ^= 0x05;
+      	   if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
+              tempah ^= 0x01;
+      	   }
+        }
+
+        if(SiS_Pr->SiS_VBInfo & DisableCRT2Display)  tempah = 0;
+
+        if(HwInfo->jChipType < SIS_315H) {
+
+      	   tempah = (tempah << 5) & 0xFF;
+      	   SiS_SetReg(SiS_Pr->SiS_Part1Port,0x01,tempah);
+      	   tempah = (tempah >> 5) & 0xFF;
+
+        } else {
+
+      	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2E,0xF8,tempah);
+
+        }
+
+        if((SiS_Pr->SiS_ModeType == ModeVGA) && (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode))) {
+      	   tempah |= 0x10;
+        }
+
+	tempah |= 0x80;
+        if(SiS_Pr->SiS_VBType & VB_SIS301) {
+	   if(SiS_Pr->PanelXRes < 1280 && SiS_Pr->PanelYRes < 960) tempah &= ~0x80;
+        }
+
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+	   if(!(SiS_Pr->SiS_TVMode & (TVSetYPbPr750p | TVSetYPbPr525p))) {
+      	      if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+                 tempah |= 0x20;
+	      }
+      	   }
+        }
+
+        SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0D,0x40,tempah);
+
+	tempah = 0x80;
+	if(SiS_Pr->SiS_VBType & VB_SIS301) {
+	   if(SiS_Pr->PanelXRes < 1280 && SiS_Pr->PanelYRes < 960) tempah = 0;
+	}
+
+	if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempah |= 0x40;
+
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+	   if(SiS_Pr->SiS_TVMode & TVRPLLDIV2XO) {
+              tempah |= 0x40;
+       	   }
+        }
+
+        SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0C,tempah);
+
+     } else {  /* LVDS */
+
+        if(HwInfo->jChipType >= SIS_315H) {
+
+#ifdef SIS315H
+	   /* LVDS can only be slave in 8bpp modes */
+	   tempah = 0x80;
+	   if((modeflag & CRT2Mode) && (SiS_Pr->SiS_ModeType > ModeVGA)) {
+	      if(SiS_Pr->SiS_VBInfo & DriverMode) {
+	         tempah |= 0x02;
+	      }
+	   }
+
+	   if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+              tempah |= 0x02;
+    	   }
+
+	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+	      tempah ^= 0x01;
+	   }
+
+	   if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) {
+	      tempah = 1;
+	   }
+
+    	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2e,0xF0,tempah);
+#endif
+
+        } else {
+
+#ifdef SIS300
+	   tempah = 0;
+	   if( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) && (SiS_Pr->SiS_ModeType > ModeVGA) ) {
+              tempah |= 0x02;
+    	   }
+	   tempah <<= 5;
+
+	   if(SiS_Pr->SiS_VBInfo & DisableCRT2Display)  tempah = 0;
+
+	   SiS_SetReg(SiS_Pr->SiS_Part1Port,0x01,tempah);
+#endif
+
+        }
+
+     }
+
+  }  /* LCDA */
+
+  if(SiS_Pr->SiS_VBType & VB_SISVB) {
+
+     if(HwInfo->jChipType >= SIS_315H) {
+
+#ifdef SIS315H
+        unsigned char bridgerev = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01);
+
+	/* The following is nearly unpreditable and varies from machine
+	 * to machine. Especially the 301DH seems to be a real trouble
+	 * maker. Some BIOSes simply set the registers (like in the
+	 * NoLCD-if-statements here), some set them according to the
+	 * LCDA stuff. It is very likely that some machines are not
+	 * treated correctly in the following, very case-orientated
+	 * code. What do I do then...?
+	 */
+
+	/* 740 variants match for 30xB, 301B-DH, 30xLV */
+
+        if(!(IS_SIS740)) {
+           tempah = 0x04;						   /* For all bridges */
+           tempbl = 0xfb;
+           if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+              tempah = 0x00;
+	      if(SiS_IsDualEdge(SiS_Pr, HwInfo)) {
+	         tempbl = 0xff;
+	      }
+           }
+           SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,tempbl,tempah);
+	}
+
+	/* The following two are responsible for eventually wrong colors
+	 * in TV output. The DH (VB_NoLCD) conditions are unknown; the
+	 * b0 was found in some 651 machine (Pim; P4_23=0xe5); the b1 version
+	 * in a 650 box (Jake). What is the criteria?
+	 */
+
+	if((IS_SIS740) || (HwInfo->jChipType >= SIS_661) || (SiS_Pr->SiS_ROMNew)) {
+	   tempah = 0x30;
+	   tempbl = 0xc0;
+	   if((SiS_Pr->SiS_VBInfo & DisableCRT2Display) ||
+	      ((SiS_Pr->SiS_ROMNew) && (!(ROMAddr[0x5b] & 0x04)))) {
+	      tempah = 0x00;
+	      tempbl = 0x00;
+	   }
+	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2c,0xcf,tempah);
+	   SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,0x3f,tempbl);
+	} else if(SiS_Pr->SiS_VBType & VB_SIS301) {
+	   /* Fixes "TV-blue-bug" on 315+301 */
+	   SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2c,0xcf);     /* For 301   */
+	   SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x21,0x3f);
+	} else if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+	   SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2c,0x30);      /* For 30xLV */
+	   SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x21,0xc0);
+	} else if((SiS_Pr->SiS_VBType & VB_NoLCD) && (bridgerev == 0xb0)) {
+	   SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2c,0x30);      /* For 30xB-DH rev b0 (or "DH on 651"?) */
+	   SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x21,0xc0);
+	} else {
+	   tempah = 0x30; tempah2 = 0xc0;		       /* For 30xB (and 301BDH rev b1) */
+	   tempbl = 0xcf; tempbl2 = 0x3f;
+	   if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+	      tempah = tempah2 = 0x00;
+	      if(SiS_IsDualEdge(SiS_Pr, HwInfo)) {
+		 tempbl = tempbl2 = 0xff;
+	      }
+	   }
+	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2c,tempbl,tempah);
+	   SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,tempbl2,tempah2);
+	}
+
+	if(IS_SIS740) {
+	   tempah = 0x80;
+	   if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 0x00;
+	   SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x23,0x7f,tempah);
+	} else {
+	   tempah = 0x00;
+           tempbl = 0x7f;
+           if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+              tempbl = 0xff;
+	      if(!(SiS_IsDualEdge(SiS_Pr, HwInfo))) tempah = 0x80;
+           }
+           SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x23,tempbl,tempah);
+	}
+
+#endif /* SIS315H */
+
+     } else if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+
+#ifdef SIS300
+        SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x21,0x3f);
+
+        if((SiS_Pr->SiS_VBInfo & DisableCRT2Display) ||
+           ((SiS_Pr->SiS_VBType & VB_NoLCD) &&
+	    (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD))) {
+	   SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x23,0x7F);
+	} else {
+	   SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x23,0x80);
+	}
+#endif
+
+     }
+
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+        SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x0D,0x80);
+        if(SiS_Pr->SiS_VBType & VB_SIS301C) {
+	   SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x3A,0xC0);
+        }
+     }
+
+  } else {  /* LVDS */
+
+#ifdef SIS315H
+     if(HwInfo->jChipType >= SIS_315H) {
+
+        if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+
+           tempah = 0x04;
+	   tempbl = 0xfb;
+           if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+              tempah = 0x00;
+	      if(SiS_IsDualEdge(SiS_Pr, HwInfo)) tempbl = 0xff;
+           }
+	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,tempbl,tempah);
+
+	   if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) {
+	      SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb);
+	   }
+
+	   SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2c,0x30);
+
+	} else if(HwInfo->jChipType == SIS_550) {
+
+	   SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb);
+	   SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2c,0x30);
+
+	}
+
+     }
+#endif
+
+  }
+
+}
+
+/*********************************************/
+/*            GET RESOLUTION DATA            */
+/*********************************************/
+
+USHORT
+SiS_GetResInfo(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex)
+{
+  if(ModeNo <= 0x13) return((USHORT)SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo);
+  else               return((USHORT)SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO);
+}
+
+static void
+SiS_GetCRT2ResInfo(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex,
+                   PSIS_HW_INFO HwInfo)
+{
+  USHORT xres,yres,modeflag=0,resindex;
+
+  if(SiS_Pr->UseCustomMode) {
+     xres = SiS_Pr->CHDisplay;
+     if(SiS_Pr->CModeFlag & HalfDCLK) xres *= 2;
+     SiS_Pr->SiS_VGAHDE = SiS_Pr->SiS_HDE = xres;
+     yres = SiS_Pr->CVDisplay;
+     if(SiS_Pr->CModeFlag & DoubleScanMode) yres *= 2;
+     SiS_Pr->SiS_VGAVDE = SiS_Pr->SiS_VDE = yres;
+     return;
+  }
+
+  resindex = SiS_GetResInfo(SiS_Pr,ModeNo,ModeIdIndex);
+
+  if(ModeNo <= 0x13) {
+     xres = SiS_Pr->SiS_StResInfo[resindex].HTotal;
+     yres = SiS_Pr->SiS_StResInfo[resindex].VTotal;
+  } else {
+     xres = SiS_Pr->SiS_ModeResInfo[resindex].HTotal;
+     yres = SiS_Pr->SiS_ModeResInfo[resindex].VTotal;
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+  }
+
+  if(!SiS_Pr->SiS_IF_DEF_DSTN && !SiS_Pr->SiS_IF_DEF_FSTN) {
+
+     if((HwInfo->jChipType >= SIS_315H) && (SiS_Pr->SiS_IF_DEF_LVDS == 1)) {
+        if((ModeNo != 0x03) && (SiS_Pr->SiS_SetFlag & SetDOSMode)) {
+           if(yres == 350) yres = 400;
+        }
+        if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x3a) & 0x01) {
+ 	   if(ModeNo == 0x12) yres = 400;
+        }
+     }
+
+     if(modeflag & HalfDCLK)       xres *= 2;
+     if(modeflag & DoubleScanMode) yres *= 2;
+
+  }
+
+  if((SiS_Pr->SiS_VBType & VB_SISVB) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) {
+
+#if 0
+        if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCDA | SetCRT2ToLCD | SetCRT2ToHiVision)) {
+           if(xres == 720) xres = 640;
+	}
+#endif
+
+	if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+	   switch(SiS_Pr->SiS_LCDResInfo) {
+	   case Panel_1024x768:
+	      if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
+                 if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
+          	    if(yres == 350) yres = 357;
+          	    if(yres == 400) yres = 420;
+            	    if(yres == 480) yres = 525;
+        	 }
+      	      }
+	      break;
+	   case Panel_1280x1024:
+	      if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
+		 /* BIOS bug - does this regardless of scaling */
+      		 if(yres == 400) yres = 405;
+	      }
+      	      if(yres == 350) yres = 360;
+      	      if(SiS_Pr->SiS_SetFlag & LCDVESATiming) {
+                 if(yres == 360) yres = 375;
+      	      }
+	      break;
+	   case Panel_1600x1200:
+	      if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
+        	 if(yres == 1024) yres = 1056;
+      	      }
+	      break;
+	   }
+	}
+
+  } else {
+
+     if(SiS_Pr->SiS_VBType & VB_SISVB) {
+        if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToHiVision)) {
+           if(xres == 720) xres = 640;
+	}
+     } else if(xres == 720) xres = 640;
+
+     if(SiS_Pr->SiS_SetFlag & SetDOSMode) {
+	yres = 400;
+        if(HwInfo->jChipType >= SIS_315H) {
+           if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x17) & 0x80) yres = 480;
+        } else {
+           if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x80) yres = 480;
+        }
+        if(SiS_Pr->SiS_IF_DEF_DSTN || SiS_Pr->SiS_IF_DEF_FSTN)  yres = 480;
+     }
+
+  }
+  SiS_Pr->SiS_VGAHDE = SiS_Pr->SiS_HDE = xres;
+  SiS_Pr->SiS_VGAVDE = SiS_Pr->SiS_VDE = yres;
+}
+
+/*********************************************/
+/*           GET CRT2 TIMING DATA            */
+/*********************************************/
+
+static BOOLEAN
+SiS_GetLVDSCRT1Ptr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+		   USHORT RefreshRateTableIndex, USHORT *ResIndex,
+		   USHORT *DisplayType)
+ {
+  USHORT modeflag=0;
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+     if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+        if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) return FALSE;
+     }
+  } else if(SiS_Pr->SiS_VBType & VB_SISVB) {
+     if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode))    return FALSE;
+  } else
+     return FALSE;
+
+  if(ModeNo <= 0x13) {
+     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+     (*ResIndex) = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  } else {
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+     (*ResIndex) = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+  }
+
+  (*ResIndex) &= 0x3F;
+
+  if((SiS_Pr->SiS_IF_DEF_CH70xx) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) {
+     (*DisplayType) = 18;
+     if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) (*DisplayType)++;
+     if(SiS_Pr->SiS_TVMode & TVSetPAL) {
+      	(*DisplayType) += 2;
+	if(SiS_Pr->SiS_ModeType > ModeVGA) {
+	   if(SiS_Pr->SiS_CHSOverScan) (*DisplayType) = 99;
+	}
+	if(SiS_Pr->SiS_TVMode & TVSetPALM) {
+	   (*DisplayType) = 18;  /* PALM uses NTSC data */
+	   if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) (*DisplayType)++;
+	} else if(SiS_Pr->SiS_TVMode & TVSetPALN) {
+	   (*DisplayType) = 20;  /* PALN uses PAL data  */
+	   if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) (*DisplayType)++;
+	}
+     }
+  } else {
+     switch(SiS_Pr->SiS_LCDResInfo) {
+     case Panel_640x480:   (*DisplayType) = 50; break;
+     case Panel_640x480_2: (*DisplayType) = 52; break;
+     case Panel_640x480_3: (*DisplayType) = 54; break;
+     case Panel_800x600:   (*DisplayType) =  0; break;
+     case Panel_1024x600:  (*DisplayType) = 23; break;
+     case Panel_1024x768:  (*DisplayType) =  4; break;
+     case Panel_1152x768:  (*DisplayType) = 27; break;
+     case Panel_1280x768:  (*DisplayType) = 40; break;
+     case Panel_1280x1024: (*DisplayType) =  8; break;
+     case Panel_1400x1050: (*DisplayType) = 14; break;
+     case Panel_1600x1200: (*DisplayType) = 36; break;
+     default: return FALSE;
+     }
+
+     if(modeflag & HalfDCLK) (*DisplayType)++;
+
+     switch(SiS_Pr->SiS_LCDResInfo) {
+     case Panel_640x480:
+     case Panel_640x480_2:
+     case Panel_640x480_3:
+        break;
+     default:
+        if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) (*DisplayType) += 2;
+     }
+
+     if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
+        (*DisplayType) = 12;
+	if(modeflag & HalfDCLK) (*DisplayType)++;
+     }
+  }
+
+#if 0
+  if(SiS_Pr->SiS_IF_DEF_FSTN) {
+     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel320x480){
+        (*DisplayType) = 22;
+     }
+  }
+#endif
+
+  return TRUE;
+}
+
+static void
+SiS_GetCRT2Ptr(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex,
+	       USHORT RefreshRateTableIndex,USHORT *CRT2Index,USHORT *ResIndex,
+	       PSIS_HW_INFO HwInfo)
+{
+  USHORT tempbx=0,tempal=0,resinfo=0;
+
+  if(ModeNo <= 0x13) {
+     tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  } else {
+     tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+     resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+  }
+
+  if((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_IF_DEF_LVDS == 0)) {
+
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {                            /* LCD */
+
+        tempbx = SiS_Pr->SiS_LCDResInfo;
+	if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx += 32;
+
+	if(SiS_Pr->SiS_LCDResInfo == Panel_1680x1050) {
+	   if     (resinfo == SIS_RI_1280x800)  tempal =  9;
+	   else if(resinfo == SIS_RI_1400x1050) tempal = 11;
+	} else if((SiS_Pr->SiS_LCDResInfo == Panel_1280x800) ||
+	          (SiS_Pr->SiS_LCDResInfo == Panel_1280x800_2)) {
+	   if     (resinfo == SIS_RI_1280x768)  tempal =  9;
+	}
+
+  	if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+	   /* Pass 1:1 only (center-screen handled outside) */
+	   /* This is never called for the panel's native resolution */
+	   /* since Pass1:1 will not be set in this case */
+	   tempbx = 100;
+	   if(ModeNo >= 0x13) {
+	      tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC_NS;
+	   }
+	}
+
+#ifdef SIS315H
+	if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
+	   if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) {
+	      if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
+	         tempbx = 200;
+	         if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx++;
+	      }
+	   }
+	}
+#endif
+
+     } else {						  	/* TV */
+
+     	if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+           /* if(SiS_Pr->SiS_VGAVDE > 480) SiS_Pr->SiS_TVMode &= (~TVSetTVSimuMode); */
+           tempbx = 2;
+           if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+	      tempbx = 13;
+              if(!(SiS_Pr->SiS_TVMode & TVSetTVSimuMode)) tempbx = 14;
+           }
+	} else if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) {
+	   if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p)      tempbx = 7;
+	   else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) tempbx = 6;
+	   else 					tempbx = 5;
+	   if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode)     tempbx += 5;
+       	} else {
+           if(SiS_Pr->SiS_TVMode & TVSetPAL) 		tempbx = 3;
+           else 					tempbx = 4;
+           if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) 	tempbx += 5;
+       	}
+
+     }
+
+     tempal &= 0x3F;
+
+     if(ModeNo > 0x13) {
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoHiVision) {
+      	   if(tempal == 6) tempal = 7;
+           if((resinfo == SIS_RI_720x480) ||
+	      (resinfo == SIS_RI_720x576) ||
+	      (resinfo == SIS_RI_768x576)) {
+	      tempal = 6;
+	      if(SiS_Pr->SiS_TVMode & (TVSetPAL | TVSetPALN)) {
+	         if(resinfo == SIS_RI_720x480) tempal = 9;
+	      }
+	   }
+	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) {
+              if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) {
+	         if(resinfo == SIS_RI_1024x768) tempal = 8;
+	      }
+	      if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) {
+		 if((resinfo == SIS_RI_720x576) ||
+	            (resinfo == SIS_RI_768x576)) {
+	            tempal = 8;
+	         }
+		 if(resinfo == SIS_RI_1280x720) tempal = 9;
+	      }
+	   }
+	}
+     }
+
+     *CRT2Index = tempbx;
+     *ResIndex = tempal;
+
+  } else {   /* LVDS, 301B-DH (if running on LCD) */
+
+     tempbx = 0;
+     if((SiS_Pr->SiS_IF_DEF_CH70xx) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) {
+
+        tempbx = 10;
+	if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1;
+        if(SiS_Pr->SiS_TVMode & TVSetPAL) {
+	   tempbx += 2;
+	   if(SiS_Pr->SiS_ModeType > ModeVGA) {
+	      if(SiS_Pr->SiS_CHSOverScan) tempbx = 99;
+	   }
+	   if(SiS_Pr->SiS_TVMode & TVSetPALM) {
+	      tempbx = 90;
+	      if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1;
+	   } else if(SiS_Pr->SiS_TVMode & TVSetPALN) {
+	      tempbx = 92;
+	      if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1;
+	   }
+        }
+
+     } else {
+
+        switch(SiS_Pr->SiS_LCDResInfo) {
+	case Panel_640x480:   tempbx = 6;  break;
+	case Panel_640x480_2:
+	case Panel_640x480_3: tempbx = 30; break;
+	case Panel_800x600:   tempbx = 0;  break;
+	case Panel_1024x600:  tempbx = 15; break;
+	case Panel_1024x768:  tempbx = 2;  break;
+	case Panel_1152x768:  tempbx = 17; break;
+	case Panel_1280x768:  tempbx = 18; break;
+	case Panel_1280x1024: tempbx = 4;  break;
+	case Panel_1400x1050: tempbx = 8;  break;
+	case Panel_1600x1200: tempbx = 21; break;
+	case Panel_Barco1366: tempbx = 80; break;
+	}
+
+	switch(SiS_Pr->SiS_LCDResInfo) {
+	case Panel_640x480:
+	case Panel_640x480_2:
+	case Panel_640x480_3:
+	   break;
+	default:
+	   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++;
+	}
+
+	if(SiS_Pr->SiS_LCDInfo & LCDPass11) tempbx = 7;
+
+	if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) {
+	   tempbx = 82;
+	   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++;
+	} else if(SiS_Pr->SiS_CustomT == CUT_PANEL848) {
+	   tempbx = 84;
+	   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++;
+	}
+
+	if((SiS_Pr->SiS_CustomT != CUT_BARCO1366) &&
+           (SiS_Pr->SiS_CustomT != CUT_PANEL848)) {
+           if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) &&
+	      (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) {
+              tempal = 0;
+	   }
+        }
+
+     }
+
+     (*CRT2Index) = tempbx;
+     (*ResIndex) = tempal & 0x1F;
+  }
+}
+
+static void
+SiS_GetRAMDAC2DATA(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex,
+                   USHORT RefreshRateTableIndex,PSIS_HW_INFO HwInfo)
+{
+  USHORT tempax=0,tempbx=0;
+  USHORT temp1=0,modeflag=0,tempcx=0;
+  USHORT index;
+
+  SiS_Pr->SiS_RVBHCMAX  = 1;
+  SiS_Pr->SiS_RVBHCFACT = 1;
+
+  if(ModeNo <= 0x13) {
+
+     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+     index = SiS_GetModePtr(SiS_Pr,ModeNo,ModeIdIndex);
+
+     tempax = SiS_Pr->SiS_StandTable[index].CRTC[0];
+     tempbx = SiS_Pr->SiS_StandTable[index].CRTC[6];
+     temp1 = SiS_Pr->SiS_StandTable[index].CRTC[7];
+
+  } else {
+
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+     index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+
+     tempax = SiS_Pr->SiS_CRT1Table[index].CR[0];
+     tempax |= (SiS_Pr->SiS_CRT1Table[index].CR[14] << 8);
+     tempax &= 0x03FF;
+     tempbx = SiS_Pr->SiS_CRT1Table[index].CR[6];
+     tempcx = SiS_Pr->SiS_CRT1Table[index].CR[13] << 8;
+     tempcx &= 0x0100;
+     tempcx <<= 2;
+     tempbx |= tempcx;
+     temp1  = SiS_Pr->SiS_CRT1Table[index].CR[7];
+
+  }
+
+  if(temp1 & 0x01) tempbx |= 0x0100;
+  if(temp1 & 0x20) tempbx |= 0x0200;
+
+  tempax += 5;
+
+  /* Charx8Dot is no more used (and assumed), so we set it */
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+     modeflag |= Charx8Dot;
+  }
+
+  if(modeflag & Charx8Dot) tempax *= 8;
+  else                     tempax *= 9;
+
+  if(modeflag & HalfDCLK)  tempax <<= 1;
+
+  tempbx++;
+
+  SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_HT = tempax;
+  SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_VT = tempbx;
+}
+
+static void
+SiS_GetCRT2DataLVDS(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex,
+                    USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo)
+{
+   USHORT CRT2Index, ResIndex;
+   const SiS_LVDSDataStruct *LVDSData = NULL;
+
+   SiS_GetCRT2ResInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo);
+
+   if(SiS_Pr->SiS_VBType & VB_SISVB) {
+      SiS_Pr->SiS_RVBHCMAX  = 1;
+      SiS_Pr->SiS_RVBHCFACT = 1;
+      SiS_Pr->SiS_NewFlickerMode = 0;
+      SiS_Pr->SiS_RVBHRS = 50;
+      SiS_Pr->SiS_RY1COE = 0;
+      SiS_Pr->SiS_RY2COE = 0;
+      SiS_Pr->SiS_RY3COE = 0;
+      SiS_Pr->SiS_RY4COE = 0;
+   }
+
+   if((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+
+#ifdef SIS315H
+      if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+         if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
+	    if(SiS_Pr->UseCustomMode) {
+	       SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_HT = SiS_Pr->CHTotal;
+	       SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_VT = SiS_Pr->CVTotal;
+	    } else {
+	       if(ModeNo < 0x13) {
+	          ResIndex = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+	       } else {
+	          ResIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC_NS;
+	       }
+	       SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_NoScaleData[ResIndex].VGAHT;
+               SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_NoScaleData[ResIndex].VGAVT;
+               SiS_Pr->SiS_HT    = SiS_Pr->SiS_NoScaleData[ResIndex].LCDHT;
+               SiS_Pr->SiS_VT    = SiS_Pr->SiS_NoScaleData[ResIndex].LCDVT;
+	    }
+	 } else {
+     	    SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_HT = SiS_Pr->PanelHT;
+            SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_VT = SiS_Pr->PanelVT;
+	 }
+      } else {
+	 /* This handles custom modes and custom panels */
+	 SiS_Pr->SiS_HDE = SiS_Pr->PanelXRes;
+         SiS_Pr->SiS_VDE = SiS_Pr->PanelYRes;
+         SiS_Pr->SiS_HT  = SiS_Pr->PanelHT;
+         SiS_Pr->SiS_VT  = SiS_Pr->PanelVT;
+	 SiS_Pr->SiS_VGAHT = SiS_Pr->PanelHT - (SiS_Pr->PanelXRes - SiS_Pr->SiS_VGAHDE);
+	 SiS_Pr->SiS_VGAVT = SiS_Pr->PanelVT - (SiS_Pr->PanelYRes - SiS_Pr->SiS_VGAVDE);
+      }
+
+      SiS_CalcLCDACRT1Timing(SiS_Pr,ModeNo,ModeIdIndex);
+
+#endif
+
+   } else {
+
+      /* 301BDH needs LVDS Data */
+      if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
+	 SiS_Pr->SiS_IF_DEF_LVDS = 1;
+      }
+
+      SiS_GetCRT2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex,
+                     		&CRT2Index, &ResIndex, HwInfo);
+
+      /* 301BDH needs LVDS Data */
+      if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
+         SiS_Pr->SiS_IF_DEF_LVDS = 0;
+      }
+
+      switch (CRT2Index) {
+      	 case  0: LVDSData = SiS_Pr->SiS_LVDS800x600Data_1;    break;
+	 case  1: LVDSData = SiS_Pr->SiS_LVDS800x600Data_2;    break;
+      	 case  2: LVDSData = SiS_Pr->SiS_LVDS1024x768Data_1;   break;
+	 case  3: LVDSData = SiS_Pr->SiS_LVDS1024x768Data_2;   break;
+      	 case  4: LVDSData = SiS_Pr->SiS_LVDS1280x1024Data_1;  break;
+      	 case  5: LVDSData = SiS_Pr->SiS_LVDS1280x1024Data_2;  break;
+	 case  6: LVDSData = SiS_Pr->SiS_LVDS640x480Data_1;    break;
+         case  7: LVDSData = SiS_Pr->SiS_LVDSXXXxXXXData_1;    break;
+	 case  8: LVDSData = SiS_Pr->SiS_LVDS1400x1050Data_1;  break;
+	 case  9: LVDSData = SiS_Pr->SiS_LVDS1400x1050Data_2;  break;
+      	 case 10: LVDSData = SiS_Pr->SiS_CHTVUNTSCData;        break;
+      	 case 11: LVDSData = SiS_Pr->SiS_CHTVONTSCData;        break;
+      	 case 12: LVDSData = SiS_Pr->SiS_CHTVUPALData;         break;
+      	 case 13: LVDSData = SiS_Pr->SiS_CHTVOPALData;         break;
+      	 case 14: LVDSData = SiS_Pr->SiS_LVDS320x480Data_1;    break;
+	 case 15: LVDSData = SiS_Pr->SiS_LVDS1024x600Data_1;   break;
+	 case 16: LVDSData = SiS_Pr->SiS_LVDS1024x600Data_2;   break;
+	 case 17: LVDSData = SiS_Pr->SiS_LVDS1152x768Data_1;   break;
+	 case 18: LVDSData = SiS_Pr->SiS_LVDS1152x768Data_2;   break;
+	 case 19: LVDSData = SiS_Pr->SiS_LVDS1280x768Data_1;   break;
+	 case 20: LVDSData = SiS_Pr->SiS_LVDS1280x768Data_2;   break;
+	 case 21: LVDSData = SiS_Pr->SiS_LVDS1600x1200Data_1;  break;
+	 case 22: LVDSData = SiS_Pr->SiS_LVDS1600x1200Data_2;  break;
+	 case 30: LVDSData = SiS_Pr->SiS_LVDS640x480Data_2;    break;
+	 case 80: LVDSData = SiS_Pr->SiS_LVDSBARCO1366Data_1;  break;
+	 case 81: LVDSData = SiS_Pr->SiS_LVDSBARCO1366Data_2;  break;
+	 case 82: LVDSData = SiS_Pr->SiS_LVDSBARCO1024Data_1;  break;
+	 case 83: LVDSData = SiS_Pr->SiS_LVDSBARCO1024Data_2;  break;
+	 case 84: LVDSData = SiS_Pr->SiS_LVDS848x480Data_1;    break;
+	 case 85: LVDSData = SiS_Pr->SiS_LVDS848x480Data_2;    break;
+	 case 90: LVDSData = SiS_Pr->SiS_CHTVUPALMData;        break;
+      	 case 91: LVDSData = SiS_Pr->SiS_CHTVOPALMData;        break;
+      	 case 92: LVDSData = SiS_Pr->SiS_CHTVUPALNData;        break;
+      	 case 93: LVDSData = SiS_Pr->SiS_CHTVOPALNData;        break;
+	 case 99: LVDSData = SiS_Pr->SiS_CHTVSOPALData;	       break;  /* Super Overscan */
+	 default: LVDSData = SiS_Pr->SiS_LVDS1024x768Data_1;   break;
+      }
+
+      SiS_Pr->SiS_VGAHT = (LVDSData+ResIndex)->VGAHT;
+      SiS_Pr->SiS_VGAVT = (LVDSData+ResIndex)->VGAVT;
+      SiS_Pr->SiS_HT    = (LVDSData+ResIndex)->LCDHT;
+      SiS_Pr->SiS_VT    = (LVDSData+ResIndex)->LCDVT;
+
+      if(!(SiS_Pr->SiS_VBType & VB_SISVB)) {
+         if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) {
+            if((!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) || (SiS_Pr->SiS_SetFlag & SetDOSMode)) {
+	       SiS_Pr->SiS_HDE = SiS_Pr->PanelXRes;
+               SiS_Pr->SiS_VDE = SiS_Pr->PanelYRes;
+	       if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) {
+		  if(ResIndex < 0x08) {
+		     SiS_Pr->SiS_HDE = 1280;
+                     SiS_Pr->SiS_VDE = 1024;
+                  }
+               }
+            }
+         }
+      }
+   }
+}
+
+static void
+SiS_GetCRT2Data301(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex,
+                   USHORT RefreshRateTableIndex,
+		   PSIS_HW_INFO HwInfo)
+{
+  UCHAR  *ROMAddr = NULL;
+  USHORT tempax,tempbx,modeflag,romptr=0;
+  USHORT resinfo,CRT2Index,ResIndex;
+  const SiS_LCDDataStruct *LCDPtr = NULL;
+  const SiS_TVDataStruct  *TVPtr  = NULL;
+#ifdef SIS315H
+  SHORT  resinfo661;
+#endif
+
+  if(ModeNo <= 0x13) {
+     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+     resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+  } else if(SiS_Pr->UseCustomMode) {
+     modeflag = SiS_Pr->CModeFlag;
+     resinfo = 0;
+  } else {
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+     resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+#ifdef SIS315H
+     resinfo661 = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].ROMMODEIDX661;
+     if( (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)   &&
+         (SiS_Pr->SiS_SetFlag & LCDVESATiming) &&
+         (resinfo661 >= 0)                     &&
+	 (SiS_Pr->SiS_NeedRomModeData) ) {
+        if((ROMAddr = GetLCDStructPtr661(SiS_Pr, HwInfo))) {
+	   if((romptr = (SISGETROMW(21)))) {
+              romptr += (resinfo661 * 10);
+	      ROMAddr = HwInfo->pjVirtualRomBase;
+	   }
+	}
+     }
+#endif
+  }
+  
+  SiS_Pr->SiS_NewFlickerMode = 0;
+  SiS_Pr->SiS_RVBHRS = 50;
+  SiS_Pr->SiS_RY1COE = 0;
+  SiS_Pr->SiS_RY2COE = 0;
+  SiS_Pr->SiS_RY3COE = 0;
+  SiS_Pr->SiS_RY4COE = 0;
+
+  SiS_GetCRT2ResInfo(SiS_Pr,ModeNo,ModeIdIndex,HwInfo);
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC){
+
+     if(SiS_Pr->UseCustomMode) {
+
+        SiS_Pr->SiS_RVBHCMAX  = 1;
+        SiS_Pr->SiS_RVBHCFACT = 1;
+        SiS_Pr->SiS_VGAHT     = SiS_Pr->CHTotal;
+        SiS_Pr->SiS_VGAVT     = SiS_Pr->CVTotal;
+        SiS_Pr->SiS_HT        = SiS_Pr->CHTotal;
+        SiS_Pr->SiS_VT        = SiS_Pr->CVTotal;
+	SiS_Pr->SiS_HDE       = SiS_Pr->SiS_VGAHDE;
+        SiS_Pr->SiS_VDE       = SiS_Pr->SiS_VGAVDE;
+
+     } else {
+
+        SiS_GetRAMDAC2DATA(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
+
+     }
+
+  } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+
+     SiS_GetCRT2Ptr(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                    &CRT2Index,&ResIndex,HwInfo);
+
+     switch(CRT2Index) {
+        case  2: TVPtr = SiS_Pr->SiS_ExtHiTVData;   break;
+        case  3: TVPtr = SiS_Pr->SiS_ExtPALData;    break;
+        case  4: TVPtr = SiS_Pr->SiS_ExtNTSCData;   break;
+        case  5: TVPtr = SiS_Pr->SiS_Ext525iData;   break;
+        case  6: TVPtr = SiS_Pr->SiS_Ext525pData;   break;
+        case  7: TVPtr = SiS_Pr->SiS_Ext750pData;   break;
+        case  8: TVPtr = SiS_Pr->SiS_StPALData;     break;
+        case  9: TVPtr = SiS_Pr->SiS_StNTSCData;    break;
+        case 10: TVPtr = SiS_Pr->SiS_St525iData;    break;
+        case 11: TVPtr = SiS_Pr->SiS_St525pData;    break;
+        case 12: TVPtr = SiS_Pr->SiS_St750pData;    break;
+        case 13: TVPtr = SiS_Pr->SiS_St1HiTVData;   break;
+        case 14: TVPtr = SiS_Pr->SiS_St2HiTVData;   break;
+        default: TVPtr = SiS_Pr->SiS_StPALData;     break;
+     }
+
+     SiS_Pr->SiS_RVBHCMAX  = (TVPtr+ResIndex)->RVBHCMAX;
+     SiS_Pr->SiS_RVBHCFACT = (TVPtr+ResIndex)->RVBHCFACT;
+     SiS_Pr->SiS_VGAHT     = (TVPtr+ResIndex)->VGAHT;
+     SiS_Pr->SiS_VGAVT     = (TVPtr+ResIndex)->VGAVT;
+     SiS_Pr->SiS_HDE       = (TVPtr+ResIndex)->TVHDE;
+     SiS_Pr->SiS_VDE       = (TVPtr+ResIndex)->TVVDE;
+     SiS_Pr->SiS_RVBHRS    = (TVPtr+ResIndex)->RVBHRS;
+     SiS_Pr->SiS_NewFlickerMode = (TVPtr+ResIndex)->FlickerMode;
+     if(modeflag & HalfDCLK) {
+        SiS_Pr->SiS_RVBHRS = (TVPtr+ResIndex)->HALFRVBHRS;
+     }
+
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+
+        if((resinfo == SIS_RI_1024x768)  ||
+           (resinfo == SIS_RI_1280x1024) ||
+           (resinfo == SIS_RI_1280x720)) {
+	   SiS_Pr->SiS_NewFlickerMode = 0x40;
+	}
+
+        if(SiS_Pr->SiS_VGAVDE == 350) SiS_Pr->SiS_TVMode |= TVSetTVSimuMode;
+
+        SiS_Pr->SiS_HT = ExtHiTVHT;
+        SiS_Pr->SiS_VT = ExtHiTVVT;
+        if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+           if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) {
+              SiS_Pr->SiS_HT = StHiTVHT;
+              SiS_Pr->SiS_VT = StHiTVVT;
+#if 0
+              if(!(modeflag & Charx8Dot)) {
+                 SiS_Pr->SiS_HT = StHiTextTVHT;
+                 SiS_Pr->SiS_VT = StHiTextTVVT;
+              }
+#endif
+           }
+        }
+
+     } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) {
+
+        if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) {
+           SiS_Pr->SiS_HT = 1650;
+           SiS_Pr->SiS_VT = 750;
+	} else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) {
+	   SiS_Pr->SiS_HT = NTSCHT;
+	   SiS_Pr->SiS_VT = NTSCVT;
+        } else {
+           SiS_Pr->SiS_HT = NTSCHT;
+	   if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) SiS_Pr->SiS_HT = NTSC2HT;
+           SiS_Pr->SiS_VT = NTSCVT;
+        }
+
+     } else {
+
+        SiS_Pr->SiS_RY1COE = (TVPtr+ResIndex)->RY1COE;
+        SiS_Pr->SiS_RY2COE = (TVPtr+ResIndex)->RY2COE;
+        SiS_Pr->SiS_RY3COE = (TVPtr+ResIndex)->RY3COE;
+        SiS_Pr->SiS_RY4COE = (TVPtr+ResIndex)->RY4COE;
+
+        if(modeflag & HalfDCLK) {
+           SiS_Pr->SiS_RY1COE = 0x00;
+           SiS_Pr->SiS_RY2COE = 0xf4;
+           SiS_Pr->SiS_RY3COE = 0x10;
+           SiS_Pr->SiS_RY4COE = 0x38;
+        }
+
+        if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) {
+           SiS_Pr->SiS_HT = NTSCHT;
+	   if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) SiS_Pr->SiS_HT = NTSC2HT;
+           SiS_Pr->SiS_VT = NTSCVT;
+        } else {
+           SiS_Pr->SiS_HT = PALHT;
+           SiS_Pr->SiS_VT = PALVT;
+        }
+
+     }
+
+  } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+
+     SiS_Pr->SiS_RVBHCMAX  = 1;
+     SiS_Pr->SiS_RVBHCFACT = 1;
+
+     if(SiS_Pr->UseCustomMode) {
+
+        SiS_Pr->SiS_VGAHT = SiS_Pr->CHTotal;
+        SiS_Pr->SiS_VGAVT = SiS_Pr->CVTotal;
+        SiS_Pr->SiS_HT    = SiS_Pr->CHTotal;
+        SiS_Pr->SiS_VT    = SiS_Pr->CVTotal;
+	SiS_Pr->SiS_HDE   = SiS_Pr->SiS_VGAHDE;
+        SiS_Pr->SiS_VDE   = SiS_Pr->SiS_VGAVDE;
+
+     } else {
+
+        BOOLEAN gotit = FALSE;
+
+        if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) {
+
+           SiS_Pr->SiS_VGAHT = SiS_Pr->PanelHT;
+           SiS_Pr->SiS_VGAVT = SiS_Pr->PanelVT;
+           SiS_Pr->SiS_HT    = SiS_Pr->PanelHT;
+           SiS_Pr->SiS_VT    = SiS_Pr->PanelVT;
+	   gotit = TRUE;
+
+	} else if( (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) && (romptr) && (ROMAddr) ) {
+
+#ifdef SIS315H
+	   SiS_Pr->SiS_RVBHCMAX  = ROMAddr[romptr];
+           SiS_Pr->SiS_RVBHCFACT = ROMAddr[romptr+1];
+           SiS_Pr->SiS_VGAHT     = ROMAddr[romptr+2] | ((ROMAddr[romptr+3] & 0x0f) << 8);
+           SiS_Pr->SiS_VGAVT     = ROMAddr[romptr+4] | ((ROMAddr[romptr+3] & 0xf0) << 4);
+           SiS_Pr->SiS_HT        = ROMAddr[romptr+5] | ((ROMAddr[romptr+6] & 0x0f) << 8);
+           SiS_Pr->SiS_VT        = ROMAddr[romptr+7] | ((ROMAddr[romptr+6] & 0xf0) << 4);
+	   if(SiS_Pr->SiS_VGAHT) gotit = TRUE;
+	   else {
+	      SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
+	      SiS_Pr->SiS_LCDInfo &= ~LCDPass11;
+	      SiS_Pr->SiS_VGAHT   = SiS_Pr->PanelHT;
+              SiS_Pr->SiS_VGAVT   = SiS_Pr->PanelVT;
+              SiS_Pr->SiS_HT      = SiS_Pr->PanelHT;
+              SiS_Pr->SiS_VT      = SiS_Pr->PanelVT;
+	      gotit = TRUE;
+	   }
+#endif
+
+	}
+
+	if(!gotit) {
+
+           SiS_GetCRT2Ptr(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                          &CRT2Index,&ResIndex,HwInfo);
+
+           switch(CRT2Index) {
+	      case Panel_1024x768      : LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data;   break;
+	      case Panel_1024x768  + 32: LCDPtr = SiS_Pr->SiS_St2LCD1024x768Data;   break;
+	      case Panel_1280x720      :
+	      case Panel_1280x720  + 32: LCDPtr = SiS_Pr->SiS_LCD1280x720Data;      break;
+	      case Panel_1280x768_2    : LCDPtr = SiS_Pr->SiS_ExtLCD1280x768_2Data; break;
+              case Panel_1280x768_2+ 32: LCDPtr = SiS_Pr->SiS_StLCD1280x768_2Data;  break;
+	      case Panel_1280x800      :
+	      case Panel_1280x800  + 32: LCDPtr = SiS_Pr->SiS_LCD1280x800Data;      break;
+	      case Panel_1280x800_2    :
+	      case Panel_1280x800_2+ 32: LCDPtr = SiS_Pr->SiS_LCD1280x800_2Data;    break;
+	      case Panel_1280x960      :
+	      case Panel_1280x960  + 32: LCDPtr = SiS_Pr->SiS_LCD1280x960Data;      break;
+              case Panel_1280x1024     : LCDPtr = SiS_Pr->SiS_ExtLCD1280x1024Data;  break;
+              case Panel_1280x1024 + 32: LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data;  break;
+              case Panel_1400x1050     : LCDPtr = SiS_Pr->SiS_ExtLCD1400x1050Data;  break;
+              case Panel_1400x1050 + 32: LCDPtr = SiS_Pr->SiS_StLCD1400x1050Data;   break;
+              case Panel_1600x1200     : LCDPtr = SiS_Pr->SiS_ExtLCD1600x1200Data;  break;
+              case Panel_1600x1200 + 32: LCDPtr = SiS_Pr->SiS_StLCD1600x1200Data;   break;
+	      case Panel_1680x1050     :
+	      case Panel_1680x1050 + 32: LCDPtr = SiS_Pr->SiS_LCD1680x1050Data;     break;
+	      case 100		       : LCDPtr = SiS_Pr->SiS_NoScaleData;	    break;
+#ifdef SIS315H
+	      case 200                 : LCDPtr = SiS310_ExtCompaq1280x1024Data;    break;
+	      case 201                 : LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data;  break;
+#endif
+              default                  : LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data;   break;
+           }
+
+#ifdef TWDEBUG
+           xf86DrvMsg(0, X_INFO, "GetCRT2Data: Index %d ResIndex %d\n", CRT2Index, ResIndex);
+#endif
+
+           SiS_Pr->SiS_RVBHCMAX  = (LCDPtr+ResIndex)->RVBHCMAX;
+           SiS_Pr->SiS_RVBHCFACT = (LCDPtr+ResIndex)->RVBHCFACT;
+           SiS_Pr->SiS_VGAHT     = (LCDPtr+ResIndex)->VGAHT;
+           SiS_Pr->SiS_VGAVT     = (LCDPtr+ResIndex)->VGAVT;
+           SiS_Pr->SiS_HT        = (LCDPtr+ResIndex)->LCDHT;
+           SiS_Pr->SiS_VT        = (LCDPtr+ResIndex)->LCDVT;
+
+        }
+
+	tempax = SiS_Pr->PanelXRes;
+        tempbx = SiS_Pr->PanelYRes;
+
+	if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+           if(SiS_Pr->SiS_SetFlag & LCDVESATiming) {
+              if(HwInfo->jChipType < SIS_315H) {
+                 if     (SiS_Pr->SiS_VGAVDE == 350) tempbx = 560;
+                 else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 640;
+              }
+           } else {
+              if     (SiS_Pr->SiS_VGAVDE == 357) tempbx = 527;
+              else if(SiS_Pr->SiS_VGAVDE == 420) tempbx = 620;
+              else if(SiS_Pr->SiS_VGAVDE == 525) tempbx = 775;
+              else if(SiS_Pr->SiS_VGAVDE == 600) tempbx = 775;
+              else if(SiS_Pr->SiS_VGAVDE == 350) tempbx = 560;
+              else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 640;
+           }
+	} else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x960) {
+           if     (SiS_Pr->SiS_VGAVDE == 350)  tempbx = 700;
+           else if(SiS_Pr->SiS_VGAVDE == 400)  tempbx = 800;
+           else if(SiS_Pr->SiS_VGAVDE == 1024) tempbx = 960;
+	} else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) {
+           if     (SiS_Pr->SiS_VGAVDE == 360) tempbx = 768;
+           else if(SiS_Pr->SiS_VGAVDE == 375) tempbx = 800;
+           else if(SiS_Pr->SiS_VGAVDE == 405) tempbx = 864;
+        } else if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) {
+	   if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
+              if     (SiS_Pr->SiS_VGAVDE == 350)  tempbx = 875;
+              else if(SiS_Pr->SiS_VGAVDE == 400)  tempbx = 1000;
+           }
+        }
+
+        if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+           tempax = SiS_Pr->SiS_VGAHDE;
+           tempbx = SiS_Pr->SiS_VGAVDE;
+        }
+
+        SiS_Pr->SiS_HDE = tempax;
+        SiS_Pr->SiS_VDE = tempbx;
+     }
+  }
+}
+
+static void
+SiS_GetCRT2Data(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+                USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo)
+{
+
+  if(SiS_Pr->SiS_VBType & VB_SISVB) {
+
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+        SiS_GetCRT2DataLVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
+     } else {
+	if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
+	   /* Need LVDS Data for LCD on 301B-DH */
+	   SiS_GetCRT2DataLVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
+	} else {
+	   SiS_GetCRT2Data301(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
+        }
+     }
+
+  } else {
+
+     SiS_GetCRT2DataLVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
+
+  }
+}
+
+/*********************************************/
+/*         GET LVDS DES (SKEW) DATA          */
+/*********************************************/
+
+static void
+SiS_GetLVDSDesPtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+                  USHORT RefreshRateTableIndex, USHORT *PanelIndex,
+		  USHORT *ResIndex, PSIS_HW_INFO HwInfo)
+{
+  USHORT modeflag;
+
+  if(ModeNo <= 0x13) {
+     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+     (*ResIndex) = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  } else {
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+     (*ResIndex) = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+  }
+
+  (*ResIndex) &= 0x1F;
+  (*PanelIndex) = 0;
+
+  if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+        (*PanelIndex) = 50;
+        if((SiS_Pr->SiS_TVMode & TVSetPAL) && (!(SiS_Pr->SiS_TVMode & TVSetPALM))) (*PanelIndex) += 2;
+        if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) (*PanelIndex) += 1;
+        /* Nothing special needed for SOverscan    */
+        /* PALM uses NTSC data, PALN uses PAL data */
+     }
+  }
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+     *PanelIndex = SiS_Pr->SiS_LCDTypeInfo;
+     if(HwInfo->jChipType >= SIS_661) {
+        /* As long as we don's use the BIOS tables, we
+	 * need to convert the TypeInfo as for 315 series
+	 */
+        (*PanelIndex) = SiS_Pr->SiS_LCDResInfo - 1;
+     }
+     if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+        (*PanelIndex) += 16;
+        if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
+           (*PanelIndex) = 32;
+           if(modeflag & HalfDCLK) (*PanelIndex)++;
+	}
+     }
+  }
+
+  if(SiS_Pr->SiS_SetFlag & SetDOSMode) {
+     if(SiS_Pr->SiS_LCDResInfo != Panel_640x480) {
+        (*ResIndex) = 7;
+        if(HwInfo->jChipType < SIS_315H) {
+           if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x80) (*ResIndex)++;
+        }
+     }
+  }
+}
+
+static void
+SiS_GetLVDSDesData(SiS_Private *SiS_Pr, USHORT ModeNo,USHORT ModeIdIndex,
+                   USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo)
+{
+  USHORT modeflag;
+  USHORT PanelIndex,ResIndex;
+  const  SiS_LVDSDesStruct *PanelDesPtr = NULL;
+
+  SiS_Pr->SiS_LCDHDES = 0;
+  SiS_Pr->SiS_LCDVDES = 0;
+
+  if( (SiS_Pr->UseCustomMode) 		         ||
+      (SiS_Pr->SiS_LCDResInfo == Panel_Custom)   ||
+      (SiS_Pr->SiS_CustomT == CUT_PANEL848)      ||
+      ((SiS_Pr->SiS_VBType & VB_SISVB) &&
+       (SiS_Pr->SiS_LCDInfo & DontExpandLCD) &&
+       (SiS_Pr->SiS_LCDInfo & LCDPass11)) ) {
+     return;
+  }
+
+  if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+
+#ifdef SIS315H
+     if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+        /* non-pass 1:1 only, see above */
+        if(SiS_Pr->SiS_VGAHDE != SiS_Pr->PanelXRes) {
+           SiS_Pr->SiS_LCDHDES = SiS_Pr->SiS_HT - ((SiS_Pr->PanelXRes - SiS_Pr->SiS_VGAHDE) / 2);
+	}
+	if(SiS_Pr->SiS_VGAVDE != SiS_Pr->PanelYRes) {
+	   SiS_Pr->SiS_LCDVDES = SiS_Pr->SiS_VT - ((SiS_Pr->PanelYRes - SiS_Pr->SiS_VGAVDE) / 2);
+	}
+     }
+     if(SiS_Pr->SiS_VGAVDE == SiS_Pr->PanelYRes) {
+        switch(SiS_Pr->SiS_CustomT) {
+        case CUT_UNIWILL1024:
+        case CUT_UNIWILL10242:
+        case CUT_CLEVO1400:
+	   if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+	      SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1;
+	   }
+	   break;
+	}
+	if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) {
+	   if(SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) {
+	      SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1;
+	   }
+	}
+     }
+#endif
+
+  } else {
+
+     SiS_GetLVDSDesPtr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex,
+                       &PanelIndex, &ResIndex, HwInfo);
+
+     switch(PanelIndex) {
+     	case  0: PanelDesPtr = SiS_Pr->SiS_PanelType00_1;    break;   /* ---  */
+     	case  1: PanelDesPtr = SiS_Pr->SiS_PanelType01_1;    break;
+     	case  2: PanelDesPtr = SiS_Pr->SiS_PanelType02_1;    break;
+     	case  3: PanelDesPtr = SiS_Pr->SiS_PanelType03_1;    break;
+     	case  4: PanelDesPtr = SiS_Pr->SiS_PanelType04_1;    break;
+     	case  5: PanelDesPtr = SiS_Pr->SiS_PanelType05_1;    break;
+     	case  6: PanelDesPtr = SiS_Pr->SiS_PanelType06_1;    break;
+     	case  7: PanelDesPtr = SiS_Pr->SiS_PanelType07_1;    break;
+     	case  8: PanelDesPtr = SiS_Pr->SiS_PanelType08_1;    break;
+     	case  9: PanelDesPtr = SiS_Pr->SiS_PanelType09_1;    break;
+     	case 10: PanelDesPtr = SiS_Pr->SiS_PanelType0a_1;    break;
+     	case 11: PanelDesPtr = SiS_Pr->SiS_PanelType0b_1;    break;
+     	case 12: PanelDesPtr = SiS_Pr->SiS_PanelType0c_1;    break;
+     	case 13: PanelDesPtr = SiS_Pr->SiS_PanelType0d_1;    break;
+     	case 14: PanelDesPtr = SiS_Pr->SiS_PanelType0e_1;    break;
+     	case 15: PanelDesPtr = SiS_Pr->SiS_PanelType0f_1;    break;
+     	case 16: PanelDesPtr = SiS_Pr->SiS_PanelType00_2;    break;    /* --- */
+     	case 17: PanelDesPtr = SiS_Pr->SiS_PanelType01_2;    break;
+     	case 18: PanelDesPtr = SiS_Pr->SiS_PanelType02_2;    break;
+     	case 19: PanelDesPtr = SiS_Pr->SiS_PanelType03_2;    break;
+     	case 20: PanelDesPtr = SiS_Pr->SiS_PanelType04_2;    break;
+     	case 21: PanelDesPtr = SiS_Pr->SiS_PanelType05_2;    break;
+     	case 22: PanelDesPtr = SiS_Pr->SiS_PanelType06_2;    break;
+     	case 23: PanelDesPtr = SiS_Pr->SiS_PanelType07_2;    break;
+     	case 24: PanelDesPtr = SiS_Pr->SiS_PanelType08_2;    break;
+     	case 25: PanelDesPtr = SiS_Pr->SiS_PanelType09_2;    break;
+     	case 26: PanelDesPtr = SiS_Pr->SiS_PanelType0a_2;    break;
+     	case 27: PanelDesPtr = SiS_Pr->SiS_PanelType0b_2;    break;
+     	case 28: PanelDesPtr = SiS_Pr->SiS_PanelType0c_2;    break;
+     	case 29: PanelDesPtr = SiS_Pr->SiS_PanelType0d_2;    break;
+     	case 30: PanelDesPtr = SiS_Pr->SiS_PanelType0e_2;    break;
+     	case 31: PanelDesPtr = SiS_Pr->SiS_PanelType0f_2;    break;
+	case 32: PanelDesPtr = SiS_Pr->SiS_PanelTypeNS_1;    break;    /* pass 1:1 */
+	case 33: PanelDesPtr = SiS_Pr->SiS_PanelTypeNS_2;    break;
+     	case 50: PanelDesPtr = SiS_Pr->SiS_CHTVUNTSCDesData; break;    /* TV */
+     	case 51: PanelDesPtr = SiS_Pr->SiS_CHTVONTSCDesData; break;
+     	case 52: PanelDesPtr = SiS_Pr->SiS_CHTVUPALDesData;  break;
+     	case 53: PanelDesPtr = SiS_Pr->SiS_CHTVOPALDesData;  break;
+	default: return;
+     }
+
+     SiS_Pr->SiS_LCDHDES = (PanelDesPtr+ResIndex)->LCDHDES;
+     SiS_Pr->SiS_LCDVDES = (PanelDesPtr+ResIndex)->LCDVDES;
+
+     if((ModeNo <= 0x13) && (SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
+        modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+        if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+	   if(!(modeflag & HalfDCLK)) SiS_Pr->SiS_LCDHDES = 632;
+        } else if(!(SiS_Pr->SiS_SetFlag & SetDOSMode)) {
+           if(SiS_Pr->SiS_LCDResInfo != Panel_1280x1024) {
+              if(SiS_Pr->SiS_LCDResInfo >= Panel_1024x768) {
+	         if(HwInfo->jChipType < SIS_315H) {
+	            if(!(modeflag & HalfDCLK)) SiS_Pr->SiS_LCDHDES = 320;
+	         } else {
+	            if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768)  SiS_Pr->SiS_LCDHDES = 480;
+                    if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) SiS_Pr->SiS_LCDHDES = 804;
+		    if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) SiS_Pr->SiS_LCDHDES = 704;
+                    if(!(modeflag & HalfDCLK)) {
+                       SiS_Pr->SiS_LCDHDES = 320;
+	               if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) SiS_Pr->SiS_LCDHDES = 632;
+		       if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) SiS_Pr->SiS_LCDHDES = 542;
+                    }
+                 }
+              }
+           }
+        }
+     }
+  }
+}
+
+/*********************************************/
+/*           DISABLE VIDEO BRIDGE            */
+/*********************************************/
+
+/* NEVER use any variables (VBInfo), this will be called
+ * from outside the context of modeswitch!
+ * MUST call getVBType before calling this
+ */
+void
+SiS_DisableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+#ifdef SIS315H
+  USHORT tempah,pushax=0,modenum;
+#endif
+  USHORT temp=0;
+
+  if(SiS_Pr->SiS_VBType & VB_SISVB) {
+
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {   /* ===== For 30xB/LV ===== */
+
+        if(HwInfo->jChipType < SIS_315H) {
+
+#ifdef SIS300	   /* 300 series */
+
+	   if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) {
+	      if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+	         SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFE);
+	      } else {
+		 SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x08);
+	      }
+	      SiS_PanelDelay(SiS_Pr, HwInfo, 3);
+	   }
+	   if(SiS_Is301B(SiS_Pr)) {
+	      SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1f,0x3f);
+	      SiS_ShortDelay(SiS_Pr,1);
+           }
+	   SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xDF);
+	   SiS_DisplayOff(SiS_Pr);
+	   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
+	   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);
+	   SiS_UnLockCRT2(SiS_Pr,HwInfo);
+	   if(!(SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) {
+	      SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x80);
+	      SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x02,0x40);
+	   }
+	   if( (!(SiS_CRT2IsLCD(SiS_Pr, HwInfo))) ||
+	       (!(SiS_CR36BIOSWord23d(SiS_Pr, HwInfo))) ) {
+	      SiS_PanelDelay(SiS_Pr, HwInfo, 2);
+	      if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+                 SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD);
+	      } else {
+		 SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x04);
+	      }
+	   }
+
+#endif  /* SIS300 */
+
+        } else {
+
+#ifdef SIS315H	   /* 315 series */
+
+	   BOOLEAN custom1 = ((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) ||
+	                      (SiS_Pr->SiS_CustomT == CUT_CLEVO1400)) ? TRUE : FALSE;
+
+	   modenum = SiS_GetReg(SiS_Pr->SiS_P3d4,0x34) & 0x7f;
+
+           if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+
+#ifdef SET_EMI
+	      if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
+		 if(SiS_Pr->SiS_CustomT != CUT_CLEVO1400) {
+	            SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c);
+		 }
+	      }
+#endif
+	      if( (modenum <= 0x13)                  ||
+		  (SiS_IsVAMode(SiS_Pr,HwInfo))      ||
+		  (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) ) {
+	     	 SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFE);
+		 if(custom1) SiS_PanelDelay(SiS_Pr, HwInfo, 3);
+	      }
+
+	      if(!custom1) {
+		 SiS_DDC2Delay(SiS_Pr,0xff00);
+		 SiS_DDC2Delay(SiS_Pr,0xe000);
+	         SiS_SetRegByte(SiS_Pr->SiS_P3c6,0x00);
+                 pushax = SiS_GetReg(SiS_Pr->SiS_P3c4,0x06);
+		 if(IS_SIS740) {
+		    SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x06,0xE3);
+		 }
+	         SiS_PanelDelay(SiS_Pr, HwInfo, 3);
+	      }
+
+           }
+
+	   if(!(SiS_IsNotM650orLater(SiS_Pr, HwInfo))) {
+	      if(HwInfo->jChipType < SIS_340) {
+	         tempah = 0xef;
+	         if(SiS_IsVAMode(SiS_Pr,HwInfo)) tempah = 0xf7;
+	         SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x4c,tempah);
+	      }
+	   }
+
+	   if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+	      SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1F,~0x10);
+	   }
+
+	   tempah = 0x3f;
+	   if(SiS_IsDualEdge(SiS_Pr,HwInfo)) {
+	      tempah = 0x7f;
+	      if(!(SiS_IsVAMode(SiS_Pr,HwInfo))) tempah = 0xbf;
+	   }
+	   SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1F,tempah);
+
+           if((SiS_IsVAMode(SiS_Pr,HwInfo)) ||
+	      ((SiS_Pr->SiS_VBType & VB_SIS301LV302LV) && (modenum <= 0x13))) {
+
+	      SiS_DisplayOff(SiS_Pr);
+	      if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+		 SiS_PanelDelay(SiS_Pr, HwInfo, 2);
+	      }
+	      SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
+	      SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1E,0xDF);
+
+	   }
+
+	   if((!(SiS_IsVAMode(SiS_Pr,HwInfo))) ||
+	      ((SiS_Pr->SiS_VBType & VB_SIS301LV302LV) && (modenum <= 0x13))) {
+
+	      if(!(SiS_IsDualEdge(SiS_Pr,HwInfo))) {
+		 SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xdf);
+		 SiS_DisplayOff(SiS_Pr);
+	      }
+	      SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80);
+
+	      if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+		 SiS_PanelDelay(SiS_Pr, HwInfo, 2);
+	      }
+
+	      SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
+	      temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00);
+              SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x10);
+	      SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);
+	      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,temp);
+
+	   }
+
+	   if(SiS_IsNotM650orLater(SiS_Pr,HwInfo)) {
+	      SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f);
+	   }
+
+	   if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+
+	      if(!custom1) {
+
+	         if(!(SiS_IsVAMode(SiS_Pr,HwInfo))) {
+	            if(!(SiS_CRT2IsLCD(SiS_Pr,HwInfo))) {
+	               if(!(SiS_IsDualEdge(SiS_Pr,HwInfo))) {
+		          SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD);
+                       }
+                    }
+	         }
+
+	         SiS_SetReg(SiS_Pr->SiS_P3c4,0x06,pushax);
+
+		 if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
+	            if(SiS_IsVAorLCD(SiS_Pr, HwInfo)) {
+		       SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 20);
+		    }
+	         }
+
+	      } else {
+
+		 if((SiS_IsVAMode(SiS_Pr,HwInfo)) ||
+		    (!(SiS_IsDualEdge(SiS_Pr,HwInfo)))) {
+		    if((!(SiS_WeHaveBacklightCtrl(SiS_Pr, HwInfo))) ||
+		       (!(SiS_CRT2IsLCD(SiS_Pr, HwInfo)))) {
+		       SiS_PanelDelay(SiS_Pr, HwInfo, 2);
+	     	       SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD);
+		       SiS_PanelDelay(SiS_Pr, HwInfo, 4);
+		    }
+		 }
+
+	      }
+           }
+
+#endif /* SIS315H */
+
+	}
+
+     } else {     /* ============ For 301 ================ */
+
+        if(HwInfo->jChipType < SIS_315H) {
+#ifdef SIS300
+           if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) {
+	      SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x08);
+	      SiS_PanelDelay(SiS_Pr, HwInfo, 3);
+	   }
+#endif
+	}
+
+        SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xDF);           /* disable VB */
+        SiS_DisplayOff(SiS_Pr);
+
+        if(HwInfo->jChipType >= SIS_315H) {
+           SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80);
+	}
+
+        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);                /* disable lock mode */
+
+	if(HwInfo->jChipType >= SIS_315H) {
+            temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00);
+            SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x10);
+	    SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);
+	    SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,temp);
+	} else {
+#ifdef SIS300
+            SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);            /* disable CRT2 */
+	    if( (!(SiS_CRT2IsLCD(SiS_Pr, HwInfo))) ||
+	        (!(SiS_CR36BIOSWord23d(SiS_Pr,HwInfo))) ) {
+		SiS_PanelDelay(SiS_Pr, HwInfo, 2);
+		SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x04);
+	    }
+#endif
+	}
+
+      }
+
+  } else {     /* ============ For LVDS =============*/
+
+    if(HwInfo->jChipType < SIS_315H) {
+
+#ifdef SIS300	/* 300 series */
+
+	if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
+	   SiS_SetCH700x(SiS_Pr,0x090E);
+	}
+
+	if(HwInfo->jChipType == SIS_730) {
+	   if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x11) & 0x08)) {
+	      SiS_WaitVBRetrace(SiS_Pr,HwInfo);
+	   }
+	   if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) {
+	      SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x08);
+	      SiS_PanelDelay(SiS_Pr, HwInfo, 3);
+	   }
+	} else {
+	   if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x11) & 0x08)) {
+	      if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x40)) {
+  	         if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) {
+                    SiS_WaitVBRetrace(SiS_Pr,HwInfo);
+		    if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x06) & 0x1c)) {
+		       SiS_DisplayOff(SiS_Pr);
+	            }
+	            SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x08);
+	            SiS_PanelDelay(SiS_Pr, HwInfo, 3);
+                 }
+              }
+	   }
+	}
+
+	SiS_DisplayOff(SiS_Pr);
+
+	SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
+
+	SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);
+	SiS_UnLockCRT2(SiS_Pr,HwInfo);
+	SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x80);
+	SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x02,0x40);
+
+	if( (!(SiS_CRT2IsLCD(SiS_Pr, HwInfo))) ||
+	    (!(SiS_CR36BIOSWord23d(SiS_Pr,HwInfo))) ) {
+	   SiS_PanelDelay(SiS_Pr, HwInfo, 2);
+	   SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x04);
+	}
+
+#endif  /* SIS300 */
+
+    } else {
+
+#ifdef SIS315H	/* 315 series */
+
+        if(!(SiS_IsNotM650orLater(SiS_Pr,HwInfo))) {
+	   if(HwInfo->jChipType < SIS_340) {
+              SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x4c,~0x18);
+	   }
+        }
+
+	if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+
+	   if(HwInfo->jChipType == SIS_740) {
+	      temp = SiS_GetCH701x(SiS_Pr,0x61);
+	      if(temp < 1) {
+	         SiS_SetCH701x(SiS_Pr,0xac76);
+	         SiS_SetCH701x(SiS_Pr,0x0066);
+	      }
+
+	      if( (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) ||
+	          (SiS_IsTVOrYPbPrOrScart(SiS_Pr,HwInfo)) ) {
+	  	 SiS_SetCH701x(SiS_Pr,0x3e49);
+	      }
+	   }
+
+	   if( (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) ||
+	       (SiS_IsVAMode(SiS_Pr,HwInfo)) ) {
+	      SiS_Chrontel701xBLOff(SiS_Pr);
+	      SiS_Chrontel701xOff(SiS_Pr,HwInfo);
+	   }
+
+	   if(HwInfo->jChipType != SIS_740) {
+	      if( (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) ||
+	          (SiS_IsTVOrYPbPrOrScart(SiS_Pr,HwInfo)) ) {
+	   	 SiS_SetCH701x(SiS_Pr,0x0149);
+  	      }
+	   }
+
+	}
+
+	if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) {
+	   SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x08);
+	   SiS_PanelDelay(SiS_Pr, HwInfo, 3);
+	}
+
+	if( (SiS_Pr->SiS_IF_DEF_CH70xx == 0)   ||
+	    (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) ||
+	    (!(SiS_IsTVOrYPbPrOrScart(SiS_Pr,HwInfo))) ) {
+	   SiS_DisplayOff(SiS_Pr);
+	}
+
+	if( (SiS_Pr->SiS_IF_DEF_CH70xx == 0)   ||
+	    (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) ||
+	    (!(SiS_IsVAMode(SiS_Pr,HwInfo))) ) {
+	   SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80);
+	}
+
+	if(HwInfo->jChipType == SIS_740) {
+	   SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f);
+	}
+
+	SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
+
+	if( (SiS_Pr->SiS_IF_DEF_CH70xx == 0)   ||
+	    (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) ||
+	    (!(SiS_IsVAMode(SiS_Pr,HwInfo))) ) {
+	   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);
+	}
+
+	if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) {
+	   if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) {
+	      SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xdf);
+	      if(HwInfo->jChipType == SIS_550) {
+	         SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xbf);
+	         SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xef);
+	      }
+	   }
+	} else {
+	   if(HwInfo->jChipType == SIS_740) {
+	      if(SiS_IsLCDOrLCDA(SiS_Pr,HwInfo)) {
+	         SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xdf);
+	      }
+	   } else if(SiS_IsVAMode(SiS_Pr,HwInfo)) {
+	      SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xdf);
+	   }
+	}
+
+	if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+	   if(SiS_IsDualEdge(SiS_Pr,HwInfo)) {
+	      /* SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xff); */
+	   } else {
+	      SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb);
+	   }
+	}
+
+	SiS_UnLockCRT2(SiS_Pr,HwInfo);
+
+	if(HwInfo->jChipType == SIS_550) {
+	   SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x80); /* DirectDVD PAL?*/
+	   SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x02,0x40); /* VB clock / 4 ? */
+	} else if( (SiS_Pr->SiS_IF_DEF_CH70xx == 0)   ||
+	           (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) ||
+		   (!(SiS_IsVAMode(SiS_Pr,HwInfo))) ) {
+	   SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0xf7);
+	}
+
+        if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) {
+	   if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) {
+	      if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) {
+	 	 SiS_PanelDelay(SiS_Pr, HwInfo, 2);
+		 SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x04);
+	      }
+	   }
+        }
+
+#endif  /* SIS315H */
+
+    }  /* 315 series */
+
+  }  /* LVDS */
+
+}
+
+/*********************************************/
+/*            ENABLE VIDEO BRIDGE            */
+/*********************************************/
+
+/* NEVER use any variables (VBInfo), this will be called
+ * from outside the context of a mode switch!
+ * MUST call getVBType before calling this
+ */
+void
+SiS_EnableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  USHORT temp=0,tempah;
+#ifdef SIS315H
+  USHORT temp1,pushax=0;
+  BOOLEAN delaylong = FALSE;
+#endif
+
+  if(SiS_Pr->SiS_VBType & VB_SISVB) {
+
+    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {   /* ====== For 301B et al  ====== */
+
+      if(HwInfo->jChipType < SIS_315H) {
+
+#ifdef SIS300     /* 300 series */
+
+	 if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) {
+	    if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+	       SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02);
+	    } else if(SiS_Pr->SiS_VBType & VB_NoLCD) {
+	       SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x00);
+	    }
+	    if(SiS_Pr->SiS_VBType & (VB_SIS301LV302LV | VB_NoLCD)) {
+	       if(!(SiS_CR36BIOSWord23d(SiS_Pr, HwInfo))) {
+	          SiS_PanelDelay(SiS_Pr, HwInfo, 0);
+	       }
+	    }
+	 }
+
+	 if((SiS_Pr->SiS_VBType & VB_NoLCD) &&
+	    (SiS_CRT2IsLCD(SiS_Pr, HwInfo))) {
+
+	    SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);   		/* Enable CRT2 */
+            SiS_DisplayOn(SiS_Pr);
+	    SiS_UnLockCRT2(SiS_Pr,HwInfo);
+	    SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0xBF);
+	    if(SiS_BridgeInSlavemode(SiS_Pr)) {
+      	       SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x01,0x1F);
+      	    } else {
+      	       SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0x1F,0x40);
+            }
+	    if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x40)) {
+	       if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x10)) {
+		  if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) {
+		     SiS_PanelDelay(SiS_Pr, HwInfo, 1);
+                  }
+		  SiS_WaitVBRetrace(SiS_Pr,HwInfo);
+                  SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x00);
+               }
+	    }
+
+	 } else {
+
+	    temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x32) & 0xDF;             /* lock mode */
+            if(SiS_BridgeInSlavemode(SiS_Pr)) {
+               tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
+               if(!(tempah & SetCRT2ToRAMDAC)) temp |= 0x20;
+            }
+            SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,temp);
+	    SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);
+	    SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1F,0x20);        /* enable VB processor */
+	    SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,0xC0);
+	    SiS_DisplayOn(SiS_Pr);
+	    if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+	       if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) {
+	          if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x10)) {
+		     if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) {
+		        SiS_PanelDelay(SiS_Pr, HwInfo, 1);
+                     }
+		     SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x01);
+	 	  }
+	       }
+	    }
+
+	 }
+
+
+#endif /* SIS300 */
+
+      } else {
+
+#ifdef SIS315H    /* 315 series */
+
+#ifdef SET_EMI
+	 UCHAR   r30=0, r31=0, r32=0, r33=0, cr36=0;
+	 /* USHORT  emidelay=0; */
+#endif
+
+	 if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+	    SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1f,0xef);
+#ifdef SET_EMI
+	    if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
+	       SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c);
+	    }
+#endif
+	 }
+
+         if(!(SiS_IsNotM650orLater(SiS_Pr, HwInfo))) {
+	    if(HwInfo->jChipType < SIS_340) {
+	       tempah = 0x10;
+	       if(SiS_LCDAEnabled(SiS_Pr, HwInfo)) {
+	          if(SiS_TVEnabled(SiS_Pr, HwInfo)) tempah = 0x18;
+	          else 			            tempah = 0x08;
+	       }
+	       SiS_SetReg(SiS_Pr->SiS_Part1Port,0x4c,tempah);
+	    }
+	 }
+
+	 if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+
+	    SiS_SetRegByte(SiS_Pr->SiS_P3c6,0x00);
+	    SiS_DisplayOff(SiS_Pr);
+	    pushax = SiS_GetReg(SiS_Pr->SiS_P3c4,0x06);
+	    if(IS_SIS740) {
+	       SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x06,0xE3);
+	    }
+
+	    if(SiS_IsVAorLCD(SiS_Pr, HwInfo)) {
+               if(!(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x26) & 0x02)) {
+		  SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 2);
+		  SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02);
+		  SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 2);
+		  if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
+		     SiS_GenericDelay(SiS_Pr, 0x4500);
+		  }
+	       }
+	    }
+
+	    if(!(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & 0x40)) {
+               SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 10);
+	       delaylong = TRUE;
+	    }
+
+	 }
+
+	 if(!(SiS_IsVAMode(SiS_Pr,HwInfo))) {
+
+            temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x32) & 0xDF;
+	    if(SiS_BridgeInSlavemode(SiS_Pr)) {
+               tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
+               if(!(tempah & SetCRT2ToRAMDAC)) {
+		  if(!(SiS_LCDAEnabled(SiS_Pr, HwInfo))) temp |= 0x20;
+	       }
+            }
+            SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,temp);
+
+	    SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);                   /* enable CRT2 */
+
+	    SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f);
+	    SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80);
+
+	    if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+	       SiS_PanelDelay(SiS_Pr, HwInfo, 2);
+	    }
+
+	 } else {
+
+	    SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x20);
+
+	 }
+
+	 SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1f,0x20);
+	 SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80);
+
+	 tempah = 0xc0;
+	 if(SiS_IsDualEdge(SiS_Pr, HwInfo)) {
+	    tempah = 0x80;
+	    if(!(SiS_IsVAMode(SiS_Pr, HwInfo))) tempah = 0x40;
+	 }
+         SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,tempah);
+
+	 if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+
+	    SiS_PanelDelay(SiS_Pr, HwInfo, 2);
+
+	    SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1f,0x10);
+	    SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80);
+
+	    if(SiS_Pr->SiS_CustomT != CUT_CLEVO1400) {
+#ifdef SET_EMI
+	       if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
+	          SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c);
+		  SiS_GenericDelay(SiS_Pr, 0x500);
+	       }
+#endif
+	       SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x0c);
+
+	       if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
+#ifdef SET_EMI
+		  cr36 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36);
+
+		  if(SiS_Pr->SiS_ROMNew) {
+		     UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+		     USHORT romptr = GetLCDStructPtr661_2(SiS_Pr, HwInfo);
+		     if(romptr) {
+		        SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x20); /* Reset */
+			SiS_Pr->EMI_30 = 0;
+			SiS_Pr->EMI_31 = ROMAddr[romptr + SiS_Pr->SiS_EMIOffset + 0];
+			SiS_Pr->EMI_32 = ROMAddr[romptr + SiS_Pr->SiS_EMIOffset + 1];
+			SiS_Pr->EMI_33 = ROMAddr[romptr + SiS_Pr->SiS_EMIOffset + 2];
+			if(ROMAddr[romptr + 1] & 0x10) SiS_Pr->EMI_30 = 0x40;
+			/* emidelay = SISGETROMW((romptr + 0x22)); */
+			SiS_Pr->HaveEMI = SiS_Pr->HaveEMILCD = SiS_Pr->OverruleEMI = TRUE;
+		     }
+		  }
+
+		  /*                                              (P4_30|0x40)  */
+		  /* Compal 1400x1050: 0x05, 0x60, 0x00                YES  (1.10.7w;  CR36=69)      */
+		  /* Compal 1400x1050: 0x0d, 0x70, 0x40                YES  (1.10.7x;  CR36=69)      */
+		  /* Acer   1280x1024: 0x12, 0xd0, 0x6b                NO   (1.10.9k;  CR36=73)      */
+		  /* Compaq 1280x1024: 0x0d, 0x70, 0x6b                YES  (1.12.04b; CR36=03)      */
+		  /* Clevo   1024x768: 0x05, 0x60, 0x33                NO   (1.10.8e;  CR36=12, DL!) */
+		  /* Clevo   1024x768: 0x0d, 0x70, 0x40 (if type == 3) YES  (1.10.8y;  CR36=?2)      */
+		  /* Clevo   1024x768: 0x05, 0x60, 0x33 (if type != 3) YES  (1.10.8y;  CR36=?2)      */
+		  /* Asus    1024x768: ?                                ?   (1.10.8o;  CR36=?2)      */
+		  /* Asus    1024x768: 0x08, 0x10, 0x3c (problematic)  YES  (1.10.8q;  CR36=22)      */
+
+		  if(SiS_Pr->HaveEMI) {
+		     r30 = SiS_Pr->EMI_30; r31 = SiS_Pr->EMI_31;
+		     r32 = SiS_Pr->EMI_32; r33 = SiS_Pr->EMI_33;
+		  } else {
+		     r30 = 0;
+		  }
+
+		  /* EMI_30 is read at driver start; however, the BIOS sets this
+		   * (if it is used) only if the LCD is in use. In case we caught
+		   * the machine while on TV output, this bit is not set and we
+		   * don't know if it should be set - hence our detection is wrong.
+		   * Work-around this here:
+		   */
+
+		  if((!SiS_Pr->HaveEMI) || (!SiS_Pr->HaveEMILCD)) {
+		     switch((cr36 & 0x0f)) {
+		     case 2:
+			r30 |= 0x40;
+			if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) r30 &= ~0x40;
+			if(!SiS_Pr->HaveEMI) {
+			   r31 = 0x05; r32 = 0x60; r33 = 0x33;
+			   if((cr36 & 0xf0) == 0x30) {
+			      r31 = 0x0d; r32 = 0x70; r33 = 0x40;
+			   }
+			}
+			break;
+		     case 3:  /* 1280x1024 */
+			if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) r30 |= 0x40;
+			if(!SiS_Pr->HaveEMI) {
+			   r31 = 0x12; r32 = 0xd0; r33 = 0x6b;
+			   if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
+			      r31 = 0x0d; r32 = 0x70; r33 = 0x6b;
+			   }
+			}
+			break;
+		     case 9:  /* 1400x1050 */
+			r30 |= 0x40;
+			if(!SiS_Pr->HaveEMI) {
+			   r31 = 0x05; r32 = 0x60; r33 = 0x00;
+			   if(SiS_Pr->SiS_CustomT == CUT_COMPAL1400_2) {
+			      r31 = 0x0d; r32 = 0x70; r33 = 0x40;  /* BIOS values */
+			   }
+			}
+			break;
+		     case 11: /* 1600x1200 - unknown */
+			r30 |= 0x40;
+			if(!SiS_Pr->HaveEMI) {
+			   r31 = 0x05; r32 = 0x60; r33 = 0x00;
+			}
+		     }
+                  }
+
+		  /* BIOS values don't work so well sometimes */
+		  if(!SiS_Pr->OverruleEMI) {
+#ifdef COMPAL_HACK
+		     if(SiS_Pr->SiS_CustomT == CUT_COMPAL1400_2) {
+		        if((cr36 & 0x0f) == 0x09) {
+			   r30 = 0x60; r31 = 0x05; r32 = 0x60; r33 = 0x00;
+			}
+ 		     }
+#endif
+#ifdef COMPAQ_HACK
+		     if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
+		        if((cr36 & 0x0f) == 0x03) {
+			   r30 = 0x20; r31 = 0x12; r32 = 0xd0; r33 = 0x6b;
+			}
+		     }
+#endif
+#ifdef ASUS_HACK
+		     if(SiS_Pr->SiS_CustomT == CUT_ASUSA2H_2) {
+		        if((cr36 & 0x0f) == 0x02) {
+			   /* r30 = 0x60; r31 = 0x05; r32 = 0x60; r33 = 0x33;  */   /* rev 2 */
+			   /* r30 = 0x20; r31 = 0x05; r32 = 0x60; r33 = 0x33;  */   /* rev 3 */
+			   /* r30 = 0x60; r31 = 0x0d; r32 = 0x70; r33 = 0x40;  */   /* rev 4 */
+			   /* r30 = 0x20; r31 = 0x0d; r32 = 0x70; r33 = 0x40;  */   /* rev 5 */
+			}
+		     }
+#endif
+ 		  }
+
+		  if(!(SiS_Pr->OverruleEMI && (!r30) && (!r31) && (!r32) && (!r33))) {
+		     SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x20); /* Reset */
+		     SiS_GenericDelay(SiS_Pr, 0x500);
+		  }
+		  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x31,r31);
+		  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x32,r32);
+		  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x33,r33);
+#endif	/* SET_EMI */
+
+		  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x34,0x10);
+
+#ifdef SET_EMI
+		  if( (SiS_LCDAEnabled(SiS_Pr, HwInfo)) ||
+	              (SiS_CRT2IsLCD(SiS_Pr, HwInfo)) ) {
+	             if(r30 & 0x40) {
+		        SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 5);
+			if(delaylong) {
+			   SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 5);
+			   delaylong = FALSE;
+			}
+			SiS_WaitVBRetrace(SiS_Pr,HwInfo);
+			if(SiS_Pr->SiS_CustomT == CUT_ASUSA2H_2) {
+			   SiS_GenericDelay(SiS_Pr, 0x500);
+			}
+	                SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x40);   /* Enable */
+	             }
+		  }
+#endif
+	       }
+	    }
+
+	    if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) {
+	       if(SiS_IsVAorLCD(SiS_Pr, HwInfo)) {
+		  SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 10);
+		  if(delaylong) {
+		     SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 10);
+		  }
+                  SiS_WaitVBRetrace(SiS_Pr,HwInfo);
+		  if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
+	 	     SiS_GenericDelay(SiS_Pr, 0x500);
+		  }
+		  SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x01);
+	       }
+	    }
+
+	    SiS_SetReg(SiS_Pr->SiS_P3c4,0x06,pushax);
+	    SiS_DisplayOn(SiS_Pr);
+	    SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xff);
+
+	 }
+
+	 if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) {
+	    SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
+	 }
+
+#endif /* SIS315H */
+
+      }
+
+    } else {	/* ============  For 301 ================ */
+
+       if(HwInfo->jChipType < SIS_315H) {
+          if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) {
+             SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x00);
+	     SiS_PanelDelay(SiS_Pr, HwInfo, 0);
+	  }
+       }
+
+       temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x32) & 0xDF;          /* lock mode */
+       if(SiS_BridgeInSlavemode(SiS_Pr)) {
+          tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
+          if(!(tempah & SetCRT2ToRAMDAC)) temp |= 0x20;
+       }
+       SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,temp);
+
+       SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);                  /* enable CRT2 */
+
+       if(HwInfo->jChipType >= SIS_315H) {
+          temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x2E);
+          if(!(temp & 0x80)) {
+             SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80);         /* BVBDOENABLE=1 */
+	  }
+       }
+
+       SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1F,0x20);     /* enable VB processor */
+
+       SiS_VBLongWait(SiS_Pr);
+       SiS_DisplayOn(SiS_Pr);
+       if(HwInfo->jChipType >= SIS_315H) {
+          SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
+       }
+       SiS_VBLongWait(SiS_Pr);
+
+       if(HwInfo->jChipType < SIS_315H) {
+          if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) {
+	     SiS_PanelDelay(SiS_Pr, HwInfo, 1);
+             SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x00);
+	  }
+       }
+
+    }
+
+  } else {   /* =================== For LVDS ================== */
+
+    if(HwInfo->jChipType < SIS_315H) {
+
+#ifdef SIS300    /* 300 series */
+
+       if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) {
+          if(HwInfo->jChipType == SIS_730) {
+	     SiS_PanelDelay(SiS_Pr, HwInfo, 1);
+	     SiS_PanelDelay(SiS_Pr, HwInfo, 1);
+	     SiS_PanelDelay(SiS_Pr, HwInfo, 1);
+	  }
+          SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x00);
+	  if(!(SiS_CR36BIOSWord23d(SiS_Pr,HwInfo))) {
+	     SiS_PanelDelay(SiS_Pr, HwInfo, 0);
+	  }
+       }
+
+       SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);
+       SiS_DisplayOn(SiS_Pr);
+       SiS_UnLockCRT2(SiS_Pr,HwInfo);
+       SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0xBF);
+       if(SiS_BridgeInSlavemode(SiS_Pr)) {
+      	  SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x01,0x1F);
+       } else {
+      	  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0x1F,0x40);
+       }
+
+       if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
+          if(!(SiS_CRT2IsLCD(SiS_Pr, HwInfo))) {
+	     SiS_WaitVBRetrace(SiS_Pr, HwInfo);
+	     SiS_SetCH700x(SiS_Pr,0x0B0E);
+          }
+       }
+
+       if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) {
+          if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x40)) {
+             if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x10)) {
+	        if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) {
+	 	   SiS_PanelDelay(SiS_Pr, HwInfo, 1);
+        	   SiS_PanelDelay(SiS_Pr, HwInfo, 1);
+	        }
+	        SiS_WaitVBRetrace(SiS_Pr, HwInfo);
+                SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x00);
+             }
+	  }
+       }
+
+#endif  /* SIS300 */
+
+    } else {
+
+#ifdef SIS315H    /* 315 series */
+
+       if(!(SiS_IsNotM650orLater(SiS_Pr,HwInfo))) {
+          if(HwInfo->jChipType < SIS_340) {
+             SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x4c,0x18);
+	  }
+       }
+
+       if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) {
+	  if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) {
+	     SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x00);
+	     SiS_PanelDelay(SiS_Pr, HwInfo, 0);
+          }
+       }
+
+       SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);
+       SiS_UnLockCRT2(SiS_Pr,HwInfo);
+
+       SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0xf7);
+
+       if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+          temp = SiS_GetCH701x(SiS_Pr,0x66);
+	  temp &= 0x20;
+	  SiS_Chrontel701xBLOff(SiS_Pr);
+       }
+
+       if(HwInfo->jChipType != SIS_550) {
+          SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f);
+       }
+
+       if(HwInfo->jChipType == SIS_740) {
+          if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+             if(SiS_IsLCDOrLCDA(SiS_Pr, HwInfo)) {
+	   	SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x20);
+	     }
+	  }
+       }
+
+       temp1 = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x2E);
+       if(!(temp1 & 0x80)) {
+          SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80);
+       }
+
+       if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+          if(temp) {
+	     SiS_Chrontel701xBLOn(SiS_Pr, HwInfo);
+	  }
+       }
+
+       if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) {
+          if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) {
+	     SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x20);
+	     if(HwInfo->jChipType == SIS_550) {
+		SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x40);
+		SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x10);
+	     }
+	  }
+       } else if(SiS_IsVAMode(SiS_Pr,HwInfo)) {
+          if(HwInfo->jChipType != SIS_740) {
+             SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x20);
+	  }
+       }
+
+       if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) {
+          SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
+       }
+
+       if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+       	  if(SiS_IsTVOrYPbPrOrScart(SiS_Pr,HwInfo)) {
+             SiS_Chrontel701xOn(SiS_Pr,HwInfo);
+          }
+          if( (SiS_IsVAMode(SiS_Pr,HwInfo)) ||
+	      (SiS_IsLCDOrLCDA(SiS_Pr,HwInfo)) ) {
+             SiS_ChrontelDoSomething1(SiS_Pr,HwInfo);
+          }
+       }
+
+       if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+       	  if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) {
+ 	     if( (SiS_IsVAMode(SiS_Pr,HwInfo)) ||
+	         (SiS_IsLCDOrLCDA(SiS_Pr,HwInfo)) ) {
+	     	SiS_Chrontel701xBLOn(SiS_Pr, HwInfo);
+	     	SiS_ChrontelInitTVVSync(SiS_Pr,HwInfo);
+             }
+       	  }
+       } else if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) {
+       	  if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) {
+	     if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) {
+		SiS_PanelDelay(SiS_Pr, HwInfo, 1);
+		SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x00);
+	     }
+	  }
+       }
+
+#endif  /* SIS315H */
+
+    } /* 310 series */
+
+  }  /* LVDS */
+
+}
+
+/*********************************************/
+/*         SET PART 1 REGISTER GROUP         */
+/*********************************************/
+
+/* Set CRT2 OFFSET / PITCH */
+static void
+SiS_SetCRT2Offset(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+	          USHORT RRTI, PSIS_HW_INFO HwInfo)
+{
+  USHORT offset;
+  UCHAR temp;
+
+  if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) return;
+
+  offset = SiS_GetOffset(SiS_Pr,ModeNo,ModeIdIndex,RRTI,HwInfo);
+
+  if((SiS_Pr->SiS_LCDResInfo == Panel_640x480_2) ||
+     (SiS_Pr->SiS_LCDResInfo == Panel_640x480_3)) {
+     offset >>= 1;
+  }
+
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x07,(offset & 0xFF));
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x09,(offset >> 8));
+  temp = (UCHAR)(((offset >> 3) & 0xFF) + 1);
+  if(offset % 8) temp++;
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x03,temp);
+}
+
+/* Set CRT2 sync and PanelLink mode */
+static void
+SiS_SetCRT2Sync(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT RefreshRateTableIndex,
+                PSIS_HW_INFO HwInfo)
+{
+  USHORT tempah=0,tempbl,infoflag;
+
+  tempbl = 0xC0;
+
+  if(SiS_Pr->UseCustomMode) {
+     infoflag = SiS_Pr->CInfoFlag;
+  } else {
+     infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+  }
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {					/* LVDS */
+
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+        tempah = 0;
+     } else if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (SiS_Pr->SiS_LCDInfo & LCDSync)) {
+        tempah = SiS_Pr->SiS_LCDInfo;
+     } else tempah = infoflag >> 8;
+     tempah &= 0xC0;
+     tempah |= 0x20;
+     if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10;
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+        if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) ||
+           (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) {
+	   tempah |= 0xf0;
+        }
+	if( (SiS_Pr->SiS_IF_DEF_FSTN) ||
+            (SiS_Pr->SiS_IF_DEF_DSTN) ||
+            (SiS_Pr->SiS_IF_DEF_TRUMPION) ||
+            (SiS_Pr->SiS_CustomT == CUT_PANEL848) ) {
+           tempah |= 0x30;
+        }
+     }
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+        if(HwInfo->jChipType >= SIS_315H) {
+           tempah >>= 3;
+	   tempah &= 0x18;
+           SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xE7,tempah);
+	   /* Don't care about 12/18/24 bit mode - TV is via VGA, not PL */
+        } else {
+           SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,0xe0);
+        }
+     } else {
+        SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah);
+     }
+
+  } else if(SiS_Pr->SiS_VBType & VB_SISVB) {
+
+     if(HwInfo->jChipType < SIS_315H) {
+
+#ifdef SIS300  /* ---- 300 series --- */
+
+        if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {			/* 630 - 301B(-DH) */
+
+	   tempah = infoflag >> 8;
+	   tempbl = 0;
+           if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+	      if(SiS_Pr->SiS_LCDInfo & LCDSync) {
+	         tempah = SiS_Pr->SiS_LCDInfo;
+		 tempbl = (tempah >> 6) & 0x03;
+              }
+           }
+           tempah &= 0xC0;
+           tempah |= 0x20;
+           if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10;
+  	   tempah |= 0xc0;
+           SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah);
+	   if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) {
+	      SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xf0,tempbl);
+	   }
+
+        } else {							/* 630 - 301 */
+
+           tempah = infoflag >> 8;
+           tempah &= 0xC0;
+           tempah |= 0x20;
+	   if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10;
+           SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah);
+
+        }
+
+#endif /* SIS300 */
+
+     } else {
+
+#ifdef SIS315H  /* ------- 315 series ------ */
+
+        if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {	  		/* 315 - LVDS */
+
+	   tempbl = 0;
+	   if((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) &&
+	      (SiS_Pr->SiS_LCDResInfo == Panel_1280x1024)) {
+	      tempah = infoflag >> 8;
+	      if(SiS_Pr->SiS_LCDInfo & LCDSync) {
+	        tempbl = ((SiS_Pr->SiS_LCDInfo & 0xc0) >> 6);
+	      }
+	   } else if((SiS_Pr->SiS_CustomT == CUT_CLEVO1400)  &&
+	             (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050)) {
+       	      tempah = infoflag >> 8;
+	      tempbl = 0x03;
+	   } else {
+              tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37);
+	      tempbl = (tempah >> 6) & 0x03;
+	      tempbl |= 0x08;
+	      if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempbl |= 0x04;
+	   }
+	   tempah &= 0xC0;
+           tempah |= 0x20;
+           if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10;
+	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)   tempah |= 0xc0;
+           SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah);
+	   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+	      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+	         SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xf0,tempbl);
+	      }
+	   }
+
+        } else {							/* 315 - TMDS */
+
+           tempah = tempbl = infoflag >> 8;
+	   if(!SiS_Pr->UseCustomMode) {
+	      tempbl = 0;
+	      if((SiS_Pr->SiS_VBType & VB_SIS301C) && (SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) {
+	         if(ModeNo <= 0x13) {
+	            tempah = SiS_GetRegByte((SiS_Pr->SiS_P3ca+0x02));
+  	         }
+	      }
+	      if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+	         if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
+	            if(SiS_Pr->SiS_LCDInfo & LCDSync) {
+	               tempah = SiS_Pr->SiS_LCDInfo;
+		       tempbl = (tempah >> 6) & 0x03;
+		    }
+	         }
+	      }
+	   }
+	   tempah &= 0xC0;
+           tempah |= 0x20;
+           if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10;
+	   if(SiS_Pr->SiS_VBType & VB_NoLCD) {
+	      /* Imitate BIOS bug */
+	      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)  tempah |= 0xc0;
+	   }
+	   if((SiS_Pr->SiS_VBType & VB_SIS301C) && (SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) {
+	      tempah >>= 3;
+	      tempah &= 0x18;
+	      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xe7,tempah);
+	   } else {
+              SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah);
+	      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+	         if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+	            SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xf0,tempbl);
+		 }
+	      }
+	   }
+
+        }
+#endif  /* SIS315H */
+      }
+   }
+}
+
+/* Set CRT2 FIFO on 300/630/730 */
+#ifdef SIS300
+static void
+SiS_SetCRT2FIFO_300(SiS_Private *SiS_Pr,USHORT ModeNo,
+                    PSIS_HW_INFO HwInfo)
+{
+  UCHAR  *ROMAddr  = HwInfo->pjVirtualRomBase;
+  USHORT temp,index;
+  USHORT modeidindex,refreshratetableindex;
+  USHORT VCLK=0,MCLK,colorth=0,data2=0;
+  USHORT tempal, tempah, tempbx, tempcl, tempax;
+  USHORT CRT1ModeNo,CRT2ModeNo;
+  USHORT SelectRate_backup;
+  ULONG  data,eax;
+  const UCHAR  LatencyFactor[] = {
+  	97, 88, 86, 79, 77, 00,       /*; 64  bit    BQ=2   */
+        00, 87, 85, 78, 76, 54,       /*; 64  bit    BQ=1   */
+        97, 88, 86, 79, 77, 00,       /*; 128 bit    BQ=2   */
+        00, 79, 77, 70, 68, 48,       /*; 128 bit    BQ=1   */
+        80, 72, 69, 63, 61, 00,       /*; 64  bit    BQ=2   */
+        00, 70, 68, 61, 59, 37,       /*; 64  bit    BQ=1   */
+        86, 77, 75, 68, 66, 00,       /*; 128 bit    BQ=2   */
+        00, 68, 66, 59, 57, 37        /*; 128 bit    BQ=1   */
+  };
+  const UCHAR  LatencyFactor730[] = {
+         69, 63, 61,
+	 86, 79, 77,
+	103, 96, 94,
+	120,113,111,
+	137,130,128,    /* <-- last entry, data below */
+	137,130,128,	/* to avoid using illegal values */
+	137,130,128,
+	137,130,128,
+	137,130,128,
+	137,130,128,
+	137,130,128,
+	137,130,128,
+	137,130,128,
+	137,130,128,
+	137,130,128,
+	137,130,128,
+  };
+  const UCHAR ThLowB[]   = {
+  	81, 4, 72, 6, 88, 8,120,12,
+        55, 4, 54, 6, 66, 8, 90,12,
+        42, 4, 45, 6, 55, 8, 75,12
+  };
+  const UCHAR ThTiming[] = {
+  	1, 2, 2, 3, 0, 1, 1, 2
+  };
+
+  SelectRate_backup = SiS_Pr->SiS_SelectCRT2Rate;
+
+  if(!SiS_Pr->CRT1UsesCustomMode) {
+
+     CRT1ModeNo = SiS_Pr->SiS_CRT1Mode;                                 /* get CRT1 ModeNo */
+     SiS_SearchModeID(SiS_Pr, &CRT1ModeNo, &modeidindex);
+     SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2);
+     SiS_Pr->SiS_SelectCRT2Rate = 0;
+     refreshratetableindex = SiS_GetRatePtr(SiS_Pr, CRT1ModeNo, modeidindex, HwInfo);
+
+     if(CRT1ModeNo >= 0x13) {
+        index = SiS_Pr->SiS_RefIndex[refreshratetableindex].Ext_CRTVCLK;
+        index &= 0x3F;
+        VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;			/* Get VCLK */
+
+	colorth = SiS_GetColorDepth(SiS_Pr,CRT1ModeNo,modeidindex); 	/* Get colordepth */
+        colorth >>= 1;
+        if(!colorth) colorth++;
+     }
+
+  } else {
+
+     CRT1ModeNo = 0xfe;
+     VCLK = SiS_Pr->CSRClock_CRT1;					/* Get VCLK */
+     data2 = (SiS_Pr->CModeFlag_CRT1 & ModeTypeMask) - 2;
+     switch(data2) {							/* Get color depth */
+        case 0 : colorth = 1; break;
+        case 1 : colorth = 1; break;
+        case 2 : colorth = 2; break;
+        case 3 : colorth = 2; break;
+        case 4 : colorth = 3; break;
+        case 5 : colorth = 4; break;
+        default: colorth = 2;
+     }
+
+  }
+
+  if(CRT1ModeNo >= 0x13) {
+    if(HwInfo->jChipType == SIS_300) {
+       index = SiS_GetReg(SiS_Pr->SiS_P3c4,0x3A);
+    } else {
+       index = SiS_GetReg(SiS_Pr->SiS_P3c4,0x1A);
+    }
+    index &= 0x07;
+    MCLK = SiS_Pr->SiS_MCLKData_0[index].CLOCK;				/* Get MCLK */
+
+    data2 = (colorth * VCLK) / MCLK;
+
+    temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14);
+    temp = ((temp & 0x00FF) >> 6) << 1;
+    if(temp == 0) temp = 1;
+    temp <<= 2;
+    temp &= 0xff;
+
+    data2 = temp - data2;
+
+    if((28 * 16) % data2) {
+      	data2 = (28 * 16) / data2;
+      	data2++;
+    } else {
+      	data2 = (28 * 16) / data2;
+    }
+
+    if(HwInfo->jChipType == SIS_300) {
+
+	tempah = SiS_GetReg(SiS_Pr->SiS_P3c4,0x18);
+	tempah &= 0x62;
+	tempah >>= 1;
+	tempal = tempah;
+	tempah >>= 3;
+	tempal |= tempah;
+	tempal &= 0x07;
+	tempcl = ThTiming[tempal];
+	tempbx = SiS_GetReg(SiS_Pr->SiS_P3c4,0x16);
+	tempbx >>= 6;
+	tempah = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14);
+	tempah >>= 4;
+	tempah &= 0x0c;
+	tempbx |= tempah;
+	tempbx <<= 1;
+	tempal = ThLowB[tempbx + 1];
+	tempal *= tempcl;
+	tempal += ThLowB[tempbx];
+	data = tempal;
+
+    } else if(HwInfo->jChipType == SIS_730) {
+
+#ifdef LINUX_KERNEL
+       SiS_SetRegLong(0xcf8,0x80000050);
+       eax = SiS_GetRegLong(0xcfc);
+#else
+       eax = pciReadLong(0x00000000, 0x50);
+#endif
+       tempal = (USHORT)(eax >> 8);
+       tempal &= 0x06;
+       tempal <<= 5;
+
+#ifdef LINUX_KERNEL
+       SiS_SetRegLong(0xcf8,0x800000A0);
+       eax = SiS_GetRegLong(0xcfc);
+#else
+       eax = pciReadLong(0x00000000, 0xA0);
+#endif
+       temp = (USHORT)(eax >> 28);
+       temp &= 0x0F;
+       tempal |= temp;
+
+       tempbx = tempal;   /* BIOS BUG (2.04.5d, 2.04.6a use ah here, which is unset!) */
+       tempbx = 0;        /* -- do it like the BIOS anyway... */
+       tempax = tempbx;
+       tempbx &= 0xc0;
+       tempbx >>= 6;
+       tempax &= 0x0f;
+       tempax *= 3;
+       tempbx += tempax;
+
+       data = LatencyFactor730[tempbx];
+       data += 15;
+       temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14);
+       if(!(temp & 0x80)) data += 5;
+
+    } else {
+
+       index = 0;
+       temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14);
+       if(temp & 0x0080) index += 12;
+
+#ifdef LINUX_KERNEL
+       SiS_SetRegLong(0xcf8,0x800000A0);
+       eax = SiS_GetRegLong(0xcfc);
+#else
+       /* We use pci functions X offers. We use tag 0, because
+        * we want to read/write to the host bridge (which is always
+        * 00:00.0 on 630, 730 and 540), not the VGA device.
+        */
+       eax = pciReadLong(0x00000000, 0xA0);
+#endif
+       temp = (USHORT)(eax >> 24);
+       if(!(temp&0x01)) index += 24;
+
+#ifdef LINUX_KERNEL
+       SiS_SetRegLong(0xcf8,0x80000050);
+       eax = SiS_GetRegLong(0xcfc);
+#else
+       eax = pciReadLong(0x00000000, 0x50);
+#endif
+       temp=(USHORT)(eax >> 24);
+       if(temp & 0x01) index += 6;
+
+       temp = (temp & 0x0F) >> 1;
+       index += temp;
+
+       data = LatencyFactor[index];
+       data += 15;
+       temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14);
+       if(!(temp & 0x80)) data += 5;
+    }
+
+    data += data2;				/* CRT1 Request Period */
+
+    SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
+    SiS_Pr->SiS_SelectCRT2Rate = SelectRate_backup;
+
+    if(!SiS_Pr->UseCustomMode) {
+
+       CRT2ModeNo = ModeNo;
+       SiS_SearchModeID(SiS_Pr, &CRT2ModeNo, &modeidindex);
+
+       refreshratetableindex = SiS_GetRatePtr(SiS_Pr, CRT2ModeNo, modeidindex, HwInfo);
+
+       index = SiS_GetVCLK2Ptr(SiS_Pr,CRT2ModeNo,modeidindex,
+                               refreshratetableindex,HwInfo);
+       VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;                /* Get VCLK  */
+
+       if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) {
+          if(SiS_Pr->SiS_UseROM) {
+	     if(ROMAddr[0x220] & 0x01) {
+                VCLK = ROMAddr[0x229] | (ROMAddr[0x22a] << 8);
+	     }
+          }
+       }
+
+    } else {
+
+       CRT2ModeNo = 0xfe;
+       VCLK = SiS_Pr->CSRClock;					/* Get VCLK */
+
+    }
+
+    colorth = SiS_GetColorDepth(SiS_Pr,CRT2ModeNo,modeidindex); /* Get colordepth */
+    colorth >>= 1;
+    if(!colorth) colorth++;
+
+    data = data * VCLK * colorth;
+    if(data % (MCLK << 4)) {
+      	data = data / (MCLK << 4);
+      	data++;
+    } else {
+      	data = data / (MCLK << 4);
+    }
+
+    if(data <= 6) data = 6;
+    if(data > 0x14) data = 0x14;
+
+    temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x01);
+    if(HwInfo->jChipType == SIS_300) {
+       if(data <= 0x0f) temp = (temp & (~0x1F)) | 0x13;
+       else             temp = (temp & (~0x1F)) | 0x16;
+       if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) {
+       	  temp = (temp & (~0x1F)) | 0x13;
+       }
+    } else {
+       if( ( (HwInfo->jChipType == SIS_630) ||
+             (HwInfo->jChipType == SIS_730) )  &&
+           (HwInfo->jChipRevision >= 0x30) ) /* 630s or 730(s?) */
+      {
+	  temp = (temp & (~0x1F)) | 0x1b;
+      } else {
+	  temp = (temp & (~0x1F)) | 0x16;
+      }
+    }
+    SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0xe0,temp);
+
+    if( (HwInfo->jChipType == SIS_630) &&
+        (HwInfo->jChipRevision >= 0x30) ) /* 630s, NOT 730 */
+    {
+   	if(data > 0x13) data = 0x13;
+    }
+    SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x02,0xe0,data);
+
+  } else {  /* If mode <= 0x13, we just restore everything */
+
+    SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
+    SiS_Pr->SiS_SelectCRT2Rate = SelectRate_backup;
+
+  }
+}
+#endif
+
+/* Set CRT2 FIFO on 315/330 series */
+#ifdef SIS315H
+static void
+SiS_SetCRT2FIFO_310(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x01,0x3B);
+  if( (HwInfo->jChipType == SIS_760)      &&
+      (SiS_Pr->SiS_SysFlags & SF_760LFB)  &&
+      (SiS_Pr->SiS_ModeType == Mode32Bpp) &&
+      (SiS_Pr->SiS_VGAHDE >= 1280)	  &&
+      (SiS_Pr->SiS_VGAVDE >= 1024) ) {
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2f,0x03);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x01,0x3b);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x4d,0xc0);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2f,0x01);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x4d,0xc0);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,0x6e);
+  } else {
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x02,~0x3f,0x04);
+  }
+
+}
+#endif
+
+static USHORT
+SiS_GetVGAHT2(SiS_Private *SiS_Pr)
+{
+  ULONG tempax,tempbx;
+
+  tempbx = (SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE) * SiS_Pr->SiS_RVBHCMAX;
+  tempax = (SiS_Pr->SiS_VT - SiS_Pr->SiS_VDE) * SiS_Pr->SiS_RVBHCFACT;
+  tempax = (tempax * SiS_Pr->SiS_HT) / tempbx;
+  return((USHORT)tempax);
+}
+
+/* Set Part 1 / SiS bridge slave mode */
+static void
+SiS_SetGroup1_301(SiS_Private *SiS_Pr, USHORT ModeNo,USHORT ModeIdIndex,
+                  PSIS_HW_INFO HwInfo,USHORT RefreshRateTableIndex)
+{
+  USHORT  push1,push2;
+  USHORT  tempax,tempbx,tempcx,temp;
+  USHORT  resinfo,modeflag,xres=0;
+  unsigned char p1_7, p1_8;
+
+  if(ModeNo <= 0x13) {
+     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+     resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+  } else if(SiS_Pr->UseCustomMode) {
+     modeflag = SiS_Pr->CModeFlag;
+     resinfo = 0;
+     xres = SiS_Pr->CHDisplay;
+  } else {
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+     resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+     xres = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].XRes;
+  }
+
+  /* The following is only done if bridge is in slave mode: */
+
+  if((HwInfo->jChipType >= SIS_661) && (ModeNo > 0x13)) {
+     if(xres >= 1600) {
+        SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x31,0x04);
+     }
+  }
+
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x03,0xff);                  /* set MAX HT */
+
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)  modeflag |= Charx8Dot;
+
+  if(modeflag & Charx8Dot) tempcx = 0x08;
+  else                     tempcx = 0x09;
+
+  tempax = SiS_Pr->SiS_VGAHDE;                                 	/* 0x04 Horizontal Display End */
+  if(modeflag & HalfDCLK) tempax >>= 1;
+  tempax = ((tempax / tempcx) - 1) & 0xff;
+  tempbx = tempax;
+
+  temp = tempax;
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x04,temp);
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+     if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) {
+        temp += 2;
+     }
+  }
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+     if(resinfo == SIS_RI_800x600) temp -= 2;
+  }
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x05,temp);                 /* 0x05 Horizontal Display Start */
+
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x06,0x03);                 /* 0x06 Horizontal Blank end     */
+
+  tempax = 0xFFFF;
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) tempax = SiS_GetVGAHT2(SiS_Pr);
+  if(tempax >= SiS_Pr->SiS_VGAHT) tempax = SiS_Pr->SiS_VGAHT;
+  if(modeflag & HalfDCLK)         tempax >>= 1;
+  tempax = (tempax / tempcx) - 5;
+  tempcx = tempax;
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+     temp = tempcx - 1;
+     if(!(modeflag & HalfDCLK)) {
+        temp -= 6;
+        if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) {
+           temp -= 2;
+           if(ModeNo > 0x13) temp -= 10;
+        }
+     }
+  } else {
+     tempcx = (tempcx + tempbx) >> 1;
+     temp = (tempcx & 0x00FF) + 2;
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+        temp--;
+        if(!(modeflag & HalfDCLK)) {
+           if((modeflag & Charx8Dot)) {
+              temp += 4;
+              if(SiS_Pr->SiS_VGAHDE >= 800) temp -= 6;
+              if(HwInfo->jChipType >= SIS_315H) {
+	         if(SiS_Pr->SiS_VGAHDE == 800) temp += 2;
+              }
+           }
+        }
+     } else {
+        if(!(modeflag & HalfDCLK)) {
+           temp -= 4;
+           if((SiS_Pr->SiS_LCDResInfo != Panel_1280x960) &&
+	      (SiS_Pr->SiS_LCDResInfo != Panel_1600x1200)) {
+              if(SiS_Pr->SiS_VGAHDE >= 800) {
+                 temp -= 7;
+	         if(HwInfo->jChipType < SIS_315H) {
+                    if(SiS_Pr->SiS_ModeType == ModeEGA) {
+                       if(SiS_Pr->SiS_VGAVDE == 1024) {
+                          temp += 15;
+                          if(SiS_Pr->SiS_LCDResInfo != Panel_1280x1024)
+		  	     temp += 7;
+                       }
+                    }
+	         }
+		 if(SiS_Pr->SiS_LCDResInfo != Panel_1400x1050) {
+                    if(SiS_Pr->SiS_VGAHDE >= 1280) {
+                       if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) temp += 28;
+		    }
+                 }
+              }
+           }
+        }
+     }
+  }
+
+  p1_7 = temp;
+  p1_8 = 0x00;
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+     if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) {
+        if(ModeNo <= 0x01) {
+	   p1_7 = 0x2a;
+	   if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) p1_8 = 0x61;
+	   else 	      			p1_8 = 0x41;
+	} else if(SiS_Pr->SiS_ModeType == ModeText) {
+	   if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) p1_7 = 0x54;
+	   else 	    			p1_7 = 0x55;
+	   p1_8 = 0x00;
+	} else if(ModeNo <= 0x13) {
+	   if(modeflag & HalfDCLK) {
+	      if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) {
+		 p1_7 = 0x30;
+		 p1_8 = 0x03;
+	      } else {
+	 	 p1_7 = 0x2f;
+		 p1_8 = 0x02;
+	      }
+	   } else {
+	      p1_7 = 0x5b;
+	      p1_8 = 0x03;
+	   }
+	} else if( ((HwInfo->jChipType >= SIS_315H) &&
+	            ((ModeNo == 0x50) || (ModeNo == 0x56) || (ModeNo == 0x53))) ||
+	           ((HwInfo->jChipType < SIS_315H) &&
+		    (resinfo == SIS_RI_320x200 || resinfo == SIS_RI_320x240)) ) {
+	   if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) {
+	      p1_7 = 0x30,
+	      p1_8 = 0x03;
+	   } else {
+	      p1_7 = 0x2f;
+	      p1_8 = 0x03;
+	   }
+        }
+     }
+  }
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) {
+     if(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p|TVSetYPbPr750p)) {
+        p1_7 = 0x63;
+	if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) p1_7 = 0x55;
+     }
+     if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) {
+        if(!(modeflag & HalfDCLK)) {
+	   p1_7 = 0xb2;
+	   if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) {
+	      p1_7 = 0xab;
+	   }
+	}
+     } else {
+        if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) {
+	   if(modeflag & HalfDCLK) p1_7 = 0x30;
+	}
+     }
+  }
+
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x07,p1_7);			/* 0x07 Horizontal Retrace Start */
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x08,p1_8);			/* 0x08 Horizontal Retrace End   */
+
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x03);                	/* 0x18 SR08 (FIFO Threshold?)   */
+
+  SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x19,0xF0);
+
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x09,0xFF);                	/* 0x09 Set Max VT    */
+
+  tempcx = 0x121;
+  tempbx = SiS_Pr->SiS_VGAVDE;                               	/* 0x0E Vertical Display End */
+  if     (tempbx == 357) tempbx = 350;
+  else if(tempbx == 360) tempbx = 350;
+  else if(tempbx == 375) tempbx = 350;
+  else if(tempbx == 405) tempbx = 400;
+  else if(tempbx == 420) tempbx = 400;
+  else if(tempbx == 525) tempbx = 480;
+  push2 = tempbx;
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+     if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+      	if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
+           if     (tempbx == 350) tempbx += 5;
+           else if(tempbx == 480) tempbx += 5;
+      	}
+     }
+  }
+  tempbx -= 2;
+  temp = tempbx & 0x00FF;
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x10,temp);        		/* 0x10 vertical Blank Start */
+
+  tempbx = push2;
+  tempbx--;
+  temp = tempbx & 0x00FF;
+#if 0
+  /* Missing code from 630/301B 2.04.5a and 650/302LV 1.10.6s (calles int 2f) */
+  if(xxx()) {
+      if(temp == 0xdf) temp = 0xda;
+  }
+#endif
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0E,temp);
+
+  temp = 0;
+  if(modeflag & DoubleScanMode) temp |= 0x80;
+  if(HwInfo->jChipType >= SIS_661) {
+     if(tempbx & 0x0200)        temp |= 0x20;
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x0B,0x5F,temp);
+     if(tempbx & 0x0100)  tempcx |= 0x000a;
+     if(tempbx & 0x0400)  tempcx |= 0x1200;
+  } else {
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0B,temp);
+     if(tempbx & 0x0100)  tempcx |= 0x0002;
+     if(tempbx & 0x0400)  tempcx |= 0x0600;
+  }
+
+  if(tempbx & 0x0200)  tempcx |= 0x0040;
+
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x11,0x00);                	/* 0x11 Vertical Blank End */
+
+  tempax = (SiS_Pr->SiS_VGAVT - tempbx) >> 2;
+
+  if((ModeNo > 0x13) || (HwInfo->jChipType < SIS_315H)) {
+     if(resinfo != SIS_RI_1280x1024) {
+	tempbx += (tempax << 1);
+     }
+  } else if(HwInfo->jChipType >= SIS_315H) {
+     if(SiS_Pr->SiS_LCDResInfo != Panel_1400x1050) {
+	tempbx += (tempax << 1);
+     }
+  }
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+     tempbx -= 10;
+  } else {
+     if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) {
+        if(SiS_Pr->SiS_TVMode & TVSetPAL) {
+           tempbx += 40;
+	   if(HwInfo->jChipType >= SIS_315H) {
+	      if(SiS_Pr->SiS_VGAHDE == 800) tempbx += 10;
+	   }
+	}
+     }
+  }
+  tempax >>= 2;
+  tempax++;
+  tempax += tempbx;
+  push1 = tempax;
+  if(SiS_Pr->SiS_TVMode & TVSetPAL) {
+     if(tempbx <= 513)  {
+     	if(tempax >= 513) tempbx = 513;
+     }
+  }
+  temp = tempbx & 0x00FF;
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0C,temp);			/* 0x0C Vertical Retrace Start */
+
+  tempbx--;
+  temp = tempbx & 0x00FF;
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x10,temp);
+
+  if(tempbx & 0x0100) tempcx |= 0x0008;
+
+  if(tempbx & 0x0200) {
+     SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x0B,0x20);
+  }
+  tempbx++;
+
+  if(tempbx & 0x0100) tempcx |= 0x0004;
+  if(tempbx & 0x0200) tempcx |= 0x0080;
+  if(tempbx & 0x0400) {
+     if(HwInfo->jChipType >= SIS_661)        tempcx |= 0x0800;
+     else if(SiS_Pr->SiS_VBType & VB_SIS301) tempcx |= 0x0800;
+     else                                    tempcx |= 0x0C00;
+  }
+
+  tempbx = push1;
+  temp = tempbx & 0x000F;
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0D,temp);        		/* 0x0D vertical Retrace End */
+
+  if(tempbx & 0x0010) tempcx |= 0x2000;
+
+  temp = tempcx & 0x00FF;
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0A,temp);              	/* 0x0A CR07 */
+
+  temp = (tempcx & 0xFF00) >> 8;
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x17,temp);              	/* 0x17 SR0A */
+
+  tempax = modeflag;
+  temp = (tempax & 0xFF00) >> 8;
+  temp = (temp >> 1) & 0x09;
+  if(!(SiS_Pr->SiS_VBType & VB_SIS301)) temp |= 0x01;		/* Always 8 dotclock */
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x16,temp);              	/* 0x16 SR01 */
+
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0F,0x00);              	/* 0x0F CR14 */
+
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x12,0x00);              	/* 0x12 CR17 */
+
+  temp = 0x00;
+  if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) {
+     if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x01) {
+	temp = 0x80;
+     }
+  }
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1A,temp);                	/* 0x1A SR0E */
+
+  temp = SiS_GetRegByte((SiS_Pr->SiS_P3ca+0x02));
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,temp);
+}
+
+/* Setup panel link
+ * This is used for LVDS, LCDA and Chrontel TV output
+ * 300/LVDS+TV, 300/301B-DH, 315/LVDS+TV, 315/LCDA
+ */
+static void
+SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+                   PSIS_HW_INFO HwInfo, USHORT RefreshRateTableIndex)
+{
+  USHORT modeflag,resinfo;
+  USHORT push2,tempax,tempbx,tempcx,temp;
+  ULONG tempeax=0,tempebx,tempecx,tempvcfact=0;
+  BOOLEAN islvds = FALSE, issis  = FALSE, chkdclkfirst = FALSE;
+#ifdef SIS300
+  USHORT crt2crtc;
+#endif
+#ifdef SIS315H
+  USHORT pushcx;
+#endif
+
+  if(ModeNo <= 0x13) {
+     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+     resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+#ifdef SIS300
+     crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+#endif
+  } else if(SiS_Pr->UseCustomMode) {
+     modeflag = SiS_Pr->CModeFlag;
+     resinfo = 0;
+#ifdef SIS300
+     crt2crtc = 0;
+#endif
+  } else {
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+     resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+#ifdef SIS300
+     crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+#endif
+  }
+
+  /* is lvds if really LVDS, or 301B-DH with external LVDS transmitter */
+  if((SiS_Pr->SiS_IF_DEF_LVDS == 1) || (SiS_Pr->SiS_VBType & VB_NoLCD)) {
+     islvds = TRUE;
+  }
+
+  /* is really sis if sis bridge, but not 301B-DH */
+  if((SiS_Pr->SiS_VBType & VB_SISVB) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) {
+     issis = TRUE;
+  }
+
+  if((HwInfo->jChipType >= SIS_315H) && (islvds) && (!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA))) {
+     if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) {
+        chkdclkfirst = TRUE;
+     }
+  }
+
+#ifdef SIS315H
+  if((HwInfo->jChipType >= SIS_315H) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+     if(IS_SIS330) {
+        SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x10);
+     } else if(IS_SIS740) {
+        if(islvds) {
+           SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xfb,0x04);
+	   SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x03);
+        } else if(SiS_Pr->SiS_VBType & VB_SISVB) {
+           SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x10);
+        }
+     } else {
+        if(islvds) {
+           SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xfb,0x04);
+	   SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x00);
+        } else if(SiS_Pr->SiS_VBType & VB_SISVB) {
+           SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2D,0x0f);
+	   if(SiS_Pr->SiS_VBType & VB_SIS301C) {
+	      if((SiS_Pr->SiS_LCDResInfo == Panel_1024x768) ||
+	         (SiS_Pr->SiS_LCDResInfo == Panel_1280x1024)) {
+	         SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x20);
+	      }
+	   }
+        }
+     }
+  }
+#endif
+
+  /* Horizontal */
+
+  tempax = SiS_Pr->SiS_LCDHDES;
+  if(islvds) {
+     if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+        if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) {
+           if((SiS_Pr->SiS_LCDResInfo == Panel_640x480) &&
+              (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode))) {
+  	      tempax -= 8;
+	   }
+	}
+     }
+  }
+
+  temp = (tempax & 0x0007);
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1A,temp);			/* BPLHDESKEW[2:0]   */
+  temp = (tempax >> 3) & 0x00FF;
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x16,temp);			/* BPLHDESKEW[10:3]  */
+
+  tempbx = SiS_Pr->SiS_HDE;
+  if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+     if((SiS_Pr->SiS_LCDResInfo == Panel_640x480_2) ||
+        (SiS_Pr->SiS_LCDResInfo == Panel_640x480_3)) {
+        tempbx >>= 1;
+     }
+     if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
+        tempbx = SiS_Pr->PanelXRes;
+     }
+  }
+
+  tempax += tempbx;
+  if(tempax >= SiS_Pr->SiS_HT) tempax -= SiS_Pr->SiS_HT;
+
+  temp = tempax;
+  if(temp & 0x07) temp += 8;
+  temp >>= 3;
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x17,temp);			/* BPLHDEE  */
+
+  tempcx = (SiS_Pr->SiS_HT - tempbx) >> 2;
+
+  if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+     if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
+        if(SiS_Pr->PanelHRS != 999) tempcx = SiS_Pr->PanelHRS;
+     }
+  }
+
+  tempcx += tempax;
+  if(tempcx >= SiS_Pr->SiS_HT) tempcx -= SiS_Pr->SiS_HT;
+
+  temp = (tempcx >> 3) & 0x00FF;
+  if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+     if(SiS_Pr->SiS_IF_DEF_TRUMPION) {
+        if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+           switch(ModeNo) {
+           case 0x04:
+           case 0x05:
+           case 0x0d: temp = 0x56; break;
+           case 0x10: temp = 0x60; break;
+           case 0x13: temp = 0x5f; break;
+           case 0x40:
+           case 0x41:
+           case 0x4f:
+           case 0x43:
+           case 0x44:
+           case 0x62:
+           case 0x56:
+           case 0x53:
+           case 0x5d:
+           case 0x5e: temp = 0x54; break;
+           }
+        }
+     }
+  }
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x14,temp);			/* BPLHRS */
+
+  if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+     temp += 2;
+     if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
+        temp += 8;
+        if(SiS_Pr->PanelHRE != 999) {
+           temp = tempcx + SiS_Pr->PanelHRE;
+	   if(temp >= SiS_Pr->SiS_HT) temp -= SiS_Pr->SiS_HT;
+	   temp >>= 3;
+        }
+     }
+  } else {
+     temp += 10;
+  }
+
+  temp &= 0x1F;
+  temp |= ((tempcx & 0x07) << 5);
+#if 0
+  if(SiS_Pr->SiS_IF_DEF_FSTN) temp = 0x20;       		/* WRONG? BIOS loads cl, not ah */
+#endif
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x15,temp);			/* BPLHRE */
+
+  /* Vertical */
+
+  tempax = SiS_Pr->SiS_VGAVDE;
+  if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+     if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
+	tempax = SiS_Pr->PanelYRes;
+     }
+  }
+
+  tempbx = SiS_Pr->SiS_LCDVDES + tempax;
+  if(tempbx >= SiS_Pr->SiS_VT) tempbx -= SiS_Pr->SiS_VT;
+
+  push2 = tempbx;
+
+  tempcx = SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE;
+  if(HwInfo->jChipType < SIS_315H) {
+     if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+        if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
+	   tempcx = SiS_Pr->SiS_VGAVT - SiS_Pr->PanelYRes;
+	}
+     }
+  }
+  if(islvds) tempcx >>= 1;
+  else       tempcx >>= 2;
+
+  if( (SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) &&
+      (!(SiS_Pr->SiS_LCDInfo & LCDPass11)) 		    &&
+      (SiS_Pr->PanelVRS != 999) ) {
+     tempcx = SiS_Pr->PanelVRS;
+     tempbx += tempcx;
+     if(issis) tempbx++;
+  } else {
+     tempbx += tempcx;
+     if(HwInfo->jChipType < SIS_315H) tempbx++;
+     else if(issis)                   tempbx++;
+  }
+
+  if(tempbx >= SiS_Pr->SiS_VT) tempbx -= SiS_Pr->SiS_VT;	/* BPLVRS  */
+
+  temp = tempbx & 0x00FF;
+  if(SiS_Pr->SiS_IF_DEF_TRUMPION) {
+     if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+        if(ModeNo == 0x10) temp = 0xa9;
+     }
+  }
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,temp);
+
+  tempcx >>= 3;
+  tempcx++;
+
+  if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+     if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
+        if(SiS_Pr->PanelVRE != 999) tempcx = SiS_Pr->PanelVRE;
+     }
+  }
+
+  tempcx += tempbx;
+  temp = tempcx & 0x000F;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0xF0,temp);	/* BPLVRE  */
+
+  temp = ((tempbx >> 8) & 0x07) << 3;
+  if(SiS_Pr->SiS_IF_DEF_FSTN || SiS_Pr->SiS_IF_DEF_DSTN) {
+     if(SiS_Pr->SiS_HDE != 640) {
+        if(SiS_Pr->SiS_VGAVDE != SiS_Pr->SiS_VDE)  temp |= 0x40;
+     }
+  } else if(SiS_Pr->SiS_VGAVDE != SiS_Pr->SiS_VDE) temp |= 0x40;
+  if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA)          temp |= 0x40;
+  tempbx = 0x87;
+  if((HwInfo->jChipType >= SIS_315H) ||
+     (HwInfo->jChipRevision >= 0x30)) {
+     tempbx = 0x07;
+     if((SiS_Pr->SiS_IF_DEF_CH70xx == 1) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) {
+	if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x03)    temp |= 0x80;
+     }
+     /* Chrontel 701x operates in 24bit mode (8-8-8, 2x12bit mutliplexed) via VGA2 */
+     if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) {
+	if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+	   if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x06) & 0x10)      temp |= 0x80;
+	} else {
+	   if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x01) temp |= 0x80;
+	}
+     }
+  }
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1A,tempbx,temp);
+
+  tempbx = push2;                                      		/* BPLVDEE */
+
+  tempcx = SiS_Pr->SiS_LCDVDES;                        		/* BPLVDES */
+
+  if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+     switch(SiS_Pr->SiS_LCDResInfo) {
+     case Panel_640x480:
+        tempbx = SiS_Pr->SiS_VGAVDE - 1;
+        tempcx = SiS_Pr->SiS_VGAVDE;
+	break;
+     case Panel_800x600:
+        if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+           if(resinfo == SIS_RI_800x600) tempcx++;
+        }
+	break;
+     case Panel_1024x600:
+        if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+           if(resinfo == SIS_RI_1024x600) tempcx++;
+           if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+	      if(resinfo == SIS_RI_800x600) tempcx++;
+	   }
+        }
+	break;
+     case Panel_1024x768:
+        if(HwInfo->jChipType < SIS_315H) {
+           if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+              if(resinfo == SIS_RI_1024x768) tempcx++;
+	   }
+        }
+	break;
+     }
+  }
+
+  temp = ((tempbx >> 8) & 0x07) << 3;
+  temp = temp | ((tempcx >> 8) & 0x07);
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1D,temp);
+  /* if(SiS_Pr->SiS_IF_DEF_FSTN) tempbx++;  */
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1C,tempbx);
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1B,tempcx);
+
+  /* Vertical scaling */
+
+  if(HwInfo->jChipType < SIS_315H) {
+
+#ifdef SIS300      /* 300 series */
+     tempeax = SiS_Pr->SiS_VGAVDE << 6;
+     temp = (tempeax % (ULONG)SiS_Pr->SiS_VDE);
+     tempeax = tempeax / (ULONG)SiS_Pr->SiS_VDE;
+     if(temp) tempeax++;
+
+     if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) tempeax = 0x3F;
+
+     temp = (USHORT)(tempeax & 0x00FF);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1E,temp);      	/* BPLVCFACT */
+     tempvcfact = temp;
+#endif /* SIS300 */
+
+  } else {
+
+#ifdef SIS315H  /* 315 series */
+     tempeax = SiS_Pr->SiS_VGAVDE << 18;
+     tempebx = SiS_Pr->SiS_VDE;
+     temp = (tempeax % tempebx);
+     tempeax = tempeax / tempebx;
+     if(temp) tempeax++;
+     tempvcfact = tempeax;
+
+     temp = (USHORT)(tempeax & 0x00FF);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x37,temp);
+     temp = (USHORT)((tempeax & 0x00FF00) >> 8);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x36,temp);
+     temp = (USHORT)((tempeax & 0x00030000) >> 16);
+     if(SiS_Pr->SiS_VDE == SiS_Pr->SiS_VGAVDE) temp |= 0x04;
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x35,temp);
+
+     if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV)) {
+        temp = (USHORT)(tempeax & 0x00FF);
+        SiS_SetReg(SiS_Pr->SiS_Part4Port,0x3c,temp);
+        temp = (USHORT)((tempeax & 0x00FF00) >> 8);
+        SiS_SetReg(SiS_Pr->SiS_Part4Port,0x3b,temp);
+        temp = (USHORT)(((tempeax & 0x00030000) >> 16) << 6);
+        SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x3a,0x3f,temp);
+        temp = 0;
+        if(SiS_Pr->SiS_VDE != SiS_Pr->SiS_VGAVDE) temp |= 0x08;
+        SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x30,0xf3,temp);
+     }
+#endif
+
+  }
+
+  /* Horizontal scaling */
+
+  tempeax = SiS_Pr->SiS_VGAHDE;		/* 1f = ( (VGAHDE * 65536) / ( (VGAHDE * 65536) / HDE ) ) - 1*/
+  if(chkdclkfirst) {
+     if(modeflag & HalfDCLK) tempeax >>= 1;
+  }
+  tempebx = tempeax << 16;
+  if(SiS_Pr->SiS_HDE == tempeax) {
+     tempecx = 0xFFFF;
+  } else {
+     tempecx = tempebx / SiS_Pr->SiS_HDE;
+     if(HwInfo->jChipType >= SIS_315H) {
+        if(tempebx % SiS_Pr->SiS_HDE) tempecx++;
+     }
+  }
+
+  if(HwInfo->jChipType >= SIS_315H) {
+     tempeax = (tempebx / tempecx) - 1;
+  } else {
+     tempeax = ((SiS_Pr->SiS_VGAHT << 16) / tempecx) - 1;
+  }
+  tempecx = (tempecx << 16) | (tempeax & 0xFFFF);
+  temp = (USHORT)(tempecx & 0x00FF);
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1F,temp);
+
+  if(HwInfo->jChipType >= SIS_315H) {
+     tempeax = (SiS_Pr->SiS_VGAVDE << 18) / tempvcfact;
+     tempbx = (USHORT)(tempeax & 0xFFFF);
+  } else {
+     tempeax = SiS_Pr->SiS_VGAVDE << 6;
+     tempbx = tempvcfact & 0x3f;
+     if(tempbx == 0) tempbx = 64;
+     tempeax /= tempbx;
+     tempbx = (USHORT)(tempeax & 0xFFFF);
+  }
+  if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) tempbx--;
+  if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) {
+     if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) tempbx = 1;
+     else if(SiS_Pr->SiS_LCDResInfo != Panel_640x480)             tempbx = 1;
+  }
+
+  temp = ((tempbx >> 8) & 0x07) << 3;
+  temp = temp | ((tempecx >> 8) & 0x07);
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x20,temp);
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x21,tempbx);
+
+  tempecx >>= 16;   	                                  	/* BPLHCFACT  */
+  if(!chkdclkfirst) {
+     if(modeflag & HalfDCLK) tempecx >>= 1;
+  }
+  temp = (USHORT)((tempecx & 0xFF00) >> 8);
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x22,temp);
+  temp = (USHORT)(tempecx & 0x00FF);
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x23,temp);
+
+#ifdef SIS315H
+  if(HwInfo->jChipType >= SIS_315H) {
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+        if((islvds) || (SiS_Pr->SiS_VBInfo & VB_SIS301LV302LV)) {
+           SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1e,0x20);
+	}
+     } else {
+        if(islvds) {
+           if(HwInfo->jChipType == SIS_740) {
+              SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x03);
+           } else {
+	      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1e,0x23);
+           }
+        }
+     }
+  }
+#endif
+
+#ifdef SIS300
+  if(SiS_Pr->SiS_IF_DEF_TRUMPION) {
+     int i;
+     UCHAR TrumpMode13[4]   = { 0x01, 0x10, 0x2c, 0x00 };
+     UCHAR TrumpMode10_1[4] = { 0x01, 0x10, 0x27, 0x00 };
+     UCHAR TrumpMode10_2[4] = { 0x01, 0x16, 0x10, 0x00 };
+
+     SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0xbf);
+     for(i=0; i<5; i++) {
+        SiS_SetTrumpionBlock(SiS_Pr, &SiS300_TrumpionData[crt2crtc][0]);
+     }
+     if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+        if(ModeNo == 0x13) {
+	   for(i=0; i<4; i++) {
+	      SiS_SetTrumpionBlock(SiS_Pr, &TrumpMode13[0]);
+	   }
+	} else if(ModeNo == 0x10) {
+	   for(i=0; i<4; i++) {
+	      SiS_SetTrumpionBlock(SiS_Pr, &TrumpMode10_1[0]);
+	      SiS_SetTrumpionBlock(SiS_Pr, &TrumpMode10_2[0]);
+	   }
+	}
+     }
+     SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x02,0x40);
+  }
+#endif
+
+#ifdef SIS315H
+  if(SiS_Pr->SiS_IF_DEF_FSTN || SiS_Pr->SiS_IF_DEF_DSTN) {
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x25,0x00);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x26,0x00);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x27,0x00);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x28,0x87);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x29,0x5A);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2A,0x4B);
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x44,~0x07,0x03);
+     tempax = SiS_Pr->SiS_HDE;                       		/* Blps = lcdhdee(lcdhdes+HDE) + 64 */
+     if(SiS_Pr->SiS_LCDResInfo == Panel_640x480_2 ||
+        SiS_Pr->SiS_LCDResInfo == Panel_640x480_3) tempax >>= 1;
+     tempax += 64;
+     temp = tempax & 0x00FF;
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x38,temp);
+     temp = ((tempax & 0xFF00) >> 8) << 3;
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x35,~0x078,temp);
+     tempax += 32;		                     		/* Blpe=lBlps+32 */
+     temp = tempax & 0x00FF;
+     if(SiS_Pr->SiS_IF_DEF_FSTN) temp = 0;
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x39,temp);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3A,0x00);        	/* Bflml=0 */
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x007,0x00);
+
+     tempax = SiS_Pr->SiS_VDE;
+     if(SiS_Pr->SiS_LCDResInfo == Panel_640x480_2 ||
+        SiS_Pr->SiS_LCDResInfo == Panel_640x480_3) tempax >>= 1;
+     tempax >>= 1;
+     temp = tempax & 0x00FF;
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3B,temp);
+     temp = ((tempax & 0xFF00) >> 8) << 3;
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x038,temp);
+
+     tempeax = SiS_Pr->SiS_HDE;
+     if(SiS_Pr->SiS_LCDResInfo == Panel_640x480_2 ||
+        SiS_Pr->SiS_LCDResInfo == Panel_640x480_3) tempeax >>= 1;
+     tempeax <<= 2;                       			/* BDxFIFOSTOP = (HDE*4)/128 */
+     tempebx = 128;
+     temp = (USHORT)(tempeax % tempebx);
+     tempeax = tempeax / tempebx;
+     if(temp) tempeax++;
+     temp = (USHORT)(tempeax & 0x003F);
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x45,~0x0FF,temp);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3F,0x00);         	/* BDxWadrst0 */
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3E,0x00);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3D,0x10);
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x040,0x00);
+
+     tempax = SiS_Pr->SiS_HDE;
+     if(SiS_Pr->SiS_LCDResInfo == Panel_640x480_2 ||
+        SiS_Pr->SiS_LCDResInfo == Panel_640x480_3) tempax >>= 1;
+     tempax >>= 4;                        			/* BDxWadroff = HDE*4/8/8 */
+     pushcx = tempax;
+     temp = tempax & 0x00FF;
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x43,temp);
+     temp = ((tempax & 0xFF00) >> 8) << 3;
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x44,~0x0F8,temp);
+
+     tempax = SiS_Pr->SiS_VDE;                             	/* BDxWadrst1 = BDxWadrst0 + BDxWadroff * VDE */
+     if(SiS_Pr->SiS_LCDResInfo == Panel_640x480_2 ||
+        SiS_Pr->SiS_LCDResInfo == Panel_640x480_3) tempax >>= 1;
+     tempeax = (tempax * pushcx);
+     tempebx = 0x00100000 + tempeax;
+     temp = (USHORT)tempebx & 0x000000FF;
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x42,temp);
+     temp = (USHORT)((tempebx & 0x0000FF00) >> 8);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x41,temp);
+     temp = (USHORT)((tempebx & 0x00FF0000) >> 16);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x40,temp);
+     temp = (USHORT)(((tempebx & 0x01000000) >> 24) << 7);
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x080,temp);
+
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2F,0x03);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x03,0x50);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x04,0x00);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2F,0x01);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x19,0x38);
+
+     if(SiS_Pr->SiS_IF_DEF_FSTN) {
+        SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2b,0x02);
+        SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2c,0x00);
+        SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2d,0x00);
+        SiS_SetReg(SiS_Pr->SiS_Part1Port,0x35,0x0c);
+        SiS_SetReg(SiS_Pr->SiS_Part1Port,0x36,0x00);
+        SiS_SetReg(SiS_Pr->SiS_Part1Port,0x37,0x00);
+        SiS_SetReg(SiS_Pr->SiS_Part1Port,0x38,0x80);
+        SiS_SetReg(SiS_Pr->SiS_Part1Port,0x39,0xA0);
+        SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3a,0x00);
+        SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3b,0xf0);
+        SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3c,0x00);
+        SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3d,0x10);
+        SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3e,0x00);
+        SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3f,0x00);
+        SiS_SetReg(SiS_Pr->SiS_Part1Port,0x40,0x10);
+        SiS_SetReg(SiS_Pr->SiS_Part1Port,0x41,0x25);
+        SiS_SetReg(SiS_Pr->SiS_Part1Port,0x42,0x80);
+        SiS_SetReg(SiS_Pr->SiS_Part1Port,0x43,0x14);
+        SiS_SetReg(SiS_Pr->SiS_Part1Port,0x44,0x03);
+        SiS_SetReg(SiS_Pr->SiS_Part1Port,0x45,0x0a);
+     }
+  }
+#endif  /* SIS315H */
+}
+
+/* Set Part 1 */
+static void
+SiS_SetGroup1(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+              PSIS_HW_INFO HwInfo, USHORT RefreshRateTableIndex)
+{
+#if defined(SIS300) || defined(SIS315H)
+  UCHAR   *ROMAddr = HwInfo->pjVirtualRomBase;
+#endif
+  USHORT  temp=0, tempax=0, tempbx=0, tempcx=0, bridgeadd=0;
+  USHORT  pushbx=0, CRT1Index=0, modeflag, resinfo=0;
+#ifdef SIS315H
+  USHORT  tempbl=0;
+#endif
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+     SiS_SetGroup1_LVDS(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex);
+     return;
+  }
+
+  if(ModeNo <= 0x13) {
+     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  } else if(SiS_Pr->UseCustomMode) {
+     modeflag = SiS_Pr->CModeFlag;
+  } else {
+     CRT1Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+     resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+  }
+
+  SiS_SetCRT2Offset(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
+
+  if( ! ((HwInfo->jChipType >= SIS_315H) &&
+         (SiS_Pr->SiS_IF_DEF_LVDS == 1) &&
+         (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ) {
+
+     if(HwInfo->jChipType < SIS_315H ) {
+#ifdef SIS300
+  	SiS_SetCRT2FIFO_300(SiS_Pr, ModeNo, HwInfo);
+#endif
+     } else {
+#ifdef SIS315H
+        SiS_SetCRT2FIFO_310(SiS_Pr, HwInfo);
+#endif
+     }
+
+     /* 1. Horizontal setup */
+
+     if(HwInfo->jChipType < SIS_315H ) {
+
+#ifdef SIS300   /* ------------- 300 series --------------*/
+
+    	temp = (SiS_Pr->SiS_VGAHT - 1) & 0x0FF;   		  /* BTVGA2HT 0x08,0x09 */
+    	SiS_SetReg(SiS_Pr->SiS_Part1Port,0x08,temp);              /* CRT2 Horizontal Total */
+
+    	temp = (((SiS_Pr->SiS_VGAHT - 1) & 0xFF00) >> 8) << 4;
+    	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0f,temp);    /* CRT2 Horizontal Total Overflow [7:4] */
+
+    	temp = (SiS_Pr->SiS_VGAHDE + 12) & 0x0FF;                 /* BTVGA2HDEE 0x0A,0x0C */
+    	SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0A,temp);              /* CRT2 Horizontal Display Enable End */
+
+	pushbx = SiS_Pr->SiS_VGAHDE + 12;                         /* bx  BTVGA2HRS 0x0B,0x0C */
+    	tempcx = (SiS_Pr->SiS_VGAHT - SiS_Pr->SiS_VGAHDE) >> 2;
+    	tempbx = pushbx + tempcx;
+    	tempcx <<= 1;
+    	tempcx += tempbx;
+
+	bridgeadd = 12;
+
+#endif /* SIS300 */
+
+     } else {
+
+#ifdef SIS315H  /* ------------------- 315/330 series --------------- */
+
+	tempcx = SiS_Pr->SiS_VGAHT;				  /* BTVGA2HT 0x08,0x09 */
+	if(modeflag & HalfDCLK) {
+	   if(SiS_Pr->SiS_VBType & VB_SISVB) {
+	      tempcx >>= 1;
+	   } else {
+	      tempax = SiS_Pr->SiS_VGAHDE >> 1;
+	      tempcx = SiS_Pr->SiS_HT - SiS_Pr->SiS_HDE + tempax;
+	      if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+	         tempcx = SiS_Pr->SiS_HT - tempax;
+	      }
+	   }
+	}
+	tempcx--;
+	SiS_SetReg(SiS_Pr->SiS_Part1Port,0x08,tempcx);            /* CRT2 Horizontal Total */
+	temp = (tempcx >> 4) & 0xF0;
+	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0F,temp);    /* CRT2 Horizontal Total Overflow [7:4] */
+
+	tempcx = SiS_Pr->SiS_VGAHT;				  /* BTVGA2HDEE 0x0A,0x0C */
+	tempbx = SiS_Pr->SiS_VGAHDE;
+	tempcx -= tempbx;
+	tempcx >>= 2;
+	if(modeflag & HalfDCLK) {
+	   tempbx >>= 1;
+	   tempcx >>= 1;
+	}
+	tempbx += 16;
+
+	SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0A,tempbx);            /* CRT2 Horizontal Display Enable End */
+
+	pushbx = tempbx;
+	tempcx >>= 1;
+	tempbx += tempcx;
+	tempcx += tempbx;
+
+	bridgeadd = 16;
+
+	if(SiS_Pr->SiS_VBType & VB_SISVB) {
+	   if(HwInfo->jChipType >= SIS_661) {
+	      if((SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) ||
+		 (SiS_Pr->SiS_LCDResInfo == Panel_1280x1024)) {
+		 if(resinfo == SIS_RI_1280x1024) {
+		    tempcx = (tempcx & 0xff00) | 0x30;
+		 } else if(resinfo == SIS_RI_1600x1200) {
+		    tempcx = (tempcx & 0xff00) | 0xff;
+		 }
+	      }
+	   }
+        }
+
+#endif  /* SIS315H */
+
+     }  /* 315/330 series */
+
+     if(SiS_Pr->SiS_VBType & VB_SISVB) {
+
+        if(SiS_Pr->UseCustomMode) {
+	   tempbx = SiS_Pr->CHSyncStart + bridgeadd;
+	   tempcx = SiS_Pr->CHSyncEnd + bridgeadd;
+	   tempax = SiS_Pr->SiS_VGAHT;
+	   if(modeflag & HalfDCLK) tempax >>= 1;
+	   tempax--;
+	   if(tempcx > tempax) tempcx = tempax;
+	}
+
+	if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) {
+	   unsigned char cr4, cr14, cr5, cr15;
+	   if(SiS_Pr->UseCustomMode) {
+	      cr4  = SiS_Pr->CCRT1CRTC[4];
+	      cr14 = SiS_Pr->CCRT1CRTC[14];
+	      cr5  = SiS_Pr->CCRT1CRTC[5];
+	      cr15 = SiS_Pr->CCRT1CRTC[15];
+	   } else {
+	      cr4  = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[4];
+	      cr14 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14];
+	      cr5  = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[5];
+	      cr15 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[15];
+	   }
+           tempbx = ((cr4 | ((cr14 & 0xC0) << 2)) - 3) << 3; 		    /* (VGAHRS-3)*8 */
+           tempcx = (((cr5 & 0x1f) | ((cr15 & 0x04) << (5-2))) - 3) << 3;   /* (VGAHRE-3)*8 */
+	   tempcx &= 0x00FF;
+	   tempcx |= (tempbx & 0xFF00);
+           tempbx += bridgeadd;
+           tempcx += bridgeadd;
+	   tempax = SiS_Pr->SiS_VGAHT;
+	   if(modeflag & HalfDCLK) tempax >>= 1;
+	   tempax--;
+	   if(tempcx > tempax) tempcx = tempax;
+        }
+
+        if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) {
+      	   tempbx = 1040;
+      	   tempcx = 1044;   /* HWCursor bug! */
+        }
+
+     }
+
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0B,tempbx);            	  /* CRT2 Horizontal Retrace Start */
+
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0D,tempcx);               /* CRT2 Horizontal Retrace End */
+
+     temp = ((tempbx >> 8) & 0x0F) | ((pushbx >> 4) & 0xF0);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0C,temp);		  /* Overflow */
+
+     /* 2. Vertical setup */
+
+     tempcx = SiS_Pr->SiS_VGAVT - 1;
+     temp = tempcx & 0x00FF;
+
+     if(HwInfo->jChipType < SIS_661) {
+        if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+	   if(HwInfo->jChipType < SIS_315H) {
+	      if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+	         if(SiS_Pr->SiS_VBInfo & (SetCRT2ToSVIDEO | SetCRT2ToAVIDEO)) {
+	            temp--;
+	         }
+              }
+	   } else {
+ 	      temp--;
+           }
+        } else if(HwInfo->jChipType >= SIS_315H) {
+	   temp--;
+	}
+     }
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0E,temp);                 /* CRT2 Vertical Total */
+
+     tempbx = SiS_Pr->SiS_VGAVDE - 1;
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0F,tempbx);               /* CRT2 Vertical Display Enable End */
+
+     temp = ((tempbx >> 5) & 0x38) | ((tempcx >> 8) & 0x07);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x12,temp);                 /* Overflow */
+
+     if((HwInfo->jChipType >= SIS_315H) && (HwInfo->jChipType < SIS_661)) {
+        tempbx++;
+   	tempax = tempbx;
+	tempcx++;
+	tempcx -= tempax;
+	tempcx >>= 2;
+	tempbx += tempcx;
+	if(tempcx < 4) tempcx = 4;
+	tempcx >>= 2;
+	tempcx += tempbx;
+	tempcx++;
+     } else {
+  	tempbx = (SiS_Pr->SiS_VGAVT + SiS_Pr->SiS_VGAVDE) >> 1;                 /*  BTVGA2VRS     0x10,0x11   */
+  	tempcx = ((SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE) >> 4) + tempbx + 1;  /*  BTVGA2VRE     0x11        */
+     }
+
+     if(SiS_Pr->SiS_VBType & VB_SISVB) {
+	if(SiS_Pr->UseCustomMode) {
+	   tempbx = SiS_Pr->CVSyncStart;
+	   tempcx = SiS_Pr->CVSyncEnd;
+	}
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) {
+	   unsigned char cr8, cr7, cr13;
+	   if(SiS_Pr->UseCustomMode) {
+	      cr8    = SiS_Pr->CCRT1CRTC[8];
+	      cr7    = SiS_Pr->CCRT1CRTC[7];
+	      cr13   = SiS_Pr->CCRT1CRTC[13];
+	      tempcx = SiS_Pr->CCRT1CRTC[9];
+	   } else {
+	      cr8    = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[8];
+	      cr7    = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[7];
+	      cr13   = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[13];
+	      tempcx = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[9];
+	   }
+      	   tempbx = cr8;
+      	   if(cr7  & 0x04) tempbx |= 0x0100;
+      	   if(cr7  & 0x80) tempbx |= 0x0200;
+      	   if(cr13 & 0x08) tempbx |= 0x0400;
+       	}
+     }
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x10,tempbx);               /* CRT2 Vertical Retrace Start */
+
+     temp = ((tempbx >> 4) & 0x70) | (tempcx & 0x0F);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x11,temp);                 /* CRT2 Vert. Retrace End; Overflow */
+
+     /* 3. Panel delay compensation */
+
+     if(HwInfo->jChipType < SIS_315H) {
+
+#ifdef SIS300  /* ---------- 300 series -------------- */
+
+	if(SiS_Pr->SiS_VBType & VB_SISVB) {
+	   temp = 0x20;
+	   if(HwInfo->jChipType == SIS_300) {
+	      temp = 0x10;
+	      if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768)  temp = 0x2c;
+	      if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) temp = 0x20;
+	   }
+	   if(SiS_Pr->SiS_VBType & VB_SIS301) {
+	      if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) temp = 0x20;
+	   }
+	   if(SiS_Pr->SiS_LCDResInfo == Panel_1280x960)     temp = 0x24;
+	   if(SiS_Pr->SiS_LCDResInfo == Panel_Custom)       temp = 0x2c;
+	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) 	    temp = 0x08;
+	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+      	      if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) 	    temp = 0x2c;
+      	      else 					    temp = 0x20;
+    	   }
+	   if(SiS_Pr->SiS_UseROM) {
+	      if(ROMAddr[0x220] & 0x80) {
+	         if(SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoYPbPrHiVision)
+	   	    temp = ROMAddr[0x221];
+		 else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision)
+		    temp = ROMAddr[0x222];
+		 else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024)
+		    temp = ROMAddr[0x223];
+		 else
+		    temp = ROMAddr[0x224];
+		 temp &= 0x3c;
+	      }
+	   }
+	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+	      if(SiS_Pr->PDC != -1)  temp = SiS_Pr->PDC & 0x3c;
+	   }
+
+	} else {
+	   temp = 0x20;
+	   if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) {
+	      if(SiS_Pr->SiS_LCDResInfo == Panel_640x480) temp = 0x04;
+	   }
+	   if(SiS_Pr->SiS_UseROM) {
+	      if(ROMAddr[0x220] & 0x80) {
+	         temp = ROMAddr[0x220] & 0x3c;
+	      }
+	   }
+	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+	      if(SiS_Pr->PDC != -1) temp = SiS_Pr->PDC & 0x3c;
+	   }
+        }
+
+    	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x3C,temp);   /* Panel Link Delay Compensation; (Software Command Reset; Power Saving) */
+
+#endif  /* SIS300 */
+
+     } else {
+
+#ifdef SIS315H   /* --------------- 315/330 series ---------------*/
+
+        if(HwInfo->jChipType < SIS_661) {
+
+	   if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+
+	      if(HwInfo->jChipType == SIS_740) temp = 0x03;
+	      else 		               temp = 0x00;
+
+	      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) temp = 0x0a;
+	      tempbl = 0xF0;
+	      if(HwInfo->jChipType == SIS_650) {
+		 if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+		    if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) tempbl = 0x0F;
+		 }
+	      }
+
+	      if(SiS_Pr->SiS_IF_DEF_DSTN || SiS_Pr->SiS_IF_DEF_FSTN) {
+		 temp = 0x08;
+		 tempbl = 0;
+		 if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) {
+		    if(ROMAddr[0x13c] & 0x80) tempbl = 0xf0;
+		 }
+	      }
+
+	      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,tempbl,temp);	    /* Panel Link Delay Compensation */
+	   }
+
+	} /* < 661 */
+
+    	tempax = 0;
+    	if(modeflag & DoubleScanMode) tempax |= 0x80;
+    	if(modeflag & HalfDCLK)       tempax |= 0x40;
+    	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2C,0x3f,tempax);
+
+#endif  /* SIS315H */
+
+     }
+
+  }  /* Slavemode */
+
+  if(SiS_Pr->SiS_VBType & VB_SISVB) {
+     if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
+        /* For 301BDH with LCD, we set up the Panel Link */
+	SiS_SetGroup1_LVDS(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex);
+     } else if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+    	SiS_SetGroup1_301(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex);
+     }
+  } else {
+     if(HwInfo->jChipType < SIS_315H) {
+	SiS_SetGroup1_LVDS(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex);
+     } else {
+	if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+           if((!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) || (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+    	      SiS_SetGroup1_LVDS(SiS_Pr, ModeNo,ModeIdIndex, HwInfo,RefreshRateTableIndex);
+           }
+	} else {
+	   SiS_SetGroup1_LVDS(SiS_Pr, ModeNo,ModeIdIndex, HwInfo,RefreshRateTableIndex);
+	}
+     }
+  }
+}
+
+/*********************************************/
+/*         SET PART 2 REGISTER GROUP         */
+/*********************************************/
+
+#ifdef SIS315H
+static UCHAR *
+SiS_GetGroup2CLVXPtr(SiS_Private *SiS_Pr, int tabletype, PSIS_HW_INFO HwInfo)
+{
+   const UCHAR  *tableptr = NULL;
+   USHORT       a, b, p = 0;
+
+   a = SiS_Pr->SiS_VGAHDE;
+   b = SiS_Pr->SiS_HDE;
+   if(tabletype) {
+      a = SiS_Pr->SiS_VGAVDE;
+      b = SiS_Pr->SiS_VDE;
+   }
+
+   if(a < b) {
+      tableptr = SiS_Part2CLVX_1;
+   } else if(a == b) {
+      tableptr = SiS_Part2CLVX_2;
+   } else {
+      if(SiS_Pr->SiS_TVMode & TVSetPAL) {
+	 tableptr = SiS_Part2CLVX_4;
+      } else {
+	 tableptr = SiS_Part2CLVX_3;
+      }
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) {
+	 if(SiS_Pr->SiS_TVMode & TVSetYPbPr525i) 	tableptr = SiS_Part2CLVX_3;
+	 else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) 	tableptr = SiS_Part2CLVX_3;
+	 else 				         	tableptr = SiS_Part2CLVX_5;
+      } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+	 tableptr = SiS_Part2CLVX_6;
+      }
+      do {
+	 if((tableptr[p] | tableptr[p+1] << 8) == a) break;
+	 p += 0x42;
+      } while((tableptr[p] | tableptr[p+1] << 8) != 0xffff);
+      if((tableptr[p] | tableptr[p+1] << 8) == 0xffff) p -= 0x42;
+   }
+   p += 2;
+   return((UCHAR *)&tableptr[p]);
+}
+
+static void
+SiS_SetGroup2_C_ELV(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+	      	    USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo)
+{
+   UCHAR *tableptr;
+   int i, j;
+   UCHAR temp;
+
+   if(!(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV))) return;
+
+   tableptr = SiS_GetGroup2CLVXPtr(SiS_Pr, 0, HwInfo);
+   for(i = 0x80, j = 0; i <= 0xbf; i++, j++) {
+      SiS_SetReg(SiS_Pr->SiS_Part2Port, i, tableptr[j]);
+   }
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+      tableptr = SiS_GetGroup2CLVXPtr(SiS_Pr, 1, HwInfo);
+      for(i = 0xc0, j = 0; i <= 0xff; i++, j++) {
+         SiS_SetReg(SiS_Pr->SiS_Part2Port, i, tableptr[j]);
+      }
+   }
+   temp = 0x10;
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) temp |= 0x04;
+   SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x4e,0xeb,temp);
+}
+
+static BOOLEAN
+SiS_GetCRT2Part2Ptr(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex,
+		    USHORT RefreshRateTableIndex,USHORT *CRT2Index,
+		    USHORT *ResIndex,PSIS_HW_INFO HwInfo)
+{
+
+  if(HwInfo->jChipType < SIS_315H) return FALSE;
+
+  if(ModeNo <= 0x13)
+     (*ResIndex) = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  else
+     (*ResIndex) = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+
+  (*ResIndex) &= 0x3f;
+  (*CRT2Index) = 0;
+
+  if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+     if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
+        (*CRT2Index) = 200;
+     }
+  }
+
+  if(SiS_Pr->SiS_CustomT == CUT_ASUSA2H_2) {
+     if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+        if(SiS_Pr->SiS_SetFlag & LCDVESATiming) (*CRT2Index) = 206;
+     }
+  }
+  return(((*CRT2Index) != 0));
+}
+#endif
+
+#ifdef SIS300
+static void
+SiS_Group2LCDSpecial(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo, USHORT crt2crtc)
+{
+   USHORT tempcx;
+   const UCHAR atable[] = {
+       0xc3,0x9e,0xc3,0x9e,0x02,0x02,0x02,
+       0xab,0x87,0xab,0x9e,0xe7,0x02,0x02
+   };
+
+   if(!SiS_Pr->UseCustomMode) {
+      if( ( ( (HwInfo->jChipType == SIS_630) ||
+              (HwInfo->jChipType == SIS_730) ) &&
+            (HwInfo->jChipRevision > 2) )  &&
+          (SiS_Pr->SiS_LCDResInfo == Panel_1024x768) &&
+          (!(SiS_Pr->SiS_SetFlag & LCDVESATiming))  &&
+          (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) ) {
+         if(ModeNo == 0x13) {
+            SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,0xB9);
+            SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,0xCC);
+            SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xA6);
+         } else {
+            if((crt2crtc & 0x3F) == 4) {
+               SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x2B);
+               SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x13);
+               SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,0xE5);
+               SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,0x08);
+               SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xE2);
+            }
+         }
+      }
+
+      if(HwInfo->jChipType < SIS_315H) {
+         if(SiS_Pr->SiS_LCDTypeInfo == 0x0c) {
+            crt2crtc &= 0x1f;
+            tempcx = 0;
+            if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) {
+               if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+                  tempcx += 7;
+               }
+            }
+            tempcx += crt2crtc;
+            if(crt2crtc >= 4) {
+               SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xff);
+            }
+
+            if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) {
+               if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+                  if(crt2crtc == 4) {
+                     SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x28);
+                  }
+               }
+            }
+            SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x18);
+            SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,atable[tempcx]);
+         }
+      }
+   }
+}
+
+/* For ECS A907. Highly preliminary. */
+static void
+SiS_Set300Part2Regs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+    		    USHORT ModeIdIndex, USHORT RefreshRateTableIndex,
+		    USHORT ModeNo)
+{
+  USHORT crt2crtc, resindex;
+  int    i,j;
+  const  SiS_Part2PortTblStruct *CRT2Part2Ptr = NULL;
+
+  if(HwInfo->jChipType != SIS_300) return;
+  if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) return;
+  if(SiS_Pr->UseCustomMode) return;
+
+  if(ModeNo <= 0x13) {
+     crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  } else {
+     crt2crtc = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+  }
+
+  resindex = crt2crtc & 0x3F;
+  if(SiS_Pr->SiS_SetFlag & LCDVESATiming) CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_1;
+  else                                    CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_2;
+
+  /* The BIOS code (1.16.51,56) is obviously a fragment! */
+  if(ModeNo > 0x13) {
+     CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_1;
+     resindex = 4;
+  }
+
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x01,0x80,(CRT2Part2Ptr+resindex)->CR[0]);
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x02,0x80,(CRT2Part2Ptr+resindex)->CR[1]);
+  for(i = 2, j = 0x04; j <= 0x06; i++, j++ ) {
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]);
+  }
+  for(j = 0x1c; j <= 0x1d; i++, j++ ) {
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]);
+  }
+  for(j = 0x1f; j <= 0x21; i++, j++ ) {
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]);
+  }
+  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x23,(CRT2Part2Ptr+resindex)->CR[10]);
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0x0f,(CRT2Part2Ptr+resindex)->CR[11]);
+}
+#endif
+
+static void
+SiS_SetTVSpecial(SiS_Private *SiS_Pr, USHORT ModeNo)
+{
+  if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) return;
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoHiVision)) return;
+  if(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p | TVSetYPbPr750p)) return;
+
+  if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) {
+     if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) {
+        const UCHAR specialtv[] = {
+		0xa7,0x07,0xf2,0x6e,0x17,0x8b,0x73,0x53,
+		0x13,0x40,0x34,0xf4,0x63,0xbb,0xcc,0x7a,
+		0x58,0xe4,0x73,0xda,0x13
+	};
+	int i, j;
+	for(i = 0x1c, j = 0; i <= 0x30; i++, j++) {
+	   SiS_SetReg(SiS_Pr->SiS_Part2Port,i,specialtv[j]);
+	}
+	SiS_SetReg(SiS_Pr->SiS_Part2Port,0x43,0x72);
+	if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750)) {
+	   if(SiS_Pr->SiS_TVMode & TVSetPALM) {
+	      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x14);
+	      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x1b);
+	   } else {
+	      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x14);  /* 15 */
+	      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x1a);  /* 1b */
+	   }
+	}
+     }
+  } else {
+     if((ModeNo == 0x38) || (ModeNo == 0x4a) || (ModeNo == 0x64) ||
+        (ModeNo == 0x52) || (ModeNo == 0x58) || (ModeNo == 0x5c)) {
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x1b);  /* 21 */
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x54);  /* 5a */
+     } else {
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x1a);  /* 21 */
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x53);  /* 5a */
+     }
+  }
+}
+
+static void
+SiS_SetGroup2_Tail(SiS_Private *SiS_Pr, USHORT ModeNo)
+{
+  USHORT temp;
+
+  if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
+     if(SiS_Pr->SiS_VGAVDE == 525) {
+	temp = 0xc3;
+	if(SiS_Pr->SiS_ModeType <= ModeVGA) {
+	   temp++;
+	   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) temp += 2;
+	}
+	SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2f,temp);
+	SiS_SetReg(SiS_Pr->SiS_Part2Port,0x30,0xb3);
+     } else if(SiS_Pr->SiS_VGAVDE == 420) {
+	temp = 0x4d;
+	if(SiS_Pr->SiS_ModeType <= ModeVGA) {
+	   temp++;
+	   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) temp++;
+	}
+	SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2f,temp);
+     }
+  }
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+     if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) {
+	if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
+	   SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x1a,0x03);
+	   /* Not always for LV, see SetGrp2 */
+	}
+	temp = 1;
+	if(ModeNo <= 0x13) temp = 3;
+	SiS_SetReg(SiS_Pr->SiS_Part2Port,0x0b,temp);
+     }
+#if 0
+     /* 651+301C, for 1280x768 - do I really need that? */
+     if((SiS_Pr->SiS_PanelXRes == 1280) && (SiS_Pr->SiS_PanelYRes == 768)) {
+        if(SiS_Pr->SiS_VBInfo & SetSimuScanMode) {
+	   if(((SiS_Pr->SiS_HDE == 640) && (SiS_Pr->SiS_VDE == 480)) ||
+	      ((SiS_Pr->SiS_HDE == 320) && (SiS_Pr->SiS_VDE == 240))) {
+	      SiS_SetReg(SiS_Part2Port,0x01,0x2b);
+	      SiS_SetReg(SiS_Part2Port,0x02,0x13);
+	      SiS_SetReg(SiS_Part2Port,0x04,0xe5);
+	      SiS_SetReg(SiS_Part2Port,0x05,0x08);
+	      SiS_SetReg(SiS_Part2Port,0x06,0xe2);
+	      SiS_SetReg(SiS_Part2Port,0x1c,0x21);
+	      SiS_SetReg(SiS_Part2Port,0x1d,0x45);
+	      SiS_SetReg(SiS_Part2Port,0x1f,0x0b);
+	      SiS_SetReg(SiS_Part2Port,0x20,0x00);
+	      SiS_SetReg(SiS_Part2Port,0x21,0xa9);
+	      SiS_SetReg(SiS_Part2Port,0x23,0x0b);
+	      SiS_SetReg(SiS_Part2Port,0x25,0x04);
+	   }
+	}
+     }
+#endif
+  }
+}
+
+static void
+SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT RefreshRateTableIndex,
+	      PSIS_HW_INFO HwInfo)
+{
+  USHORT      i, j, tempax, tempbx, tempcx, tempch, tempcl, temp;
+  USHORT      push2, modeflag, crt2crtc, bridgeoffset;
+  ULONG       longtemp;
+  const       UCHAR *PhasePoint;
+  const       UCHAR *TimingPoint;
+#ifdef SIS315H
+  USHORT      resindex, CRT2Index;
+  const       SiS_Part2PortTblStruct *CRT2Part2Ptr = NULL;
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) return;
+#endif
+
+  if(ModeNo <= 0x13) {
+     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+     crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  } else if(SiS_Pr->UseCustomMode) {
+     modeflag = SiS_Pr->CModeFlag;
+     crt2crtc = 0;
+  } else {
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+     crt2crtc = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+  }
+
+  temp = 0;
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToAVIDEO)) temp |= 0x08;
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToSVIDEO)) temp |= 0x04;
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToSCART)     temp |= 0x02;
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision)  temp |= 0x01;
+
+  if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) 	      temp |= 0x10;
+
+  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x00,temp);
+
+  PhasePoint  = SiS_Pr->SiS_PALPhase;
+  TimingPoint = SiS_Pr->SiS_PALTiming;
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+
+     TimingPoint = SiS_Pr->SiS_HiTVExtTiming;
+     if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+        TimingPoint = SiS_Pr->SiS_HiTVSt2Timing;
+        if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) {
+	   TimingPoint = SiS_Pr->SiS_HiTVSt1Timing;
+#if 0
+           if(!(modeflag & Charx8Dot))  TimingPoint = SiS_Pr->SiS_HiTVTextTiming;
+#endif
+        }
+     }
+
+  } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) {
+
+     if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p)      TimingPoint = &SiS_YPbPrTable[2][0];
+     else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) TimingPoint = &SiS_YPbPrTable[1][0];
+     else					  TimingPoint = &SiS_YPbPrTable[0][0];
+
+     PhasePoint = SiS_Pr->SiS_NTSCPhase;
+
+  } else if(SiS_Pr->SiS_TVMode & TVSetPAL) {
+
+     if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) &&
+         ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+	   (SiS_Pr->SiS_TVMode & TVSetTVSimuMode) ) ) {
+        PhasePoint = SiS_Pr->SiS_PALPhase2;
+     }
+
+  } else {
+
+     TimingPoint = SiS_Pr->SiS_NTSCTiming;
+     PhasePoint  = SiS_Pr->SiS_NTSCPhase;
+     if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) {
+	PhasePoint = SiS_Pr->SiS_PALPhase;
+     }
+
+     if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) &&
+	 ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+	   (SiS_Pr->SiS_TVMode & TVSetTVSimuMode) ) ) {
+        PhasePoint = SiS_Pr->SiS_NTSCPhase2;
+	if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) {
+	   PhasePoint = SiS_Pr->SiS_PALPhase2;
+	}
+     }
+
+  }
+
+  if(SiS_Pr->SiS_TVMode & TVSetPALM) {
+     PhasePoint = SiS_Pr->SiS_PALMPhase;
+     if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) &&
+	 ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+	   (SiS_Pr->SiS_TVMode & TVSetTVSimuMode) ) ) {
+        PhasePoint = SiS_Pr->SiS_PALMPhase2;
+     }
+  }
+
+  if(SiS_Pr->SiS_TVMode & TVSetPALN) {
+     PhasePoint = SiS_Pr->SiS_PALNPhase;
+     if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) &&
+	 ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+	   (SiS_Pr->SiS_TVMode & TVSetTVSimuMode) ) ) {
+	PhasePoint = SiS_Pr->SiS_PALNPhase2;
+     }
+  }
+
+  if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) {
+     PhasePoint = SiS_Pr->SiS_SpecialPhase;
+     if(SiS_Pr->SiS_TVMode & TVSetPALM) {
+        PhasePoint = SiS_Pr->SiS_SpecialPhaseM;
+     } else if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) {
+        PhasePoint = SiS_Pr->SiS_SpecialPhaseJ;
+     }
+  }
+
+  for(i=0x31, j=0; i<=0x34; i++, j++) {
+     SiS_SetReg(SiS_Pr->SiS_Part2Port,i,PhasePoint[j]);
+  }
+
+  for(i=0x01, j=0; i<=0x2D; i++, j++) {
+     SiS_SetReg(SiS_Pr->SiS_Part2Port,i,TimingPoint[j]);
+  }
+  for(i=0x39; i<=0x45; i++, j++) {
+     SiS_SetReg(SiS_Pr->SiS_Part2Port,i,TimingPoint[j]);
+  }
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+     if(SiS_Pr->SiS_ModeType != ModeText) {
+        SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x3A,0x1F);
+     }
+  }
+
+  SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x0A,SiS_Pr->SiS_NewFlickerMode);
+
+  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x35,SiS_Pr->SiS_RY1COE);
+  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x36,SiS_Pr->SiS_RY2COE);
+  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x37,SiS_Pr->SiS_RY3COE);
+  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x38,SiS_Pr->SiS_RY4COE);
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) 	tempax = 950;
+  else if(SiS_Pr->SiS_TVMode & TVSetPAL)      	tempax = 520;
+  else 			            		tempax = 440; /* NTSC, YPbPr 525, 750 */
+
+  if( ( (!(SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoHiVision)) && (SiS_Pr->SiS_VDE <= tempax) ) ||
+      ( (SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoHiVision) &&
+        ((SiS_Pr->SiS_VGAHDE == 1024) || (SiS_Pr->SiS_VDE <= tempax)) ) ) {
+
+     tempax -= SiS_Pr->SiS_VDE;
+     tempax >>= 2;
+     tempax &= 0x00ff;
+
+     temp = tempax + (USHORT)TimingPoint[0];
+     SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,temp);
+
+     temp = tempax + (USHORT)TimingPoint[1];
+     SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,temp);
+
+     if((SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoYPbPrHiVision) && (SiS_Pr->SiS_VGAHDE >= 1024)) {
+        if(SiS_Pr->SiS_TVMode & TVSetPAL) {
+           SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x1b);  /* 19 */
+           SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x54);  /* 52 */
+        } else {
+           SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x17);
+           SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x1d);
+        }
+     }
+
+  }
+
+  tempcx = SiS_Pr->SiS_HT;
+  if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempcx >>= 1;
+  tempcx--;
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) tempcx--;
+  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1B,tempcx);
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1D,0xF0,((tempcx >> 8) & 0x0f));
+
+  tempcx = SiS_Pr->SiS_HT >> 1;
+  if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempcx >>= 1;
+  tempcx += 7;
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) tempcx -= 4;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x22,0x0F,((tempcx << 4) & 0xf0));
+
+  tempbx = TimingPoint[j] | (TimingPoint[j+1] << 8);
+  tempbx += tempcx;
+  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x24,tempbx);
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0x0F,((tempbx >> 4) & 0xf0));
+
+  tempbx += 8;
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+     tempbx -= 4;
+     tempcx = tempbx;
+  }
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x29,0x0F,((tempbx << 4) & 0xf0));
+
+  j += 2;
+  tempcx += (TimingPoint[j] | (TimingPoint[j+1] << 8));
+  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x27,tempcx);
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x28,0x0F,((tempcx >> 4) & 0xf0));
+
+  tempcx += 8;
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) tempcx -= 4;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2A,0x0F,((tempcx << 4) & 0xf0));
+
+  tempcx = SiS_Pr->SiS_HT >> 1;
+  if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempcx >>= 1;
+  j += 2;
+  tempcx -= (TimingPoint[j] | ((TimingPoint[j+1]) << 8));
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2D,0x0F,((tempcx << 4) & 0xf0));
+
+  tempcx -= 11;
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) {
+     tempcx = SiS_GetVGAHT2(SiS_Pr) - 1;
+  }
+  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2E,tempcx);
+
+  tempbx = SiS_Pr->SiS_VDE;
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+     if(SiS_Pr->SiS_VGAVDE == 360) tempbx = 746;
+     if(SiS_Pr->SiS_VGAVDE == 375) tempbx = 746;
+     if(SiS_Pr->SiS_VGAVDE == 405) tempbx = 853;
+  } else if( (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) &&
+             (!(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p|TVSetYPbPr750p))) ) {
+     tempbx >>= 1;
+     if(HwInfo->jChipType >= SIS_315H) {
+        if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) {
+	   if((ModeNo <= 0x13) && (crt2crtc == 1)) tempbx++;
+	} else if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+	   if(SiS_Pr->SiS_ModeType <= ModeVGA) {
+	      if(crt2crtc == 4) tempbx++;
+	   }
+	}
+     }
+     if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+	   if((ModeNo == 0x2f) || (ModeNo == 0x5d) || (ModeNo == 0x5e)) tempbx++;
+	}
+	if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) {
+	   if(ModeNo == 0x03) tempbx++; /* From 1.10.7w - doesn't make sense */
+        }
+     }
+  }
+  tempbx -= 2;
+  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2F,tempbx);
+
+  temp = (tempcx >> 8) & 0x0F;
+  temp |= ((tempbx >> 2) & 0xC0);
+  if(SiS_Pr->SiS_VBInfo & (SetCRT2ToSVIDEO | SetCRT2ToAVIDEO)) {
+     temp |= 0x10;
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToAVIDEO) temp |= 0x20;
+  }
+  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x30,temp);
+
+  if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302LV | VB_SIS302ELV)) {
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x10,0xdf,((tempbx & 0x0400) >> 5));
+  }
+
+#if 0
+  /* TEST qqqq */
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) {
+     for(i=0x01, j=0; i<=0x2D; i++, j++) {
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,i,TimingPoint[j]);
+     }
+     for(i=0x39; i<=0x45; i++, j++) {
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,i,TimingPoint[j]);
+     }
+  }
+#endif
+
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+     tempbx = SiS_Pr->SiS_VDE;
+     if( (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) &&
+         (!(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p | TVSetYPbPr750p))) ) {
+        tempbx >>= 1;
+     }
+     tempbx -= 3;
+     temp = ((tempbx >> 3) & 0x60) | 0x18;
+     SiS_SetReg(SiS_Pr->SiS_Part2Port,0x46,temp);
+     SiS_SetReg(SiS_Pr->SiS_Part2Port,0x47,tempbx);
+
+     if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302LV | VB_SIS302ELV)) {
+	SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x10,0xbf,((tempbx & 0x0400) >> 4));
+     }
+  }
+
+  tempbx = 0;
+  if(!(modeflag & HalfDCLK)) {
+     if(SiS_Pr->SiS_VGAHDE >= SiS_Pr->SiS_HDE) {
+        tempax = 0;
+        tempbx |= 0x20;
+     }
+  }
+
+  tempch = tempcl = 0x01;
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+     if(SiS_Pr->SiS_VGAHDE >= 1024) {
+        if((!(modeflag & HalfDCLK)) || (HwInfo->jChipType < SIS_315H)) {
+           tempch = 0x19;
+	   tempcl = 0x20;
+           if(SiS_Pr->SiS_VGAHDE >= 1280) {
+              tempch = 0x14;
+              tempbx &= ~0x20;
+           }
+        }
+     }
+  }
+
+  if(!(tempbx & 0x20)) {
+     if(modeflag & HalfDCLK) tempcl <<= 1;
+     longtemp = ((SiS_Pr->SiS_VGAHDE * tempch) / tempcl) << 13;
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) longtemp <<= 3;
+     tempax = longtemp / SiS_Pr->SiS_HDE;
+     if(longtemp % SiS_Pr->SiS_HDE) tempax++;
+     tempbx |= ((tempax >> 8) & 0x1F);
+     tempcx = tempax >> 13;
+  }
+
+  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x44,tempax);
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x45,0xC0,tempbx);
+
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+
+     tempcx &= 0x07;
+     if(tempbx & 0x20) tempcx = 0;
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x46,0xF8,tempcx);
+
+     if(SiS_Pr->SiS_TVMode & TVSetPAL) {
+        tempbx = 0x0382;
+        tempcx = 0x007e;
+     } else {
+        tempbx = 0x0369;
+        tempcx = 0x0061;
+     }
+     SiS_SetReg(SiS_Pr->SiS_Part2Port,0x4B,tempbx);
+     SiS_SetReg(SiS_Pr->SiS_Part2Port,0x4C,tempcx);
+     temp = (tempcx & 0x0300) >> 6;
+     temp |= ((tempbx >> 8) & 0x03);
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) {
+        temp |= 0x10;
+	if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p)      temp |= 0x20;
+	else if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) temp |= 0x40;
+     }
+     SiS_SetReg(SiS_Pr->SiS_Part2Port,0x4D,temp);
+
+     temp = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x43);
+     SiS_SetReg(SiS_Pr->SiS_Part2Port,0x43,(temp - 3));
+
+     SiS_SetTVSpecial(SiS_Pr, ModeNo);
+
+     if(SiS_Pr->SiS_VBType & VB_SIS301C) {
+        temp = 0;
+        if(SiS_Pr->SiS_TVMode & TVSetPALM) temp = 8;
+        SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x4e,0xf7,temp);
+     }
+
+  }
+
+  if(SiS_Pr->SiS_TVMode & TVSetPALM) {
+     if(!(SiS_Pr->SiS_TVMode & TVSetNTSC1024)) {
+        temp = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x01);
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,(temp - 1));
+     }
+     SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xEF);
+  }
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+     if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,0x0B,0x00);
+     }
+  }
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) return;
+
+  /* From here: Part2 LCD setup */
+
+  tempbx = SiS_Pr->SiS_HDE;
+  if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempbx >>= 1;
+  tempbx--;			         	/* RHACTE = HDE - 1 */
+  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2C,tempbx);
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2B,0x0F,((tempbx >> 4) & 0xf0));
+
+  temp = 0x01;
+  if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) {
+     if(SiS_Pr->SiS_ModeType == ModeEGA) {
+        if(SiS_Pr->SiS_VGAHDE >= 1024) {
+           temp = 0x02;
+	   if(HwInfo->jChipType >= SIS_315H) {
+              if(SiS_Pr->SiS_SetFlag & LCDVESATiming) {
+                 temp = 0x01;
+	      }
+	   }
+        }
+     }
+  }
+  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x0B,temp);
+
+  tempbx = SiS_Pr->SiS_VDE - 1;
+  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x03,tempbx);
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x0C,0xF8,((tempbx >> 8) & 0x07));
+
+  tempcx = SiS_Pr->SiS_VT - 1;
+  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x19,tempcx);
+  temp = (tempcx >> 3) & 0xE0;
+  if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) {
+     /* Enable dithering; only do this for 32bpp mode */
+     if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x01) {
+        temp |= 0x10;
+     }
+  }
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1A,0x0f,temp);
+
+  SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x09,0xF0);
+  SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x0A,0xF0);
+
+  SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x17,0xFB);
+  SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x18,0xDF);
+
+#ifdef SIS315H
+  if(SiS_GetCRT2Part2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex,
+                          			&CRT2Index, &resindex, HwInfo)) {
+      switch(CRT2Index) {
+        case 200: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_1;   break;
+	case 206: CRT2Part2Ptr = SiS310_CRT2Part2_Asus1024x768_3;    break;
+	default:  CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_3;   break;
+      }
+
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x01,0x80,(CRT2Part2Ptr+resindex)->CR[0]);
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x02,0x80,(CRT2Part2Ptr+resindex)->CR[1]);
+      for(i = 2, j = 0x04; j <= 0x06; i++, j++ ) {
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]);
+      }
+      for(j = 0x1c; j <= 0x1d; i++, j++ ) {
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]);
+      }
+      for(j = 0x1f; j <= 0x21; i++, j++ ) {
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]);
+      }
+      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x23,(CRT2Part2Ptr+resindex)->CR[10]);
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0x0f,(CRT2Part2Ptr+resindex)->CR[11]);
+
+      SiS_SetGroup2_Tail(SiS_Pr, ModeNo);
+
+
+  } else {
+#endif
+
+    /* Checked for 1024x768, 1280x1024, 1400x1050, 1600x1200 */
+    /*             Clevo dual-link 1024x768 */
+    /* 		   Compaq 1280x1024 has HT 1696 sometimes (calculation OK, if given HT is correct)  */
+    /*		   Acer: OK, but uses different setting for VESA timing at 640/800/1024 and 640x400 */
+
+    if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+       if((SiS_Pr->SiS_LCDInfo & LCDPass11) || (SiS_Pr->PanelYRes == SiS_Pr->SiS_VDE)) {
+          tempbx = SiS_Pr->SiS_VDE - 1;
+          tempcx = SiS_Pr->SiS_VT - 1;
+       } else {
+          tempbx = SiS_Pr->SiS_VDE + ((SiS_Pr->PanelYRes - SiS_Pr->SiS_VDE) / 2);
+	  tempcx = SiS_Pr->SiS_VT - ((SiS_Pr->PanelYRes - SiS_Pr->SiS_VDE) / 2);
+       }
+    } else {
+       tempbx = SiS_Pr->PanelYRes;
+       tempcx = SiS_Pr->SiS_VT;
+       tempax = 1;
+       if(SiS_Pr->PanelYRes != SiS_Pr->SiS_VDE) {
+          tempax = SiS_Pr->PanelYRes;
+	  /* if(SiS_Pr->SiS_VGAVDE == 525) tempax += 0x3c;   */  /* 651+301C */
+          if(SiS_Pr->PanelYRes < SiS_Pr->SiS_VDE) {
+             tempax = tempcx = 0;
+          } else {
+             tempax -= SiS_Pr->SiS_VDE;
+          }
+          tempax >>= 1;
+       }
+       tempcx -= tempax; /* lcdvdes */
+       tempbx -= tempax; /* lcdvdee */
+    }
+
+    /* Non-expanding: lcdvdes = tempcx = VT-1; lcdvdee = tempbx = VDE-1 */
+
+#ifdef TWDEBUG
+    xf86DrvMsg(0, X_INFO, "lcdvdes 0x%x lcdvdee 0x%x\n", tempcx, tempbx);
+#endif
+
+    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,tempcx);	/* lcdvdes  */
+    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,tempbx);	/* lcdvdee  */
+
+    temp = (tempbx >> 5) & 0x38;
+    temp |= ((tempcx >> 8) & 0x07);
+    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,temp);
+
+    tempax = SiS_Pr->SiS_VDE;
+    if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) {
+       tempax = SiS_Pr->PanelYRes;
+    }
+    tempcx = (SiS_Pr->SiS_VT - tempax) >> 4;
+    if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) {
+       if(SiS_Pr->PanelYRes != SiS_Pr->SiS_VDE) {
+	  tempcx = (SiS_Pr->SiS_VT - tempax) / 10;
+       }
+    }
+
+    tempbx = ((SiS_Pr->SiS_VT + SiS_Pr->SiS_VDE) >> 1) - 1;
+    if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+       if(SiS_Pr->PanelYRes != SiS_Pr->SiS_VDE) {
+          if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { /* ? */
+             tempax = SiS_Pr->SiS_VT - SiS_Pr->PanelYRes;
+	     if(tempax % 4) { tempax >>= 2; tempax++; }
+	     else           { tempax >>= 2;           }
+             tempbx -= (tempax - 1);
+	  } else {
+	     tempbx -= 10;
+	     if(tempbx <= SiS_Pr->SiS_VDE) tempbx = SiS_Pr->SiS_VDE + 1;
+	  }
+       }
+    }
+    if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+       tempbx++;
+       if((!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) || (crt2crtc == 6)) {
+          if(SiS_Pr->SiS_SetFlag & LCDVESATiming) {
+	     tempbx = 770;
+	     tempcx = 3;
+	  }
+       }
+    }
+
+    /* non-expanding: lcdvrs = ((VT + VDE) / 2) - 10 */
+
+    if(SiS_Pr->UseCustomMode) {
+       tempbx = SiS_Pr->CVSyncStart;
+    }
+
+#ifdef TWDEBUG
+    xf86DrvMsg(0, X_INFO, "lcdvrs 0x%x\n", tempbx);
+#endif
+
+    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,tempbx);	    /* lcdvrs */
+
+    temp = (tempbx >> 4) & 0xF0;
+    tempbx += (tempcx + 1);
+    temp |= (tempbx & 0x0F);
+
+    if(SiS_Pr->UseCustomMode) {
+       temp &= 0xf0;
+       temp |= (SiS_Pr->CVSyncEnd & 0x0f);
+    }
+
+#ifdef TWDEBUG
+    xf86DrvMsg(0, X_INFO, "lcdvre[3:0] 0x%x\n", (temp & 0x0f));
+#endif
+
+    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,temp);
+
+#ifdef SIS300
+    SiS_Group2LCDSpecial(SiS_Pr, HwInfo, ModeNo, crt2crtc);
+#endif
+
+    bridgeoffset = 7;
+    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)          bridgeoffset += 2;
+    if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV)) bridgeoffset++;
+    if(SiS_IsDualLink(SiS_Pr, HwInfo))        		 bridgeoffset++;
+
+    temp = 0;
+    if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) {
+       if(SiS_Pr->PanelXRes != SiS_Pr->SiS_HDE) {
+          temp = SiS_Pr->SiS_HT - ((SiS_Pr->PanelXRes - SiS_Pr->SiS_HDE) / 2);
+	  if(SiS_IsDualLink(SiS_Pr, HwInfo)) temp >>= 1;
+       }
+    }
+    temp += bridgeoffset;
+    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1F,temp);  	     /* lcdhdes */
+    SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x20,0x0F,((temp >> 4) & 0xf0));
+
+    tempcx = SiS_Pr->SiS_HT;
+    tempax = tempbx = SiS_Pr->SiS_HDE;
+    if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) {
+       if(SiS_Pr->PanelXRes != SiS_Pr->SiS_HDE) {
+          tempax = SiS_Pr->PanelXRes;
+          tempbx = SiS_Pr->PanelXRes - ((SiS_Pr->PanelXRes - SiS_Pr->SiS_HDE) / 2);
+       }
+    }
+    if(SiS_IsDualLink(SiS_Pr, HwInfo)) {
+       tempcx >>= 1;
+       tempbx >>= 1;
+       tempax >>= 1;
+    }
+
+#ifdef TWDEBUG
+    xf86DrvMsg(0, X_INFO, "lcdhdee 0x%x\n", tempbx);
+#endif
+
+    tempbx += bridgeoffset;
+
+    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x23,tempbx);	    /* lcdhdee */
+    SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0xF0,((tempbx >> 8) & 0x0f));
+
+    tempcx = (tempcx - tempax) >> 2;
+
+    tempbx += tempcx;
+    push2 = tempbx;
+
+    if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) {
+       if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+          if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
+             if(SiS_Pr->SiS_HDE == 1280) tempbx = (tempbx & 0xff00) | 0x47;
+	  }
+       }
+    }
+
+    if(SiS_Pr->UseCustomMode) {
+       tempbx = SiS_Pr->CHSyncStart;
+       if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempbx >>= 1;
+       tempbx += bridgeoffset;
+    }
+
+#ifdef TWDEBUG
+    xf86DrvMsg(0, X_INFO, "lcdhrs 0x%x\n", tempbx);
+#endif
+
+    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1C,tempbx);	    /* lcdhrs */
+    SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1D,0x0F,((tempbx >> 4) & 0xf0));
+
+    tempbx = push2;
+
+    tempcx <<= 1;
+    if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) {
+       if(SiS_Pr->PanelXRes != SiS_Pr->SiS_HDE) tempcx >>= 2;
+    }
+    tempbx += tempcx;
+
+    if(SiS_Pr->UseCustomMode) {
+       tempbx = SiS_Pr->CHSyncEnd;
+       if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempbx >>= 1;
+       tempbx += bridgeoffset;
+    }
+
+#ifdef TWDEBUG
+    xf86DrvMsg(0, X_INFO, "lcdhre 0x%x\n", tempbx);
+#endif
+
+    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x21,tempbx);	    /* lcdhre */
+
+    SiS_SetGroup2_Tail(SiS_Pr, ModeNo);
+
+#ifdef SIS300
+    SiS_Set300Part2Regs(SiS_Pr, HwInfo, ModeIdIndex, RefreshRateTableIndex, ModeNo);
+#endif
+#ifdef SIS315H
+  } /* CRT2-LCD from table */
+#endif
+}
+
+/*********************************************/
+/*         SET PART 3 REGISTER GROUP         */
+/*********************************************/
+
+static void
+SiS_SetGroup3(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+              PSIS_HW_INFO HwInfo)
+{
+  USHORT 	i;
+  const UCHAR  	*tempdi;
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) return;
+
+#ifndef SIS_CP
+  SiS_SetReg(SiS_Pr->SiS_Part3Port,0x00,0x00);
+#else
+  SIS_CP_INIT301_CP
+#endif
+
+  if(SiS_Pr->SiS_TVMode & TVSetPAL) {
+     SiS_SetReg(SiS_Pr->SiS_Part3Port,0x13,0xFA);
+     SiS_SetReg(SiS_Pr->SiS_Part3Port,0x14,0xC8);
+  } else {
+     SiS_SetReg(SiS_Pr->SiS_Part3Port,0x13,0xF5);
+     SiS_SetReg(SiS_Pr->SiS_Part3Port,0x14,0xB7);
+  }
+
+  if(SiS_Pr->SiS_TVMode & TVSetPALM) {
+     SiS_SetReg(SiS_Pr->SiS_Part3Port,0x13,0xFA);
+     SiS_SetReg(SiS_Pr->SiS_Part3Port,0x14,0xC8);
+     SiS_SetReg(SiS_Pr->SiS_Part3Port,0x3D,0xA8);
+  }
+
+  tempdi = NULL;
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+     tempdi = SiS_Pr->SiS_HiTVGroup3Data;
+     if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) {
+        tempdi = SiS_Pr->SiS_HiTVGroup3Simu;
+     }
+  } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) {
+     if(!(SiS_Pr->SiS_TVMode & TVSetYPbPr525i)) {
+        tempdi = SiS_HiTVGroup3_1;
+        if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) tempdi = SiS_HiTVGroup3_2;
+     }
+  }
+  if(tempdi) {
+     for(i=0; i<=0x3E; i++) {
+        SiS_SetReg(SiS_Pr->SiS_Part3Port,i,tempdi[i]);
+     }
+     if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV)) {
+	if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) {
+	   SiS_SetReg(SiS_Pr->SiS_Part3Port,0x28,0x3f);
+	}
+     }
+  }
+
+#ifdef SIS_CP
+  SIS_CP_INIT301_CP2
+#endif
+}
+
+/*********************************************/
+/*         SET PART 4 REGISTER GROUP         */
+/*********************************************/
+
+#ifdef SIS315H
+static void
+SiS_ShiftXPos(SiS_Private *SiS_Pr, int shift)
+{
+   USHORT temp, temp1, temp2;
+
+   temp1 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x1f);
+   temp2 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x20);
+   temp = (USHORT)((int)((temp1 | ((temp2 & 0xf0) << 4))) + shift);
+   SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1f,temp);
+   SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x20,0x0f,((temp >> 4) & 0xf0));
+   temp = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x2b) & 0x0f;
+   temp = (USHORT)((int)(temp) + shift);
+   SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2b,0xf0,(temp & 0x0f));
+   temp1 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x43);
+   temp2 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x42);
+   temp = (USHORT)((int)((temp1 | ((temp2 & 0xf0) << 4))) + shift);
+   SiS_SetReg(SiS_Pr->SiS_Part2Port,0x43,temp);
+   SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x42,0x0f,((temp >> 4) & 0xf0));
+}
+
+static void
+SiS_SetGroup4_C_ELV(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+                    USHORT ModeNo, USHORT ModeIdIndex)
+{
+   USHORT temp, temp1, resinfo = 0;
+
+   if(!(SiS_Pr->SiS_VBType & VB_SIS301C)) return;
+   if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToHiVision | SetCRT2ToYPbPr525750))) return;
+
+   if(ModeNo > 0x13) {
+      resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+   }
+
+   SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x3a,0x08);
+   temp = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x3a);
+   if(!(temp & 0x01)) {
+      SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x3a,0xdf);
+      SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x25,0xfc);
+      if((HwInfo->jChipType < SIS_661) && (!(SiS_Pr->SiS_ROMNew))) {
+         SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x25,0xf8);
+      }
+      SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x0f,0xfb);
+      if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p)      temp = 0x0000;
+      else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) temp = 0x0002;
+      else if(SiS_Pr->SiS_TVMode & TVSetHiVision)  temp = 0x0400;
+      else					   temp = 0x0402;
+      if((HwInfo->jChipType >= SIS_661) || (SiS_Pr->SiS_ROMNew)) {
+         temp1 = 0;
+	 if(SiS_Pr->SiS_TVMode & TVAspect43) temp1 = 4;
+	 SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0f,0xfb,temp1);
+	 if(SiS_Pr->SiS_TVMode & TVAspect43LB) temp |= 0x01;
+	 SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0x7c,(temp & 0xff));
+      } else {
+         temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x3b) & 0x03;
+	 if(temp1 == 0x01) temp |= 0x01;
+	 if(temp1 == 0x03) temp |= 0x04;  /* ? why not 0x10? */
+	 SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xf8,(temp & 0xff));
+      }
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x3a,0xfb,(temp >> 8));
+      if(ModeNo > 0x13) {
+         SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x3b,0xfd);
+      }
+
+      if(HwInfo->jChipType >= SIS_661) { 		/* ? */
+         if(SiS_Pr->SiS_TVMode & TVAspect43) {
+            if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) {
+	       if(resinfo == SIS_RI_1024x768) {
+	          SiS_ShiftXPos(SiS_Pr, 97);
+	       } else {
+	          SiS_ShiftXPos(SiS_Pr, 111);
+	       }
+	    } else if(SiS_Pr->SiS_TVMode & TVSetHiVision) {
+	       SiS_ShiftXPos(SiS_Pr, 136);
+	    }
+         }
+      }
+   }
+}
+#endif
+
+static void
+SiS_SetCRT2VCLK(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+                 USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo)
+{
+  USHORT vclkindex;
+  USHORT temp, reg1, reg2;
+
+  if(SiS_Pr->UseCustomMode) {
+     reg1 = SiS_Pr->CSR2B;
+     reg2 = SiS_Pr->CSR2C;
+  } else {
+     vclkindex = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex,
+                                 HwInfo);
+     reg1 = SiS_Pr->SiS_VBVCLKData[vclkindex].Part4_A;
+     reg2 = SiS_Pr->SiS_VBVCLKData[vclkindex].Part4_B;
+  }
+
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+     if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) {
+        SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0a,0x57);
+ 	SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0b,0x46);
+	SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1f,0xf6);
+     } else {
+        SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0a,reg1);
+        SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0b,reg2);
+     }
+  } else {
+     SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0a,0x01);
+     SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0b,reg2);
+     SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0a,reg1);
+  }
+  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x12,0x00);
+  temp = 0x08;
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) temp |= 0x20;
+  SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x12,temp);
+}
+
+static void
+SiS_SetGroup4(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+  	      USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo)
+{
+  USHORT tempax,tempcx,tempbx,modeflag,temp,resinfo;
+  ULONG tempebx,tempeax,templong;
+
+  if(ModeNo <= 0x13) {
+     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+     resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+  } else if(SiS_Pr->UseCustomMode) {
+     modeflag = SiS_Pr->CModeFlag;
+     resinfo = 0;
+  } else {
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+     resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+  }
+
+  if(HwInfo->jChipType >= SIS_315H) {
+     if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+           SiS_SetReg(SiS_Pr->SiS_Part4Port,0x24,0x0e);
+        }
+     }
+  }
+
+  if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302LV)) {
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+        SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x10,0x9f);
+     }
+  }
+
+  if(HwInfo->jChipType >= SIS_315H) {
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+        if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+	   if(SiS_IsDualLink(SiS_Pr, HwInfo)) {
+	      SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x2c);
+	   } else {
+	      SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x27,~0x20);
+	   }
+
+	   if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
+	      SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2a,0x00);
+#ifdef SET_EMI
+	      SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c);
+#endif
+	      SiS_SetReg(SiS_Pr->SiS_Part4Port,0x34,0x10);
+	   }
+	}
+   	return;
+     }
+  }
+
+  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x13,SiS_Pr->SiS_RVBHCFACT);
+
+  tempbx = SiS_Pr->SiS_RVBHCMAX;
+  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x14,tempbx);
+
+  temp = (tempbx >> 1) & 0x80;
+
+  tempcx = SiS_Pr->SiS_VGAHT - 1;
+  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x16,tempcx);
+
+  temp |= ((tempcx >> 5) & 0x78);
+
+  tempcx = SiS_Pr->SiS_VGAVT - 1;
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) tempcx -= 5;
+  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x17,tempcx);
+
+  temp |= ((tempcx >> 8) & 0x07);
+  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x15,temp);
+
+  tempbx = SiS_Pr->SiS_VGAHDE;
+  if(modeflag & HalfDCLK)            tempbx >>= 1;
+  if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempbx >>= 1;
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+     temp = 0;
+     if(tempbx > 800)        temp = 0x60;
+  } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+     temp = 0;
+     if(tempbx == 1024)      temp = 0xA0;
+     else if(tempbx > 1024)  temp = 0xC0;
+  } else if(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p | TVSetYPbPr750p)) {
+     temp = 0;
+     if(tempbx >= 1280)      temp = 0x40;
+     else if(tempbx >= 1024) temp = 0x20;
+  } else {
+     temp = 0x80;
+     if(tempbx >= 1024)      temp = 0xA0;
+  }
+
+  if(SiS_Pr->SiS_VBType & VB_SIS301) {
+     if(SiS_Pr->SiS_LCDResInfo != Panel_1280x1024) temp |= 0x0A;
+  }
+
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0E,0x10,temp);
+
+  tempeax = SiS_Pr->SiS_VGAVDE;
+  tempebx = SiS_Pr->SiS_VDE;
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+     if(!(temp & 0xE0)) tempebx >>=1;
+  }
+
+  tempcx = SiS_Pr->SiS_RVBHRS;
+  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x18,tempcx);
+  tempcx >>= 8;
+  tempcx |= 0x40;
+
+  if(tempeax <= tempebx) {
+     tempcx ^= 0x40;
+  } else {
+     tempeax -= tempebx;
+  }
+
+  tempeax *= (256 * 1024);
+  templong = tempeax % tempebx;
+  tempeax /= tempebx;
+  if(templong) tempeax++;
+
+  temp = (USHORT)(tempeax & 0x000000FF);
+  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1B,temp);
+  temp = (USHORT)((tempeax & 0x0000FF00) >> 8);
+  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1A,temp);
+  temp = (USHORT)((tempeax >> 12) & 0x70); /* sic! */
+  temp |= (tempcx & 0x4F);
+  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x19,temp);
+
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+
+     SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1C,0x28);
+
+     /* Calc Linebuffer max address and set/clear decimode */
+     tempbx = 0;
+     if(SiS_Pr->SiS_TVMode & (TVSetHiVision | TVSetYPbPr750p)) tempbx = 0x08;
+     tempax = SiS_Pr->SiS_VGAHDE;
+     if(modeflag & HalfDCLK)            tempax >>= 1;
+     if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempax >>= 1;
+     if(tempax > 800) {
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+	   tempax -= 800;
+	} else {  /* 651+301C: Only if TVNoHiviNoYPbPr */
+	   tempbx = 0x08;
+           if(tempax == 1024) tempax *= 25;
+           else	              tempax *= 20;
+	   temp = tempax % 32;
+	   tempax /= 32;
+	   if(temp) tempax++;
+	   tempax++;
+	   if((SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoYPbPrHiVision) ||
+	      (SiS_Pr->SiS_TVMode & TVSetYPbPr525i)) {
+	      if(resinfo == SIS_RI_1024x768) {
+	         /* Otherwise white line at right edge */
+	         tempax = (tempax & 0xff00) | 0x20;
+	      }
+	   }
+	}
+     }
+     tempax--;
+     temp = ((tempax >> 4) & 0x30) | tempbx;
+     SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1D,tempax);
+     SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1E,temp);
+
+     temp = 0x0036; tempbx = 0xD0;
+     if((HwInfo->jChipType >= SIS_315H) && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) {
+	temp = 0x0026; tempbx = 0xC0; /* See En/DisableBridge() */
+     }
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+        if(!(SiS_Pr->SiS_TVMode & (TVSetNTSC1024 | TVSetHiVision | TVSetYPbPr750p | TVSetYPbPr525p))) {
+	   temp |= 0x01;
+	   if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+	      if(!(SiS_Pr->SiS_TVMode & TVSetTVSimuMode)) {
+  	         temp &= ~0x01;
+	      }
+	   }
+	}
+     }
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x1F,tempbx,temp);
+
+     tempbx = SiS_Pr->SiS_HT >> 1;
+     if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempbx >>= 1;
+     tempbx -= 2;
+     SiS_SetReg(SiS_Pr->SiS_Part4Port,0x22,tempbx);
+     temp = (tempbx >> 5) & 0x38;
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,0xC0,temp);
+
+     if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+	if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+           SiS_SetReg(SiS_Pr->SiS_Part4Port,0x24,0x0e);
+	   /* LCD-too-dark-error-source, see FinalizeLCD() */
+	}
+	if(HwInfo->jChipType >= SIS_315H) {
+	   if(SiS_IsDualLink(SiS_Pr, HwInfo)) {
+	      SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x2c);
+	   } else {
+	      SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x27,~0x20);
+	   }
+	}
+	if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
+	   SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2a,0x00);
+#ifdef SET_EMI
+	   SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c);
+#endif
+	   SiS_SetReg(SiS_Pr->SiS_Part4Port,0x34,0x10);
+	}
+     }
+
+  }  /* 301B */
+
+  SiS_SetCRT2VCLK(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
+}
+
+/*********************************************/
+/*         SET PART 5 REGISTER GROUP         */
+/*********************************************/
+
+static void
+SiS_SetGroup5(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+              PSIS_HW_INFO HwInfo)
+{
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)  return;
+
+  if(SiS_Pr->SiS_ModeType == ModeVGA) {
+     if(!(SiS_Pr->SiS_VBInfo & (SetInSlaveMode | LoadDACFlag))) {
+        SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);
+        SiS_LoadDAC(SiS_Pr, HwInfo, ModeNo, ModeIdIndex);
+     }
+  }
+}
+
+/*********************************************/
+/*     MODIFY CRT1 GROUP FOR SLAVE MODE      */
+/*********************************************/
+
+static void
+SiS_ModCRT1CRTC(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+                USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo)
+{
+  USHORT tempah,i,modeflag,j;
+  USHORT ResIndex,DisplayType;
+  const SiS_LVDSCRT1DataStruct *LVDSCRT1Ptr=NULL;
+
+  if(ModeNo <= 0x13) modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  else               modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+
+  if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) ||
+     (SiS_Pr->SiS_CustomT == CUT_BARCO1024) ||
+     (SiS_Pr->SiS_CustomT == CUT_PANEL848))
+     return;
+
+  if(!(SiS_GetLVDSCRT1Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex,
+                          &ResIndex, &DisplayType))) {
+     return;
+  }
+
+  if(HwInfo->jChipType < SIS_315H) {
+     if(SiS_Pr->SiS_SetFlag & SetDOSMode) return;
+  }
+
+  switch(DisplayType) {
+    case 0 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_1;           break;
+    case 1 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_1_H;         break;
+    case 2 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2;           break;
+    case 3 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2_H;         break;
+    case 4 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1;          break;
+    case 5 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1_H;        break;
+    case 6 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2;          break;
+    case 7 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2_H;        break;
+    case 8 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1;         break;
+    case 9 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1_H;       break;
+    case 10: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_2;         break;
+    case 11: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_2_H;       break;
+    case 12: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1XXXxXXX_1;           break;
+    case 13: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1XXXxXXX_1_H;         break;
+    case 14: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_1;         break;
+    case 15: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_1_H;       break;
+    case 16: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_2;         break;
+    case 17: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_2_H;       break;
+    case 18: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1UNTSC;               break;
+    case 19: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1ONTSC;               break;
+    case 20: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1UPAL;                break;
+    case 21: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1OPAL;                break;
+    case 22: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1320x480_1;           break; /* FSTN */
+    case 23: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_1;          break;
+    case 24: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_1_H;        break;
+    case 25: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_2;          break;
+    case 26: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_2_H;        break;
+    case 27: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_1;          break;
+    case 28: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_1_H;        break;
+    case 29: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_2;          break;
+    case 30: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_2_H;        break;
+    case 36: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_1;         break;
+    case 37: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_1_H;       break;
+    case 38: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_2;         break;
+    case 39: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_2_H;       break;
+    case 40: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x768_1;          break;
+    case 41: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x768_1_H;        break;
+    case 42: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x768_2;          break;
+    case 43: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x768_2_H;        break;
+    case 50: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1640x480_1;           break;
+    case 51: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1640x480_1_H;         break;
+    case 52: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1640x480_2;           break;
+    case 53: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1640x480_2_H;         break;
+    case 54: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1640x480_3;           break;
+    case 55: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1640x480_3_H;         break;
+    case 99: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1SOPAL;               break;
+    default: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1;          break;
+  }
+
+  SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f);
+
+  tempah = (LVDSCRT1Ptr + ResIndex)->CR[0];
+  SiS_SetReg(SiS_Pr->SiS_P3d4,0x00,tempah);
+
+  for(i=0x02,j=1;i<=0x05;i++,j++){
+    tempah = (LVDSCRT1Ptr + ResIndex)->CR[j];
+    SiS_SetReg(SiS_Pr->SiS_P3d4,i,tempah);
+  }
+  for(i=0x06,j=5;i<=0x07;i++,j++){
+    tempah = (LVDSCRT1Ptr + ResIndex)->CR[j];
+    SiS_SetReg(SiS_Pr->SiS_P3d4,i,tempah);
+  }
+  for(i=0x10,j=7;i<=0x11;i++,j++){
+    tempah = (LVDSCRT1Ptr + ResIndex)->CR[j];
+    SiS_SetReg(SiS_Pr->SiS_P3d4,i,tempah);
+  }
+  for(i=0x15,j=9;i<=0x16;i++,j++){
+    tempah = (LVDSCRT1Ptr + ResIndex)->CR[j];
+    SiS_SetReg(SiS_Pr->SiS_P3d4,i,tempah);
+  }
+  for(i=0x0A,j=11;i<=0x0C;i++,j++){
+    tempah = (LVDSCRT1Ptr + ResIndex)->CR[j];
+    SiS_SetReg(SiS_Pr->SiS_P3c4,i,tempah);
+  }
+
+  tempah = (LVDSCRT1Ptr + ResIndex)->CR[14];
+  tempah &= 0xE0;
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0x1f,tempah);
+
+  tempah = (LVDSCRT1Ptr + ResIndex)->CR[14];
+  tempah &= 0x01;
+  tempah <<= 5;
+  if(modeflag & DoubleScanMode)  tempah |= 0x080;
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,~0x020,tempah);
+}
+
+/*********************************************/
+/*              SET CRT2 ECLK                */
+/*********************************************/
+
+static void
+SiS_SetCRT2ECLK(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+           USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo)
+{
+  UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+  USHORT clkbase, vclkindex=0;
+  UCHAR  sr2b, sr2c;
+
+  if((SiS_Pr->SiS_LCDResInfo == Panel_640x480) || (SiS_Pr->SiS_LCDInfo & LCDPass11)) {
+	SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2);
+        if((SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK & 0x3f) == 2) {
+	   RefreshRateTableIndex--;
+	}
+	vclkindex = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex,
+                                    RefreshRateTableIndex, HwInfo);
+	SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
+  } else {
+        vclkindex = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex,
+                                    RefreshRateTableIndex, HwInfo);
+  }
+
+  sr2b = SiS_Pr->SiS_VCLKData[vclkindex].SR2B;
+  sr2c = SiS_Pr->SiS_VCLKData[vclkindex].SR2C;
+
+  if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) {
+     if(SiS_Pr->SiS_UseROM) {
+	if(ROMAddr[0x220] & 0x01) {
+           sr2b = ROMAddr[0x227];
+	   sr2c = ROMAddr[0x228];
+	}
+     }
+  }
+
+  clkbase = 0x02B;
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+     if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+    	clkbase += 3;
+     }
+  }
+
+  SiS_SetReg(SiS_Pr->SiS_P3c4,0x31,0x20);
+  SiS_SetReg(SiS_Pr->SiS_P3c4,clkbase,sr2b);
+  SiS_SetReg(SiS_Pr->SiS_P3c4,clkbase+1,sr2c);
+  SiS_SetReg(SiS_Pr->SiS_P3c4,0x31,0x10);
+  SiS_SetReg(SiS_Pr->SiS_P3c4,clkbase,sr2b);
+  SiS_SetReg(SiS_Pr->SiS_P3c4,clkbase+1,sr2c);
+  SiS_SetReg(SiS_Pr->SiS_P3c4,0x31,0x00);
+  SiS_SetReg(SiS_Pr->SiS_P3c4,clkbase,sr2b);
+  SiS_SetReg(SiS_Pr->SiS_P3c4,clkbase+1,sr2c);
+}
+
+/*********************************************/
+/*           SET UP CHRONTEL CHIPS           */
+/*********************************************/
+
+static void
+SiS_SetCHTVReg(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+               USHORT RefreshRateTableIndex)
+{
+#if defined(SIS300) || defined(SIS315H)
+  USHORT temp, tempbx;
+#endif
+  USHORT tempcl;
+  USHORT TVType, resindex;
+  const SiS_CHTVRegDataStruct *CHTVRegData = NULL;
+
+  if(ModeNo <= 0x13)
+     tempcl = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  else
+     tempcl = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+
+  TVType = 0;
+  if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) TVType += 1;
+  if(SiS_Pr->SiS_TVMode & TVSetPAL) {
+  	TVType += 2;
+	if(SiS_Pr->SiS_ModeType > ModeVGA) {
+	   if(SiS_Pr->SiS_CHSOverScan) TVType = 8;
+	}
+	if(SiS_Pr->SiS_TVMode & TVSetPALM) {
+		TVType = 4;
+		if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) TVType += 1;
+	} else if(SiS_Pr->SiS_TVMode & TVSetPALN) {
+		TVType = 6;
+		if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) TVType += 1;
+	}
+  }
+  switch(TVType) {
+     case  0: CHTVRegData = SiS_Pr->SiS_CHTVReg_UNTSC; break;
+     case  1: CHTVRegData = SiS_Pr->SiS_CHTVReg_ONTSC; break;
+     case  2: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPAL;  break;
+     case  3: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPAL;  break;
+     case  4: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPALM; break;
+     case  5: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPALM; break;
+     case  6: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPALN; break;
+     case  7: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPALN; break;
+     case  8: CHTVRegData = SiS_Pr->SiS_CHTVReg_SOPAL; break;
+     default: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPAL;  break;
+  }
+  resindex = tempcl & 0x3F;
+
+  if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
+
+#ifdef SIS300
+
+     /* Chrontel 7005 - I assume that it does not come with a 315 series chip */
+
+     /* We don't support modes >800x600 */
+     if (resindex > 5) return;
+
+     if(SiS_Pr->SiS_TVMode & TVSetPAL) {
+    	SiS_SetCH700x(SiS_Pr,0x4304);   /* 0x40=76uA (PAL); 0x03=15bit non-multi RGB*/
+    	SiS_SetCH700x(SiS_Pr,0x6909);	/* Black level for PAL (105)*/
+     } else {
+    	SiS_SetCH700x(SiS_Pr,0x0304);   /* upper nibble=71uA (NTSC), 0x03=15bit non-multi RGB*/
+    	SiS_SetCH700x(SiS_Pr,0x7109);	/* Black level for NTSC (113)*/
+     }
+
+     temp = CHTVRegData[resindex].Reg[0];
+     tempbx=((temp&0x00FF)<<8)|0x00;	/* Mode register */
+     SiS_SetCH700x(SiS_Pr,tempbx);
+     temp = CHTVRegData[resindex].Reg[1];
+     tempbx=((temp&0x00FF)<<8)|0x07;	/* Start active video register */
+     SiS_SetCH700x(SiS_Pr,tempbx);
+     temp = CHTVRegData[resindex].Reg[2];
+     tempbx=((temp&0x00FF)<<8)|0x08;	/* Position overflow register */
+     SiS_SetCH700x(SiS_Pr,tempbx);
+     temp = CHTVRegData[resindex].Reg[3];
+     tempbx=((temp&0x00FF)<<8)|0x0A;	/* Horiz Position register */
+     SiS_SetCH700x(SiS_Pr,tempbx);
+     temp = CHTVRegData[resindex].Reg[4];
+     tempbx=((temp&0x00FF)<<8)|0x0B;	/* Vertical Position register */
+     SiS_SetCH700x(SiS_Pr,tempbx);
+
+     /* Set minimum flicker filter for Luma channel (SR1-0=00),
+                minimum text enhancement (S3-2=10),
+   	        maximum flicker filter for Chroma channel (S5-4=10)
+	        =00101000=0x28 (When reading, S1-0->S3-2, and S3-2->S1-0!)
+      */
+     SiS_SetCH700x(SiS_Pr,0x2801);
+
+     /* Set video bandwidth
+            High bandwith Luma composite video filter(S0=1)
+            low bandwith Luma S-video filter (S2-1=00)
+	    disable peak filter in S-video channel (S3=0)
+	    high bandwidth Chroma Filter (S5-4=11)
+	    =00110001=0x31
+     */
+     SiS_SetCH700x(SiS_Pr,0xb103);       /* old: 3103 */
+
+     /* Register 0x3D does not exist in non-macrovision register map
+            (Maybe this is a macrovision register?)
+      */
+#ifndef SIS_CP
+     SiS_SetCH70xx(SiS_Pr,0x003D);
+#endif
+
+     /* Register 0x10 only contains 1 writable bit (S0) for sensing,
+            all other bits a read-only. Macrovision?
+      */
+     SiS_SetCH70xxANDOR(SiS_Pr,0x0010,0x1F);
+
+     /* Register 0x11 only contains 3 writable bits (S0-S2) for
+            contrast enhancement (set to 010 -> gain 1 Yout = 17/16*(Yin-30) )
+      */
+     SiS_SetCH70xxANDOR(SiS_Pr,0x0211,0xF8);
+
+     /* Clear DSEN
+      */
+     SiS_SetCH70xxANDOR(SiS_Pr,0x001C,0xEF);
+
+     if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) {		/* ---- NTSC ---- */
+       if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) {
+         if(resindex == 0x04) {   			/* 640x480 overscan: Mode 16 */
+      	   SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF);   	/* loop filter off */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE);      /* ACIV on, no need to set FSCI */
+         } else if(resindex == 0x05) {    		/* 800x600 overscan: Mode 23 */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0118,0xF0);	/* 0x18-0x1f: FSCI 469,762,048 */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0C19,0xF0);
+           SiS_SetCH70xxANDOR(SiS_Pr,0x001A,0xF0);
+           SiS_SetCH70xxANDOR(SiS_Pr,0x001B,0xF0);
+           SiS_SetCH70xxANDOR(SiS_Pr,0x001C,0xF0);
+           SiS_SetCH70xxANDOR(SiS_Pr,0x001D,0xF0);
+           SiS_SetCH70xxANDOR(SiS_Pr,0x001E,0xF0);
+           SiS_SetCH70xxANDOR(SiS_Pr,0x001F,0xF0);
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0120,0xEF);       /* Loop filter on for mode 23 */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0021,0xFE);       /* ACIV off, need to set FSCI */
+         }
+       } else {
+         if(resindex == 0x04) {     			 /* ----- 640x480 underscan; Mode 17 */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF); 	 /* loop filter off */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE);
+         } else if(resindex == 0x05) {   		 /* ----- 800x600 underscan: Mode 24 */
+#if 0
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0118,0xF0);       /* (FSCI was 0x1f1c71c7 - this is for mode 22) */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0919,0xF0);	 /* FSCI for mode 24 is 428,554,851 */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x081A,0xF0);       /* 198b3a63 */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0b1B,0xF0);
+           SiS_SetCH70xxANDOR(SiS_Pr,0x041C,0xF0);
+           SiS_SetCH70xxANDOR(SiS_Pr,0x011D,0xF0);
+           SiS_SetCH70xxANDOR(SiS_Pr,0x061E,0xF0);
+           SiS_SetCH70xxANDOR(SiS_Pr,0x051F,0xF0);
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF);       /* loop filter off for mode 24 */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0021,0xFE);	 /* ACIV off, need to set FSCI */
+#endif     /* All alternatives wrong (datasheet wrong?), don't use FSCI */
+	   SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF); 	 /* loop filter off */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE);
+         }
+       }
+     } else {						/* ---- PAL ---- */
+           /* We don't play around with FSCI in PAL mode */
+         if(resindex == 0x04) {
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF); 	/* loop filter off */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE);      /* ACIV on */
+         } else {
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF); 	/* loop filter off */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE);      /* ACIV on */
+         }
+     }
+     
+#endif  /* 300 */
+
+  } else {
+
+     /* Chrontel 7019 - assumed that it does not come with a 300 series chip */
+
+#ifdef SIS315H
+
+     /* We don't support modes >1024x768 */
+     if (resindex > 6) return;
+
+     temp = CHTVRegData[resindex].Reg[0];
+     if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) {
+        temp |= 0x10;
+     }
+     tempbx=((temp & 0x00FF) << 8) | 0x00;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[1];
+     tempbx=((temp & 0x00FF) << 8) | 0x01;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[2];
+     tempbx=((temp & 0x00FF) << 8) | 0x02;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[3];
+     tempbx=((temp & 0x00FF) << 8) | 0x04;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[4];
+     tempbx=((temp & 0x00FF) << 8) | 0x03;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[5];
+     tempbx=((temp & 0x00FF) << 8) | 0x05;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[6];
+     tempbx=((temp & 0x00FF) << 8) | 0x06;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[7];
+     if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) {
+	temp = 0x66;
+     }
+     tempbx=((temp & 0x00FF) << 8) | 0x07;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[8];
+     tempbx=((temp & 0x00FF) << 8) | 0x08;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[9];
+     tempbx=((temp & 0x00FF) << 8) | 0x15;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[10];
+     tempbx=((temp & 0x00FF) << 8) | 0x1f;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[11];
+     tempbx=((temp & 0x00FF) << 8) | 0x0c;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[12];
+     tempbx=((temp & 0x00FF) << 8) | 0x0d;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[13];
+     tempbx=((temp & 0x00FF) << 8) | 0x0e;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[14];
+     tempbx=((temp & 0x00FF) << 8) | 0x0f;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[15];
+     tempbx=((temp & 0x00FF) << 8) | 0x10;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = SiS_GetCH701x(SiS_Pr,0x21) & ~0x02;
+     /* D1 should be set for PAL, PAL-N and NTSC-J,
+        but I won't do that for PAL unless somebody
+	tells me to do so. Since the BIOS uses
+	non-default CIV values and blacklevels,
+	this might be compensated anyway.
+      */
+     if(SiS_Pr->SiS_TVMode & (TVSetPALN | TVSetNTSCJ)) temp |= 0x02;
+     SiS_SetCH701x(SiS_Pr,((temp << 8) | 0x21));
+
+#endif	/* 315 */
+
+  }
+
+#ifdef SIS_CP
+  SIS_CP_INIT301_CP3
+#endif
+
+}
+
+void
+SiS_Chrontel701xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  USHORT temp;
+
+  /* Enable Chrontel 7019 LCD panel backlight */
+  if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+     if(HwInfo->jChipType == SIS_740) {
+        SiS_SetCH701x(SiS_Pr,0x6566);
+     } else {
+        temp = SiS_GetCH701x(SiS_Pr,0x66);
+        temp |= 0x20;
+	SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x66);
+     }
+  }
+}
+
+void
+SiS_Chrontel701xBLOff(SiS_Private *SiS_Pr)
+{
+  USHORT temp;
+
+  /* Disable Chrontel 7019 LCD panel backlight */
+  if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+     temp = SiS_GetCH701x(SiS_Pr,0x66);
+     temp &= 0xDF;
+     SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x66);
+  }
+}
+
+#ifdef SIS315H  /* ----------- 315 series only ---------- */
+
+static void
+SiS_ChrontelPowerSequencing(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  UCHAR regtable[]      = { 0x67, 0x68, 0x69, 0x6a, 0x6b };
+  UCHAR table1024_740[] = { 0x01, 0x02, 0x01, 0x01, 0x01 };
+  UCHAR table1400_740[] = { 0x01, 0x6e, 0x01, 0x01, 0x01 };
+  UCHAR asus1024_740[]  = { 0x19, 0x6e, 0x01, 0x19, 0x09 };
+  UCHAR asus1400_740[]  = { 0x19, 0x6e, 0x01, 0x19, 0x09 };
+  UCHAR table1024_650[] = { 0x01, 0x02, 0x01, 0x01, 0x02 };
+  UCHAR table1400_650[] = { 0x01, 0x02, 0x01, 0x01, 0x02 };
+  UCHAR *tableptr = NULL;
+  int i;
+
+  /* Set up Power up/down timing */
+
+  if(HwInfo->jChipType == SIS_740) {
+     if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+        if(SiS_Pr->SiS_CustomT == CUT_ASUSL3000D) tableptr = asus1024_740;
+        else    			          tableptr = table1024_740;
+     } else if((SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) ||
+               (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) ||
+	       (SiS_Pr->SiS_LCDResInfo == Panel_1600x1200)) {
+	if(SiS_Pr->SiS_CustomT == CUT_ASUSL3000D) tableptr = asus1400_740;
+        else					  tableptr = table1400_740;
+     } else return;
+  } else {
+     if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+        tableptr = table1024_650;
+     } else if((SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) ||
+               (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) ||
+	       (SiS_Pr->SiS_LCDResInfo == Panel_1600x1200)) {
+        tableptr = table1400_650;
+     } else return;
+  }
+
+  for(i=0; i<5; i++) {
+     SiS_SetCH701x(SiS_Pr,(tableptr[i] << 8) | regtable[i]);
+  }
+}
+
+static void
+SiS_SetCH701xForLCD(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  UCHAR regtable[]      = { 0x1c, 0x5f, 0x64, 0x6f, 0x70, 0x71,
+                            0x72, 0x73, 0x74, 0x76, 0x78, 0x7d, 0x66 };
+  UCHAR table1024_740[] = { 0x60, 0x02, 0x00, 0x07, 0x40, 0xed,
+                            0xa3, 0xc8, 0xc7, 0xac, 0xe0, 0x02, 0x44 };
+  UCHAR table1280_740[] = { 0x60, 0x03, 0x11, 0x00, 0x40, 0xe3,
+   			    0xad, 0xdb, 0xf6, 0xac, 0xe0, 0x02, 0x44 };
+  UCHAR table1400_740[] = { 0x60, 0x03, 0x11, 0x00, 0x40, 0xe3,
+                            0xad, 0xdb, 0xf6, 0xac, 0xe0, 0x02, 0x44 };
+  UCHAR table1600_740[] = { 0x60, 0x04, 0x11, 0x00, 0x40, 0xe3,
+  			    0xad, 0xde, 0xf6, 0xac, 0x60, 0x1a, 0x44 };
+  UCHAR table1024_650[] = { 0x60, 0x02, 0x00, 0x07, 0x40, 0xed,
+                            0xa3, 0xc8, 0xc7, 0xac, 0x60, 0x02 };
+  UCHAR table1280_650[] = { 0x60, 0x03, 0x11, 0x00, 0x40, 0xe3,
+   		   	    0xad, 0xdb, 0xf6, 0xac, 0xe0, 0x02 };
+  UCHAR table1400_650[] = { 0x60, 0x03, 0x11, 0x00, 0x40, 0xef,
+                            0xad, 0xdb, 0xf6, 0xac, 0x60, 0x02 };
+  UCHAR table1600_650[] = { 0x60, 0x04, 0x11, 0x00, 0x40, 0xe3,
+  			    0xad, 0xde, 0xf6, 0xac, 0x60, 0x1a };
+  UCHAR *tableptr = NULL;
+  USHORT tempbh;
+  int i;
+
+  if(HwInfo->jChipType == SIS_740) {
+     if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768)       tableptr = table1024_740;
+     else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) tableptr = table1280_740;
+     else if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) tableptr = table1400_740;
+     else if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) tableptr = table1600_740;
+     else return;
+  } else {
+     if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768)       tableptr = table1024_650;
+     else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) tableptr = table1280_650;
+     else if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) tableptr = table1400_650;
+     else if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) tableptr = table1600_650;
+     else return;
+  }
+
+  tempbh = SiS_GetCH701x(SiS_Pr,0x74);
+  if((tempbh == 0xf6) || (tempbh == 0xc7)) {
+     tempbh = SiS_GetCH701x(SiS_Pr,0x73);
+     if(tempbh == 0xc8) {
+        if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) return;
+     } else if(tempbh == 0xdb) {
+        if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) return;
+	if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) return;
+     } else if(tempbh == 0xde) {
+        if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) return;
+     }
+  }
+
+  if(HwInfo->jChipType == SIS_740) tempbh = 0x0d;
+  else     			   tempbh = 0x0c;
+
+  for(i = 0; i < tempbh; i++) {
+     SiS_SetCH701x(SiS_Pr,(tableptr[i] << 8) | regtable[i]);
+  }
+  SiS_ChrontelPowerSequencing(SiS_Pr,HwInfo);
+  tempbh = SiS_GetCH701x(SiS_Pr,0x1e);
+  tempbh |= 0xc0;
+  SiS_SetCH701x(SiS_Pr,(tempbh << 8) | 0x1e);
+
+  if(HwInfo->jChipType == SIS_740) {
+     tempbh = SiS_GetCH701x(SiS_Pr,0x1c);
+     tempbh &= 0xfb;
+     SiS_SetCH701x(SiS_Pr,(tempbh << 8) | 0x1c);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2d,0x03);
+     tempbh = SiS_GetCH701x(SiS_Pr,0x64);
+     tempbh |= 0x40;
+     SiS_SetCH701x(SiS_Pr,(tempbh << 8) | 0x64);
+     tempbh = SiS_GetCH701x(SiS_Pr,0x03);
+     tempbh &= 0x3f;
+     SiS_SetCH701x(SiS_Pr,(tempbh << 8) | 0x03);
+  }
+}
+
+static void
+SiS_ChrontelResetVSync(SiS_Private *SiS_Pr)
+{
+  unsigned char temp, temp1;
+
+  temp1 = SiS_GetCH701x(SiS_Pr,0x49);
+  SiS_SetCH701x(SiS_Pr,0x3e49);
+  temp = SiS_GetCH701x(SiS_Pr,0x47);
+  temp &= 0x7f;	/* Use external VSYNC */
+  SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47);
+  SiS_LongDelay(SiS_Pr,3);
+  temp = SiS_GetCH701x(SiS_Pr,0x47);
+  temp |= 0x80;	/* Use internal VSYNC */
+  SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47);
+  SiS_SetCH701x(SiS_Pr,(temp1 << 8) | 0x49);
+}
+
+static void
+SiS_Chrontel701xOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  USHORT temp;
+
+  if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+     if(HwInfo->jChipType == SIS_740) {
+        temp = SiS_GetCH701x(SiS_Pr,0x1c);
+        temp |= 0x04;	/* Invert XCLK phase */
+        SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x1c);
+     }
+     if(SiS_IsYPbPr(SiS_Pr, HwInfo)) {
+        temp = SiS_GetCH701x(SiS_Pr,0x01);
+	temp &= 0x3f;
+	temp |= 0x80;	/* Enable YPrPb (HDTV) */
+	SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x01);
+     }
+     if(SiS_IsChScart(SiS_Pr, HwInfo)) {
+        temp = SiS_GetCH701x(SiS_Pr,0x01);
+	temp &= 0x3f;
+	temp |= 0xc0;	/* Enable SCART + CVBS */
+	SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x01);
+     }
+     if(HwInfo->jChipType == SIS_740) {
+        SiS_ChrontelResetVSync(SiS_Pr);
+        SiS_SetCH701x(SiS_Pr,0x2049);   /* Enable TV path */
+     } else {
+        SiS_SetCH701x(SiS_Pr,0x2049);   /* Enable TV path */
+        temp = SiS_GetCH701x(SiS_Pr,0x49);
+        if(SiS_IsYPbPr(SiS_Pr,HwInfo)) {
+           temp = SiS_GetCH701x(SiS_Pr,0x73);
+	   temp |= 0x60;
+	   SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x73);
+        }
+        temp = SiS_GetCH701x(SiS_Pr,0x47);
+        temp &= 0x7f;
+        SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47);
+        SiS_LongDelay(SiS_Pr,2);
+        temp = SiS_GetCH701x(SiS_Pr,0x47);
+        temp |= 0x80;
+        SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47);
+     }
+  }
+}
+
+static void
+SiS_Chrontel701xOff(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  USHORT temp;
+
+  /* Complete power down of LVDS */
+  if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+     if(HwInfo->jChipType == SIS_740) {
+        SiS_LongDelay(SiS_Pr,1);
+	SiS_GenericDelay(SiS_Pr,0x16ff);
+	SiS_SetCH701x(SiS_Pr,0xac76);
+	SiS_SetCH701x(SiS_Pr,0x0066);
+     } else {
+        SiS_LongDelay(SiS_Pr,2);
+	temp = SiS_GetCH701x(SiS_Pr,0x76);
+	temp &= 0xfc;
+	SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x76);
+	SiS_SetCH701x(SiS_Pr,0x0066);
+     }
+  }
+}
+
+static void
+SiS_ChrontelResetDB(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+     USHORT temp;
+
+     if(HwInfo->jChipType == SIS_740) {
+
+        temp = SiS_GetCH701x(SiS_Pr,0x4a);  /* Version ID */
+        temp &= 0x01;
+        if(!temp) {
+
+           if(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo)) {
+	      temp = SiS_GetCH701x(SiS_Pr,0x49);
+	      SiS_SetCH701x(SiS_Pr,0x3e49);
+	   }
+	   /* Reset Chrontel 7019 datapath */
+           SiS_SetCH701x(SiS_Pr,0x1048);
+           SiS_LongDelay(SiS_Pr,1);
+           SiS_SetCH701x(SiS_Pr,0x1848);
+
+	   if(SiS_WeHaveBacklightCtrl(SiS_Pr, HwInfo)) {
+	      SiS_ChrontelResetVSync(SiS_Pr);
+	      SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x49);
+	   }
+
+        } else {
+
+	   /* Clear/set/clear GPIO */
+           temp = SiS_GetCH701x(SiS_Pr,0x5c);
+	   temp &= 0xef;
+	   SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x5c);
+	   temp = SiS_GetCH701x(SiS_Pr,0x5c);
+	   temp |= 0x10;
+	   SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x5c);
+	   temp = SiS_GetCH701x(SiS_Pr,0x5c);
+	   temp &= 0xef;
+	   SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x5c);
+	   temp = SiS_GetCH701x(SiS_Pr,0x61);
+	   if(!temp) {
+	      SiS_SetCH701xForLCD(SiS_Pr, HwInfo);
+	   }
+        }
+
+     } else { /* 650 */
+        /* Reset Chrontel 7019 datapath */
+        SiS_SetCH701x(SiS_Pr,0x1048);
+        SiS_LongDelay(SiS_Pr,1);
+        SiS_SetCH701x(SiS_Pr,0x1848);
+     }
+}
+
+static void
+SiS_ChrontelInitTVVSync(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+     USHORT temp;
+
+     if(HwInfo->jChipType == SIS_740) {
+
+        if(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo)) {
+           SiS_ChrontelResetVSync(SiS_Pr);
+        }
+
+     } else {
+
+        SiS_SetCH701x(SiS_Pr,0xaf76);  /* Power up LVDS block */
+        temp = SiS_GetCH701x(SiS_Pr,0x49);
+        temp &= 1;
+        if(temp != 1) {  /* TV block powered? (0 = yes, 1 = no) */
+	   temp = SiS_GetCH701x(SiS_Pr,0x47);
+	   temp &= 0x70;
+	   SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47);  /* enable VSYNC */
+	   SiS_LongDelay(SiS_Pr,3);
+	   temp = SiS_GetCH701x(SiS_Pr,0x47);
+	   temp |= 0x80;
+	   SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47);  /* disable VSYNC */
+        }
+
+     }
+}
+
+static void
+SiS_ChrontelDoSomething3(SiS_Private *SiS_Pr, USHORT ModeNo, PSIS_HW_INFO HwInfo)
+{
+     USHORT temp,temp1;
+
+     if(HwInfo->jChipType == SIS_740) {
+
+        temp = SiS_GetCH701x(SiS_Pr,0x61);
+        if(temp < 1) {
+           temp++;
+	   SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x61);
+        }
+        SiS_SetCH701x(SiS_Pr,0x4566);  /* Panel power on */
+        SiS_SetCH701x(SiS_Pr,0xaf76);  /* All power on */
+        SiS_LongDelay(SiS_Pr,1);
+        SiS_GenericDelay(SiS_Pr,0x16ff);
+
+     } else {  /* 650 */
+
+        temp1 = 0;
+        temp = SiS_GetCH701x(SiS_Pr,0x61);
+        if(temp < 2) {
+           temp++;
+	   SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x61);
+	   temp1 = 1;
+        }
+        SiS_SetCH701x(SiS_Pr,0xac76);
+        temp = SiS_GetCH701x(SiS_Pr,0x66);
+        temp |= 0x5f;
+        SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x66);
+        if(ModeNo > 0x13) {
+           if(SiS_WeHaveBacklightCtrl(SiS_Pr, HwInfo)) {
+	      SiS_GenericDelay(SiS_Pr,0x3ff);
+	   } else {
+	      SiS_GenericDelay(SiS_Pr,0x2ff);
+	   }
+        } else {
+           if(!temp1)
+	      SiS_GenericDelay(SiS_Pr,0x2ff);
+        }
+        temp = SiS_GetCH701x(SiS_Pr,0x76);
+        temp |= 0x03;
+        SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x76);
+        temp = SiS_GetCH701x(SiS_Pr,0x66);
+        temp &= 0x7f;
+        SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x66);
+        SiS_LongDelay(SiS_Pr,1);
+
+     }
+}
+
+static void
+SiS_ChrontelDoSomething2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+     USHORT temp,tempcl,tempch;
+
+     SiS_LongDelay(SiS_Pr, 1);
+     tempcl = 3;
+     tempch = 0;
+
+     do {
+       temp = SiS_GetCH701x(SiS_Pr,0x66);
+       temp &= 0x04;  /* PLL stable? -> bail out */
+       if(temp == 0x04) break;
+
+       if(HwInfo->jChipType == SIS_740) {
+          /* Power down LVDS output, PLL normal operation */
+          SiS_SetCH701x(SiS_Pr,0xac76);
+       }
+
+       SiS_SetCH701xForLCD(SiS_Pr,HwInfo);
+
+       if(tempcl == 0) {
+           if(tempch == 3) break;
+	   SiS_ChrontelResetDB(SiS_Pr,HwInfo);
+	   tempcl = 3;
+	   tempch++;
+       }
+       tempcl--;
+       temp = SiS_GetCH701x(SiS_Pr,0x76);
+       temp &= 0xfb;  /* Reset PLL */
+       SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x76);
+       SiS_LongDelay(SiS_Pr,2);
+       temp = SiS_GetCH701x(SiS_Pr,0x76);
+       temp |= 0x04;  /* PLL normal operation */
+       SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x76);
+       if(HwInfo->jChipType == SIS_740) {
+          SiS_SetCH701x(SiS_Pr,0xe078);	/* PLL loop filter */
+       } else {
+          SiS_SetCH701x(SiS_Pr,0x6078);
+       }
+       SiS_LongDelay(SiS_Pr,2);
+    } while(0);
+
+    SiS_SetCH701x(SiS_Pr,0x0077);  /* MV? */
+}
+
+static void
+SiS_ChrontelDoSomething1(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+     USHORT temp;
+
+     temp = SiS_GetCH701x(SiS_Pr,0x03);
+     temp |= 0x80;	/* Set datapath 1 to TV   */
+     temp &= 0xbf;	/* Set datapath 2 to LVDS */
+     SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x03);
+
+     if(HwInfo->jChipType == SIS_740) {
+
+        temp = SiS_GetCH701x(SiS_Pr,0x1c);
+        temp &= 0xfb;	/* Normal XCLK phase */
+        SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x1c);
+
+        SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2d,0x03);
+
+        temp = SiS_GetCH701x(SiS_Pr,0x64);
+        temp |= 0x40;	/* ? Bit not defined */
+        SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x64);
+
+        temp = SiS_GetCH701x(SiS_Pr,0x03);
+        temp &= 0x3f;	/* D1 input to both LVDS and TV */
+        SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x03);
+
+	if(SiS_Pr->SiS_CustomT == CUT_ASUSL3000D) {
+	   SiS_SetCH701x(SiS_Pr,0x4063); /* LVDS off */
+	   SiS_LongDelay(SiS_Pr, 1);
+	   SiS_SetCH701x(SiS_Pr,0x0063); /* LVDS on */
+	   SiS_ChrontelResetDB(SiS_Pr, HwInfo);
+	   SiS_ChrontelDoSomething2(SiS_Pr, HwInfo);
+	   SiS_ChrontelDoSomething3(SiS_Pr, 0, HwInfo);
+	} else {
+           temp = SiS_GetCH701x(SiS_Pr,0x66);
+           if(temp != 0x45) {
+              SiS_ChrontelResetDB(SiS_Pr, HwInfo);
+              SiS_ChrontelDoSomething2(SiS_Pr, HwInfo);
+              SiS_ChrontelDoSomething3(SiS_Pr, 0, HwInfo);
+           }
+	}
+
+     } else { /* 650 */
+
+        SiS_ChrontelResetDB(SiS_Pr,HwInfo);
+        SiS_ChrontelDoSomething2(SiS_Pr,HwInfo);
+        temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x34);
+        SiS_ChrontelDoSomething3(SiS_Pr,temp,HwInfo);
+        SiS_SetCH701x(SiS_Pr,0xaf76);  /* All power on, LVDS normal operation */
+
+     }
+
+}
+#endif  /* 315 series  */
+
+/*********************************************/
+/*      MAIN: SET CRT2 REGISTER GROUP        */
+/*********************************************/
+
+BOOLEAN
+SiS_SetCRT2Group(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo)
+{
+#ifdef SIS300
+   UCHAR  *ROMAddr  = HwInfo->pjVirtualRomBase;
+#endif
+   USHORT ModeIdIndex, RefreshRateTableIndex;
+#if 0
+   USHORT temp;
+#endif
+
+   SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
+
+   if(!SiS_Pr->UseCustomMode) {
+      SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex);
+   } else {
+      ModeIdIndex = 0;
+   }
+
+   /* Used for shifting CR33 */
+   SiS_Pr->SiS_SelectCRT2Rate = 4;
+
+   SiS_UnLockCRT2(SiS_Pr, HwInfo);
+
+   RefreshRateTableIndex = SiS_GetRatePtr(SiS_Pr, ModeNo, ModeIdIndex, HwInfo);
+
+   SiS_SaveCRT2Info(SiS_Pr,ModeNo);
+
+   if(SiS_Pr->SiS_SetFlag & LowModeTests) {
+      SiS_DisableBridge(SiS_Pr,HwInfo);
+      if((SiS_Pr->SiS_IF_DEF_LVDS == 1) && (HwInfo->jChipType == SIS_730)) {
+         SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,0x80);
+      }
+      SiS_SetCRT2ModeRegs(SiS_Pr, ModeNo, ModeIdIndex, HwInfo);
+   }
+
+   if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) {
+      SiS_LockCRT2(SiS_Pr, HwInfo);
+      SiS_DisplayOn(SiS_Pr);
+      return TRUE;
+   }
+
+   SiS_GetCRT2Data(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
+
+   /* Set up Panel Link for LVDS and LCDA */
+   SiS_Pr->SiS_LCDHDES = SiS_Pr->SiS_LCDVDES = 0;
+   if( (SiS_Pr->SiS_IF_DEF_LVDS == 1) ||
+       ((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) ||
+       ((HwInfo->jChipType >= SIS_315H) && (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) ) {
+      SiS_GetLVDSDesData(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
+   }
+
+#ifdef LINUX_XF86
+#ifdef TWDEBUG
+  xf86DrvMsg(0, X_INFO, "(init301: LCDHDES 0x%03x LCDVDES 0x%03x)\n", SiS_Pr->SiS_LCDHDES, SiS_Pr->SiS_LCDVDES);
+  xf86DrvMsg(0, X_INFO, "(init301: HDE     0x%03x VDE     0x%03x)\n", SiS_Pr->SiS_HDE, SiS_Pr->SiS_VDE);
+  xf86DrvMsg(0, X_INFO, "(init301: VGAHDE  0x%03x VGAVDE  0x%03x)\n", SiS_Pr->SiS_VGAHDE, SiS_Pr->SiS_VGAVDE);
+  xf86DrvMsg(0, X_INFO, "(init301: HT      0x%03x VT      0x%03x)\n", SiS_Pr->SiS_HT, SiS_Pr->SiS_VT);
+  xf86DrvMsg(0, X_INFO, "(init301: VGAHT   0x%03x VGAVT   0x%03x)\n", SiS_Pr->SiS_VGAHT, SiS_Pr->SiS_VGAVT);
+#endif
+#endif
+
+   if(SiS_Pr->SiS_SetFlag & LowModeTests) {
+      SiS_SetGroup1(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex);
+   }
+
+   if(SiS_Pr->SiS_VBType & VB_SISVB) {
+
+        if(SiS_Pr->SiS_SetFlag & LowModeTests) {
+
+	   SiS_SetGroup2(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
+#ifdef SIS315H
+	   SiS_SetGroup2_C_ELV(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
+#endif
+      	   SiS_SetGroup3(SiS_Pr, ModeNo, ModeIdIndex, HwInfo);
+      	   SiS_SetGroup4(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
+#ifdef SIS315H
+	   SiS_SetGroup4_C_ELV(SiS_Pr, HwInfo, ModeNo, ModeIdIndex);
+#endif
+      	   SiS_SetGroup5(SiS_Pr, ModeNo, ModeIdIndex, HwInfo);
+
+	   SiS_SetCRT2Sync(SiS_Pr, ModeNo, RefreshRateTableIndex, HwInfo);
+
+	   /* For 301BDH (Panel link initialization): */
+	   if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
+	      if(SiS_Pr->SiS_LCDResInfo != Panel_640x480) {
+		 if(!((SiS_Pr->SiS_SetFlag & SetDOSMode) && ((ModeNo == 0x03) || (ModeNo == 0x10)))) {
+		    if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+		       SiS_ModCRT1CRTC(SiS_Pr,ModeNo,ModeIdIndex,
+		                       RefreshRateTableIndex,HwInfo);
+		    }
+                 }
+	      }
+	      SiS_SetCRT2ECLK(SiS_Pr,ModeNo,ModeIdIndex,
+		              RefreshRateTableIndex,HwInfo);
+	   }
+        }
+
+   } else {
+
+        SiS_SetCRT2Sync(SiS_Pr, ModeNo, RefreshRateTableIndex, HwInfo);
+
+        if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
+    	   SiS_ModCRT1CRTC(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex,HwInfo);
+	}
+
+        SiS_SetCRT2ECLK(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex,HwInfo);
+
+	if(SiS_Pr->SiS_SetFlag & LowModeTests) {
+     	   if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+	      if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+	         if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+#ifdef SIS315H
+		    SiS_SetCH701xForLCD(SiS_Pr,HwInfo);
+#endif
+		 }
+	      }
+	      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+       		 SiS_SetCHTVReg(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex);
+	      }
+     	   }
+	}
+
+   }
+
+#ifdef SIS300
+   if(HwInfo->jChipType < SIS_315H) {
+      if(SiS_Pr->SiS_SetFlag & LowModeTests) {
+	 if(SiS_Pr->SiS_UseOEM) {
+	    if((SiS_Pr->SiS_UseROM) && (SiS_Pr->SiS_UseOEM == -1)) {
+	       if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) {
+	          SiS_OEM300Setting(SiS_Pr,HwInfo,ModeNo,ModeIdIndex,
+	       			    RefreshRateTableIndex);
+	       }
+	    } else {
+       	       SiS_OEM300Setting(SiS_Pr,HwInfo,ModeNo,ModeIdIndex,
+	       			 RefreshRateTableIndex);
+	    }
+	 }
+	 if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+            if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) ||
+	       (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) {
+	       SetOEMLCDData2(SiS_Pr, HwInfo, ModeNo, ModeIdIndex,RefreshRateTableIndex);
+	    }
+	    SiS_DisplayOn(SiS_Pr);
+         }
+      }
+   }
+#endif
+
+#ifdef SIS315H
+   if(HwInfo->jChipType >= SIS_315H) {
+      if(SiS_Pr->SiS_SetFlag & LowModeTests) {
+	 if(HwInfo->jChipType < SIS_661) {
+	    SiS_FinalizeLCD(SiS_Pr, ModeNo, ModeIdIndex, HwInfo);
+            SiS_OEM310Setting(SiS_Pr, HwInfo, ModeNo, ModeIdIndex, RefreshRateTableIndex);
+	 } else {
+	    SiS_OEM661Setting(SiS_Pr, HwInfo, ModeNo, ModeIdIndex, RefreshRateTableIndex);
+	 }
+         SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x40);
+      }
+   }
+#endif
+
+   if(SiS_Pr->SiS_SetFlag & LowModeTests) {
+      SiS_EnableBridge(SiS_Pr, HwInfo);
+   }
+
+   SiS_DisplayOn(SiS_Pr);
+
+   if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+	 /* Disable LCD panel when using TV */
+	 SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFF,0x0C);
+      } else {
+	 /* Disable TV when using LCD */
+	 SiS_SetCH70xxANDOR(SiS_Pr,0x010E,0xF8);
+      }
+   }
+
+   if(SiS_Pr->SiS_SetFlag & LowModeTests) {
+      SiS_LockCRT2(SiS_Pr,HwInfo);
+   }
+
+   return TRUE;
+}
+
+
+/*********************************************/
+/*     ENABLE/DISABLE LCD BACKLIGHT (SIS)    */
+/*********************************************/
+
+void
+SiS_SiS30xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  /* Switch on LCD backlight on SiS30xLV */
+  SiS_DDC2Delay(SiS_Pr,0xff00);
+  if(!(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x26) & 0x02)) {
+     SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02);
+     SiS_WaitVBRetrace(SiS_Pr,HwInfo);
+  }
+  if(!(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x26) & 0x01)) {
+     SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x01);
+  }
+}
+
+void
+SiS_SiS30xBLOff(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  /* Switch off LCD backlight on SiS30xLV */
+  SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFE);
+  SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD);
+  SiS_DDC2Delay(SiS_Pr,0xe000);
+}
+
+/*********************************************/
+/*          DDC RELATED FUNCTIONS            */
+/*********************************************/
+
+static void
+SiS_SetupDDCN(SiS_Private *SiS_Pr)
+{
+  SiS_Pr->SiS_DDC_NData = ~SiS_Pr->SiS_DDC_Data;
+  SiS_Pr->SiS_DDC_NClk  = ~SiS_Pr->SiS_DDC_Clk;
+  if((SiS_Pr->SiS_DDC_Index == 0x11) && (SiS_Pr->SiS_SensibleSR11)) {
+     SiS_Pr->SiS_DDC_NData &= 0x0f;
+     SiS_Pr->SiS_DDC_NClk  &= 0x0f;
+  }
+}
+
+#ifdef SIS300
+static UCHAR *
+SiS_SetTrumpBlockLoop(SiS_Private *SiS_Pr, UCHAR *dataptr)
+{
+  int i, j, num;
+  USHORT tempah,temp;
+  UCHAR *mydataptr;
+
+  for(i=0; i<20; i++) {				/* Do 20 attempts to write */
+     mydataptr = dataptr;
+     num = *mydataptr++;
+     if(!num) return mydataptr;
+     if(i) {
+        SiS_SetStop(SiS_Pr);
+	SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT*2);
+     }
+     if(SiS_SetStart(SiS_Pr)) continue;		/* Set start condition */
+     tempah = SiS_Pr->SiS_DDC_DeviceAddr;
+     temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* Write DAB (S0=0=write) */
+     if(temp) continue;				/*    (ERROR: no ack) */
+     tempah = *mydataptr++;
+     temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* Write register number */
+     if(temp) continue;				/*    (ERROR: no ack) */
+     for(j=0; j<num; j++) {
+        tempah = *mydataptr++;
+        temp = SiS_WriteDDC2Data(SiS_Pr,tempah);/* Write DAB (S0=0=write) */
+	if(temp) break;
+     }
+     if(temp) continue;
+     if(SiS_SetStop(SiS_Pr)) continue;
+     return mydataptr;
+  }
+  return NULL;
+}
+
+static BOOLEAN
+SiS_SetTrumpionBlock(SiS_Private *SiS_Pr, UCHAR *dataptr)
+{
+  SiS_Pr->SiS_DDC_DeviceAddr = 0xF0;  		/* DAB (Device Address Byte) */
+  SiS_Pr->SiS_DDC_Index = 0x11;			/* Bit 0 = SC;  Bit 1 = SD */
+  SiS_Pr->SiS_DDC_Data  = 0x02;              	/* Bitmask in IndexReg for Data */
+  SiS_Pr->SiS_DDC_Clk   = 0x01;              	/* Bitmask in IndexReg for Clk */
+  SiS_SetupDDCN(SiS_Pr);
+
+  SiS_SetSwitchDDC2(SiS_Pr);
+
+  while(*dataptr) {
+     dataptr = SiS_SetTrumpBlockLoop(SiS_Pr, dataptr);
+     if(!dataptr) return FALSE;
+  }
+#ifdef TWDEBUG
+  xf86DrvMsg(0, X_INFO, "Trumpion block success\n");
+#endif
+  return TRUE;
+}
+#endif
+
+/* The Chrontel 700x is connected to the 630/730 via
+ * the 630/730's DDC/I2C port.
+ *
+ * On 630(S)T chipset, the index changed from 0x11 to
+ * 0x0a, possibly for working around the DDC problems
+ */
+
+static BOOLEAN
+SiS_SetChReg(SiS_Private *SiS_Pr, USHORT tempbx, USHORT myor)
+{
+  USHORT tempah,temp,i;
+
+  for(i=0; i<20; i++) {				/* Do 20 attempts to write */
+     if(i) {
+        SiS_SetStop(SiS_Pr);
+	SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT);
+     }
+     if(SiS_SetStart(SiS_Pr)) continue;		/* Set start condition */
+     tempah = SiS_Pr->SiS_DDC_DeviceAddr;
+     temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* Write DAB (S0=0=write) */
+     if(temp) continue;				/*    (ERROR: no ack) */
+     tempah = tempbx & 0x00FF;			/* Write RAB */
+     tempah |= myor;                            /* (700x: set bit 7, see datasheet) */
+     temp = SiS_WriteDDC2Data(SiS_Pr,tempah);
+     if(temp) continue;				/*    (ERROR: no ack) */
+     tempah = (tempbx & 0xFF00) >> 8;
+     temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* Write data */
+     if(temp) continue;				/*    (ERROR: no ack) */
+     if(SiS_SetStop(SiS_Pr)) continue;		/* Set stop condition */
+     SiS_Pr->SiS_ChrontelInit = 1;
+     return TRUE;
+  }
+  return FALSE;
+}
+
+#if 0
+#ifdef SIS300
+/* Write Trumpion register */
+static void
+SiS_SetTrumpReg(SiS_Private *SiS_Pr, USHORT tempbx)
+{
+  SiS_Pr->SiS_DDC_DeviceAddr = 0xF0;  		/* DAB (Device Address Byte) */
+  SiS_Pr->SiS_DDC_Index = 0x11;			/* Bit 0 = SC;  Bit 1 = SD */
+  SiS_Pr->SiS_DDC_Data  = 0x02;              	/* Bitmask in IndexReg for Data */
+  SiS_Pr->SiS_DDC_Clk   = 0x01;              	/* Bitmask in IndexReg for Clk */
+  SiS_SetupDDCN(SiS_Pr);
+  SiS_SetChReg(SiS_Pr, tempbx, 0);
+}
+#endif
+#endif
+
+/* Write to Chrontel 700x */
+/* Parameter is [Data (S15-S8) | Register no (S7-S0)] */
+void
+SiS_SetCH700x(SiS_Private *SiS_Pr, USHORT tempbx)
+{
+  SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;  		/* DAB (Device Address Byte) */
+
+  if(!(SiS_Pr->SiS_ChrontelInit)) {
+     SiS_Pr->SiS_DDC_Index = 0x11;		/* Bit 0 = SC;  Bit 1 = SD */
+     SiS_Pr->SiS_DDC_Data  = 0x02;              /* Bitmask in IndexReg for Data */
+     SiS_Pr->SiS_DDC_Clk   = 0x01;              /* Bitmask in IndexReg for Clk */
+     SiS_SetupDDCN(SiS_Pr);
+  }
+
+  if( (!(SiS_SetChReg(SiS_Pr, tempbx, 0x80))) &&
+      (!(SiS_Pr->SiS_ChrontelInit)) ) {
+     SiS_Pr->SiS_DDC_Index = 0x0a;		/* Bit 7 = SC;  Bit 6 = SD */
+     SiS_Pr->SiS_DDC_Data  = 0x80;              /* Bitmask in IndexReg for Data */
+     SiS_Pr->SiS_DDC_Clk   = 0x40;              /* Bitmask in IndexReg for Clk */
+     SiS_SetupDDCN(SiS_Pr);
+
+     SiS_SetChReg(SiS_Pr, tempbx, 0x80);
+  }
+}
+
+/* Write to Chrontel 701x */
+/* Parameter is [Data (S15-S8) | Register no (S7-S0)] */
+void
+SiS_SetCH701x(SiS_Private *SiS_Pr, USHORT tempbx)
+{
+  SiS_Pr->SiS_DDC_Index = 0x11;			/* Bit 0 = SC;  Bit 1 = SD */
+  SiS_Pr->SiS_DDC_Data  = 0x08;                 /* Bitmask in IndexReg for Data */
+  SiS_Pr->SiS_DDC_Clk   = 0x04;                 /* Bitmask in IndexReg for Clk */
+  SiS_SetupDDCN(SiS_Pr);
+  SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;  		/* DAB (Device Address Byte) */
+  SiS_SetChReg(SiS_Pr, tempbx, 0);
+}
+
+void
+SiS_SetCH70xx(SiS_Private *SiS_Pr, USHORT tempbx)
+{
+  if(SiS_Pr->SiS_IF_DEF_CH70xx == 1)
+     SiS_SetCH700x(SiS_Pr,tempbx);
+  else
+     SiS_SetCH701x(SiS_Pr,tempbx);
+}
+
+static USHORT
+SiS_GetChReg(SiS_Private *SiS_Pr, USHORT myor)
+{
+  USHORT tempah,temp,i;
+
+  for(i=0; i<20; i++) {				/* Do 20 attempts to read */
+     if(i) {
+        SiS_SetStop(SiS_Pr);
+	SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT);
+     }
+     if(SiS_SetStart(SiS_Pr)) continue;		/* Set start condition */
+     tempah = SiS_Pr->SiS_DDC_DeviceAddr;
+     temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* Write DAB (S0=0=write) */
+     if(temp) continue;				/*        (ERROR: no ack) */
+     tempah = SiS_Pr->SiS_DDC_ReadAddr | myor;	/* Write RAB (700x: | 0x80) */
+     temp = SiS_WriteDDC2Data(SiS_Pr,tempah);
+     if(temp) continue;				/*        (ERROR: no ack) */
+     if (SiS_SetStart(SiS_Pr)) continue;	/* Re-start */
+     tempah = SiS_Pr->SiS_DDC_DeviceAddr | 0x01;/* DAB | 0x01 = Read */
+     temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* DAB (S0=1=read) */
+     if(temp) continue;				/*        (ERROR: no ack) */
+     tempah = SiS_ReadDDC2Data(SiS_Pr,tempah);	/* Read byte */
+     if(SiS_SetStop(SiS_Pr)) continue;		/* Stop condition */
+     SiS_Pr->SiS_ChrontelInit = 1;
+     return(tempah);
+  }
+  return 0xFFFF;
+}
+
+#if 0
+#ifdef SIS300
+/* Read from Trumpion */
+static USHORT
+SiS_GetTrumpReg(SiS_Private *SiS_Pr, USHORT tempbx)
+{
+  SiS_Pr->SiS_DDC_DeviceAddr = 0xF0;	/* DAB */
+  SiS_Pr->SiS_DDC_Index = 0x11;		/* Bit 0 = SC;  Bit 1 = SD */
+  SiS_Pr->SiS_DDC_Data  = 0x02;         /* Bitmask in IndexReg for Data */
+  SiS_Pr->SiS_DDC_Clk   = 0x01;         /* Bitmask in IndexReg for Clk */
+  SiS_SetupDDCN(SiS_Pr);
+  SiS_Pr->SiS_DDC_ReadAddr = tempbx;
+  return(SiS_GetChReg(SiS_Pr,0));
+}
+#endif
+#endif
+
+/* Read from Chrontel 700x */
+/* Parameter is [Register no (S7-S0)] */
+USHORT
+SiS_GetCH700x(SiS_Private *SiS_Pr, USHORT tempbx)
+{
+  USHORT result;
+
+  SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;		/* DAB */
+
+  if(!(SiS_Pr->SiS_ChrontelInit)) {
+     SiS_Pr->SiS_DDC_Index = 0x11;		/* Bit 0 = SC;  Bit 1 = SD */
+     SiS_Pr->SiS_DDC_Data  = 0x02;              /* Bitmask in IndexReg for Data */
+     SiS_Pr->SiS_DDC_Clk   = 0x01;              /* Bitmask in IndexReg for Clk */
+     SiS_SetupDDCN(SiS_Pr);
+  }
+
+  SiS_Pr->SiS_DDC_ReadAddr = tempbx;
+
+  if( ((result = SiS_GetChReg(SiS_Pr,0x80)) == 0xFFFF) &&
+      (!SiS_Pr->SiS_ChrontelInit) ) {
+
+     SiS_Pr->SiS_DDC_Index = 0x0a;
+     SiS_Pr->SiS_DDC_Data  = 0x80;
+     SiS_Pr->SiS_DDC_Clk   = 0x40;
+     SiS_SetupDDCN(SiS_Pr);
+
+     result = SiS_GetChReg(SiS_Pr,0x80);
+  }
+  return(result);
+}
+
+/* Read from Chrontel 701x */
+/* Parameter is [Register no (S7-S0)] */
+USHORT
+SiS_GetCH701x(SiS_Private *SiS_Pr, USHORT tempbx)
+{
+  SiS_Pr->SiS_DDC_Index = 0x11;			/* Bit 0 = SC;  Bit 1 = SD */
+  SiS_Pr->SiS_DDC_Data  = 0x08;                 /* Bitmask in IndexReg for Data */
+  SiS_Pr->SiS_DDC_Clk   = 0x04;                 /* Bitmask in IndexReg for Clk */
+  SiS_SetupDDCN(SiS_Pr);
+  SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;		/* DAB */
+
+  SiS_Pr->SiS_DDC_ReadAddr = tempbx;
+
+  return(SiS_GetChReg(SiS_Pr,0));
+}
+
+/* Read from Chrontel 70xx */
+/* Parameter is [Register no (S7-S0)] */
+USHORT
+SiS_GetCH70xx(SiS_Private *SiS_Pr, USHORT tempbx)
+{
+  if(SiS_Pr->SiS_IF_DEF_CH70xx == 1)
+     return(SiS_GetCH700x(SiS_Pr, tempbx));
+  else
+     return(SiS_GetCH701x(SiS_Pr, tempbx));
+}
+
+/* Our own DDC functions */
+static USHORT
+SiS_InitDDCRegs(SiS_Private *SiS_Pr, unsigned long VBFlags, int VGAEngine,
+                USHORT adaptnum, USHORT DDCdatatype, BOOLEAN checkcr32)
+{
+     unsigned char ddcdtype[] = { 0xa0, 0xa0, 0xa0, 0xa2, 0xa6 };
+     unsigned char flag, cr32;
+     USHORT        temp = 0, myadaptnum = adaptnum;
+
+     if(adaptnum != 0) {
+        if(!(VBFlags & (VB_301|VB_301B|VB_301C|VB_302B))) return 0xFFFF;
+	if((VBFlags & VB_30xBDH) && (adaptnum == 1)) return 0xFFFF;
+     }	
+     
+     /* adapternum for SiS bridges: 0 = CRT1, 1 = LCD, 2 = VGA2 */
+     
+     SiS_Pr->SiS_ChrontelInit = 0;   /* force re-detection! */
+
+     SiS_Pr->SiS_DDC_SecAddr = 0;
+     SiS_Pr->SiS_DDC_DeviceAddr = ddcdtype[DDCdatatype];
+     SiS_Pr->SiS_DDC_Port = SiS_Pr->SiS_P3c4;
+     SiS_Pr->SiS_DDC_Index = 0x11;
+     flag = 0xff;
+
+     cr32 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x32);
+
+#if 0
+     if(VBFlags & VB_SISBRIDGE) {
+	if(myadaptnum == 0) {
+	   if(!(cr32 & 0x20)) {
+	      myadaptnum = 2;
+	      if(!(cr32 & 0x10)) {
+	         myadaptnum = 1;
+		 if(!(cr32 & 0x08)) {
+		    myadaptnum = 0;
+		 }
+	      }
+	   }
+        }
+     }
+#endif
+
+     if(VGAEngine == SIS_300_VGA) {		/* 300 series */
+	
+        if(myadaptnum != 0) {
+	   flag = 0;
+	   if(VBFlags & VB_SISBRIDGE) {
+	      SiS_Pr->SiS_DDC_Port = SiS_Pr->SiS_Part4Port;
+              SiS_Pr->SiS_DDC_Index = 0x0f;
+	   }
+        }
+
+	if(!(VBFlags & VB_301)) {
+	   if((cr32 & 0x80) && (checkcr32)) {
+              if(myadaptnum >= 1) {
+	         if(!(cr32 & 0x08)) {
+	             myadaptnum = 1;
+		     if(!(cr32 & 0x10)) return 0xFFFF;
+                 }
+	      }
+	   }
+	}
+
+	temp = 4 - (myadaptnum * 2);
+	if(flag) temp = 0;
+
+     } else {						/* 315/330 series */
+
+     	/* here we simplify: 0 = CRT1, 1 = CRT2 (VGA, LCD) */
+
+	if(VBFlags & VB_SISBRIDGE) {
+	   if(myadaptnum == 2) {
+	      myadaptnum = 1;
+           }
+	}
+
+        if(myadaptnum == 1) {
+     	   flag = 0;
+	   if(VBFlags & VB_SISBRIDGE) {
+	      SiS_Pr->SiS_DDC_Port = SiS_Pr->SiS_Part4Port;
+              SiS_Pr->SiS_DDC_Index = 0x0f;
+	   }
+        }
+
+        if((cr32 & 0x80) && (checkcr32)) {
+           if(myadaptnum >= 1) {
+	      if(!(cr32 & 0x08)) {
+	         myadaptnum = 1;
+		 if(!(cr32 & 0x10)) return 0xFFFF;
+	      }
+	   }
+        }
+
+        temp = myadaptnum;
+        if(myadaptnum == 1) {
+           temp = 0;
+	   if(VBFlags & VB_LVDS) flag = 0xff;
+        }
+
+	if(flag) temp = 0;
+    }
+    
+    SiS_Pr->SiS_DDC_Data = 0x02 << temp;
+    SiS_Pr->SiS_DDC_Clk  = 0x01 << temp;
+
+    SiS_SetupDDCN(SiS_Pr);
+
+#ifdef TWDEBUG
+    xf86DrvMsg(0, X_INFO, "DDC Port %x Index %x Shift %d\n",
+    		SiS_Pr->SiS_DDC_Port, SiS_Pr->SiS_DDC_Index, temp);
+#endif
+    
+    return 0;
+}
+
+static USHORT
+SiS_WriteDABDDC(SiS_Private *SiS_Pr)
+{
+   if(SiS_SetStart(SiS_Pr)) return 0xFFFF;
+   if(SiS_WriteDDC2Data(SiS_Pr, SiS_Pr->SiS_DDC_DeviceAddr)) {
+  	return 0xFFFF;
+   }
+   if(SiS_WriteDDC2Data(SiS_Pr, SiS_Pr->SiS_DDC_SecAddr)) {
+   	return 0xFFFF;
+   }
+   return(0);
+}
+
+static USHORT
+SiS_PrepareReadDDC(SiS_Private *SiS_Pr)
+{
+   if(SiS_SetStart(SiS_Pr)) return 0xFFFF;
+   if(SiS_WriteDDC2Data(SiS_Pr, (SiS_Pr->SiS_DDC_DeviceAddr | 0x01))) {
+   	return 0xFFFF;
+   }
+   return(0);
+}
+
+static USHORT
+SiS_PrepareDDC(SiS_Private *SiS_Pr)
+{
+   if(SiS_WriteDABDDC(SiS_Pr)) SiS_WriteDABDDC(SiS_Pr);
+   if(SiS_PrepareReadDDC(SiS_Pr)) return(SiS_PrepareReadDDC(SiS_Pr));
+   return(0);
+}
+
+static void
+SiS_SendACK(SiS_Private *SiS_Pr, USHORT yesno)
+{
+   SiS_SetSCLKLow(SiS_Pr);
+   if(yesno) {
+      SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,
+      		      SiS_Pr->SiS_DDC_Index,
+                      SiS_Pr->SiS_DDC_NData,
+		      SiS_Pr->SiS_DDC_Data);
+   } else {
+      SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,
+      		      SiS_Pr->SiS_DDC_Index,
+                      SiS_Pr->SiS_DDC_NData,
+		      0);
+   }
+   SiS_SetSCLKHigh(SiS_Pr);
+}
+
+static USHORT
+SiS_DoProbeDDC(SiS_Private *SiS_Pr)
+{
+    unsigned char mask, value;
+    USHORT  temp, ret=0;
+    BOOLEAN failed = FALSE;
+
+    SiS_SetSwitchDDC2(SiS_Pr);
+    if(SiS_PrepareDDC(SiS_Pr)) {
+         SiS_SetStop(SiS_Pr);
+#ifdef TWDEBUG
+         xf86DrvMsg(0, X_INFO, "Probe: Prepare failed\n");
+#endif
+         return(0xFFFF);
+    }
+    mask = 0xf0;
+    value = 0x20;
+    if(SiS_Pr->SiS_DDC_DeviceAddr == 0xa0) {
+       temp = (unsigned char)SiS_ReadDDC2Data(SiS_Pr, 0);
+       SiS_SendACK(SiS_Pr, 0);
+       if(temp == 0) {
+           mask = 0xff;
+	   value = 0xff;
+       } else {
+           failed = TRUE;
+	   ret = 0xFFFF;
+#ifdef TWDEBUG
+           xf86DrvMsg(0, X_INFO, "Probe: Read 1 failed\n");
+#endif
+       }
+    }
+    if(failed == FALSE) {
+       temp = (unsigned char)SiS_ReadDDC2Data(SiS_Pr, 0);
+       SiS_SendACK(SiS_Pr, 1);
+       temp &= mask;
+       if(temp == value) ret = 0;
+       else {
+          ret = 0xFFFF;
+#ifdef TWDEBUG
+          xf86DrvMsg(0, X_INFO, "Probe: Read 2 failed\n");
+#endif
+          if(SiS_Pr->SiS_DDC_DeviceAddr == 0xa0) {
+             if(temp == 0x30) ret = 0;
+          }
+       }
+    }
+    SiS_SetStop(SiS_Pr);
+    return(ret);
+}
+
+static USHORT
+SiS_ProbeDDC(SiS_Private *SiS_Pr)
+{
+   USHORT flag;
+
+   flag = 0x180;
+   SiS_Pr->SiS_DDC_DeviceAddr = 0xa0;
+   if(!(SiS_DoProbeDDC(SiS_Pr))) flag |= 0x02;
+   SiS_Pr->SiS_DDC_DeviceAddr = 0xa2;
+   if(!(SiS_DoProbeDDC(SiS_Pr))) flag |= 0x08;
+   SiS_Pr->SiS_DDC_DeviceAddr = 0xa6;
+   if(!(SiS_DoProbeDDC(SiS_Pr))) flag |= 0x10;
+   if(!(flag & 0x1a)) flag = 0;
+   return(flag);
+}
+
+static USHORT
+SiS_ReadDDC(SiS_Private *SiS_Pr, USHORT DDCdatatype, unsigned char *buffer)
+{
+   USHORT flag, length, i;
+   unsigned char chksum,gotcha;
+
+   if(DDCdatatype > 4) return 0xFFFF;  
+
+   flag = 0;
+   SiS_SetSwitchDDC2(SiS_Pr);
+   if(!(SiS_PrepareDDC(SiS_Pr))) {
+      length = 127;
+      if(DDCdatatype != 1) length = 255;
+      chksum = 0;
+      gotcha = 0;
+      for(i=0; i<length; i++) {
+         buffer[i] = (unsigned char)SiS_ReadDDC2Data(SiS_Pr, 0);
+	 chksum += buffer[i];
+	 gotcha |= buffer[i];
+	 SiS_SendACK(SiS_Pr, 0);
+      }
+      buffer[i] = (unsigned char)SiS_ReadDDC2Data(SiS_Pr, 0);
+      chksum += buffer[i];
+      SiS_SendACK(SiS_Pr, 1);
+      if(gotcha) flag = (USHORT)chksum;
+      else flag = 0xFFFF;
+   } else {
+      flag = 0xFFFF;
+   }
+   SiS_SetStop(SiS_Pr);
+   return(flag);
+}
+
+/* Our private DDC functions
+
+   It complies somewhat with the corresponding VESA function
+   in arguments and return values.
+
+   Since this is probably called before the mode is changed,
+   we use our pre-detected pSiS-values instead of SiS_Pr as
+   regards chipset and video bridge type.
+
+   Arguments:
+       adaptnum: 0=CRT1(analog), 1=CRT2/LCD(digital), 2=CRT2/VGA2(analog)
+                 CRT2 DDC is only supported on SiS301, 301B, 301C, 302B.
+		 LCDA is CRT1, but DDC is read from CRT2 port.
+       DDCdatatype: 0=Probe, 1=EDID, 2=EDID+VDIF, 3=EDID V2 (P&D), 4=EDID V2 (FPDI-2)
+       buffer: ptr to 256 data bytes which will be filled with read data.
+
+   Returns 0xFFFF if error, otherwise
+       if DDCdatatype > 0:  Returns 0 if reading OK (included a correct checksum)
+       if DDCdatatype = 0:  Returns supported DDC modes
+
+ */
+USHORT
+SiS_HandleDDC(SiS_Private *SiS_Pr, unsigned long VBFlags, int VGAEngine,
+              USHORT adaptnum, USHORT DDCdatatype, unsigned char *buffer)
+{
+   unsigned char sr1f,cr17=1;
+   USHORT result;
+
+   if(adaptnum > 2) return 0xFFFF;
+   if(DDCdatatype > 4) return 0xFFFF;
+   if((!(VBFlags & VB_VIDEOBRIDGE)) && (adaptnum > 0)) return 0xFFFF;
+   if(SiS_InitDDCRegs(SiS_Pr, VBFlags, VGAEngine, adaptnum, DDCdatatype, FALSE) == 0xFFFF) return 0xFFFF;
+
+   sr1f = SiS_GetReg(SiS_Pr->SiS_P3c4,0x1f);
+   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x1f,0x3f,0x04);
+   if(VGAEngine == SIS_300_VGA) {
+      cr17 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x17) & 0x80;
+      if(!cr17) {
+         SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x17,0x80);
+         SiS_SetReg(SiS_Pr->SiS_P3c4,0x00,0x01);
+         SiS_SetReg(SiS_Pr->SiS_P3c4,0x00,0x03);
+      }
+   }
+   if((sr1f) || (!cr17)) {
+      SiS_WaitRetrace1(SiS_Pr);
+      SiS_WaitRetrace1(SiS_Pr);
+      SiS_WaitRetrace1(SiS_Pr);
+      SiS_WaitRetrace1(SiS_Pr);
+   }
+
+   if(DDCdatatype == 0) {
+      result = SiS_ProbeDDC(SiS_Pr);
+   } else {
+      result = SiS_ReadDDC(SiS_Pr, DDCdatatype, buffer);
+      if((!result) && (DDCdatatype == 1)) {
+         if((buffer[0] == 0x00) && (buffer[1] == 0xff) &&
+	    (buffer[2] == 0xff) && (buffer[3] == 0xff) &&
+	    (buffer[4] == 0xff) && (buffer[5] == 0xff) &&
+	    (buffer[6] == 0xff) && (buffer[7] == 0x00) &&
+	    (buffer[0x12] == 1)) {
+	    if(adaptnum == 1) {
+	       if(!(buffer[0x14] & 0x80)) result = 0xFFFE;
+	    } else {
+	       if(buffer[0x14] & 0x80)    result = 0xFFFE;
+	    }
+	 }
+      }
+   }
+   SiS_SetReg(SiS_Pr->SiS_P3c4,0x1f,sr1f);
+   if(VGAEngine == SIS_300_VGA) {
+      SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x17,0x7f,cr17);
+   }
+   return result;
+}
+
+#ifdef LINUX_XF86
+
+static BOOLEAN
+checkedid1(unsigned char *buffer)
+{
+   /* Check header */
+   if((buffer[0] != 0x00) ||
+      (buffer[1] != 0xff) ||
+      (buffer[2] != 0xff) ||
+      (buffer[3] != 0xff) ||
+      (buffer[4] != 0xff) ||
+      (buffer[5] != 0xff) ||
+      (buffer[6] != 0xff) ||
+      (buffer[7] != 0x00))
+      return FALSE;
+
+   /* Check EDID version and revision */
+   if((buffer[0x12] != 1) || (buffer[0x13] > 4)) return FALSE;
+
+   /* Check week of manufacture for sanity */
+   if(buffer[0x10] > 53) return FALSE;
+
+   /* Check year of manufacture for sanity */
+   if(buffer[0x11] > 40) return FALSE;
+
+   return TRUE;
+}
+
+static BOOLEAN
+checkedid2(unsigned char *buffer)
+{
+   USHORT year = buffer[6] | (buffer[7] << 8);
+
+   /* Check EDID version */
+   if((buffer[0] & 0xf0) != 0x20) return FALSE;
+
+   /* Check week of manufacture for sanity */
+   if(buffer[5] > 53) return FALSE;
+
+   /* Check year of manufacture for sanity */
+   if((year != 0) && ((year < 1990) || (year > 2030))) return FALSE;
+
+   return TRUE;
+}
+
+/* Sense the LCD parameters (CR36, CR37) via DDC */
+/* SiS30x(B) only */
+USHORT
+SiS_SenseLCDDDC(SiS_Private *SiS_Pr, SISPtr pSiS)
+{
+   USHORT DDCdatatype, paneltype, flag, xres=0, yres=0;
+   USHORT index, myindex, lumsize, numcodes, panelvendor, panelproduct;
+   int maxx=0, maxy=0, prefx=0, prefy=0;
+   unsigned char cr37=0, seekcode;
+   BOOLEAN checkexpand = FALSE;
+   BOOLEAN havesync = FALSE;
+   BOOLEAN indb = FALSE;
+   int retry, i;
+   unsigned char buffer[256];
+
+   for(i=0; i<7; i++) SiS_Pr->CP_DataValid[i] = FALSE;
+   SiS_Pr->CP_HaveCustomData = FALSE;
+   SiS_Pr->CP_MaxX = SiS_Pr->CP_MaxY = SiS_Pr->CP_MaxClock = 0;
+   SiS_Pr->CP_PreferredX = SiS_Pr->CP_PreferredY = 0;
+   SiS_Pr->CP_PreferredIndex = -1;
+   SiS_Pr->CP_PrefClock = 0;
+   SiS_Pr->PanelSelfDetected = FALSE;
+
+   if(!(pSiS->VBFlags & (VB_301|VB_301B|VB_301C|VB_302B))) return 0;
+   if(pSiS->VBFlags & VB_30xBDH) return 0;
+  
+   if(SiS_InitDDCRegs(SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine, 1, 0, FALSE) == 0xFFFF) return 0;
+   
+   SiS_Pr->SiS_DDC_SecAddr = 0x00;
+   
+   /* Probe supported DA's */
+   flag = SiS_ProbeDDC(SiS_Pr);
+#ifdef TWDEBUG
+   xf86DrvMsg(pSiS->pScrn->scrnIndex, X_INFO,
+   	"CRT2 DDC capabilities 0x%x\n", flag);
+#endif	
+   if(flag & 0x10) {
+      SiS_Pr->SiS_DDC_DeviceAddr = 0xa6;	/* EDID V2 (FP) */
+      DDCdatatype = 4;
+   } else if(flag & 0x08) {
+      SiS_Pr->SiS_DDC_DeviceAddr = 0xa2;	/* EDID V2 (P&D-D Monitor) */
+      DDCdatatype = 3;
+   } else if(flag & 0x02) {
+      SiS_Pr->SiS_DDC_DeviceAddr = 0xa0;	/* EDID V1 */
+      DDCdatatype = 1;
+   } else return 0;				/* no DDC support (or no device attached) */
+   
+   /* Read the entire EDID */
+   retry = 2;
+   do {
+      if(SiS_ReadDDC(SiS_Pr, DDCdatatype, buffer)) {
+         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
+	 	"CRT2: DDC read failed (attempt %d), %s\n",
+		(3-retry), (retry == 1) ? "giving up" : "retrying");
+	 retry--;
+	 if(retry == 0) return 0xFFFF;
+      } else break;
+   } while(1);
+
+#ifdef TWDEBUG
+   for(i=0; i<256; i+=16) {
+       xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
+       	"%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+	buffer[i],    buffer[i+1], buffer[i+2], buffer[i+3],
+	buffer[i+4],  buffer[i+5], buffer[i+6], buffer[i+7],
+	buffer[i+8],  buffer[i+9], buffer[i+10], buffer[i+11],
+	buffer[i+12], buffer[i+13], buffer[i+14], buffer[i+15]);
+   }
+#endif   
+   
+   /* Analyze EDID and retrieve LCD panel information */
+   paneltype = 0;
+   switch(DDCdatatype) {
+   case 1:							/* Analyze EDID V1 */
+      /* Catch a few clear cases: */
+      if(!(checkedid1(buffer))) {
+         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
+	 	"LCD sense: EDID corrupt\n");
+	 return 0;
+      }
+
+      if(!(buffer[0x14] & 0x80)) {
+         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
+	        "LCD sense: Attached display expects analog input (0x%02x)\n",
+		buffer[0x14]);
+      	 return 0;
+      }
+
+      if((buffer[0x18] & 0x18) != 0x08) {
+         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
+	 	"LCD sense: Warning: Attached display is not of RGB but of %s type (0x%02x)\n",
+		((buffer[0x18] & 0x18) == 0x00) ? "monochrome/greyscale" :
+		  ( ((buffer[0x18] & 0x18) == 0x10) ? "non-RGB multicolor" :
+		     "undefined"),
+		buffer[0x18]);
+      }
+
+      /* Now analyze the first Detailed Timing Block and see
+       * if the preferred timing mode is stored there. If so,
+       * check if this is a standard panel for which we already
+       * know the timing.
+       */
+
+      paneltype = Panel_Custom;
+      checkexpand = FALSE;
+
+      panelvendor = buffer[9] | (buffer[8] << 8);
+      panelproduct = buffer[10] | (buffer[11] << 8);
+
+      /* Overrule bogus preferred modes from database */
+      if((indb = SiS_FindPanelFromDB(pSiS, panelvendor, panelproduct, &maxx, &maxy, &prefx, &prefy))) {
+         if(prefx) SiS_Pr->CP_PreferredX = xres = prefx;
+	 if(prefy) SiS_Pr->CP_PreferredY = yres = prefy;
+      }
+
+      if(buffer[0x18] & 0x02) {
+
+         USHORT pclk = (buffer[0x36] | (buffer[0x37] << 8));
+	 USHORT phb  = (buffer[0x39] | ((buffer[0x3a] & 0x0f) << 8));
+	 USHORT pvb  = (buffer[0x3c] | ((buffer[0x3d] & 0x0f) << 8));
+
+	 if(!xres) SiS_Pr->CP_PreferredX = xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
+         if(!yres) SiS_Pr->CP_PreferredY = yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
+
+         switch(xres) {
+#if 0	    /* Treat as custom */
+            case 800:
+	        if(yres == 600) {
+	     	   paneltype = Panel_800x600;
+	     	   checkexpand = TRUE;
+	        }
+	        break;
+#endif
+            case 1024:
+	        if(yres == 768) {
+	     	   paneltype = Panel_1024x768;
+	     	   checkexpand = TRUE;
+	        }
+	        break;
+	    case 1280:
+	        if(yres == 1024) {
+	     	   paneltype = Panel_1280x1024;
+		   checkexpand = TRUE;
+	        } else if(yres == 960) {
+	           if(pSiS->VGAEngine == SIS_300_VGA) {
+		      paneltype = Panel300_1280x960;
+		   } else {
+		      paneltype = Panel310_1280x960;
+		   }
+	        } else if(yres == 768) {
+		   if( (pclk == 8100) &&
+		       (phb == (1688 - 1280)) &&
+		       (pvb == (802 - 768)) ) {
+	       	      paneltype = Panel_1280x768;
+		      checkexpand = FALSE;
+		      cr37 |= 0x10;
+		   }
+	        } else if(yres == 800) {
+		   if( (pclk == 6900) &&
+		       (phb == (1408 - 1280)) &&
+		       (pvb == (816 - 800)) ) {
+	       	      paneltype = Panel_1280x800;
+		   }
+		}
+	        break;
+	    case 1400:
+	        if(pSiS->VGAEngine == SIS_315_VGA) {
+	           if(yres == 1050) {
+	              paneltype = Panel310_1400x1050;
+		      checkexpand = TRUE;
+	           }
+	        }
+      	        break;
+	    case 1600:
+	        if(pSiS->VGAEngine == SIS_315_VGA) {
+		   if(pSiS->VBFlags & VB_301C) {
+	              if(yres == 1200) {
+	                 paneltype = Panel310_1600x1200;
+		         checkexpand = TRUE;
+		      }
+	           }
+	        }
+      	        break;
+         }
+
+	 /* Save sync: This is used if "Pass 1:1" is off; in this case
+	  * we always use the panel's native mode = this "preferred mode"
+	  * we just have been analysing. Hence, we also need its sync.
+	  */
+	 if((buffer[0x47] & 0x18) == 0x18) {
+	    cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
+	    havesync = TRUE;
+	 } else {
+	    /* What now? There is no digital separate output timing... */
+	    xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
+	       	   "LCD sense: Unable to retrieve Sync polarity information\n");
+	    cr37 |= 0xc0;  /* Default */
+	 }
+
+      }
+
+      /* Check against our database; eg. Sanyo Z2 projector reports
+       * 1024x768 as preferred mode, although it supports 1280x720
+       * natively in non-HDCP mode. Treat such wrongly reporting
+       * panels as custom and fixup actual maximum resolutions.
+       */
+      if(paneltype != Panel_Custom) {
+         if(indb) {
+	    paneltype = Panel_Custom;
+	    SiS_Pr->CP_MaxX = maxx;
+	    SiS_Pr->CP_MaxY = maxy;
+	    /* Leave preferred unchanged (MUST contain a valid mode!) */
+	 }
+      }
+
+      /* If we still don't know what panel this is, we take it
+       * as a custom panel and derive the timing data from the
+       * detailed timing blocks
+       */
+      if(paneltype == Panel_Custom) {
+
+	 int i, temp, base = 0x36;
+	 unsigned long estpack;
+	 const unsigned short estx[] = {
+	 	720, 720, 640, 640, 640, 640, 800, 800,
+		800, 800, 832,1024,1024,1024,1024,1280,
+		1152
+	 };
+	 const unsigned short esty[] = {
+	 	400, 400, 480, 480, 480, 480, 600, 600,
+		600, 600, 624, 768, 768, 768, 768,1024,
+		870
+	 };
+	 const int estclk[] = {
+	            0,     0, 25100,   0, 31500, 31500, 36100, 40000,
+		50100, 49500,     0,   0, 65100, 75200, 78700,135200,
+		0
+	 };
+
+	 paneltype = 0;
+	 SiS_Pr->CP_Supports64048075 = TRUE;
+
+	 /* Find the maximum resolution */
+
+	 /* 1. From Established timings */
+	 estpack = (buffer[0x23] << 9) | (buffer[0x24] << 1) | ((buffer[0x25] >> 7) & 0x01);
+	 for(i=16; i>=0; i--) {
+	     if(estpack & (1 << i)) {
+	        if(estx[16 - i] > SiS_Pr->CP_MaxX) SiS_Pr->CP_MaxX = estx[16 - i];
+		if(esty[16 - i] > SiS_Pr->CP_MaxY) SiS_Pr->CP_MaxY = esty[16 - i];
+		if(estclk[16 - i] > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = estclk[16 - i];
+	     }
+	 }
+
+	 /* By default we drive the LCD at 75Hz in 640x480 mode; if
+  	  * the panel does not provide this mode, use 60hz
+	  */
+	 if(!(buffer[0x23] & 0x04)) SiS_Pr->CP_Supports64048075 = FALSE;
+
+	 /* 2. From Standard Timings */
+	 for(i=0x26; i < 0x36; i+=2) {
+	    if((buffer[i] != 0x01) && (buffer[i+1] != 0x01)) {
+	       temp = (buffer[i] + 31) * 8;
+	       if(temp > SiS_Pr->CP_MaxX) SiS_Pr->CP_MaxX = temp;
+	       switch((buffer[i+1] & 0xc0) >> 6) {
+	       case 0x03: temp = temp * 9 / 16; break;
+	       case 0x02: temp = temp * 4 / 5;  break;
+	       case 0x01: temp = temp * 3 / 4;  break;
+	       }
+	       if(temp > SiS_Pr->CP_MaxY) SiS_Pr->CP_MaxY = temp;
+	    }
+	 }
+
+	 /* Now extract the Detailed Timings and convert them into modes */
+
+         for(i = 0; i < 4; i++, base += 18) {
+
+	    /* Is this a detailed timing block or a monitor descriptor? */
+	    if(buffer[base] || buffer[base+1] || buffer[base+2]) {
+
+      	       xres = buffer[base+2] | ((buffer[base+4] & 0xf0) << 4);
+               yres = buffer[base+5] | ((buffer[base+7] & 0xf0) << 4);
+
+	       SiS_Pr->CP_HDisplay[i] = xres;
+	       SiS_Pr->CP_HSyncStart[i] = xres + (buffer[base+8] | ((buffer[base+11] & 0xc0) << 2));
+               SiS_Pr->CP_HSyncEnd[i]   = SiS_Pr->CP_HSyncStart[i] + (buffer[base+9] | ((buffer[base+11] & 0x30) << 4));
+	       SiS_Pr->CP_HTotal[i] = xres + (buffer[base+3] | ((buffer[base+4] & 0x0f) << 8));
+	       SiS_Pr->CP_HBlankStart[i] = xres + 1;
+	       SiS_Pr->CP_HBlankEnd[i] = SiS_Pr->CP_HTotal[i];
+
+	       SiS_Pr->CP_VDisplay[i] = yres;
+               SiS_Pr->CP_VSyncStart[i] = yres + (((buffer[base+10] & 0xf0) >> 4) | ((buffer[base+11] & 0x0c) << 2));
+               SiS_Pr->CP_VSyncEnd[i] = SiS_Pr->CP_VSyncStart[i] + ((buffer[base+10] & 0x0f) | ((buffer[base+11] & 0x03) << 4));
+	       SiS_Pr->CP_VTotal[i] = yres + (buffer[base+6] | ((buffer[base+7] & 0x0f) << 8));
+	       SiS_Pr->CP_VBlankStart[i] = yres + 1;
+	       SiS_Pr->CP_VBlankEnd[i] = SiS_Pr->CP_VTotal[i];
+
+	       SiS_Pr->CP_Clock[i] = (buffer[base] | (buffer[base+1] << 8)) * 10;
+
+	       SiS_Pr->CP_DataValid[i] = TRUE;
+
+	       /* Sort out invalid timings, interlace and too high clocks */
+	       if((SiS_Pr->CP_HDisplay[i] & 7)						  ||
+	          (SiS_Pr->CP_HDisplay[i] > SiS_Pr->CP_HSyncStart[i])  			  ||
+	          (SiS_Pr->CP_HDisplay[i] >= SiS_Pr->CP_HSyncEnd[i])   			  ||
+	          (SiS_Pr->CP_HDisplay[i] >= SiS_Pr->CP_HTotal[i])     			  ||
+	          (SiS_Pr->CP_HSyncStart[i] >= SiS_Pr->CP_HSyncEnd[i]) 			  ||
+	          (SiS_Pr->CP_HSyncStart[i] > SiS_Pr->CP_HTotal[i])    			  ||
+	          (SiS_Pr->CP_HSyncEnd[i] > SiS_Pr->CP_HTotal[i])      			  ||
+	          (SiS_Pr->CP_VDisplay[i] > SiS_Pr->CP_VSyncStart[i])  			  ||
+	          (SiS_Pr->CP_VDisplay[i] >= SiS_Pr->CP_VSyncEnd[i])   			  ||
+	          (SiS_Pr->CP_VDisplay[i] >= SiS_Pr->CP_VTotal[i])     			  ||
+	          (SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VSyncEnd[i])  			  ||
+	          (SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VTotal[i])    			  ||
+	          (SiS_Pr->CP_VSyncEnd[i] > SiS_Pr->CP_VTotal[i])      			  ||
+		  (((pSiS->VBFlags & VB_301C) && (SiS_Pr->CP_Clock[i] > 162500)) ||
+	           ((!(pSiS->VBFlags & VB_301C)) &&
+		    ((SiS_Pr->CP_Clock[i] > 108200) || (SiS_Pr->CP_VDisplay[i] > 1024) ||
+		     (SiS_Pr->CP_HDisplay[i] > 1600)))) 				  ||
+		  (buffer[base+17] & 0x80)) {
+
+	          SiS_Pr->CP_DataValid[i] = FALSE;
+
+	       } else {
+
+		  SiS_Pr->CP_HaveCustomData = TRUE;
+
+		  if(xres > SiS_Pr->CP_MaxX) SiS_Pr->CP_MaxX = xres;
+	          if(yres > SiS_Pr->CP_MaxY) SiS_Pr->CP_MaxY = yres;
+		  if(SiS_Pr->CP_Clock[i] > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = SiS_Pr->CP_Clock[i];
+
+		  if((SiS_Pr->CP_PreferredX == xres) && (SiS_Pr->CP_PreferredY == yres)) {
+	             SiS_Pr->CP_PreferredIndex = i;
+		     SiS_MakeClockRegs(pSiS->pScrn, SiS_Pr->CP_Clock[i], &SiS_Pr->CP_PrefSR2B, &SiS_Pr->CP_PrefSR2C);
+		     SiS_Pr->CP_PrefClock = (SiS_Pr->CP_Clock[i] / 1000) + 1;
+	          }
+
+	          /* Extract the sync polarisation information. This only works
+	           * if the Flags indicate a digital separate output.
+	           */
+	          if((buffer[base+17] & 0x18) == 0x18) {
+		     SiS_Pr->CP_HSync_P[i] = (buffer[base+17] & 0x02) ? TRUE : FALSE;
+		     SiS_Pr->CP_VSync_P[i] = (buffer[base+17] & 0x04) ? TRUE : FALSE;
+		     SiS_Pr->CP_SyncValid[i] = TRUE;
+		     if((i == SiS_Pr->CP_PreferredIndex) && (!havesync)) {
+	                cr37 |= ((((buffer[base+17] & 0x06) ^ 0x06) << 5) | 0x20);
+			havesync = TRUE;
+	   	     }
+	          } else {
+		     SiS_Pr->CP_SyncValid[i] = FALSE;
+		  }
+
+	       }
+
+            } else if((!buffer[base]) && (!buffer[base+1]) && (!buffer[base+2]) && (!buffer[base+4])) {
+
+	       /* Maximum pixclock from Monitor Range Limits */
+	       if((buffer[base+3] == 0xfd) && (buffer[base+9] != 0xff)) {
+	          int maxclk = buffer[base+9] * 10;
+		  /* More than 170 is not supported anyway */
+		  if(maxclk <= 170) SiS_Pr->CP_MaxClock = maxclk * 1000;
+	       }
+
+	    }
+
+	 }
+
+	 if(SiS_Pr->CP_MaxX && SiS_Pr->CP_MaxY) {
+	    paneltype = Panel_Custom;
+	    checkexpand = FALSE;
+	    cr37 |= 0x10;
+	    SiS_Pr->CP_Vendor = panelvendor;
+	    SiS_Pr->CP_Product = panelproduct;
+	 }
+
+      }
+
+      if(paneltype && checkexpand) {
+         /* If any of the Established low-res modes is supported, the
+	  * panel can scale automatically. For 800x600 panels, we only 
+	  * check the even lower ones.
+	  */
+	 if(paneltype == Panel_800x600) {
+	    if(buffer[0x23] & 0xfc) cr37 |= 0x10;
+	 } else {
+            if(buffer[0x23])	    cr37 |= 0x10;
+	 }
+      }
+       
+      break;
+      
+   case 3:							/* Analyze EDID V2 */
+   case 4:
+      index = 0;
+
+      if(!(checkedid2(buffer))) {
+         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
+	 	"LCD sense: EDID corrupt\n");
+	 return 0;
+      }
+
+      if((buffer[0x41] & 0x0f) == 0x03) {
+         index = 0x42 + 3;
+         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
+	 	"LCD sense: Display supports TMDS input on primary interface\n");
+      } else if((buffer[0x41] & 0xf0) == 0x30) {
+         index = 0x46 + 3;
+         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
+	 	"LCD sense: Display supports TMDS input on secondary interface\n");
+      } else {
+         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
+	 	"LCD sense: Display does not support TMDS video interface (0x%02x)\n",
+		buffer[0x41]);
+	 return 0;
+      }
+
+      SiS_Pr->CP_Vendor = panelvendor = buffer[2] | (buffer[1] << 8);
+      SiS_Pr->CP_Product = panelproduct = buffer[3] | (buffer[4] << 8);
+
+      paneltype = Panel_Custom;
+      SiS_Pr->CP_MaxX = SiS_Pr->CP_PreferredX = xres = buffer[0x76] | (buffer[0x77] << 8);
+      SiS_Pr->CP_MaxY = SiS_Pr->CP_PreferredY = yres = buffer[0x78] | (buffer[0x79] << 8);
+
+      switch(xres) {
+#if 0
+         case 800:
+	     if(yres == 600) {
+	     	paneltype = Panel_800x600;
+	     	checkexpand = TRUE;
+	     }
+	     break;
+#endif
+         case 1024:
+	     if(yres == 768) {
+	     	paneltype = Panel_1024x768;
+	     	checkexpand = TRUE;
+	     }
+	     break;
+	 case 1280:
+	     if(yres == 960) {
+	        if(pSiS->VGAEngine == SIS_315_VGA) {
+	     	   paneltype = Panel310_1280x960;
+		} else {
+		   paneltype = Panel300_1280x960;
+		}
+	     } else if(yres == 1024) {
+	     	paneltype = Panel_1280x1024;
+		checkexpand = TRUE;
+	     }
+	     /* 1280x768 treated as custom here */
+	     break;
+	 case 1400:
+	     if(pSiS->VGAEngine == SIS_315_VGA) {
+	        if(yres == 1050) {
+	           paneltype = Panel310_1400x1050;
+		   checkexpand = TRUE;
+	        }
+	     }
+      	     break;
+	 case 1600:
+	     if(pSiS->VGAEngine == SIS_315_VGA) {
+	        if(pSiS->VBFlags & VB_301C) {
+	           if(yres == 1200) {
+	              paneltype = Panel310_1600x1200;
+		      checkexpand = TRUE;
+		   }
+	        }
+	     }
+      	     break;
+      }
+
+      /* Determine if RGB18 or RGB24 */
+      if(index) {
+         if((buffer[index] == 0x20) || (buffer[index] == 0x34)) {
+	    cr37 |= 0x01;
+	 }
+      }
+
+      if(checkexpand) {
+         /* TODO - for now, we let the panel scale */
+	 cr37 |= 0x10;
+      }
+
+      /* Now seek 4-Byte Timing codes and extract sync pol info */
+      index = 0x80;
+      if(buffer[0x7e] & 0x20) {			    /* skip Luminance Table (if provided) */
+         lumsize = buffer[0x80] & 0x1f;
+	 if(buffer[0x80] & 0x80) lumsize *= 3;
+	 lumsize++;  /* luminance header byte */
+	 index += lumsize;
+      }
+#if 0 /* "pixel rate" = pixel clock? */
+      if(buffer[0x7e] & 0x1c) {
+         for(i=0; i<((buffer[0x7e] & 0x1c) >> 2); i++) {
+	    if(buffer[index + (i*8) + 6] && (buffer[index + (i*8) + 7] & 0x0f)) {
+	       int clk = (buffer[index + (i*8) + 6] | ((buffer[index + (i*8) + 7] & 0x0f) << 4)) * 1000;
+	       if(clk > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = clk;
+	    }
+	 }
+      }
+#endif
+      index += (((buffer[0x7e] & 0x1c) >> 2) * 8);   /* skip Frequency Ranges */
+      if(buffer[0x7e] & 0x03) {
+         for(i=0; i<(buffer[0x7e] & 0x03); i++) {
+	    if((buffer[index + (i*27) + 9]) || (buffer[index + (i*27) + 10])) {
+	       int clk = ((buffer[index + (i*27) + 9]) | ((buffer[index + (i*27) + 9]) << 8)) * 10;
+	       if(clk > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = clk;
+	    }
+	 }
+      }
+      index += ((buffer[0x7e] & 0x03) * 27);         /* skip Detailed Range Limits */
+      numcodes = (buffer[0x7f] & 0xf8) >> 3;
+      if(numcodes) {
+         myindex = index;
+ 	 seekcode = (xres - 256) / 16;
+     	 for(i=0; i<numcodes; i++) {
+	    if(buffer[myindex] == seekcode) break;
+	    myindex += 4;
+	 }
+	 if(buffer[myindex] == seekcode) {
+	    cr37 |= ((((buffer[myindex + 1] & 0x0c) ^ 0x0c) << 4) | 0x20);
+	    havesync = TRUE;
+	 } else {
+	    xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
+	        "LCD sense: Unable to retrieve Sync polarity information\n");
+	 }
+      } else {
+         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
+	     "LCD sense: Unable to retrieve Sync polarity information\n");
+      }
+
+      /* Check against our database; Eg. Sanyo projector reports
+       * 1024x768 in non-HDPC mode, although it supports 1280x720.
+       * Treat such wrongly reporting panels as custom.
+       */
+      if(paneltype != Panel_Custom) {
+         int maxx, maxy, prefx, prefy;
+         if((SiS_FindPanelFromDB(pSiS, panelvendor, panelproduct, &maxx, &maxy, &prefx, &prefy))) {
+	    paneltype = Panel_Custom;
+	    SiS_Pr->CP_MaxX = maxx;
+	    SiS_Pr->CP_MaxY = maxy;
+	    cr37 |= 0x10;
+	    /* Leave preferred unchanged (MUST be a valid mode!) */
+	 }
+      }
+
+      /* Now seek the detailed timing descriptions for custom panels */
+      if(paneltype == Panel_Custom) {
+
+         SiS_Pr->CP_Supports64048075 = TRUE;
+
+         index += (numcodes * 4);
+	 numcodes = buffer[0x7f] & 0x07;
+	 for(i=0; i<numcodes; i++, index += 18) {
+	    xres = buffer[index+2] | ((buffer[index+4] & 0xf0) << 4);
+            yres = buffer[index+5] | ((buffer[index+7] & 0xf0) << 4);
+
+	    SiS_Pr->CP_HDisplay[i] = xres;
+	    SiS_Pr->CP_HSyncStart[i] = xres + (buffer[index+8] | ((buffer[index+11] & 0xc0) << 2));
+            SiS_Pr->CP_HSyncEnd[i] = SiS_Pr->CP_HSyncStart[i] + (buffer[index+9] | ((buffer[index+11] & 0x30) << 4));
+	    SiS_Pr->CP_HTotal[i] = xres + (buffer[index+3] | ((buffer[index+4] & 0x0f) << 8));
+	    SiS_Pr->CP_HBlankStart[i] = xres + 1;
+	    SiS_Pr->CP_HBlankEnd[i] = SiS_Pr->CP_HTotal[i];
+
+	    SiS_Pr->CP_VDisplay[i] = yres;
+            SiS_Pr->CP_VSyncStart[i] = yres + (((buffer[index+10] & 0xf0) >> 4) | ((buffer[index+11] & 0x0c) << 2));
+            SiS_Pr->CP_VSyncEnd[i] = SiS_Pr->CP_VSyncStart[i] + ((buffer[index+10] & 0x0f) | ((buffer[index+11] & 0x03) << 4));
+	    SiS_Pr->CP_VTotal[i] = yres + (buffer[index+6] | ((buffer[index+7] & 0x0f) << 8));
+	    SiS_Pr->CP_VBlankStart[i] = yres + 1;
+	    SiS_Pr->CP_VBlankEnd[i] = SiS_Pr->CP_VTotal[i];
+
+	    SiS_Pr->CP_Clock[i] = (buffer[index] | (buffer[index+1] << 8)) * 10;
+
+	    SiS_Pr->CP_DataValid[i] = TRUE;
+
+	    if((SiS_Pr->CP_HDisplay[i] & 7)						||
+	       (SiS_Pr->CP_HDisplay[i] > SiS_Pr->CP_HSyncStart[i])  			||
+	       (SiS_Pr->CP_HDisplay[i] >= SiS_Pr->CP_HSyncEnd[i])   			||
+	       (SiS_Pr->CP_HDisplay[i] >= SiS_Pr->CP_HTotal[i])     			||
+	       (SiS_Pr->CP_HSyncStart[i] >= SiS_Pr->CP_HSyncEnd[i]) 			||
+	       (SiS_Pr->CP_HSyncStart[i] > SiS_Pr->CP_HTotal[i])    			||
+	       (SiS_Pr->CP_HSyncEnd[i] > SiS_Pr->CP_HTotal[i])      			||
+	       (SiS_Pr->CP_VDisplay[i] > SiS_Pr->CP_VSyncStart[i])  			||
+	       (SiS_Pr->CP_VDisplay[i] >= SiS_Pr->CP_VSyncEnd[i])   			||
+	       (SiS_Pr->CP_VDisplay[i] >= SiS_Pr->CP_VTotal[i])     			||
+	       (SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VSyncEnd[i])  			||
+	       (SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VTotal[i])    			||
+	       (SiS_Pr->CP_VSyncEnd[i] > SiS_Pr->CP_VTotal[i])      			||
+	       (((pSiS->VBFlags & VB_301C) && (SiS_Pr->CP_Clock[i] > 162500)) ||
+	        ((!(pSiS->VBFlags & VB_301C)) &&
+		 ((SiS_Pr->CP_Clock[i] > 108200) || (SiS_Pr->CP_VDisplay[i] > 1024))))	||
+	       (buffer[index + 17] & 0x80)) {
+
+	       SiS_Pr->CP_DataValid[i] = FALSE;
+
+	    } else {
+
+	       SiS_Pr->CP_HaveCustomData = TRUE;
+
+	       if(SiS_Pr->CP_Clock[i] > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = SiS_Pr->CP_Clock[i];
+
+	       if((SiS_Pr->CP_PreferredX == xres) && (SiS_Pr->CP_PreferredY == yres)) {
+	          SiS_Pr->CP_PreferredIndex = i;
+		  SiS_MakeClockRegs(pSiS->pScrn, SiS_Pr->CP_Clock[i], &SiS_Pr->CP_PrefSR2B, &SiS_Pr->CP_PrefSR2C);
+		  SiS_Pr->CP_PrefClock = (SiS_Pr->CP_Clock[i] / 1000) + 1;
+		  if(!havesync) {
+	             cr37 |= ((((buffer[index + 17] & 0x06) ^ 0x06) << 5) | 0x20);
+		     havesync = TRUE;
+	   	  }
+	       }
+
+	       SiS_Pr->CP_HSync_P[i] = (buffer[index + 17] & 0x02) ? TRUE : FALSE;
+	       SiS_Pr->CP_VSync_P[i] = (buffer[index + 17] & 0x04) ? TRUE : FALSE;
+	       SiS_Pr->CP_SyncValid[i] = TRUE;
+
+	    }
+	 }
+
+	 cr37 |= 0x10;
+
+      }
+
+      break;
+
+   }
+
+   /* 1280x960 panels are always RGB24, unable to scale and use
+    * high active sync polarity
+    */
+   if(pSiS->VGAEngine == SIS_315_VGA) {
+      if(paneltype == Panel310_1280x960) cr37 &= 0x0e;
+   } else {
+      if(paneltype == Panel300_1280x960) cr37 &= 0x0e;
+   }
+
+   for(i = 0; i < 7; i++) {
+      if(SiS_Pr->CP_DataValid[i]) {
+         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
+            "Non-standard LCD/DVI-D timing data no. %d:\n", i);
+         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
+	    "   HDisplay %d HSync %d HSyncEnd %d HTotal %d\n",
+	    SiS_Pr->CP_HDisplay[i], SiS_Pr->CP_HSyncStart[i],
+	    SiS_Pr->CP_HSyncEnd[i], SiS_Pr->CP_HTotal[i]);
+         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
+            "   VDisplay %d VSync %d VSyncEnd %d VTotal %d\n",
+            SiS_Pr->CP_VDisplay[i], SiS_Pr->CP_VSyncStart[i],
+   	    SiS_Pr->CP_VSyncEnd[i], SiS_Pr->CP_VTotal[i]);
+         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
+	    "   Pixel clock: %3.3fMhz\n", (float)SiS_Pr->CP_Clock[i] / 1000);
+	 xf86DrvMsg(pSiS->pScrn->scrnIndex, X_INFO,
+	    "   To use this, add \"%dx%d\" to the list of Modes in the Screen section\n",
+	    SiS_Pr->CP_HDisplay[i],
+	    SiS_Pr->CP_VDisplay[i]);
+      }
+   }
+
+   if(paneltype) {
+       if(!SiS_Pr->CP_PreferredX) SiS_Pr->CP_PreferredX = SiS_Pr->CP_MaxX;
+       if(!SiS_Pr->CP_PreferredY) SiS_Pr->CP_PreferredY = SiS_Pr->CP_MaxY;
+       SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x32,0x08);
+       SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,paneltype);
+       cr37 &= 0xf1;
+       SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,0x0c,cr37);
+       SiS_Pr->PanelSelfDetected = TRUE;
+#ifdef TWDEBUG
+       xf86DrvMsgVerb(pSiS->pScrn->scrnIndex, X_PROBED, 3, 
+       	   "LCD sense: [DDC LCD results: 0x%02x, 0x%02x]\n", paneltype, cr37);
+#endif	
+   } else {
+       SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x32,~0x08);
+       SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,0x00);
+   }
+   return 0;
+}
+   
+USHORT
+SiS_SenseVGA2DDC(SiS_Private *SiS_Pr, SISPtr pSiS)
+{
+   USHORT DDCdatatype,flag;
+   BOOLEAN foundcrt = FALSE;
+   int retry;
+   unsigned char buffer[256];
+
+   if(!(pSiS->VBFlags & (VB_301|VB_301B|VB_301C|VB_302B))) return 0;
+
+   if(SiS_InitDDCRegs(SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine, 2, 0, FALSE) == 0xFFFF) return 0;
+   
+   SiS_Pr->SiS_DDC_SecAddr = 0x00;
+   
+   /* Probe supported DA's */
+   flag = SiS_ProbeDDC(SiS_Pr);
+   if(flag & 0x10) {
+      SiS_Pr->SiS_DDC_DeviceAddr = 0xa6;	/* EDID V2 (FP) */
+      DDCdatatype = 4;
+   } else if(flag & 0x08) {
+      SiS_Pr->SiS_DDC_DeviceAddr = 0xa2;	/* EDID V2 (P&D-D Monitor) */
+      DDCdatatype = 3;
+   } else if(flag & 0x02) {
+      SiS_Pr->SiS_DDC_DeviceAddr = 0xa0;	/* EDID V1 */
+      DDCdatatype = 1;
+   } else {
+   	xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
+		"VGA2 sense: Do DDC answer\n");
+   	return 0;				/* no DDC support (or no device attached) */
+   }
+
+   /* Read the entire EDID */
+   retry = 2;
+   do {
+      if(SiS_ReadDDC(SiS_Pr, DDCdatatype, buffer)) {
+         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
+	 	"VGA2 sense: DDC read failed (attempt %d), %s\n",
+		(3-retry), (retry == 1) ? "giving up" : "retrying");
+	 retry--;
+	 if(retry == 0) return 0xFFFF;
+      } else break;
+   } while(1);
+
+   /* Analyze EDID. We don't have many chances to
+    * distinguish a flat panel from a CRT...
+    */
+   switch(DDCdatatype) {
+   case 1:
+      if(!(checkedid1(buffer))) {
+          xf86DrvMsg(pSiS->pScrn->scrnIndex, X_ERROR,
+	  	"VGA2 sense: EDID corrupt\n");
+      	  return 0;
+      }
+      if(buffer[0x14] & 0x80) {			/* Display uses digital input */
+          xf86DrvMsg(pSiS->pScrn->scrnIndex, X_ERROR,
+	  	"VGA2 sense: Attached display expects digital input\n");
+      	  return 0;
+      }
+      SiS_Pr->CP_Vendor = buffer[9] | (buffer[8] << 8);
+      SiS_Pr->CP_Product = buffer[10] | (buffer[11] << 8);
+      foundcrt = TRUE;
+      break;
+   case 3:
+   case 4:
+      if(!(checkedid2(buffer))) {
+          xf86DrvMsg(pSiS->pScrn->scrnIndex, X_ERROR,
+	  	"VGA2 sense: EDID corrupt\n");
+      	  return 0;
+      }
+      if( ((buffer[0x41] & 0x0f) != 0x01) &&  	/* Display does not support analog input */
+          ((buffer[0x41] & 0x0f) != 0x02) &&
+	  ((buffer[0x41] & 0xf0) != 0x10) &&
+	  ((buffer[0x41] & 0xf0) != 0x20) ) {
+	  xf86DrvMsg(pSiS->pScrn->scrnIndex, X_ERROR,
+	     	"VGA2 sense: Attached display does not support analog input (0x%02x)\n",
+		buffer[0x41]);
+	  return 0;
+      }
+      SiS_Pr->CP_Vendor = buffer[2] | (buffer[1] << 8);
+      SiS_Pr->CP_Product = buffer[3] | (buffer[4] << 8);
+      foundcrt = TRUE;
+      break;
+   }
+
+   if(foundcrt) {
+      SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x32,0x10);
+   }
+   return(0);
+}
+
+#endif
+
+void
+SiS_SetCH70xxANDOR(SiS_Private *SiS_Pr, USHORT tempax,USHORT tempbh)
+{
+  USHORT tempbl;
+
+  tempbl = SiS_GetCH70xx(SiS_Pr,(tempax & 0x00FF));
+  tempbl = (((tempbl & tempbh) << 8) | tempax);
+  SiS_SetCH70xx(SiS_Pr,tempbl);
+}
+
+/* Generic I2C functions for Chrontel & DDC --------- */
+
+static void
+SiS_SetSwitchDDC2(SiS_Private *SiS_Pr)
+{
+  SiS_SetSCLKHigh(SiS_Pr);
+  SiS_WaitRetrace1(SiS_Pr);
+
+  SiS_SetSCLKLow(SiS_Pr);
+  SiS_WaitRetrace1(SiS_Pr);
+}
+
+USHORT
+SiS_ReadDDC1Bit(SiS_Private *SiS_Pr)
+{
+   SiS_WaitRetrace1(SiS_Pr);
+   return((SiS_GetReg(SiS_Pr->SiS_P3c4,0x11) & 0x02) >> 1);
+}
+
+/* Set I2C start condition */
+/* This is done by a SD high-to-low transition while SC is high */
+static USHORT
+SiS_SetStart(SiS_Private *SiS_Pr)
+{
+  if(SiS_SetSCLKLow(SiS_Pr)) return 0xFFFF;			           /* (SC->low)  */
+  SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,
+    		  SiS_Pr->SiS_DDC_Index,
+                  SiS_Pr->SiS_DDC_NData,
+		  SiS_Pr->SiS_DDC_Data);             			   /* SD->high */
+  if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF;			           /* SC->high */
+  SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,
+  		  SiS_Pr->SiS_DDC_Index,
+                  SiS_Pr->SiS_DDC_NData,
+		  0x00);                             			   /* SD->low = start condition */
+  if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF;			           /* (SC->low) */
+  return 0;
+}
+
+/* Set I2C stop condition */
+/* This is done by a SD low-to-high transition while SC is high */
+static USHORT
+SiS_SetStop(SiS_Private *SiS_Pr)
+{
+  if(SiS_SetSCLKLow(SiS_Pr)) return 0xFFFF;			           /* (SC->low) */
+  SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,
+  	          SiS_Pr->SiS_DDC_Index,
+                  SiS_Pr->SiS_DDC_NData,
+		  0x00);          		   			   /* SD->low   */
+  if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF;			           /* SC->high  */
+  SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,
+  		  SiS_Pr->SiS_DDC_Index,
+                  SiS_Pr->SiS_DDC_NData,
+		  SiS_Pr->SiS_DDC_Data);  	   			   /* SD->high = stop condition */
+  if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF;			           /* (SC->high) */
+  return 0;
+}
+
+/* Write 8 bits of data */
+static USHORT
+SiS_WriteDDC2Data(SiS_Private *SiS_Pr, USHORT tempax)
+{
+  USHORT i,flag,temp;
+
+  flag = 0x80;
+  for(i=0; i<8; i++) {
+    SiS_SetSCLKLow(SiS_Pr);				                      /* SC->low */
+    if(tempax & flag) {
+      SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,
+      		      SiS_Pr->SiS_DDC_Index,
+                      SiS_Pr->SiS_DDC_NData,
+		      SiS_Pr->SiS_DDC_Data);            		      /* Write bit (1) to SD */
+    } else {
+      SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,
+      		      SiS_Pr->SiS_DDC_Index,
+                      SiS_Pr->SiS_DDC_NData,
+		      0x00);                            		      /* Write bit (0) to SD */
+    }
+    SiS_SetSCLKHigh(SiS_Pr);				                      /* SC->high */
+    flag >>= 1;
+  }
+  temp = SiS_CheckACK(SiS_Pr);				                      /* Check acknowledge */
+  return(temp);
+}
+
+static USHORT
+SiS_ReadDDC2Data(SiS_Private *SiS_Pr, USHORT tempax)
+{
+  USHORT i,temp,getdata;
+
+  getdata=0;
+  for(i=0; i<8; i++) {
+    getdata <<= 1;
+    SiS_SetSCLKLow(SiS_Pr);
+    SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,
+    		    SiS_Pr->SiS_DDC_Index,
+                    SiS_Pr->SiS_DDC_NData,
+		    SiS_Pr->SiS_DDC_Data);
+    SiS_SetSCLKHigh(SiS_Pr);
+    temp = SiS_GetReg(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index);
+    if(temp & SiS_Pr->SiS_DDC_Data) getdata |= 0x01;
+  }
+  return(getdata);
+}
+
+static USHORT
+SiS_SetSCLKLow(SiS_Private *SiS_Pr)
+{
+  SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,
+  		  SiS_Pr->SiS_DDC_Index,
+                  SiS_Pr->SiS_DDC_NClk,
+		  0x00);      					/* SetSCLKLow()  */
+  SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT);
+  return 0;
+}
+
+static USHORT
+SiS_SetSCLKHigh(SiS_Private *SiS_Pr)
+{
+  USHORT temp, watchdog=1000;
+
+  SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,
+  		  SiS_Pr->SiS_DDC_Index,
+                  SiS_Pr->SiS_DDC_NClk,
+		  SiS_Pr->SiS_DDC_Clk);  			/* SetSCLKHigh()  */
+  do {
+    temp = SiS_GetReg(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index);
+  } while((!(temp & SiS_Pr->SiS_DDC_Clk)) && --watchdog);
+  if (!watchdog) {
+#ifdef TWDEBUG
+        xf86DrvMsg(0, X_INFO, "SetClkHigh failed\n");
+#endif
+  	return 0xFFFF;
+  }
+  SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT);
+  return 0;
+}
+
+/* Check I2C acknowledge */
+/* Returns 0 if ack ok, non-0 if ack not ok */
+static USHORT
+SiS_CheckACK(SiS_Private *SiS_Pr)
+{
+  USHORT tempah;
+
+  SiS_SetSCLKLow(SiS_Pr);				           /* (SC->low) */
+  SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,
+  		  SiS_Pr->SiS_DDC_Index,
+                  SiS_Pr->SiS_DDC_NData,
+		  SiS_Pr->SiS_DDC_Data);     			   /* (SD->high) */
+  SiS_SetSCLKHigh(SiS_Pr);				           /* SC->high = clock impulse for ack */
+  tempah = SiS_GetReg(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index); /* Read SD */
+  SiS_SetSCLKLow(SiS_Pr);				           /* SC->low = end of clock impulse */
+  if(tempah & SiS_Pr->SiS_DDC_Data) return(1);			   /* Ack OK if bit = 0 */
+  else return(0);
+}
+
+/* End of I2C functions ----------------------- */
+
+
+/* =============== SiS 315/330 O.E.M. ================= */
+
+#ifdef SIS315H
+
+static USHORT
+GetRAMDACromptr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+  USHORT romptr;
+
+  if(HwInfo->jChipType < SIS_330) {
+     romptr = SISGETROMW(0x128);
+     if(SiS_Pr->SiS_VBType & VB_SIS301B302B)
+        romptr = SISGETROMW(0x12a);
+  } else {
+     romptr = SISGETROMW(0x1a8);
+     if(SiS_Pr->SiS_VBType & VB_SIS301B302B)
+        romptr = SISGETROMW(0x1aa);
+  }
+  return(romptr);
+}
+
+static USHORT
+GetLCDromptr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+  USHORT romptr;
+
+  if(HwInfo->jChipType < SIS_330) {
+     romptr = SISGETROMW(0x120);
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)
+        romptr = SISGETROMW(0x122);
+  } else {
+     romptr = SISGETROMW(0x1a0);
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)
+        romptr = SISGETROMW(0x1a2);
+  }
+  return(romptr);
+}
+
+static USHORT
+GetTVromptr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+  USHORT romptr;
+
+  if(HwInfo->jChipType < SIS_330) {
+     romptr = SISGETROMW(0x114);
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)
+        romptr = SISGETROMW(0x11a);
+  } else {
+     romptr = SISGETROMW(0x194);
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)
+        romptr = SISGETROMW(0x19a);
+  }
+  return(romptr);
+}
+
+static USHORT
+GetLCDPtrIndexBIOS(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  USHORT index;
+
+  if((IS_SIS650) && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) {
+     if(!(SiS_IsNotM650orLater(SiS_Pr, HwInfo))) {
+        if((index = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) & 0xf0)) {
+	   index >>= 4;
+	   index *= 3;
+	   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) index += 2;
+           else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) index++;
+           return index;
+	}
+     }
+  }
+
+  index = SiS_GetBIOSLCDResInfo(SiS_Pr) & 0x0F;
+  if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050)      index -= 5;
+  else if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) index -= 6;
+  index--;
+  index *= 3;
+  if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) index += 2;
+  else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) index++;
+  return index;
+}
+
+static USHORT
+GetLCDPtrIndex(SiS_Private *SiS_Pr)
+{
+  USHORT index;
+
+  index = ((SiS_GetBIOSLCDResInfo(SiS_Pr) & 0x0F) - 1) * 3;
+  if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)         index += 2;
+  else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) index++;
+  return index;
+}
+
+static USHORT
+GetTVPtrIndex(SiS_Private *SiS_Pr)
+{
+  USHORT index;
+
+  index = 0;
+  if(SiS_Pr->SiS_TVMode & TVSetPAL) index = 1;
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) index = 2;
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) index = 0;
+
+  index <<= 1;
+
+  if((SiS_Pr->SiS_VBInfo & SetInSlaveMode) &&
+     (SiS_Pr->SiS_TVMode & TVSetTVSimuMode)) {
+     index++;
+  }
+
+  return index;
+}
+
+static ULONG
+GetOEMTVPtr661_2_GEN(SiS_Private *SiS_Pr, int addme)
+{
+   USHORT index = 0, temp = 0;
+
+   if(SiS_Pr->SiS_TVMode & TVSetPAL)   index = 1;
+   if(SiS_Pr->SiS_TVMode & TVSetPALM)  index = 2;
+   if(SiS_Pr->SiS_TVMode & TVSetPALN)  index = 3;
+   if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) index = 6;
+   if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) {
+      index = 4;
+      if(SiS_Pr->SiS_TVMode & TVSetPALM)  index++;
+      if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) index = 7;
+   }
+
+   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+      if((!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+         (SiS_Pr->SiS_TVMode & TVSetTVSimuMode)) {
+	 index += addme;
+	 temp++;
+      }
+      temp += 0x0100;
+   }
+   return(ULONG)(index | (temp << 16));
+}
+
+static ULONG
+GetOEMTVPtr661_2_OLD(SiS_Private *SiS_Pr)
+{
+   return(GetOEMTVPtr661_2_GEN(SiS_Pr, 8));
+}
+
+#if 0
+static ULONG
+GetOEMTVPtr661_2_NEW(SiS_Private *SiS_Pr)
+{
+   return(GetOEMTVPtr661_2_GEN(SiS_Pr, 6));
+}
+#endif
+
+static int
+GetOEMTVPtr661(SiS_Private *SiS_Pr)
+{
+   int index = 0;
+
+   if(SiS_Pr->SiS_TVMode & TVSetPAL)          index = 2;
+   if(SiS_Pr->SiS_ROMNew) {
+      if(SiS_Pr->SiS_TVMode & TVSetYPbPr525i) index = 4;
+      if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) index = 6;
+      if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) index = 8;
+      if(SiS_Pr->SiS_TVMode & TVSetHiVision)  index = 10;
+   } else {
+      if(SiS_Pr->SiS_TVMode & TVSetHiVision)  index = 4;
+      if(SiS_Pr->SiS_TVMode & TVSetYPbPr525i) index = 6;
+      if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) index = 8;
+      if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) index = 10;
+   }
+
+   if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) index++;
+
+   return index;
+}
+
+static void
+SetDelayComp(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo)
+{
+  UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+  USHORT delay=0,index,myindex,temp,romptr=0;
+  BOOLEAN dochiptest = TRUE;
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+     SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x20,0xbf);
+  } else {
+     SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x35,0x7f);
+  }
+
+  /* Find delay (from ROM, internal tables, PCI subsystem) */
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) {			/* ------------ VGA */
+     
+     if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) {
+        romptr = GetRAMDACromptr(SiS_Pr, HwInfo);
+     }
+     if(romptr) delay = ROMAddr[romptr];
+     else {
+        delay = 0x04;
+        if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
+	   if(IS_SIS650) {
+	      delay = 0x0a;
+	   } else if(IS_SIS740) {
+	      delay = 0x00;
+	   } else if(HwInfo->jChipType < SIS_330) {
+	      delay = 0x0c;
+	   } else {
+	      delay = 0x0c;
+	   }
+	} else if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+           delay = 0x00;
+	}
+     }
+
+  } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD|SetCRT2ToLCDA)) {  /* ----------	LCD/LCDA */
+
+     BOOLEAN gotitfrompci = FALSE;
+
+     /* Could we detect a PDC for LCD or did we get a user-defined? If yes, use it */
+
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+	if(SiS_Pr->PDC != -1) {
+           SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0xf0,((SiS_Pr->PDC >> 1) & 0x0f));
+	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x35,0x7f,((SiS_Pr->PDC & 0x01) << 7));
+	   return;
+	}
+     } else {
+	if(SiS_Pr->PDCA != -1) {
+	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0x0f,((SiS_Pr->PDCA << 3) & 0xf0));
+	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x20,0xbf,((SiS_Pr->PDCA & 0x01) << 6));
+	   return;
+	}
+     }
+
+     /* Custom Panel? */
+
+     if(SiS_Pr->SiS_LCDResInfo == Panel_Custom) {
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+	   delay = 0x00;
+	   if((SiS_Pr->PanelXRes <= 1280) && (SiS_Pr->PanelYRes <= 1024)) {
+	      delay = 0x20;
+	   }
+	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0x0f,delay);
+	} else {
+	   delay = 0x0c;
+	   if(SiS_Pr->SiS_VBType & VB_SIS301C) delay = 0x03;
+	   else if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+	      if(IS_SIS740) delay = 0x01;
+	      else          delay = 0x03;
+	   }
+	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0xf0,delay);
+	}
+        return;
+     }
+
+     /* This is a piece of typical SiS crap: They code the OEM LCD
+      * delay into the code, at no defined place in the BIOS.
+      * We now have to start doing a PCI subsystem check here.
+      */
+
+     switch(SiS_Pr->SiS_CustomT) {
+     case CUT_COMPAQ1280:
+     case CUT_COMPAQ12802:
+	if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) {
+	   gotitfrompci = TRUE;
+	   dochiptest = FALSE;
+	   delay = 0x03;
+	}
+	break;
+     case CUT_CLEVO1400:
+     case CUT_CLEVO14002:
+	gotitfrompci = TRUE;
+	dochiptest = FALSE;
+	delay = 0x02;
+	break;
+     case CUT_CLEVO1024:
+     case CUT_CLEVO10242:
+        if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+	   gotitfrompci = TRUE;
+	   dochiptest = FALSE;
+	   delay = 0x33;
+	   SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2D,delay);
+	   delay &= 0x0f;
+	}
+	break;
+     }
+
+     /* Could we find it through the PCI ID? If no, use ROM or table */
+
+     if(!gotitfrompci) {
+
+        index = GetLCDPtrIndexBIOS(SiS_Pr, HwInfo);
+        myindex = GetLCDPtrIndex(SiS_Pr);
+
+        if(IS_SIS650 && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) {
+
+           if(SiS_IsNotM650orLater(SiS_Pr, HwInfo)) {
+
+              if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) {
+	         /* Always use the second pointer on 650; some BIOSes */
+                 /* still carry old 301 data at the first location    */
+	         /* romptr = SISGETROMW(0x120);                       */
+	         /* if(SiS_Pr->SiS_VBType & VB_SIS302LV)              */
+	         romptr = SISGETROMW(0x122);
+	         if(!romptr) return;
+	         delay = ROMAddr[(romptr + index)];
+	      } else {
+                 delay = SiS310_LCDDelayCompensation_650301LV[myindex];
+	      }
+
+          } else {
+
+             delay = SiS310_LCDDelayCompensation_651301LV[myindex];
+	     if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV))
+	        delay = SiS310_LCDDelayCompensation_651302LV[myindex];
+
+          }
+
+        } else if(SiS_Pr->SiS_UseROM 			      &&
+		  (!(SiS_Pr->SiS_ROMNew))		      &&
+	          (SiS_Pr->SiS_LCDResInfo != Panel_1280x1024) &&
+		  (SiS_Pr->SiS_LCDResInfo != Panel_1280x768)  &&
+		  (SiS_Pr->SiS_LCDResInfo != Panel_1280x960)) {
+
+	   /* Data for 1280x1024 wrong in 301B BIOS */
+           romptr = GetLCDromptr(SiS_Pr, HwInfo);
+	   if(!romptr) return;
+	   delay = ROMAddr[(romptr + index)];
+
+        } else if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+
+	   if(IS_SIS740) delay = 0x03;
+	   else          delay = 0x00;
+
+	} else {
+
+           delay = SiS310_LCDDelayCompensation_301[myindex];
+	   if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+	      if(IS_SIS740) delay = 0x01;
+	      else if(HwInfo->jChipType <= SIS_315PRO) delay = SiS310_LCDDelayCompensation_3xx301LV[myindex];
+	      else          delay = SiS310_LCDDelayCompensation_650301LV[myindex];
+	   } else if(SiS_Pr->SiS_VBType & VB_SIS301C) {
+	      if(IS_SIS740) delay = 0x01;  /* ? */
+	      else          delay = 0x03;
+	   } else if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
+	      if(IS_SIS740) delay = 0x01;
+	      else          delay = SiS310_LCDDelayCompensation_3xx301B[myindex];
+	   }
+
+        }
+
+     }  /* got it from PCI */
+
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,0x0F,((delay << 4) & 0xf0));
+	dochiptest = FALSE;
+     }
+     
+  } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {			/* ------------ TV */
+
+     index = GetTVPtrIndex(SiS_Pr);
+     
+     if(IS_SIS650 && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) {
+
+        if(SiS_IsNotM650orLater(SiS_Pr,HwInfo)) {
+
+           if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) {
+	      /* Always use the second pointer on 650; some BIOSes */
+              /* still carry old 301 data at the first location    */
+              /* romptr = SISGETROMW(0x114);			   */
+	      /* if(SiS_Pr->SiS_VBType & VB_SIS302LV)              */
+	      romptr = SISGETROMW(0x11a);
+	      if(!romptr) return;
+	      delay = ROMAddr[romptr + index];
+
+	   } else {
+
+	      delay = SiS310_TVDelayCompensation_301B[index];
+
+	   }
+
+        } else {
+
+           switch(SiS_Pr->SiS_CustomT) {
+	   case CUT_COMPAQ1280:
+	   case CUT_COMPAQ12802:
+	   case CUT_CLEVO1400:
+	   case CUT_CLEVO14002:
+	      delay = 0x02;
+	      dochiptest = FALSE;
+	      break;
+	   case CUT_CLEVO1024:
+	   case CUT_CLEVO10242:
+	      delay = 0x03;
+	      dochiptest = FALSE;
+   	      break;
+	   default:
+              delay = SiS310_TVDelayCompensation_651301LV[index];
+	      if(SiS_Pr->SiS_VBType & VB_SIS302LV) {
+	         delay = SiS310_TVDelayCompensation_651302LV[index];
+	      }
+	   }
+        }
+
+     } else if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) {
+
+        romptr = GetTVromptr(SiS_Pr, HwInfo);
+	if(!romptr) return;
+	delay = ROMAddr[romptr + index];
+
+     } else if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+
+        delay = SiS310_TVDelayCompensation_LVDS[index];
+
+     } else {
+
+	delay = SiS310_TVDelayCompensation_301[index];
+        if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+	   if(IS_SIS740) {
+	      delay = SiS310_TVDelayCompensation_740301B[index];
+	      /* LV: use 301 data? BIOS bug? */
+	   } else {
+              delay = SiS310_TVDelayCompensation_301B[index];
+	      if(SiS_Pr->SiS_VBType & VB_SIS301C) delay = 0x02;
+	   }
+	}
+
+     }
+
+     if(SiS_LCDAEnabled(SiS_Pr, HwInfo)) {
+	delay &= 0x0f;
+	dochiptest = FALSE;
+     }
+    
+  } else return;
+
+  /* Write delay */
+
+  if(SiS_Pr->SiS_VBType & VB_SISVB) {
+
+     if(IS_SIS650 && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV) && dochiptest) {
+
+        temp = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) & 0xf0) >> 4;
+        if(temp == 8) {		/* 1400x1050 BIOS (COMPAL) */
+	   delay &= 0x0f;
+	   delay |= 0xb0;
+        } else if(temp == 6) {
+           delay &= 0x0f;
+	   delay |= 0xc0;
+        } else if(temp > 7) {	/* 1280x1024 BIOS (which one?) */
+	   delay = 0x35;
+        }
+        SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2D,delay);
+
+     } else {
+
+        SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,0xF0,delay);
+
+     }
+
+  } else {  /* LVDS */
+
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+        SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,0xF0,delay);
+     } else {
+        if(IS_SIS650 && (SiS_Pr->SiS_IF_DEF_CH70xx != 0)) {
+           delay <<= 4;
+           SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,0x0F,delay);
+        } else {
+           SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,0xF0,delay);
+        }
+     }
+
+  }
+
+}
+
+static void
+SetAntiFlicker(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+               USHORT ModeNo,USHORT ModeIdIndex)
+{
+  UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+  USHORT index,temp,temp1,romptr=0;
+
+  if(SiS_Pr->SiS_TVMode & (TVSetYPbPr750p|TVSetYPbPr525p)) return;
+
+  if(ModeNo<=0x13)
+     index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].VB_StTVFlickerIndex;
+  else
+     index = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].VB_ExtTVFlickerIndex;
+
+  temp = GetTVPtrIndex(SiS_Pr);
+  temp >>= 1;  	  /* 0: NTSC/YPbPr, 1: PAL, 2: HiTV */
+  temp1 = temp;
+
+  if(SiS_Pr->SiS_UseROM && (!(SiS_Pr->SiS_ROMNew))) {
+     if(HwInfo->jChipType >= SIS_661) {
+        temp1 = GetOEMTVPtr661(SiS_Pr);
+        temp1 >>= 1;
+        romptr = SISGETROMW(0x260);
+        if(HwInfo->jChipType >= SIS_760) {
+	   romptr = SISGETROMW(0x360);
+	}
+     } else if(HwInfo->jChipType >= SIS_330) {
+        romptr = SISGETROMW(0x192);
+     } else {
+        romptr = SISGETROMW(0x112);
+     }
+  }
+
+  if(romptr) {
+     temp1 <<= 1;
+     temp = ROMAddr[romptr + temp1 + index];
+  } else {
+     temp = SiS310_TVAntiFlick1[temp][index];
+  }
+  temp <<= 4;
+
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x0A,0x8f,temp);  /* index 0A D[6:4] */
+}
+
+static void
+SetEdgeEnhance(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+               USHORT ModeNo,USHORT ModeIdIndex)
+{
+  UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+  USHORT index,temp,temp1,romptr=0;
+
+  temp = temp1 = GetTVPtrIndex(SiS_Pr) >> 1; 	/* 0: NTSC/YPbPr, 1: PAL, 2: HiTV */
+
+  if(ModeNo <= 0x13)
+     index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].VB_StTVEdgeIndex;
+  else
+     index = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].VB_ExtTVEdgeIndex;
+
+  if(SiS_Pr->SiS_UseROM && (!(SiS_Pr->SiS_ROMNew))) {
+     if(HwInfo->jChipType >= SIS_661) {
+        romptr = SISGETROMW(0x26c);
+        if(HwInfo->jChipType >= SIS_760) {
+	   romptr = SISGETROMW(0x36c);
+	}
+	temp1 = GetOEMTVPtr661(SiS_Pr);
+        temp1 >>= 1;
+     } else if(HwInfo->jChipType >= SIS_330) {
+        romptr = SISGETROMW(0x1a4);
+     } else {
+        romptr = SISGETROMW(0x124);
+     }
+  }
+
+  if(romptr) {
+     temp1 <<= 1;
+     temp = ROMAddr[romptr + temp1 + index];
+  } else {
+     temp = SiS310_TVEdge1[temp][index];
+  }
+  temp <<= 5;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x3A,0x1F,temp);  /* index 0A D[7:5] */
+}
+
+static void
+SetYFilter(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+           USHORT ModeNo,USHORT ModeIdIndex)
+{
+  USHORT index, temp, i, j;
+
+  if(ModeNo <= 0x13) {
+     index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].VB_StTVYFilterIndex;
+  } else {
+     index = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].VB_ExtTVYFilterIndex;
+  }
+
+  temp = GetTVPtrIndex(SiS_Pr) >> 1;  /* 0: NTSC/YPbPr, 1: PAL, 2: HiTV */
+
+  if(SiS_Pr->SiS_TVMode & TVSetNTSCJ)	     temp = 1;  /* NTSC-J uses PAL */
+  else if(SiS_Pr->SiS_TVMode & TVSetPALM)    temp = 3;  /* PAL-M */
+  else if(SiS_Pr->SiS_TVMode & TVSetPALN)    temp = 4;  /* PAL-N */
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) temp = 1;  /* HiVision uses PAL */
+
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+     for(i=0x35, j=0; i<=0x38; i++, j++) {
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS310_TVYFilter2[temp][index][j]);
+     }
+     for(i=0x48; i<=0x4A; i++, j++) {
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS310_TVYFilter2[temp][index][j]);
+     }
+  } else {
+     for(i=0x35, j=0; i<=0x38; i++, j++) {
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS310_TVYFilter1[temp][index][j]);
+     }
+  }
+}
+
+static void
+SetPhaseIncr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+             USHORT ModeNo,USHORT ModeIdIndex)
+{
+  UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+  USHORT index,temp,i,j,resinfo,romptr=0;
+  ULONG  lindex;
+
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) return;
+
+  /* NTSC-J data not in BIOS, and already set in SetGroup2 */
+  if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) return;
+
+  if((HwInfo->jChipType >= SIS_661) || SiS_Pr->SiS_ROMNew) {
+     lindex = GetOEMTVPtr661_2_OLD(SiS_Pr) & 0xffff;
+     lindex <<= 2;
+     for(j=0, i=0x31; i<=0x34; i++, j++) {
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS661_TVPhase[lindex + j]);
+     }
+     return;
+  }
+
+  /* PAL-M, PAL-N not in BIOS, and already set in SetGroup2 */
+  if(SiS_Pr->SiS_TVMode & (TVSetPALM | TVSetPALN)) return;
+
+  if(ModeNo<=0x13) {
+     resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+  } else {
+     resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+  }
+
+  temp = GetTVPtrIndex(SiS_Pr);
+  /* 0: NTSC Graphics, 1: NTSC Text,    2: PAL Graphics,
+   * 3: PAL Text,      4: HiTV Graphics 5: HiTV Text
+   */
+  if(SiS_Pr->SiS_UseROM) {
+     romptr = SISGETROMW(0x116);
+     if(HwInfo->jChipType >= SIS_330) {
+        romptr = SISGETROMW(0x196);
+     }
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+        romptr = SISGETROMW(0x11c);
+	if(HwInfo->jChipType >= SIS_330) {
+	   romptr = SISGETROMW(0x19c);
+	}
+	if((SiS_Pr->SiS_VBInfo & SetInSlaveMode) && (!(SiS_Pr->SiS_TVMode & TVSetTVSimuMode))) {
+	   romptr = SISGETROMW(0x116);
+	   if(HwInfo->jChipType >= SIS_330) {
+              romptr = SISGETROMW(0x196);
+           }
+	}
+     }
+  }
+  if(romptr) {
+     romptr += (temp << 2);
+     for(j=0, i=0x31; i<=0x34; i++, j++) {
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,i,ROMAddr[romptr + j]);
+     }
+  } else {
+     index = temp % 2;
+     temp >>= 1;          /* 0:NTSC, 1:PAL, 2:HiTV */
+     for(j=0, i=0x31; i<=0x34; i++, j++) {
+        if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV))
+	   SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS310_TVPhaseIncr1[temp][index][j]);
+        else if((!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) || (SiS_Pr->SiS_TVMode & TVSetTVSimuMode))
+           SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS310_TVPhaseIncr2[temp][index][j]);
+        else
+           SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS310_TVPhaseIncr1[temp][index][j]);
+     }
+  }
+
+  if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (!(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision))) {
+     if((!(SiS_Pr->SiS_TVMode & (TVSetPAL | TVSetYPbPr525p | TVSetYPbPr750p))) && (ModeNo > 0x13)) {
+        if((resinfo == SIS_RI_640x480) ||
+	   (resinfo == SIS_RI_800x600)) {
+	   SiS_SetReg(SiS_Pr->SiS_Part2Port,0x31,0x21);
+	   SiS_SetReg(SiS_Pr->SiS_Part2Port,0x32,0xf0);
+	   SiS_SetReg(SiS_Pr->SiS_Part2Port,0x33,0xf5);
+	   SiS_SetReg(SiS_Pr->SiS_Part2Port,0x34,0x7f);
+	} else if(resinfo == SIS_RI_1024x768) {
+	   SiS_SetReg(SiS_Pr->SiS_Part2Port,0x31,0x1e);
+	   SiS_SetReg(SiS_Pr->SiS_Part2Port,0x32,0x8b);
+	   SiS_SetReg(SiS_Pr->SiS_Part2Port,0x33,0xfb);
+	   SiS_SetReg(SiS_Pr->SiS_Part2Port,0x34,0x7b);
+	}
+     }
+  }
+}
+
+static void
+SetDelayComp661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo,
+                USHORT ModeIdIndex, USHORT RTI)
+{
+   USHORT delay = 0, romptr = 0, index, lcdpdcindex;
+   UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+
+   if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToTV | SetCRT2ToLCD | SetCRT2ToLCDA | SetCRT2ToRAMDAC)))
+      return;
+
+   /* 1. New ROM: VGA2 and LCD/LCDA-Pass1:1 */
+   /* (If a custom mode is used, Pass1:1 is always set; hence we do this:) */
+
+   if(SiS_Pr->SiS_ROMNew) {
+      if((SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) 			||
+         ((SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) &&
+	  (SiS_Pr->SiS_LCDInfo & LCDPass11))) {
+         index = 25;
+         if(SiS_Pr->UseCustomMode) {
+	    index = SiS_Pr->CSRClock;
+         } else if(ModeNo > 0x13) {
+            index = SiS_GetVCLK2Ptr(SiS_Pr,ModeNo,ModeIdIndex,RTI,HwInfo);
+            index = SiS_Pr->SiS_VCLKData[index].CLOCK;
+         }
+	 if(index < 25) index = 25;
+         index = ((index / 25) - 1) << 1;
+         if((ROMAddr[0x5b] & 0x80) || (SiS_Pr->SiS_VBInfo & (SetCRT2ToRAMDAC | SetCRT2ToLCD))) {
+	    index++;
+	 }
+	 romptr = SISGETROMW(0x104);
+         delay = ROMAddr[romptr + index];
+         if(SiS_Pr->SiS_VBInfo & (SetCRT2ToRAMDAC | SetCRT2ToLCD)) {
+            SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0xf0,((delay >> 1) & 0x0f));
+            SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x35,0x7f,((delay & 0x01) << 7));
+         } else {
+            SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0x0f,((delay << 3) & 0xf0));
+	    SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x20,0xbf,((delay & 0x01) << 6));
+         }
+         return;
+      }
+   }
+
+   /* 2. Old ROM: VGA2 and LCD/LCDA-Pass 1:1 */
+
+   if(SiS_Pr->UseCustomMode) delay = 0x04;
+   else if(ModeNo <= 0x13)   delay = 0x04;
+   else                      delay = (SiS_Pr->SiS_RefIndex[RTI].Ext_PDC >> 4);
+   delay |= (delay << 8);
+
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+
+      /* 3. TV */
+
+      index = GetOEMTVPtr661(SiS_Pr);
+      if(SiS_Pr->SiS_ROMNew) {
+         romptr = SISGETROMW(0x106);
+	 if(SiS_Pr->SiS_VBType & VB_UMC) romptr += 12;
+         delay = ROMAddr[romptr + index];
+      } else {
+         delay = 0x04;
+	 if(index > 3) delay = 0;
+      }
+
+   } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+
+      /* 4. LCD, LCDA (for new ROM only LV and non-Pass 1:1) */
+
+      if( (SiS_Pr->SiS_LCDResInfo != Panel_Custom) &&
+          ((romptr = GetLCDStructPtr661_2(SiS_Pr, HwInfo))) ) {
+
+	 lcdpdcindex = (SiS_Pr->SiS_VBType & VB_UMC) ? 14 : 12;
+
+	 /* For LVDS (and sometimes TMDS), the BIOS must know about the correct value */
+	 delay = ROMAddr[romptr + lcdpdcindex + 1];	/* LCD  */
+	 delay |= (ROMAddr[romptr + lcdpdcindex] << 8);	/* LCDA */
+
+      } else {
+
+         /* TMDS: Set our own, since BIOS has no idea */
+	 /* (This is done on >=661 only, since <661 is calling this only for LVDS) */
+         if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
+	    switch(SiS_Pr->SiS_LCDResInfo) {
+	    case Panel_1024x768:  delay = 0x0008; break;
+	    case Panel_1280x720:  delay = 0x0004; break;
+	    case Panel_1280x768:
+	    case Panel_1280x768_2:delay = 0x0004; break;
+	    case Panel_1280x800:
+	    case Panel_1280x800_2:delay = 0x0004; break; /* Verified for 1280x800 */
+	    case Panel_1280x1024: delay = 0x1e04; break;
+	    case Panel_1400x1050: delay = 0x0004; break;
+	    case Panel_1600x1200: delay = 0x0400; break;
+	    case Panel_1680x1050: delay = 0x0e04; break;
+	    default:
+               if((SiS_Pr->PanelXRes <= 1024) && (SiS_Pr->PanelYRes <= 768)) {
+	          delay = 0x0008;
+	       } else if((SiS_Pr->PanelXRes == 1280) && (SiS_Pr->PanelYRes == 1024)) {
+	          delay = 0x1e04;
+               } else if((SiS_Pr->PanelXRes <= 1400) && (SiS_Pr->PanelYRes <= 1050)) {
+	          delay = 0x0004;
+	       } else if((SiS_Pr->PanelXRes <= 1600) && (SiS_Pr->PanelYRes <= 1200)) {
+	          delay = 0x0400;
+               } else
+	          delay = 0x0e04;
+	       break;
+	    }
+         }
+
+	 /* Override by detected or user-set values */
+	 /* (but only if, for some reason, we can't read value from BIOS) */
+         if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (SiS_Pr->PDC != -1)) {
+            delay = SiS_Pr->PDC & 0x1f;
+         }
+         if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) && (SiS_Pr->PDCA != -1)) {
+            delay = (SiS_Pr->PDCA & 0x1f) << 8;
+         }
+
+      }
+
+   }
+
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+      delay >>= 8;
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0x0f,((delay << 3) & 0xf0));
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x20,0xbf,((delay & 0x01) << 6));
+   } else {
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0xf0,((delay >> 1) & 0x0f));
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x35,0x7f,((delay & 0x01) << 7));
+   }
+}
+
+static void
+SetCRT2SyncDither661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo, USHORT RTI)
+{
+   USHORT infoflag;
+   UCHAR temp;
+
+   if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+
+      if(ModeNo <= 0x13) {
+         infoflag = SiS_GetRegByte(SiS_Pr->SiS_P3ca+2);
+      } else if(SiS_Pr->UseCustomMode) {
+         infoflag = SiS_Pr->CInfoFlag;
+      } else {
+         infoflag = SiS_Pr->SiS_RefIndex[RTI].Ext_InfoFlag;
+      }
+
+      if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
+         infoflag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37); /* No longer check D5 */
+      }
+
+      infoflag &= 0xc0;
+
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+         temp = (infoflag >> 6) | 0x0c;
+         if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) {
+	    temp ^= 0x04;
+	    if(SiS_Pr->SiS_ModeType >= Mode24Bpp) temp |= 0x10;
+	 }
+         SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xe0,temp);
+      } else {
+         temp = 0x30;
+         if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) temp = 0x20;
+         temp |= infoflag;
+         SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0f,temp);
+         temp = 0;
+         if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) {
+	    if(SiS_Pr->SiS_ModeType >= Mode24Bpp) temp |= 0x80;
+	 }
+         SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1a,0x7f,temp);
+      }
+
+   }
+}
+
+static void
+SetPanelParms661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+   UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+   USHORT romptr, temp1, temp2;
+
+   if(SiS_Pr->SiS_VBType & (VB_SIS301LV | VB_SIS302LV | VB_SIS302ELV)) {
+      if(SiS_Pr->LVDSHL != -1) {
+         SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,SiS_Pr->LVDSHL);
+      }
+   }
+
+   if(SiS_Pr->SiS_ROMNew) {
+
+      if((romptr = GetLCDStructPtr661_2(SiS_Pr, HwInfo))) {
+         if(SiS_Pr->SiS_VBType & (VB_SIS301LV | VB_SIS302LV | VB_SIS302ELV)) {
+            temp1 = (ROMAddr[romptr] & 0x03) | 0x0c;
+	    temp2 = 0xfc;
+	    if(SiS_Pr->LVDSHL != -1) {
+	      temp1 &= 0xfc;
+	      temp2 = 0xf3;
+	    }
+	    SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,temp2,temp1);
+         }
+	 if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+            temp1 = (ROMAddr[romptr + 1] & 0x80) >> 1;
+            SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0d,0xbf,temp1);
+	 }
+      }
+
+   }
+}
+
+static void
+SiS_OEM310Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+                  USHORT ModeNo,USHORT ModeIdIndex,USHORT RRTI)
+{
+   if((SiS_Pr->SiS_ROMNew) && (SiS_Pr->SiS_VBType & VB_SISLVDS)) {
+      SetDelayComp661(SiS_Pr,HwInfo,ModeNo,ModeIdIndex,RRTI);
+      if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+         SetCRT2SyncDither661(SiS_Pr,HwInfo,ModeNo,RRTI);
+         SetPanelParms661(SiS_Pr,HwInfo);
+      }
+   } else {
+      SetDelayComp(SiS_Pr,HwInfo,ModeNo);
+   }
+
+   if((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) {
+      SetAntiFlicker(SiS_Pr,HwInfo,ModeNo,ModeIdIndex);
+      SetPhaseIncr(SiS_Pr,HwInfo,ModeNo,ModeIdIndex);
+      SetYFilter(SiS_Pr,HwInfo,ModeNo,ModeIdIndex);
+      if(SiS_Pr->SiS_VBType & VB_SIS301) {
+         SetEdgeEnhance(SiS_Pr,HwInfo,ModeNo,ModeIdIndex);
+      }
+   }
+}
+
+static void
+SiS_OEM661Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+                  USHORT ModeNo,USHORT ModeIdIndex, USHORT RRTI)
+{
+   if(SiS_Pr->SiS_VBType & VB_SISVB) {
+
+      SetDelayComp661(SiS_Pr,HwInfo,ModeNo,ModeIdIndex,RRTI);
+
+      if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+         SetCRT2SyncDither661(SiS_Pr,HwInfo,ModeNo,RRTI);
+         SetPanelParms661(SiS_Pr,HwInfo);
+      }
+
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+         SetPhaseIncr(SiS_Pr,HwInfo,ModeNo,ModeIdIndex);
+         SetYFilter(SiS_Pr,HwInfo,ModeNo,ModeIdIndex);
+         SetAntiFlicker(SiS_Pr,HwInfo,ModeNo,ModeIdIndex);
+         if(SiS_Pr->SiS_VBType & VB_SIS301) {
+            SetEdgeEnhance(SiS_Pr,HwInfo,ModeNo,ModeIdIndex);
+         }
+      }
+   }
+}
+
+/* FinalizeLCD
+ * This finalizes some CRT2 registers for the very panel used.
+ * If we have a backup if these registers, we use it; otherwise
+ * we set the register according to most BIOSes. However, this
+ * function looks quite different in every BIOS, so you better
+ * pray that we have a backup...
+ */
+static void
+SiS_FinalizeLCD(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+                PSIS_HW_INFO HwInfo)
+{
+  USHORT tempcl,tempch,tempbl,tempbh,tempbx,tempax,temp;
+  USHORT resinfo,modeflag;
+
+  if(!(SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) return;
+  if(SiS_Pr->SiS_ROMNew) return;
+
+  if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+     if(SiS_Pr->LVDSHL != -1) {
+        SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,SiS_Pr->LVDSHL);
+     }
+  }
+
+  if(SiS_Pr->SiS_LCDResInfo == Panel_Custom) return;
+  if(SiS_Pr->UseCustomMode) return;
+
+  switch(SiS_Pr->SiS_CustomT) {
+  case CUT_COMPAQ1280:
+  case CUT_COMPAQ12802:
+  case CUT_CLEVO1400:
+  case CUT_CLEVO14002:
+     return;
+  }
+
+  if(ModeNo <= 0x13) {
+     resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+     modeflag =  SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  } else {
+     resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+     modeflag =  SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+  }
+
+  if(IS_SIS650) {
+     if(!(SiS_GetReg(SiS_Pr->SiS_P3d4, 0x5f) & 0xf0)) {
+        if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) {
+	   SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x02);
+	} else {
+           SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x03);
+	}
+     }
+  }
+
+  if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) {
+     if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+        /* Maybe all panels? */
+        if(SiS_Pr->LVDSHL == -1) {
+           SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,0x01);
+	}
+	return;
+     }
+  }
+
+  if(SiS_Pr->SiS_CustomT == CUT_CLEVO10242) {
+     if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+        if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+	   if(SiS_Pr->LVDSHL == -1) {
+	      /* Maybe all panels? */
+              SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,0x01);
+	   }
+	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+	      tempch = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4;
+	      if(tempch == 3) {
+	         SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x02);
+	         SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,0x25);
+	         SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1c,0x00);
+	         SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1d,0x1b);
+	      }
+	   }
+	   return;
+	}
+     }
+  }
+
+  if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+     if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+	if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
+	   SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2a,0x00);
+#ifdef SET_EMI
+	   SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c);
+#endif
+	   SiS_SetReg(SiS_Pr->SiS_Part4Port,0x34,0x10);
+	}
+     } else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) {
+        if(SiS_Pr->LVDSHL == -1) {
+           /* Maybe ACER only? */
+           SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,0x01);
+	}
+     }
+     tempch = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4;
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+	if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) {
+	   SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1f,0x76);
+	} else if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+	   if(tempch == 0x03) {
+	      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x02);
+	      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,0x25);
+	      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1c,0x00);
+	      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1d,0x1b);
+	   }
+	   if((SiS_Pr->Backup == TRUE) && (SiS_Pr->Backup_Mode == ModeNo)) {
+	      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x14,SiS_Pr->Backup_14);
+	      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x15,SiS_Pr->Backup_15);
+	      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x16,SiS_Pr->Backup_16);
+	      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x17,SiS_Pr->Backup_17);
+	      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,SiS_Pr->Backup_18);
+	      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x19,SiS_Pr->Backup_19);
+	      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1a,SiS_Pr->Backup_1a);
+	      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,SiS_Pr->Backup_1b);
+	      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1c,SiS_Pr->Backup_1c);
+	      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1d,SiS_Pr->Backup_1d);
+	   } else if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {	/* 1.10.8w */
+	      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x14,0x90);
+	      if(ModeNo <= 0x13) {
+	         SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x11);
+		 if((resinfo == 0) || (resinfo == 2)) return;
+		 SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x18);
+		 if((resinfo == 1) || (resinfo == 3)) return;
+	      }
+	      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x02);
+	      if((ModeNo > 0x13) && (resinfo == SIS_RI_1024x768)) {
+	         SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x02);  /* 1.10.7u */
+#if 0
+	         tempbx = 806;  /* 0x326 */			 /* other older BIOSes */
+		 tempbx--;
+		 temp = tempbx & 0xff;
+		 SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,temp);
+		 temp = (tempbx >> 8) & 0x03;
+		 SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1d,0xf8,temp);
+#endif
+	      }
+	   } else if(ModeNo <= 0x13) {
+	      if(ModeNo <= 1) {
+		 SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x70);
+		 SiS_SetReg(SiS_Pr->SiS_Part1Port,0x19,0xff);
+		 SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,0x48);
+		 SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1d,0x12);
+	      }
+	      if(!(modeflag & HalfDCLK)) {
+		 SiS_SetReg(SiS_Pr->SiS_Part1Port,0x14,0x20);
+		 SiS_SetReg(SiS_Pr->SiS_Part1Port,0x15,0x1a);
+		 SiS_SetReg(SiS_Pr->SiS_Part1Port,0x16,0x28);
+		 SiS_SetReg(SiS_Pr->SiS_Part1Port,0x17,0x00);
+		 SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x4c);
+		 SiS_SetReg(SiS_Pr->SiS_Part1Port,0x19,0xdc);
+		 if(ModeNo == 0x12) {
+		    switch(tempch) {
+		       case 0:
+			  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x95);
+			  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x19,0xdc);
+			  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1a,0x10);
+			  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,0x95);
+			  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1c,0x48);
+			  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1d,0x12);
+			  break;
+		       case 2:
+			  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x95);
+			  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,0x48);
+			  break;
+		       case 3:
+			  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,0x95);
+			  break;
+		    }
+		 }
+	      }
+	   }
+	}
+     } else {
+        tempcl = tempbh = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x01);
+	tempcl &= 0x0f;
+	tempbh &= 0x70;
+	tempbh >>= 4;
+	tempbl = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x04);
+	tempbx = (tempbh << 8) | tempbl;
+	if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+	   if((resinfo == SIS_RI_1024x768) || (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD))) {
+	      if(SiS_Pr->SiS_SetFlag & LCDVESATiming) {
+	      	 tempbx = 770;
+	      } else {
+	         if(tempbx > 770) tempbx = 770;
+		 if(SiS_Pr->SiS_VGAVDE < 600) {
+		    tempax = 768 - SiS_Pr->SiS_VGAVDE;
+		    tempax >>= 4;  				 /* 1.10.7w; 1.10.6s: 3;  */
+		    if(SiS_Pr->SiS_VGAVDE <= 480)  tempax >>= 4; /* 1.10.7w; 1.10.6s: < 480; >>=1; */
+		    tempbx -= tempax;
+		 }
+	      }
+	   } else return;
+	}
+	temp = tempbx & 0xff;
+	SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,temp);
+	temp = ((tempbx & 0xff00) >> 4) | tempcl;
+	SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x01,0x80,temp);
+     }
+  }
+}
+
+#endif
+
+/*  =================  SiS 300 O.E.M. ================== */
+
+#ifdef SIS300
+
+static void
+SetOEMLCDData2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+               USHORT ModeNo,USHORT ModeIdIndex, USHORT RefTabIndex)
+{
+  USHORT crt2crtc=0, modeflag, myindex=0;
+  UCHAR  temp;
+  int i;
+
+  if(ModeNo <= 0x13) {
+     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+     crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  } else {
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+     crt2crtc = SiS_Pr->SiS_RefIndex[RefTabIndex].Ext_CRT2CRTC;
+  }
+
+  crt2crtc &= 0x3f;
+
+  if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) {
+     SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xdf);
+  }
+
+  if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) {
+     if(modeflag & HalfDCLK) myindex = 1;
+
+     if(SiS_Pr->SiS_SetFlag & LowModeTests) {
+        for(i=0; i<7; i++) {
+           if(barco_p1[myindex][crt2crtc][i][0]) {
+	      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,
+	                      barco_p1[myindex][crt2crtc][i][0],
+	   	   	      barco_p1[myindex][crt2crtc][i][2],
+			      barco_p1[myindex][crt2crtc][i][1]);
+	   }
+        }
+     }
+     temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00);
+     if(temp & 0x80) {
+        temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x18);
+        temp++;
+        SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,temp);
+     }
+  }
+}
+
+static USHORT
+GetOEMLCDPtr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, int Flag)
+{
+  UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+  USHORT tempbx=0,romptr=0;
+  UCHAR customtable300[] = {
+  	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+  };
+  UCHAR customtable630[] = {
+  	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+  };
+
+  if(HwInfo->jChipType == SIS_300) {
+
+    tempbx = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) & 0x0f;
+    if(SiS_Pr->SiS_VBType & VB_SIS301) tempbx &= 0x07;
+    tempbx -= 2;
+    if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx += 4;
+    if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+       if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 3;
+    }
+    if(SiS_Pr->SiS_UseROM) {
+       if(ROMAddr[0x235] & 0x80) {
+          tempbx = SiS_Pr->SiS_LCDTypeInfo;
+          if(Flag) {
+	     romptr = SISGETROMW(0x255);
+	     if(romptr) tempbx = ROMAddr[romptr + SiS_Pr->SiS_LCDTypeInfo];
+	     else       tempbx = customtable300[SiS_Pr->SiS_LCDTypeInfo];
+             if(tempbx == 0xFF) return 0xFFFF;
+          }
+	  tempbx <<= 1;
+	  if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx++;
+       }
+    }
+
+  } else {
+
+    if(Flag) {
+       if(SiS_Pr->SiS_UseROM) {
+          romptr = SISGETROMW(0x255);
+	  if(romptr) tempbx = ROMAddr[romptr + SiS_Pr->SiS_LCDTypeInfo];
+	  else 	     tempbx = 0xff;
+       } else {
+          tempbx = customtable630[SiS_Pr->SiS_LCDTypeInfo];
+       }
+       if(tempbx == 0xFF) return 0xFFFF;
+       tempbx <<= 2;
+       if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) tempbx += 2;
+       if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++;
+       return tempbx;
+    }
+    tempbx = SiS_Pr->SiS_LCDTypeInfo << 2;
+    if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) tempbx += 2;
+    if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++;
+
+  }
+
+  return tempbx;
+}
+
+static void
+SetOEMLCDDelay(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+               USHORT ModeNo,USHORT ModeIdIndex)
+{
+  UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+  USHORT index,temp,romptr=0;
+
+  if(SiS_Pr->SiS_LCDResInfo == Panel_Custom) return;
+
+  if(SiS_Pr->SiS_UseROM) {
+     if(!(ROMAddr[0x237] & 0x01)) return;
+     if(!(ROMAddr[0x237] & 0x02)) return;
+     romptr = SISGETROMW(0x24b);
+  }
+
+  /* The Panel Compensation Delay should be set according to tables
+   * here. Unfortunately, various BIOS versions don't case about
+   * a uniform way using eg. ROM byte 0x220, but use different
+   * hard coded delays (0x04, 0x20, 0x18) in SetGroup1().
+   * Thus we don't set this if the user select a custom pdc or if
+   * we otherwise detected a valid pdc.
+   */
+  if(SiS_Pr->PDC != -1) return;
+
+  temp = GetOEMLCDPtr(SiS_Pr,HwInfo, 0);
+
+  if(SiS_Pr->UseCustomMode)
+     index = 0;
+  else
+     index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_LCDDelayIndex;
+
+  if(HwInfo->jChipType != SIS_300) {
+     if(romptr) {
+	romptr += (temp * 2);
+	romptr = SISGETROMW(romptr);
+	romptr += index;
+	temp = ROMAddr[romptr];
+     } else {
+	if(SiS_Pr->SiS_VBType & VB_SISVB) {
+    	   temp = SiS300_OEMLCDDelay2[temp][index];
+	} else {
+           temp = SiS300_OEMLCDDelay3[temp][index];
+        }
+     }
+  } else {
+     if(SiS_Pr->SiS_UseROM && (ROMAddr[0x235] & 0x80)) {
+	if(romptr) {
+	   romptr += (temp * 2);
+	   romptr = SISGETROMW(romptr);
+	   romptr += index;
+	   temp = ROMAddr[romptr];
+	} else {
+	   temp = SiS300_OEMLCDDelay5[temp][index];
+	}
+     } else {
+        if(SiS_Pr->SiS_UseROM) {
+	   romptr = ROMAddr[0x249] | (ROMAddr[0x24a] << 8);
+	   if(romptr) {
+	      romptr += (temp * 2);
+	      romptr = SISGETROMW(romptr);
+	      romptr += index;
+	      temp = ROMAddr[romptr];
+	   } else {
+	      temp = SiS300_OEMLCDDelay4[temp][index];
+	   }
+	} else {
+	   temp = SiS300_OEMLCDDelay4[temp][index];
+	}
+     }
+  }
+  temp &= 0x3c;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x3C,temp);  /* index 0A D[6:4] */
+}
+
+static void
+SetOEMLCDData(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+              USHORT ModeNo,USHORT ModeIdIndex)
+{
+#if 0  /* Unfinished; Data table missing */
+  UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+  USHORT index,temp;
+
+  if((SiS_Pr->SiS_UseROM) {
+     if(!(ROMAddr[0x237] & 0x01)) return;
+     if(!(ROMAddr[0x237] & 0x04)) return;
+     /* No rom pointer in BIOS header! */
+  }
+
+  temp = GetOEMLCDPtr(SiS_Pr,HwInfo, 1);
+  if(temp = 0xFFFF) return;
+
+  index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex]._VB_LCDHIndex;
+  for(i=0x14, j=0; i<=0x17; i++, j++) {
+      SiS_SetReg(SiS_Pr->SiS_Part1Port,i,SiS300_LCDHData[temp][index][j]);
+  }
+  SiS_SetRegANDOR(SiS_SiS_Part1Port,0x1a, 0xf8, (SiS300_LCDHData[temp][index][j] & 0x07));
+
+  index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex]._VB_LCDVIndex;
+  SiS_SetReg(SiS_SiS_Part1Port,0x18, SiS300_LCDVData[temp][index][0]);
+  SiS_SetRegANDOR(SiS_SiS_Part1Port,0x19, 0xF0, SiS300_LCDVData[temp][index][1]);
+  SiS_SetRegANDOR(SiS_SiS_Part1Port,0x1A, 0xC7, (SiS300_LCDVData[temp][index][2] & 0x38));
+  for(i=0x1b, j=3; i<=0x1d; i++, j++) {
+      SiS_SetReg(SiS_Pr->SiS_Part1Port,i,SiS300_LCDVData[temp][index][j]);
+  }
+#endif
+}
+
+static USHORT
+GetOEMTVPtr(SiS_Private *SiS_Pr)
+{
+  USHORT index;
+
+  index = 0;
+  if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode))  index += 4;
+  if(SiS_Pr->SiS_VBType & VB_SISVB) {
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToSCART)  index += 2;
+     else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) index += 3;
+     else if(SiS_Pr->SiS_TVMode & TVSetPAL)   index += 1;
+  } else {
+     if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) index += 2;
+     if(SiS_Pr->SiS_TVMode & TVSetPAL)        index += 1;
+  }
+  return index;
+}
+
+static void
+SetOEMTVDelay(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+              USHORT ModeNo,USHORT ModeIdIndex)
+{
+  UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+  USHORT index,temp,romptr=0;
+
+  if(SiS_Pr->SiS_UseROM) {
+     if(!(ROMAddr[0x238] & 0x01)) return;
+     if(!(ROMAddr[0x238] & 0x02)) return;
+     romptr = SISGETROMW(0x241);
+  }
+
+  temp = GetOEMTVPtr(SiS_Pr);
+
+  index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_TVDelayIndex;
+
+  if(romptr) {
+     romptr += (temp * 2);
+     romptr = SISGETROMW(romptr);
+     romptr += index;
+     temp = ROMAddr[romptr];
+  } else {
+     if(SiS_Pr->SiS_VBType & VB_SISVB) {
+        temp = SiS300_OEMTVDelay301[temp][index];
+     } else {
+        temp = SiS300_OEMTVDelayLVDS[temp][index];
+     }
+  }
+  temp &= 0x3c;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x3C,temp);
+}
+
+static void
+SetOEMAntiFlicker(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+                  USHORT ModeNo, USHORT ModeIdIndex)
+{
+  UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+  USHORT index,temp,romptr=0;
+
+  if(SiS_Pr->SiS_UseROM) {
+     if(!(ROMAddr[0x238] & 0x01)) return;
+     if(!(ROMAddr[0x238] & 0x04)) return;
+     romptr = SISGETROMW(0x243);
+  }
+
+  temp = GetOEMTVPtr(SiS_Pr);
+
+  index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_TVFlickerIndex;
+
+  if(romptr) {
+     romptr += (temp * 2);
+     romptr = SISGETROMW(romptr);
+     romptr += index;
+     temp = ROMAddr[romptr];
+  } else {
+     temp = SiS300_OEMTVFlicker[temp][index];
+  }
+  temp &= 0x70;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x0A,0x8F,temp);
+}
+
+static void
+SetOEMPhaseIncr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+                USHORT ModeNo,USHORT ModeIdIndex)
+{
+  UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+  USHORT index,i,j,temp,romptr=0;
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) return;
+
+  if(SiS_Pr->SiS_TVMode & (TVSetNTSC1024 | TVSetNTSCJ | TVSetPALM | TVSetPALN)) return;
+
+  if(SiS_Pr->SiS_UseROM) {
+     if(!(ROMAddr[0x238] & 0x01)) return;
+     if(!(ROMAddr[0x238] & 0x08)) return;
+     romptr = SISGETROMW(0x245);
+  }
+
+  temp = GetOEMTVPtr(SiS_Pr);
+
+  index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_TVPhaseIndex;
+
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+     for(i=0x31, j=0; i<=0x34; i++, j++) {
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS300_Phase2[temp][index][j]);
+     }
+  } else {
+     if(romptr) {
+        romptr += (temp * 2);
+	romptr = SISGETROMW(romptr);
+	romptr += (index * 4);
+        for(i=0x31, j=0; i<=0x34; i++, j++) {
+	   SiS_SetReg(SiS_Pr->SiS_Part2Port,i,ROMAddr[romptr + j]);
+	}
+     } else {
+        for(i=0x31, j=0; i<=0x34; i++, j++) {
+           SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS300_Phase1[temp][index][j]);
+	}
+     }
+  }
+}
+
+static void
+SetOEMYFilter(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+              USHORT ModeNo,USHORT ModeIdIndex)
+{
+  UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+  USHORT index,temp,i,j,romptr=0;
+
+  if(SiS_Pr->SiS_VBInfo & (SetCRT2ToSCART | SetCRT2ToHiVision | SetCRT2ToYPbPr525750)) return;
+
+  if(SiS_Pr->SiS_UseROM) {
+     if(!(ROMAddr[0x238] & 0x01)) return;
+     if(!(ROMAddr[0x238] & 0x10)) return;
+     romptr = SISGETROMW(0x247);
+  }
+
+  temp = GetOEMTVPtr(SiS_Pr);
+
+  if(SiS_Pr->SiS_TVMode & TVSetPALM)      temp = 8;
+  else if(SiS_Pr->SiS_TVMode & TVSetPALN) temp = 9;
+  /* NTSCJ uses NTSC filters */
+
+  index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_TVYFilterIndex;
+
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+      for(i=0x35, j=0; i<=0x38; i++, j++) {
+       	SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS300_Filter2[temp][index][j]);
+      }
+      for(i=0x48; i<=0x4A; i++, j++) {
+     	SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS300_Filter2[temp][index][j]);
+      }
+  } else {
+      if((romptr) && (!(SiS_Pr->SiS_TVMode & (TVSetPALM|TVSetPALN)))) {
+         romptr += (temp * 2);
+	 romptr = SISGETROMW(romptr);
+	 romptr += (index * 4);
+	 for(i=0x35, j=0; i<=0x38; i++, j++) {
+       	    SiS_SetReg(SiS_Pr->SiS_Part2Port,i,ROMAddr[romptr + j]);
+         }
+      } else {
+         for(i=0x35, j=0; i<=0x38; i++, j++) {
+       	    SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS300_Filter1[temp][index][j]);
+         }
+      }
+  }
+}
+
+static USHORT
+SiS_SearchVBModeID(SiS_Private *SiS_Pr, USHORT *ModeNo)
+{
+   USHORT ModeIdIndex;
+   UCHAR VGAINFO = SiS_Pr->SiS_VGAINFO;
+
+   if(*ModeNo <= 5) *ModeNo |= 1;
+
+   for(ModeIdIndex=0; ; ModeIdIndex++) {
+      if(SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].ModeID == *ModeNo) break;
+      if(SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].ModeID == 0xFF)    return 0;
+   }
+
+   if(*ModeNo != 0x07) {
+      if(*ModeNo > 0x03) return ModeIdIndex;
+      if(VGAINFO & 0x80) return ModeIdIndex;
+      ModeIdIndex++;
+   }
+
+   if(VGAINFO & 0x10) ModeIdIndex++;   /* 400 lines */
+	                               /* else 350 lines */
+   return ModeIdIndex;
+}
+
+static void
+SiS_OEM300Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+		  USHORT ModeNo, USHORT ModeIdIndex, USHORT RefTableIndex)
+{
+  USHORT OEMModeIdIndex=0;
+
+  if(!SiS_Pr->UseCustomMode) {
+     OEMModeIdIndex = SiS_SearchVBModeID(SiS_Pr,&ModeNo);
+     if(!(OEMModeIdIndex)) return;
+  }
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+     SetOEMLCDDelay(SiS_Pr, HwInfo, ModeNo, OEMModeIdIndex);
+     if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+        SetOEMLCDData(SiS_Pr, HwInfo, ModeNo, OEMModeIdIndex);
+     }
+  }
+  if(SiS_Pr->UseCustomMode) return;
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+     SetOEMTVDelay(SiS_Pr, HwInfo, ModeNo,OEMModeIdIndex);
+     if(SiS_Pr->SiS_VBType & VB_SISVB) {
+        SetOEMAntiFlicker(SiS_Pr, HwInfo, ModeNo, OEMModeIdIndex);
+    	SetOEMPhaseIncr(SiS_Pr, HwInfo, ModeNo, OEMModeIdIndex);
+       	SetOEMYFilter(SiS_Pr, HwInfo, ModeNo, OEMModeIdIndex);
+     }
+  }
+}
+#endif
+
diff --git a/drivers/video/sis/init301.h b/drivers/video/sis/init301.h
new file mode 100644
index 0000000..f05aebc
--- /dev/null
+++ b/drivers/video/sis/init301.h
@@ -0,0 +1,410 @@
+/* $XFree86$ */
+/* $XdotOrg$ */
+/*
+ * Data and prototypes for init301.c
+ *
+ * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, the following license terms
+ * apply:
+ *
+ * * This program is free software; you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License as published by
+ * * the Free Software Foundation; either version 2 of the named License,
+ * * or any later version.
+ * *
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details.
+ * *
+ * * You should have received a copy of the GNU General Public License
+ * * along with this program; if not, write to the Free Software
+ * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * * Redistribution and use in source and binary forms, with or without
+ * * modification, are permitted provided that the following conditions
+ * * are met:
+ * * 1) Redistributions of source code must retain the above copyright
+ * *    notice, this list of conditions and the following disclaimer.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * *    notice, this list of conditions and the following disclaimer in the
+ * *    documentation and/or other materials provided with the distribution.
+ * * 3) The name of the author may not be used to endorse or promote products
+ * *    derived from this software without specific prior written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ */
+
+#ifndef  _INIT301_
+#define  _INIT301_
+
+#include "osdef.h"
+#include "initdef.h"
+
+#ifdef LINUX_XF86
+#include "sis.h"
+#include "sis_regs.h"
+#endif
+
+#ifdef LINUX_KERNEL
+#include "vgatypes.h"
+#include "vstruct.h"
+#ifdef SIS_CP
+#undef SIS_CP
+#endif
+#include <linux/config.h>
+#include <linux/version.h>
+#include <asm/io.h>
+#include <linux/types.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#include <linux/sisfb.h>
+#else
+#include <video/sisfb.h>
+#endif
+#endif
+
+static const UCHAR SiS_YPbPrTable[3][64] = {
+  {
+    0x17,0x1d,0x03,0x09,0x05,0x06,0x0c,0x0c,
+    0x94,0x49,0x01,0x0a,0x06,0x0d,0x04,0x0a,
+    0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x1b,
+    0x0c,0x50,0x00,0x97,0x00,0xda,0x4a,0x17,
+    0x7d,0x05,0x4b,0x00,0x00,0xe2,0x00,0x02,
+    0x03,0x0a,0x65,0x9d /*0x8d*/,0x08,0x92,0x8f,0x40,
+    0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x53 /*0x50*/,
+    0x00,0x40,0x44,0x00,0xdb,0x02,0x3b,0x00
+  },
+  {
+    0x1d,0x11,0x06,0x09,0x0b,0x0c,0x0c,0x0c,
+    0x98,0x0a,0x01,0x0d,0x06,0x0d,0x04,0x0a,
+    0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x3f,
+    0x0c,0x50,0xb2,0x9f,0x16,0x59,0x4c /*0x4f*/,0x13,
+    0xad,0x11,0xad,0x1d,0x40,0x8a,0x3d,0xb8,
+    0x51,0x5e,0x60,0x57 /*0x49*/,0x7b /*0x7d*/,0x92,0x0f,0x40,
+    0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x4b,
+    0x43,0x41,0x11,0x00,0xfc,0xff,0x32,0x00
+  },
+  {
+#if 1
+    0x13,0x1d,0xe8,0x09,0x09,0xed,0x0c,0x0c,
+    0x98,0x0a,0x01,0x0c,0x06,0x0d,0x04,0x0a,
+    0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x3f,
+    0xed,0x50,0x70,0x9f,0x16,0x59,0x21 /*0x2b*/,0x13,
+    0x27,0x0b,0x27,0xfc,0x30,0x27,0x1c,0xb0,
+    0x4b,0x4b,0x65 /*0x6f*/,0x2f,0x63,0x92,0x0f,0x40,
+    0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x27,
+    0x00,0x40,0x11,0x00,0xfc,0xff,0x32,0x00
+#endif
+#if 0
+    0x2a,0x14,0xe8,0x09,0x09,0xed,0x0c,0x0c,  /* TEST (0.93) - BAD */
+    0x98,0x0a,0x01,0x0c,0x06,0x0d,0x04,0x0a,
+    0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x3f,
+    0xed,0x50,0x70,0x9e,0x16,0x57,0x6c,0x13,
+    0x27,0x0b,0x27,0xfb,0x30,0x27,0x15,0xb0,
+    0x3b,0xdb,0x61,0x24,0x78,0x92,0x0f,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0x14,0x6f,
+    0x00,0x52,0xbb,0x00,0xd5,0xf7,0xa2,0x00
+#endif
+  }
+};
+
+static const UCHAR SiS_HiTVGroup3_1[] = {
+    0x00, 0x14, 0x15, 0x25, 0x55, 0x15, 0x0b, 0x13,
+    0xb1, 0x41, 0x62, 0x62, 0xff, 0xf4, 0x45, 0xa6,
+    0x25, 0x2f, 0x67, 0xf6, 0xbf, 0xff, 0x8e, 0x20,
+    0xac, 0xda, 0x60, 0xfe, 0x6a, 0x9a, 0x06, 0x10,
+    0xd1, 0x04, 0x18, 0x0a, 0xff, 0x80, 0x00, 0x80,
+    0x3b, 0x77, 0x00, 0xef, 0xe0, 0x10, 0xb0, 0xe0,
+    0x10, 0x4f, 0x0f, 0x0f, 0x05, 0x0f, 0x08, 0x6e,
+    0x1a, 0x1f, 0x25, 0x2a, 0x4c, 0xaa, 0x01
+};
+
+static const UCHAR SiS_HiTVGroup3_2[] = {
+    0x00, 0x14, 0x15, 0x25, 0x55, 0x15, 0x0b, 0x7a,
+    0x54, 0x41, 0xe7, 0xe7, 0xff, 0xf4, 0x45, 0xa6,
+    0x25, 0x2f, 0x67, 0xf6, 0xbf, 0xff, 0x8e, 0x20,
+    0xac, 0x6a, 0x60, 0x2b, 0x52, 0xcd, 0x61, 0x10,
+    0x51, 0x04, 0x18, 0x0a, 0x1f, 0x80, 0x00, 0x80,
+    0xff, 0xa4, 0x04, 0x2b, 0x94, 0x21, 0x72, 0x94,
+    0x26, 0x05, 0x01, 0x0f, 0xed, 0x0f, 0x0a, 0x64,
+    0x18, 0x1d, 0x23, 0x28, 0x4c, 0xaa, 0x01
+};
+
+/* 301C / 302ELV extended Part2 TV registers (4 tap scaler) */
+
+static const UCHAR SiS_Part2CLVX_1[] = {
+    0x00,0x00,
+    0x00,0x20,0x00,0x00,0x7F,0x20,0x02,0x7F,0x7D,0x20,0x04,0x7F,0x7D,0x1F,0x06,0x7E,
+    0x7C,0x1D,0x09,0x7E,0x7C,0x1B,0x0B,0x7E,0x7C,0x19,0x0E,0x7D,0x7C,0x17,0x11,0x7C,
+    0x7C,0x14,0x14,0x7C,0x7C,0x11,0x17,0x7C,0x7D,0x0E,0x19,0x7C,0x7E,0x0B,0x1B,0x7C,
+    0x7E,0x09,0x1D,0x7C,0x7F,0x06,0x1F,0x7C,0x7F,0x04,0x20,0x7D,0x00,0x02,0x20,0x7E
+};
+
+static const UCHAR SiS_Part2CLVX_2[] = {
+    0x00,0x00,
+    0x00,0x20,0x00,0x00,0x7F,0x20,0x02,0x7F,0x7D,0x20,0x04,0x7F,0x7D,0x1F,0x06,0x7E,
+    0x7C,0x1D,0x09,0x7E,0x7C,0x1B,0x0B,0x7E,0x7C,0x19,0x0E,0x7D,0x7C,0x17,0x11,0x7C,
+    0x7C,0x14,0x14,0x7C,0x7C,0x11,0x17,0x7C,0x7D,0x0E,0x19,0x7C,0x7E,0x0B,0x1B,0x7C,
+    0x7E,0x09,0x1D,0x7C,0x7F,0x06,0x1F,0x7C,0x7F,0x04,0x20,0x7D,0x00,0x02,0x20,0x7E
+};
+
+static const UCHAR SiS_Part2CLVX_3[] = {  /* NTSC, 525i, 525p */
+    0xE0,0x01,
+    0x04,0x1A,0x04,0x7E,0x03,0x1A,0x06,0x7D,0x01,0x1A,0x08,0x7D,0x00,0x19,0x0A,0x7D,
+    0x7F,0x19,0x0C,0x7C,0x7E,0x18,0x0E,0x7C,0x7E,0x17,0x10,0x7B,0x7D,0x15,0x12,0x7C,
+    0x7D,0x13,0x13,0x7D,0x7C,0x12,0x15,0x7D,0x7C,0x10,0x17,0x7D,0x7C,0x0E,0x18,0x7E,
+    0x7D,0x0C,0x19,0x7E,0x7D,0x0A,0x19,0x00,0x7D,0x08,0x1A,0x01,0x7E,0x06,0x1A,0x02,
+    0x58,0x02,
+    0x07,0x14,0x07,0x7E,0x06,0x14,0x09,0x7D,0x05,0x14,0x0A,0x7D,0x04,0x13,0x0B,0x7E,
+    0x03,0x13,0x0C,0x7E,0x02,0x12,0x0D,0x7F,0x01,0x12,0x0E,0x7F,0x01,0x11,0x0F,0x7F,
+    0x00,0x10,0x10,0x00,0x7F,0x0F,0x11,0x01,0x7F,0x0E,0x12,0x01,0x7E,0x0D,0x12,0x03,
+    0x7E,0x0C,0x13,0x03,0x7E,0x0B,0x13,0x04,0x7E,0x0A,0x14,0x04,0x7D,0x09,0x14,0x06,
+    0x00,0x03,
+    0x09,0x0F,0x09,0x7F,0x08,0x0F,0x09,0x00,0x07,0x0F,0x0A,0x00,0x06,0x0F,0x0A,0x01,
+    0x06,0x0E,0x0B,0x01,0x05,0x0E,0x0B,0x02,0x04,0x0E,0x0C,0x02,0x04,0x0D,0x0C,0x03,
+    0x03,0x0D,0x0D,0x03,0x02,0x0C,0x0D,0x05,0x02,0x0C,0x0E,0x04,0x01,0x0B,0x0E,0x06,
+    0x01,0x0B,0x0E,0x06,0x00,0x0A,0x0F,0x07,0x00,0x0A,0x0F,0x07,0x00,0x09,0x0F,0x08,
+    0xFF,0xFF
+};
+
+static const UCHAR SiS_Part2CLVX_4[] = {   /* PAL */
+    0x58,0x02,
+    0x05,0x19,0x05,0x7D,0x03,0x19,0x06,0x7E,0x02,0x19,0x08,0x7D,0x01,0x18,0x0A,0x7D,
+    0x00,0x18,0x0C,0x7C,0x7F,0x17,0x0E,0x7C,0x7E,0x16,0x0F,0x7D,0x7E,0x14,0x11,0x7D,
+    0x7D,0x13,0x13,0x7D,0x7D,0x11,0x14,0x7E,0x7D,0x0F,0x16,0x7E,0x7D,0x0E,0x17,0x7E,
+    0x7D,0x0C,0x18,0x7F,0x7D,0x0A,0x18,0x01,0x7D,0x08,0x19,0x02,0x7D,0x06,0x19,0x04,
+    0x00,0x03,
+    0x08,0x12,0x08,0x7E,0x07,0x12,0x09,0x7E,0x06,0x12,0x0A,0x7E,0x05,0x11,0x0B,0x7F,
+    0x04,0x11,0x0C,0x7F,0x03,0x11,0x0C,0x00,0x03,0x10,0x0D,0x00,0x02,0x0F,0x0E,0x01,
+    0x01,0x0F,0x0F,0x01,0x01,0x0E,0x0F,0x02,0x00,0x0D,0x10,0x03,0x7F,0x0C,0x11,0x04,
+    0x7F,0x0C,0x11,0x04,0x7F,0x0B,0x11,0x05,0x7E,0x0A,0x12,0x06,0x7E,0x09,0x12,0x07,
+    0x40,0x02,
+    0x04,0x1A,0x04,0x7E,0x02,0x1B,0x05,0x7E,0x01,0x1A,0x07,0x7E,0x00,0x1A,0x09,0x7D,
+    0x7F,0x19,0x0B,0x7D,0x7E,0x18,0x0D,0x7D,0x7D,0x17,0x10,0x7C,0x7D,0x15,0x12,0x7C,
+    0x7C,0x14,0x14,0x7C,0x7C,0x12,0x15,0x7D,0x7C,0x10,0x17,0x7D,0x7C,0x0D,0x18,0x7F,
+    0x7D,0x0B,0x19,0x7F,0x7D,0x09,0x1A,0x00,0x7D,0x07,0x1A,0x02,0x7E,0x05,0x1B,0x02,
+    0xFF,0xFF
+};
+
+static const UCHAR SiS_Part2CLVX_5[] = {   /* 750p */
+    0x00,0x03,
+    0x05,0x19,0x05,0x7D,0x03,0x19,0x06,0x7E,0x02,0x19,0x08,0x7D,0x01,0x18,0x0A,0x7D,
+    0x00,0x18,0x0C,0x7C,0x7F,0x17,0x0E,0x7C,0x7E,0x16,0x0F,0x7D,0x7E,0x14,0x11,0x7D,
+    0x7D,0x13,0x13,0x7D,0x7D,0x11,0x14,0x7E,0x7D,0x0F,0x16,0x7E,0x7D,0x0E,0x17,0x7E,
+    0x7D,0x0C,0x18,0x7F,0x7D,0x0A,0x18,0x01,0x7D,0x08,0x19,0x02,0x7D,0x06,0x19,0x04,
+    0xFF,0xFF
+};
+
+static const UCHAR SiS_Part2CLVX_6[] = {   /* 1080i */
+    0x00,0x04,
+    0x04,0x1A,0x04,0x7E,0x02,0x1B,0x05,0x7E,0x01,0x1A,0x07,0x7E,0x00,0x1A,0x09,0x7D,
+    0x7F,0x19,0x0B,0x7D,0x7E,0x18,0x0D,0x7D,0x7D,0x17,0x10,0x7C,0x7D,0x15,0x12,0x7C,
+    0x7C,0x14,0x14,0x7C,0x7C,0x12,0x15,0x7D,0x7C,0x10,0x17,0x7D,0x7C,0x0D,0x18,0x7F,
+    0x7D,0x0B,0x19,0x7F,0x7D,0x09,0x1A,0x00,0x7D,0x07,0x1A,0x02,0x7E,0x05,0x1B,0x02,
+    0xFF,0xFF,
+};
+
+#ifdef SIS315H
+/* 661 et al LCD data structure (2.03.00) */
+static const UCHAR SiS_LCDStruct661[] = {
+    /* 1024x768 */
+/*  type|CR37|   HDE   |   VDE   |    HT   |    VT   |   hss    | hse   */
+    0x02,0xC0,0x00,0x04,0x00,0x03,0x40,0x05,0x26,0x03,0x10,0x00,0x88,
+    0x00,0x02,0x00,0x06,0x00,0x41,0x5A,0x64,0x00,0x00,0x00,0x00,0x04,
+    /*  | vss     |    vse  |clck|  clock  |CRT2DataP|CRT2DataP|idx     */
+    /*					      VESA    non-VESA  noscale */
+    /* 1280x1024 */
+    0x03,0xC0,0x00,0x05,0x00,0x04,0x98,0x06,0x2A,0x04,0x30,0x00,0x70,
+    0x00,0x01,0x00,0x03,0x00,0x6C,0xF8,0x2F,0x00,0x00,0x00,0x00,0x08,
+    /* 1400x1050 */
+    0x09,0x20,0x78,0x05,0x1A,0x04,0x98,0x06,0x2A,0x04,0x18,0x00,0x38,
+    0x00,0x01,0x00,0x03,0x00,0x6C,0xF8,0x2F,0x00,0x00,0x00,0x00,0x09,
+    /* 1600x1200 */
+    0x0B,0xE0,0x40,0x06,0xB0,0x04,0x70,0x08,0xE2,0x04,0x40,0x00,0xC0,
+    0x00,0x01,0x00,0x03,0x00,0xA2,0x70,0x24,0x00,0x00,0x00,0x00,0x0A,
+    /* 1280x768 (_2) */
+    0x0A,0xE0,0x00,0x05,0x00,0x03,0x7C,0x06,0x26,0x03,0x30,0x00,0x70,
+    0x00,0x03,0x00,0x06,0x00,0x4D,0xC8,0x48,0x00,0x00,0x00,0x00,0x06,
+    /* 1280x720 */
+    0x0E,0xE0,0x00,0x05,0xD0,0x02,0x80,0x05,0x26,0x03,0x10,0x00,0x20,
+    0x00,0x01,0x00,0x06,0x00,0x45,0x9C,0x62,0x00,0x00,0x00,0x00,0x05,
+    /* 1280x800 (_2) */
+    0x0C,0xE0,0x00,0x05,0x20,0x03,0x10,0x06,0x2C,0x03,0x30,0x00,0x70,
+    0x00,0x04,0x00,0x03,0x00,0x49,0xCE,0x1E,0x00,0x00,0x00,0x00,0x09,
+    /* 1680x1050 */
+    0x0D,0xE0,0x90,0x06,0x1A,0x04,0x6C,0x07,0x2A,0x04,0x1A,0x00,0x4C,
+    0x00,0x03,0x00,0x06,0x00,0x79,0xBE,0x44,0x00,0x00,0x00,0x00,0x06,
+};
+#endif
+
+#ifdef SIS300
+static UCHAR SiS300_TrumpionData[7][80] = {
+  { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x7F,0x00,0x80,0x02,
+    0x20,0x03,0x0B,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x10,0x00,0x00,0x04,0x23,
+    0x00,0x00,0x03,0x28,0x03,0x10,0x05,0x08,0x40,0x10,0x00,0x10,0x04,0x23,0x00,0x23,
+    0x03,0x11,0x60,0xBC,0x01,0xFF,0x03,0xFF,0x19,0x01,0x00,0x05,0x09,0x04,0x04,0x05,
+    0x04,0x0C,0x09,0x05,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x5A,0x01,0xBE,0x01,0x00 },
+  { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x27,0x00,0x80,0x02,
+    0x20,0x03,0x07,0x00,0x5E,0x01,0x0D,0x02,0x60,0x0C,0x30,0x11,0x00,0x00,0x04,0x23,
+    0x00,0x00,0x03,0x80,0x03,0x28,0x06,0x08,0x40,0x11,0x00,0x11,0x04,0x23,0x00,0x23,
+    0x03,0x11,0x60,0x90,0x01,0xFF,0x0F,0xF4,0x19,0x01,0x00,0x05,0x01,0x00,0x04,0x05,
+    0x04,0x0C,0x02,0x01,0x02,0xB0,0x00,0x00,0x02,0xBA,0xEC,0x57,0x01,0xBE,0x01,0x00 },
+  { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x8A,0x00,0xD8,0x02,
+    0x84,0x03,0x16,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x1C,0x00,0x20,0x04,0x23,
+    0x00,0x01,0x03,0x53,0x03,0x28,0x06,0x08,0x40,0x1C,0x00,0x16,0x04,0x23,0x00,0x23,
+    0x03,0x11,0x60,0xD9,0x01,0xFF,0x0F,0xF4,0x18,0x07,0x05,0x05,0x13,0x04,0x04,0x05,
+    0x01,0x0B,0x13,0x0A,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x59,0x01,0xBE,0x01,0x00 },
+  { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x72,0x00,0xD8,0x02,
+    0x84,0x03,0x16,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x1C,0x00,0x20,0x04,0x23,
+    0x00,0x01,0x03,0x53,0x03,0x28,0x06,0x08,0x40,0x1C,0x00,0x16,0x04,0x23,0x00,0x23,
+    0x03,0x11,0x60,0xDA,0x01,0xFF,0x0F,0xF4,0x18,0x07,0x05,0x05,0x13,0x04,0x04,0x05,
+    0x01,0x0B,0x13,0x0A,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x55,0x01,0xBE,0x01,0x00 },
+  { 0x02,0x0A,0x02,0x00,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x7F,0x00,0x80,0x02,
+    0x20,0x03,0x16,0x00,0xE0,0x01,0x0D,0x02,0x60,0x0C,0x30,0x98,0x00,0x00,0x04,0x23,
+    0x00,0x01,0x03,0x45,0x03,0x48,0x06,0x08,0x40,0x98,0x00,0x98,0x04,0x23,0x00,0x23,
+    0x03,0x11,0x60,0xF4,0x01,0xFF,0x0F,0xF4,0x18,0x01,0x00,0x05,0x01,0x00,0x05,0x05,
+    0x04,0x0C,0x08,0x05,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x5B,0x01,0xBE,0x01,0x00 },
+  { 0x02,0x0A,0x02,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0xBF,0x00,0x20,0x03,
+    0x20,0x04,0x0D,0x00,0x58,0x02,0x71,0x02,0x80,0x0C,0x30,0x9A,0x00,0xFA,0x03,0x1D,
+    0x00,0x01,0x03,0x22,0x03,0x28,0x06,0x08,0x40,0x98,0x00,0x98,0x04,0x1D,0x00,0x1D,
+    0x03,0x11,0x60,0x39,0x03,0x40,0x05,0xF4,0x18,0x07,0x02,0x06,0x04,0x01,0x06,0x0B,
+    0x02,0x0A,0x20,0x19,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x5B,0x01,0xBE,0x01,0x00 },
+  { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0xEF,0x00,0x00,0x04,
+    0x40,0x05,0x13,0x00,0x00,0x03,0x26,0x03,0x88,0x0C,0x30,0x90,0x00,0x00,0x04,0x23,
+    0x00,0x01,0x03,0x24,0x03,0x28,0x06,0x08,0x40,0x90,0x00,0x90,0x04,0x23,0x00,0x23,
+    0x03,0x11,0x60,0x40,0x05,0xFF,0x0F,0xF4,0x18,0x01,0x00,0x08,0x01,0x00,0x08,0x01,
+    0x00,0x08,0x01,0x01,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x5B,0x01,0xBE,0x01,0x00 }
+};
+#endif
+
+void	SiS_UnLockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
+void	SiS_LockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
+void	SiS_EnableCRT2(SiS_Private *SiS_Pr);
+USHORT	SiS_GetRatePtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, PSIS_HW_INFO HwInfo);
+void	SiS_WaitRetrace1(SiS_Private *SiS_Pr);
+BOOLEAN	SiS_IsDualEdge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
+BOOLEAN	SiS_IsVAMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
+void	SiS_SetChrontelGPIO(SiS_Private *SiS_Pr, USHORT myvbinfo);
+void	SiS_GetVBInfo(SiS_Private *SiS_Pr, USHORT ModeNo,
+              	USHORT ModeIdIndex, PSIS_HW_INFO HwInfo,
+	      	int checkcrt2mode);
+void	SiS_SetYPbPr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
+void    SiS_SetTVMode(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, PSIS_HW_INFO HwInfo);
+void	SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, PSIS_HW_INFO HwInfo);
+USHORT	SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+                USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo);
+USHORT	SiS_GetResInfo(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex);
+void	SiS_DisableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
+void	SiS_EnableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
+BOOLEAN	SiS_SetCRT2Group(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo);
+void	SiS_SiS30xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
+void	SiS_SiS30xBLOff(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
+
+void   	SiS_SetCH700x(SiS_Private *SiS_Pr, USHORT tempax);
+USHORT 	SiS_GetCH700x(SiS_Private *SiS_Pr, USHORT tempax);
+void   	SiS_SetCH701x(SiS_Private *SiS_Pr, USHORT tempax);
+USHORT 	SiS_GetCH701x(SiS_Private *SiS_Pr, USHORT tempax);
+void   	SiS_SetCH70xx(SiS_Private *SiS_Pr, USHORT tempax);
+USHORT 	SiS_GetCH70xx(SiS_Private *SiS_Pr, USHORT tempax);
+void   	SiS_SetCH70xxANDOR(SiS_Private *SiS_Pr, USHORT tempax,USHORT tempbh);
+#ifdef SIS315H
+static void   	SiS_Chrontel701xOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
+static void   	SiS_Chrontel701xOff(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
+static void   	SiS_ChrontelInitTVVSync(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
+static void  	SiS_ChrontelDoSomething1(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
+void   	SiS_Chrontel701xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
+void   	SiS_Chrontel701xBLOff(SiS_Private *SiS_Pr);
+#endif /* 315 */
+
+#ifdef SIS300
+#if 0
+static  void    SiS_SetTrumpReg(SiS_Private *SiS_Pr, USHORT tempbx);
+static  USHORT  SiS_GetTrumpReg(SiS_Private *SiS_Pr, USHORT tempbx);
+#endif
+static  BOOLEAN	SiS_SetTrumpionBlock(SiS_Private *SiS_Pr, UCHAR *dataptr);
+#endif
+
+void    SiS_DDC2Delay(SiS_Private *SiS_Pr, USHORT delaytime);
+USHORT  SiS_ReadDDC1Bit(SiS_Private *SiS_Pr);
+USHORT  SiS_HandleDDC(SiS_Private *SiS_Pr, ULONG VBFlags, int VGAEngine,
+		      USHORT adaptnum, USHORT DDCdatatype, UCHAR *buffer);
+#ifdef LINUX_XF86
+USHORT  SiS_SenseLCDDDC(SiS_Private *SiS_Pr, SISPtr pSiS);
+USHORT  SiS_SenseVGA2DDC(SiS_Private *SiS_Pr, SISPtr pSiS);
+#endif
+
+static void    	SiS_SetSwitchDDC2(SiS_Private *SiS_Pr);
+static USHORT  	SiS_SetStart(SiS_Private *SiS_Pr);
+static USHORT  	SiS_SetStop(SiS_Private *SiS_Pr);
+static USHORT  	SiS_SetSCLKLow(SiS_Private *SiS_Pr);
+static USHORT  	SiS_SetSCLKHigh(SiS_Private *SiS_Pr);
+static USHORT  	SiS_ReadDDC2Data(SiS_Private *SiS_Pr, USHORT tempax);
+static USHORT  	SiS_WriteDDC2Data(SiS_Private *SiS_Pr, USHORT tempax);
+static USHORT  	SiS_CheckACK(SiS_Private *SiS_Pr);
+static USHORT  	SiS_InitDDCRegs(SiS_Private *SiS_Pr, ULONG VBFlags, int VGAEngine,
+                        USHORT adaptnum, USHORT DDCdatatype, BOOLEAN checkcr32);
+static USHORT  	SiS_WriteDABDDC(SiS_Private *SiS_Pr);
+static USHORT  	SiS_PrepareReadDDC(SiS_Private *SiS_Pr);
+static USHORT  	SiS_PrepareDDC(SiS_Private *SiS_Pr);
+static void    	SiS_SendACK(SiS_Private *SiS_Pr, USHORT yesno);
+static USHORT  	SiS_DoProbeDDC(SiS_Private *SiS_Pr);
+static USHORT  	SiS_ProbeDDC(SiS_Private *SiS_Pr);
+static USHORT  	SiS_ReadDDC(SiS_Private *SiS_Pr, USHORT DDCdatatype, UCHAR *buffer);
+
+#ifdef SIS315H
+static void    	SiS_OEM310Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+                        USHORT ModeNo,USHORT ModeIdIndex, USHORT RRTI);
+static void    	SiS_OEM661Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+                        USHORT ModeNo,USHORT ModeIdIndex, USHORT RRTI);
+static void    	SiS_FinalizeLCD(SiS_Private *, USHORT, USHORT, PSIS_HW_INFO);
+#endif
+#ifdef SIS300
+static void    	SiS_OEM300Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+                        USHORT ModeNo, USHORT ModeIdIndex, USHORT RefTabindex);
+static void    	SetOEMLCDData2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+		        USHORT ModeNo, USHORT ModeIdIndex,USHORT RefTableIndex);
+#endif
+
+extern void     SiS_SetReg(SISIOADDRESS, USHORT, USHORT);
+extern void     SiS_SetRegByte(SISIOADDRESS, USHORT);
+extern void     SiS_SetRegShort(SISIOADDRESS, USHORT);
+extern void     SiS_SetRegLong(SISIOADDRESS, ULONG);
+extern UCHAR    SiS_GetReg(SISIOADDRESS, USHORT);
+extern UCHAR    SiS_GetRegByte(SISIOADDRESS);
+extern USHORT   SiS_GetRegShort(SISIOADDRESS);
+extern ULONG    SiS_GetRegLong(SISIOADDRESS);
+extern void     SiS_SetRegANDOR(SISIOADDRESS, USHORT, USHORT, USHORT);
+extern void     SiS_SetRegOR(SISIOADDRESS, USHORT, USHORT);
+extern void     SiS_SetRegAND(SISIOADDRESS, USHORT, USHORT);
+extern void     SiS_DisplayOff(SiS_Private *SiS_Pr);
+extern void     SiS_DisplayOn(SiS_Private *SiS_Pr);
+extern BOOLEAN  SiS_SearchModeID(SiS_Private *, USHORT *, USHORT *);
+extern UCHAR    SiS_GetModePtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex);
+extern USHORT   SiS_GetColorDepth(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex);
+extern USHORT   SiS_GetOffset(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+                      	USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo);
+extern void     SiS_LoadDAC(SiS_Private *SiS_Pr, PSIS_HW_INFO, USHORT ModeNo,
+                        USHORT ModeIdIndex);
+extern void	SiS_CalcLCDACRT1Timing(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex);
+#ifdef LINUX_XF86
+extern void     SiS_MakeClockRegs(ScrnInfoPtr pScrn, int clock, UCHAR *p2b, UCHAR *p2c);
+extern int 	SiS_FindPanelFromDB(SISPtr pSiS, USHORT panelvendor, USHORT panelproduct,
+			int *maxx, int *maxy, int *prefx, int *prefy);
+#endif
+
+#endif
diff --git a/drivers/video/sis/initdef.h b/drivers/video/sis/initdef.h
new file mode 100644
index 0000000..55a82d6
--- /dev/null
+++ b/drivers/video/sis/initdef.h
@@ -0,0 +1,671 @@
+/* $XFree86$ */
+/* $XdotOrg$ */
+/*
+ * Global definitions for init.c and init301.c
+ *
+ * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, the following license terms
+ * apply:
+ *
+ * * This program is free software; you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License as published by
+ * * the Free Software Foundation; either version 2 of the named License,
+ * * or any later version.
+ * *
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details.
+ * *
+ * * You should have received a copy of the GNU General Public License
+ * * along with this program; if not, write to the Free Software
+ * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * * Redistribution and use in source and binary forms, with or without
+ * * modification, are permitted provided that the following conditions
+ * * are met:
+ * * 1) Redistributions of source code must retain the above copyright
+ * *    notice, this list of conditions and the following disclaimer.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * *    notice, this list of conditions and the following disclaimer in the
+ * *    documentation and/or other materials provided with the distribution.
+ * * 3) The name of the author may not be used to endorse or promote products
+ * *    derived from this software without specific prior written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ */
+
+#ifndef _INITDEF_
+#define _INITDEF_
+
+#define IS_SIS330		(HwInfo->jChipType == SIS_330)
+#define IS_SIS550		(HwInfo->jChipType == SIS_550)
+#define IS_SIS650		(HwInfo->jChipType == SIS_650)  /* All versions, incl 651, M65x */
+#define IS_SIS740		(HwInfo->jChipType == SIS_740)
+#define IS_SIS651	        (SiS_Pr->SiS_SysFlags & (SF_Is651 | SF_Is652))
+#define IS_SISM650	        (SiS_Pr->SiS_SysFlags & (SF_IsM650 | SF_IsM652 | SF_IsM653))
+#define IS_SIS65x               (IS_SIS651 || IS_SISM650)       /* Only special versions of 65x */
+#define IS_SIS661		(HwInfo->jChipType == SIS_661)
+#define IS_SIS741		(HwInfo->jChipType == SIS_741)
+#define IS_SIS660		(HwInfo->jChipType == SIS_660)
+#define IS_SIS760		(HwInfo->jChipType == SIS_760)
+#define IS_SIS661741660760	(IS_SIS661 || IS_SIS741 || IS_SIS660 || IS_SIS760)
+#define IS_SIS650740            ((HwInfo->jChipType >= SIS_650) && (HwInfo->jChipType < SIS_330))
+#define IS_SIS550650740         (IS_SIS550 || IS_SIS650740)
+#define IS_SIS650740660         (IS_SIS650 || IS_SIS740 || IS_SIS661741660760)
+#define IS_SIS550650740660      (IS_SIS550 || IS_SIS650740660)
+
+#define SISGETROMW(x)		(ROMAddr[(x)] | (ROMAddr[(x)+1] << 8))
+
+/* SiS_VBType */
+#define VB_SIS301	      	0x0001
+#define VB_SIS301B        	0x0002
+#define VB_SIS302B        	0x0004
+#define VB_SIS301LV     	0x0008
+#define VB_SIS302LV     	0x0010
+#define VB_SIS302ELV		0x0020
+#define VB_SIS301C              0x0040
+#define VB_UMC			0x4000
+#define VB_NoLCD        	0x8000
+#define VB_SIS301BLV302BLV      (VB_SIS301B|VB_SIS301C|VB_SIS302B|VB_SIS301LV|VB_SIS302LV|VB_SIS302ELV)
+#define VB_SIS301B302B          (VB_SIS301B|VB_SIS301C|VB_SIS302B)
+#define VB_SIS301LV302LV        (VB_SIS301LV|VB_SIS302LV|VB_SIS302ELV)
+#define VB_SISVB		(VB_SIS301 | VB_SIS301BLV302BLV)
+#define VB_SISTMDS		(VB_SIS301 | VB_SIS301B302B)
+#define VB_SISLVDS		VB_SIS301LV302LV
+#define VB_SISLCDA		(VB_SIS302B|VB_SIS301C|VB_SIS301LV|VB_SIS302LV|VB_SIS302ELV)
+#define VB_SISYPBPR		(VB_SIS301C|VB_SIS301LV|VB_SIS302LV|VB_SIS302ELV)
+#define VB_SISHIVISION		(VB_SIS301|VB_SIS301B|VB_SIS302B)
+
+/* VBInfo */
+#define SetSimuScanMode         0x0001   /* CR 30 */
+#define SwitchCRT2              0x0002
+#define SetCRT2ToAVIDEO         0x0004
+#define SetCRT2ToSVIDEO         0x0008
+#define SetCRT2ToSCART          0x0010
+#define SetCRT2ToLCD            0x0020
+#define SetCRT2ToRAMDAC         0x0040
+#define SetCRT2ToHiVision       0x0080   		/* for SiS bridge */
+#define SetCRT2ToCHYPbPr       	SetCRT2ToHiVision	/* for Chrontel   */
+#define SetNTSCTV               0x0000   /* CR 31 */
+#define SetPALTV                0x0100   		/* Deprecated here, now in TVMode */
+#define SetInSlaveMode          0x0200
+#define SetNotSimuMode          0x0400
+#define SetNotSimuTVMode        SetNotSimuMode
+#define SetDispDevSwitch        0x0800
+#define SetCRT2ToYPbPr525750    0x0800
+#define LoadDACFlag             0x1000
+#define DisableCRT2Display      0x2000
+#define DriverMode              0x4000
+#define HotKeySwitch            0x8000
+#define SetCRT2ToLCDA           0x8000
+
+/* v-- Needs change in sis_vga.c if changed (GPIO) --v */
+#define SetCRT2ToTV             (SetCRT2ToYPbPr525750|SetCRT2ToHiVision|SetCRT2ToSCART|SetCRT2ToSVIDEO|SetCRT2ToAVIDEO)
+#define SetCRT2ToTVNoYPbPrHiVision (SetCRT2ToSCART | SetCRT2ToSVIDEO | SetCRT2ToAVIDEO)
+#define SetCRT2ToTVNoHiVision  	(SetCRT2ToYPbPr525750 | SetCRT2ToSCART | SetCRT2ToSVIDEO | SetCRT2ToAVIDEO)
+
+/* SiS_ModeType */
+#define ModeText                0x00
+#define ModeCGA                 0x01
+#define ModeEGA                 0x02
+#define ModeVGA                 0x03
+#define Mode15Bpp               0x04
+#define Mode16Bpp               0x05
+#define Mode24Bpp               0x06
+#define Mode32Bpp               0x07
+
+#define ModeTypeMask            0x07
+#define IsTextMode              0x07
+
+#define DACInfoFlag             0x0018
+#define MemoryInfoFlag          0x01E0
+#define MemorySizeShift         5
+
+/* modeflag */
+#define Charx8Dot               0x0200
+#define LineCompareOff          0x0400
+#define CRT2Mode                0x0800
+#define HalfDCLK                0x1000
+#define NoSupportSimuTV         0x2000
+#define NoSupportLCDScale	0x4000 /* SiS bridge: No scaling possible (no matter what panel) */
+#define DoubleScanMode          0x8000
+
+/* Infoflag */
+#define SupportTV               0x0008
+#define SupportTV1024           0x0800
+#define SupportCHTV 		0x0800
+#define Support64048060Hz       0x0800  /* Special for 640x480 LCD */
+#define SupportHiVision         0x0010
+#define SupportYPbPr750p        0x1000
+#define SupportLCD              0x0020
+#define SupportRAMDAC2          0x0040	/* All           (<= 100Mhz) */
+#define SupportRAMDAC2_135      0x0100  /* All except DH (<= 135Mhz) */
+#define SupportRAMDAC2_162      0x0200  /* B, C          (<= 162Mhz) */
+#define SupportRAMDAC2_202      0x0400  /* C             (<= 202Mhz) */
+#define InterlaceMode           0x0080
+#define SyncPP                  0x0000
+#define SyncPN                  0x4000
+#define SyncNP                  0x8000
+#define SyncNN                  0xc000
+
+/* SetFlag */
+#define ProgrammingCRT2         0x0001
+#define LowModeTests		0x0002
+/* #define TVSimuMode           0x0002 - deprecated */
+/* #define RPLLDIV2XO           0x0004 - deprecated */
+#define LCDVESATiming           0x0008
+#define EnableLVDSDDA           0x0010
+#define SetDispDevSwitchFlag    0x0020
+#define CheckWinDos             0x0040
+#define SetDOSMode              0x0080
+
+/* TVMode flag */
+#define TVSetPAL		0x0001
+#define TVSetNTSCJ		0x0002
+#define TVSetPALM		0x0004
+#define TVSetPALN		0x0008
+#define TVSetCHOverScan		0x0010
+#define TVSetYPbPr525i		0x0020 /* new 0x10 */
+#define TVSetYPbPr525p		0x0040 /* new 0x20 */
+#define TVSetYPbPr750p		0x0080 /* new 0x40 */
+#define TVSetHiVision		0x0100 /* new 0x80; = 1080i, software-wise identical */
+#define TVSetTVSimuMode		0x0200 /* new 0x200, prev. 0x800 */
+#define TVRPLLDIV2XO		0x0400 /* prev 0x1000 */
+#define TVSetNTSC1024		0x0800 /* new 0x100, prev. 0x2000 */
+#define TVAspect43		0x2000
+#define TVAspect169		0x4000
+#define TVAspect43LB		0x8000
+
+/* YPbPr flag (>=315, <661; converted to TVMode) */
+#define YPbPr525p               0x0001
+#define YPbPr750p               0x0002
+#define YPbPr525i               0x0004
+#define YPbPrHiVision           0x0008
+#define YPbPrModeMask           (YPbPr750p | YPbPr525p | YPbPr525i | YPbPrHiVision)
+
+/* SysFlags (to identify special versions) */
+#define SF_Is651                0x0001
+#define SF_IsM650               0x0002
+#define SF_Is652		0x0004
+#define SF_IsM652		0x0008
+#define SF_IsM653		0x0010
+#define SF_IsM661		0x0020
+#define SF_IsM741		0x0040
+#define SF_IsM760		0x0080
+#define SF_760LFB		0x8000  /* 760: We have LFB */
+
+/* CR32 (Newer 630, and 315 series)
+
+   [0]   VB connected with CVBS
+   [1]   VB connected with SVHS
+   [2]   VB connected with SCART
+   [3]   VB connected with LCD
+   [4]   VB connected with CRT2 (secondary VGA)
+   [5]   CRT1 monitor is connected
+   [6]   VB connected with Hi-Vision TV
+   [7]   <= 330: VB connected with DVI combo connector
+         >= 661: VB connected to YPbPr
+*/
+
+/* CR35 (300 series only) */
+#define TVOverScan              0x10
+#define TVOverScanShift         4
+
+/* CR35 (661 series only)
+
+   [0]    1 = PAL, 0 = NTSC
+   [1]    1 = NTSC-J (if D0 = 0)
+   [2]    1 = PALM (if D0 = 1)
+   [3]    1 = PALN (if D0 = 1)
+   [4]    1 = Overscan (Chrontel only)
+   [7:5]  (only if D2 in CR38 is set)
+          000  525i
+ 	  001  525p
+	  010  750p
+	  011  1080i (or HiVision on 301, 301B)
+
+   These bits are being translated to TVMode flag.
+
+*/
+
+/*
+   CR37
+
+   [0]   Set 24/18 bit (0/1) RGB to LVDS/TMDS transmitter (set by BIOS)
+   [3:1] External chip
+         300 series:
+	    001   SiS301 (never seen)
+	    010   LVDS
+	    011   LVDS + Tumpion Zurac
+	    100   LVDS + Chrontel 7005
+	    110   Chrontel 7005
+	  315/330 series
+	    001   SiS30x (never seen)
+	    010   LVDS
+	    011   LVDS + Chrontel 7019
+	  660 series [2:1] only:
+	     reserved (now in CR38)
+	  All other combinations reserved
+   [3]    661 only: Pass 1:1 data
+   [4]    LVDS: 0: Panel Link expands / 1: Panel Link does not expand
+          30x:  0: Bridge scales      / 1: Bridge does not scale = Panel scales (if possible)
+   [5]    LCD polarity select
+          0: VESA DMT Standard
+	  1: EDID 2.x defined
+   [6]    LCD horizontal polarity select
+          0: High active
+	  1: Low active
+   [7]    LCD vertical polarity select
+          0: High active
+	  1: Low active
+*/
+
+/* CR37: LCDInfo */
+#define LCDRGB18Bit           0x0001
+#define LCDNonExpanding       0x0010
+#define LCDSync               0x0020
+#define LCDPass11             0x0100   /* 0: center screen, 1: Pass 1:1 data */
+#define LCDDualLink	      0x0200
+
+#define DontExpandLCD	      LCDNonExpanding
+#define LCDNonExpandingShift       4
+#define DontExpandLCDShift    LCDNonExpandingShift
+#define LCDSyncBit            0x00e0
+#define LCDSyncShift               6
+
+/* CR38 (315 series) */
+#define EnableDualEdge 		0x01
+#define SetToLCDA		0x02   /* LCD channel A (301C/302B/30x(E)LV and 650+LVDS only) */
+#define EnableCHScart           0x04   /* Scart on Ch7019 (unofficial definition - TW) */
+#define EnableCHYPbPr           0x08   /* YPbPr on Ch7019 (480i HDTV); only on 650/Ch7019 systems */
+#define EnableSiSYPbPr          0x08   /* Enable YPbPr mode (30xLV/301C only) */
+#define EnableYPbPr525i         0x00   /* Enable 525i YPbPr mode (30xLV/301C only) (mask 0x30) */
+#define EnableYPbPr525p         0x10   /* Enable 525p YPbPr mode (30xLV/301C only) (mask 0x30) */
+#define EnableYPbPr750p         0x20   /* Enable 750p YPbPr mode (30xLV/301C only) (mask 0x30) */
+#define EnableYPbPr1080i        0x30   /* Enable 1080i YPbPr mode (30xLV/301C only) (mask 0x30) */
+#define EnablePALM              0x40   /* 1 = Set PALM */
+#define EnablePALN              0x80   /* 1 = Set PALN */
+#define EnableNTSCJ             EnablePALM  /* Not BIOS */
+
+/* CR38 (661 and later)
+  D[7:5]  000 No VB
+          001 301 series VB
+	  010 LVDS
+	  011 Chrontel 7019
+	  100 Conexant
+  D2      Enable YPbPr output (see CR35)
+  D[1:0]  LCDA (like before)
+*/
+
+#define EnablePALMN             0x40   /* Romflag: 1 = Allow PALM/PALN */
+
+/* CR39 (650 only) */
+#define LCDPass1_1		0x01   /* 0: center screen, 1: pass 1:1 data output  */
+#define Enable302LV_DualLink    0x04   /* 302LV only; enable dual link */
+
+/* CR39 (661 and later)
+   D[1:0] YPbPr Aspect Ratio
+          00 4:3 letterbox
+	  01 4:3
+	  10 16:9
+	  11 4:3
+*/
+
+/* CR3B (651+301C)
+   D[1:0] YPbPr Aspect Ratio
+          ?
+*/
+
+/* CR79 (315/330 series only; not 661 and later)
+   [3-0] Notify driver
+         0001 Mode Switch event (set by BIOS)
+	 0010 Epansion On/Off event
+	 0011 TV UnderScan/OverScan event
+	 0100 Set Brightness event
+	 0101 Set Contrast event
+	 0110 Set Mute event
+	 0111 Set Volume Up/Down event
+   [4]   Enable Backlight Control by BIOS/driver 
+         (set by driver; set means that the BIOS should
+	 not touch the backlight registers because eg.
+	 the driver already switched off the backlight)
+   [5]   PAL/NTSC (set by BIOS)
+   [6]   Expansion On/Off (set by BIOS; copied to CR32[4])
+   [7]   TV UnderScan/OverScan (set by BIOS)
+*/
+
+/* LCDResInfo */
+#define Panel300_800x600        0x01	/* CR36 */
+#define Panel300_1024x768       0x02
+#define Panel300_1280x1024      0x03
+#define Panel300_1280x960       0x04
+#define Panel300_640x480        0x05
+#define Panel300_1024x600       0x06
+#define Panel300_1152x768       0x07
+#define Panel300_1280x768       0x0a
+#define Panel300_320x480        0x0e 	/* fstn - This is fake, can be any */
+#define Panel300_Custom		0x0f
+#define Panel300_Barco1366      0x10
+
+#define Panel310_800x600        0x01
+#define Panel310_1024x768       0x02
+#define Panel310_1280x1024      0x03
+#define Panel310_640x480        0x04
+#define Panel310_1024x600       0x05
+#define Panel310_1152x864       0x06
+#define Panel310_1280x960       0x07
+#define Panel310_1152x768       0x08	/* LVDS only */
+#define Panel310_1400x1050      0x09
+#define Panel310_1280x768       0x0a
+#define Panel310_1600x1200      0x0b
+#define Panel310_640x480_2      0x0c
+#define Panel310_640x480_3      0x0d
+#define Panel310_320x480        0x0e    /* fstn - TW: This is fake, can be any */
+#define Panel310_Custom		0x0f
+
+#define Panel661_800x600        0x01
+#define Panel661_1024x768       0x02
+#define Panel661_1280x1024      0x03
+#define Panel661_640x480        0x04
+#define Panel661_1024x600       0x05
+#define Panel661_1152x864       0x06
+#define Panel661_1280x960       0x07
+#define Panel661_1152x768       0x08
+#define Panel661_1400x1050      0x09
+#define Panel661_1280x768       0x0a
+#define Panel661_1600x1200      0x0b
+#define Panel661_1280x800       0x0c
+#define Panel661_1680x1050      0x0d
+#define Panel661_1280x720       0x0e
+#define Panel661_Custom		0x0f
+
+#define Panel_800x600           0x01	/* Unified values */
+#define Panel_1024x768          0x02    /* MUST match BIOS values from 0-e */
+#define Panel_1280x1024         0x03
+#define Panel_640x480           0x04
+#define Panel_1024x600          0x05
+#define Panel_1152x864          0x06
+#define Panel_1280x960          0x07
+#define Panel_1152x768          0x08	/* LVDS only */
+#define Panel_1400x1050         0x09
+#define Panel_1280x768          0x0a    /* 30xB/C and LVDS only (BIOS: all) */
+#define Panel_1600x1200         0x0b
+#define Panel_1280x800		0x0c    /* 661etc (TMDS) */
+#define Panel_1680x1050         0x0d    /* 661etc  */
+#define Panel_1280x720		0x0e    /* 661etc  */
+#define Panel_Custom		0x0f	/* MUST BE 0x0f (for DVI DDC detection) */
+#define Panel_320x480           0x10    /* SiS 550 fstn - TW: This is fake, can be any */
+#define Panel_Barco1366         0x11
+#define Panel_848x480		0x12
+#define Panel_640x480_2		0x13    /* SiS 550 */
+#define Panel_640x480_3		0x14    /* SiS 550 */
+#define Panel_1280x768_2        0x15	/* 30xLV */
+#define Panel_1280x768_3        0x16    /* (unused) */
+#define Panel_1280x800_2	0x17    /* 30xLV */
+
+/* Index in ModeResInfo table */
+#define SIS_RI_320x200    0
+#define SIS_RI_320x240    1
+#define SIS_RI_320x400    2
+#define SIS_RI_400x300    3
+#define SIS_RI_512x384    4
+#define SIS_RI_640x400    5
+#define SIS_RI_640x480    6
+#define SIS_RI_800x600    7
+#define SIS_RI_1024x768   8
+#define SIS_RI_1280x1024  9
+#define SIS_RI_1600x1200 10
+#define SIS_RI_1920x1440 11
+#define SIS_RI_2048x1536 12
+#define SIS_RI_720x480   13
+#define SIS_RI_720x576   14
+#define SIS_RI_1280x960  15
+#define SIS_RI_800x480   16
+#define SIS_RI_1024x576  17
+#define SIS_RI_1280x720  18
+#define SIS_RI_856x480   19
+#define SIS_RI_1280x768  20
+#define SIS_RI_1400x1050 21
+#define SIS_RI_1152x864  22  /* Up to here SiS conforming */
+#define SIS_RI_848x480   23
+#define SIS_RI_1360x768  24
+#define SIS_RI_1024x600  25
+#define SIS_RI_1152x768  26
+#define SIS_RI_768x576   27
+#define SIS_RI_1360x1024 28
+#define SIS_RI_1680x1050 29
+#define SIS_RI_1280x800  30
+#define SIS_RI_1920x1080 31
+#define SIS_RI_960x540   32
+#define SIS_RI_960x600   33
+
+/* CR5F */
+#define IsM650                  0x80
+
+/* Timing data */
+#define NTSCHT                  1716
+#define NTSC2HT                 1920
+#define NTSCVT                  525
+#define PALHT                   1728
+#define PALVT                   625
+#define StHiTVHT                892
+#define StHiTVVT                1126
+#define StHiTextTVHT            1000
+#define StHiTextTVVT            1126
+#define ExtHiTVHT               2100
+#define ExtHiTVVT               1125
+
+/* Indices in (VB)VCLKData tables */
+
+#define VCLK28                  0x00   /* Index in VCLKData table (300 and 315) */
+#define VCLK40                  0x04   /* Index in VCLKData table (300 and 315) */
+#define VCLK65_300              0x09   /* Index in VCLKData table (300) */
+#define VCLK108_2_300           0x14   /* Index in VCLKData table (300) */
+#define VCLK81_300		0x3f   /* Index in VCLKData table (300) */
+#define VCLK108_3_300           0x42   /* Index in VCLKData table (300) */
+#define VCLK100_300             0x43   /* Index in VCLKData table (300) */
+#define VCLK34_300              0x3d   /* Index in VCLKData table (300) */
+#define VCLK_CUSTOM_300		0x47
+#define VCLK65_315              0x0b   /* Index in (VB)VCLKData table (315) */
+#define VCLK108_2_315           0x19   /* Index in (VB)VCLKData table (315) */
+#define VCLK81_315		0x5b   /* Index in (VB)VCLKData table (315) */
+#define VCLK162_315             0x5e   /* Index in (VB)VCLKData table (315) */
+#define VCLK108_3_315           0x45   /* Index in VBVCLKData table (315) */
+#define VCLK100_315             0x46   /* Index in VBVCLKData table (315) */
+#define VCLK34_315              0x55
+#define VCLK68_315		0x0d
+#define VCLK_1280x800_315_2	0x5c   /* Index in VBVCLKData table (315) */
+#define VCLK121_315		0x5d   /* Index in VBVCLKData table (315) */
+#define VCLK_1280x720		0x5f
+#define VCLK_1280x768_2		0x60
+#define VCLK_1280x768_3		0x61   /* (unused?) */
+#define VCLK_CUSTOM_315		0x62
+#define VCLK_1280x720_2		0x63
+#define VCLK_720x480		0x67
+#define VCLK_720x576		0x68
+#define VCLK_768x576		0x68
+#define VCLK_848x480		0x65
+#define VCLK_856x480		0x66
+#define VCLK_800x480		0x65
+#define VCLK_1024x576		0x51
+#define VCLK_1152x864		0x64
+#define VCLK_1360x768		0x58
+#define VCLK_1280x800_315	0x6c
+
+#define TVCLKBASE_300		0x21   /* Indices on TV clocks in VCLKData table (300) */
+#define TVCLKBASE_315	        0x3a   /* Indices on TV clocks in (VB)VCLKData table (315) */
+#define TVVCLKDIV2              0x00   /* Index relative to TVCLKBASE */
+#define TVVCLK                  0x01   /* Index relative to TVCLKBASE */
+#define HiTVVCLKDIV2            0x02   /* Index relative to TVCLKBASE */
+#define HiTVVCLK                0x03   /* Index relative to TVCLKBASE */
+#define HiTVSimuVCLK            0x04   /* Index relative to TVCLKBASE */
+#define HiTVTextVCLK            0x05   /* Index relative to TVCLKBASE */
+#define YPbPr750pVCLK		0x25   /* Index relative to TVCLKBASE; was 0x0f NOT relative */
+
+/* ------------------------------ */
+
+#define SetSCARTOutput          0x01
+
+#define HotPlugFunction         0x08
+
+#define StStructSize            0x06
+
+#define SIS_VIDEO_CAPTURE       0x00 - 0x30
+#define SIS_VIDEO_PLAYBACK      0x02 - 0x30
+#define SIS_CRT2_PORT_04        0x04 - 0x30
+#define SIS_CRT2_PORT_10        0x10 - 0x30
+#define SIS_CRT2_PORT_12        0x12 - 0x30
+#define SIS_CRT2_PORT_14        0x14 - 0x30
+
+#define ADR_CRT2PtrData         0x20E
+#define offset_Zurac            0x210   /* TW: Trumpion Zurac data pointer */
+#define ADR_LVDSDesPtrData      0x212
+#define ADR_LVDSCRT1DataPtr     0x214
+#define ADR_CHTVVCLKPtr         0x216
+#define ADR_CHTVRegDataPtr      0x218
+
+#define LCDDataLen              8
+#define HiTVDataLen             12
+#define TVDataLen               16
+
+#define LVDSDataLen             6
+#define LVDSDesDataLen          3
+#define ActiveNonExpanding      0x40
+#define ActiveNonExpandingShift 6
+#define ActivePAL               0x20
+#define ActivePALShift          5
+#define ModeSwitchStatus        0x0F
+#define SoftTVType              0x40
+#define SoftSettingAddr         0x52
+#define ModeSettingAddr         0x53
+
+#define _PanelType00             0x00
+#define _PanelType01             0x08
+#define _PanelType02             0x10
+#define _PanelType03             0x18
+#define _PanelType04             0x20
+#define _PanelType05             0x28
+#define _PanelType06             0x30
+#define _PanelType07             0x38
+#define _PanelType08             0x40
+#define _PanelType09             0x48
+#define _PanelType0A             0x50
+#define _PanelType0B             0x58
+#define _PanelType0C             0x60
+#define _PanelType0D             0x68
+#define _PanelType0E             0x70
+#define _PanelType0F             0x78
+
+#define PRIMARY_VGA       	0     /* 1: SiS is primary vga 0:SiS is secondary vga */
+
+#define BIOSIDCodeAddr          0x235  /* Offsets to ptrs in BIOS image */
+#define OEMUtilIDCodeAddr       0x237
+#define VBModeIDTableAddr       0x239
+#define OEMTVPtrAddr            0x241
+#define PhaseTableAddr          0x243
+#define NTSCFilterTableAddr     0x245
+#define PALFilterTableAddr      0x247
+#define OEMLCDPtr_1Addr         0x249
+#define OEMLCDPtr_2Addr         0x24B
+#define LCDHPosTable_1Addr      0x24D
+#define LCDHPosTable_2Addr      0x24F
+#define LCDVPosTable_1Addr      0x251
+#define LCDVPosTable_2Addr      0x253
+#define OEMLCDPIDTableAddr      0x255
+
+#define VBModeStructSize        5
+#define PhaseTableSize          4
+#define FilterTableSize         4
+#define LCDHPosTableSize        7
+#define LCDVPosTableSize        5
+#define OEMLVDSPIDTableSize     4
+#define LVDSHPosTableSize       4
+#define LVDSVPosTableSize       6
+
+#define VB_ModeID               0
+#define VB_TVTableIndex         1
+#define VB_LCDTableIndex        2
+#define VB_LCDHIndex            3
+#define VB_LCDVIndex            4
+
+#define OEMLCDEnable            0x0001
+#define OEMLCDDelayEnable       0x0002
+#define OEMLCDPOSEnable         0x0004
+#define OEMTVEnable             0x0100
+#define OEMTVDelayEnable        0x0200
+#define OEMTVFlickerEnable      0x0400
+#define OEMTVPhaseEnable        0x0800
+#define OEMTVFilterEnable       0x1000
+
+#define OEMLCDPanelIDSupport    0x0080
+
+/*
+  =============================================================
+   		  for 315 series (old data layout)
+  =============================================================
+*/
+#define SoftDRAMType        0x80
+#define SoftSetting_OFFSET  0x52
+#define SR07_OFFSET  0x7C
+#define SR15_OFFSET  0x7D
+#define SR16_OFFSET  0x81
+#define SR17_OFFSET  0x85
+#define SR19_OFFSET  0x8D
+#define SR1F_OFFSET  0x99
+#define SR21_OFFSET  0x9A
+#define SR22_OFFSET  0x9B
+#define SR23_OFFSET  0x9C
+#define SR24_OFFSET  0x9D
+#define SR25_OFFSET  0x9E
+#define SR31_OFFSET  0x9F
+#define SR32_OFFSET  0xA0
+#define SR33_OFFSET  0xA1
+
+#define CR40_OFFSET  0xA2
+#define SR25_1_OFFSET  0xF6
+#define CR49_OFFSET  0xF7
+
+#define VB310Data_1_2_Offset  0xB6
+#define VB310Data_4_D_Offset  0xB7
+#define VB310Data_4_E_Offset  0xB8
+#define VB310Data_4_10_Offset 0xBB
+
+#define RGBSenseDataOffset    0xBD
+#define YCSenseDataOffset     0xBF
+#define VideoSenseDataOffset  0xC1
+#define OutputSelectOffset    0xF3
+
+#define ECLK_MCLK_DISTANCE  0x14
+#define VBIOSTablePointerStart    0x100
+#define StandTablePtrOffset       VBIOSTablePointerStart+0x02
+#define EModeIDTablePtrOffset     VBIOSTablePointerStart+0x04
+#define CRT1TablePtrOffset        VBIOSTablePointerStart+0x06
+#define ScreenOffsetPtrOffset     VBIOSTablePointerStart+0x08
+#define VCLKDataPtrOffset         VBIOSTablePointerStart+0x0A
+#define MCLKDataPtrOffset         VBIOSTablePointerStart+0x0E
+#define CRT2PtrDataPtrOffset      VBIOSTablePointerStart+0x10
+#define TVAntiFlickPtrOffset      VBIOSTablePointerStart+0x12
+#define TVDelayPtr1Offset         VBIOSTablePointerStart+0x14
+#define TVPhaseIncrPtr1Offset     VBIOSTablePointerStart+0x16
+#define TVYFilterPtr1Offset       VBIOSTablePointerStart+0x18
+#define LCDDelayPtr1Offset        VBIOSTablePointerStart+0x20
+#define TVEdgePtr1Offset          VBIOSTablePointerStart+0x24
+#define CRT2Delay1Offset          VBIOSTablePointerStart+0x28
+
+#endif
diff --git a/drivers/video/sis/oem300.h b/drivers/video/sis/oem300.h
new file mode 100644
index 0000000..b1358b7
--- /dev/null
+++ b/drivers/video/sis/oem300.h
@@ -0,0 +1,859 @@
+/* $XFree86$ */
+/* $XdotOrg$ */
+/*
+ * OEM Data for 300 series
+ *
+ * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, the following license terms
+ * apply:
+ *
+ * * This program is free software; you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License as published by
+ * * the Free Software Foundation; either version 2 of the named License,
+ * * or any later version.
+ * *
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details.
+ * *
+ * * You should have received a copy of the GNU General Public License
+ * * along with this program; if not, write to the Free Software
+ * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * * Redistribution and use in source and binary forms, with or without
+ * * modification, are permitted provided that the following conditions
+ * * are met:
+ * * 1) Redistributions of source code must retain the above copyright
+ * *    notice, this list of conditions and the following disclaimer.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * *    notice, this list of conditions and the following disclaimer in the
+ * *    documentation and/or other materials provided with the distribution.
+ * * 3) The name of the author may not be used to endorse or promote products
+ * *    derived from this software without specific prior written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ */
+
+static const UCHAR SiS300_OEMTVDelay301[8][4] =
+{
+	{0x08,0x08,0x08,0x08},
+	{0x08,0x08,0x08,0x08},
+	{0x08,0x08,0x08,0x08},
+	{0x2c,0x2c,0x2c,0x2c},
+	{0x08,0x08,0x08,0x08},
+	{0x08,0x08,0x08,0x08},
+	{0x08,0x08,0x08,0x08},
+	{0x20,0x20,0x20,0x20}
+};
+
+static const UCHAR SiS300_OEMTVDelayLVDS[8][4] =
+{
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20}
+};
+
+static const UCHAR SiS300_OEMTVFlicker[8][4] =
+{
+	{0x00,0x00,0x00,0x00},
+	{0x00,0x00,0x00,0x00},
+	{0x00,0x00,0x00,0x00},
+	{0x00,0x00,0x00,0x00},
+	{0x00,0x00,0x00,0x00},
+	{0x00,0x00,0x00,0x00},
+	{0x00,0x00,0x00,0x00},
+	{0x00,0x00,0x00,0x00}
+};
+
+#if 0   /* TW: Not used */
+static const UCHAR SiS300_OEMLCDDelay1[12][4]={
+	{0x2c,0x2c,0x2c,0x2c},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x2c,0x2c,0x2c,0x2c},
+	{0x2c,0x2c,0x2c,0x2c},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x24,0x24,0x24,0x24},
+	{0x24,0x24,0x24,0x24},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x24,0x24,0x24,0x24}
+};
+#endif
+
+/* From 630/301B BIOS */
+static const UCHAR SiS300_OEMLCDDelay2[64][4] =		 /* for 301/301b/302b/301LV/302LV */
+{
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20}
+};
+
+/* From 300/301LV BIOS */
+static const UCHAR SiS300_OEMLCDDelay4[12][4] =
+{
+	{0x2c,0x2c,0x2c,0x2c},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x2c,0x2c,0x2c,0x2c},
+	{0x2c,0x2c,0x2c,0x2c},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x24,0x24,0x24,0x24},
+	{0x24,0x24,0x24,0x24},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x24,0x24,0x24,0x24}
+};
+
+/* From 300/301LV BIOS */
+static const UCHAR SiS300_OEMLCDDelay5[32][4] =
+{
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+};
+
+/* Added for LVDS */
+static const UCHAR SiS300_OEMLCDDelay3[64][4] = {	/* For LVDS */
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20}
+};
+
+static const UCHAR SiS300_Phase1[8][5][4] =
+{
+    {
+	{0x21,0xed,0x00,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0x21,0xed,0x8a,0x08}
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00}
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00}
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00}
+    },
+    {
+        {0x21,0xed,0x00,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0x21,0xed,0x8a,0x08}
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00}
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00}
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00}
+    }
+};
+
+
+static const UCHAR SiS300_Phase2[8][5][4] =
+{
+    {
+        {0x21,0xed,0x00,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0x21,0xed,0x8a,0x08}
+    },
+    {
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00}
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00}
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00}
+    },
+    {
+        {0x21,0xed,0x00,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0x21,0xed,0x8a,0x08}
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00}
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00}
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00}
+    }
+};
+
+static const UCHAR SiS300_Filter1[10][16][4] =
+{
+    {
+	{0x00,0xf4,0x10,0x38},
+	{0x00,0xf4,0x10,0x38},
+	{0xeb,0x04,0x10,0x18},
+	{0xf7,0x06,0x19,0x14},
+	{0x00,0xf4,0x10,0x38},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x15,0x25,0xf6},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18}
+    },
+    {
+	{0x00,0xf4,0x10,0x38},
+	{0x00,0xf4,0x10,0x38},
+	{0xf1,0xf7,0x10,0x32},
+	{0xf3,0x00,0x1d,0x20},
+	{0x00,0xf4,0x10,0x38},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xfc,0xfb,0x14,0x2a},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32}
+    },
+    {
+	{0x00,0xf4,0x10,0x38},
+	{0x00,0xf4,0x10,0x38},
+	{0xf1,0xf7,0x10,0x32},
+	{0xf3,0x00,0x1d,0x20},
+	{0x00,0xf4,0x10,0x38},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xfc,0xfb,0x14,0x2a},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32}
+    },
+    {
+	{0x00,0xf4,0x10,0x38},
+	{0x00,0xf4,0x10,0x38},
+	{0xf1,0xf7,0x10,0x32},
+	{0xf3,0x00,0x1d,0x20},
+	{0x00,0xf4,0x10,0x38},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xfc,0xfb,0x14,0x2a},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32}
+    },
+    {
+	{0x00,0xf4,0x10,0x38},
+	{0x00,0xf4,0x10,0x38},
+	{0xeb,0x04,0x10,0x18},
+	{0xf7,0x06,0x19,0x14},
+	{0x00,0xf4,0x10,0x38},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x15,0x25,0xf6},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18}
+    },
+    {
+	{0x00,0xf4,0x10,0x38},
+	{0x00,0xf4,0x10,0x38},
+	{0xf1,0xf7,0x10,0x32},
+	{0xf3,0x00,0x1d,0x20},
+	{0x00,0xf4,0x10,0x38},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xfc,0xfb,0x14,0x2a},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32}
+    },
+    {
+	{0x00,0xf4,0x10,0x38},
+	{0x00,0xf4,0x10,0x38},
+	{0xf1,0xf7,0x10,0x32},
+	{0xf3,0x00,0x1d,0x20},
+	{0x00,0xf4,0x10,0x38},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xfc,0xfb,0x14,0x2a},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32}
+    },
+    {
+	{0x00,0xf4,0x10,0x38},
+	{0x00,0xf4,0x10,0x38},
+	{0xf1,0xf7,0x10,0x32},
+	{0xf3,0x00,0x1d,0x20},
+	{0x00,0xf4,0x10,0x38},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xfc,0xfb,0x14,0x2a},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf1,0xf7,0x1f,0x32}
+    },
+    {
+	{0x00,0xf4,0x10,0x38},
+	{0x00,0xf4,0x10,0x38},
+	{0xeb,0x04,0x10,0x18},
+	{0xf7,0x06,0x19,0x14},
+	{0x00,0xf4,0x10,0x38},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x15,0x25,0xf6},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18}
+    },
+    {
+	{0x00,0xf4,0x10,0x38},
+	{0x00,0xf4,0x10,0x38},
+	{0xeb,0x04,0x10,0x18},
+	{0xf7,0x06,0x19,0x14},
+	{0x00,0xf4,0x10,0x38},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x15,0x25,0xf6},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18}
+    },
+};
+
+static const UCHAR SiS300_Filter2[10][9][7] =
+{
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    },
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    },
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    },
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    },
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    },
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    },
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    },
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    },
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    },
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    }
+};
+
+/* Custom data for Barco iQ Pro R300 */
+static const UCHAR barco_p1[2][9][7][3] = {
+    {
+	{  { 0x16, 0xcf, 0x00 },
+	   { 0x18, 0x00, 0x00 },
+	   { 0x1a, 0xe7, 0x00 },
+	   { 0x1b, 0x26, 0x00 },
+	   { 0x1c, 0xff, 0x00 },
+	   { 0x1d, 0x1c, 0x00 },
+	   { 0x1e, 0x19, 0x00 }
+	},
+	{
+	   { 0x16, 0xcf, 0x00 },
+	   { 0x18, 0x00, 0x00 },
+	   { 0x1a, 0xe7, 0x00 },
+	   { 0x1b, 0x1e, 0x00 },
+	   { 0x1c, 0xff, 0x00 },
+	   { 0x1d, 0x1c, 0x00 },
+	   { 0x1e, 0x16, 0x00 }
+	},
+	{
+	   { 0x16, 0xcf, 0x00 },
+	   { 0x1a, 0xe7, 0x00 },
+	   { 0x1b, 0x26, 0x00 },
+	   { 0x1c, 0xff, 0x00 },
+	   { 0x1d, 0x1c, 0x00 },
+	   { 0x1e, 0x19, 0x00 },
+	   {    0,    0,    0 }
+	},
+	{
+	   {    0,    0,    0 }
+	},
+	{
+	   { 0x16, 0xcf, 0x00 },
+	   { 0x1a, 0xe7, 0x00 },
+	   { 0x1b, 0x26, 0x00 },
+	   { 0x1c, 0xff, 0x00 },
+	   { 0x1d, 0x1c, 0x00 },
+	   { 0x1e, 0x1e, 0x00 },
+	   {    0,    0,    0 }
+	},
+	{
+	   { 0x16, 0xd1, 0x00 },
+	   { 0x18, 0x00, 0x00 },
+	   { 0x1a, 0xe7, 0x00 },
+	   { 0x1b, 0x11, 0x00 },
+	   { 0x1c, 0xff, 0x00 },
+	   { 0x1d, 0x1c, 0x00 },
+	   { 0x1e, 0x26, 0x00 }
+	},
+	{
+	   { 0x16, 0xd1, 0x00 },
+	   { 0x1a, 0xe7, 0x00 },
+	   { 0x1b, 0x26, 0x00 },
+	   { 0x1c, 0xff, 0x00 },
+	   { 0x1d, 0x1c, 0x00 },
+	   { 0x1e, 0x30, 0x00 },
+	   {    0,    0,    0 }
+	},
+	{
+	   { 0x16, 0x00, 0x00 },
+	   { 0x17, 0xa0, 0x00 },
+	   { 0x1a, 0xa0, 0x00 },
+	   { 0x1b, 0x2a, 0x00 },
+	   { 0x1c, 0xff, 0x00 },
+	   { 0x1d, 0x1c, 0x00 },
+	   {    0,    0,    0 }
+	},
+	{
+	   { 0x16, 0x00, 0x00 },
+	   { 0x17, 0xaa, 0x00 },
+	   { 0x1a, 0xa0, 0x00 },
+	   { 0x1b, 0x2a, 0x00 },
+	   { 0x1c, 0xff, 0x00 },
+	   { 0x1d, 0x1c, 0x00 },
+	   {    0,    0,    0 }
+	}
+    },
+    {
+	{
+	   { 0x16, 0xcf, 0x00 },
+	   { 0x18, 0x00, 0x00 },
+	   { 0x1a, 0xe7, 0x00 },
+	   { 0x1b, 0x26, 0x00 },
+	   { 0x1c, 0xff, 0x00 },
+	   { 0x1d, 0x1c, 0x00 },
+	   { 0x1e, 0x19, 0x00 }
+	},
+	{
+	   {    0,    0,    0 }
+	},
+	{
+	   { 0x16, 0xcf, 0x00 },
+	   { 0x18, 0x00, 0x00 },
+	   { 0x1a, 0xe7, 0x00 },
+	   { 0x1b, 0x26, 0x00 },
+	   { 0x1c, 0xff, 0x00 },
+	   { 0x1d, 0x1c, 0x00 },
+	   { 0x1e, 0x19, 0x00 },
+	},
+	{
+	   {    0,    0,    0 }
+	},
+	{
+	   { 0x16, 0xcf, 0x00 },
+	   { 0x18, 0x00, 0x00 },
+	   { 0x1a, 0xe7, 0x00 },
+	   { 0x1b, 0x26, 0x00 },
+	   { 0x1c, 0xff, 0x00 },
+	   { 0x1d, 0x1c, 0x00 },
+	   { 0x1e, 0x1e, 0x00 }
+	},
+	{
+	   { 0x16, 0xd1, 0x00 },
+	   { 0x18, 0x00, 0x00 },
+	   { 0x1a, 0xe6, 0x00 },
+	   { 0x1b, 0x11, 0x00 },
+	   { 0x1c, 0xff, 0x00 },
+	   { 0x1d, 0x1c, 0x00 },
+	   { 0x1e, 0x26, 0x00 }
+	},
+	{
+	   { 0x18, 0x00, 0x00 },
+	   { 0x1a, 0xe0, 0x00 },
+	   { 0x1b, 0x26, 0x00 },
+	   { 0x1c, 0xff, 0x00 },
+	   { 0x1d, 0x1c, 0x00 },
+	   { 0x1e, 0x30, 0x00 },
+	   {    0,    0,    0 }
+	},
+	{
+	   {    0,    0,    0 }
+	},
+	{
+	   {    0,    0,    0 }
+	}
+    }
+};
+
+
+
+
+
+
diff --git a/drivers/video/sis/oem310.h b/drivers/video/sis/oem310.h
new file mode 100644
index 0000000..2b7db91
--- /dev/null
+++ b/drivers/video/sis/oem310.h
@@ -0,0 +1,449 @@
+/* $XFree86$ */
+/* $XdotOrg$ */
+/*
+ * OEM Data for 315/330 series
+ *
+ * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, the following license terms
+ * apply:
+ *
+ * * This program is free software; you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License as published by
+ * * the Free Software Foundation; either version 2 of the named License,
+ * * or any later version.
+ * *
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details.
+ * *
+ * * You should have received a copy of the GNU General Public License
+ * * along with this program; if not, write to the Free Software
+ * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * * Redistribution and use in source and binary forms, with or without
+ * * modification, are permitted provided that the following conditions
+ * * are met:
+ * * 1) Redistributions of source code must retain the above copyright
+ * *    notice, this list of conditions and the following disclaimer.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * *    notice, this list of conditions and the following disclaimer in the
+ * *    documentation and/or other materials provided with the distribution.
+ * * 3) The name of the author may not be used to endorse or promote products
+ * *    derived from this software without specific prior written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ */
+
+static const UCHAR SiS310_LCDDelayCompensation_301[] =	    		/* 301 */
+{
+		 0x00,0x00,0x00,    /*   800x600 */
+		 0x0b,0x0b,0x0b,    /*  1024x768 */
+		 0x08,0x08,0x08,    /* 1280x1024 */
+		 0x00,0x00,0x00,    /*   640x480 (unknown) */
+		 0x00,0x00,0x00,    /*  1024x600 (unknown) */
+		 0x00,0x00,0x00,    /*  1152x864 (unknown) */
+		 0x08,0x08,0x08,    /*  1280x960 (guessed) */
+		 0x00,0x00,0x00,    /*  1152x768 (unknown) */
+		 0x08,0x08,0x08,    /* 1400x1050 */
+		 0x08,0x08,0x08,    /*  1280x768  (guessed) */
+		 0x00,0x00,0x00,    /* 1600x1200 */
+		 0x00,0x00,0x00,    /*   320x480 (unknown) */
+		 0x00,0x00,0x00,
+		 0x00,0x00,0x00,
+		 0x00,0x00,0x00
+};
+
+/* This is contained in 650+301B BIOSes, but it is wrong - so we don't use it */
+static const UCHAR SiS310_LCDDelayCompensation_650301LV[] =	   	/* 650 + 30xLV */
+{
+		 0x01,0x01,0x01,    /*   800x600 */
+		 0x01,0x01,0x01,    /*  1024x768 */
+		 0x01,0x01,0x01,    /* 1280x1024 */
+                 0x01,0x01,0x01,    /*   640x480 (unknown) */
+		 0x01,0x01,0x01,    /*  1024x600 (unknown) */
+		 0x01,0x01,0x01,    /*  1152x864 (unknown) */
+		 0x01,0x01,0x01,    /*  1280x960 (guessed) */
+		 0x01,0x01,0x01,    /*  1152x768 (unknown) */
+		 0x01,0x01,0x01,    /* 1400x1050 */
+		 0x01,0x01,0x01,    /*  1280x768  (guessed) */
+		 0x01,0x01,0x01,    /* 1600x1200 */
+		 0x02,0x02,0x02,
+		 0x02,0x02,0x02,
+		 0x02,0x02,0x02,
+		 0x02,0x02,0x02
+};
+
+static const UCHAR SiS310_LCDDelayCompensation_651301LV[] =	  	/* M650/651 301LV */
+{
+                 0x33,0x33,0x33,    /*   800x600 (guessed) - new: PanelType, not PanelRes ! */
+		 0x33,0x33,0x33,    /*  1024x768 */
+		 0x33,0x33,0x33,    /* 1280x1024 */
+		 0x33,0x33,0x33,    /*   640x480 (unknown) */
+		 0x33,0x33,0x33,    /*  1024x600 (unknown) */
+		 0x33,0x33,0x33,    /*  1152x864 (unknown) */
+		 0x33,0x33,0x33,    /*  1280x960 (guessed) */
+		 0x33,0x33,0x33,    /*  1152x768 (unknown) */
+		 0x33,0x33,0x33,    /* 1400x1050 */
+		 0x33,0x33,0x33,    /*  1280x768  (guessed) */
+		 0x33,0x33,0x33,    /* 1600x1200 */
+		 0x33,0x33,0x33,
+		 0x33,0x33,0x33,
+		 0x33,0x33,0x33,
+		 0x33,0x33,0x33
+};
+
+static const UCHAR SiS310_LCDDelayCompensation_651302LV[] =	   	/* M650/651 302LV */
+{
+                 0x33,0x33,0x33,    /*   800x600 (guessed) */
+		 0x33,0x33,0x33,    /*  1024x768 */
+		 0x33,0x33,0x33,    /* 1280x1024 */
+		 0x33,0x33,0x33,    /*   640x480 (unknown) */
+		 0x33,0x33,0x33,    /*  1024x600 (unknown) */
+		 0x33,0x33,0x33,    /*  1152x864 (unknown) */
+		 0x33,0x33,0x33,    /*  1280x960 (guessed) */
+		 0x33,0x33,0x33,    /*  1152x768 (unknown) */
+		 0x33,0x33,0x33,    /* 1400x1050 */
+		 0x33,0x33,0x33,    /*  1280x768  (guessed) */
+		 0x33,0x33,0x33,    /* 1600x1200 */
+		 0x33,0x33,0x33,
+		 0x33,0x33,0x33,
+		 0x33,0x33,0x33,
+		 0x33,0x33,0x33
+};
+
+static const UCHAR SiS310_LCDDelayCompensation_3xx301B[] =	   	/* 30xB */
+{
+		 0x01,0x01,0x01,    /*   800x600 */
+		 0x0C,0x0C,0x0C,    /*  1024x768 */
+		 0x0C,0x0C,0x0C,    /* 1280x1024 */
+                 0x08,0x08,0x08,    /*   640x480 */
+		 0x0C,0x0C,0x0C,    /*  1024x600 (guessed) */
+		 0x0C,0x0C,0x0C,    /*  1152x864 (guessed) */
+		 0x0C,0x0C,0x0C,    /*  1280x960 (guessed) */
+		 0x0C,0x0C,0x0C,    /*  1152x768 (guessed) */
+		 0x0C,0x0C,0x0C,    /* 1400x1050 (guessed) */
+		 0x0C,0x0C,0x0C,    /*  1280x768 (guessed) */
+		 0x0C,0x0C,0x0C,    /* 1600x1200 (guessed) */
+		 0x02,0x02,0x02,
+		 0x02,0x02,0x02,
+		 0x02,0x02,0x02,
+		 0x02,0x02,0x02
+};
+
+static const UCHAR SiS310_LCDDelayCompensation_3xx301LV[] =	   	/* 315+30xLV */
+{
+		 0x01,0x01,0x01,    /*   800x600 */
+		 0x04,0x04,0x04,    /*  1024x768 (A531/BIOS 1.14.05f: 4 - works with 6 */
+		 0x0C,0x0C,0x0C,    /* 1280x1024 */
+                 0x08,0x08,0x08,    /*   640x480 */
+		 0x0C,0x0C,0x0C,    /*  1024x600 (guessed) */
+		 0x0C,0x0C,0x0C,    /*  1152x864 (guessed) */
+		 0x0C,0x0C,0x0C,    /*  1280x960 (guessed) */
+		 0x0C,0x0C,0x0C,    /*  1152x768 (guessed) */
+		 0x0C,0x0C,0x0C,    /* 1400x1050 (guessed) */
+		 0x0C,0x0C,0x0C,    /*  1280x768 (guessed) */
+		 0x0C,0x0C,0x0C,    /* 1600x1200 (guessed) */
+		 0x02,0x02,0x02,
+		 0x02,0x02,0x02,
+		 0x02,0x02,0x02,
+		 0x02,0x02,0x02
+};
+
+static const UCHAR SiS310_TVDelayCompensation_301[] = 		/* 301 */
+{
+		 0x02,0x02,    /* NTSC Enhanced, Standard */
+                 0x02,0x02,    /* PAL */
+		 0x08,0x0b     /* HiVision */
+};
+
+static const UCHAR SiS310_TVDelayCompensation_301B[] =		/* 30xB, 30xLV */
+{
+		 0x03,0x03,
+		 0x03,0x03,
+		 0x03,0x03
+};
+
+static const UCHAR SiS310_TVDelayCompensation_740301B[] =	/* 740 + 30xB (30xLV?) */
+{
+		 0x05,0x05,
+		 0x05,0x05,
+		 0x05,0x05
+};
+
+static const UCHAR SiS310_TVDelayCompensation_651301LV[] =	/* M650, 651, 301LV */
+{
+		 0x33,0x33,
+		 0x33,0x33,
+		 0x33,0x33
+};
+
+static const UCHAR SiS310_TVDelayCompensation_651302LV[] =	/* M650, 651, 302LV */
+{
+		 0x33,0x33,
+		 0x33,0x33,
+		 0x33,0x33
+};
+
+static const UCHAR SiS_TVDelay661_301[] =			/* 661, 301 */
+{
+		 0x44,0x44,
+		 0x44,0x44,
+		 0x00,0x00,
+		 0x44,0x44,
+		 0x44,0x44,
+		 0x44,0x44
+};
+
+static const UCHAR SiS_TVDelay661_301B[] =			/* 661, 301B et al */
+{
+		 0x44,0x44,
+		 0x44,0x44,
+		 0x00,0x00,
+		 0x44,0x44,
+		 0x44,0x44,
+		 0x44,0x44
+};
+
+static const UCHAR SiS310_TVDelayCompensation_LVDS[] =		/* LVDS */
+{
+		 0x0a,0x0a,
+		 0x0a,0x0a,
+		 0x0a,0x0a
+};
+
+static const UCHAR SiS310_TVAntiFlick1[6][2] =
+{
+            {0x4,0x0},
+	    {0x4,0x8},
+	    {0x0,0x0},
+	    {0x0,0x0},
+	    {0x0,0x0},
+	    {0x0,0x0}
+};
+
+static const UCHAR SiS310_TVEdge1[6][2] =
+{
+            {0x0,0x4},
+	    {0x0,0x4},
+	    {0x0,0x0},
+	    {0x0,0x0},
+	    {0x0,0x0},
+	    {0x0,0x0}
+};
+
+static const UCHAR SiS310_TVYFilter1[5][8][4] =
+{
+ {
+	{0x00,0xf4,0x10,0x38},	/* NTSC */
+	{0x00,0xf4,0x10,0x38},
+	{0xeb,0x04,0x25,0x18},
+	{0xf1,0x04,0x1f,0x18},
+	{0x00,0xf4,0x10,0x38},
+	{0xeb,0x04,0x25,0x18},
+	{0xee,0x0c,0x22,0x08},
+	{0xeb,0x15,0x25,0xf6}
+ },
+ {
+	{0x00,0xf4,0x10,0x38},	/* PAL */
+	{0x00,0xf4,0x10,0x38},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf3,0x00,0x1d,0x20},
+	{0x00,0xf4,0x10,0x38},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf3,0x00,0x1d,0x20},
+	{0xfc,0xfb,0x14,0x2a}
+ },
+ {
+	{0x00,0x00,0x00,0x00},	/* HiVision */
+	{0x00,0xf4,0x10,0x38},
+	{0x00,0xf4,0x10,0x38},
+	{0xeb,0x04,0x25,0x18},
+	{0xf7,0x06,0x19,0x14},
+	{0x00,0xf4,0x10,0x38},
+	{0xeb,0x04,0x25,0x18},
+	{0xee,0x0c,0x22,0x08}
+ },
+ {
+ 	{0x00,0xf4,0x10,0x38},	/* PAL-M */
+	{0x00,0xf4,0x10,0x38},
+	{0xeb,0x04,0x10,0x18},
+	{0xf7,0x06,0x19,0x14},
+	{0x00,0xf4,0x10,0x38},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x15,0x25,0xf6}
+ },
+ {
+ 	{0x00,0xf4,0x10,0x38},	/* PAL-N */
+	{0x00,0xf4,0x10,0x38},
+	{0xeb,0x04,0x10,0x18},
+	{0xf7,0x06,0x19,0x14},
+	{0x00,0xf4,0x10,0x38},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x04,0x25,0x18},
+	{0xeb,0x15,0x25,0xf6}
+ }
+};
+
+static const UCHAR SiS310_TVYFilter2[5][9][7] =
+{
+ {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},	/* NTSC */
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+ },
+ {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},   /* PAL */
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+ },
+ {
+	{0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22},	/* HiVision */
+	{0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22},
+	{0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22},
+	{0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22},
+	{0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22},
+	{0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22},
+	{0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22},
+	{0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22},
+	{0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22}
+ },
+ {
+ 	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, 	/* PAL-M */
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+ },
+ {
+ 	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},	/* PAL-N */
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+ }
+};
+
+static const UCHAR SiS310_TVPhaseIncr1[3][2][4] =
+{
+ {
+	{0x21,0xed,0xba,0x08},
+	{0x21,0xed,0xba,0x08}
+ },
+ {
+	{0x2a,0x05,0xe3,0x00},
+	{0x2a,0x05,0xe3,0x00}
+ },
+ {
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00}
+ }
+};
+
+static const UCHAR SiS310_TVPhaseIncr2[3][2][4] =
+{
+ {
+	{0x21,0xf0,0x7b,0xd6},
+	{0x21,0xf0,0x7b,0xd6}
+ },
+ {
+	{0x2a,0x0a,0x41,0xe9},
+	{0x2a,0x0a,0x41,0xe9}
+ },
+ {
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00}
+ }
+};
+
+static const UCHAR SiS661_TVPhase[] = {
+    0x21,0xED,0xBA,0x08,
+    0x2A,0x05,0xE3,0x00,
+    0x21,0xE4,0x2E,0x9B,
+    0x21,0xF4,0x3E,0xBA,
+    0x1E,0x8B,0xA2,0xA7,
+    0x1E,0x83,0x0A,0xE0,
+    0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,
+    0x21,0xF0,0x7B,0xD6,
+    0x2A,0x09,0x86,0xE9,
+    0x21,0xE6,0xEF,0xA4,
+    0x21,0xF6,0x94,0x46,
+    0x1E,0x8B,0xA2,0xA7,
+    0x1E,0x83,0x0A,0xE0,
+    0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00
+};
+
+/**************************************************************/
+/* CUSTOM TIMING DATA --------------------------------------- */
+/**************************************************************/
+
+/* Inventec / Compaq Presario 3045US, 3017 */
+
+static const SiS_LCDDataStruct  SiS310_ExtCompaq1280x1024Data[] =
+{
+	{  211,  60,1024, 501,1688,1066},
+	{  211,  60,1024, 508,1688,1066},
+	{  211,  60,1024, 501,1688,1066},
+	{  211,  60,1024, 508,1688,1066},
+	{   32,  15,1696, 501,1696,1066},
+	{  212,  75,1024, 621,1696,1066},
+	{    4,   3,1696, 810,1696,1066},
+	{    1,   1,1696,1066,1696,1066}
+};
+
+/* Asus A2xxxH _2 */
+
+static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Asus1024x768_3[] =
+{
+ {{0x25,0x13,0xc9,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x2c,0x13,0x9a,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x25,0x13,0xc9,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x38,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x38,0x13,0x16,0x25,0xff,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}},
+ {{0x36,0x13,0x13,0x25,0xff,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x25,0x13,0xc9,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}
+};
+
+
+
+
diff --git a/drivers/video/sis/osdef.h b/drivers/video/sis/osdef.h
new file mode 100644
index 0000000..15939b0
--- /dev/null
+++ b/drivers/video/sis/osdef.h
@@ -0,0 +1,131 @@
+/* $XFree86$ */
+/* $XdotOrg$ */
+/*
+ * OS depending defines
+ *
+ * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, the following license terms
+ * apply:
+ *
+ * * This program is free software; you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License as published by
+ * * the Free Software Foundation; either version 2 of the named License,
+ * * or any later version.
+ * *
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details.
+ * *
+ * * You should have received a copy of the GNU General Public License
+ * * along with this program; if not, write to the Free Software
+ * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * * Redistribution and use in source and binary forms, with or without
+ * * modification, are permitted provided that the following conditions
+ * * are met:
+ * * 1) Redistributions of source code must retain the above copyright
+ * *    notice, this list of conditions and the following disclaimer.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * *    notice, this list of conditions and the following disclaimer in the
+ * *    documentation and/or other materials provided with the distribution.
+ * * 3) The name of the author may not be used to endorse or promote products
+ * *    derived from this software without specific prior written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ *		Silicon Integrated Systems, Inc. (used by permission)
+ *
+ */
+
+#ifndef _SIS_OSDEF_H_
+#define _SIS_OSDEF_H_
+
+/* The choices are: */
+#define LINUX_KERNEL	   /* Linux kernel framebuffer */
+/* #define LINUX_XF86 */   /* XFree86/X.org */
+
+#ifdef OutPortByte
+#undef OutPortByte
+#endif
+
+#ifdef OutPortWord
+#undef OutPortWord
+#endif
+
+#ifdef OutPortLong
+#undef OutPortLong
+#endif
+
+#ifdef InPortByte
+#undef InPortByte
+#endif
+
+#ifdef InPortWord
+#undef InPortWord
+#endif
+
+#ifdef InPortLong
+#undef InPortLong
+#endif
+
+/**********************************************************************/
+/*  LINUX KERNEL                                                      */
+/**********************************************************************/
+
+#ifdef LINUX_KERNEL
+#include <linux/config.h>
+
+#ifdef CONFIG_FB_SIS_300
+#define SIS300
+#endif
+
+#ifdef CONFIG_FB_SIS_315
+#define SIS315H
+#endif
+
+#if !defined(SIS300) && !defined(SIS315H)
+#warning Neither CONFIG_FB_SIS_300 nor CONFIG_FB_SIS_315 is set
+#warning sisfb will not work!
+#endif
+
+#define OutPortByte(p,v) outb((u8)(v),(SISIOADDRESS)(p))
+#define OutPortWord(p,v) outw((u16)(v),(SISIOADDRESS)(p))
+#define OutPortLong(p,v) outl((u32)(v),(SISIOADDRESS)(p))
+#define InPortByte(p)    inb((SISIOADDRESS)(p))
+#define InPortWord(p)    inw((SISIOADDRESS)(p))
+#define InPortLong(p)    inl((SISIOADDRESS)(p))
+#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset_io(MemoryAddress, value, MemorySize)
+#endif
+
+/**********************************************************************/
+/*  XFree86/X.org                                                    */
+/**********************************************************************/
+
+#ifdef LINUX_XF86
+#define SIS300
+#define SIS315H
+
+#define OutPortByte(p,v) outSISREG((IOADDRESS)(p),(CARD8)(v))
+#define OutPortWord(p,v) outSISREGW((IOADDRESS)(p),(CARD16)(v))
+#define OutPortLong(p,v) outSISREGL((IOADDRESS)(p),(CARD32)(v))
+#define InPortByte(p)    inSISREG((IOADDRESS)(p))
+#define InPortWord(p)    inSISREGW((IOADDRESS)(p))
+#define InPortLong(p)    inSISREGL((IOADDRESS)(p))
+#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize)
+#endif
+
+#endif  /* _OSDEF_H_ */
diff --git a/drivers/video/sis/sis.h b/drivers/video/sis/sis.h
new file mode 100644
index 0000000..d0103c1
--- /dev/null
+++ b/drivers/video/sis/sis.h
@@ -0,0 +1,573 @@
+/*
+ * SiS 300/630/730/540/315/550/[M]650/651/[M]661[FM]X/740/[M]741[GX]/330/[M]760[GX]
+ * frame buffer driver for Linux kernels >=2.4.14 and >=2.6.3
+ *
+ * Copyright (C) 2001-2004 Thomas Winischhofer, Vienna, Austria.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the named License,
+ * or any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef _SIS_H
+#define _SIS_H
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#include "osdef.h"
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#include <video/sisfb.h>
+#else
+#include <linux/sisfb.h>
+#endif
+
+#include "vgatypes.h"
+#include "vstruct.h"
+
+#define VER_MAJOR                 1
+#define VER_MINOR                 7
+#define VER_LEVEL                 17
+
+#undef SIS_CONFIG_COMPAT
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#include <linux/spinlock.h>
+#ifdef CONFIG_COMPAT
+#include <linux/ioctl32.h>
+#define SIS_CONFIG_COMPAT
+#endif
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19)
+#ifdef __x86_64__
+/* Shouldn't we check for CONFIG_IA32_EMULATION here? */
+#include <asm/ioctl32.h>
+#define SIS_CONFIG_COMPAT
+#endif
+#endif
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
+#define SIS_IOTYPE1 void __iomem
+#define SIS_IOTYPE2 __iomem
+#define SISINITSTATIC static
+#else
+#define SIS_IOTYPE1 unsigned char
+#define SIS_IOTYPE2
+#define SISINITSTATIC
+#endif
+
+#undef SISFBDEBUG
+
+#ifdef SISFBDEBUG
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#define TWDEBUG(x) printk(KERN_INFO x "\n");
+#else
+#define DPRINTK(fmt, args...)
+#define TWDEBUG(x)
+#endif
+
+#define SISFAIL(x) do { printk(x "\n"); return -EINVAL; } while(0)
+
+/* To be included in pci_ids.h */
+#ifndef PCI_DEVICE_ID_SI_650_VGA
+#define PCI_DEVICE_ID_SI_650_VGA  0x6325
+#endif
+#ifndef PCI_DEVICE_ID_SI_650
+#define PCI_DEVICE_ID_SI_650      0x0650
+#endif
+#ifndef PCI_DEVICE_ID_SI_651
+#define PCI_DEVICE_ID_SI_651      0x0651
+#endif
+#ifndef PCI_DEVICE_ID_SI_740
+#define PCI_DEVICE_ID_SI_740      0x0740
+#endif
+#ifndef PCI_DEVICE_ID_SI_330
+#define PCI_DEVICE_ID_SI_330      0x0330
+#endif
+#ifndef PCI_DEVICE_ID_SI_660_VGA
+#define PCI_DEVICE_ID_SI_660_VGA  0x6330
+#endif
+#ifndef PCI_DEVICE_ID_SI_661
+#define PCI_DEVICE_ID_SI_661      0x0661
+#endif
+#ifndef PCI_DEVICE_ID_SI_741
+#define PCI_DEVICE_ID_SI_741      0x0741
+#endif
+#ifndef PCI_DEVICE_ID_SI_660
+#define PCI_DEVICE_ID_SI_660      0x0660
+#endif
+#ifndef PCI_DEVICE_ID_SI_760
+#define PCI_DEVICE_ID_SI_760      0x0760
+#endif
+
+/* To be included in fb.h */
+#ifndef FB_ACCEL_SIS_GLAMOUR_2
+#define FB_ACCEL_SIS_GLAMOUR_2	  40	/* SiS 315, 65x, 740, 661, 741  */
+#endif
+#ifndef FB_ACCEL_SIS_XABRE
+#define FB_ACCEL_SIS_XABRE        41	/* SiS 330 ("Xabre"), 760 	*/
+#endif
+
+#define MAX_ROM_SCAN              0x10000
+
+/* ivideo->caps */
+#define HW_CURSOR_CAP             0x80
+#define TURBO_QUEUE_CAP           0x40
+#define AGP_CMD_QUEUE_CAP         0x20
+#define VM_CMD_QUEUE_CAP          0x10
+#define MMIO_CMD_QUEUE_CAP        0x08
+
+/* For 300 series */
+#define TURBO_QUEUE_AREA_SIZE     0x80000 /* 512K */
+#define HW_CURSOR_AREA_SIZE_300   0x1000  /* 4K */
+
+/* For 315/Xabre series */
+#define COMMAND_QUEUE_AREA_SIZE   0x80000 /* 512K */
+#define COMMAND_QUEUE_THRESHOLD   0x1F
+#define HW_CURSOR_AREA_SIZE_315   0x4000  /* 16K */
+
+#define SIS_OH_ALLOC_SIZE         4000
+#define SENTINEL                  0x7fffffff
+
+#define SEQ_ADR                   0x14
+#define SEQ_DATA                  0x15
+#define DAC_ADR                   0x18
+#define DAC_DATA                  0x19
+#define CRTC_ADR                  0x24
+#define CRTC_DATA                 0x25
+#define DAC2_ADR                  (0x16-0x30)
+#define DAC2_DATA                 (0x17-0x30)
+#define VB_PART1_ADR              (0x04-0x30)
+#define VB_PART1_DATA             (0x05-0x30)
+#define VB_PART2_ADR              (0x10-0x30)
+#define VB_PART2_DATA             (0x11-0x30)
+#define VB_PART3_ADR              (0x12-0x30)
+#define VB_PART3_DATA             (0x13-0x30)
+#define VB_PART4_ADR              (0x14-0x30)
+#define VB_PART4_DATA             (0x15-0x30)
+
+#define SISSR			  ivideo->SiS_Pr.SiS_P3c4
+#define SISCR                     ivideo->SiS_Pr.SiS_P3d4
+#define SISDACA                   ivideo->SiS_Pr.SiS_P3c8
+#define SISDACD                   ivideo->SiS_Pr.SiS_P3c9
+#define SISPART1                  ivideo->SiS_Pr.SiS_Part1Port
+#define SISPART2                  ivideo->SiS_Pr.SiS_Part2Port
+#define SISPART3                  ivideo->SiS_Pr.SiS_Part3Port
+#define SISPART4                  ivideo->SiS_Pr.SiS_Part4Port
+#define SISPART5                  ivideo->SiS_Pr.SiS_Part5Port
+#define SISDAC2A                  SISPART5
+#define SISDAC2D                  (SISPART5 + 1)
+#define SISMISCR                  (ivideo->SiS_Pr.RelIO + 0x1c)
+#define SISMISCW                  ivideo->SiS_Pr.SiS_P3c2
+#define SISINPSTAT		  (ivideo->SiS_Pr.RelIO + 0x2a)
+#define SISPEL			  ivideo->SiS_Pr.SiS_P3c6
+
+#define IND_SIS_PASSWORD          0x05  /* SRs */
+#define IND_SIS_COLOR_MODE        0x06
+#define IND_SIS_RAMDAC_CONTROL    0x07
+#define IND_SIS_DRAM_SIZE         0x14
+#define IND_SIS_MODULE_ENABLE     0x1E
+#define IND_SIS_PCI_ADDRESS_SET   0x20
+#define IND_SIS_TURBOQUEUE_ADR    0x26
+#define IND_SIS_TURBOQUEUE_SET    0x27
+#define IND_SIS_POWER_ON_TRAP     0x38
+#define IND_SIS_POWER_ON_TRAP2    0x39
+#define IND_SIS_CMDQUEUE_SET      0x26
+#define IND_SIS_CMDQUEUE_THRESHOLD  0x27
+
+#define IND_SIS_AGP_IO_PAD        0x48
+
+#define SIS_CRT2_WENABLE_300 	  0x24  /* Part1 */
+#define SIS_CRT2_WENABLE_315 	  0x2F
+
+#define SIS_PASSWORD              0x86  /* SR05 */
+
+#define SIS_INTERLACED_MODE       0x20  /* SR06 */
+#define SIS_8BPP_COLOR_MODE       0x0
+#define SIS_15BPP_COLOR_MODE      0x1
+#define SIS_16BPP_COLOR_MODE      0x2
+#define SIS_32BPP_COLOR_MODE      0x4
+
+#define SIS_ENABLE_2D             0x40  /* SR1E */
+
+#define SIS_MEM_MAP_IO_ENABLE     0x01  /* SR20 */
+#define SIS_PCI_ADDR_ENABLE       0x80
+
+#define SIS_AGP_CMDQUEUE_ENABLE   0x80  /* 315/330 series SR26 */
+#define SIS_VRAM_CMDQUEUE_ENABLE  0x40
+#define SIS_MMIO_CMD_ENABLE       0x20
+#define SIS_CMD_QUEUE_SIZE_512k   0x00
+#define SIS_CMD_QUEUE_SIZE_1M     0x04
+#define SIS_CMD_QUEUE_SIZE_2M     0x08
+#define SIS_CMD_QUEUE_SIZE_4M     0x0C
+#define SIS_CMD_QUEUE_RESET       0x01
+#define SIS_CMD_AUTO_CORR	  0x02
+
+#define SIS_SIMULTANEOUS_VIEW_ENABLE  0x01  /* CR30 */
+#define SIS_MODE_SELECT_CRT2      0x02
+#define SIS_VB_OUTPUT_COMPOSITE   0x04
+#define SIS_VB_OUTPUT_SVIDEO      0x08
+#define SIS_VB_OUTPUT_SCART       0x10
+#define SIS_VB_OUTPUT_LCD         0x20
+#define SIS_VB_OUTPUT_CRT2        0x40
+#define SIS_VB_OUTPUT_HIVISION    0x80
+
+#define SIS_VB_OUTPUT_DISABLE     0x20  /* CR31 */
+#define SIS_DRIVER_MODE           0x40
+
+#define SIS_VB_COMPOSITE          0x01  /* CR32 */
+#define SIS_VB_SVIDEO             0x02
+#define SIS_VB_SCART              0x04
+#define SIS_VB_LCD                0x08
+#define SIS_VB_CRT2               0x10
+#define SIS_CRT1                  0x20
+#define SIS_VB_HIVISION           0x40
+#define SIS_VB_YPBPR              0x80
+#define SIS_VB_TV                 (SIS_VB_COMPOSITE | SIS_VB_SVIDEO | \
+                                   SIS_VB_SCART | SIS_VB_HIVISION | SIS_VB_YPBPR)
+
+#define SIS_EXTERNAL_CHIP_MASK    	   0x0E  /* CR37 (< SiS 660) */
+#define SIS_EXTERNAL_CHIP_SIS301           0x01  /* in CR37 << 1 ! */
+#define SIS_EXTERNAL_CHIP_LVDS             0x02
+#define SIS_EXTERNAL_CHIP_TRUMPION         0x03
+#define SIS_EXTERNAL_CHIP_LVDS_CHRONTEL    0x04
+#define SIS_EXTERNAL_CHIP_CHRONTEL         0x05
+#define SIS310_EXTERNAL_CHIP_LVDS          0x02
+#define SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL 0x03
+
+#define SIS_AGP_2X                0x20  /* CR48 */
+
+#define HW_DEVICE_EXTENSION	  SIS_HW_INFO
+#define PHW_DEVICE_EXTENSION      PSIS_HW_INFO
+
+/* I/O port access macros */
+#define inSISREG(base)          inb(base)
+
+#define outSISREG(base,val)     outb(val,base)
+
+#define orSISREG(base,val)      			\
+		    do { 				\
+                      u8 __Temp = inSISREG(base); 	\
+                      outSISREG(base, __Temp | (val)); 	\
+                    } while (0)
+
+#define andSISREG(base,val)     			\
+		    do { 				\
+                      u8 __Temp = inSISREG(base); 	\
+                      outSISREG(base, __Temp & (val)); 	\
+                    } while (0)
+
+#define inSISIDXREG(base,idx,var)   		\
+		    do { 			\
+                      outSISREG(base, idx); 	\
+		      var = inSISREG((base)+1);	\
+                    } while (0)
+
+#define outSISIDXREG(base,idx,val)  		\
+		    do { 			\
+                      outSISREG(base, idx); 	\
+		      outSISREG((base)+1, val); \
+                    } while (0)
+
+#define orSISIDXREG(base,idx,val)   				\
+		    do { 					\
+                      u8 __Temp; 				\
+                      outSISREG(base, idx);   			\
+                      __Temp = inSISREG((base)+1) | (val); 	\
+		      outSISREG((base)+1, __Temp);		\
+                    } while (0)
+
+#define andSISIDXREG(base,idx,and)  				\
+		    do { 					\
+                      u8 __Temp; 				\
+                      outSISREG(base, idx);   			\
+                      __Temp = inSISREG((base)+1) & (and); 	\
+		      outSISREG((base)+1, __Temp);		\
+                    } while (0)
+
+#define setSISIDXREG(base,idx,and,or)   		   		\
+		    do { 				   		\
+                      u8 __Temp; 		   			\
+                      outSISREG(base, idx);   		   		\
+                      __Temp = (inSISREG((base)+1) & (and)) | (or); 	\
+		      outSISREG((base)+1, __Temp);			\
+                    } while (0)
+
+/* MMIO access macros */
+#define MMIO_IN8(base, offset)  readb((base+offset))
+#define MMIO_IN16(base, offset) readw((base+offset))
+#define MMIO_IN32(base, offset) readl((base+offset))
+
+#define MMIO_OUT8(base, offset, val)  writeb(((u8)(val)), (base+offset))
+#define MMIO_OUT16(base, offset, val) writew(((u16)(val)), (base+offset))
+#define MMIO_OUT32(base, offset, val) writel(((u32)(val)), (base+offset))
+
+/* Queue control MMIO registers */
+#define Q_BASE_ADDR		0x85C0  /* Base address of software queue */
+#define Q_WRITE_PTR		0x85C4  /* Current write pointer */
+#define Q_READ_PTR		0x85C8  /* Current read pointer */
+#define Q_STATUS		0x85CC  /* queue status */
+
+#define MMIO_QUEUE_PHYBASE      Q_BASE_ADDR
+#define MMIO_QUEUE_WRITEPORT    Q_WRITE_PTR
+#define MMIO_QUEUE_READPORT     Q_READ_PTR
+
+#ifndef FB_BLANK_UNBLANK
+#define FB_BLANK_UNBLANK 	0
+#endif
+#ifndef FB_BLANK_NORMAL
+#define FB_BLANK_NORMAL  	1
+#endif
+#ifndef FB_BLANK_VSYNC_SUSPEND
+#define FB_BLANK_VSYNC_SUSPEND 	2
+#endif
+#ifndef FB_BLANK_HSYNC_SUSPEND
+#define FB_BLANK_HSYNC_SUSPEND 	3
+#endif
+#ifndef FB_BLANK_POWERDOWN
+#define FB_BLANK_POWERDOWN 	4
+#endif
+
+enum _SIS_LCD_TYPE {
+    LCD_INVALID = 0,
+    LCD_800x600,
+    LCD_1024x768,
+    LCD_1280x1024,
+    LCD_1280x960,
+    LCD_640x480,
+    LCD_1600x1200,
+    LCD_1920x1440,
+    LCD_2048x1536,
+    LCD_320x480,       /* FSTN */
+    LCD_1400x1050,
+    LCD_1152x864,
+    LCD_1152x768,
+    LCD_1280x768,
+    LCD_1024x600,
+    LCD_640x480_2,     /* DSTN */
+    LCD_640x480_3,     /* DSTN */
+    LCD_848x480,
+    LCD_1280x800,
+    LCD_1680x1050,
+    LCD_1280x720,
+    LCD_CUSTOM,
+    LCD_UNKNOWN
+};
+
+enum _SIS_CMDTYPE {
+    MMIO_CMD = 0,
+    AGP_CMD_QUEUE,
+    VM_CMD_QUEUE,
+};
+typedef unsigned int SIS_CMDTYPE;
+
+/* Our "par" */
+struct sis_video_info {
+	int		cardnumber;
+	struct fb_info  *memyselfandi;
+
+	SIS_HW_INFO 	sishw_ext;
+	SiS_Private  	SiS_Pr;
+
+	sisfb_info 	sisfbinfo;	/* For ioctl SISFB_GET_INFO */
+
+	struct fb_var_screeninfo default_var;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	struct fb_fix_screeninfo sisfb_fix;
+	u32 		pseudo_palette[17];
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	struct display 		 sis_disp;
+	struct display_switch 	 sisfb_sw;
+	struct {
+		u16 red, green, blue, pad;
+	} 		sis_palette[256];
+	union {
+#ifdef FBCON_HAS_CFB16
+		u16 cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+		u32 cfb32[16];
+#endif
+	} 		sis_fbcon_cmap;
+#endif
+
+        struct sisfb_monitor {
+		u16 hmin;
+		u16 hmax;
+		u16 vmin;
+		u16 vmax;
+		u32 dclockmax;
+		u8  feature;
+		BOOLEAN datavalid;
+	} 		sisfb_thismonitor;
+
+	int           	chip_id;
+	char		myid[40];
+
+	struct pci_dev  *nbridge;
+
+	int		mni;	/* Mode number index */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	int  		currcon;
+#endif
+
+	unsigned long	video_size;
+	unsigned long 	video_base;
+	unsigned long	mmio_size;
+	unsigned long 	mmio_base;
+	unsigned long 	vga_base;
+
+	SIS_IOTYPE1  	*video_vbase;
+	SIS_IOTYPE1 	*mmio_vbase;
+
+	unsigned char   *bios_abase;
+
+	int 		mtrr;
+
+	u32		sisfb_mem;
+
+	u32 		sisfb_parm_mem;
+	int 	   	sisfb_accel;
+	int 		sisfb_ypan;
+	int 		sisfb_max;
+	int 		sisfb_userom;
+	int 		sisfb_useoem;
+	int		sisfb_mode_idx;
+	int		sisfb_parm_rate;
+	int		sisfb_crt1off;
+	int		sisfb_forcecrt1;
+	int		sisfb_crt2type;
+	int		sisfb_crt2flags;
+	int 		sisfb_dstn;
+	int 		sisfb_fstn;
+	int		sisfb_tvplug;
+	int		sisfb_tvstd;
+	int		sisfb_filter;
+	int		sisfb_nocrt2rate;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	int		sisfb_inverse;
+#endif
+
+	u32 		heapstart;        	/* offset  */
+	SIS_IOTYPE1  	*sisfb_heap_start; 	/* address */
+	SIS_IOTYPE1  	*sisfb_heap_end;   	/* address */
+	u32 	      	sisfb_heap_size;
+	int		havenoheap;
+#if 0
+	SIS_HEAP       	sisfb_heap;
+#endif
+
+
+	int    		video_bpp;
+	int    		video_cmap_len;
+	int    		video_width;
+	int    		video_height;
+	unsigned int 	refresh_rate;
+
+	unsigned int 	chip;
+	u8   		revision_id;
+
+	int    		video_linelength;	/* real pitch */
+	int		scrnpitchCRT1;		/* pitch regarding interlace */
+
+        u16 		DstColor;		/* For 2d acceleration */
+	u32  		SiS310_AccelDepth;
+	u32  		CommandReg;
+	int		cmdqueuelength;
+
+	spinlock_t     	lockaccel;		/* Do not use outside of kernel! */
+
+        unsigned int   	pcibus;
+	unsigned int   	pcislot;
+	unsigned int   	pcifunc;
+
+	int 	       	accel;
+
+	u16 		subsysvendor;
+	u16 		subsysdevice;
+
+	u32  		vbflags;		/* Replacing deprecated stuff from above */
+	u32  		currentvbflags;
+
+	int		lcdxres, lcdyres;
+	int		lcddefmodeidx, tvdefmodeidx, defmodeidx;
+	u32  		CRT2LCDType;        	/* defined in "SIS_LCD_TYPE" */
+
+	int    		current_bpp;
+	int    		current_width;
+	int    		current_height;
+	int    		current_htotal;
+	int    		current_vtotal;
+	int		current_linelength;
+	__u32  		current_pixclock;
+	int    		current_refresh_rate;
+
+	u8  		mode_no;
+	u8  		rate_idx;
+	int    		modechanged;
+	unsigned char 	modeprechange;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	u8 		sisfb_lastrates[128];
+#endif
+
+	int  		newrom;
+	int  		registered;
+	int		warncount;
+
+	int 		sisvga_engine;
+	int 		hwcursor_size;
+	int 		CRT2_write_enable;
+	u8            	caps;
+
+	u8 		detectedpdc;
+	u8 		detectedpdca;
+	u8 		detectedlcda;
+
+	SIS_IOTYPE1 	*hwcursor_vbase;
+
+	int 		chronteltype;
+	int    		tvxpos, tvypos;
+	u8              p2_1f,p2_20,p2_2b,p2_42,p2_43,p2_01,p2_02;
+	int		tvx, tvy;
+
+	u8 		sisfblocked;
+
+	struct sis_video_info *next;
+};
+
+typedef struct _SIS_OH {
+	struct _SIS_OH *poh_next;
+	struct _SIS_OH *poh_prev;
+	u32            offset;
+	u32            size;
+} SIS_OH;
+
+typedef struct _SIS_OHALLOC {
+	struct _SIS_OHALLOC *poha_next;
+	SIS_OH aoh[1];
+} SIS_OHALLOC;
+
+typedef struct _SIS_HEAP {
+	SIS_OH      oh_free;
+	SIS_OH      oh_used;
+	SIS_OH      *poh_freelist;
+	SIS_OHALLOC *poha_chain;
+	u32         max_freesize;
+	struct sis_video_info *vinfo;
+} SIS_HEAP;
+
+#endif
diff --git a/drivers/video/sis/sis_accel.c b/drivers/video/sis/sis_accel.c
new file mode 100644
index 0000000..30e90a5
--- /dev/null
+++ b/drivers/video/sis/sis_accel.c
@@ -0,0 +1,678 @@
+/*
+ * SiS 300/630/730/540/315/550/65x/74x/330/760 frame buffer driver
+ * for Linux kernels 2.4.x and 2.6.x
+ *
+ * 2D acceleration part
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the named License,
+ * or any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Based on the XFree86/X.org driver which is
+ *     Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
+ *
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>
+ *			(see http://www.winischhofer.net/
+ *			for more information and updates)
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/selection.h>
+#include <linux/ioport.h>
+#include <linux/capability.h>
+#include <linux/fs.h>
+#include <linux/types.h>
+
+#include <asm/io.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+#endif
+
+#include "sis.h"
+#include "sis_accel.h"
+
+static const u8 sisALUConv[] =
+{
+    0x00,       /* dest = 0;            0,      GXclear,        0 */
+    0x88,       /* dest &= src;         DSa,    GXand,          0x1 */
+    0x44,       /* dest = src & ~dest;  SDna,   GXandReverse,   0x2 */
+    0xCC,       /* dest = src;          S,      GXcopy,         0x3 */
+    0x22,       /* dest &= ~src;        DSna,   GXandInverted,  0x4 */
+    0xAA,       /* dest = dest;         D,      GXnoop,         0x5 */
+    0x66,       /* dest = ^src;         DSx,    GXxor,          0x6 */
+    0xEE,       /* dest |= src;         DSo,    GXor,           0x7 */
+    0x11,       /* dest = ~src & ~dest; DSon,   GXnor,          0x8 */
+    0x99,       /* dest ^= ~src ;       DSxn,   GXequiv,        0x9 */
+    0x55,       /* dest = ~dest;        Dn,     GXInvert,       0xA */
+    0xDD,       /* dest = src|~dest ;   SDno,   GXorReverse,    0xB */
+    0x33,       /* dest = ~src;         Sn,     GXcopyInverted, 0xC */
+    0xBB,       /* dest |= ~src;        DSno,   GXorInverted,   0xD */
+    0x77,       /* dest = ~src|~dest;   DSan,   GXnand,         0xE */
+    0xFF,       /* dest = 0xFF;         1,      GXset,          0xF */
+};
+/* same ROP but with Pattern as Source */
+static const u8 sisPatALUConv[] =
+{
+    0x00,       /* dest = 0;            0,      GXclear,        0 */
+    0xA0,       /* dest &= src;         DPa,    GXand,          0x1 */
+    0x50,       /* dest = src & ~dest;  PDna,   GXandReverse,   0x2 */
+    0xF0,       /* dest = src;          P,      GXcopy,         0x3 */
+    0x0A,       /* dest &= ~src;        DPna,   GXandInverted,  0x4 */
+    0xAA,       /* dest = dest;         D,      GXnoop,         0x5 */
+    0x5A,       /* dest = ^src;         DPx,    GXxor,          0x6 */
+    0xFA,       /* dest |= src;         DPo,    GXor,           0x7 */
+    0x05,       /* dest = ~src & ~dest; DPon,   GXnor,          0x8 */
+    0xA5,       /* dest ^= ~src ;       DPxn,   GXequiv,        0x9 */
+    0x55,       /* dest = ~dest;        Dn,     GXInvert,       0xA */
+    0xF5,       /* dest = src|~dest ;   PDno,   GXorReverse,    0xB */
+    0x0F,       /* dest = ~src;         Pn,     GXcopyInverted, 0xC */
+    0xAF,       /* dest |= ~src;        DPno,   GXorInverted,   0xD */
+    0x5F,       /* dest = ~src|~dest;   DPan,   GXnand,         0xE */
+    0xFF,       /* dest = 0xFF;         1,      GXset,          0xF */
+};
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+static const int myrops[] = {
+   	3, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
+};
+#endif
+
+/* 300 series ----------------------------------------------------- */
+#ifdef CONFIG_FB_SIS_300
+static void
+SiS300Sync(struct sis_video_info *ivideo)
+{
+	SiS300Idle
+}
+
+static void
+SiS300SetupForScreenToScreenCopy(struct sis_video_info *ivideo, int xdir, int ydir,
+                                 int rop, int trans_color)
+{
+	SiS300SetupDSTColorDepth(ivideo->DstColor);
+	SiS300SetupSRCPitch(ivideo->video_linelength)
+	SiS300SetupDSTRect(ivideo->video_linelength, 0xffff)
+
+	if(trans_color != -1) {
+		SiS300SetupROP(0x0A)
+		SiS300SetupSRCTrans(trans_color)
+		SiS300SetupCMDFlag(TRANSPARENT_BITBLT)
+	} else {
+	        SiS300SetupROP(sisALUConv[rop])
+	}
+	if(xdir > 0) {
+		SiS300SetupCMDFlag(X_INC)
+	}
+	if(ydir > 0) {
+		SiS300SetupCMDFlag(Y_INC)
+	}
+}
+
+static void
+SiS300SubsequentScreenToScreenCopy(struct sis_video_info *ivideo, int src_x,
+				   int src_y, int dst_x, int dst_y, int width, int height)
+{
+	u32 srcbase = 0, dstbase = 0;
+
+	if(src_y >= 2048) {
+		srcbase = ivideo->video_linelength * src_y;
+		src_y = 0;
+	}
+	if(dst_y >= 2048) {
+		dstbase = ivideo->video_linelength * dst_y;
+		dst_y = 0;
+	}
+
+	SiS300SetupSRCBase(srcbase);
+	SiS300SetupDSTBase(dstbase);
+
+	if(!(ivideo->CommandReg & X_INC))  {
+		src_x += width-1;
+		dst_x += width-1;
+	}
+	if(!(ivideo->CommandReg & Y_INC))  {
+		src_y += height-1;
+		dst_y += height-1;
+	}
+	SiS300SetupRect(width, height)
+	SiS300SetupSRCXY(src_x, src_y)
+	SiS300SetupDSTXY(dst_x, dst_y)
+	SiS300DoCMD
+}
+
+static void
+SiS300SetupForSolidFill(struct sis_video_info *ivideo, u32 color, int rop)
+{
+	SiS300SetupPATFG(color)
+	SiS300SetupDSTRect(ivideo->video_linelength, 0xffff)
+	SiS300SetupDSTColorDepth(ivideo->DstColor);
+	SiS300SetupROP(sisPatALUConv[rop])
+	SiS300SetupCMDFlag(PATFG)
+}
+
+static void
+SiS300SubsequentSolidFillRect(struct sis_video_info *ivideo, int x, int y, int w, int h)
+{
+	u32 dstbase = 0;
+
+	if(y >= 2048) {
+		dstbase = ivideo->video_linelength * y;
+		y = 0;
+	}
+	SiS300SetupDSTBase(dstbase)
+	SiS300SetupDSTXY(x,y)
+	SiS300SetupRect(w,h)
+	SiS300SetupCMDFlag(X_INC | Y_INC | BITBLT)
+	SiS300DoCMD
+}
+#endif
+
+/* 315/330 series ------------------------------------------------- */
+
+#ifdef CONFIG_FB_SIS_315
+static void
+SiS310Sync(struct sis_video_info *ivideo)
+{
+	SiS310Idle
+}
+
+static void
+SiS310SetupForScreenToScreenCopy(struct sis_video_info *ivideo, int rop, int trans_color)
+{
+	SiS310SetupDSTColorDepth(ivideo->DstColor);
+	SiS310SetupSRCPitch(ivideo->video_linelength)
+	SiS310SetupDSTRect(ivideo->video_linelength, 0xffff)
+	if(trans_color != -1) {
+		SiS310SetupROP(0x0A)
+		SiS310SetupSRCTrans(trans_color)
+		SiS310SetupCMDFlag(TRANSPARENT_BITBLT)
+	} else {
+	        SiS310SetupROP(sisALUConv[rop])
+		/* Set command - not needed, both 0 */
+		/* SiSSetupCMDFlag(BITBLT | SRCVIDEO) */
+	}
+	SiS310SetupCMDFlag(ivideo->SiS310_AccelDepth)
+	/* The 315 series is smart enough to know the direction */
+}
+
+static void
+SiS310SubsequentScreenToScreenCopy(struct sis_video_info *ivideo, int src_x, int src_y,
+			 int dst_x, int dst_y, int width, int height)
+{
+	u32 srcbase = 0, dstbase = 0;
+	int mymin = min(src_y, dst_y);
+	int mymax = max(src_y, dst_y);
+	
+	/* Although the chip knows the direction to use
+	 * if the source and destination areas overlap, 
+	 * that logic fails if we fiddle with the bitmap
+	 * addresses. Therefore, we check if the source
+	 * and destination blitting areas overlap and 
+	 * adapt the bitmap addresses synchronously 
+	 * if the coordinates exceed the valid range.
+	 * The the areas do not overlap, we do our 
+	 * normal check.
+	 */
+	if((mymax - mymin) < height) { 
+	   if((src_y >= 2048) || (dst_y >= 2048)) {	      
+	      srcbase = ivideo->video_linelength * mymin;
+	      dstbase = ivideo->video_linelength * mymin;
+	      src_y -= mymin;
+	      dst_y -= mymin;
+	   }
+	} else {
+	   if(src_y >= 2048) {
+	      srcbase = ivideo->video_linelength * src_y;
+	      src_y = 0;
+	   }
+	   if(dst_y >= 2048) {
+	      dstbase = ivideo->video_linelength * dst_y;
+	      dst_y = 0;
+	   }
+	}
+
+	SiS310SetupSRCBase(srcbase);
+	SiS310SetupDSTBase(dstbase);
+	SiS310SetupRect(width, height)
+	SiS310SetupSRCXY(src_x, src_y)
+	SiS310SetupDSTXY(dst_x, dst_y)
+	SiS310DoCMD
+}
+
+static void
+SiS310SetupForSolidFill(struct sis_video_info *ivideo, u32 color, int rop)
+{
+	SiS310SetupPATFG(color)
+	SiS310SetupDSTRect(ivideo->video_linelength, 0xffff)
+	SiS310SetupDSTColorDepth(ivideo->DstColor);
+	SiS310SetupROP(sisPatALUConv[rop])
+	SiS310SetupCMDFlag(PATFG | ivideo->SiS310_AccelDepth)
+}
+
+static void
+SiS310SubsequentSolidFillRect(struct sis_video_info *ivideo, int x, int y, int w, int h)
+{
+	u32 dstbase = 0;
+
+	if(y >= 2048) {
+		dstbase = ivideo->video_linelength * y;
+		y = 0;
+	}
+	SiS310SetupDSTBase(dstbase)
+	SiS310SetupDSTXY(x,y)
+	SiS310SetupRect(w,h)
+	SiS310SetupCMDFlag(BITBLT)
+	SiS310DoCMD
+}
+#endif
+
+/* --------------------------------------------------------------------- */
+
+/* The exported routines */
+
+int sisfb_initaccel(struct sis_video_info *ivideo)
+{
+#ifdef SISFB_USE_SPINLOCKS
+    spin_lock_init(&ivideo->lockaccel);
+#endif
+    return(0);
+}
+
+void sisfb_syncaccel(struct sis_video_info *ivideo)
+{
+    if(ivideo->sisvga_engine == SIS_300_VGA) {
+#ifdef CONFIG_FB_SIS_300
+    	SiS300Sync(ivideo);
+#endif
+    } else {
+#ifdef CONFIG_FB_SIS_315
+    	SiS310Sync(ivideo);
+#endif
+    }
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)  /* --------------- 2.5 --------------- */
+
+int fbcon_sis_sync(struct fb_info *info)
+{
+   struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+   CRITFLAGS
+
+   if(!ivideo->accel)
+   	return 0;
+
+   if(ivideo->sisvga_engine == SIS_300_VGA) {
+#ifdef CONFIG_FB_SIS_300
+      SiS300Sync(ivideo);
+#endif
+   } else {
+#ifdef CONFIG_FB_SIS_315
+      SiS310Sync(ivideo);
+#endif
+   }
+   CRITEND
+   return 0;
+}
+
+void fbcon_sis_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+   struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+   u32 col = 0;
+   u32 vxres = info->var.xres_virtual;
+   u32 vyres = info->var.yres_virtual;
+   int width, height;
+   CRITFLAGS
+
+   if(info->state != FBINFO_STATE_RUNNING) {
+	return;
+   }
+
+   if(!ivideo->accel) {
+	cfb_fillrect(info, rect);
+	return;
+   }
+   
+   if(!rect->width || !rect->height || rect->dx >= vxres || rect->dy >= vyres) {
+	return;
+   }
+
+   /* Clipping */
+   width = ((rect->dx + rect->width) > vxres) ? (vxres - rect->dx) : rect->width;
+   height = ((rect->dy + rect->height) > vyres) ? (vyres - rect->dy) : rect->height;
+
+   switch(info->var.bits_per_pixel) {
+	case 8:  col = rect->color;
+		 break;
+	case 16:
+	case 32: col = ((u32 *)(info->pseudo_palette))[rect->color];
+		 break;
+   }
+
+   if(ivideo->sisvga_engine == SIS_300_VGA) {
+#ifdef CONFIG_FB_SIS_300
+      CRITBEGIN
+      SiS300SetupForSolidFill(ivideo, col, myrops[rect->rop]);
+      SiS300SubsequentSolidFillRect(ivideo, rect->dx, rect->dy, width, height);
+      CRITEND
+      SiS300Sync(ivideo);
+#endif
+   } else {
+#ifdef CONFIG_FB_SIS_315
+      CRITBEGIN
+      SiS310SetupForSolidFill(ivideo, col, myrops[rect->rop]);
+      SiS310SubsequentSolidFillRect(ivideo, rect->dx, rect->dy, width, height);
+      CRITEND
+      SiS310Sync(ivideo);
+#endif
+   }
+
+}
+
+void fbcon_sis_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+   struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+   u32 vxres = info->var.xres_virtual;
+   u32 vyres = info->var.yres_virtual;
+   int width = area->width;
+   int height = area->height;
+   CRITFLAGS
+
+   if(info->state != FBINFO_STATE_RUNNING) {
+	return;
+   }
+
+   if(!ivideo->accel) {
+   	cfb_copyarea(info, area);
+	return;
+   }
+
+   if(!width || !height ||
+      area->sx >= vxres || area->sy >= vyres ||
+      area->dx >= vxres || area->dy >= vyres) {
+   	return;
+   }
+
+   /* Clipping */
+   if((area->sx + width) > vxres) width = vxres - area->sx;
+   if((area->dx + width) > vxres) width = vxres - area->dx;
+   if((area->sy + height) > vyres) height = vyres - area->sy;
+   if((area->dy + height) > vyres) height = vyres - area->dy;
+
+   if(ivideo->sisvga_engine == SIS_300_VGA) {
+#ifdef CONFIG_FB_SIS_300
+      int xdir, ydir;
+
+      if(area->sx < area->dx) xdir = 0;
+      else                    xdir = 1;
+      if(area->sy < area->dy) ydir = 0;
+      else                    ydir = 1;
+
+      CRITBEGIN
+      SiS300SetupForScreenToScreenCopy(ivideo, xdir, ydir, 3, -1);
+      SiS300SubsequentScreenToScreenCopy(ivideo, area->sx, area->sy, area->dx, area->dy,
+      					 width, height);
+      CRITEND
+      SiS300Sync(ivideo);
+#endif
+   } else {
+#ifdef CONFIG_FB_SIS_315
+      CRITBEGIN
+      SiS310SetupForScreenToScreenCopy(ivideo, 3, -1);
+      SiS310SubsequentScreenToScreenCopy(ivideo, area->sx, area->sy, area->dx, area->dy,
+      					 width, height);
+      CRITEND
+      SiS310Sync(ivideo);
+#endif
+   }
+}
+
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)  /* -------------- 2.4 --------------- */
+
+void fbcon_sis_bmove(struct display *p, int srcy, int srcx,
+			    int dsty, int dstx, int height, int width)
+{
+	struct sis_video_info *ivideo = (struct sis_video_info *)p->fb_info->par;
+
+	CRITFLAGS
+
+	if(!ivideo->accel) {
+	    switch(ivideo->video_bpp) {
+	    case 8:
+#ifdef FBCON_HAS_CFB8
+	       fbcon_cfb8_bmove(p, srcy, srcx, dsty, dstx, height, width);
+#endif
+	       break;
+	    case 16:
+#ifdef FBCON_HAS_CFB16
+	       fbcon_cfb16_bmove(p, srcy, srcx, dsty, dstx, height, width);
+#endif
+	       break;
+	    case 32:
+#ifdef FBCON_HAS_CFB32
+	       fbcon_cfb32_bmove(p, srcy, srcx, dsty, dstx, height, width);
+#endif
+	       break;
+            }
+	    return;
+	}
+
+	srcx *= fontwidth(p);
+	srcy *= fontheight(p);
+	dstx *= fontwidth(p);
+	dsty *= fontheight(p);
+	width *= fontwidth(p);
+	height *= fontheight(p);
+
+	if(ivideo->sisvga_engine == SIS_300_VGA) {
+#ifdef CONFIG_FB_SIS_300
+	   int xdir, ydir;
+
+	   if(srcx < dstx) xdir = 0;
+	   else            xdir = 1;
+	   if(srcy < dsty) ydir = 0;
+	   else            ydir = 1;
+
+	   CRITBEGIN
+	   SiS300SetupForScreenToScreenCopy(ivideo, xdir, ydir, 3, -1);
+	   SiS300SubsequentScreenToScreenCopy(ivideo, srcx, srcy, dstx, dsty, width, height);
+	   CRITEND
+	   SiS300Sync(ivideo);
+#endif
+	} else {
+#ifdef CONFIG_FB_SIS_315
+	   CRITBEGIN
+	   SiS310SetupForScreenToScreenCopy(ivideo, 3, -1);
+	   SiS310SubsequentScreenToScreenCopy(ivideo, srcx, srcy, dstx, dsty, width, height);
+	   CRITEND
+	   SiS310Sync(ivideo);
+#endif
+	}
+}
+
+static void fbcon_sis_clear(struct vc_data *conp, struct display *p,
+			int srcy, int srcx, int height, int width, int color)
+{
+        struct sis_video_info *ivideo = (struct sis_video_info *)p->fb_info->par;
+	CRITFLAGS
+
+	srcx *= fontwidth(p);
+	srcy *= fontheight(p);
+	width *= fontwidth(p);
+	height *= fontheight(p);
+
+	if(ivideo->sisvga_engine == SIS_300_VGA) {
+#ifdef CONFIG_FB_SIS_300
+	   CRITBEGIN
+	   SiS300SetupForSolidFill(ivideo, color, 3);
+	   SiS300SubsequentSolidFillRect(ivideo, srcx, srcy, width, height);
+	   CRITEND
+	   SiS300Sync(ivideo);
+#endif
+	} else {
+#ifdef CONFIG_FB_SIS_315
+	   CRITBEGIN
+	   SiS310SetupForSolidFill(ivideo, color, 3);
+	   SiS310SubsequentSolidFillRect(ivideo, srcx, srcy, width, height);
+	   CRITEND
+	   SiS310Sync(ivideo);
+#endif
+	}
+}
+
+void fbcon_sis_clear8(struct vc_data *conp, struct display *p,
+			int srcy, int srcx, int height, int width)
+{
+	struct sis_video_info *ivideo = (struct sis_video_info *)p->fb_info->par;
+	u32 bgx;
+
+	if(!ivideo->accel) {
+#ifdef FBCON_HAS_CFB8
+	    fbcon_cfb8_clear(conp, p, srcy, srcx, height, width);
+#endif
+	    return;
+	}
+
+	bgx = attr_bgcol_ec(p, conp);
+	fbcon_sis_clear(conp, p, srcy, srcx, height, width, bgx);
+}
+
+void fbcon_sis_clear16(struct vc_data *conp, struct display *p,
+			int srcy, int srcx, int height, int width)
+{
+        struct sis_video_info *ivideo = (struct sis_video_info *)p->fb_info->par;
+	u32 bgx;
+
+	if(!ivideo->accel) {
+#ifdef FBCON_HAS_CFB16
+	    fbcon_cfb16_clear(conp, p, srcy, srcx, height, width);
+#endif
+	    return;
+	}
+
+	bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+	fbcon_sis_clear(conp, p, srcy, srcx, height, width, bgx);
+}
+
+void fbcon_sis_clear32(struct vc_data *conp, struct display *p,
+			int srcy, int srcx, int height, int width)
+{
+	struct sis_video_info *ivideo = (struct sis_video_info *)p->fb_info->par;
+	u32 bgx;
+
+	if(!ivideo->accel) {
+#ifdef FBCON_HAS_CFB32
+	    fbcon_cfb32_clear(conp, p, srcy, srcx, height, width);
+#endif
+	    return;
+	}
+
+	bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+	fbcon_sis_clear(conp, p, srcy, srcx, height, width, bgx);
+}
+
+void fbcon_sis_revc(struct display *p, int srcx, int srcy)
+{
+	struct sis_video_info *ivideo = (struct sis_video_info *)p->fb_info->par;
+	CRITFLAGS
+
+	if(!ivideo->accel) {
+	    switch(ivideo->video_bpp) {
+	    case 16:
+#ifdef FBCON_HAS_CFB16
+	       fbcon_cfb16_revc(p, srcx, srcy);
+#endif
+	       break;
+	    case 32:
+#ifdef FBCON_HAS_CFB32
+	       fbcon_cfb32_revc(p, srcx, srcy);
+#endif
+	       break;
+            }
+	    return;
+	}
+
+	srcx *= fontwidth(p);
+	srcy *= fontheight(p);
+
+	if(ivideo->sisvga_engine == SIS_300_VGA) {
+#ifdef CONFIG_FB_SIS_300
+	   CRITBEGIN
+	   SiS300SetupForSolidFill(ivideo, 0, 0x0a);
+	   SiS300SubsequentSolidFillRect(ivideo, srcx, srcy, fontwidth(p), fontheight(p));
+	   CRITEND
+	   SiS300Sync(ivideo);
+#endif
+	} else {
+#ifdef CONFIG_FB_SIS_315
+	   CRITBEGIN
+	   SiS310SetupForSolidFill(ivideo, 0, 0x0a);
+	   SiS310SubsequentSolidFillRect(ivideo, srcx, srcy, fontwidth(p), fontheight(p));
+	   CRITEND
+	   SiS310Sync(ivideo);
+#endif
+	}
+}
+
+#ifdef FBCON_HAS_CFB8
+struct display_switch fbcon_sis8 = {
+	.setup		= fbcon_cfb8_setup,
+	.bmove		= fbcon_sis_bmove,
+	.clear		= fbcon_sis_clear8,
+	.putc		= fbcon_cfb8_putc,
+	.putcs		= fbcon_cfb8_putcs,
+	.revc		= fbcon_cfb8_revc,
+	.clear_margins	= fbcon_cfb8_clear_margins,
+	.fontwidthmask	= FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+#ifdef FBCON_HAS_CFB16
+struct display_switch fbcon_sis16 = {
+	.setup		= fbcon_cfb16_setup,
+	.bmove		= fbcon_sis_bmove,
+	.clear		= fbcon_sis_clear16,
+	.putc		= fbcon_cfb16_putc,
+	.putcs		= fbcon_cfb16_putcs,
+	.revc		= fbcon_sis_revc,
+	.clear_margins	= fbcon_cfb16_clear_margins,
+	.fontwidthmask	= FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+#ifdef FBCON_HAS_CFB32
+struct display_switch fbcon_sis32 = {
+	.setup		= fbcon_cfb32_setup,
+	.bmove		= fbcon_sis_bmove,
+	.clear		= fbcon_sis_clear32,
+	.putc		= fbcon_cfb32_putc,
+	.putcs		= fbcon_cfb32_putcs,
+	.revc		= fbcon_sis_revc,
+	.clear_margins	= fbcon_cfb32_clear_margins,
+	.fontwidthmask	= FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+
+#endif /* KERNEL VERSION */
+
+
diff --git a/drivers/video/sis/sis_accel.h b/drivers/video/sis/sis_accel.h
new file mode 100644
index 0000000..bb28f33
--- /dev/null
+++ b/drivers/video/sis/sis_accel.h
@@ -0,0 +1,409 @@
+/*
+ * SiS 300/630/730/540/315/550/650/740 frame buffer driver
+ * for Linux kernels 2.4.x and 2.5.x
+ *
+ * 2D acceleration part
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the named License,
+ * or any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Based on the X driver's sis300_accel.h which is
+ *     Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
+ * and sis310_accel.h which is
+ *     Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
+ *
+ * Author:   Thomas Winischhofer <thomas@winischhofer.net>:
+ *			(see http://www.winischhofer.net/
+ *			for more information and updates)
+ */
+
+#ifndef _SISFB_ACCEL_H
+#define _SISFB_ACCEL_H
+
+/* Guard accelerator accesses with spin_lock_irqsave? Works well without. */
+#undef SISFB_USE_SPINLOCKS
+
+#ifdef SISFB_USE_SPINLOCKS
+#include <linux/spinlock.h>
+#define CRITBEGIN  spin_lock_irqsave(&ivideo->lockaccel, critflags);
+#define CRITEND	   spin_unlock_irqrestore(&ivideo->lockaccel, critflags);
+#define CRITFLAGS  unsigned long critflags;
+#else
+#define CRITBEGIN
+#define CRITEND
+#define CRITFLAGS
+#endif
+
+/* Definitions for the SIS engine communication. */
+
+#define PATREGSIZE      384  /* Pattern register size. 384 bytes @ 0x8300 */
+#define BR(x)   (0x8200 | (x) << 2)
+#define PBR(x)  (0x8300 | (x) << 2)
+
+/* SiS300 engine commands */
+#define BITBLT                  0x00000000  /* Blit */
+#define COLOREXP                0x00000001  /* Color expand */
+#define ENCOLOREXP              0x00000002  /* Enhanced color expand */
+#define MULTIPLE_SCANLINE       0x00000003  /* ? */
+#define LINE                    0x00000004  /* Draw line */
+#define TRAPAZOID_FILL          0x00000005  /* Fill trapezoid */
+#define TRANSPARENT_BITBLT      0x00000006  /* Transparent Blit */
+
+/* Additional engine commands for 315 */
+#define ALPHA_BLEND		0x00000007  /* Alpha blend ? */
+#define A3D_FUNCTION		0x00000008  /* 3D command ? */
+#define	CLEAR_Z_BUFFER		0x00000009  /* ? */
+#define GRADIENT_FILL		0x0000000A  /* Gradient fill */
+
+/* source select */
+#define SRCVIDEO                0x00000000  /* source is video RAM */
+#define SRCSYSTEM               0x00000010  /* source is system memory */
+#define SRCCPUBLITBUF           SRCSYSTEM   /* source is CPU-driven BitBuffer (for color expand) */
+#define SRCAGP                  0x00000020  /* source is AGP memory (?) */
+
+/* Pattern flags */
+#define PATFG                   0x00000000  /* foreground color */
+#define PATPATREG               0x00000040  /* pattern in pattern buffer (0x8300) */
+#define PATMONO                 0x00000080  /* mono pattern */
+
+/* blitting direction (300 series only) */
+#define X_INC                   0x00010000
+#define X_DEC                   0x00000000
+#define Y_INC                   0x00020000
+#define Y_DEC                   0x00000000
+
+/* Clipping flags */
+#define NOCLIP                  0x00000000
+#define NOMERGECLIP             0x04000000
+#define CLIPENABLE              0x00040000
+#define CLIPWITHOUTMERGE        0x04040000
+
+/* Transparency */
+#define OPAQUE                  0x00000000
+#define TRANSPARENT             0x00100000
+
+/* ? */
+#define DSTAGP                  0x02000000
+#define DSTVIDEO                0x02000000
+
+/* Subfunctions for Color/Enhanced Color Expansion (315 only) */
+#define COLOR_TO_MONO		0x00100000
+#define AA_TEXT			0x00200000
+
+/* Some general registers for 315 series */
+#define SRC_ADDR		0x8200
+#define SRC_PITCH		0x8204
+#define AGP_BASE		0x8206 /* color-depth dependent value */
+#define SRC_Y			0x8208
+#define SRC_X			0x820A
+#define DST_Y			0x820C
+#define DST_X			0x820E
+#define DST_ADDR		0x8210
+#define DST_PITCH		0x8214
+#define DST_HEIGHT		0x8216
+#define RECT_WIDTH		0x8218
+#define RECT_HEIGHT		0x821A
+#define PAT_FGCOLOR		0x821C
+#define PAT_BGCOLOR		0x8220
+#define SRC_FGCOLOR		0x8224
+#define SRC_BGCOLOR		0x8228
+#define MONO_MASK		0x822C
+#define LEFT_CLIP		0x8234
+#define TOP_CLIP		0x8236
+#define RIGHT_CLIP		0x8238
+#define BOTTOM_CLIP		0x823A
+#define COMMAND_READY		0x823C
+#define FIRE_TRIGGER      	0x8240
+
+#define PATTERN_REG		0x8300  /* 384 bytes pattern buffer */
+
+/* Transparent bitblit registers */
+#define TRANS_DST_KEY_HIGH	PAT_FGCOLOR
+#define TRANS_DST_KEY_LOW	PAT_BGCOLOR
+#define TRANS_SRC_KEY_HIGH	SRC_FGCOLOR
+#define TRANS_SRC_KEY_LOW	SRC_BGCOLOR
+
+/* Store queue length in par */
+#define CmdQueLen ivideo->cmdqueuelength
+
+/* ------------- SiS 300 series -------------- */
+
+/* BR(16) (0x8240):
+
+   bit 31 2D engine: 1 is idle,
+   bit 30 3D engine: 1 is idle,
+   bit 29 Command queue: 1 is empty
+   bits 28:24: Current CPU driven BitBlt buffer stage bit[4:0]
+   bits 15:0:  Current command queue length
+
+*/
+
+#define SiS300Idle \
+  { \
+  	while((MMIO_IN16(ivideo->mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \
+  	while((MMIO_IN16(ivideo->mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \
+  	while((MMIO_IN16(ivideo->mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \
+  	CmdQueLen = MMIO_IN16(ivideo->mmio_vbase, 0x8240); \
+  }
+/* (do three times, because 2D engine seems quite unsure about whether or not it's idle) */
+
+#define SiS300SetupSRCBase(base) \
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(0), base);\
+	CmdQueLen--;
+
+#define SiS300SetupSRCPitch(pitch) \
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT16(ivideo->mmio_vbase, BR(1), pitch);\
+	CmdQueLen--;
+
+#define SiS300SetupSRCXY(x,y) \
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(2), (x)<<16 | (y) );\
+	CmdQueLen--;
+
+#define SiS300SetupDSTBase(base) \
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(4), base);\
+	CmdQueLen--;
+
+#define SiS300SetupDSTXY(x,y) \
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(3), (x)<<16 | (y) );\
+	CmdQueLen--;
+
+#define SiS300SetupDSTRect(x,y) \
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(5), (y)<<16 | (x) );\
+	CmdQueLen--;
+
+#define SiS300SetupDSTColorDepth(bpp) \
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT16(ivideo->mmio_vbase, BR(1)+2, bpp);\
+	CmdQueLen--;
+
+#define SiS300SetupRect(w,h) \
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(6), (h)<<16 | (w) );\
+	CmdQueLen--;
+
+#define SiS300SetupPATFG(color) \
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(7), color);\
+	CmdQueLen--;
+
+#define SiS300SetupPATBG(color) \
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(8), color);\
+	CmdQueLen--;
+
+#define SiS300SetupSRCFG(color) \
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(9), color);\
+	CmdQueLen--;
+
+#define SiS300SetupSRCBG(color) \
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(10), color);\
+	CmdQueLen--;
+
+/* 0x8224 src colorkey high */
+/* 0x8228 src colorkey low */
+/* 0x821c dest colorkey high */
+/* 0x8220 dest colorkey low */
+#define SiS300SetupSRCTrans(color) \
+	if(CmdQueLen <= 1) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, 0x8224, color);\
+	MMIO_OUT32(ivideo->mmio_vbase, 0x8228, color);\
+	CmdQueLen -= 2;
+
+#define SiS300SetupDSTTrans(color) \
+	if(CmdQueLen <= 1) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, 0x821C, color); \
+	MMIO_OUT32(ivideo->mmio_vbase, 0x8220, color); \
+	CmdQueLen -= 2;
+
+#define SiS300SetupMONOPAT(p0,p1) \
+	if(CmdQueLen <= 1) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(11), p0);\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(12), p1);\
+	CmdQueLen -= 2;
+
+#define SiS300SetupClipLT(left,top) \
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(13), ((left) & 0xFFFF) | (top)<<16 );\
+	CmdQueLen--;
+
+#define SiS300SetupClipRB(right,bottom) \
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(14), ((right) & 0xFFFF) | (bottom)<<16 );\
+	CmdQueLen--;
+
+/* General */
+#define SiS300SetupROP(rop) \
+	ivideo->CommandReg = (rop) << 8;
+
+#define SiS300SetupCMDFlag(flags) \
+	ivideo->CommandReg |= (flags);
+
+#define SiS300DoCMD \
+	if(CmdQueLen <= 1) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(15), ivideo->CommandReg); \
+	MMIO_OUT32(ivideo->mmio_vbase, BR(16), 0);\
+	CmdQueLen -= 2;
+
+/* -------------- SiS 315/330 series --------------- */
+
+/* Q_STATUS:
+   bit 31 = 1: All engines idle and all queues empty
+   bit 30 = 1: Hardware Queue (=HW CQ, 2D queue, 3D queue) empty
+   bit 29 = 1: 2D engine is idle
+   bit 28 = 1: 3D engine is idle
+   bit 27 = 1: HW command queue empty
+   bit 26 = 1: 2D queue empty
+   bit 25 = 1: 3D queue empty
+   bit 24 = 1: SW command queue empty
+   bits 23:16: 2D counter 3
+   bits 15:8:  2D counter 2
+   bits 7:0:   2D counter 1
+*/
+
+#define SiS310Idle \
+  { \
+  	while( (MMIO_IN16(ivideo->mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \
+  	while( (MMIO_IN16(ivideo->mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \
+  	CmdQueLen = 0; \
+  }
+
+#define SiS310SetupSRCBase(base) \
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, SRC_ADDR, base);\
+	CmdQueLen--;
+
+#define SiS310SetupSRCPitch(pitch) \
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT16(ivideo->mmio_vbase, SRC_PITCH, pitch);\
+	CmdQueLen--;
+
+#define SiS310SetupSRCXY(x,y) \
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, SRC_Y, (x)<<16 | (y) );\
+	CmdQueLen--;
+
+#define SiS310SetupDSTBase(base) \
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, DST_ADDR, base);\
+	CmdQueLen--;
+
+#define SiS310SetupDSTXY(x,y) \
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, DST_Y, (x)<<16 | (y) );\
+	CmdQueLen--;
+
+#define SiS310SetupDSTRect(x,y) \
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, DST_PITCH, (y)<<16 | (x) );\
+	CmdQueLen--;
+
+#define SiS310SetupDSTColorDepth(bpp) \
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT16(ivideo->mmio_vbase, AGP_BASE, bpp);\
+	CmdQueLen--;
+
+#define SiS310SetupRect(w,h) \
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, RECT_WIDTH, (h)<<16 | (w) );\
+	CmdQueLen--;
+
+#define SiS310SetupPATFG(color) \
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, PAT_FGCOLOR, color);\
+	CmdQueLen--;
+
+#define SiS310SetupPATBG(color) \
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, PAT_BGCOLOR, color);\
+	CmdQueLen--;
+
+#define SiS310SetupSRCFG(color) \
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, SRC_FGCOLOR, color);\
+	CmdQueLen--;
+
+#define SiS310SetupSRCBG(color) \
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, SRC_BGCOLOR, color);\
+	CmdQueLen--;
+
+#define SiS310SetupSRCTrans(color) \
+	if(CmdQueLen <= 1) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, TRANS_SRC_KEY_HIGH, color);\
+	MMIO_OUT32(ivideo->mmio_vbase, TRANS_SRC_KEY_LOW, color);\
+	CmdQueLen -= 2;
+
+#define SiS310SetupDSTTrans(color) \
+	if(CmdQueLen <= 1) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, TRANS_DST_KEY_HIGH, color); \
+	MMIO_OUT32(ivideo->mmio_vbase, TRANS_DST_KEY_LOW, color); \
+	CmdQueLen -= 2;
+
+#define SiS310SetupMONOPAT(p0,p1) \
+	if(CmdQueLen <= 1) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, MONO_MASK, p0);\
+	MMIO_OUT32(ivideo->mmio_vbase, MONO_MASK+4, p1);\
+	CmdQueLen -= 2;
+
+#define SiS310SetupClipLT(left,top) \
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, LEFT_CLIP, ((left) & 0xFFFF) | (top)<<16 );\
+	CmdQueLen--;
+
+#define SiS310SetupClipRB(right,bottom) \
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, RIGHT_CLIP, ((right) & 0xFFFF) | (bottom)<<16 );\
+	CmdQueLen--;
+
+#define SiS310SetupROP(rop) \
+	ivideo->CommandReg = (rop) << 8;
+
+#define SiS310SetupCMDFlag(flags) \
+	ivideo->CommandReg |= (flags);
+
+#define SiS310DoCMD \
+	if(CmdQueLen <= 1) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, COMMAND_READY, ivideo->CommandReg); \
+	MMIO_OUT32(ivideo->mmio_vbase, FIRE_TRIGGER, 0); \
+	CmdQueLen -= 2;
+
+
+int  sisfb_initaccel(struct sis_video_info *ivideo);
+void sisfb_syncaccel(struct sis_video_info *ivideo);
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+void fbcon_sis_bmove(struct display *p, int srcy, int srcx, int dsty,
+			int dstx, int height, int width);
+void fbcon_sis_revc(struct display *p, int srcy, int srcx);
+void fbcon_sis_clear8(struct vc_data *conp, struct display *p, int srcy,
+			int srcx, int height, int width);
+void fbcon_sis_clear16(struct vc_data *conp, struct display *p, int srcy,
+			int srcx, int height, int width);
+void fbcon_sis_clear32(struct vc_data *conp, struct display *p, int srcy,
+			int srcx, int height, int width);
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+void fbcon_sis_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
+void fbcon_sis_copyarea(struct fb_info *info, const struct fb_copyarea *area);
+#endif
+
+#endif
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
new file mode 100644
index 0000000..b773c98
--- /dev/null
+++ b/drivers/video/sis/sis_main.c
@@ -0,0 +1,6027 @@
+/*
+ * SiS 300/305/540/630(S)/730(S)
+ * SiS 315(H/PRO)/55x/(M)65x/(M)661(F/M)X/740/741(GX)/330/(M)760
+ * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
+ *
+ * Copyright (C) 2001-2004 Thomas Winischhofer, Vienna, Austria.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the named License,
+ * or any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Author:   	Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ * Author of (practically wiped) code base:
+ *		SiS (www.sis.com)
+ *	 	Copyright (C) 1999 Silicon Integrated Systems, Inc.
+ *
+ * See http://www.winischhofer.net/ for more information and updates
+ *
+ * Originally based on the VBE 2.0 compliant graphic boards framebuffer driver,
+ * which is (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#include <linux/moduleparam.h>
+#endif
+#include <linux/kernel.h>
+#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/selection.h>
+#include <linux/smp_lock.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/vt_kern.h>
+#include <linux/capability.h>
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+#endif
+
+#include "sis.h"
+#include "sis_main.h"
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3)
+#error "This version of sisfb requires at least 2.6.3"
+#endif
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#ifdef FBCON_HAS_CFB8
+extern struct display_switch fbcon_sis8;
+#endif
+#ifdef FBCON_HAS_CFB16
+extern struct display_switch fbcon_sis16;
+#endif
+#ifdef FBCON_HAS_CFB32
+extern struct display_switch fbcon_sis32;
+#endif
+#endif
+
+/* ------------------ Internal helper routines ----------------- */
+
+static void __init
+sisfb_setdefaultparms(void)
+{
+	sisfb_off 		= 0;
+	sisfb_parm_mem 		= 0;
+	sisfb_accel 		= -1;
+	sisfb_ypan      	= -1;
+	sisfb_max 		= -1;
+	sisfb_userom    	= -1;
+        sisfb_useoem    	= -1;
+#ifdef MODULE
+	/* Module: "None" for 2.4, default mode for 2.5+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	sisfb_mode_idx 		= -1;
+#else
+	sisfb_mode_idx  	= MODE_INDEX_NONE;
+#endif
+#else
+	/* Static: Default mode */
+	sisfb_mode_idx  	= -1;
+#endif
+	sisfb_parm_rate 	= -1;
+	sisfb_crt1off 		= 0;
+	sisfb_forcecrt1 	= -1;
+	sisfb_crt2type  	= -1;
+	sisfb_crt2flags 	= 0;
+	sisfb_pdc 		= 0xff;
+	sisfb_pdca 		= 0xff;
+	sisfb_scalelcd  	= -1;
+	sisfb_specialtiming 	= CUT_NONE;
+	sisfb_lvdshl 		= -1;
+	sisfb_dstn     		= 0;
+	sisfb_fstn 		= 0;
+	sisfb_tvplug    	= -1;
+	sisfb_tvstd     	= -1;
+	sisfb_tvxposoffset 	= 0;
+	sisfb_tvyposoffset 	= 0;
+	sisfb_filter 		= -1;
+	sisfb_nocrt2rate 	= 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	sisfb_inverse   	= 0;
+	sisfb_fontname[0] 	= 0;
+#endif
+#if !defined(__i386__) && !defined(__x86_64__)
+	sisfb_resetcard 	= 0;
+	sisfb_videoram  	= 0;
+#endif
+}
+
+static void __devinit
+sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
+{
+	int i = 0, j = 0;
+
+	/* BEWARE: We don't know the hardware specs yet and there is no ivideo */
+
+	if(vesamode == 0) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+		sisfb_mode_idx = MODE_INDEX_NONE;
+#else
+		if(!quiet) {
+		   printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
+		}
+		sisfb_mode_idx = DEFAULT_MODE;
+#endif
+		return;
+	}
+
+	vesamode &= 0x1dff;  /* Clean VESA mode number from other flags */
+
+	while(sisbios_mode[i++].mode_no[0] != 0) {
+		if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
+		    (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
+		    if(sisfb_fstn) {
+		       if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
+		          sisbios_mode[i-1].mode_no[1] == 0x56 ||
+		          sisbios_mode[i-1].mode_no[1] == 0x53) continue;
+	            } else {
+		       if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
+		          sisbios_mode[i-1].mode_no[1] == 0x5b) continue;
+		    }
+		    sisfb_mode_idx = i - 1;
+		    j = 1;
+		    break;
+		}
+	}
+	if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
+}
+
+static void
+sisfb_search_mode(char *name, BOOLEAN quiet)
+{
+	int i = 0;
+	unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
+	char strbuf[16], strbuf1[20];
+	char *nameptr = name;
+
+	/* BEWARE: We don't know the hardware specs yet and there is no ivideo */
+
+	if(name == NULL) {
+	   if(!quiet) {
+	      printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
+	   }
+	   sisfb_mode_idx = DEFAULT_MODE;
+	   return;
+	}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+        if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
+	   if(!quiet) {
+	      printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
+	   }
+	   sisfb_mode_idx = DEFAULT_MODE;
+	   return;
+	}
+#endif
+	if(strlen(name) <= 19) {
+	   strcpy(strbuf1, name);
+	   for(i=0; i<strlen(strbuf1); i++) {
+	      if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
+	   }
+
+	   /* This does some fuzzy mode naming detection */
+	   if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
+	      if((rate <= 32) || (depth > 32)) {
+	         j = rate; rate = depth; depth = j;
+	      }
+	      sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
+	      nameptr = strbuf;
+	      sisfb_parm_rate = rate;
+	   } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
+	      sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
+	      nameptr = strbuf;
+	   } else {
+	      xres = 0;
+	      if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
+	         sprintf(strbuf, "%ux%ux8", xres, yres);
+	         nameptr = strbuf;
+	      } else {
+	         sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
+	         return;
+	      }
+	   }
+	}
+
+	i = 0; j = 0;
+	while(sisbios_mode[i].mode_no[0] != 0) {
+		if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
+		   	if(sisfb_fstn) {
+		      		if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
+		         	   sisbios_mode[i-1].mode_no[1] == 0x56 ||
+		         	   sisbios_mode[i-1].mode_no[1] == 0x53) continue;
+	           	} else {
+		      		if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
+		         	   sisbios_mode[i-1].mode_no[1] == 0x5b) continue;
+		   	}
+		   	sisfb_mode_idx = i - 1;
+		   	j = 1;
+		   	break;
+		}
+	}
+	if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
+}
+
+#ifndef MODULE
+static void __devinit
+sisfb_get_vga_mode_from_kernel(void)
+{
+#if (defined(__i386__) || defined(__x86_64__)) && defined(CONFIG_VIDEO_SELECT)
+   	char mymode[32];
+	int  mydepth = screen_info.lfb_depth;
+
+	if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
+
+	if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
+	    (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
+	    (mydepth >= 8) && (mydepth <= 32) ) {
+
+	    if(mydepth == 24) mydepth = 32;
+
+	    sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
+	    				screen_info.lfb_height,
+					mydepth);
+
+	    printk(KERN_DEBUG "sisfb: Using vga mode %s pre-set by kernel as default\n", mymode);
+
+	    sisfb_search_mode(mymode, TRUE);
+	}
+#endif
+	return;
+}
+#endif
+
+static void __init
+sisfb_search_crt2type(const char *name)
+{
+	int i = 0;
+
+	/* BEWARE: We don't know the hardware specs yet and there is no ivideo */
+
+	if(name == NULL) return;
+
+	while(sis_crt2type[i].type_no != -1) {
+	   	if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
+	      		sisfb_crt2type = sis_crt2type[i].type_no;
+	      		sisfb_tvplug = sis_crt2type[i].tvplug_no;
+	      		sisfb_crt2flags = sis_crt2type[i].flags;
+	      		break;
+	   	}
+	   	i++;
+	}
+
+	sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
+	sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
+
+	if(sisfb_crt2type < 0) {
+		printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
+	}
+}
+
+static void __init
+sisfb_search_tvstd(const char *name)
+{
+	int i = 0;
+
+	/* BEWARE: We don't know the hardware specs yet and there is no ivideo */
+
+	if(name == NULL) return;
+
+	while(sis_tvtype[i].type_no != -1) {
+	   	if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
+	      		sisfb_tvstd = sis_tvtype[i].type_no;
+	      		break;
+	   	}
+	   	i++;
+	}
+}
+
+static void __init
+sisfb_search_specialtiming(const char *name)
+{
+	int i = 0;
+	BOOLEAN found = FALSE;
+
+	/* BEWARE: We don't know the hardware specs yet and there is no ivideo */
+
+	if(name == NULL) return;
+
+	if(!strnicmp(name, "none", 4)) {
+	        sisfb_specialtiming = CUT_FORCENONE;
+		printk(KERN_DEBUG "sisfb: Special timing disabled\n");
+	} else {
+	   while(mycustomttable[i].chipID != 0) {
+	      if(!strnicmp(name,mycustomttable[i].optionName, strlen(mycustomttable[i].optionName))) {
+		 sisfb_specialtiming = mycustomttable[i].SpecialID;
+		 found = TRUE;
+		 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
+		 	mycustomttable[i].vendorName, mycustomttable[i].cardName,
+		 	mycustomttable[i].optionName);
+		 break;
+	      }
+	      i++;
+	   }
+	   if(!found) {
+	      printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
+	      printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
+	      i = 0;
+	      while(mycustomttable[i].chipID != 0) {
+		 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
+		     mycustomttable[i].optionName,
+		     mycustomttable[i].vendorName,
+		     mycustomttable[i].cardName);
+		 i++;
+	      }
+           }
+ 	}
+}
+
+static BOOLEAN __devinit
+sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
+{
+	int i, j, xres, yres, refresh, index;
+	u32 emodes;
+
+	if(buffer[0] != 0x00 || buffer[1] != 0xff ||
+	   buffer[2] != 0xff || buffer[3] != 0xff ||
+	   buffer[4] != 0xff || buffer[5] != 0xff ||
+	   buffer[6] != 0xff || buffer[7] != 0x00) {
+	   printk(KERN_DEBUG "sisfb: Bad EDID header\n");
+	   return FALSE;
+	}
+
+	if(buffer[0x12] != 0x01) {
+	   printk(KERN_INFO "sisfb: EDID version %d not supported\n",
+	   	buffer[0x12]);
+	   return FALSE;
+	}
+
+	monitor->feature = buffer[0x18];
+
+	if(!buffer[0x14] & 0x80) {
+	   if(!(buffer[0x14] & 0x08)) {
+	      printk(KERN_INFO "sisfb: WARNING: Monitor does not support separate syncs\n");
+	   }
+	}
+
+	if(buffer[0x13] >= 0x01) {
+	   /* EDID V1 rev 1 and 2: Search for monitor descriptor
+	    * to extract ranges
+	    */
+	    j = 0x36;
+	    for(i=0; i<4; i++) {
+	       if(buffer[j]     == 0x00 && buffer[j + 1] == 0x00 &&
+	          buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
+		  buffer[j + 4] == 0x00) {
+		  monitor->hmin = buffer[j + 7];
+		  monitor->hmax = buffer[j + 8];
+		  monitor->vmin = buffer[j + 5];
+		  monitor->vmax = buffer[j + 6];
+		  monitor->dclockmax = buffer[j + 9] * 10 * 1000;
+		  monitor->datavalid = TRUE;
+		  break;
+	       }
+	       j += 18;
+	    }
+	}
+
+	if(!monitor->datavalid) {
+	   /* Otherwise: Get a range from the list of supported
+	    * Estabished Timings. This is not entirely accurate,
+	    * because fixed frequency monitors are not supported
+	    * that way.
+	    */
+	   monitor->hmin = 65535; monitor->hmax = 0;
+	   monitor->vmin = 65535; monitor->vmax = 0;
+	   monitor->dclockmax = 0;
+	   emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
+	   for(i = 0; i < 13; i++) {
+	      if(emodes & sisfb_ddcsmodes[i].mask) {
+	         if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
+		 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
+		 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
+		 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
+		 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
+	      }
+	   }
+	   index = 0x26;
+	   for(i = 0; i < 8; i++) {
+	      xres = (buffer[index] + 31) * 8;
+	      switch(buffer[index + 1] & 0xc0) {
+	         case 0xc0: yres = (xres * 9) / 16; break;
+	         case 0x80: yres = (xres * 4) /  5; break;
+	         case 0x40: yres = (xres * 3) /  4; break;
+	         default:   yres = xres;	    break;
+	      }
+	      refresh = (buffer[index + 1] & 0x3f) + 60;
+	      if((xres >= 640) && (yres >= 480)) {
+                 for(j = 0; j < 8; j++) {
+	            if((xres == sisfb_ddcfmodes[j].x) &&
+	               (yres == sisfb_ddcfmodes[j].y) &&
+		       (refresh == sisfb_ddcfmodes[j].v)) {
+		      if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
+		      if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
+		      if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
+		      if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
+		      if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
+	            }
+	         }
+	      }
+	      index += 2;
+           }
+	   if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
+	      monitor->datavalid = TRUE;
+	   }
+	}
+
+ 	return(monitor->datavalid);
+}
+
+static void __devinit
+sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
+{
+	USHORT  temp, i, realcrtno = crtno;
+   	u8      buffer[256];
+
+	monitor->datavalid = FALSE;
+
+	if(crtno) {
+       	   if(ivideo->vbflags & CRT2_LCD)      realcrtno = 1;
+      	   else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
+      	   else return;
+   	}
+
+	if((ivideo->sisfb_crt1off) && (!crtno)) return;
+
+    	temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
+				realcrtno, 0, &buffer[0]);
+   	if((!temp) || (temp == 0xffff)) {
+      	   printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
+	   return;
+   	} else {
+      	   printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
+      	   printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
+	   	crtno + 1,
+	   	(temp & 0x1a) ? "" : "[none of the supported]",
+	   	(temp & 0x02) ? "2 " : "",
+	   	(temp & 0x08) ? "D&P" : "",
+           	(temp & 0x10) ? "FPDI-2" : "");
+      	   if(temp & 0x02) {
+	      i = 3;  /* Number of retrys */
+	      do {
+	    	 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
+				     realcrtno, 1, &buffer[0]);
+	      } while((temp) && i--);
+              if(!temp) {
+	    	 if(sisfb_interpret_edid(monitor, &buffer[0])) {
+		    printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
+		    	monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
+			monitor->dclockmax / 1000);
+		 } else {
+	       	    printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
+	    	 }
+	      } else {
+            	 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
+	      }
+	   } else {
+	      printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
+	   }
+	}
+}
+
+static BOOLEAN
+sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
+		int mode_idx, int rate_idx, int rate)
+{
+	int htotal, vtotal;
+	unsigned int dclock, hsync;
+
+	if(!monitor->datavalid) return TRUE;
+
+	if(mode_idx < 0) return FALSE;
+
+	/* Skip for 320x200, 320x240, 640x400 */
+    	switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
+    	case 0x59:
+    	case 0x41:
+    	case 0x4f:
+    	case 0x50:
+    	case 0x56:
+    	case 0x53:
+    	case 0x2f:
+    	case 0x5d:
+    	case 0x5e:
+    		return TRUE;
+#ifdef CONFIG_FB_SIS_315
+	case 0x5a:
+	case 0x5b:
+		if(ivideo->sisvga_engine == SIS_315_VGA) return TRUE;
+#endif
+    	}
+
+	if(rate < (monitor->vmin - 1)) return FALSE;
+	if(rate > (monitor->vmax + 1)) return FALSE;
+
+	if(sisfb_gettotalfrommode(&ivideo->SiS_Pr, &ivideo->sishw_ext,
+				  sisbios_mode[mode_idx].mode_no[ivideo->mni],
+	                          &htotal, &vtotal, rate_idx)) {
+		dclock = (htotal * vtotal * rate) / 1000;
+		if(dclock > (monitor->dclockmax + 1000)) return FALSE;
+		hsync = dclock / htotal;
+		if(hsync < (monitor->hmin - 1)) return FALSE;
+		if(hsync > (monitor->hmax + 1)) return FALSE;
+        } else {
+	  	return FALSE;
+	}
+	return TRUE;
+}
+
+static int
+sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
+{
+   u16 xres=0, yres, myres;
+
+#ifdef CONFIG_FB_SIS_300
+   if(ivideo->sisvga_engine == SIS_300_VGA) {
+      if(!(sisbios_mode[myindex].chipset & MD_SIS300)) return(-1);
+   }
+#endif
+#ifdef CONFIG_FB_SIS_315
+   if(ivideo->sisvga_engine == SIS_315_VGA) {
+      if(!(sisbios_mode[myindex].chipset & MD_SIS315)) return(-1);
+   }
+#endif
+
+   myres = sisbios_mode[myindex].yres;
+
+   switch(vbflags & VB_DISPTYPE_DISP2) {
+
+     case CRT2_LCD:
+
+        xres = ivideo->lcdxres; yres = ivideo->lcdyres;
+
+	if(ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) {
+	   	if(sisbios_mode[myindex].xres > xres) return(-1);
+           	if(myres > yres) return(-1);
+	}
+
+	if(vbflags & (VB_LVDS | VB_30xBDH)) {
+	   if(sisbios_mode[myindex].xres == 320) {
+	      if((myres == 240) || (myres == 480)) {
+		 if(!ivideo->sisfb_fstn) {
+		    if(sisbios_mode[myindex].mode_no[1] == 0x5a ||
+		       sisbios_mode[myindex].mode_no[1] == 0x5b)
+		       return(-1);
+		 } else {
+		    if(sisbios_mode[myindex].mode_no[1] == 0x50 ||
+		       sisbios_mode[myindex].mode_no[1] == 0x56 ||
+		       sisbios_mode[myindex].mode_no[1] == 0x53)
+		       return(-1);
+		 }
+	      }
+	   }
+	}
+
+	if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
+			     sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
+			     ivideo->SiS_Pr.SiS_CustomT, xres, yres) < 0x14) {
+	   	return(-1);
+	}
+	break;
+
+     case CRT2_TV:
+	if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
+	                    sisbios_mode[myindex].yres, 0) < 0x14) {
+	   	return(-1);
+	}
+	break;
+
+     case CRT2_VGA:
+        if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
+	                      sisbios_mode[myindex].yres, 0) < 0x14) {
+	   	return(-1);
+	}
+	break;
+     }
+
+     return(myindex);
+}
+
+static u8
+sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
+{
+	u16 xres, yres;
+	int i = 0;
+
+	xres = sisbios_mode[mode_idx].xres;
+	yres = sisbios_mode[mode_idx].yres;
+
+	ivideo->rate_idx = 0;
+	while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
+		if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
+			if(sisfb_vrate[i].refresh == rate) {
+				ivideo->rate_idx = sisfb_vrate[i].idx;
+				break;
+			} else if(sisfb_vrate[i].refresh > rate) {
+				if((sisfb_vrate[i].refresh - rate) <= 3) {
+					DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
+						rate, sisfb_vrate[i].refresh);
+					ivideo->rate_idx = sisfb_vrate[i].idx;
+					ivideo->refresh_rate = sisfb_vrate[i].refresh;
+				} else if(((rate - sisfb_vrate[i-1].refresh) <= 2)
+						&& (sisfb_vrate[i].idx != 1)) {
+					DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
+						rate, sisfb_vrate[i-1].refresh);
+					ivideo->rate_idx = sisfb_vrate[i-1].idx;
+					ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
+				} 
+				break;
+			} else if((rate - sisfb_vrate[i].refresh) <= 2) {
+				DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
+						rate, sisfb_vrate[i].refresh);
+	           		ivideo->rate_idx = sisfb_vrate[i].idx;
+		   		break;
+	       		}
+		}
+		i++;
+	}
+	if(ivideo->rate_idx > 0) {
+		return ivideo->rate_idx;
+	} else {
+		printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
+				rate, xres, yres);
+		return 0;
+	}
+}
+
+static BOOLEAN
+sisfb_bridgeisslave(struct sis_video_info *ivideo)
+{
+   unsigned char P1_00;
+
+   if(!(ivideo->vbflags & VB_VIDEOBRIDGE)) return FALSE;
+
+   inSISIDXREG(SISPART1,0x00,P1_00);
+   if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
+       ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
+	   return TRUE;
+   } else {
+           return FALSE;
+   }
+}
+
+static BOOLEAN
+sisfballowretracecrt1(struct sis_video_info *ivideo)
+{
+   u8 temp;
+
+   inSISIDXREG(SISCR,0x17,temp);
+   if(!(temp & 0x80)) return FALSE;
+
+   inSISIDXREG(SISSR,0x1f,temp);
+   if(temp & 0xc0) return FALSE;
+
+   return TRUE;
+}
+
+static BOOLEAN
+sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
+{
+   if(!sisfballowretracecrt1(ivideo)) return FALSE;
+
+   if(inSISREG(SISINPSTAT) & 0x08) return TRUE;
+   else 			   return FALSE;
+}
+
+static void
+sisfbwaitretracecrt1(struct sis_video_info *ivideo)
+{
+   int watchdog;
+
+   if(!sisfballowretracecrt1(ivideo)) return;
+
+   watchdog = 65536;
+   while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
+   watchdog = 65536;
+   while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
+}
+
+static BOOLEAN
+sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
+{
+   unsigned char temp, reg;
+
+   switch(ivideo->sisvga_engine) {
+   case SIS_300_VGA: reg = 0x25; break;
+   case SIS_315_VGA: reg = 0x30; break;
+   default:          return FALSE;
+   }
+
+   inSISIDXREG(SISPART1, reg, temp);
+   if(temp & 0x02) return TRUE;
+   else 	   return FALSE;
+}
+
+static BOOLEAN
+sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
+{
+   if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
+      if(sisfb_bridgeisslave(ivideo)) {
+         return(sisfbcheckvretracecrt1(ivideo));
+      } else {
+         return(sisfbcheckvretracecrt2(ivideo));
+      }
+   } 
+   return(sisfbcheckvretracecrt1(ivideo));
+}
+
+static u32
+sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
+{
+   u8 idx, reg1, reg2, reg3, reg4;
+   u32 ret = 0;
+
+   (*vcount) = (*hcount) = 0;
+
+   if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
+      ret |= (FB_VBLANK_HAVE_VSYNC  |
+      	      FB_VBLANK_HAVE_HBLANK |
+              FB_VBLANK_HAVE_VBLANK |
+	      FB_VBLANK_HAVE_VCOUNT |
+	      FB_VBLANK_HAVE_HCOUNT);
+      switch(ivideo->sisvga_engine) {
+         case SIS_300_VGA: idx = 0x25; break;
+	 default:
+         case SIS_315_VGA: idx = 0x30; break;
+      }
+      inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */
+      inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */
+      inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */
+      inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */
+      if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
+      if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
+      if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
+      (*vcount) = reg3 | ((reg4 & 0x70) << 4);
+      (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
+   } else if(sisfballowretracecrt1(ivideo)) {
+      ret |= (FB_VBLANK_HAVE_VSYNC  |
+              FB_VBLANK_HAVE_VBLANK |
+	      FB_VBLANK_HAVE_VCOUNT |
+	      FB_VBLANK_HAVE_HCOUNT);
+      reg1 = inSISREG(SISINPSTAT);
+      if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
+      if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
+      inSISIDXREG(SISCR,0x20,reg1);
+      inSISIDXREG(SISCR,0x1b,reg1);
+      inSISIDXREG(SISCR,0x1c,reg2);
+      inSISIDXREG(SISCR,0x1d,reg3);
+      (*vcount) = reg2 | ((reg3 & 0x07) << 8);
+      (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
+   }
+   return ret;
+}
+
+static int
+sisfb_myblank(struct sis_video_info *ivideo, int blank)
+{
+   u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
+   BOOLEAN backlight = TRUE;
+
+   switch(blank) {
+   case FB_BLANK_UNBLANK:	/* on */
+      sr01  = 0x00;
+      sr11  = 0x00;
+      sr1f  = 0x00;
+      cr63  = 0x00;
+      p2_0  = 0x20;
+      p1_13 = 0x00;
+      backlight = TRUE;
+      break;
+   case FB_BLANK_NORMAL:	/* blank */
+      sr01  = 0x20;
+      sr11  = 0x00;
+      sr1f  = 0x00;
+      cr63  = 0x00;
+      p2_0  = 0x20;
+      p1_13 = 0x00;
+      backlight = TRUE;
+      break;
+   case FB_BLANK_VSYNC_SUSPEND:	/* no vsync */
+      sr01  = 0x20;
+      sr11  = 0x08;
+      sr1f  = 0x80;
+      cr63  = 0x40;
+      p2_0  = 0x40;
+      p1_13 = 0x80;
+      backlight = FALSE;
+      break;
+   case FB_BLANK_HSYNC_SUSPEND:	/* no hsync */
+      sr01  = 0x20;
+      sr11  = 0x08;
+      sr1f  = 0x40;
+      cr63  = 0x40;
+      p2_0  = 0x80;
+      p1_13 = 0x40;
+      backlight = FALSE;
+      break;
+   case FB_BLANK_POWERDOWN:	/* off */
+      sr01  = 0x20;
+      sr11  = 0x08;
+      sr1f  = 0xc0;
+      cr63  = 0x40;
+      p2_0  = 0xc0;
+      p1_13 = 0xc0;
+      backlight = FALSE;
+      break;
+   default:
+      return 1;
+   }
+
+   if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
+
+      if( (!ivideo->sisfb_thismonitor.datavalid) ||
+          ((ivideo->sisfb_thismonitor.datavalid) &&
+           (ivideo->sisfb_thismonitor.feature & 0xe0))) {
+
+	 if(ivideo->sisvga_engine == SIS_315_VGA) {
+	    setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
+	 }
+
+	 if(!(sisfb_bridgeisslave(ivideo))) {
+	    setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
+	    setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
+	 }
+      }
+
+   }
+
+   if(ivideo->currentvbflags & CRT2_LCD) {
+
+      if(ivideo->vbflags & (VB_301LV|VB_302LV|VB_302ELV)) {
+	 if(backlight) {
+	    SiS_SiS30xBLOn(&ivideo->SiS_Pr, &ivideo->sishw_ext);
+	 } else {
+	    SiS_SiS30xBLOff(&ivideo->SiS_Pr, &ivideo->sishw_ext);
+	 }
+      } else if(ivideo->sisvga_engine == SIS_315_VGA) {
+	 if(ivideo->vbflags & VB_CHRONTEL) {
+	    if(backlight) {
+	       SiS_Chrontel701xBLOn(&ivideo->SiS_Pr,&ivideo->sishw_ext);
+	    } else {
+	       SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
+	    }
+	 }
+      }
+
+      if(((ivideo->sisvga_engine == SIS_300_VGA) &&
+          (ivideo->vbflags & (VB_301|VB_30xBDH|VB_LVDS))) ||
+         ((ivideo->sisvga_engine == SIS_315_VGA) &&
+          ((ivideo->vbflags & (VB_LVDS | VB_CHRONTEL)) == VB_LVDS))) {
+          setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
+      }
+
+      if(ivideo->sisvga_engine == SIS_300_VGA) {
+         if((ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) &&
+            (!(ivideo->vbflags & VB_30xBDH))) {
+	    setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
+	 }
+      } else if(ivideo->sisvga_engine == SIS_315_VGA) {
+         if((ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) &&
+            (!(ivideo->vbflags & VB_30xBDH))) {
+	    setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
+	 }
+      }
+
+   } else if(ivideo->currentvbflags & CRT2_VGA) {
+
+      if(ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) {
+         setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
+      }
+
+   }
+
+   return(0);
+}
+
+/* ----------- FBDev related routines for all series ----------- */
+
+static int
+sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
+{
+	return (var->bits_per_pixel == 8) ? 256 : 16;
+}
+
+static void
+sisfb_set_vparms(struct sis_video_info *ivideo)
+{
+   	switch(ivideo->video_bpp) {
+	case 8:
+		ivideo->DstColor = 0x0000;
+		ivideo->SiS310_AccelDepth = 0x00000000;
+		ivideo->video_cmap_len = 256;
+		break;
+	case 16:
+		ivideo->DstColor = 0x8000;
+		ivideo->SiS310_AccelDepth = 0x00010000;
+		ivideo->video_cmap_len = 16;
+		break;
+	case 32:
+		ivideo->DstColor = 0xC000;
+		ivideo->SiS310_AccelDepth = 0x00020000;
+		ivideo->video_cmap_len = 16;
+		break;
+	default:
+		ivideo->video_cmap_len = 16;
+		printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
+		ivideo->accel = 0;
+		break;
+   	}
+}
+
+static int
+sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
+{
+	int maxyres = ivideo->heapstart / (var->xres_virtual * (var->bits_per_pixel >> 3));
+
+	if(maxyres > 32767) maxyres = 32767;
+
+	return maxyres;
+}
+
+static void
+sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
+{
+	ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
+	ivideo->scrnpitchCRT1 = ivideo->video_linelength;
+	if(!(ivideo->currentvbflags & CRT1_LCDA)) {
+		if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+			ivideo->scrnpitchCRT1 <<= 1;
+		}
+	}
+
+}
+
+static void
+sisfb_set_pitch(struct sis_video_info *ivideo)
+{
+   	BOOLEAN isslavemode = FALSE;
+	unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
+	unsigned short HDisplay2 = ivideo->video_linelength >> 3;
+
+   	if(sisfb_bridgeisslave(ivideo)) isslavemode = TRUE;
+
+   	/* We need to set pitch for CRT1 if bridge is in slave mode, too */
+   	if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
+   		outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF));
+   		setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8));
+	}
+
+   	/* We must not set the pitch for CRT2 if bridge is in slave mode */
+   	if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
+		orSISIDXREG(SISPART1,ivideo->CRT2_write_enable,0x01);
+   		outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF));
+   		setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8));
+   	}
+}
+
+static void
+sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
+{
+	ivideo->video_cmap_len = sisfb_get_cmap_len(var);
+
+	switch(var->bits_per_pixel) {
+	case 8:
+		var->red.offset = var->green.offset = var->blue.offset = 0;
+		var->red.length = var->green.length = var->blue.length = 6;
+		break;
+	case 16:
+		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;
+	case 32:
+		var->red.offset = 16;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		var->transp.offset = 24;
+		var->transp.length = 8;
+		break;
+	}
+}
+
+static int
+sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
+{
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+	unsigned int htotal = 0, vtotal = 0;
+	unsigned int drate = 0, hrate = 0;
+	int found_mode = 0;
+	int old_mode;
+	u32 pixclock;
+
+	htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
+
+	vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
+
+	pixclock = var->pixclock;
+
+	if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
+		vtotal += var->yres;
+		vtotal <<= 1;
+	} else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+		vtotal += var->yres;
+		vtotal <<= 2;
+	} else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+		vtotal += var->yres;
+		vtotal <<= 1;
+	} else 	vtotal += var->yres;
+
+	if(!(htotal) || !(vtotal)) {
+		DPRINTK("sisfb: Invalid 'var' information\n");
+		return -EINVAL;
+	}
+
+	if(pixclock && htotal && vtotal) {
+	   	drate = 1000000000 / pixclock;
+	   	hrate = (drate * 1000) / htotal;
+	   	ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
+	} else {
+	   	ivideo->refresh_rate = 60;
+	}
+
+	old_mode = ivideo->sisfb_mode_idx;
+	ivideo->sisfb_mode_idx = 0;
+
+	while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
+	       (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
+		if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
+		    (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
+		    (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
+			ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
+			found_mode = 1;
+			break;
+		}
+		ivideo->sisfb_mode_idx++;
+	}
+
+	if(found_mode) {
+		ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
+				ivideo->sisfb_mode_idx, ivideo->currentvbflags);
+	} else {
+		ivideo->sisfb_mode_idx = -1;
+	}
+
+       	if(ivideo->sisfb_mode_idx < 0) {
+		printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
+		       var->yres, var->bits_per_pixel);
+		ivideo->sisfb_mode_idx = old_mode;
+		return -EINVAL;
+	}
+
+	if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
+		ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
+		ivideo->refresh_rate = 60;
+	}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	if(ivideo->sisfb_thismonitor.datavalid) {
+	   if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
+	                         ivideo->rate_idx, ivideo->refresh_rate)) {
+	      printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
+	   }
+	}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	if(((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
+#else
+	if(isactive) {
+#endif
+		sisfb_pre_setmode(ivideo);
+
+		if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) {
+			printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
+			return -EINVAL;
+		}
+
+		outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
+
+		sisfb_post_setmode(ivideo);
+
+		ivideo->video_bpp    = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
+		ivideo->video_width  = sisbios_mode[ivideo->sisfb_mode_idx].xres;
+		ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
+
+		sisfb_calc_pitch(ivideo, var);
+		sisfb_set_pitch(ivideo);
+
+		ivideo->accel = 0;
+#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
+#ifdef STUPID_ACCELF_TEXT_SHIT
+		if(var->accel_flags & FB_ACCELF_TEXT) {
+			info->flags &= ~FBINFO_HWACCEL_DISABLED;
+		} else {
+			info->flags |= FBINFO_HWACCEL_DISABLED;
+		}
+#endif
+		if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
+#else
+		if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
+#endif
+
+		sisfb_set_vparms(ivideo);
+
+		ivideo->current_width = ivideo->video_width;
+		ivideo->current_height = ivideo->video_height;
+		ivideo->current_bpp = ivideo->video_bpp;
+		ivideo->current_htotal = htotal;
+		ivideo->current_vtotal = vtotal;
+		ivideo->current_linelength = ivideo->video_linelength;
+		ivideo->current_pixclock = var->pixclock;
+		ivideo->current_refresh_rate = ivideo->refresh_rate;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+                ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
+#endif
+	}
+
+	return 0;
+}
+
+static int
+sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
+{
+	unsigned int base;
+
+	if(var->xoffset > (var->xres_virtual - var->xres)) {
+		return -EINVAL;
+	}
+	if(var->yoffset > (var->yres_virtual - var->yres)) {
+		return -EINVAL;
+	}
+
+	base = (var->yoffset * var->xres_virtual) + var->xoffset;
+
+        /* calculate base bpp dep. */
+        switch(var->bits_per_pixel) {
+	case 32:
+            	break;
+        case 16:
+        	base >>= 1;
+        	break;
+	case 8:
+        default:
+        	base >>= 2;
+            	break;
+        }
+	
+	outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
+
+        outSISIDXREG(SISCR, 0x0D, base & 0xFF);
+	outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
+	outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
+	if(ivideo->sisvga_engine == SIS_315_VGA) {
+		setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
+	}
+        if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
+		orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
+        	outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
+        	outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
+        	outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
+		if(ivideo->sisvga_engine == SIS_315_VGA) {
+			setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
+		}
+        }
+	return 0;
+}
+
+/* ------------ FBDev related routines for 2.4 series ----------- */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+
+static void
+sisfb_crtc_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
+{
+	u16 VRE, VBE, VRS, VBS, VDE, VT;
+	u16 HRE, HBE, HRS, HBS, HDE, HT;
+	u8  sr_data, cr_data, cr_data2, cr_data3, mr_data;
+	int A, B, C, D, E, F, temp;
+	unsigned int hrate, drate, maxyres;
+
+	inSISIDXREG(SISSR, IND_SIS_COLOR_MODE, sr_data);
+
+	if(sr_data & SIS_INTERLACED_MODE)
+	   var->vmode = FB_VMODE_INTERLACED;
+	else
+	   var->vmode = FB_VMODE_NONINTERLACED;
+
+	switch((sr_data & 0x1C) >> 2) {
+	case SIS_8BPP_COLOR_MODE:
+		var->bits_per_pixel = 8;
+		break;
+	case SIS_16BPP_COLOR_MODE:
+		var->bits_per_pixel = 16;
+		break;
+	case SIS_32BPP_COLOR_MODE:
+		var->bits_per_pixel = 32;
+		break;
+	}
+
+	sisfb_bpp_to_var(ivideo, var);
+	
+	inSISIDXREG(SISSR, 0x0A, sr_data);
+        inSISIDXREG(SISCR, 0x06, cr_data);
+        inSISIDXREG(SISCR, 0x07, cr_data2);
+
+	VT = (cr_data & 0xFF) |
+	     ((u16) (cr_data2 & 0x01) << 8) |
+	     ((u16) (cr_data2 & 0x20) << 4) |
+	     ((u16) (sr_data  & 0x01) << 10);
+	A = VT + 2;
+
+	inSISIDXREG(SISCR, 0x12, cr_data);
+
+	VDE = (cr_data & 0xff) |
+	      ((u16) (cr_data2 & 0x02) << 7) |
+	      ((u16) (cr_data2 & 0x40) << 3) |
+	      ((u16) (sr_data  & 0x02) << 9);
+	E = VDE + 1;
+
+	inSISIDXREG(SISCR, 0x10, cr_data);
+
+	VRS = (cr_data & 0xff) |
+	      ((u16) (cr_data2 & 0x04) << 6) |
+	      ((u16) (cr_data2 & 0x80) << 2) |
+	      ((u16) (sr_data  & 0x08) << 7);
+	F = VRS + 1 - E;
+
+	inSISIDXREG(SISCR, 0x15, cr_data);
+	inSISIDXREG(SISCR, 0x09, cr_data3);
+
+	if(cr_data3 & 0x80) var->vmode = FB_VMODE_DOUBLE;
+
+	VBS = (cr_data & 0xff) |
+	      ((u16) (cr_data2 & 0x08) << 5) |
+	      ((u16) (cr_data3 & 0x20) << 4) |
+	      ((u16) (sr_data & 0x04) << 8);
+
+	inSISIDXREG(SISCR, 0x16, cr_data);
+
+	VBE = (cr_data & 0xff) | ((u16) (sr_data & 0x10) << 4);
+	temp = VBE - ((E - 1) & 511);
+	B = (temp > 0) ? temp : (temp + 512);
+
+	inSISIDXREG(SISCR, 0x11, cr_data);
+
+	VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1);
+	temp = VRE - ((E + F - 1) & 31);
+	C = (temp > 0) ? temp : (temp + 32);
+
+	D = B - F - C;
+
+        var->yres = E;
+	var->upper_margin = D;
+	var->lower_margin = F;
+	var->vsync_len = C;
+
+	if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+	   var->yres <<= 1;
+	   var->upper_margin <<= 1;
+	   var->lower_margin <<= 1;
+	   var->vsync_len <<= 1;
+	} else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+	   var->yres >>= 1;
+	   var->upper_margin >>= 1;
+	   var->lower_margin >>= 1;
+	   var->vsync_len >>= 1;
+	}
+
+	inSISIDXREG(SISSR, 0x0b, sr_data);
+	inSISIDXREG(SISCR, 0x00, cr_data);
+
+	HT = (cr_data & 0xff) | ((u16) (sr_data & 0x03) << 8);
+	A = HT + 5;
+
+	inSISIDXREG(SISCR, 0x01, cr_data);
+
+	HDE = (cr_data & 0xff) | ((u16) (sr_data & 0x0C) << 6);
+	E = HDE + 1;
+
+	inSISIDXREG(SISCR, 0x04, cr_data);
+
+	HRS = (cr_data & 0xff) | ((u16) (sr_data & 0xC0) << 2);
+	F = HRS - E - 3;
+
+	inSISIDXREG(SISCR, 0x02, cr_data);
+
+	HBS = (cr_data & 0xff) | ((u16) (sr_data & 0x30) << 4);
+
+	inSISIDXREG(SISSR, 0x0c, sr_data);
+	inSISIDXREG(SISCR, 0x03, cr_data);
+	inSISIDXREG(SISCR, 0x05, cr_data2);
+
+	HBE = (cr_data & 0x1f) |
+	      ((u16) (cr_data2 & 0x80) >> 2) |
+	      ((u16) (sr_data  & 0x03) << 6);
+	HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3);
+
+	temp = HBE - ((E - 1) & 255);
+	B = (temp > 0) ? temp : (temp + 256);
+
+	temp = HRE - ((E + F + 3) & 63);
+	C = (temp > 0) ? temp : (temp + 64);
+
+	D = B - F - C;
+
+	var->xres = E * 8;
+	if(var->xres_virtual < var->xres) {
+		var->xres_virtual = var->xres;
+	}
+
+	if((var->xres == 320) &&
+	   (var->yres == 200 || var->yres == 240)) {
+		/* Terrible hack, but the correct CRTC data for
+	  	 * these modes only produces a black screen...
+	  	 */
+       		var->left_margin = (400 - 376);
+       		var->right_margin = (328 - 320);
+       		var->hsync_len = (376 - 328);
+	} else {
+	   	var->left_margin = D * 8;
+	   	var->right_margin = F * 8;
+	   	var->hsync_len = C * 8;
+	}
+	var->activate = FB_ACTIVATE_NOW;
+
+	var->sync = 0;
+
+	mr_data = inSISREG(SISMISCR);
+	if(mr_data & 0x80)
+	   var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
+	else
+	   var->sync |= FB_SYNC_VERT_HIGH_ACT;
+
+	if(mr_data & 0x40)
+	   var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
+	else
+	   var->sync |= FB_SYNC_HOR_HIGH_ACT;
+
+	VT += 2;
+	VT <<= 1;
+	HT = (HT + 5) * 8;
+
+	if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+	   VT <<= 1;
+	}
+	hrate = ivideo->refresh_rate * VT / 2;
+	drate = (hrate * HT) / 1000;
+	var->pixclock = (u32) (1000000000 / drate);
+
+	if(ivideo->sisfb_ypan) {
+	   maxyres = sisfb_calc_maxyres(ivideo, var);
+	   if(ivideo->sisfb_max) {
+	      var->yres_virtual = maxyres;
+	   } else {
+	      if(var->yres_virtual > maxyres) {
+	         var->yres_virtual = maxyres;
+	      }
+	   }
+	   if(var->yres_virtual <= var->yres) {
+	      var->yres_virtual = var->yres;
+	   }
+	} else {
+	   var->yres_virtual = var->yres;
+	}
+
+}
+
+static int
+sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue,
+			 unsigned *transp, struct fb_info *info)
+{
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+
+	if(regno >= ivideo->video_cmap_len) return 1;
+
+	*red   = ivideo->sis_palette[regno].red;
+	*green = ivideo->sis_palette[regno].green;
+	*blue  = ivideo->sis_palette[regno].blue;
+	*transp = 0;
+
+	return 0;
+}
+
+static int
+sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
+                           unsigned transp, struct fb_info *info)
+{
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+
+	if(regno >= ivideo->video_cmap_len) return 1;
+
+	ivideo->sis_palette[regno].red   = red;
+	ivideo->sis_palette[regno].green = green;
+	ivideo->sis_palette[regno].blue  = blue;
+
+	switch(ivideo->video_bpp) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+	        outSISREG(SISDACA, regno);
+		outSISREG(SISDACD, (red >> 10));
+		outSISREG(SISDACD, (green >> 10));
+		outSISREG(SISDACD, (blue >> 10));
+		if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
+		        outSISREG(SISDAC2A, regno);
+			outSISREG(SISDAC2D, (red >> 8));
+			outSISREG(SISDAC2D, (green >> 8));
+			outSISREG(SISDAC2D, (blue >> 8));
+		}
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		ivideo->sis_fbcon_cmap.cfb16[regno] =
+		    ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 32:
+		red   >>= 8;
+		green >>= 8;
+		blue  >>= 8;
+		ivideo->sis_fbcon_cmap.cfb32[regno] = (red << 16) | (green << 8) | (blue);
+		break;
+#endif
+	}
+
+	return 0;
+}
+
+static void
+sisfb_set_disp(int con, struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct sis_video_info    *ivideo = (struct sis_video_info *)info->par;
+	struct display           *display;
+	struct display_switch    *sw;
+	struct fb_fix_screeninfo fix;
+	long   flags;
+
+	display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
+
+	sisfb_get_fix(&fix, con, info);
+
+	display->var = *var;
+	display->screen_base = (char *)ivideo->video_vbase;
+	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 = ivideo->sisfb_inverse;
+	display->next_line = fix.line_length;
+
+	save_flags(flags);
+
+	switch(ivideo->video_bpp) {
+#ifdef FBCON_HAS_CFB8
+	case 8:	sw = ivideo->accel ? &fbcon_sis8 : &fbcon_cfb8;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:sw = ivideo->accel ? &fbcon_sis16 : &fbcon_cfb16;
+		display->dispsw_data = &ivideo->sis_fbcon_cmap.cfb16;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 32:sw = ivideo->accel ? &fbcon_sis32 : &fbcon_cfb32;
+		display->dispsw_data = &ivideo->sis_fbcon_cmap.cfb32;
+		break;
+#endif
+	default:sw = &fbcon_dummy;
+		break;
+	}
+	memcpy(&ivideo->sisfb_sw, sw, sizeof(*sw));
+	display->dispsw = &ivideo->sisfb_sw;
+
+	restore_flags(flags);
+
+        if(ivideo->sisfb_ypan) {
+  	    /* display->scrollmode = 0;  */
+	} else {
+	    display->scrollmode = SCROLL_YREDRAW;
+	    ivideo->sisfb_sw.bmove = fbcon_redraw_bmove;
+	}
+}
+
+static void
+sisfb_do_install_cmap(int con, struct fb_info *info)
+{
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+
+        if(con != ivideo->currcon) return;
+
+        if(fb_display[con].cmap.len) {
+		fb_set_cmap(&fb_display[con].cmap, 1, sisfb_setcolreg, info);
+        } else {
+		int size = sisfb_get_cmap_len(&fb_display[con].var);
+		fb_set_cmap(fb_default_cmap(size), 1, sisfb_setcolreg, info);
+	}
+}
+
+static int
+sisfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+{
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+
+	if(con == -1) {
+		memcpy(var, &ivideo->default_var, sizeof(struct fb_var_screeninfo));
+	} else {
+		*var = fb_display[con].var;
+	}
+
+	if(ivideo->sisfb_fstn) {
+	   	if(var->xres == 320 && var->yres == 480) var->yres = 240;
+        }
+
+	return 0;
+}
+
+static int
+sisfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+{
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+	int err;
+
+	fb_display[con].var.activate = FB_ACTIVATE_NOW;
+
+        if(sisfb_do_set_var(var, con == ivideo->currcon, info)) {
+		sisfb_crtc_to_var(ivideo, var);
+		return -EINVAL;
+	}
+
+	sisfb_crtc_to_var(ivideo, var);
+
+	sisfb_set_disp(con, var, info);
+
+	if(info->changevar) {
+		(*info->changevar)(con);
+	}
+
+	if((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0))) {
+		return err;
+	}
+
+	sisfb_do_install_cmap(con, info);
+
+#if 0	/* Why was this called here? */
+	unsigned int cols, rows;
+	cols = sisbios_mode[ivideo->sisfb_mode_idx].cols;
+	rows = sisbios_mode[ivideo->sisfb_mode_idx].rows;
+ 	vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
+#endif
+	return 0;
+}
+
+static int
+sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
+{
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+	struct display *display;
+
+	display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
+
+        if(con == ivideo->currcon) {
+
+		return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
+
+	} else if(display->cmap.len) {
+
+		fb_copy_cmap(&display->cmap, cmap, kspc ? 0 : 2);
+
+	} else {
+
+		int size = sisfb_get_cmap_len(&display->var);
+		fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
+
+	}
+
+	return 0;
+}
+
+static int
+sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
+{
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+	struct display *display;
+	int err, size;
+
+	display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
+
+	size = sisfb_get_cmap_len(&display->var);
+	if(display->cmap.len != size) {
+		err = fb_alloc_cmap(&display->cmap, size, 0);
+		if(err)	return err;
+	}
+        
+	if(con == ivideo->currcon) {
+		return fb_set_cmap(cmap, kspc, sisfb_setcolreg, info);
+	} else {
+		fb_copy_cmap(cmap, &display->cmap, kspc ? 0 : 1);
+	}
+
+	return 0;
+}
+
+static int
+sisfb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info* info)
+{
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+	int err;
+
+	if(var->vmode & FB_VMODE_YWRAP) return -EINVAL;
+
+	if((var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual) ||
+	   (var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)) {
+		return -EINVAL;
+	}
+
+        if(con == ivideo->currcon) {
+	   	if((err = sisfb_pan_var(ivideo, var)) < 0) return err;
+	}
+
+	fb_display[con].var.xoffset = var->xoffset;
+	fb_display[con].var.yoffset = var->yoffset;
+
+	return 0;
+}
+
+static int
+sisfb_update_var(int con, struct fb_info *info)
+{
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+
+        return(sisfb_pan_var(ivideo, &fb_display[con].var));
+}
+
+static int
+sisfb_switch(int con, struct fb_info *info)
+{
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+	int cols, rows;
+
+        if(fb_display[ivideo->currcon].cmap.len) {
+		fb_get_cmap(&fb_display[ivideo->currcon].cmap, 1, sis_getcolreg, info);
+	}
+
+	fb_display[con].var.activate = FB_ACTIVATE_NOW;
+
+	if(!memcmp(&fb_display[con].var, &fb_display[ivideo->currcon].var,
+	                           	sizeof(struct fb_var_screeninfo))) {
+		ivideo->currcon = con;
+		return 1;
+	}
+
+	ivideo->currcon = con;
+
+	sisfb_do_set_var(&fb_display[con].var, 1, info);
+
+	sisfb_set_disp(con, &fb_display[con].var, info);
+
+	sisfb_do_install_cmap(con, info);
+
+	cols = sisbios_mode[ivideo->sisfb_mode_idx].cols;
+	rows = sisbios_mode[ivideo->sisfb_mode_idx].rows;
+	vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
+
+	sisfb_update_var(con, info);
+
+	return 1;
+}
+
+static void
+sisfb_blank(int blank, struct fb_info *info)
+{
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+
+	sisfb_myblank(ivideo, blank);
+}
+#endif
+
+/* ------------ FBDev related routines for 2.6 series ----------- */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+
+static int
+sisfb_open(struct fb_info *info, int user)
+{
+    	return 0;
+}
+
+static int
+sisfb_release(struct fb_info *info, int user)
+{
+    	return 0;
+}
+
+static int
+sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
+		unsigned transp, struct fb_info *info)
+{
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+
+	if(regno >= sisfb_get_cmap_len(&info->var)) return 1;
+
+	switch(info->var.bits_per_pixel) {
+	case 8:
+	        outSISREG(SISDACA, regno);
+		outSISREG(SISDACD, (red >> 10));
+		outSISREG(SISDACD, (green >> 10));
+		outSISREG(SISDACD, (blue >> 10));
+		if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
+		        outSISREG(SISDAC2A, regno);
+			outSISREG(SISDAC2D, (red >> 8));
+			outSISREG(SISDAC2D, (green >> 8));
+			outSISREG(SISDAC2D, (blue >> 8));
+		}
+		break;
+	case 16:
+		((u32 *)(info->pseudo_palette))[regno] =
+		    ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
+		break;
+	case 32:
+		red >>= 8;
+		green >>= 8;
+		blue >>= 8;
+		((u32 *)(info->pseudo_palette))[regno] =
+				(red << 16) | (green << 8) | (blue);
+		break;
+	}
+	return 0;
+}
+
+static int
+sisfb_set_par(struct fb_info *info)
+{
+	int err;
+
+        if((err = sisfb_do_set_var(&info->var, 1, info))) {
+		return err;
+	}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
+	sisfb_get_fix(&info->fix, info->currcon, info);
+#else
+      	sisfb_get_fix(&info->fix, -1, info);
+#endif
+	return 0;
+}
+
+static int
+sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+	unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
+	unsigned int drate = 0, hrate = 0, maxyres;
+	int found_mode = 0;
+	int refresh_rate, search_idx;
+	BOOLEAN recalc_clock = FALSE;
+	u32 pixclock;
+
+	htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
+
+	vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
+
+	pixclock = var->pixclock;
+
+	if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
+		vtotal += var->yres;
+		vtotal <<= 1;
+	} else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+		vtotal += var->yres;
+		vtotal <<= 2;
+	} else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+		vtotal += var->yres;
+		vtotal <<= 1;
+	} else 	vtotal += var->yres;
+
+	if(!(htotal) || !(vtotal)) {
+		SISFAIL("sisfb: no valid timing data");
+	}
+
+	search_idx = 0;
+	while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
+	       (sisbios_mode[search_idx].xres <= var->xres) ) {
+		if( (sisbios_mode[search_idx].xres == var->xres) &&
+		    (sisbios_mode[search_idx].yres == var->yres) &&
+		    (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
+		        if(sisfb_validate_mode(ivideo, search_idx, ivideo->currentvbflags) > 0) {
+			   found_mode = 1;
+			   break;
+			}
+		}
+		search_idx++;
+	}
+
+	if(!found_mode) {
+                search_idx = 0;
+		while(sisbios_mode[search_idx].mode_no[0] != 0) {
+		   if( (var->xres <= sisbios_mode[search_idx].xres) &&
+		       (var->yres <= sisbios_mode[search_idx].yres) &&
+		       (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
+		          if(sisfb_validate_mode(ivideo,search_idx, ivideo->currentvbflags) > 0) {
+			     found_mode = 1;
+			     break;
+			  }
+		   }
+		   search_idx++;
+	        }
+		if(found_mode) {
+			printk(KERN_DEBUG "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
+		   		var->xres, var->yres, var->bits_per_pixel,
+				sisbios_mode[search_idx].xres,
+				sisbios_mode[search_idx].yres,
+				var->bits_per_pixel);
+			var->xres = sisbios_mode[search_idx].xres;
+		      	var->yres = sisbios_mode[search_idx].yres;
+
+
+		} else {
+		   	printk(KERN_ERR "sisfb: Failed to find supported mode near %dx%dx%d\n",
+				var->xres, var->yres, var->bits_per_pixel);
+		   	return -EINVAL;
+		}
+	}
+
+	if( ((ivideo->vbflags & VB_LVDS) ||			/* Slave modes on LVDS and 301B-DH */
+	     ((ivideo->vbflags & VB_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
+	    (var->bits_per_pixel == 8) ) {
+	    	refresh_rate = 60;
+		recalc_clock = TRUE;
+	} else if( (ivideo->current_htotal == htotal) &&	/* x=x & y=y & c=c -> assume depth change */
+	    	   (ivideo->current_vtotal == vtotal) &&
+	    	   (ivideo->current_pixclock == pixclock) ) {
+		drate = 1000000000 / pixclock;
+	        hrate = (drate * 1000) / htotal;
+	        refresh_rate = (unsigned int) (hrate * 2 / vtotal);
+	} else if( ( (ivideo->current_htotal != htotal) ||	/* x!=x | y!=y & c=c -> invalid pixclock */
+	    	     (ivideo->current_vtotal != vtotal) ) &&
+	    	   (ivideo->current_pixclock == var->pixclock) ) {
+		if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
+			refresh_rate = ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
+		} else if(ivideo->sisfb_parm_rate != -1) {
+			/* Sic, sisfb_parm_rate - want to know originally desired rate here */
+			refresh_rate = ivideo->sisfb_parm_rate;
+		} else {
+			refresh_rate = 60;
+		}
+		recalc_clock = TRUE;
+	} else if((pixclock) && (htotal) && (vtotal)) {
+		drate = 1000000000 / pixclock;
+	   	hrate = (drate * 1000) / htotal;
+	   	refresh_rate = (unsigned int) (hrate * 2 / vtotal);
+	} else if(ivideo->current_refresh_rate) {
+		refresh_rate = ivideo->current_refresh_rate;
+		recalc_clock = TRUE;
+	} else {
+		refresh_rate = 60;
+		recalc_clock = TRUE;
+	}
+
+	myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
+
+	/* Eventually recalculate timing and clock */
+	if(recalc_clock) {
+	   if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
+	   var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
+	   					&ivideo->sishw_ext,
+						sisbios_mode[search_idx].mode_no[ivideo->mni],
+						myrateindex));
+	   sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext,
+		 		    sisbios_mode[search_idx].mode_no[ivideo->mni], myrateindex,	var);
+	   if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+	      var->pixclock <<= 1;
+	   }
+	}
+
+	if(ivideo->sisfb_thismonitor.datavalid) {
+	   if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
+	                         myrateindex, refresh_rate)) {
+	      printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
+	   }
+	}
+
+	/* Adapt RGB settings */
+	sisfb_bpp_to_var(ivideo, var);
+	
+	/* Sanity check for offsets */
+	if(var->xoffset < 0) var->xoffset = 0;
+	if(var->yoffset < 0) var->yoffset = 0;
+
+	if(var->xres > var->xres_virtual) {
+	   var->xres_virtual = var->xres;
+	}
+
+	if(ivideo->sisfb_ypan) {
+	   maxyres = sisfb_calc_maxyres(ivideo, var);
+	   if(ivideo->sisfb_max) {
+	      var->yres_virtual = maxyres;
+	   } else {
+	      if(var->yres_virtual > maxyres) {
+	         var->yres_virtual = maxyres;
+	      }
+	   }
+	   if(var->yres_virtual <= var->yres) {
+	      var->yres_virtual = var->yres;
+	   }
+	} else {
+	   if(var->yres != var->yres_virtual) {
+	      var->yres_virtual = var->yres;
+	   }
+	   var->xoffset = 0;
+	   var->yoffset = 0;
+	}
+	
+	/* Truncate offsets to maximum if too high */
+	if(var->xoffset > var->xres_virtual - var->xres) {
+	   var->xoffset = var->xres_virtual - var->xres - 1;
+	}
+
+	if(var->yoffset > var->yres_virtual - var->yres) {
+	   var->yoffset = var->yres_virtual - var->yres - 1;
+	}
+	
+	/* Set everything else to 0 */
+	var->red.msb_right = 
+	var->green.msb_right =
+	var->blue.msb_right =
+	var->transp.offset =
+	var->transp.length =
+	var->transp.msb_right = 0;
+
+	return 0;
+}
+
+static int
+sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
+{
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+	int err;
+
+	if(var->xoffset > (var->xres_virtual - var->xres)) {
+		return -EINVAL;
+	}
+	if(var->yoffset > (var->yres_virtual - var->yres)) {
+		return -EINVAL;
+	}
+
+	if(var->vmode & FB_VMODE_YWRAP) return -EINVAL;
+
+	if(var->xoffset + info->var.xres > info->var.xres_virtual ||
+	   var->yoffset + info->var.yres > info->var.yres_virtual) {
+		return -EINVAL;
+	}
+
+	if((err = sisfb_pan_var(ivideo, var)) < 0) return err;
+
+	info->var.xoffset = var->xoffset;
+	info->var.yoffset = var->yoffset;
+
+	return 0;
+}
+
+static int
+sisfb_blank(int blank, struct fb_info *info)
+{
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+
+	return(sisfb_myblank(ivideo, blank));
+}
+
+#endif
+
+/* ----------- FBDev related routines for all series ---------- */
+
+static int
+sisfb_ioctl(struct inode *inode, struct file *file,
+            unsigned int cmd, unsigned long arg,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	    int con,
+#endif
+	    struct fb_info *info)
+{
+	struct sis_video_info	*ivideo = (struct sis_video_info *)info->par;
+	struct sis_memreq 	sismemreq;
+	struct fb_vblank  	sisvbblank;
+	sisfb_info        	x;
+	u32			gpu32 = 0;
+#ifndef __user
+#define __user
+#endif
+	u32 __user 		*argp = (u32 __user *)arg;
+
+	switch (cmd) {
+	   case FBIO_ALLOC:
+		if(!capable(CAP_SYS_RAWIO)) {
+			return -EPERM;
+		}
+		if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq))) {
+		   	return -EFAULT;
+		}
+		sis_malloc(&sismemreq);
+		if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
+			sis_free((u32)sismemreq.offset);
+		    	return -EFAULT;
+		}
+		break;
+
+	   case FBIO_FREE:
+		if(!capable(CAP_SYS_RAWIO)) {
+			return -EPERM;
+		}
+		if(get_user(gpu32, argp)) {
+			return -EFAULT;
+		}
+		sis_free(gpu32);
+		break;
+
+	   case FBIOGET_VBLANK:
+		sisvbblank.count = 0;
+		sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
+		if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank))) {
+			return -EFAULT;
+		}
+		break;
+
+	   case SISFB_GET_INFO_SIZE:
+	        return put_user(sizeof(sisfb_info), argp);
+
+	   case SISFB_GET_INFO_OLD:
+	        if(ivideo->warncount++ < 50) {
+	           printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
+		}
+	   case SISFB_GET_INFO:  /* For communication with X driver */
+		x.sisfb_id         = SISFB_ID;
+		x.sisfb_version    = VER_MAJOR;
+		x.sisfb_revision   = VER_MINOR;
+		x.sisfb_patchlevel = VER_LEVEL;
+		x.chip_id = ivideo->chip_id;
+		x.memory = ivideo->video_size / 1024;
+		x.heapstart = ivideo->heapstart / 1024;
+		if(ivideo->modechanged) {
+		   x.fbvidmode = ivideo->mode_no;
+		} else {
+		   x.fbvidmode = ivideo->modeprechange;
+		}
+		x.sisfb_caps = ivideo->caps;
+		x.sisfb_tqlen = 512; /* yet fixed */
+		x.sisfb_pcibus = ivideo->pcibus;
+		x.sisfb_pcislot = ivideo->pcislot;
+		x.sisfb_pcifunc = ivideo->pcifunc;
+		x.sisfb_lcdpdc = ivideo->detectedpdc;
+		x.sisfb_lcdpdca = ivideo->detectedpdca;
+		x.sisfb_lcda = ivideo->detectedlcda;
+		x.sisfb_vbflags = ivideo->vbflags;
+		x.sisfb_currentvbflags = ivideo->currentvbflags;
+		x.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
+		x.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
+		x.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
+		x.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
+		x.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
+		x.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
+		x.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
+		x.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
+		x.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
+		x.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
+
+		if(copy_to_user((void __user *)arg, &x, sizeof(x))) {
+			return -EFAULT;
+		}
+	        break;
+
+	   case SISFB_GET_VBRSTATUS_OLD:
+	   	if(ivideo->warncount++ < 50) {
+	           printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
+		}
+	   case SISFB_GET_VBRSTATUS:
+	        if(sisfb_CheckVBRetrace(ivideo)) {
+			return put_user((u32)1, argp);
+		} else {
+			return put_user((u32)0, argp);
+		}
+
+	   case SISFB_GET_AUTOMAXIMIZE_OLD:
+	   	if(ivideo->warncount++ < 50) {
+	           printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
+		}
+	   case SISFB_GET_AUTOMAXIMIZE:
+	        if(ivideo->sisfb_max)	return put_user((u32)1, argp);
+		else			return put_user((u32)0, argp);
+
+	   case SISFB_SET_AUTOMAXIMIZE_OLD:
+	   	if(ivideo->warncount++ < 50) {
+		   printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
+		}
+	   case SISFB_SET_AUTOMAXIMIZE:
+		if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
+			return -EFAULT;
+		}
+		ivideo->sisfb_max = (gpu32) ? 1 : 0;
+		break;
+
+	   case SISFB_SET_TVPOSOFFSET:
+		if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
+			return -EFAULT;
+		}
+		sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
+		sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
+		break;
+
+	   case SISFB_GET_TVPOSOFFSET:
+	        return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
+				argp);
+
+	   case SISFB_SET_LOCK:
+		if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
+			return -EFAULT;
+		}
+		ivideo->sisfblocked = (gpu32) ? 1 : 0;
+		break;
+
+	   default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_COMPAT
+static long sisfb_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg, struct fb_info *info)
+{
+	int ret;
+	lock_kernel();
+	ret = sisfb_ioctl(NULL, f, cmd, arg, info);
+	unlock_kernel();
+	return ret;
+}
+#endif
+
+static int
+sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
+{
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+
+	strcpy(fix->id, ivideo->myid);
+
+	fix->smem_start  = ivideo->video_base;
+	fix->smem_len    = ivideo->sisfb_mem;
+	fix->type        = FB_TYPE_PACKED_PIXELS;
+	fix->type_aux    = 0;
+	fix->visual      = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+	fix->xpanstep    = 1;
+	fix->ypanstep 	 = (ivideo->sisfb_ypan) ? 1 : 0;
+	fix->ywrapstep   = 0;
+	fix->line_length = ivideo->video_linelength;
+	fix->mmio_start  = ivideo->mmio_base;
+	fix->mmio_len    = ivideo->mmio_size;
+	if(ivideo->sisvga_engine == SIS_300_VGA) {
+	   fix->accel    = FB_ACCEL_SIS_GLAMOUR;
+	} else if((ivideo->chip == SIS_330) || (ivideo->chip == SIS_760)) {
+	   fix->accel    = FB_ACCEL_SIS_XABRE;
+	} else {
+	   fix->accel    = FB_ACCEL_SIS_GLAMOUR_2;
+	}
+
+	return 0;
+}
+
+/* ----------------  fb_ops structures ----------------- */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+static struct fb_ops sisfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_get_fix	= sisfb_get_fix,
+	.fb_get_var	= sisfb_get_var,
+	.fb_set_var	= sisfb_set_var,
+	.fb_get_cmap	= sisfb_get_cmap,
+	.fb_set_cmap	= sisfb_set_cmap,
+        .fb_pan_display = sisfb_pan_display,
+	.fb_ioctl	= sisfb_ioctl
+};
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+static struct fb_ops sisfb_ops = {
+	.owner          = THIS_MODULE,
+	.fb_open        = sisfb_open,
+	.fb_release     = sisfb_release,
+	.fb_check_var   = sisfb_check_var,
+	.fb_set_par     = sisfb_set_par,
+	.fb_setcolreg   = sisfb_setcolreg,
+        .fb_pan_display = sisfb_pan_display,
+        .fb_blank       = sisfb_blank,
+	.fb_fillrect    = fbcon_sis_fillrect,
+	.fb_copyarea    = fbcon_sis_copyarea,
+	.fb_imageblit   = cfb_imageblit,
+	.fb_cursor      = soft_cursor,
+	.fb_sync        = fbcon_sis_sync,
+	.fb_ioctl       = sisfb_ioctl,
+#ifdef CONFIG_COMPAT
+	.fb_compat_ioctl = sisfb_compat_ioctl,
+#endif
+};
+#endif
+
+/* ---------------- Chip generation dependent routines ---------------- */
+
+static struct pci_dev * sisfb_get_northbridge(int basechipid)
+{
+	struct pci_dev *pdev = NULL;
+	int nbridgenum, nbridgeidx, i;
+	const unsigned short nbridgeids[] = {
+		PCI_DEVICE_ID_SI_540,	/* for SiS 540 VGA */
+		PCI_DEVICE_ID_SI_630,	/* for SiS 630/730 VGA */
+		PCI_DEVICE_ID_SI_730,
+		PCI_DEVICE_ID_SI_550,   /* for SiS 550 VGA */
+		PCI_DEVICE_ID_SI_650,   /* for SiS 650/651/740 VGA */
+		PCI_DEVICE_ID_SI_651,
+		PCI_DEVICE_ID_SI_740,
+		PCI_DEVICE_ID_SI_661,	/* for SiS 661/741/660/760 VGA */
+		PCI_DEVICE_ID_SI_741,
+		PCI_DEVICE_ID_SI_660,
+		PCI_DEVICE_ID_SI_760
+	};
+
+    	switch(basechipid) {
+#ifdef CONFIG_FB_SIS_300
+	case SIS_540:	nbridgeidx = 0; nbridgenum = 1; break;
+	case SIS_630:	nbridgeidx = 1; nbridgenum = 2; break;
+#endif
+#ifdef CONFIG_FB_SIS_315
+	case SIS_550:   nbridgeidx = 3; nbridgenum = 1; break;
+	case SIS_650:	nbridgeidx = 4; nbridgenum = 3; break;
+	case SIS_660:	nbridgeidx = 7; nbridgenum = 4; break;
+#endif
+	default:	return NULL;
+	}
+	for(i = 0; i < nbridgenum; i++) {
+		if((pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridgeids[nbridgeidx+i], NULL))) break;
+	}
+	return pdev;
+}
+
+static int __devinit sisfb_get_dram_size(struct sis_video_info *ivideo)
+{
+#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
+	u8 reg;
+#endif
+
+	ivideo->video_size = 0;
+
+	switch(ivideo->chip) {
+#ifdef CONFIG_FB_SIS_300
+	case SIS_300:
+	        inSISIDXREG(SISSR, 0x14, reg);
+		ivideo->video_size = ((reg & 0x3F) + 1) << 20;
+		break;
+	case SIS_540:
+	case SIS_630:
+	case SIS_730:
+	   	if(!ivideo->nbridge) return -1;
+	   	pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
+		ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
+		break;
+#endif
+#ifdef CONFIG_FB_SIS_315
+	case SIS_315H:
+	case SIS_315PRO:
+	case SIS_315:
+	   	inSISIDXREG(SISSR, 0x14, reg);
+		ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
+		switch((reg >> 2) & 0x03) {
+		case 0x01:
+		case 0x03:
+		   ivideo->video_size <<= 1;
+		   break;
+		case 0x02:
+		   ivideo->video_size += (ivideo->video_size/2);
+		}
+	   	break;
+	case SIS_330:
+	   	inSISIDXREG(SISSR, 0x14, reg);
+		ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
+		if(reg & 0x0c) ivideo->video_size <<= 1;
+	   	break;
+	case SIS_550:
+	case SIS_650:
+	case SIS_740:
+	    	inSISIDXREG(SISSR, 0x14, reg);
+		ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
+		break;
+	case SIS_661:
+	case SIS_741:
+	     	inSISIDXREG(SISCR, 0x79, reg);
+		ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
+	   	break;
+	case SIS_660:
+	case SIS_760:
+		inSISIDXREG(SISCR, 0x79, reg);
+		reg = (reg & 0xf0) >> 4;
+		if(reg)	ivideo->video_size = (1 << reg) << 20;
+		inSISIDXREG(SISCR, 0x78, reg);
+		reg &= 0x30;
+		if(reg) {
+		   if(reg == 0x10) ivideo->video_size += (32 << 20);
+		   else		   ivideo->video_size += (64 << 20);
+		}
+	   	break;
+#endif
+	default:
+		return -1;
+	}
+	return 0;
+}
+
+/* -------------- video bridge device detection --------------- */
+
+static void __devinit sisfb_detect_VB_connect(struct sis_video_info *ivideo)
+{
+	u8 cr32, temp;
+
+#ifdef CONFIG_FB_SIS_300
+	if(ivideo->sisvga_engine == SIS_300_VGA) {
+		inSISIDXREG(SISSR, 0x17, temp);
+		if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
+			/* PAL/NTSC is stored on SR16 on such machines */
+			if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
+		   		inSISIDXREG(SISSR, 0x16, temp);
+				if(temp & 0x20)
+					ivideo->vbflags |= TV_PAL;
+				else
+					ivideo->vbflags |= TV_NTSC;
+			}
+		}
+	}
+#endif
+
+	inSISIDXREG(SISCR, 0x32, cr32);
+
+	if(cr32 & SIS_CRT1) {
+		ivideo->sisfb_crt1off = 0;
+	} else {
+		ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
+	}
+
+	ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
+
+	if(cr32 & SIS_VB_TV)   ivideo->vbflags |= CRT2_TV;
+	if(cr32 & SIS_VB_LCD)  ivideo->vbflags |= CRT2_LCD;
+	if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
+
+	/* Check given parms for hardware compatibility.
+	 * (Cannot do this in the search_xx routines since we don't
+	 * know what hardware we are running on then)
+	 */
+
+	if(ivideo->chip != SIS_550) {
+	   ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
+	}
+
+	if(ivideo->sisfb_tvplug != -1) {
+	   if( (ivideo->sisvga_engine != SIS_315_VGA) ||
+	       (!(ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV))) ) {
+	      if(ivideo->sisfb_tvplug & TV_YPBPR) {
+	         ivideo->sisfb_tvplug = -1;
+		 printk(KERN_ERR "sisfb: YPbPr not supported\n");
+	      }
+	   }
+	}
+	if(ivideo->sisfb_tvplug != -1) {
+	   if( (ivideo->sisvga_engine != SIS_315_VGA) ||
+	       (!(ivideo->vbflags & (VB_301|VB_301B|VB_302B))) ) {
+	      if(ivideo->sisfb_tvplug & TV_HIVISION) {
+	         ivideo->sisfb_tvplug = -1;
+		 printk(KERN_ERR "sisfb: HiVision not supported\n");
+	      }
+	   }
+	}
+	if(ivideo->sisfb_tvstd != -1) {
+	   if( (!(ivideo->vbflags & VB_SISBRIDGE)) &&
+	       (!((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags & VB_CHRONTEL))) ) {
+	      if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
+	         ivideo->sisfb_tvstd = -1;
+	         printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
+	      }
+	   }
+	}
+
+	/* Detect/set TV plug & type */
+	if(ivideo->sisfb_tvplug != -1) {
+		ivideo->vbflags |= ivideo->sisfb_tvplug;
+	} else {
+		if(cr32 & SIS_VB_YPBPR)     	 ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
+		else if(cr32 & SIS_VB_HIVISION)  ivideo->vbflags |= TV_HIVISION;
+		else if(cr32 & SIS_VB_SCART)     ivideo->vbflags |= TV_SCART;
+	 	else {
+			if(cr32 & SIS_VB_SVIDEO)    ivideo->vbflags |= TV_SVIDEO;
+			if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
+		}
+	}
+
+	if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
+	    if(ivideo->sisfb_tvstd != -1) {
+	       ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
+	       ivideo->vbflags |= ivideo->sisfb_tvstd;
+	    }
+	    if(ivideo->vbflags & TV_SCART) {
+	       ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
+	       ivideo->vbflags |= TV_PAL;
+	    }
+	    if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
+		if(ivideo->sisvga_engine == SIS_300_VGA) {
+	        	inSISIDXREG(SISSR, 0x38, temp);
+			if(temp & 0x01) ivideo->vbflags |= TV_PAL;
+			else		ivideo->vbflags |= TV_NTSC;
+		} else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
+                	inSISIDXREG(SISSR, 0x38, temp);
+			if(temp & 0x01) ivideo->vbflags |= TV_PAL;
+			else		ivideo->vbflags |= TV_NTSC;
+	    	} else {
+	        	inSISIDXREG(SISCR, 0x79, temp);
+			if(temp & 0x20)	ivideo->vbflags |= TV_PAL;
+			else		ivideo->vbflags |= TV_NTSC;
+	    	}
+	    }
+	}
+
+	/* Copy forceCRT1 option to CRT1off if option is given */
+    	if(ivideo->sisfb_forcecrt1 != -1) {
+    	   ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
+    	}
+}
+
+static void __devinit sisfb_get_VB_type(struct sis_video_info *ivideo)
+{
+	char stdstr[]    = "sisfb: Detected";
+	char bridgestr[] = "video bridge";
+	u8 vb_chipid;
+	u8 reg;
+
+	inSISIDXREG(SISPART4, 0x00, vb_chipid);
+	switch(vb_chipid) {
+	case 0x01:
+		inSISIDXREG(SISPART4, 0x01, reg);
+		if(reg < 0xb0) {
+			ivideo->vbflags |= VB_301;
+			printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
+		} else if(reg < 0xc0) {
+		 	ivideo->vbflags |= VB_301B;
+			inSISIDXREG(SISPART4,0x23,reg);
+			if(!(reg & 0x02)) {
+			   ivideo->vbflags |= VB_30xBDH;
+			   printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
+			} else {
+			   printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
+			}
+		} else if(reg < 0xd0) {
+		 	ivideo->vbflags |= VB_301C;
+			printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
+		} else if(reg < 0xe0) {
+			ivideo->vbflags |= VB_301LV;
+			printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
+		} else if(reg <= 0xe1) {
+		        inSISIDXREG(SISPART4,0x39,reg);
+			if(reg == 0xff) {
+			   ivideo->vbflags |= VB_302LV;
+			   printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
+			} else {
+			   ivideo->vbflags |= VB_301C;
+			   printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
+#if 0
+			   ivideo->vbflags |= VB_302ELV;
+			   printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
+#endif
+			}
+		}
+		break;
+	case 0x02:
+		ivideo->vbflags |= VB_302B;
+		printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
+		break;
+	}
+
+	if((!(ivideo->vbflags & VB_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
+		inSISIDXREG(SISCR, 0x37, reg);
+		reg &= SIS_EXTERNAL_CHIP_MASK;
+		reg >>= 1;
+		if(ivideo->sisvga_engine == SIS_300_VGA) {
+#ifdef CONFIG_FB_SIS_300
+			switch(reg) {
+			   case SIS_EXTERNAL_CHIP_LVDS:
+				ivideo->vbflags |= VB_LVDS;
+				break;
+			   case SIS_EXTERNAL_CHIP_TRUMPION:
+				ivideo->vbflags |= VB_TRUMPION;
+				break;
+			   case SIS_EXTERNAL_CHIP_CHRONTEL:
+				ivideo->vbflags |= VB_CHRONTEL;
+				break;
+			   case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
+				ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
+				break;
+			}
+			if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 1;
+#endif
+		} else if(ivideo->chip < SIS_661) {
+#ifdef CONFIG_FB_SIS_315
+			switch (reg) {
+	 	   	   case SIS310_EXTERNAL_CHIP_LVDS:
+				ivideo->vbflags |= VB_LVDS;
+				break;
+		   	   case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
+				ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
+				break;
+			}
+			if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 2;
+#endif
+		} else if(ivideo->chip >= SIS_661) {
+#ifdef CONFIG_FB_SIS_315
+			inSISIDXREG(SISCR, 0x38, reg);
+			reg >>= 5;
+			switch(reg) {
+			   case 0x02:
+				ivideo->vbflags |= VB_LVDS;
+				break;
+			   case 0x03:
+				ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
+				break;
+			   case 0x04:
+				ivideo->vbflags |= (VB_LVDS | VB_CONEXANT);
+				break;
+			}
+			if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 2;
+#endif
+		}
+		if(ivideo->vbflags & VB_LVDS) {
+		   printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
+		}
+		if(ivideo->vbflags & VB_TRUMPION) {
+		   printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
+		}
+		if(ivideo->vbflags & VB_CHRONTEL) {
+		   printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
+		}
+		if(ivideo->vbflags & VB_CONEXANT) {
+		   printk(KERN_INFO "%s Conexant external device\n", stdstr);
+		}
+	}
+
+	if(ivideo->vbflags & VB_SISBRIDGE) {
+		SiS_Sense30x(ivideo);
+	} else if(ivideo->vbflags & VB_CHRONTEL) {
+		SiS_SenseCh(ivideo);
+	}
+}
+
+/* ------------------ Sensing routines ------------------ */
+
+static BOOLEAN __devinit sisfb_test_DDC1(struct sis_video_info *ivideo)
+{
+    unsigned short old;
+    int count = 48;
+
+    old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
+    do {
+       	if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
+    } while(count--);
+    return (count == -1) ? FALSE : TRUE;
+}
+
+static void __devinit sisfb_sense_crt1(struct sis_video_info *ivideo)
+{
+    BOOLEAN mustwait = FALSE;
+    u8  sr1F, cr17;
+#ifdef CONFIG_FB_SIS_315
+    u8  cr63=0;
+#endif
+    u16 temp = 0xffff;
+    int i;
+
+    inSISIDXREG(SISSR,0x1F,sr1F);
+    orSISIDXREG(SISSR,0x1F,0x04);
+    andSISIDXREG(SISSR,0x1F,0x3F);
+    if(sr1F & 0xc0) mustwait = TRUE;
+
+#ifdef CONFIG_FB_SIS_315
+    if(ivideo->sisvga_engine == SIS_315_VGA) {
+       inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
+       cr63 &= 0x40;
+       andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
+    }
+#endif
+
+    inSISIDXREG(SISCR,0x17,cr17);
+    cr17 &= 0x80;
+    if(!cr17) {
+       orSISIDXREG(SISCR,0x17,0x80);
+       mustwait = TRUE;
+       outSISIDXREG(SISSR, 0x00, 0x01);
+       outSISIDXREG(SISSR, 0x00, 0x03);
+    }
+
+    if(mustwait) {
+       for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
+    }
+
+#ifdef CONFIG_FB_SIS_315
+    if(ivideo->chip >= SIS_330) {
+       andSISIDXREG(SISCR,0x32,~0x20);
+       if(ivideo->chip >= SIS_340) {
+          outSISIDXREG(SISCR, 0x57, 0x4a);
+       } else {
+          outSISIDXREG(SISCR, 0x57, 0x5f);
+       }
+       orSISIDXREG(SISCR, 0x53, 0x02);
+       while((inSISREG(SISINPSTAT)) & 0x01)    break;
+       while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
+       if((inSISREG(SISMISCW)) & 0x10) temp = 1;
+       andSISIDXREG(SISCR, 0x53, 0xfd);
+       andSISIDXREG(SISCR, 0x57, 0x00);
+    }
+#endif
+
+    if(temp == 0xffff) {
+       i = 3;
+       do {
+          temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine, 0, 0, NULL);
+       } while(((temp == 0) || (temp == 0xffff)) && i--);
+
+       if((temp == 0) || (temp == 0xffff)) {
+          if(sisfb_test_DDC1(ivideo)) temp = 1;
+       }
+    }
+
+    if((temp) && (temp != 0xffff)) {
+       orSISIDXREG(SISCR,0x32,0x20);
+    }
+
+#ifdef CONFIG_FB_SIS_315
+    if(ivideo->sisvga_engine == SIS_315_VGA) {
+       setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
+    }
+#endif
+
+    setSISIDXREG(SISCR,0x17,0x7F,cr17);
+
+    outSISIDXREG(SISSR,0x1F,sr1F);
+}
+
+/* Determine and detect attached devices on SiS30x */
+static int __devinit SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
+{
+    int temp, mytest, result, i, j;
+
+    for(j = 0; j < 10; j++) {
+       result = 0;
+       for(i = 0; i < 3; i++) {
+          mytest = test;
+          outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
+          temp = (type >> 8) | (mytest & 0x00ff);
+          setSISIDXREG(SISPART4,0x10,0xe0,temp);
+          SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
+          mytest >>= 8;
+          mytest &= 0x7f;
+          inSISIDXREG(SISPART4,0x03,temp);
+          temp ^= 0x0e;
+          temp &= mytest;
+          if(temp == mytest) result++;
+#if 1
+	  outSISIDXREG(SISPART4,0x11,0x00);
+	  andSISIDXREG(SISPART4,0x10,0xe0);
+	  SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
+#endif
+       }
+       if((result == 0) || (result >= 2)) break;
+    }
+    return(result);
+}
+
+static void __devinit SiS_Sense30x(struct sis_video_info *ivideo)
+{
+    u8  backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
+    u16 svhs=0, svhs_c=0;
+    u16 cvbs=0, cvbs_c=0;
+    u16 vga2=0, vga2_c=0;
+    int myflag, result;
+    char stdstr[] = "sisfb: Detected";
+    char tvstr[]  = "TV connected to";
+
+    if(ivideo->vbflags & VB_301) {
+       svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
+       inSISIDXREG(SISPART4,0x01,myflag);
+       if(myflag & 0x04) {
+	  svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
+       }
+    } else if(ivideo->vbflags & (VB_301B | VB_302B)) {
+       svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
+    } else if(ivideo->vbflags & (VB_301LV | VB_302LV)) {
+       svhs = 0x0200; cvbs = 0x0100;
+    } else if(ivideo->vbflags & (VB_301C | VB_302ELV)) {
+       svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
+    } else return;
+
+    vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
+    if(ivideo->vbflags & (VB_301LV|VB_302LV|VB_302ELV)) {
+       svhs_c = 0x0408; cvbs_c = 0x0808;
+    }
+    biosflag = 2;
+
+    if(ivideo->chip == SIS_300) {
+       inSISIDXREG(SISSR,0x3b,myflag);
+       if(!(myflag & 0x01)) vga2 = vga2_c = 0;
+    }
+
+    inSISIDXREG(SISSR,0x1e,backupSR_1e);
+    orSISIDXREG(SISSR,0x1e,0x20);
+
+    inSISIDXREG(SISPART4,0x0d,backupP4_0d);
+    if(ivideo->vbflags & VB_301C) {
+       setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
+    } else {
+       orSISIDXREG(SISPART4,0x0d,0x04);
+    }
+    SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
+
+    inSISIDXREG(SISPART2,0x00,backupP2_00);
+    outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
+
+    inSISIDXREG(SISPART2,0x4d,backupP2_4d);
+    if(ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV|VB_302ELV)) {
+       outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
+    }
+
+    if(!(ivideo->vbflags & VB_301C)) {
+       SISDoSense(ivideo, 0, 0);
+    }
+
+    andSISIDXREG(SISCR, 0x32, ~0x14);
+
+    if(vga2_c || vga2) {
+       if(SISDoSense(ivideo, vga2, vga2_c)) {
+          if(biosflag & 0x01) {
+	     printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
+	     orSISIDXREG(SISCR, 0x32, 0x04);
+	  } else {
+	     printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
+	     orSISIDXREG(SISCR, 0x32, 0x10);
+	  }
+       }
+    }
+
+    andSISIDXREG(SISCR, 0x32, 0x3f);
+
+    if(ivideo->vbflags & VB_301C) {
+       orSISIDXREG(SISPART4,0x0d,0x04);
+    }
+
+    if((ivideo->sisvga_engine == SIS_315_VGA) &&
+       (ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV|VB_302ELV))) {
+       outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
+       SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
+       if((result = SISDoSense(ivideo, svhs, 0x0604))) {
+          if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
+	     printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
+	     orSISIDXREG(SISCR,0x32,0x80);
+	  }
+       }
+       outSISIDXREG(SISPART2,0x4d,backupP2_4d);
+    }
+
+    andSISIDXREG(SISCR, 0x32, ~0x03);
+
+    if(!(ivideo->vbflags & TV_YPBPR)) {
+       if((result = SISDoSense(ivideo, svhs, svhs_c))) {
+          printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
+          orSISIDXREG(SISCR, 0x32, 0x02);
+       }
+       if((biosflag & 0x02) || (!result)) {
+          if(SISDoSense(ivideo, cvbs, cvbs_c)) {
+	     printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
+	     orSISIDXREG(SISCR, 0x32, 0x01);
+          }
+       }
+    }
+
+    SISDoSense(ivideo, 0, 0);
+
+    outSISIDXREG(SISPART2,0x00,backupP2_00);
+    outSISIDXREG(SISPART4,0x0d,backupP4_0d);
+    outSISIDXREG(SISSR,0x1e,backupSR_1e);
+
+    if(ivideo->vbflags & VB_301C) {
+       inSISIDXREG(SISPART2,0x00,biosflag);
+       if(biosflag & 0x20) {
+          for(myflag = 2; myflag > 0; myflag--) {
+	     biosflag ^= 0x20;
+	     outSISIDXREG(SISPART2,0x00,biosflag);
+	  }
+       }
+    }
+
+    outSISIDXREG(SISPART2,0x00,backupP2_00);
+}
+
+/* Determine and detect attached TV's on Chrontel */
+static void __devinit SiS_SenseCh(struct sis_video_info *ivideo)
+{
+#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
+    u8 temp1, temp2;
+    char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
+#endif
+#ifdef CONFIG_FB_SIS_300
+    unsigned char test[3];
+    int i;
+#endif
+
+    if(ivideo->chip < SIS_315H) {
+
+#ifdef CONFIG_FB_SIS_300
+       ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1;		/* Chrontel 700x */
+       SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c);	/* Set general purpose IO for Chrontel communication */
+       SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
+       temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
+       /* See Chrontel TB31 for explanation */
+       temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
+       if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
+	  SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b0e);
+	  SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
+       }
+       temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
+       if(temp2 != temp1) temp1 = temp2;
+
+       if((temp1 >= 0x22) && (temp1 <= 0x50)) {
+	   /* Read power status */
+	   temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
+	   if((temp1 & 0x03) != 0x03) {
+     	        /* Power all outputs */
+		SiS_SetCH700x(&ivideo->SiS_Pr, 0x0B0E);
+		SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
+	   }
+	   /* Sense connected TV devices */
+	   for(i = 0; i < 3; i++) {
+	       SiS_SetCH700x(&ivideo->SiS_Pr, 0x0110);
+	       SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
+	       SiS_SetCH700x(&ivideo->SiS_Pr, 0x0010);
+	       SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
+	       temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
+	       if(!(temp1 & 0x08))       test[i] = 0x02;
+	       else if(!(temp1 & 0x02))  test[i] = 0x01;
+	       else                      test[i] = 0;
+	       SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
+	   }
+
+	   if(test[0] == test[1])      temp1 = test[0];
+	   else if(test[0] == test[2]) temp1 = test[0];
+	   else if(test[1] == test[2]) temp1 = test[1];
+	   else {
+	   	printk(KERN_INFO
+			"sisfb: TV detection unreliable - test results varied\n");
+		temp1 = test[2];
+	   }
+	   if(temp1 == 0x02) {
+		printk(KERN_INFO "%s SVIDEO output\n", stdstr);
+		ivideo->vbflags |= TV_SVIDEO;
+		orSISIDXREG(SISCR, 0x32, 0x02);
+		andSISIDXREG(SISCR, 0x32, ~0x05);
+	   } else if (temp1 == 0x01) {
+		printk(KERN_INFO "%s CVBS output\n", stdstr);
+		ivideo->vbflags |= TV_AVIDEO;
+		orSISIDXREG(SISCR, 0x32, 0x01);
+		andSISIDXREG(SISCR, 0x32, ~0x06);
+	   } else {
+ 		SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x010E,0xF8);
+		andSISIDXREG(SISCR, 0x32, ~0x07);
+	   }
+       } else if(temp1 == 0) {
+	  SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x010E,0xF8);
+	  andSISIDXREG(SISCR, 0x32, ~0x07);
+       }
+       /* Set general purpose IO for Chrontel communication */
+       SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
+#endif
+
+    } else {
+
+#ifdef CONFIG_FB_SIS_315
+	ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2;		/* Chrontel 7019 */
+        temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
+	SiS_SetCH701x(&ivideo->SiS_Pr, 0x2049);
+	SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
+	temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
+	temp2 |= 0x01;
+	SiS_SetCH701x(&ivideo->SiS_Pr, (temp2 << 8) | 0x20);
+	SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
+	temp2 ^= 0x01;
+	SiS_SetCH701x(&ivideo->SiS_Pr, (temp2 << 8) | 0x20);
+	SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
+	temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
+	SiS_SetCH701x(&ivideo->SiS_Pr, (temp1 << 8) | 0x49);
+        temp1 = 0;
+	if(temp2 & 0x02) temp1 |= 0x01;
+	if(temp2 & 0x10) temp1 |= 0x01;
+	if(temp2 & 0x04) temp1 |= 0x02;
+	if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
+	switch(temp1) {
+	case 0x01:
+	     printk(KERN_INFO "%s CVBS output\n", stdstr);
+	     ivideo->vbflags |= TV_AVIDEO;
+	     orSISIDXREG(SISCR, 0x32, 0x01);
+	     andSISIDXREG(SISCR, 0x32, ~0x06);
+             break;
+	case 0x02:
+	     printk(KERN_INFO "%s SVIDEO output\n", stdstr);
+	     ivideo->vbflags |= TV_SVIDEO;
+	     orSISIDXREG(SISCR, 0x32, 0x02);
+	     andSISIDXREG(SISCR, 0x32, ~0x05);
+             break;
+	case 0x04:
+	     printk(KERN_INFO "%s SCART output\n", stdstr);
+	     orSISIDXREG(SISCR, 0x32, 0x04);
+	     andSISIDXREG(SISCR, 0x32, ~0x03);
+             break;
+	default:
+	     andSISIDXREG(SISCR, 0x32, ~0x07);
+	}
+#endif
+    }
+}
+
+/* ------------------------ Heap routines -------------------------- */
+
+static u32 __devinit
+sisfb_getheapstart(struct sis_video_info *ivideo)
+{
+	u32 ret = ivideo->sisfb_parm_mem * 1024;
+	u32 max = ivideo->video_size - ivideo->hwcursor_size;
+	u32 def;
+
+	/* Calculate heap start = end of memory for console
+	 *
+	 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
+	 * C = console, D = heap, H = HWCursor, Q = cmd-queue
+	 *
+	 * Basically given by "mem" parameter
+	 *
+	 * maximum = videosize - cmd_queue - hwcursor
+	 *           (results in a heap of size 0)
+	 * default = SiS 300: depends on videosize
+	 *           SiS 315/330: 32k below max
+	 */
+
+	if(ivideo->sisvga_engine == SIS_300_VGA) {
+	   max -= TURBO_QUEUE_AREA_SIZE;
+	   if(ivideo->video_size > 0x1000000) {
+	      def = 0xc00000;
+	   } else if(ivideo->video_size > 0x800000) {
+	      def = 0x800000;
+	   } else {
+	      def = 0x400000;
+	   }
+	} else {
+	   max -= COMMAND_QUEUE_AREA_SIZE;
+	   def = max - 0x8000;
+	}
+
+        if((!ret) || (ret > max) || (ivideo->cardnumber != 0)) {
+	   ret = def;
+        }
+
+	return ret;
+}
+
+static int __devinit
+sisfb_heap_init(struct sis_video_info *ivideo)
+{
+     SIS_OH *poh;
+
+     ivideo->heapstart = ivideo->sisfb_mem = sisfb_getheapstart(ivideo);
+
+     ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
+     ivideo->sisfb_heap_end   = ivideo->video_vbase + ivideo->video_size;
+
+     /* Initialize command queue (We use MMIO only) */
+
+#ifdef CONFIG_FB_SIS_315
+     if(ivideo->sisvga_engine == SIS_315_VGA) {
+        u32 tempq = 0;
+	u8  temp = 0;
+
+        ivideo->sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
+
+	outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
+	outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
+
+	tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
+	MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
+
+	temp = SIS_CMD_QUEUE_SIZE_512k;
+	temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
+	outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
+
+	tempq = (u32)(ivideo->video_size - COMMAND_QUEUE_AREA_SIZE);
+	MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
+
+	ivideo->caps |= MMIO_CMD_QUEUE_CAP;
+     }
+#endif
+
+#ifdef CONFIG_FB_SIS_300
+     if(ivideo->sisvga_engine == SIS_300_VGA) {
+     	unsigned long tqueue_pos;
+	u8 tq_state;
+
+	ivideo->sisfb_heap_end -= TURBO_QUEUE_AREA_SIZE;
+
+	tqueue_pos = (ivideo->video_size - TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
+
+	inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
+	tq_state |= 0xf0;
+	tq_state &= 0xfc;
+	tq_state |= (u8)(tqueue_pos >> 8);
+	outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
+
+	outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
+
+	ivideo->caps |= TURBO_QUEUE_CAP;
+     }
+#endif
+
+     /* Reserve memory for the HWCursor */
+     ivideo->sisfb_heap_end -= ivideo->hwcursor_size;
+     ivideo->hwcursor_vbase = ivideo->sisfb_heap_end;
+     ivideo->caps |= HW_CURSOR_CAP;
+
+     ivideo->sisfb_heap_size = ivideo->sisfb_heap_end - ivideo->sisfb_heap_start;
+
+     if(ivideo->cardnumber == 0) {
+
+     	printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
+     		(int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
+
+	sisfb_heap.vinfo = ivideo;
+
+     	sisfb_heap.poha_chain = NULL;
+     	sisfb_heap.poh_freelist = NULL;
+
+     	poh = sisfb_poh_new_node();
+     	if(poh == NULL) return 1;
+
+     	poh->poh_next = &sisfb_heap.oh_free;
+     	poh->poh_prev = &sisfb_heap.oh_free;
+     	poh->size = ivideo->sisfb_heap_size;
+     	poh->offset = ivideo->heapstart;
+
+     	sisfb_heap.oh_free.poh_next = poh;
+     	sisfb_heap.oh_free.poh_prev = poh;
+     	sisfb_heap.oh_free.size = 0;
+     	sisfb_heap.max_freesize = poh->size;
+
+     	sisfb_heap.oh_used.poh_next = &sisfb_heap.oh_used;
+     	sisfb_heap.oh_used.poh_prev = &sisfb_heap.oh_used;
+     	sisfb_heap.oh_used.size = SENTINEL;
+
+     } else {
+
+        printk(KERN_INFO "Skipped heap initialization for secondary cards\n");
+
+     }
+
+     return 0;
+}
+
+static SIS_OH *
+sisfb_poh_new_node(void)
+{
+	int           i;
+	unsigned long cOhs;
+	SIS_OHALLOC   *poha;
+	SIS_OH        *poh;
+
+	if(sisfb_heap.poh_freelist == NULL) {
+		poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
+		if(!poha) return NULL;
+
+		poha->poha_next = sisfb_heap.poha_chain;
+		sisfb_heap.poha_chain = poha;
+
+		cOhs = (SIS_OH_ALLOC_SIZE - sizeof(SIS_OHALLOC)) / sizeof(SIS_OH) + 1;
+
+		poh = &poha->aoh[0];
+		for(i = cOhs - 1; i != 0; i--) {
+			poh->poh_next = poh + 1;
+			poh = poh + 1;
+		}
+
+		poh->poh_next = NULL;
+		sisfb_heap.poh_freelist = &poha->aoh[0];
+	}
+
+	poh = sisfb_heap.poh_freelist;
+	sisfb_heap.poh_freelist = poh->poh_next;
+
+	return (poh);
+}
+
+static SIS_OH *
+sisfb_poh_allocate(u32 size)
+{
+	SIS_OH *pohThis;
+	SIS_OH *pohRoot;
+	int     bAllocated = 0;
+
+	if(size > sisfb_heap.max_freesize) {
+		DPRINTK("sisfb: Can't allocate %dk video memory\n",
+			(unsigned int) size / 1024);
+		return (NULL);
+	}
+
+	pohThis = sisfb_heap.oh_free.poh_next;
+
+	while(pohThis != &sisfb_heap.oh_free) {
+		if (size <= pohThis->size) {
+			bAllocated = 1;
+			break;
+		}
+		pohThis = pohThis->poh_next;
+	}
+
+	if(!bAllocated) {
+		DPRINTK("sisfb: Can't allocate %dk video memory\n",
+			(unsigned int) size / 1024);
+		return (NULL);
+	}
+
+	if(size == pohThis->size) {
+		pohRoot = pohThis;
+		sisfb_delete_node(pohThis);
+	} else {
+		pohRoot = sisfb_poh_new_node();
+
+		if(pohRoot == NULL) {
+			return (NULL);
+		}
+
+		pohRoot->offset = pohThis->offset;
+		pohRoot->size = size;
+
+		pohThis->offset += size;
+		pohThis->size -= size;
+	}
+
+	sisfb_heap.max_freesize -= size;
+
+	pohThis = &sisfb_heap.oh_used;
+	sisfb_insert_node(pohThis, pohRoot);
+
+	return (pohRoot);
+}
+
+static void
+sisfb_delete_node(SIS_OH *poh)
+{
+	SIS_OH *poh_prev;
+	SIS_OH *poh_next;
+
+	poh_prev = poh->poh_prev;
+	poh_next = poh->poh_next;
+
+	poh_prev->poh_next = poh_next;
+	poh_next->poh_prev = poh_prev;
+}
+
+static void
+sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh)
+{
+	SIS_OH *pohTemp;
+
+	pohTemp = pohList->poh_next;
+
+	pohList->poh_next = poh;
+	pohTemp->poh_prev = poh;
+
+	poh->poh_prev = pohList;
+	poh->poh_next = pohTemp;
+}
+
+static SIS_OH *
+sisfb_poh_free(u32 base)
+{
+	SIS_OH *pohThis;
+	SIS_OH *poh_freed;
+	SIS_OH *poh_prev;
+	SIS_OH *poh_next;
+	u32     ulUpper;
+	u32     ulLower;
+	int     foundNode = 0;
+
+	poh_freed = sisfb_heap.oh_used.poh_next;
+
+	while(poh_freed != &sisfb_heap.oh_used) {
+		if(poh_freed->offset == base) {
+			foundNode = 1;
+			break;
+		}
+
+		poh_freed = poh_freed->poh_next;
+	}
+
+	if(!foundNode) return(NULL);
+
+	sisfb_heap.max_freesize += poh_freed->size;
+
+	poh_prev = poh_next = NULL;
+	ulUpper = poh_freed->offset + poh_freed->size;
+	ulLower = poh_freed->offset;
+
+	pohThis = sisfb_heap.oh_free.poh_next;
+
+	while(pohThis != &sisfb_heap.oh_free) {
+		if(pohThis->offset == ulUpper) {
+			poh_next = pohThis;
+		} else if((pohThis->offset + pohThis->size) == ulLower) {
+			poh_prev = pohThis;
+		}
+		pohThis = pohThis->poh_next;
+	}
+
+	sisfb_delete_node(poh_freed);
+
+	if(poh_prev && poh_next) {
+		poh_prev->size += (poh_freed->size + poh_next->size);
+		sisfb_delete_node(poh_next);
+		sisfb_free_node(poh_freed);
+		sisfb_free_node(poh_next);
+		return(poh_prev);
+	}
+
+	if(poh_prev) {
+		poh_prev->size += poh_freed->size;
+		sisfb_free_node(poh_freed);
+		return(poh_prev);
+	}
+
+	if(poh_next) {
+		poh_next->size += poh_freed->size;
+		poh_next->offset = poh_freed->offset;
+		sisfb_free_node(poh_freed);
+		return(poh_next);
+	}
+
+	sisfb_insert_node(&sisfb_heap.oh_free, poh_freed);
+
+	return(poh_freed);
+}
+
+static void
+sisfb_free_node(SIS_OH *poh)
+{
+	if(poh == NULL) return;
+
+	poh->poh_next = sisfb_heap.poh_freelist;
+	sisfb_heap.poh_freelist = poh;
+}
+
+void
+sis_malloc(struct sis_memreq *req)
+{
+	struct sis_video_info *ivideo = sisfb_heap.vinfo;
+	SIS_OH *poh = NULL;
+
+	if((ivideo) && (!ivideo->havenoheap)) {
+	   poh = sisfb_poh_allocate((u32)req->size);
+	}
+
+	if(poh == NULL) {
+	   req->offset = req->size = 0;
+	   DPRINTK("sisfb: Video RAM allocation failed\n");
+	} else {
+	   req->offset = poh->offset;
+	   req->size = poh->size;
+	   DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
+	   	    (poh->offset + ivideo->video_vbase));
+	}
+}
+
+/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
+
+void
+sis_free(u32 base)
+{
+	struct sis_video_info *ivideo = sisfb_heap.vinfo;
+	SIS_OH *poh;
+
+	if((!ivideo) || (ivideo->havenoheap)) return;
+
+	poh = sisfb_poh_free((u32)base);
+
+	if(poh == NULL) {
+		DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
+			(unsigned int) base);
+	}
+}
+
+/* --------------------- SetMode routines ------------------------- */
+
+static void
+sisfb_pre_setmode(struct sis_video_info *ivideo)
+{
+	u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
+	int tvregnum = 0;
+
+	ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
+
+	inSISIDXREG(SISCR, 0x31, cr31);
+	cr31 &= ~0x60;
+	cr31 |= 0x04;
+
+	cr33 = ivideo->rate_idx & 0x0F;
+
+#ifdef CONFIG_FB_SIS_315
+	if(ivideo->sisvga_engine == SIS_315_VGA) {
+	   if(ivideo->chip >= SIS_661) {
+	      inSISIDXREG(SISCR, 0x38, cr38);
+	      cr38 &= ~0x07;  /* Clear LCDA/DualEdge and YPbPr bits */
+	   } else {
+	      tvregnum = 0x38;
+	      inSISIDXREG(SISCR, tvregnum, cr38);
+	      cr38 &= ~0x3b;  /* Clear LCDA/DualEdge and YPbPr bits */
+	   }
+	}
+#endif
+#ifdef CONFIG_FB_SIS_300
+	if(ivideo->sisvga_engine == SIS_300_VGA) {
+	   tvregnum = 0x35;
+	   inSISIDXREG(SISCR, tvregnum, cr38);
+	}
+#endif
+
+	SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
+	SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
+
+	switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
+
+	   case CRT2_TV:
+	      cr38 &= ~0xc0;   /* Clear PAL-M / PAL-N bits */
+	      if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV))) {
+#ifdef CONFIG_FB_SIS_315
+	         if(ivideo->chip >= SIS_661) {
+	            cr38 |= 0x04;
+	            if(ivideo->vbflags & TV_YPBPR525P)       cr35 |= 0x20;
+		    else if(ivideo->vbflags & TV_YPBPR750P)  cr35 |= 0x40;
+		    else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
+		    cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
+		    cr35 &= ~0x01;
+		    ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
+	         } else if(ivideo->sisvga_engine == SIS_315_VGA) {
+	            cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
+		    cr38 |= 0x08;
+	            if(ivideo->vbflags & TV_YPBPR525P)       cr38 |= 0x10;
+		    else if(ivideo->vbflags & TV_YPBPR750P)  cr38 |= 0x20;
+		    else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
+		    cr31 &= ~0x01;
+		    ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
+	         }
+#endif
+	      } else if((ivideo->vbflags & TV_HIVISION) && (ivideo->vbflags & (VB_301|VB_301B|VB_302B))) {
+	         if(ivideo->chip >= SIS_661) {
+	            cr38 |= 0x04;
+	            cr35 |= 0x60;
+	         } else {
+	            cr30 |= 0x80;
+	         }
+		 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
+	         cr31 |= 0x01;
+	         cr35 |= 0x01;
+		 ivideo->currentvbflags |= TV_HIVISION;
+	      } else if(ivideo->vbflags & TV_SCART) {
+		 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
+		 cr31 |= 0x01;
+		 cr35 |= 0x01;
+		 ivideo->currentvbflags |= TV_SCART;
+	      } else {
+		 if(ivideo->vbflags & TV_SVIDEO) {
+		    cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
+		    ivideo->currentvbflags |= TV_SVIDEO;
+		 }
+		 if(ivideo->vbflags & TV_AVIDEO) {
+		    cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
+		    ivideo->currentvbflags |= TV_AVIDEO;
+		 }
+	      }
+	      cr31 |= SIS_DRIVER_MODE;
+
+	      if(ivideo->vbflags & (TV_AVIDEO|TV_SVIDEO)) {
+	         if(ivideo->vbflags & TV_PAL) {
+		    cr31 |= 0x01; cr35 |= 0x01;
+		    ivideo->currentvbflags |= TV_PAL;
+		    if(ivideo->vbflags & TV_PALM) {
+		       cr38 |= 0x40; cr35 |= 0x04;
+		       ivideo->currentvbflags |= TV_PALM;
+		    } else if(ivideo->vbflags & TV_PALN) {
+		       cr38 |= 0x80; cr35 |= 0x08;
+		       ivideo->currentvbflags |= TV_PALN;
+	  	    }
+                 } else {
+		    cr31 &= ~0x01; cr35 &= ~0x01;
+		    ivideo->currentvbflags |= TV_NTSC;
+		    if(ivideo->vbflags & TV_NTSCJ) {
+		       cr38 |= 0x40; cr35 |= 0x02;
+		       ivideo->currentvbflags |= TV_NTSCJ;
+	 	    }
+		 }
+	      }
+	      break;
+
+	   case CRT2_LCD:
+	      cr30  = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
+	      cr31 |= SIS_DRIVER_MODE;
+	      SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
+	      SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
+	      break;
+
+	   case CRT2_VGA:
+	      cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
+	      cr31 |= SIS_DRIVER_MODE;
+	      if(ivideo->sisfb_nocrt2rate) {
+		 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
+	      } else {
+		 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
+	      }
+	      break;
+
+	   default:	/* disable CRT2 */
+	      cr30 = 0x00;
+	      cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
+	}
+
+	outSISIDXREG(SISCR, 0x30, cr30);
+	outSISIDXREG(SISCR, 0x33, cr33);
+
+	if(ivideo->chip >= SIS_661) {
+#ifdef CONFIG_FB_SIS_315
+	   cr31 &= ~0x01;                          /* Clear PAL flag (now in CR35) */
+	   setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
+	   cr38 &= 0x07;                           /* Use only LCDA and HiVision/YPbPr bits */
+	   setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
+#endif
+	} else if(ivideo->chip != SIS_300) {
+	   outSISIDXREG(SISCR, tvregnum, cr38);
+	}
+	outSISIDXREG(SISCR, 0x31, cr31);
+
+	if(ivideo->accel) sisfb_syncaccel(ivideo);
+
+	ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
+}
+
+/* Fix SR11 for 661 and later */
+#ifdef CONFIG_FB_SIS_315
+static void
+sisfb_fixup_SR11(struct sis_video_info *ivideo)
+{
+    u8  tmpreg;
+
+    if(ivideo->chip >= SIS_661) {
+       inSISIDXREG(SISSR,0x11,tmpreg);
+       if(tmpreg & 0x20) {
+          inSISIDXREG(SISSR,0x3e,tmpreg);
+	  tmpreg = (tmpreg + 1) & 0xff;
+	  outSISIDXREG(SISSR,0x3e,tmpreg);
+	  inSISIDXREG(SISSR,0x11,tmpreg);
+       }
+       if(tmpreg & 0xf0) {
+          andSISIDXREG(SISSR,0x11,0x0f);
+       }
+    }
+}
+#endif
+
+static void sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
+{
+   if(val > 32) val = 32;
+   if(val < -32) val = -32;
+   ivideo->tvxpos = val;
+
+   if(ivideo->sisfblocked) return;
+   if(!ivideo->modechanged) return;
+
+   if(ivideo->currentvbflags & CRT2_TV) {
+
+      if(ivideo->vbflags & VB_CHRONTEL) {
+
+	 int x = ivideo->tvx;
+
+	 switch(ivideo->chronteltype) {
+	 case 1:
+	     x += val;
+	     if(x < 0) x = 0;
+	     outSISIDXREG(SISSR,0x05,0x86);
+	     SiS_SetCH700x(&ivideo->SiS_Pr, (((x & 0xff) << 8) | 0x0a));
+	     SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, (((x & 0x0100) << 1) | 0x08),0xFD);
+	     break;
+	 case 2:
+	     /* Not supported by hardware */
+	     break;
+	 }
+
+      } else if(ivideo->vbflags & VB_SISBRIDGE) {
+
+	 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
+	 unsigned short temp;
+
+	 p2_1f = ivideo->p2_1f;
+	 p2_20 = ivideo->p2_20;
+	 p2_2b = ivideo->p2_2b;
+	 p2_42 = ivideo->p2_42;
+	 p2_43 = ivideo->p2_43;
+
+	 temp = p2_1f | ((p2_20 & 0xf0) << 4);
+	 temp += (val * 2);
+	 p2_1f = temp & 0xff;
+	 p2_20 = (temp & 0xf00) >> 4;
+	 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
+	 temp = p2_43 | ((p2_42 & 0xf0) << 4);
+	 temp += (val * 2);
+	 p2_43 = temp & 0xff;
+	 p2_42 = (temp & 0xf00) >> 4;
+	 outSISIDXREG(SISPART2,0x1f,p2_1f);
+	 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
+	 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
+	 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
+	 outSISIDXREG(SISPART2,0x43,p2_43);
+      }
+   }
+}
+
+static void sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
+{
+   if(val > 32) val = 32;
+   if(val < -32) val = -32;
+   ivideo->tvypos = val;
+
+   if(ivideo->sisfblocked) return;
+   if(!ivideo->modechanged) return;
+
+   if(ivideo->currentvbflags & CRT2_TV) {
+
+      if(ivideo->vbflags & VB_CHRONTEL) {
+
+	 int y = ivideo->tvy;
+
+	 switch(ivideo->chronteltype) {
+	 case 1:
+	    y -= val;
+	    if(y < 0) y = 0;
+	    outSISIDXREG(SISSR,0x05,0x86);
+	    SiS_SetCH700x(&ivideo->SiS_Pr, (((y & 0xff) << 8) | 0x0b));
+	    SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, ((y & 0x0100) | 0x08),0xFE);
+	    break;
+	 case 2:
+	    /* Not supported by hardware */
+	    break;
+	 }
+
+      } else if(ivideo->vbflags & VB_SISBRIDGE) {
+
+	 char p2_01, p2_02;
+	 val /= 2;
+	 p2_01 = ivideo->p2_01;
+	 p2_02 = ivideo->p2_02;
+
+	 p2_01 += val;
+	 p2_02 += val;
+	 while((p2_01 <= 0) || (p2_02 <= 0)) {
+	    p2_01 += 2;
+	    p2_02 += 2;
+	 }
+	 outSISIDXREG(SISPART2,0x01,p2_01);
+	 outSISIDXREG(SISPART2,0x02,p2_02);
+      }
+   }
+}
+
+static void
+sisfb_post_setmode(struct sis_video_info *ivideo)
+{
+	BOOLEAN crt1isoff = FALSE;
+	BOOLEAN doit = TRUE;
+#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
+	u8 reg;
+#endif
+#ifdef CONFIG_FB_SIS_315
+	u8 reg1;
+#endif
+
+	outSISIDXREG(SISSR,0x05,0x86);
+
+#ifdef CONFIG_FB_SIS_315
+	sisfb_fixup_SR11(ivideo);
+#endif
+
+	/* Now we actually HAVE changed the display mode */
+        ivideo->modechanged = 1;
+
+	/* We can't switch off CRT1 if bridge is in slave mode */
+	if(ivideo->vbflags & VB_VIDEOBRIDGE) {
+		if(sisfb_bridgeisslave(ivideo)) doit = FALSE;
+	} else ivideo->sisfb_crt1off = 0;
+
+#ifdef CONFIG_FB_SIS_300
+	if(ivideo->sisvga_engine == SIS_300_VGA) {
+	   if((ivideo->sisfb_crt1off) && (doit)) {
+	        crt1isoff = TRUE;
+		reg = 0x00;
+	   } else {
+	        crt1isoff = FALSE;
+		reg = 0x80;
+	   }
+	   setSISIDXREG(SISCR, 0x17, 0x7f, reg);
+	}
+#endif
+#ifdef CONFIG_FB_SIS_315
+	if(ivideo->sisvga_engine == SIS_315_VGA) {
+	   if((ivideo->sisfb_crt1off) && (doit)) {
+	        crt1isoff = TRUE;
+		reg  = 0x40;
+		reg1 = 0xc0;
+	   } else {
+	        crt1isoff = FALSE;
+		reg  = 0x00;
+		reg1 = 0x00;
+
+	   }
+	   setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
+	   setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
+	}
+#endif
+
+	if(crt1isoff) {
+	   ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
+	   ivideo->currentvbflags |= VB_SINGLE_MODE;
+	} else {
+	   ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
+	   if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
+	  	ivideo->currentvbflags |= VB_MIRROR_MODE;
+	   } else {
+	 	ivideo->currentvbflags |= VB_SINGLE_MODE;
+	   }
+	}
+
+        andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
+
+	if(ivideo->currentvbflags & CRT2_TV) {
+	   if(ivideo->vbflags & VB_SISBRIDGE) {
+	      inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
+	      inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
+	      inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
+	      inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
+	      inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
+	      inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
+	      inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
+	   } else if(ivideo->vbflags & VB_CHRONTEL) {
+	      if(ivideo->chronteltype == 1) {
+	         ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
+	         ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
+	         ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
+	         ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
+ 	      }
+	   }
+	}
+
+	if(ivideo->tvxpos) {
+   	   sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
+	}
+	if(ivideo->tvypos) {
+   	   sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
+	}
+
+	if((ivideo->currentvbflags & CRT2_TV) && (ivideo->vbflags & VB_301)) {  /* Set filter for SiS301 */
+
+	   	unsigned char filter_tb = 0;
+
+		switch (ivideo->video_width) {
+		   case 320:
+			filter_tb = (ivideo->vbflags & TV_NTSC) ? 4 : 12;
+			break;
+		   case 640:
+			filter_tb = (ivideo->vbflags & TV_NTSC) ? 5 : 13;
+			break;
+		   case 720:
+			filter_tb = (ivideo->vbflags & TV_NTSC) ? 6 : 14;
+			break;
+		   case 400:
+		   case 800:
+			filter_tb = (ivideo->vbflags & TV_NTSC) ? 7 : 15;
+			break;
+		   default:
+			ivideo->sisfb_filter = -1;
+			break;
+		}
+
+		orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
+
+		if(ivideo->vbflags & TV_NTSC) {
+
+		        andSISIDXREG(SISPART2, 0x3a, 0x1f);
+
+			if (ivideo->vbflags & TV_SVIDEO) {
+
+			        andSISIDXREG(SISPART2, 0x30, 0xdf);
+
+			} else if (ivideo->vbflags & TV_AVIDEO) {
+
+			        orSISIDXREG(SISPART2, 0x30, 0x20);
+
+				switch (ivideo->video_width) {
+				case 640:
+				        outSISIDXREG(SISPART2, 0x35, 0xEB);
+					outSISIDXREG(SISPART2, 0x36, 0x04);
+					outSISIDXREG(SISPART2, 0x37, 0x25);
+					outSISIDXREG(SISPART2, 0x38, 0x18);
+					break;
+				case 720:
+					outSISIDXREG(SISPART2, 0x35, 0xEE);
+					outSISIDXREG(SISPART2, 0x36, 0x0C);
+					outSISIDXREG(SISPART2, 0x37, 0x22);
+					outSISIDXREG(SISPART2, 0x38, 0x08);
+					break;
+				case 400:
+				case 800:
+					outSISIDXREG(SISPART2, 0x35, 0xEB);
+					outSISIDXREG(SISPART2, 0x36, 0x15);
+					outSISIDXREG(SISPART2, 0x37, 0x25);
+					outSISIDXREG(SISPART2, 0x38, 0xF6);
+					break;
+				}
+			}
+
+		} else if(ivideo->vbflags & TV_PAL) {
+
+			andSISIDXREG(SISPART2, 0x3A, 0x1F);
+
+			if (ivideo->vbflags & TV_SVIDEO) {
+
+			        andSISIDXREG(SISPART2, 0x30, 0xDF);
+
+			} else if (ivideo->vbflags & TV_AVIDEO) {
+
+			        orSISIDXREG(SISPART2, 0x30, 0x20);
+
+				switch (ivideo->video_width) {
+				case 640:
+					outSISIDXREG(SISPART2, 0x35, 0xF1);
+					outSISIDXREG(SISPART2, 0x36, 0xF7);
+					outSISIDXREG(SISPART2, 0x37, 0x1F);
+					outSISIDXREG(SISPART2, 0x38, 0x32);
+					break;
+				case 720:
+					outSISIDXREG(SISPART2, 0x35, 0xF3);
+					outSISIDXREG(SISPART2, 0x36, 0x00);
+					outSISIDXREG(SISPART2, 0x37, 0x1D);
+					outSISIDXREG(SISPART2, 0x38, 0x20);
+					break;
+				case 400:
+				case 800:
+					outSISIDXREG(SISPART2, 0x35, 0xFC);
+					outSISIDXREG(SISPART2, 0x36, 0xFB);
+					outSISIDXREG(SISPART2, 0x37, 0x14);
+					outSISIDXREG(SISPART2, 0x38, 0x2A);
+					break;
+				}
+			}
+		}
+
+		if((ivideo->sisfb_filter >= 0) && (ivideo->sisfb_filter <= 7)) {
+		   outSISIDXREG(SISPART2,0x35,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][0]));
+		   outSISIDXREG(SISPART2,0x36,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][1]));
+		   outSISIDXREG(SISPART2,0x37,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][2]));
+		   outSISIDXREG(SISPART2,0x38,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][3]));
+		}
+	  
+	}
+}
+
+#ifndef MODULE
+SISINITSTATIC int __init sisfb_setup(char *options)
+{
+	char *this_opt;
+	
+	sisfb_setdefaultparms();
+
+        printk(KERN_DEBUG "sisfb: Options %s\n", options);
+
+	if(!options || !(*options)) {
+		return 0;
+	}
+
+	while((this_opt = strsep(&options, ",")) != NULL) {
+
+		if(!(*this_opt)) continue;
+
+		if(!strnicmp(this_opt, "off", 3)) {
+			sisfb_off = 1;
+		} else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
+			/* Need to check crt2 type first for fstn/dstn */
+			sisfb_search_crt2type(this_opt + 14);
+		} else if(!strnicmp(this_opt, "tvmode:",7)) {
+		        sisfb_search_tvstd(this_opt + 7);
+                } else if(!strnicmp(this_opt, "tvstandard:",11)) {
+			sisfb_search_tvstd(this_opt + 7);
+		} else if(!strnicmp(this_opt, "mode:", 5)) {
+			sisfb_search_mode(this_opt + 5, FALSE);
+		} else if(!strnicmp(this_opt, "vesa:", 5)) {
+			sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+		} else if(!strnicmp(this_opt, "inverse", 7)) {
+			sisfb_inverse = 1;
+			/* fb_invert_cmaps(); */
+		} else if(!strnicmp(this_opt, "font:", 5)) {
+		        if(strlen(this_opt + 5) < 40) {
+			   strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
+			   sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
+			}
+#endif
+		} else if(!strnicmp(this_opt, "rate:", 5)) {
+			sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
+		} else if(!strnicmp(this_opt, "filter:", 7)) {
+			sisfb_filter = (int)simple_strtoul(this_opt + 7, NULL, 0);
+		} else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
+			sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
+                } else if(!strnicmp(this_opt, "mem:",4)) {
+		        sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
+		} else if(!strnicmp(this_opt, "pdc:", 4)) {
+		        sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
+		} else if(!strnicmp(this_opt, "pdc1:", 5)) {
+		        sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
+		} else if(!strnicmp(this_opt, "noaccel", 7)) {
+			sisfb_accel = 0;
+		} else if(!strnicmp(this_opt, "accel", 5)) {
+			sisfb_accel = -1;
+		} else if(!strnicmp(this_opt, "noypan", 6)) {
+		        sisfb_ypan = 0;
+		} else if(!strnicmp(this_opt, "ypan", 4)) {
+		        sisfb_ypan = -1;
+		} else if(!strnicmp(this_opt, "nomax", 5)) {
+		        sisfb_max = 0;
+		} else if(!strnicmp(this_opt, "max", 3)) {
+		        sisfb_max = -1;
+		} else if(!strnicmp(this_opt, "userom:", 7)) {
+			sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
+		} else if(!strnicmp(this_opt, "useoem:", 7)) {
+			sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
+		} else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
+			sisfb_nocrt2rate = 1;
+	 	} else if(!strnicmp(this_opt, "scalelcd:", 9)) {
+		        unsigned long temp = 2;
+		        temp = simple_strtoul(this_opt + 9, NULL, 0);
+		        if((temp == 0) || (temp == 1)) {
+			   sisfb_scalelcd = temp ^ 1;
+		        }
+		} else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
+		        int temp = 0;
+		        temp = (int)simple_strtol(this_opt + 13, NULL, 0);
+		        if((temp >= -32) && (temp <= 32)) {
+			   sisfb_tvxposoffset = temp;
+		        }
+		} else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
+		        int temp = 0;
+		        temp = (int)simple_strtol(this_opt + 13, NULL, 0);
+		        if((temp >= -32) && (temp <= 32)) {
+			   sisfb_tvyposoffset = temp;
+		        }
+		} else if(!strnicmp(this_opt, "specialtiming:", 14)) {
+			sisfb_search_specialtiming(this_opt + 14);
+		} else if(!strnicmp(this_opt, "lvdshl:", 7)) {
+		        int temp = 4;
+		        temp = simple_strtoul(this_opt + 7, NULL, 0);
+		        if((temp >= 0) && (temp <= 3)) {
+			   sisfb_lvdshl = temp;
+		        }
+		} else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
+			sisfb_search_mode(this_opt, TRUE);
+#if !defined(__i386__) && !defined(__x86_64__)
+	        } else if(!strnicmp(this_opt, "resetcard", 9)) {
+		  	sisfb_resetcard = 1;
+	        } else if(!strnicmp(this_opt, "videoram:", 9)) {
+		  	sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
+#endif
+		} else {
+			printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
+		}
+
+	}
+
+
+
+	return 0;
+}
+#endif
+
+static UCHAR * __devinit sis_find_rom(struct pci_dev *pdev)
+{
+	struct sis_video_info *ivideo = pci_get_drvdata(pdev);
+	USHORT pciid;
+	int    romptr;
+	UCHAR  *myrombase;
+	u32    temp;
+	SIS_IOTYPE1 *rom_base, *rom;
+
+	if(!(myrombase = vmalloc(65536))) return NULL;
+
+#if defined(__i386__) || defined(__x86_64__)
+
+        for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
+
+            rom_base = ioremap(temp, 0x10000);
+	    if(!rom_base) continue;
+
+	    if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa)) {
+	       iounmap(rom_base);
+               continue;
+	    }
+
+	    romptr = (unsigned short)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
+	    if(romptr > (0x10000 - 8)) {
+	       iounmap(rom_base);
+	       continue;
+	    }
+
+	    rom = rom_base + romptr;
+
+	    if((readb(rom)     != 'P') || (readb(rom + 1) != 'C') ||
+	       (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R')) {
+	       iounmap(rom_base);
+	       continue;
+	    }
+
+	    pciid = readb(rom + 4) | (readb(rom + 5) << 8);
+	    if(pciid != 0x1039) {
+	       iounmap(rom_base);
+	       continue;
+	    }
+
+	    pciid = readb(rom + 6) | (readb(rom + 7) << 8);
+	    if(pciid == ivideo->chip_id) {
+	       memcpy_fromio(myrombase, rom_base, 65536);
+	       iounmap(rom_base);
+	       return myrombase;
+	    }
+
+	    iounmap(rom_base);
+        }
+
+#else
+
+	pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
+	pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
+			(ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
+
+	rom_base = ioremap(ivideo->video_base, 65536);
+	if(rom_base) {
+	   if((readb(rom_base) == 0x55) && (readb(rom_base + 1) == 0xaa)) {
+	      romptr = (u16)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
+	      if(romptr <= (0x10000 - 8)) {
+	         rom = rom_base + romptr;
+		 if((readb(rom)     == 'P') && (readb(rom + 1) == 'C') &&
+		    (readb(rom + 2) == 'I') && (readb(rom + 3) == 'R')) {
+		    pciid = readb(rom + 4) | (readb(rom + 5) << 8);
+		    if(pciid == 0x1039) {
+		       pciid = readb(rom + 6) | (readb(rom + 7) << 8);
+		       if(pciid == ivideo->chip_id) {
+			  memcpy_fromio(myrombase, rom_base, 65536);
+			  iounmap(rom_base);
+			  pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
+			  return myrombase;
+		       }
+		    }
+		 }
+	      }
+	   }
+	   iounmap(rom_base);
+	}
+        pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
+
+#endif
+
+       	vfree(myrombase);
+        return NULL;
+}
+
+#ifdef CONFIG_FB_SIS_300
+static int __devinit
+sisfb_chkbuswidth300(struct pci_dev *pdev, SIS_IOTYPE1 *FBAddress)
+{
+	struct sis_video_info *ivideo = pci_get_drvdata(pdev);
+	int i, j;
+	USHORT temp;
+	UCHAR reg;
+
+	andSISIDXREG(SISSR,0x15,0xFB);
+	orSISIDXREG(SISSR,0x15,0x04);
+   	outSISIDXREG(SISSR,0x13,0x00);
+   	outSISIDXREG(SISSR,0x14,0xBF);
+
+	for(i=0; i<2; i++) {
+	   temp = 0x1234;
+	   for(j=0; j<4; j++) {
+	      writew(temp, FBAddress);
+	      if(readw(FBAddress) == temp) break;
+	      orSISIDXREG(SISSR,0x3c,0x01);
+	      inSISIDXREG(SISSR,0x05,reg);
+	      inSISIDXREG(SISSR,0x05,reg);
+	      andSISIDXREG(SISSR,0x3c,0xfe);
+	      inSISIDXREG(SISSR,0x05,reg);
+	      inSISIDXREG(SISSR,0x05,reg);
+	      temp++;
+	   }
+	}
+
+	writel(0x01234567L, FBAddress);
+	writel(0x456789ABL, (FBAddress+4));
+	writel(0x89ABCDEFL, (FBAddress+8));
+	writel(0xCDEF0123L, (FBAddress+12));
+	inSISIDXREG(SISSR,0x3b,reg);
+	if(reg & 0x01) {
+	   if(readl((FBAddress+12)) == 0xCDEF0123L) return(4);  /* Channel A 128bit */
+	}
+	if(readl((FBAddress+4)) == 0x456789ABL)     return(2);  /* Channel B 64bit */
+	return(1);						/* 32bit */
+}
+
+static void __devinit
+sisfb_setramsize300(struct pci_dev *pdev)
+{
+	struct  sis_video_info *ivideo = pci_get_drvdata(pdev);
+  	SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
+	SIS_IOTYPE1 *Addr;
+	USHORT 	sr13, sr14=0, buswidth, Done, data, TotalCapacity, PhysicalAdrOtherPage=0;
+	int     PseudoRankCapacity, PseudoTotalCapacity, PseudoAdrPinCount;
+   	int     RankCapacity, AdrPinCount, BankNumHigh, BankNumMid, MB2Bank;
+   	int     PageCapacity, PhysicalAdrHigh, PhysicalAdrHalfPage, i, j, k;
+	const 	USHORT SiS_DRAMType[17][5] = {
+			{0x0C,0x0A,0x02,0x40,0x39},
+			{0x0D,0x0A,0x01,0x40,0x48},
+			{0x0C,0x09,0x02,0x20,0x35},
+			{0x0D,0x09,0x01,0x20,0x44},
+			{0x0C,0x08,0x02,0x10,0x31},
+			{0x0D,0x08,0x01,0x10,0x40},
+			{0x0C,0x0A,0x01,0x20,0x34},
+			{0x0C,0x09,0x01,0x08,0x32},
+			{0x0B,0x08,0x02,0x08,0x21},
+			{0x0C,0x08,0x01,0x08,0x30},
+			{0x0A,0x08,0x02,0x04,0x11},
+			{0x0B,0x0A,0x01,0x10,0x28},
+			{0x09,0x08,0x02,0x02,0x01},
+			{0x0B,0x09,0x01,0x08,0x24},
+			{0x0B,0x08,0x01,0x04,0x20},
+			{0x0A,0x08,0x01,0x02,0x10},
+			{0x09,0x08,0x01,0x01,0x00}
+		};
+
+        buswidth = sisfb_chkbuswidth300(pdev, FBAddr);
+
+   	MB2Bank = 16;
+   	Done = 0;
+   	for(i = 6; i >= 0; i--) {
+      	   if(Done) break;
+      	   PseudoRankCapacity = 1 << i;
+      	   for(j = 4; j >= 1; j--) {
+              if(Done) break;
+              PseudoTotalCapacity = PseudoRankCapacity * j;
+              PseudoAdrPinCount = 15 - j;
+              if(PseudoTotalCapacity <= 64) {
+                 for(k = 0; k <= 16; k++) {
+                    if(Done) break;
+                    RankCapacity = buswidth * SiS_DRAMType[k][3];
+                    AdrPinCount = SiS_DRAMType[k][2] + SiS_DRAMType[k][0];
+                    if(RankCapacity == PseudoRankCapacity)
+                       if(AdrPinCount <= PseudoAdrPinCount) {
+                          if(j == 3) {             /* Rank No */
+                             BankNumHigh = RankCapacity * MB2Bank * 3 - 1;
+                             BankNumMid  = RankCapacity * MB2Bank * 1 - 1;
+                          } else {
+                             BankNumHigh = RankCapacity * MB2Bank * j - 1;
+                             BankNumMid  = RankCapacity * MB2Bank * j / 2 - 1;
+                          }
+                          PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
+                          PhysicalAdrHigh = BankNumHigh;
+                          PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
+                          PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
+                          /* Write data */
+                          andSISIDXREG(SISSR,0x15,0xFB); /* Test */
+                          orSISIDXREG(SISSR,0x15,0x04);  /* Test */
+                          TotalCapacity = SiS_DRAMType[k][3] * buswidth;
+                          sr13 = SiS_DRAMType[k][4];
+                          if(buswidth == 4) sr14 = (TotalCapacity - 1) | 0x80;
+                          if(buswidth == 2) sr14 = (TotalCapacity - 1) | 0x40;
+                          if(buswidth == 1) sr14 = (TotalCapacity - 1) | 0x00;
+                          outSISIDXREG(SISSR,0x13,sr13);
+                          outSISIDXREG(SISSR,0x14,sr14);
+                          Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh;
+                          /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHigh; */
+			  writew(((USHORT)PhysicalAdrHigh), Addr);
+                          Addr = FBAddr + BankNumMid * 64 * 1024 + PhysicalAdrHigh;
+                          /* *((USHORT *)(Addr)) = (USHORT)BankNumMid; */
+			  writew(((USHORT)BankNumMid), Addr);
+                          Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHalfPage;
+                          /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHalfPage; */
+			  writew(((USHORT)PhysicalAdrHalfPage), Addr);
+                          Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrOtherPage;
+                          /* *((USHORT *)(Addr)) = PhysicalAdrOtherPage; */
+			  writew(((USHORT)PhysicalAdrOtherPage), Addr);
+                          /* Read data */
+                          Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh;
+                          data = readw(Addr); /* *((USHORT *)(Addr)); */
+                          if(data == PhysicalAdrHigh) Done = 1;
+                       }  /* if */
+                 }  /* for k */
+              }  /* if */
+      	   }  /* for j */
+   	}  /* for i */
+}
+
+static void __devinit sisfb_post_sis300(struct pci_dev *pdev)
+{
+	struct sis_video_info *ivideo = pci_get_drvdata(pdev);
+	u8  reg, v1, v2, v3, v4, v5, v6, v7, v8;
+	u16 index, rindex, memtype = 0;
+
+	outSISIDXREG(SISSR,0x05,0x86);
+
+	if(ivideo->sishw_ext.UseROM) {
+	   if(ivideo->sishw_ext.pjVirtualRomBase[0x52] & 0x80) {
+	      memtype = ivideo->sishw_ext.pjVirtualRomBase[0x52];
+ 	   } else {
+	      inSISIDXREG(SISSR,0x3a,memtype);
+	   }
+	   memtype &= 0x07;
+	}
+
+	if(ivideo->revision_id <= 0x13) {
+	   v1 = 0x44; v2 = 0x42; v3 = 0x80;
+	   v4 = 0x44; v5 = 0x42; v6 = 0x80;
+	} else {
+	   v1 = 0x68; v2 = 0x43; v3 = 0x80;  /* Assume 125Mhz MCLK */
+	   v4 = 0x68; v5 = 0x43; v6 = 0x80;  /* Assume 125Mhz ECLK */
+	   if(ivideo->sishw_ext.UseROM) {
+	      index = memtype * 5;
+	      rindex = index + 0x54;
+	      v1 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
+	      v2 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
+	      v3 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
+	      rindex = index + 0x7c;
+	      v4 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
+	      v5 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
+	      v6 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
+	   }
+	}
+	outSISIDXREG(SISSR,0x28,v1);
+	outSISIDXREG(SISSR,0x29,v2);
+	outSISIDXREG(SISSR,0x2a,v3);
+	outSISIDXREG(SISSR,0x2e,v4);
+	outSISIDXREG(SISSR,0x2f,v5);
+	outSISIDXREG(SISSR,0x30,v6);
+	v1 = 0x10;
+	if(ivideo->sishw_ext.UseROM) v1 = ivideo->sishw_ext.pjVirtualRomBase[0xa4];
+	outSISIDXREG(SISSR,0x07,v1);       /* DAC speed */
+	outSISIDXREG(SISSR,0x11,0x0f);     /* DDC, power save */
+	v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
+	v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
+	if(ivideo->sishw_ext.UseROM) {
+	   memtype += 0xa5;
+	   v1 = ivideo->sishw_ext.pjVirtualRomBase[memtype];
+	   v2 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 8];
+	   v3 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 16];
+	   v4 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 24];
+	   v5 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 32];
+	   v6 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 40];
+	   v7 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 48];
+	   v8 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 56];
+	}
+	if(ivideo->revision_id >= 0x80) v3 &= 0xfd;
+	outSISIDXREG(SISSR,0x15,v1);       /* Ram type (assuming 0, BIOS 0xa5 step 8) */
+	outSISIDXREG(SISSR,0x16,v2);
+	outSISIDXREG(SISSR,0x17,v3);
+	outSISIDXREG(SISSR,0x18,v4);
+	outSISIDXREG(SISSR,0x19,v5);
+	outSISIDXREG(SISSR,0x1a,v6);
+	outSISIDXREG(SISSR,0x1b,v7);
+	outSISIDXREG(SISSR,0x1c,v8);	   /* ---- */
+	andSISIDXREG(SISSR,0x15,0xfb);
+	orSISIDXREG(SISSR,0x15,0x04);
+	if(ivideo->sishw_ext.UseROM) {
+	   if(ivideo->sishw_ext.pjVirtualRomBase[0x53] & 0x02) {
+	      orSISIDXREG(SISSR,0x19,0x20);
+	   }
+	}
+	v1 = 0x04;			   /* DAC pedestal (BIOS 0xe5) */
+	if(ivideo->revision_id >= 0x80) v1 |= 0x01;
+	outSISIDXREG(SISSR,0x1f,v1);
+	outSISIDXREG(SISSR,0x20,0xa0);     /* linear & relocated io */
+	v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
+	if(ivideo->sishw_ext.UseROM) {
+	   v1 = ivideo->sishw_ext.pjVirtualRomBase[0xe8];
+	   v2 = ivideo->sishw_ext.pjVirtualRomBase[0xe9];
+	   v3 = ivideo->sishw_ext.pjVirtualRomBase[0xea];
+	}
+	outSISIDXREG(SISSR,0x23,v1);
+	outSISIDXREG(SISSR,0x24,v2);
+	outSISIDXREG(SISSR,0x25,v3);
+	outSISIDXREG(SISSR,0x21,0x84);
+	outSISIDXREG(SISSR,0x22,0x00);
+	outSISIDXREG(SISCR,0x37,0x00);
+	orSISIDXREG(SISPART1,0x24,0x01);   /* unlock crt2 */
+	outSISIDXREG(SISPART1,0x00,0x00);
+	v1 = 0x40; v2 = 0x11;
+	if(ivideo->sishw_ext.UseROM) {
+	   v1 = ivideo->sishw_ext.pjVirtualRomBase[0xec];
+	   v2 = ivideo->sishw_ext.pjVirtualRomBase[0xeb];
+	}
+	outSISIDXREG(SISPART1,0x02,v1);
+	if(ivideo->revision_id >= 0x80) v2 &= ~0x01;
+	inSISIDXREG(SISPART4,0x00,reg);
+	if((reg == 1) || (reg == 2)) {
+	   outSISIDXREG(SISCR,0x37,0x02);
+	   outSISIDXREG(SISPART2,0x00,0x1c);
+	   v4 = 0x00; v5 = 0x00; v6 = 0x10;
+	   if(ivideo->sishw_ext.UseROM) {
+	      v4 = ivideo->sishw_ext.pjVirtualRomBase[0xf5];
+	      v5 = ivideo->sishw_ext.pjVirtualRomBase[0xf6];
+	      v6 = ivideo->sishw_ext.pjVirtualRomBase[0xf7];
+	   }
+	   outSISIDXREG(SISPART4,0x0d,v4);
+	   outSISIDXREG(SISPART4,0x0e,v5);
+	   outSISIDXREG(SISPART4,0x10,v6);
+	   outSISIDXREG(SISPART4,0x0f,0x3f);
+	   inSISIDXREG(SISPART4,0x01,reg);
+	   if(reg >= 0xb0) {
+	      inSISIDXREG(SISPART4,0x23,reg);
+	      reg &= 0x20;
+	      reg <<= 1;
+	      outSISIDXREG(SISPART4,0x23,reg);
+	   }
+	} else {
+	   v2 &= ~0x10;
+	}
+	outSISIDXREG(SISSR,0x32,v2);
+	andSISIDXREG(SISPART1,0x24,0xfe);  /* Lock CRT2 */
+	inSISIDXREG(SISSR,0x16,reg);
+	reg &= 0xc3;
+	outSISIDXREG(SISCR,0x35,reg);
+	outSISIDXREG(SISCR,0x83,0x00);
+#if !defined(__i386__) && !defined(__x86_64__)
+	if(sisfb_videoram) {
+	   outSISIDXREG(SISSR,0x13,0x28);  /* ? */
+	   reg = ((sisfb_videoram >> 10) - 1) | 0x40;
+	   outSISIDXREG(SISSR,0x14,reg);
+	} else {
+#endif
+	   /* Need to map max FB size for finding out about RAM size */
+	   ivideo->video_vbase = ioremap(ivideo->video_base, 0x4000000);
+	   if(ivideo->video_vbase) {
+	      sisfb_setramsize300(pdev);
+	      iounmap(ivideo->video_vbase);
+	   } else {
+	      printk(KERN_DEBUG "sisfb: Failed to map memory for size detection, assuming 8MB\n");
+	      outSISIDXREG(SISSR,0x13,0x28);  /* ? */
+	      outSISIDXREG(SISSR,0x14,0x47);  /* 8MB, 64bit default */
+	   }
+#if !defined(__i386__) && !defined(__x86_64__)
+	}
+#endif
+	if(ivideo->sishw_ext.UseROM) {
+	   v1 = ivideo->sishw_ext.pjVirtualRomBase[0xe6];
+	   v2 = ivideo->sishw_ext.pjVirtualRomBase[0xe7];
+	} else {
+	   inSISIDXREG(SISSR,0x3a,reg);
+	   if((reg & 0x30) == 0x30) {
+	      v1 = 0x04; /* PCI */
+	      v2 = 0x92;
+	   } else {
+	      v1 = 0x14; /* AGP */
+	      v2 = 0xb2;
+	   }
+	}
+	outSISIDXREG(SISSR,0x21,v1);
+	outSISIDXREG(SISSR,0x22,v2);
+}
+#endif
+
+#ifdef CONFIG_FB_SIS_315
+static void __devinit sisfb_post_sis315330(struct pci_dev *pdev)
+{
+#ifdef YET_TO_BE_DONE
+	struct sis_video_info *ivideo = pci_get_drvdata(pdev);
+	u8  reg, v1, v2, v3, v4, v5, v6, v7, v8;
+	u16 index, rindex, memtype = 0;
+	u32 reg1_32, reg2_32, reg3_32;
+	int i;
+
+	/* Unlock */
+	/* outSISIDXREG(0x3c4,0x05,0x86); */
+	outSISIDXREG(SISSR,0x05,0x86);
+
+	/* Enable relocated i/o ports */
+	/* setSISIDXREG(0x3c4,0x20,~0x10,0x20); */
+	setSISIDXREG(SISSR,0x20,~0x10,0x20);
+
+	/* Clear regs */
+	for(i = 0; i < 0x22; i++) {
+	   outSISIDXREG(SISSR,(0x06 + i),0x00);
+	}
+	v1 = 0x0d;
+	if( is 330) v1 = 0x0b;
+	for(i = 0; i < v1; i++) {
+	   outSISIDXREG(SISSR,(0x31 + i),0x00);
+	}
+	for(i = 0; i < 0x10; i++) {
+	   outSISIDXREG(SISCR,(0x30 + i),0x00);
+	}
+
+	/* Reset clocks */
+	reg = inSISREG(SISMISCR);
+	outSISIDXREG(SISSR,0x28,0x81);
+	outSISIDXREG(SISSR,0x2A,0x00);
+	outSISIDXREG(SISSR,0x29,0xE1);
+	outSISREG(SISMISCW,(reg | 0x0c));
+	outSISIDXREG(SISSR,0x2B,0x81);
+	outSISIDXREG(SISSR,0x2D,0x00);
+	outSISIDXREG(SISSR,0x2C,0xE1);
+	outSISIDXREG(SISSR,0x2E,0x81);
+	outSISIDXREG(SISSR,0x30,0x00);
+	outSISIDXREG(SISSR,0x2F,0xE1);
+	SiS_DDC2Delay(....);
+	outSISREG(SISMISCW,reg);
+
+	/* Get memory type */
+	if(ivideo->sishw_ext.UseROM) {
+	   if(ivideo->sishw_ext.pjVirtualRomBase[0x52] & 0x80)) {
+	      memtype = ivideo->sishw_ext.pjVirtualRomBase[0x52];
+ 	   } else {
+	      inSISIDXREG(SISSR,0x3a,memtype);
+	   }
+	   memtype &= 0x03;
+	   if( is 330 ) {
+	      if(memtype <= 1) memtype = 0;
+	      else {
+	         inSISIDXREG(SISCR,0x5F,reg);
+		 reg &= 0x30;
+		 switch(reg) {
+		 case 0x00: memtype = 1; break;
+		 case 0x10: memtype = 3; break;
+		 case 0x20: memtype = 3; break;
+		 default:   memtype = 2;
+		 }
+	      }
+	   }
+	}
+
+	/* Set clocks */
+	v1 = 0x3b; v2 = 0x22; v3 = 0x01;  /* Assume 143Mhz MCLK */
+	v4 = 0x5c; v5 = 0x23; v6 = 0x01;  /* Assume 166Mhz ECLK */
+	if(ivideo->sishw_ext.UseROM) {
+	   index = memtype * 5;
+	   rindex = index + 0x54;
+	   v1 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
+	   v2 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
+	   v3 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
+	   rindex = index + 0x68;
+	   v4 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
+	   v5 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
+	   v6 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
+	}
+	outSISIDXREG(SISSR,0x28,v1);
+	outSISIDXREG(SISSR,0x29,v2);
+	outSISIDXREG(SISSR,0x2a,v3);
+	if( is 330 ) {
+	   inSISIDXREG(SISSR,0x3a,reg);
+	   reg &= 0x03;
+	   if(reg >= 2) {
+	      ...
+	   }
+	}
+	outSISIDXREG(SISSR,0x2e,v4);
+	outSISIDXREG(SISSR,0x2f,v5);
+	outSISIDXREG(SISSR,0x30,v6);
+
+	/* End of comp with 330 */
+
+	v1 = 0x18;
+	if(ivideo->sishw_ext.UseROM) v1 = ivideo->sishw_ext.pjVirtualRomBase[0x7c];
+	outSISIDXREG(SISSR,0x07,v1);
+	outSISIDXREG(SISSR,0x11,0x0f);
+
+	v1 = 0x00; v2 = 0x0f; v3 = 0xba; v4 = 0xa9;
+	v5 = 0xa0; v6 = 0x00; v7 = 0x30;
+	if(ivideo->sishw_ext.UseROM) {
+	   index = memtype + 0x7d;
+	   v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
+	   v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
+	   v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
+	   v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
+	   v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
+	   v6 = ivideo->sishw_ext.pjVirtualRomBase[index + 20];
+	   v7 = ivideo->sishw_ext.pjVirtualRomBase[index + 24];
+	}
+	outSISIDXREG(SISSR,0x15,v1);       /* Ram type (assuming 0, BIOS 0x7d step 4) */
+	outSISIDXREG(SISSR,0x16,v2);
+	outSISIDXREG(SISSR,0x17,v3);
+	outSISIDXREG(SISSR,0x18,v4);
+	outSISIDXREG(SISSR,0x19,v5);
+	outSISIDXREG(SISSR,0x1a,v6);
+	outSISIDXREG(SISSR,0x1b,v7);
+	outSISIDXREG(SISSR,0x1c,v8);	   /* ---- */
+
+	v1 = 0x77; v2 = 0x77; v3 = 0x00; v4 = 0x5b; v5 = 0x00;
+	if(ivideo->sishw_ext.UseROM) {
+	   index = memtype + 0xa2;
+	   v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
+	   v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
+	   v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
+	   v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
+	   v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
+	}
+	outSISIDXREG(SISCR,0x40,v1);
+	outSISIDXREG(SISCR,0x41,v2);
+	outSISIDXREG(SISCR,0x42,v3);
+	outSISIDXREG(SISCR,0x43,v4);
+	outSISIDXREG(SISCR,0x44,v5);
+
+	if( is 330 ) {
+
+	   v1 = 0x;
+	   if(ivideo->sishw_ext.UseROM) {
+	      v1 = ivideo->sishw_ext.pjVirtualRomBase[0xBA];
+	   }
+	   outSISIDXREG(SISCR,0x59,v1);
+
+	   v1 = 0x; v2 = 0x; v3 = 0x; v4 = 0x;
+	   v5 = 0x; v6 = 0x; v7 = 0x; v8 = 0x;
+	   if(ivideo->sishw_ext.UseROM) {
+	      index = memtype + 0xbe;
+	      v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
+	      v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
+	      v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
+	      v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
+	      v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
+	      v6 = ivideo->sishw_ext.pjVirtualRomBase[index + 20];
+	      v7 = ivideo->sishw_ext.pjVirtualRomBase[index + 24];
+	      v8 = ivideo->sishw_ext.pjVirtualRomBase[index + 28];
+	   }
+	   outSISIDXREG(SISCR,0x68,v1);
+	   outSISIDXREG(SISCR,0x69,v2);
+	   outSISIDXREG(SISCR,0x6a,v3);
+	   outSISIDXREG(SISCR,0x6b,v4);
+	   outSISIDXREG(SISCR,0x6c,v5);
+	   outSISIDXREG(SISCR,0x6d,v6);
+	   outSISIDXREG(SISCR,0x6e,v7);
+	   outSISIDXREG(SISCR,0x6f,v8);
+
+	   v1 = 0x20;
+	   inSISIDXREG(SISSR,0x3b,reg);
+
+	   if(!(reg & 0x04)) {
+	      inSISIDXREG(SISCR,0x5F,reg);
+	      reg &= 0x30;
+	      if(reg) v1 = 0x23;
+	   }
+	   outSISIDXREG(SISCR,0x48,v1);
+	   outSISIDXREG(SISCR,0x4c,0x20);
+
+	   xx= xxx();
+	   if(xx >= 1) {
+	      v1 = 0x;
+	      if(ivideo->sishw_ext.UseROM) {
+	         v1 = ivideo->sishw_ext.pjVirtualRomBase[0xBA];
+	      }
+	      outSISIDXREG(SISCR,0x59,v1);
+	   }
+
+
+
+	} else {
+
+	   outSISIDXREG(SISCR,0x48,0x23);
+
+	   andSISIDXREG(SISSR,0x16,0x0f);
+	   if(memtype <= 1) {
+	      orSISIDXREG(SISSR,0x16,0x80);
+	   } else {
+	      v1 = 0x0f;
+	      if(ivideo->sishw_ext.UseROM) {
+	         v1 = ivideo->sishw_ext.pjVirtualRomBase[0x81 + memtype];
+	      }
+	      if(!(v1 & 0x10)) v2 = 0xc0;
+	      else             v2 = 0xd0;
+	      orSISIDXREG(SISSR,0x16,v2);
+	      andSISIDXREG(SISSR,0x16,0x0f);
+	      if(!(v1 & 0x10)) v2 = 0x80;
+	      else             v2 = 0xA0;
+	      orSISIDXREG(SISSR,0x16,v2);
+ 	   }
+
+	   if(memtype >= 2) {
+	      const u8 sr3cseq1[] = { 0xc0,0xe0,0xf0,0xe0,0xf0,0xa0,0xb0,0xa0,0xb0,0x90,0xd0 };
+	      const u8 sr3cseq2[] = { 0xc0,0xa0,0xb0,0xa0,0xb0,0xe0,0xf0,0xa0,0xb0,0x90,0xd0 };
+	      for(i = 0; i < 11; i++) {
+	         outSISIDXREG(SISSR,0x3c,sr3cseq1[i]);
+	      }
+	      outSISIDXREG(SISSR,0x3d,0x00);
+	      outSISIDXREG(SISSR,0x3d,0x04);
+	      SiS_DDC2Delay(0x200);
+	      v1 = inSISIDXREG(SISCR,0xEC);
+	      v2 = inSISIDXREG(SISCR,0xED);
+	      reg1_32 = (v2 << 8) | v1;
+	      outSISIDXREG(SISSR,0x3D,0x00);
+	      for(i = 0; i < 11; i++) {
+	         outSISIDXREG(SISSR,0x3c,sr3cseq2[i]);
+	      }
+	      outSISIDXREG(SISSR,0x3d,0x00);
+	      outSISIDXREG(SISSR,0x3d,0x04);
+	      SiS_DDC2Delay(0x200);
+	      v1 = inSISIDXREG(SISCR,0xEC);
+	      v2 = inSISIDXREG(SISCR,0xED);
+	      reg2_32 = (v2 << 8) | v1;
+	      outSISIDXREG(SISSR,0x3D,0x00);
+	      reg3_32 = reg2_32 << 1;
+	      reg2_32 >>= 1;
+	      reg3_32 += reg2_32;
+	      v1 = 0x40;
+	      if(reg3_32 > reg1_32) v1 = 0x10;
+	         outSISIDXREG(SISCR,0x59,v1);
+	   }
+
+	}
+
+	v1 = 0x00;
+	if(ivideo->sishw_ext.UseROM) {
+	   v1 = ivideo->sishw_ext.pjVirtualRomBase[0x99];
+	}
+	outSISIDXREG(SISSR,0x1f,v1);
+
+	outSISIDXREG(SISSR,0x20,0x20);
+
+	v1 = 0xf6; v2 = 0x0d; v3 = 0x33;
+	if(ivideo->sishw_ext.UseROM) {
+	   v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9c];
+	   v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9d];
+	   v3 = ivideo->sishw_ext.pjVirtualRomBase[0x9e];
+	}
+	outSISIDXREG(SISSR,0x23,v1);
+	outSISIDXREG(SISSR,0x24,v2);
+	outSISIDXREG(SISSR,0x25,v3);
+
+	outSISIDXREG(SISSR,0x21,0x84);
+	outSISIDXREG(SISSR,0x22,0x00);
+	outSISIDXREG(SISSR,0x27,0x1f);
+
+	v1 = 0x00; v2 = 0x00;
+	if(ivideo->sishw_ext.UseROM) {
+	   v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9F];
+	   v2 = ivideo->sishw_ext.pjVirtualRomBase[0xA1];
+	}
+	outSISIDXREG(SISSR,0x31,v1);
+	outSISIDXREG(SISSR,0x33,v2);
+
+	v1 = 0x11;
+	if(ivideo->sishw_ext.UseROM) {
+	   v1 = ivideo->sishw_ext.pjVirtualRomBase[0xA0];
+	}
+	v2 = inSISIDXREG(SISPART4,0x00);
+	if((v2 != 1) && (v2 != 2)) v1 &= 0xef;
+	outSISIDXREG(SISSR,0x32,v1);
+
+	/* AGP */
+	pci_read_config_long(pdev, 0x50, &reg1_32);
+	reg1_32 >>= 20;
+	reg1_32 &= 0x0f;
+	if(reg1_32 == 1) {
+	   v1 = 0xAA; v2 = 0x33;
+	   if(ivideo->sishw_ext.UseROM) {
+	      v1 = ivideo->sishw_ext.pjVirtualRomBase[0xF7];
+	      v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9E];
+	   }
+	} else {
+	   v1 = 0x88; v2 = 0x03;
+	   if(ivideo->sishw_ext.UseROM) {
+	      v1 = ivideo->sishw_ext.pjVirtualRomBase[0xF8];
+	      v2 = ivideo->sishw_ext.pjVirtualRomBase[0xF6];
+	   }
+	}
+	outSISIDXREG(SISCR,0x49,v1);
+	outSISIDXREG(SISSR,0x25,v2);
+
+	v1 = inSISIDXREG(SISPART4,0x00);
+	if((v1 == 1) || (v1 == 2)) {
+	   orSISIDXREG(SISPART1,0x2F,0x01);  /* Unlock CRT2 */
+	   outSISIDXREG(SISPART1,0x00,0x00);
+	   v1 = 0x00;
+	   if(ivideo->sishw_ext.UseROM) {
+	      v1 = ivideo->sishw_ext.pjVirtualRomBase[0xb6];
+	   }
+	   outSISIDXREG(SISPART1,0x02,v1);
+	   outSISIDXREG(SISPART1,0x2E,0x08);
+	   outSISIDXREG(SISPART2,0x00,0x1c);
+	   v1 = 0x40; v2 = 0x00; v3 = 0x80;
+	   if(ivideo->sishw_ext.UseROM) {
+	      v1 = ivideo->sishw_ext.pjVirtualRomBase[0xb7];
+	      v2 = ivideo->sishw_ext.pjVirtualRomBase[0xb8];
+	      v3 = ivideo->sishw_ext.pjVirtualRomBase[0xbb];
+	   }
+	   outSISIDXREG(SISPART4,0x0d,v1);
+	   outSISIDXREG(SISPART4,0x0e,v2);
+	   outSISIDXREG(SISPART4,0x10,v3);
+	   outSISIDXREG(SISPART4,0x0F,0x3F);
+
+	   inSISIDXREG(SISPART4,0x01,reg);
+	   if(reg >= 0xb0) {
+	      inSISIDXREG(SISPART4,0x23,reg);
+	      reg &= 0x20;
+	      reg <<= 1;
+	      outSISIDXREG(SISPART4,0x23,reg);
+	   }
+	}
+	outSISIDXREG(SISCR,0x37,0x02); /* Why? */
+
+	outSISIDXREG(SISCR,0x83,0x00);
+	outSISIDXREG(SISCR,0x90,0x00);
+	andSISIDXREG(SISSR,0x5B,0xDF);
+	outSISIDXREG(SISVID,0x00,0x86);
+	outSISIDXREG(SISVID,0x32,0x00);
+	outSISIDXREG(SISVID,0x30,0x00);
+	outSISIDXREG(SISVID,0x32,0x01);
+	outSISIDXREG(SISVID,0x30,0x00);
+	orSISIDXREG(SISCR,0x63,0x80);
+	/* End of Init1 */
+
+	/* Set Mode 0x2e */
+
+	/* Ramsize */
+	orSISIDXREG(SISSR,0x16,0x0f);
+	orSISIDXREG(SISSR,0x18,0xA9);
+	orSISIDXREG(SISSR,0x19,0xA0);
+	orSISIDXREG(SISSR,0x1B,0x30);
+	andSISIDXREG(SISSR,0x17,0xF8);
+	orSISIDXREG(SISSR,0x19,0x03);
+	andSIDIDXREG(SISSR,0x13,0x00);
+
+	/* Need to map max FB size for finding out about RAM size */
+	ivideo->video_vbase = ioremap(ivideo->video_base, 0x4000000);
+	if(ivideo->video_vbase) {
+	   /* Find out about bus width */
+	   if(memtype <= 1) {
+	      outSISIDXREG(SISSR,0x14,0x02);
+	      andSISIDXREG(SISSR,0x16,0x0F);
+	      orSISIDXREG(SISSR,0x16,0x80);
+
+	      ...
+
+	   } else {
+
+	      ...
+
+	   }
+
+	   /* Find out about size */
+
+
+	   iounmap(ivideo->video_vbase);
+	} else {
+	   printk(KERN_DEBUG "sisfb: Failed to map memory for size detection, assuming 8MB\n");
+	   outSISIDXREG(SISSR,0x14,0x??);  /* 8MB, 64bit default */
+	}
+
+	/* AGP (Missing: Checks for VIA and AMD hosts) */
+	v1 = 0xA5; v2 = 0xFB;
+	if(ivideo->sishw_ext.UseROM) {
+	   v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9A];
+	   v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9B];
+	}
+	outSISIDXREG(SISSR,0x21,v1);
+	outSISIDXREG(SISSR,0x22,v2);
+
+#endif
+	return;
+}
+#endif
+
+
+int __devinit sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	struct sisfb_chip_info 	*chipinfo = &sisfb_chip_info[ent->driver_data];
+	struct sis_video_info 	*ivideo = NULL;
+	struct fb_info 		*sis_fb_info = NULL;
+	u16 reg16;
+	u8  reg;
+	int sisvga_enabled = 0, i;
+
+	if(sisfb_off) return -ENXIO;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
+	sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
+	if(!sis_fb_info) return -ENOMEM;
+#else
+	sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
+	if(!sis_fb_info) return -ENOMEM;
+	memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
+	sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
+#endif
+
+	ivideo = (struct sis_video_info *)sis_fb_info->par;
+	ivideo->memyselfandi = sis_fb_info;
+
+	if(card_list == NULL) {
+	   ivideo->cardnumber = 0;
+	} else {
+	   struct sis_video_info *countvideo = card_list;
+	   ivideo->cardnumber = 1;
+	   while((countvideo = countvideo->next) != NULL) ivideo->cardnumber++;
+	}
+
+	strncpy(ivideo->myid, chipinfo->chip_name, 30);
+
+	ivideo->warncount = 0;
+	ivideo->chip_id = pdev->device;
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
+	ivideo->sishw_ext.jChipRevision = ivideo->revision_id;
+	pci_read_config_word(pdev, PCI_COMMAND, &reg16);
+	sisvga_enabled = reg16 & 0x01;
+	ivideo->pcibus = pdev->bus->number;
+	ivideo->pcislot = PCI_SLOT(pdev->devfn);
+	ivideo->pcifunc = PCI_FUNC(pdev->devfn);
+	ivideo->subsysvendor = pdev->subsystem_vendor;
+	ivideo->subsysdevice = pdev->subsystem_device;
+
+#ifndef MODULE
+	if(sisfb_mode_idx == -1) {
+		sisfb_get_vga_mode_from_kernel();
+	}
+#endif
+
+	ivideo->chip = chipinfo->chip;
+	ivideo->sisvga_engine = chipinfo->vgaengine;
+	ivideo->hwcursor_size = chipinfo->hwcursor_size;
+	ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
+	ivideo->mni = chipinfo->mni;
+
+	ivideo->detectedpdc  = 0xff;
+	ivideo->detectedpdca = 0xff;
+	ivideo->detectedlcda = 0xff;
+
+	ivideo->sisfb_thismonitor.datavalid = FALSE;
+
+	ivideo->sisfb_parm_mem = sisfb_parm_mem;
+	ivideo->sisfb_accel = sisfb_accel;
+	ivideo->sisfb_ypan = sisfb_ypan;
+	ivideo->sisfb_max = sisfb_max;
+	ivideo->sisfb_userom = sisfb_userom;
+	ivideo->sisfb_useoem = sisfb_useoem;
+	ivideo->sisfb_mode_idx = sisfb_mode_idx;
+	ivideo->sisfb_parm_rate = sisfb_parm_rate;
+	ivideo->sisfb_crt1off = sisfb_crt1off;
+	ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
+	ivideo->sisfb_crt2type = sisfb_crt2type;
+	ivideo->sisfb_crt2flags = sisfb_crt2flags;
+	/* pdc(a), scalelcd, special timing, lvdshl handled below */
+	ivideo->sisfb_dstn = sisfb_dstn;
+	ivideo->sisfb_fstn = sisfb_fstn;
+	ivideo->sisfb_tvplug = sisfb_tvplug;
+	ivideo->sisfb_tvstd = sisfb_tvstd;
+	ivideo->tvxpos = sisfb_tvxposoffset;
+	ivideo->tvypos = sisfb_tvyposoffset;
+	ivideo->sisfb_filter = sisfb_filter;
+	ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
+	ivideo->sisfb_inverse = sisfb_inverse;
+#endif
+
+	ivideo->refresh_rate = 0;
+	if(ivideo->sisfb_parm_rate != -1) {
+	   ivideo->refresh_rate = ivideo->sisfb_parm_rate;
+	}
+
+	ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
+	ivideo->SiS_Pr.CenterScreen = -1;
+	ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
+	ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
+
+	ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
+        ivideo->SiS_Pr.SiS_CHOverScan = -1;
+        ivideo->SiS_Pr.SiS_ChSW = FALSE;
+	ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
+	ivideo->SiS_Pr.HaveEMI = FALSE;
+	ivideo->SiS_Pr.HaveEMILCD = FALSE;
+	ivideo->SiS_Pr.OverruleEMI = FALSE;
+	ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE;
+	ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
+	ivideo->SiS_Pr.PDC  = -1;
+	ivideo->SiS_Pr.PDCA = -1;
+#ifdef CONFIG_FB_SIS_315
+	if(ivideo->chip >= SIS_330) {
+	   ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
+	   if(ivideo->chip >= SIS_661) {
+	      ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
+	   }
+	}
+#endif
+
+	memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
+
+	pci_set_drvdata(pdev, ivideo);
+
+	/* Patch special cases */
+	if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
+		switch(ivideo->nbridge->device) {
+#ifdef CONFIG_FB_SIS_300
+		case PCI_DEVICE_ID_SI_730:
+		   	ivideo->chip = SIS_730;
+			strcpy(ivideo->myid, "SiS 730");
+		   	break;
+#endif
+#ifdef CONFIG_FB_SIS_315
+		case PCI_DEVICE_ID_SI_651:
+			/* ivideo->chip is ok */
+			strcpy(ivideo->myid, "SiS 651");
+			break;
+		case PCI_DEVICE_ID_SI_740:
+		   	ivideo->chip = SIS_740;
+			strcpy(ivideo->myid, "SiS 740");
+			break;
+		case PCI_DEVICE_ID_SI_661:
+		   	ivideo->chip = SIS_661;
+			strcpy(ivideo->myid, "SiS 661");
+			break;
+		case PCI_DEVICE_ID_SI_741:
+		   	ivideo->chip = SIS_741;
+			strcpy(ivideo->myid, "SiS 741");
+			break;
+		case PCI_DEVICE_ID_SI_760:
+		   	ivideo->chip = SIS_760;
+			strcpy(ivideo->myid, "SiS 760");
+			break;
+#endif
+		}
+	}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	strcpy(sis_fb_info->modename, ivideo->myid);
+#endif
+
+	ivideo->sishw_ext.jChipType = ivideo->chip;
+
+#ifdef CONFIG_FB_SIS_315
+	if((ivideo->sishw_ext.jChipType == SIS_315PRO) ||
+	   (ivideo->sishw_ext.jChipType == SIS_315)) {
+		ivideo->sishw_ext.jChipType = SIS_315H;
+	}
+#endif
+
+	ivideo->video_base = pci_resource_start(pdev, 0);
+	ivideo->mmio_base  = pci_resource_start(pdev, 1);
+	ivideo->mmio_size  = pci_resource_len(pdev, 1);
+	ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
+	ivideo->sishw_ext.ulIOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
+
+	if(!sisvga_enabled) {
+	   	if(pci_enable_device(pdev)) {
+	      		pci_set_drvdata(pdev, NULL);
+	      		kfree(sis_fb_info);
+	      		return -EIO;
+	   	}
+	}
+
+	SiSRegInit(&ivideo->SiS_Pr, ivideo->sishw_ext.ulIOAddress);
+
+#ifdef CONFIG_FB_SIS_300
+	/* Find PCI systems for Chrontel/GPIO communication setup */
+	if(ivideo->chip == SIS_630) {
+	   i=0;
+           do {
+	      if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
+	         mychswtable[i].subsysCard   == ivideo->subsysdevice) {
+		 ivideo->SiS_Pr.SiS_ChSW = TRUE;
+		 printk(KERN_DEBUG "sisfb: Identified [%s %s] requiring Chrontel/GPIO setup\n",
+		        mychswtable[i].vendorName, mychswtable[i].cardName);
+		 break;
+              }
+              i++;
+           } while(mychswtable[i].subsysVendor != 0);
+	}
+#endif
+
+        outSISIDXREG(SISSR, 0x05, 0x86);
+
+	if( (!sisvga_enabled)
+#if !defined(__i386__) && !defined(__x86_64__)
+		  	      || (sisfb_resetcard)
+#endif
+			      			   ) {
+	   	for(i = 0x30; i <= 0x3f; i++) {
+	      		outSISIDXREG(SISCR,i,0x00);
+	   	}
+	}
+
+	/* Find out about current video mode */
+	ivideo->modeprechange = 0x03;
+	inSISIDXREG(SISCR,0x34,reg);
+	if(reg & 0x7f) {
+		ivideo->modeprechange = reg & 0x7f;
+	} else if(sisvga_enabled) {
+#if defined(__i386__) || defined(__x86_64__)
+		unsigned char SIS_IOTYPE2 *tt = ioremap(0, 0x1000);
+		if(tt) {
+		   	ivideo->modeprechange = readb(tt + 0x449);
+		   	iounmap(tt);
+		}
+#endif
+	}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#ifdef MODULE
+	if((reg & 0x80) && (reg != 0xff)) {
+	   if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF) {
+	      printk(KERN_INFO "sisfb: Cannot initialize display mode, X server is active\n");
+	      pci_set_drvdata(pdev, NULL);
+	      kfree(sis_fb_info);
+	      return -EBUSY;
+	   }
+	}
+#endif	
+#endif
+
+	ivideo->sishw_ext.bIntegratedMMEnabled = TRUE;
+#ifdef CONFIG_FB_SIS_300
+	if(ivideo->sisvga_engine == SIS_300_VGA) {
+	   if(ivideo->chip != SIS_300) {
+	      inSISIDXREG(SISSR, 0x1a, reg);
+	      if(!(reg & 0x10)) {
+		 ivideo->sishw_ext.bIntegratedMMEnabled = FALSE;
+	      }
+	   }
+	}
+#endif
+
+	ivideo->bios_abase = NULL;
+	if(ivideo->sisfb_userom) {
+	    ivideo->sishw_ext.pjVirtualRomBase = sis_find_rom(pdev);
+	    ivideo->bios_abase = ivideo->sishw_ext.pjVirtualRomBase;
+	    if(ivideo->sishw_ext.pjVirtualRomBase) {
+		printk(KERN_INFO "sisfb: Video ROM found and copied\n");
+		ivideo->sishw_ext.UseROM = TRUE;
+	    } else {
+	        ivideo->sishw_ext.UseROM = FALSE;
+	        printk(KERN_INFO "sisfb: Video ROM not found\n");
+	    }
+	} else {
+	    ivideo->sishw_ext.pjVirtualRomBase = NULL;
+	    ivideo->sishw_ext.UseROM = FALSE;
+	    printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
+	}
+
+        /* Find systems for special custom timing */
+	if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
+	   int j;
+	   unsigned char *biosver = NULL;
+           unsigned char *biosdate = NULL;
+	   BOOLEAN footprint;
+	   u32 chksum = 0;
+
+	   if(ivideo->sishw_ext.UseROM) {
+	      biosver = ivideo->sishw_ext.pjVirtualRomBase + 0x06;
+	      biosdate = ivideo->sishw_ext.pjVirtualRomBase + 0x2c;
+              for(i=0; i<32768; i++) chksum += ivideo->sishw_ext.pjVirtualRomBase[i];
+	   }
+
+	   i=0;
+           do {
+	      if( (mycustomttable[i].chipID == ivideo->chip) &&
+	          ((!strlen(mycustomttable[i].biosversion)) ||
+		   (ivideo->sishw_ext.UseROM &&
+		   (!strncmp(mycustomttable[i].biosversion, biosver, strlen(mycustomttable[i].biosversion))))) &&
+	          ((!strlen(mycustomttable[i].biosdate)) ||
+		   (ivideo->sishw_ext.UseROM &&
+		   (!strncmp(mycustomttable[i].biosdate, biosdate, strlen(mycustomttable[i].biosdate))))) &&
+		  ((!mycustomttable[i].bioschksum) ||
+		   (ivideo->sishw_ext.UseROM &&
+	           (mycustomttable[i].bioschksum == chksum)))	&&
+		  (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
+		  (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
+		 footprint = TRUE;
+	         for(j = 0; j < 5; j++) {
+	            if(mycustomttable[i].biosFootprintAddr[j]) {
+		       if(ivideo->sishw_ext.UseROM) {
+	                  if(ivideo->sishw_ext.pjVirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
+		      		mycustomttable[i].biosFootprintData[j]) {
+		             footprint = FALSE;
+			  }
+		       } else footprint = FALSE;
+		    }
+	         }
+	         if(footprint) {
+	 	    ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
+		    printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
+		        mycustomttable[i].vendorName,
+			mycustomttable[i].cardName);
+		    printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
+		    	mycustomttable[i].optionName);
+	            break;
+                 }
+	      }
+              i++;
+           } while(mycustomttable[i].chipID);
+	}
+
+#ifdef CONFIG_FB_SIS_300
+	if(ivideo->sisvga_engine == SIS_300_VGA) {
+		if( (!sisvga_enabled)
+#if !defined(__i386__) && !defined(__x86_64__)
+		    		      || (sisfb_resetcard)
+#endif
+		  					   ) {
+			if(ivideo->chip == SIS_300) {
+				sisfb_post_sis300(pdev);
+			}
+		}
+	}
+#endif
+
+#ifdef CONFIG_FB_SIS_315
+	if(ivideo->sisvga_engine == SIS_315_VGA) {
+		if( (!sisvga_enabled)
+#if !defined(__i386__) && !defined(__x86_64__)
+		    		     || (sisfb_resetcard)
+#endif
+		  					  ) {
+			if((ivideo->chip == SIS_315H)   ||
+			   (ivideo->chip == SIS_315)    ||
+			   (ivideo->chip == SIS_315PRO) ||
+			   (ivideo->chip == SIS_330)) {
+				sisfb_post_sis315330(pdev);
+			}
+		}
+	}
+#endif
+
+	if(sisfb_get_dram_size(ivideo)) {
+		printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size.\n");
+		if(ivideo->bios_abase) vfree(ivideo->bios_abase);
+		pci_set_drvdata(pdev, NULL);
+		kfree(sis_fb_info);
+		return -ENODEV;
+	}
+
+	if((ivideo->sisfb_mode_idx < 0) ||
+	   ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
+	        /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE  */
+	        orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
+                /* Enable 2D accelerator engine */
+	        orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
+	}
+
+	if(sisfb_pdc != 0xff) {
+	   if(ivideo->sisvga_engine == SIS_300_VGA) sisfb_pdc &= 0x3c;
+	   else				            sisfb_pdc &= 0x1f;
+	   ivideo->SiS_Pr.PDC = sisfb_pdc;
+	}
+#ifdef CONFIG_FB_SIS_315
+	if(ivideo->sisvga_engine == SIS_315_VGA) {
+	   if(sisfb_pdca != 0xff) ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
+	}
+#endif
+
+	if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
+		printk(KERN_ERR "sisfb: Fatal error: Unable to reserve frame buffer memory\n");
+		printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
+		if(ivideo->bios_abase) vfree(ivideo->bios_abase);
+		pci_set_drvdata(pdev, NULL);
+		kfree(sis_fb_info);
+		return -ENODEV;
+	}
+
+	if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
+		printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
+		release_mem_region(ivideo->video_base, ivideo->video_size);
+		if(ivideo->bios_abase) vfree(ivideo->bios_abase);
+		pci_set_drvdata(pdev, NULL);
+		kfree(sis_fb_info);
+		return -ENODEV;
+	}
+
+	ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
+	ivideo->sishw_ext.pjVideoMemoryAddress = ivideo->video_vbase;
+	if(!ivideo->video_vbase) {
+	   	printk(KERN_ERR "sisfb: Fatal error: Unable to map frame buffer memory\n");
+	   	release_mem_region(ivideo->video_base, ivideo->video_size);
+	   	release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
+		if(ivideo->bios_abase) vfree(ivideo->bios_abase);
+		pci_set_drvdata(pdev, NULL);
+	   	kfree(sis_fb_info);
+	   	return -ENODEV;
+	}
+
+	ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
+	if(!ivideo->mmio_vbase) {
+	   	printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
+	   	iounmap(ivideo->video_vbase);
+	   	release_mem_region(ivideo->video_base, ivideo->video_size);
+	   	release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
+		if(ivideo->bios_abase) vfree(ivideo->bios_abase);
+		pci_set_drvdata(pdev, NULL);
+	   	kfree(sis_fb_info);
+	   	return -ENODEV;
+	}
+
+	printk(KERN_INFO "sisfb: Framebuffer at 0x%lx, mapped to 0x%lx, size %ldk\n",
+	       	ivideo->video_base, (ULONG)ivideo->video_vbase, ivideo->video_size / 1024);
+
+	printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
+	       	ivideo->mmio_base, (ULONG)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
+
+	if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
+		printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
+	}
+
+	/* Used for clearing the screen only, therefore respect our mem limit */
+	ivideo->sishw_ext.ulVideoMemorySize = ivideo->sisfb_mem;
+
+	ivideo->mtrr = 0;
+
+	ivideo->vbflags = 0;
+	ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
+	ivideo->tvdefmodeidx  = DEFAULT_TVMODE;
+	ivideo->defmodeidx    = DEFAULT_MODE;
+
+	ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr, &ivideo->sishw_ext);
+
+	if((ivideo->sisfb_mode_idx < 0) ||
+	   ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
+
+		sisfb_sense_crt1(ivideo);
+
+		sisfb_get_VB_type(ivideo);
+
+		if(ivideo->vbflags & VB_VIDEOBRIDGE) {
+			sisfb_detect_VB_connect(ivideo);
+		}
+
+		ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
+
+		if(ivideo->vbflags & VB_VIDEOBRIDGE) {
+		   if(ivideo->sisfb_crt2type != -1) {
+		      if((ivideo->sisfb_crt2type == CRT2_LCD) && (ivideo->vbflags & CRT2_LCD)) {
+		         ivideo->currentvbflags |= CRT2_LCD;
+		      } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
+		         ivideo->currentvbflags |= ivideo->sisfb_crt2type;
+		      }
+		   } else {
+		      /* Chrontel 700x TV detection often unreliable, therefore use a
+		       * different default order on such machines
+		       */
+		      if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags & VB_CHRONTEL)) {
+		         if(ivideo->vbflags & CRT2_LCD)      ivideo->currentvbflags |= CRT2_LCD;
+		         else if(ivideo->vbflags & CRT2_TV)  ivideo->currentvbflags |= CRT2_TV;
+		         else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
+		      } else {
+		         if(ivideo->vbflags & CRT2_TV)       ivideo->currentvbflags |= CRT2_TV;
+		         else if(ivideo->vbflags & CRT2_LCD) ivideo->currentvbflags |= CRT2_LCD;
+		         else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
+		      }
+		   }
+		}
+
+		if(ivideo->vbflags & CRT2_LCD) {
+		   inSISIDXREG(SISCR, 0x36, reg);
+		   reg &= 0x0f;
+		   if(ivideo->sisvga_engine == SIS_300_VGA) {
+		      ivideo->CRT2LCDType = sis300paneltype[reg];
+		   } else if(ivideo->chip >= SIS_661) {
+		      ivideo->CRT2LCDType = sis661paneltype[reg];
+		   } else {
+		      ivideo->CRT2LCDType = sis310paneltype[reg];
+		      if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
+		         if((ivideo->CRT2LCDType != LCD_640x480_2) &&
+			    (ivideo->CRT2LCDType != LCD_640x480_3)) {
+		      	    ivideo->CRT2LCDType = LCD_320x480;
+			 }
+		      }
+		   }
+		   if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
+		      /* For broken BIOSes: Assume 1024x768, RGB18 */
+		      ivideo->CRT2LCDType = LCD_1024x768;
+		      setSISIDXREG(SISCR,0x36,0xf0,0x02);
+		      setSISIDXREG(SISCR,0x37,0xee,0x01);
+		      printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
+		   }
+		   for(i = 0; i < SIS_LCD_NUMBER; i++) {
+		      if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
+		         ivideo->lcdxres = sis_lcd_data[i].xres;
+			 ivideo->lcdyres = sis_lcd_data[i].yres;
+			 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
+			 break;
+		      }
+		   }
+		   if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
+	   		ivideo->lcdxres = 1360; ivideo->lcdyres = 1024; ivideo->lcddefmodeidx = 99;
+		   } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
+	   		ivideo->lcdxres =  848; ivideo->lcdyres =  480; ivideo->lcddefmodeidx = 47;
+		   }
+		   printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
+		   		ivideo->lcdxres, ivideo->lcdyres);
+		}
+
+#ifdef CONFIG_FB_SIS_300
+                /* Save the current PanelDelayCompensation if the LCD is currently used */
+		if(ivideo->sisvga_engine == SIS_300_VGA) {
+	           if(ivideo->vbflags & (VB_LVDS | VB_30xBDH)) {
+		       int tmp;
+		       inSISIDXREG(SISCR,0x30,tmp);
+		       if(tmp & 0x20) {
+		          /* Currently on LCD? If yes, read current pdc */
+		          inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
+			  ivideo->detectedpdc &= 0x3c;
+			  if(ivideo->SiS_Pr.PDC == -1) {
+			     /* Let option override detection */
+			     ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
+			  }
+			  printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
+  			         ivideo->detectedpdc);
+		       }
+		       if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
+		          printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
+				 ivideo->SiS_Pr.PDC);
+		       }
+	           }
+		}
+#endif
+
+#ifdef CONFIG_FB_SIS_315
+		if(ivideo->sisvga_engine == SIS_315_VGA) {
+
+		   /* Try to find about LCDA */
+		   if(ivideo->vbflags & (VB_301C | VB_302B | VB_301LV | VB_302LV | VB_302ELV)) {
+		      int tmp;
+		      inSISIDXREG(SISPART1,0x13,tmp);
+		      if(tmp & 0x04) {
+		         ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
+		         ivideo->detectedlcda = 0x03;
+		      }
+	           }
+
+		   /* Save PDC */
+		   if(ivideo->vbflags & (VB_301LV | VB_302LV | VB_302ELV)) {
+		      int tmp;
+		      inSISIDXREG(SISCR,0x30,tmp);
+		      if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
+		         /* Currently on LCD? If yes, read current pdc */
+			 u8 pdc;
+		         inSISIDXREG(SISPART1,0x2D,pdc);
+			 ivideo->detectedpdc  = (pdc & 0x0f) << 1;
+			 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
+			 inSISIDXREG(SISPART1,0x35,pdc);
+			 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
+			 inSISIDXREG(SISPART1,0x20,pdc);
+			 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
+			 if(ivideo->newrom) {
+			    /* New ROM invalidates other PDC resp. */
+			    if(ivideo->detectedlcda != 0xff) {
+			       ivideo->detectedpdc = 0xff;
+			    } else {
+			       ivideo->detectedpdca = 0xff;
+			    }
+			 }
+			 if(ivideo->SiS_Pr.PDC == -1) {
+			    if(ivideo->detectedpdc != 0xff) {
+			       ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
+			    }
+			 }
+			 if(ivideo->SiS_Pr.PDCA == -1) {
+			    if(ivideo->detectedpdca != 0xff) {
+			       ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
+			    }
+			 }
+			 if(ivideo->detectedpdc != 0xff) {
+			    printk(KERN_INFO
+			         "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
+  			          ivideo->detectedpdc);
+			 }
+			 if(ivideo->detectedpdca != 0xff) {
+			    printk(KERN_INFO
+			         "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
+  			          ivideo->detectedpdca);
+			 }
+		      }
+
+		      /* Save EMI */
+		      if(ivideo->vbflags & (VB_302LV | VB_302ELV)) {
+		         inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
+			 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
+			 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
+			 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
+			 ivideo->SiS_Pr.HaveEMI = TRUE;
+			 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
+			  	ivideo->SiS_Pr.HaveEMILCD = TRUE;
+			 }
+		      }
+		   }
+
+		   /* Let user override detected PDCs (all bridges) */
+		   if(ivideo->vbflags & (VB_301B | VB_301C | VB_301LV | VB_302LV | VB_302ELV)) {
+		      if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
+		         printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
+				 ivideo->SiS_Pr.PDC);
+		      }
+		      if((ivideo->SiS_Pr.PDCA != -1) && (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
+		         printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
+				 ivideo->SiS_Pr.PDCA);
+		      }
+		   }
+
+		}
+#endif
+
+		if(!ivideo->sisfb_crt1off) {
+		   	sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
+		} else {
+		   	if((ivideo->vbflags & (VB_301|VB_301B|VB_301C|VB_302B)) &&
+		      	   (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
+		      		sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
+		   	}
+		}
+
+		if(ivideo->sisfb_mode_idx >= 0) {
+			int bu = ivideo->sisfb_mode_idx;
+			ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
+					ivideo->sisfb_mode_idx, ivideo->currentvbflags);
+			if(bu != ivideo->sisfb_mode_idx) {
+				printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
+					sisbios_mode[bu].xres,
+					sisbios_mode[bu].yres,
+					sisbios_mode[bu].bpp);
+			}
+		}
+
+		if(ivideo->sisfb_mode_idx < 0) {
+			switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
+			   case CRT2_LCD:
+				ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
+				break;
+			   case CRT2_TV:
+				ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
+				break;
+			   default:
+				ivideo->sisfb_mode_idx = ivideo->defmodeidx;
+				break;
+			}
+		}
+
+		ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
+
+		if(ivideo->refresh_rate != 0) {
+			sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx);
+		}
+
+		if(ivideo->rate_idx == 0) {
+			ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
+			ivideo->refresh_rate = 60;
+		}
+
+		if(ivideo->sisfb_thismonitor.datavalid) {
+			if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
+			                      ivideo->rate_idx, ivideo->refresh_rate)) {
+				printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
+			}
+		}
+
+		ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
+		ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
+		ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
+
+		sisfb_set_vparms(ivideo);
+		
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	
+
+		/* ---------------- For 2.4: Now switch the mode ------------------ */		
+		
+		printk(KERN_INFO "sisfb: Mode is %dx%dx%d (%dHz)\n",
+	       		ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
+			ivideo->refresh_rate);
+
+		sisfb_pre_setmode(ivideo);
+
+		if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) {
+			printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
+									ivideo->mode_no);
+			iounmap(ivideo->video_vbase);
+			iounmap(ivideo->mmio_vbase);
+			release_mem_region(ivideo->video_base, ivideo->video_size);
+			release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
+			if(ivideo->bios_abase) vfree(ivideo->bios_abase);
+			pci_set_drvdata(pdev, NULL);
+			kfree(sis_fb_info);
+			return -EINVAL;
+		}
+
+		outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
+
+		sisfb_post_setmode(ivideo);
+
+		/* Maximize regardless of sisfb_max at startup */
+		ivideo->default_var.yres_virtual = 32767;
+
+		/* Force reset of x virtual in crtc_to_var */
+		ivideo->default_var.xres_virtual = 0;
+
+		sisfb_crtc_to_var(ivideo, &ivideo->default_var);
+
+		sisfb_calc_pitch(ivideo, &ivideo->default_var);
+		sisfb_set_pitch(ivideo);
+
+		ivideo->accel = 0;
+		if(ivideo->sisfb_accel) {
+		   ivideo->accel = -1;
+		   ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
+		}
+		sisfb_initaccel(ivideo);
+		
+		sis_fb_info->node  = -1;
+		sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
+		sis_fb_info->fbops = &sisfb_ops;
+		sis_fb_info->disp  = &ivideo->sis_disp;
+		sis_fb_info->blank = &sisfb_blank;
+		sis_fb_info->switch_con = &sisfb_switch;
+		sis_fb_info->updatevar  = &sisfb_update_var;
+		sis_fb_info->changevar  = NULL;
+		strcpy(sis_fb_info->fontname, sisfb_fontname);
+
+		sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
+
+#else		/* --------- For 2.6: Setup a somewhat sane default var ------------ */
+
+		printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
+	       		ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
+			ivideo->refresh_rate);
+
+		ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
+		ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
+		ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
+
+		sisfb_bpp_to_var(ivideo, &ivideo->default_var);
+		
+		ivideo->default_var.pixclock = (u32) (1000000000 /
+				sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, &ivideo->sishw_ext,
+						ivideo->mode_no, ivideo->rate_idx));
+						
+		if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext,
+			 	ivideo->mode_no, ivideo->rate_idx, &ivideo->default_var)) {
+		   if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+		      ivideo->default_var.pixclock <<= 1;
+	   	   }
+	        }
+
+		if(ivideo->sisfb_ypan) {
+		   /* Maximize regardless of sisfb_max at startup */
+	    	   ivideo->default_var.yres_virtual = sisfb_calc_maxyres(ivideo, &ivideo->default_var);
+	    	   if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
+	              ivideo->default_var.yres_virtual = ivideo->default_var.yres;
+	    	   }
+		}
+
+		sisfb_calc_pitch(ivideo, &ivideo->default_var);
+
+		ivideo->accel = 0;
+		if(ivideo->sisfb_accel) {
+		   ivideo->accel = -1;
+#ifdef STUPID_ACCELF_TEXT_SHIT
+		   ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
+#endif
+		}
+		sisfb_initaccel(ivideo);
+
+#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
+		sis_fb_info->flags = FBINFO_DEFAULT 		|
+				     FBINFO_HWACCEL_YPAN 	|
+				     FBINFO_HWACCEL_XPAN 	|
+				     FBINFO_HWACCEL_COPYAREA 	|
+				     FBINFO_HWACCEL_FILLRECT 	|
+				     ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
+#else
+		sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
+#endif
+		sis_fb_info->var = ivideo->default_var;
+		sis_fb_info->fix = ivideo->sisfb_fix;
+		sis_fb_info->screen_base = ivideo->video_vbase;
+		sis_fb_info->fbops = &sisfb_ops;
+
+		sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
+		sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
+		
+		fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
+#endif		/* 2.6 */
+
+		printk(KERN_DEBUG "sisfb: Initial vbflags 0x%lx\n", (unsigned long)ivideo->vbflags);
+
+#ifdef CONFIG_MTRR
+		ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
+					MTRR_TYPE_WRCOMB, 1);
+		if(!ivideo->mtrr) {
+			printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
+		}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+		vc_resize_con(1, 1, 0);
+#endif
+
+		if(register_framebuffer(sis_fb_info) < 0) {
+			printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
+			iounmap(ivideo->video_vbase);
+			iounmap(ivideo->mmio_vbase);
+			release_mem_region(ivideo->video_base, ivideo->video_size);
+			release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
+			if(ivideo->bios_abase) vfree(ivideo->bios_abase);
+			pci_set_drvdata(pdev, NULL);
+			kfree(sis_fb_info);
+			return -EINVAL;
+		}
+
+		ivideo->registered = 1;
+
+		/* Enlist us */
+		ivideo->next = card_list;
+		card_list = ivideo;
+
+		printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
+		     ivideo->sisfb_accel ? "enabled" : "disabled",
+		     ivideo->sisfb_ypan  ?
+		     	(ivideo->sisfb_max ? "enabled (auto-max)" : "enabled (no auto-max)") : "disabled");
+
+
+		printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%d\n",
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	       		GET_FB_IDX(sis_fb_info->node),
+#else
+	       		sis_fb_info->node,
+#endif
+			ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
+
+		printk(KERN_INFO "sisfb: (C) 2001-2004 Thomas Winischhofer.\n");
+
+	}	/* if mode = "none" */
+
+	return 0;
+}
+
+/*****************************************************/
+/*                PCI DEVICE HANDLING                */
+/*****************************************************/
+
+static void __devexit sisfb_remove(struct pci_dev *pdev)
+{
+	struct sis_video_info *ivideo = pci_get_drvdata(pdev);
+	struct fb_info        *sis_fb_info = ivideo->memyselfandi;
+	int                   registered = ivideo->registered;
+
+	/* Unmap */
+	iounmap(ivideo->video_vbase);
+	iounmap(ivideo->mmio_vbase);
+	vfree(ivideo->bios_abase);
+
+	/* Release mem regions */
+	release_mem_region(ivideo->video_base, ivideo->video_size);
+	release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
+
+#ifdef CONFIG_MTRR
+	/* Release MTRR region */
+	if(ivideo->mtrr) {
+		mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
+	}
+#endif
+
+	/* Unregister the framebuffer */
+	if(ivideo->registered) {
+		unregister_framebuffer(sis_fb_info);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
+		framebuffer_release(sis_fb_info);
+#else
+		kfree(sis_fb_info);
+#endif
+	}
+
+	pci_set_drvdata(pdev, NULL);
+
+	/* TODO: Restore the initial mode
+	 * This sounds easy but is as good as impossible
+	 * on many machines with SiS chip and video bridge
+	 * since text modes are always set up differently
+	 * from machine to machine. Depends on the type
+	 * of integration between chipset and bridge.
+	 */
+	if(registered) {
+	   printk(KERN_INFO "sisfb: Restoring of text mode not supported yet\n");
+	}
+};
+
+static struct pci_driver sisfb_driver = {
+	.name		= "sisfb",
+	.id_table 	= sisfb_pci_table,
+	.probe 		= sisfb_probe,
+	.remove 	= __devexit_p(sisfb_remove)
+};
+
+SISINITSTATIC int __init sisfb_init(void)
+{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
+#ifndef MODULE
+	char *options = NULL;
+
+	if(fb_get_options("sisfb", &options))
+		return -ENODEV;
+	sisfb_setup(options);
+#endif
+#endif
+	return(pci_register_driver(&sisfb_driver));
+}
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
+#ifndef MODULE
+module_init(sisfb_init);
+#endif
+#endif
+
+/*****************************************************/
+/*                      MODULE                       */
+/*****************************************************/
+
+#ifdef MODULE
+
+static char         *mode = NULL;
+static int          vesa = -1;
+static unsigned int rate = 0;
+static unsigned int crt1off = 1;
+static unsigned int mem = 0;
+static char         *forcecrt2type = NULL;
+static int          forcecrt1 = -1;
+static int          pdc = -1;
+static int          pdc1 = -1;
+static int          noaccel = -1;
+static int          noypan  = -1;
+static int	    nomax = -1;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+static int          inverse = 0;
+#endif
+static int          userom = -1;
+static int          useoem = -1;
+static char         *tvstandard = NULL;
+static int	    nocrt2rate = 0;
+static int          scalelcd = -1;
+static char	    *specialtiming = NULL;
+static int	    lvdshl = -1;
+static int	    tvxposoffset = 0, tvyposoffset = 0;
+static int	    filter = -1;
+#if !defined(__i386__) && !defined(__x86_64__)
+static int	    resetcard = 0;
+static int	    videoram = 0;
+#endif
+
+MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/65x/661/74x/330/760 framebuffer device driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+MODULE_PARM(mem, "i");
+MODULE_PARM(noaccel, "i");
+MODULE_PARM(noypan, "i");
+MODULE_PARM(nomax, "i");
+MODULE_PARM(userom, "i");
+MODULE_PARM(useoem, "i");
+MODULE_PARM(mode, "s");
+MODULE_PARM(vesa, "i");
+MODULE_PARM(rate, "i");
+MODULE_PARM(forcecrt1, "i");
+MODULE_PARM(forcecrt2type, "s");
+MODULE_PARM(scalelcd, "i");
+MODULE_PARM(pdc, "i");
+MODULE_PARM(pdc1, "i");
+MODULE_PARM(specialtiming, "s");
+MODULE_PARM(lvdshl, "i");
+MODULE_PARM(tvstandard, "s");
+MODULE_PARM(tvxposoffset, "i");
+MODULE_PARM(tvyposoffset, "i");
+MODULE_PARM(filter, "i");
+MODULE_PARM(nocrt2rate, "i");
+MODULE_PARM(inverse, "i");
+#if !defined(__i386__) && !defined(__x86_64__)
+MODULE_PARM(resetcard, "i");
+MODULE_PARM(videoram, "i");
+#endif
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+module_param(mem, int, 0);
+module_param(noaccel, int, 0);
+module_param(noypan, int, 0);
+module_param(nomax, int, 0);
+module_param(userom, int, 0);
+module_param(useoem, int, 0);
+module_param(mode, charp, 0);
+module_param(vesa, int, 0);
+module_param(rate, int, 0);
+module_param(forcecrt1, int, 0);
+module_param(forcecrt2type, charp, 0);
+module_param(scalelcd, int, 0);
+module_param(pdc, int, 0);
+module_param(pdc1, int, 0);
+module_param(specialtiming, charp, 0);
+module_param(lvdshl, int, 0);
+module_param(tvstandard, charp, 0);
+module_param(tvxposoffset, int, 0);
+module_param(tvyposoffset, int, 0);
+module_param(filter, int, 0);
+module_param(nocrt2rate, int, 0);
+#if !defined(__i386__) && !defined(__x86_64__)
+module_param(resetcard, int, 0);
+module_param(videoram, int, 0);
+#endif
+#endif
+
+MODULE_PARM_DESC(mem,
+	"\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
+	  "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
+	  "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
+	  "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
+	  "otherwise at 12288KB. On 315 and Xabre series, the heap size is 32KB by default.\n"
+	  "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
+	  "for XFree86 4.x/X.org 6.7 and later.\n");
+
+MODULE_PARM_DESC(noaccel,
+        "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
+	  "(default: 0)\n");
+
+MODULE_PARM_DESC(noypan,
+        "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
+ 	  "will be performed by redrawing the screen. (default: 0)\n");
+
+MODULE_PARM_DESC(nomax,
+        "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
+	  "memory for the virtual screen in order to optimize scrolling performance. If\n"
+	  "this is set to anything other than 0, sisfb will not do this and thereby \n"
+	  "enable the user to positively specify a virtual Y size of the screen using\n"
+	  "fbset. (default: 0)\n");
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+MODULE_PARM_DESC(mode,
+        "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
+          "1024x768x16. Other formats supported include XxY-Depth and\n"
+ 	  "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
+	  "number, it will be interpreted as a VESA mode number. (default: none if\n"
+	  "sisfb is a module; this leaves the console untouched and the driver will\n"
+	  "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
+	  "is in the kernel)\n");
+MODULE_PARM_DESC(vesa,
+        "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
+          "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
+	  "and the driver will only do the video memory management for eg. DRM/DRI;\n"
+	  "0x0103 if sisfb is in the kernel)\n");
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+MODULE_PARM_DESC(mode,
+       "\nSelects the desired default display mode in the format XxYxDepth,\n"
+         "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
+	 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
+	 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
+
+MODULE_PARM_DESC(vesa,
+       "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
+         "0x117 (default: 0x0103)\n");
+#endif
+
+MODULE_PARM_DESC(rate,
+	"\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
+	  "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
+	  "will be ignored (default: 60)\n");
+
+MODULE_PARM_DESC(forcecrt1,
+	"\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
+	  "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
+	  "0=CRT1 OFF) (default: [autodetected])\n");
+
+MODULE_PARM_DESC(forcecrt2type,
+	"\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
+	  "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
+	  "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
+	  "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
+	  "be used instead of TV to override the TV detection. Furthermore, on systems\n"
+	  "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
+	  "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
+	  "depends on the very hardware in use. (default: [autodetected])\n");
+
+MODULE_PARM_DESC(scalelcd,
+	"\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
+	  "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
+	  "show black bars around the image, TMDS panels will probably do the scaling\n"
+	  "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
+
+MODULE_PARM_DESC(pdc,
+        "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
+	  "should detect this correctly in most cases; however, sometimes this is not\n"
+	  "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
+	  "on a 300 series chipset; 6 on a 315 series chipset. If the problem persists,\n"
+	  "try other values (on 300 series: between 4 and 60 in steps of 4; on 315 series:\n"
+	  "any value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
+
+#ifdef CONFIG_FB_SIS_315
+MODULE_PARM_DESC(pdc1,
+        "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330\n"
+	  "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
+	  "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
+	  "implemented yet.\n");
+#endif
+
+MODULE_PARM_DESC(specialtiming,
+	"\nPlease refer to documentation for more information on this option.\n");
+
+MODULE_PARM_DESC(lvdshl,
+	"\nPlease refer to documentation for more information on this option.\n");
+
+MODULE_PARM_DESC(tvstandard,
+	"\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
+	  "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
+
+MODULE_PARM_DESC(tvxposoffset,
+	"\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
+	  "Default: 0\n");
+
+MODULE_PARM_DESC(tvyposoffset,
+	"\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
+	  "Default: 0\n");
+
+MODULE_PARM_DESC(filter,
+	"\nSelects TV flicker filter type (only for systems with a SiS301 video bridge).\n"
+	  "(Possible values 0-7, default: [no filter])\n");
+
+MODULE_PARM_DESC(nocrt2rate,
+	"\nSetting this to 1 will force the driver to use the default refresh rate for\n"
+	  "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+MODULE_PARM_DESC(inverse,
+        "\nSetting this to anything but 0 should invert the display colors, but this\n"
+	  "does not seem to work. (default: 0)\n");
+#endif
+
+#if !defined(__i386__) && !defined(__x86_64__)
+#ifdef CONFIG_FB_SIS_300
+MODULE_PARM_DESC(resetcard,
+	"\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
+	  "the BIOS did not POST the card (only supported for SiS 300/305 currently).\n"
+	  "Default: 0\n");
+
+MODULE_PARM_DESC(videoram,
+	"\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
+	  "some non-x86 architectures where the memory auto detection fails. Only\n"
+	  "relevant if resetcard is set, too. Default: [auto-detect]\n");
+#endif
+#endif
+
+int __devinit sisfb_init_module(void)
+{
+	sisfb_setdefaultparms();
+
+	if(rate) sisfb_parm_rate = rate;
+
+	if((scalelcd == 0) || (scalelcd == 1)) {
+	   sisfb_scalelcd = scalelcd ^ 1;
+	}
+
+	/* Need to check crt2 type first for fstn/dstn */
+
+	if(forcecrt2type)
+		sisfb_search_crt2type(forcecrt2type);
+
+	if(tvstandard)
+		sisfb_search_tvstd(tvstandard);
+
+	if(mode)
+		sisfb_search_mode(mode, FALSE);
+	else if(vesa != -1)
+		sisfb_search_vesamode(vesa, FALSE);
+
+	sisfb_crt1off = (crt1off == 0) ? 1 : 0;
+
+	sisfb_forcecrt1 = forcecrt1;
+	if(forcecrt1 == 1)      sisfb_crt1off = 0;
+	else if(forcecrt1 == 0) sisfb_crt1off = 1;
+
+	if(noaccel == 1)      sisfb_accel = 0;
+	else if(noaccel == 0) sisfb_accel = 1;
+
+	if(noypan == 1)       sisfb_ypan = 0;
+	else if(noypan == 0)  sisfb_ypan = 1;
+
+	if(nomax == 1)        sisfb_max = 0;
+	else if(nomax == 0)   sisfb_max = 1;
+	
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	if(inverse)           sisfb_inverse = 1;
+#endif
+
+	if(mem)		      sisfb_parm_mem = mem;
+
+	if(userom != -1)      sisfb_userom = userom;
+	if(useoem != -1)      sisfb_useoem = useoem;
+
+        if(pdc != -1)  sisfb_pdc  = (pdc  & 0x7f);
+	if(pdc1 != -1) sisfb_pdca = (pdc1 & 0x1f);
+
+	sisfb_nocrt2rate = nocrt2rate;
+
+	if(specialtiming)
+		sisfb_search_specialtiming(specialtiming);
+
+	if((lvdshl >= 0) && (lvdshl <= 3))  sisfb_lvdshl = lvdshl;
+
+	if(filter != -1) sisfb_filter = filter;
+
+	sisfb_tvxposoffset = tvxposoffset;
+	sisfb_tvyposoffset = tvyposoffset;
+
+#if !defined(__i386__) && !defined(__x86_64__)
+ 	sisfb_resetcard = (resetcard) ? 1 : 0;
+	if(videoram)    sisfb_videoram = videoram;
+#endif
+
+        return(sisfb_init());
+}
+
+static void __exit sisfb_remove_module(void)
+{
+	pci_unregister_driver(&sisfb_driver);
+	printk(KERN_DEBUG "sisfb: Module unloaded\n");
+}
+
+module_init(sisfb_init_module);
+module_exit(sisfb_remove_module);
+
+#endif 	   /*  /MODULE  */
+
+EXPORT_SYMBOL(sis_malloc);
+EXPORT_SYMBOL(sis_free);
+
+
diff --git a/drivers/video/sis/sis_main.h b/drivers/video/sis/sis_main.h
new file mode 100644
index 0000000..a6678a7
--- /dev/null
+++ b/drivers/video/sis/sis_main.h
@@ -0,0 +1,955 @@
+/*
+ * SiS 300/305/540/630(S)/730(S)
+ * SiS 315(H/PRO)/55x/(M)65x/(M)661(F/M)X/740/741(GX)/330/(M)760
+ * frame buffer driver for Linux kernels >=2.4.14 and >=2.6.3
+ *
+ * Copyright (C) 2001-2004 Thomas Winischhofer, Vienna, Austria.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the named License,
+ * or any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef _SISFB_MAIN
+#define _SISFB_MAIN
+
+#include <linux/spinlock.h>
+
+#include "vstruct.h"
+#include "sis.h"
+
+#define MODE_INDEX_NONE           0  /* index for mode=none */
+
+/* Fbcon stuff */
+static struct fb_var_screeninfo my_default_var = {
+	.xres            = 0,
+	.yres            = 0,
+	.xres_virtual    = 0,
+	.yres_virtual    = 0,
+	.xoffset         = 0,
+	.yoffset         = 0,
+	.bits_per_pixel  = 0,
+	.grayscale       = 0,
+	.red             = {0, 8, 0},
+	.green           = {0, 8, 0},
+	.blue            = {0, 8, 0},
+	.transp          = {0, 0, 0},
+	.nonstd          = 0,
+	.activate        = FB_ACTIVATE_NOW,
+	.height          = -1,
+	.width           = -1,
+	.accel_flags     = 0,
+	.pixclock        = 0,
+	.left_margin     = 0,
+	.right_margin    = 0,
+	.upper_margin    = 0,
+	.lower_margin    = 0,
+	.hsync_len       = 0,
+	.vsync_len       = 0,
+	.sync            = 0,
+	.vmode           = FB_VMODE_NONINTERLACED,
+};
+
+/* Boot-time parameters */
+static int sisfb_off = 0;
+static int sisfb_parm_mem = 0;
+static int sisfb_accel = -1;
+static int sisfb_ypan = -1;
+static int sisfb_max = -1;
+static int sisfb_userom = 1;
+static int sisfb_useoem = -1;
+#ifdef MODULE
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+static int sisfb_mode_idx = -1;
+#else
+static int sisfb_mode_idx = MODE_INDEX_NONE;  /* Don't use a mode by default if we are a module */
+#endif
+#else
+static int sisfb_mode_idx = -1;               /* Use a default mode if we are inside the kernel */
+#endif
+static int sisfb_parm_rate = -1;
+static int sisfb_crt1off = 0;
+static int sisfb_forcecrt1 = -1;
+static int sisfb_crt2type  = -1;	/* CRT2 type (for overriding autodetection) */
+static int sisfb_crt2flags = 0;
+static int sisfb_pdc = 0xff;
+static int sisfb_pdca = 0xff;
+static int sisfb_scalelcd = -1;
+static int sisfb_specialtiming = CUT_NONE;
+static int sisfb_lvdshl = -1;
+static int sisfb_dstn = 0;
+static int sisfb_fstn = 0;
+static int sisfb_tvplug = -1;		/* Tv plug type (for overriding autodetection) */
+static int sisfb_tvstd  = -1;
+static int sisfb_tvxposoffset = 0;
+static int sisfb_tvyposoffset = 0;
+static int sisfb_filter = -1;
+static int sisfb_nocrt2rate = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+static int  sisfb_inverse = 0;
+static char sisfb_fontname[40];
+#endif
+#if !defined(__i386__) && !defined(__x86_64__)
+static int sisfb_resetcard = 0;
+static int sisfb_videoram = 0;
+#endif
+
+/* List of supported chips */
+static struct sisfb_chip_info {
+        int 		chip;
+	int 		vgaengine;
+	int		mni;
+	int 		hwcursor_size;
+	int		CRT2_write_enable;
+	const char 	*chip_name;
+} sisfb_chip_info[] __devinitdata = {
+	{ SIS_300,    SIS_300_VGA, 0, HW_CURSOR_AREA_SIZE_300 * 2, SIS_CRT2_WENABLE_300, "SiS 300/305" },
+	{ SIS_540,    SIS_300_VGA, 0, HW_CURSOR_AREA_SIZE_300 * 2, SIS_CRT2_WENABLE_300, "SiS 540" },
+	{ SIS_630,    SIS_300_VGA, 0, HW_CURSOR_AREA_SIZE_300 * 2, SIS_CRT2_WENABLE_300, "SiS 630" },
+	{ SIS_315H,   SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 315H" },
+	{ SIS_315,    SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 315" },
+	{ SIS_315PRO, SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 315PRO" },
+	{ SIS_550,    SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 55x" },
+	{ SIS_650,    SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 650" },
+	{ SIS_330,    SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 330" },
+	{ SIS_660,    SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 660" },
+};
+
+static struct pci_device_id __devinitdata sisfb_pci_table[] = {
+#ifdef CONFIG_FB_SIS_300
+	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300,     PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+#endif
+#ifdef CONFIG_FB_SIS_315
+	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315H,    PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315,     PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315PRO,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_550_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
+	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7},
+	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_330,     PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8},
+	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_660_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9},
+#endif
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, sisfb_pci_table);
+
+static struct sis_video_info *card_list = NULL;
+
+/* TODO: This is not handled card-wise because the DRM
+   does not refer to a unique fb when calling sis_alloc
+   or sis_free. Therefore, this is handled globally for
+   now (hoping that nobody is crazy enough to run two
+   SiS cards at the same time).
+ */
+static SIS_HEAP       	sisfb_heap;
+
+#define MD_SIS300 1
+#define MD_SIS315 2
+
+/* Mode table */
+static const struct _sisbios_mode {
+	char name[15];
+	u8  mode_no[2];
+	u16 vesa_mode_no_1;  /* "SiS defined" VESA mode number */
+	u16 vesa_mode_no_2;  /* Real VESA mode numbers */
+	u16 xres;
+	u16 yres;
+	u16 bpp;
+	u16 rate_idx;
+	u16 cols;
+	u16 rows;
+	u8  chipset;
+} sisbios_mode[] = {
+/*0*/	{"none",         {0xff,0xff}, 0x0000, 0x0000,    0,    0,  0, 0,   0,  0, MD_SIS300|MD_SIS315},
+	{"320x200x8",    {0x59,0x59}, 0x0138, 0x0000,  320,  200,  8, 1,  40, 12, MD_SIS300|MD_SIS315},
+	{"320x200x16",   {0x41,0x41}, 0x010e, 0x0000,  320,  200, 16, 1,  40, 12, MD_SIS300|MD_SIS315},
+	{"320x200x24",   {0x4f,0x4f}, 0x0000, 0x0000,  320,  200, 32, 1,  40, 12, MD_SIS300|MD_SIS315},  /* That's for people who mix up color- and fb depth */
+	{"320x200x32",   {0x4f,0x4f}, 0x0000, 0x0000,  320,  200, 32, 1,  40, 12, MD_SIS300|MD_SIS315},
+	{"320x240x8",    {0x50,0x50}, 0x0132, 0x0000,  320,  240,  8, 1,  40, 15, MD_SIS300|MD_SIS315},
+	{"320x240x16",   {0x56,0x56}, 0x0135, 0x0000,  320,  240, 16, 1,  40, 15, MD_SIS300|MD_SIS315},
+	{"320x240x24",   {0x53,0x53}, 0x0000, 0x0000,  320,  240, 32, 1,  40, 15, MD_SIS300|MD_SIS315},
+	{"320x240x32",   {0x53,0x53}, 0x0000, 0x0000,  320,  240, 32, 1,  40, 15, MD_SIS300|MD_SIS315},
+	{"320x240x8",    {0x5a,0x5a}, 0x0132, 0x0000,  320,  480,  8, 1,  40, 30,           MD_SIS315},  /* FSTN */
+/*10*/	{"320x240x16",   {0x5b,0x5b}, 0x0135, 0x0000,  320,  480, 16, 1,  40, 30,           MD_SIS315},  /* FSTN */
+	{"400x300x8",    {0x51,0x51}, 0x0133, 0x0000,  400,  300,  8, 1,  50, 18, MD_SIS300|MD_SIS315},
+	{"400x300x16",   {0x57,0x57}, 0x0136, 0x0000,  400,  300, 16, 1,  50, 18, MD_SIS300|MD_SIS315},
+	{"400x300x24",   {0x54,0x54}, 0x0000, 0x0000,  400,  300, 32, 1,  50, 18, MD_SIS300|MD_SIS315},
+	{"400x300x32",   {0x54,0x54}, 0x0000, 0x0000,  400,  300, 32, 1,  50, 18, MD_SIS300|MD_SIS315},
+	{"512x384x8",    {0x52,0x52}, 0x0000, 0x0000,  512,  384,  8, 1,  64, 24, MD_SIS300|MD_SIS315},
+	{"512x384x16",   {0x58,0x58}, 0x0000, 0x0000,  512,  384, 16, 1,  64, 24, MD_SIS300|MD_SIS315},
+	{"512x384x24",   {0x5c,0x5c}, 0x0000, 0x0000,  512,  384, 32, 1,  64, 24, MD_SIS300|MD_SIS315},
+	{"512x384x32",   {0x5c,0x5c}, 0x0000, 0x0000,  512,  384, 32, 1,  64, 24, MD_SIS300|MD_SIS315},
+	{"640x400x8",    {0x2f,0x2f}, 0x0000, 0x0000,  640,  400,  8, 1,  80, 25, MD_SIS300|MD_SIS315},
+/*20*/	{"640x400x16",   {0x5d,0x5d}, 0x0000, 0x0000,  640,  400, 16, 1,  80, 25, MD_SIS300|MD_SIS315},
+	{"640x400x24",   {0x5e,0x5e}, 0x0000, 0x0000,  640,  400, 32, 1,  80, 25, MD_SIS300|MD_SIS315},
+	{"640x400x32",   {0x5e,0x5e}, 0x0000, 0x0000,  640,  400, 32, 1,  80, 25, MD_SIS300|MD_SIS315},
+	{"640x480x8",    {0x2e,0x2e}, 0x0101, 0x0101,  640,  480,  8, 1,  80, 30, MD_SIS300|MD_SIS315},
+	{"640x480x16",   {0x44,0x44}, 0x0111, 0x0111,  640,  480, 16, 1,  80, 30, MD_SIS300|MD_SIS315},
+	{"640x480x24",   {0x62,0x62}, 0x013a, 0x0112,  640,  480, 32, 1,  80, 30, MD_SIS300|MD_SIS315},
+	{"640x480x32",   {0x62,0x62}, 0x013a, 0x0112,  640,  480, 32, 1,  80, 30, MD_SIS300|MD_SIS315},
+	{"720x480x8",    {0x31,0x31}, 0x0000, 0x0000,  720,  480,  8, 1,  90, 30, MD_SIS300|MD_SIS315},
+	{"720x480x16",   {0x33,0x33}, 0x0000, 0x0000,  720,  480, 16, 1,  90, 30, MD_SIS300|MD_SIS315},
+	{"720x480x24",   {0x35,0x35}, 0x0000, 0x0000,  720,  480, 32, 1,  90, 30, MD_SIS300|MD_SIS315},
+/*30*/	{"720x480x32",   {0x35,0x35}, 0x0000, 0x0000,  720,  480, 32, 1,  90, 30, MD_SIS300|MD_SIS315},
+	{"720x576x8",    {0x32,0x32}, 0x0000, 0x0000,  720,  576,  8, 1,  90, 36, MD_SIS300|MD_SIS315},
+	{"720x576x16",   {0x34,0x34}, 0x0000, 0x0000,  720,  576, 16, 1,  90, 36, MD_SIS300|MD_SIS315},
+	{"720x576x24",   {0x36,0x36}, 0x0000, 0x0000,  720,  576, 32, 1,  90, 36, MD_SIS300|MD_SIS315},
+	{"720x576x32",   {0x36,0x36}, 0x0000, 0x0000,  720,  576, 32, 1,  90, 36, MD_SIS300|MD_SIS315},
+	{"768x576x8",    {0x5f,0x5f}, 0x0000, 0x0000,  768,  576,  8, 1,  96, 36, MD_SIS300|MD_SIS315},
+	{"768x576x16",   {0x60,0x60}, 0x0000, 0x0000,  768,  576, 16, 1,  96, 36, MD_SIS300|MD_SIS315},
+	{"768x576x24",   {0x61,0x61}, 0x0000, 0x0000,  768,  576, 32, 1,  96, 36, MD_SIS300|MD_SIS315},
+	{"768x576x32",   {0x61,0x61}, 0x0000, 0x0000,  768,  576, 32, 1,  96, 36, MD_SIS300|MD_SIS315},
+	{"800x480x8",    {0x70,0x70}, 0x0000, 0x0000,  800,  480,  8, 1, 100, 30, MD_SIS300|MD_SIS315},
+/*40*/	{"800x480x16",   {0x7a,0x7a}, 0x0000, 0x0000,  800,  480, 16, 1, 100, 30, MD_SIS300|MD_SIS315},
+	{"800x480x24",   {0x76,0x76}, 0x0000, 0x0000,  800,  480, 32, 1, 100, 30, MD_SIS300|MD_SIS315},
+	{"800x480x32",   {0x76,0x76}, 0x0000, 0x0000,  800,  480, 32, 1, 100, 30, MD_SIS300|MD_SIS315},
+#define DEFAULT_MODE              43 /* index for 800x600x8 */
+#define DEFAULT_LCDMODE           43 /* index for 800x600x8 */
+#define DEFAULT_TVMODE            43 /* index for 800x600x8 */
+	{"800x600x8",    {0x30,0x30}, 0x0103, 0x0103,  800,  600,  8, 2, 100, 37, MD_SIS300|MD_SIS315},
+	{"800x600x16",   {0x47,0x47}, 0x0114, 0x0114,  800,  600, 16, 2, 100, 37, MD_SIS300|MD_SIS315},
+	{"800x600x24",   {0x63,0x63}, 0x013b, 0x0115,  800,  600, 32, 2, 100, 37, MD_SIS300|MD_SIS315},
+	{"800x600x32",   {0x63,0x63}, 0x013b, 0x0115,  800,  600, 32, 2, 100, 37, MD_SIS300|MD_SIS315},
+	{"848x480x8",    {0x39,0x39}, 0x0000, 0x0000,  848,  480,  8, 2, 106, 30, MD_SIS300|MD_SIS315},
+	{"848x480x16",   {0x3b,0x3b}, 0x0000, 0x0000,  848,  480, 16, 2, 106, 30, MD_SIS300|MD_SIS315},
+	{"848x480x24",   {0x3e,0x3e}, 0x0000, 0x0000,  848,  480, 32, 2, 106, 30, MD_SIS300|MD_SIS315},
+/*50*/	{"848x480x32",   {0x3e,0x3e}, 0x0000, 0x0000,  848,  480, 32, 2, 106, 30, MD_SIS300|MD_SIS315},
+	{"856x480x8",    {0x3f,0x3f}, 0x0000, 0x0000,  856,  480,  8, 2, 107, 30, MD_SIS300|MD_SIS315},
+	{"856x480x16",   {0x42,0x42}, 0x0000, 0x0000,  856,  480, 16, 2, 107, 30, MD_SIS300|MD_SIS315},
+	{"856x480x24",   {0x45,0x45}, 0x0000, 0x0000,  856,  480, 32, 2, 107, 30, MD_SIS300|MD_SIS315},
+	{"856x480x32",   {0x45,0x45}, 0x0000, 0x0000,  856,  480, 32, 2, 107, 30, MD_SIS300|MD_SIS315},
+	{"960x540x8",    {0x1d,0x1d}, 0x0000, 0x0000,  960,  540,  8, 1, 120, 33,           MD_SIS315},
+	{"960x540x16",   {0x1e,0x1e}, 0x0000, 0x0000,  960,  540, 16, 1, 120, 33,           MD_SIS315},
+	{"960x540x24",   {0x1f,0x1f}, 0x0000, 0x0000,  960,  540, 32, 1, 120, 33,           MD_SIS315},
+	{"960x540x32",   {0x1f,0x1f}, 0x0000, 0x0000,  960,  540, 32, 1, 120, 33,           MD_SIS315},
+	{"960x600x8",    {0x20,0x20}, 0x0000, 0x0000,  960,  600,  8, 1, 120, 37,           MD_SIS315},
+/*60*/	{"960x600x16",   {0x21,0x21}, 0x0000, 0x0000,  960,  600, 16, 1, 120, 37,           MD_SIS315},
+	{"960x600x24",   {0x22,0x22}, 0x0000, 0x0000,  960,  600, 32, 1, 120, 37,           MD_SIS315},
+	{"960x600x32",   {0x22,0x22}, 0x0000, 0x0000,  960,  600, 32, 1, 120, 37,           MD_SIS315},
+	{"1024x576x8",   {0x71,0x71}, 0x0000, 0x0000, 1024,  576,  8, 1, 128, 36, MD_SIS300|MD_SIS315},
+	{"1024x576x16",  {0x74,0x74}, 0x0000, 0x0000, 1024,  576, 16, 1, 128, 36, MD_SIS300|MD_SIS315},
+	{"1024x576x24",  {0x77,0x77}, 0x0000, 0x0000, 1024,  576, 32, 1, 128, 36, MD_SIS300|MD_SIS315},
+	{"1024x576x32",  {0x77,0x77}, 0x0000, 0x0000, 1024,  576, 32, 1, 128, 36, MD_SIS300|MD_SIS315},
+	{"1024x600x8",   {0x20,0x20}, 0x0000, 0x0000, 1024,  600,  8, 1, 128, 37, MD_SIS300          },
+	{"1024x600x16",  {0x21,0x21}, 0x0000, 0x0000, 1024,  600, 16, 1, 128, 37, MD_SIS300          },
+	{"1024x600x24",  {0x22,0x22}, 0x0000, 0x0000, 1024,  600, 32, 1, 128, 37, MD_SIS300          },
+/*70*/	{"1024x600x32",  {0x22,0x22}, 0x0000, 0x0000, 1024,  600, 32, 1, 128, 37, MD_SIS300          },
+	{"1024x768x8",   {0x38,0x38}, 0x0105, 0x0105, 1024,  768,  8, 2, 128, 48, MD_SIS300|MD_SIS315},
+	{"1024x768x16",  {0x4a,0x4a}, 0x0117, 0x0117, 1024,  768, 16, 2, 128, 48, MD_SIS300|MD_SIS315},
+	{"1024x768x24",  {0x64,0x64}, 0x013c, 0x0118, 1024,  768, 32, 2, 128, 48, MD_SIS300|MD_SIS315},
+	{"1024x768x32",  {0x64,0x64}, 0x013c, 0x0118, 1024,  768, 32, 2, 128, 48, MD_SIS300|MD_SIS315},
+	{"1152x768x8",   {0x23,0x23}, 0x0000, 0x0000, 1152,  768,  8, 1, 144, 48, MD_SIS300          },
+	{"1152x768x16",  {0x24,0x24}, 0x0000, 0x0000, 1152,  768, 16, 1, 144, 48, MD_SIS300          },
+	{"1152x768x24",  {0x25,0x25}, 0x0000, 0x0000, 1152,  768, 32, 1, 144, 48, MD_SIS300          },
+	{"1152x768x32",  {0x25,0x25}, 0x0000, 0x0000, 1152,  768, 32, 1, 144, 48, MD_SIS300          },
+	{"1152x864x8",   {0x29,0x29}, 0x0000, 0x0000, 1152,  864,  8, 1, 144, 54, MD_SIS300|MD_SIS315},
+/*80*/	{"1152x864x16",  {0x2a,0x2a}, 0x0000, 0x0000, 1152,  864, 16, 1, 144, 54, MD_SIS300|MD_SIS315},
+	{"1152x864x24",  {0x2b,0x2b}, 0x0000, 0x0000, 1152,  864, 32, 1, 144, 54, MD_SIS300|MD_SIS315},
+	{"1152x864x32",  {0x2b,0x2b}, 0x0000, 0x0000, 1152,  864, 32, 1, 144, 54, MD_SIS300|MD_SIS315},
+	{"1280x720x8",   {0x79,0x79}, 0x0000, 0x0000, 1280,  720,  8, 1, 160, 45, MD_SIS300|MD_SIS315},
+	{"1280x720x16",  {0x75,0x75}, 0x0000, 0x0000, 1280,  720, 16, 1, 160, 45, MD_SIS300|MD_SIS315},
+	{"1280x720x24",  {0x78,0x78}, 0x0000, 0x0000, 1280,  720, 32, 1, 160, 45, MD_SIS300|MD_SIS315},
+	{"1280x720x32",  {0x78,0x78}, 0x0000, 0x0000, 1280,  720, 32, 1, 160, 45, MD_SIS300|MD_SIS315},
+	{"1280x768x8",   {0x55,0x23}, 0x0000, 0x0000, 1280,  768,  8, 1, 160, 48, MD_SIS300|MD_SIS315},
+	{"1280x768x16",  {0x5a,0x24}, 0x0000, 0x0000, 1280,  768, 16, 1, 160, 48, MD_SIS300|MD_SIS315},
+	{"1280x768x24",  {0x5b,0x25}, 0x0000, 0x0000, 1280,  768, 32, 1, 160, 48, MD_SIS300|MD_SIS315},
+/*90*/	{"1280x768x32",  {0x5b,0x25}, 0x0000, 0x0000, 1280,  768, 32, 1, 160, 48, MD_SIS300|MD_SIS315},
+	{"1280x800x8",   {0x14,0x14}, 0x0000, 0x0000, 1280,  800,  8, 1, 160, 50,           MD_SIS315},
+	{"1280x800x16",  {0x15,0x15}, 0x0000, 0x0000, 1280,  800, 16, 1, 160, 50,           MD_SIS315},
+	{"1280x800x24",  {0x16,0x16}, 0x0000, 0x0000, 1280,  800, 32, 1, 160, 50,           MD_SIS315},
+	{"1280x800x32",  {0x16,0x16}, 0x0000, 0x0000, 1280,  800, 32, 1, 160, 50,           MD_SIS315},
+	{"1280x960x8",   {0x7c,0x7c}, 0x0000, 0x0000, 1280,  960,  8, 1, 160, 60, MD_SIS300|MD_SIS315},
+	{"1280x960x16",  {0x7d,0x7d}, 0x0000, 0x0000, 1280,  960, 16, 1, 160, 60, MD_SIS300|MD_SIS315},
+	{"1280x960x24",  {0x7e,0x7e}, 0x0000, 0x0000, 1280,  960, 32, 1, 160, 60, MD_SIS300|MD_SIS315},
+	{"1280x960x32",  {0x7e,0x7e}, 0x0000, 0x0000, 1280,  960, 32, 1, 160, 60, MD_SIS300|MD_SIS315},
+	{"1280x1024x8",  {0x3a,0x3a}, 0x0107, 0x0107, 1280, 1024,  8, 2, 160, 64, MD_SIS300|MD_SIS315},
+/*100*/	{"1280x1024x16", {0x4d,0x4d}, 0x011a, 0x011a, 1280, 1024, 16, 2, 160, 64, MD_SIS300|MD_SIS315},
+	{"1280x1024x24", {0x65,0x65}, 0x013d, 0x011b, 1280, 1024, 32, 2, 160, 64, MD_SIS300|MD_SIS315},
+	{"1280x1024x32", {0x65,0x65}, 0x013d, 0x011b, 1280, 1024, 32, 2, 160, 64, MD_SIS300|MD_SIS315},
+	{"1360x768x8",   {0x48,0x48}, 0x0000, 0x0000, 1360,  768,  8, 1, 170, 48, MD_SIS300|MD_SIS315},
+	{"1360x768x16",  {0x4b,0x4b}, 0x0000, 0x0000, 1360,  768, 16, 1, 170, 48, MD_SIS300|MD_SIS315},
+	{"1360x768x24",  {0x4e,0x4e}, 0x0000, 0x0000, 1360,  768, 32, 1, 170, 48, MD_SIS300|MD_SIS315},
+	{"1360x768x32",  {0x4e,0x4e}, 0x0000, 0x0000, 1360,  768, 32, 1, 170, 48, MD_SIS300|MD_SIS315},
+	{"1360x1024x8",  {0x67,0x67}, 0x0000, 0x0000, 1360, 1024,  8, 1, 170, 64, MD_SIS300          },
+	{"1360x1024x16", {0x6f,0x6f}, 0x0000, 0x0000, 1360, 1024, 16, 1, 170, 64, MD_SIS300          },
+	{"1360x1024x24", {0x72,0x72}, 0x0000, 0x0000, 1360, 1024, 32, 1, 170, 64, MD_SIS300          },
+/*110*/	{"1360x1024x32", {0x72,0x72}, 0x0000, 0x0000, 1360, 1024, 32, 1, 170, 64, MD_SIS300          },
+	{"1400x1050x8",  {0x26,0x26}, 0x0000, 0x0000, 1400, 1050,  8, 1, 175, 65,           MD_SIS315},
+	{"1400x1050x16", {0x27,0x27}, 0x0000, 0x0000, 1400, 1050, 16, 1, 175, 65,           MD_SIS315},
+	{"1400x1050x24", {0x28,0x28}, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65,           MD_SIS315},
+	{"1400x1050x32", {0x28,0x28}, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65,           MD_SIS315},
+	{"1600x1200x8",  {0x3c,0x3c}, 0x0130, 0x011c, 1600, 1200,  8, 1, 200, 75, MD_SIS300|MD_SIS315},
+	{"1600x1200x16", {0x3d,0x3d}, 0x0131, 0x011e, 1600, 1200, 16, 1, 200, 75, MD_SIS300|MD_SIS315},
+	{"1600x1200x24", {0x66,0x66}, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, MD_SIS300|MD_SIS315},
+	{"1600x1200x32", {0x66,0x66}, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, MD_SIS300|MD_SIS315},
+	{"1680x1050x8",  {0x17,0x17}, 0x0000, 0x0000, 1680, 1050,  8, 1, 210, 65,           MD_SIS315},
+/*120*/	{"1680x1050x16", {0x18,0x18}, 0x0000, 0x0000, 1680, 1050, 16, 1, 210, 65,           MD_SIS315},
+	{"1680x1050x24", {0x19,0x19}, 0x0000, 0x0000, 1680, 1050, 32, 1, 210, 65,           MD_SIS315},
+	{"1680x1050x32", {0x19,0x19}, 0x0000, 0x0000, 1680, 1050, 32, 1, 210, 65,           MD_SIS315},
+	{"1920x1080x8",  {0x2c,0x2c}, 0x0000, 0x0000, 1920, 1080,  8, 1, 240, 67,           MD_SIS315},
+	{"1920x1080x16", {0x2d,0x2d}, 0x0000, 0x0000, 1920, 1080, 16, 1, 240, 67,           MD_SIS315},
+	{"1920x1080x24", {0x73,0x73}, 0x0000, 0x0000, 1920, 1080, 32, 1, 240, 67,           MD_SIS315},
+	{"1920x1080x32", {0x73,0x73}, 0x0000, 0x0000, 1920, 1080, 32, 1, 240, 67,           MD_SIS315},
+	{"1920x1440x8",  {0x68,0x68}, 0x013f, 0x0000, 1920, 1440,  8, 1, 240, 75, MD_SIS300|MD_SIS315},
+	{"1920x1440x16", {0x69,0x69}, 0x0140, 0x0000, 1920, 1440, 16, 1, 240, 75, MD_SIS300|MD_SIS315},
+	{"1920x1440x24", {0x6b,0x6b}, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_SIS300|MD_SIS315},
+/*130*/	{"1920x1440x32", {0x6b,0x6b}, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_SIS300|MD_SIS315},
+	{"2048x1536x8",  {0x6c,0x6c}, 0x0000, 0x0000, 2048, 1536,  8, 1, 256, 96,           MD_SIS315},
+	{"2048x1536x16", {0x6d,0x6d}, 0x0000, 0x0000, 2048, 1536, 16, 1, 256, 96,           MD_SIS315},
+	{"2048x1536x24", {0x6e,0x6e}, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96,           MD_SIS315},
+	{"2048x1536x32", {0x6e,0x6e}, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96,           MD_SIS315},
+	{"\0", {0x00,0x00}, 0, 0, 0, 0, 0, 0, 0}
+};
+
+#define SIS_LCD_NUMBER 17
+static const struct _sis_lcd_data {
+	u32 lcdtype;
+	u16 xres;
+	u16 yres;
+	u8  default_mode_idx;
+} sis_lcd_data[] = {
+	{ LCD_640x480,    640,  480,  23 },
+	{ LCD_800x600,    800,  600,  43 },
+	{ LCD_1024x600,  1024,  600,  67 },
+	{ LCD_1024x768,  1024,  768,  71 },
+	{ LCD_1152x768,  1152,  768,  75 },
+	{ LCD_1152x864,  1152,  864,  79 },
+	{ LCD_1280x720,  1280,  720,  83 },
+	{ LCD_1280x768,  1280,  768,  87 },
+	{ LCD_1280x800,  1280,  800,  91 },
+	{ LCD_1280x960,  1280,  960,  95 },
+	{ LCD_1280x1024, 1280, 1024,  99 },
+	{ LCD_1400x1050, 1400, 1050, 111 },
+	{ LCD_1680x1050, 1680, 1050, 119 },
+	{ LCD_1600x1200, 1600, 1200, 115 },
+	{ LCD_640x480_2,  640,  480,  23 },
+	{ LCD_640x480_3,  640,  480,  23 },
+	{ LCD_320x480,    320,  480,   9 },
+};
+
+/* CR36 evaluation */
+static const USHORT sis300paneltype[] =
+    { LCD_UNKNOWN,   LCD_800x600,   LCD_1024x768,  LCD_1280x1024,
+      LCD_1280x960,  LCD_640x480,   LCD_1024x600,  LCD_1152x768,
+      LCD_UNKNOWN,   LCD_UNKNOWN,   LCD_UNKNOWN,   LCD_UNKNOWN,
+      LCD_UNKNOWN,   LCD_UNKNOWN,   LCD_UNKNOWN,   LCD_UNKNOWN };
+
+static const USHORT sis310paneltype[] =
+    { LCD_UNKNOWN,   LCD_800x600,   LCD_1024x768,  LCD_1280x1024,
+      LCD_640x480,   LCD_1024x600,  LCD_1152x864,  LCD_1280x960,
+      LCD_1152x768,  LCD_1400x1050, LCD_1280x768,  LCD_1600x1200,
+      LCD_640x480_2, LCD_640x480_3, LCD_UNKNOWN,   LCD_UNKNOWN };
+
+static const USHORT sis661paneltype[] =
+    { LCD_UNKNOWN,   LCD_800x600,   LCD_1024x768,  LCD_1280x1024,
+      LCD_640x480,   LCD_1024x600,  LCD_1152x864,  LCD_1280x960,
+      LCD_1152x768,  LCD_1400x1050, LCD_1280x768,  LCD_1600x1200,
+      LCD_1280x800,  LCD_1680x1050, LCD_1280x720,  LCD_UNKNOWN };
+
+#define FL_550_DSTN 0x01
+#define FL_550_FSTN 0x02
+#define FL_300      0x04
+#define FL_315      0x08
+
+static struct _sis_crt2type {
+	char name[32];
+	u32 type_no;
+	u32 tvplug_no;
+	u16 flags;
+} sis_crt2type[] __initdata = {
+	{"NONE", 	     0, 	-1,                     FL_300|FL_315},
+	{"LCD",  	     CRT2_LCD, 	-1,                     FL_300|FL_315},
+	{"TV",   	     CRT2_TV, 	-1,                     FL_300|FL_315},
+	{"VGA",  	     CRT2_VGA, 	-1,                     FL_300|FL_315},
+	{"SVIDEO", 	     CRT2_TV, 	TV_SVIDEO,              FL_300|FL_315},
+	{"COMPOSITE", 	     CRT2_TV, 	TV_AVIDEO,              FL_300|FL_315},
+	{"CVBS", 	     CRT2_TV, 	TV_AVIDEO,              FL_300|FL_315},
+	{"SVIDEO+COMPOSITE", CRT2_TV,   TV_AVIDEO|TV_SVIDEO,    FL_300|FL_315},
+	{"COMPOSITE+SVIDEO", CRT2_TV,   TV_AVIDEO|TV_SVIDEO,    FL_300|FL_315},
+	{"SVIDEO+CVBS",      CRT2_TV,   TV_AVIDEO|TV_SVIDEO,    FL_300|FL_315},
+	{"CVBS+SVIDEO",      CRT2_TV,   TV_AVIDEO|TV_SVIDEO,    FL_300|FL_315},
+	{"SCART", 	     CRT2_TV, 	TV_SCART,               FL_300|FL_315},
+	{"HIVISION",	     CRT2_TV,   TV_HIVISION,            FL_315},
+	{"YPBPR480I",	     CRT2_TV,   TV_YPBPR|TV_YPBPR525I,  FL_315},
+	{"YPBPR480P",	     CRT2_TV,   TV_YPBPR|TV_YPBPR525P,  FL_315},
+	{"YPBPR720P",	     CRT2_TV,   TV_YPBPR|TV_YPBPR750P,  FL_315},
+	{"YPBPR1080I",	     CRT2_TV,   TV_YPBPR|TV_YPBPR1080I, FL_315},
+	{"DSTN",             CRT2_LCD,  -1,                     FL_315|FL_550_DSTN},
+	{"FSTN",             CRT2_LCD,  -1,                     FL_315|FL_550_FSTN},
+	{"\0",  	     -1, 	-1,                     0}
+};
+
+/* TV standard */
+static struct _sis_tvtype {
+	char name[6];
+	u32 type_no;
+} sis_tvtype[] __initdata = {
+	{"PAL",  	TV_PAL},
+	{"NTSC", 	TV_NTSC},
+	{"PALM",  	TV_PAL|TV_PALM},
+	{"PALN",  	TV_PAL|TV_PALN},
+	{"NTSCJ",  	TV_NTSC|TV_NTSCJ},
+	{"\0",   	-1}
+};
+
+static const struct _sis_vrate {
+	u16 idx;
+	u16 xres;
+	u16 yres;
+	u16 refresh;
+	BOOLEAN SiS730valid32bpp;
+} sisfb_vrate[] = {
+	{1,  320,  200,  70,  TRUE},
+	{1,  320,  240,  60,  TRUE},
+	{1,  320,  480,  60,  TRUE},
+	{1,  400,  300,  60,  TRUE},
+	{1,  512,  384,  60,  TRUE},
+	{1,  640,  400,  72,  TRUE},
+	{1,  640,  480,  60,  TRUE}, {2,  640,  480,  72,  TRUE}, {3,  640,  480,  75,  TRUE},
+	{4,  640,  480,  85,  TRUE}, {5,  640,  480, 100,  TRUE}, {6,  640,  480, 120,  TRUE},
+	{7,  640,  480, 160,  TRUE}, {8,  640,  480, 200,  TRUE},
+	{1,  720,  480,  60,  TRUE},
+	{1,  720,  576,  58,  TRUE},
+	{1,  768,  576,  58,  TRUE},
+	{1,  800,  480,  60,  TRUE}, {2,  800,  480,  75,  TRUE}, {3,  800,  480,  85,  TRUE},
+	{1,  800,  600,  56,  TRUE}, {2,  800,  600,  60,  TRUE}, {3,  800,  600,  72,  TRUE},
+	{4,  800,  600,  75,  TRUE}, {5,  800,  600,  85,  TRUE}, {6,  800,  600, 105,  TRUE},
+	{7,  800,  600, 120,  TRUE}, {8,  800,  600, 160,  TRUE},
+	{1,  848,  480,  39,  TRUE}, {2,  848,  480,  60,  TRUE},
+	{1,  856,  480,  39,  TRUE}, {2,  856,  480,  60,  TRUE},
+	{1,  960,  540,  60,  TRUE},
+	{1,  960,  600,  60,  TRUE},
+	{1, 1024,  576,  60,  TRUE}, {2, 1024,  576,  75,  TRUE}, {3, 1024,  576,  85,  TRUE},
+	{1, 1024,  600,  60,  TRUE},
+	{1, 1024,  768,  43,  TRUE}, {2, 1024,  768,  60,  TRUE}, {3, 1024,  768,  70, FALSE},
+	{4, 1024,  768,  75, FALSE}, {5, 1024,  768,  85,  TRUE}, {6, 1024,  768, 100,  TRUE},
+	{7, 1024,  768, 120,  TRUE},
+	{1, 1152,  768,  60,  TRUE},
+	{1, 1152,  864,  60,  TRUE}, {1, 1152,  864,  75,  TRUE}, {2, 1152,  864,  84,  TRUE},
+	{1, 1280,  720,  60,  TRUE}, {2, 1280,  720,  75,  TRUE}, {3, 1280,  720,  85,  TRUE},
+	{1, 1280,  768,  60,  TRUE},
+	{1, 1280,  800,  60,  TRUE},
+	{1, 1280,  960,  60,  TRUE}, {2, 1280,  960,  85,  TRUE},
+	{1, 1280, 1024,  43,  TRUE}, {2, 1280, 1024,  60,  TRUE}, {3, 1280, 1024,  75,  TRUE},
+	{4, 1280, 1024,  85,  TRUE},
+	{1, 1360,  768,  60,  TRUE},
+	{1, 1360, 1024,  59,  TRUE},
+	{1, 1400, 1050,  60,  TRUE}, {2, 1400, 1050,  75,  TRUE},
+	{1, 1600, 1200,  60,  TRUE}, {2, 1600, 1200,  65,  TRUE}, {3, 1600, 1200,  70,  TRUE},
+	{4, 1600, 1200,  75,  TRUE}, {5, 1600, 1200,  85,  TRUE}, {6, 1600, 1200, 100,  TRUE},
+	{7, 1600, 1200, 120,  TRUE},
+	{1, 1680, 1050,  60,  TRUE},
+	{1, 1920, 1080,  30,  TRUE},
+	{1, 1920, 1440,  60,  TRUE}, {2, 1920, 1440,  65,  TRUE}, {3, 1920, 1440,  70,  TRUE},
+	{4, 1920, 1440,  75,  TRUE}, {5, 1920, 1440,  85,  TRUE}, {6, 1920, 1440, 100,  TRUE},
+	{1, 2048, 1536,  60,  TRUE}, {2, 2048, 1536,  65,  TRUE}, {3, 2048, 1536,  70,  TRUE},
+	{4, 2048, 1536,  75,  TRUE}, {5, 2048, 1536,  85,  TRUE},
+	{0,    0,    0,   0, FALSE}
+};
+
+static const struct _sisfbddcsmodes {
+	u32 mask;
+	u16 h;
+	u16 v;
+	u32 d;
+} sisfb_ddcsmodes[] = {
+	{ 0x10000, 67, 75, 108000},
+	{ 0x08000, 48, 72,  50000},
+	{ 0x04000, 46, 75,  49500},
+	{ 0x01000, 35, 43,  44900},
+	{ 0x00800, 48, 60,  65000},
+	{ 0x00400, 56, 70,  75000},
+	{ 0x00200, 60, 75,  78800},
+	{ 0x00100, 80, 75, 135000},
+	{ 0x00020, 31, 60,  25200},
+	{ 0x00008, 38, 72,  31500},
+	{ 0x00004, 37, 75,  31500},
+	{ 0x00002, 35, 56,  36000},
+	{ 0x00001, 38, 60,  40000}
+};
+
+static const struct _sisfbddcfmodes {
+	u16 x;
+	u16 y;
+	u16 v;
+	u16 h;
+	u32 d;
+} sisfb_ddcfmodes[] = {
+       { 1280, 1024, 85, 92, 157500},
+       { 1600, 1200, 60, 75, 162000},
+       { 1600, 1200, 65, 82, 175500},
+       { 1600, 1200, 70, 88, 189000},
+       { 1600, 1200, 75, 94, 202500},
+       { 1600, 1200, 85, 107,229500},
+       { 1920, 1440, 60, 90, 234000},
+       { 1920, 1440, 75, 113,297000}
+};
+
+#ifdef CONFIG_FB_SIS_300
+static struct _chswtable {
+    u16  subsysVendor;
+    u16  subsysCard;
+    char *vendorName;
+    char *cardName;
+} mychswtable[] __devinitdata = {
+        { 0x1631, 0x1002, "Mitachi", "0x1002" },
+	{ 0x1071, 0x7521, "Mitac"  , "7521P"  },
+	{ 0,      0,      ""       , ""       }
+};
+#endif
+
+static struct _customttable {
+    u16   chipID;
+    char  *biosversion;
+    char  *biosdate;
+    u32   bioschksum;
+    u16   biosFootprintAddr[5];
+    u8    biosFootprintData[5];
+    u16   pcisubsysvendor;
+    u16   pcisubsyscard;
+    char  *vendorName;
+    char  *cardName;
+    u32   SpecialID;
+    char  *optionName;
+} mycustomttable[] __devinitdata = {
+	{ SIS_630, "2.00.07", "09/27/2002-13:38:25",
+	  0x3240A8,
+	  { 0x220, 0x227, 0x228, 0x229, 0x0ee },
+	  {  0x01,  0xe3,  0x9a,  0x6a,  0xef },
+	  0x1039, 0x6300,
+	  "Barco", "iQ R200L/300/400", CUT_BARCO1366, "BARCO_1366"
+	},
+	{ SIS_630, "2.00.07", "09/27/2002-13:38:25",
+	  0x323FBD,
+	  { 0x220, 0x227, 0x228, 0x229, 0x0ee },
+	  {  0x00,  0x5a,  0x64,  0x41,  0xef },
+	  0x1039, 0x6300,
+	  "Barco", "iQ G200L/300/400/500", CUT_BARCO1024, "BARCO_1024"
+	},
+	{ SIS_650, "", "",
+	  0,
+	  { 0, 0, 0, 0, 0 },
+	  { 0, 0, 0, 0, 0 },
+	  0x0e11, 0x083c,
+	  "Inventec (Compaq)", "3017cl/3045US", CUT_COMPAQ12802, "COMPAQ_1280"
+	},
+	{ SIS_650, "", "",
+	  0,
+	  { 0x00c, 0, 0, 0, 0 },
+	  { 'e'  , 0, 0, 0, 0 },
+	  0x1558, 0x0287,
+	  "Clevo", "L285/L287 (Version 1)", CUT_CLEVO1024, "CLEVO_L28X_1"
+	},
+	{ SIS_650, "", "",
+	  0,
+	  { 0x00c, 0, 0, 0, 0 },
+	  { 'y'  , 0, 0, 0, 0 },
+	  0x1558, 0x0287,
+	  "Clevo", "L285/L287 (Version 2)", CUT_CLEVO10242, "CLEVO_L28X_2"
+	},
+	{ SIS_650, "", "",
+	  0,
+	  { 0, 0, 0, 0, 0 },
+	  { 0, 0, 0, 0, 0 },
+	  0x1558, 0x0400,  /* possibly 401 and 402 as well; not panelsize specific (?) */
+	  "Clevo", "D400S/D410S/D400H/D410H", CUT_CLEVO1400, "CLEVO_D4X0"
+	},
+	{ SIS_650, "", "",
+	  0,	/* Shift LCD in LCD-via-CRT1 mode */
+	  { 0, 0, 0, 0, 0 },
+	  { 0, 0, 0, 0, 0 },
+	  0x1558, 0x2263,
+	  "Clevo", "D22ES/D27ES", CUT_UNIWILL1024, "CLEVO_D2X0ES"
+	},
+	{ SIS_650, "", "",
+	  0,	/* Shift LCD in LCD-via-CRT1 mode */
+	  { 0, 0, 0, 0, 0 },
+	  { 0, 0, 0, 0, 0 },
+	  0x1734, 0x101f,
+	  "Uniwill", "N243S9", CUT_UNIWILL1024, "UNIWILL_N243S9"
+	},
+	{ SIS_650, "", "",
+	  0,	/* Shift LCD in LCD-via-CRT1 mode */
+	  { 0, 0, 0, 0, 0 },
+	  { 0, 0, 0, 0, 0 },
+	  0x1584, 0x5103,
+	  "Uniwill", "N35BS1", CUT_UNIWILL10242, "UNIWILL_N35BS1"
+	},
+	{ SIS_650, "1.09.2c", "",  /* Other versions, too? */
+	  0,	/* Shift LCD in LCD-via-CRT1 mode */
+	  { 0, 0, 0, 0, 0 },
+	  { 0, 0, 0, 0, 0 },
+	  0x1019, 0x0f05,
+	  "ECS", "A928", CUT_UNIWILL1024, "ECS_A928"
+	},
+	{ SIS_740, "1.11.27a", "",
+	  0,
+	  { 0, 0, 0, 0, 0 },
+	  { 0, 0, 0, 0, 0 },
+	  0x1043, 0x1612,
+	  "Asus", "L3000D/L3500D", CUT_ASUSL3000D, "ASUS_L3X00"
+	},
+	{ SIS_650, "1.10.9k", "",
+	  0,
+	  { 0, 0, 0, 0, 0 },
+	  { 0, 0, 0, 0, 0 },
+	  0x1025, 0x0028,
+	  "Acer", "Aspire 1700", CUT_ACER1280, "ACER_ASPIRE1700"
+	},
+	{ SIS_650, "1.10.7w", "",
+	  0,
+	  { 0, 0, 0, 0, 0 },
+	  { 0, 0, 0, 0, 0 },
+	  0x14c0, 0x0012,
+	  "Compal", "??? (V1)", CUT_COMPAL1400_1, "COMPAL_1400_1"
+	},
+	{ SIS_650, "1.10.7x", "",
+	  0,
+	  { 0, 0, 0, 0, 0 },
+	  { 0, 0, 0, 0, 0 },
+	  0x14c0, 0x0012,
+	  "Compal", "??? (V2)", CUT_COMPAL1400_2, "COMPAL_1400_2"
+	},
+	{ SIS_650, "1.10.8o", "",
+	  0,	/* For EMI (unknown) */
+	  { 0, 0, 0, 0, 0 },
+	  { 0, 0, 0, 0, 0 },
+	  0x1043, 0x1612,
+	  "Asus", "A2H (V1)", CUT_ASUSA2H_1, "ASUS_A2H_1"
+	},
+	{ SIS_650, "1.10.8q", "",
+	  0,	/* For EMI */
+	  { 0, 0, 0, 0, 0 },
+	  { 0, 0, 0, 0, 0 },
+	  0x1043, 0x1612,
+	  "Asus", "A2H (V2)", CUT_ASUSA2H_2, "ASUS_A2H_2"
+	},
+	{ 4321, "", "",			/* never autodetected */
+	  0,
+	  { 0, 0, 0, 0, 0 },
+	  { 0, 0, 0, 0, 0 },
+	  0, 0,
+	  "Generic", "LVDS/Parallel 848x480", CUT_PANEL848, "PANEL848x480"
+	},
+	{ 0, "", "",
+	  0,
+	  { 0, 0, 0, 0 },
+	  { 0, 0, 0, 0 },
+	  0, 0,
+	  "", "", CUT_NONE, ""
+	}
+};
+
+static const struct _sis_TV_filter {
+	u8 filter[9][4];
+} sis_TV_filter[] = {
+	{ {{0x00,0x00,0x00,0x40},  /* NTSCFilter_0 */
+	   {0x00,0xE0,0x10,0x60},
+	   {0x00,0xEE,0x10,0x44},
+	   {0x00,0xF4,0x10,0x38},
+	   {0xF8,0xF4,0x18,0x38},
+	   {0xFC,0xFB,0x14,0x2A},
+	   {0x00,0x00,0x10,0x20},
+	   {0x00,0x04,0x10,0x18}, 
+	   {0xFF,0xFF,0xFF,0xFF} }},
+	{ {{0x00,0x00,0x00,0x40},  /* NTSCFilter_1 */
+	   {0x00,0xE0,0x10,0x60},
+	   {0x00,0xEE,0x10,0x44},
+	   {0x00,0xF4,0x10,0x38},
+	   {0xF8,0xF4,0x18,0x38},
+	   {0xFC,0xFB,0x14,0x2A},
+	   {0x00,0x00,0x10,0x20},
+	   {0x00,0x04,0x10,0x18},
+	   {0xFF,0xFF,0xFF,0xFF} }},
+	{ {{0x00,0x00,0x00,0x40},  /* NTSCFilter_2 */
+	   {0xF5,0xEE,0x1B,0x44},
+	   {0xF8,0xF4,0x18,0x38},
+	   {0xEB,0x04,0x25,0x18},
+	   {0xF1,0x05,0x1F,0x16},
+	   {0xF6,0x06,0x1A,0x14},
+	   {0xFA,0x06,0x16,0x14},
+	   {0x00,0x04,0x10,0x18}, 
+	   {0xFF,0xFF,0xFF,0xFF} }},
+	{ {{0x00,0x00,0x00,0x40},  /* NTSCFilter_3 */
+	   {0xF1,0x04,0x1F,0x18},
+	   {0xEE,0x0D,0x22,0x06},
+	   {0xF7,0x06,0x19,0x14},
+	   {0xF4,0x0B,0x1C,0x0A},
+	   {0xFA,0x07,0x16,0x12},
+	   {0xF9,0x0A,0x17,0x0C},
+	   {0x00,0x07,0x10,0x12}, 
+	   {0xFF,0xFF,0xFF,0xFF} }},
+	{ {{0x00,0x00,0x00,0x40},  /* NTSCFilter_4 - 320 */
+	   {0x00,0xE0,0x10,0x60},
+	   {0x00,0xEE,0x10,0x44},
+	   {0x00,0xF4,0x10,0x38},
+	   {0xF8,0xF4,0x18,0x38},
+	   {0xFC,0xFB,0x14,0x2A},
+	   {0x00,0x00,0x10,0x20},
+	   {0x00,0x04,0x10,0x18}, 
+	   {0xFF,0xFF,0xFF,0xFF} }},
+	{ {{0x00,0x00,0x00,0x40},  /* NTSCFilter_5 - 640 */
+	   {0xF5,0xEE,0x1B,0x44},
+	   {0xF8,0xF4,0x18,0x38},
+	   {0xEB,0x04,0x25,0x18},
+	   {0xF1,0x05,0x1F,0x16},
+	   {0xF6,0x06,0x1A,0x14},
+	   {0xFA,0x06,0x16,0x14},
+	   {0x00,0x04,0x10,0x18}, 
+	   {0xFF,0xFF,0xFF,0xFF} }},
+	{ {{0x00,0x00,0x00,0x40},  /* NTSCFilter_6 - 720 */
+	   {0xEB,0x04,0x25,0x18},
+	   {0xE7,0x0E,0x29,0x04},
+	   {0xEE,0x0C,0x22,0x08},
+	   {0xF6,0x0B,0x1A,0x0A},
+	   {0xF9,0x0A,0x17,0x0C},
+	   {0xFC,0x0A,0x14,0x0C},
+	   {0x00,0x08,0x10,0x10}, 
+	   {0xFF,0xFF,0xFF,0xFF} }},
+	{ {{0x00,0x00,0x00,0x40},  /* NTSCFilter_7 - 800 */
+	   {0xEC,0x02,0x24,0x1C},
+	   {0xF2,0x04,0x1E,0x18},
+	   {0xEB,0x15,0x25,0xF6},
+	   {0xF4,0x10,0x1C,0x00},
+	   {0xF8,0x0F,0x18,0x02},
+	   {0x00,0x04,0x10,0x18},
+	   {0x01,0x06,0x0F,0x14}, 
+	   {0xFF,0xFF,0xFF,0xFF} }},
+	{ {{0x00,0x00,0x00,0x40},  /* PALFilter_0 */
+	   {0x00,0xE0,0x10,0x60},
+	   {0x00,0xEE,0x10,0x44},
+	   {0x00,0xF4,0x10,0x38},
+	   {0xF8,0xF4,0x18,0x38},
+	   {0xFC,0xFB,0x14,0x2A},
+	   {0x00,0x00,0x10,0x20},
+	   {0x00,0x04,0x10,0x18}, 
+	   {0xFF,0xFF,0xFF,0xFF} }},
+	{ {{0x00,0x00,0x00,0x40},  /* PALFilter_1 */
+	   {0x00,0xE0,0x10,0x60},
+	   {0x00,0xEE,0x10,0x44},
+	   {0x00,0xF4,0x10,0x38},
+	   {0xF8,0xF4,0x18,0x38},
+	   {0xFC,0xFB,0x14,0x2A},
+	   {0x00,0x00,0x10,0x20},
+	   {0x00,0x04,0x10,0x18}, 
+	   {0xFF,0xFF,0xFF,0xFF} }},
+	{ {{0x00,0x00,0x00,0x40},  /* PALFilter_2 */
+	   {0xF5,0xEE,0x1B,0x44},
+	   {0xF8,0xF4,0x18,0x38},
+	   {0xF1,0xF7,0x01,0x32},
+	   {0xF5,0xFB,0x1B,0x2A},
+	   {0xF9,0xFF,0x17,0x22},
+	   {0xFB,0x01,0x15,0x1E},
+	   {0x00,0x04,0x10,0x18}, 
+	   {0xFF,0xFF,0xFF,0xFF} }},
+	{ {{0x00,0x00,0x00,0x40},  /* PALFilter_3 */
+	   {0xF5,0xFB,0x1B,0x2A},
+	   {0xEE,0xFE,0x22,0x24},
+	   {0xF3,0x00,0x1D,0x20},
+	   {0xF9,0x03,0x17,0x1A},
+	   {0xFB,0x02,0x14,0x1E},
+	   {0xFB,0x04,0x15,0x18},
+	   {0x00,0x06,0x10,0x14}, 
+	   {0xFF,0xFF,0xFF,0xFF} }},
+	{ {{0x00,0x00,0x00,0x40},  /* PALFilter_4 - 320 */
+	   {0x00,0xE0,0x10,0x60},
+	   {0x00,0xEE,0x10,0x44},
+	   {0x00,0xF4,0x10,0x38},
+	   {0xF8,0xF4,0x18,0x38},
+	   {0xFC,0xFB,0x14,0x2A},
+	   {0x00,0x00,0x10,0x20},
+	   {0x00,0x04,0x10,0x18}, 
+	   {0xFF,0xFF,0xFF,0xFF} }},
+	{ {{0x00,0x00,0x00,0x40},  /* PALFilter_5 - 640 */
+	   {0xF5,0xEE,0x1B,0x44},
+	   {0xF8,0xF4,0x18,0x38},
+	   {0xF1,0xF7,0x1F,0x32},
+	   {0xF5,0xFB,0x1B,0x2A},
+	   {0xF9,0xFF,0x17,0x22},
+	   {0xFB,0x01,0x15,0x1E},
+	   {0x00,0x04,0x10,0x18}, 
+	   {0xFF,0xFF,0xFF,0xFF} }},
+	{ {{0x00,0x00,0x00,0x40},  /* PALFilter_6 - 720 */
+	   {0xF5,0xEE,0x1B,0x2A},
+	   {0xEE,0xFE,0x22,0x24},
+	   {0xF3,0x00,0x1D,0x20},
+	   {0xF9,0x03,0x17,0x1A},
+	   {0xFB,0x02,0x14,0x1E},
+	   {0xFB,0x04,0x15,0x18},
+	   {0x00,0x06,0x10,0x14}, 
+	   {0xFF,0xFF,0xFF,0xFF} }},
+	{ {{0x00,0x00,0x00,0x40},  /* PALFilter_7 - 800 */
+	   {0xF5,0xEE,0x1B,0x44},
+	   {0xF8,0xF4,0x18,0x38},
+	   {0xFC,0xFB,0x14,0x2A},
+	   {0xEB,0x05,0x25,0x16},
+	   {0xF1,0x05,0x1F,0x16},
+	   {0xFA,0x07,0x16,0x12},
+	   {0x00,0x07,0x10,0x12}, 
+	   {0xFF,0xFF,0xFF,0xFF} }}
+};
+
+/* ---------------------- Prototypes ------------------------- */
+
+/* Interface used by the world */
+#ifndef MODULE
+SISINITSTATIC int sisfb_setup(char *options);
+#endif
+
+/* Interface to the low level console driver */
+SISINITSTATIC int sisfb_init(void);
+
+
+/* fbdev routines */
+static int      sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			      struct fb_info *info);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+static int      sisfb_get_fix(struct fb_fix_screeninfo *fix, 
+			      int con,
+			      struct fb_info *info);
+static int      sisfb_get_var(struct fb_var_screeninfo *var, 
+			      int con,
+			      struct fb_info *info);
+static int      sisfb_set_var(struct fb_var_screeninfo *var, 
+			      int con,
+			      struct fb_info *info);
+static void     sisfb_crtc_to_var(struct sis_video_info *ivideo,
+			          struct fb_var_screeninfo *var);
+static int      sisfb_get_cmap(struct fb_cmap *cmap, 
+			       int kspc, 
+			       int con,
+			       struct fb_info *info);
+static int      sisfb_set_cmap(struct fb_cmap *cmap, 
+			       int kspc, 
+			       int con,
+			       struct fb_info *info);			
+static int      sisfb_update_var(int con, 
+				 struct fb_info *info);
+static int      sisfb_switch(int con, 
+			     struct fb_info *info);
+static void     sisfb_blank(int blank, 
+			    struct fb_info *info);
+static void     sisfb_set_disp(int con, 
+			       struct fb_var_screeninfo *var, 
+                               struct fb_info *info);
+static int      sis_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+			      unsigned *blue, unsigned *transp,
+			      struct fb_info *fb_info);
+static void     sisfb_do_install_cmap(int con, 
+                                      struct fb_info *info);
+static int      sisfb_ioctl(struct inode *inode, struct file *file,
+		       	    unsigned int cmd, unsigned long arg, int con,
+		       	    struct fb_info *info);		      
+#endif			
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+static int      sisfb_ioctl(struct inode *inode, struct file *file,
+		       	    unsigned int cmd, unsigned long arg,
+		       	    struct fb_info *info);
+static int      sisfb_set_par(struct fb_info *info);
+static int      sisfb_blank(int blank, 
+                            struct fb_info *info);			
+extern void     fbcon_sis_fillrect(struct fb_info *info, 
+                                   const struct fb_fillrect *rect);
+extern void     fbcon_sis_copyarea(struct fb_info *info, 
+                                   const struct fb_copyarea *area);
+extern int      fbcon_sis_sync(struct fb_info *info);
+#endif
+			
+/* Internal 2D accelerator functions */
+extern int      sisfb_initaccel(struct sis_video_info *ivideo);
+extern void     sisfb_syncaccel(struct sis_video_info *ivideo);
+
+/* Internal general routines */
+static void     sisfb_search_mode(char *name, BOOLEAN quiet);
+static int      sisfb_validate_mode(struct sis_video_info *ivideo, int modeindex, u32 vbflags);
+static u8       sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate,
+			int index);
+static int      sisfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			unsigned blue, unsigned transp,
+			struct fb_info *fb_info);
+static int      sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
+		      	struct fb_info *info);
+static void     sisfb_pre_setmode(struct sis_video_info *ivideo);
+static void     sisfb_post_setmode(struct sis_video_info *ivideo);
+static BOOLEAN  sisfb_CheckVBRetrace(struct sis_video_info *ivideo);
+static BOOLEAN  sisfbcheckvretracecrt2(struct sis_video_info *ivideo);
+static BOOLEAN  sisfbcheckvretracecrt1(struct sis_video_info *ivideo);
+static BOOLEAN  sisfb_bridgeisslave(struct sis_video_info *ivideo);
+static void     sisfb_detect_VB_connect(struct sis_video_info *ivideo);
+static void     sisfb_get_VB_type(struct sis_video_info *ivideo);
+static void     sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val);
+static void     sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val);
+
+/* SiS-specific exported functions */
+void            sis_malloc(struct sis_memreq *req);
+void            sis_free(u32 base);
+
+/* Internal heap routines */
+static int      sisfb_heap_init(struct sis_video_info *ivideo);
+static SIS_OH   *sisfb_poh_new_node(void);
+static SIS_OH   *sisfb_poh_allocate(u32 size);
+static void     sisfb_delete_node(SIS_OH *poh);
+static void     sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh);
+static SIS_OH   *sisfb_poh_free(u32 base);
+static void     sisfb_free_node(SIS_OH *poh);
+
+/* Sensing routines */
+static void     SiS_Sense30x(struct sis_video_info *ivideo);
+static void     SiS_SenseCh(struct sis_video_info *ivideo);
+
+/* Routines from init.c/init301.c */
+extern USHORT   SiS_GetModeID_LCD(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth,
+                                  BOOLEAN FSTN, USHORT CustomT, int LCDwith, int LCDheight);
+extern USHORT   SiS_GetModeID_TV(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth);
+extern USHORT   SiS_GetModeID_VGA2(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth);
+
+extern void 	SiSRegInit(SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr);
+extern BOOLEAN  SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceInfo, USHORT ModeNo);
+extern void     SiS_SetEnableDstn(SiS_Private *SiS_Pr, int enable);
+extern void     SiS_SetEnableFstn(SiS_Private *SiS_Pr, int enable);
+
+extern BOOLEAN  SiSDetermineROMLayout661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
+
+extern BOOLEAN  sisfb_gettotalfrommode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceExtension,
+		       unsigned char modeno, int *htotal, int *vtotal, unsigned char rateindex);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+extern int	sisfb_mode_rate_to_dclock(SiS_Private *SiS_Pr,
+		    	PSIS_HW_INFO HwDeviceExtension,
+			unsigned char modeno, unsigned char rateindex);
+extern int      sisfb_mode_rate_to_ddata(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceExtension,
+			unsigned char modeno, unsigned char rateindex,
+			struct fb_var_screeninfo *var);
+#endif
+
+/* Chrontel TV, DDC and DPMS functions */
+extern USHORT 	SiS_GetCH700x(SiS_Private *SiS_Pr, USHORT tempbx);
+extern void 	SiS_SetCH700x(SiS_Private *SiS_Pr, USHORT tempbx);
+extern USHORT 	SiS_GetCH701x(SiS_Private *SiS_Pr, USHORT tempbx);
+extern void 	SiS_SetCH701x(SiS_Private *SiS_Pr, USHORT tempbx);
+extern void     SiS_SetCH70xxANDOR(SiS_Private *SiS_Pr, USHORT tempax,USHORT tempbh);
+extern void     SiS_DDC2Delay(SiS_Private *SiS_Pr, USHORT delaytime);
+extern void     SiS_SetChrontelGPIO(SiS_Private *SiS_Pr, USHORT myvbinfo);
+extern USHORT   SiS_HandleDDC(SiS_Private *SiS_Pr, ULONG VBFlags, int VGAEngine,
+		              USHORT adaptnum, USHORT DDCdatatype, unsigned char *buffer);
+extern USHORT   SiS_ReadDDC1Bit(SiS_Private *SiS_Pr);
+extern void 	SiS_Chrontel701xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceInfo);
+extern void 	SiS_Chrontel701xBLOff(SiS_Private *SiS_Pr);
+extern void 	SiS_SiS30xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceInfo);
+extern void 	SiS_SiS30xBLOff(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceInfo);
+#endif
+
+
diff --git a/drivers/video/sis/vgatypes.h b/drivers/video/sis/vgatypes.h
new file mode 100644
index 0000000..507bba1
--- /dev/null
+++ b/drivers/video/sis/vgatypes.h
@@ -0,0 +1,242 @@
+/* $XFree86$ */
+/* $XdotOrg$ */
+/*
+ * General type definitions for universal mode switching modules
+ *
+ * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, the following license terms
+ * apply:
+ *
+ * * This program is free software; you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License as published by
+ * * the Free Software Foundation; either version 2 of the named License,
+ * * or any later version.
+ * *
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details.
+ * *
+ * * You should have received a copy of the GNU General Public License
+ * * along with this program; if not, write to the Free Software
+ * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * * Redistribution and use in source and binary forms, with or without
+ * * modification, are permitted provided that the following conditions
+ * * are met:
+ * * 1) Redistributions of source code must retain the above copyright
+ * *    notice, this list of conditions and the following disclaimer.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * *    notice, this list of conditions and the following disclaimer in the
+ * *    documentation and/or other materials provided with the distribution.
+ * * 3) The name of the author may not be used to endorse or promote products
+ * *    derived from this software without specific prior written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ */
+
+#ifndef _VGATYPES_
+#define _VGATYPES_
+
+#ifdef LINUX_KERNEL  /* We don't want the X driver to depend on kernel source */
+#include <linux/ioctl.h>
+#include <linux/version.h>
+#endif
+
+#ifndef FALSE
+#define FALSE   0
+#endif
+
+#ifndef TRUE
+#define TRUE    1
+#endif
+
+#ifndef NULL
+#define NULL    0
+#endif
+
+#ifndef CHAR
+typedef char CHAR;
+#endif
+
+#ifndef SHORT
+typedef short SHORT;
+#endif
+
+#ifndef LONG
+typedef long  LONG;
+#endif
+
+#ifndef UCHAR
+typedef unsigned char UCHAR;
+#endif
+
+#ifndef USHORT
+typedef unsigned short USHORT;
+#endif
+
+#ifndef ULONG
+typedef unsigned long ULONG;
+#endif
+
+#ifndef BOOLEAN
+typedef unsigned char BOOLEAN;
+#endif
+
+#define SISIOMEMTYPE
+
+#ifdef LINUX_KERNEL
+typedef unsigned long SISIOADDRESS;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
+#include <linux/types.h>  /* Need __iomem */
+#undef SISIOMEMTYPE
+#define SISIOMEMTYPE __iomem
+#endif
+#endif
+
+#ifdef LINUX_XF86
+#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,0,0,0)
+typedef unsigned long IOADDRESS;
+typedef unsigned long SISIOADDRESS;
+#else
+typedef IOADDRESS SISIOADDRESS;
+#endif
+#endif
+
+enum _SIS_CHIP_TYPE {
+    SIS_VGALegacy = 0,
+    SIS_530,
+    SIS_OLD,
+    SIS_300,
+    SIS_630,
+    SIS_730,
+    SIS_540,
+    SIS_315H,   /* SiS 310 */
+    SIS_315,
+    SIS_315PRO,
+    SIS_550,
+    SIS_650,
+    SIS_740,
+    SIS_330,
+    SIS_661,
+    SIS_741,
+    SIS_660,
+    SIS_760,
+    SIS_761,
+    SIS_340,
+    MAX_SIS_CHIP
+};
+
+#ifndef SIS_HW_INFO
+typedef struct _SIS_HW_INFO  SIS_HW_INFO, *PSIS_HW_INFO;
+
+struct _SIS_HW_INFO
+{
+#ifdef LINUX_XF86
+    PCITAG PciTag;		 /* PCI Tag */
+#endif
+
+    UCHAR *pjVirtualRomBase;	 /* ROM image */
+
+    BOOLEAN UseROM;		 /* Use the ROM image if provided */
+
+#ifdef LINUX_KERNEL
+    UCHAR SISIOMEMTYPE *pjVideoMemoryAddress;
+    				 /* base virtual memory address */
+                                 /* of Linear VGA memory */
+
+    ULONG  ulVideoMemorySize;    /* size, in bytes, of the memory on the board */
+#endif
+
+    SISIOADDRESS ulIOAddress;    /* base I/O address of VGA ports (0x3B0; relocated) */
+
+    UCHAR  jChipType;            /* Used to Identify SiS Graphics Chip */
+                                 /* defined in the enum "SIS_CHIP_TYPE" (above or sisfb.h) */
+
+    UCHAR  jChipRevision;        /* Used to Identify SiS Graphics Chip Revision */
+
+    BOOLEAN bIntegratedMMEnabled;/* supporting integration MM enable */
+};
+#endif
+
+/* Addtional IOCTLs for communication sisfb <> X driver        */
+/* If changing this, sisfb.h must also be changed (for sisfb) */
+
+#ifdef LINUX_XF86  /* We don't want the X driver to depend on the kernel source */
+
+/* ioctl for identifying and giving some info (esp. memory heap start) */
+#define SISFB_GET_INFO_SIZE	0x8004f300
+#define SISFB_GET_INFO		0x8000f301  /* Must be patched with result from ..._SIZE at D[29:16] */
+/* deprecated ioctl number (for older versions of sisfb) */
+#define SISFB_GET_INFO_OLD    	0x80046ef8
+
+/* ioctls for tv parameters (position) */
+#define SISFB_SET_TVPOSOFFSET   0x4004f304
+
+/* lock sisfb from register access */
+#define SISFB_SET_LOCK		0x4004f306
+
+/* Structure argument for SISFB_GET_INFO ioctl  */
+typedef struct _SISFB_INFO sisfb_info, *psisfb_info;
+
+struct _SISFB_INFO {
+	CARD32 	sisfb_id;         	/* for identifying sisfb */
+#ifndef SISFB_ID
+#define SISFB_ID	  0x53495346    /* Identify myself with 'SISF' */
+#endif
+ 	CARD32 	chip_id;		/* PCI ID of detected chip */
+	CARD32	memory;			/* video memory in KB which sisfb manages */
+	CARD32	heapstart;             	/* heap start (= sisfb "mem" argument) in KB */
+	CARD8 	fbvidmode;		/* current sisfb mode */
+
+	CARD8 	sisfb_version;
+	CARD8	sisfb_revision;
+	CARD8 	sisfb_patchlevel;
+
+	CARD8 	sisfb_caps;		/* sisfb's capabilities */
+
+	CARD32 	sisfb_tqlen;		/* turbo queue length (in KB) */
+
+	CARD32 	sisfb_pcibus;      	/* The card's PCI ID */
+	CARD32 	sisfb_pcislot;
+	CARD32 	sisfb_pcifunc;
+
+	CARD8 	sisfb_lcdpdc;
+
+	CARD8	sisfb_lcda;
+
+	CARD32	sisfb_vbflags;
+	CARD32	sisfb_currentvbflags;
+
+	CARD32 	sisfb_scalelcd;
+	CARD32 	sisfb_specialtiming;
+
+	CARD8 	sisfb_haveemi;
+	CARD8 	sisfb_emi30,sisfb_emi31,sisfb_emi32,sisfb_emi33;
+	CARD8 	sisfb_haveemilcd;
+
+	CARD8 	sisfb_lcdpdca;
+
+	CARD16  sisfb_tvxpos, sisfb_tvypos;  	/* Warning: Values + 32 ! */
+
+	CARD8 reserved[208]; 			/* for future use */
+};
+#endif
+
+#endif
+
diff --git a/drivers/video/sis/vstruct.h b/drivers/video/sis/vstruct.h
new file mode 100644
index 0000000..d4d55c9
--- /dev/null
+++ b/drivers/video/sis/vstruct.h
@@ -0,0 +1,676 @@
+/* $XFree86$ */
+/* $XdotOrg$ */
+/*
+ * General structure definitions for universal mode switching modules
+ *
+ * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, the following license terms
+ * apply:
+ *
+ * * This program is free software; you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License as published by
+ * * the Free Software Foundation; either version 2 of the named License,
+ * * or any later version.
+ * *
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details.
+ * *
+ * * You should have received a copy of the GNU General Public License
+ * * along with this program; if not, write to the Free Software
+ * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * * Redistribution and use in source and binary forms, with or without
+ * * modification, are permitted provided that the following conditions
+ * * are met:
+ * * 1) Redistributions of source code must retain the above copyright
+ * *    notice, this list of conditions and the following disclaimer.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * *    notice, this list of conditions and the following disclaimer in the
+ * *    documentation and/or other materials provided with the distribution.
+ * * 3) The name of the author may not be used to endorse or promote products
+ * *    derived from this software without specific prior written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ */
+
+#ifndef _VSTRUCT_
+#define _VSTRUCT_
+
+typedef struct _SiS_PanelDelayTblStruct
+{
+ 	UCHAR timer[2];
+} SiS_PanelDelayTblStruct;
+
+typedef struct _SiS_LCDDataStruct
+{
+	USHORT RVBHCMAX;
+	USHORT RVBHCFACT;
+	USHORT VGAHT;
+	USHORT VGAVT;
+	USHORT LCDHT;
+	USHORT LCDVT;
+} SiS_LCDDataStruct;
+
+typedef struct _SiS_TVDataStruct
+{
+	USHORT RVBHCMAX;
+	USHORT RVBHCFACT;
+	USHORT VGAHT;
+	USHORT VGAVT;
+	USHORT TVHDE;
+	USHORT TVVDE;
+	USHORT RVBHRS;
+	UCHAR  FlickerMode;
+	USHORT HALFRVBHRS;
+	UCHAR  RY1COE;
+	UCHAR  RY2COE;
+	UCHAR  RY3COE;
+	UCHAR  RY4COE;
+} SiS_TVDataStruct;
+
+typedef struct _SiS_LVDSDataStruct
+{
+	USHORT VGAHT;
+	USHORT VGAVT;
+	USHORT LCDHT;
+	USHORT LCDVT;
+} SiS_LVDSDataStruct;
+
+typedef struct _SiS_LVDSDesStruct
+{
+	USHORT LCDHDES;
+	USHORT LCDVDES;
+} SiS_LVDSDesStruct;
+
+typedef struct _SiS_LVDSCRT1DataStruct
+{
+	UCHAR  CR[15];
+} SiS_LVDSCRT1DataStruct;
+
+typedef struct _SiS_LCDACRT1DataStruct
+{
+	UCHAR  CR[17];
+} SiS_LCDACRT1DataStruct;
+
+typedef struct _SiS_CHTVRegDataStruct
+{
+	UCHAR  Reg[16];
+} SiS_CHTVRegDataStruct;
+
+typedef struct _SiS_StStruct
+{
+	UCHAR  St_ModeID;
+	USHORT St_ModeFlag;
+	UCHAR  St_StTableIndex;
+	UCHAR  St_CRT2CRTC;
+	UCHAR  St_ResInfo;
+	UCHAR  VB_StTVFlickerIndex;
+	UCHAR  VB_StTVEdgeIndex;
+	UCHAR  VB_StTVYFilterIndex;
+	UCHAR  St_PDC;
+} SiS_StStruct;
+
+typedef struct _SiS_VBModeStruct
+{
+	UCHAR  ModeID;
+	UCHAR  VB_TVDelayIndex;
+	UCHAR  VB_TVFlickerIndex;
+	UCHAR  VB_TVPhaseIndex;
+	UCHAR  VB_TVYFilterIndex;
+	UCHAR  VB_LCDDelayIndex;
+	UCHAR  _VB_LCDHIndex;
+	UCHAR  _VB_LCDVIndex;
+} SiS_VBModeStruct;
+
+typedef struct _SiS_StandTableStruct
+{
+	UCHAR  CRT_COLS;
+	UCHAR  ROWS;
+	UCHAR  CHAR_HEIGHT;
+	USHORT CRT_LEN;
+	UCHAR  SR[4];
+	UCHAR  MISC;
+	UCHAR  CRTC[0x19];
+	UCHAR  ATTR[0x14];
+	UCHAR  GRC[9];
+} SiS_StandTableStruct;
+
+typedef struct _SiS_ExtStruct
+{
+	UCHAR  Ext_ModeID;
+	USHORT Ext_ModeFlag;
+	USHORT Ext_VESAID;
+	UCHAR  Ext_RESINFO;
+	UCHAR  VB_ExtTVFlickerIndex;
+	UCHAR  VB_ExtTVEdgeIndex;
+	UCHAR  VB_ExtTVYFilterIndex;
+	UCHAR  VB_ExtTVYFilterIndexROM661;
+	UCHAR  REFindex;
+	CHAR   ROMMODEIDX661;
+} SiS_ExtStruct;
+
+typedef struct _SiS_Ext2Struct
+{
+	USHORT Ext_InfoFlag;
+	UCHAR  Ext_CRT1CRTC;
+	UCHAR  Ext_CRTVCLK;
+	UCHAR  Ext_CRT2CRTC;
+	UCHAR  Ext_CRT2CRTC_NS;
+	UCHAR  ModeID;
+	USHORT XRes;
+	USHORT YRes;
+	UCHAR  Ext_PDC;
+} SiS_Ext2Struct;
+
+typedef struct _SiS_Part2PortTblStruct
+{
+ 	UCHAR  CR[12];
+} SiS_Part2PortTblStruct;
+
+typedef struct _SiS_CRT1TableStruct
+{
+	UCHAR  CR[17];
+} SiS_CRT1TableStruct;
+
+typedef struct _SiS_MCLKDataStruct
+{
+	UCHAR  SR28,SR29,SR2A;
+	USHORT CLOCK;
+} SiS_MCLKDataStruct;
+
+typedef struct _SiS_VCLKDataStruct
+{
+	UCHAR  SR2B,SR2C;
+	USHORT CLOCK;
+} SiS_VCLKDataStruct;
+
+typedef struct _SiS_VBVCLKDataStruct
+{
+	UCHAR  Part4_A,Part4_B;
+	USHORT CLOCK;
+} SiS_VBVCLKDataStruct;
+
+typedef struct _SiS_StResInfoStruct
+{
+	USHORT HTotal;
+	USHORT VTotal;
+} SiS_StResInfoStruct;
+
+typedef struct _SiS_ModeResInfoStruct
+{
+	USHORT HTotal;
+	USHORT VTotal;
+	UCHAR  XChar;
+	UCHAR  YChar;
+} SiS_ModeResInfoStruct;
+
+
+
+typedef UCHAR DRAM4Type[4];
+
+/* Defines for SiS_CustomT */
+/* Never change these for sisfb compatibility */
+#define CUT_NONE          0
+#define CUT_FORCENONE     1
+#define CUT_BARCO1366     2
+#define CUT_BARCO1024     3
+#define CUT_COMPAQ1280    4
+#define CUT_COMPAQ12802   5
+#define CUT_PANEL848      6
+#define CUT_CLEVO1024     7
+#define CUT_CLEVO10242    8
+#define CUT_CLEVO1400     9
+#define CUT_CLEVO14002    10
+#define CUT_UNIWILL1024   11
+#define CUT_ASUSL3000D    12
+#define CUT_UNIWILL10242  13
+#define CUT_ACER1280      14
+#define CUT_COMPAL1400_1  15
+#define CUT_COMPAL1400_2  16
+#define CUT_ASUSA2H_1     17
+#define CUT_ASUSA2H_2     18
+
+typedef struct _SiS_Private
+{
+#ifdef LINUX_KERNEL
+        SISIOADDRESS RelIO;
+#endif
+	SISIOADDRESS SiS_P3c4;
+	SISIOADDRESS SiS_P3d4;
+	SISIOADDRESS SiS_P3c0;
+	SISIOADDRESS SiS_P3ce;
+	SISIOADDRESS SiS_P3c2;
+	SISIOADDRESS SiS_P3ca;
+	SISIOADDRESS SiS_P3c6;
+	SISIOADDRESS SiS_P3c7;
+	SISIOADDRESS SiS_P3c8;
+	SISIOADDRESS SiS_P3c9;
+	SISIOADDRESS SiS_P3cb;
+	SISIOADDRESS SiS_P3cd;
+	SISIOADDRESS SiS_P3da;
+	SISIOADDRESS SiS_Part1Port;
+	SISIOADDRESS SiS_Part2Port;
+	SISIOADDRESS SiS_Part3Port;
+	SISIOADDRESS SiS_Part4Port;
+	SISIOADDRESS SiS_Part5Port;
+	SISIOADDRESS SiS_VidCapt;
+	SISIOADDRESS SiS_VidPlay;
+	USHORT SiS_IF_DEF_LVDS;
+	USHORT SiS_IF_DEF_CH70xx;
+	USHORT SiS_IF_DEF_CONEX;
+	USHORT SiS_IF_DEF_TRUMPION;
+	USHORT SiS_IF_DEF_DSTN;
+	USHORT SiS_IF_DEF_FSTN;
+	USHORT SiS_SysFlags;
+	UCHAR  SiS_VGAINFO;
+#ifdef LINUX_XF86
+        USHORT SiS_CP1, SiS_CP2, SiS_CP3, SiS_CP4;
+#endif
+	BOOLEAN SiS_UseROM;
+	BOOLEAN SiS_ROMNew;
+	BOOLEAN SiS_NeedRomModeData;
+	BOOLEAN PanelSelfDetected;
+	int     SiS_CHOverScan;
+	BOOLEAN SiS_CHSOverScan;
+	BOOLEAN SiS_ChSW;
+	BOOLEAN SiS_UseLCDA;
+	int     SiS_UseOEM;
+	ULONG   SiS_CustomT;
+	USHORT  SiS_Backup70xx;
+	BOOLEAN HaveEMI;
+	BOOLEAN HaveEMILCD;
+	BOOLEAN OverruleEMI;
+	UCHAR  EMI_30,EMI_31,EMI_32,EMI_33;
+	USHORT SiS_EMIOffset;
+	SHORT  PDC, PDCA;
+	UCHAR  SiS_MyCR63;
+	USHORT SiS_CRT1Mode;
+	USHORT SiS_flag_clearbuffer;
+	int    SiS_RAMType;
+	UCHAR  SiS_ChannelAB;
+	UCHAR  SiS_DataBusWidth;
+	USHORT SiS_ModeType;
+	USHORT SiS_VBInfo;
+	USHORT SiS_TVMode;
+	USHORT SiS_LCDResInfo;
+	USHORT SiS_LCDTypeInfo;
+	USHORT SiS_LCDInfo;
+	USHORT SiS_LCDInfo661;
+	USHORT SiS_VBType;
+	USHORT SiS_VBExtInfo;
+	USHORT SiS_YPbPr;
+	USHORT SiS_SelectCRT2Rate;
+	USHORT SiS_SetFlag;
+	USHORT SiS_RVBHCFACT;
+	USHORT SiS_RVBHCMAX;
+	USHORT SiS_RVBHRS;
+	USHORT SiS_VGAVT;
+	USHORT SiS_VGAHT;
+	USHORT SiS_VT;
+	USHORT SiS_HT;
+	USHORT SiS_VGAVDE;
+	USHORT SiS_VGAHDE;
+	USHORT SiS_VDE;
+	USHORT SiS_HDE;
+	USHORT SiS_NewFlickerMode;
+	USHORT SiS_RY1COE;
+	USHORT SiS_RY2COE;
+	USHORT SiS_RY3COE;
+	USHORT SiS_RY4COE;
+	USHORT SiS_LCDHDES;
+	USHORT SiS_LCDVDES;
+	USHORT SiS_DDC_Port;
+	USHORT SiS_DDC_Index;
+	USHORT SiS_DDC_Data;
+	USHORT SiS_DDC_NData;
+	USHORT SiS_DDC_Clk;
+	USHORT SiS_DDC_NClk;
+	USHORT SiS_DDC_DeviceAddr;
+	USHORT SiS_DDC_ReadAddr;
+	USHORT SiS_DDC_SecAddr;
+	USHORT SiS_ChrontelInit;
+	BOOLEAN SiS_SensibleSR11;
+	USHORT SiS661LCD2TableSize;
+
+	USHORT SiS_PanelMinLVDS;
+	USHORT SiS_PanelMin301;
+
+	const SiS_StStruct          *SiS_SModeIDTable;
+	const SiS_StandTableStruct  *SiS_StandTable;
+	const SiS_ExtStruct         *SiS_EModeIDTable;
+	const SiS_Ext2Struct        *SiS_RefIndex;
+	const SiS_VBModeStruct      *SiS_VBModeIDTable;
+	const SiS_CRT1TableStruct   *SiS_CRT1Table;
+	const SiS_MCLKDataStruct    *SiS_MCLKData_0;
+	const SiS_MCLKDataStruct    *SiS_MCLKData_1;
+	SiS_VCLKDataStruct    	    *SiS_VCLKData;
+	SiS_VBVCLKDataStruct        *SiS_VBVCLKData;
+	const SiS_StResInfoStruct   *SiS_StResInfo;
+	const SiS_ModeResInfoStruct *SiS_ModeResInfo;
+
+	const UCHAR                 *pSiS_OutputSelect;
+	const UCHAR                 *pSiS_SoftSetting;
+
+	const DRAM4Type *SiS_SR15; /* pointer : point to array */
+#ifdef LINUX_KERNEL
+	UCHAR *pSiS_SR07;
+	const DRAM4Type *SiS_CR40; /* pointer : point to array */
+	UCHAR *SiS_CR49;
+	UCHAR *SiS_SR25;
+	UCHAR *pSiS_SR1F;
+	UCHAR *pSiS_SR21;
+	UCHAR *pSiS_SR22;
+	UCHAR *pSiS_SR23;
+	UCHAR *pSiS_SR24;
+	UCHAR *pSiS_SR31;
+	UCHAR *pSiS_SR32;
+	UCHAR *pSiS_SR33;
+	UCHAR *pSiS_CRT2Data_1_2;
+	UCHAR *pSiS_CRT2Data_4_D;
+	UCHAR *pSiS_CRT2Data_4_E;
+	UCHAR *pSiS_CRT2Data_4_10;
+	const USHORT *pSiS_RGBSenseData;
+	const USHORT *pSiS_VideoSenseData;
+	const USHORT *pSiS_YCSenseData;
+	const USHORT *pSiS_RGBSenseData2;
+	const USHORT *pSiS_VideoSenseData2;
+	const USHORT *pSiS_YCSenseData2;
+#endif
+
+	const SiS_PanelDelayTblStruct *SiS_PanelDelayTbl;
+	const SiS_PanelDelayTblStruct *SiS_PanelDelayTblLVDS;
+
+	/* SiS bridge */
+
+	const UCHAR *SiS_NTSCPhase;
+	const UCHAR *SiS_PALPhase;
+	const UCHAR *SiS_NTSCPhase2;
+	const UCHAR *SiS_PALPhase2;
+	const UCHAR *SiS_PALMPhase;
+	const UCHAR *SiS_PALNPhase;
+	const UCHAR *SiS_PALMPhase2;
+	const UCHAR *SiS_PALNPhase2;
+	const UCHAR *SiS_SpecialPhase;
+	const UCHAR *SiS_SpecialPhaseM;
+	const UCHAR *SiS_SpecialPhaseJ;
+	const SiS_LCDDataStruct  *SiS_ExtLCD1024x768Data;
+	const SiS_LCDDataStruct  *SiS_St2LCD1024x768Data;
+	const SiS_LCDDataStruct  *SiS_LCD1280x720Data;
+	const SiS_LCDDataStruct  *SiS_StLCD1280x768_2Data;
+	const SiS_LCDDataStruct  *SiS_ExtLCD1280x768_2Data;
+	const SiS_LCDDataStruct  *SiS_LCD1280x800Data;
+	const SiS_LCDDataStruct  *SiS_LCD1280x800_2Data;
+	const SiS_LCDDataStruct  *SiS_LCD1280x960Data;
+	const SiS_LCDDataStruct  *SiS_ExtLCD1280x1024Data;
+	const SiS_LCDDataStruct  *SiS_St2LCD1280x1024Data;
+	const SiS_LCDDataStruct  *SiS_StLCD1400x1050Data;
+	const SiS_LCDDataStruct  *SiS_ExtLCD1400x1050Data;
+	const SiS_LCDDataStruct  *SiS_StLCD1600x1200Data;
+	const SiS_LCDDataStruct  *SiS_ExtLCD1600x1200Data;
+	const SiS_LCDDataStruct  *SiS_LCD1680x1050Data;
+	const SiS_LCDDataStruct  *SiS_NoScaleData;
+	const SiS_TVDataStruct   *SiS_StPALData;
+	const SiS_TVDataStruct   *SiS_ExtPALData;
+	const SiS_TVDataStruct   *SiS_StNTSCData;
+	const SiS_TVDataStruct   *SiS_ExtNTSCData;
+	const SiS_TVDataStruct   *SiS_St1HiTVData;
+	const SiS_TVDataStruct   *SiS_St2HiTVData;
+	const SiS_TVDataStruct   *SiS_ExtHiTVData;
+	const SiS_TVDataStruct   *SiS_St525iData;
+	const SiS_TVDataStruct   *SiS_St525pData;
+	const SiS_TVDataStruct   *SiS_St750pData;
+	const SiS_TVDataStruct   *SiS_Ext525iData;
+	const SiS_TVDataStruct   *SiS_Ext525pData;
+	const SiS_TVDataStruct   *SiS_Ext750pData;
+	const UCHAR *SiS_NTSCTiming;
+	const UCHAR *SiS_PALTiming;
+	const UCHAR *SiS_HiTVExtTiming;
+	const UCHAR *SiS_HiTVSt1Timing;
+	const UCHAR *SiS_HiTVSt2Timing;
+	const UCHAR *SiS_HiTVGroup3Data;
+	const UCHAR *SiS_HiTVGroup3Simu;
+#if 0
+	const UCHAR *SiS_HiTVTextTiming;
+	const UCHAR *SiS_HiTVGroup3Text;
+#endif
+
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_1;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_1;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_2;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_2;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_3;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_3;
+
+	/* LVDS, Chrontel */
+
+	const SiS_LVDSDataStruct  *SiS_LVDS800x600Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS800x600Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS1024x768Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS1024x768Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS1280x1024Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS1280x1024Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS1280x960Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS1280x960Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS1400x1050Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS1400x1050Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS1600x1200Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS1600x1200Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS1280x768Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS1280x768Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS1024x600Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS1024x600Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS1152x768Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS1152x768Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS640x480Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS640x480Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS320x480Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDSXXXxXXXData_1;
+	const SiS_LVDSDataStruct  *SiS_LVDSBARCO1366Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDSBARCO1366Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDSBARCO1024Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDSBARCO1024Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS848x480Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS848x480Data_2;
+	const SiS_LVDSDataStruct  *SiS_CHTVUNTSCData;
+	const SiS_LVDSDataStruct  *SiS_CHTVONTSCData;
+	const SiS_LVDSDataStruct  *SiS_CHTVUPALData;
+	const SiS_LVDSDataStruct  *SiS_CHTVOPALData;
+	const SiS_LVDSDataStruct  *SiS_CHTVUPALMData;
+	const SiS_LVDSDataStruct  *SiS_CHTVOPALMData;
+	const SiS_LVDSDataStruct  *SiS_CHTVUPALNData;
+	const SiS_LVDSDataStruct  *SiS_CHTVOPALNData;
+	const SiS_LVDSDataStruct  *SiS_CHTVSOPALData;
+
+	const SiS_LVDSDesStruct  *SiS_PanelType00_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType01_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType02_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType03_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType04_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType05_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType06_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType07_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType08_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType09_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType0a_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType0b_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType0c_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType0d_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType0e_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType0f_1;
+	const SiS_LVDSDesStruct  *SiS_PanelTypeNS_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType00_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType01_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType02_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType03_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType04_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType05_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType06_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType07_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType08_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType09_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType0a_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType0b_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType0c_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType0d_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType0e_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType0f_2;
+	const SiS_LVDSDesStruct  *SiS_PanelTypeNS_2;
+	const SiS_LVDSDesStruct  *SiS_CHTVUNTSCDesData;
+	const SiS_LVDSDesStruct  *SiS_CHTVONTSCDesData;
+	const SiS_LVDSDesStruct  *SiS_CHTVUPALDesData;
+	const SiS_LVDSDesStruct  *SiS_CHTVOPALDesData;
+
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1800x600_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x768_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11280x1024_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11400x1050_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11280x768_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x600_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11152x768_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11600x1200_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1800x600_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x768_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11280x1024_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11400x1050_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11280x768_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x600_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11152x768_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11600x1200_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1800x600_2;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x768_2;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11280x1024_2;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11400x1050_2;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11280x768_2;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x600_2;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11152x768_2;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11600x1200_2;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1800x600_2_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x768_2_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11280x1024_2_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11400x1050_2_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11280x768_2_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x600_2_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11152x768_2_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11600x1200_2_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1XXXxXXX_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1XXXxXXX_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1640x480_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1640x480_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1640x480_2;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1640x480_2_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1640x480_3;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1640x480_3_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1320x480_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1UNTSC;
+	const SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1ONTSC;
+	const SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1UPAL;
+	const SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1OPAL;
+	const SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1SOPAL;
+
+	const SiS_CHTVRegDataStruct *SiS_CHTVReg_UNTSC;
+	const SiS_CHTVRegDataStruct *SiS_CHTVReg_ONTSC;
+	const SiS_CHTVRegDataStruct *SiS_CHTVReg_UPAL;
+	const SiS_CHTVRegDataStruct *SiS_CHTVReg_OPAL;
+	const SiS_CHTVRegDataStruct *SiS_CHTVReg_UPALM;
+	const SiS_CHTVRegDataStruct *SiS_CHTVReg_OPALM;
+	const SiS_CHTVRegDataStruct *SiS_CHTVReg_UPALN;
+	const SiS_CHTVRegDataStruct *SiS_CHTVReg_OPALN;
+	const SiS_CHTVRegDataStruct *SiS_CHTVReg_SOPAL;
+
+	const UCHAR *SiS_CHTVVCLKUNTSC;
+	const UCHAR *SiS_CHTVVCLKONTSC;
+	const UCHAR *SiS_CHTVVCLKUPAL;
+	const UCHAR *SiS_CHTVVCLKOPAL;
+	const UCHAR *SiS_CHTVVCLKUPALM;
+	const UCHAR *SiS_CHTVVCLKOPALM;
+	const UCHAR *SiS_CHTVVCLKUPALN;
+	const UCHAR *SiS_CHTVVCLKOPALN;
+	const UCHAR *SiS_CHTVVCLKSOPAL;
+
+	USHORT  PanelXRes, PanelHT;
+	USHORT  PanelYRes, PanelVT;
+	USHORT  PanelHRS,  PanelHRE;
+  	USHORT 	PanelVRS,  PanelVRE;
+	USHORT  PanelVCLKIdx300;
+	USHORT  PanelVCLKIdx315;
+
+	BOOLEAN UseCustomMode;
+	BOOLEAN CRT1UsesCustomMode;
+	USHORT  CHDisplay;
+	USHORT  CHSyncStart;
+	USHORT  CHSyncEnd;
+	USHORT  CHTotal;
+	USHORT  CHBlankStart;
+	USHORT  CHBlankEnd;
+	USHORT  CVDisplay;
+	USHORT  CVSyncStart;
+	USHORT  CVSyncEnd;
+	USHORT  CVTotal;
+	USHORT  CVBlankStart;
+	USHORT  CVBlankEnd;
+	ULONG   CDClock;
+	ULONG   CFlags;   
+	UCHAR   CCRT1CRTC[17];
+	UCHAR   CSR2B;
+	UCHAR   CSR2C;
+	USHORT  CSRClock;
+	USHORT  CSRClock_CRT1;
+	USHORT  CModeFlag;
+	USHORT  CModeFlag_CRT1;
+	USHORT  CInfoFlag;
+
+	int	LVDSHL;
+	
+	BOOLEAN Backup;
+	UCHAR Backup_Mode;
+	UCHAR Backup_14;
+	UCHAR Backup_15;
+	UCHAR Backup_16;
+	UCHAR Backup_17;
+	UCHAR Backup_18;
+	UCHAR Backup_19;
+	UCHAR Backup_1a;
+	UCHAR Backup_1b;
+	UCHAR Backup_1c;
+	UCHAR Backup_1d;
+	
+	int     UsePanelScaler;
+	int	CenterScreen;
+
+	USHORT  CP_Vendor, CP_Product;
+	BOOLEAN CP_HaveCustomData;
+	int     CP_PreferredX, CP_PreferredY, CP_PreferredIndex;
+	int	CP_MaxX, CP_MaxY, CP_MaxClock;
+	UCHAR   CP_PrefSR2B, CP_PrefSR2C;
+	USHORT  CP_PrefClock;
+	BOOLEAN CP_Supports64048075;
+	int     CP_HDisplay[7], CP_VDisplay[7];	/* For Custom LCD panel dimensions */
+    	int     CP_HTotal[7], CP_VTotal[7];
+    	int     CP_HSyncStart[7], CP_VSyncStart[7];
+    	int     CP_HSyncEnd[7], CP_VSyncEnd[7];
+	int     CP_HBlankStart[7], CP_VBlankStart[7];
+	int     CP_HBlankEnd[7], CP_VBlankEnd[7];
+    	int     CP_Clock[7];
+	BOOLEAN CP_DataValid[7];
+	BOOLEAN CP_HSync_P[7], CP_VSync_P[7], CP_SyncValid[7];
+} SiS_Private;
+
+#endif
+
diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c
new file mode 100644
index 0000000..7b43716
--- /dev/null
+++ b/drivers/video/skeletonfb.c
@@ -0,0 +1,684 @@
+/*
+ * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device
+ *
+ *  Modified to new api Jan 2001 by James Simmons (jsimmons@transvirtual.com)
+ *
+ *  Created 28 Dec 1997 by Geert Uytterhoeven
+ *
+ *
+ *  I have started rewriting this driver as a example of the upcoming new API
+ *  The primary goal is to remove the console code from fbdev and place it
+ *  into fbcon.c. This reduces the code and makes writing a new fbdev driver
+ *  easy since the author doesn't need to worry about console internals. It
+ *  also allows the ability to run fbdev without a console/tty system on top 
+ *  of it. 
+ *
+ *  First the roles of struct fb_info and struct display have changed. Struct
+ *  display will go away. The way the the new framebuffer console code will
+ *  work is that it will act to translate data about the tty/console in 
+ *  struct vc_data to data in a device independent way in struct fb_info. Then
+ *  various functions in struct fb_ops will be called to store the device 
+ *  dependent state in the par field in struct fb_info and to change the 
+ *  hardware to that state. This allows a very clean separation of the fbdev
+ *  layer from the console layer. It also allows one to use fbdev on its own
+ *  which is a bounus for embedded devices. The reason this approach works is  
+ *  for each framebuffer device when used as a tty/console device is allocated
+ *  a set of virtual terminals to it. Only one virtual terminal can be active 
+ *  per framebuffer device. We already have all the data we need in struct 
+ *  vc_data so why store a bunch of colormaps and other fbdev specific data
+ *  per virtual terminal. 
+ *
+ *  As you can see doing this makes the con parameter pretty much useless
+ *  for struct fb_ops functions, as it should be. Also having struct  
+ *  fb_var_screeninfo and other data in fb_info pretty much eliminates the 
+ *  need for get_fix and get_var. Once all drivers use the fix, var, and cmap
+ *  fbcon can be written around these fields. This will also eliminate the
+ *  need to regenerate struct fb_var_screeninfo, struct fb_fix_screeninfo
+ *  struct fb_cmap every time get_var, get_fix, get_cmap functions are called
+ *  as many drivers do now. 
+ *
+ *  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/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/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+
+    /*
+     *  This is just simple sample code.
+     *
+     *  No warranty that it actually compiles.
+     *  Even less warranty that it actually works :-)
+     */
+
+/*
+ *  If your driver supports multiple boards, you should make the  
+ *  below data types arrays, or allocate them dynamically (using kmalloc()). 
+ */ 
+
+/* 
+ * This structure defines the hardware state of the graphics card. Normally
+ * you place this in a header file in linux/include/video. This file usually
+ * also includes register information. That allows other driver subsystems
+ * and userland applications the ability to use the same header file to 
+ * avoid duplicate work and easy porting of software. 
+ */
+struct xxx_par;
+
+/*
+ * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo
+ * if we don't use modedb. If we do use modedb see xxxfb_init how to use it
+ * to get a fb_var_screeninfo. Otherwise define a default var as well. 
+ */
+static struct fb_fix_screeninfo xxxfb_fix __initdata = {
+	.id =		"FB's name", 
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_PSEUDOCOLOR,
+	.xpanstep =	1,
+	.ypanstep =	1,
+	.ywrapstep =	1, 
+	.accel =	FB_ACCEL_NONE,
+};
+
+    /*
+     * 	Modern graphical hardware not only supports pipelines but some 
+     *  also support multiple monitors where each display can have its  
+     *  its own unique data. In this case each display could be  
+     *  represented by a separate framebuffer device thus a separate 
+     *  struct fb_info. Now the struct xxx_par represents the graphics
+     *  hardware state thus only one exist per card. In this case the 
+     *  struct xxx_par for each graphics card would be shared between 
+     *  every struct fb_info that represents a framebuffer on that card. 
+     *  This allows when one display changes it video resolution (info->var) 
+     *  the other displays know instantly. Each display can always be
+     *  aware of the entire hardware state that affects it because they share
+     *  the same xxx_par struct. The other side of the coin is multiple
+     *  graphics cards that pass data around until it is finally displayed
+     *  on one monitor. Such examples are the voodoo 1 cards and high end
+     *  NUMA graphics servers. For this case we have a bunch of pars, each
+     *  one that represents a graphics state, that belong to one struct 
+     *  fb_info. Their you would want to have *par point to a array of device
+     *  states and have each struct fb_ops function deal with all those 
+     *  states. I hope this covers every possible hardware design. If not
+     *  feel free to send your ideas at jsimmons@users.sf.net 
+     */
+
+    /*
+     *  If your driver supports multiple boards or it supports multiple 
+     *  framebuffers, you should make these arrays, or allocate them 
+     *  dynamically (using kmalloc()). 
+     */ 
+static struct fb_info info;
+
+    /* 
+     * Each one represents the state of the hardware. Most hardware have
+     * just one hardware state. These here represent the default state(s). 
+     */
+static struct xxx_par __initdata current_par;
+
+int xxxfb_init(void);
+int xxxfb_setup(char*);
+
+/**
+ *	xxxfb_open - Optional function. Called when the framebuffer is
+ *		     first accessed.
+ *	@info: frame buffer structure that represents a single frame buffer
+ *	@user: tell us if the userland (value=1) or the console is accessing
+ *	       the framebuffer. 
+ *
+ *	This function is the first function called in the framebuffer api.
+ *	Usually you don't need to provide this function. The case where it 
+ *	is used is to change from a text mode hardware state to a graphics
+ * 	mode state. 
+ *
+ *	Returns negative errno on error, or zero on success.
+ */
+static int xxxfb_open(const struct fb_info *info, int user)
+{
+    return 0;
+}
+
+/**
+ *	xxxfb_release - Optional function. Called when the framebuffer 
+ *			device is closed. 
+ *	@info: frame buffer structure that represents a single frame buffer
+ *	@user: tell us if the userland (value=1) or the console is accessing
+ *	       the framebuffer. 
+ *	
+ *	Thus function is called when we close /dev/fb or the framebuffer 
+ *	console system is released. Usually you don't need this function.
+ *	The case where it is usually used is to go from a graphics state
+ *	to a text mode state.
+ *
+ *	Returns negative errno on error, or zero on success.
+ */
+static int xxxfb_release(const struct fb_info *info, int user)
+{
+    return 0;
+}
+
+/**
+ *      xxxfb_check_var - Optional function. Validates a var passed in. 
+ *      @var: frame buffer variable screen structure
+ *      @info: frame buffer structure that represents a single frame buffer 
+ *
+ *	Checks to see if the hardware supports the state requested by
+ *	var passed in. This function does not alter the hardware state!!! 
+ *	This means the data stored in struct fb_info and struct xxx_par do 
+ *      not change. This includes the var inside of struct fb_info. 
+ *	Do NOT change these. This function can be called on its own if we
+ *	intent to only test a mode and not actually set it. The stuff in 
+ *	modedb.c is a example of this. If the var passed in is slightly 
+ *	off by what the hardware can support then we alter the var PASSED in
+ *	to what we can do. If the hardware doesn't support mode change 
+ * 	a -EINVAL will be returned by the upper layers. You don't need to 
+ *	implement this function then. If you hardware doesn't support 
+ *	changing the resolution then this function is not needed. In this
+ *	case the driver woudl just provide a var that represents the static
+ *	state the screen is in.
+ *
+ *	Returns negative errno on error, or zero on success.
+ */
+static int xxxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+    const struct xxx_par *par = (const struct xxx_par *) info->par;
+    /* ... */
+    return 0;	   	
+}
+
+/**
+ *      xxxfb_set_par - Optional function. Alters the hardware state.
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ *	Using the fb_var_screeninfo in fb_info we set the resolution of the
+ *	this particular framebuffer. This function alters the par AND the
+ *	fb_fix_screeninfo stored in fb_info. It doesn't not alter var in 
+ *	fb_info since we are using that data. This means we depend on the
+ *	data in var inside fb_info to be supported by the hardware. 
+ *	xxxfb_check_var is always called before xxxfb_set_par to ensure this.
+ *	Again if you can't change the resolution you don't need this function.
+ *
+ *	Returns negative errno on error, or zero on success.
+ */
+static int xxxfb_set_par(struct fb_info *info)
+{
+    struct xxx_par *par = (struct xxx_par *) info->par;
+    /* ... */
+    return 0;	
+}
+
+/**
+ *  	xxxfb_setcolreg - Optional function. Sets a color register.
+ *      @regno: Which register in the CLUT we are programming 
+ *      @red: The red value which can be up to 16 bits wide 
+ *	@green: The green value which can be up to 16 bits wide 
+ *	@blue:  The blue value which can be up to 16 bits wide.
+ *	@transp: If supported, the alpha value which can be up to 16 bits wide.
+ *      @info: frame buffer info structure
+ * 
+ *  	Set a single color register. The values supplied have a 16 bit
+ *  	magnitude which needs to be scaled in this function for the hardware. 
+ *	Things to take into consideration are how many color registers, if
+ *	any, are supported with the current color visual. With truecolor mode
+ *	no color palettes are supported. Here a pseudo palette is created
+ *	which we store the value in pseudo_palette in struct fb_info. For
+ *	pseudocolor mode we have a limited color palette. To deal with this
+ *	we can program what color is displayed for a particular pixel value.
+ *	DirectColor is similar in that we can program each color field. If
+ *	we have a static colormap we don't need to implement this function. 
+ * 
+ *	Returns negative errno on error, or zero on success.
+ */
+static int xxxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp,
+			   const struct fb_info *info)
+{
+    if (regno >= 256)  /* no. of hw registers */
+       return -EINVAL;
+    /*
+     * Program hardware... do anything you want with transp
+     */
+
+    /* grayscale works only partially under directcolor */
+    if (info->var.grayscale) {
+       /* grayscale = 0.30*R + 0.59*G + 0.11*B */
+       red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+    }
+
+    /* Directcolor:
+     *   var->{color}.offset contains start of bitfield
+     *   var->{color}.length contains length of bitfield
+     *   {hardwarespecific} contains width of DAC
+     *   cmap[X] is programmed to (X << red.offset) | (X << green.offset) | (X << blue.offset)
+     *   RAMDAC[X] is programmed to (red, green, blue)
+     *
+     * Pseudocolor:
+     *    uses offset = 0 && length = DAC register width.
+     *    var->{color}.offset is 0
+     *    var->{color}.length contains widht of DAC
+     *    cmap is not used
+     *    DAC[X] is programmed to (red, green, blue)
+     * Truecolor:
+     *    does not use RAMDAC (usually has 3 of them).
+     *    var->{color}.offset contains start of bitfield
+     *    var->{color}.length contains length of bitfield
+     *    cmap is programmed to (red << red.offset) | (green << green.offset) |
+     *                      (blue << blue.offset) | (transp << transp.offset)
+     *    RAMDAC does not exist
+     */
+#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+    switch (info->fix.visual) {
+       case FB_VISUAL_TRUECOLOR:
+       case FB_VISUAL_PSEUDOCOLOR:
+               red = CNVT_TOHW(red, info->var.red.length);
+               green = CNVT_TOHW(green, info->var.green.length);
+               blue = CNVT_TOHW(blue, info->var.blue.length);
+               transp = CNVT_TOHW(transp, info->var.transp.length);
+               break;
+       case FB_VISUAL_DIRECTCOLOR:
+	       /* example here assumes 8 bit DAC. Might be different 
+		* for your hardware */	
+               red = CNVT_TOHW(red, 8);       
+               green = CNVT_TOHW(green, 8);
+               blue = CNVT_TOHW(blue, 8);
+               /* hey, there is bug in transp handling... */
+               transp = CNVT_TOHW(transp, 8);
+               break;
+    }
+#undef CNVT_TOHW
+    /* Truecolor has hardware independent palette */
+    if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+       u32 v;
+
+       if (regno >= 16)
+           return -EINVAL;
+
+       v = (red << info->var.red.offset) |
+           (green << info->var.green.offset) |
+           (blue << info->var.blue.offset) |
+           (transp << info->var.transp.offset);
+
+       switch (info->var.bits_per_pixel) {
+		case 8:
+			/* Yes some hand held devices have this. */ 
+           		((u8*)(info->pseudo_palette))[regno] = v;
+			break;	
+   		case 16:
+           		((u16*)(info->pseudo_palette))[regno] = v;
+			break;
+		case 24:
+		case 32:	
+           		((u32*)(info->pseudo_palette))[regno] = v;
+			break;
+       }
+       return 0;
+    }
+    /* ... */
+    return 0;
+}
+
+/**
+ *      xxxfb_pan_display - NOT a required function. Pans the display.
+ *      @var: frame buffer variable screen structure
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ *	Pan (or wrap, depending on the `vmode' field) the display using the
+ *  	`xoffset' and `yoffset' fields of the `var' structure.
+ *  	If the values don't fit, return -EINVAL.
+ *
+ *      Returns negative errno on error, or zero on success.
+ */
+static int xxxfb_pan_display(struct fb_var_screeninfo *var,
+			     const struct fb_info *info)
+{
+    /* ... */
+    return 0;
+}
+
+/**
+ *      xxxfb_blank - NOT a required function. Blanks the display.
+ *      @blank_mode: the blank mode we want. 
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ *      Blank the screen if blank_mode != 0, else unblank. Return 0 if
+ *      blanking succeeded, != 0 if un-/blanking failed due to e.g. a 
+ *      video mode which doesn't support it. Implements VESA suspend
+ *      and powerdown modes on hardware that supports disabling hsync/vsync:
+ *      blank_mode == 2: suspend vsync
+ *      blank_mode == 3: suspend hsync
+ *      blank_mode == 4: powerdown
+ *
+ *      Returns negative errno on error, or zero on success.
+ *
+ */
+static int xxxfb_blank(int blank_mode, const struct fb_info *info)
+{
+    /* ... */
+    return 0;
+}
+
+/* ------------ Accelerated Functions --------------------- */
+
+/*
+ * We provide our own functions if we have hardware acceleration
+ * or non packed pixel format layouts. If we have no hardware 
+ * acceleration, we can use a generic unaccelerated function. If using
+ * a pack pixel format just use the functions in cfb_*.c. Each file 
+ * has one of the three different accel functions we support.
+ */
+
+/**
+ *      xxxfb_fillrect - REQUIRED function. Can use generic routines if 
+ *		 	 non acclerated hardware and packed pixel based.
+ *			 Draws a rectangle on the screen.		
+ *
+ *      @info: frame buffer structure that represents a single frame buffer
+ *	@region: The structure representing the rectangular region we 
+ *		 wish to draw to.
+ *
+ *	This drawing operation places/removes a retangle on the screen 
+ *	depending on the rastering operation with the value of color which
+ *	is in the current color depth format.
+ */
+void xxfb_fillrect(struct fb_info *p, const struct fb_fillrect *region)
+{
+/*	Meaning of struct fb_fillrect
+ *
+ *	@dx: The x and y corrdinates of the upper left hand corner of the 
+ *	@dy: area we want to draw to. 
+ *	@width: How wide the rectangle is we want to draw.
+ *	@height: How tall the rectangle is we want to draw.
+ *	@color:	The color to fill in the rectangle with. 
+ *	@rop: The raster operation. We can draw the rectangle with a COPY
+ *	      of XOR which provides erasing effect. 
+ */
+}
+
+/**
+ *      xxxfb_copyarea - REQUIRED function. Can use generic routines if
+ *                       non acclerated hardware and packed pixel based.
+ *                       Copies one area of the screen to another area.
+ *
+ *      @info: frame buffer structure that represents a single frame buffer
+ *      @area: Structure providing the data to copy the framebuffer contents
+ *	       from one region to another.
+ *
+ *      This drawing operation copies a rectangular area from one area of the
+ *	screen to another area.
+ */
+void xxxfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) 
+{
+/*
+ *      @dx: The x and y coordinates of the upper left hand corner of the
+ *	@dy: destination area on the screen.
+ *      @width: How wide the rectangle is we want to copy.
+ *      @height: How tall the rectangle is we want to copy.
+ *      @sx: The x and y coordinates of the upper left hand corner of the
+ *      @sy: source area on the screen.
+ */
+}
+
+
+/**
+ *      xxxfb_imageblit - REQUIRED function. Can use generic routines if
+ *                        non acclerated hardware and packed pixel based.
+ *                        Copies a image from system memory to the screen. 
+ *
+ *      @info: frame buffer structure that represents a single frame buffer
+ *	@image:	structure defining the image.
+ *
+ *      This drawing operation draws a image on the screen. It can be a 
+ *	mono image (needed for font handling) or a color image (needed for
+ *	tux). 
+ */
+void xxxfb_imageblit(struct fb_info *p, const struct fb_image *image) 
+{
+/*
+ *      @dx: The x and y coordinates of the upper left hand corner of the
+ *	@dy: destination area to place the image on the screen.
+ *      @width: How wide the image is we want to copy.
+ *      @height: How tall the image is we want to copy.
+ *      @fg_color: For mono bitmap images this is color data for     
+ *      @bg_color: the foreground and background of the image to
+ *		   write directly to the frmaebuffer.
+ *	@depth:	How many bits represent a single pixel for this image.
+ *	@data: The actual data used to construct the image on the display.
+ *	@cmap: The colormap used for color images.   
+ */
+}
+
+/**
+ *	xxxfb_cursor - 	REQUIRED function. If your hardware lacks support
+ *			for a cursor you can use the default cursor whose
+ *			function is called soft_cursor. It will always 
+ *			work since it uses xxxfb_imageblit function which 
+ *			is required. 	  	 
+ *
+ *      @info: frame buffer structure that represents a single frame buffer
+ *	@cursor: structure defining the cursor to draw.
+ *
+ *      This operation is used to set or alter the properities of the
+ *	cursor.
+ *
+ *	Returns negative errno on error, or zero on success.
+ */
+int xxxfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+/*
+ *      @set: 	Which fields we are altering in struct fb_cursor 
+ *	@enable: Disable or enable the cursor 
+ *      @rop: 	The bit operation we want to do. 
+ *      @mask:  This is the cursor mask bitmap. 
+ *      @dest:  A image of the area we are going to display the cursor.
+ *		Used internally by the driver.	 
+ *      @hot:	The hot spot. 
+ *	@image:	The actual data for the cursor image.
+ *
+ *      NOTES ON FLAGS (cursor->set):
+ *
+ *      FB_CUR_SETIMAGE - the cursor image has changed (cursor->image.data)
+ *      FB_CUR_SETPOS   - the cursor position has changed (cursor->image.dx|dy)
+ *      FB_CUR_SETHOT   - the cursor hot spot has changed (cursor->hot.dx|dy)
+ *      FB_CUR_SETCMAP  - the cursor colors has changed (cursor->fg_color|bg_color)
+ *      FB_CUR_SETSHAPE - the cursor bitmask has changed (cursor->mask)
+ *      FB_CUR_SETSIZE  - the cursor size has changed (cursor->width|height)
+ *      FB_CUR_SETALL   - everything has changed
+ *
+ *      NOTES ON ROPs (cursor->rop, Raster Operation)
+ *
+ *      ROP_XOR         - cursor->image.data XOR cursor->mask
+ *      ROP_COPY        - curosr->image.data AND cursor->mask
+ *
+ *      OTHER NOTES:
+ *
+ *      - fbcon only supports a 2-color cursor (cursor->image.depth = 1)
+ *      - The fb_cursor structure, @cursor, _will_ always contain valid
+ *        fields, whether any particular bitfields in cursor->set is set
+ *        or not.
+ */
+}
+
+/**
+ *	xxxfb_rotate -  NOT a required function. If your hardware
+ *			supports rotation the whole screen then 
+ *			you would provide a hook for this. 
+ *
+ *      @info: frame buffer structure that represents a single frame buffer
+ *	@angle: The angle we rotate the screen.   
+ *
+ *      This operation is used to set or alter the properities of the
+ *	cursor.
+ */
+void xxxfb_rotate(struct fb_info *info, int angle)
+{
+}
+
+/**
+ *	xxxfb_poll - NOT a required function. The purpose of this
+ *		     function is to provide a way for some process
+ *		     to wait until a specific hardware event occurs
+ *		     for the framebuffer device.
+ * 				 
+ *      @info: frame buffer structure that represents a single frame buffer
+ *	@wait: poll table where we store process that await a event.     
+ */
+void xxxfb_poll(struct fb_info *info, poll_table *wait)
+{
+}
+
+/**
+ *	xxxfb_sync - NOT a required function. Normally the accel engine 
+ *		     for a graphics card take a specific amount of time.
+ *		     Often we have to wait for the accelerator to finish
+ *		     its operation before we can write to the framebuffer
+ *		     so we can have consistent display output. 
+ *
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+void xxxfb_sync(struct fb_info *info)
+{
+}
+
+    /*
+     *  Initialization
+     */
+
+int __init xxxfb_init(void)
+{
+    int cmap_len, retval;	
+   
+    /*
+     *  For kernel boot options (in 'video=xxxfb:<options>' format)
+     */
+#ifndef MODULE
+    char *option = NULL;
+
+    if (fb_get_options("xxxfb", &option))
+	    return -ENODEV;
+    xxxfb_setup(option);
+#endif
+
+    /* 
+     * Here we set the screen_base to the virtual memory address
+     * for the framebuffer. Usually we obtain the resource address
+     * from the bus layer and then translate it to virtual memory
+     * space via ioremap. Consult ioport.h. 
+     */
+    info.screen_base = framebuffer_virtual_memory;	
+    info.fbops = &xxxfb_ops;
+    info.fix = xxxfb_fix;
+    info.pseudo_palette = pseudo_palette;
+
+    /*
+     * Set up flags to indicate what sort of acceleration your
+     * driver can provide (pan/wrap/copyarea/etc.) and whether it
+     * is a module -- see FBINFO_* in include/linux/fb.h
+     */
+    info.flags = FBINFO_DEFAULT;
+    info.par = current_par;
+
+    /*
+     * This should give a reasonable default video mode. The following is
+     * done when we can set a video mode. 
+     */
+    if (!mode_option)
+	mode_option = "640x480@60";	 	
+
+    retval = fb_find_mode(&info.var, &info, mode_option, NULL, 0, NULL, 8);
+  
+    if (!retval || retval == 4)
+	return -EINVAL;			
+
+    /* This has to been done !!! */	
+    fb_alloc_cmap(&info.cmap, cmap_len, 0);
+	
+    /* 
+     * The following is done in the case of having hardware with a static 
+     * mode. If we are setting the mode ourselves we don't call this. 
+     */	
+    info.var = xxxfb_var;
+	
+    if (register_framebuffer(&info) < 0)
+	return -EINVAL;
+    printk(KERN_INFO "fb%d: %s frame buffer device\n", info.node,
+	   info.fix.id);
+    return 0;
+}
+
+    /*
+     *  Cleanup
+     */
+
+static void __exit xxxfb_cleanup(void)
+{
+    /*
+     *  If your driver supports multiple boards, you should unregister and
+     *  clean up all instances.
+     */
+
+    unregister_framebuffer(info);
+    fb_dealloc_cmap(&info.cmap);
+    /* ... */
+}
+
+    /*
+     *  Setup
+     */
+
+/* 
+ * Only necessary if your driver takes special options,
+ * otherwise we fall back on the generic fb_setup().
+ */
+int __init xxxfb_setup(char *options)
+{
+    /* Parse user speficied options (`video=xxxfb:') */
+}
+
+/* ------------------------------------------------------------------------- */
+
+    /*
+     *  Frame buffer operations
+     */
+
+static struct fb_ops xxxfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_open	= xxxfb_open,
+	.fb_read	= xxxfb_read,
+	.fb_write	= xxxfb_write,
+	.fb_release	= xxxfb_release,
+	.fb_check_var	= xxxfb_check_var,
+	.fb_set_par	= xxxfb_set_par,	
+	.fb_setcolreg	= xxxfb_setcolreg,
+	.fb_blank	= xxxfb_blank,
+	.fb_pan_display	= xxxfb_pan_display,	
+	.fb_fillrect	= xxxfb_fillrect, 	/* Needed !!! */ 
+	.fb_copyarea	= xxxfb_copyarea,	/* Needed !!! */ 
+	.fb_imageblit	= xxxfb_imageblit,	/* Needed !!! */
+	.fb_cursor	= xxxfb_cursor,		/* Needed !!! */
+	.fb_rotate	= xxxfb_rotate,
+	.fb_poll	= xxxfb_poll,
+	.fb_sync	= xxxfb_sync,
+	.fb_ioctl	= xxxfb_ioctl,
+	.fb_mmap	= xxxfb_mmap,	
+};
+
+/* ------------------------------------------------------------------------- */
+
+
+    /*
+     *  Modularization
+     */
+
+module_init(xxxfb_init);
+module_exit(xxxfb_cleanup);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/softcursor.c b/drivers/video/softcursor.c
new file mode 100644
index 0000000..13a4511
--- /dev/null
+++ b/drivers/video/softcursor.c
@@ -0,0 +1,79 @@
+/*
+ * linux/drivers/video/softcursor.c -- Generic software cursor for frame buffer devices
+ *
+ *  Created 14 Nov 2002 by James Simmons 
+ *
+ * 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/module.h>
+#include <linux/string.h>
+#include <linux/tty.h>
+#include <linux/fb.h>
+#include <linux/slab.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+	unsigned int scan_align = info->pixmap.scan_align - 1;
+	unsigned int buf_align = info->pixmap.buf_align - 1;
+	unsigned int i, size, dsize, s_pitch, d_pitch;
+	struct fb_image *image;
+	u8 *dst, *src;
+
+	if (info->state != FBINFO_STATE_RUNNING)
+		return 0;
+
+	s_pitch = (cursor->image.width + 7) >> 3;
+	dsize = s_pitch * cursor->image.height;
+
+	src = kmalloc(dsize + sizeof(struct fb_image), GFP_ATOMIC);
+	if (!src)
+		return -ENOMEM;
+
+	image = (struct fb_image *) (src + dsize);
+	*image = cursor->image;
+	d_pitch = (s_pitch + scan_align) & ~scan_align;
+
+	size = d_pitch * image->height + buf_align;
+	size &= ~buf_align;
+	dst = fb_get_buffer_offset(info, &info->pixmap, size);
+
+	if (cursor->enable) {
+		switch (cursor->rop) {
+		case ROP_XOR:
+			for (i = 0; i < dsize; i++)
+				src[i] = image->data[i] ^ cursor->mask[i];
+			break;
+		case ROP_COPY:
+		default:
+			for (i = 0; i < dsize; i++)
+				src[i] = image->data[i] & cursor->mask[i];
+			break;
+		}
+	} else 
+		memcpy(src, image->data, dsize);
+	
+	if (info->pixmap.outbuf)
+		fb_iomove_buf_aligned(info, &info->pixmap, dst, d_pitch, src,
+				  s_pitch, image->height);
+	else
+		fb_sysmove_buf_aligned(info, &info->pixmap, dst, d_pitch, src,
+				   s_pitch, image->height);
+
+	image->data = dst;
+	info->fbops->fb_imageblit(info, image);
+	kfree(src);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(soft_cursor);
+ 
+MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
+MODULE_DESCRIPTION("Generic software cursor");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c
new file mode 100644
index 0000000..663d536
--- /dev/null
+++ b/drivers/video/sstfb.c
@@ -0,0 +1,1722 @@
+/*
+ * linux/drivers/video/sstfb.c -- voodoo graphics frame buffer
+ *
+ *     Copyright (c) 2000-2002 Ghozlane Toumi <gtoumi@laposte.net>
+ *
+ *     Created 15 Jan 2000 by Ghozlane Toumi
+ *
+ * Contributions (and many thanks) :
+ *
+ * 03/2001 James Simmons   <jsimmons@infradead.org>
+ * 04/2001 Paul Mundt      <lethal@chaoticdreams.org>
+ * 05/2001 Urs Ganse       <ursg@uni.de>
+ *	(initial work on voodoo2 port, interlace)
+ * 09/2002 Helge Deller    <deller@gmx.de>
+ *	(enable driver on big-endian machines (hppa), ioctl fixes)
+ * 12/2002 Helge Deller    <deller@gmx.de>
+ *	(port driver to new frambuffer infrastructure)
+ * 01/2003 Helge Deller    <deller@gmx.de>
+ *	(initial work on fb hardware acceleration for voodoo2)
+ *
+ */
+
+/*
+ * The voodoo1 has the following memory mapped address space:
+ * 0x000000 - 0x3fffff : registers              (4MB)
+ * 0x400000 - 0x7fffff : linear frame buffer    (4MB)
+ * 0x800000 - 0xffffff : texture memory         (8MB)
+ */
+
+/*
+ * misc notes, TODOs, toASKs, and deep thoughts
+
+-TODO: at one time or another test that the mode is acceptable by the monitor
+-ASK: Can I choose different ordering for the color bitfields (rgba argb ...)
+      wich one should i use ? is there any preferred one ? It seems ARGB is
+      the one ...
+-TODO: in  set_var check the validity of timings (hsync vsync)...
+-TODO: check and recheck the use of sst_wait_idle : we don't flush the fifo via
+       a nop command. so it's ok as long as the commands we pass don't go
+       through the fifo. warning: issuing a nop command seems to need pci_fifo
+-FIXME: in case of failure in the init sequence, be sure we return to a safe
+        state.
+-FIXME: 4MB boards have banked memory (FbiInit2 bits 1 & 20)
+ */
+
+/*
+ * debug info
+ * SST_DEBUG : enable debugging
+ * SST_DEBUG_REG : debug registers
+ *   0 :  no debug
+ *   1 : dac calls, [un]set_bits, FbiInit
+ *   2 : insane debug level (log every register read/write)
+ * SST_DEBUG_FUNC : functions
+ *   0 : no debug
+ *   1 : function call / debug ioctl
+ *   2 : variables
+ *   3 : flood . you don't want to do that. trust me.
+ * SST_DEBUG_VAR : debug display/var structs
+ *   0 : no debug
+ *   1 : dumps display, fb_var
+ *
+ * sstfb specific ioctls:
+ *   		toggle vga (0x46db) : toggle vga_pass_through
+ *   		fill fb    (0x46dc) : fills fb
+ *   		test disp  (0x46de) : draws a test image
+ */
+
+#undef SST_DEBUG
+
+/* enable 24/32 bpp functions ? (completely untested!) */
+#undef EN_24_32_BPP
+
+/*
+  Default video mode .
+  0 800x600@60  took from glide
+  1 640x480@75  took from glide
+  2 1024x768@76 std fb.mode
+  3 640x480@60  glide default */
+#define DEFAULT_MODE 3 
+
+/*
+ * Includes
+ */
+
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+#include <asm/ioctl.h>
+#include <asm/uaccess.h>
+#include <video/sstfb.h>
+
+
+/* initialized by setup */
+
+static int vgapass;		/* enable Vga passthrough cable */
+static int mem;			/* mem size in MB, 0 = autodetect */
+static int clipping = 1;	/* use clipping (slower, safer) */
+static int gfxclk;		/* force FBI freq in Mhz . Dangerous */
+static int slowpci;		/* slow PCI settings */
+
+static char *mode_option __devinitdata;
+
+enum {
+	ID_VOODOO1 = 0,
+	ID_VOODOO2 = 1,
+};
+
+#define IS_VOODOO2(par) ((par)->type == ID_VOODOO2)
+
+static struct sst_spec voodoo_spec[] __devinitdata = {
+ { .name = "Voodoo Graphics", .default_gfx_clock = 50000, .max_gfxclk = 60 },
+ { .name = "Voodoo2",	      .default_gfx_clock = 75000, .max_gfxclk = 85 },
+};
+
+static struct fb_var_screeninfo	sstfb_default =
+#if ( DEFAULT_MODE == 0 )
+    { /* 800x600@60, 16 bpp .borowed from glide/sst1/include/sst1init.h */
+    800, 600, 800, 600, 0, 0, 16, 0,
+    {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
+    0, 0, -1, -1, 0,
+    25000, 86, 41, 23, 1, 127, 4,
+    0, FB_VMODE_NONINTERLACED };
+#elif ( DEFAULT_MODE == 1 )
+    {/* 640x480@75, 16 bpp .borowed from glide/sst1/include/sst1init.h */
+    640, 480, 640, 480, 0, 0, 16, 0,
+    {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
+    0, 0, -1, -1, 0,
+    31746, 118, 17, 16, 1, 63, 3,
+    0, FB_VMODE_NONINTERLACED };
+#elif ( DEFAULT_MODE == 2 )
+    { /* 1024x768@76 took from my /etc/fb.modes */
+    1024, 768, 1024, 768,0, 0, 16,0,
+    {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
+    0, 0, -1, -1, 0,
+    11764, 208, 8, 36, 16, 120, 3 ,
+    0, FB_VMODE_NONINTERLACED };
+#elif ( DEFAULT_MODE == 3 )
+    { /* 640x480@60 , 16bpp glide default ?*/
+    640, 480, 640, 480, 0, 0, 16, 0,
+    {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
+    0, 0, -1, -1, 0,
+    39721 ,  38, 26 ,  25 ,18  , 96 ,2,
+    0, FB_VMODE_NONINTERLACED };
+#elif
+    #error "Invalid DEFAULT_MODE value !"
+#endif
+
+
+/*
+ * debug functions
+ */
+
+static void sstfb_drawdebugimage(struct fb_info *info);
+static int sstfb_dump_regs(struct fb_info *info);
+
+
+#if (SST_DEBUG_REG > 0)
+static void sst_dbg_print_read_reg(u32 reg, u32 val) {
+	const char *regname;
+	switch (reg) {
+	case FBIINIT0:	regname = "FbiInit0"; break;
+	case FBIINIT1:	regname = "FbiInit1"; break;
+	case FBIINIT2:	regname = "FbiInit2"; break;
+	case FBIINIT3:	regname = "FbiInit3"; break;
+	case FBIINIT4:	regname = "FbiInit4"; break;
+	case FBIINIT5:	regname = "FbiInit5"; break;
+	case FBIINIT6:	regname = "FbiInit6"; break;
+	default:	regname = NULL;       break;
+	}
+	if (regname == NULL)
+		r_ddprintk("sst_read(%#x): %#x\n", reg, val);
+	else
+		r_dprintk(" sst_read(%s): %#x\n", regname, val);
+}
+
+static void sst_dbg_print_write_reg(u32 reg, u32 val) {
+	const char *regname;
+	switch (reg) {
+	case FBIINIT0:	regname = "FbiInit0"; break;
+	case FBIINIT1:	regname = "FbiInit1"; break;
+	case FBIINIT2:	regname = "FbiInit2"; break;
+	case FBIINIT3:	regname = "FbiInit3"; break;
+	case FBIINIT4:	regname = "FbiInit4"; break;
+	case FBIINIT5:	regname = "FbiInit5"; break;
+	case FBIINIT6:	regname = "FbiInit6"; break;
+	default:	regname = NULL;       break;
+	}
+	if (regname == NULL)
+		r_ddprintk("sst_write(%#x, %#x)\n", reg, val);
+	else
+		r_dprintk(" sst_write(%s, %#x)\n", regname, val);
+}
+#else /*  (SST_DEBUG_REG > 0) */
+#  define sst_dbg_print_read_reg(reg, val)	do {} while(0)
+#  define sst_dbg_print_write_reg(reg, val)	do {} while(0)
+#endif /*  (SST_DEBUG_REG > 0) */
+
+/*
+ * hardware access functions
+ */
+
+/* register access */
+#define sst_read(reg)		__sst_read(par->mmio_vbase, reg)
+#define sst_write(reg,val)	__sst_write(par->mmio_vbase, reg, val)
+#define sst_set_bits(reg,val)	__sst_set_bits(par->mmio_vbase, reg, val)
+#define sst_unset_bits(reg,val)	__sst_unset_bits(par->mmio_vbase, reg, val)
+#define sst_dac_read(reg)	__sst_dac_read(par->mmio_vbase, reg)
+#define sst_dac_write(reg,val)	__sst_dac_write(par->mmio_vbase, reg, val)
+#define dac_i_read(reg)		__dac_i_read(par->mmio_vbase, reg)
+#define dac_i_write(reg,val)	__dac_i_write(par->mmio_vbase, reg, val)
+
+static inline u32 __sst_read(u8 __iomem *vbase, u32 reg)
+{
+	u32 ret = readl(vbase + reg);
+	sst_dbg_print_read_reg(reg, ret);
+	return ret;
+}
+
+static inline void __sst_write(u8 __iomem *vbase, u32 reg, u32 val)
+{
+	sst_dbg_print_write_reg(reg, val);
+	writel(val, vbase + reg);
+}
+
+static inline void __sst_set_bits(u8 __iomem *vbase, u32 reg, u32 val)
+{
+	r_dprintk("sst_set_bits(%#x, %#x)\n", reg, val);
+	__sst_write(vbase, reg, __sst_read(vbase, reg) | val);
+}
+
+static inline void __sst_unset_bits(u8 __iomem *vbase, u32 reg, u32 val)
+{
+	r_dprintk("sst_unset_bits(%#x, %#x)\n", reg, val);
+	__sst_write(vbase, reg, __sst_read(vbase, reg) & ~val);
+}
+
+/*
+ * wait for the fbi chip. ASK: what happens if the fbi is stuck ?
+ *
+ * the FBI is supposed to be ready if we receive 5 time
+ * in a row a "idle" answer to our requests
+ */
+
+#define sst_wait_idle() __sst_wait_idle(par->mmio_vbase)
+
+static int __sst_wait_idle(u8 __iomem *vbase)
+{
+	int count = 0;
+
+	/* if (doFBINOP) __sst_write(vbase, NOPCMD, 0); */
+
+	while(1) {
+		if (__sst_read(vbase, STATUS) & STATUS_FBI_BUSY) {
+			f_dddprintk("status: busy\n");
+/* FIXME basicaly, this is a busy wait. maybe not that good. oh well;
+ * this is a small loop after all.
+ * Or maybe we should use mdelay() or udelay() here instead ? */
+			count = 0;
+		} else {
+			count++;
+			f_dddprintk("status: idle(%d)\n", count);
+		}
+		if (count >= 5) return 1;
+/* XXX  do something to avoid hanging the machine if the voodoo is out */
+	}
+}
+
+
+/* dac access */
+/* dac_read should be remaped to FbiInit2 (via the pci reg init_enable) */
+static u8 __sst_dac_read(u8 __iomem *vbase, u8 reg)
+{
+	u8 ret;
+
+	reg &= 0x07;
+	__sst_write(vbase, DAC_DATA, ((u32)reg << 8) | DAC_READ_CMD );
+	__sst_wait_idle(vbase);
+	/* udelay(10); */
+	ret = __sst_read(vbase, DAC_READ) & 0xff;
+	r_dprintk("sst_dac_read(%#x): %#x\n", reg, ret);
+
+	return ret;
+}
+
+static void __sst_dac_write(u8 __iomem *vbase, u8 reg, u8 val)
+{
+	r_dprintk("sst_dac_write(%#x, %#x)\n", reg, val);
+	reg &= 0x07;
+	__sst_write(vbase, DAC_DATA,(((u32)reg << 8)) | (u32)val);
+}
+
+/* indexed access to ti/att dacs */
+static u32 __dac_i_read(u8 __iomem *vbase, u8 reg)
+{
+	u32 ret;
+
+	__sst_dac_write(vbase, DACREG_ADDR_I, reg);
+	ret = __sst_dac_read(vbase, DACREG_DATA_I);
+	r_dprintk("sst_dac_read_i(%#x): %#x\n", reg, ret);
+	return ret;
+}
+static void __dac_i_write(u8 __iomem *vbase, u8 reg,u8 val)
+{
+	r_dprintk("sst_dac_write_i(%#x, %#x)\n", reg, val);
+	__sst_dac_write(vbase, DACREG_ADDR_I, reg);
+	__sst_dac_write(vbase, DACREG_DATA_I, val);
+}
+
+/* compute the m,n,p  , returns the real freq
+ * (ics datasheet :  N <-> N1 , P <-> N2)
+ *
+ * Fout= Fref * (M+2)/( 2^P * (N+2))
+ *  we try to get close to the asked freq
+ *  with P as high, and M as low as possible
+ * range:
+ * ti/att : 0 <= M <= 255; 0 <= P <= 3; 0<= N <= 63
+ * ics    : 1 <= M <= 127; 0 <= P <= 3; 1<= N <= 31
+ * we'll use the lowest limitation, should be precise enouth
+ */
+static int sst_calc_pll(const int freq, int *freq_out, struct pll_timing *t)
+{
+	int m, m2, n, p, best_err, fout;
+	int best_n = -1;
+	int best_m = -1;
+
+	best_err = freq;
+	p = 3;
+	/* f * 2^P = vco should be less than VCOmax ~ 250 MHz for ics*/
+	while (((1 << p) * freq > VCO_MAX) && (p >= 0))
+		p--;
+	if (p == -1)
+		return -EINVAL;
+	for (n = 1; n < 32; n++) {
+		/* calc 2 * m so we can round it later*/
+		m2 = (2 * freq * (1 << p) * (n + 2) ) / DAC_FREF - 4 ;
+
+		m = (m2 % 2 ) ? m2/2+1 : m2/2 ;
+		if (m >= 128)
+			break;
+		fout = (DAC_FREF * (m + 2)) / ((1 << p) * (n + 2));
+		if ((abs(fout - freq) < best_err) && (m > 0)) {
+			best_n = n;
+			best_m = m;
+			best_err = abs(fout - freq);
+			/* we get the lowest m , allowing 0.5% error in freq*/
+			if (200*best_err < freq) break;
+		}
+	}
+	if (best_n == -1)  /* unlikely, but who knows ? */
+		return -EINVAL;
+	t->p = p;
+	t->n = best_n;
+	t->m = best_m;
+	*freq_out = (DAC_FREF * (t->m + 2)) / ((1 << t->p) * (t->n + 2));
+	f_ddprintk ("m: %d, n: %d, p: %d, F: %dKhz\n",
+		  t->m, t->n, t->p, *freq_out);
+	return 0;
+}
+
+/*
+ * clear lfb screen
+ */
+static void sstfb_clear_screen(struct fb_info *info)
+{
+	/* clear screen */
+	fb_memset(info->screen_base, 0, info->fix.smem_len);
+}
+
+
+/**
+ *      sstfb_check_var - Optional function.  Validates a var passed in.
+ *      @var: frame buffer variable screen structure
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int sstfb_check_var(struct fb_var_screeninfo *var,
+		struct fb_info *info)
+{
+	struct sstfb_par *par = (struct sstfb_par *) info->par;
+	int hSyncOff   = var->xres + var->right_margin + var->left_margin;
+	int vSyncOff   = var->yres + var->lower_margin + var->upper_margin;
+	int vBackPorch = var->left_margin, yDim = var->yres;
+	int vSyncOn    = var->vsync_len;
+	int tiles_in_X, real_length;
+	unsigned int freq;
+
+	if (sst_calc_pll(PICOS2KHZ(var->pixclock), &freq, &par->pll)) {
+		eprintk("Pixclock at %ld KHZ out of range\n",
+				PICOS2KHZ(var->pixclock));
+		return -EINVAL;
+	}
+	var->pixclock = KHZ2PICOS(freq);
+	
+	if (var->vmode & FB_VMODE_INTERLACED)
+		vBackPorch += (vBackPorch % 2);
+	if (var->vmode & FB_VMODE_DOUBLE) {
+		vBackPorch <<= 1;
+		yDim <<=1;
+		vSyncOn <<=1;
+		vSyncOff <<=1;
+	}
+
+	switch (var->bits_per_pixel) {
+	case 0 ... 16 :
+		var->bits_per_pixel = 16;
+		break;
+#ifdef EN_24_32_BPP
+	case 17 ... 24 :
+		var->bits_per_pixel = 24;
+		break;
+	case 25 ... 32 :
+		var->bits_per_pixel = 32;
+		break;
+#endif
+	default :
+		eprintk("Unsupported bpp %d\n", var->bits_per_pixel);
+		return -EINVAL;
+	}
+	
+	/* validity tests */
+	if ((var->xres <= 1) || (yDim <= 0 )
+	   || (var->hsync_len <= 1)
+	   || (hSyncOff <= 1)
+	   || (var->left_margin <= 2)
+	   || (vSyncOn <= 0)
+	   || (vSyncOff <= 0)
+	   || (vBackPorch <= 0)) {
+		return -EINVAL;
+	}
+
+	if (IS_VOODOO2(par)) {
+		/* Voodoo 2 limits */
+		tiles_in_X = (var->xres + 63 ) / 64 * 2;		
+
+		if (((var->xres - 1) >= POW2(11)) || (yDim >= POW2(11))) {
+			eprintk("Unsupported resolution %dx%d\n",
+			         var->xres, var->yres);
+			return -EINVAL;
+		}
+
+		if (((var->hsync_len-1) >= POW2(9))
+		   || ((hSyncOff-1) >= POW2(11))
+		   || ((var->left_margin - 2) >= POW2(9))
+		   || (vSyncOn >= POW2(13))
+		   || (vSyncOff >= POW2(13))
+		   || (vBackPorch >= POW2(9))
+		   || (tiles_in_X >= POW2(6))
+		   || (tiles_in_X <= 0)) {
+			eprintk("Unsupported Timings\n");
+			return -EINVAL;
+		}
+	} else {
+		/* Voodoo limits */
+		tiles_in_X = (var->xres + 63 ) / 64;
+
+		if (var->vmode) {
+			eprintk("Interlace/Doublescan not supported %#x\n",
+				var->vmode);
+			return -EINVAL;
+		}
+		if (((var->xres - 1) >= POW2(10)) || (var->yres >= POW2(10))) {
+			eprintk("Unsupported resolution %dx%d\n",
+			         var->xres, var->yres);
+			return -EINVAL;
+		}
+		if (((var->hsync_len - 1) >= POW2(8))
+		   || ((hSyncOff-1) >= POW2(10))
+		   || ((var->left_margin - 2) >= POW2(8))
+		   || (vSyncOn >= POW2(12))
+		   || (vSyncOff >= POW2(12))
+		   || (vBackPorch >= POW2(8))
+		   || (tiles_in_X >= POW2(4))
+		   || (tiles_in_X <= 0)) {
+			eprintk("Unsupported Timings\n");
+			return -EINVAL;
+		}
+	}
+
+	/* it seems that the fbi uses tiles of 64x16 pixels to "map" the mem */
+	/* FIXME: i don't like this... looks wrong */
+	real_length = tiles_in_X  * (IS_VOODOO2(par) ? 32 : 64 )
+	              * ((var->bits_per_pixel == 16) ? 2 : 4);
+
+	if ((real_length * yDim) > info->fix.smem_len) {
+		eprintk("Not enough video memory\n");
+		return -ENOMEM;
+	}
+
+	var->sync &= (FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT);
+	var->vmode &= (FB_VMODE_INTERLACED | FB_VMODE_DOUBLE);
+	var->xoffset = 0;
+	var->yoffset = 0;
+	var->height  = -1;
+	var->width   = -1;
+
+	/*
+	 * correct the color bit fields
+	 */
+	/* var->{red|green|blue}.msb_right = 0; */
+
+	switch (var->bits_per_pixel) {
+	case 16:	/* RGB 565  LfbMode 0 */
+		var->red.length    = 5;
+		var->green.length  = 6;
+		var->blue.length   = 5;
+		var->transp.length = 0;
+
+		var->red.offset    = 11;
+		var->green.offset  = 5;
+		var->blue.offset   = 0;
+		var->transp.offset = 0;
+		break;
+#ifdef EN_24_32_BPP
+	case 24:	/* RGB 888 LfbMode 4 */
+	case 32:	/* ARGB 8888 LfbMode 5 */
+		var->red.length    = 8;
+		var->green.length  = 8;
+		var->blue.length   = 8;
+		var->transp.length = 0;
+
+		var->red.offset    = 16;
+		var->green.offset  = 8;
+		var->blue.offset   = 0;
+		var->transp.offset = 0; /* in 24bpp we fake a 32 bpp mode */
+		break;
+#endif
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/**
+ *      sstfb_set_par - Optional function.  Alters the hardware state.
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int sstfb_set_par(struct fb_info *info)
+{
+	struct sstfb_par *par = (struct sstfb_par *) info->par;
+	u32 lfbmode, fbiinit1, fbiinit2, fbiinit3, fbiinit5, fbiinit6=0;
+	struct pci_dev *sst_dev = par->dev;
+	unsigned int freq;
+	int ntiles;
+
+	par->hSyncOff	= info->var.xres + info->var.right_margin + info->var.left_margin;
+
+	par->yDim 	= info->var.yres;
+	par->vSyncOn 	= info->var.vsync_len;
+	par->vSyncOff	= info->var.yres + info->var.lower_margin + info->var.upper_margin;
+	par->vBackPorch = info->var.upper_margin;
+
+	/* We need par->pll */
+	sst_calc_pll(PICOS2KHZ(info->var.pixclock), &freq, &par->pll);
+
+	if (info->var.vmode & FB_VMODE_INTERLACED)
+		par->vBackPorch += (par->vBackPorch % 2);
+	if (info->var.vmode & FB_VMODE_DOUBLE) {
+		par->vBackPorch <<= 1;
+		par->yDim <<=1;
+		par->vSyncOn <<=1;
+		par->vSyncOff <<=1;
+	}
+
+	if (IS_VOODOO2(par)) {
+		/* voodoo2 has 32 pixel wide tiles , BUT stange things
+		   happen with odd number of tiles */
+		par->tiles_in_X = (info->var.xres + 63 ) / 64 * 2;
+	} else {
+		/* voodoo1 has 64 pixels wide tiles. */
+		par->tiles_in_X = (info->var.xres + 63 ) / 64;
+	}
+
+	f_ddprintk("hsync_len hSyncOff vsync_len vSyncOff\n");
+	f_ddprintk("%-7d %-8d %-7d %-8d\n",
+	           info->var.hsync_len, par->hSyncOff,
+	           par->vSyncOn, par->vSyncOff);
+	f_ddprintk("left_margin upper_margin xres yres Freq\n");
+	f_ddprintk("%-10d %-10d %-4d %-4d %-8ld\n",
+	           info->var.left_margin, info->var.upper_margin,
+	           info->var.xres, info->var.yres, PICOS2KHZ(info->var.pixclock));
+
+	sst_write(NOPCMD, 0);
+	sst_wait_idle();
+	pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR);
+	sst_set_bits(FBIINIT1, VIDEO_RESET);
+	sst_set_bits(FBIINIT0, FBI_RESET | FIFO_RESET);
+	sst_unset_bits(FBIINIT2, EN_DRAM_REFRESH);
+	sst_wait_idle();
+
+	/*sst_unset_bits (FBIINIT0, FBI_RESET); / reenable FBI ? */
+
+	sst_write(BACKPORCH, par->vBackPorch << 16 | (info->var.left_margin - 2));
+	sst_write(VIDEODIMENSIONS, par->yDim << 16 | (info->var.xres - 1));
+	sst_write(HSYNC, (par->hSyncOff - 1) << 16 | (info->var.hsync_len - 1));
+	sst_write(VSYNC,       par->vSyncOff << 16 | par->vSyncOn);
+
+	fbiinit2 = sst_read(FBIINIT2);
+	fbiinit3 = sst_read(FBIINIT3);
+
+	/* everything is reset. we enable fbiinit2/3 remap : dac acces ok */
+	pci_write_config_dword(sst_dev, PCI_INIT_ENABLE,
+	                       PCI_EN_INIT_WR | PCI_REMAP_DAC );
+
+	par->dac_sw.set_vidmod(info, info->var.bits_per_pixel);
+
+	/* set video clock */
+	par->dac_sw.set_pll(info, &par->pll, VID_CLOCK);
+
+	/* disable fbiinit2/3 remap */
+	pci_write_config_dword(sst_dev, PCI_INIT_ENABLE,
+	                       PCI_EN_INIT_WR);
+
+	/* restore fbiinit2/3 */
+	sst_write(FBIINIT2,fbiinit2);
+	sst_write(FBIINIT3,fbiinit3);
+
+	fbiinit1 = (sst_read(FBIINIT1) & VIDEO_MASK)
+	            | EN_DATA_OE
+	            | EN_BLANK_OE
+	            | EN_HVSYNC_OE
+	            | EN_DCLK_OE
+		 /* | (15 << TILES_IN_X_SHIFT) */
+	            | SEL_INPUT_VCLK_2X
+		 /* | (2 << VCLK_2X_SEL_DEL_SHIFT)
+	            | (2 << VCLK_DEL_SHIFT) */;
+/* try with vclk_in_delay =0 (bits 29:30) , vclk_out_delay =0 (bits(27:28)
+ in (near) future set them accordingly to revision + resolution (cf glide)
+ first understand what it stands for :)
+ FIXME: there are some artefacts... check for the vclk_in_delay
+ lets try with 6ns delay in both vclk_out & in...
+ doh... they're still there :\
+*/
+
+	ntiles = par->tiles_in_X;
+	if (IS_VOODOO2(par)) {
+		fbiinit1 |= ((ntiles & 0x20) >> 5) << TILES_IN_X_MSB_SHIFT
+		            | ((ntiles & 0x1e) >> 1) << TILES_IN_X_SHIFT;
+/* as the only value of importance for us in fbiinit6 is tiles in X (lsb),
+   and as reading fbinit 6 will return crap (see FBIINIT6_DEFAULT) we just
+   write our value. BTW due to the dac unable to read odd number of tiles, this
+   field is always null ... */
+		fbiinit6 = (ntiles & 0x1) << TILES_IN_X_LSB_SHIFT;
+	}
+	else
+		fbiinit1 |= ntiles << TILES_IN_X_SHIFT;
+
+	switch (info->var.bits_per_pixel) {
+	case 16:
+		fbiinit1 |=  SEL_SOURCE_VCLK_2X_SEL;
+		break;
+#ifdef EN_24_32_BPP
+	case 24:
+	case 32:
+		/* sst_set_bits(FBIINIT1, SEL_SOURCE_VCLK_2X_DIV2 | EN_24BPP);*/
+		fbiinit1 |= SEL_SOURCE_VCLK_2X_SEL | EN_24BPP;
+		break;
+#endif
+	default:
+		return -EINVAL;
+	}
+	sst_write(FBIINIT1, fbiinit1);
+	if (IS_VOODOO2(par)) {
+		sst_write(FBIINIT6, fbiinit6);
+		fbiinit5=sst_read(FBIINIT5) & FBIINIT5_MASK ;
+		if (info->var.vmode & FB_VMODE_INTERLACED)
+			fbiinit5 |= INTERLACE;
+		if (info->var.vmode & FB_VMODE_DOUBLE)
+			fbiinit5 |= VDOUBLESCAN;
+		if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
+			fbiinit5 |= HSYNC_HIGH;
+		if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
+			fbiinit5 |= VSYNC_HIGH;
+		sst_write(FBIINIT5, fbiinit5);
+	}
+	sst_wait_idle();
+	sst_unset_bits(FBIINIT1, VIDEO_RESET);
+	sst_unset_bits(FBIINIT0, FBI_RESET | FIFO_RESET);
+	sst_set_bits(FBIINIT2, EN_DRAM_REFRESH);
+	/* disables fbiinit writes */
+	pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, PCI_EN_FIFO_WR);
+
+	/* set lfbmode : set mode + front buffer for reads/writes
+	   + disable pipeline */
+	switch (info->var.bits_per_pixel) {
+	case 16:
+		lfbmode = LFB_565;
+		break;
+#ifdef EN_24_32_BPP
+	case 24:
+		lfbmode = LFB_888;
+		break;
+	case 32:
+		lfbmode = LFB_8888;
+		break;
+#endif
+	default:
+		return -EINVAL;
+	}
+
+#if defined(__BIG_ENDIAN)
+	/* Enable byte-swizzle functionality in hardware.
+	 * With this enabled, all our read- and write-accesses to
+	 * the voodoo framebuffer can be done in native format, and
+	 * the hardware will automatically convert it to little-endian.
+	 * - tested on HP-PARISC, Helge Deller <deller@gmx.de> */
+	lfbmode |= ( LFB_WORD_SWIZZLE_WR | LFB_BYTE_SWIZZLE_WR |
+		     LFB_WORD_SWIZZLE_RD | LFB_BYTE_SWIZZLE_RD );
+#endif
+	
+	if (clipping) {
+		sst_write(LFBMODE, lfbmode | EN_PXL_PIPELINE);
+	/*
+	 * Set "clipping" dimensions. If clipping is disabled and
+	 * writes to offscreen areas of the framebuffer are performed,
+	 * the "behaviour is undefined" (_very_ undefined) - Urs
+	 */
+	/* btw, it requires enabling pixel pipeline in LFBMODE .
+	   off screen read/writes will just wrap and read/print pixels
+	   on screen. Ugly but not that dangerous */
+		f_ddprintk("setting clipping dimensions 0..%d, 0..%d\n",
+		            info->var.xres - 1, par->yDim - 1);
+
+		sst_write(CLIP_LEFT_RIGHT, info->var.xres);
+		sst_write(CLIP_LOWY_HIGHY, par->yDim);
+		sst_set_bits(FBZMODE, EN_CLIPPING | EN_RGB_WRITE);
+	} else {
+		/* no clipping : direct access, no pipeline */
+		sst_write(LFBMODE, lfbmode);
+	}
+	return 0;
+}
+
+/**
+ *      sstfb_setcolreg - Optional function. Sets a color register.
+ *      @regno: hardware colormap register
+ *      @red: frame buffer colormap structure
+ *      @green: The green value which can be up to 16 bits wide
+ *      @blue:  The blue value which can be up to 16 bits wide.
+ *      @transp: If supported the alpha value which can be up to 16 bits wide.
+ *      @info: frame buffer info structure
+ */
+static int sstfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                           u_int transp, struct fb_info *info)
+{
+	u32 col;
+
+	f_dddprintk("sstfb_setcolreg\n");
+	f_dddprintk("%-2d rgbt: %#x, %#x, %#x, %#x\n",
+	            regno, red, green, blue, transp);
+	if (regno >= 16)
+		return -EINVAL;
+
+	red    >>= (16 - info->var.red.length);
+	green  >>= (16 - info->var.green.length);
+	blue   >>= (16 - info->var.blue.length);
+	transp >>= (16 - info->var.transp.length);
+	col = (red << info->var.red.offset)
+	    | (green << info->var.green.offset)
+	    | (blue  << info->var.blue.offset)
+	    | (transp << info->var.transp.offset);
+	
+	((u32 *)info->pseudo_palette)[regno] = col;
+
+	return 0;
+}
+
+static int sstfb_ioctl(struct inode *inode, struct file *file,
+                       u_int cmd, u_long arg, struct fb_info *info )
+{
+	struct sstfb_par *par = (struct sstfb_par *) info->par;
+	struct pci_dev *sst_dev = par->dev;
+	u32 fbiinit0, tmp, val;
+	u_long p;
+
+	switch (cmd) {
+		
+	/* dump current FBIINIT values to system log */
+	case _IO('F', 0xdb):            /* 0x46db */
+		return sstfb_dump_regs(info);
+		
+	/* fills lfb with #arg pixels */
+	case _IOW('F', 0xdc, u32):	/* 0x46dc */
+		if (copy_from_user(&val, (void __user *)arg, sizeof(val)))
+			return -EFAULT;
+		if (val > info->fix.smem_len)
+			val = info->fix.smem_len;
+		printk("filling %#x \n", val);
+		for (p=0 ; p<val; p+=2)
+			writew(p >> 6, info->screen_base + p);
+		return 0;
+		
+	/* change VGA pass_through mode */
+	case _IOW('F', 0xdd, u32):	/* 0x46dd */
+		if (copy_from_user(&val, (void __user *)arg, sizeof(val)))
+			return -EFAULT;
+		pci_read_config_dword(sst_dev, PCI_INIT_ENABLE, &tmp);
+		pci_write_config_dword(sst_dev, PCI_INIT_ENABLE,
+				       tmp | PCI_EN_INIT_WR );
+		fbiinit0 = sst_read (FBIINIT0);
+		if (val) {
+			sst_write(FBIINIT0, fbiinit0 & ~EN_VGA_PASSTHROUGH);
+			iprintk("Disabling VGA pass-through\n");
+		} else {
+			sst_write(FBIINIT0, fbiinit0 | EN_VGA_PASSTHROUGH);
+			iprintk("Enabling VGA pass-through\n");
+		}
+		pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, tmp);
+		return 0;
+		
+	/* draw test image  */
+	case _IO('F', 0xde):		/* 0x46de */
+		f_dprintk("test color display at %d bpp\n",
+					info->var.bits_per_pixel);
+		sstfb_drawdebugimage(info);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+
+/*
+ * Screen-to-Screen BitBlt 2D command (for the bmove fb op.) - Voodoo2 only
+ */
+#if 0
+static void sstfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+	struct sstfb_par *par = (struct sstfb_par *) info->par;
+	u32 stride = info->fix.line_length;
+   
+	if (!IS_VOODOO2(par))
+		return;
+
+	sst_write(BLTSRCBASEADDR, 0);
+	sst_write(BLTDSTBASEADDR, 0);
+	sst_write(BLTROP, BLTROP_COPY);
+	sst_write(BLTXYSTRIDES, stride | (stride << 16));
+	sst_write(BLTSRCXY, area->sx | (area->sy << 16));
+	sst_write(BLTDSTXY, area->dx | (area->dy << 16));
+	sst_write(BLTSIZE, area->width | (area->height << 16));
+	sst_write(BLTCOMMAND, BLT_SCR2SCR_BITBLT | LAUNCH_BITBLT |
+		(BLT_16BPP_FMT << 3) /* | BIT(14) */ | BIT(15) );
+	sst_wait_idle();
+}
+#endif
+
+
+/*
+ * FillRect 2D command (solidfill or invert (via ROP_XOR)) - Voodoo2 only
+ */
+static void sstfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 
+{
+	struct sstfb_par *par = (struct sstfb_par *) info->par;
+	u32 stride = info->fix.line_length;
+
+	if (!IS_VOODOO2(par))
+		return;
+   	
+	sst_write(BLTCLIPX, info->var.xres);
+	sst_write(BLTCLIPY, info->var.yres);
+	
+	sst_write(BLTDSTBASEADDR, 0);
+	sst_write(BLTCOLOR, rect->color);
+	sst_write(BLTROP, rect->rop == ROP_COPY ? BLTROP_COPY : BLTROP_XOR);
+	sst_write(BLTXYSTRIDES, stride | (stride << 16));
+	sst_write(BLTDSTXY, rect->dx | (rect->dy << 16));
+	sst_write(BLTSIZE, rect->width | (rect->height << 16));
+	sst_write(BLTCOMMAND, BLT_RECFILL_BITBLT | LAUNCH_BITBLT
+		 | (BLT_16BPP_FMT << 3) /* | BIT(14) */ | BIT(15) | BIT(16) );
+	sst_wait_idle();
+}
+
+
+
+/* 
+ * get lfb size 
+ */
+static int __devinit sst_get_memsize(struct fb_info *info, __u32 *memsize)
+{
+	u8 __iomem *fbbase_virt = info->screen_base;
+
+	/* force memsize */
+	if ((mem >= 1 ) &&  (mem <= 4)) {
+		*memsize = (mem * 0x100000);
+		iprintk("supplied memsize: %#x\n", *memsize);
+		return 1;
+	}
+
+	writel(0xdeadbeef, fbbase_virt);
+	writel(0xdeadbeef, fbbase_virt+0x100000);
+	writel(0xdeadbeef, fbbase_virt+0x200000);
+	f_ddprintk("0MB: %#x, 1MB: %#x, 2MB: %#x\n",
+	           readl(fbbase_virt), readl(fbbase_virt + 0x100000),
+	           readl(fbbase_virt + 0x200000));
+
+	writel(0xabcdef01, fbbase_virt);
+
+	f_ddprintk("0MB: %#x, 1MB: %#x, 2MB: %#x\n",
+	           readl(fbbase_virt), readl(fbbase_virt + 0x100000),
+	           readl(fbbase_virt + 0x200000));
+
+	/* checks for 4mb lfb, then 2, then defaults to 1 */
+	if (readl(fbbase_virt + 0x200000) == 0xdeadbeef)
+		*memsize = 0x400000;
+	else if (readl(fbbase_virt + 0x100000) == 0xdeadbeef)
+		*memsize = 0x200000;
+	else
+		*memsize = 0x100000;
+	f_ddprintk("detected memsize: %dMB\n", *memsize >> 20);
+	return 1;
+}
+
+
+/* 
+ * DAC detection routines 
+ */
+
+/* fbi should be idle, and fifo emty and mem disabled */
+/* supposed to detect AT&T ATT20C409 and Ti TVP3409 ramdacs */
+
+static int __devinit sst_detect_att(struct fb_info *info)
+{
+	struct sstfb_par *par = (struct sstfb_par *) info->par;
+	int i, mir, dir;
+
+	for (i=0; i<3; i++) {
+		sst_dac_write(DACREG_WMA, 0); 	/* backdoor */
+		sst_dac_read(DACREG_RMR);	/* read 4 times RMR */
+		sst_dac_read(DACREG_RMR);
+		sst_dac_read(DACREG_RMR);
+		sst_dac_read(DACREG_RMR);
+		/* the fifth time,  CR0 is read */
+		sst_dac_read(DACREG_RMR);
+		/* the 6th, manufacturer id register */
+		mir = sst_dac_read(DACREG_RMR);
+		/*the 7th, device ID register */
+		dir = sst_dac_read(DACREG_RMR);
+		f_ddprintk("mir: %#x, dir: %#x\n", mir, dir);
+		if ((mir == DACREG_MIR_ATT ) && (dir == DACREG_DIR_ATT)) {
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static int __devinit sst_detect_ti(struct fb_info *info)
+{
+	struct sstfb_par *par = (struct sstfb_par *) info->par;
+	int i, mir, dir;
+
+	for (i = 0; i<3; i++) {
+		sst_dac_write(DACREG_WMA, 0); 	/* backdoor */
+		sst_dac_read(DACREG_RMR);	/* read 4 times RMR */
+		sst_dac_read(DACREG_RMR);
+		sst_dac_read(DACREG_RMR);
+		sst_dac_read(DACREG_RMR);
+		/* the fifth time,  CR0 is read */
+		sst_dac_read(DACREG_RMR);
+		/* the 6th, manufacturer id register */
+		mir = sst_dac_read(DACREG_RMR);
+		/*the 7th, device ID register */
+		dir = sst_dac_read(DACREG_RMR);
+		f_ddprintk("mir: %#x, dir: %#x\n", mir, dir);
+		if ((mir == DACREG_MIR_TI ) && (dir == DACREG_DIR_TI)) {
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * try to detect ICS5342  ramdac
+ * we get the 1st byte (M value) of preset f1,f7 and fB
+ * why those 3 ? mmmh... for now, i'll do it the glide way...
+ * and ask questions later. anyway, it seems that all the freq registers are
+ * realy at their default state (cf specs) so i ask again, why those 3 regs ?
+ * mmmmh.. it seems that's much more ugly than i thought. we use f0 and fA for
+ * pll programming, so in fact, we *hope* that the f1, f7 & fB won't be
+ * touched...
+ * is it realy safe ? how can i reset this ramdac ? geee...
+ */
+static int __devinit sst_detect_ics(struct fb_info *info)
+{
+	struct sstfb_par *par = (struct sstfb_par *) info->par;
+	int m_clk0_1, m_clk0_7, m_clk1_b;
+	int n_clk0_1, n_clk0_7, n_clk1_b;
+	int i;
+
+	for (i = 0; i<5; i++ ) {
+		sst_dac_write(DACREG_ICS_PLLRMA, 0x1);	/* f1 */
+		m_clk0_1 = sst_dac_read(DACREG_ICS_PLLDATA);
+		n_clk0_1 = sst_dac_read(DACREG_ICS_PLLDATA);
+		sst_dac_write(DACREG_ICS_PLLRMA, 0x7);	/* f7 */
+		m_clk0_7 = sst_dac_read(DACREG_ICS_PLLDATA);
+		n_clk0_7 = sst_dac_read(DACREG_ICS_PLLDATA);
+		sst_dac_write(DACREG_ICS_PLLRMA, 0xb);	/* fB */
+		m_clk1_b= sst_dac_read(DACREG_ICS_PLLDATA);
+		n_clk1_b= sst_dac_read(DACREG_ICS_PLLDATA);
+		f_ddprintk("m_clk0_1: %#x, m_clk0_7: %#x, m_clk1_b: %#x\n",
+			m_clk0_1, m_clk0_7, m_clk1_b);
+		f_ddprintk("n_clk0_1: %#x, n_clk0_7: %#x, n_clk1_b: %#x\n",
+			n_clk0_1, n_clk0_7, n_clk1_b);
+		if ((   m_clk0_1 == DACREG_ICS_PLL_CLK0_1_INI)
+		    && (m_clk0_7 == DACREG_ICS_PLL_CLK0_7_INI)
+		    && (m_clk1_b == DACREG_ICS_PLL_CLK1_B_INI)) {
+			return 1;
+		}
+	}
+	return 0;
+}
+
+
+/*
+ * gfx, video, pci fifo should be reset, dram refresh disabled
+ * see detect_dac
+ */
+
+static int sst_set_pll_att_ti(struct fb_info *info, 
+		const struct pll_timing *t, const int clock)
+{
+	struct sstfb_par *par = (struct sstfb_par *) info->par;
+	u8 cr0, cc;
+
+	/* enable indexed mode */
+	sst_dac_write(DACREG_WMA, 0); 	/* backdoor */
+	sst_dac_read(DACREG_RMR);	/* 1 time:  RMR */
+	sst_dac_read(DACREG_RMR);	/* 2 RMR */
+	sst_dac_read(DACREG_RMR);	/* 3 //  */
+	sst_dac_read(DACREG_RMR);	/* 4 //  */
+	cr0 = sst_dac_read(DACREG_RMR);	/* 5 CR0 */
+
+	sst_dac_write(DACREG_WMA, 0);
+	sst_dac_read(DACREG_RMR);
+	sst_dac_read(DACREG_RMR);
+	sst_dac_read(DACREG_RMR);
+	sst_dac_read(DACREG_RMR);
+	sst_dac_write(DACREG_RMR, (cr0 & 0xf0)
+	              | DACREG_CR0_EN_INDEXED
+	              | DACREG_CR0_8BIT
+	              | DACREG_CR0_PWDOWN );
+	/* so, now we are in indexed mode . dunno if its common, but
+	   i find this way of doing things a little bit weird :p */
+
+	udelay(300);
+	cc = dac_i_read(DACREG_CC_I);
+	switch (clock) {
+	case VID_CLOCK:
+		dac_i_write(DACREG_AC0_I, t->m);
+		dac_i_write(DACREG_AC1_I, t->p << 6 | t->n);
+		dac_i_write(DACREG_CC_I,
+		            (cc & 0x0f) | DACREG_CC_CLKA | DACREG_CC_CLKA_C);
+		break;
+	case GFX_CLOCK:
+		dac_i_write(DACREG_BD0_I, t->m);
+		dac_i_write(DACREG_BD1_I, t->p << 6 | t->n);
+		dac_i_write(DACREG_CC_I,
+		            (cc & 0xf0) | DACREG_CC_CLKB | DACREG_CC_CLKB_D);
+		break;
+	default:
+		dprintk("%s: wrong clock code '%d'\n",
+		        __FUNCTION__, clock);
+		return 0;
+		}
+	udelay(300);
+
+	/* power up the dac & return to "normal" non-indexed mode */
+	dac_i_write(DACREG_CR0_I,
+	            cr0 & ~DACREG_CR0_PWDOWN & ~DACREG_CR0_EN_INDEXED);
+	return 1;
+}
+
+static int sst_set_pll_ics(struct fb_info *info,
+		const struct pll_timing *t, const int clock)
+{
+	struct sstfb_par *par = (struct sstfb_par *) info->par;
+	u8 pll_ctrl;
+
+	sst_dac_write(DACREG_ICS_PLLRMA, DACREG_ICS_PLL_CTRL);
+	pll_ctrl = sst_dac_read(DACREG_ICS_PLLDATA);
+	switch(clock) {
+	case VID_CLOCK:
+		sst_dac_write(DACREG_ICS_PLLWMA, 0x0);	/* CLK0, f0 */
+		sst_dac_write(DACREG_ICS_PLLDATA, t->m);
+		sst_dac_write(DACREG_ICS_PLLDATA, t->p << 5 | t->n);
+		/* selects freq f0 for clock 0 */
+		sst_dac_write(DACREG_ICS_PLLWMA, DACREG_ICS_PLL_CTRL);
+		sst_dac_write(DACREG_ICS_PLLDATA,
+		              (pll_ctrl & 0xd8)
+		              | DACREG_ICS_CLK0
+		              | DACREG_ICS_CLK0_0);
+		break;
+	case GFX_CLOCK :
+		sst_dac_write(DACREG_ICS_PLLWMA, 0xa);	/* CLK1, fA */
+		sst_dac_write(DACREG_ICS_PLLDATA, t->m);
+		sst_dac_write(DACREG_ICS_PLLDATA, t->p << 5 | t->n);
+		/* selects freq fA for clock 1 */
+		sst_dac_write(DACREG_ICS_PLLWMA, DACREG_ICS_PLL_CTRL);
+		sst_dac_write(DACREG_ICS_PLLDATA,
+		              (pll_ctrl & 0xef) | DACREG_ICS_CLK1_A);
+		break;
+	default:
+		dprintk("%s: wrong clock code '%d'\n",
+		        __FUNCTION__, clock);
+		return 0;
+		}
+	udelay(300);
+	return 1;
+}
+
+static void sst_set_vidmod_att_ti(struct fb_info *info, const int bpp)
+{
+	struct sstfb_par *par = (struct sstfb_par *) info->par;
+	u8 cr0;
+
+	sst_dac_write(DACREG_WMA, 0); 	/* backdoor */
+	sst_dac_read(DACREG_RMR);	/* read 4 times RMR */
+	sst_dac_read(DACREG_RMR);
+	sst_dac_read(DACREG_RMR);
+	sst_dac_read(DACREG_RMR);
+	/* the fifth time,  CR0 is read */
+	cr0 = sst_dac_read(DACREG_RMR);
+
+	sst_dac_write(DACREG_WMA, 0); 	/* backdoor */
+	sst_dac_read(DACREG_RMR);	/* read 4 times RMR */
+	sst_dac_read(DACREG_RMR);
+	sst_dac_read(DACREG_RMR);
+	sst_dac_read(DACREG_RMR);
+	/* cr0 */
+	switch(bpp) {
+	case 16:
+		sst_dac_write(DACREG_RMR, (cr0 & 0x0f) | DACREG_CR0_16BPP);
+		break;
+#ifdef EN_24_32_BPP
+	case 24:
+	case 32:
+		sst_dac_write(DACREG_RMR, (cr0 & 0x0f) | DACREG_CR0_24BPP);
+		break;
+#endif
+	default:
+		dprintk("%s: bad depth '%u'\n", __FUNCTION__, bpp);
+		break;
+	}
+}
+
+static void sst_set_vidmod_ics(struct fb_info *info, const int bpp)
+{
+	struct sstfb_par *par = (struct sstfb_par *) info->par;
+
+	switch(bpp) {
+	case 16:
+		sst_dac_write(DACREG_ICS_CMD, DACREG_ICS_CMD_16BPP);
+		break;
+#ifdef EN_24_32_BPP
+	case 24:
+	case 32:
+		sst_dac_write(DACREG_ICS_CMD, DACREG_ICS_CMD_24BPP);
+		break;
+#endif
+	default:
+		dprintk("%s: bad depth '%u'\n", __FUNCTION__, bpp);
+		break;
+	}
+}
+
+/*
+ * detect dac type
+ * prerequisite : write to FbiInitx enabled, video and fbi and pci fifo reset,
+ * dram refresh disabled, FbiInit remaped.
+ * TODO: mmh.. maybe i shoud put the "prerequisite" in the func ...
+ */
+
+
+static struct dac_switch dacs[] __devinitdata = {
+	{	.name		= "TI TVP3409",
+		.detect		= sst_detect_ti,
+		.set_pll	= sst_set_pll_att_ti,
+		.set_vidmod	= sst_set_vidmod_att_ti },
+
+	{	.name		= "AT&T ATT20C409",
+		.detect		= sst_detect_att,
+		.set_pll	= sst_set_pll_att_ti,
+		.set_vidmod	= sst_set_vidmod_att_ti },
+	{	.name		= "ICS ICS5342",
+		.detect		= sst_detect_ics,
+		.set_pll	= sst_set_pll_ics,
+		.set_vidmod	= sst_set_vidmod_ics },
+};
+
+static int __devinit sst_detect_dactype(struct fb_info *info, struct sstfb_par *par)
+{
+	int i, ret = 0;
+	
+	for (i=0; i<sizeof(dacs)/sizeof(dacs[0]); i++) {
+		ret = dacs[i].detect(info);
+		if (ret) break;
+	}
+	if (!ret)
+		return 0;
+	f_dprintk("%s found %s\n", __FUNCTION__, dacs[i].name);
+	par->dac_sw = dacs[i];
+	return 1;
+}
+
+/*
+ * Internal Routines
+ */
+static int __devinit sst_init(struct fb_info *info, struct sstfb_par *par)
+{
+	u32 fbiinit0, fbiinit1, fbiinit4;
+	struct pci_dev *dev = par->dev;
+	struct pll_timing gfx_timings;
+	struct sst_spec *spec;
+	int Fout;
+
+	spec = &voodoo_spec[par->type];
+	f_ddprintk(" fbiinit0   fbiinit1   fbiinit2   fbiinit3   fbiinit4  "
+	           " fbiinit6\n");
+	f_ddprintk("%0#10x %0#10x %0#10x %0#10x %0#10x %0#10x\n",
+	            sst_read(FBIINIT0), sst_read(FBIINIT1), sst_read(FBIINIT2),
+	            sst_read(FBIINIT3), sst_read(FBIINIT4), sst_read(FBIINIT6));
+	/* disable video clock */
+	pci_write_config_dword(dev, PCI_VCLK_DISABLE, 0);
+
+	/* enable writing to init registers, disable pci fifo */
+	pci_write_config_dword(dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR);
+	/* reset video */
+	sst_set_bits(FBIINIT1, VIDEO_RESET);
+	sst_wait_idle();
+	/* reset gfx + pci fifo */
+	sst_set_bits(FBIINIT0, FBI_RESET | FIFO_RESET);
+	sst_wait_idle();
+
+	/* unreset fifo */
+	/*sst_unset_bits(FBIINIT0, FIFO_RESET);
+	sst_wait_idle();*/
+	/* unreset FBI */
+	/*sst_unset_bits(FBIINIT0, FBI_RESET);
+	sst_wait_idle();*/
+
+	/* disable dram refresh */
+	sst_unset_bits(FBIINIT2, EN_DRAM_REFRESH);
+	sst_wait_idle();
+	/* remap fbinit2/3 to dac */
+	pci_write_config_dword(dev, PCI_INIT_ENABLE,
+				PCI_EN_INIT_WR | PCI_REMAP_DAC );
+	/* detect dac type */
+	if (!sst_detect_dactype(info, par)) {
+		eprintk("Unknown dac type\n");
+		//FIXME watch it: we are not in a safe state, bad bad bad.
+		return 0;
+	}
+
+	/* set graphic clock */
+	par->gfx_clock = spec->default_gfx_clock;
+	if ((gfxclk >10 ) && (gfxclk < spec->max_gfxclk)) {
+		iprintk("Using supplied graphic freq : %dMHz\n", gfxclk);
+		 par->gfx_clock = gfxclk *1000;
+	} else if (gfxclk) {
+		wprintk ("%dMhz is way out of spec! Using default\n", gfxclk);
+	}
+
+	sst_calc_pll(par->gfx_clock, &Fout, &gfx_timings);
+	par->dac_sw.set_pll(info, &gfx_timings, GFX_CLOCK);
+
+	/* disable fbiinit remap */
+	pci_write_config_dword(dev, PCI_INIT_ENABLE,
+	                       PCI_EN_INIT_WR| PCI_EN_FIFO_WR );
+	/* defaults init registers */
+	/* FbiInit0: unreset gfx, unreset fifo */
+	fbiinit0 = FBIINIT0_DEFAULT;
+	fbiinit1 = FBIINIT1_DEFAULT;
+	fbiinit4 = FBIINIT4_DEFAULT;
+	if (vgapass)
+		fbiinit0 &= ~EN_VGA_PASSTHROUGH;
+	else
+		fbiinit0 |= EN_VGA_PASSTHROUGH;
+	if (slowpci) {
+		fbiinit1 |= SLOW_PCI_WRITES;
+		fbiinit4 |= SLOW_PCI_READS;
+	} else {
+		fbiinit1 &= ~SLOW_PCI_WRITES;
+		fbiinit4 &= ~SLOW_PCI_READS;
+	}
+	sst_write(FBIINIT0, fbiinit0);
+	sst_wait_idle();
+	sst_write(FBIINIT1, fbiinit1);
+	sst_wait_idle();
+	sst_write(FBIINIT2, FBIINIT2_DEFAULT);
+	sst_wait_idle();
+	sst_write(FBIINIT3, FBIINIT3_DEFAULT);
+	sst_wait_idle();
+	sst_write(FBIINIT4, fbiinit4);
+	sst_wait_idle();
+	if (IS_VOODOO2(par)) {
+		sst_write(FBIINIT6, FBIINIT6_DEFAULT);
+		sst_wait_idle();
+	}
+
+	pci_write_config_dword(dev, PCI_INIT_ENABLE, PCI_EN_FIFO_WR);
+	pci_write_config_dword(dev, PCI_VCLK_ENABLE, 0);
+	return 1;
+}
+
+static void  __devexit sst_shutdown(struct fb_info *info)
+{
+	struct sstfb_par *par = (struct sstfb_par *) info->par;
+	struct pci_dev *dev = par->dev;
+	struct pll_timing gfx_timings;
+	int Fout;
+
+	/* reset video, gfx, fifo, disable dram + remap fbiinit2/3 */
+	pci_write_config_dword(dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR);
+	sst_set_bits(FBIINIT1, VIDEO_RESET | EN_BLANKING);
+	sst_unset_bits(FBIINIT2, EN_DRAM_REFRESH);
+	sst_set_bits(FBIINIT0, FBI_RESET | FIFO_RESET);
+	sst_wait_idle();
+	pci_write_config_dword(dev, PCI_INIT_ENABLE,
+	                       PCI_EN_INIT_WR | PCI_REMAP_DAC);
+	/* set 20Mhz gfx clock */
+	sst_calc_pll(20000, &Fout, &gfx_timings);
+	par->dac_sw.set_pll(info, &gfx_timings, GFX_CLOCK);
+	/* TODO maybe shutdown the dac, vrefresh and so on... */
+	pci_write_config_dword(dev, PCI_INIT_ENABLE,
+	                       PCI_EN_INIT_WR);
+	sst_unset_bits(FBIINIT0, FBI_RESET | FIFO_RESET | EN_VGA_PASSTHROUGH);
+	pci_write_config_dword(dev, PCI_VCLK_DISABLE,0);
+	/* maybe keep fbiinit* and PCI_INIT_enable in the fb_info struct
+	 * from start ? */
+	pci_write_config_dword(dev, PCI_INIT_ENABLE, 0);
+
+}
+
+/*
+ * Interface to the world
+ */
+#ifndef MODULE
+static int  __init sstfb_setup(char *options)
+{
+	char *this_opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt) continue;
+
+		f_ddprintk("option %s\n", this_opt);
+
+		if (!strcmp(this_opt, "vganopass"))
+			vgapass = 0;
+		else if (!strcmp(this_opt, "vgapass"))
+			vgapass = 1;
+		else if (!strcmp(this_opt, "clipping"))
+		        clipping = 1;
+		else if (!strcmp(this_opt, "noclipping"))
+		        clipping = 0;
+		else if (!strcmp(this_opt, "fastpci"))
+		        slowpci = 0;
+		else if (!strcmp(this_opt, "slowpci"))
+		        slowpci = 1;
+		else if (!strncmp(this_opt, "mem:",4))
+			mem = simple_strtoul (this_opt+4, NULL, 0);
+		else if (!strncmp(this_opt, "gfxclk:",7))
+			gfxclk = simple_strtoul (this_opt+7, NULL, 0);
+		else
+			mode_option = this_opt;
+	}
+	return 0;
+}
+#endif
+
+static struct fb_ops sstfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= sstfb_check_var,
+	.fb_set_par	= sstfb_set_par,
+	.fb_setcolreg	= sstfb_setcolreg,
+	.fb_fillrect	= cfb_fillrect, /* sstfb_fillrect */
+	.fb_copyarea	= cfb_copyarea, /* sstfb_copyarea */
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+	.fb_ioctl	= sstfb_ioctl,
+};
+
+static int __devinit sstfb_probe(struct pci_dev *pdev,
+			const struct pci_device_id *id)
+{
+	struct fb_info *info;
+	struct fb_fix_screeninfo *fix;
+	struct sstfb_par *par;
+	struct sst_spec *spec;
+	int err;
+
+	struct all_info {
+		struct fb_info info;
+		struct sstfb_par par;
+		u32 pseudo_palette[16];
+	} *all;
+	
+	/* Enable device in PCI config. */
+	if ((err=pci_enable_device(pdev))) {
+		eprintk("cannot enable device\n");
+		return err;
+	}
+
+	/* Allocate the fb and par structures.  */
+	all = kmalloc(sizeof(*all), GFP_KERNEL);
+	if (!all)
+		return -ENOMEM;
+	memset(all, 0, sizeof(*all));
+	pci_set_drvdata(pdev, all);
+	
+	info = &all->info;
+	par  = info->par = &all->par;
+	fix  = &info->fix;
+	
+	par->type = id->driver_data;
+	spec = &voodoo_spec[par->type];
+	f_ddprintk("found device : %s\n", spec->name);
+
+	par->dev = pdev;
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &par->revision);
+
+	fix->mmio_start = pci_resource_start(pdev,0);
+	fix->mmio_len	= 0x400000;
+	fix->smem_start = fix->mmio_start + 0x400000;
+
+	if (!request_mem_region(fix->mmio_start, fix->mmio_len, "sstfb MMIO")) {
+		eprintk("cannot reserve mmio memory\n");
+		goto fail_mmio_mem;
+	}
+
+	if (!request_mem_region(fix->smem_start, 0x400000,"sstfb FB")) {
+		eprintk("cannot reserve fb memory\n");
+		goto fail_fb_mem;
+	}
+
+	par->mmio_vbase = ioremap_nocache(fix->mmio_start,
+					fix->mmio_len);
+	if (!par->mmio_vbase) {
+		eprintk("cannot remap register area %#lx\n",
+		        fix->mmio_start);
+		goto fail_mmio_remap;
+	}
+	info->screen_base = ioremap_nocache(fix->smem_start, 0x400000);
+	if (!info->screen_base) {
+		eprintk("cannot remap framebuffer %#lx\n",
+		        fix->smem_start);
+		goto fail_fb_remap;
+	}
+
+	if (!sst_init(info, par)) {
+		eprintk("Init failed\n");
+		goto fail;
+	}
+	sst_get_memsize(info, &fix->smem_len);
+	strlcpy(fix->id, spec->name, sizeof(fix->id));
+
+	iprintk("%s (revision %d) with %s dac\n",
+		fix->id, par->revision, par->dac_sw.name);
+	iprintk("framebuffer at %#lx, mapped to 0x%p, size %dMB\n",
+	        fix->smem_start, info->screen_base,
+	        fix->smem_len >> 20);
+
+	f_ddprintk("regbase_virt: %#lx\n", par->mmio_vbase);
+	f_ddprintk("membase_phys: %#lx\n", fix->smem_start);
+	f_ddprintk("fbbase_virt: %p\n", info->screen_base);
+
+	info->flags	= FBINFO_DEFAULT;
+	info->fbops	= &sstfb_ops;
+	info->pseudo_palette = &all->pseudo_palette;
+
+	fix->type	= FB_TYPE_PACKED_PIXELS;
+	fix->visual	= FB_VISUAL_TRUECOLOR;
+	fix->accel	= FB_ACCEL_NONE;  /* FIXME */
+	/*
+	 * According to the specs, the linelength must be of 1024 *pixels*
+	 * and the 24bpp mode is in fact a 32 bpp mode.
+	 */
+	fix->line_length = 2048; /* default value, for 24 or 32bit: 4096 */
+	
+	if ( mode_option &&
+	     fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 16)) {
+		eprintk("can't set supplied video mode. Using default\n");
+		info->var = sstfb_default;
+	} else
+		info->var = sstfb_default;
+
+	if (sstfb_check_var(&info->var, info)) {
+		eprintk("invalid default video mode.\n");
+		goto fail;
+	}
+
+	if (sstfb_set_par(info)) {
+		eprintk("can't set default video mode.\n");
+		goto fail;
+	}
+	
+	fb_alloc_cmap(&info->cmap, 256, 0);
+
+	/* register fb */
+	info->device = &pdev->dev;
+	if (register_framebuffer(info) < 0) {
+		eprintk("can't register framebuffer.\n");
+		goto fail;
+	}
+
+	if (1) /* set to 0 to see an initial bitmap instead */
+		sstfb_clear_screen(info);
+	else
+		sstfb_drawdebugimage(info);
+
+	printk(KERN_INFO "fb%d: %s frame buffer device at 0x%p\n",
+	       info->node, fix->id, info->screen_base);
+
+	return 0;
+
+fail:
+	iounmap(info->screen_base);
+fail_fb_remap:
+	iounmap(par->mmio_vbase);
+fail_mmio_remap:
+	release_mem_region(fix->smem_start, 0x400000);
+fail_fb_mem:
+	release_mem_region(fix->mmio_start, info->fix.mmio_len);
+fail_mmio_mem:
+	kfree(info);
+	return -ENXIO; 	/* no voodoo detected */
+}
+
+static void __devexit sstfb_remove(struct pci_dev *pdev)
+{
+	struct sstfb_par *par;
+	struct fb_info *info;
+
+	info = pci_get_drvdata(pdev);
+	par = (struct sstfb_par *) info->par;
+	
+	sst_shutdown(info);
+	unregister_framebuffer(info);
+	iounmap(info->screen_base);
+	iounmap(par->mmio_vbase);
+	release_mem_region(info->fix.smem_start, 0x400000);
+	release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+	kfree(info);
+}
+
+
+static struct pci_device_id sstfb_id_tbl[] = {
+	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_VOODOO1 },
+	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO2,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_VOODOO2 },
+	{ 0 },
+};
+
+static struct pci_driver sstfb_driver = {
+	.name		= "sstfb",
+	.id_table	= sstfb_id_tbl,
+	.probe		= sstfb_probe,
+	.remove		= __devexit_p(sstfb_remove),
+};
+
+
+static int __devinit sstfb_init(void)
+{
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("sstfb", &option))
+		return -ENODEV;
+	sstfb_setup(option);
+#endif
+	return pci_register_driver(&sstfb_driver);
+}
+
+#ifdef MODULE
+static void __devexit sstfb_exit(void)
+{
+	pci_unregister_driver(&sstfb_driver);
+}
+#endif
+
+
+/*
+ * testing and debugging functions
+ */
+
+static int sstfb_dump_regs(struct fb_info *info)
+{
+#ifdef SST_DEBUG
+	static struct { u32 reg ; const char *reg_name;}  pci_regs[] = {
+		{ PCI_INIT_ENABLE, "initenable"},
+		{ PCI_VCLK_ENABLE, "enable vclk"},
+		{ PCI_VCLK_DISABLE, "disable vclk"},
+	};
+
+	static struct { u32 reg ; const char *reg_name;}  sst_regs[] = {
+		{FBIINIT0,"fbiinit0"},
+		{FBIINIT1,"fbiinit1"},
+		{FBIINIT2,"fbiinit2"},
+		{FBIINIT3,"fbiinit3"},
+		{FBIINIT4,"fbiinit4"},
+		{FBIINIT5,"fbiinit5"},
+		{FBIINIT6,"fbiinit6"},
+		{FBIINIT7,"fbiinit7"},
+		{LFBMODE,"lfbmode"},
+		{FBZMODE,"fbzmode"},
+	};
+
+	const int pci_s = sizeof(pci_regs)/sizeof(pci_regs[0]);
+	const int sst_s = sizeof(sst_regs)/sizeof(sst_regs[0]);
+	struct sstfb_par *par = (struct sstfb_par *) info->par;
+	struct pci_dev *dev = par->dev;
+	u32 pci_res[pci_s];
+	u32 sst_res[sst_s];
+	int i;
+
+	for (i=0; i<pci_s; i++) {
+		pci_read_config_dword(dev, pci_regs[i].reg, &pci_res[i]);
+	}
+	for (i=0; i<sst_s; i++) {
+		sst_res[i] = sst_read(sst_regs[i].reg);
+	}
+
+	dprintk("hardware register dump:\n");
+	for (i=0; i<pci_s; i++) {
+		dprintk("%s %0#10x\n", pci_regs[i].reg_name, pci_res[i]);
+	}
+	for (i=0; i<sst_s; i++) {
+		dprintk("%s %0#10x\n", sst_regs[i].reg_name, sst_res[i]);
+	}
+	return 0;
+#else
+	return -EINVAL;
+#endif
+}
+
+static void sstfb_fillrect_softw( struct fb_info *info, const struct fb_fillrect *rect)
+{
+	u8 __iomem *fbbase_virt = info->screen_base;
+	int x, y, w = info->var.bits_per_pixel == 16 ? 2 : 4;
+	u32 color = rect->color, height = rect->height;
+	u8 __iomem *p;
+	
+	if (w==2) color |= color<<16;
+	for (y=rect->dy; height; y++, height--) {
+		p = fbbase_virt + y*info->fix.line_length + rect->dx*w;
+		x = rect->width;
+		if (w==2) x>>=1;
+		while (x) {
+			writel(color, p);
+			p += 4;
+			x--;
+		}
+	}
+}
+
+static void sstfb_drawrect_XY( struct fb_info *info, int x, int y,
+		int w, int h, int color, int hwfunc)
+{
+	struct fb_fillrect rect;
+	rect.dx = x;
+	rect.dy = y;
+	rect.height = h;
+	rect.width = w;
+	rect.color = color;
+	rect.rop = ROP_COPY;
+	if (hwfunc)
+		sstfb_fillrect(info, &rect);
+	else
+		sstfb_fillrect_softw(info, &rect);
+}
+
+/* print some squares on the fb */
+static void sstfb_drawdebugimage(struct fb_info *info)
+{
+	static int idx;
+
+	/* clear screen */
+	sstfb_clear_screen(info);
+	
+   	idx = (idx+1) & 1;
+
+	/* white rect */
+	sstfb_drawrect_XY(info, 0, 0, 50, 50, 0xffff, idx);
+	
+	/* blue rect */
+	sstfb_drawrect_XY(info, 50, 50, 50, 50, 0x001f, idx);
+
+	/* green rect */
+	sstfb_drawrect_XY(info, 100, 100, 80, 80, 0x07e0, idx);
+	
+	/* red rect */
+	sstfb_drawrect_XY(info, 250, 250, 120, 100, 0xf800, idx);
+}
+
+module_init(sstfb_init);
+
+#ifdef MODULE
+module_exit(sstfb_exit);
+#endif
+
+MODULE_AUTHOR("(c) 2000,2002 Ghozlane Toumi <gtoumi@laposte.net>");
+MODULE_DESCRIPTION("FBDev driver for 3dfx Voodoo Graphics and Voodoo2 based video boards");
+MODULE_LICENSE("GPL");
+
+module_param(mem, int, 0);
+MODULE_PARM_DESC(mem, "Size of frame buffer memory in MB (1, 2, 4 MB, default=autodetect)");
+module_param(vgapass, bool, 0);
+MODULE_PARM_DESC(vgapass, "Enable VGA PassThrough mode (0 or 1) (default=0)");
+module_param(clipping, bool, 0);
+MODULE_PARM_DESC(clipping, "Enable clipping (slower, safer) (0 or 1) (default=1)");
+module_param(gfxclk, int, 0);
+MODULE_PARM_DESC(gfxclk, "Force graphic chip frequency in MHz. DANGEROUS. (default=auto)");
+module_param(slowpci, bool, 0);
+MODULE_PARM_DESC(slowpci, "Uses slow PCI settings (0 or 1) (default=0)");
+
diff --git a/drivers/video/sticore.h b/drivers/video/sticore.h
new file mode 100644
index 0000000..dc93336
--- /dev/null
+++ b/drivers/video/sticore.h
@@ -0,0 +1,380 @@
+#ifndef STICORE_H
+#define STICORE_H
+
+/* generic STI structures & functions */
+
+#if 0
+#define DPRINTK(x)	printk x
+#else
+#define DPRINTK(x) 
+#endif
+
+#define MAX_STI_ROMS 4		/* max no. of ROMs which this driver handles */
+
+#define STI_REGION_MAX 8	/* hardcoded STI constants */
+#define STI_DEV_NAME_LENGTH 32
+#define STI_MONITOR_MAX 256
+
+#define STI_FONT_HPROMAN8 1
+#define STI_FONT_KANA8 2
+
+/* The latency of the STI functions cannot really be reduced by setting
+ * this to 0;  STI doesn't seem to be designed to allow calling a different
+ * function (or the same function with different arguments) after a
+ * function exited with 1 as return value.
+ *
+ * As all of the functions below could be called from interrupt context,
+ * we have to spin_lock_irqsave around the do { ret = bla(); } while(ret==1)
+ * block.  Really bad latency there.
+ *
+ * Probably the best solution to all this is have the generic code manage
+ * the screen buffer and a kernel thread to call STI occasionally.
+ * 
+ * Luckily, the frame buffer guys have the same problem so we can just wait
+ * for them to fix it and steal their solution.   prumpf
+ */
+ 
+#define STI_WAIT 1
+
+#include <asm/io.h> /* for USE_HPPA_IOREMAP */
+
+#if USE_HPPA_IOREMAP
+
+#define STI_PTR(p)	(p)
+#define PTR_STI(p)	(p)
+static inline int STI_CALL( unsigned long func, 
+		void *flags, void *inptr, void *outptr, void *glob_cfg )
+{
+       int (*f)(void *,void *,void *,void *);
+       f = (void*)func;
+       return f(flags, inptr, outptr, glob_cfg);
+}
+
+#else /* !USE_HPPA_IOREMAP */
+
+#define STI_PTR(p)	( virt_to_phys(p) )
+#define PTR_STI(p)	( phys_to_virt((long)p) )
+#define STI_CALL(func, flags, inptr, outptr, glob_cfg) \
+       ({                                                      \
+               pdc_sti_call( func, (unsigned long)STI_PTR(flags), \
+                                   (unsigned long)STI_PTR(inptr), \
+                                   (unsigned long)STI_PTR(outptr), \
+                                   (unsigned long)STI_PTR(glob_cfg)); \
+       })
+
+#endif /* USE_HPPA_IOREMAP */
+
+
+#define sti_onscreen_x(sti) (sti->glob_cfg->onscreen_x)
+#define sti_onscreen_y(sti) (sti->glob_cfg->onscreen_y)
+
+/* sti_font_xy() use the native font ROM ! */
+#define sti_font_x(sti) (PTR_STI(sti->font)->width)
+#define sti_font_y(sti) (PTR_STI(sti->font)->height)
+
+
+/* STI function configuration structs */
+
+typedef union region {
+	struct { 
+		u32 offset	: 14;	/* offset in 4kbyte page */
+		u32 sys_only	: 1;	/* don't map to user space */
+		u32 cache	: 1;	/* map to data cache */
+		u32 btlb	: 1;	/* map to block tlb */
+		u32 last	: 1;	/* last region in list */
+		u32 length	: 14;	/* length in 4kbyte page */
+	} region_desc;
+
+	u32 region;			/* complete region value */
+} region_t;
+
+#define REGION_OFFSET_TO_PHYS( rt, hpa ) \
+	(((rt).region_desc.offset << 12) + (hpa))
+
+struct sti_glob_cfg_ext {
+	 u8 curr_mon;			/* current monitor configured */
+	 u8 friendly_boot;		/* in friendly boot mode */
+	s16 power;			/* power calculation (in Watts) */
+	s32 freq_ref;			/* frequency refrence */
+	u32 sti_mem_addr;		/* pointer to global sti memory (size=sti_mem_request) */
+	u32 future_ptr; 		/* pointer to future data */
+};
+
+struct sti_glob_cfg {
+	s32 text_planes;		/* number of planes used for text */
+	s16 onscreen_x;			/* screen width in pixels */
+	s16 onscreen_y;			/* screen height in pixels */
+	s16 offscreen_x;		/* offset width in pixels */
+	s16 offscreen_y;		/* offset height in pixels */
+	s16 total_x;			/* frame buffer width in pixels */
+	s16 total_y;			/* frame buffer height in pixels */
+	u32 region_ptrs[STI_REGION_MAX]; /* region pointers */
+	s32 reent_lvl;			/* storage for reentry level value */
+	u32 save_addr;			/* where to save or restore reentrant state */
+	u32 ext_ptr;			/* pointer to extended glob_cfg data structure */
+};
+
+
+/* STI init function structs */
+
+struct sti_init_flags {
+	u32 wait : 1;		/* should routine idle wait or not */
+	u32 reset : 1;		/* hard reset the device? */
+	u32 text : 1;		/* turn on text display planes? */
+	u32 nontext : 1;	/* turn on non-text display planes? */
+	u32 clear : 1;		/* clear text display planes? */
+	u32 cmap_blk : 1;	/* non-text planes cmap black? */
+	u32 enable_be_timer : 1; /* enable bus error timer */
+	u32 enable_be_int : 1;	/* enable bus error timer interrupt */
+	u32 no_chg_tx : 1;	/* don't change text settings */
+	u32 no_chg_ntx : 1;	/* don't change non-text settings */
+	u32 no_chg_bet : 1;	/* don't change berr timer settings */
+	u32 no_chg_bei : 1;	/* don't change berr int settings */
+	u32 init_cmap_tx : 1;	/* initialize cmap for text planes */
+	u32 cmt_chg : 1;	/* change current monitor type */
+	u32 retain_ie : 1;	/* don't allow reset to clear int enables */
+	u32 caller_bootrom : 1;	/* set only by bootrom for each call */
+	u32 caller_kernel : 1;	/* set only by kernel for each call */
+	u32 caller_other : 1;	/* set only by non-[BR/K] caller */
+	u32 pad	: 14;		/* pad to word boundary */
+	u32 future_ptr; 	/* pointer to future data */
+};
+
+struct sti_init_inptr_ext {
+	u8  config_mon_type;	/* configure to monitor type */
+	u8  pad[1];		/* pad to word boundary */
+	u16 inflight_data;	/* inflight data possible on PCI */
+	u32 future_ptr; 	/* pointer to future data */
+};
+
+struct sti_init_inptr {
+	s32 text_planes;	/* number of planes to use for text */
+	u32 ext_ptr;		/* pointer to extended init_graph inptr data structure*/
+};
+
+
+struct sti_init_outptr {
+	s32 errno;		/* error number on failure */
+	s32 text_planes;	/* number of planes used for text */
+	u32 future_ptr; 	/* pointer to future data */
+};
+
+
+
+/* STI configuration function structs */
+
+struct sti_conf_flags {
+	u32 wait : 1;		/* should routine idle wait or not */
+	u32 pad : 31;		/* pad to word boundary */
+	u32 future_ptr; 	/* pointer to future data */
+};
+
+struct sti_conf_inptr {
+	u32 future_ptr; 	/* pointer to future data */
+};
+
+struct sti_conf_outptr_ext {
+	u32 crt_config[3];	/* hardware specific X11/OGL information */	
+	u32 crt_hdw[3];
+	u32 future_ptr;
+};
+
+struct sti_conf_outptr {
+	s32 errno;		/* error number on failure */
+	s16 onscreen_x;		/* screen width in pixels */
+	s16 onscreen_y;		/* screen height in pixels */
+	s16 offscreen_x;	/* offscreen width in pixels */
+	s16 offscreen_y;	/* offscreen height in pixels */
+	s16 total_x;		/* frame buffer width in pixels */
+	s16 total_y;		/* frame buffer height in pixels */
+	s32 bits_per_pixel;	/* bits/pixel device has configured */
+	s32 bits_used;		/* bits which can be accessed */
+	s32 planes;		/* number of fb planes in system */
+	 u8 dev_name[STI_DEV_NAME_LENGTH]; /* null terminated product name */
+	u32 attributes;		/* flags denoting attributes */
+	u32 ext_ptr;		/* pointer to future data */
+};
+
+struct sti_rom {
+	 u8 type[4];
+	 u8 res004;
+	 u8 num_mons;
+	 u8 revno[2];
+	u32 graphics_id[2];
+
+	u32 font_start;
+	u32 statesize;
+	u32 last_addr;
+	u32 region_list;
+
+	u16 reentsize;
+	u16 maxtime;
+	u32 mon_tbl_addr;
+	u32 user_data_addr;
+	u32 sti_mem_req;
+
+	u32 user_data_size;
+	u16 power;
+	 u8 bus_support;
+	 u8 ext_bus_support;
+	 u8 alt_code_type;
+	 u8 ext_dd_struct[3];
+	u32 cfb_addr;
+
+	u32 init_graph;
+	u32 state_mgmt;
+	u32 font_unpmv;
+	u32 block_move;
+	u32 self_test;
+	u32 excep_hdlr;
+	u32 inq_conf;
+	u32 set_cm_entry;
+	u32 dma_ctrl;
+	 u8 res040[7 * 4];
+	
+	u32 init_graph_addr;
+	u32 state_mgmt_addr;
+	u32 font_unp_addr;
+	u32 block_move_addr;
+	u32 self_test_addr;
+	u32 excep_hdlr_addr;
+	u32 inq_conf_addr;
+	u32 set_cm_entry_addr;
+	u32 image_unpack_addr;
+	u32 pa_risx_addrs[7];
+};
+
+struct sti_rom_font {
+	u16 first_char;
+	u16 last_char;
+	 u8 width;
+	 u8 height;
+	 u8 font_type;		/* language type */
+	 u8 bytes_per_char;
+	u32 next_font;
+	 u8 underline_height;
+	 u8 underline_pos;
+	 u8 res008[2];
+};
+
+/* sticore internal font handling */
+
+struct sti_cooked_font {
+        struct sti_rom_font *raw;
+	struct sti_cooked_font *next_font;
+};
+
+struct sti_cooked_rom {
+        struct sti_rom *raw;
+	struct sti_cooked_font *font_start;
+};
+
+/* STI font printing function structs */
+
+struct sti_font_inptr {
+	u32 font_start_addr;	/* address of font start */
+	s16 index;		/* index into font table of character */
+	u8 fg_color;		/* foreground color of character */
+	u8 bg_color;		/* background color of character */
+	s16 dest_x;		/* X location of character upper left */
+	s16 dest_y;		/* Y location of character upper left */
+	u32 future_ptr; 	/* pointer to future data */
+};
+
+struct sti_font_flags {
+	u32 wait : 1;		/* should routine idle wait or not */
+	u32 non_text : 1;	/* font unpack/move in non_text planes =1, text =0 */
+	u32 pad : 30;		/* pad to word boundary */
+	u32 future_ptr; 	/* pointer to future data */
+};
+	
+struct sti_font_outptr {
+	s32 errno;		/* error number on failure */
+	u32 future_ptr; 	/* pointer to future data */
+};
+
+/* STI blockmove structs */
+
+struct sti_blkmv_flags {
+	u32 wait : 1;		/* should routine idle wait or not */
+	u32 color : 1;		/* change color during move? */
+	u32 clear : 1;		/* clear during move? */
+	u32 non_text : 1;	/* block move in non_text planes =1, text =0 */
+	u32 pad : 28;		/* pad to word boundary */
+	u32 future_ptr; 	/* pointer to future data */
+};
+
+struct sti_blkmv_inptr {
+	u8 fg_color;		/* foreground color after move */
+	u8 bg_color;		/* background color after move */
+	s16 src_x;		/* source upper left pixel x location */
+	s16 src_y;		/* source upper left pixel y location */
+	s16 dest_x;		/* dest upper left pixel x location */
+	s16 dest_y;		/* dest upper left pixel y location */
+	s16 width;		/* block width in pixels */
+	s16 height;		/* block height in pixels */
+	u32 future_ptr; 	/* pointer to future data */
+};
+
+struct sti_blkmv_outptr {
+	s32 errno;		/* error number on failure */
+	u32 future_ptr; 	/* pointer to future data */
+};
+
+
+/* internal generic STI struct */
+
+struct sti_struct {
+	spinlock_t lock;
+		
+	/* the following fields needs to be filled in by the word/byte routines */
+	int font_width;	
+	int font_height;
+	/* char **mon_strings; */
+	int sti_mem_request;
+	u32 graphics_id[2];
+
+	struct sti_cooked_rom *rom;
+
+	unsigned long font_unpmv;
+	unsigned long block_move;
+	unsigned long init_graph;
+	unsigned long inq_conf;
+
+	/* all following fields are initialized by the generic routines */
+	int text_planes;
+	region_t regions[STI_REGION_MAX];
+	unsigned long regions_phys[STI_REGION_MAX];
+
+	struct sti_glob_cfg *glob_cfg;
+	struct sti_cooked_font *font;	/* ptr to selected font (cooked) */
+
+	struct sti_conf_outptr outptr; /* configuration */
+	struct sti_conf_outptr_ext outptr_ext;
+
+	/* PCI data structures (pg. 17ff from sti.pdf) */
+	struct pci_dev *pd;
+	u8 rm_entry[16]; /* pci region mapper array == pci config space offset */
+
+	/* pointer to the fb_info where this STI device is used */
+	struct fb_info *info;
+};
+
+
+/* sticore interface functions */
+
+struct sti_struct *sti_get_rom(unsigned int index); /* 0: default sti */
+
+/* functions to call the STI ROM directly */
+
+int  sti_init_graph(struct sti_struct *sti);
+void sti_inq_conf(struct sti_struct *sti);
+void sti_putc(struct sti_struct *sti, int c, int y, int x);
+void sti_set(struct sti_struct *sti, int src_y, int src_x,
+	     int height, int width, u8 color);
+void sti_clear(struct sti_struct *sti, int src_y, int src_x,
+	       int height, int width, int c);
+void sti_bmove(struct sti_struct *sti, int src_y, int src_x,
+	       int dst_y, int dst_x, int height, int width);
+
+#endif	/* STICORE_H */
diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c
new file mode 100644
index 0000000..9e52794
--- /dev/null
+++ b/drivers/video/stifb.c
@@ -0,0 +1,1495 @@
+/*
+ * linux/drivers/video/stifb.c - 
+ * Low level Frame buffer driver for HP workstations with 
+ * STI (standard text interface) video firmware.
+ *
+ * Copyright (C) 2001-2004 Helge Deller <deller@gmx.de>
+ * Portions Copyright (C) 2001 Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+ * 
+ * Based on:
+ * - linux/drivers/video/artistfb.c -- Artist frame buffer driver
+ *	Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ *   - based on skeletonfb, which was
+ *	Created 28 Dec 1997 by Geert Uytterhoeven
+ * - HP Xhp cfb-based X11 window driver for XFree86
+ *	(c)Copyright 1992 Hewlett-Packard Co.
+ *
+ * 
+ *  The following graphics display devices (NGLE family) are supported by this driver:
+ *
+ *  HPA4070A	known as "HCRX", a 1280x1024 color device with 8 planes
+ *  HPA4071A	known as "HCRX24", a 1280x1024 color device with 24 planes,
+ *		optionally available with a hardware accelerator as HPA4071A_Z
+ *  HPA1659A	known as "CRX", a 1280x1024 color device with 8 planes
+ *  HPA1439A	known as "CRX24", a 1280x1024 color device with 24 planes,
+ *		optionally available with a hardware accelerator.
+ *  HPA1924A	known as "GRX", a 1280x1024 grayscale device with 8 planes
+ *  HPA2269A	known as "Dual CRX", a 1280x1024 color device with 8 planes,
+ *		implements support for two displays on a single graphics card.
+ *  HP710C	internal graphics support optionally available on the HP9000s710 SPU,
+ *		supports 1280x1024 color displays with 8 planes.
+ *  HP710G	same as HP710C, 1280x1024 grayscale only
+ *  HP710L	same as HP710C, 1024x768 color only
+ *  HP712	internal graphics support on HP9000s712 SPU, supports 640x480, 
+ *		1024x768 or 1280x1024 color displays on 8 planes (Artist)
+ *
+ * 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.
+ */
+
+/* TODO:
+ *	- 1bpp mode is completely untested
+ *	- add support for h/w acceleration
+ *	- add hardware cursor
+ *	- automatically disable double buffering (e.g. on RDI precisionbook laptop)
+ */
+
+
+/* on supported graphic devices you may:
+ * #define FALLBACK_TO_1BPP to fall back to 1 bpp, or
+ * #undef  FALLBACK_TO_1BPP to reject support for unsupported cards */
+#undef FALLBACK_TO_1BPP
+
+#undef DEBUG_STIFB_REGS		/* debug sti register accesses */
+
+
+#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/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+
+#include <asm/grfioctl.h>	/* for HP-UX compatibility */
+#include <asm/uaccess.h>
+
+#include "sticore.h"
+
+/* REGION_BASE(fb_info, index) returns the virtual address for region <index> */
+#ifdef __LP64__
+  #define REGION_BASE(fb_info, index) \
+	(fb_info->sti->glob_cfg->region_ptrs[index] | 0xffffffff00000000)
+#else
+  #define REGION_BASE(fb_info, index) \
+	fb_info->sti->glob_cfg->region_ptrs[index]
+#endif
+
+#define NGLEDEVDEPROM_CRT_REGION 1
+
+typedef struct {
+	__s32	video_config_reg;
+	__s32	misc_video_start;
+	__s32	horiz_timing_fmt;
+	__s32	serr_timing_fmt;
+	__s32	vert_timing_fmt;
+	__s32	horiz_state;
+	__s32	vert_state;
+	__s32	vtg_state_elements;
+	__s32	pipeline_delay;
+	__s32	misc_video_end;
+} video_setup_t;
+
+typedef struct {                  
+	__s16	sizeof_ngle_data;
+	__s16	x_size_visible;	    /* visible screen dim in pixels  */
+	__s16	y_size_visible;
+	__s16	pad2[15];
+	__s16	cursor_pipeline_delay;
+	__s16	video_interleaves;
+	__s32	pad3[11];
+} ngle_rom_t;
+
+struct stifb_info {
+	struct fb_info info;
+	unsigned int id;
+	ngle_rom_t ngle_rom;
+	struct sti_struct *sti;
+	int deviceSpecificConfig;
+	u32 pseudo_palette[256];
+};
+
+static int __initdata stifb_bpp_pref[MAX_STI_ROMS];
+
+/* ------------------- chipset specific functions -------------------------- */
+
+/* offsets to graphic-chip internal registers */
+
+#define REG_1		0x000118
+#define REG_2		0x000480
+#define REG_3		0x0004a0
+#define REG_4		0x000600
+#define REG_6		0x000800
+#define REG_8		0x000820
+#define REG_9		0x000a04
+#define REG_10		0x018000
+#define REG_11		0x018004
+#define REG_12		0x01800c
+#define REG_13		0x018018
+#define REG_14  	0x01801c
+#define REG_15		0x200000
+#define REG_15b0	0x200000
+#define REG_16b1	0x200005
+#define REG_16b3	0x200007
+#define REG_21		0x200218
+#define REG_22		0x0005a0
+#define REG_23		0x0005c0
+#define REG_26		0x200118
+#define REG_27		0x200308
+#define REG_32		0x21003c
+#define REG_33		0x210040
+#define REG_34		0x200008
+#define REG_35		0x018010
+#define REG_38		0x210020
+#define REG_39		0x210120
+#define REG_40		0x210130
+#define REG_42		0x210028
+#define REG_43		0x21002c
+#define REG_44		0x210030
+#define REG_45		0x210034
+
+#define READ_BYTE(fb,reg)		gsc_readb((fb)->info.fix.mmio_start + (reg))
+#define READ_WORD(fb,reg)		gsc_readl((fb)->info.fix.mmio_start + (reg))
+
+
+#ifndef DEBUG_STIFB_REGS
+# define  DEBUG_OFF()
+# define  DEBUG_ON()
+# define WRITE_BYTE(value,fb,reg)	gsc_writeb((value),(fb)->info.fix.mmio_start + (reg))
+# define WRITE_WORD(value,fb,reg)	gsc_writel((value),(fb)->info.fix.mmio_start + (reg))
+#else
+  static int debug_on = 1;
+# define  DEBUG_OFF() debug_on=0
+# define  DEBUG_ON()  debug_on=1
+# define WRITE_BYTE(value,fb,reg)	do { if (debug_on) \
+						printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \
+							__FUNCTION__, reg, value, READ_BYTE(fb,reg)); 		  \
+					gsc_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
+# define WRITE_WORD(value,fb,reg)	do { if (debug_on) \
+						printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \
+							__FUNCTION__, reg, value, READ_WORD(fb,reg)); 		  \
+					gsc_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
+#endif /* DEBUG_STIFB_REGS */
+
+
+#define ENABLE	1	/* for enabling/disabling screen */	
+#define DISABLE 0
+
+#define NGLE_LOCK(fb_info)	do { } while (0) 
+#define NGLE_UNLOCK(fb_info)	do { } while (0)
+
+static void
+SETUP_HW(struct stifb_info *fb)
+{
+	char stat;
+
+	do {
+		stat = READ_BYTE(fb, REG_15b0);
+		if (!stat)
+	    		stat = READ_BYTE(fb, REG_15b0);
+	} while (stat);
+}
+
+
+static void
+SETUP_FB(struct stifb_info *fb)
+{	
+	unsigned int reg10_value = 0;
+	
+	SETUP_HW(fb);
+	switch (fb->id)
+	{
+		case CRT_ID_VISUALIZE_EG:
+		case S9000_ID_ARTIST:
+		case S9000_ID_A1659A:
+			reg10_value = 0x13601000;
+			break;
+		case S9000_ID_A1439A:
+			if (fb->info.var.bits_per_pixel == 32)						
+				reg10_value = 0xBBA0A000;
+			else 
+				reg10_value = 0x13601000;
+			break;
+		case S9000_ID_HCRX:
+			if (fb->info.var.bits_per_pixel == 32)
+				reg10_value = 0xBBA0A000;
+			else					
+				reg10_value = 0x13602000;
+			break;
+		case S9000_ID_TIMBER:
+		case CRX24_OVERLAY_PLANES:
+			reg10_value = 0x13602000;
+			break;
+	}
+	if (reg10_value)
+		WRITE_WORD(reg10_value, fb, REG_10);
+	WRITE_WORD(0x83000300, fb, REG_14);
+	SETUP_HW(fb);
+	WRITE_BYTE(1, fb, REG_16b1);
+}
+
+static void
+START_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
+{
+	SETUP_HW(fb);
+	WRITE_WORD(0xBBE0F000, fb, REG_10);
+	WRITE_WORD(0x03000300, fb, REG_14);
+	WRITE_WORD(~0, fb, REG_13);
+}
+
+static void
+WRITE_IMAGE_COLOR(struct stifb_info *fb, int index, int color) 
+{
+	SETUP_HW(fb);
+	WRITE_WORD(((0x100+index)<<2), fb, REG_3);
+	WRITE_WORD(color, fb, REG_4);
+}
+
+static void
+FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb) 
+{		
+	WRITE_WORD(0x400, fb, REG_2);
+	if (fb->info.var.bits_per_pixel == 32) {
+		WRITE_WORD(0x83000100, fb, REG_1);
+	} else {
+		if (fb->id == S9000_ID_ARTIST || fb->id == CRT_ID_VISUALIZE_EG)
+			WRITE_WORD(0x80000100, fb, REG_26);
+		else							
+			WRITE_WORD(0x80000100, fb, REG_1);
+	}
+	SETUP_FB(fb);
+}
+
+static void
+SETUP_RAMDAC(struct stifb_info *fb) 
+{
+	SETUP_HW(fb);
+	WRITE_WORD(0x04000000, fb, 0x1020);
+	WRITE_WORD(0xff000000, fb, 0x1028);
+}
+
+static void 
+CRX24_SETUP_RAMDAC(struct stifb_info *fb) 
+{
+	SETUP_HW(fb);
+	WRITE_WORD(0x04000000, fb, 0x1000);
+	WRITE_WORD(0x02000000, fb, 0x1004);
+	WRITE_WORD(0xff000000, fb, 0x1008);
+	WRITE_WORD(0x05000000, fb, 0x1000);
+	WRITE_WORD(0x02000000, fb, 0x1004);
+	WRITE_WORD(0x03000000, fb, 0x1008);
+}
+
+#if 0
+static void 
+HCRX_SETUP_RAMDAC(struct stifb_info *fb)
+{
+	WRITE_WORD(0xffffffff, fb, REG_32);
+}
+#endif
+
+static void 
+CRX24_SET_OVLY_MASK(struct stifb_info *fb)
+{
+	SETUP_HW(fb);
+	WRITE_WORD(0x13a02000, fb, REG_11);
+	WRITE_WORD(0x03000300, fb, REG_14);
+	WRITE_WORD(0x000017f0, fb, REG_3);
+	WRITE_WORD(0xffffffff, fb, REG_13);
+	WRITE_WORD(0xffffffff, fb, REG_22);
+	WRITE_WORD(0x00000000, fb, REG_23);
+}
+
+static void
+ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
+{
+	unsigned int value = enable ? 0x43000000 : 0x03000000;
+        SETUP_HW(fb);
+        WRITE_WORD(0x06000000,	fb, 0x1030);
+        WRITE_WORD(value, 	fb, 0x1038);
+}
+
+static void 
+CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
+{
+	unsigned int value = enable ? 0x10000000 : 0x30000000;
+	SETUP_HW(fb);
+	WRITE_WORD(0x01000000,	fb, 0x1000);
+	WRITE_WORD(0x02000000,	fb, 0x1004);
+	WRITE_WORD(value,	fb, 0x1008);
+}
+
+static void
+ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable) 
+{
+	u32 DregsMiscVideo = REG_21;
+	u32 DregsMiscCtl = REG_27;
+	
+	SETUP_HW(fb);
+	if (enable) {
+	  WRITE_WORD(READ_WORD(fb, DregsMiscVideo) | 0x0A000000, fb, DregsMiscVideo);
+	  WRITE_WORD(READ_WORD(fb, DregsMiscCtl)   | 0x00800000, fb, DregsMiscCtl);
+	} else {
+	  WRITE_WORD(READ_WORD(fb, DregsMiscVideo) & ~0x0A000000, fb, DregsMiscVideo);
+	  WRITE_WORD(READ_WORD(fb, DregsMiscCtl)   & ~0x00800000, fb, DregsMiscCtl);
+	}
+}
+
+#define GET_ROMTABLE_INDEX(fb) \
+	(READ_BYTE(fb, REG_16b3) - 1)
+
+#define HYPER_CONFIG_PLANES_24 0x00000100
+	
+#define IS_24_DEVICE(fb) \
+	(fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24)
+
+#define IS_888_DEVICE(fb) \
+	(!(IS_24_DEVICE(fb)))
+
+#define GET_FIFO_SLOTS(fb, cnt, numslots)			\
+{	while (cnt < numslots) 					\
+		cnt = READ_WORD(fb, REG_34);	\
+	cnt -= numslots;					\
+}
+
+#define	    IndexedDcd	0	/* Pixel data is indexed (pseudo) color */
+#define	    Otc04	2	/* Pixels in each longword transfer (4) */
+#define	    Otc32	5	/* Pixels in each longword transfer (32) */
+#define	    Ots08	3	/* Each pixel is size (8)d transfer (1) */
+#define	    OtsIndirect	6	/* Each bit goes through FG/BG color(8) */
+#define	    AddrLong	5	/* FB address is Long aligned (pixel) */
+#define	    BINovly	0x2	/* 8 bit overlay */
+#define	    BINapp0I	0x0	/* Application Buffer 0, Indexed */
+#define	    BINapp1I	0x1	/* Application Buffer 1, Indexed */
+#define	    BINapp0F8	0xa	/* Application Buffer 0, Fractional 8-8-8 */
+#define	    BINattr	0xd	/* Attribute Bitmap */
+#define	    RopSrc 	0x3
+#define	    BitmapExtent08  3	/* Each write hits ( 8) bits in depth */
+#define	    BitmapExtent32  5	/* Each write hits (32) bits in depth */
+#define	    DataDynamic	    0	/* Data register reloaded by direct access */
+#define	    MaskDynamic	    1	/* Mask register reloaded by direct access */
+#define	    MaskOtc	    0	/* Mask contains Object Count valid bits */
+
+#define MaskAddrOffset(offset) (offset)
+#define StaticReg(en) (en)
+#define BGx(en) (en)
+#define FGx(en) (en)
+
+#define BAJustPoint(offset) (offset)
+#define BAIndexBase(base) (base)
+#define BA(F,C,S,A,J,B,I) \
+	(((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I))
+
+#define IBOvals(R,M,X,S,D,L,B,F) \
+	(((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F))
+
+#define NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, val) \
+	WRITE_WORD(val, fb, REG_14)
+
+#define NGLE_QUICK_SET_DST_BM_ACCESS(fb, val) \
+	WRITE_WORD(val, fb, REG_11)
+
+#define NGLE_QUICK_SET_CTL_PLN_REG(fb, val) \
+	WRITE_WORD(val, fb, REG_12)
+
+#define NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, plnmsk32) \
+	WRITE_WORD(plnmsk32, fb, REG_13)
+
+#define NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, fg32) \
+	WRITE_WORD(fg32, fb, REG_35)
+
+#define NGLE_SET_TRANSFERDATA(fb, val) \
+	WRITE_WORD(val, fb, REG_8)
+
+#define NGLE_SET_DSTXY(fb, val) \
+	WRITE_WORD(val, fb, REG_6)
+
+#define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) (		\
+	(u32) (fbaddrbase) +					\
+	    (	(unsigned int)  ( (y) << 13      ) |		\
+		(unsigned int)  ( (x) << 2       )	)	\
+	)
+
+#define NGLE_BINC_SET_DSTADDR(fb, addr) \
+	WRITE_WORD(addr, fb, REG_3)
+
+#define NGLE_BINC_SET_SRCADDR(fb, addr) \
+	WRITE_WORD(addr, fb, REG_2)
+
+#define NGLE_BINC_SET_DSTMASK(fb, mask) \
+	WRITE_WORD(mask, fb, REG_22)
+
+#define NGLE_BINC_WRITE32(fb, data32) \
+	WRITE_WORD(data32, fb, REG_23)
+
+#define START_COLORMAPLOAD(fb, cmapBltCtlData32) \
+	WRITE_WORD((cmapBltCtlData32), fb, REG_38)
+
+#define SET_LENXY_START_RECFILL(fb, lenxy) \
+	WRITE_WORD(lenxy, fb, REG_9)
+
+static void
+HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
+{
+	u32 DregsHypMiscVideo = REG_33;
+	unsigned int value;
+	SETUP_HW(fb);
+	value = READ_WORD(fb, DregsHypMiscVideo);
+	if (enable)
+		value |= 0x0A000000;
+	else
+		value &= ~0x0A000000;
+	WRITE_WORD(value, fb, DregsHypMiscVideo);
+}
+
+
+/* BufferNumbers used by SETUP_ATTR_ACCESS() */
+#define BUFF0_CMAP0	0x00001e02
+#define BUFF1_CMAP0	0x02001e02
+#define BUFF1_CMAP3	0x0c001e02
+#define ARTIST_CMAP0	0x00000102
+#define HYPER_CMAP8	0x00000100
+#define HYPER_CMAP24	0x00000800
+
+static void
+SETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber)
+{
+	SETUP_HW(fb);
+	WRITE_WORD(0x2EA0D000, fb, REG_11);
+	WRITE_WORD(0x23000302, fb, REG_14);
+	WRITE_WORD(BufferNumber, fb, REG_12);
+	WRITE_WORD(0xffffffff, fb, REG_8);
+}
+
+static void
+SET_ATTR_SIZE(struct stifb_info *fb, int width, int height) 
+{
+	/* REG_6 seems to have special values when run on a 
+	   RDI precisionbook parisc laptop (INTERNAL_EG_DX1024 or
+	   INTERNAL_EG_X1024).  The values are:
+		0x2f0: internal (LCD) & external display enabled
+		0x2a0: external display only
+		0x000: zero on standard artist graphic cards
+	*/ 
+	WRITE_WORD(0x00000000, fb, REG_6);
+	WRITE_WORD((width<<16) | height, fb, REG_9);
+	WRITE_WORD(0x05000000, fb, REG_6);
+	WRITE_WORD(0x00040001, fb, REG_9);
+}
+
+static void
+FINISH_ATTR_ACCESS(struct stifb_info *fb) 
+{
+	SETUP_HW(fb);
+	WRITE_WORD(0x00000000, fb, REG_12);
+}
+
+static void
+elkSetupPlanes(struct stifb_info *fb)
+{
+	SETUP_RAMDAC(fb);
+	SETUP_FB(fb);
+}
+
+static void 
+ngleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber)
+{
+	SETUP_ATTR_ACCESS(fb, BufferNumber);
+	SET_ATTR_SIZE(fb, fb->info.var.xres, fb->info.var.yres);
+	FINISH_ATTR_ACCESS(fb);
+	SETUP_FB(fb);
+}
+
+
+static void
+rattlerSetupPlanes(struct stifb_info *fb)
+{
+	CRX24_SETUP_RAMDAC(fb);
+    
+	/* replacement for: SETUP_FB(fb, CRX24_OVERLAY_PLANES); */
+	WRITE_WORD(0x83000300, fb, REG_14);
+	SETUP_HW(fb);
+	WRITE_BYTE(1, fb, REG_16b1);
+
+	fb_memset(fb->info.fix.smem_start, 0xff,
+		fb->info.var.yres*fb->info.fix.line_length);
+    
+	CRX24_SET_OVLY_MASK(fb);
+	SETUP_FB(fb);
+}
+
+
+#define HYPER_CMAP_TYPE				0
+#define NGLE_CMAP_INDEXED0_TYPE			0
+#define NGLE_CMAP_OVERLAY_TYPE			3
+
+/* typedef of LUT (Colormap) BLT Control Register */
+typedef union	/* Note assumption that fields are packed left-to-right */
+{	u32 all;
+	struct
+	{
+		unsigned enable              :  1;
+		unsigned waitBlank           :  1;
+		unsigned reserved1           :  4;
+		unsigned lutOffset           : 10;   /* Within destination LUT */
+		unsigned lutType             :  2;   /* Cursor, image, overlay */
+		unsigned reserved2           :  4;
+		unsigned length              : 10;
+	} fields;
+} NgleLutBltCtl;
+
+
+#if 0
+static NgleLutBltCtl
+setNgleLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
+{
+	NgleLutBltCtl lutBltCtl;
+
+	/* set enable, zero reserved fields */
+	lutBltCtl.all           = 0x80000000;
+	lutBltCtl.fields.length = length;
+
+	switch (fb->id) 
+	{
+	case S9000_ID_A1439A:		/* CRX24 */
+		if (fb->var.bits_per_pixel == 8) {
+			lutBltCtl.fields.lutType = NGLE_CMAP_OVERLAY_TYPE;
+			lutBltCtl.fields.lutOffset = 0;
+		} else {
+			lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
+			lutBltCtl.fields.lutOffset = 0 * 256;
+		}
+		break;
+		
+	case S9000_ID_ARTIST:
+		lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
+		lutBltCtl.fields.lutOffset = 0 * 256;
+		break;
+		
+	default:
+		lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
+		lutBltCtl.fields.lutOffset = 0;
+		break;
+	}
+
+	/* Offset points to start of LUT.  Adjust for within LUT */
+	lutBltCtl.fields.lutOffset += offsetWithinLut;
+
+	return lutBltCtl;
+}
+#endif
+
+static NgleLutBltCtl
+setHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length) 
+{
+	NgleLutBltCtl lutBltCtl;
+
+	/* set enable, zero reserved fields */
+	lutBltCtl.all = 0x80000000;
+
+	lutBltCtl.fields.length = length;
+	lutBltCtl.fields.lutType = HYPER_CMAP_TYPE;
+
+	/* Expect lutIndex to be 0 or 1 for image cmaps, 2 or 3 for overlay cmaps */
+	if (fb->info.var.bits_per_pixel == 8)
+		lutBltCtl.fields.lutOffset = 2 * 256;
+	else
+		lutBltCtl.fields.lutOffset = 0 * 256;
+
+	/* Offset points to start of LUT.  Adjust for within LUT */
+	lutBltCtl.fields.lutOffset += offsetWithinLut;
+
+	return lutBltCtl;
+}
+
+
+static void hyperUndoITE(struct stifb_info *fb)
+{
+	int nFreeFifoSlots = 0;
+	u32 fbAddr;
+
+	NGLE_LOCK(fb);
+
+	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
+	WRITE_WORD(0xffffffff, fb, REG_32);
+
+	/* Write overlay transparency mask so only entry 255 is transparent */
+
+	/* Hardware setup for full-depth write to "magic" location */
+	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
+	NGLE_QUICK_SET_DST_BM_ACCESS(fb, 
+		BA(IndexedDcd, Otc04, Ots08, AddrLong,
+		BAJustPoint(0), BINovly, BAIndexBase(0)));
+	NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
+		IBOvals(RopSrc, MaskAddrOffset(0),
+		BitmapExtent08, StaticReg(0),
+		DataDynamic, MaskOtc, BGx(0), FGx(0)));
+
+	/* Now prepare to write to the "magic" location */
+	fbAddr = NGLE_LONG_FB_ADDRESS(0, 1532, 0);
+	NGLE_BINC_SET_DSTADDR(fb, fbAddr);
+	NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffff);
+	NGLE_BINC_SET_DSTMASK(fb, 0xffffffff);
+
+	/* Finally, write a zero to clear the mask */
+	NGLE_BINC_WRITE32(fb, 0);
+
+	NGLE_UNLOCK(fb);
+}
+
+static void 
+ngleDepth8_ClearImagePlanes(struct stifb_info *fb)
+{
+	/* FIXME! */
+}
+
+static void 
+ngleDepth24_ClearImagePlanes(struct stifb_info *fb)
+{
+	/* FIXME! */
+}
+
+static void
+ngleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg)
+{
+	int nFreeFifoSlots = 0;
+	u32 packed_dst;
+	u32 packed_len;
+
+	NGLE_LOCK(fb);
+
+	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 4);
+	NGLE_QUICK_SET_DST_BM_ACCESS(fb, 
+				     BA(IndexedDcd, Otc32, OtsIndirect,
+					AddrLong, BAJustPoint(0),
+					BINattr, BAIndexBase(0)));
+	NGLE_QUICK_SET_CTL_PLN_REG(fb, ctlPlaneReg);
+	NGLE_SET_TRANSFERDATA(fb, 0xffffffff);
+
+	NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
+				       IBOvals(RopSrc, MaskAddrOffset(0),
+					       BitmapExtent08, StaticReg(1),
+					       DataDynamic, MaskOtc,
+					       BGx(0), FGx(0)));
+	packed_dst = 0;
+	packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
+	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
+	NGLE_SET_DSTXY(fb, packed_dst);
+	SET_LENXY_START_RECFILL(fb, packed_len);
+
+	/*
+	 * In order to work around an ELK hardware problem (Buffy doesn't
+	 * always flush it's buffers when writing to the attribute
+	 * planes), at least 4 pixels must be written to the attribute
+	 * planes starting at (X == 1280) and (Y != to the last Y written
+	 * by BIF):
+	 */
+
+	if (fb->id == S9000_ID_A1659A) {   /* ELK_DEVICE_ID */
+		/* It's safe to use scanline zero: */
+		packed_dst = (1280 << 16);
+		GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
+		NGLE_SET_DSTXY(fb, packed_dst);
+		packed_len = (4 << 16) | 1;
+		SET_LENXY_START_RECFILL(fb, packed_len);
+	}   /* ELK Hardware Kludge */
+
+	/**** Finally, set the Control Plane Register back to zero: ****/
+	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
+	NGLE_QUICK_SET_CTL_PLN_REG(fb, 0);
+	
+	NGLE_UNLOCK(fb);
+}
+    
+static void
+ngleClearOverlayPlanes(struct stifb_info *fb, int mask, int data)
+{
+	int nFreeFifoSlots = 0;
+	u32 packed_dst;
+	u32 packed_len;
+    
+	NGLE_LOCK(fb);
+
+	/* Hardware setup */
+	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 8);
+	NGLE_QUICK_SET_DST_BM_ACCESS(fb, 
+				     BA(IndexedDcd, Otc04, Ots08, AddrLong,
+					BAJustPoint(0), BINovly, BAIndexBase(0)));
+
+        NGLE_SET_TRANSFERDATA(fb, 0xffffffff);  /* Write foreground color */
+
+        NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, data);
+        NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, mask);
+    
+        packed_dst = 0;
+        packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
+        NGLE_SET_DSTXY(fb, packed_dst);
+    
+        /* Write zeroes to overlay planes */		       
+	NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
+				       IBOvals(RopSrc, MaskAddrOffset(0),
+					       BitmapExtent08, StaticReg(0),
+					       DataDynamic, MaskOtc, BGx(0), FGx(0)));
+		       
+        SET_LENXY_START_RECFILL(fb, packed_len);
+
+	NGLE_UNLOCK(fb);
+}
+
+static void 
+hyperResetPlanes(struct stifb_info *fb, int enable)
+{
+	unsigned int controlPlaneReg;
+
+	NGLE_LOCK(fb);
+
+	if (IS_24_DEVICE(fb))
+		if (fb->info.var.bits_per_pixel == 32)
+			controlPlaneReg = 0x04000F00;
+		else
+			controlPlaneReg = 0x00000F00;   /* 0x00000800 should be enought, but lets clear all 4 bits */
+	else
+		controlPlaneReg = 0x00000F00; /* 0x00000100 should be enought, but lets clear all 4 bits */
+
+	switch (enable) {
+	case ENABLE:
+		/* clear screen */
+		if (IS_24_DEVICE(fb))
+			ngleDepth24_ClearImagePlanes(fb);
+		else
+			ngleDepth8_ClearImagePlanes(fb);
+
+		/* Paint attribute planes for default case.
+		 * On Hyperdrive, this means all windows using overlay cmap 0. */
+		ngleResetAttrPlanes(fb, controlPlaneReg);
+
+		/* clear overlay planes */
+	        ngleClearOverlayPlanes(fb, 0xff, 255);
+
+		/**************************************************
+		 ** Also need to counteract ITE settings 
+		 **************************************************/
+		hyperUndoITE(fb);
+		break;
+
+	case DISABLE:
+		/* clear screen */
+		if (IS_24_DEVICE(fb))
+			ngleDepth24_ClearImagePlanes(fb);
+		else
+			ngleDepth8_ClearImagePlanes(fb);
+		ngleResetAttrPlanes(fb, controlPlaneReg);
+		ngleClearOverlayPlanes(fb, 0xff, 0);
+		break;
+
+	case -1:	/* RESET */
+		hyperUndoITE(fb);
+		ngleResetAttrPlanes(fb, controlPlaneReg);
+		break;
+    	}
+	
+	NGLE_UNLOCK(fb);
+}
+
+/* Return pointer to in-memory structure holding ELK device-dependent ROM values. */
+
+static void 
+ngleGetDeviceRomData(struct stifb_info *fb)
+{
+#if 0
+XXX: FIXME: !!!
+	int	*pBytePerLongDevDepData;/* data byte == LSB */
+	int 	*pRomTable;
+	NgleDevRomData	*pPackedDevRomData;
+	int	sizePackedDevRomData = sizeof(*pPackedDevRomData);
+	char	*pCard8;
+	int	i;
+	char	*mapOrigin = NULL;
+    
+	int romTableIdx;
+
+	pPackedDevRomData = fb->ngle_rom;
+
+	SETUP_HW(fb);
+	if (fb->id == S9000_ID_ARTIST) {
+		pPackedDevRomData->cursor_pipeline_delay = 4;
+		pPackedDevRomData->video_interleaves     = 4;
+	} else {
+		/* Get pointer to unpacked byte/long data in ROM */
+		pBytePerLongDevDepData = fb->sti->regions[NGLEDEVDEPROM_CRT_REGION];
+
+		/* Tomcat supports several resolutions: 1280x1024, 1024x768, 640x480 */
+		if (fb->id == S9000_ID_TOMCAT)
+	{
+	    /*  jump to the correct ROM table  */
+	    GET_ROMTABLE_INDEX(romTableIdx);
+	    while  (romTableIdx > 0)
+	    {
+		pCard8 = (Card8 *) pPackedDevRomData;
+		pRomTable = pBytePerLongDevDepData;
+		/* Pack every fourth byte from ROM into structure */
+		for (i = 0; i < sizePackedDevRomData; i++)
+		{
+		    *pCard8++ = (Card8) (*pRomTable++);
+		}
+
+		pBytePerLongDevDepData = (Card32 *)
+			((Card8 *) pBytePerLongDevDepData +
+			       pPackedDevRomData->sizeof_ngle_data);
+
+		romTableIdx--;
+	    }
+	}
+
+	pCard8 = (Card8 *) pPackedDevRomData;
+
+	/* Pack every fourth byte from ROM into structure */
+	for (i = 0; i < sizePackedDevRomData; i++)
+	{
+	    *pCard8++ = (Card8) (*pBytePerLongDevDepData++);
+	}
+    }
+
+    SETUP_FB(fb);
+#endif
+}
+
+
+#define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES	4
+#define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE	8
+#define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE		10
+#define HYPERBOWL_MODE2_8_24					15
+
+/* HCRX specific boot-time initialization */
+static void __init
+SETUP_HCRX(struct stifb_info *fb)
+{
+	int	hyperbowl;
+        int	nFreeFifoSlots = 0;
+
+	if (fb->id != S9000_ID_HCRX)
+		return;
+
+	/* Initialize Hyperbowl registers */
+	GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
+	
+	if (IS_24_DEVICE(fb)) {
+		hyperbowl = (fb->info.var.bits_per_pixel == 32) ?
+			HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE :
+			HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE;
+
+		/* First write to Hyperbowl must happen twice (bug) */
+		WRITE_WORD(hyperbowl, fb, REG_40);
+		WRITE_WORD(hyperbowl, fb, REG_40);
+		
+		WRITE_WORD(HYPERBOWL_MODE2_8_24, fb, REG_39);
+		
+		WRITE_WORD(0x014c0148, fb, REG_42); /* Set lut 0 to be the direct color */
+		WRITE_WORD(0x404c4048, fb, REG_43);
+		WRITE_WORD(0x034c0348, fb, REG_44);
+		WRITE_WORD(0x444c4448, fb, REG_45);
+	} else {
+		hyperbowl = HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES;
+
+		/* First write to Hyperbowl must happen twice (bug) */
+		WRITE_WORD(hyperbowl, fb, REG_40);
+		WRITE_WORD(hyperbowl, fb, REG_40);
+
+		WRITE_WORD(0x00000000, fb, REG_42);
+		WRITE_WORD(0x00000000, fb, REG_43);
+		WRITE_WORD(0x00000000, fb, REG_44);
+		WRITE_WORD(0x444c4048, fb, REG_45);
+	}
+}
+
+
+/* ------------------- driver specific functions --------------------------- */
+
+#define TMPBUFLEN 2048
+
+static ssize_t
+stifb_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+	unsigned long p = *ppos;
+	struct inode *inode = file->f_dentry->d_inode;
+	int fbidx = iminor(inode);
+	struct fb_info *info = registered_fb[fbidx];
+	char tmpbuf[TMPBUFLEN];
+
+	if (!info || ! info->screen_base)
+		return -ENODEV;
+
+	if (p >= info->fix.smem_len)
+	    return 0;
+	if (count >= info->fix.smem_len)
+	    count = info->fix.smem_len;
+	if (count + p > info->fix.smem_len)
+		count = info->fix.smem_len - p;
+	if (count > sizeof(tmpbuf))
+		count = sizeof(tmpbuf);
+	if (count) {
+	    char *base_addr;
+
+	    base_addr = info->screen_base;
+	    memcpy_fromio(&tmpbuf, base_addr+p, count);
+	    count -= copy_to_user(buf, &tmpbuf, count);
+	    if (!count)
+		return -EFAULT;
+	    *ppos += count;
+	}
+	return count;
+}
+
+static ssize_t
+stifb_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	int fbidx = iminor(inode);
+	struct fb_info *info = registered_fb[fbidx];
+	unsigned long p = *ppos;
+	size_t c;
+	int err;
+	char tmpbuf[TMPBUFLEN];
+
+	if (!info || !info->screen_base)
+		return -ENODEV;
+
+	if (p > info->fix.smem_len)
+	    return -ENOSPC;
+	if (count >= info->fix.smem_len)
+	    count = info->fix.smem_len;
+	err = 0;
+	if (count + p > info->fix.smem_len) {
+	    count = info->fix.smem_len - p;
+	    err = -ENOSPC;
+	}
+
+	p += (unsigned long)info->screen_base;
+	c = count;
+	while (c) {
+	    int len = c > sizeof(tmpbuf) ? sizeof(tmpbuf) : c;
+	    err = -EFAULT;
+	    if (copy_from_user(&tmpbuf, buf, len))
+		    break;
+	    memcpy_toio(p, &tmpbuf, len);
+	    c -= len;
+	    p += len;
+	    buf += len;
+	    *ppos += len;
+	}
+	if (count-c)
+		return (count-c);
+	return err;
+}
+
+static int
+stifb_setcolreg(u_int regno, u_int red, u_int green,
+	      u_int blue, u_int transp, struct fb_info *info)
+{
+	struct stifb_info *fb = (struct stifb_info *) info;
+	u32 color;
+
+	if (regno >= 256)  /* no. of hw registers */
+		return 1;
+
+	red   >>= 8;
+	green >>= 8;
+	blue  >>= 8;
+
+	DEBUG_OFF();
+
+	START_IMAGE_COLORMAP_ACCESS(fb);
+	
+	if (fb->info.var.grayscale) {
+		/* gray = 0.30*R + 0.59*G + 0.11*B */
+		color = ((red * 77) +
+			 (green * 151) +
+			 (blue * 28)) >> 8;
+	} else {
+		color = ((red << 16) |
+			 (green << 8) |
+			 (blue));
+	}
+
+	if (info->var.bits_per_pixel == 32) {
+		((u32 *)(info->pseudo_palette))[regno] =
+			(red   << info->var.red.offset)   |
+			(green << info->var.green.offset) |
+			(blue  << info->var.blue.offset);
+	} else {
+		((u32 *)(info->pseudo_palette))[regno] = regno;
+	}
+
+	WRITE_IMAGE_COLOR(fb, regno, color);
+	
+	if (fb->id == S9000_ID_HCRX) {
+		NgleLutBltCtl lutBltCtl;
+
+		lutBltCtl = setHyperLutBltCtl(fb,
+				0,	/* Offset w/i LUT */
+				256);	/* Load entire LUT */
+		NGLE_BINC_SET_SRCADDR(fb,
+				NGLE_LONG_FB_ADDRESS(0, 0x100, 0)); 
+				/* 0x100 is same as used in WRITE_IMAGE_COLOR() */
+		START_COLORMAPLOAD(fb, lutBltCtl.all);
+		SETUP_FB(fb);
+	} else {
+		/* cleanup colormap hardware */
+		FINISH_IMAGE_COLORMAP_ACCESS(fb);
+	}
+
+	DEBUG_ON();
+
+	return 0;
+}
+
+static int
+stifb_blank(int blank_mode, struct fb_info *info)
+{
+	struct stifb_info *fb = (struct stifb_info *) info;
+	int enable = (blank_mode == 0) ? ENABLE : DISABLE;
+
+	switch (fb->id) {
+	case S9000_ID_A1439A:
+		CRX24_ENABLE_DISABLE_DISPLAY(fb, enable);
+		break;
+	case CRT_ID_VISUALIZE_EG:
+	case S9000_ID_ARTIST:
+		ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable);
+		break;
+	case S9000_ID_HCRX:
+		HYPER_ENABLE_DISABLE_DISPLAY(fb, enable);
+		break;
+	case S9000_ID_A1659A:;	/* fall through */
+	case S9000_ID_TIMBER:;
+	case CRX24_OVERLAY_PLANES:;
+	default:
+		ENABLE_DISABLE_DISPLAY(fb, enable);
+		break;
+	}
+	
+	SETUP_FB(fb);
+	return 0;
+}
+
+static void __init
+stifb_init_display(struct stifb_info *fb)
+{
+	int id = fb->id;
+
+	SETUP_FB(fb);
+
+	/* HCRX specific initialization */
+	SETUP_HCRX(fb);
+	
+	/*
+	if (id == S9000_ID_HCRX)
+		hyperInitSprite(fb);
+	else
+		ngleInitSprite(fb);
+	*/
+	
+	/* Initialize the image planes. */ 
+        switch (id) {
+	 case S9000_ID_HCRX:
+	    hyperResetPlanes(fb, ENABLE);
+	    break;
+	 case S9000_ID_A1439A:
+	    rattlerSetupPlanes(fb);
+	    break;
+	 case S9000_ID_A1659A:
+	 case S9000_ID_ARTIST:
+	 case CRT_ID_VISUALIZE_EG:
+	    elkSetupPlanes(fb);
+	    break;
+	}
+
+	/* Clear attribute planes on non HCRX devices. */
+        switch (id) {
+	 case S9000_ID_A1659A:
+	 case S9000_ID_A1439A:
+	    if (fb->info.var.bits_per_pixel == 32)
+		ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
+	    else {
+		ngleSetupAttrPlanes(fb, BUFF1_CMAP0);
+	    }
+	    if (id == S9000_ID_A1439A)
+		ngleClearOverlayPlanes(fb, 0xff, 0);
+	    break;
+	 case S9000_ID_ARTIST:
+	 case CRT_ID_VISUALIZE_EG:
+	    if (fb->info.var.bits_per_pixel == 32)
+		ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
+	    else {
+		ngleSetupAttrPlanes(fb, ARTIST_CMAP0);
+	    }
+	    break;
+	}
+	stifb_blank(0, (struct fb_info *)fb);	/* 0=enable screen */
+
+	SETUP_FB(fb);
+}
+
+/* ------------ Interfaces to hardware functions ------------ */
+
+static struct fb_ops stifb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_read	= stifb_read,
+	.fb_write	= stifb_write,
+	.fb_setcolreg	= stifb_setcolreg,
+	.fb_blank	= stifb_blank,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor      = soft_cursor,
+};
+
+
+/*
+ *  Initialization
+ */
+
+int __init
+stifb_init_fb(struct sti_struct *sti, int bpp_pref)
+{
+	struct fb_fix_screeninfo *fix;
+	struct fb_var_screeninfo *var;
+	struct stifb_info *fb;
+	struct fb_info *info;
+	unsigned long sti_rom_address;
+	char *dev_name;
+	int bpp, xres, yres;
+
+	fb = kmalloc(sizeof(*fb), GFP_ATOMIC);
+	if (!fb) {
+		printk(KERN_ERR "stifb: Could not allocate stifb structure\n");
+		return -ENODEV;
+	}
+	
+	info = &fb->info;
+
+	/* set struct to a known state */
+	memset(fb, 0, sizeof(*fb));
+	fix = &info->fix;
+	var = &info->var;
+
+	fb->sti = sti;
+	/* store upper 32bits of the graphics id */
+	fb->id = fb->sti->graphics_id[0];
+
+	/* only supported cards are allowed */
+	switch (fb->id) {
+	case CRT_ID_VISUALIZE_EG:
+		/* look for a double buffering device like e.g. the 
+		   "INTERNAL_EG_DX1024" in the RDI precisionbook laptop
+		   which won't work. The same device in non-double 
+		   buffering mode returns "INTERNAL_EG_X1024". */
+		if (strstr(sti->outptr.dev_name, "EG_DX")) {
+		   printk(KERN_WARNING 
+			"stifb: ignoring '%s'. Disable double buffering in IPL menu.\n",
+			sti->outptr.dev_name);
+		   goto out_err0;
+		}
+		/* fall though */
+	case S9000_ID_ARTIST:
+	case S9000_ID_HCRX:
+	case S9000_ID_TIMBER:
+	case S9000_ID_A1659A:
+	case S9000_ID_A1439A:
+		break;
+	default:
+		printk(KERN_WARNING "stifb: '%s' (id: 0x%08x) not supported.\n",
+			sti->outptr.dev_name, fb->id);
+		goto out_err0;
+	}
+	
+	/* default to 8 bpp on most graphic chips */
+	bpp = 8;
+	xres = sti_onscreen_x(fb->sti);
+	yres = sti_onscreen_y(fb->sti);
+
+	ngleGetDeviceRomData(fb);
+
+	/* get (virtual) io region base addr */
+	fix->mmio_start = REGION_BASE(fb,2);
+	fix->mmio_len   = 0x400000;
+
+       	/* Reject any device not in the NGLE family */
+	switch (fb->id) {
+	case S9000_ID_A1659A:	/* CRX/A1659A */
+		break;
+	case S9000_ID_ELM:	/* GRX, grayscale but else same as A1659A */
+		var->grayscale = 1;
+		fb->id = S9000_ID_A1659A;
+		break;
+	case S9000_ID_TIMBER:	/* HP9000/710 Any (may be a grayscale device) */
+		dev_name = fb->sti->outptr.dev_name;
+		if (strstr(dev_name, "GRAYSCALE") || 
+		    strstr(dev_name, "Grayscale") ||
+		    strstr(dev_name, "grayscale"))
+			var->grayscale = 1;
+		break;
+	case S9000_ID_TOMCAT:	/* Dual CRX, behaves else like a CRX */
+		/* FIXME: TomCat supports two heads:
+		 * fb.iobase = REGION_BASE(fb_info,3);
+		 * fb.screen_base = (void*) REGION_BASE(fb_info,2);
+		 * for now we only support the left one ! */
+		xres = fb->ngle_rom.x_size_visible;
+		yres = fb->ngle_rom.y_size_visible;
+		fb->id = S9000_ID_A1659A;
+		break;
+	case S9000_ID_A1439A:	/* CRX24/A1439A */
+		bpp = 32;
+		break;
+	case S9000_ID_HCRX:	/* Hyperdrive/HCRX */
+		memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
+		if ((fb->sti->regions_phys[0] & 0xfc000000) ==
+		    (fb->sti->regions_phys[2] & 0xfc000000))
+			sti_rom_address = fb->sti->regions_phys[0];
+		else
+			sti_rom_address = fb->sti->regions_phys[1];
+#ifdef __LP64__
+	        sti_rom_address |= 0xffffffff00000000;
+#endif
+		fb->deviceSpecificConfig = gsc_readl(sti_rom_address);
+		if (IS_24_DEVICE(fb)) {
+			if (bpp_pref == 8 || bpp_pref == 32)
+				bpp = bpp_pref;
+			else
+				bpp = 32;
+		} else
+			bpp = 8;
+		READ_WORD(fb, REG_15);
+		SETUP_HW(fb);
+		break;
+	case CRT_ID_VISUALIZE_EG:
+	case S9000_ID_ARTIST:	/* Artist */
+		break;
+	default: 
+#ifdef FALLBACK_TO_1BPP
+	       	printk(KERN_WARNING 
+			"stifb: Unsupported graphics card (id=0x%08x) "
+				"- now trying 1bpp mode instead\n",
+			fb->id);
+		bpp = 1;	/* default to 1 bpp */
+		break;
+#else
+	       	printk(KERN_WARNING 
+			"stifb: Unsupported graphics card (id=0x%08x) "
+				"- skipping.\n",
+			fb->id);
+		goto out_err0;
+#endif
+	}
+
+
+	/* get framebuffer physical and virtual base addr & len (64bit ready) */
+	fix->smem_start = F_EXTEND(fb->sti->regions_phys[1]);
+	fix->smem_len = fb->sti->regions[1].region_desc.length * 4096;
+
+	fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8;
+	if (!fix->line_length)
+		fix->line_length = 2048; /* default */
+	
+	/* limit fbsize to max visible screen size */
+	if (fix->smem_len > yres*fix->line_length)
+		fix->smem_len = yres*fix->line_length;
+	
+	fix->accel = FB_ACCEL_NONE;
+
+	switch (bpp) {
+	    case 1:
+		fix->type = FB_TYPE_PLANES;	/* well, sort of */
+		fix->visual = FB_VISUAL_MONO10;
+		var->red.length = var->green.length = var->blue.length = 1;
+		break;
+	    case 8:
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->visual = FB_VISUAL_PSEUDOCOLOR;
+		var->red.length = var->green.length = var->blue.length = 8;
+		break;
+	    case 32:
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->visual = FB_VISUAL_TRUECOLOR;
+		var->red.length = var->green.length = var->blue.length = var->transp.length = 8;
+		var->blue.offset = 0;
+		var->green.offset = 8;
+		var->red.offset = 16;
+		var->transp.offset = 24;
+		break;
+	    default:
+		break;
+	}
+	
+	var->xres = var->xres_virtual = xres;
+	var->yres = var->yres_virtual = yres;
+	var->bits_per_pixel = bpp;
+
+	strcpy(fix->id, "stifb");
+	info->fbops = &stifb_ops;
+	info->screen_base = (void*) REGION_BASE(fb,1);
+	info->flags = FBINFO_DEFAULT;
+	info->pseudo_palette = &fb->pseudo_palette;
+
+	/* This has to been done !!! */
+	fb_alloc_cmap(&info->cmap, 256, 0);
+	stifb_init_display(fb);
+
+	if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) {
+		printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
+				fix->smem_start, fix->smem_start+fix->smem_len);
+		goto out_err1;
+	}
+		
+	if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
+		printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
+				fix->mmio_start, fix->mmio_start+fix->mmio_len);
+		goto out_err2;
+	}
+
+	if (register_framebuffer(&fb->info) < 0)
+		goto out_err3;
+
+	sti->info = info; /* save for unregister_framebuffer() */
+
+	printk(KERN_INFO 
+	    "fb%d: %s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n",
+		fb->info.node, 
+		fix->id,
+		var->xres, 
+		var->yres,
+		var->bits_per_pixel,
+		sti->outptr.dev_name,
+		fb->id, 
+		fix->mmio_start);
+
+	return 0;
+
+
+out_err3:
+	release_mem_region(fix->mmio_start, fix->mmio_len);
+out_err2:
+	release_mem_region(fix->smem_start, fix->smem_len);
+out_err1:
+	fb_dealloc_cmap(&info->cmap);
+out_err0:
+	kfree(fb);
+	return -ENXIO;
+}
+
+static int stifb_disabled __initdata;
+
+int __init
+stifb_setup(char *options);
+
+int __init
+stifb_init(void)
+{
+	struct sti_struct *sti;
+	struct sti_struct *def_sti;
+	int i;
+	
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("stifb", &option))
+		return -ENODEV;
+	stifb_setup(option);
+#endif
+	if (stifb_disabled) {
+		printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n");
+		return -ENXIO;
+	}
+	
+	def_sti = sti_get_rom(0);
+	if (def_sti) {
+		for (i = 1; i <= MAX_STI_ROMS; i++) {
+			sti = sti_get_rom(i);
+			if (!sti)
+				break;
+			if (sti == def_sti) {
+				stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
+				break;
+			}
+		}
+	}
+
+	for (i = 1; i <= MAX_STI_ROMS; i++) {
+		sti = sti_get_rom(i);
+		if (!sti)
+			break;
+		if (sti == def_sti)
+			continue;
+		stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
+	}
+	return 0;
+}
+
+/*
+ *  Cleanup
+ */
+
+static void __exit
+stifb_cleanup(void)
+{
+	struct sti_struct *sti;
+	int i;
+	
+	for (i = 1; i <= MAX_STI_ROMS; i++) {
+		sti = sti_get_rom(i);
+		if (!sti)
+			break;
+		if (sti->info) {
+			struct fb_info *info = sti->info;
+			unregister_framebuffer(sti->info);
+			release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+		        release_mem_region(info->fix.smem_start, info->fix.smem_len);
+		        fb_dealloc_cmap(&info->cmap);
+		        kfree(info); 
+		}
+		sti->info = NULL;
+	}
+}
+
+int __init
+stifb_setup(char *options)
+{
+	int i;
+	
+	if (!options || !*options)
+		return 0;
+	
+	if (strncmp(options, "off", 3) == 0) {
+		stifb_disabled = 1;
+		options += 3;
+	}
+
+	if (strncmp(options, "bpp", 3) == 0) {
+		options += 3;
+		for (i = 0; i < MAX_STI_ROMS; i++) {
+			if (*options++ != ':')
+				break;
+			stifb_bpp_pref[i] = simple_strtoul(options, &options, 10);
+		}
+	}
+	return 0;
+}
+
+__setup("stifb=", stifb_setup);
+
+module_init(stifb_init);
+module_exit(stifb_cleanup);
+
+MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
+MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
+MODULE_LICENSE("GPL v2");
+
+MODULE_PARM(bpp, "i");
+MODULE_PARM_DESC(mem, "Bits per pixel (default: 8)");
+
diff --git a/drivers/video/sun3fb.c b/drivers/video/sun3fb.c
new file mode 100644
index 0000000..9b36b9d
--- /dev/null
+++ b/drivers/video/sun3fb.c
@@ -0,0 +1,704 @@
+/*
+ *  linux/drivers/video/sun3fb.c -- Frame buffer driver for Sun3
+ *
+ * (C) 1998 Thomas Bogendoerfer
+ *
+ * This driver is bases on sbusfb.c, which is
+ *
+ *	Copyright (C) 1998 Jakub Jelinek
+ *
+ *  This driver is partly based on the Open Firmware console driver
+ *
+ *	Copyright (C) 1997 Geert Uytterhoeven
+ *
+ *  and SPARC console subsystem
+ *
+ *      Copyright (C) 1995 Peter Zaitcev (zaitcev@yahoo.com)
+ *      Copyright (C) 1995-1997 David S. Miller (davem@caip.rutgers.edu)
+ *      Copyright (C) 1995-1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *      Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
+ *      Copyright (C) 1996-1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *      Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ *
+ *  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 <linux/fb.h>
+#include <linux/selection.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/kd.h>
+#include <linux/vt_kern.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>	/* io_remap_page_range() */
+
+#ifdef CONFIG_SUN3
+#include <asm/oplib.h>
+#include <asm/machines.h>
+#include <asm/idprom.h>
+
+#define CGFOUR_OBMEM_ADDR 0x1f300000
+#define BWTWO_OBMEM_ADDR 0x1f000000
+#define BWTWO_OBMEM50_ADDR 0x00100000
+
+#endif
+#ifdef CONFIG_SUN3X
+#include <asm/sun3x.h>
+#endif
+#include <video/sbusfb.h>
+
+#define DEFAULT_CURSOR_BLINK_RATE       (2*HZ/5)
+
+#define CURSOR_SHAPE			1
+#define CURSOR_BLINK			2
+
+#define mymemset(x,y) memset(x,0,y)
+
+    /*
+     *  Interface used by the world
+     */
+
+int sun3fb_init(void);
+void sun3fb_setup(char *options);
+
+static char fontname[40] __initdata = { 0 };
+static int curblink __initdata = 1;
+
+static int sun3fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			struct fb_info *info);
+static int sun3fb_get_var(struct fb_var_screeninfo *var, int con,
+			struct fb_info *info);
+static int sun3fb_set_var(struct fb_var_screeninfo *var, int con,
+			struct fb_info *info);
+static int sun3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			struct fb_info *info);
+static int sun3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			struct fb_info *info);
+static int sun3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			    u_int transp, struct fb_info *info);
+static int sun3fb_blank(int blank, struct fb_info *info);
+static void sun3fb_cursor(struct display *p, int mode, int x, int y);
+static void sun3fb_clear_margin(struct display *p, int s);
+
+    /*
+     *  Interface to the low level console driver
+     */
+
+static int sun3fbcon_switch(int con, struct fb_info *info);
+static int sun3fbcon_updatevar(int con, struct fb_info *info);
+
+    /*
+     *  Internal routines
+     */
+
+static int sun3fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+			    u_int *transp, struct fb_info *info);
+
+static struct fb_ops sun3fb_ops = {
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	sun3fb_get_fix,
+	.fb_get_var =	sun3fb_get_var,
+	.fb_set_var =	sun3fb_set_var,
+	.fb_get_cmap =	sun3fb_get_cmap,
+	.fb_set_cmap =	sun3fb_set_cmap,
+	.fb_setcolreg =	sun3fb_setcolreg,
+	.fb_blank =	sun3fb_blank,
+};
+
+static void sun3fb_clear_margin(struct display *p, int s)
+{
+	struct fb_info_sbusfb *fb = sbusfbinfod(p);
+	
+	return;
+
+	if (fb->switch_from_graph)
+		(*fb->switch_from_graph)(fb);
+	if (fb->fill) {
+		unsigned short rects [16];
+
+		rects [0] = 0;
+		rects [1] = 0;
+		rects [2] = fb->var.xres_virtual;
+		rects [3] = fb->y_margin;
+		rects [4] = 0;
+		rects [5] = fb->y_margin;
+		rects [6] = fb->x_margin;
+		rects [7] = fb->var.yres_virtual;
+		rects [8] = fb->var.xres_virtual - fb->x_margin;
+		rects [9] = fb->y_margin;
+		rects [10] = fb->var.xres_virtual;
+		rects [11] = fb->var.yres_virtual;
+		rects [12] = fb->x_margin;
+		rects [13] = fb->var.yres_virtual - fb->y_margin;
+		rects [14] = fb->var.xres_virtual - fb->x_margin;
+		rects [15] = fb->var.yres_virtual;
+		(*fb->fill)(fb, p, s, 4, rects);
+	} else {
+		unsigned char *fb_base = fb->info.screen_base, *q;
+		int skip_bytes = fb->y_margin * fb->var.xres_virtual;
+		int scr_size = fb->var.xres_virtual * fb->var.yres_virtual;
+		int h, he, incr, size;
+
+		he = fb->var.yres;
+		if (fb->var.bits_per_pixel == 1) {
+			fb_base -= (skip_bytes + fb->x_margin) / 8;
+			skip_bytes /= 8;
+			scr_size /= 8;
+			mymemset (fb_base, skip_bytes - fb->x_margin / 8);
+			mymemset (fb_base + scr_size - skip_bytes + fb->x_margin / 8, skip_bytes - fb->x_margin / 8);
+			incr = fb->var.xres_virtual / 8;
+			size = fb->x_margin / 8 * 2;
+			for (q = fb_base + skip_bytes - fb->x_margin / 8, h = 0;
+			     h <= he; q += incr, h++)
+				mymemset (q, size);
+		} else {
+			fb_base -= (skip_bytes + fb->x_margin);
+			memset (fb_base, attr_bgcol(p,s), skip_bytes - fb->x_margin);
+			memset (fb_base + scr_size - skip_bytes + fb->x_margin, attr_bgcol(p,s), skip_bytes - fb->x_margin);
+			incr = fb->var.xres_virtual;
+			size = fb->x_margin * 2;
+			for (q = fb_base + skip_bytes - fb->x_margin, h = 0;
+			     h <= he; q += incr, h++)
+				memset (q, attr_bgcol(p,s), size);
+		}
+	}
+}
+
+static void sun3fb_disp_setup(struct display *p)
+{
+	struct fb_info_sbusfb *fb = sbusfbinfod(p);
+
+	if (fb->setup)
+		fb->setup(p);	
+	sun3fb_clear_margin(p, 0);
+}
+
+    /*
+     *  Get the Fixed Part of the Display
+     */
+
+static int sun3fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			  struct fb_info *info)
+{
+	struct fb_info_sbusfb *fb = sbusfbinfo(info);
+
+	memcpy(fix, &fb->fix, sizeof(struct fb_fix_screeninfo));
+	return 0;
+}
+
+    /*
+     *  Get the User Defined Part of the Display
+     */
+
+static int sun3fb_get_var(struct fb_var_screeninfo *var, int con,
+			  struct fb_info *info)
+{
+	struct fb_info_sbusfb *fb = sbusfbinfo(info);
+
+	memcpy(var, &fb->var, sizeof(struct fb_var_screeninfo));
+	return 0;
+}
+
+    /*
+     *  Set the User Defined Part of the Display
+     */
+
+static int sun3fb_set_var(struct fb_var_screeninfo *var, int con,
+			struct fb_info *info)
+{
+	struct fb_info_sbusfb *fb = sbusfbinfo(info);
+
+	if (var->xres > fb->var.xres || var->yres > fb->var.yres ||
+	    var->xres_virtual > fb->var.xres_virtual ||
+	    var->yres_virtual > fb->var.yres_virtual ||
+	    var->bits_per_pixel != fb->var.bits_per_pixel ||
+	    var->nonstd ||
+	    (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+		return -EINVAL;
+	memcpy(var, &fb->var, sizeof(struct fb_var_screeninfo));
+	return 0;
+}
+
+    /*
+     *  Hardware cursor
+     */
+     
+static unsigned char hw_cursor_cmap[2] = { 0, 0xff };
+
+static void
+sun3fb_cursor_timer_handler(unsigned long dev_addr)
+{
+	struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)dev_addr;
+        
+	if (!fb->setcursor) return;
+                                
+	if (fb->cursor.mode & CURSOR_BLINK) {
+		fb->cursor.enable ^= 1;
+		fb->setcursor(fb);
+	}
+	
+	fb->cursor.timer.expires = jiffies + fb->cursor.blink_rate;
+	add_timer(&fb->cursor.timer);
+}
+
+static void sun3fb_cursor(struct display *p, int mode, int x, int y)
+{
+	struct fb_info_sbusfb *fb = sbusfbinfod(p);
+	
+	switch (mode) {
+	case CM_ERASE:
+		fb->cursor.mode &= ~CURSOR_BLINK;
+		fb->cursor.enable = 0;
+		(*fb->setcursor)(fb);
+		break;
+				  
+	case CM_MOVE:
+	case CM_DRAW:
+		if (fb->cursor.mode & CURSOR_SHAPE) {
+			fb->cursor.size.fbx = fontwidth(p);
+			fb->cursor.size.fby = fontheight(p);
+			fb->cursor.chot.fbx = 0;
+			fb->cursor.chot.fby = 0;
+			fb->cursor.enable = 1;
+			memset (fb->cursor.bits, 0, sizeof (fb->cursor.bits));
+			fb->cursor.bits[0][fontheight(p) - 2] = (0xffffffff << (32 - fontwidth(p)));
+			fb->cursor.bits[1][fontheight(p) - 2] = (0xffffffff << (32 - fontwidth(p)));
+			fb->cursor.bits[0][fontheight(p) - 1] = (0xffffffff << (32 - fontwidth(p)));
+			fb->cursor.bits[1][fontheight(p) - 1] = (0xffffffff << (32 - fontwidth(p)));
+			(*fb->setcursormap) (fb, hw_cursor_cmap, hw_cursor_cmap, hw_cursor_cmap);
+			(*fb->setcurshape) (fb);
+		}
+		fb->cursor.mode = CURSOR_BLINK;
+		if (fontwidthlog(p))
+			fb->cursor.cpos.fbx = (x << fontwidthlog(p)) + fb->x_margin;
+		else
+			fb->cursor.cpos.fbx = (x * fontwidth(p)) + fb->x_margin;
+		if (fontheightlog(p))
+			fb->cursor.cpos.fby = (y << fontheightlog(p)) + fb->y_margin;
+		else
+			fb->cursor.cpos.fby = (y * fontheight(p)) + fb->y_margin;
+		(*fb->setcursor)(fb);
+		break;
+	}
+}
+
+    /*
+     *  Get the Colormap
+     */
+
+static int sun3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			 struct fb_info *info)
+{
+	if (con == info->currcon) /* current console? */
+		return fb_get_cmap(cmap, kspc, sun3fb_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 sun3fb_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? */
+		if ((err = fb_alloc_cmap(&fb_display[con].cmap, 1<<fb_display[con].var.bits_per_pixel, 0)))
+			return err;
+	}
+	if (con == info->currcon) {			/* current console? */
+		err = fb_set_cmap(cmap, kspc, info);
+		if (!err) {
+			struct fb_info_sbusfb *fb = sbusfbinfo(info);
+			
+			if (fb->loadcmap)
+				(*fb->loadcmap)(fb, &fb_display[con], cmap->start, cmap->len);
+		}
+		return err;
+	} else
+		fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+	return 0;
+}
+
+    /*
+     *  Setup: parse used options
+     */
+
+void __init sun3fb_setup(char *options)
+{
+	char *p;
+	
+	for (p = options;;) {
+		if (!strncmp(p, "font=", 5)) {
+			int i;
+			
+			for (i = 0; i < sizeof(fontname) - 1; i++)
+				if (p[i+5] == ' ' || !p[i+5])
+					break;
+			memcpy(fontname, p+5, i);
+			fontname[i] = 0;
+		} else if (!strncmp(p, "noblink", 7))
+			curblink = 0;
+		while (*p && *p != ' ' && *p != ',') p++;
+		if (*p != ',') break;
+		p++;
+	}
+
+	return;
+}
+
+static int sun3fbcon_switch(int con, struct fb_info *info)
+{
+	int x_margin, y_margin;
+	struct fb_info_sbusfb *fb = sbusfbinfo(info);
+	int lastconsole;
+    
+	/* Do we have to save the colormap? */
+	if (fb_display[info->currcon].cmap.len)
+		fb_get_cmap(&fb_display[info->currcon].cmap, 1, sun3fb_getcolreg, info);
+
+	if (info->display_fg) {
+		lastconsole = info->display_fg->vc_num;
+		if (lastconsole != con && 
+		    (fontwidth(&fb_display[lastconsole]) != fontwidth(&fb_display[con]) ||
+		     fontheight(&fb_display[lastconsole]) != fontheight(&fb_display[con])))
+			fb->cursor.mode |= CURSOR_SHAPE;
+	}
+	x_margin = (fb_display[con].var.xres_virtual - fb_display[con].var.xres) / 2;
+	y_margin = (fb_display[con].var.yres_virtual - fb_display[con].var.yres) / 2;
+	if (fb->margins)
+		fb->margins(fb, &fb_display[con], x_margin, y_margin);
+	if (fb->graphmode || fb->x_margin != x_margin || fb->y_margin != y_margin) {
+		fb->x_margin = x_margin; fb->y_margin = y_margin;
+		sun3fb_clear_margin(&fb_display[con], 0);
+	}
+	info->currcon = con;
+	/* Install new colormap */
+	do_install_cmap(con, info);
+	return 0;
+}
+
+    /*
+     *  Update the `var' structure (called by fbcon.c)
+     */
+
+static int sun3fbcon_updatevar(int con, struct fb_info *info)
+{
+	/* Nothing */
+	return 0;
+}
+
+    /*
+     *  Blank the display.
+     */
+
+static int sun3fb_blank(int blank, struct fb_info *info)
+{
+    struct fb_info_sbusfb *fb = sbusfbinfo(info);
+    
+    if (blank && fb->blank)
+    	return fb->blank(fb);
+    else if (!blank && fb->unblank)
+    	return fb->unblank(fb);
+    return 0;
+}
+
+    /*
+     *  Read a single color register and split it into
+     *  colors/transparent. Return != 0 for invalid regno.
+     */
+
+static int sun3fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+			  u_int *transp, struct fb_info *info)
+{
+	struct fb_info_sbusfb *fb = sbusfbinfo(info);
+
+	if (!fb->color_map || regno > 255)
+		return 1;
+	*red = (fb->color_map CM(regno, 0)<<8) | fb->color_map CM(regno, 0);
+	*green = (fb->color_map CM(regno, 1)<<8) | fb->color_map CM(regno, 1);
+	*blue = (fb->color_map CM(regno, 2)<<8) | fb->color_map CM(regno, 2);
+	*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 sun3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			    u_int transp, struct fb_info *info)
+{
+	struct fb_info_sbusfb *fb = sbusfbinfo(info);
+
+	if (!fb->color_map || regno > 255)
+		return 1;
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+	fb->color_map CM(regno, 0) = red;
+	fb->color_map CM(regno, 1) = green;
+	fb->color_map CM(regno, 2) = blue;
+	return 0;
+}
+
+static int sun3fb_set_font(struct display *p, int width, int height)
+{
+	int w = p->var.xres_virtual, h = p->var.yres_virtual;
+	int depth = p->var.bits_per_pixel;
+	struct fb_info_sbusfb *fb = sbusfbinfod(p);
+	int x_margin, y_margin;
+	
+	if (depth > 8) depth = 8;
+	x_margin = (w % width) / 2;
+	y_margin = (h % height) / 2;
+
+	p->var.xres = w - 2*x_margin;
+	p->var.yres = h - 2*y_margin;
+	
+	fb->cursor.mode |= CURSOR_SHAPE;
+	
+	if (fb->margins)
+		fb->margins(fb, p, x_margin, y_margin);
+	if (fb->x_margin != x_margin || fb->y_margin != y_margin) {
+		fb->x_margin = x_margin; fb->y_margin = y_margin;
+		sun3fb_clear_margin(p, 0);
+	}
+
+	return 1;
+}
+
+void sun3fb_palette(int enter)
+{
+	int i;
+	struct display *p;
+	
+	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+		p = &fb_display[i];
+		if (p->dispsw && p->dispsw->setup == sun3fb_disp_setup &&
+		    p->fb_info->display_fg &&
+		    p->fb_info->display_fg->vc_num == i) {
+			struct fb_info_sbusfb *fb = sbusfbinfod(p);
+
+			if (fb->restore_palette) {
+				if (enter)
+					fb->restore_palette(fb);
+				else if (vc_cons[i].d->vc_mode != KD_GRAPHICS)
+				         vc_cons[i].d->vc_sw->con_set_palette(vc_cons[i].d, color_table);
+			}
+		}
+	}
+}
+
+    /*
+     *  Initialisation
+     */
+static int __init sun3fb_init_fb(int fbtype, unsigned long addr)
+{
+	static struct sbus_dev sdb;
+	struct fb_fix_screeninfo *fix;
+	struct fb_var_screeninfo *var;
+	struct display *disp;
+	struct fb_info_sbusfb *fb;
+	struct fbtype *type;
+	int linebytes, w, h, depth;
+	char *p = NULL;
+	
+	fb = kmalloc(sizeof(struct fb_info_sbusfb), GFP_ATOMIC);
+	if (!fb)
+		return -ENOMEM;
+	
+	memset(fb, 0, sizeof(struct fb_info_sbusfb));
+	fix = &fb->fix;
+	var = &fb->var;
+	disp = &fb->disp;
+	type = &fb->type;
+	
+	sdb.reg_addrs[0].phys_addr = addr;
+	fb->sbdp = &sdb;
+
+	type->fb_type = fbtype;
+	
+	type->fb_height = h = 900;
+	type->fb_width  = w = 1152;
+sizechange:
+	type->fb_depth  = depth = (fbtype == FBTYPE_SUN2BW) ? 1 : 8;
+	linebytes = w * depth / 8;
+	type->fb_size   = PAGE_ALIGN((linebytes) * h);
+/*	
+	fb->x_margin = (w & 7) / 2;
+	fb->y_margin = (h & 15) / 2;
+*/
+	fb->x_margin = fb->y_margin = 0;
+
+	var->xres_virtual = w;
+	var->yres_virtual = h;
+	var->xres = w - 2*fb->x_margin;
+	var->yres = h - 2*fb->y_margin;
+	
+	var->bits_per_pixel = depth;
+	var->height = var->width = -1;
+	var->pixclock = 10000;
+	var->vmode = FB_VMODE_NONINTERLACED;
+	var->red.length = var->green.length = var->blue.length = 8;
+
+	fix->line_length = linebytes;
+	fix->smem_len = type->fb_size;
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->visual = FB_VISUAL_PSEUDOCOLOR;
+	
+	fb->info.fbops = &sun3fb_ops;
+	fb->info.disp = disp;
+	fb->info.currcon = -1;
+	strcpy(fb->info.fontname, fontname);
+	fb->info.changevar = NULL;
+	fb->info.switch_con = &sun3fbcon_switch;
+	fb->info.updatevar = &sun3fbcon_updatevar;
+	fb->info.flags = FBINFO_FLAG_DEFAULT;
+	
+	fb->cursor.hwsize.fbx = 32;
+	fb->cursor.hwsize.fby = 32;
+	
+	if (depth > 1 && !fb->color_map) {
+		if((fb->color_map = kmalloc(256 * 3, GFP_ATOMIC))==NULL)
+			return -ENOMEM;
+	}
+			
+	switch(fbtype) {
+#ifdef CONFIG_FB_CGSIX
+	case FBTYPE_SUNFAST_COLOR:
+		p = cgsixfb_init(fb); break;
+#endif
+#ifdef CONFIG_FB_BWTWO
+	case FBTYPE_SUN2BW:
+		p = bwtwofb_init(fb); break;
+#endif
+#ifdef CONFIG_FB_CGTHREE
+	case FBTYPE_SUN4COLOR:
+	case FBTYPE_SUN3COLOR:
+		type->fb_size = 0x100000;
+		p = cgthreefb_init(fb); break;
+#endif
+	}
+	fix->smem_start = (unsigned long)fb->info.screen_base;	// FIXME
+	
+	if (!p) {
+		kfree(fb);
+		return -ENODEV;
+	}
+	
+	if (p == SBUSFBINIT_SIZECHANGE)
+		goto sizechange;
+
+	disp->dispsw = &fb->dispsw;
+	if (fb->setcursor) {
+		fb->dispsw.cursor = sun3fb_cursor;
+		if (curblink) {
+			fb->cursor.blink_rate = DEFAULT_CURSOR_BLINK_RATE;
+			init_timer(&fb->cursor.timer);
+			fb->cursor.timer.expires = jiffies + fb->cursor.blink_rate;
+			fb->cursor.timer.data = (unsigned long)fb;
+			fb->cursor.timer.function = sun3fb_cursor_timer_handler;
+			add_timer(&fb->cursor.timer);
+		}
+	}
+	fb->cursor.mode = CURSOR_SHAPE;
+	fb->dispsw.set_font = sun3fb_set_font;
+	fb->setup = fb->dispsw.setup;
+	fb->dispsw.setup = sun3fb_disp_setup;
+	fb->dispsw.clear_margins = NULL;
+
+	disp->var = *var;
+	disp->visual = fix->visual;
+	disp->type = fix->type;
+	disp->type_aux = fix->type_aux;
+	disp->line_length = fix->line_length;
+	
+	if (fb->blank)
+		disp->can_soft_blank = 1;
+
+	sun3fb_set_var(var, -1, &fb->info);
+
+	if (register_framebuffer(&fb->info) < 0) {
+		kfree(fb);
+		return -EINVAL;
+	}
+	printk("fb%d: %s\n", fb->info.node, p);
+
+	return 0;
+}
+
+
+int __init sun3fb_init(void)
+{
+	extern int con_is_present(void);
+	unsigned long addr;
+	char p4id;
+	
+	if (!con_is_present()) return -ENODEV;
+#ifdef CONFIG_SUN3
+        switch(*(romvec->pv_fbtype))
+        {
+	case FBTYPE_SUN2BW:
+		addr = 0xfe20000;
+		return sun3fb_init_fb(FBTYPE_SUN2BW, addr);
+	case FBTYPE_SUN3COLOR:
+	case FBTYPE_SUN4COLOR:
+		if(idprom->id_machtype != (SM_SUN3|SM_3_60)) {
+			printk("sun3fb: cgthree/four only supported on 3/60\n");
+			return -ENODEV;
+		}
+		
+		addr = CGFOUR_OBMEM_ADDR;
+		return sun3fb_init_fb(*(romvec->pv_fbtype), addr);
+	default:
+		printk("sun3fb: unsupported framebuffer\n");
+		return -ENODEV;
+	}
+#else
+	addr = SUN3X_VIDEO_BASE;
+	p4id = *(char *)SUN3X_VIDEO_P4ID;
+
+	p4id = (p4id == 0x45) ? p4id : (p4id & 0xf0);
+	switch (p4id) {
+		case 0x00:
+			return sun3fb_init_fb(FBTYPE_SUN2BW, addr);
+#if 0 /* not yet */
+		case 0x40:
+			return sun3fb_init_fb(FBTYPE_SUN4COLOR, addr);
+			break;
+		case 0x45:
+			return sun3fb_init_fb(FBTYPE_SUN8COLOR, addr);
+			break;
+#endif
+		case 0x60:
+			return sun3fb_init_fb(FBTYPE_SUNFAST_COLOR, addr);
+	}
+#endif			
+	
+	return -ENODEV;
+}
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c
new file mode 100644
index 0000000..e2fa9e1
--- /dev/null
+++ b/drivers/video/tcx.c
@@ -0,0 +1,504 @@
+/* tcx.c: TCX frame buffer driver
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ *
+ * Driver layout based loosely on tgafb.c, see that file for credits.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/mm.h>
+
+#include <asm/io.h>
+#include <asm/sbus.h>
+#include <asm/oplib.h>
+#include <asm/fbio.h>
+
+#include "sbuslib.h"
+
+/*
+ * Local functions.
+ */
+
+static int tcx_setcolreg(unsigned, unsigned, unsigned, unsigned,
+			 unsigned, struct fb_info *);
+static int tcx_blank(int, struct fb_info *);
+
+static int tcx_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
+static int tcx_ioctl(struct inode *, struct file *, unsigned int,
+		     unsigned long, struct fb_info *);
+
+/*
+ *  Frame buffer operations
+ */
+
+static struct fb_ops tcx_ops = {
+	.owner			= THIS_MODULE,
+	.fb_setcolreg		= tcx_setcolreg,
+	.fb_blank		= tcx_blank,
+	.fb_fillrect		= cfb_fillrect,
+	.fb_copyarea		= cfb_copyarea,
+	.fb_imageblit		= cfb_imageblit,
+	.fb_mmap		= tcx_mmap,
+	.fb_ioctl		= tcx_ioctl,
+	.fb_cursor		= soft_cursor,
+};
+
+/* THC definitions */
+#define TCX_THC_MISC_REV_SHIFT       16
+#define TCX_THC_MISC_REV_MASK        15
+#define TCX_THC_MISC_VSYNC_DIS       (1 << 25)
+#define TCX_THC_MISC_HSYNC_DIS       (1 << 24)
+#define TCX_THC_MISC_RESET           (1 << 12)
+#define TCX_THC_MISC_VIDEO           (1 << 10)
+#define TCX_THC_MISC_SYNC            (1 << 9)
+#define TCX_THC_MISC_VSYNC           (1 << 8)
+#define TCX_THC_MISC_SYNC_ENAB       (1 << 7)
+#define TCX_THC_MISC_CURS_RES        (1 << 6)
+#define TCX_THC_MISC_INT_ENAB        (1 << 5)
+#define TCX_THC_MISC_INT             (1 << 4)
+#define TCX_THC_MISC_INIT            0x9f
+#define TCX_THC_REV_REV_SHIFT        20
+#define TCX_THC_REV_REV_MASK         15
+#define TCX_THC_REV_MINREV_SHIFT     28
+#define TCX_THC_REV_MINREV_MASK      15
+
+/* The contents are unknown */
+struct tcx_tec {
+	volatile u32 tec_matrix;
+	volatile u32 tec_clip;
+	volatile u32 tec_vdc;
+};
+
+struct tcx_thc {
+	volatile u32 thc_rev;
+        u32 thc_pad0[511];
+	volatile u32 thc_hs;		/* hsync timing */
+	volatile u32 thc_hsdvs;
+	volatile u32 thc_hd;
+	volatile u32 thc_vs;		/* vsync timing */
+	volatile u32 thc_vd;
+	volatile u32 thc_refresh;
+	volatile u32 thc_misc;
+	u32 thc_pad1[56];
+	volatile u32 thc_cursxy;	/* cursor x,y position (16 bits each) */
+	volatile u32 thc_cursmask[32];	/* cursor mask bits */
+	volatile u32 thc_cursbits[32];	/* what to show where mask enabled */
+};
+
+struct bt_regs {
+	volatile u32 addr;
+	volatile u32 color_map;
+	volatile u32 control;
+	volatile u32 cursor;
+};
+
+#define TCX_MMAP_ENTRIES 14
+
+struct tcx_par {
+	spinlock_t		lock;
+	struct bt_regs		__iomem *bt;
+	struct tcx_thc		__iomem *thc;
+	struct tcx_tec		__iomem *tec;
+	volatile u32		__iomem *cplane;
+
+	u32			flags;
+#define TCX_FLAG_BLANKED	0x00000001
+
+	unsigned long		physbase;
+	unsigned long		fbsize;
+
+	struct sbus_mmap_map	mmap_map[TCX_MMAP_ENTRIES];
+	int			lowdepth;
+
+	struct sbus_dev		*sdev;
+	struct list_head	list;
+};
+
+/* Reset control plane so that WID is 8-bit plane. */
+static void __tcx_set_control_plane (struct tcx_par *par)
+{
+	volatile u32 __iomem *p, *pend;
+        
+	if (par->lowdepth)
+		return;
+
+	p = par->cplane;
+	if (p == NULL)
+		return;
+	for (pend = p + par->fbsize; p < pend; p++) {
+		u32 tmp = sbus_readl(p);
+
+		tmp &= 0xffffff;
+		sbus_writel(tmp, p);
+	}
+}
+                                                
+static void tcx_reset (struct fb_info *info)
+{
+	struct tcx_par *par = (struct tcx_par *) info->par;
+	unsigned long flags;
+
+	spin_lock_irqsave(&par->lock, flags);
+	__tcx_set_control_plane(par);
+	spin_unlock_irqrestore(&par->lock, flags);
+}
+
+/**
+ *      tcx_setcolreg - Optional function. Sets a color register.
+ *      @regno: boolean, 0 copy local, 1 get_user() function
+ *      @red: frame buffer colormap structure
+ *      @green: The green value which can be up to 16 bits wide
+ *      @blue:  The blue value which can be up to 16 bits wide.
+ *      @transp: If supported the alpha value which can be up to 16 bits wide.
+ *      @info: frame buffer info structure
+ */
+static int tcx_setcolreg(unsigned regno,
+			 unsigned red, unsigned green, unsigned blue,
+			 unsigned transp, struct fb_info *info)
+{
+	struct tcx_par *par = (struct tcx_par *) info->par;
+	struct bt_regs __iomem *bt = par->bt;
+	unsigned long flags;
+
+	if (regno >= 256)
+		return 1;
+
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	sbus_writel(regno << 24, &bt->addr);
+	sbus_writel(red << 24, &bt->color_map);
+	sbus_writel(green << 24, &bt->color_map);
+	sbus_writel(blue << 24, &bt->color_map);
+
+	spin_unlock_irqrestore(&par->lock, flags);
+
+	return 0;
+}
+
+/**
+ *      tcx_blank - Optional function.  Blanks the display.
+ *      @blank_mode: the blank mode we want.
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+tcx_blank(int blank, struct fb_info *info)
+{
+	struct tcx_par *par = (struct tcx_par *) info->par;
+	struct tcx_thc __iomem *thc = par->thc;
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	val = sbus_readl(&thc->thc_misc);
+
+	switch (blank) {
+	case FB_BLANK_UNBLANK: /* Unblanking */
+		val &= ~(TCX_THC_MISC_VSYNC_DIS |
+			 TCX_THC_MISC_HSYNC_DIS);
+		val |= TCX_THC_MISC_VIDEO;
+		par->flags &= ~TCX_FLAG_BLANKED;
+		break;
+
+	case FB_BLANK_NORMAL: /* Normal blanking */
+		val &= ~TCX_THC_MISC_VIDEO;
+		par->flags |= TCX_FLAG_BLANKED;
+		break;
+
+	case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
+		val |= TCX_THC_MISC_VSYNC_DIS;
+		break;
+	case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
+		val |= TCX_THC_MISC_HSYNC_DIS;
+		break;
+
+	case FB_BLANK_POWERDOWN: /* Poweroff */
+		break;
+	};
+
+	sbus_writel(val, &thc->thc_misc);
+
+	spin_unlock_irqrestore(&par->lock, flags);
+
+	return 0;
+}
+
+static struct sbus_mmap_map __tcx_mmap_map[TCX_MMAP_ENTRIES] = {
+	{
+		.voff	= TCX_RAM8BIT,
+		.size	= SBUS_MMAP_FBSIZE(1)
+	},
+	{
+		.voff	= TCX_RAM24BIT,
+		.size	= SBUS_MMAP_FBSIZE(4)
+	},
+	{
+		.voff	= TCX_UNK3,
+		.size	= SBUS_MMAP_FBSIZE(8)
+	},
+	{
+		.voff	= TCX_UNK4,
+		.size	= SBUS_MMAP_FBSIZE(8)
+	},
+	{
+		.voff	= TCX_CONTROLPLANE,
+		.size	= SBUS_MMAP_FBSIZE(4)
+	},
+	{
+		.voff	= TCX_UNK6,
+		.size	= SBUS_MMAP_FBSIZE(8)
+	},
+	{
+		.voff	= TCX_UNK7,
+		.size	= SBUS_MMAP_FBSIZE(8)
+	},
+	{
+		.voff	= TCX_TEC,
+		.size	= PAGE_SIZE
+	},
+	{
+		.voff	= TCX_BTREGS,
+		.size	= PAGE_SIZE
+	},
+	{
+		.voff	= TCX_THC,
+		.size	= PAGE_SIZE
+	},
+	{
+		.voff	= TCX_DHC,
+		.size	= PAGE_SIZE
+	},
+	{
+		.voff	= TCX_ALT,
+		.size	= PAGE_SIZE
+	},
+	{
+		.voff	= TCX_UNK2,
+		.size	= 0x20000
+	},
+	{ .size = 0 }
+};
+
+static int tcx_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+{
+	struct tcx_par *par = (struct tcx_par *)info->par;
+
+	return sbusfb_mmap_helper(par->mmap_map,
+				  par->physbase, par->fbsize,
+				  par->sdev->reg_addrs[0].which_io,
+				  vma);
+}
+
+static int tcx_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		     unsigned long arg, struct fb_info *info)
+{
+	struct tcx_par *par = (struct tcx_par *) info->par;
+
+	return sbusfb_ioctl_helper(cmd, arg, info,
+				   FBTYPE_TCXCOLOR,
+				   (par->lowdepth ? 8 : 24),
+				   par->fbsize);
+}
+
+/*
+ *  Initialisation
+ */
+
+static void
+tcx_init_fix(struct fb_info *info, int linebytes)
+{
+	struct tcx_par *par = (struct tcx_par *)info->par;
+	const char *tcx_name;
+
+	if (par->lowdepth)
+		tcx_name = "TCX8";
+	else
+		tcx_name = "TCX24";
+
+	strlcpy(info->fix.id, tcx_name, sizeof(info->fix.id));
+
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+
+	info->fix.line_length = linebytes;
+
+	info->fix.accel = FB_ACCEL_SUN_TCX;
+}
+
+struct all_info {
+	struct fb_info info;
+	struct tcx_par par;
+	struct list_head list;
+};
+static LIST_HEAD(tcx_list);
+
+static void tcx_init_one(struct sbus_dev *sdev)
+{
+	struct all_info *all;
+	int linebytes, i;
+
+	all = kmalloc(sizeof(*all), GFP_KERNEL);
+	if (!all) {
+		printk(KERN_ERR "tcx: Cannot allocate memory.\n");
+		return;
+	}
+	memset(all, 0, sizeof(*all));
+
+	INIT_LIST_HEAD(&all->list);
+
+	spin_lock_init(&all->par.lock);
+	all->par.sdev = sdev;
+
+	all->par.lowdepth = prom_getbool(sdev->prom_node, "tcx-8-bit");
+
+	sbusfb_fill_var(&all->info.var, sdev->prom_node, 8);
+
+	linebytes = prom_getintdefault(sdev->prom_node, "linebytes",
+				       all->info.var.xres);
+	all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
+
+	all->par.tec = sbus_ioremap(&sdev->resource[7], 0,
+			     sizeof(struct tcx_tec), "tcx tec");
+	all->par.thc = sbus_ioremap(&sdev->resource[9], 0,
+			     sizeof(struct tcx_thc), "tcx thc");
+	all->par.bt = sbus_ioremap(&sdev->resource[8], 0,
+			     sizeof(struct bt_regs), "tcx dac");
+	memcpy(&all->par.mmap_map, &__tcx_mmap_map, sizeof(all->par.mmap_map));
+	if (!all->par.lowdepth) {
+		all->par.cplane = sbus_ioremap(&sdev->resource[4], 0,
+				     all->par.fbsize * sizeof(u32), "tcx cplane");
+	} else {
+		all->par.mmap_map[1].size = SBUS_MMAP_EMPTY;
+		all->par.mmap_map[4].size = SBUS_MMAP_EMPTY;
+		all->par.mmap_map[5].size = SBUS_MMAP_EMPTY;
+		all->par.mmap_map[6].size = SBUS_MMAP_EMPTY;
+	}
+
+	all->par.physbase = 0;
+	for (i = 0; i < TCX_MMAP_ENTRIES; i++) {
+		int j;
+
+		switch (i) {
+		case 10:
+			j = 12;
+			break;
+
+		case 11: case 12:
+			j = i - 1;
+			break;
+
+		default:
+			j = i;
+			break;
+		};
+		all->par.mmap_map[i].poff = sdev->reg_addrs[j].phys_addr;
+	}
+
+	all->info.flags = FBINFO_DEFAULT;
+	all->info.fbops = &tcx_ops;
+#ifdef CONFIG_SPARC32
+	all->info.screen_base = (char __iomem *)
+		prom_getintdefault(sdev->prom_node, "address", 0);
+#endif
+	if (!all->info.screen_base)
+		all->info.screen_base = sbus_ioremap(&sdev->resource[0], 0,
+				     all->par.fbsize, "tcx ram");
+	all->info.par = &all->par;
+
+	/* Initialize brooktree DAC. */
+	sbus_writel(0x04 << 24, &all->par.bt->addr);         /* color planes */
+	sbus_writel(0xff << 24, &all->par.bt->control);
+	sbus_writel(0x05 << 24, &all->par.bt->addr);
+	sbus_writel(0x00 << 24, &all->par.bt->control);
+	sbus_writel(0x06 << 24, &all->par.bt->addr);         /* overlay plane */
+	sbus_writel(0x73 << 24, &all->par.bt->control);
+	sbus_writel(0x07 << 24, &all->par.bt->addr);
+	sbus_writel(0x00 << 24, &all->par.bt->control);
+
+	tcx_reset(&all->info);
+
+	tcx_blank(0, &all->info);
+
+	if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
+		printk(KERN_ERR "tcx: Could not allocate color map.\n");
+		kfree(all);
+		return;
+	}
+
+	tcx_init_fix(&all->info, linebytes);
+
+	if (register_framebuffer(&all->info) < 0) {
+		printk(KERN_ERR "tcx: Could not register framebuffer.\n");
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+		return;
+	}
+
+	list_add(&all->list, &tcx_list);
+
+	printk("tcx: %s at %lx:%lx, %s\n",
+	       sdev->prom_name,
+	       (long) sdev->reg_addrs[0].which_io,
+	       (long) sdev->reg_addrs[0].phys_addr,
+	       all->par.lowdepth ? "8-bit only" : "24-bit depth");
+}
+
+int __init tcx_init(void)
+{
+	struct sbus_bus *sbus;
+	struct sbus_dev *sdev;
+
+	if (fb_get_options("tcxfb", NULL))
+		return -ENODEV;
+
+	for_all_sbusdev(sdev, sbus) {
+		if (!strcmp(sdev->prom_name, "tcx"))
+			tcx_init_one(sdev);
+	}
+
+	return 0;
+}
+
+void __exit tcx_exit(void)
+{
+	struct list_head *pos, *tmp;
+
+	list_for_each_safe(pos, tmp, &tcx_list) {
+		struct all_info *all = list_entry(pos, typeof(*all), list);
+
+		unregister_framebuffer(&all->info);
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+	}
+}
+
+int __init
+tcx_setup(char *arg)
+{
+	/* No cmdline options yet... */
+	return 0;
+}
+
+module_init(tcx_init);
+
+#ifdef MODULE
+module_exit(tcx_exit);
+#endif
+
+MODULE_DESCRIPTION("framebuffer driver for TCX chipsets");
+MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
new file mode 100644
index 0000000..c34ba39
--- /dev/null
+++ b/drivers/video/tdfxfb.c
@@ -0,0 +1,1366 @@
+/*
+ *
+ * tdfxfb.c
+ *
+ * Author: Hannu Mallat <hmallat@cc.hut.fi>
+ *
+ * Copyright © 1999 Hannu Mallat
+ * All rights reserved
+ *
+ * Created      : Thu Sep 23 18:17:43 1999, hmallat
+ * Last modified: Tue Nov  2 21:19:47 1999, hmallat
+ *
+ * Lots of the information here comes from the Daryll Strauss' Banshee 
+ * patches to the XF86 server, and the rest comes from the 3dfx
+ * Banshee specification. I'm very much indebted to Daryll for his
+ * work on the X server.
+ *
+ * Voodoo3 support was contributed Harold Oga. Lots of additions
+ * (proper acceleration, 24 bpp, hardware cursor) and bug fixes by Attila
+ * Kesmarki. Thanks guys!
+ *
+ * Voodoo1 and Voodoo2 support aren't relevant to this driver as they
+ * behave very differently from the Voodoo3/4/5. For anyone wanting to
+ * use frame buffer on the Voodoo1/2, see the sstfb driver (which is
+ * located at http://www.sourceforge.net/projects/sstfb).
+ * 
+ * While I _am_ grateful to 3Dfx for releasing the specs for Banshee,
+ * I do wish the next version is a bit more complete. Without the XF86
+ * patches I couldn't have gotten even this far... for instance, the
+ * extensions to the VGA register set go completely unmentioned in the
+ * spec! Also, lots of references are made to the 'SST core', but no
+ * spec is publicly available, AFAIK.
+ *
+ * The structure of this driver comes pretty much from the Permedia
+ * driver by Ilario Nardinocchi, which in turn is based on skeletonfb.
+ * 
+ * TODO:
+ * - support for 16/32 bpp needs fixing (funky bootup penguin)
+ * - multihead support (basically need to support an array of fb_infos)
+ * - support other architectures (PPC, Alpha); does the fact that the VGA
+ *   core can be accessed only thru I/O (not memory mapped) complicate
+ *   things?
+ *
+ * Version history:
+ *
+ * 0.1.4 (released 2002-05-28) ported over to new fbdev api by James Simmons
+ *
+ * 0.1.3 (released 1999-11-02) added Attila's panning support, code
+ *			       reorg, hwcursor address page size alignment
+ *                             (for mmaping both frame buffer and regs),
+ *                             and my changes to get rid of hardcoded
+ *                             VGA i/o register locations (uses PCI
+ *                             configuration info now)
+ * 0.1.2 (released 1999-10-19) added Attila Kesmarki's bug fixes and
+ *                             improvements
+ * 0.1.1 (released 1999-10-07) added Voodoo3 support by Harold Oga.
+ * 0.1.0 (released 1999-10-06) initial version
+ *
+ */
+
+#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/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/nvram.h>
+#include <asm/io.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+
+#include <video/tdfx.h>
+
+#undef TDFXFB_DEBUG 
+#ifdef TDFXFB_DEBUG
+#define DPRINTK(a,b...) printk(KERN_DEBUG "fb: %s: " a, __FUNCTION__ , ## b)
+#else
+#define DPRINTK(a,b...)
+#endif 
+
+#define BANSHEE_MAX_PIXCLOCK 270000
+#define VOODOO3_MAX_PIXCLOCK 300000
+#define VOODOO5_MAX_PIXCLOCK 350000
+
+static struct fb_fix_screeninfo tdfx_fix __devinitdata = {
+	.id =		"3Dfx",
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_PSEUDOCOLOR, 
+	.ypanstep =	1,
+	.ywrapstep =	1, 
+	.accel =	FB_ACCEL_3DFX_BANSHEE
+};
+
+static struct fb_var_screeninfo tdfx_var __devinitdata = {
+	/* "640x480, 8 bpp @ 60 Hz */
+	.xres =		640,
+	.yres =		480,
+	.xres_virtual =	640,
+	.yres_virtual =	1024,
+	.bits_per_pixel =8,
+	.red =		{0, 8, 0},
+	.blue =		{0, 8, 0},
+	.green =	{0, 8, 0},
+	.activate =	FB_ACTIVATE_NOW,
+	.height =	-1,
+	.width =	-1,
+	.accel_flags =	FB_ACCELF_TEXT,
+	.pixclock =	39722,
+	.left_margin =	40,
+	.right_margin =	24,
+	.upper_margin =	32,
+	.lower_margin =	11,
+	.hsync_len =	96,
+	.vsync_len =	2,
+	.vmode =	FB_VMODE_NONINTERLACED
+};
+
+/*
+ * PCI driver prototypes
+ */
+static int __devinit tdfxfb_probe(struct pci_dev *pdev,
+				  const struct pci_device_id *id);
+static void __devexit tdfxfb_remove(struct pci_dev *pdev);
+
+static struct pci_device_id tdfxfb_id_table[] = {
+	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE,
+	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
+	  0xff0000, 0 },
+	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3,
+	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
+	  0xff0000, 0 },
+	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO5,
+	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
+	  0xff0000, 0 },
+	{ 0, }
+};
+
+static struct pci_driver tdfxfb_driver = {
+	.name		= "tdfxfb",
+	.id_table 	= tdfxfb_id_table,
+	.probe 		= tdfxfb_probe,
+	.remove 	= __devexit_p(tdfxfb_remove),
+};
+
+MODULE_DEVICE_TABLE(pci, tdfxfb_id_table);
+
+/*
+ *  Frame buffer device API
+ */
+static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb); 
+static int tdfxfb_set_par(struct fb_info *info); 
+static int tdfxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 
+			    u_int transp, struct fb_info *info); 
+static int tdfxfb_blank(int blank, struct fb_info *info); 
+static int tdfxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
+static int banshee_wait_idle(struct fb_info *info);
+#ifdef CONFIG_FB_3DFX_ACCEL
+static void tdfxfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
+static void tdfxfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);  
+static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image); 
+#endif /* CONFIG_FB_3DFX_ACCEL */
+
+static struct fb_ops tdfxfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= tdfxfb_check_var,
+	.fb_set_par	= tdfxfb_set_par,
+	.fb_setcolreg	= tdfxfb_setcolreg,
+	.fb_blank	= tdfxfb_blank,
+	.fb_pan_display	= tdfxfb_pan_display,
+	.fb_sync	= banshee_wait_idle,
+#ifdef CONFIG_FB_3DFX_ACCEL
+	.fb_fillrect	= tdfxfb_fillrect,
+	.fb_copyarea	= tdfxfb_copyarea,
+	.fb_imageblit	= tdfxfb_imageblit,
+#else
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+#endif
+	.fb_cursor	= soft_cursor,
+};
+
+/*
+ * do_xxx: Hardware-specific functions
+ */
+static u32 do_calc_pll(int freq, int *freq_out);
+static void  do_write_regs(struct fb_info *info, struct banshee_reg *reg);
+static unsigned long do_lfb_size(struct tdfx_par *par, unsigned short);
+
+/*
+ * Driver data 
+ */
+static int  nopan   = 0;
+static int  nowrap  = 1;      // not implemented (yet)
+static char *mode_option __devinitdata = NULL;
+
+/* ------------------------------------------------------------------------- 
+ *                      Hardware-specific funcions
+ * ------------------------------------------------------------------------- */
+
+#ifdef VGA_REG_IO 
+static inline  u8 vga_inb(struct tdfx_par *par, u32 reg) { return inb(reg); }
+
+static inline void vga_outb(struct tdfx_par *par, u32 reg,  u8 val) { outb(val, reg); }
+#else
+static inline  u8 vga_inb(struct tdfx_par *par, u32 reg) { 
+	return inb(par->iobase + reg - 0x300); 
+}
+static inline void vga_outb(struct tdfx_par *par, u32 reg,  u8 val) { 
+	outb(val, par->iobase + reg - 0x300); 
+}
+#endif
+
+static inline void gra_outb(struct tdfx_par *par, u32 idx, u8 val) {
+	vga_outb(par, GRA_I, idx); vga_outb(par, GRA_D, val);
+}
+
+static inline void seq_outb(struct tdfx_par *par, u32 idx, u8 val) {
+	vga_outb(par, SEQ_I, idx); vga_outb(par, SEQ_D, val);
+}
+
+static inline u8 seq_inb(struct tdfx_par *par, u32 idx) {
+	vga_outb(par, SEQ_I, idx); return vga_inb(par, SEQ_D);
+}
+
+static inline void crt_outb(struct tdfx_par *par, u32 idx, u8 val) {
+	vga_outb(par, CRT_I, idx); vga_outb(par, CRT_D, val);
+}
+
+static inline u8 crt_inb(struct tdfx_par *par, u32 idx) {
+	vga_outb(par, CRT_I, idx); return vga_inb(par, CRT_D);
+}
+
+static inline void att_outb(struct tdfx_par *par, u32 idx, u8 val) 
+{
+	unsigned char tmp;
+	
+	tmp = vga_inb(par, IS1_R);
+	vga_outb(par, ATT_IW, idx);
+	vga_outb(par, ATT_IW, val);
+}
+
+static inline void vga_disable_video(struct tdfx_par *par)
+{
+	unsigned char s;
+
+	s = seq_inb(par, 0x01) | 0x20;
+	seq_outb(par, 0x00, 0x01);
+	seq_outb(par, 0x01, s);
+	seq_outb(par, 0x00, 0x03);
+}
+
+static inline void vga_enable_video(struct tdfx_par *par)
+{
+	unsigned char s;
+
+	s = seq_inb(par, 0x01) & 0xdf;
+	seq_outb(par, 0x00, 0x01);
+	seq_outb(par, 0x01, s);
+	seq_outb(par, 0x00, 0x03);
+}
+
+static inline void vga_enable_palette(struct tdfx_par *par)
+{
+	vga_inb(par, IS1_R);
+	vga_outb(par, ATT_IW, 0x20);
+}
+
+static inline u32 tdfx_inl(struct tdfx_par *par, unsigned int reg) 
+{
+	return readl(par->regbase_virt + reg);
+}
+
+static inline void tdfx_outl(struct tdfx_par *par, unsigned int reg, u32 val)
+{
+	writel(val, par->regbase_virt + reg);
+}
+
+static inline void banshee_make_room(struct tdfx_par *par, int size)
+{
+	/* Note: The Voodoo3's onboard FIFO has 32 slots. This loop
+	 * won't quit if you ask for more. */
+	while((tdfx_inl(par, STATUS) & 0x1f) < size-1);
+}
+ 
+static int banshee_wait_idle(struct fb_info *info)
+{
+	struct tdfx_par *par = (struct tdfx_par *) info->par; 
+	int i = 0;
+
+	banshee_make_room(par, 1);
+	tdfx_outl(par, COMMAND_3D, COMMAND_3D_NOP);
+
+	while(1) {
+		i = (tdfx_inl(par, STATUS) & STATUS_BUSY) ? 0 : i + 1;
+		if(i == 3) break;
+	}
+	return 0;
+}
+
+/*
+ * Set the color of a palette entry in 8bpp mode 
+ */
+static inline void do_setpalentry(struct tdfx_par *par, unsigned regno, u32 c)
+{  
+	banshee_make_room(par, 2);
+	tdfx_outl(par, DACADDR, regno);
+	tdfx_outl(par, DACDATA, c);
+}
+
+static u32 do_calc_pll(int freq, int* freq_out) 
+{
+	int m, n, k, best_m, best_n, best_k, f_cur, best_error;
+	int fref = 14318;
+  
+	/* this really could be done with more intelligence --
+	   255*63*4 = 64260 iterations is silly */
+	best_error = freq;
+	best_n = best_m = best_k = 0;
+	for (n = 1; n < 256; n++) {
+		for (m = 1; m < 64; m++) {
+			for (k = 0; k < 4; k++) {
+				f_cur = fref*(n + 2)/(m + 2)/(1 << k);
+				if (abs(f_cur - freq) < best_error) {
+					best_error = abs(f_cur-freq);
+					best_n = n;
+					best_m = m;
+					best_k = k;
+				}
+			}
+		}
+	}
+	n = best_n;
+	m = best_m;
+	k = best_k;
+	*freq_out = fref*(n + 2)/(m + 2)/(1 << k);
+	return (n << 8) | (m << 2) | k;
+}
+
+static void do_write_regs(struct fb_info *info, struct banshee_reg* reg) 
+{
+	struct tdfx_par *par = (struct tdfx_par *) info->par; 
+	int i;
+
+	banshee_wait_idle(info);
+
+	tdfx_outl(par, MISCINIT1, tdfx_inl(par, MISCINIT1) | 0x01);
+
+	crt_outb(par, 0x11, crt_inb(par, 0x11) & 0x7f); /* CRT unprotect */
+
+	banshee_make_room(par, 3);
+	tdfx_outl(par, VGAINIT1,	reg->vgainit1 &  0x001FFFFF);
+	tdfx_outl(par, VIDPROCCFG,	reg->vidcfg   & ~0x00000001);
+#if 0
+	tdfx_outl(par, PLLCTRL1, reg->mempll);
+	tdfx_outl(par, PLLCTRL2, reg->gfxpll);
+#endif
+	tdfx_outl(par, PLLCTRL0,	reg->vidpll);
+
+	vga_outb(par, MISC_W, reg->misc[0x00] | 0x01);
+
+	for (i = 0; i < 5; i++)
+		seq_outb(par, i, reg->seq[i]);
+
+	for (i = 0; i < 25; i++)
+		crt_outb(par, i, reg->crt[i]);
+
+	for (i = 0; i < 9; i++)
+		gra_outb(par, i, reg->gra[i]);
+
+	for (i = 0; i < 21; i++)
+		att_outb(par, i, reg->att[i]);
+
+	crt_outb(par, 0x1a, reg->ext[0]);
+	crt_outb(par, 0x1b, reg->ext[1]);
+
+	vga_enable_palette(par);
+	vga_enable_video(par);
+
+	banshee_make_room(par, 11);
+	tdfx_outl(par, 	VGAINIT0,      reg->vgainit0);
+	tdfx_outl(par,	DACMODE,       reg->dacmode);
+	tdfx_outl(par,	VIDDESKSTRIDE, reg->stride);
+	tdfx_outl(par,	HWCURPATADDR,  0);
+   
+	tdfx_outl(par,	VIDSCREENSIZE,reg->screensize);
+	tdfx_outl(par,	VIDDESKSTART,	reg->startaddr);
+	tdfx_outl(par,	VIDPROCCFG,	reg->vidcfg);
+	tdfx_outl(par,	VGAINIT1,	reg->vgainit1);  
+	tdfx_outl(par,	MISCINIT0,	reg->miscinit0);	
+
+	banshee_make_room(par,	8);
+	tdfx_outl(par,	SRCBASE,         reg->srcbase);
+	tdfx_outl(par,	DSTBASE,         reg->dstbase);
+	tdfx_outl(par,	COMMANDEXTRA_2D, 0);
+	tdfx_outl(par,	CLIP0MIN,        0);
+	tdfx_outl(par,	CLIP0MAX,        0x0fff0fff);
+	tdfx_outl(par,	CLIP1MIN,        0);
+	tdfx_outl(par,	CLIP1MAX,        0x0fff0fff);
+	tdfx_outl(par,	SRCXY,	   0);
+
+	banshee_wait_idle(info);
+}
+
+static unsigned long do_lfb_size(struct tdfx_par *par, unsigned short dev_id) 
+{
+	u32 draminit0 = 0;
+	u32 draminit1 = 0;
+	u32 miscinit1 = 0;
+	u32 lfbsize   = 0;
+	int sgram_p   = 0;
+
+	draminit0 = tdfx_inl(par, DRAMINIT0);  
+	draminit1 = tdfx_inl(par, DRAMINIT1);
+ 
+	if ((dev_id == PCI_DEVICE_ID_3DFX_BANSHEE) ||
+	    (dev_id == PCI_DEVICE_ID_3DFX_VOODOO3)) {             	 
+		sgram_p = (draminit1 & DRAMINIT1_MEM_SDRAM) ? 0 : 1;
+  
+	lfbsize = sgram_p ?
+		(((draminit0 & DRAMINIT0_SGRAM_NUM)  ? 2 : 1) * 
+		((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 8 : 4) * 1024 * 1024) :
+		16 * 1024 * 1024;
+	} else {
+		/* Voodoo4/5 */
+		u32 chips, psize, banks;
+
+		chips = ((draminit0 & (1 << 26)) == 0) ? 4 : 8;
+		psize = 1 << ((draminit0 & 0x38000000) >> 28);
+		banks = ((draminit0 & (1 << 30)) == 0) ? 2 : 4;
+		lfbsize = chips * psize * banks;
+		lfbsize <<= 20;
+	}                 
+	/* disable block writes for SDRAM (why?) */
+	miscinit1 = tdfx_inl(par, MISCINIT1);
+	miscinit1 |= sgram_p ? 0 : MISCINIT1_2DBLOCK_DIS;
+	miscinit1 |= MISCINIT1_CLUT_INV;
+
+	banshee_make_room(par, 1); 
+	tdfx_outl(par, MISCINIT1, miscinit1);
+	return lfbsize;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int tdfxfb_check_var(struct fb_var_screeninfo *var,struct fb_info *info) 
+{
+	struct tdfx_par *par = (struct tdfx_par *) info->par; 
+	u32 lpitch;
+
+	if (var->bits_per_pixel != 8  && var->bits_per_pixel != 16 &&
+	    var->bits_per_pixel != 24 && var->bits_per_pixel != 32) {
+		DPRINTK("depth not supported: %u\n", var->bits_per_pixel);
+		return -EINVAL;
+	}
+
+	if (var->xres != var->xres_virtual)
+		var->xres_virtual = var->xres;
+
+	if (var->yres > var->yres_virtual)
+		var->yres_virtual = var->yres;
+
+	if (var->xoffset) {
+		DPRINTK("xoffset not supported\n");
+		return -EINVAL;
+	}
+
+	/* Banshee doesn't support interlace, but Voodoo4/5 and probably Voodoo3 do. */
+	/* no direct information about device id now? use max_pixclock for this... */
+	if (((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) &&
+			(par->max_pixclock < VOODOO3_MAX_PIXCLOCK)) {
+		DPRINTK("interlace not supported\n");
+		return -EINVAL;
+	}
+
+	var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */
+	lpitch = var->xres * ((var->bits_per_pixel + 7)>>3);
+  
+	if (var->xres < 320 || var->xres > 2048) {
+		DPRINTK("width not supported: %u\n", var->xres);
+		return -EINVAL;
+	}
+  
+	if (var->yres < 200 || var->yres > 2048) {
+		DPRINTK("height not supported: %u\n", var->yres);
+		return -EINVAL;
+	}
+  
+	if (lpitch * var->yres_virtual > info->fix.smem_len) {
+		var->yres_virtual = info->fix.smem_len/lpitch;
+		if (var->yres_virtual < var->yres) {
+			DPRINTK("no memory for screen (%ux%ux%u)\n",
+			var->xres, var->yres_virtual, var->bits_per_pixel);
+			return -EINVAL;
+		}
+	}
+  
+	if (PICOS2KHZ(var->pixclock) > par->max_pixclock) {
+		DPRINTK("pixclock too high (%ldKHz)\n",PICOS2KHZ(var->pixclock));
+		return -EINVAL;
+	}
+
+	switch(var->bits_per_pixel) {
+		case 8:
+			var->red.length = var->green.length = var->blue.length = 8;
+			break;
+		case 16:
+			var->red.offset   = 11;
+			var->red.length   = 5;
+			var->green.offset = 5;
+			var->green.length = 6;
+			var->blue.offset  = 0;
+			var->blue.length  = 5;
+			break;
+		case 24:
+			var->red.offset=16;
+			var->green.offset=8;
+			var->blue.offset=0;
+			var->red.length = var->green.length = var->blue.length = 8;
+		case 32:
+			var->red.offset   = 16;
+			var->green.offset = 8;
+			var->blue.offset  = 0;
+			var->red.length = var->green.length = var->blue.length = 8;
+			break;
+	}
+	var->height = var->width = -1;
+  
+	var->accel_flags = FB_ACCELF_TEXT;
+	
+	DPRINTK("Checking graphics mode at %dx%d depth %d\n",  var->xres, var->yres, var->bits_per_pixel);
+	return 0;
+}
+
+static int tdfxfb_set_par(struct fb_info *info)
+{
+	struct tdfx_par *par = (struct tdfx_par *) info->par;	
+	u32 hdispend, hsyncsta, hsyncend, htotal;
+	u32 hd, hs, he, ht, hbs, hbe;
+	u32 vd, vs, ve, vt, vbs, vbe;
+	struct banshee_reg reg;
+	int fout, freq;
+	u32 wd, cpp;
+  
+	par->baseline  = 0;
+ 
+	memset(&reg, 0, sizeof(reg));
+	cpp = (info->var.bits_per_pixel + 7)/8;
+ 
+	reg.vidcfg = VIDCFG_VIDPROC_ENABLE | VIDCFG_DESK_ENABLE | VIDCFG_CURS_X11 | ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) | (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0);
+
+	/* PLL settings */
+	freq = PICOS2KHZ(info->var.pixclock);
+
+	reg.dacmode = 0;
+	reg.vidcfg  &= ~VIDCFG_2X;
+
+	hdispend = info->var.xres;
+	hsyncsta = hdispend + info->var.right_margin;
+	hsyncend = hsyncsta + info->var.hsync_len;
+	htotal   = hsyncend + info->var.left_margin;	
+
+	if (freq > par->max_pixclock/2) {
+		freq = freq > par->max_pixclock ? par->max_pixclock : freq;
+		reg.dacmode |= DACMODE_2X;
+		reg.vidcfg  |= VIDCFG_2X;
+		hdispend >>= 1;
+		hsyncsta >>= 1;
+		hsyncend >>= 1;
+		htotal   >>= 1;
+	}
+  
+	hd  = wd = (hdispend >> 3) - 1;
+	hs  = (hsyncsta >> 3) - 1;
+	he  = (hsyncend >> 3) - 1;
+	ht  = (htotal >> 3) - 1;
+	hbs = hd;
+	hbe = ht;
+
+	if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+		vbs = vd = (info->var.yres << 1) - 1;
+		vs  = vd + (info->var.lower_margin << 1);
+		ve  = vs + (info->var.vsync_len << 1);
+		vbe = vt = ve + (info->var.upper_margin << 1) - 1;
+	} else {
+		vbs = vd = info->var.yres - 1;
+		vs  = vd + info->var.lower_margin;
+		ve  = vs + info->var.vsync_len;
+		vbe = vt = ve + info->var.upper_margin - 1;
+	}
+  
+	/* this is all pretty standard VGA register stuffing */
+	reg.misc[0x00] = 0x0f | 
+			(info->var.xres < 400 ? 0xa0 :
+			 info->var.xres < 480 ? 0x60 :
+			 info->var.xres < 768 ? 0xe0 : 0x20);
+     
+	reg.gra[0x00] = 0x00;
+	reg.gra[0x01] = 0x00;
+	reg.gra[0x02] = 0x00;
+	reg.gra[0x03] = 0x00;
+	reg.gra[0x04] = 0x00;
+	reg.gra[0x05] = 0x40;
+	reg.gra[0x06] = 0x05;
+	reg.gra[0x07] = 0x0f;
+	reg.gra[0x08] = 0xff;
+
+	reg.att[0x00] = 0x00;
+	reg.att[0x01] = 0x01;
+	reg.att[0x02] = 0x02;
+	reg.att[0x03] = 0x03;
+	reg.att[0x04] = 0x04;
+	reg.att[0x05] = 0x05;
+	reg.att[0x06] = 0x06;
+	reg.att[0x07] = 0x07;
+	reg.att[0x08] = 0x08;
+	reg.att[0x09] = 0x09;
+	reg.att[0x0a] = 0x0a;
+	reg.att[0x0b] = 0x0b;
+	reg.att[0x0c] = 0x0c;
+	reg.att[0x0d] = 0x0d;
+	reg.att[0x0e] = 0x0e;
+	reg.att[0x0f] = 0x0f;
+	reg.att[0x10] = 0x41;
+	reg.att[0x11] = 0x00;
+	reg.att[0x12] = 0x0f;
+	reg.att[0x13] = 0x00;
+	reg.att[0x14] = 0x00;
+
+	reg.seq[0x00] = 0x03;
+	reg.seq[0x01] = 0x01; /* fixme: clkdiv2? */
+	reg.seq[0x02] = 0x0f;
+	reg.seq[0x03] = 0x00;
+	reg.seq[0x04] = 0x0e;
+
+	reg.crt[0x00] = ht - 4;
+	reg.crt[0x01] = hd;
+	reg.crt[0x02] = hbs;
+	reg.crt[0x03] = 0x80 | (hbe & 0x1f);
+	reg.crt[0x04] = hs;
+	reg.crt[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f); 
+	reg.crt[0x06] = vt;
+	reg.crt[0x07] = ((vs & 0x200) >> 2) |
+			((vd & 0x200) >> 3) |
+			((vt & 0x200) >> 4) | 0x10 |
+			((vbs & 0x100) >> 5) |
+			((vs  & 0x100) >> 6) |
+			((vd  & 0x100) >> 7) |
+			((vt  & 0x100) >> 8);
+	reg.crt[0x08] = 0x00;
+	reg.crt[0x09] = 0x40 | ((vbs & 0x200) >> 4); 
+	reg.crt[0x0a] = 0x00;
+	reg.crt[0x0b] = 0x00;
+	reg.crt[0x0c] = 0x00;
+	reg.crt[0x0d] = 0x00;
+	reg.crt[0x0e] = 0x00;
+	reg.crt[0x0f] = 0x00;
+	reg.crt[0x10] = vs;
+	reg.crt[0x11] = (ve & 0x0f) | 0x20; 
+	reg.crt[0x12] = vd;
+	reg.crt[0x13] = wd;
+	reg.crt[0x14] = 0x00;
+	reg.crt[0x15] = vbs;
+	reg.crt[0x16] = vbe + 1; 
+	reg.crt[0x17] = 0xc3;
+	reg.crt[0x18] = 0xff;
+ 
+	/* Banshee's nonvga stuff */
+	reg.ext[0x00] = (((ht  & 0x100) >> 8) | 
+			((hd  & 0x100) >> 6) |
+			((hbs & 0x100) >> 4) |
+			((hbe &  0x40) >> 1) |
+			((hs  & 0x100) >> 2) |
+			((he  &  0x20) << 2)); 
+	reg.ext[0x01] = (((vt  & 0x400) >> 10) |
+			((vd  & 0x400) >>  8) | 
+			((vbs & 0x400) >>  6) |
+			((vbe & 0x400) >>  4));
+
+	reg.vgainit0 = 	VGAINIT0_8BIT_DAC     |
+			VGAINIT0_EXT_ENABLE   |
+			VGAINIT0_WAKEUP_3C3   |
+			VGAINIT0_ALT_READBACK |
+			VGAINIT0_EXTSHIFTOUT;
+	reg.vgainit1 = tdfx_inl(par, VGAINIT1) & 0x1fffff;
+
+	reg.cursloc   = 0;
+   
+	reg.cursc0    = 0; 
+	reg.cursc1    = 0xffffff;
+   
+	reg.stride    = info->var.xres * cpp;
+	reg.startaddr = par->baseline * reg.stride;
+	reg.srcbase   = reg.startaddr;
+	reg.dstbase   = reg.startaddr;
+
+	/* PLL settings */
+	freq = PICOS2KHZ(info->var.pixclock);
+
+	reg.dacmode &= ~DACMODE_2X;
+	reg.vidcfg  &= ~VIDCFG_2X;
+	if (freq > par->max_pixclock/2) {
+		freq = freq > par->max_pixclock ? par->max_pixclock : freq;
+		reg.dacmode |= DACMODE_2X;
+		reg.vidcfg  |= VIDCFG_2X;
+	}
+	reg.vidpll = do_calc_pll(freq, &fout);
+#if 0
+	reg.mempll = do_calc_pll(..., &fout);
+	reg.gfxpll = do_calc_pll(..., &fout);
+#endif
+
+	if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+		reg.screensize = info->var.xres | (info->var.yres << 13);
+		reg.vidcfg |= VIDCFG_HALF_MODE;
+		reg.crt[0x09] |= 0x80;
+	} else {
+		reg.screensize = info->var.xres | (info->var.yres << 12);
+		reg.vidcfg &= ~VIDCFG_HALF_MODE;
+	}
+	if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
+		reg.vidcfg |= VIDCFG_INTERLACE;
+	reg.miscinit0 = tdfx_inl(par, MISCINIT0);
+
+#if defined(__BIG_ENDIAN)
+	switch (info->var.bits_per_pixel) {
+		case 8:
+		case 24:
+			reg.miscinit0 &= ~(1 << 30);
+			reg.miscinit0 &= ~(1 << 31);
+			break;
+		case 16:
+			reg.miscinit0 |= (1 << 30);
+			reg.miscinit0 |= (1 << 31);
+			break;
+		case 32:
+			reg.miscinit0 |= (1 << 30);
+			reg.miscinit0 &= ~(1 << 31);
+			break;
+	}
+#endif 
+	do_write_regs(info, &reg);
+
+	/* Now change fb_fix_screeninfo according to changes in par */
+	info->fix.line_length = info->var.xres * ((info->var.bits_per_pixel + 7)>>3);
+	info->fix.visual = (info->var.bits_per_pixel == 8) 
+				? FB_VISUAL_PSEUDOCOLOR
+				: FB_VISUAL_TRUECOLOR;
+	DPRINTK("Graphics mode is now set at %dx%d depth %d\n", info->var.xres, info->var.yres, info->var.bits_per_pixel);
+	return 0;	
+}
+
+/* A handy macro shamelessly pinched from matroxfb */
+#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+
+static int tdfxfb_setcolreg(unsigned regno, unsigned red, unsigned green,  
+			    unsigned blue,unsigned transp,struct fb_info *info) 
+{
+	struct tdfx_par *par = (struct tdfx_par *) info->par;
+	u32 rgbcol;
+   
+	if (regno >= info->cmap.len || regno > 255) return 1;
+   
+	switch (info->fix.visual) {
+		case FB_VISUAL_PSEUDOCOLOR:
+			rgbcol =(((u32)red   & 0xff00) << 8) |
+				(((u32)green & 0xff00) << 0) |
+				(((u32)blue  & 0xff00) >> 8);
+			do_setpalentry(par, regno, rgbcol);
+			break;
+		/* Truecolor has no hardware color palettes. */
+		case FB_VISUAL_TRUECOLOR:
+			rgbcol = (CNVT_TOHW( red, info->var.red.length) << info->var.red.offset) |
+				 (CNVT_TOHW( green, info->var.green.length) << info->var.green.offset) |
+				 (CNVT_TOHW( blue, info->var.blue.length) << info->var.blue.offset) |
+				 (CNVT_TOHW( transp, info->var.transp.length) << info->var.transp.offset);
+				((u32*)(info->pseudo_palette))[regno] = rgbcol;
+			break;
+		default:
+			DPRINTK("bad depth %u\n", info->var.bits_per_pixel);
+			break;
+	}
+	return 0;
+}
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+static int tdfxfb_blank(int blank, struct fb_info *info)
+{ 
+	struct tdfx_par *par = (struct tdfx_par *) info->par;
+	u32 dacmode, state = 0, vgablank = 0;
+
+	dacmode = tdfx_inl(par, DACMODE);
+
+	switch (blank) {
+		case FB_BLANK_UNBLANK: /* Screen: On; HSync: On, VSync: On */
+			state    = 0;
+			vgablank = 0;
+			break;
+		case FB_BLANK_NORMAL: /* Screen: Off; HSync: On, VSync: On */
+			state    = 0;
+			vgablank = 1;
+			break;
+		case FB_BLANK_VSYNC_SUSPEND: /* Screen: Off; HSync: On, VSync: Off */
+			state    = BIT(3);
+			vgablank = 1;
+			break;
+		case FB_BLANK_HSYNC_SUSPEND: /* Screen: Off; HSync: Off, VSync: On */
+			state    = BIT(1);
+			vgablank = 1;
+			break;
+		case FB_BLANK_POWERDOWN: /* Screen: Off; HSync: Off, VSync: Off */
+			state    = BIT(1) | BIT(3);
+			vgablank = 1;
+			break;
+	}
+
+	dacmode &= ~(BIT(1) | BIT(3));
+	dacmode |= state;
+	banshee_make_room(par, 1); 
+	tdfx_outl(par, DACMODE, dacmode);
+	if (vgablank) 
+		vga_disable_video(par);
+	else
+		vga_enable_video(par);
+	return 0;
+}
+
+/*   
+ * Set the starting position of the visible screen to var->yoffset
+ */   
+static int tdfxfb_pan_display(struct fb_var_screeninfo *var,
+			      struct fb_info *info) 
+{
+	struct tdfx_par *par = (struct tdfx_par *) info->par;
+	u32 addr;  	
+
+	if (nopan || var->xoffset || (var->yoffset > var->yres_virtual))
+		return -EINVAL;
+	if ((var->yoffset + var->yres > var->yres_virtual && nowrap))
+		return -EINVAL;
+
+	addr = var->yoffset * info->fix.line_length;
+	banshee_make_room(par, 1);
+	tdfx_outl(par, VIDDESKSTART, addr);
+   
+	info->var.xoffset = var->xoffset;
+	info->var.yoffset = var->yoffset; 
+	return 0;
+}
+
+#ifdef CONFIG_FB_3DFX_ACCEL
+/*
+ * FillRect 2D command (solidfill or invert (via ROP_XOR))   
+ */
+static void tdfxfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 
+{
+	struct tdfx_par *par = (struct tdfx_par *) info->par;
+	u32 bpp = info->var.bits_per_pixel;
+	u32 stride = info->fix.line_length;
+	u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13); 
+	int tdfx_rop;
+   	
+	if (rect->rop == ROP_COPY) 
+		tdfx_rop = TDFX_ROP_COPY;
+	else 			 
+		tdfx_rop = TDFX_ROP_XOR;
+
+	banshee_make_room(par, 5);
+	tdfx_outl(par,	DSTFORMAT, fmt);
+	if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) {
+		tdfx_outl(par,	COLORFORE, rect->color);
+	} else { /* FB_VISUAL_TRUECOLOR */
+		tdfx_outl(par, COLORFORE, ((u32*)(info->pseudo_palette))[rect->color]);
+	}
+	tdfx_outl(par,	COMMAND_2D, COMMAND_2D_FILLRECT | (tdfx_rop << 24));
+	tdfx_outl(par,	DSTSIZE,    rect->width | (rect->height << 16));
+	tdfx_outl(par,	LAUNCH_2D,  rect->dx | (rect->dy << 16));
+}
+
+/*
+ * Screen-to-Screen BitBlt 2D command (for the bmove fb op.) 
+ */
+static void tdfxfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)  
+{
+	struct tdfx_par *par = (struct tdfx_par *) info->par;
+   	u32 sx = area->sx, sy = area->sy, dx = area->dx, dy = area->dy;
+	u32 bpp = info->var.bits_per_pixel;
+	u32 stride = info->fix.line_length;
+	u32 blitcmd = COMMAND_2D_S2S_BITBLT | (TDFX_ROP_COPY << 24);
+	u32 fmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13); 
+	
+	if (area->sx <= area->dx) {
+		//-X 
+		blitcmd |= BIT(14);
+		sx += area->width - 1;
+		dx += area->width - 1;
+	}
+	if (area->sy <= area->dy) {
+		//-Y  
+		blitcmd |= BIT(15);
+		sy += area->height - 1;
+		dy += area->height - 1;
+	}
+   
+	banshee_make_room(par, 6);
+
+	tdfx_outl(par,	SRCFORMAT, fmt);
+	tdfx_outl(par,	DSTFORMAT, fmt);
+	tdfx_outl(par,	COMMAND_2D, blitcmd); 
+	tdfx_outl(par,	DSTSIZE,   area->width | (area->height << 16));
+	tdfx_outl(par,	DSTXY,     dx | (dy << 16));
+	tdfx_outl(par,	LAUNCH_2D, sx | (sy << 16)); 
+}
+
+static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image) 
+{
+	struct tdfx_par *par = (struct tdfx_par *) info->par;
+	int size = image->height * ((image->width * image->depth + 7)>>3);
+	int fifo_free;
+	int i, stride = info->fix.line_length;
+	u32 bpp = info->var.bits_per_pixel;
+	u32 dstfmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13); 
+	u8 *chardata = (u8 *) image->data;
+	u32 srcfmt;
+
+	if (image->depth != 1) {
+		//banshee_make_room(par, 6 + ((size + 3) >> 2));
+		//srcfmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13) | 0x400000;
+		cfb_imageblit(info, image);
+		return;
+	} else {
+		banshee_make_room(par, 8);
+		switch (info->fix.visual) {
+			case FB_VISUAL_PSEUDOCOLOR:
+		tdfx_outl(par, COLORFORE, image->fg_color);
+		tdfx_outl(par, COLORBACK, image->bg_color);
+				break;
+			case FB_VISUAL_TRUECOLOR:
+			default:
+				tdfx_outl(par, COLORFORE, ((u32*)(info->pseudo_palette))[image->fg_color]);
+				tdfx_outl(par, COLORBACK, ((u32*)(info->pseudo_palette))[image->bg_color]);
+		}
+#ifdef __BIG_ENDIAN
+		srcfmt = 0x400000 | BIT(20);
+#else
+		srcfmt = 0x400000;
+#endif
+	}	
+
+	tdfx_outl(par,	SRCXY,     0);
+	tdfx_outl(par,	DSTXY,     image->dx | (image->dy << 16));
+	tdfx_outl(par,	COMMAND_2D, COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24));
+	tdfx_outl(par,	SRCFORMAT, srcfmt);
+	tdfx_outl(par,	DSTFORMAT, dstfmt);
+	tdfx_outl(par,	DSTSIZE,   image->width | (image->height << 16));
+
+	/* A count of how many free FIFO entries we've requested.
+	 * When this goes negative, we need to request more. */
+	fifo_free = 0;
+
+	/* Send four bytes at a time of data */	
+	for (i = (size >> 2) ; i > 0; i--) { 
+		if(--fifo_free < 0) {
+			fifo_free=31;
+			banshee_make_room(par,fifo_free);
+		}
+		tdfx_outl(par,	LAUNCH_2D,*(u32*)chardata);
+		chardata += 4; 
+	}	
+
+	/* Send the leftovers now */	
+	banshee_make_room(par,3);
+	i = size%4;	
+	switch (i) {
+		case 0: break;
+		case 1:  tdfx_outl(par,	LAUNCH_2D,*chardata); break;
+		case 2:  tdfx_outl(par,	LAUNCH_2D,*(u16*)chardata); break;
+		case 3:  tdfx_outl(par,	LAUNCH_2D,*(u16*)chardata | ((chardata[3]) << 24)); break;
+	}
+}
+#endif /* CONFIG_FB_3DFX_ACCEL */
+
+#ifdef TDFX_HARDWARE_CURSOR
+static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+	struct tdfx_par *par = (struct tdfx_par *) info->par;
+	unsigned long flags;
+
+	/*
+	 * If the cursor is not be changed this means either we want the 
+	 * current cursor state (if enable is set) or we want to query what
+	 * we can do with the cursor (if enable is not set) 
+ 	 */
+	if (!cursor->set) return 0;
+
+	/* Too large of a cursor :-( */
+	if (cursor->image.width > 64 || cursor->image.height > 64)
+		return -ENXIO;
+
+	/* 
+	 * If we are going to be changing things we should disable
+	 * the cursor first 
+	 */
+	if (info->cursor.enable) {
+		spin_lock_irqsave(&par->DAClock, flags);
+		info->cursor.enable = 0;
+		del_timer(&(par->hwcursor.timer));
+		tdfx_outl(par, VIDPROCCFG, par->hwcursor.disable);
+		spin_unlock_irqrestore(&par->DAClock, flags);
+	}
+
+	/* Disable the Cursor */
+	if ((cursor->set && FB_CUR_SETCUR) && !cursor->enable)
+		return 0;
+
+	/* fix cursor color - XFree86 forgets to restore it properly */
+	if (cursor->set && FB_CUR_SETCMAP) {
+		struct fb_cmap cmap = cursor->image.cmap;
+		unsigned long bg_color, fg_color;
+
+		cmap.len = 2; /* Voodoo 3+ only support 2 color cursors */
+		fg_color = ((cmap.red[cmap.start] << 16) |
+			    (cmap.green[cmap.start] << 8)  |
+			    (cmap.blue[cmap.start]));
+		bg_color = ((cmap.red[cmap.start+1] << 16) |
+			    (cmap.green[cmap.start+1] << 8) |
+			    (cmap.blue[cmap.start+1]));
+		fb_copy_cmap(&cmap, &info->cursor.image.cmap);
+		spin_lock_irqsave(&par->DAClock, flags);
+		banshee_make_room(par, 2);
+		tdfx_outl(par, HWCURC0, bg_color);
+		tdfx_outl(par, HWCURC1, fg_color);
+		spin_unlock_irqrestore(&par->DAClock, flags);
+	}
+
+	if (cursor->set && FB_CUR_SETPOS) {
+		int x, y;
+
+		x = cursor->image.dx;
+		y = cursor->image.dy;
+		y -= info->var.yoffset;
+		info->cursor.image.dx = x;
+		info->cursor.image.dy = y;
+		x += 63;
+		y += 63;
+		spin_lock_irqsave(&par->DAClock, flags);
+		banshee_make_room(par, 1);
+		tdfx_outl(par, HWCURLOC, (y << 16) + x);
+		spin_unlock_irqrestore(&par->DAClock, flags);
+	}
+
+	/* Not supported so we fake it */
+	if (cursor->set && FB_CUR_SETHOT) {
+		info->cursor.hot.x = cursor->hot.x;
+		info->cursor.hot.y = cursor->hot.y;
+	}
+
+	if (cursor->set && FB_CUR_SETSHAPE) {
+		/*
+	 	 * Voodoo 3 and above cards use 2 monochrome cursor patterns.
+		 *    The reason is so the card can fetch 8 words at a time
+		 * and are stored on chip for use for the next 8 scanlines.
+		 * This reduces the number of times for access to draw the
+		 * cursor for each screen refresh.
+		 *    Each pattern is a bitmap of 64 bit wide and 64 bit high
+		 * (total of 8192 bits or 1024 Kbytes). The two patterns are
+		 * stored in such a way that pattern 0 always resides in the
+		 * lower half (least significant 64 bits) of a 128 bit word
+		 * and pattern 1 the upper half. If you examine the data of
+		 * the cursor image the graphics card uses then from the
+		 * begining you see line one of pattern 0, line one of
+		 * pattern 1, line two of pattern 0, line two of pattern 1,
+		 * etc etc. The linear stride for the cursor is always 16 bytes
+		 * (128 bits) which is the maximum cursor width times two for
+		 * the two monochrome patterns.
+		 */
+		u8 *cursorbase = (u8 *) info->cursor.image.data;
+		char *bitmap = (char *)cursor->image.data;
+		char *mask = (char *) cursor->mask;
+		int i, j, k, h = 0;
+
+		for (i = 0; i < 64; i++) {
+			if (i < cursor->image.height) {
+				j = (cursor->image.width + 7) >> 3;
+				k = 8 - j;
+
+				for (;j > 0; j--) {
+				/* Pattern 0. Copy the cursor bitmap to it */
+					fb_writeb(*bitmap, cursorbase + h);
+					bitmap++;
+				/* Pattern 1. Copy the cursor mask to it */
+					fb_writeb(*mask, cursorbase + h + 8);
+					mask++;
+					h++;
+				}
+				for (;k > 0; k--) {
+					fb_writeb(0, cursorbase + h);
+					fb_writeb(~0, cursorbase + h + 8);
+					h++;
+				}
+			} else {
+				fb_writel(0, cursorbase + h);
+				fb_writel(0, cursorbase + h + 4);
+				fb_writel(~0, cursorbase + h + 8);
+				fb_writel(~0, cursorbase + h + 12);
+				h += 16;
+			}
+		}
+	}
+	/* Turn the cursor on */
+	cursor->enable = 1;
+	info->cursor = *cursor;
+	mod_timer(&par->hwcursor.timer, jiffies+HZ/2);
+	spin_lock_irqsave(&par->DAClock, flags);
+	banshee_make_room(par, 1);
+	tdfx_outl(par, VIDPROCCFG, par->hwcursor.enable);
+	spin_unlock_irqrestore(&par->DAClock, flags);
+	return 0;
+}
+#endif
+
+/**
+ *      tdfxfb_probe - Device Initializiation
+ *
+ *      @pdev:  PCI Device to initialize
+ *      @id:    PCI Device ID
+ *
+ *      Initializes and allocates resources for PCI device @pdev.
+ *
+ */
+static int __devinit tdfxfb_probe(struct pci_dev *pdev,
+                                  const struct pci_device_id *id)
+{
+	struct tdfx_par *default_par;
+	struct fb_info *info;
+	int size, err, lpitch;
+
+	if ((err = pci_enable_device(pdev))) {
+		printk(KERN_WARNING "tdfxfb: Can't enable pdev: %d\n", err);
+		return err;
+	}
+
+	size = sizeof(struct tdfx_par)+256*sizeof(u32);
+
+	info = framebuffer_alloc(size, &pdev->dev);
+
+	if (!info)	return -ENOMEM;
+		
+	default_par = info->par;
+ 
+	/* Configure the default fb_fix_screeninfo first */
+	switch (pdev->device) {
+		case PCI_DEVICE_ID_3DFX_BANSHEE:	
+			strcat(tdfx_fix.id, " Banshee");
+			default_par->max_pixclock = BANSHEE_MAX_PIXCLOCK;
+			break;
+		case PCI_DEVICE_ID_3DFX_VOODOO3:
+			strcat(tdfx_fix.id, " Voodoo3");
+			default_par->max_pixclock = VOODOO3_MAX_PIXCLOCK;
+			break;
+		case PCI_DEVICE_ID_3DFX_VOODOO5:
+			strcat(tdfx_fix.id, " Voodoo5");
+			default_par->max_pixclock = VOODOO5_MAX_PIXCLOCK;
+			break;
+	}
+
+	tdfx_fix.mmio_start = pci_resource_start(pdev, 0);
+	tdfx_fix.mmio_len = pci_resource_len(pdev, 0);
+	default_par->regbase_virt = ioremap_nocache(tdfx_fix.mmio_start, tdfx_fix.mmio_len);
+	if (!default_par->regbase_virt) {
+		printk("fb: Can't remap %s register area.\n", tdfx_fix.id);
+		goto out_err;
+	}
+    
+	if (!request_mem_region(pci_resource_start(pdev, 0),
+	    pci_resource_len(pdev, 0), "tdfx regbase")) {
+		printk(KERN_WARNING "tdfxfb: Can't reserve regbase\n");
+		goto out_err;
+	} 
+
+	tdfx_fix.smem_start = pci_resource_start(pdev, 1);
+	if (!(tdfx_fix.smem_len = do_lfb_size(default_par, pdev->device))) {
+		printk("fb: Can't count %s memory.\n", tdfx_fix.id);
+		release_mem_region(pci_resource_start(pdev, 0),
+				   pci_resource_len(pdev, 0));
+		goto out_err;	
+	}
+
+	if (!request_mem_region(pci_resource_start(pdev, 1),
+	     pci_resource_len(pdev, 1), "tdfx smem")) {
+		printk(KERN_WARNING "tdfxfb: Can't reserve smem\n");
+		release_mem_region(pci_resource_start(pdev, 0),
+				   pci_resource_len(pdev, 0));
+		goto out_err;
+	}
+
+	info->screen_base = ioremap_nocache(tdfx_fix.smem_start, 
+					    tdfx_fix.smem_len);
+	if (!info->screen_base) {
+		printk("fb: Can't remap %s framebuffer.\n", tdfx_fix.id);
+		release_mem_region(pci_resource_start(pdev, 1),
+				   pci_resource_len(pdev, 1));
+		release_mem_region(pci_resource_start(pdev, 0),
+				   pci_resource_len(pdev, 0));
+		goto out_err;
+	}
+
+	default_par->iobase = pci_resource_start(pdev, 2);
+    
+	if (!request_region(pci_resource_start(pdev, 2),
+	    pci_resource_len(pdev, 2), "tdfx iobase")) {
+		printk(KERN_WARNING "tdfxfb: Can't reserve iobase\n");
+		release_mem_region(pci_resource_start(pdev, 1),
+				   pci_resource_len(pdev, 1));
+		release_mem_region(pci_resource_start(pdev, 0),
+				   pci_resource_len(pdev, 0));
+		goto out_err;
+	}
+
+	printk("fb: %s memory = %dK\n", tdfx_fix.id, tdfx_fix.smem_len >> 10);
+
+	tdfx_fix.ypanstep	= nopan ? 0 : 1;
+	tdfx_fix.ywrapstep	= nowrap ? 0 : 1;
+   
+	info->fbops		= &tdfxfb_ops;
+	info->fix		= tdfx_fix; 	
+	info->pseudo_palette	= (void *)(default_par + 1); 
+	info->flags		= FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+#ifdef CONFIG_FB_3DFX_ACCEL
+	info->flags             |= FBINFO_HWACCEL_FILLRECT |
+		FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_IMAGEBLIT;
+#endif
+
+	if (!mode_option)
+		mode_option = "640x480@60";
+	 
+	err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); 
+	if (!err || err == 4)
+		info->var = tdfx_var;
+
+	/* maximize virtual vertical length */
+	lpitch = info->var.xres_virtual * ((info->var.bits_per_pixel + 7) >> 3);
+	info->var.yres_virtual = info->fix.smem_len/lpitch;
+	if (info->var.yres_virtual < info->var.yres)
+		goto out_err;
+
+#ifdef CONFIG_FB_3DFX_ACCEL
+	/*
+	 * FIXME: Limit var->yres_virtual to 4096 because of screen artifacts
+	 * during scrolling. This is only present if 2D acceleration is
+	 * enabled.
+	 */
+	if (info->var.yres_virtual > 4096)
+		info->var.yres_virtual = 4096;
+#endif /* CONFIG_FB_3DFX_ACCEL */
+
+	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+		printk(KERN_WARNING "tdfxfb: Can't allocate color map\n");
+		goto out_err;
+	}
+
+	if (register_framebuffer(info) < 0) {
+		printk("tdfxfb: can't register framebuffer\n");
+		fb_dealloc_cmap(&info->cmap);
+		goto out_err;
+	}
+	/*
+	 * Our driver data
+	 */
+	pci_set_drvdata(pdev, info);
+	return 0; 
+
+out_err:
+	/*
+	 * Cleanup after anything that was remapped/allocated.
+	 */
+	if (default_par->regbase_virt)
+		iounmap(default_par->regbase_virt);
+	if (info->screen_base)
+		iounmap(info->screen_base);
+	framebuffer_release(info);
+	return -ENXIO;
+}
+
+#ifndef MODULE
+void tdfxfb_setup(char *options)
+{
+	char* this_opt;
+
+	if (!options || !*options)
+		return;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt)
+			continue;
+		if(!strcmp(this_opt, "nopan")) {
+			nopan = 1;
+		} else if(!strcmp(this_opt, "nowrap")) {
+			nowrap = 1;
+		} else {
+			mode_option = this_opt;
+		}
+	}
+}
+#endif
+
+/**
+ *      tdfxfb_remove - Device removal
+ *
+ *      @pdev:  PCI Device to cleanup
+ *
+ *      Releases all resources allocated during the course of the driver's
+ *      lifetime for the PCI device @pdev.
+ *
+ */
+static void __devexit tdfxfb_remove(struct pci_dev *pdev)
+{
+	struct fb_info *info = pci_get_drvdata(pdev);
+	struct tdfx_par *par = (struct tdfx_par *) info->par;
+
+	unregister_framebuffer(info);
+	iounmap(par->regbase_virt);
+	iounmap(info->screen_base);
+
+	/* Clean up after reserved regions */
+	release_region(pci_resource_start(pdev, 2),
+		       pci_resource_len(pdev, 2));
+	release_mem_region(pci_resource_start(pdev, 1),
+			   pci_resource_len(pdev, 1));
+	release_mem_region(pci_resource_start(pdev, 0),
+			   pci_resource_len(pdev, 0));
+	pci_set_drvdata(pdev, NULL);
+	framebuffer_release(info);
+}
+
+static int __init tdfxfb_init(void)
+{
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("tdfxfb", &option))
+		return -ENODEV;
+
+	tdfxfb_setup(option);
+#endif
+        return pci_register_driver(&tdfxfb_driver);
+}
+
+static void __exit tdfxfb_exit(void)
+{
+        pci_unregister_driver(&tdfxfb_driver);
+}
+
+MODULE_AUTHOR("Hannu Mallat <hmallat@cc.hut.fi>");
+MODULE_DESCRIPTION("3Dfx framebuffer device driver");
+MODULE_LICENSE("GPL");
+ 
+module_init(tdfxfb_init);
+module_exit(tdfxfb_exit);
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c
new file mode 100644
index 0000000..3099630
--- /dev/null
+++ b/drivers/video/tgafb.c
@@ -0,0 +1,1557 @@
+/*
+ *  linux/drivers/video/tgafb.c -- DEC 21030 TGA frame buffer device
+ *
+ *	Copyright (C) 1995 Jay Estabrook
+ *	Copyright (C) 1997 Geert Uytterhoeven
+ *	Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha
+ *	Copyright (C) 2002 Richard Henderson
+ *
+ *  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/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include <linux/selection.h>
+#include <asm/io.h>
+#include <video/tgafb.h>
+#include <linux/selection.h>
+
+/*
+ * Local functions.
+ */
+
+static int tgafb_check_var(struct fb_var_screeninfo *, struct fb_info *);
+static int tgafb_set_par(struct fb_info *);
+static void tgafb_set_pll(struct tga_par *, int);
+static int tgafb_setcolreg(unsigned, unsigned, unsigned, unsigned,
+			   unsigned, struct fb_info *);
+static int tgafb_blank(int, struct fb_info *);
+static void tgafb_init_fix(struct fb_info *);
+
+static void tgafb_imageblit(struct fb_info *, const struct fb_image *);
+static void tgafb_fillrect(struct fb_info *, const struct fb_fillrect *);
+static void tgafb_copyarea(struct fb_info *, const struct fb_copyarea *);
+
+static int tgafb_pci_register(struct pci_dev *, const struct pci_device_id *);
+#ifdef MODULE
+static void tgafb_pci_unregister(struct pci_dev *);
+#endif
+
+static const char *mode_option = "640x480@60";
+
+
+/*
+ *  Frame buffer operations
+ */
+
+static struct fb_ops tgafb_ops = {
+	.owner			= THIS_MODULE,
+	.fb_check_var		= tgafb_check_var,
+	.fb_set_par		= tgafb_set_par,
+	.fb_setcolreg		= tgafb_setcolreg,
+	.fb_blank		= tgafb_blank,
+	.fb_fillrect		= tgafb_fillrect,
+	.fb_copyarea		= tgafb_copyarea,
+	.fb_imageblit		= tgafb_imageblit,
+	.fb_cursor		= soft_cursor,
+};
+
+
+/*
+ *  PCI registration operations
+ */
+
+static struct pci_device_id const tgafb_pci_table[] = {
+	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA, PCI_ANY_ID, PCI_ANY_ID,
+	  0, 0, 0 }
+};
+
+static struct pci_driver tgafb_driver = {
+	.name			= "tgafb",
+	.id_table		= tgafb_pci_table,
+	.probe			= tgafb_pci_register,
+	.remove			= __devexit_p(tgafb_pci_unregister),
+};
+
+
+/**
+ *      tgafb_check_var - Optional function.  Validates a var passed in.
+ *      @var: frame buffer variable screen structure
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+tgafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct tga_par *par = (struct tga_par *)info->par;
+
+	if (par->tga_type == TGA_TYPE_8PLANE) {
+		if (var->bits_per_pixel != 8)
+			return -EINVAL;
+	} else {
+		if (var->bits_per_pixel != 32)
+			return -EINVAL;
+	}
+
+	if (var->xres_virtual != var->xres || var->yres_virtual != var->yres)
+		return -EINVAL;
+	if (var->nonstd)
+		return -EINVAL;
+	if (1000000000 / var->pixclock > TGA_PLL_MAX_FREQ)
+		return -EINVAL;
+	if ((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+		return -EINVAL;
+
+	/* Some of the acceleration routines assume the line width is
+	   a multiple of 64 bytes.  */
+	if (var->xres * (par->tga_type == TGA_TYPE_8PLANE ? 1 : 4) % 64)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ *      tgafb_set_par - Optional function.  Alters the hardware state.
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+tgafb_set_par(struct fb_info *info)
+{
+	static unsigned int const deep_presets[4] = {
+		0x00014000,
+		0x0001440d,
+		0xffffffff,
+		0x0001441d
+	};
+	static unsigned int const rasterop_presets[4] = {
+		0x00000003,
+		0x00000303,
+		0xffffffff,
+		0x00000303
+	};
+	static unsigned int const mode_presets[4] = {
+		0x00002000,
+		0x00002300,
+		0xffffffff,
+		0x00002300
+	};
+	static unsigned int const base_addr_presets[4] = {
+		0x00000000,
+		0x00000001,
+		0xffffffff,
+		0x00000001
+	};
+
+	struct tga_par *par = (struct tga_par *) info->par;
+	u32 htimings, vtimings, pll_freq;
+	u8 tga_type;
+	int i, j;
+
+	/* Encode video timings.  */
+	htimings = (((info->var.xres/4) & TGA_HORIZ_ACT_LSB)
+		    | (((info->var.xres/4) & 0x600 << 19) & TGA_HORIZ_ACT_MSB));
+	vtimings = (info->var.yres & TGA_VERT_ACTIVE);
+	htimings |= ((info->var.right_margin/4) << 9) & TGA_HORIZ_FP;
+	vtimings |= (info->var.lower_margin << 11) & TGA_VERT_FP;
+	htimings |= ((info->var.hsync_len/4) << 14) & TGA_HORIZ_SYNC;
+	vtimings |= (info->var.vsync_len << 16) & TGA_VERT_SYNC;
+	htimings |= ((info->var.left_margin/4) << 21) & TGA_HORIZ_BP;
+	vtimings |= (info->var.upper_margin << 22) & TGA_VERT_BP;
+
+	if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
+		htimings |= TGA_HORIZ_POLARITY;
+	if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
+		vtimings |= TGA_VERT_POLARITY;
+
+	par->htimings = htimings;
+	par->vtimings = vtimings;
+
+	par->sync_on_green = !!(info->var.sync & FB_SYNC_ON_GREEN);
+
+	/* Store other useful values in par.  */
+	par->xres = info->var.xres;
+	par->yres = info->var.yres;
+	par->pll_freq = pll_freq = 1000000000 / info->var.pixclock;
+	par->bits_per_pixel = info->var.bits_per_pixel;
+
+	tga_type = par->tga_type;
+
+	/* First, disable video.  */
+	TGA_WRITE_REG(par, TGA_VALID_VIDEO | TGA_VALID_BLANK, TGA_VALID_REG);
+
+	/* Write the DEEP register.  */
+	while (TGA_READ_REG(par, TGA_CMD_STAT_REG) & 1) /* wait for not busy */
+		continue;
+	mb();
+	TGA_WRITE_REG(par, deep_presets[tga_type], TGA_DEEP_REG);
+	while (TGA_READ_REG(par, TGA_CMD_STAT_REG) & 1) /* wait for not busy */
+		continue;
+	mb();
+
+	/* Write some more registers.  */
+	TGA_WRITE_REG(par, rasterop_presets[tga_type], TGA_RASTEROP_REG);
+	TGA_WRITE_REG(par, mode_presets[tga_type], TGA_MODE_REG);
+	TGA_WRITE_REG(par, base_addr_presets[tga_type], TGA_BASE_ADDR_REG);
+
+	/* Calculate & write the PLL.  */
+	tgafb_set_pll(par, pll_freq);
+
+	/* Write some more registers.  */
+	TGA_WRITE_REG(par, 0xffffffff, TGA_PLANEMASK_REG);
+	TGA_WRITE_REG(par, 0xffffffff, TGA_PIXELMASK_REG);
+
+	/* Init video timing regs.  */
+	TGA_WRITE_REG(par, htimings, TGA_HORIZ_REG);
+	TGA_WRITE_REG(par, vtimings, TGA_VERT_REG);
+
+	/* Initalise RAMDAC. */
+	if (tga_type == TGA_TYPE_8PLANE) {
+
+		/* Init BT485 RAMDAC registers.  */
+		BT485_WRITE(par, 0xa2 | (par->sync_on_green ? 0x8 : 0x0),
+			    BT485_CMD_0);
+		BT485_WRITE(par, 0x01, BT485_ADDR_PAL_WRITE);
+		BT485_WRITE(par, 0x14, BT485_CMD_3); /* cursor 64x64 */
+		BT485_WRITE(par, 0x40, BT485_CMD_1);
+		BT485_WRITE(par, 0x20, BT485_CMD_2); /* cursor off, for now */
+		BT485_WRITE(par, 0xff, BT485_PIXEL_MASK);
+
+		/* Fill palette registers.  */
+		BT485_WRITE(par, 0x00, BT485_ADDR_PAL_WRITE);
+		TGA_WRITE_REG(par, BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG);
+
+		for (i = 0; i < 16; i++) {
+			j = color_table[i];
+			TGA_WRITE_REG(par, default_red[j]|(BT485_DATA_PAL<<8),
+				      TGA_RAMDAC_REG);
+			TGA_WRITE_REG(par, default_grn[j]|(BT485_DATA_PAL<<8),
+				      TGA_RAMDAC_REG);
+			TGA_WRITE_REG(par, default_blu[j]|(BT485_DATA_PAL<<8),
+				      TGA_RAMDAC_REG);
+		}
+		for (i = 0; i < 240*3; i += 4) {
+			TGA_WRITE_REG(par, 0x55|(BT485_DATA_PAL<<8),
+				      TGA_RAMDAC_REG);
+			TGA_WRITE_REG(par, 0x00|(BT485_DATA_PAL<<8),
+				      TGA_RAMDAC_REG);
+			TGA_WRITE_REG(par, 0x00|(BT485_DATA_PAL<<8),
+				      TGA_RAMDAC_REG);
+			TGA_WRITE_REG(par, 0x00|(BT485_DATA_PAL<<8),
+				      TGA_RAMDAC_REG);
+		}
+
+	} else { /* 24-plane or 24plusZ */
+
+		/* Init BT463 registers.  */
+		BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_0, 0x40);
+		BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_1, 0x08);
+		BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_2,
+			    (par->sync_on_green ? 0x80 : 0x40));
+
+		BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_0, 0xff);
+		BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_1, 0xff);
+		BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_2, 0xff);
+		BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_3, 0x0f);
+
+		BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_0, 0x00);
+		BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_1, 0x00);
+		BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_2, 0x00);
+		BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_3, 0x00);
+
+		/* Fill the palette.  */
+		BT463_LOAD_ADDR(par, 0x0000);
+		TGA_WRITE_REG(par, BT463_PALETTE<<2, TGA_RAMDAC_REG);
+
+		for (i = 0; i < 16; i++) {
+			j = color_table[i];
+			TGA_WRITE_REG(par, default_red[j]|(BT463_PALETTE<<10),
+				      TGA_RAMDAC_REG);
+			TGA_WRITE_REG(par, default_grn[j]|(BT463_PALETTE<<10),
+				      TGA_RAMDAC_REG);
+			TGA_WRITE_REG(par, default_blu[j]|(BT463_PALETTE<<10),
+				      TGA_RAMDAC_REG);
+		}
+		for (i = 0; i < 512*3; i += 4) {
+			TGA_WRITE_REG(par, 0x55|(BT463_PALETTE<<10),
+				      TGA_RAMDAC_REG);
+			TGA_WRITE_REG(par, 0x00|(BT463_PALETTE<<10),
+				      TGA_RAMDAC_REG);
+			TGA_WRITE_REG(par, 0x00|(BT463_PALETTE<<10),
+				      TGA_RAMDAC_REG);
+			TGA_WRITE_REG(par, 0x00|(BT463_PALETTE<<10),
+				      TGA_RAMDAC_REG);
+		}
+
+		/* Fill window type table after start of vertical retrace.  */
+		while (!(TGA_READ_REG(par, TGA_INTR_STAT_REG) & 0x01))
+			continue;
+		TGA_WRITE_REG(par, 0x01, TGA_INTR_STAT_REG);
+		mb();
+		while (!(TGA_READ_REG(par, TGA_INTR_STAT_REG) & 0x01))
+			continue;
+		TGA_WRITE_REG(par, 0x01, TGA_INTR_STAT_REG);
+
+		BT463_LOAD_ADDR(par, BT463_WINDOW_TYPE_BASE);
+		TGA_WRITE_REG(par, BT463_REG_ACC<<2, TGA_RAMDAC_SETUP_REG);
+
+		for (i = 0; i < 16; i++) {
+			TGA_WRITE_REG(par, 0x00|(BT463_REG_ACC<<10),
+				      TGA_RAMDAC_REG);
+			TGA_WRITE_REG(par, 0x01|(BT463_REG_ACC<<10),
+				      TGA_RAMDAC_REG);
+			TGA_WRITE_REG(par, 0x80|(BT463_REG_ACC<<10),
+				      TGA_RAMDAC_REG);
+		}
+
+	}
+
+	/* Finally, enable video scan (and pray for the monitor... :-) */
+	TGA_WRITE_REG(par, TGA_VALID_VIDEO, TGA_VALID_REG);
+
+	return 0;
+}
+
+#define DIFFCHECK(X)							  \
+do {									  \
+	if (m <= 0x3f) {						  \
+		int delta = f - (TGA_PLL_BASE_FREQ * (X)) / (r << shift); \
+		if (delta < 0)						  \
+			delta = -delta;					  \
+		if (delta < min_diff)					  \
+			min_diff = delta, vm = m, va = a, vr = r;	  \
+	}								  \
+} while (0)
+
+static void
+tgafb_set_pll(struct tga_par *par, int f)
+{
+	int n, shift, base, min_diff, target;
+	int r,a,m,vm = 34, va = 1, vr = 30;
+
+	for (r = 0 ; r < 12 ; r++)
+		TGA_WRITE_REG(par, !r, TGA_CLOCK_REG);
+
+	if (f > TGA_PLL_MAX_FREQ)
+		f = TGA_PLL_MAX_FREQ;
+
+	if (f >= TGA_PLL_MAX_FREQ / 2)
+		shift = 0;
+	else if (f >= TGA_PLL_MAX_FREQ / 4)
+		shift = 1;
+	else
+		shift = 2;
+
+	TGA_WRITE_REG(par, shift & 1, TGA_CLOCK_REG);
+	TGA_WRITE_REG(par, shift >> 1, TGA_CLOCK_REG);
+
+	for (r = 0 ; r < 10 ; r++)
+		TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);
+
+	if (f <= 120000) {
+		TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);
+		TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);
+	}
+	else if (f <= 200000) {
+		TGA_WRITE_REG(par, 1, TGA_CLOCK_REG);
+		TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);
+	}
+	else {
+		TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);
+		TGA_WRITE_REG(par, 1, TGA_CLOCK_REG);
+	}
+
+	TGA_WRITE_REG(par, 1, TGA_CLOCK_REG);
+	TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);
+	TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);
+	TGA_WRITE_REG(par, 1, TGA_CLOCK_REG);
+	TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);
+	TGA_WRITE_REG(par, 1, TGA_CLOCK_REG);
+
+	target = (f << shift) / TGA_PLL_BASE_FREQ;
+	min_diff = TGA_PLL_MAX_FREQ;
+
+	r = 7 / target;
+	if (!r) r = 1;
+
+	base = target * r;
+	while (base < 449) {
+		for (n = base < 7 ? 7 : base; n < base + target && n < 449; n++) {
+			m = ((n + 3) / 7) - 1;
+			a = 0;
+			DIFFCHECK((m + 1) * 7);
+			m++;
+			DIFFCHECK((m + 1) * 7);
+			m = (n / 6) - 1;
+			if ((a = n % 6))
+				DIFFCHECK(n);
+		}
+		r++;
+		base += target;
+	}
+
+	vr--;
+
+	for (r = 0; r < 8; r++)
+		TGA_WRITE_REG(par, (vm >> r) & 1, TGA_CLOCK_REG);
+	for (r = 0; r < 8 ; r++)
+		TGA_WRITE_REG(par, (va >> r) & 1, TGA_CLOCK_REG);
+	for (r = 0; r < 7 ; r++)
+		TGA_WRITE_REG(par, (vr >> r) & 1, TGA_CLOCK_REG);
+	TGA_WRITE_REG(par, ((vr >> 7) & 1)|2, TGA_CLOCK_REG);
+}
+
+
+/**
+ *      tgafb_setcolreg - Optional function. Sets a color register.
+ *      @regno: boolean, 0 copy local, 1 get_user() function
+ *      @red: frame buffer colormap structure
+ *      @green: The green value which can be up to 16 bits wide
+ *      @blue:  The blue value which can be up to 16 bits wide.
+ *      @transp: If supported the alpha value which can be up to 16 bits wide.
+ *      @info: frame buffer info structure
+ */
+static int
+tgafb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
+		unsigned transp, struct fb_info *info)
+{
+	struct tga_par *par = (struct tga_par *) info->par;
+
+	if (regno > 255)
+		return 1;
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	if (par->tga_type == TGA_TYPE_8PLANE) {
+		BT485_WRITE(par, regno, BT485_ADDR_PAL_WRITE);
+		TGA_WRITE_REG(par, BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG);
+		TGA_WRITE_REG(par, red|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
+		TGA_WRITE_REG(par, green|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
+		TGA_WRITE_REG(par, blue|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
+	} else if (regno < 16) {
+		u32 value = (red << 16) | (green << 8) | blue;
+		((u32 *)info->pseudo_palette)[regno] = value;
+	}
+
+	return 0;
+}
+
+
+/**
+ *      tgafb_blank - Optional function.  Blanks the display.
+ *      @blank_mode: the blank mode we want.
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+tgafb_blank(int blank, struct fb_info *info)
+{
+	struct tga_par *par = (struct tga_par *) info->par;
+	u32 vhcr, vvcr, vvvr;
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	vhcr = TGA_READ_REG(par, TGA_HORIZ_REG);
+	vvcr = TGA_READ_REG(par, TGA_VERT_REG);
+	vvvr = TGA_READ_REG(par, TGA_VALID_REG);
+	vvvr &= ~(TGA_VALID_VIDEO | TGA_VALID_BLANK);
+
+	switch (blank) {
+	case FB_BLANK_UNBLANK: /* Unblanking */
+		if (par->vesa_blanked) {
+			TGA_WRITE_REG(par, vhcr & 0xbfffffff, TGA_HORIZ_REG);
+			TGA_WRITE_REG(par, vvcr & 0xbfffffff, TGA_VERT_REG);
+			par->vesa_blanked = 0;
+		}
+		TGA_WRITE_REG(par, vvvr | TGA_VALID_VIDEO, TGA_VALID_REG);
+		break;
+
+	case FB_BLANK_NORMAL: /* Normal blanking */
+		TGA_WRITE_REG(par, vvvr | TGA_VALID_VIDEO | TGA_VALID_BLANK,
+			      TGA_VALID_REG);
+		break;
+
+	case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
+		TGA_WRITE_REG(par, vvcr | 0x40000000, TGA_VERT_REG);
+		TGA_WRITE_REG(par, vvvr | TGA_VALID_BLANK, TGA_VALID_REG);
+		par->vesa_blanked = 1;
+		break;
+
+	case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
+		TGA_WRITE_REG(par, vhcr | 0x40000000, TGA_HORIZ_REG);
+		TGA_WRITE_REG(par, vvvr | TGA_VALID_BLANK, TGA_VALID_REG);
+		par->vesa_blanked = 1;
+		break;
+
+	case FB_BLANK_POWERDOWN: /* Poweroff */
+		TGA_WRITE_REG(par, vhcr | 0x40000000, TGA_HORIZ_REG);
+		TGA_WRITE_REG(par, vvcr | 0x40000000, TGA_VERT_REG);
+		TGA_WRITE_REG(par, vvvr | TGA_VALID_BLANK, TGA_VALID_REG);
+		par->vesa_blanked = 1;
+		break;
+	}
+
+	local_irq_restore(flags);
+	return 0;
+}
+
+
+/*
+ *  Acceleration.
+ */
+
+/**
+ *      tgafb_imageblit - REQUIRED function. Can use generic routines if
+ *                        non acclerated hardware and packed pixel based.
+ *                        Copies a image from system memory to the screen. 
+ *
+ *      @info: frame buffer structure that represents a single frame buffer
+ *      @image: structure defining the image.
+ */
+static void
+tgafb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	static unsigned char const bitrev[256] = {
+		0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+		0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+		0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+		0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+		0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+		0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+		0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+		0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+		0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+		0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+		0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+		0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+		0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+		0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+		0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+		0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+		0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+		0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+		0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+		0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+		0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+		0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+		0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+		0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+		0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+		0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+		0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+		0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+		0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+		0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+		0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+		0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+	};
+
+	struct tga_par *par = (struct tga_par *) info->par;
+	u32 fgcolor, bgcolor, dx, dy, width, height, vxres, vyres, pixelmask;
+	unsigned long rincr, line_length, shift, pos, is8bpp;
+	unsigned long i, j;
+	const unsigned char *data;
+	void __iomem *regs_base;
+	void __iomem *fb_base;
+
+	dx = image->dx;
+	dy = image->dy;
+	width = image->width;
+	height = image->height;
+	vxres = info->var.xres_virtual;
+	vyres = info->var.yres_virtual;
+	line_length = info->fix.line_length;
+	rincr = (width + 7) / 8;
+
+	/* Crop the image to the screen.  */
+	if (dx > vxres || dy > vyres)
+		return;
+	if (dx + width > vxres)
+		width = vxres - dx;
+	if (dy + height > vyres)
+		height = vyres - dy;
+
+	/* For copies that aren't pixel expansion, there's little we
+	   can do better than the generic code.  */
+	/* ??? There is a DMA write mode; I wonder if that could be
+	   made to pull the data from the image buffer...  */
+	if (image->depth > 1) {
+		cfb_imageblit(info, image);
+		return;
+	}
+
+	regs_base = par->tga_regs_base;
+	fb_base = par->tga_fb_base;
+	is8bpp = info->var.bits_per_pixel == 8;
+
+	/* Expand the color values to fill 32-bits.  */
+	/* ??? Would be nice to notice colour changes elsewhere, so
+	   that we can do this only when necessary.  */
+	fgcolor = image->fg_color;
+	bgcolor = image->bg_color;
+	if (is8bpp) {
+		fgcolor |= fgcolor << 8;
+		fgcolor |= fgcolor << 16;
+		bgcolor |= bgcolor << 8;
+		bgcolor |= bgcolor << 16;
+	} else {
+		if (fgcolor < 16)
+			fgcolor = ((u32 *)info->pseudo_palette)[fgcolor];
+		if (bgcolor < 16)
+			bgcolor = ((u32 *)info->pseudo_palette)[bgcolor];
+	}
+	__raw_writel(fgcolor, regs_base + TGA_FOREGROUND_REG);
+	__raw_writel(bgcolor, regs_base + TGA_BACKGROUND_REG);
+
+	/* Acquire proper alignment; set up the PIXELMASK register
+	   so that we only write the proper character cell.  */
+	pos = dy * line_length;
+	if (is8bpp) {
+		pos += dx;
+		shift = pos & 3;
+		pos &= -4;
+	} else {
+		pos += dx * 4;
+		shift = (pos & 7) >> 2;
+		pos &= -8;
+	}
+
+	data = (const unsigned char *) image->data;
+
+	/* Enable opaque stipple mode.  */
+	__raw_writel((is8bpp
+		      ? TGA_MODE_SBM_8BPP | TGA_MODE_OPAQUE_STIPPLE
+		      : TGA_MODE_SBM_24BPP | TGA_MODE_OPAQUE_STIPPLE),
+		     regs_base + TGA_MODE_REG);
+
+	if (width + shift <= 32) {
+		unsigned long bwidth;
+
+		/* Handle common case of imaging a single character, in
+		   a font less than 32 pixels wide.  */
+
+		pixelmask = (1 << width) - 1;
+		pixelmask <<= shift;
+		__raw_writel(pixelmask, regs_base + TGA_PIXELMASK_REG);
+		wmb();
+
+		bwidth = (width + 7) / 8;
+
+		for (i = 0; i < height; ++i) {
+			u32 mask = 0;
+
+			/* The image data is bit big endian; we need
+			   little endian.  */
+			for (j = 0; j < bwidth; ++j)
+				mask |= bitrev[data[j]] << (j * 8);
+
+			__raw_writel(mask << shift, fb_base + pos);
+
+			pos += line_length;
+			data += rincr;
+		}
+		wmb();
+		__raw_writel(0xffffffff, regs_base + TGA_PIXELMASK_REG);
+	} else if (shift == 0) {
+		unsigned long pos0 = pos;
+		const unsigned char *data0 = data;
+		unsigned long bincr = (is8bpp ? 8 : 8*4);
+		unsigned long bwidth;
+
+		/* Handle another common case in which accel_putcs
+		   generates a large bitmap, which happens to be aligned.
+		   Allow the tail to be misaligned.  This case is 
+		   interesting because we've not got to hold partial
+		   bytes across the words being written.  */
+
+		wmb();
+
+		bwidth = (width / 8) & -4;
+		for (i = 0; i < height; ++i) {
+			for (j = 0; j < bwidth; j += 4) {
+				u32 mask = 0;
+				mask |= bitrev[data[j+0]] << (0 * 8);
+				mask |= bitrev[data[j+1]] << (1 * 8);
+				mask |= bitrev[data[j+2]] << (2 * 8);
+				mask |= bitrev[data[j+3]] << (3 * 8);
+				__raw_writel(mask, fb_base + pos + j*bincr);
+			}
+			pos += line_length;
+			data += rincr;
+		}
+		wmb();
+
+		pixelmask = (1ul << (width & 31)) - 1;
+		if (pixelmask) {
+			__raw_writel(pixelmask, regs_base + TGA_PIXELMASK_REG);
+			wmb();
+
+			pos = pos0 + bwidth*bincr;
+			data = data0 + bwidth;
+			bwidth = ((width & 31) + 7) / 8;
+
+			for (i = 0; i < height; ++i) {
+				u32 mask = 0;
+				for (j = 0; j < bwidth; ++j)
+					mask |= bitrev[data[j]] << (j * 8);
+				__raw_writel(mask, fb_base + pos);
+				pos += line_length;
+				data += rincr;
+			}
+			wmb();
+			__raw_writel(0xffffffff, regs_base + TGA_PIXELMASK_REG);
+		}
+	} else {
+		unsigned long pos0 = pos;
+		const unsigned char *data0 = data;
+		unsigned long bincr = (is8bpp ? 8 : 8*4);
+		unsigned long bwidth;
+
+		/* Finally, handle the generic case of misaligned start.
+		   Here we split the write into 16-bit spans.  This allows
+		   us to use only one pixel mask, instead of four as would
+		   be required by writing 24-bit spans.  */
+
+		pixelmask = 0xffff << shift;
+		__raw_writel(pixelmask, regs_base + TGA_PIXELMASK_REG);
+		wmb();
+
+		bwidth = (width / 8) & -2;
+		for (i = 0; i < height; ++i) {
+			for (j = 0; j < bwidth; j += 2) {
+				u32 mask = 0;
+				mask |= bitrev[data[j+0]] << (0 * 8);
+				mask |= bitrev[data[j+1]] << (1 * 8);
+				mask <<= shift;
+				__raw_writel(mask, fb_base + pos + j*bincr);
+			}
+			pos += line_length;
+			data += rincr;
+		}
+		wmb();
+
+		pixelmask = ((1ul << (width & 15)) - 1) << shift;
+		if (pixelmask) {
+			__raw_writel(pixelmask, regs_base + TGA_PIXELMASK_REG);
+			wmb();
+
+			pos = pos0 + bwidth*bincr;
+			data = data0 + bwidth;
+			bwidth = (width & 15) > 8;
+
+			for (i = 0; i < height; ++i) {
+				u32 mask = bitrev[data[0]];
+				if (bwidth)
+					mask |= bitrev[data[1]] << 8;
+				mask <<= shift;
+				__raw_writel(mask, fb_base + pos);
+				pos += line_length;
+				data += rincr;
+			}
+			wmb();
+		}
+		__raw_writel(0xffffffff, regs_base + TGA_PIXELMASK_REG);
+	}
+
+	/* Disable opaque stipple mode.  */
+	__raw_writel((is8bpp
+		      ? TGA_MODE_SBM_8BPP | TGA_MODE_SIMPLE
+		      : TGA_MODE_SBM_24BPP | TGA_MODE_SIMPLE),
+		     regs_base + TGA_MODE_REG);
+}
+
+/**
+ *      tgafb_fillrect - REQUIRED function. Can use generic routines if 
+ *                       non acclerated hardware and packed pixel based.
+ *                       Draws a rectangle on the screen.               
+ *
+ *      @info: frame buffer structure that represents a single frame buffer
+ *      @rect: structure defining the rectagle and operation.
+ */
+static void
+tgafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+	struct tga_par *par = (struct tga_par *) info->par;
+	int is8bpp = info->var.bits_per_pixel == 8;
+	u32 dx, dy, width, height, vxres, vyres, color;
+	unsigned long pos, align, line_length, i, j;
+	void __iomem *regs_base;
+	void __iomem *fb_base;
+
+	dx = rect->dx;
+	dy = rect->dy;
+	width = rect->width;
+	height = rect->height;
+	vxres = info->var.xres_virtual;
+	vyres = info->var.yres_virtual;
+	line_length = info->fix.line_length;
+	regs_base = par->tga_regs_base;
+	fb_base = par->tga_fb_base;
+
+	/* Crop the rectangle to the screen.  */
+	if (dx > vxres || dy > vyres || !width || !height)
+		return;
+	if (dx + width > vxres)
+		width = vxres - dx;
+	if (dy + height > vyres)
+		height = vyres - dy;
+
+	pos = dy * line_length + dx * (is8bpp ? 1 : 4);
+
+	/* ??? We could implement ROP_XOR with opaque fill mode
+	   and a RasterOp setting of GXxor, but as far as I can
+	   tell, this mode is not actually used in the kernel.
+	   Thus I am ignoring it for now.  */
+	if (rect->rop != ROP_COPY) {
+		cfb_fillrect(info, rect);
+		return;
+	}
+
+	/* Expand the color value to fill 8 pixels.  */
+	color = rect->color;
+	if (is8bpp) {
+		color |= color << 8;
+		color |= color << 16;
+		__raw_writel(color, regs_base + TGA_BLOCK_COLOR0_REG);
+		__raw_writel(color, regs_base + TGA_BLOCK_COLOR1_REG);
+	} else {
+		if (color < 16)
+			color = ((u32 *)info->pseudo_palette)[color];
+		__raw_writel(color, regs_base + TGA_BLOCK_COLOR0_REG);
+		__raw_writel(color, regs_base + TGA_BLOCK_COLOR1_REG);
+		__raw_writel(color, regs_base + TGA_BLOCK_COLOR2_REG);
+		__raw_writel(color, regs_base + TGA_BLOCK_COLOR3_REG);
+		__raw_writel(color, regs_base + TGA_BLOCK_COLOR4_REG);
+		__raw_writel(color, regs_base + TGA_BLOCK_COLOR5_REG);
+		__raw_writel(color, regs_base + TGA_BLOCK_COLOR6_REG);
+		__raw_writel(color, regs_base + TGA_BLOCK_COLOR7_REG);
+	}
+
+	/* The DATA register holds the fill mask for block fill mode.
+	   Since we're not stippling, this is all ones.  */
+	__raw_writel(0xffffffff, regs_base + TGA_DATA_REG);
+
+	/* Enable block fill mode.  */
+	__raw_writel((is8bpp
+		      ? TGA_MODE_SBM_8BPP | TGA_MODE_BLOCK_FILL
+		      : TGA_MODE_SBM_24BPP | TGA_MODE_BLOCK_FILL),
+		     regs_base + TGA_MODE_REG);
+	wmb();
+
+	/* We can fill 2k pixels per operation.  Notice blocks that fit
+	   the width of the screen so that we can take advantage of this
+	   and fill more than one line per write.  */
+	if (width == line_length)
+		width *= height, height = 1;
+
+	/* The write into the frame buffer must be aligned to 4 bytes,
+	   but we are allowed to encode the offset within the word in
+	   the data word written.  */
+	align = (pos & 3) << 16;
+	pos &= -4;
+
+	if (width <= 2048) {
+		u32 data;
+
+		data = (width - 1) | align;
+
+		for (i = 0; i < height; ++i) {
+			__raw_writel(data, fb_base + pos);
+			pos += line_length;
+		}
+	} else {
+		unsigned long Bpp = (is8bpp ? 1 : 4);
+		unsigned long nwidth = width & -2048;
+		u32 fdata, ldata;
+
+		fdata = (2048 - 1) | align;
+		ldata = ((width & 2047) - 1) | align;
+
+		for (i = 0; i < height; ++i) {
+			for (j = 0; j < nwidth; j += 2048)
+				__raw_writel(fdata, fb_base + pos + j*Bpp);
+			if (j < width)
+				__raw_writel(ldata, fb_base + pos + j*Bpp);
+			pos += line_length;
+		}
+	}
+	wmb();
+
+	/* Disable block fill mode.  */
+	__raw_writel((is8bpp
+		      ? TGA_MODE_SBM_8BPP | TGA_MODE_SIMPLE
+		      : TGA_MODE_SBM_24BPP | TGA_MODE_SIMPLE),
+		     regs_base + TGA_MODE_REG);
+}
+
+/**
+ *      tgafb_copyarea - REQUIRED function. Can use generic routines if
+ *                       non acclerated hardware and packed pixel based.
+ *                       Copies on area of the screen to another area.
+ *
+ *      @info: frame buffer structure that represents a single frame buffer
+ *      @area: structure defining the source and destination.
+ */
+
+/* Handle the special case of copying entire lines, e.g. during scrolling.
+   We can avoid a lot of needless computation in this case.  In the 8bpp
+   case we need to use the COPY64 registers instead of mask writes into 
+   the frame buffer to achieve maximum performance.  */
+
+static inline void
+copyarea_line_8bpp(struct fb_info *info, u32 dy, u32 sy,
+		   u32 height, u32 width)
+{
+	struct tga_par *par = (struct tga_par *) info->par;
+	void __iomem *tga_regs = par->tga_regs_base;
+	unsigned long dpos, spos, i, n64;
+
+	/* Set up the MODE and PIXELSHIFT registers.  */
+	__raw_writel(TGA_MODE_SBM_8BPP | TGA_MODE_COPY, tga_regs+TGA_MODE_REG);
+	__raw_writel(0, tga_regs+TGA_PIXELSHIFT_REG);
+	wmb();
+
+	n64 = (height * width) / 64;
+
+	if (dy < sy) {
+		spos = (sy + height) * width;
+		dpos = (dy + height) * width;
+
+		for (i = 0; i < n64; ++i) {
+			spos -= 64;
+			dpos -= 64;
+			__raw_writel(spos, tga_regs+TGA_COPY64_SRC);
+			wmb();
+			__raw_writel(dpos, tga_regs+TGA_COPY64_DST);
+			wmb();
+		}
+	} else {
+		spos = sy * width;
+		dpos = dy * width;
+
+		for (i = 0; i < n64; ++i) {
+			__raw_writel(spos, tga_regs+TGA_COPY64_SRC);
+			wmb();
+			__raw_writel(dpos, tga_regs+TGA_COPY64_DST);
+			wmb();
+			spos += 64;
+			dpos += 64;
+		}
+	}
+
+	/* Reset the MODE register to normal.  */
+	__raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_SIMPLE, tga_regs+TGA_MODE_REG);
+}
+
+static inline void
+copyarea_line_32bpp(struct fb_info *info, u32 dy, u32 sy,
+		    u32 height, u32 width)
+{
+	struct tga_par *par = (struct tga_par *) info->par;
+	void __iomem *tga_regs = par->tga_regs_base;
+	void __iomem *tga_fb = par->tga_fb_base;
+	void __iomem *src;
+	void __iomem *dst;
+	unsigned long i, n16;
+
+	/* Set up the MODE and PIXELSHIFT registers.  */
+	__raw_writel(TGA_MODE_SBM_24BPP | TGA_MODE_COPY, tga_regs+TGA_MODE_REG);
+	__raw_writel(0, tga_regs+TGA_PIXELSHIFT_REG);
+	wmb();
+
+	n16 = (height * width) / 16;
+
+	if (dy < sy) {
+		src = tga_fb + (sy + height) * width * 4;
+		dst = tga_fb + (dy + height) * width * 4;
+
+		for (i = 0; i < n16; ++i) {
+			src -= 64;
+			dst -= 64;
+			__raw_writel(0xffff, src);
+			wmb();
+			__raw_writel(0xffff, dst);
+			wmb();
+		}
+	} else {
+		src = tga_fb + sy * width * 4;
+		dst = tga_fb + dy * width * 4;
+
+		for (i = 0; i < n16; ++i) {
+			__raw_writel(0xffff, src);
+			wmb();
+			__raw_writel(0xffff, dst);
+			wmb();
+			src += 64;
+			dst += 64;
+		}
+	}
+
+	/* Reset the MODE register to normal.  */
+	__raw_writel(TGA_MODE_SBM_24BPP|TGA_MODE_SIMPLE, tga_regs+TGA_MODE_REG);
+}
+
+/* The general case of forward copy in 8bpp mode.  */
+static inline void
+copyarea_foreward_8bpp(struct fb_info *info, u32 dx, u32 dy, u32 sx, u32 sy,
+		       u32 height, u32 width, u32 line_length)
+{
+	struct tga_par *par = (struct tga_par *) info->par;
+	unsigned long i, copied, left;
+	unsigned long dpos, spos, dalign, salign, yincr;
+	u32 smask_first, dmask_first, dmask_last;
+	int pixel_shift, need_prime, need_second;
+	unsigned long n64, n32, xincr_first;
+	void __iomem *tga_regs;
+	void __iomem *tga_fb;
+
+	yincr = line_length;
+	if (dy > sy) {
+		dy += height - 1;
+		sy += height - 1;
+		yincr = -yincr;
+	}
+
+	/* Compute the offsets and alignments in the frame buffer.
+	   More than anything else, these control how we do copies.  */
+	dpos = dy * line_length + dx;
+	spos = sy * line_length + sx;
+	dalign = dpos & 7;
+	salign = spos & 7;
+	dpos &= -8;
+	spos &= -8;
+
+	/* Compute the value for the PIXELSHIFT register.  This controls
+	   both non-co-aligned source and destination and copy direction.  */
+	if (dalign >= salign)
+		pixel_shift = dalign - salign;
+	else
+		pixel_shift = 8 - (salign - dalign);
+
+	/* Figure out if we need an additional priming step for the
+	   residue register.  */
+	need_prime = (salign > dalign);
+	if (need_prime)
+		dpos -= 8;
+
+	/* Begin by copying the leading unaligned destination.  Copy enough
+	   to make the next destination address 32-byte aligned.  */
+	copied = 32 - (dalign + (dpos & 31));
+	if (copied == 32)
+		copied = 0;
+	xincr_first = (copied + 7) & -8;
+	smask_first = dmask_first = (1ul << copied) - 1;
+	smask_first <<= salign;
+	dmask_first <<= dalign + need_prime*8;
+	if (need_prime && copied > 24)
+		copied -= 8;
+	left = width - copied;
+
+	/* Care for small copies.  */
+	if (copied > width) {
+		u32 t;
+		t = (1ul << width) - 1;
+		t <<= dalign + need_prime*8;
+		dmask_first &= t;
+		left = 0;
+	}
+
+	/* Attempt to use 64-byte copies.  This is only possible if the
+	   source and destination are co-aligned at 64 bytes.  */
+	n64 = need_second = 0;
+	if ((dpos & 63) == (spos & 63)
+	    && (height == 1 || line_length % 64 == 0)) {
+		/* We may need a 32-byte copy to ensure 64 byte alignment.  */
+		need_second = (dpos + xincr_first) & 63;
+		if ((need_second & 32) != need_second)
+			printk(KERN_ERR "tgafb: need_second wrong\n");
+		if (left >= need_second + 64) {
+			left -= need_second;
+			n64 = left / 64;
+			left %= 64;
+		} else
+			need_second = 0;
+	}
+
+	/* Copy trailing full 32-byte sections.  This will be the main
+	   loop if the 64 byte loop can't be used.  */
+	n32 = left / 32;
+	left %= 32;
+
+	/* Copy the trailing unaligned destination.  */
+	dmask_last = (1ul << left) - 1;
+
+	tga_regs = par->tga_regs_base;
+	tga_fb = par->tga_fb_base;
+
+	/* Set up the MODE and PIXELSHIFT registers.  */
+	__raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_COPY, tga_regs+TGA_MODE_REG);
+	__raw_writel(pixel_shift, tga_regs+TGA_PIXELSHIFT_REG);
+	wmb();
+
+	for (i = 0; i < height; ++i) {
+		unsigned long j;
+		void __iomem *sfb;
+		void __iomem *dfb;
+
+		sfb = tga_fb + spos;
+		dfb = tga_fb + dpos;
+		if (dmask_first) {
+			__raw_writel(smask_first, sfb);
+			wmb();
+			__raw_writel(dmask_first, dfb);
+			wmb();
+			sfb += xincr_first;
+			dfb += xincr_first;
+		}
+
+		if (need_second) {
+			__raw_writel(0xffffffff, sfb);
+			wmb();
+			__raw_writel(0xffffffff, dfb);
+			wmb();
+			sfb += 32;
+			dfb += 32;
+		}
+
+		if (n64 && (((unsigned long)sfb | (unsigned long)dfb) & 63))
+			printk(KERN_ERR
+			       "tgafb: misaligned copy64 (s:%p, d:%p)\n",
+			       sfb, dfb);
+
+		for (j = 0; j < n64; ++j) {
+			__raw_writel(sfb - tga_fb, tga_regs+TGA_COPY64_SRC);
+			wmb();
+			__raw_writel(dfb - tga_fb, tga_regs+TGA_COPY64_DST);
+			wmb();
+			sfb += 64;
+			dfb += 64;
+		}
+
+		for (j = 0; j < n32; ++j) {
+			__raw_writel(0xffffffff, sfb);
+			wmb();
+			__raw_writel(0xffffffff, dfb);
+			wmb();
+			sfb += 32;
+			dfb += 32;
+		}
+
+		if (dmask_last) {
+			__raw_writel(0xffffffff, sfb);
+			wmb();
+			__raw_writel(dmask_last, dfb);
+			wmb();
+		}
+
+		spos += yincr;
+		dpos += yincr;
+	}
+
+	/* Reset the MODE register to normal.  */
+	__raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_SIMPLE, tga_regs+TGA_MODE_REG);
+}
+
+/* The (almost) general case of backward copy in 8bpp mode.  */
+static inline void
+copyarea_backward_8bpp(struct fb_info *info, u32 dx, u32 dy, u32 sx, u32 sy,
+		       u32 height, u32 width, u32 line_length,
+		       const struct fb_copyarea *area)
+{
+	struct tga_par *par = (struct tga_par *) info->par;
+	unsigned long i, left, yincr;
+	unsigned long depos, sepos, dealign, sealign;
+	u32 mask_first, mask_last;
+	unsigned long n32;
+	void __iomem *tga_regs;
+	void __iomem *tga_fb;
+
+	yincr = line_length;
+	if (dy > sy) {
+		dy += height - 1;
+		sy += height - 1;
+		yincr = -yincr;
+	}
+
+	/* Compute the offsets and alignments in the frame buffer.
+	   More than anything else, these control how we do copies.  */
+	depos = dy * line_length + dx + width;
+	sepos = sy * line_length + sx + width;
+	dealign = depos & 7;
+	sealign = sepos & 7;
+
+	/* ??? The documentation appears to be incorrect (or very
+	   misleading) wrt how pixel shifting works in backward copy
+	   mode, i.e. when PIXELSHIFT is negative.  I give up for now.
+	   Do handle the common case of co-aligned backward copies,
+	   but frob everything else back on generic code.  */
+	if (dealign != sealign) {
+		cfb_copyarea(info, area);
+		return;
+	}
+
+	/* We begin the copy with the trailing pixels of the
+	   unaligned destination.  */
+	mask_first = (1ul << dealign) - 1;
+	left = width - dealign;
+
+	/* Care for small copies.  */
+	if (dealign > width) {
+		mask_first ^= (1ul << (dealign - width)) - 1;
+		left = 0;
+	}
+
+	/* Next copy full words at a time.  */
+	n32 = left / 32;
+	left %= 32;
+
+	/* Finally copy the unaligned head of the span.  */
+	mask_last = -1 << (32 - left);
+
+	tga_regs = par->tga_regs_base;
+	tga_fb = par->tga_fb_base;
+
+	/* Set up the MODE and PIXELSHIFT registers.  */
+	__raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_COPY, tga_regs+TGA_MODE_REG);
+	__raw_writel(0, tga_regs+TGA_PIXELSHIFT_REG);
+	wmb();
+
+	for (i = 0; i < height; ++i) {
+		unsigned long j;
+		void __iomem *sfb;
+		void __iomem *dfb;
+
+		sfb = tga_fb + sepos;
+		dfb = tga_fb + depos;
+		if (mask_first) {
+			__raw_writel(mask_first, sfb);
+			wmb();
+			__raw_writel(mask_first, dfb);
+			wmb();
+		}
+
+		for (j = 0; j < n32; ++j) {
+			sfb -= 32;
+			dfb -= 32;
+			__raw_writel(0xffffffff, sfb);
+			wmb();
+			__raw_writel(0xffffffff, dfb);
+			wmb();
+		}
+
+		if (mask_last) {
+			sfb -= 32;
+			dfb -= 32;
+			__raw_writel(mask_last, sfb);
+			wmb();
+			__raw_writel(mask_last, dfb);
+			wmb();
+		}
+
+		sepos += yincr;
+		depos += yincr;
+	}
+
+	/* Reset the MODE register to normal.  */
+	__raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_SIMPLE, tga_regs+TGA_MODE_REG);
+}
+
+static void
+tgafb_copyarea(struct fb_info *info, const struct fb_copyarea *area) 
+{
+	unsigned long dx, dy, width, height, sx, sy, vxres, vyres;
+	unsigned long line_length, bpp;
+
+	dx = area->dx;
+	dy = area->dy;
+	width = area->width;
+	height = area->height;
+	sx = area->sx;
+	sy = area->sy;
+	vxres = info->var.xres_virtual;
+	vyres = info->var.yres_virtual;
+	line_length = info->fix.line_length;
+
+	/* The top left corners must be in the virtual screen.  */
+	if (dx > vxres || sx > vxres || dy > vyres || sy > vyres)
+		return;
+
+	/* Clip the destination.  */
+	if (dx + width > vxres)
+		width = vxres - dx;
+	if (dy + height > vyres)
+		height = vyres - dy;
+
+	/* The source must be completely inside the virtual screen.  */
+	if (sx + width > vxres || sy + height > vyres)
+		return;
+
+	bpp = info->var.bits_per_pixel;
+
+	/* Detect copies of the entire line.  */
+	if (width * (bpp >> 3) == line_length) {
+		if (bpp == 8)
+			copyarea_line_8bpp(info, dy, sy, height, width);
+		else
+			copyarea_line_32bpp(info, dy, sy, height, width);
+	}
+
+	/* ??? The documentation is unclear to me exactly how the pixelshift
+	   register works in 32bpp mode.  Since I don't have hardware to test,
+	   give up for now and fall back on the generic routines.  */
+	else if (bpp == 32)
+		cfb_copyarea(info, area);
+
+	/* Detect overlapping source and destination that requires
+	   a backward copy.  */
+	else if (dy == sy && dx > sx && dx < sx + width)
+		copyarea_backward_8bpp(info, dx, dy, sx, sy, height,
+				       width, line_length, area);
+	else
+		copyarea_foreward_8bpp(info, dx, dy, sx, sy, height,
+				       width, line_length);
+}
+
+
+/*
+ *  Initialisation
+ */
+
+static void
+tgafb_init_fix(struct fb_info *info)
+{
+	struct tga_par *par = (struct tga_par *)info->par;
+	u8 tga_type = par->tga_type;
+	const char *tga_type_name;
+
+	switch (tga_type) {
+	case TGA_TYPE_8PLANE:
+		tga_type_name = "Digital ZLXp-E1";
+		break;
+	case TGA_TYPE_24PLANE:
+		tga_type_name = "Digital ZLXp-E2";
+		break;
+	case TGA_TYPE_24PLUSZ:
+		tga_type_name = "Digital ZLXp-E3";
+		break;
+	default:
+		tga_type_name = "Unknown";
+		break;
+	}
+
+	strlcpy(info->fix.id, tga_type_name, sizeof(info->fix.id));
+
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.type_aux = 0;
+	info->fix.visual = (tga_type == TGA_TYPE_8PLANE
+			    ? FB_VISUAL_PSEUDOCOLOR
+			    : FB_VISUAL_TRUECOLOR);
+
+	info->fix.line_length = par->xres * (par->bits_per_pixel >> 3);
+	info->fix.smem_start = (size_t) par->tga_fb_base;
+	info->fix.smem_len = info->fix.line_length * par->yres;
+	info->fix.mmio_start = (size_t) par->tga_regs_base;
+	info->fix.mmio_len = 512;
+
+	info->fix.xpanstep = 0;
+	info->fix.ypanstep = 0;
+	info->fix.ywrapstep = 0;
+
+	info->fix.accel = FB_ACCEL_DEC_TGA;
+}
+
+static __devinit int
+tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static unsigned int const fb_offset_presets[4] = {
+		TGA_8PLANE_FB_OFFSET,
+		TGA_24PLANE_FB_OFFSET,
+		0xffffffff,
+		TGA_24PLUSZ_FB_OFFSET
+	};
+
+	struct all_info {
+		struct fb_info info;
+		struct tga_par par;
+		u32 pseudo_palette[16];
+	} *all;
+
+	void __iomem *mem_base;
+	unsigned long bar0_start, bar0_len;
+	u8 tga_type;
+	int ret;
+
+	/* Enable device in PCI config.  */
+	if (pci_enable_device(pdev)) {
+		printk(KERN_ERR "tgafb: Cannot enable PCI device\n");
+		return -ENODEV;
+	}
+
+	/* Allocate the fb and par structures.  */
+	all = kmalloc(sizeof(*all), GFP_KERNEL);
+	if (!all) {
+		printk(KERN_ERR "tgafb: Cannot allocate memory\n");
+		return -ENOMEM;
+	}
+	memset(all, 0, sizeof(*all));
+	pci_set_drvdata(pdev, all);
+
+	/* Request the mem regions.  */
+	bar0_start = pci_resource_start(pdev, 0);
+	bar0_len = pci_resource_len(pdev, 0);
+	ret = -ENODEV;
+	if (!request_mem_region (bar0_start, bar0_len, "tgafb")) {
+		printk(KERN_ERR "tgafb: cannot reserve FB region\n");
+		goto err0;
+	}
+
+	/* Map the framebuffer.  */
+	mem_base = ioremap(bar0_start, bar0_len);
+	if (!mem_base) {
+		printk(KERN_ERR "tgafb: Cannot map MMIO\n");
+		goto err1;
+	}
+
+	/* Grab info about the card.  */
+	tga_type = (readl(mem_base) >> 12) & 0x0f;
+	all->par.pdev = pdev;
+	all->par.tga_mem_base = mem_base;
+	all->par.tga_fb_base = mem_base + fb_offset_presets[tga_type];
+	all->par.tga_regs_base = mem_base + TGA_REGS_OFFSET;
+	all->par.tga_type = tga_type;
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &all->par.tga_chip_rev);
+
+	/* Setup framebuffer.  */
+	all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA |
+                          FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT;
+	all->info.fbops = &tgafb_ops;
+	all->info.screen_base = all->par.tga_fb_base;
+	all->info.par = &all->par;
+	all->info.pseudo_palette = all->pseudo_palette;
+
+	/* This should give a reasonable default video mode.  */
+
+	ret = fb_find_mode(&all->info.var, &all->info, mode_option,
+			   NULL, 0, NULL,
+			   tga_type == TGA_TYPE_8PLANE ? 8 : 32);
+	if (ret == 0 || ret == 4) {
+		printk(KERN_ERR "tgafb: Could not find valid video mode\n");
+		ret = -EINVAL;
+		goto err1;
+	}
+
+	if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
+		printk(KERN_ERR "tgafb: Could not allocate color map\n");
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	tgafb_set_par(&all->info);
+	tgafb_init_fix(&all->info);
+
+	all->info.device = &pdev->dev;
+	if (register_framebuffer(&all->info) < 0) {
+		printk(KERN_ERR "tgafb: Could not register framebuffer\n");
+		ret = -EINVAL;
+		goto err1;
+	}
+
+	printk(KERN_INFO "tgafb: DC21030 [TGA] detected, rev=0x%02x\n",
+	       all->par.tga_chip_rev);
+	printk(KERN_INFO "tgafb: at PCI bus %d, device %d, function %d\n",
+	       pdev->bus->number, PCI_SLOT(pdev->devfn),
+	       PCI_FUNC(pdev->devfn));
+	printk(KERN_INFO "fb%d: %s frame buffer device at 0x%lx\n",
+	       all->info.node, all->info.fix.id, bar0_start);
+
+	return 0;
+
+ err1:
+	release_mem_region(bar0_start, bar0_len);
+ err0:
+	kfree(all);
+	return ret;
+}
+
+#ifdef MODULE
+static void __exit
+tgafb_pci_unregister(struct pci_dev *pdev)
+{
+	struct fb_info *info = pci_get_drvdata(pdev);
+	struct tga_par *par = info->par;
+
+	if (!info)
+		return;
+	unregister_framebuffer(info);
+	iounmap(par->tga_mem_base);
+	release_mem_region(pci_resource_start(pdev, 0),
+			   pci_resource_len(pdev, 0));
+	kfree(info);
+}
+
+static void __exit
+tgafb_exit(void)
+{
+	pci_unregister_driver(&tgafb_driver);
+}
+#endif /* MODULE */
+
+#ifndef MODULE
+int __init
+tgafb_setup(char *arg)
+{
+	char *this_opt;
+
+	if (arg && *arg) {
+		while ((this_opt = strsep(&arg, ","))) {
+			if (!*this_opt)
+				continue;
+			if (!strncmp(this_opt, "mode:", 5))
+				mode_option = this_opt+5;
+			else
+				printk(KERN_ERR
+				       "tgafb: unknown parameter %s\n",
+				       this_opt);
+		}
+	}
+
+	return 0;
+}
+#endif /* !MODULE */
+
+int __init
+tgafb_init(void)
+{
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("tgafb", &option))
+		return -ENODEV;
+	tgafb_setup(option);
+#endif
+	return pci_register_driver(&tgafb_driver);
+}
+
+/*
+ *  Modularisation
+ */
+
+module_init(tgafb_init);
+
+#ifdef MODULE
+module_exit(tgafb_exit);
+#endif
+
+MODULE_DESCRIPTION("framebuffer driver for TGA chipset");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c
new file mode 100644
index 0000000..da8004e
--- /dev/null
+++ b/drivers/video/tridentfb.c
@@ -0,0 +1,1294 @@
+/*
+ * Frame buffer driver for Trident Blade and Image series
+ *
+ * Copyright 2001,2002 - Jani Monoses   <jani@iv.ro>
+ *
+ *
+ * CREDITS:(in order of appearance)
+ * 	skeletonfb.c by Geert Uytterhoeven and other fb code in drivers/video
+ * 	Special thanks ;) to Mattia Crivellini <tia@mclink.it>
+ * 	much inspired by the XFree86 4.x Trident driver sources by Alan Hourihane
+ * 	the FreeVGA project
+ *	Francesco Salvestrini <salvestrini@users.sf.net> XP support,code,suggestions
+ * TODO:
+ * 	timing value tweaking so it looks good on every monitor in every mode
+ *	TGUI acceleration	
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <linux/delay.h>
+#include <video/trident.h>
+
+#define VERSION		"0.7.8-NEWAPI"
+
+struct tridentfb_par {
+	int vclk;		//in MHz
+	void __iomem * io_virt;	//iospace virtual memory address
+};
+
+static unsigned char eng_oper;		//engine operation...
+static struct fb_ops tridentfb_ops;
+
+static struct tridentfb_par default_par;
+
+/* FIXME:kmalloc these 3 instead */
+static struct fb_info fb_info;
+static u32 pseudo_pal[16];
+
+
+static struct fb_var_screeninfo default_var;
+
+static struct fb_fix_screeninfo tridentfb_fix = {
+	.id = "Trident",	
+	.type = FB_TYPE_PACKED_PIXELS,
+	.ypanstep = 1,
+	.visual = FB_VISUAL_PSEUDOCOLOR,
+	.accel = FB_ACCEL_NONE,
+};
+
+static int chip_id;
+
+static int defaultaccel;
+static int displaytype;
+
+
+/* defaults which are normally overriden by user values */
+
+/* video mode */
+static char * mode = "640x480";
+static int bpp = 8;
+
+static int noaccel;
+
+static int center;
+static int stretch;
+
+static int fp;
+static int crt;
+
+static int memsize;
+static int memdiff;
+static int nativex;
+
+
+module_param(mode, charp, 0);
+module_param(bpp, int, 0);
+module_param(center, int, 0);
+module_param(stretch, int, 0);
+module_param(noaccel, int, 0);
+module_param(memsize, int, 0);
+module_param(memdiff, int, 0);
+module_param(nativex, int, 0);
+module_param(fp, int, 0);
+module_param(crt, int, 0);
+
+
+static int chip3D;
+static int chipcyber;
+
+static int is3Dchip(int id)
+{
+	return 	((id == BLADE3D) || (id == CYBERBLADEE4) ||
+		 (id == CYBERBLADEi7) || (id == CYBERBLADEi7D) ||
+		 (id == CYBER9397) || (id == CYBER9397DVD) ||
+		 (id == CYBER9520) || (id == CYBER9525DVD) ||
+		 (id == IMAGE975) || (id == IMAGE985) ||
+		 (id == CYBERBLADEi1) || (id == CYBERBLADEi1D) ||
+		 (id ==	CYBERBLADEAi1) || (id == CYBERBLADEAi1D) ||
+		 (id ==	CYBERBLADEXPm8) || (id == CYBERBLADEXPm16) ||
+		 (id ==	CYBERBLADEXPAi1));
+}
+
+static int iscyber(int id)
+{
+	switch (id) {
+		case CYBER9388:		
+		case CYBER9382:
+		case CYBER9385:
+		case CYBER9397:
+		case CYBER9397DVD:
+		case CYBER9520:
+		case CYBER9525DVD:
+		case CYBERBLADEE4:
+		case CYBERBLADEi7D:
+		case CYBERBLADEi1:
+		case CYBERBLADEi1D: 
+		case CYBERBLADEAi1: 
+		case CYBERBLADEAi1D:
+		case CYBERBLADEXPAi1:
+			return 1;
+		
+		case CYBER9320:
+		case TGUI9660:     
+		case IMAGE975:
+		case IMAGE985:
+		case BLADE3D:
+		case CYBERBLADEi7: /* VIA MPV4 integrated version */
+
+		default:
+			/* case CYBERBLDAEXPm8:	 Strange */
+			/* case CYBERBLDAEXPm16: Strange */
+			return 0;
+	}
+}
+
+#define CRT 0x3D0		//CRTC registers offset for color display
+
+#ifndef TRIDENT_MMIO
+	#define TRIDENT_MMIO 1
+#endif
+
+#if TRIDENT_MMIO
+	#define t_outb(val,reg)	writeb(val,((struct tridentfb_par *)(fb_info.par))->io_virt + reg)
+	#define t_inb(reg)	readb(((struct tridentfb_par*)(fb_info.par))->io_virt + reg)
+#else
+	#define t_outb(val,reg) outb(val,reg)
+	#define t_inb(reg) inb(reg)
+#endif
+
+
+static struct accel_switch {
+	void (*init_accel)(int,int);
+	void (*wait_engine)(void);
+	void (*fill_rect)(__u32,__u32,__u32,__u32,__u32,__u32);
+	void (*copy_rect)(__u32,__u32,__u32,__u32,__u32,__u32);
+} *acc;
+
+#define writemmr(r,v)	writel(v, ((struct tridentfb_par *)fb_info.par)->io_virt + r)
+#define readmmr(r)	readl(((struct tridentfb_par *)fb_info.par)->io_virt + r)
+
+
+
+/*
+ * Blade specific acceleration.
+ */
+
+#define point(x,y) ((y)<<16|(x))
+#define STA	0x2120
+#define CMD	0x2144
+#define ROP	0x2148
+#define CLR	0x2160
+#define SR1	0x2100
+#define SR2	0x2104
+#define DR1	0x2108
+#define DR2	0x210C
+
+#define ROP_S	0xCC
+
+static void blade_init_accel(int pitch,int bpp)
+{
+	int v1 = (pitch>>3)<<20;
+	int tmp = 0,v2;
+	switch (bpp) {
+		case 8:tmp = 0;break;
+		case 15:tmp = 5;break;
+		case 16:tmp = 1;break;
+		case 24:
+		case 32:tmp = 2;break;
+	}
+	v2 = v1 | (tmp<<29);
+	writemmr(0x21C0,v2);
+	writemmr(0x21C4,v2);
+	writemmr(0x21B8,v2);
+	writemmr(0x21BC,v2);
+	writemmr(0x21D0,v1);
+	writemmr(0x21D4,v1);
+	writemmr(0x21C8,v1);
+	writemmr(0x21CC,v1);
+	writemmr(0x216C,0);
+}
+
+static void blade_wait_engine(void)
+{
+	while(readmmr(STA) & 0xFA800000);
+}
+
+static void blade_fill_rect(__u32 x,__u32 y,__u32 w,__u32 h,__u32 c,__u32 rop)
+{
+	writemmr(CLR,c);
+	writemmr(ROP,rop ? 0x66:ROP_S);
+	writemmr(CMD,0x20000000|1<<19|1<<4|2<<2);
+
+	writemmr(DR1,point(x,y));
+	writemmr(DR2,point(x+w-1,y+h-1));
+}
+
+static void blade_copy_rect(__u32 x1,__u32 y1,__u32 x2,__u32 y2,__u32 w,__u32 h)
+{
+	__u32 s1,s2,d1,d2;
+	int direction = 2;
+	s1 = point(x1,y1);
+	s2 = point(x1+w-1,y1+h-1);
+	d1 = point(x2,y2);
+	d2 = point(x2+w-1,y2+h-1);
+
+	if ((y1 > y2) || ((y1 == y2) && (x1 > x2)))
+			direction = 0;
+
+
+	writemmr(ROP,ROP_S);
+	writemmr(CMD,0xE0000000|1<<19|1<<4|1<<2|direction);
+
+	writemmr(SR1,direction?s2:s1);
+	writemmr(SR2,direction?s1:s2);
+	writemmr(DR1,direction?d2:d1);
+	writemmr(DR2,direction?d1:d2);
+}
+
+static struct accel_switch accel_blade = {
+	blade_init_accel,
+	blade_wait_engine,
+	blade_fill_rect,
+	blade_copy_rect,
+};
+
+
+/*
+ * BladeXP specific acceleration functions
+ */
+
+#define ROP_P 0xF0
+#define masked_point(x,y) ((y & 0xffff)<<16|(x & 0xffff))
+
+static void xp_init_accel(int pitch,int bpp)
+{
+	int tmp = 0,v1;
+	unsigned char x = 0;
+
+	switch (bpp) {
+		case 8:  x = 0; break;
+		case 16: x = 1; break;
+		case 24: x = 3; break;
+		case 32: x = 2; break;
+	}
+
+	switch (pitch << (bpp >> 3)) {
+		case 8192:
+		case 512:  x |= 0x00; break;
+		case 1024: x |= 0x04; break;
+		case 2048: x |= 0x08; break;
+		case 4096: x |= 0x0C; break;
+	}
+
+	t_outb(x,0x2125);
+
+	eng_oper = x | 0x40;
+
+	switch (bpp) {
+		case 8:  tmp = 18; break;
+		case 15:
+		case 16: tmp = 19; break;
+		case 24:
+		case 32: tmp = 20; break;
+	}
+
+	v1 = pitch << tmp;
+
+	writemmr(0x2154,v1);
+	writemmr(0x2150,v1);
+	t_outb(3,0x2126);
+}
+
+static void xp_wait_engine(void)
+{
+	int busy;
+	int count, timeout;
+
+	count = 0;
+	timeout = 0;
+	for (;;) {
+		busy = t_inb(STA) & 0x80;
+		if (busy != 0x80)
+			return;
+		count++;
+		if (count == 10000000) {
+			/* Timeout */
+			count = 9990000;
+			timeout++;
+			if (timeout == 8) {
+				/* Reset engine */
+				t_outb(0x00, 0x2120);
+				return;
+			}
+		}
+	}
+}
+
+static void xp_fill_rect(__u32 x,__u32 y,__u32 w,__u32 h,__u32 c,__u32 rop)
+{
+	writemmr(0x2127,ROP_P);
+	writemmr(0x2158,c);
+	writemmr(0x2128,0x4000);
+	writemmr(0x2140,masked_point(h,w));
+	writemmr(0x2138,masked_point(y,x));
+	t_outb(0x01,0x2124);
+        t_outb(eng_oper,0x2125);
+}
+
+static void xp_copy_rect(__u32 x1,__u32 y1,__u32 x2,__u32 y2,__u32 w,__u32 h)
+{
+	int direction;
+	__u32 x1_tmp, x2_tmp, y1_tmp, y2_tmp;
+
+	direction = 0x0004;
+	
+	if ((x1 < x2) && (y1 == y2)) {
+		direction |= 0x0200;
+		x1_tmp = x1 + w - 1;
+		x2_tmp = x2 + w - 1;
+	} else {
+		x1_tmp = x1;
+		x2_tmp = x2;
+	}
+  
+	if (y1 < y2) {
+		direction |= 0x0100;
+		y1_tmp = y1 + h - 1;
+		y2_tmp = y2 + h - 1;
+  	} else {
+		y1_tmp = y1;
+		y2_tmp = y2;
+	}
+
+	writemmr(0x2128,direction);	
+	t_outb(ROP_S,0x2127);
+	writemmr(0x213C,masked_point(y1_tmp,x1_tmp));
+	writemmr(0x2138,masked_point(y2_tmp,x2_tmp));
+	writemmr(0x2140,masked_point(h,w));
+	t_outb(0x01,0x2124);
+}
+
+static struct accel_switch accel_xp = {
+  	xp_init_accel,
+	xp_wait_engine,
+	xp_fill_rect,
+	xp_copy_rect,
+};
+
+
+/*
+ * Image specific acceleration functions
+ */
+static void image_init_accel(int pitch,int bpp)
+{
+	int tmp = 0;
+   	switch (bpp) {
+		case 8:tmp = 0;break;
+		case 15:tmp = 5;break;
+		case 16:tmp = 1;break;
+		case 24:
+		case 32:tmp = 2;break;
+	}
+	writemmr(0x2120, 0xF0000000);
+	writemmr(0x2120, 0x40000000|tmp);
+	writemmr(0x2120, 0x80000000);
+	writemmr(0x2144, 0x00000000);
+	writemmr(0x2148, 0x00000000);
+	writemmr(0x2150, 0x00000000);
+	writemmr(0x2154, 0x00000000);
+	writemmr(0x2120, 0x60000000|(pitch<<16) |pitch);
+	writemmr(0x216C, 0x00000000);
+	writemmr(0x2170, 0x00000000);
+	writemmr(0x217C, 0x00000000);
+	writemmr(0x2120, 0x10000000);
+	writemmr(0x2130, (2047 << 16) | 2047);
+}
+
+static void image_wait_engine(void)
+{
+	while(readmmr(0x2164) & 0xF0000000);
+}
+
+static void image_fill_rect(__u32 x, __u32 y, __u32 w, __u32 h, __u32 c, __u32 rop)
+{
+	writemmr(0x2120,0x80000000);
+	writemmr(0x2120,0x90000000|ROP_S);
+
+	writemmr(0x2144,c);
+
+	writemmr(DR1,point(x,y));
+	writemmr(DR2,point(x+w-1,y+h-1));
+
+	writemmr(0x2124,0x80000000|3<<22|1<<10|1<<9);
+}
+
+static void image_copy_rect(__u32 x1,__u32 y1,__u32 x2,__u32 y2,__u32 w,__u32 h)
+{
+	__u32 s1,s2,d1,d2;
+	int direction = 2;
+	s1 = point(x1,y1);
+	s2 = point(x1+w-1,y1+h-1);
+	d1 = point(x2,y2);
+	d2 = point(x2+w-1,y2+h-1);
+
+	if ((y1 > y2) || ((y1 == y2) && (x1 >x2)))
+			direction = 0;
+
+	writemmr(0x2120,0x80000000);
+	writemmr(0x2120,0x90000000|ROP_S);
+
+	writemmr(SR1,direction?s2:s1);
+	writemmr(SR2,direction?s1:s2);
+	writemmr(DR1,direction?d2:d1);
+	writemmr(DR2,direction?d1:d2);
+	writemmr(0x2124,0x80000000|1<<22|1<<10|1<<7|direction);
+}
+
+
+static struct accel_switch accel_image = {
+	image_init_accel,
+	image_wait_engine,
+	image_fill_rect,
+	image_copy_rect,
+};
+
+/*
+ * Accel functions called by the upper layers
+ */
+#ifdef CONFIG_FB_TRIDENT_ACCEL
+static void tridentfb_fillrect(struct fb_info * info, const struct fb_fillrect *fr)
+{
+	int bpp = info->var.bits_per_pixel;
+	int col;
+	
+	switch (bpp) {
+		default:
+		case 8: col = fr->color;
+			break;
+		case 16: col = ((u32 *)(info->pseudo_palette))[fr->color];
+			 break;
+		case 32: col = ((u32 *)(info->pseudo_palette))[fr->color];
+			 break;
+	}		 
+			
+	acc->fill_rect(fr->dx, fr->dy, fr->width, fr->height, col, fr->rop);
+	acc->wait_engine();
+}
+static void tridentfb_copyarea(struct fb_info *info, const struct fb_copyarea *ca)
+{
+	acc->copy_rect(ca->sx,ca->sy,ca->dx,ca->dy,ca->width,ca->height);
+	acc->wait_engine();
+}
+#else /* !CONFIG_FB_TRIDENT_ACCEL */
+#define tridentfb_fillrect cfb_fillrect
+#define tridentfb_copyarea cfb_copyarea
+#endif /* CONFIG_FB_TRIDENT_ACCEL */
+
+
+/*
+ * Hardware access functions
+ */
+
+static inline unsigned char read3X4(int reg)
+{
+	struct tridentfb_par * par = (struct tridentfb_par *)fb_info.par;
+	writeb(reg, par->io_virt + CRT + 4);
+	return readb( par->io_virt + CRT + 5);
+}
+
+static inline void write3X4(int reg, unsigned char val)
+{
+	struct tridentfb_par * par = (struct tridentfb_par *)fb_info.par;
+	writeb(reg, par->io_virt + CRT + 4);
+	writeb(val, par->io_virt + CRT + 5);
+}
+
+static inline unsigned char read3C4(int reg)
+{
+	t_outb(reg, 0x3C4);
+	return t_inb(0x3C5);
+}
+
+static inline void write3C4(int reg, unsigned char val)
+{
+	t_outb(reg, 0x3C4);
+	t_outb(val, 0x3C5);
+}
+
+static inline unsigned char read3CE(int reg)
+{
+	t_outb(reg, 0x3CE);
+	return t_inb(0x3CF);
+}
+
+static inline void writeAttr(int reg, unsigned char val)
+{
+	readb(((struct tridentfb_par *)fb_info.par)->io_virt + CRT + 0x0A);	//flip-flop to index
+	t_outb(reg, 0x3C0);
+	t_outb(val, 0x3C0);
+}
+
+static inline void write3CE(int reg, unsigned char val)
+{
+	t_outb(reg, 0x3CE);
+	t_outb(val, 0x3CF);
+}
+
+static inline void enable_mmio(void)
+{
+	/* Goto New Mode */
+	outb(0x0B, 0x3C4);
+	inb(0x3C5);
+
+	/* Unprotect registers */
+	outb(NewMode1, 0x3C4);
+	outb(0x80, 0x3C5);
+  
+	/* Enable MMIO */
+	outb(PCIReg, 0x3D4); 
+	outb(inb(0x3D5) | 0x01, 0x3D5);
+}
+
+
+#define crtc_unlock()	write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F)
+
+/*  Return flat panel's maximum x resolution */
+static int __init get_nativex(void)
+{
+	int x,y,tmp;
+
+	if (nativex)
+		return nativex;
+
+       	tmp = (read3CE(VertStretch) >> 4) & 3;
+
+	switch (tmp) {
+		case 0: x = 1280; y = 1024; break;
+		case 2: x = 1024; y = 768;  break;
+		case 3: x = 800;  y = 600;  break; 
+		case 4: x = 1400; y = 1050; break;
+		case 1: 
+		default:x = 640;  y = 480;  break;
+	}
+
+	output("%dx%d flat panel found\n", x, y);
+	return x;
+}
+
+/* Set pitch */
+static void set_lwidth(int width)
+{
+	write3X4(Offset, width & 0xFF);
+	write3X4(AddColReg, (read3X4(AddColReg) & 0xCF) | ((width & 0x300) >>4));
+}
+
+/* For resolutions smaller than FP resolution stretch */
+static void screen_stretch(void)
+{
+  	if (chip_id != CYBERBLADEXPAi1)
+  		write3CE(BiosReg,0);
+  	else
+  		write3CE(BiosReg,8);
+	write3CE(VertStretch,(read3CE(VertStretch) & 0x7C) | 1);
+	write3CE(HorStretch,(read3CE(HorStretch) & 0x7C) | 1);
+}
+
+/* For resolutions smaller than FP resolution center */
+static void screen_center(void)
+{
+	write3CE(VertStretch,(read3CE(VertStretch) & 0x7C) | 0x80);
+	write3CE(HorStretch,(read3CE(HorStretch) & 0x7C) | 0x80);
+}
+
+/* Address of first shown pixel in display memory */
+static void set_screen_start(int base)
+{
+	write3X4(StartAddrLow, base & 0xFF);
+	write3X4(StartAddrHigh, (base & 0xFF00) >> 8);
+	write3X4(CRTCModuleTest, (read3X4(CRTCModuleTest) & 0xDF) | ((base & 0x10000) >> 11));
+	write3X4(CRTHiOrd, (read3X4(CRTHiOrd) & 0xF8) | ((base & 0xE0000) >> 17));
+}
+
+/* Use 20.12 fixed-point for NTSC value and frequency calculation */
+#define calc_freq(n,m,k)  ( ((unsigned long)0xE517 * (n+8) / ((m+2)*(1<<k))) >> 12 )
+
+/* Set dotclock frequency */
+static void set_vclk(int freq)
+{
+	int m,n,k;
+	int f,fi,d,di;
+	unsigned char lo=0,hi=0;
+
+	d = 20;
+	for(k = 2;k>=0;k--)
+	for(m = 0;m<63;m++)
+	for(n = 0;n<128;n++) {
+		fi = calc_freq(n,m,k);
+		if ((di = abs(fi - freq)) < d) {
+			d = di;
+			f = fi;
+			lo = n;
+			hi = (k<<6) | m;
+		}
+	}
+	if (chip3D) {
+		write3C4(ClockHigh,hi);
+		write3C4(ClockLow,lo);
+	} else {
+		outb(lo,0x43C8);
+		outb(hi,0x43C9);
+	}
+	debug("VCLK = %X %X\n",hi,lo);
+}
+
+/* Set number of lines for flat panels*/
+static void set_number_of_lines(int lines)
+{
+	int tmp = read3CE(CyberEnhance) & 0x8F;
+	if (lines > 1024)
+		tmp |= 0x50;
+	else if (lines > 768)
+		tmp |= 0x30;
+	else if (lines > 600)
+		tmp |= 0x20;
+	else if (lines > 480)
+		tmp |= 0x10;
+	write3CE(CyberEnhance, tmp);
+}
+
+/*
+ * If we see that FP is active we assume we have one.
+ * Otherwise we have a CRT display.User can override.
+ */
+static unsigned int __init get_displaytype(void)
+{
+	if (fp)
+		return DISPLAY_FP;
+	if (crt || !chipcyber)
+		return DISPLAY_CRT;
+	return (read3CE(FPConfig) & 0x10)?DISPLAY_FP:DISPLAY_CRT;
+}
+
+/* Try detecting the video memory size */
+static unsigned int __init get_memsize(void)
+{
+	unsigned char tmp, tmp2;
+	unsigned int k;
+
+	/* If memory size provided by user */
+	if (memsize)
+		k = memsize * Kb;
+	else
+	switch (chip_id) {
+		case CYBER9525DVD:    k = 2560 * Kb; break;
+		default:
+			tmp = read3X4(SPR) & 0x0F;
+			switch (tmp) {
+
+				case 0x01: k = 512;     break;
+				case 0x02: k = 6 * Mb;  break; /* XP */
+				case 0x03: k = 1 * Mb;  break;
+				case 0x04: k = 8 * Mb;  break;
+				case 0x06: k = 10 * Mb; break; /* XP */
+				case 0x07: k = 2 * Mb;  break;
+				case 0x08: k = 12 * Mb; break; /* XP */
+				case 0x0A: k = 14 * Mb; break; /* XP */
+				case 0x0C: k = 16 * Mb; break; /* XP */
+				case 0x0E:                     /* XP */
+  
+					tmp2 = read3C4(0xC1);
+					switch (tmp2) {
+						case 0x00: k = 20 * Mb; break;
+						case 0x01: k = 24 * Mb; break;
+						case 0x10: k = 28 * Mb; break;
+						case 0x11: k = 32 * Mb; break;
+						default:   k = 1 * Mb;  break;
+					}
+				break;
+	
+				case 0x0F: k = 4 * Mb; break;
+				default:   k = 1 * Mb;
+			}
+	}
+
+	k -= memdiff * Kb;
+	output("framebuffer size = %d Kb\n", k/Kb);
+	return k;
+}
+
+/* See if we can handle the video mode described in var */
+static int tridentfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	int bpp = var->bits_per_pixel;
+	debug("enter\n");
+
+	/* check color depth */
+	if (bpp == 24 )
+		bpp = var->bits_per_pixel = 32;
+	/* check whether resolution fits on panel and in memory*/
+	if (flatpanel && nativex && var->xres > nativex)
+		return -EINVAL;
+	if (var->xres * var->yres_virtual * bpp/8 > info->fix.smem_len)
+		return -EINVAL;
+
+	switch (bpp) {
+		case 8:
+			var->red.offset = 0;
+			var->green.offset = 0;
+			var->blue.offset = 0;
+			var->red.length = 6;
+			var->green.length = 6;
+			var->blue.length = 6;
+			break;
+		case 16:
+			var->red.offset = 11;
+			var->green.offset = 5;
+			var->blue.offset = 0;
+			var->red.length = 5;
+			var->green.length = 6;
+			var->blue.length = 5;
+			break;
+		case 32:
+			var->red.offset = 16;
+			var->green.offset = 8;
+			var->blue.offset = 0;
+			var->red.length = 8;
+			var->green.length = 8;
+			var->blue.length = 8;
+			break;
+		default:
+			return -EINVAL;	
+	}
+	debug("exit\n");
+
+	return 0;
+
+}
+/* Pan the display */
+static int tridentfb_pan_display(struct fb_var_screeninfo *var,
+				   struct fb_info *info)
+{
+	unsigned int offset;
+
+	debug("enter\n");
+	offset = (var->xoffset + (var->yoffset * var->xres))
+			* var->bits_per_pixel/32;
+	info->var.xoffset = var->xoffset;
+	info->var.yoffset = var->yoffset;
+	set_screen_start(offset);
+	debug("exit\n");
+	return 0;
+}
+
+#define shadowmode_on()  write3CE(CyberControl,read3CE(CyberControl) | 0x81)
+#define shadowmode_off() write3CE(CyberControl,read3CE(CyberControl) & 0x7E)
+
+/* Set the hardware to the requested video mode */
+static int tridentfb_set_par(struct fb_info *info)
+{
+	struct tridentfb_par * par = (struct tridentfb_par *)(info->par);
+	u32	htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend,
+		vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend;
+	struct fb_var_screeninfo *var = &info->var;	
+	int bpp = var->bits_per_pixel;
+	unsigned char tmp;
+	debug("enter\n");
+	htotal = (var->xres + var->left_margin + var->right_margin + var->hsync_len)/8 - 10;
+	hdispend = var->xres/8 - 1;
+	hsyncstart = (var->xres + var->right_margin)/8;
+	hsyncend = var->hsync_len/8;
+	hblankstart = hdispend + 1;
+	hblankend = htotal + 5;
+
+	vtotal = var->yres + var->upper_margin + var->lower_margin + var->vsync_len - 2;
+	vdispend = var->yres - 1;
+	vsyncstart = var->yres + var->lower_margin;
+	vsyncend = var->vsync_len;
+	vblankstart = var->yres;
+	vblankend = vtotal + 2;
+
+	enable_mmio();
+	crtc_unlock();
+	write3CE(CyberControl,8);
+
+	if (flatpanel && var->xres < nativex) {
+		/*
+		 * on flat panels with native size larger
+		 * than requested resolution decide whether
+		 * we stretch or center
+		 */
+		t_outb(0xEB,0x3C2);
+
+		shadowmode_on();
+
+		if (center) 
+			screen_center();
+		else if (stretch)
+			screen_stretch();
+
+	} else {
+		t_outb(0x2B,0x3C2);
+		write3CE(CyberControl,8);
+	}
+
+	/* vertical timing values */
+	write3X4(CRTVTotal, vtotal & 0xFF);
+	write3X4(CRTVDispEnd, vdispend & 0xFF);
+	write3X4(CRTVSyncStart, vsyncstart & 0xFF);
+	write3X4(CRTVSyncEnd, (vsyncend & 0x0F));
+	write3X4(CRTVBlankStart, vblankstart & 0xFF);
+	write3X4(CRTVBlankEnd, 0/*p->vblankend & 0xFF*/);
+
+	/* horizontal timing values */
+	write3X4(CRTHTotal, htotal & 0xFF);
+	write3X4(CRTHDispEnd, hdispend & 0xFF);
+	write3X4(CRTHSyncStart, hsyncstart & 0xFF);
+	write3X4(CRTHSyncEnd, (hsyncend & 0x1F) | ((hblankend & 0x20)<<2));
+	write3X4(CRTHBlankStart, hblankstart & 0xFF);
+	write3X4(CRTHBlankEnd, 0/*(p->hblankend & 0x1F)*/);
+
+	/* higher bits of vertical timing values */
+	tmp = 0x10;
+	if (vtotal & 0x100) tmp |= 0x01;
+	if (vdispend & 0x100) tmp |= 0x02;
+	if (vsyncstart & 0x100) tmp |= 0x04;
+	if (vblankstart & 0x100) tmp |= 0x08;
+
+	if (vtotal & 0x200) tmp |= 0x20;
+	if (vdispend & 0x200) tmp |= 0x40;
+	if (vsyncstart & 0x200) tmp |= 0x80;
+	write3X4(CRTOverflow, tmp);
+
+	tmp = read3X4(CRTHiOrd) | 0x08;	//line compare bit 10
+	if (vtotal & 0x400) tmp |= 0x80;
+	if (vblankstart & 0x400) tmp |= 0x40;
+	if (vsyncstart & 0x400) tmp |= 0x20;
+	if (vdispend & 0x400) tmp |= 0x10;
+	write3X4(CRTHiOrd, tmp);
+
+	tmp = 0;
+	if (htotal & 0x800) tmp |= 0x800 >> 11;
+	if (hblankstart & 0x800) tmp |= 0x800 >> 7;
+	write3X4(HorizOverflow, tmp);
+	
+	tmp = 0x40;
+	if (vblankstart & 0x200) tmp |= 0x20;
+//FIXME	if (info->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80;  //double scan for 200 line modes
+	write3X4(CRTMaxScanLine, tmp);
+
+	write3X4(CRTLineCompare,0xFF);
+	write3X4(CRTPRowScan,0);
+	write3X4(CRTModeControl,0xC3);
+
+	write3X4(LinearAddReg,0x20);	//enable linear addressing
+
+	tmp = (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84:0x80;
+	write3X4(CRTCModuleTest,tmp);	//enable access extended memory
+
+	write3X4(GraphEngReg, 0x80);	//enable GE for text acceleration
+
+//	if (info->var.accel_flags & FB_ACCELF_TEXT)
+//FIXME		acc->init_accel(info->var.xres,bpp);
+	
+	switch (bpp) {
+		case 8:  tmp = 0x00; break;
+		case 16: tmp = 0x05; break;
+		case 24: tmp = 0x29; break;
+		case 32: tmp = 0x09; 
+	}
+
+	write3X4(PixelBusReg, tmp);
+
+	tmp = 0x10;
+	if (chipcyber)
+	    tmp |= 0x20;
+	write3X4(DRAMControl, tmp);	//both IO,linear enable
+
+	write3X4(InterfaceSel, read3X4(InterfaceSel) | 0x40);
+	write3X4(Performance,0x20);
+	write3X4(PCIReg,0x07);		//MMIO & PCI read and write burst enable
+
+	/* convert from picoseconds to MHz */
+	par->vclk = 1000000/info->var.pixclock;
+	if (bpp == 32)
+		par->vclk *=2;
+	set_vclk(par->vclk);
+
+	write3C4(0,3);
+	write3C4(1,1);		//set char clock 8 dots wide
+	write3C4(2,0x0F);	//enable 4 maps because needed in chain4 mode
+	write3C4(3,0);
+	write3C4(4,0x0E);	//memory mode enable bitmaps ??
+
+	write3CE(MiscExtFunc,(bpp==32)?0x1A:0x12);	//divide clock by 2 if 32bpp
+							//chain4 mode display and CPU path
+	write3CE(0x5,0x40);	//no CGA compat,allow 256 col
+	write3CE(0x6,0x05);	//graphics mode
+	write3CE(0x7,0x0F);	//planes?
+
+	if (chip_id == CYBERBLADEXPAi1) {
+		/* This fixes snow-effect in 32 bpp */
+		write3X4(CRTHSyncStart,0x84);
+	}
+
+	writeAttr(0x10,0x41);	//graphics mode and support 256 color modes
+	writeAttr(0x12,0x0F);	//planes
+	writeAttr(0x13,0);	//horizontal pel panning
+
+	//colors
+	for(tmp = 0;tmp < 0x10;tmp++)
+		writeAttr(tmp,tmp);
+	readb(par->io_virt + CRT + 0x0A);	//flip-flop to index
+	t_outb(0x20, 0x3C0);			//enable attr
+
+	switch (bpp) {
+		case 8:	tmp = 0;break;		//256 colors
+		case 15: tmp = 0x10;break;
+		case 16: tmp = 0x30;break;	//hicolor
+		case 24: 			//truecolor
+		case 32: tmp = 0xD0;break;
+	}
+
+	t_inb(0x3C8);
+	t_inb(0x3C6);
+	t_inb(0x3C6);
+	t_inb(0x3C6);
+	t_inb(0x3C6);
+	t_outb(tmp,0x3C6);
+	t_inb(0x3C8);
+
+	if (flatpanel)
+		set_number_of_lines(info->var.yres);
+	set_lwidth(info->var.xres * bpp/(4*16));
+	info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+	info->fix.line_length = info->var.xres * (bpp >> 3);  
+	info->cmap.len = (bpp == 8) ? 256: 16;
+	debug("exit\n");
+	return 0;
+}
+
+/* Set one color register */
+static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+				 unsigned blue, unsigned transp,
+				 struct fb_info *info)
+{
+	int bpp = info->var.bits_per_pixel;
+
+	if (regno >= info->cmap.len)
+		return 1;
+
+
+	if (bpp==8) {
+		t_outb(0xFF,0x3C6);
+		t_outb(regno,0x3C8);
+
+		t_outb(red>>10,0x3C9);
+		t_outb(green>>10,0x3C9);
+		t_outb(blue>>10,0x3C9);
+
+	} else
+	if (bpp == 16) 			/* RGB 565 */
+			((u32*)info->pseudo_palette)[regno] = (red & 0xF800) |
+			((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
+	else
+	if (bpp == 32)		/* ARGB 8888 */
+		((u32*)info->pseudo_palette)[regno] =
+			((transp & 0xFF00) <<16) 	|
+			((red & 0xFF00) << 8) 		|
+			((green & 0xFF00))		|
+			((blue & 0xFF00)>>8);
+
+//	debug("exit\n");
+	return 0;
+}
+
+/* Try blanking the screen.For flat panels it does nothing */
+static int tridentfb_blank(int blank_mode, struct fb_info *info)
+{
+	unsigned char PMCont,DPMSCont;
+
+	debug("enter\n");
+	if (flatpanel)
+		return 0;
+	t_outb(0x04,0x83C8); /* Read DPMS Control */
+	PMCont = t_inb(0x83C6) & 0xFC;
+	DPMSCont = read3CE(PowerStatus) & 0xFC;
+	switch (blank_mode)
+	{
+	case FB_BLANK_UNBLANK:
+		/* Screen: On, HSync: On, VSync: On */
+	case FB_BLANK_NORMAL:
+		/* Screen: Off, HSync: On, VSync: On */
+		PMCont |= 0x03;
+		DPMSCont |= 0x00;
+		break;
+	case FB_BLANK_HSYNC_SUSPEND:
+		/* Screen: Off, HSync: Off, VSync: On */
+		PMCont |= 0x02;
+		DPMSCont |= 0x01;
+		break;
+	case FB_BLANK_VSYNC_SUSPEND:
+		/* Screen: Off, HSync: On, VSync: Off */
+		PMCont |= 0x02;
+		DPMSCont |= 0x02;
+		break;
+	case FB_BLANK_POWERDOWN:
+		/* Screen: Off, HSync: Off, VSync: Off */
+		PMCont |= 0x00;
+		DPMSCont |= 0x03;
+		break;
+    	}
+
+	write3CE(PowerStatus,DPMSCont);
+	t_outb(4,0x83C8);
+	t_outb(PMCont,0x83C6);
+
+	debug("exit\n");
+
+	/* let fbcon do a softblank for us */
+	return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
+}
+
+static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_device_id * id)
+{
+	int err;
+	unsigned char revision;
+
+	err = pci_enable_device(dev);
+	if (err)
+		return err;
+
+	chip_id = id->device;
+
+	/* If PCI id is 0x9660 then further detect chip type */
+	
+	if (chip_id == TGUI9660) {
+		outb(RevisionID,0x3C4);
+		revision = inb(0x3C5);	
+	
+		switch (revision) {
+			case 0x22:
+			case 0x23: chip_id = CYBER9397;break;
+			case 0x2A: chip_id = CYBER9397DVD;break;
+			case 0x30:
+			case 0x33:
+			case 0x34:
+			case 0x35:
+			case 0x38:
+			case 0x3A:
+			case 0xB3: chip_id = CYBER9385;break;
+			case 0x40 ... 0x43: chip_id = CYBER9382;break;
+			case 0x4A: chip_id = CYBER9388;break;
+			default:break;	
+		}
+	}
+
+	chip3D = is3Dchip(chip_id);
+	chipcyber = iscyber(chip_id);
+
+	if (is_xp(chip_id)) {
+		acc = &accel_xp;
+	} else 
+	if (is_blade(chip_id)) {
+		acc = &accel_blade;
+	} else {
+		acc = &accel_image;
+	}
+
+	/* acceleration is on by default for 3D chips */
+	defaultaccel = chip3D && !noaccel;
+
+	fb_info.par = &default_par;
+
+	/* setup MMIO region */
+	tridentfb_fix.mmio_start = pci_resource_start(dev,1);
+	tridentfb_fix.mmio_len = chip3D ? 0x20000:0x10000;
+
+	if (!request_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len, "tridentfb")) {
+		debug("request_region failed!\n");
+		return -1;
+	}
+
+	default_par.io_virt = ioremap_nocache(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
+
+	if (!default_par.io_virt) {
+		release_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
+		debug("ioremap failed\n");
+		return -1;
+	}
+
+	enable_mmio();
+	
+	/* setup framebuffer memory */
+	tridentfb_fix.smem_start = pci_resource_start(dev,0);
+	tridentfb_fix.smem_len = get_memsize();
+	
+	if (!request_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len, "tridentfb")) {
+		debug("request_mem_region failed!\n");
+		return -1;
+	}
+
+	fb_info.screen_base = ioremap_nocache(tridentfb_fix.smem_start,
+		       			tridentfb_fix.smem_len);
+
+	if (!fb_info.screen_base) {
+		release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
+		debug("ioremap failed\n");
+		return -1;
+	}
+
+	output("%s board found\n", pci_name(dev));
+#if 0	
+	output("Trident board found : mem = %X,io = %X, mem_v = %X, io_v = %X\n",
+		tridentfb_fix.smem_start, tridentfb_fix.mmio_start, fb_info.screen_base, default_par.io_virt);
+#endif
+	displaytype = get_displaytype();
+
+	if(flatpanel)
+		nativex = get_nativex();
+
+	fb_info.fix = tridentfb_fix;
+	fb_info.fbops = &tridentfb_ops;
+
+
+	fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+#ifdef CONFIG_FB_TRIDENT_ACCEL
+	fb_info.flags |= FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
+#endif
+	fb_info.pseudo_palette = pseudo_pal;
+
+	if (!fb_find_mode(&default_var,&fb_info,mode,NULL,0,NULL,bpp))
+		return -EINVAL;
+	fb_alloc_cmap(&fb_info.cmap,256,0);
+	if (defaultaccel && acc)
+		default_var.accel_flags |= FB_ACCELF_TEXT;
+	else
+		default_var.accel_flags &= ~FB_ACCELF_TEXT;
+	default_var.activate |= FB_ACTIVATE_NOW;
+	fb_info.var = default_var;
+	fb_info.device = &dev->dev;
+	if (register_framebuffer(&fb_info) < 0) {
+		printk(KERN_ERR "tridentfb: could not register Trident framebuffer\n");
+		return -EINVAL;
+	}
+	output("fb%d: %s frame buffer device %dx%d-%dbpp\n",
+	   fb_info.node, fb_info.fix.id,default_var.xres,
+	   default_var.yres,default_var.bits_per_pixel);
+	return 0;
+}
+
+static void __devexit trident_pci_remove(struct pci_dev * dev)
+{
+	struct tridentfb_par *par = (struct tridentfb_par*)fb_info.par;
+	unregister_framebuffer(&fb_info);
+	iounmap(par->io_virt);
+	iounmap(fb_info.screen_base);
+	release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
+	release_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
+}
+
+/* List of boards that we are trying to support */
+static struct pci_device_id trident_devices[] = {
+	{PCI_VENDOR_ID_TRIDENT,	BLADE3D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEi7, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEi7D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEi1D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEAi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEAi1D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEE4, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	TGUI9660, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	IMAGE975, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	IMAGE985, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBER9320, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBER9388, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBER9520, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBER9525DVD, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBER9397, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBER9397DVD, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEXPAi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEXPm8, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEXPm16, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+	{0,}
+};	
+	
+MODULE_DEVICE_TABLE(pci,trident_devices); 
+
+static struct pci_driver tridentfb_pci_driver = {
+	.name		= "tridentfb",
+	.id_table	= trident_devices,
+	.probe		= trident_pci_probe,
+	.remove		= __devexit_p(trident_pci_remove)
+};
+
+/*
+ * Parse user specified options (`video=trident:')
+ * example:
+ * 	video=trident:800x600,bpp=16,noaccel
+ */
+#ifndef MODULE
+static int tridentfb_setup(char *options)
+{
+	char * opt;
+	if (!options || !*options)
+		return 0;
+	while((opt = strsep(&options,",")) != NULL ) {
+		if (!*opt) continue;
+		if (!strncmp(opt,"noaccel",7))
+			noaccel = 1;
+		else if (!strncmp(opt,"fp",2))
+			displaytype = DISPLAY_FP;
+		else if (!strncmp(opt,"crt",3))
+			displaytype = DISPLAY_CRT;
+		else if (!strncmp(opt,"bpp=",4))
+			bpp = simple_strtoul(opt+4,NULL,0);
+		else if (!strncmp(opt,"center",6))
+			center = 1;
+		else if (!strncmp(opt,"stretch",7))
+			stretch = 1;
+		else if (!strncmp(opt,"memsize=",8))
+			memsize = simple_strtoul(opt+8,NULL,0);
+		else if (!strncmp(opt,"memdiff=",8))
+			memdiff = simple_strtoul(opt+8,NULL,0);
+		else if (!strncmp(opt,"nativex=",8))
+			nativex = simple_strtoul(opt+8,NULL,0);
+		else
+			mode = opt;
+	}
+	return 0;
+}
+#endif
+
+static int __init tridentfb_init(void)
+{
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("tridentfb", &option))
+		return -ENODEV;
+	tridentfb_setup(option);
+#endif
+	output("Trident framebuffer %s initializing\n", VERSION);
+	return pci_register_driver(&tridentfb_pci_driver);
+}
+
+static void __exit tridentfb_exit(void)
+{
+	pci_unregister_driver(&tridentfb_pci_driver);
+}
+
+static struct fb_ops tridentfb_ops = {
+	.owner	= THIS_MODULE,
+	.fb_setcolreg = tridentfb_setcolreg,
+	.fb_pan_display = tridentfb_pan_display,
+	.fb_blank = tridentfb_blank,
+	.fb_check_var = tridentfb_check_var,
+	.fb_set_par = tridentfb_set_par,
+	.fb_fillrect = tridentfb_fillrect,
+	.fb_copyarea= tridentfb_copyarea,
+	.fb_imageblit = cfb_imageblit,
+	.fb_cursor = soft_cursor,
+};
+
+module_init(tridentfb_init);
+module_exit(tridentfb_exit);
+
+MODULE_AUTHOR("Jani Monoses <jani@iv.ro>");
+MODULE_DESCRIPTION("Framebuffer driver for Trident cards");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/tx3912fb.c b/drivers/video/tx3912fb.c
new file mode 100644
index 0000000..39d9ca7
--- /dev/null
+++ b/drivers/video/tx3912fb.c
@@ -0,0 +1,328 @@
+/*
+ *  drivers/video/tx3912fb.c
+ *
+ *  Copyright (C) 1999 Harald Koerfgen
+ *  Copyright (C) 2001 Steven Hill (sjhill@realitydiluted.com)
+ *
+ * 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.
+ *
+ *  Framebuffer for LCD controller in TMPR3912/05 and PR31700 processors
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/tty.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/fb.h>
+#include <asm/io.h>
+#include <asm/bootinfo.h>
+#include <asm/uaccess.h>
+#include <asm/tx3912.h>
+#include <video/tx3912.h>
+
+/*
+ * Frame buffer, palette and console structures
+ */
+static struct fb_info fb_info;
+static u32 cfb8[16];
+
+static struct fb_fix_screeninfo tx3912fb_fix __initdata = {
+	.id =		"tx3912fb",
+	.smem_len =	((240 * 320)/2),
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_TRUECOLOR, 
+	.xpanstep =	1,
+	.ypanstep =	1,
+	.ywrapstep =	1,
+	.accel =	FB_ACCEL_NONE,
+};
+
+static struct fb_var_screeninfo tx3912fb_var = {
+	.xres =		240,
+	.yres =		320,
+	.xres_virtual =	240,
+	.yres_virtual =	320,
+	.bits_per_pixel =4,
+	.red =		{ 0, 4, 0 },	/* ??? */
+	.green =	{ 0, 4, 0 },
+	.blue =		{ 0, 4, 0 },
+	.activate =	FB_ACTIVATE_NOW,
+	.width =	-1,
+	.height =	-1,
+	.pixclock =	20000,
+	.left_margin =	64,
+	.right_margin =	64,
+	.upper_margin =	32,
+	.lower_margin =	32,
+	.hsync_len =	64,
+	.vsync_len =	2,
+	.vmode =	FB_VMODE_NONINTERLACED,
+};
+
+/*
+ * Interface used by the world
+ */
+int tx3912fb_init(void);
+
+static int tx3912fb_setcolreg(u_int regno, u_int red, u_int green,
+			      u_int blue, u_int transp,
+			      struct fb_info *info);
+
+/*
+ * Macros
+ */
+#define get_line_length(xres_virtual, bpp) \
+                (u_long) (((int) xres_virtual * (int) bpp + 7) >> 3)
+
+/*
+ * Frame buffer operations structure used by console driver
+ */
+static struct fb_ops tx3912fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_setcolreg	= tx3912fb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+static int tx3912fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	/*
+	 * Memory limit
+	 */
+	line_length =
+	    get_line_length(var->xres_virtual, var->bits_per_pixel);
+	if ((line_length * var->yres_virtual) > info->fix.smem_len)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int tx3912fb_set_par(struct fb_info *info)
+{
+	u_long tx3912fb_paddr = 0;
+
+	/* Disable the video logic */
+	outl(inl(TX3912_VIDEO_CTRL1) &
+	     ~(TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON),
+	     TX3912_VIDEO_CTRL1);
+	udelay(200);
+
+	/* Set start address for DMA transfer */
+	outl(tx3912fb_paddr, TX3912_VIDEO_CTRL3);
+
+	/* Set end address for DMA transfer */
+	outl((tx3912fb_paddr + tx3912fb_fix.smem_len + 1), TX3912_VIDEO_CTRL4);
+
+	/* Set the pixel depth */
+	switch (info->var.bits_per_pixel) {
+	case 1:
+		/* Monochrome */
+		outl(inl(TX3912_VIDEO_CTRL1) &
+		     ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
+		info->fix.visual = FB_VISUAL_MONO10;
+		break;
+	case 4:
+		/* 4-bit gray */
+		outl(inl(TX3912_VIDEO_CTRL1) &
+		     ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
+		outl(inl(TX3912_VIDEO_CTRL1) |
+		     TX3912_VIDEO_CTRL1_BITSEL_4BIT_GRAY,
+		     TX3912_VIDEO_CTRL1);
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+		break;
+	case 8:
+		/* 8-bit color */
+		outl(inl(TX3912_VIDEO_CTRL1) &
+		     ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
+		outl(inl(TX3912_VIDEO_CTRL1) |
+		     TX3912_VIDEO_CTRL1_BITSEL_8BIT_COLOR,
+		     TX3912_VIDEO_CTRL1);
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+		break;
+	case 2:
+	default:
+		/* 2-bit gray */
+		outl(inl(TX3912_VIDEO_CTRL1) &
+		     ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
+		outl(inl(TX3912_VIDEO_CTRL1) |
+		     TX3912_VIDEO_CTRL1_BITSEL_2BIT_GRAY,
+		     TX3912_VIDEO_CTRL1);
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+		break;
+	}
+
+	/* Enable the video clock */
+	outl(inl(TX3912_CLK_CTRL) | TX3912_CLK_CTRL_ENVIDCLK,
+	     TX3912_CLK_CTRL);
+
+	/* Unfreeze video logic and enable DF toggle */
+	outl(inl(TX3912_VIDEO_CTRL1) &
+	     ~(TX3912_VIDEO_CTRL1_ENFREEZEFRAME |
+	       TX3912_VIDEO_CTRL1_DFMODE)
+	     , TX3912_VIDEO_CTRL1);
+	udelay(200);
+
+	/* Enable the video logic */
+	outl(inl(TX3912_VIDEO_CTRL1) |
+	     (TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON),
+	     TX3912_VIDEO_CTRL1);
+
+	info->fix.line_length = get_line_length(var->xres_virtual,
+					    var->bits_per_pixel);
+}
+
+/*
+ * Set a single color register
+ */
+static int tx3912fb_setcolreg(u_int regno, u_int red, u_int green,
+			      u_int blue, u_int transp,
+			      struct fb_info *info)
+{
+	if (regno > 255)
+		return 1;
+
+	if (regno < 16)
+		((u32 *)(info->pseudo_palette))[regno] = ((red & 0xe000) >> 8)
+		    | ((green & 0xe000) >> 11)
+		    | ((blue & 0xc000) >> 14);
+	return 0;
+}
+
+int __init tx3912fb_setup(char *options);
+
+/*
+ * Initialization of the framebuffer
+ */
+int __init tx3912fb_init(void)
+{
+	u_long tx3912fb_paddr = 0;
+	int size = (info->var.bits_per_pixel == 8) ? 256 : 16;
+	char *option = NULL;
+
+	if (fb_get_options("tx3912fb", &option))
+		return -ENODEV;
+	tx3912fb_setup(option);
+
+	/* Disable the video logic */
+	outl(inl(TX3912_VIDEO_CTRL1) &
+	     ~(TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON),
+	     TX3912_VIDEO_CTRL1);
+	udelay(200);
+
+	/* Set start address for DMA transfer */
+	outl(tx3912fb_paddr, TX3912_VIDEO_CTRL3);
+
+	/* Set end address for DMA transfer */
+	outl((tx3912fb_paddr + tx3912fb_fix.smem_len + 1), TX3912_VIDEO_CTRL4);
+
+	/* Set the pixel depth */
+	switch (tx3912fb_var.bits_per_pixel) {
+	case 1:
+		/* Monochrome */
+		outl(inl(TX3912_VIDEO_CTRL1) &
+		     ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
+		tx3912fb_fix.visual = FB_VISUAL_MONO10;
+		break;
+	case 4:
+		/* 4-bit gray */
+		outl(inl(TX3912_VIDEO_CTRL1) &
+		     ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
+		outl(inl(TX3912_VIDEO_CTRL1) |
+		     TX3912_VIDEO_CTRL1_BITSEL_4BIT_GRAY,
+		     TX3912_VIDEO_CTRL1);
+		tx3912fb_fix.visual = FB_VISUAL_TRUECOLOR;
+		tx3912fb_fix.grayscale = 1;
+		break;
+	case 8:
+		/* 8-bit color */
+		outl(inl(TX3912_VIDEO_CTRL1) &
+		     ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
+		outl(inl(TX3912_VIDEO_CTRL1) |
+		     TX3912_VIDEO_CTRL1_BITSEL_8BIT_COLOR,
+		     TX3912_VIDEO_CTRL1);
+		tx3912fb_fix.visual = FB_VISUAL_TRUECOLOR;
+		break;
+	case 2:
+	default:
+		/* 2-bit gray */
+		outl(inl(TX3912_VIDEO_CTRL1) &
+		     ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
+		outl(inl(TX3912_VIDEO_CTRL1) |
+		     TX3912_VIDEO_CTRL1_BITSEL_2BIT_GRAY,
+		     TX3912_VIDEO_CTRL1);
+		tx3912fb_fix.visual = FB_VISUAL_PSEUDOCOLOR;
+		tx3912fb_fix.grayscale = 1;
+		break;
+	}
+
+	/* Enable the video clock */
+	outl(inl(TX3912_CLK_CTRL) | TX3912_CLK_CTRL_ENVIDCLK,
+		TX3912_CLK_CTRL);
+
+	/* Unfreeze video logic and enable DF toggle */
+	outl(inl(TX3912_VIDEO_CTRL1) &
+		~(TX3912_VIDEO_CTRL1_ENFREEZEFRAME | TX3912_VIDEO_CTRL1_DFMODE),
+		TX3912_VIDEO_CTRL1);
+	udelay(200);
+
+	/* Clear the framebuffer */
+	memset((void *) tx3912fb_fix.smem_start, 0xff, tx3912fb_fix.smem_len);
+	udelay(200);
+
+	/* Enable the video logic */
+	outl(inl(TX3912_VIDEO_CTRL1) |
+		(TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON),
+		TX3912_VIDEO_CTRL1);
+
+	/*
+	 * Memory limit
+	 */
+	tx3912fb_fix.line_length =
+	    get_line_length(tx3912fb_var.xres_virtual, tx3912fb_var.bits_per_pixel);
+	if ((tx3912fb_fix.line_length * tx3912fb_var.yres_virtual) > tx3912fb_fix.smem_len)
+		return -ENOMEM;
+
+	fb_info.fbops = &tx3912fb_ops;
+	fb_info.var = tx3912fb_var;
+	fb_info.fix = tx3912fb_fix;
+	fb_info.pseudo_palette = pseudo_palette;
+	fb_info.flags = FBINFO_DEFAULT;
+
+	/* Clear the framebuffer */
+	memset((void *) fb_info.fix.smem_start, 0xff, fb_info.fix.smem_len);
+	udelay(200);
+
+	fb_alloc_cmap(&info->cmap, size, 0);
+
+	if (register_framebuffer(&fb_info) < 0)
+		return -1;
+
+	printk(KERN_INFO "fb%d: TX3912 frame buffer using %uKB.\n",
+	       fb_info.node, (u_int) (fb_info.fix.smem_len >> 10));
+	return 0;
+}
+
+int __init tx3912fb_setup(char *options)
+{
+	char *this_opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ","))) {
+		if (!strncmp(options, "bpp:", 4))	
+			tx3912fb_var.bits_per_pixel = simple_strtoul(options+4, NULL, 0);
+	}	
+	return 0;
+}
+
+module_init(tx3912fb_init);
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c
new file mode 100644
index 0000000..31a2bbc
--- /dev/null
+++ b/drivers/video/valkyriefb.c
@@ -0,0 +1,590 @@
+/*
+ *  valkyriefb.c -- frame buffer device for the PowerMac 'valkyrie' display
+ *
+ *  Created 8 August 1998 by 
+ *  Martin Costabel <costabel@wanadoo.fr> and Kevin Schoedel
+ *
+ *  Vmode-switching changes and vmode 15/17 modifications created 29 August
+ *  1998 by Barry K. Nathan <barryn@pobox.com>.
+ *
+ *  Ported to m68k Macintosh by David Huggins-Daines <dhd@debian.org>
+ *
+ *  Derived directly from:
+ *
+ *   controlfb.c -- frame buffer device for the PowerMac 'control' display
+ *   Copyright (C) 1998 Dan Jacobowitz <dan@debian.org>
+ *
+ *   pmc-valkyrie.c -- Console support for PowerMac "valkyrie" display adaptor.
+ *   Copyright (C) 1997 Paul Mackerras.
+ *
+ *  and indirectly:
+ *
+ *  Frame buffer structure from:
+ *    drivers/video/chipsfb.c -- frame buffer device for
+ *    Chips & Technologies 65550 chip.
+ *
+ *    Copyright (C) 1998 Paul Mackerras
+ *
+ *    This file is derived from the Powermac "chips" driver:
+ *    Copyright (C) 1997 Fabio Riccardi.
+ *    And from the frame buffer device for Open Firmware-initialized devices:
+ *    Copyright (C) 1997 Geert Uytterhoeven.
+ *
+ *  Hardware information from:
+ *    control.c: Console support for PowerMac "control" display adaptor.
+ *    Copyright (C) 1996 Paul Mackerras
+ *
+ *  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 <linux/fb.h>
+#include <linux/selection.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/nvram.h>
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <asm/io.h>
+#ifdef CONFIG_MAC
+#include <asm/bootinfo.h>
+#include <asm/macintosh.h>
+#else
+#include <asm/prom.h>
+#endif
+#include <asm/pgtable.h>
+
+#include "macmodes.h"
+#include "valkyriefb.h"
+
+#ifdef CONFIG_MAC
+/* We don't yet have functions to read the PRAM... perhaps we can
+   adapt them from the PPC code? */
+static int default_vmode = VMODE_640_480_67;
+static int default_cmode = CMODE_8;
+#else
+static int default_vmode = VMODE_NVRAM;
+static int default_cmode = CMODE_NVRAM;
+#endif
+
+struct fb_par_valkyrie {
+	int	vmode, cmode;
+	int	xres, yres;
+	int	vxres, vyres;
+	struct valkyrie_regvals *init;
+};
+
+struct fb_info_valkyrie {
+	struct fb_info		info;
+	struct fb_par_valkyrie	par;
+	struct cmap_regs	__iomem *cmap_regs;
+	unsigned long		cmap_regs_phys;
+	
+	struct valkyrie_regs	__iomem *valkyrie_regs;
+	unsigned long		valkyrie_regs_phys;
+	
+	__u8			__iomem *frame_buffer;
+	unsigned long		frame_buffer_phys;
+	
+	int			sense;
+	unsigned long		total_vram;
+
+	u32			pseudo_palette[16];
+};
+
+/*
+ * Exported functions
+ */
+int valkyriefb_init(void);
+int valkyriefb_setup(char*);
+
+static int valkyriefb_check_var(struct fb_var_screeninfo *var,
+				struct fb_info *info);
+static int valkyriefb_set_par(struct fb_info *info);
+static int valkyriefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			     u_int transp, struct fb_info *info);
+static int valkyriefb_blank(int blank_mode, struct fb_info *info);
+
+static int read_valkyrie_sense(struct fb_info_valkyrie *p);
+static void set_valkyrie_clock(unsigned char *params);
+static int valkyrie_var_to_par(struct fb_var_screeninfo *var,
+	struct fb_par_valkyrie *par, const struct fb_info *fb_info);
+
+static void valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p);
+static void valkyrie_par_to_fix(struct fb_par_valkyrie *par, struct fb_fix_screeninfo *fix);
+static void valkyrie_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_valkyrie *p);
+
+static struct fb_ops valkyriefb_ops = {
+	.owner =	THIS_MODULE,
+	.fb_check_var =	valkyriefb_check_var,
+	.fb_set_par =	valkyriefb_set_par,
+	.fb_setcolreg =	valkyriefb_setcolreg,
+	.fb_blank =	valkyriefb_blank,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+/* Sets the video mode according to info->var */
+static int valkyriefb_set_par(struct fb_info *info)
+{
+	struct fb_info_valkyrie *p = (struct fb_info_valkyrie *) info;
+	volatile struct valkyrie_regs __iomem *valkyrie_regs = p->valkyrie_regs;
+	struct fb_par_valkyrie *par = info->par;
+	struct valkyrie_regvals	*init;
+	int err;
+
+	if ((err = valkyrie_var_to_par(&info->var, par, info)))
+		return err;
+
+	valkyrie_par_to_fix(par, &info->fix);
+
+	/* Reset the valkyrie */
+	out_8(&valkyrie_regs->status.r, 0);
+	udelay(100);
+
+	/* Initialize display timing registers */
+	init = par->init;
+	out_8(&valkyrie_regs->mode.r, init->mode | 0x80);
+	out_8(&valkyrie_regs->depth.r, par->cmode + 3);
+	set_valkyrie_clock(init->clock_params);
+	udelay(100);
+
+	/* Turn on display */
+	out_8(&valkyrie_regs->mode.r, init->mode);
+
+	return 0;
+}
+
+static inline int valkyrie_par_to_var(struct fb_par_valkyrie *par,
+				      struct fb_var_screeninfo *var)
+{
+	return mac_vmode_to_var(par->vmode, par->cmode, var);
+}
+
+static int
+valkyriefb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	int err;
+	struct fb_par_valkyrie par;
+
+	if ((err = valkyrie_var_to_par(var, &par, info)))
+		return err;
+	valkyrie_par_to_var(&par, var);
+	return 0;
+}
+
+/*
+ *  Blank the screen if blank_mode != 0, else unblank. If blank_mode == NULL
+ *  then the caller blanks by setting the CLUT (Color Look Up Table) to all
+ *  black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
+ *  to e.g. a video mode which doesn't support it. Implements VESA suspend
+ *  and powerdown modes on hardware that supports disabling hsync/vsync:
+ *    blank_mode == 2: suspend vsync
+ *    blank_mode == 3: suspend hsync
+ *    blank_mode == 4: powerdown
+ */
+static int valkyriefb_blank(int blank_mode, struct fb_info *info)
+{
+	struct fb_info_valkyrie *p = (struct fb_info_valkyrie *) info;
+	struct fb_par_valkyrie *par = info->par;
+	struct valkyrie_regvals	*init = par->init;
+
+	if (init == NULL)
+		return 1;
+
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANK:			/* unblank */
+		out_8(&p->valkyrie_regs->mode.r, init->mode);
+		break;
+	case FB_BLANK_NORMAL:
+		return 1;	/* get caller to set CLUT to all black */
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+		/*
+		 * [kps] Value extracted from MacOS. I don't know
+		 * whether this bit disables hsync or vsync, or
+		 * whether the hardware can do the other as well.
+		 */
+		out_8(&p->valkyrie_regs->mode.r, init->mode | 0x40);
+		break;
+	case FB_BLANK_POWERDOWN:
+		out_8(&p->valkyrie_regs->mode.r, 0x66);
+		break;
+	}
+	return 0;
+}
+
+static int valkyriefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			     u_int transp, struct fb_info *info)
+{
+	struct fb_info_valkyrie *p = (struct fb_info_valkyrie *) info;
+	volatile struct cmap_regs __iomem *cmap_regs = p->cmap_regs;
+	struct fb_par_valkyrie *par = info->par;
+
+	if (regno > 255)
+		return 1;
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	/* tell clut which address to fill */
+	out_8(&p->cmap_regs->addr, regno);
+	udelay(1);
+	/* send one color channel at a time */
+	out_8(&cmap_regs->lut, red);
+	out_8(&cmap_regs->lut, green);
+	out_8(&cmap_regs->lut, blue);
+
+	if (regno < 16 && par->cmode == CMODE_16)
+		((u32 *)info->pseudo_palette)[regno] =
+			(regno << 10) | (regno << 5) | regno;
+
+	return 0;
+}
+
+static inline int valkyrie_vram_reqd(int video_mode, int color_mode)
+{
+	int pitch;
+	struct valkyrie_regvals *init = valkyrie_reg_init[video_mode-1];
+	
+	if ((pitch = init->pitch[color_mode]) == 0)
+		pitch = 2 * init->pitch[0];
+	return init->vres * pitch;
+}
+
+static void set_valkyrie_clock(unsigned char *params)
+{
+	struct adb_request req;
+	int i;
+
+#ifdef CONFIG_ADB_CUDA
+	for (i = 0; i < 3; ++i) {
+		cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+			     0x50, i + 1, params[i]);
+		while (!req.complete)
+			cuda_poll();
+	}
+#endif
+}
+
+static void __init valkyrie_choose_mode(struct fb_info_valkyrie *p)
+{
+	p->sense = read_valkyrie_sense(p);
+	printk(KERN_INFO "Monitor sense value = 0x%x\n", p->sense);
+
+	/* Try to pick a video mode out of NVRAM if we have one. */
+#ifndef CONFIG_MAC
+	if (default_vmode == VMODE_NVRAM) {
+		default_vmode = nvram_read_byte(NV_VMODE);
+		if (default_vmode <= 0
+		 || default_vmode > VMODE_MAX
+		 || !valkyrie_reg_init[default_vmode - 1])
+			default_vmode = VMODE_CHOOSE;
+	}
+#endif
+	if (default_vmode == VMODE_CHOOSE)
+		default_vmode = mac_map_monitor_sense(p->sense);
+	if (!valkyrie_reg_init[default_vmode - 1])
+		default_vmode = VMODE_640_480_67;
+#ifndef CONFIG_MAC
+	if (default_cmode == CMODE_NVRAM)
+		default_cmode = nvram_read_byte(NV_CMODE);
+#endif
+
+	/*
+	 * Reduce the pixel size if we don't have enough VRAM or bandwidth.
+	 */
+	if (default_cmode < CMODE_8 || default_cmode > CMODE_16
+	    || valkyrie_reg_init[default_vmode-1]->pitch[default_cmode] == 0
+	    || valkyrie_vram_reqd(default_vmode, default_cmode) > p->total_vram)
+		default_cmode = CMODE_8;
+
+	printk(KERN_INFO "using video mode %d and color mode %d.\n",
+	       default_vmode, default_cmode);
+}
+
+int __init valkyriefb_init(void)
+{
+	struct fb_info_valkyrie	*p;
+	unsigned long frame_buffer_phys, cmap_regs_phys, flags;
+	int err;
+	char *option = NULL;
+
+	if (fb_get_options("valkyriefb", &option))
+		return -ENODEV;
+	valkyriefb_setup(option);
+
+#ifdef CONFIG_MAC
+	if (!MACH_IS_MAC)
+		return 0;
+	if (!(mac_bi_data.id == MAC_MODEL_Q630
+	      /* I'm not sure about this one */
+	    || mac_bi_data.id == MAC_MODEL_P588))
+		return 0;
+
+	/* Hardcoded addresses... welcome to 68k Macintosh country :-) */
+	frame_buffer_phys = 0xf9000000;
+	cmap_regs_phys = 0x50f24000;
+	flags = IOMAP_NOCACHE_SER; /* IOMAP_WRITETHROUGH?? */
+#else /* ppc (!CONFIG_MAC) */
+	{
+		struct device_node *dp;
+
+		dp = find_devices("valkyrie");
+		if (dp == 0)
+			return 0;
+
+		if (dp->n_addrs != 1) {
+			printk(KERN_ERR "expecting 1 address for valkyrie (got %d)\n",
+			       dp->n_addrs);
+			return 0;
+		}
+
+		frame_buffer_phys = dp->addrs[0].address;
+		cmap_regs_phys = dp->addrs[0].address+0x304000;
+		flags = _PAGE_WRITETHRU;
+	}
+#endif /* ppc (!CONFIG_MAC) */
+
+	p = kmalloc(sizeof(*p), GFP_ATOMIC);
+	if (p == 0)
+		return -ENOMEM;
+	memset(p, 0, sizeof(*p));
+
+	/* Map in frame buffer and registers */
+	if (!request_mem_region(frame_buffer_phys, 0x100000, "valkyriefb")) {
+		kfree(p);
+		return 0;
+	}
+	p->total_vram = 0x100000;
+	p->frame_buffer_phys = frame_buffer_phys;
+	p->frame_buffer = __ioremap(frame_buffer_phys, p->total_vram, flags);
+	p->cmap_regs_phys = cmap_regs_phys;
+	p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000);
+	p->valkyrie_regs_phys = cmap_regs_phys+0x6000;
+	p->valkyrie_regs = ioremap(p->valkyrie_regs_phys, 0x1000);
+	err = -ENOMEM;
+	if (p->frame_buffer == NULL || p->cmap_regs == NULL
+	    || p->valkyrie_regs == NULL) {
+		printk(KERN_ERR "valkyriefb: couldn't map resources\n");
+		goto out_free;
+	}
+
+	valkyrie_choose_mode(p);
+	mac_vmode_to_var(default_vmode, default_cmode, &p->info.var);
+	valkyrie_init_info(&p->info, p);
+	valkyrie_init_fix(&p->info.fix, p);
+	if (valkyriefb_set_par(&p->info))
+		/* "can't happen" */
+		printk(KERN_ERR "valkyriefb: can't set default video mode\n");
+
+	if ((err = register_framebuffer(&p->info)) != 0)
+		goto out_free;
+
+	printk(KERN_INFO "fb%d: valkyrie frame buffer device\n", p->info.node);
+	return 0;
+
+ out_free:
+	if (p->frame_buffer)
+		iounmap(p->frame_buffer);
+	if (p->cmap_regs)
+		iounmap(p->cmap_regs);
+	if (p->valkyrie_regs)
+		iounmap(p->valkyrie_regs);
+	kfree(p);
+	return err;
+}
+
+/*
+ * Get the monitor sense value.
+ */
+static int read_valkyrie_sense(struct fb_info_valkyrie *p)
+{
+	int sense, in;
+
+	out_8(&p->valkyrie_regs->msense.r, 0);   /* release all lines */
+	__delay(20000);
+	sense = ((in = in_8(&p->valkyrie_regs->msense.r)) & 0x70) << 4;
+	/* drive each sense line low in turn and collect the other 2 */
+	out_8(&p->valkyrie_regs->msense.r, 4);   /* drive A low */
+	__delay(20000);
+	sense |= ((in = in_8(&p->valkyrie_regs->msense.r)) & 0x30);
+	out_8(&p->valkyrie_regs->msense.r, 2);   /* drive B low */
+	__delay(20000);
+	sense |= ((in = in_8(&p->valkyrie_regs->msense.r)) & 0x40) >> 3;
+	sense |= (in & 0x10) >> 2;
+	out_8(&p->valkyrie_regs->msense.r, 1);   /* drive C low */
+	__delay(20000);
+	sense |= ((in = in_8(&p->valkyrie_regs->msense.r)) & 0x60) >> 5;
+
+	out_8(&p->valkyrie_regs->msense.r, 7);
+
+	return sense;
+}
+
+/*
+ * This routine takes a user-supplied var,
+ * and picks the best vmode/cmode from it.
+ */
+
+/* [bkn] I did a major overhaul of this function.
+ *
+ * Much of the old code was "swiped by jonh from atyfb.c". Because
+ * macmodes has mac_var_to_vmode, I felt that it would be better to
+ * rework this function to use that, instead of reinventing the wheel to
+ * add support for vmode 17. This was reinforced by the fact that
+ * the previously swiped atyfb.c code is no longer there.
+ *
+ * So, I swiped and adapted platinum_var_to_par (from platinumfb.c), replacing
+ * most, but not all, of the old code in the process. One side benefit of
+ * swiping the platinumfb code is that we now have more comprehensible error
+ * messages when a vmode/cmode switch fails. (Most of the error messages are
+ * platinumfb.c, but I added two of my own, and I also changed some commas
+ * into colons to make the messages more consistent with other Linux error
+ * messages.) In addition, I think the new code *might* fix some vmode-
+ * switching oddities, but I'm not sure.
+ *
+ * There may be some more opportunities for cleanup in here, but this is a
+ * good start...
+ */
+
+static int valkyrie_var_to_par(struct fb_var_screeninfo *var,
+	struct fb_par_valkyrie *par, const struct fb_info *fb_info)
+{
+	int vmode, cmode;
+	struct valkyrie_regvals *init;
+	struct fb_info_valkyrie *p = (struct fb_info_valkyrie *) fb_info;
+
+	if (mac_var_to_vmode(var, &vmode, &cmode) != 0) {
+		printk(KERN_ERR "valkyriefb: can't do %dx%dx%d.\n",
+		       var->xres, var->yres, var->bits_per_pixel);
+		return -EINVAL;
+	}
+
+	/* Check if we know about the wanted video mode */
+	if (vmode < 1 || vmode > VMODE_MAX || !valkyrie_reg_init[vmode-1]) {
+		printk(KERN_ERR "valkyriefb: vmode %d not valid.\n", vmode);
+		return -EINVAL;
+	}
+	
+	if (cmode != CMODE_8 && cmode != CMODE_16) {
+		printk(KERN_ERR "valkyriefb: cmode %d not valid.\n", cmode);
+		return -EINVAL;
+	}
+
+	if (var->xres_virtual > var->xres || var->yres_virtual > var->yres
+	    || var->xoffset != 0 || var->yoffset != 0) {
+		return -EINVAL;
+	}
+
+	init = valkyrie_reg_init[vmode-1];
+	if (init->pitch[cmode] == 0) {
+		printk(KERN_ERR "valkyriefb: vmode %d does not support "
+		       "cmode %d.\n", vmode, cmode);
+		return -EINVAL;
+	}
+
+	if (valkyrie_vram_reqd(vmode, cmode) > p->total_vram) {
+		printk(KERN_ERR "valkyriefb: not enough ram for vmode %d, "
+		       "cmode %d.\n", vmode, cmode);
+		return -EINVAL;
+	}
+
+	par->vmode = vmode;
+	par->cmode = cmode;
+	par->init = init;
+	par->xres = var->xres;
+	par->yres = var->yres;
+	par->vxres = par->xres;
+	par->vyres = par->yres;
+
+	return 0;
+}
+
+static void valkyrie_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_valkyrie *p)
+{
+	memset(fix, 0, sizeof(*fix));
+	strcpy(fix->id, "valkyrie");
+	fix->mmio_start = p->valkyrie_regs_phys;
+	fix->mmio_len = sizeof(struct valkyrie_regs);
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->smem_start = p->frame_buffer_phys + 0x1000;
+	fix->smem_len = p->total_vram;
+
+	fix->type_aux = 0;
+	fix->ywrapstep = 0;
+	fix->ypanstep = 0;
+	fix->xpanstep = 0;
+	
+}
+
+/* Fix must already be inited above */
+static void valkyrie_par_to_fix(struct fb_par_valkyrie *par,
+	struct fb_fix_screeninfo *fix)
+{
+	fix->smem_len = valkyrie_vram_reqd(par->vmode, par->cmode);
+	fix->visual = (par->cmode == CMODE_8) ?
+		FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
+	fix->line_length = par->vxres << par->cmode;
+		/* ywrapstep, xpanstep, ypanstep */
+}
+
+static void __init valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p)
+{
+	info->fbops = &valkyriefb_ops;
+	info->screen_base = p->frame_buffer + 0x1000;
+	info->flags = FBINFO_DEFAULT;
+	info->pseudo_palette = p->pseudo_palette;
+	fb_alloc_cmap(&info->cmap, 256, 0);
+	info->par = &p->par;
+}
+
+
+/*
+ * Parse user speficied options (`video=valkyriefb:')
+ */
+int __init valkyriefb_setup(char *options)
+{
+	char *this_opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!strncmp(this_opt, "vmode:", 6)) {
+	    		int vmode = simple_strtoul(this_opt+6, NULL, 0);
+			if (vmode > 0 && vmode <= VMODE_MAX)
+				default_vmode = vmode;
+		}
+		else if (!strncmp(this_opt, "cmode:", 6)) {
+			int depth = simple_strtoul(this_opt+6, NULL, 0);
+			switch (depth) {
+			case 8:
+				default_cmode = CMODE_8;
+				break;
+			case 15:
+			case 16:
+				default_cmode = CMODE_16;
+				break;
+			}
+		}
+	}
+	return 0;
+}
+
+module_init(valkyriefb_init);
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/valkyriefb.h b/drivers/video/valkyriefb.h
new file mode 100644
index 0000000..97aaf7b
--- /dev/null
+++ b/drivers/video/valkyriefb.h
@@ -0,0 +1,211 @@
+/*
+ * valkyriefb.h: Constants of all sorts for valkyriefb
+ *
+ *  Created 8 August 1998 by 
+ *  Martin Costabel <costabel@wanadoo.fr> and Kevin Schoedel
+ *
+ * Vmode-switching changes and vmode 15/17 modifications created 29 August
+ * 1998 by Barry K. Nathan <barryn@pobox.com>.
+ * 
+ * vmode 10 changed by Steven Borley <sjb@salix.demon.co.uk>, 14 mai 2000
+ *
+ * Ported to 68k Macintosh by David Huggins-Daines <dhd@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Based directly on:
+ *
+ *  controlfb.h: Constants of all sorts for controlfb
+ *  Copyright (C) 1998 Daniel Jacobowitz <dan@debian.org>
+ *
+ *  pmc-valkyrie.h: Console support for PowerMac "control" display adaptor.
+ *  Copyright (C) 1997 Paul Mackerras.
+ *
+ *  pmc-valkyrie.c: Console support for PowerMac "control" display adaptor.
+ *  Copyright (C) 1997 Paul Mackerras.
+ *
+ * and indirectly from:
+ *
+ *  pmc-control.h: Console support for PowerMac "control" display adaptor.
+ *  Copyright (C) 1997 Paul Mackerras.
+ *
+ *  pmc-control.c: Console support for PowerMac "control" display adaptor.
+ *  Copyright (C) 1996 Paul Mackerras.
+ *
+ *  platinumfb.c: Console support for PowerMac "platinum" display adaptor.
+ *  Copyright (C) 1998 Jon Howell
+ */
+
+#ifdef CONFIG_MAC
+/* Valkyrie registers are word-aligned on m68k */
+#define VALKYRIE_REG_PADSIZE	3
+#else
+#define VALKYRIE_REG_PADSIZE	7
+#endif
+
+/*
+ * Structure of the registers for the Valkyrie colormap registers.
+ */
+struct cmap_regs {
+	unsigned char addr;
+	char pad1[VALKYRIE_REG_PADSIZE];
+	unsigned char lut;
+};
+
+/*
+ * Structure of the registers for the "valkyrie" display adaptor.
+ */
+
+struct vpreg {			/* padded register */
+	unsigned char r;
+	char pad[VALKYRIE_REG_PADSIZE];
+};
+
+
+struct valkyrie_regs {
+	struct vpreg mode;
+	struct vpreg depth;
+	struct vpreg status;
+	struct vpreg reg3;
+	struct vpreg intr;
+	struct vpreg reg5;
+	struct vpreg intr_enb;
+	struct vpreg msense;
+};
+
+/*
+ * Register initialization tables for the valkyrie display.
+ *
+ * Dot clock rate is
+ * 3.9064MHz * 2**clock_params[2] * clock_params[1] / clock_params[0].
+ */
+struct valkyrie_regvals {
+	unsigned char mode;
+	unsigned char clock_params[3];
+	int	pitch[2];		/* bytes/line, indexed by color_mode */
+	int	hres;
+	int	vres;
+};
+
+#ifndef CONFIG_MAC
+/* Register values for 1024x768, 75Hz mode (17) */
+/* I'm not sure which mode this is (16 or 17), so I'm defining it as 17,
+ * since the equivalent mode in controlfb (which I adapted this from) is
+ * also 17. Just because MacOS can't do this on Valkyrie doesn't mean we
+ * can't! :)
+ *
+ * I was going to use 12, 31, 3, which I found by myself, but instead I'm
+ * using 11, 28, 3 like controlfb, for consistency's sake.
+ */
+
+static struct valkyrie_regvals valkyrie_reg_init_17 = {
+    15, 
+    { 11, 28, 3 },  /* pixel clock = 79.55MHz for V=74.50Hz */
+    { 1024, 0 },
+	1024, 768
+};
+
+/* Register values for 1024x768, 72Hz mode (15) */
+/* This used to be 12, 30, 3 for pixel clock = 78.12MHz for V=72.12Hz, but
+ * that didn't match MacOS in the same video mode on this chip, and it also
+ * caused the 15" Apple Studio Display to not work in this mode. While this
+ * mode still doesn't match MacOS exactly (as far as I can tell), it's a lot
+ * closer now, and it works with the Apple Studio Display.
+ *
+ * Yes, even though MacOS calls it "72Hz", in reality it's about 70Hz.
+ */
+static struct valkyrie_regvals valkyrie_reg_init_15 = {
+    15,
+    { 12, 29, 3 },  /* pixel clock = 75.52MHz for V=69.71Hz? */
+		    /* I interpolated the V=69.71 from the vmode 14 and old 15
+		     * numbers. Is this result correct?
+		     */
+    { 1024, 0 },
+	1024, 768
+};
+
+/* Register values for 1024x768, 60Hz mode (14) */
+static struct valkyrie_regvals valkyrie_reg_init_14 = {
+    14,
+    { 15, 31, 3 },  /* pixel clock = 64.58MHz for V=59.62Hz */
+    { 1024, 0 },
+	1024, 768
+};
+
+/* Register values for 800x600, 72Hz mode (11) */
+static struct valkyrie_regvals valkyrie_reg_init_11 = {
+    13,
+    { 17, 27, 3 },  /* pixel clock = 49.63MHz for V=71.66Hz */
+    { 800, 0 },
+	800, 600
+};
+#endif /* CONFIG_MAC */
+
+/* Register values for 832x624, 75Hz mode (13) */
+static struct valkyrie_regvals valkyrie_reg_init_13 = {
+    9,
+    { 23, 42, 3 },  /* pixel clock = 57.07MHz for V=74.27Hz */
+    { 832, 0 },
+	832, 624
+};
+
+/* Register values for 800x600, 60Hz mode (10) */
+static struct valkyrie_regvals valkyrie_reg_init_10 = {
+    12,
+    { 25, 32, 3 },  /* pixel clock = 40.0015MHz,
+                     used to be 20,53,2, pixel clock 41.41MHz for V=59.78Hz */
+    { 800, 1600 },
+	800, 600
+};
+
+/* Register values for 640x480, 67Hz mode (6) */
+static struct valkyrie_regvals valkyrie_reg_init_6 = {
+    6,
+    { 14, 27, 2 },  /* pixel clock = 30.13MHz for V=66.43Hz */
+    { 640, 1280 },
+	640, 480
+};
+
+/* Register values for 640x480, 60Hz mode (5) */
+static struct valkyrie_regvals valkyrie_reg_init_5 = {
+    11,
+    { 23, 37, 2 },  /* pixel clock = 25.14MHz for V=59.85Hz */
+    { 640, 1280 },
+	640, 480
+};
+
+static struct valkyrie_regvals *valkyrie_reg_init[VMODE_MAX] = {
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	&valkyrie_reg_init_5,
+	&valkyrie_reg_init_6,
+	NULL,
+	NULL,
+	NULL,
+	&valkyrie_reg_init_10,
+#ifdef CONFIG_MAC
+	NULL,
+	NULL,
+	&valkyrie_reg_init_13,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+#else
+	&valkyrie_reg_init_11,
+	NULL,
+	&valkyrie_reg_init_13,
+	&valkyrie_reg_init_14,
+	&valkyrie_reg_init_15,
+	NULL,
+	&valkyrie_reg_init_17,
+#endif
+	NULL,
+	NULL,
+	NULL
+};
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
new file mode 100644
index 0000000..8fc1278
--- /dev/null
+++ b/drivers/video/vesafb.c
@@ -0,0 +1,456 @@
+/*
+ * framebuffer driver for VBE 2.0 compliant graphic boards
+ *
+ * switching to graphics mode happens at boot time (while
+ * running in real mode, see arch/i386/boot/video.S).
+ *
+ * (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ */
+
+#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/delay.h>
+#include <linux/fb.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#ifdef __i386__
+#include <video/edid.h>
+#endif
+#include <asm/io.h>
+#include <asm/mtrr.h>
+
+#define dac_reg	(0x3c8)
+#define dac_val	(0x3c9)
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_var_screeninfo vesafb_defined __initdata = {
+	.activate	= FB_ACTIVATE_NOW,
+	.height		= -1,
+	.width		= -1,
+	.right_margin	= 32,
+	.upper_margin	= 16,
+	.lower_margin	= 4,
+	.vsync_len	= 4,
+	.vmode		= FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_fix_screeninfo vesafb_fix __initdata = {
+	.id	= "VESA VGA",
+	.type	= FB_TYPE_PACKED_PIXELS,
+	.accel	= FB_ACCEL_NONE,
+};
+
+static int             inverse   = 0;
+static int             mtrr      = 1;
+static int	       vram_remap __initdata = 0; /* Set amount of memory to be used */
+static int	       vram_total __initdata = 0; /* Set total amount of memory */
+static int             pmi_setpal = 0;	/* pmi for palette changes ??? */
+static int             ypan       = 0;  /* 0..nothing, 1..ypan, 2..ywrap */
+static unsigned short  *pmi_base  = NULL;
+static void            (*pmi_start)(void);
+static void            (*pmi_pal)(void);
+static int             depth;
+
+/* --------------------------------------------------------------------- */
+
+static int vesafb_pan_display(struct fb_var_screeninfo *var,
+                              struct fb_info *info)
+{
+#ifdef __i386__
+	int offset;
+
+	if (!ypan)
+		return -EINVAL;
+	if (var->xoffset)
+		return -EINVAL;
+	if (var->yoffset > var->yres_virtual)
+		return -EINVAL;
+	if ((ypan==1) && var->yoffset+var->yres > var->yres_virtual)
+		return -EINVAL;
+
+	offset = (var->yoffset * info->fix.line_length + var->xoffset) / 4;
+
+        __asm__ __volatile__(
+                "call *(%%edi)"
+                : /* no return value */
+                : "a" (0x4f07),         /* EAX */
+                  "b" (0),              /* EBX */
+                  "c" (offset),         /* ECX */
+                  "d" (offset >> 16),   /* EDX */
+                  "D" (&pmi_start));    /* EDI */
+#endif
+	return 0;
+}
+
+static void vesa_setpalette(int regno, unsigned red, unsigned green,
+			    unsigned blue)
+{
+#ifdef __i386__
+	struct { u_char blue, green, red, pad; } entry;
+	int shift = 16 - depth;
+
+	if (pmi_setpal) {
+		entry.red   = red   >> shift;
+		entry.green = green >> shift;
+		entry.blue  = blue  >> shift;
+		entry.pad   = 0;
+	        __asm__ __volatile__(
+                "call *(%%esi)"
+                : /* no return value */
+                : "a" (0x4f09),         /* EAX */
+                  "b" (0),              /* EBX */
+                  "c" (1),              /* ECX */
+                  "d" (regno),          /* EDX */
+                  "D" (&entry),         /* EDI */
+                  "S" (&pmi_pal));      /* ESI */
+	} else {
+		/* without protected mode interface, try VGA registers... */
+		outb_p(regno,       dac_reg);
+		outb_p(red   >> shift, dac_val);
+		outb_p(green >> shift, dac_val);
+		outb_p(blue  >> shift, dac_val);
+	}
+#endif
+}
+
+static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			    unsigned blue, unsigned transp,
+			    struct fb_info *info)
+{
+	/*
+	 *  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.
+	 */
+	
+	if (regno >= info->cmap.len)
+		return 1;
+
+	switch (info->var.bits_per_pixel) {
+	case 8:
+		vesa_setpalette(regno,red,green,blue);
+		break;
+	case 16:
+		if (info->var.red.offset == 10) {
+			/* 1:5:5:5 */
+			((u32*) (info->pseudo_palette))[regno] =	
+					((red   & 0xf800) >>  1) |
+					((green & 0xf800) >>  6) |
+					((blue  & 0xf800) >> 11);
+		} else {
+			/* 0:5:6:5 */
+			((u32*) (info->pseudo_palette))[regno] =	
+					((red   & 0xf800)      ) |
+					((green & 0xfc00) >>  5) |
+					((blue  & 0xf800) >> 11);
+		}
+		break;
+	case 24:
+		red   >>= 8;
+		green >>= 8;
+		blue  >>= 8;
+		((u32 *)(info->pseudo_palette))[regno] =
+			(red   << info->var.red.offset)   |
+			(green << info->var.green.offset) |
+			(blue  << info->var.blue.offset);
+		break;
+	case 32:
+		red   >>= 8;
+		green >>= 8;
+		blue  >>= 8;
+		((u32 *)(info->pseudo_palette))[regno] =
+			(red   << info->var.red.offset)   |
+			(green << info->var.green.offset) |
+			(blue  << info->var.blue.offset);
+		break;
+    }
+    return 0;
+}
+
+static struct fb_ops vesafb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_setcolreg	= vesafb_setcolreg,
+	.fb_pan_display	= vesafb_pan_display,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+static int __init vesafb_setup(char *options)
+{
+	char *this_opt;
+	
+	if (!options || !*options)
+		return 0;
+	
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt) continue;
+		
+		if (! strcmp(this_opt, "inverse"))
+			inverse=1;
+		else if (! strcmp(this_opt, "redraw"))
+			ypan=0;
+		else if (! strcmp(this_opt, "ypan"))
+			ypan=1;
+		else if (! strcmp(this_opt, "ywrap"))
+			ypan=2;
+		else if (! strcmp(this_opt, "vgapal"))
+			pmi_setpal=0;
+		else if (! strcmp(this_opt, "pmipal"))
+			pmi_setpal=1;
+		else if (! strcmp(this_opt, "mtrr"))
+			mtrr=1;
+		else if (! strcmp(this_opt, "nomtrr"))
+			mtrr=0;
+		else if (! strncmp(this_opt, "vtotal:", 7))
+			vram_total = simple_strtoul(this_opt+7, NULL, 0);
+		else if (! strncmp(this_opt, "vremap:", 7))
+			vram_remap = simple_strtoul(this_opt+7, NULL, 0);
+	}
+	return 0;
+}
+
+static int __init vesafb_probe(struct device *device)
+{
+	struct platform_device *dev = to_platform_device(device);
+	struct fb_info *info;
+	int i, err;
+	unsigned int size_vmode;
+	unsigned int size_remap;
+	unsigned int size_total;
+
+	if (screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB)
+		return -ENODEV;
+
+	vesafb_fix.smem_start = screen_info.lfb_base;
+	vesafb_defined.bits_per_pixel = screen_info.lfb_depth;
+	if (15 == vesafb_defined.bits_per_pixel)
+		vesafb_defined.bits_per_pixel = 16;
+	vesafb_defined.xres = screen_info.lfb_width;
+	vesafb_defined.yres = screen_info.lfb_height;
+	vesafb_fix.line_length = screen_info.lfb_linelength;
+	vesafb_fix.visual   = (vesafb_defined.bits_per_pixel == 8) ?
+		FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+
+	/*   size_vmode -- that is the amount of memory needed for the
+	 *                 used video mode, i.e. the minimum amount of
+	 *                 memory we need. */
+	size_vmode = vesafb_defined.yres * vesafb_fix.line_length;
+
+	/*   size_total -- all video memory we have. Used for mtrr
+	 *                 entries, ressource allocation and bounds
+	 *                 checking. */
+	size_total = screen_info.lfb_size * 65536;
+	if (vram_total)
+		size_total = vram_total * 1024 * 1024;
+	if (size_total < size_vmode)
+		size_total = size_vmode;
+
+	/*   size_remap -- the amount of video memory we are going to
+	 *                 use for vesafb.  With modern cards it is no
+	 *                 option to simply use size_total as that
+	 *                 wastes plenty of kernel address space. */
+	size_remap  = size_vmode * 2;
+	if (vram_remap)
+		size_remap = vram_remap * 1024 * 1024;
+	if (size_remap < size_vmode)
+		size_remap = size_vmode;
+	if (size_remap > size_total)
+		size_remap = size_total;
+	vesafb_fix.smem_len = size_remap;
+
+#ifndef __i386__
+	screen_info.vesapm_seg = 0;
+#endif
+
+	if (!request_mem_region(vesafb_fix.smem_start, size_total, "vesafb")) {
+		printk(KERN_WARNING
+		       "vesafb: abort, cannot reserve video memory at 0x%lx\n",
+			vesafb_fix.smem_start);
+		/* We cannot make this fatal. Sometimes this comes from magic
+		   spaces our resource handlers simply don't know about */
+	}
+
+	info = framebuffer_alloc(sizeof(u32) * 256, &dev->dev);
+	if (!info) {
+		release_mem_region(vesafb_fix.smem_start, vesafb_fix.smem_len);
+		return -ENOMEM;
+	}
+	info->pseudo_palette = info->par;
+	info->par = NULL;
+
+        info->screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len);
+	if (!info->screen_base) {
+		printk(KERN_ERR
+		       "vesafb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n",
+			vesafb_fix.smem_len, vesafb_fix.smem_start);
+		err = -EIO;
+		goto err;
+	}
+
+	printk(KERN_INFO "vesafb: framebuffer at 0x%lx, mapped to 0x%p, "
+	       "using %dk, total %dk\n",
+	       vesafb_fix.smem_start, info->screen_base,
+	       size_remap/1024, size_total/1024);
+	printk(KERN_INFO "vesafb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
+	       vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel, vesafb_fix.line_length, screen_info.pages);
+
+	if (screen_info.vesapm_seg) {
+		printk(KERN_INFO "vesafb: protected mode interface info at %04x:%04x\n",
+		       screen_info.vesapm_seg,screen_info.vesapm_off);
+	}
+
+	if (screen_info.vesapm_seg < 0xc000)
+		ypan = pmi_setpal = 0; /* not available or some DOS TSR ... */
+
+	if (ypan || pmi_setpal) {
+		pmi_base  = (unsigned short*)phys_to_virt(((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off);
+		pmi_start = (void*)((char*)pmi_base + pmi_base[1]);
+		pmi_pal   = (void*)((char*)pmi_base + pmi_base[2]);
+		printk(KERN_INFO "vesafb: pmi: set display start = %p, set palette = %p\n",pmi_start,pmi_pal);
+		if (pmi_base[3]) {
+			printk(KERN_INFO "vesafb: pmi: ports = ");
+				for (i = pmi_base[3]/2; pmi_base[i] != 0xffff; i++)
+					printk("%x ",pmi_base[i]);
+			printk("\n");
+			if (pmi_base[i] != 0xffff) {
+				/*
+				 * memory areas not supported (yet?)
+				 *
+				 * Rules are: we have to set up a descriptor for the requested
+				 * memory area and pass it in the ES register to the BIOS function.
+				 */
+				printk(KERN_INFO "vesafb: can't handle memory requests, pmi disabled\n");
+				ypan = pmi_setpal = 0;
+			}
+		}
+	}
+
+	vesafb_defined.xres_virtual = vesafb_defined.xres;
+	vesafb_defined.yres_virtual = vesafb_fix.smem_len / vesafb_fix.line_length;
+	if (ypan && vesafb_defined.yres_virtual > vesafb_defined.yres) {
+		printk(KERN_INFO "vesafb: scrolling: %s using protected mode interface, yres_virtual=%d\n",
+		       (ypan > 1) ? "ywrap" : "ypan",vesafb_defined.yres_virtual);
+	} else {
+		printk(KERN_INFO "vesafb: scrolling: redraw\n");
+		vesafb_defined.yres_virtual = vesafb_defined.yres;
+		ypan = 0;
+	}
+
+	/* some dummy values for timing to make fbset happy */
+	vesafb_defined.pixclock     = 10000000 / vesafb_defined.xres * 1000 / vesafb_defined.yres;
+	vesafb_defined.left_margin  = (vesafb_defined.xres / 8) & 0xf8;
+	vesafb_defined.hsync_len    = (vesafb_defined.xres / 8) & 0xf8;
+	
+	vesafb_defined.red.offset    = screen_info.red_pos;
+	vesafb_defined.red.length    = screen_info.red_size;
+	vesafb_defined.green.offset  = screen_info.green_pos;
+	vesafb_defined.green.length  = screen_info.green_size;
+	vesafb_defined.blue.offset   = screen_info.blue_pos;
+	vesafb_defined.blue.length   = screen_info.blue_size;
+	vesafb_defined.transp.offset = screen_info.rsvd_pos;
+	vesafb_defined.transp.length = screen_info.rsvd_size;
+
+	if (vesafb_defined.bits_per_pixel <= 8) {
+		depth = vesafb_defined.green.length;
+		vesafb_defined.red.length =
+		vesafb_defined.green.length =
+		vesafb_defined.blue.length =
+		vesafb_defined.bits_per_pixel;
+	}
+
+	printk(KERN_INFO "vesafb: %s: "
+	       "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
+	       (vesafb_defined.bits_per_pixel > 8) ?
+	       "Truecolor" : "Pseudocolor",
+	       screen_info.rsvd_size,
+	       screen_info.red_size,
+	       screen_info.green_size,
+	       screen_info.blue_size,
+	       screen_info.rsvd_pos,
+	       screen_info.red_pos,
+	       screen_info.green_pos,
+	       screen_info.blue_pos);
+
+	vesafb_fix.ypanstep  = ypan     ? 1 : 0;
+	vesafb_fix.ywrapstep = (ypan>1) ? 1 : 0;
+
+	/* request failure does not faze us, as vgacon probably has this
+	 * region already (FIXME) */
+	request_region(0x3c0, 32, "vesafb");
+
+	if (mtrr) {
+		int temp_size = size_total;
+		/* Find the largest power-of-two */
+		while (temp_size & (temp_size - 1))
+                	temp_size &= (temp_size - 1);
+                        
+                /* Try and find a power of two to add */
+		while (temp_size && mtrr_add(vesafb_fix.smem_start, temp_size, MTRR_TYPE_WRCOMB, 1)==-EINVAL) {
+			temp_size >>= 1;
+		}
+	}
+	
+	info->fbops = &vesafb_ops;
+	info->var = vesafb_defined;
+	info->fix = vesafb_fix;
+	info->flags = FBINFO_FLAG_DEFAULT |
+		(ypan) ? FBINFO_HWACCEL_YPAN : 0;
+
+	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+		err = -ENOMEM;
+		goto err;
+	}
+	if (register_framebuffer(info)<0) {
+		err = -EINVAL;
+		fb_dealloc_cmap(&info->cmap);
+		goto err;
+	}
+	printk(KERN_INFO "fb%d: %s frame buffer device\n",
+	       info->node, info->fix.id);
+	return 0;
+err:
+	framebuffer_release(info);
+	release_mem_region(vesafb_fix.smem_start, size_total);
+	return err;
+}
+
+static struct device_driver vesafb_driver = {
+	.name	= "vesafb",
+	.bus	= &platform_bus_type,
+	.probe	= vesafb_probe,
+};
+
+static struct platform_device vesafb_device = {
+	.name	= "vesafb",
+};
+
+static int __init vesafb_init(void)
+{
+	int ret;
+	char *option = NULL;
+
+	/* ignore error return of fb_get_options */
+	fb_get_options("vesafb", &option);
+	vesafb_setup(option);
+	ret = driver_register(&vesafb_driver);
+
+	if (!ret) {
+		ret = platform_device_register(&vesafb_device);
+		if (ret)
+			driver_unregister(&vesafb_driver);
+	}
+	return ret;
+}
+module_init(vesafb_init);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c
new file mode 100644
index 0000000..b137a3f
--- /dev/null
+++ b/drivers/video/vfb.c
@@ -0,0 +1,528 @@
+/*
+ *  linux/drivers/video/vfb.c -- Virtual frame buffer device
+ *
+ *      Copyright (C) 2002 James Simmons
+ *
+ *	Copyright (C) 1997 Geert Uytterhoeven
+ *
+ *  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/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>
+
+    /*
+     *  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
+     */
+
+#define VIDEOMEMSIZE	(1*1024*1024)	/* 1 MB */
+
+static void *videomemory;
+static u_long videomemorysize = VIDEOMEMSIZE;
+module_param(videomemorysize, ulong, 0);
+
+static struct fb_var_screeninfo vfb_default __initdata = {
+	.xres =		640,
+	.yres =		480,
+	.xres_virtual =	640,
+	.yres_virtual =	480,
+	.bits_per_pixel = 8,
+	.red =		{ 0, 8, 0 },
+      	.green =	{ 0, 8, 0 },
+      	.blue =		{ 0, 8, 0 },
+      	.activate =	FB_ACTIVATE_TEST,
+      	.height =	-1,
+      	.width =	-1,
+      	.pixclock =	20000,
+      	.left_margin =	64,
+      	.right_margin =	64,
+      	.upper_margin =	32,
+      	.lower_margin =	32,
+      	.hsync_len =	64,
+      	.vsync_len =	2,
+      	.vmode =	FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_fix_screeninfo vfb_fix __initdata = {
+	.id =		"Virtual FB",
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_PSEUDOCOLOR,
+	.xpanstep =	1,
+	.ypanstep =	1,
+	.ywrapstep =	1,
+	.accel =	FB_ACCEL_NONE,
+};
+
+static int vfb_enable __initdata = 0;	/* disabled by default */
+module_param(vfb_enable, bool, 0);
+
+static int vfb_check_var(struct fb_var_screeninfo *var,
+			 struct fb_info *info);
+static int vfb_set_par(struct fb_info *info);
+static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			 u_int transp, struct fb_info *info);
+static int vfb_pan_display(struct fb_var_screeninfo *var,
+			   struct fb_info *info);
+static int vfb_mmap(struct fb_info *info, struct file *file,
+		    struct vm_area_struct *vma);
+
+static struct fb_ops vfb_ops = {
+	.fb_check_var	= vfb_check_var,
+	.fb_set_par	= vfb_set_par,
+	.fb_setcolreg	= vfb_setcolreg,
+	.fb_pan_display	= vfb_pan_display,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+	.fb_mmap	= vfb_mmap,
+};
+
+    /*
+     *  Internal routines
+     */
+
+static u_long get_line_length(int xres_virtual, int bpp)
+{
+	u_long length;
+
+	length = xres_virtual * bpp;
+	length = (length + 31) & ~31;
+	length >>= 3;
+	return (length);
+}
+
+    /*
+     *  Setting the video mode has been split into two parts.
+     *  First part, xxxfb_check_var, must not write anything
+     *  to hardware, it should only verify and adjust var.
+     *  This means it doesn't alter par but it does use hardware
+     *  data from it to check this var. 
+     */
+
+static int vfb_check_var(struct fb_var_screeninfo *var,
+			 struct fb_info *info)
+{
+	u_long line_length;
+
+	/*
+	 *  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 = info->var.xoffset;
+		var->yoffset = info->var.yoffset;
+	}
+
+	/*
+	 *  Some very basic checks
+	 */
+	if (!var->xres)
+		var->xres = 1;
+	if (!var->yres)
+		var->yres = 1;
+	if (var->xres > var->xres_virtual)
+		var->xres_virtual = var->xres;
+	if (var->yres > var->yres_virtual)
+		var->yres_virtual = var->yres;
+	if (var->bits_per_pixel <= 1)
+		var->bits_per_pixel = 1;
+	else 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 <= 24)
+		var->bits_per_pixel = 24;
+	else if (var->bits_per_pixel <= 32)
+		var->bits_per_pixel = 32;
+	else
+		return -EINVAL;
+
+	if (var->xres_virtual < var->xoffset + var->xres)
+		var->xres_virtual = var->xoffset + var->xres;
+	if (var->yres_virtual < var->yoffset + var->yres)
+		var->yres_virtual = var->yoffset + var->yres;
+
+	/*
+	 *  Memory limit
+	 */
+	line_length =
+	    get_line_length(var->xres_virtual, var->bits_per_pixel);
+	if (line_length * var->yres_virtual > videomemorysize)
+		return -ENOMEM;
+
+	/*
+	 * Now that we checked it we alter var. The reason being is that the video
+	 * mode passed in might not work but slight changes to it might make it 
+	 * work. This way we let the user know what is acceptable.
+	 */
+	switch (var->bits_per_pixel) {
+	case 1:
+	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 */
+		if (var->transp.length) {
+			var->red.offset = 0;
+			var->red.length = 5;
+			var->green.offset = 5;
+			var->green.length = 5;
+			var->blue.offset = 10;
+			var->blue.length = 5;
+			var->transp.offset = 15;
+			var->transp.length = 1;
+		} else {	/* RGB 565 */
+			var->red.offset = 0;
+			var->red.length = 5;
+			var->green.offset = 5;
+			var->green.length = 6;
+			var->blue.offset = 11;
+			var->blue.length = 5;
+			var->transp.offset = 0;
+			var->transp.length = 0;
+		}
+		break;
+	case 24:		/* RGB 888 */
+		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 = 0;
+		var->transp.length = 0;
+		break;
+	case 32:		/* RGBA 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;
+
+	return 0;
+}
+
+/* This routine actually sets the video mode. It's in here where we
+ * the hardware state info->par and fix which can be affected by the 
+ * change in par. For this driver it doesn't do much. 
+ */
+static int vfb_set_par(struct fb_info *info)
+{
+	info->fix.line_length = get_line_length(info->var.xres_virtual,
+						info->var.bits_per_pixel);
+	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 vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			 u_int transp, struct fb_info *info)
+{
+	if (regno >= 256)	/* no. of hw registers */
+		return 1;
+	/*
+	 * Program hardware... do anything you want with transp
+	 */
+
+	/* grayscale works only partially under directcolor */
+	if (info->var.grayscale) {
+		/* grayscale = 0.30*R + 0.59*G + 0.11*B */
+		red = green = blue =
+		    (red * 77 + green * 151 + blue * 28) >> 8;
+	}
+
+	/* Directcolor:
+	 *   var->{color}.offset contains start of bitfield
+	 *   var->{color}.length contains length of bitfield
+	 *   {hardwarespecific} contains width of RAMDAC
+	 *   cmap[X] is programmed to (X << red.offset) | (X << green.offset) | (X << blue.offset)
+	 *   RAMDAC[X] is programmed to (red, green, blue)
+	 * 
+	 * Pseudocolor:
+	 *    uses offset = 0 && length = RAMDAC register width.
+	 *    var->{color}.offset is 0
+	 *    var->{color}.length contains widht of DAC
+	 *    cmap is not used
+	 *    RAMDAC[X] is programmed to (red, green, blue)
+	 * Truecolor:
+	 *    does not use DAC. Usually 3 are present.
+	 *    var->{color}.offset contains start of bitfield
+	 *    var->{color}.length contains length of bitfield
+	 *    cmap is programmed to (red << red.offset) | (green << green.offset) |
+	 *                      (blue << blue.offset) | (transp << transp.offset)
+	 *    RAMDAC does not exist
+	 */
+#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+	switch (info->fix.visual) {
+	case FB_VISUAL_TRUECOLOR:
+	case FB_VISUAL_PSEUDOCOLOR:
+		red = CNVT_TOHW(red, info->var.red.length);
+		green = CNVT_TOHW(green, info->var.green.length);
+		blue = CNVT_TOHW(blue, info->var.blue.length);
+		transp = CNVT_TOHW(transp, info->var.transp.length);
+		break;
+	case FB_VISUAL_DIRECTCOLOR:
+		red = CNVT_TOHW(red, 8);	/* expect 8 bit DAC */
+		green = CNVT_TOHW(green, 8);
+		blue = CNVT_TOHW(blue, 8);
+		/* hey, there is bug in transp handling... */
+		transp = CNVT_TOHW(transp, 8);
+		break;
+	}
+#undef CNVT_TOHW
+	/* Truecolor has hardware independent palette */
+	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+		u32 v;
+
+		if (regno >= 16)
+			return 1;
+
+		v = (red << info->var.red.offset) |
+		    (green << info->var.green.offset) |
+		    (blue << info->var.blue.offset) |
+		    (transp << info->var.transp.offset);
+		switch (info->var.bits_per_pixel) {
+		case 8:
+			break;
+		case 16:
+			((u32 *) (info->pseudo_palette))[regno] = v;
+			break;
+		case 24:
+		case 32:
+			((u32 *) (info->pseudo_palette))[regno] = v;
+			break;
+		}
+		return 0;
+	}
+	return 0;
+}
+
+    /*
+     *  Pan or Wrap the Display
+     *
+     *  This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
+     */
+
+static int vfb_pan_display(struct fb_var_screeninfo *var,
+			   struct fb_info *info)
+{
+	if (var->vmode & FB_VMODE_YWRAP) {
+		if (var->yoffset < 0
+		    || var->yoffset >= info->var.yres_virtual
+		    || var->xoffset)
+			return -EINVAL;
+	} else {
+		if (var->xoffset + var->xres > info->var.xres_virtual ||
+		    var->yoffset + var->yres > info->var.yres_virtual)
+			return -EINVAL;
+	}
+	info->var.xoffset = var->xoffset;
+	info->var.yoffset = var->yoffset;
+	if (var->vmode & FB_VMODE_YWRAP)
+		info->var.vmode |= FB_VMODE_YWRAP;
+	else
+		info->var.vmode &= ~FB_VMODE_YWRAP;
+	return 0;
+}
+
+    /*
+     *  Most drivers don't need their own mmap function 
+     */
+
+static int vfb_mmap(struct fb_info *info, struct file *file,
+		    struct vm_area_struct *vma)
+{
+	return -EINVAL;
+}
+
+#ifndef MODULE
+static int __init vfb_setup(char *options)
+{
+	char *this_opt;
+
+	vfb_enable = 1;
+
+	if (!options || !*options)
+		return 1;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt)
+			continue;
+		if (!strncmp(this_opt, "disable", 7))
+			vfb_enable = 0;
+	}
+	return 1;
+}
+#endif  /*  MODULE  */
+
+    /*
+     *  Initialisation
+     */
+
+static void vfb_platform_release(struct device *device)
+{
+	// This is called when the reference count goes to zero.
+}
+
+static int __init vfb_probe(struct device *device)
+{
+	struct platform_device *dev = to_platform_device(device);
+	struct fb_info *info;
+	int retval = -ENOMEM;
+
+	/*
+	 * For real video cards we use ioremap.
+	 */
+	if (!(videomemory = vmalloc(videomemorysize)))
+		return retval;
+
+	/*
+	 * VFB must clear memory to prevent kernel info
+	 * leakage into userspace
+	 * VGA-based drivers MUST NOT clear memory if
+	 * they want to be able to take over vgacon
+	 */
+	memset(videomemory, 0, videomemorysize);
+
+	info = framebuffer_alloc(sizeof(u32) * 256, &dev->dev);
+	if (!info)
+		goto err;
+
+	info->screen_base = (char __iomem *)videomemory;
+	info->fbops = &vfb_ops;
+
+	retval = fb_find_mode(&info->var, info, NULL,
+			      NULL, 0, NULL, 8);
+
+	if (!retval || (retval == 4))
+		info->var = vfb_default;
+	info->fix = vfb_fix;
+	info->pseudo_palette = info->par;
+	info->par = NULL;
+	info->flags = FBINFO_FLAG_DEFAULT;
+
+	retval = fb_alloc_cmap(&info->cmap, 256, 0);
+	if (retval < 0)
+		goto err1;
+
+	retval = register_framebuffer(info);
+	if (retval < 0)
+		goto err2;
+	dev_set_drvdata(&dev->dev, info);
+
+	printk(KERN_INFO
+	       "fb%d: Virtual frame buffer device, using %ldK of video memory\n",
+	       info->node, videomemorysize >> 10);
+	return 0;
+err2:
+	fb_dealloc_cmap(&info->cmap);
+err1:
+	framebuffer_release(info);
+err:
+	vfree(videomemory);
+	return retval;
+}
+
+static int vfb_remove(struct device *device)
+{
+	struct fb_info *info = dev_get_drvdata(device);
+
+	if (info) {
+		unregister_framebuffer(info);
+		vfree(videomemory);
+		framebuffer_release(info);
+	}
+	return 0;
+}
+
+static struct device_driver vfb_driver = {
+	.name	= "vfb",
+	.bus	= &platform_bus_type,
+	.probe	= vfb_probe,
+	.remove = vfb_remove,
+};
+
+static struct platform_device vfb_device = {
+	.name	= "vfb",
+	.id	= 0,
+	.dev	= {
+		.release = vfb_platform_release,
+	}
+};
+
+static int __init vfb_init(void)
+{
+	int ret = 0;
+
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("vfb", &option))
+		return -ENODEV;
+	vfb_setup(option);
+#endif
+
+	if (!vfb_enable)
+		return -ENXIO;
+
+	ret = driver_register(&vfb_driver);
+
+	if (!ret) {
+		ret = platform_device_register(&vfb_device);
+		if (ret)
+			driver_unregister(&vfb_driver);
+	}
+	return ret;
+}
+
+module_init(vfb_init);
+
+#ifdef MODULE
+static void __exit vfb_exit(void)
+{
+	platform_device_unregister(&vfb_device);
+	driver_unregister(&vfb_driver);
+}
+
+module_exit(vfb_exit);
+
+MODULE_LICENSE("GPL");
+#endif				/* MODULE */
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c
new file mode 100644
index 0000000..b46454c
--- /dev/null
+++ b/drivers/video/vga16fb.c
@@ -0,0 +1,1444 @@
+/*
+ * linux/drivers/video/vga16.c -- VGA 16-color framebuffer driver
+ * 
+ * Copyright 1999 Ben Pfaff <pfaffben@debian.org> and Petr Vandrovec <VANDROVE@vc.cvut.cz>
+ * Based on VGA info at http://www.goodnet.com/~tinara/FreeVGA/home.htm
+ * Based on VESA framebuffer (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ * 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/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/delay.h>
+#include <linux/fb.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <video/vga.h>
+
+#define GRAPHICS_ADDR_REG VGA_GFX_I	/* Graphics address register. */
+#define GRAPHICS_DATA_REG VGA_GFX_D	/* Graphics data register. */
+
+#define SET_RESET_INDEX 	VGA_GFX_SR_VALUE	/* Set/Reset Register index. */
+#define ENABLE_SET_RESET_INDEX	VGA_GFX_SR_ENABLE	/* Enable Set/Reset Register index. */
+#define DATA_ROTATE_INDEX	VGA_GFX_DATA_ROTATE	/* Data Rotate Register index. */
+#define GRAPHICS_MODE_INDEX	VGA_GFX_MODE		/* Graphics Mode Register index. */
+#define BIT_MASK_INDEX		VGA_GFX_BIT_MASK	/* Bit Mask Register index. */
+
+#define dac_reg	(VGA_PEL_IW)
+#define dac_val	(VGA_PEL_D)
+
+#define VGA_FB_PHYS 0xA0000
+#define VGA_FB_PHYS_LEN 65536
+
+#define MODE_SKIP4	1
+#define MODE_8BPP	2
+#define MODE_CFB	4
+#define MODE_TEXT	8
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * card parameters
+ */
+
+static struct fb_info vga16fb; 
+
+static struct vga16fb_par {
+	/* structure holding original VGA register settings when the
+           screen is blanked */
+	struct {
+		unsigned char	SeqCtrlIndex;		/* Sequencer Index reg.   */
+		unsigned char	CrtCtrlIndex;		/* CRT-Contr. Index reg.  */
+		unsigned char	CrtMiscIO;		/* Miscellaneous register */
+		unsigned char	HorizontalTotal;	/* CRT-Controller:00h */
+		unsigned char	HorizDisplayEnd;	/* CRT-Controller:01h */
+		unsigned char	StartHorizRetrace;	/* CRT-Controller:04h */
+		unsigned char	EndHorizRetrace;	/* CRT-Controller:05h */
+		unsigned char	Overflow;		/* CRT-Controller:07h */
+		unsigned char	StartVertRetrace;	/* CRT-Controller:10h */
+		unsigned char	EndVertRetrace;		/* CRT-Controller:11h */
+		unsigned char	ModeControl;		/* CRT-Controller:17h */
+		unsigned char	ClockingMode;		/* Seq-Controller:01h */
+	} vga_state;
+	struct vgastate state;
+	atomic_t ref_count;
+	int palette_blanked, vesa_blanked, mode, isVGA;
+	u8 misc, pel_msk, vss, clkdiv;
+	u8 crtc[VGA_CRT_C];
+} vga16_par;
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_var_screeninfo vga16fb_defined = {
+	.xres		= 640,
+	.yres		= 480,
+	.xres_virtual	= 640,
+	.yres_virtual	= 480,
+	.bits_per_pixel	= 4,	
+	.activate	= FB_ACTIVATE_TEST,
+	.height		= -1,
+	.width		= -1,
+	.pixclock	= 39721,
+	.left_margin	= 48,
+	.right_margin	= 16,
+	.upper_margin	= 33,
+	.lower_margin	= 10,
+	.hsync_len 	= 96,
+	.vsync_len	= 2,
+	.vmode		= FB_VMODE_NONINTERLACED,
+};
+
+/* name should not depend on EGA/VGA */
+static struct fb_fix_screeninfo vga16fb_fix __initdata = {
+	.id		= "VGA16 VGA",
+	.smem_start	= VGA_FB_PHYS,
+	.smem_len	= VGA_FB_PHYS_LEN,
+	.type		= FB_TYPE_VGA_PLANES,
+	.type_aux	= FB_AUX_VGA_PLANES_VGA4,
+	.visual		= FB_VISUAL_PSEUDOCOLOR,
+	.xpanstep	= 8,
+	.ypanstep	= 1,
+	.line_length	= 640/8,
+	.accel		= FB_ACCEL_NONE
+};
+
+/* The VGA's weird architecture often requires that we read a byte and
+   write a byte to the same location.  It doesn't matter *what* byte
+   we write, however.  This is because all the action goes on behind
+   the scenes in the VGA's 32-bit latch register, and reading and writing
+   video memory just invokes latch behavior.
+
+   To avoid race conditions (is this necessary?), reading and writing
+   the memory byte should be done with a single instruction.  One
+   suitable instruction is the x86 bitwise OR.  The following
+   read-modify-write routine should optimize to one such bitwise
+   OR. */
+static inline void rmw(volatile char __iomem *p)
+{
+	readb(p);
+	writeb(1, p);
+}
+
+/* Set the Graphics Mode Register, and return its previous value.
+   Bits 0-1 are write mode, bit 3 is read mode. */
+static inline int setmode(int mode)
+{
+	int oldmode;
+	
+	vga_io_w(GRAPHICS_ADDR_REG, GRAPHICS_MODE_INDEX);
+	oldmode = vga_io_r(GRAPHICS_DATA_REG);
+	vga_io_w(GRAPHICS_DATA_REG, mode);
+	return oldmode;
+}
+
+/* Select the Bit Mask Register and return its value. */
+static inline int selectmask(void)
+{
+	return vga_io_rgfx(BIT_MASK_INDEX);
+}
+
+/* Set the value of the Bit Mask Register.  It must already have been
+   selected with selectmask(). */
+static inline void setmask(int mask)
+{
+	vga_io_w(GRAPHICS_DATA_REG, mask);
+}
+
+/* Set the Data Rotate Register and return its old value. 
+   Bits 0-2 are rotate count, bits 3-4 are logical operation
+   (0=NOP, 1=AND, 2=OR, 3=XOR). */
+static inline int setop(int op)
+{
+	int oldop;
+	
+	vga_io_w(GRAPHICS_ADDR_REG, DATA_ROTATE_INDEX);
+	oldop = vga_io_r(GRAPHICS_DATA_REG);
+	vga_io_w(GRAPHICS_DATA_REG, op);
+	return oldop;
+}
+
+/* Set the Enable Set/Reset Register and return its old value.  
+   The code here always uses value 0xf for thsi register. */
+static inline int setsr(int sr)
+{
+	int oldsr;
+
+	vga_io_w(GRAPHICS_ADDR_REG, ENABLE_SET_RESET_INDEX);
+	oldsr = vga_io_r(GRAPHICS_DATA_REG);
+	vga_io_w(GRAPHICS_DATA_REG, sr);
+	return oldsr;
+}
+
+/* Set the Set/Reset Register and return its old value. */
+static inline int setcolor(int color)
+{
+	int oldcolor;
+
+	vga_io_w(GRAPHICS_ADDR_REG, SET_RESET_INDEX);
+	oldcolor = vga_io_r(GRAPHICS_DATA_REG);
+	vga_io_w(GRAPHICS_DATA_REG, color);
+	return oldcolor;
+}
+
+/* Return the value in the Graphics Address Register. */
+static inline int getindex(void)
+{
+	return vga_io_r(GRAPHICS_ADDR_REG);
+}
+
+/* Set the value in the Graphics Address Register. */
+static inline void setindex(int index)
+{
+	vga_io_w(GRAPHICS_ADDR_REG, index);
+}
+
+static void vga16fb_pan_var(struct fb_info *info, 
+			    struct fb_var_screeninfo *var)
+{
+	struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+	u32 xoffset, pos;
+
+	xoffset = var->xoffset;
+	if (info->var.bits_per_pixel == 8) {
+		pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 2;
+	} else if (par->mode & MODE_TEXT) {
+		int fh = 16; // FIXME !!! font height. Fugde for now.
+		pos = (info->var.xres_virtual * (var->yoffset / fh) + xoffset) >> 3;
+	} else {
+		if (info->var.nonstd)
+			xoffset--;
+		pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 3;
+	}
+	vga_io_wcrt(VGA_CRTC_START_HI, pos >> 8);
+	vga_io_wcrt(VGA_CRTC_START_LO, pos & 0xFF);
+	/* if we support CFB4, then we must! support xoffset with pixel
+	 * granularity if someone supports xoffset in bit resolution */
+	vga_io_r(VGA_IS1_RC);		/* reset flip-flop */
+	vga_io_w(VGA_ATT_IW, VGA_ATC_PEL);
+	if (var->bits_per_pixel == 8)
+		vga_io_w(VGA_ATT_IW, (xoffset & 3) << 1);
+	else
+		vga_io_w(VGA_ATT_IW, xoffset & 7);
+	vga_io_r(VGA_IS1_RC);
+	vga_io_w(VGA_ATT_IW, 0x20);
+}
+
+static void vga16fb_update_fix(struct fb_info *info)
+{
+	if (info->var.bits_per_pixel == 4) {
+		if (info->var.nonstd) {
+			info->fix.type = FB_TYPE_PACKED_PIXELS;
+			info->fix.line_length = info->var.xres_virtual / 2;
+		} else {
+			info->fix.type = FB_TYPE_VGA_PLANES;
+			info->fix.type_aux = FB_AUX_VGA_PLANES_VGA4;
+			info->fix.line_length = info->var.xres_virtual / 8;
+		}
+	} else if (info->var.bits_per_pixel == 0) {
+		info->fix.type = FB_TYPE_TEXT;
+		info->fix.type_aux = FB_AUX_TEXT_CGA;
+		info->fix.line_length = info->var.xres_virtual / 4;
+	} else {	/* 8bpp */
+		if (info->var.nonstd) {
+			info->fix.type = FB_TYPE_VGA_PLANES;
+			info->fix.type_aux = FB_AUX_VGA_PLANES_CFB8;
+			info->fix.line_length = info->var.xres_virtual / 4;
+		} else {
+			info->fix.type = FB_TYPE_PACKED_PIXELS;
+			info->fix.line_length = info->var.xres_virtual;
+		}
+	}
+}
+
+static void vga16fb_clock_chip(struct vga16fb_par *par,
+			       unsigned int pixclock,
+			       const struct fb_info *info,
+			       int mul, int div)
+{
+	static struct {
+		u32 pixclock;
+		u8  misc;
+		u8  seq_clock_mode;
+	} *ptr, *best, vgaclocks[] = {
+		{ 79442 /* 12.587 */, 0x00, 0x08},
+		{ 70616 /* 14.161 */, 0x04, 0x08},
+		{ 39721 /* 25.175 */, 0x00, 0x00},
+		{ 35308 /* 28.322 */, 0x04, 0x00},
+		{     0 /* bad */,    0x00, 0x00}};
+	int err;
+
+	pixclock = (pixclock * mul) / div;
+	best = vgaclocks;
+	err = pixclock - best->pixclock;
+	if (err < 0) err = -err;
+	for (ptr = vgaclocks + 1; ptr->pixclock; ptr++) {
+		int tmp;
+
+		tmp = pixclock - ptr->pixclock;
+		if (tmp < 0) tmp = -tmp;
+		if (tmp < err) {
+			err = tmp;
+			best = ptr;
+		}
+	}
+	par->misc |= best->misc;
+	par->clkdiv = best->seq_clock_mode;
+	pixclock = (best->pixclock * div) / mul;		
+}
+			       
+#define FAIL(X) return -EINVAL
+
+static int vga16fb_open(struct fb_info *info, int user)
+{
+	struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+	int cnt = atomic_read(&par->ref_count);
+
+	if (!cnt) {
+		memset(&par->state, 0, sizeof(struct vgastate));
+		par->state.flags = VGA_SAVE_FONTS | VGA_SAVE_MODE |
+			VGA_SAVE_CMAP;
+		save_vga(&par->state);
+	}
+	atomic_inc(&par->ref_count);
+	return 0;
+}
+
+static int vga16fb_release(struct fb_info *info, int user)
+{
+	struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+	int cnt = atomic_read(&par->ref_count);
+
+	if (!cnt)
+		return -EINVAL;
+	if (cnt == 1)
+		restore_vga(&par->state);
+	atomic_dec(&par->ref_count);
+
+	return 0;
+}
+
+static int vga16fb_check_var(struct fb_var_screeninfo *var,
+			     struct fb_info *info)
+{
+	struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+	u32 xres, right, hslen, left, xtotal;
+	u32 yres, lower, vslen, upper, ytotal;
+	u32 vxres, xoffset, vyres, yoffset;
+	u32 pos;
+	u8 r7, rMode;
+	int shift;
+	int mode;
+	u32 maxmem;
+
+	par->pel_msk = 0xFF;
+
+	if (var->bits_per_pixel == 4) {
+		if (var->nonstd) {
+			if (!par->isVGA)
+				return -EINVAL;
+			shift = 3;
+			mode = MODE_SKIP4 | MODE_CFB;
+			maxmem = 16384;
+			par->pel_msk = 0x0F;
+		} else {
+			shift = 3;
+			mode = 0;
+			maxmem = 65536;
+		}
+	} else if (var->bits_per_pixel == 8) {
+		if (!par->isVGA)
+			return -EINVAL;	/* no support on EGA */
+		shift = 2;
+		if (var->nonstd) {
+			mode = MODE_8BPP | MODE_CFB;
+			maxmem = 65536;
+		} else {
+			mode = MODE_SKIP4 | MODE_8BPP | MODE_CFB;
+			maxmem = 16384;
+		}
+	} else
+		return -EINVAL;
+
+	xres = (var->xres + 7) & ~7;
+	vxres = (var->xres_virtual + 0xF) & ~0xF;
+	xoffset = (var->xoffset + 7) & ~7;
+	left = (var->left_margin + 7) & ~7;
+	right = (var->right_margin + 7) & ~7;
+	hslen = (var->hsync_len + 7) & ~7;
+
+	if (vxres < xres)
+		vxres = xres;
+	if (xres + xoffset > vxres)
+		xoffset = vxres - xres;
+
+	var->xres = xres;
+	var->right_margin = right;
+	var->hsync_len = hslen;
+	var->left_margin = left;
+	var->xres_virtual = vxres;
+	var->xoffset = xoffset;
+
+	xres >>= shift;
+	right >>= shift;
+	hslen >>= shift;
+	left >>= shift;
+	vxres >>= shift;
+	xtotal = xres + right + hslen + left;
+	if (xtotal >= 256)
+		FAIL("xtotal too big");
+	if (hslen > 32)
+		FAIL("hslen too big");
+	if (right + hslen + left > 64)
+		FAIL("hblank too big");
+	par->crtc[VGA_CRTC_H_TOTAL] = xtotal - 5;
+	par->crtc[VGA_CRTC_H_BLANK_START] = xres - 1;
+	par->crtc[VGA_CRTC_H_DISP] = xres - 1;
+	pos = xres + right;
+	par->crtc[VGA_CRTC_H_SYNC_START] = pos;
+	pos += hslen;
+	par->crtc[VGA_CRTC_H_SYNC_END] = pos & 0x1F;
+	pos += left - 2; /* blank_end + 2 <= total + 5 */
+	par->crtc[VGA_CRTC_H_BLANK_END] = (pos & 0x1F) | 0x80;
+	if (pos & 0x20)
+		par->crtc[VGA_CRTC_H_SYNC_END] |= 0x80;
+
+	yres = var->yres;
+	lower = var->lower_margin;
+	vslen = var->vsync_len;
+	upper = var->upper_margin;
+	vyres = var->yres_virtual;
+	yoffset = var->yoffset;
+
+	if (yres > vyres)
+		vyres = yres;
+	if (vxres * vyres > maxmem) {
+		vyres = maxmem / vxres;
+		if (vyres < yres)
+			return -ENOMEM;
+	}
+	if (yoffset + yres > vyres)
+		yoffset = vyres - yres;
+	var->yres = yres;
+	var->lower_margin = lower;
+	var->vsync_len = vslen;
+	var->upper_margin = upper;
+	var->yres_virtual = vyres;
+	var->yoffset = yoffset;
+
+	if (var->vmode & FB_VMODE_DOUBLE) {
+		yres <<= 1;
+		lower <<= 1;
+		vslen <<= 1;
+		upper <<= 1;
+	}
+	ytotal = yres + lower + vslen + upper;
+	if (ytotal > 1024) {
+		ytotal >>= 1;
+		yres >>= 1;
+		lower >>= 1;
+		vslen >>= 1;
+		upper >>= 1;
+		rMode = 0x04;
+	} else
+		rMode = 0x00;
+	if (ytotal > 1024)
+		FAIL("ytotal too big");
+	if (vslen > 16)
+		FAIL("vslen too big");
+	par->crtc[VGA_CRTC_V_TOTAL] = ytotal - 2;
+	r7 = 0x10;	/* disable linecompare */
+	if (ytotal & 0x100) r7 |= 0x01;
+	if (ytotal & 0x200) r7 |= 0x20;
+	par->crtc[VGA_CRTC_PRESET_ROW] = 0;
+	par->crtc[VGA_CRTC_MAX_SCAN] = 0x40;	/* 1 scanline, no linecmp */
+	if (var->vmode & FB_VMODE_DOUBLE)
+		par->crtc[VGA_CRTC_MAX_SCAN] |= 0x80;
+	par->crtc[VGA_CRTC_CURSOR_START] = 0x20;
+	par->crtc[VGA_CRTC_CURSOR_END]   = 0x00;
+	if ((mode & (MODE_CFB | MODE_8BPP)) == MODE_CFB)
+		xoffset--;
+	pos = yoffset * vxres + (xoffset >> shift);
+	par->crtc[VGA_CRTC_START_HI]     = pos >> 8;
+	par->crtc[VGA_CRTC_START_LO]     = pos & 0xFF;
+	par->crtc[VGA_CRTC_CURSOR_HI]    = 0x00;
+	par->crtc[VGA_CRTC_CURSOR_LO]    = 0x00;
+	pos = yres - 1;
+	par->crtc[VGA_CRTC_V_DISP_END] = pos & 0xFF;
+	par->crtc[VGA_CRTC_V_BLANK_START] = pos & 0xFF;
+	if (pos & 0x100)
+		r7 |= 0x0A;	/* 0x02 -> DISP_END, 0x08 -> BLANK_START */
+	if (pos & 0x200) {
+		r7 |= 0x40;	/* 0x40 -> DISP_END */
+		par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20; /* BLANK_START */
+	}
+	pos += lower;
+	par->crtc[VGA_CRTC_V_SYNC_START] = pos & 0xFF;
+	if (pos & 0x100)
+		r7 |= 0x04;
+	if (pos & 0x200)
+		r7 |= 0x80;
+	pos += vslen;
+	par->crtc[VGA_CRTC_V_SYNC_END] = (pos & 0x0F) & ~0x10; /* disabled IRQ */
+	pos += upper - 1; /* blank_end + 1 <= ytotal + 2 */
+	par->crtc[VGA_CRTC_V_BLANK_END] = pos & 0xFF; /* 0x7F for original VGA,
+                     but some SVGA chips requires all 8 bits to set */
+	if (vxres >= 512)
+		FAIL("vxres too long");
+	par->crtc[VGA_CRTC_OFFSET] = vxres >> 1;
+	if (mode & MODE_SKIP4)
+		par->crtc[VGA_CRTC_UNDERLINE] = 0x5F;	/* 256, cfb8 */
+	else
+		par->crtc[VGA_CRTC_UNDERLINE] = 0x1F;	/* 16, vgap */
+	par->crtc[VGA_CRTC_MODE] = rMode | ((mode & MODE_TEXT) ? 0xA3 : 0xE3);
+	par->crtc[VGA_CRTC_LINE_COMPARE] = 0xFF;
+	par->crtc[VGA_CRTC_OVERFLOW] = r7;
+
+	par->vss = 0x00;	/* 3DA */
+
+	par->misc = 0xE3;	/* enable CPU, ports 0x3Dx, positive sync */
+	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+		par->misc &= ~0x40;
+	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+		par->misc &= ~0x80;
+	
+	par->mode = mode;
+
+	if (mode & MODE_8BPP)
+		/* pixel clock == vga clock / 2 */
+		vga16fb_clock_chip(par, var->pixclock, info, 1, 2);
+	else
+		/* pixel clock == vga clock */
+		vga16fb_clock_chip(par, var->pixclock, info, 1, 1);
+	
+	var->red.offset = var->green.offset = var->blue.offset = 
+	var->transp.offset = 0;
+	var->red.length = var->green.length = var->blue.length =
+		(par->isVGA) ? 6 : 2;
+	var->transp.length = 0;
+	var->activate = FB_ACTIVATE_NOW;
+	var->height = -1;
+	var->width = -1;
+	var->accel_flags = 0;
+	return 0;
+}
+#undef FAIL
+
+static int vga16fb_set_par(struct fb_info *info)
+{
+	struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+	u8 gdc[VGA_GFX_C];
+	u8 seq[VGA_SEQ_C];
+	u8 atc[VGA_ATT_C];
+	int fh, i;
+
+	seq[VGA_SEQ_CLOCK_MODE] = 0x01 | par->clkdiv;
+	if (par->mode & MODE_TEXT)
+		seq[VGA_SEQ_PLANE_WRITE] = 0x03;
+	else
+		seq[VGA_SEQ_PLANE_WRITE] = 0x0F;
+	seq[VGA_SEQ_CHARACTER_MAP] = 0x00;
+	if (par->mode & MODE_TEXT)
+		seq[VGA_SEQ_MEMORY_MODE] = 0x03;
+	else if (par->mode & MODE_SKIP4)
+		seq[VGA_SEQ_MEMORY_MODE] = 0x0E;
+	else
+		seq[VGA_SEQ_MEMORY_MODE] = 0x06;
+
+	gdc[VGA_GFX_SR_VALUE] = 0x00;
+	gdc[VGA_GFX_SR_ENABLE] = 0x00;
+	gdc[VGA_GFX_COMPARE_VALUE] = 0x00;
+	gdc[VGA_GFX_DATA_ROTATE] = 0x00;
+	gdc[VGA_GFX_PLANE_READ] = 0;
+	if (par->mode & MODE_TEXT) {
+		gdc[VGA_GFX_MODE] = 0x10;
+		gdc[VGA_GFX_MISC] = 0x06;
+	} else {
+		if (par->mode & MODE_CFB)
+			gdc[VGA_GFX_MODE] = 0x40;
+		else
+			gdc[VGA_GFX_MODE] = 0x00;
+		gdc[VGA_GFX_MISC] = 0x05;
+	}
+	gdc[VGA_GFX_COMPARE_MASK] = 0x0F;
+	gdc[VGA_GFX_BIT_MASK] = 0xFF;
+
+	for (i = 0x00; i < 0x10; i++)
+		atc[i] = i;
+	if (par->mode & MODE_TEXT)
+		atc[VGA_ATC_MODE] = 0x04;
+	else if (par->mode & MODE_8BPP)
+		atc[VGA_ATC_MODE] = 0x41;
+	else
+		atc[VGA_ATC_MODE] = 0x81;
+	atc[VGA_ATC_OVERSCAN] = 0x00;	/* 0 for EGA, 0xFF for VGA */
+	atc[VGA_ATC_PLANE_ENABLE] = 0x0F;
+	if (par->mode & MODE_8BPP)
+		atc[VGA_ATC_PEL] = (info->var.xoffset & 3) << 1;
+	else
+		atc[VGA_ATC_PEL] = info->var.xoffset & 7;
+	atc[VGA_ATC_COLOR_PAGE] = 0x00;
+	
+	if (par->mode & MODE_TEXT) {
+		fh = 16; // FIXME !!! Fudge font height. 
+		par->crtc[VGA_CRTC_MAX_SCAN] = (par->crtc[VGA_CRTC_MAX_SCAN] 
+					       & ~0x1F) | (fh - 1);
+	}
+
+	vga_io_w(VGA_MIS_W, vga_io_r(VGA_MIS_R) | 0x01);
+
+	/* Enable graphics register modification */
+	if (!par->isVGA) {
+		vga_io_w(EGA_GFX_E0, 0x00);
+		vga_io_w(EGA_GFX_E1, 0x01);
+	}
+	
+	/* update misc output register */
+	vga_io_w(VGA_MIS_W, par->misc);
+	
+	/* synchronous reset on */
+	vga_io_wseq(0x00, 0x01);
+
+	if (par->isVGA)
+		vga_io_w(VGA_PEL_MSK, par->pel_msk);
+
+	/* write sequencer registers */
+	vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE] | 0x20);
+	for (i = 2; i < VGA_SEQ_C; i++) {
+		vga_io_wseq(i, seq[i]);
+	}
+	
+	/* synchronous reset off */
+	vga_io_wseq(0x00, 0x03);
+
+	/* deprotect CRT registers 0-7 */
+	vga_io_wcrt(VGA_CRTC_V_SYNC_END, par->crtc[VGA_CRTC_V_SYNC_END]);
+
+	/* write CRT registers */
+	for (i = 0; i < VGA_CRTC_REGS; i++) {
+		vga_io_wcrt(i, par->crtc[i]);
+	}
+	
+	/* write graphics controller registers */
+	for (i = 0; i < VGA_GFX_C; i++) {
+		vga_io_wgfx(i, gdc[i]);
+	}
+	
+	/* write attribute controller registers */
+	for (i = 0; i < VGA_ATT_C; i++) {
+		vga_io_r(VGA_IS1_RC);		/* reset flip-flop */
+		vga_io_wattr(i, atc[i]);
+	}
+
+	/* Wait for screen to stabilize. */
+	mdelay(50);
+
+	vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE]);
+
+	vga_io_r(VGA_IS1_RC);
+	vga_io_w(VGA_ATT_IW, 0x20);
+
+	vga16fb_update_fix(info);
+	return 0;
+}
+
+static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
+{
+	static unsigned char map[] = { 000, 001, 010, 011 };
+	int val;
+	
+	if (regno >= 16)
+		return;
+	val = map[red>>14] | ((map[green>>14]) << 1) | ((map[blue>>14]) << 2);
+	vga_io_r(VGA_IS1_RC);   /* ! 0x3BA */
+	vga_io_wattr(regno, val);
+	vga_io_r(VGA_IS1_RC);   /* some clones need it */
+	vga_io_w(VGA_ATT_IW, 0x20); /* unblank screen */
+}
+
+static void vga16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
+{
+	outb(regno,       dac_reg);
+	outb(red   >> 10, dac_val);
+	outb(green >> 10, dac_val);
+	outb(blue  >> 10, dac_val);
+}
+
+static int vga16fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			     unsigned blue, unsigned transp,
+			     struct fb_info *info)
+{
+	struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+	int gray;
+
+	/*
+	 *  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.
+	 */
+	
+	if (regno >= 256)
+		return 1;
+
+	gray = info->var.grayscale;
+	
+	if (gray) {
+		/* gray = 0.30*R + 0.59*G + 0.11*B */
+		red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+	}
+	if (par->isVGA) 
+		vga16_setpalette(regno,red,green,blue);
+	else
+		ega16_setpalette(regno,red,green,blue);
+	return 0;
+}
+
+static int vga16fb_pan_display(struct fb_var_screeninfo *var,
+			       struct fb_info *info) 
+{
+	if (var->xoffset + info->var.xres > info->var.xres_virtual ||
+	    var->yoffset + info->var.yres > info->var.yres_virtual)
+		return -EINVAL;
+
+	vga16fb_pan_var(info, var);
+
+	info->var.xoffset = var->xoffset;
+	info->var.yoffset = var->yoffset;
+	info->var.vmode &= ~FB_VMODE_YWRAP;
+	return 0;
+}
+
+/* The following VESA blanking code is taken from vgacon.c.  The VGA
+   blanking code was originally by Huang shi chao, and modified by
+   Christoph Rimek (chrimek@toppoint.de) and todd j. derr
+   (tjd@barefoot.org) for Linux. */
+#define attrib_port		VGA_ATC_IW
+#define seq_port_reg		VGA_SEQ_I
+#define seq_port_val		VGA_SEQ_D
+#define gr_port_reg		VGA_GFX_I
+#define gr_port_val		VGA_GFX_D
+#define video_misc_rd		VGA_MIS_R
+#define video_misc_wr		VGA_MIS_W
+#define vga_video_port_reg	VGA_CRT_IC
+#define vga_video_port_val	VGA_CRT_DC
+
+static void vga_vesa_blank(struct vga16fb_par *par, int mode)
+{
+	unsigned char SeqCtrlIndex;
+	unsigned char CrtCtrlIndex;
+	
+	//cli();
+	SeqCtrlIndex = vga_io_r(seq_port_reg);
+	CrtCtrlIndex = vga_io_r(vga_video_port_reg);
+
+	/* save original values of VGA controller registers */
+	if(!par->vesa_blanked) {
+		par->vga_state.CrtMiscIO = vga_io_r(video_misc_rd);
+		//sti();
+
+		par->vga_state.HorizontalTotal = vga_io_rcrt(0x00);	/* HorizontalTotal */
+		par->vga_state.HorizDisplayEnd = vga_io_rcrt(0x01);	/* HorizDisplayEnd */
+		par->vga_state.StartHorizRetrace = vga_io_rcrt(0x04);	/* StartHorizRetrace */
+		par->vga_state.EndHorizRetrace = vga_io_rcrt(0x05);	/* EndHorizRetrace */
+		par->vga_state.Overflow = vga_io_rcrt(0x07);		/* Overflow */
+		par->vga_state.StartVertRetrace = vga_io_rcrt(0x10);	/* StartVertRetrace */
+		par->vga_state.EndVertRetrace = vga_io_rcrt(0x11);	/* EndVertRetrace */
+		par->vga_state.ModeControl = vga_io_rcrt(0x17);	/* ModeControl */
+		par->vga_state.ClockingMode = vga_io_rseq(0x01);	/* ClockingMode */
+	}
+
+	/* assure that video is enabled */
+	/* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
+	//cli();
+	vga_io_wseq(0x01, par->vga_state.ClockingMode | 0x20);
+
+	/* test for vertical retrace in process.... */
+	if ((par->vga_state.CrtMiscIO & 0x80) == 0x80)
+		vga_io_w(video_misc_wr, par->vga_state.CrtMiscIO & 0xef);
+
+	/*
+	 * Set <End of vertical retrace> to minimum (0) and
+	 * <Start of vertical Retrace> to maximum (incl. overflow)
+	 * Result: turn off vertical sync (VSync) pulse.
+	 */
+	if (mode & FB_BLANK_VSYNC_SUSPEND) {
+		outb_p(0x10,vga_video_port_reg);	/* StartVertRetrace */
+		outb_p(0xff,vga_video_port_val); 	/* maximum value */
+		outb_p(0x11,vga_video_port_reg);	/* EndVertRetrace */
+		outb_p(0x40,vga_video_port_val);	/* minimum (bits 0..3)  */
+		outb_p(0x07,vga_video_port_reg);	/* Overflow */
+		outb_p(par->vga_state.Overflow | 0x84,vga_video_port_val); /* bits 9,10 of vert. retrace */
+	}
+
+	if (mode & FB_BLANK_HSYNC_SUSPEND) {
+		/*
+		 * Set <End of horizontal retrace> to minimum (0) and
+		 *  <Start of horizontal Retrace> to maximum
+		 * Result: turn off horizontal sync (HSync) pulse.
+		 */
+		outb_p(0x04,vga_video_port_reg);	/* StartHorizRetrace */
+		outb_p(0xff,vga_video_port_val);	/* maximum */
+		outb_p(0x05,vga_video_port_reg);	/* EndHorizRetrace */
+		outb_p(0x00,vga_video_port_val);	/* minimum (0) */
+	}
+
+	/* restore both index registers */
+	outb_p(SeqCtrlIndex,seq_port_reg);
+	outb_p(CrtCtrlIndex,vga_video_port_reg);
+	//sti();
+}
+
+static void vga_vesa_unblank(struct vga16fb_par *par)
+{
+	unsigned char SeqCtrlIndex;
+	unsigned char CrtCtrlIndex;
+	
+	//cli();
+	SeqCtrlIndex = vga_io_r(seq_port_reg);
+	CrtCtrlIndex = vga_io_r(vga_video_port_reg);
+
+	/* restore original values of VGA controller registers */
+	vga_io_w(video_misc_wr, par->vga_state.CrtMiscIO);
+
+	/* HorizontalTotal */
+	vga_io_wcrt(0x00, par->vga_state.HorizontalTotal);
+	/* HorizDisplayEnd */
+	vga_io_wcrt(0x01, par->vga_state.HorizDisplayEnd);
+	/* StartHorizRetrace */
+	vga_io_wcrt(0x04, par->vga_state.StartHorizRetrace);
+	/* EndHorizRetrace */
+	vga_io_wcrt(0x05, par->vga_state.EndHorizRetrace);
+	/* Overflow */
+	vga_io_wcrt(0x07, par->vga_state.Overflow);
+	/* StartVertRetrace */
+	vga_io_wcrt(0x10, par->vga_state.StartVertRetrace);
+	/* EndVertRetrace */
+	vga_io_wcrt(0x11, par->vga_state.EndVertRetrace);
+	/* ModeControl */
+	vga_io_wcrt(0x17, par->vga_state.ModeControl);
+	/* ClockingMode */
+	vga_io_wseq(0x01, par->vga_state.ClockingMode);
+
+	/* restore index/control registers */
+	vga_io_w(seq_port_reg, SeqCtrlIndex);
+	vga_io_w(vga_video_port_reg, CrtCtrlIndex);
+	//sti();
+}
+
+static void vga_pal_blank(void)
+{
+	int i;
+
+	for (i=0; i<16; i++) {
+		outb_p (i, dac_reg) ;
+		outb_p (0, dac_val) ;
+		outb_p (0, dac_val) ;
+		outb_p (0, dac_val) ;
+	}
+}
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+static int vga16fb_blank(int blank, struct fb_info *info)
+{
+	struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+
+	switch (blank) {
+	case FB_BLANK_UNBLANK:				/* Unblank */
+		if (par->vesa_blanked) {
+			vga_vesa_unblank(par);
+			par->vesa_blanked = 0;
+		}
+		if (par->palette_blanked) {
+			par->palette_blanked = 0;
+		}
+		break;
+	case FB_BLANK_NORMAL:				/* blank */
+		vga_pal_blank();
+		par->palette_blanked = 1;
+		break;
+	default:			/* VESA blanking */
+		vga_vesa_blank(par, blank);
+		par->vesa_blanked = 1;
+		break;
+	}
+	return 0;
+}
+
+static void vga_8planes_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+	u32 dx = rect->dx, width = rect->width;
+        char oldindex = getindex();
+        char oldmode = setmode(0x40);
+        char oldmask = selectmask();
+        int line_ofs, height;
+        char oldop, oldsr;
+        char __iomem *where;
+
+        dx /= 4;
+        where = info->screen_base + dx + rect->dy * info->fix.line_length;
+
+        if (rect->rop == ROP_COPY) {
+                oldop = setop(0);
+                oldsr = setsr(0);
+
+                width /= 4;
+                line_ofs = info->fix.line_length - width;
+                setmask(0xff);
+
+                height = rect->height;
+
+                while (height--) {
+                        int x;
+
+                        /* we can do memset... */
+                        for (x = width; x > 0; --x) {
+                                writeb(rect->color, where);
+                                where++;
+                        }
+                        where += line_ofs;
+                }
+        } else {
+                char oldcolor = setcolor(0xf);
+                int y;
+
+                oldop = setop(0x18);
+                oldsr = setsr(0xf);
+                setmask(0x0F);
+                for (y = 0; y < rect->height; y++) {
+                        rmw(where);
+                        rmw(where+1);
+                        where += info->fix.line_length;
+                }
+                setcolor(oldcolor);
+        }
+        setmask(oldmask);
+        setsr(oldsr);
+        setop(oldop);
+        setmode(oldmode);
+        setindex(oldindex);
+}
+
+static void vga16fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+	int x, x2, y2, vxres, vyres, width, height, line_ofs;
+	char __iomem *dst;
+
+	vxres = info->var.xres_virtual;
+	vyres = info->var.yres_virtual;
+
+	if (!rect->width || !rect->height || rect->dx > vxres || rect->dy > vyres)
+		return;
+
+	/* We could use hardware clipping but on many cards you get around
+	 * hardware clipping by writing to framebuffer directly. */
+
+	x2 = rect->dx + rect->width;
+	y2 = rect->dy + rect->height;
+	x2 = x2 < vxres ? x2 : vxres;
+	y2 = y2 < vyres ? y2 : vyres;
+	width = x2 - rect->dx;
+
+	switch (info->fix.type) {
+	case FB_TYPE_VGA_PLANES:
+		if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
+
+			height = y2 - rect->dy;
+			width = rect->width/8;
+
+			line_ofs = info->fix.line_length - width;
+			dst = info->screen_base + (rect->dx/8) + rect->dy * info->fix.line_length;
+
+			switch (rect->rop) {
+			case ROP_COPY:
+				setmode(0);
+				setop(0);
+				setsr(0xf);
+				setcolor(rect->color);
+				selectmask();
+
+				setmask(0xff);
+
+				while (height--) {
+					for (x = 0; x < width; x++) {
+						writeb(0, dst);
+						dst++;
+					}
+					dst += line_ofs;
+				}
+				break;
+			case ROP_XOR:
+				setmode(0);
+				setop(0x18);
+				setsr(0xf);
+				setcolor(0xf);
+				selectmask();
+
+				setmask(0xff);
+				while (height--) {
+					for (x = 0; x < width; x++) {
+						rmw(dst);
+						dst++;
+					}
+					dst += line_ofs;
+				}
+				break;
+			}
+		} else 
+			vga_8planes_fillrect(info, rect);
+		break;
+	case FB_TYPE_PACKED_PIXELS:
+	default:
+		cfb_fillrect(info, rect);
+		break;
+	}
+}
+
+static void vga_8planes_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+        char oldindex = getindex();
+        char oldmode = setmode(0x41);
+        char oldop = setop(0);
+        char oldsr = setsr(0xf);
+        int height, line_ofs, x;
+	u32 sx, dx, width;
+	char __iomem *dest;
+	char __iomem *src;
+
+        height = area->height;
+
+        sx = area->sx / 4;
+        dx = area->dx / 4;
+        width = area->width / 4;
+
+        if (area->dy < area->sy || (area->dy == area->sy && dx < sx)) {
+                line_ofs = info->fix.line_length - width;
+                dest = info->screen_base + dx + area->dy * info->fix.line_length;
+                src = info->screen_base + sx + area->sy * info->fix.line_length;
+                while (height--) {
+                        for (x = 0; x < width; x++) {
+                                readb(src);
+                                writeb(0, dest);
+                                src++;
+                                dest++;
+                        }
+                        src += line_ofs;
+                        dest += line_ofs;
+                }
+        } else {
+                line_ofs = info->fix.line_length - width;
+                dest = info->screen_base + dx + width +
+			(area->dy + height - 1) * info->fix.line_length;
+                src = info->screen_base + sx + width +
+			(area->sy + height - 1) * info->fix.line_length;
+                while (height--) {
+                        for (x = 0; x < width; x++) {
+                                --src;
+                                --dest;
+                                readb(src);
+                                writeb(0, dest);
+                        }
+                        src -= line_ofs;
+                        dest -= line_ofs;
+                }
+        }
+
+        setsr(oldsr);
+        setop(oldop);
+        setmode(oldmode);
+        setindex(oldindex);
+}
+
+static void vga16fb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+	u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy; 
+	int x, x2, y2, old_dx, old_dy, vxres, vyres;
+	int height, width, line_ofs;
+	char __iomem *dst = NULL;
+	char __iomem *src = NULL;
+
+	vxres = info->var.xres_virtual;
+	vyres = info->var.yres_virtual;
+
+	if (area->dx > vxres || area->sx > vxres || area->dy > vyres ||
+	    area->sy > vyres)
+		return;
+
+	/* clip the destination */
+	old_dx = area->dx;
+	old_dy = area->dy;
+
+	/*
+	 * We could use hardware clipping but on many cards you get around
+	 * hardware clipping by writing to framebuffer directly.
+	 */
+	x2 = area->dx + area->width;
+	y2 = area->dy + area->height;
+	dx = area->dx > 0 ? area->dx : 0;
+	dy = area->dy > 0 ? area->dy : 0;
+	x2 = x2 < vxres ? x2 : vxres;
+	y2 = y2 < vyres ? y2 : vyres;
+	width = x2 - dx;
+	height = y2 - dy;
+
+	/* update sx1,sy1 */
+	sx += (dx - old_dx);
+	sy += (dy - old_dy);
+
+	/* the source must be completely inside the virtual screen */
+	if (sx < 0 || sy < 0 || (sx + width) > vxres || (sy + height) > vyres)
+		return;
+
+	switch (info->fix.type) {
+	case FB_TYPE_VGA_PLANES:
+		if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
+			width = width/8;
+			height = height;
+			line_ofs = info->fix.line_length - width;
+
+			setmode(1);
+			setop(0);
+			setsr(0xf);
+
+			if (dy < sy || (dy == sy && dx < sx)) {
+				dst = info->screen_base + (dx/8) + dy * info->fix.line_length;
+				src = info->screen_base + (sx/8) + sy * info->fix.line_length;
+				while (height--) {
+					for (x = 0; x < width; x++) {
+						readb(src);
+						writeb(0, dst);
+						dst++;
+						src++;
+					}
+					src += line_ofs;
+					dst += line_ofs;
+				}
+			} else {
+				dst = info->screen_base + (dx/8) + width + 
+					(dy + height - 1) * info->fix.line_length;
+				src = info->screen_base + (sx/8) + width + 
+					(sy + height  - 1) * info->fix.line_length;
+				while (height--) {
+					for (x = 0; x < width; x++) {
+						dst--;
+						src--;
+						readb(src);
+						writeb(0, dst);
+					}
+					src -= line_ofs;
+					dst -= line_ofs;
+				}
+			}
+		} else 
+			vga_8planes_copyarea(info, area);
+		break;
+	case FB_TYPE_PACKED_PIXELS:
+	default:
+		cfb_copyarea(info, area);
+		break;
+	}
+}
+
+#ifdef __LITTLE_ENDIAN
+static unsigned int transl_l[] =
+{0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF};
+static unsigned int transl_h[] =
+{0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00,
+ 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00};
+#else
+#ifdef __BIG_ENDIAN
+static unsigned int transl_h[] =
+{0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF};
+static unsigned int transl_l[] =
+{0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00,
+ 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00};
+#else
+#error "Only __BIG_ENDIAN and __LITTLE_ENDIAN are supported in vga-planes"
+#endif
+#endif
+
+static void vga_8planes_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+        char oldindex = getindex();
+        char oldmode = setmode(0x40);
+        char oldop = setop(0);
+        char oldsr = setsr(0);
+        char oldmask = selectmask();
+        const char *cdat = image->data;
+	u32 dx = image->dx;
+        char __iomem *where;
+        int y;
+
+        dx /= 4;
+        where = info->screen_base + dx + image->dy * info->fix.line_length;
+
+        setmask(0xff);
+        writeb(image->bg_color, where);
+        readb(where);
+        selectmask();
+        setmask(image->fg_color ^ image->bg_color);
+        setmode(0x42);
+        setop(0x18);
+        for (y = 0; y < image->height; y++, where += info->fix.line_length)
+                writew(transl_h[cdat[y]&0xF] | transl_l[cdat[y] >> 4], where);
+        setmask(oldmask);
+        setsr(oldsr);
+        setop(oldop);
+        setmode(oldmode);
+        setindex(oldindex);
+}
+
+static void vga_imageblit_expand(struct fb_info *info, const struct fb_image *image)
+{
+	char __iomem *where = info->screen_base + (image->dx/8) +
+		image->dy * info->fix.line_length;
+	struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+	char *cdat = (char *) image->data;
+	char __iomem *dst;
+	int x, y;
+
+	switch (info->fix.type) {
+	case FB_TYPE_VGA_PLANES:
+		if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
+			if (par->isVGA) {
+				setmode(2);
+				setop(0);
+				setsr(0xf);
+				setcolor(image->fg_color);
+				selectmask();
+				
+				setmask(0xff);
+				writeb(image->bg_color, where);
+				rmb();
+				readb(where); /* fill latches */
+				setmode(3);
+				wmb();
+				for (y = 0; y < image->height; y++) {
+					dst = where;
+					for (x = image->width/8; x--;) 
+						writeb(*cdat++, dst++);
+					where += info->fix.line_length;
+				}
+				wmb();
+			} else {
+				setmode(0);
+				setop(0);
+				setsr(0xf);
+				setcolor(image->bg_color);
+				selectmask();
+				
+				setmask(0xff);
+				for (y = 0; y < image->height; y++) {
+					dst = where;
+					for (x=image->width/8; x--;){
+						rmw(dst);
+						setcolor(image->fg_color);
+						selectmask();
+						if (*cdat) {
+							setmask(*cdat++);
+							rmw(dst++);
+						}
+					}
+					where += info->fix.line_length;
+				}
+			}
+		} else 
+			vga_8planes_imageblit(info, image);
+		break;
+	case FB_TYPE_PACKED_PIXELS:
+	default:
+		cfb_imageblit(info, image);
+		break;
+	}
+}
+
+static void vga_imageblit_color(struct fb_info *info, const struct fb_image *image)
+{
+	/*
+	 * Draw logo 
+	 */
+	struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+	char __iomem *where =
+		info->screen_base + image->dy * info->fix.line_length +
+		image->dx/8;
+	const char *cdat = image->data;
+	char __iomem *dst;
+	int x, y;
+
+	switch (info->fix.type) {
+	case FB_TYPE_VGA_PLANES:
+		if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4 &&
+		    par->isVGA) {
+			setsr(0xf);
+			setop(0);
+			setmode(0);
+			
+			for (y = 0; y < image->height; y++) {
+				for (x = 0; x < image->width; x++) {
+					dst = where + x/8;
+
+					setcolor(*cdat);
+					selectmask();
+					setmask(1 << (7 - (x % 8)));
+					fb_readb(dst);
+					fb_writeb(0, dst);
+
+					cdat++;
+				}
+				where += info->fix.line_length;
+			}
+		}
+		break;
+	case FB_TYPE_PACKED_PIXELS:
+		cfb_imageblit(info, image);
+		break;
+	default:
+		break;
+	}
+}
+				
+static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	if (image->depth == 1)
+		vga_imageblit_expand(info, image);
+	else
+		vga_imageblit_color(info, image);
+}
+
+static struct fb_ops vga16fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_open        = vga16fb_open,
+	.fb_release     = vga16fb_release,
+	.fb_check_var	= vga16fb_check_var,
+	.fb_set_par	= vga16fb_set_par,
+	.fb_setcolreg 	= vga16fb_setcolreg,
+	.fb_pan_display = vga16fb_pan_display,
+	.fb_blank 	= vga16fb_blank,
+	.fb_fillrect	= vga16fb_fillrect,
+	.fb_copyarea	= vga16fb_copyarea,
+	.fb_imageblit	= vga16fb_imageblit,
+	.fb_cursor      = soft_cursor,
+};
+
+#ifndef MODULE
+static int vga16fb_setup(char *options)
+{
+	char *this_opt;
+	
+	if (!options || !*options)
+		return 0;
+	
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt) continue;
+	}
+	return 0;
+}
+#endif
+
+static int __init vga16fb_init(void)
+{
+	int i;
+	int ret;
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("vga16fb", &option))
+		return -ENODEV;
+
+	vga16fb_setup(option);
+#endif
+	printk(KERN_DEBUG "vga16fb: initializing\n");
+
+	/* XXX share VGA_FB_PHYS and I/O region with vgacon and others */
+
+	vga16fb.screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS);
+	if (!vga16fb.screen_base) {
+		printk(KERN_ERR "vga16fb: unable to map device\n");
+		ret = -ENOMEM;
+		goto err_ioremap;
+	}
+	printk(KERN_INFO "vga16fb: mapped to 0x%p\n", vga16fb.screen_base);
+
+	vga16_par.isVGA = ORIG_VIDEO_ISVGA;
+	vga16_par.palette_blanked = 0;
+	vga16_par.vesa_blanked = 0;
+
+	i = vga16_par.isVGA? 6 : 2;
+	
+	vga16fb_defined.red.length   = i;
+	vga16fb_defined.green.length = i;
+	vga16fb_defined.blue.length  = i;	
+
+	/* name should not depend on EGA/VGA */
+	vga16fb.fbops = &vga16fb_ops;
+	vga16fb.var = vga16fb_defined;
+	vga16fb.fix = vga16fb_fix;
+	vga16fb.par = &vga16_par;
+	vga16fb.flags = FBINFO_FLAG_DEFAULT |
+		FBINFO_HWACCEL_YPAN;
+
+	i = (vga16fb_defined.bits_per_pixel == 8) ? 256 : 16;
+	ret = fb_alloc_cmap(&vga16fb.cmap, i, 0);
+	if (ret) {
+		printk(KERN_ERR "vga16fb: unable to allocate colormap\n");
+		ret = -ENOMEM;
+		goto err_alloc_cmap;
+	}
+
+	if (vga16fb_check_var(&vga16fb.var, &vga16fb)) {
+		printk(KERN_ERR "vga16fb: unable to validate variable\n");
+		ret = -EINVAL;
+		goto err_check_var;
+	}
+
+	vga16fb_update_fix(&vga16fb);
+
+	if (register_framebuffer(&vga16fb) < 0) {
+		printk(KERN_ERR "vga16fb: unable to register framebuffer\n");
+		ret = -EINVAL;
+		goto err_check_var;
+	}
+
+	printk(KERN_INFO "fb%d: %s frame buffer device\n",
+	       vga16fb.node, vga16fb.fix.id);
+
+	return 0;
+
+ err_check_var:
+	fb_dealloc_cmap(&vga16fb.cmap);
+ err_alloc_cmap:
+	iounmap(vga16fb.screen_base);
+ err_ioremap:
+	return ret;
+}
+
+static void __exit vga16fb_exit(void)
+{
+    unregister_framebuffer(&vga16fb);
+    iounmap(vga16fb.screen_base);
+    fb_dealloc_cmap(&vga16fb.cmap);
+    /* XXX unshare VGA regions */
+}
+
+MODULE_LICENSE("GPL");
+module_init(vga16fb_init);
+module_exit(vga16fb_exit);
+
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
diff --git a/drivers/video/vgastate.c b/drivers/video/vgastate.c
new file mode 100644
index 0000000..0ea62d8
--- /dev/null
+++ b/drivers/video/vgastate.c
@@ -0,0 +1,504 @@
+/*
+ * linux/drivers/video/vgastate.c -- VGA state save/restore
+ *
+ * Copyright 2002 James Simmons
+ * 
+ * Copyright history from vga16fb.c:
+ *	Copyright 1999 Ben Pfaff and Petr Vandrovec
+ *	Based on VGA info at http://www.goodnet.com/~tinara/FreeVGA/home.htm
+ *	Based on VESA framebuffer (c) 1998 Gerd Knorr
+ *
+ * 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/slab.h>
+#include <linux/fb.h>
+#include <linux/vmalloc.h>
+#include <video/vga.h>
+
+struct regstate {
+	__u8 *vga_font0;
+	__u8 *vga_font1;
+	__u8 *vga_text;
+	__u8 *vga_cmap;
+	__u8 *attr;
+	__u8 *crtc;
+	__u8 *gfx;
+	__u8 *seq;
+	__u8 misc;
+};	
+
+static inline unsigned char vga_rcrtcs(void __iomem *regbase, unsigned short iobase, 
+				       unsigned char reg)
+{
+	vga_w(regbase, iobase + 0x4, reg);
+	return vga_r(regbase, iobase + 0x5);
+}
+
+static inline void vga_wcrtcs(void __iomem *regbase, unsigned short iobase, 
+			      unsigned char reg, unsigned char val)
+{
+	vga_w(regbase, iobase + 0x4, reg);
+	vga_w(regbase, iobase + 0x5, val);
+}
+
+static void save_vga_text(struct vgastate *state, void __iomem *fbbase)
+{
+	struct regstate *saved = (struct regstate *) state->vidstate;
+	int i;
+	u8 misc, attr10, gr4, gr5, gr6, seq1, seq2, seq4;
+
+	/* if in graphics mode, no need to save */
+	attr10 = vga_rattr(state->vgabase, 0x10);
+	if (attr10 & 1)
+		return;
+	
+	/* save regs */
+	misc = vga_r(state->vgabase, VGA_MIS_R);
+	gr4 = vga_rgfx(state->vgabase, VGA_GFX_PLANE_READ);
+	gr5 = vga_rgfx(state->vgabase, VGA_GFX_MODE);
+	gr6 = vga_rgfx(state->vgabase, VGA_GFX_MISC);
+	seq2 = vga_rseq(state->vgabase, VGA_SEQ_PLANE_WRITE);
+	seq4 = vga_rseq(state->vgabase, VGA_SEQ_MEMORY_MODE);
+	
+	/* force graphics mode */
+	vga_w(state->vgabase, VGA_MIS_W, misc | 1);
+
+	/* blank screen */
+	seq1 = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
+	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
+	vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1 | 1 << 5);
+	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x3);
+
+	/* save font at plane 2 */
+	if (state->flags & VGA_SAVE_FONT0) {
+		vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x4);
+		vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6);
+		vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x2);
+		vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
+		vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
+		for (i = 0; i < 4 * 8192; i++) 
+			saved->vga_font0[i] = vga_r(fbbase, i);
+	}
+
+	/* save font at plane 3 */
+	if (state->flags & VGA_SAVE_FONT1) {
+		vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x8);
+		vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6);
+		vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x3);
+		vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
+		vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
+		for (i = 0; i < state->memsize; i++) 
+			saved->vga_font1[i] = vga_r(fbbase, i);
+	}
+	
+	/* save font at plane 0/1 */
+	if (state->flags & VGA_SAVE_TEXT) {
+		vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x1);
+		vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6);
+		vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x0);
+		vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
+		vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
+		for (i = 0; i < 8192; i++) 
+			saved->vga_text[i] = vga_r(fbbase, i);
+
+		vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x2);
+		vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6);
+		vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x1);
+		vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
+		vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
+		for (i = 0; i < 8192; i++) 
+			saved->vga_text[8192+i] = vga_r(fbbase + 2 * 8192, i); 
+	}
+
+	/* restore regs */
+	vga_wattr(state->vgabase, 0x10, attr10);
+
+	vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, seq2);
+	vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, seq4);
+
+	vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, gr4);
+	vga_wgfx(state->vgabase, VGA_GFX_MODE, gr5);
+	vga_wgfx(state->vgabase, VGA_GFX_MISC, gr6);
+	vga_w(state->vgabase, VGA_MIS_W, misc);
+
+	/* unblank screen */
+	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
+	vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1 & ~(1 << 5));
+	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x3);
+
+	vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1);
+}
+
+static void restore_vga_text(struct vgastate *state, void __iomem *fbbase)
+{
+	struct regstate *saved = (struct regstate *) state->vidstate;
+	int i;
+	u8 misc, gr1, gr3, gr4, gr5, gr6, gr8; 
+	u8 seq1, seq2, seq4;
+
+	/* save regs */
+	misc = vga_r(state->vgabase, VGA_MIS_R);
+	gr1 = vga_rgfx(state->vgabase, VGA_GFX_SR_ENABLE);
+	gr3 = vga_rgfx(state->vgabase, VGA_GFX_DATA_ROTATE);
+	gr4 = vga_rgfx(state->vgabase, VGA_GFX_PLANE_READ);
+	gr5 = vga_rgfx(state->vgabase, VGA_GFX_MODE);
+	gr6 = vga_rgfx(state->vgabase, VGA_GFX_MISC);
+	gr8 = vga_rgfx(state->vgabase, VGA_GFX_BIT_MASK);
+	seq2 = vga_rseq(state->vgabase, VGA_SEQ_PLANE_WRITE);
+	seq4 = vga_rseq(state->vgabase, VGA_SEQ_MEMORY_MODE);
+	
+	/* force graphics mode */
+	vga_w(state->vgabase, VGA_MIS_W, misc | 1);
+
+	/* blank screen */
+	seq1 = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
+	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
+	vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1 | 1 << 5);
+	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x3);
+
+	if (state->depth == 4) {
+		vga_wgfx(state->vgabase, VGA_GFX_DATA_ROTATE, 0x0);
+		vga_wgfx(state->vgabase, VGA_GFX_BIT_MASK, 0xff);
+		vga_wgfx(state->vgabase, VGA_GFX_SR_ENABLE, 0x00);
+	}
+	
+	/* restore font at plane 2 */
+	if (state->flags & VGA_SAVE_FONT0) {
+		vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x4);
+		vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6);
+		vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x2);
+		vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
+		vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
+		for (i = 0; i < 4 * 8192; i++) 
+			vga_w(fbbase, i, saved->vga_font0[i]);
+	}
+
+	/* restore font at plane 3 */
+	if (state->flags & VGA_SAVE_FONT1) {
+		vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x8);
+		vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6);
+		vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x3);
+		vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
+		vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
+		for (i = 0; i < state->memsize; i++) 
+			vga_w(fbbase, i, saved->vga_font1[i]);
+	}
+	
+	/* restore font at plane 0/1 */
+	if (state->flags & VGA_SAVE_TEXT) {
+		vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x1);
+		vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6);
+		vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x0);
+		vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
+		vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
+		for (i = 0; i < 8192; i++) 
+			vga_w(fbbase, i, saved->vga_text[i]);
+		
+		vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x2);
+		vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6);
+		vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x1);
+		vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
+		vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
+		for (i = 0; i < 8192; i++) 
+			vga_w(fbbase, i, saved->vga_text[8192+i]); 
+	}
+
+	/* unblank screen */
+	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
+	vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1 & ~(1 << 5));
+	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x3);
+
+	/* restore regs */
+	vga_w(state->vgabase, VGA_MIS_W, misc);
+
+	vga_wgfx(state->vgabase, VGA_GFX_SR_ENABLE, gr1);
+	vga_wgfx(state->vgabase, VGA_GFX_DATA_ROTATE, gr3);
+	vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, gr4);
+	vga_wgfx(state->vgabase, VGA_GFX_MODE, gr5);
+	vga_wgfx(state->vgabase, VGA_GFX_MISC, gr6);
+	vga_wgfx(state->vgabase, VGA_GFX_BIT_MASK, gr8);
+
+	vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1);
+	vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, seq2);
+	vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, seq4);
+}
+			      
+static void save_vga_mode(struct vgastate *state)
+{
+	struct regstate *saved = (struct regstate *) state->vidstate;
+	unsigned short iobase;
+	int i;
+
+	saved->misc = vga_r(state->vgabase, VGA_MIS_R);
+	if (saved->misc & 1)
+		iobase = 0x3d0;
+	else
+		iobase = 0x3b0;
+
+	for (i = 0; i < state->num_crtc; i++) 
+		saved->crtc[i] = vga_rcrtcs(state->vgabase, iobase, i);
+	
+	vga_r(state->vgabase, iobase + 0xa); 
+	vga_w(state->vgabase, VGA_ATT_W, 0x00);
+	for (i = 0; i < state->num_attr; i++) {
+		vga_r(state->vgabase, iobase + 0xa);
+		saved->attr[i] = vga_rattr(state->vgabase, i);
+	}
+	vga_r(state->vgabase, iobase + 0xa);
+	vga_w(state->vgabase, VGA_ATT_W, 0x20);
+
+	for (i = 0; i < state->num_gfx; i++) 
+		saved->gfx[i] = vga_rgfx(state->vgabase, i);
+
+	for (i = 0; i < state->num_seq; i++) 
+		saved->seq[i] = vga_rseq(state->vgabase, i);
+}
+
+static void restore_vga_mode(struct vgastate *state)
+{
+	struct regstate *saved = (struct regstate *) state->vidstate;
+	unsigned short iobase;
+	int i;
+
+	vga_w(state->vgabase, VGA_MIS_W, saved->misc);
+
+	if (saved->misc & 1)
+		iobase = 0x3d0;
+	else
+		iobase = 0x3b0;
+
+	/* turn off display */
+	vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, 
+		 saved->seq[VGA_SEQ_CLOCK_MODE] | 0x20);
+
+	/* disable sequencer */
+	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01);
+	
+	/* enable palette addressing */
+	vga_r(state->vgabase, iobase + 0xa);
+	vga_w(state->vgabase, VGA_ATT_W, 0x00);
+
+	for (i = 2; i < state->num_seq; i++) 
+		vga_wseq(state->vgabase, i, saved->seq[i]);
+
+
+	/* unprotect vga regs */
+	vga_wcrtcs(state->vgabase, iobase, 17, saved->crtc[17] & ~0x80);
+	for (i = 0; i < state->num_crtc; i++) 
+		vga_wcrtcs(state->vgabase, iobase, i, saved->crtc[i]);
+	
+	for (i = 0; i < state->num_gfx; i++) 
+		vga_wgfx(state->vgabase, i, saved->gfx[i]);
+
+	for (i = 0; i < state->num_attr; i++) {
+		vga_r(state->vgabase, iobase + 0xa);
+		vga_wattr(state->vgabase, i, saved->attr[i]);
+	}
+
+	/* reenable sequencer */
+	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
+	/* turn display on */
+	vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, 
+		 saved->seq[VGA_SEQ_CLOCK_MODE] & ~(1 << 5));
+
+	/* disable video/palette source */
+	vga_r(state->vgabase, iobase + 0xa);
+	vga_w(state->vgabase, VGA_ATT_W, 0x20);
+}
+
+static void save_vga_cmap(struct vgastate *state)
+{
+	struct regstate *saved = (struct regstate *) state->vidstate;
+	int i;
+
+	vga_w(state->vgabase, VGA_PEL_MSK, 0xff);
+	
+	/* assumes DAC is readable and writable */
+	vga_w(state->vgabase, VGA_PEL_IR, 0x00);
+	for (i = 0; i < 768; i++)
+		saved->vga_cmap[i] = vga_r(state->vgabase, VGA_PEL_D);
+}
+
+static void restore_vga_cmap(struct vgastate *state)
+{
+	struct regstate *saved = (struct regstate *) state->vidstate;
+	int i;
+
+	vga_w(state->vgabase, VGA_PEL_MSK, 0xff);
+
+	/* assumes DAC is readable and writable */
+	vga_w(state->vgabase, VGA_PEL_IW, 0x00);
+	for (i = 0; i < 768; i++)
+		vga_w(state->vgabase, VGA_PEL_D, saved->vga_cmap[i]);
+}
+
+static void vga_cleanup(struct vgastate *state)
+{
+	if (state->vidstate != NULL) {
+		struct regstate *saved = (struct regstate *) state->vidstate;
+
+		if (saved->vga_font0) 
+			vfree(saved->vga_font0);
+		if (saved->vga_font1) 
+			vfree(saved->vga_font1);
+		if (saved->vga_text)
+			vfree(saved->vga_text);
+		if (saved->vga_cmap)
+			vfree(saved->vga_cmap);
+		if (saved->attr)
+			vfree(saved->attr);
+		kfree(saved);
+		state->vidstate = NULL;
+	}
+}
+		
+int save_vga(struct vgastate *state)
+{
+	struct regstate *saved;
+
+	saved = kmalloc(sizeof(struct regstate), GFP_KERNEL);
+	if (saved == NULL)
+		return 1;
+	memset (saved, 0, sizeof(struct regstate));
+	state->vidstate = (void *)saved;
+		
+	if (state->flags & VGA_SAVE_CMAP) {
+		saved->vga_cmap = vmalloc(768);
+		if (!saved->vga_cmap) {
+			vga_cleanup(state);
+			return 1;
+		}
+		save_vga_cmap(state);
+	}
+
+	if (state->flags & VGA_SAVE_MODE) {
+		int total;
+
+		if (state->num_attr < 21)
+			state->num_attr = 21;
+		if (state->num_crtc < 25)
+			state->num_crtc = 25;
+		if (state->num_gfx < 9)
+			state->num_gfx = 9;
+		if (state->num_seq < 5)
+			state->num_seq = 5;
+		total = state->num_attr + state->num_crtc +
+			state->num_gfx + state->num_seq;
+
+		saved->attr = vmalloc(total);
+		if (!saved->attr) {
+			vga_cleanup(state);
+			return 1;
+		}
+		saved->crtc = saved->attr + state->num_attr;
+		saved->gfx = saved->crtc + state->num_crtc;
+		saved->seq = saved->gfx + state->num_gfx;
+
+		save_vga_mode(state);
+	}
+
+	if (state->flags & VGA_SAVE_FONTS) {
+		void __iomem *fbbase;
+
+		/* exit if window is less than 32K */
+		if (state->memsize && state->memsize < 4 * 8192) {
+			vga_cleanup(state);
+			return 1;
+		}
+		if (!state->memsize)
+			state->memsize = 8 * 8192;
+		
+		if (!state->membase)
+			state->membase = 0xA0000;
+
+		fbbase = ioremap(state->membase, state->memsize);
+
+		if (!fbbase) {
+			vga_cleanup(state);
+			return 1;
+		}
+
+		/* 
+		 * save only first 32K used by vgacon
+		 */
+		if (state->flags & VGA_SAVE_FONT0) {
+			saved->vga_font0 = vmalloc(4 * 8192);
+			if (!saved->vga_font0) {
+				iounmap(fbbase);
+				vga_cleanup(state);
+				return 1;
+			}
+		}
+		/* 
+		 * largely unused, but if required by the caller
+		 * we'll just save everything.
+		 */
+		if (state->flags & VGA_SAVE_FONT1) {
+			saved->vga_font1 = vmalloc(state->memsize);
+			if (!saved->vga_font1) {
+				iounmap(fbbase);
+				vga_cleanup(state);
+				return 1;
+			}
+		}
+		/*
+		 * Save 8K at plane0[0], and 8K at plane1[16K]
+		 */
+		if (state->flags & VGA_SAVE_TEXT) {
+			saved->vga_text = vmalloc(8192 * 2);
+			if (!saved->vga_text) {
+				iounmap(fbbase);
+				vga_cleanup(state);
+				return 1;
+			}
+		}
+		
+		save_vga_text(state, fbbase);
+		iounmap(fbbase);
+	}
+	return 0;
+}
+
+int restore_vga (struct vgastate *state)
+{
+	if (state->vidstate == NULL)
+		return 1;
+
+	if (state->flags & VGA_SAVE_MODE)
+		restore_vga_mode(state);
+
+	if (state->flags & VGA_SAVE_FONTS) {
+		void __iomem *fbbase = ioremap(state->membase, state->memsize);
+
+		if (!fbbase) {
+			vga_cleanup(state);
+			return 1;
+		}
+		restore_vga_text(state, fbbase);
+		iounmap(fbbase);
+	}
+
+	if (state->flags & VGA_SAVE_CMAP)
+		restore_vga_cmap(state);
+
+	vga_cleanup(state);
+	return 0;
+}
+
+#ifdef MODULE
+int init_module(void) { return 0; };
+void cleanup_module(void) {};
+#endif
+
+EXPORT_SYMBOL(save_vga);
+EXPORT_SYMBOL(restore_vga);
+
+MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
+MODULE_DESCRIPTION("VGA State Save/Restore");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/virgefb.c b/drivers/video/virgefb.c
new file mode 100644
index 0000000..ed78747
--- /dev/null
+++ b/drivers/video/virgefb.c
@@ -0,0 +1,2513 @@
+/*
+ * linux/drivers/video/virgefb.c -- CyberVision64/3D frame buffer device
+ *
+ *    Copyright (C) 1997 André Heynatz
+ *
+ *
+ * This file is based on the CyberVision frame buffer device (cyberfb.c):
+ *
+ *    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/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/zorro.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/amigahw.h>
+#include <asm/io.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)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#ifdef VIRGEFBDUMP
+static void cv64_dump(void);
+#define DUMP cv64_dump()
+#else
+#define DUMP
+#endif
+
+/*
+ *	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 {
+   struct fb_var_screeninfo var;
+   __u32 type;
+   __u32 type_aux;
+   __u32 visual;
+   __u32 line_length;
+};
+
+static struct virgefb_par current_par;
+
+static int current_par_valid = 0;
+
+static struct display disp;
+static struct fb_info fb_info;
+
+static union {
+#ifdef FBCON_HAS_CFB16
+    u16 cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+    u32 cfb32[16];
+#endif
+} fbcon_cmap;
+
+/*
+ *    Switch for Chipset Independency
+ */
+
+static struct fb_hwswitch {
+
+   /* Initialisation */
+
+   int (*init)(void);
+
+   /* Display Control */
+
+   int (*encode_fix)(struct fb_fix_screeninfo *fix, struct virgefb_par *par);
+   int (*decode_var)(struct fb_var_screeninfo *var, struct virgefb_par *par);
+   int (*encode_var)(struct fb_var_screeninfo *var, struct virgefb_par *par);
+   int (*getcolreg)(u_int regno, u_int *red, u_int *green, u_int *blue,
+                    u_int *transp, struct fb_info *info);
+   void (*blank)(int blank);
+} *fbhw;
+
+static unsigned char blit_maybe_busy = 0;
+
+/*
+ *    Frame Buffer Name
+ */
+
+static char virgefb_name[16] = "CyberVision/3D";
+
+/*
+ *    CyberVision64/3d Graphics Board
+ */
+
+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
+ */
+
+#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
+
+/*
+ *    MEMCLOCK was 32MHz, 64MHz works, 72MHz doesn't (on my board)
+ */
+
+#define MEMCLOCK 50000000
+
+/*
+ *    Predefined Video Modes
+ */
+
+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, 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, 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, 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, 19230, 280, 168, 45, 1, 64, 10,
+	    0, FB_VMODE_NONINTERLACED
+	    }
+    }, {
+	"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},
+  #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 */
+	    1600, 1200, 1600, 1200, 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, 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, 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, 28571, 168, 104, 22, 1, 48, 2,
+	    0, FB_VMODE_NONINTERLACED
+	    }
+    }, {
+#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, 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 */
+	    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, 19230, 280, 168, 45, 1, 64, 10,
+	    0, FB_VMODE_NONINTERLACED
+	    }
+    }, {
+	"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, 17857, 232, 232, 71, 15, 176, 12,
+	    0, FB_VMODE_NONINTERLACED
+	    }
+    }, {
+	"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, 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
+
+#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
+
+/* 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)
+
+/*
+ *    Default to 800x600 for video=virge8:, virge16: or virge32:
+ */
+
+#ifdef FBCON_HAS_CFB8
+#define VIRGE8_DEFMODE	(2)
+#endif
+
+#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_cmap(struct fb_cmap *cmap, int kspc, int con,
+			   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);
+static int virgefb_blank(int blank, struct fb_info *info);
+
+/*
+ *    Interface to the low level console driver
+ */
+
+int virgefb_init(void);
+static int virgefb_switch(int con, struct fb_info *info);
+static int virgefb_updatevar(int con, struct fb_info *info);
+
+/*
+ *    Text console acceleration
+ */
+
+#ifdef FBCON_HAS_CFB8
+static struct display_switch fbcon_virge8;
+#endif
+
+#ifdef FBCON_HAS_CFB16
+static struct display_switch fbcon_virge16;
+#endif
+
+#ifdef FBCON_HAS_CFB32
+static struct display_switch fbcon_virge32;
+#endif
+
+/*
+ *   Hardware Specific Routines
+ */
+
+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
+ */
+
+static void virgefb_get_par(struct virgefb_par *par);
+static void virgefb_set_par(struct virgefb_par *par);
+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 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
+ */
+
+/* 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;
+
+	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 */
+
+	wb_mmio(GREG_FEATURE_CONTROL_W, 0x00);
+
+	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 {
+		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;
+	}
+
+/* clear framebuffer memory */
+
+	memset((char*)v_ram, 0x00, v_ram_size);
+
+	DPRINTK("EXIT\n");
+	return 0;
+}
+
+
+/*
+ *    This function should fill in the `fix' structure based on the
+ *    values in the `par' structure.
+ */
+
+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 (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 = 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->var.bits_per_pixel == 8)
+		fix->visual = FB_VISUAL_PSEUDOCOLOR;
+	else
+		fix->visual = FB_VISUAL_TRUECOLOR;
+
+	fix->xpanstep = 0;
+	fix->ypanstep = 0;
+	fix->ywrapstep = 0;
+	fix->line_length = par->var.xres_virtual*par->var.bits_per_pixel/8;
+	fix->accel = FB_ACCEL_S3_VIRGE;
+	DPRINTK("EXIT v_ram_phys = 0x%8.8lx\n", (unsigned long)fix->smem_start);
+	return 0;
+}
+
+
+/*
+ *	Fill the `par' structure based on the values in `var'.
+ *	TODO: Verify and adjust values, return -EINVAL if bad.
+ */
+
+static int virgefb_decode_var(struct fb_var_screeninfo *var,
+			    struct virgefb_par *par)
+{
+	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->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->var.accel_flags = 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.
+ */
+
+static int virgefb_encode_var(struct fb_var_screeninfo *var,
+				struct virgefb_par *par)
+{
+	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
+ *    entries in the var structure). Return != 0 for invalid regno.
+ */
+
+static int virgefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			     u_int transp, struct fb_info *info)
+{
+	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.var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
+		case 8:
+			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
+		case 16:
+			fbcon_cmap.cfb16[regno] =
+				((red  & 0xf800) |
+				((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
+	}
+	DPRINTK("EXIT\n");
+	return 0;
+}
+
+
+/*
+ *    Read a single color register and split it into
+ *    colors/transparent. Return != 0 for invalid regno.
+ */
+
+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;
+
+	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;
+	DPRINTK("EXIT\n");
+	return 0;
+}
+
+
+/*
+ *    (Un)Blank the screen
+ */
+
+static void virgefb_gfx_on_off(int blank)
+{
+	DPRINTK("ENTER\n");
+	gfx_on_off(blank);
+	DPRINTK("EXIT\n");
+}
+
+/*
+ * CV3D low-level support
+ */
+
+
+static inline void wait_3d_fifo_slots(int n)	/* WaitQueue */
+{
+	do {
+		mb();
+	} while (((rl_mmio(MR_SUBSYSTEM_STATUS_R) >> 8) & 0x1f) < (n + 2));
+}
+
+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 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;
+
+	switch (depth) {
+#ifdef FBCON_HAS_CFB8
+		case 8 :
+			blitcmd |= S3V_DST_8BPP;
+			break;
+#endif
+#ifdef FBCON_HAS_CFB16
+		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) {
+		blitcmd |= (1 << 25);  /* Drawing direction +X */
+	} else {
+		curx  += (width - 1);
+		destx += (width - 1);
+	}
+
+	if (cury > desty) {
+		blitcmd |= (1 << 26);  /* Drawing direction +Y */
+	} else {
+		cury  += (height - 1);
+		desty += (height - 1);
+	}
+
+	wait_3d_fifo_slots(8);		/* wait on fifo slots for 8 writes */
+
+	if (blit_maybe_busy)
+		virgefb_wait_for_idle();
+	blit_maybe_busy = 1;
+
+	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 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 blitcmd = S3V_RECTFILL | S3V_DRAW |
+		S3V_BLT_CLEAR | S3V_MONO_PAT | (1 << 26) | (1 << 25);
+
+	switch (depth) {
+#ifdef FBCON_HAS_CFB8
+		case 8 :
+			blitcmd |= S3V_DST_8BPP;
+			break;
+#endif
+#ifdef FBCON_HAS_CFB16
+		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
+	}
+
+	wait_3d_fifo_slots(5);		/* wait on fifo slots for 5 writes */
+
+	if (blit_maybe_busy)
+		virgefb_wait_for_idle();
+	blit_maybe_busy = 1;
+
+	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 virgefb_move_cursor(u_short x, u_short y)
+{
+	DPRINTK("Yuck .... MoveCursor on a 3D\n");
+	return 0;
+}
+#endif
+
+/* -------------------- Interfaces to hardware functions -------------------- */
+
+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
+};
+
+
+/* -------------------- Generic routines ------------------------------------ */
+
+
+/*
+ *    Fill the hardware's `par' structure.
+ */
+
+static void virgefb_get_par(struct virgefb_par *par)
+{
+	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 virgefb_set_video(struct fb_var_screeninfo *var)
+{
+/* 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_mmio(BLT_CLIP_LEFT_RIGHT, clip);
+	clip = ((0 << 16) | (var->yres - 1));
+	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 virgefb_do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
+{
+	int err, activate;
+	struct virgefb_par par;
+
+	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;
+        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
+ */
+
+static int virgefb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			   struct fb_info *info)
+{
+	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);
+
+	if (!error)
+		error = fbhw->encode_fix(fix, &par);
+	DPRINTK("EXIT\n");
+	return(error);
+}
+
+
+/*
+ *    Get the User Defined Part of the Display
+ */
+
+static int virgefb_get_var(struct fb_var_screeninfo *var, int con,
+			   struct fb_info *info)
+{
+	struct virgefb_par par;
+	int error = 0;
+
+	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 {
+		*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
+		display = &disp;	/* used during initialization */
+
+	virgefb_get_fix(&fix, con, info);
+	if (con == -1)
+		con = 0;
+	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*)(v_ram + CYBMEM_OFFSET_8);
+				break;
+#endif
+#ifdef FBCON_HAS_CFB16
+			case 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;
+	display->type = fix.type;
+	display->type_aux = fix.type_aux;
+	display->ypanstep = fix.ypanstep;
+	display->ywrapstep = fix.ywrapstep;
+	display->can_soft_blank = 1;
+	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:
+			if (display->var.accel_flags & FB_ACCELF_TEXT) {
+		   		display->dispsw = &fbcon_virge8;
+#warning FIXME: We should reinit the graphics engine here
+			} else
+				display->dispsw = &fbcon_cfb8;
+			break;
+#endif
+#ifdef FBCON_HAS_CFB16
+		case 16:
+			if (display->var.accel_flags & FB_ACCELF_TEXT) {
+				display->dispsw = &fbcon_virge16;
+			} else
+				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);
+}
+
+
+/*
+ *    Set the User Defined Part of the Display
+ */
+
+static int virgefb_set_var(struct fb_var_screeninfo *var, int con,
+			   struct fb_info *info)
+{
+	int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel;
+
+	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;
+		oldvxres = fb_display[con].var.xres_virtual;
+		oldvyres = fb_display[con].var.yres_virtual;
+		oldbpp = fb_display[con].var.bits_per_pixel;
+		oldaccel = fb_display[con].var.accel_flags;
+		fb_display[con].var = *var;
+		if (oldxres != var->xres || oldyres != var->yres ||
+		    oldvxres != var->xres_virtual ||
+		    oldvyres != var->yres_virtual ||
+		    oldbpp != var->bits_per_pixel ||
+		    oldaccel != var->accel_flags) {
+			virgefb_set_disp(con, info);
+			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;
+	DPRINTK("EXIT\n");
+	return 0;
+}
+
+
+/*
+ *    Get the Colormap
+ */
+
+static int virgefb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			    struct fb_info *info)
+{
+	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? */
+		DPRINTK("Use console cmap\n");
+		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
+	} 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);
+	}
+	DPRINTK("EXIT\n");
+	return 0;
+}
+
+static struct fb_ops virgefb_ops = {
+	.owner =	THIS_MODULE,
+	.fb_get_fix =	virgefb_get_fix,
+	.fb_get_var =	virgefb_get_var,
+	.fb_set_var =	virgefb_set_var,
+	.fb_get_cmap =	virgefb_get_cmap,
+	.fb_set_cmap =	gen_set_cmap,
+	.fb_setcolreg =	virgefb_setcolreg,
+	.fb_blank =	virgefb_blank,
+};
+
+int __init virgefb_setup(char *options)
+{
+	char *this_opt;
+	fb_info.fontname[0] = '\0';
+
+	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")) {
+			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
+			virgefb_get_video_mode(this_opt);
+	}
+
+	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
+ */
+
+int __init virgefb_init(void)
+{
+	struct virgefb_par par;
+	unsigned long board_addr, board_size;
+	struct zorro_dev *z = NULL;
+
+	DPRINTK("ENTER\n");
+
+	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 {
+
+		/* board running in Z3 space. Separate video memory (3 apertures)
+		   and S3 register set */
+
+		on_zorro2 = 0;
+		board_size = 0x01000000;
+
+		if (!request_mem_region(board_addr, board_size, "S3 ViRGE"))
+			return -ENOMEM;
+
+		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 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.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",
+	       fb_info.node, fb_info.modename, v_ram_size>>10);
+
+	/* TODO: This driver cannot be unloaded yet */
+
+	DPRINTK("EXIT\n");
+	return 0;
+}
+
+
+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);
+	virgefb_do_fb_set_var(&fb_display[con].var, 1);
+	info->currcon = con;
+	/* Install new colormap */
+	do_install_cmap(con, info);
+	DPRINTK("EXIT\n");
+	return 0;
+}
+
+
+/*
+ *    Update the `var' structure (called by fbcon.c)
+ *
+ *    This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
+ *    Since it's called by a kernel driver, no range checking is done.
+ */
+
+static int virgefb_updatevar(int con, struct fb_info *info)
+{
+	DPRINTK("ENTER\n");
+	return 0;
+	DPRINTK("EXIT\n");
+}
+
+/*
+ *    Blank the display.
+ */
+
+static int virgefb_blank(int blank, struct fb_info *info)
+{
+	DPRINTK("ENTER\n");
+	fbhw->blank(blank);
+	DPRINTK("EXIT\n");
+	return 0;
+}
+
+
+/*
+ *    Text console acceleration
+ */
+
+#ifdef FBCON_HAS_CFB8
+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;
+        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, 8);
+}
+
+static void fbcon_virge8_clear(struct vc_data *conp, struct display *p, int sy,
+			       int sx, int height, int width)
+{
+        unsigned char bg;
+
+        sx *= 8; width *= 8;
+        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, 8);
+}
+
+static void fbcon_virge8_putc(struct vc_data *conp, struct display *p, int c, int yy,
+                              int xx)
+{
+	if (blit_maybe_busy)
+		virgefb_wait_for_idle();
+	fbcon_cfb8_putc(conp, p, c, yy, xx);
+}
+
+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)
+		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)
+		virgefb_wait_for_idle();
+	fbcon_cfb8_revc(p, xx, yy);
+}
+
+static void fbcon_virge8_clear_margins(struct vc_data *conp, struct display *p,
+                              int bottom_only)
+{
+	if (blit_maybe_busy)
+		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)
+};
+#endif
+
+#ifdef FBCON_HAS_CFB16
+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;
+        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_virge16_clear(struct vc_data *conp, struct display *p, int sy,
+                               int sx, int height, int width)
+{
+        unsigned char bg;
+
+        sx *= 8; width *= 8;
+        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_virge16_putc(struct vc_data *conp, struct display *p, int c, int yy,
+                              int xx)
+{
+	if (blit_maybe_busy)
+		virgefb_wait_for_idle();
+	fbcon_cfb16_putc(conp, p, c, yy, xx);
+}
+
+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)
+		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)
+		virgefb_wait_for_idle();
+	fbcon_cfb16_revc(p, xx, yy);
+}
+
+static void fbcon_virge16_clear_margins(struct vc_data *conp, struct display *p,
+                              int bottom_only)
+{
+	if (blit_maybe_busy)
+		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)
+};
+#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
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+
+int init_module(void)
+{
+	return virgefb_init();
+}
+#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
index 0000000..157d66d
--- /dev/null
+++ b/drivers/video/virgefb.h
@@ -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)
diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c
new file mode 100644
index 0000000..057e154
--- /dev/null
+++ b/drivers/video/w100fb.c
@@ -0,0 +1,1873 @@
+/*
+ * linux/drivers/video/w100fb.c
+ *
+ * Frame Buffer Device for ATI Imageon w100 (Wallaby)
+ *
+ * Copyright (C) 2002, ATI Corp.
+ * Copyright (C) 2004-2005 Richard Purdie
+ *
+ * Rewritten for 2.6 by Richard Purdie <rpurdie@rpsys.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/device.h>
+#include <linux/string.h>
+#include <linux/proc_fs.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <video/w100fb.h>
+#include "w100fb.h"
+
+/*
+ * Prototypes
+ */
+static void w100fb_save_buffer(void);
+static void w100fb_clear_buffer(void);
+static void w100fb_restore_buffer(void);
+static void w100fb_clear_screen(u32 mode, long int offset);
+static void w100_resume(void);
+static void w100_suspend(u32 mode);
+static void w100_init_qvga_rotation(u16 deg);
+static void w100_init_vga_rotation(u16 deg);
+static void w100_vsync(void);
+static void w100_init_sharp_lcd(u32 mode);
+static void w100_pwm_setup(void);
+static void w100_InitExtMem(u32 mode);
+static void w100_hw_init(void);
+static u16 w100_set_fastsysclk(u16 Freq);
+
+static void lcdtg_hw_init(u32 mode);
+static void lcdtg_lcd_change(u32 mode);
+static void lcdtg_resume(void);
+static void lcdtg_suspend(void);
+
+
+/* Register offsets & lengths */
+#define REMAPPED_FB_LEN   0x15ffff
+
+#define BITS_PER_PIXEL    16
+
+/* Pseudo palette size */
+#define MAX_PALETTES      16
+
+/* for resolution change */
+#define LCD_MODE_INIT (-1)
+#define LCD_MODE_480    0
+#define LCD_MODE_320    1
+#define LCD_MODE_240    2
+#define LCD_MODE_640    3
+
+#define LCD_SHARP_QVGA 0
+#define LCD_SHARP_VGA  1
+
+#define LCD_MODE_PORTRAIT	0
+#define LCD_MODE_LANDSCAPE	1
+
+#define W100_SUSPEND_EXTMEM 0
+#define W100_SUSPEND_ALL    1
+
+/* General frame buffer data structures */
+struct w100fb_par {
+	u32 xres;
+	u32 yres;
+	int fastsysclk_mode;
+	int lcdMode;
+	int rotation_flag;
+	int blanking_flag;
+	int comadj;
+	int phadadj;
+};
+
+static struct w100fb_par *current_par;
+
+/* Remapped addresses for base cfg, memmapped regs and the frame buffer itself */
+static void *remapped_base;
+static void *remapped_regs;
+static void *remapped_fbuf;
+
+/* External Function */
+static void(*w100fb_ssp_send)(u8 adrs, u8 data);
+
+/*
+ * Sysfs functions
+ */
+
+static ssize_t rotation_show(struct device *dev, char *buf)
+{
+	struct fb_info *info = dev_get_drvdata(dev);
+	struct w100fb_par *par=info->par;
+
+	return sprintf(buf, "%d\n",par->rotation_flag);
+}
+
+static ssize_t rotation_store(struct device *dev, const char *buf, size_t count)
+{
+	unsigned int rotate;
+	struct fb_info *info = dev_get_drvdata(dev);
+	struct w100fb_par *par=info->par;
+
+	rotate = simple_strtoul(buf, NULL, 10);
+
+	if (rotate > 0) par->rotation_flag = 1;
+	else par->rotation_flag = 0;
+
+	if (par->lcdMode == LCD_MODE_320)
+		w100_init_qvga_rotation(par->rotation_flag ? 270 : 90);
+	else if (par->lcdMode == LCD_MODE_240)
+		w100_init_qvga_rotation(par->rotation_flag ? 180 : 0);
+	else if (par->lcdMode == LCD_MODE_640)
+		w100_init_vga_rotation(par->rotation_flag ? 270 : 90);
+	else if (par->lcdMode == LCD_MODE_480)
+		w100_init_vga_rotation(par->rotation_flag ? 180 : 0);
+
+	return count;
+}
+
+static DEVICE_ATTR(rotation, 0644, rotation_show, rotation_store);
+
+static ssize_t w100fb_reg_read(struct device *dev, const char *buf, size_t count)
+{
+	unsigned long param;
+	unsigned long regs;
+	regs = simple_strtoul(buf, NULL, 16);
+	param = readl(remapped_regs + regs);
+	printk("Read Register 0x%08lX: 0x%08lX\n", regs, param);
+	return count;
+}
+
+static DEVICE_ATTR(reg_read, 0200, NULL, w100fb_reg_read);
+
+static ssize_t w100fb_reg_write(struct device *dev, const char *buf, size_t count)
+{
+	unsigned long regs;
+	unsigned long param;
+	sscanf(buf, "%lx %lx", &regs, &param);
+
+	if (regs <= 0x2000) {
+		printk("Write Register 0x%08lX: 0x%08lX\n", regs, param);
+		writel(param, remapped_regs + regs);
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(reg_write, 0200, NULL, w100fb_reg_write);
+
+
+static ssize_t fastsysclk_show(struct device *dev, char *buf)
+{
+	struct fb_info *info = dev_get_drvdata(dev);
+	struct w100fb_par *par=info->par;
+
+	return sprintf(buf, "%d\n",par->fastsysclk_mode);
+}
+
+static ssize_t fastsysclk_store(struct device *dev, const char *buf, size_t count)
+{
+	int param;
+	struct fb_info *info = dev_get_drvdata(dev);
+	struct w100fb_par *par=info->par;
+
+	param = simple_strtoul(buf, NULL, 10);
+
+	if (param == 75) {
+		printk("Set fastsysclk %d\n", param);
+		par->fastsysclk_mode = param;
+		w100_set_fastsysclk(par->fastsysclk_mode);
+	} else if (param == 100) {
+		printk("Set fastsysclk %d\n", param);
+		par->fastsysclk_mode = param;
+		w100_set_fastsysclk(par->fastsysclk_mode);
+	}
+	return count;
+}
+
+static DEVICE_ATTR(fastsysclk, 0644, fastsysclk_show, fastsysclk_store);
+
+/*
+ * The touchscreen on this device needs certain information
+ * from the video driver to function correctly. We export it here.
+ */
+int w100fb_get_xres(void) {
+	return current_par->xres;
+}
+
+int w100fb_get_blanking(void) {
+	return current_par->blanking_flag;
+}
+
+int w100fb_get_fastsysclk(void) {
+	return current_par->fastsysclk_mode;
+}
+EXPORT_SYMBOL(w100fb_get_xres);
+EXPORT_SYMBOL(w100fb_get_blanking);
+EXPORT_SYMBOL(w100fb_get_fastsysclk);
+
+
+/*
+ * Set a palette value from rgb components
+ */
+static int w100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			     u_int trans, struct fb_info *info)
+{
+	unsigned int val;
+	int ret = 1;
+
+	/*
+	 * If greyscale is true, then we convert the RGB value
+	 * to greyscale no matter what visual we are using.
+	 */
+	if (info->var.grayscale)
+		red = green = blue = (19595 * red + 38470 * green + 7471 * blue) >> 16;
+
+	/*
+	 * 16-bit True Colour.  We encode the RGB value
+	 * according to the RGB bitfield information.
+	 */
+	if (regno < MAX_PALETTES) {
+
+		u32 *pal = info->pseudo_palette;
+
+		val = (red & 0xf800) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
+		pal[regno] = val;
+		ret = 0;
+	}
+	return ret;
+}
+
+
+/*
+ * Blank the display based on value in blank_mode
+ */
+static int w100fb_blank(int blank_mode, struct fb_info *info)
+{
+	struct w100fb_par *par;
+	par=info->par;
+
+	switch(blank_mode) {
+
+ 	case FB_BLANK_NORMAL: /* Normal blanking */
+	case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
+	case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
+ 	case FB_BLANK_POWERDOWN: /* Poweroff */
+  		if (par->blanking_flag == 0) {
+			w100fb_save_buffer();
+			lcdtg_suspend();
+			par->blanking_flag = 1;
+  		}
+  		break;
+
+ 	case FB_BLANK_UNBLANK: /* Unblanking */
+  		if (par->blanking_flag != 0) {
+			w100fb_restore_buffer();
+			lcdtg_resume();
+			par->blanking_flag = 0;
+  		}
+  		break;
+ 	}
+	return 0;
+}
+
+/*
+ *  Change the resolution by calling the appropriate hardware functions
+ */
+static void w100fb_changeres(int rotate_mode, u32 mode)
+{
+	u16 rotation=0;
+
+	switch(rotate_mode) {
+	case LCD_MODE_LANDSCAPE:
+		rotation=(current_par->rotation_flag ? 270 : 90);
+		break;
+	case LCD_MODE_PORTRAIT:
+		rotation=(current_par->rotation_flag ? 180 : 0);
+		break;
+	}
+
+	w100_pwm_setup();
+	switch(mode) {
+	case LCD_SHARP_QVGA:
+		w100_vsync();
+		w100_suspend(W100_SUSPEND_EXTMEM);
+		w100_init_sharp_lcd(LCD_SHARP_QVGA);
+		w100_init_qvga_rotation(rotation);
+		w100_InitExtMem(LCD_SHARP_QVGA);
+		w100fb_clear_screen(LCD_SHARP_QVGA, 0);
+		lcdtg_lcd_change(LCD_SHARP_QVGA);
+		break;
+	case LCD_SHARP_VGA:
+		w100fb_clear_screen(LCD_SHARP_QVGA, 0);
+		writel(0xBFFFA000, remapped_regs + mmMC_EXT_MEM_LOCATION);
+		w100_InitExtMem(LCD_SHARP_VGA);
+		w100fb_clear_screen(LCD_SHARP_VGA, 0x200000);
+		w100_vsync();
+		w100_init_sharp_lcd(LCD_SHARP_VGA);
+		if (rotation != 0)
+			w100_init_vga_rotation(rotation);
+		lcdtg_lcd_change(LCD_SHARP_VGA);
+		break;
+	}
+}
+
+/*
+ * Set up the display for the fb subsystem
+ */
+static void w100fb_activate_var(struct fb_info *info)
+{
+	u32 temp32;
+	struct w100fb_par *par=info->par;
+	struct fb_var_screeninfo *var = &info->var;
+
+	/* Set the hardware to 565 */
+	temp32 = readl(remapped_regs + mmDISP_DEBUG2);
+	temp32 &= 0xff7fffff;
+	temp32 |= 0x00800000;
+	writel(temp32, remapped_regs + mmDISP_DEBUG2);
+
+	if (par->lcdMode == LCD_MODE_INIT) {
+		w100_init_sharp_lcd(LCD_SHARP_VGA);
+		w100_init_vga_rotation(par->rotation_flag ? 270 : 90);
+		par->lcdMode = LCD_MODE_640;
+		lcdtg_hw_init(LCD_SHARP_VGA);
+	} else if (var->xres == 320 && var->yres == 240) {
+		if (par->lcdMode != LCD_MODE_320) {
+			w100fb_changeres(LCD_MODE_LANDSCAPE, LCD_SHARP_QVGA);
+			par->lcdMode = LCD_MODE_320;
+		}
+	} else if (var->xres == 240 && var->yres == 320) {
+		if (par->lcdMode != LCD_MODE_240) {
+			w100fb_changeres(LCD_MODE_PORTRAIT, LCD_SHARP_QVGA);
+			par->lcdMode = LCD_MODE_240;
+		}
+	} else if (var->xres == 640 && var->yres == 480) {
+		if (par->lcdMode != LCD_MODE_640) {
+			w100fb_changeres(LCD_MODE_LANDSCAPE, LCD_SHARP_VGA);
+			par->lcdMode = LCD_MODE_640;
+		}
+	} else if (var->xres == 480 && var->yres == 640) {
+		if (par->lcdMode != LCD_MODE_480) {
+			w100fb_changeres(LCD_MODE_PORTRAIT, LCD_SHARP_VGA);
+			par->lcdMode = LCD_MODE_480;
+		}
+	} else printk(KERN_ERR "W100FB: Resolution error!\n");
+}
+
+
+/*
+ *  w100fb_check_var():
+ *  Get the video params out of 'var'. If a value doesn't fit, round it up,
+ *  if it's too big, return -EINVAL.
+ *
+ */
+static int w100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	if (var->xres < var->yres) { /* Portrait mode */
+		if ((var->xres > 480) || (var->yres > 640)) {
+			return -EINVAL;
+		} else if ((var->xres > 240) || (var->yres > 320)) {
+			var->xres = 480;
+			var->yres = 640;
+		} else {
+			var->xres = 240;
+			var->yres = 320;
+		}
+	} else { /* Landscape mode */
+		if ((var->xres > 640) || (var->yres > 480)) {
+			return -EINVAL;
+		} else if ((var->xres > 320) || (var->yres > 240)) {
+			var->xres = 640;
+			var->yres = 480;
+		} else {
+			var->xres = 320;
+			var->yres = 240;
+		}
+	}
+
+	var->xres_virtual = max(var->xres_virtual, var->xres);
+	var->yres_virtual = max(var->yres_virtual, var->yres);
+
+	if (var->bits_per_pixel > BITS_PER_PIXEL)
+		return -EINVAL;
+	else
+		var->bits_per_pixel = BITS_PER_PIXEL;
+
+	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 = var->transp.length = 0;
+
+	var->nonstd = 0;
+
+	var->height = -1;
+	var->width = -1;
+	var->vmode = FB_VMODE_NONINTERLACED;
+
+	var->sync = 0;
+	var->pixclock = 0x04;	/* 171521; */
+
+	return 0;
+}
+
+
+/*
+ * w100fb_set_par():
+ *	Set the user defined part of the display for the specified console
+ *  by looking at the values in info.var
+ */
+static int w100fb_set_par(struct fb_info *info)
+{
+	struct w100fb_par *par=info->par;
+
+	par->xres = info->var.xres;
+	par->yres = info->var.yres;
+
+	info->fix.visual = FB_VISUAL_TRUECOLOR;
+
+	info->fix.ypanstep = 0;
+	info->fix.ywrapstep = 0;
+
+	if (par->blanking_flag)
+		w100fb_clear_buffer();
+
+	w100fb_activate_var(info);
+
+	if (par->lcdMode == LCD_MODE_480) {
+		info->fix.line_length = (480 * BITS_PER_PIXEL) / 8;
+		info->fix.smem_len = 0x200000;
+	} else if (par->lcdMode == LCD_MODE_320) {
+		info->fix.line_length = (320 * BITS_PER_PIXEL) / 8;
+		info->fix.smem_len = 0x60000;
+	} else if (par->lcdMode == LCD_MODE_240) {
+		info->fix.line_length = (240 * BITS_PER_PIXEL) / 8;
+		info->fix.smem_len = 0x60000;
+	} else if (par->lcdMode == LCD_MODE_INIT || par->lcdMode == LCD_MODE_640) {
+		info->fix.line_length = (640 * BITS_PER_PIXEL) / 8;
+		info->fix.smem_len = 0x200000;
+	}
+
+	return 0;
+}
+
+
+/*
+ *      Frame buffer operations
+ */
+static struct fb_ops w100fb_ops = {
+	.owner = THIS_MODULE,
+	.fb_check_var = w100fb_check_var,
+	.fb_set_par = w100fb_set_par,
+	.fb_setcolreg = w100fb_setcolreg,
+	.fb_blank = w100fb_blank,
+	.fb_fillrect = cfb_fillrect,
+	.fb_copyarea = cfb_copyarea,
+	.fb_imageblit = cfb_imageblit,
+	.fb_cursor = soft_cursor,
+};
+
+
+static void w100fb_clear_screen(u32 mode, long int offset)
+{
+	int i, numPix = 0;
+
+	if (mode == LCD_SHARP_VGA)
+		numPix = 640 * 480;
+	else if (mode == LCD_SHARP_QVGA)
+		numPix = 320 * 240;
+
+	for (i = 0; i < numPix; i++)
+		writew(0xffff, remapped_fbuf + offset + (2*i));
+}
+
+
+/* Need to split up the buffers to stay within the limits of kmalloc */
+#define W100_BUF_NUM	6
+static uint32_t *gSaveImagePtr[W100_BUF_NUM] = { NULL };
+
+static void w100fb_save_buffer(void)
+{
+	int i, j, bufsize;
+
+	bufsize=(current_par->xres * current_par->yres * BITS_PER_PIXEL / 8) / W100_BUF_NUM;
+	for (i = 0; i < W100_BUF_NUM; i++) {
+		if (gSaveImagePtr[i] == NULL)
+			gSaveImagePtr[i] = kmalloc(bufsize, GFP_KERNEL);
+		if (gSaveImagePtr[i] == NULL) {
+			w100fb_clear_buffer();
+			printk(KERN_WARNING "can't alloc pre-off image buffer %d\n", i);
+			break;
+		}
+		for (j = 0; j < bufsize/4; j++)
+			*(gSaveImagePtr[i] + j) = readl(remapped_fbuf + (bufsize*i) + j*4);
+	}
+}
+
+
+static void w100fb_restore_buffer(void)
+{
+	int i, j, bufsize;
+
+	bufsize=(current_par->xres * current_par->yres * BITS_PER_PIXEL / 8) / W100_BUF_NUM;
+	for (i = 0; i < W100_BUF_NUM; i++) {
+		if (gSaveImagePtr[i] == NULL) {
+			printk(KERN_WARNING "can't find pre-off image buffer %d\n", i);
+			w100fb_clear_buffer();
+			break;
+		}
+		for (j = 0; j < (bufsize/4); j++)
+			writel(*(gSaveImagePtr[i] + j),remapped_fbuf + (bufsize*i) + (j*4));
+		kfree(gSaveImagePtr[i]);
+		gSaveImagePtr[i] = NULL;
+	}
+}
+
+
+static void w100fb_clear_buffer(void)
+{
+	int i;
+	for (i = 0; i < W100_BUF_NUM; i++) {
+		kfree(gSaveImagePtr[i]);
+		gSaveImagePtr[i] = NULL;
+	}
+}
+
+
+#ifdef CONFIG_PM
+static int w100fb_suspend(struct device *dev, u32 state, u32 level)
+{
+	if (level == SUSPEND_POWER_DOWN) {
+		struct fb_info *info = dev_get_drvdata(dev);
+		struct w100fb_par *par=info->par;
+
+		w100fb_save_buffer();
+		lcdtg_suspend();
+		w100_suspend(W100_SUSPEND_ALL);
+		par->blanking_flag = 1;
+	}
+	return 0;
+}
+
+static int w100fb_resume(struct device *dev, u32 level)
+{
+	if (level == RESUME_POWER_ON) {
+		struct fb_info *info = dev_get_drvdata(dev);
+		struct w100fb_par *par=info->par;
+
+		w100_resume();
+		w100fb_restore_buffer();
+		lcdtg_resume();
+		par->blanking_flag = 0;
+	}
+	return 0;
+}
+#else
+#define w100fb_suspend	NULL
+#define w100fb_resume	NULL
+#endif
+
+
+int __init w100fb_probe(struct device *dev)
+{
+	struct w100fb_mach_info *inf;
+	struct fb_info *info;
+	struct w100fb_par *par;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (!mem)
+		return -EINVAL;
+
+	/* remap the areas we're going to use */
+	remapped_base = ioremap_nocache(mem->start+W100_CFG_BASE, W100_CFG_LEN);
+	if (remapped_base == NULL)
+		return -EIO;
+
+	remapped_regs = ioremap_nocache(mem->start+W100_REG_BASE, W100_REG_LEN);
+	if (remapped_regs == NULL) {
+		iounmap(remapped_base);
+		return -EIO;
+	}
+
+	remapped_fbuf = ioremap_nocache(mem->start+MEM_EXT_BASE_VALUE, REMAPPED_FB_LEN);
+	if (remapped_fbuf == NULL) {
+		iounmap(remapped_base);
+		iounmap(remapped_regs);
+		return -EIO;
+	}
+
+	info=framebuffer_alloc(sizeof(struct w100fb_par), dev);
+	if (!info) {
+		iounmap(remapped_base);
+		iounmap(remapped_regs);
+		iounmap(remapped_fbuf);
+		return -ENOMEM;
+	}
+
+	info->device=dev;
+	par = info->par;
+	current_par=info->par;
+	dev_set_drvdata(dev, info);
+
+	inf = dev->platform_data;
+	par->phadadj = inf->phadadj;
+	par->comadj = inf->comadj;
+	par->fastsysclk_mode = 75;
+	par->lcdMode = LCD_MODE_INIT;
+	par->rotation_flag=0;
+	par->blanking_flag=0;
+	w100fb_ssp_send = inf->w100fb_ssp_send;
+
+	w100_hw_init();
+	w100_pwm_setup();
+
+	info->pseudo_palette = kmalloc(sizeof (u32) * MAX_PALETTES, GFP_KERNEL);
+	if (!info->pseudo_palette) {
+		iounmap(remapped_base);
+		iounmap(remapped_regs);
+		iounmap(remapped_fbuf);
+		return -ENOMEM;
+	}
+
+	info->fbops = &w100fb_ops;
+	info->flags = FBINFO_DEFAULT;
+	info->node = -1;
+	info->screen_base = remapped_fbuf;
+	info->screen_size = REMAPPED_FB_LEN;
+
+	info->var.xres = 640;
+	info->var.xres_virtual = info->var.xres;
+	info->var.yres = 480;
+	info->var.yres_virtual = info->var.yres;
+	info->var.pixclock = 0x04;	/* 171521; */
+	info->var.sync = 0;
+	info->var.grayscale = 0;
+	info->var.xoffset = info->var.yoffset = 0;
+	info->var.accel_flags = 0;
+	info->var.activate = FB_ACTIVATE_NOW;
+
+	strcpy(info->fix.id, "w100fb");
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.type_aux = 0;
+	info->fix.accel = FB_ACCEL_NONE;
+	info->fix.smem_start = mem->start+MEM_EXT_BASE_VALUE;
+	info->fix.mmio_start = mem->start+W100_REG_BASE;
+	info->fix.mmio_len = W100_REG_LEN;
+
+	w100fb_check_var(&info->var, info);
+	w100fb_set_par(info);
+
+	if (register_framebuffer(info) < 0) {
+		kfree(info->pseudo_palette);
+		iounmap(remapped_base);
+		iounmap(remapped_regs);
+		iounmap(remapped_fbuf);
+		return -EINVAL;
+	}
+
+	device_create_file(dev, &dev_attr_fastsysclk);
+	device_create_file(dev, &dev_attr_reg_read);
+	device_create_file(dev, &dev_attr_reg_write);
+	device_create_file(dev, &dev_attr_rotation);
+
+	printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id);
+	return 0;
+}
+
+
+static int w100fb_remove(struct device *dev)
+{
+	struct fb_info *info = dev_get_drvdata(dev);
+
+	device_remove_file(dev, &dev_attr_fastsysclk);
+	device_remove_file(dev, &dev_attr_reg_read);
+	device_remove_file(dev, &dev_attr_reg_write);
+	device_remove_file(dev, &dev_attr_rotation);
+
+	unregister_framebuffer(info);
+
+	w100fb_clear_buffer();
+	kfree(info->pseudo_palette);
+
+	iounmap(remapped_base);
+	iounmap(remapped_regs);
+	iounmap(remapped_fbuf);
+
+	framebuffer_release(info);
+
+	return 0;
+}
+
+
+/* ------------------- chipset specific functions -------------------------- */
+
+
+static void w100_soft_reset(void)
+{
+	u16 val = readw((u16 *) remapped_base + cfgSTATUS);
+	writew(val | 0x08, (u16 *) remapped_base + cfgSTATUS);
+	udelay(100);
+	writew(0x00, (u16 *) remapped_base + cfgSTATUS);
+	udelay(100);
+}
+
+/*
+ * Initialization of critical w100 hardware
+ */
+static void w100_hw_init(void)
+{
+	u32 temp32;
+	union cif_cntl_u cif_cntl;
+	union intf_cntl_u intf_cntl;
+	union cfgreg_base_u cfgreg_base;
+	union wrap_top_dir_u wrap_top_dir;
+	union cif_read_dbg_u cif_read_dbg;
+	union cpu_defaults_u cpu_default;
+	union cif_write_dbg_u cif_write_dbg;
+	union wrap_start_dir_u wrap_start_dir;
+	union mc_ext_mem_location_u mc_ext_mem_loc;
+	union cif_io_u cif_io;
+
+	w100_soft_reset();
+
+	/* This is what the fpga_init code does on reset. May be wrong
+	   but there is little info available */
+	writel(0x31, remapped_regs + mmSCRATCH_UMSK);
+	for (temp32 = 0; temp32 < 10000; temp32++)
+		readl(remapped_regs + mmSCRATCH_UMSK);
+	writel(0x30, remapped_regs + mmSCRATCH_UMSK);
+
+	/* Set up CIF */
+	cif_io.val = defCIF_IO;
+	writel((u32)(cif_io.val), remapped_regs + mmCIF_IO);
+
+	cif_write_dbg.val = readl(remapped_regs + mmCIF_WRITE_DBG);
+	cif_write_dbg.f.dis_packer_ful_during_rbbm_timeout = 0;
+	cif_write_dbg.f.en_dword_split_to_rbbm = 1;
+	cif_write_dbg.f.dis_timeout_during_rbbm = 1;
+	writel((u32) (cif_write_dbg.val), remapped_regs + mmCIF_WRITE_DBG);
+
+	cif_read_dbg.val = readl(remapped_regs + mmCIF_READ_DBG);
+	cif_read_dbg.f.dis_rd_same_byte_to_trig_fetch = 1;
+	writel((u32) (cif_read_dbg.val), remapped_regs + mmCIF_READ_DBG);
+
+	cif_cntl.val = readl(remapped_regs + mmCIF_CNTL);
+	cif_cntl.f.dis_system_bits = 1;
+	cif_cntl.f.dis_mr = 1;
+	cif_cntl.f.en_wait_to_compensate_dq_prop_dly = 0;
+	cif_cntl.f.intb_oe = 1;
+	cif_cntl.f.interrupt_active_high = 1;
+	writel((u32) (cif_cntl.val), remapped_regs + mmCIF_CNTL);
+
+	/* Setup cfgINTF_CNTL and cfgCPU defaults */
+	intf_cntl.val = defINTF_CNTL;
+	intf_cntl.f.ad_inc_a = 1;
+	intf_cntl.f.ad_inc_b = 1;
+	intf_cntl.f.rd_data_rdy_a = 0;
+	intf_cntl.f.rd_data_rdy_b = 0;
+	writeb((u8) (intf_cntl.val), remapped_base + cfgINTF_CNTL);
+
+	cpu_default.val = defCPU_DEFAULTS;
+	cpu_default.f.access_ind_addr_a = 1;
+	cpu_default.f.access_ind_addr_b = 1;
+	cpu_default.f.access_scratch_reg = 1;
+	cpu_default.f.transition_size = 0;
+	writeb((u8) (cpu_default.val), remapped_base + cfgCPU_DEFAULTS);
+
+	/* set up the apertures */
+	writeb((u8) (W100_REG_BASE >> 16), remapped_base + cfgREG_BASE);
+
+	cfgreg_base.val = defCFGREG_BASE;
+	cfgreg_base.f.cfgreg_base = W100_CFG_BASE;
+	writel((u32) (cfgreg_base.val), remapped_regs + mmCFGREG_BASE);
+
+	/* This location is relative to internal w100 addresses */
+	writel(0x15FF1000, remapped_regs + mmMC_FB_LOCATION);
+
+	mc_ext_mem_loc.val = defMC_EXT_MEM_LOCATION;
+	mc_ext_mem_loc.f.mc_ext_mem_start = MEM_EXT_BASE_VALUE >> 8;
+	mc_ext_mem_loc.f.mc_ext_mem_top = MEM_EXT_TOP_VALUE >> 8;
+	writel((u32) (mc_ext_mem_loc.val), remapped_regs + mmMC_EXT_MEM_LOCATION);
+
+	if ((current_par->lcdMode == LCD_MODE_240) || (current_par->lcdMode == LCD_MODE_320))
+		w100_InitExtMem(LCD_SHARP_QVGA);
+	else
+		w100_InitExtMem(LCD_SHARP_VGA);
+
+	wrap_start_dir.val = defWRAP_START_DIR;
+	wrap_start_dir.f.start_addr = WRAP_BUF_BASE_VALUE >> 1;
+	writel((u32) (wrap_start_dir.val), remapped_regs + mmWRAP_START_DIR);
+
+	wrap_top_dir.val = defWRAP_TOP_DIR;
+	wrap_top_dir.f.top_addr = WRAP_BUF_TOP_VALUE >> 1;
+	writel((u32) (wrap_top_dir.val), remapped_regs + mmWRAP_TOP_DIR);
+
+	writel((u32) 0x2440, remapped_regs + mmRBBM_CNTL);
+}
+
+
+/*
+ * Types
+ */
+
+struct pll_parm {
+	u16 freq;		/* desired Fout for PLL */
+	u8 M;
+	u8 N_int;
+	u8 N_fac;
+	u8 tfgoal;
+	u8 lock_time;
+};
+
+struct power_state {
+	union clk_pin_cntl_u clk_pin_cntl;
+	union pll_ref_fb_div_u pll_ref_fb_div;
+	union pll_cntl_u pll_cntl;
+	union sclk_cntl_u sclk_cntl;
+	union pclk_cntl_u pclk_cntl;
+	union clk_test_cntl_u clk_test_cntl;
+	union pwrmgt_cntl_u pwrmgt_cntl;
+	u32 freq;		/* Fout for PLL calibration */
+	u8 tf100;		/* for pll calibration */
+	u8 tf80;		/* for pll calibration */
+	u8 tf20;		/* for pll calibration */
+	u8 M;			/* for pll calibration */
+	u8 N_int;		/* for pll calibration */
+	u8 N_fac;		/* for pll calibration */
+	u8 lock_time;	/* for pll calibration */
+	u8 tfgoal;		/* for pll calibration */
+	u8 auto_mode;	/* hardware auto switch? */
+	u8 pwm_mode;		/* 0 fast, 1 normal/slow */
+	u16 fast_sclk;	/* fast clk freq */
+	u16 norm_sclk;	/* slow clk freq */
+};
+
+
+/*
+ * Global state variables
+ */
+
+static struct power_state w100_pwr_state;
+
+/* This table is specific for 12.5MHz ref crystal.  */
+static struct pll_parm gPLLTable[] = {
+    /*freq     M   N_int    N_fac  tfgoal  lock_time */
+    { 50,      0,   1,       0,     0xE0,        56}, /*  50.00 MHz */
+    { 75,      0,   5,       0,     0xDE,	     37}, /*  75.00 MHz */
+    {100,      0,   7,       0,     0xE0,        28}, /* 100.00 MHz */
+    {125,      0,   9,       0,     0xE0,        22}, /* 125.00 MHz */
+    {150,      0,   11,      0,     0xE0,        17}, /* 150.00 MHz */
+    {  0,      0,   0,       0,        0,         0}  /* Terminator */
+};
+
+
+static u8 w100_pll_get_testcount(u8 testclk_sel)
+{
+	udelay(5);
+
+	w100_pwr_state.clk_test_cntl.f.start_check_freq = 0x0;
+	w100_pwr_state.clk_test_cntl.f.testclk_sel = testclk_sel;
+	w100_pwr_state.clk_test_cntl.f.tstcount_rst = 0x1;	/*reset test count */
+	writel((u32) (w100_pwr_state.clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
+	w100_pwr_state.clk_test_cntl.f.tstcount_rst = 0x0;
+	writel((u32) (w100_pwr_state.clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
+
+	w100_pwr_state.clk_test_cntl.f.start_check_freq = 0x1;
+	writel((u32) (w100_pwr_state.clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
+
+	udelay(20);
+
+	w100_pwr_state.clk_test_cntl.val = readl(remapped_regs + mmCLK_TEST_CNTL);
+	w100_pwr_state.clk_test_cntl.f.start_check_freq = 0x0;
+	writel((u32) (w100_pwr_state.clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
+
+	return w100_pwr_state.clk_test_cntl.f.test_count;
+}
+
+
+static u8 w100_pll_adjust(void)
+{
+	do {
+		/* Wai Ming 80 percent of VDD 1.3V gives 1.04V, minimum operating voltage is 1.08V
+		 * therefore, commented out the following lines
+		 * tf80 meant tf100
+		 * set VCO input = 0.8 * VDD
+		 */
+		w100_pwr_state.pll_cntl.f.pll_dactal = 0xd;
+		writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
+
+		w100_pwr_state.tf80 = w100_pll_get_testcount(0x1);	/* PLLCLK */
+		if (w100_pwr_state.tf80 >= (w100_pwr_state.tfgoal)) {
+			/* set VCO input = 0.2 * VDD */
+			w100_pwr_state.pll_cntl.f.pll_dactal = 0x7;
+			writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
+
+			w100_pwr_state.tf20 = w100_pll_get_testcount(0x1);	/* PLLCLK */
+			if (w100_pwr_state.tf20 <= (w100_pwr_state.tfgoal))
+				return 1; // Success
+
+			if ((w100_pwr_state.pll_cntl.f.pll_vcofr == 0x0) &&
+			    ((w100_pwr_state.pll_cntl.f.pll_pvg == 0x7) ||
+			     (w100_pwr_state.pll_cntl.f.pll_ioffset == 0x0))) {
+				/* slow VCO config */
+				w100_pwr_state.pll_cntl.f.pll_vcofr = 0x1;
+				w100_pwr_state.pll_cntl.f.pll_pvg = 0x0;
+				w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
+				writel((u32) (w100_pwr_state.pll_cntl.val),
+					remapped_regs + mmPLL_CNTL);
+				continue;
+			}
+		}
+		if ((w100_pwr_state.pll_cntl.f.pll_ioffset) < 0x3) {
+			w100_pwr_state.pll_cntl.f.pll_ioffset += 0x1;
+			writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
+			continue;
+		}
+		if ((w100_pwr_state.pll_cntl.f.pll_pvg) < 0x7) {
+			w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
+			w100_pwr_state.pll_cntl.f.pll_pvg += 0x1;
+			writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
+			continue;
+		}
+		return 0; // error
+	} while(1);
+}
+
+
+/*
+ * w100_pll_calibration
+ *                freq = target frequency of the PLL
+ *                (note: crystal = 14.3MHz)
+ */
+static u8 w100_pll_calibration(u32 freq)
+{
+	u8 status;
+
+	/* initial setting */
+	w100_pwr_state.pll_cntl.f.pll_pwdn = 0x0;		/* power down */
+	w100_pwr_state.pll_cntl.f.pll_reset = 0x0;		/* not reset */
+	w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x1;	/* Hi-Z */
+	w100_pwr_state.pll_cntl.f.pll_pvg = 0x0;		/* VCO gain = 0 */
+	w100_pwr_state.pll_cntl.f.pll_vcofr = 0x0;		/* VCO frequency range control = off */
+	w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;	/* current offset inside VCO = 0 */
+	w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0;
+	writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
+
+	/* check for (tf80 >= tfgoal) && (tf20 =< tfgoal) */
+	if ((w100_pwr_state.tf80 < w100_pwr_state.tfgoal) || (w100_pwr_state.tf20 > w100_pwr_state.tfgoal)) {
+		status=w100_pll_adjust();
+	}
+	/* PLL Reset And Lock */
+
+	/* set VCO input = 0.5 * VDD */
+	w100_pwr_state.pll_cntl.f.pll_dactal = 0xa;
+	writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
+
+	/* reset time */
+	udelay(1);
+
+	/* enable charge pump */
+	w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0;	/* normal */
+	writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
+
+	/* set VCO input = Hi-Z */
+	/* disable DAC */
+	w100_pwr_state.pll_cntl.f.pll_dactal = 0x0;
+	writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
+
+	/* lock time */
+	udelay(400);	/* delay 400 us */
+
+	/* PLL locked */
+
+	w100_pwr_state.sclk_cntl.f.sclk_src_sel = 0x1;	/* PLL clock */
+	writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
+
+	w100_pwr_state.tf100 = w100_pll_get_testcount(0x1);	/* PLLCLK */
+
+	return status;
+}
+
+
+static u8 w100_pll_set_clk(void)
+{
+	u8 status;
+
+	if (w100_pwr_state.auto_mode == 1)	/* auto mode */
+	{
+		w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0;	/* disable fast to normal */
+		w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0;	/* disable normal to fast */
+		writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
+	}
+
+	w100_pwr_state.sclk_cntl.f.sclk_src_sel = 0x0;	/* crystal clock */
+	writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
+
+	w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = w100_pwr_state.M;
+	w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = w100_pwr_state.N_int;
+	w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = w100_pwr_state.N_fac;
+	w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = w100_pwr_state.lock_time;
+	writel((u32) (w100_pwr_state.pll_ref_fb_div.val), remapped_regs + mmPLL_REF_FB_DIV);
+
+	w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0;
+	writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
+
+	status = w100_pll_calibration (w100_pwr_state.freq);
+
+	if (w100_pwr_state.auto_mode == 1)	/* auto mode */
+	{
+		w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x1;	/* reenable fast to normal */
+		w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x1;	/* reenable normal to fast  */
+		writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
+	}
+	return status;
+}
+
+
+/* assume reference crystal clk is 12.5MHz,
+ * and that doubling is not enabled.
+ *
+ * Freq = 12 == 12.5MHz.
+ */
+static u16 w100_set_slowsysclk(u16 freq)
+{
+	if (w100_pwr_state.norm_sclk == freq)
+		return freq;
+
+	if (w100_pwr_state.auto_mode == 1)	/* auto mode */
+		return 0;
+
+	if (freq == 12) {
+		w100_pwr_state.norm_sclk = freq;
+		w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = 0x0;	/* Pslow = 1 */
+		w100_pwr_state.sclk_cntl.f.sclk_src_sel = 0x0;	/* crystal src */
+
+		writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
+
+		w100_pwr_state.clk_pin_cntl.f.xtalin_pm_en = 0x1;
+		writel((u32) (w100_pwr_state.clk_pin_cntl.val), remapped_regs + mmCLK_PIN_CNTL);
+
+		w100_pwr_state.pwrmgt_cntl.f.pwm_enable = 0x1;
+		w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0x1;
+		writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
+		w100_pwr_state.pwm_mode = 1;	/* normal mode */
+		return freq;
+	} else
+		return 0;
+}
+
+
+static u16 w100_set_fastsysclk(u16 freq)
+{
+	u16 pll_freq;
+	int i;
+
+	while(1) {
+		pll_freq = (u16) (freq * (w100_pwr_state.sclk_cntl.f.sclk_post_div_fast + 1));
+		i = 0;
+		do {
+			if (pll_freq == gPLLTable[i].freq) {
+				w100_pwr_state.freq = gPLLTable[i].freq * 1000000;
+				w100_pwr_state.M = gPLLTable[i].M;
+				w100_pwr_state.N_int = gPLLTable[i].N_int;
+				w100_pwr_state.N_fac = gPLLTable[i].N_fac;
+				w100_pwr_state.tfgoal = gPLLTable[i].tfgoal;
+				w100_pwr_state.lock_time = gPLLTable[i].lock_time;
+				w100_pwr_state.tf20 = 0xff;	/* set highest */
+				w100_pwr_state.tf80 = 0x00;	/* set lowest */
+
+				w100_pll_set_clk();
+				w100_pwr_state.pwm_mode = 0;	/* fast mode */
+				w100_pwr_state.fast_sclk = freq;
+				return freq;
+			}
+			i++;
+		} while(gPLLTable[i].freq);
+
+		if (w100_pwr_state.auto_mode == 1)
+			break;
+
+		if (w100_pwr_state.sclk_cntl.f.sclk_post_div_fast == 0)
+			break;
+
+		w100_pwr_state.sclk_cntl.f.sclk_post_div_fast -= 1;
+		writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
+	}
+	return 0;
+}
+
+
+/* Set up an initial state.  Some values/fields set
+   here will be overwritten. */
+static void w100_pwm_setup(void)
+{
+	w100_pwr_state.clk_pin_cntl.f.osc_en = 0x1;
+	w100_pwr_state.clk_pin_cntl.f.osc_gain = 0x1f;
+	w100_pwr_state.clk_pin_cntl.f.dont_use_xtalin = 0x0;
+	w100_pwr_state.clk_pin_cntl.f.xtalin_pm_en = 0x0;
+	w100_pwr_state.clk_pin_cntl.f.xtalin_dbl_en = 0x0;	/* no freq doubling */
+	w100_pwr_state.clk_pin_cntl.f.cg_debug = 0x0;
+	writel((u32) (w100_pwr_state.clk_pin_cntl.val), remapped_regs + mmCLK_PIN_CNTL);
+
+	w100_pwr_state.sclk_cntl.f.sclk_src_sel = 0x0;	/* Crystal Clk */
+	w100_pwr_state.sclk_cntl.f.sclk_post_div_fast = 0x0;	/* Pfast = 1 */
+	w100_pwr_state.sclk_cntl.f.sclk_clkon_hys = 0x3;
+	w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = 0x0;	/* Pslow = 1 */
+	w100_pwr_state.sclk_cntl.f.disp_cg_ok2switch_en = 0x0;
+	w100_pwr_state.sclk_cntl.f.sclk_force_reg = 0x0;	/* Dynamic */
+	w100_pwr_state.sclk_cntl.f.sclk_force_disp = 0x0;	/* Dynamic */
+	w100_pwr_state.sclk_cntl.f.sclk_force_mc = 0x0;	/* Dynamic */
+	w100_pwr_state.sclk_cntl.f.sclk_force_extmc = 0x0;	/* Dynamic */
+	w100_pwr_state.sclk_cntl.f.sclk_force_cp = 0x0;	/* Dynamic */
+	w100_pwr_state.sclk_cntl.f.sclk_force_e2 = 0x0;	/* Dynamic */
+	w100_pwr_state.sclk_cntl.f.sclk_force_e3 = 0x0;	/* Dynamic */
+	w100_pwr_state.sclk_cntl.f.sclk_force_idct = 0x0;	/* Dynamic */
+	w100_pwr_state.sclk_cntl.f.sclk_force_bist = 0x0;	/* Dynamic */
+	w100_pwr_state.sclk_cntl.f.busy_extend_cp = 0x0;
+	w100_pwr_state.sclk_cntl.f.busy_extend_e2 = 0x0;
+	w100_pwr_state.sclk_cntl.f.busy_extend_e3 = 0x0;
+	w100_pwr_state.sclk_cntl.f.busy_extend_idct = 0x0;
+	writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
+
+	w100_pwr_state.pclk_cntl.f.pclk_src_sel = 0x0;	/* Crystal Clk */
+	w100_pwr_state.pclk_cntl.f.pclk_post_div = 0x1;	/* P = 2 */
+	w100_pwr_state.pclk_cntl.f.pclk_force_disp = 0x0;	/* Dynamic */
+	writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
+
+	w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = 0x0;	/* M = 1 */
+	w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = 0x0;	/* N = 1.0 */
+	w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = 0x0;
+	w100_pwr_state.pll_ref_fb_div.f.pll_reset_time = 0x5;
+	w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = 0xff;
+	writel((u32) (w100_pwr_state.pll_ref_fb_div.val), remapped_regs + mmPLL_REF_FB_DIV);
+
+	w100_pwr_state.pll_cntl.f.pll_pwdn = 0x1;
+	w100_pwr_state.pll_cntl.f.pll_reset = 0x1;
+	w100_pwr_state.pll_cntl.f.pll_pm_en = 0x0;
+	w100_pwr_state.pll_cntl.f.pll_mode = 0x0;	/* uses VCO clock */
+	w100_pwr_state.pll_cntl.f.pll_refclk_sel = 0x0;
+	w100_pwr_state.pll_cntl.f.pll_fbclk_sel = 0x0;
+	w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0;
+	w100_pwr_state.pll_cntl.f.pll_pcp = 0x4;
+	w100_pwr_state.pll_cntl.f.pll_pvg = 0x0;
+	w100_pwr_state.pll_cntl.f.pll_vcofr = 0x0;
+	w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
+	w100_pwr_state.pll_cntl.f.pll_pecc_mode = 0x0;
+	w100_pwr_state.pll_cntl.f.pll_pecc_scon = 0x0;
+	w100_pwr_state.pll_cntl.f.pll_dactal = 0x0;	/* Hi-Z */
+	w100_pwr_state.pll_cntl.f.pll_cp_clip = 0x3;
+	w100_pwr_state.pll_cntl.f.pll_conf = 0x2;
+	w100_pwr_state.pll_cntl.f.pll_mbctrl = 0x2;
+	w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0;
+	writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
+
+	w100_pwr_state.clk_test_cntl.f.testclk_sel = 0x1;	/* PLLCLK (for testing) */
+	w100_pwr_state.clk_test_cntl.f.start_check_freq = 0x0;
+	w100_pwr_state.clk_test_cntl.f.tstcount_rst = 0x0;
+	writel((u32) (w100_pwr_state.clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
+
+	w100_pwr_state.pwrmgt_cntl.f.pwm_enable = 0x0;
+	w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0x1;	/* normal mode (0, 1, 3) */
+	w100_pwr_state.pwrmgt_cntl.f.pwm_wakeup_cond = 0x0;
+	w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0;
+	w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0;
+	w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_cond = 0x1;	/* PM4,ENG */
+	w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_cond = 0x1;	/* PM4,ENG */
+	w100_pwr_state.pwrmgt_cntl.f.pwm_idle_timer = 0xFF;
+	w100_pwr_state.pwrmgt_cntl.f.pwm_busy_timer = 0xFF;
+	writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
+
+	w100_pwr_state.auto_mode = 0;	/* manual mode */
+	w100_pwr_state.pwm_mode = 1;	/* normal mode (0, 1, 2) */
+	w100_pwr_state.freq = 50000000;	/* 50 MHz */
+	w100_pwr_state.M = 3;	/* M = 4 */
+	w100_pwr_state.N_int = 6;	/* N = 7.0 */
+	w100_pwr_state.N_fac = 0;
+	w100_pwr_state.tfgoal = 0xE0;
+	w100_pwr_state.lock_time = 56;
+	w100_pwr_state.tf20 = 0xff;	/* set highest */
+	w100_pwr_state.tf80 = 0x00;	/* set lowest */
+	w100_pwr_state.tf100 = 0x00;	/* set lowest */
+	w100_pwr_state.fast_sclk = 50;	/* 50.0 MHz */
+	w100_pwr_state.norm_sclk = 12;	/* 12.5 MHz */
+}
+
+
+static void w100_init_sharp_lcd(u32 mode)
+{
+	u32 temp32;
+	union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl;
+
+	/* Prevent display updates */
+	disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
+	disp_db_buf_wr_cntl.f.update_db_buf = 0;
+	disp_db_buf_wr_cntl.f.en_db_buf = 0;
+	writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
+
+	switch(mode) {
+	case LCD_SHARP_QVGA:
+		w100_set_slowsysclk(12);	/* use crystal -- 12.5MHz */
+		/* not use PLL */
+
+		writel(0x7FFF8000, remapped_regs + mmMC_EXT_MEM_LOCATION);
+		writel(0x85FF8000, remapped_regs + mmMC_FB_LOCATION);
+		writel(0x00000003, remapped_regs + mmLCD_FORMAT);
+		writel(0x00CF1C06, remapped_regs + mmGRAPHIC_CTRL);
+		writel(0x01410145, remapped_regs + mmCRTC_TOTAL);
+		writel(0x01170027, remapped_regs + mmACTIVE_H_DISP);
+		writel(0x01410001, remapped_regs + mmACTIVE_V_DISP);
+		writel(0x01170027, remapped_regs + mmGRAPHIC_H_DISP);
+		writel(0x01410001, remapped_regs + mmGRAPHIC_V_DISP);
+		writel(0x81170027, remapped_regs + mmCRTC_SS);
+		writel(0xA0140000, remapped_regs + mmCRTC_LS);
+		writel(0x00400008, remapped_regs + mmCRTC_REV);
+		writel(0xA0000000, remapped_regs + mmCRTC_DCLK);
+		writel(0xC0140014, remapped_regs + mmCRTC_GS);
+		writel(0x00010141, remapped_regs + mmCRTC_VPOS_GS);
+		writel(0x8015010F, remapped_regs + mmCRTC_GCLK);
+		writel(0x80100110, remapped_regs + mmCRTC_GOE);
+		writel(0x00000000, remapped_regs + mmCRTC_FRAME);
+		writel(0x00000000, remapped_regs + mmCRTC_FRAME_VPOS);
+		writel(0x01CC0000, remapped_regs + mmLCDD_CNTL1);
+		writel(0x0003FFFF, remapped_regs + mmLCDD_CNTL2);
+		writel(0x00FFFF0D, remapped_regs + mmGENLCD_CNTL1);
+		writel(0x003F3003, remapped_regs + mmGENLCD_CNTL2);
+		writel(0x00000000, remapped_regs + mmCRTC_DEFAULT_COUNT);
+		writel(0x0000FF00, remapped_regs + mmLCD_BACKGROUND_COLOR);
+		writel(0x000102aa, remapped_regs + mmGENLCD_CNTL3);
+		writel(0x00800000, remapped_regs + mmGRAPHIC_OFFSET);
+		writel(0x000001e0, remapped_regs + mmGRAPHIC_PITCH);
+		writel(0x000000bf, remapped_regs + mmGPIO_DATA);
+		writel(0x03c0feff, remapped_regs + mmGPIO_CNTL2);
+		writel(0x00000000, remapped_regs + mmGPIO_CNTL1);
+		writel(0x41060010, remapped_regs + mmCRTC_PS1_ACTIVE);
+		break;
+	case LCD_SHARP_VGA:
+		w100_set_slowsysclk(12);	/* use crystal -- 12.5MHz */
+		w100_set_fastsysclk(current_par->fastsysclk_mode);	/* use PLL -- 75.0MHz */
+		w100_pwr_state.pclk_cntl.f.pclk_src_sel = 0x1;
+		w100_pwr_state.pclk_cntl.f.pclk_post_div = 0x2;
+		writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
+		writel(0x15FF1000, remapped_regs + mmMC_FB_LOCATION);
+		writel(0x9FFF8000, remapped_regs + mmMC_EXT_MEM_LOCATION);
+		writel(0x00000003, remapped_regs + mmLCD_FORMAT);
+		writel(0x00DE1D66, remapped_regs + mmGRAPHIC_CTRL);
+
+		writel(0x0283028B, remapped_regs + mmCRTC_TOTAL);
+		writel(0x02360056, remapped_regs + mmACTIVE_H_DISP);
+		writel(0x02830003, remapped_regs + mmACTIVE_V_DISP);
+		writel(0x02360056, remapped_regs + mmGRAPHIC_H_DISP);
+		writel(0x02830003, remapped_regs + mmGRAPHIC_V_DISP);
+		writel(0x82360056, remapped_regs + mmCRTC_SS);
+		writel(0xA0280000, remapped_regs + mmCRTC_LS);
+		writel(0x00400008, remapped_regs + mmCRTC_REV);
+		writel(0xA0000000, remapped_regs + mmCRTC_DCLK);
+		writel(0x80280028, remapped_regs + mmCRTC_GS);
+		writel(0x02830002, remapped_regs + mmCRTC_VPOS_GS);
+		writel(0x8015010F, remapped_regs + mmCRTC_GCLK);
+		writel(0x80100110, remapped_regs + mmCRTC_GOE);
+		writel(0x00000000, remapped_regs + mmCRTC_FRAME);
+		writel(0x00000000, remapped_regs + mmCRTC_FRAME_VPOS);
+		writel(0x01CC0000, remapped_regs + mmLCDD_CNTL1);
+		writel(0x0003FFFF, remapped_regs + mmLCDD_CNTL2);
+		writel(0x00FFFF0D, remapped_regs + mmGENLCD_CNTL1);
+		writel(0x003F3003, remapped_regs + mmGENLCD_CNTL2);
+		writel(0x00000000, remapped_regs + mmCRTC_DEFAULT_COUNT);
+		writel(0x0000FF00, remapped_regs + mmLCD_BACKGROUND_COLOR);
+		writel(0x000102aa, remapped_regs + mmGENLCD_CNTL3);
+		writel(0x00800000, remapped_regs + mmGRAPHIC_OFFSET);
+		writel(0x000003C0, remapped_regs + mmGRAPHIC_PITCH);
+		writel(0x000000bf, remapped_regs + mmGPIO_DATA);
+		writel(0x03c0feff, remapped_regs + mmGPIO_CNTL2);
+		writel(0x00000000, remapped_regs + mmGPIO_CNTL1);
+		writel(0x41060010, remapped_regs + mmCRTC_PS1_ACTIVE);
+		break;
+	default:
+		break;
+	}
+
+	/* Hack for overlay in ext memory */
+	temp32 = readl(remapped_regs + mmDISP_DEBUG2);
+	temp32 |= 0xc0000000;
+	writel(temp32, remapped_regs + mmDISP_DEBUG2);
+
+	/* Re-enable display updates */
+	disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
+	disp_db_buf_wr_cntl.f.update_db_buf = 1;
+	disp_db_buf_wr_cntl.f.en_db_buf = 1;
+	writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
+}
+
+
+static void w100_set_vga_rotation_regs(u16 divider, unsigned long ctrl, unsigned long offset, unsigned long pitch)
+{
+	w100_pwr_state.pclk_cntl.f.pclk_src_sel = 0x1;
+	w100_pwr_state.pclk_cntl.f.pclk_post_div = divider;
+	writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
+
+	writel(ctrl, remapped_regs + mmGRAPHIC_CTRL);
+	writel(offset, remapped_regs + mmGRAPHIC_OFFSET);
+	writel(pitch, remapped_regs + mmGRAPHIC_PITCH);
+
+	/* Re-enable display updates */
+	writel(0x0000007b, remapped_regs + mmDISP_DB_BUF_CNTL);
+}
+
+
+static void w100_init_vga_rotation(u16 deg)
+{
+	switch(deg) {
+	case 0:
+		w100_set_vga_rotation_regs(0x02, 0x00DE1D66, 0x00800000, 0x000003c0);
+		break;
+	case 90:
+		w100_set_vga_rotation_regs(0x06, 0x00DE1D0e, 0x00895b00, 0x00000500);
+		break;
+	case 180:
+		w100_set_vga_rotation_regs(0x02, 0x00DE1D7e, 0x00895ffc, 0x000003c0);
+		break;
+	case 270:
+		w100_set_vga_rotation_regs(0x06, 0x00DE1D16, 0x008004fc, 0x00000500);
+		break;
+	default:
+		/* not-support */
+		break;
+	}
+}
+
+
+static void w100_set_qvga_rotation_regs(unsigned long ctrl, unsigned long offset, unsigned long pitch)
+{
+	writel(ctrl, remapped_regs + mmGRAPHIC_CTRL);
+	writel(offset, remapped_regs + mmGRAPHIC_OFFSET);
+	writel(pitch, remapped_regs + mmGRAPHIC_PITCH);
+
+	/* Re-enable display updates */
+	writel(0x0000007b, remapped_regs + mmDISP_DB_BUF_CNTL);
+}
+
+
+static void w100_init_qvga_rotation(u16 deg)
+{
+	switch(deg) {
+	case 0:
+		w100_set_qvga_rotation_regs(0x00d41c06, 0x00800000, 0x000001e0);
+		break;
+	case 90:
+		w100_set_qvga_rotation_regs(0x00d41c0E, 0x00825580, 0x00000280);
+		break;
+	case 180:
+		w100_set_qvga_rotation_regs(0x00d41c1e, 0x008257fc, 0x000001e0);
+		break;
+	case 270:
+		w100_set_qvga_rotation_regs(0x00d41c16, 0x0080027c, 0x00000280);
+		break;
+	default:
+		/* not-support */
+		break;
+	}
+}
+
+
+static void w100_suspend(u32 mode)
+{
+	u32 val;
+
+	writel(0x7FFF8000, remapped_regs + mmMC_EXT_MEM_LOCATION);
+	writel(0x00FF0000, remapped_regs + mmMC_PERF_MON_CNTL);
+
+	val = readl(remapped_regs + mmMEM_EXT_TIMING_CNTL);
+	val &= ~(0x00100000);	/* bit20=0 */
+	val |= 0xFF000000;	/* bit31:24=0xff */
+	writel(val, remapped_regs + mmMEM_EXT_TIMING_CNTL);
+
+	val = readl(remapped_regs + mmMEM_EXT_CNTL);
+	val &= ~(0x00040000);	/* bit18=0 */
+	val |= 0x00080000;	/* bit19=1 */
+	writel(val, remapped_regs + mmMEM_EXT_CNTL);
+
+	udelay(1);		/* wait 1us */
+
+	if (mode == W100_SUSPEND_EXTMEM) {
+
+		/* CKE: Tri-State */
+		val = readl(remapped_regs + mmMEM_EXT_CNTL);
+		val |= 0x40000000;	/* bit30=1 */
+		writel(val, remapped_regs + mmMEM_EXT_CNTL);
+
+		/* CLK: Stop */
+		val = readl(remapped_regs + mmMEM_EXT_CNTL);
+		val &= ~(0x00000001);	/* bit0=0 */
+		writel(val, remapped_regs + mmMEM_EXT_CNTL);
+	} else {
+
+		writel(0x00000000, remapped_regs + mmSCLK_CNTL);
+		writel(0x000000BF, remapped_regs + mmCLK_PIN_CNTL);
+		writel(0x00000015, remapped_regs + mmPWRMGT_CNTL);
+
+		udelay(5);
+
+		val = readl(remapped_regs + mmPLL_CNTL);
+		val |= 0x00000004;	/* bit2=1 */
+		writel(val, remapped_regs + mmPLL_CNTL);
+		writel(0x0000001d, remapped_regs + mmPWRMGT_CNTL);
+	}
+}
+
+
+static void w100_resume(void)
+{
+	u32 temp32;
+
+	w100_hw_init();
+	w100_pwm_setup();
+
+	temp32 = readl(remapped_regs + mmDISP_DEBUG2);
+	temp32 &= 0xff7fffff;
+	temp32 |= 0x00800000;
+	writel(temp32, remapped_regs + mmDISP_DEBUG2);
+
+	if (current_par->lcdMode == LCD_MODE_480 || current_par->lcdMode == LCD_MODE_640) {
+		w100_init_sharp_lcd(LCD_SHARP_VGA);
+		if (current_par->lcdMode == LCD_MODE_640) {
+			w100_init_vga_rotation(current_par->rotation_flag ? 270 : 90);
+		}
+	} else {
+		w100_init_sharp_lcd(LCD_SHARP_QVGA);
+		if (current_par->lcdMode == LCD_MODE_320) {
+			w100_init_qvga_rotation(current_par->rotation_flag ? 270 : 90);
+		}
+	}
+}
+
+
+static void w100_vsync(void)
+{
+	u32 tmp;
+	int timeout = 30000; /* VSync timeout = 30[ms] > 16.8[ms] */
+
+	tmp = readl(remapped_regs + mmACTIVE_V_DISP);
+
+	/* set vline pos  */
+	writel((tmp >> 16) & 0x3ff, remapped_regs + mmDISP_INT_CNTL);
+
+	/* disable vline irq */
+	tmp = readl(remapped_regs + mmGEN_INT_CNTL);
+
+	tmp &= ~0x00000002;
+	writel(tmp, remapped_regs + mmGEN_INT_CNTL);
+
+	/* clear vline irq status */
+	writel(0x00000002, remapped_regs + mmGEN_INT_STATUS);
+
+	/* enable vline irq */
+	writel((tmp | 0x00000002), remapped_regs + mmGEN_INT_CNTL);
+
+	/* clear vline irq status */
+	writel(0x00000002, remapped_regs + mmGEN_INT_STATUS);
+
+	while(timeout > 0) {
+		if (readl(remapped_regs + mmGEN_INT_STATUS) & 0x00000002)
+			break;
+		udelay(1);
+		timeout--;
+	}
+
+	/* disable vline irq */
+	writel(tmp, remapped_regs + mmGEN_INT_CNTL);
+
+	/* clear vline irq status */
+	writel(0x00000002, remapped_regs + mmGEN_INT_STATUS);
+}
+
+
+static void w100_InitExtMem(u32 mode)
+{
+	switch(mode) {
+	case LCD_SHARP_QVGA:
+		/* QVGA doesn't use external memory
+		   nothing to do, really. */
+		break;
+	case LCD_SHARP_VGA:
+		writel(0x00007800, remapped_regs + mmMC_BIST_CTRL);
+		writel(0x00040003, remapped_regs + mmMEM_EXT_CNTL);
+		writel(0x00200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
+		udelay(100);
+		writel(0x80200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
+		udelay(100);
+		writel(0x00650021, remapped_regs + mmMEM_SDRAM_MODE_REG);
+		udelay(100);
+		writel(0x10002a4a, remapped_regs + mmMEM_EXT_TIMING_CNTL);
+		writel(0x7ff87012, remapped_regs + mmMEM_IO_CNTL);
+		break;
+	default:
+		break;
+	}
+}
+
+
+#define RESCTL_ADRS     0x00
+#define PHACTRL_ADRS	0x01
+#define DUTYCTRL_ADRS	0x02
+#define POWERREG0_ADRS	0x03
+#define POWERREG1_ADRS	0x04
+#define GPOR3_ADRS		0x05
+#define PICTRL_ADRS     0x06
+#define POLCTRL_ADRS    0x07
+
+#define RESCTL_QVGA     0x01
+#define RESCTL_VGA      0x00
+
+#define POWER1_VW_ON	0x01	/* VW Supply FET ON */
+#define POWER1_GVSS_ON	0x02	/* GVSS(-8V) Power Supply ON */
+#define POWER1_VDD_ON	0x04	/* VDD(8V),SVSS(-4V) Power Supply ON */
+
+#define POWER1_VW_OFF	0x00	/* VW Supply FET OFF */
+#define POWER1_GVSS_OFF	0x00	/* GVSS(-8V) Power Supply OFF */
+#define POWER1_VDD_OFF	0x00	/* VDD(8V),SVSS(-4V) Power Supply OFF */
+
+#define POWER0_COM_DCLK	0x01	/* COM Voltage DC Bias DAC Serial Data Clock */
+#define POWER0_COM_DOUT	0x02	/* COM Voltage DC Bias DAC Serial Data Out */
+#define POWER0_DAC_ON	0x04	/* DAC Power Supply ON */
+#define POWER0_COM_ON	0x08	/* COM Powewr Supply ON */
+#define POWER0_VCC5_ON	0x10	/* VCC5 Power Supply ON */
+
+#define POWER0_DAC_OFF	0x00	/* DAC Power Supply OFF */
+#define POWER0_COM_OFF	0x00	/* COM Powewr Supply OFF */
+#define POWER0_VCC5_OFF	0x00	/* VCC5 Power Supply OFF */
+
+#define PICTRL_INIT_STATE	0x01
+#define PICTRL_INIOFF		0x02
+#define PICTRL_POWER_DOWN	0x04
+#define PICTRL_COM_SIGNAL_OFF	0x08
+#define PICTRL_DAC_SIGNAL_OFF	0x10
+
+#define PICTRL_POWER_ACTIVE	(0)
+
+#define POLCTRL_SYNC_POL_FALL	0x01
+#define POLCTRL_EN_POL_FALL	0x02
+#define POLCTRL_DATA_POL_FALL	0x04
+#define POLCTRL_SYNC_ACT_H	0x08
+#define POLCTRL_EN_ACT_L	0x10
+
+#define POLCTRL_SYNC_POL_RISE	0x00
+#define POLCTRL_EN_POL_RISE	0x00
+#define POLCTRL_DATA_POL_RISE	0x00
+#define POLCTRL_SYNC_ACT_L	0x00
+#define POLCTRL_EN_ACT_H	0x00
+
+#define PHACTRL_PHASE_MANUAL	0x01
+
+#define PHAD_QVGA_DEFAULT_VAL (9)
+#define COMADJ_DEFAULT        (125)
+
+static void lcdtg_ssp_send(u8 adrs, u8 data)
+{
+	w100fb_ssp_send(adrs,data);
+}
+
+/*
+ * This is only a psuedo I2C interface. We can't use the standard kernel
+ * routines as the interface is write only. We just assume the data is acked...
+ */
+static void lcdtg_ssp_i2c_send(u8 data)
+{
+	lcdtg_ssp_send(POWERREG0_ADRS, data);
+	udelay(10);
+}
+
+static void lcdtg_i2c_send_bit(u8 data)
+{
+	lcdtg_ssp_i2c_send(data);
+	lcdtg_ssp_i2c_send(data | POWER0_COM_DCLK);
+	lcdtg_ssp_i2c_send(data);
+}
+
+static void lcdtg_i2c_send_start(u8 base)
+{
+	lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK | POWER0_COM_DOUT);
+	lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK);
+	lcdtg_ssp_i2c_send(base);
+}
+
+static void lcdtg_i2c_send_stop(u8 base)
+{
+	lcdtg_ssp_i2c_send(base);
+	lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK);
+	lcdtg_ssp_i2c_send(base | POWER0_COM_DCLK | POWER0_COM_DOUT);
+}
+
+static void lcdtg_i2c_send_byte(u8 base, u8 data)
+{
+	int i;
+	for (i = 0; i < 8; i++) {
+		if (data & 0x80)
+			lcdtg_i2c_send_bit(base | POWER0_COM_DOUT);
+		else
+			lcdtg_i2c_send_bit(base);
+		data <<= 1;
+	}
+}
+
+static void lcdtg_i2c_wait_ack(u8 base)
+{
+	lcdtg_i2c_send_bit(base);
+}
+
+static void lcdtg_set_common_voltage(u8 base_data, u8 data)
+{
+	/* Set Common Voltage to M62332FP via I2C */
+	lcdtg_i2c_send_start(base_data);
+	lcdtg_i2c_send_byte(base_data, 0x9c);
+	lcdtg_i2c_wait_ack(base_data);
+	lcdtg_i2c_send_byte(base_data, 0x00);
+	lcdtg_i2c_wait_ack(base_data);
+	lcdtg_i2c_send_byte(base_data, data);
+	lcdtg_i2c_wait_ack(base_data);
+	lcdtg_i2c_send_stop(base_data);
+}
+
+static struct lcdtg_register_setting {
+	u8 adrs;
+	u8 data;
+	u32 wait;
+} lcdtg_power_on_table[] = {
+
+    /* Initialize Internal Logic & Port */
+    { PICTRL_ADRS,
+      PICTRL_POWER_DOWN | PICTRL_INIOFF | PICTRL_INIT_STATE |
+      PICTRL_COM_SIGNAL_OFF | PICTRL_DAC_SIGNAL_OFF,
+      0 },
+
+    { POWERREG0_ADRS,
+      POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_OFF | POWER0_COM_OFF |
+      POWER0_VCC5_OFF,
+      0 },
+
+    { POWERREG1_ADRS,
+      POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF,
+      0 },
+
+    /* VDD(+8V),SVSS(-4V) ON */
+    { POWERREG1_ADRS,
+      POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON /* VDD ON */,
+      3000 },
+
+    /* DAC ON */
+    { POWERREG0_ADRS,
+      POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON /* DAC ON */ |
+      POWER0_COM_OFF | POWER0_VCC5_OFF,
+      0 },
+
+    /* INIB = H, INI = L  */
+    { PICTRL_ADRS,
+      /* PICTL[0] = H , PICTL[1] = PICTL[2] = PICTL[4] = L */
+      PICTRL_INIT_STATE | PICTRL_COM_SIGNAL_OFF,
+      0 },
+
+    /* Set Common Voltage */
+    { 0xfe, 0, 0 },
+
+    /* VCC5 ON */
+    { POWERREG0_ADRS,
+      POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON /* DAC ON */ |
+      POWER0_COM_OFF | POWER0_VCC5_ON /* VCC5 ON */,
+      0 },
+
+    /* GVSS(-8V) ON */
+    { POWERREG1_ADRS,
+      POWER1_VW_OFF | POWER1_GVSS_ON /* GVSS ON */ |
+      POWER1_VDD_ON /* VDD ON */,
+      2000 },
+
+    /* COM SIGNAL ON (PICTL[3] = L) */
+    { PICTRL_ADRS,
+      PICTRL_INIT_STATE,
+      0 },
+
+    /* COM ON */
+    { POWERREG0_ADRS,
+      POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON /* DAC ON */ |
+      POWER0_COM_ON /* COM ON */ | POWER0_VCC5_ON /* VCC5_ON */,
+      0 },
+
+    /* VW ON */
+    { POWERREG1_ADRS,
+      POWER1_VW_ON /* VW ON */ | POWER1_GVSS_ON /* GVSS ON */ |
+      POWER1_VDD_ON /* VDD ON */,
+      0 /* Wait 100ms */ },
+
+    /* Signals output enable */
+    { PICTRL_ADRS,
+      0 /* Signals output enable */,
+      0 },
+
+    { PHACTRL_ADRS,
+      PHACTRL_PHASE_MANUAL,
+      0 },
+
+    /* Initialize for Input Signals from ATI */
+    { POLCTRL_ADRS,
+      POLCTRL_SYNC_POL_RISE | POLCTRL_EN_POL_RISE | POLCTRL_DATA_POL_RISE |
+      POLCTRL_SYNC_ACT_L | POLCTRL_EN_ACT_H,
+      1000 /*100000*/ /* Wait 100ms */ },
+
+    /* end mark */
+    { 0xff, 0, 0 }
+};
+
+static void lcdtg_resume(void)
+{
+	if (current_par->lcdMode == LCD_MODE_480 || current_par->lcdMode == LCD_MODE_640) {
+		lcdtg_hw_init(LCD_SHARP_VGA);
+	} else {
+		lcdtg_hw_init(LCD_SHARP_QVGA);
+	}
+}
+
+static void lcdtg_suspend(void)
+{
+	int i;
+
+	for (i = 0; i < (current_par->xres * current_par->yres); i++) {
+		writew(0xffff, remapped_fbuf + (2*i));
+	}
+
+	/* 60Hz x 2 frame = 16.7msec x 2 = 33.4 msec */
+	mdelay(34);
+
+	/* (1)VW OFF */
+	lcdtg_ssp_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_ON | POWER1_VDD_ON);
+
+	/* (2)COM OFF */
+	lcdtg_ssp_send(PICTRL_ADRS, PICTRL_COM_SIGNAL_OFF);
+	lcdtg_ssp_send(POWERREG0_ADRS, POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_ON);
+
+	/* (3)Set Common Voltage Bias 0V */
+	lcdtg_set_common_voltage(POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_ON, 0);
+
+	/* (4)GVSS OFF */
+	lcdtg_ssp_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON);
+
+	/* (5)VCC5 OFF */
+	lcdtg_ssp_send(POWERREG0_ADRS, POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_OFF);
+
+	/* (6)Set PDWN, INIOFF, DACOFF */
+	lcdtg_ssp_send(PICTRL_ADRS, PICTRL_INIOFF | PICTRL_DAC_SIGNAL_OFF |
+			PICTRL_POWER_DOWN | PICTRL_COM_SIGNAL_OFF);
+
+	/* (7)DAC OFF */
+	lcdtg_ssp_send(POWERREG0_ADRS, POWER0_DAC_OFF | POWER0_COM_OFF | POWER0_VCC5_OFF);
+
+	/* (8)VDD OFF */
+	lcdtg_ssp_send(POWERREG1_ADRS, POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF);
+
+}
+
+static void lcdtg_set_phadadj(u32 mode)
+{
+	int adj;
+
+	if (mode == LCD_SHARP_VGA) {
+		/* Setting for VGA */
+		adj = current_par->phadadj;
+		if (adj < 0) {
+			adj = PHACTRL_PHASE_MANUAL;
+		} else {
+			adj = ((adj & 0x0f) << 1) | PHACTRL_PHASE_MANUAL;
+		}
+	} else {
+		/* Setting for QVGA */
+		adj = (PHAD_QVGA_DEFAULT_VAL << 1) | PHACTRL_PHASE_MANUAL;
+	}
+	lcdtg_ssp_send(PHACTRL_ADRS, adj);
+}
+
+static void lcdtg_hw_init(u32 mode)
+{
+	int i;
+	int comadj;
+
+	i = 0;
+	while(lcdtg_power_on_table[i].adrs != 0xff) {
+		if (lcdtg_power_on_table[i].adrs == 0xfe) {
+			/* Set Common Voltage */
+			comadj = current_par->comadj;
+			if (comadj < 0) {
+				comadj = COMADJ_DEFAULT;
+			}
+			lcdtg_set_common_voltage((POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_OFF), comadj);
+		} else if (lcdtg_power_on_table[i].adrs == PHACTRL_ADRS) {
+			/* Set Phase Adjuct */
+			lcdtg_set_phadadj(mode);
+		} else {
+			/* Other */
+			lcdtg_ssp_send(lcdtg_power_on_table[i].adrs, lcdtg_power_on_table[i].data);
+		}
+		if (lcdtg_power_on_table[i].wait != 0)
+			udelay(lcdtg_power_on_table[i].wait);
+		i++;
+	}
+
+	switch(mode) {
+	case LCD_SHARP_QVGA:
+		/* Set Lcd Resolution (QVGA) */
+		lcdtg_ssp_send(RESCTL_ADRS, RESCTL_QVGA);
+		break;
+	case LCD_SHARP_VGA:
+		/* Set Lcd Resolution (VGA) */
+		lcdtg_ssp_send(RESCTL_ADRS, RESCTL_VGA);
+		break;
+	default:
+		break;
+	}
+}
+
+static void lcdtg_lcd_change(u32 mode)
+{
+	/* Set Phase Adjuct */
+	lcdtg_set_phadadj(mode);
+
+	if (mode == LCD_SHARP_VGA)
+		/* Set Lcd Resolution (VGA) */
+		lcdtg_ssp_send(RESCTL_ADRS, RESCTL_VGA);
+	else if (mode == LCD_SHARP_QVGA)
+		/* Set Lcd Resolution (QVGA) */
+		lcdtg_ssp_send(RESCTL_ADRS, RESCTL_QVGA);
+}
+
+
+static struct device_driver w100fb_driver = {
+	.name		= "w100fb",
+	.bus		= &platform_bus_type,
+	.probe		= w100fb_probe,
+	.remove		= w100fb_remove,
+	.suspend	= w100fb_suspend,
+	.resume		= w100fb_resume,
+};
+
+int __devinit w100fb_init(void)
+{
+	return driver_register(&w100fb_driver);
+}
+
+void __exit w100fb_cleanup(void)
+{
+ 	driver_unregister(&w100fb_driver);
+}
+
+module_init(w100fb_init);
+module_exit(w100fb_cleanup);
+
+MODULE_DESCRIPTION("ATI Imageon w100 framebuffer driver");
+MODULE_LICENSE("GPLv2");
diff --git a/drivers/video/w100fb.h b/drivers/video/w100fb.h
new file mode 100644
index 0000000..41624f9
--- /dev/null
+++ b/drivers/video/w100fb.h
@@ -0,0 +1,615 @@
+/*
+ * linux/drivers/video/w100fb.h
+ *
+ * Frame Buffer Device for ATI w100 (Wallaby)
+ *
+ * Copyright (C) 2002, ATI Corp.
+ * Copyright (C) 2004-2005 Richard Purdie
+ *
+ * Modified to work with 2.6 by Richard Purdie <rpurdie@rpsys.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#if !defined (_W100FB_H)
+#define _W100FB_H
+
+/* Block CIF Start: */
+#define mmCHIP_ID           0x0000
+#define mmREVISION_ID		0x0004
+#define mmWRAP_BUF_A        0x0008
+#define mmWRAP_BUF_B        0x000C
+#define mmWRAP_TOP_DIR      0x0010
+#define mmWRAP_START_DIR    0x0014
+#define mmCIF_CNTL          0x0018
+#define mmCFGREG_BASE       0x001C
+#define mmCIF_IO            0x0020
+#define mmCIF_READ_DBG      0x0024
+#define mmCIF_WRITE_DBG     0x0028
+#define cfgIND_ADDR_A_0     0x0000
+#define cfgIND_ADDR_A_1     0x0001
+#define cfgIND_ADDR_A_2     0x0002
+#define cfgIND_DATA_A       0x0003
+#define cfgREG_BASE         0x0004
+#define cfgINTF_CNTL        0x0005
+#define cfgSTATUS           0x0006
+#define cfgCPU_DEFAULTS     0x0007
+#define cfgIND_ADDR_B_0     0x0008
+#define cfgIND_ADDR_B_1     0x0009
+#define cfgIND_ADDR_B_2     0x000A
+#define cfgIND_DATA_B       0x000B
+#define cfgPM4_RPTR         0x000C
+#define cfgSCRATCH          0x000D
+#define cfgPM4_WRPTR_0      0x000E
+#define cfgPM4_WRPTR_1      0x000F
+/* Block CIF End: */
+
+/* Block CP Start: */
+#define mmSCRATCH_UMSK      0x0280
+#define mmSCRATCH_ADDR      0x0284
+#define mmGEN_INT_CNTL      0x0200
+#define mmGEN_INT_STATUS    0x0204
+/* Block CP End: */
+
+/* Block DISPLAY Start: */
+#define mmLCD_FORMAT        0x0410
+#define mmGRAPHIC_CTRL      0x0414
+#define mmGRAPHIC_OFFSET    0x0418
+#define mmGRAPHIC_PITCH     0x041C
+#define mmCRTC_TOTAL        0x0420
+#define mmACTIVE_H_DISP     0x0424
+#define mmACTIVE_V_DISP     0x0428
+#define mmGRAPHIC_H_DISP    0x042C
+#define mmGRAPHIC_V_DISP    0x0430
+#define mmVIDEO_CTRL        0x0434
+#define mmGRAPHIC_KEY       0x0438
+#define mmBRIGHTNESS_CNTL   0x045C
+#define mmDISP_INT_CNTL     0x0488
+#define mmCRTC_SS           0x048C
+#define mmCRTC_LS           0x0490
+#define mmCRTC_REV          0x0494
+#define mmCRTC_DCLK         0x049C
+#define mmCRTC_GS           0x04A0
+#define mmCRTC_VPOS_GS      0x04A4
+#define mmCRTC_GCLK         0x04A8
+#define mmCRTC_GOE          0x04AC
+#define mmCRTC_FRAME        0x04B0
+#define mmCRTC_FRAME_VPOS   0x04B4
+#define mmGPIO_DATA         0x04B8
+#define mmGPIO_CNTL1        0x04BC
+#define mmGPIO_CNTL2        0x04C0
+#define mmLCDD_CNTL1        0x04C4
+#define mmLCDD_CNTL2        0x04C8
+#define mmGENLCD_CNTL1      0x04CC
+#define mmGENLCD_CNTL2      0x04D0
+#define mmDISP_DEBUG        0x04D4
+#define mmDISP_DB_BUF_CNTL  0x04D8
+#define mmDISP_CRC_SIG      0x04DC
+#define mmCRTC_DEFAULT_COUNT 	0x04E0
+#define mmLCD_BACKGROUND_COLOR  0x04E4
+#define mmCRTC_PS2          0x04E8
+#define mmCRTC_PS2_VPOS     0x04EC
+#define mmCRTC_PS1_ACTIVE   0x04F0
+#define mmCRTC_PS1_NACTIVE  0x04F4
+#define mmCRTC_GCLK_EXT     0x04F8
+#define mmCRTC_ALW          0x04FC
+#define mmCRTC_ALW_VPOS     0x0500
+#define mmCRTC_PSK          0x0504
+#define mmCRTC_PSK_HPOS     0x0508
+#define mmCRTC_CV4_START    0x050C
+#define mmCRTC_CV4_END      0x0510
+#define mmCRTC_CV4_HPOS     0x0514
+#define mmCRTC_ECK          0x051C
+#define mmREFRESH_CNTL      0x0520
+#define mmGENLCD_CNTL3      0x0524
+#define mmGPIO_DATA2        0x0528
+#define mmGPIO_CNTL3        0x052C
+#define mmGPIO_CNTL4        0x0530
+#define mmCHIP_STRAP        0x0534
+#define mmDISP_DEBUG2       0x0538
+#define mmDEBUG_BUS_CNTL    0x053C
+#define mmGAMMA_VALUE1      0x0540
+#define mmGAMMA_VALUE2      0x0544
+#define mmGAMMA_SLOPE       0x0548
+#define mmGEN_STATUS        0x054C
+#define mmHW_INT            0x0550
+/* Block DISPLAY End: */
+
+/* Block GFX Start: */
+#define mmBRUSH_OFFSET      0x108C
+#define mmBRUSH_Y_X         0x1074
+#define mmDEFAULT_PITCH_OFFSET		0x10A0
+#define mmDEFAULT_SC_BOTTOM_RIGHT	0x10A8
+#define mmDEFAULT2_SC_BOTTOM_RIGHT	0x10AC
+#define mmGLOBAL_ALPHA      0x1210
+#define mmFILTER_COEF       0x1214
+#define mmMVC_CNTL_START    0x11E0
+#define mmE2_ARITHMETIC_CNTL	0x1220
+#define mmENG_CNTL          0x13E8
+#define mmENG_PERF_CNT      0x13F0
+/* Block GFX End: */
+
+/* Block IDCT Start: */
+#define mmIDCT_RUNS         0x0C00
+#define mmIDCT_LEVELS       0x0C04
+#define mmIDCT_CONTROL      0x0C3C
+#define mmIDCT_AUTH_CONTROL 0x0C08
+#define mmIDCT_AUTH         0x0C0C
+/* Block IDCT End: */
+
+/* Block MC Start: */
+#define mmMEM_CNTL          0x0180
+#define mmMEM_ARB           0x0184
+#define mmMC_FB_LOCATION    0x0188
+#define mmMEM_EXT_CNTL      0x018C
+#define mmMC_EXT_MEM_LOCATION   0x0190
+#define mmMEM_EXT_TIMING_CNTL   0x0194
+#define mmMEM_SDRAM_MODE_REG	0x0198
+#define mmMEM_IO_CNTL       0x019C
+#define mmMC_DEBUG          0x01A0
+#define mmMC_BIST_CTRL      0x01A4
+#define mmMC_BIST_COLLAR_READ  	0x01A8
+#define mmTC_MISMATCH       0x01AC
+#define mmMC_PERF_MON_CNTL  0x01B0
+#define mmMC_PERF_COUNTERS  0x01B4
+/* Block MC End: */
+
+/* Block RBBM Start: */
+#define mmWAIT_UNTIL        0x1400
+#define mmISYNC_CNTL        0x1404
+#define mmRBBM_CNTL         0x0144
+#define mmNQWAIT_UNTIL      0x0150
+/* Block RBBM End: */
+
+/* Block CG Start: */
+#define mmCLK_PIN_CNTL      0x0080
+#define mmPLL_REF_FB_DIV    0x0084
+#define mmPLL_CNTL          0x0088
+#define mmSCLK_CNTL         0x008C
+#define mmPCLK_CNTL         0x0090
+#define mmCLK_TEST_CNTL     0x0094
+#define mmPWRMGT_CNTL       0x0098
+#define mmPWRMGT_STATUS     0x009C
+/* Block CG End: */
+
+/* default value definitions */
+#define defWRAP_TOP_DIR     0x00000000
+#define defWRAP_START_DIR	0x00000000
+#define defCFGREG_BASE      0x00000000
+#define defCIF_IO           0x000C0902
+#define defINTF_CNTL        0x00000011
+#define defCPU_DEFAULTS     0x00000006
+#define defHW_INT           0x00000000
+#define defMC_EXT_MEM_LOCATION            0x07ff0000
+#define defTC_MISMATCH      0x00000000
+
+#define W100_CFG_BASE          0x0
+#define W100_CFG_LEN           0x10
+#define W100_REG_BASE          0x10000
+#define W100_REG_LEN           0x2000
+#define MEM_INT_BASE_VALUE     0x100000
+#define MEM_INT_TOP_VALUE_W100 0x15ffff
+#define MEM_EXT_BASE_VALUE     0x800000
+#define MEM_EXT_TOP_VALUE      0x9fffff
+#define WRAP_BUF_BASE_VALUE    0x80000
+#define WRAP_BUF_TOP_VALUE     0xbffff
+
+
+/* data structure definitions */
+
+struct wrap_top_dir_t {
+     unsigned long top_addr         : 23;
+     unsigned long    				: 9;
+} __attribute__((packed));
+
+union wrap_top_dir_u {
+     unsigned long val : 32;
+     struct wrap_top_dir_t f;
+} __attribute__((packed));
+
+struct wrap_start_dir_t {
+     unsigned long start_addr       : 23;
+     unsigned long    				: 9;
+} __attribute__((packed));
+
+union wrap_start_dir_u {
+     unsigned long val : 32;
+     struct wrap_start_dir_t f;
+} __attribute__((packed));
+
+struct cif_cntl_t {
+     unsigned long swap_reg         		: 2;
+     unsigned long swap_fbuf_1      		: 2;
+     unsigned long swap_fbuf_2      		: 2;
+     unsigned long swap_fbuf_3      		: 2;
+     unsigned long pmi_int_disable  		: 1;
+     unsigned long pmi_schmen_disable       : 1;
+     unsigned long intb_oe          		: 1;
+     unsigned long en_wait_to_compensate_dq_prop_dly : 1;
+     unsigned long compensate_wait_rd_size  : 2;
+     unsigned long wait_asserted_timeout_val      : 2;
+     unsigned long wait_masked_val  		: 2;
+     unsigned long en_wait_timeout  		: 1;
+     unsigned long en_one_clk_setup_before_wait   : 1;
+     unsigned long interrupt_active_high    : 1;
+     unsigned long en_overwrite_straps      : 1;
+     unsigned long strap_wait_active_hi     : 1;
+     unsigned long lat_busy_count   		: 2;
+     unsigned long lat_rd_pm4_sclk_busy     : 1;
+     unsigned long dis_system_bits  		: 1;
+     unsigned long dis_mr           		: 1;
+     unsigned long cif_spare_1      		: 4;
+} __attribute__((packed));
+
+union cif_cntl_u {
+     unsigned long val : 32;
+     struct cif_cntl_t f;
+} __attribute__((packed));
+
+struct cfgreg_base_t {
+     unsigned long cfgreg_base      : 24;
+     unsigned long    				: 8;
+} __attribute__((packed));
+
+union cfgreg_base_u {
+     unsigned long val : 32;
+     struct cfgreg_base_t f;
+} __attribute__((packed));
+
+struct cif_io_t {
+     unsigned long dq_srp           : 1;
+     unsigned long dq_srn           : 1;
+     unsigned long dq_sp            : 4;
+     unsigned long dq_sn            : 4;
+     unsigned long waitb_srp        : 1;
+     unsigned long waitb_srn        : 1;
+     unsigned long waitb_sp         : 4;
+     unsigned long waitb_sn         : 4;
+     unsigned long intb_srp         : 1;
+     unsigned long intb_srn         : 1;
+     unsigned long intb_sp          : 4;
+     unsigned long intb_sn          : 4;
+     unsigned long    				: 2;
+} __attribute__((packed));
+
+union cif_io_u {
+     unsigned long val : 32;
+     struct cif_io_t f;
+} __attribute__((packed));
+
+struct cif_read_dbg_t {
+     unsigned long unpacker_pre_fetch_trig_gen  : 2;
+     unsigned long dly_second_rd_fetch_trig     : 1;
+     unsigned long rst_rd_burst_id  			: 1;
+     unsigned long dis_rd_burst_id  			: 1;
+     unsigned long en_block_rd_when_packer_is_not_emp : 1;
+     unsigned long dis_pre_fetch_cntl_sm        : 1;
+     unsigned long rbbm_chrncy_dis  			: 1;
+     unsigned long rbbm_rd_after_wr_lat         : 2;
+     unsigned long dis_be_during_rd 			: 1;
+     unsigned long one_clk_invalidate_pulse     : 1;
+     unsigned long dis_chnl_priority			: 1;
+     unsigned long rst_read_path_a_pls          : 1;
+     unsigned long rst_read_path_b_pls          : 1;
+     unsigned long dis_reg_rd_fetch_trig        : 1;
+     unsigned long dis_rd_fetch_trig_from_ind_addr : 1;
+     unsigned long dis_rd_same_byte_to_trig_fetch : 1;
+     unsigned long dis_dir_wrap     			: 1;
+     unsigned long dis_ring_buf_to_force_dec    : 1;
+     unsigned long dis_addr_comp_in_16bit       : 1;
+     unsigned long clr_w            			: 1;
+     unsigned long err_rd_tag_is_3  			: 1;
+     unsigned long err_load_when_ful_a          : 1;
+     unsigned long err_load_when_ful_b          : 1;
+     unsigned long    							: 7;
+} __attribute__((packed));
+
+union cif_read_dbg_u {
+     unsigned long val : 32;
+     struct cif_read_dbg_t f;
+} __attribute__((packed));
+
+struct cif_write_dbg_t {
+     unsigned long packer_timeout_count           : 2;
+     unsigned long en_upper_load_cond             : 1;
+     unsigned long en_chnl_change_cond            : 1;
+     unsigned long dis_addr_comp_cond             : 1;
+     unsigned long dis_load_same_byte_addr_cond   : 1;
+     unsigned long dis_timeout_cond 			  : 1;
+     unsigned long dis_timeout_during_rbbm        : 1;
+     unsigned long dis_packer_ful_during_rbbm_timeout : 1;
+     unsigned long en_dword_split_to_rbbm         : 1;
+     unsigned long en_dummy_val     			  : 1;
+     unsigned long dummy_val_sel    			  : 1;
+     unsigned long mask_pm4_wrptr_dec             : 1;
+     unsigned long dis_mc_clean_cond			  : 1;
+     unsigned long err_two_reqi_during_ful        : 1;
+     unsigned long err_reqi_during_idle_clk       : 1;
+     unsigned long err_global       			  : 1;
+     unsigned long en_wr_buf_dbg_load             : 1;
+     unsigned long en_wr_buf_dbg_path             : 1;
+     unsigned long sel_wr_buf_byte  			  : 3;
+     unsigned long dis_rd_flush_wr  			  : 1;
+     unsigned long dis_packer_ful_cond            : 1;
+     unsigned long dis_invalidate_by_ops_chnl     : 1;
+     unsigned long en_halt_when_reqi_err          : 1;
+     unsigned long cif_spare_2      			  : 5;
+     unsigned long    							  : 1;
+} __attribute__((packed));
+
+union cif_write_dbg_u {
+     unsigned long val : 32;
+     struct cif_write_dbg_t f;
+} __attribute__((packed));
+
+
+struct intf_cntl_t {
+     unsigned char ad_inc_a            : 1;
+     unsigned char ring_buf_a          : 1;
+     unsigned char rd_fetch_trigger_a  : 1;
+     unsigned char rd_data_rdy_a       : 1;
+     unsigned char ad_inc_b            : 1;
+     unsigned char ring_buf_b          : 1;
+     unsigned char rd_fetch_trigger_b  : 1;
+     unsigned char rd_data_rdy_b       : 1;
+} __attribute__((packed));
+
+union intf_cntl_u {
+     unsigned char val : 8;
+     struct intf_cntl_t f;
+} __attribute__((packed));
+
+struct cpu_defaults_t {
+     unsigned char unpack_rd_data   : 1;
+     unsigned char access_ind_addr_a: 1;
+     unsigned char access_ind_addr_b: 1;
+     unsigned char access_scratch_reg             : 1;
+     unsigned char pack_wr_data     : 1;
+     unsigned char transition_size  : 1;
+     unsigned char en_read_buf_mode : 1;
+     unsigned char rd_fetch_scratch : 1;
+} __attribute__((packed));
+
+union cpu_defaults_u {
+     unsigned char val : 8;
+     struct cpu_defaults_t f;
+} __attribute__((packed));
+
+struct video_ctrl_t {
+     unsigned long video_mode       : 1;
+     unsigned long keyer_en         : 1;
+     unsigned long en_video_req     : 1;
+     unsigned long en_graphic_req_video           : 1;
+     unsigned long en_video_crtc    : 1;
+     unsigned long video_hor_exp    : 2;
+     unsigned long video_ver_exp    : 2;
+     unsigned long uv_combine       : 1;
+     unsigned long total_req_video  : 9;
+     unsigned long video_ch_sel     : 1;
+     unsigned long video_portrait   : 2;
+     unsigned long yuv2rgb_en       : 1;
+     unsigned long yuv2rgb_option   : 1;
+     unsigned long video_inv_hor    : 1;
+     unsigned long video_inv_ver    : 1;
+     unsigned long gamma_sel        : 2;
+     unsigned long dis_limit        : 1;
+     unsigned long en_uv_hblend     : 1;
+     unsigned long rgb_gamma_sel    : 2;
+} __attribute__((packed));
+
+union video_ctrl_u {
+     unsigned long val : 32;
+     struct video_ctrl_t f;
+} __attribute__((packed));
+
+struct disp_db_buf_cntl_rd_t {
+     unsigned long en_db_buf        	: 1;
+     unsigned long update_db_buf_done   : 1;
+     unsigned long db_buf_cntl      	: 6;
+     unsigned long    					: 24;
+} __attribute__((packed));
+
+union disp_db_buf_cntl_rd_u {
+     unsigned long val : 32;
+     struct disp_db_buf_cntl_rd_t f;
+} __attribute__((packed));
+
+struct disp_db_buf_cntl_wr_t {
+     unsigned long en_db_buf        : 1;
+     unsigned long update_db_buf    : 1;
+     unsigned long db_buf_cntl      : 6;
+     unsigned long    : 24;
+} __attribute__((packed));
+
+union disp_db_buf_cntl_wr_u {
+     unsigned long val : 32;
+     struct disp_db_buf_cntl_wr_t f;
+} __attribute__((packed));
+
+struct gamma_value1_t {
+     unsigned long gamma1           : 8;
+     unsigned long gamma2           : 8;
+     unsigned long gamma3           : 8;
+     unsigned long gamma4           : 8;
+} __attribute__((packed));
+
+union gamma_value1_u {
+     unsigned long val : 32;
+     struct gamma_value1_t f;
+} __attribute__((packed));
+
+struct gamma_value2_t {
+     unsigned long gamma5           : 8;
+     unsigned long gamma6           : 8;
+     unsigned long gamma7           : 8;
+     unsigned long gamma8           : 8;
+} __attribute__((packed));
+
+union gamma_value2_u {
+     unsigned long val : 32;
+     struct gamma_value2_t f;
+} __attribute__((packed));
+
+struct gamma_slope_t {
+     unsigned long slope1           : 3;
+     unsigned long slope2           : 3;
+     unsigned long slope3           : 3;
+     unsigned long slope4           : 3;
+     unsigned long slope5           : 3;
+     unsigned long slope6           : 3;
+     unsigned long slope7           : 3;
+     unsigned long slope8           : 3;
+     unsigned long    				: 8;
+} __attribute__((packed));
+
+union gamma_slope_u {
+     unsigned long val : 32;
+     struct gamma_slope_t f;
+} __attribute__((packed));
+
+struct mc_ext_mem_location_t {
+     unsigned long mc_ext_mem_start : 16;
+     unsigned long mc_ext_mem_top   : 16;
+} __attribute__((packed));
+
+union mc_ext_mem_location_u {
+     unsigned long val : 32;
+     struct mc_ext_mem_location_t f;
+} __attribute__((packed));
+
+struct clk_pin_cntl_t {
+     unsigned long osc_en           : 1;
+     unsigned long osc_gain         : 5;
+     unsigned long dont_use_xtalin  : 1;
+     unsigned long xtalin_pm_en     : 1;
+     unsigned long xtalin_dbl_en    : 1;
+     unsigned long    				: 7;
+     unsigned long cg_debug         : 16;
+} __attribute__((packed));
+
+union clk_pin_cntl_u {
+     unsigned long val : 32;
+     struct clk_pin_cntl_t f;
+} __attribute__((packed));
+
+struct pll_ref_fb_div_t {
+     unsigned long pll_ref_div      : 4;
+     unsigned long    				: 4;
+     unsigned long pll_fb_div_int   : 6;
+     unsigned long    				: 2;
+     unsigned long pll_fb_div_frac  : 3;
+     unsigned long    				: 1;
+     unsigned long pll_reset_time   : 4;
+     unsigned long pll_lock_time    : 8;
+} __attribute__((packed));
+
+union pll_ref_fb_div_u {
+     unsigned long val : 32;
+     struct pll_ref_fb_div_t f;
+} __attribute__((packed));
+
+struct pll_cntl_t {
+     unsigned long pll_pwdn         : 1;
+     unsigned long pll_reset        : 1;
+     unsigned long pll_pm_en        : 1;
+     unsigned long pll_mode         : 1;
+     unsigned long pll_refclk_sel   : 1;
+     unsigned long pll_fbclk_sel    : 1;
+     unsigned long pll_tcpoff       : 1;
+     unsigned long pll_pcp          : 3;
+     unsigned long pll_pvg          : 3;
+     unsigned long pll_vcofr        : 1;
+     unsigned long pll_ioffset      : 2;
+     unsigned long pll_pecc_mode    : 2;
+     unsigned long pll_pecc_scon    : 2;
+     unsigned long pll_dactal       : 4;
+     unsigned long pll_cp_clip      : 2;
+     unsigned long pll_conf         : 3;
+     unsigned long pll_mbctrl       : 2;
+     unsigned long pll_ring_off     : 1;
+} __attribute__((packed));
+
+union pll_cntl_u {
+     unsigned long val : 32;
+     struct pll_cntl_t f;
+} __attribute__((packed));
+
+struct sclk_cntl_t {
+     unsigned long sclk_src_sel     	: 2;
+     unsigned long    					: 2;
+     unsigned long sclk_post_div_fast   : 4;
+     unsigned long sclk_clkon_hys   	: 3;
+     unsigned long sclk_post_div_slow   : 4;
+     unsigned long disp_cg_ok2switch_en : 1;
+     unsigned long sclk_force_reg   	: 1;
+     unsigned long sclk_force_disp  	: 1;
+     unsigned long sclk_force_mc    	: 1;
+     unsigned long sclk_force_extmc 	: 1;
+     unsigned long sclk_force_cp    	: 1;
+     unsigned long sclk_force_e2    	: 1;
+     unsigned long sclk_force_e3    	: 1;
+     unsigned long sclk_force_idct  	: 1;
+     unsigned long sclk_force_bist  	: 1;
+     unsigned long busy_extend_cp   	: 1;
+     unsigned long busy_extend_e2   	: 1;
+     unsigned long busy_extend_e3   	: 1;
+     unsigned long busy_extend_idct 	: 1;
+     unsigned long    					: 3;
+} __attribute__((packed));
+
+union sclk_cntl_u {
+     unsigned long val : 32;
+     struct sclk_cntl_t f;
+} __attribute__((packed));
+
+struct pclk_cntl_t {
+     unsigned long pclk_src_sel     : 2;
+     unsigned long    				: 2;
+     unsigned long pclk_post_div    : 4;
+     unsigned long    				: 8;
+     unsigned long pclk_force_disp  : 1;
+     unsigned long    				: 15;
+} __attribute__((packed));
+
+union pclk_cntl_u {
+     unsigned long val : 32;
+     struct pclk_cntl_t f;
+} __attribute__((packed));
+
+struct clk_test_cntl_t {
+     unsigned long testclk_sel      : 4;
+     unsigned long    				: 3;
+     unsigned long start_check_freq : 1;
+     unsigned long tstcount_rst     : 1;
+     unsigned long    				: 15;
+     unsigned long test_count       : 8;
+} __attribute__((packed));
+
+union clk_test_cntl_u {
+     unsigned long val : 32;
+     struct clk_test_cntl_t f;
+} __attribute__((packed));
+
+struct pwrmgt_cntl_t {
+     unsigned long pwm_enable       	: 1;
+     unsigned long    					: 1;
+     unsigned long pwm_mode_req         : 2;
+     unsigned long pwm_wakeup_cond      : 2;
+     unsigned long pwm_fast_noml_hw_en  : 1;
+     unsigned long pwm_noml_fast_hw_en  : 1;
+     unsigned long pwm_fast_noml_cond   : 4;
+     unsigned long pwm_noml_fast_cond   : 4;
+     unsigned long pwm_idle_timer   	: 8;
+     unsigned long pwm_busy_timer   	: 8;
+} __attribute__((packed));
+
+union pwrmgt_cntl_u {
+     unsigned long val : 32;
+     struct pwrmgt_cntl_t f;
+} __attribute__((packed));
+
+#endif
+