
	patch to cyberfb.c to handle S3 Aurora 64 V+ (used in Thinkpad 860)
	cyberfb.c is a fairly generic S3 fbcon driver
	half of this patch is byte ordering and PCI bus probing
	still doesn't work completely right - XF86_VGA16 on fbcon breaks it

--- /powerpc/dist-2.4.20/drivers/video/Config.in	Sun Apr 20 12:04:35 2003
+++ /powerpc/linux-2.4.20/drivers/video/Config.in	Mon Apr 21 09:12:53 2003
@@ -51,8 +51,8 @@
 	 bool '    Amiga AGA chipset support' CONFIG_FB_AMIGA_AGA
       fi
    fi
+   tristate '  S3 Trio (Amiga CyberVision) support' CONFIG_FB_CYBER
    if [ "$CONFIG_ZORRO" = "y" ]; then
-      tristate '  Amiga CyberVision support' CONFIG_FB_CYBER
       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
 	 bool '  Amiga CyberVision3D support (EXPERIMENTAL)' CONFIG_FB_VIRGE
 	 tristate '  Amiga RetinaZ3 support (EXPERIMENTAL)' CONFIG_FB_RETINAZ3
--- /powerpc/dist-2.4.20/drivers/video/cyberfb.c	Wed Nov 14 17:52:20 2001
+++ /powerpc/linux-2.4.20/drivers/video/cyberfb.c	Tue Apr 15 18:35:07 2003
@@ -85,6 +85,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/zorro.h>
+#include <linux/pci.h>
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
@@ -99,7 +100,7 @@
 #include <video/fbcon-cfb8.h>
 #include <video/fbcon-cfb16.h>
 
-/*#define CYBERFBDEBUG*/
+/* #define CYBERFBDEBUG */
 #ifdef CYBERFBDEBUG
 #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
 static void cv64_dump(void);
@@ -110,7 +111,26 @@
 #define wb_64(regs,reg,dat) (*(((volatile unsigned char *)regs) + reg) = dat)
 #define rb_64(regs, reg) (*(((volatile unsigned char *)regs) + reg))
 
-#define ww_64(regs,reg,dat) (*((volatile unsigned short *)(regs + reg) = dat)
+#if 0
+
+#define ww_64(regs,reg,dat) (*((volatile unsigned short *)(regs + reg)) = dat)
+#define rw_64(regs,reg)     (*((volatile unsigned short *)(regs + reg)))
+
+#define wl_64(regs,reg,dat) (*((volatile unsigned long *)(regs + reg)) = dat)
+#define rl_64(regs,reg)     (*((volatile unsigned long *)(regs + reg)))
+
+#else
+
+#define ww_64(regs,reg,dat) st_le16((volatile unsigned short *)(regs + reg), dat)
+#define rw_64(regs,reg)     ld_le16((volatile unsigned short *)(regs + reg))
+
+#define wl_64(regs,reg,dat) st_le32((volatile unsigned *)(regs + reg), dat)
+#define rl_64(regs,reg)     ld_le32((volatile unsigned *)(regs + reg))
+
+#endif
+
+/* Write 16 Bit VGA register */
+#define vgaw16(ba, reg, val) ww_64(ba, reg, val)
 
 struct cyberfb_par {
 	struct fb_var_screeninfo var;
@@ -148,6 +168,10 @@
 static unsigned long CyberMem_phys;
 static unsigned long CyberRegs_phys;
 
+static int disabled = 0;
+
+#define AURORA (CyberBase == NULL)
+
 /*
  *    Predefined Video Modes
  */
@@ -438,6 +462,8 @@
 	par->var.yres_virtual = var->yres_virtual;
 	par->var.xoffset = var->xoffset;
 	par->var.yoffset = var->yoffset;
+	if (var->bits_per_pixel != 8 && var->bits_per_pixel != 16)
+		return -EINVAL;
 	par->var.bits_per_pixel = var->bits_per_pixel;
 	par->var.grayscale = var->grayscale;
 	par->var.red = var->red;
@@ -621,7 +647,7 @@
 
 	DPRINTK("ENTER\n");
 	do {
-		status = *((u_short volatile *)(CyberRegs + S3_GP_STAT));
+		status = rw_64(CyberRegs, S3_GP_STAT);
 	} while (status & fifo);
 	DPRINTK("EXIT\n");
 }
