Date: Wed, 6 May 1998 08:58:41 +0200 (CEST)
From: Geert Uytterhoeven <Geert.Uytterhoeven@cs.kuleuven.ac.be>
To: Linux/m68k <linux-m68k@lists.linux-m68k.org>
Subject: L68K: Patches for 2.1.99
Sender: owner-linux-m68k@phil.uni-sb.de


Video fixes:

  - Many atyfb updates. It should work on Atari ISA Mach64 boards now. (Bernd
    Harries and I)

  - S3triofb updates. (Peter De Schrijver)

  - vgafb and fbcon-vga: support for a VGA text mode frame buffer device (on
    ia32/AXP/PPC). fbcon-vga is also what you may want to use on chipsets that
    are VGA compatible (if (fb_var.screeninfo.accel_flags & FB_ACCELF_TEXT)).

  - Fixes by the GGI guys (we're working on the merge), e.g. hardware cursor
    support and ypan for VGA text mode.

  - Support non-page aligned frame buffers and MMIO regions.
    fb_fix_screeninfo.smem_offset is gone now. Michael, can you please update
    macfb.c?

  - Resizing the current VC before it was opened crashed the machine. This bug
    showed up if you used fbset in rc.local with console=ttyS0.

  - Addition of VESA_* defines to <linux/fb.h>.

  - First ACORN stuff. (from the vger tree)

  - Some Configure.help entries. (Hartmut Koptein)

  - Non-m68k drivers rely on the `new' (vger) initialization order. Just don't
    care for the moment.

Keyboard fixes:

  - Don't reference the various *_map keymaps directly, but use key_maps[i].
    This means the keymap symbols in defkeymap.c can be static, which is the
    case when you generate them with some versions of the kbd utils. (suggested
    by someone on the Linux/PPC mailing list)

IDE fixes:

  - Don't double byteswap the cache values on correct endian machines. (Michael
    Schmitz)


My current tree also contains some Mac and Blizzard stuff that seems to be
forgotten...

diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/Documentation/Configure.help m68k/Documentation/Configure.help
--- m68k-2.1.99/Documentation/Configure.help	Mon May  4 20:07:03 1998
+++ m68k/Documentation/Configure.help	Mon May  4 22:29:26 1998
@@ -8019,6 +8019,20 @@
   Please read http://www.cs.kuleuven.ac.be/~geert/Console/ first before saying
   Y here. Normal users say N.
 
+# drivers/video section
+Open Firmware frame buffer device support 
+CONFIG_FB_OF
+  Say Y if you want support with Open Firmware for your graphics board.
+
+S3 Trio frame buffer device support 
+CONFIG_FB_S3TRIO
+  If you have a S3 Trio say Y. Say N for S3 Virge. 
+
+ATI Mach64 display support
+CONFIG_FB_ATY
+  This driver supports graphics boards with the ATI Mach64 chips.
+
+  
 # need an empty line after last entry, for sed script in Configure.
 #
 # A couple of things I keep forgetting:
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/arch/m68k/atari/atakeyb.c m68k/arch/m68k/atari/atakeyb.c
--- m68k-2.1.99/arch/m68k/atari/atakeyb.c	Mon May  4 20:07:03 1998
+++ m68k/arch/m68k/atari/atakeyb.c	Mon May  4 22:25:18 1998
@@ -193,7 +193,7 @@
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
 };
 
-static u_short atashift_alt_map[NR_KEYS] = {
+static u_short atashift_alt_map[NR_KEYS] __initdata = {
 	0xf200, 0xf81b, 0xf821, 0xf840, 0xf823, 0xf824, 0xf825, 0xf85e,
 	0xf826, 0xf82a, 0xf828, 0xf829, 0xf85f, 0xf82b, 0xf808, 0xf809,
 	0xf851, 0xf857, 0xf845, 0xf852, 0xf854, 0xf859, 0xf855, 0xf849,
@@ -767,14 +767,17 @@
 __initfunc(int atari_keyb_init(void))
 {
     /* setup key map */
-    memcpy(plain_map, ataplain_map, sizeof(plain_map));
-    memcpy(shift_map, atashift_map, sizeof(shift_map));
+    memcpy(key_maps[0], ataplain_map, sizeof(plain_map));
+    memcpy(key_maps[1], atashift_map, sizeof(plain_map));
+    memcpy(key_maps[4], atactrl_map, sizeof(plain_map));
+    memcpy(key_maps[5], atashift_ctrl_map, sizeof(plain_map));
+    memcpy(key_maps[8], ataalt_map, sizeof(plain_map));
+    /* Atari doesn't have an altgr_map, so we can reuse its memory for
+       atashift_alt_map */
+    memcpy(key_maps[2], atashift_alt_map, sizeof(plain_map));
+    key_maps[9]  = key_maps[2];
     key_maps[2]  = 0; /* ataaltgr_map */
-    memcpy(ctrl_map, atactrl_map, sizeof(ctrl_map));
-    memcpy(shift_ctrl_map, atashift_ctrl_map, sizeof(shift_ctrl_map));
-    memcpy(alt_map, ataalt_map, sizeof(alt_map));
-    key_maps[9]  = atashift_alt_map;
-    memcpy(ctrl_alt_map, atactrl_alt_map, sizeof(ctrl_alt_map));
+    memcpy(key_maps[12], atactrl_alt_map, sizeof(plain_map));
     key_maps[13] = atashift_ctrl_alt_map;
     keymap_count = 8;
 
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/arch/m68k/mac/mackeyb.c m68k/arch/m68k/mac/mackeyb.c
--- m68k-2.1.99/arch/m68k/mac/mackeyb.c	Mon Mar 30 00:49:31 1998
+++ m68k/arch/m68k/mac/mackeyb.c	Mon May  4 22:25:18 1998
@@ -600,13 +600,13 @@
 	volatile int ct;
 
 	/* setup key map */
-	memcpy (plain_map, mac_plain_map, sizeof(plain_map));
-	memcpy(shift_map, mac_shift_map, sizeof(shift_map));
-	memcpy(altgr_map, mac_altgr_map, sizeof(altgr_map));
-	memcpy(ctrl_map, mac_ctrl_map, sizeof(ctrl_map));
-	memcpy(shift_ctrl_map, mac_shift_ctrl_map, sizeof(shift_ctrl_map));
-	memcpy(alt_map, mac_alt_map, sizeof(alt_map));
-	memcpy(ctrl_alt_map, mac_ctrl_alt_map, sizeof(ctrl_alt_map));
+	memcpy(key_maps[0], mac_plain_map, sizeof(plain_map));
+	memcpy(key_maps[1], mac_shift_map, sizeof(plain_map));
+	memcpy(key_maps[2], mac_altgr_map, sizeof(plain_map));
+	memcpy(key_maps[4], mac_ctrl_map, sizeof(plain_map));
+	memcpy(key_maps[5], mac_shift_ctrl_map, sizeof(plain_map));
+	memcpy(key_maps[8], mac_alt_map, sizeof(plain_map));
+	memcpy(key_maps[12], mac_ctrl_alt_map, sizeof(plain_map));
 
 	/* initialize mouse interrupt hook */
 	mac_mouse_interrupt_hook = NULL;
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/char/amikeyb.c m68k/drivers/char/amikeyb.c
--- m68k-2.1.99/drivers/char/amikeyb.c	Mon May  4 20:07:05 1998
+++ m68k/drivers/char/amikeyb.c	Mon May  4 22:25:18 1998
@@ -301,13 +301,13 @@
         return -EIO;
 
     /* setup key map */
-    memcpy(plain_map, amiplain_map, sizeof(plain_map));
-    memcpy(shift_map, amishift_map, sizeof(shift_map));
-    memcpy(altgr_map, amialtgr_map, sizeof(altgr_map));
-    memcpy(ctrl_map, amictrl_map, sizeof(ctrl_map));
-    memcpy(shift_ctrl_map, amishift_ctrl_map, sizeof(shift_ctrl_map));
-    memcpy(alt_map, amialt_map, sizeof(alt_map));
-    memcpy(ctrl_alt_map, amictrl_alt_map, sizeof(ctrl_alt_map));
+    memcpy(key_maps[0], amiplain_map, sizeof(plain_map));
+    memcpy(key_maps[1], amishift_map, sizeof(plain_map));
+    memcpy(key_maps[2], amialtgr_map, sizeof(plain_map));
+    memcpy(key_maps[4], amictrl_map, sizeof(plain_map));
+    memcpy(key_maps[5], amishift_ctrl_map, sizeof(plain_map));
+    memcpy(key_maps[8], amialt_map, sizeof(plain_map));
+    memcpy(key_maps[12], amictrl_alt_map, sizeof(plain_map));
 
     /*
      * Initialize serial data direction.
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/char/console.new.c m68k/drivers/char/console.new.c
--- m68k-2.1.99/drivers/char/console.new.c	Mon May  4 20:07:05 1998
+++ m68k/drivers/char/console.new.c	Tue May  5 22:45:47 1998
@@ -108,10 +108,13 @@
  *     int con_get_font(struct vc_data *conp, int *w, int *h, char *data)
  *     int con_set_font(struct vc_data *conp, int w, int h, char *data)
  *     int con_set_palette(struct vc_data *conp, unsigned char *table)
- *     int con_scrolldelta(int lines)
+ *     int con_scrolldelta(struct vc_data *conp, int lines)
  *
  * Support for changeable cursor shape
  * by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>, August 1997
+ *
+ * Ported to i386 and con_scrolldelta fixed
+ * by Emmanuel Marty <core@ggi-project.org>, April 1998
  */
 
 #include <linux/sched.h>
@@ -433,7 +436,6 @@
 	unsigned long occ, oll, oss, osr;
 	unsigned short *newscreen;
 	long ol, nl, rlth, rrem;
-	struct winsize ws, *cws;
 
 	if (!cols || !lines || currcons >= MAX_NR_CONSOLES)
 	    return;
@@ -496,13 +498,15 @@
 	    gotoxy(currcons, x, y);
 	    save_cur(currcons);
 
-	    cws = &console_table[currcons]->winsize;
-	    ws.ws_row = video_num_lines;
-	    ws.ws_col = video_num_columns;
-	    if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) &&
-		console_table[currcons]->pgrp > 0)
-		kill_pg(console_table[currcons]->pgrp, SIGWINCH, 1);
-	    *cws = ws;
+	    if (console_table[currcons]) {
+		struct winsize ws, *cws = &console_table[currcons]->winsize;
+		ws.ws_row = video_num_lines;
+		ws.ws_col = video_num_columns;
+		if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) &&
+		    console_table[currcons]->pgrp > 0)
+		    kill_pg(console_table[currcons]->pgrp, SIGWINCH, 1);
+		*cws = ws;
+	    }
 	}
 
 	/* don't update in graphics mode */
@@ -595,7 +599,7 @@
 static inline void scrolldelta(int lines)
 {
     int currcons = fg_console;
-    sw->con_scrolldelta(lines);
+    sw->con_scrolldelta(vc_cons[currcons].d, lines);
 }
 
 void scrollback(int lines)
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/char/dn_keyb.c m68k/drivers/char/dn_keyb.c
--- m68k-2.1.99/drivers/char/dn_keyb.c	Mon Mar 30 00:49:32 1998
+++ m68k/drivers/char/dn_keyb.c	Mon May  4 22:25:18 1998
@@ -573,13 +573,13 @@
 
 /*  printk("dn_keyb_init\n"); */
 
-  memcpy(plain_map, dnplain_map, sizeof(plain_map));
-  memcpy(shift_map, dnshift_map, sizeof(shift_map));
-  memcpy(altgr_map, dnaltgr_map, sizeof(altgr_map));
-  memcpy(ctrl_map, dnctrl_map, sizeof(ctrl_map));
-  memcpy(shift_ctrl_map, dnshift_ctrl_map, sizeof(shift_ctrl_map));
-  memcpy(alt_map, dnalt_map, sizeof(alt_map));
-  memcpy(ctrl_alt_map, dnctrl_alt_map, sizeof(ctrl_alt_map));
+  memcpy(key_maps[0], dnplain_map, sizeof(plain_map));
+  memcpy(key_maps[1], dnshift_map, sizeof(plain_map));
+  memcpy(key_maps[2], dnaltgr_map, sizeof(plain_map));
+  memcpy(key_maps[4], dnctrl_map, sizeof(plain_map));
+  memcpy(key_maps[5], dnshift_ctrl_map, sizeof(plain_map));
+  memcpy(key_maps[8], dnalt_map, sizeof(plain_map));
+  memcpy(key_maps[12], dnctrl_alt_map, sizeof(plain_map));
 
   mouse_dx=0; 
   mouse_dy=0; 
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/char/fbmem.c m68k/drivers/char/fbmem.c
--- m68k-2.1.99/drivers/char/fbmem.c	Mon May  4 20:07:05 1998
+++ m68k/drivers/char/fbmem.c	Tue May  5 22:41:07 1998
@@ -67,8 +67,10 @@
 extern unsigned long virgefb_init(unsigned long mem_start);
 extern void virgefb_setup(char *options, int *ints);
 extern void resolver_video_setup(char *options, int *ints);
-extern unsigned long s3triofb_init(unsigned long mem_start);
-extern void s3trio_video_setup(char *options, int *ints);
+extern void s3triofb_init(void);
+extern void s3triofb_setup(char *options, int *ints);
+extern void vgafb_init(void);
+extern void vgafb_setup(char *options, int *ints);
 
 
 static struct {
@@ -107,7 +109,7 @@
 	{ "apollo", dnfb_init, NULL },
 #endif
 #ifdef CONFIG_FB_S3TRIO
-	{ "s3trio",s3triofb_init,s3trio_video_setup },
+	{ "s3trio", s3triofb_init, s3triofb_setup },
 #endif 
 #ifdef CONFIG_FB_TGA
 	{ "tga", tgafb_init, NULL },
@@ -115,6 +117,9 @@
 #ifdef CONFIG_FB_VIRGE
 	{ "virge", virgefb_init, virgefb_setup },
 #endif
+#ifdef CONFIG_FB_VGA
+	{ "vga", vgafb_init, vgafb_setup },
+#endif 
 #ifdef CONFIG_GSP_RESOLVER
 	/* Not a real frame buffer device... */
 	{ "resolver", NULL, resolver_video_setup },
@@ -339,34 +344,38 @@
 	struct fb_info *info = registered_fb[fbidx];
 	struct fb_ops *fb = info->fbops;
 	struct fb_fix_screeninfo fix;
-	unsigned char *start;
-	unsigned long len;
+	struct fb_var_screeninfo var;
+	unsigned long start;
+	u32 len;
 
-	if (! fb)
+	if (!fb)
 		return -ENODEV;
 	fb->fb_get_fix(&fix, PROC_CONSOLE(), info);
-	if (vma->vm_offset < fix.smem_len) {
-		/* frame buffer memory */
-		start = fix.smem_start;
-		len = fix.smem_len;
-	} else {
+
+	/* frame buffer memory */
+	start = (unsigned long)fix.smem_start;
+	len = (start & ~PAGE_MASK)+fix.smem_len;
+	start &= PAGE_MASK;
+	len = (len+~PAGE_MASK) & PAGE_MASK;
+	if (vma->vm_offset >= len) {
 		/* memory mapped io */
-		struct fb_var_screeninfo var;
+		vma->vm_offset -= len;
 		fb->fb_get_var(&var, PROC_CONSOLE(), info);
 		if (var.accel_flags)
 			return -EINVAL;
-		start = fix.mmio_start;
-		len = fix.mmio_len;
-		vma->vm_offset -= fix.smem_len;
+		start = (unsigned long)fix.mmio_start;
+		len = (start & ~PAGE_MASK)+fix.mmio_len;
+		start &= PAGE_MASK;
+		len = (len+~PAGE_MASK) & PAGE_MASK;
 	}
 	if ((vma->vm_end - vma->vm_start + vma->vm_offset) > len)
 		return -EINVAL;
 #ifdef __powerpc__
-	start = (unsigned char *)iopa((unsigned long)start);
+	start = iopa(start);
 #else
-	start = (unsigned char *)__pa(start);
+	start = __pa(start);
 #endif
-	vma->vm_offset += (unsigned long)start;
+	vma->vm_offset += start;
 	if (vma->vm_offset & ~PAGE_MASK)
 		return -ENXIO;
 #if defined(__mc68000__)
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/macintosh/mac_keyb.c m68k/drivers/macintosh/mac_keyb.c
--- m68k-2.1.99/drivers/macintosh/mac_keyb.c	Mon May  4 20:07:10 1998
+++ m68k/drivers/macintosh/mac_keyb.c	Mon May  4 22:25:18 1998
@@ -534,13 +534,13 @@
 		return;
 
 	/* setup key map */
-	memcpy(plain_map, macplain_map, sizeof(plain_map));
-	memcpy(shift_map, macshift_map, sizeof(shift_map));
-	memcpy(altgr_map, macaltgr_map, sizeof(altgr_map));
-	memcpy(ctrl_map, macctrl_map, sizeof(ctrl_map));
-	memcpy(shift_ctrl_map, macshift_ctrl_map, sizeof(shift_ctrl_map));
-	memcpy(alt_map, macalt_map, sizeof(alt_map));
-	memcpy(ctrl_alt_map, macctrl_alt_map, sizeof(ctrl_alt_map));
+	memcpy(key_maps[0], macplain_map, sizeof(plain_map));
+	memcpy(key_maps[1], macshift_map, sizeof(plain_map));
+	memcpy(key_maps[2], macaltgr_map, sizeof(plain_map));
+	memcpy(key_maps[4], macctrl_map, sizeof(plain_map));
+	memcpy(key_maps[5], macshift_ctrl_map, sizeof(plain_map));
+	memcpy(key_maps[8], macalt_map, sizeof(plain_map));
+	memcpy(key_maps[12], macctrl_alt_map, sizeof(plain_map));
 
 	/* initialize mouse interrupt hook */
 	adb_mouse_interrupt_hook = NULL;
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/Config.in m68k/drivers/video/Config.in
--- m68k-2.1.99/drivers/video/Config.in	Mon Mar 30 00:49:38 1998
+++ m68k/drivers/video/Config.in	Tue May  5 22:21:56 1998
@@ -7,6 +7,9 @@
   mainmenu_option next_comment
   comment 'Frame buffer devices'
 
+  if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+    define_bool CONFIG_FB_ACORN y
+  fi
   if [ "$CONFIG_APOLLO" = "y" ]; then
     define_bool CONFIG_FB_APOLLO y
   fi
@@ -46,6 +49,9 @@
   if [ "$CONFIG_TGA_CONSOLE" = "y" ]; then
     define_bool CONFIG_FB_TGA y
   fi
+  if [ "$ARCH" = "i386" -o "$ARCH" = "alpha" -o "$ARCH" = "ppc" ]; then
+    bool 'VGA chipset support (text only)' CONFIG_FB_VGA
+  fi
   tristate 'Virtual Frame Buffer support (ONLY FOR TESTING!)' CONFIG_FB_VIRTUAL
 
   bool 'Advanced low level driver options' CONFIG_FBCON_ADVANCED
@@ -63,6 +69,7 @@
     bool 'Atari interleaved bitplanes (4 planes) support' CONFIG_FBCON_IPLAN2P4
     bool 'Atari interleaved bitplanes (8 planes) support' CONFIG_FBCON_IPLAN2P8
     bool 'Mac variable bpp packed pixels support' CONFIG_FBCON_MAC
+    bool 'VGA characters/attributes support' CONFIG_FBCON_VGA
   else
     if [ "$CONFIG_FB_AMIGA" = "y" -o "$CONFIG_FB_AMIGA" = "m" -o \
 	 "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATARI" = "m" -o \
@@ -108,6 +115,15 @@
 	 "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_ATY" = "m" -o \
 	 "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
       define_bool CONFIG_FBCON_CFB32 y
+    fi
+    if [ "$CONFIG_FB_ACORN" != "n" ]; then
+      define_bool CONFIG_FBCON_MFB y
+      define_bool CONFIG_FBCON_CFB2 y
+      define_bool CONFIG_FBCON_CFB4 y
+      define_bool CONFIG_FBCON_CFB8 y
+    fi
+    if [ "$CONFIG_FB_VGA" = "y" -o "$CONFIG_FB_VGA" = "m" ]; then
+      define_bool CONFIG_FBCON_VGA y
     fi
   fi
 
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/Makefile m68k/drivers/video/Makefile
--- m68k-2.1.99/drivers/video/Makefile	Mon Mar 30 00:49:38 1998
+++ m68k/drivers/video/Makefile	Tue May  5 22:21:56 1998
@@ -88,6 +88,10 @@
 L_OBJS += tgafb.o
 endif
 
+ifeq ($(CONFIG_FB_VGA),y)
+L_OBJS += vgafb.o
+endif
+
 ifeq ($(CONFIG_FB_VIRGE),y)
 L_OBJS += virgefb.o
 else
@@ -156,6 +160,10 @@
 
 ifdef CONFIG_FBCON_MFB
 LX_OBJS += fbcon-mfb.o
+endif
+
+ifdef CONFIG_FBCON_VGA
+LX_OBJS += fbcon-vga.o
 endif
 
 # GSP Console
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/S3triofb.c m68k/drivers/video/S3triofb.c
--- m68k-2.1.99/drivers/video/S3triofb.c	Mon May  4 20:07:17 1998
+++ m68k/drivers/video/S3triofb.c	Tue May  5 22:21:58 1998
@@ -23,9 +23,8 @@
 
 */
 
-#include <linux/config.h>
-#include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/mm.h>
@@ -36,11 +35,18 @@
 #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>
+#ifdef CONFIG_FB_COMPAT_XPMAC
+#include <linux/vc_ioctl.h>
+#endif
 
+#include "fbcon.h"
 #include "fbcon-cfb8.h"
+#include "s3blit.h"
 
 
 #define mem_in8(addr)           in_8((void *)(addr))
@@ -70,8 +76,6 @@
      *  Interface used by the world
      */
 
-void of_video_setup(char *options, int *ints);
-
 static int s3trio_open(struct fb_info *info);
 static int s3trio_release(struct fb_info *info);
 static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con,
@@ -102,11 +106,13 @@
      *  Interface to the low level console driver
      */
 
-unsigned long s3trio_fb_init(unsigned long mem_start);
+void s3triofb_init(void);
 static int s3triofbcon_switch(int con, struct fb_info *info);
 static int s3triofbcon_updatevar(int con, struct fb_info *info);
 static void s3triofbcon_blank(int blank, struct fb_info *info);
+#if 0
 static int s3triofbcon_setcmap(struct fb_cmap *cmap, int con);
+#endif
 
     /*
      *  Text console acceleration
@@ -138,7 +144,7 @@
                          u_int *transp, 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 void do_install_cmap(int con);
+static void do_install_cmap(int con, struct fb_info *info);
 
 
 static struct fb_ops s3trio_ops = {
@@ -200,11 +206,16 @@
 			  struct fb_info *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_NONINTERLACED)
+	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;
 }
@@ -219,12 +230,25 @@
 static int s3trio_pan_display(struct fb_var_screeninfo *var, int con,
 			      struct fb_info *info)
 {
-    if (var->xoffset || var->yoffset)
+    unsigned int base;
+
+    if (var->xoffset > (var->xres_virtual - var->xres))
 	return -EINVAL;
-    else
-	return 0;
+    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
      */
@@ -238,7 +262,7 @@
     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(fb_display[con].var.bits_per_pixel),
+	fb_copy_cmap(fb_default_cmap(1 << fb_display[con].var.bits_per_pixel),
 		     cmap, kspc ? 0 : 2);
     return 0;
 }
@@ -273,7 +297,17 @@
     return -EINVAL;
 }
 
-__initfunc(int s3trio_resetaccel(void)) {
+__initfunc(void s3triofb_init(void))
+{
+#ifdef __powerpc__
+    /* We don't want to be called like this. */
+    /* We rely on Open Firmware (offb) instead. */
+#else /* !__powerpc__ */
+    /* To be merged with cybervision */
+#endif /* !__powerpc__ */
+}
+
+__initfunc(void s3trio_resetaccel(void)) {
 
 
 #define EC01_ENH_ENB    0x0005
@@ -314,18 +348,15 @@
 	outw(0xffff,  0xaae8);       /* Enable all planes */
 	outw(0xffff, 0xaae8);       /* Enable all planes */
 	outw( MF_PIX_CONTROL | MFA_SRC_FOREGR_MIX,  0xbee8);
-
 }
 
-__initfunc(int s3trio_init(void)) {
+__initfunc(int s3trio_init(struct device_node *dp)) {
 
     u_char bus, dev;
     unsigned int t32;
     unsigned short cmd;
-    int i;
 
-	bus=0;
-	dev=(3<<3);
+	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);
@@ -351,16 +382,16 @@
 			outw(IO_OUT16VAL(0x48, 0x38),0x03D4);
 			outw(IO_OUT16VAL(0xA0, 0x39),0x03D4);
 			outb(0x33,0x3d4);
-			outw(IO_OUT16VAL( inb(0x3d5) & ~(0x2 |
-			 0x10 | 0x40) , 0x33),0x3d4);
+			outw(IO_OUT16VAL((inb(0x3d5) & ~(0x2 | 0x10 |  0x40)) |
+					  0x20, 0x33), 0x3d4);
 
-			outw(IO_OUT16VAL(0x6,0x8), 0x3c4);
+			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);
+			outb(0x58, 0x3d4);
+			outw(IO_OUT16VAL(inb(0x3d5) | 3 | 0x10, 0x58), 0x3d4);
+			outw(IO_OUT16VAL(8, 0x53), 0x3d4);
 
 			/* switch off I/O accesses */
 
@@ -368,6 +399,7 @@
 			pcibios_write_config_word(bus, dev, PCI_COMMAND,
 				        PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
 #endif
+			return 1;
                 }
 
 	return 0;
@@ -379,18 +411,12 @@
      *  We heavily rely on OF for the moment. This needs fixing.
      */
 
-__initfunc(unsigned long s3trio_fb_init(unsigned long mem_start))
+__initfunc(void s3triofb_init_of(struct device_node *dp))
 {
-    struct device_node *dp;
     int i, err, *pp, len;
-    unsigned *up, address;
+    unsigned long address;
     u_long *CursorBase;
 
-    if (!prom_display_paths[0])
-	return mem_start;
-    if (!(dp = find_path_device(prom_display_paths[0])))
-	return mem_start;
-
     strncat(s3trio_name, dp->name, sizeof(s3trio_name));
     s3trio_name[sizeof(s3trio_name)-1] = '\0';
     strcpy(fb_fix.id, s3trio_name);
@@ -398,19 +424,19 @@
     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 mem_start;
+	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 mem_start;
+	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 mem_start;
+	return;
     }
     if ((pp = (int *)get_property(dp, "width", &len)) != NULL
 	&& len == sizeof(int))
@@ -425,45 +451,48 @@
 	fb_fix.line_length = fb_var.xres_virtual;
     fb_fix.smem_len = fb_fix.line_length*fb_var.yres;
 
-    s3trio_init();
-    address=0xc6000000;
+    s3trio_init(dp);
+    address = 0xc6000000;
     fb_fix.smem_start = ioremap(address,64*1024*1024);
     fb_fix.type = FB_TYPE_PACKED_PIXELS;
     fb_fix.type_aux = 0;
     fb_fix.accel = FB_ACCEL_S3_TRIO64;
 
+    fb_fix.xpanstep = 1;
+    fb_fix.ypanstep = 1;
+
     s3trio_resetaccel();
 
-	mem_out8(0x30,fb_fix.smem_start+0x1008000 + 0x03D4);
-	mem_out8(0x2d,fb_fix.smem_start+0x1008000 + 0x03D4);
-	mem_out8(0x2e,fb_fix.smem_start+0x1008000 + 0x03D4);
+    mem_out8(0x30, fb_fix.smem_start+0x1008000 + 0x03D4);
+    mem_out8(0x2d, fb_fix.smem_start+0x1008000 + 0x03D4);
+    mem_out8(0x2e, fb_fix.smem_start+0x1008000 + 0x03D4);
 
-	mem_out8(0x50,fb_fix.smem_start+0x1008000 + 0x03D4);
+    mem_out8(0x50, fb_fix.smem_start+0x1008000 + 0x03D4);
 
     /* disable HW cursor */
 
-    mem_out8(0x39,fb_fix.smem_start+0x1008000 + 0x03D4);
-    mem_out8(0xa0,fb_fix.smem_start+0x1008000 + 0x03D5);
+    mem_out8(0x39, fb_fix.smem_start+0x1008000 + 0x03D4);
+    mem_out8(0xa0, fb_fix.smem_start+0x1008000 + 0x03D5);
 
-    mem_out8(0x45,fb_fix.smem_start+0x1008000 + 0x03D4);
-    mem_out8(0,fb_fix.smem_start+0x1008000 + 0x03D5);
+    mem_out8(0x45, fb_fix.smem_start+0x1008000 + 0x03D4);
+    mem_out8(0, fb_fix.smem_start+0x1008000 + 0x03D5);
 
-    mem_out8(0x4e,fb_fix.smem_start+0x1008000 + 0x03D4);
-    mem_out8(0,fb_fix.smem_start+0x1008000 + 0x03D5);
+    mem_out8(0x4e, fb_fix.smem_start+0x1008000 + 0x03D4);
+    mem_out8(0, fb_fix.smem_start+0x1008000 + 0x03D5);
 
-    mem_out8(0x4f,fb_fix.smem_start+0x1008000 + 0x03D4);
-    mem_out8(0,fb_fix.smem_start+0x1008000 + 0x03D5);
+    mem_out8(0x4f, fb_fix.smem_start+0x1008000 + 0x03D4);
+    mem_out8(0, fb_fix.smem_start+0x1008000 + 0x03D5);
 
     /* init HW cursor */
 
-    CursorBase=(u_long *)(fb_fix.smem_start + 2*1024*1024 - 0x400);
-	for (i=0; i < 8; i++) {
+    CursorBase = (u_long *)(fb_fix.smem_start + 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++) {
+	for (i = 8; i < 64; i++) {
 		*(CursorBase  +(i*4)) = 0xffff0000;
 		*(CursorBase+1+(i*4)) = 0xffff0000;
 		*(CursorBase+2+(i*4)) = 0xffff0000;
@@ -471,34 +500,43 @@
 	}
 
 
-    mem_out8(0x4c,fb_fix.smem_start+0x1008000 + 0x03D4);
-    mem_out8(((2*1024 - 1)&0xf00)>>8,fb_fix.smem_start+0x1008000 + 0x03D5);
+    mem_out8(0x4c, fb_fix.smem_start+0x1008000 + 0x03D4);
+    mem_out8(((2*1024 - 1)&0xf00)>>8, fb_fix.smem_start+0x1008000 + 0x03D5);
 
-    mem_out8(0x4d,fb_fix.smem_start+0x1008000 + 0x03D4);
-    mem_out8((2*1024 - 1) & 0xff,fb_fix.smem_start+0x1008000 + 0x03D5);
+    mem_out8(0x4d, fb_fix.smem_start+0x1008000 + 0x03D4);
+    mem_out8((2*1024 - 1) & 0xff, fb_fix.smem_start+0x1008000 + 0x03D5);
 
-    mem_out8(0x45,fb_fix.smem_start+0x1008000 + 0x03D4);
-	mem_in8(fb_fix.smem_start+0x1008000 + 0x03D4);
+    mem_out8(0x45, fb_fix.smem_start+0x1008000 + 0x03D4);
+    mem_in8(fb_fix.smem_start+0x1008000 + 0x03D4);
 
-    mem_out8(0x4a,fb_fix.smem_start+0x1008000 + 0x03D4);
-    mem_out8(0x80,fb_fix.smem_start+0x1008000 + 0x03D5);
-    mem_out8(0x80,fb_fix.smem_start+0x1008000 + 0x03D5);
-    mem_out8(0x80,fb_fix.smem_start+0x1008000 + 0x03D5);
-
-    mem_out8(0x4b,fb_fix.smem_start+0x1008000 + 0x03D4);
-    mem_out8(0x00,fb_fix.smem_start+0x1008000 + 0x03D5);
-    mem_out8(0x00,fb_fix.smem_start+0x1008000 + 0x03D5);
-    mem_out8(0x00,fb_fix.smem_start+0x1008000 + 0x03D5);
-
-    mem_out8(0x45,fb_fix.smem_start+0x1008000 + 0x03D4);
-    mem_out8(0,fb_fix.smem_start+0x1008000 + 0x03D5);
+    mem_out8(0x4a, fb_fix.smem_start+0x1008000 + 0x03D4);
+    mem_out8(0x80, fb_fix.smem_start+0x1008000 + 0x03D5);
+    mem_out8(0x80, fb_fix.smem_start+0x1008000 + 0x03D5);
+    mem_out8(0x80, fb_fix.smem_start+0x1008000 + 0x03D5);
+
+    mem_out8(0x4b, fb_fix.smem_start+0x1008000 + 0x03D4);
+    mem_out8(0x00, fb_fix.smem_start+0x1008000 + 0x03D5);
+    mem_out8(0x00, fb_fix.smem_start+0x1008000 + 0x03D5);
+    mem_out8(0x00, fb_fix.smem_start+0x1008000 + 0x03D5);
+
+    mem_out8(0x45, fb_fix.smem_start+0x1008000 + 0x03D4);
+    mem_out8(0, fb_fix.smem_start+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 *)fb_fix.smem_start,0,640*480);
+    memset((char *)fb_fix.smem_start, 0, 640*480);
 
 #if 0
-    Trio_RectFill(0,0,90,90,7,1);
+    Trio_RectFill(0, 0, 90, 90, 7, 1);
 #endif
 
     fb_fix.visual = FB_VISUAL_PSEUDOCOLOR ;
@@ -512,8 +550,8 @@
     fb_var.nonstd = 0;
     fb_var.activate = 0;
     fb_var.height = fb_var.width = -1;
-    fb_var.text_accel = FB_ACCELF_TEXT;
-#warning FIXME: always obey fb_var.text_accel
+    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;
@@ -535,7 +573,7 @@
     disp.can_soft_blank = 1;
     disp.inverse = 0;
 #ifdef CONFIG_FBCON_CFB8
-    if (fb_var.text_accel & FB_ACCELF_TEXT)
+    if (fb_var.accel_flags & FB_ACCELF_TEXT)
 	disp.dispsw = &fbcon_trio8;
     else
 	disp.dispsw = &fbcon_cfb8;
@@ -581,12 +619,10 @@
 
     err = register_framebuffer(&fb_info);
     if (err < 0)
-	return mem_start;
+	return;
 
     printk("fb%d: S3 Trio frame buffer device on %s\n",
 	   GET_FB_IDX(fb_info.node), dp->full_name);
-
-    return mem_start;
 }
 
 
@@ -599,7 +635,7 @@
 
     currcon = con;
     /* Install new colormap */
-    do_install_cmap(con);
+    do_install_cmap(con,info);
     return 0;
 }
 
@@ -619,17 +655,24 @@
 
 static void s3triofbcon_blank(int blank, struct fb_info *info)
 {
-    /* Nothing */
+    unsigned char x;
+
+    mem_out8(0x1, fb_fix.smem_start+0x1008000 + 0x03c4);
+    x = mem_in8(fb_fix.smem_start+0x1008000 + 0x03c5);
+    mem_out8((x & (~0x20)) | (blank << 5),
+	     fb_fix.smem_start+0x1008000 + 0x03c5);
 }
 
     /*
      *  Set the colormap
      */
 
+#if 0
 static int s3triofbcon_setcmap(struct fb_cmap *cmap, int con)
 {
     return(s3trio_set_cmap(cmap, 1, con, &fb_info));
 }
+#endif
 
 
     /*
@@ -673,7 +716,7 @@
 }
 
 
-static void do_install_cmap(int con)
+static void do_install_cmap(int con, struct fb_info *info)
 {
     if (con != currcon)
 	return;
@@ -693,6 +736,9 @@
 
 static int s3trio_console_setmode(struct vc_mode *mode, int doit)
 {
+#if 1
+    return -EINVAL;
+#else
     int err;
     struct fb_var_screeninfo var;
     struct s3trio_par par;
@@ -722,11 +768,12 @@
     if (doit)
         s3trio_set_var(&var, currcon, 0);
     return 0;
+#endif
 }
 
 #endif /* CONFIG_FB_COMPAT_XPMAC */
 
-void s3trio_video_setup(char *options, int *ints) {
+void s3triofb_setup(char *options, int *ints) {
 
         return;
 
@@ -884,6 +931,6 @@
 
 static struct display_switch fbcon_trio8 = {
    fbcon_cfb8_setup, fbcon_trio8_bmove, fbcon_trio8_clear, fbcon_trio8_putc,
-   fbcon_trio8_putcs, fbcon_trio8_revc
+   fbcon_trio8_putcs, fbcon_trio8_revc, NULL
 };
 #endif
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/amifb.c m68k/drivers/video/amifb.c
--- m68k-2.1.99/drivers/video/amifb.c	Mon May  4 20:07:17 1998
+++ m68k/drivers/video/amifb.c	Tue May  5 22:21:54 1998
@@ -2925,20 +2925,20 @@
 		custom.dmacon = DMAF_RASTER | DMAF_SPRITE;
 		red = green = blue = 0;
 		if (!IS_OCS && do_blank > 1) {
-			switch (do_blank) {
-				case 2 : /* suspend vsync */
+			switch (do_blank-1) {
+				case VESA_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 3 : /* suspend hsync */
+				case VESA_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 4 : /* powerdown */
+				case VESA_POWERDOWN:
 					custom.hsstrt = hsstrt2hw(par->htotal+16);
 					custom.hsstop = hsstop2hw(par->htotal+16);
 					custom.vsstrt = vsstrt2hw(par->vtotal+4);
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/aty.h m68k/drivers/video/aty.h
--- m68k-2.1.99/drivers/video/aty.h	Mon Mar 30 00:49:39 1998
+++ m68k/drivers/video/aty.h	Tue May  5 22:21:54 1998
@@ -569,7 +569,8 @@
 #define PLL_WR_EN		0x02
 
 /* PLL registers */
-#define PLL_MACRO_CNTL		0x01
+#define MPLL_CNTL		0x00
+#define VPLL_CNTL		0x01
 #define PLL_REF_DIV		0x02
 #define PLL_GEN_CNTL		0x03
 #define MCLK_FB_DIV		0x04
@@ -579,7 +580,9 @@
 #define VCLK1_FB_DIV		0x08
 #define VCLK2_FB_DIV		0x09
 #define VCLK3_FB_DIV		0x0A
-#define PLL_XCLK_CNTL		0x0B
+#define PLL_EXT_CNTL		0x0B
+#define DLL_CNTL		0x0C
+#define VFC_CNTL		0x0D
 #define PLL_TEST_CTRL		0x0E
 #define PLL_TEST_COUNT		0x0F
 
@@ -692,24 +695,57 @@
 #define PCI_MACH64_CX		0x4358
 #define PCI_MACH64_CT		0x4354
 #define PCI_MACH64_ET		0x4554
-#define PCI_MACH64_VT		0x5654
-#define PCI_MACH64_GT		0x4754
+#define PCI_MACH64_GB		0x4742	/* RAGE PRO, BGA, AGP 1x and 2x */
+#define PCI_MACH64_GD		0x4744	/* RAGE PRO, BGA, AGP 1x only */
+#define PCI_MACH64_GI		0x4749	/* RAGE PRO, BGA, PCI33 only */
+#define PCI_MACH64_GP		0x4750	/* RAGE PRO, PQFP, PCI33, full 3D */
+#define PCI_MACH64_GQ		0x4751	/* RAGE PRO, PQFP, PCI33, limited 3D */
+#define PCI_MACH64_GT		0x4754	/* 3D RAGE II/II+ */
+#define PCI_MACH64_LG		0x4c47	/* 3D RAGE LT */
+#define PCI_MACH64_VT		0x5654	/* 264VT */
 
 /* CONFIG_CHIP_ID register constants */
 #define CFG_CHIP_TYPE		0x0000FFFF
 #define CFG_CHIP_CLASS		0x00FF0000
 #define CFG_CHIP_REV		0xFF000000
-#define CFG_CHIP_VERSION	0x07000000
-#define CFG_CHIP_FOUNDRY	0x38000000
-#define CFG_CHIP_REVISION	0xC0000000
+#define CFG_CHIP_MAJOR		0x07000000
+#define CFG_CHIP_FND_ID		0x38000000
+#define CFG_CHIP_MINOR		0xC0000000
 
 /* Chip IDs read from CONFIG_CHIP_ID */
 #define MACH64_GX_ID		0xD7
 #define MACH64_CX_ID		0x57
 #define MACH64_CT_ID		0x4354
 #define MACH64_ET_ID		0x4554
-#define MACH64_VT_ID		0x5654
-#define MACH64_GT_ID		0x4754
+#define MACH64_GB_ID		0x4742	/* RAGE PRO, BGA, AGP 1x and 2x */
+#define MACH64_GD_ID		0x4744	/* RAGE PRO, BGA, AGP 1x only */
+#define MACH64_GI_ID		0x4749	/* RAGE PRO, BGA, PCI33 only */
+#define MACH64_GP_ID		0x4750	/* RAGE PRO, PQFP, PCI33, full 3D */
+#define MACH64_GQ_ID		0x4751	/* RAGE PRO, PQFP, PCI33, limited 3D */
+#define MACH64_GT_ID		0x4754	/* 3D RAGE II/II+ */
+#define MACH64_LG_ID		0x4c47	/* 3D RAGE LT */
+#define MACH64_VT_ID		0x5654	/* 264VT */
+
+/* Mach64 major ASIC revisions */
+#define MACH64_ASIC_NEC_VT_A3		0x08
+#define MACH64_ASIC_NEC_VT_A4		0x48
+#define MACH64_ASIC_SGS_VT_A4		0x40
+#define MACH64_ASIC_SGS_VT_B1S1		0x01
+#define MACH64_ASIC_SGS_GT_B1S1		0x01
+#define MACH64_ASIC_SGS_GT_B1S2		0x41
+#define MACH64_ASIC_UMC_GT_B2U1		0x1a
+#define MACH64_ASIC_UMC_GT_B2U2		0x5a
+#define MACH64_ASIC_UMC_VT_B2U3		0x9a
+#define MACH64_ASIC_UMC_GT_B2U3		0x9a
+#define MACH64_ASIC_UMC_R3B_D_P_A1	0x1b
+#define MACH64_ASIC_UMC_R3B_D_P_A2	0x5b
+#define MACH64_ASIC_UMC_R3B_D_P_A3	0x1c
+#define MACH64_ASIC_UMC_R3B_D_P_A4	0x5c
+
+/* Mach64 foundries */
+#define MACH64_FND_SGS		0
+#define MACH64_FND_NEC		1
+#define MACH64_FND_UMC		3
 
 /* Mach64 chip types */
 #define MACH64_UNKNOWN		0
@@ -901,23 +937,29 @@
 #define MACH64_NUM_FREQS	50
 
 /* Wait until "v" queue entries are free */
-#define aty_WaitQueue(v)    { while ((aty_ld_le32(FIFO_STAT) & 0xffff) > \
-			 ((unsigned short)(0x8000 >> (v)))); }
+#define aty_WaitQueue(v, info) \
+{ \
+    while ((aty_ld_le32(FIFO_STAT, info) & 0xffff) > ((u16)(0x8000 >> (v)))); \
+}
 
 /* Wait until GP is idle and queue is empty */
-#define aty_WaitIdleEmpty() { aty_WaitQueue(16); \
-			  while ((aty_ld_le32(GUI_STAT) & 1) != 0); }
+#define aty_WaitIdleEmpty(info) \
+{ \
+    aty_WaitQueue(16, info); \
+    while ((aty_ld_le32(GUI_STAT, info) & 1) != 0); \
+}
 
 #define SKIP_2(_v) ((((_v)<<1)&0xfff8)|((_v)&0x3)|(((_v)&0x80)>>5))
 
-#define MACH64_BIT_BLT(_srcx, _srcy, _dstx, _dsty, _w, _h, _dir) \
+#define MACH64_BIT_BLT(_srcx, _srcy, _dstx, _dsty, _w, _h, _dir, info) \
 { \
-    aty_WaitQueue(5); \
-    aty_st_le32(SRC_Y_X, (((_srcx) << 16) | ((_srcy) & 0x0000ffff))); \
-    aty_st_le32(SRC_WIDTH1, (_w)); \
-    aty_st_le32(DST_CNTL, (_dir)); \
-    aty_st_le32(DST_Y_X, (((_dstx) << 16) | ((_dsty) & 0x0000ffff))); \
-    aty_st_le32(DST_HEIGHT_WIDTH, (((_w) << 16) | ((_h) & 0x0000ffff))); \
+    aty_WaitQueue(5, info); \
+    aty_st_le32(SRC_Y_X, (((_srcx) << 16) | ((_srcy) & 0x0000ffff)), info); \
+    aty_st_le32(SRC_WIDTH1, (_w), info); \
+    aty_st_le32(DST_CNTL, (_dir), info); \
+    aty_st_le32(DST_Y_X, (((_dstx) << 16) | ((_dsty) & 0x0000ffff)), info); \
+    aty_st_le32(DST_HEIGHT_WIDTH, (((_w) << 16) | ((_h) & 0x0000ffff)), \
+		info); \
 }
 #endif /* REGMACH64_H */
 
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/atyfb.c m68k/drivers/video/atyfb.c
--- m68k-2.1.99/drivers/video/atyfb.c	Mon May  4 20:07:17 1998
+++ m68k/drivers/video/atyfb.c	Tue May  5 23:04:34 1998
@@ -1,7 +1,8 @@
 /*
- *  linux/drivers/video/atyfb.c -- Frame buffer device for ATI/Open Firmware
+ *  linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
  *
  *	Copyright (C) 1997 Geert Uytterhoeven
+ *	Copyright (C) 1998 Bernd Harries
  *
  *  This driver is partly based on the PowerMac console driver:
  *
@@ -20,6 +21,17 @@
  *  more details.
  */
 
+
+/******************************************************************************
+
+  TODO:
+
+    - support arbitrary video modes
+
+    - fix acceleration on PPC
+
+******************************************************************************/
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -36,10 +48,14 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/nvram.h>
+#ifdef CONFIG_FB_COMPAT_XPMAC
 #include <linux/vc_ioctl.h>
+#endif
 #include <asm/io.h>
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
 #include <asm/prom.h>
 #include <asm/pci-bridge.h>
+#endif
 
 #include "aty.h"
 #include "fbcon.h"
@@ -48,16 +64,23 @@
 #include "fbcon-cfb32.h"
 
 
+#ifndef __powerpc__
+#define eieio()		/* Enforce In-order Execution of I/O */
+#endif
+
 static int currcon = 0;
 static struct display fb_disp;
-static struct fb_info fb_info;
-static struct { u_char red, green, blue, pad; } palette[256];
 
 static char atyfb_name[16] = "ATY Mach64";
 
 struct atyfb_par {
-    int vmode;
-    int cmode;
+    union {
+	/* this should contain chipset specific mode information */
+	struct {
+	    int vmode;
+	    int cmode;
+	} gx, gt, vt;
+    } hw;
     u_int vxres;	/* virtual screen size */
     u_int vyres;
     int xoffset;	/* virtual screen position */
@@ -104,34 +127,31 @@
 #define CMODE_32		2	/* 32 (actually 24) bits/pixel */
 
 
-static int default_video_mode = VMODE_NVRAM;
-static int default_color_mode = CMODE_NVRAM;
+static int default_vmode = VMODE_NVRAM;
+static int default_cmode = CMODE_NVRAM;
 
 static struct atyfb_par default_par;
 static struct atyfb_par current_par;
 
 
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
 /*
  * Addresses in NVRAM where video mode and pixel size are stored.
  */
 #define NV_VMODE	0x140f
 #define NV_CMODE	0x1410
+#endif /* CONFIG_PMAC || CONFIG_CHRP */
+
 
 /*
- * Horizontal and vertical resolution information.
+ * Horizontal and vertical resolution for each mode.
  */
-extern struct vmode_attr {
+static struct vmode_attr {
 	int	hres;
 	int	vres;
 	int	vfreq;
 	int	interlaced;
-} vmode_attrs[VMODE_MAX];
-
-
-/*
- * Horizontal and vertical resolution for each mode.
- */
-static struct vmode_attr vmode_attrs[VMODE_MAX] = {
+} vmode_attrs[VMODE_MAX] = {
     {512, 384, 60, 1},
     {512, 384, 60},
     {640, 480, 50, 1},
@@ -198,44 +218,53 @@
 }
 
 struct aty_cmap_regs {
-    unsigned char windex;
-    unsigned char lut;
-    unsigned char mask;
-    unsigned char rindex;
-    unsigned char cntl;
+    u8 windex;
+    u8 lut;
+    u8 mask;
+    u8 rindex;
+    u8 cntl;
 };
 
 typedef struct aty_regvals {
-    int offset[3];		/* first pixel address */
+    u32 offset[3];		/* first pixel address */
 
-    int crtc_h_sync_strt_wid[3];	/* depth dependant */
-    int crtc_gen_cntl[3];
-    int mem_cntl[3];
-
-    int crtc_h_tot_disp;	/* mode dependant */
-    int crtc_v_tot_disp;
-    int crtc_v_sync_strt_wid;
-    int crtc_off_pitch;
+    u32 crtc_h_sync_strt_wid[3];	/* depth dependant */
+    u32 crtc_gen_cntl[3];
+    u32 mem_cntl[3];
+
+    u32 crtc_h_tot_disp;	/* mode dependant */
+    u32 crtc_v_tot_disp;
+    u32 crtc_v_sync_strt_wid;
+    u32 crtc_off_pitch;
 
-    unsigned char clock_val[2];	/* vals for 20 and 21 */
+    u8 clock_val[2];	/* vals for 20 and 21 */
 } aty_regvals;
 
 struct rage_regvals {
-    int h_total, h_sync_start, h_sync_width;
-    int v_total, v_sync_start, v_sync_width;
-    int h_sync_neg, v_sync_neg;
+    u32 h_total, h_sync_start, h_sync_width;
+    u32 v_total, v_sync_start, v_sync_width;
+    u32 h_sync_neg, v_sync_neg;
 };
 
-static int aty_vram_reqd(const struct atyfb_par *par);
-static struct aty_regvals *get_aty_struct(int vmode);
-
-static unsigned long frame_buffer;
+struct fb_info_aty {
+    struct fb_info fb_info;
+    unsigned long ati_regbase;
+    unsigned long frame_buffer;
+    u32 chip_type;
+    u32 total_vram;
+    struct aty_cmap_regs *aty_cmap_regs;
+    struct { u8 red, green, blue, pad; } palette[256];
+};
 
-static int total_vram;		/* total amount of video memory, bytes */
-static int chip_type;		/* what chip type was detected */
+#ifdef __mc68000__
+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
 
-static unsigned long ati_regbase;
-static struct aty_cmap_regs *aty_cmap_regs;
+static int aty_vram_reqd(const struct atyfb_par *par);
+static struct aty_regvals *get_aty_struct(int vmode, struct fb_info_aty *info);
 
 #include "ati-gx.h"
 #include "ati-gt.h"
@@ -298,6 +327,9 @@
      */
 
 unsigned long atyfb_init(unsigned long mem_start);
+#ifdef CONFIG_FB_OF
+void atyfb_of_init(struct device_node *dp);
+#endif
 void atyfb_setup(char *options, int *ints);
 
 static int atyfb_open(struct fb_info *info);
@@ -343,13 +375,19 @@
 extern int (*console_set_cmap_ptr)(struct fb_cmap *, int, int,
 				   struct fb_info *);
 static int atyfb_console_setmode(struct vc_mode *, int);
-#endif
+#endif /* CONFIG_FB_COMPAT_XPMAC */
 
 
     /*
      *  Internal routines
      */
 
+static int aty_init(struct fb_info_aty *info, const char *name);
+#ifndef CONFIG_FB_OF
+static int store_video_par(char *videopar, unsigned char m64_num);
+static char *strtoke(char *s, const char *ct);
+#endif
+
 static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
 			 u_int *transp, struct fb_info *info);
 static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
@@ -365,61 +403,104 @@
 
 static inline int aty_vram_reqd(const struct atyfb_par *par)
 {
-    return (par->vxres*par->vyres) << par->cmode;
+    return (par->vxres*par->vyres) << par->hw.gx.cmode;
 }
 
-extern inline unsigned aty_ld_le32(volatile unsigned long addr)
+static inline u32 aty_ld_le32(volatile unsigned int regindex,
+			      struct fb_info_aty *info)
 {
-    register unsigned long temp = ati_regbase,val;
+    unsigned long temp;
+    u32 val;
 
-    asm("lwbrx %0,%1,%2": "=r"(val):"r"(addr), "r"(temp));
+#ifdef __powerpc__
+    temp = info->ati_regbase;
+    asm("lwbrx %0,%1,%2": "=r"(val):"r"(regindex), "r"(temp));
+#else
+    temp = info->ati_regbase+regindex;
+    val = *((volatile u32 *)(temp));
+    val = (val>>16) | (val<<16);
+    val = ((val>>8) & 0x00ff00ff) | ((val<<8) & 0xff00ff00);
+#endif
     return val;
 }
 
-extern inline void aty_st_le32(volatile unsigned long addr, unsigned val)
+static inline void aty_st_le32(volatile unsigned int regindex, u32 val,
+			       struct fb_info_aty *info)
 {
-    register unsigned long temp = ati_regbase;
+    unsigned long temp;
+
+#ifdef __powerpc__
+    temp = info->ati_regbase;
+    asm("stwbrx %0,%1,%2": : "r"(val), "r"(regindex), "r"(temp):"memory");
+#else
+    temp = info->ati_regbase+regindex;
+    val = (val>>16) | (val<<16);
+    val = ((val>>8) & 0x00ff00ff) | ((val<<8) & 0xff00ff00);
+    *((volatile u32 *)(temp)) = val;
+#endif
+}
 
-    asm("stwbrx %0,%1,%2": : "r"(val), "r"(addr), "r"(temp):"memory");
+static inline u8 aty_ld_8(volatile unsigned int regindex,
+			  struct fb_info_aty *info)
+{
+    return *(volatile u8 *)(info->ati_regbase+regindex);
 }
 
-extern inline unsigned char aty_ld_8(volatile unsigned long addr)
+static inline void aty_st_8(volatile unsigned int regindex, u8 val,
+			    struct fb_info_aty *info)
 {
-    return *(char *) ((long) addr + (long) ati_regbase);
+    *(volatile u8 *)(info->ati_regbase+regindex) = val;
 }
 
-extern inline void aty_st_8(volatile unsigned long addr, unsigned char val)
+#ifdef __mc68000__
+static void bha_delay(int units)
 {
-    *(unsigned char *) (addr + (unsigned long) ati_regbase) = val;
+    unsigned int n;
+    unsigned int maxn;
+#if defined(__mc68000__)
+    maxn = 1000000;
+#else
+    maxn = 20000000;
+#endif
+
+    do {
+	for (n = 0; n < maxn; n++);
+	units--;
+    } while(units > 0);
 }
+#endif
 
-static void aty_st_514(int offset, char val)
+static void aty_st_514(int offset, u8 val, struct fb_info_aty *info)
 {
-    aty_WaitQueue(5);
-    aty_st_8(DAC_CNTL, 1);
-    aty_st_8(DAC_W_INDEX, offset & 0xff);	/* right addr byte */
-    aty_st_8(DAC_DATA, (offset >> 8) & 0xff);	/* left addr byte */
+    aty_WaitQueue(5, info);
+    aty_st_8(DAC_CNTL, 1, info);
+    /* right addr byte */
+    aty_st_8(DAC_W_INDEX, offset & 0xff, info);	
+    /* left addr byte */
+    aty_st_8(DAC_DATA, (offset >> 8) & 0xff, info);
     eieio();
-    aty_st_8(DAC_MASK, val);
+    aty_st_8(DAC_MASK, val, info);
     eieio();
-    aty_st_8(DAC_CNTL, 0);
+    aty_st_8(DAC_CNTL, 0, info);
 }
 
-static void aty_st_pll(int offset, char val)
+static void aty_st_pll(int offset, u8 val, struct fb_info_aty *info)
 {
-    aty_WaitQueue(3);
-    aty_st_8(CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN);	/* write addr byte */
+    aty_WaitQueue(3, info);
+    /* write addr byte */
+    aty_st_8(CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN, info);
     eieio();
-    aty_st_8(CLOCK_CNTL + 2, val);	/* write the register value */
+    /* write the register value */
+    aty_st_8(CLOCK_CNTL + 2, val, info);
     eieio();
-    aty_st_8(CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN);
+    aty_st_8(CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN, info);
 }
 
-static struct aty_regvals *get_aty_struct(int vmode)
+static struct aty_regvals *get_aty_struct(int vmode, struct fb_info_aty *info)
 {
     int v = vmode - 1;
 
-    switch (chip_type) {
+    switch (info->chip_type) {
 	case MACH64_GT_ID:
 	    return aty_gt_reg_init[v];
 	    break;
@@ -432,48 +513,48 @@
     }
 }
 
-static int read_aty_sense(void)
+static int read_aty_sense(struct fb_info_aty *info)
 {
     int sense, i;
 
-    aty_st_le32(GP_IO, 0x31003100);	/* drive outputs high */
+    aty_st_le32(GP_IO, 0x31003100, info);	/* drive outputs high */
     __delay(200);
-    aty_st_le32(GP_IO, 0);		/* turn off outputs */
+    aty_st_le32(GP_IO, 0, info);		/* turn off outputs */
     __delay(2000);
-    i = aty_ld_le32(GP_IO);		/* get primary sense value */
+    i = aty_ld_le32(GP_IO, info);		/* 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);	/* drive A low */
+    aty_st_le32(GP_IO, 0x20000000, info);	/* drive A low */
     __delay(2000);
-    i = aty_ld_le32(GP_IO);
+    i = aty_ld_le32(GP_IO, info);
     sense |= ((i & 0x1000) >> 7) | ((i & 0x100) >> 4);
-    aty_st_le32(GP_IO, 0x20002000);	/* drive A high again */
+    aty_st_le32(GP_IO, 0x20002000, info);	/* drive A high again */
     __delay(200);
 
-    aty_st_le32(GP_IO, 0x10000000);	/* drive B low */
+    aty_st_le32(GP_IO, 0x10000000, info);	/* drive B low */
     __delay(2000);
-    i = aty_ld_le32(GP_IO);
+    i = aty_ld_le32(GP_IO, info);
     sense |= ((i & 0x2000) >> 10) | ((i & 0x100) >> 6);
-    aty_st_le32(GP_IO, 0x10001000);	/* drive B high again */
+    aty_st_le32(GP_IO, 0x10001000, info);	/* drive B high again */
     __delay(200);
 
-    aty_st_le32(GP_IO, 0x01000000);	/* drive C low */
+    aty_st_le32(GP_IO, 0x01000000, info);	/* drive C low */
     __delay(2000);
-    sense |= (aty_ld_le32(GP_IO) & 0x3000) >> 12;
-    aty_st_le32(GP_IO, 0);		/* turn off outputs */
+    sense |= (aty_ld_le32(GP_IO, info) & 0x3000) >> 12;
+    aty_st_le32(GP_IO, 0, info);		/* turn off outputs */
 
     return sense;
 }
 
-static void RGB514_Program(int cmode)
+static void RGB514_Program(int cmode, struct fb_info_aty *info)
 {
     typedef struct {
-	char pixel_dly;
-	char misc2_cntl;
-	char pixel_rep;
-	char pixel_cntl_index;
-	char pixel_cntl_v1;
+	u8 pixel_dly;
+	u8 misc2_cntl;
+	u8 pixel_rep;
+	u8 pixel_cntl_index;
+	u8 pixel_cntl_v1;
     } RGB514_DAC_Table;
 
     static RGB514_DAC_Table RGB514DAC_Tab[8] = {
@@ -485,211 +566,246 @@
 
     pDacProgTab = &RGB514DAC_Tab[cmode];
 
-    aty_st_514(0x90, 0x00);
-    aty_st_514(0x04, pDacProgTab->pixel_dly);
-    aty_st_514(0x05, 0x00);
+    aty_st_514(0x90, 0x00, info);
+    aty_st_514(0x04, pDacProgTab->pixel_dly, info);
+    aty_st_514(0x05, 0x00, info);
 
-    aty_st_514(0x2, 0x1);
-    aty_st_514(0x71, pDacProgTab->misc2_cntl);
-    aty_st_514(0x0a, pDacProgTab->pixel_rep);
+    aty_st_514(0x2, 0x1, info);
+    aty_st_514(0x71, pDacProgTab->misc2_cntl, info);
+    aty_st_514(0x0a, pDacProgTab->pixel_rep, info);
 
-    aty_st_514(pDacProgTab->pixel_cntl_index, pDacProgTab->pixel_cntl_v1);
+    aty_st_514(pDacProgTab->pixel_cntl_index, pDacProgTab->pixel_cntl_v1,
+	       info);
 }
 
-static void set_off_pitch(const struct atyfb_par *par)
+static void set_off_pitch(const struct atyfb_par *par,
+			  struct fb_info_aty *info)
 {
     u32 pitch, offset;
 
     pitch = par->vxres>>3;
-    offset = ((par->yoffset*par->vxres+par->xoffset)>>3)<<par->cmode;
-    aty_st_le32(CRTC_OFF_PITCH, pitch<<22 | offset);
-    if (chip_type == MACH64_GT_ID) {
+    offset = ((par->yoffset*par->vxres+par->xoffset)>>3)<<par->hw.gx.cmode;
+    aty_st_le32(CRTC_OFF_PITCH, pitch<<22 | offset, info);
+    if (1 /* info->chip_type == MACH64_GT_ID */) {
 	/* Is this OK for other chips? */
-	aty_st_le32(DST_OFF_PITCH, pitch<<22 | offset);
-	aty_st_le32(SRC_OFF_PITCH, pitch<<22 | offset);
+	aty_WaitQueue(13, info);
+	aty_st_le32(DST_OFF_PITCH, pitch<<22 | offset, info);
+	aty_st_le32(SRC_OFF_PITCH, pitch<<22 | offset, info);
+	aty_st_le32(SC_LEFT_RIGHT, (par->vxres -1) << 16, info);
+	aty_st_le32(SC_TOP_BOTTOM, (par->vyres -1) << 16, info);
+
+	/* Caution: This is valid for 8 bpp only!!!! */
+
+	aty_st_le32(DP_BKGD_CLR, 0x00000000, info);
+	aty_st_le32(DP_FRGD_CLR, 0x00000001, info);
+
+	aty_st_le32(DP_WRITE_MSK, 0x000000ff /* pGC->planemask */, info);
+	aty_st_le32(DP_PIX_WIDTH, BYTE_ORDER_MSB_TO_LSB | HOST_8BPP |
+				  SRC_8BPP | DST_8BPP,
+		    info);
+	aty_st_le32(DP_MIX, FRGD_MIX_S | BKGD_MIX_D, info);
+	aty_st_le32(DP_SRC, FRGD_SRC_BLIT | BKGD_SRC_BKGD_CLR, info);
+
+	aty_st_le32(CLR_CMP_CNTL, 0x00000000, info);
+	aty_st_le32(CLR_CMP_CLR, 0x00000000, info);
+
+	aty_st_le32(GUI_TRAJ_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM,
+		    info);
     }
 }
 
-static void atyfb_set_par(struct atyfb_par *par)
+static void atyfb_set_par(struct atyfb_par *par, struct fb_info_aty *info)
 {
     int i, hres;
-    struct aty_regvals *init = get_aty_struct(par->vmode);
-    int vram_type = aty_ld_le32(CONFIG_STAT0) & 7;
+    struct aty_regvals *init = get_aty_struct(par->hw.gx.vmode, info);
+    int vram_type = aty_ld_le32(CONFIG_STAT0, info) & 7;
+
+#ifdef __mc68000__
+    bha_delay(3);
+#endif
 
     if (init == 0)	/* paranoia, shouldn't get here */
-	panic("aty: display mode %d not supported", par->vmode);
+	panic("aty: display mode %d not supported", par->hw.gx.vmode);
 
     current_par = *par;
-    hres = vmode_attrs[par->vmode-1].hres;
+    hres = vmode_attrs[par->hw.gx.vmode-1].hres;
 
     /* clear FIFO errors */
-    aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL) | BUS_HOST_ERR_ACK
-			  | BUS_FIFO_ERR_ACK);
+    aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL, info) | BUS_HOST_ERR_ACK
+			  | BUS_FIFO_ERR_ACK, info);
 
     /* Reset engine */
-    i = aty_ld_le32(GEN_TEST_CNTL);
-    aty_st_le32(GEN_TEST_CNTL, i & ~GUI_ENGINE_ENABLE);
+    i = aty_ld_le32(GEN_TEST_CNTL, info);
+    aty_st_le32(GEN_TEST_CNTL, i & ~GUI_ENGINE_ENABLE, info);
     eieio();
-    aty_WaitIdleEmpty();
-    aty_st_le32(GEN_TEST_CNTL, i | GUI_ENGINE_ENABLE);
-    aty_WaitIdleEmpty();
+    aty_WaitIdleEmpty(info);
+    aty_st_le32(GEN_TEST_CNTL, i | GUI_ENGINE_ENABLE, info);
+    aty_WaitIdleEmpty(info);
 
-    if ( chip_type != MACH64_GT_ID ) {
-	i = aty_ld_le32(CRTC_GEN_CNTL);
-	aty_st_le32(CRTC_GEN_CNTL, i | CRTC_EXT_DISP_EN);
+    if (info->chip_type != MACH64_GT_ID) {
+	i = aty_ld_le32(CRTC_GEN_CNTL, info);
+	aty_st_le32(CRTC_GEN_CNTL, i | CRTC_EXT_DISP_EN, info);
     }
 
-    if ( chip_type == MACH64_GX_ID ) {
-	i = aty_ld_le32(GEN_TEST_CNTL);
-	aty_st_le32(GEN_TEST_CNTL, i | GEN_OVR_OUTPUT_EN );
+    if (info->chip_type == MACH64_GX_ID) {
+	i = aty_ld_le32(GEN_TEST_CNTL, info);
+	aty_st_le32(GEN_TEST_CNTL, i | GEN_OVR_OUTPUT_EN, info);
     }
 
-    switch (chip_type) {
+    switch (info->chip_type) {
 	case MACH64_VT_ID:
-	    aty_st_pll(PLL_MACRO_CNTL, 0xb5);
-	    aty_st_pll(PLL_REF_DIV, 0x2d);
-	    aty_st_pll(PLL_GEN_CNTL, 0x14);
-	    aty_st_pll(MCLK_FB_DIV, 0xbd);
-	    aty_st_pll(PLL_VCLK_CNTL, 0x0b);
-	    aty_st_pll(VCLK_POST_DIV, init->clock_val[0]);
-	    aty_st_pll(VCLK0_FB_DIV, init->clock_val[1]);
-	    aty_st_pll(VCLK1_FB_DIV, 0xd6);
-	    aty_st_pll(VCLK2_FB_DIV, 0xee);
-	    aty_st_pll(VCLK3_FB_DIV, 0xf8);
-	    aty_st_pll(PLL_XCLK_CNTL, 0x0);
-	    aty_st_pll(PLL_TEST_CTRL, 0x0);
-	    aty_st_pll(PLL_TEST_COUNT, 0x0);
+	    aty_st_pll(VPLL_CNTL, 0xb5, info);
+	    aty_st_pll(PLL_REF_DIV, 0x2d, info);
+	    aty_st_pll(PLL_GEN_CNTL, 0x14, info);
+	    aty_st_pll(MCLK_FB_DIV, 0xbd, info);
+	    aty_st_pll(PLL_VCLK_CNTL, 0x0b, info);
+	    aty_st_pll(VCLK_POST_DIV, init->clock_val[0], info);
+	    aty_st_pll(VCLK0_FB_DIV, init->clock_val[1], info);
+	    aty_st_pll(VCLK1_FB_DIV, 0xd6, info);
+	    aty_st_pll(VCLK2_FB_DIV, 0xee, info);
+	    aty_st_pll(VCLK3_FB_DIV, 0xf8, info);
+	    aty_st_pll(PLL_EXT_CNTL, 0x0, info);
+	    aty_st_pll(PLL_TEST_CTRL, 0x0, info);
+	    aty_st_pll(PLL_TEST_COUNT, 0x0, info);
 	    break;
 	case MACH64_GT_ID:
 	    if (vram_type == 5) {
-		aty_st_pll(0, 0xcd);
-		aty_st_pll(PLL_MACRO_CNTL,
-			   par->vmode >= VMODE_1024_768_60 ? 0xd3: 0xd5);
-		aty_st_pll(PLL_REF_DIV, 0x21);
-		aty_st_pll(PLL_GEN_CNTL, 0x44);
-		aty_st_pll(MCLK_FB_DIV, 0xe8);
-		aty_st_pll(PLL_VCLK_CNTL, 0x03);
-		aty_st_pll(VCLK_POST_DIV, init->offset[0]);
-		aty_st_pll(VCLK0_FB_DIV, init->offset[1]);
-		aty_st_pll(VCLK1_FB_DIV, 0x8e);
-		aty_st_pll(VCLK2_FB_DIV, 0x9e);
-		aty_st_pll(VCLK3_FB_DIV, 0xc6);
-		aty_st_pll(PLL_XCLK_CNTL, init->offset[2]);
-		aty_st_pll(12, 0xa6);
-		aty_st_pll(13, 0x1b);
+		aty_st_pll(MPLL_CNTL, 0xcd, info);
+		aty_st_pll(VPLL_CNTL,
+			   par->hw.gx.vmode >= VMODE_1024_768_60 ? 0xd3
+								 : 0xd5,
+			   info);
+		aty_st_pll(PLL_REF_DIV, 0x21, info);
+		aty_st_pll(PLL_GEN_CNTL, 0x44, info);
+		aty_st_pll(MCLK_FB_DIV, 0xe8, info);
+		aty_st_pll(PLL_VCLK_CNTL, 0x03, info);
+		aty_st_pll(VCLK_POST_DIV, init->offset[0], info);
+		aty_st_pll(VCLK0_FB_DIV, init->offset[1], info);
+		aty_st_pll(VCLK1_FB_DIV, 0x8e, info);
+		aty_st_pll(VCLK2_FB_DIV, 0x9e, info);
+		aty_st_pll(VCLK3_FB_DIV, 0xc6, info);
+		aty_st_pll(PLL_EXT_CNTL, init->offset[2], info);
+		aty_st_pll(DLL_CNTL, 0xa6, info);
+		aty_st_pll(VFC_CNTL, 0x1b, info);
 	    } else {
-		aty_st_pll(PLL_MACRO_CNTL, 0xd5);
-		aty_st_pll(PLL_REF_DIV, 0x21);
-		aty_st_pll(PLL_GEN_CNTL, 0xc4);
-		aty_st_pll(MCLK_FB_DIV, 0xda);
-		aty_st_pll(PLL_VCLK_CNTL, 0x03);
+		aty_st_pll(VPLL_CNTL, 0xd5, info);
+		aty_st_pll(PLL_REF_DIV, 0x21, info);
+		aty_st_pll(PLL_GEN_CNTL, 0xc4, info);
+		aty_st_pll(MCLK_FB_DIV, 0xda, info);
+		aty_st_pll(PLL_VCLK_CNTL, 0x03, info);
 		/* offset actually holds clock values */
-		aty_st_pll(VCLK_POST_DIV, init->offset[0]);
-		aty_st_pll(VCLK0_FB_DIV, init->offset[1]);
-		aty_st_pll(VCLK1_FB_DIV, 0x8e);
-		aty_st_pll(VCLK2_FB_DIV, 0x9e);
-		aty_st_pll(VCLK3_FB_DIV, 0xc6);
-		aty_st_pll(PLL_TEST_CTRL, 0x0);
-		aty_st_pll(PLL_XCLK_CNTL, init->offset[2]);
-		aty_st_pll(12, 0xa0);
-		aty_st_pll(13, 0x1b);
+		aty_st_pll(VCLK_POST_DIV, init->offset[0], info);
+		aty_st_pll(VCLK0_FB_DIV, init->offset[1], info);
+		aty_st_pll(VCLK1_FB_DIV, 0x8e, info);
+		aty_st_pll(VCLK2_FB_DIV, 0x9e, info);
+		aty_st_pll(VCLK3_FB_DIV, 0xc6, info);
+		aty_st_pll(PLL_TEST_CTRL, 0x0, info);
+		aty_st_pll(PLL_EXT_CNTL, init->offset[2], info);
+		aty_st_pll(DLL_CNTL, 0xa0, info);
+		aty_st_pll(VFC_CNTL, 0x1b, info);
 	    }
 	    break;
 	default:
-	    RGB514_Program(par->cmode);
-	    aty_WaitIdleEmpty();
-	    aty_st_514(0x06, 0x02);
-	    aty_st_514(0x10, 0x01);
-	    aty_st_514(0x70, 0x01);
-	    aty_st_514(0x8f, 0x1f);
-	    aty_st_514(0x03, 0x00);
-	    aty_st_514(0x05, 0x00);
-	    aty_st_514(0x20, init->clock_val[0]);
-	    aty_st_514(0x21, init->clock_val[1]);
+	    RGB514_Program(par->hw.gx.cmode, info);
+	    aty_WaitIdleEmpty(info);
+	    aty_st_514(0x06, 0x02, info);
+	    aty_st_514(0x10, 0x01, info);
+	    aty_st_514(0x70, 0x01, info);
+	    aty_st_514(0x8f, 0x1f, info);
+	    aty_st_514(0x03, 0x00, info);
+	    aty_st_514(0x05, 0x00, info);
+	    aty_st_514(0x20, init->clock_val[0], info);
+	    aty_st_514(0x21, init->clock_val[1], info);
 	    break;
     }
 
-    aty_ld_8(DAC_REGS);	/* clear counter */
-    aty_WaitIdleEmpty();
+    aty_ld_8(DAC_REGS, info);	/* clear counter */
+    aty_WaitIdleEmpty(info);
 
-    aty_st_le32(CRTC_H_TOTAL_DISP, init->crtc_h_tot_disp);
-    aty_st_le32(CRTC_H_SYNC_STRT_WID, init->crtc_h_sync_strt_wid[par->cmode]);
-    aty_st_le32(CRTC_V_TOTAL_DISP, init->crtc_v_tot_disp);
-    aty_st_le32(CRTC_V_SYNC_STRT_WID, init->crtc_v_sync_strt_wid);
+    aty_st_le32(CRTC_H_TOTAL_DISP, init->crtc_h_tot_disp, info);
+    aty_st_le32(CRTC_H_SYNC_STRT_WID,
+		init->crtc_h_sync_strt_wid[par->hw.gx.cmode], info);
+    aty_st_le32(CRTC_V_TOTAL_DISP, init->crtc_v_tot_disp, info);
+    aty_st_le32(CRTC_V_SYNC_STRT_WID, init->crtc_v_sync_strt_wid, info);
 
-    aty_st_8(CLOCK_CNTL, 0);
-    aty_st_8(CLOCK_CNTL, CLOCK_STROBE);
+    aty_st_8(CLOCK_CNTL, 0, info);
+    aty_st_8(CLOCK_CNTL, CLOCK_STROBE, info);
 
-    aty_st_le32(CRTC_VLINE_CRNT_VLINE, 0);
+    aty_st_le32(CRTC_VLINE_CRNT_VLINE, 0, info);
 
-    set_off_pitch(par);
+    set_off_pitch(par, info);
 
-    if (chip_type == MACH64_GT_ID) {
-	aty_st_le32(BUS_CNTL, 0x7b23a040);
+    if (info->chip_type == MACH64_GT_ID) {
+	aty_st_le32(BUS_CNTL, 0x7b23a040, info);
 
 	/* need to set DSP values !! assume sdram */
-	i = init->crtc_gen_cntl[0] - (0x100000 * par->cmode);
+	i = init->crtc_gen_cntl[0] - (0x100000 * par->hw.gx.cmode);
 	if ( vram_type == 5 )
-	    i = init->crtc_gen_cntl[1] - (0x100000 * par->cmode);
-	aty_st_le32(DSP_CONFIG, i);
+	    i = init->crtc_gen_cntl[1] - (0x100000 * par->hw.gx.cmode);
+	aty_st_le32(DSP_CONFIG, i, info);
 
-	i = aty_ld_le32(MEM_CNTL) & MEM_SIZE_ALIAS;
+	i = aty_ld_le32(MEM_CNTL, info) & MEM_SIZE_ALIAS;
 	if ( vram_type == 5 ) {
-	    i |= ((1 * par->cmode) << 26) | 0x4215b0;
-	    aty_st_le32(DSP_ON_OFF,sgram_dsp[par->vmode-1][par->cmode]);
+	    i |= ((1 * par->hw.gx.cmode) << 26) | 0x4215b0;
+	    aty_st_le32(DSP_ON_OFF,
+			sgram_dsp[par->hw.gx.vmode-1][par->hw.gx.cmode], info);
 
-	//aty_st_le32(CLOCK_CNTL,8192);
+	//aty_st_le32(CLOCK_CNTL,8192, info);
 	} else {
-	    i |= ((1 * par->cmode) << 26) | 0x300090;
-	    aty_st_le32(DSP_ON_OFF, init->mem_cntl[par->cmode]);
+	    i |= ((1 * par->hw.gx.cmode) << 26) | 0x300090;
+	    aty_st_le32(DSP_ON_OFF, init->mem_cntl[par->hw.gx.cmode], info);
 	}
 
-	aty_st_le32(MEM_CNTL, i);
-	aty_st_le32(EXT_MEM_CNTL, 0x5000001);
+	aty_st_le32(MEM_CNTL, i, info);
+	aty_st_le32(EXT_MEM_CNTL, 0x5000001, info);
 
-	/* if (total_vram > 0x400000)	
+	/* if (info->total_vram > 0x400000)	
 	    i |= 0x538; this not been verified on > 4Megs!! */
-    } else {
-
-/* The magic constant below translates into:
-* 5   = No RDY delay, 1 wait st for mem write, increment during burst transfer
-* 9   = DAC access delayed, 1 wait state for DAC
-* 0   = Disables interupts for FIFO errors
-* e   = Allows FIFO to generate 14 wait states before generating error
-* 1   = DAC snooping disabled, ROM disabled
-* 0   = ROM page at 0 (disabled so doesn't matter)
-* f   = 15 ROM wait states (disabled so doesn't matter)
-* f   = 15 BUS wait states (I'm not sure this applies to PCI bus types)
-* at some point it would be good to experiment with bench marks to see if
-* we can gain some speed by fooling with the wait states etc.
-*/
-	if (chip_type == MACH64_VT_ID)
-	    aty_st_le32(BUS_CNTL, 0x680000f9);
-	else
-	    aty_st_le32(BUS_CNTL, 0x590e10ff);
-
-	switch (total_vram) {
+    } else if (info->chip_type == MACH64_VT_ID) {
+	aty_st_le32(BUS_CNTL, 0x680000f9, info);
+	switch (info->total_vram) {
 	    case 0x00100000:
-		aty_st_le32(MEM_CNTL, vt_mem_cntl[0][par->cmode]);
+		aty_st_le32(MEM_CNTL, vt_mem_cntl[0][par->hw.gx.cmode],
+			    info);
 		break;
 	    case 0x00200000:
-		aty_st_le32(MEM_CNTL, vt_mem_cntl[1][par->cmode]);
+		aty_st_le32(MEM_CNTL, vt_mem_cntl[1][par->hw.gx.cmode],
+			    info);
 		break;
 	    case 0x00400000:
-		aty_st_le32(MEM_CNTL, vt_mem_cntl[2][par->cmode]);
+		aty_st_le32(MEM_CNTL, vt_mem_cntl[2][par->hw.gx.cmode],
+			    info);
 		break;
 	    default:
-		i = aty_ld_le32(MEM_CNTL) & 0x000F;
+		i = aty_ld_le32(MEM_CNTL, info) & 0x000F;
 		aty_st_le32(MEM_CNTL,
-			    (init->mem_cntl[par->cmode] & 0xFFFFFFF0) | i);
+			    (init->mem_cntl[par->hw.gx.cmode] &
+			     0xFFFFFFF0) | i,
+			    info);
 	}
+    } else /* not GT/VT => GX */ {
+	/* The magic constant below translates into:
+	 * 5  = No RDY delay, 1 wait st for mem write, increment during burst
+	 *	transfer
+	 * 9  = DAC access delayed, 1 wait state for DAC
+	 * 0  = Disables interupts for FIFO errors
+	 * e  = Allows FIFO to generate 14 wait states before generating error
+	 * 1  = DAC snooping disabled, ROM disabled
+	 * 0  = ROM page at 0 (disabled so doesn't matter)
+	 * f  = 15 ROM wait states (disabled so doesn't matter)
+	 * f  = 15 BUS wait states (I'm not sure this applies to PCI bus types)
+	 * at some point it would be good to experiment with bench marks to see
+	 * if we can gain some speed by fooling with the wait states etc.
+	 */
+	aty_st_le32(BUS_CNTL, 0x890e20f1 /* 0x590e10ff */, info);
     }
+
 /* These magic constants are harder to figure out
 * on the vt chipset bit 2 set makes the screen brighter
 * and bit 15 makes the screen black! But nothing else
 * seems to matter for the vt DAC_CNTL
 */
-    switch (chip_type) {
+    switch (info->chip_type) {
 	case MACH64_GT_ID:
 	    i = 0x86010102;
 	    break;
@@ -698,13 +814,14 @@
 	    break;
 	default:
 	    i = 0x47012100;
+	    i = 0x47052100;
 	    break;
     }
 
-    aty_st_le32(DAC_CNTL, i);
-    aty_st_8(DAC_MASK, 0xff);
+    aty_st_le32(DAC_CNTL, i, info);
+    aty_st_8(DAC_MASK, 0xff, info);
 
-    switch (par->cmode) {
+    switch (par->hw.gx.cmode) {
 	case CMODE_16:
 	    i = CRTC_PIX_WIDTH_15BPP; break;
 	/*case CMODE_24: */
@@ -715,30 +832,31 @@
 	    i = CRTC_PIX_WIDTH_8BPP; break;
     }
 
-    if (chip_type != MACH64_GT_ID) {
-	aty_st_le32(CRTC_INT_CNTL, 0x00000002);
-	aty_st_le32(GEN_TEST_CNTL, GUI_ENGINE_ENABLE | BLOCK_WRITE_ENABLE);	/* gui_en block_en */
-	i |= init->crtc_gen_cntl[par->cmode];
+    if (info->chip_type != MACH64_GT_ID) {
+	aty_st_le32(CRTC_INT_CNTL, 0x00000002, info);
+	aty_st_le32(GEN_TEST_CNTL, GUI_ENGINE_ENABLE | BLOCK_WRITE_ENABLE,
+		    info);	/* gui_en block_en */
+	i |= init->crtc_gen_cntl[par->hw.gx.cmode];
     }
     /* Gentlemen, start your crtc engine */
-    aty_st_le32(CRTC_GEN_CNTL, CRTC_EXT_DISP_EN | CRTC_ENABLE | i);
+    aty_st_le32(CRTC_GEN_CNTL, CRTC_EXT_DISP_EN | CRTC_ENABLE | i, info);
 
 #ifdef CONFIG_FB_COMPAT_XPMAC
-    if (console_fb_info == &fb_info) {
-	display_info.height = vmode_attrs[par->vmode-1].vres;
-	display_info.width = vmode_attrs[par->vmode-1].hres;
-	display_info.depth = 8<<par->cmode;
-	display_info.pitch = par->vxres<<par->cmode;
-	display_info.mode = par->vmode;
+    if (console_fb_info == &info->fb_info) {
+	display_info.height = vmode_attrs[par->hw.gx.vmode-1].vres;
+	display_info.width = vmode_attrs[par->hw.gx.vmode-1].hres;
+	display_info.depth = 8<<par->hw.gx.cmode;
+	display_info.pitch = par->vxres<<par->hw.gx.cmode;
+	display_info.mode = par->hw.gx.vmode;
 	strcpy(display_info.name, atyfb_name);
-	display_info.fb_address =
-	    iopa(((chip_type != MACH64_GT_ID) ?
-		 frame_buffer + init->offset[par->cmode] : frame_buffer));
-	display_info.cmap_adr_address = iopa((unsigned long)&aty_cmap_regs->windex);
-	display_info.cmap_data_address = iopa((unsigned long)&aty_cmap_regs->lut);
-	display_info.disp_reg_address = iopa(ati_regbase);
+	display_info.fb_address = info->frame_buffer;
+	if (info->chip_type == MACH64_VT_ID)
+	    display_info.fb_address += init->offset[par->hw.gx.cmode];
+	display_info.cmap_adr_address = iopa(info->aty_cmap_regs->windex);
+	display_info.cmap_data_address = iopa(info->aty_cmap_regs->lut);
+	display_info.disp_reg_address = iopa(info->ati_regbase);
     }
-#endif /* CONFIG_FB_COMPAT_XPMAC) */
+#endif /* CONFIG_FB_COMPAT_XPMAC */
 }
 
 
@@ -765,30 +883,43 @@
 
 
 static int encode_fix(struct fb_fix_screeninfo *fix,
-		      const struct atyfb_par *par)
+		      const struct atyfb_par *par, struct fb_info_aty *info)
 {
     struct aty_regvals *init;
 
     memset(fix, 0, sizeof(struct fb_fix_screeninfo));
 
     strcpy(fix->id, atyfb_name);
-    init = get_aty_struct(par->vmode);
+    init = get_aty_struct(par->hw.gx.vmode, info);
     /*
      *  FIXME: This will cause problems on non-GT chips, because the frame
      *  buffer must be aligned to a page
      */
-    fix->smem_start = (char *)((chip_type != MACH64_GT_ID)
-	    ? frame_buffer + init->offset[par->cmode] : frame_buffer);
-    fix->smem_len = (u32)total_vram;
-    if (fix->smem_len > 0x7ff000)
-	fix->smem_len = 0x7ff000;	/* last page is MMIO */
-    fix->mmio_start = (char *)(ati_regbase & ~0xfff);
-    fix->mmio_len = 4096;
+    fix->smem_start = (char *)info->frame_buffer;
+    if (info->chip_type == MACH64_VT_ID)
+	fix->smem_start += init->offset[par->hw.gx.cmode];
+    fix->smem_len = (u32)info->total_vram;
+
+#ifdef __LITTLE_ENDIAN
+    /*
+     *  Last page of 8 MB little-endian aperture is MMIO
+     *  FIXME: we should use the auxillary aperture instead so we can acces the
+     *  full 8 MB of video RAM on 8 MB boards
+     */
+    if (fix->smem_len > 0x800000-PAGE_SIZE)
+	fix->smem_len = 0x800000-PAGE_SIZE;
+#endif
+    /*
+     *  Reg Block 0 (CT-compatible block) is at ati_regbase
+     *  Reg Block 1 (multimedia extensions) is at ati_regbase-0x400
+     */
+    fix->mmio_start = (char *)(info->ati_regbase-0x400);
+    fix->mmio_len = 0x800;
     fix->type = FB_TYPE_PACKED_PIXELS;
     fix->type_aux = 0;
-    fix->line_length = par->vxres<<par->cmode;
-    fix->visual = par->cmode == CMODE_8 ? FB_VISUAL_PSEUDOCOLOR
-					: FB_VISUAL_TRUECOLOR;
+    fix->line_length = par->vxres<<par->hw.gx.cmode;
+    fix->visual = par->hw.gx.cmode == CMODE_8 ? FB_VISUAL_PSEUDOCOLOR
+					      : FB_VISUAL_TRUECOLOR;
     fix->ywrapstep = 0;
     fix->xpanstep = 8;
     fix->ypanstep = 1;
@@ -799,7 +930,7 @@
 
 
 static int decode_var(struct fb_var_screeninfo *var,
-		      struct atyfb_par *par)
+		      struct atyfb_par *par, struct fb_info_aty *info)
 {
     int xres = var->xres;
     int yres = var->yres;
@@ -809,30 +940,30 @@
     /* This should support more video modes */
 
     if (xres <= 512 && yres <= 384)
-	par->vmode = VMODE_512_384_60;		/* 512x384, 60Hz */
+	par->hw.gx.vmode = VMODE_512_384_60;	/* 512x384, 60Hz */
     else if (xres <= 640 && yres <= 480)
-	par->vmode = VMODE_640_480_67;		/* 640x480, 67Hz */
+	par->hw.gx.vmode = VMODE_640_480_67;	/* 640x480, 67Hz */
     else if (xres <= 640 && yres <= 870)
-	par->vmode = VMODE_640_870_75P;		/* 640x870, 75Hz (portrait) */
+	par->hw.gx.vmode = VMODE_640_870_75P;	/* 640x870, 75Hz (portrait) */
     else if (xres <= 768 && yres <= 576)
-	par->vmode = VMODE_768_576_50I;		/* 768x576, 50Hz (PAL full frame) */
+	par->hw.gx.vmode = VMODE_768_576_50I;	/* 768x576, 50Hz (PAL full frame) */
     else if (xres <= 800 && yres <= 600)
-	par->vmode = VMODE_800_600_75;		/* 800x600, 75Hz */
+	par->hw.gx.vmode = VMODE_800_600_75;	/* 800x600, 75Hz */
     else if (xres <= 832 && yres <= 624)
-	par->vmode = VMODE_832_624_75;		/* 832x624, 75Hz */
+	par->hw.gx.vmode = VMODE_832_624_75;	/* 832x624, 75Hz */
     else if (xres <= 1024 && yres <= 768)
-	par->vmode = VMODE_1024_768_75;		/* 1024x768, 75Hz */
+	par->hw.gx.vmode = VMODE_1024_768_75;	/* 1024x768, 75Hz */
     else if (xres <= 1152 && yres <= 870)
-	par->vmode = VMODE_1152_870_75;		/* 1152x870, 75Hz */
+	par->hw.gx.vmode = VMODE_1152_870_75;	/* 1152x870, 75Hz */
     else if (xres <= 1280 && yres <= 960)
-	par->vmode = VMODE_1280_960_75;		/* 1280x960, 75Hz */
+	par->hw.gx.vmode = VMODE_1280_960_75;	/* 1280x960, 75Hz */
     else if (xres <= 1280 && yres <= 1024)
-	par->vmode = VMODE_1280_1024_75;	/* 1280x1024, 75Hz */
+	par->hw.gx.vmode = VMODE_1280_1024_75;	/* 1280x1024, 75Hz */
     else
 	return -EINVAL;
 
-    xres = vmode_attrs[par->vmode-1].hres;
-    yres = vmode_attrs[par->vmode-1].vres;
+    xres = vmode_attrs[par->hw.gx.vmode-1].hres;
+    yres = vmode_attrs[par->hw.gx.vmode-1].vres;
 
     if (var->xres_virtual <= xres)
 	par->vxres = xres;
@@ -849,29 +980,30 @@
 	return -EINVAL;
 
     if (bpp <= 8) {
-	par->cmode = CMODE_8;
+	par->hw.gx.cmode = CMODE_8;
 	if (var->accel_flags & FB_ACCELF_TEXT)
 	    par->accel = FB_ACCELF_TEXT;
 	else
 	    par->accel = 0;
     } else if (bpp <= 16) {
-	par->cmode = CMODE_16;
+	par->hw.gx.cmode = CMODE_16;
 	par->accel = 0;
     } else if (bpp <= 32) {
-	par->cmode = CMODE_32;
+	par->hw.gx.cmode = CMODE_32;
 	par->accel = 0;
     } else
 	return -EINVAL;
 
-    if (aty_vram_reqd(par) > total_vram)
+    if (aty_vram_reqd(par) > info->total_vram)
 	return -EINVAL;
 
     /* Check if we know about the wanted video mode */
-    init = get_aty_struct(par->vmode);
-    if (init == NULL || init->crtc_h_sync_strt_wid[par->cmode] == 0 ||
-	(chip_type != MACH64_GT_ID &&
-	 init->crtc_gen_cntl[par->cmode] == 0) ||
-	(chip_type == MACH64_GT_ID && (aty_ld_le32(CONFIG_STAT0) & 7) == 5 &&
+    init = get_aty_struct(par->hw.gx.vmode, info);
+    if (init == NULL || init->crtc_h_sync_strt_wid[par->hw.gx.cmode] == 0 ||
+	(info->chip_type != MACH64_GT_ID &&
+	 init->crtc_gen_cntl[par->hw.gx.cmode] == 0) ||
+	(info->chip_type == MACH64_GT_ID &&
+	 (aty_ld_le32(CONFIG_STAT0, info) & 7) == 5 &&
 	 init->crtc_gen_cntl[1] == 0))
 	return -EINVAL;
 
@@ -884,18 +1016,31 @@
 }
 
 static int encode_var(struct fb_var_screeninfo *var,
-		      const struct atyfb_par *par)
+		      const struct atyfb_par *par,
+		      struct fb_info_aty *info)
 {
+    int vmode = par->hw.gx.vmode;
+    int cmode = par->hw.gx.cmode;
+    struct aty_regvals *init = get_aty_struct(vmode, info);
+    u_int h_total, h_disp;
+    u_int h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol;
+    u_int v_total, v_disp;
+    u_int v_sync_strt, v_sync_wid, v_sync_pol;
+    u_int xtalin, vclk;
+    u8 pll_ref_div, vclk_fb_div, vclk_post_div, pll_ext_cntl;
+
     memset(var, 0, sizeof(struct fb_var_screeninfo));
+    if (!init)
+	return -EINVAL;
 
-    var->xres = vmode_attrs[par->vmode-1].hres;
-    var->yres = vmode_attrs[par->vmode-1].vres;
+    var->xres = vmode_attrs[vmode-1].hres;
+    var->yres = vmode_attrs[vmode-1].vres;
     var->xres_virtual = par->vxres;
     var->yres_virtual = par->vyres;
     var->xoffset = par->xoffset;
     var->yoffset = par->yoffset;
     var->grayscale = 0;
-    switch (par->cmode) {
+    switch (cmode) {
 	case CMODE_8:
 	    var->bits_per_pixel = 8;
 	    var->red.offset = 0;
@@ -940,19 +1085,94 @@
     var->width = -1;
     var->vmode = FB_VMODE_NONINTERLACED;
     var->accel_flags = par->accel;
-    var->left_margin = var->right_margin = 64;	/* guesses */
-    var->upper_margin = var->lower_margin = 32;
-    var->hsync_len = 64;
-    var->vsync_len = 2;
-
-    /* no long long support in the kernel :-( */
-    /* this splittig trick will work if xres > 232 */
-    var->pixclock = 1000000000/
-	(var->left_margin+var->xres+var->right_margin+var->hsync_len);
-    var->pixclock *= 1000;
-    var->pixclock /= vmode_attrs[par->vmode-1].vfreq*
-	 (var->upper_margin+var->yres+var->lower_margin+var->vsync_len);
-    var->sync = 0;
+
+    h_total = (init->crtc_h_tot_disp<<3) & 0xff8;
+    h_disp = (init->crtc_h_tot_disp>>13) & 0x7f8;
+    h_sync_strt = ((init->crtc_h_sync_strt_wid[cmode]<<3) & 0x7f8) |
+		  ((init->crtc_h_sync_strt_wid[cmode]>>1) & 0x800);
+    h_sync_dly = (init->crtc_h_sync_strt_wid[cmode]>>8) & 0x7;
+    h_sync_wid = (init->crtc_h_sync_strt_wid[cmode]>>13) & 0xf8;
+    h_sync_pol = (init->crtc_h_sync_strt_wid[cmode]>>21) & 0x1;
+
+    v_total = init->crtc_v_tot_disp & 0x7ff;
+    v_disp = (init->crtc_v_tot_disp>>16) & 0x7ff;
+    v_sync_strt = init->crtc_v_sync_strt_wid & 0x7ff;
+    v_sync_wid = (init->crtc_v_sync_strt_wid>>16) & 0x1f;
+    v_sync_pol = (init->crtc_v_sync_strt_wid>>21) & 0x1;
+
+    var->left_margin = (h_total+8)-h_sync_strt-h_sync_wid;
+    var->right_margin = h_sync_strt-(h_disp+8);
+    var->upper_margin = (v_total+1)-v_sync_strt-v_sync_wid;
+    var->lower_margin = v_sync_strt-(v_disp+1);
+    var->hsync_len = h_sync_wid;
+    var->vsync_len = v_sync_wid;
+    var->sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) |
+		(v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT);
+
+    xtalin = 69841;	/* 14.31818 MHz */
+    switch (info->chip_type) {
+	case MACH64_GT_ID:
+	case MACH64_VT_ID:
+	    if (info->chip_type == MACH64_GT_ID) {
+		pll_ref_div = 0x21;
+		vclk_post_div = init->offset[0];
+		vclk_fb_div = init->offset[1];
+		pll_ext_cntl = init->offset[2];
+	    } else {
+		pll_ref_div = 0x2d;
+		vclk_post_div = init->clock_val[0];
+		vclk_fb_div = init->clock_val[1];
+		pll_ext_cntl = 0x0;
+	    }
+	    vclk = xtalin*pll_ref_div;
+	    switch (vclk_post_div & 3) {
+		case 0:
+		    vclk *= (pll_ext_cntl & 0x10) ? 3 : 1;
+		    break;
+		case 1:
+		    if (pll_ext_cntl & 0x10)
+			return -EINVAL;
+		    vclk *= 2;
+		    break;
+		case 2:
+		    vclk *= (pll_ext_cntl & 0x10) ? 6 : 4;
+		    break;
+		case 3:
+		    vclk *= (pll_ext_cntl & 0x10) ? 12 : 8;
+		    break;
+	    }
+	    vclk /= 2*vclk_fb_div;
+	    break;
+	default: /* MACH64_GX_ID */
+	    {
+		/* haven't read the IBM RGB514 PDF yet, so just guesses */
+		static u32 gx_vclk[VMODE_MAX] = {
+		        0,	/* vmode  1 */	
+		        0,	/* vmode  2 */	
+		        0,	/* vmode  3 */	
+		        0,	/* vmode  4 */	
+		    39722,	/* vmode  5 (25.175 MHz) */
+		    33333,	/* vmode  6 (30 MHz) */
+		        0,	/* vmode  7 */	
+		        0,	/* vmode  8 */	
+		    27778,	/* vmode  9 (36 MHz) */
+		    25000,	/* vmode 10 (40 MHz) */
+		    20000,	/* vmode 11 (50 MHz) */
+		    20000,	/* vmode 12 (50 MHz) */
+		    17544,	/* vmode 13 (57 MHz) */
+		    15385,	/* vmode 14 (65 MHz) */
+		    13333,	/* vmode 15 (75 MHz) */
+		        0,	/* vmode 16 */	
+		    12821,	/* vmode 17 (78 MHz) */
+		    10000,	/* vmode 18 (100 MHz) */
+		     7937,	/* vmode 19 (126 MHz) */
+		     7407	/* vmode 20 (135 MHz) */
+		};
+		vclk = gx_vclk[vmode-1];
+	    }
+	    break;
+    }
+    var->pixclock = vclk;
 
     return 0;
 }
@@ -960,12 +1180,18 @@
 
 static void init_par(struct atyfb_par *par, int vmode, int cmode)
 {
-    par->vmode = vmode;
-    par->cmode = cmode;
+    par->hw.gx.vmode = vmode;
+    par->hw.gx.cmode = cmode;
     par->vxres = vmode_attrs[vmode-1].hres;
     par->vyres = vmode_attrs[vmode-1].vres;
     par->xoffset = 0;
     par->yoffset = 0;
+#ifdef __mc68000__
+    par->accel = FB_ACCELF_TEXT;
+#else
+    /* FIXME: accel doesn't work yet on PPC */
+    par->accel = 0;
+#endif
 }
 
 
@@ -976,13 +1202,14 @@
 static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con,
 			 struct fb_info *info)
 {
+    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
     struct atyfb_par par;
 
     if (con == -1)
 	par = default_par;
     else
-	decode_var(&fb_display[con].var, &par);
-    encode_fix(fix, &par);
+	decode_var(&fb_display[con].var, &par, info2);
+    encode_fix(fix, &par, info2);
     return 0;
 }
 
@@ -995,7 +1222,7 @@
 			 struct fb_info *info)
 {
     if (con == -1)
-	encode_var(var, &default_par);
+	encode_var(var, &default_par, (struct fb_info_aty *)info);
     else
 	*var = fb_display[con].var;
     return 0;
@@ -1009,9 +1236,10 @@
 static int atyfb_set_var(struct fb_var_screeninfo *var, int con,
 			 struct fb_info *info)
 {
+    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
     struct atyfb_par par;
     struct display *display;
-    int oldxres, oldyres, oldvxres, oldvyres, oldbpp;
+    int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel;
     int err;
     int activate = var->activate;
 
@@ -1020,10 +1248,10 @@
     else
 	display = &fb_disp;	/* used during initialization */
 
-    if ((err = decode_var(var, &par)))
+    if ((err = decode_var(var, &par, info2)))
 	return err;
 
-    encode_var(var, &par);
+    encode_var(var, &par, (struct fb_info_aty *)info);
 
     if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
 	oldxres = display->var.xres;
@@ -1031,14 +1259,15 @@
 	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) {
+	    oldbpp != var->bits_per_pixel || oldaccel != var->accel_flags) {
 	    struct fb_fix_screeninfo fix;
 
-	    encode_fix(&fix, &par);
-	    display->screen_base = (u_char *)fix.smem_start;
+	    encode_fix(&fix, &par, info2);
+	    display->screen_base = fix.smem_start;
 	    display->visual = fix.visual;
 	    display->type = fix.type;
 	    display->type_aux = fix.type_aux;
@@ -1047,29 +1276,35 @@
 	    display->line_length = fix.line_length;
 	    display->can_soft_blank = 1;
 	    display->inverse = 0;
-	    switch (par.cmode) {
+	    switch (par.hw.gx.cmode) {
+#ifdef CONFIG_FBCON_CFB8
 		case CMODE_8:
-		    if (par.accel & FB_ACCELF_TEXT) {
-			display->dispsw = &fbcon_aty8;
+		    if (var->accel_flags & FB_ACCELF_TEXT) {
+			display->dispsw = &fbcon_aty8;	/* doesn't work yet */
 #warning FIXME: We should reinit the graphics engine here
 		    } else
 			display->dispsw = &fbcon_cfb8;
 		    break;
+#endif
+#ifdef CONFIG_FBCON_CFB16
 		case CMODE_16:
 		    display->dispsw = &fbcon_cfb16;
 		    break;
+#endif
+#ifdef CONFIG_FBCON_CFB32
 		case CMODE_32:
 		    display->dispsw = &fbcon_cfb32;
 		    break;
+#endif
 		default:
 		    display->dispsw = NULL;
 		    break;
 	    }
-	    if (fb_info.changevar)
-		(*fb_info.changevar)(con);
+	    if (info->changevar)
+		(*info->changevar)(con);
 	}
 	if (con == currcon)
-	    atyfb_set_par(&par);
+	    atyfb_set_par(&par, info2);
 	if (oldbpp != var->bits_per_pixel) {
 	    if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
 		return err;
@@ -1090,18 +1325,19 @@
 static int atyfb_pan_display(struct fb_var_screeninfo *var, int con,
 			     struct fb_info *info)
 {
+    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
     u32 xres, yres, xoffset, yoffset;
     struct atyfb_par *par = &current_par;
 
-    xres = vmode_attrs[par->vmode-1].hres;
-    yres = vmode_attrs[par->vmode-1].vres;
+    xres = vmode_attrs[par->hw.gx.vmode-1].hres;
+    yres = vmode_attrs[par->hw.gx.vmode-1].vres;
     xoffset = (var->xoffset+7) & ~7;
     yoffset = var->yoffset;
     if (xoffset+xres > par->vxres || yoffset+yres > par->vyres)
 	return -EINVAL;
     par->xoffset = xoffset;
     par->yoffset = yoffset;
-    set_off_pitch(par);
+    set_off_pitch(par, info2);
     return 0;
 }
 
@@ -1142,6 +1378,9 @@
 			   info);
     else
 	fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+#ifdef __mc68000__
+    bha_delay(2);
+#endif
     return 0;
 }
 
@@ -1157,167 +1396,236 @@
      *  Initialisation
      */
 
-__initfunc(unsigned long atyfb_init(unsigned long mem_start))
+__initfunc(static int aty_init(struct fb_info_aty *info, const char *name))
 {
-#ifdef __powerpc__
-    /* We don't want to be called like this. */
-    /* We rely on Open Firmware (offb) instead. */
-    return mem_start;
-#else /* !__powerpc__ */
-    /* To be merged with Bernd's mach64fb */
-    return mem_start;
-#endif /* !__powerpc__ */
-}
-
-
-unsigned long atyfb_of_init(unsigned long mem_start, struct device_node *dp)
-{
-    int i, err, sense;
+    u32 i;
+    int j, k, err, sense;
     struct fb_var_screeninfo var;
     struct aty_regvals *init;
-    unsigned long addr;
-    unsigned char bus, devfn;
-    unsigned short cmd;
+    u8 asic, fnd;
 
-    if (dp->next)
-	printk("Warning: only using first ATI card detected\n");
-    if (dp->n_addrs != 1 && dp->n_addrs != 3)
-	printk("Warning: expecting 1 or 3 addresses for ATY (got %d)",
-	       dp->n_addrs);
-
-    ati_regbase = (int)ioremap((0x7ffc00 + dp->addrs[0].address), 0x1000);
-    aty_cmap_regs = (struct aty_cmap_regs *)(ati_regbase + 0xC0);
-
-    /* enable memory-space accesses using config-space command register */
-    if (pci_device_loc(dp, &bus, &devfn) == 0) {
-	pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
-	if (cmd != 0xffff) {
-	    cmd |= PCI_COMMAND_MEMORY;
-	    pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
-	}
+    info->aty_cmap_regs = (struct aty_cmap_regs *)(info->ati_regbase+0xc0);
+    info->chip_type = (aty_ld_le32(CONFIG_CHIP_ID, info) & CFG_CHIP_TYPE);
+    asic = (aty_ld_le32(CONFIG_CHIP_ID, info) & CFG_CHIP_MAJOR)>>24;
+    fnd = (aty_ld_le32(CONFIG_CHIP_ID, info) & CFG_CHIP_FND_ID)>>27;
+    printk("atyfb: ");
+    switch (fnd) {
+	case MACH64_FND_SGS:
+	    printk("SGS ");
+	    break;
+	case MACH64_FND_NEC:
+	    printk("NEC ");
+	    break;
+	case MACH64_FND_UMC:
+	    printk("UMC ");
+	    break;
+    }
+    switch (info->chip_type) {
+	case MACH64_GX_ID:
+	    printk("Mach64 GX");
+	    break;
+	case MACH64_CX_ID:
+	    printk("Mach64 CX");
+	    break;
+	case MACH64_CT_ID:
+	    printk("Mach64 CT");
+	    break;
+	case MACH64_ET_ID:
+	    printk("Mach64 ET");
+	    break;
+	case MACH64_GB_ID:
+	    printk("3D RAGE PRO AGP 1x/2x");
+	    goto RAGE_PRO;
+	case MACH64_GD_ID:
+	    printk("3D RAGE PRO AGP 1x");
+	    goto RAGE_PRO;
+	case MACH64_GI_ID:
+	case MACH64_GP_ID:
+	    printk("3D RAGE PRO PCI");
+	    goto RAGE_PRO;
+	case MACH64_GQ_ID:
+	    printk("RAGE PRO PCI");
+RAGE_PRO:   switch (asic) {
+		case MACH64_ASIC_UMC_R3B_D_P_A1:
+		    i = 1;
+		    goto UMC_R3B;
+		case MACH64_ASIC_UMC_R3B_D_P_A2:
+		    i = 2;
+		    goto UMC_R3B;
+		case MACH64_ASIC_UMC_R3B_D_P_A3:
+		    i = 3;
+		    goto UMC_R3B;
+		case MACH64_ASIC_UMC_R3B_D_P_A4:
+		    i = 4;
+UMC_R3B:	    printk(" UMC R3B/D/P-A%d", i);
+		    break;
+	    }
+	    break;
+	case MACH64_GT_ID:
+	    printk("3D RAGE II/II+");
+	    switch (asic) {
+		case MACH64_ASIC_SGS_GT_B1S1:
+		    printk(" SGS GT-B1S1");
+		    break;
+		case MACH64_ASIC_SGS_GT_B1S2:
+		    printk(" SGS GT-B1S2");
+		    break;
+		case MACH64_ASIC_UMC_GT_B2U1:
+		    printk(" UMC GT-B2U1");
+		    break;
+		case MACH64_ASIC_UMC_GT_B2U2:
+		    printk(" UMC GT-B2U2");
+		    break;
+		case MACH64_ASIC_UMC_GT_B2U3:
+		    printk(" UMC GT-B2U3");
+		    break;
+	    }
+	    break;
+	case MACH64_LG_ID:
+	    printk("3D RAGE LT");
+	    break;
+	case MACH64_VT_ID:
+	    printk("Mach64 VT");
+	    switch (asic) {
+		case MACH64_ASIC_NEC_VT_A3:
+		    printk(" NEC VT-A3");
+		    break;
+		case MACH64_ASIC_NEC_VT_A4:
+		    printk(" NEC VT-A4");
+		    break;
+		case MACH64_ASIC_SGS_VT_A4:
+		    printk(" SGS VT-A4");
+		    break;
+		case MACH64_ASIC_SGS_VT_B1S1:
+		    printk(" SGS VT-B1S1");
+		    break;
+		case MACH64_ASIC_UMC_VT_B2U3:
+		    printk(" UMC VT-B2U3");
+		    break;
+	    }
+	    break;
+	default:
+	    printk("Unknown Mach64");
+	    break;
     }
-    chip_type = (aty_ld_le32(CONFIG_CHIP_ID) & CFG_CHIP_TYPE);
+    printk("\n");
 
-    i = aty_ld_le32(MEM_CNTL);
-    if (chip_type != MACH64_GT_ID)
+    i = aty_ld_le32(MEM_CNTL, info);
+    if (info->chip_type != MACH64_GT_ID)
 	switch (i & MEM_SIZE_ALIAS) {
 	    case MEM_SIZE_512K:
-		total_vram = 0x80000;
+		info->total_vram = 0x80000;
 		break;
 	    case MEM_SIZE_1M:
-		total_vram = 0x100000;
+		info->total_vram = 0x100000;
 		break;
 	    case MEM_SIZE_2M:
-		total_vram = 0x200000;
+		info->total_vram = 0x200000;
 		break;
 	    case MEM_SIZE_4M:
-		total_vram = 0x400000;
+		info->total_vram = 0x400000;
 		break;
 	    case MEM_SIZE_6M:
-		total_vram = 0x600000;
+		info->total_vram = 0x600000;
 		break;
 	    case MEM_SIZE_8M:
-		total_vram = 0x800000;
+		info->total_vram = 0x800000;
 		break;
 	    default:
-		total_vram = 0x80000;
+		info->total_vram = 0x80000;
 	}
     else
 	switch (i & 0xF) {	/* 0xF used instead of MEM_SIZE_ALIAS */
 	    case MEM_SIZE_512K:
-		total_vram = 0x80000;
+		info->total_vram = 0x80000;
 		break;
 	    case MEM_SIZE_1M:
-		total_vram = 0x100000;
+		info->total_vram = 0x100000;
 		break;
 	    case MEM_SIZE_2M_GTB:
-		total_vram = 0x200000;
+		info->total_vram = 0x200000;
 		break;
 	    case MEM_SIZE_4M_GTB:
-		total_vram = 0x400000;
+		info->total_vram = 0x400000;
 		break;
 	    case MEM_SIZE_6M_GTB:
-		total_vram = 0x600000;
+		info->total_vram = 0x600000;
 		break;
 	    case MEM_SIZE_8M_GTB:
-		total_vram = 0x800000;
+		info->total_vram = 0x800000;
 		break;
 	    default:
-		total_vram = 0x80000;
+		info->total_vram = 0x80000;
 	}
+#ifdef __mc68000__
+    info->total_vram -= 0x00080000;
+#endif
 
 #if 1
-    printk("aty_display_init: node = %p, addrs = ", dp->node);
-    printk(" %x(%x)", dp->addrs[0].address, dp->addrs[0].size);
-    printk(", intrs =");
-    for (i = 0; i < dp->n_intrs; ++i)
-    printk(" %x", dp->intrs[i].line);
-    printk("\nregbase: %x pci loc: %x:%x total_vram: %x cregs: %p\n",
-	   (int)ati_regbase, bus, devfn, total_vram, aty_cmap_regs);
-#endif
-
-    /* Map in frame buffer */
-    addr = dp->addrs[0].address;
-
-    /* use the big-endian aperture (??) */
-    addr += 0x800000;
-    frame_buffer = (unsigned long)__ioremap(addr, 0x800000, _PAGE_WRITETHRU);
-
-    if (default_video_mode != -1) {
-	sense = read_aty_sense();
-	printk("monitor sense = %x\n", sense);
-	if (default_video_mode == VMODE_NVRAM) {
-	    default_video_mode = nvram_read_byte(NV_VMODE);
-	    init = get_aty_struct(default_video_mode);
-	    if (default_video_mode <= 0 ||
-		default_video_mode > VMODE_MAX || init == 0)
-		default_video_mode = VMODE_CHOOSE;
-	}
-	if (default_video_mode == VMODE_CHOOSE)
-	    default_video_mode = map_monitor_sense(sense);
+    printk("aty_init: regbase = %lx, frame_buffer = %lx, total_vram = %x\n",
+	   info->ati_regbase, info->frame_buffer, info->total_vram);
+#endif
 
-	init = get_aty_struct(default_video_mode);
-	if (!init)
-	    default_video_mode = VMODE_640_480_60;
-    }
+    sense = read_aty_sense(info);
+    printk("monitor sense = %x\n", sense);
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
+    if (default_vmode == VMODE_NVRAM) {
+	default_vmode = nvram_read_byte(NV_VMODE);
+	init = get_aty_struct(default_vmode, info);
+	if (default_vmode <= 0 || default_vmode > VMODE_MAX || init == 0)
+	    default_vmode = VMODE_CHOOSE;
+    }
+    if (default_vmode == VMODE_CHOOSE)
+	default_vmode = map_monitor_sense(sense);
+#else /* !CONFIG_PMAC && !CONFIG_CHRP */
+    if (default_vmode == VMODE_NVRAM)
+	default_vmode = map_monitor_sense(sense);
+#endif /* !CONFIG_PMAC && !CONFIG_CHRP */
+
+    if (!(init = get_aty_struct(default_vmode, info)))
+	default_vmode = VMODE_640_480_60;
 
     /*
      * Reduce the pixel size if we don't have enough VRAM.
      */
 
-    if (default_color_mode == CMODE_NVRAM)
-	default_color_mode = nvram_read_byte(NV_CMODE);
-    if (default_color_mode < CMODE_8 ||
-	default_color_mode > CMODE_32)
-	default_color_mode = CMODE_8;
-
-    init_par(&default_par, default_video_mode, default_color_mode);
-    while (aty_vram_reqd(&default_par) > total_vram) {
-	while (default_color_mode > CMODE_8 &&
-	       aty_vram_reqd(&default_par) > total_vram) {
-	    --default_color_mode;
-	    init_par(&default_par, default_video_mode, default_color_mode);
+    if (default_cmode == CMODE_NVRAM)
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
+	default_cmode = nvram_read_byte(NV_CMODE);
+#else /* !CONFIG_PMAC && !CONFIG_CHRP */
+	default_cmode = CMODE_8;
+#endif /* !CONFIG_PMAC && !CONFIG_CHRP */
+    if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
+	default_cmode = CMODE_8;
+
+    init_par(&default_par, default_vmode, default_cmode);
+    while (aty_vram_reqd(&default_par) > info->total_vram) {
+	while (default_cmode > CMODE_8 &&
+	       aty_vram_reqd(&default_par) > info->total_vram) {
+	    --default_cmode;
+	    init_par(&default_par, default_vmode, default_cmode);
 	}
 	/*
-	 * adjust the video mode smaller if there still is not enough VRAM
+	 * Adjust the video mode smaller if there still is not enough VRAM
 	 */
-	if (aty_vram_reqd(&default_par) > total_vram)
+	if (aty_vram_reqd(&default_par) > info->total_vram)
 	    do {
-		default_video_mode--;
-		init_par(&default_par, default_video_mode, default_color_mode);
-		init = get_aty_struct(default_video_mode);
+		default_vmode--;
+		init_par(&default_par, default_vmode, default_cmode);
+		init = get_aty_struct(default_vmode, info);
 	    } while ((init == 0) &&
-		     (default_video_mode > VMODE_640_480_60));
+		     (default_vmode > VMODE_640_480_60));
     }
 
-    if (chip_type == MACH64_GT_ID && (aty_ld_le32(CONFIG_STAT0) & 7) == 5
+    if (info->chip_type == MACH64_GT_ID &&
+	(aty_ld_le32(CONFIG_STAT0, info) & 7) == 5
 	&& init->crtc_gen_cntl[1] == 0) {
-	    default_video_mode = VMODE_640_480_67;
-	    default_color_mode = CMODE_8;
-	    init_par(&default_par, default_video_mode, default_color_mode);
+	    default_vmode = VMODE_640_480_67;
+	    default_cmode = CMODE_8;
+	    init_par(&default_par, default_vmode, default_cmode);
     }
 
-    switch (chip_type) {
+    switch (info->chip_type) {
 	case MACH64_GX_ID:
 	    strcat(atyfb_name, "GX");
 	    break;
@@ -1330,52 +1638,141 @@
 	default:
 	    break;
     }
-    strcpy(fb_info.modename, atyfb_name);
-    fb_info.node = -1;
-    fb_info.fbops = &atyfb_ops;
-    fb_info.disp = &fb_disp;
-    fb_info.fontname[0] = '\0';
-    fb_info.changevar = NULL;
-    fb_info.switch_con = &atyfbcon_switch;
-    fb_info.updatevar = &atyfbcon_updatevar;
-    fb_info.blank = &atyfbcon_blank;
+    strcpy(info->fb_info.modename, atyfb_name);
+    info->fb_info.node = -1;
+    info->fb_info.fbops = &atyfb_ops;
+    info->fb_info.disp = &fb_disp;
+    info->fb_info.fontname[0] = '\0';
+    info->fb_info.changevar = NULL;
+    info->fb_info.switch_con = &atyfbcon_switch;
+    info->fb_info.updatevar = &atyfbcon_updatevar;
+    info->fb_info.blank = &atyfbcon_blank;
+
+    for (j = 0; j < 16; j++) {
+	k = color_table[j];
+	info->palette[j].red = default_red[k];
+	info->palette[j].green = default_grn[k];
+	info->palette[j].blue = default_blu[k];
+    }
 
-    err = register_framebuffer(&fb_info);
+    err = register_framebuffer(&info->fb_info);
     if (err < 0)
-	return mem_start;
+	return 0;
+    atyfb_set_par(&default_par, info);
+    encode_var(&var, &default_par, info);
+    atyfb_set_var(&var, -1, &info->fb_info);
+
+    printk("fb%d: %s frame buffer device on %s\n",
+	   GET_FB_IDX(info->fb_info.node), atyfb_name, name);
+#ifdef __mc68000__
+    bha_delay(3);
+#endif
 
-    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];
-    }
-    atyfb_set_par(&default_par);
-    encode_var(&var, &default_par);
-    atyfb_set_var(&var, -1, &fb_info);
+    return 1;
+}
 
-    printk("fb%d: %s frame buffer device on %s\n", GET_FB_IDX(fb_info.node),
-	   atyfb_name, dp->full_name);
+__initfunc(unsigned long atyfb_init(unsigned long mem_start))
+{
+#if defined(CONFIG_FB_OF)
+    /* We don't want to be called like this. */
+    /* We rely on Open Firmware (offb) instead. */
+#elif defined(CONFIG_PCI)
+    /* Anyone who wants to do a PCI probe for an ATI chip? */
+#elif defined(__mc68000__)
+    int m64_num;
+    struct fb_info_aty *info;
+
+    for (m64_num = 0; m64_num < mach64_count; m64_num++) {
+	if (!phys_vmembase[m64_num] || !phys_size[m64_num] ||
+	    !phys_guiregbase[m64_num]) {
+	    printk(" phys_*[%d] parameters not set => returning early. \n",
+		   m64_num);
+	    continue;
+	}
 
-#ifdef CONFIG_FB_COMPAT_XPMAC
-    if (!console_fb_info) {
-	console_fb_info = &fb_info;
-	console_setmode_ptr = atyfb_console_setmode;
-	console_set_cmap_ptr = atyfb_set_cmap;
-    }
-#endif /* CONFIG_FB_COMPAT_XPMAC) */
+	info = (struct fb_info_aty *)mem_start;
+	mem_start += sizeof(struct fb_info_aty);
+	mem_start = PAGE_ALIGN(mem_start);
 
+	/*
+	 *  Map the video memory (physical address given) to somewhere in the
+	 *  kernel address space.
+	 */
+	info->frame_buffer = kernel_map(phys_vmembase[m64_num],
+					phys_size[m64_num],
+					KERNELMAP_NOCACHE_SER, &mem_start);
+	info->ati_regbase = kernel_map(phys_guiregbase[m64_num], 0x10000,
+				       KERNELMAP_NOCACHE_SER, &mem_start)
+			    +0xFC00ul;
+
+	if (!aty_init(info, "ISA bus")) {
+	    /* This is insufficient! kernel_map has added two large chunks!! */
+	    return mem_start;
+	}
+    }
+#endif
     return mem_start;
 }
 
+#ifdef CONFIG_FB_OF
+__initfunc(void atyfb_of_init(struct device_node *dp))
+{
+    unsigned long addr;
+    u8 bus, devfn;
+    u16 cmd;
+    struct fb_info_aty *info;
+
+    for (; dp; dp = dp->next) {
+	if (dp->n_addrs != 1 && dp->n_addrs != 3)
+	    printk("Warning: expecting 1 or 3 addresses for ATY (got %d)",
+		   dp->n_addrs);
+
+	info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
+
+	info->ati_regbase = (unsigned long)ioremap(0x7ff000+
+						   dp->addrs[0].address,
+						   0x1000)+0xc00;
+
+	/* enable memory-space accesses using config-space command register */
+	if (pci_device_loc(dp, &bus, &devfn) == 0) {
+	    pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
+	    if (cmd != 0xffff) {
+		cmd |= PCI_COMMAND_MEMORY;
+		pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
+	    }
+	}
+	/* Map in frame buffer */
+	addr = dp->addrs[0].address;
+
+#ifdef __BIG_ENDIAN
+	/* Use the big-endian aperture */
+	addr += 0x800000;
+#endif
+	info->frame_buffer = (unsigned long)__ioremap(addr, 0x800000,
+						      _PAGE_WRITETHRU);
 
-/* XXX: doesn't work yet */
-void atyfb_setup(char *options, int *ints)
+	if (!aty_init(info, dp->full_name)) {
+	    kfree(info);
+	    return;
+	}
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+	if (!console_fb_info) {
+	    console_fb_info = &info->fb_info;
+	    console_setmode_ptr = atyfb_console_setmode;
+	    console_set_cmap_ptr = atyfb_set_cmap;
+	}
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+    }
+}
+#endif /* CONFIG_FB_OF */
+
+
+__initfunc(void atyfb_setup(char *options, int *ints))
 {
     char *this_opt;
     int vmode;
     int depth;
-
     if (!options || !*options)
 	return;
 
@@ -1384,38 +1781,103 @@
 	if (!strncmp(this_opt, "vmode:", 6)) {
 	    vmode = simple_strtoul(this_opt+6, NULL, 0);
 	    if (vmode > 0 && vmode <= VMODE_MAX)
-		default_video_mode = vmode;
+		default_vmode = vmode;
 	} else if (!strncmp(this_opt, "cmode:", 6)) {
 	    depth = simple_strtoul(this_opt+6, NULL, 0);
 	    switch (depth) {
 		case 8:
-		    default_color_mode = CMODE_8;
+		    default_cmode = CMODE_8;
 		    break;
 		case 15:
 		case 16:
-		    default_color_mode = CMODE_16;
+		    default_cmode = CMODE_16;
 		    break;
 		case 24:
 		case 32:
-		    default_color_mode = CMODE_32;
+		    default_cmode = CMODE_32;
 		    break;
-	    };
+	    }
 	}
+#ifndef CONFIG_FB_OF
+	else if (!strncmp(this_opt, "Mach64:", 7)) {
+	    static unsigned char m64_num;
+	    static char mach64_str[80];
+	    strncpy(mach64_str, this_opt+7, 80);
+	    if (!store_video_par(mach64_str, m64_num)) {
+		m64_num++;
+		mach64_count = m64_num;
+	    }
+	}
+#endif /* !CONFIG_FB_OF */
     }
 }
 
+#ifndef CONFIG_FB_OF
+__initfunc(static int store_video_par(char *video_str, unsigned char m64_num))
+{
+    char *p;
+    unsigned long vmembase, size, guiregbase;
+
+    printk("store_video_par() '%s' \n", video_str);
+
+    if (!(p = strtoke(video_str, ";")) || !*p)
+	goto mach64_invalid;
+    vmembase = simple_strtoul(p, NULL, 0);
+    if (!(p = strtoke(NULL, ";")) || !*p)
+	goto mach64_invalid;
+    size = simple_strtoul(p, NULL, 0);
+    if (!(p = strtoke(NULL, ";")) || !*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;
+    printk(" stored them all: $%08lX $%08lX $%08lX \n", vmembase, size,
+	   guiregbase);
+    return 0;
+
+mach64_invalid:
+    phys_vmembase[m64_num]   = 0;
+    return -1;
+}
+
+__initfunc(static char *strtoke(char *s, const char *ct))
+{
+    static char *ssave = NULL;
+    char *sbegin, *send;
+
+    sbegin  = s ? s : ssave;
+    if (!sbegin)
+	return NULL;
+    if (*sbegin == '\0') {
+	ssave = NULL;
+	return NULL;
+    }
+    send = strpbrk(sbegin, ct);
+    if (send && *send != '\0')
+	*send++ = '\0';
+    ssave = send;
+    return sbegin;
+}
+#endif /* !CONFIG_FB_OF */
 
 static int atyfbcon_switch(int con, struct fb_info *info)
 {
+    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
     struct atyfb_par par;
 
+#ifdef __mc68000__
+    bha_delay(4);
+#endif
+
     /* Do we have to save the colormap? */
     if (fb_display[currcon].cmap.len)
 	fb_get_cmap(&fb_display[currcon].cmap, &fb_display[currcon].var, 1,
 		    atyfb_getcolreg, info);
     currcon = con;
-    decode_var(&fb_display[con].var, &par);
-    atyfb_set_par(&par);
+    decode_var(&fb_display[con].var, &par, info2);
+    atyfb_set_par(&par, info2);
     /* Install new colormap */
     do_install_cmap(con, info);
     return 0;
@@ -1427,8 +1889,10 @@
 
 static int atyfbcon_updatevar(int con, struct fb_info *info)
 {
+    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+
     current_par.yoffset = fb_display[con].var.yoffset;
-    set_off_pitch(&current_par);
+    set_off_pitch(&current_par, info2);
     return 0;
 }
 
@@ -1438,9 +1902,10 @@
 
 static void atyfbcon_blank(int blank, struct fb_info *info)
 {
-    char gen_cntl;
+    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+    u8 gen_cntl;
 
-    gen_cntl = aty_ld_8(CRTC_GEN_CNTL);
+    gen_cntl = aty_ld_8(CRTC_GEN_CNTL, info2);
     if (blank & VESA_VSYNC_SUSPEND)
 	    gen_cntl |= 0x8;
     if (blank & VESA_HSYNC_SUSPEND)
@@ -1449,7 +1914,7 @@
 	    gen_cntl |= 0x40;
     if (blank == VESA_NO_BLANKING)
 	    gen_cntl &= ~(0x4c);
-    aty_st_8(CRTC_GEN_CNTL, gen_cntl);
+    aty_st_8(CRTC_GEN_CNTL, gen_cntl, info2);
 }
 
 
@@ -1459,13 +1924,15 @@
      */
 
 static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-			 u_int *transp, struct fb_info *info)
+			   u_int *transp, struct fb_info *info)
 {
+    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+
     if (regno > 255)
 	return 1;
-    *red = palette[regno].red;
-    *green = palette[regno].green;
-    *blue = palette[regno].blue;
+    *red = info2->palette[regno].red;
+    *green = info2->palette[regno].green;
+    *blue = info2->palette[regno].blue;
     return 0;
 }
 
@@ -1477,32 +1944,33 @@
      */
 
 static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-			 u_int transp, struct fb_info *info)
+			   u_int transp, struct fb_info *info)
 {
+    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
     int i, scale;
 
     if (regno > 255)
 	return 1;
-    palette[regno].red = red;
-    palette[regno].green = green;
-    palette[regno].blue = blue;
-    aty_WaitQueue(2);
-    i = aty_ld_8(DAC_CNTL) & 0xfc;
-    if (chip_type == MACH64_GT_ID)
-	    i |= 0x2;	/*DAC_CNTL|0x2 turns off the extra brightness for gt*/
-    aty_st_8(DAC_CNTL, i);
-    aty_st_8(DAC_REGS + DAC_MASK, 0xff);
+    info2->palette[regno].red = red;
+    info2->palette[regno].green = green;
+    info2->palette[regno].blue = blue;
+    aty_WaitQueue(2, info2);
+    i = aty_ld_8(DAC_CNTL, info2) & 0xfc;
+    if (info2->chip_type == MACH64_GT_ID)
+	i |= 0x2;	/*DAC_CNTL|0x2 turns off the extra brightness for gt*/
+    aty_st_8(DAC_CNTL, i, info2);
+    aty_st_8(DAC_REGS + DAC_MASK, 0xff, info2);
     eieio();
-    scale = ((chip_type != MACH64_GX_ID) &&
-	     (current_par.cmode == CMODE_16)) ? 3 : 0;
-    aty_WaitQueue(4);
-    aty_cmap_regs->windex = regno << scale;
+    scale = ((info2->chip_type != MACH64_GX_ID) &&
+	     (current_par.hw.gx.cmode == CMODE_16)) ? 3 : 0;
+    aty_WaitQueue(4, info2);
+    info2->aty_cmap_regs->windex = regno << scale;
     eieio();
-    aty_cmap_regs->lut = red << scale;
+    info2->aty_cmap_regs->lut = red << scale;
     eieio();
-    aty_cmap_regs->lut = green << scale;
+    info2->aty_cmap_regs->lut = green << scale;
     eieio();
-    aty_cmap_regs->lut = blue << scale;
+    info2->aty_cmap_regs->lut = blue << scale;
     eieio();
     if (regno < 16) {
 #ifdef CONFIG_FBCON_CFB16
@@ -1535,13 +2003,13 @@
      *  Accelerated functions
      */
 
-void aty_waitblit(void)
+static void aty_waitblit(struct fb_info_aty *info)
 {
-    aty_WaitIdleEmpty();	/* Make sure that all commands have finished */
+    aty_WaitIdleEmpty(info);	/* Make sure that all commands have finished */
 }
 
-void aty_rectcopy(int srcx, int srcy, int dstx, int dsty, u_int width,
-		  u_int height)
+static void aty_rectcopy(int srcx, int srcy, int dstx, int dsty, u_int width,
+			 u_int height, struct fb_info_aty *info)
 {
     u_int direction = 0;
 
@@ -1557,46 +2025,48 @@
     } else
 	direction |= DST_X_LEFT_TO_RIGHT;
 
-    aty_WaitQueue(4);
-    aty_st_le32(DP_WRITE_MSK, 0x000000FF /* pGC->planemask */ );
-    aty_st_le32(DP_MIX, (MIX_SRC << 16) |  MIX_DST);
-    aty_st_le32(DP_SRC, FRGD_SRC_BLIT);
-
-    aty_WaitQueue(5);
-    aty_st_le32(SRC_Y_X, (srcx << 16) | (srcy & 0x0000ffff));
-    aty_st_le32(SRC_WIDTH1, width);
-    aty_st_le32(DST_CNTL, direction);
-    aty_st_le32(DST_Y_X, (dstx << 16) | (dsty & 0x0000ffff));
-    aty_st_le32(DST_HEIGHT_WIDTH, (width << 16) | (height & 0x0000ffff));
+    aty_WaitQueue(4, info);
+    aty_st_le32(DP_WRITE_MSK, 0x000000FF /* pGC->planemask */ , info);
+    aty_st_le32(DP_MIX, (MIX_SRC << 16) |  MIX_DST, info);
+    aty_st_le32(DP_SRC, FRGD_SRC_BLIT, info);
+
+    aty_WaitQueue(5, info);
+    aty_st_le32(SRC_Y_X, (srcx << 16) | (srcy & 0x0000ffff), info);
+    aty_st_le32(SRC_WIDTH1, width, info);
+    aty_st_le32(DST_CNTL, direction, info);
+    aty_st_le32(DST_Y_X, (dstx << 16) | (dsty & 0x0000ffff), info);
+    aty_st_le32(DST_HEIGHT_WIDTH, (width << 16) | (height & 0x0000ffff), info);
 
-    aty_WaitIdleEmpty();	/* Make sure that all commands have finished */
+    aty_WaitIdleEmpty(info);	/* Make sure that all commands have finished */
 
     /*
      * Make sure that the destination trajectory is correctly set
      * for subsequent calls.  MACH64_BIT_BLT is the only function that
      * currently changes the destination trajectory from L->R and T->B.
      */
-    aty_st_le32(DST_CNTL, (DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM));
+    aty_st_le32(DST_CNTL, (DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM), info);
 }
 
-void aty_rectfill(int dstx, int dsty, u_int width, u_int height, u_int color)
+static void aty_rectfill(int dstx, int dsty, u_int width, u_int height,
+			 u_int color, struct fb_info_aty *info)
 {
     if (!width || !height)
 	return;
 
-    aty_WaitQueue(5);
-    aty_st_le32(DP_FRGD_CLR, color /* pGC->fgPixel */ );
-    aty_st_le32(DP_WRITE_MSK, 0x000000FF /* pGC->planemask */ );
-    aty_st_le32(DP_MIX, (MIX_SRC << 16) | MIX_DST);
-    aty_st_le32(DP_SRC, FRGD_SRC_FRGD_CLR);
-
-    aty_st_le32(DST_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM);
-
-    aty_WaitQueue(2);
-    aty_st_le32(DST_Y_X, (((u_int)dstx << 16) | ((u_int)dsty & 0x0000ffff)));
-    aty_st_le32(DST_HEIGHT_WIDTH, (((u_int)width << 16) | height));
+    aty_WaitQueue(5, info);
+    aty_st_le32(DP_FRGD_CLR, color /* pGC->fgPixel */ , info);
+    aty_st_le32(DP_WRITE_MSK, 0x000000FF /* pGC->planemask */ , info);
+    aty_st_le32(DP_MIX, (MIX_SRC << 16) | MIX_DST, info);
+    aty_st_le32(DP_SRC, FRGD_SRC_FRGD_CLR, info);
+
+    aty_st_le32(DST_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM, info);
+
+    aty_WaitQueue(2, info);
+    aty_st_le32(DST_Y_X, (((u_int)dstx << 16) | ((u_int)dsty & 0x0000ffff)),
+		info);
+    aty_st_le32(DST_HEIGHT_WIDTH, (((u_int)width << 16) | height), info);
 
-    aty_WaitIdleEmpty();	/* Make sure that all commands have finished */
+    aty_WaitIdleEmpty(info);	/* Make sure that all commands have finished */
 }
 
 
@@ -1614,7 +2084,8 @@
     width *= p->fontwidth;
     height *= p->fontheight;
 
-    aty_rectcopy(sx, sy, dx, dy, width, height);
+    aty_rectcopy(sx, sy, dx, dy, width, height,
+		 (struct fb_info_aty *)p->fb_info);
 }
 
 static void fbcon_aty8_clear(struct vc_data *conp, struct display *p, int sy,
@@ -1629,26 +2100,27 @@
     width *= p->fontwidth;
     height *= p->fontheight;
 
-    aty_rectfill(sx, sy, width, height, bgx);
+    aty_rectfill(sx, sy, width, height, bgx,
+		 (struct fb_info_aty *)p->fb_info);
 }
 
 static void fbcon_aty8_putc(struct vc_data *conp, struct display *p, int c,
 			    int yy, int xx)
 {
-    aty_waitblit();
+    aty_waitblit((struct fb_info_aty *)p->fb_info);
     fbcon_cfb8_putc(conp, p, c, yy, xx);
 }
 
 static void fbcon_aty8_putcs(struct vc_data *conp, struct display *p,
 			     const char *s, int count, int yy, int xx)
 {
-    aty_waitblit();
+    aty_waitblit((struct fb_info_aty *)p->fb_info);
     fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
 }
 
 static struct display_switch fbcon_aty8 = {
     fbcon_cfb8_setup, fbcon_aty8_bmove, fbcon_aty8_clear, fbcon_aty8_putc,
-    fbcon_aty8_putcs, fbcon_cfb8_revc
+    fbcon_aty8_putcs, fbcon_cfb8_revc, NULL
 };
 
 
@@ -1663,7 +2135,6 @@
 
 static int atyfb_console_setmode(struct vc_mode *mode, int doit)
 {
-    int err;
     struct fb_var_screeninfo var;
     struct atyfb_par par;
     int vmode, cmode;
@@ -1688,12 +2159,9 @@
 	    return -EINVAL;
     }
     init_par(&par, vmode, cmode);
-    encode_var(&var, &par);
-    if ((err = decode_var(&var, &par)))
-	return err;
-    if (doit)
-	atyfb_set_var(&var, currcon, 0);
-    return 0;
+    encode_var(&var, &par, (struct fb_info_aty *)console_fb_info);
+    var.activate = doit ? FB_ACTIVATE_NOW : FB_ACTIVATE_TEST;
+    return atyfb_set_var(&var, currcon, console_fb_info);
 }
 
 #endif /* CONFIG_FB_COMPAT_XPMAC */
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/cyberfb.c m68k/drivers/video/cyberfb.c
--- m68k-2.1.99/drivers/video/cyberfb.c	Mon May  4 20:07:17 1998
+++ m68k/drivers/video/cyberfb.c	Tue May  5 22:21:54 1998
@@ -1177,7 +1177,7 @@
 
 static struct display_switch fbcon_cyber8 = {
    fbcon_cfb8_setup, fbcon_cyber8_bmove, fbcon_cyber8_clear, fbcon_cyber8_putc,
-   fbcon_cyber8_putcs, fbcon_cyber8_revc
+   fbcon_cyber8_putcs, fbcon_cyber8_revc, NULL
 };
 #endif
 
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/fbcon-afb.c m68k/drivers/video/fbcon-afb.c
--- m68k-2.1.99/drivers/video/fbcon-afb.c	Sun Apr 12 23:46:34 1998
+++ m68k/drivers/video/fbcon-afb.c	Tue May  5 22:21:54 1998
@@ -414,7 +414,7 @@
 
 struct display_switch fbcon_afb = {
     fbcon_afb_setup, fbcon_afb_bmove, fbcon_afb_clear, fbcon_afb_putc,
-    fbcon_afb_putcs, fbcon_afb_revc
+    fbcon_afb_putcs, fbcon_afb_revc, NULL
 };
 
 
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/fbcon-cfb16.c m68k/drivers/video/fbcon-cfb16.c
--- m68k-2.1.99/drivers/video/fbcon-cfb16.c	Mon May  4 20:07:17 1998
+++ m68k/drivers/video/fbcon-cfb16.c	Tue May  5 22:21:54 1998
@@ -181,7 +181,7 @@
 
 struct display_switch fbcon_cfb16 = {
     fbcon_cfb16_setup, fbcon_cfb16_bmove, fbcon_cfb16_clear, fbcon_cfb16_putc,
-    fbcon_cfb16_putcs, fbcon_cfb16_revc
+    fbcon_cfb16_putcs, fbcon_cfb16_revc, NULL
 };
 
 
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/fbcon-cfb2.c m68k/drivers/video/fbcon-cfb2.c
--- m68k-2.1.99/drivers/video/fbcon-cfb2.c	Sun Apr 12 23:46:34 1998
+++ m68k/drivers/video/fbcon-cfb2.c	Tue May  5 22:21:54 1998
@@ -187,7 +187,7 @@
 
 struct display_switch fbcon_cfb2 = {
     fbcon_cfb2_setup, fbcon_cfb2_bmove, fbcon_cfb2_clear, fbcon_cfb2_putc,
-    fbcon_cfb2_putcs, fbcon_cfb2_revc
+    fbcon_cfb2_putcs, fbcon_cfb2_revc, NULL
 };
 
 
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/fbcon-cfb24.c m68k/drivers/video/fbcon-cfb24.c
--- m68k-2.1.99/drivers/video/fbcon-cfb24.c	Sun Apr 12 23:46:34 1998
+++ m68k/drivers/video/fbcon-cfb24.c	Tue May  5 22:21:54 1998
@@ -202,7 +202,7 @@
 
 struct display_switch fbcon_cfb24 = {
     fbcon_cfb24_setup, fbcon_cfb24_bmove, fbcon_cfb24_clear, fbcon_cfb24_putc,
-    fbcon_cfb24_putcs, fbcon_cfb24_revc
+    fbcon_cfb24_putcs, fbcon_cfb24_revc, NULL
 };
 
 
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/fbcon-cfb32.c m68k/drivers/video/fbcon-cfb32.c
--- m68k-2.1.99/drivers/video/fbcon-cfb32.c	Sun Apr 12 23:46:34 1998
+++ m68k/drivers/video/fbcon-cfb32.c	Tue May  5 22:21:54 1998
@@ -186,7 +186,7 @@
 
 struct display_switch fbcon_cfb32 = {
     fbcon_cfb32_setup, fbcon_cfb32_bmove, fbcon_cfb32_clear, fbcon_cfb32_putc,
-    fbcon_cfb32_putcs, fbcon_cfb32_revc
+    fbcon_cfb32_putcs, fbcon_cfb32_revc, NULL
 };
 
 
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/fbcon-cfb4.c m68k/drivers/video/fbcon-cfb4.c
--- m68k-2.1.99/drivers/video/fbcon-cfb4.c	Sun Apr 12 23:46:34 1998
+++ m68k/drivers/video/fbcon-cfb4.c	Tue May  5 22:21:54 1998
@@ -190,7 +190,7 @@
 
 struct display_switch fbcon_cfb4 = {
     fbcon_cfb4_setup, fbcon_cfb4_bmove, fbcon_cfb4_clear, fbcon_cfb4_putc,
-    fbcon_cfb4_putcs, fbcon_cfb4_revc
+    fbcon_cfb4_putcs, fbcon_cfb4_revc, NULL
 };
 
 
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/fbcon-cfb8.c m68k/drivers/video/fbcon-cfb8.c
--- m68k-2.1.99/drivers/video/fbcon-cfb8.c	Mon May  4 20:07:17 1998
+++ m68k/drivers/video/fbcon-cfb8.c	Tue May  5 22:21:55 1998
@@ -178,7 +178,7 @@
 
 struct display_switch fbcon_cfb8 = {
     fbcon_cfb8_setup, fbcon_cfb8_bmove, fbcon_cfb8_clear, fbcon_cfb8_putc,
-    fbcon_cfb8_putcs, fbcon_cfb8_revc
+    fbcon_cfb8_putcs, fbcon_cfb8_revc, NULL
 };
 
 
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/fbcon-ilbm.c m68k/drivers/video/fbcon-ilbm.c
--- m68k-2.1.99/drivers/video/fbcon-ilbm.c	Mon Mar 30 00:49:49 1998
+++ m68k/drivers/video/fbcon-ilbm.c	Tue May  5 22:21:55 1998
@@ -262,7 +262,7 @@
 
 struct display_switch fbcon_ilbm = {
     fbcon_ilbm_setup, fbcon_ilbm_bmove, fbcon_ilbm_clear, fbcon_ilbm_putc,
-    fbcon_ilbm_putcs, fbcon_ilbm_revc
+    fbcon_ilbm_putcs, fbcon_ilbm_revc, NULL
 };
 
 
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/fbcon-iplan2p2.c m68k/drivers/video/fbcon-iplan2p2.c
--- m68k-2.1.99/drivers/video/fbcon-iplan2p2.c	Mon May  4 20:07:17 1998
+++ m68k/drivers/video/fbcon-iplan2p2.c	Tue May  5 22:21:55 1998
@@ -375,7 +375,7 @@
 
 struct display_switch fbcon_iplan2p2 = {
     fbcon_iplan2p2_setup, fbcon_iplan2p2_bmove, fbcon_iplan2p2_clear,
-    fbcon_iplan2p2_putc, fbcon_iplan2p2_putcs, fbcon_iplan2p2_revc
+    fbcon_iplan2p2_putc, fbcon_iplan2p2_putcs, fbcon_iplan2p2_revc, NULL
 };
 
 
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/fbcon-iplan2p4.c m68k/drivers/video/fbcon-iplan2p4.c
--- m68k-2.1.99/drivers/video/fbcon-iplan2p4.c	Mon May  4 20:07:17 1998
+++ m68k/drivers/video/fbcon-iplan2p4.c	Tue May  5 22:21:55 1998
@@ -395,7 +395,7 @@
 
 struct display_switch fbcon_iplan2p4 = {
     fbcon_iplan2p4_setup, fbcon_iplan2p4_bmove, fbcon_iplan2p4_clear,
-    fbcon_iplan2p4_putc, fbcon_iplan2p4_putcs, fbcon_iplan2p4_revc
+    fbcon_iplan2p4_putc, fbcon_iplan2p4_putcs, fbcon_iplan2p4_revc, NULL
 };
 
 
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/fbcon-iplan2p8.c m68k/drivers/video/fbcon-iplan2p8.c
--- m68k-2.1.99/drivers/video/fbcon-iplan2p8.c	Mon May  4 20:07:17 1998
+++ m68k/drivers/video/fbcon-iplan2p8.c	Tue May  5 22:21:55 1998
@@ -432,7 +432,7 @@
 
 struct display_switch fbcon_iplan2p8 = {
     fbcon_iplan2p8_setup, fbcon_iplan2p8_bmove, fbcon_iplan2p8_clear,
-    fbcon_iplan2p8_putc, fbcon_iplan2p8_putcs, fbcon_iplan2p8_revc
+    fbcon_iplan2p8_putc, fbcon_iplan2p8_putcs, fbcon_iplan2p8_revc, NULL
 };
 
 
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/fbcon-mac.c m68k/drivers/video/fbcon-mac.c
--- m68k-2.1.99/drivers/video/fbcon-mac.c	Sun Apr 12 23:46:34 1998
+++ m68k/drivers/video/fbcon-mac.c	Tue May  5 22:21:55 1998
@@ -495,7 +495,7 @@
 
 struct display_switch fbcon_mac = {
     fbcon_mac_setup, fbcon_mac_bmove, fbcon_mac_clear, fbcon_mac_putc,
-    fbcon_mac_putcs, fbcon_mac_revc
+    fbcon_mac_putcs, fbcon_mac_revc, NULL
 };
 
 
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/fbcon-mfb.c m68k/drivers/video/fbcon-mfb.c
--- m68k-2.1.99/drivers/video/fbcon-mfb.c	Sun Apr 12 23:46:34 1998
+++ m68k/drivers/video/fbcon-mfb.c	Tue May  5 22:21:55 1998
@@ -155,7 +155,7 @@
 
 struct display_switch fbcon_mfb = {
     fbcon_mfb_setup, fbcon_mfb_bmove, fbcon_mfb_clear, fbcon_mfb_putc,
-    fbcon_mfb_putcs, fbcon_mfb_revc
+    fbcon_mfb_putcs, fbcon_mfb_revc, NULL
 };
 
 
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/fbcon-vga.c m68k/drivers/video/fbcon-vga.c
--- m68k-2.1.99/drivers/video/fbcon-vga.c	Thu Jan  1 01:00:00 1970
+++ m68k/drivers/video/fbcon-vga.c	Tue May  5 22:21:58 1998
@@ -0,0 +1,171 @@
+/*
+ *  linux/drivers/video/fbcon-vga.c -- Low level frame buffer operations for
+ *				       VGA characters/attributes
+ *
+ *	Created 28 Mar 1998 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/tty.h>
+#include <linux/console.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+
+#include <asm/io.h>
+
+#include "fbcon.h"
+#include "fbcon-vga.h"
+
+
+    /*
+     *  VGA screen access
+     */ 
+
+static inline void vga_writew(u16 val, u16 *addr)
+{
+#ifdef __powerpc__
+    st_le16(addr, val);
+#else
+    writew(val, (unsigned long)addr);
+#endif /* !__powerpc__ */
+}
+
+static inline u16 vga_readw(u16 *addr)
+{
+#ifdef __powerpc__
+    return ld_le16(addr);
+#else
+    return readw((unsigned long)addr);
+#endif /* !__powerpc__ */	
+}
+
+static inline void vga_memsetw(void *s, u16 c, unsigned int count)
+{
+    u16 *addr = (u16 *)s;
+
+    while (count) {
+	count--;
+	vga_writew(c, addr++);
+    }
+}
+
+static inline void vga_memmovew(u16 *to, u16 *from, unsigned int count)
+{
+    if (to < from) {
+	while (count) {
+	    count--;
+	    vga_writew(vga_readw(from++), to++);
+	}
+    } else {
+	from += count;
+	to += count;
+	while (count) {
+	    count--;
+	    vga_writew(vga_readw(--from), --to);
+	}
+    }
+}
+
+
+    /*
+     *  VGA characters/attributes
+     */
+
+void fbcon_vga_setup(struct display *p)
+{
+    p->next_line = p->line_length;
+    p->next_plane = 0;
+}
+
+void fbcon_vga_bmove(struct display *p, int sy, int sx, int dy, int dx,
+		     int height, int width)
+{
+    u16 *src, *dst;
+    int rows;
+
+    if (sx == 0 && dx == 0 && width == p->next_line/2) {
+	src = (u16 *)(p->screen_base+sy*p->next_line);
+	dst = (u16 *)(p->screen_base+dy*p->next_line);
+	vga_memmovew(dst, src, height*width);
+    } else if (dy < sy || (dy == sy && dx < sx)) {
+	src = (u16 *)(p->screen_base+sy*p->next_line+sx*2);
+	dst = (u16 *)(p->screen_base+dy*p->next_line+dx*2);
+	for (rows = height; rows-- ;) {
+	    vga_memmovew(dst, src, width);
+	    src += p->next_line/2;
+	    dst += p->next_line/2;
+	}
+    } else {
+	src = (u16 *)(p->screen_base+(sy+height-1)*p->next_line+sx*2);
+	dst = (u16 *)(p->screen_base+(dy+height-1)*p->next_line+dx*2);
+	for (rows = height; rows-- ;) {
+	    vga_memmovew(dst, src, width);
+	    src -= p->next_line/2;
+	    dst -= p->next_line/2;
+	}
+    }
+}
+
+void fbcon_vga_clear(struct vc_data *conp, struct display *p, int sy, int sx,
+		     int height, int width)
+{
+    u16 *dest = (u16 *)(p->screen_base+sy*p->next_line+sx*2);
+    int rows;
+
+    if (sx == 0 && width*2 == p->next_line)      
+	vga_memsetw(dest, conp->vc_video_erase_char, height*width);
+    else
+	for (rows = height; rows-- ; dest += p->next_line/2)
+	    vga_memsetw(dest, conp->vc_video_erase_char, width);
+}
+
+void fbcon_vga_putc(struct vc_data *conp, struct display *p, int c, int y,
+		    int x)
+{
+    u16 *dst = (u16 *)(p->screen_base+y*p->next_line+x*2);
+    vga_writew(conp->vc_attr << 8 | c, dst);
+}
+
+void fbcon_vga_putcs(struct vc_data *conp, struct display *p, const char *s,
+		     int count, int y, int x)
+{
+    u16 *dst = (u16 *)(p->screen_base+y*p->next_line+x*2);
+    u16 sattr = conp->vc_attr << 8;
+    while (count--)
+	vga_writew(sattr | ((int) (*s++) & 0xff), dst++);
+}
+
+void fbcon_vga_revc(struct display *p, int x, int y)
+{
+    u16 *dst = (u16 *)(p->screen_base+y*p->next_line+x*2);
+    u16 val = vga_readw(dst);
+    val = (val & 0x88ff) | ((val<<4) & 0x7000) | ((val>>4) & 0x0700);
+    vga_writew(val, dst);
+}
+
+
+    /*
+     *  `switch' for the low level operations
+     */
+
+struct display_switch fbcon_vga = {
+    fbcon_vga_setup, fbcon_vga_bmove, fbcon_vga_clear, fbcon_vga_putc,
+    fbcon_vga_putcs, fbcon_vga_revc, NULL
+};
+
+
+    /*
+     *  Visible symbols for modules
+     */
+
+EXPORT_SYMBOL(fbcon_vga);
+EXPORT_SYMBOL(fbcon_vga_setup);
+EXPORT_SYMBOL(fbcon_vga_bmove);
+EXPORT_SYMBOL(fbcon_vga_clear);
+EXPORT_SYMBOL(fbcon_vga_putc);
+EXPORT_SYMBOL(fbcon_vga_putcs);
+EXPORT_SYMBOL(fbcon_vga_revc);
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/fbcon-vga.h m68k/drivers/video/fbcon-vga.h
--- m68k-2.1.99/drivers/video/fbcon-vga.h	Thu Jan  1 01:00:00 1970
+++ m68k/drivers/video/fbcon-vga.h	Tue May  5 22:21:58 1998
@@ -0,0 +1,15 @@
+    /*
+     *  VGA characters/attributes
+     */
+
+extern struct display_switch fbcon_vga;
+extern void fbcon_vga_setup(struct display *p);
+extern void fbcon_vga_bmove(struct display *p, int sy, int sx, int dy, int dx,
+			    int height, int width);
+extern void fbcon_vga_clear(struct vc_data *conp, struct display *p, int sy,
+			    int sx, int height, int width);
+extern void fbcon_vga_putc(struct vc_data *conp, struct display *p, int c,
+			   int yy, int xx);
+extern void fbcon_vga_putcs(struct vc_data *conp, struct display *p,
+			    const char *s, int count, int yy, int xx);
+extern void fbcon_vga_revc(struct display *p, int xx, int yy);
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/fbcon.c m68k/drivers/video/fbcon.c
--- m68k-2.1.99/drivers/video/fbcon.c	Mon May  4 20:07:18 1998
+++ m68k/drivers/video/fbcon.c	Tue May  5 22:21:55 1998
@@ -24,6 +24,8 @@
  *			   Martin Schaller
  *			   Andreas Schwab
  *
+ *  Hardware cursor support added by Emmanuel Marty (core@ggi-project.org)
+ *
  *
  *  The low level operations for the various display memory organizations are
  *  now in separate source files.
@@ -39,7 +41,6 @@
  *  To do:
  *
  *    - Implement 16 plane mode (iplan2p16)
- *    - Hardware cursor
  *
  *
  *  This file is subject to the terms and conditions of the GNU General Public
@@ -101,8 +102,13 @@
 struct display fb_display[MAX_NR_CONSOLES];
 
 
-/* ++Geert: Sorry, no hardware cursor support at the moment;
-   use Atari alike software cursor */
+/*
+ * Emmanuel: fbcon will now use a hardware cursor if the
+ * low-level driver provides a non-NULL dispsw->cursor pointer,
+ * in which case the hardware should do blinking, etc.
+ *
+ * if dispsw->cursor is NULL, use Atari alike software cursor
+ */
 
 #if FLASHING_CURSOR
 static int cursor_drawn = 0;
@@ -164,7 +170,7 @@
 static int fbcon_get_font(struct vc_data *conp, int *w, int *h, char *data);
 static int fbcon_set_font(struct vc_data *conp, int w, int h, char *data);
 static int fbcon_set_palette(struct vc_data *conp, unsigned char *table);
-static int fbcon_scrolldelta(int lines);
+static int fbcon_scrolldelta(struct vc_data *conp, int lines);
 
 
 /*
@@ -530,21 +536,28 @@
     if (p->cursor_x == conp->vc_x && p->cursor_y == conp->vc_y &&
 	(mode == CM_ERASE) == !cursor_on)
 	return;
-    if (CURSOR_UNDRAWN ())
-	p->dispsw->revc(p, p->cursor_x, real_y(p, p->cursor_y));
-    p->cursor_x = conp->vc_x;
-    p->cursor_y = conp->vc_y;
-
-    switch (mode) {
-	case CM_ERASE:
-	    cursor_on = 0;
-	    break;
 
-	case CM_MOVE:
-	case CM_DRAW:
-	    vbl_cursor_cnt = CURSOR_DRAW_DELAY;
-	    cursor_on = 1;
-	    break;
+    if (p->dispsw->cursor) {
+	p->cursor_x = conp->vc_x;
+	p->cursor_y = conp->vc_y;
+	p->dispsw->cursor(p, mode, p->cursor_x, real_y(p, p->cursor_y));
+    } else {
+	if (CURSOR_UNDRAWN ())
+	    p->dispsw->revc(p, p->cursor_x, real_y(p, p->cursor_y));
+	p->cursor_x = conp->vc_x;
+	p->cursor_y = conp->vc_y;
+
+	switch (mode) {
+	    case CM_ERASE:
+		cursor_on = 0;
+		break;
+
+	    case CM_MOVE:
+	    case CM_DRAW:
+		vbl_cursor_cnt = CURSOR_DRAW_DELAY;
+		cursor_on = 1;
+		break;
+	}
     }
 }
 
@@ -1056,7 +1069,7 @@
     return p->fb_info->fbops->fb_set_cmap(&palette_cmap, 1, unit, p->fb_info);
 }
 
-static int fbcon_scrolldelta(int lines)
+static int fbcon_scrolldelta(struct vc_data *conp, int lines)
 {
 #if SUPPORT_SCROLLBACK
     int unit = fg_console; /* xxx */
@@ -1105,7 +1118,7 @@
     unsigned char *dst, *src;
     int i, j, n, x1, y1;
     int logo_depth, done = 0;
-	
+
     /* Set colors if visual is PSEUDOCOLOR and we have enough colors, or for
      * TRUECOLOR */
     if ((p->visual == FB_VISUAL_PSEUDOCOLOR && depth >= 4) ||
@@ -1366,6 +1379,7 @@
     (void *)fbcon_dummy_op,	/* fbcon_dummy_putc */
     (void *)fbcon_dummy_op,	/* fbcon_dummy_putcs */
     (void *)fbcon_dummy_op,	/* fbcon_dummy_revc */
+    NULL,			/* fbcon_dummy_cursor */
 };
 
 
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/fbcon.h m68k/drivers/video/fbcon.h
--- m68k-2.1.99/drivers/video/fbcon.h	Mon Mar 30 00:49:53 1998
+++ m68k/drivers/video/fbcon.h	Tue May  5 22:21:55 1998
@@ -29,6 +29,7 @@
     void (*putcs)(struct vc_data *conp, struct display *p, const char *s,
 		  int count, int yy, int xx);     
     void (*revc)(struct display *p, int xx, int yy);
+    void (*cursor)(struct display *p, int mode, int xx, int yy);
 }; 
 
 
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/macfb.c m68k/drivers/video/macfb.c
--- m68k-2.1.99/drivers/video/macfb.c	Mon May  4 20:07:18 1998
+++ m68k/drivers/video/macfb.c	Tue May  5 22:21:55 1998
@@ -423,7 +423,7 @@
 	if(err<0)
 	{
 		mac_boom(6);
-		return NULL;
+		return mem_start;
 	}
 
 	macfb_get_var(&disp.var, -1, &fb_info);
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/offb.c m68k/drivers/video/offb.c
--- m68k-2.1.99/drivers/video/offb.c	Mon May  4 20:07:18 1998
+++ m68k/drivers/video/offb.c	Tue May  5 22:21:55 1998
@@ -47,8 +47,6 @@
     volatile unsigned char *cmap_data;
 };
 
