File Index
Files and directories
Sign in
FILE

gbefb.c

File preview with syntax highlighting.

linux-6.19.14/drivers/video/fbdev/gbefb.c C
   1/*
   2 *  SGI GBE frame buffer driver
   3 *
   4 *  Copyright (C) 1999 Silicon Graphics, Inc. - Jeffrey Newquist
   5 *  Copyright (C) 2002 Vivien Chappelier <vivien.chappelier@linux-mips.org>
   6 *
   7 *  This file is subject to the terms and conditions of the GNU General Public
   8 *  License. See the file COPYING in the main directory of this archive for
   9 *  more details.
  10 */
  11
  12#include <linux/delay.h>
  13#include <linux/platform_device.h>
  14#include <linux/dma-mapping.h>
  15#include <linux/dma-direct.h>
  16#include <linux/errno.h>
  17#include <linux/gfp.h>
  18#include <linux/fb.h>
  19#include <linux/init.h>
  20#include <linux/interrupt.h>
  21#include <linux/kernel.h>
  22#include <linux/mm.h>
  23#include <linux/module.h>
  24#include <linux/io.h>
  25
  26#ifdef CONFIG_MIPS
  27#include <asm/addrspace.h>
  28#endif
  29#include <asm/byteorder.h>
  30#include <asm/tlbflush.h>
  31
  32#include <video/gbe.h>
  33
  34static struct sgi_gbe *gbe;
  35
  36struct gbefb_par {
  37	struct fb_var_screeninfo var;
  38	struct gbe_timing_info timing;
  39	int wc_cookie;
  40	int valid;
  41};
  42
  43#define GBE_BASE	0x16000000 /* SGI O2 */
  44
  45/* macro for fastest write-though access to the framebuffer */
  46#ifdef CONFIG_MIPS
  47#ifdef CONFIG_CPU_R10000
  48#define pgprot_fb(_prot) (((_prot) & (~_CACHE_MASK)) | _CACHE_UNCACHED_ACCELERATED)
  49#else
  50#define pgprot_fb(_prot) (((_prot) & (~_CACHE_MASK)) | _CACHE_CACHABLE_NO_WA)
  51#endif
  52#endif
  53
  54/*
  55 *  RAM we reserve for the frame buffer. This defines the maximum screen
  56 *  size
  57 */
  58#if CONFIG_FB_GBE_MEM > 8
  59#error GBE Framebuffer cannot use more than 8MB of memory
  60#endif
  61
  62#define TILE_SHIFT 16
  63#define TILE_SIZE (1 << TILE_SHIFT)
  64#define TILE_MASK (TILE_SIZE - 1)
  65
  66static unsigned int gbe_mem_size = CONFIG_FB_GBE_MEM * 1024*1024;
  67static void *gbe_mem;
  68static dma_addr_t gbe_dma_addr;
  69static phys_addr_t gbe_mem_phys;
  70
  71static struct {
  72	uint16_t *cpu;
  73	dma_addr_t dma;
  74} gbe_tiles;
  75
  76static int gbe_revision;
  77
  78static int ypan, ywrap;
  79
  80static uint32_t pseudo_palette[16];
  81static uint32_t gbe_cmap[256];
  82static int gbe_turned_on; /* 0 turned off, 1 turned on */
  83
  84static char *mode_option = NULL;
  85
  86/* default CRT mode */
  87static struct fb_var_screeninfo default_var_CRT = {
  88	/* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
  89	.xres		= 640,
  90	.yres		= 480,
  91	.xres_virtual	= 640,
  92	.yres_virtual	= 480,
  93	.xoffset	= 0,
  94	.yoffset	= 0,
  95	.bits_per_pixel	= 8,
  96	.grayscale	= 0,
  97	.red		= { 0, 8, 0 },
  98	.green		= { 0, 8, 0 },
  99	.blue		= { 0, 8, 0 },
 100	.transp		= { 0, 0, 0 },
 101	.nonstd		= 0,
 102	.activate	= 0,
 103	.height		= -1,
 104	.width		= -1,
 105	.accel_flags	= 0,
 106	.pixclock	= 39722,	/* picoseconds */
 107	.left_margin	= 48,
 108	.right_margin	= 16,
 109	.upper_margin	= 33,
 110	.lower_margin	= 10,
 111	.hsync_len	= 96,
 112	.vsync_len	= 2,
 113	.sync		= 0,
 114	.vmode		= FB_VMODE_NONINTERLACED,
 115};
 116
 117/* default LCD mode */
 118static struct fb_var_screeninfo default_var_LCD = {
 119	/* 1600x1024, 8 bpp */
 120	.xres		= 1600,
 121	.yres		= 1024,
 122	.xres_virtual	= 1600,
 123	.yres_virtual	= 1024,
 124	.xoffset	= 0,
 125	.yoffset	= 0,
 126	.bits_per_pixel	= 8,
 127	.grayscale	= 0,
 128	.red		= { 0, 8, 0 },
 129	.green		= { 0, 8, 0 },
 130	.blue		= { 0, 8, 0 },
 131	.transp		= { 0, 0, 0 },
 132	.nonstd		= 0,
 133	.activate	= 0,
 134	.height		= -1,
 135	.width		= -1,
 136	.accel_flags	= 0,
 137	.pixclock	= 9353,
 138	.left_margin	= 20,
 139	.right_margin	= 30,
 140	.upper_margin	= 37,
 141	.lower_margin	= 3,
 142	.hsync_len	= 20,
 143	.vsync_len	= 3,
 144	.sync		= 0,
 145	.vmode		= FB_VMODE_NONINTERLACED
 146};
 147
 148/* default modedb mode */
 149/* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */
 150static struct fb_videomode default_mode_CRT = {
 151	.refresh	= 60,
 152	.xres		= 640,
 153	.yres		= 480,
 154	.pixclock	= 39722,
 155	.left_margin	= 48,
 156	.right_margin	= 16,
 157	.upper_margin	= 33,
 158	.lower_margin	= 10,
 159	.hsync_len	= 96,
 160	.vsync_len	= 2,
 161	.sync		= 0,
 162	.vmode		= FB_VMODE_NONINTERLACED,
 163};
 164/* 1600x1024 SGI flatpanel 1600sw */
 165static struct fb_videomode default_mode_LCD = {
 166	/* 1600x1024, 8 bpp */
 167	.xres		= 1600,
 168	.yres		= 1024,
 169	.pixclock	= 9353,
 170	.left_margin	= 20,
 171	.right_margin	= 30,
 172	.upper_margin	= 37,
 173	.lower_margin	= 3,
 174	.hsync_len	= 20,
 175	.vsync_len	= 3,
 176	.vmode		= FB_VMODE_NONINTERLACED,
 177};
 178
 179static struct fb_videomode *default_mode = &default_mode_CRT;
 180static struct fb_var_screeninfo *default_var = &default_var_CRT;
 181
 182static int flat_panel_enabled = 0;
 183
 184static void gbe_reset(void)
 185{
 186	/* Turn on dotclock PLL */
 187	gbe->ctrlstat = 0x300aa000;
 188}
 189
 190
 191/*
 192 * Function:	gbe_turn_off
 193 * Parameters:	(None)
 194 * Description:	This should turn off the monitor and gbe.  This is used
 195 *              when switching between the serial console and the graphics
 196 *              console.
 197 */
 198
 199static void gbe_turn_off(void)
 200{
 201	int i;
 202	unsigned int val, y, vpixen_off;
 203
 204	gbe_turned_on = 0;
 205
 206	/* check if pixel counter is on */
 207	val = gbe->vt_xy;
 208	if (GET_GBE_FIELD(VT_XY, FREEZE, val) == 1)
 209		return;
 210
 211	/* turn off DMA */
 212	val = gbe->ovr_control;
 213	SET_GBE_FIELD(OVR_CONTROL, OVR_DMA_ENABLE, val, 0);
 214	gbe->ovr_control = val;
 215	udelay(1000);
 216	val = gbe->frm_control;
 217	SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 0);
 218	gbe->frm_control = val;
 219	udelay(1000);
 220	val = gbe->did_control;
 221	SET_GBE_FIELD(DID_CONTROL, DID_DMA_ENABLE, val, 0);
 222	gbe->did_control = val;
 223	udelay(1000);
 224
 225	/* We have to wait through two vertical retrace periods before
 226	 * the pixel DMA is turned off for sure. */
 227	for (i = 0; i < 10000; i++) {
 228		val = gbe->frm_inhwctrl;
 229		if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, val)) {
 230			udelay(10);
 231		} else {
 232			val = gbe->ovr_inhwctrl;
 233			if (GET_GBE_FIELD(OVR_INHWCTRL, OVR_DMA_ENABLE, val)) {
 234				udelay(10);
 235			} else {
 236				val = gbe->did_inhwctrl;
 237				if (GET_GBE_FIELD(DID_INHWCTRL, DID_DMA_ENABLE, val)) {
 238					udelay(10);
 239				} else
 240					break;
 241			}
 242		}
 243	}
 244	if (i == 10000)
 245		printk(KERN_ERR "gbefb: turn off DMA timed out\n");
 246
 247	/* wait for vpixen_off */
 248	val = gbe->vt_vpixen;
 249	vpixen_off = GET_GBE_FIELD(VT_VPIXEN, VPIXEN_OFF, val);
 250
 251	for (i = 0; i < 100000; i++) {
 252		val = gbe->vt_xy;
 253		y = GET_GBE_FIELD(VT_XY, Y, val);
 254		if (y < vpixen_off)
 255			break;
 256		udelay(1);
 257	}
 258	if (i == 100000)
 259		printk(KERN_ERR
 260		       "gbefb: wait for vpixen_off timed out\n");
 261	for (i = 0; i < 10000; i++) {
 262		val = gbe->vt_xy;
 263		y = GET_GBE_FIELD(VT_XY, Y, val);
 264		if (y > vpixen_off)
 265			break;
 266		udelay(1);
 267	}
 268	if (i == 10000)
 269		printk(KERN_ERR "gbefb: wait for vpixen_off timed out\n");
 270
 271	/* turn off pixel counter */
 272	val = 0;
 273	SET_GBE_FIELD(VT_XY, FREEZE, val, 1);
 274	gbe->vt_xy = val;
 275	mdelay(10);
 276	for (i = 0; i < 10000; i++) {
 277		val = gbe->vt_xy;
 278		if (GET_GBE_FIELD(VT_XY, FREEZE, val) != 1)
 279			udelay(10);
 280		else
 281			break;
 282	}
 283	if (i == 10000)
 284		printk(KERN_ERR "gbefb: turn off pixel clock timed out\n");
 285
 286	/* turn off dot clock */
 287	val = gbe->dotclock;
 288	SET_GBE_FIELD(DOTCLK, RUN, val, 0);
 289	gbe->dotclock = val;
 290	mdelay(10);
 291	for (i = 0; i < 10000; i++) {
 292		val = gbe->dotclock;
 293		if (GET_GBE_FIELD(DOTCLK, RUN, val))
 294			udelay(10);
 295		else
 296			break;
 297	}
 298	if (i == 10000)
 299		printk(KERN_ERR "gbefb: turn off dotclock timed out\n");
 300
 301	/* reset the frame DMA FIFO */
 302	val = gbe->frm_size_tile;
 303	SET_GBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, val, 1);
 304	gbe->frm_size_tile = val;
 305	SET_GBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, val, 0);
 306	gbe->frm_size_tile = val;
 307}
 308
 309static void gbe_turn_on(void)
 310{
 311	unsigned int val, i;
 312
 313	/*
 314	 * Check if pixel counter is off, for unknown reason this
 315	 * code hangs Visual Workstations
 316	 */
 317	if (gbe_revision < 2) {
 318		val = gbe->vt_xy;
 319		if (GET_GBE_FIELD(VT_XY, FREEZE, val) == 0)
 320			return;
 321	}
 322
 323	/* turn on dot clock */
 324	val = gbe->dotclock;
 325	SET_GBE_FIELD(DOTCLK, RUN, val, 1);
 326	gbe->dotclock = val;
 327	mdelay(10);
 328	for (i = 0; i < 10000; i++) {
 329		val = gbe->dotclock;
 330		if (GET_GBE_FIELD(DOTCLK, RUN, val) != 1)
 331			udelay(10);
 332		else
 333			break;
 334	}
 335	if (i == 10000)
 336		printk(KERN_ERR "gbefb: turn on dotclock timed out\n");
 337
 338	/* turn on pixel counter */
 339	val = 0;
 340	SET_GBE_FIELD(VT_XY, FREEZE, val, 0);
 341	gbe->vt_xy = val;
 342	mdelay(10);
 343	for (i = 0; i < 10000; i++) {
 344		val = gbe->vt_xy;
 345		if (GET_GBE_FIELD(VT_XY, FREEZE, val))
 346			udelay(10);
 347		else
 348			break;
 349	}
 350	if (i == 10000)
 351		printk(KERN_ERR "gbefb: turn on pixel clock timed out\n");
 352
 353	/* turn on DMA */
 354	val = gbe->frm_control;
 355	SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 1);
 356	gbe->frm_control = val;
 357	udelay(1000);
 358	for (i = 0; i < 10000; i++) {
 359		val = gbe->frm_inhwctrl;
 360		if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, val) != 1)
 361			udelay(10);
 362		else
 363			break;
 364	}
 365	if (i == 10000)
 366		printk(KERN_ERR "gbefb: turn on DMA timed out\n");
 367
 368	gbe_turned_on = 1;
 369}
 370
 371static void gbe_loadcmap(void)
 372{
 373	int i, j;
 374
 375	for (i = 0; i < 256; i++) {
 376		for (j = 0; j < 1000 && gbe->cm_fifo >= 63; j++)
 377			udelay(10);
 378		if (j == 1000)
 379			printk(KERN_ERR "gbefb: cmap FIFO timeout\n");
 380
 381		gbe->cmap[i] = gbe_cmap[i];
 382	}
 383}
 384
 385/*
 386 *  Blank the display.
 387 */
 388static int gbefb_blank(int blank, struct fb_info *info)
 389{
 390	/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
 391	switch (blank) {
 392	case FB_BLANK_UNBLANK:		/* unblank */
 393		gbe_turn_on();
 394		gbe_loadcmap();
 395		break;
 396
 397	case FB_BLANK_NORMAL:		/* blank */
 398		gbe_turn_off();
 399		break;
 400
 401	default:
 402		/* Nothing */
 403		break;
 404	}
 405	return 0;
 406}
 407
 408/*
 409 *  Setup flatpanel related registers.
 410 */
 411static void gbefb_setup_flatpanel(struct gbe_timing_info *timing)
 412{
 413	int fp_wid, fp_hgt, fp_vbs, fp_vbe;
 414	u32 outputVal = 0;
 415
 416	SET_GBE_FIELD(VT_FLAGS, HDRV_INVERT, outputVal,
 417		(timing->flags & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1);
 418	SET_GBE_FIELD(VT_FLAGS, VDRV_INVERT, outputVal,
 419		(timing->flags & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1);
 420	gbe->vt_flags = outputVal;
 421
 422	/* Turn on the flat panel */
 423	fp_wid = 1600;
 424	fp_hgt = 1024;
 425	fp_vbs = 0;
 426	fp_vbe = 1600;
 427	timing->pll_m = 4;
 428	timing->pll_n = 1;
 429	timing->pll_p = 0;
 430
 431	outputVal = 0;
 432	SET_GBE_FIELD(FP_DE, ON, outputVal, fp_vbs);
 433	SET_GBE_FIELD(FP_DE, OFF, outputVal, fp_vbe);
 434	gbe->fp_de = outputVal;
 435	outputVal = 0;
 436	SET_GBE_FIELD(FP_HDRV, OFF, outputVal, fp_wid);
 437	gbe->fp_hdrv = outputVal;
 438	outputVal = 0;
 439	SET_GBE_FIELD(FP_VDRV, ON, outputVal, 1);
 440	SET_GBE_FIELD(FP_VDRV, OFF, outputVal, fp_hgt + 1);
 441	gbe->fp_vdrv = outputVal;
 442}
 443
 444struct gbe_pll_info {
 445	int clock_rate;
 446	int fvco_min;
 447	int fvco_max;
 448};
 449
 450static struct gbe_pll_info gbe_pll_table[2] = {
 451	{ 20, 80, 220 },
 452	{ 27, 80, 220 },
 453};
 454
 455static int compute_gbe_timing(struct fb_var_screeninfo *var,
 456			      struct gbe_timing_info *timing)
 457{
 458	int pll_m, pll_n, pll_p, error, best_m, best_n, best_p, best_error;
 459	int pixclock;
 460	struct gbe_pll_info *gbe_pll;
 461
 462	if (gbe_revision < 2)
 463		gbe_pll = &gbe_pll_table[0];
 464	else
 465		gbe_pll = &gbe_pll_table[1];
 466
 467	/* Determine valid resolution and timing
 468	 * GBE crystal runs at 20Mhz or 27Mhz
 469	 * pll_m, pll_n, pll_p define the following frequencies
 470	 * fvco = pll_m * 20Mhz / pll_n
 471	 * fout = fvco / (2**pll_p) */
 472	best_error = 1000000000;
 473	best_n = best_m = best_p = 0;
 474	for (pll_p = 0; pll_p < 4; pll_p++)
 475		for (pll_m = 1; pll_m < 256; pll_m++)
 476			for (pll_n = 1; pll_n < 64; pll_n++) {
 477				pixclock = (1000000 / gbe_pll->clock_rate) *
 478						(pll_n << pll_p) / pll_m;
 479
 480				error = var->pixclock - pixclock;
 481
 482				if (error < 0)
 483					error = -error;
 484
 485				if (error < best_error &&
 486				    pll_m / pll_n >
 487				    gbe_pll->fvco_min / gbe_pll->clock_rate &&
 488 				    pll_m / pll_n <
 489				    gbe_pll->fvco_max / gbe_pll->clock_rate) {
 490					best_error = error;
 491					best_m = pll_m;
 492					best_n = pll_n;
 493					best_p = pll_p;
 494				}
 495			}
 496
 497	if (!best_n || !best_m)
 498		return -EINVAL;	/* Resolution to high */
 499
 500	pixclock = (1000000 / gbe_pll->clock_rate) *
 501		(best_n << best_p) / best_m;
 502
 503	/* set video timing information */
 504	if (timing) {
 505		timing->width = var->xres;
 506		timing->height = var->yres;
 507		timing->pll_m = best_m;
 508		timing->pll_n = best_n;
 509		timing->pll_p = best_p;
 510		timing->cfreq = gbe_pll->clock_rate * 1000 * timing->pll_m /
 511			(timing->pll_n << timing->pll_p);
 512		timing->htotal = var->left_margin + var->xres +
 513				var->right_margin + var->hsync_len;
 514		timing->vtotal = var->upper_margin + var->yres +
 515				var->lower_margin + var->vsync_len;
 516		timing->fields_sec = 1000 * timing->cfreq / timing->htotal *
 517				1000 / timing->vtotal;
 518		timing->hblank_start = var->xres;
 519		timing->vblank_start = var->yres;
 520		timing->hblank_end = timing->htotal;
 521		timing->hsync_start = var->xres + var->right_margin + 1;
 522		timing->hsync_end = timing->hsync_start + var->hsync_len;
 523		timing->vblank_end = timing->vtotal;
 524		timing->vsync_start = var->yres + var->lower_margin + 1;
 525		timing->vsync_end = timing->vsync_start + var->vsync_len;
 526	}
 527
 528	return pixclock;
 529}
 530
 531static void gbe_set_timing_info(struct gbe_timing_info *timing)
 532{
 533	int temp;
 534	unsigned int val;
 535
 536	/* setup dot clock PLL */
 537	val = 0;
 538	SET_GBE_FIELD(DOTCLK, M, val, timing->pll_m - 1);
 539	SET_GBE_FIELD(DOTCLK, N, val, timing->pll_n - 1);
 540	SET_GBE_FIELD(DOTCLK, P, val, timing->pll_p);
 541	SET_GBE_FIELD(DOTCLK, RUN, val, 0);	/* do not start yet */
 542	gbe->dotclock = val;
 543	mdelay(10);
 544
 545	/* setup pixel counter */
 546	val = 0;
 547	SET_GBE_FIELD(VT_XYMAX, MAXX, val, timing->htotal);
 548	SET_GBE_FIELD(VT_XYMAX, MAXY, val, timing->vtotal);
 549	gbe->vt_xymax = val;
 550
 551	/* setup video timing signals */
 552	val = 0;
 553	SET_GBE_FIELD(VT_VSYNC, VSYNC_ON, val, timing->vsync_start);
 554	SET_GBE_FIELD(VT_VSYNC, VSYNC_OFF, val, timing->vsync_end);
 555	gbe->vt_vsync = val;
 556	val = 0;
 557	SET_GBE_FIELD(VT_HSYNC, HSYNC_ON, val, timing->hsync_start);
 558	SET_GBE_FIELD(VT_HSYNC, HSYNC_OFF, val, timing->hsync_end);
 559	gbe->vt_hsync = val;
 560	val = 0;
 561	SET_GBE_FIELD(VT_VBLANK, VBLANK_ON, val, timing->vblank_start);
 562	SET_GBE_FIELD(VT_VBLANK, VBLANK_OFF, val, timing->vblank_end);
 563	gbe->vt_vblank = val;
 564	val = 0;
 565	SET_GBE_FIELD(VT_HBLANK, HBLANK_ON, val,
 566		      timing->hblank_start - 5);
 567	SET_GBE_FIELD(VT_HBLANK, HBLANK_OFF, val,
 568		      timing->hblank_end - 3);
 569	gbe->vt_hblank = val;
 570
 571	/* setup internal timing signals */
 572	val = 0;
 573	SET_GBE_FIELD(VT_VCMAP, VCMAP_ON, val, timing->vblank_start);
 574	SET_GBE_FIELD(VT_VCMAP, VCMAP_OFF, val, timing->vblank_end);
 575	gbe->vt_vcmap = val;
 576	val = 0;
 577	SET_GBE_FIELD(VT_HCMAP, HCMAP_ON, val, timing->hblank_start);
 578	SET_GBE_FIELD(VT_HCMAP, HCMAP_OFF, val, timing->hblank_end);
 579	gbe->vt_hcmap = val;
 580
 581	val = 0;
 582	temp = timing->vblank_start - timing->vblank_end - 1;
 583	if (temp > 0)
 584		temp = -temp;
 585
 586	if (flat_panel_enabled)
 587		gbefb_setup_flatpanel(timing);
 588
 589	SET_GBE_FIELD(DID_START_XY, DID_STARTY, val, (u32) temp);
 590	if (timing->hblank_end >= 20)
 591		SET_GBE_FIELD(DID_START_XY, DID_STARTX, val,
 592			      timing->hblank_end - 20);
 593	else
 594		SET_GBE_FIELD(DID_START_XY, DID_STARTX, val,
 595			      timing->htotal - (20 - timing->hblank_end));
 596	gbe->did_start_xy = val;
 597
 598	val = 0;
 599	SET_GBE_FIELD(CRS_START_XY, CRS_STARTY, val, (u32) (temp + 1));
 600	if (timing->hblank_end >= GBE_CRS_MAGIC)
 601		SET_GBE_FIELD(CRS_START_XY, CRS_STARTX, val,
 602			      timing->hblank_end - GBE_CRS_MAGIC);
 603	else
 604		SET_GBE_FIELD(CRS_START_XY, CRS_STARTX, val,
 605			      timing->htotal - (GBE_CRS_MAGIC -
 606						timing->hblank_end));
 607	gbe->crs_start_xy = val;
 608
 609	val = 0;
 610	SET_GBE_FIELD(VC_START_XY, VC_STARTY, val, (u32) temp);
 611	SET_GBE_FIELD(VC_START_XY, VC_STARTX, val, timing->hblank_end - 4);
 612	gbe->vc_start_xy = val;
 613
 614	val = 0;
 615	temp = timing->hblank_end - GBE_PIXEN_MAGIC_ON;
 616	if (temp < 0)
 617		temp += timing->htotal;	/* allow blank to wrap around */
 618
 619	SET_GBE_FIELD(VT_HPIXEN, HPIXEN_ON, val, temp);
 620	SET_GBE_FIELD(VT_HPIXEN, HPIXEN_OFF, val,
 621		      ((temp + timing->width -
 622			GBE_PIXEN_MAGIC_OFF) % timing->htotal));
 623	gbe->vt_hpixen = val;
 624
 625	val = 0;
 626	SET_GBE_FIELD(VT_VPIXEN, VPIXEN_ON, val, timing->vblank_end);
 627	SET_GBE_FIELD(VT_VPIXEN, VPIXEN_OFF, val, timing->vblank_start);
 628	gbe->vt_vpixen = val;
 629
 630	/* turn off sync on green */
 631	val = 0;
 632	SET_GBE_FIELD(VT_FLAGS, SYNC_LOW, val, 1);
 633	gbe->vt_flags = val;
 634}
 635
 636/*
 637 *  Set the hardware according to 'par'.
 638 */
 639
 640static int gbefb_set_par(struct fb_info *info)
 641{
 642	int i;
 643	unsigned int val;
 644	int wholeTilesX, partTilesX, maxPixelsPerTileX;
 645	int height_pix;
 646	int xpmax, ypmax;	/* Monitor resolution */
 647	int bytesPerPixel;	/* Bytes per pixel */
 648	struct gbefb_par *par = (struct gbefb_par *) info->par;
 649
 650	compute_gbe_timing(&info->var, &par->timing);
 651
 652	bytesPerPixel = info->var.bits_per_pixel / 8;
 653	info->fix.line_length = info->var.xres_virtual * bytesPerPixel;
 654	xpmax = par->timing.width;
 655	ypmax = par->timing.height;
 656
 657	/* turn off GBE */
 658	gbe_turn_off();
 659
 660	/* set timing info */
 661	gbe_set_timing_info(&par->timing);
 662
 663	/* initialize DIDs */
 664	val = 0;
 665	switch (bytesPerPixel) {
 666	case 1:
 667		SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_I8);
 668		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
 669		break;
 670	case 2:
 671		SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_ARGB5);
 672		info->fix.visual = FB_VISUAL_TRUECOLOR;
 673		break;
 674	case 4:
 675		SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_RGB8);
 676		info->fix.visual = FB_VISUAL_TRUECOLOR;
 677		break;
 678	}
 679	SET_GBE_FIELD(WID, BUF, val, GBE_BMODE_BOTH);
 680
 681	for (i = 0; i < 32; i++)
 682		gbe->mode_regs[i] = val;
 683
 684	/* Initialize interrupts */
 685	gbe->vt_intr01 = 0xffffffff;
 686	gbe->vt_intr23 = 0xffffffff;
 687
 688	/* HACK:
 689	   The GBE hardware uses a tiled memory to screen mapping. Tiles are
 690	   blocks of 512x128, 256x128 or 128x128 pixels, respectively for 8bit,
 691	   16bit and 32 bit modes (64 kB). They cover the screen with partial
 692	   tiles on the right and/or bottom of the screen if needed.
 693	   For example in 640x480 8 bit mode the mapping is:
 694
 695	   <-------- 640 ----->
 696	   <---- 512 ----><128|384 offscreen>
 697	   ^  ^
 698	   | 128    [tile 0]        [tile 1]
 699	   |  v
 700	   ^
 701	   4 128    [tile 2]        [tile 3]
 702	   8  v
 703	   0  ^
 704	   128    [tile 4]        [tile 5]
 705	   |  v
 706	   |  ^
 707	   v  96    [tile 6]        [tile 7]
 708	   32 offscreen
 709
 710	   Tiles have the advantage that they can be allocated individually in
 711	   memory. However, this mapping is not linear at all, which is not
 712	   really convenient. In order to support linear addressing, the GBE
 713	   DMA hardware is fooled into thinking the screen is only one tile
 714	   large and but has a greater height, so that the DMA transfer covers
 715	   the same region.
 716	   Tiles are still allocated as independent chunks of 64KB of
 717	   continuous physical memory and remapped so that the kernel sees the
 718	   framebuffer as a continuous virtual memory. The GBE tile table is
 719	   set up so that each tile references one of these 64k blocks:
 720
 721	   GBE -> tile list    framebuffer           TLB   <------------ CPU
 722	          [ tile 0 ] -> [ 64KB ]  <- [ 16x 4KB page entries ]     ^
 723	             ...           ...              ...       linear virtual FB
 724	          [ tile n ] -> [ 64KB ]  <- [ 16x 4KB page entries ]     v
 725
 726
 727	   The GBE hardware is then told that the buffer is 512*tweaked_height,
 728	   with tweaked_height = real_width*real_height/pixels_per_tile.
 729	   Thus the GBE hardware will scan the first tile, filing the first 64k
 730	   covered region of the screen, and then will proceed to the next
 731	   tile, until the whole screen is covered.
 732
 733	   Here is what would happen at 640x480 8bit:
 734
 735	   normal tiling               linear
 736	   ^   11111111111111112222    11111111111111111111  ^
 737	   128 11111111111111112222    11111111111111111111 102 lines
 738	       11111111111111112222    11111111111111111111  v
 739	   V   11111111111111112222    11111111222222222222
 740	       33333333333333334444    22222222222222222222
 741	       33333333333333334444    22222222222222222222
 742	       <      512     >        <  256 >               102*640+256 = 64k
 743
 744	   NOTE: The only mode for which this is not working is 800x600 8bit,
 745	   as 800*600/512 = 937.5 which is not integer and thus causes
 746	   flickering.
 747	   I guess this is not so important as one can use 640x480 8bit or
 748	   800x600 16bit anyway.
 749	 */
 750
 751	/* Tell gbe about the tiles table location */
 752	/* tile_ptr -> [ tile 1 ] -> FB mem */
 753	/*             [ tile 2 ] -> FB mem */
 754	/*               ...                */
 755	val = 0;
 756	SET_GBE_FIELD(FRM_CONTROL, FRM_TILE_PTR, val, gbe_tiles.dma >> 9);
 757	SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 0); /* do not start */
 758	SET_GBE_FIELD(FRM_CONTROL, FRM_LINEAR, val, 0);
 759	gbe->frm_control = val;
 760
 761	maxPixelsPerTileX = 512 / bytesPerPixel;
 762	wholeTilesX = 1;
 763	partTilesX = 0;
 764
 765	/* Initialize the framebuffer */
 766	val = 0;
 767	SET_GBE_FIELD(FRM_SIZE_TILE, FRM_WIDTH_TILE, val, wholeTilesX);
 768	SET_GBE_FIELD(FRM_SIZE_TILE, FRM_RHS, val, partTilesX);
 769
 770	switch (bytesPerPixel) {
 771	case 1:
 772		SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
 773			      GBE_FRM_DEPTH_8);
 774		break;
 775	case 2:
 776		SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
 777			      GBE_FRM_DEPTH_16);
 778		break;
 779	case 4:
 780		SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
 781			      GBE_FRM_DEPTH_32);
 782		break;
 783	}
 784	gbe->frm_size_tile = val;
 785
 786	/* compute tweaked height */
 787	height_pix = xpmax * ypmax / maxPixelsPerTileX;
 788
 789	val = 0;
 790	SET_GBE_FIELD(FRM_SIZE_PIXEL, FB_HEIGHT_PIX, val, height_pix);
 791	gbe->frm_size_pixel = val;
 792
 793	/* turn off DID and overlay DMA */
 794	gbe->did_control = 0;
 795	gbe->ovr_width_tile = 0;
 796
 797	/* Turn off mouse cursor */
 798	gbe->crs_ctl = 0;
 799
 800	/* Turn on GBE */
 801	gbe_turn_on();
 802
 803	/* Initialize the gamma map */
 804	udelay(10);
 805	for (i = 0; i < 256; i++)
 806		gbe->gmap[i] = (i << 24) | (i << 16) | (i << 8);
 807
 808	/* Initialize the color map */
 809	for (i = 0; i < 256; i++)
 810		gbe_cmap[i] = (i << 8) | (i << 16) | (i << 24);
 811
 812	gbe_loadcmap();
 813
 814	return 0;
 815}
 816
 817static void gbefb_encode_fix(struct fb_fix_screeninfo *fix,
 818			     struct fb_var_screeninfo *var)
 819{
 820	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
 821	strcpy(fix->id, "SGI GBE");
 822	fix->smem_start = (unsigned long) gbe_mem;
 823	fix->smem_len = gbe_mem_size;
 824	fix->type = FB_TYPE_PACKED_PIXELS;
 825	fix->type_aux = 0;
 826	fix->accel = FB_ACCEL_NONE;
 827	switch (var->bits_per_pixel) {
 828	case 8:
 829		fix->visual = FB_VISUAL_PSEUDOCOLOR;
 830		break;
 831	default:
 832		fix->visual = FB_VISUAL_TRUECOLOR;
 833		break;
 834	}
 835	fix->ywrapstep = 0;
 836	fix->xpanstep = 0;
 837	fix->ypanstep = 0;
 838	fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
 839	fix->mmio_start = GBE_BASE;
 840	fix->mmio_len = sizeof(struct sgi_gbe);
 841}
 842
 843/*
 844 *  Set a single color register. The values supplied are already
 845 *  rounded down to the hardware's capabilities (according to the
 846 *  entries in the var structure). Return != 0 for invalid regno.
 847 */
 848
 849static int gbefb_setcolreg(unsigned regno, unsigned red, unsigned green,
 850			     unsigned blue, unsigned transp,
 851			     struct fb_info *info)
 852{
 853	int i;
 854
 855	if (regno > 255)
 856		return 1;
 857	red >>= 8;
 858	green >>= 8;
 859	blue >>= 8;
 860
 861	if (info->var.bits_per_pixel <= 8) {
 862		gbe_cmap[regno] = (red << 24) | (green << 16) | (blue << 8);
 863		if (gbe_turned_on) {
 864			/* wait for the color map FIFO to have a free entry */
 865			for (i = 0; i < 1000 && gbe->cm_fifo >= 63; i++)
 866				udelay(10);
 867			if (i == 1000) {
 868				printk(KERN_ERR "gbefb: cmap FIFO timeout\n");
 869				return 1;
 870			}
 871			gbe->cmap[regno] = gbe_cmap[regno];
 872		}
 873	} else if (regno < 16) {
 874		switch (info->var.bits_per_pixel) {
 875		case 15:
 876		case 16:
 877			red >>= 3;
 878			green >>= 3;
 879			blue >>= 3;
 880			pseudo_palette[regno] =
 881				(red << info->var.red.offset) |
 882				(green << info->var.green.offset) |
 883				(blue << info->var.blue.offset);
 884			break;
 885		case 32:
 886			pseudo_palette[regno] =
 887				(red << info->var.red.offset) |
 888				(green << info->var.green.offset) |
 889				(blue << info->var.blue.offset);
 890			break;
 891		}
 892	}
 893
 894	return 0;
 895}
 896
 897/*
 898 *  Check video mode validity, eventually modify var to best match.
 899 */
 900static int gbefb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 901{
 902	unsigned int line_length;
 903	struct gbe_timing_info timing;
 904	int ret;
 905
 906	/* Limit bpp to 8, 16, and 32 */
 907	if (var->bits_per_pixel <= 8)
 908		var->bits_per_pixel = 8;
 909	else if (var->bits_per_pixel <= 16)
 910		var->bits_per_pixel = 16;
 911	else if (var->bits_per_pixel <= 32)
 912		var->bits_per_pixel = 32;
 913	else
 914		return -EINVAL;
 915
 916	/* Check the mode can be mapped linearly with the tile table trick. */
 917	/* This requires width x height x bytes/pixel be a multiple of 512 */
 918	if ((var->xres * var->yres * var->bits_per_pixel) & 4095)
 919		return -EINVAL;
 920
 921	var->grayscale = 0;	/* No grayscale for now */
 922
 923	ret = compute_gbe_timing(var, &timing);
 924	var->pixclock = ret;
 925	if (ret < 0)
 926		return -EINVAL;
 927
 928	/* Adjust virtual resolution, if necessary */
 929	if (var->xres > var->xres_virtual || (!ywrap && !ypan))
 930		var->xres_virtual = var->xres;
 931	if (var->yres > var->yres_virtual || (!ywrap && !ypan))
 932		var->yres_virtual = var->yres;
 933
 934	if (var->vmode & FB_VMODE_CONUPDATE) {
 935		var->vmode |= FB_VMODE_YWRAP;
 936		var->xoffset = info->var.xoffset;
 937		var->yoffset = info->var.yoffset;
 938	}
 939
 940	/* No grayscale for now */
 941	var->grayscale = 0;
 942
 943	/* Memory limit */
 944	line_length = var->xres_virtual * var->bits_per_pixel / 8;
 945	if (line_length * var->yres_virtual > gbe_mem_size)
 946		return -ENOMEM;	/* Virtual resolution too high */
 947
 948	switch (var->bits_per_pixel) {
 949	case 8:
 950		var->red.offset = 0;
 951		var->red.length = 8;
 952		var->green.offset = 0;
 953		var->green.length = 8;
 954		var->blue.offset = 0;
 955		var->blue.length = 8;
 956		var->transp.offset = 0;
 957		var->transp.length = 0;
 958		break;
 959	case 16:		/* RGB 1555 */
 960		var->red.offset = 10;
 961		var->red.length = 5;
 962		var->green.offset = 5;
 963		var->green.length = 5;
 964		var->blue.offset = 0;
 965		var->blue.length = 5;
 966		var->transp.offset = 0;
 967		var->transp.length = 0;
 968		break;
 969	case 32:		/* RGB 8888 */
 970		var->red.offset = 24;
 971		var->red.length = 8;
 972		var->green.offset = 16;
 973		var->green.length = 8;
 974		var->blue.offset = 8;
 975		var->blue.length = 8;
 976		var->transp.offset = 0;
 977		var->transp.length = 8;
 978		break;
 979	}
 980	var->red.msb_right = 0;
 981	var->green.msb_right = 0;
 982	var->blue.msb_right = 0;
 983	var->transp.msb_right = 0;
 984
 985	var->left_margin = timing.htotal - timing.hsync_end;
 986	var->right_margin = timing.hsync_start - timing.width;
 987	var->upper_margin = timing.vtotal - timing.vsync_end;
 988	var->lower_margin = timing.vsync_start - timing.height;
 989	var->hsync_len = timing.hsync_end - timing.hsync_start;
 990	var->vsync_len = timing.vsync_end - timing.vsync_start;
 991
 992	return 0;
 993}
 994
 995static int gbefb_mmap(struct fb_info *info,
 996			struct vm_area_struct *vma)
 997{
 998	unsigned long size = vma->vm_end - vma->vm_start;
 999	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
1000	unsigned long addr;
1001	unsigned long phys_addr, phys_size;
1002	u16 *tile;
1003
1004	vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
1005
1006	/* check range */
1007	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
1008		return -EINVAL;
1009	if (size > gbe_mem_size)
1010		return -EINVAL;
1011	if (offset > gbe_mem_size - size)
1012		return -EINVAL;
1013
1014	/* remap using the fastest write-through mode on architecture */
1015	/* try not polluting the cache when possible */
1016#ifdef CONFIG_MIPS
1017	pgprot_val(vma->vm_page_prot) =
1018		pgprot_fb(pgprot_val(vma->vm_page_prot));
1019#endif
1020	/* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */
1021
1022	/* look for the starting tile */
1023	tile = &gbe_tiles.cpu[offset >> TILE_SHIFT];
1024	addr = vma->vm_start;
1025	offset &= TILE_MASK;
1026
1027	/* remap each tile separately */
1028	do {
1029		phys_addr = (((unsigned long) (*tile)) << TILE_SHIFT) + offset;
1030		if ((offset + size) < TILE_SIZE)
1031			phys_size = size;
1032		else
1033			phys_size = TILE_SIZE - offset;
1034
1035		if (remap_pfn_range(vma, addr, phys_addr >> PAGE_SHIFT,
1036						phys_size, vma->vm_page_prot))
1037			return -EAGAIN;
1038
1039		offset = 0;
1040		size -= phys_size;
1041		addr += phys_size;
1042		tile++;
1043	} while (size);
1044
1045	return 0;
1046}
1047
1048static const struct fb_ops gbefb_ops = {
1049	.owner		= THIS_MODULE,
1050	__FB_DEFAULT_IOMEM_OPS_RDWR,
1051	.fb_check_var	= gbefb_check_var,
1052	.fb_set_par	= gbefb_set_par,
1053	.fb_setcolreg	= gbefb_setcolreg,
1054	.fb_blank	= gbefb_blank,
1055	__FB_DEFAULT_IOMEM_OPS_DRAW,
1056	.fb_mmap	= gbefb_mmap,
1057};
1058
1059/*
1060 * sysfs
1061 */
1062
1063static ssize_t gbefb_show_memsize(struct device *dev, struct device_attribute *attr, char *buf)
1064{
1065	return sysfs_emit(buf, "%u\n", gbe_mem_size);
1066}
1067
1068static DEVICE_ATTR(size, S_IRUGO, gbefb_show_memsize, NULL);
1069
1070static ssize_t gbefb_show_rev(struct device *device, struct device_attribute *attr, char *buf)
1071{
1072	return sysfs_emit(buf, "%d\n", gbe_revision);
1073}
1074
1075static DEVICE_ATTR(revision, S_IRUGO, gbefb_show_rev, NULL);
1076
1077static struct attribute *gbefb_attrs[] = {
1078	&dev_attr_size.attr,
1079	&dev_attr_revision.attr,
1080	NULL,
1081};
1082ATTRIBUTE_GROUPS(gbefb);
1083
1084/*
1085 * Initialization
1086 */
1087
1088static int gbefb_setup(char *options)
1089{
1090	char *this_opt;
1091
1092	if (!options || !*options)
1093		return 0;
1094
1095	while ((this_opt = strsep(&options, ",")) != NULL) {
1096		if (!strncmp(this_opt, "monitor:", 8)) {
1097			if (!strncmp(this_opt + 8, "crt", 3)) {
1098				flat_panel_enabled = 0;
1099				default_var = &default_var_CRT;
1100				default_mode = &default_mode_CRT;
1101			} else if (!strncmp(this_opt + 8, "1600sw", 6) ||
1102				   !strncmp(this_opt + 8, "lcd", 3)) {
1103				flat_panel_enabled = 1;
1104				default_var = &default_var_LCD;
1105				default_mode = &default_mode_LCD;
1106			}
1107		} else if (!strncmp(this_opt, "mem:", 4)) {
1108			gbe_mem_size = memparse(this_opt + 4, &this_opt);
1109			if (gbe_mem_size > CONFIG_FB_GBE_MEM * 1024 * 1024)
1110				gbe_mem_size = CONFIG_FB_GBE_MEM * 1024 * 1024;
1111			if (gbe_mem_size < TILE_SIZE)
1112				gbe_mem_size = TILE_SIZE;
1113		} else
1114			mode_option = this_opt;
1115	}
1116	return 0;
1117}
1118
1119static int gbefb_probe(struct platform_device *p_dev)
1120{
1121	int i, ret = 0;
1122	struct fb_info *info;
1123	struct gbefb_par *par;
1124#ifndef MODULE
1125	char *options = NULL;
1126#endif
1127
1128	info = framebuffer_alloc(sizeof(struct gbefb_par), &p_dev->dev);
1129	if (!info)
1130		return -ENOMEM;
1131
1132#ifndef MODULE
1133	if (fb_get_options("gbefb", &options)) {
1134		ret = -ENODEV;
1135		goto out_release_framebuffer;
1136	}
1137	gbefb_setup(options);
1138#endif
1139
1140	if (!request_mem_region(GBE_BASE, sizeof(struct sgi_gbe), "GBE")) {
1141		printk(KERN_ERR "gbefb: couldn't reserve mmio region\n");
1142		ret = -EBUSY;
1143		goto out_release_framebuffer;
1144	}
1145
1146	gbe = (struct sgi_gbe *) devm_ioremap(&p_dev->dev, GBE_BASE,
1147					      sizeof(struct sgi_gbe));
1148	if (!gbe) {
1149		printk(KERN_ERR "gbefb: couldn't map mmio region\n");
1150		ret = -ENXIO;
1151		goto out_release_mem_region;
1152	}
1153	gbe_revision = gbe->ctrlstat & 15;
1154
1155	gbe_tiles.cpu = dmam_alloc_coherent(&p_dev->dev,
1156				GBE_TLB_SIZE * sizeof(uint16_t),
1157				&gbe_tiles.dma, GFP_KERNEL);
1158	if (!gbe_tiles.cpu) {
1159		printk(KERN_ERR "gbefb: couldn't allocate tiles table\n");
1160		ret = -ENOMEM;
1161		goto out_release_mem_region;
1162	}
1163
1164	if (gbe_mem_phys) {
1165		/* memory was allocated at boot time */
1166		gbe_mem = devm_ioremap_wc(&p_dev->dev, gbe_mem_phys,
1167					  gbe_mem_size);
1168		if (!gbe_mem) {
1169			printk(KERN_ERR "gbefb: couldn't map framebuffer\n");
1170			ret = -ENOMEM;
1171			goto out_release_mem_region;
1172		}
1173
1174		gbe_dma_addr = 0;
1175	} else {
1176		/* try to allocate memory with the classical allocator
1177		 * this has high chance to fail on low memory machines */
1178		gbe_mem = dmam_alloc_attrs(&p_dev->dev, gbe_mem_size,
1179				&gbe_dma_addr, GFP_KERNEL,
1180				DMA_ATTR_WRITE_COMBINE);
1181		if (!gbe_mem) {
1182			printk(KERN_ERR "gbefb: couldn't allocate framebuffer memory\n");
1183			ret = -ENOMEM;
1184			goto out_release_mem_region;
1185		}
1186
1187		gbe_mem_phys = dma_to_phys(&p_dev->dev, gbe_dma_addr);
1188	}
1189
1190	par = info->par;
1191	par->wc_cookie = arch_phys_wc_add(gbe_mem_phys, gbe_mem_size);
1192
1193	/* map framebuffer memory into tiles table */
1194	for (i = 0; i < (gbe_mem_size >> TILE_SHIFT); i++)
1195		gbe_tiles.cpu[i] = (gbe_mem_phys >> TILE_SHIFT) + i;
1196
1197	info->fbops = &gbefb_ops;
1198	info->pseudo_palette = pseudo_palette;
1199	info->screen_base = gbe_mem;
1200	fb_alloc_cmap(&info->cmap, 256, 0);
1201
1202	/* reset GBE */
1203	gbe_reset();
1204
1205	/* turn on default video mode */
1206	if (fb_find_mode(&par->var, info, mode_option, NULL, 0,
1207			 default_mode, 8) == 0)
1208		par->var = *default_var;
1209	info->var = par->var;
1210	gbefb_check_var(&par->var, info);
1211	gbefb_encode_fix(&info->fix, &info->var);
1212
1213	if (register_framebuffer(info) < 0) {
1214		printk(KERN_ERR "gbefb: couldn't register framebuffer\n");
1215		ret = -ENXIO;
1216		goto out_gbe_unmap;
1217	}
1218
1219	platform_set_drvdata(p_dev, info);
1220
1221	fb_info(info, "%s rev %d @ 0x%08x using %dkB memory\n",
1222		info->fix.id, gbe_revision, (unsigned)GBE_BASE,
1223		gbe_mem_size >> 10);
1224
1225	return 0;
1226
1227out_gbe_unmap:
1228	arch_phys_wc_del(par->wc_cookie);
1229out_release_mem_region:
1230	release_mem_region(GBE_BASE, sizeof(struct sgi_gbe));
1231out_release_framebuffer:
1232	framebuffer_release(info);
1233
1234	return ret;
1235}
1236
1237static void gbefb_remove(struct platform_device* p_dev)
1238{
1239	struct fb_info *info = platform_get_drvdata(p_dev);
1240	struct gbefb_par *par = info->par;
1241
1242	unregister_framebuffer(info);
1243	gbe_turn_off();
1244	arch_phys_wc_del(par->wc_cookie);
1245	release_mem_region(GBE_BASE, sizeof(struct sgi_gbe));
1246	framebuffer_release(info);
1247}
1248
1249static struct platform_driver gbefb_driver = {
1250	.probe = gbefb_probe,
1251	.remove = gbefb_remove,
1252	.driver = {
1253		.name = "gbefb",
1254		.dev_groups = gbefb_groups,
1255	},
1256};
1257
1258static struct platform_device *gbefb_device;
1259
1260static int __init gbefb_init(void)
1261{
1262	int ret = platform_driver_register(&gbefb_driver);
1263	if (IS_ENABLED(CONFIG_SGI_IP32) && !ret) {
1264		gbefb_device = platform_device_alloc("gbefb", 0);
1265		if (gbefb_device) {
1266			ret = platform_device_add(gbefb_device);
1267		} else {
1268			ret = -ENOMEM;
1269		}
1270		if (ret) {
1271			platform_device_put(gbefb_device);
1272			platform_driver_unregister(&gbefb_driver);
1273		}
1274	}
1275	return ret;
1276}
1277
1278static void __exit gbefb_exit(void)
1279{
1280	platform_device_unregister(gbefb_device);
1281	platform_driver_unregister(&gbefb_driver);
1282}
1283
1284module_init(gbefb_init);
1285module_exit(gbefb_exit);
1286
1287MODULE_LICENSE("GPL");
~/ Read-only file preview.