From: Ralf Baechle <ralf@linux-mips.org>

This patch adds the GBE video driver for the video system in SGI IP32
aka O2 and it's i386-based equivalent the Visual Workstation.
                                                                                
This driver obsoletes sgivwfb.c; but I'd prefer to play safe and remove
it after some additional time, just in case.


---

 25-akpm/drivers/video/Kconfig  |   15 
 25-akpm/drivers/video/Makefile |    1 
 25-akpm/drivers/video/fbmem.c  |    5 
 25-akpm/drivers/video/gbefb.c  | 1200 +++++++++++++++++++++++++++++++++++++++++
 25-akpm/include/video/gbe.h    |  317 ++++++++++
 5 files changed, 1538 insertions(+)

diff -puN drivers/video/fbmem.c~mips-gbe-video-driver drivers/video/fbmem.c
--- 25/drivers/video/fbmem.c~mips-gbe-video-driver	Thu Apr 29 15:45:57 2004
+++ 25-akpm/drivers/video/fbmem.c	Thu Apr 29 15:45:57 2004
@@ -121,6 +121,8 @@ extern int sun3fb_init(void);
 extern int sun3fb_setup(char *);
 extern int sgivwfb_init(void);
 extern int sgivwfb_setup(char*);
+extern int gbefb_init(void);
+extern int gbefb_setup(char*);
 extern int rivafb_init(void);
 extern int rivafb_setup(char*);
 extern int tdfxfb_init(void);
