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