@@ -635,7 +661,7 @@
 
 	DPRINTK("ENTER\n");
 	do {
-		status = *((u_short volatile *)(CyberRegs + S3_GP_STAT));
+		status = rw_64(CyberRegs, S3_GP_STAT);
 	} while (status & S3_HDW_BUSY);
 	DPRINTK("EXIT\n");
 }
@@ -669,19 +695,19 @@
 
 	Cyber_WaitQueue (0x8000);
 
-	*((u_short volatile *)(regs + S3_PIXEL_CNTL)) = 0xa000;
-	*((u_short volatile *)(regs + S3_FRGD_MIX)) = (0x0060 | mode);
+	ww_64(regs, S3_PIXEL_CNTL, 0xa000);
+	ww_64(regs, S3_FRGD_MIX, (0x0060 | mode));
 
-	*((u_short volatile *)(regs + S3_CUR_X)) = curx;
-	*((u_short volatile *)(regs + S3_CUR_Y)) = cury;
+	ww_64(regs, S3_CUR_X, curx);
+	ww_64(regs, S3_CUR_Y, cury);
 
-	*((u_short volatile *)(regs + S3_DESTX_DIASTP)) = destx;
-	*((u_short volatile *)(regs + S3_DESTY_AXSTP)) = desty;
+	ww_64(regs, S3_DESTX_DIASTP, destx);
+	ww_64(regs, S3_DESTY_AXSTP, desty);
 
-	*((u_short volatile *)(regs + S3_MIN_AXIS_PCNT)) = height - 1;
-	*((u_short volatile *)(regs + S3_MAJ_AXIS_PCNT)) = width  - 1;
+	ww_64(regs, S3_MIN_AXIS_PCNT, height - 1);
+	ww_64(regs, S3_MAJ_AXIS_PCNT, width  - 1);
 
-	*((u_short volatile *)(regs + S3_CMD)) = blitcmd;
+	ww_64(regs, S3_CMD, blitcmd);
 	DPRINTK("EXIT\n");
 }
 
@@ -697,19 +723,19 @@
 	DPRINTK("ENTER\n");
 	Cyber_WaitQueue (0x8000);
 
-	*((u_short volatile *)(regs + S3_PIXEL_CNTL)) = 0xa000;
-	*((u_short volatile *)(regs + S3_FRGD_MIX)) = (0x0020 | mode);
+	ww_64(regs, S3_PIXEL_CNTL, 0xa000);
+	ww_64(regs, S3_FRGD_MIX, (0x0020 | mode));
 
-	*((u_short volatile *)(regs + S3_MULT_MISC)) = 0xe000;
-	*((u_short volatile *)(regs + S3_FRGD_COLOR)) = color;
+	ww_64(regs, S3_MULT_MISC, 0xe000);
+	ww_64(regs, S3_FRGD_COLOR, color);
 
-	*((u_short volatile *)(regs + S3_CUR_X)) = x;
-	*((u_short volatile *)(regs + S3_CUR_Y)) = y;
+	ww_64(regs, S3_CUR_X, x);
+	ww_64(regs, S3_CUR_Y, y);
 
-	*((u_short volatile *)(regs + S3_MIN_AXIS_PCNT)) = height - 1;
-	*((u_short volatile *)(regs + S3_MAJ_AXIS_PCNT)) = width  - 1;
+	ww_64(regs, S3_MIN_AXIS_PCNT, height - 1);
+	ww_64(regs, S3_MAJ_AXIS_PCNT, width  - 1);
 
-	*((u_short volatile *)(regs + S3_CMD)) = blitcmd;
+	ww_64(regs, S3_CMD, blitcmd);
 	DPRINTK("EXIT\n");
 }
 