@@ -307,6 +309,9 @@ static struct {
 #ifdef CONFIG_FB_SGIVW
 	{ "sgivwfb", sgivwfb_init, sgivwfb_setup },
 #endif
+#ifdef CONFIG_FB_GBE
+	{ "gbefb", gbefb_init, gbefb_setup },
+#endif
 #ifdef CONFIG_FB_ACORN
 	{ "acornfb", acornfb_init, acornfb_setup },
 #endif
diff -puN /dev/null drivers/video/gbefb.c
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/drivers/video/gbefb.c	Thu Apr 29 15:45:57 2004
@@ -0,0 +1,1200 @@
+/*
+ *  SGI GBE frame buffer driver
+ *
+ *  Copyright (C) 1999 Silicon Graphics, Inc. - Jeffrey Newquist
+ *  Copyright (C) 2002 Vivien Chappelier <vivien.chappelier@linux-mips.org>
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+
+#ifdef CONFIG_X86
+#include <asm/mtrr.h>
+#endif
+#ifdef CONFIG_MIPS
+#include <asm/addrspace.h>
+#endif
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/tlbflush.h>
+
+#include <video/gbe.h>
+
+static struct sgi_gbe *gbe;
+
+struct gbefb_par {
+	struct fb_var_screeninfo var;
+	struct gbe_timing_info timing;
+	int valid;
+};
+
+#ifdef CONFIG_SGI_IP32
+#define GBE_BASE	0x16000000 /* SGI O2 */
+#endif
+
+#ifdef CONFIG_X86_VISWS
+#define GBE_BASE	0xd0000000 /* SGI Visual Workstation */
+#endif
+
+/* macro for fastest write-though access to the framebuffer */
+#ifdef CONFIG_MIPS
+#ifdef CONFIG_CPU_R10000
+#define pgprot_fb(_prot) (((_prot) & (~_CACHE_MASK)) | _CACHE_UNCACHED_ACCELERATED)
+#else
+#define pgprot_fb(_prot) (((_prot) & (~_CACHE_MASK)) | _CACHE_CACHABLE_NO_WA)
+#endif
+#endif
+#ifdef CONFIG_X86
+#define pgprot_fb(_prot) ((_prot) | _PAGE_PCD)
+#endif
+
+/*
+ *  RAM we reserve for the frame buffer. This defines the maximum screen
+ *  size
+ */
+#if CONFIG_FB_GBE_MEM > 8
+#error GBE Framebuffer cannot use more than 8MB of memory
+#endif
+
+#define TILE_SHIFT 16
+#define TILE_SIZE (1 << TILE_SHIFT)
+#define TILE_MASK (TILE_SIZE - 1)
+
+static unsigned int gbe_mem_size = CONFIG_FB_GBE_MEM * 1024*1024;
+static void *gbe_mem;
+static dma_addr_t gbe_dma_addr;
+unsigned long gbe_mem_phys;
+
+static struct {
+	uint16_t *cpu;
+	dma_addr_t dma;
+} gbe_tiles;
+
+static int gbe_revision;
+
+static struct fb_info fb_info;
+static int ypan, ywrap;
+
+static uint32_t pseudo_palette[256];
+
+static char *mode_option __initdata = NULL;
+
+/* default CRT mode */
+static struct fb_var_screeninfo default_var_CRT __initdata = {
+	/* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
+	.xres		= 640,
+	.yres		= 480,
+	.xres_virtual	= 640,
+	.yres_virtual	= 480,
+	.xoffset	= 0,
+	.yoffset	= 0,
+	.bits_per_pixel	= 8,
+	.grayscale	= 0,
+	.red		= { 0, 8, 0 },
+	.green		= { 0, 8, 0 },
+	.blue		= { 0, 8, 0 },
+	.transp		= { 0, 0, 0 },
+	.nonstd		= 0,
+	.activate	= 0,
+	.height		= -1,
+	.width		= -1,
+	.accel_flags	= 0,
+	.pixclock	= 39722,	/* picoseconds */
+	.left_margin	= 48,
+	.right_margin	= 16,
+	.upper_margin	= 33,
+	.lower_margin	= 10,
+	.hsync_len	= 96,
+	.vsync_len	= 2,
+	.sync		= 0,
+	.vmode		= FB_VMODE_NONINTERLACED,
+};
+
+/* default LCD mode */
+static struct fb_var_screeninfo default_var_LCD __initdata = {
+	/* 1600x1024, 8 bpp */
+	.xres		= 1600,
+	.yres		= 1024,
+	.xres_virtual	= 1600,
+	.yres_virtual	= 1024,
+	.xoffset	= 0,
+	.yoffset	= 0,
+	.bits_per_pixel	= 8,
+	.grayscale	= 0,
+	.red		= { 0, 8, 0 },
+	.green		= { 0, 8, 0 },
+	.blue		= { 0, 8, 0 },
+	.transp		= { 0, 0, 0 },
+	.nonstd		= 0,
+	.activate	= 0,
+	.height		= -1,
+	.width		= -1,
+	.accel_flags	= 0,
+	.pixclock	= 9353,
+	.left_margin	= 20,
+	.right_margin	= 30,
+	.upper_margin	= 37,
+	.lower_margin	= 3,
+	.hsync_len	= 20,
+	.vsync_len	= 3,
+	.sync		= 0,
+	.vmode		= FB_VMODE_NONINTERLACED
+};
+
+/* default modedb mode */
+/* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */
+static struct fb_videomode default_mode_CRT __initdata = {
+	.refresh	= 60,
+	.xres		= 640,
+	.yres		= 480,
+	.pixclock	= 39722,
+	.left_margin	= 48,
+	.right_margin	= 16,
+	.upper_margin	= 33,
+	.lower_margin	= 10,
+	.hsync_len	= 96,
+	.vsync_len	= 2,
+	.sync		= 0,
+	.vmode		= FB_VMODE_NONINTERLACED,
+};
+/* 1600x1024 SGI flatpanel 1600sw */
+static struct fb_videomode default_mode_LCD __initdata = {
+	/* 1600x1024, 8 bpp */
+	.xres		= 1600,
+	.yres		= 1024,
+	.pixclock	= 9353,
+	.left_margin	= 20,
+	.right_margin	= 30,
+	.upper_margin	= 37,
+	.lower_margin	= 3,
+	.hsync_len	= 20,
+	.vsync_len	= 3,
+	.vmode		= FB_VMODE_NONINTERLACED,
+};
+
+struct fb_videomode *default_mode = &default_mode_CRT;
+struct fb_var_screeninfo *default_var = &default_var_CRT;
+
+static int flat_panel_enabled = 0;
+
+static struct gbefb_par par_current;
+
+static void gbe_reset(void)
+{
+	/* Turn on dotclock PLL */
+	gbe->ctrlstat = 0x300aa000;
+}
+
+
+/*
+ * Function:	gbe_turn_off
+ * Parameters:	(None)
+ * Description:	This should turn off the monitor and gbe.  This is used
+ *              when switching between the serial console and the graphics
+ *              console.
+ */
+
+void gbe_turn_off(void)
+{
+	int i;
+	unsigned int val, x, y, vpixen_off;
+
+	/* check if pixel counter is on */
+	val = gbe->vt_xy;
+	if (GET_GBE_FIELD(VT_XY, FREEZE, val) == 1)
+		return;
+
+	/* turn off DMA */
+	val = gbe->ovr_control;
+	SET_GBE_FIELD(OVR_CONTROL, OVR_DMA_ENABLE, val, 0);
+	gbe->ovr_control = val;
+	udelay(1000);
+	val = gbe->frm_control;
+	SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 0);
+	gbe->frm_control = val;
+	udelay(1000);
+	val = gbe->did_control;
+	SET_GBE_FIELD(DID_CONTROL, DID_DMA_ENABLE, val, 0);
+	gbe->did_control = val;
+	udelay(1000);
+
+	/* We have to wait through two vertical retrace periods before
+	 * the pixel DMA is turned off for sure. */
+	for (i = 0; i < 10000; i++) {
+		val = gbe->frm_inhwctrl;
+		if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, val)) {
+			udelay(10);
+		} else {
+			val = gbe->ovr_inhwctrl;
+			if (GET_GBE_FIELD(OVR_INHWCTRL, OVR_DMA_ENABLE, val)) {
+				udelay(10);
+			} else {
+				val = gbe->did_inhwctrl;
+				if (GET_GBE_FIELD(DID_INHWCTRL, DID_DMA_ENABLE, val)) {
+					udelay(10);
+				} else
+					break;
+			}
+		}
+	}
+	if (i == 10000)
+		printk(KERN_ERR "gbefb: turn off DMA timed out\n");
+
+	/* wait for vpixen_off */
+	val = gbe->vt_vpixen;
+	vpixen_off = GET_GBE_FIELD(VT_VPIXEN, VPIXEN_OFF, val);
+
+	for (i = 0; i < 100000; i++) {
+		val = gbe->vt_xy;
+		x = GET_GBE_FIELD(VT_XY, X, val);
+		y = GET_GBE_FIELD(VT_XY, Y, val);
+		if (y < vpixen_off)
+			break;
+		udelay(1);
+	}
+	if (i == 100000)
+		printk(KERN_ERR
+		       "gbefb: wait for vpixen_off timed out\n");
+	for (i = 0; i < 10000; i++) {
+		val = gbe->vt_xy;
+		x = GET_GBE_FIELD(VT_XY, X, val);
+		y = GET_GBE_FIELD(VT_XY, Y, val);
+		if (y > vpixen_off)
+			break;
+		udelay(1);
+	}
+	if (i == 10000)
+		printk(KERN_ERR "gbefb: wait for vpixen_off timed out\n");
+
+	/* turn off pixel counter */
+	val = 0;
+	SET_GBE_FIELD(VT_XY, FREEZE, val, 1);
+	gbe->vt_xy = val;
+	udelay(10000);
+	for (i = 0; i < 10000; i++) {
+		val = gbe->vt_xy;
+		if (GET_GBE_FIELD(VT_XY, FREEZE, val) != 1)
+			udelay(10);
+		else
+			break;
+	}
+	if (i == 10000)
+		printk(KERN_ERR "gbefb: turn off pixel clock timed out\n");
+
+	/* turn off dot clock */
+	val = gbe->dotclock;
+	SET_GBE_FIELD(DOTCLK, RUN, val, 0);
+	gbe->dotclock = val;
+	udelay(10000);
+	for (i = 0; i < 10000; i++) {
+		val = gbe->dotclock;
+		if (GET_GBE_FIELD(DOTCLK, RUN, val))
+			udelay(10);
+		else
+			break;
+	}
+	if (i == 10000)
+		printk(KERN_ERR "gbefb: turn off dotclock timed out\n");
+
+	/* reset the frame DMA FIFO */
+	val = gbe->frm_size_tile;
+	SET_GBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, val, 1);
+	gbe->frm_size_tile = val;
+	SET_GBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, val, 0);
+	gbe->frm_size_tile = val;
+}
+
+static void gbe_turn_on(void)
+{
+	unsigned int val, i;
+
+	/*
+	 * Check if pixel counter is off, for unknown reason this
+	 * code hangs Visual Workstations
+	 */
+	if (gbe_revision < 2) {
+		val = gbe->vt_xy;
+		if (GET_GBE_FIELD(VT_XY, FREEZE, val) == 0)
+			return;
+	}
+
+	/* turn on dot clock */
+	val = gbe->dotclock;
+	SET_GBE_FIELD(DOTCLK, RUN, val, 1);
+	gbe->dotclock = val;
+	udelay(10000);
+	for (i = 0; i < 10000; i++) {
+		val = gbe->dotclock;
+		if (GET_GBE_FIELD(DOTCLK, RUN, val) != 1)
+			udelay(10);
+		else
+			break;
+	}
+	if (i == 10000)
+		printk(KERN_ERR "gbefb: turn on dotclock timed out\n");
+
+	/* turn on pixel counter */
+	val = 0;
+	SET_GBE_FIELD(VT_XY, FREEZE, val, 0);
+	gbe->vt_xy = val;
+	udelay(10000);
+	for (i = 0; i < 10000; i++) {
+		val = gbe->vt_xy;
+		if (GET_GBE_FIELD(VT_XY, FREEZE, val))
+			udelay(10);
+		else
+			break;
+	}
+	if (i == 10000)
+		printk(KERN_ERR "gbefb: turn on pixel clock timed out\n");
+
+	/* turn on DMA */
+	val = gbe->frm_control;
+	SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 1);
+	gbe->frm_control = val;
+	udelay(1000);
+	for (i = 0; i < 10000; i++) {
+		val = gbe->frm_inhwctrl;
+		if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, val) != 1)
+			udelay(10);
+		else
+			break;
+	}
+	if (i == 10000)
+		printk(KERN_ERR "gbefb: turn on DMA timed out\n");
+}
+
+/*
+ *  Blank the display.
+ */
+static int gbefb_blank(int blank, struct fb_info *info)
+{
+	/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+	switch (blank) {
+	case 0:		/* unblank */
+		gbe_turn_on();
+		break;
+
+	case 1:		/* blank */
+		gbe_turn_off();
+		break;
+
+	default:
+		/* Nothing */
+		break;
+	}
+	return 0;
+}
+
+/*
+ *  Setup flatpanel related registers.
+ */
+static void gbefb_setup_flatpanel(struct gbe_timing_info *timing)
+{
+	int fp_wid, fp_hgt, fp_vbs, fp_vbe;
+	u32 outputVal = 0;
+
+	SET_GBE_FIELD(VT_FLAGS, HDRV_INVERT, outputVal,
+		(timing->flags & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1);
+	SET_GBE_FIELD(VT_FLAGS, VDRV_INVERT, outputVal,
+		(timing->flags & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1);
+	gbe->vt_flags = outputVal;
+
+	/* Turn on the flat panel */
+	fp_wid = 1600;
+	fp_hgt = 1024;
+	fp_vbs = 0;
+	fp_vbe = 1600;
+	timing->pll_m = 4;
+	timing->pll_n = 1;
+	timing->pll_p = 0;
+
+	outputVal = 0;
+	SET_GBE_FIELD(FP_DE, ON, outputVal, fp_vbs);
+	SET_GBE_FIELD(FP_DE, OFF, outputVal, fp_vbe);
+	gbe->fp_de = outputVal;
+	outputVal = 0;
+	SET_GBE_FIELD(FP_HDRV, OFF, outputVal, fp_wid);
+	gbe->fp_hdrv = outputVal;
+	outputVal = 0;
+	SET_GBE_FIELD(FP_VDRV, ON, outputVal, 1);
+	SET_GBE_FIELD(FP_VDRV, OFF, outputVal, fp_hgt + 1);
+	gbe->fp_vdrv = outputVal;
+}
+
+struct gbe_pll_info {
+	int clock_rate;
+	int fvco_min;
+	int fvco_max;
+};
+
+static struct gbe_pll_info gbe_pll_table[2] = {
+	{ 20, 80, 220 },
+	{ 27, 80, 220 },
+};
+
+static int compute_gbe_timing(struct fb_var_screeninfo *var,
+			      struct gbe_timing_info *timing)
+{
+	int pll_m, pll_n, pll_p, error, best_m, best_n, best_p, best_error;
+	int pixclock;
+	struct gbe_pll_info *gbe_pll;
+
+	if (gbe_revision < 2)
+		gbe_pll = &gbe_pll_table[0];
+	else
+		gbe_pll = &gbe_pll_table[1];
+
+	/* Determine valid resolution and timing
+	 * GBE crystal runs at 20Mhz or 27Mhz
+	 * pll_m, pll_n, pll_p define the following frequencies
+	 * fvco = pll_m * 20Mhz / pll_n
+	 * fout = fvco / (2**pll_p) */
+	best_error = 1000000000;
+	best_n = best_m = best_p = 0;
+	for (pll_p = 0; pll_p < 4; pll_p++)
+		for (pll_m = 1; pll_m < 256; pll_m++)
+			for (pll_n = 1; pll_n < 64; pll_n++) {
+				pixclock = (1000000 / gbe_pll->clock_rate) *
+						(pll_n << pll_p) / pll_m;
+
+				error = var->pixclock - pixclock;
+
+				if (error < 0)
+					error = -error;
+
+				if (error < best_error &&
+				    pll_m / pll_n >
+				    gbe_pll->fvco_min / gbe_pll->clock_rate &&
+ 				    pll_m / pll_n <
+				    gbe_pll->fvco_max / gbe_pll->clock_rate) {
+					best_error = error;
+					best_m = pll_m;
+					best_n = pll_n;
+					best_p = pll_p;
+				}
+			}
+
+	if (!best_n || !best_m)
+		return -EINVAL;	/* Resolution to high */
+
+	pixclock = (1000000 / gbe_pll->clock_rate) *
+		(best_n << best_p) / best_m;
+
+	/* set video timing information */
+	if (timing) {
+		timing->width = var->xres;
+		timing->height = var->yres;
+		timing->pll_m = best_m;
+		timing->pll_n = best_n;
+		timing->pll_p = best_p;
+		timing->cfreq = gbe_pll->clock_rate * 1000 * timing->pll_m /
+			(timing->pll_n << timing->pll_p);
+		timing->htotal = var->left_margin + var->xres +
+				var->right_margin + var->hsync_len;
+		timing->vtotal = var->upper_margin + var->yres +
+				var->lower_margin + var->vsync_len;
+		timing->fields_sec = 1000 * timing->cfreq / timing->htotal *
+				1000 / timing->vtotal;
+		timing->hblank_start = var->xres;
+		timing->vblank_start = var->yres;
+		timing->hblank_end = timing->htotal;
+		timing->hsync_start = var->xres + var->right_margin + 1;
+		timing->hsync_end = timing->hsync_start + var->hsync_len;
+		timing->vblank_end = timing->vtotal;
+		timing->vsync_start = var->yres + var->lower_margin + 1;
+		timing->vsync_end = timing->vsync_start + var->vsync_len;
+	}
+
+	return pixclock;
+}
+
+static void gbe_set_timing_info(struct gbe_timing_info *timing)
+{
+	int temp;
+	unsigned int val;
+
+	/* setup dot clock PLL */
+	val = 0;
+	SET_GBE_FIELD(DOTCLK, M, val, timing->pll_m - 1);
+	SET_GBE_FIELD(DOTCLK, N, val, timing->pll_n - 1);
+	SET_GBE_FIELD(DOTCLK, P, val, timing->pll_p);
+	SET_GBE_FIELD(DOTCLK, RUN, val, 0);	/* do not start yet */
+	gbe->dotclock = val;
+	udelay(10000);
+
+	/* setup pixel counter */
+	val = 0;
+	SET_GBE_FIELD(VT_XYMAX, MAXX, val, timing->htotal);
+	SET_GBE_FIELD(VT_XYMAX, MAXY, val, timing->vtotal);
+	gbe->vt_xymax = val;
+
+	/* setup video timing signals */
+	val = 0;
+	SET_GBE_FIELD(VT_VSYNC, VSYNC_ON, val, timing->vsync_start);
+	SET_GBE_FIELD(VT_VSYNC, VSYNC_OFF, val, timing->vsync_end);
+	gbe->vt_vsync = val;
+	val = 0;
+	SET_GBE_FIELD(VT_HSYNC, HSYNC_ON, val, timing->hsync_start);
+	SET_GBE_FIELD(VT_HSYNC, HSYNC_OFF, val, timing->hsync_end);
+	gbe->vt_hsync = val;
+	val = 0;
+	SET_GBE_FIELD(VT_VBLANK, VBLANK_ON, val, timing->vblank_start);
+	SET_GBE_FIELD(VT_VBLANK, VBLANK_OFF, val, timing->vblank_end);
+	gbe->vt_vblank = val;
+	val = 0;
+	SET_GBE_FIELD(VT_HBLANK, HBLANK_ON, val,
+		      timing->hblank_start - 5);
+	SET_GBE_FIELD(VT_HBLANK, HBLANK_OFF, val,
+		      timing->hblank_end - 3);
+	gbe->vt_hblank = val;
+
+	/* setup internal timing signals */
+	val = 0;
+	SET_GBE_FIELD(VT_VCMAP, VCMAP_ON, val, timing->vblank_start);
+	SET_GBE_FIELD(VT_VCMAP, VCMAP_OFF, val, timing->vblank_end);
+	gbe->vt_vcmap = val;
+	val = 0;
+	SET_GBE_FIELD(VT_HCMAP, HCMAP_ON, val, timing->hblank_start);
+	SET_GBE_FIELD(VT_HCMAP, HCMAP_OFF, val, timing->hblank_end);
+	gbe->vt_hcmap = val;
+
+	val = 0;
+	temp = timing->vblank_start - timing->vblank_end - 1;
+	if (temp > 0)
+		temp = -temp;
+
+	if (flat_panel_enabled)
+		gbefb_setup_flatpanel(timing);
+
+	SET_GBE_FIELD(DID_START_XY, DID_STARTY, val, (u32) temp);
+	if (timing->hblank_end >= 20)
+		SET_GBE_FIELD(DID_START_XY, DID_STARTX, val,
+			      timing->hblank_end - 20);
+	else
+		SET_GBE_FIELD(DID_START_XY, DID_STARTX, val,
+			      timing->htotal - (20 - timing->hblank_end));
+	gbe->did_start_xy = val;
+
+	val = 0;
+	SET_GBE_FIELD(CRS_START_XY, CRS_STARTY, val, (u32) (temp + 1));
+	if (timing->hblank_end >= GBE_CRS_MAGIC)
+		SET_GBE_FIELD(CRS_START_XY, CRS_STARTX, val,
+			      timing->hblank_end - GBE_CRS_MAGIC);
+	else
+		SET_GBE_FIELD(CRS_START_XY, CRS_STARTX, val,
+			      timing->htotal - (GBE_CRS_MAGIC -
+						timing->hblank_end));
+	gbe->crs_start_xy = val;
+
+	val = 0;
+	SET_GBE_FIELD(VC_START_XY, VC_STARTY, val, (u32) temp);
+	SET_GBE_FIELD(VC_START_XY, VC_STARTX, val, timing->hblank_end - 4);
+	gbe->vc_start_xy = val;
+
+	val = 0;
+	temp = timing->hblank_end - GBE_PIXEN_MAGIC_ON;
+	if (temp < 0)
+		temp += timing->htotal;	/* allow blank to wrap around */
+
+	SET_GBE_FIELD(VT_HPIXEN, HPIXEN_ON, val, temp);
+	SET_GBE_FIELD(VT_HPIXEN, HPIXEN_OFF, val,
+		      ((temp + timing->width -
+			GBE_PIXEN_MAGIC_OFF) % timing->htotal));
+	gbe->vt_hpixen = val;
+
+	val = 0;
+	SET_GBE_FIELD(VT_VPIXEN, VPIXEN_ON, val, timing->vblank_end);
+	SET_GBE_FIELD(VT_VPIXEN, VPIXEN_OFF, val, timing->vblank_start);
+	gbe->vt_vpixen = val;
+
+	/* turn off sync on green */
+	val = 0;
+	SET_GBE_FIELD(VT_FLAGS, SYNC_LOW, val, 1);
+	gbe->vt_flags = val;
+}
+
+/*
+ *  Set the hardware according to 'par'.
+ */
+
+static int gbefb_set_par(struct fb_info *info)
+{
+	int i;
+	unsigned int val;
+	int wholeTilesX, partTilesX, maxPixelsPerTileX;
+	int height_pix;
+	int xpmax, ypmax;	/* Monitor resolution */
+	int bytesPerPixel;	/* Bytes per pixel */
+	struct gbefb_par *par = (struct gbefb_par *) info->par;
+
+	compute_gbe_timing(&info->var, &par->timing);
+
+	bytesPerPixel = info->var.bits_per_pixel / 8;
+	info->fix.line_length = info->var.xres_virtual * bytesPerPixel;
+	xpmax = par->timing.width;
+	ypmax = par->timing.height;
+
+	/* turn off GBE */
+	gbe_turn_off();
+
+	/* set timing info */
+	gbe_set_timing_info(&par->timing);
+
+	/* initialize DIDs */
+	val = 0;
+	switch (bytesPerPixel) {
+	case 1:
+		SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_I8);
+		break;
+	case 2:
+		SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_ARGB5);
+		break;
+	case 4:
+		SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_RGB8);
+		break;
+	}
+	SET_GBE_FIELD(WID, BUF, val, GBE_BMODE_BOTH);
+
+	for (i = 0; i < 32; i++)
+		gbe->mode_regs[i] = val;
+
+	/* Initialize interrupts */
+	gbe->vt_intr01 = 0xffffffff;
+	gbe->vt_intr23 = 0xffffffff;
+
+	/* HACK:
+	   The GBE hardware uses a tiled memory to screen mapping. Tiles are
+	   blocks of 512x128, 256x128 or 128x128 pixels, respectively for 8bit,
+	   16bit and 32 bit modes (64 kB). They cover the screen with partial
+	   tiles on the right and/or bottom of the screen if needed.
+	   For exemple in 640x480 8 bit mode the mapping is:
+
+	   <-------- 640 ----->
+	   <---- 512 ----><128|384 offscreen>
+	   ^  ^
+	   | 128    [tile 0]        [tile 1]
+	   |  v
+	   ^
+	   4 128    [tile 2]        [tile 3]
+	   8  v
+	   0  ^
+	   128    [tile 4]        [tile 5]
+	   |  v
+	   |  ^
+	   v  96    [tile 6]        [tile 7]
+	   32 offscreen
+
+	   Tiles have the advantage that they can be allocated individually in
+	   memory. However, this mapping is not linear at all, which is not
+	   really convienient. In order to support linear addressing, the GBE
+	   DMA hardware is fooled into thinking the screen is only one tile
+	   large and but has a greater height, so that the DMA transfer covers
+	   the same region.
+	   Tiles are still allocated as independent chunks of 64KB of
+	   continuous physical memory and remapped so that the kernel sees the
+	   framebuffer as a continuous virtual memory. The GBE tile table is
+	   set up so that each tile references one of these 64k blocks:
+
+	   GBE -> tile list    framebuffer           TLB   <------------ CPU
+	          [ tile 0 ] -> [ 64KB ]  <- [ 16x 4KB page entries ]     ^
+	             ...           ...              ...       linear virtual FB
+	          [ tile n ] -> [ 64KB ]  <- [ 16x 4KB page entries ]     v
+
+
+	   The GBE hardware is then told that the buffer is 512*tweaked_height,
+	   with tweaked_height = real_width*real_height/pixels_per_tile.
+	   Thus the GBE hardware will scan the first tile, filing the first 64k
+	   covered region of the screen, and then will proceed to the next
+	   tile, until the whole screen is covered.
+
+	   Here is what would happen at 640x480 8bit:
+
+	   normal tiling               linear
+	   ^   11111111111111112222    11111111111111111111  ^
+	   128 11111111111111112222    11111111111111111111 102 lines
+	       11111111111111112222    11111111111111111111  v
+	   V   11111111111111112222    11111111222222222222
+	       33333333333333334444    22222222222222222222
+	       33333333333333334444    22222222222222222222
+	       <      512     >        <  256 >               102*640+256 = 64k
+
+	   NOTE: The only mode for which this is not working is 800x600 8bit,
+	   as 800*600/512 = 937.5 which is not integer and thus causes
+	   flickering.
+	   I guess this is not so important as one can use 640x480 8bit or
+	   800x600 16bit anyway.
+	 */
+
+	/* Tell gbe about the tiles table location */
+	/* tile_ptr -> [ tile 1 ] -> FB mem */
+	/*             [ tile 2 ] -> FB mem */
+	/*               ...                */
+	val = 0;
+	SET_GBE_FIELD(FRM_CONTROL, FRM_TILE_PTR, val, gbe_tiles.dma >> 9);
+	SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 0); /* do not start */
+	SET_GBE_FIELD(FRM_CONTROL, FRM_LINEAR, val, 0);
+	gbe->frm_control = val;
+
+	maxPixelsPerTileX = 512 / bytesPerPixel;
+	wholeTilesX = 1;
+	partTilesX = 0;
+
+	/* Initialize the framebuffer */
+	val = 0;
+	SET_GBE_FIELD(FRM_SIZE_TILE, FRM_WIDTH_TILE, val, wholeTilesX);
+	SET_GBE_FIELD(FRM_SIZE_TILE, FRM_RHS, val, partTilesX);
+
+	switch (bytesPerPixel) {
+	case 1:
+		SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
+			      GBE_FRM_DEPTH_8);
+		break;
+	case 2:
+		SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
+			      GBE_FRM_DEPTH_16);
+		break;
+	case 4:
+		SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
+			      GBE_FRM_DEPTH_32);
+		break;
+	}
+	gbe->frm_size_tile = val;
+
+	/* compute tweaked height */
+	height_pix = xpmax * ypmax / maxPixelsPerTileX;
+
+	val = 0;
+	SET_GBE_FIELD(FRM_SIZE_PIXEL, FB_HEIGHT_PIX, val, height_pix);
+	gbe->frm_size_pixel = val;
+
+	/* turn off DID and overlay DMA */
+	gbe->did_control = 0;
+	gbe->ovr_width_tile = 0;
+
+	/* Turn off mouse cursor */
+	gbe->crs_ctl = 0;
+
+	/* Turn on GBE */
+	gbe_turn_on();
+
+	/* Initialize the gamma map */
+	udelay(10);
+	for (i = 0; i < 256; i++)
+		gbe->gmap[i] = (i << 24) | (i << 16) | (i << 8);
+
+	/* Initialize the color map */
+	for (i = 0; i < 256; i++) {
+		int j;
+
+		for (j = 0; j < 1000 && gbe->cm_fifo >= 63; j++)
+			udelay(10);
+		if (j == 1000)
+			printk(KERN_ERR "gbefb: cmap FIFO timeout\n");
+
+		gbe->cmap[i] = (i << 8) | (i << 16) | (i << 24);
+	}
+
+	return 0;
+}
+
+static void gbefb_encode_fix(struct fb_fix_screeninfo *fix,
+			     struct fb_var_screeninfo *var)
+{
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+	strcpy(fix->id, "SGI GBE");
+	fix->smem_start = (unsigned long) gbe_mem;
+	fix->smem_len = gbe_mem_size;
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->type_aux = 0;
+	fix->accel = FB_ACCEL_NONE;
+	switch (var->bits_per_pixel) {
+	case 8:
+		fix->visual = FB_VISUAL_PSEUDOCOLOR;
+		break;
+	default:
+		fix->visual = FB_VISUAL_TRUECOLOR;
+		break;
+	}
+	fix->ywrapstep = 0;
+	fix->xpanstep = 0;
+	fix->ypanstep = 0;
+	fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
+	fix->mmio_start = GBE_BASE;
+	fix->mmio_len = sizeof(struct sgi_gbe);
+}
+
+/*
+ *  Set a single color register. The values supplied are already
+ *  rounded down to the hardware's capabilities (according to the
+ *  entries in the var structure). Return != 0 for invalid regno.
+ */
+
+static int gbefb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			     unsigned blue, unsigned transp,
+			     struct fb_info *info)
+{
+	int i;
+
+	if (regno > 255)
+		return 1;
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	switch (info->var.bits_per_pixel) {
+	case 8:
+		/* wait for the color map FIFO to have a free entry */
+		for (i = 0; i < 1000 && gbe->cm_fifo >= 63; i++)
+			udelay(10);
+		if (i == 1000) {
+			printk(KERN_ERR "gbefb: cmap FIFO timeout\n");
+			return 1;
+		}
+		gbe->cmap[regno] = (red << 24) | (green << 16) | (blue << 8);
+		break;
+	case 15:
+	case 16:
+		red >>= 3;
+		green >>= 3;
+		blue >>= 3;
+		pseudo_palette[regno] =
+			(red << info->var.red.offset) |
+			(green << info->var.green.offset) |
+			(blue << info->var.blue.offset);
+		break;
+	case 32:
+		pseudo_palette[regno] =
+			(red << info->var.red.offset) |
+			(green << info->var.green.offset) |
+			(blue << info->var.blue.offset);
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ *  Check video mode validity, eventually modify var to best match.
+ */
+static int gbefb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	unsigned int line_length;
+	struct gbe_timing_info timing;
+
+	/* Limit bpp to 8, 16, and 32 */
+	if (var->bits_per_pixel <= 8)
+		var->bits_per_pixel = 8;
+	else if (var->bits_per_pixel <= 16)
+		var->bits_per_pixel = 16;
+	else if (var->bits_per_pixel <= 32)
+		var->bits_per_pixel = 32;
+	else
+		return -EINVAL;
+
+	/* Check the mode can be mapped linearly with the tile table trick. */
+	/* This requires width x height x bytes/pixel be a multiple of 512 */
+	if ((var->xres * var->yres * var->bits_per_pixel) & 4095)
+		return -EINVAL;
+
+	var->grayscale = 0;	/* No grayscale for now */
+
+	if ((var->pixclock = compute_gbe_timing(var, &timing)) < 0)
+		return(-EINVAL);
+
+	/* Adjust virtual resolution, if necessary */
+	if (var->xres > var->xres_virtual || (!ywrap && !ypan))
+		var->xres_virtual = var->xres;
+	if (var->yres > var->yres_virtual || (!ywrap && !ypan))
+		var->yres_virtual = var->yres;
+
+	if (var->vmode & FB_VMODE_CONUPDATE) {
+		var->vmode |= FB_VMODE_YWRAP;
+		var->xoffset = info->var.xoffset;
+		var->yoffset = info->var.yoffset;
+	}
+
+	/* No grayscale for now */
+	var->grayscale = 0;
+
+	/* Memory limit */
+	line_length = var->xres_virtual * var->bits_per_pixel / 8;
+	if (line_length * var->yres_virtual > gbe_mem_size)
+		return -ENOMEM;	/* Virtual resolution too high */
+
+	switch (var->bits_per_pixel) {
+	case 8:
+		var->red.offset = 0;
+		var->red.length = 8;
+		var->green.offset = 0;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		break;
+	case 16:		/* RGB 1555 */
+		var->red.offset = 10;
+		var->red.length = 5;
+		var->green.offset = 5;
+		var->green.length = 5;
+		var->blue.offset = 0;
+		var->blue.length = 5;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		break;
+	case 32:		/* RGB 8888 */
+		var->red.offset = 24;
+		var->red.length = 8;
+		var->green.offset = 16;
+		var->green.length = 8;
+		var->blue.offset = 8;
+		var->blue.length = 8;
+		var->transp.offset = 0;
+		var->transp.length = 8;
+		break;
+	}
+	var->red.msb_right = 0;
+	var->green.msb_right = 0;
+	var->blue.msb_right = 0;
+	var->transp.msb_right = 0;
+
+	var->left_margin = timing.htotal - timing.hsync_end;
+	var->right_margin = timing.hsync_start - timing.width;
+	var->upper_margin = timing.vtotal - timing.vsync_end;
+	var->lower_margin = timing.vsync_start - timing.height;
+	var->hsync_len = timing.hsync_end - timing.hsync_start;
+	var->vsync_len = timing.vsync_end - timing.vsync_start;
+
+	return 0;
+}
+
+static int gbefb_mmap(struct fb_info *info, struct file *file,
+			struct vm_area_struct *vma)
+{
+	unsigned long size = vma->vm_end - vma->vm_start;
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	unsigned long addr;
+	unsigned long phys_addr, phys_size;
+	u16 *tile;
+
+	/* check range */
+	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+		return -EINVAL;
+	if (offset + size > gbe_mem_size)
+		return -EINVAL;
+
+	/* remap using the fastest write-through mode on architecture */
+	/* try not polluting the cache when possible */
+	pgprot_val(vma->vm_page_prot) =
+		pgprot_fb(pgprot_val(vma->vm_page_prot));
+
+	vma->vm_flags |= VM_IO | VM_RESERVED;
+	vma->vm_file = file;
+
+	/* look for the starting tile */
+	tile = &gbe_tiles.cpu[offset >> TILE_SHIFT];
+	addr = vma->vm_start;
+	offset &= TILE_MASK;
+
+	/* remap each tile separately */
+	do {
+		phys_addr = (((unsigned long) (*tile)) << TILE_SHIFT) + offset;
+		if ((offset + size) < TILE_SIZE)
+			phys_size = size;
+		else
+			phys_size = TILE_SIZE - offset;
+
+		if (remap_page_range
+		    (vma, addr, phys_addr, phys_size, vma->vm_page_prot))
+			return -EAGAIN;
+
+		offset = 0;
+		size -= phys_size;
+		addr += phys_size;
+		tile++;
+	} while (size);
+
+	return 0;
+}
+
+static struct fb_ops gbefb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= gbefb_check_var,
+	.fb_set_par	= gbefb_set_par,
+	.fb_setcolreg	= gbefb_setcolreg,
+	.fb_mmap	= gbefb_mmap,
+	.fb_blank	= gbefb_blank,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_cursor	= soft_cursor,
+};
+
+/*
+ * Initialization
+ */
+
+int __init gbefb_setup(char *options)
+{
+	char *this_opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!strncmp(this_opt, "monitor:", 8)) {
+			if (!strncmp(this_opt + 8, "crt", 3)) {
+				flat_panel_enabled = 0;
+				default_var = &default_var_CRT;
+				default_mode = &default_mode_CRT;
+			} else if (!strncmp(this_opt + 8, "1600sw", 6) ||
+				   !strncmp(this_opt + 8, "lcd", 3)) {
+				flat_panel_enabled = 1;
+				default_var = &default_var_LCD;
+				default_mode = &default_mode_LCD;
+			}
+		} else if (!strncmp(this_opt, "mem:", 4)) {
+			gbe_mem_size = memparse(this_opt + 4, &this_opt);
+			if (gbe_mem_size > CONFIG_FB_GBE_MEM * 1024 * 1024)
+				gbe_mem_size = CONFIG_FB_GBE_MEM * 1024 * 1024;
+			if (gbe_mem_size < TILE_SIZE)
+				gbe_mem_size = TILE_SIZE;
+		} else
+			mode_option = this_opt;
+	}
+	return 0;
+}
+
+int __init gbefb_init(void)
+{
+	int i, ret = 0;
+
+	if (!request_mem_region(GBE_BASE, sizeof(struct sgi_gbe), "GBE")) {
+		printk(KERN_ERR "gbefb: couldn't reserve mmio region\n");
+		return -EBUSY;
+	}
+
+	gbe = (struct sgi_gbe *) ioremap(GBE_BASE, sizeof(struct sgi_gbe));
+	if (!gbe) {
+		printk(KERN_ERR "gbefb: couldn't map mmio region\n");
+		ret = -ENXIO;
+		goto out_release_mem_region;
+	}
+	gbe_revision = gbe->ctrlstat & 15;
+
+	gbe_tiles.cpu =
+		dma_alloc_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),
+				   &gbe_tiles.dma, GFP_KERNEL);
+	if (!gbe_tiles.cpu) {
+		printk(KERN_ERR "gbefb: couldn't allocate tiles table\n");
+		ret = -ENOMEM;
+		goto out_unmap;
+	}
+
+
+	if (gbe_mem_phys) {
+		/* memory was allocated at boot time */
+		gbe_mem = ioremap_nocache(gbe_mem_phys, gbe_mem_size);
+		gbe_dma_addr = 0;
+	} else {
+		/* try to allocate memory with the classical allocator
+		 * this has high chance to fail on low memory machines */
+		gbe_mem = dma_alloc_coherent(NULL, gbe_mem_size, &gbe_dma_addr,
+					     GFP_KERNEL);
+		gbe_mem_phys = (unsigned long) gbe_dma_addr;
+	}
+
+#ifdef CONFIG_X86
+	mtrr_add(gbe_mem_phys, gbe_mem_size, MTRR_TYPE_WRCOMB, 1);
+#endif
+
+	if (!gbe_mem) {
+		printk(KERN_ERR "gbefb: couldn't map framebuffer\n");
+		ret = -ENXIO;
+		goto out_tiles_free;
+	}
+
+	/* map framebuffer memory into tiles table */
+	for (i = 0; i < (gbe_mem_size >> TILE_SHIFT); i++)
+		gbe_tiles.cpu[i] = (gbe_mem_phys >> TILE_SHIFT) + i;
+
+	fb_info.currcon = -1;
+	fb_info.fbops = &gbefb_ops;
+	fb_info.pseudo_palette = pseudo_palette;
+	fb_info.flags = FBINFO_FLAG_DEFAULT;
+	fb_info.screen_base = gbe_mem;
+	fb_alloc_cmap(&fb_info.cmap, 256, 0);
+
+	/* reset GBE */
+	gbe_reset();
+
+	/* turn on default video mode */
+	if (fb_find_mode(&par_current.var, &fb_info, mode_option, NULL, 0,
+			 default_mode, 8) == 0)
+		par_current.var = *default_var;
+	fb_info.var = par_current.var;
+	gbefb_check_var(&par_current.var, &fb_info);
+	gbefb_encode_fix(&fb_info.fix, &fb_info.var);
+	fb_info.par = &par_current;
+
+	if (register_framebuffer(&fb_info) < 0) {
+		ret = -ENXIO;
+		printk(KERN_ERR "gbefb: couldn't register framebuffer\n");
+		goto out_gbe_unmap;
+	}
+
+	printk(KERN_INFO "fb%d: %s rev %d @ 0x%08x using %dkB memory\n",
+	       fb_info.node, fb_info.fix.id, gbe_revision, (unsigned) GBE_BASE,
+	       gbe_mem_size >> 10);
+
+	return 0;
+
+out_gbe_unmap:
+	if (gbe_dma_addr)
+		dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys);
+	else
+		iounmap(gbe_mem);
+out_tiles_free:
+	dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),
+			  (void *)gbe_tiles.cpu, gbe_tiles.dma);
+out_unmap:
+	iounmap(gbe);
+out_release_mem_region:
+	release_mem_region(GBE_BASE, sizeof(struct sgi_gbe));
+	return ret;
+}
+
+void __exit gbefb_exit(void)
+{
+	unregister_framebuffer(&fb_info);
+	gbe_turn_off();
+	if (gbe_dma_addr)
+		dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys);
+	else
+		iounmap(gbe_mem);
+	dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),
+			  (void *)gbe_tiles.cpu, gbe_tiles.dma);
+	release_mem_region(GBE_BASE, sizeof(struct sgi_gbe));
+	iounmap(gbe);
+}
+
+#ifdef MODULE
+module_init(gbefb_init);
+module_exit(gbefb_exit);
+#endif
+
+MODULE_LICENSE("GPL");
diff -puN drivers/video/Kconfig~mips-gbe-video-driver drivers/video/Kconfig
--- 25/drivers/video/Kconfig~mips-gbe-video-driver	Thu Apr 29 15:45:57 2004
+++ 25-akpm/drivers/video/Kconfig	Thu Apr 29 15:45:57 2004
@@ -319,6 +319,21 @@ config FB_SGIVW
 	help
 	  SGI Visual Workstation support for framebuffer graphics.
 
