brintos

brintos / linux-shallow public Read only

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