-static struct fb_info_offb fb_info[FB_MAX];
-
 #ifdef __powerpc__
 #define mach_eieio()	eieio()
 #else
@@ -62,7 +60,7 @@
      *  Interface used by the world
      */
 
-unsigned long offb_init(unsigned long mem_start);
+void offb_init(void);
 void offb_setup(char *options, int *ints);
 
 static int offb_open(struct fb_info *info);
@@ -277,8 +275,7 @@
 
 
 #ifdef CONFIG_FB_ATY
-extern unsigned long atyfb_of_init(unsigned long mem_start,
-				   struct device_node *dp);
+extern void atyfb_of_init(struct device_node *dp);
 
 static const char *aty_names[] = {
     "ATY,mach64", "ATY,XCLAIM", "ATY,264VT", "ATY,mach64ii", "ATY,264GT-B", 
@@ -286,13 +283,16 @@
     "ATY,XCLAIMVRPro", "ATY,mach64_3DU"
 };
 #endif /* CONFIG_FB_ATY */
+#ifdef CONFIG_FB_S3TRIO
+extern void s3triofb_init_of(struct device_node *dp);
+#endif /* CONFIG_FB_S3TRIO */
 
 
     /*
      *  Initialisation
      */
 
-__initfunc(unsigned long offb_init(unsigned long mem_start))
+__initfunc(void offb_init(void))
 {
     struct device_node *dp;
     int dpy, i, err, *pp, len;
@@ -306,23 +306,27 @@
 	if (!(dp = find_path_device(prom_display_paths[dpy])))
 	    continue;
 
-	info = &fb_info[dpy];
-	fix = &info->fix;
-	var = &info->var;
-	disp = &info->disp;
-
 	if (!ofonly) {
 #ifdef CONFIG_FB_ATY
 	    for (i = 0; i < sizeof(aty_names)/sizeof(*aty_names); i++)
 		if (!strcmp(dp->name, aty_names[i]))
 		    break;
 	    if (i < sizeof(aty_names)/sizeof(*aty_names)) {
-		mem_start = atyfb_of_init(mem_start, dp);
+		atyfb_of_init(dp);
 		continue;
 	    }
 #endif /* CONFIG_FB_ATY */
+#ifdef CONFIG_FB_S3TRIO
+            if (s3triofb_init_of(dp))
+                continue;
+#endif /* CONFIG_FB_S3TRIO */
 	}
 
+	info = kmalloc(sizeof(struct fb_info_offb), GFP_ATOMIC);
+	fix = &info->fix;
+	var = &info->var;
+	disp = &info->disp;
+
 	strcpy(fix->id, "OFfb ");
 	strncat(fix->id, dp->name, sizeof(fix->id));
 	fix->id[sizeof(fix->id)-1] = '\0';
@@ -330,6 +334,7 @@
 	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);