+config FB_GBE
+	bool "SGI Graphics Backend frame buffer support"
+	depends on FB && (SGI_IP32 || X86_VISWS)
+ 	help
+	  This is the frame buffer device driver for SGI Graphics Backend.
+	  This chip is used in SGI O2 and Visual Workstation 320/540.
+
+config FB_GBE_MEM
+	int "Video memory size in MB"
+	depends on FB_GBE
+	default 8
+	help
+	  This is the amount of memory reserved for the framebuffer,
+	  which can be any value between 1MB and 8MB.
+
 config BUS_I2C
 	bool
 	depends on FB && VISWS
diff -puN drivers/video/Makefile~mips-gbe-video-driver drivers/video/Makefile
--- 25/drivers/video/Makefile~mips-gbe-video-driver	Thu Apr 29 15:45:57 2004
+++ 25-akpm/drivers/video/Makefile	Thu Apr 29 15:45:57 2004
@@ -31,6 +31,7 @@ obj-$(CONFIG_FB_CT65550)          += chi
 obj-$(CONFIG_FB_CLPS711X)         += clps711xfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_CYBER)            += cyberfb.o
 obj-$(CONFIG_FB_CYBER2000)        += cyber2000fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
+obj-$(CONFIG_FB_GBE)              += gbefb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_SGIVW)            += sgivwfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_3DFX)             += tdfxfb.o cfbimgblt.o
 obj-$(CONFIG_FB_MAC)              += macfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o 