@@ -1051,7 +1077,57 @@
  *    Initialization
  */
 
-int __init cyberfb_init(void)
+int __init cyberfb_init_device(void)
+{
+	struct cyberfb_par par;
+	DPRINTK("ENTER\n");
+
+	DPRINTK("CyberBase=%08lx CyberRegs=%08lx CyberMem=%08lx\n",
+		CyberBase, (long unsigned int)CyberRegs, CyberMem);
+
+#ifdef CYBERFBDEBUG
+	DPRINTK("Register state just after mapping memory\n");
+	cv64_dump();
+#endif
+
+	strcpy(fb_info.modename, cyberfb_name);
+	fb_info.changevar = NULL;
+	fb_info.node = -1;
+	fb_info.fbops = &cyberfb_ops;
+	fb_info.disp = &disp;
+	fb_info.switch_con = &Cyberfb_switch;
+	fb_info.updatevar = &Cyberfb_updatevar;
+	fb_info.blank = &Cyberfb_blank;
+
+	Cyber_init();
+	/* ++Andre: set cyberfb default mode */
+	if (!cyberfb_usermode) {
+		cyberfb_default = cyberfb_predefined[CYBER8_DEFMODE].var;
+		DPRINTK("Use default cyber8 mode\n");
+	}
+	Cyber_decode_var(&cyberfb_default, &par);
+	Cyber_encode_var(&cyberfb_default, &par);
+
+	do_fb_set_var(&cyberfb_default, 1);
+	cyberfb_get_var(&fb_display[0].var, -1, &fb_info);
+	cyberfb_set_disp(-1, &fb_info);
+	do_install_cmap(0, &fb_info);
+
+	if (register_framebuffer(&fb_info) < 0) {
+		DPRINTK("EXIT - register_framebuffer failed\n");
+		return -1;
+	}
+
+	printk("fb%d: %s frame buffer device, using %ldK of video memory\n",
+	       GET_FB_IDX(fb_info.node), fb_info.modename, CyberSize>>10);
+
+	DPRINTK("EXIT\n");
+	return 0;
+}
+
+
+#ifdef CONFIG_ZORRO
+int __init cyberfb_init_zorro(void)
 {
 	unsigned long board_addr, board_size;
 	struct cyberfb_par par;
@@ -1059,70 +1135,105 @@
 	DPRINTK("ENTER\n");
 
 	while ((z = zorro_find_device(ZORRO_PROD_PHASE5_CYBERVISION64, z))) {
-	    board_addr = z->resource.start;
-	    board_size = z->resource.end-z->resource.start+1;
-	    CyberMem_phys = board_addr + 0x01400000;
-	    CyberRegs_phys = CyberMem_phys + 0x00c00000;
-	    if (!request_mem_region(CyberRegs_phys, 0x10000, "S3 Trio64"))
-		continue;
-	    if (!request_mem_region(CyberMem_phys, 0x400000, "RAM")) {
-		release_mem_region(CyberRegs_phys, 0x10000);
-		continue;
-	    }
-	    DPRINTK("board_addr=%08lx\n", board_addr);
-	    DPRINTK("board_size=%08lx\n", board_size);
-
-	    CyberBase = ioremap(board_addr, board_size);
-	    CyberRegs = CyberBase + 0x02000000;
-	    CyberMem = CyberBase + 0x01400000;
-	    DPRINTK("CyberBase=%08lx CyberRegs=%08lx CyberMem=%08lx\n",
-		    CyberBase, (long unsigned int)CyberRegs, CyberMem);
+		board_addr = z->resource.start;
+		board_size = z->resource.end-z->resource.start+1;
+		CyberMem_phys = board_addr + 0x01400000;
+		CyberRegs_phys = CyberMem_phys + 0x00c00000;
+		if (!request_mem_region(CyberRegs_phys, 0x10000, "S3 Trio64"))
+			continue;
+		if (!request_mem_region(CyberMem_phys, 0x400000, "RAM")) {
+			release_mem_region(CyberRegs_phys, 0x10000);
+			continue;
+		}
+		DPRINTK("board_addr=%08lx\n", board_addr);
+		DPRINTK("board_size=%08lx\n", board_size);
 
-#ifdef CYBERFBDEBUG
-	    DPRINTK("Register state just after mapping memory\n");
-	    cv64_dump();
-#endif
+		CyberBase = ioremap(board_addr, board_size);
+		CyberRegs = CyberBase + 0x02000000;
+		CyberMem = CyberBase + 0x01400000;
+		DPRINTK("CyberBase=%08lx CyberRegs=%08lx CyberMem=%08lx\n",
+			CyberBase, (long unsigned int)CyberRegs, CyberMem);
+
+		if (cyberfb_init_device() < 0) {
+			DPRINTK("EXIT - cyberfb_init_device failed\n");
+			release_mem_region(CyberMem_phys, 0x400000);
+			release_mem_region(CyberRegs_phys, 0x10000);
+			return -EINVAL;
+		}
 
-	    strcpy(fb_info.modename, cyberfb_name);
-	    fb_info.changevar = NULL;
-	    fb_info.node = -1;
-	    fb_info.fbops = &cyberfb_ops;
-	    fb_info.disp = &disp;
-	    fb_info.switch_con = &Cyberfb_switch;
-	    fb_info.updatevar = &Cyberfb_updatevar;
-	    fb_info.blank = &Cyberfb_blank;
-
-	    Cyber_init();
-	    /* ++Andre: set cyberfb default mode */
-	    if (!cyberfb_usermode) {
-		    cyberfb_default = cyberfb_predefined[CYBER8_DEFMODE].var;
-		    DPRINTK("Use default cyber8 mode\n");
-	    }
-	    Cyber_decode_var(&cyberfb_default, &par);
-	    Cyber_encode_var(&cyberfb_default, &par);
-
-	    do_fb_set_var(&cyberfb_default, 1);
-	    cyberfb_get_var(&fb_display[0].var, -1, &fb_info);
-	    cyberfb_set_disp(-1, &fb_info);
-	    do_install_cmap(0, &fb_info);
-
-	    if (register_framebuffer(&fb_info) < 0) {
-		    DPRINTK("EXIT - register_framebuffer failed\n");
-		    release_mem_region(CyberMem_phys, 0x400000);
-		    release_mem_region(CyberRegs_phys, 0x10000);
-		    return -EINVAL;
-	    }
-
-	    printk("fb%d: %s frame buffer device, using %ldK of video memory\n",
-		   GET_FB_IDX(fb_info.node), fb_info.modename, CyberSize>>10);
-
-	    /* TODO: This driver cannot be unloaded yet */
-	    MOD_INC_USE_COUNT;
-	    DPRINTK("EXIT\n");
-	    return 0;
+		DPRINTK("EXIT\n");
+		return 0;
 	}
 	return -ENXIO;
 }
