1/*
2 * SiS 300/540/630[S]/730[S],
3 * SiS 315[E|PRO]/550/[M]65x/[M]66x[F|M|G]X/[M]74x[GX]/330/[M]76x[GX],
4 * XGI V3XT/V5/V8, Z7
5 * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
6 *
7 * Copyright (C) 2001-2005 Thomas Winischhofer, Vienna, Austria.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the named License,
12 * or any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
22 *
23 * Author:	Thomas Winischhofer <thomas@winischhofer.net>
24 *
25 * Author of (practically wiped) code base:
26 *		SiS (www.sis.com)
27 *		Copyright (C) 1999 Silicon Integrated Systems, Inc.
28 *
29 * See http://www.winischhofer.net/ for more information and updates
30 *
31 * Originally based on the VBE 2.0 compliant graphic boards framebuffer driver,
32 * which is (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
33 *
34 */
35
36#include <linux/version.h>
37#include <linux/module.h>
38#include <linux/moduleparam.h>
39#include <linux/kernel.h>
40#include <linux/spinlock.h>
41#include <linux/errno.h>
42#include <linux/string.h>
43#include <linux/mm.h>
44
45#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
46#include <linux/tty.h>
47#else
48#include <linux/screen_info.h>
49#endif
50
51#include <linux/slab.h>
52#include <linux/fb.h>
53#include <linux/selection.h>
54#include <linux/ioport.h>
55#include <linux/init.h>
56#include <linux/pci.h>
57#include <linux/vmalloc.h>
58#include <linux/capability.h>
59#include <linux/fs.h>
60#include <linux/types.h>
61#include <asm/uaccess.h>
62#include <asm/io.h>
63#ifdef CONFIG_MTRR
64#include <asm/mtrr.h>
65#endif
66
67#include "sis.h"
68#include "sis_main.h"
69
70static void sisfb_handle_command(struct sis_video_info *ivideo,
71				 struct sisfb_cmd *sisfb_command);
72
73/* ------------------ Internal helper routines ----------------- */
74
75static void __init
76sisfb_setdefaultparms(void)
77{
78	sisfb_off		= 0;
79	sisfb_parm_mem		= 0;
80	sisfb_accel		= -1;
81	sisfb_ypan		= -1;
82	sisfb_max		= -1;
83	sisfb_userom		= -1;
84	sisfb_useoem		= -1;
85	sisfb_mode_idx		= -1;
86	sisfb_parm_rate		= -1;
87	sisfb_crt1off		= 0;
88	sisfb_forcecrt1		= -1;
89	sisfb_crt2type		= -1;
90	sisfb_crt2flags		= 0;
91	sisfb_pdc		= 0xff;
92	sisfb_pdca		= 0xff;
93	sisfb_scalelcd		= -1;
94	sisfb_specialtiming 	= CUT_NONE;
95	sisfb_lvdshl		= -1;
96	sisfb_dstn		= 0;
97	sisfb_fstn		= 0;
98	sisfb_tvplug		= -1;
99	sisfb_tvstd		= -1;
100	sisfb_tvxposoffset	= 0;
101	sisfb_tvyposoffset	= 0;
102	sisfb_nocrt2rate	= 0;
103#if !defined(__i386__) && !defined(__x86_64__)
104	sisfb_resetcard		= 0;
105	sisfb_videoram		= 0;
106#endif
107}
108
109/* ------------- Parameter parsing -------------- */
110
111static void __devinit
112sisfb_search_vesamode(unsigned int vesamode, bool quiet)
113{
114	int i = 0, j = 0;
115
116	/* We don't know the hardware specs yet and there is no ivideo */
117
118	if(vesamode == 0) {
119		if(!quiet)
120			printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
121
122		sisfb_mode_idx = DEFAULT_MODE;
123
124		return;
125	}
126
127	vesamode &= 0x1dff;  /* Clean VESA mode number from other flags */
128
129	while(sisbios_mode[i++].mode_no[0] != 0) {
130		if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
131		    (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
132			if(sisfb_fstn) {
133				if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
134				   sisbios_mode[i-1].mode_no[1] == 0x56 ||
135				   sisbios_mode[i-1].mode_no[1] == 0x53)
136					continue;
137			} else {
138				if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
139				   sisbios_mode[i-1].mode_no[1] == 0x5b)
140					continue;
141			}
142			sisfb_mode_idx = i - 1;
143			j = 1;
144			break;
145		}
146	}
147	if((!j) && !quiet)
148		printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
149}
150
151static void __devinit
152sisfb_search_mode(char *name, bool quiet)
153{
154	unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
155	int i = 0;
156	char strbuf[16], strbuf1[20];
157	char *nameptr = name;
158
159	/* We don't know the hardware specs yet and there is no ivideo */
160
161	if(name == NULL) {
162		if(!quiet)
163			printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
164
165		sisfb_mode_idx = DEFAULT_MODE;
166		return;
167	}
168
169	if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
170		if(!quiet)
171			printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
172
173		sisfb_mode_idx = DEFAULT_MODE;
174		return;
175	}
176
177	if(strlen(name) <= 19) {
178		strcpy(strbuf1, name);
179		for(i = 0; i < strlen(strbuf1); i++) {
180			if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
181		}
182
183		/* This does some fuzzy mode naming detection */
184		if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
185			if((rate <= 32) || (depth > 32)) {
186				j = rate; rate = depth; depth = j;
187			}
188			sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
189			nameptr = strbuf;
190			sisfb_parm_rate = rate;
191		} else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
192			sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
193			nameptr = strbuf;
194		} else {
195			xres = 0;
196			if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
197				sprintf(strbuf, "%ux%ux8", xres, yres);
198				nameptr = strbuf;
199			} else {
200				sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
201				return;
202			}
203		}
204	}
205
206	i = 0; j = 0;
207	while(sisbios_mode[i].mode_no[0] != 0) {
208		if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
209			if(sisfb_fstn) {
210				if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
211				   sisbios_mode[i-1].mode_no[1] == 0x56 ||
212				   sisbios_mode[i-1].mode_no[1] == 0x53)
213					continue;
214			} else {
215				if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
216				   sisbios_mode[i-1].mode_no[1] == 0x5b)
217					continue;
218			}
219			sisfb_mode_idx = i - 1;
220			j = 1;
221			break;
222		}
223	}
224
225	if((!j) && !quiet)
226		printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
227}
228
229#ifndef MODULE
230static void __devinit
231sisfb_get_vga_mode_from_kernel(void)
232{
233#ifdef CONFIG_X86
234	char mymode[32];
235	int  mydepth = screen_info.lfb_depth;
236
237	if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
238
239	if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
240	    (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
241	    (mydepth >= 8) && (mydepth <= 32) ) {
242
243		if(mydepth == 24) mydepth = 32;
244
245		sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
246					screen_info.lfb_height,
247					mydepth);
248
249		printk(KERN_DEBUG
250			"sisfb: Using vga mode %s pre-set by kernel as default\n",
251			mymode);
252
253		sisfb_search_mode(mymode, true);
254	}
255#endif
256	return;
257}
258#endif
259
260static void __init
261sisfb_search_crt2type(const char *name)
262{
263	int i = 0;
264
265	/* We don't know the hardware specs yet and there is no ivideo */
266
267	if(name == NULL) return;
268
269	while(sis_crt2type[i].type_no != -1) {
270		if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
271			sisfb_crt2type = sis_crt2type[i].type_no;
272			sisfb_tvplug = sis_crt2type[i].tvplug_no;
273			sisfb_crt2flags = sis_crt2type[i].flags;
274			break;
275		}
276		i++;
277	}
278
279	sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
280	sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
281
282	if(sisfb_crt2type < 0)
283		printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
284}
285
286static void __init
287sisfb_search_tvstd(const char *name)
288{
289	int i = 0;
290
291	/* We don't know the hardware specs yet and there is no ivideo */
292
293	if(name == NULL)
294		return;
295
296	while(sis_tvtype[i].type_no != -1) {
297		if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
298			sisfb_tvstd = sis_tvtype[i].type_no;
299			break;
300		}
301		i++;
302	}
303}
304
305static void __init
306sisfb_search_specialtiming(const char *name)
307{
308	int i = 0;
309	bool found = false;
310
311	/* We don't know the hardware specs yet and there is no ivideo */
312
313	if(name == NULL)
314		return;
315
316	if(!strnicmp(name, "none", 4)) {
317		sisfb_specialtiming = CUT_FORCENONE;
318		printk(KERN_DEBUG "sisfb: Special timing disabled\n");
319	} else {
320		while(mycustomttable[i].chipID != 0) {
321			if(!strnicmp(name,mycustomttable[i].optionName,
322			   strlen(mycustomttable[i].optionName))) {
323				sisfb_specialtiming = mycustomttable[i].SpecialID;
324				found = true;
325				printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
326					mycustomttable[i].vendorName,
327					mycustomttable[i].cardName,
328					mycustomttable[i].optionName);
329				break;
330			}
331			i++;
332		}
333		if(!found) {
334			printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
335			printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
336			i = 0;
337			while(mycustomttable[i].chipID != 0) {
338				printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
339					mycustomttable[i].optionName,
340					mycustomttable[i].vendorName,
341					mycustomttable[i].cardName);
342				i++;
343			}
344		}
345	}
346}
347
348/* ----------- Various detection routines ----------- */
349
350static void __devinit
351sisfb_detect_custom_timing(struct sis_video_info *ivideo)
352{
353	unsigned char *biosver = NULL;
354	unsigned char *biosdate = NULL;
355	bool footprint;
356	u32 chksum = 0;
357	int i, j;
358
359	if(ivideo->SiS_Pr.UseROM) {
360		biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06;
361		biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c;
362		for(i = 0; i < 32768; i++)
363			chksum += ivideo->SiS_Pr.VirtualRomBase[i];
364	}
365
366	i = 0;
367	do {
368		if( (mycustomttable[i].chipID == ivideo->chip)			&&
369		    ((!strlen(mycustomttable[i].biosversion)) ||
370		     (ivideo->SiS_Pr.UseROM &&
371		      (!strncmp(mycustomttable[i].biosversion, biosver,
372				strlen(mycustomttable[i].biosversion)))))	&&
373		    ((!strlen(mycustomttable[i].biosdate)) ||
374		     (ivideo->SiS_Pr.UseROM &&
375		      (!strncmp(mycustomttable[i].biosdate, biosdate,
376				strlen(mycustomttable[i].biosdate)))))		&&
377		    ((!mycustomttable[i].bioschksum) ||
378		     (ivideo->SiS_Pr.UseROM &&
379		      (mycustomttable[i].bioschksum == chksum)))		&&
380		    (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
381		    (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
382			footprint = true;
383			for(j = 0; j < 5; j++) {
384				if(mycustomttable[i].biosFootprintAddr[j]) {
385					if(ivideo->SiS_Pr.UseROM) {
386						if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
387							mycustomttable[i].biosFootprintData[j]) {
388							footprint = false;
389						}
390					} else
391						footprint = false;
392				}
393			}
394			if(footprint) {
395				ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
396				printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
397					mycustomttable[i].vendorName,
398				mycustomttable[i].cardName);
399				printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
400					mycustomttable[i].optionName);
401				break;
402			}
403		}
404		i++;
405	} while(mycustomttable[i].chipID);
406}
407
408static bool __devinit
409sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
410{
411	int i, j, xres, yres, refresh, index;
412	u32 emodes;
413
414	if(buffer[0] != 0x00 || buffer[1] != 0xff ||
415	   buffer[2] != 0xff || buffer[3] != 0xff ||
416	   buffer[4] != 0xff || buffer[5] != 0xff ||
417	   buffer[6] != 0xff || buffer[7] != 0x00) {
418		printk(KERN_DEBUG "sisfb: Bad EDID header\n");
419		return false;
420	}
421
422	if(buffer[0x12] != 0x01) {
423		printk(KERN_INFO "sisfb: EDID version %d not supported\n",
424			buffer[0x12]);
425		return false;
426	}
427
428	monitor->feature = buffer[0x18];
429
430	if(!buffer[0x14] & 0x80) {
431		if(!(buffer[0x14] & 0x08)) {
432			printk(KERN_INFO
433				"sisfb: WARNING: Monitor does not support separate syncs\n");
434		}
435	}
436
437	if(buffer[0x13] >= 0x01) {
438	   /* EDID V1 rev 1 and 2: Search for monitor descriptor
439	    * to extract ranges
440	    */
441	    j = 0x36;
442	    for(i=0; i<4; i++) {
443	       if(buffer[j]     == 0x00 && buffer[j + 1] == 0x00 &&
444		  buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
445		  buffer[j + 4] == 0x00) {
446		  monitor->hmin = buffer[j + 7];
447		  monitor->hmax = buffer[j + 8];
448		  monitor->vmin = buffer[j + 5];
449		  monitor->vmax = buffer[j + 6];
450		  monitor->dclockmax = buffer[j + 9] * 10 * 1000;
451		  monitor->datavalid = true;
452		  break;
453	       }
454	       j += 18;
455	    }
456	}
457
458	if(!monitor->datavalid) {
459	   /* Otherwise: Get a range from the list of supported
460	    * Estabished Timings. This is not entirely accurate,
461	    * because fixed frequency monitors are not supported
462	    * that way.
463	    */
464	   monitor->hmin = 65535; monitor->hmax = 0;
465	   monitor->vmin = 65535; monitor->vmax = 0;
466	   monitor->dclockmax = 0;
467	   emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
468	   for(i = 0; i < 13; i++) {
469	      if(emodes & sisfb_ddcsmodes[i].mask) {
470		 if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
471		 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
472		 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
473		 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
474		 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
475	      }
476	   }
477	   index = 0x26;
478	   for(i = 0; i < 8; i++) {
479	      xres = (buffer[index] + 31) * 8;
480	      switch(buffer[index + 1] & 0xc0) {
481		 case 0xc0: yres = (xres * 9) / 16; break;
482		 case 0x80: yres = (xres * 4) /  5; break;
483		 case 0x40: yres = (xres * 3) /  4; break;
484		 default:   yres = xres;	    break;
485	      }
486	      refresh = (buffer[index + 1] & 0x3f) + 60;
487	      if((xres >= 640) && (yres >= 480)) {
488		 for(j = 0; j < 8; j++) {
489		    if((xres == sisfb_ddcfmodes[j].x) &&
490		       (yres == sisfb_ddcfmodes[j].y) &&
491		       (refresh == sisfb_ddcfmodes[j].v)) {
492		      if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
493		      if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
494		      if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
495		      if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
496		      if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[j].d;
497		    }
498		 }
499	      }
500	      index += 2;
501	   }
502	   if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
503	      monitor->datavalid = true;
504	   }
505	}
506
507	return monitor->datavalid;
508}
509
510static void __devinit
511sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
512{
513	unsigned short temp, i, realcrtno = crtno;
514	unsigned char  buffer[256];
515
516	monitor->datavalid = false;
517
518	if(crtno) {
519	   if(ivideo->vbflags & CRT2_LCD)      realcrtno = 1;
520	   else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
521	   else return;
522	}
523
524	if((ivideo->sisfb_crt1off) && (!crtno))
525		return;
526
527	temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
528				realcrtno, 0, &buffer[0], ivideo->vbflags2);
529	if((!temp) || (temp == 0xffff)) {
530	   printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
531	   return;
532	} else {
533	   printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
534	   printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
535		crtno + 1,
536		(temp & 0x1a) ? "" : "[none of the supported]",
537		(temp & 0x02) ? "2 " : "",
538		(temp & 0x08) ? "D&P" : "",
539		(temp & 0x10) ? "FPDI-2" : "");
540	   if(temp & 0x02) {
541	      i = 3;  /* Number of retrys */
542	      do {
543		 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
544				     realcrtno, 1, &buffer[0], ivideo->vbflags2);
545	      } while((temp) && i--);
546	      if(!temp) {
547		 if(sisfb_interpret_edid(monitor, &buffer[0])) {
548		    printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
549			monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
550			monitor->dclockmax / 1000);
551		 } else {
552		    printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
553		 }
554	      } else {
555		 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
556	      }
557	   } else {
558	      printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
559	   }
560	}
561}
562
563/* -------------- Mode validation --------------- */
564
565static bool
566sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
567		int mode_idx, int rate_idx, int rate)
568{
569	int htotal, vtotal;
570	unsigned int dclock, hsync;
571
572	if(!monitor->datavalid)
573		return true;
574
575	if(mode_idx < 0)
576		return false;
577
578	/* Skip for 320x200, 320x240, 640x400 */
579	switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
580	case 0x59:
581	case 0x41:
582	case 0x4f:
583	case 0x50:
584	case 0x56:
585	case 0x53:
586	case 0x2f:
587	case 0x5d:
588	case 0x5e:
589		return true;
590#ifdef CONFIG_FB_SIS_315
591	case 0x5a:
592	case 0x5b:
593		if(ivideo->sisvga_engine == SIS_315_VGA) return true;
594#endif
595	}
596
597	if(rate < (monitor->vmin - 1))
598		return false;
599	if(rate > (monitor->vmax + 1))
600		return false;
601
602	if(sisfb_gettotalfrommode(&ivideo->SiS_Pr,
603				  sisbios_mode[mode_idx].mode_no[ivideo->mni],
604				  &htotal, &vtotal, rate_idx)) {
605		dclock = (htotal * vtotal * rate) / 1000;
606		if(dclock > (monitor->dclockmax + 1000))
607			return false;
608		hsync = dclock / htotal;
609		if(hsync < (monitor->hmin - 1))
610			return false;
611		if(hsync > (monitor->hmax + 1))
612			return false;
613        } else {
614		return false;
615	}
616	return true;
617}
618
619static int
620sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
621{
622	u16 xres=0, yres, myres;
623
624#ifdef CONFIG_FB_SIS_300
625	if(ivideo->sisvga_engine == SIS_300_VGA) {
626		if(!(sisbios_mode[myindex].chipset & MD_SIS300))
627			return -1 ;
628	}
629#endif
630#ifdef CONFIG_FB_SIS_315
631	if(ivideo->sisvga_engine == SIS_315_VGA) {
632		if(!(sisbios_mode[myindex].chipset & MD_SIS315))
633			return -1;
634	}
635#endif
636
637	myres = sisbios_mode[myindex].yres;
638
639	switch(vbflags & VB_DISPTYPE_DISP2) {
640
641	case CRT2_LCD:
642		xres = ivideo->lcdxres; yres = ivideo->lcdyres;
643
644		if((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) &&
645		   (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) {
646			if(sisbios_mode[myindex].xres > xres)
647				return -1;
648			if(myres > yres)
649				return -1;
650		}
651
652		if(ivideo->sisfb_fstn) {
653			if(sisbios_mode[myindex].xres == 320) {
654				if(myres == 240) {
655					switch(sisbios_mode[myindex].mode_no[1]) {
656						case 0x50: myindex = MODE_FSTN_8;  break;
657						case 0x56: myindex = MODE_FSTN_16; break;
658						case 0x53: return -1;
659					}
660				}
661			}
662		}
663
664		if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
665			 	sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
666			 	ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) {
667			return -1;
668		}
669		break;
670
671	case CRT2_TV:
672		if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
673				sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
674			return -1;
675		}
676		break;
677
678	case CRT2_VGA:
679		if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
680				sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
681			return -1;
682		}
683		break;
684	}
685
686	return myindex;
687}
688
689static u8
690sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
691{
692	int i = 0;
693	u16 xres = sisbios_mode[mode_idx].xres;
694	u16 yres = sisbios_mode[mode_idx].yres;
695
696	ivideo->rate_idx = 0;
697	while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
698		if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
699			if(sisfb_vrate[i].refresh == rate) {
700				ivideo->rate_idx = sisfb_vrate[i].idx;
701				break;
702			} else if(sisfb_vrate[i].refresh > rate) {
703				if((sisfb_vrate[i].refresh - rate) <= 3) {
704					DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
705						rate, sisfb_vrate[i].refresh);
706					ivideo->rate_idx = sisfb_vrate[i].idx;
707					ivideo->refresh_rate = sisfb_vrate[i].refresh;
708				} else if(((rate - sisfb_vrate[i-1].refresh) <= 2)
709						&& (sisfb_vrate[i].idx != 1)) {
710					DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
711						rate, sisfb_vrate[i-1].refresh);
712					ivideo->rate_idx = sisfb_vrate[i-1].idx;
713					ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
714				}
715				break;
716			} else if((rate - sisfb_vrate[i].refresh) <= 2) {
717				DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
718						rate, sisfb_vrate[i].refresh);
719				ivideo->rate_idx = sisfb_vrate[i].idx;
720				break;
721			}
722		}
723		i++;
724	}
725	if(ivideo->rate_idx > 0) {
726		return ivideo->rate_idx;
727	} else {
728		printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
729				rate, xres, yres);
730		return 0;
731	}
732}
733
734static bool
735sisfb_bridgeisslave(struct sis_video_info *ivideo)
736{
737	unsigned char P1_00;
738
739	if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE))
740		return false;
741
742	inSISIDXREG(SISPART1,0x00,P1_00);
743	if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
744	    ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
745		return true;
746	} else {
747		return false;
748	}
749}
750
751static bool
752sisfballowretracecrt1(struct sis_video_info *ivideo)
753{
754	u8 temp;
755
756	inSISIDXREG(SISCR,0x17,temp);
757	if(!(temp & 0x80))
758		return false;
759
760	inSISIDXREG(SISSR,0x1f,temp);
761	if(temp & 0xc0)
762		return false;
763
764	return true;
765}
766
767static bool
768sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
769{
770	if(!sisfballowretracecrt1(ivideo))
771		return false;
772
773	if(inSISREG(SISINPSTAT) & 0x08)
774		return true;
775	else
776		return false;
777}
778
779static void
780sisfbwaitretracecrt1(struct sis_video_info *ivideo)
781{
782	int watchdog;
783
784	if(!sisfballowretracecrt1(ivideo))
785		return;
786
787	watchdog = 65536;
788	while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
789	watchdog = 65536;
790	while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
791}
792
793static bool
794sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
795{
796	unsigned char temp, reg;
797
798	switch(ivideo->sisvga_engine) {
799	case SIS_300_VGA: reg = 0x25; break;
800	case SIS_315_VGA: reg = 0x30; break;
801	default:	  return false;
802	}
803
804	inSISIDXREG(SISPART1, reg, temp);
805	if(temp & 0x02)
806		return true;
807	else
808		return false;
809}
810
811static bool
812sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
813{
814	if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
815		if(!sisfb_bridgeisslave(ivideo)) {
816			return sisfbcheckvretracecrt2(ivideo);
817		}
818	}
819	return sisfbcheckvretracecrt1(ivideo);
820}
821
822static u32
823sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
824{
825	u8 idx, reg1, reg2, reg3, reg4;
826	u32 ret = 0;
827
828	(*vcount) = (*hcount) = 0;
829
830	if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
831
832		ret |= (FB_VBLANK_HAVE_VSYNC  |
833			FB_VBLANK_HAVE_HBLANK |
834			FB_VBLANK_HAVE_VBLANK |
835			FB_VBLANK_HAVE_VCOUNT |
836			FB_VBLANK_HAVE_HCOUNT);
837		switch(ivideo->sisvga_engine) {
838			case SIS_300_VGA: idx = 0x25; break;
839			default:
840			case SIS_315_VGA: idx = 0x30; break;
841		}
842		inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */
843		inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */
844		inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */
845		inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */
846		if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
847		if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
848		if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
849		(*vcount) = reg3 | ((reg4 & 0x70) << 4);
850		(*hcount) = reg2 | ((reg4 & 0x0f) << 8);
851
852	} else if(sisfballowretracecrt1(ivideo)) {
853
854		ret |= (FB_VBLANK_HAVE_VSYNC  |
855			FB_VBLANK_HAVE_VBLANK |
856			FB_VBLANK_HAVE_VCOUNT |
857			FB_VBLANK_HAVE_HCOUNT);
858		reg1 = inSISREG(SISINPSTAT);
859		if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
860		if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
861		inSISIDXREG(SISCR,0x20,reg1);
862		inSISIDXREG(SISCR,0x1b,reg1);
863		inSISIDXREG(SISCR,0x1c,reg2);
864		inSISIDXREG(SISCR,0x1d,reg3);
865		(*vcount) = reg2 | ((reg3 & 0x07) << 8);
866		(*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
867	}
868
869	return ret;
870}
871
872static int
873sisfb_myblank(struct sis_video_info *ivideo, int blank)
874{
875	u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
876	bool backlight = true;
877
878	switch(blank) {
879		case FB_BLANK_UNBLANK:	/* on */
880			sr01  = 0x00;
881			sr11  = 0x00;
882			sr1f  = 0x00;
883			cr63  = 0x00;
884			p2_0  = 0x20;
885			p1_13 = 0x00;
886			backlight = true;
887			break;
888		case FB_BLANK_NORMAL:	/* blank */
889			sr01  = 0x20;
890			sr11  = 0x00;
891			sr1f  = 0x00;
892			cr63  = 0x00;
893			p2_0  = 0x20;
894			p1_13 = 0x00;
895			backlight = true;
896			break;
897		case FB_BLANK_VSYNC_SUSPEND:	/* no vsync */
898			sr01  = 0x20;
899			sr11  = 0x08;
900			sr1f  = 0x80;
901			cr63  = 0x40;
902			p2_0  = 0x40;
903			p1_13 = 0x80;
904			backlight = false;
905			break;
906		case FB_BLANK_HSYNC_SUSPEND:	/* no hsync */
907			sr01  = 0x20;
908			sr11  = 0x08;
909			sr1f  = 0x40;
910			cr63  = 0x40;
911			p2_0  = 0x80;
912			p1_13 = 0x40;
913			backlight = false;
914			break;
915		case FB_BLANK_POWERDOWN:	/* off */
916			sr01  = 0x20;
917			sr11  = 0x08;
918			sr1f  = 0xc0;
919			cr63  = 0x40;
920			p2_0  = 0xc0;
921			p1_13 = 0xc0;
922			backlight = false;
923			break;
924		default:
925			return 1;
926	}
927
928	if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
929
930		if( (!ivideo->sisfb_thismonitor.datavalid) ||
931		    ((ivideo->sisfb_thismonitor.datavalid) &&
932		     (ivideo->sisfb_thismonitor.feature & 0xe0))) {
933
934			if(ivideo->sisvga_engine == SIS_315_VGA) {
935				setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
936			}
937
938			if(!(sisfb_bridgeisslave(ivideo))) {
939				setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
940				setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
941			}
942		}
943
944	}
945
946	if(ivideo->currentvbflags & CRT2_LCD) {
947
948		if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
949			if(backlight) {
950				SiS_SiS30xBLOn(&ivideo->SiS_Pr);
951			} else {
952				SiS_SiS30xBLOff(&ivideo->SiS_Pr);
953			}
954		} else if(ivideo->sisvga_engine == SIS_315_VGA) {
955#ifdef CONFIG_FB_SIS_315
956			if(ivideo->vbflags2 & VB2_CHRONTEL) {
957				if(backlight) {
958					SiS_Chrontel701xBLOn(&ivideo->SiS_Pr);
959				} else {
960					SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
961				}
962			}
963#endif
964		}
965
966		if(((ivideo->sisvga_engine == SIS_300_VGA) &&
967		    (ivideo->vbflags2 & (VB2_301|VB2_30xBDH|VB2_LVDS))) ||
968		   ((ivideo->sisvga_engine == SIS_315_VGA) &&
969		    ((ivideo->vbflags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS))) {
970			setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
971		}
972
973		if(ivideo->sisvga_engine == SIS_300_VGA) {
974			if((ivideo->vbflags2 & VB2_30xB) &&
975			   (!(ivideo->vbflags2 & VB2_30xBDH))) {
976				setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
977			}
978		} else if(ivideo->sisvga_engine == SIS_315_VGA) {
979			if((ivideo->vbflags2 & VB2_30xB) &&
980			   (!(ivideo->vbflags2 & VB2_30xBDH))) {
981				setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
982			}
983		}
984
985	} else if(ivideo->currentvbflags & CRT2_VGA) {
986
987		if(ivideo->vbflags2 & VB2_30xB) {
988			setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
989		}
990
991	}
992
993	return 0;
994}
995
996/* ------------- Callbacks from init.c/init301.c  -------------- */
997
998#ifdef CONFIG_FB_SIS_300
999unsigned int
1000sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1001{
1002   struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1003   u32 val = 0;
1004
1005   pci_read_config_dword(ivideo->nbridge, reg, &val);
1006   return (unsigned int)val;
1007}
1008
1009void
1010sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val)
1011{
1012   struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1013
1014   pci_write_config_dword(ivideo->nbridge, reg, (u32)val);
1015}
1016
1017unsigned int
1018sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1019{
1020   struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1021   u32 val = 0;
1022
1023   if(!ivideo->lpcdev) return 0;
1024
1025   pci_read_config_dword(ivideo->lpcdev, reg, &val);
1026   return (unsigned int)val;
1027}
1028#endif
1029
1030#ifdef CONFIG_FB_SIS_315
1031void
1032sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val)
1033{
1034   struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1035
1036   pci_write_config_byte(ivideo->nbridge, reg, (u8)val);
1037}
1038
1039unsigned int
1040sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg)
1041{
1042   struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1043   u16 val = 0;
1044
1045   if(!ivideo->lpcdev) return 0;
1046
1047   pci_read_config_word(ivideo->lpcdev, reg, &val);
1048   return (unsigned int)val;
1049}
1050#endif
1051
1052/* ----------- FBDev related routines for all series ----------- */
1053
1054static int
1055sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
1056{
1057	return (var->bits_per_pixel == 8) ? 256 : 16;
1058}
1059
1060static void
1061sisfb_set_vparms(struct sis_video_info *ivideo)
1062{
1063	switch(ivideo->video_bpp) {
1064	case 8:
1065		ivideo->DstColor = 0x0000;
1066		ivideo->SiS310_AccelDepth = 0x00000000;
1067		ivideo->video_cmap_len = 256;
1068		break;
1069	case 16:
1070		ivideo->DstColor = 0x8000;
1071		ivideo->SiS310_AccelDepth = 0x00010000;
1072		ivideo->video_cmap_len = 16;
1073		break;
1074	case 32:
1075		ivideo->DstColor = 0xC000;
1076		ivideo->SiS310_AccelDepth = 0x00020000;
1077		ivideo->video_cmap_len = 16;
1078		break;
1079	default:
1080		ivideo->video_cmap_len = 16;
1081		printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
1082		ivideo->accel = 0;
1083	}
1084}
1085
1086static int
1087sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1088{
1089	int maxyres = ivideo->sisfb_mem / (var->xres_virtual * (var->bits_per_pixel >> 3));
1090
1091	if(maxyres > 32767) maxyres = 32767;
1092
1093	return maxyres;
1094}
1095
1096static void
1097sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1098{
1099	ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
1100	ivideo->scrnpitchCRT1 = ivideo->video_linelength;
1101	if(!(ivideo->currentvbflags & CRT1_LCDA)) {
1102		if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1103			ivideo->scrnpitchCRT1 <<= 1;
1104		}
1105	}
1106}
1107
1108static void
1109sisfb_set_pitch(struct sis_video_info *ivideo)
1110{
1111	bool isslavemode = false;
1112	unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
1113	unsigned short HDisplay2 = ivideo->video_linelength >> 3;
1114
1115	if(sisfb_bridgeisslave(ivideo)) isslavemode = true;
1116
1117	/* We need to set pitch for CRT1 if bridge is in slave mode, too */
1118	if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
1119		outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF));
1120		setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8));
1121	}
1122
1123	/* We must not set the pitch for CRT2 if bridge is in slave mode */
1124	if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
1125		orSISIDXREG(SISPART1,ivideo->CRT2_write_enable,0x01);
1126		outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF));
1127		setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8));
1128	}
1129}
1130
1131static void
1132sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1133{
1134	ivideo->video_cmap_len = sisfb_get_cmap_len(var);
1135
1136	switch(var->bits_per_pixel) {
1137	case 8:
1138		var->red.offset = var->green.offset = var->blue.offset = 0;
1139		var->red.length = var->green.length = var->blue.length = 6;
1140		break;
1141	case 16:
1142		var->red.offset = 11;
1143		var->red.length = 5;
1144		var->green.offset = 5;
1145		var->green.length = 6;
1146		var->blue.offset = 0;
1147		var->blue.length = 5;
1148		var->transp.offset = 0;
1149		var->transp.length = 0;
1150		break;
1151	case 32:
1152		var->red.offset = 16;
1153		var->red.length = 8;
1154		var->green.offset = 8;
1155		var->green.length = 8;
1156		var->blue.offset = 0;
1157		var->blue.length = 8;
1158		var->transp.offset = 24;
1159		var->transp.length = 8;
1160		break;
1161	}
1162}
1163
1164static int
1165sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
1166{
1167	unsigned short modeno = ivideo->mode_no;
1168
1169	/* >=2.6.12's fbcon clears the screen anyway */
1170#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
1171	if(!clrscrn) modeno |= 0x80;
1172#else
1173	modeno |= 0x80;
1174#endif
1175
1176	outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1177
1178	sisfb_pre_setmode(ivideo);
1179
1180	if(!SiSSetMode(&ivideo->SiS_Pr, modeno)) {
1181		printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
1182		return -EINVAL;
1183	}
1184
1185	outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1186
1187	sisfb_post_setmode(ivideo);
1188
1189	return 0;
1190}
1191
1192
1193static int
1194sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
1195{
1196	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1197	unsigned int htotal = 0, vtotal = 0;
1198	unsigned int drate = 0, hrate = 0;
1199	int found_mode = 0, ret;
1200	int old_mode;
1201	u32 pixclock;
1202
1203	htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1204
1205	vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1206
1207	pixclock = var->pixclock;
1208
1209	if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1210		vtotal += var->yres;
1211		vtotal <<= 1;
1212	} else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1213		vtotal += var->yres;
1214		vtotal <<= 2;
1215	} else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1216		vtotal += var->yres;
1217		vtotal <<= 1;
1218	} else 	vtotal += var->yres;
1219
1220	if(!(htotal) || !(vtotal)) {
1221		DPRINTK("sisfb: Invalid 'var' information\n");
1222		return -EINVAL;
1223	}
1224
1225	if(pixclock && htotal && vtotal) {
1226		drate = 1000000000 / pixclock;
1227		hrate = (drate * 1000) / htotal;
1228		ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1229	} else {
1230		ivideo->refresh_rate = 60;
1231	}
1232
1233	old_mode = ivideo->sisfb_mode_idx;
1234	ivideo->sisfb_mode_idx = 0;
1235
1236	while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
1237	       (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
1238		if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
1239		    (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
1240		    (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1241			ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1242			found_mode = 1;
1243			break;
1244		}
1245		ivideo->sisfb_mode_idx++;
1246	}
1247
1248	if(found_mode) {
1249		ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
1250				ivideo->sisfb_mode_idx, ivideo->currentvbflags);
1251		ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1252	} else {
1253		ivideo->sisfb_mode_idx = -1;
1254	}
1255
1256       	if(ivideo->sisfb_mode_idx < 0) {
1257		printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1258		       var->yres, var->bits_per_pixel);
1259		ivideo->sisfb_mode_idx = old_mode;
1260		return -EINVAL;
1261	}
1262
1263	if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1264		ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1265		ivideo->refresh_rate = 60;
1266	}
1267
1268	if(isactive) {
1269		/* If acceleration to be used? Need to know
1270		 * before pre/post_set_mode()
1271		 */
1272		ivideo->accel = 0;
1273#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1274#ifdef STUPID_ACCELF_TEXT_SHIT
1275		if(var->accel_flags & FB_ACCELF_TEXT) {
1276			info->flags &= ~FBINFO_HWACCEL_DISABLED;
1277		} else {
1278			info->flags |= FBINFO_HWACCEL_DISABLED;
1279		}
1280#endif
1281		if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
1282#else
1283		if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
1284#endif
1285
1286		if((ret = sisfb_set_mode(ivideo, 1))) {
1287			return ret;
1288		}
1289
1290		ivideo->video_bpp    = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1291		ivideo->video_width  = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1292		ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1293
1294		sisfb_calc_pitch(ivideo, var);
1295		sisfb_set_pitch(ivideo);
1296
1297		sisfb_set_vparms(ivideo);
1298
1299		ivideo->current_width = ivideo->video_width;
1300		ivideo->current_height = ivideo->video_height;
1301		ivideo->current_bpp = ivideo->video_bpp;
1302		ivideo->current_htotal = htotal;
1303		ivideo->current_vtotal = vtotal;
1304		ivideo->current_linelength = ivideo->video_linelength;
1305		ivideo->current_pixclock = var->pixclock;
1306		ivideo->current_refresh_rate = ivideo->refresh_rate;
1307		ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
1308	}
1309
1310	return 0;
1311}
1312
1313static void
1314sisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base)
1315{
1316	outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1317
1318	outSISIDXREG(SISCR, 0x0D, base & 0xFF);
1319	outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
1320	outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
1321	if(ivideo->sisvga_engine == SIS_315_VGA) {
1322		setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
1323	}
1324}
1325
1326static void
1327sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
1328{
1329	if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1330		orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
1331		outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
1332		outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
1333		outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
1334		if(ivideo->sisvga_engine == SIS_315_VGA) {
1335			setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
1336		}
1337	}
1338}
1339
1340static int
1341sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1342{
1343	if(var->xoffset > (var->xres_virtual - var->xres)) {
1344		return -EINVAL;
1345	}
1346	if(var->yoffset > (var->yres_virtual - var->yres)) {
1347		return -EINVAL;
1348	}
1349
1350	ivideo->current_base = (var->yoffset * var->xres_virtual) + var->xoffset;
1351
1352	/* calculate base bpp dep. */
1353	switch(var->bits_per_pixel) {
1354	case 32:
1355		break;
1356	case 16:
1357		ivideo->current_base >>= 1;
1358		break;
1359	case 8:
1360	default:
1361		ivideo->current_base >>= 2;
1362		break;
1363	}
1364
1365	ivideo->current_base += (ivideo->video_offset >> 2);
1366
1367	sisfb_set_base_CRT1(ivideo, ivideo->current_base);
1368	sisfb_set_base_CRT2(ivideo, ivideo->current_base);
1369
1370	return 0;
1371}
1372
1373static int
1374sisfb_open(struct fb_info *info, int user)
1375{
1376	return 0;
1377}
1378
1379static int
1380sisfb_release(struct fb_info *info, int user)
1381{
1382	return 0;
1383}
1384
1385static int
1386sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1387		unsigned transp, struct fb_info *info)
1388{
1389	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1390
1391	if(regno >= sisfb_get_cmap_len(&info->var))
1392		return 1;
1393
1394	switch(info->var.bits_per_pixel) {
1395	case 8:
1396		outSISREG(SISDACA, regno);
1397		outSISREG(SISDACD, (red >> 10));
1398		outSISREG(SISDACD, (green >> 10));
1399		outSISREG(SISDACD, (blue >> 10));
1400		if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1401			outSISREG(SISDAC2A, regno);
1402			outSISREG(SISDAC2D, (red >> 8));
1403			outSISREG(SISDAC2D, (green >> 8));
1404			outSISREG(SISDAC2D, (blue >> 8));
1405		}
1406		break;
1407	case 16:
1408		((u32 *)(info->pseudo_palette))[regno] =
1409				(red & 0xf800)          |
1410				((green & 0xfc00) >> 5) |
1411				((blue & 0xf800) >> 11);
1412		break;
1413	case 32:
1414		red >>= 8;
1415		green >>= 8;
1416		blue >>= 8;
1417		((u32 *)(info->pseudo_palette))[regno] =
1418				(red << 16) | (green << 8) | (blue);
1419		break;
1420	}
1421	return 0;
1422}
1423
1424static int
1425sisfb_set_par(struct fb_info *info)
1426{
1427	int err;
1428
1429	if((err = sisfb_do_set_var(&info->var, 1, info)))
1430		return err;
1431
1432#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
1433	sisfb_get_fix(&info->fix, info->currcon, info);
1434#else
1435	sisfb_get_fix(&info->fix, -1, info);
1436#endif
1437	return 0;
1438}
1439
1440static int
1441sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1442{
1443	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1444	unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1445	unsigned int drate = 0, hrate = 0, maxyres;
1446	int found_mode = 0;
1447	int refresh_rate, search_idx, tidx;
1448	bool recalc_clock = false;
1449	u32 pixclock;
1450
1451	htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1452
1453	vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1454
1455	pixclock = var->pixclock;
1456
1457	if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1458		vtotal += var->yres;
1459		vtotal <<= 1;
1460	} else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1461		vtotal += var->yres;
1462		vtotal <<= 2;
1463	} else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1464		vtotal += var->yres;
1465		vtotal <<= 1;
1466	} else
1467		vtotal += var->yres;
1468
1469	if(!(htotal) || !(vtotal)) {
1470		SISFAIL("sisfb: no valid timing data");
1471	}
1472
1473	search_idx = 0;
1474	while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1475	       (sisbios_mode[search_idx].xres <= var->xres) ) {
1476		if( (sisbios_mode[search_idx].xres == var->xres) &&
1477		    (sisbios_mode[search_idx].yres == var->yres) &&
1478		    (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
1479			if((tidx = sisfb_validate_mode(ivideo, search_idx,
1480						ivideo->currentvbflags)) > 0) {
1481				found_mode = 1;
1482				search_idx = tidx;
1483				break;
1484			}
1485		}
1486		search_idx++;
1487	}
1488
1489	if(!found_mode) {
1490		search_idx = 0;
1491		while(sisbios_mode[search_idx].mode_no[0] != 0) {
1492		   if( (var->xres <= sisbios_mode[search_idx].xres) &&
1493		       (var->yres <= sisbios_mode[search_idx].yres) &&
1494		       (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
1495			if((tidx = sisfb_validate_mode(ivideo,search_idx,
1496						ivideo->currentvbflags)) > 0) {
1497				found_mode = 1;
1498				search_idx = tidx;
1499				break;
1500			}
1501		   }
1502		   search_idx++;
1503		}
1504		if(found_mode) {
1505			printk(KERN_DEBUG
1506				"sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1507				var->xres, var->yres, var->bits_per_pixel,
1508				sisbios_mode[search_idx].xres,
1509				sisbios_mode[search_idx].yres,
1510				var->bits_per_pixel);
1511			var->xres = sisbios_mode[search_idx].xres;
1512			var->yres = sisbios_mode[search_idx].yres;
1513		} else {
1514			printk(KERN_ERR
1515				"sisfb: Failed to find supported mode near %dx%dx%d\n",
1516				var->xres, var->yres, var->bits_per_pixel);
1517			return -EINVAL;
1518		}
1519	}
1520
1521	if( ((ivideo->vbflags2 & VB2_LVDS) ||
1522	     ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
1523	    (var->bits_per_pixel == 8) ) {
1524		/* Slave modes on LVDS and 301B-DH */
1525		refresh_rate = 60;
1526		recalc_clock = true;
1527	} else if( (ivideo->current_htotal == htotal) &&
1528		   (ivideo->current_vtotal == vtotal) &&
1529		   (ivideo->current_pixclock == pixclock) ) {
1530		/* x=x & y=y & c=c -> assume depth change */
1531		drate = 1000000000 / pixclock;
1532		hrate = (drate * 1000) / htotal;
1533		refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1534	} else if( ( (ivideo->current_htotal != htotal) ||
1535		     (ivideo->current_vtotal != vtotal) ) &&
1536		   (ivideo->current_pixclock == var->pixclock) ) {
1537		/* x!=x | y!=y & c=c -> invalid pixclock */
1538		if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
1539			refresh_rate =
1540				ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
1541		} else if(ivideo->sisfb_parm_rate != -1) {
1542			/* Sic, sisfb_parm_rate - want to know originally desired rate here */
1543			refresh_rate = ivideo->sisfb_parm_rate;
1544		} else {
1545			refresh_rate = 60;
1546		}
1547		recalc_clock = true;
1548	} else if((pixclock) && (htotal) && (vtotal)) {
1549		drate = 1000000000 / pixclock;
1550		hrate = (drate * 1000) / htotal;
1551		refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1552	} else if(ivideo->current_refresh_rate) {
1553		refresh_rate = ivideo->current_refresh_rate;
1554		recalc_clock = true;
1555	} else {
1556		refresh_rate = 60;
1557		recalc_clock = true;
1558	}
1559
1560	myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1561
1562	/* Eventually recalculate timing and clock */
1563	if(recalc_clock) {
1564		if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1565		var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
1566						sisbios_mode[search_idx].mode_no[ivideo->mni],
1567						myrateindex));
1568		sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr,
1569					sisbios_mode[search_idx].mode_no[ivideo->mni],
1570					myrateindex, var);
1571		if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1572			var->pixclock <<= 1;
1573		}
1574	}
1575
1576	if(ivideo->sisfb_thismonitor.datavalid) {
1577		if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1578				myrateindex, refresh_rate)) {
1579			printk(KERN_INFO
1580				"sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1581		}
1582	}
1583
1584	/* Adapt RGB settings */
1585	sisfb_bpp_to_var(ivideo, var);
1586
1587	/* Sanity check for offsets */
1588	if(var->xoffset < 0) var->xoffset = 0;
1589	if(var->yoffset < 0) var->yoffset = 0;
1590
1591	if(var->xres > var->xres_virtual)
1592		var->xres_virtual = var->xres;
1593
1594	if(ivideo->sisfb_ypan) {
1595		maxyres = sisfb_calc_maxyres(ivideo, var);
1596		if(ivideo->sisfb_max) {
1597			var->yres_virtual = maxyres;
1598		} else {
1599			if(var->yres_virtual > maxyres) {
1600				var->yres_virtual = maxyres;
1601			}
1602		}
1603		if(var->yres_virtual <= var->yres) {
1604			var->yres_virtual = var->yres;
1605		}
1606	} else {
1607		if(var->yres != var->yres_virtual) {
1608			var->yres_virtual = var->yres;
1609		}
1610		var->xoffset = 0;
1611		var->yoffset = 0;
1612	}
1613
1614	/* Truncate offsets to maximum if too high */
1615	if(var->xoffset > var->xres_virtual - var->xres) {
1616		var->xoffset = var->xres_virtual - var->xres - 1;
1617	}
1618
1619	if(var->yoffset > var->yres_virtual - var->yres) {
1620		var->yoffset = var->yres_virtual - var->yres - 1;
1621	}
1622
1623	/* Set everything else to 0 */
1624	var->red.msb_right =
1625		var->green.msb_right =
1626		var->blue.msb_right =
1627		var->transp.offset =
1628		var->transp.length =
1629		var->transp.msb_right = 0;
1630
1631	return 0;
1632}
1633
1634static int
1635sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
1636{
1637	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1638	int err;
1639
1640	if(var->xoffset > (var->xres_virtual - var->xres))
1641		return -EINVAL;
1642
1643	if(var->yoffset > (var->yres_virtual - var->yres))
1644		return -EINVAL;
1645
1646	if(var->vmode & FB_VMODE_YWRAP)
1647		return -EINVAL;
1648
1649	if(var->xoffset + info->var.xres > info->var.xres_virtual ||
1650	   var->yoffset + info->var.yres > info->var.yres_virtual)
1651		return -EINVAL;
1652
1653	if((err = sisfb_pan_var(ivideo, var)) < 0)
1654		return err;
1655
1656	info->var.xoffset = var->xoffset;
1657	info->var.yoffset = var->yoffset;
1658
1659	return 0;
1660}
1661
1662static int
1663sisfb_blank(int blank, struct fb_info *info)
1664{
1665	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1666
1667	return sisfb_myblank(ivideo, blank);
1668}
1669
1670/* ----------- FBDev related routines for all series ---------- */
1671
1672#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
1673static int	sisfb_ioctl(struct fb_info *info, unsigned int cmd,
1674			    unsigned long arg)
1675#else
1676static int	sisfb_ioctl(struct inode *inode, struct file *file,
1677				unsigned int cmd, unsigned long arg,
1678				struct fb_info *info)
1679#endif
1680{
1681	struct sis_video_info	*ivideo = (struct sis_video_info *)info->par;
1682	struct sis_memreq	sismemreq;
1683	struct fb_vblank	sisvbblank;
1684	u32			gpu32 = 0;
1685#ifndef __user
1686#define __user
1687#endif
1688	u32 __user 		*argp = (u32 __user *)arg;
1689
1690	switch(cmd) {
1691	   case FBIO_ALLOC:
1692		if(!capable(CAP_SYS_RAWIO))
1693			return -EPERM;
1694
1695		if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
1696			return -EFAULT;
1697
1698		sis_malloc(&sismemreq);
1699
1700		if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
1701			sis_free((u32)sismemreq.offset);
1702			return -EFAULT;
1703		}
1704		break;
1705
1706	   case FBIO_FREE:
1707		if(!capable(CAP_SYS_RAWIO))
1708			return -EPERM;
1709
1710		if(get_user(gpu32, argp))
1711			return -EFAULT;
1712
1713		sis_free(gpu32);
1714		break;
1715
1716	   case FBIOGET_VBLANK:
1717		sisvbblank.count = 0;
1718		sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
1719
1720		if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
1721			return -EFAULT;
1722
1723		break;
1724
1725	   case SISFB_GET_INFO_SIZE:
1726		return put_user(sizeof(struct sisfb_info), argp);
1727
1728	   case SISFB_GET_INFO_OLD:
1729		if(ivideo->warncount++ < 10)
1730			printk(KERN_INFO
1731				"sisfb: Deprecated ioctl call received - update your application!\n");
1732	   case SISFB_GET_INFO:  /* For communication with X driver */
1733		ivideo->sisfb_infoblock.sisfb_id         = SISFB_ID;
1734		ivideo->sisfb_infoblock.sisfb_version    = VER_MAJOR;
1735		ivideo->sisfb_infoblock.sisfb_revision   = VER_MINOR;
1736		ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1737		ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1738		ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1739		ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1740		ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
1741		if(ivideo->modechanged) {
1742			ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
1743		} else {
1744			ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
1745		}
1746		ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1747		ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1748		ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1749		ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1750		ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1751		ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1752		ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1753		ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1754		ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1755		ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1756		ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1757		ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1758		ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1759		ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1760		ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1761		ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1762		ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1763		ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1764		ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1765		ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1766		ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1767		ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1768		ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1769		ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1770		ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1771		ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1772		ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1773		ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
1774
1775		if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1776						sizeof(ivideo->sisfb_infoblock)))
1777			return -EFAULT;
1778
1779	        break;
1780
1781	   case SISFB_GET_VBRSTATUS_OLD:
1782		if(ivideo->warncount++ < 10)
1783			printk(KERN_INFO
1784				"sisfb: Deprecated ioctl call received - update your application!\n");
1785	   case SISFB_GET_VBRSTATUS:
1786		if(sisfb_CheckVBRetrace(ivideo))
1787			return put_user((u32)1, argp);
1788		else
1789			return put_user((u32)0, argp);
1790
1791	   case SISFB_GET_AUTOMAXIMIZE_OLD:
1792		if(ivideo->warncount++ < 10)
1793			printk(KERN_INFO
1794				"sisfb: Deprecated ioctl call received - update your application!\n");
1795	   case SISFB_GET_AUTOMAXIMIZE:
1796		if(ivideo->sisfb_max)
1797			return put_user((u32)1, argp);
1798		else
1799			return put_user((u32)0, argp);
1800
1801	   case SISFB_SET_AUTOMAXIMIZE_OLD:
1802		if(ivideo->warncount++ < 10)
1803			printk(KERN_INFO
1804				"sisfb: Deprecated ioctl call received - update your application!\n");
1805	   case SISFB_SET_AUTOMAXIMIZE:
1806		if(get_user(gpu32, argp))
1807			return -EFAULT;
1808
1809		ivideo->sisfb_max = (gpu32) ? 1 : 0;
1810		break;
1811
1812	   case SISFB_SET_TVPOSOFFSET:
1813		if(get_user(gpu32, argp))
1814			return -EFAULT;
1815
1816		sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1817		sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1818		break;
1819
1820	   case SISFB_GET_TVPOSOFFSET:
1821		return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1822							argp);
1823
1824	   case SISFB_COMMAND:
1825		if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1826							sizeof(struct sisfb_cmd)))
1827			return -EFAULT;
1828
1829		sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1830
1831		if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1832							sizeof(struct sisfb_cmd)))
1833			return -EFAULT;
1834
1835		break;
1836
1837	   case SISFB_SET_LOCK:
1838		if(get_user(gpu32, argp))
1839			return -EFAULT;
1840
1841		ivideo->sisfblocked = (gpu32) ? 1 : 0;
1842		break;
1843
1844	   default:
1845#ifdef SIS_NEW_CONFIG_COMPAT
1846		return -ENOIOCTLCMD;
1847#else
1848		return -EINVAL;
1849#endif
1850	}
1851	return 0;
1852}
1853
1854static int
1855sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1856{
1857	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1858
1859	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1860
1861	strcpy(fix->id, ivideo->myid);
1862
1863	fix->smem_start  = ivideo->video_base + ivideo->video_offset;
1864	fix->smem_len    = ivideo->sisfb_mem;
1865	fix->type        = FB_TYPE_PACKED_PIXELS;
1866	fix->type_aux    = 0;
1867	fix->visual      = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1868	fix->xpanstep    = 1;
1869	fix->ypanstep 	 = (ivideo->sisfb_ypan) ? 1 : 0;
1870	fix->ywrapstep   = 0;
1871	fix->line_length = ivideo->video_linelength;
1872	fix->mmio_start  = ivideo->mmio_base;
1873	fix->mmio_len    = ivideo->mmio_size;
1874	if(ivideo->sisvga_engine == SIS_300_VGA) {
1875		fix->accel = FB_ACCEL_SIS_GLAMOUR;
1876	} else if((ivideo->chip == SIS_330) ||
1877		  (ivideo->chip == SIS_760) ||
1878		  (ivideo->chip == SIS_761)) {
1879		fix->accel = FB_ACCEL_SIS_XABRE;
1880	} else if(ivideo->chip == XGI_20) {
1881		fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1882	} else if(ivideo->chip >= XGI_40) {
1883		fix->accel = FB_ACCEL_XGI_VOLARI_V;
1884	} else {
1885		fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
1886	}
1887
1888	return 0;
1889}
1890
1891/* ----------------  fb_ops structures ----------------- */
1892
1893static struct fb_ops sisfb_ops = {
1894	.owner		= THIS_MODULE,
1895	.fb_open	= sisfb_open,
1896	.fb_release	= sisfb_release,
1897	.fb_check_var	= sisfb_check_var,
1898	.fb_set_par	= sisfb_set_par,
1899	.fb_setcolreg	= sisfb_setcolreg,
1900	.fb_pan_display	= sisfb_pan_display,
1901	.fb_blank	= sisfb_blank,
1902	.fb_fillrect	= fbcon_sis_fillrect,
1903	.fb_copyarea	= fbcon_sis_copyarea,
1904	.fb_imageblit	= cfb_imageblit,
1905#ifdef CONFIG_FB_SOFT_CURSOR
1906	.fb_cursor	= soft_cursor,
1907#endif
1908	.fb_sync	= fbcon_sis_sync,
1909#ifdef SIS_NEW_CONFIG_COMPAT
1910	.fb_compat_ioctl= sisfb_ioctl,
1911#endif
1912	.fb_ioctl	= sisfb_ioctl
1913};
1914
1915/* ---------------- Chip generation dependent routines ---------------- */
1916
1917static struct pci_dev * __devinit
1918sisfb_get_northbridge(int basechipid)
1919{
1920	struct pci_dev *pdev = NULL;
1921	int nbridgenum, nbridgeidx, i;
1922	static const unsigned short nbridgeids[] = {
1923		PCI_DEVICE_ID_SI_540,	/* for SiS 540 VGA */
1924		PCI_DEVICE_ID_SI_630,	/* for SiS 630/730 VGA */
1925		PCI_DEVICE_ID_SI_730,
1926		PCI_DEVICE_ID_SI_550,   /* for SiS 550 VGA */
1927		PCI_DEVICE_ID_SI_650,   /* for SiS 650/651/740 VGA */
1928		PCI_DEVICE_ID_SI_651,
1929		PCI_DEVICE_ID_SI_740,
1930		PCI_DEVICE_ID_SI_661,	/* for SiS 661/741/660/760/761 VGA */
1931		PCI_DEVICE_ID_SI_741,
1932		PCI_DEVICE_ID_SI_660,
1933		PCI_DEVICE_ID_SI_760,
1934		PCI_DEVICE_ID_SI_761
1935	};
1936
1937	switch(basechipid) {
1938#ifdef CONFIG_FB_SIS_300
1939	case SIS_540:	nbridgeidx = 0; nbridgenum = 1; break;
1940	case SIS_630:	nbridgeidx = 1; nbridgenum = 2; break;
1941#endif
1942#ifdef CONFIG_FB_SIS_315
1943	case SIS_550:   nbridgeidx = 3; nbridgenum = 1; break;
1944	case SIS_650:	nbridgeidx = 4; nbridgenum = 3; break;
1945	case SIS_660:	nbridgeidx = 7; nbridgenum = 5; break;
1946#endif
1947	default:	return NULL;
1948	}
1949	for(i = 0; i < nbridgenum; i++) {
1950		if((pdev = pci_get_device(PCI_VENDOR_ID_SI,
1951				nbridgeids[nbridgeidx+i], NULL)))
1952			break;
1953	}
1954	return pdev;
1955}
1956
1957static int __devinit
1958sisfb_get_dram_size(struct sis_video_info *ivideo)
1959{
1960#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
1961	u8 reg;
1962#endif
1963
1964	ivideo->video_size = 0;
1965	ivideo->UMAsize = ivideo->LFBsize = 0;
1966
1967	switch(ivideo->chip) {
1968#ifdef CONFIG_FB_SIS_300
1969	case SIS_300:
1970		inSISIDXREG(SISSR, 0x14, reg);
1971		ivideo->video_size = ((reg & 0x3F) + 1) << 20;
1972		break;
1973	case SIS_540:
1974	case SIS_630:
1975	case SIS_730:
1976		if(!ivideo->nbridge)
1977			return -1;
1978		pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
1979		ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
1980		break;
1981#endif
1982#ifdef CONFIG_FB_SIS_315
1983	case SIS_315H:
1984	case SIS_315PRO:
1985	case SIS_315:
1986		inSISIDXREG(SISSR, 0x14, reg);
1987		ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1988		switch((reg >> 2) & 0x03) {
1989		case 0x01:
1990		case 0x03:
1991			ivideo->video_size <<= 1;
1992			break;
1993		case 0x02:
1994			ivideo->video_size += (ivideo->video_size/2);
1995		}
1996		break;
1997	case SIS_330:
1998		inSISIDXREG(SISSR, 0x14, reg);
1999		ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2000		if(reg & 0x0c) ivideo->video_size <<= 1;
2001		break;
2002	case SIS_550:
2003	case SIS_650:
2004	case SIS_740:
2005		inSISIDXREG(SISSR, 0x14, reg);
2006		ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2007		break;
2008	case SIS_661:
2009	case SIS_741:
2010		inSISIDXREG(SISCR, 0x79, reg);
2011		ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2012		break;
2013	case SIS_660:
2014	case SIS_760:
2015	case SIS_761:
2016		inSISIDXREG(SISCR, 0x79, reg);
2017		reg = (reg & 0xf0) >> 4;
2018		if(reg)	{
2019			ivideo->video_size = (1 << reg) << 20;
2020			ivideo->UMAsize = ivideo->video_size;
2021		}
2022		inSISIDXREG(SISCR, 0x78, reg);
2023		reg &= 0x30;
2024		if(reg) {
2025			if(reg == 0x10) {
2026				ivideo->LFBsize = (32 << 20);
2027			} else {
2028				ivideo->LFBsize = (64 << 20);
2029			}
2030			ivideo->video_size += ivideo->LFBsize;
2031		}
2032		break;
2033	case SIS_340:
2034	case XGI_20:
2035	case XGI_40:
2036		inSISIDXREG(SISSR, 0x14, reg);
2037		ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2038		if(ivideo->chip != XGI_20) {
2039			reg = (reg & 0x0c) >> 2;
2040			if(ivideo->revision_id == 2) {
2041				if(reg & 0x01) reg = 0x02;
2042				else	       reg = 0x00;
2043			}
2044			if(reg == 0x02)		ivideo->video_size <<= 1;
2045			else if(reg == 0x03)	ivideo->video_size <<= 2;
2046		}
2047		break;
2048#endif
2049	default:
2050		return -1;
2051	}
2052	return 0;
2053}
2054
2055/* -------------- video bridge device detection --------------- */
2056
2057static void __devinit
2058sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2059{
2060	u8 cr32, temp;
2061
2062	/* No CRT2 on XGI Z7 */
2063	if(ivideo->chip == XGI_20) {
2064		ivideo->sisfb_crt1off = 0;
2065		return;
2066	}
2067
2068#ifdef CONFIG_FB_SIS_300
2069	if(ivideo->sisvga_engine == SIS_300_VGA) {
2070		inSISIDXREG(SISSR, 0x17, temp);
2071		if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2072			/* PAL/NTSC is stored on SR16 on such machines */
2073			if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2074				inSISIDXREG(SISSR, 0x16, temp);
2075				if(temp & 0x20)
2076					ivideo->vbflags |= TV_PAL;
2077				else
2078					ivideo->vbflags |= TV_NTSC;
2079			}
2080		}
2081	}
2082#endif
2083
2084	inSISIDXREG(SISCR, 0x32, cr32);
2085
2086	if(cr32 & SIS_CRT1) {
2087		ivideo->sisfb_crt1off = 0;
2088	} else {
2089		ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2090	}
2091
2092	ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2093
2094	if(cr32 & SIS_VB_TV)   ivideo->vbflags |= CRT2_TV;
2095	if(cr32 & SIS_VB_LCD)  ivideo->vbflags |= CRT2_LCD;
2096	if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2097
2098	/* Check given parms for hardware compatibility.
2099	 * (Cannot do this in the search_xx routines since we don't
2100	 * know what hardware we are running on then)
2101	 */
2102
2103	if(ivideo->chip != SIS_550) {
2104	   ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2105	}
2106
2107	if(ivideo->sisfb_tvplug != -1) {
2108	   if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2109	       (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
2110	      if(ivideo->sisfb_tvplug & TV_YPBPR) {
2111		 ivideo->sisfb_tvplug = -1;
2112		 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2113	      }
2114	   }
2115	}
2116	if(ivideo->sisfb_tvplug != -1) {
2117	   if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2118	       (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
2119	      if(ivideo->sisfb_tvplug & TV_HIVISION) {
2120		 ivideo->sisfb_tvplug = -1;
2121		 printk(KERN_ERR "sisfb: HiVision not supported\n");
2122	      }
2123	   }
2124	}
2125	if(ivideo->sisfb_tvstd != -1) {
2126	   if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2127	       (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2128			(ivideo->vbflags2 & VB2_CHRONTEL))) ) {
2129	      if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
2130		 ivideo->sisfb_tvstd = -1;
2131		 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2132	      }
2133	   }
2134	}
2135
2136	/* Detect/set TV plug & type */
2137	if(ivideo->sisfb_tvplug != -1) {
2138		ivideo->vbflags |= ivideo->sisfb_tvplug;
2139	} else {
2140		if(cr32 & SIS_VB_YPBPR)     	 ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2141		else if(cr32 & SIS_VB_HIVISION)  ivideo->vbflags |= TV_HIVISION;
2142		else if(cr32 & SIS_VB_SCART)     ivideo->vbflags |= TV_SCART;
2143		else {
2144			if(cr32 & SIS_VB_SVIDEO)    ivideo->vbflags |= TV_SVIDEO;
2145			if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2146		}
2147	}
2148
2149	if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2150	    if(ivideo->sisfb_tvstd != -1) {
2151	       ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2152	       ivideo->vbflags |= ivideo->sisfb_tvstd;
2153	    }
2154	    if(ivideo->vbflags & TV_SCART) {
2155	       ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2156	       ivideo->vbflags |= TV_PAL;
2157	    }
2158	    if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2159		if(ivideo->sisvga_engine == SIS_300_VGA) {
2160			inSISIDXREG(SISSR, 0x38, temp);
2161			if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2162			else		ivideo->vbflags |= TV_NTSC;
2163		} else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2164			inSISIDXREG(SISSR, 0x38, temp);
2165			if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2166			else		ivideo->vbflags |= TV_NTSC;
2167		} else {
2168			inSISIDXREG(SISCR, 0x79, temp);
2169			if(temp & 0x20)	ivideo->vbflags |= TV_PAL;
2170			else		ivideo->vbflags |= TV_NTSC;
2171		}
2172	    }
2173	}
2174
2175	/* Copy forceCRT1 option to CRT1off if option is given */
2176	if(ivideo->sisfb_forcecrt1 != -1) {
2177	   ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2178	}
2179}
2180
2181/* ------------------ Sensing routines ------------------ */
2182
2183static bool __devinit
2184sisfb_test_DDC1(struct sis_video_info *ivideo)
2185{
2186    unsigned short old;
2187    int count = 48;
2188
2189    old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2190    do {
2191	if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2192    } while(count--);
2193    return (count != -1);
2194}
2195
2196static void __devinit
2197sisfb_sense_crt1(struct sis_video_info *ivideo)
2198{
2199    bool mustwait = false;
2200    u8  sr1F, cr17;
2201#ifdef CONFIG_FB_SIS_315
2202    u8  cr63=0;
2203#endif
2204    u16 temp = 0xffff;
2205    int i;
2206
2207    inSISIDXREG(SISSR,0x1F,sr1F);
2208    orSISIDXREG(SISSR,0x1F,0x04);
2209    andSISIDXREG(SISSR,0x1F,0x3F);
2210    if(sr1F & 0xc0) mustwait = true;
2211
2212#ifdef CONFIG_FB_SIS_315
2213    if(ivideo->sisvga_engine == SIS_315_VGA) {
2214       inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2215       cr63 &= 0x40;
2216       andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2217    }
2218#endif
2219
2220    inSISIDXREG(SISCR,0x17,cr17);
2221    cr17 &= 0x80;
2222    if(!cr17) {
2223       orSISIDXREG(SISCR,0x17,0x80);
2224       mustwait = true;
2225       outSISIDXREG(SISSR, 0x00, 0x01);
2226       outSISIDXREG(SISSR, 0x00, 0x03);
2227    }
2228
2229    if(mustwait) {
2230       for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2231    }
2232
2233#ifdef CONFIG_FB_SIS_315
2234    if(ivideo->chip >= SIS_330) {
2235       andSISIDXREG(SISCR,0x32,~0x20);
2236       if(ivideo->chip >= SIS_340) {
2237          outSISIDXREG(SISCR, 0x57, 0x4a);
2238       } else {
2239          outSISIDXREG(SISCR, 0x57, 0x5f);
2240       }
2241       orSISIDXREG(SISCR, 0x53, 0x02);
2242       while((inSISREG(SISINPSTAT)) & 0x01)    break;
2243       while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2244       if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2245       andSISIDXREG(SISCR, 0x53, 0xfd);
2246       andSISIDXREG(SISCR, 0x57, 0x00);
2247    }
2248#endif
2249
2250    if(temp == 0xffff) {
2251       i = 3;
2252       do {
2253	  temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2254		ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
2255       } while(((temp == 0) || (temp == 0xffff)) && i--);
2256
2257       if((temp == 0) || (temp == 0xffff)) {
2258          if(sisfb_test_DDC1(ivideo)) temp = 1;
2259       }
2260    }
2261
2262    if((temp) && (temp != 0xffff)) {
2263       orSISIDXREG(SISCR,0x32,0x20);
2264    }
2265
2266#ifdef CONFIG_FB_SIS_315
2267    if(ivideo->sisvga_engine == SIS_315_VGA) {
2268       setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2269    }
2270#endif
2271
2272    setSISIDXREG(SISCR,0x17,0x7F,cr17);
2273
2274    outSISIDXREG(SISSR,0x1F,sr1F);
2275}
2276
2277/* Determine and detect attached devices on SiS30x */
2278static void __devinit
2279SiS_SenseLCD(struct sis_video_info *ivideo)
2280{
2281	unsigned char buffer[256];
2282	unsigned short temp, realcrtno, i;
2283	u8 reg, cr37 = 0, paneltype = 0;
2284	u16 xres, yres;
2285
2286	ivideo->SiS_Pr.PanelSelfDetected = false;
2287
2288	/* LCD detection only for TMDS bridges */
2289	if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2290		return;
2291	if(ivideo->vbflags2 & VB2_30xBDH)
2292		return;
2293
2294	/* If LCD already set up by BIOS, skip it */
2295	inSISIDXREG(SISCR, 0x32, reg);
2296	if(reg & 0x08)
2297		return;
2298
2299	realcrtno = 1;
2300	if(ivideo->SiS_Pr.DDCPortMixup)
2301		realcrtno = 0;
2302
2303	/* Check DDC capabilities */
2304	temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2305				realcrtno, 0, &buffer[0], ivideo->vbflags2);
2306
2307	if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2308		return;
2309
2310	/* Read DDC data */
2311	i = 3;  /* Number of retrys */
2312	do {
2313		temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2314				ivideo->sisvga_engine, realcrtno, 1,
2315				&buffer[0], ivideo->vbflags2);
2316	} while((temp) && i--);
2317
2318	if(temp)
2319		return;
2320
2321	/* No digital device */
2322	if(!(buffer[0x14] & 0x80))
2323		return;
2324
2325	/* First detailed timing preferred timing? */
2326	if(!(buffer[0x18] & 0x02))
2327		return;
2328
2329	xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2330	yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2331
2332	switch(xres) {
2333		case 1024:
2334			if(yres == 768)
2335				paneltype = 0x02;
2336			break;
2337		case 1280:
2338			if(yres == 1024)
2339				paneltype = 0x03;
2340			break;
2341		case 1600:
2342			if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2343				paneltype = 0x0b;
2344			break;
2345	}
2346
2347	if(!paneltype)
2348		return;
2349
2350	if(buffer[0x23])
2351		cr37 |= 0x10;
2352
2353	if((buffer[0x47] & 0x18) == 0x18)
2354		cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2355	else
2356		cr37 |= 0xc0;
2357
2358	outSISIDXREG(SISCR, 0x36, paneltype);
2359	cr37 &= 0xf1;
2360	setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2361	orSISIDXREG(SISCR, 0x32, 0x08);
2362
2363	ivideo->SiS_Pr.PanelSelfDetected = true;
2364}
2365
2366static int __devinit
2367SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2368{
2369    int temp, mytest, result, i, j;
2370
2371    for(j = 0; j < 10; j++) {
2372       result = 0;
2373       for(i = 0; i < 3; i++) {
2374          mytest = test;
2375          outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2376          temp = (type >> 8) | (mytest & 0x00ff);
2377          setSISIDXREG(SISPART4,0x10,0xe0,temp);
2378          SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2379          mytest >>= 8;
2380          mytest &= 0x7f;
2381          inSISIDXREG(SISPART4,0x03,temp);
2382          temp ^= 0x0e;
2383          temp &= mytest;
2384          if(temp == mytest) result++;
2385	  outSISIDXREG(SISPART4,0x11,0x00);
2386	  andSISIDXREG(SISPART4,0x10,0xe0);
2387	  SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2388       }
2389       if((result == 0) || (result >= 2)) break;
2390    }
2391    return result;
2392}
2393
2394static void __devinit
2395SiS_Sense30x(struct sis_video_info *ivideo)
2396{
2397    u8  backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2398    u16 svhs=0, svhs_c=0;
2399    u16 cvbs=0, cvbs_c=0;
2400    u16 vga2=0, vga2_c=0;
2401    int myflag, result;
2402    char stdstr[] = "sisfb: Detected";
2403    char tvstr[]  = "TV connected to";
2404
2405    if(ivideo->vbflags2 & VB2_301) {
2406       svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2407       inSISIDXREG(SISPART4,0x01,myflag);
2408       if(myflag & 0x04) {
2409	  svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2410       }
2411    } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
2412       svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2413    } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
2414       svhs = 0x0200; cvbs = 0x0100;
2415    } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
2416       svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2417    } else
2418       return;
2419
2420    vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2421    if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
2422       svhs_c = 0x0408; cvbs_c = 0x0808;
2423    }
2424
2425    biosflag = 2;
2426    if(ivideo->haveXGIROM) {
2427       biosflag = ivideo->bios_abase[0x58] & 0x03;
2428    } else if(ivideo->newrom) {
2429       if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2430    } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2431       if(ivideo->bios_abase) {
2432          biosflag = ivideo->bios_abase[0xfe] & 0x03;
2433       }
2434    }
2435
2436    if(ivideo->chip == SIS_300) {
2437       inSISIDXREG(SISSR,0x3b,myflag);
2438       if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2439    }
2440
2441    if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2442       vga2 = vga2_c = 0;
2443    }
2444
2445    inSISIDXREG(SISSR,0x1e,backupSR_1e);
2446    orSISIDXREG(SISSR,0x1e,0x20);
2447
2448    inSISIDXREG(SISPART4,0x0d,backupP4_0d);
2449    if(ivideo->vbflags2 & VB2_30xC) {
2450       setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2451    } else {
2452       orSISIDXREG(SISPART4,0x0d,0x04);
2453    }
2454    SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2455
2456    inSISIDXREG(SISPART2,0x00,backupP2_00);
2457    outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2458
2459    inSISIDXREG(SISPART2,0x4d,backupP2_4d);
2460    if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
2461       outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2462    }
2463
2464    if(!(ivideo->vbflags2 & VB2_30xCLV)) {
2465       SISDoSense(ivideo, 0, 0);
2466    }
2467
2468    andSISIDXREG(SISCR, 0x32, ~0x14);
2469
2470    if(vga2_c || vga2) {
2471       if(SISDoSense(ivideo, vga2, vga2_c)) {
2472          if(biosflag & 0x01) {
2473	     printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2474	     orSISIDXREG(SISCR, 0x32, 0x04);
2475	  } else {
2476	     printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2477	     orSISIDXREG(SISCR, 0x32, 0x10);
2478	  }
2479       }
2480    }
2481
2482    andSISIDXREG(SISCR, 0x32, 0x3f);
2483
2484    if(ivideo->vbflags2 & VB2_30xCLV) {
2485       orSISIDXREG(SISPART4,0x0d,0x04);
2486    }
2487
2488    if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
2489       outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2490       SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2491       if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2492          if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2493	     printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2494	     orSISIDXREG(SISCR,0x32,0x80);
2495	  }
2496       }
2497       outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2498    }
2499
2500    andSISIDXREG(SISCR, 0x32, ~0x03);
2501
2502    if(!(ivideo->vbflags & TV_YPBPR)) {
2503       if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2504          printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2505          orSISIDXREG(SISCR, 0x32, 0x02);
2506       }
2507       if((biosflag & 0x02) || (!result)) {
2508          if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2509	     printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2510	     orSISIDXREG(SISCR, 0x32, 0x01);
2511          }
2512       }
2513    }
2514
2515    SISDoSense(ivideo, 0, 0);
2516
2517    outSISIDXREG(SISPART2,0x00,backupP2_00);
2518    outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2519    outSISIDXREG(SISSR,0x1e,backupSR_1e);
2520
2521    if(ivideo->vbflags2 & VB2_30xCLV) {
2522       inSISIDXREG(SISPART2,0x00,biosflag);
2523       if(biosflag & 0x20) {
2524          for(myflag = 2; myflag > 0; myflag--) {
2525	     biosflag ^= 0x20;
2526	     outSISIDXREG(SISPART2,0x00,biosflag);
2527	  }
2528       }
2529    }
2530
2531    outSISIDXREG(SISPART2,0x00,backupP2_00);
2532}
2533
2534/* Determine and detect attached TV's on Chrontel */
2535static void __devinit
2536SiS_SenseCh(struct sis_video_info *ivideo)
2537{
2538#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2539    u8 temp1, temp2;
2540    char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2541#endif
2542#ifdef CONFIG_FB_SIS_300
2543    unsigned char test[3];
2544    int i;
2545#endif
2546
2547    if(ivideo->chip < SIS_315H) {
2548
2549#ifdef CONFIG_FB_SIS_300
2550       ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1;		/* Chrontel 700x */
2551       SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c);	/* Set general purpose IO for Chrontel communication */
2552       SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2553       temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2554       /* See Chrontel TB31 for explanation */
2555       temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2556       if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2557	  SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
2558	  SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2559       }
2560       temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2561       if(temp2 != temp1) temp1 = temp2;
2562
2563       if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2564	   /* Read power status */
2565	   temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2566	   if((temp1 & 0x03) != 0x03) {
2567		/* Power all outputs */
2568		SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
2569		SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2570	   }
2571	   /* Sense connected TV devices */
2572	   for(i = 0; i < 3; i++) {
2573	       SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
2574	       SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2575	       SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
2576	       SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2577	       temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2578	       if(!(temp1 & 0x08))       test[i] = 0x02;
2579	       else if(!(temp1 & 0x02))  test[i] = 0x01;
2580	       else                      test[i] = 0;
2581	       SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2582	   }
2583
2584	   if(test[0] == test[1])      temp1 = test[0];
2585	   else if(test[0] == test[2]) temp1 = test[0];
2586	   else if(test[1] == test[2]) temp1 = test[1];
2587	   else {
2588		printk(KERN_INFO
2589			"sisfb: TV detection unreliable - test results varied\n");
2590		temp1 = test[2];
2591	   }
2592	   if(temp1 == 0x02) {
2593		printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2594		ivideo->vbflags |= TV_SVIDEO;
2595		orSISIDXREG(SISCR, 0x32, 0x02);
2596		andSISIDXREG(SISCR, 0x32, ~0x05);
2597	   } else if (temp1 == 0x01) {
2598		printk(KERN_INFO "%s CVBS output\n", stdstr);
2599		ivideo->vbflags |= TV_AVIDEO;
2600		orSISIDXREG(SISCR, 0x32, 0x01);
2601		andSISIDXREG(SISCR, 0x32, ~0x06);
2602	   } else {
2603		SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2604		andSISIDXREG(SISCR, 0x32, ~0x07);
2605	   }
2606       } else if(temp1 == 0) {
2607	  SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2608	  andSISIDXREG(SISCR, 0x32, ~0x07);
2609       }
2610       /* Set general purpose IO for Chrontel communication */
2611       SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2612#endif
2613
2614    } else {
2615
2616#ifdef CONFIG_FB_SIS_315
2617	ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2;		/* Chrontel 7019 */
2618	temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2619	SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
2620	SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2621	temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2622	temp2 |= 0x01;
2623	SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2624	SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2625	temp2 ^= 0x01;
2626	SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2627	SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2628	temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2629	SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2630	temp1 = 0;
2631	if(temp2 & 0x02) temp1 |= 0x01;
2632	if(temp2 & 0x10) temp1 |= 0x01;
2633	if(temp2 & 0x04) temp1 |= 0x02;
2634	if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2635	switch(temp1) {
2636	case 0x01:
2637	     printk(KERN_INFO "%s CVBS output\n", stdstr);
2638	     ivideo->vbflags |= TV_AVIDEO;
2639	     orSISIDXREG(SISCR, 0x32, 0x01);
2640	     andSISIDXREG(SISCR, 0x32, ~0x06);
2641	     break;
2642	case 0x02:
2643	     printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2644	     ivideo->vbflags |= TV_SVIDEO;
2645	     orSISIDXREG(SISCR, 0x32, 0x02);
2646	     andSISIDXREG(SISCR, 0x32, ~0x05);
2647	     break;
2648	case 0x04:
2649	     printk(KERN_INFO "%s SCART output\n", stdstr);
2650	     orSISIDXREG(SISCR, 0x32, 0x04);
2651	     andSISIDXREG(SISCR, 0x32, ~0x03);
2652	     break;
2653	default:
2654	     andSISIDXREG(SISCR, 0x32, ~0x07);
2655	}
2656#endif
2657    }
2658}
2659
2660static void __devinit
2661sisfb_get_VB_type(struct sis_video_info *ivideo)
2662{
2663	char stdstr[]    = "sisfb: Detected";
2664	char bridgestr[] = "video bridge";
2665	u8 vb_chipid;
2666	u8 reg;
2667
2668	/* No CRT2 on XGI Z7 */
2669	if(ivideo->chip == XGI_20)
2670		return;
2671
2672	inSISIDXREG(SISPART4, 0x00, vb_chipid);
2673	switch(vb_chipid) {
2674	case 0x01:
2675		inSISIDXREG(SISPART4, 0x01, reg);
2676		if(reg < 0xb0) {
2677			ivideo->vbflags |= VB_301;	/* Deprecated */
2678			ivideo->vbflags2 |= VB2_301;
2679			printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2680		} else if(reg < 0xc0) {
2681			ivideo->vbflags |= VB_301B;	/* Deprecated */
2682			ivideo->vbflags2 |= VB2_301B;
2683			inSISIDXREG(SISPART4,0x23,reg);
2684			if(!(reg & 0x02)) {
2685			   ivideo->vbflags |= VB_30xBDH;	/* Deprecated */
2686			   ivideo->vbflags2 |= VB2_30xBDH;
2687			   printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2688			} else {
2689			   printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2690			}
2691		} else if(reg < 0xd0) {
2692			ivideo->vbflags |= VB_301C;	/* Deprecated */
2693			ivideo->vbflags2 |= VB2_301C;
2694			printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2695		} else if(reg < 0xe0) {
2696			ivideo->vbflags |= VB_301LV;	/* Deprecated */
2697			ivideo->vbflags2 |= VB2_301LV;
2698			printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2699		} else if(reg <= 0xe1) {
2700			inSISIDXREG(SISPART4,0x39,reg);
2701			if(reg == 0xff) {
2702			   ivideo->vbflags |= VB_302LV;	/* Deprecated */
2703			   ivideo->vbflags2 |= VB2_302LV;
2704			   printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2705			} else {
2706			   ivideo->vbflags |= VB_301C;	/* Deprecated */
2707			   ivideo->vbflags2 |= VB2_301C;
2708			   printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2709			}
2710		}
2711		break;
2712	case 0x02:
2713		ivideo->vbflags |= VB_302B;	/* Deprecated */
2714		ivideo->vbflags2 |= VB2_302B;
2715		printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2716		break;
2717	}
2718
2719	if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2720		inSISIDXREG(SISCR, 0x37, reg);
2721		reg &= SIS_EXTERNAL_CHIP_MASK;
2722		reg >>= 1;
2723		if(ivideo->sisvga_engine == SIS_300_VGA) {
2724#ifdef CONFIG_FB_SIS_300
2725			switch(reg) {
2726			   case SIS_EXTERNAL_CHIP_LVDS:
2727				ivideo->vbflags |= VB_LVDS;	/* Deprecated */
2728				ivideo->vbflags2 |= VB2_LVDS;
2729				break;
2730			   case SIS_EXTERNAL_CHIP_TRUMPION:
2731				ivideo->vbflags |= (VB_LVDS | VB_TRUMPION);	/* Deprecated */
2732				ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2733				break;
2734			   case SIS_EXTERNAL_CHIP_CHRONTEL:
2735				ivideo->vbflags |= VB_CHRONTEL;	/* Deprecated */
2736				ivideo->vbflags2 |= VB2_CHRONTEL;
2737				break;
2738			   case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2739				ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);	/* Deprecated */
2740				ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2741				break;
2742			}
2743			if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2744#endif
2745		} else if(ivideo->chip < SIS_661) {
2746#ifdef CONFIG_FB_SIS_315
2747			switch (reg) {
2748			   case SIS310_EXTERNAL_CHIP_LVDS:
2749				ivideo->vbflags |= VB_LVDS;	/* Deprecated */
2750				ivideo->vbflags2 |= VB2_LVDS;
2751				break;
2752			   case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2753				ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);	/* Deprecated */
2754				ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2755				break;
2756			}
2757			if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2758#endif
2759		} else if(ivideo->chip >= SIS_661) {
2760#ifdef CONFIG_FB_SIS_315
2761			inSISIDXREG(SISCR, 0x38, reg);
2762			reg >>= 5;
2763			switch(reg) {
2764			   case 0x02:
2765				ivideo->vbflags |= VB_LVDS;	/* Deprecated */
2766				ivideo->vbflags2 |= VB2_LVDS;
2767				break;
2768			   case 0x03:
2769				ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);	/* Deprecated */
2770				ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2771				break;
2772			   case 0x04:
2773				ivideo->vbflags |= (VB_LVDS | VB_CONEXANT);	/* Deprecated */
2774				ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2775				break;
2776			}
2777			if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2778#endif
2779		}
2780		if(ivideo->vbflags2 & VB2_LVDS) {
2781		   printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2782		}
2783		if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2784		   printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2785		}
2786		if(ivideo->vbflags2 & VB2_CHRONTEL) {
2787		   printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2788		}
2789		if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2790		   printk(KERN_INFO "%s Conexant external device\n", stdstr);
2791		}
2792	}
2793
2794	if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2795		SiS_SenseLCD(ivideo);
2796		SiS_Sense30x(ivideo);
2797	} else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2798		SiS_SenseCh(ivideo);
2799	}
2800}
2801
2802/* ---------- Engine initialization routines ------------ */
2803
2804static void
2805sisfb_engine_init(struct sis_video_info *ivideo)
2806{
2807
2808	/* Initialize command queue (we use MMIO only) */
2809
2810	/* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2811
2812	ivideo->caps &= ~(TURBO_QUEUE_CAP    |
2813			  MMIO_CMD_QUEUE_CAP |
2814			  VM_CMD_QUEUE_CAP   |
2815			  AGP_CMD_QUEUE_CAP);
2816
2817#ifdef CONFIG_FB_SIS_300
2818	if(ivideo->sisvga_engine == SIS_300_VGA) {
2819		u32 tqueue_pos;
2820		u8 tq_state;
2821
2822		tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2823
2824		inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2825		tq_state |= 0xf0;
2826		tq_state &= 0xfc;
2827		tq_state |= (u8)(tqueue_pos >> 8);
2828		outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2829
2830		outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2831
2832		ivideo->caps |= TURBO_QUEUE_CAP;
2833	}
2834#endif
2835
2836#ifdef CONFIG_FB_SIS_315
2837	if(ivideo->sisvga_engine == SIS_315_VGA) {
2838		u32 tempq = 0, templ;
2839		u8  temp;
2840
2841		if(ivideo->chip == XGI_20) {
2842			switch(ivideo->cmdQueueSize) {
2843			case (64 * 1024):
2844				temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2845				break;
2846			case (128 * 1024):
2847			default:
2848				temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2849			}
2850		} else {
2851			switch(ivideo->cmdQueueSize) {
2852			case (4 * 1024 * 1024):
2853				temp = SIS_CMD_QUEUE_SIZE_4M;
2854				break;
2855			case (2 * 1024 * 1024):
2856				temp = SIS_CMD_QUEUE_SIZE_2M;
2857				break;
2858			case (1 * 1024 * 1024):
2859				temp = SIS_CMD_QUEUE_SIZE_1M;
2860				break;
2861			default:
2862			case (512 * 1024):
2863				temp = SIS_CMD_QUEUE_SIZE_512k;
2864			}
2865		}
2866
2867		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2868		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2869
2870		if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2871			/* Must disable dual pipe on XGI_40. Can't do
2872			 * this in MMIO mode, because it requires
2873			 * setting/clearing a bit in the MMIO fire trigger
2874			 * register.
2875			 */
2876			if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2877
2878				MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2879
2880				outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2881
2882				tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2883				MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2884
2885				tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2886				MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2887
2888				writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2889				writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2890				writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2891				writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2892
2893				MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2894
2895				sisfb_syncaccel(ivideo);
2896
2897				outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2898
2899			}
2900		}
2901
2902		tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2903		MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
2904
2905		temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
2906		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
2907
2908		tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2909		MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
2910
2911		ivideo->caps |= MMIO_CMD_QUEUE_CAP;
2912	}
2913#endif
2914
2915	ivideo->engineok = 1;
2916}
2917
2918static void __devinit
2919sisfb_detect_lcd_type(struct sis_video_info *ivideo)
2920{
2921	u8 reg;
2922	int i;
2923
2924	inSISIDXREG(SISCR, 0x36, reg);
2925	reg &= 0x0f;
2926	if(ivideo->sisvga_engine == SIS_300_VGA) {
2927		ivideo->CRT2LCDType = sis300paneltype[reg];
2928	} else if(ivideo->chip >= SIS_661) {
2929		ivideo->CRT2LCDType = sis661paneltype[reg];
2930	} else {
2931		ivideo->CRT2LCDType = sis310paneltype[reg];
2932		if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
2933			if((ivideo->CRT2LCDType != LCD_320x240_2) &&
2934			   (ivideo->CRT2LCDType != LCD_320x240_3)) {
2935				ivideo->CRT2LCDType = LCD_320x240;
2936			}
2937		}
2938	}
2939
2940	if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
2941		/* For broken BIOSes: Assume 1024x768, RGB18 */
2942		ivideo->CRT2LCDType = LCD_1024x768;
2943		setSISIDXREG(SISCR,0x36,0xf0,0x02);
2944		setSISIDXREG(SISCR,0x37,0xee,0x01);
2945		printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
2946	}
2947
2948	for(i = 0; i < SIS_LCD_NUMBER; i++) {
2949		if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
2950			ivideo->lcdxres = sis_lcd_data[i].xres;
2951			ivideo->lcdyres = sis_lcd_data[i].yres;
2952			ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
2953			break;
2954		}
2955	}
2956
2957#ifdef CONFIG_FB_SIS_300
2958	if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
2959		ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
2960		ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
2961	} else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
2962		ivideo->lcdxres =  848; ivideo->lcdyres =  480;
2963		ivideo->lcddefmodeidx = DEFAULT_MODE_848;
2964	} else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
2965		ivideo->lcdxres =  856; ivideo->lcdyres =  480;
2966		ivideo->lcddefmodeidx = DEFAULT_MODE_856;
2967	}
2968#endif
2969
2970	printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
2971			ivideo->lcdxres, ivideo->lcdyres);
2972}
2973
2974static void __devinit
2975sisfb_save_pdc_emi(struct sis_video_info *ivideo)
2976{
2977#ifdef CONFIG_FB_SIS_300
2978	/* Save the current PanelDelayCompensation if the LCD is currently used */
2979	if(ivideo->sisvga_engine == SIS_300_VGA) {
2980		if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
2981			int tmp;
2982			inSISIDXREG(SISCR,0x30,tmp);
2983			if(tmp & 0x20) {
2984				/* Currently on LCD? If yes, read current pdc */
2985				inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
2986				ivideo->detectedpdc &= 0x3c;
2987				if(ivideo->SiS_Pr.PDC == -1) {
2988					/* Let option override detection */
2989					ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
2990				}
2991				printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
2992					ivideo->detectedpdc);
2993			}
2994			if((ivideo->SiS_Pr.PDC != -1) &&
2995			   (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
2996				printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
2997					ivideo->SiS_Pr.PDC);
2998			}
2999		}
3000	}
3001#endif
3002
3003#ifdef CONFIG_FB_SIS_315
3004	if(ivideo->sisvga_engine == SIS_315_VGA) {
3005
3006		/* Try to find about LCDA */
3007		if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3008			int tmp;
3009			inSISIDXREG(SISPART1,0x13,tmp);
3010			if(tmp & 0x04) {
3011				ivideo->SiS_Pr.SiS_UseLCDA = true;
3012				ivideo->detectedlcda = 0x03;
3013			}
3014		}
3015
3016		/* Save PDC */
3017		if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3018			int tmp;
3019			inSISIDXREG(SISCR,0x30,tmp);
3020			if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3021				/* Currently on LCD? If yes, read current pdc */
3022				u8 pdc;
3023				inSISIDXREG(SISPART1,0x2D,pdc);
3024				ivideo->detectedpdc  = (pdc & 0x0f) << 1;
3025				ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3026				inSISIDXREG(SISPART1,0x35,pdc);
3027				ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3028				inSISIDXREG(SISPART1,0x20,pdc);
3029				ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3030				if(ivideo->newrom) {
3031					/* New ROM invalidates other PDC resp. */
3032					if(ivideo->detectedlcda != 0xff) {
3033						ivideo->detectedpdc = 0xff;
3034					} else {
3035						ivideo->detectedpdca = 0xff;
3036					}
3037				}
3038				if(ivideo->SiS_Pr.PDC == -1) {
3039					if(ivideo->detectedpdc != 0xff) {
3040						ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3041					}
3042				}
3043				if(ivideo->SiS_Pr.PDCA == -1) {
3044					if(ivideo->detectedpdca != 0xff) {
3045						ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3046					}
3047				}
3048				if(ivideo->detectedpdc != 0xff) {
3049					printk(KERN_INFO
3050						"sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3051						ivideo->detectedpdc);
3052				}
3053				if(ivideo->detectedpdca != 0xff) {
3054					printk(KERN_INFO
3055						"sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3056						ivideo->detectedpdca);
3057				}
3058			}
3059
3060			/* Save EMI */
3061			if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3062				inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3063				inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3064				inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3065				inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
3066				ivideo->SiS_Pr.HaveEMI = true;
3067				if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3068					ivideo->SiS_Pr.HaveEMILCD = true;
3069				}
3070			}
3071		}
3072
3073		/* Let user override detected PDCs (all bridges) */
3074		if(ivideo->vbflags2 & VB2_30xBLV) {
3075			if((ivideo->SiS_Pr.PDC != -1) &&
3076			   (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3077				printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3078					ivideo->SiS_Pr.PDC);
3079			}
3080			if((ivideo->SiS_Pr.PDCA != -1) &&
3081			   (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3082				printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3083				 ivideo->SiS_Pr.PDCA);
3084			}
3085		}
3086
3087	}
3088#endif
3089}
3090
3091/* -------------------- Memory manager routines ---------------------- */
3092
3093static u32 __devinit
3094sisfb_getheapstart(struct sis_video_info *ivideo)
3095{
3096	u32 ret = ivideo->sisfb_parm_mem * 1024;
3097	u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3098	u32 def;
3099
3100	/* Calculate heap start = end of memory for console
3101	 *
3102	 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3103	 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3104	 *
3105	 * On 76x in UMA+LFB mode, the layout is as follows:
3106	 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3107	 * where the heap is the entire UMA area, eventually
3108	 * into the LFB area if the given mem parameter is
3109	 * higher than the size of the UMA memory.
3110	 *
3111	 * Basically given by "mem" parameter
3112	 *
3113	 * maximum = videosize - cmd_queue - hwcursor
3114	 *           (results in a heap of size 0)
3115	 * default = SiS 300: depends on videosize
3116	 *           SiS 315/330/340/XGI: 32k below max
3117	 */
3118
3119	if(ivideo->sisvga_engine == SIS_300_VGA) {
3120		if(ivideo->video_size > 0x1000000) {
3121			def = 0xc00000;
3122		} else if(ivideo->video_size > 0x800000) {
3123			def = 0x800000;
3124		} else {
3125			def = 0x400000;
3126		}
3127	} else if(ivideo->UMAsize && ivideo->LFBsize) {
3128		ret = def = 0;
3129	} else {
3130		def = maxoffs - 0x8000;
3131	}
3132
3133	if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3134		ret = def;
3135
3136	return ret;
3137}
3138
3139static u32 __devinit
3140sisfb_getheapsize(struct sis_video_info *ivideo)
3141{
3142	u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3143	u32 ret = 0;
3144
3145	if(ivideo->UMAsize && ivideo->LFBsize) {
3146		if( (!ivideo->sisfb_parm_mem)			||
3147		    ((ivideo->sisfb_parm_mem * 1024) > max)	||
3148		    ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3149			ret = ivideo->UMAsize;
3150			max -= ivideo->UMAsize;
3151		} else {
3152			ret = max - (ivideo->sisfb_parm_mem * 1024);
3153			max = ivideo->sisfb_parm_mem * 1024;
3154		}
3155		ivideo->video_offset = ret;
3156		ivideo->sisfb_mem = max;
3157	} else {
3158		ret = max - ivideo->heapstart;
3159		ivideo->sisfb_mem = ivideo->heapstart;
3160	}
3161
3162	return ret;
3163}
3164
3165static int __devinit
3166sisfb_heap_init(struct sis_video_info *ivideo)
3167{
3168	struct SIS_OH *poh;
3169
3170	ivideo->video_offset = 0;
3171	if(ivideo->sisfb_parm_mem) {
3172		if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3173		    (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3174			ivideo->sisfb_parm_mem = 0;
3175		}
3176	}
3177
3178	ivideo->heapstart = sisfb_getheapstart(ivideo);
3179	ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
3180
3181	ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3182	ivideo->sisfb_heap_end   = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
3183
3184	printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3185		(int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3186
3187	ivideo->sisfb_heap.vinfo = ivideo;
3188
3189	ivideo->sisfb_heap.poha_chain = NULL;
3190	ivideo->sisfb_heap.poh_freelist = NULL;
3191
3192	poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3193	if(poh == NULL)
3194		return 1;
3195
3196	poh->poh_next = &ivideo->sisfb_heap.oh_free;
3197	poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3198	poh->size = ivideo->sisfb_heap_size;
3199	poh->offset = ivideo->heapstart;
3200
3201	ivideo->sisfb_heap.oh_free.poh_next = poh;
3202	ivideo->sisfb_heap.oh_free.poh_prev = poh;
3203	ivideo->sisfb_heap.oh_free.size = 0;
3204	ivideo->sisfb_heap.max_freesize = poh->size;
3205
3206	ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3207	ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3208	ivideo->sisfb_heap.oh_used.size = SENTINEL;
3209
3210	if(ivideo->cardnumber == 0) {
3211		/* For the first card, make this heap the "global" one
3212		 * for old DRM (which could handle only one card)
3213		 */
3214		sisfb_heap = &ivideo->sisfb_heap;
3215	}
3216
3217	return 0;
3218}
3219
3220static struct SIS_OH *
3221sisfb_poh_new_node(struct SIS_HEAP *memheap)
3222{
3223	struct SIS_OHALLOC	*poha;
3224	struct SIS_OH		*poh;
3225	unsigned long		cOhs;
3226	int			i;
3227
3228	if(memheap->poh_freelist == NULL) {
3229		poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3230		if(!poha)
3231			return NULL;
3232
3233		poha->poha_next = memheap->poha_chain;
3234		memheap->poha_chain = poha;
3235
3236		cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
3237
3238		poh = &poha->aoh[0];
3239		for(i = cOhs - 1; i != 0; i--) {
3240			poh->poh_next = poh + 1;
3241			poh = poh + 1;
3242		}
3243
3244		poh->poh_next = NULL;
3245		memheap->poh_freelist = &poha->aoh[0];
3246	}
3247
3248	poh = memheap->poh_freelist;
3249	memheap->poh_freelist = poh->poh_next;
3250
3251	return poh;
3252}
3253
3254static struct SIS_OH *
3255sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
3256{
3257	struct SIS_OH	*pohThis;
3258	struct SIS_OH	*pohRoot;
3259	int		bAllocated = 0;
3260
3261	if(size > memheap->max_freesize) {
3262		DPRINTK("sisfb: Can't allocate %dk video memory\n",
3263			(unsigned int) size / 1024);
3264		return NULL;
3265	}
3266
3267	pohThis = memheap->oh_free.poh_next;
3268
3269	while(pohThis != &memheap->oh_free) {
3270		if(size <= pohThis->size) {
3271			bAllocated = 1;
3272			break;
3273		}
3274		pohThis = pohThis->poh_next;
3275	}
3276
3277	if(!bAllocated) {
3278		DPRINTK("sisfb: Can't allocate %dk video memory\n",
3279			(unsigned int) size / 1024);
3280		return NULL;
3281	}
3282
3283	if(size == pohThis->size) {
3284		pohRoot = pohThis;
3285		sisfb_delete_node(pohThis);
3286	} else {
3287		pohRoot = sisfb_poh_new_node(memheap);
3288		if(pohRoot == NULL)
3289			return NULL;
3290
3291		pohRoot->offset = pohThis->offset;
3292		pohRoot->size = size;
3293
3294		pohThis->offset += size;
3295		pohThis->size -= size;
3296	}
3297
3298	memheap->max_freesize -= size;
3299
3300	pohThis = &memheap->oh_used;
3301	sisfb_insert_node(pohThis, pohRoot);
3302
3303	return pohRoot;
3304}
3305
3306static void
3307sisfb_delete_node(struct SIS_OH *poh)
3308{
3309	poh->poh_prev->poh_next = poh->poh_next;
3310	poh->poh_next->poh_prev = poh->poh_prev;
3311}
3312
3313static void
3314sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
3315{
3316	struct SIS_OH *pohTemp = pohList->poh_next;
3317
3318	pohList->poh_next = poh;
3319	pohTemp->poh_prev = poh;
3320
3321	poh->poh_prev = pohList;
3322	poh->poh_next = pohTemp;
3323}
3324
3325static struct SIS_OH *
3326sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
3327{
3328	struct SIS_OH *pohThis;
3329	struct SIS_OH *poh_freed;
3330	struct SIS_OH *poh_prev;
3331	struct SIS_OH *poh_next;
3332	u32    ulUpper;
3333	u32    ulLower;
3334	int    foundNode = 0;
3335
3336	poh_freed = memheap->oh_used.poh_next;
3337
3338	while(poh_freed != &memheap->oh_used) {
3339		if(poh_freed->offset == base) {
3340			foundNode = 1;
3341			break;
3342		}
3343
3344		poh_freed = poh_freed->poh_next;
3345	}
3346
3347	if(!foundNode)
3348		return NULL;
3349
3350	memheap->max_freesize += poh_freed->size;
3351
3352	poh_prev = poh_next = NULL;
3353	ulUpper = poh_freed->offset + poh_freed->size;
3354	ulLower = poh_freed->offset;
3355
3356	pohThis = memheap->oh_free.poh_next;
3357
3358	while(pohThis != &memheap->oh_free) {
3359		if(pohThis->offset == ulUpper) {
3360			poh_next = pohThis;
3361		} else if((pohThis->offset + pohThis->size) == ulLower) {
3362			poh_prev = pohThis;
3363		}
3364		pohThis = pohThis->poh_next;
3365	}
3366
3367	sisfb_delete_node(poh_freed);
3368
3369	if(poh_prev && poh_next) {
3370		poh_prev->size += (poh_freed->size + poh_next->size);
3371		sisfb_delete_node(poh_next);
3372		sisfb_free_node(memheap, poh_freed);
3373		sisfb_free_node(memheap, poh_next);
3374		return poh_prev;
3375	}
3376
3377	if(poh_prev) {
3378		poh_prev->size += poh_freed->size;
3379		sisfb_free_node(memheap, poh_freed);
3380		return poh_prev;
3381	}
3382
3383	if(poh_next) {
3384		poh_next->size += poh_freed->size;
3385		poh_next->offset = poh_freed->offset;
3386		sisfb_free_node(memheap, poh_freed);
3387		return poh_next;
3388	}
3389
3390	sisfb_insert_node(&memheap->oh_free, poh_freed);
3391
3392	return poh_freed;
3393}
3394
3395static void
3396sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
3397{
3398	if(poh == NULL)
3399		return;
3400
3401	poh->poh_next = memheap->poh_freelist;
3402	memheap->poh_freelist = poh;
3403}
3404
3405static void
3406sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3407{
3408	struct SIS_OH *poh = NULL;
3409
3410	if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3411		poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3412
3413	if(poh == NULL) {
3414		req->offset = req->size = 0;
3415		DPRINTK("sisfb: Video RAM allocation failed\n");
3416	} else {
3417		req->offset = poh->offset;
3418		req->size = poh->size;
3419		DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3420			(poh->offset + ivideo->video_vbase));
3421	}
3422}
3423
3424void
3425sis_malloc(struct sis_memreq *req)
3426{
3427	struct sis_video_info *ivideo = sisfb_heap->vinfo;
3428
3429	if(&ivideo->sisfb_heap == sisfb_heap)
3430		sis_int_malloc(ivideo, req);
3431	else
3432		req->offset = req->size = 0;
3433}
3434
3435void
3436sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3437{
3438	struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3439
3440	sis_int_malloc(ivideo, req);
3441}
3442
3443/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3444
3445static void
3446sis_int_free(struct sis_video_info *ivideo, u32 base)
3447{
3448	struct SIS_OH *poh;
3449
3450	if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3451		return;
3452
3453	poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
3454
3455	if(poh == NULL) {
3456		DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3457			(unsigned int) base);
3458	}
3459}
3460
3461void
3462sis_free(u32 base)
3463{
3464	struct sis_video_info *ivideo = sisfb_heap->vinfo;
3465
3466	sis_int_free(ivideo, base);
3467}
3468
3469void
3470sis_free_new(struct pci_dev *pdev, u32 base)
3471{
3472	struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3473
3474	sis_int_free(ivideo, base);
3475}
3476
3477/* --------------------- SetMode routines ------------------------- */
3478
3479static void
3480sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3481{
3482	u8 cr30, cr31;
3483
3484	/* Check if MMIO and engines are enabled,
3485	 * and sync in case they are. Can't use
3486	 * ivideo->accel here, as this might have
3487	 * been changed before this is called.
3488	 */
3489	inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3490	inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3491	/* MMIO and 2D/3D engine enabled? */
3492	if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3493#ifdef CONFIG_FB_SIS_300
3494		if(ivideo->sisvga_engine == SIS_300_VGA) {
3495			/* Don't care about TurboQueue. It's
3496			 * enough to know that the engines
3497			 * are enabled
3498			 */
3499			sisfb_syncaccel(ivideo);
3500		}
3501#endif
3502#ifdef CONFIG_FB_SIS_315
3503		if(ivideo->sisvga_engine == SIS_315_VGA) {
3504			/* Check that any queue mode is
3505			 * enabled, and that the queue
3506			 * is not in the state of "reset"
3507			 */
3508			inSISIDXREG(SISSR, 0x26, cr30);
3509			if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3510				sisfb_syncaccel(ivideo);
3511			}
3512		}
3513#endif
3514	}
3515}
3516
3517static void
3518sisfb_pre_setmode(struct sis_video_info *ivideo)
3519{
3520	u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3521	int tvregnum = 0;
3522
3523	ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3524
3525	outSISIDXREG(SISSR, 0x05, 0x86);
3526
3527	inSISIDXREG(SISCR, 0x31, cr31);
3528	cr31 &= ~0x60;
3529	cr31 |= 0x04;
3530
3531	cr33 = ivideo->rate_idx & 0x0F;
3532
3533#ifdef CONFIG_FB_SIS_315
3534	if(ivideo->sisvga_engine == SIS_315_VGA) {
3535	   if(ivideo->chip >= SIS_661) {
3536	      inSISIDXREG(SISCR, 0x38, cr38);
3537	      cr38 &= ~0x07;  /* Clear LCDA/DualEdge and YPbPr bits */
3538	   } else {
3539	      tvregnum = 0x38;
3540	      inSISIDXREG(SISCR, tvregnum, cr38);
3541	      cr38 &= ~0x3b;  /* Clear LCDA/DualEdge and YPbPr bits */
3542	   }
3543	}
3544#endif
3545#ifdef CONFIG_FB_SIS_300
3546	if(ivideo->sisvga_engine == SIS_300_VGA) {
3547	   tvregnum = 0x35;
3548	   inSISIDXREG(SISCR, tvregnum, cr38);
3549	}
3550#endif
3551
3552	SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
3553	SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
3554	ivideo->curFSTN = ivideo->curDSTN = 0;
3555
3556	switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3557
3558	   case CRT2_TV:
3559	      cr38 &= ~0xc0;   /* Clear PAL-M / PAL-N bits */
3560	      if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
3561#ifdef CONFIG_FB_SIS_315
3562		 if(ivideo->chip >= SIS_661) {
3563		    cr38 |= 0x04;
3564		    if(ivideo->vbflags & TV_YPBPR525P)       cr35 |= 0x20;
3565		    else if(ivideo->vbflags & TV_YPBPR750P)  cr35 |= 0x40;
3566		    else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3567		    cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3568		    cr35 &= ~0x01;
3569		    ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3570		 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3571		    cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3572		    cr38 |= 0x08;
3573		    if(ivideo->vbflags & TV_YPBPR525P)       cr38 |= 0x10;
3574		    else if(ivideo->vbflags & TV_YPBPR750P)  cr38 |= 0x20;
3575		    else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3576		    cr31 &= ~0x01;
3577		    ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3578		 }
3579#endif
3580	      } else if((ivideo->vbflags & TV_HIVISION) &&
3581				(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3582		 if(ivideo->chip >= SIS_661) {
3583		    cr38 |= 0x04;
3584		    cr35 |= 0x60;
3585		 } else {
3586		    cr30 |= 0x80;
3587		 }
3588		 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3589		 cr31 |= 0x01;
3590		 cr35 |= 0x01;
3591		 ivideo->currentvbflags |= TV_HIVISION;
3592	      } else if(ivideo->vbflags & TV_SCART) {
3593		 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3594		 cr31 |= 0x01;
3595		 cr35 |= 0x01;
3596		 ivideo->currentvbflags |= TV_SCART;
3597	      } else {
3598		 if(ivideo->vbflags & TV_SVIDEO) {
3599		    cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3600		    ivideo->currentvbflags |= TV_SVIDEO;
3601		 }
3602		 if(ivideo->vbflags & TV_AVIDEO) {
3603		    cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3604		    ivideo->currentvbflags |= TV_AVIDEO;
3605		 }
3606	      }
3607	      cr31 |= SIS_DRIVER_MODE;
3608
3609	      if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3610		 if(ivideo->vbflags & TV_PAL) {
3611		    cr31 |= 0x01; cr35 |= 0x01;
3612		    ivideo->currentvbflags |= TV_PAL;
3613		    if(ivideo->vbflags & TV_PALM) {
3614		       cr38 |= 0x40; cr35 |= 0x04;
3615		       ivideo->currentvbflags |= TV_PALM;
3616		    } else if(ivideo->vbflags & TV_PALN) {
3617		       cr38 |= 0x80; cr35 |= 0x08;
3618		       ivideo->currentvbflags |= TV_PALN;
3619		    }
3620		 } else {
3621		    cr31 &= ~0x01; cr35 &= ~0x01;
3622		    ivideo->currentvbflags |= TV_NTSC;
3623		    if(ivideo->vbflags & TV_NTSCJ) {
3624		       cr38 |= 0x40; cr35 |= 0x02;
3625		       ivideo->currentvbflags |= TV_NTSCJ;
3626		    }
3627		 }
3628	      }
3629	      break;
3630
3631	   case CRT2_LCD:
3632	      cr30  = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3633	      cr31 |= SIS_DRIVER_MODE;
3634	      SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3635	      SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
3636	      ivideo->curFSTN = ivideo->sisfb_fstn;
3637	      ivideo->curDSTN = ivideo->sisfb_dstn;
3638	      break;
3639
3640	   case CRT2_VGA:
3641	      cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3642	      cr31 |= SIS_DRIVER_MODE;
3643	      if(ivideo->sisfb_nocrt2rate) {
3644		 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3645	      } else {
3646		 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3647	      }
3648	      break;
3649
3650	   default:	/* disable CRT2 */
3651	      cr30 = 0x00;
3652	      cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3653	}
3654
3655	outSISIDXREG(SISCR, 0x30, cr30);
3656	outSISIDXREG(SISCR, 0x33, cr33);
3657
3658	if(ivideo->chip >= SIS_661) {
3659#ifdef CONFIG_FB_SIS_315
3660	   cr31 &= ~0x01;                          /* Clear PAL flag (now in CR35) */
3661	   setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3662	   cr38 &= 0x07;                           /* Use only LCDA and HiVision/YPbPr bits */
3663	   setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3664#endif
3665	} else if(ivideo->chip != SIS_300) {
3666	   outSISIDXREG(SISCR, tvregnum, cr38);
3667	}
3668	outSISIDXREG(SISCR, 0x31, cr31);
3669
3670	ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3671
3672	sisfb_check_engine_and_sync(ivideo);
3673}
3674
3675/* Fix SR11 for 661 and later */
3676#ifdef CONFIG_FB_SIS_315
3677static void
3678sisfb_fixup_SR11(struct sis_video_info *ivideo)
3679{
3680	u8  tmpreg;
3681
3682	if(ivideo->chip >= SIS_661) {
3683		inSISIDXREG(SISSR,0x11,tmpreg);
3684		if(tmpreg & 0x20) {
3685			inSISIDXREG(SISSR,0x3e,tmpreg);
3686			tmpreg = (tmpreg + 1) & 0xff;
3687			outSISIDXREG(SISSR,0x3e,tmpreg);
3688			inSISIDXREG(SISSR,0x11,tmpreg);
3689		}
3690		if(tmpreg & 0xf0) {
3691			andSISIDXREG(SISSR,0x11,0x0f);
3692		}
3693	}
3694}
3695#endif
3696
3697static void
3698sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3699{
3700	if(val > 32) val = 32;
3701	if(val < -32) val = -32;
3702	ivideo->tvxpos = val;
3703
3704	if(ivideo->sisfblocked) return;
3705	if(!ivideo->modechanged) return;
3706
3707	if(ivideo->currentvbflags & CRT2_TV) {
3708
3709		if(ivideo->vbflags2 & VB2_CHRONTEL) {
3710
3711			int x = ivideo->tvx;
3712
3713			switch(ivideo->chronteltype) {
3714			case 1:
3715				x += val;
3716				if(x < 0) x = 0;
3717				outSISIDXREG(SISSR,0x05,0x86);
3718				SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3719				SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3720				break;
3721			case 2:
3722				/* Not supported by hardware */
3723				break;
3724			}
3725
3726		} else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3727
3728			u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3729			unsigned short temp;
3730
3731			p2_1f = ivideo->p2_1f;
3732			p2_20 = ivideo->p2_20;
3733			p2_2b = ivideo->p2_2b;
3734			p2_42 = ivideo->p2_42;
3735			p2_43 = ivideo->p2_43;
3736
3737			temp = p2_1f | ((p2_20 & 0xf0) << 4);
3738			temp += (val * 2);
3739			p2_1f = temp & 0xff;
3740			p2_20 = (temp & 0xf00) >> 4;
3741			p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3742			temp = p2_43 | ((p2_42 & 0xf0) << 4);
3743			temp += (val * 2);
3744			p2_43 = temp & 0xff;
3745			p2_42 = (temp & 0xf00) >> 4;
3746			outSISIDXREG(SISPART2,0x1f,p2_1f);
3747			setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3748			setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3749			setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3750			outSISIDXREG(SISPART2,0x43,p2_43);
3751		}
3752	}
3753}
3754
3755static void
3756sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3757{
3758	if(val > 32) val = 32;
3759	if(val < -32) val = -32;
3760	ivideo->tvypos = val;
3761
3762	if(ivideo->sisfblocked) return;
3763	if(!ivideo->modechanged) return;
3764
3765	if(ivideo->currentvbflags & CRT2_TV) {
3766
3767		if(ivideo->vbflags2 & VB2_CHRONTEL) {
3768
3769			int y = ivideo->tvy;
3770
3771			switch(ivideo->chronteltype) {
3772			case 1:
3773				y -= val;
3774				if(y < 0) y = 0;
3775				outSISIDXREG(SISSR,0x05,0x86);
3776				SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3777				SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3778				break;
3779			case 2:
3780				/* Not supported by hardware */
3781				break;
3782			}
3783
3784		} else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3785
3786			char p2_01, p2_02;
3787			val /= 2;
3788			p2_01 = ivideo->p2_01;
3789			p2_02 = ivideo->p2_02;
3790
3791			p2_01 += val;
3792			p2_02 += val;
3793			if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3794				while((p2_01 <= 0) || (p2_02 <= 0)) {
3795					p2_01 += 2;
3796					p2_02 += 2;
3797				}
3798			}
3799			outSISIDXREG(SISPART2,0x01,p2_01);
3800			outSISIDXREG(SISPART2,0x02,p2_02);
3801		}
3802	}
3803}
3804
3805static void
3806sisfb_post_setmode(struct sis_video_info *ivideo)
3807{
3808	bool crt1isoff = false;
3809	bool doit = true;
3810#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3811	u8 reg;
3812#endif
3813#ifdef CONFIG_FB_SIS_315
3814	u8 reg1;
3815#endif
3816
3817	outSISIDXREG(SISSR, 0x05, 0x86);
3818
3819#ifdef CONFIG_FB_SIS_315
3820	sisfb_fixup_SR11(ivideo);
3821#endif
3822
3823	/* Now we actually HAVE changed the display mode */
3824	ivideo->modechanged = 1;
3825
3826	/* We can't switch off CRT1 if bridge is in slave mode */
3827	if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
3828		if(sisfb_bridgeisslave(ivideo)) doit = false;
3829	} else
3830		ivideo->sisfb_crt1off = 0;
3831
3832#ifdef CONFIG_FB_SIS_300
3833	if(ivideo->sisvga_engine == SIS_300_VGA) {
3834		if((ivideo->sisfb_crt1off) && (doit)) {
3835			crt1isoff = true;
3836			reg = 0x00;
3837		} else {
3838			crt1isoff = false;
3839			reg = 0x80;
3840		}
3841		setSISIDXREG(SISCR, 0x17, 0x7f, reg);
3842	}
3843#endif
3844#ifdef CONFIG_FB_SIS_315
3845	if(ivideo->sisvga_engine == SIS_315_VGA) {
3846		if((ivideo->sisfb_crt1off) && (doit)) {
3847			crt1isoff = true;
3848			reg  = 0x40;
3849			reg1 = 0xc0;
3850		} else {
3851			crt1isoff = false;
3852			reg  = 0x00;
3853			reg1 = 0x00;
3854		}
3855		setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3856		setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
3857	}
3858#endif
3859
3860	if(crt1isoff) {
3861		ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3862		ivideo->currentvbflags |= VB_SINGLE_MODE;
3863	} else {
3864		ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3865		if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3866			ivideo->currentvbflags |= VB_MIRROR_MODE;
3867		} else {
3868			ivideo->currentvbflags |= VB_SINGLE_MODE;
3869		}
3870	}
3871
3872	andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3873
3874	if(ivideo->currentvbflags & CRT2_TV) {
3875		if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3876			inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3877			inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3878			inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3879			inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3880			inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3881			inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3882			inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3883		} else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3884			if(ivideo->chronteltype == 1) {
3885				ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3886				ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3887				ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3888				ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3889			}
3890		}
3891	}
3892
3893	if(ivideo->tvxpos) {
3894		sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
3895	}
3896	if(ivideo->tvypos) {
3897		sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
3898	}
3899
3900	/* Eventually sync engines */
3901	sisfb_check_engine_and_sync(ivideo);
3902
3903	/* (Re-)Initialize chip engines */
3904	if(ivideo->accel) {
3905		sisfb_engine_init(ivideo);
3906	} else {
3907		ivideo->engineok = 0;
3908	}
3909}
3910
3911static int
3912sisfb_reset_mode(struct sis_video_info *ivideo)
3913{
3914	if(sisfb_set_mode(ivideo, 0))
3915		return 1;
3916
3917	sisfb_set_pitch(ivideo);
3918	sisfb_set_base_CRT1(ivideo, ivideo->current_base);
3919	sisfb_set_base_CRT2(ivideo, ivideo->current_base);
3920
3921	return 0;
3922}
3923
3924static void
3925sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
3926{
3927	int mycrt1off;
3928
3929	switch(sisfb_command->sisfb_cmd) {
3930	case SISFB_CMD_GETVBFLAGS:
3931		if(!ivideo->modechanged) {
3932			sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3933		} else {
3934			sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3935			sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
3936			sisfb_command->sisfb_result[2] = ivideo->vbflags2;
3937		}
3938		break;
3939	case SISFB_CMD_SWITCHCRT1:
3940		/* arg[0]: 0 = off, 1 = on, 99 = query */
3941		if(!ivideo->modechanged) {
3942			sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3943		} else if(sisfb_command->sisfb_arg[0] == 99) {
3944			/* Query */
3945			sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3946			sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3947		} else if(ivideo->sisfblocked) {
3948			sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
3949		} else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
3950					(sisfb_command->sisfb_arg[0] == 0)) {
3951			sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
3952		} else {
3953			sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3954			mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
3955			if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
3956			    ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
3957				ivideo->sisfb_crt1off = mycrt1off;
3958				if(sisfb_reset_mode(ivideo)) {
3959					sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
3960				}
3961			}
3962			sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3963		}
3964		break;
3965	/* more to come */
3966	default:
3967		sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
3968		printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
3969			sisfb_command->sisfb_cmd);
3970	}
3971}
3972
3973#ifndef MODULE
3974SISINITSTATIC int __init
3975sisfb_setup(char *options)
3976{
3977	char *this_opt;
3978
3979	sisfb_setdefaultparms();
3980
3981	if(!options || !(*options))
3982		return 0;
3983
3984	while((this_opt = strsep(&options, ",")) != NULL) {
3985
3986		if(!(*this_opt)) continue;
3987
3988		if(!strnicmp(this_opt, "off", 3)) {
3989			sisfb_off = 1;
3990		} else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
3991			/* Need to check crt2 type first for fstn/dstn */
3992			sisfb_search_crt2type(this_opt + 14);
3993		} else if(!strnicmp(this_opt, "tvmode:",7)) {
3994			sisfb_search_tvstd(this_opt + 7);
3995		} else if(!strnicmp(this_opt, "tvstandard:",11)) {
3996			sisfb_search_tvstd(this_opt + 11);
3997		} else if(!strnicmp(this_opt, "mode:", 5)) {
3998			sisfb_search_mode(this_opt + 5, false);
3999		} else if(!strnicmp(this_opt, "vesa:", 5)) {
4000			sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false);
4001		} else if(!strnicmp(this_opt, "rate:", 5)) {
4002			sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
4003		} else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
4004			sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
4005		} else if(!strnicmp(this_opt, "mem:",4)) {
4006			sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
4007		} else if(!strnicmp(this_opt, "pdc:", 4)) {
4008			sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
4009		} else if(!strnicmp(this_opt, "pdc1:", 5)) {
4010			sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
4011		} else if(!strnicmp(this_opt, "noaccel", 7)) {
4012			sisfb_accel = 0;
4013		} else if(!strnicmp(this_opt, "accel", 5)) {
4014			sisfb_accel = -1;
4015		} else if(!strnicmp(this_opt, "noypan", 6)) {
4016			sisfb_ypan = 0;
4017		} else if(!strnicmp(this_opt, "ypan", 4)) {
4018			sisfb_ypan = -1;
4019		} else if(!strnicmp(this_opt, "nomax", 5)) {
4020			sisfb_max = 0;
4021		} else if(!strnicmp(this_opt, "max", 3)) {
4022			sisfb_max = -1;
4023		} else if(!strnicmp(this_opt, "userom:", 7)) {
4024			sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4025		} else if(!strnicmp(this_opt, "useoem:", 7)) {
4026			sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4027		} else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4028			sisfb_nocrt2rate = 1;
4029		} else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4030			unsigned long temp = 2;
4031			temp = simple_strtoul(this_opt + 9, NULL, 0);
4032			if((temp == 0) || (temp == 1)) {
4033			   sisfb_scalelcd = temp ^ 1;
4034			}
4035		} else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
4036			int temp = 0;
4037			temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4038			if((temp >= -32) && (temp <= 32)) {
4039			   sisfb_tvxposoffset = temp;
4040			}
4041		} else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
4042			int temp = 0;
4043			temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4044			if((temp >= -32) && (temp <= 32)) {
4045			   sisfb_tvyposoffset = temp;
4046			}
4047		} else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4048			sisfb_search_specialtiming(this_opt + 14);
4049		} else if(!strnicmp(this_opt, "lvdshl:", 7)) {
4050			int temp = 4;
4051			temp = simple_strtoul(this_opt + 7, NULL, 0);
4052			if((temp >= 0) && (temp <= 3)) {
4053			   sisfb_lvdshl = temp;
4054			}
4055		} else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
4056			sisfb_search_mode(this_opt, true);
4057#if !defined(__i386__) && !defined(__x86_64__)
4058		} else if(!strnicmp(this_opt, "resetcard", 9)) {
4059			sisfb_resetcard = 1;
4060	        } else if(!strnicmp(this_opt, "videoram:", 9)) {
4061			sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
4062#endif
4063		} else {
4064			printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4065		}
4066
4067	}
4068
4069	return 0;
4070}
4071#endif
4072
4073static int __devinit
4074sisfb_check_rom(SIS_IOTYPE1 *rom_base, struct sis_video_info *ivideo)
4075{
4076	SIS_IOTYPE1 *rom;
4077	int romptr;
4078
4079	if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4080		return 0;
4081
4082	romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4083	if(romptr > (0x10000 - 8))
4084		return 0;
4085
4086	rom = rom_base + romptr;
4087
4088	if((readb(rom)     != 'P') || (readb(rom + 1) != 'C') ||
4089	   (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4090		return 0;
4091
4092	if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4093		return 0;
4094
4095	if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4096		return 0;
4097
4098	return 1;
4099}
4100
4101static unsigned char * __devinit
4102sisfb_find_rom(struct pci_dev *pdev)
4103{
4104	struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4105	SIS_IOTYPE1 *rom_base;
4106	unsigned char *myrombase = NULL;
4107	u32 temp;
4108#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
4109	size_t romsize;
4110
4111	/* First, try the official pci ROM functions (except
4112	 * on integrated chipsets which have no ROM).
4113	 */
4114
4115	if(!ivideo->nbridge) {
4116
4117		if((rom_base = pci_map_rom(pdev, &romsize))) {
4118
4119			if(sisfb_check_rom(rom_base, ivideo)) {
4120
4121				if((myrombase = vmalloc(65536))) {
4122
4123					if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4124						romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4125
4126					memcpy_fromio(myrombase, rom_base,
4127							(romsize > 65536) ? 65536 : romsize);
4128				}
4129			}
4130			pci_unmap_rom(pdev, rom_base);
4131		}
4132	}
4133
4134	if(myrombase) return myrombase;
4135#endif
4136
4137	/* Otherwise do it the conventional way. */
4138
4139#if defined(__i386__) || defined(__x86_64__)
4140
4141	for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
4142
4143		rom_base = ioremap(temp, 65536);
4144		if(!rom_base)
4145			continue;
4146
4147		if(!sisfb_check_rom(rom_base, ivideo)) {
4148			iounmap(rom_base);
4149			continue;
4150		}
4151
4152		if((myrombase = vmalloc(65536)))
4153			memcpy_fromio(myrombase, rom_base, 65536);
4154
4155		iounmap(rom_base);
4156		break;
4157
4158        }
4159
4160#else
4161
4162	pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4163	pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4164			(ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4165
4166	rom_base = ioremap(ivideo->video_base, 65536);
4167	if(rom_base) {
4168		if(sisfb_check_rom(rom_base, ivideo)) {
4169			if((myrombase = vmalloc(65536)))
4170				memcpy_fromio(myrombase, rom_base, 65536);
4171		}
4172		iounmap(rom_base);
4173	}
4174
4175	pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4176
4177#endif
4178
4179	return myrombase;
4180}
4181
4182static void __devinit
4183sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4184			unsigned int min)
4185{
4186	ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4187
4188	if(!ivideo->video_vbase) {
4189		printk(KERN_ERR
4190			"sisfb: Unable to map maximum video RAM for size detection\n");
4191		(*mapsize) >>= 1;
4192		while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4193			(*mapsize) >>= 1;
4194			if((*mapsize) < (min << 20))
4195				break;
4196		}
4197		if(ivideo->video_vbase) {
4198			printk(KERN_ERR
4199				"sisfb: Video RAM size detection limited to %dMB\n",
4200				(int)((*mapsize) >> 20));
4201		}
4202	}
4203}
4204
4205#ifdef CONFIG_FB_SIS_300
4206static int __devinit
4207sisfb_post_300_buswidth(struct sis_video_info *ivideo)
4208{
4209	SIS_IOTYPE1 *FBAddress = ivideo->video_vbase;
4210	unsigned short temp;
4211	unsigned char reg;
4212	int i, j;
4213
4214	andSISIDXREG(SISSR, 0x15, 0xFB);
4215	orSISIDXREG(SISSR, 0x15, 0x04);
4216	outSISIDXREG(SISSR, 0x13, 0x00);
4217	outSISIDXREG(SISSR, 0x14, 0xBF);
4218
4219	for(i = 0; i < 2; i++) {
4220		temp = 0x1234;
4221		for(j = 0; j < 4; j++) {
4222			writew(temp, FBAddress);
4223			if(readw(FBAddress) == temp)
4224				break;
4225			orSISIDXREG(SISSR, 0x3c, 0x01);
4226			inSISIDXREG(SISSR, 0x05, reg);
4227			inSISIDXREG(SISSR, 0x05, reg);
4228			andSISIDXREG(SISSR, 0x3c, 0xfe);
4229			inSISIDXREG(SISSR, 0x05, reg);
4230			inSISIDXREG(SISSR, 0x05, reg);
4231			temp++;
4232		}
4233	}
4234
4235	writel(0x01234567L, FBAddress);
4236	writel(0x456789ABL, (FBAddress + 4));
4237	writel(0x89ABCDEFL, (FBAddress + 8));
4238	writel(0xCDEF0123L, (FBAddress + 12));
4239
4240	inSISIDXREG(SISSR, 0x3b, reg);
4241	if(reg & 0x01) {
4242		if(readl((FBAddress + 12)) == 0xCDEF0123L)
4243			return 4;	/* Channel A 128bit */
4244	}
4245
4246	if(readl((FBAddress + 4)) == 0x456789ABL)
4247		return 2;		/* Channel B 64bit */
4248
4249	return 1;			/* 32bit */
4250}
4251
4252static int __devinit
4253sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4254			int PseudoRankCapacity, int PseudoAdrPinCount,
4255			unsigned int mapsize)
4256{
4257	SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
4258	unsigned short sr14;
4259	unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4260	unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4261	static const unsigned short SiS_DRAMType[17][5] = {
4262		{0x0C,0x0A,0x02,0x40,0x39},
4263		{0x0D,0x0A,0x01,0x40,0x48},
4264		{0x0C,0x09,0x02,0x20,0x35},
4265		{0x0D,0x09,0x01,0x20,0x44},
4266		{0x0C,0x08,0x02,0x10,0x31},
4267		{0x0D,0x08,0x01,0x10,0x40},
4268		{0x0C,0x0A,0x01,0x20,0x34},
4269		{0x0C,0x09,0x01,0x08,0x32},
4270		{0x0B,0x08,0x02,0x08,0x21},
4271		{0x0C,0x08,0x01,0x08,0x30},
4272		{0x0A,0x08,0x02,0x04,0x11},
4273		{0x0B,0x0A,0x01,0x10,0x28},
4274		{0x09,0x08,0x02,0x02,0x01},
4275		{0x0B,0x09,0x01,0x08,0x24},
4276		{0x0B,0x08,0x01,0x04,0x20},
4277		{0x0A,0x08,0x01,0x02,0x10},
4278		{0x09,0x08,0x01,0x01,0x00}
4279	};
4280
4281	 for(k = 0; k <= 16; k++) {
4282
4283		RankCapacity = buswidth * SiS_DRAMType[k][3];
4284
4285		if(RankCapacity != PseudoRankCapacity)
4286			continue;
4287
4288		if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4289			continue;
4290
4291		BankNumHigh = RankCapacity * 16 * iteration - 1;
4292		if(iteration == 3) {             /* Rank No */
4293			BankNumMid  = RankCapacity * 16 - 1;
4294		} else {
4295			BankNumMid  = RankCapacity * 16 * iteration / 2 - 1;
4296		}
4297
4298		PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4299		PhysicalAdrHigh = BankNumHigh;
4300		PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4301		PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4302
4303		andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4304		orSISIDXREG(SISSR, 0x15, 0x04);  /* Test */
4305		sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4306		if(buswidth == 4)      sr14 |= 0x80;
4307		else if(buswidth == 2) sr14 |= 0x40;
4308		outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4309		outSISIDXREG(SISSR, 0x14, sr14);
4310
4311		BankNumHigh <<= 16;
4312		BankNumMid <<= 16;
4313
4314		if((BankNumHigh + PhysicalAdrHigh      >= mapsize) ||
4315		   (BankNumMid  + PhysicalAdrHigh      >= mapsize) ||
4316		   (BankNumHigh + PhysicalAdrHalfPage  >= mapsize) ||
4317		   (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4318			continue;
4319
4320		/* Write data */
4321		writew(((unsigned short)PhysicalAdrHigh),
4322				(FBAddr + BankNumHigh + PhysicalAdrHigh));
4323		writew(((unsigned short)BankNumMid),
4324				(FBAddr + BankNumMid  + PhysicalAdrHigh));
4325		writew(((unsigned short)PhysicalAdrHalfPage),
4326				(FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4327		writew(((unsigned short)PhysicalAdrOtherPage),
4328				(FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4329
4330		/* Read data */
4331		if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4332			return 1;
4333	}
4334
4335	return 0;
4336}
4337
4338static void __devinit
4339sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
4340{
4341	struct	sis_video_info *ivideo = pci_get_drvdata(pdev);
4342	int	i, j, buswidth;
4343	int	PseudoRankCapacity, PseudoAdrPinCount;
4344
4345	buswidth = sisfb_post_300_buswidth(ivideo);
4346
4347	for(i = 6; i >= 0; i--) {
4348		PseudoRankCapacity = 1 << i;
4349		for(j = 4; j >= 1; j--) {
4350			PseudoAdrPinCount = 15 - j;
4351			if((PseudoRankCapacity * j) <= 64) {
4352				if(sisfb_post_300_rwtest(ivideo,
4353						j,
4354						buswidth,
4355						PseudoRankCapacity,
4356						PseudoAdrPinCount,
4357						mapsize))
4358					return;
4359			}
4360		}
4361	}
4362}
4363
4364static void __devinit
4365sisfb_post_sis300(struct pci_dev *pdev)
4366{
4367	struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4368	unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
4369	u8  reg, v1, v2, v3, v4, v5, v6, v7, v8;
4370	u16 index, rindex, memtype = 0;
4371	unsigned int mapsize;
4372
4373	if(!ivideo->SiS_Pr.UseROM)
4374		bios = NULL;
4375
4376	outSISIDXREG(SISSR, 0x05, 0x86);
4377
4378	if(bios) {
4379		if(bios[0x52] & 0x80) {
4380			memtype = bios[0x52];
4381		} else {
4382			inSISIDXREG(SISSR, 0x3a, memtype);
4383		}
4384		memtype &= 0x07;
4385	}
4386
4387	v3 = 0x80; v6 = 0x80;
4388	if(ivideo->revision_id <= 0x13) {
4389		v1 = 0x44; v2 = 0x42;
4390		v4 = 0x44; v5 = 0x42;
4391	} else {
4392		v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4393		v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4394		if(bios) {
4395			index = memtype * 5;
4396			rindex = index + 0x54;
4397			v1 = bios[rindex++];
4398			v2 = bios[rindex++];
4399			v3 = bios[rindex++];
4400			rindex = index + 0x7c;
4401			v4 = bios[rindex++];
4402			v5 = bios[rindex++];
4403			v6 = bios[rindex++];
4404		}
4405	}
4406	outSISIDXREG(SISSR, 0x28, v1);
4407	outSISIDXREG(SISSR, 0x29, v2);
4408	outSISIDXREG(SISSR, 0x2a, v3);
4409	outSISIDXREG(SISSR, 0x2e, v4);
4410	outSISIDXREG(SISSR, 0x2f, v5);
4411	outSISIDXREG(SISSR, 0x30, v6);
4412
4413	v1 = 0x10;
4414	if(bios)
4415		v1 = bios[0xa4];
4416	outSISIDXREG(SISSR, 0x07, v1);       /* DAC speed */
4417
4418	outSISIDXREG(SISSR, 0x11, 0x0f);     /* DDC, power save */
4419
4420	v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4421	v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4422	if(bios) {
4423		memtype += 0xa5;
4424		v1 = bios[memtype];
4425		v2 = bios[memtype + 8];
4426		v3 = bios[memtype + 16];
4427		v4 = bios[memtype + 24];
4428		v5 = bios[memtype + 32];
4429		v6 = bios[memtype + 40];
4430		v7 = bios[memtype + 48];
4431		v8 = bios[memtype + 56];
4432	}
4433	if(ivideo->revision_id >= 0x80)
4434		v3 &= 0xfd;
4435	outSISIDXREG(SISSR, 0x15, v1);       /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4436	outSISIDXREG(SISSR, 0x16, v2);
4437	outSISIDXREG(SISSR, 0x17, v3);
4438	outSISIDXREG(SISSR, 0x18, v4);
4439	outSISIDXREG(SISSR, 0x19, v5);
4440	outSISIDXREG(SISSR, 0x1a, v6);
4441	outSISIDXREG(SISSR, 0x1b, v7);
4442	outSISIDXREG(SISSR, 0x1c, v8);	   /* ---- */
4443	andSISIDXREG(SISSR, 0x15 ,0xfb);
4444	orSISIDXREG(SISSR, 0x15, 0x04);
4445	if(bios) {
4446		if(bios[0x53] & 0x02) {
4447			orSISIDXREG(SISSR, 0x19, 0x20);
4448		}
4449	}
4450	v1 = 0x04;			   /* DAC pedestal (BIOS 0xe5) */
4451	if(ivideo->revision_id >= 0x80)
4452		v1 |= 0x01;
4453	outSISIDXREG(SISSR, 0x1f, v1);
4454	outSISIDXREG(SISSR, 0x20, 0xa4);     /* linear & relocated io & disable a0000 */
4455	v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4456	if(bios) {
4457		v1 = bios[0xe8];
4458		v2 = bios[0xe9];
4459		v3 = bios[0xea];
4460	}
4461	outSISIDXREG(SISSR, 0x23, v1);
4462	outSISIDXREG(SISSR, 0x24, v2);
4463	outSISIDXREG(SISSR, 0x25, v3);
4464	outSISIDXREG(SISSR, 0x21, 0x84);
4465	outSISIDXREG(SISSR, 0x22, 0x00);
4466	outSISIDXREG(SISCR, 0x37, 0x00);
4467	orSISIDXREG(SISPART1, 0x24, 0x01);   /* unlock crt2 */
4468	outSISIDXREG(SISPART1, 0x00, 0x00);
4469	v1 = 0x40; v2 = 0x11;
4470	if(bios) {
4471		v1 = bios[0xec];
4472		v2 = bios[0xeb];
4473	}
4474	outSISIDXREG(SISPART1, 0x02, v1);
4475
4476	if(ivideo->revision_id >= 0x80)
4477		v2 &= ~0x01;
4478
4479	inSISIDXREG(SISPART4, 0x00, reg);
4480	if((reg == 1) || (reg == 2)) {
4481		outSISIDXREG(SISCR, 0x37, 0x02);
4482		outSISIDXREG(SISPART2, 0x00, 0x1c);
4483		v4 = 0x00; v5 = 0x00; v6 = 0x10;
4484		if(ivideo->SiS_Pr.UseROM) {
4485			v4 = bios[0xf5];
4486			v5 = bios[0xf6];
4487			v6 = bios[0xf7];
4488		}
4489		outSISIDXREG(SISPART4, 0x0d, v4);
4490		outSISIDXREG(SISPART4, 0x0e, v5);
4491		outSISIDXREG(SISPART4, 0x10, v6);
4492		outSISIDXREG(SISPART4, 0x0f, 0x3f);
4493		inSISIDXREG(SISPART4, 0x01, reg);
4494		if(reg >= 0xb0) {
4495			inSISIDXREG(SISPART4, 0x23, reg);
4496			reg &= 0x20;
4497			reg <<= 1;
4498			outSISIDXREG(SISPART4, 0x23, reg);
4499		}
4500	} else {
4501		v2 &= ~0x10;
4502	}
4503	outSISIDXREG(SISSR, 0x32, v2);
4504
4505	andSISIDXREG(SISPART1, 0x24, 0xfe);  /* Lock CRT2 */
4506
4507	inSISIDXREG(SISSR, 0x16, reg);
4508	reg &= 0xc3;
4509	outSISIDXREG(SISCR, 0x35, reg);
4510	outSISIDXREG(SISCR, 0x83, 0x00);
4511#if !defined(__i386__) && !defined(__x86_64__)
4512	if(sisfb_videoram) {
4513		outSISIDXREG(SISSR, 0x13, 0x28);  /* ? */
4514		reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4515		outSISIDXREG(SISSR, 0x14, reg);
4516	} else {
4517#endif
4518		/* Need to map max FB size for finding out about RAM size */
4519		mapsize = 64 << 20;
4520		sisfb_post_map_vram(ivideo, &mapsize, 4);
4521
4522		if(ivideo->video_vbase) {
4523			sisfb_post_300_ramsize(pdev, mapsize);
4524			iounmap(ivideo->video_vbase);
4525		} else {
4526			printk(KERN_DEBUG
4527				"sisfb: Failed to map memory for size detection, assuming 8MB\n");
4528			outSISIDXREG(SISSR, 0x13, 0x28);  /* ? */
4529			outSISIDXREG(SISSR, 0x14, 0x47);  /* 8MB, 64bit default */
4530		}
4531#if !defined(__i386__) && !defined(__x86_64__)
4532	}
4533#endif
4534	if(bios) {
4535		v1 = bios[0xe6];
4536		v2 = bios[0xe7];
4537	} else {
4538		inSISIDXREG(SISSR, 0x3a, reg);
4539		if((reg & 0x30) == 0x30) {
4540			v1 = 0x04; /* PCI */
4541			v2 = 0x92;
4542		} else {
4543			v1 = 0x14; /* AGP */
4544			v2 = 0xb2;
4545		}
4546	}
4547	outSISIDXREG(SISSR, 0x21, v1);
4548	outSISIDXREG(SISSR, 0x22, v2);
4549
4550	/* Sense CRT1 */
4551	sisfb_sense_crt1(ivideo);
4552
4553	/* Set default mode, don't clear screen */
4554	ivideo->SiS_Pr.SiS_UseOEM = false;
4555	SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
4556	SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
4557	ivideo->curFSTN = ivideo->curDSTN = 0;
4558	ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4559	SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4560
4561	outSISIDXREG(SISSR, 0x05, 0x86);
4562
4563	/* Display off */
4564	orSISIDXREG(SISSR, 0x01, 0x20);
4565
4566	/* Save mode number in CR34 */
4567	outSISIDXREG(SISCR, 0x34, 0x2e);
4568
4569	/* Let everyone know what the current mode is */
4570	ivideo->modeprechange = 0x2e;
4571}
4572#endif
4573
4574#ifdef CONFIG_FB_SIS_315
4575
4576static void __devinit
4577sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
4578{
4579	unsigned int i;
4580	u8 reg;
4581
4582	for(i = 0; i <= (delay * 10 * 36); i++) {
4583		inSISIDXREG(SISSR, 0x05, reg);
4584		reg++;
4585	}
4586}
4587
4588static int __devinit
4589sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4590				unsigned short pcivendor)
4591{
4592	struct pci_dev *pdev = NULL;
4593	unsigned short temp;
4594	int ret = 0;
4595
4596	while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
4597		temp = pdev->vendor;
4598		pci_dev_put(pdev);
4599		if(temp == pcivendor) {
4600			ret = 1;
4601			break;
4602		}
4603	}
4604
4605	return ret;
4606}
4607
4608static int __devinit
4609sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4610			unsigned int enda, unsigned int mapsize)
4611{
4612	unsigned int pos;
4613	int i;
4614
4615	writel(0, ivideo->video_vbase);
4616
4617	for(i = starta; i <= enda; i++) {
4618		pos = 1 << i;
4619		if(pos < mapsize)
4620			writel(pos, ivideo->video_vbase + pos);
4621	}
4622
4623	sisfb_post_xgi_delay(ivideo, 150);
4624
4625	if(readl(ivideo->video_vbase) != 0)
4626		return 0;
4627
4628	for(i = starta; i <= enda; i++) {
4629		pos = 1 << i;
4630		if(pos < mapsize) {
4631			if(readl(ivideo->video_vbase + pos) != pos)
4632				return 0;
4633		} else
4634			return 0;
4635	}
4636
4637	return 1;
4638}
4639
4640static void __devinit
4641sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4642{
4643	unsigned int buswidth, ranksize, channelab, mapsize;
4644	int i, j, k, l;
4645	u8 reg, sr14;
4646	static const u8 dramsr13[12 * 5] = {
4647		0x02, 0x0e, 0x0b, 0x80, 0x5d,
4648		0x02, 0x0e, 0x0a, 0x40, 0x59,
4649		0x02, 0x0d, 0x0b, 0x40, 0x4d,
4650		0x02, 0x0e, 0x09, 0x20, 0x55,
4651		0x02, 0x0d, 0x0a, 0x20, 0x49,
4652		0x02, 0x0c, 0x0b, 0x20, 0x3d,
4653		0x02, 0x0e, 0x08, 0x10, 0x51,
4654		0x02, 0x0d, 0x09, 0x10, 0x45,
4655		0x02, 0x0c, 0x0a, 0x10, 0x39,
4656		0x02, 0x0d, 0x08, 0x08, 0x41,
4657		0x02, 0x0c, 0x09, 0x08, 0x35,
4658		0x02, 0x0c, 0x08, 0x04, 0x31
4659	};
4660	static const u8 dramsr13_4[4 * 5] = {
4661		0x02, 0x0d, 0x09, 0x40, 0x45,
4662		0x02, 0x0c, 0x09, 0x20, 0x35,
4663		0x02, 0x0c, 0x08, 0x10, 0x31,
4664		0x02, 0x0b, 0x08, 0x08, 0x21
4665	};
4666
4667	/* Enable linear mode, disable 0xa0000 address decoding */
4668	/* We disable a0000 address decoding, because
4669	 * - if running on x86, if the card is disabled, it means
4670	 *   that another card is in the system. We don't want
4671	 *   to interphere with that primary card's textmode.
4672	 * - if running on non-x86, there usually is no VGA window
4673	 *   at a0000.
4674	 */
4675	orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4676
4677	/* Need to map max FB size for finding out about RAM size */
4678	mapsize = 256 << 20;
4679	sisfb_post_map_vram(ivideo, &mapsize, 32);
4680
4681	if(!ivideo->video_vbase) {
4682		printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4683		outSISIDXREG(SISSR, 0x13, 0x35);
4684		outSISIDXREG(SISSR, 0x14, 0x41);
4685		/* TODO */
4686		return;
4687	}
4688
4689	/* Non-interleaving */
4690	outSISIDXREG(SISSR, 0x15, 0x00);
4691	/* No tiling */
4692	outSISIDXREG(SISSR, 0x1c, 0x00);
4693
4694	if(ivideo->chip == XGI_20) {
4695
4696		channelab = 1;
4697		inSISIDXREG(SISCR, 0x97, reg);
4698		if(!(reg & 0x01)) {	/* Single 32/16 */
4699			buswidth = 32;
4700			outSISIDXREG(SISSR, 0x13, 0xb1);
4701			outSISIDXREG(SISSR, 0x14, 0x52);
4702			sisfb_post_xgi_delay(ivideo, 1);
4703			sr14 = 0x02;
4704			if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4705				goto bail_out;
4706
4707			outSISIDXREG(SISSR, 0x13, 0x31);
4708			outSISIDXREG(SISSR, 0x14, 0x42);
4709			sisfb_post_xgi_delay(ivideo, 1);
4710			if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4711				goto bail_out;
4712
4713			buswidth = 16;
4714			outSISIDXREG(SISSR, 0x13, 0xb1);
4715			outSISIDXREG(SISSR, 0x14, 0x41);
4716			sisfb_post_xgi_delay(ivideo, 1);
4717			sr14 = 0x01;
4718			if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4719				goto bail_out;
4720			else
4721				outSISIDXREG(SISSR, 0x13, 0x31);
4722		} else {		/* Dual 16/8 */
4723			buswidth = 16;
4724			outSISIDXREG(SISSR, 0x13, 0xb1);
4725			outSISIDXREG(SISSR, 0x14, 0x41);
4726			sisfb_post_xgi_delay(ivideo, 1);
4727			sr14 = 0x01;
4728			if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4729				goto bail_out;
4730
4731			outSISIDXREG(SISSR, 0x13, 0x31);
4732			outSISIDXREG(SISSR, 0x14, 0x31);
4733			sisfb_post_xgi_delay(ivideo, 1);
4734			if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4735				goto bail_out;
4736
4737			buswidth = 8;
4738			outSISIDXREG(SISSR, 0x13, 0xb1);
4739			outSISIDXREG(SISSR, 0x14, 0x30);
4740			sisfb_post_xgi_delay(ivideo, 1);
4741			sr14 = 0x00;
4742			if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4743				goto bail_out;
4744			else
4745				outSISIDXREG(SISSR, 0x13, 0x31);
4746		}
4747
4748	} else {	/* XGI_40 */
4749
4750		inSISIDXREG(SISCR, 0x97, reg);
4751		if(!(reg & 0x10)) {
4752			inSISIDXREG(SISSR, 0x39, reg);
4753			reg >>= 1;
4754		}
4755
4756		if(reg & 0x01) {	/* DDRII */
4757			buswidth = 32;
4758			if(ivideo->revision_id == 2) {
4759				channelab = 2;
4760				outSISIDXREG(SISSR, 0x13, 0xa1);
4761				outSISIDXREG(SISSR, 0x14, 0x44);
4762				sr14 = 0x04;
4763				sisfb_post_xgi_delay(ivideo, 1);
4764				if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4765					goto bail_out;
4766
4767				outSISIDXREG(SISSR, 0x13, 0x21);
4768				outSISIDXREG(SISSR, 0x14, 0x34);
4769				if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4770					goto bail_out;
4771
4772				channelab = 1;
4773				outSISIDXREG(SISSR, 0x13, 0xa1);
4774				outSISIDXREG(SISSR, 0x14, 0x40);
4775				sr14 = 0x00;
4776				if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4777					goto bail_out;
4778
4779				outSISIDXREG(SISSR, 0x13, 0x21);
4780				outSISIDXREG(SISSR, 0x14, 0x30);
4781			} else {
4782				channelab = 3;
4783				outSISIDXREG(SISSR, 0x13, 0xa1);
4784				outSISIDXREG(SISSR, 0x14, 0x4c);
4785				sr14 = 0x0c;
4786				sisfb_post_xgi_delay(ivideo, 1);
4787				if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4788					goto bail_out;
4789
4790				channelab = 2;
4791				outSISIDXREG(SISSR, 0x14, 0x48);
4792				sisfb_post_xgi_delay(ivideo, 1);
4793				sr14 = 0x08;
4794				if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4795					goto bail_out;
4796
4797				outSISIDXREG(SISSR, 0x13, 0x21);
4798				outSISIDXREG(SISSR, 0x14, 0x3c);
4799				sr14 = 0x0c;
4800
4801				if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4802					channelab = 3;
4803				} else {
4804					channelab = 2;
4805					outSISIDXREG(SISSR, 0x14, 0x38);
4806					sr14 = 0x08;
4807				}
4808			}
4809			sisfb_post_xgi_delay(ivideo, 1);
4810
4811		} else {	/* DDR */
4812
4813			buswidth = 64;
4814			if(ivideo->revision_id == 2) {
4815				channelab = 1;
4816				outSISIDXREG(SISSR, 0x13, 0xa1);
4817				outSISIDXREG(SISSR, 0x14, 0x52);
4818				sisfb_post_xgi_delay(ivideo, 1);
4819				sr14 = 0x02;
4820				if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4821					goto bail_out;
4822
4823				outSISIDXREG(SISSR, 0x13, 0x21);
4824				outSISIDXREG(SISSR, 0x14, 0x42);
4825			} else {
4826				channelab = 2;
4827				outSISIDXREG(SISSR, 0x13, 0xa1);
4828				outSISIDXREG(SISSR, 0x14, 0x5a);
4829				sisfb_post_xgi_delay(ivideo, 1);
4830				sr14 = 0x0a;
4831				if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4832					goto bail_out;
4833
4834				outSISIDXREG(SISSR, 0x13, 0x21);
4835				outSISIDXREG(SISSR, 0x14, 0x4a);
4836			}
4837			sisfb_post_xgi_delay(ivideo, 1);
4838
4839		}
4840	}
4841
4842bail_out:
4843	setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4844	sisfb_post_xgi_delay(ivideo, 1);
4845
4846	j = (ivideo->chip == XGI_20) ? 5 : 9;
4847	k = (ivideo->chip == XGI_20) ? 12 : 4;
4848
4849	for(i = 0; i < k; i++) {
4850
4851		reg = (ivideo->chip == XGI_20) ?
4852				dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4853		setSISIDXREG(SISSR, 0x13, 0x80, reg);
4854		sisfb_post_xgi_delay(ivideo, 50);
4855
4856		ranksize = (ivideo->chip == XGI_20) ?
4857				dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4858
4859		inSISIDXREG(SISSR, 0x13, reg);
4860		if(reg & 0x80) ranksize <<= 1;
4861
4862		if(ivideo->chip == XGI_20) {
4863			if(buswidth == 16)      ranksize <<= 1;
4864			else if(buswidth == 32) ranksize <<= 2;
4865		} else {
4866			if(buswidth == 64)      ranksize <<= 1;
4867		}
4868
4869		reg = 0;
4870		l = channelab;
4871		if(l == 3) l = 4;
4872		if((ranksize * l) <= 256) {
4873			while((ranksize >>= 1)) reg += 0x10;
4874		}
4875
4876		if(!reg) continue;
4877
4878		setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
4879		sisfb_post_xgi_delay(ivideo, 1);
4880
4881		if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
4882			break;
4883	}
4884
4885	iounmap(ivideo->video_vbase);
4886}
4887
4888static void __devinit
4889sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
4890{
4891	u8 v1, v2, v3;
4892	int index;
4893	static const u8 cs90[8 * 3] = {
4894		0x16, 0x01, 0x01,
4895		0x3e, 0x03, 0x01,
4896		0x7c, 0x08, 0x01,
4897		0x79, 0x06, 0x01,
4898		0x29, 0x01, 0x81,
4899		0x5c, 0x23, 0x01,
4900		0x5c, 0x23, 0x01,
4901		0x5c, 0x23, 0x01
4902	};
4903	static const u8 csb8[8 * 3] = {
4904		0x5c, 0x23, 0x01,
4905		0x29, 0x01, 0x01,
4906		0x7c, 0x08, 0x01,
4907		0x79, 0x06, 0x01,
4908		0x29, 0x01, 0x81,
4909		0x5c, 0x23, 0x01,
4910		0x5c, 0x23, 0x01,
4911		0x5c, 0x23, 0x01
4912	};
4913
4914	regb = 0;  /* ! */
4915
4916	index = regb * 3;
4917	v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
4918	if(ivideo->haveXGIROM) {
4919		v1 = ivideo->bios_abase[0x90 + index];
4920		v2 = ivideo->bios_abase[0x90 + index + 1];
4921		v3 = ivideo->bios_abase[0x90 + index + 2];
4922	}
4923	outSISIDXREG(SISSR, 0x28, v1);
4924	outSISIDXREG(SISSR, 0x29, v2);
4925	outSISIDXREG(SISSR, 0x2a, v3);
4926	sisfb_post_xgi_delay(ivideo, 0x43);
4927	sisfb_post_xgi_delay(ivideo, 0x43);
4928	sisfb_post_xgi_delay(ivideo, 0x43);
4929	index = regb * 3;
4930	v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
4931	if(ivideo->haveXGIROM) {
4932		v1 = ivideo->bios_abase[0xb8 + index];
4933		v2 = ivideo->bios_abase[0xb8 + index + 1];
4934		v3 = ivideo->bios_abase[0xb8 + index + 2];
4935	}
4936	outSISIDXREG(SISSR, 0x2e, v1);
4937	outSISIDXREG(SISSR, 0x2f, v2);
4938	outSISIDXREG(SISSR, 0x30, v3);
4939	sisfb_post_xgi_delay(ivideo, 0x43);
4940	sisfb_post_xgi_delay(ivideo, 0x43);
4941	sisfb_post_xgi_delay(ivideo, 0x43);
4942}
4943
4944static int __devinit
4945sisfb_post_xgi(struct pci_dev *pdev)
4946{
4947	struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4948	unsigned char *bios = ivideo->bios_abase;
4949	struct pci_dev *mypdev = NULL;
4950	const u8 *ptr, *ptr2;
4951	u8 v1, v2, v3, v4, v5, reg, ramtype;
4952	u32 rega, regb, regd;
4953	int i, j, k, index;
4954	static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
4955	static const u8 cs76[2] = { 0xa3, 0xfb };
4956	static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
4957	static const u8 cs158[8] = {
4958		0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
4959	};
4960	static const u8 cs160[8] = {
4961		0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
4962	};
4963	static const u8 cs168[8] = {
4964		0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
4965	};
4966	static const u8 cs128[3 * 8] = {
4967		0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
4968		0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4969		0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
4970	};
4971	static const u8 cs148[2 * 8] = {
4972		0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
4973		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4974	};
4975	static const u8 cs31a[8 * 4] = {
4976		0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
4977		0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
4978		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4979		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4980	};
4981	static const u8 cs33a[8 * 4] = {
4982		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4983		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4984		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4985		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4986	};
4987	static const u8 cs45a[8 * 2] = {
4988		0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
4989		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4990	};
4991	static const u8 cs170[7 * 8] = {
4992		0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4993		0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4994		0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
4995		0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4996		0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
4997		0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
4998		0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
4999	};
5000	static const u8 cs1a8[3 * 8] = {
5001		0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5002		0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5003		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5004	};
5005	static const u8 cs100[2 * 8] = {
5006		0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5007		0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5008	};
5009
5010	/* VGA enable */
5011	reg = inSISREG(SISVGAENABLE) | 0x01;
5012	outSISREG(SISVGAENABLE, reg);
5013
5014	/* Misc */
5015	reg = inSISREG(SISMISCR) | 0x01;
5016	outSISREG(SISMISCW, reg);
5017
5018	/* Unlock SR */
5019	outSISIDXREG(SISSR, 0x05, 0x86);
5020	inSISIDXREG(SISSR, 0x05, reg);
5021	if(reg != 0xa1)
5022		return 0;
5023
5024	/* Clear some regs */
5025	for(i = 0; i < 0x22; i++) {
5026		if(0x06 + i == 0x20) continue;
5027		outSISIDXREG(SISSR, 0x06 + i, 0x00);
5028	}
5029	for(i = 0; i < 0x0b; i++) {
5030		outSISIDXREG(SISSR, 0x31 + i, 0x00);
5031	}
5032	for(i = 0; i < 0x10; i++) {
5033		outSISIDXREG(SISCR, 0x30 + i, 0x00);
5034	}
5035
5036	ptr = cs78;
5037	if(ivideo->haveXGIROM) {
5038		ptr = (const u8 *)&bios[0x78];
5039	}
5040	for(i = 0; i < 3; i++) {
5041		outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5042	}
5043
5044	ptr = cs76;
5045	if(ivideo->haveXGIROM) {
5046		ptr = (const u8 *)&bios[0x76];
5047	}
5048	for(i = 0; i < 2; i++) {
5049		outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5050	}
5051
5052	v1 = 0x18; v2 = 0x00;
5053	if(ivideo->haveXGIROM) {
5054		v1 = bios[0x74];
5055		v2 = bios[0x75];
5056	}
5057	outSISIDXREG(SISSR, 0x07, v1);
5058	outSISIDXREG(SISSR, 0x11, 0x0f);
5059	outSISIDXREG(SISSR, 0x1f, v2);
5060	/* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5061	outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5062	outSISIDXREG(SISSR, 0x27, 0x74);
5063
5064	ptr = cs7b;
5065	if(ivideo->haveXGIROM) {
5066		ptr = (const u8 *)&bios[0x7b];
5067	}
5068	for(i = 0; i < 3; i++) {
5069		outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5070	}
5071
5072	if(ivideo->chip == XGI_40) {
5073		if(ivideo->revision_id == 2) {
5074			setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5075		}
5076		outSISIDXREG(SISCR, 0x7d, 0xfe);
5077		outSISIDXREG(SISCR, 0x7e, 0x0f);
5078	}
5079	if(ivideo->revision_id == 0) {	/* 40 *and* 20? */
5080		andSISIDXREG(SISCR, 0x58, 0xd7);
5081		inSISIDXREG(SISCR, 0xcb, reg);
5082		if(reg & 0x20) {
5083			setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5084		}
5085	}
5086
5087	reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5088	setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5089
5090	if(ivideo->chip == XGI_20) {
5091		outSISIDXREG(SISSR, 0x36, 0x70);
5092	} else {
5093		outSISIDXREG(SISVID, 0x00, 0x86);
5094		outSISIDXREG(SISVID, 0x32, 0x00);
5095		outSISIDXREG(SISVID, 0x30, 0x00);
5096		outSISIDXREG(SISVID, 0x32, 0x01);
5097		outSISIDXREG(SISVID, 0x30, 0x00);
5098		andSISIDXREG(SISVID, 0x2f, 0xdf);
5099		andSISIDXREG(SISCAP, 0x00, 0x3f);
5100
5101		outSISIDXREG(SISPART1, 0x2f, 0x01);
5102		outSISIDXREG(SISPART1, 0x00, 0x00);
5103		outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5104		outSISIDXREG(SISPART1, 0x2e, 0x08);
5105		andSISIDXREG(SISPART1, 0x35, 0x7f);
5106		andSISIDXREG(SISPART1, 0x50, 0xfe);
5107
5108		inSISIDXREG(SISPART4, 0x00, reg);
5109		if(reg == 1 || reg == 2) {
5110			outSISIDXREG(SISPART2, 0x00, 0x1c);
5111			outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5112			outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5113			outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5114			andSISIDXREG(SISPART4, 0x0f, 0x3f);
5115
5116			inSISIDXREG(SISPART4, 0x01, reg);
5117			if((reg & 0xf0) >= 0xb0) {
5118				inSISIDXREG(SISPART4, 0x23, reg);
5119				if(reg & 0x20) reg |= 0x40;
5120				outSISIDXREG(SISPART4, 0x23, reg);
5121				reg = (reg & 0x20) ? 0x02 : 0x00;
5122				setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5123			}
5124		}
5125
5126		v1 = bios[0x77];
5127
5128		inSISIDXREG(SISSR, 0x3b, reg);
5129		if(reg & 0x02) {
5130			inSISIDXREG(SISSR, 0x3a, reg);
5131			v2 = (reg & 0x30) >> 3;
5132			if(!(v2 & 0x04)) v2 ^= 0x02;
5133			inSISIDXREG(SISSR, 0x39, reg);
5134			if(reg & 0x80) v2 |= 0x80;
5135			v2 |= 0x01;
5136
5137			if((mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5138				pci_dev_put(mypdev);
5139				if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5140					v2 &= 0xf9;
5141				v2 |= 0x08;
5142				v1 &= 0xfe;
5143			} else {
5144				mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0735, NULL);
5145				if(!mypdev)
5146					mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0645, NULL);
5147				if(!mypdev)
5148					mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0650, NULL);
5149				if(mypdev) {
5150					pci_read_config_dword(mypdev, 0x94, &regd);
5151					regd &= 0xfffffeff;
5152					pci_write_config_dword(mypdev, 0x94, regd);
5153					v1 &= 0xfe;
5154					pci_dev_put(mypdev);
5155				} else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5156					v1 &= 0xfe;
5157				} else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5158					  sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5159					  sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5160					  sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5161					if((v2 & 0x06) == 4)
5162						v2 ^= 0x06;
5163					v2 |= 0x08;
5164				}
5165			}
5166			setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5167		}
5168		outSISIDXREG(SISSR, 0x22, v1);
5169
5170		if(ivideo->revision_id == 2) {
5171			inSISIDXREG(SISSR, 0x3b, v1);
5172			inSISIDXREG(SISSR, 0x3a, v2);
5173			regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5174			if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5175				setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5176
5177			if((mypdev = pci_get_device(0x10de, 0x01e0, NULL))) {
5178				/* TODO: set CR5f &0xf1 | 0x01 for version 6570
5179				 * of nforce 2 ROM
5180				 */
5181				if(0)
5182					setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5183				pci_dev_put(mypdev);
5184			}
5185		}
5186
5187		v1 = 0x30;
5188		inSISIDXREG(SISSR, 0x3b, reg);
5189		inSISIDXREG(SISCR, 0x5f, v2);
5190		if((!(reg & 0x02)) && (v2 & 0x0e))
5191			v1 |= 0x08;
5192		outSISIDXREG(SISSR, 0x27, v1);
5193
5194		if(bios[0x64] & 0x01) {
5195			setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5196		}
5197
5198		v1 = bios[0x4f7];
5199		pci_read_config_dword(pdev, 0x50, &regd);
5200		regd = (regd >> 20) & 0x0f;
5201		if(regd == 1) {
5202			v1 &= 0xfc;
5203			orSISIDXREG(SISCR, 0x5f, 0x08);
5204		}
5205		outSISIDXREG(SISCR, 0x48, v1);
5206
5207		setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5208		setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5209		setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5210		setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5211		setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5212		outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5213		setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5214		outSISIDXREG(SISCR, 0x74, 0xd0);
5215		setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5216		setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5217		setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5218		v1 = bios[0x501];
5219		if((mypdev = pci_get_device(0x8086, 0x2530, NULL))) {
5220			v1 = 0xf0;
5221			pci_dev_put(mypdev);
5222		}
5223		outSISIDXREG(SISCR, 0x77, v1);
5224	}
5225
5226	/* RAM type */
5227
5228	regb = 0;	/* ! */
5229
5230	v1 = 0xff;
5231	if(ivideo->haveXGIROM) {
5232		v1 = bios[0x140 + regb];
5233	}
5234	outSISIDXREG(SISCR, 0x6d, v1);
5235
5236	ptr = cs128;
5237	if(ivideo->haveXGIROM) {
5238		ptr = (const u8 *)&bios[0x128];
5239	}
5240	for(i = 0, j = 0; i < 3; i++, j += 8) {
5241		outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5242	}
5243
5244	ptr  = cs31a;
5245	ptr2 = cs33a;
5246	if(ivideo->haveXGIROM) {
5247		index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5248		ptr  = (const u8 *)&bios[index];
5249		ptr2 = (const u8 *)&bios[index + 0x20];
5250	}
5251	for(i = 0; i < 2; i++) {
5252		if(i == 0) {
5253			regd = le32_to_cpu(((u32 *)ptr)[regb]);
5254			rega = 0x6b;
5255		} else {
5256			regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5257			rega = 0x6e;
5258		}
5259		reg = 0x00;
5260		for(j = 0; j < 16; j++) {
5261			reg &= 0xf3;
5262			if(regd & 0x01) reg |= 0x04;
5263			if(regd & 0x02) reg |= 0x08;
5264			regd >>= 2;
5265			outSISIDXREG(SISCR, rega, reg);
5266			inSISIDXREG(SISCR, rega, reg);
5267			inSISIDXREG(SISCR, rega, reg);
5268			reg += 0x10;
5269		}
5270	}
5271
5272	andSISIDXREG(SISCR, 0x6e, 0xfc);
5273
5274	ptr  = NULL;
5275	if(ivideo->haveXGIROM) {
5276		index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5277		ptr  = (const u8 *)&bios[index];
5278	}
5279	for(i = 0; i < 4; i++) {
5280		setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5281		reg = 0x00;
5282		for(j = 0; j < 2; j++) {
5283			regd = 0;
5284			if(ptr) {
5285				regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5286				ptr += 4;
5287			}
5288			/* reg = 0x00; */
5289			for(k = 0; k < 16; k++) {
5290				reg &= 0xfc;
5291				if(regd & 0x01) reg |= 0x01;
5292				if(regd & 0x02) reg |= 0x02;
5293				regd >>= 2;
5294				outSISIDXREG(SISCR, 0x6f, reg);
5295				inSISIDXREG(SISCR, 0x6f, reg);
5296				inSISIDXREG(SISCR, 0x6f, reg);
5297				reg += 0x08;
5298			}
5299		}
5300	}
5301
5302	ptr  = cs148;
5303	if(ivideo->haveXGIROM) {
5304		ptr  = (const u8 *)&bios[0x148];
5305	}
5306	for(i = 0, j = 0; i < 2; i++, j += 8) {
5307		outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5308	}
5309
5310	andSISIDXREG(SISCR, 0x89, 0x8f);
5311
5312	ptr  = cs45a;
5313	if(ivideo->haveXGIROM) {
5314		index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5315		ptr  = (const u8 *)&bios[index];
5316	}
5317	regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5318	reg = 0x80;
5319	for(i = 0; i < 5; i++) {
5320		reg &= 0xfc;
5321		if(regd & 0x01) reg |= 0x01;
5322		if(regd & 0x02) reg |= 0x02;
5323		regd >>= 2;
5324		outSISIDXREG(SISCR, 0x89, reg);
5325		inSISIDXREG(SISCR, 0x89, reg);
5326		inSISIDXREG(SISCR, 0x89, reg);
5327		reg += 0x10;
5328	}
5329
5330	v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5331	if(ivideo->haveXGIROM) {
5332		v1 = bios[0x118 + regb];
5333		v2 = bios[0xf8 + regb];
5334		v3 = bios[0x120 + regb];
5335		v4 = bios[0x1ca];
5336	}
5337	outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5338	outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5339	orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5340	outSISIDXREG(SISCR, 0x41, v2);
5341
5342	ptr  = cs170;
5343	if(ivideo->haveXGIROM) {
5344		ptr  = (const u8 *)&bios[0x170];
5345	}
5346	for(i = 0, j = 0; i < 7; i++, j += 8) {
5347		outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5348	}
5349
5350	outSISIDXREG(SISCR, 0x59, v3);
5351
5352	ptr  = cs1a8;
5353	if(ivideo->haveXGIROM) {
5354		ptr  = (const u8 *)&bios[0x1a8];
5355	}
5356	for(i = 0, j = 0; i < 3; i++, j += 8) {
5357		outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5358	}
5359
5360	ptr  = cs100;
5361	if(ivideo->haveXGIROM) {
5362		ptr  = (const u8 *)&bios[0x100];
5363	}
5364	for(i = 0, j = 0; i < 2; i++, j += 8) {
5365		outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5366	}
5367
5368	outSISIDXREG(SISCR, 0xcf, v4);
5369
5370	outSISIDXREG(SISCR, 0x83, 0x09);
5371	outSISIDXREG(SISCR, 0x87, 0x00);
5372
5373	if(ivideo->chip == XGI_40) {
5374		if( (ivideo->revision_id == 1) ||
5375		    (ivideo->revision_id == 2) ) {
5376			outSISIDXREG(SISCR, 0x8c, 0x87);
5377		}
5378	}
5379
5380	outSISIDXREG(SISSR, 0x17, 0x00);
5381	outSISIDXREG(SISSR, 0x1a, 0x87);
5382
5383	if(ivideo->chip == XGI_20) {
5384		outSISIDXREG(SISSR, 0x15, 0x00);
5385		outSISIDXREG(SISSR, 0x1c, 0x00);
5386	}
5387
5388	ramtype = 0x00; v1 = 0x10;
5389	if(ivideo->haveXGIROM) {
5390		ramtype = bios[0x62];
5391		v1 = bios[0x1d2];
5392	}
5393	if(!(ramtype & 0x80)) {
5394		if(ivideo->chip == XGI_20) {
5395			outSISIDXREG(SISCR, 0x97, v1);
5396			inSISIDXREG(SISCR, 0x97, reg);
5397			if(reg & 0x10) {
5398				ramtype = (reg & 0x01) << 1;
5399			}
5400		} else {
5401			inSISIDXREG(SISSR, 0x39, reg);
5402			ramtype = reg & 0x02;
5403			if(!(ramtype)) {
5404				inSISIDXREG(SISSR, 0x3a, reg);
5405				ramtype = (reg >> 1) & 0x01;
5406			}
5407		}
5408	}
5409	ramtype &= 0x07;
5410
5411	regb = 0;	/* ! */
5412
5413	switch(ramtype) {
5414	case 0:
5415		sisfb_post_xgi_setclocks(ivideo, regb);
5416		if((ivideo->chip == XGI_20) ||
5417		   (ivideo->revision_id == 1)   ||
5418		   (ivideo->revision_id == 2)) {
5419			v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5420			if(ivideo->haveXGIROM) {
5421				v1 = bios[regb + 0x158];
5422				v2 = bios[regb + 0x160];
5423				v3 = bios[regb + 0x168];
5424			}
5425			outSISIDXREG(SISCR, 0x82, v1);
5426			outSISIDXREG(SISCR, 0x85, v2);
5427			outSISIDXREG(SISCR, 0x86, v3);
5428		} else {
5429			outSISIDXREG(SISCR, 0x82, 0x88);
5430			outSISIDXREG(SISCR, 0x86, 0x00);
5431			inSISIDXREG(SISCR, 0x86, reg);
5432			outSISIDXREG(SISCR, 0x86, 0x88);
5433			inSISIDXREG(SISCR, 0x86, reg);
5434			outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5435			outSISIDXREG(SISCR, 0x82, 0x77);
5436			outSISIDXREG(SISCR, 0x85, 0x00);
5437			inSISIDXREG(SISCR, 0x85, reg);
5438			outSISIDXREG(SISCR, 0x85, 0x88);
5439			inSISIDXREG(SISCR, 0x85, reg);
5440			outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5441			outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5442		}
5443		if(ivideo->chip == XGI_40) {
5444			outSISIDXREG(SISCR, 0x97, 0x00);
5445		}
5446		outSISIDXREG(SISCR, 0x98, 0x01);
5447		outSISIDXREG(SISCR, 0x9a, 0x02);
5448
5449		outSISIDXREG(SISSR, 0x18, 0x01);
5450		if((ivideo->chip == XGI_20) ||
5451		   (ivideo->revision_id == 2)) {
5452			outSISIDXREG(SISSR, 0x19, 0x40);
5453		} else {
5454			outSISIDXREG(SISSR, 0x19, 0x20);
5455		}
5456		outSISIDXREG(SISSR, 0x16, 0x00);
5457		outSISIDXREG(SISSR, 0x16, 0x80);
5458		if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5459			sisfb_post_xgi_delay(ivideo, 0x43);
5460			sisfb_post_xgi_delay(ivideo, 0x43);
5461			sisfb_post_xgi_delay(ivideo, 0x43);
5462			outSISIDXREG(SISSR, 0x18, 0x00);
5463			if((ivideo->chip == XGI_20) ||
5464			   (ivideo->revision_id == 2)) {
5465				outSISIDXREG(SISSR, 0x19, 0x40);
5466			} else {
5467				outSISIDXREG(SISSR, 0x19, 0x20);
5468			}
5469		} else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5470			/* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5471		}
5472		outSISIDXREG(SISSR, 0x16, 0x00);
5473		outSISIDXREG(SISSR, 0x16, 0x80);
5474		sisfb_post_xgi_delay(ivideo, 4);
5475		v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5476		if(ivideo->haveXGIROM) {
5477			v1 = bios[0xf0];
5478			index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5479			v2 = bios[index];
5480			v3 = bios[index + 1];
5481			v4 = bios[index + 2];
5482			v5 = bios[index + 3];
5483		}
5484		outSISIDXREG(SISSR, 0x18, v1);
5485		outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5486		outSISIDXREG(SISSR, 0x16, v2);
5487		outSISIDXREG(SISSR, 0x16, v3);
5488		sisfb_post_xgi_delay(ivideo, 0x43);
5489		outSISIDXREG(SISSR, 0x1b, 0x03);
5490		sisfb_post_xgi_delay(ivideo, 0x22);
5491		outSISIDXREG(SISSR, 0x18, v1);
5492		outSISIDXREG(SISSR, 0x19, 0x00);
5493		outSISIDXREG(SISSR, 0x16, v4);
5494		outSISIDXREG(SISSR, 0x16, v5);
5495		outSISIDXREG(SISSR, 0x1b, 0x00);
5496		break;
5497	case 1:
5498		outSISIDXREG(SISCR, 0x82, 0x77);
5499		outSISIDXREG(SISCR, 0x86, 0x00);
5500		inSISIDXREG(SISCR, 0x86, reg);
5501		outSISIDXREG(SISCR, 0x86, 0x88);
5502		inSISIDXREG(SISCR, 0x86, reg);
5503		v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5504		if(ivideo->haveXGIROM) {
5505			v1 = bios[regb + 0x168];
5506			v2 = bios[regb + 0x160];
5507			v3 = bios[regb + 0x158];
5508		}
5509		outSISIDXREG(SISCR, 0x86, v1);
5510		outSISIDXREG(SISCR, 0x82, 0x77);
5511		outSISIDXREG(SISCR, 0x85, 0x00);
5512		inSISIDXREG(SISCR, 0x85, reg);
5513		outSISIDXREG(SISCR, 0x85, 0x88);
5514		inSISIDXREG(SISCR, 0x85, reg);
5515		outSISIDXREG(SISCR, 0x85, v2);
5516		outSISIDXREG(SISCR, 0x82, v3);
5517		outSISIDXREG(SISCR, 0x98, 0x01);
5518		outSISIDXREG(SISCR, 0x9a, 0x02);
5519
5520		outSISIDXREG(SISSR, 0x28, 0x64);
5521		outSISIDXREG(SISSR, 0x29, 0x63);
5522		sisfb_post_xgi_delay(ivideo, 15);
5523		outSISIDXREG(SISSR, 0x18, 0x00);
5524		outSISIDXREG(SISSR, 0x19, 0x20);
5525		outSISIDXREG(SISSR, 0x16, 0x00);
5526		outSISIDXREG(SISSR, 0x16, 0x80);
5527		outSISIDXREG(SISSR, 0x18, 0xc5);
5528		outSISIDXREG(SISSR, 0x19, 0x23);
5529		outSISIDXREG(SISSR, 0x16, 0x00);
5530		outSISIDXREG(SISSR, 0x16, 0x80);
5531		sisfb_post_xgi_delay(ivideo, 1);
5532		outSISIDXREG(SISCR, 0x97,0x11);
5533		sisfb_post_xgi_setclocks(ivideo, regb);
5534		sisfb_post_xgi_delay(ivideo, 0x46);
5535		outSISIDXREG(SISSR, 0x18, 0xc5);
5536		outSISIDXREG(SISSR, 0x19, 0x23);
5537		outSISIDXREG(SISSR, 0x16, 0x00);
5538		outSISIDXREG(SISSR, 0x16, 0x80);
5539		sisfb_post_xgi_delay(ivideo, 1);
5540		outSISIDXREG(SISSR, 0x1b, 0x04);
5541		sisfb_post_xgi_delay(ivideo, 1);
5542		outSISIDXREG(SISSR, 0x1b, 0x00);
5543		sisfb_post_xgi_delay(ivideo, 1);
5544		v1 = 0x31;
5545		if(ivideo->haveXGIROM) {
5546			v1 = bios[0xf0];
5547		}
5548		outSISIDXREG(SISSR, 0x18, v1);
5549		outSISIDXREG(SISSR, 0x19, 0x06);
5550		outSISIDXREG(SISSR, 0x16, 0x04);
5551		outSISIDXREG(SISSR, 0x16, 0x84);
5552		sisfb_post_xgi_delay(ivideo, 1);
5553		break;
5554	default:
5555		sisfb_post_xgi_setclocks(ivideo, regb);
5556		if((ivideo->chip == XGI_40) &&
5557		   ((ivideo->revision_id == 1) ||
5558		    (ivideo->revision_id == 2))) {
5559			outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5560			outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5561			outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5562		} else {
5563			outSISIDXREG(SISCR, 0x82, 0x88);
5564			outSISIDXREG(SISCR, 0x86, 0x00);
5565			inSISIDXREG(SISCR, 0x86, reg);
5566			outSISIDXREG(SISCR, 0x86, 0x88);
5567			outSISIDXREG(SISCR, 0x82, 0x77);
5568			outSISIDXREG(SISCR, 0x85, 0x00);
5569			inSISIDXREG(SISCR, 0x85, reg);
5570			outSISIDXREG(SISCR, 0x85, 0x88);
5571			inSISIDXREG(SISCR, 0x85, reg);
5572			v1 = cs160[regb]; v2 = cs158[regb];
5573			if(ivideo->haveXGIROM) {
5574				v1 = bios[regb + 0x160];
5575				v2 = bios[regb + 0x158];
5576			}
5577			outSISIDXREG(SISCR, 0x85, v1);
5578			outSISIDXREG(SISCR, 0x82, v2);
5579		}
5580		if(ivideo->chip == XGI_40) {
5581			outSISIDXREG(SISCR, 0x97, 0x11);
5582		}
5583		if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5584			outSISIDXREG(SISCR, 0x98, 0x01);
5585		} else {
5586			outSISIDXREG(SISCR, 0x98, 0x03);
5587		}
5588		outSISIDXREG(SISCR, 0x9a, 0x02);
5589
5590		if(ivideo->chip == XGI_40) {
5591			outSISIDXREG(SISSR, 0x18, 0x01);
5592		} else {
5593			outSISIDXREG(SISSR, 0x18, 0x00);
5594		}
5595		outSISIDXREG(SISSR, 0x19, 0x40);
5596		outSISIDXREG(SISSR, 0x16, 0x00);
5597		outSISIDXREG(SISSR, 0x16, 0x80);
5598		if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5599			sisfb_post_xgi_delay(ivideo, 0x43);
5600			sisfb_post_xgi_delay(ivideo, 0x43);
5601			sisfb_post_xgi_delay(ivideo, 0x43);
5602			outSISIDXREG(SISSR, 0x18, 0x00);
5603			outSISIDXREG(SISSR, 0x19, 0x40);
5604			outSISIDXREG(SISSR, 0x16, 0x00);
5605			outSISIDXREG(SISSR, 0x16, 0x80);
5606		}
5607		sisfb_post_xgi_delay(ivideo, 4);
5608		v1 = 0x31;
5609		if(ivideo->haveXGIROM) {
5610			v1 = bios[0xf0];
5611		}
5612		outSISIDXREG(SISSR, 0x18, v1);
5613		outSISIDXREG(SISSR, 0x19, 0x01);
5614		if(ivideo->chip == XGI_40) {
5615			outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5616			outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5617		} else {
5618			outSISIDXREG(SISSR, 0x16, 0x05);
5619			outSISIDXREG(SISSR, 0x16, 0x85);
5620		}
5621		sisfb_post_xgi_delay(ivideo, 0x43);
5622		if(ivideo->chip == XGI_40) {
5623			outSISIDXREG(SISSR, 0x1b, 0x01);
5624		} else {
5625			outSISIDXREG(SISSR, 0x1b, 0x03);
5626		}
5627		sisfb_post_xgi_delay(ivideo, 0x22);
5628		outSISIDXREG(SISSR, 0x18, v1);
5629		outSISIDXREG(SISSR, 0x19, 0x00);
5630		if(ivideo->chip == XGI_40) {
5631			outSISIDXREG(SISSR, 0x16, bios[0x540]);
5632			outSISIDXREG(SISSR, 0x16, bios[0x541]);
5633		} else {
5634			outSISIDXREG(SISSR, 0x16, 0x05);
5635			outSISIDXREG(SISSR, 0x16, 0x85);
5636		}
5637		outSISIDXREG(SISSR, 0x1b, 0x00);
5638	}
5639
5640	regb = 0;	/* ! */
5641	v1 = 0x03;
5642	if(ivideo->haveXGIROM) {
5643		v1 = bios[0x110 + regb];
5644	}
5645	outSISIDXREG(SISSR, 0x1b, v1);
5646
5647	/* RAM size */
5648	v1 = 0x00; v2 = 0x00;
5649	if(ivideo->haveXGIROM) {
5650		v1 = bios[0x62];
5651		v2 = bios[0x63];
5652	}
5653	regb = 0;	/* ! */
5654	regd = 1 << regb;
5655	if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5656
5657		outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5658		outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5659
5660	} else {
5661
5662		/* Set default mode, don't clear screen */
5663		ivideo->SiS_Pr.SiS_UseOEM = false;
5664		SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5665		SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
5666		ivideo->curFSTN = ivideo->curDSTN = 0;
5667		ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5668		SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5669
5670		outSISIDXREG(SISSR, 0x05, 0x86);
5671
5672		/* Disable read-cache */
5673		andSISIDXREG(SISSR, 0x21, 0xdf);
5674		sisfb_post_xgi_ramsize(ivideo);
5675		/* Enable read-cache */
5676		orSISIDXREG(SISSR, 0x21, 0x20);
5677
5678	}
5679
5680
5681	/* Sense CRT1 */
5682	if(ivideo->chip == XGI_20) {
5683		orSISIDXREG(SISCR, 0x32, 0x20);
5684	} else {
5685		inSISIDXREG(SISPART4, 0x00, reg);
5686		if((reg == 1) || (reg == 2)) {
5687			sisfb_sense_crt1(ivideo);
5688		} else {
5689			orSISIDXREG(SISCR, 0x32, 0x20);
5690		}
5691	}
5692
5693	/* Set default mode, don't clear screen */
5694	ivideo->SiS_Pr.SiS_UseOEM = false;
5695	SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5696	SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
5697	ivideo->curFSTN = ivideo->curDSTN = 0;
5698	SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5699
5700	outSISIDXREG(SISSR, 0x05, 0x86);
5701
5702	/* Display off */
5703	orSISIDXREG(SISSR, 0x01, 0x20);
5704
5705	/* Save mode number in CR34 */
5706	outSISIDXREG(SISCR, 0x34, 0x2e);
5707
5708	/* Let everyone know what the current mode is */
5709	ivideo->modeprechange = 0x2e;
5710
5711	if(ivideo->chip == XGI_40) {
5712		inSISIDXREG(SISCR, 0xca, reg);
5713		inSISIDXREG(SISCR, 0xcc, v1);
5714		if((reg & 0x10) && (!(v1 & 0x04))) {
5715			printk(KERN_ERR
5716				"sisfb: Please connect power to the card.\n");
5717			return 0;
5718		}
5719	}
5720
5721	return 1;
5722}
5723#endif
5724
5725static int __devinit
5726sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5727{
5728	struct sisfb_chip_info	*chipinfo = &sisfb_chip_info[ent->driver_data];
5729	struct sis_video_info	*ivideo = NULL;
5730	struct fb_info		*sis_fb_info = NULL;
5731	u16 reg16;
5732	u8  reg;
5733	int i, ret;
5734
5735	if(sisfb_off)
5736		return -ENXIO;
5737
5738	sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
5739	if(!sis_fb_info)
5740		return -ENOMEM;
5741
5742	ivideo = (struct sis_video_info *)sis_fb_info->par;
5743	ivideo->memyselfandi = sis_fb_info;
5744
5745	ivideo->sisfb_id = SISFB_ID;
5746
5747	if(card_list == NULL) {
5748		ivideo->cardnumber = 0;
5749	} else {
5750		struct sis_video_info *countvideo = card_list;
5751		ivideo->cardnumber = 1;
5752		while((countvideo = countvideo->next) != 0)
5753			ivideo->cardnumber++;
5754	}
5755
5756	strncpy(ivideo->myid, chipinfo->chip_name, 30);
5757
5758	ivideo->warncount = 0;
5759	ivideo->chip_id = pdev->device;
5760	ivideo->chip_vendor = pdev->vendor;
5761	pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
5762	ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
5763	pci_read_config_word(pdev, PCI_COMMAND, &reg16);
5764	ivideo->sisvga_enabled = reg16 & 0x01;
5765	ivideo->pcibus = pdev->bus->number;
5766	ivideo->pcislot = PCI_SLOT(pdev->devfn);
5767	ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5768	ivideo->subsysvendor = pdev->subsystem_vendor;
5769	ivideo->subsysdevice = pdev->subsystem_device;
5770#ifdef SIS_OLD_CONFIG_COMPAT
5771	ivideo->ioctl32registered = 0;
5772#endif
5773
5774#ifndef MODULE
5775	if(sisfb_mode_idx == -1) {
5776		sisfb_get_vga_mode_from_kernel();
5777	}
5778#endif
5779
5780	ivideo->chip = chipinfo->chip;
5781	ivideo->sisvga_engine = chipinfo->vgaengine;
5782	ivideo->hwcursor_size = chipinfo->hwcursor_size;
5783	ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5784	ivideo->mni = chipinfo->mni;
5785
5786	ivideo->detectedpdc  = 0xff;
5787	ivideo->detectedpdca = 0xff;
5788	ivideo->detectedlcda = 0xff;
5789
5790	ivideo->sisfb_thismonitor.datavalid = false;
5791
5792	ivideo->current_base = 0;
5793
5794	ivideo->engineok = 0;
5795
5796	ivideo->sisfb_was_boot_device = 0;
5797#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12))
5798	if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5799		if(ivideo->sisvga_enabled)
5800			ivideo->sisfb_was_boot_device = 1;
5801		else {
5802			printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5803				"but marked as boot video device ???\n");
5804			printk(KERN_DEBUG "sisfb: I will not accept this "
5805				"as the primary VGA device\n");
5806		}
5807	}
5808#endif
5809
5810	ivideo->sisfb_parm_mem = sisfb_parm_mem;
5811	ivideo->sisfb_accel = sisfb_accel;
5812	ivideo->sisfb_ypan = sisfb_ypan;
5813	ivideo->sisfb_max = sisfb_max;
5814	ivideo->sisfb_userom = sisfb_userom;
5815	ivideo->sisfb_useoem = sisfb_useoem;
5816	ivideo->sisfb_mode_idx = sisfb_mode_idx;
5817	ivideo->sisfb_parm_rate = sisfb_parm_rate;
5818	ivideo->sisfb_crt1off = sisfb_crt1off;
5819	ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5820	ivideo->sisfb_crt2type = sisfb_crt2type;
5821	ivideo->sisfb_crt2flags = sisfb_crt2flags;
5822	/* pdc(a), scalelcd, special timing, lvdshl handled below */
5823	ivideo->sisfb_dstn = sisfb_dstn;
5824	ivideo->sisfb_fstn = sisfb_fstn;
5825	ivideo->sisfb_tvplug = sisfb_tvplug;
5826	ivideo->sisfb_tvstd = sisfb_tvstd;
5827	ivideo->tvxpos = sisfb_tvxposoffset;
5828	ivideo->tvypos = sisfb_tvyposoffset;
5829	ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
5830	ivideo->refresh_rate = 0;
5831	if(ivideo->sisfb_parm_rate != -1) {
5832		ivideo->refresh_rate = ivideo->sisfb_parm_rate;
5833	}
5834
5835	ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5836	ivideo->SiS_Pr.CenterScreen = -1;
5837	ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5838	ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5839
5840	ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
5841	ivideo->SiS_Pr.SiS_CHOverScan = -1;
5842	ivideo->SiS_Pr.SiS_ChSW = false;
5843	ivideo->SiS_Pr.SiS_UseLCDA = false;
5844	ivideo->SiS_Pr.HaveEMI = false;
5845	ivideo->SiS_Pr.HaveEMILCD = false;
5846	ivideo->SiS_Pr.OverruleEMI = false;
5847	ivideo->SiS_Pr.SiS_SensibleSR11 = false;
5848	ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5849	ivideo->SiS_Pr.PDC  = -1;
5850	ivideo->SiS_Pr.PDCA = -1;
5851	ivideo->SiS_Pr.DDCPortMixup = false;
5852#ifdef CONFIG_FB_SIS_315
5853	if(ivideo->chip >= SIS_330) {
5854		ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
5855		if(ivideo->chip >= SIS_661) {
5856			ivideo->SiS_Pr.SiS_SensibleSR11 = true;
5857		}
5858	}
5859#endif
5860
5861	memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
5862
5863	pci_set_drvdata(pdev, ivideo);
5864
5865	/* Patch special cases */
5866	if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
5867		switch(ivideo->nbridge->device) {
5868#ifdef CONFIG_FB_SIS_300
5869		case PCI_DEVICE_ID_SI_730:
5870			ivideo->chip = SIS_730;
5871			strcpy(ivideo->myid, "SiS 730");
5872			break;
5873#endif
5874#ifdef CONFIG_FB_SIS_315
5875		case PCI_DEVICE_ID_SI_651:
5876			/* ivideo->chip is ok */
5877			strcpy(ivideo->myid, "SiS 651");
5878			break;
5879		case PCI_DEVICE_ID_SI_740:
5880			ivideo->chip = SIS_740;
5881			strcpy(ivideo->myid, "SiS 740");
5882			break;
5883		case PCI_DEVICE_ID_SI_661:
5884			ivideo->chip = SIS_661;
5885			strcpy(ivideo->myid, "SiS 661");
5886			break;
5887		case PCI_DEVICE_ID_SI_741:
5888			ivideo->chip = SIS_741;
5889			strcpy(ivideo->myid, "SiS 741");
5890			break;
5891		case PCI_DEVICE_ID_SI_760:
5892			ivideo->chip = SIS_760;
5893			strcpy(ivideo->myid, "SiS 760");
5894			break;
5895		case PCI_DEVICE_ID_SI_761:
5896			ivideo->chip = SIS_761;
5897			strcpy(ivideo->myid, "SiS 761");
5898			break;
5899#endif
5900		default:
5901			break;
5902		}
5903	}
5904
5905	ivideo->SiS_Pr.ChipType = ivideo->chip;
5906
5907	ivideo->SiS_Pr.ivideo = (void *)ivideo;
5908
5909#ifdef CONFIG_FB_SIS_315
5910	if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
5911	   (ivideo->SiS_Pr.ChipType == SIS_315)) {
5912		ivideo->SiS_Pr.ChipType = SIS_315H;
5913	}
5914#endif
5915
5916	if(!ivideo->sisvga_enabled) {
5917		if(pci_enable_device(pdev)) {
5918			if(ivideo->nbridge) pci_dev_put(ivideo->nbridge);
5919			pci_set_drvdata(pdev, NULL);
5920			kfree(sis_fb_info);
5921			return -EIO;
5922		}
5923	}
5924
5925	ivideo->video_base = pci_resource_start(pdev, 0);
5926	ivideo->mmio_base  = pci_resource_start(pdev, 1);
5927	ivideo->mmio_size  = pci_resource_len(pdev, 1);
5928	ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
5929	ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
5930
5931	SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
5932
5933#ifdef CONFIG_FB_SIS_300
5934	/* Find PCI systems for Chrontel/GPIO communication setup */
5935	if(ivideo->chip == SIS_630) {
5936		i = 0;
5937        	do {
5938			if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
5939			   mychswtable[i].subsysCard   == ivideo->subsysdevice) {
5940				ivideo->SiS_Pr.SiS_ChSW = true;
5941				printk(KERN_DEBUG "sisfb: Identified [%s %s] "
5942					"requiring Chrontel/GPIO setup\n",
5943					mychswtable[i].vendorName,
5944					mychswtable[i].cardName);
5945				ivideo->lpcdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0008, NULL);
5946				break;
5947			}
5948			i++;
5949		} while(mychswtable[i].subsysVendor != 0);
5950	}
5951#endif
5952
5953#ifdef CONFIG_FB_SIS_315
5954	if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
5955		ivideo->lpcdev = pci_get_slot(ivideo->nbridge->bus, (2 << 3));
5956	}
5957#endif
5958
5959	outSISIDXREG(SISSR, 0x05, 0x86);
5960
5961	if( (!ivideo->sisvga_enabled)
5962#if !defined(__i386__) && !defined(__x86_64__)
5963			      || (sisfb_resetcard)
5964#endif
5965						   ) {
5966		for(i = 0x30; i <= 0x3f; i++) {
5967			outSISIDXREG(SISCR, i, 0x00);
5968		}
5969	}
5970
5971	/* Find out about current video mode */
5972	ivideo->modeprechange = 0x03;
5973	inSISIDXREG(SISCR, 0x34, reg);
5974	if(reg & 0x7f) {
5975		ivideo->modeprechange = reg & 0x7f;
5976	} else if(ivideo->sisvga_enabled) {
5977#if defined(__i386__) || defined(__x86_64__)
5978		unsigned char SIS_IOTYPE2 *tt = ioremap(0x400, 0x100);
5979		if(tt) {
5980			ivideo->modeprechange = readb(tt + 0x49);
5981			iounmap(tt);
5982		}
5983#endif
5984	}
5985
5986	/* Search and copy ROM image */
5987	ivideo->bios_abase = NULL;
5988	ivideo->SiS_Pr.VirtualRomBase = NULL;
5989	ivideo->SiS_Pr.UseROM = false;
5990	ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = false;
5991	if(ivideo->sisfb_userom) {
5992		ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
5993		ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
5994		ivideo->SiS_Pr.UseROM = (bool)(ivideo->SiS_Pr.VirtualRomBase);
5995		printk(KERN_INFO "sisfb: Video ROM %sfound\n",
5996			ivideo->SiS_Pr.UseROM ? "" : "not ");
5997		if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
5998		   ivideo->SiS_Pr.UseROM = false;
5999		   ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = true;
6000		   if( (ivideo->revision_id == 2) &&
6001		       (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
6002			ivideo->SiS_Pr.DDCPortMixup = true;
6003		   }
6004		}
6005	} else {
6006		printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6007	}
6008
6009	/* Find systems for special custom timing */
6010	if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6011		sisfb_detect_custom_timing(ivideo);
6012	}
6013
6014	/* POST card in case this has not been done by the BIOS */
6015	if( (!ivideo->sisvga_enabled)
6016#if !defined(__i386__) && !defined(__x86_64__)
6017			     || (sisfb_resetcard)
6018#endif
6019						 ) {
6020#ifdef CONFIG_FB_SIS_300
6021		if(ivideo->sisvga_engine == SIS_300_VGA) {
6022			if(ivideo->chip == SIS_300) {
6023				sisfb_post_sis300(pdev);
6024				ivideo->sisfb_can_post = 1;
6025			}
6026		}
6027#endif
6028
6029#ifdef CONFIG_FB_SIS_315
6030		if(ivideo->sisvga_engine == SIS_315_VGA) {
6031			int result = 1;
6032		/*	if((ivideo->chip == SIS_315H)   ||
6033			   (ivideo->chip == SIS_315)    ||
6034			   (ivideo->chip == SIS_315PRO) ||
6035			   (ivideo->chip == SIS_330)) {
6036				sisfb_post_sis315330(pdev);
6037			} else */ if(ivideo->chip == XGI_20) {
6038				result = sisfb_post_xgi(pdev);
6039				ivideo->sisfb_can_post = 1;
6040			} else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6041				result = sisfb_post_xgi(pdev);
6042				ivideo->sisfb_can_post = 1;
6043			} else {
6044				printk(KERN_INFO "sisfb: Card is not "
6045					"POSTed and sisfb can't do this either.\n");
6046			}
6047			if(!result) {
6048				printk(KERN_ERR "sisfb: Failed to POST card\n");
6049				ret = -ENODEV;
6050				goto error_3;
6051			}
6052		}
6053#endif
6054	}
6055
6056	ivideo->sisfb_card_posted = 1;
6057
6058	/* Find out about RAM size */
6059	if(sisfb_get_dram_size(ivideo)) {
6060		printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6061		ret = -ENODEV;
6062		goto error_3;
6063	}
6064
6065
6066	/* Enable PCI addressing and MMIO */
6067	if((ivideo->sisfb_mode_idx < 0) ||
6068	   ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6069		/* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE  */
6070		orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6071		/* Enable 2D accelerator engine */
6072		orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
6073	}
6074
6075	if(sisfb_pdc != 0xff) {
6076		if(ivideo->sisvga_engine == SIS_300_VGA)
6077			sisfb_pdc &= 0x3c;
6078		else
6079			sisfb_pdc &= 0x1f;
6080		ivideo->SiS_Pr.PDC = sisfb_pdc;
6081	}
6082#ifdef CONFIG_FB_SIS_315
6083	if(ivideo->sisvga_engine == SIS_315_VGA) {
6084		if(sisfb_pdca != 0xff)
6085			ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
6086	}
6087#endif
6088
6089	if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
6090		printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6091				(int)(ivideo->video_size >> 20));
6092		printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
6093		ret = -ENODEV;
6094		goto error_3;
6095	}
6096
6097	if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6098		printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
6099		ret = -ENODEV;
6100		goto error_2;
6101	}
6102
6103	ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
6104	ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
6105	if(!ivideo->video_vbase) {
6106		printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6107		ret = -ENODEV;
6108		goto error_1;
6109	}
6110
6111	ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6112	if(!ivideo->mmio_vbase) {
6113		printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6114		ret = -ENODEV;
6115error_0:	iounmap(ivideo->video_vbase);
6116error_1:	release_mem_region(ivideo->video_base, ivideo->video_size);
6117error_2:	release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6118error_3:	vfree(ivideo->bios_abase);
6119		if(ivideo->lpcdev)
6120			pci_dev_put(ivideo->lpcdev);
6121		if(ivideo->nbridge)
6122			pci_dev_put(ivideo->nbridge);
6123		pci_set_drvdata(pdev, NULL);
6124		if(!ivideo->sisvga_enabled)
6125			pci_disable_device(pdev);
6126		kfree(sis_fb_info);
6127		return ret;
6128	}
6129
6130	printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6131		ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6132
6133	if(ivideo->video_offset) {
6134		printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6135			ivideo->video_offset / 1024);
6136	}
6137
6138	printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
6139		ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
6140
6141
6142	/* Determine the size of the command queue */
6143	if(ivideo->sisvga_engine == SIS_300_VGA) {
6144		ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6145	} else {
6146		if(ivideo->chip == XGI_20) {
6147			ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6148		} else {
6149			ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6150		}
6151	}
6152
6153	/* Engines are no longer initialized here; this is
6154	 * now done after the first mode-switch (if the
6155	 * submitted var has its acceleration flags set).
6156	 */
6157
6158	/* Calculate the base of the (unused) hw cursor */
6159	ivideo->hwcursor_vbase = ivideo->video_vbase
6160				 + ivideo->video_size
6161				 - ivideo->cmdQueueSize
6162				 - ivideo->hwcursor_size;
6163	ivideo->caps |= HW_CURSOR_CAP;
6164
6165	/* Initialize offscreen memory manager */
6166	if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6167		printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6168	}
6169
6170	/* Used for clearing the screen only, therefore respect our mem limit */
6171	ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6172	ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
6173
6174	ivideo->mtrr = -1;
6175
6176	ivideo->vbflags = 0;
6177	ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6178	ivideo->tvdefmodeidx  = DEFAULT_TVMODE;
6179	ivideo->defmodeidx    = DEFAULT_MODE;
6180
6181	ivideo->newrom = 0;
6182	if(ivideo->chip < XGI_20) {
6183		if(ivideo->bios_abase) {
6184			ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6185		}
6186	}
6187
6188	if((ivideo->sisfb_mode_idx < 0) ||
6189	   ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6190
6191		sisfb_sense_crt1(ivideo);
6192
6193		sisfb_get_VB_type(ivideo);
6194
6195		if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6196			sisfb_detect_VB_connect(ivideo);
6197		}
6198
6199		ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6200
6201		/* Decide on which CRT2 device to use */
6202		if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6203			if(ivideo->sisfb_crt2type != -1) {
6204				if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6205				   (ivideo->vbflags & CRT2_LCD)) {
6206					ivideo->currentvbflags |= CRT2_LCD;
6207				} else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6208					ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6209				}
6210			} else {
6211				/* Chrontel 700x TV detection often unreliable, therefore
6212				 * use a different default order on such machines
6213				 */
6214				if((ivideo->sisvga_engine == SIS_300_VGA) &&
6215				   (ivideo->vbflags2 & VB2_CHRONTEL)) {
6216					if(ivideo->vbflags & CRT2_LCD)
6217						ivideo->currentvbflags |= CRT2_LCD;
6218					else if(ivideo->vbflags & CRT2_TV)
6219						ivideo->currentvbflags |= CRT2_TV;
6220					else if(ivideo->vbflags & CRT2_VGA)
6221						ivideo->currentvbflags |= CRT2_VGA;
6222				} else {
6223					if(ivideo->vbflags & CRT2_TV)
6224						ivideo->currentvbflags |= CRT2_TV;
6225					else if(ivideo->vbflags & CRT2_LCD)
6226						ivideo->currentvbflags |= CRT2_LCD;
6227					else if(ivideo->vbflags & CRT2_VGA)
6228						ivideo->currentvbflags |= CRT2_VGA;
6229				}
6230			}
6231		}
6232
6233		if(ivideo->vbflags & CRT2_LCD) {
6234			sisfb_detect_lcd_type(ivideo);
6235		}
6236
6237		sisfb_save_pdc_emi(ivideo);
6238
6239		if(!ivideo->sisfb_crt1off) {
6240			sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
6241		} else {
6242			if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6243			   (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6244				sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6245			}
6246		}
6247
6248		if(ivideo->sisfb_mode_idx >= 0) {
6249			int bu = ivideo->sisfb_mode_idx;
6250			ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6251					ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6252			if(bu != ivideo->sisfb_mode_idx) {
6253				printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6254					sisbios_mode[bu].xres,
6255					sisbios_mode[bu].yres,
6256					sisbios_mode[bu].bpp);
6257			}
6258		}
6259
6260		if(ivideo->sisfb_mode_idx < 0) {
6261			switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6262			   case CRT2_LCD:
6263				ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6264				break;
6265			   case CRT2_TV:
6266				ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6267				break;
6268			   default:
6269				ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6270				break;
6271			}
6272		}
6273
6274		ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6275
6276		if(ivideo->refresh_rate != 0) {
6277			sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6278						ivideo->sisfb_mode_idx);
6279		}
6280
6281		if(ivideo->rate_idx == 0) {
6282			ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6283			ivideo->refresh_rate = 60;
6284		}
6285
6286		if(ivideo->sisfb_thismonitor.datavalid) {
6287			if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6288						ivideo->sisfb_mode_idx,
6289						ivideo->rate_idx,
6290						ivideo->refresh_rate)) {
6291				printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6292							"exceeds monitor specs!\n");
6293			}
6294		}
6295
6296		ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6297		ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6298		ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6299
6300		sisfb_set_vparms(ivideo);
6301
6302		printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
6303			ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6304			ivideo->refresh_rate);
6305
6306		/* Set up the default var according to chosen default display mode */
6307		ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6308		ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6309		ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6310
6311		sisfb_bpp_to_var(ivideo, &ivideo->default_var);
6312
6313		ivideo->default_var.pixclock = (u32) (1000000000 /
6314			sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6315
6316		if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6317						ivideo->rate_idx, &ivideo->default_var)) {
6318			if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6319				ivideo->default_var.pixclock <<= 1;
6320			}
6321		}
6322
6323		if(ivideo->sisfb_ypan) {
6324			/* Maximize regardless of sisfb_max at startup */
6325			ivideo->default_var.yres_virtual =
6326				sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6327			if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6328				ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6329			}
6330		}
6331
6332		sisfb_calc_pitch(ivideo, &ivideo->default_var);
6333
6334		ivideo->accel = 0;
6335		if(ivideo->sisfb_accel) {
6336			ivideo->accel = -1;
6337#ifdef STUPID_ACCELF_TEXT_SHIT
6338			ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6339#endif
6340		}
6341		sisfb_initaccel(ivideo);
6342
6343#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6344		sis_fb_info->flags = FBINFO_DEFAULT 		|
6345				     FBINFO_HWACCEL_YPAN 	|
6346				     FBINFO_HWACCEL_XPAN 	|
6347				     FBINFO_HWACCEL_COPYAREA 	|
6348				     FBINFO_HWACCEL_FILLRECT 	|
6349				     ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6350#else
6351		sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6352#endif
6353		sis_fb_info->var = ivideo->default_var;
6354		sis_fb_info->fix = ivideo->sisfb_fix;
6355		sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
6356		sis_fb_info->fbops = &sisfb_ops;
6357		sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
6358		sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
6359
6360		fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
6361
6362		printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
6363
6364#ifdef CONFIG_MTRR
6365		ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6366					MTRR_TYPE_WRCOMB, 1);
6367		if(ivideo->mtrr < 0) {
6368			printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6369		}
6370#endif
6371
6372		if(register_framebuffer(sis_fb_info) < 0) {
6373			printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
6374			ret = -EINVAL;
6375			iounmap(ivideo->mmio_vbase);
6376			goto error_0;
6377		}
6378
6379		ivideo->registered = 1;
6380
6381		/* Enlist us */
6382		ivideo->next = card_list;
6383		card_list = ivideo;
6384
6385#ifdef SIS_OLD_CONFIG_COMPAT
6386		{
6387		int ret;
6388		/* Our ioctls are all "32/64bit compatible" */
6389		ret =  register_ioctl32_conversion(FBIO_ALLOC,             NULL);
6390		ret |= register_ioctl32_conversion(FBIO_FREE,              NULL);
6391		ret |= register_ioctl32_conversion(FBIOGET_VBLANK,         NULL);
6392		ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE,    NULL);
6393		ret |= register_ioctl32_conversion(SISFB_GET_INFO,         NULL);
6394		ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET,  NULL);
6395		ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET,  NULL);
6396		ret |= register_ioctl32_conversion(SISFB_SET_LOCK,         NULL);
6397		ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS,    NULL);
6398		ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
6399		ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
6400		ret |= register_ioctl32_conversion(SISFB_COMMAND,          NULL);
6401		if(ret)
6402			printk(KERN_ERR
6403				"sisfb: Error registering ioctl32 translations\n");
6404		else
6405			ivideo->ioctl32registered = 1;
6406		}
6407#endif
6408
6409		printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
6410			ivideo->sisfb_accel ? "enabled" : "disabled",
6411			ivideo->sisfb_ypan  ?
6412				(ivideo->sisfb_max ? "enabled (auto-max)" :
6413						"enabled (no auto-max)") :
6414									"disabled");
6415
6416
6417		printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
6418			sis_fb_info->node, ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
6419
6420		printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
6421
6422	}	/* if mode = "none" */
6423
6424	return 0;
6425}
6426
6427/*****************************************************/
6428/*                PCI DEVICE HANDLING                */
6429/*****************************************************/
6430
6431static void __devexit sisfb_remove(struct pci_dev *pdev)
6432{
6433	struct sis_video_info	*ivideo = pci_get_drvdata(pdev);
6434	struct fb_info		*sis_fb_info = ivideo->memyselfandi;
6435	int			registered = ivideo->registered;
6436	int			modechanged = ivideo->modechanged;
6437
6438#ifdef SIS_OLD_CONFIG_COMPAT
6439	if(ivideo->ioctl32registered) {
6440		int ret;
6441		ret =  unregister_ioctl32_conversion(FBIO_ALLOC);
6442		ret |= unregister_ioctl32_conversion(FBIO_FREE);
6443		ret |= unregister_ioctl32_conversion(FBIOGET_VBLANK);
6444		ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
6445		ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
6446		ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
6447		ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
6448		ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
6449		ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
6450		ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
6451		ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
6452		ret |= unregister_ioctl32_conversion(SISFB_COMMAND);
6453		if(ret)
6454			printk(KERN_ERR
6455			     "sisfb: Error unregistering ioctl32 translations\n");
6456	}
6457#endif
6458
6459	/* Unmap */
6460	iounmap(ivideo->mmio_vbase);
6461	iounmap(ivideo->video_vbase);
6462
6463	/* Release mem regions */
6464	release_mem_region(ivideo->video_base, ivideo->video_size);
6465	release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6466
6467	vfree(ivideo->bios_abase);
6468
6469	if(ivideo->lpcdev)
6470		pci_dev_put(ivideo->lpcdev);
6471
6472	if(ivideo->nbridge)
6473		pci_dev_put(ivideo->nbridge);
6474
6475#ifdef CONFIG_MTRR
6476	/* Release MTRR region */
6477	if(ivideo->mtrr >= 0)
6478		mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
6479#endif
6480
6481	pci_set_drvdata(pdev, NULL);
6482
6483	/* If device was disabled when starting, disable
6484	 * it when quitting.
6485	 */
6486	if(!ivideo->sisvga_enabled)
6487		pci_disable_device(pdev);
6488
6489	/* Unregister the framebuffer */
6490	if(ivideo->registered) {
6491		unregister_framebuffer(sis_fb_info);
6492		framebuffer_release(sis_fb_info);
6493	}
6494
6495	/* OK, our ivideo is gone for good from here. */
6496
6497	/* TODO: Restore the initial mode
6498	 * This sounds easy but is as good as impossible
6499	 * on many machines with SiS chip and video bridge
6500	 * since text modes are always set up differently
6501	 * from machine to machine. Depends on the type
6502	 * of integration between chipset and bridge.
6503	 */
6504	if(registered && modechanged)
6505		printk(KERN_INFO
6506			"sisfb: Restoring of text mode not supported yet\n");
6507};
6508
6509static struct pci_driver sisfb_driver = {
6510	.name		= "sisfb",
6511	.id_table 	= sisfb_pci_table,
6512	.probe		= sisfb_probe,
6513	.remove 	= __devexit_p(sisfb_remove)
6514};
6515
6516SISINITSTATIC int __init sisfb_init(void)
6517{
6518#ifndef MODULE
6519	char *options = NULL;
6520
6521	if(fb_get_options("sisfb", &options))
6522		return -ENODEV;
6523
6524	sisfb_setup(options);
6525#endif
6526	return pci_register_driver(&sisfb_driver);
6527}
6528
6529#ifndef MODULE
6530module_init(sisfb_init);
6531#endif
6532
6533/*****************************************************/
6534/*                      MODULE                       */
6535/*****************************************************/
6536
6537#ifdef MODULE
6538
6539static char		*mode = NULL;
6540static int		vesa = -1;
6541static unsigned int	rate = 0;
6542static unsigned int	crt1off = 1;
6543static unsigned int	mem = 0;
6544static char		*forcecrt2type = NULL;
6545static int		forcecrt1 = -1;
6546static int		pdc = -1;
6547static int		pdc1 = -1;
6548static int		noaccel = -1;
6549static int		noypan  = -1;
6550static int		nomax = -1;
6551static int		userom = -1;
6552static int		useoem = -1;
6553static char		*tvstandard = NULL;
6554static int		nocrt2rate = 0;
6555static int		scalelcd = -1;
6556static char		*specialtiming = NULL;
6557static int		lvdshl = -1;
6558static int		tvxposoffset = 0, tvyposoffset = 0;
6559#if !defined(__i386__) && !defined(__x86_64__)
6560static int		resetcard = 0;
6561static int		videoram = 0;
6562#endif
6563
6564static int __init sisfb_init_module(void)
6565{
6566	sisfb_setdefaultparms();
6567
6568	if(rate)
6569		sisfb_parm_rate = rate;
6570
6571	if((scalelcd == 0) || (scalelcd == 1))
6572		sisfb_scalelcd = scalelcd ^ 1;
6573
6574	/* Need to check crt2 type first for fstn/dstn */
6575
6576	if(forcecrt2type)
6577		sisfb_search_crt2type(forcecrt2type);
6578
6579	if(tvstandard)
6580		sisfb_search_tvstd(tvstandard);
6581
6582	if(mode)
6583		sisfb_search_mode(mode, false);
6584	else if(vesa != -1)
6585		sisfb_search_vesamode(vesa, false);
6586
6587	sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6588
6589	sisfb_forcecrt1 = forcecrt1;
6590	if(forcecrt1 == 1)
6591		sisfb_crt1off = 0;
6592	else if(forcecrt1 == 0)
6593		sisfb_crt1off = 1;
6594
6595	if(noaccel == 1)
6596		sisfb_accel = 0;
6597	else if(noaccel == 0)
6598		sisfb_accel = 1;
6599
6600	if(noypan == 1)
6601		sisfb_ypan = 0;
6602	else if(noypan == 0)
6603		sisfb_ypan = 1;
6604
6605	if(nomax == 1)
6606		sisfb_max = 0;
6607	else if(nomax == 0)
6608		sisfb_max = 1;
6609
6610	if(mem)
6611		sisfb_parm_mem = mem;
6612
6613	if(userom != -1)
6614		sisfb_userom = userom;
6615
6616	if(useoem != -1)
6617		sisfb_useoem = useoem;
6618
6619        if(pdc != -1)
6620		sisfb_pdc  = (pdc  & 0x7f);
6621
6622	if(pdc1 != -1)
6623		sisfb_pdca = (pdc1 & 0x1f);
6624
6625	sisfb_nocrt2rate = nocrt2rate;
6626
6627	if(specialtiming)
6628		sisfb_search_specialtiming(specialtiming);
6629
6630	if((lvdshl >= 0) && (lvdshl <= 3))
6631		sisfb_lvdshl = lvdshl;
6632
6633	sisfb_tvxposoffset = tvxposoffset;
6634	sisfb_tvyposoffset = tvyposoffset;
6635
6636#if !defined(__i386__) && !defined(__x86_64__)
6637	sisfb_resetcard = (resetcard) ? 1 : 0;
6638	if(videoram)
6639		sisfb_videoram = videoram;
6640#endif
6641
6642	return sisfb_init();
6643}
6644
6645static void __exit sisfb_remove_module(void)
6646{
6647	pci_unregister_driver(&sisfb_driver);
6648	printk(KERN_DEBUG "sisfb: Module unloaded\n");
6649}
6650
6651module_init(sisfb_init_module);
6652module_exit(sisfb_remove_module);
6653
6654MODULE_DESCRIPTION("SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3XT/V5/V8/Z7 framebuffer device driver");
6655MODULE_LICENSE("GPL");
6656MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6657
6658module_param(mem, int, 0);
6659module_param(noaccel, int, 0);
6660module_param(noypan, int, 0);
6661module_param(nomax, int, 0);
6662module_param(userom, int, 0);
6663module_param(useoem, int, 0);
6664module_param(mode, charp, 0);
6665module_param(vesa, int, 0);
6666module_param(rate, int, 0);
6667module_param(forcecrt1, int, 0);
6668module_param(forcecrt2type, charp, 0);
6669module_param(scalelcd, int, 0);
6670module_param(pdc, int, 0);
6671module_param(pdc1, int, 0);
6672module_param(specialtiming, charp, 0);
6673module_param(lvdshl, int, 0);
6674module_param(tvstandard, charp, 0);
6675module_param(tvxposoffset, int, 0);
6676module_param(tvyposoffset, int, 0);
6677module_param(nocrt2rate, int, 0);
6678#if !defined(__i386__) && !defined(__x86_64__)
6679module_param(resetcard, int, 0);
6680module_param(videoram, int, 0);
6681#endif
6682
6683MODULE_PARM_DESC(mem,
6684	"\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6685	  "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6686	  "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6687	  "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6688	  "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6689	  "The value is to be specified without 'KB'.\n");
6690
6691MODULE_PARM_DESC(noaccel,
6692	"\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
6693	  "(default: 0)\n");
6694
6695MODULE_PARM_DESC(noypan,
6696	"\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6697	  "will be performed by redrawing the screen. (default: 0)\n");
6698
6699MODULE_PARM_DESC(nomax,
6700	"\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
6701	  "memory for the virtual screen in order to optimize scrolling performance. If\n"
6702	  "this is set to anything other than 0, sisfb will not do this and thereby \n"
6703	  "enable the user to positively specify a virtual Y size of the screen using\n"
6704	  "fbset. (default: 0)\n");
6705
6706MODULE_PARM_DESC(mode,
6707	"\nSelects the desired default display mode in the format XxYxDepth,\n"
6708	 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
6709	 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
6710	 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
6711
6712MODULE_PARM_DESC(vesa,
6713	"\nSelects the desired default display mode by VESA defined mode number, eg.\n"
6714	 "0x117 (default: 0x0103)\n");
6715
6716MODULE_PARM_DESC(rate,
6717	"\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
6718	  "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
6719	  "will be ignored (default: 60)\n");
6720
6721MODULE_PARM_DESC(forcecrt1,
6722	"\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
6723	  "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
6724	  "0=CRT1 OFF) (default: [autodetected])\n");
6725
6726MODULE_PARM_DESC(forcecrt2type,
6727	"\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
6728	  "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
6729	  "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
6730	  "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
6731	  "be used instead of TV to override the TV detection. Furthermore, on systems\n"
6732	  "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
6733	  "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
6734	  "depends on the very hardware in use. (default: [autodetected])\n");
6735
6736MODULE_PARM_DESC(scalelcd,
6737	"\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
6738	  "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
6739	  "show black bars around the image, TMDS panels will probably do the scaling\n"
6740	  "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
6741
6742MODULE_PARM_DESC(pdc,
6743	"\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
6744	  "should detect this correctly in most cases; however, sometimes this is not\n"
6745	  "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
6746	  "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
6747	  "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
6748	  "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
6749
6750#ifdef CONFIG_FB_SIS_315
6751MODULE_PARM_DESC(pdc1,
6752	"\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330/340\n"
6753	  "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
6754	  "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
6755	  "implemented yet.\n");
6756#endif
6757
6758MODULE_PARM_DESC(specialtiming,
6759	"\nPlease refer to documentation for more information on this option.\n");
6760
6761MODULE_PARM_DESC(lvdshl,
6762	"\nPlease refer to documentation for more information on this option.\n");
6763
6764MODULE_PARM_DESC(tvstandard,
6765	"\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
6766	  "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
6767
6768MODULE_PARM_DESC(tvxposoffset,
6769	"\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
6770	  "Default: 0\n");
6771
6772MODULE_PARM_DESC(tvyposoffset,
6773	"\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
6774	  "Default: 0\n");
6775
6776MODULE_PARM_DESC(nocrt2rate,
6777	"\nSetting this to 1 will force the driver to use the default refresh rate for\n"
6778	  "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
6779
6780#if !defined(__i386__) && !defined(__x86_64__)
6781#ifdef CONFIG_FB_SIS_300
6782MODULE_PARM_DESC(resetcard,
6783	"\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
6784	  "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
6785	  "currently). Default: 0\n");
6786
6787MODULE_PARM_DESC(videoram,
6788	"\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
6789	  "some non-x86 architectures where the memory auto detection fails. Only\n"
6790	  "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
6791#endif
6792#endif
6793
6794#endif 	   /*  /MODULE  */
6795
6796/* _GPL only for new symbols. */
6797EXPORT_SYMBOL(sis_malloc);
6798EXPORT_SYMBOL(sis_free);
6799EXPORT_SYMBOL_GPL(sis_malloc_new);
6800EXPORT_SYMBOL_GPL(sis_free_new);
6801