diff -puN /dev/null include/video/gbe.h
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/include/video/gbe.h	Thu Apr 29 15:45:57 2004
@@ -0,0 +1,317 @@
+/*
+ * include/video/gbe.h -- SGI GBE (Graphics Back End)
+ *
+ * Copyright (C) 1999 Silicon Graphics, Inc. (Jeffrey Newquist)
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef __GBE_H__
+#define __GBE_H__
+
+struct sgi_gbe {
+	volatile uint32_t ctrlstat;	/* general control */
+	volatile uint32_t dotclock;	/* dot clock PLL control */
+	volatile uint32_t i2c;		/* crt I2C control */
+	volatile uint32_t sysclk;	/* system clock PLL control */
+	volatile uint32_t i2cfp;	/* flat panel I2C control */
+	volatile uint32_t id;		/* device id/chip revision */
+	volatile uint32_t config;       /* power on configuration [1] */
+	volatile uint32_t bist;         /* internal bist status [1] */
+	uint32_t _pad0[0x010000/4 - 8];
+	volatile uint32_t vt_xy;	/* current dot coords */
+	volatile uint32_t vt_xymax;	/* maximum dot coords */
+	volatile uint32_t vt_vsync;	/* vsync on/off */
+	volatile uint32_t vt_hsync;	/* hsync on/off */
+	volatile uint32_t vt_vblank;	/* vblank on/off */
+	volatile uint32_t vt_hblank;	/* hblank on/off */
+	volatile uint32_t vt_flags;	/* polarity of vt signals */
+	volatile uint32_t vt_f2rf_lock;	/* f2rf & framelck y coord */
+	volatile uint32_t vt_intr01;	/* intr 0,1 y coords */
+	volatile uint32_t vt_intr23;	/* intr 2,3 y coords */
+	volatile uint32_t fp_hdrv;	/* flat panel hdrv on/off */
+	volatile uint32_t fp_vdrv;	/* flat panel vdrv on/off */
+	volatile uint32_t fp_de;	/* flat panel de on/off */
+	volatile uint32_t vt_hpixen;	/* intrnl horiz pixel on/off */
+	volatile uint32_t vt_vpixen;	/* intrnl vert pixel on/off */
+	volatile uint32_t vt_hcmap;	/* cmap write (horiz) */
+	volatile uint32_t vt_vcmap;	/* cmap write (vert) */
+	volatile uint32_t did_start_xy;	/* eol/f did/xy reset val */
+	volatile uint32_t crs_start_xy;	/* eol/f crs/xy reset val */
+	volatile uint32_t vc_start_xy;	/* eol/f vc/xy reset val */
+	uint32_t _pad1[0xffb0/4];
+	volatile uint32_t ovr_width_tile;/*overlay plane ctrl 0 */
+	volatile uint32_t ovr_inhwctrl;	/* overlay plane ctrl 1 */
+	volatile uint32_t ovr_control;	/* overlay plane ctrl 1 */
+	uint32_t _pad2[0xfff4/4];
+	volatile uint32_t frm_size_tile;/* normal plane ctrl 0 */
+	volatile uint32_t frm_size_pixel;/*normal plane ctrl 1 */
+	volatile uint32_t frm_inhwctrl;	/* normal plane ctrl 2 */
+	volatile uint32_t frm_control;	/* normal plane ctrl 3 */
+	uint32_t _pad3[0xfff0/4];
+	volatile uint32_t did_inhwctrl;	/* DID control */
+	volatile uint32_t did_control;	/* DID shadow */
+	uint32_t _pad4[0x7ff8/4];
+	volatile uint32_t mode_regs[32];/* WID table */
+	uint32_t _pad5[0x7f80/4];
+	volatile uint32_t cmap[6144];	/* color map */
+	uint32_t _pad6[0x2000/4];
+	volatile uint32_t cm_fifo;	/* color map fifo status */
+	uint32_t _pad7[0x7ffc/4];
+	volatile uint32_t gmap[256];	/* gamma map */
+	uint32_t _pad8[0x7c00/4];
+	volatile uint32_t gmap10[1024];	/* gamma map */
+	uint32_t _pad9[0x7000/4];
+	volatile uint32_t crs_pos;	/* cusror control 0 */
+	volatile uint32_t crs_ctl;	/* cusror control 1 */
+	volatile uint32_t crs_cmap[3];	/* crs cmap */
+	uint32_t _pad10[0x7fec/4];
+	volatile uint32_t crs_glyph[64];/* crs glyph */
+	uint32_t _pad11[0x7f00/4];
+	volatile uint32_t vc_0;	/* video capture crtl 0 */
+	volatile uint32_t vc_1;	/* video capture crtl 1 */
+	volatile uint32_t vc_2;	/* video capture crtl 2 */
+	volatile uint32_t vc_3;	/* video capture crtl 3 */
+	volatile uint32_t vc_4;	/* video capture crtl 4 */
+	volatile uint32_t vc_5;	/* video capture crtl 5 */
+	volatile uint32_t vc_6;	/* video capture crtl 6 */
+	volatile uint32_t vc_7;	/* video capture crtl 7 */
+	volatile uint32_t vc_8;	/* video capture crtl 8 */
+};
+
+#define MASK(msb, lsb)		\
+	( (((u32)1<<((msb)-(lsb)+1))-1) << (lsb) )
+#define GET(v, msb, lsb)	\
+	( ((u32)(v) & MASK(msb,lsb)) >> (lsb) )
+#define SET(v, f, msb, lsb)	\
+	( (v) = ((v)&~MASK(msb,lsb)) | (( (u32)(f)<<(lsb) ) & MASK(msb,lsb)) )
+
+#define GET_GBE_FIELD(reg, field, v)		\
+	GET((v), GBE_##reg##_##field##_MSB, GBE_##reg##_##field##_LSB)
+#define SET_GBE_FIELD(reg, field, v, f)		\
+	SET((v), (f), GBE_##reg##_##field##_MSB, GBE_##reg##_##field##_LSB)
+
+/*
+ * Bit mask information
+ */
+#define GBE_CTRLSTAT_CHIPID_MSB		 3
+#define GBE_CTRLSTAT_CHIPID_LSB		 0
+#define GBE_CTRLSTAT_SENSE_N_MSB	 4
+#define GBE_CTRLSTAT_SENSE_N_LSB	 4
+#define GBE_CTRLSTAT_PCLKSEL_MSB	29
+#define GBE_CTRLSTAT_PCLKSEL_LSB	28
+
+#define GBE_DOTCLK_M_MSB		 7
+#define GBE_DOTCLK_M_LSB		 0
+#define GBE_DOTCLK_N_MSB		13
+#define GBE_DOTCLK_N_LSB		 8
+#define GBE_DOTCLK_P_MSB		15
+#define GBE_DOTCLK_P_LSB		14
+#define GBE_DOTCLK_RUN_MSB		20
+#define GBE_DOTCLK_RUN_LSB		20
+
+#define GBE_VT_XY_Y_MSB		23
+#define GBE_VT_XY_Y_LSB		12
+#define GBE_VT_XY_X_MSB		11
+#define GBE_VT_XY_X_LSB		 0
+#define GBE_VT_XY_FREEZE_MSB		31
+#define GBE_VT_XY_FREEZE_LSB		31
+
+#define GBE_FP_VDRV_ON_MSB	23
+#define GBE_FP_VDRV_ON_LSB	12
+#define GBE_FP_VDRV_OFF_MSB	11
+#define GBE_FP_VDRV_OFF_LSB	0
+
+#define GBE_FP_HDRV_ON_MSB	23
+#define GBE_FP_HDRV_ON_LSB	12
+#define GBE_FP_HDRV_OFF_MSB	11
+#define GBE_FP_HDRV_OFF_LSB	0
+
+#define GBE_FP_DE_ON_MSB		23
+#define GBE_FP_DE_ON_LSB		12
+#define GBE_FP_DE_OFF_MSB		11
+#define GBE_FP_DE_OFF_LSB		0
+
+#define GBE_VT_VSYNC_VSYNC_ON_MSB	23
+#define GBE_VT_VSYNC_VSYNC_ON_LSB	12
+#define GBE_VT_VSYNC_VSYNC_OFF_MSB	11
+#define GBE_VT_VSYNC_VSYNC_OFF_LSB	 0
+
+#define GBE_VT_HSYNC_HSYNC_ON_MSB	23
+#define GBE_VT_HSYNC_HSYNC_ON_LSB	12
+#define GBE_VT_HSYNC_HSYNC_OFF_MSB	11
+#define GBE_VT_HSYNC_HSYNC_OFF_LSB	 0
+
+#define GBE_VT_VBLANK_VBLANK_ON_MSB	23
+#define GBE_VT_VBLANK_VBLANK_ON_LSB	12
+#define GBE_VT_VBLANK_VBLANK_OFF_MSB	11
+#define GBE_VT_VBLANK_VBLANK_OFF_LSB	 0
+
+#define GBE_VT_HBLANK_HBLANK_ON_MSB	23
+#define GBE_VT_HBLANK_HBLANK_ON_LSB	12
+#define GBE_VT_HBLANK_HBLANK_OFF_MSB	11
+#define GBE_VT_HBLANK_HBLANK_OFF_LSB	 0
+
+#define GBE_VT_FLAGS_F2RF_HIGH_MSB	 6
+#define GBE_VT_FLAGS_F2RF_HIGH_LSB	 6
+#define GBE_VT_FLAGS_SYNC_LOW_MSB	 5
+#define GBE_VT_FLAGS_SYNC_LOW_LSB	 5
+#define GBE_VT_FLAGS_SYNC_HIGH_MSB	 4
+#define GBE_VT_FLAGS_SYNC_HIGH_LSB	 4
+#define GBE_VT_FLAGS_HDRV_LOW_MSB	 3
+#define GBE_VT_FLAGS_HDRV_LOW_LSB	 3
+#define GBE_VT_FLAGS_HDRV_INVERT_MSB	 2
+#define GBE_VT_FLAGS_HDRV_INVERT_LSB	 2
+#define GBE_VT_FLAGS_VDRV_LOW_MSB	 1
+#define GBE_VT_FLAGS_VDRV_LOW_LSB	 1
+#define GBE_VT_FLAGS_VDRV_INVERT_MSB	 0
+#define GBE_VT_FLAGS_VDRV_INVERT_LSB	 0
+
+#define GBE_VT_VCMAP_VCMAP_ON_MSB	23
+#define GBE_VT_VCMAP_VCMAP_ON_LSB	12
+#define GBE_VT_VCMAP_VCMAP_OFF_MSB	11
+#define GBE_VT_VCMAP_VCMAP_OFF_LSB	 0
+
+#define GBE_VT_HCMAP_HCMAP_ON_MSB	23
+#define GBE_VT_HCMAP_HCMAP_ON_LSB	12
+#define GBE_VT_HCMAP_HCMAP_OFF_MSB	11
+#define GBE_VT_HCMAP_HCMAP_OFF_LSB	 0
+
+#define GBE_VT_XYMAX_MAXX_MSB	11
+#define GBE_VT_XYMAX_MAXX_LSB	 0
+#define GBE_VT_XYMAX_MAXY_MSB	23
+#define GBE_VT_XYMAX_MAXY_LSB	12
+
+#define GBE_VT_HPIXEN_HPIXEN_ON_MSB	23
+#define GBE_VT_HPIXEN_HPIXEN_ON_LSB	12
+#define GBE_VT_HPIXEN_HPIXEN_OFF_MSB	11
+#define GBE_VT_HPIXEN_HPIXEN_OFF_LSB	 0
+
+#define GBE_VT_VPIXEN_VPIXEN_ON_MSB	23
+#define GBE_VT_VPIXEN_VPIXEN_ON_LSB	12
+#define GBE_VT_VPIXEN_VPIXEN_OFF_MSB	11
+#define GBE_VT_VPIXEN_VPIXEN_OFF_LSB	 0
+
+#define GBE_OVR_CONTROL_OVR_DMA_ENABLE_MSB	 0
+#define GBE_OVR_CONTROL_OVR_DMA_ENABLE_LSB	 0
+
+#define GBE_OVR_INHWCTRL_OVR_DMA_ENABLE_MSB	 0
+#define GBE_OVR_INHWCTRL_OVR_DMA_ENABLE_LSB	 0
+
+#define GBE_OVR_WIDTH_TILE_OVR_FIFO_RESET_MSB	13
+#define GBE_OVR_WIDTH_TILE_OVR_FIFO_RESET_LSB	13
+
+#define GBE_FRM_CONTROL_FRM_DMA_ENABLE_MSB	 0
+#define GBE_FRM_CONTROL_FRM_DMA_ENABLE_LSB	 0
+#define GBE_FRM_CONTROL_FRM_TILE_PTR_MSB	31
+#define GBE_FRM_CONTROL_FRM_TILE_PTR_LSB	 9
+#define GBE_FRM_CONTROL_FRM_LINEAR_MSB		 1
+#define GBE_FRM_CONTROL_FRM_LINEAR_LSB		 1
+
+#define GBE_FRM_INHWCTRL_FRM_DMA_ENABLE_MSB	 0
+#define GBE_FRM_INHWCTRL_FRM_DMA_ENABLE_LSB	 0
+
+#define GBE_FRM_SIZE_TILE_FRM_WIDTH_TILE_MSB	12
+#define GBE_FRM_SIZE_TILE_FRM_WIDTH_TILE_LSB	 5
+#define GBE_FRM_SIZE_TILE_FRM_RHS_MSB		 4
+#define GBE_FRM_SIZE_TILE_FRM_RHS_LSB		 0
+#define GBE_FRM_SIZE_TILE_FRM_DEPTH_MSB		14
+#define GBE_FRM_SIZE_TILE_FRM_DEPTH_LSB		13
+#define GBE_FRM_SIZE_TILE_FRM_FIFO_RESET_MSB	15
+#define GBE_FRM_SIZE_TILE_FRM_FIFO_RESET_LSB	15
+
+#define GBE_FRM_SIZE_PIXEL_FB_HEIGHT_PIX_MSB	31
+#define GBE_FRM_SIZE_PIXEL_FB_HEIGHT_PIX_LSB	16
+
+#define GBE_DID_CONTROL_DID_DMA_ENABLE_MSB	 0
+#define GBE_DID_CONTROL_DID_DMA_ENABLE_LSB	 0
+#define GBE_DID_INHWCTRL_DID_DMA_ENABLE_MSB	 0
+#define GBE_DID_INHWCTRL_DID_DMA_ENABLE_LSB	 0
+
+#define GBE_DID_START_XY_DID_STARTY_MSB		23
+#define GBE_DID_START_XY_DID_STARTY_LSB		12
+#define GBE_DID_START_XY_DID_STARTX_MSB		11
+#define GBE_DID_START_XY_DID_STARTX_LSB		 0
+
+#define GBE_CRS_START_XY_CRS_STARTY_MSB		23
+#define GBE_CRS_START_XY_CRS_STARTY_LSB		12
+#define GBE_CRS_START_XY_CRS_STARTX_MSB		11
+#define GBE_CRS_START_XY_CRS_STARTX_LSB		 0
+
+#define GBE_WID_AUX_MSB		12
+#define GBE_WID_AUX_LSB		11
+#define GBE_WID_GAMMA_MSB	10
+#define GBE_WID_GAMMA_LSB	10
+#define GBE_WID_CM_MSB		 9
+#define GBE_WID_CM_LSB		 5
+#define GBE_WID_TYP_MSB		 4
+#define GBE_WID_TYP_LSB		 2
+#define GBE_WID_BUF_MSB		 1
+#define GBE_WID_BUF_LSB		 0
+
+#define GBE_VC_START_XY_VC_STARTY_MSB	23
+#define GBE_VC_START_XY_VC_STARTY_LSB	12
+#define GBE_VC_START_XY_VC_STARTX_MSB	11
+#define GBE_VC_START_XY_VC_STARTX_LSB	 0
+
+/* Constants */
+
+#define GBE_FRM_DEPTH_8		0
+#define GBE_FRM_DEPTH_16	1
+#define GBE_FRM_DEPTH_32	2
+
+#define GBE_CMODE_I8		0
+#define GBE_CMODE_I12		1
+#define GBE_CMODE_RG3B2		2
+#define GBE_CMODE_RGB4		3
+#define GBE_CMODE_ARGB5		4
+#define GBE_CMODE_RGB8		5
+#define GBE_CMODE_RGBA5		6
+#define GBE_CMODE_RGB10		7
+
+#define GBE_BMODE_BOTH		3
+
+#define GBE_CRS_MAGIC		54
+#define GBE_PIXEN_MAGIC_ON	19
+#define GBE_PIXEN_MAGIC_OFF	 2
+
+#define GBE_TLB_SIZE		128
+
+/* [1] - only GBE revision 2 and later */
+
+/*
+ * Video Timing Data Structure
+ */
+
+struct gbe_timing_info {
+	int flags;
+	short width;		/* Monitor resolution */
+	short height;
+	int fields_sec;		/* fields/sec  (Hz -3 dec. places */
+	int cfreq;		/* pixel clock frequency (MHz -3 dec. places) */
+	short htotal;		/* Horizontal total pixels */
+	short hblank_start;	/* Horizontal blank start */
+	short hblank_end;	/* Horizontal blank end */
+	short hsync_start;	/* Horizontal sync start */
+	short hsync_end;	/* Horizontal sync end */
+	short vtotal;		/* Vertical total lines */
+	short vblank_start;	/* Vertical blank start */
+	short vblank_end;	/* Vertical blank end */
+	short vsync_start;	/* Vertical sync start */
+	short vsync_end;	/* Vertical sync end */
+	short pll_m;		/* PLL M parameter */
+	short pll_n;		/* PLL P parameter */
+	short pll_p;		/* PLL N parameter */
+};
+
+/* Defines for gbe_vof_info_t flags */
+
+#define GBE_VOF_UNKNOWNMON	1
+#define GBE_VOF_STEREO		2
+#define GBE_VOF_DO_GENSYNC	4	/* enable incoming sync */
+#define GBE_VOF_SYNC_ON_GREEN	8	/* sync on green */
+#define GBE_VOF_FLATPANEL	0x1000	/* FLATPANEL Timing */
+#define GBE_VOF_MAGICKEY	0x2000	/* Backdoor key */
+
+#endif		/* ! __GBE_H__ */

_