+#endif
+
+int __init cyberfb_init_pci(void)
+{
+	struct pci_dev *dp = NULL;
+	unsigned long address, size;
+
+	if (disabled)
+		return -ENXIO;
+
+	dp = pci_find_device(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_TRIO, dp);
+	if (!dp)
+		dp = pci_find_device(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_AURORA64VP, dp);
+
+	if ((dp != 0) && ((dp->class >> 16) == PCI_BASE_CLASS_DISPLAY)) {
+
+		if (pci_enable_device(dp)) {
+			printk(KERN_ERR "cyberfb: failed to enable PCI device\n");
+			return -EINVAL;
+		}
+
+		/* There is only one memory region and it covers the mmio and fb areas */
+		address = pci_resource_start(dp, 0);
+		size    = pci_resource_len(dp, 0); /* size = 64*1024*1024; */
+		if (!request_mem_region(address, size, "S3 Trio")) {
+			printk("cyberfb: failed to allocate memory region\n");
+			return -EINVAL;
+		}
+
+		CyberBase = NULL;
+		CyberMem = ioremap(address, size);
+		/* XXX this memory mapping scheme works only on powerpc */
+		CyberRegs = (volatile unsigned char *) _IO_BASE;
+
+		CyberMem_phys = address;
+		/* XXX wrong, but is this (mmio_start) really used? */
+		CyberRegs_phys = 0;
+
+		if (cyberfb_init_device() < 0) {
+			DPRINTK("EXIT - cyberfb_init_device failed\n");
+			release_mem_region(address, size);
+			return -EINVAL;
+		}
+
+		return 0;
+	} else
+		return -ENODEV;
+}
+
+int __init cyberfb_init(void)
+{
+	int retval = -ENXIO;
+
+#ifdef CONFIG_ZORRO
+	retval = cyberfb_init_zorro();
+#endif
+
+	if (retval == -ENXIO) {
+		retval = cyberfb_init_pci();
+	}
+
+	if (retval == 0) {
+		/* TODO: This driver cannot be unloaded yet */
+		MOD_INC_USE_COUNT;
+	}
+
+	return retval;
+}
 
 
 static int Cyberfb_switch(int con, struct fb_info *info)