+	    kfree(info);
 	    continue;
 	}
 	if ((pp = (int *)get_property(dp, "width", &len)) != NULL
@@ -353,6 +358,7 @@
 		    break;
 	    if (i >= dp->n_addrs) {
 		printk("no framebuffer address found for %s\n", dp->full_name);
+		kfree(info);
 		continue;
 	    }
 	    address = (u_long)dp->addrs[i].address;
@@ -419,8 +425,10 @@
 	info->info.blank = &offbcon_blank;
 
 	err = register_framebuffer(&info->info);
-	if (err < 0)
-	    continue;
+	if (err < 0) {
+	    kfree(info);
+	    return;
+	}
 
 	for (i = 0; i < 16; i++) {
 	    int j = color_table[i];
@@ -456,7 +464,6 @@
 	}
 #endif /* CONFIG_FB_COMPAT_XPMAC) */
     }
-    return mem_start;
 }
 
 
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/skeletonfb.c m68k/drivers/video/skeletonfb.c
--- m68k-2.1.99/drivers/video/skeletonfb.c	Mon May  4 20:07:18 1998
+++ m68k/drivers/video/skeletonfb.c	Tue May  5 22:21:56 1998
@@ -298,7 +298,7 @@
     fbgen_do_set_var(var, 1, &fbinfo.gen);
     err = register_framebuffer(&fb_info.gen.info);
     if (err < 0)
