• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/video/
1/*
2 *  linux/drivers/video/sgivwfb.c -- SGI DBE frame buffer device
3 *
4 *	Copyright (C) 1999 Silicon Graphics, Inc.
5 *      Jeffrey Newquist, newquist@engr.sgi.som
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/module.h>
13#include <linux/kernel.h>
14#include <linux/mm.h>
15#include <linux/errno.h>
16#include <linux/delay.h>
17#include <linux/fb.h>
18#include <linux/init.h>
19#include <linux/ioport.h>
20#include <linux/platform_device.h>
21
22#include <asm/io.h>
23#include <asm/mtrr.h>
24#include <asm/visws/sgivw.h>
25
26#define INCLUDE_TIMING_TABLE_DATA
27#define DBE_REG_BASE par->regs
28#include <video/sgivw.h>
29
30struct sgivw_par {
31	struct asregs *regs;
32	u32 cmap_fifo;
33	u_long timing_num;
34};
35
36#define FLATPANEL_SGI_1600SW	5
37
38/*
39 *  RAM we reserve for the frame buffer. This defines the maximum screen
40 *  size
41 *
42 *  The default can be overridden if the driver is compiled as a module
43 */
44
45static int ypan = 0;
46static int ywrap = 0;
47
48static int flatpanel_id = -1;
49
50static struct fb_fix_screeninfo sgivwfb_fix __devinitdata = {
51	.id		= "SGI Vis WS FB",
52	.type		= FB_TYPE_PACKED_PIXELS,
53        .visual		= FB_VISUAL_PSEUDOCOLOR,
54	.mmio_start	= DBE_REG_PHYS,
55	.mmio_len	= DBE_REG_SIZE,
56        .accel		= FB_ACCEL_NONE,
57	.line_length	= 640,
58};
59
60static struct fb_var_screeninfo sgivwfb_var __devinitdata = {
61	/* 640x480, 8 bpp */
62	.xres		= 640,
63	.yres		= 480,
64	.xres_virtual	= 640,
65	.yres_virtual	= 480,
66	.bits_per_pixel	= 8,
67	.red		= { 0, 8, 0 },
68	.green		= { 0, 8, 0 },
69	.blue		= { 0, 8, 0 },
70	.height		= -1,
71	.width		= -1,
72	.pixclock	= 20000,
73	.left_margin	= 64,
74	.right_margin	= 64,
75	.upper_margin	= 32,
76	.lower_margin	= 32,
77	.hsync_len	= 64,
78	.vsync_len	= 2,
79	.vmode		= FB_VMODE_NONINTERLACED
80};
81
82static struct fb_var_screeninfo sgivwfb_var1600sw __devinitdata = {
83	/* 1600x1024, 8 bpp */
84	.xres		= 1600,
85	.yres		= 1024,
86	.xres_virtual	= 1600,
87	.yres_virtual	= 1024,
88	.bits_per_pixel	= 8,
89	.red		= { 0, 8, 0 },
90	.green		= { 0, 8, 0 },
91	.blue		= { 0, 8, 0 },
92	.height		= -1,
93	.width		= -1,
94	.pixclock	= 9353,
95	.left_margin	= 20,
96	.right_margin	= 30,
97	.upper_margin	= 37,
98	.lower_margin	= 3,
99	.hsync_len	= 20,
100	.vsync_len	= 3,
101	.vmode		= FB_VMODE_NONINTERLACED
102};
103
104/*
105 *  Interface used by the world
106 */
107int sgivwfb_init(void);
108
109static int sgivwfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info);
110static int sgivwfb_set_par(struct fb_info *info);
111static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green,
112			     u_int blue, u_int transp,
113			     struct fb_info *info);
114static int sgivwfb_mmap(struct fb_info *info,
115			struct vm_area_struct *vma);
116
117static struct fb_ops sgivwfb_ops = {
118	.owner		= THIS_MODULE,
119	.fb_check_var	= sgivwfb_check_var,
120	.fb_set_par	= sgivwfb_set_par,
121	.fb_setcolreg	= sgivwfb_setcolreg,
122	.fb_fillrect	= cfb_fillrect,
123	.fb_copyarea	= cfb_copyarea,
124	.fb_imageblit	= cfb_imageblit,
125	.fb_mmap	= sgivwfb_mmap,
126};
127
128/*
129 *  Internal routines
130 */
131static unsigned long bytes_per_pixel(int bpp)
132{
133	switch (bpp) {
134		case 8:
135			return 1;
136		case 16:
137			return 2;
138		case 32:
139			return 4;
140		default:
141			printk(KERN_INFO "sgivwfb: unsupported bpp %d\n", bpp);
142			return 0;
143	}
144}
145
146static unsigned long get_line_length(int xres_virtual, int bpp)
147{
148	return (xres_virtual * bytes_per_pixel(bpp));
149}
150
151/*
152 * Function:	dbe_TurnOffDma
153 * Parameters:	(None)
154 * Description:	This should turn off the monitor and dbe.  This is used
155 *              when switching between the serial console and the graphics
156 *              console.
157 */
158
159static void dbe_TurnOffDma(struct sgivw_par *par)
160{
161	unsigned int readVal;
162	int i;
163
164	// Check to see if things are already turned off:
165	// 1) Check to see if dbe is not using the internal dotclock.
166	// 2) Check to see if the xy counter in dbe is already off.
167
168	DBE_GETREG(ctrlstat, readVal);
169	if (GET_DBE_FIELD(CTRLSTAT, PCLKSEL, readVal) < 2)
170		return;
171
172	DBE_GETREG(vt_xy, readVal);
173	if (GET_DBE_FIELD(VT_XY, VT_FREEZE, readVal) == 1)
174		return;
175
176	// Otherwise, turn off dbe
177
178	DBE_GETREG(ovr_control, readVal);
179	SET_DBE_FIELD(OVR_CONTROL, OVR_DMA_ENABLE, readVal, 0);
180	DBE_SETREG(ovr_control, readVal);
181	udelay(1000);
182	DBE_GETREG(frm_control, readVal);
183	SET_DBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, readVal, 0);
184	DBE_SETREG(frm_control, readVal);
185	udelay(1000);
186	DBE_GETREG(did_control, readVal);
187	SET_DBE_FIELD(DID_CONTROL, DID_DMA_ENABLE, readVal, 0);
188	DBE_SETREG(did_control, readVal);
189	udelay(1000);
190
191	//
192	//    This was necessary for GBE--we had to wait through two
193	//    vertical retrace periods before the pixel DMA was
194	//    turned off for sure.  I've left this in for now, in
195	//    case dbe needs it.
196
197	for (i = 0; i < 10000; i++) {
198		DBE_GETREG(frm_inhwctrl, readVal);
199		if (GET_DBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, readVal) ==
200		    0)
201			udelay(10);
202		else {
203			DBE_GETREG(ovr_inhwctrl, readVal);
204			if (GET_DBE_FIELD
205			    (OVR_INHWCTRL, OVR_DMA_ENABLE, readVal) == 0)
206				udelay(10);
207			else {
208				DBE_GETREG(did_inhwctrl, readVal);
209				if (GET_DBE_FIELD
210				    (DID_INHWCTRL, DID_DMA_ENABLE,
211				     readVal) == 0)
212					udelay(10);
213				else
214					break;
215			}
216		}
217	}
218}
219
220/*
221 *  Set the User Defined Part of the Display. Again if par use it to get
222 *  real video mode.
223 */
224static int sgivwfb_check_var(struct fb_var_screeninfo *var,
225			     struct fb_info *info)
226{
227	struct sgivw_par *par = (struct sgivw_par *)info->par;
228	struct dbe_timing_info *timing;
229	u_long line_length;
230	u_long min_mode;
231	int req_dot;
232	int test_mode;
233
234	/*
235	 *  FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
236	 *  as FB_VMODE_SMOOTH_XPAN is only used internally
237	 */
238
239	if (var->vmode & FB_VMODE_CONUPDATE) {
240		var->vmode |= FB_VMODE_YWRAP;
241		var->xoffset = info->var.xoffset;
242		var->yoffset = info->var.yoffset;
243	}
244
245	var->xoffset = 0;
246	var->yoffset = 0;
247
248	/* Limit bpp to 8, 16, and 32 */
249	if (var->bits_per_pixel <= 8)
250		var->bits_per_pixel = 8;
251	else if (var->bits_per_pixel <= 16)
252		var->bits_per_pixel = 16;
253	else if (var->bits_per_pixel <= 32)
254		var->bits_per_pixel = 32;
255	else
256		return -EINVAL;
257
258	var->grayscale = 0;	/* No grayscale for now */
259
260	/* determine valid resolution and timing */
261	for (min_mode = 0; min_mode < ARRAY_SIZE(dbeVTimings); min_mode++) {
262		if (dbeVTimings[min_mode].width >= var->xres &&
263		    dbeVTimings[min_mode].height >= var->yres)
264			break;
265	}
266
267	if (min_mode == ARRAY_SIZE(dbeVTimings))
268		return -EINVAL;	/* Resolution to high */
269
270	/* for now, pick closest dot-clock within 3MHz */
271	req_dot = PICOS2KHZ(var->pixclock);
272	printk(KERN_INFO "sgivwfb: requested pixclock=%d ps (%d KHz)\n",
273	       var->pixclock, req_dot);
274	test_mode = min_mode;
275	while (dbeVTimings[min_mode].width == dbeVTimings[test_mode].width) {
276		if (dbeVTimings[test_mode].cfreq + 3000 > req_dot)
277			break;
278		test_mode++;
279	}
280	if (dbeVTimings[min_mode].width != dbeVTimings[test_mode].width)
281		test_mode--;
282	min_mode = test_mode;
283	timing = &dbeVTimings[min_mode];
284	printk(KERN_INFO "sgivwfb: granted dot-clock=%d KHz\n", timing->cfreq);
285
286	/* Adjust virtual resolution, if necessary */
287	if (var->xres > var->xres_virtual || (!ywrap && !ypan))
288		var->xres_virtual = var->xres;
289	if (var->yres > var->yres_virtual || (!ywrap && !ypan))
290		var->yres_virtual = var->yres;
291
292	/*
293	 *  Memory limit
294	 */
295	line_length = get_line_length(var->xres_virtual, var->bits_per_pixel);
296	if (line_length * var->yres_virtual > sgivwfb_mem_size)
297		return -ENOMEM;	/* Virtual resolution to high */
298
299	info->fix.line_length = line_length;
300
301	switch (var->bits_per_pixel) {
302	case 8:
303		var->red.offset = 0;
304		var->red.length = 8;
305		var->green.offset = 0;
306		var->green.length = 8;
307		var->blue.offset = 0;
308		var->blue.length = 8;
309		var->transp.offset = 0;
310		var->transp.length = 0;
311		break;
312	case 16:		/* RGBA 5551 */
313		var->red.offset = 11;
314		var->red.length = 5;
315		var->green.offset = 6;
316		var->green.length = 5;
317		var->blue.offset = 1;
318		var->blue.length = 5;
319		var->transp.offset = 0;
320		var->transp.length = 0;
321		break;
322	case 32:		/* RGB 8888 */
323		var->red.offset = 0;
324		var->red.length = 8;
325		var->green.offset = 8;
326		var->green.length = 8;
327		var->blue.offset = 16;
328		var->blue.length = 8;
329		var->transp.offset = 24;
330		var->transp.length = 8;
331		break;
332	}
333	var->red.msb_right = 0;
334	var->green.msb_right = 0;
335	var->blue.msb_right = 0;
336	var->transp.msb_right = 0;
337
338	/* set video timing information */
339	var->pixclock = KHZ2PICOS(timing->cfreq);
340	var->left_margin = timing->htotal - timing->hsync_end;
341	var->right_margin = timing->hsync_start - timing->width;
342	var->upper_margin = timing->vtotal - timing->vsync_end;
343	var->lower_margin = timing->vsync_start - timing->height;
344	var->hsync_len = timing->hsync_end - timing->hsync_start;
345	var->vsync_len = timing->vsync_end - timing->vsync_start;
346
347	/* Ouch. This breaks the rules but timing_num is only important if you
348	* change a video mode */
349	par->timing_num = min_mode;
350
351	printk(KERN_INFO "sgivwfb: new video mode xres=%d yres=%d bpp=%d\n",
352		var->xres, var->yres, var->bits_per_pixel);
353	printk(KERN_INFO "         vxres=%d vyres=%d\n", var->xres_virtual,
354		var->yres_virtual);
355	return 0;
356}
357
358/*
359 *  Setup flatpanel related registers.
360 */
361static void sgivwfb_setup_flatpanel(struct sgivw_par *par, struct dbe_timing_info *currentTiming)
362{
363	int fp_wid, fp_hgt, fp_vbs, fp_vbe;
364	u32 outputVal = 0;
365
366	SET_DBE_FIELD(VT_FLAGS, HDRV_INVERT, outputVal,
367		(currentTiming->flags & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1);
368	SET_DBE_FIELD(VT_FLAGS, VDRV_INVERT, outputVal,
369		(currentTiming->flags & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1);
370	DBE_SETREG(vt_flags, outputVal);
371
372	/* Turn on the flat panel */
373	switch (flatpanel_id) {
374		case FLATPANEL_SGI_1600SW:
375			fp_wid = 1600;
376			fp_hgt = 1024;
377			fp_vbs = 0;
378			fp_vbe = 1600;
379			currentTiming->pll_m = 4;
380			currentTiming->pll_n = 1;
381			currentTiming->pll_p = 0;
382			break;
383		default:
384      			fp_wid = fp_hgt = fp_vbs = fp_vbe = 0xfff;
385  	}
386
387	outputVal = 0;
388	SET_DBE_FIELD(FP_DE, FP_DE_ON, outputVal, fp_vbs);
389	SET_DBE_FIELD(FP_DE, FP_DE_OFF, outputVal, fp_vbe);
390	DBE_SETREG(fp_de, outputVal);
391	outputVal = 0;
392	SET_DBE_FIELD(FP_HDRV, FP_HDRV_OFF, outputVal, fp_wid);
393	DBE_SETREG(fp_hdrv, outputVal);
394	outputVal = 0;
395	SET_DBE_FIELD(FP_VDRV, FP_VDRV_ON, outputVal, 1);
396	SET_DBE_FIELD(FP_VDRV, FP_VDRV_OFF, outputVal, fp_hgt + 1);
397	DBE_SETREG(fp_vdrv, outputVal);
398}
399
400/*
401 *  Set the hardware according to 'par'.
402 */
403static int sgivwfb_set_par(struct fb_info *info)
404{
405	struct sgivw_par *par = info->par;
406	int i, j, htmp, temp;
407	u32 readVal, outputVal;
408	int wholeTilesX, maxPixelsPerTileX;
409	int frmWrite1, frmWrite2, frmWrite3b;
410	struct dbe_timing_info *currentTiming; /* Current Video Timing */
411	int xpmax, ypmax;	// Monitor resolution
412	int bytesPerPixel;	// Bytes per pixel
413
414	currentTiming = &dbeVTimings[par->timing_num];
415	bytesPerPixel = bytes_per_pixel(info->var.bits_per_pixel);
416	xpmax = currentTiming->width;
417	ypmax = currentTiming->height;
418
419	/* dbe_InitGraphicsBase(); */
420	/* Turn on dotclock PLL */
421	DBE_SETREG(ctrlstat, 0x20000000);
422
423	dbe_TurnOffDma(par);
424
425	/* dbe_CalculateScreenParams(); */
426	maxPixelsPerTileX = 512 / bytesPerPixel;
427	wholeTilesX = xpmax / maxPixelsPerTileX;
428	if (wholeTilesX * maxPixelsPerTileX < xpmax)
429		wholeTilesX++;
430
431	printk(KERN_DEBUG "sgivwfb: pixPerTile=%d wholeTilesX=%d\n",
432	       maxPixelsPerTileX, wholeTilesX);
433
434	/* dbe_InitGammaMap(); */
435	udelay(10);
436
437	for (i = 0; i < 256; i++) {
438		DBE_ISETREG(gmap, i, (i << 24) | (i << 16) | (i << 8));
439	}
440
441	/* dbe_TurnOn(); */
442	DBE_GETREG(vt_xy, readVal);
443	if (GET_DBE_FIELD(VT_XY, VT_FREEZE, readVal) == 1) {
444		DBE_SETREG(vt_xy, 0x00000000);
445		udelay(1);
446	} else
447		dbe_TurnOffDma(par);
448
449	/* dbe_Initdbe(); */
450	for (i = 0; i < 256; i++) {
451		for (j = 0; j < 100; j++) {
452			DBE_GETREG(cm_fifo, readVal);
453			if (readVal != 0x00000000)
454				break;
455			else
456				udelay(10);
457		}
458
459		// DBE_ISETREG(cmap, i, 0x00000000);
460		DBE_ISETREG(cmap, i, (i << 8) | (i << 16) | (i << 24));
461	}
462
463	/* dbe_InitFramebuffer(); */
464	frmWrite1 = 0;
465	SET_DBE_FIELD(FRM_SIZE_TILE, FRM_WIDTH_TILE, frmWrite1,
466		      wholeTilesX);
467	SET_DBE_FIELD(FRM_SIZE_TILE, FRM_RHS, frmWrite1, 0);
468
469	switch (bytesPerPixel) {
470	case 1:
471		SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1,
472			      DBE_FRM_DEPTH_8);
473		break;
474	case 2:
475		SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1,
476			      DBE_FRM_DEPTH_16);
477		break;
478	case 4:
479		SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1,
480			      DBE_FRM_DEPTH_32);
481		break;
482	}
483
484	frmWrite2 = 0;
485	SET_DBE_FIELD(FRM_SIZE_PIXEL, FB_HEIGHT_PIX, frmWrite2, ypmax);
486
487	// Tell dbe about the framebuffer location and type
488	frmWrite3b = 0;
489	SET_DBE_FIELD(FRM_CONTROL, FRM_TILE_PTR, frmWrite3b,
490		      sgivwfb_mem_phys >> 9);
491	SET_DBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, frmWrite3b, 1);
492	SET_DBE_FIELD(FRM_CONTROL, FRM_LINEAR, frmWrite3b, 1);
493
494	/* Initialize DIDs */
495
496	outputVal = 0;
497	switch (bytesPerPixel) {
498	case 1:
499		SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_I8);
500		break;
501	case 2:
502		SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_RGBA5);
503		break;
504	case 4:
505		SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_RGB8);
506		break;
507	}
508	SET_DBE_FIELD(WID, BUF, outputVal, DBE_BMODE_BOTH);
509
510	for (i = 0; i < 32; i++) {
511		DBE_ISETREG(mode_regs, i, outputVal);
512	}
513
514	/* dbe_InitTiming(); */
515	DBE_SETREG(vt_intr01, 0xffffffff);
516	DBE_SETREG(vt_intr23, 0xffffffff);
517
518	DBE_GETREG(dotclock, readVal);
519	DBE_SETREG(dotclock, readVal & 0xffff);
520
521	DBE_SETREG(vt_xymax, 0x00000000);
522	outputVal = 0;
523	SET_DBE_FIELD(VT_VSYNC, VT_VSYNC_ON, outputVal,
524		      currentTiming->vsync_start);
525	SET_DBE_FIELD(VT_VSYNC, VT_VSYNC_OFF, outputVal,
526		      currentTiming->vsync_end);
527	DBE_SETREG(vt_vsync, outputVal);
528	outputVal = 0;
529	SET_DBE_FIELD(VT_HSYNC, VT_HSYNC_ON, outputVal,
530		      currentTiming->hsync_start);
531	SET_DBE_FIELD(VT_HSYNC, VT_HSYNC_OFF, outputVal,
532		      currentTiming->hsync_end);
533	DBE_SETREG(vt_hsync, outputVal);
534	outputVal = 0;
535	SET_DBE_FIELD(VT_VBLANK, VT_VBLANK_ON, outputVal,
536		      currentTiming->vblank_start);
537	SET_DBE_FIELD(VT_VBLANK, VT_VBLANK_OFF, outputVal,
538		      currentTiming->vblank_end);
539	DBE_SETREG(vt_vblank, outputVal);
540	outputVal = 0;
541	SET_DBE_FIELD(VT_HBLANK, VT_HBLANK_ON, outputVal,
542		      currentTiming->hblank_start);
543	SET_DBE_FIELD(VT_HBLANK, VT_HBLANK_OFF, outputVal,
544		      currentTiming->hblank_end - 3);
545	DBE_SETREG(vt_hblank, outputVal);
546	outputVal = 0;
547	SET_DBE_FIELD(VT_VCMAP, VT_VCMAP_ON, outputVal,
548		      currentTiming->vblank_start);
549	SET_DBE_FIELD(VT_VCMAP, VT_VCMAP_OFF, outputVal,
550		      currentTiming->vblank_end);
551	DBE_SETREG(vt_vcmap, outputVal);
552	outputVal = 0;
553	SET_DBE_FIELD(VT_HCMAP, VT_HCMAP_ON, outputVal,
554		      currentTiming->hblank_start);
555	SET_DBE_FIELD(VT_HCMAP, VT_HCMAP_OFF, outputVal,
556		      currentTiming->hblank_end - 3);
557	DBE_SETREG(vt_hcmap, outputVal);
558
559	if (flatpanel_id != -1)
560		sgivwfb_setup_flatpanel(par, currentTiming);
561
562	outputVal = 0;
563	temp = currentTiming->vblank_start - currentTiming->vblank_end - 1;
564	if (temp > 0)
565		temp = -temp;
566
567	SET_DBE_FIELD(DID_START_XY, DID_STARTY, outputVal, (u32) temp);
568	if (currentTiming->hblank_end >= 20)
569		SET_DBE_FIELD(DID_START_XY, DID_STARTX, outputVal,
570			      currentTiming->hblank_end - 20);
571	else
572		SET_DBE_FIELD(DID_START_XY, DID_STARTX, outputVal,
573			      currentTiming->htotal - (20 -
574						       currentTiming->
575						       hblank_end));
576	DBE_SETREG(did_start_xy, outputVal);
577
578	outputVal = 0;
579	SET_DBE_FIELD(CRS_START_XY, CRS_STARTY, outputVal,
580		      (u32) (temp + 1));
581	if (currentTiming->hblank_end >= DBE_CRS_MAGIC)
582		SET_DBE_FIELD(CRS_START_XY, CRS_STARTX, outputVal,
583			      currentTiming->hblank_end - DBE_CRS_MAGIC);
584	else
585		SET_DBE_FIELD(CRS_START_XY, CRS_STARTX, outputVal,
586			      currentTiming->htotal - (DBE_CRS_MAGIC -
587						       currentTiming->
588						       hblank_end));
589	DBE_SETREG(crs_start_xy, outputVal);
590
591	outputVal = 0;
592	SET_DBE_FIELD(VC_START_XY, VC_STARTY, outputVal, (u32) temp);
593	SET_DBE_FIELD(VC_START_XY, VC_STARTX, outputVal,
594		      currentTiming->hblank_end - 4);
595	DBE_SETREG(vc_start_xy, outputVal);
596
597	DBE_SETREG(frm_size_tile, frmWrite1);
598	DBE_SETREG(frm_size_pixel, frmWrite2);
599
600	outputVal = 0;
601	SET_DBE_FIELD(DOTCLK, M, outputVal, currentTiming->pll_m - 1);
602	SET_DBE_FIELD(DOTCLK, N, outputVal, currentTiming->pll_n - 1);
603	SET_DBE_FIELD(DOTCLK, P, outputVal, currentTiming->pll_p);
604	SET_DBE_FIELD(DOTCLK, RUN, outputVal, 1);
605	DBE_SETREG(dotclock, outputVal);
606
607	udelay(11 * 1000);
608
609	DBE_SETREG(vt_vpixen, 0xffffff);
610	DBE_SETREG(vt_hpixen, 0xffffff);
611
612	outputVal = 0;
613	SET_DBE_FIELD(VT_XYMAX, VT_MAXX, outputVal, currentTiming->htotal);
614	SET_DBE_FIELD(VT_XYMAX, VT_MAXY, outputVal, currentTiming->vtotal);
615	DBE_SETREG(vt_xymax, outputVal);
616
617	outputVal = frmWrite1;
618	SET_DBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, outputVal, 1);
619	DBE_SETREG(frm_size_tile, outputVal);
620	DBE_SETREG(frm_size_tile, frmWrite1);
621
622	outputVal = 0;
623	SET_DBE_FIELD(OVR_WIDTH_TILE, OVR_FIFO_RESET, outputVal, 1);
624	DBE_SETREG(ovr_width_tile, outputVal);
625	DBE_SETREG(ovr_width_tile, 0);
626
627	DBE_SETREG(frm_control, frmWrite3b);
628	DBE_SETREG(did_control, 0);
629
630	// Wait for dbe to take frame settings
631	for (i = 0; i < 100000; i++) {
632		DBE_GETREG(frm_inhwctrl, readVal);
633		if (GET_DBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, readVal) !=
634		    0)
635			break;
636		else
637			udelay(1);
638	}
639
640	if (i == 100000)
641		printk(KERN_INFO
642		       "sgivwfb: timeout waiting for frame DMA enable.\n");
643
644	outputVal = 0;
645	htmp = currentTiming->hblank_end - 19;
646	if (htmp < 0)
647		htmp += currentTiming->htotal;	/* allow blank to wrap around */
648	SET_DBE_FIELD(VT_HPIXEN, VT_HPIXEN_ON, outputVal, htmp);
649	SET_DBE_FIELD(VT_HPIXEN, VT_HPIXEN_OFF, outputVal,
650		      ((htmp + currentTiming->width -
651			2) % currentTiming->htotal));
652	DBE_SETREG(vt_hpixen, outputVal);
653
654	outputVal = 0;
655	SET_DBE_FIELD(VT_VPIXEN, VT_VPIXEN_OFF, outputVal,
656		      currentTiming->vblank_start);
657	SET_DBE_FIELD(VT_VPIXEN, VT_VPIXEN_ON, outputVal,
658		      currentTiming->vblank_end);
659	DBE_SETREG(vt_vpixen, outputVal);
660
661	// Turn off mouse cursor
662	par->regs->crs_ctl = 0;
663
664	DBE_GETREG(ctrlstat, readVal);
665	readVal &= 0x02000000;
666
667	if (readVal != 0) {
668		DBE_SETREG(ctrlstat, 0x30000000);
669	}
670	return 0;
671}
672
673/*
674 *  Set a single color register. The values supplied are already
675 *  rounded down to the hardware's capabilities (according to the
676 *  entries in the var structure). Return != 0 for invalid regno.
677 */
678
679static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green,
680			     u_int blue, u_int transp,
681			     struct fb_info *info)
682{
683	struct sgivw_par *par = (struct sgivw_par *) info->par;
684
685	if (regno > 255)
686		return 1;
687	red >>= 8;
688	green >>= 8;
689	blue >>= 8;
690
691	/* wait for the color map FIFO to have a free entry */
692	while (par->cmap_fifo == 0)
693		par->cmap_fifo = par->regs->cm_fifo;
694
695	par->regs->cmap[regno] = (red << 24) | (green << 16) | (blue << 8);
696	par->cmap_fifo--;	/* assume FIFO is filling up */
697	return 0;
698}
699
700static int sgivwfb_mmap(struct fb_info *info,
701			struct vm_area_struct *vma)
702{
703	unsigned long size = vma->vm_end - vma->vm_start;
704	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
705
706	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
707		return -EINVAL;
708	if (offset + size > sgivwfb_mem_size)
709		return -EINVAL;
710	offset += sgivwfb_mem_phys;
711	pgprot_val(vma->vm_page_prot) =
712	    pgprot_val(vma->vm_page_prot) | _PAGE_PCD;
713	vma->vm_flags |= VM_IO;
714	if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT,
715						size, vma->vm_page_prot))
716		return -EAGAIN;
717	printk(KERN_DEBUG "sgivwfb: mmap framebuffer P(%lx)->V(%lx)\n",
718	       offset, vma->vm_start);
719	return 0;
720}
721
722int __init sgivwfb_setup(char *options)
723{
724	char *this_opt;
725
726	if (!options || !*options)
727		return 0;
728
729	while ((this_opt = strsep(&options, ",")) != NULL) {
730		if (!strncmp(this_opt, "monitor:", 8)) {
731			if (!strncmp(this_opt + 8, "crt", 3))
732				flatpanel_id = -1;
733			else if (!strncmp(this_opt + 8, "1600sw", 6))
734				flatpanel_id = FLATPANEL_SGI_1600SW;
735		}
736	}
737	return 0;
738}
739
740/*
741 *  Initialisation
742 */
743static int __devinit sgivwfb_probe(struct platform_device *dev)
744{
745	struct sgivw_par *par;
746	struct fb_info *info;
747	char *monitor;
748
749	info = framebuffer_alloc(sizeof(struct sgivw_par) + sizeof(u32) * 16, &dev->dev);
750	if (!info)
751		return -ENOMEM;
752	par = info->par;
753
754	if (!request_mem_region(DBE_REG_PHYS, DBE_REG_SIZE, "sgivwfb")) {
755		printk(KERN_ERR "sgivwfb: couldn't reserve mmio region\n");
756		framebuffer_release(info);
757		return -EBUSY;
758	}
759
760	par->regs = (struct asregs *) ioremap_nocache(DBE_REG_PHYS, DBE_REG_SIZE);
761	if (!par->regs) {
762		printk(KERN_ERR "sgivwfb: couldn't ioremap registers\n");
763		goto fail_ioremap_regs;
764	}
765
766	mtrr_add(sgivwfb_mem_phys, sgivwfb_mem_size, MTRR_TYPE_WRCOMB, 1);
767
768	sgivwfb_fix.smem_start = sgivwfb_mem_phys;
769	sgivwfb_fix.smem_len = sgivwfb_mem_size;
770	sgivwfb_fix.ywrapstep = ywrap;
771	sgivwfb_fix.ypanstep = ypan;
772
773	info->fix = sgivwfb_fix;
774
775	switch (flatpanel_id) {
776		case FLATPANEL_SGI_1600SW:
777			info->var = sgivwfb_var1600sw;
778			monitor = "SGI 1600SW flatpanel";
779			break;
780		default:
781			info->var = sgivwfb_var;
782			monitor = "CRT";
783	}
784
785	printk(KERN_INFO "sgivwfb: %s monitor selected\n", monitor);
786
787	info->fbops = &sgivwfb_ops;
788	info->pseudo_palette = (void *) (par + 1);
789	info->flags = FBINFO_DEFAULT;
790
791	info->screen_base = ioremap_nocache((unsigned long) sgivwfb_mem_phys, sgivwfb_mem_size);
792	if (!info->screen_base) {
793		printk(KERN_ERR "sgivwfb: couldn't ioremap screen_base\n");
794		goto fail_ioremap_fbmem;
795	}
796
797	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
798		goto fail_color_map;
799
800	if (register_framebuffer(info) < 0) {
801		printk(KERN_ERR "sgivwfb: couldn't register framebuffer\n");
802		goto fail_register_framebuffer;
803	}
804
805	platform_set_drvdata(dev, info);
806
807	printk(KERN_INFO "fb%d: SGI DBE frame buffer device, using %ldK of video memory at %#lx\n",
808		info->node, sgivwfb_mem_size >> 10, sgivwfb_mem_phys);
809	return 0;
810
811fail_register_framebuffer:
812	fb_dealloc_cmap(&info->cmap);
813fail_color_map:
814	iounmap((char *) info->screen_base);
815fail_ioremap_fbmem:
816	iounmap(par->regs);
817fail_ioremap_regs:
818	release_mem_region(DBE_REG_PHYS, DBE_REG_SIZE);
819	framebuffer_release(info);
820	return -ENXIO;
821}
822
823static int __devexit sgivwfb_remove(struct platform_device *dev)
824{
825	struct fb_info *info = platform_get_drvdata(dev);
826
827	if (info) {
828		struct sgivw_par *par = info->par;
829
830		unregister_framebuffer(info);
831		dbe_TurnOffDma(par);
832		iounmap(par->regs);
833		iounmap(info->screen_base);
834		release_mem_region(DBE_REG_PHYS, DBE_REG_SIZE);
835		fb_dealloc_cmap(&info->cmap);
836		framebuffer_release(info);
837	}
838	return 0;
839}
840
841static struct platform_driver sgivwfb_driver = {
842	.probe	= sgivwfb_probe,
843	.remove	= __devexit_p(sgivwfb_remove),
844	.driver	= {
845		.name	= "sgivwfb",
846	},
847};
848
849static struct platform_device *sgivwfb_device;
850
851int __init sgivwfb_init(void)
852{
853	int ret;
854
855#ifndef MODULE
856	char *option = NULL;
857
858	if (fb_get_options("sgivwfb", &option))
859		return -ENODEV;
860	sgivwfb_setup(option);
861#endif
862	ret = platform_driver_register(&sgivwfb_driver);
863	if (!ret) {
864		sgivwfb_device = platform_device_alloc("sgivwfb", 0);
865		if (sgivwfb_device) {
866			ret = platform_device_add(sgivwfb_device);
867		} else
868			ret = -ENOMEM;
869		if (ret) {
870			platform_driver_unregister(&sgivwfb_driver);
871			platform_device_put(sgivwfb_device);
872		}
873	}
874	return ret;
875}
876
877module_init(sgivwfb_init);
878
879#ifdef MODULE
880MODULE_LICENSE("GPL");
881
882static void __exit sgivwfb_exit(void)
883{
884	platform_device_unregister(sgivwfb_device);
885	platform_driver_unregister(&sgivwfb_driver);
886}
887
888module_exit(sgivwfb_exit);
889
890#endif				/* MODULE */
891