@@ -1583,22 +1694,28 @@
 	/*
 	 * Special CyberVision 64 board operations
 	 */
-	/* Reset board */
-	for (i = 0; i < 6; i++) {
-		cv64_write_port (0xff, CyberBase);
+
+	if (! AURORA) {
+		/* Reset board */
+		for (i = 0; i < 6; i++) {
+			cv64_write_port (0xff, CyberBase);
+		}
+		/* Return to operational mode */
+		cv64_write_port (0x8004, CyberBase);
 	}
-	/* Return to operational mode */
-	cv64_write_port (0x8004, CyberBase);
 	
 	/*
 	 * Generic (?) S3 chip wakeup
 	 */
-	/* Disable I/O & memory decoders, video in setup mode */
-	wb_64 (regs, SREG_VIDEO_SUBS_ENABLE, 0x10);
-	/* Video responds to cmds, addrs & data */
-	wb_64 (regs, SREG_OPTION_SELECT, 0x1);
-	/* Enable I/O & memory decoders, video in operational mode */
-	wb_64 (regs, SREG_VIDEO_SUBS_ENABLE, 0x8);
+
+	if (! AURORA) {
+		/* Disable I/O & memory decoders, video in setup mode */
+		wb_64 (regs, SREG_VIDEO_SUBS_ENABLE, 0x10);
+		/* Video responds to cmds, addrs & data */
+		wb_64 (regs, SREG_OPTION_SELECT, 0x1);
+		/* Enable I/O & memory decoders, video in operational mode */
+		wb_64 (regs, SREG_VIDEO_SUBS_ENABLE, 0x8);
+	}
 	/* VGA color emulation, enable cpu access to display mem */ 
 	wb_64 (regs, GREG_MISC_OUTPUT_W, 0x03);
 	/* Unlock S3 VGA regs */
@@ -1615,9 +1732,13 @@
 	 * bit 0=1: Enable enhaced mode functions
 	 * bit 2=0: Enhanced mode 8+ bits/pixel
 	 * bit 4=1: Enable linear addressing
-	 * bit 5=1: Enable MMIO
+	 * bit 5=1: Enable MMIO (except on Aurora 64V+)
 	 */
 	wb_64 (regs, ECR_ADV_FUNC_CNTL, 0x31);
+	if (AURORA) {
+		/* Enable new-style MMIO on Aurora 64V+ */
+		WCrt(regs, CRT_ID_EXT_MEM_CNTL_1, 0x08);
+	}
 	/*
 	 * bit 0=1: Color emulation
 	 * bit 1=1: Enable CPU access to display memory
@@ -1642,12 +1763,15 @@
 	/* Unlock S3 extensions to VGA Sequencer regs */
 	WSeq (regs, SEQ_ID_UNLOCK_EXT, 0x6);
 	
-	/* Enable 4MB fast page mode */
-	test = RSeq (regs, SEQ_ID_BUS_REQ_CNTL);
-	test = test | 1 << 6;
-	WSeq (regs, SEQ_ID_BUS_REQ_CNTL, test);
+	if (! AURORA) {
+		/* Enable 4MB fast page mode */
+		test = RSeq (regs, SEQ_ID_BUS_REQ_CNTL);
+		test = test | 1 << 6;
+		WSeq (regs, SEQ_ID_BUS_REQ_CNTL, test);
+	}
 	
 	/* Faster LUT write: 1 DCLK LUT write cycle, RAMDAC clk doubled */
+	/* XXX may be able to powerdown RAMDAC on Aurora 64V+ if no CRT */
 	WSeq (regs, SEQ_ID_RAMDAC_CNTL, 0xC0);
 
 	/* Clear immediate clock load bit */
@@ -1750,8 +1874,8 @@
 
 	wb_64 (regs, VDAC_MASK, 0xFF);
 
-	*((unsigned long *) (regs + ECR_FRGD_COLOR)) = 0xFF;
-	*((unsigned long *) (regs + ECR_BKGD_COLOR)) = 0;
+	wl_64 (regs, ECR_FRGD_COLOR, 0xFF);
+	wl_64 (regs, ECR_BKGD_COLOR, 0);
 
 	/* Colors initially set to grayscale */
 
@@ -1823,7 +1947,7 @@
 	gfx_on_off (0, regs);
 
 	/* Pass-through */
-	cvscreen (0, CyberBase);
+	if (! AURORA) cvscreen (0, CyberBase);
 
 	DPRINTK("EXIT\n");
 }
