[go: nahoru, domu]

11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  SGI GBE frame buffer driver
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 1999 Silicon Graphics, Inc. - Jeffrey Newquist
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 2002 Vivien Chappelier <vivien.chappelier@linux-mips.org>
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  This file is subject to the terms and conditions of the GNU General Public
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  License. See the file COPYING in the main directory of this archive for
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  more details.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
13d052d1beff706920e82c5d55006b08e256b5df09Russell King#include <linux/platform_device.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/dma-mapping.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
165a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fb.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
23cd9d6f10d07f26dd8a70e519c22b6b4f8a9e3e7aFlorian Tobias Schandinat#include <linux/io.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_X86
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/mtrr.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_MIPS
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/addrspace.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/tlbflush.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <video/gbe.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sgi_gbe *gbe;
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct gbefb_par {
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fb_var_screeninfo var;
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct gbe_timing_info timing;
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int valid;
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SGI_IP32
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GBE_BASE	0x16000000 /* SGI O2 */
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* macro for fastest write-though access to the framebuffer */
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_MIPS
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_CPU_R10000
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define pgprot_fb(_prot) (((_prot) & (~_CACHE_MASK)) | _CACHE_UNCACHED_ACCELERATED)
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define pgprot_fb(_prot) (((_prot) & (~_CACHE_MASK)) | _CACHE_CACHABLE_NO_WA)
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_X86
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define pgprot_fb(_prot) ((_prot) | _PAGE_PCD)
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  RAM we reserve for the frame buffer. This defines the maximum screen
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  size
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if CONFIG_FB_GBE_MEM > 8
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#error GBE Framebuffer cannot use more than 8MB of memory
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TILE_SHIFT 16
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TILE_SIZE (1 << TILE_SHIFT)
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TILE_MASK (TILE_SIZE - 1)
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int gbe_mem_size = CONFIG_FB_GBE_MEM * 1024*1024;
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void *gbe_mem;
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic dma_addr_t gbe_dma_addr;
75b6d57ae97af3c38d28f066b5e47b7d58e468728aDmitri Vorobievstatic unsigned long gbe_mem_phys;
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct {
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uint16_t *cpu;
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dma_addr_t dma;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} gbe_tiles;
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int gbe_revision;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ypan, ywrap;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
869058be43cf9f32b6c636aa6954b4f1a6b22098f6Antonino A. Daplasstatic uint32_t pseudo_palette[16];
878d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerferstatic uint32_t gbe_cmap[256];
888d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerferstatic int gbe_turned_on; /* 0 turned off, 1 turned on */
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9048c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanstatic char *mode_option = NULL;
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* default CRT mode */
9348c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanstatic struct fb_var_screeninfo default_var_CRT = {
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.xres		= 640,
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.yres		= 480,
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.xres_virtual	= 640,
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.yres_virtual	= 480,
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.xoffset	= 0,
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.yoffset	= 0,
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.bits_per_pixel	= 8,
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.grayscale	= 0,
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.red		= { 0, 8, 0 },
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.green		= { 0, 8, 0 },
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.blue		= { 0, 8, 0 },
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.transp		= { 0, 0, 0 },
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.nonstd		= 0,
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.activate	= 0,
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.height		= -1,
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.width		= -1,
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.accel_flags	= 0,
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pixclock	= 39722,	/* picoseconds */
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.left_margin	= 48,
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.right_margin	= 16,
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.upper_margin	= 33,
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lower_margin	= 10,
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hsync_len	= 96,
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.vsync_len	= 2,
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.sync		= 0,
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.vmode		= FB_VMODE_NONINTERLACED,
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* default LCD mode */
12448c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanstatic struct fb_var_screeninfo default_var_LCD = {
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* 1600x1024, 8 bpp */
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.xres		= 1600,
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.yres		= 1024,
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.xres_virtual	= 1600,
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.yres_virtual	= 1024,
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.xoffset	= 0,
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.yoffset	= 0,
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.bits_per_pixel	= 8,
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.grayscale	= 0,
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.red		= { 0, 8, 0 },
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.green		= { 0, 8, 0 },
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.blue		= { 0, 8, 0 },
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.transp		= { 0, 0, 0 },
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.nonstd		= 0,
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.activate	= 0,
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.height		= -1,
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.width		= -1,
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.accel_flags	= 0,
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pixclock	= 9353,
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.left_margin	= 20,
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.right_margin	= 30,
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.upper_margin	= 37,
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lower_margin	= 3,
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hsync_len	= 20,
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.vsync_len	= 3,
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.sync		= 0,
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.vmode		= FB_VMODE_NONINTERLACED
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* default modedb mode */
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */
15648c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanstatic struct fb_videomode default_mode_CRT = {
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.refresh	= 60,
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.xres		= 640,
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.yres		= 480,
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pixclock	= 39722,
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.left_margin	= 48,
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.right_margin	= 16,
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.upper_margin	= 33,
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lower_margin	= 10,
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hsync_len	= 96,
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.vsync_len	= 2,
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.sync		= 0,
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.vmode		= FB_VMODE_NONINTERLACED,
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1600x1024 SGI flatpanel 1600sw */
17148c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanstatic struct fb_videomode default_mode_LCD = {
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* 1600x1024, 8 bpp */
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.xres		= 1600,
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.yres		= 1024,
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pixclock	= 9353,
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.left_margin	= 20,
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.right_margin	= 30,
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.upper_margin	= 37,
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lower_margin	= 3,
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hsync_len	= 20,
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.vsync_len	= 3,
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.vmode		= FB_VMODE_NONINTERLACED,
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18548c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanstatic struct fb_videomode *default_mode = &default_mode_CRT;
18648c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanstatic struct fb_var_screeninfo *default_var = &default_var_CRT;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int flat_panel_enabled = 0;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void gbe_reset(void)
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Turn on dotclock PLL */
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->ctrlstat = 0x300aa000;
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function:	gbe_turn_off
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Parameters:	(None)
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Description:	This should turn off the monitor and gbe.  This is used
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              when switching between the serial console and the graphics
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              console.
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
205b6d57ae97af3c38d28f066b5e47b7d58e468728aDmitri Vorobievstatic void gbe_turn_off(void)
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int val, x, y, vpixen_off;
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2108d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer	gbe_turned_on = 0;
2118d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check if pixel counter is on */
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = gbe->vt_xy;
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (GET_GBE_FIELD(VT_XY, FREEZE, val) == 1)
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* turn off DMA */
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = gbe->ovr_control;
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(OVR_CONTROL, OVR_DMA_ENABLE, val, 0);
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->ovr_control = val;
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(1000);
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = gbe->frm_control;
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 0);
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->frm_control = val;
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(1000);
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = gbe->did_control;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(DID_CONTROL, DID_DMA_ENABLE, val, 0);
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->did_control = val;
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(1000);
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We have to wait through two vertical retrace periods before
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the pixel DMA is turned off for sure. */
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 10000; i++) {
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = gbe->frm_inhwctrl;
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, val)) {
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			udelay(10);
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			val = gbe->ovr_inhwctrl;
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (GET_GBE_FIELD(OVR_INHWCTRL, OVR_DMA_ENABLE, val)) {
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				udelay(10);
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				val = gbe->did_inhwctrl;
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (GET_GBE_FIELD(DID_INHWCTRL, DID_DMA_ENABLE, val)) {
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					udelay(10);
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (i == 10000)
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "gbefb: turn off DMA timed out\n");
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* wait for vpixen_off */
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = gbe->vt_vpixen;
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vpixen_off = GET_GBE_FIELD(VT_VPIXEN, VPIXEN_OFF, val);
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 100000; i++) {
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = gbe->vt_xy;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		x = GET_GBE_FIELD(VT_XY, X, val);
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		y = GET_GBE_FIELD(VT_XY, Y, val);
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (y < vpixen_off)
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(1);
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (i == 100000)
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "gbefb: wait for vpixen_off timed out\n");
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 10000; i++) {
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = gbe->vt_xy;
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		x = GET_GBE_FIELD(VT_XY, X, val);
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		y = GET_GBE_FIELD(VT_XY, Y, val);
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (y > vpixen_off)
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(1);
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (i == 10000)
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "gbefb: wait for vpixen_off timed out\n");
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* turn off pixel counter */
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = 0;
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(VT_XY, FREEZE, val, 1);
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->vt_xy = val;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(10000);
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 10000; i++) {
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = gbe->vt_xy;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (GET_GBE_FIELD(VT_XY, FREEZE, val) != 1)
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			udelay(10);
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (i == 10000)
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "gbefb: turn off pixel clock timed out\n");
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* turn off dot clock */
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = gbe->dotclock;
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(DOTCLK, RUN, val, 0);
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->dotclock = val;
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(10000);
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 10000; i++) {
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = gbe->dotclock;
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (GET_GBE_FIELD(DOTCLK, RUN, val))
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			udelay(10);
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (i == 10000)
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "gbefb: turn off dotclock timed out\n");
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* reset the frame DMA FIFO */
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = gbe->frm_size_tile;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, val, 1);
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->frm_size_tile = val;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, val, 0);
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->frm_size_tile = val;
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void gbe_turn_on(void)
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int val, i;
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Check if pixel counter is off, for unknown reason this
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * code hangs Visual Workstations
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (gbe_revision < 2) {
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = gbe->vt_xy;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (GET_GBE_FIELD(VT_XY, FREEZE, val) == 0)
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* turn on dot clock */
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = gbe->dotclock;
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(DOTCLK, RUN, val, 1);
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->dotclock = val;
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(10000);
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 10000; i++) {
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = gbe->dotclock;
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (GET_GBE_FIELD(DOTCLK, RUN, val) != 1)
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			udelay(10);
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (i == 10000)
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "gbefb: turn on dotclock timed out\n");
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* turn on pixel counter */
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = 0;
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(VT_XY, FREEZE, val, 0);
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->vt_xy = val;
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(10000);
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 10000; i++) {
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = gbe->vt_xy;
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (GET_GBE_FIELD(VT_XY, FREEZE, val))
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			udelay(10);
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (i == 10000)
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "gbefb: turn on pixel clock timed out\n");
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* turn on DMA */
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = gbe->frm_control;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 1);
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->frm_control = val;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(1000);
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 10000; i++) {
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = gbe->frm_inhwctrl;
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, val) != 1)
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			udelay(10);
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (i == 10000)
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "gbefb: turn on DMA timed out\n");
3758d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer
3768d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer	gbe_turned_on = 1;
3778d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer}
3788d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer
3798d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerferstatic void gbe_loadcmap(void)
3808d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer{
3818d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer	int i, j;
3828d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer
3838d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer	for (i = 0; i < 256; i++) {
3848d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer		for (j = 0; j < 1000 && gbe->cm_fifo >= 63; j++)
3858d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer			udelay(10);
3868d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer		if (j == 1000)
3878d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer			printk(KERN_ERR "gbefb: cmap FIFO timeout\n");
3888d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer
3898d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer		gbe->cmap[i] = gbe_cmap[i];
3908d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer	}
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Blank the display.
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int gbefb_blank(int blank, struct fb_info *info)
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (blank) {
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FB_BLANK_UNBLANK:		/* unblank */
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		gbe_turn_on();
4028d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer		gbe_loadcmap();
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FB_BLANK_NORMAL:		/* blank */
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		gbe_turn_off();
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Nothing */
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Setup flatpanel related registers.
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void gbefb_setup_flatpanel(struct gbe_timing_info *timing)
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int fp_wid, fp_hgt, fp_vbs, fp_vbe;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 outputVal = 0;
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(VT_FLAGS, HDRV_INVERT, outputVal,
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(timing->flags & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1);
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(VT_FLAGS, VDRV_INVERT, outputVal,
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(timing->flags & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1);
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->vt_flags = outputVal;
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Turn on the flat panel */
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fp_wid = 1600;
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fp_hgt = 1024;
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fp_vbs = 0;
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fp_vbe = 1600;
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timing->pll_m = 4;
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timing->pll_n = 1;
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timing->pll_p = 0;
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outputVal = 0;
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(FP_DE, ON, outputVal, fp_vbs);
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(FP_DE, OFF, outputVal, fp_vbe);
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->fp_de = outputVal;
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outputVal = 0;
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(FP_HDRV, OFF, outputVal, fp_wid);
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->fp_hdrv = outputVal;
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outputVal = 0;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(FP_VDRV, ON, outputVal, 1);
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(FP_VDRV, OFF, outputVal, fp_hgt + 1);
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->fp_vdrv = outputVal;
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct gbe_pll_info {
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int clock_rate;
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int fvco_min;
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int fvco_max;
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct gbe_pll_info gbe_pll_table[2] = {
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 20, 80, 220 },
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 27, 80, 220 },
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int compute_gbe_timing(struct fb_var_screeninfo *var,
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      struct gbe_timing_info *timing)
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int pll_m, pll_n, pll_p, error, best_m, best_n, best_p, best_error;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int pixclock;
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct gbe_pll_info *gbe_pll;
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (gbe_revision < 2)
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		gbe_pll = &gbe_pll_table[0];
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		gbe_pll = &gbe_pll_table[1];
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Determine valid resolution and timing
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * GBE crystal runs at 20Mhz or 27Mhz
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * pll_m, pll_n, pll_p define the following frequencies
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * fvco = pll_m * 20Mhz / pll_n
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * fout = fvco / (2**pll_p) */
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	best_error = 1000000000;
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	best_n = best_m = best_p = 0;
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (pll_p = 0; pll_p < 4; pll_p++)
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (pll_m = 1; pll_m < 256; pll_m++)
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (pll_n = 1; pll_n < 64; pll_n++) {
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pixclock = (1000000 / gbe_pll->clock_rate) *
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						(pll_n << pll_p) / pll_m;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				error = var->pixclock - pixclock;
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (error < 0)
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					error = -error;
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (error < best_error &&
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    pll_m / pll_n >
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    gbe_pll->fvco_min / gbe_pll->clock_rate &&
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 				    pll_m / pll_n <
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    gbe_pll->fvco_max / gbe_pll->clock_rate) {
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					best_error = error;
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					best_m = pll_m;
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					best_n = pll_n;
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					best_p = pll_p;
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!best_n || !best_m)
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;	/* Resolution to high */
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pixclock = (1000000 / gbe_pll->clock_rate) *
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(best_n << best_p) / best_m;
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set video timing information */
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (timing) {
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timing->width = var->xres;
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timing->height = var->yres;
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timing->pll_m = best_m;
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timing->pll_n = best_n;
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timing->pll_p = best_p;
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timing->cfreq = gbe_pll->clock_rate * 1000 * timing->pll_m /
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(timing->pll_n << timing->pll_p);
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timing->htotal = var->left_margin + var->xres +
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				var->right_margin + var->hsync_len;
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timing->vtotal = var->upper_margin + var->yres +
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				var->lower_margin + var->vsync_len;
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timing->fields_sec = 1000 * timing->cfreq / timing->htotal *
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				1000 / timing->vtotal;
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timing->hblank_start = var->xres;
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timing->vblank_start = var->yres;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timing->hblank_end = timing->htotal;
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timing->hsync_start = var->xres + var->right_margin + 1;
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timing->hsync_end = timing->hsync_start + var->hsync_len;
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timing->vblank_end = timing->vtotal;
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timing->vsync_start = var->yres + var->lower_margin + 1;
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		timing->vsync_end = timing->vsync_start + var->vsync_len;
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return pixclock;
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void gbe_set_timing_info(struct gbe_timing_info *timing)
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int temp;
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int val;
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup dot clock PLL */
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = 0;
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(DOTCLK, M, val, timing->pll_m - 1);
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(DOTCLK, N, val, timing->pll_n - 1);
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(DOTCLK, P, val, timing->pll_p);
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(DOTCLK, RUN, val, 0);	/* do not start yet */
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->dotclock = val;
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(10000);
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup pixel counter */
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = 0;
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(VT_XYMAX, MAXX, val, timing->htotal);
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(VT_XYMAX, MAXY, val, timing->vtotal);
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->vt_xymax = val;
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup video timing signals */
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = 0;
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(VT_VSYNC, VSYNC_ON, val, timing->vsync_start);
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(VT_VSYNC, VSYNC_OFF, val, timing->vsync_end);
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->vt_vsync = val;
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = 0;
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(VT_HSYNC, HSYNC_ON, val, timing->hsync_start);
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(VT_HSYNC, HSYNC_OFF, val, timing->hsync_end);
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->vt_hsync = val;
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = 0;
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(VT_VBLANK, VBLANK_ON, val, timing->vblank_start);
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(VT_VBLANK, VBLANK_OFF, val, timing->vblank_end);
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->vt_vblank = val;
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = 0;
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(VT_HBLANK, HBLANK_ON, val,
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      timing->hblank_start - 5);
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(VT_HBLANK, HBLANK_OFF, val,
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      timing->hblank_end - 3);
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->vt_hblank = val;
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup internal timing signals */
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = 0;
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(VT_VCMAP, VCMAP_ON, val, timing->vblank_start);
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(VT_VCMAP, VCMAP_OFF, val, timing->vblank_end);
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->vt_vcmap = val;
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = 0;
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(VT_HCMAP, HCMAP_ON, val, timing->hblank_start);
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(VT_HCMAP, HCMAP_OFF, val, timing->hblank_end);
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->vt_hcmap = val;
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = 0;
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	temp = timing->vblank_start - timing->vblank_end - 1;
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (temp > 0)
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp = -temp;
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (flat_panel_enabled)
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		gbefb_setup_flatpanel(timing);
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(DID_START_XY, DID_STARTY, val, (u32) temp);
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (timing->hblank_end >= 20)
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SET_GBE_FIELD(DID_START_XY, DID_STARTX, val,
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      timing->hblank_end - 20);
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SET_GBE_FIELD(DID_START_XY, DID_STARTX, val,
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      timing->htotal - (20 - timing->hblank_end));
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->did_start_xy = val;
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = 0;
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(CRS_START_XY, CRS_STARTY, val, (u32) (temp + 1));
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (timing->hblank_end >= GBE_CRS_MAGIC)
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SET_GBE_FIELD(CRS_START_XY, CRS_STARTX, val,
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      timing->hblank_end - GBE_CRS_MAGIC);
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SET_GBE_FIELD(CRS_START_XY, CRS_STARTX, val,
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      timing->htotal - (GBE_CRS_MAGIC -
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						timing->hblank_end));
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->crs_start_xy = val;
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = 0;
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(VC_START_XY, VC_STARTY, val, (u32) temp);
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(VC_START_XY, VC_STARTX, val, timing->hblank_end - 4);
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->vc_start_xy = val;
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = 0;
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	temp = timing->hblank_end - GBE_PIXEN_MAGIC_ON;
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (temp < 0)
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp += timing->htotal;	/* allow blank to wrap around */
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(VT_HPIXEN, HPIXEN_ON, val, temp);
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(VT_HPIXEN, HPIXEN_OFF, val,
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      ((temp + timing->width -
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			GBE_PIXEN_MAGIC_OFF) % timing->htotal));
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->vt_hpixen = val;
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = 0;
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(VT_VPIXEN, VPIXEN_ON, val, timing->vblank_end);
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(VT_VPIXEN, VPIXEN_OFF, val, timing->vblank_start);
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->vt_vpixen = val;
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* turn off sync on green */
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = 0;
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(VT_FLAGS, SYNC_LOW, val, 1);
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->vt_flags = val;
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Set the hardware according to 'par'.
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int gbefb_set_par(struct fb_info *info)
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int val;
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int wholeTilesX, partTilesX, maxPixelsPerTileX;
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int height_pix;
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int xpmax, ypmax;	/* Monitor resolution */
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int bytesPerPixel;	/* Bytes per pixel */
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct gbefb_par *par = (struct gbefb_par *) info->par;
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	compute_gbe_timing(&info->var, &par->timing);
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bytesPerPixel = info->var.bits_per_pixel / 8;
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->fix.line_length = info->var.xres_virtual * bytesPerPixel;
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xpmax = par->timing.width;
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ypmax = par->timing.height;
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* turn off GBE */
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe_turn_off();
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set timing info */
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe_set_timing_info(&par->timing);
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* initialize DIDs */
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = 0;
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (bytesPerPixel) {
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1:
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_I8);
67668b06deb2b343c040485a9fc6c813577bf6d5cf5Kaj-Michael Lang		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 2:
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_ARGB5);
68068b06deb2b343c040485a9fc6c813577bf6d5cf5Kaj-Michael Lang		info->fix.visual = FB_VISUAL_TRUECOLOR;
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 4:
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_RGB8);
68468b06deb2b343c040485a9fc6c813577bf6d5cf5Kaj-Michael Lang		info->fix.visual = FB_VISUAL_TRUECOLOR;
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(WID, BUF, val, GBE_BMODE_BOTH);
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 32; i++)
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		gbe->mode_regs[i] = val;
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Initialize interrupts */
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->vt_intr01 = 0xffffffff;
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->vt_intr23 = 0xffffffff;
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* HACK:
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   The GBE hardware uses a tiled memory to screen mapping. Tiles are
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   blocks of 512x128, 256x128 or 128x128 pixels, respectively for 8bit,
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   16bit and 32 bit modes (64 kB). They cover the screen with partial
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   tiles on the right and/or bottom of the screen if needed.
701af901ca181d92aac3a7dc265144a9081a86d8f39André Goddard Rosa	   For example in 640x480 8 bit mode the mapping is:
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   <-------- 640 ----->
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   <---- 512 ----><128|384 offscreen>
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   ^  ^
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   | 128    [tile 0]        [tile 1]
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   |  v
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   ^
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   4 128    [tile 2]        [tile 3]
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   8  v
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   0  ^
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   128    [tile 4]        [tile 5]
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   |  v
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   |  ^
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   v  96    [tile 6]        [tile 7]
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   32 offscreen
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   Tiles have the advantage that they can be allocated individually in
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   memory. However, this mapping is not linear at all, which is not
72025985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	   really convenient. In order to support linear addressing, the GBE
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   DMA hardware is fooled into thinking the screen is only one tile
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   large and but has a greater height, so that the DMA transfer covers
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   the same region.
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   Tiles are still allocated as independent chunks of 64KB of
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   continuous physical memory and remapped so that the kernel sees the
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   framebuffer as a continuous virtual memory. The GBE tile table is
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   set up so that each tile references one of these 64k blocks:
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   GBE -> tile list    framebuffer           TLB   <------------ CPU
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	          [ tile 0 ] -> [ 64KB ]  <- [ 16x 4KB page entries ]     ^
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	             ...           ...              ...       linear virtual FB
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	          [ tile n ] -> [ 64KB ]  <- [ 16x 4KB page entries ]     v
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   The GBE hardware is then told that the buffer is 512*tweaked_height,
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   with tweaked_height = real_width*real_height/pixels_per_tile.
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   Thus the GBE hardware will scan the first tile, filing the first 64k
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   covered region of the screen, and then will proceed to the next
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   tile, until the whole screen is covered.
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   Here is what would happen at 640x480 8bit:
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   normal tiling               linear
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   ^   11111111111111112222    11111111111111111111  ^
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   128 11111111111111112222    11111111111111111111 102 lines
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       11111111111111112222    11111111111111111111  v
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   V   11111111111111112222    11111111222222222222
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       33333333333333334444    22222222222222222222
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       33333333333333334444    22222222222222222222
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       <      512     >        <  256 >               102*640+256 = 64k
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   NOTE: The only mode for which this is not working is 800x600 8bit,
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   as 800*600/512 = 937.5 which is not integer and thus causes
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   flickering.
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   I guess this is not so important as one can use 640x480 8bit or
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   800x600 16bit anyway.
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Tell gbe about the tiles table location */
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* tile_ptr -> [ tile 1 ] -> FB mem */
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*             [ tile 2 ] -> FB mem */
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*               ...                */
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = 0;
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(FRM_CONTROL, FRM_TILE_PTR, val, gbe_tiles.dma >> 9);
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 0); /* do not start */
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(FRM_CONTROL, FRM_LINEAR, val, 0);
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->frm_control = val;
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	maxPixelsPerTileX = 512 / bytesPerPixel;
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wholeTilesX = 1;
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	partTilesX = 0;
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Initialize the framebuffer */
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = 0;
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(FRM_SIZE_TILE, FRM_WIDTH_TILE, val, wholeTilesX);
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(FRM_SIZE_TILE, FRM_RHS, val, partTilesX);
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (bytesPerPixel) {
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1:
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      GBE_FRM_DEPTH_8);
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 2:
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      GBE_FRM_DEPTH_16);
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 4:
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      GBE_FRM_DEPTH_32);
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->frm_size_tile = val;
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* compute tweaked height */
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	height_pix = xpmax * ypmax / maxPixelsPerTileX;
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = 0;
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_GBE_FIELD(FRM_SIZE_PIXEL, FB_HEIGHT_PIX, val, height_pix);
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->frm_size_pixel = val;
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* turn off DID and overlay DMA */
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->did_control = 0;
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->ovr_width_tile = 0;
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Turn off mouse cursor */
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe->crs_ctl = 0;
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Turn on GBE */
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe_turn_on();
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Initialize the gamma map */
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(10);
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 256; i++)
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		gbe->gmap[i] = (i << 24) | (i << 16) | (i << 8);
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Initialize the color map */
8178d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer	for (i = 0; i < 256; i++)
8188d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer		gbe_cmap[i] = (i << 8) | (i << 16) | (i << 24);
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8208d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer	gbe_loadcmap();
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void gbefb_encode_fix(struct fb_fix_screeninfo *fix,
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     struct fb_var_screeninfo *var)
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcpy(fix->id, "SGI GBE");
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fix->smem_start = (unsigned long) gbe_mem;
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fix->smem_len = gbe_mem_size;
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fix->type = FB_TYPE_PACKED_PIXELS;
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fix->type_aux = 0;
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fix->accel = FB_ACCEL_NONE;
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (var->bits_per_pixel) {
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 8:
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fix->visual = FB_VISUAL_PSEUDOCOLOR;
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fix->visual = FB_VISUAL_TRUECOLOR;
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fix->ywrapstep = 0;
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fix->xpanstep = 0;
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fix->ypanstep = 0;
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fix->mmio_start = GBE_BASE;
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fix->mmio_len = sizeof(struct sgi_gbe);
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Set a single color register. The values supplied are already
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  rounded down to the hardware's capabilities (according to the
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  entries in the var structure). Return != 0 for invalid regno.
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int gbefb_setcolreg(unsigned regno, unsigned red, unsigned green,
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     unsigned blue, unsigned transp,
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     struct fb_info *info)
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (regno > 255)
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	red >>= 8;
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	green >>= 8;
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	blue >>= 8;
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8699058be43cf9f32b6c636aa6954b4f1a6b22098f6Antonino A. Daplas	if (info->var.bits_per_pixel <= 8) {
8708d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer		gbe_cmap[regno] = (red << 24) | (green << 16) | (blue << 8);
8718d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer		if (gbe_turned_on) {
8728d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer			/* wait for the color map FIFO to have a free entry */
8738d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer			for (i = 0; i < 1000 && gbe->cm_fifo >= 63; i++)
8748d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer				udelay(10);
8758d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer			if (i == 1000) {
8768d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer				printk(KERN_ERR "gbefb: cmap FIFO timeout\n");
8778d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer				return 1;
8788d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer			}
8798d0b1c51eb8375f88c0886d2e9f71881e19d42a7Thomas Bogendoerfer			gbe->cmap[regno] = gbe_cmap[regno];
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8819058be43cf9f32b6c636aa6954b4f1a6b22098f6Antonino A. Daplas	} else if (regno < 16) {
8829058be43cf9f32b6c636aa6954b4f1a6b22098f6Antonino A. Daplas		switch (info->var.bits_per_pixel) {
8839058be43cf9f32b6c636aa6954b4f1a6b22098f6Antonino A. Daplas		case 15:
8849058be43cf9f32b6c636aa6954b4f1a6b22098f6Antonino A. Daplas		case 16:
8859058be43cf9f32b6c636aa6954b4f1a6b22098f6Antonino A. Daplas			red >>= 3;
8869058be43cf9f32b6c636aa6954b4f1a6b22098f6Antonino A. Daplas			green >>= 3;
8879058be43cf9f32b6c636aa6954b4f1a6b22098f6Antonino A. Daplas			blue >>= 3;
8889058be43cf9f32b6c636aa6954b4f1a6b22098f6Antonino A. Daplas			pseudo_palette[regno] =
8899058be43cf9f32b6c636aa6954b4f1a6b22098f6Antonino A. Daplas				(red << info->var.red.offset) |
8909058be43cf9f32b6c636aa6954b4f1a6b22098f6Antonino A. Daplas				(green << info->var.green.offset) |
8919058be43cf9f32b6c636aa6954b4f1a6b22098f6Antonino A. Daplas				(blue << info->var.blue.offset);
8929058be43cf9f32b6c636aa6954b4f1a6b22098f6Antonino A. Daplas			break;
8939058be43cf9f32b6c636aa6954b4f1a6b22098f6Antonino A. Daplas		case 32:
8949058be43cf9f32b6c636aa6954b4f1a6b22098f6Antonino A. Daplas			pseudo_palette[regno] =
8959058be43cf9f32b6c636aa6954b4f1a6b22098f6Antonino A. Daplas				(red << info->var.red.offset) |
8969058be43cf9f32b6c636aa6954b4f1a6b22098f6Antonino A. Daplas				(green << info->var.green.offset) |
8979058be43cf9f32b6c636aa6954b4f1a6b22098f6Antonino A. Daplas				(blue << info->var.blue.offset);
8989058be43cf9f32b6c636aa6954b4f1a6b22098f6Antonino A. Daplas			break;
8999058be43cf9f32b6c636aa6954b4f1a6b22098f6Antonino A. Daplas		}
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Check video mode validity, eventually modify var to best match.
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int gbefb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int line_length;
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct gbe_timing_info timing;
9126405141fb3d06ec4a50d054a113e3317cad054f9roel kluin	int ret;
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Limit bpp to 8, 16, and 32 */
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->bits_per_pixel <= 8)
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->bits_per_pixel = 8;
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (var->bits_per_pixel <= 16)
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->bits_per_pixel = 16;
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (var->bits_per_pixel <= 32)
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->bits_per_pixel = 32;
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check the mode can be mapped linearly with the tile table trick. */
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* This requires width x height x bytes/pixel be a multiple of 512 */
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((var->xres * var->yres * var->bits_per_pixel) & 4095)
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	var->grayscale = 0;	/* No grayscale for now */
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9316405141fb3d06ec4a50d054a113e3317cad054f9roel kluin	ret = compute_gbe_timing(var, &timing);
9326405141fb3d06ec4a50d054a113e3317cad054f9roel kluin	var->pixclock = ret;
9336405141fb3d06ec4a50d054a113e3317cad054f9roel kluin	if (ret < 0)
9346405141fb3d06ec4a50d054a113e3317cad054f9roel kluin		return -EINVAL;
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Adjust virtual resolution, if necessary */
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->xres > var->xres_virtual || (!ywrap && !ypan))
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->xres_virtual = var->xres;
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->yres > var->yres_virtual || (!ywrap && !ypan))
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->yres_virtual = var->yres;
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->vmode & FB_VMODE_CONUPDATE) {
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->vmode |= FB_VMODE_YWRAP;
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->xoffset = info->var.xoffset;
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->yoffset = info->var.yoffset;
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* No grayscale for now */
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	var->grayscale = 0;
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Memory limit */
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	line_length = var->xres_virtual * var->bits_per_pixel / 8;
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (line_length * var->yres_virtual > gbe_mem_size)
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;	/* Virtual resolution too high */
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (var->bits_per_pixel) {
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 8:
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->red.offset = 0;
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->red.length = 8;
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->green.offset = 0;
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->green.length = 8;
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->blue.offset = 0;
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->blue.length = 8;
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->transp.offset = 0;
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->transp.length = 0;
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 16:		/* RGB 1555 */
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->red.offset = 10;
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->red.length = 5;
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->green.offset = 5;
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->green.length = 5;
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->blue.offset = 0;
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->blue.length = 5;
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->transp.offset = 0;
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->transp.length = 0;
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 32:		/* RGB 8888 */
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->red.offset = 24;
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->red.length = 8;
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->green.offset = 16;
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->green.length = 8;
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->blue.offset = 8;
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->blue.length = 8;
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->transp.offset = 0;
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->transp.length = 8;
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	var->red.msb_right = 0;
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	var->green.msb_right = 0;
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	var->blue.msb_right = 0;
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	var->transp.msb_right = 0;
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	var->left_margin = timing.htotal - timing.hsync_end;
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	var->right_margin = timing.hsync_start - timing.width;
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	var->upper_margin = timing.vtotal - timing.vsync_end;
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	var->lower_margin = timing.vsync_start - timing.height;
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	var->hsync_len = timing.hsync_end - timing.hsync_start;
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	var->vsync_len = timing.vsync_end - timing.vsync_start;
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1003216d526c89d144928f095f2800bc6c67e968d628Christoph Hellwigstatic int gbefb_mmap(struct fb_info *info,
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct vm_area_struct *vma)
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long size = vma->vm_end - vma->vm_start;
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long addr;
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long phys_addr, phys_size;
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 *tile;
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check range */
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
101504f8afbec37f63fafce16e454a7848426aa36202Tomi Valkeinen	if (size > gbe_mem_size)
101604f8afbec37f63fafce16e454a7848426aa36202Tomi Valkeinen		return -EINVAL;
101704f8afbec37f63fafce16e454a7848426aa36202Tomi Valkeinen	if (offset > gbe_mem_size - size)
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* remap using the fastest write-through mode on architecture */
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* try not polluting the cache when possible */
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pgprot_val(vma->vm_page_prot) =
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pgprot_fb(pgprot_val(vma->vm_page_prot));
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1025314e51b9851b4f4e8ab302243ff5a6fc6147f379Konstantin Khlebnikov	/* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* look for the starting tile */
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tile = &gbe_tiles.cpu[offset >> TILE_SHIFT];
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	addr = vma->vm_start;
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	offset &= TILE_MASK;
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* remap each tile separately */
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		phys_addr = (((unsigned long) (*tile)) << TILE_SHIFT) + offset;
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((offset + size) < TILE_SIZE)
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			phys_size = size;
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			phys_size = TILE_SIZE - offset;
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (remap_pfn_range(vma, addr, phys_addr >> PAGE_SHIFT,
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						phys_size, vma->vm_page_prot))
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EAGAIN;
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		offset = 0;
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size -= phys_size;
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		addr += phys_size;
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tile++;
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while (size);
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct fb_ops gbefb_ops = {
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner		= THIS_MODULE,
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_check_var	= gbefb_check_var,
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_set_par	= gbefb_set_par,
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_setcolreg	= gbefb_setcolreg,
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_mmap	= gbefb_mmap,
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_blank	= gbefb_blank,
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_fillrect	= cfb_fillrect,
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_copyarea	= cfb_copyarea,
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_imageblit	= cfb_imageblit,
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sysfs
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1069060b8845e6bea938d65ad6f89e83507e5ff4fec4Yani Ioannoustatic ssize_t gbefb_show_memsize(struct device *dev, struct device_attribute *attr, char *buf)
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10717e81b9ddf2be0f691bf883acfe2b2ee6e55baa7eMasanari Iida	return snprintf(buf, PAGE_SIZE, "%u\n", gbe_mem_size);
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(size, S_IRUGO, gbefb_show_memsize, NULL);
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1076060b8845e6bea938d65ad6f89e83507e5ff4fec4Yani Ioannoustatic ssize_t gbefb_show_rev(struct device *device, struct device_attribute *attr, char *buf)
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return snprintf(buf, PAGE_SIZE, "%d\n", gbe_revision);
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(revision, S_IRUGO, gbefb_show_rev, NULL);
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
108348c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanstatic void gbefb_remove_sysfs(struct device *dev)
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_remove_file(dev, &dev_attr_size);
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_remove_file(dev, &dev_attr_revision);
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void gbefb_create_sysfs(struct device *dev)
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_create_file(dev, &dev_attr_size);
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_create_file(dev, &dev_attr_revision);
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initialization
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
109948c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanstatic int gbefb_setup(char *options)
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *this_opt;
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!options || !*options)
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((this_opt = strsep(&options, ",")) != NULL) {
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!strncmp(this_opt, "monitor:", 8)) {
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!strncmp(this_opt + 8, "crt", 3)) {
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				flat_panel_enabled = 0;
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				default_var = &default_var_CRT;
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				default_mode = &default_mode_CRT;
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (!strncmp(this_opt + 8, "1600sw", 6) ||
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   !strncmp(this_opt + 8, "lcd", 3)) {
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				flat_panel_enabled = 1;
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				default_var = &default_var_LCD;
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				default_mode = &default_mode_LCD;
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (!strncmp(this_opt, "mem:", 4)) {
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			gbe_mem_size = memparse(this_opt + 4, &this_opt);
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (gbe_mem_size > CONFIG_FB_GBE_MEM * 1024 * 1024)
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				gbe_mem_size = CONFIG_FB_GBE_MEM * 1024 * 1024;
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (gbe_mem_size < TILE_SIZE)
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				gbe_mem_size = TILE_SIZE;
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mode_option = this_opt;
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
113048c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanstatic int gbefb_probe(struct platform_device *p_dev)
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, ret = 0;
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fb_info *info;
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct gbefb_par *par;
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef MODULE
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *options = NULL;
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info = framebuffer_alloc(sizeof(struct gbefb_par), &p_dev->dev);
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!info)
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef MODULE
1144f35691062a138484b51bf53b36ae8a4495d8fb91Julia Lawall	if (fb_get_options("gbefb", &options)) {
1145f35691062a138484b51bf53b36ae8a4495d8fb91Julia Lawall		ret = -ENODEV;
1146f35691062a138484b51bf53b36ae8a4495d8fb91Julia Lawall		goto out_release_framebuffer;
1147f35691062a138484b51bf53b36ae8a4495d8fb91Julia Lawall	}
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbefb_setup(options);
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11510fdd07f77fd9cc6a7d49076793daef06ea5d8f13Julia Lawall	if (!request_mem_region(GBE_BASE, sizeof(struct sgi_gbe), "GBE")) {
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "gbefb: couldn't reserve mmio region\n");
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -EBUSY;
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_release_framebuffer;
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1157ae1937f69b1f04dcb2a855d66f94860a6bcf7620Damien Cassou	gbe = (struct sgi_gbe *) devm_ioremap(&p_dev->dev, GBE_BASE,
1158ae1937f69b1f04dcb2a855d66f94860a6bcf7620Damien Cassou					      sizeof(struct sgi_gbe));
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!gbe) {
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "gbefb: couldn't map mmio region\n");
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -ENXIO;
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_release_mem_region;
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe_revision = gbe->ctrlstat & 15;
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe_tiles.cpu =
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dma_alloc_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   &gbe_tiles.dma, GFP_KERNEL);
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!gbe_tiles.cpu) {
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "gbefb: couldn't allocate tiles table\n");
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -ENOMEM;
1172ae1937f69b1f04dcb2a855d66f94860a6bcf7620Damien Cassou		goto out_release_mem_region;
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (gbe_mem_phys) {
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* memory was allocated at boot time */
1177ae1937f69b1f04dcb2a855d66f94860a6bcf7620Damien Cassou		gbe_mem = devm_ioremap_nocache(&p_dev->dev, gbe_mem_phys,
1178ae1937f69b1f04dcb2a855d66f94860a6bcf7620Damien Cassou					       gbe_mem_size);
11796d7bf017e821f3c093c80d1ee919d8d87904701cThiemo Seufer		if (!gbe_mem) {
11806d7bf017e821f3c093c80d1ee919d8d87904701cThiemo Seufer			printk(KERN_ERR "gbefb: couldn't map framebuffer\n");
11816d7bf017e821f3c093c80d1ee919d8d87904701cThiemo Seufer			ret = -ENOMEM;
11826d7bf017e821f3c093c80d1ee919d8d87904701cThiemo Seufer			goto out_tiles_free;
11836d7bf017e821f3c093c80d1ee919d8d87904701cThiemo Seufer		}
11846d7bf017e821f3c093c80d1ee919d8d87904701cThiemo Seufer
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		gbe_dma_addr = 0;
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* try to allocate memory with the classical allocator
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * this has high chance to fail on low memory machines */
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		gbe_mem = dma_alloc_coherent(NULL, gbe_mem_size, &gbe_dma_addr,
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     GFP_KERNEL);
11916d7bf017e821f3c093c80d1ee919d8d87904701cThiemo Seufer		if (!gbe_mem) {
11926d7bf017e821f3c093c80d1ee919d8d87904701cThiemo Seufer			printk(KERN_ERR "gbefb: couldn't allocate framebuffer memory\n");
11936d7bf017e821f3c093c80d1ee919d8d87904701cThiemo Seufer			ret = -ENOMEM;
11946d7bf017e821f3c093c80d1ee919d8d87904701cThiemo Seufer			goto out_tiles_free;
11956d7bf017e821f3c093c80d1ee919d8d87904701cThiemo Seufer		}
11966d7bf017e821f3c093c80d1ee919d8d87904701cThiemo Seufer
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		gbe_mem_phys = (unsigned long) gbe_dma_addr;
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_X86
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mtrr_add(gbe_mem_phys, gbe_mem_size, MTRR_TYPE_WRCOMB, 1);
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* map framebuffer memory into tiles table */
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < (gbe_mem_size >> TILE_SHIFT); i++)
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		gbe_tiles.cpu[i] = (gbe_mem_phys >> TILE_SHIFT) + i;
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->fbops = &gbefb_ops;
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->pseudo_palette = pseudo_palette;
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->flags = FBINFO_DEFAULT;
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->screen_base = gbe_mem;
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fb_alloc_cmap(&info->cmap, 256, 0);
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* reset GBE */
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe_reset();
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	par = info->par;
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* turn on default video mode */
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fb_find_mode(&par->var, info, mode_option, NULL, 0,
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 default_mode, 8) == 0)
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		par->var = *default_var;
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->var = par->var;
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbefb_check_var(&par->var, info);
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbefb_encode_fix(&info->fix, &info->var);
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (register_framebuffer(info) < 0) {
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "gbefb: couldn't register framebuffer\n");
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -ENXIO;
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_gbe_unmap;
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12323ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	platform_set_drvdata(p_dev, info);
12333ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	gbefb_create_sysfs(&p_dev->dev);
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
123531b6780c15a4e3a90fe260e977f5186772ce7afbJoe Perches	fb_info(info, "%s rev %d @ 0x%08x using %dkB memory\n",
123631b6780c15a4e3a90fe260e977f5186772ce7afbJoe Perches		info->fix.id, gbe_revision, (unsigned)GBE_BASE,
123731b6780c15a4e3a90fe260e977f5186772ce7afbJoe Perches		gbe_mem_size >> 10);
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_gbe_unmap:
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (gbe_dma_addr)
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys);
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_tiles_free:
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  (void *)gbe_tiles.cpu, gbe_tiles.dma);
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_release_mem_region:
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_mem_region(GBE_BASE, sizeof(struct sgi_gbe));
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_release_framebuffer:
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	framebuffer_release(info);
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
125548c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanstatic int gbefb_remove(struct platform_device* p_dev)
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12573ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	struct fb_info *info = platform_get_drvdata(p_dev);
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unregister_framebuffer(info);
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gbe_turn_off();
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (gbe_dma_addr)
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys);
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  (void *)gbe_tiles.cpu, gbe_tiles.dma);
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_mem_region(GBE_BASE, sizeof(struct sgi_gbe));
1266d30864392823d5f38002fa32950689e651ee11daJoshua Kinard	gbefb_remove_sysfs(&p_dev->dev);
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	framebuffer_release(info);
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12723ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver gbefb_driver = {
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe = gbefb_probe,
127448c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartman	.remove = gbefb_remove,
12753ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	.driver	= {
12763ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.name = "gbefb",
12773ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	},
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1280abbf268ae8f51e19779cdf3f5fbb8144f1a5fbc3Russell Kingstatic struct platform_device *gbefb_device;
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1282b6d57ae97af3c38d28f066b5e47b7d58e468728aDmitri Vorobievstatic int __init gbefb_init(void)
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12843ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	int ret = platform_driver_register(&gbefb_driver);
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ret) {
1286abbf268ae8f51e19779cdf3f5fbb8144f1a5fbc3Russell King		gbefb_device = platform_device_alloc("gbefb", 0);
1287abbf268ae8f51e19779cdf3f5fbb8144f1a5fbc3Russell King		if (gbefb_device) {
1288abbf268ae8f51e19779cdf3f5fbb8144f1a5fbc3Russell King			ret = platform_device_add(gbefb_device);
1289abbf268ae8f51e19779cdf3f5fbb8144f1a5fbc3Russell King		} else {
1290abbf268ae8f51e19779cdf3f5fbb8144f1a5fbc3Russell King			ret = -ENOMEM;
1291abbf268ae8f51e19779cdf3f5fbb8144f1a5fbc3Russell King		}
1292abbf268ae8f51e19779cdf3f5fbb8144f1a5fbc3Russell King		if (ret) {
1293abbf268ae8f51e19779cdf3f5fbb8144f1a5fbc3Russell King			platform_device_put(gbefb_device);
12943ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King			platform_driver_unregister(&gbefb_driver);
1295abbf268ae8f51e19779cdf3f5fbb8144f1a5fbc3Russell King		}
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1300b6d57ae97af3c38d28f066b5e47b7d58e468728aDmitri Vorobievstatic void __exit gbefb_exit(void)
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1302abbf268ae8f51e19779cdf3f5fbb8144f1a5fbc3Russell King	platform_device_unregister(gbefb_device);
13033ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	platform_driver_unregister(&gbefb_driver);
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(gbefb_init);
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(gbefb_exit);
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
1310