-	return err;
+	return mem_start;
     fbgen_set_disp(-1, &fb_info.gen.info);
     fbgen_install_cmap(0, &fb_info.gen);
     printk("fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info.node),
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/tgafb.c m68k/drivers/video/tgafb.c
--- m68k-2.1.99/drivers/video/tgafb.c	Mon May  4 20:07:18 1998
+++ m68k/drivers/video/tgafb.c	Tue May  5 22:21:56 1998
@@ -274,7 +274,7 @@
      *  Interface to the low level console driver
      */
 
-unsigned long tgafb_init(unsigned long mem_start);
+void tgafb_init(void);
 static int tgafbcon_switch(int con, struct fb_info *info);
 static int tgafbcon_updatevar(int con, struct fb_info *info);
 static void tgafbcon_blank(int blank, struct fb_info *info);
@@ -453,7 +453,7 @@
      *  Initialisation
      */
 
-__initfunc(unsigned long tgafb_init(unsigned long mem_start))
+__initfunc(void tgafb_init(void))
 {
     int i, j, temp, err;
     unsigned char *cbp;
@@ -461,7 +461,7 @@
 
     pdev = pci_find_device(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA, NULL);
     if (!pdev)
-	return mem_start;
+	return;
     tga_mem_base = pdev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK;
 #ifdef DEBUG
     printk("tgafb_init: mem_base 0x%x\n", tga_mem_base);
@@ -480,7 +480,7 @@
 	    break;
 	default:
 	    printk("TGA type (0x%x) unrecognized!\n", tga_type);
-	    return mem_start;
+	    return;
     }
 
     tga_regs_base = ((unsigned long)tga_mem_base + TGA_REGS_OFFSET);
@@ -767,13 +767,12 @@
 
     err = register_framebuffer(&fb_info);
     if (err < 0)
-	return mem_start;
+	return;
 
     tgafb_set_var(&fb_var, -1, &fb_info);
 
     printk("fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info.node),
 	   fb_fix.id);
-    return mem_start;
 }
 
 
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/txtcon.c m68k/drivers/video/txtcon.c
--- m68k-2.1.99/drivers/video/txtcon.c	Mon May  4 20:07:18 1998
+++ m68k/drivers/video/txtcon.c	Tue May  5 22:21:56 1998
@@ -18,6 +18,7 @@
 #include <linux/types.h>
 #include <linux/kdev_t.h>
 #include <linux/console.h>