@@ -2060,9 +2184,11 @@
   test = RCrt (regs, CRT_ID_EXT_MISC_CNTL_2);
   test &= 0xD;
 	
-  /* Clear roxxler byte-swapping... */
-  cv64_write_port (0x0040, CyberBase);
-  cv64_write_port (0x0020, CyberBase);
+  if (! AURORA) {
+	  /* Clear roxxler byte-swapping... */
+	  cv64_write_port (0x0040, CyberBase);
+	  cv64_write_port (0x0020, CyberBase);
+  }
 	
   switch (video_mode->bits_per_pixel) {
   case 1:
@@ -2081,14 +2207,14 @@
     break;
 		
   case 15:
-    cv64_write_port (0x8020, CyberBase);
+    if (! AURORA) cv64_write_port (0x8020, CyberBase);
     clock_mode = 0x30;
     HDE = video_mode->xres / 4;
     cr50 |= 0x10;
     break;
 		
   case 16:
-    cv64_write_port (0x8020, CyberBase);
+    if (! AURORA) cv64_write_port (0x8020, CyberBase);
     clock_mode = 0x50;
     HDE = video_mode->xres / 4;
     cr50 |= 0x10;
@@ -2096,7 +2222,7 @@
 		
   case 24:
   case 32:
-    cv64_write_port (0x8040, CyberBase);
+    if (! AURORA) cv64_write_port (0x8040, CyberBase);
     clock_mode = 0xD0;
     HDE = video_mode->xres / 2;
     cr50 |= 0x30;
@@ -2207,7 +2333,7 @@
   gfx_on_off (0, (volatile unsigned char *) regs);
 	
   /* Pass-through */
-  cvscreen (0, CyberBase);
+  if (! AURORA) cvscreen (0, CyberBase);
 
 DPRINTK("EXIT\n");
 }
--- /powerpc/dist-2.4.20/drivers/video/cyberfb.h	Wed Aug 15 04:22:16 2001
+++ /powerpc/linux-2.4.20/drivers/video/cyberfb.h	Tue Apr 15 10:07:07 2003
@@ -120,10 +120,6 @@
 #define GRFBBOPset		0xf	/* 1 */
 
 
-/* Write 16 Bit VGA register */
-#define vgaw16(ba, reg, val) \
-*((unsigned short *)  (((volatile unsigned char *)ba)+reg)) = val
-
 /*
  * Defines for the used register addresses (mw)
  *
