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