+#include <linux/init.h>
 
 
     /*
@@ -43,7 +44,7 @@
 static int txtcon_get_font(struct vc_data *conp, int *w, int *h, char *data);
 static int txtcon_set_font(struct vc_data *conp, int w, int h, char *data);
 static int txtcon_set_palette(struct vc_data *conp, unsigned char *table);
-static int txtcon_scrolldelta(int lines);
+static int txtcon_scrolldelta(struct vc_data *conp, int lines);
 
 
 static unsigned long txtcon_startup(unsigned long kmem_start,
@@ -140,11 +141,12 @@
 }
 
 
-static int txtcon_scrolldelta(int lines)
+static int txtcon_scrolldelta(struct vc_data *conp, int lines)
 {
     return -ENOSYS;
 }
 
+
 /* ====================================================================== */
 
     /*
@@ -166,5 +168,5 @@
     txtcon_get_font,
     txtcon_set_font,
     txtcon_set_palette,
-    txtcon_scrolldelta,
+    txtcon_scrolldelta
 };
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/vgacon.c m68k/drivers/video/vgacon.c
--- m68k-2.1.99/drivers/video/vgacon.c	Mon May  4 20:07:18 1998
+++ m68k/drivers/video/vgacon.c	Tue May  5 22:21:56 1998
@@ -40,7 +40,7 @@
  *
  *	- speed up scrolling by changing the screen origin
  *
- *	- add support for palette, loadable fonts and VESA blanking
+ *	- add support for loadable fonts and VESA blanking
  *
  * KNOWN PROBLEMS/TO DO ==================================================== */
 
@@ -84,8 +84,7 @@
  *  Interface used by the world
  */
 
-static unsigned long vgacon_startup(unsigned long kmem_start,
-				   const char **display_desc);
+static const char *vgacon_startup(void);
 static void vgacon_init(struct vc_data *conp);
 static void vgacon_deinit(struct vc_data *conp);
 static void vgacon_clear(struct vc_data *conp, int sy, int sx, int height,
@@ -103,7 +102,7 @@
 static int vgacon_get_font(struct vc_data *conp, int *w, int *h, char *data);
 static int vgacon_set_font(struct vc_data *conp, int w, int h, char *data);
 static int vgacon_set_palette(struct vc_data *conp, unsigned char *table);
-static int vgacon_scrolldelta(int lines);
+static int vgacon_scrolldelta(struct vc_data *conp, int lines);
 
 
 /*
@@ -116,8 +115,8 @@
 /* Description of the hardware situation */
 static unsigned long   vga_video_mem_base;	/* Base of video memory */
 static unsigned long   vga_video_mem_term;	/* End of video memory */
-static unsigned short  vga_video_port_reg;	/* Video register select port */
-static unsigned short  vga_video_port_val;	/* Video register value port */
+static u16             vga_video_port_reg;	/* Video register select port */
+static u16             vga_video_port_val;	/* Video register value port */
 static unsigned long   vga_video_num_columns;	/* Number of text columns */
 static unsigned long   vga_video_num_lines;	/* Number of text lines */
 static unsigned long   vga_video_size_row;
@@ -137,7 +136,7 @@
      *  VGA screen access
      */ 
 
-static inline void vga_writew(unsigned short val, unsigned short * addr)
+static inline void vga_writew(u16 val, u16 * addr)
 {
 #ifdef __powerpc__
 	st_le16(addr, val);
@@ -146,7 +145,7 @@
 #endif /* !__powerpc__ */
 }
 
-static inline unsigned short vga_readw(unsigned short * addr)
+static inline u16 vga_readw(u16 * addr)
 {
 #ifdef __powerpc__
 	return ld_le16(addr);
@@ -155,9 +154,9 @@
 #endif /* !__powerpc__ */	
 }
 
-static inline void vga_memsetw(void * s, unsigned short c, unsigned int count)
+static inline void vga_memsetw(void * s, u16 c, unsigned int count)
 {
-	unsigned short * addr = (unsigned short *) s;
+	u16 * addr = (u16 *) s;
 
 	while (count) {
 		count--;
@@ -165,8 +164,7 @@
 	}
 }
 
-static inline void vga_memmovew(unsigned short *to, unsigned short *from,
-				unsigned int count)
+static inline void vga_memmovew(u16 *to, u16 *from, unsigned int count)
 {
 	if (to < from) {
 	    while (count) {
@@ -209,11 +207,11 @@
 }
 
 
-__initfunc(static unsigned long vgacon_startup(unsigned long kmem_start,
-					       const char **display_desc))
+__initfunc(static const char *vgacon_startup(void))
 {
-	unsigned short saved;
-	unsigned short *p;
+	const char *display_desc = NULL;
+	u16 saved;
+	u16 *p;
 
 	vga_video_num_lines = ORIG_VIDEO_LINES;
 	vga_video_num_columns = ORIG_VIDEO_COLS;
@@ -229,14 +227,14 @@
 		{
 			vga_video_type = VIDEO_TYPE_EGAM;
 			vga_video_mem_term = 0xb8000 + VGA_OFFSET;
-			*display_desc = "EGA+";
+			display_desc = "EGA+";
 			request_region(0x3b0,16,"ega");
 		}
 		else
 		{
 			vga_video_type = VIDEO_TYPE_MDA;
 			vga_video_mem_term = 0xb2000 + VGA_OFFSET;
-			*display_desc = "*MDA";
+			display_desc = "*MDA";
 			request_region(0x3b0,12,"mda");
 			request_region(0x3bf, 1,"mda");
 		}
@@ -255,11 +253,11 @@
 
 			if (!ORIG_VIDEO_ISVGA) {
 				vga_video_type = VIDEO_TYPE_EGAC;
-				*display_desc = "EGA";
+				display_desc = "EGA";
 				request_region(0x3c0,32,"ega");
 			} else {
 				vga_video_type = VIDEO_TYPE_VGAC;
-				*display_desc = "VGA+";
+				display_desc = "VGA+";
 				request_region(0x3c0,32,"vga+");
 
 #ifdef VGA_CAN_DO_64KB
@@ -303,7 +301,7 @@
 		{
 			vga_video_type = VIDEO_TYPE_CGA;
 			vga_video_mem_term = 0xba000 + VGA_OFFSET;
-			*display_desc = "*CGA";
+			display_desc = "*CGA";
 			request_region(0x3d4,2,"cga");
 		}
 	}
@@ -312,17 +310,17 @@
 	 *	Find out if there is a graphics card present.
 	 *	Are there smarter methods around?
 	 */
-	p = (unsigned short *)vga_video_mem_base;
+	p = (u16 *)vga_video_mem_base;
 	saved = vga_readw(p);
 	vga_writew(0xAA55, p);
 	if (vga_readw(p) != 0xAA55) {
 		vga_writew(saved, p);
-		return kmem_start;
+		return NULL;
 	}
 	vga_writew(0x55AA, p);
 	if (vga_readw(p) != 0x55AA) {
 		vga_writew(saved, p);
-		return kmem_start;
+		return NULL;
 	}
 	vga_writew(saved, p);
 
@@ -346,7 +344,7 @@
 	if (!console_show_logo)
 	    console_show_logo = vgacon_show_logo;
 
-	return kmem_start;
+	return display_desc;
 }
 
 
@@ -479,13 +477,12 @@
     if (sx == 0 && dx == 0 && width == vga_video_num_columns) {
 	src = vga_video_mem_base + sy * vga_video_size_row;
 	dst = vga_video_mem_base + dy * vga_video_size_row;
-	vga_memmovew((unsigned short *)dst, (unsigned short *)src,
-		     height * width);
+	vga_memmovew((u16 *)dst, (u16 *)src, height * width);
     } else if (dy < sy || (dy == sy && dx < sx)) {
 	src = vga_video_mem_base + sy * vga_video_size_row + sx * 2;
 	dst = vga_video_mem_base + dy * vga_video_size_row + dx * 2;
 	for (rows = height; rows-- ;) {
-	    vga_memmovew((unsigned short *)dst, (unsigned short *)src, width);
+	    vga_memmovew((u16 *)dst, (u16 *)src, width);
 	    src += vga_video_size_row;
 	    dst += vga_video_size_row;
 	}
@@ -493,7 +490,7 @@
 	src = vga_video_mem_base + (sy+height-1) * vga_video_size_row + sx * 2;
 	dst = vga_video_mem_base + (dy+height-1) * vga_video_size_row + dx * 2;
 	for (rows = height; rows-- ;) {
-	    vga_memmovew((unsigned short *)dst, (unsigned short *)src, width);
+	    vga_memmovew((u16 *)dst, (u16 *)src, width);
 	    src -= vga_video_size_row;
 	    dst -= vga_video_size_row;
 	}
@@ -550,7 +547,7 @@
 	return 0;
 }
 
-static int vgacon_scrolldelta(int lines)
+static int vgacon_scrolldelta(struct vc_data *conp, int lines)
 {
     /* TODO */
     return -ENOSYS;
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/vgafb.c m68k/drivers/video/vgafb.c
--- m68k-2.1.99/drivers/video/vgafb.c	Thu Jan  1 01:00:00 1970
+++ m68k/drivers/video/vgafb.c	Tue May  5 22:21:58 1998
@@ -0,0 +1,739 @@
+/*
+ *  linux/drivers/video/vgafb.c -- VGA frame buffer device
+ *
+ *	Created 28 Mar 1998 by Geert Uytterhoeven
+ *	Hardware cursor support added on 14 Apr 1998 by Emmanuel Marty
+ *
+ *  This file is heavily based on vgacon.c. Read about its contributors there.
+ *
+ *  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 PROBLEMS/TO DO ===================================================== *
+ *
+ *	- monochrome attribute encoding (convert abscon <-> VGA style)
+ *
+ *	- speed up scrolling by changing the screen origin
+ *
+ *	- add support for loadable fonts and VESA blanking
+ *
+ *	- for now only VGA _text_ mode is supported
+ *
+ * KNOWN PROBLEMS/TO DO ==================================================== */
+
+
+#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/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/selection.h>
+#include <linux/console.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include "fbcon.h"
+#include "fbcon-vga.h"
+
+
+#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 */
+
+#define dac_reg	(0x3c8)
+#define dac_val	(0x3c9)
+
+#ifdef __powerpc__
+#define VGA_OFFSET _ISA_MEM_BASE;
+#else
+#define VGA_OFFSET 0x0
+#endif
+
+
+static int currcon = 0;
+static struct display disp;
+static struct fb_info fb_info;
+static struct { u_char red, green, blue, pad; } palette[16];
+
+static struct fb_fix_screeninfo fb_fix = { { 0, } };
+static struct fb_var_screeninfo fb_var = { 0, };
+
+
+/* Description of the hardware situation */
+static unsigned char vga_video_type;
+static unsigned long vga_video_mem_base;	/* Base of video memory */
+static unsigned long vga_video_mem_term;	/* 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 long vga_video_num_columns;	/* Number of text columns */
+static unsigned long vga_video_num_lines;	/* Number of text lines */
+static int vga_can_do_color = 0;
+
+
+    /*
+     *  VGA screen access
+     */ 
+
+static inline void vga_writew(u16 val, u16 *addr)
+{
+#ifdef __powerpc__
+    st_le16(addr, val);
+#else
+    writew(val, (unsigned long)addr);
+#endif /* !__powerpc__ */
+}
+
+static inline u16 vga_readw(u16 *addr)
+{
+#ifdef __powerpc__
+    return ld_le16(addr);
+#else
+    return readw((unsigned long)addr);
+#endif /* !__powerpc__ */	
+}
+
+static void vga_set_split(unsigned short linenum)
+{
+	unsigned long flags;
+	unsigned char overflow, fontsize;
+	
+	if (vga_video_type != VIDEO_TYPE_VGAC) {
+		return;
+	}
+
+	save_flags(flags); cli();
+
+	outb_p(0x07, vga_video_port_reg);
+	overflow = inb_p(vga_video_port_val);
+
+	outb_p(0x09, vga_video_port_reg);
+	fontsize = inb_p(vga_video_port_val);
+	
+	overflow &= ~0x10; overflow |= (linenum & 0x100) ? 0x10 : 0;
+	fontsize &= ~0x40; fontsize |= (linenum & 0x200) ? 0x40 : 0;
+	linenum  &=  0xff;
+
+	outb_p(0x18, vga_video_port_reg);
+	outb_p(linenum, vga_video_port_val);
+
+	outb_p(0x07, vga_video_port_reg);
+	outb_p(overflow, vga_video_port_val);
+
+	outb_p(0x09, vga_video_port_reg);
+	outb_p(fontsize, vga_video_port_val);
+
+	restore_flags(flags);
+}
+
+
+/*
+ * 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)
+{
+#ifndef SLOW_VGA
+    unsigned int v1, v2;
+
+    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
+}
+
+static inline void vga_set_origin(unsigned short offset)
+{
+	write_vga(12, offset);
+}
+
+
+    /*
+     *  Interface used by the world
+     */
+
+static int vgafb_open(struct fb_info *info);
+static int vgafb_release(struct fb_info *info);
+static int vgafb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			 struct fb_info *info);
+static int vgafb_get_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info);
+static int vgafb_set_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info);
+static int vgafb_pan_display(struct fb_var_screeninfo *var, int con,
+			     struct fb_info *info);
+static int vgafb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			  struct fb_info *info);
+static int vgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			  struct fb_info *info);
+static int vgafb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+		       u_long arg, int con, struct fb_info *info);
+
+
+    /*
+     *  Interface to the low level console driver
+     */
+
+void vgafb_init(void);
+void vgafb_setup(char *options, int *ints);
+static int vgafbcon_switch(int con, struct fb_info *info);
+static int vgafbcon_updatevar(int con, struct fb_info *info);
+static void vgafbcon_blank(int blank, struct fb_info *info);
+
+
+    /*
+     *  VGA text console with hardware cursor
+     */
+
+static struct display_switch fbcon_vgafb;
+
+
+    /*
+     *  Internal routines
+     */
+
+static int vgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+			   u_int *transp, struct fb_info *info);
+static int vgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			   u_int transp, struct fb_info *info);
+static void do_install_cmap(int con, struct fb_info *info);
+
+
+static struct fb_ops vgafb_ops = {
+    vgafb_open, vgafb_release, vgafb_get_fix, vgafb_get_var, vgafb_set_var,
+    vgafb_get_cmap, vgafb_set_cmap, vgafb_pan_display, vgafb_ioctl
+};
+
+
+    /*
+     *  Open/Release the frame buffer device
+     */
+
+static int vgafb_open(struct fb_info *info)
+
+{
+    /*
+     *  Nothing, only a usage count for the moment
+     */
+
+    MOD_INC_USE_COUNT;
+    return(0);
+}
+
+static int vgafb_release(struct fb_info *info)
+{
+    MOD_DEC_USE_COUNT;
+    return(0);
+}
+
+
+    /*
+     *  Get the Fixed Part of the Display
+     */
+
+static int vgafb_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 vgafb_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 vgafb_set_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info)
+{
+    struct display *display;
+    int oldbpp = -1, err;
+
+    if (con >= 0)
+	display = &fb_display[con];
+    else
+	display = &disp;	/* used during initialization */
+
+    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->accel_flags & FB_ACCELF_TEXT) ||
+	(var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+	return -EINVAL;
+    memcpy(var, &fb_var, sizeof(fb_var));
+
+    if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+	oldbpp = display->var.bits_per_pixel;
+	display->var = *var;
+	vga_set_origin(var->yoffset/video_font_height*fb_fix.line_length/2);
+    }
+    if (oldbpp != var->bits_per_pixel) {
+	if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
+	    return err;
+	do_install_cmap(con, info);
+    }
+    return 0;
+}
+
+
+    /*
+     *  Pan or Wrap the Display
+     *
+     *  This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
+     */
+
+static int vgafb_pan_display(struct fb_var_screeninfo *var, int con,
+			     struct fb_info *info)
+{
+    if (var->xoffset || var->yoffset+var->yres > var->yres_virtual)
+	return -EINVAL;
+
+    vga_set_origin(var->yoffset/video_font_height*fb_fix.line_length/2);
+    return 0;
+}
+
+
+    /*
+     *  Get the Colormap
+     */
+
+static int vgafb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			  struct fb_info *info)
+{
+    if (con == currcon) /* current console? */
+	return fb_get_cmap(cmap, &fb_display[con].var, kspc, vgafb_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 vgafb_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 == currcon) {		/* current console? */
+	err = fb_set_cmap(cmap, &fb_display[con].var, kspc, vgafb_setcolreg,
+			  info);
+	return err;
+    } else
+	fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+    return 0;
+}
+
+
+static int vgafb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+		       u_long arg, int con, struct fb_info *info)
+{
+    return -EINVAL;
+}
+
+
+    /*
+     *  Move hardware vga cursor
+     */
+
+static void vga_write_cursor(int location)
+{
+    write_vga(14, location);
+}
+
+static void fbcon_vgafb_cursor(struct display *p, int mode, int x, int y)
+{
+    switch (mode) {
+	case CM_ERASE:
+	   /* Emmanuel: hiding doesn't work properly on MediaGX.
+	      probably a Cyrix VSA bug. investigate. */
+	   vga_write_cursor(p->vrows * (p->next_line >> 1));
+	   break;
+
+	case CM_MOVE:
+	case CM_DRAW:
+	   vga_write_cursor(y*(p->next_line >> 1)+x);
+	   break;
+    }
+}
+
+
+    /*
+     *  Initialisation
+     */
+
+__initfunc(void vgafb_init(void))
+{
+    int err;
+    u16 saved;
+    u16 *p;
+
+    vga_video_num_lines = ORIG_VIDEO_LINES;
+    vga_video_num_columns = ORIG_VIDEO_COLS;
+
+    if (ORIG_VIDEO_MODE == 7) {		/* Is this a monochrome display? */
+	vga_video_mem_base = 0xb0000 + VGA_OFFSET;
+	vga_video_port_reg = 0x3b4;
+	vga_video_port_val = 0x3b5;
+	if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) {
+	    vga_video_type = VIDEO_TYPE_EGAM;
+	    vga_video_mem_term = 0xb8000 + VGA_OFFSET;
+	    strcpy(fb_fix.id, "EGA+");
+	    request_region(0x3b0, 16, "ega");
+	} else {
+	    vga_video_type = VIDEO_TYPE_MDA;
+	    vga_video_mem_term = 0xb2000 + VGA_OFFSET;
+	    strcpy(fb_fix.id, "*MDA");
+	    request_region(0x3b0, 12, "mda");
+	    request_region(0x3bf, 1, "mda");
+	}
+    } else {				/* If not, it is color. */
+	vga_can_do_color = 1;
+	vga_video_mem_base = 0xb8000  + VGA_OFFSET;
+	vga_video_port_reg = 0x3d4;
+	vga_video_port_val = 0x3d5;
+	if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) {
+	    int i;
+
+	    vga_video_mem_term = 0xc0000 + VGA_OFFSET;
+
+	    if (!ORIG_VIDEO_ISVGA) {
+		vga_video_type = VIDEO_TYPE_EGAC;
+		strcpy(fb_fix.id, "EGA");
+		request_region(0x3c0, 32, "ega");
+	    } else {
+		vga_video_type = VIDEO_TYPE_VGAC;
+		strcpy(fb_fix.id, "VGA+");
+		request_region(0x3c0, 32, "vga+");
+
+#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_video_mem_base = 0xa0000  + VGA_OFFSET;
+		vga_video_mem_term = 0xb0000  + VGA_OFFSET;
+		outb_p(6, 0x3ce);
+		outb_p(6, 0x3cf);
+#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(0x3da);
+		    outb_p(i, 0x3c0);
+		    outb_p(i, 0x3c0);
+		}
+		outb_p(0x20, 0x3c0);
+
+		/* now set the DAC registers back to their
+		 * default values */
+
+		for (i = 0; i < 16; i++) {
+		    outb_p(color_table[i], dac_reg);
+		    outb_p(default_red[i], dac_val);
+		    outb_p(default_grn[i], dac_val);
+		    outb_p(default_blu[i], dac_val);
+		}
+	    }
+	} else {
+		vga_video_type = VIDEO_TYPE_CGA;
+		vga_video_mem_term = 0xba000 + VGA_OFFSET;
+		strcpy(fb_fix.id, "*CGA");
+		request_region(0x3d4, 2, "cga");
+	}
+    }
+
+    /*
+     *	Find out if there is a graphics card present.
+     *	Are there smarter methods around?
+     */
+    p = (u16 *)vga_video_mem_base;
+    saved = vga_readw(p);
+    vga_writew(0xAA55, p);
+    if (vga_readw(p) != 0xAA55) {
+	vga_writew(saved, p);
+	return;
+    }
+    vga_writew(0x55AA, p);
+    if (vga_readw(p) != 0x55AA) {
+	vga_writew(saved, p);
+	return;
+    }
+    vga_writew(saved, p);
+
+    if (vga_video_type == VIDEO_TYPE_VGAC
+	|| vga_video_type == VIDEO_TYPE_EGAC
+	|| vga_video_type == VIDEO_TYPE_EGAM) {
+	    video_font_height = ORIG_VIDEO_POINTS;
+	    /* This may be suboptimal but is a safe bet - go with it */
+	    video_scan_lines =
+		    video_font_height * vga_video_num_lines;
+    }
+
+    fb_fix.smem_start = bus_to_virt(vga_video_mem_base);
+    fb_fix.smem_len = vga_video_mem_term-vga_video_mem_base;
+    fb_fix.type = FB_TYPE_VGA_TEXT;
+    fb_fix.type_aux = 0;
+    fb_fix.visual = FB_VISUAL_PSEUDOCOLOR;
+    fb_fix.xpanstep = 0;
+    fb_fix.ypanstep = video_font_height;
+    fb_fix.ywrapstep = 0;
+    fb_fix.line_length = 2*vga_video_num_columns;
+    fb_fix.mmio_start = NULL;
+    fb_fix.mmio_len = 0;
+    fb_fix.accel = FB_ACCEL_NONE;
+
+    fb_var.xres = vga_video_num_columns*8;
+    fb_var.yres = vga_video_num_lines*video_font_height;
+    fb_var.xres_virtual = fb_var.xres;
+    /* the cursor is put at the end of the video memory, hence the -2 */
+    fb_var.yres_virtual = ((fb_fix.smem_len-2)/fb_fix.line_length)*
+			  video_font_height;
+
+    fb_var.xoffset = fb_var.yoffset = 0;
+    fb_var.bits_per_pixel = 4;
+    fb_var.grayscale = !vga_can_do_color;
+    fb_var.red.offset = 0;
+    fb_var.red.length = 6;
+    fb_var.red.msb_right = 0;
+    fb_var.green.offset = 0;
+    fb_var.green.length = 6;
+    fb_var.green.msb_right = 0;
+    fb_var.blue.offset = 0;
+    fb_var.blue.length = 6;
+    fb_var.blue.msb_right = 0;
+    fb_var.transp.offset = 0;
+    fb_var.transp.length = 0;
+    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;
+    fb_var.pixclock = 39722;		/* 25.175 MHz */
+    fb_var.left_margin = 40;
+    fb_var.right_margin = 24;
+    fb_var.upper_margin = 39;
+    fb_var.lower_margin = 9;
+    fb_var.hsync_len = 96;
+    fb_var.vsync_len = 2;
+    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 = NULL;
+    disp.cmap.green = NULL;
+    disp.cmap.blue = NULL;
+    disp.cmap.transp = NULL;
+    disp.screen_base = fb_fix.smem_start;
+    disp.visual = fb_fix.visual;
+    disp.type = fb_fix.type;
+    disp.type_aux = fb_fix.type_aux;
+    disp.ypanstep = fb_fix.ypanstep;
+    disp.ywrapstep = fb_fix.ywrapstep;
+    disp.line_length = fb_fix.line_length;
+    disp.can_soft_blank = 1;
+    disp.inverse = 0;
+    disp.dispsw = &fbcon_vgafb;
+
+    strcpy(fb_info.modename, fb_fix.id);
+    fb_info.node = -1;
+    fb_info.fbops = &vgafb_ops;
+    fb_info.disp = &disp;
+    fb_info.fontname[0] = '\0';
+    fb_info.changevar = NULL;
+    fb_info.switch_con = &vgafbcon_switch;
+    fb_info.updatevar = &vgafbcon_updatevar;
+    fb_info.blank = &vgafbcon_blank;
+
+    err = register_framebuffer(&fb_info);
+    if (err < 0)
+	return;
+
+    vgafb_set_var(&fb_var, -1, &fb_info);
+
+    printk("fb%d: VGA frame buffer device, using %dK of video memory\n",
+	   GET_FB_IDX(fb_info.node), fb_fix.smem_len>>10);
+}
+
+__initfunc(void vgafb_setup(char *options, int *ints))
+{
+    /* nothing yet */
+}
+
+    /*
+     *  Update the `var' structure (called by fbcon.c)
+     */
+
+static int vgafbcon_updatevar(int con, struct fb_info *info)
+{
+	if (con == currcon) {
+		struct fb_var_screeninfo *var = &fb_display[currcon].var;
+
+		/* hardware scrolling */
+
+		vga_set_origin(var->yoffset / video_font_height *
+			fb_fix.line_length / 2);
+
+		vga_set_split(var->yres - ((var->vmode & FB_VMODE_YWRAP) ?
+			var->yoffset+1 : 0));
+	}
+
+	return 0;
+}
+
+static int vgafbcon_switch(int con, struct fb_info *info)
+{
+    /* Do we have to save the colormap? */
+    if (fb_display[currcon].cmap.len)
+	fb_get_cmap(&fb_display[currcon].cmap, &fb_display[currcon].var, 1,
+		    vgafb_getcolreg, info);
+
+    currcon = con;
+    /* Install new colormap */
+    do_install_cmap(con, info);
+    vgafbcon_updatevar(con, info);
+    return 0;
+}
+
+    /*
+     *  Blank the display.
+     */
+
+static void vgafbcon_blank(int blank, struct fb_info *info)
+{
+    int i;
+
+    outb_p(0, dac_reg);
+    if (blank)
+	for (i = 0; i < 16; i++) {
+	    outb_p(0, dac_val);
+	    outb_p(0, dac_val);
+	    outb_p(0, dac_val);
+	}
+    else
+	for (i = 0; i < 16; i++) {
+	    outb_p(palette[i].blue, dac_val);
+	    outb_p(palette[i].green, dac_val);
+	    outb_p(palette[i].blue, dac_val);
+	}
+}
+
+
+    /*
+     *  Read a single color register and split it into
+     *  colors/transparent. Return != 0 for invalid regno.
+     */
+
+static int vgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+			 u_int *transp, struct fb_info *info)
+{
+    if (regno > 15)
+	return 1;
+    *red = palette[regno].red;
+    *green = palette[regno].green;
+    *blue = palette[regno].blue;
+    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 vgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			 u_int transp, struct fb_info *info)
+{
+    if (regno > 15)
+	return 1;
+    palette[regno].red = red;
+    palette[regno].green = green;
+    palette[regno].blue = blue;
+
+    outb_p(regno, dac_reg);
+    outb_p(red, dac_val);
+    outb_p(green, dac_val);
+    outb_p(blue, dac_val);
+
+    return 0;
+}
+
+static void do_install_cmap(int con, struct fb_info *info)
+{
+    if (con != currcon)
+	return;
+    if (fb_display[con].cmap.len)
+	fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1,
+		    vgafb_setcolreg, info);
+    else
+	fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
+				    &fb_display[con].var, 1, vgafb_setcolreg,
+				    info);
+}
+
+
+    /*
+     *  VGA text console with hardware cursor
+     */
+
+static struct display_switch fbcon_vgafb = {
+    fbcon_vga_setup, fbcon_vga_bmove, fbcon_vga_clear, fbcon_vga_putc,
+    fbcon_vga_putcs, fbcon_vga_revc, fbcon_vgafb_cursor
+};
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/drivers/video/virgefb.c m68k/drivers/video/virgefb.c
--- m68k-2.1.99/drivers/video/virgefb.c	Mon May  4 20:07:18 1998
+++ m68k/drivers/video/virgefb.c	Tue May  5 22:21:56 1998
@@ -849,7 +849,7 @@
 	switch (display->var.bits_per_pixel) {
 #ifdef CONFIG_FBCON_CFB8
 	    case 8:
-		if (display->var.accel_text & FB_ACCELF_TEXT) {
+		if (display->var.accel_flags & FB_ACCELF_TEXT) {
 		    display->dispsw = &fbcon_virge8;
 #warning FIXME: We should reinit the graphics engine here
 		} else
@@ -1033,7 +1033,7 @@
 
 		CyberMem = ZTWO_VADDR(board_addr);
 		printk("CV3D detected running in Z2 mode ... not yet supported!\n");
-		return -ENODEV;
+		return mem_start;
 	}
 	else
 	{
@@ -1172,7 +1172,7 @@
 
 static struct display_switch fbcon_virge8 = {
    fbcon_cfb8_setup, fbcon_virge8_bmove, fbcon_virge8_clear, fbcon_cfb8_putc,
-   fbcon_cfb8_putcs, fbcon_cfb8_revc
+   fbcon_cfb8_putcs, fbcon_cfb8_revc, NULL
 };
 #endif
 
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/include/linux/console.h m68k/include/linux/console.h
--- m68k-2.1.99/include/linux/console.h	Mon May  4 20:07:20 1998
+++ m68k/include/linux/console.h	Tue May  5 22:21:57 1998
@@ -41,7 +41,7 @@
 	int	(*con_get_font)(struct vc_data *, int *, int *, char *);
 	int	(*con_set_font)(struct vc_data *, int, int, char *);
 	int	(*con_set_palette)(struct vc_data *, unsigned char *);
-	int	(*con_scrolldelta)(int);
+	int	(*con_scrolldelta)(struct vc_data *, int);
 };
 
 extern struct consw *conswitchp;
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/include/linux/fb.h m68k/include/linux/fb.h
--- m68k-2.1.99/include/linux/fb.h	Mon May  4 20:07:20 1998
+++ m68k/include/linux/fb.h	Tue May  5 22:21:58 1998
@@ -60,7 +60,7 @@
 	__u16 ypanstep;			/* zero if no hardware panning  */
 	__u16 ywrapstep;		/* zero if no hardware ywrap    */
 	__u32 line_length;		/* length of a line in bytes    */
-	unsigned char *mmio_start;	/* Start of Memory Mapped I/O   */
+	char *mmio_start;		/* Start of Memory Mapped I/O   */
 	__u32 mmio_len;			/* Length of Memory Mapped I/O  */
 	__u32 accel;			/* Type of acceleration available */
 	__u16 reserved[3];		/* Reserved for future compatibility */
@@ -271,6 +271,8 @@
    int (*updatevar)(int, struct fb_info*);
 					/* tell fb to update the vars */
    void (*blank)(int, struct fb_info*);	/* tell fb to (un)blank the screen */
+					/* arg = 0: unblank */
+					/* arg > 0: VESA level (arg-1) */
 
    /* From here on everything is device dependent */
 };
@@ -355,6 +357,12 @@
 		       struct fb_info *fb_info);
 extern struct fb_cmap *fb_default_cmap(int len);
 extern void fb_invert_cmaps(void);
+
+/* VEA Blanking Levels */
+#define VESA_NO_BLANKING	0
+#define VESA_VSYNC_SUSPEND	1
+#define VESA_HSYNC_SUSPEND	2
+#define VESA_POWERDOWN		3
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --exclude-from=/home/geert/diff-excludes-linux --new-file m68k-2.1.99/include/linux/keyboard.h m68k/include/linux/keyboard.h
--- m68k-2.1.99/include/linux/keyboard.h	Mon May  4 20:07:20 1998
+++ m68k/include/linux/keyboard.h	Mon May  4 22:25:18 1998
@@ -24,12 +24,6 @@
 extern const int max_vals[];
 extern unsigned short *key_maps[MAX_NR_KEYMAPS];
 extern unsigned short plain_map[NR_KEYS];
-extern unsigned short shift_map[NR_KEYS];
-extern unsigned short altgr_map[NR_KEYS];
-extern unsigned short ctrl_map[NR_KEYS];
-extern unsigned short shift_ctrl_map[NR_KEYS];
-extern unsigned short alt_map[NR_KEYS];
-extern unsigned short ctrl_alt_map[NR_KEYS];
 extern struct wait_queue * keypress_wait;
 #endif
 
--- m68k-2.1.99/drivers/block/ide-disk.c	Mon May  4 20:07:04 1998
+++ m68k/drivers/block/ide-disk.c	Wed May  6 00:24:27 1998
@@ -715,9 +715,6 @@
 		if (drive->cyl > drive->bios_cyl)
 			drive->bios_cyl = drive->cyl;
 	}
-	/* fix byte-ordering of buffer size field */
-	id->buf_size = le16_to_cpu(id->buf_size);
-
 	printk (KERN_INFO "%s: %.40s, %ldMB w/%dkB Cache, CHS=%d/%d/%d",
 	 drive->name, id->model, idedisk_capacity(drive)/2048L, id->buf_size/2,
 	 drive->bios_cyl, drive->bios_head, drive->bios_sect);

Greetings,

						Geert

--
Geert Uytterhoeven                     Geert.Uytterhoeven@cs.kuleuven.ac.be
Wavelets, Linux/{m68k~Amiga,PPC~CHRP}  http://www.cs.kuleuven.ac.be/~geert/
Department of Computer Science -- Katholieke Universiteit Leuven -- Belgium

